/* A few useful utility functions. */ var internetExplorer = document.selection && window.ActiveXObject && /MSIE/.test(navigator.userAgent); var webkit = /AppleWebKit/.test(navigator.userAgent); // Capture a method on an object. function method(obj, name) { return function() {obj[name].apply(obj, arguments);}; } // The value used to signal the end of a sequence in iterators. var StopIteration = {toString: function() {return "StopIteration"}}; // Apply a function to each element in a sequence. function forEach(iter, f) { if (iter.next) { try {while (true) f(iter.next());} catch (e) {if (e != StopIteration) throw e;} } else { for (var i = 0; i < iter.length; i++) f(iter[i]); } } // Map a function over a sequence, producing an array of results. function map(iter, f) { var accum = []; forEach(iter, function(val) {accum.push(f(val));}); return accum; } // Create a predicate function that tests a string againsts a given // regular expression. No longer used but might be used by 3rd party // parsers. function matcher(regexp){ return function(value){return regexp.test(value);}; } // Test whether a DOM node has a certain CSS class. Much faster than // the MochiKit equivalent, for some reason. function hasClass(element, className){ var classes = element.className; return classes && new RegExp("(^| )" + className + "($| )").test(classes); } // Insert a DOM node after another node. function insertAfter(newNode, oldNode) { var parent = oldNode.parentNode; parent.insertBefore(newNode, oldNode.nextSibling); return newNode; } function removeElement(node) { if (node.parentNode) node.parentNode.removeChild(node); } function clearElement(node) { while (node.firstChild) node.removeChild(node.firstChild); } // Check whether a node is contained in another one. function isAncestor(node, child) { while (child = child.parentNode) { if (node == child) return true; } return false; } // The non-breaking space character. var nbsp = "\u00a0"; var matching = {"{": "}", "[": "]", "(": ")", "}": "{", "]": "[", ")": "("}; // Standardize a few unportable event properties. function normalizeEvent(event) { if (!event.stopPropagation) { event.stopPropagation = function() {this.cancelBubble = true;}; event.preventDefault = function() {this.returnValue = false;}; } if (!event.stop) { event.stop = function() { this.stopPropagation(); this.preventDefault(); }; } if (event.type == "keypress") { event.code = (event.charCode == null) ? event.keyCode : event.charCode; event.character = String.fromCharCode(event.code); } return event; } // Portably register event handlers. function addEventHandler(node, type, handler, removeFunc) { function wrapHandler(event) { handler(normalizeEvent(event || window.event)); } if (typeof node.addEventListener == "function") { node.addEventListener(type, wrapHandler, false); if (removeFunc) return function() {node.removeEventListener(type, wrapHandler, false);}; } else { node.attachEvent("on" + type, wrapHandler); if (removeFunc) return function() {node.detachEvent("on" + type, wrapHandler);}; } } function nodeText(node) { return node.innerText || node.textContent || node.nodeValue || ""; }