r105553 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r105552‎ | r105553 | r105554 >
Date:14:37, 8 December 2011
Author:gwicke
Status:deferred
Tags:
Comment:
Add a TokenTransformer dispatcher class. This class provides subscriptions by
token type, and supports asynchronous token expansion (for example for async
template expansion). This code is not yet tested or used. The interface for
token insertion from transformation functions will be expanded as needed.
Modified paths:
  • /trunk/extensions/VisualEditor/modules/parser/mediawiki.TokenTransformer.js (added) (history)

Diff [purge]

Index: trunk/extensions/VisualEditor/modules/parser/mediawiki.TokenTransformer.js
@@ -0,0 +1,162 @@
 2+/* Generic token transformation dispatcher with support for asynchronous token
 3+ * expansion. Individual transformations register for the token types they are
 4+ * interested in and are called on each matching token. */
 5+
 6+function TokenTransformer( callback ) {
 7+ this.cb = callback; // Called with transformed token list when done
 8+ this.accum = new TokenAccumulator();
 9+ this.firstaccum = this.accum;
 10+ this.transformers = {
 11+ tag: {}, // for TAG, ENDTAG, SELFCLOSINGTAG, keyed on name
 12+ text: [],
 13+ newline: [],
 14+ comment: [],
 15+ end: [], // eof
 16+ martian: [] // none of the above
 17+ };
 18+ this.outstanding = 1; // Number of outstanding processing steps
 19+ // (e.g., async template fetches/expansions)
 20+ return this;
 21+}
 22+
 23+TokenTransformer.prototype.appendListener = function ( listener, type, name ) {
 24+ if ( type === 'tag' ) {
 25+ if ( $.isArray(this.transformers.tag.name) ) {
 26+ this.transformers.tag[name].push(listener);
 27+ } else {
 28+ this.transformers.tag[name] = [listener];
 29+ }
 30+ } else {
 31+ this.transformers[type].push(listener);
 32+ }
 33+};
 34+
 35+TokenTransformer.prototype.prependListener = function ( listener, type, name ) {
 36+ if ( type === 'tag' ) {
 37+ if ( $.isArray(this.transformers.tag.name) ) {
 38+ this.transformers.tag[name].unshift(listener);
 39+ } else {
 40+ this.transformers.tag[name] = [listener];
 41+ }
 42+ } else {
 43+ this.transformers[type].unshift(listener);
 44+ }
 45+};
 46+
 47+TokenTransformer.prototype.removeListener = function ( listener, type, name ) {
 48+ var i = -1;
 49+ var ts;
 50+ if ( type === 'tag' ) {
 51+ if ( $.isArray(this.transformers.tag.name) ) {
 52+ ts = this.transformers.tag[name];
 53+ i = ts.indexOf(listener);
 54+ }
 55+ } else {
 56+ ts = this.transformers[type];
 57+ i = ts.indexOf(listener);
 58+ }
 59+ if ( i >= 0 ) {
 60+ ts.splice(i, 1);
 61+ }
 62+};
 63+
 64+TokenTransformer.prototype._transformTagToken = function ( token, lastToken ) {
 65+ var ts = this.transformers.tag[token.name];
 66+ if ( ts ) {
 67+ for (var i = 0, l = ts.length; i < l; i++ ) {
 68+ token = ts[i]( token, lastToken, this.accum, this );
 69+ if ( token === null ) {
 70+ break;
 71+ }
 72+ }
 73+ }
 74+ return token;
 75+};
 76+
 77+TokenTransformer.prototype._transformToken = function ( ts, token, lastToken ) {
 78+ if ( ts ) {
 79+ for (var i = 0, l = ts.length; i < l; i++ ) {
 80+ token = ts[i]( token, lastToken, this.accum, this );
 81+ if ( token === null ) {
 82+ break;
 83+ }
 84+ }
 85+ }
 86+ return token;
 87+};
 88+
 89+TokenTransformer.prototype.transformTokens = function ( tokens ) {
 90+ var currentOutout = [];
 91+ var lastToken;
 92+ for ( var i = 0, l = tokens.length; i < l; i++ ) {
 93+ var token = tokens[i];
 94+ var ts;
 95+ switch(token.type) {
 96+ case 'TAG':
 97+ case 'ENDTAG':
 98+ case 'SELFCLOSINGTAG':
 99+ lastToken = this._transformTagToken( token, lastToken );
 100+ break;
 101+ case 'TEXT':
 102+ lastToken = this._transformToken(this.transformers.text, token, lastToken);
 103+ break;
 104+ case 'COMMENT':
 105+ lastToken = this._transformToken(this.transformers.comment, token, lastToken);
 106+ break;
 107+ case 'NEWLINE':
 108+ lastToken = this._transformToken(this.transformers.newline, token, lastToken);
 109+ break;
 110+ case 'END':
 111+ lastToken = this._transformToken(this.transformers.end, token, lastToken);
 112+ break;
 113+ default:
 114+ lastToken = this._transformToken(this.transformers.martian, token, lastToken);
 115+ break;
 116+ }
 117+ if(lastToken) {
 118+ this.accum.push(lastToken);
 119+ }
 120+ }
 121+ this.finish();
 122+};
 123+
 124+TokenTransformer.prototype.finish = function ( ) {
 125+ this.outstanding--;
 126+ if ( this.outstanding === 0 ) {
 127+ // Join back the token accumulators into a single token list
 128+ var a = this.firstaccum;
 129+ var accums = [a.accum];
 130+ while ( a.next !== undefined ) {
 131+ a = a.next;
 132+ accums.push(a.accum);
 133+ }
 134+ // Call our callback with the token list
 135+ this.cb(accums.join());
 136+ }
 137+};
 138+
 139+
 140+
 141+// Start a new accumulator with the given tokens.
 142+TokenTransformer.prototype.newAccumulator = function ( tokens ) {
 143+ this.accum = this.accum.spliceAccumulator( tokens );
 144+};
 145+
 146+// Token accumulators in a linked list. Using a linked list simplifies async
 147+// callbacks for template expansions.
 148+function TokenAccumulator ( next, tokens ) {
 149+ this.next = next;
 150+ if ( tokens )
 151+ this.accum = tokens;
 152+ else
 153+ this.accum = [];
 154+}
 155+
 156+TokenAccumulator.prototype.push = function ( token ) {
 157+ this.accum.push(token);
 158+};
 159+
 160+TokenAccumulator.prototype.spliceAccumulator = function ( tokens ) {
 161+ this.next = new TokenAccumulator(this.next, tokens);
 162+ return this.next;
 163+};
Property changes on: trunk/extensions/VisualEditor/modules/parser/mediawiki.TokenTransformer.js
___________________________________________________________________
Added: svn:eol-style
1164 + native

Status & tagging log