Skip to content

Commit c4ab56e

Browse files
ptrdopsylwester
authored andcommitted
Defaults
1 parent fd870dc commit c4ab56e

3 files changed

Lines changed: 92 additions & 45 deletions

File tree

README.md

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,11 @@ The resulting markup would be:
202202
</table>
203203
```
204204

205+
**OR Alternatives:** If it is not certain that a token will resolve or exist, alternatives can be supplied, separated by a pipe `|` character. These will by tried from left-to-right until a key resolves. If none resolve, then an empty string results.
206+
```html
207+
<samp>{{ tryThis|thenThis|default }}</samp>
208+
```
209+
205210
***
206211
### The Modifiers
207212
By default, the value inserted for a token will be applied as the nodeValue of the tag or the literal value of the attribute. However, there are instances when the insertion should be treated differently. Modifiers are reserved keywords that can precede a token to prescribe special treatment.
@@ -210,7 +215,7 @@ By default, the value inserted for a token will be applied as the nodeValue of t
210215
|----------|-----------|---------|
211216
| html | `{{ html:token }}` | Insert value with innerHTML rather than nodeValue (e.g. escaped content, unicodes, html entities). |
212217
| concat | `{{ concat:token }}` | Concatenates value in-context to any adjacent content within the targeted attribute or node. |
213-
| forin | `{{ forin:token }}` | Iterates over every property found in the assumed object (see [object](/example/simple-javascript/object.html) example). |
218+
| forin | `{{ forin:token }}` | Iterates over every property found in the assumed object. See the [object](/example/simple-javascript/object.html) example. |
214219
| boolean | `{{ boolean:token }}` | Inserts boolean per resolved truthiness of value (e.g. *checked="false"*, *disabled="true"*, *class="true"*). |
215220

216221
***
@@ -225,7 +230,7 @@ Transformers allow for modification of a value prior to insertion into the targe
225230
| toMebibytes | `{{ toMebibytes:token }}` | Converts bytes to mebibytes. (e.g. 1048576 becomes "1.00"). |
226231
| exists | `{{ exists:token }}` | Inserts `true` or `false` if value exists (e.g. as a CSS class name to denote visibility). |
227232
| absent | `{{ absent:token }}` | Inserts `true` or `false` if value does not exist (the obverse of `exists`). |
228-
| combineString | `{{ combineString:('foo',token1,'bar',token2,…) }}` | Combines arbitrary strings and/or token values (e.g. to construct an URL). |
233+
| combineString | `{{ combineString:('foo',token1,'bar',token2,…) }}` | Combines arbitrary strings and/or token values (e.g. to construct an URL). See the [transformer](/example/simple-javascript/transformer.html) example. |
229234

230235
***
231236
### Public API

example/simple-javascript/transformer.html

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,18 @@
3434
width: 100%;
3535
text-align: right;
3636
font-size: smaller;
37+
color: lightsteelblue;
38+
}
39+
a {
40+
color: #0776A2;
41+
border-bottom: 1px solid lightsteelblue;
42+
text-decoration: none;
43+
}
44+
a:visited {
45+
color: lightsteelblue;
46+
}
47+
blockquote:hover a {
48+
color: #0776A2;
3749
}
3850
</style>
3951
</head>
@@ -42,7 +54,7 @@
4254
<article>
4355
<section>
4456
<blockquote itemscope itemid="{{ id }}" itemtype="https://schema.org/UserTweets" hidden>
45-
<h5 itemprop="screen_name">{{ concat:combineString:("@", user.screen_name, " tweeted from ", user.location) }}:</h5>
57+
<h5 itemprop="tweet"><a href="{{ combineString:('http://twitter.com/', user.screen_name, '/status/', id) }}">{{ concat:combineString:("@", user.screen_name, " tweeted from ", user.location) }}:</a></h5>
4658
<p itemprop="text">{{ text }}</p>
4759
<time itemprop="created_at" datetime="{{ parseDateToTimeValue:created_at }}">{{ formatDate:created_at }}</time>
4860
</blockquote>

lib/microdata-template.js

Lines changed: 72 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,6 @@
108108

109109
/**
110110
* 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).
112111
*
113112
* @private static
114113
* @property proxy will match the token-identifying wrapper (e.g. the "{{ info }}" of <span>{{ info }}</span>).
@@ -119,16 +118,20 @@
119118
* @property expressioncombo separates expression(s) from a combineString list (e.g. "combineString:("foo",bar)").
120119
* @property orsplit separates tokens progressively considered for value (e.g. "{{ perhaps|maybe|probably|definitely }}").
121120
* @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).
122123
*/
123124
var PATTERN = {
124125
proxy: /{{\s*\b(.*)\s* }}/,
125126
notation: /[\.\[\]]+/,
126127
address: /(\w+(\.\w+)+)|(\w+(\[\w+\])+)/,
127128
expression: /^(.*)\:(?=[^:]*$)(.*)/,
128129
expressionsplit: /\:/,
129-
expressioncombo: /^([^(]+)/,
130+
expressioncombo: /^([^(]+)(\(.*\))/,
130131
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
132135
};
133136

134137
/**
@@ -242,7 +245,7 @@
242245

243246
var parseDotNotation = function (obj, notation) {
244247
/* 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; });
246249
while (address.length > 0 && !!obj) {
247250
var index, property = address.shift();
248251
if (Array.isArray(obj)) {
@@ -324,41 +327,56 @@
324327

325328
var traverseImpl = function (datum, i, key) {
326329
return function (node) {
327-
var proxy, value, attrs, alternates, notation, transform, modify, booleans = [];
330+
var proxy, combo, value, attrs, alternates, notation, transform, modify, booleans = [];
328331
if (isNestedTemplate(node)) {
329332
renderNestedTemplate(node, datum);
330333
} else if (node.nodeType === 3) {
331334
proxy = node.nodeValue.match(PATTERN.proxy);
332335
if (!!proxy) {
333336
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 {
339346
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+
}
342355
}
343356
if (!!proxy) {
344357
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+
}
347368
})[0];
348369
}
349-
if (/\(/.test(proxy[0])) {
370+
if (!!combo) {
350371
// this is a parenthetical, e/g combineString:(foo,bar)
351372
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]);
360378
} else {
361-
value.push(param.replace(/[\'\"]/g, ""));
379+
value.push(substr.replace(PATTERN.endquotes, ""));
362380
}
363381
});
364382
} else if (notation) {
@@ -369,6 +387,7 @@
369387
: proxy === TOKEN.key ? key
370388
: proxy === TOKEN.value ? (key !== void(0) ? datum[key] : datum)
371389
: datum.hasOwnProperty(proxy) ? datum[proxy]
390+
: PATTERN.endquotes.test(proxy) ? proxy.replace(PATTERN.endquotes, "")
372391
: "";
373392
}
374393
if (!!transform && transform.length > 0) {
@@ -397,34 +416,45 @@
397416
proxy = attrs[j].value.match(PATTERN.proxy);
398417
if (!!proxy) {
399418
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 {
405428
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+
}
408437
}
409438
if (!!proxy) {
410439
if (alternates.length > 1) {
411440
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+
}
413446
})[0];
414447
}
415-
if (/\(/.test(proxy[0])) {
448+
if (!!combo) {
416449
// this is a parenthetical, e/g combineString:(foo,bar)
417450
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]);
426456
} else {
427-
value.push(param.replace(/[\'\"]/g, ""));
457+
value.push(substr.replace(PATTERN.endquotes, ""));
428458
}
429459
});
430460
} else if (notation) {

0 commit comments

Comments
 (0)