15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright 2006 Google Inc. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Licensed under the Apache License, Version 2.0 (the "License"); 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// you may not use this file except in compliance with the License. 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// You may obtain a copy of the License at 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// http://www.apache.org/licenses/LICENSE-2.0 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Unless required by applicable law or agreed to in writing, software 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// distributed under the License is distributed on an "AS IS" BASIS, 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// implied. See the License for the specific language governing 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// permissions and limitations under the License. 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Author: Steffen Meschkat <mesch@google.com> 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @fileoverview This class is used to evaluate expressions in a local 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * context. Used by JstProcessor. 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Names of special variables defined by the jstemplate evaluation 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * context. These can be used in js expression in jstemplate 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * attributes. 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)var VAR_index = '$index'; 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)var VAR_count = '$count'; 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)var VAR_this = '$this'; 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)var VAR_context = '$context'; 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)var VAR_top = '$top'; 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * The name of the global variable which holds the value to be returned if 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * context evaluation results in an error. 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Use JsEvalContext.setGlobal(GLOB_default, value) to set this. 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)var GLOB_default = '$default'; 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Un-inlined literals, to avoid object creation in IE6. TODO(mesch): 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * So far, these are only used here, but we could use them thoughout 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * the code and thus move them to constants.js. 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)var CHAR_colon = ':'; 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)var REGEXP_semicolon = /\s*;\s*/; 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * See constructor_() 531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @param {Object|null=} opt_data 541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @param {Object=} opt_parent 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @constructor 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)function JsEvalContext(opt_data, opt_parent) { 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.constructor_.apply(this, arguments); 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Context for processing a jstemplate. The context contains a context 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * object, whose properties can be referred to in jstemplate 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * expressions, and it holds the locally defined variables. 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {Object|null} opt_data The context object. Null if no context. 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {Object} opt_parent The parent context, from which local 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * variables are inherited. Normally the context object of the parent 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * context is the object whose property the parent object is. Null for the 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * context of the root object. 721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @private 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)JsEvalContext.prototype.constructor_ = function(opt_data, opt_parent) { 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var me = this; 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!me.vars_) { 781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci /** 791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * The context for variable definitions in which the jstemplate 801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * expressions are evaluated. Other than for the local context, 811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * which replaces the parent context, variable definitions of the 821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * parent are inherited. The special variable $this points to data_. 831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * 841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * If this instance is recycled from the cache, then the property is 851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * already initialized. 861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * 871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @type {Object} 881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci */ 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) me.vars_ = {}; 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (opt_parent) { 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If there is a parent node, inherit local variables from the 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // parent. 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) copyProperties(me.vars_, opt_parent.vars_); 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If a root node, inherit global symbols. Since every parent 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // chain has a root with no parent, global variables will be 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // present in the case above too. This means that globals can be 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // overridden by locals, as it should be. 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) copyProperties(me.vars_, JsEvalContext.globals_); 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /** 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * The current context object is assigned to the special variable 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * $this so it is possible to use it in expressions. 1061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @type {Object} 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) me.vars_[VAR_this] = opt_data; 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /** 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * The entire context structure is exposed as a variable so it can be 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * passed to javascript invocations through jseval. 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) me.vars_[VAR_context] = me; 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /** 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * The local context of the input data in which the jstemplate 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * expressions are evaluated. Notice that this is usually an Object, 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * but it can also be a scalar value (and then still the expression 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * $this can be used to refer to it). Notice this can even be value, 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * undefined or null. Hence, we have to protect jsexec() from using 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * undefined or null, yet we want $this to reflect the true value of 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * the current context. Thus we assign the original value to $this, 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * above, but for the expression context we replace null and 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * undefined by the empty string. 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 1271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @type {*} 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) me.data_ = getDefaultObject(opt_data, STRING_empty); 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!opt_parent) { 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If this is a top-level context, create a variable reference to the data 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // to allow for accessing top-level properties of the original context 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // data from child contexts. 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) me.vars_[VAR_top] = me.data_; 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * A map of globally defined symbols. Every instance of JsExprContext 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * inherits them in its vars_. 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @type Object 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)JsEvalContext.globals_ = {} 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Sets a global symbol. It will be available like a variable in every 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * JsEvalContext instance. This is intended mainly to register 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * immutable global objects, such as functions, at load time, and not 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * to add global data at runtime. I.e. the same objections as to 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * global variables in general apply also here. (Hence the name 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * "global", and not "global var".) 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {string} name 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {Object|null} value 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)JsEvalContext.setGlobal = function(name, value) { 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) JsEvalContext.globals_[name] = value; 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Set the default value to be returned if context evaluation results in an 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * error. (This can occur if a non-existent value was requested). 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)JsEvalContext.setGlobal(GLOB_default, null); 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * A cache to reuse JsEvalContext instances. (IE6 perf) 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @type Array.<JsEvalContext> 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)JsEvalContext.recycledInstances_ = []; 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * A factory to create a JsEvalContext instance, possibly reusing 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * one from recycledInstances_. (IE6 perf) 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {Object} opt_data 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {JsEvalContext} opt_parent 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @return {JsEvalContext} 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)JsEvalContext.create = function(opt_data, opt_parent) { 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (jsLength(JsEvalContext.recycledInstances_) > 0) { 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var instance = JsEvalContext.recycledInstances_.pop(); 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) JsEvalContext.call(instance, opt_data, opt_parent); 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return instance; 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return new JsEvalContext(opt_data, opt_parent); 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Recycle a used JsEvalContext instance, so we can avoid creating one 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * the next time we need one. (IE6 perf) 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {JsEvalContext} instance 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)JsEvalContext.recycle = function(instance) { 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (var i in instance.vars_) { 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // NOTE(mesch): We avoid object creation here. (IE6 perf) 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) delete instance.vars_[i]; 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) instance.data_ = null; 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) JsEvalContext.recycledInstances_.push(instance); 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Executes a function created using jsEvalToFunction() in the context 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * of vars, data, and template. 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {Function} exprFunction A javascript function created from 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * a jstemplate attribute value. 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {Element} template DOM node of the template. 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @return {Object|null} The value of the expression from which 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * exprFunction was created in the current js expression context and 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * the context of template. 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)JsEvalContext.prototype.jsexec = function(exprFunction, template) { 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) try { 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return exprFunction.call(template, this.vars_, this.data_); 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } catch (e) { 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) log('jsexec EXCEPTION: ' + e + ' at ' + template + 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ' with ' + exprFunction); 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return JsEvalContext.globals_[GLOB_default]; 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Clones the current context for a new context object. The cloned 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * context has the data object as its context object and the current 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * context as its parent context. It also sets the $index variable to 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * the given value. This value usually is the position of the data 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * object in a list for which a template is instantiated multiply. 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {Object} data The new context object. 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {number} index Position of the new context when multiply 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * instantiated. (See implementation of jstSelect().) 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {number} count The total number of contexts that were multiply 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * instantiated. (See implementation of jstSelect().) 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @return {JsEvalContext} 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)JsEvalContext.prototype.clone = function(data, index, count) { 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var ret = JsEvalContext.create(data, this); 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ret.setVariable(VAR_index, index); 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ret.setVariable(VAR_count, count); 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ret; 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Binds a local variable to the given value. If set from jstemplate 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * jsvalue expressions, variable names must start with $, but in the 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * API they only have to be valid javascript identifier. 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {string} name 2681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @param {*} value 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)JsEvalContext.prototype.setVariable = function(name, value) { 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.vars_[name] = value; 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Returns the value bound to the local variable of the given name, or 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * undefined if it wasn't set. There is no way to distinguish a 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * variable that wasn't set from a variable that was set to 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * undefined. Used mostly for testing. 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {string} name 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 2831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @return {*} value 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)JsEvalContext.prototype.getVariable = function(name) { 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return this.vars_[name]; 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Evaluates a string expression within the scope of this context 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * and returns the result. 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {string} expr A javascript expression 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {Element} opt_template An optional node to serve as "this" 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @return {Object?} value 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)JsEvalContext.prototype.evalExpression = function(expr, opt_template) { 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var exprFunction = jsEvalToFunction(expr); 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return this.jsexec(exprFunction, opt_template); 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Uninlined string literals for jsEvalToFunction() (IE6 perf). 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)var STRING_a = 'a_'; 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)var STRING_b = 'b_'; 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)var STRING_with = 'with (a_) with (b_) return '; 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Cache for jsEvalToFunction results. 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @type Object 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)JsEvalContext.evalToFunctionCache_ = {}; 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Evaluates the given expression as the body of a function that takes 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * vars and data as arguments. Since the resulting function depends 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * only on expr, we cache the result so we save some Function 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * invocations, and some object creations in IE6. 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {string} expr A javascript expression. 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @return {Function} A function that returns the value of expr in the 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * context of vars and data. 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)function jsEvalToFunction(expr) { 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!JsEvalContext.evalToFunctionCache_[expr]) { 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) try { 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // NOTE(mesch): The Function constructor is faster than eval(). 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) JsEvalContext.evalToFunctionCache_[expr] = 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new Function(STRING_a, STRING_b, STRING_with + expr); 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } catch (e) { 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) log('jsEvalToFunction (' + expr + ') EXCEPTION ' + e); 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return JsEvalContext.evalToFunctionCache_[expr]; 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Evaluates the given expression to itself. This is meant to pass 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * through string attribute values. 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {string} expr 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @return {string} 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)function jsEvalToSelf(expr) { 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return expr; 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Parses the value of the jsvalues attribute in jstemplates: splits 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * it up into a map of labels and expressions, and creates functions 3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * from the expressions that are suitable for execution by 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * JsEvalContext.jsexec(). All that is returned as a flattened array 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * of pairs of a String and a Function. 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {string} expr 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @return {Array} 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)function jsEvalToValues(expr) { 3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(mesch): It is insufficient to split the values by simply 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // finding semi-colons, as the semi-colon may be part of a string 3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // constant or escaped. 3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var ret = []; 3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var values = expr.split(REGEXP_semicolon); 3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (var i = 0, I = jsLength(values); i < I; ++i) { 3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var colon = values[i].indexOf(CHAR_colon); 3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (colon < 0) { 3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var label = stringTrim(values[i].substr(0, colon)); 3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var value = jsEvalToFunction(values[i].substr(colon + 1)); 3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ret.push(label, value); 3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ret; 3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Parses the value of the jseval attribute of jstemplates: splits it 3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * up into a list of expressions, and creates functions from the 3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * expressions that are suitable for execution by 3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * JsEvalContext.jsexec(). All that is returned as an Array of 3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Function. 3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {string} expr 3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @return {Array.<Function>} 3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)function jsEvalToExpressions(expr) { 4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var ret = []; 4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var values = expr.split(REGEXP_semicolon); 4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (var i = 0, I = jsLength(values); i < I; ++i) { 4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (values[i]) { 4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var value = jsEvalToFunction(values[i]); 4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ret.push(value); 4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ret; 4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 410