Tchanders has uploaded a new change for review. ( 
https://gerrit.wikimedia.org/r/355716 )

Change subject: Visual Diff: add internal list diff
......................................................................

Visual Diff: add internal list diff

Display changes to references in the visual diff.

Bug: T162819
Change-Id: If603a1861b32c1241396608ea1bd1927ebba9049
---
M src/dm/ve.dm.VisualDiff.js
M src/ui/elements/ve.ui.DiffElement.js
2 files changed, 173 insertions(+), 12 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/VisualEditor/VisualEditor 
refs/changes/16/355716/1

diff --git a/src/dm/ve.dm.VisualDiff.js b/src/dm/ve.dm.VisualDiff.js
index 750d112..6782614 100644
--- a/src/dm/ve.dm.VisualDiff.js
+++ b/src/dm/ve.dm.VisualDiff.js
@@ -21,16 +21,19 @@
 
        this.oldDoc = oldDoc.cloneFromRange();
        this.newDoc = newDoc.cloneFromRange();
-       this.oldDocNode = oldDoc.getDocumentNode();
-       this.newDocNode = newDoc.getDocumentNode();
+       this.oldDocNode = this.oldDoc.getDocumentNode();
+       this.newDocNode = this.newDoc.getDocumentNode();
        this.oldDocChildren = this.oldDocNode.children;
        this.newDocChildren = this.newDocNode.children;
+       this.oldDocInternalListNode = this.oldDocChildren[ 
this.oldDocChildren.length - 1 ];
+       this.newDocInternalListNode = this.newDocChildren[ 
this.newDocChildren.length - 1 ];
        this.treeDiffer = treeDiffer;
        // eslint-disable-next-line camelcase,new-cap
        this.linearDiffer = new ve.DiffMatchPatch( this.oldDoc.getStore(), 
this.newDoc.getStore() );
        this.endTime = new Date().getTime() + ( timeout || 1000 );
 
        this.diff = this.getDiff();
+       this.diff.internalListDiff = this.getInternalListDiffInfo();
 };
 
 /**
@@ -364,6 +367,7 @@
        if ( keepLength < 0.5 * diffLength ) {
                return false;
        }
+
        return {
                treeDiff: treeDiff,
                diffInfo: diffInfo,
@@ -372,3 +376,81 @@
        };
 
 };
+
+/*
+ * Get the diff between the old document's internal list and the new document's
+ * internal list. The diff is grouped by list group, and each node in each list
+ * group is marked as removed, inserted, the same, or changed (in which case 
the
+ * linear diff is given).
+ *
+ * @return {Object} Internal list diff object
+ */
+ve.dm.VisualDiff.prototype.getInternalListDiffInfo = function () {
+       var i, ilen, diff,
+               group, groupIndexOrder, nodeIndex,
+               oldDocInternalListNodes = this.oldDoc.internalList.nodes,
+               newDocInternalListNodes = this.newDoc.internalList.nodes,
+               retainedInternalListItems = {},
+               removedInternalListItems = {},
+               internalListDiffInfo = {};
+
+       // Find all nodes referenced by the new document's internal list
+       for ( group in newDocInternalListNodes ) {
+               groupIndexOrder = newDocInternalListNodes[ group ].indexOrder;
+               internalListDiffInfo[ group ] = {};
+               for ( i = 0, ilen = groupIndexOrder.length; i < ilen; i++ ) {
+                       nodeIndex = groupIndexOrder[ i ];
+                       retainedInternalListItems[ nodeIndex ] = group;
+                       internalListDiffInfo[ group ] = {
+                               changes: false
+                       };
+               }
+       }
+
+       // Find all nodes referenced by the old document's internal list
+       for ( group in oldDocInternalListNodes ) {
+               groupIndexOrder = oldDocInternalListNodes[ group ].indexOrder;
+               for ( i = 0, ilen = groupIndexOrder.length; i < ilen; i++ ) {
+                       nodeIndex = groupIndexOrder[ i ];
+                       if ( retainedInternalListItems[ nodeIndex ] ) {
+                               continue;
+                       }
+                       removedInternalListItems[ nodeIndex ] = group;
+                       // TODO: Work out what should happen if the whole list 
group was removed
+                       internalListDiffInfo[ group ] = {
+                               changes: false
+                       };
+               }
+       }
+
+       for ( i = 0, ilen = this.newDocInternalListNode.children.length; i < 
ilen; i++ ) {
+               nodeIndex = i;
+               group = retainedInternalListItems[ nodeIndex ] || 
removedInternalListItems[ nodeIndex ];
+               if ( i > this.oldDocInternalListNode.children.length - 1 ) {
+                       // Item was inserted
+                       internalListDiffInfo[ group ][ nodeIndex ] = 1;
+                       internalListDiffInfo[ group ].changes = true;
+               } else if ( i in removedInternalListItems ) {
+                       // Item was removed
+                       internalListDiffInfo[ group ][ nodeIndex ] = -1;
+                       internalListDiffInfo[ group ].changes = true;
+               } else {
+                       // Item corresponds to the item in the old document's 
internal list with
+                       // the same index. They could be the same or changed.
+                       diff = this.getDocChildDiff(
+                               this.oldDocInternalListNode.children[ i ],
+                               this.newDocInternalListNode.children[ i ]
+                       );
+                       if ( diff.diffInfo.length > 0 ) {
+                               // Item was changed from an old item
+                               internalListDiffInfo[ group ][ nodeIndex ] = 
diff;
+                               internalListDiffInfo[ group ].changes = true;
+                       } else {
+                               // Item is unchanged from an old item
+                               internalListDiffInfo[ group ][ nodeIndex ] = 0;
+                       }
+               }
+       }
+
+       return internalListDiffInfo;
+};
diff --git a/src/ui/elements/ve.ui.DiffElement.js 
b/src/ui/elements/ve.ui.DiffElement.js
index 67e3961..f88e087 100644
--- a/src/ui/elements/ve.ui.DiffElement.js
+++ b/src/ui/elements/ve.ui.DiffElement.js
@@ -25,14 +25,19 @@
        // Documents
        this.oldDoc = visualDiff.oldDoc;
        this.newDoc = visualDiff.newDoc;
-       this.oldDocChildren = this.oldDoc.getDocumentNode().children;
-       this.newDocChildren = this.newDoc.getDocumentNode().children;
+       this.oldDocChildren = visualDiff.oldDocChildren;
+       this.newDocChildren = visualDiff.newDocChildren;
+
+       // Internal list
+       this.newDocInternalListNode = visualDiff.newDocInternalListNode;
+       this.oldDocInternalListNode = visualDiff.oldDocInternalListNode;
 
        // Diff
        this.oldToNew = diff.docChildrenOldToNew;
        this.newToOld = diff.docChildrenNewToOld;
        this.insert = diff.docChildrenInsert;
        this.remove = diff.docChildrenRemove;
+       this.internalListDiff = diff.internalListDiff;
 
        this.$overlays = $( '<div>' ).addClass( 've-ui-diffElement-overlays' );
        this.$content = $( '<div>' ).addClass( 've-ui-diffElement-content' );
@@ -184,6 +189,9 @@
  */
 ve.ui.DiffElement.prototype.renderDiff = function () {
        var i, j, k, ilen, jlen, klen, nodes, move, elements, spacerNode, 
noChanges,
+               group, headingNode, listNode, groupName, nodeIndex, 
listItemNode,
+               internalListGroup, annotatedData, documentSlice, nodeData, body,
+               referenceDiffDiv, anyInternalListChanges,
                documentNode = this.$document[ 0 ],
                anyChanges = false,
                spacer = false,
@@ -267,8 +275,80 @@
                        }
                } else if ( !spacer ) {
                        spacer = true;
-                       documentNode.appendChild( spacerNode.cloneNode( true ) 
);
+                       documentNode.appendChild(
+                               documentNode.ownerDocument.adoptNode( 
spacerNode.cloneNode( true ) )
+                       );
                }
+       }
+
+       // Render the internal list diff, i.e. all reflists with changed nodes.
+       // TODO: It would be nice if the reflists could be rendered in place in 
the document; however,
+       // they could be hard to find if they are within a template, so for now 
they are just shown at
+       // the end of the diff.
+       referenceDiffDiv = document.createElement( 'div' );
+       for ( group in this.internalListDiff ) {
+
+               internalListGroup = this.internalListDiff[ group ];
+               if ( !internalListGroup.changes ) {
+                       continue;
+               }
+               delete internalListGroup.changes;
+
+               // There are changes, so display this list
+               anyInternalListChanges = true;
+               headingNode = document.createElement( 'h2' );
+               headingNode.setAttribute( 'data-diff-action', 'none' );
+               listNode = document.createElement( 'ol' );
+               groupName = group.split( '/' )[ 1 ] || 'References';
+               headingNode.appendChild( document.createTextNode( groupName ) );
+               referenceDiffDiv.appendChild( headingNode );
+               referenceDiffDiv.appendChild( listNode );
+
+               for ( nodeIndex in internalListGroup ) {
+                       listItemNode = document.createElement( 'li' );
+                       if ( internalListGroup[ nodeIndex ] === 1 ) {
+                               elements = this.getNodeElements( 
this.newDocInternalListNode.children[ nodeIndex ].children[ 0 ], 'insert' );
+                               listItemNode.appendChild(
+                                       listItemNode.ownerDocument.adoptNode( 
elements[ 0 ] )
+                               );
+                       } else if ( internalListGroup[ nodeIndex ] === -1 ) {
+                               elements = this.getNodeElements( 
this.oldDocInternalListNode.children[ nodeIndex ].children[ 0 ], 'remove' );
+                               listItemNode.appendChild(
+                                       listItemNode.ownerDocument.adoptNode( 
elements[ 0 ] )
+                               );
+                       } else if ( internalListGroup[ nodeIndex ] === 0 ) {
+                               elements = this.getNodeElements( 
this.newDocInternalListNode.children[ nodeIndex ].children[ 0 ], 'none' );
+                               listItemNode.appendChild(
+                                       listItemNode.ownerDocument.adoptNode( 
elements[ 0 ] )
+                               );
+                       } else {
+
+                               annotatedData = this.annotateNode( 
internalListGroup[ nodeIndex ].diffInfo[ 0 ].linearDiff );
+                               elements = document.createElement( 'div' );
+                               elements.setAttribute( 'class', 
've-ui-diffElement-doc-child-change' );
+                               documentSlice = this.newDoc.cloneFromRange( { 
from: 0, to: 0 } );
+                               documentSlice.getStore().merge( 
this.newDoc.getStore() );
+                               nodeData = documentSlice.data.data;
+                               ve.batchSplice( nodeData, 0, 0, annotatedData );
+                               body = ve.dm.converter.getDomFromModel( 
documentSlice, true ).body;
+                               while ( body.childNodes.length ) {
+                                       elements.appendChild(
+                                               
elements.ownerDocument.adoptNode( body.childNodes[ 0 ] )
+                                       );
+                               }
+
+                               listItemNode.appendChild(
+                                       listItemNode.ownerDocument.adoptNode( 
elements )
+                               );
+
+                       }
+
+                       listNode.appendChild( listItemNode );
+
+               }
+       }
+       if ( anyInternalListChanges ) {
+               documentNode.appendChild( referenceDiffDiv );
        }
 
        ve.resolveAttributes( documentNode, this.newDoc.getHtmlDocument(), 
ve.dm.Converter.static.computedAttributes );
@@ -295,10 +375,10 @@
  * or moved
  * @param {string} action 'remove', 'insert' or, if moved, 'none'
  * @param {string} [move] 'up' or 'down' if the node has moved
- * @return {HTMLElement[]} HTML to display the action/move
+ * @return {HTMLElement[]} Elements (not owned by window.document)
  */
 ve.ui.DiffElement.prototype.getNodeElements = function ( node, action, move ) {
-       var nodeData, body, element,
+       var nodeData, doc, body, element,
                nodeDoc = action === 'remove' ? this.oldDoc : this.newDoc,
                documentSlice = nodeDoc.cloneFromRange( node.getOuterRange() );
 
@@ -312,15 +392,14 @@
        // Doc is always the new doc when inserting into the store
        documentSlice.getStore().merge( this.newDoc.getStore() );
        // forClipboard is true, so that we can render otherwise invisible nodes
-       body = ve.dm.converter.getDomFromModel( documentSlice, true ).body;
+       doc = ve.dm.converter.getDomFromModel( documentSlice, true );
+       body = doc.body;
 
        if ( action !== 'none' ) {
-               element = document.createElement( 'div' );
+               element = doc.createElement( 'div' );
                element.setAttribute( 'class', 
've-ui-diffElement-doc-child-change' );
                while ( body.childNodes.length ) {
-                       element.appendChild(
-                               element.ownerDocument.adoptNode( 
body.childNodes[ 0 ] )
-                       );
+                       element.appendChild( body.childNodes[ 0 ] );
                }
                return [ element ];
        }

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

Gerrit-MessageType: newchange
Gerrit-Change-Id: If603a1861b32c1241396608ea1bd1927ebba9049
Gerrit-PatchSet: 1
Gerrit-Project: VisualEditor/VisualEditor
Gerrit-Branch: master
Gerrit-Owner: Tchanders <thalia.e.c...@googlemail.com>

_______________________________________________
MediaWiki-commits mailing list
MediaWiki-commits@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to