@whitesev/utils 1.0.1 → 1.0.3
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/README.md +5 -3
- package/dist/index.amd.js +6037 -0
- package/dist/index.amd.js.map +1 -0
- package/dist/index.cjs.js +518 -505
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.esm.js +518 -505
- package/dist/index.esm.js.map +1 -1
- package/dist/index.iife.js +6038 -0
- package/dist/index.iife.js.map +1 -0
- package/dist/index.system.js +6040 -0
- package/dist/index.system.js.map +1 -0
- package/dist/index.umd.js +518 -505
- package/dist/index.umd.js.map +1 -1
- package/dist/src/ajaxHooker.d.ts +6 -6
- package/package.json +2 -1
- package/rollup.config.js +21 -1
- package/src/Utils.ts +3 -3
- package/src/ajaxHooker.js +518 -505
package/dist/index.cjs.js
CHANGED
|
@@ -370,188 +370,188 @@ class UtilsGMCookie {
|
|
|
370
370
|
}
|
|
371
371
|
}
|
|
372
372
|
|
|
373
|
-
// ==UserScript==
|
|
374
373
|
// @name ajaxHooker
|
|
375
374
|
// @author cxxjackie
|
|
376
375
|
// @version 1.4.1
|
|
377
376
|
// @supportURL https://bbs.tampermonkey.net.cn/thread-3284-1-1.html
|
|
378
|
-
// ==/UserScript==
|
|
379
377
|
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
function catchError(fn, ...args) {
|
|
419
|
-
try {
|
|
420
|
-
const result = fn(...args);
|
|
421
|
-
if (isThenable(result)) return result.then(null, errorFn);
|
|
422
|
-
return result;
|
|
423
|
-
} catch (err) {
|
|
424
|
-
console.error(err);
|
|
378
|
+
const AjaxHooker = function () {
|
|
379
|
+
return (function () {
|
|
380
|
+
const version = "1.4.1";
|
|
381
|
+
const hookInst = {
|
|
382
|
+
hookFns: [],
|
|
383
|
+
filters: [],
|
|
384
|
+
};
|
|
385
|
+
const win = window.unsafeWindow || document.defaultView || window;
|
|
386
|
+
let winAh = win.__ajaxHooker;
|
|
387
|
+
const resProto = win.Response.prototype;
|
|
388
|
+
const xhrResponses = ["response", "responseText", "responseXML"];
|
|
389
|
+
const fetchResponses = ["arrayBuffer", "blob", "formData", "json", "text"];
|
|
390
|
+
const fetchInitProps = [
|
|
391
|
+
"method",
|
|
392
|
+
"headers",
|
|
393
|
+
"body",
|
|
394
|
+
"mode",
|
|
395
|
+
"credentials",
|
|
396
|
+
"cache",
|
|
397
|
+
"redirect",
|
|
398
|
+
"referrer",
|
|
399
|
+
"referrerPolicy",
|
|
400
|
+
"integrity",
|
|
401
|
+
"keepalive",
|
|
402
|
+
"signal",
|
|
403
|
+
"priority",
|
|
404
|
+
];
|
|
405
|
+
const xhrAsyncEvents = ["readystatechange", "load", "loadend"];
|
|
406
|
+
const getType = {}.toString.call.bind({}.toString);
|
|
407
|
+
const getDescriptor = Object.getOwnPropertyDescriptor.bind(Object);
|
|
408
|
+
const emptyFn = () => {};
|
|
409
|
+
const errorFn = (e) => console.error(e);
|
|
410
|
+
function isThenable(obj) {
|
|
411
|
+
return (
|
|
412
|
+
obj &&
|
|
413
|
+
["object", "function"].includes(typeof obj) &&
|
|
414
|
+
typeof obj.then === "function"
|
|
415
|
+
);
|
|
425
416
|
}
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
}
|
|
435
|
-
function readonly(obj, prop, value = obj[prop]) {
|
|
436
|
-
defineProp(obj, prop, () => value, emptyFn);
|
|
437
|
-
}
|
|
438
|
-
function writable(obj, prop, value = obj[prop]) {
|
|
439
|
-
Object.defineProperty(obj, prop, {
|
|
440
|
-
configurable: true,
|
|
441
|
-
enumerable: true,
|
|
442
|
-
writable: true,
|
|
443
|
-
value: value,
|
|
444
|
-
});
|
|
445
|
-
}
|
|
446
|
-
function parseHeaders(obj) {
|
|
447
|
-
const headers = {};
|
|
448
|
-
switch (getType(obj)) {
|
|
449
|
-
case "[object String]":
|
|
450
|
-
for (const line of obj.trim().split(/[\r\n]+/)) {
|
|
451
|
-
const [header, value] = line.split(/\s*:\s*/);
|
|
452
|
-
if (!header) break;
|
|
453
|
-
const lheader = header.toLowerCase();
|
|
454
|
-
headers[lheader] =
|
|
455
|
-
lheader in headers ? `${headers[lheader]}, ${value}` : value;
|
|
456
|
-
}
|
|
457
|
-
break;
|
|
458
|
-
case "[object Headers]":
|
|
459
|
-
for (const [key, val] of obj) {
|
|
460
|
-
headers[key] = val;
|
|
461
|
-
}
|
|
462
|
-
break;
|
|
463
|
-
case "[object Object]":
|
|
464
|
-
return { ...obj };
|
|
417
|
+
function catchError(fn, ...args) {
|
|
418
|
+
try {
|
|
419
|
+
const result = fn(...args);
|
|
420
|
+
if (isThenable(result)) return result.then(null, errorFn);
|
|
421
|
+
return result;
|
|
422
|
+
} catch (err) {
|
|
423
|
+
console.error(err);
|
|
424
|
+
}
|
|
465
425
|
}
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
fn && fn();
|
|
474
|
-
return new SyncThenable();
|
|
426
|
+
function defineProp(obj, prop, getter, setter) {
|
|
427
|
+
Object.defineProperty(obj, prop, {
|
|
428
|
+
configurable: true,
|
|
429
|
+
enumerable: true,
|
|
430
|
+
get: getter,
|
|
431
|
+
set: setter,
|
|
432
|
+
});
|
|
475
433
|
}
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
constructor(request) {
|
|
479
|
-
this.request = request;
|
|
480
|
-
this.requestClone = { ...this.request };
|
|
434
|
+
function readonly(obj, prop, value = obj[prop]) {
|
|
435
|
+
defineProp(obj, prop, () => value, emptyFn);
|
|
481
436
|
}
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
437
|
+
function writable(obj, prop, value = obj[prop]) {
|
|
438
|
+
Object.defineProperty(obj, prop, {
|
|
439
|
+
configurable: true,
|
|
440
|
+
enumerable: true,
|
|
441
|
+
writable: true,
|
|
442
|
+
value: value,
|
|
443
|
+
});
|
|
444
|
+
}
|
|
445
|
+
function parseHeaders(obj) {
|
|
446
|
+
const headers = {};
|
|
447
|
+
switch (getType(obj)) {
|
|
448
|
+
case "[object String]":
|
|
449
|
+
for (const line of obj.trim().split(/[\r\n]+/)) {
|
|
450
|
+
const [header, value] = line.split(/\s*:\s*/);
|
|
451
|
+
if (!header) break;
|
|
452
|
+
const lheader = header.toLowerCase();
|
|
453
|
+
headers[lheader] =
|
|
454
|
+
lheader in headers ? `${headers[lheader]}, ${value}` : value;
|
|
496
455
|
}
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
456
|
+
break;
|
|
457
|
+
case "[object Headers]":
|
|
458
|
+
for (const [key, val] of obj) {
|
|
459
|
+
headers[key] = val;
|
|
460
|
+
}
|
|
461
|
+
break;
|
|
462
|
+
case "[object Object]":
|
|
463
|
+
return { ...obj };
|
|
464
|
+
}
|
|
465
|
+
return headers;
|
|
500
466
|
}
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
if (getType(fn) === "[object Function]")
|
|
508
|
-
catchError(fn, this.request);
|
|
509
|
-
});
|
|
510
|
-
requestKeys.forEach((key) => {
|
|
511
|
-
if (isThenable(this.request[key]))
|
|
512
|
-
this.request[key] = this.requestClone[key];
|
|
513
|
-
});
|
|
514
|
-
});
|
|
467
|
+
function stopImmediatePropagation() {
|
|
468
|
+
this.ajaxHooker_isStopped = true;
|
|
469
|
+
}
|
|
470
|
+
class SyncThenable {
|
|
471
|
+
then(fn) {
|
|
472
|
+
fn && fn();
|
|
515
473
|
return new SyncThenable();
|
|
516
474
|
}
|
|
517
|
-
const promises = [];
|
|
518
|
-
win.__ajaxHooker.hookInsts.forEach(({ hookFns, filters }) => {
|
|
519
|
-
if (this.shouldFilter(filters)) return;
|
|
520
|
-
promises.push(
|
|
521
|
-
Promise.all(hookFns.map((fn) => catchError(fn, this.request))).then(
|
|
522
|
-
() =>
|
|
523
|
-
Promise.all(
|
|
524
|
-
requestKeys.map((key) =>
|
|
525
|
-
Promise.resolve(this.request[key]).then(
|
|
526
|
-
(val) => (this.request[key] = val),
|
|
527
|
-
() => (this.request[key] = this.requestClone[key])
|
|
528
|
-
)
|
|
529
|
-
)
|
|
530
|
-
)
|
|
531
|
-
)
|
|
532
|
-
);
|
|
533
|
-
});
|
|
534
|
-
return Promise.all(promises);
|
|
535
475
|
}
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
this.request
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
) {
|
|
547
|
-
|
|
476
|
+
class AHRequest {
|
|
477
|
+
constructor(request) {
|
|
478
|
+
this.request = request;
|
|
479
|
+
this.requestClone = { ...this.request };
|
|
480
|
+
}
|
|
481
|
+
shouldFilter(filters) {
|
|
482
|
+
const { type, url, method, async } = this.request;
|
|
483
|
+
return (
|
|
484
|
+
filters.length &&
|
|
485
|
+
!filters.find((obj) => {
|
|
486
|
+
switch (true) {
|
|
487
|
+
case obj.type && obj.type !== type:
|
|
488
|
+
case getType(obj.url) === "[object String]" &&
|
|
489
|
+
!url.includes(obj.url):
|
|
490
|
+
case getType(obj.url) === "[object RegExp]" && !obj.url.test(url):
|
|
491
|
+
case obj.method &&
|
|
492
|
+
obj.method.toUpperCase() !== method.toUpperCase():
|
|
493
|
+
case "async" in obj && obj.async !== async:
|
|
494
|
+
return false;
|
|
548
495
|
}
|
|
496
|
+
return true;
|
|
497
|
+
})
|
|
498
|
+
);
|
|
499
|
+
}
|
|
500
|
+
waitForRequestKeys() {
|
|
501
|
+
const requestKeys = ["url", "method", "abort", "headers", "data"];
|
|
502
|
+
if (!this.request.async) {
|
|
503
|
+
win.__ajaxHooker.hookInsts.forEach(({ hookFns, filters }) => {
|
|
504
|
+
if (this.shouldFilter(filters)) return;
|
|
505
|
+
hookFns.forEach((fn) => {
|
|
506
|
+
if (getType(fn) === "[object Function]")
|
|
507
|
+
catchError(fn, this.request);
|
|
508
|
+
});
|
|
509
|
+
requestKeys.forEach((key) => {
|
|
510
|
+
if (isThenable(this.request[key]))
|
|
511
|
+
this.request[key] = this.requestClone[key];
|
|
512
|
+
});
|
|
549
513
|
});
|
|
514
|
+
return new SyncThenable();
|
|
550
515
|
}
|
|
551
|
-
|
|
516
|
+
const promises = [];
|
|
517
|
+
win.__ajaxHooker.hookInsts.forEach(({ hookFns, filters }) => {
|
|
518
|
+
if (this.shouldFilter(filters)) return;
|
|
519
|
+
promises.push(
|
|
520
|
+
Promise.all(hookFns.map((fn) => catchError(fn, this.request))).then(
|
|
521
|
+
() =>
|
|
522
|
+
Promise.all(
|
|
523
|
+
requestKeys.map((key) =>
|
|
524
|
+
Promise.resolve(this.request[key]).then(
|
|
525
|
+
(val) => (this.request[key] = val),
|
|
526
|
+
() => (this.request[key] = this.requestClone[key])
|
|
527
|
+
)
|
|
528
|
+
)
|
|
529
|
+
)
|
|
530
|
+
)
|
|
531
|
+
);
|
|
532
|
+
});
|
|
533
|
+
return Promise.all(promises);
|
|
552
534
|
}
|
|
553
|
-
|
|
554
|
-
|
|
535
|
+
waitForResponseKeys(response) {
|
|
536
|
+
const responseKeys =
|
|
537
|
+
this.request.type === "xhr" ? xhrResponses : fetchResponses;
|
|
538
|
+
if (!this.request.async) {
|
|
539
|
+
if (getType(this.request.response) === "[object Function]") {
|
|
540
|
+
catchError(this.request.response, response);
|
|
541
|
+
responseKeys.forEach((key) => {
|
|
542
|
+
if (
|
|
543
|
+
"get" in getDescriptor(response, key) ||
|
|
544
|
+
isThenable(response[key])
|
|
545
|
+
) {
|
|
546
|
+
delete response[key];
|
|
547
|
+
}
|
|
548
|
+
});
|
|
549
|
+
}
|
|
550
|
+
return new SyncThenable();
|
|
551
|
+
}
|
|
552
|
+
return Promise.resolve(
|
|
553
|
+
catchError(this.request.response, response)
|
|
554
|
+
).then(() =>
|
|
555
555
|
Promise.all(
|
|
556
556
|
responseKeys.map((key) => {
|
|
557
557
|
const descriptor = getDescriptor(response, key);
|
|
@@ -565,368 +565,381 @@ var ajaxHooker = (function () {
|
|
|
565
565
|
}
|
|
566
566
|
})
|
|
567
567
|
)
|
|
568
|
-
|
|
568
|
+
);
|
|
569
|
+
}
|
|
569
570
|
}
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
571
|
+
const proxyHandler = {
|
|
572
|
+
get(target, prop) {
|
|
573
|
+
const descriptor = getDescriptor(target, prop);
|
|
574
|
+
if (
|
|
575
|
+
descriptor &&
|
|
576
|
+
!descriptor.configurable &&
|
|
577
|
+
!descriptor.writable &&
|
|
578
|
+
!descriptor.get
|
|
579
|
+
)
|
|
580
|
+
return target[prop];
|
|
581
|
+
const ah = target.__ajaxHooker;
|
|
582
|
+
if (ah && ah.proxyProps) {
|
|
583
|
+
if (prop in ah.proxyProps) {
|
|
584
|
+
const pDescriptor = ah.proxyProps[prop];
|
|
585
|
+
if ("get" in pDescriptor) return pDescriptor.get();
|
|
586
|
+
if (typeof pDescriptor.value === "function")
|
|
587
|
+
return pDescriptor.value.bind(ah);
|
|
588
|
+
return pDescriptor.value;
|
|
589
|
+
}
|
|
590
|
+
if (typeof target[prop] === "function")
|
|
591
|
+
return target[prop].bind(target);
|
|
592
|
+
}
|
|
580
593
|
return target[prop];
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
594
|
+
},
|
|
595
|
+
set(target, prop, value) {
|
|
596
|
+
const descriptor = getDescriptor(target, prop);
|
|
597
|
+
if (
|
|
598
|
+
descriptor &&
|
|
599
|
+
!descriptor.configurable &&
|
|
600
|
+
!descriptor.writable &&
|
|
601
|
+
!descriptor.set
|
|
602
|
+
)
|
|
603
|
+
return true;
|
|
604
|
+
const ah = target.__ajaxHooker;
|
|
605
|
+
if (ah && ah.proxyProps && prop in ah.proxyProps) {
|
|
584
606
|
const pDescriptor = ah.proxyProps[prop];
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
607
|
+
pDescriptor.set
|
|
608
|
+
? pDescriptor.set(value)
|
|
609
|
+
: (pDescriptor.value = value);
|
|
610
|
+
} else {
|
|
611
|
+
target[prop] = value;
|
|
589
612
|
}
|
|
590
|
-
if (typeof target[prop] === "function")
|
|
591
|
-
return target[prop].bind(target);
|
|
592
|
-
}
|
|
593
|
-
return target[prop];
|
|
594
|
-
},
|
|
595
|
-
set(target, prop, value) {
|
|
596
|
-
const descriptor = getDescriptor(target, prop);
|
|
597
|
-
if (
|
|
598
|
-
descriptor &&
|
|
599
|
-
!descriptor.configurable &&
|
|
600
|
-
!descriptor.writable &&
|
|
601
|
-
!descriptor.set
|
|
602
|
-
)
|
|
603
613
|
return true;
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
614
|
+
},
|
|
615
|
+
};
|
|
616
|
+
class XhrHooker {
|
|
617
|
+
constructor(xhr) {
|
|
618
|
+
const ah = this;
|
|
619
|
+
Object.assign(ah, {
|
|
620
|
+
originalXhr: xhr,
|
|
621
|
+
proxyXhr: new Proxy(xhr, proxyHandler),
|
|
622
|
+
resThenable: new SyncThenable(),
|
|
623
|
+
proxyProps: {},
|
|
624
|
+
proxyEvents: {},
|
|
625
|
+
});
|
|
626
|
+
xhr.addEventListener("readystatechange", (e) => {
|
|
627
|
+
if (
|
|
628
|
+
ah.proxyXhr.readyState === 4 &&
|
|
629
|
+
ah.request &&
|
|
630
|
+
typeof ah.request.response === "function"
|
|
631
|
+
) {
|
|
632
|
+
const response = {
|
|
633
|
+
finalUrl: ah.proxyXhr.responseURL,
|
|
634
|
+
status: ah.proxyXhr.status,
|
|
635
|
+
responseHeaders: parseHeaders(
|
|
636
|
+
ah.proxyXhr.getAllResponseHeaders()
|
|
637
|
+
),
|
|
638
|
+
};
|
|
639
|
+
const tempValues = {};
|
|
640
|
+
for (const key of xhrResponses) {
|
|
641
|
+
try {
|
|
642
|
+
tempValues[key] = ah.originalXhr[key];
|
|
643
|
+
} catch (err) {}
|
|
644
|
+
defineProp(
|
|
645
|
+
response,
|
|
646
|
+
key,
|
|
647
|
+
() => {
|
|
648
|
+
return (response[key] = tempValues[key]);
|
|
649
|
+
},
|
|
650
|
+
(val) => {
|
|
651
|
+
delete response[key];
|
|
652
|
+
response[key] = val;
|
|
653
|
+
}
|
|
654
|
+
);
|
|
655
|
+
}
|
|
656
|
+
ah.resThenable = new AHRequest(ah.request)
|
|
657
|
+
.waitForResponseKeys(response)
|
|
658
|
+
.then(() => {
|
|
659
|
+
for (const key of xhrResponses) {
|
|
660
|
+
ah.proxyProps[key] = {
|
|
661
|
+
get: () => {
|
|
662
|
+
if (!(key in response)) response[key] = tempValues[key];
|
|
663
|
+
return response[key];
|
|
664
|
+
},
|
|
665
|
+
};
|
|
666
|
+
}
|
|
667
|
+
});
|
|
651
668
|
}
|
|
652
|
-
ah.
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
669
|
+
ah.dispatchEvent(e);
|
|
670
|
+
});
|
|
671
|
+
xhr.addEventListener("load", (e) => ah.dispatchEvent(e));
|
|
672
|
+
xhr.addEventListener("loadend", (e) => ah.dispatchEvent(e));
|
|
673
|
+
for (const evt of xhrAsyncEvents) {
|
|
674
|
+
const onEvt = "on" + evt;
|
|
675
|
+
ah.proxyProps[onEvt] = {
|
|
676
|
+
get: () => ah.proxyEvents[onEvt] || null,
|
|
677
|
+
set: (val) => ah.addEvent(onEvt, val),
|
|
678
|
+
};
|
|
679
|
+
}
|
|
680
|
+
for (const method of [
|
|
681
|
+
"setRequestHeader",
|
|
682
|
+
"addEventListener",
|
|
683
|
+
"removeEventListener",
|
|
684
|
+
"open",
|
|
685
|
+
"send",
|
|
686
|
+
]) {
|
|
687
|
+
ah.proxyProps[method] = { value: ah[method] };
|
|
664
688
|
}
|
|
665
|
-
ah.dispatchEvent(e);
|
|
666
|
-
});
|
|
667
|
-
xhr.addEventListener("load", (e) => ah.dispatchEvent(e));
|
|
668
|
-
xhr.addEventListener("loadend", (e) => ah.dispatchEvent(e));
|
|
669
|
-
for (const evt of xhrAsyncEvents) {
|
|
670
|
-
const onEvt = "on" + evt;
|
|
671
|
-
ah.proxyProps[onEvt] = {
|
|
672
|
-
get: () => ah.proxyEvents[onEvt] || null,
|
|
673
|
-
set: (val) => ah.addEvent(onEvt, val),
|
|
674
|
-
};
|
|
675
689
|
}
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
"
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
690
|
+
toJSON() {} // Converting circular structure to JSON
|
|
691
|
+
addEvent(type, event) {
|
|
692
|
+
if (type.startsWith("on")) {
|
|
693
|
+
this.proxyEvents[type] = typeof event === "function" ? event : null;
|
|
694
|
+
} else {
|
|
695
|
+
if (typeof event === "object" && event !== null)
|
|
696
|
+
event = event.handleEvent;
|
|
697
|
+
if (typeof event !== "function") return;
|
|
698
|
+
this.proxyEvents[type] = this.proxyEvents[type] || new Set();
|
|
699
|
+
this.proxyEvents[type].add(event);
|
|
700
|
+
}
|
|
684
701
|
}
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
if (typeof event !== "function") return;
|
|
694
|
-
this.proxyEvents[type] = this.proxyEvents[type] || new Set();
|
|
695
|
-
this.proxyEvents[type].add(event);
|
|
702
|
+
removeEvent(type, event) {
|
|
703
|
+
if (type.startsWith("on")) {
|
|
704
|
+
this.proxyEvents[type] = null;
|
|
705
|
+
} else {
|
|
706
|
+
if (typeof event === "object" && event !== null)
|
|
707
|
+
event = event.handleEvent;
|
|
708
|
+
this.proxyEvents[type] && this.proxyEvents[type].delete(event);
|
|
709
|
+
}
|
|
696
710
|
}
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
this.proxyEvents[type]
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
711
|
+
dispatchEvent(e) {
|
|
712
|
+
e.stopImmediatePropagation = stopImmediatePropagation;
|
|
713
|
+
defineProp(e, "target", () => this.proxyXhr);
|
|
714
|
+
this.proxyEvents[e.type] &&
|
|
715
|
+
this.proxyEvents[e.type].forEach((fn) => {
|
|
716
|
+
this.resThenable.then(
|
|
717
|
+
() => !e.ajaxHooker_isStopped && fn.call(this.proxyXhr, e)
|
|
718
|
+
);
|
|
719
|
+
});
|
|
720
|
+
if (e.ajaxHooker_isStopped) return;
|
|
721
|
+
const onEvent = this.proxyEvents["on" + e.type];
|
|
722
|
+
onEvent && this.resThenable.then(onEvent.bind(this.proxyXhr, e));
|
|
705
723
|
}
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
724
|
+
setRequestHeader(header, value) {
|
|
725
|
+
this.originalXhr.setRequestHeader(header, value);
|
|
726
|
+
if (this.originalXhr.readyState !== 1) return;
|
|
727
|
+
const headers = this.request.headers;
|
|
728
|
+
headers[header] =
|
|
729
|
+
header in headers ? `${headers[header]}, ${value}` : value;
|
|
730
|
+
}
|
|
731
|
+
addEventListener(...args) {
|
|
732
|
+
if (xhrAsyncEvents.includes(args[0])) {
|
|
733
|
+
this.addEvent(args[0], args[1]);
|
|
734
|
+
} else {
|
|
735
|
+
this.originalXhr.addEventListener(...args);
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
removeEventListener(...args) {
|
|
739
|
+
if (xhrAsyncEvents.includes(args[0])) {
|
|
740
|
+
this.removeEvent(args[0], args[1]);
|
|
741
|
+
} else {
|
|
742
|
+
this.originalXhr.removeEventListener(...args);
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
open(method, url, async = true, ...args) {
|
|
746
|
+
this.request = {
|
|
747
|
+
type: "xhr",
|
|
748
|
+
url: url.toString(),
|
|
749
|
+
method: method.toUpperCase(),
|
|
750
|
+
abort: false,
|
|
751
|
+
headers: {},
|
|
752
|
+
data: null,
|
|
753
|
+
response: null,
|
|
754
|
+
async: !!async,
|
|
755
|
+
};
|
|
756
|
+
this.openArgs = args;
|
|
757
|
+
this.resThenable = new SyncThenable();
|
|
758
|
+
[
|
|
759
|
+
"responseURL",
|
|
760
|
+
"readyState",
|
|
761
|
+
"status",
|
|
762
|
+
"statusText",
|
|
763
|
+
...xhrResponses,
|
|
764
|
+
].forEach((key) => {
|
|
765
|
+
delete this.proxyProps[key];
|
|
715
766
|
});
|
|
716
|
-
|
|
717
|
-
const onEvent = this.proxyEvents["on" + e.type];
|
|
718
|
-
onEvent && this.resThenable.then(onEvent.bind(this.proxyXhr, e));
|
|
719
|
-
}
|
|
720
|
-
setRequestHeader(header, value) {
|
|
721
|
-
this.originalXhr.setRequestHeader(header, value);
|
|
722
|
-
if (this.originalXhr.readyState !== 1) return;
|
|
723
|
-
const headers = this.request.headers;
|
|
724
|
-
headers[header] =
|
|
725
|
-
header in headers ? `${headers[header]}, ${value}` : value;
|
|
726
|
-
}
|
|
727
|
-
addEventListener(...args) {
|
|
728
|
-
if (xhrAsyncEvents.includes(args[0])) {
|
|
729
|
-
this.addEvent(args[0], args[1]);
|
|
730
|
-
} else {
|
|
731
|
-
this.originalXhr.addEventListener(...args);
|
|
767
|
+
return this.originalXhr.open(method, url, async, ...args);
|
|
732
768
|
}
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
769
|
+
send(data) {
|
|
770
|
+
const ah = this;
|
|
771
|
+
const xhr = ah.originalXhr;
|
|
772
|
+
const request = ah.request;
|
|
773
|
+
if (!request) return xhr.send(data);
|
|
774
|
+
request.data = data;
|
|
775
|
+
new AHRequest(request).waitForRequestKeys().then(() => {
|
|
776
|
+
if (request.abort) {
|
|
777
|
+
if (typeof request.response === "function") {
|
|
778
|
+
Object.assign(ah.proxyProps, {
|
|
779
|
+
responseURL: { value: request.url },
|
|
780
|
+
readyState: { value: 4 },
|
|
781
|
+
status: { value: 200 },
|
|
782
|
+
statusText: { value: "OK" },
|
|
783
|
+
});
|
|
784
|
+
xhrAsyncEvents.forEach((evt) =>
|
|
785
|
+
xhr.dispatchEvent(new Event(evt))
|
|
786
|
+
);
|
|
787
|
+
}
|
|
788
|
+
} else {
|
|
789
|
+
xhr.open(
|
|
790
|
+
request.method,
|
|
791
|
+
request.url,
|
|
792
|
+
request.async,
|
|
793
|
+
...ah.openArgs
|
|
794
|
+
);
|
|
795
|
+
for (const header in request.headers) {
|
|
796
|
+
xhr.setRequestHeader(header, request.headers[header]);
|
|
797
|
+
}
|
|
798
|
+
xhr.send(request.data);
|
|
799
|
+
}
|
|
800
|
+
});
|
|
739
801
|
}
|
|
740
802
|
}
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
803
|
+
function fakeXHR() {
|
|
804
|
+
const xhr = new winAh.realXHR();
|
|
805
|
+
if ("__ajaxHooker" in xhr)
|
|
806
|
+
console.warn("检测到不同版本的ajaxHooker,可能发生冲突!");
|
|
807
|
+
xhr.__ajaxHooker = new XhrHooker(xhr);
|
|
808
|
+
return xhr.__ajaxHooker.proxyXhr;
|
|
809
|
+
}
|
|
810
|
+
fakeXHR.prototype = win.XMLHttpRequest.prototype;
|
|
811
|
+
Object.keys(win.XMLHttpRequest).forEach(
|
|
812
|
+
(key) => (fakeXHR[key] = win.XMLHttpRequest[key])
|
|
813
|
+
);
|
|
814
|
+
function fakeFetch(url, options = {}) {
|
|
815
|
+
if (!url) return winAh.realFetch.call(win, url, options);
|
|
816
|
+
const init = {};
|
|
817
|
+
if (getType(url) === "[object Request]") {
|
|
818
|
+
for (const prop of fetchInitProps) init[prop] = url[prop];
|
|
819
|
+
url = url.url;
|
|
820
|
+
}
|
|
821
|
+
url = url.toString();
|
|
822
|
+
Object.assign(init, options);
|
|
823
|
+
init.method = init.method || "GET";
|
|
824
|
+
init.headers = init.headers || {};
|
|
825
|
+
const request = {
|
|
826
|
+
type: "fetch",
|
|
827
|
+
url: url,
|
|
828
|
+
method: init.method.toUpperCase(),
|
|
746
829
|
abort: false,
|
|
747
|
-
headers:
|
|
748
|
-
data:
|
|
830
|
+
headers: parseHeaders(init.headers),
|
|
831
|
+
data: init.body,
|
|
749
832
|
response: null,
|
|
750
|
-
async:
|
|
833
|
+
async: true,
|
|
751
834
|
};
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
835
|
+
const req = new AHRequest(request);
|
|
836
|
+
return new Promise((resolve, reject) => {
|
|
837
|
+
req
|
|
838
|
+
.waitForRequestKeys()
|
|
839
|
+
.then(() => {
|
|
840
|
+
if (request.abort) {
|
|
841
|
+
if (typeof request.response === "function") {
|
|
842
|
+
const response = {
|
|
843
|
+
finalUrl: request.url,
|
|
844
|
+
status: 200,
|
|
845
|
+
responseHeaders: {},
|
|
846
|
+
};
|
|
847
|
+
req.waitForResponseKeys(response).then(() => {
|
|
848
|
+
const key = fetchResponses.find((k) => k in response);
|
|
849
|
+
let val = response[key];
|
|
850
|
+
if (key === "json" && typeof val === "object") {
|
|
851
|
+
val = catchError(JSON.stringify.bind(JSON), val);
|
|
852
|
+
}
|
|
853
|
+
const res = new Response(val, {
|
|
854
|
+
status: 200,
|
|
855
|
+
statusText: "OK",
|
|
856
|
+
});
|
|
857
|
+
defineProp(res, "type", () => "basic");
|
|
858
|
+
defineProp(res, "url", () => request.url);
|
|
859
|
+
resolve(res);
|
|
860
|
+
});
|
|
861
|
+
} else {
|
|
862
|
+
reject(new DOMException("aborted", "AbortError"));
|
|
863
|
+
}
|
|
864
|
+
return;
|
|
865
|
+
}
|
|
866
|
+
init.method = request.method;
|
|
867
|
+
init.headers = request.headers;
|
|
868
|
+
init.body = request.data;
|
|
869
|
+
winAh.realFetch.call(win, request.url, init).then((res) => {
|
|
870
|
+
if (typeof request.response === "function") {
|
|
871
|
+
const response = {
|
|
872
|
+
finalUrl: res.url,
|
|
873
|
+
status: res.status,
|
|
874
|
+
responseHeaders: parseHeaders(res.headers),
|
|
875
|
+
};
|
|
876
|
+
fetchResponses.forEach(
|
|
877
|
+
(key) =>
|
|
878
|
+
(res[key] = function () {
|
|
879
|
+
if (key in response)
|
|
880
|
+
return Promise.resolve(response[key]);
|
|
881
|
+
return resProto[key].call(this).then((val) => {
|
|
882
|
+
response[key] = val;
|
|
883
|
+
return req
|
|
884
|
+
.waitForResponseKeys(response)
|
|
885
|
+
.then(() => (key in response ? response[key] : val));
|
|
886
|
+
});
|
|
887
|
+
})
|
|
888
|
+
);
|
|
889
|
+
}
|
|
890
|
+
resolve(res);
|
|
891
|
+
}, reject);
|
|
892
|
+
})
|
|
893
|
+
.catch((err) => {
|
|
894
|
+
console.error(err);
|
|
895
|
+
resolve(winAh.realFetch.call(win, url, init));
|
|
896
|
+
});
|
|
762
897
|
});
|
|
763
|
-
return this.originalXhr.open(method, url, async, ...args);
|
|
764
898
|
}
|
|
765
|
-
|
|
766
|
-
const
|
|
767
|
-
const
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
request.data = data;
|
|
771
|
-
new AHRequest(request).waitForRequestKeys().then(() => {
|
|
772
|
-
if (request.abort) {
|
|
773
|
-
if (typeof request.response === "function") {
|
|
774
|
-
Object.assign(ah.proxyProps, {
|
|
775
|
-
responseURL: { value: request.url },
|
|
776
|
-
readyState: { value: 4 },
|
|
777
|
-
status: { value: 200 },
|
|
778
|
-
statusText: { value: "OK" },
|
|
779
|
-
});
|
|
780
|
-
xhrAsyncEvents.forEach((evt) => xhr.dispatchEvent(new Event(evt)));
|
|
781
|
-
}
|
|
782
|
-
} else {
|
|
783
|
-
xhr.open(request.method, request.url, request.async, ...ah.openArgs);
|
|
784
|
-
for (const header in request.headers) {
|
|
785
|
-
xhr.setRequestHeader(header, request.headers[header]);
|
|
786
|
-
}
|
|
787
|
-
xhr.send(request.data);
|
|
788
|
-
}
|
|
789
|
-
});
|
|
899
|
+
function fakeFetchClone() {
|
|
900
|
+
const descriptors = Object.getOwnPropertyDescriptors(this);
|
|
901
|
+
const res = winAh.realFetchClone.call(this);
|
|
902
|
+
Object.defineProperties(res, descriptors);
|
|
903
|
+
return res;
|
|
790
904
|
}
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
905
|
+
winAh = win.__ajaxHooker = winAh || {
|
|
906
|
+
version,
|
|
907
|
+
fakeXHR,
|
|
908
|
+
fakeFetch,
|
|
909
|
+
fakeFetchClone,
|
|
910
|
+
realXHR: win.XMLHttpRequest,
|
|
911
|
+
realFetch: win.fetch,
|
|
912
|
+
realFetchClone: resProto.clone,
|
|
913
|
+
hookInsts: new Set(),
|
|
914
|
+
};
|
|
915
|
+
if (winAh.version !== version)
|
|
795
916
|
console.warn("检测到不同版本的ajaxHooker,可能发生冲突!");
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
headers: parseHeaders(init.headers),
|
|
820
|
-
data: init.body,
|
|
821
|
-
response: null,
|
|
822
|
-
async: true,
|
|
917
|
+
win.XMLHttpRequest = winAh.fakeXHR;
|
|
918
|
+
win.fetch = winAh.fakeFetch;
|
|
919
|
+
resProto.clone = winAh.fakeFetchClone;
|
|
920
|
+
winAh.hookInsts.add(hookInst);
|
|
921
|
+
return {
|
|
922
|
+
hook: (fn) => hookInst.hookFns.push(fn),
|
|
923
|
+
filter: (arr) => {
|
|
924
|
+
if (Array.isArray(arr)) hookInst.filters = arr;
|
|
925
|
+
},
|
|
926
|
+
protect: () => {
|
|
927
|
+
readonly(win, "XMLHttpRequest", winAh.fakeXHR);
|
|
928
|
+
readonly(win, "fetch", winAh.fakeFetch);
|
|
929
|
+
readonly(resProto, "clone", winAh.fakeFetchClone);
|
|
930
|
+
},
|
|
931
|
+
unhook: () => {
|
|
932
|
+
winAh.hookInsts.delete(hookInst);
|
|
933
|
+
if (!winAh.hookInsts.size) {
|
|
934
|
+
writable(win, "XMLHttpRequest", winAh.realXHR);
|
|
935
|
+
writable(win, "fetch", winAh.realFetch);
|
|
936
|
+
writable(resProto, "clone", winAh.realFetchClone);
|
|
937
|
+
delete win.__ajaxHooker;
|
|
938
|
+
}
|
|
939
|
+
},
|
|
823
940
|
};
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
req
|
|
827
|
-
.waitForRequestKeys()
|
|
828
|
-
.then(() => {
|
|
829
|
-
if (request.abort) {
|
|
830
|
-
if (typeof request.response === "function") {
|
|
831
|
-
const response = {
|
|
832
|
-
finalUrl: request.url,
|
|
833
|
-
status: 200,
|
|
834
|
-
responseHeaders: {},
|
|
835
|
-
};
|
|
836
|
-
req.waitForResponseKeys(response).then(() => {
|
|
837
|
-
const key = fetchResponses.find((k) => k in response);
|
|
838
|
-
let val = response[key];
|
|
839
|
-
if (key === "json" && typeof val === "object") {
|
|
840
|
-
val = catchError(JSON.stringify.bind(JSON), val);
|
|
841
|
-
}
|
|
842
|
-
const res = new Response(val, {
|
|
843
|
-
status: 200,
|
|
844
|
-
statusText: "OK",
|
|
845
|
-
});
|
|
846
|
-
defineProp(res, "type", () => "basic");
|
|
847
|
-
defineProp(res, "url", () => request.url);
|
|
848
|
-
resolve(res);
|
|
849
|
-
});
|
|
850
|
-
} else {
|
|
851
|
-
reject(new DOMException("aborted", "AbortError"));
|
|
852
|
-
}
|
|
853
|
-
return;
|
|
854
|
-
}
|
|
855
|
-
init.method = request.method;
|
|
856
|
-
init.headers = request.headers;
|
|
857
|
-
init.body = request.data;
|
|
858
|
-
winAh.realFetch.call(win, request.url, init).then((res) => {
|
|
859
|
-
if (typeof request.response === "function") {
|
|
860
|
-
const response = {
|
|
861
|
-
finalUrl: res.url,
|
|
862
|
-
status: res.status,
|
|
863
|
-
responseHeaders: parseHeaders(res.headers),
|
|
864
|
-
};
|
|
865
|
-
fetchResponses.forEach(
|
|
866
|
-
(key) =>
|
|
867
|
-
(res[key] = function () {
|
|
868
|
-
if (key in response) return Promise.resolve(response[key]);
|
|
869
|
-
return resProto[key].call(this).then((val) => {
|
|
870
|
-
response[key] = val;
|
|
871
|
-
return req
|
|
872
|
-
.waitForResponseKeys(response)
|
|
873
|
-
.then(() => (key in response ? response[key] : val));
|
|
874
|
-
});
|
|
875
|
-
})
|
|
876
|
-
);
|
|
877
|
-
}
|
|
878
|
-
resolve(res);
|
|
879
|
-
}, reject);
|
|
880
|
-
})
|
|
881
|
-
.catch((err) => {
|
|
882
|
-
console.error(err);
|
|
883
|
-
resolve(winAh.realFetch.call(win, url, init));
|
|
884
|
-
});
|
|
885
|
-
});
|
|
886
|
-
}
|
|
887
|
-
function fakeFetchClone() {
|
|
888
|
-
const descriptors = Object.getOwnPropertyDescriptors(this);
|
|
889
|
-
const res = winAh.realFetchClone.call(this);
|
|
890
|
-
Object.defineProperties(res, descriptors);
|
|
891
|
-
return res;
|
|
892
|
-
}
|
|
893
|
-
winAh = win.__ajaxHooker = winAh || {
|
|
894
|
-
version,
|
|
895
|
-
fakeXHR,
|
|
896
|
-
fakeFetch,
|
|
897
|
-
fakeFetchClone,
|
|
898
|
-
realXHR: win.XMLHttpRequest,
|
|
899
|
-
realFetch: win.fetch,
|
|
900
|
-
realFetchClone: resProto.clone,
|
|
901
|
-
hookInsts: new Set(),
|
|
902
|
-
};
|
|
903
|
-
if (winAh.version !== version)
|
|
904
|
-
console.warn("检测到不同版本的ajaxHooker,可能发生冲突!");
|
|
905
|
-
win.XMLHttpRequest = winAh.fakeXHR;
|
|
906
|
-
win.fetch = winAh.fakeFetch;
|
|
907
|
-
resProto.clone = winAh.fakeFetchClone;
|
|
908
|
-
winAh.hookInsts.add(hookInst);
|
|
909
|
-
return {
|
|
910
|
-
hook: (fn) => hookInst.hookFns.push(fn),
|
|
911
|
-
filter: (arr) => {
|
|
912
|
-
if (Array.isArray(arr)) hookInst.filters = arr;
|
|
913
|
-
},
|
|
914
|
-
protect: () => {
|
|
915
|
-
readonly(win, "XMLHttpRequest", winAh.fakeXHR);
|
|
916
|
-
readonly(win, "fetch", winAh.fakeFetch);
|
|
917
|
-
readonly(resProto, "clone", winAh.fakeFetchClone);
|
|
918
|
-
},
|
|
919
|
-
unhook: () => {
|
|
920
|
-
winAh.hookInsts.delete(hookInst);
|
|
921
|
-
if (!winAh.hookInsts.size) {
|
|
922
|
-
writable(win, "XMLHttpRequest", winAh.realXHR);
|
|
923
|
-
writable(win, "fetch", winAh.realFetch);
|
|
924
|
-
writable(resProto, "clone", winAh.realFetchClone);
|
|
925
|
-
delete win.__ajaxHooker;
|
|
926
|
-
}
|
|
927
|
-
},
|
|
928
|
-
};
|
|
929
|
-
})();
|
|
941
|
+
})();
|
|
942
|
+
};
|
|
930
943
|
|
|
931
944
|
/**
|
|
932
945
|
*
|
|
@@ -3197,7 +3210,7 @@ class UtilsDictionary {
|
|
|
3197
3210
|
|
|
3198
3211
|
let Utils$1 = class Utils {
|
|
3199
3212
|
/** 版本号 */
|
|
3200
|
-
version = "2024.5.
|
|
3213
|
+
version = "2024.5.25";
|
|
3201
3214
|
addStyle(cssText) {
|
|
3202
3215
|
if (typeof cssText !== "string") {
|
|
3203
3216
|
throw new Error("Utils.addStyle 参数cssText 必须为String类型");
|
|
@@ -3312,7 +3325,7 @@ let Utils$1 = class Utils {
|
|
|
3312
3325
|
* + 版本:1.4.1
|
|
3313
3326
|
* + 文档:https://scriptcat.org/zh-CN/script-show-page/637/
|
|
3314
3327
|
*/
|
|
3315
|
-
ajaxHooker =
|
|
3328
|
+
ajaxHooker = AjaxHooker;
|
|
3316
3329
|
canvasClickByPosition(canvasElement, clientX = 0, clientY = 0, view = globalThis) {
|
|
3317
3330
|
if (!(canvasElement instanceof HTMLCanvasElement)) {
|
|
3318
3331
|
throw new Error("Utils.canvasClickByPosition 参数canvasElement必须是canvas元素");
|