2012-04-27 21:59:52 +00:00
|
|
|
module( 've.dm.Document' );
|
|
|
|
|
|
|
|
/* Tests */
|
|
|
|
|
2012-04-30 20:48:20 +00:00
|
|
|
test( 'getOuterLength', 1, function() {
|
2012-05-09 22:30:18 +00:00
|
|
|
var doc = new ve.dm.Document( ve.dm.example.data );
|
2012-04-30 20:48:20 +00:00
|
|
|
strictEqual(
|
2012-05-09 22:30:18 +00:00
|
|
|
doc.getDocumentNode().getOuterLength(),
|
2012-04-30 20:48:20 +00:00
|
|
|
ve.dm.example.data.length,
|
|
|
|
'document does not have elements around it'
|
|
|
|
);
|
|
|
|
} );
|
|
|
|
|
2012-05-11 00:20:57 +00:00
|
|
|
test( 'isContentOffset', function() {
|
|
|
|
var data = [
|
|
|
|
{ 'type': 'heading' },
|
|
|
|
'a',
|
|
|
|
{ 'type': 'image' },
|
|
|
|
{ 'type': '/image' },
|
|
|
|
'b',
|
|
|
|
'c',
|
|
|
|
{ 'type': '/heading' },
|
|
|
|
{ 'type': 'paragraph' },
|
|
|
|
{ 'type': '/paragraph' },
|
|
|
|
{ 'type': 'preformatted' },
|
|
|
|
{ 'type': 'image' },
|
|
|
|
{ 'type': '/image' },
|
|
|
|
{ 'type': '/preformatted' },
|
|
|
|
{ 'type': 'list' },
|
|
|
|
{ 'type': 'listItem' },
|
|
|
|
{ 'type': '/listItem' },
|
|
|
|
{ 'type': '/list' }
|
|
|
|
],
|
|
|
|
cases = [
|
|
|
|
{ 'msg': 'left of document', 'expected': false },
|
|
|
|
{ 'msg': 'begining of content branch', 'expected': true },
|
|
|
|
{ 'msg': 'left of non-text leaf', 'expected': true },
|
|
|
|
{ 'msg': 'inside non-text leaf', 'expected': false },
|
|
|
|
{ 'msg': 'right of non-text leaf', 'expected': true },
|
|
|
|
{ 'msg': 'between characters', 'expected': true },
|
|
|
|
{ 'msg': 'end of content branch', 'expected': true },
|
|
|
|
{ 'msg': 'between content branches', 'expected': false },
|
|
|
|
{ 'msg': 'inside emtpy content branch', 'expected': true },
|
|
|
|
{ 'msg': 'between content branches', 'expected': false },
|
|
|
|
{ 'msg': 'begining of content branch and left of a leaf', 'expected': true },
|
|
|
|
{ 'msg': 'inside content branch with only one non-text leaf', 'expected': false },
|
|
|
|
{ 'msg': 'end of content branch and right of a leaf', 'expected': true },
|
|
|
|
{ 'msg': 'between content and non-content branches', 'expected': false },
|
|
|
|
{ 'msg': 'between parent and child branches, descending', 'expected': false },
|
|
|
|
{ 'msg': 'inside empty non-content branch', 'expected': false },
|
|
|
|
{ 'msg': 'between parent and child branches, ascending', 'expected': false },
|
|
|
|
{ 'msg': 'right of document', 'expected': false }
|
|
|
|
];
|
|
|
|
expect( data.length + 1 );
|
|
|
|
for ( var i = 0; i < cases.length; i++ ) {
|
|
|
|
strictEqual( ve.dm.Document.isContentOffset( data, i ), cases[i].expected, cases[i].msg );
|
|
|
|
}
|
|
|
|
} );
|
|
|
|
|
|
|
|
test( 'isStructuralOffset', function() {
|
|
|
|
var data = [
|
|
|
|
{ 'type': 'heading' },
|
|
|
|
'a',
|
|
|
|
{ 'type': 'image' },
|
|
|
|
{ 'type': '/image' },
|
|
|
|
'b',
|
|
|
|
'c',
|
|
|
|
{ 'type': '/heading' },
|
|
|
|
{ 'type': 'paragraph' },
|
|
|
|
{ 'type': '/paragraph' },
|
|
|
|
{ 'type': 'preformatted' },
|
|
|
|
{ 'type': 'image' },
|
|
|
|
{ 'type': '/image' },
|
|
|
|
{ 'type': '/preformatted' },
|
|
|
|
{ 'type': 'list' },
|
|
|
|
{ 'type': 'listItem' },
|
|
|
|
{ 'type': '/listItem' },
|
|
|
|
{ 'type': '/list' }
|
|
|
|
],
|
|
|
|
cases = [
|
|
|
|
{ 'msg': 'left of document', 'expected': true },
|
|
|
|
{ 'msg': 'begining of content branch', 'expected': false },
|
|
|
|
{ 'msg': 'left of non-text leaf', 'expected': false },
|
|
|
|
{ 'msg': 'inside non-text leaf', 'expected': false },
|
|
|
|
{ 'msg': 'right of non-text leaf', 'expected': false },
|
|
|
|
{ 'msg': 'between characters', 'expected': false },
|
|
|
|
{ 'msg': 'end of content branch', 'expected': false },
|
|
|
|
{ 'msg': 'between content branches', 'expected': true },
|
|
|
|
{ 'msg': 'inside emtpy content branch', 'expected': false },
|
|
|
|
{ 'msg': 'between content branches', 'expected': true },
|
|
|
|
{ 'msg': 'begining of content branch and left of a leaf', 'expected': false },
|
|
|
|
{ 'msg': 'inside content branch with only one non-text leaf', 'expected': false },
|
|
|
|
{ 'msg': 'end of content branch and right of a leaf', 'expected': false },
|
|
|
|
{ 'msg': 'between content and non-content branches', 'expected': true },
|
|
|
|
{ 'msg': 'between parent and child branches, descending', 'expected': true },
|
|
|
|
{ 'msg': 'inside empty non-content branch', 'expected': true },
|
|
|
|
{ 'msg': 'between parent and child branches, ascending', 'expected': true },
|
|
|
|
{ 'msg': 'right of document', 'expected': true }
|
|
|
|
];
|
|
|
|
expect( data.length + 1 );
|
|
|
|
for ( var i = 0; i < cases.length; i++ ) {
|
|
|
|
strictEqual( ve.dm.Document.isStructuralOffset( data, i ), cases[i].expected, cases[i].msg );
|
|
|
|
}
|
|
|
|
} );
|
|
|
|
|
|
|
|
test( 'isElementData', 1, function() {
|
|
|
|
var data = [
|
|
|
|
{ 'type': 'heading' },
|
|
|
|
'a',
|
|
|
|
{ 'type': 'image' },
|
|
|
|
{ 'type': '/image' },
|
|
|
|
'b',
|
|
|
|
'c',
|
|
|
|
{ 'type': '/heading' },
|
|
|
|
{ 'type': 'paragraph' },
|
|
|
|
{ 'type': '/paragraph' },
|
|
|
|
{ 'type': 'preformatted' },
|
|
|
|
{ 'type': 'image' },
|
|
|
|
{ 'type': '/image' },
|
|
|
|
{ 'type': '/preformatted' },
|
|
|
|
{ 'type': 'list' },
|
|
|
|
{ 'type': 'listItem' },
|
|
|
|
{ 'type': '/listItem' },
|
|
|
|
{ 'type': '/list' }
|
|
|
|
],
|
|
|
|
cases = [
|
|
|
|
{ 'msg': 'left of document', 'expected': true },
|
|
|
|
{ 'msg': 'begining of content branch', 'expected': false },
|
|
|
|
{ 'msg': 'left of non-text leaf', 'expected': true },
|
|
|
|
{ 'msg': 'inside non-text leaf', 'expected': true },
|
|
|
|
{ 'msg': 'right of non-text leaf', 'expected': false },
|
|
|
|
{ 'msg': 'between characters', 'expected': false },
|
|
|
|
{ 'msg': 'end of content branch', 'expected': true },
|
|
|
|
{ 'msg': 'between content branches', 'expected': true },
|
|
|
|
{ 'msg': 'inside emtpy content branch', 'expected': true },
|
|
|
|
{ 'msg': 'between content branches', 'expected': true },
|
|
|
|
{ 'msg': 'begining of content branch and left of a leaf', 'expected': true },
|
|
|
|
{ 'msg': 'inside content branch with only one non-text leaf', 'expected': true },
|
|
|
|
{ 'msg': 'end of content branch and right of a leaf', 'expected': true },
|
|
|
|
{ 'msg': 'between content and non-content branches', 'expected': true },
|
|
|
|
{ 'msg': 'between parent and child branches, descending', 'expected': true },
|
|
|
|
{ 'msg': 'inside empty non-content branch', 'expected': true },
|
|
|
|
{ 'msg': 'between parent and child branches, ascending', 'expected': true },
|
|
|
|
{ 'msg': 'right of document', 'expected': false }
|
|
|
|
];
|
|
|
|
expect( data.length + 1 );
|
|
|
|
for ( var i = 0; i < cases.length; i++ ) {
|
|
|
|
strictEqual( ve.dm.Document.isElementData( data, i ), cases[i].expected, cases[i].msg );
|
|
|
|
}
|
|
|
|
} );
|
|
|
|
|
|
|
|
test( 'containsElementData', 1, function() {
|
|
|
|
var cases = [
|
|
|
|
{
|
|
|
|
'msg': 'simple paragraph',
|
|
|
|
'data': [{ 'type': 'paragraph' }, 'a', { 'type': '/paragraph' }],
|
|
|
|
'expected': true
|
|
|
|
},
|
|
|
|
{
|
|
|
|
'msg': 'plain text',
|
|
|
|
'data': ['a', 'b', 'c'],
|
|
|
|
'expected': false
|
|
|
|
},
|
|
|
|
{
|
|
|
|
'msg': 'annotated text',
|
|
|
|
'data': [['a', { '{"type:"bold"}': { 'type': 'bold' } } ]],
|
|
|
|
'expected': false
|
|
|
|
},
|
|
|
|
{
|
|
|
|
'msg': 'non-text leaf',
|
|
|
|
'data': ['a', { 'type': 'image' }, { 'type': '/image' }, 'c'],
|
|
|
|
'expected': true
|
|
|
|
}
|
|
|
|
];
|
|
|
|
expect( cases.length );
|
|
|
|
for ( var i = 0; i < cases.length; i++ ) {
|
|
|
|
strictEqual(
|
|
|
|
ve.dm.Document.containsElementData( cases[i].data ), cases[i].expected, cases[i].msg
|
|
|
|
);
|
|
|
|
}
|
|
|
|
} );
|
|
|
|
|
2012-05-11 23:03:22 +00:00
|
|
|
test( 'getScope', function() {
|
|
|
|
var doc = new ve.dm.Document( ve.dm.example.data.slice( 0 ) );
|
|
|
|
var documentNode = doc.getDocumentNode();
|
|
|
|
var lookup = ve.example.lookupNode;
|
|
|
|
var cases = [
|
|
|
|
{
|
|
|
|
'msg': 'enclosed paragraph in a listItem',
|
|
|
|
// table/tableRow/tableCell/list/listItem
|
|
|
|
'node': lookup( documentNode, 1, 0, 0, 1, 0 ),
|
|
|
|
'data': [ { 'type': 'paragraph' }, 'A', { 'type': '/paragraph' } ],
|
|
|
|
// Same node
|
|
|
|
'expected': lookup( documentNode, 1, 0, 0, 1, 0 )
|
|
|
|
},
|
|
|
|
{
|
|
|
|
'msg': 'enclosed list in the document',
|
|
|
|
'node': documentNode,
|
|
|
|
'data': [
|
|
|
|
{ 'type': 'list', 'attributes': { 'style': 'bullet' } },
|
|
|
|
{ 'type': 'listItem' },
|
|
|
|
{ 'type': 'paragraph' },
|
|
|
|
'A',
|
|
|
|
{ 'type': '/paragraph' },
|
|
|
|
{ 'type': 'paragraph' },
|
|
|
|
'B',
|
|
|
|
{ 'type': '/paragraph' },
|
|
|
|
{ 'type': '/listItem' },
|
|
|
|
{ 'type': 'listItem' },
|
|
|
|
{ 'type': 'paragraph' },
|
|
|
|
'C',
|
|
|
|
{ 'type': 'image', 'attributes': { 'html/src': 'image.png' } },
|
|
|
|
{ 'type': '/image' },
|
|
|
|
'D',
|
|
|
|
{ 'type': '/paragraph' },
|
|
|
|
{ 'type': '/listItem' },
|
|
|
|
{ 'type': '/list' }
|
|
|
|
],
|
|
|
|
// Same node
|
|
|
|
'expected': documentNode
|
|
|
|
},
|
|
|
|
{
|
|
|
|
'msg': 'heading split',
|
|
|
|
// heading
|
|
|
|
'node': lookup( documentNode, 0 ),
|
|
|
|
'data': [
|
|
|
|
{ 'type': '/heading' },
|
|
|
|
{ 'type': 'heading', 'attributes': { 'level': 1 } }
|
|
|
|
],
|
|
|
|
'expected': documentNode
|
|
|
|
},
|
|
|
|
{
|
|
|
|
'msg': 'listItem split, passing textnode',
|
|
|
|
// table/tableRow/tableCell/list/listItem/paragraph/text
|
|
|
|
'node': lookup( documentNode, 1, 0, 0, 1, 0, 0, 0 ),
|
|
|
|
'data': [
|
|
|
|
{ 'type': '/paragraph' },
|
|
|
|
{ 'type': '/listItem' },
|
|
|
|
{ 'type': 'listItem' },
|
|
|
|
{ 'type': 'paragraph' }
|
|
|
|
],
|
|
|
|
// table/tableRow/tableCell/list
|
|
|
|
'expected': lookup( documentNode, 1, 0, 0, 1 )
|
|
|
|
}
|
|
|
|
];
|
|
|
|
|
|
|
|
for ( var i = 0; i < cases.length; i++ ) {
|
|
|
|
ok( ve.dm.Document.getScope( cases[i].node, cases[i].data ) === cases[i].expected,
|
|
|
|
cases[i].msg
|
|
|
|
);
|
|
|
|
}
|
|
|
|
} );
|
|
|
|
|
2012-05-07 23:25:39 +00:00
|
|
|
test( 'rebuildNodes', function() {
|
2012-05-08 00:03:14 +00:00
|
|
|
var doc = new ve.dm.Document( ve.dm.example.data.slice( 0 ) ),
|
2012-04-30 20:42:32 +00:00
|
|
|
documentNode = doc.getDocumentNode();
|
2012-05-07 23:18:24 +00:00
|
|
|
// Rebuild without changes
|
2012-04-30 20:42:32 +00:00
|
|
|
doc.rebuildNodes( documentNode, 1, 1, 5, 30 );
|
2012-05-15 05:36:06 +00:00
|
|
|
ve.example.nodeTreeEqual( documentNode, ve.dm.example.tree, 'rebuild without changes' );
|
2012-05-07 23:25:39 +00:00
|
|
|
|
2012-05-09 22:28:06 +00:00
|
|
|
// XXX: Create a new document node tree from the old one
|
2012-05-07 23:25:39 +00:00
|
|
|
var tree = new ve.dm.DocumentNode( ve.dm.example.tree.getChildren() );
|
2012-05-10 01:31:09 +00:00
|
|
|
// Replace table with paragraph
|
2012-05-07 23:25:39 +00:00
|
|
|
doc.data.splice( 5, 30, { 'type': 'paragraph' }, 'a', 'b', 'c', { 'type': '/paragraph' } );
|
|
|
|
// Remove table from tree model
|
|
|
|
tree.splice( 1, 1, new ve.dm.ParagraphNode( [new ve.dm.TextNode( 3 )] ) );
|
|
|
|
// Rebuild with changes
|
|
|
|
doc.rebuildNodes( documentNode, 1, 1, 5, 5 );
|
2012-05-15 05:36:06 +00:00
|
|
|
ve.example.nodeTreeEqual( documentNode, tree, 'replace table with paragraph' );
|
2012-04-27 21:59:52 +00:00
|
|
|
} );
|
2012-05-07 22:14:37 +00:00
|
|
|
|
2012-05-11 00:20:57 +00:00
|
|
|
test( 'getRelativeContentOffset', 1, function() {
|
2012-05-11 19:14:29 +00:00
|
|
|
var doc = new ve.dm.Document( ve.dm.example.data );
|
|
|
|
var cases = [
|
|
|
|
{
|
|
|
|
'msg': 'first content offset is farthest left',
|
|
|
|
'offset': 2,
|
|
|
|
'distance': -2,
|
|
|
|
'expected': 1
|
|
|
|
},
|
|
|
|
{
|
|
|
|
'msg': 'last content offset is farthest right',
|
|
|
|
'offset': 49,
|
|
|
|
'distance': 2,
|
|
|
|
'expected': 50
|
|
|
|
},
|
|
|
|
{
|
|
|
|
'msg': '1 right within text',
|
|
|
|
'offset': 1,
|
|
|
|
'distance': 1,
|
|
|
|
'expected': 2
|
|
|
|
},
|
|
|
|
{
|
|
|
|
'msg': '2 right within text',
|
|
|
|
'offset': 1,
|
|
|
|
'distance': 2,
|
|
|
|
'expected': 3
|
|
|
|
},
|
|
|
|
{
|
|
|
|
'msg': '1 left within text',
|
|
|
|
'offset': 2,
|
|
|
|
'distance': -1,
|
|
|
|
'expected': 1
|
|
|
|
},
|
|
|
|
{
|
|
|
|
'msg': '2 left within text',
|
|
|
|
'offset': 3,
|
|
|
|
'distance': -2,
|
|
|
|
'expected': 1
|
|
|
|
},
|
|
|
|
{
|
|
|
|
'msg': '1 right over elements',
|
|
|
|
'offset': 4,
|
|
|
|
'distance': 1,
|
|
|
|
'expected': 9
|
|
|
|
},
|
|
|
|
{
|
|
|
|
'msg': '2 right over elements',
|
|
|
|
'offset': 4,
|
|
|
|
'distance': 2,
|
|
|
|
'expected': 10
|
|
|
|
},
|
|
|
|
{
|
|
|
|
'msg': '1 left over elements',
|
|
|
|
'offset': 9,
|
|
|
|
'distance': -1,
|
|
|
|
'expected': 4
|
|
|
|
},
|
|
|
|
{
|
|
|
|
'msg': '2 left over elements',
|
|
|
|
'offset': 9,
|
|
|
|
'distance': -2,
|
|
|
|
'expected': 3
|
|
|
|
}
|
|
|
|
];
|
|
|
|
expect( cases.length );
|
|
|
|
for ( var i = 0; i < cases.length; i++ ) {
|
|
|
|
strictEqual(
|
|
|
|
doc.getRelativeContentOffset( cases[i].offset, cases[i].distance ),
|
|
|
|
cases[i].expected,
|
|
|
|
cases[i].msg
|
|
|
|
);
|
|
|
|
}
|
2012-05-11 00:20:57 +00:00
|
|
|
} );
|
|
|
|
|
2012-05-09 22:28:06 +00:00
|
|
|
test( 'selectNodes', function() {
|
2012-05-07 22:14:37 +00:00
|
|
|
var doc = new ve.dm.Document( ve.dm.example.data ),
|
2012-05-10 04:11:09 +00:00
|
|
|
cases = ve.example.getSelectNodesCases( doc );
|
2012-05-09 22:28:06 +00:00
|
|
|
for ( var i = 0; i < cases.length; i++ ) {
|
2012-05-15 05:54:53 +00:00
|
|
|
ve.example.nodeSelectionEqual( cases[i].actual, cases[i].expected, cases[i].msg );
|
2012-05-09 22:28:06 +00:00
|
|
|
}
|
2012-05-07 22:14:37 +00:00
|
|
|
} );
|