Robmoen has uploaded a new change for review. https://gerrit.wikimedia.org/r/50045
Change subject: Introduce configurable target views. ...................................................................... Introduce configurable target views. Major changes: ve.init.Target.js * Create abstract class methods for Target. ve.init.sa.Target.js * Create Standalone target view methods. ve.init.mw.Target.js * Added MW specific target view methods. * Integration action buttons are now added to the edit view in the toolbar. ve.Surface.js * Change toolbar config object to include views * Tweak setupToolbars to incorporate view elements and contain their configured tools. * Each toolbar view has an actions container. * Other changes include some documentation and code cleanup. Change-Id: Iff39266bdd3052f34bda254ca407030dbbc81f26 --- M VisualEditor.php M demos/ve/index.php M modules/ve/init/mw/targets/ve.init.mw.ViewPageTarget.js M modules/ve/init/mw/ve.init.mw.Platform.js M modules/ve/init/mw/ve.init.mw.Target.js M modules/ve/init/sa/styles/ve.init.sa.css M modules/ve/init/sa/ve.init.sa.Platform.js A modules/ve/init/sa/ve.init.sa.Target.js M modules/ve/init/ve.init.Platform.js A modules/ve/init/ve.init.Target.js M modules/ve/ve.Surface.js 11 files changed, 262 insertions(+), 49 deletions(-) git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/VisualEditor refs/changes/45/50045/1 diff --git a/VisualEditor.php b/VisualEditor.php index 45a4e33..414bd63 100644 --- a/VisualEditor.php +++ b/VisualEditor.php @@ -175,6 +175,7 @@ 've/ve.EventEmitter.js', 've/init/ve.init.js', 've/init/ve.init.Platform.js', + 've/init/ve.init.Target.js', ), 'debugScripts' => array( 've/ve.debug.js', diff --git a/demos/ve/index.php b/demos/ve/index.php index 85295dd..23dbf40 100644 --- a/demos/ve/index.php +++ b/demos/ve/index.php @@ -59,7 +59,7 @@ </li> <?php endforeach; ?> </ul> - <div class="ve-demo-content"></div> + <div class="ve-container"></div> <!-- Generated by maintenance/makeStaticLoader.php --> <!-- Dependencies --> @@ -71,10 +71,12 @@ <script src="../../modules/ve/ve.EventEmitter.js"></script> <script src="../../modules/ve/init/ve.init.js"></script> <script src="../../modules/ve/init/ve.init.Platform.js"></script> + <script src="../../modules/ve/init/ve.init.Target.js"></script> <script src="../../modules/ve/ve.debug.js"></script> <!-- Standalone Init --> <script src="../../modules/ve/init/sa/ve.init.sa.js"></script> <script src="../../modules/ve/init/sa/ve.init.sa.Platform.js"></script> + <script src="../../modules/ve/init/sa/ve.init.sa.Target.js"></script> <script> <?php require( '../../modules/../VisualEditor.i18n.php' ); @@ -212,12 +214,16 @@ <script src="../../modules/ve/ui/inspectors/ve.ui.MWLinkInspector.js"></script> <!-- demo --> <script> - $(document).ready( function () { + $( document ).ready( function () { + var target = new ve.init.sa.Target(); new ve.Surface( - $( '.ve-demo-content' ), + target.$, ve.createDocumentFromHTML( <?php echo json_encode( $html ) ?> ) + target ); $( '.ve-ce-documentNode' ).focus(); + //expose target for a sec. + window.target = target; } ); </script> diff --git a/modules/ve/init/mw/targets/ve.init.mw.ViewPageTarget.js b/modules/ve/init/mw/targets/ve.init.mw.ViewPageTarget.js index 7fe0be8..8f6d102 100644 --- a/modules/ve/init/mw/targets/ve.init.mw.ViewPageTarget.js +++ b/modules/ve/init/mw/targets/ve.init.mw.ViewPageTarget.js @@ -57,13 +57,16 @@ 'top': { 'float': !this.isMobileDevice, // HACK: The toolbar configuration isn't very extendable, so this is mostly - // copy-pasted from ve.Surface except using mwLink for the link tool - 'tools': [ - { 'name': 'history', 'items' : ['undo', 'redo'] }, - { 'name': 'textStyle', 'items' : ['format'] }, - { 'name': 'textStyle', 'items' : ['bold', 'italic', 'mwLink', 'clear'] }, - { 'name': 'list', 'items' : ['number', 'bullet', 'outdent', 'indent'] } - ] + 'views': { + 'edit': { + 'groups': [ + { 'name': 'history', 'items' : ['undo', 'redo'] }, + { 'name': 'textStyle', 'items' : ['format'] }, + { 'name': 'textStyle', 'items' : ['bold', 'italic', 'link', 'clear'] }, + { 'name': 'list', 'items' : ['number', 'bullet', 'outdent', 'indent'] } + ] + } + } } }, 'commands': ['bold', 'italic', 'mwLink', 'undo', 'redo', 'indent', 'outdent'] @@ -686,7 +689,7 @@ // Store the HTML for reporting purposes this.originalHtml = doc.body.innerHTML; // TODO store entire document in the future // Initialize surface - this.surface = new ve.Surface( $( '#content' ), doc, this.surfaceOptions ); + this.surface = new ve.Surface( this.$, doc, this, this.surfaceOptions ); this.surface.getContext().hide(); this.$document = this.surface.$.find( '.ve-ce-documentNode' ); this.surface.getModel().on( 'transact', this.proxiedOnSurfaceModelTransact ); @@ -905,7 +908,7 @@ * @method */ ve.init.mw.ViewPageTarget.prototype.attachToolbarButtons = function () { - var $target = $( '.ve-ui-toolbar .ve-ui-actions' ); + var $target = $( '.ve-ui-toolbar .ve-ui-toolbar-view-edit .ve-ui-actions' ); $target.append( this.$toolbarFeedbackTool ); if ( !ve.isEmptyObject( this.editNotices ) ) { $target.append( this.$toolbarEditNoticesTool ); @@ -1711,6 +1714,63 @@ } }; +/** + * Adds an editor view to the target container. + * + * @method + * @param {string} view name of view. + * @param {object} config object of jQuery objects for the view. + */ +ve.init.mw.ViewPageTarget.prototype.addView = function ( view, config ) { + if( view in this.views ) { + throw new Error( 'View: ' + view + ' already registered!' ); + } + this.views[view] = config; + // Add the view to the target container + if( config.$.length === 0 ) { + this.$.append( config.$ ); + } + // Add the toolbar view to the toolbar. + +}; + +/** + * Hides all registered views and shows given editor view & matching toolbar view. + * + * @method + * @param {string} view name of view. + */ +ve.init.mw.ViewPageTarget.prototype.showView = function ( view ) { + var name; + if ( !( view in this.views ) ) { + throw new Error( 'View: ' + view + ' not found!' ); + } + // Hide all the views. + for( name in this.views ) { + this.hideView( name ); + } + // Show view container. + this.views[view].$.show(); + this.views[view].$toolbar.show(); + // Show toolbar view container +}; + + +/** + * Hide a view + * + * @method + * @param {string} view name of view. + */ +ve.init.mw.Target.prototype.hideView = function ( view ) { + if ( ! ( view in this.views ) ) { + throw new Error( 'View: ' + view + ' not found!' ); + } + // Hide the view objects. + this.views[view].$.hide(); + this.views[view].$toolbar.hide(); +}; + /* Initialization */ ve.init.mw.targets.push( new ve.init.mw.ViewPageTarget() ); diff --git a/modules/ve/init/mw/ve.init.mw.Platform.js b/modules/ve/init/mw/ve.init.mw.Platform.js index 5cb8c3f..1454d8b 100644 --- a/modules/ve/init/mw/ve.init.mw.Platform.js +++ b/modules/ve/init/mw/ve.init.mw.Platform.js @@ -1,5 +1,5 @@ /*! - * VisualEditor MediaWiki Initialization Target class. + * VisualEditor MediaWiki Initialization Platform class. * * @copyright 2011-2013 VisualEditor Team and others; see AUTHORS.txt * @license The MIT License (MIT); see LICENSE.txt diff --git a/modules/ve/init/mw/ve.init.mw.Target.js b/modules/ve/init/mw/ve.init.mw.Target.js index 0f941b4..9ef116d 100644 --- a/modules/ve/init/mw/ve.init.mw.Target.js +++ b/modules/ve/init/mw/ve.init.mw.Target.js @@ -11,16 +11,17 @@ * Initialization MediaWiki target. * * @class - * @extends ve.EventEmitter + * @extends ve.init.Target * @constructor * @param {string} pageName Name of target page * @param {number} [revision] Revision ID */ ve.init.mw.Target = function VeInitMwTarget( pageName, revision ) { // Parent constructor - ve.EventEmitter.call( this ); + ve.init.Target.call( this ); // Properties + this.$ = $( '#content' ); this.pageName = pageName; this.pageExists = mw.config.get( 'wgArticleId', 0 ) !== 0; this.oldid = revision || ''; @@ -70,7 +71,7 @@ /* Inheritance */ -ve.inheritClass( ve.init.mw.Target, ve.EventEmitter ); +ve.inheritClass( ve.init.mw.Target, ve.init.Target ); /* Static Methods */ diff --git a/modules/ve/init/sa/styles/ve.init.sa.css b/modules/ve/init/sa/styles/ve.init.sa.css index 0dc2c1e..fac7841 100644 --- a/modules/ve/init/sa/styles/ve.init.sa.css +++ b/modules/ve/init/sa/styles/ve.init.sa.css @@ -1,5 +1,5 @@ /*! - * VisualEditor Stand-alone Initialization styles. + * VisualEditor Standalone Initialization styles. * * @copyright 2011-2013 VisualEditor Team and others; see AUTHORS.txt * @license The MIT License (MIT); see LICENSE.txt diff --git a/modules/ve/init/sa/ve.init.sa.Platform.js b/modules/ve/init/sa/ve.init.sa.Platform.js index 4daa93d..3b950ec 100644 --- a/modules/ve/init/sa/ve.init.sa.Platform.js +++ b/modules/ve/init/sa/ve.init.sa.Platform.js @@ -1,12 +1,12 @@ /*! - * VisualEditor stand-alone Initialization Target class. + * VisualEditor Standalone Initialization Platform class. * * @copyright 2011-2013 VisualEditor Team and others; see AUTHORS.txt * @license The MIT License (MIT); see LICENSE.txt */ /** - * Initialization stand-alone platform. + * Initialization Standalone platform. * * @class * @extends ve.init.Platform diff --git a/modules/ve/init/sa/ve.init.sa.Target.js b/modules/ve/init/sa/ve.init.sa.Target.js new file mode 100644 index 0000000..c32c1de --- /dev/null +++ b/modules/ve/init/sa/ve.init.sa.Target.js @@ -0,0 +1,72 @@ +/*! + * VisualEditor Standalone Initialization Target class. + * + * @copyright 2011-2012 VisualEditor Team and others; see AUTHORS.txt + * @license The MIT License (MIT); see LICENSE.txt + */ + +/*global mw */ + +/** + * Initialization Standalone target. + * + * @class + * @extends ve.init.Target + * @constructor + */ +ve.init.sa.Target = function VeInitSaTarget() { + // Parent constructor + ve.init.Target.call( this ); + this.$ = $( '.ve-container' ); +}; + +/* Inheritance */ + +ve.inheritClass( ve.init.sa.Target, ve.init.Target ); + +/* Methods */ + +/** + * Adds a view to the target. + * + * @method + * @param {string} message + */ +ve.init.sa.Target.prototype.addView = function ( view, config ) { + if( view in this.views ) { + throw new Error( 'View: ' + view + ' already registered!' ); + } + this.views[view] = config; + // If not already present, add the dialog to the container. + if( config.$.length === 0 ) { + this.$.append( config.$ ); + } +}; + +/** + * Show a view + * + * @method + * @param {string} view + */ +ve.init.sa.Target.prototype.showView = function ( view ) { + if ( ! ( view in this.views ) ) { + throw new Error( 'View: ' + view + ' not found!' ); + } + // Show the dialog. + this.views[view].$.show(); +}; + +/** + * Hide a view + * + * @method + * @param {string} view name of view. + */ +ve.init.sa.Target.prototype.hideView = function ( view ) { + if ( ! ( view in this.views ) ) { + throw new Error( 'View: ' + view + ' not found!' ); + } + // Hide the dialog. + this.views[view].$.hide(); +}; diff --git a/modules/ve/init/ve.init.Platform.js b/modules/ve/init/ve.init.Platform.js index b421370..afac259 100644 --- a/modules/ve/init/ve.init.Platform.js +++ b/modules/ve/init/ve.init.Platform.js @@ -1,5 +1,5 @@ /*! - * VisualEditor Initialization Target class. + * VisualEditor Initialization Platform class. * * @copyright 2011-2013 VisualEditor Team and others; see AUTHORS.txt * @license The MIT License (MIT); see LICENSE.txt diff --git a/modules/ve/init/ve.init.Target.js b/modules/ve/init/ve.init.Target.js new file mode 100644 index 0000000..d178314 --- /dev/null +++ b/modules/ve/init/ve.init.Target.js @@ -0,0 +1,56 @@ +/*! + * VisualEditor Initialization Target class. + * + * @copyright 2011-2012 VisualEditor Team and others; see AUTHORS.txt + * @license The MIT License (MIT); see LICENSE.txt + */ + +/** + * Generic Initialization target. + * + * @abstract + * @extends ve.EventEmitter + * @constructor + */ +ve.init.Target = function VeInitTarget() { + // Parent constructor + ve.EventEmitter.call( this ); + // Map of target views + this.views = {}; +}; + +/* Inheritance */ + +ve.inheritClass( ve.init.Target, ve.EventEmitter ); + +/* Abstract Methods */ + +/** + * Adds a view to the target. + * + * @method + * @abstract + */ +ve.init.Target.prototype.addView = function () { + throw new Error( 've.init.Target.addView must be overridden in subclass' ); +}; + +/** + * Show a view. + * + * @method + * @abstract + */ +ve.init.Target.prototype.showView = function () { + throw new Error( 've.init.Target.showView must be overridden in subclass' ); +}; + +/** + * Hide a view. + * + * @method + * @abstract + */ +ve.init.Target.prototype.hideView = function () { + throw new Error( 've.init.Target.hideView must be overridden in subclass' ); +}; diff --git a/modules/ve/ve.Surface.js b/modules/ve/ve.Surface.js index b777be1..0a41ee7 100644 --- a/modules/ve/ve.Surface.js +++ b/modules/ve/ve.Surface.js @@ -20,24 +20,24 @@ * @constructor * @param {string} parent Selector of element to attach to * @param {HTMLDocument} doc HTML document to edit + * @param {Object} target Subclass of ve.init.Target * @param {Object} options Configuration options */ -ve.Surface = function VeSurface( parent, doc, options ) { +ve.Surface = function VeSurface( parent, doc, target, options ) { // Properties this.$ = $( '<div>' ); this.documentModel = new ve.dm.Document( ve.dm.converter.getDataFromDom( doc ) ); this.options = ve.extendObject( true, ve.Surface.defaultOptions, options ); this.model = new ve.dm.Surface( this.documentModel ); - this.view = new ve.ce.Surface( this.$, this.model, this ); + this.view = new ve.ce.Surface( this.$, this.model, this ); this.context = new ve.ui.Context( this ); + this.target = target; this.toolbars = {}; this.commands = {}; this.enabled = true; // DOM Changes - this.$.addClass( 've-surface' ); - $( parent ).append( this.$ ); - + $( parent ).append( this.$.addClass( 've-surface' ) ); // Initialization // Propagate to each node information that it is live (attached to the live DOM) this.view.getDocument().getDocumentNode().setLive( true ); @@ -60,12 +60,16 @@ 'toolbars': { 'top': { 'float': true, - 'tools': [ - { 'name': 'history', 'items' : ['undo', 'redo'] }, - { 'name': 'textStyle', 'items' : ['format'] }, - { 'name': 'textStyle', 'items' : ['bold', 'italic', 'link', 'clear'] }, - { 'name': 'list', 'items' : ['number', 'bullet', 'outdent', 'indent'] } - ] + 'views': { + 'edit': { + 'groups': [ + { 'name': 'history', 'items' : ['undo', 'redo'] }, + { 'name': 'textStyle', 'items' : ['format'] }, + { 'name': 'textStyle', 'items' : ['bold', 'italic', 'link', 'clear'] }, + { 'name': 'list', 'items' : ['number', 'bullet', 'outdent', 'indent'] } + ] + } + } } }, // Items can either be symbolic names or objects with trigger and action properties @@ -250,37 +254,50 @@ }; /** - * Initialize the toolbar. + * Initialize all configured toolbars. * * This method uses {this.options} for its configuration. * * @method */ ve.Surface.prototype.setupToolbars = function () { - var name, config, toolbar, + var name, config, toolbar, view, $toolbarView, toolbars = this.options.toolbars; for ( name in toolbars ) { config = toolbars[name]; if ( ve.isPlainObject( config ) ) { this.toolbars[name] = toolbar = { '$': $( '<div class="ve-ui-toolbar"></div>' ) }; - if ( name === 'top' ) { + for( view in config.views ) { + // Create a view element to place the tool groups in. + $toolbarView = $( '<div class="ve-ui-toolbar-view-' + view + '">' ) + .appendTo( toolbar.$ ); // Add extra sections to the toolbar - toolbar.$.append( - '<div class="ve-ui-actions"></div>' + - '<div style="clear:both"></div>' + - '<div class="ve-ui-toolbar-shadow"></div>' - ); - // Wrap toolbar for floating - toolbar.$wrapper = $( '<div class="ve-ui-toolbar-wrapper"></div>' ) - .append( this.toolbars[name].$ ); - // Add toolbar to surface - this.$.before( toolbar.$wrapper ); - if ( 'float' in config && config.float === true ) { - // Float top toolbar - this.floatTopToolbar(); - } + $toolbarView.append( '<div class="ve-ui-actions"></div>' ); + // Create a new toolbar per configured view + toolbar[view] = new ve.ui.Toolbar( $toolbarView, this, config.views[view].groups ); + // Register view. If the view is the edit view, + // use the Surface jQuery object. Otherwise, attach an empty container. + this.target.addView( view, { + '$': view === 'edit' ? this.$ : $( '<div>' ), + '$toolbar': $toolbarView + } ); } - toolbar.instance = new ve.ui.Toolbar( toolbar.$, this, config.tools ); + toolbar.$.append( + '<div style="clear:both"></div>' + + '<div class="ve-ui-toolbar-shadow"></div>' + ); + } + // Do special stuff to the top toolbar + if ( name === 'top' ) { + // Wrap toolbar for floating + toolbar.$wrapper = $( '<div class="ve-ui-toolbar-wrapper"></div>' ) + .append( toolbar.$ ); + // Add toolbar to surface + this.$.before( toolbar.$wrapper ); + if ( 'float' in config && config.float === true ) { + // Float top toolbar + this.floatTopToolbar(); + } } } }; -- To view, visit https://gerrit.wikimedia.org/r/50045 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Iff39266bdd3052f34bda254ca407030dbbc81f26 Gerrit-PatchSet: 1 Gerrit-Project: mediawiki/extensions/VisualEditor Gerrit-Branch: master Gerrit-Owner: Robmoen <rm...@wikimedia.org> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits