@whitesev/domutils 1.6.8 → 1.7.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 (55) hide show
  1. package/dist/index.amd.js +1928 -1047
  2. package/dist/index.amd.js.map +1 -1
  3. package/dist/index.amd.min.js +2 -0
  4. package/dist/index.amd.min.js.map +1 -0
  5. package/dist/index.cjs.js +1928 -1047
  6. package/dist/index.cjs.js.map +1 -1
  7. package/dist/index.cjs.min.js +2 -0
  8. package/dist/index.cjs.min.js.map +1 -0
  9. package/dist/index.esm.js +1928 -1047
  10. package/dist/index.esm.js.map +1 -1
  11. package/dist/index.esm.min.js +2 -0
  12. package/dist/index.esm.min.js.map +1 -0
  13. package/dist/index.iife.js +1928 -1047
  14. package/dist/index.iife.js.map +1 -1
  15. package/dist/index.iife.min.js +2 -0
  16. package/dist/index.iife.min.js.map +1 -0
  17. package/dist/index.system.js +1928 -1047
  18. package/dist/index.system.js.map +1 -1
  19. package/dist/index.system.min.js +2 -0
  20. package/dist/index.system.min.js.map +1 -0
  21. package/dist/index.umd.js +1928 -1047
  22. package/dist/index.umd.js.map +1 -1
  23. package/dist/index.umd.min.js +2 -0
  24. package/dist/index.umd.min.js.map +1 -0
  25. package/dist/types/index.d.ts +1 -1
  26. package/dist/types/src/{DOMUtilsCommonUtils.d.ts → CommonUtils.d.ts} +20 -8
  27. package/dist/types/src/ElementAnimate.d.ts +89 -0
  28. package/dist/types/src/{DOMUtilsEvent.d.ts → ElementEvent.d.ts} +19 -84
  29. package/dist/types/src/ElementHandler.d.ts +17 -0
  30. package/dist/types/src/ElementSelector.d.ts +96 -0
  31. package/dist/types/src/ElementWait.d.ts +278 -0
  32. package/dist/types/src/GlobalData.d.ts +4 -0
  33. package/dist/types/src/{DOMUtilsOriginPrototype.d.ts → OriginPrototype.d.ts} +1 -2
  34. package/dist/types/src/Utils.d.ts +68 -0
  35. package/dist/types/src/{DOMUtils.d.ts → index.d.ts} +157 -177
  36. package/dist/types/src/types/env.d.ts +9 -0
  37. package/dist/types/src/types/global.d.ts +0 -2
  38. package/dist/types/src/types/gm.d.ts +0 -4
  39. package/index.ts +1 -1
  40. package/package.json +6 -2
  41. package/src/{DOMUtilsCommonUtils.ts → CommonUtils.ts} +25 -11
  42. package/src/ElementAnimate.ts +290 -0
  43. package/src/{DOMUtilsEvent.ts → ElementEvent.ts} +166 -361
  44. package/src/ElementHandler.ts +43 -0
  45. package/src/ElementSelector.ts +260 -0
  46. package/src/ElementWait.ts +699 -0
  47. package/src/GlobalData.ts +5 -0
  48. package/src/{DOMUtilsOriginPrototype.ts → OriginPrototype.ts} +1 -3
  49. package/src/Utils.ts +386 -0
  50. package/src/{DOMUtils.ts → index.ts} +678 -757
  51. package/src/types/env.d.ts +9 -0
  52. package/src/types/global.d.ts +0 -2
  53. package/src/types/gm.d.ts +0 -4
  54. package/dist/types/src/DOMUtilsData.d.ts +0 -5
  55. package/src/DOMUtilsData.ts +0 -7
@@ -0,0 +1,43 @@
1
+ import { ElementEvent } from "./ElementEvent";
2
+ import type { WindowApiOption } from "./types/WindowApi";
3
+ import { WindowApi } from "./WindowApi";
4
+
5
+ class ElementHandler extends ElementEvent {
6
+ windowApi: typeof WindowApi.prototype;
7
+ constructor(windowApiOption?: WindowApiOption) {
8
+ super(windowApiOption);
9
+ this.windowApi = new WindowApi(windowApiOption);
10
+ }
11
+ /**
12
+ * 获取元素的选择器字符串
13
+ * @param $el
14
+ * @example
15
+ * DOMUtils.getElementSelector(document.querySelector("a"))
16
+ * > '.....'
17
+ */
18
+ getElementSelector($el: HTMLElement): string {
19
+ const that = this;
20
+ if (!$el) return void 0 as any as string;
21
+ if (!$el.parentElement) return void 0 as any as string;
22
+ /* 如果元素有id属性,则直接返回id选择器 */
23
+ if ($el.id) return `#${$el.id}`;
24
+
25
+ /* 递归地获取父元素的选择器 */
26
+ let selector = that.getElementSelector($el.parentElement);
27
+ if (!selector) {
28
+ return $el.tagName.toLowerCase();
29
+ }
30
+ /* 如果有多个相同类型的兄弟元素,则需要添加索引 */
31
+ if ($el.parentElement.querySelectorAll($el.tagName).length > 1) {
32
+ const index = Array.prototype.indexOf.call($el.parentElement.children, $el) + 1;
33
+ selector += ` > ${$el.tagName.toLowerCase()}:nth-child(${index})`;
34
+ } else {
35
+ selector += ` > ${$el.tagName.toLowerCase()}`;
36
+ }
37
+ return selector;
38
+ }
39
+ }
40
+
41
+ const elementHandler = new ElementHandler();
42
+
43
+ export { elementHandler, ElementHandler };
@@ -0,0 +1,260 @@
1
+ import type { WindowApiOption } from "./types/WindowApi";
2
+ import { WindowApi } from "./WindowApi";
3
+
4
+ class ElementSelector {
5
+ windowApi: typeof WindowApi.prototype;
6
+ constructor(windowApiOption?: WindowApiOption) {
7
+ this.windowApi = new WindowApi(windowApiOption);
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 = HTMLElement>(
32
+ selector: string,
33
+ parent?: Element | Document | DocumentFragment | ShadowRoot
34
+ ): E | undefined;
35
+ selector<E extends Element = HTMLElement>(
36
+ selector: string,
37
+ parent?: Element | Document | DocumentFragment | ShadowRoot
38
+ ) {
39
+ return this.selectorAll<E>(selector, parent)[0];
40
+ }
41
+ /**
42
+ * 选择器,可使用以下的额外语法
43
+ *
44
+ * + :contains([text]) 作用: 找到包含指定文本内容的指定元素
45
+ * + :empty 作用:找到既没有文本内容也没有子元素的指定元素
46
+ * + :regexp([text]) 作用: 找到符合正则表达式的内容的指定元素
47
+ * @param selector 选择器
48
+ * @param parent 指定父元素
49
+ * @example
50
+ * DOMUtils.selectorAll("div:contains('测试')")
51
+ * > [div.xxx]
52
+ * @example
53
+ * DOMUtils.selectorAll("div:empty")
54
+ * > [div.xxx]
55
+ * @example
56
+ * DOMUtils.selectorAll("div:regexp('^xxxx$')")
57
+ * > [div.xxx]
58
+ * @example
59
+ * DOMUtils.selectorAll("div:regexp(/^xxx/ig)")
60
+ * > [div.xxx]
61
+ */
62
+ selectorAll<K extends keyof HTMLElementTagNameMap>(
63
+ selector: K,
64
+ parent?: Element | Document | DocumentFragment | ShadowRoot
65
+ ): HTMLElementTagNameMap[K][];
66
+ selectorAll<E extends Element = HTMLElement>(
67
+ selector: string,
68
+ parent?: Element | Document | DocumentFragment | ShadowRoot
69
+ ): E[];
70
+ selectorAll<E extends Element = HTMLElement>(
71
+ selector: string,
72
+ parent?: Element | Document | DocumentFragment | ShadowRoot
73
+ ) {
74
+ const context = this;
75
+ parent = parent || context.windowApi.document;
76
+ selector = selector.trim();
77
+ if (selector.match(/[^\s]{1}:empty$/gi)) {
78
+ // empty 语法
79
+ selector = selector.replace(/:empty$/gi, "");
80
+ return Array.from(parent.querySelectorAll<E>(selector)).filter(($ele) => {
81
+ return $ele?.innerHTML?.trim() === "";
82
+ });
83
+ } else if (selector.match(/[^\s]{1}:contains\("(.*)"\)$/i) || selector.match(/[^\s]{1}:contains\('(.*)'\)$/i)) {
84
+ // contains 语法
85
+ const textMatch = selector.match(/:contains\(("|')(.*)("|')\)$/i);
86
+ const text = textMatch![2];
87
+ selector = selector.replace(/:contains\(("|')(.*)("|')\)$/gi, "");
88
+ return Array.from(parent.querySelectorAll<E>(selector)).filter(($ele) => {
89
+ // @ts-ignore
90
+ return ($ele?.textContent || $ele?.innerText)?.includes(text);
91
+ });
92
+ } else if (selector.match(/[^\s]{1}:regexp\("(.*)"\)$/i) || selector.match(/[^\s]{1}:regexp\('(.*)'\)$/i)) {
93
+ // regexp 语法
94
+ const textMatch = selector.match(/:regexp\(("|')(.*)("|')\)$/i);
95
+ let pattern = textMatch![2];
96
+ const flagMatch = pattern.match(/("|'),[\s]*("|')([igm]{0,3})$/i);
97
+ let flags = "";
98
+ if (flagMatch) {
99
+ pattern = pattern.replace(/("|'),[\s]*("|')([igm]{0,3})$/gi, "");
100
+ flags = flagMatch[3];
101
+ }
102
+ const regexp = new RegExp(pattern, flags);
103
+ selector = selector.replace(/:regexp\(("|')(.*)("|')\)$/gi, "");
104
+ return Array.from(parent.querySelectorAll<E>(selector)).filter(($ele) => {
105
+ // @ts-ignore
106
+ return Boolean(($ele?.textContent || $ele?.innerText)?.match(regexp));
107
+ });
108
+ } else {
109
+ // 普通语法
110
+ return Array.from(parent.querySelectorAll<E>(selector));
111
+ }
112
+ }
113
+ /**
114
+ * 匹配元素,可使用以下的额外语法
115
+ *
116
+ * + :contains([text]) 作用: 找到包含指定文本内容的指定元素
117
+ * + :empty 作用:找到既没有文本内容也没有子元素的指定元素
118
+ * + :regexp([text]) 作用: 找到符合正则表达式的内容的指定元素
119
+ * @param $el 元素
120
+ * @param selector 选择器
121
+ * @example
122
+ * DOMUtils.matches("div:contains('测试')")
123
+ * > true
124
+ * @example
125
+ * DOMUtils.matches("div:empty")
126
+ * > true
127
+ * @example
128
+ * DOMUtils.matches("div:regexp('^xxxx$')")
129
+ * > true
130
+ * @example
131
+ * DOMUtils.matches("div:regexp(/^xxx/ig)")
132
+ * > false
133
+ */
134
+ matches($el: HTMLElement | Element | null | undefined, selector: string): boolean {
135
+ selector = selector.trim();
136
+ if ($el == null) {
137
+ return false;
138
+ }
139
+
140
+ if (selector.match(/[^\s]{1}:empty$/gi)) {
141
+ // empty 语法
142
+ selector = selector.replace(/:empty$/gi, "");
143
+ return $el.matches(selector) && $el?.innerHTML?.trim() === "";
144
+ } else if (selector.match(/[^\s]{1}:contains\("(.*)"\)$/i) || selector.match(/[^\s]{1}:contains\('(.*)'\)$/i)) {
145
+ // contains 语法
146
+ const textMatch = selector.match(/:contains\(("|')(.*)("|')\)$/i);
147
+ const text = textMatch![2];
148
+ selector = selector.replace(/:contains\(("|')(.*)("|')\)$/gi, "");
149
+ // @ts-ignore
150
+ let content = $el?.textContent || $el?.innerText;
151
+ if (typeof content !== "string") {
152
+ content = "";
153
+ }
154
+ return $el.matches(selector) && content?.includes(text);
155
+ } else if (selector.match(/[^\s]{1}:regexp\("(.*)"\)$/i) || selector.match(/[^\s]{1}:regexp\('(.*)'\)$/i)) {
156
+ // regexp 语法
157
+ const textMatch = selector.match(/:regexp\(("|')(.*)("|')\)$/i);
158
+ let pattern = textMatch![2];
159
+ const flagMatch = pattern.match(/("|'),[\s]*("|')([igm]{0,3})$/i);
160
+ let flags = "";
161
+ if (flagMatch) {
162
+ pattern = pattern.replace(/("|'),[\s]*("|')([igm]{0,3})$/gi, "");
163
+ flags = flagMatch[3];
164
+ }
165
+ const regexp = new RegExp(pattern, flags);
166
+ selector = selector.replace(/:regexp\(("|')(.*)("|')\)$/gi, "");
167
+ // @ts-ignore
168
+ let content = $el?.textContent || $el?.innerText;
169
+ if (typeof content !== "string") {
170
+ content = "";
171
+ }
172
+ return $el.matches(selector) && Boolean(content?.match(regexp));
173
+ } else {
174
+ // 普通语法
175
+ return $el.matches(selector);
176
+ }
177
+ }
178
+ /**
179
+ * 根据选择器获取上层元素,可使用以下的额外语法
180
+ *
181
+ * + :contains([text]) 作用: 找到包含指定文本内容的指定元素
182
+ * + :empty 作用:找到既没有文本内容也没有子元素的指定元素
183
+ * + :regexp([text]) 作用: 找到符合正则表达式的内容的指定元素
184
+ * @param $el 元素
185
+ * @param selector 选择器
186
+ * @example
187
+ * DOMUtils.closest("div:contains('测试')")
188
+ * > div.xxx
189
+ * @example
190
+ * DOMUtils.closest("div:empty")
191
+ * > div.xxx
192
+ * @example
193
+ * DOMUtils.closest("div:regexp('^xxxx$')")
194
+ * > div.xxxx
195
+ * @example
196
+ * DOMUtils.closest("div:regexp(/^xxx/ig)")
197
+ * > null
198
+ */
199
+ closest<K extends keyof HTMLElementTagNameMap>(
200
+ $el: HTMLElement | Element,
201
+ selector: string
202
+ ): HTMLElementTagNameMap[K] | null;
203
+ closest<E extends Element = Element>($el: HTMLElement | Element, selector: string): E | null;
204
+ closest<E extends Element = Element>($el: HTMLElement | Element, selector: string): E | null {
205
+ selector = selector.trim();
206
+
207
+ if (selector.match(/[^\s]{1}:empty$/gi)) {
208
+ // empty 语法
209
+ selector = selector.replace(/:empty$/gi, "");
210
+ const $closest = $el?.closest<E>(selector);
211
+ if ($closest && $closest?.innerHTML?.trim() === "") {
212
+ return $closest;
213
+ }
214
+ return null;
215
+ } else if (selector.match(/[^\s]{1}:contains\("(.*)"\)$/i) || selector.match(/[^\s]{1}:contains\('(.*)'\)$/i)) {
216
+ // contains 语法
217
+ const textMatch = selector.match(/:contains\(("|')(.*)("|')\)$/i);
218
+ const text = textMatch![2];
219
+ selector = selector.replace(/:contains\(("|')(.*)("|')\)$/gi, "");
220
+ const $closest = $el?.closest<E>(selector);
221
+ if ($closest) {
222
+ // @ts-ignore
223
+ const content = $el?.textContent || $el?.innerText;
224
+ if (typeof content === "string" && content.includes(text)) {
225
+ return $closest;
226
+ }
227
+ }
228
+ return null;
229
+ } else if (selector.match(/[^\s]{1}:regexp\("(.*)"\)$/i) || selector.match(/[^\s]{1}:regexp\('(.*)'\)$/i)) {
230
+ // regexp 语法
231
+ const textMatch = selector.match(/:regexp\(("|')(.*)("|')\)$/i);
232
+ let pattern = textMatch![2];
233
+ const flagMatch = pattern.match(/("|'),[\s]*("|')([igm]{0,3})$/i);
234
+ let flags = "";
235
+ if (flagMatch) {
236
+ pattern = pattern.replace(/("|'),[\s]*("|')([igm]{0,3})$/gi, "");
237
+ flags = flagMatch[3];
238
+ }
239
+ const regexp = new RegExp(pattern, flags);
240
+ selector = selector.replace(/:regexp\(("|')(.*)("|')\)$/gi, "");
241
+ const $closest = $el?.closest<E>(selector);
242
+ if ($closest) {
243
+ // @ts-ignore
244
+ const content = $el?.textContent || $el?.innerText;
245
+ if (typeof content === "string" && content.match(regexp)) {
246
+ return $closest;
247
+ }
248
+ }
249
+ return null;
250
+ } else {
251
+ // 普通语法
252
+ const $closest = $el?.closest<E>(selector);
253
+ return $closest;
254
+ }
255
+ }
256
+ }
257
+
258
+ const elementSelector = new ElementSelector();
259
+
260
+ export { elementSelector, ElementSelector };