diff --git a/domUtil/template.js b/domUtil/template.js index c2408ef6..16038fe4 100644 --- a/domUtil/template.js +++ b/domUtil/template.js @@ -11,8 +11,10 @@ var isArray = require('../type/isArray'); var isString = require('../type/isString'); var extend = require('../object/extend'); -var EXPRESSION_REGEXP = /{{\s?(\/?[a-zA-Z0-9_.@[\] ]+)\s?}}/g; -var BRACKET_REGEXP = /^([a-zA-Z0-9_@]+)\[([a-zA-Z0-9_@]+)\]$/; +var EXPRESSION_REGEXP = /{{\s?(\/?[a-zA-Z0-9_.@[\]"'\- ]+)\s?}}/g; +var BRACKET_REGEXP = /^([a-zA-Z0-9_@]+)\[([a-zA-Z0-9_@"']+)\]$/; +var DOT_REGEXP = /^([a-zA-Z_]+)\.([a-zA-Z_]+)$/; +var STRING_REGEXP = /^["'](\w+)["']$/; var NUMBER_REGEXP = /^-?\d+\.?\d*$/; var EXPRESSION_INTERVAL = 2; @@ -30,17 +32,23 @@ var BLOCK_HELPERS = { * @returns {*} * @private */ +// eslint-disable-next-line complexity function getValueFromContext(exp, context) { - var bracketExps; + var splitedExps; var value = context[exp]; if (exp === 'true') { value = true; } else if (exp === 'false') { value = false; + } else if (STRING_REGEXP.test(exp)) { + value = STRING_REGEXP.exec(exp)[1]; } else if (BRACKET_REGEXP.test(exp)) { - bracketExps = exp.split(BRACKET_REGEXP); - value = getValueFromContext(bracketExps[1], context)[getValueFromContext(bracketExps[2], context)]; + splitedExps = exp.split(BRACKET_REGEXP); + value = getValueFromContext(splitedExps[1], context)[getValueFromContext(splitedExps[2], context)]; + } else if (DOT_REGEXP.test(exp)) { + splitedExps = exp.split(DOT_REGEXP); + value = getValueFromContext(splitedExps[1], context)[splitedExps[2]]; } else if (NUMBER_REGEXP.test(exp)) { value = parseFloat(exp); } @@ -296,6 +304,10 @@ function compile(sources, context) { *
* If expression exists in the context, it will be replaced. * ex) '{{title}}' with context {title: 'Hello!'} is converted to 'Hello!'. + * An array or object can be accessed using bracket and dot notation. + * ex) '{{odds[2]}}' with context {odds: [1, 3, 5]} is converted to '5'. + * ex) '{{evens[first]}}' with context {evens: [2, 4], first: 0} is converted to '2'. + * ex) '{{project["name"]}}' and '{{project.name}}' with context {project: {name: 'CodeSnippet'}} is converted to 'CodeSnippet'. *
* If replaced expression is a function, next expressions will be arguments of the function. * ex) '{{add 1 2}}' with context {add: function(a, b) {return a + b;}} is converted to '3'. diff --git a/test/template.spec.js b/test/template.spec.js index a22f24f2..f144bae1 100644 --- a/test/template.spec.js +++ b/test/template.spec.js @@ -21,21 +21,39 @@ describe('{{expression}}', function() { it('should bind with number if value is a number.', function() { expect(template('

{{ 3 }}

', {})).toBe('

3

'); expect(template('

{{123.4567}}

', {})).toBe('

123.4567

'); + expect(template('

{{-1}}

', {})).toBe('

-1

'); + expect(template('

{{-0}}

', {})).toBe('

0

'); + expect(template('

{{-123.4567}}

', {})).toBe('

-123.4567

'); }); it('should access the value with brackets if value is an object or array.', function() { expect(template('

{{ arr[2] }}

', {arr: [0, 1, 2]})).toBe('

2

'); - expect(template('

{{obj[key]}}

', { + expect(template('

{{obj["key"]}}

', {obj: {key: 'value'}})).toBe('

value

'); + expect(template('

{{obj[name]}}

', { obj: {key: 'value'}, - key: 'key' + name: 'key' })).toBe('

value

'); expect(template('{{each nums}}{{nums[@index]}}{{/each}}', {nums: [1, 2, 3]})).toBe('123'); }); + it('should access the value with dots if value is an object.', function() { + expect(template('

{{obj.key}}

', {obj: {key: 'value'}})).toBe('

value

'); + }); + it('should bind with boolean if value is "true" or "false".', function() { expect(template('

{{ false }}

', {})).toBe('

false

'); expect(template('

{{true}}

', {})).toBe('

true

'); }); + + it('should bind with string if value is string with quotes.', function() { + var context = { + sayHello: function(name) { + return 'Hello, ' + name; + } + }; + expect(template('

{{ sayHello "CodeSnippet" }}

', context)).toBe('

Hello, CodeSnippet

'); + expect(template('

{{sayHello \'world\'}}

', context)).toBe('

Hello, world

'); + }); }); describe('{{helper arg1 arg2}}', function() {