| @@ -78,7 +78,7 @@ var whiteRe = /\s*/; | |||||
| var spaceRe = /\s+/; | var spaceRe = /\s+/; | ||||
| var equalsRe = /\s*=/; | var equalsRe = /\s*=/; | ||||
| var curlyRe = /\s*\}/; | var curlyRe = /\s*\}/; | ||||
| var tagRe = /#|\^|\/|>|\{|&|=|!/; | |||||
| var tagRe = /#|@|\^|\/|>|\{|&|=|!/; | |||||
| /** | /** | ||||
| * Breaks up the given `template` string into a tree of tokens. If the `tags` | * Breaks up the given `template` string into a tree of tokens. If the `tags` | ||||
| @@ -149,7 +149,7 @@ function parseTemplate (template, tags) { | |||||
| var scanner = new Scanner(template); | var scanner = new Scanner(template); | ||||
| var start, type, value, chr, token, openSection; | |||||
| var start, type, value, chr, token, openSection, argsGlobalHelper; | |||||
| while (!scanner.eos()) { | while (!scanner.eos()) { | ||||
| start = scanner.pos; | start = scanner.pos; | ||||
| @@ -202,6 +202,10 @@ function parseTemplate (template, tags) { | |||||
| scanner.scan(curlyRe); | scanner.scan(curlyRe); | ||||
| scanner.scanUntil(closingTagRe); | scanner.scanUntil(closingTagRe); | ||||
| type = '&'; | type = '&'; | ||||
| } else if (type === '@') { | |||||
| var data = scanner.scanArgsGlobalHelper(scanner.scanUntil(closingTagRe)); | |||||
| value = data.globalHelperName; | |||||
| argsGlobalHelper = data.argsGlobalHelper; | |||||
| } else { | } else { | ||||
| value = scanner.scanUntil(closingTagRe); | value = scanner.scanUntil(closingTagRe); | ||||
| } | } | ||||
| @@ -213,7 +217,7 @@ function parseTemplate (template, tags) { | |||||
| if (type == '>') { | if (type == '>') { | ||||
| token = [ type, value, start, scanner.pos, indentation, tagIndex, lineHasNonSpace ]; | token = [ type, value, start, scanner.pos, indentation, tagIndex, lineHasNonSpace ]; | ||||
| } else { | } else { | ||||
| token = [ type, value, start, scanner.pos ]; | |||||
| token = [type, value, start, scanner.pos, argsGlobalHelper]; | |||||
| } | } | ||||
| tagIndex++; | tagIndex++; | ||||
| tokens.push(token); | tokens.push(token); | ||||
| @@ -343,6 +347,20 @@ Scanner.prototype.scan = function scan (re) { | |||||
| return string; | return string; | ||||
| }; | }; | ||||
| Scanner.prototype.scanArgsGlobalHelper = function scanArgsGlobalHelper (helperData) { | |||||
| var argsGlobalHelper; | |||||
| var data = helperData.split(/\s+/g); | |||||
| for (var i = 1; i <= data.length; i++) { | |||||
| if (data[i]) { | |||||
| argsGlobalHelper = data[i]; | |||||
| break; | |||||
| } | |||||
| } | |||||
| return {argsGlobalHelper: argsGlobalHelper, globalHelperName: data[0]}; | |||||
| }; | |||||
| /** | /** | ||||
| * Skips all text until the given regular expression can be matched. Returns | * Skips all text until the given regular expression can be matched. Returns | ||||
| * the skipped string, which is the entire tail if no match can be made. | * the skipped string, which is the entire tail if no match can be made. | ||||
| @@ -574,6 +592,7 @@ Writer.prototype.renderTokens = function renderTokens (tokens, context, partials | |||||
| else if (symbol === '&') value = this.unescapedValue(token, context); | else if (symbol === '&') value = this.unescapedValue(token, context); | ||||
| else if (symbol === 'name') value = this.escapedValue(token, context, config); | else if (symbol === 'name') value = this.escapedValue(token, context, config); | ||||
| else if (symbol === 'text') value = this.rawValue(token); | else if (symbol === 'text') value = this.rawValue(token); | ||||
| else if (symbol === '@') value = this.invokeGlobalHelper(token, context); | |||||
| if (value !== undefined) | if (value !== undefined) | ||||
| buffer += value; | buffer += value; | ||||
| @@ -671,6 +690,22 @@ Writer.prototype.rawValue = function rawValue (token) { | |||||
| return token[1]; | return token[1]; | ||||
| }; | }; | ||||
| Writer.prototype.invokeGlobalHelper = function invokeGlobalHelper (token, context) { | |||||
| var helperName = token[1]; | |||||
| var argsHelper = token[4]; | |||||
| var view = Object.assign({}, context.view); | |||||
| var value = function getValueFromView (arg) { | |||||
| if (arg.length > 1) | |||||
| getValueFromView(arg.slice(1)); | |||||
| return view = view[arg[0]]; | |||||
| }(argsHelper.split(/\.+/g).reverse()); | |||||
| return mustache.escape(mustache.helpers.get(helperName)(value)) || null; | |||||
| }; | |||||
| Writer.prototype.getConfigTags = function getConfigTags (config) { | Writer.prototype.getConfigTags = function getConfigTags (config) { | ||||
| if (isArray(config)) { | if (isArray(config)) { | ||||
| return config; | return config; | ||||
| @@ -693,6 +728,7 @@ Writer.prototype.getConfigEscape = function getConfigEscape (config) { | |||||
| }; | }; | ||||
| var mustache = { | var mustache = { | ||||
| helpers: new Map(), | |||||
| name: 'mustache.js', | name: 'mustache.js', | ||||
| version: '4.2.0', | version: '4.2.0', | ||||
| tags: [ '{{', '}}' ], | tags: [ '{{', '}}' ], | ||||
| @@ -738,6 +774,21 @@ mustache.parse = function parse (template, tags) { | |||||
| return defaultWriter.parse(template, tags); | return defaultWriter.parse(template, tags); | ||||
| }; | }; | ||||
| /** | |||||
| * Add a global custom helper which is accessed from any template | |||||
| * @param string name | |||||
| * @param function helper | |||||
| */ | |||||
| mustache.globalHelper = function globalHelper (name, helper) { | |||||
| if (!isFunction(helper)) { | |||||
| console.error('helper must be a function'); | |||||
| return false; | |||||
| } | |||||
| mustache.helpers.set(name, helper); | |||||
| }; | |||||
| /** | /** | ||||
| * Renders the `template` with the given `view`, `partials`, and `config` | * Renders the `template` with the given `view`, `partials`, and `config` | ||||
| * using the default writer. | * using the default writer. | ||||