utils.js-93Akkord-Fork

GitHub userscript utilities

此脚本不应直接安装,它是一个供其他脚本使用的外部库。如果您需要使用该库,请在脚本元属性加入:// @require https://update.gf.qytechs.cn/scripts/483333/1302836/utilsjs-93Akkord-Fork.js

  1. /* GitHub userscript utilities v0.2.3
  2. * Copyright © 2022 Rob Garrison
  3. * License: MIT
  4. */
  5. /* exported
  6. * $ $$
  7. * addClass removeClass toggleClass
  8. * removeEls removeSelection
  9. * on off make
  10. * debounce
  11. */
  12. // 'use strict';
  13.  
  14. var REGEX = {
  15. WHITESPACE: /\s+/,
  16. NAMESPACE: /[.:]/,
  17. COMMA: /\s*,\s*/,
  18. };
  19.  
  20. /* DOM utilities */
  21. /**
  22. * Find & return a single DOM node
  23. * @param {String} selector - CSS selector string
  24. * @param {HTMLElement} el - DOM node to start the query (defaults to document)
  25. * @returns {HTMLElement|null}
  26. */
  27. const $ = (selector, el) => (el || document).querySelector(selector);
  28.  
  29. /**
  30. * Find & return multiple DOM nodes
  31. * @param {String} selector - CSS selector string
  32. * @param {HTMLElement} el - DOM node to start the query (defaults to document)
  33. * @returns {HTMLElement[]}
  34. */
  35. const $$ = (selector, el) => [...(el || document).querySelectorAll(selector)];
  36.  
  37. /**
  38. * Common functions
  39. */
  40. var _ = {};
  41. /**
  42. * Return an array of elements
  43. * @param {HTMLElement|HTMLElement[]|NodeList} elements
  44. * @returns {HTMLElement[]}
  45. */
  46. _.createElementArray = (elements) => {
  47. if (Array.isArray(elements)) {
  48. return elements;
  49. }
  50. return elements instanceof NodeList ? [...elements] : [elements];
  51. };
  52. /**
  53. * Common event listener code
  54. * @param {String} type - "add" or "remove" event listener
  55. * @param {HTMLElement[]} els - DOM node array that need listeners
  56. * @param {String} name - Event name, e.g. "click", "mouseover", etc
  57. * @param {Function} handler - Event callback
  58. * @param {Object} options - Event listener options or useCapture - see
  59. * https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#parameters
  60. */
  61. _.eventListener = (type, els, name, handler, options) => {
  62. const events = name.split(REGEX.WHITESPACE);
  63. _.createElementArray(els).forEach((el) => {
  64. events.forEach((ev) => {
  65. el?.[`${type}EventListener`](ev, handler, options);
  66. });
  67. });
  68. };
  69. /**
  70. * Create an array of classes/event types from a space or comma separated string
  71. * @param {String} classes - space or comma separated list of classes or events
  72. * @returns {String[]}
  73. */
  74. _.getClasses = (classes) => {
  75. if (Array.isArray(classes)) {
  76. return classes;
  77. }
  78. const names = classes.toString();
  79. return names.includes(',') ? names.split(REGEX.COMMA) : [names];
  80. };
  81.  
  82. /**
  83. * Add class name(s) to one or more elements
  84. * @param {HTMLElements[]|Nodelist|HTMLElement|Node} elements
  85. * @param {string|array} classes - class name(s) to add; string can contain a
  86. * comma separated list
  87. */
  88. var addClass = (elements, classes) => {
  89. const classNames = _.getClasses(classes);
  90. const els = _.createElementArray(elements);
  91. let index = els.length;
  92. while (index--) {
  93. els[index]?.classList.add(...classNames);
  94. }
  95. };
  96.  
  97. /**
  98. * Remove class name(s) from one or more elements
  99. * @param {HTMLElements[]|NodeList|HTMLElement|Node} elements
  100. * @param {string|array} classes - class name(s) to add; string can contain a
  101. * comma separated list
  102. */
  103. var removeClass = (elements, classes) => {
  104. const classNames = _.getClasses(classes);
  105. const els = _.createElementArray(elements);
  106. let index = els.length;
  107. while (index--) {
  108. els[index]?.classList.remove(...classNames);
  109. }
  110. };
  111.  
  112. /**
  113. * Toggle class name of DOM element(s)
  114. * @param {HTMLElement|HTMLElement[]|NodeList} els
  115. * @param {string} name - class name to toggle (toggle only accepts one name)
  116. * @param {boolean} flag - force toggle; true = add class, false = remove class;
  117. * if undefined, the class will be toggled based on the element's class name
  118. */
  119. // flag = true, then add class
  120. var toggleClass = (elements, className, flag) => {
  121. const els = _.createElementArray(elements);
  122. let index = elms.length;
  123. while (index--) {
  124. els[index]?.classList.toggle(className, flag);
  125. }
  126. };
  127.  
  128. /**
  129. * Remove DOM nodes
  130. * @param {String} selector - CSS selector string
  131. * @param {HTMLElement|undefined} el - parent DOM node (defaults to document)
  132. */
  133. var removeEls = (selector, el) => {
  134. let els = $$(selector, el);
  135. let index = els.length;
  136. while (index--) {
  137. els[index].parentNode.removeChild(els[index]);
  138. }
  139. };
  140.  
  141. /**
  142. * Remove text selection
  143. */
  144. var removeSelection = () => {
  145. // remove text selection - https://stackoverflow.com/a/3171348/145346
  146. const sel = window.getSelection ? window.getSelection() : document.selection;
  147. if (sel) {
  148. if (sel.removeAllRanges) {
  149. sel.removeAllRanges();
  150. } else if (sel.empty) {
  151. sel.empty();
  152. }
  153. }
  154. };
  155.  
  156. /**
  157. * Add/remove event listener
  158. * @param {HTMLElement|HTMLElement[]|NodeList} els
  159. * @param {string} name - event name(s) to bind, e.g. "mouseup mousedown"; also
  160. * accpets a comma separated string, e.g. "mouseup, mousedown"
  161. * @param {function} handler - event handler
  162. * @param {options} eventListener options
  163. */
  164. var on = (els, name = '', handler, options) => {
  165. _.eventListener('add', els, name, handler, options);
  166. };
  167. var off = (els, name = '', handler, options) => {
  168. _.eventListener('remove', els, name, handler, options);
  169. };
  170.  
  171. /**
  172. * **** Helpers ****
  173. */
  174. /**
  175. * Debounce
  176. * @param {Function} fxn - callback executed after debounce
  177. * @param {Number} time - time (in ms) to delay
  178. * @returns {Function} debounced function
  179. */
  180. var debounce = (fxn, time = 500) => {
  181. let timer;
  182. return function () {
  183. clearTimeout(timer);
  184. timer = setTimeout(() => {
  185. fxn.apply(this, arguments);
  186. }, time);
  187. };
  188. };
  189.  
  190. /**
  191. * @typedef Utils~makeOptions
  192. * @type {object}
  193. * @property {string} el - HTML element tag, e.g. "div" (default)
  194. * @property {string} appendTo - selector of target element to append menu
  195. * @property {string} className - CSS classes to add to the element
  196. * @property {object} attrs - HTML attributes (as key/value paries) to set
  197. * @property {object} text - string added to el using textContent
  198. * @property {string} html - html to be added using `innerHTML` (overrides `text`)
  199. * @property {array} children - array of elements to append to the created element
  200. */
  201. /**
  202. * Create a DOM element
  203. * @param {Utils~makeOptions}
  204. * @returns {HTMLElement} (may be already inserted in the DOM)
  205. * @example
  206. make({ el: 'ul', className: 'wrapper', appendTo: 'body' }, [
  207. make({ el: 'li', text: 'item #1' }),
  208. make({ el: 'li', text: 'item #2' })
  209. ]);
  210. */
  211. var make = (obj = {}, children) => {
  212. const el = document.createElement(obj.el || 'div');
  213. const { appendTo } = obj;
  214. const xref = {
  215. className: 'className',
  216. id: 'id',
  217. text: 'textContent',
  218. html: 'innerHTML', // overrides text setting
  219. };
  220. Object.keys(xref).forEach((key) => {
  221. if (obj[key]) {
  222. el[xref[key]] = obj[key];
  223. }
  224. });
  225. if (obj.attrs) {
  226. for (let key in obj.attrs) {
  227. if (obj.attrs.hasOwnProperty(key)) {
  228. el.setAttribute(key, obj.attrs[key]);
  229. }
  230. }
  231. }
  232. if (Array.isArray(children) && children.length) {
  233. children.forEach((child) => el.appendChild(child));
  234. }
  235. if (appendTo) {
  236. const wrap = typeof appendTo === 'string' ? $(appendTo) : appendTo;
  237. if (wrap) {
  238. wrap.appendChild(el);
  239. }
  240. }
  241. return el;
  242. };

QingJ © 2025

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