|
|
|
@@ -45,6 +45,19 @@ |
|
|
|
return obj != null && typeof obj === 'object' && (propName in obj); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Safe way of detecting whether or not the given thing is a primitive and |
|
|
|
* whether it has the given property |
|
|
|
*/ |
|
|
|
function primitiveHasOwnProperty (primitive, propName) { |
|
|
|
return ( |
|
|
|
primitive != null |
|
|
|
&& typeof primitive !== 'object' |
|
|
|
&& primitive.hasOwnProperty |
|
|
|
&& primitive.hasOwnProperty(propName) |
|
|
|
); |
|
|
|
} |
|
|
|
|
|
|
|
// Workaround for https://issues.apache.org/jira/browse/COUCHDB-577 |
|
|
|
// See https://github.com/janl/mustache.js/issues/189 |
|
|
|
var regExpTest = RegExp.prototype.test; |
|
|
|
@@ -377,11 +390,11 @@ |
|
|
|
if (cache.hasOwnProperty(name)) { |
|
|
|
value = cache[name]; |
|
|
|
} else { |
|
|
|
var context = this, names, index, lookupHit = false; |
|
|
|
var context = this, intermediateValue, names, index, lookupHit = false; |
|
|
|
|
|
|
|
while (context) { |
|
|
|
if (name.indexOf('.') > 0) { |
|
|
|
value = context.view; |
|
|
|
intermediateValue = context.view; |
|
|
|
names = name.split('.'); |
|
|
|
index = 0; |
|
|
|
|
|
|
|
@@ -395,20 +408,51 @@ |
|
|
|
* |
|
|
|
* This is specially necessary for when the value has been set to |
|
|
|
* `undefined` and we want to avoid looking up parent contexts. |
|
|
|
* |
|
|
|
* In the case where dot notation is used, we consider the lookup |
|
|
|
* to be successful even if the last "object" in the path is |
|
|
|
* not actually an object but a primitive (e.g., a string, or an |
|
|
|
* integer), because it is sometimes useful to access a property |
|
|
|
* of an autoboxed primitive, such as the length of a string. |
|
|
|
**/ |
|
|
|
while (value != null && index < names.length) { |
|
|
|
while (intermediateValue != null && index < names.length) { |
|
|
|
if (index === names.length - 1) |
|
|
|
lookupHit = hasProperty(value, names[index]); |
|
|
|
lookupHit = ( |
|
|
|
hasProperty(intermediateValue, names[index]) |
|
|
|
|| primitiveHasOwnProperty(intermediateValue, names[index]) |
|
|
|
); |
|
|
|
|
|
|
|
value = value[names[index++]]; |
|
|
|
intermediateValue = intermediateValue[names[index++]]; |
|
|
|
} |
|
|
|
} else { |
|
|
|
value = context.view[name]; |
|
|
|
intermediateValue = context.view[name]; |
|
|
|
|
|
|
|
/** |
|
|
|
* Only checking against `hasProperty`, which always returns `false` if |
|
|
|
* `context.view` is not an object. Deliberately omitting the check |
|
|
|
* against `primitiveHasOwnProperty` if dot notation is not used. |
|
|
|
* |
|
|
|
* Consider this example: |
|
|
|
* ``` |
|
|
|
* Mustache.render("The length of a football field is {{#length}}{{length}}{{/length}}.", {length: "100 yards"}) |
|
|
|
* ``` |
|
|
|
* |
|
|
|
* If we were to check also against `primitiveHasOwnProperty`, as we do |
|
|
|
* in the dot notation case, then render call would return: |
|
|
|
* |
|
|
|
* "The length of a football field is 9." |
|
|
|
* |
|
|
|
* rather than the expected: |
|
|
|
* |
|
|
|
* "The length of a football field is 100 yards." |
|
|
|
**/ |
|
|
|
lookupHit = hasProperty(context.view, name); |
|
|
|
} |
|
|
|
|
|
|
|
if (lookupHit) |
|
|
|
if (lookupHit) { |
|
|
|
value = intermediateValue; |
|
|
|
break; |
|
|
|
} |
|
|
|
|
|
|
|
context = context.parent; |
|
|
|
} |
|
|
|
|