mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/VisualEditor
synced 2024-09-25 03:08:42 +00:00
Merge "(bug 45062) Implement the new node API in the converter"
This commit is contained in:
commit
fb11cc8a8c
|
@ -35,20 +35,29 @@ ve.dm.AlienNode.static.enableAboutGrouping = true;
|
||||||
|
|
||||||
ve.dm.AlienNode.static.storeHtmlAttributes = false;
|
ve.dm.AlienNode.static.storeHtmlAttributes = false;
|
||||||
|
|
||||||
ve.dm.AlienNode.static.toDataElement = function ( domElement, context ) {
|
ve.dm.AlienNode.static.toDataElement = function ( domElements, context ) {
|
||||||
|
var i, isInline, allTagsInline, type, html;
|
||||||
|
// Check whether all elements are inline elements
|
||||||
|
allTagsInline = true;
|
||||||
|
for ( i = 0; i < domElements.length; i++ ) {
|
||||||
|
if ( ve.isBlockElement( domElements[i] ) ) {
|
||||||
|
allTagsInline = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// We generate alienBlock elements for block tags and alienInline elements for
|
// We generate alienBlock elements for block tags and alienInline elements for
|
||||||
// inline tags; unless we're in a content location, in which case we have no choice
|
// inline tags; unless we're in a content location, in which case we have no choice
|
||||||
// but to generate an alienInline element.
|
// but to generate an alienInline element.
|
||||||
var isInline =
|
isInline =
|
||||||
// Force inline in content locations (but not wrappers)
|
// Force inline in content locations (but not wrappers)
|
||||||
( context.expectingContent && !context.inWrapper ) ||
|
( context.expectingContent && !context.inWrapper ) ||
|
||||||
// Also force inline in wrappers that we can't close
|
// Also force inline in wrappers that we can't close
|
||||||
( context.inWrapper && !context.canCloseWrapper ) ||
|
( context.inWrapper && !context.canCloseWrapper ) ||
|
||||||
// Look at the tag name otherwise
|
// Look at the tag names otherwise
|
||||||
!ve.isBlockElement( domElement ),
|
allTagsInline;
|
||||||
type = isInline ? 'alienInline' : 'alienBlock',
|
type = isInline ? 'alienInline' : 'alienBlock';
|
||||||
// TODO handle about groups somehow
|
html = $( '<div>', domElements[0].ownerDocument ).append( $( domElements ).clone() ).html();
|
||||||
html = $( '<div>' ).append( $( domElement ).clone() ).html();
|
|
||||||
return {
|
return {
|
||||||
'type': type,
|
'type': type,
|
||||||
'attributes': {
|
'attributes': {
|
||||||
|
@ -57,11 +66,11 @@ ve.dm.AlienNode.static.toDataElement = function ( domElement, context ) {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
ve.dm.AlienNode.static.toDomElement = function ( dataElement ) {
|
ve.dm.AlienNode.static.toDomElements = function ( dataElement ) {
|
||||||
var wrapper = document.createElement( 'div' );
|
var wrapper = document.createElement( 'div' );
|
||||||
wrapper.innerHTML = dataElement.attributes.html;
|
wrapper.innerHTML = dataElement.attributes.html;
|
||||||
// TODO handle multiple nodes (from about groups) somehow
|
// Convert wrapper.children to an array
|
||||||
return wrapper.firstChild;
|
return Array.prototype.slice.call( wrapper.childNodes, 0 );
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Concrete subclasses */
|
/* Concrete subclasses */
|
||||||
|
|
|
@ -35,8 +35,8 @@ ve.dm.BreakNode.static.toDataElement = function () {
|
||||||
return { 'type': 'break' };
|
return { 'type': 'break' };
|
||||||
};
|
};
|
||||||
|
|
||||||
ve.dm.BreakNode.static.toDomElement = function () {
|
ve.dm.BreakNode.static.toDomElements = function () {
|
||||||
return document.createElement( 'br' );
|
return [ document.createElement( 'br' ) ];
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Registration */
|
/* Registration */
|
||||||
|
|
|
@ -33,8 +33,8 @@ ve.dm.CenterNode.static.toDataElement = function () {
|
||||||
return { 'type': 'center' };
|
return { 'type': 'center' };
|
||||||
};
|
};
|
||||||
|
|
||||||
ve.dm.CenterNode.static.toDomElement = function () {
|
ve.dm.CenterNode.static.toDomElements = function () {
|
||||||
return document.createElement( 'center' );
|
return [ document.createElement( 'center' ) ];
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Registration */
|
/* Registration */
|
||||||
|
|
|
@ -35,14 +35,14 @@ ve.dm.DefinitionListItemNode.static.defaultAttributes = {
|
||||||
|
|
||||||
ve.dm.DefinitionListItemNode.static.matchTagNames = [ 'dt', 'dd' ];
|
ve.dm.DefinitionListItemNode.static.matchTagNames = [ 'dt', 'dd' ];
|
||||||
|
|
||||||
ve.dm.DefinitionListItemNode.static.toDataElement = function ( domElement ) {
|
ve.dm.DefinitionListItemNode.static.toDataElement = function ( domElements ) {
|
||||||
var style = domElement.nodeName.toLowerCase() === 'dt' ? 'term' : 'definition';
|
var style = domElements[0].nodeName.toLowerCase() === 'dt' ? 'term' : 'definition';
|
||||||
return { 'type': 'definitionListItem', 'attributes': { 'style': style } };
|
return { 'type': 'definitionListItem', 'attributes': { 'style': style } };
|
||||||
};
|
};
|
||||||
|
|
||||||
ve.dm.DefinitionListItemNode.static.toDomElement = function ( dataElement ) {
|
ve.dm.DefinitionListItemNode.static.toDomElements = function ( dataElement ) {
|
||||||
var tag = dataElement.attributes && dataElement.attributes.style === 'term' ? 'dt' : 'dd';
|
var tag = dataElement.attributes && dataElement.attributes.style === 'term' ? 'dt' : 'dd';
|
||||||
return document.createElement( tag );
|
return [ document.createElement( tag ) ];
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Registration */
|
/* Registration */
|
||||||
|
|
|
@ -35,8 +35,8 @@ ve.dm.DefinitionListNode.static.toDataElement = function () {
|
||||||
return { 'type': 'definitionList' };
|
return { 'type': 'definitionList' };
|
||||||
};
|
};
|
||||||
|
|
||||||
ve.dm.DefinitionListNode.static.toDomElement = function () {
|
ve.dm.DefinitionListNode.static.toDomElements = function () {
|
||||||
return document.createElement( 'dl' );
|
return [ document.createElement( 'dl' ) ];
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Registration */
|
/* Registration */
|
||||||
|
|
|
@ -35,7 +35,7 @@ ve.dm.HeadingNode.static.defaultAttributes = {
|
||||||
|
|
||||||
ve.dm.HeadingNode.static.matchTagNames = [ 'h1', 'h2', 'h3', 'h4', 'h5', 'h6' ];
|
ve.dm.HeadingNode.static.matchTagNames = [ 'h1', 'h2', 'h3', 'h4', 'h5', 'h6' ];
|
||||||
|
|
||||||
ve.dm.HeadingNode.static.toDataElement = function ( domElement ) {
|
ve.dm.HeadingNode.static.toDataElement = function ( domElements ) {
|
||||||
var levels = {
|
var levels = {
|
||||||
'h1': 1,
|
'h1': 1,
|
||||||
'h2': 2,
|
'h2': 2,
|
||||||
|
@ -44,13 +44,13 @@ ve.dm.HeadingNode.static.toDataElement = function ( domElement ) {
|
||||||
'h5': 5,
|
'h5': 5,
|
||||||
'h6': 6
|
'h6': 6
|
||||||
},
|
},
|
||||||
level = levels[domElement.nodeName.toLowerCase()];
|
level = levels[domElements[0].nodeName.toLowerCase()];
|
||||||
return { 'type': 'heading', 'attributes': { 'level': level } };
|
return { 'type': 'heading', 'attributes': { 'level': level } };
|
||||||
};
|
};
|
||||||
|
|
||||||
ve.dm.HeadingNode.static.toDomElement = function ( dataElement ) {
|
ve.dm.HeadingNode.static.toDomElements = function ( dataElement ) {
|
||||||
var level = dataElement.attributes && dataElement.attributes.level || 1;
|
var level = dataElement.attributes && dataElement.attributes.level || 1;
|
||||||
return document.createElement( 'h' + level );
|
return [ document.createElement( 'h' + level ) ];
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Registration */
|
/* Registration */
|
||||||
|
|
|
@ -35,8 +35,8 @@ ve.dm.ImageNode.static.toDataElement = function () {
|
||||||
return { 'type': 'image' };
|
return { 'type': 'image' };
|
||||||
};
|
};
|
||||||
|
|
||||||
ve.dm.ImageNode.static.toDomElement = function () {
|
ve.dm.ImageNode.static.toDomElements = function () {
|
||||||
return document.createElement( 'img' );
|
return [ document.createElement( 'img' ) ];
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Registration */
|
/* Registration */
|
||||||
|
|
|
@ -35,8 +35,8 @@ ve.dm.ListItemNode.static.toDataElement = function () {
|
||||||
return { 'type': 'listItem' };
|
return { 'type': 'listItem' };
|
||||||
};
|
};
|
||||||
|
|
||||||
ve.dm.ListItemNode.static.toDomElement = function () {
|
ve.dm.ListItemNode.static.toDomElements = function () {
|
||||||
return document.createElement( 'li' );
|
return [ document.createElement( 'li' ) ];
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Registration */
|
/* Registration */
|
||||||
|
|
|
@ -35,14 +35,14 @@ ve.dm.ListNode.static.defaultAttributes = {
|
||||||
|
|
||||||
ve.dm.ListNode.static.matchTagNames = [ 'ul', 'ol' ];
|
ve.dm.ListNode.static.matchTagNames = [ 'ul', 'ol' ];
|
||||||
|
|
||||||
ve.dm.ListNode.static.toDataElement = function ( domElement ) {
|
ve.dm.ListNode.static.toDataElement = function ( domElements ) {
|
||||||
var style = domElement.nodeName.toLowerCase() === 'ol' ? 'number' : 'bullet';
|
var style = domElements[0].nodeName.toLowerCase() === 'ol' ? 'number' : 'bullet';
|
||||||
return { 'type': 'list', 'attributes': { 'style': style } };
|
return { 'type': 'list', 'attributes': { 'style': style } };
|
||||||
};
|
};
|
||||||
|
|
||||||
ve.dm.ListNode.static.toDomElement = function ( dataElement ) {
|
ve.dm.ListNode.static.toDomElements = function ( dataElement ) {
|
||||||
var tag = dataElement.attributes && dataElement.attributes.style === 'number' ? 'ol' : 'ul';
|
var tag = dataElement.attributes && dataElement.attributes.style === 'number' ? 'ol' : 'ul';
|
||||||
return document.createElement( tag );
|
return [ document.createElement( tag ) ];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -31,18 +31,18 @@ ve.dm.MWEntityNode.static.isContent = true;
|
||||||
|
|
||||||
ve.dm.MWEntityNode.static.matchTagNames = [ 'span' ];
|
ve.dm.MWEntityNode.static.matchTagNames = [ 'span' ];
|
||||||
|
|
||||||
ve.dm.MWEntityNode.static.matchRdfaTypes = [ 'mw:Entity' ]; // TODO ignored, still using a converter hack
|
ve.dm.MWEntityNode.static.matchRdfaTypes = [ 'mw:Entity' ];
|
||||||
|
|
||||||
ve.dm.MWEntityNode.static.toDataElement = function ( domElement ) {
|
ve.dm.MWEntityNode.static.toDataElement = function ( domElements ) {
|
||||||
return { 'type': 'MWentity', 'attributes': { 'character': domElement.textContent } };
|
return { 'type': 'MWentity', 'attributes': { 'character': domElements[0].textContent } };
|
||||||
};
|
};
|
||||||
|
|
||||||
ve.dm.MWEntityNode.static.toDomElement = function ( dataElement ) {
|
ve.dm.MWEntityNode.static.toDomElements = function ( dataElement ) {
|
||||||
var domElement = document.createElement( 'span' ),
|
var domElement = document.createElement( 'span' ),
|
||||||
textNode = document.createTextNode( dataElement.attributes.character );
|
textNode = document.createTextNode( dataElement.attributes.character );
|
||||||
domElement.setAttribute( 'typeof', 'mw:Entity' );
|
domElement.setAttribute( 'typeof', 'mw:Entity' );
|
||||||
domElement.appendChild( textNode );
|
domElement.appendChild( textNode );
|
||||||
return domElement;
|
return [ domElement ];
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Registration */
|
/* Registration */
|
||||||
|
|
|
@ -33,24 +33,25 @@ ve.dm.MetaNode.static.isMeta = true;
|
||||||
|
|
||||||
ve.dm.MetaNode.static.matchTagNames = [ 'meta', 'link' ];
|
ve.dm.MetaNode.static.matchTagNames = [ 'meta', 'link' ];
|
||||||
|
|
||||||
ve.dm.MetaNode.static.toDataElement = function ( domElement, context ) {
|
ve.dm.MetaNode.static.toDataElement = function ( domElements, context ) {
|
||||||
var isLink = domElement.nodeName.toLowerCase() === 'link',
|
var firstDomElement = domElements[0],
|
||||||
|
isLink = firstDomElement.nodeName.toLowerCase() === 'link',
|
||||||
keyAttr = isLink ? 'rel' : 'property',
|
keyAttr = isLink ? 'rel' : 'property',
|
||||||
valueAttr = isLink ? 'href' : 'content',
|
valueAttr = isLink ? 'href' : 'content',
|
||||||
dataElement = {
|
dataElement = {
|
||||||
'type': context.expectingContent ? 'metaInline' : 'metaBlock',
|
'type': context.expectingContent ? 'metaInline' : 'metaBlock',
|
||||||
'attributes': {
|
'attributes': {
|
||||||
'style': isLink ? 'link' : 'meta',
|
'style': isLink ? 'link' : 'meta',
|
||||||
'key': domElement.getAttribute( keyAttr )
|
'key': firstDomElement.getAttribute( keyAttr )
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if ( domElement.hasAttribute( valueAttr ) ) {
|
if ( firstDomElement.hasAttribute( valueAttr ) ) {
|
||||||
dataElement.attributes.value = domElement.getAttribute( valueAttr );
|
dataElement.attributes.value = firstDomElement.getAttribute( valueAttr );
|
||||||
}
|
}
|
||||||
return dataElement;
|
return dataElement;
|
||||||
};
|
};
|
||||||
|
|
||||||
ve.dm.MetaNode.static.toDomElement = function ( dataElement ) {
|
ve.dm.MetaNode.static.toDomElements = function ( dataElement ) {
|
||||||
var style = dataElement.attributes && dataElement.attributes.style || 'meta',
|
var style = dataElement.attributes && dataElement.attributes.style || 'meta',
|
||||||
isLink = style === 'link',
|
isLink = style === 'link',
|
||||||
tag = isLink ? 'link' : 'meta',
|
tag = isLink ? 'link' : 'meta',
|
||||||
|
@ -58,7 +59,7 @@ ve.dm.MetaNode.static.toDomElement = function ( dataElement ) {
|
||||||
valueAttr = isLink ? 'href' : 'content',
|
valueAttr = isLink ? 'href' : 'content',
|
||||||
domElement;
|
domElement;
|
||||||
if ( style === 'comment' ) {
|
if ( style === 'comment' ) {
|
||||||
return document.createComment( dataElement.attributes && dataElement.attributes.text || '' );
|
return [ document.createComment( dataElement.attributes && dataElement.attributes.text || '' ) ];
|
||||||
}
|
}
|
||||||
domElement = document.createElement( tag );
|
domElement = document.createElement( tag );
|
||||||
if ( dataElement.attributes && dataElement.attributes.key !== null ) {
|
if ( dataElement.attributes && dataElement.attributes.key !== null ) {
|
||||||
|
@ -67,7 +68,7 @@ ve.dm.MetaNode.static.toDomElement = function ( dataElement ) {
|
||||||
if ( dataElement.attributes && dataElement.attributes.value ) {
|
if ( dataElement.attributes && dataElement.attributes.value ) {
|
||||||
domElement.setAttribute( valueAttr, dataElement.attributes.value );
|
domElement.setAttribute( valueAttr, dataElement.attributes.value );
|
||||||
}
|
}
|
||||||
return domElement;
|
return [ domElement ];
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Concrete subclasses */
|
/* Concrete subclasses */
|
||||||
|
|
|
@ -35,8 +35,8 @@ ve.dm.ParagraphNode.static.toDataElement = function () {
|
||||||
return { 'type': 'paragraph' };
|
return { 'type': 'paragraph' };
|
||||||
};
|
};
|
||||||
|
|
||||||
ve.dm.ParagraphNode.static.toDomElement = function () {
|
ve.dm.ParagraphNode.static.toDomElements = function () {
|
||||||
return document.createElement( 'p' );
|
return [ document.createElement( 'p' ) ];
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Registration */
|
/* Registration */
|
||||||
|
|
|
@ -37,8 +37,8 @@ ve.dm.PreformattedNode.static.toDataElement = function () {
|
||||||
return { 'type': 'preformatted' };
|
return { 'type': 'preformatted' };
|
||||||
};
|
};
|
||||||
|
|
||||||
ve.dm.PreformattedNode.static.toDomElement = function () {
|
ve.dm.PreformattedNode.static.toDomElements = function () {
|
||||||
return document.createElement( 'pre' );
|
return [ document.createElement( 'pre' ) ];
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Registration */
|
/* Registration */
|
||||||
|
|
|
@ -35,14 +35,14 @@ ve.dm.TableCellNode.static.defaultAttributes = {
|
||||||
|
|
||||||
ve.dm.TableCellNode.static.matchTagNames = [ 'td', 'th' ];
|
ve.dm.TableCellNode.static.matchTagNames = [ 'td', 'th' ];
|
||||||
|
|
||||||
ve.dm.TableCellNode.static.toDataElement = function ( domElement ) {
|
ve.dm.TableCellNode.static.toDataElement = function ( domElements ) {
|
||||||
var style = domElement.nodeName.toLowerCase() === 'th' ? 'header' : 'data';
|
var style = domElements[0].nodeName.toLowerCase() === 'th' ? 'header' : 'data';
|
||||||
return { 'type': 'tableCell', 'attributes': { 'style': style } };
|
return { 'type': 'tableCell', 'attributes': { 'style': style } };
|
||||||
};
|
};
|
||||||
|
|
||||||
ve.dm.TableCellNode.static.toDomElement = function ( dataElement ) {
|
ve.dm.TableCellNode.static.toDomElements = function ( dataElement ) {
|
||||||
var tag = dataElement.attributes && dataElement.attributes.style === 'header' ? 'th' : 'td';
|
var tag = dataElement.attributes && dataElement.attributes.style === 'header' ? 'th' : 'td';
|
||||||
return document.createElement( tag );
|
return [ document.createElement( tag ) ];
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Registration */
|
/* Registration */
|
||||||
|
|
|
@ -35,8 +35,8 @@ ve.dm.TableNode.static.toDataElement = function () {
|
||||||
return { 'type': 'table' };
|
return { 'type': 'table' };
|
||||||
};
|
};
|
||||||
|
|
||||||
ve.dm.TableNode.static.toDomElement = function () {
|
ve.dm.TableNode.static.toDomElements = function () {
|
||||||
return document.createElement( 'table' );
|
return [ document.createElement( 'table' ) ];
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Registration */
|
/* Registration */
|
||||||
|
|
|
@ -37,8 +37,8 @@ ve.dm.TableRowNode.static.toDataElement = function () {
|
||||||
return { 'type': 'tableRow' };
|
return { 'type': 'tableRow' };
|
||||||
};
|
};
|
||||||
|
|
||||||
ve.dm.TableRowNode.static.toDomElement = function () {
|
ve.dm.TableRowNode.static.toDomElements = function () {
|
||||||
return document.createElement( 'tr' );
|
return [ document.createElement( 'tr' ) ];
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Registration */
|
/* Registration */
|
||||||
|
|
|
@ -37,24 +37,24 @@ ve.dm.TableSectionNode.static.defaultAttributes = {
|
||||||
|
|
||||||
ve.dm.TableSectionNode.static.matchTagNames = [ 'thead', 'tbody', 'tfoot' ];
|
ve.dm.TableSectionNode.static.matchTagNames = [ 'thead', 'tbody', 'tfoot' ];
|
||||||
|
|
||||||
ve.dm.TableSectionNode.static.toDataElement = function ( domElement ) {
|
ve.dm.TableSectionNode.static.toDataElement = function ( domElements ) {
|
||||||
var styles = {
|
var styles = {
|
||||||
'thead': 'header',
|
'thead': 'header',
|
||||||
'tbody': 'body',
|
'tbody': 'body',
|
||||||
'tfoot': 'footer'
|
'tfoot': 'footer'
|
||||||
},
|
},
|
||||||
style = styles[domElement.nodeName.toLowerCase()] || 'body';
|
style = styles[domElements[0].nodeName.toLowerCase()] || 'body';
|
||||||
return { 'type': 'tableSection', 'attributes': { 'style': style } };
|
return { 'type': 'tableSection', 'attributes': { 'style': style } };
|
||||||
};
|
};
|
||||||
|
|
||||||
ve.dm.TableSectionNode.static.toDomElement = function ( dataElement ) {
|
ve.dm.TableSectionNode.static.toDomElements = function ( dataElement ) {
|
||||||
var tags = {
|
var tags = {
|
||||||
'header': 'thead',
|
'header': 'thead',
|
||||||
'body': 'tbody',
|
'body': 'tbody',
|
||||||
'footer': 'tfoot'
|
'footer': 'tfoot'
|
||||||
},
|
},
|
||||||
tag = tags[dataElement.attributes && dataElement.attributes.style || 'body'];
|
tag = tags[dataElement.attributes && dataElement.attributes.style || 'body'];
|
||||||
return document.createElement( tag );
|
return [ document.createElement( tag ) ];
|
||||||
};
|
};
|
||||||
/* Registration */
|
/* Registration */
|
||||||
|
|
||||||
|
|
|
@ -12,21 +12,15 @@
|
||||||
*
|
*
|
||||||
* @class
|
* @class
|
||||||
* @constructor
|
* @constructor
|
||||||
|
* @param {ve.dm.ModelRegistry} modelRegistry
|
||||||
* @param {ve.dm.NodeFactory} nodeFactory
|
* @param {ve.dm.NodeFactory} nodeFactory
|
||||||
* @param {ve.dm.AnnotationFactory} annotationFactory
|
* @param {ve.dm.AnnotationFactory} annotationFactory
|
||||||
*/
|
*/
|
||||||
ve.dm.Converter = function VeDmConverter( nodeFactory, annotationFactory ) {
|
ve.dm.Converter = function VeDmConverter( modelRegistry, nodeFactory, annotationFactory ) {
|
||||||
// Properties
|
// Properties
|
||||||
|
this.modelRegistry = modelRegistry;
|
||||||
this.nodeFactory = nodeFactory;
|
this.nodeFactory = nodeFactory;
|
||||||
this.annotationFactory = annotationFactory;
|
this.annotationFactory = annotationFactory;
|
||||||
this.elements = {
|
|
||||||
'toDomElement': {},
|
|
||||||
'toDataElement': {},
|
|
||||||
'dataElementTypes': {}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Events
|
|
||||||
this.nodeFactory.addListenerMethod( this, 'register', 'onNodeRegister' );
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Static Methods */
|
/* Static Methods */
|
||||||
|
@ -58,80 +52,36 @@ ve.dm.Converter.getDataContentFromText = function ( text, annotations ) {
|
||||||
|
|
||||||
/* Methods */
|
/* Methods */
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle register events from the node factory.
|
|
||||||
*
|
|
||||||
* FIXME
|
|
||||||
* If a node is special; such as document, alienInline, alienBlock and text; its {converters}
|
|
||||||
* property should be set to null, as to distinguish it from a new node type that someone has simply
|
|
||||||
* forgotten to implement converters for.
|
|
||||||
*
|
|
||||||
* @method
|
|
||||||
* @param {string} type Node type
|
|
||||||
* @param {Function} constructor Node constructor
|
|
||||||
* @throws {Error} Missing conversion data in node implementation
|
|
||||||
*/
|
|
||||||
ve.dm.Converter.prototype.onNodeRegister = function ( dataElementType, constructor ) {
|
|
||||||
if ( !constructor.static.toDomElement || !constructor.static.toDataElement ) {
|
|
||||||
throw new Error( 'Missing static properties in node implementation of ' + dataElementType );
|
|
||||||
} else {
|
|
||||||
var i,
|
|
||||||
domElementTypes = constructor.static.matchTagNames || [],
|
|
||||||
toDomElement = constructor.static.toDomElement,
|
|
||||||
toDataElement = constructor.static.toDataElement;
|
|
||||||
// Registration
|
|
||||||
this.elements.toDomElement[dataElementType] = toDomElement;
|
|
||||||
for ( i = 0; i < domElementTypes.length; i++ ) {
|
|
||||||
this.elements.toDataElement[domElementTypes[i]] = toDataElement;
|
|
||||||
this.elements.dataElementTypes[domElementTypes[i]] = dataElementType;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the DOM element for a given linear model element.
|
* Get the DOM element for a given linear model element.
|
||||||
*
|
*
|
||||||
* This invokes the toDomElement function registered for the element type.
|
* This invokes the toDomElements function registered for the element type.
|
||||||
*
|
*
|
||||||
* @method
|
* @method
|
||||||
* @param {Object} dataElement Linear model element
|
* @param {Object} dataElement Linear model element
|
||||||
* @param {HTMLDocument} doc Document to create DOM elements in
|
* @param {HTMLDocument} doc Document to create DOM elements in
|
||||||
* @returns {HTMLElement|boolean} DOM element, or false if the element cannot be converted
|
* @returns {HTMLElement|boolean} DOM element, or false if the element cannot be converted
|
||||||
*/
|
*/
|
||||||
ve.dm.Converter.prototype.getDomElementFromDataElement = function ( dataElement, doc ) {
|
ve.dm.Converter.prototype.getDomElementsFromDataElement = function ( dataElement, doc ) {
|
||||||
var key, domElement, dataElementAttributes, wrapper,
|
var domElements, dataElementAttributes, key, matches,
|
||||||
dataElementType = dataElement.type;
|
nodeClass = this.nodeFactory.lookup( dataElement.type );
|
||||||
if ( dataElementType === 'alienInline' || dataElementType === 'alienBlock' ) {
|
if ( !nodeClass ) {
|
||||||
// Alien
|
throw new Error( 'Attempting to convert unknown data element type ' + dataElement.type );
|
||||||
// Create nodes from source
|
|
||||||
wrapper = doc.createElement( 'div' );
|
|
||||||
wrapper.innerHTML = dataElement.attributes.html;
|
|
||||||
if ( wrapper.childNodes.length > 1 ) {
|
|
||||||
// Wrap the HTML in a single element, this makes
|
|
||||||
// it much easier to deal with. It'll be unwrapped
|
|
||||||
// at the end of getDomFromData().
|
|
||||||
domElement = doc.createElement( 'div' );
|
|
||||||
domElement.setAttribute( 'data-ve-multi-child-alien-wrapper', 'true' );
|
|
||||||
while ( wrapper.firstChild ) {
|
|
||||||
domElement.appendChild( wrapper.firstChild );
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
domElement = wrapper.firstChild;
|
|
||||||
}
|
|
||||||
return domElement;
|
|
||||||
}
|
}
|
||||||
if ( !( dataElementType in this.elements.toDomElement ) ) {
|
domElements = nodeClass.static.toDomElements( dataElement, doc );
|
||||||
// Unsupported element
|
if ( !domElements || !domElements.length ) {
|
||||||
return false;
|
throw new Error( 'toDomElements() failed to return an array when converting element of type ' + dataElement.type );
|
||||||
}
|
}
|
||||||
|
|
||||||
domElement = this.elements.toDomElement[dataElementType]( dataElement );
|
|
||||||
dataElementAttributes = dataElement.attributes;
|
dataElementAttributes = dataElement.attributes;
|
||||||
if ( dataElementAttributes ) {
|
if ( dataElementAttributes ) {
|
||||||
for ( key in dataElementAttributes ) {
|
for ( key in dataElementAttributes ) {
|
||||||
// Only include 'html/0/*' attributes and strip the 'html/0/' from the beginning of the name
|
// Only include 'html/i/*' attributes and strip the 'html/i/' from the beginning of the name
|
||||||
if ( key.indexOf( 'html/0/' ) === 0 ) {
|
/*jshint regexp:false */
|
||||||
domElement.setAttribute( key.substr( 7 ), dataElementAttributes[key] );
|
matches = key.match( /^html\/(\d+)\/(.*)$/ );
|
||||||
|
if ( matches ) {
|
||||||
|
if ( domElements[matches[1]] && !domElements[matches[1]].hasAttribute( matches[2] ) ) {
|
||||||
|
domElements[matches[1]].setAttribute( matches[2], dataElementAttributes[key] );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -141,66 +91,34 @@ ve.dm.Converter.prototype.getDomElementFromDataElement = function ( dataElement,
|
||||||
!ve.isEmptyObject( dataElement.internal.changed ) &&
|
!ve.isEmptyObject( dataElement.internal.changed ) &&
|
||||||
ve.init.platform.useChangeMarkers()
|
ve.init.platform.useChangeMarkers()
|
||||||
) {
|
) {
|
||||||
domElement.setAttribute( 'data-ve-changed',
|
domElements[0].setAttribute( 'data-ve-changed',
|
||||||
JSON.stringify( dataElement.internal.changed )
|
JSON.stringify( dataElement.internal.changed )
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return domElement;
|
|
||||||
|
return domElements;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
ve.dm.Converter.prototype.createDataElement = function ( modelClass, domElements, context ) {
|
||||||
* Get the linear model data element for a given DOM element.
|
var i, j, dataElement, dataElementAttributes, domElementAttributes, domElementAttribute;
|
||||||
*
|
dataElement = modelClass.static.toDataElement( domElements, ve.copyObject( context ) );
|
||||||
* This invokes the toDataElement function registered for the element type
|
if ( modelClass.static.storeHTMLAttributes && dataElement ) {
|
||||||
*
|
for ( i = 0; i < domElements.length; i++ ) {
|
||||||
* @method
|
domElementAttributes = domElements[i].attributes;
|
||||||
* @param {HTMLElement} domElement DOM element
|
if ( domElementAttributes && domElementAttributes.length ) {
|
||||||
* @param {ve.AnnotationSet} annotations Annotations to apply if the node is a content node
|
dataElementAttributes = dataElement.attributes = dataElement.attributes || {};
|
||||||
* @returns {Object|boolean} Linear model element, or false if the node cannot be converted
|
// Include all attributes and prepend 'html/i/' to each attribute name
|
||||||
*/
|
for ( j = 0; j < domElementAttributes.length; j++ ) {
|
||||||
ve.dm.Converter.prototype.getDataElementFromDomElement = function ( domElement, annotations ) {
|
domElementAttribute = domElementAttributes[j];
|
||||||
var dataElement, domElementAttributes, dataElementAttributes, domElementAttribute, i,
|
dataElementAttributes['html/' + i + '/' + domElementAttribute.name] =
|
||||||
domElementType = domElement.nodeName.toLowerCase();
|
domElementAttribute.value;
|
||||||
annotations = annotations || new ve.AnnotationSet();
|
}
|
||||||
if (
|
}
|
||||||
// Unsupported elements
|
|
||||||
!( domElementType in this.elements.toDataElement )
|
|
||||||
// TODO check for generated elements
|
|
||||||
) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
dataElement = this.elements.toDataElement[domElementType]( domElement );
|
|
||||||
domElementAttributes = domElement.attributes;
|
|
||||||
if (
|
|
||||||
dataElement && ve.dm.nodeFactory.doesNodeStoreHtmlAttributes( dataElement.type ) &&
|
|
||||||
domElementAttributes.length
|
|
||||||
) {
|
|
||||||
dataElementAttributes = dataElement.attributes = dataElement.attributes || {};
|
|
||||||
// Include all attributes and prepend 'html/0/' to each attribute name
|
|
||||||
for ( i = 0; i < domElementAttributes.length; i++ ) {
|
|
||||||
domElementAttribute = domElementAttributes[i];
|
|
||||||
dataElementAttributes['html/0/' + domElementAttribute.name] = domElementAttribute.value;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ( this.nodeFactory.isNodeContent( dataElement.type ) && !annotations.isEmpty() ) {
|
|
||||||
dataElement.annotations = annotations.clone();
|
|
||||||
}
|
|
||||||
return dataElement;
|
return dataElement;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if an HTML DOM node represents an annotation, and if so, build an annotation object for it.
|
|
||||||
*
|
|
||||||
* Annotation Object:
|
|
||||||
* { 'type': 'type', data: { 'key': 'value', ... } }
|
|
||||||
*
|
|
||||||
* @param {HTMLElement} domElement HTML DOM node
|
|
||||||
* @returns {Object|boolean} Annotation object, or false if the node is not an annotation
|
|
||||||
*/
|
|
||||||
ve.dm.Converter.prototype.getDataAnnotationFromDomElement = function ( domElement ) {
|
|
||||||
return this.annotationFactory.createFromElement( domElement ) || false;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Build an HTML DOM node for a linear model annotation.
|
* Build an HTML DOM node for a linear model annotation.
|
||||||
*
|
*
|
||||||
|
@ -238,38 +156,6 @@ ve.dm.Converter.prototype.getDataFromDom = function ( doc ) {
|
||||||
*/
|
*/
|
||||||
ve.dm.Converter.prototype.getDataFromDomRecursion = function ( domElement, annotations,
|
ve.dm.Converter.prototype.getDataFromDomRecursion = function ( domElement, annotations,
|
||||||
dataElement, path, alreadyWrapped ) {
|
dataElement, path, alreadyWrapped ) {
|
||||||
function createAlien( domElement, context, isWrapper ) {
|
|
||||||
// We generate alienBlock elements for block tags and alienInline elements for
|
|
||||||
// inline tags; unless we're in a content location, in which case we have no choice
|
|
||||||
// but to generate an alienInline element.
|
|
||||||
var isInline =
|
|
||||||
// Force inline in content locations (but not wrappers)
|
|
||||||
( !context.inWrapper && context.expectingContent ) ||
|
|
||||||
// Also force inline in wrappers that we can't close
|
|
||||||
( context.inWrapper && !context.canCloseWrapper ) ||
|
|
||||||
// Look at the tag name otherwise
|
|
||||||
!ve.isBlockElement( domElement ),
|
|
||||||
type = isInline ? 'alienInline' : 'alienBlock',
|
|
||||||
html, alien;
|
|
||||||
if ( isWrapper ) {
|
|
||||||
html = $( domElement ).html();
|
|
||||||
} else {
|
|
||||||
html = $( '<div>', doc ).append( $( domElement ).clone() ).html();
|
|
||||||
}
|
|
||||||
alien = [
|
|
||||||
{
|
|
||||||
'type': type,
|
|
||||||
'attributes': {
|
|
||||||
'html': html
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{ 'type': '/' + type }
|
|
||||||
];
|
|
||||||
if ( !annotations.isEmpty() ) {
|
|
||||||
alien[0].annotations = annotations.clone();
|
|
||||||
}
|
|
||||||
return alien;
|
|
||||||
}
|
|
||||||
function addWhitespace( element, index, whitespace ) {
|
function addWhitespace( element, index, whitespace ) {
|
||||||
if ( !element.internal ) {
|
if ( !element.internal ) {
|
||||||
element.internal = {};
|
element.internal = {};
|
||||||
|
@ -321,76 +207,40 @@ ve.dm.Converter.prototype.getDataFromDomRecursion = function ( domElement, annot
|
||||||
context.expectingContent = originallyExpectingContent;
|
context.expectingContent = originallyExpectingContent;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
function getAboutGroup( el ) {
|
||||||
* Helper function to group adjacent child elements with the same about attribute together.
|
var textNodes = [], aboutGroup = [ el ], elAbout, node;
|
||||||
* If there are multiple adjacent child nodes with the same about attribute, they are
|
if ( !el.getAttribute || el.getAttribute( 'about' ) === null ) {
|
||||||
* wrapped in a `<div>` with the data-ve-aboutgroup attribute set.
|
return aboutGroup;
|
||||||
*
|
}
|
||||||
* This function does not wrap single-element about groups, and does not descend into the
|
elAbout = el.getAttribute( 'about' );
|
||||||
* child elements.
|
for ( node = el.nextSibling; node; node = node.nextSibling ) {
|
||||||
*
|
if ( !node.getAttribute ) {
|
||||||
* @private
|
|
||||||
* @param element {HTMLElement} Element to process
|
|
||||||
*/
|
|
||||||
function doAboutGrouping( element ) {
|
|
||||||
var child = element.firstChild, textNodes = [],
|
|
||||||
prevChild, aboutGroup, aboutWrapper, childAbout, nextChild, i;
|
|
||||||
while ( child ) {
|
|
||||||
nextChild = child.nextSibling;
|
|
||||||
if ( !child.getAttribute ) {
|
|
||||||
// Text nodes don't have a getAttribute() method. Thanks HTML DOM,
|
// Text nodes don't have a getAttribute() method. Thanks HTML DOM,
|
||||||
// that's really helpful ^^
|
// that's really helpful ^^
|
||||||
textNodes.push( child );
|
textNodes.push( node );
|
||||||
child = nextChild;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
childAbout = child.getAttribute( 'about' );
|
if ( node.getAttribute( 'about' ) === elAbout ) {
|
||||||
if ( childAbout && !aboutGroup ) {
|
aboutGroup = aboutGroup.concat( textNodes );
|
||||||
// Start of a new about group
|
textNodes = [];
|
||||||
aboutGroup = childAbout;
|
aboutGroup.push( node );
|
||||||
} else if ( childAbout && childAbout === aboutGroup ) {
|
} else {
|
||||||
// Continuation of the current about group
|
break;
|
||||||
if ( !aboutWrapper ) {
|
|
||||||
// This is the second child in this group, so the
|
|
||||||
// previous child is the first child in this group.
|
|
||||||
// Wrap the previous child
|
|
||||||
aboutWrapper = doc.createElement( 'div' );
|
|
||||||
aboutWrapper.setAttribute( 'data-ve-aboutgroup', aboutGroup );
|
|
||||||
element.insertBefore( aboutWrapper, prevChild );
|
|
||||||
aboutWrapper.appendChild( prevChild );
|
|
||||||
}
|
|
||||||
// Append any outstanding text nodes to the wrapper
|
|
||||||
for ( i = 0; i < textNodes.length; i++ ) {
|
|
||||||
aboutWrapper.appendChild( textNodes[i] );
|
|
||||||
}
|
|
||||||
// Append this child to the wrapper
|
|
||||||
aboutWrapper.appendChild( child );
|
|
||||||
} else if ( aboutGroup ) {
|
|
||||||
// This child isn't in the current about group
|
|
||||||
aboutGroup = undefined;
|
|
||||||
aboutWrapper = undefined;
|
|
||||||
if ( childAbout ) {
|
|
||||||
// Start of a new about group
|
|
||||||
aboutGroup = childAbout;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
prevChild = child;
|
|
||||||
child = nextChild;
|
|
||||||
textNodes = [];
|
|
||||||
}
|
}
|
||||||
|
return aboutGroup;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fallback to defaults
|
// Fallback to defaults
|
||||||
annotations = annotations || new ve.AnnotationSet();
|
annotations = annotations || new ve.AnnotationSet();
|
||||||
path = path || ['document'];
|
path = path || ['document'];
|
||||||
var i, j, childDomElement, annotation, childDataElement, text, childTypes, matches,
|
var i, childDomElement, childDomElements, childDataElement, text, childTypes, matches,
|
||||||
wrappingParagraph, prevElement, alien, rdfaType, isLink, childAnnotations,
|
wrappingParagraph, prevElement, childAnnotations, modelName, modelClass,
|
||||||
doc = domElement.ownerDocument,
|
annotation, childIsContent, aboutGroup,
|
||||||
data = [],
|
data = [],
|
||||||
branchType = path[path.length - 1],
|
branchType = path[path.length - 1],
|
||||||
branchHasContent = this.nodeFactory.canNodeContainContent( branchType ),
|
branchHasContent = this.nodeFactory.canNodeContainContent( branchType ),
|
||||||
originallyExpectingContent = branchHasContent || !annotations.isEmpty(),
|
originallyExpectingContent = branchHasContent || !annotations.isEmpty(),
|
||||||
childIsContent,
|
|
||||||
nextWhitespace = '',
|
nextWhitespace = '',
|
||||||
wrappedWhitespace = '',
|
wrappedWhitespace = '',
|
||||||
wrappedWhitespaceIndex,
|
wrappedWhitespaceIndex,
|
||||||
|
@ -403,101 +253,25 @@ ve.dm.Converter.prototype.getDataFromDomRecursion = function ( domElement, annot
|
||||||
if ( dataElement ) {
|
if ( dataElement ) {
|
||||||
data.push( dataElement );
|
data.push( dataElement );
|
||||||
}
|
}
|
||||||
// Do about grouping
|
|
||||||
// FIXME this assumes every about group is an alien
|
|
||||||
doAboutGrouping( domElement );
|
|
||||||
// Add contents
|
// Add contents
|
||||||
for ( i = 0; i < domElement.childNodes.length; i++ ) {
|
for ( i = 0; i < domElement.childNodes.length; i++ ) {
|
||||||
childDomElement = domElement.childNodes[i];
|
childDomElement = domElement.childNodes[i];
|
||||||
switch ( childDomElement.nodeType ) {
|
switch ( childDomElement.nodeType ) {
|
||||||
case Node.ELEMENT_NODE:
|
case Node.ELEMENT_NODE:
|
||||||
// Alienate about groups
|
modelName = this.modelRegistry.matchElement( childDomElement );
|
||||||
if ( childDomElement.hasAttribute( 'data-ve-aboutgroup' ) ) {
|
modelClass = this.modelRegistry.lookup( modelName ) || ve.dm.AlienNode;
|
||||||
alien = createAlien( childDomElement, context, true );
|
// HACK: force MetaNode for <meta>/<link> even if they have an mw: type
|
||||||
if ( context.inWrapper && alien[0].type === 'alienBlock' ) {
|
// FIXME EWWWWWW find a better way to handle this
|
||||||
stopWrapping();
|
|
||||||
} else if (
|
|
||||||
!context.inWrapper && !context.expectingContent &&
|
|
||||||
alien[0].type === 'alienInline'
|
|
||||||
) {
|
|
||||||
startWrapping();
|
|
||||||
}
|
|
||||||
data = data.concat( alien );
|
|
||||||
processNextWhitespace( alien[0] );
|
|
||||||
prevElement = alien[0];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// HACK handle <meta>/<link> separately because of the
|
|
||||||
// metaInline/metaBlock distinction
|
|
||||||
if (
|
if (
|
||||||
childDomElement.nodeName.toLowerCase() === 'meta' ||
|
( childDomElement.nodeName.toLowerCase() === 'meta' || childDomElement.nodeName.toLowerCase() === 'link' ) &&
|
||||||
childDomElement.nodeName.toLowerCase() === 'link'
|
( modelClass.prototype instanceof ve.dm.AlienNode || modelClass === ve.dm.AlienNode )
|
||||||
) {
|
) {
|
||||||
isLink = childDomElement.nodeName.toLowerCase() === 'link';
|
modelClass = ve.dm.MetaNode;
|
||||||
childDataElement = {
|
|
||||||
'type': context.expectingContent ? 'metaInline' : 'metaBlock',
|
|
||||||
'attributes': {
|
|
||||||
'style': isLink ? 'link' : 'meta',
|
|
||||||
'key': childDomElement.getAttribute( isLink ? 'rel' : 'property' )
|
|
||||||
}
|
|
||||||
};
|
|
||||||
if ( childDomElement.hasAttribute( isLink ? 'href' : 'content' ) ) {
|
|
||||||
childDataElement.attributes.value = childDomElement.getAttribute( isLink ? 'href' : 'content' );
|
|
||||||
}
|
|
||||||
// Preserve HTML attributes
|
|
||||||
// FIXME the following is duplicated from getDataElementFromDomElement()
|
|
||||||
// Include all attributes and prepend 'html/0/' to each attribute name
|
|
||||||
for ( j = 0; j < childDomElement.attributes.length; j++ ) {
|
|
||||||
// ..but exclude attributes we've already processed,
|
|
||||||
// because they'll be overwritten otherwise *sigh*
|
|
||||||
// FIXME this sucks, we need a new node type API so bad
|
|
||||||
if (
|
|
||||||
childDomElement.attributes[j].name !== ( isLink ? 'rel' : 'property' ) &&
|
|
||||||
childDomElement.attributes[j].name !== ( isLink ? 'href' : 'content' )
|
|
||||||
) {
|
|
||||||
childDataElement.attributes['html/0/' + childDomElement.attributes[j].name] = childDomElement.attributes[j].value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
data.push( childDataElement );
|
|
||||||
data.push( { 'type': context.expectingContent ? '/metaInline' : '/metaBlock' } );
|
|
||||||
processNextWhitespace( childDataElement );
|
|
||||||
prevElement = childDataElement;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// Alienate anything with a mw: type that isn't registered
|
|
||||||
// HACK because we don't actually have an RDFa type registry yet,
|
|
||||||
// this hardcodes the set of recognized types
|
|
||||||
rdfaType = childDomElement.getAttribute( 'rel' ) ||
|
|
||||||
childDomElement.getAttribute( 'typeof' ) ||
|
|
||||||
childDomElement.getAttribute( 'property' );
|
|
||||||
if (
|
|
||||||
rdfaType &&
|
|
||||||
rdfaType.match( /^mw:/ ) &&
|
|
||||||
!rdfaType.match( /^mw:WikiLink/ ) &&
|
|
||||||
!rdfaType.match( /^mw:ExtLink/ ) &&
|
|
||||||
!rdfaType.match( /^mw:Entity/ )
|
|
||||||
) {
|
|
||||||
alien = createAlien( childDomElement, context );
|
|
||||||
if ( context.inWrapper && alien[0].type === 'alienBlock' ) {
|
|
||||||
stopWrapping();
|
|
||||||
} else if (
|
|
||||||
!context.inWrapper && !context.expectingContent &&
|
|
||||||
alien[0].type === 'alienInline'
|
|
||||||
) {
|
|
||||||
startWrapping();
|
|
||||||
}
|
|
||||||
data = data.concat( alien );
|
|
||||||
processNextWhitespace( alien[0] );
|
|
||||||
prevElement = alien[0];
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
if ( modelClass.prototype instanceof ve.dm.Annotation ) {
|
||||||
|
annotation = this.annotationFactory.create( modelName, childDomElement );
|
||||||
|
|
||||||
// Detect and handle annotated content
|
// Start wrapping if needed
|
||||||
// HACK except for mw:Entity. We need a node API rewrite, badly
|
|
||||||
annotation = this.getDataAnnotationFromDomElement( childDomElement );
|
|
||||||
if ( annotation && rdfaType !== 'mw:Entity' ) {
|
|
||||||
// Start auto-wrapping of bare content
|
|
||||||
if ( !context.inWrapper && !context.expectingContent ) {
|
if ( !context.inWrapper && !context.expectingContent ) {
|
||||||
startWrapping();
|
startWrapping();
|
||||||
prevElement = wrappingParagraph;
|
prevElement = wrappingParagraph;
|
||||||
|
@ -511,65 +285,62 @@ ve.dm.Converter.prototype.getDataFromDomRecursion = function ( domElement, annot
|
||||||
undefined, path, context.inWrapper
|
undefined, path, context.inWrapper
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
break;
|
} else {
|
||||||
}
|
aboutGroup = getAboutGroup( childDomElement );
|
||||||
|
childDomElements = modelClass.static.enableAboutGrouping ?
|
||||||
// Look up child element type
|
aboutGroup : [ childDomElement ];
|
||||||
childDataElement = this.getDataElementFromDomElement( childDomElement, annotations );
|
childDataElement = this.createDataElement( modelClass, childDomElements, context );
|
||||||
if ( childDataElement ) {
|
|
||||||
childIsContent = this.nodeFactory.isNodeContent( childDataElement.type );
|
childIsContent = this.nodeFactory.isNodeContent( childDataElement.type );
|
||||||
// Check that something isn't terribly wrong
|
|
||||||
if ( !(
|
// If childIsContent isn't what we expect, adjust
|
||||||
// Non-content child in a content container
|
if ( !context.expectingContent && childIsContent ) {
|
||||||
( originallyExpectingContent && !childIsContent ) ||
|
startWrapping();
|
||||||
// Non-content child trying to break wrapping at
|
prevElement = wrappingParagraph;
|
||||||
// the wrong level
|
} else if ( context.expectingContent && !childIsContent ) {
|
||||||
( context.inWrapper && !context.canCloseWrapper && !childIsContent )
|
if ( context.inWrapper && context.canCloseWrapper ) {
|
||||||
) ) {
|
|
||||||
// End auto-wrapping of bare content from a previously processed node
|
|
||||||
// but only if childDataElement is a non-content element
|
|
||||||
if ( context.inWrapper && context.canCloseWrapper && !childIsContent ) {
|
|
||||||
stopWrapping();
|
stopWrapping();
|
||||||
} else if ( !context.inWrapper && !context.expectingContent && childIsContent ) {
|
|
||||||
startWrapping();
|
|
||||||
prevElement = wrappingParagraph;
|
|
||||||
}
|
|
||||||
if ( this.nodeFactory.canNodeHaveChildren( childDataElement.type ) ) {
|
|
||||||
// Append child element data
|
|
||||||
data = data.concat(
|
|
||||||
this.getDataFromDomRecursion(
|
|
||||||
childDomElement,
|
|
||||||
new ve.AnnotationSet(),
|
|
||||||
childDataElement,
|
|
||||||
path.concat( childDataElement.type ),
|
|
||||||
context.inWrapper
|
|
||||||
)
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
// Append empty node
|
// Alienate
|
||||||
data.push( childDataElement );
|
modelClass = ve.dm.AlienNode;
|
||||||
data.push( { 'type': '/' + childDataElement.type } );
|
childDomElements = modelClass.static.enableAboutGrouping ?
|
||||||
|
aboutGroup : [ childDomElement ];
|
||||||
|
childDataElement = this.createDataElement( modelClass, childDomElements, context );
|
||||||
|
childIsContent = this.nodeFactory.isNodeContent( childDataElement.type );
|
||||||
}
|
}
|
||||||
processNextWhitespace( childDataElement );
|
|
||||||
prevElement = childDataElement;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
// If something is wrong, fall through, and the bad child
|
|
||||||
// will be alienated below.
|
// Annotate child
|
||||||
|
if ( childIsContent && !annotations.isEmpty() ) {
|
||||||
|
childDataElement.annotations = annotations.clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output child and its children, if any
|
||||||
|
if (
|
||||||
|
childDomElements.length === 1 &&
|
||||||
|
this.nodeFactory.canNodeHaveChildren( childDataElement.type )
|
||||||
|
) {
|
||||||
|
// Recursion
|
||||||
|
// Opening and closing elements are added by the recursion too
|
||||||
|
data = data.concat(
|
||||||
|
this.getDataFromDomRecursion(
|
||||||
|
childDomElement,
|
||||||
|
new ve.AnnotationSet(),
|
||||||
|
childDataElement,
|
||||||
|
path.concat( childDataElement.type ),
|
||||||
|
context.inWrapper
|
||||||
|
)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// Write an opening and closing
|
||||||
|
data.push( childDataElement );
|
||||||
|
data.push( { 'type': '/' + childDataElement.type } );
|
||||||
|
}
|
||||||
|
processNextWhitespace( childDataElement );
|
||||||
|
prevElement = childDataElement;
|
||||||
|
|
||||||
|
// In case we consumed multiple childDomElements, adjust i accordingly
|
||||||
|
i += childDomElements.length - 1;
|
||||||
}
|
}
|
||||||
// We don't know what this is, fall back to alien.
|
|
||||||
alien = createAlien( childDomElement, context );
|
|
||||||
if ( context.inWrapper && alien[0].type === 'alienBlock' ) {
|
|
||||||
stopWrapping();
|
|
||||||
} else if (
|
|
||||||
!context.inWrapper && !context.expectingContent &&
|
|
||||||
alien[0].type === 'alienInline'
|
|
||||||
) {
|
|
||||||
startWrapping();
|
|
||||||
}
|
|
||||||
data = data.concat( alien );
|
|
||||||
processNextWhitespace( alien[0] );
|
|
||||||
prevElement = alien[0];
|
|
||||||
break;
|
break;
|
||||||
case Node.TEXT_NODE:
|
case Node.TEXT_NODE:
|
||||||
text = childDomElement.data;
|
text = childDomElement.data;
|
||||||
|
@ -700,6 +471,7 @@ ve.dm.Converter.prototype.getDataFromDomRecursion = function ( domElement, annot
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case Node.COMMENT_NODE:
|
case Node.COMMENT_NODE:
|
||||||
|
// TODO treat this as a node with nodeName #comment
|
||||||
childDataElement = {
|
childDataElement = {
|
||||||
'type': context.expectingContent ? 'metaInline' : 'metaBlock',
|
'type': context.expectingContent ? 'metaInline' : 'metaBlock',
|
||||||
'attributes': {
|
'attributes': {
|
||||||
|
@ -761,7 +533,7 @@ ve.dm.Converter.prototype.getDataFromDomRecursion = function ( domElement, annot
|
||||||
*/
|
*/
|
||||||
ve.dm.Converter.prototype.getDomFromData = function ( data ) {
|
ve.dm.Converter.prototype.getDomFromData = function ( data ) {
|
||||||
var text, i, j, k, annotations, annotation, annotationElement, dataElement, arr,
|
var text, i, j, k, annotations, annotation, annotationElement, dataElement, arr,
|
||||||
childDomElement, pre, ours, theirs, parentDomElement, startClosingAt,
|
childDomElements, pre, ours, theirs, parentDomElement, lastChild, startClosingAt,
|
||||||
isContentNode, changed, parentChanged,
|
isContentNode, changed, parentChanged,
|
||||||
doc = ve.createDocumentFromHTML( '' ),
|
doc = ve.createDocumentFromHTML( '' ),
|
||||||
container = doc.body,
|
container = doc.body,
|
||||||
|
@ -855,8 +627,11 @@ ve.dm.Converter.prototype.getDomFromData = function ( data ) {
|
||||||
domElement.appendChild( doc.createTextNode( text ) );
|
domElement.appendChild( doc.createTextNode( text ) );
|
||||||
text = '';
|
text = '';
|
||||||
}
|
}
|
||||||
// Insert the element
|
// Insert the elements
|
||||||
domElement.appendChild( this.getDomElementFromDataElement( data[i], doc ) );
|
childDomElements = this.getDomElementsFromDataElement( data[i], doc );
|
||||||
|
for ( j = 0; j < childDomElements.length; j++ ) {
|
||||||
|
domElement.appendChild( childDomElements[j] );
|
||||||
|
}
|
||||||
// Increment i once more so we skip over the closing as well
|
// Increment i once more so we skip over the closing as well
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
@ -909,6 +684,11 @@ ve.dm.Converter.prototype.getDomFromData = function ( data ) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
lastChild = domElement.veInternal.childDomElements ?
|
||||||
|
domElement.veInternal
|
||||||
|
.childDomElements[domElement.veInternal.childDomElements.length - 1]
|
||||||
|
.lastChild :
|
||||||
|
domElement.lastChild;
|
||||||
ours = domElement.veInternal.whitespace[2];
|
ours = domElement.veInternal.whitespace[2];
|
||||||
if ( domElement.lastOuterPost === undefined ) {
|
if ( domElement.lastOuterPost === undefined ) {
|
||||||
// This node didn't have any structural children
|
// This node didn't have any structural children
|
||||||
|
@ -919,10 +699,7 @@ ve.dm.Converter.prototype.getDomFromData = function ( data ) {
|
||||||
theirs = domElement.lastOuterPost;
|
theirs = domElement.lastOuterPost;
|
||||||
}
|
}
|
||||||
if ( ours && ours === theirs ) {
|
if ( ours && ours === theirs ) {
|
||||||
if (
|
if ( lastChild && lastChild.nodeType === 3 ) {
|
||||||
domElement.lastChild &&
|
|
||||||
domElement.lastChild.nodeType === 3
|
|
||||||
) {
|
|
||||||
// Last child is a TextNode, append to it
|
// Last child is a TextNode, append to it
|
||||||
domElement.lastChild.appendData( ours );
|
domElement.lastChild.appendData( ours );
|
||||||
} else {
|
} else {
|
||||||
|
@ -991,16 +768,19 @@ ve.dm.Converter.prototype.getDomFromData = function ( data ) {
|
||||||
domElement = parentDomElement;
|
domElement = parentDomElement;
|
||||||
} else {
|
} else {
|
||||||
// Create node from data
|
// Create node from data
|
||||||
childDomElement = this.getDomElementFromDataElement( dataElement, doc );
|
childDomElements = this.getDomElementsFromDataElement( dataElement, doc );
|
||||||
// Add reference to internal data
|
// Add reference to internal data
|
||||||
if ( dataElement.internal ) {
|
childDomElements[0].veInternal = ve.extendObject(
|
||||||
childDomElement.veInternal = dataElement.internal;
|
{ 'childDomElements': childDomElements },
|
||||||
|
dataElement.internal || {}
|
||||||
|
);
|
||||||
|
// Add elements
|
||||||
|
for ( j = 0; j < childDomElements.length; j++ ) {
|
||||||
|
domElement.appendChild( childDomElements[j] );
|
||||||
}
|
}
|
||||||
// Add element
|
// Descend into the first child node
|
||||||
domElement.appendChild( childDomElement );
|
|
||||||
// Descend into child node
|
|
||||||
parentDomElement = domElement;
|
parentDomElement = domElement;
|
||||||
domElement = childDomElement;
|
domElement = childDomElements[0];
|
||||||
|
|
||||||
// Process outer whitespace
|
// Process outer whitespace
|
||||||
// Every piece of outer whitespace is duplicated somewhere:
|
// Every piece of outer whitespace is duplicated somewhere:
|
||||||
|
@ -1057,11 +837,6 @@ ve.dm.Converter.prototype.getDomFromData = function ( data ) {
|
||||||
delete container.lastOuterPost;
|
delete container.lastOuterPost;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unwrap multi-child alien wrappers
|
|
||||||
$( container ).find( '[data-ve-multi-child-alien-wrapper]' ).each( function() {
|
|
||||||
$( this ).replaceWith( $( this ).contents() );
|
|
||||||
} );
|
|
||||||
|
|
||||||
// Workaround for bug 42469: if a <pre> starts with a newline, that means .innerHTML will
|
// Workaround for bug 42469: if a <pre> starts with a newline, that means .innerHTML will
|
||||||
// screw up and stringify it with one fewer newline. Work around this by adding a newline.
|
// screw up and stringify it with one fewer newline. Work around this by adding a newline.
|
||||||
// If we don't see a leading newline, we still don't know if the original HTML was
|
// If we don't see a leading newline, we still don't know if the original HTML was
|
||||||
|
@ -1082,4 +857,4 @@ ve.dm.Converter.prototype.getDomFromData = function ( data ) {
|
||||||
|
|
||||||
/* Initialization */
|
/* Initialization */
|
||||||
|
|
||||||
ve.dm.converter = new ve.dm.Converter( ve.dm.nodeFactory, ve.dm.annotationFactory );
|
ve.dm.converter = new ve.dm.Converter( ve.dm.modelRegistry, ve.dm.nodeFactory, ve.dm.annotationFactory );
|
||||||
|
|
|
@ -87,10 +87,14 @@ ve.dm.Node.static.matchRdfaTypes = null;
|
||||||
ve.dm.Node.static.matchFunction = null;
|
ve.dm.Node.static.matchFunction = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Static function to convert a DOM element to a linear model data element for this node type.
|
* Static function to convert a DOM element or set of sibling DOM elements to a linear model data
|
||||||
|
* element for this node type.
|
||||||
*
|
*
|
||||||
* This function is only called if this node "won" the matching for the DOM element, so domElement
|
* This function is only called if this node "won" the matching for the first DOM element, so
|
||||||
* will match this node's matching rule.
|
* domElements[0] will match this node's matching rule. There is usually only one node in
|
||||||
|
* domElements[]. Multiple nodes will only be passed if this node 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).
|
||||||
*
|
*
|
||||||
* This function is allowed to return a content element when context indicates that a non-content
|
* This function is allowed to return a content element when context indicates that a non-content
|
||||||
* element is expected or vice versa. If that happens, the converter deals with it in the following way:
|
* element is expected or vice versa. If that happens, the converter deals with it in the following way:
|
||||||
|
@ -114,7 +118,7 @@ ve.dm.Node.static.matchFunction = null;
|
||||||
*
|
*
|
||||||
* @static
|
* @static
|
||||||
* @method
|
* @method
|
||||||
* @param {HTMLElement} domElement DOM element to convert
|
* @param {HTMLElement[]} domElements DOM elements to convert. Usually only one element
|
||||||
* @param {Object} context Object describing the current state of the converter
|
* @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.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;
|
* @param {boolean} context.inWrapper Whether this element is in a wrapper paragraph generated by the converter;
|
||||||
|
@ -123,20 +127,24 @@ ve.dm.Node.static.matchFunction = null;
|
||||||
* can only be true if context.inWrapper is also true
|
* can only be true if context.inWrapper is also true
|
||||||
* @returns {Object|null} Linear model element, or null to alienate
|
* @returns {Object|null} Linear model element, or null to alienate
|
||||||
*/
|
*/
|
||||||
ve.dm.Node.static.toDataElement = function ( /*domElement, context*/ ) {
|
ve.dm.Node.static.toDataElement = function ( /*domElements, context*/ ) {
|
||||||
throw new Error( 've.dm.Node subclass must implement toDataElement' );
|
throw new Error( 've.dm.Node subclass must implement toDataElement' );
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Static function to convert a linear model data element for this node type back to a DOM element.
|
* Static function to convert a linear model data element for this node type back to one or more
|
||||||
|
* DOM elements.
|
||||||
|
*
|
||||||
|
* NOTE: If this function returns multiple DOM elements, the DOM elements produced by the children
|
||||||
|
* of this node (if any) will be attached to the first DOM element in the array.
|
||||||
*
|
*
|
||||||
* @static
|
* @static
|
||||||
* @method
|
* @method
|
||||||
* @param {Object} Linear model element with a type property and optionally an attributes property
|
* @param {Object} Linear model element with a type property and optionally an attributes property
|
||||||
* @returns {HTMLElement} DOM element
|
* @returns {HTMLElement[]} DOM elements
|
||||||
*/
|
*/
|
||||||
ve.dm.Node.static.toDomElement = function ( /*dataElement*/ ) {
|
ve.dm.Node.static.toDomElements = function ( /*dataElement*/ ) {
|
||||||
throw new Error( 've.dm.Node subclass must implement toDomElement' );
|
throw new Error( 've.dm.Node subclass must implement toDomElements' );
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -169,7 +177,8 @@ ve.dm.Node.static.enableAboutGrouping = false;
|
||||||
/**
|
/**
|
||||||
* Whether HTML attributes should be preserved for this node type. If true, the HTML attributes
|
* 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 be
|
||||||
* html/0/attrName, where attrName is the name of the attribute.
|
* 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 node types that store their entire HTML in an
|
* This should generally be enabled, except for node types that store their entire HTML in an
|
||||||
* attribute.
|
* attribute.
|
||||||
|
|
|
@ -9,6 +9,8 @@ QUnit.module( 've.dm.Converter' );
|
||||||
|
|
||||||
/* Tests */
|
/* Tests */
|
||||||
|
|
||||||
|
// TODO rewrite to test getDataElementOrAnnotationFromDomElement
|
||||||
|
/*
|
||||||
QUnit.test( 'getDataElementFromDomElement', 20, function ( assert ) {
|
QUnit.test( 'getDataElementFromDomElement', 20, function ( assert ) {
|
||||||
var msg, conversion;
|
var msg, conversion;
|
||||||
|
|
||||||
|
@ -21,14 +23,15 @@ QUnit.test( 'getDataElementFromDomElement', 20, function ( assert ) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} );
|
} );
|
||||||
|
*/
|
||||||
|
|
||||||
QUnit.test( 'getDomElementFromDataElement', 20, function ( assert ) {
|
QUnit.test( 'getDomElementsFromDataElement', 20, function ( assert ) {
|
||||||
var msg, conversion;
|
var msg, conversion;
|
||||||
|
|
||||||
for ( msg in ve.dm.example.conversions ) {
|
for ( msg in ve.dm.example.conversions ) {
|
||||||
conversion = ve.dm.example.conversions[msg];
|
conversion = ve.dm.example.conversions[msg];
|
||||||
assert.equalDomElement(
|
assert.equalDomElement(
|
||||||
ve.dm.converter.getDomElementFromDataElement( conversion.dataElement ),
|
ve.dm.converter.getDomElementsFromDataElement( conversion.dataElement )[0],
|
||||||
conversion.domElement,
|
conversion.domElement,
|
||||||
msg
|
msg
|
||||||
);
|
);
|
||||||
|
|
|
@ -81,7 +81,7 @@ ve.dm.StubBarNode.static.matchRdfaTypes = ['bar'];
|
||||||
// HACK keep ve.dm.Converter happy for now
|
// HACK keep ve.dm.Converter happy for now
|
||||||
// TODO once ve.dm.Converter is rewritten, this can be removed
|
// TODO once ve.dm.Converter is rewritten, this can be removed
|
||||||
ve.dm.StubBarNode.static.toDataElement = function () {};
|
ve.dm.StubBarNode.static.toDataElement = function () {};
|
||||||
ve.dm.StubBarNode.static.toDomElement = function () {};
|
ve.dm.StubBarNode.static.toDomElements = function () {};
|
||||||
|
|
||||||
/* Tests */
|
/* Tests */
|
||||||
|
|
||||||
|
|
|
@ -302,7 +302,8 @@ ve.dm.example.withMeta = [
|
||||||
'type': 'metaBlock',
|
'type': 'metaBlock',
|
||||||
'attributes': {
|
'attributes': {
|
||||||
'style': 'meta',
|
'style': 'meta',
|
||||||
'key': 'mw:PageProp/nocc'
|
'key': 'mw:PageProp/nocc',
|
||||||
|
'html/0/property': 'mw:PageProp/nocc'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{ 'type': '/metaBlock' },
|
{ 'type': '/metaBlock' },
|
||||||
|
@ -315,7 +316,9 @@ ve.dm.example.withMeta = [
|
||||||
'attributes': {
|
'attributes': {
|
||||||
'style': 'link',
|
'style': 'link',
|
||||||
'key': 'mw:WikiLink/Category',
|
'key': 'mw:WikiLink/Category',
|
||||||
'value': './Category:Bar'
|
'value': './Category:Bar',
|
||||||
|
'html/0/href': './Category:Bar',
|
||||||
|
'html/0/rel': 'mw:WikiLink/Category'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{ 'type': '/metaInline' },
|
{ 'type': '/metaInline' },
|
||||||
|
@ -327,7 +330,9 @@ ve.dm.example.withMeta = [
|
||||||
'attributes': {
|
'attributes': {
|
||||||
'style': 'meta',
|
'style': 'meta',
|
||||||
'key': 'mw:foo',
|
'key': 'mw:foo',
|
||||||
'value': 'bar'
|
'value': 'bar',
|
||||||
|
'html/0/content': 'bar',
|
||||||
|
'html/0/property': 'mw:foo'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{ 'type': '/metaInline' },
|
{ 'type': '/metaInline' },
|
||||||
|
@ -348,7 +353,9 @@ ve.dm.example.withMeta = [
|
||||||
'attributes': {
|
'attributes': {
|
||||||
'style': 'meta',
|
'style': 'meta',
|
||||||
'key': 'mw:bar',
|
'key': 'mw:bar',
|
||||||
'value': 'baz'
|
'value': 'baz',
|
||||||
|
'html/0/content': 'baz',
|
||||||
|
'html/0/property': 'mw:bar'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{ 'type': '/metaBlock' },
|
{ 'type': '/metaBlock' },
|
||||||
|
@ -365,7 +372,9 @@ ve.dm.example.withMeta = [
|
||||||
'attributes': {
|
'attributes': {
|
||||||
'style': 'link',
|
'style': 'link',
|
||||||
'key': 'mw:WikiLink/Category',
|
'key': 'mw:WikiLink/Category',
|
||||||
'value': './Category:Foo#Bar baz%23quux'
|
'value': './Category:Foo#Bar baz%23quux',
|
||||||
|
'html/0/href': './Category:Foo#Bar baz%23quux',
|
||||||
|
'html/0/rel': 'mw:WikiLink/Category'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{ 'type': '/metaBlock' },
|
{ 'type': '/metaBlock' },
|
||||||
|
@ -408,7 +417,8 @@ ve.dm.example.withMetaMetaData = [
|
||||||
'type': 'metaBlock',
|
'type': 'metaBlock',
|
||||||
'attributes': {
|
'attributes': {
|
||||||
'style': 'meta',
|
'style': 'meta',
|
||||||
'key': 'mw:PageProp/nocc'
|
'key': 'mw:PageProp/nocc',
|
||||||
|
'html/0/property': 'mw:PageProp/nocc'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
@ -421,7 +431,9 @@ ve.dm.example.withMetaMetaData = [
|
||||||
'attributes': {
|
'attributes': {
|
||||||
'style': 'link',
|
'style': 'link',
|
||||||
'key': 'mw:WikiLink/Category',
|
'key': 'mw:WikiLink/Category',
|
||||||
'value': './Category:Bar'
|
'value': './Category:Bar',
|
||||||
|
'html/0/href': './Category:Bar',
|
||||||
|
'html/0/rel': 'mw:WikiLink/Category'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
@ -433,7 +445,9 @@ ve.dm.example.withMetaMetaData = [
|
||||||
'attributes': {
|
'attributes': {
|
||||||
'style': 'meta',
|
'style': 'meta',
|
||||||
'key': 'mw:foo',
|
'key': 'mw:foo',
|
||||||
'value': 'bar'
|
'value': 'bar',
|
||||||
|
'html/0/content': 'bar',
|
||||||
|
'html/0/property': 'mw:foo'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
@ -454,7 +468,9 @@ ve.dm.example.withMetaMetaData = [
|
||||||
'attributes': {
|
'attributes': {
|
||||||
'style': 'meta',
|
'style': 'meta',
|
||||||
'key': 'mw:bar',
|
'key': 'mw:bar',
|
||||||
'value': 'baz'
|
'value': 'baz',
|
||||||
|
'html/0/content': 'baz',
|
||||||
|
'html/0/property': 'mw:bar'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -469,7 +485,9 @@ ve.dm.example.withMetaMetaData = [
|
||||||
'attributes': {
|
'attributes': {
|
||||||
'style': 'link',
|
'style': 'link',
|
||||||
'key': 'mw:WikiLink/Category',
|
'key': 'mw:WikiLink/Category',
|
||||||
'value': './Category:Foo#Bar baz%23quux'
|
'value': './Category:Foo#Bar baz%23quux',
|
||||||
|
'html/0/href': './Category:Foo#Bar baz%23quux',
|
||||||
|
'html/0/rel': 'mw:WikiLink/Category'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -478,7 +496,7 @@ ve.dm.example.withMetaMetaData = [
|
||||||
'style': 'meta',
|
'style': 'meta',
|
||||||
'key': null,
|
'key': null,
|
||||||
'html/0/typeof': 'mw:Placeholder',
|
'html/0/typeof': 'mw:Placeholder',
|
||||||
'html/0/data-parsoid': 'foobar',
|
'html/0/data-parsoid': 'foobar'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -865,13 +883,11 @@ ve.dm.example.domToDataCases = {
|
||||||
'data': [
|
'data': [
|
||||||
{ 'type': 'paragraph', 'internal': { 'generated': 'wrapper' } },
|
{ 'type': 'paragraph', 'internal': { 'generated': 'wrapper' } },
|
||||||
'1',
|
'1',
|
||||||
{ 'type': '/paragraph' },
|
|
||||||
{
|
{
|
||||||
'type': 'alienBlock',
|
'type': 'alienInline',
|
||||||
'attributes': { 'html': '<tt about="#mwt1">foo</tt><tt about="#mwt1">bar</tt>' }
|
'attributes': { 'html': '<tt about="#mwt1">foo</tt><tt about="#mwt1">bar</tt>' }
|
||||||
},
|
},
|
||||||
{ 'type': '/alienBlock' },
|
{ 'type': '/alienInline' },
|
||||||
{ 'type': 'paragraph', 'internal': { 'generated': 'wrapper' } },
|
|
||||||
'2',
|
'2',
|
||||||
{ 'type': '/paragraph' }
|
{ 'type': '/paragraph' }
|
||||||
]
|
]
|
||||||
|
@ -1973,7 +1989,9 @@ ve.dm.example.domToDataCases = {
|
||||||
'attributes': {
|
'attributes': {
|
||||||
'style': 'meta',
|
'style': 'meta',
|
||||||
'key': 'mw:foo',
|
'key': 'mw:foo',
|
||||||
'value': 'bar'
|
'value': 'bar',
|
||||||
|
'html/0/content': 'bar',
|
||||||
|
'html/0/property': 'mw:foo'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{ 'type': '/metaInline' },
|
{ 'type': '/metaInline' },
|
||||||
|
@ -2075,4 +2093,4 @@ ve.dm.example.isolationData = [
|
||||||
{ 'type': '/preformatted' },
|
{ 'type': '/preformatted' },
|
||||||
{ 'type': '/listItem' },
|
{ 'type': '/listItem' },
|
||||||
{ 'type': '/list' }
|
{ 'type': '/list' }
|
||||||
];
|
];
|
||||||
|
|
Loading…
Reference in a new issue