@whitesev/utils 2.11.11 → 2.11.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.umd.js CHANGED
@@ -243,7 +243,7 @@
243
243
  const setInterval$1 = (...args) => loadOrReturnBroker().setInterval(...args);
244
244
  const setTimeout$1 = (...args) => loadOrReturnBroker().setTimeout(...args);
245
245
 
246
- const version = "2.11.11";
246
+ const version = "2.11.12";
247
247
 
248
248
  /* eslint-disable */
249
249
  // ==UserScript==
@@ -378,8 +378,12 @@
378
378
  }));
379
379
  }
380
380
  waitForRequestKeys() {
381
+ /**
382
+ * @type {Set<typeof hookInst>}
383
+ */
384
+ const winHookInsts = win.__ajaxHooker.hookInsts;
381
385
  if (!this.request.async) {
382
- win.__ajaxHooker.hookInsts.forEach(({ hookFns, filters }) => {
386
+ winHookInsts.forEach(({ hookFns, filters }) => {
383
387
  if (this.shouldFilter(filters))
384
388
  return;
385
389
  hookFns.forEach((fn) => {
@@ -395,10 +399,10 @@
395
399
  }
396
400
  const promises = [];
397
401
  const ignoreKeys = new Set(["type", "async", "response"]);
398
- win.__ajaxHooker.hookInsts.forEach(({ hookFns, filters }) => {
402
+ winHookInsts.forEach(({ hookFns, filters }) => {
399
403
  if (this.shouldFilter(filters))
400
404
  return;
401
- promises.push(Promise.all(hookFns.map((fn) => catchError(fn, this.request))).then(() => {
405
+ promises.push(Promise.all(hookFns.map((fn, index) => catchError(fn, this.request, index))).then(() => {
402
406
  const requestKeys = [];
403
407
  for (const key in this.request)
404
408
  !ignoreKeys.has(key) && requestKeys.push(key);
@@ -820,11 +824,52 @@
820
824
  });
821
825
  });
822
826
  }
827
+ /**
828
+ *
829
+ * @type {import("./../types/ajaxHooker.d.ts").UtilsAjaxHookResult["removeHook"]}
830
+ */
831
+ const removeHook = (fn, onlyRemove = false) => {
832
+ let flag = false;
833
+ for (let index = hookInst.hookFns.length - 1; index >= 0; index--) {
834
+ const __fn__ = hookInst.hookFns[index];
835
+ if (fn === __fn__) {
836
+ hookInst.hookFns.splice(index, 1);
837
+ flag = true;
838
+ if (onlyRemove) {
839
+ break;
840
+ }
841
+ }
842
+ }
843
+ return flag;
844
+ };
845
+ /**
846
+ *
847
+ * @type {import("./../types/ajaxHooker.d.ts").UtilsAjaxHookResult["removeFilter"]}
848
+ */
849
+ const removeFilter = () => {
850
+ if (Array.isArray(hookInst.filters)) {
851
+ hookInst.filters.length = 0;
852
+ }
853
+ else {
854
+ hookInst.filters = [];
855
+ }
856
+ };
823
857
  return {
824
- hook: (fn) => hookInst.hookFns.push(fn),
858
+ hook: (fn) => {
859
+ hookInst.hookFns.push(fn);
860
+ return {
861
+ remove: () => {
862
+ return removeHook(fn, true);
863
+ }
864
+ };
865
+ },
825
866
  filter: (arr) => {
826
- if (Array.isArray(arr))
867
+ if (Array.isArray(arr)) {
827
868
  hookInst.filters = arr;
869
+ }
870
+ return {
871
+ remove: removeFilter
872
+ };
828
873
  },
829
874
  protect: () => {
830
875
  readonly(win, "XMLHttpRequest", winAh.fakeXHR);
@@ -840,6 +885,8 @@
840
885
  delete win.__ajaxHooker;
841
886
  }
842
887
  },
888
+ removeHook: removeHook,
889
+ removeFilter: removeFilter
843
890
  };
844
891
  };
845
892
 
@@ -1238,10 +1285,50 @@
1238
1285
  Object.keys(realXhr).forEach((key) => (fakeXhr[key] = realXhr[key]));
1239
1286
  fakeXhr.prototype = realXhr.prototype;
1240
1287
  win.fetch = fakeFetch;
1288
+ /**
1289
+ *
1290
+ * @type {import("./../types/ajaxHooker.d.ts").UtilsAjaxHookResult["removeHook"]}
1291
+ */
1292
+ const removeHook = (fn, onlyRemove = false) => {
1293
+ let flag = false;
1294
+ for (let index = hookFns.length - 1; index >= 0; index--) {
1295
+ const __fn__ = hookFns[index];
1296
+ if (fn === __fn__) {
1297
+ hookFns.splice(index, 1);
1298
+ flag = true;
1299
+ if (onlyRemove) {
1300
+ break;
1301
+ }
1302
+ }
1303
+ }
1304
+ return flag;
1305
+ };
1306
+ /**
1307
+ *
1308
+ * @type {import("./../types/ajaxHooker.d.ts").UtilsAjaxHookResult["removeFilter"]}
1309
+ */
1310
+ const removeFilter = () => {
1311
+ if (Array.isArray(filter)) {
1312
+ filter.length = 0;
1313
+ }
1314
+ else {
1315
+ filter = void 0;
1316
+ }
1317
+ };
1241
1318
  return {
1242
- hook: (fn) => hookFns.push(fn),
1319
+ hook: (fn) => {
1320
+ hookFns.push(fn);
1321
+ return {
1322
+ remove: () => {
1323
+ return removeHook(fn, true);
1324
+ }
1325
+ };
1326
+ },
1243
1327
  filter: (arr) => {
1244
1328
  filter = Array.isArray(arr) && arr.map(toFilterObj);
1329
+ return {
1330
+ remove: removeFilter
1331
+ };
1245
1332
  },
1246
1333
  protect: () => {
1247
1334
  readonly(win, "XMLHttpRequest", fakeXhr);
@@ -1251,6 +1338,8 @@
1251
1338
  writable(win, "XMLHttpRequest", realXhr);
1252
1339
  writable(win, "fetch", realFetch);
1253
1340
  },
1341
+ removeHook: removeHook,
1342
+ removeFilter: removeFilter
1254
1343
  };
1255
1344
  })();
1256
1345
  };
@@ -2675,42 +2764,42 @@
2675
2764
  const method = requestOption.method;
2676
2765
  if (method === "GET" || method === "HEAD") {
2677
2766
  // GET类型,data如果有,那么需要转为searchParams
2678
- const urlObj = new URL(requestOption.url);
2767
+ const urlInst = new URL(requestOption.url);
2679
2768
  let urlSearch = "";
2680
- let isHandler = false;
2769
+ let deleteData = false;
2681
2770
  if (typeof requestOption.data === "string") {
2682
- isHandler = true;
2771
+ deleteData = true;
2683
2772
  urlSearch = requestOption.data;
2684
2773
  }
2685
2774
  else if (typeof requestOption.data === "object") {
2686
- isHandler = true;
2775
+ deleteData = true;
2687
2776
  // URLSearchParams参数可以转普通的string:string,包括FormData
2688
2777
  const searchParams = new URLSearchParams(requestOption.data);
2689
2778
  urlSearch = searchParams.toString();
2690
2779
  }
2691
- if (isHandler) {
2780
+ if (deleteData) {
2692
2781
  // GET/HEAD请求不支持data参数
2693
2782
  // 对data进行处理了才可以删除
2694
2783
  Reflect.deleteProperty(requestOption, "data");
2695
2784
  }
2696
- if (urlSearch != "") {
2697
- if (urlObj.search === "") {
2785
+ if (urlSearch.trim() != "") {
2786
+ if (urlInst.search.trim() === "") {
2698
2787
  // url没有search参数,直接覆盖
2699
- urlObj.search = urlSearch;
2788
+ urlInst.search = urlSearch;
2700
2789
  }
2701
2790
  else {
2702
2791
  // 有search参数
2703
- if (urlObj.search.endsWith("&")) {
2792
+ if (urlInst.search.trim().endsWith("&")) {
2704
2793
  // xxx=xxx&
2705
- urlObj.search = urlObj.search + urlSearch;
2794
+ urlInst.search = urlInst.search + urlSearch;
2706
2795
  }
2707
2796
  else {
2708
2797
  // xxx=xxx&xxx=
2709
- urlObj.search = `${urlObj.search}&${urlSearch}`;
2798
+ urlInst.search = `${urlInst.search}&${urlSearch}`;
2710
2799
  }
2711
2800
  }
2712
2801
  }
2713
- requestOption.url = urlObj.toString();
2802
+ requestOption.url = urlInst.toString();
2714
2803
  }
2715
2804
  else if (method === "POST" && requestOption.headers != null) {
2716
2805
  // POST类型,data如果是FormData,那么需要转为string
@@ -2720,10 +2809,10 @@
2720
2809
  typeof requestOption.headers[headerKey] === "string");
2721
2810
  });
2722
2811
  if (ContentTypeIndex !== -1) {
2723
- const ContentTypeKey = headersKeyList[ContentTypeIndex];
2724
- const ContentType = requestOption.headers[ContentTypeKey];
2812
+ const contentTypeKey = headersKeyList[ContentTypeIndex];
2813
+ const contentType = requestOption.headers[contentTypeKey].toLowerCase();
2725
2814
  // 设置了Content-Type
2726
- if (ContentType.includes("application/json")) {
2815
+ if (contentType.includes("application/json")) {
2727
2816
  // application/json
2728
2817
  if (requestOption.data instanceof FormData) {
2729
2818
  const entries = {};
@@ -2736,16 +2825,16 @@
2736
2825
  requestOption.data = JSON.stringify(requestOption.data);
2737
2826
  }
2738
2827
  }
2739
- else if (ContentType.includes("application/x-www-form-urlencoded")) {
2828
+ else if (contentType.includes("application/x-www-form-urlencoded")) {
2740
2829
  // application/x-www-form-urlencoded
2741
2830
  if (typeof requestOption.data === "object") {
2742
2831
  requestOption.data = new URLSearchParams(requestOption.data).toString();
2743
2832
  }
2744
2833
  }
2745
- else if (ContentType.includes("multipart/form-data")) {
2834
+ else if (contentType.includes("multipart/form-data")) {
2746
2835
  // multipart/form-data
2747
2836
  if (requestOption.data instanceof FormData) {
2748
- Reflect.deleteProperty(requestOption.headers, ContentTypeKey);
2837
+ Reflect.deleteProperty(requestOption.headers, contentTypeKey);
2749
2838
  }
2750
2839
  }
2751
2840
  }
@@ -5703,20 +5792,25 @@
5703
5792
  }
5704
5793
  /**
5705
5794
  * ajax劫持库,支持xhr和fetch劫持。
5706
- * + 来源:https://bbs.tampermonkey.net.cn/thread-3284-1-1.html
5707
- * + 作者:cxxjackie
5708
- * + 版本:1.4.8
5709
- * + 旧版本:1.2.4
5710
- * + 文档:https://scriptcat.org/zh-CN/script-show-page/637/
5711
- * @param useOldVersion 是否使用旧版本,默认false
5712
- */
5713
- ajaxHooker = (useOldVersion = false) => {
5714
- if (useOldVersion) {
5715
- return AjaxHooker1_2_4();
5716
- }
5717
- else {
5718
- return ajaxHooker();
5719
- }
5795
+ * + 来源: https://bbs.tampermonkey.net.cn/thread-3284-1-1.html
5796
+ * + 作者: cxxjackie
5797
+ * + 实现方式: Proxy
5798
+ * + 版本: `1.4.8`
5799
+ * + 文档: https://scriptcat.org/zh-CN/script-show-page/637/
5800
+ */
5801
+ ajaxHooker = () => {
5802
+ return ajaxHooker();
5803
+ };
5804
+ /**
5805
+ * ajax劫持库,支持xhr和fetch劫持。
5806
+ * + 来源: https://bbs.tampermonkey.net.cn/thread-3284-1-1.html
5807
+ * + 作者: cxxjackie
5808
+ * + 实现方式: Object.defineProperty
5809
+ * + 版本: `1.2.4`
5810
+ * + 文档: https://scriptcat.org/zh-CN/script-show-page/637/
5811
+ */
5812
+ oldAjaxHooker = () => {
5813
+ return AjaxHooker1_2_4();
5720
5814
  };
5721
5815
  canvasClickByPosition(canvasElement, clientX = 0, clientY = 0, view = this.windowApi.window) {
5722
5816
  if (!(canvasElement instanceof HTMLCanvasElement)) {
@@ -7241,6 +7335,26 @@
7241
7335
  }
7242
7336
  return content;
7243
7337
  }
7338
+ /**
7339
+ * 监听页面元素改变并处理
7340
+ * @param target 需要监听的元素,如果不存在,可以等待它出现
7341
+ * @param observer_config MutationObserver的配置
7342
+ * @example
7343
+ Utils.mutationObserver(document.querySelector("div.xxxx"),{
7344
+ "callback":(mutations, observer)=>{},
7345
+ "config":{childList:true,attributes:true}
7346
+ });
7347
+ * @example
7348
+ Utils.mutationObserver(document.querySelectorAll("div.xxxx"),{
7349
+ "callback":(mutations, observer)=>{},
7350
+ "config":{childList:true,attributes:true}}
7351
+ );
7352
+ * @example
7353
+ Utils.mutationObserver($("div.xxxx"),{
7354
+ "callback":(mutations, observer)=>{},
7355
+ "config":{childList:true,attributes:true}}
7356
+ );
7357
+ **/
7244
7358
  mutationObserver(target, observer_config) {
7245
7359
  const that = this;
7246
7360
  const default_obverser_config = {
@@ -7283,16 +7397,24 @@
7283
7397
  characterDataOldValue: void 0,
7284
7398
  },
7285
7399
  immediate: false,
7400
+ once: false,
7286
7401
  };
7287
7402
  observer_config = that.assign(default_obverser_config, observer_config);
7288
7403
  const windowMutationObserver = this.windowApi.window.MutationObserver ||
7289
7404
  this.windowApi.window.webkitMutationObserver ||
7290
7405
  this.windowApi.window.MozMutationObserver;
7291
7406
  // 观察者对象
7292
- const mutationObserver = new windowMutationObserver(function (mutations, observer) {
7407
+ const handler = (mutations, observer) => {
7408
+ if (observer_config.once) {
7409
+ // 仅触发一次
7410
+ observer.disconnect();
7411
+ }
7293
7412
  if (typeof observer_config.callback === "function") {
7294
7413
  observer_config.callback(mutations, observer);
7295
7414
  }
7415
+ };
7416
+ const mutationObserver = new windowMutationObserver(function (mutations, observer) {
7417
+ handler(mutations, observer);
7296
7418
  });
7297
7419
  if (Array.isArray(target) || target instanceof NodeList) {
7298
7420
  // 传入的是数组或者元素数组
@@ -7301,7 +7423,7 @@
7301
7423
  });
7302
7424
  }
7303
7425
  else if (that.isJQuery(target)) {
7304
- /* 传入的参数是jQuery对象 */
7426
+ // 传入的参数是jQuery对象
7305
7427
  target.each((_, item) => {
7306
7428
  mutationObserver.observe(item, observer_config.config);
7307
7429
  });
@@ -7310,16 +7432,14 @@
7310
7432
  mutationObserver.observe(target, observer_config.config);
7311
7433
  }
7312
7434
  if (observer_config.immediate) {
7313
- /* 主动触发一次 */
7314
- if (typeof observer_config.callback === "function") {
7315
- observer_config.callback([], mutationObserver);
7316
- }
7435
+ // 主动触发一次
7436
+ handler([], mutationObserver);
7317
7437
  }
7318
7438
  return mutationObserver;
7319
7439
  }
7320
7440
  /**
7321
7441
  * 使用观察器观察元素出现在视图内,出现的话触发回调
7322
- * @param target 目标元素
7442
+ * @param $el 目标元素
7323
7443
  * @param callback 触发的回调
7324
7444
  * @param options 观察器配置
7325
7445
  * @example
@@ -7327,34 +7447,47 @@
7327
7447
  * console.log("该元素出现在视图内");
7328
7448
  * }))
7329
7449
  */
7330
- mutationVisible(target, callback, options) {
7450
+ mutationVisible($el, callback, options) {
7331
7451
  if (typeof IntersectionObserver === "undefined") {
7332
7452
  throw new TypeError("IntersectionObserver is not defined");
7333
7453
  }
7334
- if (target == null) {
7454
+ if ($el == null) {
7335
7455
  throw new TypeError("mutatuinVisible target is null");
7336
7456
  }
7457
+ options = options || {};
7337
7458
  let defaultOptions = {
7338
7459
  root: null,
7339
7460
  rootMargin: "0px 0px 0px 0px",
7340
7461
  threshold: [0.01, 0.99],
7341
7462
  };
7342
- defaultOptions = this.assign(defaultOptions, options || {});
7463
+ defaultOptions = this.assign(defaultOptions, options);
7464
+ const handler = (entries, observer) => {
7465
+ if (options.once) {
7466
+ // 仅触发一次
7467
+ observer.disconnect();
7468
+ }
7469
+ if (typeof callback === "function") {
7470
+ callback(entries, observer);
7471
+ }
7472
+ };
7343
7473
  const intersectionObserver = new IntersectionObserver((entries, observer) => {
7344
7474
  if (entries[0].isIntersecting) {
7345
- if (typeof callback === "function") {
7346
- callback(entries, observer);
7347
- }
7475
+ handler(entries, observer);
7348
7476
  }
7349
7477
  }, defaultOptions);
7350
- if (Array.isArray(target)) {
7351
- target.forEach((item) => {
7352
- intersectionObserver.observe(item);
7478
+ if (Array.isArray($el)) {
7479
+ $el.forEach(($elItem) => {
7480
+ intersectionObserver.observe($elItem);
7353
7481
  });
7354
7482
  }
7355
7483
  else {
7356
- intersectionObserver.observe(target);
7484
+ intersectionObserver.observe($el);
7357
7485
  }
7486
+ if (options.immediate) {
7487
+ // 立即触发
7488
+ handler([], intersectionObserver);
7489
+ }
7490
+ return intersectionObserver;
7358
7491
  }
7359
7492
  /**
7360
7493
  * 去除全局window下的Utils,返回控制权
@@ -8143,12 +8276,25 @@
8143
8276
  }
8144
8277
  /**
8145
8278
  * 将UrlSearchParams格式的字符串转为对象
8279
+ * @param searhParamsStr 字符串或对象
8280
+ * @example
8281
+ * Utils.searchParamStrToObj("xxx=xx&xx2=xx2")
8282
+ * @example
8283
+ * Utils.searchParamStrToObj(new URLSearchParams({
8284
+ * test1: 1,
8285
+ * test2: 2
8286
+ * }))
8146
8287
  */
8147
8288
  searchParamStrToObj(searhParamsStr) {
8148
- if (typeof searhParamsStr !== "string") {
8149
- return {};
8289
+ const params = {};
8290
+ if (searhParamsStr == null) {
8291
+ return params;
8150
8292
  }
8151
- return Object.fromEntries(new URLSearchParams(searhParamsStr));
8293
+ const urlSearchParams = searhParamsStr instanceof URLSearchParams ? searhParamsStr : new URLSearchParams(searhParamsStr);
8294
+ urlSearchParams.forEach((value, key) => {
8295
+ Reflect.set(params, key, value);
8296
+ });
8297
+ return params;
8152
8298
  }
8153
8299
  /**
8154
8300
  * 提供一个封装了 try-catch 的函数,可以执行传入的函数并捕获其可能抛出的错误,并通过传入的错误处理函数进行处理。