summaryrefslogtreecommitdiffstats
path: root/chrome/third_party/jstemplate/base.js
blob: a4014d895b6079a73f00f764c348b59586856533 (plain)
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
// Copyright 2005-2006 Google Inc. All Rights Reserved.
/**
 * @fileoverview This file contains miscellaneous basic functionality.
 *
 */

/**
 * Creates a DOM element with the given tag name in the document of the
 * owner element.
 *
 * @param {String} tagName  The name of the tag to create.
 * @param {Element} owner The intended owner (i.e., parent element) of
 * the created element.
 * @param {Point} opt_position  The top-left corner of the created element.
 * @param {Size} opt_size  The size of the created element.
 * @param {Boolean} opt_noAppend Do not append the new element to the owner.
 * @return {Element}  The newly created element node.
 */
function createElement(tagName, owner, opt_position, opt_size, opt_noAppend) {
  var element = ownerDocument(owner).createElement(tagName);
  // NOTE: Firefox/1.5 makes elements visible as soon as they
  // are inserted in the DOM. Hence, position must be set before
  // appending the element to its parent in order to avoid it showing
  // up transiently at the origin before placed at the right
  // position. NOTE: I don't think that this triggers the
  // reverse DOM insertion memory leak in IE.
  if (opt_position) {
    setPosition(element, opt_position);
  }
  if (opt_size) {
    setSize(element, opt_size);
  }
  if (owner && !opt_noAppend) {
    appendChild(owner, element);
  }

  return element;
}

/**
 * Creates a text node with the given value.
 *
 * @param {String} value  The text to place in the new node.
 * @param {Element} owner The owner (i.e., parent element) of the new
 * text node.
 * @return {Text}  The newly created text node.
 */
function createTextNode(value, owner) {
  var element = ownerDocument(owner).createTextNode(value);
  if (owner) {
    appendChild(owner, element);
  }
  return 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.
 *
 * @param {Node} node  The node whose ownerDocument is required.
 * @returns {Document|Null}  The owner document or null if unsupported.
 */
function ownerDocument(node) {
  return (node ? node.ownerDocument : null) || document;
}

/**
 * Wrapper function to create CSS units (pixels) string
 *
 * @param {Number} numPixels  Number of pixels, may be floating point.
 * @returns {String}  Corresponding CSS units string.
 */
function px(numPixels) {
  return round(numPixels) + "px";
}

/**
 * Sets the left and top of the given element to the given point.
 *
 * @param {Element} element  The dom element to manipulate.
 * @param {Point} point  The desired position.
 */
function setPosition(element, point) {
  var style = element.style;
  style.position = "absolute";
  style.left = px(point.x);
  style.top = px(point.y);
}

/**
 * Sets the width and height style attributes to the given size.
 *
 * @param {Element} element  The dom element to manipulate.
 * @param {Size} size  The desired size.
 */
function setSize(element, size) {
  var style = element.style;
  style.width = px(size.width);
  style.height = px(size.height);
}

/**
 * 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.display = 'none';
}

/**
 * Sets display to default.
 *
 * @param {Element} node  The dom element to manipulate.
 */
function displayDefault(node) {
  node.style.display = '';
}

/**
 * Appends the given child to the given parent in the DOM
 *
 * @param {Element} parent  The parent dom element.
 * @param {Node} child  The new child dom node.
 */
function appendChild(parent, child) {
  parent.appendChild(child);
}


/**
 * 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: 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) {
    return null;
  }
}


/**
 * Wrapper for the eval() builtin function to execute statements. This
 * guards against exceptions thrown, but doesn't return a
 * value. Still, mostly for testability, it returns a boolean to
 * indicate whether execution was successful. NOTE:
 * javascript's eval semantics is murky in that it confounds
 * expression evaluation and statement execution into a single
 * construct. Cf. jsEval().
 *
 * @param {String} stmt
 * @return {Boolean}
 */
function jsExec(stmt) {
  try {
    eval(stmt);
    return true;
  } catch (e) {
    return false;
  }
}


/**
 * Wrapper for eval with a context. NOTE: The style guide
 * deprecates eval, so this is the exception that proves the
 * rule. Notice also that since the value of the expression is
 * returned rather than assigned to a local variable, one major
 * objection aganist the use of the with() statement, namely that
 * properties of the with() target override local variables of the
 * same name, is void here.
 *
 * @param {String} expr
 * @param {Object} context
 * @return {Object|Null}
 */
function jsEvalWith(expr, context) {
  try {
    with (context) {
      // See comment in jsEval.
      return eval('[' + expr + '][0]');
    }
  } catch (e) {
    return null;
  }
}