From 5b9a2645a6180223cc88d24df6076f74244b1e09 Mon Sep 17 00:00:00 2001 From: Catrope Date: Fri, 11 May 2012 16:03:22 -0700 Subject: [PATCH] Port getScope() from the old VE code and add tests for it Change-Id: I8c34fed919e60fa1b8cb6a13cb9ca98f3e695421 --- modules/ve2/dm/ve.dm.Document.js | 33 ++++++++++++++ tests/ve2/dm/ve.dm.Document.test.js | 71 +++++++++++++++++++++++++++++ 2 files changed, 104 insertions(+) diff --git a/modules/ve2/dm/ve.dm.Document.js b/modules/ve2/dm/ve.dm.Document.js index d5df11a48c..96b250534c 100644 --- a/modules/ve2/dm/ve.dm.Document.js +++ b/modules/ve2/dm/ve.dm.Document.js @@ -186,6 +186,39 @@ ve.dm.Document.containsElementData = function( data ) { return false; }; +/** + * Get the parent node that would be affected by inserting given data into its child. + * + * This is used when inserting data that closes and reopens one or more parent nodes into a + * child node, which requires rebuilding at a higher level. + * + * @param {ve.Node} node Child node to start from + * @param {Array} data Data to inspect for closings + * @returns {ve.Node} Lowest level parent node being affected + */ +ve.dm.Document.getScope = function( node, data ) { + debugger; + var i, + length, + level = 0, + max = 0; + for ( i = 0, length = data.length; i < length; i++ ) { + if ( data[i].type ) { + level += data[i].type.charAt( 0 ) === '/' ? 1 : -1; + max = level > max ? level : max; + } + } + for ( i = 0; i < max; i++ ) { + // Skip over unwrapped parents, they're not counted in the level count + while ( !node.isWrapped() && node.getParent() ) { + node = node.getParent(); + } + // Go up one level + node = node.getParent() || node; + } + return node; +}; + /* Methods */ /** diff --git a/tests/ve2/dm/ve.dm.Document.test.js b/tests/ve2/dm/ve.dm.Document.test.js index 16cf5fa793..938f9bdaa8 100644 --- a/tests/ve2/dm/ve.dm.Document.test.js +++ b/tests/ve2/dm/ve.dm.Document.test.js @@ -180,6 +180,77 @@ test( 'containsElementData', 1, function() { } } ); +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 + ); + } +} ); + test( 'rebuildNodes', function() { var doc = new ve.dm.Document( ve.dm.example.data.slice( 0 ) ), documentNode = doc.getDocumentNode();