18ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen// Copyright 2006 Google Inc. 28ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen// 38ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen// Licensed under the Apache License, Version 2.0 (the "License"); 48ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen// you may not use this file except in compliance with the License. 58ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen// You may obtain a copy of the License at 68ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen// 78ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen// http://www.apache.org/licenses/LICENSE-2.0 88ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen// 98ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen// Unless required by applicable law or agreed to in writing, software 108ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen// distributed under the License is distributed on an "AS IS" BASIS, 118ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 128ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen// implied. See the License for the specific language governing 138ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen// permissions and limitations under the License. 148ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 158ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Author: Steffen Meschkat <mesch@google.com> 168ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * 178ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @fileoverview A simple formatter to project JavaScript data into 188ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * HTML templates. The template is edited in place. I.e. in order to 198ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * instantiate a template, clone it from the DOM first, and then 208ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * process the cloned template. This allows for updating of templates: 218ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * If the templates is processed again, changed values are merely 228ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * updated. 238ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * 248ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * NOTE(mesch): IE DOM doesn't have importNode(). 258ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * 268ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * NOTE(mesch): The property name "length" must not be used in input 278ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * data, see comment in jstSelect_(). 288ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 298ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 308ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 318ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 328ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Names of jstemplate attributes. These attributes are attached to 338ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * normal HTML elements and bind expression context data to the HTML 348ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * fragment that is used as template. 358ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 368ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenvar ATT_select = 'jsselect'; 378ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenvar ATT_instance = 'jsinstance'; 388ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenvar ATT_display = 'jsdisplay'; 398ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenvar ATT_values = 'jsvalues'; 408ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenvar ATT_vars = 'jsvars'; 418ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenvar ATT_eval = 'jseval'; 428ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenvar ATT_transclude = 'transclude'; 438ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenvar ATT_content = 'jscontent'; 448ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenvar ATT_skip = 'jsskip'; 458ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 468ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 478ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 488ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Name of the attribute that caches a reference to the parsed 498ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * template processing attribute values on a template node. 508ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 518ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenvar ATT_jstcache = 'jstcache'; 528ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 538ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 548ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 558ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Name of the property that caches the parsed template processing 568ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * attribute values on a template node. 578ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 588ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenvar PROP_jstcache = '__jstcache'; 598ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 608ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 618ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 628ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * ID of the element that contains dynamically loaded jstemplates. 638ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 648ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenvar STRING_jsts = 'jsts'; 658ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 668ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 678ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 688ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Un-inlined string literals, to avoid object creation in 698ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * IE6. 708ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 718ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenvar CHAR_asterisk = '*'; 728ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenvar CHAR_dollar = '$'; 738ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenvar CHAR_period = '.'; 748ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenvar CHAR_ampersand = '&'; 758ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenvar STRING_div = 'div'; 768ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenvar STRING_id = 'id'; 778ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenvar STRING_asteriskzero = '*0'; 788ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenvar STRING_zero = '0'; 798ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 808ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 818ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 828ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * HTML template processor. Data values are bound to HTML templates 838ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * using the attributes transclude, jsselect, jsdisplay, jscontent, 848ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * jsvalues. The template is modifed in place. The values of those 858ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * attributes are JavaScript expressions that are evaluated in the 868ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * context of the data object fragment. 878ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * 888ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {JsEvalContext} context Context created from the input data 898ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * object. 908ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * 918ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Element} template DOM node of the template. This will be 928ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * processed in place. After processing, it will still be a valid 938ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * template that, if processed again with the same data, will remain 948ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * unchanged. 958ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * 968ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {boolean} opt_debugging Optional flag to collect debugging 978ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * information while processing the template. Only takes effect 988ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * in MAPS_DEBUG. 998ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 1008ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction jstProcess(context, template, opt_debugging) { 1018ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var processor = new JstProcessor; 1028ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (MAPS_DEBUG && opt_debugging) { 1038ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen processor.setDebugging(opt_debugging); 1048ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 1058ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen JstProcessor.prepareTemplate_(template); 1068ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 1078ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen /** 1088ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Caches the document of the template node, so we don't have to 1098ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * access it through ownerDocument. 1108ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @type Document 1118ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 1128ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen processor.document_ = ownerDocument(template); 1138ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 1148ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen processor.run_(bindFully(processor, processor.jstProcessOuter_, 1158ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen context, template)); 1168ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (MAPS_DEBUG && opt_debugging) { 1178ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen log('jstProcess:' + '\n' + processor.getLogs().join('\n')); 1188ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 1198ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen} 1208ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 1218ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 1228ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 1238ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Internal class used by jstemplates to maintain context. This is 1248ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * necessary to process deep templates in Safari which has a 1258ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * relatively shallow maximum recursion depth of 100. 1268ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @class 1278ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @constructor 1288ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 1298ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction JstProcessor() { 1308ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (MAPS_DEBUG) { 1318ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen /** 1328ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * An array of logging messages. These are collected during processing 1338ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * and dumped to the console at the end. 1348ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @type Array.<string> 1358ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 1368ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen this.logs_ = []; 1378ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 1388ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen} 1398ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 1408ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 1418ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 1428ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Counter to generate node ids. These ids will be stored in 1438ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * ATT_jstcache and be used to lookup the preprocessed js attributes 1448ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * from the jstcache_. The id is stored in an attribute so it 1458ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * suvives cloneNode() and thus cloned template nodes can share the 1468ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * same cache entry. 1478ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @type number 1488ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 1498ae428e0fb7feea16d79853f29447469a93bedffKristian MonsenJstProcessor.jstid_ = 0; 1508ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 1518ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 1528ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 1538ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Map from jstid to processed js attributes. 1548ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @type Object 1558ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 1568ae428e0fb7feea16d79853f29447469a93bedffKristian MonsenJstProcessor.jstcache_ = {}; 1578ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 1588ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 1598ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * The neutral cache entry. Used for all nodes that don't have any 1608ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * jst attributes. We still set the jsid attribute on those nodes so 1618ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * we can avoid to look again for all the other jst attributes that 1628ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * aren't there. Remember: not only the processing of the js 1638ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * attribute values is expensive and we thus want to cache it. The 1648ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * access to the attributes on the Node in the first place is 1658ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * expensive too. 1668ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 1678ae428e0fb7feea16d79853f29447469a93bedffKristian MonsenJstProcessor.jstcache_[0] = {}; 1688ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 1698ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 1708ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 1718ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Map from concatenated attribute string to jstid. 1728ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * The key is the concatenation of all jst atributes found on a node 1738ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * formatted as "name1=value1&name2=value2&...", in the order defined by 1748ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * JST_ATTRIBUTES. The value is the id of the jstcache_ entry that can 1758ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * be used for this node. This allows the reuse of cache entries in cases 1768ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * when a cached entry already exists for a given combination of attribute 1778ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * values. (For example when two different nodes in a template share the same 1788ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * JST attributes.) 1798ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @type Object 1808ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 1818ae428e0fb7feea16d79853f29447469a93bedffKristian MonsenJstProcessor.jstcacheattributes_ = {}; 1828ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 1838ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 1848ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 1858ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Map for storing temporary attribute values in prepareNode_() so they don't 1868ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * have to be retrieved twice. (IE6 perf) 1878ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @type Object 1888ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 1898ae428e0fb7feea16d79853f29447469a93bedffKristian MonsenJstProcessor.attributeValues_ = {}; 1908ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 1918ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 1928ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 1938ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * A list for storing non-empty attributes found on a node in prepareNode_(). 1948ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * The array is global since it can be reused - this way there is no need to 1958ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * construct a new array object for each invocation. (IE6 perf) 1968ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @type Array 1978ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 1988ae428e0fb7feea16d79853f29447469a93bedffKristian MonsenJstProcessor.attributeList_ = []; 1998ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 2008ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 2018ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 2028ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Prepares the template: preprocesses all jstemplate attributes. 2038ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * 2048ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Element} template 2058ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 2068ae428e0fb7feea16d79853f29447469a93bedffKristian MonsenJstProcessor.prepareTemplate_ = function(template) { 2078ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (!template[PROP_jstcache]) { 2088ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen domTraverseElements(template, function(node) { 2098ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen JstProcessor.prepareNode_(node); 2108ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen }); 2118ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 2128ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}; 2138ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 2148ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 2158ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 2168ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * A list of attributes we use to specify jst processing instructions, 2178ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * and the functions used to parse their values. 2188ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * 2198ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @type Array.<Array> 2208ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 2218ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenvar JST_ATTRIBUTES = [ 2228ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen [ ATT_select, jsEvalToFunction ], 2238ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen [ ATT_display, jsEvalToFunction ], 2248ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen [ ATT_values, jsEvalToValues ], 2258ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen [ ATT_vars, jsEvalToValues ], 2268ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen [ ATT_eval, jsEvalToExpressions ], 2278ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen [ ATT_transclude, jsEvalToSelf ], 2288ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen [ ATT_content, jsEvalToFunction ], 2298ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen [ ATT_skip, jsEvalToFunction ] 2308ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen]; 2318ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 2328ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 2338ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 2348ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Prepares a single node: preprocesses all template attributes of the 2358ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * node, and if there are any, assigns a jsid attribute and stores the 2368ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * preprocessed attributes under the jsid in the jstcache. 2378ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * 2388ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Element} node 2398ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * 2408ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @return {Object} The jstcache entry. The processed jst attributes 2418ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * are properties of this object. If the node has no jst attributes, 2428ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * returns an object with no properties (the jscache_[0] entry). 2438ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 2448ae428e0fb7feea16d79853f29447469a93bedffKristian MonsenJstProcessor.prepareNode_ = function(node) { 2458ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // If the node already has a cache property, return it. 2468ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (node[PROP_jstcache]) { 2478ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return node[PROP_jstcache]; 2488ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 2498ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 2508ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // If it is not found, we always set the PROP_jstcache property on the node. 2518ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // Accessing the property is faster than executing getAttribute(). If we 2528ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // don't find the property on a node that was cloned in jstSelect_(), we 2538ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // will fall back to check for the attribute and set the property 2548ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // from cache. 2558ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 2568ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // If the node has an attribute indexing a cache object, set it as a property 2578ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // and return it. 2588ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var jstid = domGetAttribute(node, ATT_jstcache); 2598ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (jstid != null) { 2608ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return node[PROP_jstcache] = JstProcessor.jstcache_[jstid]; 2618ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 2628ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 2638ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var attributeValues = JstProcessor.attributeValues_; 2648ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var attributeList = JstProcessor.attributeList_; 2658ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen attributeList.length = 0; 2668ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 2678ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // Look for interesting attributes. 2688ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen for (var i = 0, I = jsLength(JST_ATTRIBUTES); i < I; ++i) { 2698ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var name = JST_ATTRIBUTES[i][0]; 2708ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var value = domGetAttribute(node, name); 2718ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen attributeValues[name] = value; 2728ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (value != null) { 2738ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen attributeList.push(name + "=" + value); 2748ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 2758ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 2768ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 2778ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // If none found, mark this node to prevent further inspection, and return 2788ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // an empty cache object. 2798ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (attributeList.length == 0) { 2808ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen domSetAttribute(node, ATT_jstcache, STRING_zero); 2818ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return node[PROP_jstcache] = JstProcessor.jstcache_[0]; 2828ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 2838ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 2848ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // If we already have a cache object corresponding to these attributes, 2858ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // annotate the node with it, and return it. 2868ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var attstring = attributeList.join(CHAR_ampersand); 2878ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (jstid = JstProcessor.jstcacheattributes_[attstring]) { 2888ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen domSetAttribute(node, ATT_jstcache, jstid); 2898ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return node[PROP_jstcache] = JstProcessor.jstcache_[jstid]; 2908ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 2918ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 2928ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // Otherwise, build a new cache object. 2938ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var jstcache = {}; 2948ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen for (var i = 0, I = jsLength(JST_ATTRIBUTES); i < I; ++i) { 2958ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var att = JST_ATTRIBUTES[i]; 2968ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var name = att[0]; 2978ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var parse = att[1]; 2988ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var value = attributeValues[name]; 2998ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (value != null) { 3008ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen jstcache[name] = parse(value); 3018ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (MAPS_DEBUG) { 3028ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen jstcache.jstAttributeValues = jstcache.jstAttributeValues || {}; 3038ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen jstcache.jstAttributeValues[name] = value; 3048ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 3058ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 3068ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 3078ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 3088ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen jstid = STRING_empty + ++JstProcessor.jstid_; 3098ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen domSetAttribute(node, ATT_jstcache, jstid); 3108ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen JstProcessor.jstcache_[jstid] = jstcache; 3118ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen JstProcessor.jstcacheattributes_[attstring] = jstid; 3128ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 3138ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return node[PROP_jstcache] = jstcache; 3148ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}; 3158ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 3168ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 3178ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 3188ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Runs the given function in our state machine. 3198ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * 3208ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * It's informative to view the set of all function calls as a tree: 3218ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * - nodes are states 3228ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * - edges are state transitions, implemented as calls to the pending 3238ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * functions in the stack. 3248ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * - pre-order function calls are downward edges (recursion into call). 3258ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * - post-order function calls are upward edges (return from call). 3268ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * - leaves are nodes which do not recurse. 3278ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * We represent the call tree as an array of array of calls, indexed as 3288ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * stack[depth][index]. Here [depth] indexes into the call stack, and 3298ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * [index] indexes into the call queue at that depth. We require a call 3308ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * queue so that a node may branch to more than one child 3318ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * (which will be called serially), typically due to a loop structure. 3328ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * 3338ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Function} f The first function to run. 3348ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 3358ae428e0fb7feea16d79853f29447469a93bedffKristian MonsenJstProcessor.prototype.run_ = function(f) { 3368ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var me = this; 3378ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 3388ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen /** 3398ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * A stack of queues of pre-order calls. 3408ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * The inner arrays (constituent queues) are structured as 3418ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * [ arg2, arg1, method, arg2, arg1, method, ...] 3428ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * ie. a flattened array of methods with 2 arguments, in reverse order 3438ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * for efficient push/pop. 3448ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * 3458ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * The outer array is a stack of such queues. 3468ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * 3478ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @type Array.<Array> 3488ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 3498ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var calls = me.calls_ = []; 3508ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 3518ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen /** 3528ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * The index into the queue for each depth. NOTE: Alternative would 3538ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * be to maintain the queues in reverse order (popping off of the 3548ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * end) but the repeated calls to .pop() consumed 90% of this 3558ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * function's execution time. 3568ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @type Array.<number> 3578ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 3588ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var queueIndices = me.queueIndices_ = []; 3598ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 3608ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen /** 3618ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * A pool of empty arrays. Minimizes object allocation for IE6's benefit. 3628ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @type Array.<Array> 3638ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 3648ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var arrayPool = me.arrayPool_ = []; 3658ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 3668ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen f(); 3678ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var queue, queueIndex; 3688ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var method, arg1, arg2; 3698ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var temp; 3708ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen while (calls.length) { 3718ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen queue = calls[calls.length - 1]; 3728ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen queueIndex = queueIndices[queueIndices.length - 1]; 3738ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (queueIndex >= queue.length) { 3748ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen me.recycleArray_(calls.pop()); 3758ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen queueIndices.pop(); 3768ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen continue; 3778ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 3788ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 3798ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // Run the first function in the queue. 3808ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen method = queue[queueIndex++]; 3818ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen arg1 = queue[queueIndex++]; 3828ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen arg2 = queue[queueIndex++]; 3838ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen queueIndices[queueIndices.length - 1] = queueIndex; 3848ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen method.call(me, arg1, arg2); 3858ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 3868ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}; 3878ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 3888ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 3898ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 3908ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Pushes one or more functions onto the stack. These will be run in sequence, 3918ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * interspersed with any recursive calls that they make. 3928ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * 3938ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * This method takes ownership of the given array! 3948ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * 3958ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Array} args Array of method calls structured as 3968ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * [ method, arg1, arg2, method, arg1, arg2, ... ] 3978ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 3988ae428e0fb7feea16d79853f29447469a93bedffKristian MonsenJstProcessor.prototype.push_ = function(args) { 3998ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen this.calls_.push(args); 4008ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen this.queueIndices_.push(0); 4018ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}; 4028ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 4038ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 4048ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 4058ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Enable/disable debugging. 4068ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {boolean} debugging New state 4078ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 4088ae428e0fb7feea16d79853f29447469a93bedffKristian MonsenJstProcessor.prototype.setDebugging = function(debugging) { 4098ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (MAPS_DEBUG) { 4108ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen this.debugging_ = debugging; 4118ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 4128ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}; 4138ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 4148ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 4158ae428e0fb7feea16d79853f29447469a93bedffKristian MonsenJstProcessor.prototype.createArray_ = function() { 4168ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (this.arrayPool_.length) { 4178ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return this.arrayPool_.pop(); 4188ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } else { 4198ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return []; 4208ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 4218ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}; 4228ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 4238ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 4248ae428e0fb7feea16d79853f29447469a93bedffKristian MonsenJstProcessor.prototype.recycleArray_ = function(array) { 4258ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen arrayClear(array); 4268ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen this.arrayPool_.push(array); 4278ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}; 4288ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 4298ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 4308ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Implements internals of jstProcess. This processes the two 4318ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * attributes transclude and jsselect, which replace or multiply 4328ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * elements, hence the name "outer". The remainder of the attributes 4338ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * is processed in jstProcessInner_(), below. That function 4348ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * jsProcessInner_() only processes attributes that affect an existing 4358ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * node, but doesn't create or destroy nodes, hence the name 4368ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * "inner". jstProcessInner_() is called through jstSelect_() if there 4378ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * is a jsselect attribute (possibly for newly created clones of the 4388ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * current template node), or directly from here if there is none. 4398ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * 4408ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {JsEvalContext} context 4418ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * 4428ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Element} template 4438ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 4448ae428e0fb7feea16d79853f29447469a93bedffKristian MonsenJstProcessor.prototype.jstProcessOuter_ = function(context, template) { 4458ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var me = this; 4468ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 4478ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var jstAttributes = me.jstAttributes_(template); 4488ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (MAPS_DEBUG && me.debugging_) { 4498ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen me.logState_('Outer', template, jstAttributes.jstAttributeValues); 4508ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 4518ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 4528ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var transclude = jstAttributes[ATT_transclude]; 4538ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (transclude) { 4548ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var tr = jstGetTemplate(transclude); 4558ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (tr) { 4568ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen domReplaceChild(tr, template); 4578ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var call = me.createArray_(); 4588ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen call.push(me.jstProcessOuter_, context, tr); 4598ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen me.push_(call); 4608ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } else { 4618ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen domRemoveNode(template); 4628ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 4638ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return; 4648ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 4658ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 4668ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var select = jstAttributes[ATT_select]; 4678ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (select) { 4688ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen me.jstSelect_(context, template, select); 4698ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } else { 4708ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen me.jstProcessInner_(context, template); 4718ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 4728ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}; 4738ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 4748ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 4758ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 4768ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Implements internals of jstProcess. This processes all attributes 4778ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * except transclude and jsselect. It is called either from 4788ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * jstSelect_() for nodes that have a jsselect attribute so that the 4798ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * jsselect attribute will not be processed again, or else directly 4808ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * from jstProcessOuter_(). See the comment on jstProcessOuter_() for 4818ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * an explanation of the name. 4828ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * 4838ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {JsEvalContext} context 4848ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * 4858ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Element} template 4868ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 4878ae428e0fb7feea16d79853f29447469a93bedffKristian MonsenJstProcessor.prototype.jstProcessInner_ = function(context, template) { 4888ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var me = this; 4898ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 4908ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var jstAttributes = me.jstAttributes_(template); 4918ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (MAPS_DEBUG && me.debugging_) { 4928ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen me.logState_('Inner', template, jstAttributes.jstAttributeValues); 4938ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 4948ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 4958ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // NOTE(mesch): See NOTE on ATT_content why this is a separate 4968ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // attribute, and not a special value in ATT_values. 4978ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var display = jstAttributes[ATT_display]; 4988ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (display) { 4998ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var shouldDisplay = context.jsexec(display, template); 5008ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (MAPS_DEBUG && me.debugging_) { 5018ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen me.logs_.push(ATT_display + ': ' + shouldDisplay + '<br/>'); 5028ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 5038ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (!shouldDisplay) { 5048ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen displayNone(template); 5058ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return; 5068ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 5078ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen displayDefault(template); 5088ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 5098ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 5108ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // NOTE(mesch): jsvars is evaluated before jsvalues, because it's 5118ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // more useful to be able to use var values in attribute value 5128ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // expressions than vice versa. 5138ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var values = jstAttributes[ATT_vars]; 5148ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (values) { 5158ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen me.jstVars_(context, template, values); 5168ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 5178ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 5188ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen values = jstAttributes[ATT_values]; 5198ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (values) { 5208ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen me.jstValues_(context, template, values); 5218ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 5228ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 5238ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // Evaluate expressions immediately. Useful for hooking callbacks 5248ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // into jstemplates. 5258ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // 5268ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // NOTE(mesch): Evaluation order is sometimes significant, e.g. when 5278ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // the expression evaluated in jseval relies on the values set in 5288ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // jsvalues, so it needs to be evaluated *after* 5298ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // jsvalues. TODO(mesch): This is quite arbitrary, it would be 5308ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // better if this would have more necessity to it. 5318ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var expressions = jstAttributes[ATT_eval]; 5328ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (expressions) { 5338ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen for (var i = 0, I = jsLength(expressions); i < I; ++i) { 5348ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen context.jsexec(expressions[i], template); 5358ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 5368ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 5378ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 5388ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var skip = jstAttributes[ATT_skip]; 5398ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (skip) { 5408ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var shouldSkip = context.jsexec(skip, template); 5418ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (MAPS_DEBUG && me.debugging_) { 5428ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen me.logs_.push(ATT_skip + ': ' + shouldSkip + '<br/>'); 5438ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 5448ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (shouldSkip) return; 5458ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 5468ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 5478ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // NOTE(mesch): content is a separate attribute, instead of just a 5488ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // special value mentioned in values, for two reasons: (1) it is 5498ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // fairly common to have only mapped content, and writing 5508ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // content="expr" is shorter than writing values="content:expr", and 5518ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // (2) the presence of content actually terminates traversal, and we 5528ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // need to check for that. Display is a separate attribute for a 5538ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // reason similar to the second, in that its presence *may* 5548ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // terminate traversal. 5558ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var content = jstAttributes[ATT_content]; 5568ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (content) { 5578ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen me.jstContent_(context, template, content); 5588ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 5598ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } else { 5608ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // Newly generated children should be ignored, so we explicitly 5618ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // store the children to be processed. 5628ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var queue = me.createArray_(); 5638ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen for (var c = template.firstChild; c; c = c.nextSibling) { 5648ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (c.nodeType == DOM_ELEMENT_NODE) { 5658ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen queue.push(me.jstProcessOuter_, context, c); 5668ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 5678ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 5688ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (queue.length) me.push_(queue); 5698ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 5708ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}; 5718ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 5728ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 5738ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 5748ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Implements the jsselect attribute: evalutes the value of the 5758ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * jsselect attribute in the current context, with the current 5768ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * variable bindings (see JsEvalContext.jseval()). If the value is an 5778ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * array, the current template node is multiplied once for every 5788ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * element in the array, with the array element being the context 5798ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * object. If the array is empty, or the value is undefined, then the 5808ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * current template node is dropped. If the value is not an array, 5818ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * then it is just made the context object. 5828ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * 5838ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {JsEvalContext} context The current evaluation context. 5848ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * 5858ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Element} template The currently processed node of the template. 5868ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * 5878ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Function} select The javascript expression to evaluate. 5888ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * 5898ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @notypecheck FIXME(hmitchell): See OCL6434950. instance and value need 5908ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * type checks. 5918ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 5928ae428e0fb7feea16d79853f29447469a93bedffKristian MonsenJstProcessor.prototype.jstSelect_ = function(context, template, select) { 5938ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var me = this; 5948ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 5958ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var value = context.jsexec(select, template); 5968ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 5978ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // Enable reprocessing: if this template is reprocessed, then only 5988ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // fill the section instance here. Otherwise do the cardinal 5998ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // processing of a new template. 6008ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var instance = domGetAttribute(template, ATT_instance); 6018ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 6028ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var instanceLast = false; 6038ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (instance) { 6048ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (instance.charAt(0) == CHAR_asterisk) { 6058ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen instance = parseInt10(instance.substr(1)); 6068ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen instanceLast = true; 6078ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } else { 6088ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen instance = parseInt10(/** @type string */(instance)); 6098ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 6108ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 6118ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 6128ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // The expression value instanceof Array is occasionally false for 6138ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // arrays, seen in Firefox. Thus we recognize an array as an object 6148ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // which is not null that has a length property. Notice that this 6158ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // also matches input data with a length property, so this property 6168ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // name should be avoided in input data. 6178ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var multiple = isArray(value); 6188ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var count = multiple ? jsLength(value) : 1; 6198ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var multipleEmpty = (multiple && count == 0); 6208ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 6218ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (multiple) { 6228ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (multipleEmpty) { 6238ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // For an empty array, keep the first template instance and mark 6248ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // it last. Remove all other template instances. 6258ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (!instance) { 6268ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen domSetAttribute(template, ATT_instance, STRING_asteriskzero); 6278ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen displayNone(template); 6288ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } else { 6298ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen domRemoveNode(template); 6308ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 6318ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 6328ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } else { 6338ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen displayDefault(template); 6348ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // For a non empty array, create as many template instances as 6358ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // are needed. If the template is first processed, as many 6368ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // template instances are needed as there are values in the 6378ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // array. If the template is reprocessed, new template instances 6388ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // are only needed if there are more array values than template 6398ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // instances. Those additional instances are created by 6408ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // replicating the last template instance. 6418ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // 6428ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // When the template is first processed, there is no jsinstance 6438ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // attribute. This is indicated by instance === null, except in 6448ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // opera it is instance === "". Notice also that the === is 6458ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // essential, because 0 == "", presumably via type coercion to 6468ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // boolean. 6478ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (instance === null || instance === STRING_empty || 6488ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen (instanceLast && instance < count - 1)) { 6498ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // A queue of calls to push. 6508ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var queue = me.createArray_(); 6518ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 6528ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var instancesStart = instance || 0; 6538ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var i, I, clone; 6548ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen for (i = instancesStart, I = count - 1; i < I; ++i) { 6558ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var node = domCloneNode(template); 6568ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen domInsertBefore(node, template); 6578ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 6588ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen jstSetInstance(/** @type Element */(node), value, i); 6598ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen clone = context.clone(value[i], i, count); 6608ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 6618ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen queue.push(me.jstProcessInner_, clone, node, 6628ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen JsEvalContext.recycle, clone, null); 6638ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 6648ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 6658ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // Push the originally present template instance last to keep 6668ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // the order aligned with the DOM order, because the newly 6678ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // created template instances are inserted *before* the 6688ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // original instance. 6698ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen jstSetInstance(template, value, i); 6708ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen clone = context.clone(value[i], i, count); 6718ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen queue.push(me.jstProcessInner_, clone, template, 6728ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen JsEvalContext.recycle, clone, null); 6738ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen me.push_(queue); 6748ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } else if (instance < count) { 6758ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var v = value[instance]; 6768ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 6778ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen jstSetInstance(template, value, instance); 6788ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var clone = context.clone(v, instance, count); 6798ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var queue = me.createArray_(); 6808ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen queue.push(me.jstProcessInner_, clone, template, 6818ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen JsEvalContext.recycle, clone, null); 6828ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen me.push_(queue); 6838ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } else { 6848ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen domRemoveNode(template); 6858ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 6868ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 6878ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } else { 6888ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (value == null) { 6898ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen displayNone(template); 6908ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } else { 6918ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen displayDefault(template); 6928ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var clone = context.clone(value, 0, 1); 6938ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var queue = me.createArray_(); 6948ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen queue.push(me.jstProcessInner_, clone, template, 6958ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen JsEvalContext.recycle, clone, null); 6968ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen me.push_(queue); 6978ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 6988ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 6998ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}; 7008ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 7018ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 7028ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 7038ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Implements the jsvars attribute: evaluates each of the values and 7048ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * assigns them to variables in the current context. Similar to 7058ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * jsvalues, except that all values are treated as vars, independent 7068ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * of their names. 7078ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * 7088ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {JsEvalContext} context Current evaluation context. 7098ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * 7108ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Element} template Currently processed template node. 7118ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * 7128ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Array} values Processed value of the jsvalues attribute: a 7138ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * flattened array of pairs. The second element in the pair is a 7148ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * function that can be passed to jsexec() for evaluation in the 7158ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * current jscontext, and the first element is the variable name that 7168ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * the value returned by jsexec is assigned to. 7178ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 7188ae428e0fb7feea16d79853f29447469a93bedffKristian MonsenJstProcessor.prototype.jstVars_ = function(context, template, values) { 7198ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen for (var i = 0, I = jsLength(values); i < I; i += 2) { 7208ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var label = values[i]; 7218ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var value = context.jsexec(values[i+1], template); 7228ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen context.setVariable(label, value); 7238ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 7248ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}; 7258ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 7268ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 7278ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 7288ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Implements the jsvalues attribute: evaluates each of the values and 7298ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * assigns them to variables in the current context (if the name 7308ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * starts with '$', javascript properties of the current template node 7318ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * (if the name starts with '.'), or DOM attributes of the current 7328ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * template node (otherwise). Since DOM attribute values are always 7338ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * strings, the value is coerced to string in the latter case, 7348ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * otherwise it's the uncoerced javascript value. 7358ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * 7368ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {JsEvalContext} context Current evaluation context. 7378ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * 7388ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Element} template Currently processed template node. 7398ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * 7408ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Array} values Processed value of the jsvalues attribute: a 7418ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * flattened array of pairs. The second element in the pair is a 7428ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * function that can be passed to jsexec() for evaluation in the 7438ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * current jscontext, and the first element is the label that 7448ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * determines where the value returned by jsexec is assigned to. 7458ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 7468ae428e0fb7feea16d79853f29447469a93bedffKristian MonsenJstProcessor.prototype.jstValues_ = function(context, template, values) { 7478ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen for (var i = 0, I = jsLength(values); i < I; i += 2) { 7488ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var label = values[i]; 7498ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var value = context.jsexec(values[i+1], template); 7508ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 7518ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (label.charAt(0) == CHAR_dollar) { 7528ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // A jsvalues entry whose name starts with $ sets a local 7538ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // variable. 7548ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen context.setVariable(label, value); 7558ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 7568ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } else if (label.charAt(0) == CHAR_period) { 7578ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // A jsvalues entry whose name starts with . sets a property of 7588ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // the current template node. The name may have further dot 7598ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // separated components, which are translated into namespace 7608ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // objects. This specifically allows to set properties on .style 7618ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // using jsvalues. NOTE(mesch): Setting the style attribute has 7628ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // no effect in IE and hence should not be done anyway. 7638ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var nameSpaceLabel = label.substr(1).split(CHAR_period); 7648ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var nameSpaceObject = template; 7658ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var nameSpaceDepth = jsLength(nameSpaceLabel); 7668ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen for (var j = 0, J = nameSpaceDepth - 1; j < J; ++j) { 7678ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var jLabel = nameSpaceLabel[j]; 7688ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (!nameSpaceObject[jLabel]) { 7698ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen nameSpaceObject[jLabel] = {}; 7708ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 7718ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen nameSpaceObject = nameSpaceObject[jLabel]; 7728ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 7738ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen nameSpaceObject[nameSpaceLabel[nameSpaceDepth - 1]] = value; 7748ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 7758ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } else if (label) { 7768ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // Any other jsvalues entry sets an attribute of the current 7778ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // template node. 7788ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (typeof value == TYPE_boolean) { 7798ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // Handle boolean values that are set as attributes specially, 7808ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // according to the XML/HTML convention. 7818ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (value) { 7828ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen domSetAttribute(template, label, label); 7838ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } else { 7848ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen domRemoveAttribute(template, label); 7858ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 7868ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } else { 7878ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen domSetAttribute(template, label, STRING_empty + value); 7888ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 7898ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 7908ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 7918ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}; 7928ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 7938ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 7948ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 7958ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Implements the jscontent attribute. Evalutes the expression in 7968ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * jscontent in the current context and with the current variables, 7978ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * and assigns its string value to the content of the current template 7988ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * node. 7998ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * 8008ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {JsEvalContext} context Current evaluation context. 8018ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * 8028ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Element} template Currently processed template node. 8038ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * 8048ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Function} content Processed value of the jscontent 8058ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * attribute. 8068ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 8078ae428e0fb7feea16d79853f29447469a93bedffKristian MonsenJstProcessor.prototype.jstContent_ = function(context, template, content) { 8088ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // NOTE(mesch): Profiling shows that this method costs significant 8098ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // time. In jstemplate_perf.html, it's about 50%. I tried to replace 8108ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // by HTML escaping and assignment to innerHTML, but that was even 8118ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // slower. 8128ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var value = STRING_empty + context.jsexec(content, template); 8138ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // Prevent flicker when refreshing a template and the value doesn't 8148ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // change. 8158ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (template.innerHTML == value) { 8168ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return; 8178ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 8188ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen while (template.firstChild) { 8198ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen domRemoveNode(template.firstChild); 8208ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 8218ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var t = domCreateTextNode(this.document_, value); 8228ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen domAppendChild(template, t); 8238ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}; 8248ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 8258ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 8268ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 8278ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Caches access to and parsing of template processing attributes. If 8288ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * domGetAttribute() is called every time a template attribute value 8298ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * is used, it takes more than 10% of the time. 8308ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * 8318ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Element} template A DOM element node of the template. 8328ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * 8338ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @return {Object} A javascript object that has all js template 8348ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * processing attribute values of the node as properties. 8358ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 8368ae428e0fb7feea16d79853f29447469a93bedffKristian MonsenJstProcessor.prototype.jstAttributes_ = function(template) { 8378ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (template[PROP_jstcache]) { 8388ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return template[PROP_jstcache]; 8398ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 8408ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 8418ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var jstid = domGetAttribute(template, ATT_jstcache); 8428ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (jstid) { 8438ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return template[PROP_jstcache] = JstProcessor.jstcache_[jstid]; 8448ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 8458ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 8468ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return JstProcessor.prepareNode_(template); 8478ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}; 8488ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 8498ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 8508ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 8518ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Helps to implement the transclude attribute, and is the initial 8528ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * call to get hold of a template from its ID. 8538ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * 8548ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * If the ID is not present in the DOM, and opt_loadHtmlFn is specified, this 8558ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * function will call that function and add the result to the DOM, before 8568ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * returning the template. 8578ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * 8588ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {string} name The ID of the HTML element used as template. 8598ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Function} opt_loadHtmlFn A function which, when called, will return 8608ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * HTML that contains an element whose ID is 'name'. 8618ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * 8628ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @return {Element|null} The DOM node of the template. (Only element nodes 8638ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * can be found by ID, hence it's a Element.) 8648ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 8658ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction jstGetTemplate(name, opt_loadHtmlFn) { 8668ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var doc = document; 8678ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var section; 8688ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (opt_loadHtmlFn) { 8698ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen section = jstLoadTemplateIfNotPresent(doc, name, opt_loadHtmlFn); 8708ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } else { 8718ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen section = domGetElementById(doc, name); 8728ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 8738ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (section) { 8748ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen JstProcessor.prepareTemplate_(section); 8758ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var ret = domCloneElement(section); 8768ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen domRemoveAttribute(ret, STRING_id); 8778ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return ret; 8788ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } else { 8798ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return null; 8808ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 8818ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen} 8828ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 8838ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 8848ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * This function is the same as 'jstGetTemplate' but, if the template 8858ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * does not exist, throw an exception. 8868ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * 8878ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {string} name The ID of the HTML element used as template. 8888ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Function} opt_loadHtmlFn A function which, when called, will return 8898ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * HTML that contains an element whose ID is 'name'. 8908ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * 8918ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @return {Element} The DOM node of the template. (Only element nodes 8928ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * can be found by ID, hence it's a Element.) 8938ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 8948ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction jstGetTemplateOrDie(name, opt_loadHtmlFn) { 8958ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var x = jstGetTemplate(name, opt_loadHtmlFn); 8968ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen check(x !== null); 8978ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return /** @type Element */(x); 8988ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen} 8998ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 9008ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 9018ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 9028ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * If an element with id 'name' is not present in the document, call loadHtmlFn 9038ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * and insert the result into the DOM. 9048ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * 9058ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Document} doc 9068ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {string} name 9078ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Function} loadHtmlFn A function that returns HTML to be inserted 9088ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * into the DOM. 9098ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {string} opt_target The id of a DOM object under which to attach the 9108ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * HTML once it's inserted. An object with this id is created if it does not 9118ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * exist. 9128ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @return {Element} The node whose id is 'name' 9138ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 9148ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction jstLoadTemplateIfNotPresent(doc, name, loadHtmlFn, opt_target) { 9158ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var section = domGetElementById(doc, name); 9168ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (section) { 9178ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return section; 9188ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 9198ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // Load any necessary HTML and try again. 9208ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen jstLoadTemplate_(doc, loadHtmlFn(), opt_target || STRING_jsts); 9218ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var section = domGetElementById(doc, name); 9228ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (!section) { 9238ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen log("Error: jstGetTemplate was provided with opt_loadHtmlFn, " + 9248ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen "but that function did not provide the id '" + name + "'."); 9258ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 9268ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return /** @type Element */(section); 9278ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen} 9288ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 9298ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 9308ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 9318ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Loads the given HTML text into the given document, so that 9328ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * jstGetTemplate can find it. 9338ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * 9348ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * We append it to the element identified by targetId, which is hidden. 9358ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * If it doesn't exist, it is created. 9368ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * 9378ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Document} doc The document to create the template in. 9388ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * 9398ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {string} html HTML text to be inserted into the document. 9408ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * 9418ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {string} targetId The id of a DOM object under which to attach the 9428ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * HTML once it's inserted. An object with this id is created if it does not 9438ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * exist. 9448ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 9458ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction jstLoadTemplate_(doc, html, targetId) { 9468ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var existing_target = domGetElementById(doc, targetId); 9478ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var target; 9488ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (!existing_target) { 9498ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen target = domCreateElement(doc, STRING_div); 9508ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen target.id = targetId; 9518ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen displayNone(target); 9528ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen positionAbsolute(target); 9538ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen domAppendChild(doc.body, target); 9548ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } else { 9558ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen target = existing_target; 9568ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 9578ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var div = domCreateElement(doc, STRING_div); 9588ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen target.appendChild(div); 9598ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen div.innerHTML = html; 9608ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen} 9618ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 9628ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 9638ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 9648ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Sets the jsinstance attribute on a node according to its context. 9658ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * 9668ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Element} template The template DOM node to set the instance 9678ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * attribute on. 9688ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * 9698ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Array} values The current input context, the array of 9708ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * values of which the template node will render one instance. 9718ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * 9728ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {number} index The index of this template node in values. 9738ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 9748ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction jstSetInstance(template, values, index) { 9758ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (index == jsLength(values) - 1) { 9768ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen domSetAttribute(template, ATT_instance, CHAR_asterisk + index); 9778ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } else { 9788ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen domSetAttribute(template, ATT_instance, STRING_empty + index); 9798ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 9808ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen} 9818ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 9828ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 9838ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 9848ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Log the current state. 9858ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {string} caller An identifier for the caller of .log_. 9868ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Element} template The template node being processed. 9878ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Object} jstAttributeValues The jst attributes of the template node. 9888ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 9898ae428e0fb7feea16d79853f29447469a93bedffKristian MonsenJstProcessor.prototype.logState_ = function( 9908ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen caller, template, jstAttributeValues) { 9918ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (MAPS_DEBUG) { 9928ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var msg = '<table>'; 9938ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen msg += '<caption>' + caller + '</caption>'; 9948ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen msg += '<tbody>'; 9958ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (template.id) { 9968ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen msg += '<tr><td>' + 'id:' + '</td><td>' + template.id + '</td></tr>'; 9978ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 9988ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (template.name) { 9998ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen msg += '<tr><td>' + 'name:' + '</td><td>' + template.name + '</td></tr>'; 10008ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 10018ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (jstAttributeValues) { 10028ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen msg += '<tr><td>' + 'attr:' + 10038ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen '</td><td>' + jsToSource(jstAttributeValues) + '</td></tr>'; 10048ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 10058ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen msg += '</tbody></table><br/>'; 10068ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen this.logs_.push(msg); 10078ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 10088ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}; 10098ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 10108ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 10118ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 10128ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Retrieve the processing logs. 10138ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @return {Array.<string>} The processing logs. 10148ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 10158ae428e0fb7feea16d79853f29447469a93bedffKristian MonsenJstProcessor.prototype.getLogs = function() { 10168ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return this.logs_; 10178ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}; 1018