Separate Simple Backend creation from initialization.
[chromium-blink-merge.git] / third_party / jstemplate / util.js
blobbeed59162615dfb89ada347a5c7ff861fa19b894
1 // Copyright 2006 Google Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
12 // implied. See the License for the specific language governing
13 // permissions and limitations under the License.
14 /**
15  * @fileoverview Miscellaneous constants and functions referenced in
16  * the main source files.
17  */
19 function log(msg) {}
21 // String literals defined globally and not to be inlined. (IE6 perf)
22 /** @const */ var STRING_empty = '';
24 /** @const */ var CSS_display = 'display';
25 /** @const */ var CSS_position = 'position';
27 // Constants for possible values of the typeof operator.
28 var TYPE_boolean = 'boolean';
29 var TYPE_number = 'number';
30 var TYPE_object = 'object';
31 var TYPE_string = 'string';
32 var TYPE_function = 'function';
33 var TYPE_undefined = 'undefined';
36 /**
37  * Wrapper for the eval() builtin function to evaluate expressions and
38  * obtain their value. It wraps the expression in parentheses such
39  * that object literals are really evaluated to objects. Without the
40  * wrapping, they are evaluated as block, and create syntax
41  * errors. Also protects against other syntax errors in the eval()ed
42  * code and returns null if the eval throws an exception.
43  *
44  * @param {string} expr
45  * @return {Object|null}
46  */
47 function jsEval(expr) {
48   try {
49     // NOTE(mesch): An alternative idiom would be:
50     //
51     //   eval('(' + expr + ')');
52     //
53     // Note that using the square brackets as below, "" evals to undefined.
54     // The alternative of using parentheses does not work when evaluating
55     // function literals in IE.
56     // e.g. eval("(function() {})") returns undefined, and not a function
57     // object, in IE.
58     return eval('[' + expr + '][0]');
59   } catch (e) {
60     log('EVAL FAILED ' + expr + ': ' + e);
61     return null;
62   }
65 function jsLength(obj) {
66   return obj.length;
69 function assert(obj) {}
71 /**
72  * Copies all properties from second object to the first.  Modifies to.
73  *
74  * @param {Object} to  The target object.
75  * @param {Object} from  The source object.
76  */
77 function copyProperties(to, from) {
78   for (var p in from) {
79     to[p] = from[p];
80   }
84 /**
85  * @param {Object|null|undefined} value The possible value to use.
86  * @param {Object} defaultValue The default if the value is not set.
87  * @return {Object} The value, if it is
88  * defined and not null; otherwise the default
89  */
90 function getDefaultObject(value, defaultValue) {
91   if (typeof value != TYPE_undefined && value != null) {
92     return /** @type Object */(value);
93   } else {
94     return defaultValue;
95   }
98 /**
99  * Detect if an object looks like an Array.
100  * Note that instanceof Array is not robust; for example an Array
101  * created in another iframe fails instanceof Array.
102  * @param {Object|null} value Object to interrogate
103  * @return {boolean} Is the object an array?
104  */
105 function isArray(value) {
106   return value != null &&
107       typeof value == TYPE_object &&
108       typeof value.length == TYPE_number;
113  * Finds a slice of an array.
115  * @param {Array} array  Array to be sliced.
116  * @param {number} start  The start of the slice.
117  * @param {number} opt_end  The end of the slice (optional).
118  * @return {Array} array  The slice of the array from start to end.
119  */
120 function arraySlice(array, start, opt_end) {
121   // Use
122   //   return Function.prototype.call.apply(Array.prototype.slice, arguments);
123   // instead of the simpler
124   //   return Array.prototype.slice.call(array, start, opt_end);
125   // here because of a bug in the FF and IE implementations of
126   // Array.prototype.slice which causes this function to return an empty list
127   // if opt_end is not provided.
128   return Function.prototype.call.apply(Array.prototype.slice, arguments);
133  * Jscompiler wrapper for parseInt() with base 10.
135  * @param {string} s string repersentation of a number.
137  * @return {number} The integer contained in s, converted on base 10.
138  */
139 function parseInt10(s) {
140   return parseInt(s, 10);
145  * Clears the array by setting the length property to 0. This usually
146  * works, and if it should turn out not to work everywhere, here would
147  * be the place to implement the browser specific workaround.
149  * @param {Array} array  Array to be cleared.
150  */
151 function arrayClear(array) {
152   array.length = 0;
157  * Prebinds "this" within the given method to an object, but ignores all
158  * arguments passed to the resulting function.
159  * I.e. var_args are all the arguments that method is invoked with when
160  * invoking the bound function.
162  * @param {Object|null} object  The object that the method call targets.
163  * @param {Function} method  The target method.
164  * @return {Function}  Method with the target object bound to it and curried by
165  *                     the provided arguments.
166  */
167 function bindFully(object, method, var_args) {
168   var args = arraySlice(arguments, 2);
169   return function() {
170     return method.apply(object, args);
171   }
174 // Based on <http://www.w3.org/TR/2000/ REC-DOM-Level-2-Core-20001113/
175 // core.html#ID-1950641247>.
176 var DOM_ELEMENT_NODE = 1;
177 var DOM_ATTRIBUTE_NODE = 2;
178 var DOM_TEXT_NODE = 3;
179 var DOM_CDATA_SECTION_NODE = 4;
180 var DOM_ENTITY_REFERENCE_NODE = 5;
181 var DOM_ENTITY_NODE = 6;
182 var DOM_PROCESSING_INSTRUCTION_NODE = 7;
183 var DOM_COMMENT_NODE = 8;
184 var DOM_DOCUMENT_NODE = 9;
185 var DOM_DOCUMENT_TYPE_NODE = 10;
186 var DOM_DOCUMENT_FRAGMENT_NODE = 11;
187 var DOM_NOTATION_NODE = 12;
191 function domGetElementById(document, id) {
192   return document.getElementById(id);
196  * Creates a new node in the given document
198  * @param {Document} doc  Target document.
199  * @param {string} name  Name of new element (i.e. the tag name)..
200  * @return {Element}  Newly constructed element.
201  */
202 function domCreateElement(doc, name) {
203   return doc.createElement(name);
207  * Traverses the element nodes in the DOM section underneath the given
208  * node and invokes the given callback as a method on every element
209  * node encountered.
211  * @param {Element} node  Parent element of the subtree to traverse.
212  * @param {Function} callback  Called on each node in the traversal.
213  */
214 function domTraverseElements(node, callback) {
215   var traverser = new DomTraverser(callback);
216   traverser.run(node);
220  * A class to hold state for a dom traversal.
221  * @param {Function} callback  Called on each node in the traversal.
222  * @constructor
223  * @class
224  */
225 function DomTraverser(callback) {
226   this.callback_ = callback;
230  * Processes the dom tree in breadth-first order.
231  * @param {Element} root  The root node of the traversal.
232  */
233 DomTraverser.prototype.run = function(root) {
234   var me = this;
235   me.queue_ = [ root ];
236   while (jsLength(me.queue_)) {
237     me.process_(me.queue_.shift());
238   }
242  * Processes a single node.
243  * @param {Element} node  The current node of the traversal.
244  */
245 DomTraverser.prototype.process_ = function(node) {
246   var me = this;
248   me.callback_(node);
250   for (var c = node.firstChild; c; c = c.nextSibling) {
251     if (c.nodeType == DOM_ELEMENT_NODE) {
252       me.queue_.push(c);
253     }
254   }
258  * Get an attribute from the DOM.  Simple redirect, exists to compress code.
260  * @param {Element} node  Element to interrogate.
261  * @param {string} name  Name of parameter to extract.
262  * @return {string|null}  Resulting attribute.
263  */
264 function domGetAttribute(node, name) {
265   return node.getAttribute(name);
266   // NOTE(mesch): Neither in IE nor in Firefox, HTML DOM attributes
267   // implement namespaces. All items in the attribute collection have
268   // null localName and namespaceURI attribute values. In IE, we even
269   // encounter DIV elements that don't implement the method
270   // getAttributeNS().
275  * Set an attribute in the DOM.  Simple redirect to compress code.
277  * @param {Element} node  Element to interrogate.
278  * @param {string} name  Name of parameter to set.
279  * @param {string|number} value  Set attribute to this value.
280  */
281 function domSetAttribute(node, name, value) {
282   node.setAttribute(name, value);
286  * Remove an attribute from the DOM.  Simple redirect to compress code.
288  * @param {Element} node  Element to interrogate.
289  * @param {string} name  Name of parameter to remove.
290  */
291 function domRemoveAttribute(node, name) {
292   node.removeAttribute(name);
296  * Clone a node in the DOM.
298  * @param {Node} node  Node to clone.
299  * @return {Node}  Cloned node.
300  */
301 function domCloneNode(node) {
302   return node.cloneNode(true);
303   // NOTE(mesch): we never so far wanted to use cloneNode(false),
304   // hence the default.
308  * Clone a element in the DOM.
310  * @param {Element} element  Element to clone.
311  * @return {Element}  Cloned element.
312  */
313 function domCloneElement(element) {
314   return /** @type {Element} */(domCloneNode(element));
318  * Returns the document owner of the given element. In particular,
319  * returns window.document if node is null or the browser does not
320  * support ownerDocument.  If the node is a document itself, returns
321  * itself.
323  * @param {Node|null|undefined} node  The node whose ownerDocument is required.
324  * @returns {Document}  The owner document or window.document if unsupported.
325  */
326 function ownerDocument(node) {
327   if (!node) {
328     return document;
329   } else if (node.nodeType == DOM_DOCUMENT_NODE) {
330     return /** @type Document */(node);
331   } else {
332     return node.ownerDocument || document;
333   }
337  * Creates a new text node in the given document.
339  * @param {Document} doc  Target document.
340  * @param {string} text  Text composing new text node.
341  * @return {Text}  Newly constructed text node.
342  */
343 function domCreateTextNode(doc, text) {
344   return doc.createTextNode(text);
348  * Appends a new child to the specified (parent) node.
350  * @param {Element} node  Parent element.
351  * @param {Node} child  Child node to append.
352  * @return {Node}  Newly appended node.
353  */
354 function domAppendChild(node, child) {
355   return node.appendChild(child);
359  * Sets display to default.
361  * @param {Element} node  The dom element to manipulate.
362  */
363 function displayDefault(node) {
364   node.style[CSS_display] = '';
368  * Sets display to none. Doing this as a function saves a few bytes for
369  * the 'style.display' property and the 'none' literal.
371  * @param {Element} node  The dom element to manipulate.
372  */
373 function displayNone(node) {
374   node.style[CSS_display] = 'none';
379  * Sets position style attribute to absolute.
381  * @param {Element} node  The dom element to manipulate.
382  */
383 function positionAbsolute(node) {
384   node.style[CSS_position] = 'absolute';
389  * Inserts a new child before a given sibling.
391  * @param {Node} newChild  Node to insert.
392  * @param {Node} oldChild  Sibling node.
393  * @return {Node}  Reference to new child.
394  */
395 function domInsertBefore(newChild, oldChild) {
396   return oldChild.parentNode.insertBefore(newChild, oldChild);
400  * Replaces an old child node with a new child node.
402  * @param {Node} newChild  New child to append.
403  * @param {Node} oldChild  Old child to remove.
404  * @return {Node}  Replaced node.
405  */
406 function domReplaceChild(newChild, oldChild) {
407   return oldChild.parentNode.replaceChild(newChild, oldChild);
411  * Removes a node from the DOM.
413  * @param {Node} node  The node to remove.
414  * @return {Node}  The removed node.
415  */
416 function domRemoveNode(node) {
417   return domRemoveChild(node.parentNode, node);
421  * Remove a child from the specified (parent) node.
423  * @param {Element} node  Parent element.
424  * @param {Node} child  Child node to remove.
425  * @return {Node}  Removed node.
426  */
427 function domRemoveChild(node, child) {
428   return node.removeChild(child);
433  * Trim whitespace from begin and end of string.
435  * @see testStringTrim();
437  * @param {string} str  Input string.
438  * @return {string}  Trimmed string.
439  */
440 function stringTrim(str) {
441   return stringTrimRight(stringTrimLeft(str));
445  * Trim whitespace from beginning of string.
447  * @see testStringTrimLeft();
449  * @param {string} str  Input string.
450  * @return {string}  Trimmed string.
451  */
452 function stringTrimLeft(str) {
453   return str.replace(/^\s+/, "");
457  * Trim whitespace from end of string.
459  * @see testStringTrimRight();
461  * @param {string} str  Input string.
462  * @return {string}  Trimmed string.
463   */
464 function stringTrimRight(str) {
465   return str.replace(/\s+$/, "");