Include Tools

Общие инструменты для всех страничек

当前为 2019-03-12 提交的版本,查看 最新版本

此脚本不应直接安装。它是供其他脚本使用的外部库,要使用该库请加入元指令 // @require https://update.gf.qytechs.cn/scripts/379902/678751/Include%20Tools.js

  1. // ==UserScript==
  2. // @name Include Tools
  3. // @namespace scriptomatika
  4. // @author mouse-karaganda
  5. // @description Общие инструменты для всех страничек
  6. // @include *
  7. // @exclude http://localhost:*
  8. // @grant none
  9. // ==/UserScript==
  10.  
  11. var paramWindow=function(){var result;try{result=unsafeWindow;}catch(e){result=window;}return result;};
  12.  
  13. (function(unsafeWindow) {
  14. var console = unsafeWindow.console;
  15. var jQuery = unsafeWindow.jQuery;
  16.  
  17. unsafeWindow.__krokodil = {
  18. /**
  19. * Отрисовывает элемент
  20. */
  21. renderElement: function(config) {
  22. // Определяем параметры по умолчанию
  23. var newRenderType = this.inner.setRenderType(config.renderType);
  24. var newConfig = {
  25. // ~~~ название тега ~~~ //
  26. tagName: config.tagName || 'div',
  27. // ~~~ атрибуты тега ~~~ //
  28. attr: config.attr || {},
  29. // ~~~ идентификатор ~~~ //
  30. id: config.id,
  31. // ~~~ имя класса ~~~ //
  32. cls: config.cls,
  33. // ~~~ встроенные стили тега ~~~ //
  34. style: config.style || {},
  35. // ~~~ содержимое элемента ~~~ //
  36. innerHTML: this.join(config.innerHTML || ''),
  37. // ~~~ обработчики событий элемента ~~~ //
  38. listeners: config.listeners || {},
  39. // ~~~ родительский элемент для нового ~~~ //
  40. renderTo: this.getIf(config.renderTo),
  41. // ~~~ способ отрисовки: append (по умолчанию), insertBefore, insertAfter, insertFirst, none ~~~ //
  42. renderType: newRenderType
  43. };
  44. var newElement;
  45. if (newConfig.tagName == 'text') {
  46. // Создаем текстовый узел
  47. newElement = document.createTextNode(newConfig.innerHTML);
  48. } else {
  49. // Создаем элемент
  50. newElement = document.createElement(newConfig.tagName);
  51. // Добавляем атрибуты
  52. this.attr(newElement, newConfig.attr);
  53. // Добавляем идентификатор, если указан
  54. if (newConfig.id) {
  55. this.attr(newElement, { 'id': newConfig.id });
  56. }
  57. //console.debug('newElement == %o, config == %o, id == ', newElement, newConfig, newConfig.id);
  58. // Добавляем атрибут класса
  59. if (newConfig.cls) {
  60. this.attr(newElement, { 'class': newConfig.cls });
  61. }
  62. // Наполняем содержимым
  63. newElement.innerHTML = newConfig.innerHTML;
  64. // Задаем стиль
  65. this.css(newElement, newConfig.style);
  66. // Навешиваем события
  67. var confListeners = newConfig.listeners;
  68. for (var ev in confListeners) {
  69. if (ev != 'scope') {
  70. //console.debug('this.on(newElement == %o, ev == %o, newConfig.listeners[ev] == %o, newConfig.listeners.scope == %o)', newElement, ev, newConfig.listeners[ev], newConfig.listeners.scope);
  71. this.on(newElement, ev, newConfig.listeners[ev], newConfig.listeners.scope);
  72. }
  73. }
  74. //console.debug('После: tag == %o, listeners == %o', newConfig.tagName, confListeners);
  75. }
  76. // Отрисовываем элемент
  77. var returnRender = true;
  78. while (returnRender) {
  79. switch (newConfig.renderType) {
  80. // Не отрисовывать, только создать
  81. case this.enumRenderType['none']: {
  82. returnRender = false;
  83. break;
  84. };
  85. // Вставить перед указанным
  86. case this.enumRenderType['insertBefore']: {
  87. var target = newConfig.renderTo || document.body.firstChild;
  88. // если элемент не задан - вернемся к способу по умолчанию
  89. if (target) {
  90. target.parentNode.insertBefore(newElement, target);
  91. returnRender = false;
  92. } else {
  93. newConfig.renderType = this.enumRenderType['default'];
  94. }
  95. break;
  96. };
  97. // Вставить после указанного
  98. case this.enumRenderType['insertAfter']: {
  99. // если элемент не задан - вернемся к способу по умолчанию
  100. if (newConfig.renderTo && newConfig.renderTo.nextSibling) {
  101. var target = newConfig.renderTo.nextSibling;
  102. target.parentNode.insertBefore(newElement, target);
  103. returnRender = false;
  104. } else {
  105. newConfig.renderType = this.enumRenderType['default'];
  106. }
  107. break;
  108. };
  109. // Вставить как первый дочерний
  110. case this.enumRenderType['insertFirst']: {
  111. // если элемент не задан - вернемся к способу по умолчанию
  112. if (newConfig.renderTo && newConfig.renderTo.firstChild) {
  113. var target = newConfig.renderTo.firstChild;
  114. target.parentNode.insertBefore(newElement, target);
  115. returnRender = false;
  116. } else {
  117. newConfig.renderType = this.enumRenderType['default'];
  118. }
  119. break;
  120. };
  121. // Вставить как последний дочерний
  122. case this.enumRenderType['append']:
  123. default: {
  124. var parent = newConfig.renderTo || document.body;
  125. parent.appendChild(newElement);
  126. returnRender = false;
  127. };
  128. }
  129. }
  130. // Возвращаем элемент
  131. return newElement;
  132. },
  133. /**
  134. * Отрисовать несколько одинаковых элементов подряд
  135. */
  136. renderElements: function(count, config) {
  137. for (var k = 0; k < count; k++) {
  138. this.renderElement(config);
  139. }
  140. },
  141. /**
  142. * Отрисовать текстовый узел
  143. */
  144. renderText: function(config) {
  145. // Упрощенные настройки
  146. var newConfig = {
  147. tagName: 'text',
  148. innerHTML: config.text,
  149. renderTo: config.renderTo,
  150. renderType: config.renderType
  151. };
  152. var newElement = this.renderElement(newConfig);
  153. return newElement;
  154. },
  155. /**
  156. * Отрисовать элемент style
  157. * @param {String} text Любое количество строк через запятую
  158. */
  159. renderStyle: function(text) {
  160. var stringSet = arguments;
  161. var tag = this.renderElement({
  162. tagName: 'style',
  163. attr: { type: 'text/css' },
  164. innerHTML: this.format('\n\t{0}\n', this.join(stringSet, '\n\t'))
  165. });
  166. return tag;
  167. },
  168. /**
  169. * Возможные способы отрисовки
  170. */
  171. enumRenderType: {
  172. 'append': 0,
  173. 'insertBefore': 1,
  174. 'insertAfter': 2,
  175. 'insertFirst': 3,
  176. 'none': 4,
  177. 'default': 0
  178. },
  179. // Назначает способ отрисовки
  180. setRenderType: function(renderType) {
  181. if (typeof renderType != 'string') {
  182. return this.enumRenderType['default'];
  183. }
  184. if (this.enumRenderType[renderType] == undefined) {
  185. return this.enumRenderType['default'];
  186. }
  187. return this.enumRenderType[renderType];
  188. },
  189. /**
  190. * Карта кодов клавиш
  191. */
  192. keyMap: {
  193. // Клавиши со стрелками
  194. arrowLeft: 37,
  195. arrowUp: 38,
  196. arrowRight: 39,
  197. arrowDown: 40
  198. },
  199. /**
  200. * Карта кодов символов
  201. */
  202. charMap: {
  203. arrowLeft: 8592, // ←
  204. arrowRight: 8594 // →
  205. },
  206. /**
  207. * Ждём, пока отрисуется элемент, и выполняем действия
  208. * @param {String} selector css-селектор для поиска элемента (строго строка)
  209. * @param {Function} callback Функция, выполняющая действия над элементом. this внутри неё — искомый DOM-узел
  210. * @param {Number} maxIterCount Максимальное количество попыток найти элемент
  211. */
  212. missingElement: function(selector, callback, maxIterCount) {
  213. // Итерации раз в секунду
  214. var missingOne = 1000;
  215. // Ограничим количество попыток разумными пределами
  216. var defaultCount = 300;
  217. if (!this.isNumber(maxIterCount)) {
  218. maxIterCount = defaultCount;
  219. }
  220. if (0 > maxIterCount || maxIterCount > defaultCount) {
  221. maxIterCount = defaultCount;
  222. }
  223. // Запускаем таймер на поиск
  224. var iterCount = 0;
  225. var elementTimer = setInterval(this.createDelegate(function() {
  226. // Сообщение об ожидании
  227. var secondsMsg = this.numberWithCase(iterCount, 'секунду', 'секунды', 'секунд');
  228. if (iterCount % 10 == 0) {
  229. console.debug('missing: Ждём [%o] %s', selector, secondsMsg);
  230. }
  231. var element = this.get(selector);
  232. // Определим, что вышел элемент
  233. var elementStop = !!element;
  234. // Определим, что кончилось количество попыток
  235. var iterStop = (iterCount >= maxIterCount);
  236. if (elementStop || iterStop) {
  237. clearInterval(elementTimer);
  238. var elementExists = true;
  239. // Если элемент так и не появился
  240. if (!elementStop && iterStop) {
  241. console.debug('missing: Закончились попытки [%o]', selector);
  242. elementExists = false;
  243. //return;
  244. }
  245. // Появился элемент - выполняем действия
  246. console.debug('missing: Появился элемент [%o] == %o', selector, element);
  247. if (this.isFunction(callback)) {
  248. callback.call(element, elementExists);
  249. }
  250. }
  251. iterCount++;
  252. }, this), missingOne);
  253. },
  254. /**
  255. * Добавить свойства в объект
  256. */
  257. extend: function(target, newProperties) {
  258. if (typeof newProperties == 'object') {
  259. for (var i in newProperties)
  260. target[i] = newProperties[i];
  261. }
  262. return target;
  263. },
  264. /**
  265. * Создать класс-наследник от базового класса или объекта
  266. */
  267. inherit: function(base, newConfig) {
  268. var newProto = (typeof base == 'function') ? new base() : this.extend({}, base);
  269. this.extend(newProto, newConfig);
  270. return function() {
  271. var F = function() {};
  272. F.prototype = newProto;
  273. return new F();
  274. };
  275. },
  276. /**
  277. * Получить элемент по селектору
  278. */
  279. get: function(selector, parent) {
  280. parent = this.getIf(parent);
  281. return (parent || unsafeWindow.document).querySelector(selector);
  282. },
  283. /**
  284. * Получить массив элементов по селектору
  285. */
  286. getAll: function(selector, parent) {
  287. parent = this.getIf(parent);
  288. return (parent || unsafeWindow.document).querySelectorAll(selector);
  289. },
  290. /**
  291. * Получить элемент, если задан элемент или селектор
  292. */
  293. getIf: function(element) {
  294. return this.isString(element) ? this.get(element) : element;
  295. },
  296. /**
  297. * Получить массив элементов, если задан массив элементов или селектор
  298. */
  299. getIfAll: function(elements) {
  300. return this.isString(elements) ? this.getAll(elements) : this.toIterable(elements);
  301. },
  302. /**
  303. * Назначим атрибуты элементу или извлечем их
  304. */
  305. attr: function(element, attributes) {
  306. var nativeEl = this.getIf(element);
  307. if (typeof attributes == 'string') {
  308. // извлечем атрибут
  309. var result = '';
  310. if (nativeEl.getAttribute) {
  311. result = nativeEl.getAttribute(attributes);
  312. }
  313. if (!result) {
  314. result = '';
  315. }
  316. return result;
  317. } else if (typeof attributes == 'object') {
  318. // назначим атрибуты всем элементам по селектору
  319. nativeEl = this.getIfAll(element);
  320. for (var i = 0; i < nativeEl.length; i++) {
  321. // назначим атрибуты из списка
  322. for (var at in attributes) {
  323. try {
  324. if (attributes[at] == '') {
  325. // Удалим пустой атрибут
  326. nativeEl[i].removeAttribute(at);
  327. } else {
  328. // Запишем осмысленный атрибут
  329. nativeEl[i].setAttribute(at, attributes[at]);
  330. }
  331. } catch (e) {
  332. console.error(e);
  333. }
  334. }
  335. }
  336. }
  337. },
  338. /**
  339. * Назначим стили элементу или извлечем их
  340. */
  341. css: function(element, properties) {
  342. var nativeEl = this.getIf(element);
  343. if (typeof properties == 'string') {
  344. // извлечем стиль
  345. var result = '';
  346. if (nativeEl.style) {
  347. var calcStyle = window.getComputedStyle(nativeEl, null) || nativeEl.currentStyle;
  348. result = calcStyle[properties];
  349. }
  350. if (!result)
  351. result = '';
  352. return result;
  353. } else if (typeof properties == 'object') {
  354. // присвоим стили всем элементам по селектору
  355. nativeEl = this.getIfAll(element);
  356. try {
  357. for (var i = 0; i < nativeEl.length; i++) {
  358. // назначим стили из списка
  359. this.extend(nativeEl[i].style, properties);
  360. }
  361. } catch (e) {
  362. console.error(e);
  363. }
  364. }
  365. },
  366. /**
  367. * Показать элемент
  368. */
  369. show: function(element, inline) {
  370. var current = this.getIf(element);
  371. if (current) {
  372. var style = current.style;
  373. style.display = inline ? 'inline' : 'block';
  374. }
  375. },
  376. /**
  377. * Спрятать элемент
  378. */
  379. hide: function(element) {
  380. var current = this.getIf(element);
  381. if (current)
  382. current.style.display = 'none';
  383. },
  384. /**
  385. * Удалить элемент
  386. */
  387. del: function(element) {
  388. var current = this.getIf(element);
  389. if (current)
  390. current.parentNode.removeChild(current);
  391. },
  392. /**
  393. * Изменить видимость элемента
  394. */
  395. toggle: function(element, inline) {
  396. this.isVisible(element) ? this.hide(element) : this.show(element, inline);
  397. },
  398. /**
  399. * Проверить, виден ли элемент
  400. */
  401. isVisible: function(element) {
  402. return this.getIf(element).style.display != 'none';
  403. },
  404. /**
  405. * Навесить обработчик
  406. */
  407. on: function(element, eventType, handler, scope) {
  408. var elements;
  409. if (!element)
  410. return false;
  411. if (this.isString(element)) {
  412. element = this.getIfAll(element);
  413. if (!(element && this.isIterable(element)))
  414. return false;
  415. }
  416. if (!this.isIterable(element)) {
  417. element = this.toIterable(element);
  418. }
  419. var eventHandler = handler;
  420. if (scope) {
  421. eventHandler = this.createDelegate(handler, scope, handler.arguments);
  422. }
  423. this.each(element, function(currentEl) {
  424. if (currentEl.addEventListener) {
  425. currentEl.addEventListener(eventType, eventHandler, false);
  426. }
  427. else if (currentEl.attachEvent) {
  428. currentEl.attachEvent('on' + eventType, eventHandler);
  429. }
  430. }, this);
  431. },
  432. /**
  433. * Запустить событие
  434. */
  435. fireEvent: function(element, eventType, keys, bubbles, cancelable) {
  436. // Определим необходимые параметры
  437. var eventBubbles = this.isBoolean(bubbles) ? bubbles : true;
  438. var eventCancelable = this.isBoolean(cancelable) ? cancelable : true;
  439. // Для клика создадим MouseEvent
  440. var isMouse = /click|dblclick|mouseup|mousedown/i.test(eventType);
  441. // Приведем к нужному виду клавиши
  442. keys = keys || {};
  443. this.each(['ctrlKey', 'altKey', 'shiftKey', 'metaKey'], function(letter) {
  444. if (!keys[letter])
  445. keys[letter] = false;
  446. });
  447. // запустим для всех элементов по селектору
  448. var nativeEl = this.getIfAll(element);
  449. this.each(nativeEl, function(elem) {
  450. var evt = document.createEvent(isMouse ? 'MouseEvents' : 'HTMLEvents');
  451. if (isMouse) {
  452. // Событие мыши
  453. // event.initMouseEvent(type, canBubble, cancelable, view, detail, screenX, screenY, clientX, clientY, ctrlKey, altKey, shiftKey, metaKey, button, relatedTarget);
  454. evt.initMouseEvent(eventType, eventBubbles, eventCancelable, window, 0, 0, 0, 0, 0, keys.ctrlKey, keys.altKey, keys.shiftKey, keys.metaKey, 0, null);
  455. } else {
  456. // Событие общего типа
  457. // event.initEvent(type, bubbles, cancelable);
  458. evt.initEvent(eventType, eventBubbles, eventCancelable);
  459. }
  460. //var evt = (isMouse ? new MouseEvent() : new UIEvent());
  461. elem.dispatchEvent(evt);
  462. console.debug('dispatchEvent elem == %o, event == %o', elem, evt);
  463. }, this);
  464. },
  465. /**
  466. * Остановить выполнение события
  467. */
  468. stopEvent: function(e) {
  469. var event = e || window.event;
  470. if (!event)
  471. return false;
  472. event.preventDefault = event.preventDefault || function() {
  473. this.returnValue = false;
  474. };
  475. event.stopPropagation = event.stopPropagation || function() {
  476. this.cancelBubble = true;
  477. };
  478. event.preventDefault();
  479. event.stopPropagation();
  480. return true;
  481. },
  482. /**
  483. * Выделить текст в поле ввода
  484. */
  485. selectText: function(element, start, end) {
  486. var current = this.getIf(element);
  487. if (!current)
  488. return;
  489. if (!end)
  490. end = start;
  491. // firefox
  492. if('selectionStart' in element)
  493. {
  494. element.setSelectionRange(start, end);
  495. element.focus(); // to make behaviour consistent with IE
  496. }
  497. // ie win
  498. else if(document.selection)
  499. {
  500. var range = element.createTextRange();
  501. range.collapse(true);
  502. range.moveStart('character', start);
  503. range.moveEnd('character', end - start);
  504. range.select();
  505. }
  506. },
  507. /**
  508. * Определить, является ли значение строкой
  509. */
  510. isString : function(v) {
  511. return typeof v === 'string';
  512. },
  513. /**
  514. * Определить, является ли значение числом
  515. */
  516. isNumber: function(v) {
  517. return typeof v === 'number' && isFinite(v);
  518. },
  519. /**
  520. * Определить, является ли значение булевым
  521. */
  522. isBoolean: function(v) {
  523. return typeof v === 'boolean';
  524. },
  525. /**
  526. * Определить, является ли значение функцией
  527. */
  528. isFunction: function(v) {
  529. return typeof v === 'function';
  530. },
  531. /**
  532. * Определить, является ли значение датой
  533. */
  534. isDate: function(v) {
  535. var result = true;
  536. this.each([
  537. 'getDay',
  538. 'getMonth',
  539. 'getFullYear',
  540. 'getHours',
  541. 'getMinutes'
  542. ], function(property) {
  543. result == result && this.isFunction(v[property]);
  544. }, this);
  545. return result;
  546. },
  547. /**
  548. * Переведем число в удобочитаемый вид с пробелами
  549. */
  550. numberToString: function(v) {
  551. var partLen = 3;
  552. try {
  553. v = Number(v);
  554. } catch (e) {
  555. return v;
  556. }
  557. v = String(v);
  558. var pointPos;
  559. pointPos = (pointPos = v.indexOf('.')) > 0 ? (pointPos) : (v.length);
  560. var result = v.substring(pointPos);
  561. v = v.substr(0, pointPos);
  562. var firstPart = true;
  563. while (v.length > 0) {
  564. var startPos = v.length - partLen;
  565. if (startPos < 0) {
  566. startPos = 0;
  567. }
  568. if (!firstPart) {
  569. result = ' ' + result;
  570. }
  571. firstPart = false;
  572. result = v.substr(startPos, partLen) + result;
  573. v = v.substr(0, v.length - partLen);
  574. }
  575. return result;
  576. },
  577. /**
  578. * Число с текстом в нужном падеже
  579. * @param {Number} number Число, к которому нужно дописать текст
  580. * @param {String} textFor1 Текст для количества 1
  581. * @param {String} textFor2 Текст для количества 2
  582. * @param {String} textFor10 Текст для количества 10
  583. */
  584. numberWithCase: function(number, textFor1, textFor2, textFor10) {
  585. // Определяем, какой текст подставить, по последней цифре
  586. var lastDigit = number % 10;
  587. var result = {
  588. number: number,
  589. text: ''
  590. };
  591. // Текст для количества 1
  592. if (this.inArray(lastDigit, [ 1 ])) {
  593. result.text = textFor1;
  594. }
  595. // Текст для количества 2
  596. if (this.inArray(lastDigit, [ 2, 3, 4 ])) {
  597. result.text = textFor2;
  598. }
  599. // Текст для количества 10
  600. if (this.inArray(lastDigit, [ 5, 6, 7, 8, 9, 0 ])) {
  601. result.text = textFor10;
  602. }
  603. // Текст для количества от 11 до 19
  604. var twoLastDigits = number % 100;
  605. if (10 < twoLastDigits && twoLastDigits < 20) {
  606. result.text = textFor10;
  607. }
  608. return this.template('{number} {text}', result);
  609. },
  610. /**
  611. * Определить, является ли тип значения скалярным
  612. */
  613. isScalar: function(v) {
  614. return this.isString(v) || this.isNumber(v) || this.isBoolean(v);
  615. },
  616. /**
  617. * Определить, является ли тип значения перечислимым
  618. */
  619. isIterable: function(v) {
  620. var result = !!v;
  621. if (result) {
  622. result = result && this.isNumber(v.length);
  623. result = result && !this.isString(v);
  624. // У формы есть свойство length - пропускаем её
  625. result = result && !(v.tagName && v.tagName.toUpperCase() == 'FORM');
  626. }
  627. return result;
  628. },
  629. /**
  630. * Сделать значение перечислимым
  631. */
  632. toIterable: function(value) {
  633. if (!value)
  634. return value;
  635. else
  636. return this.isIterable(value) ? value : [value];
  637. },
  638. /**
  639. * Задать область видимости (scope) для функции
  640. */
  641. createDelegate: function(func, scope, args) {
  642. var method = func;
  643. return function() {
  644. var callArgs = args || arguments;
  645. return method.apply(scope || window, callArgs);
  646. };
  647. },
  648. /**
  649. * Проверим, является ли значение элементом массива или объекта
  650. */
  651. inArray: function(value, array) {
  652. return this.each(array, function(key) {
  653. if (key === value)
  654. return true;
  655. }) !== true;
  656. },
  657. /**
  658. * Найдем значение в массиве и вернем индекс
  659. */
  660. findInArray: function(value, array) {
  661. var result = this.each(array, function(key) {
  662. if (key === value)
  663. return true;
  664. });
  665. return this.isNumber(result) ? result : -1;
  666. },
  667. /**
  668. * Запустить функцию для всех элементов массива или объекта
  669. * @param {Array} array Массив, в котором значения будут перебираться по индексу элемента
  670. * @param {Object} array Объект, в котором значения будут перебираться по имени поля
  671. * @returns {Number} Индекс элемента, на котором досрочно завершилось выполнение, если array - массив
  672. * @returns {String} Имя поля, на котором досрочно завершилось выполнение, если array - объект
  673. * @returns {Boolean} True, если выполнение не завершалось досрочно
  674. */
  675. each: function(array, fn, scope) {
  676. if (!array) {
  677. return;
  678. }
  679. if (this.isIterable(array)) {
  680. for (var i = 0, len = array.length; i < len; i++) {
  681. if (this.isBoolean( fn.call(scope || array[i], array[i], i, array) )) {
  682. return i;
  683. };
  684. }
  685. } else {
  686. for (var key in array) {
  687. if (this.isBoolean( fn.call(scope || array[key], array[key], key, array) )) {
  688. return key;
  689. };
  690. }
  691. }
  692. return true;
  693. },
  694. /**
  695. * Разбить строку, укоротив её и склеив части указанным разделителем
  696. * @param {String} original Исходная строка
  697. * @param {Number} maxLength Максимальная длина, до которой нужно усечь исходную строку
  698. * @param {Number} tailLength Длина второй короткой части
  699. * @param {String} glue Разделитель, который склеит две части укороченной строки
  700. */
  701. splitWithGlue: function(original, maxLength, tailLength, glue) {
  702. // Разделитель по умолчанию
  703. if (!this.isString(glue)) {
  704. glue = '...';
  705. }
  706. // По умолчанию строка завершается разделителем
  707. if (!this.isNumber(tailLength)) {
  708. tailLength = 0;
  709. }
  710. var result = original;
  711. if (result.length > maxLength) {
  712. result = this.template('{head}{glue}{tail}', {
  713. head: original.substring(0, maxLength - (tailLength + glue.length)),
  714. glue: glue,
  715. tail: original.substring(original.length - tailLength)
  716. });
  717. }
  718. return result;
  719. },
  720. /**
  721. * форматирование строки, используя объект
  722. */
  723. template: function(strTarget, objSource) {
  724. var s = arguments[0];
  725. for (var prop in objSource) {
  726. var reg = new RegExp("\\{" + prop + "\\}", "gm");
  727. s = s.replace(reg, objSource[prop]);
  728. }
  729. return s;
  730. },
  731. /**
  732. * форматирование строки, используя числовые индексы
  733. */
  734. format: function() {
  735. var original = arguments[0];
  736. this.each(arguments, function(sample, index) {
  737. if (index > 0) {
  738. var currentI = index - 1;
  739. var reg = new RegExp("\\{" + currentI + "\\}", "gm");
  740. original = original.replace(reg, sample);
  741. }
  742. });
  743. return original;
  744. },
  745. /**
  746. * Быстрый доступ к форматированию
  747. */
  748. fmt: function() {
  749. return this.format.apply(this, arguments);
  750. },
  751. /**
  752. * Выдать строку заданной длины с заполнением символом
  753. */
  754. leftPad: function (val, size, character) {
  755. var result = String(val);
  756. if (!character)
  757. character = ' ';
  758. while (result.length < size) {
  759. result = character + result;
  760. }
  761. return result;
  762. },
  763. /**
  764. * Определить, какая часть окна ушла вверх при прокрутке
  765. */
  766. getScrollOffset: function () {
  767. var d = unsafeWindow.top.document;
  768. return top.pageYOffset ? top.pageYOffset : (
  769. (d.documentElement && d.documentElement.scrollTop) ? (d.documentElement.scrollTop) : (d.body.scrollTop)
  770. );
  771. },
  772. /**
  773. * Определить размер окна
  774. */
  775. getWindowSize: function () {
  776. var d = unsafeWindow.top.document;
  777. return {
  778. width: /*top.innerWidth ? top.innerWidth :*/ (
  779. (d.documentElement.clientWidth) ? (d.documentElement.clientWidth) : (d.body.offsetWidth)
  780. ),
  781. height: /*top.innerHeight ? top.innerHeight :*/ (
  782. (d.documentElement.clientHeight) ? (d.documentElement.clientHeight) : (d.body.offsetHeight)
  783. )
  784. };
  785. },
  786. /**
  787. * Склеить строки
  788. */
  789. join: function(rows, glue) {
  790. return Array.prototype.slice.call(this.toIterable(rows), 0).join(glue || '');
  791. },
  792. /**
  793. * Вернем значение cookie
  794. */
  795. getCookie: function(name) {
  796. var value = null;
  797. // Проверим, есть ли кука с таким именем
  798. var cookie = unsafeWindow.document.cookie;
  799. var regKey = new RegExp(name.replace(/([\.$?*|{}\(\)\[\]\\\/\+^])/g, '\\$1') + '=(.*?)((; ?)|$)');
  800. var hasMatch = cookie.match(regKey);
  801. if (hasMatch && hasMatch[1]) {
  802. value = decodeURIComponent(hasMatch[1]);
  803. }
  804. return value;
  805. },
  806. /**
  807. * Установим значение cookie
  808. * @param {Object} options Объект с дополнительными значениями
  809. * - expires Срок действия куки: {Number} количество дней или {Data} дата окончания срока
  810. * - path Путь, отсчитывая от которого будет действовать кука
  811. * - domain Домен, в пределах которого будет действовать кука
  812. * - secure Кука для https-соединения
  813. */
  814. setCookie: function(name, value, options) {
  815. // Можно опустить значение куки, если нужно удалить
  816. if (!value)
  817. value = '';
  818. options = options || {};
  819. // Проверяем, задана дата или количество дней
  820. var expires = '';
  821. if (options.expires && (typeof options.expires == 'number' || options.expires.toUTCString)) {
  822. var date;
  823. if (typeof options.expires == 'number') {
  824. date = new Date();
  825. date.setTime(date.getTime() + (options.expires * 24 * 60 * 60 * 1000));
  826. } else {
  827. date = options.expires;
  828. }
  829. expires = '; expires=' + date.toUTCString();
  830. }
  831. // Проставляем другие опции
  832. var path = options.path ? '; path=' + (options.path) : '';
  833. var domain = options.domain ? '; domain=' + (options.domain) : '';
  834. var secure = (options.secure === true) ? '; secure' : '';
  835. unsafeWindow.document.cookie = [name, '=', encodeURIComponent(value), expires, path, domain, secure].join('');
  836. },
  837. /**
  838. * Удалим значение cookie
  839. */
  840. removeCookie: function(name) {
  841. this.setCookie(name, null, { expires: -1 });
  842. },
  843. /**
  844. * Отладка
  845. */
  846. groupDir: function(name, object) {
  847. console.group(name);
  848. console.dir(object);
  849. console.groupEnd();
  850. },
  851. /**
  852. * Отладка: ошибка с пользовательским сообщением
  853. */
  854. errorist: function(error, text, parameters) {
  855. var params = Array.prototype.slice.call(arguments, 1);
  856. params.unshift('#FFEBEB');
  857. this.coloredLog(params);
  858. console.error(error);
  859. },
  860. /**
  861. * Отладка: вывод цветной строки
  862. */
  863. coloredLog: function(color, text, parameters) {
  864. var params = Array.prototype.slice.call(arguments, 2);
  865. params.unshift('background-color: ' + color + ';');
  866. params.unshift('%c' + text);
  867. console.debug.apply(console, params);
  868. },
  869. /**
  870. * XPath-запрос
  871. */
  872. xpath: function(selector) {
  873. var nodes = document.evaluate(selector, document, null, XPathResult.ANY_TYPE, null);
  874. var thisNode = nodes.iterateNext();
  875. while (thisNode) {
  876. console.debug(thisNode.textContent);
  877. thisNode = nodes.iterateNext();
  878. }
  879. },
  880. /**
  881. * Упаковать для хранилища
  882. */
  883. packToStorage: function(objBox) {
  884. var clone = this.extend({}, objBox);
  885. this.each(clone, function(property, index) {
  886. if (typeof property == 'function') {
  887. clone[index] = property.toString();
  888. }
  889. if (typeof property == 'object') {
  890. clone[index] = this.packToStorage(property);
  891. }
  892. }, this);
  893. return JSON.stringify(clone);
  894. },
  895. /**
  896. * Распаковать из хранилища
  897. */
  898. unpackFromStorage: function(objBox) {
  899. var result = {};
  900. try {
  901. result = JSON.parse(objBox);
  902. } catch (e) {
  903. try {
  904. result = eval('(' + objBox + ')');
  905. } catch (e) {
  906. result = objBox;
  907. }
  908. }
  909. if (typeof result == 'object') {
  910. for (var property in result) {
  911. result[property] = this.unpackFromStorage(result[property]);
  912. }
  913. }
  914. return result;
  915. }
  916. };
  917. // Добавляем обратный порядок в jQuery
  918. if (typeof jQuery != 'undefined') {
  919. if (typeof jQuery.fn.reverse != 'function') {
  920. jQuery.fn.reverse = function() {
  921. return jQuery(this.get().reverse());
  922. };
  923. }
  924. if (typeof jQuery.fn.softHide != 'function') {
  925. jQuery.fn.softHide = function() {
  926. return jQuery(this).css({ visibility: 'hidden' });
  927. };
  928. }
  929. }
  930.  
  931. // форматирование строки
  932. unsafeWindow.String.format = unsafeWindow.__krokodil.format;
  933. //отладка
  934. unsafeWindow.console.groupDir = unsafeWindow.__krokodil.groupDir;
  935. unsafeWindow.console.coloredLog = unsafeWindow.__krokodil.coloredLog;
  936. unsafeWindow.console.errorist = unsafeWindow.__krokodil.errorist;
  937.  
  938. console.coloredLog('red', 'Include Tools');
  939. })(paramWindow());

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址