/****************************************************************************** Bija - Javascript Library and Framework [B]ija [I]sn't [J]ust [A]jax @author: Matan Lurey @version: 1.1a @projectDescription: Bija is a multi-use, cross-browser JavaScript library which enables the use of advanced DOM and Networking techniques on a variety of systems. The reason that something like Mootools or Prototype is not used is to allow only the most efficient and needed code to be available. Fully Supported: - Firefox 2.0 (Gecko) - Netscape (Gecko) - Safari 3 (WebKit 420) - Opera 9 Fully Supported with Work-Arounds: - Konqueror (Interval-Based checking of Comet data) Untested, but Compatible: - Safari 2 (However, uses Konqueror's method of 'push' data) Pending Tests: - Internet Explorer 5.5 - Internet Explorer 6 - Internet Explorer 7 *******************************************************************************/ window.Bija = { version: "1.10a" } /** Browser Detection - Tries a non-sniffing method, if possible. *************/ var Browser = { ie7: (document.all && !window.opera && window.XMLHttpRequest), ie6: (document.all && !window.opera && !window.XMLHttpRequest), ie5: (document.all && !window.opera && document.appendData), ie: (document.all && !window.opera), webkit: (document.childNodes && !document.all && !navigator.taintEnabled), khtml: (navigator.userAgent.indexOf('Konqueror' != -1)), gecko: (!!document.getBoxObjectFor), opera: (!!window.opera) } // Detect WebKit 420 (Safari 3 Beta) ------------------------------------------- Browser.webkit420 = (Browser.webkit && document.evaluate); /** Class Prototyping - A new face for JavaScript OOP Ideas from Prototype, Base, and Mootools Creating a Class: new Class( ) Extending a Class: Class.Extend( ) Creating an Interface: new Interface( arguments = method names ) Implementing an Interface: myClass.Implement( ) Extending a Class Object: myClass.Extend( ) */ /****************************************************************************** function: Extend @param: destination [object] the object to copy methods to @param: source [object] the object to copy methods from @return: Object *******************************************************************************/ function Extend(destination, source) { if (!source && this) return Extend(this, destination); var safeWrite = (arguments.length > 1); for (method in source) if (!safeWrite || !destination[method]) destination[method] = source[method]; return destination; } /****************************************************************************** function: Implement @param: object [object] the object to try the interface's methods on @param: iface [Interface] the Interface object @return: Object *******************************************************************************/ function Implement(object, iface) { if (!iface && this) return Impelement(this, object); for (var i = 0; i < iface.length; i++) if (!isFunction(object[iface[i]]) && !isFunction(object.prototype[iface[i]])) throw new Error("Object does not implement method Object." + iface[i]); return object; } // Interfaces are constructed, and are identical to, Arrays -------------------- var Interface = Array; /****************************************************************************** object: Class @constructor: @param: methods [object] the object to copy methods from @return: Class *******************************************************************************/ function Class(methods) { var Klass = Class.Empty(); Extend(Klass.prototype, methods); return Klass; } /****************************************************************************** object: Class.Extend @constructor: @param: object [class] the base class (parent class) @param: methods [object] the object to copy methods from @return: Class *******************************************************************************/ Extend(Class, { Extend: function(object, methods) { var Klass = Class.Empty(); Klass.prototype.Super = Klass.prototype = object.prototype; Extend(Klass.prototype, object); return Klass; }, // Internally Used Function to Create a new 'Class' ---------------------------- Empty: function() { return function() { if (isFunction(this.init)) { this.init.apply(this, arguments); } } } }); /****************************************************************************** object: Abstract @constructor: @param: object [object] the object to give an abstract to, allowing it to be extended @return: Object *******************************************************************************/ function Abstract(object) { object.Extend = Extend; return object; } /** END CLASS PROTOTYPING *****************************************************/ /** START UTILITY FUNCTIONS Utility functions are basic functions used throughout to speed up or improve the usage of common tasks. */ /****************************************************************************** function: $ @param: el [element id] Reads an element from the document DOM, by Id name. We make sure the HTMLElement inherits HTMLElement.prototype. If it didn't, it means that we cant extend the DOM, and have to inherit it on demand (IE). @return: HTMLElement *******************************************************************************/ function $(el) { el = document.getElementById(el); if (!el) return null; if (!el.Bija) $e(el); return el; } /****************************************************************************** function: $a @param: collection [collection] the object to convert to an Array object, to allow usage of it's methods. @return: Array *******************************************************************************/ function $a(collection) { if (!collection) return []; var arr = (collection.length > 1) ? Array.prototype.slice.call(collection, 0) : [ collection[0] ]; return arr; } /****************************************************************************** function: $e @param: HTMLElement the htmlelemnt to inherit bija's dom extensions. @return: HTMLElement *******************************************************************************/ function $e(htmlobject) { return (htmlobject.Bija) ? htmlobject : Extend(htmlobject, Element.methods); } function $element(tag) { return $e(document.createElement(tag)); } /****************************************************************************** function: $Time Generatese a Unix Timestamp @return: Integer *******************************************************************************/ function $time() { return (new Date).getTime(); } // isType functions ----------------------------------------------------------- function isArray(obj) {return (!!obj.sort);} function isFunction(obj) {return (typeof obj == "function");} function isString(obj) {return (typeof obj == "string");} function isObject(obj) {return (typeof obj == "object");} /** END UTILITY FUNCTIONS *****************************************************/ /** START NATIVE EXTENSIONS We give several native objects additional functionality, or implement functionality not yet available in their version of ECMAScript */ /****************************************************************************** function: $Native @param: Arguments being Native objects *******************************************************************************/ function $Native() { var a = arguments; for (var i = 0; i < a.length; i++) a[i].extend = $Native.Extend; } // Internally Used, Special Extend Event for Native Objects ------------------- $Native.Extend = function(methods){ for (method in methods) if (!isFunction(this.prototype[method])) this.prototype[method] = methods[method]; } // Give .Extend to all objects ------------------------------------------------ $Native(Function, String, Array, Number); /** FUNCTION - Extended *******************************************************/ Function.extend({ // Extend Functionality extend: Extend, // Implement Functionality implement: Implement, // Delayed Execution delay: function(ms) { setTimeout(function() { this.apply(this, $a(arguments).remove(0)) }, ms); } }); /** ARRAY - Extended **********************************************************/ Array.extend({ // Get an item using a method item: function(index) { return this[index]; }, // Remove an Item remove: function(index) { this.splice(index, 1); return this; }, // Enumerates through All forEach: function(callback) { var l = this.length; for (var i = 0; i < l; i++) callback(this[i]); return this; } }) // Compatibility / Easy Access -------------------------------------------------- Array.prototype.each = Array.prototype.forEach; /** STRING - Extended **********************************************************/ String.extend({ // Contains another string contains: function(string) { return (this.indexOf(string) != -1); } }); /** ELEMENT - Extended *********************************************************/ // Special for Cross Browser :( // Expose Safari's Prototypes --------------------------------------------------- if (window.webkit && !window.webkit420) { window.Document = {} window.Event = {} window.HTMLCollection = {} window.HTMLElement = {} window.Node = {} window.Document.prototype = window["[[DOMDocument]]"]; window.Event.prototype = window["[[DOMEvent]]"]; window.HTMLCollection.prototype = window["[[HTMLCollection.prototype]]"]; window.HTMLElement.prototype = window["[[DOMElement.prototype]]"]; window.Node.prototype = window["[[DOMNode.prototype]]"]; } // Allow IE to manually extend ------------------------------------------------- var Element = { extend: function(methods) { if (!Browser.ie) return Extend(HTMLElement.prototype, methods); Extend(Element.methods, methods); }, methods: {} } // ELEMENT - Extended *********************************************************** Element.extend({ hide: function() { this.style.display = "none"; return this; }, show: function() { this.style.display = ""; return this; }, inject: function(el) { var el = el || document.body; el.appendChild(this); return this; }, remove: function() { this.parentNode.removeChild(this); } }); /** Generate Document.Head for Inserting Scripts and Styles ********************/ document.head = document.getElementsByTagName("head").item(0); /******************************************************************************* 'Class': Events Passes a new set of events to another object, used like "abstract" Events(object); or Events(object.prototype); Remeber, when "watching" HTMLElement events (click etc..), the first object returned is the EVENT object (e). ********************************************************************************/ function Events(object) { // More than one object? if (arguments.length > 1) { for (var i = 0; i < arguments.length; i++) Events(arguments[i]); return this; } return Extend(object, { events: [], fire: function(id) { if (!this.events[id]) return this; // Fire's an event - return a literal of 'true' to block future events from accessing // or return an object with a parameter of modargs: true to change the arguments reciveved var args = $a(arguments).remove(0); for (var i = 0; i < this.events[id].length; i++) { var result = this.events[id][i].apply(this, args); if (result){ if (result == true) return this; if (isArray(result)) args = result; } } return this; }, observe: function(id, callback, top) { if (!isString(id)) return this.observeAll(id); var Self = this; // Does it already exist? if (!this.events[id]) { // No, check for DOM-needed. if (this.addEventListener) { this.addEventListener(id, function(e) { if (!e) var e = window.event; Self.fire(id, e); }, false); } else if (this.attachEvent) { this.attachEvent("on"+id, function(e) { if (!e) var e = window.event; // Use the same property for all browsers e.target = e.target || e.srcElement; e.relatedTarget = e.relatedTarget || e.fromElement || e.toElement; e.stopPropogation = function() { e.cancelBubble = true; } Self.fire(id, e); }); } else { // No, this isn't a DOM object. Do nothing. } // Setup default data this.events[id] = [ callback ]; return this; } // No, add it (top or bottom) if (!top) this.events[id].push(callback); else this.events[id].unshift(callback); return this; }, observeAll: function() { for (id in obj) this.watch(id, obj[id]); return this; } }); } // Give Events to Window (watch load, for example) ------------------------------------------ Events(window); // Also give a DOMReady functional callback ------------------------------------------------- // window.observe("DOMContentLoaded") -- works natively for mozilla/opera, lets fix others // webkit, interval-based with document.readyState ------------------------------------------ if (Browser.webkit) { // Interval based checking var _timer = setInterval(function(){ if (/loaded|complete/.test(document.readyState)) { clearInterval(_timer); window.fire("DOMContentLoaded"); } }, 10); } // ie, 'defered' blank javascript ----------------------------------------------------------- if (Browser.ie) { document.write("