Index: trunk/extensions/VisualEditor/modules/parser/mediawiki.TokenTransformManager.js |
— | — | @@ -314,7 +314,7 @@ |
315 | 315 | this._construct(); |
316 | 316 | this._reset( args, env ); |
317 | 317 | // FIXME: pass actual title? |
318 | | - this.loopCheck = new LoopCheck( null ); |
| 318 | + this.loopAndDepthCheck = new LoopAndDepthCheck( null ); |
319 | 319 | } |
320 | 320 | |
321 | 321 | // Inherit from TokenTransformManager, and thus also from EventEmitter. |
— | — | @@ -336,14 +336,12 @@ |
337 | 337 | |
338 | 338 | // now set up a few things on the child AsyncTokenTransformManager. |
339 | 339 | var child = pipe.last; |
340 | | - // We assume that the title was already checked against this.loopCheck |
| 340 | + // We assume that the title was already checked against this.loopAndDepthCheck |
341 | 341 | // before! |
342 | | - child.loopCheck = new LoopCheck ( |
343 | | - this.env.normalizeTitle( this.env.tokensToString ( title ) ), |
344 | | - this.loopCheck |
| 342 | + child.loopAndDepthCheck = new LoopAndDepthCheck ( |
| 343 | + this.loopAndDepthCheck, |
| 344 | + this.env.normalizeTitle( this.env.tokensToString ( title ) ) |
345 | 345 | ); |
346 | | - // Same for depth! |
347 | | - child.depth = this.depth + 1; |
348 | 346 | return pipe; |
349 | 347 | }; |
350 | 348 | |
— | — | @@ -357,7 +355,10 @@ |
358 | 356 | * first stage of the pipeline, and 'last' pointing to the last stage. |
359 | 357 | */ |
360 | 358 | AsyncTokenTransformManager.prototype.getAttributePipeline = function ( inputType, args ) { |
361 | | - return this.childFactories.attributes( inputType, args ); |
| 359 | + var pipe = this.childFactories.attributes( inputType, args ); |
| 360 | + var child = pipe.last; |
| 361 | + child.loopAndDepthCheck = new LoopAndDepthCheck ( this.loopAndDepthCheck, '' ); |
| 362 | + return pipe; |
362 | 363 | }; |
363 | 364 | |
364 | 365 | /** |
— | — | @@ -373,8 +374,6 @@ |
374 | 375 | this.tailAccumulator = undefined; |
375 | 376 | // eventize: bend to event emitter callback |
376 | 377 | this.tokenCB = this._returnTokens.bind( this ); |
377 | | - this.accum = new TokenAccumulator(null); |
378 | | - this.firstaccum = this.accum; |
379 | 378 | this.prevToken = undefined; |
380 | 379 | //console.log( 'AsyncTokenTransformManager args ' + JSON.stringify( args ) ); |
381 | 380 | if ( ! args ) { |
— | — | @@ -412,13 +411,24 @@ |
413 | 412 | AsyncTokenTransformManager.prototype.onChunk = function ( tokens ) { |
414 | 413 | // Set top-level callback to next transform phase |
415 | 414 | var res = this.transformTokens ( tokens, this.tokenCB ); |
416 | | - this.tailAccumulator = res.async; |
417 | | - //console.log('AsyncTokenTransformManager onChunk ', tokens); |
418 | | - //this.phase2TailCB( tokens, true ); |
| 415 | + |
| 416 | + if ( ! this.tailAccumulator ) { |
| 417 | + this.emit( 'chunk', res.tokens ); |
| 418 | + } else { |
| 419 | + this.tailAccumulator.push( res.tokens ); |
| 420 | + } |
| 421 | + |
419 | 422 | if ( res.async ) { |
| 423 | + this.tailAccumulator = res.async; |
420 | 424 | this.tokenCB = res.async.getParentCB ( 'sibling' ); |
421 | 425 | } |
422 | | - this.emit( 'chunk', res.tokens ); |
| 426 | + this.env.dp('AsyncTokenTransformManager onChunk ' + res.async); |
| 427 | + //this.phase2TailCB( tokens, true ); |
| 428 | + |
| 429 | + // The next processed chunk should call back as a sibling to last |
| 430 | + // accumulator, if any. |
| 431 | + if ( res.async ) { |
| 432 | + } |
423 | 433 | }; |
424 | 434 | |
425 | 435 | /** |
— | — | @@ -519,7 +529,8 @@ |
520 | 530 | */ |
521 | 531 | AsyncTokenTransformManager.prototype._returnTokens = function ( tokens, notYetDone ) { |
522 | 532 | //tokens = this._transformPhase2( this.frame, tokens, this.parentCB ); |
523 | | - //console.log('AsyncTokenTransformManager._returnTokens, after _transformPhase2.'); |
| 533 | + this.env.dp('AsyncTokenTransformManager._returnTokens, emitting chunk: ' + |
| 534 | + JSON.stringify( tokens ) ); |
524 | 535 | |
525 | 536 | this.emit( 'chunk', tokens ); |
526 | 537 | |
— | — | @@ -542,9 +553,11 @@ |
543 | 554 | */ |
544 | 555 | AsyncTokenTransformManager.prototype.onEndEvent = function () { |
545 | 556 | if ( this.tailAccumulator ) { |
| 557 | + this.env.dp( 'AsyncTokenTransformManager.onEndEvent: calling siblingDone' ); |
546 | 558 | this.tailAccumulator.siblingDone(); |
547 | 559 | } else { |
548 | 560 | // nothing was asynchronous, so we'll have to emit end here. |
| 561 | + this.env.dp( 'AsyncTokenTransformManager.onEndEvent: synchronous done' ); |
549 | 562 | this.emit('end'); |
550 | 563 | this._reset(); |
551 | 564 | } |
— | — | @@ -650,6 +663,8 @@ |
651 | 664 | } |
652 | 665 | } |
653 | 666 | } |
| 667 | + this.env.dp( 'SyncTokenTransformManager.onChunk: emitting ' + |
| 668 | + JSON.stringify( localAccum ) ); |
654 | 669 | this.emit( 'chunk', localAccum ); |
655 | 670 | }; |
656 | 671 | |
— | — | @@ -685,7 +700,7 @@ |
686 | 701 | this.callback = callback; |
687 | 702 | this.outstanding = 0; |
688 | 703 | this.kvs = []; |
689 | | - this.pipe = manager.getAttributePipeline( manager.args ); |
| 704 | + //this.pipe = manager.getAttributePipeline( manager.args ); |
690 | 705 | } |
691 | 706 | |
692 | 707 | AttributeTransformManager.prototype.process = function ( attributes ) { |
— | — | @@ -834,8 +849,9 @@ |
835 | 850 | //console.log( 'TokenAccumulator._returnTokens' ); |
836 | 851 | if ( reference === 'child' ) { |
837 | 852 | tokens = tokens.concat( this.accum ); |
838 | | - //console.log('TokenAccumulator._returnTokens: ' + |
839 | | - // JSON.stringify( tokens, null, 2 ) |
| 853 | + //console.log('TokenAccumulator._returnTokens child: ' + |
| 854 | + // JSON.stringify( tokens, null, 2 ) + |
| 855 | + // ' outstanding: ' + this.outstanding |
840 | 856 | // ); |
841 | 857 | this.accum = []; |
842 | 858 | // XXX: Use some marker to avoid re-transforming token chunks several |
— | — | @@ -862,7 +878,7 @@ |
863 | 879 | // tokens = res.tokens.concat( this.accum ); |
864 | 880 | // this.accum = []; |
865 | 881 | //} |
866 | | - this.parentCB( tokens, false ); |
| 882 | + this.parentCB( tokens, this.outstanding !== 0 ); |
867 | 883 | return null; |
868 | 884 | } else { |
869 | 885 | // sibling |
— | — | @@ -870,14 +886,22 @@ |
871 | 887 | tokens = this.accum.concat( tokens ); |
872 | 888 | // A sibling will transform tokens, so we don't have to do this |
873 | 889 | // again. |
874 | | - this.parentCB( res.tokens, false ); |
| 890 | + //console.log( 'TokenAccumulator._returnTokens: sibling done and parentCB ' + |
| 891 | + // JSON.stringify( tokens ) ); |
| 892 | + this.parentCB( tokens, false ); |
875 | 893 | return null; |
876 | 894 | } else if ( this.outstanding === 1 && notYetDone ) { |
| 895 | + //console.log( 'TokenAccumulator._returnTokens: sibling done and parentCB but notYetDone ' + |
| 896 | + // JSON.stringify( tokens ) ); |
877 | 897 | // Sibling is not yet done, but child is. Return own parentCB to |
878 | 898 | // allow the sibling to go direct, and call back parent with |
879 | 899 | // tokens. The internal accumulator is empty at this stage, as its |
880 | 900 | // tokens are passed to the parent when the child is done. |
881 | 901 | return this.parentCB( tokens, true); |
| 902 | + } else { |
| 903 | + this.accum = this.accum.concat( tokens ); |
| 904 | + //console.log( 'TokenAccumulator._returnTokens: sibling done, but not overall ' + |
| 905 | + // JSON.stringify( tokens ) ); |
882 | 906 | } |
883 | 907 | |
884 | 908 | |
— | — | @@ -913,10 +937,12 @@ |
914 | 938 | * @class |
915 | 939 | * @constructor |
916 | 940 | */ |
917 | | -function LoopCheck ( title, parent ) { |
| 941 | +function LoopAndDepthCheck ( parent, title ) { |
918 | 942 | if ( parent ) { |
| 943 | + this.depth = parent.depth + 1; |
919 | 944 | this.parent = parent; |
920 | 945 | } else { |
| 946 | + this.depth = 0; |
921 | 947 | this.parent = null; |
922 | 948 | } |
923 | 949 | this.title = title; |
— | — | @@ -928,13 +954,19 @@ |
929 | 955 | * @method |
930 | 956 | * @param {String} Title to check. |
931 | 957 | */ |
932 | | -LoopCheck.prototype.check = function ( title ) { |
| 958 | +LoopAndDepthCheck.prototype.check = function ( title ) { |
| 959 | + // XXX: set limit really low for testing! |
| 960 | + if ( this.depth > 6 ) { |
| 961 | + // too deep |
| 962 | + //console.log( 'Loopcheck: ' + JSON.stringify( this, null, 2 ) ); |
| 963 | + return 'Template expansion depth limit exceeded at '; |
| 964 | + } |
933 | 965 | var elem = this; |
934 | 966 | do { |
935 | 967 | //console.log( 'loop check: ' + title + ' vs ' + elem.title ); |
936 | 968 | if ( elem.title === title ) { |
937 | 969 | // Loop detected |
938 | | - return true; |
| 970 | + return 'Template expansion loop detected at '; |
939 | 971 | } |
940 | 972 | elem = elem.parent; |
941 | 973 | } while ( elem ); |
Index: trunk/extensions/VisualEditor/modules/parser/parse.js |
— | — | @@ -11,7 +11,8 @@ |
12 | 12 | DOMConverter = require('./mediawiki.DOMConverter.js').DOMConverter, |
13 | 13 | optimist = require('optimist'); |
14 | 14 | |
15 | | - var parser = new ParserPipeline( new ParserEnv({ fetchTemplates: true }) ); |
| 15 | + var env = new ParserEnv( { fetchTemplates: true } ), |
| 16 | + parser = new ParserPipeline( env ); |
16 | 17 | |
17 | 18 | |
18 | 19 | process.stdin.resume(); |
— | — | @@ -33,6 +34,12 @@ |
34 | 35 | process.stdout.write( output ); |
35 | 36 | // add a trailing newline for shell user's benefit |
36 | 37 | process.stdout.write( "\n" ); |
| 38 | + |
| 39 | + if ( env.debug ) { |
| 40 | + // Also print out the html |
| 41 | + process.stderr.write( document.body.innerHTML ); |
| 42 | + process.stderr.write( "\n" ); |
| 43 | + } |
37 | 44 | process.exit(0); |
38 | 45 | }); |
39 | 46 | // Kick off the pipeline by feeding the input into the parser pipeline |
Index: trunk/extensions/VisualEditor/modules/parser/ext.core.TemplateHandler.js |
— | — | @@ -22,7 +22,6 @@ |
23 | 23 | } |
24 | 24 | |
25 | 25 | TemplateHandler.prototype.reset = function ( token ) { |
26 | | - this.resultTokens = []; |
27 | 26 | return {token: token}; |
28 | 27 | }; |
29 | 28 | |
— | — | @@ -56,8 +55,6 @@ |
57 | 56 | //console.log('onTemplate! ' + JSON.stringify( token, null, 2 ) + |
58 | 57 | // ' args: ' + JSON.stringify( this.manager.args )); |
59 | 58 | |
60 | | - this.parentCB = cb; |
61 | | - |
62 | 59 | // check for 'subst:' |
63 | 60 | // check for variable magic names |
64 | 61 | // check for msg, msgnw, raw magics |
— | — | @@ -67,10 +64,12 @@ |
68 | 65 | var templateTokenTransformData = { |
69 | 66 | args: {}, |
70 | 67 | manager: this.manager, |
71 | | - outstanding: 1, // Avoid premature finish |
72 | 68 | cb: cb, |
73 | 69 | origToken: token, |
74 | | - isAsync: false |
| 70 | + resultTokens: [], |
| 71 | + attribsAsync: true, |
| 72 | + overallAsync: false, |
| 73 | + expandDone: false |
75 | 74 | }, |
76 | 75 | transformCB, |
77 | 76 | i = 0, |
— | — | @@ -89,17 +88,22 @@ |
90 | 89 | ).process( attributes ); |
91 | 90 | |
92 | 91 | // Unblock finish |
93 | | - templateTokenTransformData.outstanding--; |
94 | | - if ( templateTokenTransformData.outstanding === 0 ) { |
95 | | - //console.log( 'direct call'); |
| 92 | + if ( ! templateTokenTransformData.attribsAsync ) { |
| 93 | + // Attributes were transformed synchronously |
| 94 | + this.manager.env.dp( 'sync attribs for ' + JSON.stringify( token )); |
96 | 95 | // All attributes are fully expanded synchronously (no IO was needed) |
97 | 96 | return this._expandTemplate ( templateTokenTransformData ); |
98 | 97 | } else { |
99 | | - templateTokenTransformData.isAsync = true; |
| 98 | + // Async attribute expansion is going on |
| 99 | + this.manager.env.dp( 'async return for ' + JSON.stringify( token )); |
| 100 | + templateTokenTransformData.overallAsync = true; |
100 | 101 | return { async: true }; |
101 | 102 | } |
102 | 103 | }; |
103 | 104 | |
| 105 | +/** |
| 106 | + * Create positional (number) keys for arguments without explicit keys |
| 107 | + */ |
104 | 108 | TemplateHandler.prototype._nameArgs = function ( orderedArgs ) { |
105 | 109 | var n = 1, |
106 | 110 | out = []; |
— | — | @@ -115,37 +119,49 @@ |
116 | 120 | return out; |
117 | 121 | }; |
118 | 122 | |
| 123 | +/** |
| 124 | + * Callback for argument (including target) expansion in AttributeTransformManager |
| 125 | + */ |
119 | 126 | TemplateHandler.prototype._returnAttributes = function ( templateTokenTransformData, |
120 | 127 | attributes ) |
121 | 128 | { |
122 | | - //console.log( 'TemplateHandler._returnAttributes: ' + JSON.stringify(attributes) ); |
| 129 | + this.manager.env.dp( 'TemplateHandler._returnAttributes: ' + JSON.stringify(attributes) ); |
123 | 130 | // Remove the target from the attributes |
| 131 | + templateTokenTransformData.attribsAsync = false; |
124 | 132 | templateTokenTransformData.target = attributes[0][1]; |
125 | 133 | attributes.shift(); |
126 | 134 | templateTokenTransformData.expandedArgs = attributes; |
127 | | - if ( templateTokenTransformData.isAsync ) { |
| 135 | + if ( templateTokenTransformData.overallAsync ) { |
128 | 136 | this._expandTemplate ( templateTokenTransformData ); |
129 | 137 | } |
130 | 138 | }; |
131 | 139 | |
132 | 140 | /** |
133 | 141 | * Fetch, tokenize and token-transform a template after all arguments and the |
134 | | - * target were expanded in frame. |
| 142 | + * target were expanded. |
135 | 143 | */ |
136 | 144 | TemplateHandler.prototype._expandTemplate = function ( templateTokenTransformData ) { |
137 | 145 | //console.log('TemplateHandler.expandTemplate: ' + |
138 | 146 | // JSON.stringify( templateTokenTransformData, null, 2 ) ); |
| 147 | + |
| 148 | + if ( ! templateTokenTransformData.target ) { |
| 149 | + this.manager.env.dp( 'No target! ' + |
| 150 | + JSON.stringify( templateTokenTransformData, null, 2 ) ); |
| 151 | + console.trace(); |
| 152 | + } |
| 153 | + |
139 | 154 | // First, check the target for loops |
140 | 155 | var target = this.manager.env.normalizeTitle( |
141 | 156 | this.manager.env.tokensToString( templateTokenTransformData.target ) |
142 | 157 | ); |
143 | | - if( this.manager.loopCheck.check( target ) ) { |
| 158 | + var checkRes = this.manager.loopAndDepthCheck.check( target ); |
| 159 | + if( checkRes ) { |
144 | 160 | // Loop detected, abort! |
145 | 161 | return { |
146 | 162 | tokens: [ |
147 | 163 | { |
148 | 164 | type: 'TEXT', |
149 | | - value: 'Template loop detected: ' |
| 165 | + value: checkRes |
150 | 166 | }, |
151 | 167 | { |
152 | 168 | type: 'TAG', |
— | — | @@ -172,6 +188,8 @@ |
173 | 189 | //console.log( 'expanded args: ' + |
174 | 190 | // JSON.stringify( this.manager.env.KVtoHash( |
175 | 191 | // templateTokenTransformData.expandedArgs ) ) ); |
| 192 | + //console.log( 'templateTokenTransformData: ' + |
| 193 | + // JSON.stringify( templateTokenTransformData , null ,2 ) ); |
176 | 194 | |
177 | 195 | var inputPipeline = this.manager.newChildPipeline( |
178 | 196 | this.manager.inputType || 'text/wiki', |
— | — | @@ -179,9 +197,10 @@ |
180 | 198 | templateTokenTransformData.target |
181 | 199 | ); |
182 | 200 | |
183 | | - // Hook up the inputPipeline output events to call back our parentCB. |
184 | | - inputPipeline.addListener( 'chunk', this._onChunk.bind ( this ) ); |
185 | | - inputPipeline.addListener( 'end', this._onEnd.bind ( this ) ); |
| 201 | + // Hook up the inputPipeline output events to call back the parent |
| 202 | + // callback. |
| 203 | + inputPipeline.addListener( 'chunk', this._onChunk.bind ( this, templateTokenTransformData ) ); |
| 204 | + inputPipeline.addListener( 'end', this._onEnd.bind ( this, templateTokenTransformData ) ); |
186 | 205 | |
187 | 206 | |
188 | 207 | // Resolve a possibly relative link |
— | — | @@ -189,9 +208,11 @@ |
190 | 209 | target, |
191 | 210 | 'Template' |
192 | 211 | ); |
193 | | - this._fetchTemplateAndTitle( templateName, |
194 | | - this._processTemplateAndTitle.bind( this, inputPipeline ) |
195 | | - ); |
| 212 | + this._fetchTemplateAndTitle( |
| 213 | + templateName, |
| 214 | + this._processTemplateAndTitle.bind( this, inputPipeline ), |
| 215 | + templateTokenTransformData |
| 216 | + ); |
196 | 217 | |
197 | 218 | // Set up a pipeline: |
198 | 219 | // fetch template source -> tokenizer |
— | — | @@ -213,30 +234,41 @@ |
214 | 235 | // fetch from DB or interwiki |
215 | 236 | // infinte loop check |
216 | 237 | |
217 | | - if ( this.isAsync ) { |
| 238 | + if ( templateTokenTransformData.overallAsync || |
| 239 | + ! templateTokenTransformData.expandDone ) { |
| 240 | + templateTokenTransformData.overallAsync = true; |
| 241 | + this.manager.env.dp( 'Async return from _expandTemplate for ' + |
| 242 | + JSON.stringify ( templateTokenTransformData.target ) ); |
218 | 243 | return { async: true }; |
219 | 244 | } else { |
220 | | - return this.result; |
| 245 | + this.manager.env.dp( 'Sync return from _expandTemplate for ' + |
| 246 | + JSON.stringify( templateTokenTransformData.target ) + ' : ' + |
| 247 | + JSON.stringify( templateTokenTransformData.result ) |
| 248 | + ); |
| 249 | + return templateTokenTransformData.result; |
221 | 250 | } |
222 | 251 | }; |
223 | 252 | |
224 | 253 | |
225 | 254 | /** |
226 | | - * Convert AsyncTokenTransformManager output chunks to parent callbacks |
| 255 | + * Handle chunk emitted from the input pipeline after feeding it a template |
227 | 256 | */ |
228 | | -TemplateHandler.prototype._onChunk = function( chunk ) { |
| 257 | +TemplateHandler.prototype._onChunk = function( data, chunk ) { |
229 | 258 | // We encapsulate the output by default, so collect tokens here. |
230 | | - this.resultTokens = this.resultTokens.concat( chunk ); |
| 259 | + this.manager.env.dp( 'TemplateHandler._onChunk' + JSON.stringify( chunk ) ); |
| 260 | + data.resultTokens = data.resultTokens.concat( chunk ); |
231 | 261 | }; |
232 | 262 | |
233 | 263 | /** |
234 | | - * Handle the end event emitted by the parser pipeline by calling our parentCB |
235 | | - * with notYetDone set to false. |
| 264 | + * Handle the end event emitted by the parser pipeline after fully processing |
| 265 | + * the template source. |
236 | 266 | */ |
237 | | -TemplateHandler.prototype._onEnd = function( token ) { |
| 267 | +TemplateHandler.prototype._onEnd = function( data, token ) { |
238 | 268 | // Encapsulate the template in a single token, which contains all the |
239 | 269 | // information needed for the editor. |
240 | | - var res = this.resultTokens; |
| 270 | + this.manager.env.dp( 'TemplateHandler._onEnd' + JSON.stringify( data.resultTokens ) ); |
| 271 | + data.expandDone = true; |
| 272 | + var res = data.resultTokens; |
241 | 273 | // Remove 'end' token from end |
242 | 274 | if ( res.length && res[res.length - 1].type === 'END' ) { |
243 | 275 | res.pop(); |
— | — | @@ -257,11 +289,14 @@ |
258 | 290 | */ |
259 | 291 | //console.log( 'TemplateHandler._onEnd: ' + JSON.stringify( res, null, 2 ) ); |
260 | 292 | |
261 | | - if ( this.isAsync ) { |
262 | | - this.parentCB( res, false ); |
| 293 | + if ( data.overallAsync ) { |
| 294 | + this.manager.env.dp( 'TemplateHandler._onEnd: calling back with res:' + |
| 295 | + JSON.stringify( res ) ); |
| 296 | + data.cb( res, false ); |
263 | 297 | } else { |
264 | | - this.result = { tokens: res }; |
265 | | - this.reset(); |
| 298 | + this.manager.env.dp( 'TemplateHandler._onEnd: synchronous return!' ); |
| 299 | + data.result = { tokens: res }; |
| 300 | + //data.reset(); |
266 | 301 | } |
267 | 302 | }; |
268 | 303 | |
— | — | @@ -272,7 +307,7 @@ |
273 | 308 | */ |
274 | 309 | TemplateHandler.prototype._processTemplateAndTitle = function( pipeline, src, title ) { |
275 | 310 | // Feed the pipeline. XXX: Support different formats. |
276 | | - //console.log( 'TemplateHandler._processTemplateAndTitle: ' + src ); |
| 311 | + this.manager.env.dp( 'TemplateHandler._processTemplateAndTitle: ' + src ); |
277 | 312 | pipeline.process ( src ); |
278 | 313 | }; |
279 | 314 | |
— | — | @@ -281,7 +316,7 @@ |
282 | 317 | /** |
283 | 318 | * Fetch a template |
284 | 319 | */ |
285 | | -TemplateHandler.prototype._fetchTemplateAndTitle = function( title, callback ) { |
| 320 | +TemplateHandler.prototype._fetchTemplateAndTitle = function( title, callback, data ) { |
286 | 321 | // @fixme normalize name? |
287 | 322 | var self = this; |
288 | 323 | if (title in this.manager.env.pageCache) { |
— | — | @@ -292,8 +327,8 @@ |
293 | 328 | } else { |
294 | 329 | // whee fun hack! |
295 | 330 | |
296 | | - this.isAsync = true; |
297 | | - console.log( 'trying to fetch ' + title ); |
| 331 | + data.overallAsync = true; |
| 332 | + this.manager.env.dp( 'trying to fetch ' + title ); |
298 | 333 | //console.log(this.manager.env.pageCache); |
299 | 334 | var url = this.manager.env.wgScriptPath + '/api' + |
300 | 335 | this.manager.env.wgScriptExtension + |
— | — | @@ -301,46 +336,48 @@ |
302 | 337 | |
303 | 338 | request({ |
304 | 339 | method: 'GET', |
305 | | - //followRedirect: false, |
| 340 | + followRedirect: true, |
306 | 341 | url: url, |
307 | 342 | headers: { |
308 | 343 | 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:9.0.1) Gecko/20100101 Firefox/9.0.1 Iceweasel/9.0.1' |
309 | 344 | } |
310 | 345 | }, |
311 | 346 | function (error, response, body) { |
312 | | - console.log( 'response for ' + title + ': ' + body ); |
| 347 | + //console.log( 'response for ' + title + ' :' + body + ':' ); |
313 | 348 | if(error) { |
314 | | - console.log(error); |
315 | | - callback('Page/template fetch failure for title ' + title); |
| 349 | + self.manager.env.dp(error); |
| 350 | + callback('Page/template fetch failure for title ' + title, title); |
316 | 351 | return ; |
317 | 352 | } |
318 | 353 | |
319 | 354 | if(response.statusCode == 200) { |
320 | | - try{ |
| 355 | + var src = ''; |
| 356 | + try { |
321 | 357 | //console.log( 'body: ' + body ); |
322 | | - data = JSON.parse(body); |
323 | | - var src = null; |
| 358 | + var data = JSON.parse( body ); |
| 359 | + } catch(e) { |
| 360 | + console.log( "Error: while parsing result. Error was: " ); |
| 361 | + console.log( e ); |
| 362 | + console.log( "Response that didn't parse was:"); |
| 363 | + console.log( "------------------------------------------\n" + body ); |
| 364 | + console.log( "------------------------------------------" ); |
| 365 | + } |
| 366 | + try { |
324 | 367 | $.each(data.query.pages, function(i, page) { |
325 | 368 | if (page.revisions && page.revisions.length) { |
326 | 369 | src = page.revisions[0]['*']; |
327 | 370 | title = page.title; |
328 | 371 | } |
329 | 372 | }); |
330 | | - console.log( 'Page ' + title + ': got ' + src ); |
331 | | - self.manager.env.pageCache[title] = src; |
332 | | - callback(src, title); |
333 | | - } catch(e) { |
334 | | - console.log("Error: while parsing result. Error was: "); |
335 | | - console.log(e); |
336 | | - console.log("Response that didn't parse was:\n" + body); |
337 | | - |
338 | | - data = { |
339 | | - error: '', |
340 | | - errorWfMsg: 'chat-err-communicating-with-mediawiki', |
341 | | - errorMsgParams: [] |
342 | | - }; |
| 373 | + } catch ( e ) { |
| 374 | + console.log( 'Did not find page revisions in the returned body:' + body ); |
| 375 | + src = ''; |
343 | 376 | } |
344 | | - console.log(data); |
| 377 | + //console.log( 'Page ' + title + ': got ' + src ); |
| 378 | + self.manager.env.dp( 'Success for ' + title + ' :' + body + ':' ); |
| 379 | + self.manager.env.pageCache[title] = src; |
| 380 | + callback(src, title); |
| 381 | + self.manager.env.dp(data); |
345 | 382 | } |
346 | 383 | }); |
347 | 384 | |
— | — | @@ -389,6 +426,8 @@ |
390 | 427 | }; |
391 | 428 | |
392 | 429 | |
| 430 | +/*********************** Template argument expansion *******************/ |
| 431 | + |
393 | 432 | /** |
394 | 433 | * Expand template arguments with tokens from the containing frame. |
395 | 434 | */ |
Index: trunk/extensions/VisualEditor/modules/parser/mediawiki.parser.environment.js |
— | — | @@ -29,6 +29,10 @@ |
30 | 30 | }; |
31 | 31 | |
32 | 32 | MWParserEnvironment.prototype.KVtoHash = function ( kvs ) { |
| 33 | + if ( ! kvs ) { |
| 34 | + console.log( "Invalid kvs!: " + JSON.stringify( kvs, null, 2 ) ); |
| 35 | + return {}; |
| 36 | + } |
33 | 37 | var res = {}; |
34 | 38 | for ( var i = 0, l = kvs.length; i < l; i++ ) { |
35 | 39 | var kv = kvs[i], |
— | — | @@ -106,13 +110,21 @@ |
107 | 111 | } |
108 | 112 | for ( var i = 0, l = tokens.length; i < l; i++ ) { |
109 | 113 | var token = tokens[i]; |
110 | | - //console.log( 'MWParserEnvironment.tokensToString, token: ' + JSON.stringify( token ) ); |
| 114 | + if ( ! token ) { |
| 115 | + console.trace(); |
| 116 | + console.log( 'MWParserEnvironment.tokensToString, invalid token: ' + |
| 117 | + JSON.stringify( token ) ); |
| 118 | + continue; |
| 119 | + } |
111 | 120 | if ( token.type === 'TEXT' ) { |
112 | 121 | out.push( token.value ); |
| 122 | + } else if ( token.type === 'COMMENT' || token.type === 'NEWLINE' ) { |
| 123 | + // strip comments and newlines |
113 | 124 | } else { |
114 | 125 | var tstring = JSON.stringify( token ); |
115 | | - //console.log ( 'MWParserEnvironment.tokensToString, non-text token: ' + tstring ); |
116 | | - //out.push( tstring ); |
| 126 | + console.log ( 'MWParserEnvironment.tokensToString, non-text token: ' + |
| 127 | + tstring + JSON.stringify( tokens, null, 2 ) ); |
| 128 | + out.push( tstring ); |
117 | 129 | } |
118 | 130 | } |
119 | 131 | //console.log( 'MWParserEnvironment.tokensToString result: ' + out.join('') ); |
— | — | @@ -120,7 +132,17 @@ |
121 | 133 | }; |
122 | 134 | |
123 | 135 | |
| 136 | +/** |
| 137 | + * Simple debug helper |
| 138 | + */ |
| 139 | +MWParserEnvironment.prototype.dp = function ( ) { |
| 140 | + if ( this.debug ) { |
| 141 | + console.log( JSON.stringify( arguments, null, 2 ) ); |
| 142 | + } |
| 143 | +}; |
124 | 144 | |
| 145 | + |
| 146 | + |
125 | 147 | if (typeof module == "object") { |
126 | 148 | module.exports.MWParserEnvironment = MWParserEnvironment; |
127 | 149 | } |