jenkins-bot has submitted this change and it was merged.
Change subject: Bug 50243: Preserve transclusion parameter order
......................................................................
Bug 50243: Preserve transclusion parameter order
* Record the order of keys in an internal array inside data-parsoid, so that
we can preserve the order on edit.
* Use it in the serializer to preserve the order
Change-Id: I541abfba5edd274f43c0eda9ddef8d61c0d544e2
---
M js/lib/ext.core.ExtensionHandler.js
M js/lib/ext.core.TemplateHandler.js
M js/lib/mediawiki.DOMPostProcessor.js
M js/lib/mediawiki.WikitextSerializer.js
4 files changed, 84 insertions(+), 32 deletions(-)
Approvals:
Subramanya Sastry: Looks good to me, approved
jenkins-bot: Verified
diff --git a/js/lib/ext.core.ExtensionHandler.js
b/js/lib/ext.core.ExtensionHandler.js
index 6f509f6..1a82a09 100644
--- a/js/lib/ext.core.ExtensionHandler.js
+++ b/js/lib/ext.core.ExtensionHandler.js
@@ -42,15 +42,17 @@
/**
* Get the public data-mw structure that exposes the extension name, args, and
body
*/
-ExtensionHandler.prototype.getArgDict = function (state) {
+ExtensionHandler.prototype.getArgInfo = function (state) {
var extToken = state.token,
extName = state.token.getAttribute("name"),
extSrc = state.token.getAttribute("source");
return {
- name: extName,
- attrs: Util.KVtoHash(extToken.getAttribute("options")),
- body: { extsrc: Util.extractExtBody(extName, extSrc) }
+ dict: {
+ name: extName,
+ attrs: Util.KVtoHash(extToken.getAttribute("options")),
+ body: { extsrc: Util.extractExtBody(extName, extSrc) }
+ }
};
};
diff --git a/js/lib/ext.core.TemplateHandler.js
b/js/lib/ext.core.TemplateHandler.js
index c44865e..eb21a64 100644
--- a/js/lib/ext.core.TemplateHandler.js
+++ b/js/lib/ext.core.TemplateHandler.js
@@ -667,7 +667,8 @@
if (state.recordArgDict) {
// Get the arg dict
- var argDict = this.getArgDict(state);
+ var argInfo = this.getArgInfo(state),
+ argDict = argInfo.dict;
// Add in tpl-target/pf-name info
// Only one of these will be set.
@@ -676,7 +677,7 @@
// Use a data-attribute to prevent the sanitizer from stripping
this
// attribute before it reaches the DOM pass where it is needed.
- attrs.push(new KV("data-mw-arginfo", JSON.stringify(argDict)));
+ attrs.push(new KV("data-mw-arginfo", JSON.stringify(argInfo)));
}
if ( chunk.length ) {
@@ -812,13 +813,14 @@
// Add the wrapper attributes to the first element
firstNode.setAttribute('typeof', state.wrapperType);
+ var argInfo = this.getArgInfo(state);
+ firstNode.setAttribute('data-mw', JSON.stringify(argInfo.dict));
firstNode.setAttribute('data-parsoid', JSON.stringify(
{
tsr: Util.clone(state.token.dataAttribs.tsr),
src: state.token.dataAttribs.src
}
));
- firstNode.setAttribute('data-mw',
JSON.stringify(this.getArgDict(state)));
function outerHTML (n) {
return n.outerHTML;
@@ -836,14 +838,16 @@
cb({ tokens: toks });
};
+
/**
* Get the public data-mw structure that exposes the template name and
parameters
- * ExtensionHandler provides its own getArgDict function
+ * ExtensionHandler provides its own getArgInfo function
*/
-TemplateHandler.prototype.getArgDict = function (state) {
+TemplateHandler.prototype.getArgInfo = function (state) {
var src = this.manager.env.page.src,
params = state.token.attribs,
dict = {},
+ keys = [],
argIndex = 1;
// Use source offsets to extract arg-name and arg-value wikitext
@@ -861,9 +865,16 @@
name = src.substring(srcOffsets[0],
srcOffsets[1]);
}
+ if (dict[name] === undefined) {
+ keys.push(name);
+ }
dict[name] = { wt: src.substring(srcOffsets[2],
srcOffsets[3]) };
} else {
- dict[params[i].k] = params[i].v;
+ name = params[i].k;
+ if (dict[name] === undefined) {
+ keys.push(name);
+ }
+ dict[name] = params[i].v;
}
}
@@ -871,13 +882,11 @@
if (tplTgtSrcOffsets) {
var tplTgtWT = src.substring(tplTgtSrcOffsets[0],
tplTgtSrcOffsets[1]);
return {
- // gwicke: Removed the non-deterministic id member for
now as this
- // makes the data-mw attribute non-deterministic across
reparses.
- // That in turn triggers diffs. See
- // https://bugzilla.wikimedia.org/show_bug.cgi?id=47426.
- //id: state.wrappedObjectId,
- target: { wt: tplTgtWT },
- params: dict
+ dict: {
+ target: { wt: tplTgtWT },
+ params: dict
+ },
+ keys: keys
};
}
};
diff --git a/js/lib/mediawiki.DOMPostProcessor.js
b/js/lib/mediawiki.DOMPostProcessor.js
index e54a0b2..b591bfe 100644
--- a/js/lib/mediawiki.DOMPostProcessor.js
+++ b/js/lib/mediawiki.DOMPostProcessor.js
@@ -1108,7 +1108,7 @@
return rId;
}
- function recordTemplateInfo(compoundTpls, compoundTplId, tpl, tplArgs) {
+ function recordTemplateInfo(compoundTpls, compoundTplId, tpl, argInfo) {
// Record template args info alongwith any intervening wikitext
// between templates part of the same compound structure
var tplArray = compoundTpls[compoundTplId],
@@ -1120,7 +1120,7 @@
tplArray.push({ wt:
env.page.src.substring(prevTplInfo.dsr[1], dsr[0]) });
}
}
- tplArray.push({ dsr: dsr, args: tplArgs });
+ tplArray.push({ dsr: dsr, args: argInfo.dict, keys:
argInfo.keys });
}
var i, r, n, e;
@@ -1444,13 +1444,36 @@
tplArray.push({ wt:
env.page.src.substring(lastTplInfo.dsr[1], dp1.dsr[1]) });
}
+ // Extract the key orders for the templates
+ /* jshint loopfunc: true */ // yes, this
function is in a loop
+ var keyArrays = [],
+ pushKey = function(a) {
+ if(a.keys) {
+ keyArrays.push(a.keys);
+ }
+ };
+ tplArray.forEach(pushKey);
+
// Map the array of { dsr: .. , args: .. }
objects to just the args property
/* jshint loopfunc: true */ // yes, this
function is in a loop
- tplArray = tplArray.map(function(a) { return
a.wt ? a.wt : {template: a.args }; });
+ var infoIndex = 0;
+ tplArray = tplArray.map(function(a) {
+ if (a.wt) {
+ return a.wt;
+ } else {
+ // Remember the position of the
transclusion relative
+ // to other transclusions.
Should match the index of
+ // the corresponding private
metadata in keyArrays
+ // above.
+ a.args.i = infoIndex++;
+ return {template: a.args};
+ }
+ });
// Output the data-mw obj.
var datamw = (tplArray.length === 1) ?
tplArray[0].template : { parts: tplArray };
range.start.setAttribute("data-mw",
JSON.stringify(datamw));
+ range.start.data.parsoid.keys = keyArrays;
}
} else {
console.warn("ERROR: Do not have necessary info. to RT
Tpl: " + i);
diff --git a/js/lib/mediawiki.WikitextSerializer.js
b/js/lib/mediawiki.WikitextSerializer.js
index 63c893e..19cf7a0 100644
--- a/js/lib/mediawiki.WikitextSerializer.js
+++ b/js/lib/mediawiki.WikitextSerializer.js
@@ -2624,7 +2624,7 @@
node, state, cb);
};
-WSP._buildTemplateWT = function(state, srcParts) {
+WSP._buildTemplateWT = function(state, srcParts, dp) {
var buf = [],
serializer = this;
srcParts.map(function(part) {
@@ -2639,19 +2639,37 @@
// tpl args
var argBuf = [],
keys = Object.keys(tpl.params),
+ // the original keys in order
+ origKeys = tpl.i !== undefined ? dp.keys[tpl.i]
: [],
n = keys.length;
if (n > 0) {
- for (var i = 0; i < n; i++) {
- var k = keys[i],
- v =
serializer.escapeTplArgWT(state, tpl.params[k].wt);
- if (k === (i+1).toString()) {
- argBuf.push(v);
- } else {
- var kStr = k + (isTpl &&
!k.match(/\s$/) ? ' ' : ''),
- vStr = (isTpl &&
!v.match(/^\s/) ? ' ' : '') + v;
- argBuf.push(kStr + "=" + vStr);
+ var numericIndex = 1,
+ pushArg = function (k) {
+ var v =
serializer.escapeTplArgWT(state, tpl.params[k].wt);
+ if (k ===
numericIndex.toString()) {
+ numericIndex++;
+ argBuf.push(v);
+ } else {
+ var kStr = k + (isTpl
&& !k.match(/\s$/) ? ' ' : ''),
+ vStr = (isTpl
&& !v.match(/^\s/) ? ' ' : '') + v;
+ argBuf.push(kStr + "="
+ vStr);
+ }
+ };
+
+ // first serialize out old parameters in order
+ origKeys.forEach(function(k) {
+ if (tpl.params[k] !== undefined) {
+ pushArg(k);
}
- }
+ });
+ // then push out remaining parameters
+ keys.forEach(function(k) {
+ if (origKeys.indexOf(k) === -1) {
+ pushArg(k);
+ }
+ });
+
+ // Now append the parameters joined by pipes
buf.push("|");
buf.push(argBuf.join("|"));
}
@@ -2752,7 +2770,7 @@
if
(/\bmw:(Transclusion\b|Param\b)/.test(typeOf)) {
dataMW =
JSON.parse(node.getAttribute("data-mw"));
if (dataMW) {
- src =
state.serializer._buildTemplateWT(state, dataMW.parts || [{ template: dataMW
}]);
+ src =
state.serializer._buildTemplateWT(state, dataMW.parts || [{ template: dataMW
}], dp);
} else {
console.error("ERROR: No
data-mw for: " + node.outerHTML);
src = dp.src;
--
To view, visit https://gerrit.wikimedia.org/r/70653
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: merged
Gerrit-Change-Id: I541abfba5edd274f43c0eda9ddef8d61c0d544e2
Gerrit-PatchSet: 8
Gerrit-Project: mediawiki/extensions/Parsoid
Gerrit-Branch: master
Gerrit-Owner: GWicke <[email protected]>
Gerrit-Reviewer: Subramanya Sastry <[email protected]>
Gerrit-Reviewer: jenkins-bot
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits