Last active
February 17, 2017 13:31
-
-
Save kotarok/ea2f2fc4f90a695972ae84a53c475e4c to your computer and use it in GitHub Desktop.
Array based tiny jQuery subset alternative with minimum number of methods + useful functionalities. Less than 1kb gzipped.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(function(window) { | |
'use strict'; | |
var camelize = function(str) { | |
str = str.replace(/^\s+/, ''); | |
return str.replace(/[\W]+([a-z0-9])(\w*)/ig, function(match, p1, p2) { | |
return p1.toUpperCase() + p2; | |
}); | |
}; | |
/** | |
* Main function to create NqObj object. | |
* @global | |
* @param {String} q [description] | |
* @param {Function} f Optional. If it's given, passed to forEach. | |
* @return {NqObj} | |
*/ | |
var nq = function(q, f) { | |
if (typeof f === 'function') { | |
return new NqObj(q).forEach(function(el, i) {f(el, i);}); | |
} else { | |
return new NqObj(q); | |
} | |
}; | |
/** | |
* NqObj | |
* @global | |
* @constructor | |
* @param {String|Array|NodeList|HTMLElement} q Given elements are added to NqObj. | |
*/ | |
var NqObj = function(q) { | |
return q? this.push(q): this; | |
}; | |
var nqp = nq.fn = NqObj.prototype = []; | |
/** | |
* Returns new NqObj with specified element. Just like NodeList.item() | |
* @param {Number} i Index number. | |
* @return {Object} New NqObj only has specified element. | |
*/ | |
nqp.item = function(i) { | |
return nq(this[i]); | |
}; | |
/** | |
* Just like jQ.find(). Find matched elements from descendant of original collection. | |
* @param {String|Array|NodeList|HTMLElement} q CSS selector or Element or Elements | |
* @return {Object} New NqObj. | |
*/ | |
nqp.find = function(q) { | |
var newNq = new NqObj(); | |
this.forEach(function(el) { | |
newNq.push(el.querySelectorAll(q)); | |
}); | |
return newNq; | |
}; | |
/** | |
* Add new elements to collection. | |
* @param {Array|NodeList|NqObj|HTMLElement|window|document} q CSS selector or Element or Elements | |
* @return {Object} self | |
*/ | |
nqp.push = function(q) { | |
var r = []; | |
if (q instanceof HTMLElement || q === window || q === document) { | |
r = [q]; | |
} else if (typeof q === 'string') { | |
[].forEach.call(document.querySelectorAll(q),function(el){ | |
r.push(el); | |
}); | |
} else { | |
r = q; | |
} | |
r.forEach(function(el) { | |
[].push.call(this, el); | |
}.bind(this)); | |
return this; | |
}; | |
/** | |
* delayEach is forEach with interval | |
* @param {Function} f function to iterate | |
* @param {Number} interval Interval in millisecond | |
* @return {Object} self | |
*/ | |
nqp.delayEach = function(f, interval) { | |
var i = 0; | |
if (interval) { | |
var timer = setInterval(function() { | |
f(this[i], i); | |
i++; | |
if (i >= this.length) { | |
clearInterval(timer); | |
} | |
}.bind(this), interval); | |
} else { | |
this.forEach(function(el) { | |
f(el); | |
}); | |
} | |
return this; | |
}; | |
/** | |
* (methodName, className[, className...][, interval]) | |
* @private | |
* @param {String} method Method Name | |
* @param {String | Number} args className[, className...][, interval] | |
* @return {Object} Self | |
*/ | |
nqp.oprtClass_ = function(method, args){ | |
args = [].slice.call(args); | |
var interval = (typeof args[args.length - 1] === 'number') ? args.pop() : 0; | |
this.delayEach(function(el) { | |
el.classList[method].apply(el.classList, args); | |
}, interval); | |
return this; | |
}; | |
/** | |
* Shorthand for HTMLElement##classList#add, and interval | |
* @param {String} className[, className...][, interval] | |
* @return {Object} Self | |
*/ | |
nqp.addClass = function() { | |
return this.oprtClass_('add', arguments); | |
}; | |
/** | |
* Shorthand for HTMLElement##classList#remove, and interval | |
* @param {String} className[, className...][, interval] | |
* @return {Object} Self | |
*/ | |
nqp.removeClass = function() { | |
return this.oprtClass_('remove', arguments); | |
}; | |
/** | |
* Shorthand for cHTMLElement#lassList#toggle, and interval | |
* @param {String} className[, condition function...][, interval] | |
* @return {Object} Self | |
*/ | |
nqp.toggleClass = function(className, condition, interval) { | |
if (typeof condition === 'number') { | |
interval = condition; | |
condition = undefined; | |
} | |
return this.oprtClass_('toggle', [className, condition, interval]); | |
}; | |
/** | |
* Shorthand for HTMLElement#classList#contains | |
* @param {String} className className | |
* @return {Object} Self | |
*/ | |
nqp.hasClass = function(className) { | |
return this[0].classList.contains(className); | |
}; | |
var treatMultipleEventListner_ = function(el, eventType, listenerType, fn) { | |
eventType.split(/,\s*/).forEach(function(e) { | |
el[listenerType + 'EventListener'](e, fn); | |
}); | |
}; | |
/** | |
* Shorthand for Element#addEventListener | |
* @param {Event} e Event type | |
* @param {Function} f Event handler function | |
* @return {Object} Self | |
*/ | |
nqp.on = function(eventType, f) { | |
this.forEach(function(el) { | |
treatMultipleEventListner_(el, eventType, 'add', f.bind(el)); | |
}); | |
return this; | |
}; | |
/** | |
* Shorthand for Element#removeEventListener | |
* @param {Event} e Event type | |
* @param {Function} f Function to remove | |
* @return {Object} Self | |
*/ | |
nqp.off = function(eventType, f) { | |
this.forEach(function(el) { | |
treatMultipleEventListner_(el, eventType, 'remove', f.bind(el)); | |
}); | |
return this; | |
}; | |
nqp.one = function(eventType, f) { | |
this.forEach(function(el) { | |
var eventName; | |
var fnWrapper = function() { | |
f.apply(el); | |
treatMultipleEventListner_(el, eventType, 'remove', fnWrapper); | |
}; | |
treatMultipleEventListner_(el, eventType, 'add', fnWrapper); | |
}); | |
return this; | |
}; | |
nqp.defineScrollObserver = function(eventName, condition) { | |
var offset = condition = condition || 0; | |
// var getScrollContainer_ = function(el) { | |
// var scrollContainer = $(el)[0].find(function(el) { | |
// return el.scrollHeight > el.offsetHeight || el.scrollWidth > el.offsetWidth; | |
// }); | |
// return (scrollContainer instanceof HTMLBodyElement)? window: scrollContainer; | |
// }; | |
if (typeof condition === 'number' && Math.abs(condition) > 1) { | |
condition = function(el, rect, vh) { | |
return vh > rect.top + offset; | |
}; | |
} else if (typeof condition !== 'function') { | |
condition = function(el, rect, vh) { | |
return vh * offset > rect.top; | |
}; | |
} | |
this.forEach(function(el) { | |
nq(window).on('load,scroll,resize', function() { | |
var rect = nq(el).rect(), vh = window.innerHeight; | |
if (condition(el, rect, vh)) { | |
var e = new Event(eventName); | |
e.rect = rect; | |
e.vh = vh; | |
el.dispatchEvent(e); | |
} | |
}); | |
}); | |
return this; | |
}; | |
nqp.parents = function() { | |
var els = [], el = this[0]; | |
while ((el = el.parentNode)) { | |
if(el instanceof HTMLElement){ | |
els.push(el); | |
} | |
} | |
return nq(els); | |
}; | |
nqp.parent = function() { | |
var el = this[0].parentNode; | |
return (el instanceof HTMLElement)? nq(el): undefined; | |
}; | |
/** | |
* Porperty accessor | |
* @param {String} n Property name | |
* @param {String | Number} v Value to set | |
* @return {Object} Self | |
*/ | |
nqp.prop = function(n, v) { | |
// this condition statement must check if it's string. | |
// Because there's a case passing '' to reset property v. | |
if (typeof v === 'string') { | |
this.forEach(function(el) { | |
el[n] = v; | |
}); | |
return this; | |
} else { | |
return this[0][n]; | |
} | |
}; | |
/** | |
* Short hand for HTMLElement#innreHTML | |
* @param {String} v HTML source string | |
* @return {Object | String} Self | innerHTML value | |
*/ | |
nqp.html = function(v) { | |
if (v !== undefined) { | |
this.forEach(function(el) { | |
el.innerHTML = v; | |
}); | |
return this; | |
} else { | |
return this[0].innderHTML; | |
} | |
}; | |
/** | |
* Short hand for HTMLElement#set/getAttribute | |
* @param {String} n Attribute name | |
* @param {String | Number} v Attribute value | |
* @return {Object | String} Self | Attribute value | |
*/ | |
nqp.attr = function(n, v) { | |
if (v !== undefined) { | |
this.forEach(function(el) { | |
el.setAttribute(n, v); | |
}); | |
return this; | |
} else { | |
return this[0].getAttribute(n); | |
} | |
}; | |
/** | |
* Short hand for HTMLElement#dataset | |
* @param {String} n Data set name | |
* @param {String | Number} v Data content to set | |
* @return {Object | String} Self | Date content | |
*/ | |
nqp.data = function(n, v) { | |
n = camelize(n); | |
if (v !== undefined) { | |
this.forEach(function(el) { | |
el.dataset[n] = v; | |
}); | |
return this; | |
} else { | |
return this[0].dataset[n]; | |
} | |
}; | |
/** | |
* Form element value accessor | |
* @param {String | Number} v Form field value | |
* @return {Object | String} Self | Form field value | |
*/ | |
nqp.val = function(v) { | |
if (v !== undefined) { | |
this.forEach(function(el) { | |
el.value = v; | |
}); | |
return this; | |
} else { | |
if (this[0].value) { | |
return this[0].value; | |
} | |
} | |
}; | |
/** | |
* Style attribute accessor | |
* @param {String} n CSS property name | Object of CSS rulesets | |
* @param {String | Number} v Form field value | |
* @return {Object | String} Self | Style property value | |
*/ | |
nqp.style = function(n, v) { | |
if (v !== undefined) { | |
return this.forEach(function(el) { | |
el.style[camelize(n)] = v; | |
}); | |
} else if (n instanceof Object) { | |
return this.forEach(function(el) { | |
Object.keys(n).forEach(function(prop) { | |
el.style[camelize(prop)] = n[prop]; | |
}); | |
}); | |
} else { | |
// return getComputedStyle(this[0])[camelize(n)]; | |
return this[0].style[camelize(n)]; | |
} | |
}; | |
/** | |
* Shorthand for .insertAdjacentHTML | |
* @param {String} position (beforebegin, afterbegin, beforeend, afterend) | |
* @param {HTMLElement | NqObj} target Target element | |
* @return {[type]} [description] | |
*/ | |
nqp.insert = function(position, insertee) { | |
this.forEach(function(el) { | |
if (typeof insertee === 'string') { | |
el.insertAdjacentHTML(position, insertee); | |
} else if (insertee instanceof HTMLElement) { | |
el.insertAdjacentElement(position, insertee); | |
} | |
}); | |
return this; | |
}; | |
/** | |
* Remove elemet themselves | |
* @return {undefined} | |
*/ | |
nqp.remove = function() { | |
this.forEach(function(el) { | |
el.parentNode.removeChild(el); | |
}); | |
}; | |
/** | |
* Get DOMRect | |
* https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XPCOM/Reference/Interface/nsIDOMClientRect | |
* @return {Object} DOMRect object | |
*/ | |
nqp.rect = function() { | |
var rect = this[0].getBoundingClientRect(); | |
rect.x = this[0].offsetLeft; | |
rect.y = this[0].offsetTop; | |
return rect; | |
}; | |
/** | |
* Uniques collection. | |
* @return {Object} self | |
*/ | |
nqp.unique = function() { | |
return this.filter(function(value, index, el) { | |
return el.indexOf(value) === index; | |
}); | |
}; | |
/** | |
* Reverse collection order | |
* @name reverse | |
* @method | |
* @public | |
* @return {Object} self | |
*/ | |
/** | |
* Work as Array#slice | |
* @name slice | |
* @method | |
* @public | |
* @return {Object} self | |
*/ | |
['reverse','slice', 'filter'] | |
.forEach(function(m) { | |
nqp[m] = function() { | |
return nq([][m].apply(this, arguments)); | |
}; | |
}); | |
window.nq = nq; | |
})(this); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
!function(a){"use strict";var b=function(a){return a=a.replace(/^\s+/,""),a.replace(/[\W]+([a-z0-9])(\w*)/gi,function(a,b,c){return b.toUpperCase()+c})},c=function(a,b){return"function"==typeof b?new d(a).forEach(function(a,c){b(a,c)}):new d(a)},d=function(a){return a?this.push(a):this},e=c.fn=d.prototype=[];e.item=function(a){return c(this[a])},e.find=function(a){var b=new d;return this.forEach(function(c){b.push(c.querySelectorAll(a))}),b},e.push=function(b){var c=[];return b instanceof HTMLElement||b===a||b===document?c=[b]:"string"==typeof b?[].forEach.call(document.querySelectorAll(b),function(a){c.push(a)}):c=b,c.forEach(function(a){[].push.call(this,a)}.bind(this)),this},e.delayEach=function(a,b){var c=0;if(b)var d=setInterval(function(){a(this[c],c),c++,c>=this.length&&clearInterval(d)}.bind(this),b);else this.forEach(function(b){a(b)});return this},e.oprtClass_=function(a,b){b=[].slice.call(b);var c="number"==typeof b[b.length-1]?b.pop():0;return this.delayEach(function(c){c.classList[a].apply(c.classList,b)},c),this},e.addClass=function(){return this.oprtClass_("add",arguments)},e.removeClass=function(){return this.oprtClass_("remove",arguments)},e.toggleClass=function(a,b,c){return"number"==typeof b&&(c=b,b=void 0),this.oprtClass_("toggle",[a,b,c])},e.hasClass=function(a){return this[0].classList.contains(a)};var f=function(a,b,c,d){b.split(/,\s*/).forEach(function(b){a[c+"EventListener"](b,d)})};e.on=function(a,b){return this.forEach(function(c){f(c,a,"add",b.bind(c))}),this},e.off=function(a,b){return this.forEach(function(c){f(c,a,"remove",b.bind(c))}),this},e.one=function(a,b){return this.forEach(function(c){var e=function(){b.apply(c),f(c,a,"remove",e)};f(c,a,"add",e)}),this},e.defineScrollObserver=function(b,d){var e=d=d||0;return"number"==typeof d&&Math.abs(d)>1?d=function(a,b,c){return c>b.top+e}:"function"!=typeof d&&(d=function(a,b,c){return c*e>b.top}),this.forEach(function(e){c(a).on("load,scroll,resize",function(){var f=c(e).rect(),g=a.innerHeight;if(d(e,f,g)){var h=new Event(b);h.rect=f,h.vh=g,e.dispatchEvent(h)}})}),this},e.parents=function(){for(var a=[],b=this[0];b=b.parentNode;)b instanceof HTMLElement&&a.push(b);return c(a)},e.parent=function(){var a=this[0].parentNode;return a instanceof HTMLElement?c(a):void 0},e.prop=function(a,b){return"string"==typeof b?(this.forEach(function(c){c[a]=b}),this):this[0][a]},e.html=function(a){return void 0!==a?(this.forEach(function(b){b.innerHTML=a}),this):this[0].innderHTML},e.attr=function(a,b){return void 0!==b?(this.forEach(function(c){c.setAttribute(a,b)}),this):this[0].getAttribute(a)},e.data=function(a,c){return a=b(a),void 0!==c?(this.forEach(function(b){b.dataset[a]=c}),this):this[0].dataset[a]},e.val=function(a){return void 0!==a?(this.forEach(function(b){b.value=a}),this):this[0].value?this[0].value:void 0},e.style=function(a,c){return void 0!==c?this.forEach(function(d){d.style[b(a)]=c}):a instanceof Object?this.forEach(function(c){Object.keys(a).forEach(function(d){c.style[b(d)]=a[d]})}):this[0].style[b(a)]},e.insert=function(a,b){return this.forEach(function(c){"string"==typeof b?c.insertAdjacentHTML(a,b):b instanceof HTMLElement&&c.insertAdjacentElement(a,b)}),this},e.remove=function(){this.forEach(function(a){a.parentNode.removeChild(a)})},e.rect=function(){var a=this[0].getBoundingClientRect();return a.x=this[0].offsetLeft,a.y=this[0].offsetTop,a},e.unique=function(){return this.filter(function(a,b,c){return c.indexOf(a)===b})},["reverse","slice","filter"].forEach(function(a){e[a]=function(){return c([][a].apply(this,arguments))}}),a.nq=c}(this); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment