Arlolra has uploaded a new change for review. ( https://gerrit.wikimedia.org/r/380899 )
Change subject: [WIP] Seperate emitSep ...................................................................... [WIP] Seperate emitSep Change-Id: I92953d00580bf8ad7d5e34a0d804931991da1e43 --- M lib/html2wt/SerializerState.js M lib/html2wt/WikitextSerializer.js M tests/parserTests-blacklist.js 3 files changed, 75 insertions(+), 68 deletions(-) git pull ssh://gerrit.wikimedia.org:29418/mediawiki/services/parsoid refs/changes/99/380899/1 diff --git a/lib/html2wt/SerializerState.js b/lib/html2wt/SerializerState.js index eb93757..5efe9e0 100644 --- a/lib/html2wt/SerializerState.js +++ b/lib/html2wt/SerializerState.js @@ -287,6 +287,74 @@ function() { return JSON.stringify(sep.text); }); }; +/* -------------------------------------------------------------------------- + * When block nodes are deleted, the deletion affects whether unmodified + * newline separators between a pair of unmodified P tags can be reused. + * + * Example: + * Original WT : "<div>x</div>foo\nbar" + * Original HTML: "<div>x</div><p>foo</p>\n<p>bar</p>" + * Edited HTML : "<p>foo</p>\n<p>bar</p>" + * Annotated DOM: "<mw:DiffMarker is-block><p>foo</p>\n<p>bar</p>" + * Expected WT : "foo\n\nbar" + * + * Note the additional newline between "foo" and "bar" even though originally, + * there was just a single newline. + * + * So, even though the two P tags and the separator between them is + * unmodified, it is insufficient to rely on just that. We have to look at + * what has happened on the two wikitext lines onto which the two P tags + * will get serialized. + * + * Now, if you check the code for 'nextToDeletedBlockNodeInWT', that code is + * not really looking at ALL the nodes before/after the nodes that could + * serialize onto the wikitext lines. It is looking at the immediately + * adjacent nodes, i.e. it is not necessary to look if a block-tag was + * deleted 2 or 5 siblings away. If we had to actually examine all of those, + * nodes, this would get very complex, and it would be much simpler to just + * discard the original separators => potentially lots of dirty diffs. + * + * To understand why it is sufficient (for correctness) to examine just + * the immediately adjacent nodes, let us look at an additional example. + * + * Original WT : "a<div>b</div>c<div>d</div>e\nf" + * Original HTML: "<p>a</p><div>b</div><p>c</p><div>d</div><p>e</p>\n<p>f</p>" + * + * Note how <block> tags and <p> tags interleave in the HTML. This would be + * the case always no matter how much inline content showed up between the + * block tags in wikitext. If the b-<div> was deleted, we don't care + * about it, since we still have the d-<div> before the P tag that preserves + * the correctness of the single "\n" separator. If the d-<div> was deleted, + * we conservatively ignore the original separator and let normal P-P constraints + * take care of it. At worst, we might generate a dirty diff in this scenario. + * -------------------------------------------------------------------------- */ +SSP.emitSep = function(node) { + var origSepUsable = + this.prevNodeUnmodified && !DU.nextToDeletedBlockNodeInWT(this.env, this.sep.lastSourceNode, true) && + this.currNodeUnmodified && !DU.nextToDeletedBlockNodeInWT(this.env, node, false); + + var origSep; + if (origSepUsable) { + if (this.prevNode && DU.isElt(this.prevNode) && DU.isElt(node)) { + origSep = this.getOrigSrc( + DU.getDataParsoid(this.prevNode).dsr[1], + DU.getDataParsoid(node).dsr[0] + ); + } else { + origSep = this.sep.src; + } + } + + if (origSep !== undefined && WTSUtils.isValidSep(origSep)) { + this.pushSep(origSep, node, 'ORIG-SEP:'); + } else { + var sep = this.serializer.buildSep(node); + if (sep !== undefined) { + this.pushSep(sep, node, 'SEP:'); + } + } +} + SSP.emitChunk = function(res, node) { if (!(res instanceof String)) { this.env.log('warning', 'Emitting non-string value: ' + String(res)); @@ -298,75 +366,11 @@ res.text = res.text.replace(/\n/g, ' '); } - /* -------------------------------------------------------------------------- - * When block nodes are deleted, the deletion affects whether unmodified - * newline separators between a pair of unmodified P tags can be reused. - * - * Example: - * Original WT : "<div>x</div>foo\nbar" - * Original HTML: "<div>x</div><p>foo</p>\n<p>bar</p>" - * Edited HTML : "<p>foo</p>\n<p>bar</p>" - * Annotated DOM: "<mw:DiffMarker is-block><p>foo</p>\n<p>bar</p>" - * Expected WT : "foo\n\nbar" - * - * Note the additional newline between "foo" and "bar" even though originally, - * there was just a single newline. - * - * So, even though the two P tags and the separator between them is - * unmodified, it is insufficient to rely on just that. We have to look at - * what has happened on the two wikitext lines onto which the two P tags - * will get serialized. - * - * Now, if you check the code for 'nextToDeletedBlockNodeInWT', that code is - * not really looking at ALL the nodes before/after the nodes that could - * serialize onto the wikitext lines. It is looking at the immediately - * adjacent nodes, i.e. it is not necessary to look if a block-tag was - * deleted 2 or 5 siblings away. If we had to actually examine all of those, - * nodes, this would get very complex, and it would be much simpler to just - * discard the original separators => potentially lots of dirty diffs. - * - * To understand why it is sufficient (for correctness) to examine just - * the immediately adjacent nodes, let us look at an additional example. - * - * Original WT : "a<div>b</div>c<div>d</div>e\nf" - * Original HTML: "<p>a</p><div>b</div><p>c</p><div>d</div><p>e</p>\n<p>f</p>" - * - * Note how <block> tags and <p> tags interleave in the HTML. This would be - * the case always no matter how much inline content showed up between the - * block tags in wikitext. If the b-<div> was deleted, we don't care - * about it, since we still have the d-<div> before the P tag that preserves - * the correctness of the single "\n" separator. If the d-<div> was deleted, - * we conservatively ignore the original separator and let normal P-P constraints - * take care of it. At worst, we might generate a dirty diff in this scenario. - * -------------------------------------------------------------------------- */ - var origSepUsable = - this.prevNodeUnmodified && !DU.nextToDeletedBlockNodeInWT(this.env, this.sep.lastSourceNode, true) && - this.currNodeUnmodified && !DU.nextToDeletedBlockNodeInWT(this.env, node, false); - // Emit separator first if (res.noSep) { /* skip separators for internal tokens fromSelSer */ } else { - var origSep; - if (origSepUsable) { - if (this.prevNode && DU.isElt(this.prevNode) && DU.isElt(node)) { - origSep = this.getOrigSrc( - DU.getDataParsoid(this.prevNode).dsr[1], - DU.getDataParsoid(node).dsr[0] - ); - } else { - origSep = this.sep.src; - } - } - - if (origSep !== undefined && WTSUtils.isValidSep(origSep)) { - this.pushSep(origSep, node, 'ORIG-SEP:'); - } else { - var sep = this.serializer.buildSep(node); - if (sep !== undefined) { - this.pushSep(sep, node, 'SEP:'); - } - } + this.emitSep(node); } if (this.onSOL) { @@ -498,9 +502,12 @@ this.currLine.chunks = []; this[inState] = true; + this.updateSep(node); + this.resetCurrLine(node.firstChild); + return this.serializeChildren(node, wtEscaper).then(function() { // Emit child-parent seps. - this.emitChunk('', node); + this.emitSep(node); // We've reached EOF, flush the remaining buffered text. this.flushLine(); diff --git a/lib/html2wt/WikitextSerializer.js b/lib/html2wt/WikitextSerializer.js index 8a414e2..691ddb4 100644 --- a/lib/html2wt/WikitextSerializer.js +++ b/lib/html2wt/WikitextSerializer.js @@ -1341,7 +1341,7 @@ return state.serializeChildren(body).then(function() { // Emit child-parent seps. - state.emitChunk('', body); + state.emitSep(body); // We've reached EOF, flush the remaining buffered text. state.flushLine(); diff --git a/tests/parserTests-blacklist.js b/tests/parserTests-blacklist.js index 583c919..d6f73af 100644 --- a/tests/parserTests-blacklist.js +++ b/tests/parserTests-blacklist.js @@ -413,7 +413,7 @@ add("html2html", "T93580: 3. Templated <ref> inside inline images", "<p data-parsoid='{\"dsr\":[0,98,0,0]}'><span class=\"mw-default-size\" typeof=\"mw:Image\" data-parsoid='{\"optList\":[{\"ck\":\"caption\",\"ak\":\"Undisplayed caption in inline image with ref: {{echo|<ref>{{echo|foo}}</ref>}}\"}],\"dsr\":[0,98,null,null]}' data-mw='{\"caption\":\"Undisplayed caption in inline image with ref: <span about=\\\"#mwt3\\\" class=\\\"mw-ref\\\" id=\\\"cite_ref-1\\\" rel=\\\"dc:references\\\" typeof=\\\"mw:Transclusion mw:Extension/ref\\\" data-parsoid='{\\\"dsr\\\":[64,96,null,null],\\\"pi\\\":[[{\\\"k\\\":\\\"1\\\"}]]}' data-mw='{\\\"parts\\\":[{\\\"template\\\":{\\\"target\\\":{\\\"wt\\\":\\\"echo\\\",\\\"href\\\":\\\"./Template:Echo\\\"},\\\"params\\\":{\\\"1\\\":{\\\"wt\\\":\\\"&lt;ref>{{echo|foo}}&lt;/ref>\\\"}},\\\"i\\\":0}}]}'><a href=\\\"./Main_Page#cite_note-1\\\" style=\\\"counter-reset: mw-Ref 1;\\\" data-parsoid=\\\"{}\\\"><span class=\\\"mw-reflink-text\\\" data-parsoid=\\\"{}\\\">[1]</span></a></span><meta typeof=\\\"mw:Transclusion mw:Extension/ref/Marker\\\" about=\\\"#mwt3\\\" data-parsoid='{\\\"group\\\":\\\"\\\",\\\"name\\\":\\\"\\\",\\\"content\\\":\\\"foo\\\",\\\"hasRefInRef\\\":false,\\\"dsr\\\":[64,96,null,null],\\\"pi\\\":[[{\\\"k\\\":\\\"1\\\"}]]}' data-mw='{\\\"parts\\\":[{\\\"template\\\":{\\\"target\\\":{\\\"wt\\\":\\\"echo\\\",\\\"href\\\":\\\"./Template:Echo\\\"},\\\"params\\\":{\\\"1\\\":{\\\"wt\\\":\\\"&lt;ref>{{echo|foo}}&lt;/ref>\\\"}},\\\"i\\\":0}}]}'/>\"}'><a href=\"./File:Foobar.jpg\" data-parsoid='{\"a\":{\"href\":\"./File:Foobar.jpg\"},\"sa\":{\"href\":\"File:Foobar.jpg\"}}'><img resource=\"./File:Foobar.jpg\" src=\"//example.com/images/3/3a/Foobar.jpg\" data-file-width=\"1941\" data-file-height=\"220\" data-file-type=\"bitmap\" height=\"220\" width=\"1941\" data-parsoid='{\"a\":{\"resource\":\"./File:Foobar.jpg\",\"height\":\"220\",\"width\":\"1941\"},\"sa\":{\"resource\":\"File:Foobar.jpg\"}}'/></a></span></p>\n\n<ol class=\"mw-references references\" typeof=\"mw:Extension/references\" about=\"#mwt7\" data-parsoid='{\"dsr\":[100,114,2,2]}' data-mw='{\"name\":\"references\",\"attrs\":{}}'><li about=\"#cite_note-1\" id=\"cite_note-1\"><a href=\"./Main_Page#cite_ref-1\" rel=\"mw:referencedBy\"><span class=\"mw-linkback-text\">↑ </span></a> <span id=\"mw-reference-text-cite_note-1\" class=\"mw-reference-text\" data-parsoid=\"{}\">foo</span></li></ol>"); add("html2html", "Subpage link", "<p data-parsoid='{\"dsr\":[0,38,0,0]}'><a rel=\"mw:WikiLink\" href=\"./Wiki/Subpage_test/subpage\" title=\"Wiki/Subpage test/subpage\" data-parsoid='{\"stx\":\"piped\",\"a\":{\"href\":\"./Wiki/Subpage_test/subpage\"},\"sa\":{\"href\":\"wiki/Subpage test/subpage\"},\"dsr\":[0,38,28,2]}'>/subpage</a></p>\n"); add("html2html", "Subpage noslash link", "<p data-parsoid='{\"dsr\":[0,37,0,0]}'><a rel=\"mw:WikiLink\" href=\"./Wiki/Subpage_test/subpage\" title=\"Wiki/Subpage test/subpage\" data-parsoid='{\"stx\":\"piped\",\"a\":{\"href\":\"./Wiki/Subpage_test/subpage\"},\"sa\":{\"href\":\"wiki/Subpage test/subpage\"},\"dsr\":[0,37,28,2]}'>subpage</a></p>\n"); -add("html2html", "Render invalid page names as plain text (T53090)", "<p data-parsoid='{\"dsr\":[0,172,0,0]}'>[[./../foo|bar]]\n[[foo�|bar]]\n[[foo/.|bar]]\n[[foo/..|bar]]\n<span typeof=\"mw:Nowiki\" data-parsoid='{\"dsr\":[59,89,8,9]}'>[[foo~~~bar]]</span>\n[[foo>bar]]\n[[foo[bar]]\n[[.]]\n[[..]]\n[[foo././bar]]\n[[foo<a rel=\"mw:ExtLink\" href=\"http://example.com\" data-parsoid='{\"targetOff\":166,\"contentOffsets\":[166,166],\"dsr\":[147,167,19,1]}'></a>xyz]]</p>\n\n<p data-parsoid='{\"dsr\":[174,420,0,0]}'>[[<span about=\"#mwt36\" typeof=\"mw:Transclusion\" data-parsoid='{\"pi\":[[{\"k\":\"1\"}]],\"dsr\":[176,193,null,null]}' data-mw='{\"parts\":[{\"template\":{\"target\":{\"wt\":\"echo\",\"href\":\"./Template:Echo\"},\"params\":{\"1\":{\"wt\":\"./../foo\"}},\"i\":0}}]}'>./../foo</span>|bar]]\n[[<span about=\"#mwt37\" typeof=\"mw:Transclusion\" data-parsoid='{\"pi\":[[{\"k\":\"1\"}]],\"dsr\":[202,216,null,null]}' data-mw='{\"parts\":[{\"template\":{\"target\":{\"wt\":\"echo\",\"href\":\"./Template:Echo\"},\"params\":{\"1\":{\"wt\":\"foo/.\"}},\"i\":0}}]}'>foo/.</span>|bar]]\n[[<span about=\"#mwt38\" typeof=\"mw:Transclusion\" data-parsoid='{\"pi\":[[{\"k\":\"1\"}]],\"dsr\":[225,240,null,null]}' data-mw='{\"parts\":[{\"template\":{\"target\":{\"wt\":\"echo\",\"href\":\"./Template:Echo\"},\"params\":{\"1\":{\"wt\":\"foo/..\"}},\"i\":0}}]}'>foo/..</span>|bar]]\n[[<span about=\"#mwt39\" typeof=\"mw:Transclusion\" data-parsoid='{\"pi\":[[{\"k\":\"1\"}]],\"dsr\":[249,268,null,null]}' data-mw='{\"parts\":[{\"template\":{\"target\":{\"wt\":\"echo\",\"href\":\"./Template:Echo\"},\"params\":{\"1\":{\"wt\":\"foo~~~~bar\"}},\"i\":0}}]}'>foo~~~~bar</span>]]\n[[<span about=\"#mwt40\" typeof=\"mw:Transclusion\" data-parsoid='{\"pi\":[[{\"k\":\"1\"}]],\"dsr\":[273,289,null,null]}' data-mw='{\"parts\":[{\"template\":{\"target\":{\"wt\":\"echo\",\"href\":\"./Template:Echo\"},\"params\":{\"1\":{\"wt\":\"foo>bar\"}},\"i\":0}}]}'>foo>bar</span>]]\n[[<span about=\"#mwt41\" typeof=\"mw:Transclusion\" data-parsoid='{\"pi\":[[{\"k\":\"1\"}]],\"dsr\":[294,313,null,null]}' data-mw='{\"parts\":[{\"template\":{\"target\":{\"wt\":\"echo\",\"href\":\"./Template:Echo\"},\"params\":{\"1\":{\"wt\":\"foo././bar\"}},\"i\":0}}]}'>foo././bar</span>]]\n[[<span about=\"#mwt42\" typeof=\"mw:Transclusion\" data-parsoid='{\"pi\":[[{\"k\":\"1\"}]],\"dsr\":[318,334,null,null]}' data-mw='{\"parts\":[{\"template\":{\"target\":{\"wt\":\"echo\",\"href\":\"./Template:Echo\"},\"params\":{\"1\":{\"wt\":\"foo{bar\"}},\"i\":0}}]}'>foo{bar</span>]]\n[[<span about=\"#mwt43\" typeof=\"mw:Transclusion\" data-parsoid='{\"pi\":[[{\"k\":\"1\"}]],\"dsr\":[339,355,null,null]}' data-mw='{\"parts\":[{\"template\":{\"target\":{\"wt\":\"echo\",\"href\":\"./Template:Echo\"},\"params\":{\"1\":{\"wt\":\"foo}bar\"}},\"i\":0}}]}'>foo}bar</span>]]\n[[<span about=\"#mwt44\" typeof=\"mw:Transclusion\" data-parsoid='{\"pi\":[[{\"k\":\"1\"}]],\"dsr\":[360,376,null,null]}' data-mw='{\"parts\":[{\"template\":{\"target\":{\"wt\":\"echo\",\"href\":\"./Template:Echo\"},\"params\":{\"1\":{\"wt\":\"foo[bar\"}},\"i\":0}}]}'>foo[bar</span>]]\n[[<span about=\"#mwt45\" typeof=\"mw:Transclusion\" data-parsoid='{\"pi\":[[{\"k\":\"1\"}]],\"dsr\":[381,397,null,null]}' data-mw='{\"parts\":[{\"template\":{\"target\":{\"wt\":\"echo\",\"href\":\"./Template:Echo\"},\"params\":{\"1\":{\"wt\":\"foo]bar\"}},\"i\":0}}]}'>foo]bar</span>]]\n[[<span about=\"#mwt46\" typeof=\"mw:Transclusion\" data-parsoid='{\"pi\":[[{\"k\":\"1\"}]],\"dsr\":[402,418,null,null]}' data-mw='{\"parts\":[{\"template\":{\"target\":{\"wt\":\"echo\",\"href\":\"./Template:Echo\"},\"params\":{\"1\":{\"wt\":\"foo<bar\"}},\"i\":0}}]}'>foo<bar</span>]]</p>\n"); +add("html2html", "Render invalid page names as plain text (T53090)", "<p data-parsoid='{\"dsr\":[0,172,0,0]}'>[[./../foo|bar]]\n[[foo�|bar]]\n[[foo/.|bar]]\n[[foo/..|bar]]\n<span typeof=\"mw:Nowiki\" data-parsoid='{\"dsr\":[59,89,8,9]}'>[[foo~~~bar]]</span>\n[[foo>bar]]\n[[foo[bar]]\n[[.]]\n[[..]]\n[[foo././bar]]\n[[foo<a rel=\"mw:ExtLink\" href=\"http://example.com\" data-parsoid='{\"targetOff\":166,\"contentOffsets\":[166,166],\"dsr\":[147,167,19,1]}'></a>xyz]]</p>\n\n<p data-parsoid='{\"dsr\":[174,420,0,0]}'>[[<span about=\"#mwt35\" typeof=\"mw:Transclusion\" data-parsoid='{\"pi\":[[{\"k\":\"1\"}]],\"dsr\":[176,193,null,null]}' data-mw='{\"parts\":[{\"template\":{\"target\":{\"wt\":\"echo\",\"href\":\"./Template:Echo\"},\"params\":{\"1\":{\"wt\":\"./../foo\"}},\"i\":0}}]}'>./../foo</span>|bar]]\n[[<span about=\"#mwt36\" typeof=\"mw:Transclusion\" data-parsoid='{\"pi\":[[{\"k\":\"1\"}]],\"dsr\":[202,216,null,null]}' data-mw='{\"parts\":[{\"template\":{\"target\":{\"wt\":\"echo\",\"href\":\"./Template:Echo\"},\"params\":{\"1\":{\"wt\":\"foo/.\"}},\"i\":0}}]}'>foo/.</span>|bar]]\n[[<span about=\"#mwt37\" typeof=\"mw:Transclusion\" data-parsoid='{\"pi\":[[{\"k\":\"1\"}]],\"dsr\":[225,240,null,null]}' data-mw='{\"parts\":[{\"template\":{\"target\":{\"wt\":\"echo\",\"href\":\"./Template:Echo\"},\"params\":{\"1\":{\"wt\":\"foo/..\"}},\"i\":0}}]}'>foo/..</span>|bar]]\n[[<span about=\"#mwt38\" typeof=\"mw:Transclusion\" data-parsoid='{\"pi\":[[{\"k\":\"1\"}]],\"dsr\":[249,268,null,null]}' data-mw='{\"parts\":[{\"template\":{\"target\":{\"wt\":\"echo\",\"href\":\"./Template:Echo\"},\"params\":{\"1\":{\"wt\":\"foo~~~~bar\"}},\"i\":0}}]}'>foo~~~~bar</span>]]\n[[<span about=\"#mwt39\" typeof=\"mw:Transclusion\" data-parsoid='{\"pi\":[[{\"k\":\"1\"}]],\"dsr\":[273,289,null,null]}' data-mw='{\"parts\":[{\"template\":{\"target\":{\"wt\":\"echo\",\"href\":\"./Template:Echo\"},\"params\":{\"1\":{\"wt\":\"foo>bar\"}},\"i\":0}}]}'>foo>bar</span>]]\n[[<span about=\"#mwt40\" typeof=\"mw:Transclusion\" data-parsoid='{\"pi\":[[{\"k\":\"1\"}]],\"dsr\":[294,313,null,null]}' data-mw='{\"parts\":[{\"template\":{\"target\":{\"wt\":\"echo\",\"href\":\"./Template:Echo\"},\"params\":{\"1\":{\"wt\":\"foo././bar\"}},\"i\":0}}]}'>foo././bar</span>]]\n[[<span about=\"#mwt41\" typeof=\"mw:Transclusion\" data-parsoid='{\"pi\":[[{\"k\":\"1\"}]],\"dsr\":[318,334,null,null]}' data-mw='{\"parts\":[{\"template\":{\"target\":{\"wt\":\"echo\",\"href\":\"./Template:Echo\"},\"params\":{\"1\":{\"wt\":\"foo{bar\"}},\"i\":0}}]}'>foo{bar</span>]]\n[[<span about=\"#mwt42\" typeof=\"mw:Transclusion\" data-parsoid='{\"pi\":[[{\"k\":\"1\"}]],\"dsr\":[339,355,null,null]}' data-mw='{\"parts\":[{\"template\":{\"target\":{\"wt\":\"echo\",\"href\":\"./Template:Echo\"},\"params\":{\"1\":{\"wt\":\"foo}bar\"}},\"i\":0}}]}'>foo}bar</span>]]\n[[<span about=\"#mwt43\" typeof=\"mw:Transclusion\" data-parsoid='{\"pi\":[[{\"k\":\"1\"}]],\"dsr\":[360,376,null,null]}' data-mw='{\"parts\":[{\"template\":{\"target\":{\"wt\":\"echo\",\"href\":\"./Template:Echo\"},\"params\":{\"1\":{\"wt\":\"foo[bar\"}},\"i\":0}}]}'>foo[bar</span>]]\n[[<span about=\"#mwt44\" typeof=\"mw:Transclusion\" data-parsoid='{\"pi\":[[{\"k\":\"1\"}]],\"dsr\":[381,397,null,null]}' data-mw='{\"parts\":[{\"template\":{\"target\":{\"wt\":\"echo\",\"href\":\"./Template:Echo\"},\"params\":{\"1\":{\"wt\":\"foo]bar\"}},\"i\":0}}]}'>foo]bar</span>]]\n[[<span about=\"#mwt45\" typeof=\"mw:Transclusion\" data-parsoid='{\"pi\":[[{\"k\":\"1\"}]],\"dsr\":[402,418,null,null]}' data-mw='{\"parts\":[{\"template\":{\"target\":{\"wt\":\"echo\",\"href\":\"./Template:Echo\"},\"params\":{\"1\":{\"wt\":\"foo<bar\"}},\"i\":0}}]}'>foo<bar</span>]]</p>\n"); add("html2html", "Disabled subpages", "<p data-parsoid='{\"dsr\":[0,58,0,0]}'>[/index.php?title=/subpage&action=edit&redlink=1 /subpage]</p>\n"); add("html2html", "T2561: {{/Subpage}}", "<p data-parsoid='{\"dsr\":[0,66,0,0]}'>[/index.php?title=Page/Subpage&action=edit&redlink=1 Page/Subpage]</p>\n"); add("html2html", "Link to category", "<p data-parsoid='{\"dsr\":[0,72,0,0]}'><a rel=\"mw:WikiLink\" href=\"./Wiki/Category:MediaWiki_User's_Guide\" title=\"Wiki/Category:MediaWiki User's Guide\" data-parsoid='{\"stx\":\"piped\",\"a\":{\"href\":\"./Wiki/Category:MediaWiki_User's_Guide\"},\"sa\":{\"href\":\"wiki/Category:MediaWiki User's Guide\"},\"dsr\":[0,72,39,2]}'>Category:MediaWiki User's Guide</a></p>\n"); -- To view, visit https://gerrit.wikimedia.org/r/380899 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I92953d00580bf8ad7d5e34a0d804931991da1e43 Gerrit-PatchSet: 1 Gerrit-Project: mediawiki/services/parsoid Gerrit-Branch: master Gerrit-Owner: Arlolra <abrea...@wikimedia.org> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits