mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/WikiEditor
synced 2024-11-27 17:50:44 +00:00
Add toggle button and two-pane layout for realtime preview
* Toolbar button to toggle a two-pane layout on and off. * Resizable bar for the width of the two panes. * Resizable bar for the edit box height, even when realtime preview is off. * Only enabled when $wgWikiEditorRealtimePreview = true. * Fires JS hooks when enabled, resized, and disabled. Bug: T293347 Change-Id: Id09d44519249c0b7f5c33d48d524b7c92a5a9106
This commit is contained in:
parent
27020ae196
commit
411be83bc3
|
@ -13,7 +13,7 @@
|
||||||
"license-name": "GPL-2.0-or-later",
|
"license-name": "GPL-2.0-or-later",
|
||||||
"type": "editor",
|
"type": "editor",
|
||||||
"requires": {
|
"requires": {
|
||||||
"MediaWiki": ">= 1.37"
|
"MediaWiki": ">= 1.38.0"
|
||||||
},
|
},
|
||||||
"MessagesDirs": {
|
"MessagesDirs": {
|
||||||
"WikiEditor": [
|
"WikiEditor": [
|
||||||
|
@ -300,6 +300,26 @@
|
||||||
"ext.wikiEditor.styles": {
|
"ext.wikiEditor.styles": {
|
||||||
"group": "ext.wikiEditor",
|
"group": "ext.wikiEditor",
|
||||||
"styles": "ext.wikiEditor.toolbar.styles.less"
|
"styles": "ext.wikiEditor.toolbar.styles.less"
|
||||||
|
},
|
||||||
|
"ext.wikiEditor.realtimepreview": {
|
||||||
|
"dependencies": [
|
||||||
|
"ext.wikiEditor",
|
||||||
|
"mediawiki.page.preview"
|
||||||
|
],
|
||||||
|
"messages": [
|
||||||
|
"wikieditor-realtimepreview-preview"
|
||||||
|
],
|
||||||
|
"packageFiles": [
|
||||||
|
"realtimepreview/init.js",
|
||||||
|
"realtimepreview/RealtimePreview.js",
|
||||||
|
"realtimepreview/ResizingDragBar.js",
|
||||||
|
"realtimepreview/TwoPaneLayout.js"
|
||||||
|
],
|
||||||
|
"styles": [
|
||||||
|
"realtimepreview/RealtimePreview.less",
|
||||||
|
"realtimepreview/ResizingDragBar.less",
|
||||||
|
"realtimepreview/TwoPaneLayout.less"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ResourceFileModulePaths": {
|
"ResourceFileModulePaths": {
|
||||||
|
@ -389,5 +409,11 @@
|
||||||
"AutoloadNamespaces": {
|
"AutoloadNamespaces": {
|
||||||
"MediaWiki\\Extension\\WikiEditor\\": "includes/"
|
"MediaWiki\\Extension\\WikiEditor\\": "includes/"
|
||||||
},
|
},
|
||||||
|
"config": {
|
||||||
|
"WikiEditorRealtimePreview": {
|
||||||
|
"description": "Whether to enable the Realtime Preview feature.",
|
||||||
|
"value": false
|
||||||
|
}
|
||||||
|
},
|
||||||
"manifest_version": 2
|
"manifest_version": 2
|
||||||
}
|
}
|
||||||
|
|
|
@ -197,5 +197,6 @@
|
||||||
"wikieditor-toolbar-help-content-indent-syntax": "Normal text<br />:Indented text<br />::Indented text",
|
"wikieditor-toolbar-help-content-indent-syntax": "Normal text<br />:Indented text<br />::Indented text",
|
||||||
"wikieditor-toolbar-help-content-indent-result": "Normal text<dl><dd>Indented text<dl><dd>Indented text</dd></dl></dd></dl>",
|
"wikieditor-toolbar-help-content-indent-result": "Normal text<dl><dd>Indented text<dl><dd>Indented text</dd></dl></dd></dl>",
|
||||||
"tag-wikieditor": "-",
|
"tag-wikieditor": "-",
|
||||||
"tag-wikieditor-description": "Edit made using [[mw:Special:MyLanguage/Extension:WikiEditor|WikiEditor]] (2010 wikitext editor)"
|
"tag-wikieditor-description": "Edit made using [[mw:Special:MyLanguage/Extension:WikiEditor|WikiEditor]] (2010 wikitext editor)",
|
||||||
|
"wikieditor-realtimepreview-preview": "Preview"
|
||||||
}
|
}
|
||||||
|
|
|
@ -228,5 +228,6 @@
|
||||||
"wikieditor-toolbar-help-content-indent-syntax": "{{RawHtml|phab=T294760}}\n\nSyntax example used in the help section \"discussion\" of the toolbar",
|
"wikieditor-toolbar-help-content-indent-syntax": "{{RawHtml|phab=T294760}}\n\nSyntax example used in the help section \"discussion\" of the toolbar",
|
||||||
"wikieditor-toolbar-help-content-indent-result": "{{RawHtml|phab=T294760}}\n\nHTML example used in the help section \"discussion\" of the toolbar",
|
"wikieditor-toolbar-help-content-indent-result": "{{RawHtml|phab=T294760}}\n\nHTML example used in the help section \"discussion\" of the toolbar",
|
||||||
"tag-wikieditor": "{{ignored}}Short description of the wikieditor tag.\n\nShown on lists of changes (history, recentchanges, etc.) for each edit made using WikiEditor.\n\nSee also:\n* {{msg-mw|Tag-wikieditor-description}}",
|
"tag-wikieditor": "{{ignored}}Short description of the wikieditor tag.\n\nShown on lists of changes (history, recentchanges, etc.) for each edit made using WikiEditor.\n\nSee also:\n* {{msg-mw|Tag-wikieditor-description}}",
|
||||||
"tag-wikieditor-description": "Long description of the wikieditor tag ({{msg-mw|Tag-wikieditor}}).\n\nShown on [[Special:Tags]].\n\nSee also:\n* {{msg-mw|Tag-wikieditor}}"
|
"tag-wikieditor-description": "Long description of the wikieditor tag ({{msg-mw|Tag-wikieditor}}).\n\nShown on [[Special:Tags]].\n\nSee also:\n* {{msg-mw|Tag-wikieditor}}",
|
||||||
|
"wikieditor-realtimepreview-preview": "Label for the toolbar button to enable/disable real-time preview."
|
||||||
}
|
}
|
||||||
|
|
|
@ -222,6 +222,10 @@ class Hooks implements
|
||||||
if ( $this->userOptionsLookup->getBoolOption( $user, 'usebetatoolbar' ) ) {
|
if ( $this->userOptionsLookup->getBoolOption( $user, 'usebetatoolbar' ) ) {
|
||||||
$outputPage->addModuleStyles( 'ext.wikiEditor.styles' );
|
$outputPage->addModuleStyles( 'ext.wikiEditor.styles' );
|
||||||
$outputPage->addModules( 'ext.wikiEditor' );
|
$outputPage->addModules( 'ext.wikiEditor' );
|
||||||
|
// Optionally enable Realtime Preview.
|
||||||
|
if ( $this->config->get( 'WikiEditorRealtimePreview' ) ) {
|
||||||
|
$outputPage->addModules( 'ext.wikiEditor.realtimepreview' );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't run this if the request was posted - we don't want to log 'init' when the
|
// Don't run this if the request was posted - we don't want to log 'init' when the
|
||||||
|
|
134
modules/realtimepreview/RealtimePreview.js
Normal file
134
modules/realtimepreview/RealtimePreview.js
Normal file
|
@ -0,0 +1,134 @@
|
||||||
|
var ResizingDragBar = require( './ResizingDragBar.js' );
|
||||||
|
var TwoPaneLayout = require( './TwoPaneLayout.js' );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class
|
||||||
|
*/
|
||||||
|
function RealtimePreview() {
|
||||||
|
this.enabled = false;
|
||||||
|
this.twoPaneLayout = new TwoPaneLayout();
|
||||||
|
this.pagePreview = require( 'mediawiki.page.preview' );
|
||||||
|
// @todo This shouldn't be required, but the preview element is added in PHP
|
||||||
|
// and can have attributes with values that aren't easily accessible from here,
|
||||||
|
// and we need to duplicate here what Live Preview does in core.
|
||||||
|
var $previewContent = $( '#wikiPreview' ).clone().html();
|
||||||
|
this.$previewNode = $( '<div>' )
|
||||||
|
.addClass( 'ext-WikiEditor-realtimepreview-preview' )
|
||||||
|
.append( $previewContent );
|
||||||
|
this.$errorNode = $( '<div>' )
|
||||||
|
.addClass( 'error' );
|
||||||
|
this.twoPaneLayout.getPane2().append( this.$previewNode, this.$errorNode );
|
||||||
|
this.eventNames = 'change.realtimepreview input.realtimepreview cut.realtimepreview paste.realtimepreview';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @public
|
||||||
|
* @param {Object} context The WikiEditor context.
|
||||||
|
* @return {OO.ui.ToggleButtonWidget}
|
||||||
|
*/
|
||||||
|
RealtimePreview.prototype.getToolbarButton = function ( context ) {
|
||||||
|
this.context = context;
|
||||||
|
var $uiText = context.$ui.find( '.wikiEditor-ui-text' );
|
||||||
|
|
||||||
|
// Fix the height of the textarea, before adding a resizing bar below it.
|
||||||
|
var height = context.$textarea.height();
|
||||||
|
$uiText.css( 'height', height + 'px' );
|
||||||
|
context.$textarea.removeAttr( 'rows cols' );
|
||||||
|
|
||||||
|
// Add the resizing bar.
|
||||||
|
var bottomDragBar = new ResizingDragBar( { isEW: false } );
|
||||||
|
$uiText.after( bottomDragBar.$element );
|
||||||
|
|
||||||
|
// Create and configure the toolbar button.
|
||||||
|
this.button = new OO.ui.ToggleButtonWidget( {
|
||||||
|
label: mw.msg( 'wikieditor-realtimepreview-preview' ),
|
||||||
|
icon: 'article',
|
||||||
|
value: this.enabled,
|
||||||
|
framed: false
|
||||||
|
} );
|
||||||
|
this.button.connect( this, { change: this.toggle } );
|
||||||
|
return this.button;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Toggle the two-pane preview display.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {Object} context The WikiEditor context object.
|
||||||
|
*/
|
||||||
|
RealtimePreview.prototype.toggle = function () {
|
||||||
|
var $uiText = this.context.$ui.find( '.wikiEditor-ui-text' );
|
||||||
|
var $textarea = this.context.$textarea;
|
||||||
|
|
||||||
|
// Remove or add the layout to the DOM.
|
||||||
|
if ( this.enabled ) {
|
||||||
|
// Move height from the TwoPaneLayout to the text UI div.
|
||||||
|
$uiText.css( 'height', this.twoPaneLayout.$element.height() + 'px' );
|
||||||
|
|
||||||
|
// Put the text div back to being after the layout, and then hide the layout.
|
||||||
|
this.twoPaneLayout.$element.after( $uiText );
|
||||||
|
this.twoPaneLayout.$element.hide();
|
||||||
|
|
||||||
|
// Remove the keyup handler.
|
||||||
|
$textarea.off( this.eventNames );
|
||||||
|
|
||||||
|
// Let other things happen after disabling.
|
||||||
|
mw.hook( 'ext.WikiEditor.realtimepreview.disable' ).fire( this );
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Add the layout before the text div of the UI and then move the text div into it.
|
||||||
|
$uiText.before( this.twoPaneLayout.$element );
|
||||||
|
this.twoPaneLayout.setPane1( $uiText );
|
||||||
|
this.twoPaneLayout.$element.show();
|
||||||
|
|
||||||
|
// Move explicit height from text-ui (which may have been set via manual resizing), to panes.
|
||||||
|
this.twoPaneLayout.$element.css( 'height', $uiText.height() + 'px' );
|
||||||
|
$uiText.css( 'height', '100%' );
|
||||||
|
|
||||||
|
// Enable realtime previewing.
|
||||||
|
this.addPreviewListener( $textarea );
|
||||||
|
|
||||||
|
// Let other things happen after enabling.
|
||||||
|
mw.hook( 'ext.WikiEditor.realtimepreview.enable' ).fire( this );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Record the toggle state and update the button.
|
||||||
|
this.enabled = !this.enabled;
|
||||||
|
this.button.setFlags( { progressive: this.enabled } );
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @public
|
||||||
|
* @param {jQuery} $editor The element to listen to changes on.
|
||||||
|
*/
|
||||||
|
RealtimePreview.prototype.addPreviewListener = function ( $editor ) {
|
||||||
|
// Get preview when enabling.
|
||||||
|
this.doRealtimePreview();
|
||||||
|
// Also get preview on keyup, change, paste etc.
|
||||||
|
$editor
|
||||||
|
.off( this.eventNames )
|
||||||
|
.on( this.eventNames, mw.util.debounce( 2000, this.doRealtimePreview.bind( this ) ) );
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
RealtimePreview.prototype.doRealtimePreview = function () {
|
||||||
|
this.twoPaneLayout.getPane2().addClass( 'ext-WikiEditor-twopanes-loading' );
|
||||||
|
var loadingSelectors = this.pagePreview.getLoadingSelectors();
|
||||||
|
loadingSelectors.push( '.ext-WikiEditor-realtimepreview-preview' );
|
||||||
|
this.$errorNode.empty();
|
||||||
|
this.pagePreview.doPreview( {
|
||||||
|
$previewNode: this.$previewNode,
|
||||||
|
$spinnerNode: false,
|
||||||
|
loadingSelectors: loadingSelectors
|
||||||
|
} ).fail( function ( code, result ) {
|
||||||
|
var $errorMsg = ( new mw.Api() ).getErrorMessage( result );
|
||||||
|
this.$previewNode.hide();
|
||||||
|
this.$errorNode.append( $errorMsg );
|
||||||
|
}.bind( this ) ).always( function () {
|
||||||
|
this.twoPaneLayout.getPane2().removeClass( 'ext-WikiEditor-twopanes-loading' );
|
||||||
|
}.bind( this ) );
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = RealtimePreview;
|
19
modules/realtimepreview/RealtimePreview.less
Normal file
19
modules/realtimepreview/RealtimePreview.less
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
@import 'mediawiki.ui/variables.less';
|
||||||
|
|
||||||
|
/* stylelint-disable selector-max-id */
|
||||||
|
#wpTextbox1,
|
||||||
|
.mw-editform #wpTextbox1 {
|
||||||
|
// stylelint-disable-next-line plugin/no-unsupported-browser-features
|
||||||
|
resize: none;
|
||||||
|
height: 100%;
|
||||||
|
min-height: auto;
|
||||||
|
max-height: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wikiEditor-ui .wikiEditor-ui-view {
|
||||||
|
border-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ext-WikiEditor-ResizingDragBar-ns {
|
||||||
|
border-top: 1px solid @colorGray12;
|
||||||
|
}
|
84
modules/realtimepreview/ResizingDragBar.js
Normal file
84
modules/realtimepreview/ResizingDragBar.js
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
/**
|
||||||
|
* @class
|
||||||
|
* @constructor
|
||||||
|
* @extends OO.ui.Element
|
||||||
|
* @param {Object} [config] Configuration options
|
||||||
|
* @param {boolean} [config.isEW] Orientation of the drag bar, East-West (true) or North-South (false).
|
||||||
|
*/
|
||||||
|
function ResizingDragBar( config ) {
|
||||||
|
config = $.extend( {}, {
|
||||||
|
isEW: true,
|
||||||
|
classes: [ 'ext-WikiEditor-ResizingDragBar' ]
|
||||||
|
}, config );
|
||||||
|
ResizingDragBar.super.call( this, config );
|
||||||
|
|
||||||
|
var classNameDir = 'ext-WikiEditor-ResizingDragBar-' + ( config.isEW ? 'ew' : 'ns' );
|
||||||
|
// Possible class names:
|
||||||
|
// * ext-WikiEditor-ResizingDragBar-ew
|
||||||
|
// * ext-WikiEditor-ResizingDragBar-ns
|
||||||
|
this.$element.addClass( classNameDir );
|
||||||
|
|
||||||
|
var resizingDragBar = this;
|
||||||
|
this.$element.on( 'mousedown', function ( eventMousedown ) {
|
||||||
|
if ( eventMousedown.button !== ResizingDragBar.static.MAIN_MOUSE_BUTTON ) {
|
||||||
|
// If not the main mouse (e.g. left) button, ignore.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Prevent selecting (or anything else) when dragging over other parts of the page.
|
||||||
|
$( document ).on( 'selectstart.' + classNameDir, false );
|
||||||
|
// Set up parameter names.
|
||||||
|
var xOrY = config.isEW ? 'pageX' : 'pageY';
|
||||||
|
var widthOrHeight = config.isEW ? 'width' : 'height';
|
||||||
|
var lastOffset = eventMousedown[ xOrY ];
|
||||||
|
// Handle the actual dragging.
|
||||||
|
$( document ).on( 'mousemove.' + classNameDir, function ( eventMousemove ) {
|
||||||
|
// Initial width or height of the pane.
|
||||||
|
var startSize = resizingDragBar.getResizedPane()[ widthOrHeight ]();
|
||||||
|
// Current position of the mouse (relative to page, not viewport).
|
||||||
|
var newOffset = eventMousemove[ xOrY ];
|
||||||
|
// Distance the mouse has moved.
|
||||||
|
var change = lastOffset - newOffset;
|
||||||
|
// Set the new size of the pane, and tell others about it.
|
||||||
|
var newSize = Math.max( startSize - change, ResizingDragBar.static.MIN_PANE_SIZE );
|
||||||
|
resizingDragBar.getResizedPane().css( widthOrHeight, newSize );
|
||||||
|
// Save the new starting point of the mouse, from which to calculate the next move.
|
||||||
|
lastOffset = newOffset;
|
||||||
|
// Let other scripts do things after the resize.
|
||||||
|
mw.hook( 'ext.WikiEditor.realtimepreview.resize' ).fire( resizingDragBar );
|
||||||
|
} );
|
||||||
|
} );
|
||||||
|
// Add a UI affordance within the handle area (CSS gives it its appearance).
|
||||||
|
this.$element.append( $( '<span>' ) );
|
||||||
|
// Remove the resize event handler when the mouse is released.
|
||||||
|
$( document ).on( 'mouseup', function () {
|
||||||
|
$( document ).off( 'mousemove.' + classNameDir );
|
||||||
|
$( document ).off( 'selectstart.' + classNameDir, false );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
OO.inheritClass( ResizingDragBar, OO.ui.Element );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @static
|
||||||
|
* @property {number} See https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/button
|
||||||
|
*/
|
||||||
|
ResizingDragBar.static.MAIN_MOUSE_BUTTON = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @static
|
||||||
|
* @property {number} The minimum pane size, in pixels.
|
||||||
|
* Should be slightly more than the affordance length.
|
||||||
|
*/
|
||||||
|
ResizingDragBar.static.MIN_PANE_SIZE = 100;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the pane that is resized by this bar (always the immediate prior sibling).
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
* @return {jQuery}
|
||||||
|
*/
|
||||||
|
ResizingDragBar.prototype.getResizedPane = function () {
|
||||||
|
return this.$element.prev();
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = ResizingDragBar;
|
40
modules/realtimepreview/ResizingDragBar.less
Normal file
40
modules/realtimepreview/ResizingDragBar.less
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
@import 'mediawiki.ui/variables.less';
|
||||||
|
|
||||||
|
// The dimensions of the UI affordance (the little line in the draggable area).
|
||||||
|
@affordance-width: 4px;
|
||||||
|
@affordance-length: 110px;
|
||||||
|
|
||||||
|
.ext-WikiEditor-ResizingDragBar {
|
||||||
|
background-color: @colorGray14;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ext-WikiEditor-ResizingDragBar-ns {
|
||||||
|
cursor: ns-resize;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ext-WikiEditor-ResizingDragBar-ew {
|
||||||
|
cursor: ew-resize;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ext-WikiEditor-ResizingDragBar span {
|
||||||
|
width: @affordance-length;
|
||||||
|
height: @affordance-width;
|
||||||
|
background-color: @colorGray12;
|
||||||
|
border-radius: 2px;
|
||||||
|
display: block;
|
||||||
|
// Don't change without also changing the calculated width of pane1 above.
|
||||||
|
margin: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ext-WikiEditor-ResizingDragBar:hover span {
|
||||||
|
background-color: @colorGray5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ext-WikiEditor-ResizingDragBar-ew span {
|
||||||
|
height: @affordance-length;
|
||||||
|
width: @affordance-width;
|
||||||
|
border-width: 0 1px;
|
||||||
|
}
|
79
modules/realtimepreview/TwoPaneLayout.js
Normal file
79
modules/realtimepreview/TwoPaneLayout.js
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
var ResizingDragBar = require( './ResizingDragBar.js' );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is a layout with two resizable panes.
|
||||||
|
*
|
||||||
|
* @class
|
||||||
|
* @constructor
|
||||||
|
* @extends OO.ui.Layout
|
||||||
|
* @param {Object} [config] Configuration options
|
||||||
|
*/
|
||||||
|
function TwoPaneLayout( config ) {
|
||||||
|
// Configuration initialization
|
||||||
|
config = config || {};
|
||||||
|
TwoPaneLayout.super.call( this, config );
|
||||||
|
|
||||||
|
this.$pane1 = $( '<div>' ).addClass( 'ext-WikiEditor-twopanes-pane1' );
|
||||||
|
var middleDragBar = new ResizingDragBar( { isEW: true } );
|
||||||
|
this.$pane2 = $( '<div>' ).addClass( 'ext-WikiEditor-twopanes-pane2' );
|
||||||
|
|
||||||
|
this.$element.addClass( 'ext-WikiEditor-twopanes-TwoPaneLayout' );
|
||||||
|
this.$element.append( this.$pane1, middleDragBar.$element, this.$pane2 );
|
||||||
|
}
|
||||||
|
|
||||||
|
OO.inheritClass( TwoPaneLayout, OO.ui.Layout );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set pane 1 content.
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
* @param {jQuery|string|Function|OO.ui.HtmlSnippet} content
|
||||||
|
*/
|
||||||
|
TwoPaneLayout.prototype.setPane1 = function ( content ) {
|
||||||
|
this.setContent( this.$pane1, content );
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @public
|
||||||
|
* @return {jQuery}
|
||||||
|
*/
|
||||||
|
TwoPaneLayout.prototype.getPane1 = function () {
|
||||||
|
return this.$pane1;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set pane 2 content.
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
* @param {jQuery|string|Function|OO.ui.HtmlSnippet} content
|
||||||
|
*/
|
||||||
|
TwoPaneLayout.prototype.setPane2 = function ( content ) {
|
||||||
|
this.setContent( this.$pane2, content );
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @public
|
||||||
|
* @return {jQuery}
|
||||||
|
*/
|
||||||
|
TwoPaneLayout.prototype.getPane2 = function () {
|
||||||
|
return this.$pane2;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @param {jQuery} $container The container to set the content in.
|
||||||
|
* @param {jQuery|string|Function|OO.ui.HtmlSnippet} content The content to set.
|
||||||
|
*/
|
||||||
|
TwoPaneLayout.prototype.setContent = function ( $container, content ) {
|
||||||
|
if ( typeof content === 'string' ) {
|
||||||
|
$container.text( content );
|
||||||
|
} else if ( content instanceof OO.ui.HtmlSnippet ) {
|
||||||
|
$container.html( content.toString() );
|
||||||
|
} else if ( content instanceof $ ) {
|
||||||
|
$container.empty().append( content );
|
||||||
|
} else {
|
||||||
|
$container.empty();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = TwoPaneLayout;
|
53
modules/realtimepreview/TwoPaneLayout.less
Normal file
53
modules/realtimepreview/TwoPaneLayout.less
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
@import 'mediawiki.ui/variables.less';
|
||||||
|
|
||||||
|
.ext-WikiEditor-twopanes-TwoPaneLayout {
|
||||||
|
// stylelint-disable-next-line plugin/no-unsupported-browser-features
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
.ext-WikiEditor-twopanes-pane1 {
|
||||||
|
border: 1px solid @colorGray12;
|
||||||
|
border-width: 0 1px 0 0;
|
||||||
|
// Offset by half the difference in padding and the UI affordance.
|
||||||
|
// stylelint-disable-next-line plugin/no-unsupported-browser-features
|
||||||
|
width: ~'calc( 50% - 9px )';
|
||||||
|
}
|
||||||
|
|
||||||
|
.ext-WikiEditor-twopanes-pane2 {
|
||||||
|
position: relative;
|
||||||
|
border: 1px solid @colorGray12;
|
||||||
|
border-width: 0 0 0 1px;
|
||||||
|
flex: 1 1 0;
|
||||||
|
overflow: auto;
|
||||||
|
padding: 0 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@loadingbar-width: 20%;
|
||||||
|
|
||||||
|
// stylelint-disable-next-line selector-pseudo-element-colon-notation
|
||||||
|
.ext-WikiEditor-twopanes-pane2.ext-WikiEditor-twopanes-loading::before {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
z-index: 5;
|
||||||
|
display: block;
|
||||||
|
opacity: 1;
|
||||||
|
content: ' ';
|
||||||
|
background-color: @color-primary;
|
||||||
|
width: @loadingbar-width;
|
||||||
|
height: 4px;
|
||||||
|
// Hide the loading bar to start with; it'll be shown if the loading state persists for more than 1s.
|
||||||
|
visibility: hidden;
|
||||||
|
animation: loadingbar 1.5s 1s infinite linear alternate;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes loadingbar {
|
||||||
|
0% {
|
||||||
|
visibility: visible;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
// stylelint-disable-next-line plugin/no-unsupported-browser-features
|
||||||
|
left: calc( 100% - @loadingbar-width );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
16
modules/realtimepreview/init.js
Normal file
16
modules/realtimepreview/init.js
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
mw.hook( 'wikiEditor.toolbarReady' ).add( function ( $textarea ) {
|
||||||
|
var RealtimePreview = require( './RealtimePreview.js' );
|
||||||
|
var realtimePreview = new RealtimePreview();
|
||||||
|
$textarea.wikiEditor( 'addToToolbar', {
|
||||||
|
section: 'secondary',
|
||||||
|
group: 'default',
|
||||||
|
tools: {
|
||||||
|
realtimepreview: {
|
||||||
|
type: 'element',
|
||||||
|
element: function ( context ) {
|
||||||
|
return realtimePreview.getToolbarButton( context ).$element;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
} );
|
Loading…
Reference in a new issue