mirror of
https://github.com/Hopiu/angular.js.git
synced 2026-03-17 07:40:22 +00:00
733 lines
21 KiB
JavaScript
733 lines
21 KiB
JavaScript
'use strict';
|
|
|
|
//////////////////////////////////
|
|
//JQLite
|
|
//////////////////////////////////
|
|
|
|
/**
|
|
* @ngdoc function
|
|
* @name angular.element
|
|
* @function
|
|
*
|
|
* @description
|
|
* Wraps a raw DOM element or HTML string as a [jQuery](http://jquery.com) element.
|
|
* `angular.element` can be either an alias for [jQuery](http://api.jquery.com/jQuery/) function, if
|
|
* jQuery is available, or a function that wraps the element or string in Angular's jQuery lite
|
|
* implementation (commonly referred to as jqLite).
|
|
*
|
|
* Real jQuery always takes precedence over jqLite, provided it was loaded before `DOMContentLoaded`
|
|
* event fired.
|
|
*
|
|
* jqLite is a tiny, API-compatible subset of jQuery that allows
|
|
* Angular to manipulate the DOM. jqLite implements only the most commonly needed functionality
|
|
* within a very small footprint, so only a subset of the jQuery API - methods, arguments and
|
|
* invocation styles - are supported.
|
|
*
|
|
* Note: All element references in Angular are always wrapped with jQuery or jqLite; they are never
|
|
* raw DOM references.
|
|
*
|
|
* ## Angular's jQuery lite provides the following methods:
|
|
*
|
|
* - [addClass()](http://api.jquery.com/addClass/)
|
|
* - [after()](http://api.jquery.com/after/)
|
|
* - [append()](http://api.jquery.com/append/)
|
|
* - [attr()](http://api.jquery.com/attr/)
|
|
* - [bind()](http://api.jquery.com/bind/)
|
|
* - [children()](http://api.jquery.com/children/)
|
|
* - [clone()](http://api.jquery.com/clone/)
|
|
* - [contents()](http://api.jquery.com/contents/)
|
|
* - [css()](http://api.jquery.com/css/)
|
|
* - [data()](http://api.jquery.com/data/)
|
|
* - [eq()](http://api.jquery.com/eq/)
|
|
* - [find()](http://api.jquery.com/find/) - Limited to lookups by tag name.
|
|
* - [hasClass()](http://api.jquery.com/hasClass/)
|
|
* - [html()](http://api.jquery.com/html/)
|
|
* - [next()](http://api.jquery.com/next/)
|
|
* - [parent()](http://api.jquery.com/parent/)
|
|
* - [prepend()](http://api.jquery.com/prepend/)
|
|
* - [prop()](http://api.jquery.com/prop/)
|
|
* - [ready()](http://api.jquery.com/ready/)
|
|
* - [remove()](http://api.jquery.com/remove/)
|
|
* - [removeAttr()](http://api.jquery.com/removeAttr/)
|
|
* - [removeClass()](http://api.jquery.com/removeClass/)
|
|
* - [removeData()](http://api.jquery.com/removeData/)
|
|
* - [replaceWith()](http://api.jquery.com/replaceWith/)
|
|
* - [text()](http://api.jquery.com/text/)
|
|
* - [toggleClass()](http://api.jquery.com/toggleClass/)
|
|
* - [unbind()](http://api.jquery.com/unbind/)
|
|
* - [val()](http://api.jquery.com/val/)
|
|
* - [wrap()](http://api.jquery.com/wrap/)
|
|
*
|
|
* ## In addtion to the above, Angular privides an additional method to both jQuery and jQuery lite:
|
|
*
|
|
* - `controller(name)` - retrieves the controller of the current element or its parent. By default
|
|
* retrieves controller associated with the `ngController` directive. If `name` is provided as
|
|
* camelCase directive name, then the controller for this directive will be retrieved (e.g.
|
|
* `'ngModel'`).
|
|
* - `injector()` - retrieves the injector of the current element or its parent.
|
|
* - `scope()` - retrieves the {@link api/angular.module.ng.$rootScope.Scope scope} of the current
|
|
* element or its parent.
|
|
* - `inheritedData()` - same as `data()`, but walks up the DOM until a value is found or the top
|
|
* parent element is reached.
|
|
*
|
|
* @param {string|DOMElement} element HTML string or DOMElement to be wrapped into jQuery.
|
|
* @returns {Object} jQuery object.
|
|
*/
|
|
|
|
var jqCache = {},
|
|
jqName = 'ng-' + new Date().getTime(),
|
|
jqId = 1,
|
|
addEventListenerFn = (window.document.addEventListener
|
|
? function(element, type, fn) {element.addEventListener(type, fn, false);}
|
|
: function(element, type, fn) {element.attachEvent('on' + type, fn);}),
|
|
removeEventListenerFn = (window.document.removeEventListener
|
|
? function(element, type, fn) {element.removeEventListener(type, fn, false); }
|
|
: function(element, type, fn) {element.detachEvent('on' + type, fn); });
|
|
|
|
function jqNextId() { return (jqId++); }
|
|
|
|
|
|
function getStyle(element) {
|
|
var current = {}, style = element[0].style, value, name, i;
|
|
if (typeof style.length == 'number') {
|
|
for(i = 0; i < style.length; i++) {
|
|
name = style[i];
|
|
current[name] = style[name];
|
|
}
|
|
} else {
|
|
for (name in style) {
|
|
value = style[name];
|
|
if (1*name != name && name != 'cssText' && value && typeof value == 'string' && value !='false')
|
|
current[name] = value;
|
|
}
|
|
}
|
|
return current;
|
|
}
|
|
|
|
|
|
var SPECIAL_CHARS_REGEXP = /([\:\-\_]+(.))/g;
|
|
var MOZ_HACK_REGEXP = /^moz([A-Z])/;
|
|
|
|
/**
|
|
* Converts snake_case to camelCase.
|
|
* Also there is special case for Moz prefix starting with upper case letter.
|
|
* @param name Name to normalize
|
|
*/
|
|
function camelCase(name) {
|
|
return name.
|
|
replace(SPECIAL_CHARS_REGEXP, function(_, separator, letter, offset) {
|
|
return offset ? letter.toUpperCase() : letter;
|
|
}).
|
|
replace(MOZ_HACK_REGEXP, 'Moz$1');
|
|
}
|
|
|
|
/////////////////////////////////////////////
|
|
// jQuery mutation patch
|
|
//
|
|
// In conjunction with bindJQuery intercepts all jQuery's DOM destruction apis and fires a
|
|
// $destroy event on all DOM nodes being removed.
|
|
//
|
|
/////////////////////////////////////////////
|
|
|
|
function JQLitePatchJQueryRemove(name, dispatchThis) {
|
|
var originalJqFn = jQuery.fn[name];
|
|
originalJqFn = originalJqFn.$original || originalJqFn;
|
|
removePatch.$original = originalJqFn;
|
|
jQuery.fn[name] = removePatch;
|
|
|
|
function removePatch() {
|
|
var list = [this],
|
|
fireEvent = dispatchThis,
|
|
set, setIndex, setLength,
|
|
element, childIndex, childLength, children,
|
|
fns, data;
|
|
|
|
while(list.length) {
|
|
set = list.shift();
|
|
for(setIndex = 0, setLength = set.length; setIndex < setLength; setIndex++) {
|
|
element = jqLite(set[setIndex]);
|
|
if (fireEvent) {
|
|
data = element.data('events');
|
|
if ( (fns = data && data.$destroy) ) {
|
|
forEach(fns, function(fn){
|
|
fn.handler();
|
|
});
|
|
}
|
|
} else {
|
|
fireEvent = !fireEvent;
|
|
}
|
|
for(childIndex = 0, childLength = (children = element.children()).length;
|
|
childIndex < childLength;
|
|
childIndex++) {
|
|
list.push(jQuery(children[childIndex]));
|
|
}
|
|
}
|
|
}
|
|
return originalJqFn.apply(this, arguments);
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////
|
|
function JQLite(element) {
|
|
if (element instanceof JQLite) {
|
|
return element;
|
|
}
|
|
if (!(this instanceof JQLite)) {
|
|
if (isString(element) && element.charAt(0) != '<') {
|
|
throw Error('selectors not implemented');
|
|
}
|
|
return new JQLite(element);
|
|
}
|
|
|
|
if (isString(element)) {
|
|
var div = document.createElement('div');
|
|
// Read about the NoScope elements here:
|
|
// http://msdn.microsoft.com/en-us/library/ms533897(VS.85).aspx
|
|
div.innerHTML = '<div> </div>' + element; // IE insanity to make NoScope elements work!
|
|
div.removeChild(div.firstChild); // remove the superfluous div
|
|
JQLiteAddNodes(this, div.childNodes);
|
|
this.remove(); // detach the elements from the temporary DOM div.
|
|
} else {
|
|
JQLiteAddNodes(this, element);
|
|
}
|
|
}
|
|
|
|
function JQLiteClone(element) {
|
|
return element.cloneNode(true);
|
|
}
|
|
|
|
function JQLiteDealoc(element){
|
|
JQLiteRemoveData(element);
|
|
for ( var i = 0, children = element.childNodes || []; i < children.length; i++) {
|
|
JQLiteDealoc(children[i]);
|
|
}
|
|
}
|
|
|
|
function JQLiteRemoveData(element) {
|
|
var cacheId = element[jqName],
|
|
cache = jqCache[cacheId];
|
|
if (cache) {
|
|
if (cache.bind) {
|
|
forEach(cache.bind, function(fn, type){
|
|
if (type == '$destroy') {
|
|
fn({});
|
|
} else {
|
|
removeEventListenerFn(element, type, fn);
|
|
}
|
|
});
|
|
}
|
|
delete jqCache[cacheId];
|
|
element[jqName] = undefined; // ie does not allow deletion of attributes on elements.
|
|
}
|
|
}
|
|
|
|
function JQLiteData(element, key, value) {
|
|
var cacheId = element[jqName],
|
|
cache = jqCache[cacheId || -1];
|
|
if (isDefined(value)) {
|
|
if (!cache) {
|
|
element[jqName] = cacheId = jqNextId();
|
|
cache = jqCache[cacheId] = {};
|
|
}
|
|
cache[key] = value;
|
|
} else {
|
|
return cache ? cache[key] : null;
|
|
}
|
|
}
|
|
|
|
function JQLiteHasClass(element, selector) {
|
|
return ((" " + element.className + " ").replace(/[\n\t]/g, " ").
|
|
indexOf( " " + selector + " " ) > -1);
|
|
}
|
|
|
|
function JQLiteRemoveClass(element, selector) {
|
|
if (selector) {
|
|
forEach(selector.split(' '), function(cssClass) {
|
|
element.className = trim(
|
|
(" " + element.className + " ")
|
|
.replace(/[\n\t]/g, " ")
|
|
.replace(" " + trim(cssClass) + " ", " ")
|
|
);
|
|
});
|
|
}
|
|
}
|
|
|
|
function JQLiteAddClass(element, selector) {
|
|
if (selector) {
|
|
forEach(selector.split(' '), function(cssClass) {
|
|
if (!JQLiteHasClass(element, cssClass)) {
|
|
element.className = trim(element.className + ' ' + trim(cssClass));
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
function JQLiteAddNodes(root, elements) {
|
|
if (elements) {
|
|
elements = (!elements.nodeName && isDefined(elements.length) && !isWindow(elements))
|
|
? elements
|
|
: [ elements ];
|
|
for(var i=0; i < elements.length; i++) {
|
|
root.push(elements[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
function JQLiteController(element, name) {
|
|
return JQLiteInheritedData(element, '$' + (name || 'ngController' ) + 'Controller');
|
|
}
|
|
|
|
function JQLiteInheritedData(element, name, value) {
|
|
element = jqLite(element);
|
|
|
|
// if element is the document object work with the html element instead
|
|
// this makes $(document).scope() possible
|
|
if(element[0].nodeType == 9) {
|
|
element = element.find('html');
|
|
}
|
|
|
|
while (element.length) {
|
|
if (value = element.data(name)) return value;
|
|
element = element.parent();
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////
|
|
// Functions which are declared directly.
|
|
//////////////////////////////////////////
|
|
var JQLitePrototype = JQLite.prototype = {
|
|
ready: function(fn) {
|
|
var fired = false;
|
|
|
|
function trigger() {
|
|
if (fired) return;
|
|
fired = true;
|
|
fn();
|
|
}
|
|
|
|
this.bind('DOMContentLoaded', trigger); // works for modern browsers and IE9
|
|
// we can not use jqLite since we are not done loading and jQuery could be loaded later.
|
|
JQLite(window).bind('load', trigger); // fallback to window.onload for others
|
|
},
|
|
toString: function() {
|
|
var value = [];
|
|
forEach(this, function(e){ value.push('' + e);});
|
|
return '[' + value.join(', ') + ']';
|
|
},
|
|
|
|
eq: function(index) {
|
|
return (index >= 0) ? jqLite(this[index]) : jqLite(this[this.length + index]);
|
|
},
|
|
|
|
length: 0,
|
|
push: push,
|
|
sort: [].sort,
|
|
splice: [].splice
|
|
};
|
|
|
|
//////////////////////////////////////////
|
|
// Functions iterating getter/setters.
|
|
// these functions return self on setter and
|
|
// value on get.
|
|
//////////////////////////////////////////
|
|
var BOOLEAN_ATTR = {};
|
|
forEach('multiple,selected,checked,disabled,readOnly,required'.split(','), function(value) {
|
|
BOOLEAN_ATTR[lowercase(value)] = value;
|
|
});
|
|
var BOOLEAN_ELEMENTS = {};
|
|
forEach('input,select,option,textarea,button,form'.split(','), function(value) {
|
|
BOOLEAN_ELEMENTS[uppercase(value)] = true;
|
|
});
|
|
|
|
function isBooleanAttr(element, name) {
|
|
return BOOLEAN_ELEMENTS[element.nodeName] && BOOLEAN_ATTR[name.toLowerCase()];
|
|
}
|
|
|
|
forEach({
|
|
data: JQLiteData,
|
|
inheritedData: JQLiteInheritedData,
|
|
|
|
scope: function(element) {
|
|
return JQLiteInheritedData(element, '$scope');
|
|
},
|
|
|
|
controller: JQLiteController ,
|
|
|
|
injector: function(element) {
|
|
return JQLiteInheritedData(element, '$injector');
|
|
},
|
|
|
|
removeAttr: function(element,name) {
|
|
element.removeAttribute(name);
|
|
},
|
|
|
|
hasClass: JQLiteHasClass,
|
|
|
|
css: function(element, name, value) {
|
|
name = camelCase(name);
|
|
|
|
if (isDefined(value)) {
|
|
element.style[name] = value;
|
|
} else {
|
|
var val;
|
|
|
|
if (msie <= 8) {
|
|
// this is some IE specific weirdness that jQuery 1.6.4 does not sure why
|
|
val = element.currentStyle && element.currentStyle[name];
|
|
if (val === '') val = 'auto';
|
|
}
|
|
|
|
val = val || element.style[name];
|
|
|
|
if (msie <= 8) {
|
|
// jquery weirdness :-/
|
|
val = (val === '') ? undefined : val;
|
|
}
|
|
|
|
return val;
|
|
}
|
|
},
|
|
|
|
attr: function(element, name, value){
|
|
var lowercasedName = lowercase(name);
|
|
if (BOOLEAN_ATTR[lowercasedName]) {
|
|
if (isDefined(value)) {
|
|
if (!!value) {
|
|
element[name] = true;
|
|
element.setAttribute(name, lowercasedName);
|
|
} else {
|
|
element[name] = false;
|
|
element.removeAttribute(lowercasedName);
|
|
}
|
|
} else {
|
|
return (element[name] ||
|
|
(element.attributes.getNamedItem(name)|| noop).specified)
|
|
? lowercasedName
|
|
: undefined;
|
|
}
|
|
} else if (isDefined(value)) {
|
|
element.setAttribute(name, value);
|
|
} else if (element.getAttribute) {
|
|
// the extra argument "2" is to get the right thing for a.href in IE, see jQuery code
|
|
// some elements (e.g. Document) don't have get attribute, so return undefined
|
|
var ret = element.getAttribute(name, 2);
|
|
// normalize non-existing attributes to undefined (as jQuery)
|
|
return ret === null ? undefined : ret;
|
|
}
|
|
},
|
|
|
|
prop: function(element, name, value) {
|
|
if (isDefined(value)) {
|
|
element[name] = value;
|
|
} else {
|
|
return element[name];
|
|
}
|
|
},
|
|
|
|
text: extend((msie < 9)
|
|
? function(element, value) {
|
|
if (element.nodeType == 1 /** Element */) {
|
|
if (isUndefined(value))
|
|
return element.innerText;
|
|
element.innerText = value;
|
|
} else {
|
|
if (isUndefined(value))
|
|
return element.nodeValue;
|
|
element.nodeValue = value;
|
|
}
|
|
}
|
|
: function(element, value) {
|
|
if (isUndefined(value)) {
|
|
return element.textContent;
|
|
}
|
|
element.textContent = value;
|
|
}, {$dv:''}),
|
|
|
|
val: function(element, value) {
|
|
if (isUndefined(value)) {
|
|
return element.value;
|
|
}
|
|
element.value = value;
|
|
},
|
|
|
|
html: function(element, value) {
|
|
if (isUndefined(value)) {
|
|
return element.innerHTML;
|
|
}
|
|
for (var i = 0, childNodes = element.childNodes; i < childNodes.length; i++) {
|
|
JQLiteDealoc(childNodes[i]);
|
|
}
|
|
element.innerHTML = value;
|
|
}
|
|
}, function(fn, name){
|
|
/**
|
|
* Properties: writes return selection, reads return first value
|
|
*/
|
|
JQLite.prototype[name] = function(arg1, arg2) {
|
|
var i, key;
|
|
|
|
// JQLiteHasClass has only two arguments, but is a getter-only fn, so we need to special-case it
|
|
// in a way that survives minification.
|
|
if (((fn.length == 2 && (fn !== JQLiteHasClass && fn !== JQLiteController)) ? arg1 : arg2) === undefined) {
|
|
if (isObject(arg1)) {
|
|
// we are a write, but the object properties are the key/values
|
|
for(i=0; i < this.length; i++) {
|
|
for (key in arg1) {
|
|
fn(this[i], key, arg1[key]);
|
|
}
|
|
}
|
|
// return self for chaining
|
|
return this;
|
|
} else {
|
|
// we are a read, so read the first child.
|
|
if (this.length)
|
|
return fn(this[0], arg1, arg2);
|
|
}
|
|
} else {
|
|
// we are a write, so apply to all children
|
|
for(i=0; i < this.length; i++) {
|
|
fn(this[i], arg1, arg2);
|
|
}
|
|
// return self for chaining
|
|
return this;
|
|
}
|
|
return fn.$dv;
|
|
};
|
|
});
|
|
|
|
function createEventHandler(element) {
|
|
var eventHandler = function (event) {
|
|
if (!event.preventDefault) {
|
|
event.preventDefault = function() {
|
|
event.returnValue = false; //ie
|
|
};
|
|
}
|
|
|
|
if (!event.stopPropagation) {
|
|
event.stopPropagation = function() {
|
|
event.cancelBubble = true; //ie
|
|
};
|
|
}
|
|
|
|
if (!event.target) {
|
|
event.target = event.srcElement || document;
|
|
}
|
|
|
|
if (isUndefined(event.defaultPrevented)) {
|
|
var prevent = event.preventDefault;
|
|
event.preventDefault = function() {
|
|
event.defaultPrevented = true;
|
|
prevent.call(event);
|
|
};
|
|
event.defaultPrevented = false;
|
|
}
|
|
|
|
event.isDefaultPrevented = function() {
|
|
return event.defaultPrevented;
|
|
};
|
|
|
|
forEach(eventHandler.fns, function(fn){
|
|
fn.call(element, event);
|
|
});
|
|
|
|
// Remove monkey-patched methods (IE),
|
|
// as they would cause memory leaks in IE8.
|
|
if (msie < 8) {
|
|
// IE7 does not allow to delete property on native object
|
|
event.preventDefault = null;
|
|
event.stopPropagation = null;
|
|
event.isDefaultPrevented = null;
|
|
} else {
|
|
// It shouldn't affect normal browsers (native methods are defined on prototype).
|
|
delete event.preventDefault;
|
|
delete event.stopPropagation;
|
|
delete event.isDefaultPrevented;
|
|
}
|
|
};
|
|
eventHandler.fns = [];
|
|
return eventHandler;
|
|
};
|
|
|
|
//////////////////////////////////////////
|
|
// Functions iterating traversal.
|
|
// These functions chain results into a single
|
|
// selector.
|
|
//////////////////////////////////////////
|
|
forEach({
|
|
removeData: JQLiteRemoveData,
|
|
|
|
dealoc: JQLiteDealoc,
|
|
|
|
bind: function bindFn(element, type, fn){
|
|
var bind = JQLiteData(element, 'bind');
|
|
|
|
|
|
if (!bind) JQLiteData(element, 'bind', bind = {});
|
|
forEach(type.split(' '), function(type){
|
|
var eventHandler = bind[type];
|
|
|
|
|
|
if (!eventHandler) {
|
|
if (type == 'mouseenter' || type == 'mouseleave') {
|
|
var mouseenter = bind.mouseenter = createEventHandler(element);
|
|
var mouseleave = bind.mouseleave = createEventHandler(element);
|
|
var counter = 0;
|
|
|
|
|
|
bindFn(element, 'mouseover', function(event) {
|
|
counter++;
|
|
if (counter == 1) {
|
|
event.type = 'mouseenter';
|
|
mouseenter(event);
|
|
}
|
|
});
|
|
bindFn(element, 'mouseout', function(event) {
|
|
counter --;
|
|
if (counter == 0) {
|
|
event.type = 'mouseleave';
|
|
mouseleave(event);
|
|
}
|
|
});
|
|
eventHandler = bind[type];
|
|
} else {
|
|
eventHandler = bind[type] = createEventHandler(element);
|
|
addEventListenerFn(element, type, eventHandler);
|
|
}
|
|
}
|
|
eventHandler.fns.push(fn);
|
|
});
|
|
},
|
|
|
|
unbind: function(element, type, fn) {
|
|
var bind = JQLiteData(element, 'bind');
|
|
if (!bind) return; //no listeners registered
|
|
|
|
if (isUndefined(type)) {
|
|
forEach(bind, function(eventHandler, type) {
|
|
removeEventListenerFn(element, type, eventHandler);
|
|
delete bind[type];
|
|
});
|
|
} else {
|
|
if (isUndefined(fn)) {
|
|
removeEventListenerFn(element, type, bind[type]);
|
|
delete bind[type];
|
|
} else {
|
|
arrayRemove(bind[type].fns, fn);
|
|
}
|
|
}
|
|
},
|
|
|
|
replaceWith: function(element, replaceNode) {
|
|
var index, parent = element.parentNode;
|
|
JQLiteDealoc(element);
|
|
forEach(new JQLite(replaceNode), function(node){
|
|
if (index) {
|
|
parent.insertBefore(node, index.nextSibling);
|
|
} else {
|
|
parent.replaceChild(node, element);
|
|
}
|
|
index = node;
|
|
});
|
|
},
|
|
|
|
children: function(element) {
|
|
var children = [];
|
|
forEach(element.childNodes, function(element){
|
|
if (element.nodeName != '#text')
|
|
children.push(element);
|
|
});
|
|
return children;
|
|
},
|
|
|
|
contents: function(element) {
|
|
return element.childNodes;
|
|
},
|
|
|
|
append: function(element, node) {
|
|
forEach(new JQLite(node), function(child){
|
|
if (element.nodeType === 1)
|
|
element.appendChild(child);
|
|
});
|
|
},
|
|
|
|
prepend: function(element, node) {
|
|
if (element.nodeType === 1) {
|
|
var index = element.firstChild;
|
|
forEach(new JQLite(node), function(child){
|
|
if (index) {
|
|
element.insertBefore(child, index);
|
|
} else {
|
|
element.appendChild(child);
|
|
index = child;
|
|
}
|
|
});
|
|
}
|
|
},
|
|
|
|
wrap: function(element, wrapNode) {
|
|
wrapNode = jqLite(wrapNode)[0];
|
|
var parent = element.parentNode;
|
|
if (parent) {
|
|
parent.replaceChild(wrapNode, element);
|
|
}
|
|
wrapNode.appendChild(element);
|
|
},
|
|
|
|
remove: function(element) {
|
|
JQLiteDealoc(element);
|
|
var parent = element.parentNode;
|
|
if (parent) parent.removeChild(element);
|
|
},
|
|
|
|
after: function(element, newElement) {
|
|
var index = element, parent = element.parentNode;
|
|
forEach(new JQLite(newElement), function(node){
|
|
parent.insertBefore(node, index.nextSibling);
|
|
index = node;
|
|
});
|
|
},
|
|
|
|
addClass: JQLiteAddClass,
|
|
removeClass: JQLiteRemoveClass,
|
|
|
|
toggleClass: function(element, selector, condition) {
|
|
if (isUndefined(condition)) {
|
|
condition = !JQLiteHasClass(element, selector);
|
|
}
|
|
(condition ? JQLiteAddClass : JQLiteRemoveClass)(element, selector);
|
|
},
|
|
|
|
parent: function(element) {
|
|
var parent = element.parentNode;
|
|
return parent && parent.nodeType !== 11 ? parent : null;
|
|
},
|
|
|
|
next: function(element) {
|
|
return element.nextSibling;
|
|
},
|
|
|
|
find: function(element, selector) {
|
|
return element.getElementsByTagName(selector);
|
|
},
|
|
|
|
clone: JQLiteClone
|
|
}, function(fn, name){
|
|
/**
|
|
* chaining functions
|
|
*/
|
|
JQLite.prototype[name] = function(arg1, arg2) {
|
|
var value;
|
|
for(var i=0; i < this.length; i++) {
|
|
if (value == undefined) {
|
|
value = fn(this[i], arg1, arg2);
|
|
if (value !== undefined) {
|
|
// any function which returns a value needs to be wrapped
|
|
value = jqLite(value);
|
|
}
|
|
} else {
|
|
JQLiteAddNodes(value, fn(this[i], arg1, arg2));
|
|
}
|
|
}
|
|
return value == undefined ? this : value;
|
|
};
|
|
});
|