(Bug 50218) Generated DOMFragment wrapping <ol> for references tag

* So far, references wikitext was being replaced with a meta marker
  token that participated as an inline token in p-wrapping.  As a
  result, in some cases, a p-tag was wrapping the references ol-node
  which is buggy HTML.  When VE loaded this DOM, the p-node was split
  around the ol-node and duplicated DSR which led to duplicated
  output when selser ran on this.

* One way of fixing this would have been to add a special case in
  the paragraph wrapper to treat the mw:Extensions/References/Marker
  meta tag as a block token.

* A better solution with an eye towards the longer-term is to emit
  mw:DOMFragment wrapper for the references tag with the content
  being an ol-node. The dom-fragment unpacking code then takes care
  of p-wrapping issues for the ol-node. This fixes the bug in this
  case.

* Also fixed parser tests output where group attribute was missing
  on some tests (which indicated that the older code was not emitting
  the group attribute on references tag).

* No change in parser tests.

Change-Id: I073b2e68667d577c75cad07d19cea2b19d0e89fe
This commit is contained in:
Subramanya Sastry 2013-06-26 12:35:08 -05:00
parent 53bbcbb37e
commit 213f968282

View file

@ -6,6 +6,8 @@
var Util = require( './mediawiki.Util.js' ).Util,
DU = require( './mediawiki.DOMUtils.js').DOMUtils,
coreutil = require('util'),
ExtensionHandler = require('./ext.core.ExtensionHandler.js').ExtensionHandler,
defines = require('./mediawiki.parser.defines.js'),
$ = require( './fakejquery' );
@ -253,6 +255,9 @@ function References(cite) {
this.reset();
}
// Inherit functionality from ExtensionHandler
coreutil.inherits(References, ExtensionHandler);
References.prototype.reset = function(group) {
if (group) {
setRefGroup(this.refGroups, group, undefined);
@ -281,21 +286,40 @@ References.prototype.handleReferences = function ( manager, pipelineOpts, refsTo
group = null;
}
// Emit a placeholder meta for the references token
// so that the dom post processor can generate and
// emit references at this point in the DOM.
var emitMarkerMeta = function() {
var marker = new SelfclosingTagTk('meta', refsTok.attribs, refsTok.dataAttribs);
// Emit a marker mw:DOMFragment for the references
// token so that the dom post processor can generate
// and emit references at this point in the DOM.
var emitReferencesFragment = function() {
var about = manager.env.newAboutId(),
type = refsTok.getAttribute('typeof');
var buf = [
"<ol class='references'",
" typeof='", "mw:Extension/references", "'",
" about='", about, "'",
"></ol>"
];
marker.dataAttribs.stx = undefined;
DU.addAttributes(marker, {
'about': manager.env.newAboutId(),
'group': group,
'typeof': 'mw:Extension/references/Marker'
});
cb({ tokens: [marker], async: false });
var wrapperDOM = Util.parseHTML(buf.join('')).body.childNodes;
wrapperDOM[0].setAttribute('source', refsTok.getAttribute('source'));
if (group) {
wrapperDOM[0].setAttribute('group', group);
}
var expansion = {
nodes: wrapperDOM,
html: wrapperDOM.map(function(n) { return n.outerHTML; }).join('')
};
// TemplateHandler wants a manager property
//
// FIXME: Seems silly -- maybe we should move encapsulateExpansionHTML
// into Util and pass env into it .. can avoid extending ExtensionHandler
// as well.
this.manager = manager;
cb({ tokens: this.encapsulateExpansionHTML(refsTok, expansion), async: false });
}.bind(this);
processExtSource(manager, refsTok, {
// Partial pipeline for processing ref-content
// Expand till stage 2 so that all embedded
@ -307,7 +331,7 @@ References.prototype.handleReferences = function ( manager, pipelineOpts, refsTo
},
res: [],
parentCB: cb,
emptyContentCB: emitMarkerMeta,
emptyContentCB: emitReferencesFragment,
chunkCB: function(chunk) {
// Extract ref-content tokens and discard the rest
var res = [];
@ -324,7 +348,7 @@ References.prototype.handleReferences = function ( manager, pipelineOpts, refsTo
// Pass along the ref toks
cb({ tokens: res, async: true });
},
endCB: emitMarkerMeta
endCB: emitReferencesFragment
});
};
@ -401,9 +425,7 @@ References.prototype.insertReferencesIntoDOM = function(refsNode) {
src = refsNode.getAttribute('source'),
// Extract ext-source for <references>..</references> usage
body = Util.extractExtBody("references", src).trim(),
refGroup = getRefGroup(this.refGroups, group),
ol = refsNode.ownerDocument.createElement('ol'),
nodeType = (refsNode.getAttribute("typeof") || '').replace(/mw:Extension\/references\/Marker/, '');
refGroup = getRefGroup(this.refGroups, group);
var dataMW = refsNode.getAttribute('data-mw');
if (!dataMW) {
@ -421,18 +443,12 @@ References.prototype.insertReferencesIntoDOM = function(refsNode) {
});
}
DU.addAttributes(ol, {
'about': about,
'class': 'references',
'data-mw': dataMW,
'typeof': nodeType
});
DU.addTypeOf(ol, "mw:Extension/references");
ol.data = refsNode.data;
refsNode.removeAttribute('source');
refsNode.setAttribute('data-mw', dataMW);
if (refGroup) {
refGroup.refs.map(refGroup.renderLine.bind(refGroup, ol));
refGroup.refs.map(refGroup.renderLine.bind(refGroup, refsNode));
}
refsNode.parentNode.replaceChild(ol, refsNode);
// reset
this.reset(group);