jenkins-bot has submitted this change and it was merged.

Change subject: Split off setup from the rest of mw.ViewPageTarget
......................................................................


Split off setup from the rest of mw.ViewPageTarget

Initialisation initialisation? It's time to rename ve.init
to ve.platform and ve.init.Platform to ve.platform.Environment,
but that'll come later.

* Moved support detection and skin set up to separate class-less
  file.
* Swapped usage of ve.msg for mw.msg.
* Callback of edit tab now does an mw.loader call to fetch
  the actual VisualEditor libraries.
  Though mw.loader won't load the same thing twice, we would
  bind a callback each time. To avoid instantiating ViewPageTarget
  more than once we use a Deferred.

Bug: 50542
Bug: 50608
Bug: 50612
Change-Id: Ic8b0004ab5288fa91bb29d496485b93ffd8d977e
---
M VisualEditor.hooks.php
M VisualEditor.php
A modules/ve-mw/init/targets/ve.init.mw.ViewPageTarget.init.js
M modules/ve-mw/init/targets/ve.init.mw.ViewPageTarget.js
M modules/ve-mw/test/init/targets/ve.init.mw.ViewPageTarget.test.js
5 files changed, 253 insertions(+), 160 deletions(-)

Approvals:
  Catrope: Looks good to me, approved
  jenkins-bot: Verified



diff --git a/VisualEditor.hooks.php b/VisualEditor.hooks.php
index 59149f2..aefa361 100644
--- a/VisualEditor.hooks.php
+++ b/VisualEditor.hooks.php
@@ -85,7 +85,7 @@
                        if ( $wgVisualEditorEnableEventLogging ) {
                                $output->addModules( array( 'schema.Edit' ) );
                        }
-                       $output->addModules( array( 
'ext.visualEditor.viewPageTarget' ) );
+                       $output->addModules( array( 
'ext.visualEditor.viewPageTarget.init' ) );
                } else {
                        if ( $wgVisualEditorEnableEventLogging ) {
                                $output->addModules( array( 'schema.Edit', 
'ext.visualEditor.splitTest' ) );
@@ -226,6 +226,7 @@
                                'ext.visualEditor.standalone',
                                'ext.visualEditor.core',
                                'ext.visualEditor.experimental',
+                               'ext.visualEditor.viewPageTarget.init',
                                'ext.visualEditor.viewPageTarget',
                        ),
                        'localBasePath' => dirname( __FILE__ ) . '/modules',
diff --git a/VisualEditor.php b/VisualEditor.php
index 738a7f4..87244ca 100644
--- a/VisualEditor.php
+++ b/VisualEditor.php
@@ -152,6 +152,27 @@
                        
've-mw/init/styles/ve.init.mw.ViewPageTarget.Icons-vector.css',
                ),
        ),
+       'ext.visualEditor.viewPageTarget.init' => 
$wgVisualEditorResourceTemplate + array(
+               'scripts' => array(
+                       've-mw/init/targets/ve.init.mw.ViewPageTarget.init.js',
+               ),
+               'dependencies' => array(
+                       'jquery.client',
+                       'mediawiki.Uri',
+                       'mediawiki.util',
+               ),
+               'messages' => array(
+                       'accesskey-ca-ve-edit',
+                       'tooltip-ca-createsource',
+                       'tooltip-ca-editsource',
+                       'tooltip-ca-ve-edit',
+                       'visualeditor-ca-createsource',
+                       'visualeditor-ca-editsource',
+                       'visualeditor-ca-ve-create',
+                       'visualeditor-ca-ve-edit',
+               ),
+               'position' => 'top',
+       ),
        'ext.visualEditor.viewPageTarget' => $wgVisualEditorResourceTemplate + 
array(
                'scripts' => array(
                        've-mw/init/targets/ve.init.mw.ViewPageTarget.js',
@@ -181,12 +202,12 @@
                        'jquery.client',
                        'jquery.placeholder',
                        'jquery.visibleText',
+                       'mediawiki.feedback',
                        'mediawiki.jqueryMsg',
+                       'mediawiki.notify',
                        'mediawiki.Title',
                        'mediawiki.Uri',
                        'mediawiki.user',
-                       'mediawiki.notify',
-                       'mediawiki.feedback',
                        'user.options',
                        'user.tokens',
                ),
@@ -196,17 +217,8 @@
                        'editing',
 
                        // Messages needed by VE in init phase only (rest go 
below)
-                       'accesskey-ca-editsource',
-                       'accesskey-ca-ve-edit',
-                       'tooltip-ca-createsource',
-                       'tooltip-ca-editsource',
-                       'tooltip-ca-ve-edit',
                        'pipe-separator',
-                       'visualeditor-ca-createsource',
-                       'visualeditor-ca-editsource',
                        'visualeditor-ca-editsource-section',
-                       'visualeditor-ca-ve-create',
-                       'visualeditor-ca-ve-edit',
                        'visualeditor-loadwarning',
                        'visualeditor-loadwarning-token',
                        'visualeditor-notification-created',
diff --git a/modules/ve-mw/init/targets/ve.init.mw.ViewPageTarget.init.js 
b/modules/ve-mw/init/targets/ve.init.mw.ViewPageTarget.init.js
new file mode 100644
index 0000000..c2c2819
--- /dev/null
+++ b/modules/ve-mw/init/targets/ve.init.mw.ViewPageTarget.init.js
@@ -0,0 +1,216 @@
+/*!
+ * VisualEditor MediaWiki ViewPageTarget init.
+ *
+ * This file must remain as widely compatible as the base compatibility
+ * for MediaWiki itself (see mediawiki/core:/resources/startup.js).
+ * Avoid use of: ES5, SVG, HTML5 DOM, ContentEditable etc.
+ *
+ * @copyright 2011-2013 VisualEditor Team and others; see AUTHORS.txt
+ * @license The MIT License (MIT); see LICENSE.txt
+ */
+
+/*global mw */
+
+/**
+ * Platform preparation for the MediaWiki view page. This loads (when user 
needs it) the
+ * actual MediaWiki integration and VisualEditor library.
+ *
+ * @class ve.init.mw.ViewPageTarget.init
+ * @singleton
+ */
+( function () {
+       var conf, uri, pageExists, viewUri, veEditUri, isViewPage,
+               init, isBlacklisted, getTargetDeferred;
+
+       /**
+        * Use deferreds to avoid loading and instantiating Target multiple 
times.
+        * @return {jQuery.Promise}
+        */
+       function getTarget() {
+               var loadTargetDeferred;
+               if ( !getTargetDeferred ) {
+                       getTargetDeferred = $.Deferred();
+                       loadTargetDeferred = $.Deferred()
+                               .done( function () {
+                                       var target = new 
ve.init.mw.ViewPageTarget();
+                                       ve.init.mw.targets.push( target );
+                                       getTargetDeferred.resolve( target );
+                               } )
+                               .fail( getTargetDeferred.reject );
+
+                       mw.loader.using( 'ext.visualEditor.viewPageTarget', 
loadTargetDeferred.resolve, loadTargetDeferred.reject );
+               }
+               return getTargetDeferred.promise();
+       }
+
+       conf = mw.config.get( 'wgVisualEditorConfig' );
+       uri = new mw.Uri();
+       pageExists = !!mw.config.get( 'wgArticleId' );
+       viewUri = new mw.Uri( mw.util.wikiGetlink( mw.config.get( 
'wgRelevantPageName' ) ) );
+       veEditUri = viewUri.clone().extend( { 'veaction': 'edit' } );
+       isViewPage = (
+               mw.config.get( 'wgAction' ) === 'view' &&
+               !( 'diff' in uri.query )
+       );
+
+
+       init = {
+
+               support: {
+                       es5: (
+                               // It would be much easier to do a quick inline 
function that asserts "use strict"
+                               // works, but since IE9 doesn't support strict 
mode (and we don't use strict mode) we
+                               // have to instead list all the ES5 features we 
do use.
+                               Array.isArray &&
+                               Array.prototype.filter &&
+                               Array.prototype.indexOf &&
+                               Array.prototype.map &&
+                               Date.prototype.toJSON &&
+                               Function.prototype.bind &&
+                               Object.create &&
+                               Object.keys &&
+                               String.prototype.trim &&
+                               window.JSON &&
+                               JSON.parse &&
+                               JSON.stringify
+                       ),
+                       contentEditable: 'contentEditable' in 
document.createElement( 'div' )
+               },
+
+               blacklist: {
+                       // IE <= 8 has various incompatibilities in layout and 
feature support
+                       // IE9 and IE10 generally work but fail in ajax 
handling when making POST
+                       // requests to the VisualEditor/Parsoid API which is 
causing silent failures
+                       // when trying to save a page (bug 49187)
+                       'msie': [['<=', 10]],
+                       // Android 2.x and below "support" CE but don't trigger 
keyboard input
+                       'android': [['<', 3]],
+                       // Bug 50534 - apparently Firefox is broken in versions 
10 and below
+                       'firefox': [['<=', 10]],
+                       // Blacklist all versions:
+                       'opera': null,
+                       'blackberry': null
+               },
+
+               skinSetup: function () {
+                       var caVeEdit, caVeEditSource,
+                               action = pageExists ? 'edit' : 'create',
+                               pTabsId = $( '#p-views' ).length ? 'p-views' : 
'p-cactions',
+                               $caSource = $( '#ca-viewsource' ),
+                               $caEdit = $( '#ca-edit' ),
+                               $caEditLink = $caEdit.find( 'a' ),
+                               reverseTabOrder = $( 'body' ).hasClass( 'rtl' ) 
&& pTabsId === 'p-views',
+                               caVeEditNextnode = reverseTabOrder ? 
$caEdit.get( 0 ) : $caEdit.next().get( 0 );
+
+                       if ( !$caEdit.length || $caSource.length ) {
+                               // If there is no edit tab or a view-source tab,
+                               // the user doesn't have permission to edit.
+                               return;
+                       }
+
+                       // Add independent "VisualEditor" tab (#ca-ve-edit).
+                       if ( conf.tabLayout === 'add' ) {
+
+                               caVeEdit = mw.util.addPortletLink(
+                                       pTabsId,
+                                       // Use url instead of '#'.
+                                       // So that 1) one can always open it in 
a new tab, even when
+                                       // onEditTabClick is bound.
+                                       // 2) when onEditTabClick is not bound 
(!isViewPage) it will
+                                       // just work.
+                                       veEditUri,
+                                       // visualeditor-ca-ve-edit
+                                       // visualeditor-ca-ve-create
+                                       mw.msg( 'visualeditor-ca-ve-' + action 
),
+                                       'ca-ve-edit',
+                                       mw.msg( 'tooltip-ca-ve-edit' ),
+                                       mw.msg( 'accesskey-ca-ve-edit' ),
+                                       caVeEditNextnode
+                               );
+
+                       // Replace "Edit" tab with a veEditUri version, add 
"Edit source" tab.
+                       } else {
+                               // Create "Edit source" link.
+                               // Re-create instead of convert ca-edit since 
we don't want to copy over accesskey etc.
+                               caVeEditSource = mw.util.addPortletLink(
+                                       pTabsId,
+                                       // Use original href to preserve oldid 
etc. (bug 38125)
+                                       $caEditLink.attr( 'href' ),
+                                       // visualeditor-ca-editsource
+                                       // visualeditor-ca-createsource
+                                       mw.msg( 'visualeditor-ca-' + action + 
'source' ),
+                                       'ca-editsource',
+                                       // tooltip-ca-editsource
+                                       // tooltip-ca-createsource
+                                       mw.msg( 'tooltip-ca-' + action + 
'source' ),
+                                       mw.msg( 'accesskey-ca-editsource' ),
+                                       caVeEditNextnode
+                               );
+                               // Copy over classes (e.g. 'selected')
+                               $( caVeEditSource ).addClass( $caEdit.attr( 
'class' ) );
+
+                               // Create "Edit" tab.
+                               $caEdit.remove();
+                               caVeEdit = mw.util.addPortletLink(
+                                       pTabsId,
+                                       // Use url instead of '#'.
+                                       // So that 1) one can always open it in 
a new tab, even when
+                                       // onEditTabClick is bound.
+                                       // 2) when onEditTabClick is not bound 
(!isViewPage) it will
+                                       // just work.
+                                       veEditUri,
+                                       $caEditLink.text(),
+                                       $caEdit.attr( 'id' ),
+                                       $caEditLink.attr( 'title' ),
+                                       mw.msg( 'accesskey-ca-ve-edit' ),
+                                       reverseTabOrder ? 
caVeEditSource.nextSibling : caVeEditSource
+                               );
+                       }
+
+                       if ( isViewPage ) {
+                               // Allow instant switching to edit mode, 
without refresh
+                               $( caVeEdit ).click( function ( e ) {
+                                       // Default mouse button is normalised 
by jQuery to key code 1.
+                                       // Only do our handling if no keys are 
pressed, mouse button is 1
+                                       // (e.g. not middle click or right 
click) and no modifier keys
+                                       // (e.g. cmd-click to open in new tab).
+                                       if ( ( e.which && e.which !== 1 ) || 
e.shiftKey || e.altKey || e.ctrlKey || e.metaKey ) {
+                                               return;
+                                       }
+                                       // Prevent the edit tab's normal 
behavior
+                                       e.preventDefault();
+
+                                       getTarget().done( function ( target ) {
+                                               target.logEvent( 'Edit', { 
action: 'edit-link-click' } );
+                                               target.activate();
+                                       } );
+                               } );
+                       }
+               }
+       };
+
+       // Expose
+       mw.libs.ve = init;
+       if ( window.console ) {
+               window.console.log( 'Support ES5: ' + 
String(!!init.support.es5) + '; UA: ' + navigator.userAgent );
+       }
+
+       isBlacklisted = !( 'vewhitelist' in uri.query ) && $.client.test( 
init.blacklist, null, true );
+
+       if ( !init.support.es5 || !init.support.contentEditable || 
isBlacklisted ) {
+               mw.log( 'Browser does not support VisualEditor' );
+               return;
+       }
+
+       $( function () {
+               if ( isViewPage ) {
+                       if ( uri.query.veaction === 'edit' ) {
+                               getTarget().done( function ( target ) {
+                                       target.activate();
+                               } );
+                       }
+               }
+               init.skinSetup();
+       } );
+
+}() );
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 a198ed8..7548800 100644
--- a/modules/ve-mw/init/targets/ve.init.mw.ViewPageTarget.js
+++ b/modules/ve-mw/init/targets/ve.init.mw.ViewPageTarget.js
@@ -17,26 +17,7 @@
  */
 ve.init.mw.ViewPageTarget = function VeInitMwViewPageTarget() {
        var browserWhitelisted,
-               browserBlacklisted,
-               currentUri = new mw.Uri(),
-               supportsES5subset = (
-                       // It would be much easier to do a quick inline 
function that asserts "use strict"
-                       // works, but since IE9 doesn't support strict mode 
(and we don't use strict mode) we
-                       // have to instead list all the ES5 features we use.
-                       Array.isArray &&
-                       Array.prototype.filter &&
-                       Array.prototype.indexOf &&
-                       Array.prototype.map &&
-                       Date.prototype.toJSON &&
-                       Function.prototype.bind &&
-                       Object.create &&
-                       Object.keys &&
-                       String.prototype.trim &&
-                       window.JSON &&
-                       JSON.parse &&
-                       JSON.stringify
-               ),
-               supportsContentEditable = 'contentEditable' in 
document.createElement( 'div' );
+               currentUri = new mw.Uri();
 
        // Parent constructor
        ve.init.mw.Target.call(
@@ -110,10 +91,6 @@
                'vewhitelist' in currentUri.query ||
                $.client.test( 
ve.init.mw.ViewPageTarget.compatibility.whitelist, null, true )
        );
-       browserBlacklisted = (
-               !( 'vewhitelist' in currentUri.query ) &&
-               $.client.test( 
ve.init.mw.ViewPageTarget.compatibility.blacklist, null, true )
-       );
 
        if ( mw.config.get( 'wgVisualEditorConfig' ).enableEventLogging ) {
                this.setUpEventLogging();
@@ -134,11 +111,6 @@
                'noChanges': 'onNoChanges',
                'serializeError': 'onSerializeError'
        } );
-
-       if ( !supportsES5subset || !supportsContentEditable || 
browserBlacklisted ) {
-               // Don't initialise in browsers that are broken
-               return;
-       }
 
        if ( !browserWhitelisted ) {
                // Show warning in unknown browsers that pass the support test
@@ -164,11 +136,6 @@
 
        this.setupSkinTabs();
        this.setupSectionEditLinks();
-       if ( this.isViewPage ) {
-               if ( currentUri.query.veaction === 'edit' ) {
-                       this.activate();
-               }
-       }
 
        window.addEventListener( 'popstate', ve.bind( this.onWindowPopState, 
this ) ) ;
 };
@@ -194,20 +161,6 @@
                'iceweasel': [['>=', 10]],
                'safari': [['>=', 5]],
                'chrome': [['>=', 19]]
-       },
-       'blacklist': {
-               // IE <= 8 has various incompatibilities in layout and feature 
support
-               // IE9 and IE10 generally work but fail in ajax handling when 
making POST
-               // requests to the VisualEditor/Parsoid API which is causing 
silent failures
-               // when trying to save a page (bug 49187)
-               'msie': [['<=', 10]],
-               // Android 2.x and below "support" CE but don't trigger 
keyboard input
-               'android': [['<', 3]],
-               // Bug 50534 - apparently Firefox is broken in versions 10 and 
below
-               'firefox': [['<=', 10]],
-               // Blacklist all versions:
-               'opera': null,
-               'blackberry': null
        }
 };
 
@@ -617,26 +570,6 @@
 ve.init.mw.ViewPageTarget.prototype.onNoChanges = function () {
        this.$saveDialogLoadingIcon.hide();
        this.swapSaveDialog( 'nochanges' );
-};
-
-/**
- * Handle clicks on the edit tab.
- *
- * @method
- * @param {jQuery.Event} e Mouse click event
- */
-ve.init.mw.ViewPageTarget.prototype.onEditTabClick = function ( e ) {
-       // Default mouse button is normalised by jQuery to key code 1.
-       // Only do our handling if no keys are pressed, mouse button is 1
-       // (e.g. not middle click or right click) and no modifier keys
-       // (e.g. cmd-click to open in new tab).
-       if ( ( e.which && e.which !== 1 ) || e.shiftKey || e.altKey || 
e.ctrlKey || e.metaKey ) {
-               return;
-       }
-       this.logEvent( 'Edit', { action: 'edit-link-click' } );
-       this.activate();
-       // Prevent the edit tab's normal behavior
-       e.preventDefault();
 };
 
 /**
@@ -1150,84 +1083,12 @@
 
 /**
  * Modify tabs in the skin to support in-place editing.
+ * Edit tab is bound outside the module in mw.ViewPageTarget.init.
  *
  * @method
  */
 ve.init.mw.ViewPageTarget.prototype.setupSkinTabs = function () {
-       var caVeEdit, caVeEditSource,
-               action = this.pageExists ? 'edit' : 'create',
-               pTabsId = $( '#p-views' ).length ? 'p-views' : 'p-cactions',
-               $caSource = $( '#ca-viewsource' ),
-               $caEdit = $( '#ca-edit' ),
-               $caEditLink = $caEdit.find( 'a' ),
-               reverseTabOrder = $( 'body' ).hasClass( 'rtl' ) && pTabsId === 
'p-views',
-               caVeEditNextnode = reverseTabOrder ? $caEdit.get( 0 ) : 
$caEdit.next().get( 0 );
-
-       if ( !$caEdit.length || $caSource.length ) {
-               // If there is no edit tab or a view-source tab,
-               // the user doesn't have permission to edit.
-               return;
-       }
-
-       // Add independent "VisualEditor" tab (#ca-ve-edit).
-       if ( this.tabLayout === 'add' ) {
-
-               caVeEdit = mw.util.addPortletLink(
-                       pTabsId,
-                       // Use url instead of '#'.
-                       // So that 1) one can always open it in a new tab, even 
when
-                       // onEditTabClick is bound.
-                       // 2) when onEditTabClick is not bound (!isViewPage) it 
will
-                       // just work.
-                       this.veEditUri,
-                       // Message: 'visualeditor-ca-ve-edit' or 
'visualeditor-ca-ve-create'
-                       ve.msg( 'visualeditor-ca-ve-' + action ),
-                       'ca-ve-edit',
-                       ve.msg( 'tooltip-ca-ve-edit' ),
-                       ve.msg( 'accesskey-ca-ve-edit' ),
-                       caVeEditNextnode
-               );
-
-       // Replace "Edit" tab with a veEditUri version, add "Edit source" tab.
-       } else {
-               // Create "Edit source" link.
-               // Re-create instead of convert ca-edit since we don't want to 
copy over accesskey etc.
-               caVeEditSource = mw.util.addPortletLink(
-                       pTabsId,
-                       // Use original href to preserve oldid etc. (bug 38125)
-                       $caEditLink.attr( 'href' ),
-                       // Message: 'visualeditor-ca-editsource' or 
'visualeditor-ca-createsource'
-                       ve.msg( 'visualeditor-ca-' + action + 'source' ),
-                       'ca-editsource',
-                       // Message: 'tooltip-ca-editsource' or 
'tooltip-ca-createsource'
-                       ve.msg( 'tooltip-ca-' + action + 'source' ),
-                       ve.msg( 'accesskey-ca-editsource' ),
-                       caVeEditNextnode
-               );
-               // Copy over classes (e.g. 'selected')
-               $( caVeEditSource ).addClass( $caEdit.attr( 'class' ) );
-
-               // Create "Edit" tab.
-               $caEdit.remove();
-               caVeEdit = mw.util.addPortletLink(
-                       pTabsId,
-                       // Use url instead of '#'.
-                       // So that 1) one can always open it in a new tab, even 
when
-                       // onEditTabClick is bound.
-                       // 2) when onEditTabClick is not bound (!isViewPage) it 
will
-                       // just work.
-                       this.veEditUri,
-                       $caEditLink.text(),
-                       $caEdit.attr( 'id' ),
-                       $caEditLink.attr( 'title' ),
-                       ve.msg( 'accesskey-ca-ve-edit' ),
-                       reverseTabOrder ? caVeEditSource.nextSibling : 
caVeEditSource
-               );
-       }
-
        if ( this.isViewPage ) {
-               // Allow instant switching to edit mode, without refresh
-               $( caVeEdit ).click( ve.bind( this.onEditTabClick, this ) );
                // Allow instant switching back to view mode, without refresh
                $( '#ca-view a, #ca-nstab-visualeditor a' )
                        .click( ve.bind( this.onViewTabClick, this ) );
@@ -2317,7 +2178,3 @@
                return message;
        }
 };
-
-/* Initialization */
-
-ve.init.mw.targets.push( new ve.init.mw.ViewPageTarget() );
diff --git a/modules/ve-mw/test/init/targets/ve.init.mw.ViewPageTarget.test.js 
b/modules/ve-mw/test/init/targets/ve.init.mw.ViewPageTarget.test.js
index 19a7fc1..45378f0 100644
--- a/modules/ve-mw/test/init/targets/ve.init.mw.ViewPageTarget.test.js
+++ b/modules/ve-mw/test/init/targets/ve.init.mw.ViewPageTarget.test.js
@@ -5,10 +5,11 @@
  * @license The MIT License (MIT); see LICENSE.txt
  */
 
+/*global mw */
 QUnit.module( 've.init.mw.ViewPageTarget' );
 
 QUnit.test( 'compatibility', function ( assert ) {
-       var i, profile, list, matches,
+       var i, profile, list, matches, compatibility,
                cases = [
                        {
                                'msg': 'Unidentified browser',
@@ -122,12 +123,18 @@
                        }
                ];
 
+       compatibility = {
+               'whitelist': ve.init.mw.ViewPageTarget.compatibility.whitelist,
+               // TODO: Fix this mess when we split ve.init from ve.platform
+               'blacklist': mw.libs.ve.blacklist
+       };
+
        QUnit.expect( cases.length );
        for ( i = 0; i < cases.length; i++ ) {
                profile = $.client.profile( { 'userAgent': cases[i].userAgent, 
'platform': '' } );
                matches = [];
-               for ( list in ve.init.mw.ViewPageTarget.compatibility ) {
-                       if ( $.client.test( 
ve.init.mw.ViewPageTarget.compatibility[list], profile, true ) ) {
+               for ( list in compatibility ) {
+                       if ( $.client.test( compatibility[list], profile, true 
) ) {
                                matches.push( list );
                        }
                }

-- 
To view, visit https://gerrit.wikimedia.org/r/71929
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: Ic8b0004ab5288fa91bb29d496485b93ffd8d977e
Gerrit-PatchSet: 11
Gerrit-Project: mediawiki/extensions/VisualEditor
Gerrit-Branch: master
Gerrit-Owner: Krinkle <[email protected]>
Gerrit-Reviewer: Catrope <[email protected]>
Gerrit-Reviewer: Krinkle <[email protected]>
Gerrit-Reviewer: jenkins-bot

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to