Commit 420ea6ab22154b7e1bb293b248599106ece52615
1 parent
82f84018
workcicle...
Showing
39 changed files
with
68 additions
and
53186 deletions
alasql-utility/alasql-utility.js
1 | -function alasql_selectData (data, fields, filters) { | |
2 | - if(fields.length == 0) | |
3 | - return []; | |
4 | - | |
5 | - var _fields = _addParenthesis(fields); | |
6 | - | |
7 | - var select = _alasql_SELECT(_fields); | |
8 | - | |
9 | - var where = ""; | |
10 | - if(filters && filters.length) { | |
11 | - var _filters = _copy(filters); | |
12 | - where = _alasql_WHERE(_filters); | |
13 | - } | |
14 | - | |
15 | - var query = select + " FROM ?" + where; | |
16 | - | |
17 | - return alasql(query, [data]); | |
18 | -} | |
19 | - | |
20 | -function alasql_complexSelectData (data, fields, filters, aggregators, orders) { | |
1 | +function alasql_QUERY (data, fields, filters, aggregators, orders) { | |
21 | 2 | if(fields.length == 0) |
22 | 3 | return []; |
23 | 4 | |
... | ... | @@ -134,17 +115,13 @@ function _addParenthesis (fields) { |
134 | 115 | } |
135 | 116 | |
136 | 117 | function _normalizeField (field) { |
137 | - /*DEPRECATED*/return "[" + field.substring(field.lastIndexOf(",") + 1, field.length) + "]"; | |
138 | - //return "[" + field + "]"; | |
118 | + return "[" + field + "]"; | |
139 | 119 | } |
140 | 120 | |
141 | -function transformData (data, fields, truncate) { | |
121 | +function alasql_transformData (data, fields, truncate) { | |
142 | 122 | if(!data || data.length == 0) |
143 | 123 | return []; |
144 | 124 | |
145 | - /*DEPRECATED*/for (var i=0; i < fields.length; i++) | |
146 | - fields[i] = fields[i].substring(fields[i].lastIndexOf(",") + 1, fields[i].length); | |
147 | - | |
148 | 125 | var tData = []; |
149 | 126 | |
150 | 127 | for (var i in fields){ | ... | ... |
bower_components/l20n/.bower.json deleted
1 | -{ | |
2 | - "name": "l20n", | |
3 | - "description": "A natural-language localization framework", | |
4 | - "version": "3.4.1", | |
5 | - "homepage": "http://l20n.org", | |
6 | - "repository": { | |
7 | - "type": "git", | |
8 | - "url": "git://github.com/l20n/l20n.js.git" | |
9 | - }, | |
10 | - "authors": [ | |
11 | - "Mozilla <l10n-drivers@mozilla.org>", | |
12 | - "Zbigniew Braniecki", | |
13 | - "Staś Małolepszy" | |
14 | - ], | |
15 | - "license": "Apache 2.0", | |
16 | - "keywords": [ | |
17 | - "localization", | |
18 | - "l10n", | |
19 | - "l20n" | |
20 | - ], | |
21 | - "main": [], | |
22 | - "ignore": [ | |
23 | - "**/*", | |
24 | - "!dist/**/*" | |
25 | - ], | |
26 | - "_release": "3.4.1", | |
27 | - "_resolution": { | |
28 | - "type": "version", | |
29 | - "tag": "v3.4.1", | |
30 | - "commit": "4b5428be54003e8dc7243665a5f844a546ddd226" | |
31 | - }, | |
32 | - "_source": "git://github.com/l20n/l20n.js.git", | |
33 | - "_target": "v3.x", | |
34 | - "_originalSource": "l20n", | |
35 | - "_direct": true | |
36 | -} | |
37 | 0 | \ No newline at end of file |
bower_components/l20n/bower.json deleted
1 | -{ | |
2 | - "name": "l20n", | |
3 | - "description": "A natural-language localization framework", | |
4 | - "version": "3.4.1", | |
5 | - "homepage": "http://l20n.org", | |
6 | - "repository": { | |
7 | - "type": "git", | |
8 | - "url": "git://github.com/l20n/l20n.js.git" | |
9 | - }, | |
10 | - "authors": [ | |
11 | - "Mozilla <l10n-drivers@mozilla.org>", | |
12 | - "Zbigniew Braniecki", | |
13 | - "Staś Małolepszy" | |
14 | - ], | |
15 | - "license": "Apache 2.0", | |
16 | - "keywords": [ | |
17 | - "localization", | |
18 | - "l10n", | |
19 | - "l20n" | |
20 | - ], | |
21 | - "main": [], | |
22 | - "ignore": [ | |
23 | - "**/*", | |
24 | - "!dist/**/*" | |
25 | - ] | |
26 | -} |
bower_components/l20n/dist/bundle/aisle/l20n.js deleted
1 | -define(['exports'], function (exports) { 'use strict'; | |
2 | - | |
3 | - class Node { | |
4 | - constructor() { | |
5 | - this.type = this.constructor.name; | |
6 | - } | |
7 | - } | |
8 | - | |
9 | - class Entry extends Node { | |
10 | - constructor() { | |
11 | - super(); | |
12 | - } | |
13 | - } | |
14 | - | |
15 | - class Identifier extends Node { | |
16 | - constructor(name) { | |
17 | - super(); | |
18 | - this.name = name; | |
19 | - } | |
20 | - } | |
21 | - | |
22 | - class Variable extends Node { | |
23 | - constructor(name) { | |
24 | - super(); | |
25 | - this.name = name; | |
26 | - } | |
27 | - } | |
28 | - | |
29 | - class Global extends Node { | |
30 | - constructor(name) { | |
31 | - super(); | |
32 | - this.name = name; | |
33 | - } | |
34 | - } | |
35 | - | |
36 | - class Value extends Node { | |
37 | - constructor() { | |
38 | - super(); | |
39 | - } | |
40 | - } | |
41 | - | |
42 | - class String extends Value { | |
43 | - constructor(source, content) { | |
44 | - super(); | |
45 | - this.source = source; | |
46 | - this.content = content; | |
47 | - | |
48 | - this._opchar = '"'; | |
49 | - } | |
50 | - } | |
51 | - | |
52 | - class Hash extends Value { | |
53 | - constructor(items) { | |
54 | - super(); | |
55 | - this.items = items; | |
56 | - } | |
57 | - } | |
58 | - | |
59 | - | |
60 | - class Entity extends Entry { | |
61 | - constructor(id, value = null, index = null, attrs = []) { | |
62 | - super(); | |
63 | - this.id = id; | |
64 | - this.value = value; | |
65 | - this.index = index; | |
66 | - this.attrs = attrs; | |
67 | - } | |
68 | - } | |
69 | - | |
70 | - class Resource extends Node { | |
71 | - constructor() { | |
72 | - super(); | |
73 | - this.body = []; | |
74 | - } | |
75 | - } | |
76 | - | |
77 | - class Attribute extends Node { | |
78 | - constructor(id, value, index = null) { | |
79 | - super(); | |
80 | - this.id = id; | |
81 | - this.value = value; | |
82 | - this.index = index; | |
83 | - } | |
84 | - } | |
85 | - | |
86 | - class HashItem extends Node { | |
87 | - constructor(id, value, defItem) { | |
88 | - super(); | |
89 | - this.id = id; | |
90 | - this.value = value; | |
91 | - this.default = defItem; | |
92 | - } | |
93 | - } | |
94 | - | |
95 | - class Comment extends Entry { | |
96 | - constructor(body) { | |
97 | - super(); | |
98 | - this.body = body; | |
99 | - } | |
100 | - } | |
101 | - | |
102 | - class Expression extends Node { | |
103 | - constructor() { | |
104 | - super(); | |
105 | - } | |
106 | - } | |
107 | - | |
108 | - class PropertyExpression extends Expression { | |
109 | - constructor(idref, exp, computed = false) { | |
110 | - super(); | |
111 | - this.idref = idref; | |
112 | - this.exp = exp; | |
113 | - this.computed = computed; | |
114 | - } | |
115 | - } | |
116 | - | |
117 | - class CallExpression extends Expression { | |
118 | - constructor(callee, args) { | |
119 | - super(); | |
120 | - this.callee = callee; | |
121 | - this.args = args; | |
122 | - } | |
123 | - } | |
124 | - | |
125 | - class JunkEntry extends Entry { | |
126 | - constructor(content) { | |
127 | - super(); | |
128 | - this.content = content; | |
129 | - } | |
130 | - } | |
131 | - | |
132 | - var AST = { | |
133 | - Node, | |
134 | - Identifier, | |
135 | - Value, | |
136 | - String, | |
137 | - Hash, | |
138 | - Entity, | |
139 | - Resource, | |
140 | - Attribute, | |
141 | - HashItem, | |
142 | - Comment, | |
143 | - Variable, | |
144 | - Global, | |
145 | - Expression, | |
146 | - PropertyExpression, | |
147 | - CallExpression, | |
148 | - JunkEntry, | |
149 | - }; | |
150 | - | |
151 | - function L10nError(message, id, lang) { | |
152 | - this.name = 'L10nError'; | |
153 | - this.message = message; | |
154 | - this.id = id; | |
155 | - this.lang = lang; | |
156 | - } | |
157 | - L10nError.prototype = Object.create(Error.prototype); | |
158 | - L10nError.prototype.constructor = L10nError; | |
159 | - | |
160 | - const MAX_PLACEABLES = 100; | |
161 | - | |
162 | - | |
163 | - class ParseContext { | |
164 | - constructor(string, pos) { | |
165 | - this._config = { | |
166 | - pos: pos | |
167 | - }; | |
168 | - this._source = string; | |
169 | - this._index = 0; | |
170 | - this._length = string.length; | |
171 | - this._curEntryStart = 0; | |
172 | - } | |
173 | - | |
174 | - setPosition(node, start, end) { | |
175 | - if (!this._config.pos) { | |
176 | - return; | |
177 | - } | |
178 | - node._pos = {start, end}; | |
179 | - } | |
180 | - | |
181 | - getResource() { | |
182 | - let resource = new AST.Resource(); | |
183 | - this.setPosition(resource, 0, this._length); | |
184 | - resource._errors = []; | |
185 | - | |
186 | - this.getWS(); | |
187 | - while (this._index < this._length) { | |
188 | - try { | |
189 | - resource.body.push(this.getEntry()); | |
190 | - } catch (e) { | |
191 | - if (e instanceof L10nError) { | |
192 | - resource._errors.push(e); | |
193 | - resource.body.push(this.getJunkEntry()); | |
194 | - } else { | |
195 | - throw e; | |
196 | - } | |
197 | - } | |
198 | - if (this._index < this._length) { | |
199 | - this.getWS(); | |
200 | - } | |
201 | - } | |
202 | - | |
203 | - return resource; | |
204 | - } | |
205 | - | |
206 | - getEntry() { | |
207 | - this._curEntryStart = this._index; | |
208 | - | |
209 | - if (this._source[this._index] === '<') { | |
210 | - ++this._index; | |
211 | - const id = this.getIdentifier(); | |
212 | - if (this._source[this._index] === '[') { | |
213 | - ++this._index; | |
214 | - return this.getEntity(id, this.getItemList(this.getExpression, ']')); | |
215 | - } | |
216 | - return this.getEntity(id); | |
217 | - } | |
218 | - | |
219 | - if (this._source.startsWith('/*', this._index)) { | |
220 | - return this.getComment(); | |
221 | - } | |
222 | - | |
223 | - throw this.error('Invalid entry'); | |
224 | - } | |
225 | - | |
226 | - getEntity(id, index) { | |
227 | - if (!this.getRequiredWS()) { | |
228 | - throw this.error('Expected white space'); | |
229 | - } | |
230 | - | |
231 | - const ch = this._source.charAt(this._index); | |
232 | - const value = this.getValue(ch, index === undefined); | |
233 | - let attrs; | |
234 | - | |
235 | - if (value === null) { | |
236 | - if (ch === '>') { | |
237 | - throw this.error('Expected ">"'); | |
238 | - } | |
239 | - attrs = this.getAttributes(); | |
240 | - } else { | |
241 | - const ws1 = this.getRequiredWS(); | |
242 | - if (this._source[this._index] !== '>') { | |
243 | - if (!ws1) { | |
244 | - throw this.error('Expected ">"'); | |
245 | - } | |
246 | - attrs = this.getAttributes(); | |
247 | - } | |
248 | - } | |
249 | - | |
250 | - // skip '>' | |
251 | - ++this._index; | |
252 | - | |
253 | - const entity = new AST.Entity(id, value, index, attrs); | |
254 | - this.setPosition(entity, this._curEntryStart, this._index); | |
255 | - return entity; | |
256 | - } | |
257 | - | |
258 | - getValue(ch = this._source[this._index], optional = false) { | |
259 | - switch (ch) { | |
260 | - case '\'': | |
261 | - case '"': | |
262 | - return this.getString(ch, 1); | |
263 | - case '{': | |
264 | - return this.getHash(); | |
265 | - } | |
266 | - | |
267 | - if (!optional) { | |
268 | - throw this.error('Unknown value type'); | |
269 | - } | |
270 | - return null; | |
271 | - } | |
272 | - | |
273 | - getWS() { | |
274 | - let cc = this._source.charCodeAt(this._index); | |
275 | - // space, \n, \t, \r | |
276 | - while (cc === 32 || cc === 10 || cc === 9 || cc === 13) { | |
277 | - cc = this._source.charCodeAt(++this._index); | |
278 | - } | |
279 | - } | |
280 | - | |
281 | - getRequiredWS() { | |
282 | - const pos = this._index; | |
283 | - let cc = this._source.charCodeAt(pos); | |
284 | - // space, \n, \t, \r | |
285 | - while (cc === 32 || cc === 10 || cc === 9 || cc === 13) { | |
286 | - cc = this._source.charCodeAt(++this._index); | |
287 | - } | |
288 | - return this._index !== pos; | |
289 | - } | |
290 | - | |
291 | - getIdentifier() { | |
292 | - const start = this._index; | |
293 | - let cc = this._source.charCodeAt(this._index); | |
294 | - | |
295 | - if ((cc >= 97 && cc <= 122) || // a-z | |
296 | - (cc >= 65 && cc <= 90) || // A-Z | |
297 | - cc === 95) { // _ | |
298 | - cc = this._source.charCodeAt(++this._index); | |
299 | - } else { | |
300 | - throw this.error('Identifier has to start with [a-zA-Z_]'); | |
301 | - } | |
302 | - | |
303 | - while ((cc >= 97 && cc <= 122) || // a-z | |
304 | - (cc >= 65 && cc <= 90) || // A-Z | |
305 | - (cc >= 48 && cc <= 57) || // 0-9 | |
306 | - cc === 95) { // _ | |
307 | - cc = this._source.charCodeAt(++this._index); | |
308 | - } | |
309 | - | |
310 | - const id = new AST.Identifier(this._source.slice(start, this._index)); | |
311 | - this.setPosition(id, start, this._index); | |
312 | - return id; | |
313 | - } | |
314 | - | |
315 | - getUnicodeChar() { | |
316 | - for (let i = 0; i < 4; i++) { | |
317 | - let cc = this._source.charCodeAt(++this._index); | |
318 | - if ((cc > 96 && cc < 103) || // a-f | |
319 | - (cc > 64 && cc < 71) || // A-F | |
320 | - (cc > 47 && cc < 58)) { // 0-9 | |
321 | - continue; | |
322 | - } | |
323 | - throw this.error('Illegal unicode escape sequence'); | |
324 | - } | |
325 | - return '\\u' + this._source.slice(this._index - 3, this._index + 1); | |
326 | - } | |
327 | - | |
328 | - getString(opchar, opcharLen) { | |
329 | - let body = []; | |
330 | - let buf = ''; | |
331 | - let placeables = 0; | |
332 | - | |
333 | - this._index += opcharLen - 1; | |
334 | - | |
335 | - const start = this._index + 1; | |
336 | - | |
337 | - let closed = false; | |
338 | - | |
339 | - while (!closed) { | |
340 | - let ch = this._source[++this._index]; | |
341 | - | |
342 | - switch (ch) { | |
343 | - case '\\': | |
344 | - const ch2 = this._source[++this._index]; | |
345 | - if (ch2 === 'u') { | |
346 | - buf += this.getUnicodeChar(); | |
347 | - } else if (ch2 === opchar || ch2 === '\\') { | |
348 | - buf += ch2; | |
349 | - } else if (ch2 === '{' && this._source[this._index + 1] === '{') { | |
350 | - buf += '{'; | |
351 | - } else { | |
352 | - throw this.error('Illegal escape sequence'); | |
353 | - } | |
354 | - break; | |
355 | - case '{': | |
356 | - if (this._source[this._index + 1] === '{') { | |
357 | - if (placeables > MAX_PLACEABLES - 1) { | |
358 | - throw this.error('Too many placeables, maximum allowed is ' + | |
359 | - MAX_PLACEABLES); | |
360 | - } | |
361 | - if (buf.length) { | |
362 | - body.push(buf); | |
363 | - buf = ''; | |
364 | - } | |
365 | - this._index += 2; | |
366 | - this.getWS(); | |
367 | - body.push(this.getExpression()); | |
368 | - this.getWS(); | |
369 | - if (!this._source.startsWith('}}', this._index)) { | |
370 | - throw this.error('Expected "}}"'); | |
371 | - } | |
372 | - this._index += 1; | |
373 | - placeables++; | |
374 | - break; | |
375 | - } | |
376 | - /* falls through */ | |
377 | - default: | |
378 | - if (ch === opchar) { | |
379 | - this._index++; | |
380 | - closed = true; | |
381 | - break; | |
382 | - } | |
383 | - | |
384 | - buf += ch; | |
385 | - if (this._index + 1 >= this._length) { | |
386 | - throw this.error('Unclosed string literal'); | |
387 | - } | |
388 | - } | |
389 | - } | |
390 | - | |
391 | - if (buf.length) { | |
392 | - body.push(buf); | |
393 | - } | |
394 | - | |
395 | - const string = new AST.String( | |
396 | - this._source.slice(start, this._index - 1), body); | |
397 | - this.setPosition(string, start, this._index); | |
398 | - string._opchar = opchar; | |
399 | - | |
400 | - return string; | |
401 | - } | |
402 | - | |
403 | - getAttributes() { | |
404 | - const attrs = []; | |
405 | - | |
406 | - while (true) { | |
407 | - const attr = this.getAttribute(); | |
408 | - attrs.push(attr); | |
409 | - const ws1 = this.getRequiredWS(); | |
410 | - const ch = this._source.charAt(this._index); | |
411 | - if (ch === '>') { | |
412 | - break; | |
413 | - } else if (!ws1) { | |
414 | - throw this.error('Expected ">"'); | |
415 | - } | |
416 | - } | |
417 | - return attrs; | |
418 | - } | |
419 | - | |
420 | - getAttribute() { | |
421 | - const start = this._index; | |
422 | - const key = this.getIdentifier(); | |
423 | - let index; | |
424 | - | |
425 | - if (this._source[this._index]=== '[') { | |
426 | - ++this._index; | |
427 | - this.getWS(); | |
428 | - index = this.getItemList(this.getExpression, ']'); | |
429 | - } | |
430 | - this.getWS(); | |
431 | - if (this._source[this._index] !== ':') { | |
432 | - throw this.error('Expected ":"'); | |
433 | - } | |
434 | - ++this._index; | |
435 | - this.getWS(); | |
436 | - const attr = new AST.Attribute(key, this.getValue(), index); | |
437 | - this.setPosition(attr, start, this._index); | |
438 | - return attr; | |
439 | - } | |
440 | - | |
441 | - getHash() { | |
442 | - const start = this._index; | |
443 | - let items = []; | |
444 | - | |
445 | - ++this._index; | |
446 | - this.getWS(); | |
447 | - | |
448 | - while (true) { | |
449 | - items.push(this.getHashItem()); | |
450 | - this.getWS(); | |
451 | - | |
452 | - const comma = this._source[this._index] === ','; | |
453 | - if (comma) { | |
454 | - ++this._index; | |
455 | - this.getWS(); | |
456 | - } | |
457 | - if (this._source[this._index] === '}') { | |
458 | - ++this._index; | |
459 | - break; | |
460 | - } | |
461 | - if (!comma) { | |
462 | - throw this.error('Expected "}"'); | |
463 | - } | |
464 | - } | |
465 | - | |
466 | - const hash = new AST.Hash(items); | |
467 | - this.setPosition(hash, start, this._index); | |
468 | - return hash; | |
469 | - } | |
470 | - | |
471 | - getHashItem() { | |
472 | - const start = this._index; | |
473 | - | |
474 | - let defItem = false; | |
475 | - if (this._source[this._index] === '*') { | |
476 | - ++this._index; | |
477 | - defItem = true; | |
478 | - } | |
479 | - | |
480 | - const key = this.getIdentifier(); | |
481 | - this.getWS(); | |
482 | - if (this._source[this._index] !== ':') { | |
483 | - throw this.error('Expected ":"'); | |
484 | - } | |
485 | - ++this._index; | |
486 | - this.getWS(); | |
487 | - | |
488 | - const hashItem = new AST.HashItem(key, this.getValue(), defItem); | |
489 | - this.setPosition(hashItem, start, this._index); | |
490 | - return hashItem; | |
491 | - } | |
492 | - | |
493 | - getComment() { | |
494 | - this._index += 2; | |
495 | - const start = this._index; | |
496 | - const end = this._source.indexOf('*/', start); | |
497 | - | |
498 | - if (end === -1) { | |
499 | - throw this.error('Comment without a closing tag'); | |
500 | - } | |
501 | - | |
502 | - this._index = end + 2; | |
503 | - const comment = new AST.Comment(this._source.slice(start, end)); | |
504 | - this.setPosition(comment, start - 2, this._index); | |
505 | - return comment; | |
506 | - } | |
507 | - | |
508 | - getExpression() { | |
509 | - const start = this._index; | |
510 | - let exp = this.getPrimaryExpression(); | |
511 | - | |
512 | - while (true) { | |
513 | - let ch = this._source[this._index]; | |
514 | - if (ch === '.' || ch === '[') { | |
515 | - ++this._index; | |
516 | - exp = this.getPropertyExpression(exp, ch === '[', start); | |
517 | - } else if (ch === '(') { | |
518 | - ++this._index; | |
519 | - exp = this.getCallExpression(exp, start); | |
520 | - } else { | |
521 | - break; | |
522 | - } | |
523 | - } | |
524 | - | |
525 | - return exp; | |
526 | - } | |
527 | - | |
528 | - getPropertyExpression(idref, computed, start) { | |
529 | - let exp; | |
530 | - | |
531 | - if (computed) { | |
532 | - this.getWS(); | |
533 | - exp = this.getExpression(); | |
534 | - this.getWS(); | |
535 | - if (this._source[this._index] !== ']') { | |
536 | - throw this.error('Expected "]"'); | |
537 | - } | |
538 | - ++this._index; | |
539 | - } else { | |
540 | - exp = this.getIdentifier(); | |
541 | - } | |
542 | - | |
543 | - const propExpr = new AST.PropertyExpression(idref, exp, computed); | |
544 | - this.setPosition(propExpr, start, this._index); | |
545 | - return propExpr; | |
546 | - } | |
547 | - | |
548 | - getCallExpression(callee, start) { | |
549 | - this.getWS(); | |
550 | - | |
551 | - const callExpr = new AST.CallExpression(callee, | |
552 | - this.getItemList(this.getExpression, ')')); | |
553 | - this.setPosition(callExpr, start, this._index); | |
554 | - return callExpr; | |
555 | - } | |
556 | - | |
557 | - getPrimaryExpression() { | |
558 | - const start = this._index; | |
559 | - const ch = this._source[this._index]; | |
560 | - | |
561 | - switch (ch) { | |
562 | - case '$': | |
563 | - ++this._index; | |
564 | - const variable = new AST.Variable(this.getIdentifier()); | |
565 | - this.setPosition(variable, start, this._index); | |
566 | - return variable; | |
567 | - case '@': | |
568 | - ++this._index; | |
569 | - const global = new AST.Global(this.getIdentifier()); | |
570 | - this.setPosition(global, start, this._index); | |
571 | - return global; | |
572 | - default: | |
573 | - return this.getIdentifier(); | |
574 | - } | |
575 | - } | |
576 | - | |
577 | - getItemList(callback, closeChar) { | |
578 | - let items = []; | |
579 | - let closed = false; | |
580 | - | |
581 | - this.getWS(); | |
582 | - | |
583 | - if (this._source[this._index] === closeChar) { | |
584 | - ++this._index; | |
585 | - closed = true; | |
586 | - } | |
587 | - | |
588 | - while (!closed) { | |
589 | - items.push(callback.call(this)); | |
590 | - this.getWS(); | |
591 | - let ch = this._source.charAt(this._index); | |
592 | - switch (ch) { | |
593 | - case ',': | |
594 | - ++this._index; | |
595 | - this.getWS(); | |
596 | - break; | |
597 | - case closeChar: | |
598 | - ++this._index; | |
599 | - closed = true; | |
600 | - break; | |
601 | - default: | |
602 | - throw this.error('Expected "," or "' + closeChar + '"'); | |
603 | - } | |
604 | - } | |
605 | - | |
606 | - return items; | |
607 | - } | |
608 | - | |
609 | - error(message) { | |
610 | - const pos = this._index; | |
611 | - | |
612 | - let start = this._source.lastIndexOf('<', pos - 1); | |
613 | - let lastClose = this._source.lastIndexOf('>', pos - 1); | |
614 | - start = lastClose > start ? lastClose + 1 : start; | |
615 | - let context = this._source.slice(start, pos + 10); | |
616 | - | |
617 | - let msg = message + ' at pos ' + pos + ': `' + context + '`'; | |
618 | - | |
619 | - const err = new L10nError(msg); | |
620 | - err._pos = {start: pos, end: undefined}; | |
621 | - err.offset = pos - start; | |
622 | - err.description = message; | |
623 | - err.context = context; | |
624 | - return err; | |
625 | - } | |
626 | - | |
627 | - getJunkEntry() { | |
628 | - const pos = this._index; | |
629 | - let nextEntity = this._source.indexOf('<', pos); | |
630 | - let nextComment = this._source.indexOf('/*', pos); | |
631 | - | |
632 | - if (nextEntity === -1) { | |
633 | - nextEntity = this._length; | |
634 | - } | |
635 | - if (nextComment === -1) { | |
636 | - nextComment = this._length; | |
637 | - } | |
638 | - | |
639 | - let nextEntry = Math.min(nextEntity, nextComment); | |
640 | - | |
641 | - this._index = nextEntry; | |
642 | - | |
643 | - const junk = new AST.JunkEntry( | |
644 | - this._source.slice(this._curEntryStart, nextEntry)); | |
645 | - | |
646 | - this.setPosition(junk, this._curEntryStart, nextEntry); | |
647 | - return junk; | |
648 | - } | |
649 | - } | |
650 | - | |
651 | - var parser = { | |
652 | - parseResource: function(string, pos = false) { | |
653 | - const parseContext = new ParseContext(string, pos); | |
654 | - return parseContext.getResource(); | |
655 | - }, | |
656 | - }; | |
657 | - | |
658 | - exports.L20nParser = parser; | |
659 | - | |
660 | -}); | |
661 | 0 | \ No newline at end of file |
bower_components/l20n/dist/bundle/bridge/l20n-client.js deleted
1 | -(function () { 'use strict'; | |
2 | - | |
3 | - /* global bridge, BroadcastChannel */ | |
4 | - | |
5 | - const Client = bridge.client; | |
6 | - const channel = new BroadcastChannel('l20n-channel'); | |
7 | - | |
8 | - // match the opening angle bracket (<) in HTML tags, and HTML entities like | |
9 | - // &, &, &. | |
10 | - const reOverlay = /<|&#?\w+;/; | |
11 | - | |
12 | - const allowed = { | |
13 | - elements: [ | |
14 | - 'a', 'em', 'strong', 'small', 's', 'cite', 'q', 'dfn', 'abbr', 'data', | |
15 | - 'time', 'code', 'var', 'samp', 'kbd', 'sub', 'sup', 'i', 'b', 'u', | |
16 | - 'mark', 'ruby', 'rt', 'rp', 'bdi', 'bdo', 'span', 'br', 'wbr' | |
17 | - ], | |
18 | - attributes: { | |
19 | - global: [ 'title', 'aria-label', 'aria-valuetext', 'aria-moz-hint' ], | |
20 | - a: [ 'download' ], | |
21 | - area: [ 'download', 'alt' ], | |
22 | - // value is special-cased in isAttrAllowed | |
23 | - input: [ 'alt', 'placeholder' ], | |
24 | - menuitem: [ 'label' ], | |
25 | - menu: [ 'label' ], | |
26 | - optgroup: [ 'label' ], | |
27 | - option: [ 'label' ], | |
28 | - track: [ 'label' ], | |
29 | - img: [ 'alt' ], | |
30 | - textarea: [ 'placeholder' ], | |
31 | - th: [ 'abbr'] | |
32 | - } | |
33 | - }; | |
34 | - | |
35 | - function overlayElement(element, translation) { | |
36 | - const value = translation.value; | |
37 | - | |
38 | - if (typeof value === 'string') { | |
39 | - if (!reOverlay.test(value)) { | |
40 | - element.textContent = value; | |
41 | - } else { | |
42 | - // start with an inert template element and move its children into | |
43 | - // `element` but such that `element`'s own children are not replaced | |
44 | - const tmpl = element.ownerDocument.createElement('template'); | |
45 | - tmpl.innerHTML = value; | |
46 | - // overlay the node with the DocumentFragment | |
47 | - overlay(element, tmpl.content); | |
48 | - } | |
49 | - } | |
50 | - | |
51 | - for (let key in translation.attrs) { | |
52 | - const attrName = camelCaseToDashed(key); | |
53 | - if (isAttrAllowed({ name: attrName }, element)) { | |
54 | - element.setAttribute(attrName, translation.attrs[key]); | |
55 | - } | |
56 | - } | |
57 | - } | |
58 | - | |
59 | - // The goal of overlay is to move the children of `translationElement` | |
60 | - // into `sourceElement` such that `sourceElement`'s own children are not | |
61 | - // replaced, but onle have their text nodes and their attributes modified. | |
62 | - // | |
63 | - // We want to make it possible for localizers to apply text-level semantics to | |
64 | - // the translations and make use of HTML entities. At the same time, we | |
65 | - // don't trust translations so we need to filter unsafe elements and | |
66 | - // attribtues out and we don't want to break the Web by replacing elements to | |
67 | - // which third-party code might have created references (e.g. two-way | |
68 | - // bindings in MVC frameworks). | |
69 | - function overlay(sourceElement, translationElement) { | |
70 | - const result = translationElement.ownerDocument.createDocumentFragment(); | |
71 | - let k, attr; | |
72 | - | |
73 | - // take one node from translationElement at a time and check it against | |
74 | - // the allowed list or try to match it with a corresponding element | |
75 | - // in the source | |
76 | - let childElement; | |
77 | - while ((childElement = translationElement.childNodes[0])) { | |
78 | - translationElement.removeChild(childElement); | |
79 | - | |
80 | - if (childElement.nodeType === childElement.TEXT_NODE) { | |
81 | - result.appendChild(childElement); | |
82 | - continue; | |
83 | - } | |
84 | - | |
85 | - const index = getIndexOfType(childElement); | |
86 | - const sourceChild = getNthElementOfType(sourceElement, childElement, index); | |
87 | - if (sourceChild) { | |
88 | - // there is a corresponding element in the source, let's use it | |
89 | - overlay(sourceChild, childElement); | |
90 | - result.appendChild(sourceChild); | |
91 | - continue; | |
92 | - } | |
93 | - | |
94 | - if (isElementAllowed(childElement)) { | |
95 | - const sanitizedChild = childElement.ownerDocument.createElement( | |
96 | - childElement.nodeName); | |
97 | - overlay(sanitizedChild, childElement); | |
98 | - result.appendChild(sanitizedChild); | |
99 | - continue; | |
100 | - } | |
101 | - | |
102 | - // otherwise just take this child's textContent | |
103 | - result.appendChild( | |
104 | - translationElement.ownerDocument.createTextNode( | |
105 | - childElement.textContent)); | |
106 | - } | |
107 | - | |
108 | - // clear `sourceElement` and append `result` which by this time contains | |
109 | - // `sourceElement`'s original children, overlayed with translation | |
110 | - sourceElement.textContent = ''; | |
111 | - sourceElement.appendChild(result); | |
112 | - | |
113 | - // if we're overlaying a nested element, translate the allowed | |
114 | - // attributes; top-level attributes are handled in `translateElement` | |
115 | - // XXX attributes previously set here for another language should be | |
116 | - // cleared if a new language doesn't use them; https://bugzil.la/922577 | |
117 | - if (translationElement.attributes) { | |
118 | - for (k = 0, attr; (attr = translationElement.attributes[k]); k++) { | |
119 | - if (isAttrAllowed(attr, sourceElement)) { | |
120 | - sourceElement.setAttribute(attr.name, attr.value); | |
121 | - } | |
122 | - } | |
123 | - } | |
124 | - } | |
125 | - | |
126 | - // XXX the allowed list should be amendable; https://bugzil.la/922573 | |
127 | - function isElementAllowed(element) { | |
128 | - return allowed.elements.indexOf(element.tagName.toLowerCase()) !== -1; | |
129 | - } | |
130 | - | |
131 | - function isAttrAllowed(attr, element) { | |
132 | - const attrName = attr.name.toLowerCase(); | |
133 | - const tagName = element.tagName.toLowerCase(); | |
134 | - // is it a globally safe attribute? | |
135 | - if (allowed.attributes.global.indexOf(attrName) !== -1) { | |
136 | - return true; | |
137 | - } | |
138 | - // are there no allowed attributes for this element? | |
139 | - if (!allowed.attributes[tagName]) { | |
140 | - return false; | |
141 | - } | |
142 | - // is it allowed on this element? | |
143 | - // XXX the allowed list should be amendable; https://bugzil.la/922573 | |
144 | - if (allowed.attributes[tagName].indexOf(attrName) !== -1) { | |
145 | - return true; | |
146 | - } | |
147 | - // special case for value on inputs with type button, reset, submit | |
148 | - if (tagName === 'input' && attrName === 'value') { | |
149 | - const type = element.type.toLowerCase(); | |
150 | - if (type === 'submit' || type === 'button' || type === 'reset') { | |
151 | - return true; | |
152 | - } | |
153 | - } | |
154 | - return false; | |
155 | - } | |
156 | - | |
157 | - // Get n-th immediate child of context that is of the same type as element. | |
158 | - // XXX Use querySelector(':scope > ELEMENT:nth-of-type(index)'), when: | |
159 | - // 1) :scope is widely supported in more browsers and 2) it works with | |
160 | - // DocumentFragments. | |
161 | - function getNthElementOfType(context, element, index) { | |
162 | - /* jshint boss:true */ | |
163 | - let nthOfType = 0; | |
164 | - for (let i = 0, child; child = context.children[i]; i++) { | |
165 | - if (child.nodeType === child.ELEMENT_NODE && | |
166 | - child.tagName === element.tagName) { | |
167 | - if (nthOfType === index) { | |
168 | - return child; | |
169 | - } | |
170 | - nthOfType++; | |
171 | - } | |
172 | - } | |
173 | - return null; | |
174 | - } | |
175 | - | |
176 | - // Get the index of the element among siblings of the same type. | |
177 | - function getIndexOfType(element) { | |
178 | - let index = 0; | |
179 | - let child; | |
180 | - while ((child = element.previousElementSibling)) { | |
181 | - if (child.tagName === element.tagName) { | |
182 | - index++; | |
183 | - } | |
184 | - } | |
185 | - return index; | |
186 | - } | |
187 | - | |
188 | - function camelCaseToDashed(string) { | |
189 | - // XXX workaround for https://bugzil.la/1141934 | |
190 | - if (string === 'ariaValueText') { | |
191 | - return 'aria-valuetext'; | |
192 | - } | |
193 | - | |
194 | - return string | |
195 | - .replace(/[A-Z]/g, function (match) { | |
196 | - return '-' + match.toLowerCase(); | |
197 | - }) | |
198 | - .replace(/^-/, ''); | |
199 | - } | |
200 | - | |
201 | - const reHtml = /[&<>]/g; | |
202 | - const htmlEntities = { | |
203 | - '&': '&', | |
204 | - '<': '<', | |
205 | - '>': '>', | |
206 | - }; | |
207 | - | |
208 | - function getResourceLinks(head) { | |
209 | - return Array.prototype.map.call( | |
210 | - head.querySelectorAll('link[rel="localization"]'), | |
211 | - el => el.getAttribute('href')); | |
212 | - } | |
213 | - | |
214 | - function setAttributes(element, id, args) { | |
215 | - element.setAttribute('data-l10n-id', id); | |
216 | - if (args) { | |
217 | - element.setAttribute('data-l10n-args', JSON.stringify(args)); | |
218 | - } | |
219 | - } | |
220 | - | |
221 | - function getAttributes(element) { | |
222 | - return { | |
223 | - id: element.getAttribute('data-l10n-id'), | |
224 | - args: JSON.parse(element.getAttribute('data-l10n-args')) | |
225 | - }; | |
226 | - } | |
227 | - | |
228 | - function getTranslatables(element) { | |
229 | - const nodes = Array.from(element.querySelectorAll('[data-l10n-id]')); | |
230 | - | |
231 | - if (typeof element.hasAttribute === 'function' && | |
232 | - element.hasAttribute('data-l10n-id')) { | |
233 | - nodes.push(element); | |
234 | - } | |
235 | - | |
236 | - return nodes; | |
237 | - } | |
238 | - | |
239 | - function translateMutations(view, langs, mutations) { | |
240 | - const targets = new Set(); | |
241 | - | |
242 | - for (let mutation of mutations) { | |
243 | - switch (mutation.type) { | |
244 | - case 'attributes': | |
245 | - targets.add(mutation.target); | |
246 | - break; | |
247 | - case 'childList': | |
248 | - for (let addedNode of mutation.addedNodes) { | |
249 | - if (addedNode.nodeType === addedNode.ELEMENT_NODE) { | |
250 | - if (addedNode.childElementCount) { | |
251 | - getTranslatables(addedNode).forEach(targets.add.bind(targets)); | |
252 | - } else { | |
253 | - if (addedNode.hasAttribute('data-l10n-id')) { | |
254 | - targets.add(addedNode); | |
255 | - } | |
256 | - } | |
257 | - } | |
258 | - } | |
259 | - break; | |
260 | - } | |
261 | - } | |
262 | - | |
263 | - if (targets.size === 0) { | |
264 | - return; | |
265 | - } | |
266 | - | |
267 | - translateElements(view, langs, Array.from(targets)); | |
268 | - } | |
269 | - | |
270 | - function translateFragment(view, langs, frag) { | |
271 | - return translateElements(view, langs, getTranslatables(frag)); | |
272 | - } | |
273 | - | |
274 | - function getElementsTranslation(view, langs, elems) { | |
275 | - const keys = elems.map(elem => { | |
276 | - const id = elem.getAttribute('data-l10n-id'); | |
277 | - const args = elem.getAttribute('data-l10n-args'); | |
278 | - return args ? [ | |
279 | - id, | |
280 | - JSON.parse(args.replace(reHtml, match => htmlEntities[match])) | |
281 | - ] : id; | |
282 | - }); | |
283 | - | |
284 | - return view._resolveEntities(langs, keys); | |
285 | - } | |
286 | - | |
287 | - function translateElements(view, langs, elements) { | |
288 | - return getElementsTranslation(view, langs, elements).then( | |
289 | - translations => applyTranslations(view, elements, translations)); | |
290 | - } | |
291 | - | |
292 | - function applyTranslations(view, elems, translations) { | |
293 | - view._disconnect(); | |
294 | - for (let i = 0; i < elems.length; i++) { | |
295 | - overlayElement(elems[i], translations[i]); | |
296 | - } | |
297 | - view._observe(); | |
298 | - } | |
299 | - | |
300 | - // Polyfill NodeList.prototype[Symbol.iterator] for Chrome. | |
301 | - // See https://code.google.com/p/chromium/issues/detail?id=401699 | |
302 | - if (typeof NodeList === 'function' && !NodeList.prototype[Symbol.iterator]) { | |
303 | - NodeList.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator]; | |
304 | - } | |
305 | - | |
306 | - // A document.ready shim | |
307 | - // https://github.com/whatwg/html/issues/127 | |
308 | - function documentReady() { | |
309 | - if (document.readyState !== 'loading') { | |
310 | - return Promise.resolve(); | |
311 | - } | |
312 | - | |
313 | - return new Promise(resolve => { | |
314 | - document.addEventListener('readystatechange', function onrsc() { | |
315 | - document.removeEventListener('readystatechange', onrsc); | |
316 | - resolve(); | |
317 | - }); | |
318 | - }); | |
319 | - } | |
320 | - | |
321 | - // Intl.Locale | |
322 | - function getDirection(code) { | |
323 | - const tag = code.split('-')[0]; | |
324 | - return ['ar', 'he', 'fa', 'ps', 'ur'].indexOf(tag) >= 0 ? | |
325 | - 'rtl' : 'ltr'; | |
326 | - } | |
327 | - | |
328 | - const observerConfig = { | |
329 | - attributes: true, | |
330 | - characterData: false, | |
331 | - childList: true, | |
332 | - subtree: true, | |
333 | - attributeFilter: ['data-l10n-id', 'data-l10n-args'] | |
334 | - }; | |
335 | - | |
336 | - const readiness = new WeakMap(); | |
337 | - | |
338 | - class View { | |
339 | - constructor(client, doc) { | |
340 | - this._doc = doc; | |
341 | - this.pseudo = { | |
342 | - 'fr-x-psaccent': createPseudo(this, 'fr-x-psaccent'), | |
343 | - 'ar-x-psbidi': createPseudo(this, 'ar-x-psbidi') | |
344 | - }; | |
345 | - | |
346 | - this._interactive = documentReady().then( | |
347 | - () => init(this, client)); | |
348 | - | |
349 | - const observer = new MutationObserver(onMutations.bind(this)); | |
350 | - this._observe = () => observer.observe(doc, observerConfig); | |
351 | - this._disconnect = () => observer.disconnect(); | |
352 | - | |
353 | - const translateView = langs => translateDocument(this, langs); | |
354 | - client.on('translateDocument', translateView); | |
355 | - this.ready = this._interactive.then( | |
356 | - client => client.method('resolvedLanguages')).then( | |
357 | - translateView); | |
358 | - } | |
359 | - | |
360 | - requestLanguages(langs, global) { | |
361 | - return this._interactive.then( | |
362 | - client => client.method('requestLanguages', langs, global)); | |
363 | - } | |
364 | - | |
365 | - _resolveEntities(langs, keys) { | |
366 | - return this._interactive.then( | |
367 | - client => client.method('resolveEntities', client.id, langs, keys)); | |
368 | - } | |
369 | - | |
370 | - formatValue(id, args) { | |
371 | - return this._interactive.then( | |
372 | - client => client.method('formatValues', client.id, [[id, args]])).then( | |
373 | - values => values[0]); | |
374 | - } | |
375 | - | |
376 | - formatValues(...keys) { | |
377 | - return this._interactive.then( | |
378 | - client => client.method('formatValues', client.id, keys)); | |
379 | - } | |
380 | - | |
381 | - translateFragment(frag) { | |
382 | - return this._interactive.then( | |
383 | - client => client.method('resolvedLanguages')).then( | |
384 | - langs => translateFragment(this, langs, frag)); | |
385 | - } | |
386 | - } | |
387 | - | |
388 | - View.prototype.setAttributes = setAttributes; | |
389 | - View.prototype.getAttributes = getAttributes; | |
390 | - | |
391 | - function createPseudo(view, code) { | |
392 | - return { | |
393 | - getName: () => view._interactive.then( | |
394 | - client => client.method('getName', code)), | |
395 | - processString: str => view._interactive.then( | |
396 | - client => client.method('processString', code, str)), | |
397 | - }; | |
398 | - } | |
399 | - | |
400 | - function init(view, client) { | |
401 | - view._observe(); | |
402 | - return client.method( | |
403 | - 'registerView', client.id, getResourceLinks(view._doc.head)).then( | |
404 | - () => client); | |
405 | - } | |
406 | - | |
407 | - function onMutations(mutations) { | |
408 | - return this._interactive.then( | |
409 | - client => client.method('resolvedLanguages')).then( | |
410 | - langs => translateMutations(this, langs, mutations)); | |
411 | - } | |
412 | - | |
413 | - function translateDocument(view, langs) { | |
414 | - const html = view._doc.documentElement; | |
415 | - | |
416 | - if (readiness.has(html)) { | |
417 | - return translateFragment(view, langs, html).then( | |
418 | - () => setAllAndEmit(html, langs)); | |
419 | - } | |
420 | - | |
421 | - const translated = | |
422 | - // has the document been already pre-translated? | |
423 | - langs[0].code === html.getAttribute('lang') ? | |
424 | - Promise.resolve() : | |
425 | - translateFragment(view, langs, html).then( | |
426 | - () => setLangDir(html, langs)); | |
427 | - | |
428 | - return translated.then(() => { | |
429 | - setLangs(html, langs); | |
430 | - readiness.set(html, true); | |
431 | - }); | |
432 | - } | |
433 | - | |
434 | - function setLangs(html, langs) { | |
435 | - const codes = langs.map(lang => lang.code); | |
436 | - html.setAttribute('langs', codes.join(' ')); | |
437 | - } | |
438 | - | |
439 | - function setLangDir(html, langs) { | |
440 | - const code = langs[0].code; | |
441 | - html.setAttribute('lang', code); | |
442 | - html.setAttribute('dir', getDirection(code)); | |
443 | - } | |
444 | - | |
445 | - function setAllAndEmit(html, langs) { | |
446 | - setLangDir(html, langs); | |
447 | - setLangs(html, langs); | |
448 | - html.parentNode.dispatchEvent(new CustomEvent('DOMRetranslated', { | |
449 | - bubbles: false, | |
450 | - cancelable: false, | |
451 | - })); | |
452 | - } | |
453 | - | |
454 | - const client = new Client({ | |
455 | - service: 'l20n', | |
456 | - endpoint: channel, | |
457 | - timeout: false | |
458 | - }); | |
459 | - | |
460 | - window.addEventListener('pageshow', () => client.connect()); | |
461 | - window.addEventListener('pagehide', () => client.disconnect()); | |
462 | - | |
463 | - document.l10n = new View(client, document); | |
464 | - | |
465 | - //Bug 1204660 - Temporary proxy for shared code. Will be removed once | |
466 | - // l10n.js migration is completed. | |
467 | - navigator.mozL10n = { | |
468 | - setAttributes: document.l10n.setAttributes, | |
469 | - getAttributes: document.l10n.getAttributes, | |
470 | - formatValue: (...args) => document.l10n.formatValue(...args), | |
471 | - translateFragment: (...args) => document.l10n.translateFragment(...args), | |
472 | - once: cb => document.l10n.ready.then(cb), | |
473 | - ready: cb => document.l10n.ready.then(() => { | |
474 | - document.addEventListener('DOMRetranslated', cb); | |
475 | - cb(); | |
476 | - }), | |
477 | - }; | |
478 | - | |
479 | -})(); | |
480 | 0 | \ No newline at end of file |
bower_components/l20n/dist/bundle/bridge/l20n-service.js deleted
1 | -(function () { 'use strict'; | |
2 | - | |
3 | - const Service = bridge.service; | |
4 | - const channel = new BroadcastChannel('l20n-channel'); | |
5 | - | |
6 | - function broadcast(type, data) { | |
7 | - return this.service.broadcast(type, data); | |
8 | - } | |
9 | - | |
10 | - function L10nError(message, id, lang) { | |
11 | - this.name = 'L10nError'; | |
12 | - this.message = message; | |
13 | - this.id = id; | |
14 | - this.lang = lang; | |
15 | - } | |
16 | - L10nError.prototype = Object.create(Error.prototype); | |
17 | - L10nError.prototype.constructor = L10nError; | |
18 | - | |
19 | - function load(type, url) { | |
20 | - return new Promise(function(resolve, reject) { | |
21 | - const xhr = new XMLHttpRequest(); | |
22 | - | |
23 | - if (xhr.overrideMimeType) { | |
24 | - xhr.overrideMimeType(type); | |
25 | - } | |
26 | - | |
27 | - xhr.open('GET', url, true); | |
28 | - | |
29 | - if (type === 'application/json') { | |
30 | - xhr.responseType = 'json'; | |
31 | - } | |
32 | - | |
33 | - xhr.addEventListener('load', function io_onload(e) { | |
34 | - if (e.target.status === 200 || e.target.status === 0) { | |
35 | - // Sinon.JS's FakeXHR doesn't have the response property | |
36 | - resolve(e.target.response || e.target.responseText); | |
37 | - } else { | |
38 | - reject(new L10nError('Not found: ' + url)); | |
39 | - } | |
40 | - }); | |
41 | - xhr.addEventListener('error', reject); | |
42 | - xhr.addEventListener('timeout', reject); | |
43 | - | |
44 | - // the app: protocol throws on 404, see https://bugzil.la/827243 | |
45 | - try { | |
46 | - xhr.send(null); | |
47 | - } catch (e) { | |
48 | - if (e.name === 'NS_ERROR_FILE_NOT_FOUND') { | |
49 | - // the app: protocol throws on 404, see https://bugzil.la/827243 | |
50 | - reject(new L10nError('Not found: ' + url)); | |
51 | - } else { | |
52 | - throw e; | |
53 | - } | |
54 | - } | |
55 | - }); | |
56 | - } | |
57 | - | |
58 | - const io = { | |
59 | - extra: function(code, ver, path, type) { | |
60 | - return navigator.mozApps.getLocalizationResource( | |
61 | - code, ver, path, type); | |
62 | - }, | |
63 | - app: function(code, ver, path, type) { | |
64 | - switch (type) { | |
65 | - case 'text': | |
66 | - return load('text/plain', path); | |
67 | - case 'json': | |
68 | - return load('application/json', path); | |
69 | - default: | |
70 | - throw new L10nError('Unknown file type: ' + type); | |
71 | - } | |
72 | - }, | |
73 | - }; | |
74 | - | |
75 | - function fetchResource(ver, res, lang) { | |
76 | - const url = res.replace('{locale}', lang.code); | |
77 | - const type = res.endsWith('.json') ? 'json' : 'text'; | |
78 | - return io[lang.src](lang.code, ver, url, type); | |
79 | - } | |
80 | - | |
81 | - const MAX_PLACEABLES$1 = 100; | |
82 | - | |
83 | - var L20nParser = { | |
84 | - parse: function(emit, string) { | |
85 | - this._source = string; | |
86 | - this._index = 0; | |
87 | - this._length = string.length; | |
88 | - this.entries = Object.create(null); | |
89 | - this.emit = emit; | |
90 | - | |
91 | - return this.getResource(); | |
92 | - }, | |
93 | - | |
94 | - getResource: function() { | |
95 | - this.getWS(); | |
96 | - while (this._index < this._length) { | |
97 | - try { | |
98 | - this.getEntry(); | |
99 | - } catch (e) { | |
100 | - if (e instanceof L10nError) { | |
101 | - // we want to recover, but we don't need it in entries | |
102 | - this.getJunkEntry(); | |
103 | - if (!this.emit) { | |
104 | - throw e; | |
105 | - } | |
106 | - } else { | |
107 | - throw e; | |
108 | - } | |
109 | - } | |
110 | - | |
111 | - if (this._index < this._length) { | |
112 | - this.getWS(); | |
113 | - } | |
114 | - } | |
115 | - | |
116 | - return this.entries; | |
117 | - }, | |
118 | - | |
119 | - getEntry: function() { | |
120 | - if (this._source[this._index] === '<') { | |
121 | - ++this._index; | |
122 | - const id = this.getIdentifier(); | |
123 | - if (this._source[this._index] === '[') { | |
124 | - ++this._index; | |
125 | - return this.getEntity(id, this.getItemList(this.getExpression, ']')); | |
126 | - } | |
127 | - return this.getEntity(id); | |
128 | - } | |
129 | - | |
130 | - if (this._source.startsWith('/*', this._index)) { | |
131 | - return this.getComment(); | |
132 | - } | |
133 | - | |
134 | - throw this.error('Invalid entry'); | |
135 | - }, | |
136 | - | |
137 | - getEntity: function(id, index) { | |
138 | - if (!this.getRequiredWS()) { | |
139 | - throw this.error('Expected white space'); | |
140 | - } | |
141 | - | |
142 | - const ch = this._source[this._index]; | |
143 | - const value = this.getValue(ch, index === undefined); | |
144 | - let attrs; | |
145 | - | |
146 | - if (value === undefined) { | |
147 | - if (ch === '>') { | |
148 | - throw this.error('Expected ">"'); | |
149 | - } | |
150 | - attrs = this.getAttributes(); | |
151 | - } else { | |
152 | - const ws1 = this.getRequiredWS(); | |
153 | - if (this._source[this._index] !== '>') { | |
154 | - if (!ws1) { | |
155 | - throw this.error('Expected ">"'); | |
156 | - } | |
157 | - attrs = this.getAttributes(); | |
158 | - } | |
159 | - } | |
160 | - | |
161 | - // skip '>' | |
162 | - ++this._index; | |
163 | - | |
164 | - if (id in this.entries) { | |
165 | - throw this.error('Duplicate entry ID "' + id, 'duplicateerror'); | |
166 | - } | |
167 | - if (!attrs && !index && typeof value === 'string') { | |
168 | - this.entries[id] = value; | |
169 | - } else { | |
170 | - this.entries[id] = { | |
171 | - value, | |
172 | - attrs, | |
173 | - index | |
174 | - }; | |
175 | - } | |
176 | - }, | |
177 | - | |
178 | - getValue: function(ch = this._source[this._index], optional = false) { | |
179 | - switch (ch) { | |
180 | - case '\'': | |
181 | - case '"': | |
182 | - return this.getString(ch, 1); | |
183 | - case '{': | |
184 | - return this.getHash(); | |
185 | - } | |
186 | - | |
187 | - if (!optional) { | |
188 | - throw this.error('Unknown value type'); | |
189 | - } | |
190 | - | |
191 | - return; | |
192 | - }, | |
193 | - | |
194 | - getWS: function() { | |
195 | - let cc = this._source.charCodeAt(this._index); | |
196 | - // space, \n, \t, \r | |
197 | - while (cc === 32 || cc === 10 || cc === 9 || cc === 13) { | |
198 | - cc = this._source.charCodeAt(++this._index); | |
199 | - } | |
200 | - }, | |
201 | - | |
202 | - getRequiredWS: function() { | |
203 | - const pos = this._index; | |
204 | - let cc = this._source.charCodeAt(pos); | |
205 | - // space, \n, \t, \r | |
206 | - while (cc === 32 || cc === 10 || cc === 9 || cc === 13) { | |
207 | - cc = this._source.charCodeAt(++this._index); | |
208 | - } | |
209 | - return this._index !== pos; | |
210 | - }, | |
211 | - | |
212 | - getIdentifier: function() { | |
213 | - const start = this._index; | |
214 | - let cc = this._source.charCodeAt(this._index); | |
215 | - | |
216 | - if ((cc >= 97 && cc <= 122) || // a-z | |
217 | - (cc >= 65 && cc <= 90) || // A-Z | |
218 | - cc === 95) { // _ | |
219 | - cc = this._source.charCodeAt(++this._index); | |
220 | - } else { | |
221 | - throw this.error('Identifier has to start with [a-zA-Z_]'); | |
222 | - } | |
223 | - | |
224 | - while ((cc >= 97 && cc <= 122) || // a-z | |
225 | - (cc >= 65 && cc <= 90) || // A-Z | |
226 | - (cc >= 48 && cc <= 57) || // 0-9 | |
227 | - cc === 95) { // _ | |
228 | - cc = this._source.charCodeAt(++this._index); | |
229 | - } | |
230 | - | |
231 | - return this._source.slice(start, this._index); | |
232 | - }, | |
233 | - | |
234 | - getUnicodeChar: function() { | |
235 | - for (let i = 0; i < 4; i++) { | |
236 | - let cc = this._source.charCodeAt(++this._index); | |
237 | - if ((cc > 96 && cc < 103) || // a-f | |
238 | - (cc > 64 && cc < 71) || // A-F | |
239 | - (cc > 47 && cc < 58)) { // 0-9 | |
240 | - continue; | |
241 | - } | |
242 | - throw this.error('Illegal unicode escape sequence'); | |
243 | - } | |
244 | - this._index++; | |
245 | - return String.fromCharCode( | |
246 | - parseInt(this._source.slice(this._index - 4, this._index), 16)); | |
247 | - }, | |
248 | - | |
249 | - stringRe: /"|'|{{|\\/g, | |
250 | - getString: function(opchar, opcharLen) { | |
251 | - const body = []; | |
252 | - let placeables = 0; | |
253 | - | |
254 | - this._index += opcharLen; | |
255 | - const start = this._index; | |
256 | - | |
257 | - let bufStart = start; | |
258 | - let buf = ''; | |
259 | - | |
260 | - while (true) { | |
261 | - this.stringRe.lastIndex = this._index; | |
262 | - const match = this.stringRe.exec(this._source); | |
263 | - | |
264 | - if (!match) { | |
265 | - throw this.error('Unclosed string literal'); | |
266 | - } | |
267 | - | |
268 | - if (match[0] === '"' || match[0] === '\'') { | |
269 | - if (match[0] !== opchar) { | |
270 | - this._index += opcharLen; | |
271 | - continue; | |
272 | - } | |
273 | - this._index = match.index + opcharLen; | |
274 | - break; | |
275 | - } | |
276 | - | |
277 | - if (match[0] === '{{') { | |
278 | - if (placeables > MAX_PLACEABLES$1 - 1) { | |
279 | - throw this.error('Too many placeables, maximum allowed is ' + | |
280 | - MAX_PLACEABLES$1); | |
281 | - } | |
282 | - placeables++; | |
283 | - if (match.index > bufStart || buf.length > 0) { | |
284 | - body.push(buf + this._source.slice(bufStart, match.index)); | |
285 | - buf = ''; | |
286 | - } | |
287 | - this._index = match.index + 2; | |
288 | - this.getWS(); | |
289 | - body.push(this.getExpression()); | |
290 | - this.getWS(); | |
291 | - this._index += 2; | |
292 | - bufStart = this._index; | |
293 | - continue; | |
294 | - } | |
295 | - | |
296 | - if (match[0] === '\\') { | |
297 | - this._index = match.index + 1; | |
298 | - const ch2 = this._source[this._index]; | |
299 | - if (ch2 === 'u') { | |
300 | - buf += this._source.slice(bufStart, match.index) + | |
301 | - this.getUnicodeChar(); | |
302 | - } else if (ch2 === opchar || ch2 === '\\') { | |
303 | - buf += this._source.slice(bufStart, match.index) + ch2; | |
304 | - this._index++; | |
305 | - } else if (this._source.startsWith('{{', this._index)) { | |
306 | - buf += this._source.slice(bufStart, match.index) + '{{'; | |
307 | - this._index += 2; | |
308 | - } else { | |
309 | - throw this.error('Illegal escape sequence'); | |
310 | - } | |
311 | - bufStart = this._index; | |
312 | - } | |
313 | - } | |
314 | - | |
315 | - if (body.length === 0) { | |
316 | - return buf + this._source.slice(bufStart, this._index - opcharLen); | |
317 | - } | |
318 | - | |
319 | - if (this._index - opcharLen > bufStart || buf.length > 0) { | |
320 | - body.push(buf + this._source.slice(bufStart, this._index - opcharLen)); | |
321 | - } | |
322 | - | |
323 | - return body; | |
324 | - }, | |
325 | - | |
326 | - getAttributes: function() { | |
327 | - const attrs = Object.create(null); | |
328 | - | |
329 | - while (true) { | |
330 | - this.getAttribute(attrs); | |
331 | - const ws1 = this.getRequiredWS(); | |
332 | - const ch = this._source.charAt(this._index); | |
333 | - if (ch === '>') { | |
334 | - break; | |
335 | - } else if (!ws1) { | |
336 | - throw this.error('Expected ">"'); | |
337 | - } | |
338 | - } | |
339 | - return attrs; | |
340 | - }, | |
341 | - | |
342 | - getAttribute: function(attrs) { | |
343 | - const key = this.getIdentifier(); | |
344 | - let index; | |
345 | - | |
346 | - if (this._source[this._index]=== '[') { | |
347 | - ++this._index; | |
348 | - this.getWS(); | |
349 | - index = this.getItemList(this.getExpression, ']'); | |
350 | - } | |
351 | - this.getWS(); | |
352 | - if (this._source[this._index] !== ':') { | |
353 | - throw this.error('Expected ":"'); | |
354 | - } | |
355 | - ++this._index; | |
356 | - this.getWS(); | |
357 | - const value = this.getValue(); | |
358 | - | |
359 | - if (key in attrs) { | |
360 | - throw this.error('Duplicate attribute "' + key, 'duplicateerror'); | |
361 | - } | |
362 | - | |
363 | - if (!index && typeof value === 'string') { | |
364 | - attrs[key] = value; | |
365 | - } else { | |
366 | - attrs[key] = { | |
367 | - value, | |
368 | - index | |
369 | - }; | |
370 | - } | |
371 | - }, | |
372 | - | |
373 | - getHash: function() { | |
374 | - const items = Object.create(null); | |
375 | - | |
376 | - ++this._index; | |
377 | - this.getWS(); | |
378 | - | |
379 | - let defKey; | |
380 | - | |
381 | - while (true) { | |
382 | - const [key, value, def] = this.getHashItem(); | |
383 | - items[key] = value; | |
384 | - | |
385 | - if (def) { | |
386 | - if (defKey) { | |
387 | - throw this.error('Default item redefinition forbidden'); | |
388 | - } | |
389 | - defKey = key; | |
390 | - } | |
391 | - this.getWS(); | |
392 | - | |
393 | - const comma = this._source[this._index] === ','; | |
394 | - if (comma) { | |
395 | - ++this._index; | |
396 | - this.getWS(); | |
397 | - } | |
398 | - if (this._source[this._index] === '}') { | |
399 | - ++this._index; | |
400 | - break; | |
401 | - } | |
402 | - if (!comma) { | |
403 | - throw this.error('Expected "}"'); | |
404 | - } | |
405 | - } | |
406 | - | |
407 | - if (defKey) { | |
408 | - items.__default = defKey; | |
409 | - } | |
410 | - | |
411 | - return items; | |
412 | - }, | |
413 | - | |
414 | - getHashItem: function() { | |
415 | - let defItem = false; | |
416 | - if (this._source[this._index] === '*') { | |
417 | - ++this._index; | |
418 | - defItem = true; | |
419 | - } | |
420 | - | |
421 | - const key = this.getIdentifier(); | |
422 | - this.getWS(); | |
423 | - if (this._source[this._index] !== ':') { | |
424 | - throw this.error('Expected ":"'); | |
425 | - } | |
426 | - ++this._index; | |
427 | - this.getWS(); | |
428 | - | |
429 | - return [key, this.getValue(), defItem]; | |
430 | - }, | |
431 | - | |
432 | - getComment: function() { | |
433 | - this._index += 2; | |
434 | - const start = this._index; | |
435 | - const end = this._source.indexOf('*/', start); | |
436 | - | |
437 | - if (end === -1) { | |
438 | - throw this.error('Comment without a closing tag'); | |
439 | - } | |
440 | - | |
441 | - this._index = end + 2; | |
442 | - }, | |
443 | - | |
444 | - getExpression: function () { | |
445 | - let exp = this.getPrimaryExpression(); | |
446 | - | |
447 | - while (true) { | |
448 | - let ch = this._source[this._index]; | |
449 | - if (ch === '.' || ch === '[') { | |
450 | - ++this._index; | |
451 | - exp = this.getPropertyExpression(exp, ch === '['); | |
452 | - } else if (ch === '(') { | |
453 | - ++this._index; | |
454 | - exp = this.getCallExpression(exp); | |
455 | - } else { | |
456 | - break; | |
457 | - } | |
458 | - } | |
459 | - | |
460 | - return exp; | |
461 | - }, | |
462 | - | |
463 | - getPropertyExpression: function(idref, computed) { | |
464 | - let exp; | |
465 | - | |
466 | - if (computed) { | |
467 | - this.getWS(); | |
468 | - exp = this.getExpression(); | |
469 | - this.getWS(); | |
470 | - if (this._source[this._index] !== ']') { | |
471 | - throw this.error('Expected "]"'); | |
472 | - } | |
473 | - ++this._index; | |
474 | - } else { | |
475 | - exp = this.getIdentifier(); | |
476 | - } | |
477 | - | |
478 | - return { | |
479 | - type: 'prop', | |
480 | - expr: idref, | |
481 | - prop: exp, | |
482 | - cmpt: computed | |
483 | - }; | |
484 | - }, | |
485 | - | |
486 | - getCallExpression: function(callee) { | |
487 | - this.getWS(); | |
488 | - | |
489 | - return { | |
490 | - type: 'call', | |
491 | - expr: callee, | |
492 | - args: this.getItemList(this.getExpression, ')') | |
493 | - }; | |
494 | - }, | |
495 | - | |
496 | - getPrimaryExpression: function() { | |
497 | - const ch = this._source[this._index]; | |
498 | - | |
499 | - switch (ch) { | |
500 | - case '$': | |
501 | - ++this._index; | |
502 | - return { | |
503 | - type: 'var', | |
504 | - name: this.getIdentifier() | |
505 | - }; | |
506 | - case '@': | |
507 | - ++this._index; | |
508 | - return { | |
509 | - type: 'glob', | |
510 | - name: this.getIdentifier() | |
511 | - }; | |
512 | - default: | |
513 | - return { | |
514 | - type: 'id', | |
515 | - name: this.getIdentifier() | |
516 | - }; | |
517 | - } | |
518 | - }, | |
519 | - | |
520 |