TankTrouble Development Library

Shared library for TankTrouble userscript development

当前为 2023-12-26 提交的版本,查看 最新版本

此脚本不应直接安装。它是供其他脚本使用的外部库,要使用该库请加入元指令 // @require https://update.cn-greasyfork.org/scripts/482092/1301938/TankTrouble%20Development%20Library.js

  1. // ==UserScript==
  2. // @name TankTrouble Development Library
  3. // @author commander
  4. // @namespace https://github.com/asger-finding
  5. // @version 0.0.6
  6. // @license GPL-3.0
  7. // @description Shared library for TankTrouble userscript development
  8. // @match *://*.tanktrouble.com/*
  9. // @grant none
  10. // @run-at document-start
  11. // @noframes
  12. // ==/UserScript==
  13.  
  14. /* eslint-disable no-unused-vars */
  15.  
  16. class Loader {
  17.  
  18. /**
  19. * Pass a function to a hook with the correct context
  20. * @param context Function context (e.g `window`)
  21. * @param funcName Function identifier in the context
  22. * @param hook Hook to call before the original
  23. * @param attributes Optionally additional descriptors
  24. */
  25. static hookFunction(context, funcName, hook, attributes) {
  26. const original = Reflect.get(context, funcName);
  27. if (typeof original !== 'function') throw new Error('Item passed is not typeof function');
  28.  
  29. Reflect.defineProperty(context, funcName, {
  30. /**
  31. * Call the hook with the original function bound to its context
  32. * and supply with the arguments list
  33. * @param args Arguments passed from outside
  34. * @returns Original function return value
  35. */
  36. value: (...args) => hook(original.bind(context), ...args),
  37. ...attributes
  38. });
  39. }
  40.  
  41. /**
  42. * Fires when the `main()` function is done on TankTrouble.
  43. * @returns Promise that resolves when Content.init() finishes
  44. */
  45. static whenContentInitialized() {
  46. if (GM.info.script.runAt !== 'document-start') return Loader.#hookContentInit();
  47. return whenContentLoaded().then(() => Loader.#hookContentInit());
  48. }
  49.  
  50. /**
  51. * Fires when the document is readyState `interactive` or `complete`
  52. * @returns Promise that resolves upon content loaded
  53. */
  54. static whenContentLoaded() {
  55. return new Promise(resolve => {
  56. if (document.readyState === 'interactive' || document.readyState === 'complete') resolve();
  57. else document.addEventListener('DOMContentLoaded', () => resolve());
  58. });
  59. }
  60.  
  61. /**
  62. * Apply a hook to the Content.init function which resolves when the promise ends
  63. * @returns Promise when Content.init has finished
  64. * @private
  65. */
  66. static #hookContentInit() {
  67. return new Promise(resolve => {
  68. Loader.hookFunction(Content, 'init', (original, ...args) => {
  69. const result = original(...args);
  70.  
  71. resolve();
  72. return result;
  73.  
  74. // Allow overriding so the event
  75. // listeners can bubble up
  76. }, { configurable: true });
  77. });
  78. }
  79.  
  80. }