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
