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 * @fileoverview Miscellaneous constants and functions referenced in 168ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * the main source files. 178ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * 188ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @author Steffen Meschkat (mesch@google.com) 198ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 208ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 218ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenvar MAPS_DEBUG = false; 228ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 238ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction log(msg) {} 248ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 258ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen// String literals defined globally and not to be inlined. (IE6 perf) 268ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** @const */ var STRING_empty = ''; 278ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 288ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** @const */ var CSS_display = 'display'; 298ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** @const */ var CSS_position = 'position'; 308ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 318ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen// Constants for possible values of the typeof operator. 328ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenvar TYPE_boolean = 'boolean'; 338ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenvar TYPE_number = 'number'; 348ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenvar TYPE_object = 'object'; 358ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenvar TYPE_string = 'string'; 368ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenvar TYPE_function = 'function'; 378ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenvar TYPE_undefined = 'undefined'; 388ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 398ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 408ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 418ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Wrapper for the eval() builtin function to evaluate expressions and 428ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * obtain their value. It wraps the expression in parentheses such 438ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * that object literals are really evaluated to objects. Without the 448ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * wrapping, they are evaluated as block, and create syntax 458ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * errors. Also protects against other syntax errors in the eval()ed 468ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * code and returns null if the eval throws an exception. 478ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * 488ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {string} expr 498ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @return {Object|null} 508ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 518ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction jsEval(expr) { 528ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen try { 538ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // NOTE(mesch): An alternative idiom would be: 548ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // 558ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // eval('(' + expr + ')'); 568ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // 578ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // Note that using the square brackets as below, "" evals to undefined. 588ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // The alternative of using parentheses does not work when evaluating 598ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // function literals in IE. 608ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // e.g. eval("(function() {})") returns undefined, and not a function 618ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // object, in IE. 628ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return eval('[' + expr + '][0]'); 638ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } catch (e) { 648ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen log('EVAL FAILED ' + expr + ': ' + e); 658ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return null; 668ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 678ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen} 688ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 698ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction jsLength(obj) { 708ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return obj.length; 718ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen} 728ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 738ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction assert(obj) {} 748ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 758ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 768ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Copies all properties from second object to the first. Modifies to. 778ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * 788ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Object} to The target object. 798ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Object} from The source object. 808ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 818ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction copyProperties(to, from) { 828ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen for (var p in from) { 838ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen to[p] = from[p]; 848ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 858ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen} 868ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 878ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 888ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 898ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Object|null|undefined} value The possible value to use. 908ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Object} defaultValue The default if the value is not set. 918ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @return {Object} The value, if it is 928ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * defined and not null; otherwise the default 938ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 948ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction getDefaultObject(value, defaultValue) { 958ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (typeof value != TYPE_undefined && value != null) { 968ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return /** @type Object */(value); 978ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } else { 988ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return defaultValue; 998ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 1008ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen} 1018ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 1028ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 1038ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Detect if an object looks like an Array. 1048ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Note that instanceof Array is not robust; for example an Array 1058ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * created in another iframe fails instanceof Array. 1068ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Object|null} value Object to interrogate 1078ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @return {boolean} Is the object an array? 1088ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 1098ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction isArray(value) { 1108ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return value != null && 1118ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen typeof value == TYPE_object && 1128ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen typeof value.length == TYPE_number; 1138ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen} 1148ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 1158ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 1168ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 1178ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Finds a slice of an array. 1188ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * 1198ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Array} array Array to be sliced. 1208ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {number} start The start of the slice. 1218ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {number} opt_end The end of the slice (optional). 1228ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @return {Array} array The slice of the array from start to end. 1238ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 1248ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction arraySlice(array, start, opt_end) { 1258ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // Use 1268ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // return Function.prototype.call.apply(Array.prototype.slice, arguments); 1278ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // instead of the simpler 1288ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // return Array.prototype.slice.call(array, start, opt_end); 1298ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // here because of a bug in the FF and IE implementations of 1308ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // Array.prototype.slice which causes this function to return an empty list 1318ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // if opt_end is not provided. 1328ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return Function.prototype.call.apply(Array.prototype.slice, arguments); 1338ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen} 1348ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 1358ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 1368ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 1378ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Jscompiler wrapper for parseInt() with base 10. 1388ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * 1398ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {string} s string repersentation of a number. 1408ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * 1418ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @return {number} The integer contained in s, converted on base 10. 1428ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 1438ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction parseInt10(s) { 1448ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return parseInt(s, 10); 1458ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen} 1468ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 1478ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 1488ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 1498ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Clears the array by setting the length property to 0. This usually 1508ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * works, and if it should turn out not to work everywhere, here would 1518ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * be the place to implement the browser specific workaround. 1528ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * 1538ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Array} array Array to be cleared. 1548ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 1558ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction arrayClear(array) { 1568ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen array.length = 0; 1578ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen} 1588ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 1598ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 1608ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 1618ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Prebinds "this" within the given method to an object, but ignores all 1628ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * arguments passed to the resulting function. 1638ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * I.e. var_args are all the arguments that method is invoked with when 1648ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * invoking the bound function. 1658ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * 1668ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Object|null} object The object that the method call targets. 1678ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Function} method The target method. 1688ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @return {Function} Method with the target object bound to it and curried by 1698ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * the provided arguments. 1708ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 1718ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction bindFully(object, method, var_args) { 1728ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var args = arraySlice(arguments, 2); 1738ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return function() { 1748ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return method.apply(object, args); 1758ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 1768ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen} 1778ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 1788ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen// Based on <http://www.w3.org/TR/2000/ REC-DOM-Level-2-Core-20001113/ 1798ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen// core.html#ID-1950641247>. 1808ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenvar DOM_ELEMENT_NODE = 1; 1818ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenvar DOM_ATTRIBUTE_NODE = 2; 1828ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenvar DOM_TEXT_NODE = 3; 1838ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenvar DOM_CDATA_SECTION_NODE = 4; 1848ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenvar DOM_ENTITY_REFERENCE_NODE = 5; 1858ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenvar DOM_ENTITY_NODE = 6; 1868ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenvar DOM_PROCESSING_INSTRUCTION_NODE = 7; 1878ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenvar DOM_COMMENT_NODE = 8; 1888ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenvar DOM_DOCUMENT_NODE = 9; 1898ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenvar DOM_DOCUMENT_TYPE_NODE = 10; 1908ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenvar DOM_DOCUMENT_FRAGMENT_NODE = 11; 1918ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenvar DOM_NOTATION_NODE = 12; 1928ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 1938ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 1948ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 1958ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction domGetElementById(document, id) { 1968ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return document.getElementById(id); 1978ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen} 1988ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 1998ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 2008ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Creates a new node in the given document 2018ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * 2028ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Document} doc Target document. 2038ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {string} name Name of new element (i.e. the tag name).. 2048ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @return {Element} Newly constructed element. 2058ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 2068ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction domCreateElement(doc, name) { 2078ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return doc.createElement(name); 2088ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen} 2098ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 2108ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 2118ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Traverses the element nodes in the DOM section underneath the given 2128ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * node and invokes the given callback as a method on every element 2138ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * node encountered. 2148ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * 2158ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Element} node Parent element of the subtree to traverse. 2168ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Function} callback Called on each node in the traversal. 2178ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 2188ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction domTraverseElements(node, callback) { 2198ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var traverser = new DomTraverser(callback); 2208ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen traverser.run(node); 2218ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen} 2228ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 2238ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 2248ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * A class to hold state for a dom traversal. 2258ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Function} callback Called on each node in the traversal. 2268ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @constructor 2278ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @class 2288ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 2298ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction DomTraverser(callback) { 2308ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen this.callback_ = callback; 2318ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen} 2328ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 2338ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 2348ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Processes the dom tree in breadth-first order. 2358ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Element} root The root node of the traversal. 2368ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 2378ae428e0fb7feea16d79853f29447469a93bedffKristian MonsenDomTraverser.prototype.run = function(root) { 2388ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var me = this; 2398ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen me.queue_ = [ root ]; 2408ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen while (jsLength(me.queue_)) { 2418ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen me.process_(me.queue_.shift()); 2428ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 2438ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen} 2448ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 2458ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 2468ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Processes a single node. 2478ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Element} node The current node of the traversal. 2488ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 2498ae428e0fb7feea16d79853f29447469a93bedffKristian MonsenDomTraverser.prototype.process_ = function(node) { 2508ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var me = this; 2518ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 2528ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen me.callback_(node); 2538ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 2548ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen for (var c = node.firstChild; c; c = c.nextSibling) { 2558ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (c.nodeType == DOM_ELEMENT_NODE) { 2568ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen me.queue_.push(c); 2578ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 2588ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 2598ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen} 2608ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 2618ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 2628ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Get an attribute from the DOM. Simple redirect, exists to compress code. 2638ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * 2648ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Element} node Element to interrogate. 2658ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {string} name Name of parameter to extract. 2668ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @return {string|null} Resulting attribute. 2678ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 2688ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction domGetAttribute(node, name) { 2698ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return node.getAttribute(name); 2708ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // NOTE(mesch): Neither in IE nor in Firefox, HTML DOM attributes 2718ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // implement namespaces. All items in the attribute collection have 2728ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // null localName and namespaceURI attribute values. In IE, we even 2738ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // encounter DIV elements that don't implement the method 2748ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // getAttributeNS(). 2758ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen} 2768ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 2778ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 2788ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 2798ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Set an attribute in the DOM. Simple redirect to compress code. 2808ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * 2818ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Element} node Element to interrogate. 2828ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {string} name Name of parameter to set. 2838ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {string|number} value Set attribute to this value. 2848ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 2858ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction domSetAttribute(node, name, value) { 2868ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen node.setAttribute(name, value); 2878ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen} 2888ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 2898ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 2908ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Remove an attribute from the DOM. Simple redirect to compress code. 2918ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * 2928ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Element} node Element to interrogate. 2938ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {string} name Name of parameter to remove. 2948ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 2958ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction domRemoveAttribute(node, name) { 2968ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen node.removeAttribute(name); 2978ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen} 2988ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 2998ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 3008ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Clone a node in the DOM. 3018ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * 3028ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Node} node Node to clone. 3038ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @return {Node} Cloned node. 3048ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 3058ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction domCloneNode(node) { 3068ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return node.cloneNode(true); 3078ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // NOTE(mesch): we never so far wanted to use cloneNode(false), 3088ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen // hence the default. 3098ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen} 3108ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 3118ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 3128ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Clone a element in the DOM. 3138ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * 3148ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Element} element Element to clone. 3158ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @return {Element} Cloned element. 3168ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 3178ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction domCloneElement(element) { 3188ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return /** @type {Element} */(domCloneNode(element)); 3198ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen} 3208ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 3218ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 3228ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Returns the document owner of the given element. In particular, 3238ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * returns window.document if node is null or the browser does not 3248ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * support ownerDocument. If the node is a document itself, returns 3258ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * itself. 3268ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * 3278ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Node|null|undefined} node The node whose ownerDocument is required. 3288ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @returns {Document} The owner document or window.document if unsupported. 3298ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 3308ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction ownerDocument(node) { 3318ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (!node) { 3328ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return document; 3338ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } else if (node.nodeType == DOM_DOCUMENT_NODE) { 3348ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return /** @type Document */(node); 3358ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } else { 3368ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return node.ownerDocument || document; 3378ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 3388ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen} 3398ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 3408ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 3418ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Creates a new text node in the given document. 3428ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * 3438ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Document} doc Target document. 3448ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {string} text Text composing new text node. 3458ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @return {Text} Newly constructed text node. 3468ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 3478ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction domCreateTextNode(doc, text) { 3488ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return doc.createTextNode(text); 3498ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen} 3508ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 3518ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 3528ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Appends a new child to the specified (parent) node. 3538ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * 3548ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Element} node Parent element. 3558ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Node} child Child node to append. 3568ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @return {Node} Newly appended node. 3578ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 3588ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction domAppendChild(node, child) { 3598ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return node.appendChild(child); 3608ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen} 3618ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 3628ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 3638ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Sets display to default. 3648ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * 3658ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Element} node The dom element to manipulate. 3668ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 3678ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction displayDefault(node) { 3688ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen node.style[CSS_display] = ''; 3698ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen} 3708ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 3718ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 3728ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Sets display to none. Doing this as a function saves a few bytes for 3738ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * the 'style.display' property and the 'none' literal. 3748ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * 3758ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Element} node The dom element to manipulate. 3768ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 3778ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction displayNone(node) { 3788ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen node.style[CSS_display] = 'none'; 3798ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen} 3808ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 3818ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 3828ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 3838ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Sets position style attribute to absolute. 3848ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * 3858ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Element} node The dom element to manipulate. 3868ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 3878ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction positionAbsolute(node) { 3888ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen node.style[CSS_position] = 'absolute'; 3898ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen} 3908ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 3918ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 3928ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 3938ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Inserts a new child before a given sibling. 3948ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * 3958ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Node} newChild Node to insert. 3968ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Node} oldChild Sibling node. 3978ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @return {Node} Reference to new child. 3988ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 3998ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction domInsertBefore(newChild, oldChild) { 4008ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return oldChild.parentNode.insertBefore(newChild, oldChild); 4018ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen} 4028ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 4038ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 4048ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Replaces an old child node with a new child node. 4058ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * 4068ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Node} newChild New child to append. 4078ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Node} oldChild Old child to remove. 4088ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @return {Node} Replaced node. 4098ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 4108ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction domReplaceChild(newChild, oldChild) { 4118ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return oldChild.parentNode.replaceChild(newChild, oldChild); 4128ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen} 4138ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 4148ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 4158ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Removes a node from the DOM. 4168ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * 4178ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Node} node The node to remove. 4188ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @return {Node} The removed node. 4198ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 4208ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction domRemoveNode(node) { 4218ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return domRemoveChild(node.parentNode, node); 4228ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen} 4238ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 4248ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 4258ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Remove a child from the specified (parent) node. 4268ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * 4278ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Element} node Parent element. 4288ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Node} child Child node to remove. 4298ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @return {Node} Removed node. 4308ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 4318ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction domRemoveChild(node, child) { 4328ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return node.removeChild(child); 4338ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen} 4348ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 4358ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 4368ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 4378ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Trim whitespace from begin and end of string. 4388ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * 4398ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @see testStringTrim(); 4408ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * 4418ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {string} str Input string. 4428ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @return {string} Trimmed string. 4438ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 4448ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction stringTrim(str) { 4458ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return stringTrimRight(stringTrimLeft(str)); 4468ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen} 4478ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 4488ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 4498ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Trim whitespace from beginning of string. 4508ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * 4518ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @see testStringTrimLeft(); 4528ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * 4538ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {string} str Input string. 4548ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @return {string} Trimmed string. 4558ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 4568ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction stringTrimLeft(str) { 4578ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return str.replace(/^\s+/, ""); 4588ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen} 4598ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 4608ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 4618ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Trim whitespace from end of string. 4628ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * 4638ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @see testStringTrimRight(); 4648ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * 4658ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {string} str Input string. 4668ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @return {string} Trimmed string. 4678ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 4688ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction stringTrimRight(str) { 4698ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return str.replace(/\s+$/, ""); 4708ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen} 4718ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 472