jenkins-bot has submitted this change and it was merged.
Change subject: Create GeneratedContentNode which can store rendered HTML in IV
store
......................................................................
Create GeneratedContentNode which can store rendered HTML in IV store
AlienNode is now a subclass of GCNode, but doesn't use the IV store yet.
Bug: 46571
Change-Id: If0717afdf557a2aa681d1bae3a6e98299631091a
---
M VisualEditor.php
M demos/ve/index.php
M modules/ve/ce/nodes/ve.ce.AlienNode.js
A modules/ve/ce/nodes/ve.ce.GeneratedContentNode.js
M modules/ve/dm/nodes/ve.dm.AlienNode.js
A modules/ve/dm/nodes/ve.dm.GeneratedContentNode.js
M modules/ve/dm/ve.dm.Converter.js
M modules/ve/dm/ve.dm.Node.js
M modules/ve/test/ce/ve.ce.ContentBranchNode.test.js
M modules/ve/test/index.php
10 files changed, 203 insertions(+), 30 deletions(-)
Approvals:
Catrope: Looks good to me, approved
Inez: Looks good to me, but someone else must approve
jenkins-bot: Verified
diff --git a/VisualEditor.php b/VisualEditor.php
index 23d2ca0..19bdc3d 100644
--- a/VisualEditor.php
+++ b/VisualEditor.php
@@ -251,6 +251,7 @@
've/dm/lineardata/ve.dm.ElementLinearData.js',
've/dm/lineardata/ve.dm.MetaLinearData.js',
+ 've/dm/nodes/ve.dm.GeneratedContentNode.js',
've/dm/nodes/ve.dm.AlienNode.js',
've/dm/nodes/ve.dm.BreakNode.js',
've/dm/nodes/ve.dm.CenterNode.js',
@@ -271,8 +272,8 @@
've/dm/nodes/ve.dm.MWEntityNode.js',
've/dm/nodes/ve.dm.MWHeadingNode.js',
- 've/dm/nodes/ve.dm.MWPreformattedNode.js',
've/dm/nodes/ve.dm.MWImageNode.js',
+ 've/dm/nodes/ve.dm.MWPreformattedNode.js',
've/dm/annotations/ve.dm.LinkAnnotation.js',
've/dm/annotations/ve.dm.MWExternalLinkAnnotation.js',
@@ -299,6 +300,7 @@
've/ce/ve.ce.Surface.js',
've/ce/ve.ce.SurfaceObserver.js',
+ 've/ce/nodes/ve.ce.GeneratedContentNode.js',
've/ce/nodes/ve.ce.AlienNode.js',
've/ce/nodes/ve.ce.AlienInlineNode.js',
've/ce/nodes/ve.ce.AlienBlockNode.js',
@@ -318,10 +320,11 @@
've/ce/nodes/ve.ce.TableRowNode.js',
've/ce/nodes/ve.ce.TableSectionNode.js',
've/ce/nodes/ve.ce.TextNode.js',
+
've/ce/nodes/ve.ce.MWEntityNode.js',
've/ce/nodes/ve.ce.MWHeadingNode.js',
- 've/ce/nodes/ve.ce.MWPreformattedNode.js',
've/ce/nodes/ve.ce.MWImageNode.js',
+ 've/ce/nodes/ve.ce.MWPreformattedNode.js',
've/ce/annotations/ve.ce.LinkAnnotation.js',
've/ce/annotations/ve.ce.MWExternalLinkAnnotation.js',
diff --git a/demos/ve/index.php b/demos/ve/index.php
index 6e30186..9bc6261 100644
--- a/demos/ve/index.php
+++ b/demos/ve/index.php
@@ -138,6 +138,7 @@
<script src="../../modules/ve/dm/ve.dm.Converter.js"></script>
<script
src="../../modules/ve/dm/lineardata/ve.dm.ElementLinearData.js"></script>
<script
src="../../modules/ve/dm/lineardata/ve.dm.MetaLinearData.js"></script>
+ <script
src="../../modules/ve/dm/nodes/ve.dm.GeneratedContentNode.js"></script>
<script
src="../../modules/ve/dm/nodes/ve.dm.AlienNode.js"></script>
<script
src="../../modules/ve/dm/nodes/ve.dm.BreakNode.js"></script>
<script
src="../../modules/ve/dm/nodes/ve.dm.CenterNode.js"></script>
@@ -157,8 +158,8 @@
<script
src="../../modules/ve/dm/nodes/ve.dm.TextNode.js"></script>
<script
src="../../modules/ve/dm/nodes/ve.dm.MWEntityNode.js"></script>
<script
src="../../modules/ve/dm/nodes/ve.dm.MWHeadingNode.js"></script>
- <script
src="../../modules/ve/dm/nodes/ve.dm.MWPreformattedNode.js"></script>
<script
src="../../modules/ve/dm/nodes/ve.dm.MWImageNode.js"></script>
+ <script
src="../../modules/ve/dm/nodes/ve.dm.MWPreformattedNode.js"></script>
<script
src="../../modules/ve/dm/annotations/ve.dm.LinkAnnotation.js"></script>
<script
src="../../modules/ve/dm/annotations/ve.dm.MWExternalLinkAnnotation.js"></script>
<script
src="../../modules/ve/dm/annotations/ve.dm.MWInternalLinkAnnotation.js"></script>
@@ -180,6 +181,7 @@
<script src="../../modules/ve/ce/ve.ce.LeafNode.js"></script>
<script src="../../modules/ve/ce/ve.ce.Surface.js"></script>
<script
src="../../modules/ve/ce/ve.ce.SurfaceObserver.js"></script>
+ <script
src="../../modules/ve/ce/nodes/ve.ce.GeneratedContentNode.js"></script>
<script
src="../../modules/ve/ce/nodes/ve.ce.AlienNode.js"></script>
<script
src="../../modules/ve/ce/nodes/ve.ce.AlienInlineNode.js"></script>
<script
src="../../modules/ve/ce/nodes/ve.ce.AlienBlockNode.js"></script>
diff --git a/modules/ve/ce/nodes/ve.ce.AlienNode.js
b/modules/ve/ce/nodes/ve.ce.AlienNode.js
index be9dabc..fa2b0da 100644
--- a/modules/ve/ce/nodes/ve.ce.AlienNode.js
+++ b/modules/ve/ce/nodes/ve.ce.AlienNode.js
@@ -9,30 +9,25 @@
* ContentEditable alien node.
*
* @class
- * @extends ve.ce.LeafNode
+ * @extends ve.ce.GeneratedContentNode
* @constructor
* @param {ve.dm.AlienNode} model Model to observe
*/
ve.ce.AlienNode = function VeCeAlienNode( model ) {
// Parent constructor
- ve.ce.LeafNode.call( this, model );
+ ve.ce.GeneratedContentNode.call( this, model );
// DOM Changes
this.$.addClass( 've-ce-alienNode' );
- this.$.attr( 'contenteditable', false );
// Events
- this.model.addListenerMethod( this, 'update', 'onUpdate' );
this.addListenerMethod( this, 'live', 'onLive' );
this.$.on( 'mouseenter', ve.bind( this.onMouseEnter, this ) );
-
- // Initialization
- this.onUpdate();
};
/* Inheritance */
-ve.inheritClass( ve.ce.AlienNode, ve.ce.LeafNode );
+ve.inheritClass( ve.ce.AlienNode, ve.ce.GeneratedContentNode );
/* Static Properties */
@@ -96,11 +91,6 @@
}
};
-/**
- * Handle update events.
- *
- * @method
- */
ve.ce.AlienNode.prototype.onUpdate = function () {
this.$.html( this.model.getAttribute( 'html' ) );
};
diff --git a/modules/ve/ce/nodes/ve.ce.GeneratedContentNode.js
b/modules/ve/ce/nodes/ve.ce.GeneratedContentNode.js
new file mode 100644
index 0000000..7d54b08
--- /dev/null
+++ b/modules/ve/ce/nodes/ve.ce.GeneratedContentNode.js
@@ -0,0 +1,100 @@
+/*!
+ * VisualEditor ContentEditable GeneratedContent class.
+ *
+ * @copyright 2011-2013 VisualEditor Team and others; see AUTHORS.txt
+ * @license The MIT License (MIT); see LICENSE.txt
+ */
+
+/**
+ * ContentEditable generated content node.
+ *
+ * @class
+ * @abstract
+ * @extends ve.ce.LeafNode
+ * @constructor
+ * @param {ve.dm.GeneratedContentNode} model Model to observe
+ */
+ve.ce.GeneratedContentNode = function VeCeGeneratedContentNode( model ) {
+ // Parent constructor
+ ve.ce.LeafNode.call( this, model );
+
+ // DOM Changes
+ this.$.addClass( 've-ce-generatedContentNode' );
+ this.$.attr( 'contenteditable', false );
+
+ // Events
+ this.model.addListenerMethod( this, 'update', 'onUpdate' );
+
+ // Initialization
+ this.onUpdate();
+};
+
+/* Inheritance */
+
+ve.inheritClass( ve.ce.GeneratedContentNode, ve.ce.LeafNode );
+
+/* Static Properties */
+
+ve.ce.GeneratedContentNode.static.name = 'generatedContent';
+
+/* Methods */
+
+/**
+ * Handle update events.
+ *
+ * @method
+ */
+ve.ce.GeneratedContentNode.prototype.onUpdate = function () {
+ var store = this.model.doc.getStore(),
+ index = store.indexOfHash( ve.getHash( this.model ) );
+ if ( index !== null ) {
+ this.$.html( store.value( index ) );
+ } else {
+ this.startGenerating();
+ this.generateContents()
+ .done( ve.bind( this.doneGenerating, this ) )
+ .fail( ve.bind( this.failGenerating, this ) );
+ }
+};
+
+/**
+ * Start a deferred process to generate the contents of the node.
+ * @returns {jQuery.Promise} Promise object
+ */
+ve.ce.GeneratedContentNode.prototype.generateContents = function () {
+ throw new Error( 've.ce.GeneratedContentNode subclass must implement
generateContents' );
+};
+
+/**
+ * Called when the node starts generating new content.
+ * @method
+ */
+ve.ce.GeneratedContentNode.prototype.startGenerating = function () {
+ // TODO: add 'generating' style
+};
+
+/**
+ * Called when the node successfully finishes generating new content.
+ *
+ * @method
+ * @param {string} contents Generated content
+ */
+ve.ce.GeneratedContentNode.prototype.doneGenerating = function ( contents ) {
+ var store = this.model.doc.getStore(),
+ hash = ve.getHash( this.model );
+ store.index( contents, hash );
+ // TODO: remove 'generating' style
+ this.onUpdate();
+};
+
+/**
+ * Called when the has failed to generate new content.
+ * @method
+ */
+ve.ce.GeneratedContentNode.prototype.failGenerating = function () {
+ // TODO: remove 'generating' style
+};
+
+/* Registration */
+
+ve.ce.nodeFactory.register( ve.ce.GeneratedContentNode );
diff --git a/modules/ve/dm/nodes/ve.dm.AlienNode.js
b/modules/ve/dm/nodes/ve.dm.AlienNode.js
index 0d60f1b..29132f4 100644
--- a/modules/ve/dm/nodes/ve.dm.AlienNode.js
+++ b/modules/ve/dm/nodes/ve.dm.AlienNode.js
@@ -10,27 +10,23 @@
*
* @class
* @abstract
- * @extends ve.dm.LeafNode
+ * @extends ve.dm.GeneratedContentNode
* @constructor
* @param {number} [length] Length of content data in document; ignored and
overridden to 0
* @param {Object} [element] Reference to element in linear model
*/
ve.dm.AlienNode = function VeDmAlienNode( length, element ) {
// Parent constructor
- ve.dm.LeafNode.call( this, 0, element );
+ ve.dm.GeneratedContentNode.call( this, 0, element );
};
/* Inheritance */
-ve.inheritClass( ve.dm.AlienNode, ve.dm.LeafNode );
+ve.inheritClass( ve.dm.AlienNode, ve.dm.GeneratedContentNode );
/* Static members */
ve.dm.AlienNode.static.name = 'alien';
-
-ve.dm.AlienNode.static.matchTagNames = [];
-
-ve.dm.AlienNode.static.enableAboutGrouping = true;
ve.dm.AlienNode.static.storeHtmlAttributes = false;
diff --git a/modules/ve/dm/nodes/ve.dm.GeneratedContentNode.js
b/modules/ve/dm/nodes/ve.dm.GeneratedContentNode.js
new file mode 100644
index 0000000..405afc8
--- /dev/null
+++ b/modules/ve/dm/nodes/ve.dm.GeneratedContentNode.js
@@ -0,0 +1,50 @@
+/*!
+ * VisualEditor DataModel GeneratedContentNode class.
+ *
+ * @copyright 2011-2013 VisualEditor Team and others; see AUTHORS.txt
+ * @license The MIT License (MIT); see LICENSE.txt
+ */
+
+/**
+ * DataModel generated content node.
+ *
+ * @class
+ * @abstract
+ * @extends ve.dm.LeafNode
+ * @constructor
+ * @param {number} [length] Length of content data in document; ignored and
overridden to 0
+ * @param {Object} [element] Reference to element in linear model
+ */
+ve.dm.GeneratedContentNode = function VeDmGeneratedContentNode( length,
element ) {
+ // Parent constructor
+ ve.dm.LeafNode.call( this, 0, element );
+};
+
+/* Inheritance */
+
+ve.inheritClass( ve.dm.GeneratedContentNode, ve.dm.LeafNode );
+
+/* Static members */
+
+ve.dm.GeneratedContentNode.static.name = 'generatedContent';
+
+ve.dm.GeneratedContentNode.static.matchTagNames = [];
+
+ve.dm.GeneratedContentNode.static.enableAboutGrouping = true;
+
+/**
+ * Store HTML of DOM elements, hashed on data element
+ * @param {Object} dataElement Data element
+ * @param {HTMLElement[]} domElements DOM elements
+ * @param {ve.dm.IndexValueStore} store Index-value store
+ * @returns {number} Index of stored data
+ */
+ve.dm.GeneratedContentNode.static.storeHtml = function( dataElement,
domElements, store ) {
+ var html = $( '<div>', domElements[0].ownerDocument ).append( $(
domElements ).clone() ).html(),
+ hash = ve.getHash( this.getHashObject( dataElement ) );
+ return store.index( html, hash );
+};
+
+/* Registration */
+
+ve.dm.modelRegistry.register( ve.dm.GeneratedContentNode );
\ No newline at end of file
diff --git a/modules/ve/dm/ve.dm.Converter.js b/modules/ve/dm/ve.dm.Converter.js
index 8b23684..5fc438c 100644
--- a/modules/ve/dm/ve.dm.Converter.js
+++ b/modules/ve/dm/ve.dm.Converter.js
@@ -148,11 +148,12 @@
* @param {ve.dm.Model} modelClass Model class to use for conversion
* @param {HTMLElement[]} domElements DOM elements to convert
* @param {Object} context Converter context to pass to toDataElement() (will
be cloned)
+ * @param {ve.dm.IndexValueStore} store Index-value store
* @returns {Object} Data element
*/
-ve.dm.Converter.prototype.createDataElement = function ( modelClass,
domElements, context ) {
+ve.dm.Converter.prototype.createDataElement = function ( modelClass,
domElements, context, store ) {
var i, j, dataElement, dataElementAttributes, domElementAttributes,
domElementAttribute;
- dataElement = modelClass.static.toDataElement( domElements,
ve.copyObject( context ) );
+ dataElement = modelClass.static.toDataElement( domElements,
ve.copyObject( context ), store );
if ( modelClass.static.storeHtmlAttributes && dataElement ) {
for ( i = 0; i < domElements.length; i++ ) {
domElementAttributes = domElements[i].attributes;
@@ -340,7 +341,7 @@
aboutGroup = getAboutGroup(
childDomElement );
childDomElements =
modelClass.static.enableAboutGrouping ?
aboutGroup : [ childDomElement
];
- childDataElement =
this.createDataElement( modelClass, childDomElements, context );
+ childDataElement =
this.createDataElement( modelClass, childDomElements, context, store );
if ( modelClass.prototype instanceof
ve.dm.MetaItem ) {
// No additional processing
needed
@@ -366,7 +367,7 @@
modelClass =
ve.dm.AlienNode;
childDomElements =
modelClass.static.enableAboutGrouping ?
aboutGroup : [
childDomElement ];
- childDataElement =
this.createDataElement( modelClass, childDomElements, context );
+ childDataElement =
this.createDataElement( modelClass, childDomElements, context, store );
childIsContent =
this.nodeFactory.isNodeContent( childDataElement.type );
}
}
diff --git a/modules/ve/dm/ve.dm.Node.js b/modules/ve/dm/ve.dm.Node.js
index 0cf9063..750fdc0 100644
--- a/modules/ve/dm/ve.dm.Node.js
+++ b/modules/ve/dm/ve.dm.Node.js
@@ -140,6 +140,20 @@
*/
ve.dm.Node.static.defaultAttributes = {};
+/**
+ * Get hash object of a linear model data element
+ *
+ * @static
+ * @param {Object} dataElement Data element
+ * @returns {Object} Hash object
+ */
+ve.dm.Node.static.getHashObject = function ( dataElement ) {
+ return {
+ type: dataElement.type,
+ attributes: dataElement.attributes
+ };
+};
+
/* Methods */
/**
@@ -411,3 +425,18 @@
}
return true;
};
+
+/**
+ * Get the hash object of the node.
+ *
+ * The actual logic is in a static function as this needs
+ * to be accessible from ve.dm.Converter
+ *
+ * This is a custom hash function for ve#getHash.
+ *
+ * @method
+ * @returns {Object} Hash object
+ */
+ve.dm.Node.prototype.getHashObject = function () {
+ return this.constructor.static.getHashObject( this.element );
+};
diff --git a/modules/ve/test/ce/ve.ce.ContentBranchNode.test.js
b/modules/ve/test/ce/ve.ce.ContentBranchNode.test.js
index 1a1bd4e..fdc88f6 100644
--- a/modules/ve/test/ce/ve.ce.ContentBranchNode.test.js
+++ b/modules/ve/test/ce/ve.ce.ContentBranchNode.test.js
@@ -245,7 +245,7 @@
],
'html': 'a<b>b<span typeof="mw:Entity"
class="ve-ce-leafNode ' +
've-ce-MWEntityNode"
contenteditable="false">c</span>d<div ' +
- 'class="ve-ce-leafNode ve-ce-alienNode
ve-ce-alienInlineNode" ' +
+ 'class="ve-ce-leafNode
ve-ce-generatedContentNode ve-ce-alienNode ve-ce-alienInlineNode" ' +
'contenteditable="false"><tt>e</tt></div></b>'
}
];
diff --git a/modules/ve/test/index.php b/modules/ve/test/index.php
index 8bb9d8d..7ec6876 100644
--- a/modules/ve/test/index.php
+++ b/modules/ve/test/index.php
@@ -82,6 +82,7 @@
<script src="../../ve/dm/ve.dm.Converter.js"></script>
<script
src="../../ve/dm/lineardata/ve.dm.ElementLinearData.js"></script>
<script
src="../../ve/dm/lineardata/ve.dm.MetaLinearData.js"></script>
+ <script
src="../../ve/dm/nodes/ve.dm.GeneratedContentNode.js"></script>
<script src="../../ve/dm/nodes/ve.dm.AlienNode.js"></script>
<script src="../../ve/dm/nodes/ve.dm.BreakNode.js"></script>
<script src="../../ve/dm/nodes/ve.dm.CenterNode.js"></script>
@@ -101,8 +102,8 @@
<script src="../../ve/dm/nodes/ve.dm.TextNode.js"></script>
<script src="../../ve/dm/nodes/ve.dm.MWEntityNode.js"></script>
<script src="../../ve/dm/nodes/ve.dm.MWHeadingNode.js"></script>
- <script
src="../../ve/dm/nodes/ve.dm.MWPreformattedNode.js"></script>
<script src="../../ve/dm/nodes/ve.dm.MWImageNode.js"></script>
+ <script
src="../../ve/dm/nodes/ve.dm.MWPreformattedNode.js"></script>
<script
src="../../ve/dm/annotations/ve.dm.LinkAnnotation.js"></script>
<script
src="../../ve/dm/annotations/ve.dm.MWExternalLinkAnnotation.js"></script>
<script
src="../../ve/dm/annotations/ve.dm.MWInternalLinkAnnotation.js"></script>
@@ -124,6 +125,7 @@
<script src="../../ve/ce/ve.ce.LeafNode.js"></script>
<script src="../../ve/ce/ve.ce.Surface.js"></script>
<script src="../../ve/ce/ve.ce.SurfaceObserver.js"></script>
+ <script
src="../../ve/ce/nodes/ve.ce.GeneratedContentNode.js"></script>
<script src="../../ve/ce/nodes/ve.ce.AlienNode.js"></script>
<script
src="../../ve/ce/nodes/ve.ce.AlienInlineNode.js"></script>
<script
src="../../ve/ce/nodes/ve.ce.AlienBlockNode.js"></script>
@@ -145,8 +147,8 @@
<script src="../../ve/ce/nodes/ve.ce.TextNode.js"></script>
<script src="../../ve/ce/nodes/ve.ce.MWEntityNode.js"></script>
<script src="../../ve/ce/nodes/ve.ce.MWHeadingNode.js"></script>
- <script
src="../../ve/ce/nodes/ve.ce.MWPreformattedNode.js"></script>
<script src="../../ve/ce/nodes/ve.ce.MWImageNode.js"></script>
+ <script
src="../../ve/ce/nodes/ve.ce.MWPreformattedNode.js"></script>
<script
src="../../ve/ce/annotations/ve.ce.LinkAnnotation.js"></script>
<script
src="../../ve/ce/annotations/ve.ce.MWExternalLinkAnnotation.js"></script>
<script
src="../../ve/ce/annotations/ve.ce.MWInternalLinkAnnotation.js"></script>
--
To view, visit https://gerrit.wikimedia.org/r/57326
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: merged
Gerrit-Change-Id: If0717afdf557a2aa681d1bae3a6e98299631091a
Gerrit-PatchSet: 15
Gerrit-Project: mediawiki/extensions/VisualEditor
Gerrit-Branch: master
Gerrit-Owner: Esanders <[email protected]>
Gerrit-Reviewer: Catrope <[email protected]>
Gerrit-Reviewer: Esanders <[email protected]>
Gerrit-Reviewer: Inez <[email protected]>
Gerrit-Reviewer: jenkins-bot
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits