Greasy Fork is available in English.

UserscriptAPI

My API for userscripts.

Stan na 06-09-2021. Zobacz najnowsza wersja.

Ten skrypt nie powinien być instalowany bezpośrednio. Jest to biblioteka dla innych skyptów do włączenia dyrektywą meta // @require https://update.greatest.deepsurf.us/scripts/409641/967894/UserscriptAPI.js

Aby zainstalować ten skrypt, wymagana jest instalacje jednego z następujących rozszerzeń: Tampermonkey, Greasemonkey lub Violentmonkey.

Aby zainstalować ten skrypt, wymagana jest instalacje jednego z następujących rozszerzeń: Tampermonkey, Violentmonkey.

Aby zainstalować ten skrypt, wymagana jest instalacje jednego z następujących rozszerzeń: Tampermonkey, Violentmonkey.

Aby zainstalować ten skrypt, wymagana będzie instalacja rozszerzenia Tampermonkey lub Userscripts.

You will need to install an extension such as Tampermonkey to install this script.

Aby zainstalować ten skrypt, musisz zainstalować rozszerzenie menedżera skryptów użytkownika.

(Mam już menedżera skryptów użytkownika, pozwól mi to zainstalować!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

Będziesz musiał zainstalować rozszerzenie menedżera stylów użytkownika, aby zainstalować ten styl.

Będziesz musiał zainstalować rozszerzenie menedżera stylów użytkownika, aby zainstalować ten styl.

Musisz zainstalować rozszerzenie menedżera stylów użytkownika, aby zainstalować ten styl.

(Mam już menedżera stylów użytkownika, pozwól mi to zainstalować!)

  1. /* exported UserscriptAPI */
  2. /**
  3. * UserscriptAPI
  4. *
  5. * 需要引入子模块方可工作。所有模块均依赖于 `UserscriptAPI`,模块间的依赖关系如下:
  6. *
  7. * ```plaintext
  8. * +─────────+─────────+
  9. * 模块 | 依赖模块
  10. * +─────────+─────────+
  11. * dom |
  12. * logger |
  13. * message | dom
  14. * tool |
  15. * wait | tool
  16. * web |
  17. * +─────────+─────────+
  18. * ```
  19. * @version 2.0.0.20210906
  20. * @author Laster2800
  21. * @see {@link https://gitee.com/liangjiancang/userscript/tree/master/lib/UserscriptAPI UserscriptAPI}
  22. */
  23. class UserscriptAPI {
  24. /** @type {UserscriptAPIDom} */
  25. dom = this.#getModuleInstance('dom')
  26. /** @type {UserscriptAPILogger} */
  27. logger = this.#getModuleInstance('logger')
  28. /** @type {UserscriptAPIMessage} */
  29. message = this.#getModuleInstance('message')
  30. /** @type {UserscriptAPITool} */
  31. tool = this.#getModuleInstance('tool')
  32. /** @type {UserscriptAPIWait} */
  33. wait = this.#getModuleInstance('wait')
  34. /** @type {UserscriptAPIWeb} */
  35. web = this.#getModuleInstance('web')
  36.  
  37. /**
  38. * @param {Object} [options] 选项
  39. * @param {string} [options.id='default'] 标识符
  40. * @param {string} [options.label] 日志标签,为空时不设置标签
  41. * @param {Object} [options.wait] `wait` API 默认选项(默认值见构造器代码)
  42. * @param {Object} [options.wait.condition] `wait` 条件 API 默认选项
  43. * @param {Object} [options.wait.element] `wait` 元素 API 默认选项
  44. * @param {number} [options.fadeTime=400] UI 渐变时间
  45. */
  46. constructor(options) {
  47. this.options = {
  48. id: 'default',
  49. label: null,
  50. fadeTime: 400,
  51. ...options,
  52. wait: {
  53. condition: {
  54. callback: result => api.logger.info(result),
  55. interval: 100,
  56. timeout: 10000,
  57. onTimeout: function() {
  58. api.logger[this.stopOnTimeout ? 'error' : 'warn'](['TIMEOUT', 'executeAfterConditionPassed', options])
  59. },
  60. stopOnTimeout: true,
  61. stopCondition: null,
  62. onStop: () => api.logger.error(['STOP', 'executeAfterConditionPassed', options]),
  63. stopInterval: 50,
  64. stopTimeout: 0,
  65. onError: e => api.logger.error(['ERROR', 'executeAfterConditionPassed', options, e]),
  66. stopOnError: true,
  67. timePadding: 0,
  68. ...options?.wait?.condition,
  69. },
  70. element: {
  71. base: document,
  72. exclude: null,
  73. callback: el => api.logger.info(el),
  74. subtree: true,
  75. multiple: false,
  76. repeat: false,
  77. throttleWait: 100,
  78. timeout: 10000,
  79. onTimeout: function() {
  80. api.logger[this.stopOnTimeout ? 'error' : 'warn'](['TIMEOUT', 'executeAfterElementLoaded', options])
  81. },
  82. stopOnTimeout: false,
  83. stopCondition: null,
  84. onStop: () => api.logger.error(['STOP', 'executeAfterElementLoaded', options]),
  85. onError: e => api.logger.error(['ERROR', 'executeAfterElementLoaded', options, e]),
  86. stopOnError: true,
  87. timePadding: 0,
  88. ...options?.wait?.element,
  89. },
  90. },
  91. }
  92.  
  93. const win = typeof unsafeWindow == 'undefined' ? window : unsafeWindow
  94. /** @type {UserscriptAPI} */
  95. let api = win[`_userscriptAPI_${this.options.id}`]
  96. if (api) {
  97. api.options = this.options
  98. return api
  99. }
  100. api = win[`_userscriptAPI_${this.options.id}`] = this
  101.  
  102. if (!api.dom) {
  103. api.dom = {
  104. addStyle(css) {
  105. const style = document.createElement('style')
  106. style.setAttribute('type', 'text/css')
  107. style.className = `${api.options.id}-style`
  108. style.appendChild(document.createTextNode(css))
  109. const parent = document.head || document.documentElement
  110. if (parent) {
  111. parent.appendChild(style)
  112. }
  113. },
  114. }
  115. }
  116. if (!api.logger) {
  117. api.logger = {
  118. info: console.log,
  119. warn: console.warn,
  120. error: console.error,
  121. }
  122. }
  123.  
  124. api.dom.addStyle(`
  125. :root {
  126. --${api.options.id}-light-text-color: white;
  127. --${api.options.id}-shadow-color: #000000bf;
  128. }
  129.  
  130. .${api.options.id}-msgbox {
  131. z-index: 100000000;
  132. background-color: var(--${api.options.id}-shadow-color);
  133. font-size: 16px;
  134. max-width: 24em;
  135. min-width: 2em;
  136. color: var(--${api.options.id}-light-text-color);
  137. padding: 0.5em 1em;
  138. border-radius: 0.6em;
  139. opacity: 0;
  140. transition: opacity ${api.options.fadeTime}ms ease-in-out;
  141. user-select: none;
  142. }
  143.  
  144. .${api.options.id}-msgbox .gm-advanced-table td {
  145. vertical-align: middle;
  146. }
  147. .${api.options.id}-msgbox .gm-advanced-table td:first-child {
  148. padding-right: 0.6em;
  149. }
  150. `)
  151. }
  152.  
  153. /** 可访问模块 */
  154. static #modules = {}
  155.  
  156. /**
  157. * 注册模块
  158. * @param {string} name 模块名称
  159. * @param {Object} module 模块类
  160. */
  161. static registerModule(name, module) {
  162. this.#modules[name] = module
  163. }
  164.  
  165. /**
  166. * 获取模块实例
  167. * @param {string} name 模块名称
  168. * @returns {Object} 模块实例,无对应模块时返回 `null`
  169. */
  170. #getModuleInstance(name) {
  171. const module = UserscriptAPI.#modules[name]
  172. return module ? new module(this) : null
  173. }
  174. }