diff --git a/VisualEditor.i18n.php b/VisualEditor.i18n.php index e8579626d2..14dc896940 100644 --- a/VisualEditor.i18n.php +++ b/VisualEditor.i18n.php @@ -47,6 +47,7 @@ $messages['en'] = array( 'visualeditor-beta-label' => 'beta', 'visualeditor-beta-warning' => 'VisualEditor is in \'beta\'. You may encounter software issues, and you may not be able to edit parts of the page. Click "{{int:visualeditor-ca-editsource}}" to switch to wikitext mode – unsaved changes will be lost.', 'visualeditor-browserwarning' => 'You are using a browser which is not officially supported by VisualEditor.', + 'visualeditor-categories-tool' => 'Categories', 'visualeditor-ca-createsource' => 'Create source', 'visualeditor-ca-editsource' => 'Edit source', 'visualeditor-ca-editsource-section' => 'edit source', @@ -137,6 +138,7 @@ $messages['en'] = array( 'visualeditor-historybutton-undo-tooltip' => 'Undo', 'visualeditor-indentationbutton-indent-tooltip' => 'Increase indentation', 'visualeditor-indentationbutton-outdent-tooltip' => 'Decrease indentation', + 'visualeditor-languages-tool' => 'Languages', 'visualeditor-languageinspector-block-tooltip' => 'Language block: $1', 'visualeditor-languageinspector-block-tooltip-rtldirection' => ': Right to Left', 'visualeditor-languageinspector-title' => 'Language', @@ -310,6 +312,7 @@ See also: Refers to {{msg-mw|Visualeditor-ca-editsource}}.", 'visualeditor-browserwarning' => 'Edit notice shown when VisualEditor loads, warning users that their browser is not officially supported', + 'visualeditor-categories-tool' => 'Tool for opening the categories section of the meta dialog.', 'visualeditor-ca-createsource' => 'Text for the create source link in the tab dropdown, if the page doesn\'t exist. It\'s shown next to the message {{msg-mw|vector-view-create}}, so they should be similar (for example, use a similar translation for "Create"). If the page exists, the following link text is used: {{msg-mw|Visualeditor-ca-editsource}}', @@ -483,6 +486,7 @@ Parameters: {{Identical|Undo}}', 'visualeditor-indentationbutton-indent-tooltip' => 'Tooltip text for list indent button', 'visualeditor-indentationbutton-outdent-tooltip' => 'Tooltip text for list outdent button', + 'visualeditor-languages-tool' => 'Tool for opening the languages links section of the meta dialog.', 'visualeditor-languageinspector-block-tooltip' => 'Tooltip identifying language block properties inside VisualEditor. A "language block" is an element that is written in a language that is different from the surrounding language. For example, it can be the Belarusian name of a Belarusian person in the French Wikipedia. diff --git a/VisualEditor.php b/VisualEditor.php index 8640eb941d..ee53c703b7 100644 --- a/VisualEditor.php +++ b/VisualEditor.php @@ -532,6 +532,7 @@ $wgResourceModules += array( 've/ui/actions/ve.ui.AnnotationAction.js', 've/ui/actions/ve.ui.ContentAction.js', + 've/ui/actions/ve.ui.DialogAction.js', 've/ui/actions/ve.ui.FormatAction.js', 've/ui/actions/ve.ui.HistoryAction.js', 've/ui/actions/ve.ui.IndentationAction.js', @@ -619,6 +620,7 @@ $wgResourceModules += array( 'visualeditor-beta-label', 'visualeditor-beta-warning', 'visualeditor-browserwarning', + 'visualeditor-categories-tool', 'visualeditor-clearbutton-tooltip', 'visualeditor-dialog-action-apply', 'visualeditor-dialog-action-cancel', @@ -693,6 +695,7 @@ $wgResourceModules += array( 'visualeditor-historybutton-undo-tooltip', 'visualeditor-indentationbutton-indent-tooltip', 'visualeditor-indentationbutton-outdent-tooltip', + 'visualeditor-languages-tool', 'visualeditor-linkinspector-illegal-title', 'visualeditor-linkinspector-suggest-external-link', 'visualeditor-linkinspector-suggest-matching-page', diff --git a/demos/ve/index.php b/demos/ve/index.php index 4414ff34e1..6222b9d2c6 100644 --- a/demos/ve/index.php +++ b/demos/ve/index.php @@ -290,6 +290,7 @@ $html = file_get_contents( $page ); + diff --git a/modules/oojs-ui/OO.ui.Dialog.js b/modules/oojs-ui/OO.ui.Dialog.js index 6c338ce543..7a49528f7c 100644 --- a/modules/oojs-ui/OO.ui.Dialog.js +++ b/modules/oojs-ui/OO.ui.Dialog.js @@ -116,11 +116,12 @@ OO.ui.Dialog.prototype.onFrameDocumentKeyDown = function ( e ) { * Wraps the parent open method. Disables native top-level window scrolling behavior. * * @method + * @param {Object} [config] Configuration options for window setup * @fires setup * @fires open */ -OO.ui.Dialog.prototype.open = function () { - OO.ui.Window.prototype.open.call( this ); +OO.ui.Dialog.prototype.open = function ( config ) { + OO.ui.Window.prototype.open.call( this, config ); // Prevent scrolling in top-level window $( window ).on( 'mousewheel', this.onWindowMouseWheelHandler ); $( document ).on( 'keydown', this.onDocumentKeyDownHandler ); diff --git a/modules/oojs-ui/OO.ui.Window.js b/modules/oojs-ui/OO.ui.Window.js index 584920b7fa..210261e561 100644 --- a/modules/oojs-ui/OO.ui.Window.js +++ b/modules/oojs-ui/OO.ui.Window.js @@ -60,17 +60,15 @@ OO.mixinClass( OO.ui.Window, OO.EventEmitter ); /** * @event setup - * @param {OO.ui.Window} win Window that's been setup + * @param {Object} config Configuration options for window setup */ /** * @event open - * @param {OO.ui.Window} win Window that's been opened */ /** * @event close - * @param {OO.ui.Window} win Window that's been closed * @param {string} action Action that caused the window to be closed */ @@ -141,6 +139,7 @@ OO.ui.Window.prototype.initialize = function () { * To be notified after this method is called, listen to the `setup` event. * * @method + * @param {Object} [config] Configuration options for window setup */ OO.ui.Window.prototype.onSetup = function () { // This is a stub, override functionality in child classes @@ -281,14 +280,15 @@ OO.ui.Window.prototype.setPosition = function ( left, top ) { * Open window. * * @method + * @param {Object} [config] Configuration options for window setup * @fires setup * @fires open */ -OO.ui.Window.prototype.open = function () { +OO.ui.Window.prototype.open = function ( config ) { if ( !this.opening ) { this.opening = true; - this.onSetup(); - this.emit( 'setup' ); + this.onSetup( config ); + this.emit( 'setup', config ); this.$.show(); this.visible = true; this.frame.$.focus(); diff --git a/modules/oojs-ui/OO.ui.WindowSet.js b/modules/oojs-ui/OO.ui.WindowSet.js index 8a30c7a836..4bad3d44fb 100644 --- a/modules/oojs-ui/OO.ui.WindowSet.js +++ b/modules/oojs-ui/OO.ui.WindowSet.js @@ -63,10 +63,11 @@ OO.mixinClass( OO.ui.WindowSet, OO.EventEmitter ); * * @method * @param {OO.ui.Window} win Window that's been setup + * @param {Object} [config] Configuration options for window setup * @fires setup */ -OO.ui.WindowSet.prototype.onWindowSetup = function ( win ) { - this.emit( 'setup', win ); +OO.ui.WindowSet.prototype.onWindowSetup = function ( win, config ) { + this.emit( 'setup', win, config ); }; /** @@ -108,10 +109,9 @@ OO.ui.WindowSet.prototype.getCurrent = function () { * Return a given window. * * @param {string} name Symbolic name of window - * @param {Object} [config] Configuration options to be sent to the window class constructor * @return {OO.ui.Window} Window with specified name */ -OO.ui.WindowSet.prototype.getWindow = function ( name, config ) { +OO.ui.WindowSet.prototype.getWindow = function ( name ) { var win; if ( !this.factory.lookup( name ) ) { @@ -121,7 +121,7 @@ OO.ui.WindowSet.prototype.getWindow = function ( name, config ) { throw new Error( 'Cannot open another window while another one is active' ); } if ( !( name in this.windows ) ) { - win = this.windows[name] = this.factory.create( name, this, config ); + win = this.windows[name] = this.factory.create( name, this, { '$$': this.$$ } ); win.connect( this, { 'setup': ['onWindowSetup', win], 'open': ['onWindowOpen', win], @@ -139,10 +139,10 @@ OO.ui.WindowSet.prototype.getWindow = function ( name, config ) { * Any already open dialog will be closed. * * @param {string} name Symbolic name of window - * @param {Object} [config] Config options to be sent to the window class constructor + * @param {Object} [config] Configuration options for window setup * @chainable */ OO.ui.WindowSet.prototype.open = function ( name, config ) { - this.getWindow( name, config ).open(); + this.getWindow( name ).open( config ); return this; }; diff --git a/modules/oojs-ui/layouts/OO.ui.PagedOutlineLayout.js b/modules/oojs-ui/layouts/OO.ui.PagedOutlineLayout.js index 1dbab7417d..1a1d36f842 100644 --- a/modules/oojs-ui/layouts/OO.ui.PagedOutlineLayout.js +++ b/modules/oojs-ui/layouts/OO.ui.PagedOutlineLayout.js @@ -157,7 +157,7 @@ OO.ui.PagedOutlineLayout.prototype.onPagedLayoutSet = function ( page ) { */ OO.ui.PagedOutlineLayout.prototype.onPageOutlineSelect = function ( item ) { if ( item ) { - this.setPage( item.getData() ); + OO.ui.PagedLayout.prototype.setPage.call( this, item.getData() ); } }; @@ -193,3 +193,12 @@ OO.ui.PagedOutlineLayout.prototype.updateOutlineWidget = function () { return this; }; + +/** + * @inheritdoc + */ +OO.ui.PagedOutlineLayout.prototype.setPage = function ( name ) { + if ( name !== this.outlineWidget.getSelectedItem().getData() ) { + this.outlineWidget.selectItem( this.outlineWidget.getItemFromData( name ) ); + } +}; diff --git a/modules/ve-mw/ce/nodes/ve.ce.MWBlockImageNode.js b/modules/ve-mw/ce/nodes/ve.ce.MWBlockImageNode.js index e9779ddb47..18590037a9 100644 --- a/modules/ve-mw/ce/nodes/ve.ce.MWBlockImageNode.js +++ b/modules/ve-mw/ce/nodes/ve.ce.MWBlockImageNode.js @@ -154,7 +154,7 @@ ve.ce.MWBlockImageNode.prototype.getCssClass = function ( type, alignment ) { * * @method */ -ve.ce.MWBlockImageNode.prototype.onSetup = function ( ) { +ve.ce.MWBlockImageNode.prototype.onSetup = function () { var type = this.model.getAttribute( 'type' ); ve.ce.BranchNode.prototype.onSetup.call( this ); diff --git a/modules/ve-mw/init/targets/ve.init.mw.ViewPageTarget.js b/modules/ve-mw/init/targets/ve.init.mw.ViewPageTarget.js index 1191931296..0a599273b9 100644 --- a/modules/ve-mw/init/targets/ve.init.mw.ViewPageTarget.js +++ b/modules/ve-mw/init/targets/ve.init.mw.ViewPageTarget.js @@ -1091,7 +1091,13 @@ ve.init.mw.ViewPageTarget.prototype.attachToolbarButtons = function () { $pushButtons = $( '
' ), actions = new ve.ui.TargetToolbar( this, this.surface ); - actions.setup( [ { 'include': [ 'help', 'notices', 'meta' ] } ] ); + actions.setup( [ + { 'include': [ 'help', 'notices' ] }, + { + 'type': 'list', + 'icon': 'menu', + 'include': [ 'meta', 'categories', 'languages' ] } + ] ); $actionTools .addClass( 've-init-mw-viewPageTarget-toolbar-utilites' ) diff --git a/modules/ve-mw/ui/dialogs/ve.ui.MWMetaDialog.js b/modules/ve-mw/ui/dialogs/ve.ui.MWMetaDialog.js index d0d47ae03b..37931a3060 100644 --- a/modules/ve-mw/ui/dialogs/ve.ui.MWMetaDialog.js +++ b/modules/ve-mw/ui/dialogs/ve.ui.MWMetaDialog.js @@ -47,7 +47,9 @@ ve.ui.MWMetaDialog.static.icon = 'settings'; /* Methods */ -/** */ +/** + * @inheritdoc + */ ve.ui.MWMetaDialog.prototype.initialize = function () { var languagePromise; @@ -158,7 +160,20 @@ ve.ui.MWMetaDialog.prototype.initialize = function () { }, this ) ); }; -/** */ +/** + * @inheritdoc + */ +ve.ui.MWMetaDialog.prototype.onSetup = function ( config ) { + // Parent method + ve.ui.MWDialog.prototype.onSetup.call( this, config ); + if ( config && config.page && this.pagedOutlineLayout.getPage( config.page ) ) { + this.pagedOutlineLayout.setPage( config.page ); + } +}; + +/** + * @inheritdoc + */ ve.ui.MWMetaDialog.prototype.onOpen = function () { var surfaceModel = this.surface.getModel(), categoryWidget = this.categoryWidget, @@ -182,7 +197,9 @@ ve.ui.MWMetaDialog.prototype.onOpen = function () { } ); }; -/** */ +/** + * @inheritdoc + */ ve.ui.MWMetaDialog.prototype.onClose = function ( action ) { var hasTransactions, newDefaultSortKeyItem, newDefaultSortKeyItemData, surfaceModel = this.surface.getModel(), diff --git a/modules/ve-mw/ui/tools/ve.ui.MWDialogTool.js b/modules/ve-mw/ui/tools/ve.ui.MWDialogTool.js index fb914de412..ce945d8a60 100644 --- a/modules/ve-mw/ui/tools/ve.ui.MWDialogTool.js +++ b/modules/ve-mw/ui/tools/ve.ui.MWDialogTool.js @@ -134,3 +134,47 @@ ve.ui.MWMetaDialogTool.static.titleMessage = 'visualeditor-meta-tool'; ve.ui.MWMetaDialogTool.static.dialog = 'meta'; ve.ui.MWMetaDialogTool.static.autoAdd = false; ve.ui.toolFactory.register( ve.ui.MWMetaDialogTool ); + +/** + * MediaWiki UserInterface categories tool. + * + * @class + * @extends ve.ui.DialogTool + * @constructor + * @param {OO.ui.Toolbar} toolbar + * @param {Object} [config] Configuration options + */ +ve.ui.MWCategoriesDialogTool = function VeUiMWCategoriesDialogTool( toolbar, config ) { + ve.ui.DialogTool.call( this, toolbar, config ); +}; +OO.inheritClass( ve.ui.MWCategoriesDialogTool, ve.ui.DialogTool ); +ve.ui.MWCategoriesDialogTool.static.name = 'categories'; +ve.ui.MWCategoriesDialogTool.static.group = 'utility'; +ve.ui.MWCategoriesDialogTool.static.icon = 'tag'; +ve.ui.MWCategoriesDialogTool.static.titleMessage = 'visualeditor-categories-tool'; +ve.ui.MWCategoriesDialogTool.static.dialog = 'meta'; +ve.ui.MWCategoriesDialogTool.static.config = { 'page': 'categories' }; +ve.ui.MWCategoriesDialogTool.static.autoAdd = false; +ve.ui.toolFactory.register( ve.ui.MWCategoriesDialogTool ); + +/** + * MediaWiki UserInterface languages tool. + * + * @class + * @extends ve.ui.DialogTool + * @constructor + * @param {OO.ui.Toolbar} toolbar + * @param {Object} [config] Configuration options + */ +ve.ui.MWLanguagesDialogTool = function VeUiMWLanguagesDialogTool( toolbar, config ) { + ve.ui.DialogTool.call( this, toolbar, config ); +}; +OO.inheritClass( ve.ui.MWLanguagesDialogTool, ve.ui.DialogTool ); +ve.ui.MWLanguagesDialogTool.static.name = 'languages'; +ve.ui.MWLanguagesDialogTool.static.group = 'utility'; +ve.ui.MWLanguagesDialogTool.static.icon = 'language'; +ve.ui.MWLanguagesDialogTool.static.titleMessage = 'visualeditor-languages-tool'; +ve.ui.MWLanguagesDialogTool.static.dialog = 'meta'; +ve.ui.MWLanguagesDialogTool.static.config = { 'page': 'languages' }; +ve.ui.MWLanguagesDialogTool.static.autoAdd = false; +ve.ui.toolFactory.register( ve.ui.MWLanguagesDialogTool ); diff --git a/modules/ve/test/index.php b/modules/ve/test/index.php index 63254db408..cb4b03c227 100644 --- a/modules/ve/test/index.php +++ b/modules/ve/test/index.php @@ -234,6 +234,7 @@ + diff --git a/modules/ve/ui/actions/ve.ui.DialogAction.js b/modules/ve/ui/actions/ve.ui.DialogAction.js new file mode 100644 index 0000000000..78b2782364 --- /dev/null +++ b/modules/ve/ui/actions/ve.ui.DialogAction.js @@ -0,0 +1,52 @@ +/*! + * VisualEditor UserInterface DialogAction class. + * + * @copyright 2011-2013 VisualEditor Team and others; see AUTHORS.txt + * @license The MIT License (MIT); see LICENSE.txt + */ + +/** + * Dialog action. + * + * @class + * @extends ve.ui.Action + * @constructor + * @param {ve.ui.Surface} surface Surface to act on + */ +ve.ui.DialogAction = function VeUiDialogAction( surface ) { + // Parent constructor + ve.ui.Action.call( this, surface ); +}; + +/* Inheritance */ + +OO.inheritClass( ve.ui.DialogAction, ve.ui.Action ); + +/* Static Properties */ + +ve.ui.DialogAction.static.name = 'dialog'; + +/** + * List of allowed methods for the action. + * + * @static + * @property + */ +ve.ui.DialogAction.static.methods = [ 'open' ]; + +/* Methods */ + +/** + * Open an Dialog. + * + * @method + * @param {string} name Symbolic name of Dialog to open + * @param {Object} [config] Configuration options for dialog setup + */ +ve.ui.DialogAction.prototype.open = function ( name, config ) { + this.surface.getDialogs().open( name, config ); +}; + +/* Registration */ + +ve.ui.actionFactory.register( ve.ui.DialogAction ); diff --git a/modules/ve/ui/actions/ve.ui.InspectorAction.js b/modules/ve/ui/actions/ve.ui.InspectorAction.js index e36952b4f9..bc53636a17 100644 --- a/modules/ve/ui/actions/ve.ui.InspectorAction.js +++ b/modules/ve/ui/actions/ve.ui.InspectorAction.js @@ -41,9 +41,10 @@ ve.ui.InspectorAction.static.methods = [ 'open' ]; * * @method * @param {string} name Symbolic name of inspector to open + * @param {Object} [config] Configuration options for inspector setup */ -ve.ui.InspectorAction.prototype.open = function ( name ) { - this.surface.getContext().openInspector( name ); +ve.ui.InspectorAction.prototype.open = function ( name, config ) { + this.surface.getContext().openInspector( name, config ); }; /* Registration */ diff --git a/modules/ve/ui/inspectors/ve.ui.AnnotationInspector.js b/modules/ve/ui/inspectors/ve.ui.AnnotationInspector.js index 1fe5ac469c..ce7da586ca 100644 --- a/modules/ve/ui/inspectors/ve.ui.AnnotationInspector.js +++ b/modules/ve/ui/inspectors/ve.ui.AnnotationInspector.js @@ -52,14 +52,15 @@ ve.ui.AnnotationInspector.static.modelClasses = []; * - Selection covering annotated text -> expand selection to cover annotation * * @method + * @param {Object} [config] Configuration options for inspector setup */ -ve.ui.AnnotationInspector.prototype.onSetup = function () { +ve.ui.AnnotationInspector.prototype.onSetup = function ( config ) { var expandedFragment, trimmedFragment, truncatedFragment, fragment = this.surface.getModel().getFragment( null, true ), annotation = this.getMatchingAnnotations( fragment, true ).get( 0 ); // Parent method - ve.ui.SurfaceInspector.prototype.onSetup.call( this ); + ve.ui.SurfaceInspector.prototype.onSetup.call( this, config ); // Initialize range if ( !annotation ) { if ( fragment.getRange().isCollapsed() && !this.surface.view.hasSlugAtOffset( fragment.getRange().start ) ) { diff --git a/modules/ve/ui/inspectors/ve.ui.LanguageInspector.js b/modules/ve/ui/inspectors/ve.ui.LanguageInspector.js index 53c32c3a16..a149690fb9 100644 --- a/modules/ve/ui/inspectors/ve.ui.LanguageInspector.js +++ b/modules/ve/ui/inspectors/ve.ui.LanguageInspector.js @@ -86,8 +86,10 @@ ve.ui.LanguageInspector.prototype.onOpen = function () { * Make sure the initial language and direction are set by the parent * of the DOM element of the selected fragment before the rest of the * onSetup method is processed by the parent ve.ui.AnnotationInspector + * + * @param {Object} [config] Configuration options for inspector setup */ -ve.ui.LanguageInspector.prototype.onSetup = function () { +ve.ui.LanguageInspector.prototype.onSetup = function ( config ) { var fragDOM, fragment = this.surface.getModel().getFragment( null, true ); @@ -103,7 +105,7 @@ ve.ui.LanguageInspector.prototype.onSetup = function () { } // Parent method - ve.ui.AnnotationInspector.prototype.onSetup.call( this ); + ve.ui.AnnotationInspector.prototype.onSetup.call( this, config ); }; diff --git a/modules/ve/ui/tools/ve.ui.DialogTool.js b/modules/ve/ui/tools/ve.ui.DialogTool.js index 614fcdd04a..7a53caec23 100644 --- a/modules/ve/ui/tools/ve.ui.DialogTool.js +++ b/modules/ve/ui/tools/ve.ui.DialogTool.js @@ -36,6 +36,16 @@ OO.inheritClass( ve.ui.DialogTool, OO.ui.Tool ); */ ve.ui.DialogTool.static.dialog = ''; +/** + * Configuration options for setting up dialog. + * + * @abstract + * @static + * @property {Object} + * @inheritable + */ +ve.ui.DialogTool.static.config = {}; + /** * Annotation or node models this tool is related to. * @@ -62,7 +72,12 @@ ve.ui.DialogTool.static.isCompatibleWith = function ( model ) { * @method */ ve.ui.DialogTool.prototype.onSelect = function () { - this.toolbar.getSurface().getDialogs().open( this.constructor.static.dialog ); + this.toolbar.getSurface().execute( + 'dialog', + 'open', + this.constructor.static.dialog, + this.constructor.static.config + ); this.setActive( false ); }; diff --git a/modules/ve/ui/tools/ve.ui.InspectorTool.js b/modules/ve/ui/tools/ve.ui.InspectorTool.js index 437d3cd5be..f228333202 100644 --- a/modules/ve/ui/tools/ve.ui.InspectorTool.js +++ b/modules/ve/ui/tools/ve.ui.InspectorTool.js @@ -36,6 +36,16 @@ OO.inheritClass( ve.ui.InspectorTool, OO.ui.Tool ); */ ve.ui.InspectorTool.static.inspector = ''; +/** + * Configuration options for setting up inspector. + * + * @abstract + * @static + * @property {Object} + * @inheritable + */ +ve.ui.InspectorTool.static.config = {}; + /** * Annotation or node models this tool is related to. * @@ -62,7 +72,12 @@ ve.ui.InspectorTool.static.isCompatibleWith = function ( model ) { * @method */ ve.ui.InspectorTool.prototype.onSelect = function () { - this.toolbar.getSurface().execute( 'inspector', 'open', this.constructor.static.inspector ); + this.toolbar.getSurface().execute( + 'inspector', + 'open', + this.constructor.static.inspector, + this.constructor.static.config + ); this.setActive( false ); };