Some basic async code in the initialization

Break setUpSurface into a bunch of parts that setTimeout() each other.
This breaks the initialization of the editor as a whole up into the
following phases:
0) Receive AJAX response, parse HTML
1) Build linear model data
2) Build DM tree
3) Build CE tree, CE DOM, create surface
4) Initialize surface, some UI initialization
5) Launch sanity check, remaining setup, unlock editor

This is a bit hacky right now, we'll probably want to refactor later.

ve.dm.InternalList.js:
* Allow construction without a dm.Document

ve.ui.Surface.js:
* Allow construction based on a dm.Document

Change-Id: Ibf48a7e85cd7376c8f6205ed165ff57e71e34c35
This commit is contained in:
Roan Kattouw 2013-07-01 13:02:10 -07:00
parent 8b24c9779a
commit c41f96cf6b
3 changed files with 63 additions and 40 deletions

View file

@ -28,7 +28,9 @@ ve.dm.InternalList = function VeDmInternalList( doc ) {
this.keys = [];
// Event handlers
this.getDocument().connect( this, { 'transact': 'onTransact' } );
if ( doc ) {
doc.connect( this, { 'transact': 'onTransact' } );
}
};
/* Inheritance */

View file

@ -353,19 +353,20 @@ ve.init.mw.ViewPageTarget.prototype.onLoad = function ( doc ) {
this.logEvent( 'Edit', { action: 'page-edit-impression' } );
this.edited = false;
this.doc = doc;
this.setUpSurface( doc );
this.startSanityCheck();
this.setupToolbarEditNotices();
this.setupToolbarBetaNotice();
this.setupToolbarButtons();
this.setupSaveDialog();
this.attachToolbarButtons();
this.attachSaveDialog();
this.restoreScrollPosition();
this.restoreEditSection();
this.setupBeforeUnloadHandler();
this.$document[0].focus();
this.activating = false;
this.setUpSurface( doc, ve.bind( function() {
this.startSanityCheck();
this.setupToolbarEditNotices();
this.setupToolbarBetaNotice();
this.setupToolbarButtons();
this.setupSaveDialog();
this.attachToolbarButtons();
this.attachSaveDialog();
this.restoreScrollPosition();
this.restoreEditSection();
this.setupBeforeUnloadHandler();
this.$document[0].focus();
this.activating = false;
}, this ) );
}
};
@ -934,32 +935,50 @@ ve.init.mw.ViewPageTarget.prototype.setupToolbarBetaNotice = function () {
*
* @method
* @param {HTMLDocument} doc HTML DOM to edit
* @param {Function} [callback] Callback to call when done
*/
ve.init.mw.ViewPageTarget.prototype.setUpSurface = function ( doc ) {
// Initialize surface
this.surface = new ve.ui.Surface( doc, this.surfaceOptions );
this.surface.connect( this, { 'toolbarPosition': 'onSurfaceToolbarPosition' } );
this.surface.getContext().hide();
this.$document = this.surface.$.find( '.ve-ce-documentNode' );
this.surface.getModel().connect( this, { 'transact': 'onSurfaceModelTransact' } );
this.surface.getModel().connect( this, { 'history': 'updateToolbarSaveButtonState' } );
this.$.append( this.surface.$ );
this.setUpToolbar();
this.transformPageTitle();
this.changeDocumentTitle();
ve.init.mw.ViewPageTarget.prototype.setUpSurface = function ( doc, callback ) {
setTimeout( ve.bind( function () {
// Build linmod
var store = new ve.dm.IndexValueStore(),
internalList = new ve.dm.InternalList(),
data = ve.dm.converter.getDataFromDom( doc, store, internalList );
setTimeout( ve.bind( function () {
// Build DM tree
var dmDoc = new ve.dm.Document( data, undefined, internalList );
setTimeout( ve.bind( function () {
// Create ui.Surface (also creates ce.Surface and dm.Surface and builds CE tree)
this.surface = new ve.ui.Surface( dmDoc, this.surfaceOptions );
setTimeout( ve.bind( function () {
// Initialize surface
this.surface.connect( this, { 'toolbarPosition': 'onSurfaceToolbarPosition' } );
this.surface.getContext().hide();
this.$document = this.surface.$.find( '.ve-ce-documentNode' );
this.surface.getModel().connect( this, { 'transact': 'onSurfaceModelTransact' } );
this.surface.getModel().connect( this, { 'history': 'updateToolbarSaveButtonState' } );
this.$.append( this.surface.$ );
this.setUpToolbar();
this.transformPageTitle();
this.changeDocumentTitle();
// Update UI
this.hidePageContent();
this.hideSpinner();
this.active = true;
this.$document.attr( {
'lang': mw.config.get( 'wgVisualEditor' ).pageLanguageCode,
'dir': mw.config.get( 'wgVisualEditor' ).pageLanguageDir
} );
// Update UI
this.hidePageContent();
this.hideSpinner();
this.active = true;
this.$document.attr( {
'lang': mw.config.get( 'wgVisualEditor' ).pageLanguageCode,
'dir': mw.config.get( 'wgVisualEditor' ).pageLanguageDir
} );
// Add appropriately mw-content-ltr or mw-content-rtl class
this.surface.$.addClass( 'mw-content-' + mw.config.get( 'wgVisualEditor' ).pageLanguageDir );
this.surface.initialize();
// Add appropriately mw-content-ltr or mw-content-rtl class
this.surface.$.addClass( 'mw-content-' + mw.config.get( 'wgVisualEditor' ).pageLanguageDir );
this.surface.initialize();
setTimeout( callback );
}, this ) );
}, this ) );
}, this ) );
}, this ) );
};
/**

View file

@ -12,10 +12,10 @@
* @extends ve.Element
*
* @constructor
* @param {HTMLDocument|Array|ve.dm.LinearData} data Document data to edit
* @param {HTMLDocument|Array|ve.dm.LinearData|ve.dm.Document} data Document data to edit
* @param {Object} [config] Config options
*/
ve.ui.Surface = function VeUiSurface( data, config ) {
ve.ui.Surface = function VeUiSurface( dataOrDoc, config ) {
// Parent constructor
ve.Element.call( this, config );
@ -28,7 +28,9 @@ ve.ui.Surface = function VeUiSurface( data, config ) {
this.$localOverlayBlockers = this.$$( '<div>' );
this.$localOverlayControls = this.$$( '<div>' );
this.$localOverlayMenus = this.$$( '<div>' );
this.model = new ve.dm.Surface( new ve.dm.Document( data ) );
this.model = new ve.dm.Surface(
dataOrDoc instanceof ve.dm.Document ? dataOrDoc : new ve.dm.Document( dataOrDoc )
);
this.view = new ve.ce.Surface( this.model, this, { '$$': this.$$ } );
this.context = new ve.ui.Context( this, { '$$': this.$$ } );
this.dialogs = new ve.ui.WindowSet( this, ve.ui.dialogFactory );