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

Change subject: Create base MobileView config and target refactor
......................................................................


Create base MobileView config and target refactor

Changes include:
* Target mobile for ve dependencies
* Create mobile view constructor
** Some tools like dialogs are excluded for now
* Refactor mw.target to permit code reuse
** Split out pageTarget view functionality from core init methods

Change-Id: I786b63ab57518fc6af7761501259ed66592f70e3
---
M VisualEditor.php
M VisualEditorDataModule.php
A modules/ve-mw/init/targets/ve.init.mw.MobileViewTarget.js
M modules/ve-mw/init/targets/ve.init.mw.ViewPageTarget.js
M modules/ve-mw/init/ve.init.mw.Target.js
5 files changed, 304 insertions(+), 92 deletions(-)

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



diff --git a/VisualEditor.php b/VisualEditor.php
index eb902bd..c20246c 100644
--- a/VisualEditor.php
+++ b/VisualEditor.php
@@ -81,18 +81,21 @@
                        'rangy/rangy-position-1.3.js',
                        'rangy/rangy-export.js',
                ),
+               'targets' => array( 'desktop', 'mobile' ),
        ),
 
        'jquery.visibleText' => $wgVisualEditorResourceTemplate + array(
                'scripts' => array(
                        'jquery/jquery.visibleText.js',
                ),
+               'targets' => array( 'desktop', 'mobile' ),
        ),
 
        'oojs' => $wgVisualEditorResourceTemplate + array(
                'scripts' => array(
                        'oojs/oojs.js',
                ),
+               'targets' => array( 'desktop', 'mobile' ),
        ),
 
        'oojs-ui' => $wgVisualEditorResourceTemplate + array(
@@ -114,7 +117,8 @@
                ),
                'dependencies' => array(
                        'oojs'
-               )
+               ),
+               'targets' => array( 'desktop', 'mobile' ),
        ),
 
        'unicodejs.wordbreak' => $wgVisualEditorResourceTemplate + array(
@@ -126,6 +130,7 @@
                        'unicodejs/unicodejs.wordbreakproperties.js',
                        'unicodejs/unicodejs.wordbreak.js',
                ),
+               'targets' => array( 'desktop', 'mobile' ),
        ),
 
        // Alias for backwards compat, safe to remove after
@@ -139,12 +144,14 @@
                'styles' => array(
                        
've-mw/init/styles/ve.init.mw.ViewPageTarget.Icons-raster.css',
                ),
+               'targets' => array( 'desktop', 'mobile' ),
        ),
 
        'ext.visualEditor.viewPageTarget.icons-vector' => 
$wgVisualEditorResourceTemplate + array(
                'styles' => array(
                        
've-mw/init/styles/ve.init.mw.ViewPageTarget.Icons-vector.css',
                ),
+               'targets' => array( 'desktop', 'mobile' ),
        ),
 
        'ext.visualEditor.viewPageTarget.init' => 
$wgVisualEditorResourceTemplate + array(
@@ -197,20 +204,9 @@
                'dependencies' => array(
                        'ext.visualEditor.base',
                        'ext.visualEditor.mediawiki',
-                       'jquery.byteLength',
-                       'jquery.byteLimit',
-                       'jquery.client',
                        'jquery.placeholder',
-                       'jquery.visibleText',
-                       'mediawiki.api',
                        'mediawiki.feedback',
                        'mediawiki.jqueryMsg',
-                       'mediawiki.notify',
-                       'mediawiki.Title',
-                       'mediawiki.Uri',
-                       'mediawiki.user',
-                       'user.options',
-                       'user.tokens',
                ),
                'messages' => array(
                        // MW core messages
@@ -228,6 +224,16 @@
                        'visualeditor-savedialog-identify-anon',
                        'visualeditor-savedialog-identify-user',
                ),
+       ),
+       'ext.visualEditor.mobileViewTarget' => $wgVisualEditorResourceTemplate 
+ array(
+               'scripts' => array(
+                       've-mw/init/targets/ve.init.mw.MobileViewTarget.js',
+               ),
+               'dependencies' => array(
+                       'ext.visualEditor.base',
+                       'ext.visualEditor.mediawiki',
+               ),
+               'targets' => array( 'mobile' ),
        ),
 
        'ext.visualEditor.base' => $wgVisualEditorResourceTemplate + array(
@@ -250,6 +256,7 @@
                        'unicodejs.wordbreak',
                        'mediawiki.util',
                ),
+               'targets' => array( 'desktop', 'mobile' ),
        ),
 
        'ext.visualEditor.mediawiki' => $wgVisualEditorResourceTemplate + array(
@@ -260,11 +267,20 @@
                        've-mw/init/ve.init.mw.Target.js',
                ),
                'dependencies' => array(
+                       'jquery.visibleText',
                        'jquery.byteLength',
                        'jquery.client',
                        'mediawiki.Uri',
+                       'mediawiki.api',
+                       'mediawiki.notify',
+                       'mediawiki.Title',
+                       'mediawiki.Uri',
+                       'mediawiki.user',
+                       'user.options',
+                       'user.tokens',
                        'ext.visualEditor.base',
                ),
+               'targets' => array( 'desktop', 'mobile' ),
        ),
 
        'ext.visualEditor.standalone' => $wgVisualEditorResourceTemplate + 
array(
@@ -280,7 +296,7 @@
        ),
 
        'ext.visualEditor.data' => $wgVisualEditorResourceTemplate + array(
-               'class' => 'VisualEditorDataModule'
+               'class' => 'VisualEditorDataModule',
        ),
 
        'ext.visualEditor.core' => $wgVisualEditorResourceTemplate + array(
@@ -541,6 +557,7 @@
                        'mediawiki.action.history.diff',
                        'mediawiki.user',
                        'jquery.autoEllipsis',
+                       'jquery.byteLimit',
                ),
                'messages' => array(
                        // VE messages for the editor (NOT experimental mode 
messages)
@@ -682,6 +699,7 @@
                        'fancycaptcha-edit',
                        'colon-separator',
                ),
+               'targets' => array( 'desktop', 'mobile' ),
        ),
 
        'ext.visualEditor.language' => $wgVisualEditorResourceTemplate + array(
@@ -708,6 +726,7 @@
                        
'visualeditor-languageinspector-block-tooltip-rtldirection',
                        'visualeditor-annotationbutton-language-tooltip',
                ),
+               'targets' => array( 'desktop', 'mobile' ),
        ),
 
        'ext.visualEditor.mwalienextension' => $wgVisualEditorResourceTemplate 
+ array(
@@ -723,6 +742,7 @@
                'messages' => array(
                        'visualeditor-mwalienextensioninspector-title',
                ),
+               'targets' => array( 'desktop', 'mobile' ),
        ),
 
        'ext.visualEditor.mwmath' => $wgVisualEditorResourceTemplate + array(
@@ -738,6 +758,7 @@
                'messages' => array(
                        'visualeditor-mwmathinspector-title',
                ),
+               'targets' => array( 'desktop', 'mobile' ),
        ),
 
        'ext.visualEditor.mwhiero' => $wgVisualEditorResourceTemplate + array(
@@ -753,6 +774,7 @@
                'messages' => array(
                        'visualeditor-mwhieroinspector-title',
                ),
+               'targets' => array( 'desktop', 'mobile' ),
        ),
 
        'ext.visualEditor.mwsyntaxHighlight' => $wgVisualEditorResourceTemplate 
+ array(
@@ -776,6 +798,7 @@
                'styles' => array(
                        'syntaxhighlight/styles/ve.ui.MWSyntaxHighlight.css',
                ),
+               'targets' => array( 'desktop', 'mobile' ),
        ),
 
        'ext.visualEditor.experimental' => array(
@@ -786,6 +809,7 @@
                        'ext.visualEditor.mwalienextension',
                        //'ext.visualEditor.mwsyntaxHighlight',
                ),
+               'targets' => array( 'desktop', 'mobile' ),
        ),
 
        'ext.visualEditor.icons-raster' => $wgVisualEditorResourceTemplate + 
array(
@@ -793,12 +817,14 @@
                        've/ui/styles/ve.ui.Icons-raster.css',
                        've-mw/ui/styles/ve.ui.Icons-raster.css',
                ),
+               'targets' => array( 'desktop', 'mobile' ),
        ),
        'ext.visualEditor.icons-vector' => $wgVisualEditorResourceTemplate + 
array(
                'styles' => array(
                        've/ui/styles/ve.ui.Icons-vector.css',
                        've-mw/ui/styles/ve.ui.Icons-vector.css',
                ),
+               'targets' => array( 'desktop', 'mobile' ),
        ),
 );
 
diff --git a/VisualEditorDataModule.php b/VisualEditorDataModule.php
index 66f4727..f64ea58 100644
--- a/VisualEditorDataModule.php
+++ b/VisualEditorDataModule.php
@@ -15,6 +15,7 @@
        protected $origin = self::ORIGIN_USER_SITEWIDE;
        protected $gitInfo;
        protected $gitHeadHash;
+       protected $targets = array( 'desktop', 'mobile' );
 
        /* Methods */
 
diff --git a/modules/ve-mw/init/targets/ve.init.mw.MobileViewTarget.js 
b/modules/ve-mw/init/targets/ve.init.mw.MobileViewTarget.js
new file mode 100644
index 0000000..d6904d2
--- /dev/null
+++ b/modules/ve-mw/init/targets/ve.init.mw.MobileViewTarget.js
@@ -0,0 +1,66 @@
+/*!
+ * VisualEditor MediaWiki Initialization MobileViewTarget class.
+ *
+ * @copyright 2011-2013 VisualEditor Team and others; see AUTHORS.txt
+ * @license The MIT License (MIT); see LICENSE.txt
+ */
+
+/*global mw*/
+
+/**
+ *
+ * @class
+ * @extends ve.init.mw.Target
+ *
+ * @constructor
+ * @param {jQuery} $container Container to render target into
+ */
+ve.init.mw.MobileViewTarget = function VeInitMwMobileViewTarget( $el ) {
+       var currentUri = new mw.Uri();
+
+       // Parent constructor
+       ve.init.mw.Target.call(
+               this, $el, mw.config.get( 'wgRelevantPageName' ), 
currentUri.query.oldid
+       );
+};
+
+/* Inheritance */
+
+OO.inheritClass( ve.init.mw.MobileViewTarget, ve.init.mw.Target );
+
+/* Static Properties */
+
+ve.init.mw.MobileViewTarget.static.toolbarGroups = [
+       { 'include': [ 'undo', 'redo' ] },
+       {
+               'type': 'menu',
+               'include': [ { 'group': 'format' } ],
+               'promote': [ 'paragraph' ],
+               'demote': [ 'preformatted', 'heading1' ]
+       },
+       { 'include': [ 'bold', 'italic', 'link', 'clear' ] },
+       { 'include': [ 'number', 'bullet', 'outdent', 'indent' ] },
+       { 'include': '*', 'exclude': [ { 'group': 'format' }, 'reference', 
'referenceList', 'mediaEdit', 'mediaInsert', 'transclusion' ] }
+];
+
+ve.init.mw.MobileViewTarget.static.surfaceCommands = [
+       'undo',
+       'redo',
+       'bold',
+       'italic',
+       'link',
+       'clear',
+       'underline',
+       'subscript',
+       'superscript',
+       'indent',
+       'outdent',
+       'paragraph',
+       'heading1',
+       'heading2',
+       'heading3',
+       'heading4',
+       'heading5',
+       'heading6',
+       'preformatted'
+];
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 c8c7cb1..f5fda29 100644
--- a/modules/ve-mw/init/targets/ve.init.mw.ViewPageTarget.js
+++ b/modules/ve-mw/init/targets/ve.init.mw.ViewPageTarget.js
@@ -37,10 +37,6 @@
        this.timings = {};
        this.active = false;
        this.edited = false;
-       this.sanityCheckFinished = false;
-       this.sanityCheckVerified = false;
-       this.activating = false;
-       this.deactivating = false;
        // If this is true then #transformPage / #restorePage will not call 
pushState
        // This is to avoid adding a new history entry for the url we just got 
from onpopstate
        // (which would mess up with the expected order of Back/Forwards 
browsing)
@@ -70,16 +66,17 @@
 
        // Events
        this.connect( this, {
-               'load': 'onLoad',
                'save': 'onSave',
                'loadError': 'onLoadError',
+               'surfaceReady': 'onSurfaceReady',
                'tokenError': 'onTokenError',
                'saveError': 'onSaveError',
                'editConflict': 'onEditConflict',
                'showChanges': 'onShowChanges',
                'showChangesError': 'onShowChangesError',
                'noChanges': 'onNoChanges',
-               'serializeError': 'onSerializeError'
+               'serializeError': 'onSerializeError',
+               'sanityCheckComplete': 'updateToolbarSaveButtonState'
        } );
 
        if ( !browserWhitelisted ) {
@@ -165,7 +162,7 @@
 
                this.saveScrollPosition();
 
-               this.load();
+               this.load( [ 'site', 'user' ] );
        }
 };
 
@@ -217,34 +214,6 @@
 };
 
 /**
- * Handle successful DOM load event.
- *
- * @method
- * @param {HTMLDocument} doc Parsed DOM from server
- */
-ve.init.mw.ViewPageTarget.prototype.onLoad = function ( doc ) {
-       if ( this.activating ) {
-               this.edited = false;
-               this.doc = doc;
-               this.setUpSurface( doc, ve.bind( function() {
-                       this.startSanityCheck();
-                       this.setupToolbarButtons();
-                       this.attachToolbarButtons();
-                       this.restoreScrollPosition();
-                       this.restoreEditSection();
-                       this.setupBeforeUnloadHandler();
-                       this.$document[0].focus();
-                       this.activating = false;
-                       if ( mw.config.get( 'wgVisualEditorConfig' 
).showBetaWelcome ) {
-                               this.showBetaWelcome();
-                       }
-                       ve.track( 'performance.system.activation', { 
'duration': ve.now() - this.timings.activationStart } );
-                       mw.hook( 've.activationComplete' ).fire();
-               }, this ) );
-       }
-};
-
-/**
  * Handle failed DOM load event.
  *
  * @method
@@ -279,6 +248,36 @@
                // User interface changes
                this.deactivate( true );
        }
+};
+
+/**
+ * Once surface is ready ready, init UI
+ *
+ * @method
+ */
+ve.init.mw.ViewPageTarget.prototype.onSurfaceReady = function () {
+       this.surface.getModel().getDocument().connect( this, {
+               'transact': 'recordLastTransactionTime'
+       } );
+       this.surface.getModel().connect( this, {
+               'documentUpdate': 'checkForWikitextWarning',
+               'history': 'updateToolbarSaveButtonState'
+       } );
+       // Update UI
+       this.transformPageTitle();
+       this.changeDocumentTitle();
+       this.hidePageContent();
+       this.hideSpinner();
+       this.setupToolbarButtons();
+       this.attachToolbarButtons();
+       this.restoreScrollPosition();
+       this.restoreEditSection();
+       this.setupBeforeUnloadHandler();
+       if ( mw.config.get( 'wgVisualEditorConfig' ).showBetaWelcome ) {
+               this.showBetaWelcome();
+       }
+       ve.track( 'performance.system.activation', { 'duration': ve.now() - 
this.timings.activationStart } );
+       mw.hook( 've.activationComplete' ).fire();
 };
 
 /**
@@ -1333,33 +1332,6 @@
                .parent()
                        .data( 've.hideTableOfContents', true )
                        .slideUp();
-};
-
-/**
- * Show the toolbar.
- *
- * This also transplants the toolbar to a new location.
- *
- * @method
- */
-ve.init.mw.ViewPageTarget.prototype.setUpToolbar = function () {
-       this.toolbar = new ve.ui.TargetToolbar( this, this.surface, { 'shadow': 
true, 'actions': true } );
-       this.toolbar.setup( this.constructor.static.toolbarGroups );
-       this.surface.addCommands( this.constructor.static.surfaceCommands );
-       if ( !this.isMobileDevice ) {
-               this.toolbar.enableFloatable();
-       }
-       this.toolbar.$element
-               .addClass( 've-init-mw-viewPageTarget-toolbar' )
-               .insertBefore( '#firstHeading' );
-       this.toolbar.$bar.slideDown( 'fast', ve.bind( function () {
-               // Check the surface wasn't torn down while the toolbar was 
animating
-               if ( this.surface ) {
-                       this.toolbar.initialize();
-                       this.surface.emit( 'position' );
-                       this.surface.getContext().update();
-               }
-       }, this ) );
 };
 
 /**
diff --git a/modules/ve-mw/init/ve.init.mw.Target.js 
b/modules/ve-mw/init/ve.init.mw.Target.js
index a7e8e5d..976235c 100644
--- a/modules/ve-mw/init/ve.init.mw.Target.js
+++ b/modules/ve-mw/init/ve.init.mw.Target.js
@@ -21,6 +21,7 @@
  */
 ve.init.mw.Target = function VeInitMwTarget( $container, pageName, revisionId 
) {
        var i, len, prefName, prefValue, conf = mw.config.get( 
'wgVisualEditorConfig' ),
+               // language, mwalienextension and mwhiero are commented out in 
VisualEditorHooks::onGetBetaPreferences()
                extraModules = [ 'experimental'/* , 'language'*//*, 
'mwalienextension'*/, 'mwmath'/*, 'mwhiero'*/ ];
 
        // Parent constructor
@@ -71,6 +72,10 @@
        this.$checkboxes = null;
        this.remoteNotices = [];
        this.localNoticeMessages = [];
+       this.sanityCheckFinished = false;
+       this.sanityCheckVerified = false;
+       this.activating = false;
+       this.deactivating = false;
        this.isMobileDevice = (
                'ontouchstart' in window ||
                        ( window.DocumentTouch && document instanceof 
window.DocumentTouch )
@@ -78,8 +83,7 @@
 };
 
 /**
- * @event load
- * @param {HTMLDocument} dom
+ * @event surfaceReady
  */
 
 /**
@@ -128,6 +132,10 @@
  * @param {Mixed|null} error HTTP status text
  */
 
+/**
+ * @event sanityCheckComplete
+ */
+
 /* Inheritance */
 
 OO.inheritClass( ve.init.mw.Target, ve.init.Target );
@@ -160,8 +168,8 @@
  * Handle response to a successful load request.
  *
  * This method is called within the context of a target instance. If 
successful the DOM from the
- * server will be parsed, stored in {this.doc} and then 
{ve.init.mw.Target.onReady} will be called once
- * the modules are ready.
+ * server will be parsed, stored in {this.doc} and then {this.onReady} will be 
called once modules
+ * are ready.
  *
  * @static
  * @method
@@ -207,17 +215,16 @@
                this.startTimeStamp = data.starttimestamp;
                this.revid = data.oldid;
                // Everything worked, the page was loaded, continue as soon as 
the modules are loaded
-               this.modulesReady.done( ve.bind( ve.init.mw.Target.onReady, 
this ) );
+               this.modulesReady.done( ve.bind( this.onReady, this ) );
        }
 };
 
 /**
  * Handle the edit notices being ready for rendering.
  *
- * @static
  * @method
  */
-ve.init.mw.Target.onNoticesReady = function () {
+ve.init.mw.Target.prototype.onNoticesReady = function () {
        var i, len, noticeHtmls, tmp, el;
 
        // Since we're going to parse them, we might as well save these nodes
@@ -261,18 +268,22 @@
 /**
  * Handle both DOM and modules being loaded and ready.
  *
- * This method is called within the context of a target instance.
- *
- * @static
  * @method
- * @fires load
+ * @fires surfaceReady
  */
-ve.init.mw.Target.onReady = function () {
+ve.init.mw.Target.prototype.onReady = function () {
        // We need to wait until onReady as local notices may require special 
messages
-       ve.init.mw.Target.onNoticesReady.call( this );
-
+       this.onNoticesReady();
        this.loading = false;
-       this.emit( 'load', this.doc );
+       if ( this.activating ) {
+               this.edited = false;
+               this.setUpSurface( this.doc, ve.bind( function() {
+                       this.startSanityCheck();
+                       this.$document[0].focus();
+                       this.activating = false;
+                       this.emit( 'surfaceReady' );
+               }, this ) );
+       }
 };
 
 /**
@@ -510,9 +521,10 @@
  * A side-effect of calling this method is that it requests {this.modules} be 
loaded.
  *
  * @method
+ * @param {string[]} [additionalModules=[]] Resource loader modules
  * @returns {boolean} Loading has been started
 */
-ve.init.mw.Target.prototype.load = function () {
+ve.init.mw.Target.prototype.load = function ( additionalModules ) {
        var data, start;
        // Prevent duplicate requests
        if ( this.loading ) {
@@ -521,7 +533,7 @@
        // Start loading the module immediately
        mw.loader.using(
                // Wait for site and user JS before running plugins
-               this.modules.concat( [ 'site', 'user' ] ),
+               this.modules.concat( additionalModules || [] ),
                ve.bind( ve.init.mw.Target.onModulesReady, this )
        );
 
@@ -867,3 +879,138 @@
 ve.init.mw.Target.prototype.getEditNotices = function () {
        return this.editNotices;
 };
+
+// FIXME: split out view specific functionality, emit to subclass
+
+/**
+ * Switch to editing mode.
+ *
+ * @method
+ * @param {HTMLDocument} doc HTML DOM to edit
+ * @param {Function} [callback] Callback to call when done
+ */
+ve.init.mw.Target.prototype.setUpSurface = function ( doc, callback ) {
+       var target = this;
+       setTimeout( function () {
+               // Build linmod
+               var store = new ve.dm.IndexValueStore(),
+                       internalList = new ve.dm.InternalList(),
+                       innerWhitespace = new Array( 2 ),
+                       data = ve.dm.converter.getDataFromDom( doc, store, 
internalList, innerWhitespace );
+               setTimeout( function () {
+                       // Build DM tree
+                       var dmDoc = new ve.dm.Document( data, doc, undefined, 
internalList, innerWhitespace );
+                       setTimeout( function () {
+                               // Create ui.Surface (also creates ce.Surface 
and dm.Surface and builds CE tree)
+                               target.surface = new ve.ui.Surface( dmDoc, 
target.surfaceOptions );
+                               target.surface.$element.addClass( 
've-init-mw-viewPageTarget-surface' );
+                               setTimeout( function () {
+                                       // Initialize surface
+                                       target.surface.getContext().hide();
+                                       target.$document = 
target.surface.$element.find( '.ve-ce-documentNode' );
+                                       target.$element.append( 
target.surface.$element );
+                                       target.setUpToolbar();
+                                       target.$document.attr( {
+                                               'lang': mw.config.get( 
'wgVisualEditor' ).pageLanguageCode,
+                                               'dir': mw.config.get( 
'wgVisualEditor' ).pageLanguageDir
+                                       } );
+                                       // Add appropriately mw-content-ltr or 
mw-content-rtl class
+                                       target.surface.view.$element.addClass(
+                                               'mw-content-' + mw.config.get( 
'wgVisualEditor' ).pageLanguageDir
+                                       );
+                                       target.active = true;
+                                       // Now that the surface is attached to 
the document and ready,
+                                       // let it initialize itself
+                                       target.surface.initialize();
+                                       setTimeout( callback );
+                               } );
+                       } );
+               } );
+       } );
+};
+
+/**
+ * Show the toolbar.
+ *
+ * This also transplants the toolbar to a new location.
+ *
+ * @method
+ */
+ve.init.mw.Target.prototype.setUpToolbar = function () {
+       this.toolbar = new ve.ui.TargetToolbar( this, this.surface, { 'shadow': 
true, 'actions': true } );
+       this.toolbar.setup( this.constructor.static.toolbarGroups );
+       this.surface.addCommands( this.constructor.static.surfaceCommands );
+       if ( !this.isMobileDevice ) {
+               this.toolbar.enableFloatable();
+       }
+       this.toolbar.$element
+               .addClass( 've-init-mw-viewPageTarget-toolbar' )
+               .insertBefore( $( '#firstHeading' ).length > 0 ? 
'#firstHeading' : this.surface.$element );
+       this.toolbar.$bar.slideDown( 'fast', ve.bind( function () {
+               // Check the surface wasn't torn down while the toolbar was 
animating
+               if ( this.surface ) {
+                       this.toolbar.initialize();
+                       this.surface.emit( 'position' );
+                       this.surface.getContext().update();
+               }
+       }, this ) );
+};
+
+/**
+ * Fire off the sanity check. Must be called before the surface is activated.
+ *
+ * To access the result, check whether #sanityCheckPromise has been resolved 
or rejected
+ * (it's asynchronous, so it may still be pending when you check).
+ *
+ * @method
+ * @fires sanityCheckComplete
+ */
+ve.init.mw.Target.prototype.startSanityCheck = function () {
+       // We have to get a copy of the data now, before we unlock the surface 
and let the user edit,
+       // but we can defer the actual conversion and comparison
+       var viewPage = this,
+               doc = viewPage.surface.getModel().getDocument(),
+               data = new ve.dm.FlatLinearData( doc.getStore().clone(), 
ve.copy( doc.getFullData() ) ),
+               oldDom = viewPage.doc,
+               d = $.Deferred();
+
+       // Reset
+       viewPage.sanityCheckFinished = false;
+       viewPage.sanityCheckVerified = false;
+
+       setTimeout( function () {
+               // We can't compare oldDom.body and newDom.body directly, 
because the attributes on the
+               // <body> were ignored in the conversion. So compare each child 
separately.
+               var i,
+                       len = oldDom.body.childNodes.length,
+                       newDoc = new ve.dm.Document( data, oldDom, undefined, 
doc.getInternalList(), doc.getInnerWhitespace() ),
+                       newDom = ve.dm.converter.getDomFromData( 
newDoc.getFullData(), newDoc.getStore(), newDoc.getInternalList(), 
newDoc.getInnerWhitespace() );
+
+               // Explicitly unlink our full copy of the original version of 
the document data
+               data = undefined;
+
+               if ( len !== newDom.body.childNodes.length ) {
+                       // Different number of children, so they're definitely 
different
+                       d.reject();
+                       return;
+               }
+               for ( i = 0; i < len; i++ ) {
+                       if ( !oldDom.body.childNodes[i].isEqualNode( 
newDom.body.childNodes[i] ) ) {
+                               d.reject();
+                               return;
+                       }
+               }
+               d.resolve();
+       } );
+
+       viewPage.sanityCheckPromise = d.promise()
+               .done( function () {
+                       // If we detect no roundtrip errors,
+                       // don't emphasize "review changes" to the user.
+                       viewPage.sanityCheckVerified = true;
+               })
+               .always( function () {
+                       viewPage.sanityCheckFinished = true;
+                       viewPage.emit( 'sanityCheckComplete' );
+               } );
+};

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

Gerrit-MessageType: merged
Gerrit-Change-Id: I786b63ab57518fc6af7761501259ed66592f70e3
Gerrit-PatchSet: 25
Gerrit-Project: mediawiki/extensions/VisualEditor
Gerrit-Branch: master
Gerrit-Owner: Robmoen <[email protected]>
Gerrit-Reviewer: Catrope <[email protected]>
Gerrit-Reviewer: Jdlrobson <[email protected]>
Gerrit-Reviewer: Kaldari <[email protected]>
Gerrit-Reviewer: Krinkle <[email protected]>
Gerrit-Reviewer: Robmoen <[email protected]>
Gerrit-Reviewer: jenkins-bot

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

Reply via email to