@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.esm.js CHANGED
@@ -237,7 +237,7 @@ const clearTimeout$1 = (timerId) => loadOrReturnBroker().clearTimeout(timerId);
237
237
  const setInterval$1 = (...args) => loadOrReturnBroker().setInterval(...args);
238
238
  const setTimeout$1 = (...args) => loadOrReturnBroker().setTimeout(...args);
239
239
 
240
- const version = "2.11.11";
240
+ const version = "2.11.12";
241
241
 
242
242
  /* eslint-disable */
243
243
  // ==UserScript==
@@ -372,8 +372,12 @@ const ajaxHooker = function () {
372
372
  }));
373
373
  }
374
374
  waitForRequestKeys() {
375
+ /**
376
+ * @type {Set<typeof hookInst>}
377
+ */
378
+ const winHookInsts = win.__ajaxHooker.hookInsts;
375
379
  if (!this.request.async) {
376
- win.__ajaxHooker.hookInsts.forEach(({ hookFns, filters }) => {
380
+ winHookInsts.forEach(({ hookFns, filters }) => {
377
381
  if (this.shouldFilter(filters))
378
382
  return;
379
383
  hookFns.forEach((fn) => {
@@ -389,10 +393,10 @@ const ajaxHooker = function () {
389
393
  }
390
394
  const promises = [];
391
395
  const ignoreKeys = new Set(["type", "async", "response"]);
392
- win.__ajaxHooker.hookInsts.forEach(({ hookFns, filters }) => {
396
+ winHookInsts.forEach(({ hookFns, filters }) => {
393
397
  if (this.shouldFilter(filters))
394
398
  return;
395
- promises.push(Promise.all(hookFns.map((fn) => catchError(fn, this.request))).then(() => {
399
+ promises.push(Promise.all(hookFns.map((fn, index) => catchError(fn, this.request, index))).then(() => {
396
400
  const requestKeys = [];
397
401
  for (const key in this.request)
398
402
  !ignoreKeys.has(key) && requestKeys.push(key);
@@ -814,11 +818,52 @@ const ajaxHooker = function () {
814
818
  });
815
819
  });
816
820
  }
821
+ /**
822
+ *
823
+ * @type {import("./../types/ajaxHooker.d.ts").UtilsAjaxHookResult["removeHook"]}
824
+ */
825
+ const removeHook = (fn, onlyRemove = false) => {
826
+ let flag = false;
827
+ for (let index = hookInst.hookFns.length - 1; index >= 0; index--) {
828
+ const __fn__ = hookInst.hookFns[index];
829
+ if (fn === __fn__) {
830
+ hookInst.hookFns.splice(index, 1);
831
+ flag = true;
832
+ if (onlyRemove) {
833
+ break;
834
+ }
835
+ }
836
+ }
837
+ return flag;
838
+ };
839
+ /**
840
+ *
841
+ * @type {import("./../types/ajaxHooker.d.ts").UtilsAjaxHookResult["removeFilter"]}
842
+ */
843
+ const removeFilter = () => {
844
+ if (Array.isArray(hookInst.filters)) {
845
+ hookInst.filters.length = 0;
846
+ }
847
+ else {
848
+ hookInst.filters = [];
849
+ }
850
+ };
817
851
  return {
818
- hook: (fn) => hookInst.hookFns.push(fn),
852
+ hook: (fn) => {
853
+ hookInst.hookFns.push(fn);
854
+ return {
855
+ remove: () => {
856
+ return removeHook(fn, true);
857
+ }
858
+ };
859
+ },
819
860
  filter: (arr) => {
820
- if (Array.isArray(arr))
861
+ if (Array.isArray(arr)) {
821
862
  hookInst.filters = arr;
863
+ }
864
+ return {
865
+ remove: removeFilter
866
+ };
822
867
  },
823
868
  protect: () => {
824
869
  readonly(win, "XMLHttpRequest", winAh.fakeXHR);
@@ -834,6 +879,8 @@ const ajaxHooker = function () {
834
879
  delete win.__ajaxHooker;
835
880
  }
836
881
  },
882
+ removeHook: removeHook,
883
+ removeFilter: removeFilter
837
884
  };
838
885
  };
839
886
 
@@ -1232,10 +1279,50 @@ const AjaxHooker1_2_4 = function () {
1232
1279
  Object.keys(realXhr).forEach((key) => (fakeXhr[key] = realXhr[key]));
1233
1280
  fakeXhr.prototype = realXhr.prototype;
1234
1281
  win.fetch = fakeFetch;
1282
+ /**
1283
+ *
1284
+ * @type {import("./../types/ajaxHooker.d.ts").UtilsAjaxHookResult["removeHook"]}
1285
+ */
1286
+ const removeHook = (fn, onlyRemove = false) => {
1287
+ let flag = false;
1288
+ for (let index = hookFns.length - 1; index >= 0; index--) {
1289
+ const __fn__ = hookFns[index];
1290
+ if (fn === __fn__) {
1291
+ hookFns.splice(index, 1);
1292
+ flag = true;
1293
+ if (onlyRemove) {
1294
+ break;
1295
+ }
1296
+ }
1297
+ }
1298
+ return flag;
1299
+ };
1300
+ /**
1301
+ *
1302
+ * @type {import("./../types/ajaxHooker.d.ts").UtilsAjaxHookResult["removeFilter"]}
1303
+ */
1304
+ const removeFilter = () => {
1305
+ if (Array.isArray(filter)) {
1306
+ filter.length = 0;
1307
+ }
1308
+ else {
1309
+ filter = void 0;
1310
+ }
1311
+ };
1235
1312
  return {
1236
- hook: (fn) => hookFns.push(fn),
1313
+ hook: (fn) => {
1314
+ hookFns.push(fn);
1315
+ return {
1316
+ remove: () => {
1317
+ return removeHook(fn, true);
1318
+ }
1319
+ };
1320
+ },
1237
1321
  filter: (arr) => {
1238
1322
  filter = Array.isArray(arr) && arr.map(toFilterObj);
1323
+ return {
1324
+ remove: removeFilter
1325
+ };
1239
1326
  },
1240
1327
  protect: () => {
1241
1328
  readonly(win, "XMLHttpRequest", fakeXhr);
@@ -1245,6 +1332,8 @@ const AjaxHooker1_2_4 = function () {
1245
1332
  writable(win, "XMLHttpRequest", realXhr);
1246
1333
  writable(win, "fetch", realFetch);
1247
1334
  },
1335
+ removeHook: removeHook,
1336
+ removeFilter: removeFilter
1248
1337
  };
1249
1338
  })();
1250
1339
  };
@@ -2669,42 +2758,42 @@ class Httpx {
2669
2758
  const method = requestOption.method;
2670
2759
  if (method === "GET" || method === "HEAD") {
2671
2760
  // GET类型,data如果有,那么需要转为searchParams
2672
- const urlObj = new URL(requestOption.url);
2761
+ const urlInst = new URL(requestOption.url);
2673
2762
  let urlSearch = "";
2674
- let isHandler = false;
2763
+ let deleteData = false;
2675
2764
  if (typeof requestOption.data === "string") {
2676
- isHandler = true;
2765
+ deleteData = true;
2677
2766
  urlSearch = requestOption.data;
2678
2767
  }
2679
2768
  else if (typeof requestOption.data === "object") {
2680
- isHandler = true;
2769
+ deleteData = true;
2681
2770
  // URLSearchParams参数可以转普通的string:string,包括FormData
2682
2771
  const searchParams = new URLSearchParams(requestOption.data);
2683
2772
  urlSearch = searchParams.toString();
2684
2773
  }
2685
- if (isHandler) {
2774
+ if (deleteData) {
2686
2775
  // GET/HEAD请求不支持data参数
2687
2776
  // 对data进行处理了才可以删除
2688
2777
  Reflect.deleteProperty(requestOption, "data");
2689
2778
  }
2690
- if (urlSearch != "") {
2691
- if (urlObj.search === "") {
2779
+ if (urlSearch.trim() != "") {
2780
+ if (urlInst.search.trim() === "") {
2692
2781
  // url没有search参数,直接覆盖
2693
- urlObj.search = urlSearch;
2782
+ urlInst.search = urlSearch;
2694
2783
  }
2695
2784
  else {
2696
2785
  // 有search参数
2697
- if (urlObj.search.endsWith("&")) {
2786
+ if (urlInst.search.trim().endsWith("&")) {
2698
2787
  // xxx=xxx&
2699
- urlObj.search = urlObj.search + urlSearch;
2788
+ urlInst.search = urlInst.search + urlSearch;
2700
2789
  }
2701
2790
  else {
2702
2791
  // xxx=xxx&xxx=
2703
- urlObj.search = `${urlObj.search}&${urlSearch}`;
2792
+ urlInst.search = `${urlInst.search}&${urlSearch}`;
2704
2793
  }
2705
2794
  }
2706
2795
  }
2707
- requestOption.url = urlObj.toString();
2796
+ requestOption.url = urlInst.toString();
2708
2797
  }
2709
2798
  else if (method === "POST" && requestOption.headers != null) {
2710
2799
  // POST类型,data如果是FormData,那么需要转为string
@@ -2714,10 +2803,10 @@ class Httpx {
2714
2803
  typeof requestOption.headers[headerKey] === "string");
2715
2804
  });
2716
2805
  if (ContentTypeIndex !== -1) {
2717
- const ContentTypeKey = headersKeyList[ContentTypeIndex];
2718
- const ContentType = requestOption.headers[ContentTypeKey];
2806
+ const contentTypeKey = headersKeyList[ContentTypeIndex];
2807
+ const contentType = requestOption.headers[contentTypeKey].toLowerCase();
2719
2808
  // 设置了Content-Type
2720
- if (ContentType.includes("application/json")) {
2809
+ if (contentType.includes("application/json")) {
2721
2810
  // application/json
2722
2811
  if (requestOption.data instanceof FormData) {
2723
2812
  const entries = {};
@@ -2730,16 +2819,16 @@ class Httpx {
2730
2819
  requestOption.data = JSON.stringify(requestOption.data);
2731
2820
  }
2732
2821
  }
2733
- else if (ContentType.includes("application/x-www-form-urlencoded")) {
2822
+ else if (contentType.includes("application/x-www-form-urlencoded")) {
2734
2823
  // application/x-www-form-urlencoded
2735
2824
  if (typeof requestOption.data === "object") {
2736
2825
  requestOption.data = new URLSearchParams(requestOption.data).toString();
2737
2826
  }
2738
2827
  }
2739
- else if (ContentType.includes("multipart/form-data")) {
2828
+ else if (contentType.includes("multipart/form-data")) {
2740
2829
  // multipart/form-data
2741
2830
  if (requestOption.data instanceof FormData) {
2742
- Reflect.deleteProperty(requestOption.headers, ContentTypeKey);
2831
+ Reflect.deleteProperty(requestOption.headers, contentTypeKey);
2743
2832
  }
2744
2833
  }
2745
2834
  }
@@ -5697,20 +5786,25 @@ class Utils {
5697
5786
  }
5698
5787
  /**
5699
5788
  * ajax劫持库,支持xhr和fetch劫持。
5700
- * + 来源:https://bbs.tampermonkey.net.cn/thread-3284-1-1.html
5701
- * + 作者:cxxjackie
5702
- * + 版本:1.4.8
5703
- * + 旧版本:1.2.4
5704
- * + 文档:https://scriptcat.org/zh-CN/script-show-page/637/
5705
- * @param useOldVersion 是否使用旧版本,默认false
5706
- */
5707
- ajaxHooker = (useOldVersion = false) => {
5708
- if (useOldVersion) {
5709
- return AjaxHooker1_2_4();
5710
- }
5711
- else {
5712
- return ajaxHooker();
5713
- }
5789
+ * + 来源: https://bbs.tampermonkey.net.cn/thread-3284-1-1.html
5790
+ * + 作者: cxxjackie
5791
+ * + 实现方式: Proxy
5792
+ * + 版本: `1.4.8`
5793
+ * + 文档: https://scriptcat.org/zh-CN/script-show-page/637/
5794
+ */
5795
+ ajaxHooker = () => {
5796
+ return ajaxHooker();
5797
+ };
5798
+ /**
5799
+ * ajax劫持库,支持xhr和fetch劫持。
5800
+ * + 来源: https://bbs.tampermonkey.net.cn/thread-3284-1-1.html
5801
+ * + 作者: cxxjackie
5802
+ * + 实现方式: Object.defineProperty
5803
+ * + 版本: `1.2.4`
5804
+ * + 文档: https://scriptcat.org/zh-CN/script-show-page/637/
5805
+ */
5806
+ oldAjaxHooker = () => {
5807
+ return AjaxHooker1_2_4();
5714
5808
  };
5715
5809
  canvasClickByPosition(canvasElement, clientX = 0, clientY = 0, view = this.windowApi.window) {
5716
5810
  if (!(canvasElement instanceof HTMLCanvasElement)) {
@@ -7235,6 +7329,26 @@ class Utils {
7235
7329
  }
7236
7330
  return content;
7237
7331
  }
7332
+ /**
7333
+ * 监听页面元素改变并处理
7334
+ * @param target 需要监听的元素,如果不存在,可以等待它出现
7335
+ * @param observer_config MutationObserver的配置
7336
+ * @example
7337
+ Utils.mutationObserver(document.querySelector("div.xxxx"),{
7338
+ "callback":(mutations, observer)=>{},
7339
+ "config":{childList:true,attributes:true}
7340
+ });
7341
+ * @example
7342
+ Utils.mutationObserver(document.querySelectorAll("div.xxxx"),{
7343
+ "callback":(mutations, observer)=>{},
7344
+ "config":{childList:true,attributes:true}}
7345
+ );
7346
+ * @example
7347
+ Utils.mutationObserver($("div.xxxx"),{
7348
+ "callback":(mutations, observer)=>{},
7349
+ "config":{childList:true,attributes:true}}
7350
+ );
7351
+ **/
7238
7352
  mutationObserver(target, observer_config) {
7239
7353
  const that = this;
7240
7354
  const default_obverser_config = {
@@ -7277,16 +7391,24 @@ class Utils {
7277
7391
  characterDataOldValue: void 0,
7278
7392
  },
7279
7393
  immediate: false,
7394
+ once: false,
7280
7395
  };
7281
7396
  observer_config = that.assign(default_obverser_config, observer_config);
7282
7397
  const windowMutationObserver = this.windowApi.window.MutationObserver ||
7283
7398
  this.windowApi.window.webkitMutationObserver ||
7284
7399
  this.windowApi.window.MozMutationObserver;
7285
7400
  // 观察者对象
7286
- const mutationObserver = new windowMutationObserver(function (mutations, observer) {
7401
+ const handler = (mutations, observer) => {
7402
+ if (observer_config.once) {
7403
+ // 仅触发一次
7404
+ observer.disconnect();
7405
+ }
7287
7406
  if (typeof observer_config.callback === "function") {
7288
7407
  observer_config.callback(mutations, observer);
7289
7408
  }
7409
+ };
7410
+ const mutationObserver = new windowMutationObserver(function (mutations, observer) {
7411
+ handler(mutations, observer);
7290
7412
  });
7291
7413
  if (Array.isArray(target) || target instanceof NodeList) {
7292
7414
  // 传入的是数组或者元素数组
@@ -7295,7 +7417,7 @@ class Utils {
7295
7417
  });
7296
7418
  }
7297
7419
  else if (that.isJQuery(target)) {
7298
- /* 传入的参数是jQuery对象 */
7420
+ // 传入的参数是jQuery对象
7299
7421
  target.each((_, item) => {
7300
7422
  mutationObserver.observe(item, observer_config.config);
7301
7423
  });
@@ -7304,16 +7426,14 @@ class Utils {
7304
7426
  mutationObserver.observe(target, observer_config.config);
7305
7427
  }
7306
7428
  if (observer_config.immediate) {
7307
- /* 主动触发一次 */
7308
- if (typeof observer_config.callback === "function") {
7309
- observer_config.callback([], mutationObserver);
7310
- }
7429
+ // 主动触发一次
7430
+ handler([], mutationObserver);
7311
7431
  }
7312
7432
  return mutationObserver;
7313
7433
  }
7314
7434
  /**
7315
7435
  * 使用观察器观察元素出现在视图内,出现的话触发回调
7316
- * @param target 目标元素
7436
+ * @param $el 目标元素
7317
7437
  * @param callback 触发的回调
7318
7438
  * @param options 观察器配置
7319
7439
  * @example
@@ -7321,34 +7441,47 @@ class Utils {
7321
7441
  * console.log("该元素出现在视图内");
7322
7442
  * }))
7323
7443
  */
7324
- mutationVisible(target, callback, options) {
7444
+ mutationVisible($el, callback, options) {
7325
7445
  if (typeof IntersectionObserver === "undefined") {
7326
7446
  throw new TypeError("IntersectionObserver is not defined");
7327
7447
  }
7328
- if (target == null) {
7448
+ if ($el == null) {
7329
7449
  throw new TypeError("mutatuinVisible target is null");
7330
7450
  }
7451
+ options = options || {};
7331
7452
  let defaultOptions = {
7332
7453
  root: null,
7333
7454
  rootMargin: "0px 0px 0px 0px",
7334
7455
  threshold: [0.01, 0.99],
7335
7456
  };
7336
- defaultOptions = this.assign(defaultOptions, options || {});
7457
+ defaultOptions = this.assign(defaultOptions, options);
7458
+ const handler = (entries, observer) => {
7459
+ if (options.once) {
7460
+ // 仅触发一次
7461
+ observer.disconnect();
7462
+ }
7463
+ if (typeof callback === "function") {
7464
+ callback(entries, observer);
7465
+ }
7466
+ };
7337
7467
  const intersectionObserver = new IntersectionObserver((entries, observer) => {
7338
7468
  if (entries[0].isIntersecting) {
7339
- if (typeof callback === "function") {
7340
- callback(entries, observer);
7341
- }
7469
+ handler(entries, observer);
7342
7470
  }
7343
7471
  }, defaultOptions);
7344
- if (Array.isArray(target)) {
7345
- target.forEach((item) => {
7346
- intersectionObserver.observe(item);
7472
+ if (Array.isArray($el)) {
7473
+ $el.forEach(($elItem) => {
7474
+ intersectionObserver.observe($elItem);
7347
7475
  });
7348
7476
  }
7349
7477
  else {
7350
- intersectionObserver.observe(target);
7478
+ intersectionObserver.observe($el);
7351
7479
  }
7480
+ if (options.immediate) {
7481
+ // 立即触发
7482
+ handler([], intersectionObserver);
7483
+ }
7484
+ return intersectionObserver;
7352
7485
  }
7353
7486
  /**
7354
7487
  * 去除全局window下的Utils,返回控制权
@@ -8137,12 +8270,25 @@ class Utils {
8137
8270
  }
8138
8271
  /**
8139
8272
  * 将UrlSearchParams格式的字符串转为对象
8273
+ * @param searhParamsStr 字符串或对象
8274
+ * @example
8275
+ * Utils.searchParamStrToObj("xxx=xx&xx2=xx2")
8276
+ * @example
8277
+ * Utils.searchParamStrToObj(new URLSearchParams({
8278
+ * test1: 1,
8279
+ * test2: 2
8280
+ * }))
8140
8281
  */
8141
8282
  searchParamStrToObj(searhParamsStr) {
8142
- if (typeof searhParamsStr !== "string") {
8143
- return {};
8283
+ const params = {};
8284
+ if (searhParamsStr == null) {
8285
+ return params;
8144
8286
  }
8145
- return Object.fromEntries(new URLSearchParams(searhParamsStr));
8287
+ const urlSearchParams = searhParamsStr instanceof URLSearchParams ? searhParamsStr : new URLSearchParams(searhParamsStr);
8288
+ urlSearchParams.forEach((value, key) => {
8289
+ Reflect.set(params, key, value);
8290
+ });
8291
+ return params;
8146
8292
  }
8147
8293
  /**
8148
8294
  * 提供一个封装了 try-catch 的函数,可以执行传入的函数并捕获其可能抛出的错误,并通过传入的错误处理函数进行处理。