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