18ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/**
28ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @fileoverview This file contains miscellaneous basic functionality.
38ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
48ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */
58ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
68ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/**
78ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Creates a DOM element with the given tag name in the document of the
88ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * owner element.
98ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
108ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {String} tagName  The name of the tag to create.
118ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Element} owner The intended owner (i.e., parent element) of
128ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * the created element.
138ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Point} opt_position  The top-left corner of the created element.
148ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Size} opt_size  The size of the created element.
158ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Boolean} opt_noAppend Do not append the new element to the owner.
168ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @return {Element}  The newly created element node.
178ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */
188ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction createElement(tagName, owner, opt_position, opt_size, opt_noAppend) {
198ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  var element = ownerDocument(owner).createElement(tagName);
208ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  if (opt_position) {
218ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    setPosition(element, opt_position);
228ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  }
238ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  if (opt_size) {
248ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    setSize(element, opt_size);
258ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  }
268ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  if (owner && !opt_noAppend) {
278ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    appendChild(owner, element);
288ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  }
298ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
308ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  return element;
318ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}
328ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
338ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/**
348ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Creates a text node with the given value.
358ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
368ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {String} value  The text to place in the new node.
378ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Element} owner The owner (i.e., parent element) of the new
388ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * text node.
398ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @return {Text}  The newly created text node.
408ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */
418ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction createTextNode(value, owner) {
428ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  var element = ownerDocument(owner).createTextNode(value);
438ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  if (owner) {
448ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    appendChild(owner, element);
458ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  }
468ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  return element;
478ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}
488ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
498ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/**
508ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Returns the document owner of the given element. In particular,
518ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * returns window.document if node is null or the browser does not
528ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * support ownerDocument.
538ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
548ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Node} node  The node whose ownerDocument is required.
558ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @returns {Document|Null}  The owner document or null if unsupported.
568ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */
578ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction ownerDocument(node) {
588ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  return (node ? node.ownerDocument : null) || document;
598ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}
608ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
618ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/**
628ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Wrapper function to create CSS units (pixels) string
638ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
648ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Number} numPixels  Number of pixels, may be floating point.
658ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @returns {String}  Corresponding CSS units string.
668ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */
678ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction px(numPixels) {
688ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  return round(numPixels) + "px";
698ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}
708ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
718ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/**
728ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Sets the left and top of the given element to the given point.
738ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
748ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Element} element  The dom element to manipulate.
758ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Point} point  The desired position.
768ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */
778ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction setPosition(element, point) {
788ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  var style = element.style;
798ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  style.position = "absolute";
808ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  style.left = px(point.x);
818ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  style.top = px(point.y);
828ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}
838ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
848ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/**
858ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Sets the width and height style attributes to the given size.
868ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
878ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Element} element  The dom element to manipulate.
888ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Size} size  The desired size.
898ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */
908ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction setSize(element, size) {
918ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  var style = element.style;
928ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  style.width = px(size.width);
938ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  style.height = px(size.height);
948ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}
958ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
968ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/**
978ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Sets display to none. Doing this as a function saves a few bytes for
988ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * the 'style.display' property and the 'none' literal.
998ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
1008ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Element} node  The dom element to manipulate.
1018ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */
1028ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction displayNone(node) {
1038ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  node.style.display = 'none';
1048ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}
1058ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
1068ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/**
1078ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Sets display to default.
1088ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
1098ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Element} node  The dom element to manipulate.
1108ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */
1118ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction displayDefault(node) {
1128ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  node.style.display = '';
1138ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}
1148ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
1158ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/**
1168ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Appends the given child to the given parent in the DOM
1178ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
1188ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Element} parent  The parent dom element.
1198ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Node} child  The new child dom node.
1208ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */
1218ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction appendChild(parent, child) {
1228ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  parent.appendChild(child);
1238ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}
1248ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
1258ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
1268ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/**
1278ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Wrapper for the eval() builtin function to evaluate expressions and
1288ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * obtain their value. It wraps the expression in parentheses such
1298ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * that object literals are really evaluated to objects. Without the
1308ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * wrapping, they are evaluated as block, and create syntax
1318ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * errors. Also protects against other syntax errors in the eval()ed
1328ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * code and returns null if the eval throws an exception.
1338ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
1348ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {String} expr
1358ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @return {Object|Null}
1368ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */
1378ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction jsEval(expr) {
1388ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  try {
1398ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    return eval('[' + expr + '][0]');
1408ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  } catch (e) {
1418ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    return null;
1428ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  }
1438ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}
1448ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
1458ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
1468ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/**
1478ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Wrapper for the eval() builtin function to execute statements. This
1488ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * guards against exceptions thrown, but doesn't return a
1498ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * value. Still, mostly for testability, it returns a boolean to
1508ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * indicate whether execution was successful. NOTE:
1518ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * javascript's eval semantics is murky in that it confounds
1528ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * expression evaluation and statement execution into a single
1538ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * construct. Cf. jsEval().
1548ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
1558ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {String} stmt
1568ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @return {Boolean}
1578ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */
1588ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction jsExec(stmt) {
1598ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  try {
1608ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    eval(stmt);
1618ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    return true;
1628ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  } catch (e) {
1638ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    return false;
1648ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  }
1658ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}
1668ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
1678ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
1688ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/**
1698ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Wrapper for eval with a context. NOTE: The style guide
1708ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * deprecates eval, so this is the exception that proves the
1718ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * rule. Notice also that since the value of the expression is
1728ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * returned rather than assigned to a local variable, one major
1738ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * objection aganist the use of the with() statement, namely that
1748ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * properties of the with() target override local variables of the
1758ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * same name, is void here.
1768ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
1778ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {String} expr
1788ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Object} context
1798ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @return {Object|Null}
1808ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */
1818ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction jsEvalWith(expr, context) {
1828ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  try {
1838ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    with (context) {
1848ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen      return eval('[' + expr + '][0]');
1858ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    }
1868ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  } catch (e) {
1878ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    return null;
1888ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  }
1898ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}
1908ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
1918ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
1928ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenvar DOM_ELEMENT_NODE = 1;
1938ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenvar DOM_ATTRIBUTE_NODE = 2;
1948ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenvar DOM_TEXT_NODE = 3;
1958ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenvar DOM_CDATA_SECTION_NODE = 4;
1968ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenvar DOM_ENTITY_REFERENCE_NODE = 5;
1978ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenvar DOM_ENTITY_NODE = 6;
1988ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenvar DOM_PROCESSING_INSTRUCTION_NODE = 7;
1998ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenvar DOM_COMMENT_NODE = 8;
2008ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenvar DOM_DOCUMENT_NODE = 9;
2018ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenvar DOM_DOCUMENT_TYPE_NODE = 10;
2028ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenvar DOM_DOCUMENT_FRAGMENT_NODE = 11;
2038ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenvar DOM_NOTATION_NODE = 12;
2048ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
2058ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/**
2068ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Traverses the element nodes in the DOM tree underneath the given
2078ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * node and finds the first node with elemId, or null if there is no such
2088ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * element.  Traversal is in depth-first order.
2098ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
2108ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * NOTE: The reason this is not combined with the elem() function is
2118ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * that the implementations are different.
2128ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * elem() is a wrapper for the built-in document.getElementById() function,
2138ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * whereas this function performs the traversal itself.
2148ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Modifying elem() to take an optional root node is a possibility,
2158ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * but the in-built function would perform better than using our own traversal.
2168ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
2178ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Element} node Root element of subtree to traverse.
2188ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {String} elemId The id of the element to search for.
2198ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @return {Element|Null} The corresponding element, or null if not found.
2208ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */
2218ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction nodeGetElementById(node, elemId) {
2228ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  for (var c = node.firstChild; c; c = c.nextSibling) {
2238ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    if (c.id == elemId) {
2248ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen      return c;
2258ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    }
2268ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    if (c.nodeType == DOM_ELEMENT_NODE) {
2278ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen      var n = arguments.callee.call(this, c, elemId);
2288ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen      if (n) {
2298ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen        return n;
2308ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen      }
2318ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    }
2328ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  }
2338ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  return null;
2348ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}
2358ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
2368ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
2378ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/**
2388ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Get an attribute from the DOM.  Simple redirect, exists to compress code.
2398ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
2408ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Element} node  Element to interrogate.
2418ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {String} name  Name of parameter to extract.
2428ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @return {String}  Resulting attribute.
2438ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */
2448ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction domGetAttribute(node, name) {
2458ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  return node.getAttribute(name);
2468ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}
2478ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
2488ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/**
2498ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Set an attribute in the DOM.  Simple redirect to compress code.
2508ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
2518ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Element} node  Element to interrogate.
2528ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {String} name  Name of parameter to set.
2538ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {String} value  Set attribute to this value.
2548ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */
2558ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction domSetAttribute(node, name, value) {
2568ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  node.setAttribute(name, value);
2578ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}
2588ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
2598ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/**
2608ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Remove an attribute from the DOM.  Simple redirect to compress code.
2618ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
2628ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Element} node  Element to interrogate.
2638ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {String} name  Name of parameter to remove.
2648ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */
2658ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction domRemoveAttribute(node, name) {
2668ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  node.removeAttribute(name);
2678ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}
2688ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
2698ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/**
2708ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Clone a node in the DOM.
2718ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
2728ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Node} node  Node to clone.
2738ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @return {Node}  Cloned node.
2748ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */
2758ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction domCloneNode(node) {
2768ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  return node.cloneNode(true);
2778ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}
2788ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
2798ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
2808ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/**
2818ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Return a safe string for the className of a node.
2828ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * If className is not a string, returns "".
2838ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
2848ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Element} node  DOM element to query.
2858ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @return {String}
2868ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */
2878ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction domClassName(node) {
2888ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  return node.className ? "" + node.className : "";
2898ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}
2908ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
2918ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/**
2928ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Adds a class name to the class attribute of the given node.
2938ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
2948ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Element} node  DOM element to modify.
2958ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {String} className  Class name to add.
2968ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */
2978ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction domAddClass(node, className) {
2988ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  var name = domClassName(node);
2998ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  if (name) {
3008ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    var cn = name.split(/\s+/);
3018ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    var found = false;
3028ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    for (var i = 0; i < jsLength(cn); ++i) {
3038ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen      if (cn[i] == className) {
3048ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen        found = true;
3058ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen        break;
3068ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen      }
3078ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    }
3088ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
3098ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    if (!found) {
3108ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen      cn.push(className);
3118ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    }
3128ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
3138ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    node.className = cn.join(' ');
3148ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  } else {
3158ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    node.className = className;
3168ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  }
3178ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}
3188ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
3198ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/**
3208ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Removes a class name from the class attribute of the given node.
3218ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
3228ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Element} node  DOM element to modify.
3238ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {String} className  Class name to remove.
3248ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */
3258ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction domRemoveClass(node, className) {
3268ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  var c = domClassName(node);
3278ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  if (!c || c.indexOf(className) == -1) {
3288ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    return;
3298ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  }
3308ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  var cn = c.split(/\s+/);
3318ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  for (var i = 0; i < jsLength(cn); ++i) {
3328ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    if (cn[i] == className) {
3338ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen      cn.splice(i--, 1);
3348ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    }
3358ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  }
3368ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  node.className = cn.join(' ');
3378ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}
3388ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
3398ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/**
3408ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Checks if a node belongs to a style class.
3418ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
3428ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Element} node  DOM element to test.
3438ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {String} className  Class name to check for.
3448ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @return {Boolean}  Node belongs to style class.
3458ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */
3468ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction domTestClass(node, className) {
3478ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  var cn = domClassName(node).split(/\s+/);
3488ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  for (var i = 0; i < jsLength(cn); ++i) {
3498ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    if (cn[i] == className) {
3508ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen      return true;
3518ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    }
3528ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  }
3538ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  return false;
3548ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}
3558ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
3568ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/**
3578ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Inserts a new child before a given sibling.
3588ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
3598ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Node} newChild  Node to insert.
3608ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Node} oldChild  Sibling node.
3618ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @return {Node}  Reference to new child.
3628ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */
3638ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction domInsertBefore(newChild, oldChild) {
3648ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  return oldChild.parentNode.insertBefore(newChild, oldChild);
3658ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}
3668ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
3678ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/**
3688ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Appends a new child to the specified (parent) node.
3698ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
3708ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Element} node  Parent element.
3718ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Node} child  Child node to append.
3728ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @return {Node}  Newly appended node.
3738ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */
3748ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction domAppendChild(node, child) {
3758ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  return node.appendChild(child);
3768ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}
3778ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
3788ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/**
3798ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Remove a new child from the specified (parent) node.
3808ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
3818ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Element} node  Parent element.
3828ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Node} child  Child node to remove.
3838ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @return {Node}  Removed node.
3848ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */
3858ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction domRemoveChild(node, child) {
3868ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  return node.removeChild(child);
3878ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}
3888ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
3898ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/**
3908ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Replaces an old child node with a new child node.
3918ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
3928ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Node} newChild  New child to append.
3938ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Node} oldChild  Old child to remove.
3948ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @return {Node}  Replaced node.
3958ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */
3968ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction domReplaceChild(newChild, oldChild) {
3978ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  return oldChild.parentNode.replaceChild(newChild, oldChild);
3988ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}
3998ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
4008ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/**
4018ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Removes a node from the DOM.
4028ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
4038ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Node} node  The node to remove.
4048ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @return {Node}  The removed node.
4058ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */
4068ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction domRemoveNode(node) {
4078ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  return domRemoveChild(node.parentNode, node);
4088ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}
4098ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
4108ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/**
4118ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Creates a new text node in the given document.
4128ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
4138ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Document} doc  Target document.
4148ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {String} text  Text composing new text node.
4158ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @return {Text}  Newly constructed text node.
4168ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */
4178ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction domCreateTextNode(doc, text) {
4188ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  return doc.createTextNode(text);
4198ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}
4208ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
4218ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/**
4228ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Creates a new node in the given document
4238ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
4248ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Document} doc  Target document.
4258ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {String} name  Name of new element (i.e. the tag name)..
4268ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @return {Element}  Newly constructed element.
4278ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */
4288ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction domCreateElement(doc, name) {
4298ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  return doc.createElement(name);
4308ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}
4318ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
4328ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/**
4338ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Creates a new attribute in the given document.
4348ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
4358ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Document} doc  Target document.
4368ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {String} name  Name of new attribute.
4378ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @return {Attr}  Newly constructed attribute.
4388ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */
4398ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction domCreateAttribute(doc, name) {
4408ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  return doc.createAttribute(name);
4418ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}
4428ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
4438ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/**
4448ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Creates a new comment in the given document.
4458ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
4468ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Document} doc  Target document.
4478ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {String} text  Comment text.
4488ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @return {Comment}  Newly constructed comment.
4498ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */
4508ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction domCreateComment(doc, text) {
4518ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  return doc.createComment(text);
4528ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}
4538ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
4548ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/**
4558ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Creates a document fragment.
4568ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
4578ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Document} doc  Target document.
4588ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @return {DocumentFragment}  Resulting document fragment node.
4598ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */
4608ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction domCreateDocumentFragment(doc) {
4618ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  return doc.createDocumentFragment();
4628ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}
4638ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
4648ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/**
4658ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Redirect to document.getElementById
4668ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
4678ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Document} doc  Target document.
4688ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {String} id  Id of requested node.
4698ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @return {Element|Null}  Resulting element.
4708ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */
4718ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction domGetElementById(doc, id) {
4728ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  return doc.getElementById(id);
4738ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}
4748ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
4758ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/**
4768ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Redirect to window.setInterval
4778ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
4788ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Window} win  Target window.
4798ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Function} fun  Callback function.
4808ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Number} time  Time in milliseconds.
4818ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @return {Object}  Contract id.
4828ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */
4838ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction windowSetInterval(win, fun, time) {
4848ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  return win.setInterval(fun, time);
4858ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}
4868ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
4878ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/**
4888ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Redirect to window.clearInterval
4898ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
4908ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Window} win  Target window.
4918ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {object} id  Contract id.
4928ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @return {any}  NOTE: Return type unknown?
4938ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */
4948ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction windowClearInterval(win, id) {
4958ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  return win.clearInterval(id);
4968ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}
4978ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
4988ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/**
4998ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Determines whether one node is recursively contained in another.
5008ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param parent The parent node.
5018ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param child The node to look for in parent.
5028ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @return parent recursively contains child
5038ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */
5048ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction containsNode(parent, child) {
5058ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  while (parent != child && child.parentNode) {
5068ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    child = child.parentNode;
5078ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  }
5088ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  return parent == child;
5098ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen};
5108ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/**
5118ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @fileoverview This file contains javascript utility functions that
5128ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * do not depend on anything defined elsewhere.
5138ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
5148ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */
5158ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
5168ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/**
5178ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Returns the value of the length property of the given object. Used
5188ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * to reduce compiled code size.
5198ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
5208ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Array | String} a  The string or array to interrogate.
5218ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @return {Number}  The value of the length property.
5228ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */
5238ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction jsLength(a) {
5248ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  return a.length;
5258ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}
5268ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
5278ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenvar min = Math.min;
5288ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenvar max = Math.max;
5298ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenvar ceil = Math.ceil;
5308ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenvar floor = Math.floor;
5318ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenvar round = Math.round;
5328ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenvar abs = Math.abs;
5338ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
5348ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/**
5358ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Copies all properties from second object to the first.  Modifies to.
5368ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
5378ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Object} to  The target object.
5388ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Object} from  The source object.
5398ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */
5408ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction copyProperties(to, from) {
5418ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  foreachin(from, function(p) {
5428ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    to[p] = from[p];
5438ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  });
5448ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}
5458ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
5468ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/**
5478ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Iterates over the array, calling the given function for each
5488ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * element.
5498ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
5508ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Array} array
5518ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Function} fn
5528ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */
5538ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction foreach(array, fn) {
5548ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  var I = jsLength(array);
5558ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  for (var i = 0; i < I; ++i) {
5568ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    fn(array[i], i);
5578ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  }
5588ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}
5598ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
5608ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/**
5618ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Safely iterates over all properties of the given object, calling
5628ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * the given function for each property. If opt_all isn't true, uses
5638ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * hasOwnProperty() to assure the property is on the object, not on
5648ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * its prototype.
5658ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
5668ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Object} object
5678ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Function} fn
5688ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Boolean} opt_all  If true, also iterates over inherited properties.
5698ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */
5708ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction foreachin(object, fn, opt_all) {
5718ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  for (var i in object) {
5728ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    if (opt_all || !object.hasOwnProperty || object.hasOwnProperty(i)) {
5738ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen      fn(i, object[i]);
5748ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    }
5758ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  }
5768ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}
5778ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
5788ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/**
5798ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Appends the second array to the first, copying its elements.
5808ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Optionally only a slice of the second array is copied.
5818ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
5828ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Array} a1  Target array (modified).
5838ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Array} a2  Source array.
5848ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Number} opt_begin  Begin of slice of second array (optional).
5858ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Number} opt_end  End (exclusive) of slice of second array (optional).
5868ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */
5878ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction arrayAppend(a1, a2, opt_begin, opt_end) {
5888ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  var i0 = opt_begin || 0;
5898ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  var i1 = opt_end || jsLength(a2);
5908ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  for (var i = i0; i < i1; ++i) {
5918ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    a1.push(a2[i]);
5928ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  }
5938ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}
5948ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
5958ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/**
5968ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Trim whitespace from begin and end of string.
5978ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
5988ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @see testStringTrim();
5998ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
6008ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {String} str  Input string.
6018ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @return {String}  Trimmed string.
6028ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */
6038ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction stringTrim(str) {
6048ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  return stringTrimRight(stringTrimLeft(str));
6058ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}
6068ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
6078ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/**
6088ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Trim whitespace from beginning of string.
6098ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
6108ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @see testStringTrimLeft();
6118ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
6128ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {String} str  Input string.
6138ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @return {String}  Trimmed string.
6148ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */
6158ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction stringTrimLeft(str) {
6168ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  return str.replace(/^\s+/, "");
6178ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}
6188ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
6198ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/**
6208ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Trim whitespace from end of string.
6218ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
6228ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @see testStringTrimRight();
6238ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
6248ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {String} str  Input string.
6258ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @return {String}  Trimmed string.
6268ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */
6278ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction stringTrimRight(str) {
6288ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  return str.replace(/\s+$/, "");
6298ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}
6308ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
6318ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/**
6328ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Jscompiler wrapper for parseInt() with base 10.
6338ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
6348ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {String} s String repersentation of a number.
6358ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
6368ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @return {Number} The integer contained in s, converted on base 10.
6378ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */
6388ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction parseInt10(s) {
6398ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  return parseInt(s, 10);
6408ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}
6418ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/**
6428ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @fileoverview A simple formatter to project JavaScript data into
6438ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * HTML templates. The template is edited in place. I.e. in order to
6448ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * instantiate a template, clone it from the DOM first, and then
6458ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * process the cloned template. This allows for updating of templates:
6468ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * If the templates is processed again, changed values are merely
6478ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * updated.
6488ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
6498ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * NOTE: IE DOM doesn't have importNode().
6508ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
6518ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * NOTE: The property name "length" must not be used in input
6528ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * data, see comment in jstSelect_().
6538ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */
6548ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
6558ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
6568ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/**
6578ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Names of jstemplate attributes. These attributes are attached to
6588ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * normal HTML elements and bind expression context data to the HTML
6598ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * fragment that is used as template.
6608ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */
6618ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenvar ATT_select = 'jsselect';
6628ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenvar ATT_instance = 'jsinstance';
6638ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenvar ATT_display = 'jsdisplay';
6648ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenvar ATT_values = 'jsvalues';
6658ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenvar ATT_eval = 'jseval';
6668ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenvar ATT_transclude = 'transclude';
6678ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenvar ATT_content = 'jscontent';
6688ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
6698ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
6708ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/**
6718ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Names of special variables defined by the jstemplate evaluation
6728ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * context. These can be used in js expression in jstemplate
6738ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * attributes.
6748ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */
6758ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenvar VAR_index = '$index';
6768ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenvar VAR_this = '$this';
6778ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
6788ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
6798ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/**
6808ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Context for processing a jstemplate. The context contains a context
6818ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * object, whose properties can be referred to in jstemplate
6828ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * expressions, and it holds the locally defined variables.
6838ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
6848ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Object} opt_data The context object. Null if no context.
6858ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
6868ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Object} opt_parent The parent context, from which local
6878ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * variables are inherited. Normally the context object of the parent
6888ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * context is the object whose property the parent object is. Null for the
6898ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * context of the root object.
6908ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
6918ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @constructor
6928ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */
6938ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction JsExprContext(opt_data, opt_parent) {
6948ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  var me = this;
6958ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
6968ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  /**
6978ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen   * The local context of the input data in which the jstemplate
6988ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen   * expressions are evaluated. Notice that this is usually an Object,
6998ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen   * but it can also be a scalar value (and then still the expression
7008ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen   * $this can be used to refer to it). Notice this can be a scalar
7018ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen   * value, including undefined.
7028ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen   *
7038ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen   * @type {Object}
7048ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen   */
7058ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  me.data_ = opt_data;
7068ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
7078ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  /**
7088ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen   * The context for variable definitions in which the jstemplate
7098ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen   * expressions are evaluated. Other than for the local context,
7108ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen   * which replaces the parent context, variable definitions of the
7118ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen   * parent are inherited. The special variable $this points to data_.
7128ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen   *
7138ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen   * @type {Object}
7148ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen   */
7158ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  me.vars_ = {};
7168ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  if (opt_parent) {
7178ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    copyProperties(me.vars_, opt_parent.vars_);
7188ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  }
7198ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  this.vars_[VAR_this] = me.data_;
7208ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}
7218ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
7228ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
7238ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/**
7248ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Evaluates the given expression in the context of the current
7258ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * context object and the current local variables.
7268ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
7278ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {String} expr A javascript expression.
7288ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
7298ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Element} template DOM node of the template.
7308ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
7318ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @return The value of that expression.
7328ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */
7338ae428e0fb7feea16d79853f29447469a93bedffKristian MonsenJsExprContext.prototype.jseval = function(expr, template) {
7348ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  with (this.vars_) {
7358ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    with (this.data_) {
7368ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen      try {
7378ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen        return (function() {
7388ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen          return eval('[' + expr + '][0]');
7398ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen        }).call(template);
7408ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen      } catch (e) {
7418ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen        return null;
7428ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen      }
7438ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    }
7448ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  }
7458ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}
7468ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
7478ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
7488ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/**
7498ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Clones the current context for a new context object. The cloned
7508ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * context has the data object as its context object and the current
7518ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * context as its parent context. It also sets the $index variable to
7528ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * the given value. This value usually is the position of the data
7538ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * object in a list for which a template is instantiated multiply.
7548ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
7558ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Object} data The new context object.
7568ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
7578ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Number} index Position of the new context when multiply
7588ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * instantiated. (See implementation of jstSelect().)
7598ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
7608ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @return {JsExprContext}
7618ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */
7628ae428e0fb7feea16d79853f29447469a93bedffKristian MonsenJsExprContext.prototype.clone = function(data, index) {
7638ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  var ret = new JsExprContext(data, this);
7648ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  ret.setVariable(VAR_index, index);
7658ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  if (this.resolver_) {
7668ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    ret.setSubTemplateResolver(this.resolver_);
7678ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  }
7688ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  return ret;
7698ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}
7708ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
7718ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
7728ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/**
7738ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Binds a local variable to the given value. If set from jstemplate
7748ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * jsvalue expressions, variable names must start with $, but in the
7758ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * API they only have to be valid javascript identifier.
7768ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
7778ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {String} name
7788ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
7798ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Object} value
7808ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */
7818ae428e0fb7feea16d79853f29447469a93bedffKristian MonsenJsExprContext.prototype.setVariable = function(name, value) {
7828ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  this.vars_[name] = value;
7838ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}
7848ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
7858ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
7868ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/**
7878ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Sets the function used to resolve the values of the transclude
7888ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * attribute into DOM nodes. By default, this is jstGetTemplate(). The
7898ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * value set here is inherited by clones of this context.
7908ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
7918ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Function} resolver The function used to resolve transclude
7928ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * ids into a DOM node of a subtemplate. The DOM node returned by this
7938ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * function will be inserted into the template instance being
7948ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * processed. Thus, the resolver function must instantiate the
7958ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * subtemplate as necessary.
7968ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */
7978ae428e0fb7feea16d79853f29447469a93bedffKristian MonsenJsExprContext.prototype.setSubTemplateResolver = function(resolver) {
7988ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  this.resolver_ = resolver;
7998ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}
8008ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
8018ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
8028ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/**
8038ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Resolves a sub template from an id. Used to process the transclude
8048ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * attribute. If a resolver function was set using
8058ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * setSubTemplateResolver(), it will be used, otherwise
8068ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * jstGetTemplate().
8078ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
8088ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {String} id The id of the sub template.
8098ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
8108ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @return {Node} The root DOM node of the sub template, for direct
8118ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * insertion into the currently processed template instance.
8128ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */
8138ae428e0fb7feea16d79853f29447469a93bedffKristian MonsenJsExprContext.prototype.getSubTemplate = function(id) {
8148ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  return (this.resolver_ || jstGetTemplate).call(this, id);
8158ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}
8168ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
8178ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
8188ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/**
8198ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * HTML template processor. Data values are bound to HTML templates
8208ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * using the attributes transclude, jsselect, jsdisplay, jscontent,
8218ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * jsvalues. The template is modifed in place. The values of those
8228ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * attributes are JavaScript expressions that are evaluated in the
8238ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * context of the data object fragment.
8248ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
8258ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {JsExprContext} context Context created from the input data
8268ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * object.
8278ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
8288ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Element} template DOM node of the template. This will be
8298ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * processed in place. After processing, it will still be a valid
8308ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * template that, if processed again with the same data, will remain
8318ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * unchanged.
8328ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */
8338ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction jstProcess(context, template) {
8348ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  var processor = new JstProcessor();
8358ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  processor.run_([ processor, processor.jstProcess_, context, template ]);
8368ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}
8378ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
8388ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
8398ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/**
8408ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Internal class used by jstemplates to maintain context.
8418ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * NOTE: This is necessary to process deep templates in Safari
8428ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * which has a relatively shallow stack.
8438ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @class
8448ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */
8458ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction JstProcessor() {
8468ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}
8478ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
8488ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
8498ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/**
8508ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Runs the state machine, beginning with function "start".
8518ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
8528ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Array} start The first function to run, in the form
8538ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * [object, method, args ...]
8548ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */
8558ae428e0fb7feea16d79853f29447469a93bedffKristian MonsenJstProcessor.prototype.run_ = function(start) {
8568ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  var me = this;
8578ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
8588ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  me.queue_ = [ start ];
8598ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  while (jsLength(me.queue_)) {
8608ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    var f = me.queue_.shift();
8618ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    f[1].apply(f[0], f.slice(2));
8628ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  }
8638ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}
8648ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
8658ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
8668ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/**
8678ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Appends a function to be called later.
8688ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Analogous to calling that function on a subsequent line, or a subsequent
8698ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * iteration of a loop.
8708ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
8718ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Array} f  A function in the form [object, method, args ...]
8728ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */
8738ae428e0fb7feea16d79853f29447469a93bedffKristian MonsenJstProcessor.prototype.enqueue_ = function(f) {
8748ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  this.queue_.push(f);
8758ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}
8768ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
8778ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
8788ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/**
8798ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Implements internals of jstProcess.
8808ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
8818ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {JsExprContext} context
8828ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
8838ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Element} template
8848ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */
8858ae428e0fb7feea16d79853f29447469a93bedffKristian MonsenJstProcessor.prototype.jstProcess_ = function(context, template) {
8868ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  var me = this;
8878ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
8888ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  var transclude = domGetAttribute(template, ATT_transclude);
8898ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  if (transclude) {
8908ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    var tr = context.getSubTemplate(transclude);
8918ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    if (tr) {
8928ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen      domReplaceChild(tr, template);
8938ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen      me.enqueue_([ me, me.jstProcess_, context, tr ]);
8948ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    } else {
8958ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen      domRemoveNode(template);
8968ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    }
8978ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    return;
8988ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  }
8998ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
9008ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  var select = domGetAttribute(template, ATT_select);
9018ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  if (select) {
9028ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    me.jstSelect_(context, template, select);
9038ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    return;
9048ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  }
9058ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
9068ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  var display = domGetAttribute(template, ATT_display);
9078ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  if (display) {
9088ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    if (!context.jseval(display, template)) {
9098ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen      displayNone(template);
9108ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen      return;
9118ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    }
9128ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
9138ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    displayDefault(template);
9148ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  }
9158ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
9168ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
9178ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  var values = domGetAttribute(template, ATT_values);
9188ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  if (values) {
9198ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    me.jstValues_(context, template, values);
9208ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  }
9218ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
9228ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  var expressions = domGetAttribute(template, ATT_eval);
9238ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  if (expressions) {
9248ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    foreach(expressions.split(/\s*;\s*/), function(expression) {
9258ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen      expression = stringTrim(expression);
9268ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen      if (jsLength(expression)) {
9278ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen        context.jseval(expression, template);
9288ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen      }
9298ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    });
9308ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  }
9318ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
9328ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  var content = domGetAttribute(template, ATT_content);
9338ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  if (content) {
9348ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    me.jstContent_(context, template, content);
9358ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
9368ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  } else {
9378ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    var childnodes = [];
9388ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    for (var i = 0; i < jsLength(template.childNodes); ++i) {
9398ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen      if (template.childNodes[i].nodeType == DOM_ELEMENT_NODE) {
9408ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen      me.enqueue_(
9418ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen          [ me, me.jstProcess_, context, template.childNodes[i] ]);
9428ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen      }
9438ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    }
9448ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  }
9458ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}
9468ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
9478ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
9488ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/**
9498ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Implements the jsselect attribute: evalutes the value of the
9508ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * jsselect attribute in the current context, with the current
9518ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * variable bindings (see JsExprContext.jseval()). If the value is an
9528ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * array, the current template node is multiplied once for every
9538ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * element in the array, with the array element being the context
9548ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * object. If the array is empty, or the value is undefined, then the
9558ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * current template node is dropped. If the value is not an array,
9568ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * then it is just made the context object.
9578ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
9588ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {JsExprContext} context The current evaluation context.
9598ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
9608ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Element} template The currently processed node of the template.
9618ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
9628ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {String} select The javascript expression to evaluate.
9638ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
9648ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Function} process The function to continue processing with.
9658ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */
9668ae428e0fb7feea16d79853f29447469a93bedffKristian MonsenJstProcessor.prototype.jstSelect_ = function(context, template, select) {
9678ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  var me = this;
9688ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
9698ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  var value = context.jseval(select, template);
9708ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  domRemoveAttribute(template, ATT_select);
9718ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
9728ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  var instance = domGetAttribute(template, ATT_instance);
9738ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  var instance_last = false;
9748ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  if (instance) {
9758ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    if (instance.charAt(0) == '*') {
9768ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen      instance = parseInt10(instance.substr(1));
9778ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen      instance_last = true;
9788ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    } else {
9798ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen      instance = parseInt10(instance);
9808ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    }
9818ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  }
9828ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
9838ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  var multiple = (value !== null &&
9848ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen                  typeof value == 'object' &&
9858ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen                  typeof value.length == 'number');
9868ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  var multiple_empty = (multiple && value.length == 0);
9878ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
9888ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  if (multiple) {
9898ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    if (multiple_empty) {
9908ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen      if (!instance) {
9918ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen        domSetAttribute(template, ATT_select, select);
9928ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen        domSetAttribute(template, ATT_instance, '*0');
9938ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen        displayNone(template);
9948ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen      } else {
9958ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen        domRemoveNode(template);
9968ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen      }
9978ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
9988ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    } else {
9998ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen      displayDefault(template);
10008ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen      if (instance === null || instance === "" || instance === undefined ||
10018ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen          (instance_last && instance < jsLength(value) - 1)) {
10028ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen        var templatenodes = [];
10038ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen        var instances_start = instance || 0;
10048ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen        for (var i = instances_start + 1; i < jsLength(value); ++i) {
10058ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen          var node = domCloneNode(template);
10068ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen          templatenodes.push(node);
10078ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen          domInsertBefore(node, template);
10088ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen        }
10098ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen        templatenodes.push(template);
10108ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
10118ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen        for (var i = 0; i < jsLength(templatenodes); ++i) {
10128ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen          var ii = i + instances_start;
10138ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen          var v = value[ii];
10148ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen          var t = templatenodes[i];
10158ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
10168ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen          me.enqueue_([ me, me.jstProcess_, context.clone(v, ii), t ]);
10178ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen          var instanceStr = (ii == jsLength(value) - 1 ? '*' : '') + ii;
10188ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen          me.enqueue_(
10198ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen              [ null, postProcessMultiple_, t, select, instanceStr ]);
10208ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen        }
10218ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
10228ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen      } else if (instance < jsLength(value)) {
10238ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen        var v = value[instance];
10248ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
10258ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen        me.enqueue_(
10268ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen            [me, me.jstProcess_, context.clone(v, instance), template]);
10278ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen        var instanceStr = (instance == jsLength(value) - 1 ? '*' : '')
10288ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen                          + instance;
10298ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen        me.enqueue_(
10308ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen            [ null, postProcessMultiple_, template, select, instanceStr ]);
10318ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen      } else {
10328ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen        domRemoveNode(template);
10338ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen      }
10348ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    }
10358ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  } else {
10368ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    if (value == null) {
10378ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen      domSetAttribute(template, ATT_select, select);
10388ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen      displayNone(template);
10398ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    } else {
10408ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen      me.enqueue_(
10418ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen          [ me, me.jstProcess_, context.clone(value, 0), template ]);
10428ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen      me.enqueue_(
10438ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen          [ null, postProcessSingle_, template, select ]);
10448ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    }
10458ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  }
10468ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}
10478ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
10488ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
10498ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/**
10508ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Sets ATT_select and ATT_instance following recursion to jstProcess.
10518ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
10528ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Element} template  The template
10538ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
10548ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {String} select  The jsselect string
10558ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
10568ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {String} instanceStr  The new value for the jsinstance attribute
10578ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */
10588ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction postProcessMultiple_(template, select, instanceStr) {
10598ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  domSetAttribute(template, ATT_select, select);
10608ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  domSetAttribute(template, ATT_instance, instanceStr);
10618ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}
10628ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
10638ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
10648ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/**
10658ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Sets ATT_select and makes the element visible following recursion to
10668ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * jstProcess.
10678ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
10688ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Element} template  The template
10698ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
10708ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {String} select  The jsselect string
10718ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */
10728ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction postProcessSingle_(template, select) {
10738ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  domSetAttribute(template, ATT_select, select);
10748ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  displayDefault(template);
10758ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}
10768ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
10778ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
10788ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/**
10798ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Implements the jsvalues attribute: evaluates each of the values and
10808ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * assigns them to variables in the current context (if the name
10818ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * starts with '$', javascript properties of the current template node
10828ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * (if the name starts with '.'), or DOM attributes of the current
10838ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * template node (otherwise). Since DOM attribute values are always
10848ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * strings, the value is coerced to string in the latter case,
10858ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * otherwise it's the uncoerced javascript value.
10868ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
10878ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {JsExprContext} context Current evaluation context.
10888ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
10898ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Element} template Currently processed template node.
10908ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
10918ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {String} valuesStr Value of the jsvalues attribute to be
10928ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * processed.
10938ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */
10948ae428e0fb7feea16d79853f29447469a93bedffKristian MonsenJstProcessor.prototype.jstValues_ = function(context, template, valuesStr) {
10958ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  var values = valuesStr.split(/\s*;\s*/);
10968ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  for (var i = 0; i < jsLength(values); ++i) {
10978ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    var colon = values[i].indexOf(':');
10988ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    if (colon < 0) {
10998ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen      continue;
11008ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    }
11018ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    var label = stringTrim(values[i].substr(0, colon));
11028ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    var value = context.jseval(values[i].substr(colon + 1), template);
11038ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
11048ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    if (label.charAt(0) == '$') {
11058ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen      context.setVariable(label, value);
11068ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
11078ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    } else if (label.charAt(0) == '.') {
11088ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen      var nameSpaceLabel = label.substr(1).split('.');
11098ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen      var nameSpaceObject = template;
11108ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen      var nameSpaceDepth = jsLength(nameSpaceLabel);
11118ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen      for (var j = 0, J = nameSpaceDepth - 1; j < J; ++j) {
11128ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen        var jLabel = nameSpaceLabel[j];
11138ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen        if (!nameSpaceObject[jLabel]) {
11148ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen          nameSpaceObject[jLabel] = {};
11158ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen        }
11168ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen        nameSpaceObject = nameSpaceObject[jLabel];
11178ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen      }
11188ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen      nameSpaceObject[nameSpaceLabel[nameSpaceDepth - 1]] = value;
11198ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    } else if (label) {
11208ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen      if (typeof value == 'boolean') {
11218ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen        if (value) {
11228ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen          domSetAttribute(template, label, label);
11238ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen        } else {
11248ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen          domRemoveAttribute(template, label);
11258ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen        }
11268ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen      } else {
11278ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen        domSetAttribute(template, label, '' + value);
11288ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen      }
11298ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    }
11308ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  }
11318ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}
11328ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
11338ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
11348ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/**
11358ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Implements the jscontent attribute. Evalutes the expression in
11368ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * jscontent in the current context and with the current variables,
11378ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * and assigns its string value to the content of the current template
11388ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * node.
11398ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
11408ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {JsExprContext} context Current evaluation context.
11418ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
11428ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Element} template Currently processed template node.
11438ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
11448ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {String} content Value of the jscontent attribute to be
11458ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * processed.
11468ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */
11478ae428e0fb7feea16d79853f29447469a93bedffKristian MonsenJstProcessor.prototype.jstContent_ = function(context, template, content) {
11488ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  var value = '' + context.jseval(content, template);
11498ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  if (template.innerHTML == value) {
11508ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    return;
11518ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  }
11528ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  while (template.firstChild) {
11538ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    domRemoveNode(template.firstChild);
11548ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  }
11558ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  var t = domCreateTextNode(ownerDocument(template), value);
11568ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  domAppendChild(template, t);
11578ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}
11588ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
11598ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
11608ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/**
11618ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Helps to implement the transclude attribute, and is the initial
11628ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * call to get hold of a template from its ID.
11638ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
11648ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {String} name The ID of the HTML element used as template.
11658ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen *
11668ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @returns {Element} The DOM node of the template. (Only element
11678ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * nodes can be found by ID, hence it's a Element.)
11688ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */
11698ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction jstGetTemplate(name) {
11708ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  var section = domGetElementById(document, name);
11718ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  if (section) {
11728ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    var ret = domCloneNode(section);
11738ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    domRemoveAttribute(ret, 'id');
11748ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    return ret;
11758ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  } else {
11768ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    return null;
11778ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  }
11788ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}
11798ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
11808ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenwindow['jstGetTemplate'] = jstGetTemplate;
11818ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenwindow['jstProcess'] = jstProcess;
11828ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenwindow['JsExprContext'] = JsExprContext;
1183