ts-query
Version:
its simple library for dom control.
814 lines (738 loc) • 22.1 kB
JavaScript
var $ = (function (W, D) {
"use strict";
var pr = "prototype",
c = "constructor",
d = "document",
w = "window",
co = console,
A = Array;
/**
* @class E
* @param {HTMLElement|HTMLInputElement} node
* @constructor
*/
var E = function (node) {
/**
* Объект для хранения временных данных
* @type {{}}
* @private
*/
this._state = {};
/**
* элемент
* @type {HTMLElement|HTMLInputElement}
* @private
*/
this._node = node;
};
/**
* Ссылка на прототип для быстрой и компактной записи (профит при обфусцировании)
* @type {Object}
*/
var ep = E.prototype;
/**
* Получаем или ставим атрибут
* @param {string} name
* @param {string} [value]
* @returns {string|null}
*/
ep.attr = function (name, value) {
if (E._hasVal(value)) {
this._node.setAttribute(name, value);
} else {
return this._node.getAttribute(name) || "";
}
};
/**
* Добавляем класс
* @param {string} className
*/
ep.addClass = function (className) {
if (!this.hasClass(className)) {
var classList = this._node.className.split(" ");
classList.push(className);
this._node.className = $.trim(classList.join(" "));
}
};
/**
* Убираем класс
* @param {string} className
*/
ep.removeClass = function (className) {
if (this.hasClass(className)) {
var classList = this._node.className.split(" ");
classList.splice(classList.indexOf(className), 1);
this._node.className = $.trim(classList.join(" "));
}
};
/**
* Добавляем/получаем стили элемента
* @param {string|Object} name
* @param [value]
* @returns {string|*}
*/
ep.css = function (name, value) {
if (typeof name == "object") {
$.forEach(name, function (value, name) {
this._setCss(name, value);
}, this);
return this;
}
if (E._hasVal(value)) {
this._setCss(name, value);
} else {
return this._getCss(name);
}
};
/**
* Скрываем элемент
* @returns {ep}
*/
ep.hide = function () {
var display = this.css('display');
if (display != 'none') {
this._state.display = display;
this.css('display', 'none');
}
return this;
};
/**
* Показываем элемент
* @returns {ep}
*/
ep.show = function () {
var display = this.css('display');
if (display === 'none') {
this.css('display', this._state.display || 'block');
}
return this;
};
/**
* Скрываем или показываем элемент
* @param {boolean} state
* @returns {ep}
*/
ep.toggleDisplay = function (state) {
if (!E._hasVal(state)) {
state = (this.css('display') == 'none');
}
return (state ? this.show() : this.hide());
};
/**
* Добавляем/убираем класс
* @param {string} className
* @param {boolean} [state]
*/
ep.toggleClass = function (className, state) {
if (!E._hasVal(state)) {
state = !this.hasClass(className);
}
return (state ? this.addClass(className) : this.removeClass(className));
};
/**
* Добавляем/получаем value элемента
* @param {string} [value]
* @returns {string|string}
*/
ep.val = function (value) {
if (E._hasVal(value)) {
this._node.value = value;
} else {
return this._node.value || "";
}
};
/**
* Проверяем наличие класса
* @param {string} className
* @returns {boolean}
*/
ep.hasClass = function (className) {
return (this._node.className.split(" ").indexOf(className) != -1);
};
/**
* Удаляем атрибут
* @param {string} name
*/
ep.removeAttr = function (name) {
this._node.removeAttribute(name);
};
["width", "height"].forEach(function (method) {
ep[method] = function (param) {
if (E._hasVal(param)) {
this._setCss(method, typeof param == "number" ? param + "px" : param);
} else {
return this._node[$.camelCase("client " + method)] || parseInt(this._getCss(method)) || 0;
}
}
});
/**
* Добавляем/получаем содержимое элемента
* @param {string} [html]
* @returns {string}
*/
ep.html = function (html) {
if (E._hasVal(html)) {
this._node.innerHTML = html;
} else {
return this._node.innerHTML;
}
};
ep.remove = function () {
this._remove();
if (this._node.parentNode) {
this._node.parentNode.removeChild(this._node);
}
};
ep._remove = function () {
};
/**
* Устанавливаем стиль элемента
* @param {string} name
* @param {string} value
* @private
*/
ep._setCss = function (name, value) {
var $name;
name = $.camelCase(name);
if (!(name in E.test.style)) {
if (!E._activePrefix) {
if (!E._prefexes.some(function (prefix) {
var $name = $.camelCase(prefix + name);
if ($name in E.test.style) {
E._activePrefix = prefix;
name = $name;
return true;
}
})) {
co.warn("Не удалось найти префикс!", name, value);
}
} else {
$name = $.camelCase(E._activePrefix + name);
if ($name in E.test.style) {
name = $name;
} else {
co.warn("Не корректный стиль!", name, value);
}
}
}
this._node.style[name] = value;
};
/**
* Получаем стиль
* @param {string} name
* @returns {string}
* @private
*/
ep._getCss = function (name) {
name = $.camelCase(name);
var styles = [this._node.style, getComputedStyle(this._node)];
var result = styles[0][name] || styles[1][name] || "";
var check = function (name, callback) {
return styles.some(function (style) {
var $name = $.camelCase(name);
if ($name in style) {
result = style[$name];
callback ? callback() : false;
return true;
}
});
};
if (!result) {
if (E._activePrefix) {
if (!check(E._activePrefix + name)) {
co.warn("Не удалось получить стиль!", name);
}
} else {
if (!E._prefexes.some(function (prefix) {
return check(prefix + name, function () {
E._activePrefix = prefix;
});
})) {
co.warn("Не удалось получить стиль и префикс!", name);
}
}
}
return result;
};
/**
* Проверяет наличие значения
* @param val
* @returns {boolean}
* @private
*/
E._hasVal = function (val) {
return val != undefined;
};
E._createE = function (node) {
return new E(node);
};
/**
* Активный префикс
* @type {string}
* @private
*/
E._activePrefix = "";
/**
* Массив префиксов браузеров
* @type {string[]}
* @private
*/
E._prefexes = [
"-moz-",
"-ms-",
"-webkit-",
"-o-"
];
/**
* @type {HTMLElement}
*/
E.test = D.createElement("DIV");
/**
* @class $
* @extends Array
* @param param
* @returns {$}
*/
var $ = function $(param) {
if (this instanceof $) {
A[pr].forEach.call(arguments, function (arg) {
this.add(arg);
}, this);
} else {
return new $(param);
}
};
$[pr] = [];
$[pr][c] = $;
var p = $.prototype;
["addClass", "removeClass", "toggleClass", "removeAttr", "show", "hide", "toggleDisplay"].forEach(function (method) {
p[method] = function (className) {
this._toAll(method, [className]);
return this;
};
});
["val", "html", "width", "height"].forEach(function (method) {
p[method] = function (val) {
return this._setOrGet(method, val);
}
});
["attr"].forEach(function (method) {
p[method] = function (name, value) {
return this._setOrGet(method, value, name);
}
});
/**
* Добавляем элементы
* @param param
* @return $
*/
p.add = function (param) {
if (A.isArray(param)) {
param.forEach(this.add, this);
} else {
this._toElem(param).forEach(function (el) {
this.push(el);
}, this);
}
return this;
};
/**
* Проверяет наличие класса у первого элемента коллекции
* @param {string} className
* @returns {boolean}
*/
p.hasClass = function (className) {
if (!this._has()) return false;
return this[0].hasClass(className);
};
/**
* Ищем элементы в первом элементе коллекции
* @param selector
* @returns {$}
*/
p.find = function (selector) {
if (!this._has()) return this;
return new $(A[pr].slice.call(this[0]._node.querySelectorAll(selector)));
};
/**
* Получаем копию ноды первого элемента коллекции
* @returns {$}
*/
p.clone = function () {
if (!this._has()) return this;
return new $(this[0]._node.cloneNode(true));
};
/**
* Применяем стили всем элементам коллекции или получаем стиль первого
* @param {string|Object} name
* @param {string} [value]
* @returns {string|$}
*/
p.css = function (name, value) {
if (typeof name == "object") {
return this._toAll("css", [name]);
} else {
if (E._hasVal(value)) {
return this._toAll("css", [name, value]);
} else {
return this[0].css(name);
}
}
};
/**
* Перебираем все элементы коллекции
* @param callback
* @returns {$}
*/
p.each = function (callback) {
this.forEach(function (el, index) {
callback(this.eq(index), el._node, index);
}, this);
return this;
};
/**
* Получаем коллекцию элементов дочерних первому элементу коллекции
* @returns {$}
*/
p.children = function () {
if (!this._has()) return this;
return new $(A[pr].slice.call(this[0]._node.childNodes));
};
/**
* Получаем новую коллекцию с элементом по номеру
* @param index
* @returns {$}
*/
p.eq = function (index) {
if (!this._has()) return this;
return new $(this[index || 0]);
};
/**
* Получаем ДОМ элемент из коллекции по номеру
* @param index
* @returns {HTMLElement|null}
*/
p.get = function (index) {
if (!this._has()) return null;
return this[index || 0]._node;
};
/**
* Получаем коллекцию из родительского элемента
*/
p.parent = function () {
if (!this._has()) return this;
return new $(this[0]._node.parentNode);
};
/**
* Добавляем в конец набора элементов
* @param param
* @returns {$}
*/
p.append = function (param) {
if (!this._has()) return this;
this._toElem(param, true).forEach(function (elem) {
this[0]._node.appendChild(elem._node);
}, this);
};
/**
* Добавляем в начало набора элементов
* @param param
* @returns {$}
*/
p.prepend = function (param) {
if (!this._has()) return this;
this._toElem(param, true).forEach(function (elem) {
var childs = A[pr].filter.call(this[0]._node.childNodes, function (el) {
return $.isElement(el)
});
if (childs.length) {
this[0]._node.insertBefore(elem._node, childs[0]);
} else {
this[0]._node.appendChild(elem._node);
}
}, this);
};
/**
* Приводим элементы к 1 типу
* @param param
* @param notSelector
* @returns {*}
* @private
*/
p._toElem = function (param, notSelector) {
if ($.isElement(param)) {
return [E._createE(param)];
} else if (param instanceof E) {
return [param];
} else if (param instanceof $) {
return [param[0]];
} else if (typeof param == "string") {
if (/<.+?>/.test(param)) {
return $.parse(param).map(function (el) {
return E._createE(el)
});
} else {
if (notSelector) {
return [{_node: document.createTextNode(param)}];
} else {
return A[pr].slice.call(D.querySelectorAll(param)).map(function (el) {
return E._createE(el)
});
}
}
} else {
co.log("wrong param!", param);
return [];
}
};
/**
* Выполняем для всех элементов коллекции
* @param method
* @param args
* @returns {$}
* @private
*/
p._toAll = function (method, args) {
this.forEach(function (elem) {
elem[method].apply(elem, args);
});
return this;
};
/**
* Проверяем есть ли элементы в коллекции
* @returns {boolean}
* @private
*/
p._has = function () {
if (!this.length) {
co.warn("not length!");
return false;
} else {
return true;
}
};
/**
* Задаем или получаем данные для элементов коллекции
* @param method
* @param argToCheck
* @param [arg]
* @returns {*}
* @private
*/
p._setOrGet = function (method, argToCheck, arg) {
if (!this._has()) return this;
if (E._hasVal(argToCheck)) {
var args = arg ? [arg, argToCheck] : [argToCheck];
this._toAll(method, args);
return this;
} else {
return this[0][method](arg);
}
};
/**
* Парсим строку превращая её в ДОМ
* @param html
* @returns {Array}
*/
$.parse = function (html) {
var div = D.createElement("div");
div.innerHTML = html;
return A[pr].filter.call(div.childNodes, function (elem) {
return $.isElement(elem);
});
};
/**
* @param {number} min
* @param {number} max
* @returns {number}
*/
$.random = function (min, max) {
return Math.random() * (max - min) + min;
};
/**
* @param {number} min
* @param {number} max
* @returns {number}
*/
$.randomInt = function (min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
};
/**
* @param {string} text
* @returns {string}
*/
$.trim = (function () {
if ("trim" in String[pr]) {
return function (text) {
return text.trim();
}
}
return function (text) {
return (text || "").replace(/^\s+|\s+$/g, "");
}
})();
/**
* @param {string} text
* @returns {string}
*/
$.camelCase = function (text) {
return text.split(/[^\d\w]/).map(function (str, index) {
return index ? str.charAt(0).toUpperCase() + str.substr(1) : str;
}).join("");
};
/**
* @returns {string}
*/
$.guuid = function () {
return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
s4() + '-' + s4() + s4() + s4();
};
/**
* @param some
* @returns {boolean}
*/
$.isElement = function (some) {
return ((some instanceof Node) && (some["nodeType"] == 1));
};
/**
* @param {Object|Array} some
* @param {function} callback
* @param {*} [context]
* @param {*} [argument]
*/
$.forEach = function (some, callback, context, argument) {
if (A.isArray(some)) {
some.forEach(function (value, id) {
callback.call(context || this, value, id, argument);
});
} else {
Object.keys(some).forEach(function (name) {
callback.call(context || this, some[name], name, argument);
});
}
};
/**
* @param {Object|Array} some
* @param {function} callback
* @param {*} [context]
* @param {*} [argument]
* @returns {boolean}
*/
$.some = function (some, callback, context, argument) {
if (A.isArray(some)) {
return some.some(function (value, index) {
return callback.call(context || this, value, index, argument);
});
} else {
return Object.keys(some).some(function (name) {
return callback.call(context || this, some[name], name, argument);
});
}
};
/**
* @param {Object|Array} some
* @param {function} callback
* @param {*} [context]
* @param {*} [argument]
* @returns {boolean}
*/
$.every = function (some, callback, context, argument) {
return !$.some(some, function (value, name) {
return !callback.call(context || this, value, name, argument);
});
};
/**
* @param {Object|Array} some
* @param {function} callback
* @param {*} [context]
* @param {*} [argument]
* @returns {{id: null, value: null}}
*/
$.findFirst = function (some, callback, context, argument) {
var result = {
id: null,
value: null
};
$.some(some, function (value, id) {
if (callback.call(context || window, value, id, argument)) {
result = {
id: id,
value: value
};
return true;
}
});
return result;
};
$.floor = function (num) {
return (num + 0.5) << 0;
};
$.roundTo = function (num, count) {
var d = Math.pow(10, count);
return $.floor(num * d) / d;
};
$.addPlugin = function (callback) {
callback($, E);
};
$.events = {};
/**
* Проверяем если винда с mcPointer
* @type {boolean}
*/
$.isPointer = false;
/**
* @returns {string}
*/
function s4() {
return Math.floor((1 + Math.random()) * 0x10000)
.toString(16)
.substring(1);
}
var getEventSupport = function (event) {
event = "on" + event;
var target = document.createElement("div");
target.setAttribute(event, "");
var isSupported = typeof target[event] === "function";
if (typeof target[event] !== "undefined") target[event] = null;
target.removeAttribute(event);
return isSupported;
};
var events = {
mouse: {
start: "mousedown",
move: "mousemove",
end: "mouseup"
},
mobile: {
start: "touchstart",
move: "touchmove",
end: "touchend"
},
win: {
start: "MSPointerDown",
move: "MSPointerMove",
end: "MSPointerUp"
}
};
(function () {
if (window.navigator.msPointerEnabled) {
$.events = events.win;
$.isPointer = true;
} else if (getEventSupport("touchmove")) {
$.events = events.mobile;
} else {
$.events = events.mouse;
}
})();
window["requestAnimationFrame"] = (function () {
return window.requestAnimationFrame ||
window["webkitRequestAnimationFrame"] ||
window["mozRequestAnimationFrame"] ||
window["oRequestAnimationFrame"] ||
window["msRequestAnimationFrame"] ||
function (callback) {
window.setTimeout(callback, 1000 / 60);
};
})();
return $;
})(window["$window"] || window, window["$document"] || document);