Subramanya Sastry has uploaded a new change for review.

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


Change subject: WIP: Fix DSR for misnested A-tags to prevent selser corruption
......................................................................

WIP: Fix DSR for misnested A-tags to prevent selser corruption

Patch for discussion.

* Adding any content in the same paragraph as the misnested A-tag
  @ https://en.wikipedia.org/wiki/User:Ssastry/VE_Test#Nested_A-tag_tests
  will cause selser-based corruption of that piece -- this could
  potentially be worse in other scenarios.

* This patch eliminates that corruption. Manually tested with that
  snippet locally.

Change-Id: I30bc3bf6d8f4c54d02b12eb7686a4b1e58ed584a
---
M js/lib/dom.t.unpackDOMFragments.js
M js/lib/mediawiki.WikitextSerializer.js
2 files changed, 71 insertions(+), 3 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/Parsoid 
refs/changes/71/89771/1

diff --git a/js/lib/dom.t.unpackDOMFragments.js 
b/js/lib/dom.t.unpackDOMFragments.js
index 3641057..48971c9 100644
--- a/js/lib/dom.t.unpackDOMFragments.js
+++ b/js/lib/dom.t.unpackDOMFragments.js
@@ -4,9 +4,10 @@
        Util = require('./mediawiki.Util.js').Util,
        Consts = require('./mediawiki.wikitext.constants.js').WikitextConstants,
        computeNodeDSR = require('./dom.computeDSR.js').computeNodeDSR,
+       DOMTraverser = require('./domTraverser.js').DOMTraverser,
        wrapTemplatesInTree = 
require('./dom.wrapTemplates.js').wrapTemplatesInTree;
 
-function hasBadNesting(targetNode, fragmentNode) {
+function hasBadNesting(targetNode, fragment) {
        // SSS FIXME: This is not entirely correct. This is only
        // looking for nesting of identical tags. But, HTML tree building
        // has lot more restrictions on nesting. It seems the simplest way
@@ -20,7 +21,67 @@
        }
 
        return !isNestableElement(targetNode.nodeName) &&
-               DU.treeHasElement(fragmentNode, targetNode.nodeName);
+               DU.treeHasElement(fragment, targetNode.nodeName);
+}
+
+function fixUpMisnestedTagDSR(targetNode, fragment) {
+       // Currently, this only deals with A-tags
+       if (targetNode.nodeName !== 'A') {
+               return;
+       }
+
+       // Walk the fragment till you find an 'A' tag and
+       // zero out DSR width for all tags from that point on.
+       // This also requires adding span wrappers around
+       // bare text from that point on.
+
+       // QUICK FIX to discuss solution -- can be optimized.
+       // Add wrappers unconditionally and strip unneeded ones
+       DU.addSpanWrappers(fragment.childNodes);
+
+       var resetDSR = false,
+               currOffset = 0,
+               dsrFixer = new DOMTraverser();
+       dsrFixer.addHandler(null, function(node) {
+               if (DU.isElt(node)) {
+                       if (node.nodeName === 'A') {
+                               resetDSR = true;
+                       }
+
+                       DU.loadDataParsoid(node);
+                       if (resetDSR) {
+                               if (node.data.parsoid.dsr && 
node.data.parsoid.dsr[0]) {
+                                       currOffset = node.data.parsoid.dsr[1] = 
node.data.parsoid.dsr[0];
+                               } else {
+                                       node.data.parsoid.dsr = [currOffset, 
currOffset];
+                               }
+                               node.data.parsoid.misnested = true;
+                               DU.setDataParsoid(node, node.data.parsoid);
+                       } else if (node.data.parsoid.tmp.wrapper) {
+                               // Unnecessary wrapper added above -- strip it.
+                               var next = node.nextSibling;
+                               DU.migrateChildren(node, node.parentNode, node);
+                               DU.deleteNode(node);
+                               return next;
+                       }
+               }
+
+               return true;
+       });
+       dsrFixer.traverse(fragment);
+
+       // Since targetNode will get re-organized, save data.parsoid
+       var dsrSaver = new DOMTraverser(),
+               saveHandler = function(node) {
+                       if (DU.isElt(node) && node.data.parsoid.dsr) {
+                               DU.setDataParsoid(node, node.data.parsoid);
+                       }
+
+                       return true;
+               };
+       dsrSaver.addHandler(null, saveHandler);
+       saveHandler(targetNode);
+       dsrSaver.traverse(targetNode);
 }
 
 function addDeltaToDSR(node, delta) {
@@ -250,6 +311,13 @@
                                        makeChildrenEncapWrappers(dummyNode, 
about);
                                }
 
+                               // 1. Set zero-dsr width on all elements that 
will get split
+                               //    in dummyNode's tree to prevent 
selser-based corruption
+                               //    on edits to a page that contains badly 
nested tags.
+                               // 2. Save data-parsoid on fragmentParent since 
it will be
+                               //    modified below and we want data.parsoid 
preserved.
+                               fixUpMisnestedTagDSR(fragmentParent, dummyNode);
+
                                var newDoc = 
DU.parseHTML(fragmentParent.outerHTML.replace(timestamp, dummyNode.innerHTML));
                                DU.migrateChildrenBetweenDocs(newDoc.body, 
fragmentParent.parentNode, fragmentParent);
 
diff --git a/js/lib/mediawiki.WikitextSerializer.js 
b/js/lib/mediawiki.WikitextSerializer.js
index e3a2fb7..6ed8c0a 100644
--- a/js/lib/mediawiki.WikitextSerializer.js
+++ b/js/lib/mediawiki.WikitextSerializer.js
@@ -4044,7 +4044,7 @@
                        // to every node of a subtree (rather than an 
indication that some node
                        // in the subtree is modified).
                        if (state.selserMode && !state.inModifiedContent &&
-                               dp && isValidDSR(dp.dsr) && (dp.dsr[1] > 
dp.dsr[0] || dp.fostered)) {
+                               dp && isValidDSR(dp.dsr) && (dp.dsr[1] > 
dp.dsr[0] || dp.fostered || dp.misnested)) {
                                // To serialize from source, we need 3 things 
of the node:
                                // -- it should not have a diff marker
                                // -- it should have valid, usable DSR

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

Gerrit-MessageType: newchange
Gerrit-Change-Id: I30bc3bf6d8f4c54d02b12eb7686a4b1e58ed584a
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/Parsoid
Gerrit-Branch: master
Gerrit-Owner: Subramanya Sastry <[email protected]>

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

Reply via email to