'use strict';
/* global
-JQLitePrototype,
-addEventListenerFn,
-removeEventListenerFn,
-BOOLEAN_ATTR
*/
//////////////////////////////////
//JQLite
//////////////////////////////////
/**
* @ngdoc function
* @name angular.element
* @module ng
* @function
*
* @description
* Wraps a raw DOM element or HTML string as a [jQuery](http://jquery.com) element.
*
* If jQuery is available, `angular.element` is an alias for the
* [jQuery](http://api.jquery.com/jQuery/) function. If jQuery is not available, `angular.element`
* delegates to Angular's built-in subset of jQuery, called "jQuery lite" or "jqLite."
*
*
jqLite is a tiny, API-compatible subset of jQuery that allows
* Angular to manipulate the DOM in a cross-browser compatible way. **jqLite** implements only the most
* commonly needed functionality with the goal of having a very small footprint.
*
* To use jQuery, simply load it before `DOMContentLoaded` event fired.
*
* **Note:** all element references in Angular are always wrapped with jQuery or
* jqLite; they are never raw DOM references.
*
* ## Angular's jqLite
* jqLite provides only the following jQuery 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/) - Does not support namespaces, selectors or eventData
* - [`children()`](http://api.jquery.com/children/) - Does not support selectors
* - [`clone()`](http://api.jquery.com/clone/)
* - [`contents()`](http://api.jquery.com/contents/)
* - [`css()`](http://api.jquery.com/css/)
* - [`data()`](http://api.jquery.com/data/)
* - [`empty()`](http://api.jquery.com/empty/)
* - [`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/) - Does not support selectors
* - [`on()`](http://api.jquery.com/on/) - Does not support namespaces, selectors or eventData
* - [`off()`](http://api.jquery.com/off/) - Does not support namespaces or selectors
* - [`one()`](http://api.jquery.com/one/) - Does not support namespaces or selectors
* - [`parent()`](http://api.jquery.com/parent/) - Does not support selectors
* - [`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/)
* - [`triggerHandler()`](http://api.jquery.com/triggerHandler/) - Passes a dummy event object to handlers.
* - [`unbind()`](http://api.jquery.com/unbind/) - Does not support namespaces
* - [`val()`](http://api.jquery.com/val/)
* - [`wrap()`](http://api.jquery.com/wrap/)
*
* ## jQuery/jqLite Extras
* Angular also provides the following additional methods and events to both jQuery and jqLite:
*
* ### Events
* - `$destroy` - AngularJS intercepts all jqLite/jQuery's DOM destruction apis and fires this event
* on all DOM nodes being removed. This can be used to clean up any 3rd party bindings to the DOM
* element before it is removed.
*
* ### Methods
* - `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 ng.$rootScope.Scope scope} of the current
* element or its parent.
* - `isolateScope()` - retrieves an isolate {@link ng.$rootScope.Scope scope} if one is attached directly to the
* current element. This getter should be used only on elements that contain a directive which starts a new isolate
* scope. Calling `scope()` on this element always returns the original non-isolate scope.
* - `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 = JQLite.cache = {},
jqName = JQLite.expando = '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); });
/*
* !!! This is an undocumented "private" function !!!
*/
var jqData = JQLite._data = function(node) {
//jQuery always returns an object on cache miss
return this.cache[node[this.expando]] || {};
};
function jqNextId() { return ++jqId; }
var SPECIAL_CHARS_REGEXP = /([\:\-\_]+(.))/g;
var MOZ_HACK_REGEXP = /^moz([A-Z])/;
var jqLiteMinErr = minErr('jqLite');
/**
* 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, filterElems, getterIfNoArguments) {
var originalJqFn = jQuery.fn[name];
originalJqFn = originalJqFn.$original || originalJqFn;
removePatch.$original = originalJqFn;
jQuery.fn[name] = removePatch;
function removePatch(param) {
// jshint -W040
var list = filterElems && param ? [this.filter(param)] : [this],
fireEvent = dispatchThis,
set, setIndex, setLength,
element, childIndex, childLength, children;
if (!getterIfNoArguments || param != null) {
while(list.length) {
set = list.shift();
for(setIndex = 0, setLength = set.length; setIndex < setLength; setIndex++) {
element = jqLite(set[setIndex]);
if (fireEvent) {
element.triggerHandler('$destroy');
} 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 (isString(element)) {
element = trim(element);
}
if (!(this instanceof JQLite)) {
if (isString(element) && element.charAt(0) != '<') {
throw jqLiteMinErr('nosel', 'Looking up elements via selectors is not supported by jqLite! See: http://docs.angularjs.org/api/angular.element');
}
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 = '
' + element; // IE insanity to make NoScope elements work!
div.removeChild(div.firstChild); // remove the superfluous div
jqLiteAddNodes(this, div.childNodes);
var fragment = jqLite(document.createDocumentFragment());
fragment.append(this); // 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 jqLiteOff(element, type, fn, unsupported) {
if (isDefined(unsupported)) throw jqLiteMinErr('offargs', 'jqLite#off() does not support the `selector` argument');
var events = jqLiteExpandoStore(element, 'events'),
handle = jqLiteExpandoStore(element, 'handle');
if (!handle) return; //no listeners registered
if (isUndefined(type)) {
forEach(events, function(eventHandler, type) {
removeEventListenerFn(element, type, eventHandler);
delete events[type];
});
} else {
forEach(type.split(' '), function(type) {
if (isUndefined(fn)) {
removeEventListenerFn(element, type, events[type]);
delete events[type];
} else {
arrayRemove(events[type] || [], fn);
}
});
}
}
function jqLiteRemoveData(element, name) {
var expandoId = element[jqName],
expandoStore = jqCache[expandoId];
if (expandoStore) {
if (name) {
delete jqCache[expandoId].data[name];
return;
}
if (expandoStore.handle) {
expandoStore.events.$destroy && expandoStore.handle({}, '$destroy');
jqLiteOff(element);
}
delete jqCache[expandoId];
element[jqName] = undefined; // ie does not allow deletion of attributes on elements.
}
}
function jqLiteExpandoStore(element, key, value) {
var expandoId = element[jqName],
expandoStore = jqCache[expandoId || -1];
if (isDefined(value)) {
if (!expandoStore) {
element[jqName] = expandoId = jqNextId();
expandoStore = jqCache[expandoId] = {};
}
expandoStore[key] = value;
} else {
return expandoStore && expandoStore[key];
}
}
function jqLiteData(element, key, value) {
var data = jqLiteExpandoStore(element, 'data'),
isSetter = isDefined(value),
keyDefined = !isSetter && isDefined(key),
isSimpleGetter = keyDefined && !isObject(key);
if (!data && !isSimpleGetter) {
jqLiteExpandoStore(element, 'data', data = {});
}
if (isSetter) {
data[key] = value;
} else {
if (keyDefined) {
if (isSimpleGetter) {
// don't create data in this case.
return data && data[key];
} else {
extend(data, key);
}
} else {
return data;
}
}
}
function jqLiteHasClass(element, selector) {
if (!element.getAttribute) return false;
return ((" " + (element.getAttribute('class') || '') + " ").replace(/[\n\t]/g, " ").
indexOf( " " + selector + " " ) > -1);
}
function jqLiteRemoveClass(element, cssClasses) {
if (cssClasses && element.setAttribute) {
forEach(cssClasses.split(' '), function(cssClass) {
element.setAttribute('class', trim(
(" " + (element.getAttribute('class') || '') + " ")
.replace(/[\n\t]/g, " ")
.replace(" " + trim(cssClass) + " ", " "))
);
});
}
}
function jqLiteAddClass(element, cssClasses) {
if (cssClasses && element.setAttribute) {
var existingClasses = (' ' + (element.getAttribute('class') || '') + ' ')
.replace(/[\n\t]/g, " ");
forEach(cssClasses.split(' '), function(cssClass) {
cssClass = trim(cssClass);
if (existingClasses.indexOf(' ' + cssClass + ' ') === -1) {
existingClasses += cssClass + ' ';
}
});
element.setAttribute('class', trim(existingClasses));
}
}
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');
}
var names = isArray(name) ? name : [name];
while (element.length) {
for (var i = 0, ii = names.length; i < ii; i++) {
if ((value = element.data(names[i])) !== undefined) return value;
}
element = element.parent();
}
}
function jqLiteEmpty(element) {
for (var i = 0, childNodes = element.childNodes; i < childNodes.length; i++) {
jqLiteDealoc(childNodes[i]);
}
while (element.firstChild) {
element.removeChild(element.firstChild);
}
}
//////////////////////////////////////////
// Functions which are declared directly.
//////////////////////////////////////////
var JQLitePrototype = JQLite.prototype = {
ready: function(fn) {
var fired = false;
function trigger() {
if (fired) return;
fired = true;
fn();
}
// check if document already is loaded
if (document.readyState === 'complete'){
setTimeout(trigger);
} else {
this.on('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.
// jshint -W064
JQLite(window).on('load', trigger); // fallback to window.onload for others
// jshint +W064
}
},
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,open'.split(','), function(value) {
BOOLEAN_ATTR[lowercase(value)] = value;
});
var BOOLEAN_ELEMENTS = {};
forEach('input,select,option,textarea,button,form,details'.split(','), function(value) {
BOOLEAN_ELEMENTS[uppercase(value)] = true;
});
function getBooleanAttrName(element, name) {
// check dom last since we will most likely fail on name
var booleanAttr = BOOLEAN_ATTR[name.toLowerCase()];
// booleanAttr is here twice to minimize DOM access
return booleanAttr && BOOLEAN_ELEMENTS[element.nodeName] && booleanAttr;
}
forEach({
data: jqLiteData,
inheritedData: jqLiteInheritedData,
scope: function(element) {
// Can't use jqLiteData here directly so we stay compatible with jQuery!
return jqLite(element).data('$scope') || jqLiteInheritedData(element.parentNode || element, ['$isolateScope', '$scope']);
},
isolateScope: function(element) {
// Can't use jqLiteData here directly so we stay compatible with jQuery!
return jqLite(element).data('$isolateScope') || jqLite(element).data('$isolateScopeNoTemplate');
},
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: (function() {
var NODE_TYPE_TEXT_PROPERTY = [];
if (msie < 9) {
NODE_TYPE_TEXT_PROPERTY[1] = 'innerText'; /** Element **/
NODE_TYPE_TEXT_PROPERTY[3] = 'nodeValue'; /** Text **/
} else {
NODE_TYPE_TEXT_PROPERTY[1] = /** Element **/
NODE_TYPE_TEXT_PROPERTY[3] = 'textContent'; /** Text **/
}
getText.$dv = '';
return getText;
function getText(element, value) {
var textProp = NODE_TYPE_TEXT_PROPERTY[element.nodeType];
if (isUndefined(value)) {
return textProp ? element[textProp] : '';
}
element[textProp] = value;
}
})(),
val: function(element, value) {
if (isUndefined(value)) {
if (nodeName_(element) === 'SELECT' && element.multiple) {
var result = [];
forEach(element.options, function (option) {
if (option.selected) {
result.push(option.value || option.text);
}
});
return result.length === 0 ? null : result;
}
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;
},
empty: jqLiteEmpty
}, 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.
// jqLiteEmpty takes no arguments but is a setter.
if (fn !== jqLiteEmpty &&
(((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++) {
if (fn === jqLiteData) {
// data() takes the whole object in jQuery
fn(this[i], arg1);
} else {
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.
var value = fn.$dv;
// Only if we have $dv do we iterate over all, otherwise it is just the first element.
var jj = (value === undefined) ? Math.min(this.length, 1) : this.length;
for (var j = 0; j < jj; j++) {
var nodeValue = fn(this[j], arg1, arg2);
value = value ? value + nodeValue : nodeValue;
}
return value;
}
} 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;
}
};
});
function createEventHandler(element, events) {
var eventHandler = function (event, type) {
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 || event.returnValue === false;
};
// Copy event handlers in case event handlers array is modified during execution.
var eventHandlersCopy = shallowCopy(events[type || event.type] || []);
forEach(eventHandlersCopy, function(fn) {
fn.call(element, event);
});
// Remove monkey-patched methods (IE),
// as they would cause memory leaks in IE8.
if (msie <= 8) {
// IE7/8 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.elem = element;
return eventHandler;
}
//////////////////////////////////////////
// Functions iterating traversal.
// These functions chain results into a single
// selector.
//////////////////////////////////////////
forEach({
removeData: jqLiteRemoveData,
dealoc: jqLiteDealoc,
on: function onFn(element, type, fn, unsupported){
if (isDefined(unsupported)) throw jqLiteMinErr('onargs', 'jqLite#on() does not support the `selector` or `eventData` parameters');
var events = jqLiteExpandoStore(element, 'events'),
handle = jqLiteExpandoStore(element, 'handle');
if (!events) jqLiteExpandoStore(element, 'events', events = {});
if (!handle) jqLiteExpandoStore(element, 'handle', handle = createEventHandler(element, events));
forEach(type.split(' '), function(type){
var eventFns = events[type];
if (!eventFns) {
if (type == 'mouseenter' || type == 'mouseleave') {
var contains = document.body.contains || document.body.compareDocumentPosition ?
function( a, b ) {
// jshint bitwise: false
var adown = a.nodeType === 9 ? a.documentElement : a,
bup = b && b.parentNode;
return a === bup || !!( bup && bup.nodeType === 1 && (
adown.contains ?
adown.contains( bup ) :
a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16
));
} :
function( a, b ) {
if ( b ) {
while ( (b = b.parentNode) ) {
if ( b === a ) {
return true;
}
}
}
return false;
};
events[type] = [];
// Refer to jQuery's implementation of mouseenter & mouseleave
// Read about mouseenter and mouseleave:
// http://www.quirksmode.org/js/events_mouse.html#link8
var eventmap = { mouseleave : "mouseout", mouseenter : "mouseover"};
onFn(element, eventmap[type], function(event) {
var target = this, related = event.relatedTarget;
// For mousenter/leave call the handler if related is outside the target.
// NB: No relatedTarget if the mouse left/entered the browser window
if ( !related || (related !== target && !contains(target, related)) ){
handle(event, type);
}
});
} else {
addEventListenerFn(element, type, handle);
events[type] = [];
}
eventFns = events[type];
}
eventFns.push(fn);
});
},
off: jqLiteOff,
one: function(element, type, fn) {
element = jqLite(element);
//add the listener twice so that when it is called
//you can remove the original function and still be
//able to call element.off(ev, fn) normally
element.on(type, function onFn() {
element.off(type, fn);
element.off(type, onFn);
});
element.on(type, 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.nodeType === 1)
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.nodeType === 11) {
element.appendChild(child);
}
});
},
prepend: function(element, node) {
if (element.nodeType === 1) {
var index = element.firstChild;
forEach(new JQLite(node), function(child){
element.insertBefore(child, index);
});
}
},
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) {
if (element.nextElementSibling) {
return element.nextElementSibling;
}
// IE8 doesn't have nextElementSibling
var elm = element.nextSibling;
while (elm != null && elm.nodeType !== 1) {
elm = elm.nextSibling;
}
return elm;
},
find: function(element, selector) {
if (element.getElementsByTagName) {
return element.getElementsByTagName(selector);
} else {
return [];
}
},
clone: jqLiteClone,
triggerHandler: function(element, eventName, eventData) {
var eventFns = (jqLiteExpandoStore(element, 'events') || {})[eventName];
eventData = eventData || [];
var event = [{
preventDefault: noop,
stopPropagation: noop
}];
forEach(eventFns, function(fn) {
fn.apply(element, event.concat(eventData));
});
}
}, function(fn, name){
/**
* chaining functions
*/
JQLite.prototype[name] = function(arg1, arg2, arg3) {
var value;
for(var i=0; i < this.length; i++) {
if (isUndefined(value)) {
value = fn(this[i], arg1, arg2, arg3);
if (isDefined(value)) {
// any function which returns a value needs to be wrapped
value = jqLite(value);
}
} else {
jqLiteAddNodes(value, fn(this[i], arg1, arg2, arg3));
}
}
return isDefined(value) ? value : this;
};
// bind legacy bind/unbind to on/off
JQLite.prototype.bind = JQLite.prototype.on;
JQLite.prototype.unbind = JQLite.prototype.off;
});