- // ==UserScript==
- // @name Include Tools
- // @namespace scriptomatika
- // @author mouse-karaganda
- // @description Общие инструменты для всех страничек
- // @version 1.33
- // @grant none
- // ==/UserScript==
-
- /* jshint esversion: 6 */
-
- var paramWindow = (typeof unsafeWindow === 'object') ? unsafeWindow : window;
-
- (function(unsafeWindow) {
- var console = unsafeWindow.console;
- var jQuery = unsafeWindow.jQuery;
-
- unsafeWindow.__krokodil = {
- /**
- * Отрисовывает элемент
- */
- renderElement: function(config) {
- // Определяем параметры по умолчанию
- var newRenderType = this.setRenderType(config.renderType);
- var newConfig = {
- // ~~~ название тега ~~~ //
- tagName: config.tagName || 'div',
- // ~~~ атрибуты тега ~~~ //
- attr: config.attr || {},
- // ~~~ идентификатор ~~~ //
- id: config.id,
- // ~~~ имя класса ~~~ //
- cls: config.cls,
- // ~~~ встроенные стили тега ~~~ //
- style: config.style || {},
- // ~~~ встроенные данные ~~~ //
- dataset: config.dataset || {},
- // ~~~ содержимое элемента ~~~ //
- innerHTML: this.join(config.innerHTML || ''),
- // ~~~ обработчики событий элемента ~~~ //
- listeners: config.listeners || {},
- // ~~~ родительский элемент для нового ~~~ //
- renderTo: this.getIf(config.renderTo),
- // ~~~ способ отрисовки: append (по умолчанию), insertBefore, insertAfter, insertFirst, none ~~~ //
- renderType: newRenderType
- };
- var newElement;
- if (newConfig.tagName == 'text') {
- // Создаем текстовый узел
- newElement = document.createTextNode(newConfig.innerHTML);
- } else {
- // Создаем элемент
- newElement = document.createElement(newConfig.tagName);
- // Добавляем атрибуты
- this.attr(newElement, newConfig.attr);
- // Добавляем идентификатор, если указан
- if (newConfig.id) {
- this.attr(newElement, { 'id': newConfig.id });
- }
- //console.log('newElement == %o, config == %o, id == ', newElement, newConfig, newConfig.id);
- // Добавляем атрибут класса
- if (newConfig.cls) {
- this.attr(newElement, { 'class': newConfig.cls });
- }
- // Наполняем содержимым
- newElement.innerHTML = newConfig.innerHTML;
- // Задаем стиль
- this.css(newElement, newConfig.style);
- // Задаем встроенные данные
- this.extend(newElement.dataset, newConfig.dataset);
- // Навешиваем события
- var confListeners = newConfig.listeners;
- for (var ev in confListeners) {
- if (ev != 'scope') {
- //console.log('this.on(newElement == %o, ev == %o, newConfig.listeners[ev] == %o, newConfig.listeners.scope == %o)', newElement, ev, newConfig.listeners[ev], newConfig.listeners.scope);
- this.on(newElement, ev, newConfig.listeners[ev], newConfig.listeners.scope);
- }
- }
- //console.log('После: tag == %o, listeners == %o', newConfig.tagName, confListeners);
- }
- // Отрисовываем элемент
- var target, returnRender = true;
- while (returnRender) {
- switch (newConfig.renderType) {
- // Не отрисовывать, только создать
- case this.enumRenderType['none']: {
- returnRender = false;
- break;
- };
- // Вставить перед указанным
- case this.enumRenderType['insertBefore']: {
- target = newConfig.renderTo || document.body.firstChild;
- // если элемент не задан - вернемся к способу по умолчанию
- if (target) {
- target.parentNode.insertBefore(newElement, target);
- returnRender = false;
- } else {
- newConfig.renderType = this.enumRenderType['default'];
- }
- break;
- };
- // Вставить после указанного
- case this.enumRenderType['insertAfter']: {
- // если элемент не задан - вернемся к способу по умолчанию
- if (newConfig.renderTo && newConfig.renderTo.nextSibling) {
- target = newConfig.renderTo.nextSibling;
- target.parentNode.insertBefore(newElement, target);
- returnRender = false;
- } else {
- newConfig.renderType = this.enumRenderType['default'];
- }
- break;
- };
- // Вставить как первый дочерний
- case this.enumRenderType['prepend']: {
- // если элемент не задан - вернемся к способу по умолчанию
- if (newConfig.renderTo && newConfig.renderTo.firstChild) {
- target = newConfig.renderTo.firstChild;
- target.parentNode.insertBefore(newElement, target);
- returnRender = false;
- } else {
- newConfig.renderType = this.enumRenderType['default'];
- }
- break;
- };
- // Вставить как последний дочерний
- case this.enumRenderType['append']:
- default: {
- var parent = newConfig.renderTo || document.body;
- parent.appendChild(newElement);
- returnRender = false;
- };
- }
- }
- // Возвращаем элемент
- return newElement;
- },
- /**
- * Отрисовать несколько одинаковых элементов подряд
- */
- renderElements: function(count, config) {
- for (var k = 0; k < count; k++) {
- this.renderElement(config);
- }
- },
- /**
- * Отрисовать текстовый узел
- */
- renderText: function(config) {
- // Упрощенные настройки
- var newConfig = {
- tagName: 'text',
- innerHTML: config.text,
- renderTo: config.renderTo,
- renderType: config.renderType
- };
- var newElement = this.renderElement(newConfig);
- return newElement;
- },
- /**
- * Отрисовать элемент style
- * @param {String} text Любое количество строк через запятую
- */
- renderStyle: function(text) {
- var stringSet = arguments;
- var tag = this.renderElement({
- tagName: 'style',
- attr: { type: 'text/css' },
- innerHTML: this.format('\n\t{0}\n', this.join(stringSet, '\n\t'))
- });
- return tag;
- },
- /**
- * Возможные способы отрисовки
- */
- enumRenderType: {
- 'append': 0,
- 'prepend': 1,
- 'insertBefore': 2,
- 'insertAfter': 3,
- 'none': 4,
- 'default': 0
- },
- // Назначает способ отрисовки
- setRenderType: function(renderType) {
- if (typeof renderType != 'string') {
- return this.enumRenderType['default'];
- }
- if (this.enumRenderType[renderType] == undefined) {
- return this.enumRenderType['default'];
- }
- return this.enumRenderType[renderType];
- },
- /**
- * Карта кодов клавиш
- */
- keyMap: {
- // Клавиши со стрелками
- arrowLeft: 37,
- arrowUp: 38,
- arrowRight: 39,
- arrowDown: 40
- },
- /**
- * Карта кодов символов
- */
- charMap: {
- arrowLeft: 8592, // ←
- arrowRight: 8594 // →
- },
- /**
- * Ждём, пока отрисуется элемент, и выполняем действия
- * @param {String} selector css-селектор для поиска элемента (строго строка)
- * @param {Function} callback Функция, выполняющая действия над элементом. this внутри неё — искомый DOM-узел
- * @param {Number} maxIterCount Максимальное количество попыток найти элемент
- */
- missingElement: function(selector, callback, maxIterCount) {
- var setLog = false;
- // Итерации 5 раз в секунду
- var missingOne = 100;
- // Ограничим количество попыток разумными пределами
- var defaultCount = 3000;
- if (!this.isNumber(maxIterCount)) {
- maxIterCount = defaultCount;
- }
- if (0 > maxIterCount || maxIterCount > defaultCount) {
- maxIterCount = defaultCount;
- }
- // Запускаем таймер на поиск
- var iterCount = 0;
- var elementTimer = setInterval(this.createDelegate(function() {
- // Сообщение об ожидании
- var secondsMsg = this.numberWithCase(iterCount, 'секунду', 'секунды', 'секунд');
- if (iterCount % 10 == 0) {
- if (setLog) console.log('missing: Ждём [%o] %s', selector, secondsMsg);
- }
- var element = this.getAll(selector);
- // Определим, что вышел элемент
- var elementStop = this.isIterable(element) && (element.length > 0);
- // Определим, что кончилось количество попыток
- var iterStop = (iterCount >= maxIterCount);
- if (elementStop || iterStop) {
- clearInterval(elementTimer);
- var elementExists = true;
- // Если элемент так и не появился
- if (!elementStop && iterStop) {
- if (setLog) console.log('missing: Закончились попытки [%o]', selector);
- elementExists = false;
- return;
- }
- // Появился элемент - выполняем действия
- if (setLog) console.log('missing: Появился элемент [%o] == %o', selector, element);
- if (this.isFunction(callback)) {
- if (element.length == 1) {
- element = element[0];
- }
- if (setLog) console.log('missing: Запускаем обработчик [%o] == %o', elementExists, element);
- callback.call(element, elementExists);
- }
- }
- iterCount++;
- }, this), missingOne);
- },
- /**
- * Добавить свойства в объект
- */
- extend: function(target, newProperties) {
- if (typeof newProperties == 'object') {
- for (var i in newProperties) {
- target[i] = newProperties[i];
- }
- }
- return target;
- },
- /**
- * Создать класс-наследник от базового класса или объекта
- */
- inherit: function(base, newConfig) {
- var newProto = (typeof base == 'function') ? new base() : this.extend({}, base);
- this.extend(newProto, newConfig);
- return function() {
- var F = function() {};
- F.prototype = newProto;
- return new F();
- };
- },
- /**
- * Получить элемент по селектору
- */
- get: function(selector, parent) {
- parent = this.getIf(parent);
- return (parent || unsafeWindow.document).querySelector(selector);
- },
- /**
- * Получить массив элементов по селектору
- */
- getAll: function(selector, parent) {
- parent = this.getIf(parent);
- return (parent || unsafeWindow.document).querySelectorAll(selector);
- },
- /**
- * Получить элемент, если задан элемент или селектор
- */
- getIf: function(element) {
- return this.isString(element) ? this.get(element) : element;
- },
- /**
- * Получить массив элементов, если задан массив элементов или селектор
- */
- getIfAll: function(elements) {
- return this.isString(elements) ? this.getAll(elements) : this.toIterable(elements);
- },
- /**
- * Назначим атрибуты элементу или извлечем их
- */
- attr: function(element, attributes) {
- var nativeEl = this.getIf(element);
- if (typeof attributes == 'string') {
- // извлечем атрибут
- var result = '';
- if (nativeEl.getAttribute) {
- result = nativeEl.getAttribute(attributes);
- }
- if (!result) {
- result = '';
- }
- return result;
- } else if (typeof attributes == 'object') {
- // назначим атрибуты всем элементам по селектору
- nativeEl = this.getIfAll(element);
- for (var i = 0; i < nativeEl.length; i++) {
- // назначим атрибуты из списка
- for (var at in attributes) {
- try {
- if (attributes[at] == '') {
- // Удалим пустой атрибут
- nativeEl[i].removeAttribute(at);
- } else {
- // Запишем осмысленный атрибут
- nativeEl[i].setAttribute(at, attributes[at]);
- }
- } catch (e) {
- console.error(e);
- }
- }
- }
- }
- },
- /**
- * Назначим стили элементу или извлечем их
- */
- css: function(element, properties) {
- var nativeEl = this.getIf(element);
- if (typeof properties == 'string') {
- // извлечем стиль
- var result = '';
- if (nativeEl.style) {
- var calcStyle = window.getComputedStyle(nativeEl, null) || nativeEl.currentStyle;
- result = calcStyle[properties];
- }
- if (!result) {
- result = '';
- }
- return result;
- } else if (typeof properties == 'object') {
- // присвоим стили всем элементам по селектору
- nativeEl = this.getIfAll(element);
- try {
- for (var i = 0; i < nativeEl.length; i++) {
- // назначим стили из списка
- this.extend(nativeEl[i].style, properties);
- }
- } catch (e) {
- console.error(e);
- }
- }
- },
- /**
- * Показать элемент
- */
- show: function(element, inline) {
- var current = this.getIf(element);
- if (current) {
- var style = current.style;
- style.display = inline ? 'inline' : 'block';
- }
- },
- /**
- * Спрятать элемент
- */
- hide: function(element, soft) {
- var current = this.getIf(element);
- if (current) {
- if (!!soft) {
- current.style.visibility = 'hidden';
- } else {
- current.style.display = 'none';
- }
- }
- },
- /**
- * Спрятать элемент, убрав его за границу экрана
- */
- hideFixed: function(element) {
- var current = this.getIf(element);
- if (current) {
- this.css(current, {
- position: 'fixed',
- left: '-2000px',
- top: '-2000px'
- });
- }
- },
- /**
- * Удалить элемент
- */
- del: function(element) {
- var current = this.getIf(element);
- if (current && current.parentNode) {
- current.parentNode.removeChild(current);
- }
- },
- /**
- * Изменить видимость элемента
- */
- toggle: function(element, inline) {
- this.isVisible(element) ? this.hide(element) : this.show(element, inline);
- },
- /**
- * Проверить, виден ли элемент
- */
- isVisible: function(element) {
- return this.getIf(element).style.display != 'none';
- },
- /**
- * Навесить обработчик
- */
- on: function(element, eventType, handler, scope) {
- var elements;
- if (!element) {
- return false;
- }
- if (this.isString(element)) {
- element = this.getIfAll(element);
- if (!(element && this.isIterable(element)))
- return false;
- }
- if (!this.isIterable(element)) {
- element = this.toIterable(element);
- }
- var eventHandler = handler;
- if (scope) {
- eventHandler = this.createDelegate(handler, scope, handler.arguments);
- }
- this.each(element, function(currentEl) {
- if (currentEl.addEventListener) {
- currentEl.addEventListener(eventType, eventHandler, false);
- }
- else if (currentEl.attachEvent) {
- currentEl.attachEvent('on' + eventType, eventHandler);
- }
- }, this);
- },
- /**
- * Запустить событие
- */
- fireEvent: function(element, eventType, keys, bubbles, cancelable) {
- // Определим необходимые параметры
- var eventBubbles = this.isBoolean(bubbles) ? bubbles : true;
- var eventCancelable = this.isBoolean(cancelable) ? cancelable : true;
- // Для клика создадим MouseEvent
- var isMouse = /click|dblclick|mouseup|mousedown/i.test(eventType);
- // Приведем к нужному виду клавиши
- keys = keys || {};
- this.each(['ctrlKey', 'altKey', 'shiftKey', 'metaKey'], function(letter) {
- if (!keys[letter]) {
- keys[letter] = false;
- }
- });
- // запустим для всех элементов по селектору
- var nativeEl = this.getIfAll(element);
- this.each(nativeEl, function(elem) {
- var evt = document.createEvent(isMouse ? 'MouseEvents' : 'HTMLEvents');
- if (isMouse) {
- // Событие мыши
- // event.initMouseEvent(type, canBubble, cancelable, view, detail, screenX, screenY, clientX, clientY, ctrlKey, altKey, shiftKey, metaKey, button, relatedTarget);
- evt.initMouseEvent(eventType, eventBubbles, eventCancelable, window, 0, 0, 0, 0, 0, keys.ctrlKey, keys.altKey, keys.shiftKey, keys.metaKey, 0, null);
- } else {
- // Событие общего типа
- // event.initEvent(type, bubbles, cancelable);
- evt.initEvent(eventType, eventBubbles, eventCancelable);
- }
- //var evt = (isMouse ? new MouseEvent() : new UIEvent());
- elem.dispatchEvent(evt);
- //console.log('dispatchEvent elem == %o, event == %o', elem, evt);
- }, this);
- },
- /**
- * Остановить выполнение события
- */
- stopEvent: function(e) {
- var event = e || window.event;
- if (!event) {
- return false;
- }
- event.preventDefault = event.preventDefault || function() {
- this.returnValue = false;
- };
- event.stopPropagation = event.stopPropagation || function() {
- this.cancelBubble = true;
- };
- event.preventDefault();
- event.stopPropagation();
- return true;
- },
- /**
- * Выделить текст в поле ввода
- */
- selectText: function(element, start, end) {
- var current = this.getIf(element);
- if (!current) {
- return;
- }
- if (!end) {
- end = start;
- }
- // firefox
- if ('selectionStart' in element) {
- element.setSelectionRange(start, end);
- element.focus(); // to make behaviour consistent with IE
- }
- // ie win
- else if(document.selection) {
- var range = element.createTextRange();
- range.collapse(true);
- range.moveStart('character', start);
- range.moveEnd('character', end - start);
- range.select();
- }
- },
- /**
- * Определяет, является ли значение строкой
- */
- isString : function(v) {
- return typeof v === 'string';
- },
- /**
- * Определяет, является ли значение числом
- */
- isNumber: function(v) {
- return typeof v === 'number' && isFinite(v);
- },
- /**
- * Определяет, является ли значение булевым
- */
- isBoolean: function(v) {
- return typeof v === 'boolean';
- },
- /**
- * Определяет, является ли значение объектом
- */
- isObject : function(v) {
- return typeof v === 'object';
- },
- /**
- * Определяет, является ли значение функцией
- */
- isFunction: function(v) {
- return typeof v === 'function';
- },
- /**
- * Определяет, является ли значение датой
- */
- isDate: function(v) {
- var result = true;
- this.each([
- 'getDay',
- 'getMonth',
- 'getFullYear',
- 'getHours',
- 'getMinutes'
- ], function(property) {
- result == result && this.isFunction(v[property]);
- }, this);
- return result;
- },
- /**
- * Переведем число в удобочитаемый вид с пробелами
- */
- numberToString: function(v) {
- var partLen = 3;
- try {
- v = Number(v);
- } catch (e) {
- return v;
- }
- v = String(v);
- var pointPos;
- pointPos = (pointPos = v.indexOf('.')) > 0 ? (pointPos) : (v.length);
- var result = v.substring(pointPos);
- v = v.substr(0, pointPos);
- var firstPart = true;
- while (v.length > 0) {
- var startPos = v.length - partLen;
- if (startPos < 0) {
- startPos = 0;
- }
- if (!firstPart) {
- result = ' ' + result;
- }
- firstPart = false;
- result = v.substr(startPos, partLen) + result;
- v = v.substr(0, v.length - partLen);
- }
- return result;
- },
- /**
- * Число с текстом в нужном падеже
- * @param {Number} number Число, к которому нужно дописать текст
- * @param {String} textFor1 Текст для количества 1
- * @param {String} textFor2 Текст для количества 2
- * @param {String} textFor10 Текст для количества 10
- */
- numberWithCase: function(number, textFor1, textFor2, textFor10) {
- // Определяем, какой текст подставить, по последней цифре
- var lastDigit = number % 10;
- var result = {
- number: number,
- text: ''
- };
- // Текст для количества 1
- if (this.inArray(lastDigit, [ 1 ])) {
- result.text = textFor1;
- }
- // Текст для количества 2
- if (this.inArray(lastDigit, [ 2, 3, 4 ])) {
- result.text = textFor2;
- }
- // Текст для количества 10
- if (this.inArray(lastDigit, [ 5, 6, 7, 8, 9, 0 ])) {
- result.text = textFor10;
- }
- // Текст для количества от 11 до 19
- var twoLastDigits = number % 100;
- if (10 < twoLastDigits && twoLastDigits < 20) {
- result.text = textFor10;
- }
- return this.template('{number} {text}', result);
- },
- /**
- * Определить, является ли тип значения скалярным
- */
- isScalar: function(v) {
- return this.isString(v) || this.isNumber(v) || this.isBoolean(v);
- },
- /**
- * Определить, является ли тип значения перечислимым
- */
- isIterable: function(v) {
- var result = !!v;
- if (result) {
- result = result && this.isNumber(v.length);
- result = result && !this.isString(v);
- // У формы есть свойство length - пропускаем её
- result = result && !(v.tagName && v.tagName.toUpperCase() == 'FORM');
- }
- return result;
- },
- /**
- * Сделать значение перечислимым
- */
- toIterable: function(value) {
- if (!value) {
- return value;
- }
- return this.isIterable(value) ? value : [value];
- },
- /**
- * Задать область видимости (scope) для функции
- */
- createDelegate: function(func, scope, args) {
- var method = func;
- return function() {
- var callArgs = args || arguments;
- return method.apply(scope || window, callArgs);
- };
- },
- /**
- * Проверим, является ли значение элементом массива или объекта
- */
- inArray: function(value, array) {
- return this.each(array, function(key) {
- if (key === value) {
- return true;
- }
- }) !== true;
- },
- /**
- * Найдем значение в массиве и вернем индекс
- */
- findInArray: function(value, array) {
- var result = this.each(array, function(key) {
- if (key === value) {
- return true;
- }
- });
- return this.isNumber(result) ? result : -1;
- },
- /**
- * Запустить функцию для всех элементов массива или объекта
- * @param {Array} array Массив, в котором значения будут перебираться по индексу элемента
- * @param {Object} array Объект, в котором значения будут перебираться по имени поля
- * @returns {Number} Индекс элемента, на котором досрочно завершилось выполнение, если array - массив
- * @returns {String} Имя поля, на котором досрочно завершилось выполнение, если array - объект
- * @returns {Boolean} True, если выполнение не завершалось досрочно
- */
- each: function(array, fn, scope) {
- if (!array) {
- return;
- }
- if (this.isIterable(array)) {
- for (var i = 0, len = array.length; i < len; i++) {
- if (this.isBoolean( fn.call(scope || array[i], array[i], i, array) )) {
- return i;
- };
- }
- } else {
- for (var key in array) {
- if (this.isBoolean( fn.call(scope || array[key], array[key], key, array) )) {
- return key;
- };
- }
- }
- return true;
- },
- /**
- * Разбить строку, укоротив её и склеив части указанным разделителем
- * @param {String} original Исходная строка
- * @param {Number} maxLength Максимальная длина, до которой нужно усечь исходную строку
- * @param {Number} tailLength Длина второй короткой части
- * @param {String} glue Разделитель, который склеит две части укороченной строки
- */
- splitWithGlue: function(original, maxLength, tailLength, glue) {
- // Разделитель по умолчанию
- if (!this.isString(glue)) {
- glue = '...';
- }
- // По умолчанию строка завершается разделителем
- if (!this.isNumber(tailLength)) {
- tailLength = 0;
- }
- var result = original;
- if (result.length > maxLength) {
- result = this.template('{head}{glue}{tail}', {
- head: original.substring(0, maxLength - (tailLength + glue.length)),
- glue: glue,
- tail: original.substring(original.length - tailLength)
- });
- }
- return result;
- },
- /**
- * форматирование строки, используя объект
- */
- template: function(strTarget, objSource) {
- var s = arguments[0];
- for (var prop in objSource) {
- var reg = new RegExp("\\{" + prop + "\\}", "gm");
- s = s.replace(reg, objSource[prop]);
- }
- return s;
- },
- /**
- * форматирование строки, используя числовые индексы
- */
- format: function() {
- var original = arguments[0];
- this.each(arguments, function(sample, index) {
- if (index > 0) {
- var currentI = index - 1;
- var reg = new RegExp("\\{" + currentI + "\\}", "gm");
- original = original.replace(reg, sample);
- }
- });
- return original;
- },
- /**
- * Быстрый доступ к форматированию
- */
- fmt: function() {
- return this.format.apply(this, arguments);
- },
- /**
- * Выдать строку заданной длины с заполнением символом
- */
- leftPad: function (val, size, character) {
- var result = String(val);
- if (!character) {
- character = ' ';
- }
- while (result.length < size) {
- result = character + result;
- }
- return result;
- },
- /**
- * Определить, какая часть окна ушла вверх при прокрутке
- */
- getScrollOffset: function () {
- var d = unsafeWindow.top.document;
- return top.pageYOffset ? top.pageYOffset : (
- (d.documentElement && d.documentElement.scrollTop) ? (d.documentElement.scrollTop) : (d.body.scrollTop)
- );
- },
- /**
- * Определить размер окна
- */
- getWindowSize: function () {
- var d = unsafeWindow.top.document;
- return {
- width: /*top.innerWidth ? top.innerWidth :*/ (
- (d.documentElement.clientWidth) ? (d.documentElement.clientWidth) : (d.body.offsetWidth)
- ),
- height: /*top.innerHeight ? top.innerHeight :*/ (
- (d.documentElement.clientHeight) ? (d.documentElement.clientHeight) : (d.body.offsetHeight)
- )
- };
- },
- /**
- * Склеить строки
- */
- join: function(rows, glue) {
- return Array.prototype.slice.call(this.toIterable(rows), 0).join(glue || '');
- },
- /**
- * Вернем значение cookie
- */
- getCookie: function(name) {
- var value = null;
- // Проверим, есть ли кука с таким именем
- var cookie = unsafeWindow.document.cookie;
- var regKey = new RegExp(name.replace(/([\.$?*|{}\(\)\[\]\\\/\+^])/g, '\\$1') + '=(.*?)((; ?)|$)');
- var hasMatch = cookie.match(regKey);
- if (hasMatch && hasMatch[1]) {
- value = decodeURIComponent(hasMatch[1]);
- }
- return value;
- },
- /**
- * Установим значение cookie
- * @param {Object} options Объект с дополнительными значениями
- * - expires Срок действия куки: {Number} количество дней или {Data} дата окончания срока
- * - path Путь, отсчитывая от которого будет действовать кука
- * - domain Домен, в пределах которого будет действовать кука
- * - secure Кука для https-соединения
- */
- setCookie: function(name, value, options) {
- // Можно опустить значение куки, если нужно удалить
- if (!value) {
- value = '';
- }
- options = options || {};
- // Проверяем, задана дата или количество дней
- var expires = '';
- if (options.expires && (typeof options.expires == 'number' || options.expires.toUTCString)) {
- var date;
- if (typeof options.expires == 'number') {
- date = new Date();
- date.setTime(date.getTime() + (options.expires * 24 * 60 * 60 * 1000));
- } else {
- date = options.expires;
- }
- expires = '; expires=' + date.toUTCString();
- }
- // Проставляем другие опции
- var path = options.path ? '; path=' + (options.path) : '';
- var domain = options.domain ? '; domain=' + (options.domain) : '';
- var secure = (options.secure === true) ? '; secure' : '';
- unsafeWindow.document.cookie = [name, '=', encodeURIComponent(value), expires, path, domain, secure].join('');
- },
- /**
- * Картинка с большим пальцем
- */
- getThumbHand: function() {
- var thumbSource;
- thumbSource = ( // рука
- 'data:image/png;base64,\
- iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAA0UlEQVR42r3SPwsBYRzA8buSlMFi\
- MymDd+A1WEiSUDarwS6TwSyjgUkkfxZh4J0YpQwKk8L36R56uu5Rd1ee+izXPd/nN/xMw+cx/xXI\
- ooYxhm4DSbRRxAQ5N4EUmqjKKZ4YOAXmeCjfj1ICddyxwVVGxL0dep+AGK2gBA5oYPZjuoWYSheY\
- Iq+52EUMAWS8BHxNUJbfo9ij5XWCEl4Y6QIrpG2X4uggjIh84KQLnFHB2uH1kGHtglis7x5scVF+\
- uom6Ye3ByxYIoo+lGvB8fAfecvkwEbIZfswAAAAASUVORK5CYII=');
- thumbSource = ( // сообщение
- 'data:image/png;base64,\
- iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABL0lEQVQ4y2P4//8/AyWYgWoGRLTv\
- EALipUD8E4j/48G7gFgFmwEbVx689f/3n7//8YEtJ++DDLkNxGxwA4AcHiD+8/ffv/8fvv37//LT\
- v//PPv77/+T9v/8P3/37f+/Nv/+3X/39f+cVxPDqBcdBhpghGyCXM/UAWPIFUOOzD//+PwZqfvD2\
- 3/+7UM3XX/z9f/UZxIDOVWdBBnhjNeApUPOjd1DNr//9v/USovkKUPPFJ7gNgHsB5Pz7QFvvvP77\
- /yZQ87Xnf/9fBmq+8ARkwB+wAbWLToAMsMQaiCBDkAHINRce/wUbjBaInLii8Q8syubuuAo36P3n\
- H2A+UPwy1mjEhoEK7zx/9xWm8TsQ1xKdEoGKe2duuwLS+AWIC0lKykANSkB8D4hT6JcXBswAAPeL\
- DyK+4moLAAAAAElFTkSuQmCC');
- return thumbSource;
- },
- /**
- * Отладка
- */
- thumb: function(text) {
- var bgImage = this.format('background: url("{0}") no-repeat;', this.getThumbHand());
- console.log('%c ', bgImage, text);
- },
- /**
- * Удалим значение cookie
- */
- removeCookie: function(name) {
- this.setCookie(name, null, { expires: -1 });
- },
- /**
- * Отладка
- */
- groupDir: function(name, object) {
- console.group(name);
- console.dir(object);
- console.groupEnd();
- },
- /**
- * Отладка: ошибка с пользовательским сообщением
- */
- errorist: function(error, text, parameters) {
- var params = Array.prototype.slice.call(arguments, 1);
- params.unshift('#FFEBEB');
- this.coloredLog(params);
- console.error(error);
- },
- /**
- * Отладка: вывод цветной строки
- */
- coloredLog: function(color, text) {
- var params = Array.prototype.slice.call(arguments, 2);
- params.unshift('background-color: ' + color + ';');
- params.unshift('%c' + text);
- console.log.apply(console, params);
- },
- /**
- * XPath-запрос
- */
- xpath: function(selector) {
- var nodes = document.evaluate(selector, document, null, XPathResult.ANY_TYPE, null);
- var thisNode = nodes.iterateNext();
- while (thisNode) {
- //console.log(thisNode.textContent);
- thisNode = nodes.iterateNext();
- }
- },
- /**
- * Упаковать для хранилища
- */
- packToStorage: function(objBox) {
- var clone = this.extend({}, objBox);
- this.each(clone, function(property, index) {
- if (typeof property == 'function') {
- clone[index] = property.toString();
- }
- if (typeof property == 'object') {
- clone[index] = this.packToStorage(property);
- }
- }, this);
- return JSON.stringify(clone);
- },
- /**
- * Распаковать из хранилища
- */
- unpackFromStorage: function(objBox) {
- var result = {};
- try {
- result = JSON.parse(objBox);
- } catch (e) {
- try {
- result = eval('(' + objBox + ')');
- } catch (e) {
- result = objBox;
- }
- }
- if (typeof result == 'object') {
- for (var property in result) {
- result[property] = this.unpackFromStorage(result[property]);
- }
- }
- return result;
- },
- /**
- * Проверить соответствие домена, как для Stylish
- */
- mozDocumentDomainIs: function() {
- let result = false;
- let domainList = Array.prototype.slice.call(arguments, 1);
- this.each(domainList, function(domainName, index) {
- let current = (document.domain == domainName) || (document.domain.substring(document.domain.indexOf(domainName) + 1) == domainName);
- result |= current;
- });
- return result;
- },
- /**
- * Проверить начало URL, как для Stylish
- */
- mozDocumentUrlPrefixIs: function() {
- let result = false;
- let prefixList = Array.prototype.slice.call(arguments, 1);
- this.each(prefixList, function(prefix, index) {
- let current = (document.location.href.indexOf(prefix) == 0);
- result |= current;
- });
- return result;
- }
- };
-
- // Добавляем обратный порядок в jQuery
- if (typeof jQuery != 'undefined') {
- if (typeof jQuery.fn.reverse != 'function') {
- jQuery.fn.reverse = function() {
- return jQuery(this.get().reverse());
- };
- }
- if (typeof jQuery.fn.softHide != 'function') {
- jQuery.fn.softHide = function() {
- return jQuery(this).css({ visibility: 'hidden' });
- };
- }
- }
-
- unsafeWindow.NodeList.prototype.size = () => this.length;
-
- // форматирование строки
- unsafeWindow.String.prototype.format = unsafeWindow.__krokodil.format;
-
- //отладка
- unsafeWindow.console.groupDir = unsafeWindow.__krokodil.groupDir;
- unsafeWindow.console.coloredLog = unsafeWindow.__krokodil.coloredLog;
- unsafeWindow.console.errorist = unsafeWindow.__krokodil.errorist;
-
- //unsafeWindow.__krokodil.thumb('Include Tools');
- //console.coloredLog('#fffbd6', 'Include Tools');
- //console.errorist('Include Tools');
- console.log('Include Tools 💬 1.33');
-
- })(paramWindow);