1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
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+$/, "");
}
|