jenkins-bot has submitted this change and it was merged.

Change subject: (Bug 51678) Fixed bug in dom-diff algorithm
......................................................................


(Bug 51678) Fixed bug in dom-diff algorithm

* The dom-diff algorithm was occasionally recursing into
  template transclusion HTML.  Since transclusion HTML can never
  be directly modified by editors and template updates are
  transmitted via the data-mw object in the wrapper, it is not
  necessary to compare transclusion content.  It can in fact
  introduce bugs as in the itwp examples in the bug report because
  DOM-diff might insert deleted-content-markers and break the
  continuity in template about markers (which is important to
  skip over transclusion content during serialization correctly).

  This bug also only surfaces because of the peculiarities of how
  updated template HTML is modified in VE (see bug report for
  more details).

* Added some documentation to dom-util functions.

* Tested this with HTML (old and edited) dumped from VE via
  Chrome's console.  Verified bug without patch and a fix with
  the patch.

  Currently, we don't have direct dom-diff tests, only indirect
  tests via selser.

  Even if we did have, it would be hard to write a test for this
  bug fix becuase it depends on template content HTML getting
  deleted on edit (see bug report for details).  But, it would be
  possible with a jasmine testing framework which we could consider
  resurrecting.

  To cut a long story short: no change in parsertest results,
  and no new tests added.

Change-Id: I886161d981a0c79b8300d88c5281514b4248cff2
---
M js/lib/mediawiki.DOMDiff.js
M js/lib/mediawiki.DOMUtils.js
M js/lib/mediawiki.WikitextSerializer.js
3 files changed, 51 insertions(+), 16 deletions(-)

Approvals:
  Cscott: Looks good to me, approved
  jenkins-bot: Verified



diff --git a/js/lib/mediawiki.DOMDiff.js b/js/lib/mediawiki.DOMDiff.js
index 5d4814e..39a90c4 100644
--- a/js/lib/mediawiki.DOMDiff.js
+++ b/js/lib/mediawiki.DOMDiff.js
@@ -231,31 +231,48 @@
                                if (origNode.nodeName === baseNode.nodeName) {
                                        // Identical wrapper-type, but modified.
                                        // Mark as modified, and recurse.
+                                       this.debug("--found diff: 
modified-wrapper--");
                                        this.markNode(origNode, 
'modified-wrapper');
-                                       this.doDOMDiff(baseNode, origNode);
+                                       if (!DU.isTplElementNode(this.env, 
baseNode) && !DU.isTplElementNode(this.env, origNode)) {
+                                               // Dont recurse into 
template-like-content
+                                               this.doDOMDiff(baseNode, 
origNode);
+                                       }
                                } else {
                                        // Mark the sub-tree as modified since
                                        // we have two entirely different nodes 
here
+                                       this.debug("--found diff: modified--");
                                        this.markNode(origNode, 'modified');
                                }
                        }
 
                        // Record the fact that direct children changed in the 
parent node
+                       this.debug("--found diff: modified-children--");
                        this.markNode(newParentNode, 'modified-children');
 
                        foundDiffOverall = true;
-               } else if (!DU.isTplElementNode(this.env, newNode)) {
+               } else if (!DU.isTplElementNode(this.env, baseNode) && 
!DU.isTplElementNode(this.env, newNode)) {
+                       this.debug("--equal: recursing--");
                        // Recursively diff subtrees if not template-like 
content
                        var subtreeDiffers = this.doDOMDiff(baseNode, newNode);
                        if (subtreeDiffers) {
+                               this.debug("--found diff: subtree-changed--");
                                this.markNode(newNode, 'subtree-changed');
                        }
                        foundDiffOverall = subtreeDiffers || foundDiffOverall;
                }
 
-               // And move on to the next pair
-               baseNode = baseNode.nextSibling;
-               newNode = newNode.nextSibling;
+               // And move on to the next pair (skipping over template HTML)
+               if (DU.isTplElementNode(this.env, baseNode)) {
+                       baseNode = DU.skipOverEncapsulatedContent(baseNode);
+               } else {
+                       baseNode = baseNode.nextSibling;
+               }
+
+               if (DU.isTplElementNode(this.env, newNode)) {
+                       newNode = DU.skipOverEncapsulatedContent(newNode);
+               } else {
+                       newNode = newNode.nextSibling;
+               }
        }
 
        // mark extra new nodes as modified
diff --git a/js/lib/mediawiki.DOMUtils.js b/js/lib/mediawiki.DOMUtils.js
index 0dd729e..b081938 100644
--- a/js/lib/mediawiki.DOMUtils.js
+++ b/js/lib/mediawiki.DOMUtils.js
@@ -4,6 +4,7 @@
  * General DOM utilities
  */
 
+require('./core-upgrade.js');
 var Util = require('./mediawiki.Util.js').Util,
        Node = require('./mediawiki.wikitext.constants.js').Node,
        pd = require('./mediawiki.parser.defines.js');
@@ -665,6 +666,18 @@
                }
        },
 
+       /**
+        * Gets all siblings that follow 'node' that have an 'about' as their 
about id.
+        *
+        * This is used to fetch transclusion/extension content by using the 
about-id
+        * as the key.  This works because transclusion/extension content is a 
forest
+        * of dom-trees formed by adjacent dom-nodes.  This is the contract that
+        * templace encapsulation, dom-reuse, and VE code all have to abide by.
+        *
+        * The only exception to this adjacency rule is IEW nodes in fosterable
+        * positions (in tables) which are not span-wrapped to prevent them 
from getting
+        * fostered out.
+        **/
        getAboutSiblings: function(node, about) {
                var nodes = [node];
 
@@ -682,6 +695,20 @@
        },
 
        /**
+        * If 'node' has about-id, it is assumed that it is generated by 
templates or
+        * extensions.  This function skips over all following content nodes 
and returns
+        * the first non-template node that follows it.
+        */
+       skipOverEncapsulatedContent: function(node) {
+               var about = node.getAttribute('about');
+               if (!about) {
+                       return node;
+               }
+
+               return this.getAboutSiblings(node, about).last().nextSibling;
+       },
+
+       /**
         * Extract transclusion and extension expansions from a DOM, and return
         * them in a structure like this:
         * {
diff --git a/js/lib/mediawiki.WikitextSerializer.js 
b/js/lib/mediawiki.WikitextSerializer.js
index bcf736b..651752e 100644
--- a/js/lib/mediawiki.WikitextSerializer.js
+++ b/js/lib/mediawiki.WikitextSerializer.js
@@ -3109,15 +3109,6 @@
        return srcParts.join('');
 };
 
-WSP.skipOverEncapsulatedContent = function(node) {
-       var about = node.getAttribute('about');
-       if (!about) {
-               return node;
-       }
-
-       return DU.getAboutSiblings(node, about).last().nextSibling;
-};
-
 /**
  * Get a DOM-based handler for an element node
  */
@@ -3168,7 +3159,7 @@
 
                                if (src !== undefined) {
                                        self.emitWikitext(src, state, cb, node);
-                                       return 
self.skipOverEncapsulatedContent(node);
+                                       return 
DU.skipOverEncapsulatedContent(node);
                                } else {
                                        console.error("ERROR: No handler for: " 
+ node.outerHTML);
                                        console.error("Serializing as HTML.");
@@ -3944,7 +3935,7 @@
                                        // Skip over encapsulated content since 
it has already been serialized
                                        var typeOf = node.getAttribute( 
'typeof' ) || '';
                                        if 
(/\bmw:(?:Transclusion\b|Param\b|Extension\/[^\s]+)/.test(typeOf)) {
-                                               nextNode = 
this.skipOverEncapsulatedContent(node);
+                                               nextNode = 
DU.skipOverEncapsulatedContent(node);
                                        }
                                } else if (DU.onlySubtreeChanged(node, 
this.env) &&
                                        hasValidTagWidths(dp.dsr) &&

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

Gerrit-MessageType: merged
Gerrit-Change-Id: I886161d981a0c79b8300d88c5281514b4248cff2
Gerrit-PatchSet: 2
Gerrit-Project: mediawiki/extensions/Parsoid
Gerrit-Branch: master
Gerrit-Owner: Subramanya Sastry <[email protected]>
Gerrit-Reviewer: Cscott <[email protected]>
Gerrit-Reviewer: jenkins-bot

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

Reply via email to