Index: trunk/extensions/VisualEditor/modules/parser/mediawiki.TokenTransformDispatcher.js |
— | — | @@ -17,6 +17,14 @@ |
18 | 18 | * insert tokens in front of other ongoing expansion tasks. |
19 | 19 | * */ |
20 | 20 | |
| 21 | +/** |
| 22 | + * Central dispatcher for potentially asynchronous token transformations. |
| 23 | + * |
| 24 | + * @class |
| 25 | + * @constructor |
| 26 | + * @param {Function} callback, a callback function accepting a token list as |
| 27 | + * its only argument. |
| 28 | + */ |
21 | 29 | function TokenTransformDispatcher( callback ) { |
22 | 30 | this.cb = callback; // Called with transformed token list when done |
23 | 31 | this.transformers = { |
— | — | @@ -29,9 +37,14 @@ |
30 | 38 | any: [] // all tokens, before more specific handlers are run |
31 | 39 | }; |
32 | 40 | this.reset(); |
33 | | - return this; |
34 | 41 | } |
35 | 42 | |
| 43 | +/** |
| 44 | + * Reset the internal token and callback state of the |
| 45 | + * TokenTransformDispatcher, but keep registrations untouched. |
| 46 | + * |
| 47 | + * @method |
| 48 | + */ |
36 | 49 | TokenTransformDispatcher.prototype.reset = function () { |
37 | 50 | this.accum = new TokenAccumulator(null); |
38 | 51 | this.firstaccum = this.accum; |
— | — | @@ -39,6 +52,17 @@ |
40 | 53 | // (e.g., async template fetches/expansions) |
41 | 54 | }; |
42 | 55 | |
| 56 | +/** |
| 57 | + * Append a listener registration. The new listener will be executed after |
| 58 | + * other listeners for the same token have been called. |
| 59 | + * |
| 60 | + * @method |
| 61 | + * @param {Function} listener, a function accepting a TokenContext and |
| 62 | + * returning a TokenContext. |
| 63 | + * @param {String} type, one of 'tag', 'text', 'newline', 'comment', 'end', |
| 64 | + * 'martian' (unknown token), 'any' (any token, matched before other matches). |
| 65 | + * @param {String} tag name for tags, omitted for non-tags |
| 66 | + */ |
43 | 67 | TokenTransformDispatcher.prototype.appendListener = function ( listener, type, name ) { |
44 | 68 | if ( type === 'tag' ) { |
45 | 69 | name = name.toLowerCase(); |
— | — | @@ -52,6 +76,17 @@ |
53 | 77 | } |
54 | 78 | }; |
55 | 79 | |
| 80 | +/** |
| 81 | + * Prepend a listener registration. The new listener will be called before |
| 82 | + * other listeners for the same token have been called. |
| 83 | + * |
| 84 | + * @method |
| 85 | + * @param {Function} listener, a function accepting a TokenContext and |
| 86 | + * returning a TokenContext. |
| 87 | + * @param {String} type, one of 'tag', 'text', 'newline', 'comment', 'end', |
| 88 | + * 'martian' (unknown token), 'any' (any token, matched before other matches). |
| 89 | + * @param {String} tag name for tags, omitted for non-tags |
| 90 | + */ |
56 | 91 | TokenTransformDispatcher.prototype.prependListener = function ( listener, type, name ) { |
57 | 92 | if ( type === 'tag' ) { |
58 | 93 | name = name.toLowerCase(); |
— | — | @@ -65,6 +100,19 @@ |
66 | 101 | } |
67 | 102 | }; |
68 | 103 | |
| 104 | +/** |
| 105 | + * Remove a listener registration |
| 106 | + * |
| 107 | + * XXX: matching the function for equality is not ideal. Use a string key |
| 108 | + * instead? |
| 109 | + * |
| 110 | + * @method |
| 111 | + * @param {Function} listener, a function accepting a TokenContext and |
| 112 | + * returning a TokenContext. |
| 113 | + * @param {String} type, one of 'tag', 'text', 'newline', 'comment', 'end', |
| 114 | + * 'martian' (unknown token), 'any' (any token, matched before other matches). |
| 115 | + * @param {String} tag name for tags, omitted for non-tags |
| 116 | + */ |
69 | 117 | TokenTransformDispatcher.prototype.removeListener = function ( listener, type, name ) { |
70 | 118 | var i = -1; |
71 | 119 | var ts; |
— | — | @@ -146,20 +194,23 @@ |
147 | 195 | return tokenCTX; |
148 | 196 | }; |
149 | 197 | |
150 | | -/* Transform and expand tokens. |
| 198 | +/** |
| 199 | + * Transform and expand tokens. |
151 | 200 | * |
152 | 201 | * Normally called with undefined accum. Asynchronous expansions will call |
153 | 202 | * this with their known accum, which allows expanded tokens to be spliced in |
154 | 203 | * at the appropriate location in the token list, which is always at the tail |
155 | | - * end of the current accumulator. |
| 204 | + * end of the current accumulator. Calls back registered callback if there are |
| 205 | + * no more outstanding asynchronous expansions. |
156 | 206 | * |
157 | | - * @param tokens {List of tokens} Tokens to process. |
158 | | - * @param accum {TokenAccumulator} object. Undefined for first call, set to |
159 | | - * accumulator with expanded token at tail for asynchronous |
160 | | - * expansions. |
161 | | - * @returns nothing: Calls back registered callback if there are no more |
162 | | - * outstanding asynchronous expansions. |
163 | | - * */ |
| 207 | + * @param {Array} Tokens to process. |
| 208 | + * @param {Object} TokenAccumulator object. Undefined for first call, set to |
| 209 | + * accumulator with expanded token at tail for asynchronous expansions. |
| 210 | + * @param {Int} delta, default 1. Decrement the outstanding async callback |
| 211 | + * count by this much to determine when all outstanding actions are done. |
| 212 | + * Main use of this argument is to avoid counting some extra callbacks from |
| 213 | + * actions before they are done. |
| 214 | + */ |
164 | 215 | TokenTransformDispatcher.prototype.transformTokens = function ( tokens, accum, delta ) { |
165 | 216 | if ( accum === undefined ) { |
166 | 217 | this.reset(); |
— | — | @@ -219,6 +270,14 @@ |
220 | 271 | this.finish( delta ); |
221 | 272 | }; |
222 | 273 | |
| 274 | +/** |
| 275 | + * Decrement the number of outstanding async actions by delta and call the |
| 276 | + * callback with a list of tokens if none are remaining. |
| 277 | + * |
| 278 | + * @method |
| 279 | + * @param {Int} delta, how much to decrement the number of outstanding async |
| 280 | + * actions. |
| 281 | + */ |
223 | 282 | TokenTransformDispatcher.prototype.finish = function ( delta ) { |
224 | 283 | this.outstanding -= delta; |
225 | 284 | if ( this.outstanding === 0 ) { |
— | — | @@ -235,7 +294,14 @@ |
236 | 295 | } |
237 | 296 | }; |
238 | 297 | |
239 | | -/* Start a new accumulator for asynchronous work. */ |
| 298 | +/** |
| 299 | + * Start a new accumulator for asynchronous work. |
| 300 | + * |
| 301 | + * @param {Object} TokenAccumulator object after which to insert a new |
| 302 | + * accumulator |
| 303 | + * @count {Int} (optional, default 1) The number of callbacks to expect before |
| 304 | + * considering the asynch work on the new accumulator done. |
| 305 | + * */ |
240 | 306 | TokenTransformDispatcher.prototype.newAccumulator = function ( accum, count ) { |
241 | 307 | if ( count !== undefined ) { |
242 | 308 | this.outstanding += count; |
— | — | @@ -248,8 +314,15 @@ |
249 | 315 | return accum.insertAccumulator( ); |
250 | 316 | }; |
251 | 317 | |
252 | | -// Token accumulators in a linked list. Using a linked list simplifies async |
253 | | -// callbacks for template expansions. |
| 318 | +/** |
| 319 | + * Token accumulators in a linked list. Using a linked list simplifies async |
| 320 | + * callbacks for template expansions as it avoids stable references to chunks. |
| 321 | + * |
| 322 | + * @class |
| 323 | + * @constructor |
| 324 | + * @param {Object} next TokenAccumulator to link to |
| 325 | + * @param {Array} (optional) tokens, init accumulator with tokens or [] |
| 326 | + */ |
254 | 327 | function TokenAccumulator ( next, tokens ) { |
255 | 328 | this.next = next; |
256 | 329 | if ( tokens ) { |
— | — | @@ -260,14 +333,32 @@ |
261 | 334 | return this; |
262 | 335 | } |
263 | 336 | |
| 337 | +/** |
| 338 | + * Push a token into the accumulator |
| 339 | + * |
| 340 | + * @method |
| 341 | + * @param {Object} token |
| 342 | + */ |
264 | 343 | TokenAccumulator.prototype.push = function ( token ) { |
265 | 344 | return this.accum.push(token); |
266 | 345 | }; |
267 | 346 | |
| 347 | +/** |
| 348 | + * Pop a token from the accumulator |
| 349 | + * |
| 350 | + * @method |
| 351 | + * @returns {Object} token |
| 352 | + */ |
268 | 353 | TokenAccumulator.prototype.pop = function ( ) { |
269 | 354 | return this.accum.pop(); |
270 | 355 | }; |
271 | 356 | |
| 357 | +/** |
| 358 | + * Insert an accumulator after this one. |
| 359 | + * |
| 360 | + * @method |
| 361 | + * @returns {Object} created TokenAccumulator |
| 362 | + */ |
272 | 363 | TokenAccumulator.prototype.insertAccumulator = function ( ) { |
273 | 364 | this.next = new TokenAccumulator(this.next); |
274 | 365 | return this.next; |