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