WhiteSevsUtils

一个好用的工具类

目前为 2024-07-24 提交的版本。查看 最新版本

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

  1. (function (global, factory) {
  2. typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
  3. typeof define === 'function' && define.amd ? define(factory) :
  4. (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Utils = factory());
  5. })(this, (function () { 'use strict';
  6.  
  7. class ColorConversion {
  8. /**
  9. * 判断是否是16进制颜色
  10. * @param str
  11. */
  12. isHex(str) {
  13. if (typeof str !== "string") {
  14. return false;
  15. }
  16. if (!str.match(/^(\#|)[0-9a-fA-F]{6}$/)) {
  17. return false;
  18. }
  19. return true;
  20. }
  21. /**
  22. * 16进制颜色转rgba
  23. *
  24. * #ff0000 转 rgba(123,123,123, 0.4)
  25. * @param hex
  26. * @param opacity
  27. */
  28. hexToRgba(hex, opacity) {
  29. if (!this.isHex(hex)) {
  30. // @ts-ignore
  31. throw new TypeError("输入错误的hex", hex);
  32. }
  33. return hex && hex.replace(/\s+/g, "").length === 7
  34. ? "rgba(" +
  35. parseInt("0x" + hex.slice(1, 3)) +
  36. "," +
  37. parseInt("0x" + hex.slice(3, 5)) +
  38. "," +
  39. parseInt("0x" + hex.slice(5, 7)) +
  40. "," +
  41. opacity +
  42. ")"
  43. : "";
  44. }
  45. /**
  46. * hex转rgb
  47. * @param str
  48. * @returns
  49. */
  50. hexToRgb(str) {
  51. if (!this.isHex(str)) {
  52. // @ts-ignore
  53. throw new TypeError("输入错误的hex", str);
  54. }
  55. /* replace替换查找的到的字符串 */
  56. str = str.replace("#", "");
  57. /* match得到查询数组 */
  58. let hxs = str.match(/../g);
  59. for (let index = 0; index < 3; index++) {
  60. // @ts-ignore
  61. hxs[index] = parseInt(hxs[index], 16);
  62. }
  63. return hxs;
  64. }
  65. /**
  66. * rgb转hex
  67. * @param redValue
  68. * @param greenValue
  69. * @param blueValue
  70. * @returns
  71. */
  72. rgbToHex(redValue, greenValue, blueValue) {
  73. /* 验证输入的rgb值是否合法 */
  74. let validPattern = /^\d{1,3}$/;
  75. if (!validPattern.test(redValue.toString()) ||
  76. !validPattern.test(greenValue.toString()) ||
  77. !validPattern.test(blueValue.toString()))
  78. throw new TypeError("输入错误的rgb颜色值");
  79. let hexs = [
  80. redValue.toString(16),
  81. greenValue.toString(16),
  82. blueValue.toString(16),
  83. ];
  84. for (let index = 0; index < 3; index++)
  85. if (hexs[index].length == 1)
  86. hexs[index] = "0" + hexs[index];
  87. return "#" + hexs.join("");
  88. }
  89. /**
  90. * 获取颜色变暗或亮
  91. * @param color 颜色
  92. * @param level 0~1.0
  93. * @returns
  94. */
  95. getDarkColor(color, level) {
  96. if (!this.isHex(color)) {
  97. // @ts-ignore
  98. throw new TypeError("输入错误的hex", color);
  99. }
  100. let rgbc = this.hexToRgb(color);
  101. for (let index = 0; index < 3; index++) {
  102. // @ts-ignore
  103. rgbc[index] = Math.floor(rgbc[index] * (1 - level));
  104. }
  105. // @ts-ignore
  106. return this.rgbToHex(rgbc[0], rgbc[1], rgbc[2]);
  107. }
  108. /**
  109. * 获取颜色变亮
  110. * @param color 颜色
  111. * @param level 0~1.0
  112. * @returns
  113. */
  114. getLightColor(color, level) {
  115. if (!this.isHex(color)) {
  116. // @ts-ignore
  117. throw new TypeError("输入错误的hex", color);
  118. }
  119. let rgbc = this.hexToRgb(color);
  120. for (let index = 0; index < 3; index++) {
  121. // @ts-ignore
  122. rgbc[index] = Math.floor((255 - rgbc[index]) * level + rgbc[index]);
  123. }
  124. // @ts-ignore
  125. return this.rgbToHex(rgbc[0], rgbc[1], rgbc[2]);
  126. }
  127. }
  128.  
  129. class GBKEncoder {
  130. #data = [];
  131. #U2Ghash = {};
  132. #G2Uhash = {};
  133. constructor() {
  134. let dataText = this.handleText("4e:020405060f12171f20212326292e2f313335373c40414244464a5155575a5b6263646567686a6b6c6d6e6f727475767778797a7b7c7d7f808182838485878a#909697999c9d9ea3aaafb0b1b4b6b7b8b9bcbdbec8cccfd0d2dadbdce0e2e6e7e9edeeeff1f4f8f9fafcfe,4f:00020304050607080b0c12131415161c1d212328292c2d2e31333537393b3e3f40414244454748494a4b4c525456616266686a6b6d6e7172757778797a7d8081828586878a8c8e909293959698999a9c9e9fa1a2a4abadb0b1b2b3b4b6b7b8b9babbbcbdbec0c1c2c6c7c8c9cbcccdd2d3d4d5d6d9dbe0e2e4e5e7ebecf0f2f4f5f6f7f9fbfcfdff,50:000102030405060708090a#0b0e1011131516171b1d1e20222324272b2f303132333435363738393b3d3f404142444546494a4b4d5051525354565758595b5d5e5f6061626364666768696a6b6d6e6f70717273747578797a7c7d818283848687898a8b8c8e8f909192939495969798999a9b9c9d9e9fa0a1a2a4a6aaabadaeafb0b1b3b4b5b6b7b8b9bcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdced0d1d2d3d4d5d7d8d9dbdcdddedfe0e1e2e3e4e5e8e9eaebeff0f1f2f4f6f7f8f9fafcfdfeff,51:00010203040508#090a0c0d0e0f1011131415161718191a1b1c1d1e1f2022232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e42474a4c4e4f5052535758595b5d5e5f606163646667696a6f727a7e7f838486878a8b8e8f90919394989a9d9e9fa1a3a6a7a8a9aaadaeb4b8b9babebfc1c2c3c5c8cacdced0d2d3d4d5d6d7d8d9dadcdedfe2e3e5e6e7e8e9eaeceef1f2f4f7fe,52:0405090b0c0f101314151c1e1f2122232526272a2c2f313234353c3e4445464748494b4e4f5253555758#595a5b5d5f6062636466686b6c6d6e7071737475767778797a7b7c7e808384858687898a8b8c8d8e8f91929495969798999a9ca4a5a6a7aeafb0b4b5b6b7b8b9babbbcbdc0c1c2c4c5c6c8cacccdcecfd1d3d4d5d7d9dadbdcdddee0e1e2e3e5e6e7e8e9eaebecedeeeff1f2f3f4f5f6f7f8fbfcfd,53:0102030407090a0b0c0e11121314181b1c1e1f2224252728292b2c2d2f3031323334353637383c3d404244464b4c4d505458595b5d65686a6c6d7276797b7c7d7e80818387888a8e8f#90919293949697999b9c9ea0a1a4a7aaabacadafb0b1b2b3b4b5b7b8b9babcbdbec0c3c4c5c6c7cecfd0d2d3d5dadcdddee1e2e7f4fafeff,54:000205070b1418191a1c2224252a303336373a3d3f4142444547494c4d4e4f515a5d5e5f6061636567696a6b6c6d6e6f7074797a7e7f8183858788898a8d919397989c9e9fa0a1a2a5aeb0b2b5b6b7b9babcbec3c5cacbd6d8dbe0e1e2e3e4ebeceff0f1f4f5f6f7f8f9fbfe,55:0002030405080a0b0c0d0e121315161718191a1c1d1e1f212526#28292b2d3234353638393a3b3d40424547484b4c4d4e4f515253545758595a5b5d5e5f60626368696b6f7071727374797a7d7f85868c8d8e9092939596979a9b9ea0a1a2a3a4a5a6a8a9aaabacadaeafb0b2b4b6b8babcbfc0c1c2c3c6c7c8cacbcecfd0d5d7d8d9dadbdee0e2e7e9edeef0f1f4f6f8f9fafbfcff,56:0203040506070a0b0d1011121314151617191a1c1d202122252628292a2b2e2f30333537383a3c3d3e404142434445464748494a4b4f5051525355565a5b5d5e5f6061#636566676d6e6f70727374757778797a7d7e7f80818283848788898a8b8c8d9091929495969798999a9b9c9d9e9fa0a1a2a4a5a6a7a8a9aaabacadaeb0b1b2b3b4b5b6b8b9babbbdbebfc0c1c2c3c4c5c6c7c8c9cbcccdcecfd0d1d2d3d5d6d8d9dce3e5e6e7e8e9eaeceeeff2f3f6f7f8fbfc,57:00010205070b0c0d0e0f101112131415161718191a1b1d1e202122242526272b313234353637383c3d3f414344454648494b52535455565859626365676c6e707172747578797a7d7e7f80#818788898a8d8e8f90919495969798999a9c9d9e9fa5a8aaacafb0b1b3b5b6b7b9babbbcbdbebfc0c1c4c5c6c7c8c9cacccdd0d1d3d6d7dbdcdee1e2e3e5e6e7e8e9eaebeceef0f1f2f3f5f6f7fbfcfeff,58:0103040508090a0c0e0f101213141617181a1b1c1d1f222325262728292b2c2d2e2f31323334363738393a3b3c3d3e3f4041424345464748494a4b4e4f505253555657595a5b5c5d5f6061626364666768696a6d6e6f707172737475767778797a7b7c7d7f82848687888a8b8c#8d8e8f909194959697989b9c9da0a1a2a3a4a5a6a7aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbdbebfc0c2c3c4c6c7c8c9cacbcccdcecfd0d2d3d4d6d7d8d9dadbdcdddedfe0e1e2e3e5e6e7e8e9eaedeff1f2f4f5f7f8fafbfcfdfeff,59:000103050608090a0b0c0e1011121317181b1d1e2021222326282c30323335363b3d3e3f404345464a4c4d505253595b5c5d5e5f616364666768696a6b6c6d6e6f70717275777a7b7c7e7f8085898b8c8e8f90919495989a9b9c9d9fa0a1a2a6#a7acadb0b1b3b4b5b6b7b8babcbdbfc0c1c2c3c4c5c7c8c9cccdcecfd5d6d9dbdedfe0e1e2e4e6e7e9eaebedeeeff0f1f2f3f4f5f6f7f8fafcfdfe,5a:00020a0b0d0e0f101214151617191a1b1d1e2122242627282a2b2c2d2e2f3033353738393a3b3d3e3f414243444547484b4c4d4e4f5051525354565758595b5c5d5e5f60616364656668696b6c6d6e6f7071727378797b7c7d7e808182838485868788898a8b8c8d8e8f9091939495969798999c9d9e9fa0a1a2a3a4a5a6a7a8a9abac#adaeafb0b1b4b6b7b9babbbcbdbfc0c3c4c5c6c7c8cacbcdcecfd0d1d3d5d7d9dadbdddedfe2e4e5e7e8eaecedeeeff0f2f3f4f5f6f7f8f9fafbfcfdfeff,5b:0001020304050607080a0b0c0d0e0f10111213141518191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303133353638393a3b3c3d3e3f4142434445464748494a4b4c4d4e4f52565e606167686b6d6e6f7274767778797b7c7e7f82868a8d8e90919294969fa7a8a9acadaeafb1b2b7babbbcc0c1c3c8c9cacbcdcecf#d1d4d5d6d7d8d9dadbdce0e2e3e6e7e9eaebecedeff1f2f3f4f5f6f7fdfe,5c:0002030507080b0c0d0e10121317191b1e1f2021232628292a2b2d2e2f303233353637434446474c4d5253545657585a5b5c5d5f62646768696a6b6c6d70727374757677787b7c7d7e808384858687898a8b8e8f9293959d9e9fa0a1a4a5a6a7a8aaaeafb0b2b4b6b9babbbcbec0c2c3c5c6c7c8c9cacccdcecfd0d1d3d4d5d6d7d8dadbdcdddedfe0e2e3e7e9ebeceeeff1f2f3f4f5f6f7f8f9fafcfdfeff,5d:00#01040508090a0b0c0d0f10111213151718191a1c1d1f2021222325282a2b2c2f3031323335363738393a3b3c3f4041424344454648494d4e4f5051525354555657595a5c5e5f6061626364656667686a6d6e7071727375767778797a7b7c7d7e7f8081838485868788898a8b8c8d8e8f9091929394959697989a9b9c9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b8b9babbbcbdbebfc0c1c2c3c4c6c7c8c9cacbcccecfd0d1d2d3d4d5d6d7d8d9dadcdfe0e3e4eaeced#f0f5f6f8f9fafbfcff,5e:000407090a0b0d0e1213171e1f20212223242528292a2b2c2f303233343536393a3e3f404143464748494a4b4d4e4f50515253565758595a5c5d5f60636465666768696a6b6c6d6e6f70717577797e8182838588898c8d8e92989b9da1a2a3a4a8a9aaabacaeafb0b1b2b4babbbcbdbfc0c1c2c3c4c5c6c7c8cbcccdcecfd0d4d5d7d8d9dadcdddedfe0e1e2e3e4e5e6e7e9ebecedeeeff0f1f2f3f5f8f9fbfcfd,5f:050607090c0d0e10121416191a1c1d1e21222324#282b2c2e30323334353637383b3d3e3f4142434445464748494a4b4c4d4e4f5154595a5b5c5e5f60636567686b6e6f72747576787a7d7e7f83868d8e8f919394969a9b9d9e9fa0a2a3a4a5a6a7a9abacafb0b1b2b3b4b6b8b9babbbebfc0c1c2c7c8cacbced3d4d5dadbdcdedfe2e3e5e6e8e9eceff0f2f3f4f6f7f9fafc,60:0708090b0c10111317181a1e1f2223242c2d2e3031323334363738393a3d3e404445464748494a4c4e4f5153545657585b5c5e5f606165666e71727475777e80#8182858687888a8b8e8f909193959798999c9ea1a2a4a5a7a9aaaeb0b3b5b6b7b9babdbebfc0c1c2c3c4c7c8c9cccdcecfd0d2d3d4d6d7d9dbdee1e2e3e4e5eaf1f2f5f7f8fbfcfdfeff,61:02030405070a0b0c1011121314161718191b1c1d1e21222528292a2c2d2e2f303132333435363738393a3b3c3d3e4041424344454647494b4d4f50525354565758595a5b5c5e5f606163646566696a6b6c6d6e6f717273747678797a7b7c7d7e7f808182838485868788898a8c8d8f9091929395#969798999a9b9c9e9fa0a1a2a3a4a5a6aaabadaeafb0b1b2b3b4b5b6b8b9babbbcbdbfc0c1c3c4c5c6c7c9cccdcecfd0d3d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e7e8e9eaebecedeeeff0f1f2f3f4f6f7f8f9fafbfcfdfe,62:00010203040507091314191c1d1e2023262728292b2d2f303132353638393a3b3c424445464a4f50555657595a5c5d5e5f6061626465687172747577787a7b7d818283858687888b8c8d8e8f9094999c9d9ea3a6a7a9aaadaeafb0b2b3b4b6b7b8babec0c1#c3cbcfd1d5dddee0e1e4eaebf0f2f5f8f9fafb,63:00030405060a0b0c0d0f10121314151718191c2627292c2d2e30313334353637383b3c3e3f40414447484a51525354565758595a5b5c5d60646566686a6b6c6f707273747578797c7d7e7f81838485868b8d9193949597999a9b9c9d9e9fa1a4a6abafb1b2b5b6b9bbbdbfc0c1c2c3c5c7c8cacbccd1d3d4d5d7d8d9dadbdcdddfe2e4e5e6e7e8ebeceeeff0f1f3f5f7f9fafbfcfe,64:0304060708090a0d0e111215161718191a1d1f222324#252728292b2e2f3031323335363738393b3c3e404243494b4c4d4e4f505153555657595a5b5c5d5f60616263646566686a6b6c6e6f70717273747576777b7c7d7e7f8081838688898a8b8c8d8e8f90939497989a9b9c9d9fa0a1a2a3a5a6a7a8aaabafb1b2b3b4b6b9bbbdbebfc1c3c4c6c7c8c9cacbcccfd1d3d4d5d6d9dadbdcdddfe0e1e3e5e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff,65:01020304050607080a0b0c0d0e0f10111314151617191a1b1c1d1e1f2021#222324262728292a2c2d30313233373a3c3d404142434446474a4b4d4e5052535457585a5c5f606164656768696a6d6e6f7173757678797a7b7c7d7e7f8081828384858688898a8d8e8f92949596989a9d9ea0a2a3a6a8aaacaeb1b2b3b4b5b6b7b8babbbebfc0c2c7c8c9cacdd0d1d3d4d5d8d9dadbdcdddedfe1e3e4eaebf2f3f4f5f8f9fbfcfdfeff,66:0104050708090b0d1011121617181a1b1c1e2122232426292a2b2c2e3032333738393a3b3d3f40424445464748494a4d4e505158#595b5c5d5e6062636567696a6b6c6d7172737578797b7c7d7f808183858688898a8b8d8e8f909293949598999a9b9c9e9fa0a1a2a3a4a5a6a9aaabacadafb0b1b2b3b5b6b7b8babbbcbdbfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8dadedfe0e1e2e3e4e5e7e8eaebecedeeeff1f5f6f8fafbfd,67:010203040506070c0e0f1112131618191a1c1e20212223242527292e303233363738393b3c3e3f414445474a4b4d5254555758595a5b5d62636466676b6c6e717476#78797a7b7d8082838586888a8c8d8e8f9192939496999b9fa0a1a4a6a9acaeb1b2b4b9babbbcbdbebfc0c2c5c6c7c8c9cacbcccdced5d6d7dbdfe1e3e4e6e7e8eaebedeef2f5f6f7f8f9fafbfcfe,68:01020304060d1012141518191a1b1c1e1f20222324252627282b2c2d2e2f30313435363a3b3f474b4d4f52565758595a5b5c5d5e5f6a6c6d6e6f707172737578797a7b7c7d7e7f8082848788898a8b8c8d8e90919294959698999a9b9c9d9e9fa0a1a3a4a5a9aaabacaeb1b2b4b6b7b8#b9babbbcbdbebfc1c3c4c5c6c7c8cacccecfd0d1d3d4d6d7d9dbdcdddedfe1e2e4e5e6e7e8e9eaebecedeff2f3f4f6f7f8fbfdfeff,69:00020304060708090a0c0f11131415161718191a1b1c1d1e21222325262728292a2b2c2e2f313233353637383a3b3c3e4041434445464748494a4b4c4d4e4f50515253555658595b5c5f616264656768696a6c6d6f7072737475767a7b7d7e7f8183858a8b8c8e8f909192939697999a9d9e9fa0a1a2a3a4a5a6a9aaacaeafb0b2b3b5b6b8b9babcbd#bebfc0c2c3c4c5c6c7c8c9cbcdcfd1d2d3d5d6d7d8d9dadcdddee1e2e3e4e5e6e7e8e9eaebeceeeff0f1f3f4f5f6f7f8f9fafbfcfe,6a:000102030405060708090b0c0d0e0f10111213141516191a1b1c1d1e20222324252627292b2c2d2e30323334363738393a3b3c3f40414243454648494a4b4c4d4e4f515253545556575a5c5d5e5f60626364666768696a6b6c6d6e6f70727374757677787a7b7d7e7f81828385868788898a8b8c8d8f929394959698999a9b9c9d9e9fa1a2a3a4a5a6#a7a8aaadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff,6b:000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f252628292a2b2c2d2e2f303133343536383b3c3d3f4041424445484a4b4d4e4f5051525354555657585a5b5c5d5e5f606168696b6c6d6e6f7071727374757677787a7d7e7f808588#8c8e8f909194959798999c9d9e9fa0a2a3a4a5a6a7a8a9abacadaeafb0b1b2b6b8b9babbbcbdbec0c3c4c6c7c8c9caccced0d1d8dadcdddedfe0e2e3e4e5e6e7e8e9ecedeef0f1f2f4f6f7f8fafbfcfeff,6c:000102030408090a0b0c0e12171c1d1e2023252b2c2d31333637393a3b3c3e3f434445484b4c4d4e4f5152535658595a62636566676b6c6d6e6f71737577787a7b7c7f8084878a8b8d8e9192959697989a9c9d9ea0a2a8acafb0b4b5b6b7bac0c1c2c3c6c7c8cbcdcecfd1d2d8#d9dadcdddfe4e6e7e9ecedf2f4f9ff,6d:000203050608090a0d0f101113141516181c1d1f20212223242628292c2d2f30343637383a3f404244494c50555657585b5d5f6162646567686b6c6d707172737576797a7b7d7e7f8081838486878a8b8d8f9092969798999a9ca2a5acadb0b1b3b4b6b7b9babbbcbdbec1c2c3c8c9cacdcecfd0d2d3d4d5d7dadbdcdfe2e3e5e7e8e9eaedeff0f2f4f5f6f8fafdfeff,6e:0001020304060708090b0f12131518191b1c1e1f222627282a2c2e30313335#3637393b3c3d3e3f40414245464748494a4b4c4f5051525557595a5c5d5e606162636465666768696a6c6d6f707172737475767778797a7b7c7d8081828487888a8b8c8d8e91929394959697999a9b9d9ea0a1a3a4a6a8a9abacadaeb0b3b5b8b9bcbebfc0c3c4c5c6c8c9cacccdced0d2d6d8d9dbdcdde3e7eaebecedeeeff0f1f2f3f5f6f7f8fafbfcfdfeff,6f:000103040507080a0b0c0d0e101112161718191a1b1c1d1e1f212223252627282c2e303234353738393a3b3c3d3f404142#43444548494a4c4e4f5051525354555657595a5b5d5f60616364656768696a6b6c6f707173757677797b7d7e7f808182838586878a8b8f909192939495969798999a9b9d9e9fa0a2a3a4a5a6a8a9aaabacadaeafb0b1b2b4b5b7b8babbbcbdbebfc1c3c4c5c6c7c8cacbcccdcecfd0d3d4d5d6d7d8d9dadbdcdddfe2e3e4e5e6e7e8e9eaebecedf0f1f2f3f4f5f6f7f8f9fafbfcfdfeff,70:000102030405060708090a0b0c0d0e0f1012131415161718191c1d1e1f2021222425262728292a#2b2c2d2e2f30313233343637383a3b3c3d3e3f404142434445464748494a4b4d4e505152535455565758595a5b5c5d5f606162636465666768696a6e7172737477797a7b7d818283848687888b8c8d8f90919397989a9b9e9fa0a1a2a3a4a5a6a7a8a9aab0b2b4b5b6babebfc4c5c6c7c9cbcccdcecfd0d1d2d3d4d5d6d7dadcdddee0e1e2e3e5eaeef0f1f2f3f4f5f6f8fafbfcfeff,71:0001020304050607080b0c0d0e0f111214171b1c1d1e1f2021222324252728292a2b2c2d2e323334#353738393a3b3c3d3e3f4041424344464748494b4d4f505152535455565758595a5b5d5f6061626365696a6b6c6d6f707174757677797b7c7e7f8081828385868788898b8c8d8e909192939596979a9b9c9d9ea1a2a3a4a5a6a7a9aaabadaeafb0b1b2b4b6b7b8babbbcbdbebfc0c1c2c4c5c6c7c8c9cacbcccdcfd0d1d2d3d6d7d8d9dadbdcdddedfe1e2e3e4e6e8e9eaebecedeff0f1f2f3f4f5f6f7f8fafbfcfdfeff,72:0001020304050708090a0b0c0d0e0f101112131415161718191a#1b1c1e1f2021222324252627292b2d2e2f3233343a3c3e40414243444546494a4b4e4f505153545557585a5c5e60636465686a6b6c6d707173747677787b7c7d828385868788898c8e9091939495969798999a9b9c9d9ea0a1a2a3a4a5a6a7a8a9aaabaeb1b2b3b5babbbcbdbebfc0c5c6c7c9cacbcccfd1d3d4d5d6d8dadb#95$,30:000102,00b702:c9c7,00a830:0305,2014ff5e20:162618191c1d,30:141508090a0b0c0d0e0f16171011,00:b1d7f7,22:362728110f2a2908371aa52520,231222:992b2e614c483d1d606e6f64651e3534,26:4240,00b020:3233,2103ff0400a4ff:e0e1,203000a7211626:0605,25:cbcfcec7c6a1a0b3b2,203b21:92909193,30:13#95$,21:70717273747576777879#4$,24:88898a8b8c8d8e8f909192939495969798999a9b7475767778797a7b7c7d7e7f808182838485868760616263646566676869##,32:20212223242526272829##,21:606162636465666768696a6b#97$,ff:010203e505060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5de3#95$,30:4142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f90919293#106$a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6#103$,03:9192939495969798999a9b9c9d9e9fa0a1a3a4a5a6a7a8a9#6$b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c3c4c5c6c7c8c9#5$,fe:3536393a3f403d3e41424344##3b3c373831#3334#104$,04:10111213141501161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f#13$30313233343551363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f#11$,02:cacbd9,20:13152535,21:050996979899,22:151f23526667bf,25:505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f7071727381828384858687#88898a8b8c8d8e8f939495bcbde2e3e4e5,2609229530:121d1e#9$,010100e101ce00e0011300e9011b00e8012b00ed01d000ec014d00f301d200f2016b00fa01d400f901:d6d8dadc,00:fcea,0251e7c701:4448,e7c802:61#2$,31:05060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20212223242526272829#19$,30:212223242526272829,32a333:8e8f9c9d9ea1c4ced1d2d5,fe30ff:e2e4#,212132:31#,20:10#1$,30:fc9b9cfdfe069d9e,fe:494a4b4c4d4e4f50515254555657595a5b5c5d5e5f6061#626364656668696a6b,e7:e7e8e9eaebecedeeeff0f1f2f3,30:07#11$,25:000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b#13$,72:dcdddfe2e3e4e5e6e7eaebf5f6f9fdfeff,73:00020405060708090b0c0d0f1011121418191a1f2023242627282d2f30323335363a3b3c3d404142434445464748#494a4b4c4e4f515354555658595a5b5c5d5e5f6162636465666768696a6b6e7071#92$72737475767778797a7b7c7d7f808182838586888a8c8d8f90929394959798999a9c9d9ea0a1a3a4a5a6a7a8aaacadb1b4b5b6b8b9bcbdbebfc1c3c4c5c6c7#cbccced2d3d4d5d6d7d8dadbdcdddfe1e2e3e4e6e8eaebeceeeff0f1f3f4f5f6f7#92$f8f9fafbfcfdfeff,74:0001020407080b0c0d0e1112131415161718191c1d1e1f2021232427292b2d2f31323738393a3b3d3e3f4042434445464748494a4b4c4d#4e4f505152535456585d606162636465666768696a6b6c6e6f717273747578797a#92$7b7c7d7f8284858688898a8c8d8f9192939495969798999a9b9d9fa0a1a2a3a4a5a6aaabacadaeafb0b1b2b3b4b5b6b7b8b9bbbcbdbebfc0c1c2c3c4c5c6c7#c8c9cacbcccdcecfd0d1d3d4d5d6d7d8d9dadbdddfe1e5e7e8e9eaebecedf0f1f2#92$f3f5f8f9fafbfcfdfe,75:0001020305060708090a0b0c0e1012141516171b1d1e202122232426272a2e3436393c3d3f414243444647494a4d5051525355565758#5d5e5f60616263646768696b6c6d6e6f7071737576777a7b7c7d7e808182848587#92$88898a8c8d8e909395989b9c9ea2a6a7a8a9aaadb6b7babbbfc0c1c6cbcccecfd0d1d3d7d9dadcdddfe0e1e5e9ecedeeeff2f3f5f6f7f8fafbfdfe,76:02040607#08090b0d0e0f11121314161a1c1d1e212327282c2e2f31323637393a3b3d414244#92$45464748494a4b4e4f50515253555758595a5b5d5f6061626465666768696a6c6d6e7071727374757677797a7c7f80818385898a8c8d8f9092949597989a9b#9c9d9e9fa0a1a2a3a5a6a7a8a9aaabacadafb0b3b5b6b7b8b9babbbcbdbec0c1c3,554a963f57c3632854ce550954c076:914c,853c77ee827e788d72319698978d6c285b894ffa630966975cb880fa684880ae660276ce51f9655671ac7ff1888450b2596561ca6fb382ad634c625253ed54277b06516b75a45df462d48dcb9776628a8019575d97387f627238767d67cf767e64464f708d2562dc7a17659173ed642c6273822c9881677f724862:6ecc,4f3474e3534a529e7eca90a65e2e6886699c81807ed168d278c5868c9551508d8c2482de80de53058912526576:c4c7c9cbccd3d5d9dadcdddee0e1e2e3e4e6e7e8e9eaebecedf0f3f5f6f7fafbfdff,77:00020305060a0c0e0f1011121314151617181b1c1d1e21232425272a2b#2c2e3031323334393b3d3e3f4244454648494a4b4c4d4e4f52535455565758595c,858496f94fdd582199715b9d62:b1a5,66b48c799c8d7206676f789160b253:5117,8f8880cc8d1d94a1500d72c8590760eb711988ab595482ef672c7b285d297ef7752d6cf58e668ff8903c9f3b6bd491197b145f7c78a784d6853d6b:d5d9d6,5e:0187,75f995ed655d5f:0ac5,8f9f58c181c2907f965b97ad8fb97f168d2c62414fbf53:d85e,8f:a8a9ab,904d68075f6a819888689cd6618b522b762a5f6c658c6fd26ee85bbe644851:75b0,67c44e1979c9997c70b377:5d5e5f606467696a6d6e6f7071727374757677787a7b7c818283868788898a8b8f90939495969798999a9b9c9d9ea1a3a4a6a8abadaeafb1b2b4b6b7b8b9ba#bcbec0c1c2c3c4c5c6c7c8c9cacbcccecfd0d1d2d3d4d5d6d8d9dadddedfe0e1e4,75c55e7673bb83e064ad62e894b56ce2535a52c3640f94c27b944f2f5e1b823681:168a,6e246cca9a736355535c54fa886557e04e0d5e036b657c3f90e8601664e6731c88c16750624d8d22776c8e2991c75f6983dc8521991053c286956b8b60:ede8,707f82:cd31,4ed36ca785cf64cd7cd969fd66f9834953957b564fa7518c6d4b5c428e6d63d253c983:2c36,67e578b4643d5bdf5c945dee8be762c667f48c7a640063ba8749998b8c177f2094f24ea7961098a4660c731677:e6e8eaeff0f1f2f4f5f7f9fafbfc,78:0304050607080a0b0e0f101315191b1e20212224282a2b2e2f31323335363d3f414243444648494a4b4d4f51535458595a#5b5c5e5f606162636465666768696f7071727374757678797a7b7d7e7f80818283,573a5c1d5e38957f507f80a05382655e7545553150218d856284949e671d56326f6e5de2543570928f66626f64a463a35f7b6f8890f481e38fb05c1866685ff16c8996488d81886c649179f057ce6a59621054484e587a0b60e96f848bda627f901e9a8b79e4540375f4630153196c608fdf5f1b9a70803b9f7f4f885c3a8d647fc565a570bd51:45b2,866b5d075ba062bd916c75748e0c7a2061017b794ec77ef877854e1181ed521d51fa6a7153a88e87950496cf6ec19664695a78:848586888a8b8f9092949596999d9ea0a2a4a6a8a9aaabacadaeafb5b6b7b8babbbcbdbfc0c2c3c4c6c7c8cccdcecfd1d2d3d6d7d8dadbdcdddedfe0e1e2e3#e4e5e6e7e9eaebedeeeff0f1f3f5f6f8f9fbfcfdfeff,79:00020304060708090a0b0c,784050a877d7641089e6590463e35ddd7a7f693d4f20823955984e3275ae7a975e:628a,95ef521b5439708a6376952457826625693f918755076df37eaf882262337ef075b5832878c196cc8f9e614874f78bcd6b64523a8d506b21806a847156f153064e:ce1b,51d17c97918b7c074fc38e7f7be17a9c64675d1450ac810676017cb96dec7fe067515b:58f8,78cb64:ae13,63:aa2b,9519642d8fbe7b5476296253592754466b7950a362345e266b864ee38d37888b5f85902e79:0d0e0f1011121415161718191a1b1c1d1f2021222325262728292a2b2c2d2e2f3031323335363738393d3f42434445474a4b4c4d4e4f505152545558596163#6466696a6b6c6e70717273747576797b7c7d7e7f8283868788898b8c8d8e909192,6020803d62c54e39535590f863b880c665e66c2e4f4660ee6de18bde5f3986cb5f536321515a83616863520063638e4850125c9b79775bfc52307a3b60bc905376d75f:b797,76848e6c706f767b7b4977aa51f3909358244f4e6ef48fea654c7b1b72c46da47fdf5ae162b55e95573084827b2c5e1d5f1f90127f1498a063826ec7789870b95178975b57ab75354f4375385e9760e659606dc06bbf788953fc96d551cb52016389540a94938c038dcc7239789f87768fed8c0d53e079:939495969798999b9c9d9e9fa0a1a2a3a4a5a6a8a9aaabacadaeafb0b1b2b4b5b6b7b8bcbfc2c4c5c7c8cacccecfd0d3d4d6d7d9dadbdcdddee0e1e2e5e8ea#eceef1f2f3f4f5f6f7f9fafcfeff,7a:0104050708090a0c0f10111213151618191b1c,4e0176ef53ee948998769f0e952d5b9a8ba24e:221c,51ac846361c252a8680b4f97606b51bb6d1e515c6296659796618c46901775d890fd77636bd272:8aec,8bfb583577798d4c675c9540809a5ea66e2159927aef77ed953b6bb565ad7f0e58065151961f5bf958a954288e726566987f56e4949d76fe9041638754c659:1a3a,579b8eb267358dfa8235524160f0581586fe5ce89e454fc4989d8bb95a2560765384627c904f9102997f6069800c513f80335c1499756d314e8c7a:1d1f21222425262728292a2b2c2d2e2f303132343536383a3e4041424344454748494a4b4c4d4e4f50525354555658595a5b5c5d5e5f606162636465666768#696a6b6c6d6e6f717273757b7c7d7e828587898a8b8c8e8f909394999a9b9ea1a2,8d3053d17f5a7b4f4f104e4f96006cd573d085e95e06756a7ffb6a0a77fe94927e4151e170e653cd8fd483038d2972af996d6cdb574a82b365b980aa623f963259a84eff8bbf7eba653e83f2975e556198de80a5532a8bfd542080ba5e9f6cb88d3982ac915a54296c1b52067eb7575f711a6c7e7c89594b4efd5fff61247caa4e305c0167ab87025cf0950b98ce75af70fd902251af7f1d8bbd594951e44f5b5426592b657780a45b7562:76c2,8f905e456c1f7b264f:0fd8,670d7a:a3a4a7a9aaabaeafb0b1b2b4b5b6b7b8b9babbbcbdbec0c1c2c3c4c5c6c7c8c9cacccdcecfd0d1d2d3d4d5d7d8dadbdcdde1e2e4e7e8e9eaebeceef0f1f2f3#f4f5f6f7f8fbfcfe,7b:0001020507090c0d0e1012131617181a1c1d1f21222327292d,6d:6eaa,798f88b15f17752b629a8f854fef91dc65a781:2f51,5e9c81508d74526f89868d4b590d50854ed8961c723681798d1f5bcc8ba3964459877f1a549056:760e,8be565396982949976d66e895e72751867:46d1,7aff809d8d76611f79c665628d635188521a94a27f38809b7eb25c976e2f67607bd9768b9ad8818f7f947cd5641e95507a3f54:4ae5,6b4c640162089e3d80f3759952729769845b683c86e496:0194,94ec4e2a54047ed968398ddf801566f45e9a7fb97b:2f303234353637393b3d3f404142434446484a4d4e535557595c5e5f61636465666768696a6b6c6d6f70737476787a7c7d7f81828384868788898a8b8c8e8f#9192939698999a9b9e9fa0a3a4a5aeafb0b2b3b5b6b7b9babbbcbdbebfc0c2c3c4,57c2803f68975de5653b529f606d9f9a4f9b8eac516c5bab5f135de96c5e62f18d21517194a952fe6c9f82df72d757a267848d2d591f8f9c83c754957b8d4f306cbd5b6459d19f1353e486ca9aa88c3780a16545987e56fa96c7522e74dc52505be1630289024e5662d0602a68fa51735b9851a089c27ba199867f5060ef704c8d2f51495e7f901b747089c4572d78455f529f9f95fa8f689b3c8be17678684267dc8d:ea35,523d8f8a6eda68cd950590ed56fd679c88f98fc754c87b:c5c8c9cacbcdcecfd0d2d4d5d6d7d8dbdcdedfe0e2e3e4e7e8e9ebecedeff0f2f3f4f5f6f8f9fafbfdff,7c:0001020304050608090a0d0e101112131415171819#1a1b1c1d1e20212223242528292b2c2d2e2f3031323334353637393a3b3c3d3e42,9ab85b696d776c264ea55bb39a87916361a890af97e9542b6db55bd251fd558a7f:55f0,64bc634d65f161be608d710a6c:5749,592f676d822a58d5568e8c6a6beb90dd597d801753f76d695475559d83:77cf,683879be548c4f55540876d28c8996026cb36db88d6b89109e648d3a563f9ed175d55f8872e0606854fc4ea86a2a886160528f7054c470d886799e3f6d2a5b8f5f187ea255894faf7334543c539a501954:0e7c,4e4e5ffd745a58f6846b80e1877472d07cca6e567c:434445464748494a4b4c4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f70717275767778797a7e7f8081828384858687#888a8b8c8d8e8f90939496999a9ba0a1a3a6a7a8a9abacadafb0b4b5b6b7b8babb,5f27864e552c62a44e926caa623782b154d7534e733e6ed1753b521253168bdd69d05f8a60006dee574f6b2273af68538fd87f13636260a3552475ea8c6271156da35ba65e7b8352614c9ec478fa87577c27768751f060f6714c66435e4c604d8c0e707063258f895fbd606286d456de6bc160946167534960e066668d3f79fd4f1a70e96c478b:b3f2,7ed88364660f5a5a9b426d:51f7,8c416d3b4f19706b83b7621660d1970d8d27797851fb57:3efa,673a75787a3d79ef7b957c:bfc0c2c3c4c6c9cbcecfd0d1d2d3d4d8dadbdddee1e2e3e4e5e6e7e9eaebecedeef0f1f2f3f4f5f6f7f9fafcfdfeff,7d:000102030405060708090b0c0d0e0f10#1112131415161718191a1b1c1d1e1f212324252628292a2c2d2e30313233343536,808c99658ff96fc08ba59e2159ec7ee97f095409678168d88f917c4d96c653ca602575be6c7253735ac97ea7632451e0810a5df184df628051805b634f0e796d524260b86d4e5b:c4c2,8b:a1b0,65e25fcc964559937e:e7aa,560967b759394f735bb652a0835a988a8d3e753294be50477a3c4ef767b69a7e5ac16b7c76d1575a5c167b3a95f4714e517c80a9827059787f04832768c067ec78:b177,62e363617b804fed526a51cf835069db92748d:f531,89c1952e7bad4ef67d:3738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6f70717273747576#78797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798,506582305251996f6e:1085,6da75efa50f559dc5c066d466c5f7586848b686859568bb253209171964d854969127901712680f64ea490ca6d479a845a0756bc640594f077eb4fa5811a72e189d2997a7f347ede527f655991758f:7f83,53eb7a9663:eda5,768679f888579636622a52ab8282685467706377776b7aed6d017ed389e359d0621285c982a5754c501f4ecb75a58beb5c4a5dfe7b4b65a491d14eca6d25895f7d2795264ec58c288fdb9773664b79818fd170ec6d787d:999a9b9c9d9e9fa0a1a2a3a4a5a7a8a9aaabacadafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9#dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fa,5c3d52b283465162830e775b66769cb84eac60ca7c:beb3,7ecf4e958b66666f988897595883656c955c5f8475c997567a:dfde,51c070af7a9863ea7a767ea0739697ed4e4570784e5d915253a965:51e7,81fc8205548e5c31759a97a062d872d975bd5c459a7983ca5c40548077e94e3e6cae805a62d2636e5de851778ddd8e1e952f4ff153e560e770ac526763509e435a1f5026773753777ee26485652b628963985014723589c951b38bc07edd574783cc94a7519b541b5cfb7d:fbfcfdfeff,7e:000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f30313233343536373839#3a3c3d3e3f40424344454648494a4b4c4d4e4f505152535455565758595a5b5c5d,4fca7ae36d5a90e19a8f55805496536154af5f0063e9697751ef6168520a582a52d8574e780d770b5eb761777ce062:5b97,4ea27095800362f770e49760577782db67ef68f578d5989779d158f354b353ef6e34514b523b5ba28bfe80af554357a660735751542d7a7a60505b5463a762a053e362635bc767af54ed7a9f82e691775e9388e4593857ae630e8de880ef57577b774fa95feb5bbd6b3e53217b5072c2684677:ff36,65f751b54e8f76d45cbf7aa58475594e9b4150807e:5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f8081838485868788898a8b8c8d8e8f909192939495969798999a9c9d9e#aeb4bbbcd6e4ecf9,7f:0a101e37393b3c3d3e3f404143464748494a4b4c4d4e4f5253,998861276e8357646606634656f062:ec69,5ed39614578362c955878721814a8fa3556683b167658d5684dd5a6a680f62e67bee961151706f9c8c3063fd89c861d27f0670c26ee57405699472fc5eca90ce67176d6a635e52b3726280014f6c59e5916a70d96d9d52d24e5096f7956d857e78ca7d2f5121579264c2808b7c7b6cea68f1695e51b7539868a872819ece7bf172f879bb6f137406674e91cc9ca4793c83:8954,540f68174e3d538952b1783e5386522950884f:8bd0,7f:56595b5c5d5e6063646566676b6c6d6f7073757677787a7b7c7d7f8082838485868788898b8d8f9091929395969798999b9ca0a2a3a5a6a8a9aaabacadaeb1#b3b4b5b6b7babbbec0c2c3c4c6c7c8c9cbcdcfd0d1d2d3d6d7d9dadbdcdddee2e3,75e27acb7c926ca596b6529b748354e94fe9805483b28fde95705ec9601c6d9f5e18655b813894fe604b70bc7ec37cae51c968817cb1826f4e248f8691cf667e4eae8c0564a9804a50da759771ce5be58fbd6f664e86648295635ed66599521788c270c852a3730e7433679778f797164e3490bb9cde6dcb51db8d41541d62ce73b283f196f69f8494c34f367f9a51cc707596755cad988653e64ee46e9c740969b4786b998f7559521876246d4167f3516d9f99804b54997b3c7abf7f:e4e7e8eaebecedeff2f4f5f6f7f8f9fafdfeff,80:020708090a0e0f11131a1b1d1e1f2123242b2c2d2e2f303234393a3c3e404144454748494e4f505153555657#595b5c5d5e5f6061626364656667686b6c6d6e6f7072737475767778797a7b7c7d,9686578462e29647697c5a0464027bd36f0f964b82a6536298855e90708963b35364864f9c819e93788c97328d:ef42,9e7f6f5e79845f559646622e9a74541594dd4fa365c55c:6561,7f1586516c2f5f8b73876ee47eff5ce6631b5b6a6ee653754e7163a0756562a18f6e4f264ed16ca67eb68bba841d87ba7f57903b95237ba99aa188f8843d6d1b9a867edc59889ebb739b780186829a:6c82,561b541757cb4e709ea653568fc881097792999286ee6ee1851366fc61626f2b80:7e818285888a8d8e8f909192949597999ea3a6a7a8acb0b3b5b6b8b9bbc5c7c8c9cacbcfd0d1d2d3d4d5d8dfe0e2e3e6eef5f7f9fbfeff,81:000103040507080b#0c1517191b1c1d1f202122232425262728292a2b2d2e3033343537393a3b3c3d3f,8c298292832b76f26c135fd983bd732b8305951a6bdb77db94c6536f830251925e3d8c8c8d384e4873ab679a68859176970971646ca177095a9295416bcf7f8e66275bd059b95a9a95:e8f7,4eec84:0c99,6aac76df9530731b68a65b5f772f919a97617cdc8ff78c1c5f257c7379d889c56ccc871c5bc65e4268c977207ef551:954d,52c95a297f05976282d763cf778485d079d26e3a5e9959998511706d6c1162bf76bf654f60af95fd660e879f9e2394ed54:0d7d,8c2c647881:40414243444547494d4e4f525657585b5c5d5e5f6162636466686a6b6c6f727375767778818384858687898b8c8d8e90929394959697999a9e9fa0a1a2a4a5#a7a9abacadaeafb0b1b2b4b5b6b7b8b9bcbdbebfc4c5c7c8c9cbcdcecfd0d1d2d3,647986116a21819c78e864699b5462b9672b83ab58a89ed86cab6f205bde964c8c0b725f67d062c772614ea959c66bcd589366ae5e5552df6155672876ee776672677a4662ff54:ea50,94a090a35a1c7eb36c164e435976801059485357753796be56ca63208111607c95f96dd65462998151855ae980fd59ae9713502a6ce55c3c62df4f60533f817b90066eba852b62c85e7478be64b5637b5ff55a18917f9e1f5c3f634f80425b7d556e95:4a4d,6d8560a867e072de51dd5b8181:d4d5d6d7d8d9dadbdcdddedfe0e1e2e4e5e6e8e9ebeeeff0f1f2f5f6f7f8f9fafdff,82:030708090a0b0e0f111315161718191a1d2024252627292e323a3c3d3f#404142434546484a4c4d4e5051525354555657595b5c5d5e606162636465666769,62e76cde725b626d94ae7ebd81136d53519c5f04597452aa6012597366968650759f632a61e67cef8bfa54e66b279e256bb485d5545550766ca4556a8db4722c5e156015743662cd6392724c5f986e436d3e65006f5876d878d076fc7554522453db4e535e9e65c180:2ad6,629b5486522870ae888d8dd16ce1547880da57f988f48d54966a914d4f696c9b55b776c6783062a870f96f8e5f6d84ec68da787c7bf781a8670b9e4f636778b0576f7812973962:79ab,528874356bd782:6a6b6c6d71757677787b7c808183858687898c90939495969a9b9ea0a2a3a7b2b5b6babbbcbfc0c2c3c5c6c9d0d6d9dadde2e7e8e9eaecedeef0f2f3f5f6f8#fafcfdfeff,83:000a0b0d1012131618191d1e1f20212223242526292a2e3032373b3d,5564813e75b276ae533975de50fb5c418b6c7bc7504f72479a9798d86f0274e27968648777a562fc98918d2b54c180584e52576a82f9840d5e7351ed74f68bc45c4f57616cfc98875a4678349b448feb7c955256625194fa4ec68386846183e984b257d467345703666e6d668c3166dd7011671f6b3a6816621a59bb4e0351c46f0667d26c8f517668cb59476b6775665d0e81109f5065d779:4841,9a918d775c824e5e4f01542f5951780c56686c148fc45f036c:7de3,8bab639083:3e3f41424445484a4b4c4d4e5355565758595d6270717273747576797a7e7f808182838487888a8b8c8d8f909194959697999a9d9fa1a2a3a4a5a6a7acadae#afb5bbbebfc2c3c4c6c8c9cbcdced0d1d2d3d5d7d9dadbdee2e3e4e6e7e8ebeced,60706d3d7275626694:8ec5,53438fc17b7e4edf8c264e7e9ed494:b1b3,524d6f5c90636d458c3458115d4c6b:2049,67aa545b81547f8c589985375f3a62a26a47953965726084686577a74e544fa85de7979864ac7fd85ced4fcf7a8d520783044e14602f7a8394a64fb54eb279e6743452e482b964d279bd5bdd6c8197528f7b6c22503e537f6e0564ce66746c3060c598778bf75e86743c7a7779cb4e1890b174036c4256da914b6cc58d8b533a86c666f28eaf5c489a716e2083:eeeff3f4f5f6f7fafbfcfeff,84:0002050708090a10121314151617191a1b1e1f20212223292a2b2c2d2e2f30323334353637393a3b3e3f404142434445474849#4a4b4c4d4e4f505253545556585d5e5f606264656667686a6e6f70727477797b7c,53d65a369f8b8da353bb570898a76743919b6cc9516875ca62f372ac52:389d,7f3a7094763853749e4a69b7786e96c088d97fa471:36c3,518967d374e458e4651856b78ba9997662707ed560f970ed58ec4e:c1ba,5fcd97e74efb8ba45203598a7eab62544ecd65e5620e833884c98363878d71946eb65bb97ed2519763c967d480898339881551125b7a59828fb14e736c5d516589258f6f962e854a745e95:10f0,6da682e55f3164926d128428816e9cc3585e8d5b4e0953c184:7d7e7f8081838485868a8d8f90919293949596989a9b9d9e9fa0a2a3a4a5a6a7a8a9aaabacadaeb0b1b3b5b6b7bbbcbec0c2c3c5c6c7c8cbcccecfd2d4d5d7#d8d9dadbdcdee1e2e4e7e8e9eaebedeeeff1f2f3f4f5f6f7f8f9fafbfdfe,85:000102,4f1e6563685155d34e2764149a9a626b5ac2745f82726da968ee50e7838e7802674052396c997eb150bb5565715e7b5b665273ca82eb67495c715220717d886b95ea965564c58d6181b355846c5562477f2e58924f2455468d4f664c4e0a5c1a88f368a2634e7a0d70e7828d52fa97f65c1154e890b57ecd59628d4a86c782:0c0d,8d6664445c0461516d89793e8bbe78377533547b4f388eab6df15a207ec5795e6c885ba15a76751a80be614e6e1758f075:1f25,727253477ef385:030405060708090a0b0d0e0f101214151618191b1c1d1e2022232425262728292a2d2e2f303132333435363e3f404142444546474b4c4d4e4f505152535455#57585a5b5c5d5f60616263656667696a6b6c6d6e6f707173757677787c7d7f8081,770176db526980dc57235e08593172ee65bd6e7f8bd75c388671534177f362fe65f64ec098df86805b9e8bc653f277e24f7f5c4e9a7659cb5f0f793a58eb4e1667ff4e8b62ed8a93901d52bf662f55dc566c90024ed54f8d91ca99706c0f5e0260435ba489c68bd56536624b99965b:88ff,6388552e53d77626517d852c67a268b36b8a62928f9353d482126dd1758f4e668d4e5b70719f85af66:91d9,7f7287009ecd9f205c5e672f8ff06811675f620d7ad658855eb665706f3185:82838688898a8b8c8d8e909192939495969798999a9d9e9fa0a1a2a3a5a6a7a9abacadb1b2b3b4b5b6b8babbbcbdbebfc0c2c3c4c5c6c7c8cacbcccdced1d2#d4d6d7d8d9dadbdddedfe0e1e2e3e5e6e7e8eaebecedeeeff0f1f2f3f4f5f6f7f8,60555237800d6454887075295e05681362f4971c53cc723d8c016c3477617a0e542e77ac987a821c8bf47855671470c165af64955636601d79c153f84e1d6b7b80865bfa55e356db4f:3a3c,99725df3677e80386002988290015b8b8b:bcf5,641c825864de55fd82cf91654fd77d20901f7c9f50f358516eaf5bbf8bc980839178849c7b97867d96:8b8f,7ee59ad3788e5c817a57904296a7795f5b59635f7b0b84d168ad55067f2974107d2295016240584c4ed65b835979585485:f9fafcfdfe,86:0001020304060708090a0b0c0d0e0f10121314151718191a1b1c1d1e1f20212223242526282a2b2c2d2e2f3031323334353637393a3b3d3e3f40#4142434445464748494a4b4c525355565758595b5c5d5f6061636465666768696a,736d631e8e:4b0f,80ce82d462ac53f06cf0915e592a60016c70574d644a8d2a762b6ee9575b6a8075f06f6d8c:2d08,57666bef889278b363a253f970ad6c645858642a580268e0819b55107cd650188eba6dcc8d9f70eb638f6d9b6ed47ee68404684390036dd896768ba85957727985e4817e75bc8a8a68af52548e22951163d098988e44557c4f5366ff568f60d56d9552435c4959296dfb586b75:301c,606c82148146631167618fe2773a8d:f334,94c15e165385542c70c386:6d6f7072737475767778838485868788898e8f90919294969798999a9b9e9fa0a1a2a5a6abadaeb2b3b7b8b9bbbcbdbebfc1c2c3c5c8cccdd2d3d5d6d7dadc#dde0e1e2e3e5e6e7e8eaebeceff5f6f7fafbfcfdff,87:010405060b0c0e0f10111416,6c405ef7505c4ead5ead633a8247901a6850916e77b3540c94dc5f647ae5687663457b527edf75db507762955934900f51f879c37a8156fe5f9290146d825c60571f541051546e4d56e263a89893817f8715892a9000541e5c6f81c062:d658,81319e3596409a:6e7c,692d59a562d3553e631654c786d96d3c5a0374e6889c6b6a59168c4c5f2f6e7e73a9987d4e3870f75b8c7897633d665a769660cb5b9b5a494e0781556c6a738b4ea167897f515f8065fa671b5fd859845a0187:191b1d1f20242627282a2b2c2d2f303233353638393a3c3d404142434445464a4b4d4f505152545556585a5b5c5d5e5f6162666768696a6b6c6d6f71727375#7778797a7f8081848687898a8c8e8f90919294959698999a9b9c9d9ea0a1a2a3a4,5dcd5fae537197e68fdd684556f4552f60df4e3a6f4d7ef482c7840e59d44f:1f2a,5c3e7eac672a851a5473754f80c355829b4f4f4d6e2d8c135c096170536b761f6e29868a658795fb7eb9543b7a337d0a95ee55e17fc174ee631d87176da17a9d621165a1536763e16c835deb545c94a84e4c6c618bec5c4b65e0829c68a754:3e34,6b:cb66,4e9463425348821e4f:0dae,575e620a96fe6664726952:ffa1,609f8bef661471996790897f785277fd6670563b54389521727a87:a5a6a7a9aaaeb0b1b2b4b6b7b8b9bbbcbebfc1c2c3c4c5c7c8c9cccdcecfd0d4d5d6d7d8d9dadcdddedfe1e2e3e4e6e7e8e9ebecedeff0f1f2f3f4f5f6f7f8#fafbfcfdff,88:0001020405060708090b0c0d0e0f101112141718191a1c1d1e1f2023,7a00606f5e0c6089819d591560dc718470ef6eaa6c5072806a8488ad5e2d4e605ab3559c94e36d177cfb9699620f7ec6778e867e5323971e8f9666875ce14fa072ed4e0b53a6590f54136380952851484ed99c9c7ea454b88d248854823795f26d8e5f265acc663e966973:b02e,53bf817a99857fa15baa96:7750,7ebf76f853a2957699997bb189446e584e617fd479658be660f354cd4eab98795df76a6150cf54118c618427785d9704524a54ee56a395006d885bb56dc6665388:2425262728292a2b2c2d2e2f30313334353637383a3b3d3e3f414243464748494a4b4e4f505152535556585a5b5c5d5e5f6066676a6d6f717374757678797a#7b7c80838687898a8c8e8f90919394959798999a9b9d9e9fa0a1a3a5a6a7a8a9aa,5c0f5b5d6821809655787b11654869544e9b6b47874e978b534f631f643a90aa659c80c18c10519968b0537887f961c86c:c4fb,8c225c5185aa82af950c6b238f9b65b05f:fbc3,4fe18845661f8165732960fa51745211578b5f6290a2884c91925e78674f602759d351:44f6,80f853086c7996c4718a4f:11ee,7f9e673d55c5950879c088967ee3589f620c9700865a5618987b5f908bb884c4915753d965ed5e8f755c60647d6e5a7f7e:eaed,8f6955a75ba360ac65cb738488:acaeafb0b2b3b4b5b6b8b9babbbdbebfc0c3c4c7c8cacbcccdcfd0d1d3d6d7dadbdcdddee0e1e6e7e9eaebecedeeeff2f5f6f7fafbfdff,89:0001030405060708#090b0c0d0e0f1114151617181c1d1e1f20222324262728292c2d2e2f3132333537,9009766377297eda9774859b5b667a7496ea884052cb718f5faa65ec8be25bfb9a6f5de16b896c5b8b:adaf,900a8fc5538b62bc9e:262d,54404e2b82bd7259869c5d1688596daf96c554d14e9a8bb6710954bd960970df6df976d04e25781487125ca95ef68a00989c960e708e6cbf594463a9773c884d6f148273583071d5538c781a96c155015f6671305bb48c1a9a8c6b83592e9e2f79e76768626c4f6f75a17f8a6d0b96336c274ef075d2517b68376f3e908081705996747689:38393a3b3c3d3e3f40424345464748494a4b4c4d4e4f505152535455565758595a5b5c5d6061626364656768696a6b6c6d6e6f707172737475767778797a7c#7d7e808284858788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1,64475c2790657a918c2359da54ac8200836f898180006930564e8036723791ce51b64e5f987563964e1a53f666f3814b591c6db24e0058f9533b63d694f14f:9d0a,886398905937905779fb4eea80f075916c825b9c59e85f5d69058681501a5df24e5977e34ee5827a6291661390915c794ebf5f7981c69038808475ab4ea688d4610f6bc55fc64e4976ca6ea28b:e3ae,8c0a8bd15f027f:fccc,7ece83:356b,56e06bb797f3963459fb541f94f66deb5bc5996e5c395f15969089:a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c3cdd3d4d5d7d8d9dbdddfe0e1e2e4e7e8e9eaecedeef0f1f2f4f5f6f7f8f9fa#fbfcfdfeff,8a:01020304050608090a0b0c0d0e0f101112131415161718191a1b1c1d,537082f16a315a749e705e947f2883b984:2425,836787478fce8d6276c85f719896786c662054df62e54f6381c375c85eb896cd8e0a86f9548f6cf36d8c6c38607f52c775285e7d4f1860a05fe75c24753190ae94c072b96cb96e389149670953:cbf3,4f5191c98bf153c85e7c8fc26de44e8e76c26986865e611a82064f:59de,903e9c7c61096e:1d14,96854e885a3196e84e0e5c7f79b95b878bed7fbd738957df828b90c15401904755bb5cea5fa161086b3272f180b28a:891e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3f4041424344454647494a4b4c4d4e4f505152535455565758595a5b5c5d5e#5f606162636465666768696a6b6c6d6e6f7071727374757677787a7b7c7d7e7f80,6d745bd388d598848c6b9a6d9e336e0a51:a443,57a38881539f63f48f9556ed54585706733f6e907f188fdc82d1613f6028966266f07ea68d:8ac3,94a55cb37ca4670860a6960580184e9190e75300966851418fd08574915d665597f55b55531d78386742683d54c9707e5bb08f7d518d572854b1651266828d:5e43,810f846c906d7cdf51ff85fb67a365e96fa186a48e81566a90207682707671e58d2362e952196cfd8d3c600e589e618e66fe8d60624e55b36e23672d8f678a:81828384858687888b8c8d8e8f9091929495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2#c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3,94e195f87728680569a8548b4e4d70b88bc86458658b5b857a84503a5be877bb6be18a797c986cbe76cf65a98f975d2d5c5586386808536062187ad96e5b7efd6a1f7ae05f706f335f20638c6da867564e085e108d264ed780c07634969c62db662d627e6cbc8d7571677f695146808753ec906e629854f286f08f998005951785178fd96d5973cd659f771f7504782781fb8d1e94884fa6679575b98bca9707632f9547963584b8632377415f8172f04e896014657462ef6b63653f8a:e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff,8b:0001020304050608090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20212223#24252728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445,5e2775c790d18bc1829d679d652f5431871877e580a281026c414e4b7ec7804c76f4690d6b966267503c4f84574063076b628dbe53ea65e87eb85fd763:1ab7,81:f3f4,7f6e5e1c5cd95236667a79e97a1a8d28709975d46ede6cbb7a924e2d76c55fe0949f88777ec879cd80bf91cd4ef24f17821f54685dde6d328bcc7ca58f7480985e1a549276b15b99663c9aa473e0682a86db6731732a8b:f8db,90107af970db716e62c477a956314e3b845767f152a986c08d2e94f87b518b:464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f6061626364656768696a6b6d6e6f707172737475767778797a7b7c7d7e7f80818283848586#8788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9facb1bbc7d0ea,8c:091e,4f4f6ce8795d9a7b6293722a62fd4e1378168f6c64b08d5a7bc668695e8488c55986649e58ee72b6690e95258ffd8d5857607f008c0651c6634962d95353684c74228301914c55447740707c6d4a517954a88d4459ff6ecb6dc45b5c7d2b4ed47c7d6ed35b5081ea6e0d5b579b0368d58e2a5b977efc603b7eb590b98d70594f63cd79df8db3535265cf79568bc5963b7ec494bb7e825634918967007f6a5c0a907566285de64f5067de505a4f5c57505e:a7#3$,8c:38393a3b3c3d3e3f4042434445484a4b4d4e4f5051525354565758595b5c5d5e5f60636465666768696c6d6e6f707172747576777b7c7d7e7f808183848687#888b8d8e8f90919293959697999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacad,4e:8d0c,51404e105eff53454e:15981e,9b325b6c56694e2879ba4e3f53154e47592d723b536e6c1056df80e499976bd3777e9f174e:369f,9f104e:5c6993,82885b5b556c560f4ec453:8d9da3a5ae,97658d5d53:1af5262e3e,8d5c53:6663,52:02080e2d333f404c5e615c,84af52:7d82819093,51827f544e:bbc3c9c2e8e1ebde,4f1b4ef34f:2264,4ef54f:2527092b5e67,65384f:5a5d,8c:aeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebec#edeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff,8d:000102030405060708090a0b0c0d,4f:5f57323d76749189838f7e7baa7cac94e6e8eac5dae3dcd1dff8,50:294c,4ff350:2c0f2e2d,4ffe50:1c0c25287e4355484e6c7ba5a7a9bad6,510650:edece6ee,51:070b,4edd6c3d4f:5865ce,9fa06c467c74516e5dfd9ec999985181591452f9530d8a07531051eb591951554ea051564eb388:6ea4,4eb5811488d279805b3488037fb851:abb1bdbc,8d:0e0f101112131415161718191a1b1c205152575f6568696a6c6e6f717278797a7b7c7d7e7f808283868788898c8d8e8f90929395969798999a9b9c9d9ea0a1#a2a4a5a6a7a8a9aaabacadaeafb0b2b6b7b9bbbdc0c1c2c5c7c8c9cacdd0d2d3d4,51:c796a2a5,8b:a0a6a7aab4b5b7c2c3cbcfced2d3d4d6d8d9dcdfe0e4e8e9eef0f3f6f9fcff,8c:000204070c0f1112141516191b181d1f202125272a2b2e2f32333536,53:697a,96:1d2221312a3d3c4249545f676c7274888d97b0,90:979b9d99aca1b4b3b6ba,8d:d5d8d9dce0e1e2e5e6e7e9edeef0f1f2f4f6fcfeff,8e:00010203040607080b0d0e1011121315161718191a1b1c202124252627282b2d303233343637383b3c3e#3f4345464c4d4e4f505354555657585a5b5c5d5e5f60616263646567686a6b6e71,90:b8b0cfc5bed0c4c7d3e6e2dcd7dbebeffe,91:04221e23312f394346,520d594252:a2acadbe,54ff52:d0d6f0,53df71ee77cd5ef451:f5fc,9b2f53b65f01755a5def57:4ca9a1,58:7ebcc5d1,57:292c2a33392e2f5c3b4269856b867c7b686d7673ada48cb2cfa7b493a0d5d8dad9d2b8f4eff8e4dd,8e:73757778797a7b7d7e808283848688898a8b8c8d8e91929395969798999a9b9d9fa0a1a2a3a4a5a6a7a8a9aaadaeb0b1b3b4b5b6b7b8b9bbbcbdbebfc0c1c2#c3c4c5c6c7c8c9cacbcccdcfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4,58:0b0d,57:fded,58:001e194420656c81899a80,99a89f1961ff82:797d7f8f8aa8848e919799abb8beb0c8cae398b7aecbccc1a9b4a1aa9fc4cea4e1,830982:f7e4,83:0f07,82:dcf4d2d8,830c82:fbd3,83:111a061415,82:e0d5,83:1c515b5c08923c34319b5e2f4f47435f4017602d3a336665,8e:e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff,8f:000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20212223#2425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f4041424344,83:681b696c6a6d6eb078b3b4a0aa939c857cb6a97db87b989ea8babcc1,840183:e5d8,580784:180b,83:ddfdd6,84:1c381106,83:d4df,84:0f03,83:f8f9eac5c0,842683:f0e1,84:5c515a597387887a89783c4669768c8e316dc1cdd0e6bdd3cabfbae0a1b9b497e5e3,850c750d853884f085:391f3a,8f:45464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f6061626364656a808c929da0a1a2a4a5a6a7aaacadaeafb2b3b4b5b7b8babbbcbfc0c3c6#c9cacbcccdcfd2d6d7dae0e1e3e7eceff1f2f4f5f6fafbfcfeff,90:07080c0e131518,85:563b,84:fffc,85:594868645e7a,77a285:43727ba4a8878f79ae9c85b9b7b0d3c1dcff,86:270529163c,5efe5f0859:3c41,803759:555a58,530f5c:22252c34,62:4c6a9fbbcadad7ee,632262f663:394b43adf6717a8eb46dac8a69aebcf2f8e0ffc4dece,645263:c6be,64:45410b1b200c26215e846d96,90:191c2324252728292a2b2c303132333437393a3d3f4043454648494a4b4c4e545556595a5c5d5e5f6061646667696a6b6c6f70717273767778797a7b7c7e81#84858687898a8c8d8e8f90929496989a9c9e9fa0a4a5a7a8a9abadb2b7bcbdbfc0,64:7ab7b899bac0d0d7e4e2,65:09252e,5f:0bd2,75195f1153:5ff1fde9e8fb,54:1216064b5253545643215759233282947771649a9b8476669dd0adc2b4d2a7a6d3d472a3d5bbbfccd9dadca9aaa4ddcfde,551b54e7552054fd551454f355:22230f11272a678fb5496d41553f503c,90:c2c3c6c8c9cbcccdd2d4d5d6d8d9dadedfe0e3e4e5e9eaeceef0f1f2f3f5f6f7f9fafbfcff,91:00010305060708090a0b0c0d0e0f1011121314151617181a1b1c#1d1f20212425262728292a2b2c2d2e30323334353637383a3b3c3d3e3f40414244,55:375675767733305c8bd283b1b988819f7ed6917bdfbdbe9499eaf7c9,561f55:d1ebecd4e6ddc4efe5f2f3cccde8f5e4,8f9456:1e080c012423,55fe56:00272d5839572c4d62595c4c548664716b7b7c8593afd4d7dde1f5ebf9ff,57:040a091c,5e:0f191411313b3c,91:454748515354555658595b5c5f606667686b6d737a7b7c808182838486888a8e8f939495969798999c9d9e9fa0a1a4a5a6a7a8a9abacb0b1b2b3b6b7b8b9bb#bcbdbebfc0c1c2c3c4c5c6c8cbd0d2d3d4d5d6d7d8d9dadbdddedfe0e1e2e3e4e5,5e:3744545b5e61,5c:8c7a8d9096889899919a9cb5a2bdacabb1a3c1b7c4d2e4cbe5,5d:020327262e241e061b583e343d6c5b6f5d6b4b4a697482999d,8c735d:b7c5,5f:73778287898c95999ca8adb5bc,88625f6172:adb0b4b7b8c3c1cecdd2e8efe9f2f4f7,730172f3730372fa91:e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff,92:000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2021222324#25262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445,72fb73:1713210a1e1d152239252c3831504d57606c6f7e,821b592598e759:2402,99:636768696a6b6c74777d8084878a8d9091939495,5e:80918b96a5a0b9b5beb3,8d535e:d2d1dbe8ea,81ba5f:c4c9d6cf,60035fee60045f:e1e4fe,60:0506,5f:eaedf8,60:1935261b0f0d292b0a3f2178797b7a42,92:464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f7071727375767778797a7b7c7d7e7f808182838485#868788898a8b8c8d8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7,60:6a7d969aad9d83928c9becbbb1ddd8c6dab4,61:20261523,60f461:000e2b4a75ac94a7b7d4f5,5fdd96b395:e9ebf1f3f5f6fcfe,96:030406080a0b0c0d0f12151617191a,4e2c723f62156c:35545c4aa38590948c6869747686a9d0d4adf7f8f1d7b2e0d6faebeeb1d3effe,92:a8a9aaabacadafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8#e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff,93:00010203040506070809,6d:39270c43480704190e2b4d2e351a4f525433916f9ea05e93945c607c63,6e1a6d:c7c5de,6e0e6d:bfe0,6e116d:e6ddd9,6e166dab6e0c6dae6e:2b6e4e6bb25f865354322544dfb198e0,6f2d6e:e2a5a7bdbbb7d7b4cf8fc29f,6f:6246472415,6ef96f:2f364b742a0929898d8c78727c7ad1,93:0a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3f40414243444546474849#4a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696b,6f:c9a7b9b6c2e1eedee0ef,70:1a231b39354f5e,5b:80849593a5b8,752f9a9e64345b:e4ee,89305bf08e478b078f:b6d3d5e5eee4e9e6f3e8,90:05040b26110d162135362d2f445152506858625b,66b990:747d8288838b,5f:50575658,5c3b54ab5c:5059,5b715c:6366,7fbc5f:2a292d,82745f3c9b3b5c6e59:81838da9aaa3,93:6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaab#acadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cbcccd,59:97caab9ea4d2b2afd7be,5a:0506,59dd5a0859:e3d8f9,5a:0c09323411231340674a553c6275,80ec5a:aa9b777abeebb2d2d4b8e0e3f1d6e6d8dc,5b:091716323740,5c:151c,5b:5a6573515362,9a:7577787a7f7d808185888a90929396989b9c9d9fa0a2a3a5a7,7e:9fa1a3a5a8a9,93:cecfd0d1d2d3d4d5d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff,94:000102030405060708090a0b0c0d#0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e,7e:adb0bec0c1c2c9cbccd0d4d7dbe0e1e8ebeeeff1f2,7f0d7e:f6fafbfe,7f:01020307080b0c0f111217191c1b1f212223242526272a2b2c2d2f3031323335,5e7a757f5ddb753e909573:8e91aea29fcfc2d1b7b3c0c9c8e5d9,987c740a73:e9e7debaf2,74:0f2a5b262528302e2c,94:2f303132333435363738393a3b3c3d3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6c6d6e6f#707172737475767778797a7b7c7d7e7f8081828384919698c7cfd3d4dae6fb,95:1c20,74:1b1a415c575559776d7e9c8e8081878b9ea8a990a7d2ba,97:eaebec,67:4c535e4869a5876a7398a775a89ead8b777cf0,680967d8680a67:e9b0,680c67:d9b5dab3dd,680067:c3b8e2,680e67:c1fd,68:323360614e624464831d55664167403e4a4929b58f7477936bc2,696e68fc69:1f20,68f995:27333d43484b555a606e74757778797a7b7c7d7e808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aa#abacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacb,692468f069:0b0157,68e369:10713960425d846b80987834cc8788ce896663799ba7bbabadd4b1c1cadf95e08dff,6a2f69ed6a:171865,69f26a:443ea0505b358e793d28587c9190a997ab,73:3752,6b:8182878492938d9a9ba1aa,8f:6b6d71727375767877797a7c7e818284878b,95:cccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7ecff,96:0713181b1e20232425262728292b2c2d2f303738393a3e41434a4e4f5152535657#58595a5c5d5e606365666b6d6e6f70717378797a7b7c7d7e7f808182838487898a,8f:8d8e8f989a,8ece62:0b171b1f222125242c,81e774:eff4ff,75:0f1113,65:34eeeff0,66:0a19,677266:031500,708566:f71d34313635,800666:5f54414f56615777848ca79dbedbdce6e9,8d:3233363b3d4045464849474d5559,89:c7cacbcccecfd0d1,72:6e9f5d666f7e7f848b8d8f92,63:0832b0,96:8c8e91929395969a9b9d9e9fa0a1a2a3a4a5a6a8a9aaabacadaeafb1b2b4b5b7b8babbbfc2c3c8cacbd0d1d3d4d6d7d8d9dadbdcdddedfe1e2e3e4e5e6e7eb#ecedeef0f1f2f4f5f8fafbfcfdff,97:0203050a0b0c10111214151718191a1b1d1f20,64:3fd8,80046b:eaf3fdf5f9,6c:0507060d1518191a2129242a32,65:35556b,72:4d525630,8662521680:9f9c93bc,670a80:bdb1abadb4b7e7e8e9eadbc2c4d9cdd7,671080:ddebf1f4ed,81:0d0e,80:f2fc,671581128c5a81:361e2c1832484c5374595a7160697c7d6d67,584d5ab581:888291,6ed581:a3aacc,672681:cabb,97:2122232425262728292b2c2e2f3133343536373a3b3c3d3f404142434445464748494a4b4c4d4e4f5051545557585a5c5d5f63646667686a6b6c6d6e6f7071#72757778797a7b7d7e7f8081828384868788898a8c8e8f9093959697999a9b9c9d,81:c1a6,6b:243739434659,98:d1d2d3d5d9da,6bb35f406bc289f365909f5165:93bcc6c4c3ccced2d6,70:809c969dbbc0b7abb1e8ca,71:1013162f31735c6845724a787a98b3b5a8a0e0d4e7f9,72:1d28,706c71:1866b9,62:3e3d434849,79:3b4046495b5c535a6257606f677a858a9aa7b3,5f:d1d0,97:9e9fa1a2a4a5a6a7a8a9aaacaeb0b1b3b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3#e4e5e8eeeff0f1f2f4f7f8f9fafbfcfdfeff,98:000102030405060708090a0b0c0d0e,60:3c5d5a67415963ab,61:060d5da99dcbd1,620680:807f,6c:93f6,6dfc77:f6f8,78:0009171811,65ab78:2d1c1d393a3b1f3c252c23294e6d56572650474c6a9b939a879ca1a3b2b9a5d4d9c9ecf2,790578f479:13241e34,9f9b9e:f9fbfc,76f177:040d,76f977:07081a22192d263538505147435a68,98:0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d#4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e,77:62657f8d7d808c919fa0b0b5bd,75:3a404e4b485b727983,7f:58615f,8a487f:68747179817e,76:cde5,883294:8586878b8a8c8d8f909497959a9b9ca3a4abaaadacafb0b2b4b6b7b8b9babcbdbfc4c8c9cacbcccdced0d1d2d5d6d7d9d8dbdedfe0e2e4e5e7e8ea,98:6f70717273748b8e929599a3a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcfd0d4d6d7dbdcdde0e1e2e3e4#e5e6e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff,99:0001020304050607,94:e9ebeeeff3f4f5f7f9fcfdff,95:03020607090a0d0e0f1213141516181b1d1e1f222a2b292c3132343637383c3e3f4235444546494c4e4f525354565758595b5e5f5d61626465666768696a6b6c6f7172733a,77:e7ec,96c979:d5ede3eb,7a065d477a:03021e14,99:08090a0b0c0e0f1112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2f303132333435363738393a3b3c3d3e3f40414243444546474849#4a4b4c4d4e4f50515253565758595a5b5c5d5e5f60616264667378797b7e828389,7a:393751,9ecf99a57a7076:888e9399a4,74:dee0,752c9e:202228292a2b2c3231363837393a3e414244464748494b4c4e5155575a5b5c5e63666768696a6b6c716d73,75:929496a09daca3b3b4b8c4b1b0c3c2d6cde3e8e6e4ebe7,760375:f1fcff,76:1000050c170a25181519,99:8c8e9a9b9c9d9e9fa0a1a2a3a4a6a7a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8#d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9,76:1b3c2220402d303f35433e334d5e545c566b6f,7fca7a:e6787980868895a6a0aca8adb3,88:6469727d7f82a2c6b7bcc9e2cee3e5f1,891a88:fce8fef0,89:2119131b0a342b3641667b,758b80e576:b2b4,77dc80:1214161c20222526272928310b3543464d526971,898398:788083,99:fafbfcfdfeff,9a:000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738#393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f50515253545556575859,98:898c8d8f949a9b9e9fa1a2a5a6,86:4d546c6e7f7a7c7ba88d8bac9da7a3aa93a9b6c4b5ceb0bab1afc9cfb4e9f1f2edf3d0,871386:def4dfd8d1,87:0307,86f887:080a0d09233b1e252e1a3e48343129373f82227d7e7b60704c6e8b53637c64596593afa8d2,9a:5a5b5c5d5e5f606162636465666768696a6b7283898d8e949599a6a9aaabacadaeafb2b3b4b5b9bbbdbebfc3c4c6c7c8c9cacdcecfd0d2d4d5d6d7d9dadbdc#dddee0e2e3e4e5e7e8e9eaeceef0f1f2f3f4f5f6f7f8fafcfdfeff,9b:000102040506,87:c68885ad9783abe5acb5b3cbd3bdd1c0cadbeae0ee,88:1613,87fe88:0a1b21393c,7f:36424445,82107a:fafd,7b:080304150a2b0f47382a192e31202524333e1e585a45754c5d606e7b62727190a6a7b8ac9da885aa9ca2abb4d1c1ccdddae5e6ea,7c0c7b:fefc,7c:0f160b,9b:07090a0b0c0d0e1011121415161718191a1b1c1d1e2021222425262728292a2b2c2d2e3031333435363738393a3d3e3f40464a4b4c4e50525355565758595a#5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b,7c:1f2a26384140,81fe82:010204,81ec884482:2122232d2f282b383b33343e44494b4f5a5f68,88:7e8588d8df,895e7f:9d9fa7afb0b2,7c7c65497c:919d9c9ea2b2bcbdc1c7cccdc8c5d7e8,826e66a87f:bfced5e5e1e6e9eef3,7cf87d:77a6ae,7e:479b,9e:b8b4,8d:73849491b1676d,8c:4749,91:4a504e4f64,9b:7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9ba#bbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadb,91:626170696f7d7e7274798c85908d91a2a3aaadaeafb5b4ba,8c559e7e8d:b8eb,8e:055969,8d:b5bfbcbac4d6d7dadececfdbc6ecf7f8e3f9fbe4,8e098dfd8e:141d1f2c2e232f3a4039353d3149414251524a70767c6f74858f94909c9e,8c:78828a859894,659b89:d6dedadc,9b:dcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff,9c:000102030405060708090a0b0c0d0e0f101112131415161718191a#1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b,89:e5ebef,8a3e8b26975396:e9f3ef,97:0601080f0e2a2d303e,9f:808385868788898a8c,9efe9f:0b0d,96:b9bcbdced2,77bf96e092:8eaec8,93:3e6aca8f,94:3e6b,9c:7f8285868788,7a239c:8b8e90919294959a9b9e9fa0a1a2a3a5a6a7a8a9abadaeb0b1b2b3b4b5b6b7babbbcbdc4c5c6c7cacb3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a#7b7d7e808384898a8c8f93969798999daaacafb9bebfc0c1c2c8c9d1d2dadbe0e1cccdcecfd0d3d4d5d7d8d9dcdddfe2,97:7c85919294afaba3b2b4,9a:b1b0b7,9e589a:b6babcc1c0c5c2cbccd1,9b:45434749484d51,98e899:0d2e5554,9a:dfe1e6efebfbedf9,9b:080f131f23,9e:bdbe,7e3b9e:8287888b92,93d69e:9d9fdbdcdde0dfe2e9e7e5eaef,9f:222c2f39373d3e44,9c:e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff,9d:000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2021#22232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142#92$434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f8081#82838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2#92$a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1#e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff,9e:000102#92$030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e24272e30343b3c404d5052535456595d5f606162656e6f727475767778797a7b7c7d80#8183848586898a8c8d8e8f90919495969798999a9b9c9ea0a1a2a3a4a5a7a8a9aa#92$abacadaeafb0b1b2b3b5b6b7b9babcbfc0c1c2c3c5c6c7c8cacbccd0d2d3d5d6d7d9dadee1e3e4e6e8ebecedeef0f1f2f3f4f5f6f7f8fafdff,9f:000102030405#060708090a0c0f1112141516181a1b1c1d1e1f21232425262728292a2b2d2e3031#92$3233343536383a3c3f4041424345464748494a4b4c4d4e4f52535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778#797a7b7c7d7e81828d8e8f9091929394959697989c9d9ea1a2a3a4a5,f9:2c7995e7f1#92$,fa:0c0d0e0f111314181f20212324272829,e8:15161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f40414243#4445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f6061626364");
  135. let index = 0;
  136. this.#data = dataText.match(/..../g);
  137. for (let i = 0x81; i <= 0xfe; i++) {
  138. for (let j = 0x40; j <= 0xfe; j++) {
  139. this.#U2Ghash[this.#data[index++]] = ("%" +
  140. i.toString(16) +
  141. "%" +
  142. j.toString(16)).toUpperCase();
  143. }
  144. }
  145. for (let key in this.#U2Ghash) {
  146. this.#G2Uhash[this.#U2Ghash[key]] = key;
  147. }
  148. }
  149. handleText(text) {
  150. text = text
  151. .replace(/#(\d+)\$/g, function (a, b) {
  152. return Array(+b + 3).join("#");
  153. })
  154. .replace(/#/g, "####")
  155. .replace(/(\w\w):([\w#]+)(?:,|$)/g, function (a, hd, dt) {
  156. return dt.replace(/../g, function (a) {
  157. if (a != "##") {
  158. return hd + a;
  159. }
  160. else {
  161. return a;
  162. }
  163. });
  164. });
  165. return text;
  166. }
  167. isAscii(unicode) {
  168. return unicode <= 0x007f && unicode >= 0x0000;
  169. }
  170. /**
  171. * 编码
  172. * @param str
  173. */
  174. encode(str) {
  175. let that = this;
  176. return [...str].reduce((result, val, i) => {
  177. return result + toGBK(val);
  178. }, "");
  179. function toGBK(val) {
  180. let result = "";
  181. for (let i = 0; i < val.length; i++) {
  182. const codePoint = val.codePointAt(i);
  183. const code = String.fromCodePoint(codePoint);
  184. let key = codePoint.toString(16);
  185. key.length != 4 && (key = ("000" + key).match(/....$/)?.[0]);
  186. /* Add up i by code.length */
  187. i += code.length - 1;
  188. /* If code is in ascii range */
  189. if (that.isAscii(codePoint)) {
  190. result += encodeURIComponent(code);
  191. continue;
  192. }
  193. /* If Got encoded string from U2Ghash */
  194. if (that.#U2Ghash[key]) {
  195. result += that.#U2Ghash[key];
  196. continue;
  197. }
  198. /*
  199. If 2 or more char combines to one visible code,
  200. or just this code is not in GBK
  201. */
  202. result += toGBK(`&#${codePoint};`);
  203. }
  204. return result;
  205. }
  206. }
  207. /**
  208. * 解码
  209. * @param str
  210. */
  211. decode(str) {
  212. var GBKMatcher = /%[0-9A-F]{2}%[0-9A-F]{2}/;
  213. var UTFMatcher = /%[0-9A-F]{2}/;
  214. // @ts-ignore
  215. var utf = true;
  216. let that = this;
  217. while (utf) {
  218. let gbkMatch = str.match(GBKMatcher);
  219. let utfMatch = str.match(UTFMatcher);
  220. utf = Boolean(utfMatch);
  221. if (gbkMatch && gbkMatch in that.#G2Uhash) {
  222. str = str.replace(gbkMatch, String.fromCharCode(("0x" + that.#G2Uhash[gbkMatch])));
  223. }
  224. else {
  225. // @ts-ignore
  226. str = str.replace(utfMatch, decodeURIComponent(utfMatch));
  227. }
  228. }
  229. return str;
  230. }
  231. }
  232.  
  233. const UtilsCoreDefaultEnv = {
  234. document: document,
  235. window: window,
  236. globalThis: globalThis,
  237. self: self,
  238. top: top,
  239. };
  240. const UtilsCoreEnv = {
  241. document: document,
  242. window: window,
  243. globalThis: globalThis,
  244. self: self,
  245. top: top,
  246. };
  247. const UtilsCore = {
  248. init(option) {
  249. if (!option) {
  250. option = Object.assign({}, UtilsCoreDefaultEnv);
  251. }
  252. Object.assign(UtilsCoreEnv, option);
  253. },
  254. get document() {
  255. return UtilsCoreEnv.document;
  256. },
  257. get window() {
  258. return UtilsCoreEnv.window;
  259. },
  260. get globalThis() {
  261. return UtilsCoreEnv.globalThis;
  262. },
  263. get self() {
  264. return UtilsCoreEnv.self;
  265. },
  266. get top() {
  267. return UtilsCoreEnv.top;
  268. },
  269. };
  270.  
  271. class UtilsGMCookie {
  272. /**
  273. * 获取单个cookie
  274. * @param cookieName cookie名
  275. */
  276. get(cookieName) {
  277. if (typeof cookieName !== "string") {
  278. throw new TypeError("Utils.GMCookie.get 参数cookieName 必须为字符串");
  279. }
  280. let cookies = UtilsCore.document.cookie.split(";");
  281. let findValue = void 0;
  282. for (const cookieItem of cookies) {
  283. let item = cookieItem.trim();
  284. let itemSplit = item.split("=");
  285. let itemName = itemSplit[0];
  286. itemSplit.splice(0, 1);
  287. let itemValue = decodeURIComponent(itemSplit.join(""));
  288. if (itemName === cookieName) {
  289. findValue = {
  290. domain: UtilsCore.globalThis.location.hostname,
  291. expirationDate: null,
  292. hostOnly: true,
  293. httpOnly: false,
  294. name: cookieName,
  295. path: "/",
  296. sameSite: "unspecified",
  297. secure: true,
  298. session: false,
  299. value: itemValue,
  300. };
  301. break;
  302. }
  303. }
  304. return findValue;
  305. }
  306. /**
  307. * 获取多组Cookie
  308. * @param paramDetails 配置
  309. * @param callback 获取操作后的回调
  310. * + cookies object[]
  311. * + error string|undefined
  312. **/
  313. list(paramDetails, callback) {
  314. if (paramDetails == null) {
  315. throw new Error("Utils.GMCookie.list 参数不能为空");
  316. }
  317. let resultData = [];
  318. try {
  319. let details = {
  320. url: UtilsCore.globalThis.location.href,
  321. domain: UtilsCore.globalThis.location.hostname,
  322. name: "",
  323. path: "/",
  324. };
  325. details = utils.assign(details, paramDetails);
  326. let cookies = UtilsCore.document.cookie.split(";");
  327. cookies.forEach((item) => {
  328. item = item.trim();
  329. let itemSplit = item.split("=");
  330. let itemName = itemSplit[0];
  331. itemSplit.splice(0, 1);
  332. let itemValue = decodeURIComponent(itemSplit.join(""));
  333. let nameRegexp = details.name instanceof RegExp
  334. ? details.name
  335. : new RegExp("^" + details.name, "g");
  336. if (itemName.match(nameRegexp)) {
  337. resultData.push({
  338. domain: UtilsCore.globalThis.location.hostname,
  339. expirationDate: null,
  340. hostOnly: true,
  341. httpOnly: false,
  342. name: itemName,
  343. path: "/",
  344. sameSite: "unspecified",
  345. secure: true,
  346. session: false,
  347. value: itemValue,
  348. });
  349. }
  350. });
  351. if (typeof callback === "function") {
  352. callback(resultData);
  353. }
  354. }
  355. catch (error) {
  356. if (typeof callback === "function") {
  357. callback(resultData, error);
  358. }
  359. }
  360. }
  361. /**
  362. * 获取多组Cookie
  363. * @param paramDetails 配置
  364. **/
  365. getList(paramDetails) {
  366. if (paramDetails == null) {
  367. throw new Error("Utils.GMCookie.list 参数不能为空");
  368. }
  369. let resultData = [];
  370. let details = {
  371. url: UtilsCore.globalThis.location.href,
  372. domain: UtilsCore.globalThis.location.hostname,
  373. name: "",
  374. path: "/",
  375. };
  376. details = utils.assign(details, paramDetails);
  377. let cookies = UtilsCore.document.cookie.split(";");
  378. cookies.forEach((item) => {
  379. item = item.trim();
  380. let itemSplit = item.split("=");
  381. let itemName = itemSplit[0];
  382. itemSplit.splice(0, 1);
  383. let itemValue = decodeURIComponent(itemSplit.join(""));
  384. let nameRegexp = details.name instanceof RegExp
  385. ? details.name
  386. : new RegExp("^" + details.name, "g");
  387. if (itemName.match(nameRegexp)) {
  388. resultData.push({
  389. domain: UtilsCore.globalThis.location.hostname,
  390. expirationDate: null,
  391. hostOnly: true,
  392. httpOnly: false,
  393. name: itemName,
  394. path: "/",
  395. sameSite: "unspecified",
  396. secure: true,
  397. session: false,
  398. value: itemValue,
  399. });
  400. }
  401. });
  402. return resultData;
  403. }
  404. /**
  405. * 设置Cookie
  406. * @param paramDetails 配置
  407. * @param callback 设置操作后的回调(成功/失败)
  408. */
  409. set(paramDetails, callback = (error) => { }) {
  410. try {
  411. let details = {
  412. url: UtilsCore.window.location.href,
  413. name: "",
  414. value: "",
  415. domain: UtilsCore.window.location.hostname,
  416. path: "/",
  417. secure: true,
  418. httpOnly: false,
  419. /**
  420. * Expires in 30 days
  421. */
  422. expirationDate: Math.floor(Date.now()) + 60 * 60 * 24 * 30,
  423. };
  424. details = utils.assign(details, paramDetails);
  425. let life = details.expirationDate
  426. ? details.expirationDate
  427. : Math.floor(Date.now()) + 60 * 60 * 24 * 30;
  428. let cookieStr = details.name +
  429. "=" +
  430. decodeURIComponent(details.value) +
  431. ";expires=" +
  432. new Date(life).toGMTString() +
  433. "; path=/";
  434. UtilsCore.document.cookie = cookieStr;
  435. callback();
  436. }
  437. catch (error) {
  438. callback(error);
  439. }
  440. }
  441. /**
  442. * 删除Cookie
  443. * @param paramDetails 配置
  444. * @param callback 删除操作后的回调(成功/失败)
  445. */
  446. delete(paramDetails, callback = (error) => { }) {
  447. try {
  448. let details = {
  449. url: UtilsCore.window.location.href,
  450. name: "",
  451. // @ts-ignore
  452. firstPartyDomain: "",
  453. };
  454. details = utils.assign(details, paramDetails);
  455. let cookieStr = details.name + "=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;";
  456. UtilsCore.document.cookie = cookieStr;
  457. callback();
  458. }
  459. catch (error) {
  460. callback(error);
  461. }
  462. }
  463. }
  464.  
  465. // @name ajaxHooker
  466. // @author cxxjackie
  467. // @version 1.4.3
  468. // @updateLog 修复特殊情况下有部分请求头丢失的问题。
  469. // @updateLog xhr事件增加currentTarget劫持。
  470. // @supportURL https://bbs.tampermonkey.net.cn/thread-3284-1-1.html
  471.  
  472. const AjaxHooker = function () {
  473. return (function () {
  474. const version = "1.4.3";
  475. const hookInst = {
  476. hookFns: [],
  477. filters: [],
  478. };
  479. const win = window.unsafeWindow || document.defaultView || window;
  480. let winAh = win.__ajaxHooker;
  481. const resProto = win.Response.prototype;
  482. const xhrResponses = ["response", "responseText", "responseXML"];
  483. const fetchResponses = ["arrayBuffer", "blob", "formData", "json", "text"];
  484. const fetchInitProps = [
  485. "method",
  486. "headers",
  487. "body",
  488. "mode",
  489. "credentials",
  490. "cache",
  491. "redirect",
  492. "referrer",
  493. "referrerPolicy",
  494. "integrity",
  495. "keepalive",
  496. "signal",
  497. "priority",
  498. ];
  499. const xhrAsyncEvents = ["readystatechange", "load", "loadend"];
  500. const getType = {}.toString.call.bind({}.toString);
  501. const getDescriptor = Object.getOwnPropertyDescriptor.bind(Object);
  502. const emptyFn = () => {};
  503. const errorFn = (e) => console.error(e);
  504. function isThenable(obj) {
  505. return (
  506. obj &&
  507. ["object", "function"].includes(typeof obj) &&
  508. typeof obj.then === "function"
  509. );
  510. }
  511. function catchError(fn, ...args) {
  512. try {
  513. const result = fn(...args);
  514. if (isThenable(result)) return result.then(null, errorFn);
  515. return result;
  516. } catch (err) {
  517. console.error(err);
  518. }
  519. }
  520. function defineProp(obj, prop, getter, setter) {
  521. Object.defineProperty(obj, prop, {
  522. configurable: true,
  523. enumerable: true,
  524. get: getter,
  525. set: setter,
  526. });
  527. }
  528. function readonly(obj, prop, value = obj[prop]) {
  529. defineProp(obj, prop, () => value, emptyFn);
  530. }
  531. function writable(obj, prop, value = obj[prop]) {
  532. Object.defineProperty(obj, prop, {
  533. configurable: true,
  534. enumerable: true,
  535. writable: true,
  536. value: value,
  537. });
  538. }
  539. function parseHeaders(obj) {
  540. const headers = {};
  541. switch (getType(obj)) {
  542. case "[object String]":
  543. for (const line of obj.trim().split(/[\r\n]+/)) {
  544. const [header, value] = line.split(/\s*:\s*/);
  545. if (!header) break;
  546. const lheader = header.toLowerCase();
  547. headers[lheader] =
  548. lheader in headers ? `${headers[lheader]}, ${value}` : value;
  549. }
  550. break;
  551. case "[object Headers]":
  552. for (const [key, val] of obj) {
  553. headers[key] = val;
  554. }
  555. break;
  556. case "[object Object]":
  557. return { ...obj };
  558. }
  559. return headers;
  560. }
  561. function stopImmediatePropagation() {
  562. this.ajaxHooker_isStopped = true;
  563. }
  564. class SyncThenable {
  565. then(fn) {
  566. fn && fn();
  567. return new SyncThenable();
  568. }
  569. }
  570. class AHRequest {
  571. constructor(request) {
  572. this.request = request;
  573. this.requestClone = { ...this.request };
  574. }
  575. shouldFilter(filters) {
  576. const { type, url, method, async } = this.request;
  577. return (
  578. filters.length &&
  579. !filters.find((obj) => {
  580. switch (true) {
  581. case obj.type && obj.type !== type:
  582. case getType(obj.url) === "[object String]" &&
  583. !url.includes(obj.url):
  584. case getType(obj.url) === "[object RegExp]" && !obj.url.test(url):
  585. case obj.method &&
  586. obj.method.toUpperCase() !== method.toUpperCase():
  587. case "async" in obj && obj.async !== async:
  588. return false;
  589. }
  590. return true;
  591. })
  592. );
  593. }
  594. waitForRequestKeys() {
  595. const requestKeys = ["url", "method", "abort", "headers", "data"];
  596. if (!this.request.async) {
  597. win.__ajaxHooker.hookInsts.forEach(({ hookFns, filters }) => {
  598. if (this.shouldFilter(filters)) return;
  599. hookFns.forEach((fn) => {
  600. if (getType(fn) === "[object Function]")
  601. catchError(fn, this.request);
  602. });
  603. requestKeys.forEach((key) => {
  604. if (isThenable(this.request[key]))
  605. this.request[key] = this.requestClone[key];
  606. });
  607. });
  608. return new SyncThenable();
  609. }
  610. const promises = [];
  611. win.__ajaxHooker.hookInsts.forEach(({ hookFns, filters }) => {
  612. if (this.shouldFilter(filters)) return;
  613. promises.push(
  614. Promise.all(hookFns.map((fn) => catchError(fn, this.request))).then(
  615. () =>
  616. Promise.all(
  617. requestKeys.map((key) =>
  618. Promise.resolve(this.request[key]).then(
  619. (val) => (this.request[key] = val),
  620. () => (this.request[key] = this.requestClone[key])
  621. )
  622. )
  623. )
  624. )
  625. );
  626. });
  627. return Promise.all(promises);
  628. }
  629. waitForResponseKeys(response) {
  630. const responseKeys =
  631. this.request.type === "xhr" ? xhrResponses : fetchResponses;
  632. if (!this.request.async) {
  633. if (getType(this.request.response) === "[object Function]") {
  634. catchError(this.request.response, response);
  635. responseKeys.forEach((key) => {
  636. if (
  637. "get" in getDescriptor(response, key) ||
  638. isThenable(response[key])
  639. ) {
  640. delete response[key];
  641. }
  642. });
  643. }
  644. return new SyncThenable();
  645. }
  646. return Promise.resolve(
  647. catchError(this.request.response, response)
  648. ).then(() =>
  649. Promise.all(
  650. responseKeys.map((key) => {
  651. const descriptor = getDescriptor(response, key);
  652. if (descriptor && "value" in descriptor) {
  653. return Promise.resolve(descriptor.value).then(
  654. (val) => (response[key] = val),
  655. () => delete response[key]
  656. );
  657. } else {
  658. delete response[key];
  659. }
  660. })
  661. )
  662. );
  663. }
  664. }
  665. const proxyHandler = {
  666. get(target, prop) {
  667. const descriptor = getDescriptor(target, prop);
  668. if (
  669. descriptor &&
  670. !descriptor.configurable &&
  671. !descriptor.writable &&
  672. !descriptor.get
  673. )
  674. return target[prop];
  675. const ah = target.__ajaxHooker;
  676. if (ah && ah.proxyProps) {
  677. if (prop in ah.proxyProps) {
  678. const pDescriptor = ah.proxyProps[prop];
  679. if ("get" in pDescriptor) return pDescriptor.get();
  680. if (typeof pDescriptor.value === "function")
  681. return pDescriptor.value.bind(ah);
  682. return pDescriptor.value;
  683. }
  684. if (typeof target[prop] === "function")
  685. return target[prop].bind(target);
  686. }
  687. return target[prop];
  688. },
  689. set(target, prop, value) {
  690. const descriptor = getDescriptor(target, prop);
  691. if (
  692. descriptor &&
  693. !descriptor.configurable &&
  694. !descriptor.writable &&
  695. !descriptor.set
  696. )
  697. return true;
  698. const ah = target.__ajaxHooker;
  699. if (ah && ah.proxyProps && prop in ah.proxyProps) {
  700. const pDescriptor = ah.proxyProps[prop];
  701. pDescriptor.set
  702. ? pDescriptor.set(value)
  703. : (pDescriptor.value = value);
  704. } else {
  705. target[prop] = value;
  706. }
  707. return true;
  708. },
  709. };
  710. class XhrHooker {
  711. constructor(xhr) {
  712. const ah = this;
  713. Object.assign(ah, {
  714. originalXhr: xhr,
  715. proxyXhr: new Proxy(xhr, proxyHandler),
  716. resThenable: new SyncThenable(),
  717. proxyProps: {},
  718. proxyEvents: {},
  719. });
  720. xhr.addEventListener("readystatechange", (e) => {
  721. if (
  722. ah.proxyXhr.readyState === 4 &&
  723. ah.request &&
  724. typeof ah.request.response === "function"
  725. ) {
  726. const response = {
  727. finalUrl: ah.proxyXhr.responseURL,
  728. status: ah.proxyXhr.status,
  729. responseHeaders: parseHeaders(
  730. ah.proxyXhr.getAllResponseHeaders()
  731. ),
  732. };
  733. const tempValues = {};
  734. for (const key of xhrResponses) {
  735. try {
  736. tempValues[key] = ah.originalXhr[key];
  737. } catch (err) {}
  738. defineProp(
  739. response,
  740. key,
  741. () => {
  742. return (response[key] = tempValues[key]);
  743. },
  744. (val) => {
  745. delete response[key];
  746. response[key] = val;
  747. }
  748. );
  749. }
  750. ah.resThenable = new AHRequest(ah.request)
  751. .waitForResponseKeys(response)
  752. .then(() => {
  753. for (const key of xhrResponses) {
  754. ah.proxyProps[key] = {
  755. get: () => {
  756. if (!(key in response)) response[key] = tempValues[key];
  757. return response[key];
  758. },
  759. };
  760. }
  761. });
  762. }
  763. ah.dispatchEvent(e);
  764. });
  765. xhr.addEventListener("load", (e) => ah.dispatchEvent(e));
  766. xhr.addEventListener("loadend", (e) => ah.dispatchEvent(e));
  767. for (const evt of xhrAsyncEvents) {
  768. const onEvt = "on" + evt;
  769. ah.proxyProps[onEvt] = {
  770. get: () => ah.proxyEvents[onEvt] || null,
  771. set: (val) => ah.addEvent(onEvt, val),
  772. };
  773. }
  774. for (const method of [
  775. "setRequestHeader",
  776. "addEventListener",
  777. "removeEventListener",
  778. "open",
  779. "send",
  780. ]) {
  781. ah.proxyProps[method] = { value: ah[method] };
  782. }
  783. }
  784. toJSON() {} // Converting circular structure to JSON
  785. addEvent(type, event) {
  786. if (type.startsWith("on")) {
  787. this.proxyEvents[type] = typeof event === "function" ? event : null;
  788. } else {
  789. if (typeof event === "object" && event !== null)
  790. event = event.handleEvent;
  791. if (typeof event !== "function") return;
  792. this.proxyEvents[type] = this.proxyEvents[type] || new Set();
  793. this.proxyEvents[type].add(event);
  794. }
  795. }
  796. removeEvent(type, event) {
  797. if (type.startsWith("on")) {
  798. this.proxyEvents[type] = null;
  799. } else {
  800. if (typeof event === "object" && event !== null)
  801. event = event.handleEvent;
  802. this.proxyEvents[type] && this.proxyEvents[type].delete(event);
  803. }
  804. }
  805. dispatchEvent(e) {
  806. e.stopImmediatePropagation = stopImmediatePropagation;
  807. defineProp(e, "target", () => this.proxyXhr);
  808. defineProp(e, "currentTarget", () => this.proxyXhr);
  809. this.proxyEvents[e.type] &&
  810. this.proxyEvents[e.type].forEach((fn) => {
  811. this.resThenable.then(
  812. () => !e.ajaxHooker_isStopped && fn.call(this.proxyXhr, e)
  813. );
  814. });
  815. if (e.ajaxHooker_isStopped) return;
  816. const onEvent = this.proxyEvents["on" + e.type];
  817. onEvent && this.resThenable.then(onEvent.bind(this.proxyXhr, e));
  818. }
  819. setRequestHeader(header, value) {
  820. this.originalXhr.setRequestHeader(header, value);
  821. if (!this.request) return;
  822. const headers = this.request.headers;
  823. headers[header] =
  824. header in headers ? `${headers[header]}, ${value}` : value;
  825. }
  826. addEventListener(...args) {
  827. if (xhrAsyncEvents.includes(args[0])) {
  828. this.addEvent(args[0], args[1]);
  829. } else {
  830. this.originalXhr.addEventListener(...args);
  831. }
  832. }
  833. removeEventListener(...args) {
  834. if (xhrAsyncEvents.includes(args[0])) {
  835. this.removeEvent(args[0], args[1]);
  836. } else {
  837. this.originalXhr.removeEventListener(...args);
  838. }
  839. }
  840. open(method, url, async = true, ...args) {
  841. this.request = {
  842. type: "xhr",
  843. url: url.toString(),
  844. method: method.toUpperCase(),
  845. abort: false,
  846. headers: {},
  847. data: null,
  848. response: null,
  849. async: !!async,
  850. };
  851. this.openArgs = args;
  852. this.resThenable = new SyncThenable();
  853. [
  854. "responseURL",
  855. "readyState",
  856. "status",
  857. "statusText",
  858. ...xhrResponses,
  859. ].forEach((key) => {
  860. delete this.proxyProps[key];
  861. });
  862. return this.originalXhr.open(method, url, async, ...args);
  863. }
  864. send(data) {
  865. const ah = this;
  866. const xhr = ah.originalXhr;
  867. const request = ah.request;
  868. if (!request) return xhr.send(data);
  869. request.data = data;
  870. new AHRequest(request).waitForRequestKeys().then(() => {
  871. if (request.abort) {
  872. if (typeof request.response === "function") {
  873. Object.assign(ah.proxyProps, {
  874. responseURL: { value: request.url },
  875. readyState: { value: 4 },
  876. status: { value: 200 },
  877. statusText: { value: "OK" },
  878. });
  879. xhrAsyncEvents.forEach((evt) =>
  880. xhr.dispatchEvent(new Event(evt))
  881. );
  882. }
  883. } else {
  884. xhr.open(
  885. request.method,
  886. request.url,
  887. request.async,
  888. ...ah.openArgs
  889. );
  890. for (const header in request.headers) {
  891. xhr.setRequestHeader(header, request.headers[header]);
  892. }
  893. xhr.send(request.data);
  894. }
  895. });
  896. }
  897. }
  898. function fakeXHR() {
  899. const xhr = new winAh.realXHR();
  900. if ("__ajaxHooker" in xhr)
  901. console.warn("检测到不同版本的ajaxHooker,可能发生冲突!");
  902. xhr.__ajaxHooker = new XhrHooker(xhr);
  903. return xhr.__ajaxHooker.proxyXhr;
  904. }
  905. fakeXHR.prototype = win.XMLHttpRequest.prototype;
  906. Object.keys(win.XMLHttpRequest).forEach(
  907. (key) => (fakeXHR[key] = win.XMLHttpRequest[key])
  908. );
  909. function fakeFetch(url, options = {}) {
  910. if (!url) return winAh.realFetch.call(win, url, options);
  911. return new Promise(async (resolve, reject) => {
  912. const init = {};
  913. if (getType(url) === "[object Request]") {
  914. for (const prop of fetchInitProps) init[prop] = url[prop];
  915. if (url.body) init.body = await url.arrayBuffer();
  916. url = url.url;
  917. }
  918. url = url.toString();
  919. Object.assign(init, options);
  920. init.method = init.method || "GET";
  921. init.headers = init.headers || {};
  922. const request = {
  923. type: "fetch",
  924. url: url,
  925. method: init.method.toUpperCase(),
  926. abort: false,
  927. headers: parseHeaders(init.headers),
  928. data: init.body,
  929. response: null,
  930. async: true,
  931. };
  932. const req = new AHRequest(request);
  933. await req.waitForRequestKeys();
  934. if (request.abort) {
  935. if (typeof request.response === "function") {
  936. const response = {
  937. finalUrl: request.url,
  938. status: 200,
  939. responseHeaders: {},
  940. };
  941. await req.waitForResponseKeys(response);
  942. const key = fetchResponses.find((k) => k in response);
  943. let val = response[key];
  944. if (key === "json" && typeof val === "object") {
  945. val = catchError(JSON.stringify.bind(JSON), val);
  946. }
  947. const res = new Response(val, {
  948. status: 200,
  949. statusText: "OK",
  950. });
  951. defineProp(res, "type", () => "basic");
  952. defineProp(res, "url", () => request.url);
  953. resolve(res);
  954. } else {
  955. reject(new DOMException("aborted", "AbortError"));
  956. }
  957. return;
  958. }
  959. init.method = request.method;
  960. init.headers = request.headers;
  961. init.body = request.data;
  962. winAh.realFetch.call(win, request.url, init).then((res) => {
  963. if (typeof request.response === "function") {
  964. const response = {
  965. finalUrl: res.url,
  966. status: res.status,
  967. responseHeaders: parseHeaders(res.headers),
  968. };
  969. fetchResponses.forEach(
  970. (key) =>
  971. (res[key] = function () {
  972. if (key in response) return Promise.resolve(response[key]);
  973. return resProto[key].call(this).then((val) => {
  974. response[key] = val;
  975. return req
  976. .waitForResponseKeys(response)
  977. .then(() => (key in response ? response[key] : val));
  978. });
  979. })
  980. );
  981. }
  982. resolve(res);
  983. }, reject);
  984. });
  985. }
  986. function fakeFetchClone() {
  987. const descriptors = Object.getOwnPropertyDescriptors(this);
  988. const res = winAh.realFetchClone.call(this);
  989. Object.defineProperties(res, descriptors);
  990. return res;
  991. }
  992. winAh = win.__ajaxHooker = winAh || {
  993. version,
  994. fakeXHR,
  995. fakeFetch,
  996. fakeFetchClone,
  997. realXHR: win.XMLHttpRequest,
  998. realFetch: win.fetch,
  999. realFetchClone: resProto.clone,
  1000. hookInsts: new Set(),
  1001. };
  1002. if (winAh.version !== version)
  1003. console.warn("检测到不同版本的ajaxHooker,可能发生冲突!");
  1004. win.XMLHttpRequest = winAh.fakeXHR;
  1005. win.fetch = winAh.fakeFetch;
  1006. resProto.clone = winAh.fakeFetchClone;
  1007. winAh.hookInsts.add(hookInst);
  1008. return {
  1009. hook: (fn) => hookInst.hookFns.push(fn),
  1010. filter: (arr) => {
  1011. if (Array.isArray(arr)) hookInst.filters = arr;
  1012. },
  1013. protect: () => {
  1014. readonly(win, "XMLHttpRequest", winAh.fakeXHR);
  1015. readonly(win, "fetch", winAh.fakeFetch);
  1016. readonly(resProto, "clone", winAh.fakeFetchClone);
  1017. },
  1018. unhook: () => {
  1019. winAh.hookInsts.delete(hookInst);
  1020. if (!winAh.hookInsts.size) {
  1021. writable(win, "XMLHttpRequest", winAh.realXHR);
  1022. writable(win, "fetch", winAh.realFetch);
  1023. writable(resProto, "clone", winAh.realFetchClone);
  1024. delete win.__ajaxHooker;
  1025. }
  1026. },
  1027. };
  1028. })();
  1029. };
  1030.  
  1031. class GMMenu {
  1032. GM_Api = {
  1033. /**
  1034. * 获取存储的数据
  1035. */
  1036. getValue: null,
  1037. /**
  1038. * 设置数据到存储
  1039. */
  1040. setValue: null,
  1041. /**
  1042. * 注册(不可用)菜单
  1043. */
  1044. registerMenuCommand: null,
  1045. /**
  1046. * 卸载菜单
  1047. */
  1048. unregisterMenuCommand: null,
  1049. };
  1050. MenuHandle = {
  1051. context: this,
  1052. $data: {
  1053. /**
  1054. * 菜单数据
  1055. */
  1056. data: [],
  1057. /**
  1058. * 本地存储的键名
  1059. */
  1060. key: "GM_Menu_Local_Map",
  1061. },
  1062. $default: {
  1063. /** 自动刷新网页,默认为true */
  1064. autoReload: true,
  1065. /**
  1066. * 菜单isStoreValue的默认值
  1067. */
  1068. isStoreValue: true,
  1069. },
  1070. $emoji: {
  1071. /**
  1072. * 菜单enable为true的emoji
  1073. */
  1074. success: "✅",
  1075. /**
  1076. * 菜单enable为false的emoji
  1077. */
  1078. error: "❌",
  1079. },
  1080. /**
  1081. * 初始化数据
  1082. */
  1083. init() {
  1084. for (let index = 0; index < this.$data.data.length; index++) {
  1085. let menuOption = this.$data.data[index]["data"];
  1086. menuOption.enable = Boolean(this.getLocalMenuData(menuOption.key, menuOption.enable));
  1087. if (typeof menuOption.showText !== "function") {
  1088. menuOption.showText = (menuText, menuEnable) => {
  1089. if (menuEnable) {
  1090. return this.$emoji.success + " " + menuText;
  1091. }
  1092. else {
  1093. return this.$emoji.error + " " + menuText;
  1094. }
  1095. };
  1096. }
  1097. }
  1098. },
  1099. /**
  1100. * 注册(不可用)油猴菜单
  1101. * @param menuOptions 如果存在,使用它
  1102. */
  1103. register(menuOptions) {
  1104. let that = this;
  1105. if (menuOptions == null) {
  1106. throw new TypeError("register菜单数据不能为空");
  1107. }
  1108. if (!Array.isArray(menuOptions)) {
  1109. menuOptions = [menuOptions];
  1110. }
  1111. for (let index = 0; index < menuOptions.length; index++) {
  1112. let cloneMenuOptionData = utils.deepClone(menuOptions[index].data);
  1113. const { showText, clickCallBack } = this.handleMenuData(cloneMenuOptionData);
  1114. let menuId = that.context.GM_Api.registerMenuCommand(showText, clickCallBack);
  1115. menuOptions[index].id = menuId;
  1116. cloneMenuOptionData.deleteMenu = function () {
  1117. that.context.GM_Api.unregisterMenuCommand(menuId);
  1118. };
  1119. Reflect.deleteProperty(menuOptions[index], "handleData");
  1120. menuOptions[index].handleData = cloneMenuOptionData;
  1121. }
  1122. },
  1123. /**
  1124. * 获取本地存储菜单键值
  1125. * @param {string} key 键
  1126. */
  1127. getLocalMenuData(key, defaultValue) {
  1128. let localData = this.context.GM_Api.getValue(this.$data.key, {});
  1129. if (key in localData) {
  1130. return localData[key];
  1131. }
  1132. else {
  1133. return defaultValue;
  1134. }
  1135. },
  1136. /**
  1137. * 设置本地存储菜单键值
  1138. * @param key 键
  1139. * @param value 值
  1140. */
  1141. setLocalMenuData(key, value) {
  1142. let localData = this.context.GM_Api.getValue(this.$data.key, {});
  1143. localData[key] = value;
  1144. this.context.GM_Api.setValue(this.$data.key, localData);
  1145. },
  1146. /**
  1147. * 处理初始化配置
  1148. * @param menuOption
  1149. */
  1150. handleInitDetail(menuOption) {
  1151. menuOption.enable = Boolean(this.getLocalMenuData(menuOption.key, menuOption.enable));
  1152. if (typeof menuOption.showText !== "function") {
  1153. menuOption.showText = (menuText, menuEnable) => {
  1154. if (menuEnable) {
  1155. return this.$emoji.success + " " + menuText;
  1156. }
  1157. else {
  1158. return this.$emoji.error + " " + menuText;
  1159. }
  1160. };
  1161. }
  1162. return menuOption;
  1163. },
  1164. /**
  1165. * 对菜单数据进行处理
  1166. * @param menuOption
  1167. */
  1168. handleMenuData(menuOption) {
  1169. let that = this;
  1170. let menuLocalDataItemKey = menuOption.key;
  1171. /* 菜单默认开启的状态 */
  1172. let defaultEnable = Boolean(this.getLocalMenuData(menuLocalDataItemKey, menuOption.enable));
  1173. /** 油猴菜单上显示的文本 */
  1174. let showText = menuOption.showText(menuOption.text, defaultEnable);
  1175. // @ts-ignore
  1176. ({
  1177. /**
  1178. * 菜单的id
  1179. */
  1180. id: menuOption.id,
  1181. /**
  1182. * 点击菜单项后是否应关闭弹出菜单
  1183. */
  1184. autoClose: menuOption.autoClose,
  1185. /**
  1186. * 菜单项的可选访问键
  1187. */
  1188. accessKey: menuOption.accessKey,
  1189. /**
  1190. * 菜单项的鼠标悬浮上的工具提示
  1191. */
  1192. title: menuOption.title,
  1193. });
  1194. /* 点击菜单后触发callback后的网页是否刷新 */
  1195. menuOption.autoReload =
  1196. typeof menuOption.autoReload !== "boolean"
  1197. ? this.$default.autoReload
  1198. : menuOption.autoReload;
  1199. /* 点击菜单后触发callback后的网页是否存储值 */
  1200. menuOption.isStoreValue =
  1201. typeof menuOption.isStoreValue !== "boolean"
  1202. ? this.$default.isStoreValue
  1203. : menuOption.isStoreValue;
  1204. /**
  1205. * 用户点击菜单后的回调函数
  1206. * @param event
  1207. */
  1208. function clickCallBack(event) {
  1209. let localEnable = Boolean(that.getLocalMenuData(menuLocalDataItemKey, defaultEnable));
  1210. if (menuOption.isStoreValue) {
  1211. that.setLocalMenuData(menuLocalDataItemKey, !localEnable);
  1212. }
  1213. if (typeof menuOption.callback === "function") {
  1214. menuOption.callback({
  1215. key: menuLocalDataItemKey,
  1216. enable: !localEnable,
  1217. oldEnable: localEnable,
  1218. event: event,
  1219. storeValue(value) {
  1220. that.setLocalMenuData(menuLocalDataItemKey, value);
  1221. },
  1222. });
  1223. }
  1224. /* 不刷新网页就刷新菜单 */
  1225. if (menuOption.autoReload) {
  1226. UtilsCore.window.location.reload();
  1227. }
  1228. else {
  1229. that.context.update();
  1230. }
  1231. }
  1232. return {
  1233. showText,
  1234. clickCallBack,
  1235. };
  1236. },
  1237. /**
  1238. * 获取目标菜单配置数据
  1239. * @param menuKey 菜单-键key
  1240. */
  1241. getMenuData(menuKey) {
  1242. return this.$data.data.find((item) => item.data.key === menuKey);
  1243. },
  1244. /**
  1245. * 获取目标菜单配置
  1246. * @param menuKey 菜单-键key
  1247. */
  1248. getMenuOption(menuKey) {
  1249. return this.$data.data.find((item) => item.data.key === menuKey)?.data;
  1250. },
  1251. /**
  1252. * 获取目标菜单处理后的配置
  1253. * @param menuKey 菜单-键key
  1254. */
  1255. getMenuHandledOption(menuKey) {
  1256. return this.$data.data.find((item) => item.handleData.key === menuKey)
  1257. ?.handleData;
  1258. },
  1259. };
  1260. constructor(details) {
  1261. this.GM_Api.getValue = details.GM_getValue;
  1262. this.GM_Api.setValue = details.GM_setValue;
  1263. this.GM_Api.registerMenuCommand = details.GM_registerMenuCommand;
  1264. this.GM_Api.unregisterMenuCommand = details.GM_unregisterMenuCommand;
  1265. this.MenuHandle.$default.autoReload =
  1266. typeof details.autoReload === "boolean" ? details.autoReload : true;
  1267. for (const keyName of Object.keys(this.GM_Api)) {
  1268. if (typeof this.GM_Api[keyName] !== "function") {
  1269. throw new Error(`Utils.GM_Menu 请在脚本开头加上 @grant ${keyName},且传入该对象`);
  1270. }
  1271. }
  1272. this.add(details?.data || []);
  1273. }
  1274. /**
  1275. * 新增菜单数据
  1276. * @param paramData
  1277. */
  1278. add(paramData) {
  1279. if (Array.isArray(paramData)) {
  1280. for (const _paramData of paramData) {
  1281. // @ts-ignore
  1282. this.MenuHandle.$data.data.push({
  1283. data: _paramData,
  1284. id: void 0,
  1285. });
  1286. }
  1287. }
  1288. else {
  1289. // @ts-ignore
  1290. this.MenuHandle.$data.data.push({
  1291. data: paramData,
  1292. id: void 0,
  1293. });
  1294. }
  1295. this.update();
  1296. }
  1297. /**
  1298. * 更新菜单数据
  1299. * @param options 数据
  1300. */
  1301. update(options) {
  1302. let optionsList = [];
  1303. if (Array.isArray(options)) {
  1304. optionsList = [...optionsList, ...options];
  1305. }
  1306. else if (options != null) {
  1307. optionsList = [...optionsList, options];
  1308. }
  1309. optionsList.forEach((item) => {
  1310. let targetMenu = this.MenuHandle.getMenuOption(item.key);
  1311. if (targetMenu) {
  1312. Object.assign(targetMenu, item);
  1313. }
  1314. });
  1315. this.MenuHandle.$data.data.forEach((value) => {
  1316. if (value.handleData) {
  1317. value.handleData.deleteMenu();
  1318. }
  1319. });
  1320. this.MenuHandle.init();
  1321. this.MenuHandle.register(this.MenuHandle.$data.data);
  1322. }
  1323. /**
  1324. * 卸载菜单
  1325. * @param menuId 已注册(不可用)的菜单id
  1326. */
  1327. delete(menuId) {
  1328. this.GM_Api.unregisterMenuCommand(menuId);
  1329. }
  1330. /**
  1331. * 根据键值获取enable值
  1332. * @param menuKey 菜单-键key
  1333. */
  1334. get(menuKey) {
  1335. return this.getEnable(menuKey);
  1336. }
  1337. /**
  1338. * 根据键值获取enable值
  1339. * @param menuKey 菜单-键key
  1340. */
  1341. getEnable(menuKey) {
  1342. return this.MenuHandle.getMenuHandledOption(menuKey).enable;
  1343. }
  1344. /**
  1345. * 根据键值获取text值
  1346. * @param menuKey 菜单-键key
  1347. */
  1348. getText(menuKey) {
  1349. return this.MenuHandle.getMenuHandledOption(menuKey).text;
  1350. }
  1351. /**
  1352. * 根据键值获取showText函数的值
  1353. * @param menuKey 菜单-键key
  1354. */
  1355. getShowTextValue(menuKey) {
  1356. return this.MenuHandle.getMenuHandledOption(menuKey).showText(this.getText(menuKey), this.get(menuKey));
  1357. }
  1358. /**
  1359. * 获取当前已注册(不可用)菜单的id
  1360. * @param menuKey
  1361. */
  1362. getMenuId(menuKey) {
  1363. let result = null;
  1364. for (let index = 0; index < this.MenuHandle.$data.data.length; index++) {
  1365. const optionData = this.MenuHandle.$data.data[index];
  1366. if (optionData.handleData.key === menuKey) {
  1367. result = optionData.id;
  1368. break;
  1369. }
  1370. }
  1371. return result;
  1372. }
  1373. /**
  1374. * 根据键值获取accessKey值
  1375. * @param menuKey 菜单-键key
  1376. */
  1377. getAccessKey(menuKey) {
  1378. return this.MenuHandle.getMenuHandledOption(menuKey)?.accessKey;
  1379. }
  1380. /**
  1381. * 根据键值获取autoClose值
  1382. * @param menuKey 菜单-键key
  1383. */
  1384. getAutoClose(menuKey) {
  1385. return this.MenuHandle.getMenuHandledOption(menuKey)?.autoClose;
  1386. }
  1387. /**
  1388. * 根据键值获取autoReload值
  1389. * @param menuKey 菜单-键key
  1390. */
  1391. getAutoReload(menuKey) {
  1392. return this.MenuHandle.getMenuHandledOption(menuKey)?.autoReload;
  1393. }
  1394. /**
  1395. * 根据键值获取callback函数
  1396. * @param menuKey 菜单-键key
  1397. */
  1398. getCallBack(menuKey) {
  1399. return this.MenuHandle.getMenuHandledOption(menuKey)?.callback;
  1400. }
  1401. /**
  1402. * 获取当enable为true时默认显示在菜单中前面的emoji图标
  1403. */
  1404. getEnableTrueEmoji() {
  1405. return this.MenuHandle.$emoji.success;
  1406. }
  1407. /**
  1408. * 获取当enable为false时默认显示在菜单中前面的emoji图标
  1409. */
  1410. getEnableFalseEmoji() {
  1411. return this.MenuHandle.$emoji.error;
  1412. }
  1413. /**
  1414. * 获取本地存储的菜单外部的键名
  1415. * @param keyName
  1416. */
  1417. getLocalStorageKeyName() {
  1418. return this.MenuHandle.$data.key;
  1419. }
  1420. /**
  1421. * 设置菜单的值
  1422. * @param menuKey 菜单-键key
  1423. * @param value 需要设置的值
  1424. */
  1425. setValue(menuKey, value) {
  1426. this.MenuHandle.setLocalMenuData(menuKey, value);
  1427. }
  1428. /**
  1429. * 设置菜单的值
  1430. * @param menuKey 菜单-键key
  1431. * @param value 需要设置的值
  1432. */
  1433. setEnable(menuKey, value) {
  1434. this.setValue(menuKey, Boolean(value));
  1435. }
  1436. /**
  1437. * 设置当enable为true时默认显示在菜单中前面的emoji图标
  1438. * @param emojiString
  1439. */
  1440. setEnableTrueEmoji(emojiString) {
  1441. if (typeof emojiString !== "string") {
  1442. throw new Error("参数emojiString必须是string类型");
  1443. }
  1444. this.MenuHandle.$emoji.success = emojiString;
  1445. }
  1446. /**
  1447. * 设置当enable为false时默认显示在菜单中前面的emoji图标
  1448. * @param emojiString
  1449. */
  1450. setEnableFalseEmoji(emojiString) {
  1451. if (typeof emojiString !== "string") {
  1452. throw new Error("参数emojiString必须是string类型");
  1453. }
  1454. this.MenuHandle.$emoji.error = emojiString;
  1455. }
  1456. /**
  1457. * 设置本地存储的菜单外部的键名
  1458. * @param keyName
  1459. */
  1460. setLocalStorageKeyName(keyName) {
  1461. if (typeof keyName !== "string") {
  1462. throw new Error("参数keyName必须是string类型");
  1463. }
  1464. this.MenuHandle.$data.key = keyName;
  1465. }
  1466. }
  1467.  
  1468. class Hooks {
  1469. /**
  1470. * 在Function原型上添加自定义方法.hook和.unhook
  1471. */
  1472. initEnv() {
  1473. Function.prototype.hook = function (realFunc, hookFunc, context) {
  1474. let _context = null; //函数上下文
  1475. let _funcName = null; //函数名
  1476. _context = context || window;
  1477. _funcName = getFuncName(this);
  1478. _context["realFunc_" + _funcName] = this;
  1479. if (_context[_funcName].prototype &&
  1480. _context[_funcName].prototype.isHooked) {
  1481. console.log("Already has been hooked,unhook first");
  1482. return false;
  1483. }
  1484. function getFuncName(fn) {
  1485. // 获取函数名
  1486. let strFunc = fn.toString();
  1487. let _regex = /function\s+(\w+)\s*\(/;
  1488. let patten = strFunc.match(_regex);
  1489. if (patten) {
  1490. return patten[1];
  1491. }
  1492. return "";
  1493. }
  1494. try {
  1495. eval("_context[_funcName] = function " +
  1496. _funcName +
  1497. "(){\n" +
  1498. "let args = Array.prototype.slice.call(arguments,0);\n" +
  1499. "let obj = this;\n" +
  1500. "hookFunc.apply(obj,args);\n" +
  1501. "return _context['realFunc_" +
  1502. _funcName +
  1503. "'].apply(obj,args);\n" +
  1504. "};");
  1505. _context[_funcName].prototype.isHooked = true;
  1506. return true;
  1507. }
  1508. catch (e) {
  1509. console.log("Hook failed,check the params.");
  1510. return false;
  1511. }
  1512. };
  1513. Function.prototype.unhook = function (realFunc, funcName, context) {
  1514. let _context = null;
  1515. let _funcName = null;
  1516. _context = context || window;
  1517. _funcName = funcName;
  1518. if (!_context[_funcName].prototype.isHooked) {
  1519. console.log("No function is hooked on");
  1520. return false;
  1521. }
  1522. _context[_funcName] = _context["realFunc" + _funcName];
  1523. Reflect.deleteProperty(_context, "realFunc_" + _funcName);
  1524. return true;
  1525. };
  1526. }
  1527. /**
  1528. * 删除在Function原型上添加的自定义方法.hook和.unhook
  1529. */
  1530. cleanEnv() {
  1531. if (Function.prototype.hasOwnProperty("hook")) {
  1532. Reflect.deleteProperty(Function.prototype, "hook");
  1533. }
  1534. if (Function.prototype.hasOwnProperty("unhook")) {
  1535. Reflect.deleteProperty(Function.prototype, "unhook");
  1536. }
  1537. return true;
  1538. }
  1539. }
  1540.  
  1541. /**
  1542. * 生成uuid
  1543. */
  1544. const GenerateUUID = function () {
  1545. if (typeof UtilsCore.globalThis?.crypto?.randomUUID === "function") {
  1546. return UtilsCore.globalThis.crypto.randomUUID();
  1547. }
  1548. else {
  1549. return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (charStr) {
  1550. var randomValue = (Math.random() * 16) | 0, randomCharValue = charStr === "x" ? randomValue : (randomValue & 0x3) | 0x8;
  1551. return randomCharValue.toString(16);
  1552. });
  1553. }
  1554. };
  1555.  
  1556. class Httpx {
  1557. GM_Api = {
  1558. xmlHttpRequest: null,
  1559. };
  1560. HttpxRequestHook = {
  1561. /**
  1562. * @private
  1563. */
  1564. $config: {
  1565. configList: [],
  1566. },
  1567. /**
  1568. * 发送请求前的回调
  1569. * 如果返回false则阻止本次返回
  1570. * @param details 当前的请求配置
  1571. * @private
  1572. */
  1573. beforeRequestCallBack(details) {
  1574. if (typeof details.allowInterceptConfig === "boolean") {
  1575. if (!details.allowInterceptConfig) {
  1576. // 不允许拦截
  1577. return details;
  1578. }
  1579. }
  1580. else {
  1581. if (details.allowInterceptConfig != null) {
  1582. // 配置存在
  1583. // 细分处理是否拦截
  1584. if (typeof details.allowInterceptConfig.beforeRequest === "boolean" &&
  1585. !details.allowInterceptConfig.beforeRequest) {
  1586. // 设置了禁止拦截
  1587. return details;
  1588. }
  1589. }
  1590. }
  1591. for (let index = 0; index < this.$config.configList.length; index++) {
  1592. let item = this.$config.configList[index];
  1593. if (typeof item.fn === "function") {
  1594. let result = item.fn(details);
  1595. if (result == null) {
  1596. return;
  1597. }
  1598. }
  1599. }
  1600. return details;
  1601. },
  1602. /**
  1603. * 添加请求前的回调处理配置
  1604. */
  1605. add(fn) {
  1606. if (typeof fn === "function") {
  1607. let uuid = GenerateUUID();
  1608. this.$config.configList.push({
  1609. id: uuid,
  1610. fn: fn,
  1611. });
  1612. return uuid;
  1613. }
  1614. else {
  1615. console.warn("HttpxRequestHook.addBeforeRequestCallBack: fn is not a function");
  1616. }
  1617. },
  1618. /**
  1619. * 删除请求前的回调处理配置
  1620. * @param id
  1621. */
  1622. delete(id) {
  1623. if (typeof id === "string") {
  1624. let findIndex = this.$config.configList.findIndex((item) => item.id === id);
  1625. if (findIndex !== -1) {
  1626. this.$config.configList.splice(findIndex, 1);
  1627. return true;
  1628. }
  1629. }
  1630. return false;
  1631. },
  1632. /**
  1633. * 清空设置的请求前的回调处理配置
  1634. */
  1635. clearAll() {
  1636. this.$config.configList = [];
  1637. },
  1638. };
  1639. HttpxResponseHook = {
  1640. /**
  1641. * @private
  1642. */
  1643. $config: {
  1644. configList: [],
  1645. },
  1646. /**
  1647. * 成功的回调
  1648. * @param response 响应
  1649. * @param details 请求的配置
  1650. */
  1651. successResponseCallBack(response, details) {
  1652. if (typeof details.allowInterceptConfig === "boolean") {
  1653. if (!details.allowInterceptConfig) {
  1654. // 不允许拦截
  1655. return details;
  1656. }
  1657. }
  1658. else {
  1659. if (details.allowInterceptConfig != null) {
  1660. // 配置存在
  1661. // 细分处理是否拦截
  1662. if (typeof details.allowInterceptConfig.afterResponseSuccess ===
  1663. "boolean" &&
  1664. !details.allowInterceptConfig.afterResponseSuccess) {
  1665. // 设置了禁止拦截
  1666. return details;
  1667. }
  1668. }
  1669. }
  1670. for (let index = 0; index < this.$config.configList.length; index++) {
  1671. let item = this.$config.configList[index];
  1672. if (typeof item.successFn === "function") {
  1673. if (item.successFn(response, details) == null) {
  1674. return;
  1675. }
  1676. }
  1677. }
  1678. return response;
  1679. },
  1680. /**
  1681. * 失败的回调
  1682. * @param data 配置
  1683. * @returns
  1684. * 返回null|undefined就是拦截掉了
  1685. */
  1686. errorResponseCallBack(data) {
  1687. if (typeof data.details.allowInterceptConfig === "boolean") {
  1688. if (!data.details.allowInterceptConfig) {
  1689. // 不允许拦截
  1690. return data;
  1691. }
  1692. }
  1693. else {
  1694. if (data.details.allowInterceptConfig != null) {
  1695. // 配置存在
  1696. // 细分处理是否拦截
  1697. if (typeof data.details.allowInterceptConfig.afterResponseError ===
  1698. "boolean" &&
  1699. !data.details.allowInterceptConfig.afterResponseError) {
  1700. // 设置了禁止拦截
  1701. return data;
  1702. }
  1703. }
  1704. }
  1705. for (let index = 0; index < this.$config.configList.length; index++) {
  1706. let item = this.$config.configList[index];
  1707. if (typeof item.errorFn === "function") {
  1708. if (item.errorFn(data) == null) {
  1709. return;
  1710. }
  1711. }
  1712. }
  1713. return data;
  1714. },
  1715. /**
  1716. * 添加请求前的回调处理配置
  1717. */
  1718. add(successFn, errorFn) {
  1719. let id = GenerateUUID();
  1720. this.$config.configList.push({
  1721. id: id,
  1722. successFn: successFn,
  1723. errorFn: errorFn,
  1724. });
  1725. return id;
  1726. },
  1727. /**
  1728. * 删除请求前的回调处理配置
  1729. * @param id
  1730. */
  1731. delete(id) {
  1732. if (typeof id === "string") {
  1733. let findIndex = this.$config.configList.findIndex((item) => item.id === id);
  1734. if (findIndex !== -1) {
  1735. this.$config.configList.splice(findIndex, 1);
  1736. return true;
  1737. }
  1738. }
  1739. return false;
  1740. },
  1741. /**
  1742. * 清空设置的请求前的回调处理配置
  1743. */
  1744. clearAll() {
  1745. this.$config.configList = [];
  1746. },
  1747. };
  1748. HttpxRequestDetails = {
  1749. context: this,
  1750. /**
  1751. * 根据传入的参数处理获取details配置
  1752. */
  1753. handleBeforeRequestDetails(...args) {
  1754. let result = {};
  1755. if (typeof args[0] === "string") {
  1756. /* 传入的是url,details? */
  1757. let url = args[0];
  1758. result.url = url;
  1759. if (typeof args[1] === "object") {
  1760. /* 处理第二个参数details */
  1761. let details = args[1];
  1762. result = details;
  1763. result.url = url;
  1764. }
  1765. }
  1766. else {
  1767. /* 传入的是details */
  1768. result = args[0];
  1769. }
  1770. return result;
  1771. },
  1772. /**
  1773. * 获取请求配置
  1774. * @param method 当前请求方法,默认get
  1775. * @param details 请求配置
  1776. * @param resolve promise回调
  1777. * @param reject 抛出错误回调
  1778. */
  1779. getDetails(method, details, resolve, reject) {
  1780. let that = this;
  1781. let result = {
  1782. url: details.url || this.context.#defaultDetails.url,
  1783. method: (method || "GET").toString().toUpperCase(),
  1784. timeout: details.timeout || this.context.#defaultDetails.timeout,
  1785. responseType: details.responseType || this.context.#defaultDetails.responseType,
  1786. /* 对象使用深拷贝 */
  1787. headers: utils.deepClone(this.context.#defaultDetails.headers),
  1788. data: details.data || this.context.#defaultDetails.data,
  1789. redirect: details.redirect || this.context.#defaultDetails.redirect,
  1790. cookie: details.cookie || this.context.#defaultDetails.cookie,
  1791. binary: details.binary || this.context.#defaultDetails.binary,
  1792. nocache: details.nocache || this.context.#defaultDetails.nocache,
  1793. revalidate: details.revalidate || this.context.#defaultDetails.revalidate,
  1794. /* 对象使用深拷贝 */
  1795. context: utils.deepClone(details.context || this.context.#defaultDetails.context),
  1796. overrideMimeType: details.overrideMimeType ||
  1797. this.context.#defaultDetails.overrideMimeType,
  1798. anonymous: details.anonymous || this.context.#defaultDetails.anonymous,
  1799. fetch: details.fetch || this.context.#defaultDetails.fetch,
  1800. /* 对象使用深拷贝 */
  1801. fetchInit: utils.deepClone(this.context.#defaultDetails.fetchInit),
  1802. allowInterceptConfig: {
  1803. beforeRequest: this.context.#defaultDetails
  1804. .allowInterceptConfig.beforeRequest,
  1805. afterResponseSuccess: this.context.#defaultDetails
  1806. .allowInterceptConfig.afterResponseSuccess,
  1807. afterResponseError: this.context.#defaultDetails
  1808. .allowInterceptConfig.afterResponseError,
  1809. },
  1810. user: details.user || this.context.#defaultDetails.user,
  1811. password: details.password || this.context.#defaultDetails.password,
  1812. onabort(...args) {
  1813. that.context.HttpxCallBack.onAbort(details, resolve, reject, args);
  1814. },
  1815. onerror(...args) {
  1816. that.context.HttpxCallBack.onError(details, resolve, reject, args);
  1817. },
  1818. onloadstart(...args) {
  1819. that.context.HttpxCallBack.onLoadStart(details, args);
  1820. },
  1821. onprogress(...args) {
  1822. that.context.HttpxCallBack.onProgress(details, args);
  1823. },
  1824. onreadystatechange(...args) {
  1825. that.context.HttpxCallBack.onReadyStateChange(details, args);
  1826. },
  1827. ontimeout(...args) {
  1828. that.context.HttpxCallBack.onTimeout(details, resolve, reject, args);
  1829. },
  1830. onload(...args) {
  1831. that.context.HttpxCallBack.onLoad(details, resolve, reject, args);
  1832. },
  1833. };
  1834. // 补全allowInterceptConfig参数
  1835. if (typeof details.allowInterceptConfig === "boolean") {
  1836. Object.keys(result.allowInterceptConfig).forEach((keyName) => {
  1837. result.allowInterceptConfig[keyName] =
  1838. details.allowInterceptConfig;
  1839. });
  1840. }
  1841. else {
  1842. if (typeof details.allowInterceptConfig === "object" &&
  1843. details.allowInterceptConfig != null) {
  1844. Object.keys(details.allowInterceptConfig).forEach((keyName) => {
  1845. let value = details.allowInterceptConfig[keyName];
  1846. if (keyName in
  1847. result.allowInterceptConfig &&
  1848. typeof value === "boolean") {
  1849. result.allowInterceptConfig[keyName] = value;
  1850. }
  1851. });
  1852. }
  1853. }
  1854. if (typeof this.context.GM_Api.xmlHttpRequest !== "function") {
  1855. result.fetch = true;
  1856. }
  1857. if (typeof result.headers === "object") {
  1858. if (typeof details.headers === "object") {
  1859. Object.keys(details.headers).forEach((keyName, index) => {
  1860. if (keyName in result.headers &&
  1861. details.headers?.[keyName] == null) {
  1862. /* 在默认的header中存在,且设置它新的值为空,那么就是默认的值 */
  1863. Reflect.deleteProperty(result.headers, keyName);
  1864. }
  1865. else {
  1866. result.headers[keyName] = details?.headers?.[keyName];
  1867. }
  1868. });
  1869. }
  1870. }
  1871. else {
  1872. result.headers = details.headers;
  1873. }
  1874. if (typeof result.fetchInit === "object") {
  1875. /* 使用assign替换且添加 */
  1876. if (typeof details.fetchInit === "object") {
  1877. Object.keys(details.fetchInit).forEach((keyName, index) => {
  1878. if (keyName in result.fetchInit &&
  1879. details.fetchInit[keyName] == null) {
  1880. /* 在默认的fetchInit中存在,且设置它新的值为空,那么就是默认的值 */
  1881. Reflect.deleteProperty(result.fetchInit, keyName);
  1882. }
  1883. else {
  1884. result.fetchInit[keyName] = details.fetchInit[keyName];
  1885. }
  1886. });
  1887. }
  1888. }
  1889. else {
  1890. result.fetchInit = details.fetchInit;
  1891. }
  1892. return result;
  1893. },
  1894. /**
  1895. * 处理发送请求的details,去除值为undefined、空function的值
  1896. * @param details
  1897. */
  1898. handle(details) {
  1899. Object.keys(details).forEach((keyName) => {
  1900. if (details[keyName] == null ||
  1901. (details[keyName] instanceof Function &&
  1902. utils.isNull(details[keyName]))) {
  1903. Reflect.deleteProperty(details, keyName);
  1904. return;
  1905. }
  1906. });
  1907. if (utils.isNull(details.url)) {
  1908. throw new TypeError(`Utils.Httpx 参数 url不符合要求: ${details.url}`);
  1909. }
  1910. /* method值统一大写,兼容Via */
  1911. details.method = details.method.toUpperCase();
  1912. /* 判断是否是以http开头,否则主动加上origin */
  1913. try {
  1914. new URL(details.url);
  1915. }
  1916. catch (error) {
  1917. if (details.url.startsWith("//")) {
  1918. details.url = UtilsCore.globalThis.location.protocol + details.url;
  1919. }
  1920. else if (details.url.startsWith("/")) {
  1921. details.url = UtilsCore.globalThis.location.origin + details.url;
  1922. }
  1923. else {
  1924. details.url =
  1925. UtilsCore.globalThis.location.origin + "/" + details.url;
  1926. }
  1927. }
  1928. return details;
  1929. },
  1930. /**
  1931. * 处理fetch的配置
  1932. * @param details
  1933. */
  1934. handleFetchDetail(details) {
  1935. /**
  1936. * fetch的请求配置
  1937. **/
  1938. let fetchRequestInit = {};
  1939. if ((details.method === "GET" || details.method === "HEAD") &&
  1940. details.data != null) {
  1941. /* GET 或 HEAD 方法的请求不能包含 body 信息 */
  1942. Reflect.deleteProperty(details, "data");
  1943. }
  1944. /* 中止信号控制器 */
  1945. let abortController = new AbortController();
  1946. let signal = abortController.signal;
  1947. signal.onabort = () => {
  1948. details.onabort({
  1949. isFetch: true,
  1950. responseText: "",
  1951. response: null,
  1952. readyState: 4,
  1953. responseHeaders: "",
  1954. status: 0,
  1955. statusText: "",
  1956. error: "aborted",
  1957. });
  1958. };
  1959. fetchRequestInit.method = details.method ?? "GET";
  1960. fetchRequestInit.headers = details.headers;
  1961. fetchRequestInit.body = details.data;
  1962. fetchRequestInit.mode = "cors";
  1963. fetchRequestInit.credentials = "include";
  1964. fetchRequestInit.cache = "no-cache";
  1965. fetchRequestInit.redirect = "follow";
  1966. fetchRequestInit.referrerPolicy = "origin-when-cross-origin";
  1967. fetchRequestInit.signal = signal;
  1968. Object.assign(fetchRequestInit, details.fetchInit || {});
  1969. return {
  1970. fetchDetails: details,
  1971. fetchRequestInit: fetchRequestInit,
  1972. abortController: abortController,
  1973. };
  1974. },
  1975. };
  1976. HttpxCallBack = {
  1977. context: this,
  1978. /**
  1979. * onabort请求被取消-触发
  1980. * @param details 配置
  1981. * @param resolve 回调
  1982. * @param reject 抛出错误
  1983. * @param argumentsList 参数列表
  1984. */
  1985. onAbort(details, resolve, reject, argumentsList) {
  1986. if ("onabort" in details) {
  1987. details.onabort.apply(this, argumentsList);
  1988. }
  1989. else if ("onabort" in this.context.#defaultDetails) {
  1990. this.context.#defaultDetails.onabort.apply(this, argumentsList);
  1991. }
  1992. if (this.context.HttpxResponseHook.errorResponseCallBack({
  1993. type: "onabort",
  1994. error: new TypeError("request canceled"),
  1995. response: null,
  1996. details: details,
  1997. }) == null) {
  1998. // reject(new TypeError("response is intercept with onabort"));
  1999. return;
  2000. }
  2001. resolve({
  2002. status: false,
  2003. data: [...argumentsList],
  2004. msg: "请求被取消",
  2005. type: "onabort",
  2006. });
  2007. },
  2008. /**
  2009. * onerror请求异常-触发
  2010. * @param details 配置
  2011. * @param resolve 回调
  2012. * @param reject 抛出错误
  2013. * @param argumentsList 响应的参数列表
  2014. */
  2015. onError(details, resolve, reject, argumentsList) {
  2016. if ("onerror" in details) {
  2017. details.onerror.apply(this, argumentsList);
  2018. }
  2019. else if ("onerror" in this.context.#defaultDetails) {
  2020. this.context.#defaultDetails.onerror.apply(this, argumentsList);
  2021. }
  2022. let response = argumentsList;
  2023. if (response.length) {
  2024. response = response[0];
  2025. }
  2026. if (this.context.HttpxResponseHook.errorResponseCallBack({
  2027. type: "onerror",
  2028. error: new TypeError("request error"),
  2029. response: response,
  2030. details: details,
  2031. }) == null) {
  2032. // reject(new TypeError("response is intercept with onerror"));
  2033. return;
  2034. }
  2035. resolve({
  2036. status: false,
  2037. data: response,
  2038. details: details,
  2039. msg: "请求异常",
  2040. type: "onerror",
  2041. });
  2042. },
  2043. /**
  2044. * ontimeout请求超时-触发
  2045. * @param details 配置
  2046. * @param resolve 回调
  2047. * @param reject 抛出错误
  2048. * @param argumentsList 参数列表
  2049. */
  2050. onTimeout(details, resolve, reject, argumentsList) {
  2051. if ("ontimeout" in details) {
  2052. details.ontimeout.apply(this, argumentsList);
  2053. }
  2054. else if ("ontimeout" in this.context.#defaultDetails) {
  2055. this.context.#defaultDetails.ontimeout.apply(this, argumentsList);
  2056. }
  2057. if (this.context.HttpxResponseHook.errorResponseCallBack({
  2058. type: "ontimeout",
  2059. error: new TypeError("request timeout"),
  2060. response: (argumentsList || [null])[0],
  2061. details: details,
  2062. }) == null) {
  2063. // reject(new TypeError("response is intercept with ontimeout"));
  2064. return;
  2065. }
  2066. resolve({
  2067. status: false,
  2068. data: [...argumentsList],
  2069. msg: "请求超时",
  2070. type: "ontimeout",
  2071. });
  2072. },
  2073. /**
  2074. * onloadstart请求开始-触发
  2075. * @param details 配置
  2076. * @param argumentsList 参数列表
  2077. */
  2078. onLoadStart(details, argumentsList) {
  2079. if ("onloadstart" in details) {
  2080. details.onloadstart.apply(this, argumentsList);
  2081. }
  2082. else if ("onloadstart" in this.context.#defaultDetails) {
  2083. this.context.#defaultDetails.onloadstart.apply(this, argumentsList);
  2084. }
  2085. },
  2086. /**
  2087. * onload加载完毕-触发
  2088. * @param details 请求的配置
  2089. * @param resolve 回调
  2090. * @param reject 抛出错误
  2091. * @param argumentsList 参数列表
  2092. */
  2093. onLoad(details, resolve, reject, argumentsList) {
  2094. /* X浏览器会因为设置了responseType导致不返回responseText */
  2095. let Response = argumentsList[0];
  2096. /* responseText为空,response不为空的情况 */
  2097. if (utils.isNull(Response["responseText"]) &&
  2098. utils.isNotNull(Response["response"])) {
  2099. if (typeof Response["response"] === "object") {
  2100. utils.tryCatch().run(() => {
  2101. Response["responseText"] = JSON.stringify(Response["response"]);
  2102. });
  2103. }
  2104. else {
  2105. Response["responseText"] = Response["response"];
  2106. }
  2107. }
  2108. /* response为空,responseText不为空的情况 */
  2109. if (Response["response"] == null &&
  2110. typeof Response["responseText"] === "string" &&
  2111. Response["responseText"].trim() !== "") {
  2112. let newResponse = Response["responseText"];
  2113. if (details.responseType === "json") {
  2114. newResponse = utils.toJSON(Response["responseText"]);
  2115. }
  2116. else if (details.responseType === "document") {
  2117. let parser = new DOMParser();
  2118. newResponse = parser.parseFromString(Response["responseText"], "text/html");
  2119. }
  2120. else if (details.responseType === "arraybuffer") {
  2121. let encoder = new TextEncoder();
  2122. let arrayBuffer = encoder.encode(Response["responseText"]);
  2123. newResponse = arrayBuffer;
  2124. }
  2125. else if (details.responseType === "blob") {
  2126. let encoder = new TextEncoder();
  2127. let arrayBuffer = encoder.encode(Response["responseText"]);
  2128. newResponse = new Blob([arrayBuffer]);
  2129. }
  2130. else {
  2131. newResponse = Response["responseText"];
  2132. }
  2133. try {
  2134. Response["response"] = newResponse;
  2135. }
  2136. catch (error) {
  2137. console.warn("response 无法被覆盖");
  2138. }
  2139. }
  2140. /* Stay扩展中没有finalUrl,对应的是responseURL */
  2141. if (Response["finalUrl"] == null &&
  2142. Response["responseURL"] != null) {
  2143. Response["finalUrl"] = Response["responseURL"];
  2144. }
  2145. /* 状态码2xx都是成功的 */
  2146. if (Math.floor(Response.status / 100) === 2) {
  2147. if (this.context.HttpxResponseHook.successResponseCallBack(Response, details) == null) {
  2148. // reject(new TypeError("response is intercept with onloada"));
  2149. return;
  2150. }
  2151. resolve({
  2152. status: true,
  2153. data: Response,
  2154. details: details,
  2155. msg: "请求完毕",
  2156. type: "onload",
  2157. });
  2158. }
  2159. else {
  2160. this.context.HttpxCallBack.onError(details, resolve, reject, argumentsList);
  2161. }
  2162. },
  2163. /**
  2164. * onprogress上传进度-触发
  2165. * @param details 配置
  2166. * @param argumentsList 参数列表
  2167. */
  2168. onProgress(details, argumentsList) {
  2169. if ("onprogress" in details) {
  2170. details.onprogress.apply(this, argumentsList);
  2171. }
  2172. else if ("onprogress" in this.context.#defaultDetails) {
  2173. this.context.#defaultDetails.onprogress.apply(this, argumentsList);
  2174. }
  2175. },
  2176. /**
  2177. * onreadystatechange准备状态改变-触发
  2178. * @param details 配置
  2179. * @param argumentsList 参数列表
  2180. */
  2181. onReadyStateChange(details, argumentsList) {
  2182. if ("onreadystatechange" in details) {
  2183. details.onreadystatechange.apply(this, argumentsList);
  2184. }
  2185. else if ("onreadystatechange" in this.context.#defaultDetails) {
  2186. this.context.#defaultDetails.onreadystatechange.apply(this, argumentsList);
  2187. }
  2188. },
  2189. };
  2190. HttpxRequest = {
  2191. context: this,
  2192. /**
  2193. * 发送请求
  2194. * @param details
  2195. */
  2196. request(details) {
  2197. if (this.context.#LOG_DETAILS) {
  2198. console.log("Httpx请求配置👇", details);
  2199. }
  2200. if (typeof this.context.HttpxRequestHook.beforeRequestCallBack ===
  2201. "function") {
  2202. let hookResult = this.context.HttpxRequestHook.beforeRequestCallBack(details);
  2203. if (hookResult == null) {
  2204. return;
  2205. }
  2206. }
  2207. if (details.fetch) {
  2208. const { fetchDetails, fetchRequestInit, abortController } = this.context.HttpxRequestDetails.handleFetchDetail(details);
  2209. this.fetch(fetchDetails, fetchRequestInit, abortController);
  2210. }
  2211. else {
  2212. Reflect.deleteProperty(details, "fetchInit");
  2213. this.xmlHttpRequest(details);
  2214. }
  2215. },
  2216. /**
  2217. * 使用油猴函数GM_xmlhttpRequest发送请求
  2218. * @param details
  2219. */
  2220. xmlHttpRequest(details) {
  2221. this.context.GM_Api.xmlHttpRequest(details);
  2222. },
  2223. /**
  2224. * 使用fetch发送请求
  2225. * @param details
  2226. * @param fetchRequestInit
  2227. * @param abortController
  2228. */
  2229. fetch(details, fetchRequestInit, abortController) {
  2230. fetch(details.url, fetchRequestInit)
  2231. .then(async (resp) => {
  2232. /**
  2233. * @type {HttpxAsyncResultData}
  2234. */
  2235. let httpxResponse = {
  2236. isFetch: true,
  2237. finalUrl: resp.url,
  2238. readyState: 4,
  2239. status: resp.status,
  2240. statusText: resp.statusText,
  2241. response: void 0,
  2242. responseFetchHeaders: resp.headers,
  2243. responseHeaders: "",
  2244. responseText: void 0,
  2245. responseType: details.responseType,
  2246. responseXML: void 0,
  2247. };
  2248. Object.assign(httpxResponse, details.context || {});
  2249. for (const [key, value] of resp.headers.entries()) {
  2250. httpxResponse.responseHeaders += `${key}: ${value}\n`;
  2251. }
  2252. /* 如果是流式传输,直接返回 */
  2253. if (details.responseType === "stream" ||
  2254. (resp.headers.has("Content-Type") &&
  2255. resp.headers.get("Content-Type").includes("text/event-stream"))) {
  2256. httpxResponse["isStream"] = true;
  2257. httpxResponse.response = resp.body;
  2258. Reflect.deleteProperty(httpxResponse, "responseText");
  2259. Reflect.deleteProperty(httpxResponse, "responseXML");
  2260. details.onload(httpxResponse);
  2261. return;
  2262. }
  2263. /** 响应 */
  2264. let response = "";
  2265. /** 响应字符串 */
  2266. let responseText = "";
  2267. /** 响应xml文档 */
  2268. let responseXML = "";
  2269. let arrayBuffer = await resp.arrayBuffer();
  2270. let encoding = "utf-8";
  2271. if (resp.headers.has("Content-Type")) {
  2272. let charsetMatched = resp.headers
  2273. .get("Content-Type")
  2274. ?.match(/charset=(.+)/);
  2275. if (charsetMatched) {
  2276. encoding = charsetMatched[1];
  2277. }
  2278. }
  2279. let textDecoder = new TextDecoder(encoding);
  2280. responseText = textDecoder.decode(arrayBuffer);
  2281. response = responseText;
  2282. if (details.responseType === "arraybuffer") {
  2283. response = arrayBuffer;
  2284. }
  2285. else if (details.responseType === "blob") {
  2286. response = new Blob([arrayBuffer]);
  2287. }
  2288. else if (details.responseType === "document" ||
  2289. details.responseType == null) {
  2290. let parser = new DOMParser();
  2291. response = parser.parseFromString(responseText, "text/html");
  2292. }
  2293. else if (details.responseType === "json") {
  2294. response = utils.toJSON(responseText);
  2295. }
  2296. let parser = new DOMParser();
  2297. responseXML = parser.parseFromString(responseText, "text/xml");
  2298. httpxResponse.response = response;
  2299. httpxResponse.responseText = responseText;
  2300. httpxResponse.responseXML = responseXML;
  2301. details.onload(httpxResponse);
  2302. })
  2303. .catch((err) => {
  2304. if (err.name === "AbortError") {
  2305. return;
  2306. }
  2307. details.onerror({
  2308. isFetch: true,
  2309. finalUrl: details.url,
  2310. readyState: 4,
  2311. status: 0,
  2312. statusText: "",
  2313. responseHeaders: "",
  2314. responseText: "",
  2315. error: err,
  2316. });
  2317. });
  2318. details.onloadstart({
  2319. isFetch: true,
  2320. finalUrl: details.url,
  2321. readyState: 1,
  2322. responseHeaders: "",
  2323. responseText: "",
  2324. status: 0,
  2325. statusText: "",
  2326. });
  2327. return {
  2328. abort() {
  2329. abortController.abort();
  2330. },
  2331. };
  2332. },
  2333. };
  2334. /**
  2335. * 默认配置
  2336. */
  2337. #defaultDetails = {
  2338. url: void 0,
  2339. timeout: 5000,
  2340. async: false,
  2341. responseType: void 0,
  2342. headers: void 0,
  2343. data: void 0,
  2344. redirect: void 0,
  2345. cookie: void 0,
  2346. binary: void 0,
  2347. nocache: void 0,
  2348. revalidate: void 0,
  2349. context: void 0,
  2350. overrideMimeType: void 0,
  2351. anonymous: void 0,
  2352. fetch: void 0,
  2353. fetchInit: void 0,
  2354. allowInterceptConfig: {
  2355. beforeRequest: true,
  2356. afterResponseSuccess: true,
  2357. afterResponseError: true,
  2358. },
  2359. user: void 0,
  2360. password: void 0,
  2361. onabort() { },
  2362. onerror() { },
  2363. ontimeout() { },
  2364. onloadstart() { },
  2365. onreadystatechange() { },
  2366. onprogress() { },
  2367. };
  2368. /**
  2369. * 当前使用请求时,输出请求的配置
  2370. */
  2371. #LOG_DETAILS = false;
  2372. constructor(__xmlHttpRequest__) {
  2373. if (typeof __xmlHttpRequest__ !== "function") {
  2374. console.warn("Httpx未传入GM_xmlhttpRequest函数或传入的GM_xmlhttpRequest不是Function,强制使用window.fetch");
  2375. }
  2376. this.interceptors.request.context = this;
  2377. this.interceptors.response.context = this;
  2378. this.GM_Api.xmlHttpRequest = __xmlHttpRequest__;
  2379. }
  2380. /**
  2381. * 覆盖当前配置
  2382. * @param details
  2383. */
  2384. config(details = {}) {
  2385. if ("logDetails" in details && typeof details["logDetails"] === "boolean") {
  2386. this.#LOG_DETAILS = details["logDetails"];
  2387. }
  2388. this.#defaultDetails = utils.assign(this.#defaultDetails, details);
  2389. }
  2390. /**
  2391. * 拦截器
  2392. */
  2393. interceptors = {
  2394. /**
  2395. * 请求拦截器
  2396. */
  2397. request: {
  2398. context: null,
  2399. /**
  2400. * 添加拦截器
  2401. * @param fn 设置的请求前回调函数,如果返回配置,则使用返回的配置,如果返回null|undefined,则阻止请求
  2402. */
  2403. use(fn) {
  2404. if (typeof fn !== "function") {
  2405. console.warn("[Httpx-interceptors-request] 请传入拦截器函数");
  2406. return;
  2407. }
  2408. return this.context.HttpxRequestHook.add(fn);
  2409. },
  2410. /**
  2411. * 移除拦截器
  2412. * @param id 通过use返回的id
  2413. */
  2414. eject(id) {
  2415. return this.context.HttpxRequestHook.delete(id);
  2416. },
  2417. /**
  2418. * 移除所有拦截器
  2419. */
  2420. ejectAll() {
  2421. this.context.HttpxRequestHook.clearAll();
  2422. },
  2423. },
  2424. /**
  2425. * 响应拦截器
  2426. */
  2427. response: {
  2428. context: null,
  2429. /**
  2430. * 添加拦截器
  2431. * @param successFn 设置的响应后回调函数,如果返回响应,则使用返回的响应,如果返回null|undefined,则阻止响应
  2432. * + 2xx 范围内的状态码都会触发该函数
  2433. * @param errorFn 设置的响应后回调函数,如果返回响应,则使用返回的响应,如果返回null|undefined,则阻止响应
  2434. * + 超出 2xx 范围的状态码都会触发该函数
  2435. */
  2436. use(successFn, errorFn) {
  2437. if (typeof successFn !== "function" && typeof errorFn !== "function") {
  2438. console.warn("[Httpx-interceptors-response] 必须传入一个拦截器函数");
  2439. return;
  2440. }
  2441. return this.context.HttpxResponseHook.add(successFn, errorFn);
  2442. },
  2443. /**
  2444. * 移除拦截器
  2445. * @param id 通过use返回的id
  2446. */
  2447. eject(id) {
  2448. return this.context.HttpxResponseHook.delete(id);
  2449. },
  2450. /**
  2451. * 移除所有拦截器
  2452. */
  2453. ejectAll() {
  2454. this.context.HttpxResponseHook.clearAll();
  2455. },
  2456. },
  2457. };
  2458. /**
  2459. * 修改xmlHttpRequest
  2460. * @param httpRequest 网络请求函数
  2461. */
  2462. setXMLHttpRequest(httpRequest) {
  2463. this.GM_Api.xmlHttpRequest = httpRequest;
  2464. }
  2465. /**
  2466. * GET 请求
  2467. */
  2468. async get(...args) {
  2469. let that = this;
  2470. let details = this.HttpxRequestDetails.handleBeforeRequestDetails(...args);
  2471. return new Promise((resolve, reject) => {
  2472. let requestDetails = that.HttpxRequestDetails.getDetails("GET", details, resolve, reject);
  2473. Reflect.deleteProperty(requestDetails, "onprogress");
  2474. requestDetails = that.HttpxRequestDetails.handle(requestDetails);
  2475. that.HttpxRequest.request(requestDetails);
  2476. });
  2477. }
  2478. /**
  2479. * POST 请求
  2480. */
  2481. async post(...args) {
  2482. let that = this;
  2483. let details = this.HttpxRequestDetails.handleBeforeRequestDetails(...args);
  2484. return new Promise((resolve, reject) => {
  2485. let requestDetails = that.HttpxRequestDetails.getDetails("POST", details, resolve, reject);
  2486. requestDetails = that.HttpxRequestDetails.handle(requestDetails);
  2487. that.HttpxRequest.request(requestDetails);
  2488. });
  2489. }
  2490. /**
  2491. * HEAD 请求
  2492. */
  2493. async head(...args) {
  2494. let that = this;
  2495. let details = this.HttpxRequestDetails.handleBeforeRequestDetails(...args);
  2496. return new Promise((resolve, reject) => {
  2497. let requestDetails = that.HttpxRequestDetails.getDetails("HEAD", details, resolve, reject);
  2498. Reflect.deleteProperty(requestDetails, "onprogress");
  2499. requestDetails = that.HttpxRequestDetails.handle(requestDetails);
  2500. that.HttpxRequest.request(requestDetails);
  2501. });
  2502. }
  2503. /**
  2504. * OPTIONS 请求
  2505. */
  2506. async options(...args) {
  2507. let that = this;
  2508. let details = this.HttpxRequestDetails.handleBeforeRequestDetails(...args);
  2509. return new Promise((resolve, reject) => {
  2510. let requestDetails = that.HttpxRequestDetails.getDetails("OPTIONS", details, resolve, reject);
  2511. Reflect.deleteProperty(requestDetails, "onprogress");
  2512. requestDetails = that.HttpxRequestDetails.handle(requestDetails);
  2513. that.HttpxRequest.request(requestDetails);
  2514. });
  2515. }
  2516. /**
  2517. * DELETE 请求
  2518. */
  2519. async delete(...args) {
  2520. let that = this;
  2521. let details = this.HttpxRequestDetails.handleBeforeRequestDetails(...args);
  2522. return new Promise((resolve, reject) => {
  2523. let requestDetails = that.HttpxRequestDetails.getDetails("DELETE", details, resolve, reject);
  2524. Reflect.deleteProperty(requestDetails, "onprogress");
  2525. requestDetails = that.HttpxRequestDetails.handle(requestDetails);
  2526. that.HttpxRequest.request(requestDetails);
  2527. });
  2528. }
  2529. /**
  2530. * PUT 请求
  2531. */
  2532. async put(...args) {
  2533. let that = this;
  2534. let details = this.HttpxRequestDetails.handleBeforeRequestDetails(...args);
  2535. return new Promise((resolve, reject) => {
  2536. let requestDetails = that.HttpxRequestDetails.getDetails("PUT", details, resolve, reject);
  2537. requestDetails = that.HttpxRequestDetails.handle(requestDetails);
  2538. that.HttpxRequest.request(requestDetails);
  2539. });
  2540. }
  2541. }
  2542.  
  2543. class indexedDB {
  2544. #dbName;
  2545. #storeName;
  2546. #dbVersion;
  2547. /* websql的版本号,由于ios的问题,版本号的写法不一样 */
  2548. // @ts-ignore
  2549. #slqVersion = "1";
  2550. /* 监听IndexDB */
  2551. #indexedDB = UtilsCore.window.indexedDB ||
  2552. UtilsCore.window.mozIndexedDB ||
  2553. UtilsCore.window.webkitIndexedDB ||
  2554. UtilsCore.window.msIndexedDB;
  2555. /* 缓存数据库,避免同一个页面重复创建和销毁 */
  2556. #db = {};
  2557. // @ts-ignore
  2558. #store = null;
  2559. #errorCode = {
  2560. /* 错误码 */
  2561. success: {
  2562. code: 200,
  2563. msg: "操作成功",
  2564. },
  2565. error: {
  2566. code: 401,
  2567. msg: "操作失败",
  2568. },
  2569. open: { code: 91001, msg: "打开数据库失败" },
  2570. save: { code: 91002, msg: "保存数据失败" },
  2571. get: { code: 91003, msg: "获取数据失败" },
  2572. delete: { code: 91004, msg: "删除数据失败" },
  2573. deleteAll: { code: 91005, msg: "清空数据库失败" },
  2574. regexpGet: { code: 91006, msg: "正则获取数据失败" },
  2575. };
  2576. /**
  2577. * @param dbName 数据存储名,默认为:default_db
  2578. * @param storeName 表名,默认为:default_form
  2579. * @param dbVersion indexDB的版本号,默认为:1
  2580. */
  2581. constructor(dbName = "default_db", storeName = "default_form", dbVersion = 1) {
  2582. this.#dbName = dbName;
  2583. this.#storeName = storeName;
  2584. this.#dbVersion = dbVersion;
  2585. if (!this.#indexedDB) {
  2586. alert("很抱歉,您的浏览器不支持indexedDB");
  2587. throw new TypeError("很抱歉,您的浏览器不支持indexedDB");
  2588. }
  2589. }
  2590. /**
  2591. * 创建 “表”
  2592. * @param dbName 表名
  2593. */
  2594. createStore(dbName) {
  2595. let txn, store;
  2596. txn = this.#db[dbName].transaction(this.#storeName, "readwrite");
  2597. /* IndexDB的读写权限 */
  2598. store = txn.objectStore(this.#storeName);
  2599. this.#store = store;
  2600. return store;
  2601. }
  2602. /**
  2603. * 打开数据库
  2604. * @param callback 回调
  2605. * @param dbName 数据库名
  2606. */
  2607. open(callback, dbName) {
  2608. let that = this;
  2609. /* 打开数据库 */
  2610. /* 如果支持IndexDB */
  2611. if (!that.#db[dbName]) {
  2612. /* 如果缓存中没有,则进行数据库的创建或打开,提高效率 */
  2613. let request = that.#indexedDB.open(dbName, that.#dbVersion);
  2614. request.onerror = function (event) {
  2615. callback({
  2616. code: that.#errorCode.open.code,
  2617. msg: that.#errorCode.open.msg,
  2618. event: event,
  2619. }, false);
  2620. };
  2621. request.onsuccess = function (event) {
  2622. if (!that.#db[dbName]) {
  2623. let target = event.target;
  2624. that.#db[dbName] = target.result;
  2625. }
  2626. let store = that.createStore(dbName);
  2627. callback(store, true);
  2628. };
  2629. request.onupgradeneeded = function (event) {
  2630. let target = event.target;
  2631. that.#db[dbName] = target.result;
  2632. let store = that.#db[dbName].createObjectStore(that.#storeName, {
  2633. keyPath: "key",
  2634. });
  2635. store.transaction.oncomplete = function (event) {
  2636. callback(store, true);
  2637. };
  2638. };
  2639. }
  2640. else {
  2641. /* 如果缓存中已经打开了数据库,就直接使用 */
  2642. let store = that.createStore(dbName);
  2643. callback(store, true);
  2644. }
  2645. }
  2646. /**
  2647. * 保存数据到数据库
  2648. * @param key 数据key
  2649. * @param value 数据值
  2650. */
  2651. async save(key, value) {
  2652. let that = this;
  2653. return new Promise((resolve) => {
  2654. let dbName = that.#dbName;
  2655. let inData = {
  2656. key: key,
  2657. value: value,
  2658. };
  2659. that.open(function (idbStore, success) {
  2660. if (!success) {
  2661. resolve({
  2662. success: false,
  2663. code: that.#errorCode.save.code,
  2664. msg: that.#errorCode.save.msg,
  2665. });
  2666. }
  2667. else {
  2668. idbStore = idbStore;
  2669. let request = idbStore.put(inData);
  2670. request.onsuccess = function (event) {
  2671. /* 保存成功有success 字段 */
  2672. // @ts-ignore
  2673. event.target;
  2674. resolve({
  2675. success: true,
  2676. code: that.#errorCode.success.code,
  2677. msg: that.#errorCode.success.msg,
  2678. event: event,
  2679. });
  2680. };
  2681. request.onerror = function (event) {
  2682. // @ts-ignore
  2683. event.target;
  2684. resolve({
  2685. success: false,
  2686. code: that.#errorCode.save.code,
  2687. msg: that.#errorCode.save.msg,
  2688. event: event,
  2689. });
  2690. };
  2691. }
  2692. }, dbName);
  2693. });
  2694. }
  2695. /**
  2696. * 根据key获取值
  2697. * @param key 数据key
  2698. */
  2699. async get(key) {
  2700. let that = this;
  2701. return new Promise((resolve) => {
  2702. let dbName = that.#dbName;
  2703. that.open(function (idbStore, success) {
  2704. /* 判断返回的数据中是否有error字段 */
  2705. if (!success) {
  2706. resolve({
  2707. success: false,
  2708. code: that.#errorCode.get.code,
  2709. msg: that.#errorCode.get.msg,
  2710. data: void 0,
  2711. });
  2712. }
  2713. else {
  2714. idbStore = idbStore;
  2715. let request = idbStore.get(key);
  2716. request.onsuccess = function (event) {
  2717. let target = event.target;
  2718. let result = target.result;
  2719. /* result 返回的是 {key: string, value: any} */
  2720. /* 键值对存储 */
  2721. let data = result ? result.value : void 0;
  2722. if (data) {
  2723. resolve({
  2724. success: true,
  2725. code: that.#errorCode.success.code,
  2726. msg: that.#errorCode.success.msg,
  2727. data: data,
  2728. event: event,
  2729. result: result,
  2730. });
  2731. }
  2732. else {
  2733. resolve({
  2734. success: false,
  2735. code: that.#errorCode.error.code,
  2736. msg: that.#errorCode.error.msg,
  2737. data: void 0,
  2738. event: event,
  2739. result: result,
  2740. });
  2741. }
  2742. };
  2743. request.onerror = function (event) {
  2744. // @ts-ignore
  2745. event.target;
  2746. resolve({
  2747. success: false,
  2748. code: that.#errorCode.get.code,
  2749. msg: that.#errorCode.get.msg,
  2750. data: void 0,
  2751. event: event,
  2752. });
  2753. };
  2754. }
  2755. }, dbName);
  2756. });
  2757. }
  2758. /**
  2759. * 正则获取数据
  2760. * @param key 数据键
  2761. */
  2762. async regexpGet(key) {
  2763. let list = [];
  2764. let that = this;
  2765. return new Promise((resolve) => {
  2766. /* 正则查询 */
  2767. let dbName = that.#dbName;
  2768. that.open(function (idbStore, success) {
  2769. /* 判断返回的数据中是否有error字段 */
  2770. if (!success) {
  2771. resolve({
  2772. success: false,
  2773. code: that.#errorCode.regexpGet.code,
  2774. msg: that.#errorCode.regexpGet.msg,
  2775. data: [],
  2776. });
  2777. }
  2778. else {
  2779. idbStore = idbStore;
  2780. let request = idbStore.getAll();
  2781. request.onsuccess = function (event) {
  2782. let target = event.target;
  2783. let result = target.result;
  2784. if (result.length !== 0) {
  2785. result.forEach((item, index) => {
  2786. if (item["key"].match(key)) {
  2787. let concatList = item["value"];
  2788. concatList["key"] = item["key"];
  2789. list = [...list, concatList];
  2790. }
  2791. });
  2792. }
  2793. resolve({
  2794. success: true,
  2795. code: that.#errorCode.success.code,
  2796. msg: that.#errorCode.success.msg,
  2797. data: list,
  2798. event: event,
  2799. });
  2800. };
  2801. request.onerror = function (event) {
  2802. // @ts-ignore
  2803. event.target;
  2804. resolve({
  2805. success: false,
  2806. code: that.#errorCode.get.code,
  2807. msg: that.#errorCode.get.msg,
  2808. data: [],
  2809. event: event,
  2810. });
  2811. };
  2812. }
  2813. }, dbName);
  2814. });
  2815. }
  2816. /**
  2817. * 删除数据
  2818. * @param {string} key 数据键
  2819. */
  2820. async delete(key) {
  2821. let that = this;
  2822. return new Promise((resolve) => {
  2823. /* 根据key删除某条数据 */
  2824. let dbName = that.#dbName;
  2825. that.open(function (idbStore, success) {
  2826. if (!success) {
  2827. resolve({
  2828. success: false,
  2829. code: that.#errorCode.delete.code,
  2830. msg: that.#errorCode.delete.msg,
  2831. });
  2832. }
  2833. else {
  2834. idbStore = idbStore;
  2835. let request = idbStore.get(key);
  2836. request.onsuccess = function (event) {
  2837. let target = event.target;
  2838. let recode = target.result;
  2839. if (recode) {
  2840. /* 成功 */
  2841. request = idbStore.delete(key);
  2842. resolve({
  2843. success: true,
  2844. code: that.#errorCode.success.code,
  2845. msg: that.#errorCode.success.msg,
  2846. });
  2847. }
  2848. else {
  2849. resolve({
  2850. success: false,
  2851. code: that.#errorCode.error.code,
  2852. msg: that.#errorCode.error.msg,
  2853. });
  2854. }
  2855. };
  2856. request.onerror = function (event) {
  2857. // @ts-ignore
  2858. event.target;
  2859. resolve({
  2860. success: false,
  2861. code: that.#errorCode.delete.code,
  2862. msg: that.#errorCode.delete.msg,
  2863. event: event,
  2864. });
  2865. };
  2866. }
  2867. }, dbName);
  2868. });
  2869. }
  2870. /**
  2871. * 删除所有数据
  2872. */
  2873. async deleteAll() {
  2874. let that = this;
  2875. return new Promise((resolve) => {
  2876. /* 清空数据库 */
  2877. let dbName = that.#dbName;
  2878. that.open(function (idbStore, success) {
  2879. if (!success) {
  2880. resolve({
  2881. success: false,
  2882. code: that.#errorCode.deleteAll.code,
  2883. msg: that.#errorCode.deleteAll.msg,
  2884. });
  2885. }
  2886. else {
  2887. idbStore = idbStore;
  2888. idbStore.clear();
  2889. resolve({
  2890. success: true,
  2891. code: that.#errorCode.success.code,
  2892. msg: that.#errorCode.success.msg,
  2893. });
  2894. }
  2895. }, dbName);
  2896. });
  2897. }
  2898. }
  2899.  
  2900. class LockFunction {
  2901. #flag = false;
  2902. #delayTime = 0;
  2903. #callback;
  2904. #context;
  2905. lock;
  2906. unlock;
  2907. run;
  2908. isLock;
  2909. constructor(callback, context, delayTime) {
  2910. let that = this;
  2911. this.#callback = callback;
  2912. if (typeof context === "number") {
  2913. this.#delayTime = context;
  2914. this.#context = utils;
  2915. }
  2916. else {
  2917. this.#delayTime = delayTime;
  2918. this.#context = context;
  2919. }
  2920. /**
  2921. * 锁
  2922. */
  2923. this.lock = function () {
  2924. that.#flag = true;
  2925. };
  2926. /**
  2927. * 解锁
  2928. */
  2929. this.unlock = function () {
  2930. setTimeout(() => {
  2931. that.#flag = false;
  2932. }, that.#delayTime);
  2933. };
  2934. /**
  2935. * 判断是否被锁
  2936. */
  2937. this.isLock = function () {
  2938. return that.#flag;
  2939. };
  2940. /**
  2941. * 执行
  2942. */
  2943. this.run = async function (...args) {
  2944. if (that.isLock()) {
  2945. return;
  2946. }
  2947. that.lock();
  2948. await that.#callback.apply(that.#context, args);
  2949. that.unlock();
  2950. };
  2951. }
  2952. }
  2953.  
  2954. class Log {
  2955. /** 是否禁用输出的flag */
  2956. #disable = false;
  2957. /** 前面的TAG标志 */
  2958. tag = "Utils.Log";
  2959. /* 使用的console函数 */
  2960. #console = null;
  2961. /* 当前输出的数量 */
  2962. #logCount = 0;
  2963. /* 配置 */
  2964. #details = {
  2965. tag: true,
  2966. successColor: "#0000FF",
  2967. errorColor: "#FF0000",
  2968. infoColor: "0",
  2969. warnColor: "0",
  2970. debug: false,
  2971. autoClearConsole: false,
  2972. logMaxCount: 999,
  2973. };
  2974. #msgColorDetails = [
  2975. "font-weight: bold; color: cornflowerblue",
  2976. "font-weight: bold; color: cornflowerblue",
  2977. "font-weight: bold; color: darkorange",
  2978. "font-weight: bold; color: cornflowerblue",
  2979. ];
  2980. /**
  2981. * @param _GM_info_ 油猴管理器的API GM_info,或者是一个对象,如{"script":{name:"Utils.Log"}},或者直接是一个字符串
  2982. * @param console 可指定console对象为unsafeWindow下的console或者是油猴window下的console
  2983. */
  2984. constructor(_GM_info_, console = UtilsCore.window.console) {
  2985. if (typeof _GM_info_ === "string") {
  2986. this.tag = _GM_info_;
  2987. }
  2988. else if (typeof _GM_info_ === "object" &&
  2989. typeof _GM_info_?.script?.name === "string") {
  2990. this.tag = _GM_info_.script.name;
  2991. }
  2992. this.#console = console;
  2993. }
  2994. /**
  2995. * 解析Error的堆栈获取实际调用者的函数名及函数所在的位置
  2996. * @param stack
  2997. */
  2998. parseErrorStack(stack) {
  2999. let result = {
  3000. name: "",
  3001. position: "",
  3002. };
  3003. for (let stackString of stack) {
  3004. stackString = stackString.trim();
  3005. let stackFunctionNameMatch = stackString.match(/^at[\s]+(.+?)[\s]+/i);
  3006. let stackFunctionNamePositionMatch = stackString.match(/^at[\s]+.+[\s]+\((.+?)\)/i);
  3007. if (stackFunctionNameMatch == null) {
  3008. continue;
  3009. }
  3010. if (stackFunctionNamePositionMatch == null) {
  3011. continue;
  3012. }
  3013. /* 获取最后一个,因为第一个是包含了at */
  3014. let stackFunctionName = stackFunctionNameMatch[stackFunctionNameMatch.length - 1];
  3015. let stackFunctionNamePosition = stackFunctionNamePositionMatch[stackFunctionNamePositionMatch.length - 1];
  3016. if (stackFunctionName === "" ||
  3017. stackFunctionName.match(/^(Utils\.|)Log(\.|)|.<anonymous>$|^Function.each|^NodeList.forEach|^k.fn.init.each/g)) {
  3018. continue;
  3019. }
  3020. else {
  3021. result.name = stackFunctionName;
  3022. result.position = stackFunctionNamePosition;
  3023. break;
  3024. }
  3025. }
  3026. if (result.position === "") {
  3027. let lastStackString = stack[stack.length - 1].trim();
  3028. if (lastStackString.startsWith("at chrome-extension://")) {
  3029. let lastStackMatch = lastStackString.match(/^at[\s]+(.+)/);
  3030. if (lastStackMatch) {
  3031. result.position = lastStackMatch[lastStackMatch.length - 1];
  3032. }
  3033. }
  3034. }
  3035. if (result.position === "") {
  3036. result.position = stack[stack.length - 1].trim().replace(/^at[\s]*/g, "");
  3037. }
  3038. return result;
  3039. }
  3040. /**
  3041. * 检测清理控制台
  3042. */
  3043. checkClearConsole() {
  3044. this.#logCount++;
  3045. if (this.#details.autoClearConsole &&
  3046. this.#logCount > this.#details.logMaxCount) {
  3047. this.#console.clear();
  3048. this.#logCount = 0;
  3049. }
  3050. }
  3051. /**
  3052. * 输出内容
  3053. * @param msg 需要输出的内容
  3054. * @param color 颜色
  3055. * @param otherStyle 其它CSS
  3056. */
  3057. printContent(msg, color, otherStyle) {
  3058. this.checkClearConsole();
  3059. otherStyle = otherStyle || "";
  3060. let stackSplit = new Error().stack.split("\n");
  3061. stackSplit.splice(0, 2);
  3062. let { name: callerName, position: callerPosition } = this.parseErrorStack(stackSplit);
  3063. let tagName = this.tag;
  3064. let that = this;
  3065. function consoleMsg(_msg_) {
  3066. if (typeof _msg_ === "string") {
  3067. that.#console.log(`%c[${tagName}%c-%c${callerName}%c]%c %s`, ...that.#msgColorDetails, `color: ${color};${otherStyle}`, _msg_);
  3068. }
  3069. else if (typeof _msg_ === "number") {
  3070. that.#console.log(`%c[${tagName}%c-%c${callerName}%c]%c %d`, ...that.#msgColorDetails, `color: ${color};${otherStyle}`, _msg_);
  3071. }
  3072. else if (typeof _msg_ === "object") {
  3073. that.#console.log(`%c[${tagName}%c-%c${callerName}%c]%c %o`, ...that.#msgColorDetails, `color: ${color};${otherStyle}`, _msg_);
  3074. }
  3075. else {
  3076. that.#console.log(_msg_);
  3077. }
  3078. }
  3079. if (Array.isArray(msg)) {
  3080. msg.forEach((item) => {
  3081. consoleMsg(item);
  3082. });
  3083. }
  3084. else {
  3085. consoleMsg(msg);
  3086. }
  3087. if (this.#details.debug) {
  3088. /* 如果开启调试模式,输出堆栈位置 */
  3089. this.#console.log(callerPosition);
  3090. }
  3091. }
  3092. /**
  3093. * 控制台-普通输出
  3094. * @param msg 需要输出的内容,如果想输出多个,修改成数组,且数组内的长度最大值为4个
  3095. * @param color 输出的颜色
  3096. * @param otherStyle 其它CSS
  3097. */
  3098. info(msg, color = this.#details.infoColor, otherStyle) {
  3099. if (this.#disable)
  3100. return;
  3101. this.printContent.call(this, msg, color, otherStyle);
  3102. }
  3103. /**
  3104. * 控制台-警告输出
  3105. * @param msg 需要输出的内容,如果想输出多个,修改成数组,且数组内的长度最大值为4个
  3106. * @param color 输出的颜色
  3107. * @param otherStyle 其它CSS
  3108. */
  3109. warn(msg, color = this.#details.warnColor, otherStyle = "background: #FEF6D5;padding: 4px 6px 4px 0px;") {
  3110. if (this.#disable)
  3111. return;
  3112. this.printContent.call(this, msg, color, otherStyle);
  3113. }
  3114. /**
  3115. * 控制台-错误输出
  3116. * @param msg 需要输出的内容,如果想输出多个,修改成数组,且数组内的长度最大值为4个
  3117. * @param color 输出的颜色
  3118. * @param otherStyle 其它CSS
  3119. */
  3120. error(msg, color = this.#details.errorColor, otherStyle) {
  3121. if (this.#disable)
  3122. return;
  3123. this.printContent.call(this, msg, color, otherStyle);
  3124. }
  3125. /**
  3126. * 控制台-成功输出
  3127. * @param msg 需要输出的内容,如果想输出多个,修改成数组,且数组内的长度最大值为4个
  3128. * @param color 输出的颜色
  3129. * @param otherStyle 其它CSS
  3130. */
  3131. success(msg, color = this.#details.successColor, otherStyle) {
  3132. if (this.#disable)
  3133. return;
  3134. this.printContent.call(this, msg, color, otherStyle);
  3135. }
  3136. /**
  3137. * 控制台-输出表格
  3138. * @param msg
  3139. * @param color 输出的颜色
  3140. * @param otherStyle 其它CSS
  3141. * @example
  3142. * log.table([{"名字":"example","值":"123"},{"名字":"example2","值":"345"}])
  3143. */
  3144. table(msg, color = this.#details.infoColor, otherStyle = "") {
  3145. if (this.#disable)
  3146. return;
  3147. this.checkClearConsole();
  3148. let stack = new Error().stack.split("\n");
  3149. stack.splice(0, 1);
  3150. let errorStackParse = this.parseErrorStack(stack);
  3151. let stackFunctionName = errorStackParse.name;
  3152. let stackFunctionNamePosition = errorStackParse.position;
  3153. let callerName = stackFunctionName;
  3154. this.#console.log(`%c[${this.tag}%c-%c${callerName}%c]%c`, ...this.#msgColorDetails, `color: ${color};${otherStyle}`);
  3155. this.#console.table(msg);
  3156. if (this.#details.debug) {
  3157. this.#console.log(stackFunctionNamePosition);
  3158. }
  3159. }
  3160. /**
  3161. * 配置Log对象的颜色
  3162. * @param paramDetails 配置信息
  3163. */
  3164. config(paramDetails) {
  3165. this.#details = Object.assign(this.#details, paramDetails);
  3166. }
  3167. /** 禁用输出 */
  3168. disable() {
  3169. this.#disable = true;
  3170. }
  3171. /** 恢复输出 */
  3172. recovery() {
  3173. this.#disable = false;
  3174. }
  3175. }
  3176.  
  3177. class Progress {
  3178. #config = {
  3179. /**
  3180. * canvas元素节点
  3181. */
  3182. canvasNode: null,
  3183. /**
  3184. * 绘制角度
  3185. */
  3186. deg: 95,
  3187. /**
  3188. * 进度
  3189. */
  3190. progress: 0,
  3191. /**
  3192. * 绘制的线宽度
  3193. */
  3194. lineWidth: 10,
  3195. /**
  3196. * 绘制的背景颜色
  3197. */
  3198. lineBgColor: "#1e637c",
  3199. /**
  3200. * 绘制的线的颜色
  3201. */
  3202. lineColor: "#25deff",
  3203. /**
  3204. * 绘制的字体颜色
  3205. */
  3206. textColor: "#000000",
  3207. /**
  3208. * 绘制的字体大小(px)
  3209. */
  3210. fontSize: 22,
  3211. /**
  3212. * 绘制的圆的半径
  3213. */
  3214. circleRadius: 50,
  3215. };
  3216. #ctx = null;
  3217. #width = null;
  3218. #height = null;
  3219. /**
  3220. *
  3221. * @param paramConfig 配置信息
  3222. */
  3223. constructor(paramConfig) {
  3224. this.#config = utils.assign(this.#config, paramConfig);
  3225. if (!(this.#config.canvasNode instanceof HTMLCanvasElement)) {
  3226. throw new Error("Utils.Progress 参数 canvasNode 必须是 HTMLCanvasElement");
  3227. }
  3228. this.init();
  3229. }
  3230. /**
  3231. * 初始化
  3232. */
  3233. init() {
  3234. /* 获取画笔 */
  3235. let ctx = this.#config.canvasNode.getContext("2d");
  3236. if (ctx == null) {
  3237. throw new Error("Utils.Progress 获取画笔失败");
  3238. }
  3239. this.#ctx = ctx;
  3240. /* 元素宽度 */
  3241. this.#width = this.#config.canvasNode.width;
  3242. /* 元素高度 */
  3243. this.#height = this.#config.canvasNode.height;
  3244. /* 清除锯齿 */
  3245. if (UtilsCore.window.devicePixelRatio) {
  3246. this.#config.canvasNode.style.width = this.#width + "px";
  3247. this.#config.canvasNode.style.height = this.#height + "px";
  3248. this.#config.canvasNode.height =
  3249. this.#height * UtilsCore.window.devicePixelRatio;
  3250. this.#config.canvasNode.width =
  3251. this.#width * UtilsCore.window.devicePixelRatio;
  3252. this.#ctx.scale(UtilsCore.window.devicePixelRatio, UtilsCore.window.devicePixelRatio);
  3253. }
  3254. /* 设置线宽 */
  3255. this.#ctx.lineWidth = this.#config.lineWidth;
  3256. }
  3257. /**
  3258. * 绘制
  3259. */
  3260. draw() {
  3261. let degActive = (this.#config.progress * 360) / 100;
  3262. /* 清除画布 */
  3263. this.#ctx.clearRect(0, 0, this.#width, this.#height);
  3264. /* 开始绘制底圆 */
  3265. this.#ctx.beginPath();
  3266. this.#ctx.arc(this.#width / 2, this.#height / 2, this.#config.circleRadius, 1, 8);
  3267. this.#ctx.strokeStyle = this.#config.lineBgColor;
  3268. this.#ctx.stroke();
  3269. /* 开始绘制动态圆 */
  3270. this.#ctx.beginPath();
  3271. this.#ctx.arc(this.#width / 2, this.#height / 2, this.#config.circleRadius, -Math.PI / 2, (degActive * Math.PI) / 180 - Math.PI / 2);
  3272. this.#ctx.strokeStyle = this.#config.lineColor;
  3273. this.#ctx.stroke();
  3274. /* 获取百分比 */
  3275. let txt = parseInt(this.#config.progress.toString()) + "%";
  3276. this.#ctx.font = this.#config.fontSize + "px SimHei";
  3277. /* 获取文本宽度 */
  3278. let w = this.#ctx.measureText(txt).width;
  3279. let h = this.#config.fontSize / 2;
  3280. this.#ctx.fillStyle = this.#config.textColor;
  3281. this.#ctx.fillText(txt, this.#width / 2 - w / 2, this.#height / 2 + h / 2);
  3282. }
  3283. }
  3284.  
  3285. const TryCatch = function (...args) {
  3286. /* 定义变量和函数 */
  3287. let callbackFunction = null;
  3288. let context = null;
  3289. let handleError = (error) => { };
  3290. let defaultDetails = {
  3291. log: true,
  3292. };
  3293. const TryCatchCore = {
  3294. /**
  3295. *
  3296. * @param paramDetails 配置
  3297. * @returns
  3298. */
  3299. config(paramDetails) {
  3300. defaultDetails = utils.assign(defaultDetails, paramDetails);
  3301. return TryCatchCore;
  3302. },
  3303. /**
  3304. * 处理错误
  3305. * @param handler
  3306. */
  3307. error(handler) {
  3308. // @ts-ignore
  3309. handleError = handler;
  3310. return TryCatchCore;
  3311. },
  3312. /**
  3313. * 执行传入的函数并捕获其可能抛出的错误,并通过传入的错误处理函数进行处理。
  3314. * @param callback 待执行函数,可以是 function 或者 string 类型。如果是 string 类型,则会被当做代码进行执行。
  3315. * @param __context__ 待执行函数的作用域,用于apply指定
  3316. * @returns 如果函数有返回值,则返回该返回值;否则返回 tryCatchObj 函数以支持链式调用。
  3317. * @throws {Error} 如果传入参数不符合要求,则会抛出相应类型的错误。
  3318. */
  3319. run(callback, __context__) {
  3320. callbackFunction = callback;
  3321. context = __context__ || this;
  3322. let result = executeTryCatch(callbackFunction, handleError, context);
  3323. // @ts-ignore
  3324. return result !== void 0 ? result : TryCatchCore;
  3325. },
  3326. };
  3327. /**
  3328. * 执行传入的函数并捕获其可能抛出的错误,并通过传入的错误处理函数进行处理。
  3329. * @param callback - 待执行函数,可以是 function 或者 string 类型。如果是 string 类型,则会被当做代码进行执行。
  3330. * @param handleErrorFunc - 错误处理函数,可以是 function 或者 string 类型。如果是 string 类型,则会被当做代码进行执行。
  3331. * @param funcThis - 待执行函数的作用域,用于apply指定
  3332. * @returns 如果函数有返回值,则返回该返回值;否则返回 undefined。
  3333. */
  3334. function executeTryCatch(callback, handleErrorFunc, funcThis) {
  3335. let result = void 0;
  3336. try {
  3337. if (typeof callback === "string") {
  3338. (function () {
  3339. eval(callback);
  3340. }).apply(funcThis, args);
  3341. }
  3342. else {
  3343. result = callback.apply(funcThis, args);
  3344. }
  3345. }
  3346. catch (error) {
  3347. if (defaultDetails.log) {
  3348. callback = callback;
  3349. console.log(`%c ${callback?.name ? callback?.name : callback + "出现错误"} `, "color: #f20000");
  3350. console.log(`%c 错误原因:${error}`, "color: #f20000");
  3351. console.trace(callback);
  3352. }
  3353. if (handleErrorFunc) {
  3354. if (typeof handleErrorFunc === "string") {
  3355. result = function () {
  3356. return eval(handleErrorFunc);
  3357. // @ts-ignore
  3358. }.apply(funcThis, [...args, error]);
  3359. }
  3360. else {
  3361. result = handleErrorFunc.apply(funcThis, [...args, error]);
  3362. }
  3363. }
  3364. }
  3365. return result;
  3366. }
  3367. return TryCatchCore;
  3368. };
  3369.  
  3370. class UtilsDictionary {
  3371. items = {};
  3372. constructor(key, value) {
  3373. if (key != null) {
  3374. this.set(key, value);
  3375. }
  3376. }
  3377. /**
  3378. * 检查是否有某一个键
  3379. * @param key 键
  3380. */
  3381. has(key) {
  3382. return Reflect.has(this.items, key);
  3383. }
  3384. /**
  3385. * 检查已有的键中是否以xx开头
  3386. * @param key 需要匹配的键
  3387. */
  3388. startsWith(key) {
  3389. let allKeys = this.keys();
  3390. for (const keyName of allKeys) {
  3391. if (String(keyName).startsWith(String(key))) {
  3392. return true;
  3393. }
  3394. }
  3395. return false;
  3396. }
  3397. /**
  3398. * 获取以xx开头的键的值
  3399. * @param key 需要匹配的键
  3400. */
  3401. getStartsWith(key) {
  3402. let allKeys = this.keys();
  3403. let result = void 0;
  3404. for (const keyName of allKeys) {
  3405. if (String(keyName).startsWith(String(key))) {
  3406. result = this.get(keyName);
  3407. break;
  3408. }
  3409. }
  3410. return result;
  3411. }
  3412. /**
  3413. * 为字典添加某一个值
  3414. * @param key 键
  3415. * @param val 值,默认为""
  3416. */
  3417. set(key, val) {
  3418. if (key === void 0) {
  3419. throw new Error("Utils.Dictionary().set 参数 key 不能为空");
  3420. }
  3421. Reflect.set(this.items, key, val);
  3422. }
  3423. /**
  3424. * 删除某一个键
  3425. * @param key 键
  3426. */
  3427. delete(key) {
  3428. if (this.has(key)) {
  3429. return Reflect.deleteProperty(this.items, key);
  3430. }
  3431. return false;
  3432. }
  3433. /**
  3434. * 获取某个键的值
  3435. * https://github.com/microsoft/TypeScript/issues/9619
  3436. * 微软到现在都没有修复has和get的联动
  3437. * @param key 键
  3438. */
  3439. get(key) {
  3440. return Reflect.get(this.items, key);
  3441. }
  3442. /**
  3443. * 返回字典中的所有值
  3444. */
  3445. values() {
  3446. let resultList = [];
  3447. for (let prop in this.getItems()) {
  3448. if (this.has(prop)) {
  3449. resultList.push(this.get(prop));
  3450. }
  3451. }
  3452. return resultList;
  3453. }
  3454. /**
  3455. * 清空字典
  3456. */
  3457. clear() {
  3458. this.items = null;
  3459. this.items = {};
  3460. }
  3461. /**
  3462. * 获取字典的长度
  3463. */
  3464. size() {
  3465. return Object.keys(this.getItems()).length;
  3466. }
  3467. /**
  3468. * 获取字典所有的键
  3469. */
  3470. keys() {
  3471. return Reflect.ownKeys(this.items);
  3472. }
  3473. /**
  3474. * 返回字典本身
  3475. */
  3476. getItems() {
  3477. // @ts-ignore
  3478. return this.items;
  3479. }
  3480. /**
  3481. * 合并另一个字典
  3482. * @param data 需要合并的字典
  3483. */
  3484. concat(data) {
  3485. this.items = utils.assign(this.items, data.getItems());
  3486. }
  3487. forEach(callbackfn) {
  3488. for (const key in this.getItems()) {
  3489. callbackfn(this.get(key), key, this.getItems());
  3490. }
  3491. }
  3492. /**
  3493. * 获取字典的长度,同this.size
  3494. */
  3495. get length() {
  3496. return this.size();
  3497. }
  3498. /**
  3499. * 迭代器
  3500. */
  3501. get entries() {
  3502. let that = this;
  3503. return function* () {
  3504. let itemKeys = Object.keys(that.getItems());
  3505. for (const keyName of itemKeys) {
  3506. yield [keyName, that.get(keyName)];
  3507. }
  3508. };
  3509. }
  3510. /**
  3511. * 是否可遍历
  3512. */
  3513. get [Symbol.iterator]() {
  3514. let that = this;
  3515. return function () {
  3516. return that.entries();
  3517. };
  3518. }
  3519. }
  3520.  
  3521. class Utils {
  3522. constructor(option) {
  3523. UtilsCore.init(option);
  3524. }
  3525. /** 版本号 */
  3526. version = "2024.7.20";
  3527. addStyle(cssText) {
  3528. if (typeof cssText !== "string") {
  3529. throw new Error("Utils.addStyle 参数cssText 必须为String类型");
  3530. }
  3531. let cssNode = UtilsCore.document.createElement("style");
  3532. cssNode.setAttribute("type", "text/css");
  3533. cssNode.innerHTML = cssText;
  3534. if (UtilsCore.document.head) {
  3535. /* 插入head最后 */
  3536. UtilsCore.document.head.appendChild(cssNode);
  3537. }
  3538. else if (UtilsCore.document.body) {
  3539. /* 插入body后 */
  3540. UtilsCore.document.body.appendChild(cssNode);
  3541. }
  3542. else if (UtilsCore.document.documentElement.childNodes.length === 0) {
  3543. /* 插入#html第一个元素后 */
  3544. UtilsCore.document.documentElement.appendChild(cssNode);
  3545. }
  3546. else {
  3547. /* 插入head前面 */
  3548. UtilsCore.document.documentElement.insertBefore(cssNode, UtilsCore.document.documentElement.childNodes[0]);
  3549. }
  3550. return cssNode;
  3551. }
  3552. assign(target = {}, source = {}, isAdd = false) {
  3553. let UtilsContext = this;
  3554. if (Array.isArray(source)) {
  3555. let canTraverse = source.filter((item) => {
  3556. return typeof item === "object";
  3557. });
  3558. if (!canTraverse.length) {
  3559. return source;
  3560. }
  3561. }
  3562. if (source == null) {
  3563. return target;
  3564. }
  3565. if (target == null) {
  3566. target = {};
  3567. }
  3568. if (isAdd) {
  3569. for (const sourceKeyName in source) {
  3570. const targetKeyName = sourceKeyName;
  3571. let targetValue = target[targetKeyName];
  3572. let sourceValue = source[sourceKeyName];
  3573. if (typeof sourceValue === "object" &&
  3574. sourceValue != null &&
  3575. sourceKeyName in target &&
  3576. !UtilsContext.isDOM(sourceValue)) {
  3577. /* 源端的值是object类型,且不是元素节点 */
  3578. target[sourceKeyName] = UtilsContext.assign(targetValue, sourceValue, isAdd);
  3579. continue;
  3580. }
  3581. target[sourceKeyName] = sourceValue;
  3582. }
  3583. }
  3584. else {
  3585. for (const targetKeyName in target) {
  3586. if (targetKeyName in source) {
  3587. let targetValue = target[targetKeyName];
  3588. let sourceValue = source[targetKeyName];
  3589. if (typeof sourceValue === "object" &&
  3590. sourceValue != null &&
  3591. !UtilsContext.isDOM(sourceValue) &&
  3592. Object.keys(sourceValue).length) {
  3593. /* 源端的值是object类型,且不是元素节点 */
  3594. target[targetKeyName] = UtilsContext.assign(targetValue, sourceValue, isAdd);
  3595. continue;
  3596. }
  3597. /* 直接赋值 */
  3598. target[targetKeyName] = sourceValue;
  3599. }
  3600. }
  3601. }
  3602. return target;
  3603. }
  3604. async asyncReplaceAll(string, pattern, asyncFn) {
  3605. let UtilsContext = this;
  3606. if (typeof string !== "string") {
  3607. throw new TypeError("string必须是字符串");
  3608. }
  3609. if (typeof asyncFn !== "function") {
  3610. throw new TypeError("asyncFn必须是函数");
  3611. }
  3612. let reg;
  3613. if (typeof pattern === "string") {
  3614. reg = new RegExp(UtilsContext.parseStringToRegExpString(pattern), "g");
  3615. }
  3616. else if (pattern instanceof RegExp) {
  3617. if (!pattern.global) {
  3618. throw new TypeError("pattern必须是全局匹配");
  3619. }
  3620. reg = new RegExp(pattern);
  3621. }
  3622. else {
  3623. throw new TypeError("pattern必须是正则对象");
  3624. }
  3625. let result = [];
  3626. let match;
  3627. let lastIndex = 0;
  3628. while ((match = reg.exec(string)) !== null) {
  3629. /* 异步获取匹配对应的字符串 */
  3630. const item = asyncFn(match[0]);
  3631. /* 获取该匹配项和上一个匹配项的中间的字符串 */
  3632. const prefix = string.slice(lastIndex, match.index);
  3633. lastIndex = match.index + match[0].length;
  3634. result.push(item);
  3635. result.push(prefix);
  3636. }
  3637. result.push(string.slice(lastIndex));
  3638. /* 等待所有异步完成 */
  3639. result = await Promise.all(result);
  3640. return result.join("");
  3641. }
  3642. /**
  3643. * ajax劫持库,支持xhr和fetch劫持。
  3644. * + 来源:https://bbs.tampermonkey.net.cn/thread-3284-1-1.html
  3645. * + 作者:cxxjackie
  3646. * + 版本:1.4.1
  3647. * + 文档:https://scriptcat.org/zh-CN/script-show-page/637/
  3648. */
  3649. ajaxHooker = AjaxHooker;
  3650. canvasClickByPosition(canvasElement, clientX = 0, clientY = 0, view = globalThis) {
  3651. if (!(canvasElement instanceof HTMLCanvasElement)) {
  3652. throw new Error("Utils.canvasClickByPosition 参数canvasElement必须是canvas元素");
  3653. }
  3654. clientX = parseInt(clientX.toString());
  3655. clientY = parseInt(clientY.toString());
  3656. const eventInit = {
  3657. cancelBubble: true,
  3658. cancelable: true,
  3659. clientX: clientX,
  3660. clientY: clientY,
  3661. // @ts-ignore
  3662. view: view,
  3663. detail: 1,
  3664. };
  3665. canvasElement.dispatchEvent(new MouseEvent("mousedown", eventInit));
  3666. canvasElement.dispatchEvent(new MouseEvent("mouseup", eventInit));
  3667. }
  3668. checkUserClickInNode(element) {
  3669. let UtilsContext = this;
  3670. if (!UtilsContext.isDOM(element)) {
  3671. throw new Error("Utils.checkUserClickInNode 参数 targetNode 必须为 Element|Node 类型");
  3672. }
  3673. let mouseClickPosX = Number(window.event.clientX.toString()); /* 鼠标相对屏幕横坐标 */
  3674. let mouseClickPosY = Number(window.event.clientY.toString()); /* 鼠标相对屏幕纵坐标 */
  3675. let elementPosXLeft = Number(element.getBoundingClientRect().left); /* 要检测的元素的相对屏幕的横坐标最左边 */
  3676. let elementPosXRight = Number(element.getBoundingClientRect().right); /* 要检测的元素的相对屏幕的横坐标最右边 */
  3677. let elementPosYTop = Number(element.getBoundingClientRect().top); /* 要检测的元素的相对屏幕的纵坐标最上边 */
  3678. let elementPosYBottom = Number(element.getBoundingClientRect().bottom); /* 要检测的元素的相对屏幕的纵坐标最下边 */
  3679. let clickNodeHTML = UtilsCore.window.event.target
  3680. .innerHTML;
  3681. if (mouseClickPosX >= elementPosXLeft &&
  3682. mouseClickPosX <= elementPosXRight &&
  3683. mouseClickPosY >= elementPosYTop &&
  3684. mouseClickPosY <= elementPosYBottom) {
  3685. return true;
  3686. }
  3687. else if (clickNodeHTML &&
  3688. element.innerHTML.includes(clickNodeHTML)) {
  3689. /* 这种情况是应对在界面中隐藏的元素,getBoundingClientRect获取的都是0 */
  3690. return true;
  3691. }
  3692. else {
  3693. return false;
  3694. }
  3695. }
  3696. cloneFormData(formData) {
  3697. let clonedFormData = new FormData();
  3698. for (let [key, value] of formData.entries()) {
  3699. clonedFormData.append(key, value);
  3700. }
  3701. return clonedFormData;
  3702. }
  3703. createOverload() {
  3704. let fnMap = new Map();
  3705. function overload(...args) {
  3706. let key = args.map((it) => typeof it).join(",");
  3707. let fn = fnMap.get(key);
  3708. if (!fn) {
  3709. throw new TypeError("没有找到对应的实现");
  3710. }
  3711. return fn.apply(this, args);
  3712. }
  3713. overload.addImpl = function (...args) {
  3714. let fn = args.pop();
  3715. if (typeof fn !== "function") {
  3716. throw new TypeError("最后一个参数必须是函数");
  3717. }
  3718. let key = args.join(",");
  3719. fnMap.set(key, fn);
  3720. };
  3721. return overload;
  3722. }
  3723. /**
  3724. * 颜色转换
  3725. * @returns
  3726. */
  3727. ColorConversion = ColorConversion;
  3728. deepClone(obj) {
  3729. let UtilsContext = this;
  3730. if (obj === void 0)
  3731. return void 0;
  3732. if (obj === null)
  3733. return null;
  3734. let clone = obj instanceof Array ? [] : {};
  3735. for (const [key, value] of Object.entries(obj)) {
  3736. clone[key] =
  3737. typeof value === "object" ? UtilsContext.deepClone(value) : value;
  3738. }
  3739. return clone;
  3740. }
  3741. debounce(fn, delay = 0) {
  3742. let timer = null;
  3743. const context = this;
  3744. return function (...args) {
  3745. clearTimeout(timer);
  3746. timer = setTimeout(function () {
  3747. fn.apply(context, args);
  3748. }, delay);
  3749. };
  3750. }
  3751. deleteParentNode(element, targetSelector) {
  3752. let UtilsContext = this;
  3753. if (element == null) {
  3754. return;
  3755. }
  3756. if (!UtilsContext.isDOM(element)) {
  3757. throw new Error("Utils.deleteParentNode 参数 target 必须为 Node|HTMLElement 类型");
  3758. }
  3759. if (typeof targetSelector !== "string") {
  3760. throw new Error("Utils.deleteParentNode 参数 targetSelector 必须为 string 类型");
  3761. }
  3762. let result = false;
  3763. let needRemoveDOM = element.closest(targetSelector);
  3764. if (needRemoveDOM) {
  3765. needRemoveDOM.remove();
  3766. result = true;
  3767. }
  3768. return result;
  3769. }
  3770. /**
  3771. * 字典
  3772. * @example
  3773. * let dictionary = new Utils.Dictionary();
  3774. * let dictionary2 = new Utils.Dictionary();
  3775. * dictionary.set("test","111");
  3776. * dictionary.get("test");
  3777. * > '111'
  3778. * dictionary.has("test");
  3779. * > true
  3780. * dictionary.concat(dictionary2);
  3781. **/
  3782. Dictionary = UtilsDictionary;
  3783. dispatchEvent(element, eventName, details) {
  3784. let eventNameList = [];
  3785. if (typeof eventName === "string") {
  3786. eventNameList = [eventName];
  3787. }
  3788. if (Array.isArray(eventName)) {
  3789. eventNameList = [...eventName];
  3790. }
  3791. eventNameList.forEach((_eventName_) => {
  3792. let event = new Event(_eventName_);
  3793. if (details) {
  3794. Object.assign(event, details);
  3795. }
  3796. element.dispatchEvent(event);
  3797. });
  3798. }
  3799. downloadBase64(base64Data, fileName, isIFrame = false) {
  3800. if (typeof base64Data !== "string") {
  3801. throw new Error("Utils.downloadBase64 参数 base64Data 必须为 string 类型");
  3802. }
  3803. if (typeof fileName !== "string") {
  3804. throw new Error("Utils.downloadBase64 参数 fileName 必须为 string 类型");
  3805. }
  3806. if (isIFrame) {
  3807. /* 使用iframe */
  3808. const iframeElement = UtilsCore.document.createElement("iframe");
  3809. iframeElement.style.display = "none";
  3810. iframeElement.src = base64Data;
  3811. UtilsCore.document.body.appendChild(iframeElement);
  3812. setTimeout(() => {
  3813. iframeElement.contentWindow.document.execCommand("SaveAs", true, fileName);
  3814. UtilsCore.document.body.removeChild(iframeElement);
  3815. }, 100);
  3816. }
  3817. else {
  3818. /* 使用A标签 */
  3819. const linkElement = UtilsCore.document.createElement("a");
  3820. linkElement.setAttribute("target", "_blank");
  3821. linkElement.download = fileName;
  3822. linkElement.href = base64Data;
  3823. linkElement.click();
  3824. }
  3825. }
  3826. findWebPageVisibleText(str = "", caseSensitive = false) {
  3827. let TRange = null;
  3828. let strFound;
  3829. if (UtilsCore.globalThis.find) {
  3830. /* CODE FOR BROWSERS THAT SUPPORT window.find */
  3831. let windowFind = UtilsCore.self.find;
  3832. strFound = windowFind(str, caseSensitive, true, true, false);
  3833. if (strFound &&
  3834. UtilsCore.self.getSelection &&
  3835. !UtilsCore.self.getSelection().anchorNode) {
  3836. strFound = windowFind(str, caseSensitive, true, true, false);
  3837. }
  3838. if (!strFound) {
  3839. strFound = windowFind(str, 0, 1);
  3840. while (windowFind(str, 0, 1))
  3841. continue;
  3842. }
  3843. }
  3844. else if (navigator.appName.indexOf("Microsoft") != -1) {
  3845. /* EXPLORER-SPECIFIC CODE */
  3846. if (TRange != null) {
  3847. TRange = TRange;
  3848. TRange.collapse(false);
  3849. strFound = TRange.findText(str);
  3850. if (strFound)
  3851. TRange.select();
  3852. }
  3853. if (TRange == null || strFound == 0) {
  3854. TRange = UtilsCore.self.document.body.createTextRange();
  3855. strFound = TRange.findText(str);
  3856. if (strFound)
  3857. TRange.select();
  3858. }
  3859. }
  3860. else if (navigator.appName == "Opera") {
  3861. alert("Opera browsers not supported, sorry...");
  3862. return;
  3863. }
  3864. return strFound ? true : false;
  3865. }
  3866. *findElementsWithText(element, text, filter) {
  3867. let that = this;
  3868. if (element.outerHTML.includes(text)) {
  3869. if (element.children.length === 0) {
  3870. let filterResult = typeof filter === "function" ? filter(element) : false;
  3871. if (!filterResult) {
  3872. yield element;
  3873. }
  3874. }
  3875. else {
  3876. let textElement = Array.from(element.childNodes).filter((ele) => ele.nodeType === Node.TEXT_NODE);
  3877. for (let ele of textElement) {
  3878. if (ele.textContent.includes(text)) {
  3879. let filterResult = typeof filter === "function" ? filter(element) : false;
  3880. if (!filterResult) {
  3881. yield ele;
  3882. }
  3883. }
  3884. }
  3885. }
  3886. }
  3887. for (let index = 0; index < element.children.length; index++) {
  3888. let childElement = element.children[index];
  3889. yield* that.findElementsWithText(childElement, text, filter);
  3890. }
  3891. }
  3892. /**
  3893. * 判断该元素是否可见,如果不可见,向上找它的父元素直至找到可见的元素
  3894. * @param element
  3895. * @example
  3896. * let visibleElement = Utils.findVisibleElement(document.querySelector("a.xx"));
  3897. * > <HTMLElement>
  3898. */
  3899. findVisibleElement(element) {
  3900. let currentElement = element;
  3901. while (currentElement) {
  3902. let elementRect = currentElement.getBoundingClientRect();
  3903. if (Boolean(elementRect.length)) {
  3904. return currentElement;
  3905. }
  3906. currentElement = currentElement.parentElement;
  3907. }
  3908. return null;
  3909. }
  3910. formatByteToSize(byteSize, addType = true) {
  3911. byteSize = parseInt(byteSize.toString());
  3912. if (isNaN(byteSize)) {
  3913. throw new Error("Utils.formatByteToSize 参数 byteSize 格式不正确");
  3914. }
  3915. let result = 0;
  3916. let resultType = "KB";
  3917. let sizeData = {};
  3918. sizeData.B = 1;
  3919. sizeData.KB = 1024;
  3920. sizeData.MB = sizeData.KB * sizeData.KB;
  3921. sizeData.GB = sizeData.MB * sizeData.KB;
  3922. sizeData.TB = sizeData.GB * sizeData.KB;
  3923. sizeData.PB = sizeData.TB * sizeData.KB;
  3924. sizeData.EB = sizeData.PB * sizeData.KB;
  3925. sizeData.ZB = sizeData.EB * sizeData.KB;
  3926. sizeData.YB = sizeData.ZB * sizeData.KB;
  3927. sizeData.BB = sizeData.YB * sizeData.KB;
  3928. sizeData.NB = sizeData.BB * sizeData.KB;
  3929. sizeData.DB = sizeData.NB * sizeData.KB;
  3930. for (let key in sizeData) {
  3931. result = byteSize / sizeData[key];
  3932. resultType = key;
  3933. if (sizeData.KB >= result) {
  3934. break;
  3935. }
  3936. }
  3937. result = result.toFixed(2);
  3938. result = addType
  3939. ? result + resultType.toString()
  3940. : parseFloat(result.toString());
  3941. return result;
  3942. }
  3943. getNodeListValue(...args) {
  3944. let resultArray = [];
  3945. for (let arg of args) {
  3946. let value = arg;
  3947. if (typeof arg === "function") {
  3948. /* 方法 */
  3949. value = arg();
  3950. }
  3951. if (value.length !== 0) {
  3952. resultArray = [...value];
  3953. break;
  3954. }
  3955. }
  3956. return resultArray;
  3957. }
  3958. getNonNullValue(...args) {
  3959. let resultValue = args[args.length - 1];
  3960. let UtilsContext = this;
  3961. for (const argValue of args) {
  3962. if (UtilsContext.isNotNull(argValue)) {
  3963. resultValue = argValue;
  3964. break;
  3965. }
  3966. }
  3967. return resultValue;
  3968. }
  3969. formatTime(text = new Date(), formatType = "yyyy-MM-dd HH:mm:ss") {
  3970. let time = text == null ? new Date() : new Date(text);
  3971. /**
  3972. * 校验时间补0
  3973. * @param timeNum
  3974. * @returns
  3975. */
  3976. function checkTime(timeNum) {
  3977. if (timeNum < 10)
  3978. return "0" + timeNum;
  3979. return timeNum;
  3980. }
  3981. /**
  3982. * 时间制修改 24小时制转12小时制
  3983. * @param hourNum 小时
  3984. * @returns
  3985. */
  3986. function timeSystemChange(hourNum) {
  3987. return hourNum > 12 ? hourNum - 12 : hourNum;
  3988. }
  3989. let timeRegexp = {
  3990. yyyy: time.getFullYear(),
  3991. /* 年 */
  3992. MM: checkTime(time.getMonth() + 1),
  3993. /* 月 */
  3994. dd: checkTime(time.getDate()),
  3995. /* 日 */
  3996. HH: checkTime(time.getHours()),
  3997. /* 时 (24小时制) */
  3998. hh: checkTime(timeSystemChange(time.getHours())),
  3999. /* 时 (12小时制) */
  4000. mm: checkTime(time.getMinutes()),
  4001. /* 分 */
  4002. ss: checkTime(time.getSeconds()),
  4003. /* 秒 */
  4004. };
  4005. Object.keys(timeRegexp).forEach(function (key) {
  4006. let replaecRegexp = new RegExp(key, "g");
  4007. formatType = formatType.replace(replaecRegexp, timeRegexp[key]);
  4008. });
  4009. return formatType;
  4010. }
  4011. formatToTimeStamp(text) {
  4012. /* 把字符串格式的时间(完整,包括日期和时间)格式化成时间 */
  4013. if (typeof text !== "string") {
  4014. throw new Error("Utils.formatToTimeStamp 参数 text 必须为 string 类型");
  4015. }
  4016. if (text.length === 8) {
  4017. /* 该字符串只有时分秒 */
  4018. let today = new Date();
  4019. text =
  4020. today.getFullYear() +
  4021. "-" +
  4022. (today.getMonth() + 1) +
  4023. "-" +
  4024. today.getDate() +
  4025. " " +
  4026. text;
  4027. }
  4028. text = text.substring(0, 19);
  4029. text = text.replace(/-/g, "/");
  4030. let timestamp = new Date(text).getTime();
  4031. return timestamp;
  4032. }
  4033. /**
  4034. * gbk格式的url编码,来自https://gf.qytechs.cn/zh-CN/scripts/427726-gbk-url-js
  4035. * @example
  4036. * let gbkEncoder = new Utils.GBKEncoder();
  4037. * gbkEncoder.encode("测试");
  4038. * > '%B2%E2%CA%D4'
  4039. * gbkEncoder.decode("%B2%E2%CA%D4");
  4040. * > 测试
  4041. */
  4042. GBKEncoder = GBKEncoder;
  4043. /**
  4044. * 获取 transitionend 的在各个浏览器的兼容名
  4045. */
  4046. getTransitionEndNameList() {
  4047. return [
  4048. "webkitTransitionEnd",
  4049. "mozTransitionEnd",
  4050. "MSTransitionEnd",
  4051. "otransitionend",
  4052. "transitionend",
  4053. ];
  4054. }
  4055. /**
  4056. * 获取 animationend 的在各个浏览器的兼容名
  4057. */
  4058. getAnimationEndNameList() {
  4059. return [
  4060. "webkitAnimationEnd",
  4061. "mozAnimationEnd",
  4062. "MSAnimationEnd",
  4063. "oanimationend",
  4064. "animationend",
  4065. ];
  4066. }
  4067. getArrayLastValue(targetObj) {
  4068. return targetObj[targetObj.length - 1];
  4069. }
  4070. getArrayRealValue(...args) {
  4071. let result = null;
  4072. for (let arg of args) {
  4073. if (typeof arg === "function") {
  4074. /* 方法 */
  4075. arg = arg();
  4076. }
  4077. if (arg != null) {
  4078. result = arg;
  4079. break;
  4080. }
  4081. }
  4082. return result;
  4083. }
  4084. getDaysDifference(timestamp1 = Date.now(), timestamp2 = Date.now(), type = "天") {
  4085. type = type.trim();
  4086. if (timestamp1.toString().length === 10) {
  4087. timestamp1 = timestamp1 * 1000;
  4088. }
  4089. if (timestamp2.toString().length === 10) {
  4090. timestamp2 = timestamp2 * 1000;
  4091. }
  4092. let smallTimeStamp = timestamp1 > timestamp2 ? timestamp2 : timestamp1;
  4093. let bigTimeStamp = timestamp1 > timestamp2 ? timestamp1 : timestamp2;
  4094. let oneSecond = 1000; /* 一秒的毫秒数 */
  4095. let oneMinute = 60 * oneSecond; /* 一分钟的毫秒数 */
  4096. let oneHour = 60 * oneMinute; /* 一小时的毫秒数 */
  4097. let oneDay = 24 * oneHour; /* 一天的毫秒数 */
  4098. let oneMonth = 30 * oneDay; /* 一个月的毫秒数(30天) */
  4099. let oneYear = 12 * oneMonth; /* 一年的毫秒数 */
  4100. let bigDate = new Date(bigTimeStamp);
  4101. let smallDate = new Date(smallTimeStamp);
  4102. let remainderValue = 1;
  4103. if (type === "年") {
  4104. remainderValue = oneYear;
  4105. }
  4106. else if (type === "月") {
  4107. remainderValue = oneMonth;
  4108. }
  4109. else if (type === "天") {
  4110. remainderValue = oneDay;
  4111. }
  4112. else if (type === "时") {
  4113. remainderValue = oneHour;
  4114. }
  4115. else if (type === "分") {
  4116. remainderValue = oneMinute;
  4117. }
  4118. else if (type === "秒") {
  4119. remainderValue = oneSecond;
  4120. }
  4121. let diffValue = Math.round(Math.abs((bigDate - smallDate) / remainderValue));
  4122. if (type === "auto") {
  4123. let timeDifference = bigTimeStamp - smallTimeStamp;
  4124. diffValue = Math.floor(timeDifference / (24 * 3600 * 1000));
  4125. if (diffValue > 0) {
  4126. diffValue = diffValue + "天";
  4127. }
  4128. else {
  4129. /* 计算出小时数 */
  4130. let leave1 = timeDifference % (24 * 3600 * 1000); /* 计算天数后剩余的毫秒数 */
  4131. let hours = Math.floor(leave1 / (3600 * 1000));
  4132. if (hours > 0) {
  4133. diffValue = hours + "小时";
  4134. }
  4135. else {
  4136. /* 计算相差分钟数 */
  4137. let leave2 = leave1 % (3600 * 1000); /* 计算小时数后剩余的毫秒数 */
  4138. let minutes = Math.floor(leave2 / (60 * 1000));
  4139. if (minutes > 0) {
  4140. diffValue = minutes + "分钟";
  4141. }
  4142. else {
  4143. /* 计算相差秒数 */
  4144. let leave3 = leave2 % (60 * 1000); /* 计算分钟数后剩余的毫秒数 */
  4145. let seconds = Math.round(leave3 / 1000);
  4146. diffValue = seconds + "秒";
  4147. }
  4148. }
  4149. }
  4150. }
  4151. return diffValue;
  4152. }
  4153. getElementSelector(element) {
  4154. let UtilsContext = this;
  4155. // @ts-ignore
  4156. if (!element)
  4157. return;
  4158. // @ts-ignore
  4159. if (!element.parentElement)
  4160. return;
  4161. /* 如果元素有id属性,则直接返回id选择器 */
  4162. if (element.id)
  4163. return "#" + element.id;
  4164. /* 递归地获取父元素的选择器 */
  4165. let selector = UtilsContext.getElementSelector(element.parentElement);
  4166. if (!selector) {
  4167. return element.tagName.toLowerCase();
  4168. }
  4169. /* 如果有多个相同类型的兄弟元素,则需要添加索引 */
  4170. if (element.parentElement.querySelectorAll(element.tagName).length > 1) {
  4171. let index = Array.prototype.indexOf.call(element.parentElement.children, element) +
  4172. 1;
  4173. selector +=
  4174. " > " + element.tagName.toLowerCase() + ":nth-child(" + index + ")";
  4175. }
  4176. else {
  4177. selector += " > " + element.tagName.toLowerCase();
  4178. }
  4179. return selector;
  4180. }
  4181. /**
  4182. * 获取最大值
  4183. * @example
  4184. * Utils.getMaxValue([{1:123},{2:345},{3:456}],(index,value)=>{return parseInt(index)})
  4185. * > 2
  4186. */
  4187. getMaxValue(...args) {
  4188. let result = [...args];
  4189. let newResult = [];
  4190. if (result.length === 0) {
  4191. // @ts-ignore
  4192. return;
  4193. }
  4194. if (result.length > 1) {
  4195. if (result.length === 2 &&
  4196. typeof result[0] === "object" &&
  4197. typeof result[1] === "function") {
  4198. let data = result[0];
  4199. let handleDataFunc = result[1];
  4200. Object.keys(data).forEach((keyName) => {
  4201. newResult = [...newResult, handleDataFunc(keyName, data[keyName])];
  4202. });
  4203. }
  4204. else {
  4205. result.forEach((item) => {
  4206. if (!isNaN(parseFloat(item))) {
  4207. newResult = [...newResult, parseFloat(item)];
  4208. }
  4209. });
  4210. }
  4211. return Math.max(...newResult);
  4212. }
  4213. else {
  4214. result[0].forEach((item) => {
  4215. if (!isNaN(parseFloat(item))) {
  4216. newResult = [...newResult, parseFloat(item)];
  4217. }
  4218. });
  4219. return Math.max(...newResult);
  4220. }
  4221. }
  4222. getMaxZIndex(deviation = 1) {
  4223. deviation = Number.isNaN(deviation) ? 1 : deviation;
  4224. // 最大值2147483647
  4225. let maxZIndex = Math.pow(2, 31) - 1;
  4226. // 比较值2000000000
  4227. let maxZIndexCompare = 2 * Math.pow(10, 9);
  4228. // 当前页面最大的z-index
  4229. let zIndex = 0;
  4230. UtilsCore.document.querySelectorAll("*").forEach(($ele, index) => {
  4231. let nodeStyle = UtilsCore.window.getComputedStyle($ele);
  4232. /* 不对position为static和display为none的元素进行获取它们的z-index */
  4233. if (nodeStyle.position !== "static" && nodeStyle.display !== "none") {
  4234. let nodeZIndex = parseInt(nodeStyle.zIndex);
  4235. if (!isNaN(nodeZIndex)) {
  4236. if (nodeZIndex > zIndex) {
  4237. zIndex = nodeZIndex;
  4238. }
  4239. }
  4240. }
  4241. });
  4242. zIndex += deviation;
  4243. if (zIndex >= maxZIndexCompare) {
  4244. // 最好不要超过最大值
  4245. zIndex = maxZIndex;
  4246. }
  4247. return zIndex;
  4248. }
  4249. getMinValue(...args) {
  4250. let result = [...args];
  4251. let newResult = [];
  4252. if (result.length === 0) {
  4253. // @ts-ignore
  4254. return;
  4255. }
  4256. if (result.length > 1) {
  4257. if (result.length === 2 &&
  4258. typeof result[0] === "object" &&
  4259. typeof result[1] === "function") {
  4260. let data = result[0];
  4261. let handleDataFunc = result[1];
  4262. Object.keys(data).forEach((keyName) => {
  4263. newResult = [...newResult, handleDataFunc(keyName, data[keyName])];
  4264. });
  4265. }
  4266. else {
  4267. result.forEach((item) => {
  4268. if (!isNaN(parseFloat(item))) {
  4269. newResult = [...newResult, parseFloat(item)];
  4270. }
  4271. });
  4272. }
  4273. return Math.min(...newResult);
  4274. }
  4275. else {
  4276. result[0].forEach((item) => {
  4277. if (!isNaN(parseFloat(item))) {
  4278. newResult = [...newResult, parseFloat(item)];
  4279. }
  4280. });
  4281. return Math.min(...newResult);
  4282. }
  4283. }
  4284. getRandomAndroidUA() {
  4285. let UtilsContext = this;
  4286. let mobileNameList = [
  4287. "LDN-LX3",
  4288. "RNE-L03",
  4289. "ASUS_X00ID Build/NMF26F",
  4290. "WAS-LX3",
  4291. "PRA-LX3",
  4292. "MYA-L03",
  4293. "Moto G Play",
  4294. "Moto C Build/NRD90M.063",
  4295. "Redmi Note 4 Build/NRD90M",
  4296. "HUAWEI VNS-L21 Build/HUAWEIVNS-L21",
  4297. "VTR-L09",
  4298. "TRT-LX3",
  4299. "M2003J15SC Build/RP1A.200720.011; wv",
  4300. "MI 13 Build/OPR1.170623.027; wv",
  4301. ];
  4302. let androidVersion = UtilsContext.getRandomValue(12, 14);
  4303. let randomMobile = UtilsContext.getRandomValue(mobileNameList);
  4304. let chromeVersion1 = UtilsContext.getRandomValue(115, 127);
  4305. let chromeVersion2 = UtilsContext.getRandomValue(0, 0);
  4306. let chromeVersion3 = UtilsContext.getRandomValue(2272, 6099);
  4307. let chromeVersion4 = UtilsContext.getRandomValue(1, 218);
  4308. return `Mozilla/5.0 (Linux; Android ${androidVersion}; ${randomMobile}) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/${chromeVersion1}.${chromeVersion2}.${chromeVersion3}.${chromeVersion4} Mobile Safari/537.36`;
  4309. }
  4310. getRandomValue(...args) {
  4311. let result = [...args];
  4312. if (result.length > 1) {
  4313. if (result.length === 2 &&
  4314. typeof result[0] === "number" &&
  4315. typeof result[1] === "number") {
  4316. let leftNumber = result[0] > result[1] ? result[1] : result[0];
  4317. let rightNumber = result[0] > result[1] ? result[0] : result[1];
  4318. return (Math.round(Math.random() * (rightNumber - leftNumber)) + leftNumber);
  4319. }
  4320. else {
  4321. return result[Math.floor(Math.random() * result.length)];
  4322. }
  4323. }
  4324. else if (result.length === 1) {
  4325. let paramData = result[0];
  4326. if (Array.isArray(paramData)) {
  4327. return paramData[Math.floor(Math.random() * paramData.length)];
  4328. }
  4329. else if (typeof paramData === "object" &&
  4330. Object.keys(paramData).length > 0) {
  4331. let paramObjDataKey = Object.keys(paramData)[Math.floor(Math.random() * Object.keys(paramData).length)];
  4332. return paramData[paramObjDataKey];
  4333. }
  4334. else {
  4335. return paramData;
  4336. }
  4337. }
  4338. }
  4339. /**
  4340. * 获取随机的电脑端User-Agent
  4341. * + Mozilla/5.0:以前用于Netscape浏览器,目前大多数浏览器UA都会带有
  4342. * + Windows NT 13:代表Window11系统
  4343. * + Windows NT 10.0:代表Window10系统
  4344. * + Windows NT 6.1:代表windows7系统
  4345. * + WOW64:Windows-on-Windows 64-bit,32位的应用程序运行于此64位处理器上
  4346. * + Win64:64位
  4347. * + AppleWebKit/537.36:浏览器内核
  4348. * + KHTML:HTML排版引擎
  4349. * + like Gecko:这不是Geckeo 浏览器,但是运行起来像Geckeo浏览器
  4350. * + Chrome/106.0.5068.19:Chrome版本号
  4351. * + Safari/537.36:宣称自己是Safari?
  4352. * @returns 返回随机字符串
  4353. * @example
  4354. * Utils.getRandomPCUA();
  4355. * > 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.5068.19 Safari/537.36'
  4356. **/
  4357. getRandomPCUA() {
  4358. let UtilsContext = this;
  4359. let chromeVersion1 = UtilsContext.getRandomValue(115, 127);
  4360. let chromeVersion2 = UtilsContext.getRandomValue(0, 0);
  4361. let chromeVersion3 = UtilsContext.getRandomValue(2272, 6099);
  4362. let chromeVersion4 = UtilsContext.getRandomValue(1, 218);
  4363. return `Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/${chromeVersion1}.${chromeVersion2}.${chromeVersion3}.${chromeVersion4} Safari/537.36`;
  4364. }
  4365. /**
  4366. * 获取元素上的使用React框架的实例属性,目前包括reactFiber、reactProps、reactEvents、reactEventHandlers、reactInternalInstance
  4367. * @param element 需要获取的目标元素
  4368. * @returns
  4369. * @example
  4370. * Utils.getReactObj(document.querySelector("input"))?.reactProps?.onChange({target:{value:"123"}});
  4371. */
  4372. getReactObj(element) {
  4373. let result = {};
  4374. Object.keys(element).forEach((domPropsName) => {
  4375. if (domPropsName.startsWith("__react")) {
  4376. let propsName = domPropsName.replace(/__(.+)\$.+/i, "$1");
  4377. if (propsName in result) ;
  4378. else {
  4379. result[propsName] = element[domPropsName];
  4380. }
  4381. }
  4382. });
  4383. return result;
  4384. }
  4385. /**
  4386. * 获取对象上的Symbol属性,如果没设置keyName,那么返回一个对象,对象是所有遍历到的Symbol对象
  4387. * @param target 目标对象
  4388. * @param keyName (可选)Symbol名或者Symbol对象
  4389. */
  4390. getSymbol(target, keyName) {
  4391. if (typeof target !== "object") {
  4392. throw new TypeError("target不是一个对象");
  4393. }
  4394. let objectsSymbols = Object.getOwnPropertySymbols(target);
  4395. if (typeof keyName === "string") {
  4396. let findSymbol = objectsSymbols.find((key) => {
  4397. return key.toString() === keyName;
  4398. });
  4399. if (findSymbol) {
  4400. return target[findSymbol];
  4401. }
  4402. }
  4403. else if (typeof keyName === "symbol") {
  4404. let findSymbol = objectsSymbols.find((key) => {
  4405. return key === keyName;
  4406. });
  4407. if (findSymbol) {
  4408. return target[findSymbol];
  4409. }
  4410. }
  4411. else {
  4412. let result = {};
  4413. objectsSymbols.forEach((item) => {
  4414. result[item] = target[item];
  4415. });
  4416. return result;
  4417. }
  4418. }
  4419. /**
  4420. * 获取文本的字符长度
  4421. * @param text
  4422. * @example
  4423. * Utils.getTextLength("测试文本")
  4424. * > 12
  4425. */
  4426. getTextLength(text) {
  4427. let encoder = new TextEncoder();
  4428. let bytes = encoder.encode(text);
  4429. return bytes.length;
  4430. }
  4431. getTextStorageSize(text, addType = true) {
  4432. let UtilsContext = this;
  4433. return UtilsContext.formatByteToSize(UtilsContext.getTextLength(text), addType);
  4434. }
  4435. getThunderUrl(url) {
  4436. if (url == null) {
  4437. throw new TypeError("url不能为空");
  4438. }
  4439. if (typeof url !== "string") {
  4440. throw new TypeError("url必须是string类型");
  4441. }
  4442. if (url.trim() === "") {
  4443. throw new TypeError("url不能为空字符串或纯空格");
  4444. }
  4445. return `thunder://${UtilsCore.globalThis.btoa("AA" + url + "ZZ")}`;
  4446. }
  4447. /**
  4448. * 对于GM_cookie的兼容写法,当无法使用GM_cookie时可以使用这个,但是并不完全兼容,有些写不出来且限制了httponly是无法访问的
  4449. * @example
  4450. let GM_cookie = new Utils.GM_Cookie();
  4451. GM_cookie.list({name:"xxx_cookie_xxx"},function(cookies,error){
  4452. if (!error) {
  4453. console.log(cookies);
  4454. console.log(cookies.value);
  4455. } else {
  4456. console.error(error);
  4457. }
  4458. });
  4459. GM_cookie.set({name:"xxx_cookie_test_xxx",value:"这是Cookie测试值"},function(error){
  4460. if (error) {
  4461. console.error(error);
  4462. } else {
  4463. console.log('Cookie set successfully.');
  4464. }
  4465. })
  4466. GM_cookie.delete({name:"xxx_cookie_test_xxx"},function(error){
  4467. if (error) {
  4468. console.error(error);
  4469. } else {
  4470. console.log('Cookie set successfully.');
  4471. }
  4472. })
  4473. **/
  4474. GM_Cookie = UtilsGMCookie;
  4475. /**
  4476. * 注册(不可用)油猴菜单,要求本地存储的键名不能存在其它键名`GM_Menu_Local_Map`会冲突/覆盖
  4477. * @example
  4478. let GM_Menu = new Utils.GM_Menu({
  4479. data: [
  4480. {
  4481. menu_key: "menu_key",
  4482. text: "测试按钮",
  4483. enable: true,
  4484. accessKey: "a",
  4485. autoClose: false,
  4486. showText(text, enable) {
  4487. return "[" + (enable ? "√" : "×") + "]" + text;
  4488. },
  4489. callback(data) {
  4490. console.log("点击菜单,值修改为", data.enable);
  4491. },
  4492. },
  4493. ],
  4494. autoReload: false,
  4495. GM_getValue,
  4496. GM_setValue,
  4497. GM_registerMenuCommand,
  4498. GM_unregisterMenuCommand,
  4499. });
  4500. // 获取某个菜单项的值
  4501. GM_Menu.get("menu_key");
  4502. > true
  4503. // 获取某个菜单项的开启/关闭后显示的文本
  4504. GM_Menu.getShowTextValue("menu_key");
  4505. > √测试按钮
  4506. // 添加键为menu_key2的菜单项
  4507. GM_Menu.add({
  4508. key:"menu_key2",
  4509. text: "测试按钮2",
  4510. enable: false,
  4511. showText(text,enable){
  4512. return "[" + (enable ? "√" : "×") + "]" + text;
  4513. },
  4514. callback(data){
  4515. console.log("点击菜单,值修改为",data.enable);
  4516. }
  4517. });
  4518. // 使用数组的方式添加多个菜单,如menu_key3、menu_key4
  4519. GM_Menu.add([
  4520. {
  4521. key:"menu_key3",
  4522. text: "测试按钮3",
  4523. enable: false,
  4524. showText(text,enable){
  4525. return "[" + (enable ? "√" : "×") + "]" + text;
  4526. },
  4527. callback(data){
  4528. console.log("点击菜单,值修改为",data.enable);
  4529. }
  4530. },
  4531. {
  4532. key:"menu_key4",
  4533. text: "测试按钮4",
  4534. enable: false,
  4535. showText(text,enable){
  4536. return "[" + (enable ? "√" : "×") + "]" + text;
  4537. },
  4538. callback(data){
  4539. console.log("点击菜单,值修改为",data.enable);
  4540. }
  4541. }
  4542. ]);
  4543. // 更新键为menu_key的显示文字和点击回调
  4544. GM_Menu.update({
  4545. menu_key:{
  4546. text: "更新后的测试按钮",
  4547. enable: true,
  4548. showText(text,enable){
  4549. return "[" + (enable ? "√" : "×") + "]" + text;
  4550. },
  4551. callback(data){
  4552. console.log("点击菜单更新后的测试按钮,新值修改为",data.enable);
  4553. }
  4554. }
  4555. });
  4556. // 删除键为menu_key的菜单
  4557. GM_Menu.delete("menu_key");
  4558. **/
  4559. GM_Menu = GMMenu;
  4560. /**
  4561. * 基于Function prototype,能够勾住和释放任何函数
  4562. *
  4563. * .hook
  4564. * + realFunc {string} 用于保存原始函数的函数名称,用于unHook
  4565. * + hookFunc {string} 替换的hook函数
  4566. * + context {object} 目标函数所在对象,用于hook非window对象下的函数,如String.protype.slice,carInstance1
  4567. * + methodName {string} 匿名函数需显式传入目标函数名eg:this.Begin = function(){....};}
  4568. *
  4569. * .unhook
  4570. * + realFunc {string} 用于保存原始函数的函数名称,用于unHook
  4571. * + funcName {string} 被Hook的函数名称
  4572. * + context {object} 目标函数所在对象,用于hook非window对象下的函数,如String.protype.slice,carInstance1
  4573. * @example
  4574. let hook = new Utils.Hooks();
  4575. hook.initEnv();
  4576. function myFunction(){
  4577. console.log("我自己需要执行的函数");
  4578. }
  4579. function testFunction(){
  4580. console.log("正常执行的函数");
  4581. }
  4582. testFunction.hook(testFunction,myFunction,window);
  4583. **/
  4584. Hooks = Hooks;
  4585. /**
  4586. * 为减少代码量和回调,把GM_xmlhttpRequest封装
  4587. * 文档地址: https://www.tampermonkey.net/documentation.php?ext=iikm
  4588. * 其中onloadstart、onprogress、onreadystatechange是回调形式,onabort、ontimeout、onerror可以设置全局回调函数
  4589. * @param _GM_xmlHttpRequest_ 油猴中的GM_xmlhttpRequest
  4590. * @example
  4591. let httpx = new Utils.Httpx(GM_xmlhttpRequest);
  4592. let postResp = await httpx.post({
  4593. url:url,
  4594. data:JSON.stringify({
  4595. test:1
  4596. }),
  4597. timeout: 5000
  4598. });
  4599. console.log(postResp);
  4600. > {
  4601. status: true,
  4602. data: {responseText: "...", response: xxx,...},
  4603. msg: "请求完毕",
  4604. type: "onload",
  4605. }
  4606. if(postResp === "onload" && postResp.status){
  4607. // onload
  4608. }else if(postResp === "ontimeout"){
  4609. // ontimeout
  4610. }
  4611. * @example
  4612. // 也可以先配置全局参数
  4613. let httpx = new Utils.Httpx(GM_xmlhttpRequest);
  4614. httpx.config({
  4615. timeout: 5000,
  4616. async: false,
  4617. responseType: "html",
  4618. redirect: "follow",
  4619. })
  4620. // 优先级为 默认details < 全局details < 单独的details
  4621. */
  4622. Httpx = Httpx;
  4623. /**
  4624. * 浏览器端的indexedDB操作封装
  4625. * @example
  4626. let db = new Utils.indexedDB('web_DB', 'nav_text')
  4627. let data = {name:'管理员', roleId: 1, type: 1};
  4628. db.save('list',data).then((resolve)=>{
  4629. console.log(resolve,'存储成功')
  4630. })
  4631. db.get('list').then((resolve)=>{
  4632. console.log(resolve,'查询成功')
  4633. })
  4634. db.getPaging('list',20,10).then((resolve)=>{
  4635. console.log(resolve,'查询分页偏移第20,一共10行成功');
  4636. })
  4637. db.delete('list').then(resolve=>{
  4638. console.log(resolve,'删除成功---->>>>>>name')
  4639. })
  4640. db.deleteAll().then(resolve=>{
  4641. console.log(resolve,'清除数据库---->>>>>>name')
  4642. })
  4643. **/
  4644. indexedDB = indexedDB;
  4645. isNativeFunc(target) {
  4646. return Boolean(target.toString().match(/^function .*\(\) { \[native code\] }$/));
  4647. }
  4648. isNearBottom(nearValue = 50) {
  4649. var scrollTop = UtilsCore.window.pageYOffset ||
  4650. UtilsCore.document.documentElement.scrollTop;
  4651. var windowHeight = UtilsCore.window.innerHeight ||
  4652. UtilsCore.document.documentElement.clientHeight;
  4653. var documentHeight = UtilsCore.document.documentElement.scrollHeight;
  4654. return scrollTop + windowHeight >= documentHeight - nearValue;
  4655. }
  4656. isDOM(target) {
  4657. return target instanceof Node;
  4658. }
  4659. isFullscreenEnabled() {
  4660. return !!(UtilsCore.document.fullscreenEnabled ||
  4661. UtilsCore.document.webkitFullScreenEnabled ||
  4662. UtilsCore.document.mozFullScreenEnabled ||
  4663. UtilsCore.document.msFullScreenEnabled);
  4664. }
  4665. isJQuery(target) {
  4666. let result = false;
  4667. // @ts-ignore
  4668. if (typeof jQuery === "object" && target instanceof jQuery) {
  4669. result = true;
  4670. }
  4671. if (target == null) {
  4672. return false;
  4673. }
  4674. if (typeof target === "object") {
  4675. /* 也有种可能,这个jQuery对象是1.8.3版本的,页面中的jQuery是3.4.1版本的 */
  4676. let jQueryProps = [
  4677. "add",
  4678. "addBack",
  4679. "addClass",
  4680. "after",
  4681. "ajaxComplete",
  4682. "ajaxError",
  4683. "ajaxSend",
  4684. "ajaxStart",
  4685. "ajaxStop",
  4686. "ajaxSuccess",
  4687. "animate",
  4688. "append",
  4689. "appendTo",
  4690. "attr",
  4691. "before",
  4692. "bind",
  4693. "blur",
  4694. "change",
  4695. "children",
  4696. "clearQueue",
  4697. "click",
  4698. "clone",
  4699. "closest",
  4700. "constructor",
  4701. "contents",
  4702. "contextmenu",
  4703. "css",
  4704. "data",
  4705. "dblclick",
  4706. "delay",
  4707. "delegate",
  4708. "dequeue",
  4709. "each",
  4710. "empty",
  4711. "end",
  4712. "eq",
  4713. "extend",
  4714. "fadeIn",
  4715. "fadeOut",
  4716. "fadeTo",
  4717. "fadeToggle",
  4718. "filter",
  4719. "find",
  4720. "first",
  4721. "focus",
  4722. "focusin",
  4723. "focusout",
  4724. "get",
  4725. "has",
  4726. "hasClass",
  4727. "height",
  4728. "hide",
  4729. "hover",
  4730. "html",
  4731. "index",
  4732. "init",
  4733. "innerHeight",
  4734. "innerWidth",
  4735. "insertAfter",
  4736. "insertBefore",
  4737. "is",
  4738. "jquery",
  4739. "keydown",
  4740. "keypress",
  4741. "keyup",
  4742. "last",
  4743. "load",
  4744. "map",
  4745. "mousedown",
  4746. "mouseenter",
  4747. "mouseleave",
  4748. "mousemove",
  4749. "mouseout",
  4750. "mouseover",
  4751. "mouseup",
  4752. "next",
  4753. "nextAll",
  4754. "not",
  4755. "off",
  4756. "offset",
  4757. "offsetParent",
  4758. "on",
  4759. "one",
  4760. "outerHeight",
  4761. "outerWidth",
  4762. "parent",
  4763. "parents",
  4764. "position",
  4765. "prepend",
  4766. "prependTo",
  4767. "prev",
  4768. "prevAll",
  4769. "prevUntil",
  4770. "promise",
  4771. "prop",
  4772. "pushStack",
  4773. "queue",
  4774. "ready",
  4775. "remove",
  4776. "removeAttr",
  4777. "removeClass",
  4778. "removeData",
  4779. "removeProp",
  4780. "replaceAll",
  4781. "replaceWith",
  4782. "resize",
  4783. "scroll",
  4784. "scrollLeft",
  4785. "scrollTop",
  4786. "select",
  4787. "show",
  4788. "siblings",
  4789. "slice",
  4790. "slideDown",
  4791. "slideToggle",
  4792. "slideUp",
  4793. "sort",
  4794. "splice",
  4795. "text",
  4796. "toArray",
  4797. "toggle",
  4798. "toggleClass",
  4799. "trigger",
  4800. "triggerHandler",
  4801. "unbind",
  4802. "width",
  4803. "wrap",
  4804. ];
  4805. for (const jQueryPropsName of jQueryProps) {
  4806. if (!(jQueryPropsName in target)) {
  4807. result = false;
  4808. /* console.log(jQueryPropsName); */
  4809. break;
  4810. }
  4811. else {
  4812. result = true;
  4813. }
  4814. }
  4815. }
  4816. return result;
  4817. }
  4818. isPhone(userAgent = navigator.userAgent) {
  4819. return Boolean(/(iPhone|iPad|iPod|iOS|Android|Mobile)/i.test(userAgent));
  4820. }
  4821. isSameChars(targetStr, coefficient = 1) {
  4822. if (typeof targetStr !== "string") {
  4823. throw new TypeError("参数 str 必须是 string 类型");
  4824. }
  4825. if (targetStr.length < 2) {
  4826. return false;
  4827. }
  4828. targetStr = targetStr.toLowerCase();
  4829. const targetCharMap = {};
  4830. let targetStrLength = 0;
  4831. for (const char of targetStr) {
  4832. if (Reflect.has(targetCharMap, char)) {
  4833. targetCharMap[char]++;
  4834. }
  4835. else {
  4836. targetCharMap[char] = 1;
  4837. }
  4838. targetStrLength++;
  4839. }
  4840. let result = false;
  4841. for (const char in targetCharMap) {
  4842. if (targetCharMap[char] / targetStrLength >= coefficient) {
  4843. result = true;
  4844. break;
  4845. }
  4846. }
  4847. return result;
  4848. }
  4849. isNotNull(...args) {
  4850. let UtilsContext = this;
  4851. return !UtilsContext.isNull.apply(this, args);
  4852. }
  4853. isNull(...args) {
  4854. let result = true;
  4855. let checkList = [...args];
  4856. for (const objItem of checkList) {
  4857. let itemResult = false;
  4858. if (objItem === null || objItem === undefined) {
  4859. itemResult = true;
  4860. }
  4861. else {
  4862. switch (typeof objItem) {
  4863. case "object":
  4864. if (typeof objItem[Symbol.iterator] === "function") {
  4865. /* 可迭代 */
  4866. itemResult = objItem.length === 0;
  4867. }
  4868. else {
  4869. itemResult = Object.keys(objItem).length === 0;
  4870. }
  4871. break;
  4872. case "number":
  4873. itemResult = objItem === 0;
  4874. break;
  4875. case "string":
  4876. itemResult =
  4877. objItem.trim() === "" ||
  4878. objItem === "null" ||
  4879. objItem === "undefined";
  4880. break;
  4881. case "boolean":
  4882. itemResult = !objItem;
  4883. break;
  4884. case "function":
  4885. let funcStr = objItem.toString().replace(/\s/g, "");
  4886. /* 排除()=>{}、(xxx="")=>{}、function(){}、function(xxx=""){} */
  4887. itemResult = Boolean(funcStr.match(/^\(.*?\)=>\{\}$|^function.*?\(.*?\)\{\}$/));
  4888. break;
  4889. }
  4890. }
  4891. result = result && itemResult;
  4892. }
  4893. return result;
  4894. }
  4895. isThemeDark() {
  4896. return UtilsCore.globalThis.matchMedia("(prefers-color-scheme: dark)")
  4897. .matches;
  4898. }
  4899. isVisible(element, inView = false) {
  4900. let needCheckDomList = [];
  4901. if (element instanceof Array || element instanceof NodeList) {
  4902. element = element;
  4903. needCheckDomList = [...element];
  4904. }
  4905. else {
  4906. needCheckDomList = [element];
  4907. }
  4908. let result = true;
  4909. for (const domItem of needCheckDomList) {
  4910. let domDisplay = UtilsCore.window.getComputedStyle(domItem);
  4911. if (domDisplay.display === "none") {
  4912. result = false;
  4913. }
  4914. else {
  4915. let domClientRect = domItem.getBoundingClientRect();
  4916. if (inView) {
  4917. let viewportWidth = UtilsCore.window.innerWidth ||
  4918. UtilsCore.document.documentElement.clientWidth;
  4919. let viewportHeight = UtilsCore.window.innerHeight ||
  4920. UtilsCore.document.documentElement.clientHeight;
  4921. result = !(domClientRect.right < 0 ||
  4922. domClientRect.left > viewportWidth ||
  4923. domClientRect.bottom < 0 ||
  4924. domClientRect.top > viewportHeight);
  4925. }
  4926. else {
  4927. result = Boolean(domItem.getClientRects().length);
  4928. }
  4929. }
  4930. if (!result) {
  4931. /* 有一个不可见就退出循环 */
  4932. break;
  4933. }
  4934. }
  4935. return result;
  4936. }
  4937. isWebView_Via() {
  4938. let result = true;
  4939. let UtilsContext = this;
  4940. if (typeof UtilsCore.top.window.via === "object") {
  4941. for (const key in Object.values(UtilsCore.top.window.via)) {
  4942. if (Reflect.has(UtilsCore.top.window.via, key)) {
  4943. let objValueFunc = UtilsCore.top.window.via[key];
  4944. if (typeof objValueFunc === "function" &&
  4945. UtilsContext.isNativeFunc(objValueFunc)) {
  4946. result = true;
  4947. }
  4948. else {
  4949. result = false;
  4950. break;
  4951. }
  4952. }
  4953. }
  4954. }
  4955. else {
  4956. result = false;
  4957. }
  4958. return result;
  4959. }
  4960. isWebView_X() {
  4961. let result = true;
  4962. let UtilsContext = this;
  4963. if (typeof UtilsCore.top.window.mbrowser === "object") {
  4964. for (const key in Object.values(UtilsCore.top.window.mbrowser)) {
  4965. if (Reflect.has(UtilsCore.top.window.mbrowser, key)) {
  4966. let objValueFunc = UtilsCore.top.window.mbrowser[key];
  4967. if (typeof objValueFunc === "function" &&
  4968. UtilsContext.isNativeFunc(objValueFunc)) {
  4969. result = true;
  4970. }
  4971. else {
  4972. result = false;
  4973. break;
  4974. }
  4975. }
  4976. }
  4977. }
  4978. else {
  4979. result = false;
  4980. }
  4981. return result;
  4982. }
  4983. parseObjectToArray(target) {
  4984. if (typeof target !== "object") {
  4985. throw new Error("Utils.parseObjectToArray 参数 target 必须为 object 类型");
  4986. }
  4987. let result = [];
  4988. Object.keys(target).forEach(function (keyName) {
  4989. result = result.concat(target[keyName]);
  4990. });
  4991. return result;
  4992. }
  4993. listenKeyboard(target, eventName = "keypress", callback) {
  4994. if (typeof target !== "object" ||
  4995. (typeof target["addEventListener"] !== "function" &&
  4996. typeof target["removeEventListener"] !== "function")) {
  4997. throw new Error("Utils.listenKeyboard 参数 target 必须为 Window|HTMLElement 类型");
  4998. }
  4999. let keyEvent = function (event) {
  5000. let keyName = event.key || event.code;
  5001. let keyValue = event.charCode || event.keyCode || event.which;
  5002. let otherCodeList = [];
  5003. if (event.ctrlKey) {
  5004. otherCodeList.push("ctrl");
  5005. }
  5006. if (event.altKey) {
  5007. otherCodeList.push("alt");
  5008. }
  5009. if (event.metaKey) {
  5010. otherCodeList.push("meta");
  5011. }
  5012. if (event.shiftKey) {
  5013. otherCodeList.push("shift");
  5014. }
  5015. if (typeof callback === "function") {
  5016. callback(keyName, keyValue.toString(), otherCodeList, event);
  5017. }
  5018. };
  5019. target.addEventListener(eventName, keyEvent);
  5020. return {
  5021. removeListen() {
  5022. target.removeEventListener(eventName, keyEvent);
  5023. },
  5024. };
  5025. }
  5026. /**
  5027. * 自动锁对象,用于循环判断运行的函数,在循环外new后使用,注意,如果函数内部存在异步操作,需要使用await
  5028. * @example
  5029. let lock = new Utils.LockFunction(()=>{console.log(1)}))
  5030. lock.run();
  5031. > 1
  5032. * @example
  5033. let lock = new Utils.LockFunction(()=>{console.log(1)}),true) -- 异步操作
  5034. await lock.run();
  5035. > 1
  5036. **/
  5037. LockFunction = LockFunction;
  5038. /**
  5039. * 日志对象
  5040. * @param _GM_info_ 油猴管理器的API GM_info,或者是一个对象,如{"script":{name:"Utils.Log"}}
  5041. * @example
  5042. let log = new Utils.Log(GM_info);
  5043. log.info("普通输出");
  5044. > 普通输出
  5045. log.success("成功输出");
  5046. > 成功输出
  5047. log.error("错误输出");
  5048. > 错误输出
  5049. log.warn("警告输出");
  5050. > 警告输出
  5051. log.tag = "自定义tag信息";
  5052. log.info("自定义info的颜色","#e0e0e0");
  5053. > 自定义info的颜色
  5054. log.config({
  5055. successColor: "#31dc02",
  5056. errorColor: "#e02d2d",
  5057. infoColor: "black",
  5058. })
  5059. log.success("颜色为#31dc02");
  5060. > 颜色为#31dc02
  5061. */
  5062. Log = Log;
  5063. mergeArrayToString(data, handleFunc) {
  5064. if (!(data instanceof Array)) {
  5065. throw new Error("Utils.mergeArrayToString 参数 data 必须为 Array 类型");
  5066. }
  5067. let content = "";
  5068. if (typeof handleFunc === "function") {
  5069. data.forEach((item) => {
  5070. content += handleFunc(item);
  5071. });
  5072. }
  5073. else if (typeof handleFunc === "string") {
  5074. data.forEach((item) => {
  5075. content += item[handleFunc];
  5076. });
  5077. }
  5078. else {
  5079. data.forEach((item) => {
  5080. Object.values(item)
  5081. .filter((item2) => typeof item2 === "string")
  5082. .forEach((item3) => {
  5083. content += item3;
  5084. });
  5085. });
  5086. }
  5087. return content;
  5088. }
  5089. mutationObserver(target, observer_config) {
  5090. let UtilsContext = this;
  5091. let default_obverser_config = {
  5092. /* 监听到元素有反馈,需执行的函数 */
  5093. callback: () => { },
  5094. config: {
  5095. /**
  5096. * + true 监听以 target 为根节点的整个子树。包括子树中所有节点的属性,而不仅仅是针对 target
  5097. * + false (默认) 不生效
  5098. */
  5099. subtree: void 0,
  5100. /**
  5101. * + true 监听 target 节点中发生的节点的新增与删除(同时,如果 subtree 为 true,会针对整个子树生效)
  5102. * + false (默认) 不生效
  5103. */
  5104. childList: void 0,
  5105. /**
  5106. * + true 观察所有监听的节点属性值的变化。默认值为 true,当声明了 attributeFilter 或 attributeOldValue
  5107. * + false (默认) 不生效
  5108. */
  5109. attributes: void 0,
  5110. /**
  5111. * 一个用于声明哪些属性名会被监听的数组。如果不声明该属性,所有属性的变化都将触发通知
  5112. */
  5113. attributeFilter: void 0,
  5114. /**
  5115. * + true 记录上一次被监听的节点的属性变化;可查阅 MutationObserver 中的 Monitoring attribute values 了解关于观察属性变化和属性值记录的详情
  5116. * + false (默认) 不生效
  5117. */
  5118. attributeOldValue: void 0,
  5119. /**
  5120. * + true 监听声明的 target 节点上所有字符的变化。默认值为 true,如果声明了 characterDataOldValue
  5121. * + false (默认) 不生效
  5122. */
  5123. characterData: void 0,
  5124. /**
  5125. * + true 记录前一个被监听的节点中发生的文本变化
  5126. * + false (默认) 不生效
  5127. */
  5128. characterDataOldValue: void 0,
  5129. },
  5130. immediate: false,
  5131. };
  5132. observer_config = UtilsContext.assign(default_obverser_config, observer_config);
  5133. let windowMutationObserver = UtilsCore.window.MutationObserver ||
  5134. UtilsCore.window.webkitMutationObserver ||
  5135. UtilsCore.window.MozMutationObserver;
  5136. // 观察者对象
  5137. let mutationObserver = new windowMutationObserver(function (mutations, observer) {
  5138. if (typeof observer_config.callback === "function") {
  5139. observer_config.callback(mutations, observer);
  5140. }
  5141. });
  5142. if (Array.isArray(target) || target instanceof NodeList) {
  5143. // 传入的是数组或者元素数组
  5144. target.forEach((item) => {
  5145. mutationObserver.observe(item, observer_config.config);
  5146. });
  5147. }
  5148. else if (UtilsContext.isJQuery(target)) {
  5149. /* 传入的参数是jQuery对象 */
  5150. target.each((index, item) => {
  5151. mutationObserver.observe(item, observer_config.config);
  5152. });
  5153. }
  5154. else {
  5155. mutationObserver.observe(target, observer_config.config);
  5156. }
  5157. if (observer_config.immediate) {
  5158. /* 主动触发一次 */
  5159. if (typeof observer_config.callback === "function") {
  5160. observer_config.callback([], mutationObserver);
  5161. }
  5162. }
  5163. return mutationObserver;
  5164. }
  5165. /**
  5166. * 去除全局window下的Utils,返回控制权
  5167. * @example
  5168. * let utils = Utils.noConflict();
  5169. * > ...
  5170. */
  5171. noConflict = function () {
  5172. if (UtilsCore.window.Utils) {
  5173. Reflect.deleteProperty(UtilsCore.window, "Utils");
  5174. }
  5175. UtilsCore.window.Utils = utils;
  5176. return utils;
  5177. };
  5178. noConflictFunc(needReleaseObject, needReleaseName, functionNameList = [], release = true) {
  5179. let UtilsContext = this;
  5180. if (typeof needReleaseObject !== "object") {
  5181. throw new Error("Utils.noConflictFunc 参数 needReleaseObject 必须为 object 类型");
  5182. }
  5183. if (typeof needReleaseName !== "string") {
  5184. throw new Error("Utils.noConflictFunc 参数 needReleaseName 必须为 string 类型");
  5185. }
  5186. if (!Array.isArray(functionNameList)) {
  5187. throw new Error("Utils.noConflictFunc 参数 functionNameList 必须为 Array 类型");
  5188. }
  5189. let needReleaseKey = "__" + needReleaseName;
  5190. /**
  5191. * 释放所有
  5192. */
  5193. function releaseAll() {
  5194. if (typeof UtilsCore.window[needReleaseKey] !== "undefined") {
  5195. /* 已存在 */
  5196. return;
  5197. }
  5198. UtilsCore.window[needReleaseKey] =
  5199. UtilsContext.deepClone(needReleaseObject);
  5200. Object.values(needReleaseObject).forEach((value) => {
  5201. if (typeof value === "function") {
  5202. needReleaseObject[value.name] = () => { };
  5203. }
  5204. });
  5205. }
  5206. /**
  5207. * 释放单个
  5208. */
  5209. function releaseOne() {
  5210. Array.from(functionNameList).forEach((item) => {
  5211. Object.values(needReleaseObject).forEach((value) => {
  5212. if (typeof value === "function") {
  5213. if (typeof UtilsCore.window[needReleaseKey] === "undefined") {
  5214. UtilsCore.window[needReleaseKey] = {};
  5215. }
  5216. if (item === value.name) {
  5217. UtilsCore.window[needReleaseKey][value.name] = needReleaseObject[value.name];
  5218. needReleaseObject[value.name] = () => { };
  5219. }
  5220. }
  5221. });
  5222. });
  5223. }
  5224. /**
  5225. * 恢复所有
  5226. */
  5227. function recoveryAll() {
  5228. if (typeof UtilsCore.window[needReleaseKey] === "undefined") {
  5229. /* 未存在 */
  5230. return;
  5231. }
  5232. Object.assign(needReleaseObject, UtilsCore.window[needReleaseKey]);
  5233. Reflect.deleteProperty(UtilsCore.window, "needReleaseKey");
  5234. }
  5235. /**
  5236. * 恢复单个
  5237. */
  5238. function recoveryOne() {
  5239. if (typeof UtilsCore.window[needReleaseKey] === "undefined") {
  5240. /* 未存在 */
  5241. return;
  5242. }
  5243. Array.from(functionNameList).forEach((item) => {
  5244. if (UtilsCore.window[needReleaseKey][item]) {
  5245. needReleaseObject[item] = UtilsCore.window[needReleaseKey][item];
  5246. Reflect.deleteProperty(UtilsCore.window[needReleaseKey], item);
  5247. if (Object.keys(UtilsCore.window[needReleaseKey]).length === 0) {
  5248. Reflect.deleteProperty(window, needReleaseKey);
  5249. }
  5250. }
  5251. });
  5252. }
  5253. if (release) {
  5254. /* 释放 */
  5255. if (functionNameList.length === 0) {
  5256. releaseAll();
  5257. }
  5258. else {
  5259. /* 对单个进行操作 */
  5260. releaseOne();
  5261. }
  5262. }
  5263. else {
  5264. /* 恢复 */
  5265. if (functionNameList.length === 0) {
  5266. recoveryAll();
  5267. }
  5268. else {
  5269. /* 对单个进行操作 */
  5270. recoveryOne();
  5271. }
  5272. }
  5273. }
  5274. parseBase64ToBlob(dataUri) {
  5275. if (typeof dataUri !== "string") {
  5276. throw new Error("Utils.parseBase64ToBlob 参数 dataUri 必须为 string 类型");
  5277. }
  5278. let dataUriSplit = dataUri.split(","), dataUriMime = dataUriSplit[0].match(/:(.*?);/)[1], dataUriBase64Str = atob(dataUriSplit[1]), dataUriLength = dataUriBase64Str.length, u8arr = new Uint8Array(dataUriLength);
  5279. while (dataUriLength--) {
  5280. u8arr[dataUriLength] = dataUriBase64Str.charCodeAt(dataUriLength);
  5281. }
  5282. return new Blob([u8arr], {
  5283. type: dataUriMime,
  5284. });
  5285. }
  5286. parseBase64ToFile(dataUri, fileName = "example") {
  5287. if (typeof dataUri !== "string") {
  5288. throw new Error("Utils.parseBase64ToFile 参数 dataUri 必须为 string 类型");
  5289. }
  5290. if (typeof fileName !== "string") {
  5291. throw new Error("Utils.parseBase64ToFile 参数 fileName 必须为 string 类型");
  5292. }
  5293. let dataUriSplit = dataUri.split(","), dataUriMime = dataUriSplit[0].match(/:(.*?);/)[1], dataUriBase64Str = atob(dataUriSplit[1]), dataUriLength = dataUriBase64Str.length, u8arr = new Uint8Array(dataUriLength);
  5294. while (dataUriLength--) {
  5295. u8arr[dataUriLength] = dataUriBase64Str.charCodeAt(dataUriLength);
  5296. }
  5297. return new File([u8arr], fileName, {
  5298. type: dataUriMime,
  5299. });
  5300. }
  5301. parseInt(matchList = [], defaultValue = 0) {
  5302. if (matchList == null) {
  5303. return parseInt(defaultValue.toString());
  5304. }
  5305. let parseValue = parseInt(matchList[matchList.length - 1]);
  5306. if (isNaN(parseValue)) {
  5307. parseValue = parseInt(defaultValue.toString());
  5308. }
  5309. return parseValue;
  5310. }
  5311. async parseBlobToFile(blobUrl, fileName = "example") {
  5312. return new Promise((resolve, reject) => {
  5313. fetch(blobUrl)
  5314. .then((response) => response.blob())
  5315. .then((blob) => {
  5316. const file = new File([blob], fileName, { type: blob.type });
  5317. resolve(file);
  5318. })
  5319. .catch((error) => {
  5320. console.error("Error:", error);
  5321. reject(error);
  5322. });
  5323. });
  5324. }
  5325. parseCDATA(text = "") {
  5326. let result = "";
  5327. let cdataRegexp = /<\!\[CDATA\[([\s\S]*)\]\]>/;
  5328. let cdataMatch = cdataRegexp.exec(text.trim());
  5329. if (cdataMatch && cdataMatch.length > 1) {
  5330. result = cdataMatch[cdataMatch.length - 1];
  5331. }
  5332. return result;
  5333. }
  5334. async parseFileToBase64(fileObj) {
  5335. let reader = new FileReader();
  5336. reader.readAsDataURL(fileObj);
  5337. return new Promise((resolve) => {
  5338. reader.onload = function (event) {
  5339. resolve(event.target.result);
  5340. };
  5341. });
  5342. }
  5343. parseFromString(text, mimeType = "text/html") {
  5344. let parser = new DOMParser();
  5345. return parser.parseFromString(text, mimeType);
  5346. }
  5347. parseStringToRegExpString(text) {
  5348. if (typeof text !== "string") {
  5349. throw new TypeError("string必须是字符串");
  5350. }
  5351. let regString = text.replace(/[.*+\-?^${}()|[\]\\]/g, "\\$&");
  5352. return regString;
  5353. }
  5354. preventEvent(element, eventNameList = [], capture) {
  5355. function stopEvent(event) {
  5356. /* 阻止事件的默认行为发生。例如,当点击一个链接时,浏览器会默认打开链接的URL */
  5357. event?.preventDefault();
  5358. /* 停止事件的传播,阻止它继续向更上层的元素冒泡,事件将不会再传播给其他的元素 */
  5359. event?.stopPropagation();
  5360. /* 阻止事件传播,并且还能阻止元素上的其他事件处理程序被触发 */
  5361. event?.stopImmediatePropagation();
  5362. return false;
  5363. }
  5364. if (arguments.length === 1) {
  5365. /* 直接阻止事件 */
  5366. return stopEvent(arguments[0]);
  5367. }
  5368. else {
  5369. /* 添加对应的事件来阻止触发 */
  5370. if (typeof eventNameList === "string") {
  5371. eventNameList = [eventNameList];
  5372. }
  5373. eventNameList.forEach((eventName) => {
  5374. element.addEventListener(eventName, stopEvent, {
  5375. capture: Boolean(capture),
  5376. });
  5377. });
  5378. }
  5379. }
  5380. /**
  5381. * 在canvas元素节点上绘制进度圆圈
  5382. * @example
  5383. let progress = new Utils.Process({canvasNode:document.querySelector("canvas")});
  5384. progress.draw();
  5385. * **/
  5386. Progress = Progress;
  5387. registerTrustClickEvent(isTrustValue = true, filter) {
  5388. function trustEvent(event) {
  5389. return new Proxy(event, {
  5390. get: function (target, property) {
  5391. if (property === "isTrusted") {
  5392. return isTrustValue;
  5393. }
  5394. else {
  5395. return Reflect.get(target, property);
  5396. }
  5397. },
  5398. });
  5399. }
  5400. if (filter == null) {
  5401. filter = function (typeName) {
  5402. return typeName === "click";
  5403. };
  5404. }
  5405. const originalListener = EventTarget.prototype.addEventListener;
  5406. EventTarget.prototype.addEventListener = function (...args) {
  5407. let type = args[0];
  5408. let callback = args[1];
  5409. // @ts-ignore
  5410. args[2];
  5411. if (filter(type)) {
  5412. if (typeof callback === "function") {
  5413. args[1] = function (event) {
  5414. callback.call(this, trustEvent(event));
  5415. };
  5416. }
  5417. else if (typeof callback === "object" &&
  5418. "handleEvent" in callback) {
  5419. let oldHandleEvent = callback["handleEvent"];
  5420. args[1]["handleEvent"] = function (event) {
  5421. if (event == null) {
  5422. return;
  5423. }
  5424. try {
  5425. /* Proxy对象使用instanceof会报错 */
  5426. event instanceof Proxy;
  5427. oldHandleEvent.call(this, trustEvent(event));
  5428. }
  5429. catch (error) {
  5430. // @ts-ignore
  5431. event["isTrusted"] = isTrustValue;
  5432. }
  5433. };
  5434. }
  5435. }
  5436. return originalListener.apply(this, args);
  5437. };
  5438. }
  5439. reverseNumber(num) {
  5440. let reversedNum = 0;
  5441. let isNegative = false;
  5442. if (num < 0) {
  5443. isNegative = true;
  5444. num = Math.abs(num);
  5445. }
  5446. while (num > 0) {
  5447. reversedNum = reversedNum * 10 + (num % 10);
  5448. num = Math.floor(num / 10);
  5449. }
  5450. return isNegative ? -reversedNum : reversedNum;
  5451. }
  5452. selectElementText(element, childTextNode, startIndex, endIndex) {
  5453. let range = UtilsCore.document.createRange();
  5454. range.selectNodeContents(element);
  5455. if (childTextNode) {
  5456. if (childTextNode.nodeType !== Node.TEXT_NODE) {
  5457. throw new TypeError("childTextNode必须是#text元素");
  5458. }
  5459. if (startIndex != null && endIndex != null) {
  5460. range.setStart(childTextNode, startIndex);
  5461. range.setEnd(childTextNode, endIndex);
  5462. }
  5463. }
  5464. let selection = UtilsCore.globalThis.getSelection();
  5465. if (selection) {
  5466. selection.removeAllRanges();
  5467. selection.addRange(range);
  5468. }
  5469. }
  5470. setClip(data, info = {
  5471. type: "text",
  5472. mimetype: "text/plain",
  5473. }) {
  5474. if (typeof data === "object") {
  5475. if (data instanceof Element) {
  5476. data = data.outerHTML;
  5477. }
  5478. else {
  5479. data = JSON.stringify(data);
  5480. }
  5481. }
  5482. else if (typeof data !== "string") {
  5483. data = data.toString();
  5484. }
  5485. let textType = typeof info === "object" ? info.type : info;
  5486. if (textType.includes("html")) {
  5487. textType = "text/html";
  5488. }
  5489. else {
  5490. textType = "text/plain";
  5491. }
  5492. class UtilsClipboard {
  5493. #resolve;
  5494. #copyData;
  5495. #copyDataType;
  5496. constructor(resolve, copyData, copyDataType) {
  5497. this.#resolve = resolve;
  5498. this.#copyData = copyData;
  5499. this.#copyDataType = copyDataType;
  5500. }
  5501. async init() {
  5502. let copyStatus = false;
  5503. // @ts-ignore
  5504. await this.requestClipboardPermission();
  5505. if (this.hasClipboard() &&
  5506. (this.hasClipboardWrite() || this.hasClipboardWriteText())) {
  5507. try {
  5508. copyStatus = await this.copyDataByClipboard();
  5509. }
  5510. catch (error) {
  5511. console.error("复制失败,使用第二种方式,error👉", error);
  5512. copyStatus = this.copyTextByTextArea();
  5513. }
  5514. }
  5515. else {
  5516. copyStatus = this.copyTextByTextArea();
  5517. }
  5518. this.#resolve(copyStatus);
  5519. this.destroy();
  5520. }
  5521. destroy() {
  5522. // @ts-ignore
  5523. this.#resolve = null;
  5524. // @ts-ignore
  5525. this.#copyData = null;
  5526. // @ts-ignore
  5527. this.#copyDataType = null;
  5528. }
  5529. isText() {
  5530. return this.#copyDataType.includes("text");
  5531. }
  5532. hasClipboard() {
  5533. return navigator?.clipboard != null;
  5534. }
  5535. hasClipboardWrite() {
  5536. return navigator?.clipboard?.write != null;
  5537. }
  5538. hasClipboardWriteText() {
  5539. return navigator?.clipboard?.writeText != null;
  5540. }
  5541. /**
  5542. * 使用textarea和document.execCommand("copy")来复制文字
  5543. */
  5544. copyTextByTextArea() {
  5545. try {
  5546. let copyElement = UtilsCore.document.createElement("textarea");
  5547. copyElement.value = this.#copyData;
  5548. copyElement.setAttribute("type", "text");
  5549. copyElement.setAttribute("style", "opacity:0;position:absolute;");
  5550. copyElement.setAttribute("readonly", "readonly");
  5551. UtilsCore.document.body.appendChild(copyElement);
  5552. copyElement.select();
  5553. UtilsCore.document.execCommand("copy");
  5554. UtilsCore.document.body.removeChild(copyElement);
  5555. return true;
  5556. }
  5557. catch (error) {
  5558. console.error("复制失败,error👉", error);
  5559. return false;
  5560. }
  5561. }
  5562. /**
  5563. * 申请剪贴板权限
  5564. * @returns {Promise<boolean>}
  5565. */
  5566. requestClipboardPermission() {
  5567. return new Promise((resolve, reject) => {
  5568. if (navigator.permissions && navigator.permissions.query) {
  5569. navigator.permissions
  5570. .query({
  5571. // @ts-ignore
  5572. name: "clipboard-write",
  5573. })
  5574. .then((permissionStatus) => {
  5575. resolve(true);
  5576. })
  5577. .catch(
  5578. /** @param {TypeError} error */
  5579. (error) => {
  5580. console.error([
  5581. "申请剪贴板权限失败,尝试直接写入👉",
  5582. error.message ?? error.name ?? error.stack,
  5583. ]);
  5584. resolve(false);
  5585. });
  5586. }
  5587. else {
  5588. resolve(false);
  5589. }
  5590. });
  5591. }
  5592. /**
  5593. * 使用clipboard直接写入数据到剪贴板
  5594. */
  5595. copyDataByClipboard() {
  5596. return new Promise((resolve, reject) => {
  5597. if (this.isText()) {
  5598. /* 只复制文字 */
  5599. navigator.clipboard
  5600. .writeText(this.#copyData)
  5601. .then(() => {
  5602. resolve(true);
  5603. })
  5604. .catch((error) => {
  5605. reject(error);
  5606. });
  5607. }
  5608. else {
  5609. /* 可复制对象 */
  5610. let textBlob = new Blob([this.#copyData], {
  5611. type: this.#copyDataType,
  5612. });
  5613. navigator.clipboard
  5614. .write([
  5615. new ClipboardItem({
  5616. [this.#copyDataType]: textBlob,
  5617. }),
  5618. ])
  5619. .then(() => {
  5620. resolve(true);
  5621. })
  5622. .catch((error) => {
  5623. reject(error);
  5624. });
  5625. }
  5626. });
  5627. }
  5628. }
  5629. return new Promise((resolve) => {
  5630. const utilsClipboard = new UtilsClipboard(resolve, data, textType);
  5631. if (UtilsCore.document.hasFocus()) {
  5632. utilsClipboard.init();
  5633. }
  5634. else {
  5635. UtilsCore.window.addEventListener("focus", () => {
  5636. utilsClipboard.init();
  5637. }, { once: true });
  5638. }
  5639. });
  5640. }
  5641. setTimeout(callback, delayTime = 0) {
  5642. let UtilsContext = this;
  5643. if (typeof callback !== "function" && typeof callback !== "string") {
  5644. throw new TypeError("Utils.setTimeout 参数 callback 必须为 function|string 类型");
  5645. }
  5646. if (typeof delayTime !== "number") {
  5647. throw new TypeError("Utils.setTimeout 参数 delayTime 必须为 number 类型");
  5648. }
  5649. return new Promise((resolve) => {
  5650. setTimeout(() => {
  5651. resolve(UtilsContext.tryCatch().run(callback));
  5652. }, delayTime);
  5653. });
  5654. }
  5655. sleep(delayTime = 0) {
  5656. if (typeof delayTime !== "number") {
  5657. throw new Error("Utils.sleep 参数 delayTime 必须为 number 类型");
  5658. }
  5659. return new Promise((resolve) => {
  5660. setTimeout(() => {
  5661. resolve(void 0);
  5662. }, delayTime);
  5663. });
  5664. }
  5665. dragSlider(selector, offsetX = UtilsCore.window.innerWidth) {
  5666. function initMouseEvent(eventName, offSetX, offSetY) {
  5667. let win = unsafeWindow || window;
  5668. let mouseEvent = UtilsCore.document.createEvent("MouseEvents");
  5669. mouseEvent.initMouseEvent(eventName, true, true, win, 0, offSetX, offSetY, offSetX, offSetY, false, false, false, false, 0, null);
  5670. return mouseEvent;
  5671. }
  5672. let sliderElement = typeof selector === "string"
  5673. ? UtilsCore.document.querySelector(selector)
  5674. : selector;
  5675. if (!(sliderElement instanceof Node) ||
  5676. !(sliderElement instanceof Element)) {
  5677. throw new Error("Utils.dragSlider 参数selector 必须为Node/Element类型");
  5678. }
  5679. let rect = sliderElement.getBoundingClientRect(), x0 = rect.x || rect.left, y0 = rect.y || rect.top, x1 = x0 + offsetX, y1 = y0;
  5680. sliderElement.dispatchEvent(initMouseEvent("mousedown", x0, y0));
  5681. sliderElement.dispatchEvent(initMouseEvent("mousemove", x1, y1));
  5682. sliderElement.dispatchEvent(initMouseEvent("mouseleave", x1, y1));
  5683. sliderElement.dispatchEvent(initMouseEvent("mouseout", x1, y1));
  5684. }
  5685. enterFullScreen(element = UtilsCore.document.documentElement, options) {
  5686. try {
  5687. if (element.requestFullscreen) {
  5688. element.requestFullscreen(options);
  5689. }
  5690. else if (element.webkitRequestFullScreen) {
  5691. element.webkitRequestFullScreen();
  5692. }
  5693. else if (element.mozRequestFullScreen) {
  5694. element.mozRequestFullScreen();
  5695. }
  5696. else if (element.msRequestFullscreen) {
  5697. element.msRequestFullscreen();
  5698. }
  5699. else {
  5700. throw new TypeError("该浏览器不支持全屏API");
  5701. }
  5702. }
  5703. catch (err) {
  5704. console.error(err);
  5705. }
  5706. }
  5707. exitFullScreen(element = UtilsCore.document.documentElement) {
  5708. if (UtilsCore.document.exitFullscreen) {
  5709. return UtilsCore.document.exitFullscreen();
  5710. }
  5711. else if (UtilsCore.document.msExitFullscreen) {
  5712. return UtilsCore.document.msExitFullscreen();
  5713. }
  5714. else if (UtilsCore.document.mozCancelFullScreen) {
  5715. return UtilsCore.document.mozCancelFullScreen();
  5716. }
  5717. else if (UtilsCore.document.webkitCancelFullScreen) {
  5718. return UtilsCore.document.webkitCancelFullScreen();
  5719. }
  5720. else {
  5721. return new Promise((resolve, reject) => {
  5722. reject(new TypeError("该浏览器不支持全屏API"));
  5723. });
  5724. }
  5725. }
  5726. sortListByProperty(data, getPropertyValueFunc, sortByDesc = true) {
  5727. let UtilsContext = this;
  5728. if (typeof getPropertyValueFunc !== "function" &&
  5729. typeof getPropertyValueFunc !== "string") {
  5730. throw new Error("Utils.sortListByProperty 参数 getPropertyValueFunc 必须为 function|string 类型");
  5731. }
  5732. if (typeof sortByDesc !== "boolean") {
  5733. throw new Error("Utils.sortListByProperty 参数 sortByDesc 必须为 boolean 类型");
  5734. }
  5735. let getObjValue = function (obj) {
  5736. return typeof getPropertyValueFunc === "string"
  5737. ? obj[getPropertyValueFunc]
  5738. : getPropertyValueFunc(obj);
  5739. };
  5740. /**
  5741. * 排序方法
  5742. * @param {any} after_obj
  5743. * @param {any} before_obj
  5744. * @returns
  5745. */
  5746. let sortFunc = function (after_obj, before_obj) {
  5747. let beforeValue = getObjValue(before_obj); /* 前 */
  5748. let afterValue = getObjValue(after_obj); /* 后 */
  5749. if (sortByDesc) {
  5750. if (afterValue > beforeValue) {
  5751. return -1;
  5752. }
  5753. else if (afterValue < beforeValue) {
  5754. return 1;
  5755. }
  5756. else {
  5757. return 0;
  5758. }
  5759. }
  5760. else {
  5761. if (afterValue < beforeValue) {
  5762. return -1;
  5763. }
  5764. else if (afterValue > beforeValue) {
  5765. return 1;
  5766. }
  5767. else {
  5768. return 0;
  5769. }
  5770. }
  5771. };
  5772. /**
  5773. * 排序元素方法
  5774. * @param nodeList 元素列表
  5775. * @param getNodeListFunc 获取元素列表的函数
  5776. */
  5777. let sortNodeFunc = function (nodeList, getNodeListFunc) {
  5778. let nodeListLength = nodeList.length;
  5779. for (let i = 0; i < nodeListLength - 1; i++) {
  5780. for (let j = 0; j < nodeListLength - 1 - i; j++) {
  5781. let beforeNode = nodeList[j];
  5782. let afterNode = nodeList[j + 1];
  5783. let beforeValue = getObjValue(beforeNode); /* 前 */
  5784. let afterValue = getObjValue(afterNode); /* 后 */
  5785. if ((sortByDesc == true && beforeValue < afterValue) ||
  5786. (sortByDesc == false && beforeValue > afterValue)) {
  5787. /* 升序/降序 */
  5788. /* 相邻元素两两对比 */
  5789. let temp = beforeNode.nextElementSibling;
  5790. afterNode.after(beforeNode);
  5791. if (temp == null) {
  5792. /* 如果为空,那么是最后一个元素,使用append */
  5793. temp.parentNode.appendChild(afterNode);
  5794. }
  5795. else {
  5796. /* 不为空,使用before */
  5797. temp.before(afterNode);
  5798. }
  5799. nodeList = getNodeListFunc();
  5800. }
  5801. }
  5802. }
  5803. };
  5804. let result = data;
  5805. let getDataFunc = null;
  5806. if (data instanceof Function) {
  5807. getDataFunc = data;
  5808. data = data();
  5809. }
  5810. if (Array.isArray(data)) {
  5811. data.sort(sortFunc);
  5812. }
  5813. else if (data instanceof NodeList || UtilsContext.isJQuery(data)) {
  5814. sortNodeFunc(data, getDataFunc);
  5815. result = getDataFunc();
  5816. }
  5817. else {
  5818. throw new Error("Utils.sortListByProperty 参数 data 必须为 Array|NodeList|jQuery 类型");
  5819. }
  5820. return result;
  5821. }
  5822. stringToRegular(targetString, flags = "ig") {
  5823. let reg;
  5824. // @ts-ignore
  5825. flags = flags.toLowerCase();
  5826. if (typeof targetString === "string") {
  5827. reg = new RegExp(targetString.replace(/[.*+\-?^${}()|[\]\\]/g, "\\$&"), flags);
  5828. }
  5829. else if (targetString instanceof RegExp) {
  5830. reg = targetString;
  5831. }
  5832. else {
  5833. throw new Error("Utils.stringToRegular 参数targetString必须是string|Regexp类型");
  5834. }
  5835. return reg;
  5836. }
  5837. stringTitleToUpperCase(targetString, otherStrToLowerCase = false) {
  5838. let newTargetString = targetString.slice(0, 1).toUpperCase();
  5839. if (otherStrToLowerCase) {
  5840. newTargetString = newTargetString + targetString.slice(1).toLowerCase();
  5841. }
  5842. else {
  5843. newTargetString = newTargetString + targetString.slice(1);
  5844. }
  5845. return newTargetString;
  5846. }
  5847. startsWith(target, searchString, position = 0) {
  5848. let UtilsContext = this;
  5849. if (position > target.length) {
  5850. /* 超出目标字符串的长度 */
  5851. return false;
  5852. }
  5853. if (position !== 0) {
  5854. target = target.slice(position, target.length);
  5855. }
  5856. let searchStringRegexp = searchString;
  5857. if (typeof searchString === "string") {
  5858. searchStringRegexp = new RegExp(`^${searchString}`);
  5859. }
  5860. else if (Array.isArray(searchString)) {
  5861. let flag = false;
  5862. for (const searcStr of searchString) {
  5863. if (!UtilsContext.startsWith(target, searcStr, position)) {
  5864. flag = true;
  5865. break;
  5866. }
  5867. }
  5868. return flag;
  5869. }
  5870. return Boolean(target.match(searchStringRegexp));
  5871. }
  5872. stringTitleToLowerCase(targetString, otherStrToUpperCase = false) {
  5873. let newTargetString = targetString.slice(0, 1).toLowerCase();
  5874. if (otherStrToUpperCase) {
  5875. newTargetString = newTargetString + targetString.slice(1).toUpperCase();
  5876. }
  5877. else {
  5878. newTargetString = newTargetString + targetString.slice(1);
  5879. }
  5880. return newTargetString;
  5881. }
  5882. toJSON(data, errorCallBack) {
  5883. let UtilsContext = this;
  5884. let result = {};
  5885. if (typeof data === "object") {
  5886. return data;
  5887. }
  5888. UtilsContext.tryCatch()
  5889. .config({ log: false })
  5890. .error((error) => {
  5891. UtilsContext.tryCatch()
  5892. .error(() => {
  5893. try {
  5894. result = UtilsCore.window.eval("(" + data + ")");
  5895. }
  5896. catch (error2) {
  5897. if (typeof errorCallBack === "function") {
  5898. errorCallBack(error2);
  5899. }
  5900. }
  5901. })
  5902. .run(() => {
  5903. if (data &&
  5904. /^[\],:{}\s]*$/.test(data
  5905. .replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, "@")
  5906. .replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, "]")
  5907. .replace(/(?:^|:|,)(?:\s*\[)+/g, ""))) {
  5908. result = new Function("return " + data)();
  5909. }
  5910. else {
  5911. if (typeof errorCallBack === "function") {
  5912. errorCallBack(new Error("target is not a JSON"));
  5913. }
  5914. }
  5915. });
  5916. })
  5917. .run(() => {
  5918. data = data.trim();
  5919. result = JSON.parse(data);
  5920. });
  5921. return result;
  5922. }
  5923. toSearchParamsStr(obj) {
  5924. let UtilsContext = this;
  5925. let searhParamsStr = "";
  5926. if (Array.isArray(obj)) {
  5927. obj.forEach((item) => {
  5928. if (searhParamsStr === "") {
  5929. searhParamsStr += UtilsContext.toSearchParamsStr(item);
  5930. }
  5931. else {
  5932. searhParamsStr += "&" + UtilsContext.toSearchParamsStr(item);
  5933. }
  5934. });
  5935. }
  5936. else {
  5937. searhParamsStr = new URLSearchParams(Object.entries(obj)).toString();
  5938. }
  5939. return searhParamsStr;
  5940. }
  5941. /**
  5942. * 提供一个封装了 try-catch 的函数,可以执行传入的函数并捕获其可能抛出的错误,并通过传入的错误处理函数进行处理。
  5943. * @example
  5944. * Utils.tryCatch().error().run(()=>{console.log(1)});
  5945. * > 1
  5946. * @example
  5947. * Utils.tryCatch().config({log:true}).error((error)=>{console.log(error)}).run(()=>{throw new Error('测试错误')});
  5948. * > ()=>{throw new Error('测试错误')}出现错误
  5949. */
  5950. tryCatch = TryCatch;
  5951. uniqueArray(uniqueArrayData = [], compareArrayData = [], compareFun = (item, item2) => {
  5952. // @ts-ignore
  5953. return item === item2;
  5954. }) {
  5955. return Array.from(uniqueArrayData).filter((item) => !Array.from(compareArrayData).some(function (item2) {
  5956. return compareFun(item, item2);
  5957. }));
  5958. }
  5959. waitArrayLoopToEnd(data, handleFunc) {
  5960. let UtilsContext = this;
  5961. if (typeof handleFunc !== "function" && typeof handleFunc !== "string") {
  5962. throw new Error("Utils.waitArrayLoopToEnd 参数 handleDataFunction 必须为 function|string 类型");
  5963. }
  5964. return Promise.all(Array.from(data).map(async (item, index) => {
  5965. await UtilsContext.tryCatch(index, item).run(handleFunc);
  5966. }));
  5967. }
  5968. waitNode(...args) {
  5969. // 过滤掉undefined
  5970. args = args.filter((arg) => arg !== void 0);
  5971. let that = this;
  5972. // 选择器
  5973. let selector = args[0];
  5974. // 父元素(监听的元素)
  5975. let parent = UtilsCore.document;
  5976. // 超时时间
  5977. let timeout = 0;
  5978. if (typeof args[0] !== "string" && !Array.isArray(args[0])) {
  5979. throw new TypeError("Utils.waitNode 第一个参数必须是string|string[]");
  5980. }
  5981. if (args.length === 1) ;
  5982. else if (args.length === 2) {
  5983. let secondParam = args[1];
  5984. if (typeof secondParam === "number") {
  5985. // "div",10000
  5986. timeout = secondParam;
  5987. }
  5988. else if (typeof secondParam === "object" &&
  5989. secondParam instanceof Node) {
  5990. // "div",document
  5991. parent = secondParam;
  5992. }
  5993. else {
  5994. throw new TypeError("Utils.waitNode 第二个参数必须是number|Node");
  5995. }
  5996. }
  5997. else if (args.length === 3) {
  5998. // "div",document,10000
  5999. // 第二个参数,parent
  6000. let secondParam = args[1];
  6001. // 第三个参数,timeout
  6002. let thirdParam = args[2];
  6003. if (typeof secondParam === "object" && secondParam instanceof Node) {
  6004. parent = secondParam;
  6005. if (typeof thirdParam === "number") {
  6006. timeout = thirdParam;
  6007. }
  6008. else {
  6009. throw new TypeError("Utils.waitNode 第三个参数必须是number");
  6010. }
  6011. }
  6012. else {
  6013. throw new TypeError("Utils.waitNode 第二个参数必须是Node");
  6014. }
  6015. }
  6016. else {
  6017. throw new TypeError("Utils.waitNode 参数个数错误");
  6018. }
  6019. return new Promise((resolve) => {
  6020. function getNode() {
  6021. if (Array.isArray(selector)) {
  6022. let result = [];
  6023. for (let index = 0; index < selector.length; index++) {
  6024. let node = parent.querySelector(selector[index]);
  6025. if (node) {
  6026. result.push(node);
  6027. }
  6028. }
  6029. if (result.length === selector.length) {
  6030. return result;
  6031. }
  6032. }
  6033. else {
  6034. return parent.querySelector(selector);
  6035. }
  6036. }
  6037. var observer = that.mutationObserver(parent, {
  6038. config: {
  6039. subtree: true,
  6040. childList: true,
  6041. attributes: true,
  6042. },
  6043. callback() {
  6044. let node = getNode();
  6045. if (node) {
  6046. // 取消观察器
  6047. if (typeof observer?.disconnect === "function") {
  6048. observer.disconnect();
  6049. }
  6050. resolve(node);
  6051. return;
  6052. }
  6053. },
  6054. immediate: true,
  6055. });
  6056. if (timeout > 0) {
  6057. setTimeout(() => {
  6058. // 取消观察器
  6059. if (typeof observer?.disconnect === "function") {
  6060. observer.disconnect();
  6061. }
  6062. resolve(null);
  6063. }, timeout);
  6064. }
  6065. });
  6066. }
  6067. waitAnyNode(...args) {
  6068. // 过滤掉undefined
  6069. args = args.filter((arg) => arg !== void 0);
  6070. let that = this;
  6071. // 选择器
  6072. let selectorList = args[0];
  6073. // 父元素(监听的元素)
  6074. let parent = UtilsCore.document;
  6075. // 超时时间
  6076. let timeout = 0;
  6077. if (typeof args[0] !== "object" && !Array.isArray(args[0])) {
  6078. throw new TypeError("Utils.waitAnyNode 第一个参数必须是string[]");
  6079. }
  6080. if (args.length === 1) ;
  6081. else if (args.length === 2) {
  6082. let secondParam = args[1];
  6083. if (typeof secondParam === "number") {
  6084. // "div",10000
  6085. timeout = secondParam;
  6086. }
  6087. else if (typeof secondParam === "object" &&
  6088. secondParam instanceof Node) {
  6089. // "div",document
  6090. parent = secondParam;
  6091. }
  6092. else {
  6093. throw new TypeError("Utils.waitAnyNode 第二个参数必须是number|Node");
  6094. }
  6095. }
  6096. else if (args.length === 3) {
  6097. // "div",document,10000
  6098. // 第二个参数,parent
  6099. let secondParam = args[1];
  6100. // 第三个参数,timeout
  6101. let thirdParam = args[2];
  6102. if (typeof secondParam === "object" && secondParam instanceof Node) {
  6103. parent = secondParam;
  6104. if (typeof thirdParam === "number") {
  6105. timeout = thirdParam;
  6106. }
  6107. else {
  6108. throw new TypeError("Utils.waitAnyNode 第三个参数必须是number");
  6109. }
  6110. }
  6111. else {
  6112. throw new TypeError("Utils.waitAnyNode 第二个参数必须是Node");
  6113. }
  6114. }
  6115. else {
  6116. throw new TypeError("Utils.waitAnyNode 参数个数错误");
  6117. }
  6118. let promiseList = selectorList.map((selector) => {
  6119. return that.waitNode(selector, parent, timeout);
  6120. });
  6121. return Promise.any(promiseList);
  6122. }
  6123. waitNodeList(...args) {
  6124. // 过滤掉undefined
  6125. args = args.filter((arg) => arg !== void 0);
  6126. let that = this;
  6127. // 选择器数组
  6128. let selector = args[0];
  6129. // 父元素(监听的元素)
  6130. let parent = UtilsCore.document;
  6131. // 超时时间
  6132. let timeout = 0;
  6133. if (typeof args[0] !== "string" && !Array.isArray(args[0])) {
  6134. throw new TypeError("Utils.waitNodeList 第一个参数必须是string|string[]");
  6135. }
  6136. if (args.length === 1) ;
  6137. else if (args.length === 2) {
  6138. let secondParam = args[1];
  6139. if (typeof secondParam === "number") {
  6140. // "div",10000
  6141. timeout = secondParam;
  6142. }
  6143. else if (typeof secondParam === "object" &&
  6144. secondParam instanceof Node) {
  6145. // "div",document
  6146. parent = secondParam;
  6147. }
  6148. else {
  6149. throw new TypeError("Utils.waitNodeList 第二个参数必须是number|Node");
  6150. }
  6151. }
  6152. else if (args.length === 3) {
  6153. // "div",document,10000
  6154. // 第二个参数,parent
  6155. let secondParam = args[1];
  6156. // 第三个参数,timeout
  6157. let thirdParam = args[2];
  6158. if (typeof secondParam === "object" && secondParam instanceof Node) {
  6159. parent = secondParam;
  6160. if (typeof thirdParam === "number") {
  6161. timeout = thirdParam;
  6162. }
  6163. else {
  6164. throw new TypeError("Utils.waitNodeList 第三个参数必须是number");
  6165. }
  6166. }
  6167. else {
  6168. throw new TypeError("Utils.waitNodeList 第二个参数必须是Node");
  6169. }
  6170. }
  6171. else {
  6172. throw new TypeError("Utils.waitNodeList 参数个数错误");
  6173. }
  6174. return new Promise((resolve) => {
  6175. function getNodeList() {
  6176. if (Array.isArray(selector)) {
  6177. let result = [];
  6178. for (let index = 0; index < selector.length; index++) {
  6179. let nodeList = parent.querySelectorAll(selector[index]);
  6180. if (nodeList.length) {
  6181. result.push(nodeList);
  6182. }
  6183. }
  6184. if (result.length === selector.length) {
  6185. return result;
  6186. }
  6187. }
  6188. else {
  6189. let nodeList = parent.querySelectorAll(selector);
  6190. if (nodeList.length) {
  6191. return nodeList;
  6192. }
  6193. }
  6194. }
  6195. var observer = that.mutationObserver(parent, {
  6196. config: {
  6197. subtree: true,
  6198. childList: true,
  6199. attributes: true,
  6200. },
  6201. callback() {
  6202. let node = getNodeList();
  6203. if (node) {
  6204. // 取消观察器
  6205. try {
  6206. observer.disconnect();
  6207. }
  6208. catch (error) { }
  6209. resolve(node);
  6210. return;
  6211. }
  6212. },
  6213. immediate: true,
  6214. });
  6215. if (timeout > 0) {
  6216. setTimeout(() => {
  6217. // 取消观察器
  6218. if (typeof observer?.disconnect === "function") {
  6219. observer.disconnect();
  6220. }
  6221. resolve(null);
  6222. }, timeout);
  6223. }
  6224. });
  6225. }
  6226. waitAnyNodeList(...args) {
  6227. // 过滤掉undefined
  6228. args = args.filter((arg) => arg !== void 0);
  6229. let that = this;
  6230. // 选择器数组
  6231. let selectorList = args[0];
  6232. // 父元素(监听的元素)
  6233. let parent = UtilsCore.document;
  6234. // 超时时间
  6235. let timeout = 0;
  6236. if (!Array.isArray(args[0])) {
  6237. throw new TypeError("Utils.waitAnyNodeList 第一个参数必须是string[]");
  6238. }
  6239. if (args.length === 1) ;
  6240. else if (args.length === 2) {
  6241. let secondParam = args[1];
  6242. if (typeof secondParam === "number") {
  6243. // "div",10000
  6244. timeout = secondParam;
  6245. }
  6246. else if (typeof secondParam === "object" &&
  6247. secondParam instanceof Node) {
  6248. // "div",document
  6249. parent = secondParam;
  6250. }
  6251. else {
  6252. throw new TypeError("Utils.waitAnyNodeList 第二个参数必须是number|Node");
  6253. }
  6254. }
  6255. else if (args.length === 3) {
  6256. // "div",document,10000
  6257. // 第二个参数,parent
  6258. let secondParam = args[1];
  6259. // 第三个参数,timeout
  6260. let thirdParam = args[2];
  6261. if (typeof secondParam === "object" && secondParam instanceof Node) {
  6262. parent = secondParam;
  6263. if (typeof thirdParam === "number") {
  6264. timeout = thirdParam;
  6265. }
  6266. else {
  6267. throw new TypeError("Utils.waitAnyNodeList 第三个参数必须是number");
  6268. }
  6269. }
  6270. else {
  6271. throw new TypeError("Utils.waitAnyNodeList 第二个参数必须是Node");
  6272. }
  6273. }
  6274. else {
  6275. throw new TypeError("Utils.waitAnyNodeList 参数个数错误");
  6276. }
  6277. let promiseList = selectorList.map((selector) => {
  6278. return that.waitNodeList(selector, parent, timeout);
  6279. });
  6280. return Promise.any(promiseList);
  6281. }
  6282. waitProperty(checkObj, checkPropertyName) {
  6283. return new Promise((resolve) => {
  6284. let obj = checkObj;
  6285. if (typeof checkObj === "function") {
  6286. obj = checkObj();
  6287. }
  6288. if (Reflect.has(obj, checkPropertyName)) {
  6289. resolve(obj[checkPropertyName]);
  6290. }
  6291. else {
  6292. Object.defineProperty(obj, checkPropertyName, {
  6293. set: function (value) {
  6294. try {
  6295. resolve(value);
  6296. }
  6297. catch (error) {
  6298. console.error("Error setting property:", error);
  6299. }
  6300. },
  6301. });
  6302. }
  6303. });
  6304. }
  6305. waitPropertyByInterval(checkObj, checkPropertyName, intervalTimer = 250, maxTime = -1) {
  6306. if (checkObj == null) {
  6307. throw new TypeError("checkObj 不能为空对象 ");
  6308. }
  6309. let isResolve = false;
  6310. return new Promise((resolve, reject) => {
  6311. let interval = setInterval(() => {
  6312. let obj = checkObj;
  6313. if (typeof checkObj === "function") {
  6314. obj = checkObj();
  6315. }
  6316. if (typeof obj !== "object") {
  6317. return;
  6318. }
  6319. if (obj == null) {
  6320. return;
  6321. }
  6322. if ((typeof checkPropertyName === "function" && checkPropertyName(obj)) ||
  6323. Reflect.has(obj, checkPropertyName)) {
  6324. isResolve = true;
  6325. clearInterval(interval);
  6326. resolve(obj[checkPropertyName]);
  6327. }
  6328. }, intervalTimer);
  6329. if (maxTime !== -1) {
  6330. setTimeout(() => {
  6331. if (!isResolve) {
  6332. clearInterval(interval);
  6333. reject();
  6334. }
  6335. }, maxTime);
  6336. }
  6337. });
  6338. }
  6339. async waitVueByInterval(element, propertyName, timer = 250, maxTime = -1, vueName = "__vue__") {
  6340. if (element == null) {
  6341. throw new Error("Utils.waitVueByInterval 参数element 不能为空");
  6342. }
  6343. let flag = false;
  6344. let UtilsContext = this;
  6345. try {
  6346. await UtilsContext.waitPropertyByInterval(element, function (targetElement) {
  6347. if (targetElement == null) {
  6348. return false;
  6349. }
  6350. if (!(vueName in targetElement)) {
  6351. return false;
  6352. }
  6353. if (propertyName == null) {
  6354. return true;
  6355. }
  6356. let vueObject = targetElement[vueName];
  6357. if (typeof propertyName === "string") {
  6358. if (propertyName in vueObject) {
  6359. flag = true;
  6360. return true;
  6361. }
  6362. }
  6363. else {
  6364. /* Function */
  6365. if (propertyName(vueObject)) {
  6366. flag = true;
  6367. return true;
  6368. }
  6369. }
  6370. return false;
  6371. }, timer, maxTime);
  6372. }
  6373. catch (error) {
  6374. return flag;
  6375. }
  6376. return flag;
  6377. }
  6378. watchObject(target, propertyName, getCallBack, setCallBack) {
  6379. if (typeof getCallBack !== "function" &&
  6380. typeof setCallBack !== "function") {
  6381. return;
  6382. }
  6383. if (typeof getCallBack === "function") {
  6384. Object.defineProperty(target, propertyName, {
  6385. get() {
  6386. if (typeof getCallBack === "function") {
  6387. return getCallBack(target[propertyName]);
  6388. }
  6389. else {
  6390. return target[propertyName];
  6391. }
  6392. },
  6393. });
  6394. }
  6395. else if (typeof setCallBack === "function") {
  6396. Object.defineProperty(target, propertyName, {
  6397. set(value) {
  6398. if (typeof setCallBack === "function") {
  6399. setCallBack(value);
  6400. }
  6401. },
  6402. });
  6403. }
  6404. else {
  6405. Object.defineProperty(target, propertyName, {
  6406. get() {
  6407. if (typeof getCallBack === "function") {
  6408. return getCallBack(target[propertyName]);
  6409. }
  6410. else {
  6411. return target[propertyName];
  6412. }
  6413. },
  6414. set(value) {
  6415. if (typeof setCallBack === "function") {
  6416. setCallBack(value);
  6417. }
  6418. },
  6419. });
  6420. }
  6421. }
  6422. /**
  6423. * 创建一个新的Utils实例
  6424. * @param option
  6425. * @returns
  6426. */
  6427. createUtils(option) {
  6428. return new Utils(option);
  6429. }
  6430. /**
  6431. * 将对象转换为FormData
  6432. * @param data 待转换的对象
  6433. * @param isEncode 是否对值为string进行编码转换(encodeURIComponent),默认false
  6434. * @param valueAutoParseToStr 是否对值强制使用JSON.stringify()转换,默认false
  6435. * @example
  6436. * Utils.toFormData({
  6437. * test: "1",
  6438. * 666: 666,
  6439. * })
  6440. */
  6441. toFormData(data, isEncode = false, valueAutoParseToStr = false) {
  6442. const formData = new FormData();
  6443. Object.keys(data).forEach((key) => {
  6444. let value = data[key];
  6445. if (valueAutoParseToStr) {
  6446. value = JSON.stringify(value);
  6447. }
  6448. if (typeof value === "number") {
  6449. value = value.toString();
  6450. }
  6451. if (isEncode && typeof value === "string") {
  6452. value = encodeURIComponent(value);
  6453. }
  6454. if (value instanceof File) {
  6455. formData.append(key, value, value.name);
  6456. }
  6457. else {
  6458. formData.append(key, value);
  6459. }
  6460. });
  6461. return formData;
  6462. }
  6463. /**
  6464. * 将链接转为URL对象,自动补充URL的protocol或者origin
  6465. * @param text 需要转换的链接字符串
  6466. * @example
  6467. * Utils.toUrl("//www.baidu.com/s?word=666");
  6468. * Utils.toUrl("/s?word=666");
  6469. */
  6470. toUrl(text) {
  6471. if (typeof text !== "string") {
  6472. throw new TypeError("toUrl: text must be string");
  6473. }
  6474. text = text.trim();
  6475. if (text === "") {
  6476. throw new TypeError("toUrl: text must not be empty");
  6477. }
  6478. if (text.startsWith("//")) {
  6479. /* //www.baidu.com/xxxxxxx */
  6480. /* 没有protocol,加上 */
  6481. text = UtilsCore.globalThis.location.protocol + text;
  6482. }
  6483. else if (text.startsWith("/")) {
  6484. /* /xxx/info?xxx=xxx */
  6485. /* 没有Origin,加上 */
  6486. text = UtilsCore.globalThis.location.origin + text;
  6487. }
  6488. return new URL(text);
  6489. }
  6490. /**
  6491. * 生成uuid
  6492. * @example
  6493. * Utils.generateUUID()
  6494. */
  6495. generateUUID = GenerateUUID;
  6496. }
  6497. let utils = new Utils();
  6498.  
  6499. return utils;
  6500.  
  6501. }));
  6502. //# sourceMappingURL=index.umd.js.map

QingJ © 2025

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