Index: trunk/extensions/VisualEditor/modules/parser/mediawiki.TokenTransformManager.js |
— | — | @@ -964,14 +964,14 @@ |
965 | 965 | if ( this.depth > 40 ) { |
966 | 966 | // too deep |
967 | 967 | //console.log( 'Loopcheck: ' + JSON.stringify( this, null, 2 ) ); |
968 | | - return 'Expansion depth limit exceeded at '; |
| 968 | + return 'Error: Expansion depth limit exceeded at '; |
969 | 969 | } |
970 | 970 | var elem = this; |
971 | 971 | do { |
972 | 972 | //console.log( 'loop check: ' + title + ' vs ' + elem.title ); |
973 | 973 | if ( elem.title === title ) { |
974 | 974 | // Loop detected |
975 | | - return 'Expansion loop detected at '; |
| 975 | + return 'Error: Expansion loop detected at '; |
976 | 976 | } |
977 | 977 | elem = elem.parent; |
978 | 978 | } while ( elem ); |
Index: trunk/extensions/VisualEditor/modules/parser/ext.core.ParserFunctions.js |
— | — | @@ -5,6 +5,7 @@ |
6 | 6 | * @author Gabriel Wicke <gwicke@wikimedia.org> |
7 | 7 | */ |
8 | 8 | |
| 9 | + |
9 | 10 | function ParserFunctions ( manager ) { |
10 | 11 | this.manager = manager; |
11 | 12 | } |
— | — | @@ -48,7 +49,7 @@ |
49 | 50 | if ( target.trim() === this.manager.env.tokensToString( argList[0][1] ).trim() ) { |
50 | 51 | return ( argList[1] && argList[1][1]) || []; |
51 | 52 | } else { |
52 | | - return ( argList[1] && argList[1][1]) || []; |
| 53 | + return ( argList[2] && argList[2][1]) || []; |
53 | 54 | } |
54 | 55 | } |
55 | 56 | }; |
— | — | @@ -87,23 +88,117 @@ |
88 | 89 | return [{type: 'TAG', name: target, attribs: argList}]; |
89 | 90 | }; |
90 | 91 | |
| 92 | +// A first approximation, anyway.. |
| 93 | +ParserFunctions.prototype['pf_#time'] = function ( target, argList, argDict ) { |
| 94 | + //return [{type: 'TEXT', value: 'January 22, 2012'}]; |
| 95 | + var res, |
| 96 | + tpl = target.trim(); |
| 97 | + //try { |
| 98 | + // var date = new Date( this.manager.env.tokensToString( argList[0][1] ) ); |
| 99 | + // res = [{type: 'TEXT', value: date.format( target ) }]; |
| 100 | + //} catch ( e ) { |
| 101 | + // this.manager.env.dp( 'ERROR: #time ' + e ); |
| 102 | + |
| 103 | + try { |
| 104 | + res = [{type: 'TEXT', value: new Date().format ( tpl ) }]; |
| 105 | + } catch ( e2 ) { |
| 106 | + this.manager.env.dp( 'ERROR: #time ' + e2 ); |
| 107 | + res = [{type: 'TEXT', value: new Date().toString() }]; |
| 108 | + } |
| 109 | + //} |
| 110 | + return res; |
| 111 | +}; |
91 | 112 | |
| 113 | +// Simulates PHP's date function |
| 114 | +Date.prototype.format = function(format) { |
| 115 | + var returnStr = ''; |
| 116 | + var replace = Date.replaceChars; |
| 117 | + for (var i = 0; i < format.length; i++) { |
| 118 | + var curChar = format.charAt(i); |
| 119 | + if (i - 1 >= 0 && format.charAt(i - 1) == "\\") { |
| 120 | + returnStr += curChar; |
| 121 | + } |
| 122 | + else if (replace[curChar]) { |
| 123 | + returnStr += replace[curChar].call(this); |
| 124 | + } else if (curChar != "\\"){ |
| 125 | + returnStr += curChar; |
| 126 | + } |
| 127 | + } |
| 128 | + return returnStr; |
| 129 | +}; |
| 130 | + |
| 131 | +Date.replaceChars = { |
| 132 | + shortMonths: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], |
| 133 | + longMonths: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'], |
| 134 | + shortDays: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], |
| 135 | + longDays: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], |
| 136 | + |
| 137 | + // Day |
| 138 | + d: function() { return (this.getDate() < 10 ? '0' : '') + this.getDate(); }, |
| 139 | + D: function() { return Date.replaceChars.shortDays[this.getDay()]; }, |
| 140 | + j: function() { return this.getDate(); }, |
| 141 | + l: function() { return Date.replaceChars.longDays[this.getDay()]; }, |
| 142 | + N: function() { return this.getDay() + 1; }, |
| 143 | + S: function() { return (this.getDate() % 10 == 1 && this.getDate() != 11 ? 'st' : (this.getDate() % 10 == 2 && this.getDate() != 12 ? 'nd' : (this.getDate() % 10 == 3 && this.getDate() != 13 ? 'rd' : 'th'))); }, |
| 144 | + w: function() { return this.getDay(); }, |
| 145 | + z: function() { var d = new Date(this.getFullYear(),0,1); return Math.ceil((this - d) / 86400000); }, // Fixed now |
| 146 | + // Week |
| 147 | + W: function() { var d = new Date(this.getFullYear(), 0, 1); return Math.ceil((((this - d) / 86400000) + d.getDay() + 1) / 7); }, // Fixed now |
| 148 | + // Month |
| 149 | + F: function() { return Date.replaceChars.longMonths[this.getMonth()]; }, |
| 150 | + m: function() { return (this.getMonth() < 9 ? '0' : '') + (this.getMonth() + 1); }, |
| 151 | + M: function() { return Date.replaceChars.shortMonths[this.getMonth()]; }, |
| 152 | + n: function() { return this.getMonth() + 1; }, |
| 153 | + t: function() { var d = new Date(); return new Date(d.getFullYear(), d.getMonth(), 0).getDate() }, // Fixed now, gets #days of date |
| 154 | + // Year |
| 155 | + L: function() { var year = this.getFullYear(); return (year % 400 == 0 || (year % 100 != 0 && year % 4 == 0)); }, // Fixed now |
| 156 | + o: function() { var d = new Date(this.valueOf()); d.setDate(d.getDate() - ((this.getDay() + 6) % 7) + 3); return d.getFullYear();}, //Fixed now |
| 157 | + Y: function() { return this.getFullYear(); }, |
| 158 | + y: function() { return ('' + this.getFullYear()).substr(2); }, |
| 159 | + // Time |
| 160 | + a: function() { return this.getHours() < 12 ? 'am' : 'pm'; }, |
| 161 | + A: function() { return this.getHours() < 12 ? 'AM' : 'PM'; }, |
| 162 | + B: function() { return Math.floor((((this.getUTCHours() + 1) % 24) + this.getUTCMinutes() / 60 + this.getUTCSeconds() / 3600) * 1000 / 24); }, // Fixed now |
| 163 | + g: function() { return this.getHours() % 12 || 12; }, |
| 164 | + G: function() { return this.getHours(); }, |
| 165 | + h: function() { return ((this.getHours() % 12 || 12) < 10 ? '0' : '') + (this.getHours() % 12 || 12); }, |
| 166 | + H: function() { return (this.getHours() < 10 ? '0' : '') + this.getHours(); }, |
| 167 | + i: function() { return (this.getMinutes() < 10 ? '0' : '') + this.getMinutes(); }, |
| 168 | + s: function() { return (this.getSeconds() < 10 ? '0' : '') + this.getSeconds(); }, |
| 169 | + u: function() { var m = this.getMilliseconds(); return (m < 10 ? '00' : (m < 100 ? |
| 170 | +'0' : '')) + m; }, |
| 171 | + // Timezone |
| 172 | + e: function() { return "Not Yet Supported"; }, |
| 173 | + I: function() { return "Not Yet Supported"; }, |
| 174 | + O: function() { return (-this.getTimezoneOffset() < 0 ? '-' : '+') + (Math.abs(this.getTimezoneOffset() / 60) < 10 ? '0' : '') + (Math.abs(this.getTimezoneOffset() / 60)) + '00'; }, |
| 175 | + P: function() { return (-this.getTimezoneOffset() < 0 ? '-' : '+') + (Math.abs(this.getTimezoneOffset() / 60) < 10 ? '0' : '') + (Math.abs(this.getTimezoneOffset() / 60)) + ':00'; }, // Fixed now |
| 176 | + T: function() { var m = this.getMonth(); this.setMonth(0); var result = this.toTimeString().replace(/^.+ \(?([^\)]+)\)?$/, '$1'); this.setMonth(m); return result;}, |
| 177 | + Z: function() { return -this.getTimezoneOffset() * 60; }, |
| 178 | + // Full Date/Time |
| 179 | + c: function() { return this.format("Y-m-d\\TH:i:sP"); }, // Fixed now |
| 180 | + r: function() { return this.toString(); }, |
| 181 | + U: function() { return this.getTime() / 1000; } |
| 182 | +}; |
| 183 | + |
| 184 | + |
| 185 | + |
92 | 186 | /** |
93 | 187 | * Stub section: Pick any of these and actually implement them! |
94 | 188 | */ |
95 | 189 | |
96 | 190 | // FIXME |
97 | 191 | ParserFunctions.prototype['pf_#ifexpr'] = function ( target, argList, argDict ) { |
98 | | - return []; |
| 192 | + this.manager.env.dp( '#ifexp: ' + JSON.stringify( argList ) ); |
| 193 | + return ( argList[0] && argList[0][1] ) || []; |
99 | 194 | }; |
100 | 195 | ParserFunctions.prototype['pf_#iferror'] = function ( target, argList, argDict ) { |
101 | | - return []; |
| 196 | + return ( argList[0] && argList[0][1] ) || []; |
102 | 197 | }; |
103 | 198 | ParserFunctions.prototype['pf_#expr'] = function ( target, argList, argDict ) { |
104 | | - return []; |
| 199 | + return ( argList[0] && argList[0][1] ) || []; |
105 | 200 | }; |
106 | 201 | ParserFunctions.prototype['pf_#ifexist'] = function ( target, argList, argDict ) { |
107 | | - return []; |
| 202 | + return ( argList[0] && argList[0][1] ) || []; |
108 | 203 | }; |
109 | 204 | ParserFunctions.prototype['pf_formatnum'] = function ( target, argList, argDict ) { |
110 | 205 | return [{type: 'TEXT', value: target}]; |
— | — | @@ -114,6 +209,9 @@ |
115 | 210 | ParserFunctions.prototype['pf_pagename'] = function ( target, argList, argDict ) { |
116 | 211 | return [{type: 'TEXT', value: target}]; |
117 | 212 | }; |
| 213 | +ParserFunctions.prototype['pf_pagesize'] = function ( target, argList, argDict ) { |
| 214 | + return [{type: 'TEXT', value: '100'}]; |
| 215 | +}; |
118 | 216 | ParserFunctions.prototype['pf_pagename'] = function ( target, argList, argDict ) { |
119 | 217 | return [{type: 'TEXT', value: target}]; |
120 | 218 | }; |
— | — | @@ -133,11 +231,7 @@ |
134 | 232 | return [{type: 'TEXT', value: 'Main'}]; |
135 | 233 | }; |
136 | 234 | |
137 | | -ParserFunctions.prototype['pf_#time'] = function ( target, argList, argDict ) { |
138 | | - return [{type: 'TEXT', value: new Date().toString()}]; |
139 | | -}; |
140 | 235 | |
141 | | - |
142 | 236 | if (typeof module == "object") { |
143 | 237 | module.exports.ParserFunctions = ParserFunctions; |
144 | 238 | } |
Index: trunk/extensions/VisualEditor/modules/parser/ext.core.TemplateHandler.js |
— | — | @@ -160,9 +160,8 @@ |
161 | 161 | // check for parser functions |
162 | 162 | |
163 | 163 | // First, check the target for loops |
164 | | - var target = this.manager.env.normalizeTitle( |
165 | | - this.manager.env.tokensToString( tplExpandData.target ) |
166 | | - ); |
| 164 | + var target = this.manager.env.tokensToString( tplExpandData.target ); |
| 165 | + |
167 | 166 | var args = this.manager.env.KVtoHash( tplExpandData.expandedArgs ); |
168 | 167 | |
169 | 168 | this.manager.env.dp( 'argHash: ', args ); |
— | — | @@ -172,7 +171,7 @@ |
173 | 172 | var funcArg = target.substr( prefix.length + 1 ); |
174 | 173 | this.manager.env.dp( 'entering prefix', funcArg, args ); |
175 | 174 | res = this.parserFunctions[ 'pf_' + prefix ]( funcArg, |
176 | | - tplExpandData.expandDone, args ); |
| 175 | + tplExpandData.expandedArgs, args ); |
177 | 176 | |
178 | 177 | // XXX: support async parser functions! |
179 | 178 | if ( tplExpandData.overallAsync ) { |
— | — | @@ -187,6 +186,9 @@ |
188 | 187 | } |
189 | 188 | } |
190 | 189 | |
| 190 | + // now normalize the target before template processing |
| 191 | + target = this.manager.env.normalizeTitle( target ); |
| 192 | + |
191 | 193 | var checkRes = this.manager.loopAndDepthCheck.check( target ); |
192 | 194 | if( checkRes ) { |
193 | 195 | // Loop detected or depth limit exceeded, abort! |
— | — | @@ -334,13 +336,14 @@ |
335 | 337 | } |
336 | 338 | ); |
337 | 339 | } else if ( ! this.manager.env.fetchTemplates ) { |
338 | | - callback( 'Page/template fetching disabled, and no cache for ' + title, title ); |
| 340 | + callback( 'Warning: Page/template fetching disabled, and no cache for ' + |
| 341 | + title, title ); |
339 | 342 | } else { |
340 | 343 | |
341 | 344 | // We are about to start an async request for a template, so mark this |
342 | 345 | // template expansion as such. |
343 | 346 | tplExpandData.overallAsync = true; |
344 | | - this.manager.env.dp( 'trying to fetch ' + title ); |
| 347 | + this.manager.env.dp( 'Note: trying to fetch ' + title ); |
345 | 348 | |
346 | 349 | // Start a new request if none is outstanding |
347 | 350 | this.manager.env.dp( 'requestQueue: ', this.manager.env.requestQueue); |