vquery
Version:
A simple, light-weight, vanilla JS wrapper for jQuery-like syntax.
907 lines (869 loc) • 26.3 kB
JavaScript
'use strict';
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var V = function () {
function V(selector) {
var _this = this;
var context = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : { methodHistory: [], selectorHistory: [] };
_classCallCheck(this, V);
if (!(this instanceof V)) {
return new V(selector);
}
if (selector instanceof V) {
return selector;
}
if (selector && selector.nodeName) {
selector = [selector];
if (!this.selector) {
this.selector = selector;
}
}
this.version = '5.0.1';
this.methodHistory = context.methodHistory;
if (context.selectorHistory.length === 0) {
this.selectorHistory = [];
this.selectorHistory.push(selector);
} else {
this.selectorHistory = context.selectorHistory;
}
// Utility functions
this.error = function (msg, selector, method, parameters) {
var errMsg = function errMsg(msg) {
console.error('vQuery: ' + msg + '\nAcceptable parameters: v(' + selector + ').' + method + '(' + parameters + ')');
};
if (msg === 'undefinedNode') {
errMsg('Selector is not a valid node.');
} else if (msg === 'notType') {
errMsg('Parameter passed to the ' + method + ' method is not of the type \'' + parameters + '\'.');
} else {
errMsg(msg);
}
};
this.isElement = function (element) {
return element instanceof Element || element[0] instanceof Element;
};
this.queryElement = function (element) {
return _this.isElement(element) ? element : _this.query(document, element)[0];
};
this.queryParameter = function (param, checkNodes) {
if (checkNodes) {
return _this.nodes ? _this.nodes : _this.nonElement ? _this.nonElement : param;
} else {
return _this.nonElement ? _this.nonElement : param;
}
};
this.assignNodes = function (nodes) {
_this.nodes = _this.slice(nodes);
_this.node = _this.nodes.length > 0 ? _this.nodes[0] : null;
};
this.handler = function (data, opts) {
// If the selector is updated, start a new instance with the updated selector.
var _selector = data ? data : _this.selector ? _this.selector : selector;
_this.selectorHistory.push(_selector);
_this.methodHistory.push(opts.method);
return new V(_selector, {
selectorHistory: _this.selectorHistory,
methodHistory: _this.methodHistory
});
};
this.slice = function (nodeList) {
return Array.prototype.slice.call(nodeList);
};
// Assign the selector by calling this.query if its an element, otherwise assign it to this.nodes directly.
var isStringElement = null;
if (selector) {
if (this.typeOf(selector) === 'string') {
try {
isStringElement = selector.match(/<(.|\n)*?>/g)[0];
} catch (e) {}
if (isStringElement) {
this.nonElement = selector;
this.assignNodes(this.parseHTML(selector));
} else {
try {
this.assignNodes(this.query(document, selector));
} catch (e) {
this.nonElement = selector;
}
}
if (!this.node) {
this.nonElement = selector;
}
} else if (isStringElement) {
this.nonElement = selector;
this.assignNodes(this.parseHTML(selector));
} else {
if (this.isElement(selector)) {
this.assignNodes(selector);
} else {
this.nodes = selector;
this.node = this.nodes[0];
}
}
this.length = this.nodes ? this.nodes.length : this.nonElement ? this.nonElement.length : 0;
}
}
_createClass(V, [{
key: 'for',
value: function _for(iterator, func) {
if (iterator !== undefined) {
for (var i = 0, len = iterator.length; i < len; i++) {
func.apply(this, [iterator[i], i, arguments]);
}
}
}
}, {
key: 'forIn',
value: function forIn(props, func) {
for (var y in props) {
func.apply(this, [y, props, arguments]);
}
}
}, {
key: 'includes',
value: function includes(string, match) {
return string.indexOf(match) > -1;
}
}, {
key: 'typeOf',
value: function typeOf(input) {
return Object.prototype.toString.call(input).replace(/^\[object (.+)\]$/, '$1').toLowerCase();
}
}, {
key: 'move',
value: function move(fromIndex, toIndex) {
try {
this.nodes = this.nodes.splice(toIndex, 0, this.nodes.splice(fromIndex, 1)[0]);
return this.handler(null, { method: 'move' });
} catch (e) {
this.error('notType', '', 'move', 'array');
}
}
}, {
key: 'uniq',
value: function uniq(array) {
var _array = array ? array : this.nonElement ? this.nonElement : this.nodes ? this.nodes : null;
var uniq = Array.from(new Set(_array));
if (array) {
return uniq;
} else {
this.selector = uniq;
return this.handler(null, { method: 'uniq' });
}
}
// Turn the CSS selector into a node, pass an existing node to this.nodes, which is used by all methods.
}, {
key: 'query',
value: function query(el, _selector) {
return el.querySelectorAll(_selector);
}
}, {
key: 'parseHTML',
value: function parseHTML(string) {
var tmp = document.implementation.createHTMLDocument();
tmp.body.innerHTML = this.nonElement ? this.nonElement : string;
return tmp.body.children;
}
}, {
key: 'mixin',
value: function mixin(_mixin) {
for (var prop in _mixin) {
if (_mixin.hasOwnProperty(prop)) {
V.prototype[prop] = _mixin[prop];
}
return V.prototype[prop].apply(this, [this.nodes, arguments]);
}
}
}, {
key: 'ajax',
value: function ajax(type, url, options) {
var _this2 = this;
var Promise = require('promise-polyfill');
var setAsap = require('setasap');
Promise._setImmediateFn(setAsap);
return new Promise(function (resolve, reject) {
var _resolve = function _resolve(data) {
var _data = options && options.chain ? _this2.handler(data, { method: 'ajax' }) : data;
if (typeof _data !== 'undefined' && _data) {
resolve(_data);
}
};
var request = new XMLHttpRequest();
request.open(type, url, true);
var data = void 0;
if (type.toLowerCase() === 'post') {
// Check if options.data is JSON, if not, send as application/x-www-form-urlencoded
try {
options.data = JSON.stringify(options.data);
request.setRequestHeader('Content-Type', 'application/json; charset=UTF-8');
} catch (e) {
request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
}
request.send(options.data);
}
request.onload = function () {
if (request.status >= 200 && request.status < 400) {
try {
data = JSON.parse(request.responseText);
} catch (e) {
data = request.responseText;
}
_resolve(data);
} else {
reject();
}
};
if (type.toLowerCase() === 'get') {
request.send();
}
request.onerror = function (err) {
reject(err);
};
});
}
// v(selector).get(0) -> <div></div>
}, {
key: 'get',
value: function get(i) {
this.selector = this.nodes[i];
return this.handler(null, { method: 'get' });
}
// Event methods
}, {
key: 'ready',
value: function ready(func) {
if (func && func !== undefined && typeof func === 'function') {
document.addEventListener('DOMContentLoaded', func);
} else {
this.error('notType', '', 'ready', 'function');
}
}
}, {
key: 'load',
value: function load(func) {
if (func && func !== undefined && typeof func === 'function') {
document.addEventListener('load', func);
} else {
this.error('notType', '', 'load', 'function');
}
}
}, {
key: 'on',
value: function on(event, func) {
this.for(this.nodes, function (i) {
i.addEventListener(event, func);
});
return this.handler(null, { method: 'on' });
}
}, {
key: 'off',
value: function off(event, func) {
this.for(this.nodes, function (i) {
i.removeEventListener(event, func);
});
return this.handler(null, { method: 'off' });
}
}, {
key: 'trigger',
value: function trigger(event) {
if (this.node.fireEvent) {
this.node.fireEvent('on' + event);
} else {
var evObj = document.createEvent('Events');
evObj.initEvent(event, true, false);
this.node.dispatchEvent(evObj);
}
return this.handler(null, { method: 'trigger' });
}
}, {
key: 'click',
value: function click(func) {
var _this3 = this;
this.for(this.nodes, function (i) {
if (func) {
_this3.on('click', func);
} else {
_this3.trigger('click');
}
});
return this.handler(null, { method: 'click' });
}
// DOM traversal and manipulation methods
}, {
key: 'filter',
value: function filter(func) {
Array.prototype.filter.call(this.nodes, func);
return this.handler(null, { method: 'filter' });
}
}, {
key: 'each',
value: function each(func) {
Array.prototype.forEach.call(this.nodes, func);
return this.handler(null, { method: 'each' });
}
}, {
key: 'map',
value: function map(func) {
Array.prototype.map.call(this.nodes, func);
return this.handler(null, { method: 'map' });
}
}, {
key: 'find',
value: function find(_selector) {
var _this4 = this;
if (!this.isElement(_selector)) {
if (this.includes(_selector, ',')) {
(function () {
var __selector = _selector.split(',');
var newSelector = [];
var subset = [];
_this4.for(__selector, function (i) {
subset = _this4.query(_this4.node, i);
_this4.for(subset, function (y) {
newSelector.push(y);
});
});
_this4.selector = newSelector;
})();
} else {
this.selector = this.query(this.node, _selector);
}
} else {
this.selector = _selector;
}
return this.handler(null, { method: 'find' });
}
}, {
key: 'end',
value: function end() {
this.selector = this.selectorHistory[0];
return this.handler(null, { method: 'end' });
}
}, {
key: 'hide',
value: function hide() {
this.for(this.nodes, function (i) {
i.style.display = 'none';
});
return this.handler(null, { method: 'hide' });
}
}, {
key: 'show',
value: function show() {
this.for(this.nodes, function (i) {
i.style.display = 'block';
});
return this.handler(null, { method: 'show' });
}
}, {
key: 'remove',
value: function remove() {
this.for(this.nodes, function (i) {
i.parentNode.removeChild(i);
});
return this.handler(null, { method: 'remove' });
}
}, {
key: 'empty',
value: function empty() {
this.for(this.nodes, function (i) {
i.innerHTML = '';
});
return this.handler(null, { method: 'empty' });
}
}, {
key: 'clone',
value: function clone() {
var clone = this.node.cloneNode(true);
this.selector = clone;
return this.handler(null, { method: 'clone' });
}
}, {
key: 'wrap',
value: function wrap(tag) {
this.for(this.nodes, function (i) {
i.outerHTML = '' + tag.match(/<(.|\n)*?>/g)[0] + i.outerHTML;
});
return this.handler(null, { method: 'wrap' });
}
}, {
key: 'parent',
value: function parent() {
this.selector = this.node.parentNode;
return this.handler(null, { method: 'parent' });
}
}, {
key: 'parents',
value: function parents(el) {
var _this5 = this;
var parent = this.node.parentNode;
var _parents = [];
while (parent) {
_parents.unshift(parent);
parent = parent.parentNode;
}
if (el) {
(function () {
var __parents = [];
var _parentsQuery = [];
_this5.for(_parents, function (i) {
__parents = _this5.slice(_this5.query(i, el));
_this5.for(__parents, function (y) {
_parentsQuery.push(y);
});
});
_this5.selector = _this5.uniq(_parentsQuery);
})();
} else {
this.selector = _parents;
}
return this.handler(null, { method: 'parents' });
}
}, {
key: 'children',
value: function children(el) {
var _this6 = this;
var children = this.slice(this.nodes[0].children);
if (el) {
(function () {
var _children = [];
var arr = [];
_this6.for(children, function (i) {
_children = _this6.slice(_this6.query(i, el));
_this6.for(_children, function (y) {
arr.push(_children[y]);
});
});
_this6.selector = arr;
})();
} else {
this.selector = children;
}
return this.handler(null, { method: 'children' });
}
}, {
key: 'allChildren',
value: function allChildren(_el) {
var _this7 = this;
var __el = _el ? this.slice(this.query(this.node, _el))[0] : this.node;
var arr = [];
var recurse = function recurse(el) {
arr.push(el);
if (el.childNodes.length > 0) {
_this7.forIn(el.childNodes, function (child) {
if (el.childNodes[child].nodeType == 1) {
recurse(el.childNodes[child]);
}
});
}
};
recurse(__el);
this.selector = arr;
return this.handler(null, { method: 'allChildren' });
}
}, {
key: 'isEmpty',
value: function isEmpty() {
return !this.node.hasChildNodes();
}
}, {
key: 'siblings',
value: function siblings() {
var _this8 = this;
this.nodes = this.node.parentNode.children;
return this.filter(function (child) {
return child !== _this8.node;
});
}
}, {
key: 'next',
value: function next() {
this.selector = this.node.nextElementSibling;
return this.handler(null, { method: 'next' });
}
}, {
key: 'prev',
value: function prev() {
this.selector = this.node.previousElementSibling;
return this.handler(null, { method: 'prev' });
}
}, {
key: 'addClass',
value: function addClass(_class) {
var _this9 = this;
var classArr = _class.split(' ');
this.for(this.nodes, function (i) {
_this9.for(classArr, function (y) {
i.classList.add(y);
});
});
return this.handler(null, { method: 'addClass' });
}
}, {
key: 'removeClass',
value: function removeClass(_class) {
var _this10 = this;
var classArr = _class.split(' ');
this.for(this.nodes, function (i) {
_this10.for(classArr, function (y) {
i.classList.remove(y);
});
});
return this.handler(null, { method: 'removeClass' });
}
}, {
key: 'toggleClass',
value: function toggleClass(_class) {
var _this11 = this;
var classArr = _class.split(' ');
this.for(this.nodes, function (i) {
_this11.for(classArr, function (y) {
i.classList.toggle(y);
});
});
return this.handler(null, { method: 'toggleClass' });
}
}, {
key: 'hasClass',
value: function hasClass(_class) {
var bool = this.node.classList.contains(_class);
return bool;
}
}, {
key: 'removeAttr',
value: function removeAttr(attr) {
this.for(this.nodes, function (i) {
i.removeAttribute(attr);
});
return this.handler(null, { method: 'removeAttr' });
}
// v(selector).attr() returns an object of camelized attribute keys.
// v(selector).attr({dataId: '0'}) -> <div data-id="0"></div>
}, {
key: 'attr',
value: function attr(props, props2) {
var _this12 = this;
var _return = null;
this.for(this.nodes, function (i) {
if (props) {
if (props2 && _this12.typeOf(props2) === 'string') {
i.setAttribute(_this12.decamelize(props), props2);
_return = _this12.handler(null, { method: 'attr' });
} else {
_this12.forIn(props, function (y) {
if (_this12.typeOf(props) === 'string') {
_return = i.attributes[props].value;
} else {
i.setAttribute(_this12.decamelize(y), props[y]);
_return = _this12.handler(null, { method: 'attr' });
}
});
}
} else {
var obj = {};
var name = null;
var value = null;
_this12.for(i.attributes, function (z) {
name = _this12.camelize(z.name);
value = z.value;
obj[name] = value;
});
_return = obj;
}
});
return _return;
}
// v(selector).css({backgroundColor: '#FFF'}) -> <div style="background-color:#FFF;"></div>
}, {
key: 'css',
value: function css(props) {
var _this13 = this;
if (props) {
this.for(this.nodes, function (i) {
_this13.forIn(props, function (y) {
i.style[y] = props[y];
});
});
return this.handler(null, { method: 'css' });
} else {
if (this.isElement(this.node)) {
return getComputedStyle(this.node);
} else {
return {};
}
}
}
}, {
key: 'val',
value: function val(string) {
if (string) {
this.for(this.nodes, function (i) {
i.value = string;
});
return this.handler(null, { method: 'val' });
} else {
return this.node.value;
}
}
}, {
key: 'rect',
value: function rect() {
return this.node.getBoundingClientRect();
}
}, {
key: 'offset',
value: function offset() {
var rect = this.rect();
var offset = {
top: rect.top + document.body.scrollTop,
left: rect.left + document.body.scrollLeft
};
return offset;
}
}, {
key: 'offsetParent',
value: function offsetParent() {
return this.node.offsetParent || this.node;
}
}, {
key: 'height',
value: function height(withMargin) {
var height = this.node.offsetHeight;
if (withMargin) {
var style = this.css();
height += parseInt(style.marginTop) + parseInt(style.marginBottom);
}
return height;
}
}, {
key: 'width',
value: function width(withMargin) {
var width = this.node.offsetWidth;
if (withMargin) {
var style = this.css();
width += parseInt(style.marginTop) + parseInt(style.marginBottom);
}
return width;
}
}, {
key: 'position',
value: function position(withMargin) {
if (typeof this.node !== 'undefined') {
return { left: this.node.offsetLeft, top: this.node.offsetTop };
} else {
this.error('undefinedNode', 'node', 'position', 'withMargin');
}
}
}, {
key: 'html',
value: function html(contents) {
var output = [];
this.for(this.nodes, function (i) {
if (!contents) {
output.push(i.outerHTML);
} else {
i.innerHTML = contents;
}
});
return contents ? this.handler(null, { method: 'html' }) : output;
}
}, {
key: 'json',
value: function json(input) {
var _input = this.nodes ? this.nodes : this.nonElement ? this.nonElement : input;
try {
return JSON.stringify(_input);
} catch (e) {
this.error(e, '', 'json', 'serializable input');
}
}
}, {
key: 'parseJSON',
value: function parseJSON(string) {
string = this.nonElement ? this.nonElement : string;
try {
var output = JSON.parse(string);
return output;
} catch (e) {
this.error(e, '', 'parseJSON', 'valid JSON');
}
}
}, {
key: 'type',
value: function type(input) {
input = this.queryParameter(input, true);
return this.nodes && this.isElement(this.nodes) ? 'node' : this.typeOf(input);
}
}, {
key: 'replaceWith',
value: function replaceWith(string) {
var _this14 = this;
this.for(this.nodes, function (i) {
if (string && typeof string === 'string') {
i.outerHTML = string;
return _this14.handler(null, { method: 'replaceWith' });
} else {
_this14.error('notType', '', 'replaceWith', 'string');
}
});
}
}, {
key: 'text',
value: function text(contents) {
var output = [];
this.for(this.nodes, function (i) {
if (!contents) {
output.push(i.textContent);
} else {
i.textContent = contents;
}
});
return contents ? this.handler(null, { method: 'text' }) : output;
}
}, {
key: 'insertBefore',
value: function insertBefore(el) {
var _element = this.queryElement(el);
this.for(this.nodes, function (i) {
_element.parentNode.insertBefore(i, _element.parentNode.firstChild);
});
return this.handler(null, { method: 'insertBefore' });
}
}, {
key: 'insertAfter',
value: function insertAfter(el) {
var _element = this.queryElement(el);
this.for(this.nodes, function (i) {
_element.parentNode.insertBefore(i, _element.parentNode.nextSibling);
});
return this.handler(null, { method: 'insertAfter' });
}
}, {
key: 'prepend',
value: function prepend(el) {
var _element = this.queryElement(el);
this.for(this.nodes, function (i) {
i.insertBefore(_element, i.firstChild);
});
return this.handler(null, { method: 'prepend' });
}
}, {
key: 'append',
value: function append(el) {
var _element = this.queryElement(el);
this.for(this.nodes, function (i) {
i.appendChild(_element);
});
return this.handler(null, { method: 'append' });
}
}, {
key: 'after',
value: function after(string) {
this.for(this.nodes, function (i) {
i.insertAdjacentHTML('afterend', string);
});
return this.handler(null, { method: 'after' });
}
}, {
key: 'before',
value: function before(string) {
this.for(this.nodes, function (i) {
i.insertAdjacentHTML('beforebegin', string);
});
return this.handler(null, { method: 'before' });
}
}, {
key: 'contains',
value: function contains(text) {
var textContent = null;
if (this.nonElement) {
textContent = this.nonElement;
} else {
textContent = this.node.textContent;
}
var bool = this.includes(this.node.textContent, text);
return bool;
}
}, {
key: 'is',
value: function is(el) {
var _el = this.queryElement(el);
return this.node === _el;
}
}, {
key: 'inViewport',
value: function inViewport() {
var rect = this.rect();
return rect.top >= 0 && rect.left >= 0 && rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && rect.right <= (window.innerWidth || document.documentElement.clientWidth);
}
}, {
key: 'inIframe',
value: function inIframe() {
try {
return window.self !== window.top;
} catch (e) {
return true;
}
}
}, {
key: 'trim',
value: function trim(string) {
string = this.queryParameter(string, true);
return string.trim();
}
// Used by attr method
}, {
key: 'camelize',
value: function camelize(string) {
string = this.queryParameter(string, false);
return string.replace(/(?:^\w|[A-Z]|\b\w)/g, function (letter, index) {
return index === 0 ? letter.toLowerCase() : letter.toUpperCase();
}).replace(/\s+/g, '').replace(/[-_]+/g, '');
}
}, {
key: 'decamelize',
value: function decamelize(string) {
string = this.queryParameter(string, false);
return string.replace(/([a-z])([A-Z])/g, '$1-$2').replace(/\b([A-Z]+)([A-Z])([a-z])/, '$1-$2$3').replace(/^./, function (str) {
return str.toLowerCase();
});
}
}, {
key: 'noConflict',
value: function noConflict() {
var _v = v;
window.v = window.oldV;
return _v;
}
// Aliases
}, {
key: 'n',
get: function get() {
return this.node;
}
}, {
key: 'ns',
get: function get() {
return this.nodes;
}
}, {
key: 'ne',
get: function get() {
return this.nonElement;
}
}]);
return V;
}();
var v = function v(selector) {
return new V(selector);
};
window.v = v;
if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
module.exports = v;
} else {
if (typeof define === 'function' && define.amd) {
define([], function () {
return v;
});
}
}