jenkins-bot has submitted this change and it was merged.

Change subject: Updated editing support for tpl args with nowiki escaping in 
arg wt
......................................................................


Updated editing support for tpl args with nowiki escaping in arg wt

* String fragments in edited params that might interfere with
  wikitext parsing are escaped.  Tokenizes the arg and tests string
  tokens for bad chars.

* TODO: Figure out a way to test this functionality.

* Tested with these and other combinations:

[subbu@earth tests] echo "{{echo | foo}}" | node parse | sed 's/foo/[[
[[ }} {{ bar }} | baz]]/g;' | node parse --html2wt --editMode
{{echo |<nowiki> [[ [[ }} </nowiki>{{ bar }}<nowiki> | baz]]</nowiki>}}

[subbu@earth tests] echo "{{echo | foo}}" | node parse | sed 's/foo/[[
[[ {{ bar }} | baz]]/g;' | node parse --html2wt --editMode
{{echo |<nowiki> [[ </nowiki>[[ {{ bar }} | baz]]}}

[subbu@earth tests] echo "{{echo | foo}}" | node parse | sed 's/foo/[[
{{ bar }} | baz]]/g;' | node parse --html2wt --editMode
{{echo | [[ {{ bar }} | baz]]}}

[subbu@earth tests] echo "{{echo|foo}}" | node parse | sed
's/"foo"/"<s>a}}"/g;' | node parse --html2wt --editMode
{{echo|<nowiki><s>a}}</nowiki>}}

[subbu@earth tests] echo "{{echo|foo}}" | node parse | sed
's/"foo"/"{{a<\/s>"/g;' | node parse --html2wt --editMode
{{echo|<nowiki>{{a</nowiki></s>}}

[subbu@earth tests] echo "{{echo|foo}}" | node parse | sed
's/"foo"/"{{a}}<\/s>"/g;' | node parse --html2wt --editMode
{{echo|{{a}}</s>}}

[subbu@earth tests] echo "{{echo|foo}}" | node parse | sed
's/"foo"/"<s>{{a}}"/g;' | node parse --html2wt --editMode
{{echo|<nowiki><s>{{a}}</nowiki>}}

Change-Id: If1b9c7c1c22dd9a012b5afa48f37c0bc7fd0a165
---
M js/lib/mediawiki.WikitextSerializer.js
1 file changed, 105 insertions(+), 32 deletions(-)

Approvals:
  GWicke: Looks good to me, approved
  jenkins-bot: Verified



diff --git a/js/lib/mediawiki.WikitextSerializer.js 
b/js/lib/mediawiki.WikitextSerializer.js
index 8ff92bf..6db9b41 100644
--- a/js/lib/mediawiki.WikitextSerializer.js
+++ b/js/lib/mediawiki.WikitextSerializer.js
@@ -189,32 +189,8 @@
        // console.warn("---HWT---:onl:" + onNewline + ":" + text);
        // tokenize the text
 
-       var prefixedText = text;
-       if (!onNewline) {
-               // Prefix '_' so that no start-of-line wiki syntax matches.
-               // Later, strip it from the result.
-               // Ex: Consider the DOM:  <ul><li> foo</li></ul>
-               // We don't want ' foo' to be converted to a <pre>foo</pre>
-               // because of the leading space.
-               prefixedText = '_' + text;
-       }
-
-       if ( state.inIndentPre || state.inPHPBlock ) {
-               prefixedText = prefixedText.replace(/(\r?\n)/g, '$1_');
-       }
-
-       var p = new PegTokenizer( state.env ), tokens = [];
-       p.on('chunk', function ( chunk ) {
-               // Avoid a stack overflow if chunk is large, but still update 
token
-               // in-place
-               for ( var ci = 0, l = chunk.length; ci < l; ci++ ) {
-                       tokens.push(chunk[ci]);
-               }
-       });
-       p.on('end', function(){ });
-
-       // The code below will break if use async tokenization.
-       p.processSync( prefixedText );
+       var sol = onNewline && !(state.inIndentPre || state.inPPHPBlock);
+       var tokens = state.serializer.tokenizeStr(state, text, sol);
 
        // If the token stream has a pd.TagTk, pd.SelfclosingTagTk, pd.EndTagTk 
or pd.CommentTk
        // then this text needs escaping!
@@ -550,6 +526,25 @@
        return ["<nowiki>", match[1], "</nowiki>", match[2]].join('');
 }
 
+WSP.tokenizeStr = function(state, str, sol) {
+       var p = new PegTokenizer( state.env ), tokens = [];
+       p.on('chunk', function ( chunk ) {
+               // Avoid a stack overflow if chunk is large,
+               // but still update token in-place
+               for ( var ci = 0, l = chunk.length; ci < l; ci++ ) {
+                       tokens.push(chunk[ci]);
+               }
+       });
+       p.on('end', function(){ });
+
+       // Init sol state
+       p.savedSOL = sol;
+
+       // The code below will break if use async tokenization.
+       p.processSync(str);
+       return tokens;
+};
+
 WSP.escapeWikiText = function ( state, text, opts ) {
        // console.warn("---EWT:ALL1---");
     // console.warn("t: " + text);
@@ -692,9 +687,87 @@
        }
 };
 
-WSP.escapeTplArgWT = function(arg) {
-       // FIXME: to be done
-       return arg;
+/**
+ * General strategy:
+ *
+ * Tokenize the arg wikitext.  Anything that parses as tags
+ * are good and we need not bother with those.  Check for harmful
+ * characters "[]{}|=" in any strings and escape those fragments
+ * since these characters could change semantics of the entire
+ * template transclusion.
+ *
+ * This function makes a couple of assumptions:
+ *
+ * 1. Each arg's wikitext has balanced opening and closing tags.
+ *    The code does make some attempt to deal with unclosed opening
+ *    and closing tags, but this may not work accurately in all cases.
+ *
+ * 2. The tokenizer sets tsr on all non-string tokens.
+ */
+WSP.escapeTplArgWT = function(state, arg) {
+       function escapeStr(str, buf) {
+               if (str.match(/[\{\[\]\}\|\=]/)) {
+                       buf.push("<nowiki>");
+                       buf.push(str);
+                       buf.push("</nowiki>");
+               } else {
+                       buf.push(str);
+               }
+       }
+
+       var tokens = this.tokenizeStr(state, arg, false);
+       var offset = 0, openTags = [], buf = [];
+       for (var i = 0, n = tokens.length; i < n; i++) {
+               var t = tokens[i], da = t.dataAttribs;
+               switch (t.constructor) {
+                       case pd.TagTk:
+                               if (openTags.length === 0) {
+                                       offset = da.tsr[0];
+                               }
+                               openTags.push(t);
+                               break;
+
+                       case pd.EndTagTk:
+                               if (openTags.length > 0) {
+                                       openTags.pop();
+                               }
+                               if (openTags.length === 0) {
+                                       var e = da.tsr[1];
+                                       buf.push(arg.substring(offset, e));
+                                       offset = e;
+                               }
+                               break;
+
+                       case pd.NlTk:
+                       case pd.Comment:
+                       case pd.SelfclosingTagTk:
+                               if (openTags.length === 0) {
+                                       buf.push(arg.substring(da.tsr[0], 
da.tsr[1]));
+                                       offset = da.tsr[1];
+                               }
+                               break;
+
+                       case String:
+                               if (openTags.length === 0) {
+                                       escapeStr(t, buf);
+                                       offset += t.length;
+                               }
+                               break;
+
+                       case pd.EOFTk:
+                               // Deal with any unprocessed fragments (that 
should exist
+                               // only if we have unbalanced opening/closing 
tags).
+                               var str = arg.substring(offset, arg.length);
+                               if (openTags.length === 0) {
+                                       buf.push(str);
+                               } else {
+                                       escapeStr(str, buf);
+                               }
+                               break;
+               }
+       }
+
+       return buf.join('');
 };
 
 /**
@@ -2076,7 +2149,7 @@
                        node, state, cb);
 };
 
-WSP._buildTemplateWT = function(srcParts) {
+WSP._buildTemplateWT = function(state, srcParts) {
        var buf = [],
                serializer = this;
        srcParts.map(function(part) {
@@ -2094,7 +2167,7 @@
                        if (n > 0) {
                                for (var i = 0; i < n; i++) {
                                        var k = keys[i],
-                                               v = 
serializer.escapeTplArgWT(tpl.params[k].wt);
+                                               v = 
serializer.escapeTplArgWT(state, tpl.params[k].wt);
                                        if (k === (i+1).toString()) {
                                                argBuf.push(v);
                                        } else {
@@ -2168,7 +2241,7 @@
                                        } else {
                                                var dataMW = 
JSON.parse(node.getAttribute("data-mw"));
                                                if (dataMW) {
-                                                       src = 
state.serializer._buildTemplateWT(dataMW.parts || [{ template: dataMW }]);
+                                                       src = 
state.serializer._buildTemplateWT(state, dataMW.parts || [{ template: dataMW 
}]);
                                                } else {
                                                        console.error("ERROR: 
No data-mw for: " + node.outerHTML);
                                                        src = dp.src;

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

Gerrit-MessageType: merged
Gerrit-Change-Id: If1b9c7c1c22dd9a012b5afa48f37c0bc7fd0a165
Gerrit-PatchSet: 3
Gerrit-Project: mediawiki/extensions/Parsoid
Gerrit-Branch: master
Gerrit-Owner: Subramanya Sastry <[email protected]>
Gerrit-Reviewer: Cscott <[email protected]>
Gerrit-Reviewer: GWicke <[email protected]>
Gerrit-Reviewer: jenkins-bot

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to