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

Reply via email to