2010-05-02 23:33:17 +00:00
|
|
|
/* A few useful utility functions. */
|
|
|
|
|
|
|
|
// 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);};
|
|
|
|
}
|
|
|
|
|
2011-01-12 15:54:09 +00:00
|
|
|
// Test whether a DOM node has a certain CSS class.
|
|
|
|
function hasClass(element, className) {
|
2010-05-02 23:33:17 +00:00
|
|
|
var classes = element.className;
|
|
|
|
return classes && new RegExp("(^| )" + className + "($| )").test(classes);
|
|
|
|
}
|
2011-01-12 15:54:09 +00:00
|
|
|
function removeClass(element, className) {
|
|
|
|
element.className = element.className.replace(new RegExp(" " + className + "\\b", "g"), "");
|
|
|
|
return element;
|
|
|
|
}
|
2010-05-02 23:33:17 +00:00
|
|
|
|
|
|
|
// 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) {
|
2010-06-02 00:39:05 +00:00
|
|
|
return node.textContent || node.innerText || node.nodeValue || "";
|
2010-05-02 23:33:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function nodeTop(node) {
|
|
|
|
var top = 0;
|
|
|
|
while (node.offsetParent) {
|
|
|
|
top += node.offsetTop;
|
|
|
|
node = node.offsetParent;
|
|
|
|
}
|
|
|
|
return top;
|
|
|
|
}
|
2010-06-02 00:39:05 +00:00
|
|
|
|
|
|
|
function isBR(node) {
|
|
|
|
var nn = node.nodeName;
|
|
|
|
return nn == "BR" || nn == "br";
|
|
|
|
}
|
|
|
|
function isSpan(node) {
|
|
|
|
var nn = node.nodeName;
|
|
|
|
return nn == "SPAN" || nn == "span";
|
|
|
|
}
|