mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/VisualEditor
synced 2024-11-25 14:56:20 +00:00
7673a39878
GeneratedContentNode didn't track concurrent updates at all, so a race condition was possible: if the node was updated a second time before the first update had been rendered, the second update might render first and then be overwritten by the other one. To prevent this, we track the promise associated with the current render. If a new update is launched while a previous one is still pending we attempt to abort the old one by calling .abort() on it, and ignore any future resolution or rejection from it. Also allow rerenders based on non-model data by calling .update( { config object } ); Change-Id: I8feefd9e8fb6c41d06b8b20131e3be5e37954e83
116 lines
2.7 KiB
JavaScript
116 lines
2.7 KiB
JavaScript
/*!
|
|
* VisualEditor ContentEditable AlienNode, AlienBlockNode and AlienInlineNode classes.
|
|
*
|
|
* @copyright 2011-2013 VisualEditor Team and others; see AUTHORS.txt
|
|
* @license The MIT License (MIT); see LICENSE.txt
|
|
*/
|
|
|
|
/**
|
|
* ContentEditable alien node.
|
|
*
|
|
* @class
|
|
* @abstract
|
|
* @extends ve.ce.LeafNode
|
|
* @mixins ve.ce.ProtectedNode
|
|
* @mixins ve.ce.GeneratedContentNode
|
|
*
|
|
* @constructor
|
|
* @param {ve.dm.AlienNode} model Model to observe
|
|
* @param {Object} [config] Config options
|
|
*/
|
|
ve.ce.AlienNode = function VeCeAlienNode( model, config ) {
|
|
// Parent constructor
|
|
ve.ce.LeafNode.call( this, model, config );
|
|
|
|
// Mixin constructors
|
|
ve.ce.ProtectedNode.call( this );
|
|
ve.ce.GeneratedContentNode.call( this );
|
|
|
|
// DOM Changes
|
|
this.$.addClass( 've-ce-alienNode' );
|
|
};
|
|
|
|
/* Inheritance */
|
|
|
|
ve.inheritClass( ve.ce.AlienNode, ve.ce.LeafNode );
|
|
|
|
ve.mixinClass( ve.ce.AlienNode, ve.ce.ProtectedNode );
|
|
|
|
ve.mixinClass( ve.ce.AlienNode, ve.ce.GeneratedContentNode );
|
|
|
|
/* Static Properties */
|
|
|
|
ve.ce.AlienNode.static.name = 'alien';
|
|
|
|
ve.ce.AlienNode.static.$phantomTemplate = ve.ce.AlienNode.static.$phantomTemplate.clone()
|
|
.addClass( 've-ce-alienNode-phantom' )
|
|
.attr( 'title', ve.msg( 'visualeditor-aliennode-tooltip' ) );
|
|
|
|
/* Methods */
|
|
|
|
/**
|
|
* Handle update events.
|
|
*
|
|
* @method
|
|
*/
|
|
ve.ce.AlienNode.prototype.update = function () {
|
|
// TODO use GeneratedContentNode the way it was meant to be used
|
|
this.$.html( ve.copyDomElements( this.model.getAttribute( 'domElements' ) || [], this.getElementDocument() ) );
|
|
};
|
|
|
|
/* Concrete subclasses */
|
|
|
|
/**
|
|
* ContentEditable alien block node.
|
|
*
|
|
* @class
|
|
* @extends ve.ce.AlienNode
|
|
* @constructor
|
|
* @param {ve.dm.AlienBlockNode} model Model to observe
|
|
*/
|
|
ve.ce.AlienBlockNode = function VeCeAlienBlockNode( model ) {
|
|
// Parent constructor
|
|
ve.ce.AlienNode.call( this, model );
|
|
|
|
// DOM Changes
|
|
this.$.addClass( 've-ce-alienBlockNode' );
|
|
};
|
|
|
|
/* Inheritance */
|
|
|
|
ve.inheritClass( ve.ce.AlienBlockNode, ve.ce.AlienNode );
|
|
|
|
/* Static Properties */
|
|
|
|
ve.ce.AlienBlockNode.static.name = 'alienBlock';
|
|
|
|
/**
|
|
* ContentEditable alien inline node.
|
|
*
|
|
* @class
|
|
* @extends ve.ce.AlienNode
|
|
* @constructor
|
|
* @param {ve.dm.AlienInlineNode} model Model to observe
|
|
*/
|
|
ve.ce.AlienInlineNode = function VeCeAlienInlineNode( model ) {
|
|
// Parent constructor
|
|
ve.ce.AlienNode.call( this, model );
|
|
|
|
// DOM Changes
|
|
this.$.addClass( 've-ce-alienInlineNode' );
|
|
};
|
|
|
|
/* Inheritance */
|
|
|
|
ve.inheritClass( ve.ce.AlienInlineNode, ve.ce.AlienNode );
|
|
|
|
/* Static Properties */
|
|
|
|
ve.ce.AlienInlineNode.static.name = 'alienInline';
|
|
|
|
/* Registration */
|
|
|
|
ve.ce.nodeFactory.register( ve.ce.AlienNode );
|
|
ve.ce.nodeFactory.register( ve.ce.AlienBlockNode );
|
|
ve.ce.nodeFactory.register( ve.ce.AlienInlineNode );
|