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