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