Fix view prototype value lookup issuestags/v2.1.1
| @@ -29,6 +29,14 @@ | |||||
| return string.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, '\\$&'); | return string.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, '\\$&'); | ||||
| } | } | ||||
| /** | |||||
| * Null safe way of checking whether or not an object, | |||||
| * including its prototype, has a given property | |||||
| */ | |||||
| function hasProperty (obj, propName) { | |||||
| return obj != null && typeof obj === 'object' && (propName in obj); | |||||
| } | |||||
| // Workaround for https://issues.apache.org/jira/browse/COUCHDB-577 | // Workaround for https://issues.apache.org/jira/browse/COUCHDB-577 | ||||
| // See https://github.com/janl/mustache.js/issues/189 | // See https://github.com/janl/mustache.js/issues/189 | ||||
| var regExpTest = RegExp.prototype.test; | var regExpTest = RegExp.prototype.test; | ||||
| @@ -379,14 +387,14 @@ | |||||
| * `undefined` and we want to avoid looking up parent contexts. | * `undefined` and we want to avoid looking up parent contexts. | ||||
| **/ | **/ | ||||
| while (value != null && index < names.length) { | while (value != null && index < names.length) { | ||||
| if (index === names.length - 1 && value != null) | |||||
| lookupHit = (typeof value === 'object') && | |||||
| value.hasOwnProperty(names[index]); | |||||
| if (index === names.length - 1) | |||||
| lookupHit = hasProperty(value, names[index]); | |||||
| value = value[names[index++]]; | value = value[names[index++]]; | ||||
| } | } | ||||
| } else if (context.view != null && typeof context.view === 'object') { | |||||
| } else { | |||||
| value = context.view[name]; | value = context.view[name]; | ||||
| lookupHit = context.view.hasOwnProperty(name); | |||||
| lookupHit = hasProperty(context.view, name); | |||||
| } | } | ||||
| if (lookupHit) | if (lookupHit) | ||||
| @@ -14,5 +14,18 @@ | |||||
| "name": "Chris", | "name": "Chris", | ||||
| "twitter": undefined | "twitter": undefined | ||||
| } | } | ||||
| ] | |||||
| ], | |||||
| "favorites": { | |||||
| "color": "blue", | |||||
| "president": "Bush", | |||||
| "show": "Futurama" | |||||
| }, | |||||
| "mascot": { | |||||
| "name": "Squid", | |||||
| "favorites": { | |||||
| "color": "orange", | |||||
| "president": undefined, | |||||
| "show": null | |||||
| } | |||||
| } | |||||
| }) | }) | ||||
| @@ -1,3 +1,9 @@ | |||||
| {{#fobject}} | {{#fobject}} | ||||
| {{name}}'s twitter: {{#twitter}}{{.}}{{/twitter}}{{^twitter}}unknown{{/twitter}}. | {{name}}'s twitter: {{#twitter}}{{.}}{{/twitter}}{{^twitter}}unknown{{/twitter}}. | ||||
| {{/fobject}} | {{/fobject}} | ||||
| {{#mascot}} | |||||
| {{name}}'s favorite color: {{#favorites.color}}{{.}}{{/favorites.color}}{{^favorites.color}}no one{{/favorites.color}}. | |||||
| {{name}}'s favorite president: {{#favorites.president}}{{.}}{{/favorites.president}}{{^favorites.president}}no one{{/favorites.president}}. | |||||
| {{name}}'s favorite show: {{#favorites.show}}{{.}}{{/favorites.show}}{{^favorites.show}}none{{/favorites.show}}. | |||||
| {{/mascot}} | |||||
| @@ -1,3 +1,7 @@ | |||||
| Flor's twitter: @florrts. | Flor's twitter: @florrts. | ||||
| Miquel's twitter: unknown. | Miquel's twitter: unknown. | ||||
| Chris's twitter: unknown. | Chris's twitter: unknown. | ||||
| Squid's favorite color: orange. | |||||
| Squid's favorite president: no one. | |||||
| Squid's favorite show: none. | |||||
| @@ -0,0 +1,30 @@ | |||||
| var Aaa = (function () { | |||||
| function Aaa(x, y) { | |||||
| this.x = x; | |||||
| this._y = y; | |||||
| } | |||||
| Object.defineProperty(Aaa.prototype, "y", { | |||||
| get: function () { | |||||
| return this._y; | |||||
| }, | |||||
| set: function (value) { | |||||
| this._y = value; | |||||
| }, | |||||
| enumerable: true, | |||||
| configurable: true | |||||
| }); | |||||
| return Aaa; | |||||
| })(); | |||||
| var Bbb = (function () { | |||||
| function Bbb() { | |||||
| } | |||||
| return Bbb; | |||||
| })(); | |||||
| var b = new Bbb(); | |||||
| b.item = new Aaa("0", "00"); | |||||
| b.items = []; | |||||
| b.items.push({ a: new Aaa("1", "2") }); | |||||
| b.items.push({ a: new Aaa("3", "4") }); | |||||
| (b) | |||||
| @@ -0,0 +1 @@ | |||||
| [{{ item.x }};{{ item.y }}]||{{#items}}[{{ a.x }};{{ a.y }} {{#a}}{{y}}{{/a}}]{{/items}} | |||||
| @@ -0,0 +1 @@ | |||||
| [0;00]||[1;2 2][3;4 4] | |||||
| @@ -26,12 +26,12 @@ function getPartial(testName) { | |||||
| } | } | ||||
| // You can put the name of a specific test to run in the TEST environment | // You can put the name of a specific test to run in the TEST environment | ||||
| // variable (e.g. TEST=backslashes vows test/render-test.js) | |||||
| // variable (e.g. TEST=backslashes mocha test/render-test.js) | |||||
| var testToRun = process.env.TEST; | var testToRun = process.env.TEST; | ||||
| var testNames; | var testNames; | ||||
| if (testToRun) { | if (testToRun) { | ||||
| testNames = [testToRun]; | |||||
| testNames = testToRun.split(','); | |||||
| } else { | } else { | ||||
| testNames = fs.readdirSync(_files).filter(function (file) { | testNames = fs.readdirSync(_files).filter(function (file) { | ||||
| return (/\.js$/).test(file); | return (/\.js$/).test(file); | ||||