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