Esanders has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/61048


Change subject: Allow fixUpInsertion to move offsets when inserting at start/end
......................................................................

Allow fixUpInsertion to move offsets when inserting at start/end

First commit, probably needs some more test cases.

Change-Id: Ic51dd03725c11f1f7e279929534ee3afea14d662
---
M modules/ve/dm/ve.dm.Document.js
M modules/ve/dm/ve.dm.Transaction.js
M modules/ve/test/dm/ve.dm.Transaction.test.js
3 files changed, 82 insertions(+), 29 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/VisualEditor 
refs/changes/48/61048/1

diff --git a/modules/ve/dm/ve.dm.Document.js b/modules/ve/dm/ve.dm.Document.js
index 1136c9d..8f2ceb5 100644
--- a/modules/ve/dm/ve.dm.Document.js
+++ b/modules/ve/dm/ve.dm.Document.js
@@ -487,6 +487,9 @@
                // and popped off when balanced out by an opening in data
                closingStack = [],
 
+               firstChildStack = [],
+               lastChildStack = [],
+
                // *** State persisting across iterations of the outer loop ***
                // The node (from the document) we're currently in. When in a 
node that was opened
                // in data, this is set to its first ancestor that is already 
in the document
@@ -602,6 +605,16 @@
        parentNode = this.getNodeFromOffset( offset );
        parentType = parentNode.getType();
        inTextNode = false;
+
+       i = offset;
+       while( this.data.isOpenElementData( --i ) ) {
+               firstChildStack.push( this.data.getData( i ) );
+       }
+       i = offset - 1;
+       while( this.data.isCloseElementData( ++i ) ) {
+               lastChildStack.push( this.data.getData( i ) );
+       }
+
        for ( i = 0; i < data.length; i++ ) {
                if ( inTextNode && data[i].type !== undefined ) {
                        parentType = openingStack.length > 0 ?
@@ -657,6 +670,10 @@
                                );
                                if ( !childrenOK ) {
                                        // We can't insert this into this parent
+                                       if ( firstChildStack.length ) {
+                                               return this.fixupInsertion( 
data, offset - 1 );
+                                       }
+
                                        // Close the parent and try one level up
                                        closings.push( { 'type': '/' + 
parentType } );
                                        if ( openingStack.length > 0 ) {
@@ -711,6 +728,10 @@
                }
        }
 
+       if ( closingStack.length > 0 && lastChildStack.length > 0 ) {
+               return this.fixupInsertion( data, offset + 1 );
+       }
+
        if ( inTextNode ) {
                parentType = openingStack.length > 0 ?
                        openingStack[openingStack.length - 1].type : 
parentNode.getType();
@@ -731,7 +752,10 @@
                writeElement( popped.getClonedElement(), i );
        }
 
-       return newData;
+       return {
+               offset: offset,
+               data: newData
+       };
 };
 
 /**
diff --git a/modules/ve/dm/ve.dm.Transaction.js 
b/modules/ve/dm/ve.dm.Transaction.js
index b2a9a7d..d8ce506 100644
--- a/modules/ve/dm/ve.dm.Transaction.js
+++ b/modules/ve/dm/ve.dm.Transaction.js
@@ -36,11 +36,11 @@
        // Fix up the insertion
        insertion = doc.fixupInsertion( insertion, offset );
        // Retain up to insertion point, if needed
-       tx.pushRetain( offset );
+       tx.pushRetain( insertion.offset );
        // Insert data
-       tx.pushReplace( doc, offset, 0, insertion );
+       tx.pushReplace( doc, offset, 0, insertion.data );
        // Retain to end of document, if needed (for completeness)
-       tx.pushRetain( data.length - offset );
+       tx.pushRetain( data.length - insertion.offset );
        return tx;
 };
 
diff --git a/modules/ve/test/dm/ve.dm.Transaction.test.js 
b/modules/ve/test/dm/ve.dm.Transaction.test.js
index 82769f4..8147e36 100644
--- a/modules/ve/test/dm/ve.dm.Transaction.test.js
+++ b/modules/ve/test/dm/ve.dm.Transaction.test.js
@@ -48,6 +48,9 @@
                doc2 = new ve.dm.Document(
                        ve.dm.example.preprocessAnnotations( [ { 'type': 
'paragraph' }, { 'type': '/paragraph' } ] )
                ),
+               doc3 = new ve.dm.Document(
+                       ve.dm.example.preprocessAnnotations( [ { 'type': 
'paragraph' }, 'F', 'o', 'o', { 'type': '/paragraph' } ] )
+               ),
                cases = {
                        'paragraph before first element': {
                                'args': [doc, 0, [{ 'type': 'paragraph' }, '1', 
{ 'type': '/paragraph' }]],
@@ -95,16 +98,16 @@
                                        { 'type': 'retain', 'length': 59 }
                                ]
                        },
-                       'paragraph inside a list closes and reopens list': {
+                       'paragraph inside a list moves in front of list': {
                                'args': [doc, 13, [{ 'type': 'paragraph' }, 
'F', 'O', 'O', { 'type': '/paragraph' }]],
                                'ops': [
-                                       { 'type': 'retain', 'length': 13 },
+                                       { 'type': 'retain', 'length': 12 },
                                        {
                                                'type': 'replace',
                                                'remove': [],
-                                               'insert': [{'type': '/list' }, 
{ 'type': 'paragraph' } , 'F', 'O', 'O', { 'type': '/paragraph' }, { 'type': 
'list', 'attributes': { 'style': 'bullet' } }]
+                                               'insert': [{ 'type': 
'paragraph' } , 'F', 'O', 'O', { 'type': '/paragraph' }]
                                        },
-                                       { 'type': 'retain', 'length': 48 }
+                                       { 'type': 'retain', 'length': 49 }
                                ]
                        },
                        'tableCell inside the document is wrapped in a table, 
tableSection and tableRow': {
@@ -119,16 +122,16 @@
                                        { 'type': 'retain', 'length': 18 }
                                ]
                        },
-                       'tableCell inside a paragraph is wrapped in a table, 
tableSection and tableRow and closes and reopens the paragraph': {
+                       'tableCell inside a paragraph is wrapped in a table, 
tableSection and tableRow and moves outside of paragraph': {
                                'args': [doc, 52, [{ 'type': 'tableCell', 
'attributes': { 'style': 'data' } }, { 'type': 'paragraph' }, 'F', 'O', 'O', { 
'type': '/paragraph' }, { 'type': '/tableCell' }]],
                                'ops': [
-                                       { 'type': 'retain', 'length': 52 },
+                                       { 'type': 'retain', 'length': 53 },
                                        {
                                                'type': 'replace',
                                                'remove': [],
-                                               'insert': [{ 'type': 
'/paragraph' }, { 'type': 'table' }, { 'type': 'tableSection', 'attributes': { 
'style': 'body' } }, { 'type': 'tableRow' }, { 'type': 'tableCell', 
'attributes': { 'style': 'data' } }, { 'type': 'paragraph' }, 'F', 'O', 'O', { 
'type': '/paragraph' }, { 'type': '/tableCell' }, { 'type': '/tableRow' }, { 
'type': '/tableSection' }, { 'type': '/table' }, { 'type': 'paragraph' }]
+                                               'insert': [{ 'type': 'table' }, 
{ 'type': 'tableSection', 'attributes': { 'style': 'body' } }, { 'type': 
'tableRow' }, { 'type': 'tableCell', 'attributes': { 'style': 'data' } }, { 
'type': 'paragraph' }, 'F', 'O', 'O', { 'type': '/paragraph' }, { 'type': 
'/tableCell' }, { 'type': '/tableRow' }, { 'type': '/tableSection' }, { 'type': 
'/table' }]
                                        },
-                                       { 'type': 'retain', 'length': 9 }
+                                       { 'type': 'retain', 'length': 8 }
                                ]
                        },
                        'text at a structural location in the document is 
wrapped in a paragraph': {
@@ -166,52 +169,56 @@
                                        { 'type': 'retain', 'length': 59 }
                                ]
                        },
-                       'text inside a tableSection is wrapped in a paragraph 
and closes and reopens the tableSection, tableRow and table': {
+                       'text inside a tableSection moves all the way to the 
end of the table and is wrapped in a paragraph': {
                                'args': [doc, 34, ['F', 'O', 'O']],
                                'ops': [
-                                       { 'type': 'retain', 'length': 34 },
+                                       { 'type': 'retain', 'length': 37 },
                                        {
                                                'type': 'replace',
                                                'remove': [],
-                                               'insert': [{ 'type': 
'/tableRow' }, { 'type': '/tableSection' }, { 'type': '/table' }, { 'type': 
'paragraph' }, 'F', 'O', 'O', { 'type': '/paragraph' }, { 'type': 'table' }, { 
'type': 'tableSection', 'attributes': { 'style': 'body' } }, { 'type': 
'tableRow' } ]
+                                               'insert': [{ 'type': 
'paragraph' }, 'F', 'O', 'O', { 'type': '/paragraph' }]
                                        },
-                                       { 'type': 'retain', 'length': 27 }
+                                       { 'type': 'retain', 'length': 24 }
                                ]
                        },
-                       'insert two complete paragraphs into a paragraph': {
+                       'insert two complete paragraphs into start of paragraph 
moves insertion point left': {
                                'args': [doc, 10, [{ 'type': 'paragraph' }, 
'F', 'O', 'O', { 'type': '/paragraph' }, { 'type': 'paragraph' }, 'B', 'A', 
'R', { 'type': '/paragraph' }]],
                                'ops': [
-                                       { 'type': 'retain', 'length': 10 },
+                                       { 'type': 'retain', 'length': 9 },
                                        {
                                                'type': 'replace',
                                                'remove': [],
-                                               'insert': [{ 'type': 
'/paragraph' }, { 'type': 'paragraph' }, 'F', 'O', 'O', { 'type': '/paragraph' 
}, { 'type': 'paragraph' }, 'B', 'A', 'R', { 'type': '/paragraph' }, { 'type': 
'paragraph' }]
+                                               'insert': [{ 'type': 
'paragraph' }, 'F', 'O', 'O', { 'type': '/paragraph' }, { 'type': 'paragraph' 
}, 'B', 'A', 'R', { 'type': '/paragraph' }]
                                        },
-                                       { 'type': 'retain', 'length': 51 }
+                                       { 'type': 'retain', 'length': 52 }
                                ]
                        },
-                       'insert text, close paragraph and open heading into 
paragraph': {
+                       'insert text, close paragraph and open heading into end 
of paragraph moves insertion point right': {
                                'args': [doc, 57, ['F', 'O', 'O', { 'type': 
'/paragraph' }, { 'type': 'heading', 'attributes': { 'level': 1 } }, 'B', 'A', 
'R']],
                                'ops': [
-                                       { 'type': 'retain', 'length': 57 },
+                                       { 'type': 'retain', 'length': 58 },
                                        {
                                                'type': 'replace',
                                                'remove': [],
-                                               'insert': ['F', 'O', 'O', { 
'type': '/paragraph' }, { 'type': 'heading', 'attributes': { 'level': 1 } }, 
'B', 'A', 'R', { 'type': '/heading' }, { 'type': 'paragraph' }]
+                                               'insert': [{ 'type': 
'paragraph' }, 'F', 'O', 'O', { 'type': '/paragraph' }, { 'type': 'heading', 
'attributes': { 'level': 1 } }, 'B', 'A', 'R', { 'type': '/heading' }]
                                        },
-                                       { 'type': 'retain', 'length': 4 }
+                                       { 'type': 'retain', 'length': 3 }
                                ]
                        },
-                       'insert paragraph and incomplete heading into 
paragraph': {
-                               'args': [doc, 10, [{ 'type': 'paragraph' }, 
'F', 'O', 'O', { 'type': '/paragraph' }, { 'type': 'heading', 'attributes': { 
'level': 1 } }, 'B', 'A', 'R']],
+                       'insert heading and incomplete paragraph into heading': 
{
+                               'args': [doc, 2, [{ 'type': 'heading', 
'attributes': { 'level': 1 } }, 'F', 'O', 'O', { 'type': '/heading' }, { 
'type': 'paragraph' }, 'B', 'A', 'R']],
                                'ops': [
-                                       { 'type': 'retain', 'length': 10 },
+                                       { 'type': 'retain', 'length': 2 },
                                        {
                                                'type': 'replace',
                                                'remove': [],
-                                               'insert': [{ 'type': 
'/paragraph' }, { 'type': 'paragraph' }, 'F', 'O', 'O', { 'type': '/paragraph' 
}, { 'type': 'heading', 'attributes': { 'level': 1 } }, 'B', 'A', 'R', { 
'type': '/heading' }, { 'type': 'paragraph' }]
+                                               'insert': [
+                                                       { 'type': '/heading' }, 
{ 'type': 'heading', 'attributes': { 'level': 1 } }, 'F', 'O', 'O', { 'type': 
'/heading' },
+                                                       { 'type': 'paragraph' 
}, 'B', 'A', 'R', { 'type': '/paragraph' },
+                                                       { 'type': 'heading', 
'attributes': { 'level': 1 } }
+                                               ]
                                        },
-                                       { 'type': 'retain', 'length': 51 }
+                                       { 'type': 'retain', 'length': 59 }
                                ]
                        },
                        'inserting two paragraphs into a document with just an 
empty paragraph': {
@@ -237,6 +244,28 @@
                                        },
                                        { 'type': 'retain', 'length': 1 }
                                ]
+                       },
+                       'inserting one paragraph into empty paragraph moves 
insertion before': {
+                               'args': [doc2, 1, [{ 'type': 'paragraph' }, 
'F', 'O', 'O', { 'type': '/paragraph' }]],
+                               'ops': [
+                                       {
+                                               'type': 'replace',
+                                               'remove': [],
+                                               'insert': [{ 'type': 
'paragraph' }, 'F', 'O', 'O', { 'type': '/paragraph' }]
+                                       },
+                                       { 'type': 'retain', 'length': 2 }
+                               ]
+                       },
+                       'inserting paragraph and end of paragraph moves 
insertion point forward': {
+                               'args': [doc3, 4, [{ 'type': 'paragraph' }, 
'B', 'A', 'R', { 'type': '/paragraph' }]],
+                               'ops': [
+                                       { 'type': 'retain', 'length': 5 },
+                                       {
+                                               'type': 'replace',
+                                               'remove': [],
+                                               'insert': [{ 'type': 
'paragraph' }, 'B', 'A', 'R', { 'type': '/paragraph' }]
+                                       }
+                               ]
                        }
                        // TODO test cases for unclosed openings
                        // TODO test cases for (currently failing) unopened 
closings use case

-- 
To view, visit https://gerrit.wikimedia.org/r/61048
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: Ic51dd03725c11f1f7e279929534ee3afea14d662
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/VisualEditor
Gerrit-Branch: master
Gerrit-Owner: Esanders <[email protected]>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to