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

Reply via email to