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

Change subject: Change MetaNodes to MetaItems
......................................................................


Change MetaNodes to MetaItems

Rather than meta-things being special kinds of nodes, they are now a
separate class of things (MetaItems) along with Nodes and Annotations.

* Created a generic ve.dm.MetaItem that meta items inherit from.
  There will be actual instances of this class as well in the upcoming
  meta group code.
* Renamed MetaNode to AlienMetaItem, MWMetaNode to MWMetaItem,
  'metaBlock'/'metaInline' to 'alienMeta'
* Created a MetaItemFactory, handle meta items in the ModelRegistry
* Kill ve.dm.Node.static.isMeta, now obsolete

ve.dm.Converter:
* Pass in the MetaItemFactory
* Look up data element types in the ModelRegistry rather than the
  NodeFactory, because they can be either nodes or meta items
* Document createDataElement() and make explicit that modelClass can be
  either a node or a meta item
* Handle meta items in getDataFromDom()
* In getDomFromData(), check the MetaItemFactory as well as the NodeFactory

Change-Id: I893709c6f3aa00f85c1b905b70f9f4e597bdeada
---
M .docs/categories.json
M VisualEditor.php
M demos/ve/index.php
A modules/ve/dm/metaitems/ve.dm.AlienMetaItem.js
A modules/ve/dm/metaitems/ve.dm.MWMetaItem.js
D modules/ve/dm/nodes/ve.dm.MWMetaNode.js
D modules/ve/dm/nodes/ve.dm.MetaNode.js
M modules/ve/dm/ve.dm.Annotation.js
M modules/ve/dm/ve.dm.Converter.js
M modules/ve/dm/ve.dm.Document.js
A modules/ve/dm/ve.dm.MetaItem.js
A modules/ve/dm/ve.dm.MetaItemFactory.js
M modules/ve/dm/ve.dm.ModelRegistry.js
M modules/ve/dm/ve.dm.Node.js
M modules/ve/dm/ve.dm.NodeFactory.js
M modules/ve/test/dm/ve.dm.Transaction.test.js
M modules/ve/test/dm/ve.dm.TransactionProcessor.test.js
M modules/ve/test/dm/ve.dm.example.js
M modules/ve/test/index.php
M modules/ve/ve.Node.js
20 files changed, 392 insertions(+), 227 deletions(-)

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



diff --git a/.docs/categories.json b/.docs/categories.json
index 6900e4f..96e04d1 100644
--- a/.docs/categories.json
+++ b/.docs/categories.json
@@ -46,6 +46,10 @@
                                "classes": ["ve.dm.*Annotation"]
                        },
                        {
+                               "name": "Meta items",
+                               "classes": ["ve.dm.*MetaItem"]
+                       },
+                       {
                                "name": "Nodes",
                                "classes": ["ve.dm.Document", "ve.dm.*Node"]
                        }
diff --git a/VisualEditor.php b/VisualEditor.php
index cdca7b6..e18bd00 100644
--- a/VisualEditor.php
+++ b/VisualEditor.php
@@ -218,10 +218,12 @@
                        've/dm/ve.dm.ModelRegistry.js',
                        've/dm/ve.dm.NodeFactory.js',
                        've/dm/ve.dm.AnnotationFactory.js',
+                       've/dm/ve.dm.MetaItemFactory.js',
                        've/dm/ve.dm.Node.js',
                        've/dm/ve.dm.BranchNode.js',
                        've/dm/ve.dm.LeafNode.js',
                        've/dm/ve.dm.Annotation.js',
+                       've/dm/ve.dm.MetaItem.js',
                        've/dm/ve.dm.TransactionProcessor.js',
                        've/dm/ve.dm.Transaction.js',
                        've/dm/ve.dm.Surface.js',
@@ -241,7 +243,6 @@
                        've/dm/nodes/ve.dm.ImageNode.js',
                        've/dm/nodes/ve.dm.ListItemNode.js',
                        've/dm/nodes/ve.dm.ListNode.js',
-                       've/dm/nodes/ve.dm.MetaNode.js',
                        've/dm/nodes/ve.dm.ParagraphNode.js',
                        've/dm/nodes/ve.dm.PreformattedNode.js',
                        've/dm/nodes/ve.dm.TableCellNode.js',
@@ -260,6 +261,9 @@
                        've/dm/annotations/ve.dm.MWInternalLinkAnnotation.js',
                        've/dm/annotations/ve.dm.TextStyleAnnotation.js',
 
+                       've/dm/metaitems/ve.dm.AlienMetaItem.js',
+                       've/dm/metaitems/ve.dm.MWMetaItem.js',
+
                        // ce
                        've/ce/ve.ce.js',
                        've/ce/ve.ce.DomRange.js',
diff --git a/demos/ve/index.php b/demos/ve/index.php
index 9deb8b8..e6640c0 100644
--- a/demos/ve/index.php
+++ b/demos/ve/index.php
@@ -114,10 +114,12 @@
                <script 
src="../../modules/ve/dm/ve.dm.ModelRegistry.js"></script>
                <script src="../../modules/ve/dm/ve.dm.NodeFactory.js"></script>
                <script 
src="../../modules/ve/dm/ve.dm.AnnotationFactory.js"></script>
+               <script 
src="../../modules/ve/dm/ve.dm.MetaItemFactory.js"></script>
                <script src="../../modules/ve/dm/ve.dm.Node.js"></script>
                <script src="../../modules/ve/dm/ve.dm.BranchNode.js"></script>
                <script src="../../modules/ve/dm/ve.dm.LeafNode.js"></script>
                <script src="../../modules/ve/dm/ve.dm.Annotation.js"></script>
+               <script src="../../modules/ve/dm/ve.dm.MetaItem.js"></script>
                <script 
src="../../modules/ve/dm/ve.dm.TransactionProcessor.js"></script>
                <script src="../../modules/ve/dm/ve.dm.Transaction.js"></script>
                <script src="../../modules/ve/dm/ve.dm.Surface.js"></script>
@@ -136,9 +138,7 @@
                <script 
src="../../modules/ve/dm/nodes/ve.dm.ImageNode.js"></script>
                <script 
src="../../modules/ve/dm/nodes/ve.dm.ListItemNode.js"></script>
                <script 
src="../../modules/ve/dm/nodes/ve.dm.ListNode.js"></script>
-               <script 
src="../../modules/ve/dm/nodes/ve.dm.MetaNode.js"></script>
                <script 
src="../../modules/ve/dm/nodes/ve.dm.MWEntityNode.js"></script>
-               <script 
src="../../modules/ve/dm/nodes/ve.dm.MWMetaNode.js"></script>
                <script 
src="../../modules/ve/dm/nodes/ve.dm.ParagraphNode.js"></script>
                <script 
src="../../modules/ve/dm/nodes/ve.dm.PreformattedNode.js"></script>
                <script 
src="../../modules/ve/dm/nodes/ve.dm.TableCellNode.js"></script>
@@ -150,6 +150,8 @@
                <script 
src="../../modules/ve/dm/annotations/ve.dm.MWExternalLinkAnnotation.js"></script>
                <script 
src="../../modules/ve/dm/annotations/ve.dm.MWInternalLinkAnnotation.js"></script>
                <script 
src="../../modules/ve/dm/annotations/ve.dm.TextStyleAnnotation.js"></script>
+               <script 
src="../../modules/ve/dm/metaitems/ve.dm.AlienMetaItem.js"></script>
+               <script 
src="../../modules/ve/dm/metaitems/ve.dm.MWMetaItem.js"></script>
                <script src="../../modules/ve/ce/ve.ce.js"></script>
                <script src="../../modules/ve/ce/ve.ce.DomRange.js"></script>
                <script src="../../modules/ve/ce/ve.ce.NodeFactory.js"></script>
diff --git a/modules/ve/dm/metaitems/ve.dm.AlienMetaItem.js 
b/modules/ve/dm/metaitems/ve.dm.AlienMetaItem.js
new file mode 100644
index 0000000..ef8ea24
--- /dev/null
+++ b/modules/ve/dm/metaitems/ve.dm.AlienMetaItem.js
@@ -0,0 +1,71 @@
+/*!
+ * VisualEditor DataModel AlienMetaItem class.
+ *
+ * @copyright 2011-2013 VisualEditor Team and others; see AUTHORS.txt
+ * @license The MIT License (MIT); see LICENSE.txt
+ */
+
+/**
+ * DataModel alien meta item.
+ *
+ * @class
+ * @extends ve.dm.MetaItem
+ * @constructor
+ * @param {Object} element Reference to element in meta-linmod
+ */
+ve.dm.AlienMetaItem = function VeDmAlienMetaItem( element ) {
+       // Parent constructor
+       ve.dm.MetaItem.call( this, element );
+};
+
+/* Inheritance */
+
+ve.inheritClass( ve.dm.AlienMetaItem, ve.dm.MetaItem );
+
+/* Static Properties */
+
+ve.dm.AlienMetaItem.static.name = 'alienMeta';
+
+ve.dm.AlienMetaItem.static.matchTagNames = [ 'meta', 'link' ];
+
+ve.dm.AlienMetaItem.static.toDataElement = function ( domElements ) {
+       var firstDomElement = domElements[0],
+               isLink = firstDomElement.nodeName.toLowerCase() === 'link',
+               keyAttr = isLink ? 'rel' : 'property',
+               valueAttr = isLink ? 'href' : 'content',
+               dataElement = {
+                       'type': 'alienMeta',
+                       'attributes': {
+                               'style': isLink ? 'link' : 'meta',
+                               'key': firstDomElement.getAttribute( keyAttr )
+                       }
+               };
+       if ( firstDomElement.hasAttribute( valueAttr ) ) {
+               dataElement.attributes.value = firstDomElement.getAttribute( 
valueAttr );
+       }
+       return dataElement;
+};
+
+ve.dm.AlienMetaItem.static.toDomElements = function ( dataElement ) {
+       var style = dataElement.attributes && dataElement.attributes.style || 
'meta',
+               isLink = style === 'link',
+               tag = isLink ? 'link' : 'meta',
+               keyAttr = isLink ? 'rel' : 'property',
+               valueAttr = isLink ? 'href' : 'content',
+               domElement;
+       if ( style === 'comment' ) {
+               return [ document.createComment( dataElement.attributes && 
dataElement.attributes.text || '' ) ];
+       }
+       domElement = document.createElement( tag );
+       if ( dataElement.attributes && dataElement.attributes.key !== null ) {
+               domElement.setAttribute( keyAttr, dataElement.attributes.key );
+       }
+       if ( dataElement.attributes && dataElement.attributes.value ) {
+               domElement.setAttribute( valueAttr, 
dataElement.attributes.value );
+       }
+       return [ domElement ];
+};
+
+/* Registration */
+
+ve.dm.modelRegistry.register( ve.dm.AlienMetaItem );
diff --git a/modules/ve/dm/metaitems/ve.dm.MWMetaItem.js 
b/modules/ve/dm/metaitems/ve.dm.MWMetaItem.js
new file mode 100644
index 0000000..050c460
--- /dev/null
+++ b/modules/ve/dm/metaitems/ve.dm.MWMetaItem.js
@@ -0,0 +1,38 @@
+/*!
+ * VisualEditor DataModel MWMetaItem class.
+ *
+ * @copyright 2011-2013 VisualEditor Team and others; see AUTHORS.txt
+ * @license The MIT License (MIT); see LICENSE.txt
+ */
+
+/**
+ * DataModel MW-specific meta item.
+ *
+ * @class
+ * @abstract
+ * @extends ve.dm.AlienMetaItem
+ * @constructor
+ * @param {Object} element Reference to element in meta-linmod
+ */
+ve.dm.MWMetaItem = function VeDmMWMetaItem( element ) {
+       // Parent constructor
+       ve.dm.AlienMetaItem.call( this, element );
+};
+
+/* Inheritance */
+
+ve.inheritClass( ve.dm.MWMetaItem, ve.dm.AlienMetaItem );
+
+/* Static Properties */
+
+ve.dm.MWMetaItem.static.name = 'MWmeta';
+
+ve.dm.MWMetaItem.static.matchRdfaTypes = [ /^mw:/ ];
+
+// toDataElement inherited from AlienMetaItem, will return regular alienMeta 
elements but
+// that's fine. This class is only here so that <meta>/<link> tags with an mw: 
type are correctly
+// mapped to AlienMetaItem rather than AlienNode.
+
+/* Registration */
+
+ve.dm.modelRegistry.register( ve.dm.MWMetaItem );
diff --git a/modules/ve/dm/nodes/ve.dm.MWMetaNode.js 
b/modules/ve/dm/nodes/ve.dm.MWMetaNode.js
deleted file mode 100644
index eb214fd..0000000
--- a/modules/ve/dm/nodes/ve.dm.MWMetaNode.js
+++ /dev/null
@@ -1,39 +0,0 @@
-/*!
- * VisualEditor DataModel MWMetaNode class.
- *
- * @copyright 2011-2013 VisualEditor Team and others; see AUTHORS.txt
- * @license The MIT License (MIT); see LICENSE.txt
- */
-
-/**
- * DataModel MW-specific meta node.
- *
- * @class
- * @abstract
- * @extends ve.dm.MetaNode
- * @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.MWMetaNode = function VeDmMWMetaNode( length, element ) {
-       // Parent constructor
-       ve.dm.LeafNode.call( this, 0, element );
-};
-
-/* Inheritance */
-
-ve.inheritClass( ve.dm.MWMetaNode, ve.dm.MetaNode );
-
-/* Static Properties */
-
-ve.dm.MWMetaNode.static.name = 'MWmeta';
-
-ve.dm.MWMetaNode.static.matchRdfaTypes = [ /^mw:/ ];
-
-// toDataElement inherited from MetaNode, will return regular 
metaBlock/metaInline elements but
-// that's fine. This class is only here so that <meta>/<link> tags with an mw: 
type are correctly
-// mapped to MetaNode and aren't alienated.
-
-/* Registration */
-
-ve.dm.modelRegistry.register( ve.dm.MWMetaNode );
diff --git a/modules/ve/dm/nodes/ve.dm.MetaNode.js 
b/modules/ve/dm/nodes/ve.dm.MetaNode.js
deleted file mode 100644
index b1533a3..0000000
--- a/modules/ve/dm/nodes/ve.dm.MetaNode.js
+++ /dev/null
@@ -1,110 +0,0 @@
-/*!
- * VisualEditor DataModel MetaNode class.
- *
- * @copyright 2011-2013 VisualEditor Team and others; see AUTHORS.txt
- * @license The MIT License (MIT); see LICENSE.txt
- */
-
-/**
- * DataModel meta 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.MetaNode = function VeDmMetaNode( length, element ) {
-       // Parent constructor
-       ve.dm.LeafNode.call( this, 0, element );
-};
-
-/* Inheritance */
-
-ve.inheritClass( ve.dm.MetaNode, ve.dm.LeafNode );
-
-/* Static Properties */
-
-ve.dm.MetaNode.static.name = 'meta';
-
-ve.dm.MetaNode.static.isMeta = true;
-
-ve.dm.MetaNode.static.matchTagNames = [ 'meta', 'link' ];
-
-ve.dm.MetaNode.static.toDataElement = function ( domElements, context ) {
-       var firstDomElement = domElements[0],
-               isLink = firstDomElement.nodeName.toLowerCase() === 'link',
-               keyAttr = isLink ? 'rel' : 'property',
-               valueAttr = isLink ? 'href' : 'content',
-               dataElement = {
-                       'type': context.expectingContent ? 'metaInline' : 
'metaBlock',
-                       'attributes': {
-                               'style': isLink ? 'link' : 'meta',
-                               'key': firstDomElement.getAttribute( keyAttr )
-                       }
-               };
-       if ( firstDomElement.hasAttribute( valueAttr ) ) {
-               dataElement.attributes.value = firstDomElement.getAttribute( 
valueAttr );
-       }
-       return dataElement;
-};
-
-ve.dm.MetaNode.static.toDomElements = function ( dataElement ) {
-       var style = dataElement.attributes && dataElement.attributes.style || 
'meta',
-               isLink = style === 'link',
-               tag = isLink ? 'link' : 'meta',
-               keyAttr = isLink ? 'rel' : 'property',
-               valueAttr = isLink ? 'href' : 'content',
-               domElement;
-       if ( style === 'comment' ) {
-               return [ document.createComment( dataElement.attributes && 
dataElement.attributes.text || '' ) ];
-       }
-       domElement = document.createElement( tag );
-       if ( dataElement.attributes && dataElement.attributes.key !== null ) {
-               domElement.setAttribute( keyAttr, dataElement.attributes.key );
-       }
-       if ( dataElement.attributes && dataElement.attributes.value ) {
-               domElement.setAttribute( valueAttr, 
dataElement.attributes.value );
-       }
-       return [ domElement ];
-};
-
-/* Concrete subclasses */
-
-/**
- * DataModel metaBlock 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.MetaBlockNode = function VeDmMetaBlockNode( length, element ) {
-       // Parent constructor
-       ve.dm.MetaNode.call( this, length, element );
-};
-
-ve.inheritClass( ve.dm.MetaBlockNode, ve.dm.MetaNode );
-
-ve.dm.MetaBlockNode.static.name = 'metaBlock';
-
-
-ve.dm.MetaInlineNode = function VeDmMetaInlineNode( length, element ) {
-       // Parent constructor
-       ve.dm.MetaNode.call( this, length, element );
-};
-
-ve.inheritClass( ve.dm.MetaInlineNode, ve.dm.MetaNode );
-
-ve.dm.MetaInlineNode.static.name = 'metaInline';
-
-ve.dm.MetaInlineNode.static.isContent = true;
-
-/* Registration */
-
-ve.dm.modelRegistry.register( ve.dm.MetaNode );
-ve.dm.modelRegistry.register( ve.dm.MetaBlockNode );
-ve.dm.modelRegistry.register( ve.dm.MetaInlineNode );
diff --git a/modules/ve/dm/ve.dm.Annotation.js 
b/modules/ve/dm/ve.dm.Annotation.js
index 91fb778..f05f158 100644
--- a/modules/ve/dm/ve.dm.Annotation.js
+++ b/modules/ve/dm/ve.dm.Annotation.js
@@ -51,7 +51,8 @@
 /**
  * Symbolic name for the annotation class.
  *
- * Must be set to a unique string by every subclass.
+ * Must be set to a unique string by every subclass. Must not conflict with 
names of other nodes,
+ * annotations, or meta items.
  *
  * @static
  * @property {string} [static.name=null]
diff --git a/modules/ve/dm/ve.dm.Converter.js b/modules/ve/dm/ve.dm.Converter.js
index 75432a2..4a6956e 100644
--- a/modules/ve/dm/ve.dm.Converter.js
+++ b/modules/ve/dm/ve.dm.Converter.js
@@ -16,11 +16,12 @@
  * @param {ve.dm.NodeFactory} nodeFactory
  * @param {ve.dm.AnnotationFactory} annotationFactory
  */
-ve.dm.Converter = function VeDmConverter( modelRegistry, nodeFactory, 
annotationFactory ) {
+ve.dm.Converter = function VeDmConverter( modelRegistry, nodeFactory, 
annotationFactory, metaItemFactory ) {
        // Properties
        this.modelRegistry = modelRegistry;
        this.nodeFactory = nodeFactory;
        this.annotationFactory = annotationFactory;
+       this.metaItemFactory = metaItemFactory;
 };
 
 /* Static Methods */
@@ -63,7 +64,7 @@
  */
 ve.dm.Converter.prototype.getDomElementsFromDataElement = function ( 
dataElement, doc ) {
        var domElements, dataElementAttributes, key, matches,
-               nodeClass = this.nodeFactory.lookup( dataElement.type );
+               nodeClass = this.modelRegistry.lookup( dataElement.type );
        if ( !nodeClass ) {
                throw new Error( 'Attempting to convert unknown data element 
type ' + dataElement.type );
        }
@@ -98,6 +99,13 @@
        return domElements;
 };
 
+/**
+ * Create a data element from a DOM element.
+ * @param {ve.dm.Node|ve.dm.MetaItem} 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)
+ * @returns {Object} Data element
+ */
 ve.dm.Converter.prototype.createDataElement = function ( modelClass, 
domElements, context ) {
        var i, j, dataElement, dataElementAttributes, domElementAttributes, 
domElementAttribute;
        dataElement = modelClass.static.toDataElement( domElements, 
ve.copyObject( context ) );
@@ -277,10 +285,22 @@
                                                )
                                        );
                                } else {
+                                       // Node or meta item
                                        aboutGroup = getAboutGroup( 
childDomElement );
                                        childDomElements = 
modelClass.static.enableAboutGrouping ?
                                                aboutGroup : [ childDomElement 
];
                                        childDataElement = 
this.createDataElement( modelClass, childDomElements, context );
+
+                                       if ( modelClass.prototype instanceof 
ve.dm.MetaItem ) {
+                                               // No additional processing 
needed
+                                               // Write to data and continue
+                                               data.push( childDataElement );
+                                               data.push( { 'type': '/' + 
childDataElement.type } );
+                                               processNextWhitespace( 
childDataElement );
+                                               prevElement = childDataElement;
+                                               break;
+                                       }
+
                                        childIsContent = 
this.nodeFactory.isNodeContent( childDataElement.type );
 
                                        // If childIsContent isn't what we 
expect, adjust
@@ -464,14 +484,14 @@
                        case Node.COMMENT_NODE:
                                // TODO treat this as a node with nodeName 
#comment
                                childDataElement = {
-                                       'type': context.expectingContent ? 
'metaInline' : 'metaBlock',
+                                       'type': 'alienMeta',
                                        'attributes': {
                                                'style': 'comment',
                                                'text': childDomElement.data
                                        }
                                };
                                data.push( childDataElement );
-                               data.push( { 'type': context.expectingContent ? 
'/metaInline' : '/metaBlock' } );
+                               data.push( { 'type': '/alienMeta' } );
                                processNextWhitespace( childDataElement );
                                prevElement = childDataElement;
                                break;
@@ -547,8 +567,10 @@
                } else if (
                        ve.isArray( data[i] ) ||
                        (
-                               data[i].annotations !== undefined &&
-                               this.nodeFactory.isNodeContent( data[i].type )
+                               data[i].annotations !== undefined && (
+                                       this.metaItemFactory.lookup( 
data[i].type ) ||
+                                       this.nodeFactory.isNodeContent( 
data[i].type )
+                               )
                        )
                ) {
                        // Annotated text or annotated nodes
@@ -648,7 +670,8 @@
                        // Element
                        if ( dataElement.type.charAt( 0 ) === '/' ) {
                                parentDomElement = domElement.parentNode;
-                               isContentNode = this.nodeFactory.isNodeContent( 
data[i].type.substr( 1 ) );
+                               isContentNode = this.metaItemFactory.lookup( 
data[i].type.substr( 1 ) ) ||
+                                       this.nodeFactory.isNodeContent( 
data[i].type.substr( 1 ) );
                                // Process whitespace
                                // whitespace = [ outerPre, innerPre, 
innerPost, outerPost ]
                                if (
@@ -884,4 +907,4 @@
 
 /* Initialization */
 
-ve.dm.converter = new ve.dm.Converter( ve.dm.modelRegistry, ve.dm.nodeFactory, 
ve.dm.annotationFactory );
+ve.dm.converter = new ve.dm.Converter( ve.dm.modelRegistry, ve.dm.nodeFactory, 
ve.dm.annotationFactory, ve.dm.metaItemFactory );
diff --git a/modules/ve/dm/ve.dm.Document.js b/modules/ve/dm/ve.dm.Document.js
index e390d58..d3f840e 100644
--- a/modules/ve/dm/ve.dm.Document.js
+++ b/modules/ve/dm/ve.dm.Document.js
@@ -70,7 +70,7 @@
                } else {
                        if (
                                this.data[i].type.charAt( 0 ) !== '/' &&
-                               ve.dm.nodeFactory.isNodeMeta( this.data[i].type 
)
+                               ve.dm.metaItemFactory.lookup( this.data[i].type 
)
                        ) {
                                // Metadata
                                // Splice the meta element and its closing out 
of the linmod
diff --git a/modules/ve/dm/ve.dm.MetaItem.js b/modules/ve/dm/ve.dm.MetaItem.js
new file mode 100644
index 0000000..2d875c0
--- /dev/null
+++ b/modules/ve/dm/ve.dm.MetaItem.js
@@ -0,0 +1,149 @@
+/*!
+ * VisualEditor DataModel MetaItem class.
+ *
+ * @copyright 2011-2013 VisualEditor Team and others; see AUTHORS.txt
+ * @license The MIT License (MIT); see LICENSE.txt
+ */
+
+/**
+ * DataModel meta item.
+ *
+ * @class
+ * @abstract
+ * @extends ve.EventEmitter
+ * @constructor
+ * @param {Object} element Reference to element in meta-linmod
+ */
+ve.dm.MetaItem = function VeDmMetaItem( element ) {
+       // Parent constructor
+       ve.EventEmitter.call( this );
+
+       // Properties
+       this.element = element;
+};
+
+/* Inheritance */
+
+ve.inheritClass( ve.dm.MetaItem, ve.EventEmitter );
+
+/* Static members */
+
+// TODO these static properties should really be in a base class or mixin, 
e.g. "matchable"
+
+/**
+ * Symbolic name for the meta item class. Must be set to a unique string by 
every subclass. Must not
+ * conflict with names of other nodes, annotations, or meta items.
+ * @static
+ * @property {string} [static.name=null]
+ * @inheritable
+ */
+ve.dm.MetaItem.static.name = null;
+
+/**
+ * Array of HTML tag names that this meta item should be a match candidate for.
+ * Empty array means none, null means any.
+ * For more information about element matching, see ve.dm.ModelRegistry.
+ * @static
+ * @property {string[]} static.matchTagNames
+ * @inheritable
+ */
+ve.dm.MetaItem.static.matchTagNames = null;
+
+/**
+ * Array of RDFa types that this meta item should be a match candidate for.
+ * Empty array means none, null means any.
+ * For more information about element matching, see ve.dm.ModelRegistry.
+ * @static
+ * @property {Array} static.matchRdfaType Array of strings or regular 
expressions
+ * @inheritable
+ */
+ve.dm.MetaItem.static.matchRdfaTypes = null;
+
+/**
+ * Optional function to determine whether this meta item should match a given 
element.
+ * Takes an HTMLElement and returns true or false.
+ * This function is only called if this meta item has a chance of "winning"; 
see
+ * ve.dm.ModelRegistry for more information about element matching.
+ * If set to null, this property is ignored. Setting this to null is not the 
same as unconditionally
+ * returning true, because the presence or absence of a matchFunction affects 
the node's
+ * specificity.
+ *
+ * NOTE: This function is NOT a method, within this function "this" will not 
refer to an instance
+ * of this class (or to anything reasonable, for that matter).
+ * @static
+ * @property {Function} static.matchFunction
+ * @inheritable
+ */
+ve.dm.MetaItem.static.matchFunction = null;
+
+/**
+ * Static function to convert a DOM element or set of sibling DOM elements to 
a meta-linmod
+ * element for this item type.
+ *
+ * This function is only called if this item "won" the matching for the first 
DOM element, so
+ * domElements[0] will match this item's matching rule. There is usually only 
one node in
+ * domElements[]. Multiple nodes will only be passed if this item supports 
about groups.
+ * If there are multiple nodes, the nodes are all adjacent siblings in the 
same about group
+ * (i.e. they are grouped together because they have the same value for the 
about attribute).
+ *
+ * Meta-elements can occur anywhere, including places where only content is 
allowed, so meta items
+ * generally won't need to worry about the context variables related to 
content vs. non-content
+ * and wrapping as long as they return meta-elements from toDataElement().
+ *
+ * Note that if this function returns null, the DOM node will be alienated as 
an alien *node*,
+ * not an alien *meta item*.
+ *
+ * @static
+ * @method
+ * @param {HTMLElement[]} domElements DOM elements to convert. Usually only 
one element
+ * @param {Object} context Object describing the current state of the converter
+ * @param {boolean} context.expectingContent Whether this function is expected 
to return a content element
+ * @param {boolean} context.inWrapper Whether this element is in a wrapper 
paragraph generated by the converter;
+ *  can only be true if context.expectingContent is also true
+ * @param {boolean} context.canCloseWrapper Whether the current wrapper 
paragraph can be closed;
+ *  can only be true if context.inWrapper is also true
+ * @returns {Object|null} Meta-linmod element, or null to alienate
+ */
+ve.dm.MetaItem.static.toDataElement = function ( /*domElements, context*/ ) {
+       throw new Error( 've.dm.MetaItem subclass must implement toDataElement' 
);
+};
+
+/**
+ * Static function to convert a meta-linmod element for this item type back to 
one or more
+ * DOM elements.
+ *
+ * @static
+ * @method
+ * @param {Object} Meta-linmod element with a type property and optionally an 
attributes property
+ * @returns {HTMLElement[]} DOM elements
+ */
+ve.dm.MetaItem.static.toDomElements = function ( /*dataElement*/ ) {
+       throw new Error( 've.dm.MetaItem subclass must implement toDomElements' 
);
+};
+
+/**
+ * Whether this item supports about grouping. When a DOM element matches an 
item type that has
+ * about grouping enabled, the converter will look for adjacent siblings with 
the same value for
+ * the about attribute, and ask toDataElement() to produce a single data 
element for all of those
+ * DOM nodes combined.
+ *
+ * @static
+ * @property {boolean} static.enableAboutGrouping
+ * @inheritable
+ */
+ve.dm.MetaItem.static.enableAboutGrouping = false;
+
+/**
+ * Whether HTML attributes should be preserved for this item type. If true, 
the HTML attributes
+ * of the DOM elements will be stored as attributes in the meta-linmod. The 
attribute names will be
+ * html/i/attrName, where i is the index of the DOM element in the domElements 
array, and attrName
+ * is the name of the attribute.
+ *
+ * This should generally be enabled, except for item types that store their 
entire HTML in an
+ * attribute.
+ *
+ * @static
+ * @property {boolean} static.storeHtmlAttributes
+ * @inheritable
+ */
+ve.dm.MetaItem.static.storeHtmlAttributes = true;
\ No newline at end of file
diff --git a/modules/ve/dm/ve.dm.MetaItemFactory.js 
b/modules/ve/dm/ve.dm.MetaItemFactory.js
new file mode 100644
index 0000000..c77ce35
--- /dev/null
+++ b/modules/ve/dm/ve.dm.MetaItemFactory.js
@@ -0,0 +1,44 @@
+/*!
+ * VisualEditor DataModel MetaItemFactory class.
+ *
+ * @copyright 2011-2013 VisualEditor Team and others; see AUTHORS.txt
+ * @license The MIT License (MIT); see LICENSE.txt
+ */
+
+/**
+ * DataModel meta item factory.
+ *
+ * @class
+ * @extends ve.Factory
+ * @constructor
+ */
+ve.dm.MetaItemFactory = function VeDmMetaItemFactory() {
+       // Parent constructor
+       ve.Factory.call( this );
+};
+
+/* Inheritance */
+
+ve.inheritClass( ve.dm.MetaItemFactory, ve.Factory );
+
+/* Methods */
+
+/**
+ * Check if the item stores HTML attributes in the meta-linmod.
+ *
+ * @method
+ * @param {string} type Meta item type
+ * @returns {boolean} Whether the item stores HTML attributes.
+ * @throws {Error} Unknown item type
+ */
+ve.dm.MetaItemFactory.prototype.doesItemStoreHtmlAttributes = function ( type 
) {
+       if ( type in this.registry ) {
+               return this.registry[type].static.storeHtmlAttributes;
+       }
+       throw new Error( 'Unknown item type: ' + type );
+};
+
+
+/* Initialization */
+
+ve.dm.metaItemFactory = new ve.dm.MetaItemFactory();
diff --git a/modules/ve/dm/ve.dm.ModelRegistry.js 
b/modules/ve/dm/ve.dm.ModelRegistry.js
index 922b48b..9ab0e0b 100644
--- a/modules/ve/dm/ve.dm.ModelRegistry.js
+++ b/modules/ve/dm/ve.dm.ModelRegistry.js
@@ -70,7 +70,7 @@
 /**
  * Register a model type.
  * @param {string} name Symbolic name for the model
- * @param {ve.dm.Annotation|ve.dm.Node} constructor Subclass of 
ve.dm.Annotation or ve.dm.Node
+ * @param {ve.dm.Annotation|ve.dm.Node|ve.dm.MetaItem} constructor Subclass of 
ve.dm.Annotation, ve.dm.Node or ve.dm.MetaItem
  */
 ve.dm.ModelRegistry.prototype.register = function ( constructor ) {
        var i, j, tags, types, name = constructor.static && 
constructor.static.name;
@@ -83,8 +83,10 @@
                ve.dm.annotationFactory.register( name, constructor );
        } else if ( constructor.prototype instanceof ve.dm.Node ) {
                ve.dm.nodeFactory.register( constructor );
+       } else if ( constructor.prototype instanceof ve.dm.MetaItem ) {
+               ve.dm.metaItemFactory.register( name, constructor );
        } else {
-               throw new Error( 'Models must be subclasses of ve.dm.Annotation 
or ve.dm.Node' );
+               throw new Error( 'Models must be subclasses of 
ve.dm.Annotation, ve.dm.Node or ve.dm.MetaItem' );
        }
        // Call parent implementation
        ve.Registry.prototype.register.call( this, name, constructor );
diff --git a/modules/ve/dm/ve.dm.Node.js b/modules/ve/dm/ve.dm.Node.js
index acf357c..c392e00 100644
--- a/modules/ve/dm/ve.dm.Node.js
+++ b/modules/ve/dm/ve.dm.Node.js
@@ -136,17 +136,6 @@
 };
 
 /**
- * Whether this node type represents metadata.
- *
- * Linear model elements with this type will be moved out of the linear model 
into the metadata.
- *
- * @static
- * @property {boolean} static.isMeta
- * @inheritable
- */
-ve.dm.Node.static.isMeta = false;
-
-/**
  * Whether this node supports about grouping. When a DOM element matches a 
node type that has
  * about grouping enabled, the converter will look for adjacent siblings with 
the same value for
  * the about attribute, and ask toDataElement() to produce a single data 
element for all of those
@@ -164,7 +153,7 @@
 
 /**
  * Whether HTML attributes should be preserved for this node type. If true, 
the HTML attributes
- * of the DOM elements will be stored as linear model attributes. The 
attribute names be
+ * of the DOM elements will be stored as linear model attributes. The 
attribute names will be
  * html/i/attrName, where i is the index of the DOM element in the domElements 
array, and attrName
  * is the name of the attribute.
  *
diff --git a/modules/ve/dm/ve.dm.NodeFactory.js 
b/modules/ve/dm/ve.dm.NodeFactory.js
index b116d31..74277bd 100644
--- a/modules/ve/dm/ve.dm.NodeFactory.js
+++ b/modules/ve/dm/ve.dm.NodeFactory.js
@@ -125,21 +125,6 @@
 };
 
 /**
- * Check if a node represents metadata.
- *
- * @method
- * @param {string} type Node type
- * @returns {boolean} The node is meta
- * @throws {Error} Unknown node type
- */
-ve.dm.NodeFactory.prototype.isNodeMeta = function ( type ) {
-       if ( type in this.registry ) {
-               return this.registry[type].static.isMeta;
-       }
-       throw new Error( 'Unknown node type: ' + type );
-};
-
-/**
  * Check if a node has a wrapped element in the document data.
  *
  * @method
diff --git a/modules/ve/test/dm/ve.dm.Transaction.test.js 
b/modules/ve/test/dm/ve.dm.Transaction.test.js
index 506488f..16021ac 100644
--- a/modules/ve/test/dm/ve.dm.Transaction.test.js
+++ b/modules/ve/test/dm/ve.dm.Transaction.test.js
@@ -1164,7 +1164,7 @@
 QUnit.test( 'newFromMetadataInsertion', 2, function( assert ) {
        var doc = new ve.dm.Document( ve.copyArray( ve.dm.example.withMeta ) ),
                element = {
-                       'type': 'metaInline',
+                       'type': 'alienMeta',
                        'attributes': {
                                'style': 'comment',
                                'text': ' inline '
@@ -1247,7 +1247,7 @@
 QUnit.test( 'newFromMetadataElementReplacement', 3, function( assert ) {
        var doc = new ve.dm.Document( ve.copyArray( ve.dm.example.withMeta ) ),
                newElement = {
-                       'type': 'metaInline',
+                       'type': 'alienMeta',
                        'attributes': {
                                'style': 'comment',
                                'text': ' inline '
diff --git a/modules/ve/test/dm/ve.dm.TransactionProcessor.test.js 
b/modules/ve/test/dm/ve.dm.TransactionProcessor.test.js
index 2d7fc5c..33c4d25 100644
--- a/modules/ve/test/dm/ve.dm.TransactionProcessor.test.js
+++ b/modules/ve/test/dm/ve.dm.TransactionProcessor.test.js
@@ -47,13 +47,13 @@
                italic = ve.dm.example.createAnnotation( ve.dm.example.italic ),
                underline = ve.dm.example.createAnnotation( 
ve.dm.example.underline ),
                metaElementInsert = {
-                               'type': 'metaInline',
+                               'type': 'alienMeta',
                                'attributes': {
                                        'style': 'comment',
                                        'text': ' inline '
                                }
                        },
-               metaElementInsertClose = { 'type': '/metaInline' },
+               metaElementInsertClose = { 'type': '/alienMeta' },
                cases = {
                        'no operations': {
                                'calls': [],
diff --git a/modules/ve/test/dm/ve.dm.example.js 
b/modules/ve/test/dm/ve.dm.example.js
index d4bebcb..146e807 100644
--- a/modules/ve/test/dm/ve.dm.example.js
+++ b/modules/ve/test/dm/ve.dm.example.js
@@ -291,28 +291,28 @@
 
 ve.dm.example.withMeta = [
        {
-               'type': 'metaBlock',
+               'type': 'alienMeta',
                'attributes': {
                        'style': 'comment',
                        'text': ' No content conversion '
                }
        },
-       { 'type': '/metaBlock' },
+       { 'type': '/alienMeta' },
        {
-               'type': 'metaBlock',
+               'type': 'alienMeta',
                'attributes': {
                        'style': 'meta',
                        'key': 'mw:PageProp/nocc',
                        'html/0/property': 'mw:PageProp/nocc'
                }
        },
-       { 'type': '/metaBlock' },
+       { 'type': '/alienMeta' },
        { 'type': 'paragraph' },
        'F',
        'o',
        'o',
        {
-               'type': 'metaInline',
+               'type': 'alienMeta',
                'attributes': {
                        'style': 'link',
                        'key': 'mw:WikiLink/Category',
@@ -321,12 +321,12 @@
                        'html/0/rel': 'mw:WikiLink/Category'
                }
        },
-       { 'type': '/metaInline' },
+       { 'type': '/alienMeta' },
        'B',
        'a',
        'r',
        {
-               'type': 'metaInline',
+               'type': 'alienMeta',
                'attributes': {
                        'style': 'meta',
                        'key': 'mw:foo',
@@ -335,21 +335,21 @@
                        'html/0/property': 'mw:foo'
                }
        },
-       { 'type': '/metaInline' },
+       { 'type': '/alienMeta' },
        'B',
        'a',
        {
-               'type': 'metaInline',
+               'type': 'alienMeta',
                'attributes': {
                        'style': 'comment',
                        'text': ' inline '
                }
        },
-       { 'type': '/metaInline' },
+       { 'type': '/alienMeta' },
        'z',
        { 'type': '/paragraph' },
        {
-               'type': 'metaBlock',
+               'type': 'alienMeta',
                'attributes': {
                        'style': 'meta',
                        'key': 'mw:bar',
@@ -358,17 +358,17 @@
                        'html/0/property': 'mw:bar'
                }
        },
-       { 'type': '/metaBlock' },
+       { 'type': '/alienMeta' },
        {
-               'type': 'metaBlock',
+               'type': 'alienMeta',
                'attributes': {
                        'style': 'comment',
                        'text': 'barbaz'
                }
        },
-       { 'type': '/metaBlock' },
+       { 'type': '/alienMeta' },
        {
-               'type': 'metaBlock',
+               'type': 'alienMeta',
                'attributes': {
                        'style': 'link',
                        'key': 'mw:WikiLink/Category',
@@ -377,9 +377,9 @@
                        'html/0/rel': 'mw:WikiLink/Category'
                }
        },
-       { 'type': '/metaBlock' },
+       { 'type': '/alienMeta' },
        {
-               'type': 'metaBlock',
+               'type': 'alienMeta',
                'attributes': {
                        'style': 'meta',
                        'key': null,
@@ -387,7 +387,7 @@
                        'html/0/data-parsoid': 'foobar'
                }
        },
-       { 'type': '/metaBlock' }
+       { 'type': '/alienMeta' }
 ];
 
 ve.dm.example.withMetaPlainData = [
@@ -407,14 +407,14 @@
 ve.dm.example.withMetaMetaData = [
        [
                {
-                       'type': 'metaBlock',
+                       'type': 'alienMeta',
                        'attributes': {
                                'style': 'comment',
                                'text': ' No content conversion '
                        }
                },
                {
-                       'type': 'metaBlock',
+                       'type': 'alienMeta',
                        'attributes': {
                                'style': 'meta',
                                'key': 'mw:PageProp/nocc',
@@ -427,7 +427,7 @@
        undefined,
        [
                {
-                       'type': 'metaInline',
+                       'type': 'alienMeta',
                        'attributes': {
                                'style': 'link',
                                'key': 'mw:WikiLink/Category',
@@ -441,7 +441,7 @@
        undefined,
        [
                {
-                       'type': 'metaInline',
+                       'type': 'alienMeta',
                        'attributes': {
                                'style': 'meta',
                                'key': 'mw:foo',
@@ -454,7 +454,7 @@
        undefined,
        [
                {
-                       'type': 'metaInline',
+                       'type': 'alienMeta',
                        'attributes': {
                                'style': 'comment',
                                'text': ' inline '
@@ -464,7 +464,7 @@
        undefined,
        [
                {
-                       'type': 'metaBlock',
+                       'type': 'alienMeta',
                        'attributes': {
                                'style': 'meta',
                                'key': 'mw:bar',
@@ -474,14 +474,14 @@
                        }
                },
                {
-                       'type': 'metaBlock',
+                       'type': 'alienMeta',
                        'attributes': {
                                'style': 'comment',
                                'text': 'barbaz'
                        }
                },
                {
-                       'type': 'metaBlock',
+                       'type': 'alienMeta',
                        'attributes': {
                                'style': 'link',
                                'key': 'mw:WikiLink/Category',
@@ -491,7 +491,7 @@
                        }
                },
                {
-                       'type': 'metaBlock',
+                       'type': 'alienMeta',
                        'attributes': {
                                'style': 'meta',
                                'key': null,
@@ -1985,7 +1985,7 @@
                        'o',
                        'o',
                        {
-                               'type': 'metaInline',
+                               'type': 'alienMeta',
                                'attributes': {
                                        'style': 'meta',
                                        'key': 'mw:foo',
@@ -1994,7 +1994,7 @@
                                        'html/0/property': 'mw:foo'
                                }
                        },
-                       { 'type': '/metaInline' },
+                       { 'type': '/alienMeta' },
                        { 'type': '/paragraph' },
                        { 'type': '/tableCell' },
                        { 'type': '/tableRow' },
diff --git a/modules/ve/test/index.php b/modules/ve/test/index.php
index 73c0f2a..87698b2 100644
--- a/modules/ve/test/index.php
+++ b/modules/ve/test/index.php
@@ -59,10 +59,12 @@
                <script src="../../ve/dm/ve.dm.ModelRegistry.js"></script>
                <script src="../../ve/dm/ve.dm.NodeFactory.js"></script>
                <script src="../../ve/dm/ve.dm.AnnotationFactory.js"></script>
+               <script src="../../ve/dm/ve.dm.MetaItemFactory.js"></script>
                <script src="../../ve/dm/ve.dm.Node.js"></script>
                <script src="../../ve/dm/ve.dm.BranchNode.js"></script>
                <script src="../../ve/dm/ve.dm.LeafNode.js"></script>
                <script src="../../ve/dm/ve.dm.Annotation.js"></script>
+               <script src="../../ve/dm/ve.dm.MetaItem.js"></script>
                <script 
src="../../ve/dm/ve.dm.TransactionProcessor.js"></script>
                <script src="../../ve/dm/ve.dm.Transaction.js"></script>
                <script src="../../ve/dm/ve.dm.Surface.js"></script>
@@ -81,7 +83,6 @@
                <script src="../../ve/dm/nodes/ve.dm.ImageNode.js"></script>
                <script src="../../ve/dm/nodes/ve.dm.ListItemNode.js"></script>
                <script src="../../ve/dm/nodes/ve.dm.ListNode.js"></script>
-               <script src="../../ve/dm/nodes/ve.dm.MetaNode.js"></script>
                <script src="../../ve/dm/nodes/ve.dm.ParagraphNode.js"></script>
                <script 
src="../../ve/dm/nodes/ve.dm.PreformattedNode.js"></script>
                <script src="../../ve/dm/nodes/ve.dm.TableCellNode.js"></script>
@@ -91,12 +92,13 @@
                <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.MWMetaNode.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>
                <script 
src="../../ve/dm/annotations/ve.dm.TextStyleAnnotation.js"></script>
+               <script 
src="../../ve/dm/metaitems/ve.dm.AlienMetaItem.js"></script>
+               <script 
src="../../ve/dm/metaitems/ve.dm.MWMetaItem.js"></script>
                <script src="../../ve/ce/ve.ce.js"></script>
                <script src="../../ve/ce/ve.ce.DomRange.js"></script>
                <script src="../../ve/ce/ve.ce.NodeFactory.js"></script>
diff --git a/modules/ve/ve.Node.js b/modules/ve/ve.Node.js
index 526ab13..9385ce0 100644
--- a/modules/ve/ve.Node.js
+++ b/modules/ve/ve.Node.js
@@ -39,7 +39,7 @@
 
 /**
  * Symbolic name for the node class. Must be set to a unique string by every 
subclass. Must not
- * conflict with other node names or other annotation names.
+ * conflict with names of other nodes, annotations or meta items.
  * @static
  * @property {string} [static.name=null]
  * @inheritable

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

Gerrit-MessageType: merged
Gerrit-Change-Id: I893709c6f3aa00f85c1b905b70f9f4e597bdeada
Gerrit-PatchSet: 7
Gerrit-Project: mediawiki/extensions/VisualEditor
Gerrit-Branch: master
Gerrit-Owner: Catrope <[email protected]>
Gerrit-Reviewer: Catrope <[email protected]>
Gerrit-Reviewer: Esanders <[email protected]>
Gerrit-Reviewer: Trevor Parscal <[email protected]>
Gerrit-Reviewer: jenkins-bot

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

Reply via email to