@whitesev/utils 2.8.1 → 2.9.0

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.
Files changed (74) hide show
  1. package/README.md +176 -176
  2. package/dist/index.amd.js +271 -777
  3. package/dist/index.amd.js.map +1 -1
  4. package/dist/index.amd.min.js +2 -0
  5. package/dist/index.amd.min.js.map +1 -0
  6. package/dist/index.cjs.js +271 -777
  7. package/dist/index.cjs.js.map +1 -1
  8. package/dist/index.cjs.min.js +2 -0
  9. package/dist/index.cjs.min.js.map +1 -0
  10. package/dist/index.esm.js +271 -777
  11. package/dist/index.esm.js.map +1 -1
  12. package/dist/index.esm.min.js +2 -0
  13. package/dist/index.esm.min.js.map +1 -0
  14. package/dist/index.iife.js +271 -777
  15. package/dist/index.iife.js.map +1 -1
  16. package/dist/index.iife.min.js +2 -0
  17. package/dist/index.iife.min.js.map +1 -0
  18. package/dist/index.system.js +271 -777
  19. package/dist/index.system.js.map +1 -1
  20. package/dist/index.system.min.js +2 -0
  21. package/dist/index.system.min.js.map +1 -0
  22. package/dist/index.umd.js +271 -777
  23. package/dist/index.umd.js.map +1 -1
  24. package/dist/index.umd.min.js +2 -0
  25. package/dist/index.umd.min.js.map +1 -0
  26. package/dist/types/src/Utils.d.ts +103 -450
  27. package/dist/types/src/UtilsGMCookie.d.ts +4 -0
  28. package/dist/types/src/UtilsGMMenu.d.ts +3 -6
  29. package/dist/types/src/types/Httpx.d.ts +1344 -1344
  30. package/dist/types/src/types/Log.d.ts +19 -19
  31. package/dist/types/src/types/Progress.d.ts +20 -20
  32. package/dist/types/src/types/React.d.ts +119 -119
  33. package/dist/types/src/types/TryCatch.d.ts +9 -9
  34. package/dist/types/src/types/UtilsGMCookie.d.ts +93 -93
  35. package/dist/types/src/types/UtilsGMMenu.d.ts +77 -77
  36. package/dist/types/src/types/Vue2.d.ts +166 -166
  37. package/dist/types/src/types/WindowApi.d.ts +14 -14
  38. package/dist/types/src/types/ajaxHooker.d.ts +151 -151
  39. package/dist/types/src/types/env.d.ts +7 -7
  40. package/dist/types/src/types/global.d.ts +31 -31
  41. package/index.ts +3 -0
  42. package/package.json +16 -10
  43. package/src/ColorConversion.ts +105 -105
  44. package/src/CommonUtil.ts +280 -280
  45. package/src/DOMUtils.ts +251 -251
  46. package/src/Dictionary.ts +153 -153
  47. package/src/GBKEncoder.ts +108 -108
  48. package/src/Hooks.ts +73 -73
  49. package/src/Httpx.ts +1457 -1457
  50. package/src/LockFunction.ts +62 -62
  51. package/src/Log.ts +258 -258
  52. package/src/Progress.ts +108 -108
  53. package/src/TryCatch.ts +86 -86
  54. package/src/Utils.ts +3778 -4772
  55. package/src/UtilsCommon.ts +14 -14
  56. package/src/UtilsGMCookie.ts +272 -254
  57. package/src/UtilsGMMenu.ts +441 -445
  58. package/src/Vue.ts +233 -233
  59. package/src/WindowApi.ts +59 -59
  60. package/src/indexedDB.ts +497 -497
  61. package/src/types/Httpx.d.ts +1344 -1344
  62. package/src/types/Log.d.ts +19 -19
  63. package/src/types/Progress.d.ts +20 -20
  64. package/src/types/React.d.ts +119 -119
  65. package/src/types/TryCatch.d.ts +9 -9
  66. package/src/types/UtilsGMCookie.d.ts +93 -93
  67. package/src/types/UtilsGMMenu.d.ts +77 -77
  68. package/src/types/Vue2.d.ts +166 -166
  69. package/src/types/WindowApi.d.ts +14 -14
  70. package/src/types/ajaxHooker.d.ts +151 -151
  71. package/src/types/env.d.ts +7 -7
  72. package/src/types/global.d.ts +31 -31
  73. package/dist/types/src/types/Event.d.ts +0 -188
  74. package/src/types/Event.d.ts +0 -188
package/src/DOMUtils.ts CHANGED
@@ -1,251 +1,251 @@
1
- import type { WindowApiOption } from "./types/WindowApi";
2
- import { WindowApi } from "./WindowApi";
3
-
4
- class DOMUtils {
5
- private windowApi: typeof WindowApi.prototype;
6
- constructor(option?: WindowApiOption) {
7
- this.windowApi = new WindowApi(option);
8
- }
9
- /**
10
- * 选择器,可使用以下的额外语法
11
- *
12
- * + :contains([text]) 作用: 找到包含指定文本内容的指定元素
13
- * + :empty 作用:找到既没有文本内容也没有子元素的指定元素
14
- * + :regexp([text]) 作用: 找到符合正则表达式的内容的指定元素
15
- * @param selector 选择器
16
- * @param parent 指定父元素
17
- * @example
18
- * DOMUtils.selector("div:contains('测试')")
19
- * > div.xxx
20
- * @example
21
- * DOMUtils.selector("div:empty")
22
- * > div.xxx
23
- * @example
24
- * DOMUtils.selector("div:regexp('^xxxx$')")
25
- * > div.xxx
26
- */
27
- selector<K extends keyof HTMLElementTagNameMap>(
28
- selector: K,
29
- parent?: Element | Document | DocumentFragment | ShadowRoot
30
- ): HTMLElementTagNameMap[K] | undefined;
31
- selector<E extends Element = Element>(
32
- selector: string,
33
- parent?: Element | Document | DocumentFragment | ShadowRoot
34
- ): E | undefined;
35
- selector<E extends Element = Element>(selector: string, parent?: Element | Document | DocumentFragment | ShadowRoot) {
36
- return this.selectorAll<E>(selector, parent)[0];
37
- }
38
- /**
39
- * 选择器,可使用以下的额外语法
40
- *
41
- * + :contains([text]) 作用: 找到包含指定文本内容的指定元素
42
- * + :empty 作用:找到既没有文本内容也没有子元素的指定元素
43
- * + :regexp([text]) 作用: 找到符合正则表达式的内容的指定元素
44
- * @param selector 选择器
45
- * @param parent 指定父元素
46
- * @example
47
- * DOMUtils.selectorAll("div:contains('测试')")
48
- * > [div.xxx]
49
- * @example
50
- * DOMUtils.selectorAll("div:empty")
51
- * > [div.xxx]
52
- * @example
53
- * DOMUtils.selectorAll("div:regexp('^xxxx$')")
54
- * > [div.xxx]
55
- * @example
56
- * DOMUtils.selectorAll("div:regexp(/^xxx/ig)")
57
- * > [div.xxx]
58
- */
59
- selectorAll<K extends keyof HTMLElementTagNameMap>(
60
- selector: K,
61
- parent?: Element | Document | DocumentFragment | ShadowRoot
62
- ): HTMLElementTagNameMap[K][];
63
- selectorAll<E extends Element = Element>(
64
- selector: string,
65
- parent?: Element | Document | DocumentFragment | ShadowRoot
66
- ): E[];
67
- selectorAll<E extends Element = Element>(
68
- selector: string,
69
- parent?: Element | Document | DocumentFragment | ShadowRoot
70
- ) {
71
- const context = this;
72
- parent = parent || context.windowApi.document;
73
- selector = selector.trim();
74
- if (selector.match(/[^\s]{1}:empty$/gi)) {
75
- // empty 语法
76
- selector = selector.replace(/:empty$/gi, "");
77
- return Array.from(parent.querySelectorAll<E>(selector)).filter(($ele) => {
78
- return $ele?.innerHTML?.trim() === "";
79
- });
80
- } else if (selector.match(/[^\s]{1}:contains\("(.*)"\)$/i) || selector.match(/[^\s]{1}:contains\('(.*)'\)$/i)) {
81
- // contains 语法
82
- const textMatch = selector.match(/:contains\(("|')(.*)("|')\)$/i);
83
- const text = textMatch![2];
84
- selector = selector.replace(/:contains\(("|')(.*)("|')\)$/gi, "");
85
- return Array.from(parent.querySelectorAll<HTMLElement>(selector)).filter(($ele) => {
86
- return ($ele?.textContent || $ele?.innerText)?.includes(text);
87
- });
88
- } else if (selector.match(/[^\s]{1}:regexp\("(.*)"\)$/i) || selector.match(/[^\s]{1}:regexp\('(.*)'\)$/i)) {
89
- // regexp 语法
90
- const textMatch = selector.match(/:regexp\(("|')(.*)("|')\)$/i);
91
- let pattern = textMatch![2];
92
- const flagMatch = pattern.match(/("|'),[\s]*("|')([igm]{0,3})$/i);
93
- let flags = "";
94
- if (flagMatch) {
95
- pattern = pattern.replace(/("|'),[\s]*("|')([igm]{0,3})$/gi, "");
96
- flags = flagMatch[3];
97
- }
98
- const regexp = new RegExp(pattern, flags);
99
- selector = selector.replace(/:regexp\(("|')(.*)("|')\)$/gi, "");
100
- return Array.from(parent.querySelectorAll<HTMLElement>(selector)).filter(($ele) => {
101
- return Boolean(($ele?.textContent || $ele?.innerText)?.match(regexp));
102
- });
103
- } else {
104
- // 普通语法
105
- return Array.from(parent.querySelectorAll<E>(selector));
106
- }
107
- }
108
- /**
109
- * 匹配元素,可使用以下的额外语法
110
- *
111
- * + :contains([text]) 作用: 找到包含指定文本内容的指定元素
112
- * + :empty 作用:找到既没有文本内容也没有子元素的指定元素
113
- * + :regexp([text]) 作用: 找到符合正则表达式的内容的指定元素
114
- * @param $el 元素
115
- * @param selector 选择器
116
- * @example
117
- * DOMUtils.matches("div:contains('测试')")
118
- * > true
119
- * @example
120
- * DOMUtils.matches("div:empty")
121
- * > true
122
- * @example
123
- * DOMUtils.matches("div:regexp('^xxxx$')")
124
- * > true
125
- * @example
126
- * DOMUtils.matches("div:regexp(/^xxx/ig)")
127
- * > false
128
- */
129
- matches($el: HTMLElement | Element | null | undefined, selector: string): boolean {
130
- selector = selector.trim();
131
- if ($el == null) {
132
- return false;
133
- }
134
-
135
- if (selector.match(/[^\s]{1}:empty$/gi)) {
136
- // empty 语法
137
- selector = selector.replace(/:empty$/gi, "");
138
- return $el.matches(selector) && $el?.innerHTML?.trim() === "";
139
- } else if (selector.match(/[^\s]{1}:contains\("(.*)"\)$/i) || selector.match(/[^\s]{1}:contains\('(.*)'\)$/i)) {
140
- // contains 语法
141
- const textMatch = selector.match(/:contains\(("|')(.*)("|')\)$/i);
142
- const text = textMatch![2];
143
- selector = selector.replace(/:contains\(("|')(.*)("|')\)$/gi, "");
144
- let content = $el?.textContent || (<HTMLElement>$el)?.innerText;
145
- if (typeof content !== "string") {
146
- content = "";
147
- }
148
- return $el.matches(selector) && content?.includes(text);
149
- } else if (selector.match(/[^\s]{1}:regexp\("(.*)"\)$/i) || selector.match(/[^\s]{1}:regexp\('(.*)'\)$/i)) {
150
- // regexp 语法
151
- const textMatch = selector.match(/:regexp\(("|')(.*)("|')\)$/i);
152
- let pattern = textMatch![2];
153
- const flagMatch = pattern.match(/("|'),[\s]*("|')([igm]{0,3})$/i);
154
- let flags = "";
155
- if (flagMatch) {
156
- pattern = pattern.replace(/("|'),[\s]*("|')([igm]{0,3})$/gi, "");
157
- flags = flagMatch[3];
158
- }
159
- const regexp = new RegExp(pattern, flags);
160
- selector = selector.replace(/:regexp\(("|')(.*)("|')\)$/gi, "");
161
- let content = $el?.textContent || (<HTMLElement>$el)?.innerText;
162
- if (typeof content !== "string") {
163
- content = "";
164
- }
165
- return $el.matches(selector) && Boolean(content?.match(regexp));
166
- } else {
167
- // 普通语法
168
- return $el.matches(selector);
169
- }
170
- }
171
- /**
172
- * 根据选择器获取上层元素,可使用以下的额外语法
173
- *
174
- * + :contains([text]) 作用: 找到包含指定文本内容的指定元素
175
- * + :empty 作用:找到既没有文本内容也没有子元素的指定元素
176
- * + :regexp([text]) 作用: 找到符合正则表达式的内容的指定元素
177
- * @param $el 元素
178
- * @param selector 选择器
179
- * @example
180
- * DOMUtils.closest("div:contains('测试')")
181
- * > div.xxx
182
- * @example
183
- * DOMUtils.closest("div:empty")
184
- * > div.xxx
185
- * @example
186
- * DOMUtils.closest("div:regexp('^xxxx$')")
187
- * > div.xxxx
188
- * @example
189
- * DOMUtils.closest("div:regexp(/^xxx/ig)")
190
- * > null
191
- */
192
- closest<K extends keyof HTMLElementTagNameMap>(
193
- $el: HTMLElement | Element,
194
- selector: string
195
- ): HTMLElementTagNameMap[K] | null;
196
- closest<E extends Element = Element>($el: HTMLElement | Element, selector: string): E | null;
197
- closest<E extends Element = Element>($el: HTMLElement | Element, selector: string): E | null {
198
- selector = selector.trim();
199
-
200
- if (selector.match(/[^\s]{1}:empty$/gi)) {
201
- // empty 语法
202
- selector = selector.replace(/:empty$/gi, "");
203
- const $closest = $el?.closest<E>(selector);
204
- if ($closest && $closest?.innerHTML?.trim() === "") {
205
- return $closest;
206
- }
207
- return null;
208
- } else if (selector.match(/[^\s]{1}:contains\("(.*)"\)$/i) || selector.match(/[^\s]{1}:contains\('(.*)'\)$/i)) {
209
- // contains 语法
210
- const textMatch = selector.match(/:contains\(("|')(.*)("|')\)$/i);
211
- const text = textMatch![2];
212
- selector = selector.replace(/:contains\(("|')(.*)("|')\)$/gi, "");
213
- const $closest = $el?.closest<E>(selector);
214
- if ($closest) {
215
- const content = $el?.textContent || (<HTMLElement>$el)?.innerText;
216
- if (typeof content === "string" && content.includes(text)) {
217
- return $closest;
218
- }
219
- }
220
- return null;
221
- } else if (selector.match(/[^\s]{1}:regexp\("(.*)"\)$/i) || selector.match(/[^\s]{1}:regexp\('(.*)'\)$/i)) {
222
- // regexp 语法
223
- const textMatch = selector.match(/:regexp\(("|')(.*)("|')\)$/i);
224
- let pattern = textMatch![2];
225
- const flagMatch = pattern.match(/("|'),[\s]*("|')([igm]{0,3})$/i);
226
- let flags = "";
227
- if (flagMatch) {
228
- pattern = pattern.replace(/("|'),[\s]*("|')([igm]{0,3})$/gi, "");
229
- flags = flagMatch[3];
230
- }
231
- const regexp = new RegExp(pattern, flags);
232
- selector = selector.replace(/:regexp\(("|')(.*)("|')\)$/gi, "");
233
- const $closest = $el?.closest<E>(selector);
234
- if ($closest) {
235
- const content = $el?.textContent || (<HTMLElement>$el)?.innerText;
236
- if (typeof content === "string" && content.match(regexp)) {
237
- return $closest;
238
- }
239
- }
240
- return null;
241
- } else {
242
- // 普通语法
243
- const $closest = $el?.closest<E>(selector);
244
- return $closest;
245
- }
246
- }
247
- }
248
-
249
- const domUtils = new DOMUtils();
250
-
251
- export { domUtils };
1
+ import type { WindowApiOption } from "./types/WindowApi";
2
+ import { WindowApi } from "./WindowApi";
3
+
4
+ class DOMUtils {
5
+ private windowApi: typeof WindowApi.prototype;
6
+ constructor(option?: WindowApiOption) {
7
+ this.windowApi = new WindowApi(option);
8
+ }
9
+ /**
10
+ * 选择器,可使用以下的额外语法
11
+ *
12
+ * + :contains([text]) 作用: 找到包含指定文本内容的指定元素
13
+ * + :empty 作用:找到既没有文本内容也没有子元素的指定元素
14
+ * + :regexp([text]) 作用: 找到符合正则表达式的内容的指定元素
15
+ * @param selector 选择器
16
+ * @param parent 指定父元素
17
+ * @example
18
+ * DOMUtils.selector("div:contains('测试')")
19
+ * > div.xxx
20
+ * @example
21
+ * DOMUtils.selector("div:empty")
22
+ * > div.xxx
23
+ * @example
24
+ * DOMUtils.selector("div:regexp('^xxxx$')")
25
+ * > div.xxx
26
+ */
27
+ selector<K extends keyof HTMLElementTagNameMap>(
28
+ selector: K,
29
+ parent?: Element | Document | DocumentFragment | ShadowRoot
30
+ ): HTMLElementTagNameMap[K] | undefined;
31
+ selector<E extends Element = Element>(
32
+ selector: string,
33
+ parent?: Element | Document | DocumentFragment | ShadowRoot
34
+ ): E | undefined;
35
+ selector<E extends Element = Element>(selector: string, parent?: Element | Document | DocumentFragment | ShadowRoot) {
36
+ return this.selectorAll<E>(selector, parent)[0];
37
+ }
38
+ /**
39
+ * 选择器,可使用以下的额外语法
40
+ *
41
+ * + :contains([text]) 作用: 找到包含指定文本内容的指定元素
42
+ * + :empty 作用:找到既没有文本内容也没有子元素的指定元素
43
+ * + :regexp([text]) 作用: 找到符合正则表达式的内容的指定元素
44
+ * @param selector 选择器
45
+ * @param parent 指定父元素
46
+ * @example
47
+ * DOMUtils.selectorAll("div:contains('测试')")
48
+ * > [div.xxx]
49
+ * @example
50
+ * DOMUtils.selectorAll("div:empty")
51
+ * > [div.xxx]
52
+ * @example
53
+ * DOMUtils.selectorAll("div:regexp('^xxxx$')")
54
+ * > [div.xxx]
55
+ * @example
56
+ * DOMUtils.selectorAll("div:regexp(/^xxx/ig)")
57
+ * > [div.xxx]
58
+ */
59
+ selectorAll<K extends keyof HTMLElementTagNameMap>(
60
+ selector: K,
61
+ parent?: Element | Document | DocumentFragment | ShadowRoot
62
+ ): HTMLElementTagNameMap[K][];
63
+ selectorAll<E extends Element = Element>(
64
+ selector: string,
65
+ parent?: Element | Document | DocumentFragment | ShadowRoot
66
+ ): E[];
67
+ selectorAll<E extends Element = Element>(
68
+ selector: string,
69
+ parent?: Element | Document | DocumentFragment | ShadowRoot
70
+ ) {
71
+ const context = this;
72
+ parent = parent || context.windowApi.document;
73
+ selector = selector.trim();
74
+ if (selector.match(/[^\s]{1}:empty$/gi)) {
75
+ // empty 语法
76
+ selector = selector.replace(/:empty$/gi, "");
77
+ return Array.from(parent.querySelectorAll<E>(selector)).filter(($ele) => {
78
+ return $ele?.innerHTML?.trim() === "";
79
+ });
80
+ } else if (selector.match(/[^\s]{1}:contains\("(.*)"\)$/i) || selector.match(/[^\s]{1}:contains\('(.*)'\)$/i)) {
81
+ // contains 语法
82
+ const textMatch = selector.match(/:contains\(("|')(.*)("|')\)$/i);
83
+ const text = textMatch![2];
84
+ selector = selector.replace(/:contains\(("|')(.*)("|')\)$/gi, "");
85
+ return Array.from(parent.querySelectorAll<HTMLElement>(selector)).filter(($ele) => {
86
+ return ($ele?.textContent || $ele?.innerText)?.includes(text);
87
+ });
88
+ } else if (selector.match(/[^\s]{1}:regexp\("(.*)"\)$/i) || selector.match(/[^\s]{1}:regexp\('(.*)'\)$/i)) {
89
+ // regexp 语法
90
+ const textMatch = selector.match(/:regexp\(("|')(.*)("|')\)$/i);
91
+ let pattern = textMatch![2];
92
+ const flagMatch = pattern.match(/("|'),[\s]*("|')([igm]{0,3})$/i);
93
+ let flags = "";
94
+ if (flagMatch) {
95
+ pattern = pattern.replace(/("|'),[\s]*("|')([igm]{0,3})$/gi, "");
96
+ flags = flagMatch[3];
97
+ }
98
+ const regexp = new RegExp(pattern, flags);
99
+ selector = selector.replace(/:regexp\(("|')(.*)("|')\)$/gi, "");
100
+ return Array.from(parent.querySelectorAll<HTMLElement>(selector)).filter(($ele) => {
101
+ return Boolean(($ele?.textContent || $ele?.innerText)?.match(regexp));
102
+ });
103
+ } else {
104
+ // 普通语法
105
+ return Array.from(parent.querySelectorAll<E>(selector));
106
+ }
107
+ }
108
+ /**
109
+ * 匹配元素,可使用以下的额外语法
110
+ *
111
+ * + :contains([text]) 作用: 找到包含指定文本内容的指定元素
112
+ * + :empty 作用:找到既没有文本内容也没有子元素的指定元素
113
+ * + :regexp([text]) 作用: 找到符合正则表达式的内容的指定元素
114
+ * @param $el 元素
115
+ * @param selector 选择器
116
+ * @example
117
+ * DOMUtils.matches("div:contains('测试')")
118
+ * > true
119
+ * @example
120
+ * DOMUtils.matches("div:empty")
121
+ * > true
122
+ * @example
123
+ * DOMUtils.matches("div:regexp('^xxxx$')")
124
+ * > true
125
+ * @example
126
+ * DOMUtils.matches("div:regexp(/^xxx/ig)")
127
+ * > false
128
+ */
129
+ matches($el: HTMLElement | Element | null | undefined, selector: string): boolean {
130
+ selector = selector.trim();
131
+ if ($el == null) {
132
+ return false;
133
+ }
134
+
135
+ if (selector.match(/[^\s]{1}:empty$/gi)) {
136
+ // empty 语法
137
+ selector = selector.replace(/:empty$/gi, "");
138
+ return $el.matches(selector) && $el?.innerHTML?.trim() === "";
139
+ } else if (selector.match(/[^\s]{1}:contains\("(.*)"\)$/i) || selector.match(/[^\s]{1}:contains\('(.*)'\)$/i)) {
140
+ // contains 语法
141
+ const textMatch = selector.match(/:contains\(("|')(.*)("|')\)$/i);
142
+ const text = textMatch![2];
143
+ selector = selector.replace(/:contains\(("|')(.*)("|')\)$/gi, "");
144
+ let content = $el?.textContent || (<HTMLElement>$el)?.innerText;
145
+ if (typeof content !== "string") {
146
+ content = "";
147
+ }
148
+ return $el.matches(selector) && content?.includes(text);
149
+ } else if (selector.match(/[^\s]{1}:regexp\("(.*)"\)$/i) || selector.match(/[^\s]{1}:regexp\('(.*)'\)$/i)) {
150
+ // regexp 语法
151
+ const textMatch = selector.match(/:regexp\(("|')(.*)("|')\)$/i);
152
+ let pattern = textMatch![2];
153
+ const flagMatch = pattern.match(/("|'),[\s]*("|')([igm]{0,3})$/i);
154
+ let flags = "";
155
+ if (flagMatch) {
156
+ pattern = pattern.replace(/("|'),[\s]*("|')([igm]{0,3})$/gi, "");
157
+ flags = flagMatch[3];
158
+ }
159
+ const regexp = new RegExp(pattern, flags);
160
+ selector = selector.replace(/:regexp\(("|')(.*)("|')\)$/gi, "");
161
+ let content = $el?.textContent || (<HTMLElement>$el)?.innerText;
162
+ if (typeof content !== "string") {
163
+ content = "";
164
+ }
165
+ return $el.matches(selector) && Boolean(content?.match(regexp));
166
+ } else {
167
+ // 普通语法
168
+ return $el.matches(selector);
169
+ }
170
+ }
171
+ /**
172
+ * 根据选择器获取上层元素,可使用以下的额外语法
173
+ *
174
+ * + :contains([text]) 作用: 找到包含指定文本内容的指定元素
175
+ * + :empty 作用:找到既没有文本内容也没有子元素的指定元素
176
+ * + :regexp([text]) 作用: 找到符合正则表达式的内容的指定元素
177
+ * @param $el 元素
178
+ * @param selector 选择器
179
+ * @example
180
+ * DOMUtils.closest("div:contains('测试')")
181
+ * > div.xxx
182
+ * @example
183
+ * DOMUtils.closest("div:empty")
184
+ * > div.xxx
185
+ * @example
186
+ * DOMUtils.closest("div:regexp('^xxxx$')")
187
+ * > div.xxxx
188
+ * @example
189
+ * DOMUtils.closest("div:regexp(/^xxx/ig)")
190
+ * > null
191
+ */
192
+ closest<K extends keyof HTMLElementTagNameMap>(
193
+ $el: HTMLElement | Element,
194
+ selector: string
195
+ ): HTMLElementTagNameMap[K] | null;
196
+ closest<E extends Element = Element>($el: HTMLElement | Element, selector: string): E | null;
197
+ closest<E extends Element = Element>($el: HTMLElement | Element, selector: string): E | null {
198
+ selector = selector.trim();
199
+
200
+ if (selector.match(/[^\s]{1}:empty$/gi)) {
201
+ // empty 语法
202
+ selector = selector.replace(/:empty$/gi, "");
203
+ const $closest = $el?.closest<E>(selector);
204
+ if ($closest && $closest?.innerHTML?.trim() === "") {
205
+ return $closest;
206
+ }
207
+ return null;
208
+ } else if (selector.match(/[^\s]{1}:contains\("(.*)"\)$/i) || selector.match(/[^\s]{1}:contains\('(.*)'\)$/i)) {
209
+ // contains 语法
210
+ const textMatch = selector.match(/:contains\(("|')(.*)("|')\)$/i);
211
+ const text = textMatch![2];
212
+ selector = selector.replace(/:contains\(("|')(.*)("|')\)$/gi, "");
213
+ const $closest = $el?.closest<E>(selector);
214
+ if ($closest) {
215
+ const content = $el?.textContent || (<HTMLElement>$el)?.innerText;
216
+ if (typeof content === "string" && content.includes(text)) {
217
+ return $closest;
218
+ }
219
+ }
220
+ return null;
221
+ } else if (selector.match(/[^\s]{1}:regexp\("(.*)"\)$/i) || selector.match(/[^\s]{1}:regexp\('(.*)'\)$/i)) {
222
+ // regexp 语法
223
+ const textMatch = selector.match(/:regexp\(("|')(.*)("|')\)$/i);
224
+ let pattern = textMatch![2];
225
+ const flagMatch = pattern.match(/("|'),[\s]*("|')([igm]{0,3})$/i);
226
+ let flags = "";
227
+ if (flagMatch) {
228
+ pattern = pattern.replace(/("|'),[\s]*("|')([igm]{0,3})$/gi, "");
229
+ flags = flagMatch[3];
230
+ }
231
+ const regexp = new RegExp(pattern, flags);
232
+ selector = selector.replace(/:regexp\(("|')(.*)("|')\)$/gi, "");
233
+ const $closest = $el?.closest<E>(selector);
234
+ if ($closest) {
235
+ const content = $el?.textContent || (<HTMLElement>$el)?.innerText;
236
+ if (typeof content === "string" && content.match(regexp)) {
237
+ return $closest;
238
+ }
239
+ }
240
+ return null;
241
+ } else {
242
+ // 普通语法
243
+ const $closest = $el?.closest<E>(selector);
244
+ return $closest;
245
+ }
246
+ }
247
+ }
248
+
249
+ const domUtils = new DOMUtils();
250
+
251
+ export { domUtils };