gecko/browser/base/content/tabcandy/core/iq.js

421 lines
11 KiB
JavaScript
Raw Normal View History

/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is iQ.
*
* The Initial Developer of the Original Code is
* Ian Gilman <ian@iangilman.com>.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Some portions copied from:
* jQuery JavaScript Library v1.4.2
* http://jquery.com/
* Copyright 2010, John Resig
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
* ... which includes Sizzle.js
* http://sizzlejs.com/
* Copyright 2010, The Dojo Foundation
* Released under the MIT, BSD, and GPL Licenses.
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
// ##########
// Title: iq.js
// jQuery, hacked down to just the bits we need.
(function( window, undefined ) {
var iQ = function(selector, context) {
// The iQ object is actually just the init constructor 'enhanced'
return new iQ.fn.init( selector, context );
},
// Map over iQ in case of overwrite
_iQ = window.iQ,
// Use the correct document accordingly with window argument (sandbox)
document = window.document,
// A central reference to the root iQ(document)
rootiQ,
// A simple way to check for HTML strings or ID strings
// (both of which we optimize for)
quickExpr = /^[^<]*(<[\w\W]+>)[^>]*$|^#([\w-]+)$/,
// Is it a simple selector
isSimple = /^.[^:#\[\.,]*$/,
// Check if a string has a non-whitespace character in it
rnotwhite = /\S/,
// Used for trimming whitespace
rtrim = /^(\s|\u00A0)+|(\s|\u00A0)+$/g,
// Match a standalone tag
rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>)?$/,
// Save a reference to some core methods
toString = Object.prototype.toString,
hasOwnProperty = Object.prototype.hasOwnProperty,
push = Array.prototype.push,
slice = Array.prototype.slice,
indexOf = Array.prototype.indexOf;
// ##########
// Class: iQ.fn
// An individual element or group of elements.
iQ.fn = iQ.prototype = {
// ----------
// Function: init
init: function( selector, context ) {
return null; // TODO: this routine not ready yet
var match, elem, ret, doc;
// Handle $(""), $(null), or $(undefined)
if ( !selector ) {
return this;
}
// Handle $(DOMElement)
if ( selector.nodeType ) {
this.context = this[0] = selector;
this.length = 1;
return this;
}
// The body element only exists once, optimize finding it
if ( selector === "body" && !context ) {
this.context = document;
this[0] = document.body;
this.selector = "body";
this.length = 1;
return this;
}
// Handle HTML strings
if ( typeof selector === "string" ) {
// Are we dealing with HTML string or an ID?
match = quickExpr.exec( selector );
// Verify a match, and that no context was specified for #id
if ( match && (match[1] || !context) ) {
// HANDLE: $(html) -> $(array)
if ( match[1] ) {
doc = (context ? context.ownerDocument || context : document);
// If a single string is passed in and it's a single tag
// just do a createElement and skip the rest
ret = rsingleTag.exec( selector );
if ( ret ) {
if ( iQ.isPlainObject( context ) ) {
selector = [ document.createElement( ret[1] ) ];
/* iQ.fn.attr.call( selector, context, true ); */
} else {
selector = [ doc.createElement( ret[1] ) ];
}
} else {
/* ret = doc.createDocumentFragment([match */
ret = buildFragment( [ match[1] ], [ doc ] );
selector = (ret.cacheable ? ret.fragment.cloneNode(true) : ret.fragment).childNodes;
}
return iQ.merge( this, selector );
// HANDLE: $("#id")
} else {
elem = document.getElementById( match[2] );
if ( elem ) {
// Handle the case where IE and Opera return items
// by name instead of ID
if ( elem.id !== match[2] ) {
return rootiQ.find( selector );
}
// Otherwise, we inject the element directly into the iQ object
this.length = 1;
this[0] = elem;
}
this.context = document;
this.selector = selector;
return this;
}
// HANDLE: $("TAG")
} else if ( !context && /^\w+$/.test( selector ) ) {
this.selector = selector;
this.context = document;
selector = document.getElementsByTagName( selector );
return iQ.merge( this, selector );
// HANDLE: $(expr, $(...))
} else if ( !context || context.iq ) {
return (context || rootiQ).find( selector );
// HANDLE: $(expr, context)
// (which is just equivalent to: $(context).find(expr)
} else {
return iQ( context ).find( selector );
}
// HANDLE: $(function)
// Shortcut for document ready
} else if ( iQ.isFunction( selector ) ) {
Utils.log('iQ does not support ready functions');
return null;
}
if (selector.selector !== undefined) {
this.selector = selector.selector;
this.context = selector.context;
}
return iQ.makeArray( selector, this );
},
// Start with an empty selector
selector: "",
// The current version of iQ being used
iq: "1.4.2",
// The default length of a iQ object is 0
length: 0
};
// ----------
// Give the init function the iQ prototype for later instantiation
iQ.fn.init.prototype = iQ.fn;
// ----------
// Function: extend
iQ.extend = iQ.fn.extend = function() {
// copy reference to target object
var target = arguments[0] || {}, i = 1, length = arguments.length, deep = false, options, name, src, copy;
// Handle a deep copy situation
if ( typeof target === "boolean" ) {
deep = target;
target = arguments[1] || {};
// skip the boolean and the target
i = 2;
}
// Handle case when target is a string or something (possible in deep copy)
if ( typeof target !== "object" && !iQ.isFunction(target) ) {
target = {};
}
// extend iQ itself if only one argument is passed
if ( length === i ) {
target = this;
--i;
}
for ( ; i < length; i++ ) {
// Only deal with non-null/undefined values
if ( (options = arguments[ i ]) != null ) {
// Extend the base object
for ( name in options ) {
src = target[ name ];
copy = options[ name ];
// Prevent never-ending loop
if ( target === copy ) {
continue;
}
// Recurse if we're merging object literal values or arrays
if ( deep && copy && ( iQ.isPlainObject(copy) || iQ.isArray(copy) ) ) {
var clone = src && ( iQ.isPlainObject(src) || iQ.isArray(src) ) ? src
: iQ.isArray(copy) ? [] : {};
// Never move original objects, clone them
target[ name ] = iQ.extend( deep, clone, copy );
// Don't bring in undefined values
} else if ( copy !== undefined ) {
target[ name ] = copy;
}
}
}
}
// Return the modified object
return target;
};
// ##########
// Class: iQ
// Singleton
iQ.extend({
// -----------
// Function: isFunction
// See test/unit/core.js for details concerning isFunction.
// Since version 1.3, DOM methods and functions like alert
// aren't supported. They return false on IE (#2968).
isFunction: function( obj ) {
return toString.call(obj) === "[object Function]";
},
// ----------
// Function: isArray
isArray: function( obj ) {
return toString.call(obj) === "[object Array]";
},
// ----------
// Function: isPlainObject
isPlainObject: function( obj ) {
// Must be an Object.
// Because of IE, we also have to check the presence of the constructor property.
// Make sure that DOM nodes and window objects don't pass through, as well
if ( !obj || toString.call(obj) !== "[object Object]" || obj.nodeType || obj.setInterval ) {
return false;
}
// Not own constructor property must be Object
if ( obj.constructor
&& !hasOwnProperty.call(obj, "constructor")
&& !hasOwnProperty.call(obj.constructor.prototype, "isPrototypeOf") ) {
return false;
}
// Own properties are enumerated firstly, so to speed up,
// if last one is own, then all properties are own.
var key;
for ( key in obj ) {}
return key === undefined || hasOwnProperty.call( obj, key );
},
// ----------
// Function: isEmptyObject
isEmptyObject: function( obj ) {
for ( var name in obj ) {
return false;
}
return true;
},
// ----------
// Function: merge
merge: function( first, second ) {
var i = first.length, j = 0;
if ( typeof second.length === "number" ) {
for ( var l = second.length; j < l; j++ ) {
first[ i++ ] = second[ j ];
}
} else {
while ( second[j] !== undefined ) {
first[ i++ ] = second[ j++ ];
}
}
first.length = i;
return first;
},
// ----------
// Function: grep
grep: function( elems, callback, inv ) {
var ret = [];
// Go through the array, only saving the items
// that pass the validator function
for ( var i = 0, length = elems.length; i < length; i++ ) {
if ( !inv !== !callback( elems[ i ], i ) ) {
ret.push( elems[ i ] );
}
}
return ret;
},
// ----------
// Function: each
// args is for internal usage only
each: function( object, callback, args ) {
var name, i = 0,
length = object.length,
isObj = length === undefined || iQ.isFunction(object);
if ( args ) {
if ( isObj ) {
for ( name in object ) {
if ( callback.apply( object[ name ], args ) === false ) {
break;
}
}
} else {
for ( ; i < length; ) {
if ( callback.apply( object[ i++ ], args ) === false ) {
break;
}
}
}
// A special, fast, case for the most common use of each
} else {
if ( isObj ) {
for ( name in object ) {
if ( callback.call( object[ name ], name, object[ name ] ) === false ) {
break;
}
}
} else {
for ( var value = object[0];
i < length && callback.call( value, i, value ) !== false; value = object[++i] ) {}
}
}
return object;
}
});
// ----------
// All iQ objects should point back to these
rootiQ = iQ(document);
// ----------
// Expose iQ to the global object
window.iQ = iQ;
})(window);