|
108 | 108 |
|
109 | 109 | /** |
110 | 110 | * Patterns are employed to identify tokens embedded within markup, and then parse any discrete components. |
111 | | - * TODO: Provide for nested expressions (the pattern already captures all, so split(':') and apply). |
112 | 111 | * |
113 | 112 | * @private static |
114 | 113 | * @property proxy will match the token-identifying wrapper (e.g. the "{{ info }}" of <span>{{ info }}</span>). |
|
119 | 118 | * @property expressioncombo separates expression(s) from a combineString list (e.g. "combineString:("foo",bar)"). |
120 | 119 | * @property orsplit separates tokens progressively considered for value (e.g. "{{ perhaps|maybe|probably|definitely }}"). |
121 | 120 | * @property falsey tests for boolean considerate of RESTful responses (e.g. falsey.test("False"); falsey.test(" "); // return true). |
| 121 | + * @property protocol disqualifies URL-like string from notation test (e.g. {{ combineString:("http://domain.com/", path) }}). |
| 122 | + * @property endquotes will match leading and ending quotes (e.g. to strip-off string values provided as tokens). |
122 | 123 | */ |
123 | 124 | var PATTERN = { |
124 | 125 | proxy: /{{\s*\b(.*)\s* }}/, |
125 | 126 | notation: /[\.\[\]]+/, |
126 | 127 | address: /(\w+(\.\w+)+)|(\w+(\[\w+\])+)/, |
127 | 128 | expression: /^(.*)\:(?=[^:]*$)(.*)/, |
128 | 129 | expressionsplit: /\:/, |
129 | | - expressioncombo: /^([^(]+)/, |
| 130 | + expressioncombo: /^([^(]+)(\(.*\))/, |
130 | 131 | orsplit: /\|/, |
131 | | - falsey: /^(false|null|undefined|nan|0|\s*)$/i |
| 132 | + falsey: /^(false|null|undefined|nan|0|\s*)$/i, |
| 133 | + protocol: /https?\:\/\//, |
| 134 | + endquotes: /^["']|['"]$/g |
132 | 135 | }; |
133 | 136 |
|
134 | 137 | /** |
|
242 | 245 |
|
243 | 246 | var parseDotNotation = function (obj, notation) { |
244 | 247 | /* TODO: return [obj].concat(notation.split(".")).reduce(function(parent, child){ return !!parent && child in parent ? parent[child] : null; }); */ |
245 | | - var address = notation.split(/\.|\[|\]\[|\]/).filter(function(item){ return item.length > 0; }); // (PATTERN.notation); |
| 248 | + var address = notation.split(/\.|\[|\]\[|\]/).filter(function(item){ return item.length > 0; }); |
246 | 249 | while (address.length > 0 && !!obj) { |
247 | 250 | var index, property = address.shift(); |
248 | 251 | if (Array.isArray(obj)) { |
|
324 | 327 |
|
325 | 328 | var traverseImpl = function (datum, i, key) { |
326 | 329 | return function (node) { |
327 | | - var proxy, value, attrs, alternates, notation, transform, modify, booleans = []; |
| 330 | + var proxy, combo, value, attrs, alternates, notation, transform, modify, booleans = []; |
328 | 331 | if (isNestedTemplate(node)) { |
329 | 332 | renderNestedTemplate(node, datum); |
330 | 333 | } else if (node.nodeType === 3) { |
331 | 334 | proxy = node.nodeValue.match(PATTERN.proxy); |
332 | 335 | if (!!proxy) { |
333 | 336 | proxy = proxy[1]; |
334 | | - alternates = proxy.split(PATTERN.orsplit); |
335 | | - notation = PATTERN.notation.test(proxy); |
336 | | - transform = proxy.match(PATTERN.expression); |
337 | | - if (!!transform) { |
338 | | - proxy = transform[2]; |
| 337 | + if (PATTERN.expressioncombo.test(proxy)) { |
| 338 | + // this is a parenthetical, e/g combineString:(foo,bar) |
| 339 | + combo = proxy.match(PATTERN.expressioncombo); |
| 340 | + transform = combo[1].match(PATTERN.expression); |
| 341 | + transform = transform[1].split(PATTERN.expressionsplit).filter(function(exp){ return !!exp; }).reverse() |
| 342 | + proxy = combo[2].replace(/[()]/g,"").split(/,\s*/); |
| 343 | + alternates = []; |
| 344 | + notation = false; |
| 345 | + } else { |
339 | 346 | alternates = proxy.split(PATTERN.orsplit); |
340 | | - notation = PATTERN.notation.test(proxy); |
341 | | - transform = transform[1].split(PATTERN.expressionsplit).reverse(); |
| 347 | + notation = PATTERN.address.test(proxy); |
| 348 | + transform = proxy.match(PATTERN.expression); |
| 349 | + if (!!transform) { |
| 350 | + proxy = transform[2]; |
| 351 | + alternates = proxy.split(PATTERN.orsplit); |
| 352 | + notation = PATTERN.address.test(proxy); |
| 353 | + transform = transform[1].split(PATTERN.expressionsplit).reverse(); |
| 354 | + } |
342 | 355 | } |
343 | 356 | if (!!proxy) { |
344 | 357 | if (alternates.length > 1) { |
345 | | - proxy = alternates.filter(function (alt) { |
346 | | - return alt in datum; |
| 358 | + proxy = alternates.filter(function (alt, i, arr) { |
| 359 | + if (PATTERN.address.test(alt)) { |
| 360 | + return parseDotNotation(datum, alt); |
| 361 | + } else if (alt in datum) { |
| 362 | + return alt in datum; |
| 363 | + } else if (i == arr.length-1 && PATTERN.endquotes.test(alt)) { |
| 364 | + return alt; |
| 365 | + } else { |
| 366 | + return false; |
| 367 | + } |
347 | 368 | })[0]; |
348 | 369 | } |
349 | | - if (/\(/.test(proxy[0])) { |
| 370 | + if (!!combo) { |
350 | 371 | // this is a parenthetical, e/g combineString:(foo,bar) |
351 | 372 | value = []; |
352 | | - var params = proxy.replace(/[\(\)]/g, ""); |
353 | | - params = params.split(","); |
354 | | - params.forEach(function (param) { |
355 | | - param = param.trim(); |
356 | | - if (PATTERN.address.test(param)) { |
357 | | - value.push(parseDotNotation(datum, param)); |
358 | | - } else if (datum.hasOwnProperty(param)) { |
359 | | - value.push(datum[param]); |
| 373 | + proxy.forEach(function (substr) { |
| 374 | + if (PATTERN.address.test(substr) && !PATTERN.protocol.test(substr)) { |
| 375 | + value.push(parseDotNotation(datum, substr)); |
| 376 | + } else if (datum.hasOwnProperty(substr)) { |
| 377 | + value.push(datum[substr]); |
360 | 378 | } else { |
361 | | - value.push(param.replace(/[\'\"]/g, "")); |
| 379 | + value.push(substr.replace(PATTERN.endquotes, "")); |
362 | 380 | } |
363 | 381 | }); |
364 | 382 | } else if (notation) { |
|
369 | 387 | : proxy === TOKEN.key ? key |
370 | 388 | : proxy === TOKEN.value ? (key !== void(0) ? datum[key] : datum) |
371 | 389 | : datum.hasOwnProperty(proxy) ? datum[proxy] |
| 390 | + : PATTERN.endquotes.test(proxy) ? proxy.replace(PATTERN.endquotes, "") |
372 | 391 | : ""; |
373 | 392 | } |
374 | 393 | if (!!transform && transform.length > 0) { |
|
397 | 416 | proxy = attrs[j].value.match(PATTERN.proxy); |
398 | 417 | if (!!proxy) { |
399 | 418 | proxy = proxy[1]; |
400 | | - alternates = proxy.split(PATTERN.orsplit); |
401 | | - notation = PATTERN.notation.test(proxy); |
402 | | - transform = proxy.match(PATTERN.expression); |
403 | | - if (!!transform) { |
404 | | - proxy = transform[2]; |
| 419 | + if (PATTERN.expressioncombo.test(proxy)) { |
| 420 | + // this is a parenthetical, e/g combineString:(foo,bar) |
| 421 | + combo = proxy.match(PATTERN.expressioncombo); |
| 422 | + transform = combo[1].match(PATTERN.expression); |
| 423 | + transform = transform[1].split(PATTERN.expressionsplit).filter(function(exp){ return !!exp; }).reverse() |
| 424 | + proxy = combo[2].replace(/[()]/g,"").split(/,\s*/); |
| 425 | + alternates = []; |
| 426 | + notation = false; |
| 427 | + } else { |
405 | 428 | alternates = proxy.split(PATTERN.orsplit); |
406 | | - notation = PATTERN.notation.test(proxy); |
407 | | - transform = transform[1].split(PATTERN.expressionsplit).reverse(); |
| 429 | + notation = PATTERN.address.test(proxy); |
| 430 | + transform = proxy.match(PATTERN.expression); |
| 431 | + if (!!transform) { |
| 432 | + proxy = transform[2]; |
| 433 | + alternates = proxy.split(PATTERN.orsplit); |
| 434 | + notation = PATTERN.address.test(proxy); |
| 435 | + transform = transform[1].split(PATTERN.expressionsplit).reverse(); |
| 436 | + } |
408 | 437 | } |
409 | 438 | if (!!proxy) { |
410 | 439 | if (alternates.length > 1) { |
411 | 440 | proxy = alternates.filter(function (alt) { |
412 | | - return alt in datum; |
| 441 | + if (PATTERN.address.test(alt)) { |
| 442 | + return parseDotNotation(datum, alt); |
| 443 | + } else { |
| 444 | + return alt in datum; |
| 445 | + } |
413 | 446 | })[0]; |
414 | 447 | } |
415 | | - if (/\(/.test(proxy[0])) { |
| 448 | + if (!!combo) { |
416 | 449 | // this is a parenthetical, e/g combineString:(foo,bar) |
417 | 450 | value = []; |
418 | | - var params = proxy.replace(/[\(\)]/g, ""); |
419 | | - params = params.split(","); |
420 | | - params.forEach(function (param) { |
421 | | - param = param.trim(); |
422 | | - if (PATTERN.address.test(param)) { |
423 | | - value.push(parseDotNotation(datum, param)); |
424 | | - } else if (datum.hasOwnProperty(param)) { |
425 | | - value.push(datum[param]); |
| 451 | + proxy.forEach(function (substr) { |
| 452 | + if (PATTERN.address.test(substr) && !PATTERN.protocol.test(substr)) { |
| 453 | + value.push(parseDotNotation(datum, substr)); |
| 454 | + } else if (datum.hasOwnProperty(substr)) { |
| 455 | + value.push(datum[substr]); |
426 | 456 | } else { |
427 | | - value.push(param.replace(/[\'\"]/g, "")); |
| 457 | + value.push(substr.replace(PATTERN.endquotes, "")); |
428 | 458 | } |
429 | 459 | }); |
430 | 460 | } else if (notation) { |
|
0 commit comments