mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/VisualEditor
synced 2024-09-25 03:08:42 +00:00
Split Broke DefinitionListNode out of ListNode and DefinitionListItemNode out of ListItemNode
* Makes it simpler in the linear model because we don't have to use style: "item" for regular list items and style: "definition" for definition lists * Enforces correct nesting through existing node rules systems * Updates tests accordingly Change-Id: I64d80af938e325f1961226505bdc386bb35ccdda
This commit is contained in:
parent
11a3b6886b
commit
9887dbd96f
|
@ -115,6 +115,8 @@ include( '../../modules/sandbox/base.php' );
|
|||
<script src="../../modules/ve2/dm/ve.dm.Document.js"></script>
|
||||
|
||||
<script src="../../modules/ve2/dm/nodes/ve.dm.AlienNode.js"></script>
|
||||
<script src="../../modules/ve2/dm/nodes/ve.dm.DefinitionListItemNode.js"></script>
|
||||
<script src="../../modules/ve2/dm/nodes/ve.dm.DefinitionListNode.js"></script>
|
||||
<script src="../../modules/ve2/dm/nodes/ve.dm.DocumentNode.js"></script>
|
||||
<script src="../../modules/ve2/dm/nodes/ve.dm.HeadingNode.js"></script>
|
||||
<script src="../../modules/ve2/dm/nodes/ve.dm.ImageNode.js"></script>
|
||||
|
@ -142,6 +144,8 @@ include( '../../modules/sandbox/base.php' );
|
|||
<script src="../../modules/ve2/ce/ve.ce.Surface.js"></script>
|
||||
|
||||
<script src="../../modules/ve2/ce/nodes/ve.ce.AlienNode.js"></script>
|
||||
<script src="../../modules/ve2/ce/nodes/ve.ce.DefinitionListItemNode.js"></script>
|
||||
<script src="../../modules/ve2/ce/nodes/ve.ce.DefinitionListNode.js"></script>
|
||||
<script src="../../modules/ve2/ce/nodes/ve.ce.DocumentNode.js"></script>
|
||||
<script src="../../modules/ve2/ce/nodes/ve.ce.HeadingNode.js"></script>
|
||||
<script src="../../modules/ve2/ce/nodes/ve.ce.ImageNode.js"></script>
|
||||
|
|
91
modules/ve2/ce/nodes/ve.ce.DefinitionListItemNode.js
Normal file
91
modules/ve2/ce/nodes/ve.ce.DefinitionListItemNode.js
Normal file
|
@ -0,0 +1,91 @@
|
|||
/**
|
||||
* ContentEditable node for a definition list item.
|
||||
*
|
||||
* @class
|
||||
* @constructor
|
||||
* @extends {ve.ce.BranchNode}
|
||||
* @param model {ve.dm.DefinitionListItemNode} Model to observe
|
||||
*/
|
||||
ve.ce.DefinitionListItemNode = function( model ) {
|
||||
// Inheritance
|
||||
ve.ce.BranchNode.call( this, model, ve.ce.DefinitionListItemNode.getDomWrapper( model ) );
|
||||
|
||||
// Properties
|
||||
this.currentStyle = model.getAttribute( 'style' );
|
||||
|
||||
// Events
|
||||
this.model.addListenerMethod( this, 'update', 'onUpdate' );
|
||||
};
|
||||
|
||||
/* Static Members */
|
||||
|
||||
/**
|
||||
* Node rules.
|
||||
*
|
||||
* @see ve.ce.NodeFactory
|
||||
* @static
|
||||
* @member
|
||||
*/
|
||||
ve.ce.DefinitionListItemNode.rules = {
|
||||
'canHaveChildren': true,
|
||||
'canHaveGrandchildren': true,
|
||||
'canBeSplit': false
|
||||
};
|
||||
|
||||
/**
|
||||
* Mapping of list item style values and DOM wrapper element types.
|
||||
*
|
||||
* @static
|
||||
* @member
|
||||
*/
|
||||
ve.ce.DefinitionListItemNode.domWrapperElementTypes = {
|
||||
'definition': 'dd',
|
||||
'term': 'dt'
|
||||
};
|
||||
|
||||
/* Static Methods */
|
||||
|
||||
/**
|
||||
* Gets an appropriate DOM wrapper for the model.
|
||||
*
|
||||
* This method is static because it is used before the node is fully constructed. Before all parent
|
||||
* constructors are called this.model may not be ready to be used.
|
||||
*
|
||||
* @static
|
||||
* @method
|
||||
* @param {ve.dm.DefinitionListItemNode} model Model to create DOM wrapper for
|
||||
* @returns {jQuery} Selection containing DOM wrapper
|
||||
*/
|
||||
ve.ce.DefinitionListItemNode.getDomWrapper = function( model ) {
|
||||
var style = model.getAttribute( 'style' ),
|
||||
type = ve.ce.DefinitionListItemNode.domWrapperElementTypes[style];
|
||||
if ( type === undefined ) {
|
||||
throw 'Invalid style attribute in list item node model: ' + style;
|
||||
}
|
||||
return $( '<' + type + '></' + type + '>' );
|
||||
};
|
||||
|
||||
/* Methods */
|
||||
|
||||
/**
|
||||
* Responds to model update events.
|
||||
*
|
||||
* If the style changed since last update the DOM wrapper will be replaced with an appropriate one.
|
||||
*
|
||||
* @method
|
||||
*/
|
||||
ve.ce.DefinitionListItemNode.prototype.onUpdate = function() {
|
||||
var style = this.model.getAttribute( 'style' );
|
||||
if ( style !== this.currentStyle ) {
|
||||
this.currentStyle = style;
|
||||
this.replaceDomWrapper( ve.ce.DefinitionListItemNode.getDomWrapper( this.model ) );
|
||||
}
|
||||
};
|
||||
|
||||
/* Registration */
|
||||
|
||||
ve.ce.factory.register( 'definitionListItem', ve.ce.DefinitionListItemNode );
|
||||
|
||||
/* Inheritance */
|
||||
|
||||
ve.extendClass( ve.ce.DefinitionListItemNode, ve.ce.BranchNode );
|
35
modules/ve2/ce/nodes/ve.ce.DefinitionListNode.js
Normal file
35
modules/ve2/ce/nodes/ve.ce.DefinitionListNode.js
Normal file
|
@ -0,0 +1,35 @@
|
|||
/**
|
||||
* ContentEditable node for a definition list.
|
||||
*
|
||||
* @class
|
||||
* @constructor
|
||||
* @extends {ve.ce.BranchNode}
|
||||
* @param model {ve.dm.DefinitionListNode} Model to observe
|
||||
*/
|
||||
ve.ce.DefinitionListNode = function( model ) {
|
||||
// Inheritance
|
||||
ve.ce.BranchNode.call( this, model, $( '<dl></dl>' ) );
|
||||
};
|
||||
|
||||
/* Static Members */
|
||||
|
||||
/**
|
||||
* Node rules.
|
||||
*
|
||||
* @see ve.ce.NodeFactory
|
||||
* @static
|
||||
* @member
|
||||
*/
|
||||
ve.ce.DefinitionListNode.rules = {
|
||||
'canHaveChildren': true,
|
||||
'canHaveGrandchildren': true,
|
||||
'canBeSplit': false
|
||||
};
|
||||
|
||||
/* Registration */
|
||||
|
||||
ve.ce.factory.register( 'definitionList', ve.ce.DefinitionListNode );
|
||||
|
||||
/* Inheritance */
|
||||
|
||||
ve.extendClass( ve.ce.DefinitionListNode, ve.ce.BranchNode );
|
|
@ -8,13 +8,7 @@
|
|||
*/
|
||||
ve.ce.ListItemNode = function( model ) {
|
||||
// Inheritance
|
||||
ve.ce.BranchNode.call( this, model, ve.ce.ListItemNode.getDomWrapper( model ) );
|
||||
|
||||
// Properties
|
||||
this.currentStyle = model.getAttribute( 'style' );
|
||||
|
||||
// Events
|
||||
this.model.addListenerMethod( this, 'update', 'onUpdate' );
|
||||
ve.ce.BranchNode.call( this, model, $( '<li></li>' ) );
|
||||
};
|
||||
|
||||
/* Static Members */
|
||||
|
@ -32,57 +26,6 @@ ve.ce.ListItemNode.rules = {
|
|||
'canBeSplit': false
|
||||
};
|
||||
|
||||
/**
|
||||
* Mapping of list item style values and DOM wrapper element types.
|
||||
*
|
||||
* @static
|
||||
* @member
|
||||
*/
|
||||
ve.ce.ListItemNode.domWrapperElementTypes = {
|
||||
'item': 'li',
|
||||
'definition': 'dd',
|
||||
'term': 'dt'
|
||||
};
|
||||
|
||||
/* Static Methods */
|
||||
|
||||
/**
|
||||
* Gets an appropriate DOM wrapper for the model.
|
||||
*
|
||||
* This method is static because it is used before the node is fully constructed. Before all parent
|
||||
* constructors are called this.model may not be ready to be used.
|
||||
*
|
||||
* @static
|
||||
* @method
|
||||
* @param {ve.dm.ListItemNode} model Model to create DOM wrapper for
|
||||
* @returns {jQuery} Selection containing DOM wrapper
|
||||
*/
|
||||
ve.ce.ListItemNode.getDomWrapper = function( model ) {
|
||||
var style = model.getAttribute( 'style' ),
|
||||
type = ve.ce.ListItemNode.domWrapperElementTypes[style];
|
||||
if ( type === undefined ) {
|
||||
throw 'Invalid style attribute in list item node model: ' + style;
|
||||
}
|
||||
return $( '<' + type + '></' + type + '>' );
|
||||
};
|
||||
|
||||
/* Methods */
|
||||
|
||||
/**
|
||||
* Responds to model update events.
|
||||
*
|
||||
* If the style changed since last update the DOM wrapper will be replaced with an appropriate one.
|
||||
*
|
||||
* @method
|
||||
*/
|
||||
ve.ce.ListItemNode.prototype.onUpdate = function() {
|
||||
var style = this.model.getAttribute( 'style' );
|
||||
if ( style !== this.currentStyle ) {
|
||||
this.currentStyle = style;
|
||||
this.replaceDomWrapper( ve.ce.ListItemNode.getDomWrapper( this.model ) );
|
||||
}
|
||||
};
|
||||
|
||||
/* Registration */
|
||||
|
||||
ve.ce.factory.register( 'listItem', ve.ce.ListItemNode );
|
||||
|
|
|
@ -40,8 +40,7 @@ ve.ce.ListNode.rules = {
|
|||
*/
|
||||
ve.ce.ListNode.domWrapperElementTypes = {
|
||||
'bullet': 'ul',
|
||||
'number': 'ol',
|
||||
'definition': 'dl'
|
||||
'number': 'ol'
|
||||
};
|
||||
|
||||
/* Static Methods */
|
||||
|
|
37
modules/ve2/dm/nodes/ve.dm.DefinitionListItemNode.js
Normal file
37
modules/ve2/dm/nodes/ve.dm.DefinitionListItemNode.js
Normal file
|
@ -0,0 +1,37 @@
|
|||
/**
|
||||
* DataModel node for a definition list item.
|
||||
*
|
||||
* @class
|
||||
* @constructor
|
||||
* @extends {ve.dm.BranchNode}
|
||||
* @param {ve.dm.BranchNode[]} [children] Child nodes to attach
|
||||
* @param {Object} [attributes] Reference to map of attribute key/value pairs
|
||||
*/
|
||||
ve.dm.DefinitionListItemNode = function( children, attributes ) {
|
||||
// Inheritance
|
||||
ve.dm.BranchNode.call( this, 'definitionListItem', children, attributes );
|
||||
};
|
||||
|
||||
/* Static Members */
|
||||
|
||||
/**
|
||||
* Node rules.
|
||||
*
|
||||
* @see ve.dm.NodeFactory
|
||||
* @static
|
||||
* @member
|
||||
*/
|
||||
ve.dm.DefinitionListItemNode.rules = {
|
||||
'canHaveChildren': true,
|
||||
'canHaveGrandchildren': true,
|
||||
'childNodeTypes': null,
|
||||
'parentNodeTypes': ['definitionList']
|
||||
};
|
||||
|
||||
/* Registration */
|
||||
|
||||
ve.dm.factory.register( 'definitionListItem', ve.dm.DefinitionListItemNode );
|
||||
|
||||
/* Inheritance */
|
||||
|
||||
ve.extendClass( ve.dm.DefinitionListItemNode, ve.dm.BranchNode );
|
37
modules/ve2/dm/nodes/ve.dm.DefinitionListNode.js
Normal file
37
modules/ve2/dm/nodes/ve.dm.DefinitionListNode.js
Normal file
|
@ -0,0 +1,37 @@
|
|||
/**
|
||||
* DataModel node for a definition list.
|
||||
*
|
||||
* @class
|
||||
* @constructor
|
||||
* @extends {ve.dm.BranchNode}
|
||||
* @param {ve.dm.BranchNode[]} [children] Child nodes to attach
|
||||
* @param {Object} [attributes] Reference to map of attribute key/value pairs
|
||||
*/
|
||||
ve.dm.DefinitionListNode = function( children, attributes ) {
|
||||
// Inheritance
|
||||
ve.dm.BranchNode.call( this, 'definitionList', children, attributes );
|
||||
};
|
||||
|
||||
/* Static Members */
|
||||
|
||||
/**
|
||||
* Node rules.
|
||||
*
|
||||
* @see ve.dm.NodeFactory
|
||||
* @static
|
||||
* @member
|
||||
*/
|
||||
ve.dm.DefinitionListNode.rules = {
|
||||
'canHaveChildren': true,
|
||||
'canHaveGrandchildren': true,
|
||||
'childNodeTypes': ['definitionListItem'],
|
||||
'parentNodeTypes': null
|
||||
};
|
||||
|
||||
/* Registration */
|
||||
|
||||
ve.dm.factory.register( 'definitionList', ve.dm.DefinitionListNode );
|
||||
|
||||
/* Inheritance */
|
||||
|
||||
ve.extendClass( ve.dm.DefinitionListNode, ve.dm.BranchNode );
|
|
@ -11,10 +11,10 @@ test( 'getOuterLength', 1, function() {
|
|||
);
|
||||
} );
|
||||
|
||||
test( 'rebuildNodes', 88, function() {
|
||||
test( 'rebuildNodes', 114, function() {
|
||||
var doc = new ve.dm.Document( ve.dm.example.data ),
|
||||
documentNode = doc.getDocumentNode();
|
||||
doc.rebuildNodes( documentNode, 1, 1, 5, 30 );
|
||||
// Test count: ( ( 4 tests x 16 branch nodes ) + ( 3 tests x 8 leaf nodes ) ) = 88
|
||||
// Test count: ( ( 4 tests x 21 branch nodes ) + ( 3 tests x 10 leaf nodes ) ) = 114
|
||||
ve.dm.example.nodeTreeEqual( documentNode, ve.dm.example.tree );
|
||||
} );
|
||||
|
|
|
@ -2,9 +2,9 @@ module( 've.dm.DocumentFragment' );
|
|||
|
||||
/* Tests */
|
||||
|
||||
test( 'constructor', 88, function() {
|
||||
test( 'constructor', 114, function() {
|
||||
var fragment = new ve.dm.DocumentFragment( ve.dm.example.data );
|
||||
// Test count: ( ( 4 tests x 16 branch nodes ) + ( 3 tests x 8 leaf nodes ) ) = 88
|
||||
// Test count: ( ( 4 tests x 21 branch nodes ) + ( 3 tests x 10 leaf nodes ) ) = 114
|
||||
ve.dm.example.nodeTreeEqual( fragment.getDocumentNode(), ve.dm.example.tree );
|
||||
} );
|
||||
|
||||
|
@ -13,7 +13,7 @@ test( 'getData', 1, function() {
|
|||
deepEqual( fragment.getData(), ve.dm.example.data );
|
||||
} );
|
||||
|
||||
test( 'getOffsetMap', 43, function() {
|
||||
test( 'getOffsetMap', 55, function() {
|
||||
var fragment = new ve.dm.DocumentFragment( ve.dm.example.data ),
|
||||
actual = fragment.getOffsetMap(),
|
||||
expected = ve.dm.example.getOffsetMap( fragment.getDocumentNode() );
|
||||
|
|
|
@ -31,7 +31,15 @@ ve.dm.example.html =
|
|||
'</td>' +
|
||||
'</tr>' +
|
||||
'</table>' +
|
||||
'<pre>h<img src="image.png">i</pre>';
|
||||
'<pre>h<img src="image.png">i</pre>'+
|
||||
'<dl>' +
|
||||
'<dt>' +
|
||||
'<p>j</p>' +
|
||||
'</dt>' +
|
||||
'<dd>' +
|
||||
'<p>k</p>' +
|
||||
'</dd>' +
|
||||
'</dl>';
|
||||
|
||||
/*
|
||||
* Linear data.
|
||||
|
@ -133,7 +141,31 @@ ve.dm.example.data = [
|
|||
// 39 - Plain "i"
|
||||
'i',
|
||||
// 40 - End of preformatted
|
||||
{ 'type': '/preformatted' }
|
||||
{ 'type': '/preformatted' },
|
||||
// 41 - Beginning of definition list
|
||||
{ 'type': 'definitionList' },
|
||||
// 42 - Beginning of definition list term item
|
||||
{ 'type': 'definitionListItem', 'attributes': { 'style': 'term' } },
|
||||
// 43 - Beginning of paragraph
|
||||
{ 'type': 'paragraph' },
|
||||
// 44 - Plain "j"
|
||||
'j',
|
||||
// 45 - End of paragraph
|
||||
{ 'type': '/paragraph' },
|
||||
// 46 - End of definition list term item
|
||||
{ 'type': '/definitionListItem' },
|
||||
// 47 - Beginning of definition list definition item
|
||||
{ 'type': 'definitionListItem', 'attributes': { 'style': 'definition' } },
|
||||
// 48 - Beginning of paragraph
|
||||
{ 'type': 'paragraph' },
|
||||
// 49 - Plain "j"
|
||||
'j',
|
||||
// 50 - End of paragraph
|
||||
{ 'type': '/paragraph' },
|
||||
// 51 - End of definition list definition item
|
||||
{ 'type': '/definitionListItem' },
|
||||
// 52 - End of definition list
|
||||
{ 'type': '/definitionList' }
|
||||
];
|
||||
|
||||
/**
|
||||
|
@ -141,18 +173,20 @@ ve.dm.example.data = [
|
|||
*
|
||||
* This is part of what a ve.dm.DocumentFragment generates when given linear data.
|
||||
*
|
||||
* (16) branch nodes
|
||||
* (21) branch nodes
|
||||
* (01) document node
|
||||
* (01) heading node
|
||||
* (01) table node
|
||||
* (01) tableRow node
|
||||
* (01) tableCell node
|
||||
* (04) paragraph nodes
|
||||
* (06) paragraph nodes
|
||||
* (03) list nodes
|
||||
* (03) listItem nodes
|
||||
* (01) preformatted node
|
||||
* (08) leaf nodes
|
||||
* (07) text nodes
|
||||
* (01) definitionList node
|
||||
* (02) definitionListItem nodes
|
||||
* (10) leaf nodes
|
||||
* (09) text nodes
|
||||
* (01) image node
|
||||
*/
|
||||
ve.dm.example.tree = new ve.dm.DocumentNode( [
|
||||
|
@ -171,15 +205,15 @@ ve.dm.example.tree = new ve.dm.DocumentNode( [
|
|||
// 2nd level bullet list item with "f"
|
||||
new ve.dm.ListItemNode( [
|
||||
new ve.dm.ParagraphNode( [new ve.dm.TextNode( 1 )] )
|
||||
], ve.dm.example.data[17].attributes )
|
||||
] )
|
||||
], ve.dm.example.data[16].attributes )
|
||||
], ve.dm.example.data[12].attributes )
|
||||
] )
|
||||
], ve.dm.example.data[11].attributes ),
|
||||
new ve.dm.ListNode( [
|
||||
// Numbered list item with "g"
|
||||
new ve.dm.ListItemNode( [
|
||||
new ve.dm.ParagraphNode( [new ve.dm.TextNode( 1 )] )
|
||||
], ve.dm.example.data[26].attributes )
|
||||
] )
|
||||
], ve.dm.example.data[25].attributes )
|
||||
] )
|
||||
] )
|
||||
|
@ -189,6 +223,16 @@ ve.dm.example.tree = new ve.dm.DocumentNode( [
|
|||
new ve.dm.TextNode( 1 ),
|
||||
new ve.dm.ImageNode( [], ve.dm.example.data[37].attributes ),
|
||||
new ve.dm.TextNode( 1 )
|
||||
] ),
|
||||
new ve.dm.DefinitionListNode( [
|
||||
// Definition list term item with "j"
|
||||
new ve.dm.DefinitionListItemNode( [
|
||||
new ve.dm.ParagraphNode( [new ve.dm.TextNode( 1 )] )
|
||||
], ve.dm.example.data[42].attributes ),
|
||||
// Definition list definition item with "k"
|
||||
new ve.dm.DefinitionListItemNode( [
|
||||
new ve.dm.ParagraphNode( [new ve.dm.TextNode( 1 )] )
|
||||
], ve.dm.example.data[47].attributes )
|
||||
] )
|
||||
] );
|
||||
|
||||
|
@ -323,6 +367,30 @@ ve.dm.example.getOffsetMap = function( root ) {
|
|||
// i
|
||||
lookup( 2 ), // 40 - preformatted
|
||||
// </pre>
|
||||
lookup() // 41 - document
|
||||
lookup(), // 41 - document
|
||||
// <dl>
|
||||
lookup( 3 ), // 42 - definitionList
|
||||
// <dt>
|
||||
lookup( 3, 0 ), // 43 - definitionListItem
|
||||
// <p>
|
||||
lookup( 3, 0, 0 ), // 44 - paragraph
|
||||
// f
|
||||
lookup( 3, 0, 0 ), // 45 - paragraph
|
||||
// </p>
|
||||
lookup( 3, 0 ), // 46 - definitionListItem
|
||||
// </dt>
|
||||
lookup( 3 ), // 47 - definitionList
|
||||
// <dd>
|
||||
lookup( 3, 1 ), // 48 - definitionListItem
|
||||
// <p>
|
||||
lookup( 3, 1, 0 ), // 49 - paragraph
|
||||
// f
|
||||
lookup( 3, 1, 0 ), // 50 - paragraph
|
||||
// </p>
|
||||
lookup( 3, 1 ), // 51 - definitionListItem
|
||||
// </dd>
|
||||
lookup( 3 ), // 52 - definitionList
|
||||
// </dl>
|
||||
lookup() // 53 - document
|
||||
];
|
||||
};
|
||||
|
|
|
@ -41,6 +41,8 @@
|
|||
|
||||
<!-- VisualEditor DataModel Nodes -->
|
||||
<script src="../../modules/ve2/dm/nodes/ve.dm.AlienNode.js"></script>
|
||||
<script src="../../modules/ve2/dm/nodes/ve.dm.DefinitionListNode.js"></script>
|
||||
<script src="../../modules/ve2/dm/nodes/ve.dm.DefinitionListItemNode.js"></script>
|
||||
<script src="../../modules/ve2/dm/nodes/ve.dm.DocumentNode.js"></script>
|
||||
<script src="../../modules/ve2/dm/nodes/ve.dm.HeadingNode.js"></script>
|
||||
<script src="../../modules/ve2/dm/nodes/ve.dm.ImageNode.js"></script>
|
||||
|
@ -62,6 +64,8 @@
|
|||
|
||||
<!-- VisualEditor ContentEditable Nodes -->
|
||||
<script src="../../modules/ve2/ce/nodes/ve.ce.AlienNode.js"></script>
|
||||
<script src="../../modules/ve2/ce/nodes/ve.ce.DefinitionListNode.js"></script>
|
||||
<script src="../../modules/ve2/ce/nodes/ve.ce.DefinitionListItemNode.js"></script>
|
||||
<script src="../../modules/ve2/ce/nodes/ve.ce.DocumentNode.js"></script>
|
||||
<script src="../../modules/ve2/ce/nodes/ve.ce.HeadingNode.js"></script>
|
||||
<script src="../../modules/ve2/ce/nodes/ve.ce.ImageNode.js"></script>
|
||||
|
|
Loading…
Reference in a new issue