diff options
Diffstat (limited to 'third_party/jstemplate/util.js')
-rw-r--r-- | third_party/jstemplate/util.js | 466 |
1 files changed, 466 insertions, 0 deletions
diff --git a/third_party/jstemplate/util.js b/third_party/jstemplate/util.js new file mode 100644 index 0000000..beed591 --- /dev/null +++ b/third_party/jstemplate/util.js @@ -0,0 +1,466 @@ +// Copyright 2006 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +// implied. See the License for the specific language governing +// permissions and limitations under the License. +/** + * @fileoverview Miscellaneous constants and functions referenced in + * the main source files. + */ + +function log(msg) {} + +// String literals defined globally and not to be inlined. (IE6 perf) +/** @const */ var STRING_empty = ''; + +/** @const */ var CSS_display = 'display'; +/** @const */ var CSS_position = 'position'; + +// Constants for possible values of the typeof operator. +var TYPE_boolean = 'boolean'; +var TYPE_number = 'number'; +var TYPE_object = 'object'; +var TYPE_string = 'string'; +var TYPE_function = 'function'; +var TYPE_undefined = 'undefined'; + + +/** + * Wrapper for the eval() builtin function to evaluate expressions and + * obtain their value. It wraps the expression in parentheses such + * that object literals are really evaluated to objects. Without the + * wrapping, they are evaluated as block, and create syntax + * errors. Also protects against other syntax errors in the eval()ed + * code and returns null if the eval throws an exception. + * + * @param {string} expr + * @return {Object|null} + */ +function jsEval(expr) { + try { + // NOTE(mesch): An alternative idiom would be: + // + // eval('(' + expr + ')'); + // + // Note that using the square brackets as below, "" evals to undefined. + // The alternative of using parentheses does not work when evaluating + // function literals in IE. + // e.g. eval("(function() {})") returns undefined, and not a function + // object, in IE. + return eval('[' + expr + '][0]'); + } catch (e) { + log('EVAL FAILED ' + expr + ': ' + e); + return null; + } +} + +function jsLength(obj) { + return obj.length; +} + +function assert(obj) {} + +/** + * Copies all properties from second object to the first. Modifies to. + * + * @param {Object} to The target object. + * @param {Object} from The source object. + */ +function copyProperties(to, from) { + for (var p in from) { + to[p] = from[p]; + } +} + + +/** + * @param {Object|null|undefined} value The possible value to use. + * @param {Object} defaultValue The default if the value is not set. + * @return {Object} The value, if it is + * defined and not null; otherwise the default + */ +function getDefaultObject(value, defaultValue) { + if (typeof value != TYPE_undefined && value != null) { + return /** @type Object */(value); + } else { + return defaultValue; + } +} + +/** + * Detect if an object looks like an Array. + * Note that instanceof Array is not robust; for example an Array + * created in another iframe fails instanceof Array. + * @param {Object|null} value Object to interrogate + * @return {boolean} Is the object an array? + */ +function isArray(value) { + return value != null && + typeof value == TYPE_object && + typeof value.length == TYPE_number; +} + + +/** + * Finds a slice of an array. + * + * @param {Array} array Array to be sliced. + * @param {number} start The start of the slice. + * @param {number} opt_end The end of the slice (optional). + * @return {Array} array The slice of the array from start to end. + */ +function arraySlice(array, start, opt_end) { + // Use + // return Function.prototype.call.apply(Array.prototype.slice, arguments); + // instead of the simpler + // return Array.prototype.slice.call(array, start, opt_end); + // here because of a bug in the FF and IE implementations of + // Array.prototype.slice which causes this function to return an empty list + // if opt_end is not provided. + return Function.prototype.call.apply(Array.prototype.slice, arguments); +} + + +/** + * Jscompiler wrapper for parseInt() with base 10. + * + * @param {string} s string repersentation of a number. + * + * @return {number} The integer contained in s, converted on base 10. + */ +function parseInt10(s) { + return parseInt(s, 10); +} + + +/** + * Clears the array by setting the length property to 0. This usually + * works, and if it should turn out not to work everywhere, here would + * be the place to implement the browser specific workaround. + * + * @param {Array} array Array to be cleared. + */ +function arrayClear(array) { + array.length = 0; +} + + +/** + * Prebinds "this" within the given method to an object, but ignores all + * arguments passed to the resulting function. + * I.e. var_args are all the arguments that method is invoked with when + * invoking the bound function. + * + * @param {Object|null} object The object that the method call targets. + * @param {Function} method The target method. + * @return {Function} Method with the target object bound to it and curried by + * the provided arguments. + */ +function bindFully(object, method, var_args) { + var args = arraySlice(arguments, 2); + return function() { + return method.apply(object, args); + } +} + +// Based on <http://www.w3.org/TR/2000/ REC-DOM-Level-2-Core-20001113/ +// core.html#ID-1950641247>. +var DOM_ELEMENT_NODE = 1; +var DOM_ATTRIBUTE_NODE = 2; +var DOM_TEXT_NODE = 3; +var DOM_CDATA_SECTION_NODE = 4; +var DOM_ENTITY_REFERENCE_NODE = 5; +var DOM_ENTITY_NODE = 6; +var DOM_PROCESSING_INSTRUCTION_NODE = 7; +var DOM_COMMENT_NODE = 8; +var DOM_DOCUMENT_NODE = 9; +var DOM_DOCUMENT_TYPE_NODE = 10; +var DOM_DOCUMENT_FRAGMENT_NODE = 11; +var DOM_NOTATION_NODE = 12; + + + +function domGetElementById(document, id) { + return document.getElementById(id); +} + +/** + * Creates a new node in the given document + * + * @param {Document} doc Target document. + * @param {string} name Name of new element (i.e. the tag name).. + * @return {Element} Newly constructed element. + */ +function domCreateElement(doc, name) { + return doc.createElement(name); +} + +/** + * Traverses the element nodes in the DOM section underneath the given + * node and invokes the given callback as a method on every element + * node encountered. + * + * @param {Element} node Parent element of the subtree to traverse. + * @param {Function} callback Called on each node in the traversal. + */ +function domTraverseElements(node, callback) { + var traverser = new DomTraverser(callback); + traverser.run(node); +} + +/** + * A class to hold state for a dom traversal. + * @param {Function} callback Called on each node in the traversal. + * @constructor + * @class + */ +function DomTraverser(callback) { + this.callback_ = callback; +} + +/** + * Processes the dom tree in breadth-first order. + * @param {Element} root The root node of the traversal. + */ +DomTraverser.prototype.run = function(root) { + var me = this; + me.queue_ = [ root ]; + while (jsLength(me.queue_)) { + me.process_(me.queue_.shift()); + } +} + +/** + * Processes a single node. + * @param {Element} node The current node of the traversal. + */ +DomTraverser.prototype.process_ = function(node) { + var me = this; + + me.callback_(node); + + for (var c = node.firstChild; c; c = c.nextSibling) { + if (c.nodeType == DOM_ELEMENT_NODE) { + me.queue_.push(c); + } + } +} + +/** + * Get an attribute from the DOM. Simple redirect, exists to compress code. + * + * @param {Element} node Element to interrogate. + * @param {string} name Name of parameter to extract. + * @return {string|null} Resulting attribute. + */ +function domGetAttribute(node, name) { + return node.getAttribute(name); + // NOTE(mesch): Neither in IE nor in Firefox, HTML DOM attributes + // implement namespaces. All items in the attribute collection have + // null localName and namespaceURI attribute values. In IE, we even + // encounter DIV elements that don't implement the method + // getAttributeNS(). +} + + +/** + * Set an attribute in the DOM. Simple redirect to compress code. + * + * @param {Element} node Element to interrogate. + * @param {string} name Name of parameter to set. + * @param {string|number} value Set attribute to this value. + */ +function domSetAttribute(node, name, value) { + node.setAttribute(name, value); +} + +/** + * Remove an attribute from the DOM. Simple redirect to compress code. + * + * @param {Element} node Element to interrogate. + * @param {string} name Name of parameter to remove. + */ +function domRemoveAttribute(node, name) { + node.removeAttribute(name); +} + +/** + * Clone a node in the DOM. + * + * @param {Node} node Node to clone. + * @return {Node} Cloned node. + */ +function domCloneNode(node) { + return node.cloneNode(true); + // NOTE(mesch): we never so far wanted to use cloneNode(false), + // hence the default. +} + +/** + * Clone a element in the DOM. + * + * @param {Element} element Element to clone. + * @return {Element} Cloned element. + */ +function domCloneElement(element) { + return /** @type {Element} */(domCloneNode(element)); +} + +/** + * Returns the document owner of the given element. In particular, + * returns window.document if node is null or the browser does not + * support ownerDocument. If the node is a document itself, returns + * itself. + * + * @param {Node|null|undefined} node The node whose ownerDocument is required. + * @returns {Document} The owner document or window.document if unsupported. + */ +function ownerDocument(node) { + if (!node) { + return document; + } else if (node.nodeType == DOM_DOCUMENT_NODE) { + return /** @type Document */(node); + } else { + return node.ownerDocument || document; + } +} + +/** + * Creates a new text node in the given document. + * + * @param {Document} doc Target document. + * @param {string} text Text composing new text node. + * @return {Text} Newly constructed text node. + */ +function domCreateTextNode(doc, text) { + return doc.createTextNode(text); +} + +/** + * Appends a new child to the specified (parent) node. + * + * @param {Element} node Parent element. + * @param {Node} child Child node to append. + * @return {Node} Newly appended node. + */ +function domAppendChild(node, child) { + return node.appendChild(child); +} + +/** + * Sets display to default. + * + * @param {Element} node The dom element to manipulate. + */ +function displayDefault(node) { + node.style[CSS_display] = ''; +} + +/** + * Sets display to none. Doing this as a function saves a few bytes for + * the 'style.display' property and the 'none' literal. + * + * @param {Element} node The dom element to manipulate. + */ +function displayNone(node) { + node.style[CSS_display] = 'none'; +} + + +/** + * Sets position style attribute to absolute. + * + * @param {Element} node The dom element to manipulate. + */ +function positionAbsolute(node) { + node.style[CSS_position] = 'absolute'; +} + + +/** + * Inserts a new child before a given sibling. + * + * @param {Node} newChild Node to insert. + * @param {Node} oldChild Sibling node. + * @return {Node} Reference to new child. + */ +function domInsertBefore(newChild, oldChild) { + return oldChild.parentNode.insertBefore(newChild, oldChild); +} + +/** + * Replaces an old child node with a new child node. + * + * @param {Node} newChild New child to append. + * @param {Node} oldChild Old child to remove. + * @return {Node} Replaced node. + */ +function domReplaceChild(newChild, oldChild) { + return oldChild.parentNode.replaceChild(newChild, oldChild); +} + +/** + * Removes a node from the DOM. + * + * @param {Node} node The node to remove. + * @return {Node} The removed node. + */ +function domRemoveNode(node) { + return domRemoveChild(node.parentNode, node); +} + +/** + * Remove a child from the specified (parent) node. + * + * @param {Element} node Parent element. + * @param {Node} child Child node to remove. + * @return {Node} Removed node. + */ +function domRemoveChild(node, child) { + return node.removeChild(child); +} + + +/** + * Trim whitespace from begin and end of string. + * + * @see testStringTrim(); + * + * @param {string} str Input string. + * @return {string} Trimmed string. + */ +function stringTrim(str) { + return stringTrimRight(stringTrimLeft(str)); +} + +/** + * Trim whitespace from beginning of string. + * + * @see testStringTrimLeft(); + * + * @param {string} str Input string. + * @return {string} Trimmed string. + */ +function stringTrimLeft(str) { + return str.replace(/^\s+/, ""); +} + +/** + * Trim whitespace from end of string. + * + * @see testStringTrimRight(); + * + * @param {string} str Input string. + * @return {string} Trimmed string. + */ +function stringTrimRight(str) { + return str.replace(/\s+$/, ""); +} |