jenkins-bot has submitted this change and it was merged. Change subject: Provide a tool to insert a signature in namespaces that need it ......................................................................
Provide a tool to insert a signature in namespaces that need it VisualEditor is usually not enabled in talk namespaces... but sometimes it is. And when users see the button to edit with VE, they're going to click it and expect to be able to sign their posts. This tool is only loaded on talk pages and pages in additional namespaces defined in $wgExtraSignatureNamespaces. Code adapted with small tweaks from my own gadget <https://meta.wikimedia.org/wiki/User:Matma_Rex/visualeditor-signature.js?oldid=13461327>, which is already available under the MIT license. Changes include: * The tool is now always visible if the wiki allows signatures in any VE namespaces, but disabled when not allowed in the current namespace. * Register '~~~~' sequence to insert the signature. * Code style tweaks for stricter lint checks in this repository. * Documentation corrections. Swedish translation provided by André Costa (already credited as a translator as Lokal_Profil). Depends on changes in VisualEditor core: * I89fe53890ab59d12260ea6b41de802c38c24e8b9 * I14cd7efac521687ea38580341ae08ddc522edeeb Bug: T53154 Change-Id: I6be5fb2118cf3eef5098d4c5320228aa81411ccb --- M VisualEditor.hooks.php M extension.json A modules/ve-mw/ce/nodes/ve.ce.MWSignatureNode.js A modules/ve-mw/dm/nodes/ve.dm.MWSignatureNode.js M modules/ve-mw/i18n/en.json M modules/ve-mw/i18n/pl.json M modules/ve-mw/i18n/qqq.json M modules/ve-mw/i18n/sv.json M modules/ve-mw/init/ve.init.mw.TargetLoader.js A modules/ve-mw/ui/contextitems/ve.ui.MWSignatureContextItem.js A modules/ve-mw/ui/tools/ve.ui.MWSignatureTool.js M modules/ve-mw/ui/ve.ui.MWSequenceRegistry.js 12 files changed, 350 insertions(+), 5 deletions(-) Approvals: Jforrester: Looks good to me, approved Esanders: Looks good to me, but someone else must approve jenkins-bot: Verified diff --git a/VisualEditor.hooks.php b/VisualEditor.hooks.php index 4b65639..a6ee8dd 100644 --- a/VisualEditor.hooks.php +++ b/VisualEditor.hooks.php @@ -447,12 +447,15 @@ $thumbLimits = $coreConfig->get( 'ThumbLimits' ); $veConfig = ConfigFactory::getDefaultInstance()->makeConfig( 'visualeditor' ); $availableNamespaces = $veConfig->get( 'VisualEditorAvailableNamespaces' ); - $onNamespaces = array_keys( array_filter( $availableNamespaces ) ); + $enabledNamespaces = array_keys( array_filter( $availableNamespaces ) ); $vars['wgVisualEditorConfig'] = array( 'disableForAnons' => $veConfig->get( 'VisualEditorDisableForAnons' ), 'preferenceModules' => $veConfig->get( 'VisualEditorPreferenceModules' ), - 'namespaces' => $onNamespaces, + 'namespaces' => $enabledNamespaces, + 'signatureNamespaces' => array_values( + array_filter( $enabledNamespaces, 'MWNamespace::wantSignatures' ) + ), 'pluginModules' => array_merge( ExtensionRegistry::getInstance()->getAttribute( 'VisualEditorPluginModules' ), $veConfig->get( 'VisualEditorPluginModules' ) // @todo deprecate the global setting diff --git a/extension.json b/extension.json index 7ef959a..87aaf3c 100644 --- a/extension.json +++ b/extension.json @@ -1656,6 +1656,27 @@ "mobile" ] }, + "ext.visualEditor.mwsignature": { + "scripts": [ + "modules/ve-mw/dm/nodes/ve.dm.MWSignatureNode.js", + "modules/ve-mw/ce/nodes/ve.ce.MWSignatureNode.js", + "modules/ve-mw/ui/tools/ve.ui.MWSignatureTool.js", + "modules/ve-mw/ui/contextitems/ve.ui.MWSignatureContextItem.js" + ], + "dependencies": [ + "ext.visualEditor.core", + "ext.visualEditor.mwtransclusion", + "mediawiki.api", + "oojs-ui.styles.icons-alerts" + ], + "messages": [ + "visualeditor-mwsignature-tool" + ], + "targets": [ + "desktop", + "mobile" + ] + }, "ext.visualEditor.experimental": { "dependencies": [ "ext.visualEditor.language" diff --git a/modules/ve-mw/ce/nodes/ve.ce.MWSignatureNode.js b/modules/ve-mw/ce/nodes/ve.ce.MWSignatureNode.js new file mode 100644 index 0000000..7d1e8ff --- /dev/null +++ b/modules/ve-mw/ce/nodes/ve.ce.MWSignatureNode.js @@ -0,0 +1,112 @@ +/*! + * VisualEditor ContentEditable MWSignatureNode class. + * + * @copyright 2011-2015 VisualEditor Team and others; see AUTHORS.txt + * @license The MIT License (MIT); see LICENSE.txt + */ + +// Update the timestamp on inserted signatures every minute. +var liveSignatures = []; +setInterval( function () { + var updatedSignatures, i, sig; + updatedSignatures = []; + for ( i = 0; i < liveSignatures.length; i++ ) { + sig = liveSignatures[ i ]; + try { + sig.forceUpdate(); + updatedSignatures.push( sig ); + } catch ( er ) { + // Do nothing + } + } + liveSignatures = updatedSignatures; +}, 60 * 1000 ); + +/** + * ContentEditable MediaWiki signature node. This defines the behavior of the signature node + * inserted into the ContentEditable document. + * + * @class + * @extends ve.ce.MWTransclusionInlineNode + * + * @constructor + * @param {ve.dm.MWSignatureNode} model Model to observe + * @param {Object} [config] Configuration options + */ +ve.ce.MWSignatureNode = function VeCeMWSignatureNode( model ) { + // Parent constructor + ve.ce.MWTransclusionInlineNode.call( this, model ); + + // DOM changes + this.$element.addClass( 've-ce-mwSignatureNode' ); + + if ( this.isGenerating() ) { + // Use an initial rendering of '~~~~' as a placeholder to avoid + // the width changing when using the Sequence. + this.$element.text( '~~~~' ); + } + + // Keep track for magical text updating + liveSignatures.push( this ); +}; + +/* Inheritance */ + +OO.inheritClass( ve.ce.MWSignatureNode, ve.ce.MWTransclusionInlineNode ); + +/* Static Properties */ + +ve.ce.MWSignatureNode.static.name = 'mwSignature'; + +ve.ce.MWSignatureNode.static.tagName = 'span'; + +ve.ce.MWSignatureNode.static.primaryCommandName = 'mwSignature'; + +/* Methods */ + +/** + * @inheritdoc + */ +ve.ce.MWSignatureNode.prototype.generateContents = function () { + var wikitext, signatureNode, api, deferred, xhr; + // Parsoid doesn't support pre-save transforms. PHP parser doesn't support Parsoid's + // meta attributes (that may or may not be required). + + // We could try hacking up one (or even both) of these, but just calling the two parsers + // in order seems slightly saner. + + // We must have only one top-level node, this is the easiest way. + wikitext = '<span>~~~~</span>'; + signatureNode = this; + + api = new mw.Api(); + deferred = $.Deferred(); + xhr = api.post( { + action: 'parse', + text: wikitext, + contentmodel: 'wikitext', + prop: 'text', + onlypst: true + } ) + .done( function ( resp ) { + var wikitext = ve.getProp( resp, 'parse', 'text', '*' ); + if ( wikitext ) { + // Call parent method with the wikitext with PST applied. + ve.ce.MWSignatureNode.parent.prototype.generateContents.call( + signatureNode, + { wikitext: wikitext } + ).done( function ( nodes ) { + deferred.resolve( nodes ); + } ); + } else { + signatureNode.onParseError( deferred ); + } + } ) + .fail( this.onParseError.bind( this, deferred ) ); + + return deferred.promise( { abort: xhr.abort } ); +}; + +/* Registration */ + +ve.ce.nodeFactory.register( ve.ce.MWSignatureNode ); diff --git a/modules/ve-mw/dm/nodes/ve.dm.MWSignatureNode.js b/modules/ve-mw/dm/nodes/ve.dm.MWSignatureNode.js new file mode 100644 index 0000000..f4813d9 --- /dev/null +++ b/modules/ve-mw/dm/nodes/ve.dm.MWSignatureNode.js @@ -0,0 +1,70 @@ +/*! + * VisualEditor DataModel MWSignatureNode class. + * + * @copyright 2011-2015 VisualEditor Team and others; see AUTHORS.txt + * @license The MIT License (MIT); see LICENSE.txt + */ + +/** + * DataModel MediaWiki signature node. This defines the behavior of the data model for the + * signature, especially the fact that it needs to be converted into a wikitext signature on + * save. + * + * @class + * @extends ve.dm.MWTransclusionInlineNode + * + * @constructor + * @param {Object} [element] Reference to element in linear model + */ +ve.dm.MWSignatureNode = function VeDmMWSignatureNode( element ) { + // Parent constructor + ve.dm.MWTransclusionInlineNode.call( this, element ); +}; + +/* Inheritance */ + +OO.inheritClass( ve.dm.MWSignatureNode, ve.dm.MWTransclusionInlineNode ); + +/* Static members */ + +ve.dm.MWSignatureNode.static.name = 'mwSignature'; + +ve.dm.MWSignatureNode.static.matchTagNames = null; + +ve.dm.MWSignatureNode.static.matchRdfaTypes = []; + +ve.dm.MWSignatureNode.static.matchFunction = function () { + return false; +}; + +ve.dm.MWSignatureNode.static.getHashObject = function ( dataElement ) { + return { + type: dataElement.type + }; +}; + +ve.dm.MWSignatureNode.static.toDomElements = function ( dataElement, doc, converter ) { + dataElement = ve.dm.MWSignatureNode.static.toDataElement(); + return ve.dm.MWSignatureNode.parent.static.toDomElements( dataElement, doc, converter ); +}; + +ve.dm.MWSignatureNode.static.toDataElement = function () { + return { + type: 'mwTransclusionInline', + attributes: { + mw: { + parts: [ '~~~~' ] + } + } + }; +}; + +/* Methods */ + +ve.dm.MWSignatureNode.prototype.getPartsList = function () { + return [ { content: '~~~~' } ]; +}; + +/* Registration */ + +ve.dm.modelRegistry.register( ve.dm.MWSignatureNode ); diff --git a/modules/ve-mw/i18n/en.json b/modules/ve-mw/i18n/en.json index eb88667..7937666 100644 --- a/modules/ve-mw/i18n/en.json +++ b/modules/ve-mw/i18n/en.json @@ -284,6 +284,7 @@ "visualeditor-mweditmodesource-warning-switch-discard": "Discard changes", "visualeditor-mwgalleryinspector-placeholder": "Example.jpg|Caption for image", "visualeditor-mwgalleryinspector-title": "Gallery", + "visualeditor-mwsignature-tool": "Your signature", "visualeditor-pagemenu-tooltip": "Page options", "visualeditor-pagetranslationwarning": "You are editing a translatable page. Editing these in this editor is not yet officially supported.", "visualeditor-parameter-input-placeholder": "Field name", diff --git a/modules/ve-mw/i18n/pl.json b/modules/ve-mw/i18n/pl.json index 864479f..f759121 100644 --- a/modules/ve-mw/i18n/pl.json +++ b/modules/ve-mw/i18n/pl.json @@ -276,6 +276,7 @@ "visualeditor-mweditmodesource-warning-switch-discard": "Porzuć zmiany", "visualeditor-mwgalleryinspector-placeholder": "Przykład.jpg|Tytuł obrazu", "visualeditor-mwgalleryinspector-title": "Galeria", + "visualeditor-mwsignature-tool": "Twój podpis", "visualeditor-pagemenu-tooltip": "Opcje strony", "visualeditor-pagetranslationwarning": "Edytujesz stronę przeznaczoną do tłumaczenia. Jej edycja w tym edytorze nie jest jeszcze oficjalnie obsługiwana.", "visualeditor-parameter-input-placeholder": "Nazwa pola", diff --git a/modules/ve-mw/i18n/qqq.json b/modules/ve-mw/i18n/qqq.json index f6156cd..946fa8e 100644 --- a/modules/ve-mw/i18n/qqq.json +++ b/modules/ve-mw/i18n/qqq.json @@ -294,6 +294,7 @@ "visualeditor-mweditmodesource-warning-switch-discard": "Label for the discard changes button on the confirmation dialog for switching to source editing.", "visualeditor-mwgalleryinspector-placeholder": "Placeholder text for the gallery inspector demonstrating how gallery syntax works.", "visualeditor-mwgalleryinspector-title": "Used as title for the gallery inspector.\n{{Identical|Gallery}}", + "visualeditor-mwsignature-tool": "Used as name of the tool for inserting signatures.", "visualeditor-pagemenu-tooltip": "Tooltip text for the page menu which has the following items:\n* {{msg-mw|visualeditor-meta-tool}}\n* {{msg-mw|visualeditor-settings-tool}}\n* {{msg-mw|visualeditor-advancedsettings-tool}}\n* {{msg-mw|visualeditor-categories-tool}}\n* {{msg-mw|visualeditor-languages-tool}}\n* {{msg-mw|visualeditor-mweditmodesource-title}}\n* {{msg-mw|visualeditor-dialog-command-help-title}}", "visualeditor-pagetranslationwarning": "Edit notice shown when VisualEditor loads, warning users editing a translated page that it is not officially supported.", "visualeditor-parameter-input-placeholder": "Placeholder text label for an input for adding a parameter to a template.\n{{Identical|Field name}}", diff --git a/modules/ve-mw/i18n/sv.json b/modules/ve-mw/i18n/sv.json index e175b02..c0f045e 100644 --- a/modules/ve-mw/i18n/sv.json +++ b/modules/ve-mw/i18n/sv.json @@ -275,6 +275,7 @@ "visualeditor-mweditmodesource-warning-switch-discard": "Överge ändringar", "visualeditor-mwgalleryinspector-placeholder": "Example.jpg|Bildtext", "visualeditor-mwgalleryinspector-title": "Galleri", + "visualeditor-mwsignature-tool": "Din signatur", "visualeditor-pagemenu-tooltip": "Sidalternativ", "visualeditor-pagetranslationwarning": "Du redigerar en översättbar sida. Redigering av dessa i denna redigerare stöds ännu inte officiellt.", "visualeditor-parameter-input-placeholder": "Fältnamn", diff --git a/modules/ve-mw/init/ve.init.mw.TargetLoader.js b/modules/ve-mw/init/ve.init.mw.TargetLoader.js index 585f7bf..e0aff5b 100644 --- a/modules/ve-mw/init/ve.init.mw.TargetLoader.js +++ b/modules/ve-mw/init/ve.init.mw.TargetLoader.js @@ -39,6 +39,11 @@ modules.push( 'ext.visualEditor.mwreference' ); } + // Allow signing posts in select namespaces + if ( conf.signatureNamespaces.length ) { + modules.push( 'ext.visualEditor.mwsignature' ); + } + // Add preference modules for ( prefName in conf.preferenceModules ) { prefValue = mw.user.options.get( prefName ); diff --git a/modules/ve-mw/ui/contextitems/ve.ui.MWSignatureContextItem.js b/modules/ve-mw/ui/contextitems/ve.ui.MWSignatureContextItem.js new file mode 100644 index 0000000..ecf6acd --- /dev/null +++ b/modules/ve-mw/ui/contextitems/ve.ui.MWSignatureContextItem.js @@ -0,0 +1,59 @@ +/*! + * VisualEditor MWSignatureContextItem class. + * + * @copyright 2011-2015 VisualEditor Team and others; see http://ve.mit-license.org + */ + +/** + * Context item for a MWSignature. + * + * @class + * @extends ve.ui.MWTransclusionContextItem + * + * @constructor + * @param {ve.ui.Context} context Context item is in + * @param {ve.dm.Model} model Model item is related to + * @param {Object} config Configuration options + */ +ve.ui.MWSignatureContextItem = function VeUiMWSignatureContextItem() { + // Parent constructor + ve.ui.MWSignatureContextItem.super.apply( this, arguments ); + + // Initialization + this.$element.addClass( 've-ui-mwSignatureContextItem' ); + this.$body.remove(); + this.$info.remove(); + this.$actions.remove(); +}; + +/* Inheritance */ + +OO.inheritClass( ve.ui.MWSignatureContextItem, ve.ui.MWTransclusionContextItem ); + +/* Static Properties */ + +ve.ui.MWSignatureContextItem.static.editable = false; + +ve.ui.MWSignatureContextItem.static.name = 'mwSignature'; + +ve.ui.MWSignatureContextItem.static.icon = 'signature'; + +ve.ui.MWSignatureContextItem.static.label = + OO.ui.deferMsg( 'visualeditor-mwsignature-tool' ); + +ve.ui.MWSignatureContextItem.static.modelClasses = [ ve.dm.MWSignatureNode ]; + +ve.ui.MWSignatureContextItem.static.commandName = 'mwSignature'; + +/* Methods */ + +/** + * @inheritdoc + */ +ve.ui.MWSignatureContextItem.prototype.getDescription = function () { + return ''; +}; + +/* Registration */ + +ve.ui.contextItemFactory.register( ve.ui.MWSignatureContextItem ); diff --git a/modules/ve-mw/ui/tools/ve.ui.MWSignatureTool.js b/modules/ve-mw/ui/tools/ve.ui.MWSignatureTool.js new file mode 100644 index 0000000..a82071f --- /dev/null +++ b/modules/ve-mw/ui/tools/ve.ui.MWSignatureTool.js @@ -0,0 +1,74 @@ +/*! + * VisualEditor MediaWiki UserInterface signature tool class. + * + * @copyright 2011-2015 VisualEditor Team and others; see AUTHORS.txt + * @license The MIT License (MIT); see LICENSE.txt + */ + +var allowsSignatures = $.inArray( + new mw.Title( mw.config.get( 'wgRelevantPageName' ) ).getNamespaceId(), + mw.config.get( 'wgVisualEditorConfig' ).signatureNamespaces +) !== -1; + +/** + * MediaWiki UserInterface signature tool. This defines the menu button and its action. + * + * @class + * @extends ve.ui.MWTransclusionDialogTool + * @constructor + * @param {OO.ui.ToolGroup} toolGroup + * @param {Object} [config] Configuration options + */ +ve.ui.MWSignatureTool = function VeUiMWSignatureTool( toolGroup, config ) { + // Parent constructor + ve.ui.MWTransclusionDialogTool.call( this, toolGroup, config ); +}; +OO.inheritClass( ve.ui.MWSignatureTool, ve.ui.MWTransclusionDialogTool ); + +ve.ui.MWSignatureTool.static.name = 'mwSignature'; +ve.ui.MWSignatureTool.static.group = 'object'; +ve.ui.MWSignatureTool.static.icon = 'signature'; +ve.ui.MWSignatureTool.static.title = + OO.ui.deferMsg( 'visualeditor-mwsignature-tool' ); +ve.ui.MWSignatureTool.static.modelClasses = [ ve.dm.MWSignatureNode ]; +// Link the tool to the command defined below +ve.ui.MWSignatureTool.static.commandName = 'mwSignature'; + +ve.ui.toolFactory.register( ve.ui.MWSignatureTool ); + +if ( allowsSignatures ) { + // Command to insert signature node. + ve.ui.commandRegistry.register( + new ve.ui.Command( 'mwSignature', 'content', 'insert', { + args: [ + [ + { type: 'mwSignature' }, + { type: '/mwSignature' } + ], + // annotate + false, + // collapseToEnd + true + ] + } ) + ); + ve.ui.sequenceRegistry.register( + new ve.ui.Sequence( 'wikitextSignature', 'mwSignature', '~~~~', 4 ) + ); + ve.ui.commandHelpRegistry.register( 'insert', 'mwSignature', { + sequences: [ 'wikitextSignature' ], + label: OO.ui.deferMsg( 'visualeditor-mwsignature-tool' ) + } ); +} else { + // No-op command that is never executable + ve.ui.commandRegistry.register( + new ve.ui.Command( 'mwSignature', 'content', 'insert', { + args: [ [] ], + supportedSelections: [] + } ) + ); + // Wikitext insertion warning + ve.ui.sequenceRegistry.register( + new ve.ui.Sequence( 'wikitextSignature', 'mwWikitextWarning', '~~~' ) + ); +} diff --git a/modules/ve-mw/ui/ve.ui.MWSequenceRegistry.js b/modules/ve-mw/ui/ve.ui.MWSequenceRegistry.js index 20b3769..caab4f9 100644 --- a/modules/ve-mw/ui/ve.ui.MWSequenceRegistry.js +++ b/modules/ve-mw/ui/ve.ui.MWSequenceRegistry.js @@ -12,9 +12,6 @@ new ve.ui.Sequence( 'wikitextNowiki', 'mwWikitextWarning', '<nowiki' ) ); ve.ui.sequenceRegistry.register( - new ve.ui.Sequence( 'wikitextSig', 'mwWikitextWarning', '~~~' ) -); -ve.ui.sequenceRegistry.register( new ve.ui.Sequence( 'wikitextHeading', 'heading2', [ { type: 'paragraph' }, '=', '=' ], 2 ) ); ve.ui.sequenceRegistry.register( -- To view, visit https://gerrit.wikimedia.org/r/251834 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: merged Gerrit-Change-Id: I6be5fb2118cf3eef5098d4c5320228aa81411ccb Gerrit-PatchSet: 9 Gerrit-Project: mediawiki/extensions/VisualEditor Gerrit-Branch: master Gerrit-Owner: Bartosz Dziewoński <[email protected]> Gerrit-Reviewer: Alex Monk <[email protected]> Gerrit-Reviewer: Bartosz Dziewoński <[email protected]> Gerrit-Reviewer: Esanders <[email protected]> Gerrit-Reviewer: Jforrester <[email protected]> Gerrit-Reviewer: Siebrand <[email protected]> Gerrit-Reviewer: jenkins-bot <> _______________________________________________ MediaWiki-commits mailing list [email protected] https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits
