@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.
- package/dist/index.amd.js +1928 -1047
- package/dist/index.amd.js.map +1 -1
- package/dist/index.amd.min.js +2 -0
- package/dist/index.amd.min.js.map +1 -0
- package/dist/index.cjs.js +1928 -1047
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.cjs.min.js +2 -0
- package/dist/index.cjs.min.js.map +1 -0
- package/dist/index.esm.js +1928 -1047
- package/dist/index.esm.js.map +1 -1
- package/dist/index.esm.min.js +2 -0
- package/dist/index.esm.min.js.map +1 -0
- package/dist/index.iife.js +1928 -1047
- package/dist/index.iife.js.map +1 -1
- package/dist/index.iife.min.js +2 -0
- package/dist/index.iife.min.js.map +1 -0
- package/dist/index.system.js +1928 -1047
- package/dist/index.system.js.map +1 -1
- package/dist/index.system.min.js +2 -0
- package/dist/index.system.min.js.map +1 -0
- package/dist/index.umd.js +1928 -1047
- package/dist/index.umd.js.map +1 -1
- package/dist/index.umd.min.js +2 -0
- package/dist/index.umd.min.js.map +1 -0
- package/dist/types/index.d.ts +1 -1
- package/dist/types/src/{DOMUtilsCommonUtils.d.ts → CommonUtils.d.ts} +20 -8
- package/dist/types/src/ElementAnimate.d.ts +89 -0
- package/dist/types/src/{DOMUtilsEvent.d.ts → ElementEvent.d.ts} +19 -84
- package/dist/types/src/ElementHandler.d.ts +17 -0
- package/dist/types/src/ElementSelector.d.ts +96 -0
- package/dist/types/src/ElementWait.d.ts +278 -0
- package/dist/types/src/GlobalData.d.ts +4 -0
- package/dist/types/src/{DOMUtilsOriginPrototype.d.ts → OriginPrototype.d.ts} +1 -2
- package/dist/types/src/Utils.d.ts +68 -0
- package/dist/types/src/{DOMUtils.d.ts → index.d.ts} +157 -177
- package/dist/types/src/types/env.d.ts +9 -0
- package/dist/types/src/types/global.d.ts +0 -2
- package/dist/types/src/types/gm.d.ts +0 -4
- package/index.ts +1 -1
- package/package.json +6 -2
- package/src/{DOMUtilsCommonUtils.ts → CommonUtils.ts} +25 -11
- package/src/ElementAnimate.ts +290 -0
- package/src/{DOMUtilsEvent.ts → ElementEvent.ts} +166 -361
- package/src/ElementHandler.ts +43 -0
- package/src/ElementSelector.ts +260 -0
- package/src/ElementWait.ts +699 -0
- package/src/GlobalData.ts +5 -0
- package/src/{DOMUtilsOriginPrototype.ts → OriginPrototype.ts} +1 -3
- package/src/Utils.ts +386 -0
- package/src/{DOMUtils.ts → index.ts} +678 -757
- package/src/types/env.d.ts +9 -0
- package/src/types/global.d.ts +0 -2
- package/src/types/gm.d.ts +0 -4
- package/dist/types/src/DOMUtilsData.d.ts +0 -5
- 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 };
|