Subramanya Sastry has uploaded a new change for review.

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


Change subject: WIP: (Bug 50536) Improved handling of tree-builder fixup
......................................................................

WIP: (Bug 50536) Improved handling of tree-builder fixup

* Have some failing tests -- to be handled.

Change-Id: If290aa7f7df1a5baf3ddf2a9ad36cfa39d66c8d4
---
M js/lib/mediawiki.DOMPostProcessor.js
M js/lib/mediawiki.DOMUtils.js
M js/lib/mediawiki.HTML5TreeBuilder.node.js
3 files changed, 87 insertions(+), 70 deletions(-)


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

diff --git a/js/lib/mediawiki.DOMPostProcessor.js 
b/js/lib/mediawiki.DOMPostProcessor.js
index 4970d91..f7ca5e3 100644
--- a/js/lib/mediawiki.DOMPostProcessor.js
+++ b/js/lib/mediawiki.DOMPostProcessor.js
@@ -1651,7 +1651,7 @@
        return tplRanges;
 }
 
-function findBuilderCorrectedTags(document, env) {
+function findAndFixBuilderCorrectedTags(document, env) {
        function addPlaceholderMeta( node, dp, name, opts ) {
                // If node is in a position where the placeholder
                // node will get fostered out, dont bother adding one
@@ -1711,8 +1711,7 @@
        // 1. Finds start-tag marker metas that dont have a corresponding start 
tag
        //    and adds placeholder metas for the purposes of round-tripping.
        // 2. Deletes any useless end-tag marker metas
-       // 3. Deletes empty nodes that is entirely builder inserted (both 
start/end)
-       function findDeletedStartTagsAndMore(node) {
+       function findDeletedStartTags(node) {
                // handle unmatched mw:StartTag meta tags
                var c = node.firstChild;
                while (c !== null) {
@@ -1740,11 +1739,8 @@
                                                // other brittle DOM passes 
working on the DOM.
                                                deleteNode(c);
                                        }
-                               } else if (dp.autoInsertedStart && 
dp.autoInsertedEnd && c.childNodes.length === 0) {
-                                       // Delete any node that was inserted as 
a fixup node but has no content
-                                       deleteNode(c);
                                } else {
-                                       findDeletedStartTagsAndMore(c);
+                                       findDeletedStartTags(c);
                                }
                        }
                        c = sibling;
@@ -1791,21 +1787,16 @@
                                        !dp.selfClose &&
                                        (cNodeName !== 'tbody' || 
DU.hasLiteralHTMLMarker(dp)))
                                {
-                                       // Do we need to run auto-inserted 
end-tag detection on c?
-                                       // -> Yes if we have tsr
-                                       // -> Yes if dont have tsr but end tag 
is outside template
-                                       if (dp.tsr || 
DU.endTagOutsideTemplate(c, dp)) {
-                                               // Detect auto-inserted end-tags
-                                               var metaNode = 
findMetaShadowNode(c, 'mw:EndTag', cNodeName);
-                                               if (!metaNode) {
-                                                       //console.log( 
c.nodeName, c.parentNode.outerHTML );
-                                                       // 'c' is a html node 
that has tsr, but no end-tag marker tag
-                                                       // => its closing tag 
was auto-generated by treebuilder.
-                                                       dp.autoInsertedEnd = 
true;
-                                               }
+                                       // Detect auto-inserted end-tags
+                                       var metaNode = findMetaShadowNode(c, 
'mw:EndTag', cNodeName);
+                                       if (!metaNode) {
+                                               //console.log( c.nodeName, 
c.parentNode.outerHTML );
+                                               // 'c' is a html node that has 
tsr, but no end-tag marker tag
+                                               // => its closing tag was 
auto-generated by treebuilder.
+                                               dp.autoInsertedEnd = true;
                                        }
 
-                                       if (dp.tsr) {
+                                       if (dp.tagId) {
                                                // Detect auto-inserted 
start-tags
                                                var fc = c.firstChild;
                                                while (fc) {
@@ -1820,7 +1811,7 @@
                                                        }
                                                }
 
-                                               expectedName = cNodeName + ":" 
+ dp.tsr;
+                                               expectedName = cNodeName + ":" 
+ dp.tagId;
                                                if (fc &&
                                                        DU.isMarkerMeta(fc, 
"mw:StartTag") &&
                                                        
fc.getAttribute('data-stag') === expectedName)
@@ -1858,8 +1849,45 @@
                }
        }
 
+       // In wikitext pages, the expectation of formatting-elt fixup is for
+       // as minimal fixup as possible (compared to HTML5 tree building 
behavior).
+       // So, we go in and cleanup the mess to preserve expectations of 
wikipedia
+       // editors and other wikitext users.
+       function stripExcessTags(node) {
+               var c = node.firstChild;
+               while (c) {
+                       var next = c.nextSibling;
+                       if (DU.isElt(c)) {
+                               stripExcessTags(c);
+
+                               // Handle fixup nodes
+                               if (c.data.parsoid.autoInsertedStart &&
+                                       c.data.parsoid.autoInsertedEnd)
+                               {
+                                       // If c itself is an entirely 
auto-inserted formatting elt.
+                                       // transfer c's children to c's parent 
and strip it.
+                                       if (DU.isFormattingElt(c)) {
+                                               var c_parent = c.parentNode;
+                                               var c_child = c.firstChild;
+                                               while (c_child) {
+                                                       var c_next = 
c_child.nextSibling;
+                                                       
c_parent.insertBefore(c_child, c);
+                                                       c_child = c_next;
+                                               }
+
+                                               deleteNode(c);
+                                       } else if (c.childNodes.length === 0) {
+                                               deleteNode(c);
+                                       }
+                               }
+                       }
+                       c = next;
+               }
+       }
+
        findAutoInsertedTags(document.body);
-       findDeletedStartTagsAndMore(document);
+       findDeletedStartTags(document.body);
+       stripExcessTags(document.body);
 }
 
 // TSR = "Tag Source Range".  Start and end offsets giving the location
@@ -2860,8 +2888,11 @@
  */
 saveDataParsoid = function( node, debugDump ) {
        if ( node.nodeType === node.ELEMENT_NODE && node.data ) {
-               if (!debugDump && node.data.parsoid && node.data.parsoid.tsr) {
-                       node.data.parsoid.tsr = undefined;
+               if (!debugDump) {
+                       node.data.parsoid.tagId = undefined;
+                       if (node.data.parsoid && node.data.parsoid.tsr) {
+                               node.data.parsoid.tsr = undefined;
+                       }
                }
                DU.saveDataAttribs( node );
        }
@@ -2893,7 +2924,7 @@
                handleUnbalancedTableTags,
                migrateStartMetas,
                //normalizeDocument,
-               findBuilderCorrectedTags,
+               findAndFixBuilderCorrectedTags,
                handlePres,
                migrateTrailingNLs
        ];
diff --git a/js/lib/mediawiki.DOMUtils.js b/js/lib/mediawiki.DOMUtils.js
index 6bd5dde..0dd729e 100644
--- a/js/lib/mediawiki.DOMUtils.js
+++ b/js/lib/mediawiki.DOMUtils.js
@@ -24,6 +24,16 @@
                return node && Util.isBlockTag(node.nodeName.toLowerCase());
        },
 
+       // See 
http://www.w3.org/html/wg/drafts/html/master/syntax.html#formatting
+       formattingTagMap: Util.arrayToHash([
+               'A', 'B', 'BIG', 'CODE', 'EM', 'FONT', 'I', 'NOBR',
+               'S', 'SMALL', 'STRIKE', 'STRONG', 'TT', 'U'
+       ]),
+
+       isFormattingElt: function(node) {
+               return this.isElt(node) && this.formattingTagMap[node.nodeName];
+       },
+
        /**
         * Add a type to the typeof attribute. This method works for both tokens
         * and DOM nodes as it only relies on getAttribute and setAttribute, 
which
@@ -380,34 +390,6 @@
                        }
                }
 
-               return false;
-       },
-
-       // This function tests if its end tag is outside a template.
-       endTagOutsideTemplate: function(node, dp) {
-               if (dp.tsr) {
-                       return true;
-               }
-
-               var next = node.nextSibling;
-               if (next && this.isElt(next) && this.getDataParsoid(next).tsr) {
-                       // If node's sibling has a valid tsr, then the sibling
-                       // is outside a template, and since node's start tag 
itself
-                       // is inside a template, this automatically implies that
-                       // the end tag is outside a template as well.
-                       return true;
-               }
-
-               // Descend into children -- walk backward
-               var children = node.childNodes;
-               for (var n = children.length, i = n-1; i >= 0; i--) {
-                       var c = children[i];
-                       if (this.isElt(c)) {
-                               return this.endTagOutsideTemplate(c, 
this.getDataParsoid(c));
-                       }
-               }
-
-               // We ran out of children to test
                return false;
        },
 
diff --git a/js/lib/mediawiki.HTML5TreeBuilder.node.js 
b/js/lib/mediawiki.HTML5TreeBuilder.node.js
index 1d17aec..08d5b64 100644
--- a/js/lib/mediawiki.HTML5TreeBuilder.node.js
+++ b/js/lib/mediawiki.HTML5TreeBuilder.node.js
@@ -32,6 +32,9 @@
 
        this.env = env;
        this.trace = env.conf.parsoid.debug || (env.conf.parsoid.traceFlags && 
(env.conf.parsoid.traceFlags.indexOf("html") !== -1));
+
+       // Tag id for
+       this.tagId = 1;
 };
 
 // Inherit from EventEmitter
@@ -78,6 +81,7 @@
        // XXX: more clean up to allow reuse.
        this.parser.setup();
        this.processToken(new TagTk( 'body' ));
+       this.tagId = 1; // Reset
 };
 
 FauxHTML5.TreeBuilder.prototype._att = function (maybeAttribs) {
@@ -99,17 +103,19 @@
        var attribs = token.attribs || [],
            dataAttribs = token.dataAttribs;
 
-       if ( dataAttribs ) {
-               var dataMW = JSON.stringify( dataAttribs );
-               if ( dataMW !== '{}' ) {
-                       attribs = attribs.concat([
-                                       {
-                                               // Mediawiki-specific 
round-trip / non-semantic information
-                                               k: 'data-parsoid',
-                                               v: dataMW
-                                       } ] );
-               }
+       // Always insert data-parsoid
+       if (!dataAttribs) {
+               dataAttribs = {};
        }
+       // Assign tagid for open tags
+       if (token.constructor === TagTk && token.name !== 'body') {
+               dataAttribs.tagId = this.tagId++;
+       }
+
+       attribs = attribs.concat([ {
+               k: 'data-parsoid',
+               v: JSON.stringify(dataAttribs)
+       } ]);
 
        if (this.trace) {
                console.warn("T:html: " + JSON.stringify(token));
@@ -152,13 +158,11 @@
                case TagTk:
                        tName = token.name;
                        this.emit('token', {type: 'StartTag', name: tName, 
data: this._att(attribs)});
-                       if (dataAttribs && dataAttribs.tsr) {
-                               attrs = [];
-                               if ( this.trace ) { console.warn('inserting 
shadow meta for ' + tName); }
-                               attrs.push({nodeName: "typeof", nodeValue: 
"mw:StartTag"});
-                               attrs.push({nodeName: "data-stag", nodeValue: 
tName + ':' + dataAttribs.tsr});
-                               this.emit('token', {type: 'StartTag', name: 
'meta', data: attrs});
-                       }
+                       attrs = [];
+                       if ( this.trace ) { console.warn('inserting shadow meta 
for ' + tName); }
+                       attrs.push({nodeName: "typeof", nodeValue: 
"mw:StartTag"});
+                       attrs.push({nodeName: "data-stag", nodeValue: tName + 
':' + dataAttribs.tagId});
+                       this.emit('token', {type: 'StartTag', name: 'meta', 
data: attrs});
                        break;
                case SelfclosingTagTk:
                        tName = token.name;

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

Gerrit-MessageType: newchange
Gerrit-Change-Id: If290aa7f7df1a5baf3ddf2a9ad36cfa39d66c8d4
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