var _assert = function (expr) { if (!expr) { var message = "_assert(" + expr + ")"; alert(message); throw message; } } // Compatibility {{{ if (typeof Array.prototype.push != "function") Array.prototype.push = function (value) { this[this.length] = value; }; // }}} var $ = function (arg, doc) { if (this.magic_ != $.prototype.magic_) return new $(arg); var type = $.type(arg); if (type == "function") $.ready(arg); else if (type == "string") { if (doc == undefined) doc = document; if (arg.charAt(0) == '#') { var node = doc.getElementById(arg.substring(1)); return $(node == null ? [] : [node]); } else if (arg.charAt(0) == '.') { var nodes = doc.getElementsByClassName(arg.substring(1)); return $(nodes == null ? [] : nodes); } else return $([doc]).descendants(arg); } else { _assert(doc == undefined); this.set($.array(arg)); return this; } }; $.xml = function (value) { return value .replace(/&/, "&") .replace(//, ">") .replace(/"/, """) .replace(/'/, "'") ; } $.type = function (value) { var type = typeof value; if ( type == "function" && value.toString != null && value.toString().substring(0, 8) == "[object " ) return "object"; else return type; }; (function () { var ready_ = null; $.ready = function (_function) { if (ready_ == null) { ready_ = []; document.addEventListener("DOMContentLoaded", function () { for (var i = 0; i != ready_.length; ++i) ready_[i](); }, false); } ready_.push(_function); }; })(); /* XXX: verify arg3 overflow */ $.each = function (values, _function, arg0, arg1, arg2) { for (var i = 0, e = values.length; i != e; ++i) _function(values[i], arg0, arg1, arg2); }; /* XXX: verify arg3 overflow */ $.map = function (values, _function, arg0, arg1, arg2) { var mapped = []; for (var i = 0, e = values.length; i != e; ++i) mapped.push(_function(values[i], arg0, arg1, arg2)); return mapped; }; $.array = function (values) { if (values.constructor == Array) return values; var array = []; for (var i = 0; i != values.length; ++i) array.push(values[i]); return array; }; $.document = function (node) { for (;;) { var parent = node.parentNode; if (parent == null) return node; node = parent; } }; $.prototype = { magic_: 2041085062, add: function (nodes) { Array.prototype.push.apply(this, nodes); }, set: function (nodes) { this.length = 0; this.add(nodes); }, css: function (name, value) { $.each(this, function (node) { node.style[name] = value; }); }, append: function (html) { $.each(this, $.type(html) == "string" ? function (node) { var doc = $.document(node); // XXX: implement wrapper system var div = doc.createElement("div"); div.innerHTML = html; while (div.childNodes.length != 0) { var child = div.childNodes[0]; node.appendChild(child); } } : function (node) { $.each(html, function (value) { node.appendChild(value); }); }); }, clone: function (deep) { return $($.map(this, function (node) { return node.cloneNode(deep); })); }, descendants: function (expression) { var descendants = $([]); $.each(this, function (node) { descendants.add(node.getElementsByTagName(expression)); }); return descendants; }, remove: function () { $.each(this, function (node) { node.parentNode.removeChild(node); }); }, parent: function () { return $($.map(this, function (node) { return node.parentNode; })); }, xpath: function (expression) { var value = $([]); $.each(this, function (node) { var doc = $.document(node); var result = doc.evaluate(expression, node, null, XPathResult.ANY_TYPE, null); if (result.resultType == XPathResult.UNORDERED_NODE_ITERATOR_TYPE) for (;;) { var next = result.iterateNext(); if (next == null) break; value.add([next]); } }); return value; } }; $.scroll = function (x, y) { window.scrollTo(x, y); }; // XXX: document.all? $.all = function (doc) { if (doc == undefined) doc = document; return $(doc.getElementsByTagName("*")); }; $.inject = function (a, b) { if ($.type(a) == "string") { $.prototype[a] = function (value) { if (value == undefined) return $.map(this, function (node) { return b.get(node); }); else $.each(this, function (node, value) { b.set(node, value); }, value); }; } else for (var name in a) $.inject(name, a[name]); }; $.inject({ display: { get: function (node) { return node.style.display; }, set: function (node, value) { node.style.display = value; } }, html: { get: function (node) { return node.innerHTML; }, set: function (node, value) { node.innerHTML = value; } }, href: { get: function (node) { return node.href; }, set: function (node, value) { node.href = value; } }, id: { get: function (node) { return node.id; }, set: function (node, value) { node.id = value; } }, src: { get: function (node) { return node.src; }, set: function (node, value) { node.src = value; } }, value: { get: function (node) { return node.value; }, set: function (node, value) { node.value = value; } } }); // Event Registration {{{ // XXX: unable to remove registration $.prototype.event = function (event, _function) { $.each(this, function (node) { // XXX: smooth over this pointer ugliness if (node.addEventListener) node.addEventListener(event, _function, false); else if (node.attachEvent) node.attachEvent("on" + event, _function); else // XXX: multiple registration SNAFU node["on" + event] = _function; }); }; $.each([ "click", "load", "submit" ], function (event) { $.prototype[event] = function (_function) { if (_function == undefined) _assert(false); else this.event(event, _function); }; }); // }}} // Timed Animation {{{ $.interpolate = function (duration, event) { var start = new Date(); var next = function () { setTimeout(update, 0); }; var update = function () { var time = new Date() - start; if (time >= duration) event(1); else { event(time / duration); next(); } }; next(); }; // }}} // AJAX Requests {{{ // XXX: abstract and implement other cases $.xhr = function (url, method, headers, data, events) { var xhr = new XMLHttpRequest(); xhr.open(method, url, true); for (var name in headers) xhr.setRequestHeader(name.replace(/_/, "-"), headers[name]); if (events == null) events = {}; xhr.onreadystatechange = function () { if (xhr.readyState == 4) if (events.complete != null) events.complete(xhr.responseText); }; xhr.send(data); }; $.call = function (url, post, onsuccess) { var events = {}; if (onsuccess != null) events.complete = function (text) { onsuccess(eval(text)); }; if (post == null) $.xhr(url, "POST", null, null, events); else $.xhr(url, "POST", { Content_Type: "application/json" }, $.json(post), events); }; // }}} // WWW Form URL Encoder {{{ $.form = function (parameters) { var data = ""; var ampersand = false; for (var name in parameters) { if (!ampersand) ampersand = true; else data += "&"; var value = parameters[name]; data += escape(name); data += "="; data += escape(value); } return data; }; // }}} // JSON Serializer {{{ $.json = function (value) { if (value == null) return "null"; var type = $.type(value); if (type == "number") return value; else if (type == "string") return "\"" + value .replace(/\\/, "\\\\") .replace(/\t/, "\\t") .replace(/\r/, "\\r") .replace(/\n/, "\\n") .replace(/"/, "\\\"") + "\""; else if (value.constructor == Array) { var json = "["; var comma = false; for (var i = 0; i != value.length; ++i) { if (!comma) comma = true; else json += ","; json += $.json(value[i]); } return json + "]"; } else if ( value.constructor == Object && value.toString() == "[object Object]" ) { var json = "{"; var comma = false; for (var name in value) { if (!comma) comma = true; else json += ","; json += name + ":" + $.json(value[name]); } return json + "}"; } else { return value; } }; // }}}