wikiparser-node 0.4.0 → 0.6.1
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/config/default.json +129 -66
- package/config/zhwiki.json +4 -4
- package/index.js +97 -65
- package/lib/element.js +159 -302
- package/lib/node.js +384 -198
- package/lib/ranges.js +3 -4
- package/lib/text.js +65 -36
- package/lib/title.js +9 -8
- package/mixin/fixedToken.js +4 -4
- package/mixin/hidden.js +2 -0
- package/mixin/sol.js +16 -7
- package/package.json +14 -3
- package/parser/brackets.js +8 -2
- package/parser/commentAndExt.js +1 -1
- package/parser/converter.js +1 -1
- package/parser/externalLinks.js +2 -2
- package/parser/hrAndDoubleUnderscore.js +8 -7
- package/parser/links.js +8 -9
- package/parser/magicLinks.js +1 -1
- package/parser/selector.js +5 -5
- package/parser/table.js +18 -16
- package/src/arg.js +71 -42
- package/src/atom/index.js +7 -5
- package/src/attribute.js +102 -64
- package/src/charinsert.js +91 -0
- package/src/converter.js +34 -15
- package/src/converterFlags.js +87 -40
- package/src/converterRule.js +59 -53
- package/src/extLink.js +45 -37
- package/src/gallery.js +71 -16
- package/src/hasNowiki/index.js +42 -0
- package/src/hasNowiki/pre.js +40 -0
- package/src/heading.js +41 -18
- package/src/html.js +76 -48
- package/src/imageParameter.js +73 -51
- package/src/imagemap.js +205 -0
- package/src/imagemapLink.js +43 -0
- package/src/index.js +243 -138
- package/src/link/category.js +10 -14
- package/src/link/file.js +112 -56
- package/src/link/galleryImage.js +74 -10
- package/src/link/index.js +86 -61
- package/src/magicLink.js +48 -21
- package/src/nested/choose.js +24 -0
- package/src/nested/combobox.js +23 -0
- package/src/nested/index.js +88 -0
- package/src/nested/references.js +23 -0
- package/src/nowiki/comment.js +18 -4
- package/src/nowiki/dd.js +2 -2
- package/src/nowiki/doubleUnderscore.js +16 -11
- package/src/nowiki/index.js +12 -0
- package/src/nowiki/quote.js +28 -1
- package/src/onlyinclude.js +15 -8
- package/src/paramTag/index.js +83 -0
- package/src/paramTag/inputbox.js +42 -0
- package/src/parameter.js +73 -46
- package/src/syntax.js +9 -1
- package/src/table/index.js +58 -44
- package/src/table/td.js +63 -63
- package/src/table/tr.js +52 -35
- package/src/tagPair/ext.js +60 -43
- package/src/tagPair/include.js +11 -1
- package/src/tagPair/index.js +29 -20
- package/src/transclude.js +214 -166
- package/tool/index.js +720 -439
- package/util/base.js +17 -0
- package/util/debug.js +1 -1
- package/{test/util.js → util/diff.js} +15 -19
- package/util/lint.js +40 -0
- package/util/string.js +37 -20
- package/.eslintrc.json +0 -714
- package/errors/README +0 -1
- package/jsconfig.json +0 -7
- package/printed/README +0 -1
- package/printed/example.json +0 -120
- package/test/api.js +0 -83
- package/test/real.js +0 -133
- package/test/test.js +0 -28
- package/typings/api.d.ts +0 -13
- package/typings/array.d.ts +0 -28
- package/typings/event.d.ts +0 -24
- package/typings/index.d.ts +0 -94
- package/typings/node.d.ts +0 -29
- package/typings/parser.d.ts +0 -16
- package/typings/table.d.ts +0 -14
- package/typings/token.d.ts +0 -22
- package/typings/tool.d.ts +0 -11
package/tool/index.js
CHANGED
|
@@ -1,60 +1,100 @@
|
|
|
1
|
-
/* eslint no-underscore-dangle: [2, {allowAfterThis: true, enforceInMethodNames: false, allow: ['__filename']}] */
|
|
2
1
|
'use strict';
|
|
3
2
|
|
|
4
|
-
const {typeError
|
|
5
|
-
{text
|
|
6
|
-
|
|
3
|
+
const {typeError} = require('../util/debug'),
|
|
4
|
+
{text} = require('../util/string'),
|
|
5
|
+
{isPlainObject} = require('../util/base'),
|
|
6
|
+
Parser = require('..'),
|
|
7
|
+
AstNode = require('../lib/node'),
|
|
7
8
|
Token = require('../src'),
|
|
8
|
-
|
|
9
|
+
AttributeToken = require('../src/attribute');
|
|
9
10
|
|
|
10
|
-
const /** @type {WeakMap<Token, Record<string,
|
|
11
|
+
const /** @type {WeakMap<Token, Record<string, *>>} */ cache = new WeakMap();
|
|
11
12
|
|
|
12
|
-
/**
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
* @returns {(token: Token) => boolean}
|
|
16
|
-
*/
|
|
17
|
-
const matchesGenerator = (method, selector) => {
|
|
18
|
-
if (typeof selector === 'string') {
|
|
19
|
-
return token => token instanceof Token && token.matches(selector);
|
|
20
|
-
} else if (Array.isArray(selector)) {
|
|
21
|
-
return token => selector.includes(token);
|
|
22
|
-
} else if (selector instanceof Token) {
|
|
23
|
-
return token => token === selector;
|
|
24
|
-
}
|
|
25
|
-
return typeError(TokenCollection, method, 'String', 'Token', 'Array'); // eslint-disable-line no-use-before-define
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
/** @extends {Array<Token>} */
|
|
29
|
-
class TokenCollection extends Array {
|
|
30
|
-
/** @type {TokenCollection} */ prevObject;
|
|
13
|
+
/** Token集合 */
|
|
14
|
+
class TokenCollection {
|
|
15
|
+
/** @type {AstNode[]} */ array = [];
|
|
31
16
|
/** @type {Set<Token>} */ #roots = new Set();
|
|
17
|
+
/** @type {TokenCollection} */ prevObject;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* 生成匹配函数
|
|
21
|
+
* @param {string} method
|
|
22
|
+
* @param {string|AstNode|Iterable<AstNode>} selector
|
|
23
|
+
* @returns {(token: AstNode) => boolean}
|
|
24
|
+
*/
|
|
25
|
+
static #matchesGenerator = (method, selector) => {
|
|
26
|
+
if (selector === undefined || typeof selector === 'string') {
|
|
27
|
+
return token => token instanceof Token && token.matches(selector);
|
|
28
|
+
} else if (selector?.[Symbol.iterator]) {
|
|
29
|
+
return token => new Set(selector).has(token);
|
|
30
|
+
}
|
|
31
|
+
return selector instanceof AstNode
|
|
32
|
+
? token => token === selector
|
|
33
|
+
: typeError(TokenCollection, method, 'String', 'AstNode', 'Iterable');
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
/** @ignore */
|
|
37
|
+
[Symbol.iterator]() {
|
|
38
|
+
return this.array[Symbol.iterator]();
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** 数组长度 */
|
|
42
|
+
get length() {
|
|
43
|
+
return this.array.length;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** 数组长度 */
|
|
47
|
+
size() {
|
|
48
|
+
return this.array.length;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* 筛选Token节点
|
|
53
|
+
* @returns {Token[]}
|
|
54
|
+
*/
|
|
55
|
+
get #tokens() {
|
|
56
|
+
return this.array.filter(ele => ele instanceof Token);
|
|
57
|
+
}
|
|
32
58
|
|
|
33
|
-
/**
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
59
|
+
/**
|
|
60
|
+
* 第一个Token节点
|
|
61
|
+
* @returns {Token}
|
|
62
|
+
*/
|
|
63
|
+
get #firstToken() {
|
|
64
|
+
return this.array.find(ele => ele instanceof Token);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* @param {Iterable<AstNode>} arr 节点数组
|
|
69
|
+
* @param {TokenCollection} prevObject 前身
|
|
70
|
+
*/
|
|
71
|
+
constructor(arr, prevObject) {
|
|
72
|
+
if (prevObject && !(prevObject instanceof TokenCollection)) {
|
|
73
|
+
this.typeError('constructor', 'TokenCollection');
|
|
38
74
|
}
|
|
39
75
|
for (const token of arr) {
|
|
40
76
|
if (token === undefined) {
|
|
41
77
|
continue;
|
|
42
|
-
} else if (token instanceof
|
|
43
|
-
this.
|
|
44
|
-
} else if (!(token
|
|
45
|
-
this.typeError('constructor', 'AstText', 'Token');
|
|
46
|
-
} else if (!this.includes(token)) {
|
|
78
|
+
} else if (!(token instanceof AstNode)) {
|
|
79
|
+
this.typeError('constructor', 'AstNode');
|
|
80
|
+
} else if (!this.array.includes(token)) {
|
|
47
81
|
this.#roots.add(token.getRootNode());
|
|
48
|
-
this.push(token);
|
|
82
|
+
this.array.push(token);
|
|
49
83
|
}
|
|
50
84
|
}
|
|
51
|
-
|
|
85
|
+
this.prevObject = prevObject;
|
|
52
86
|
this.#sort();
|
|
87
|
+
Object.defineProperties(this, {
|
|
88
|
+
array: {writable: false, configurable: false},
|
|
89
|
+
prevObject: {enumerable: prevObject, writable: false, configurable: false},
|
|
90
|
+
});
|
|
91
|
+
Object.freeze(this.array);
|
|
53
92
|
}
|
|
54
93
|
|
|
55
94
|
/**
|
|
95
|
+
* 抛出TypeError
|
|
56
96
|
* @param {string} method
|
|
57
|
-
* @param {...string} types
|
|
97
|
+
* @param {...string} types 可接受的参数类型
|
|
58
98
|
*/
|
|
59
99
|
typeError(method, ...types) {
|
|
60
100
|
return typeError(this.constructor, method, ...types);
|
|
@@ -62,316 +102,399 @@ class TokenCollection extends Array {
|
|
|
62
102
|
|
|
63
103
|
/** 节点排序 */
|
|
64
104
|
#sort() {
|
|
65
|
-
if (this.some(({type}) => type === 'text')) {
|
|
66
|
-
return;
|
|
67
|
-
}
|
|
68
105
|
const rootArray = [...this.#roots];
|
|
69
|
-
this.sort((a, b) => {
|
|
106
|
+
this.array.sort(/** @type {(a: AstNode, b: AstNode) => boolean} */ (a, b) => {
|
|
70
107
|
const aRoot = a.getRootNode(),
|
|
71
108
|
bRoot = b.getRootNode();
|
|
72
109
|
return aRoot === bRoot ? a.compareDocumentPosition(b) : rootArray.indexOf(aRoot) - rootArray.indexOf(bRoot);
|
|
73
110
|
});
|
|
74
111
|
}
|
|
75
112
|
|
|
113
|
+
/** 转换为数组 */
|
|
76
114
|
toArray() {
|
|
77
115
|
return [...this];
|
|
78
116
|
}
|
|
79
117
|
|
|
80
|
-
_filter(selector = '') {
|
|
81
|
-
const arr = this.toArray().filter(ele => ele instanceof Token);
|
|
82
|
-
if (selector) {
|
|
83
|
-
return arr.filter(ele => ele.matches(selector));
|
|
84
|
-
}
|
|
85
|
-
return arr;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
_find() {
|
|
89
|
-
return super.find(ele => ele instanceof Token);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
/** @param {(arr: Token[]) => (string|Token)[]} map */
|
|
93
|
-
_create(map, filter = '') {
|
|
94
|
-
const $arr = $(map(this._filter())),
|
|
95
|
-
$filtered = filter ? $arr.filter(filter) : $arr;
|
|
96
|
-
$filtered.prevObject = this;
|
|
97
|
-
return $filtered;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
118
|
/**
|
|
119
|
+
* 提取第n个元素
|
|
101
120
|
* @template {unknown} T
|
|
102
|
-
* @param {T}
|
|
103
|
-
* @returns {T extends number ?
|
|
121
|
+
* @param {T} n 序号
|
|
122
|
+
* @returns {T extends number ? AstNode : AstNode[]}
|
|
104
123
|
*/
|
|
105
|
-
get(
|
|
106
|
-
if (
|
|
107
|
-
return this.at(
|
|
124
|
+
get(n) {
|
|
125
|
+
if (Number.isInteger(n)) {
|
|
126
|
+
return this.array.at(n);
|
|
108
127
|
}
|
|
109
|
-
return this.toArray();
|
|
128
|
+
return n === undefined ? this.toArray() : this.typeError('get', 'Number');
|
|
110
129
|
}
|
|
111
130
|
|
|
112
|
-
/**
|
|
131
|
+
/**
|
|
132
|
+
* 循环
|
|
133
|
+
* @param {CollectionCallback<void, AstNode>} callback
|
|
134
|
+
*/
|
|
113
135
|
each(callback) {
|
|
114
136
|
for (let i = 0; i < this.length; i++) {
|
|
115
|
-
|
|
137
|
+
const ele = this.array[i];
|
|
138
|
+
callback.call(ele, i, ele);
|
|
116
139
|
}
|
|
117
140
|
return this;
|
|
118
141
|
}
|
|
119
142
|
|
|
120
|
-
/**
|
|
143
|
+
/**
|
|
144
|
+
* map方法
|
|
145
|
+
* @param {CollectionCallback<*, AstNode>} callback
|
|
146
|
+
*/
|
|
121
147
|
map(callback) {
|
|
122
|
-
const arr = this.
|
|
148
|
+
const arr = this.array.map((ele, i) => callback.call(ele, i, ele));
|
|
123
149
|
try {
|
|
124
|
-
|
|
125
|
-
$arr.prevObject = this;
|
|
126
|
-
return $arr;
|
|
150
|
+
return new TokenCollection(arr, this);
|
|
127
151
|
} catch {
|
|
128
152
|
return arr;
|
|
129
153
|
}
|
|
130
154
|
}
|
|
131
155
|
|
|
132
156
|
/**
|
|
133
|
-
*
|
|
134
|
-
* @param {number}
|
|
157
|
+
* 子序列
|
|
158
|
+
* @param {number} start 起点
|
|
159
|
+
* @param {number} end 终点
|
|
135
160
|
*/
|
|
136
161
|
slice(start, end) {
|
|
137
|
-
|
|
138
|
-
$arr.prevObject = this;
|
|
139
|
-
return $arr;
|
|
162
|
+
return new TokenCollection(this.array.slice(start, end), this);
|
|
140
163
|
}
|
|
141
164
|
|
|
165
|
+
/** 第一个元素 */
|
|
142
166
|
first() {
|
|
143
167
|
return this.slice(0, 1);
|
|
144
168
|
}
|
|
145
169
|
|
|
170
|
+
/** 最后一个元素 */
|
|
146
171
|
last() {
|
|
147
172
|
return this.slice(-1);
|
|
148
173
|
}
|
|
149
174
|
|
|
150
|
-
/**
|
|
175
|
+
/**
|
|
176
|
+
* 任一元素
|
|
177
|
+
* @param {number} i 序号
|
|
178
|
+
*/
|
|
151
179
|
eq(i) {
|
|
152
180
|
return this.slice(i, i === -1 ? undefined : i + 1);
|
|
153
181
|
}
|
|
154
182
|
|
|
155
183
|
/** 使用空字符串join */
|
|
156
184
|
toString() {
|
|
157
|
-
return this.
|
|
185
|
+
return this.array.map(String).join('');
|
|
158
186
|
}
|
|
159
187
|
|
|
160
188
|
/**
|
|
189
|
+
* 输出有效部分或设置文本
|
|
161
190
|
* @template {unknown} T
|
|
162
|
-
* @param {T} str
|
|
163
|
-
* @returns {T extends string|
|
|
191
|
+
* @param {T} str 新文本
|
|
192
|
+
* @returns {T extends string|CollectionCallback<string, string> ? this : string}
|
|
164
193
|
*/
|
|
165
194
|
text(str) {
|
|
166
|
-
/** @type {
|
|
167
|
-
const callback = typeof str === 'function' ? str.call : () => str;
|
|
195
|
+
const /** @type {CollectionCallback<string, string> */ callback = typeof str === 'function' ? str : () => str;
|
|
168
196
|
if (typeof str === 'string' || typeof str === 'function') {
|
|
169
197
|
for (let i = 0; i < this.length; i++) {
|
|
170
|
-
const ele = this[i];
|
|
198
|
+
const ele = this.array[i];
|
|
171
199
|
if (ele instanceof Token) {
|
|
172
200
|
try {
|
|
173
|
-
ele.replaceChildren(callback(ele, i, ele.text()));
|
|
201
|
+
ele.replaceChildren(callback.call(ele, i, ele.text()));
|
|
174
202
|
} catch {}
|
|
175
203
|
}
|
|
176
204
|
}
|
|
177
205
|
return this;
|
|
178
206
|
}
|
|
179
|
-
return text(this.toArray());
|
|
207
|
+
return str === undefined ? text(this.toArray()) : this.typeError('text', 'String', 'Function');
|
|
180
208
|
}
|
|
181
209
|
|
|
182
|
-
/**
|
|
210
|
+
/**
|
|
211
|
+
* 判断是否存在元素满足选择器
|
|
212
|
+
* @param {string|AstNode|Iterable<AstNode>|CollectionCallback<boolean, AstNode>} selector
|
|
213
|
+
*/
|
|
183
214
|
is(selector) {
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
const matches = matchesGenerator('is', selector);
|
|
188
|
-
return this.some(matches);
|
|
215
|
+
return typeof selector === 'function'
|
|
216
|
+
? this.array.some((ele, i) => selector.call(ele, i, ele))
|
|
217
|
+
: this.array.some(TokenCollection.#matchesGenerator('is', selector));
|
|
189
218
|
}
|
|
190
219
|
|
|
191
|
-
/**
|
|
220
|
+
/**
|
|
221
|
+
* 筛选满足选择器的元素
|
|
222
|
+
* @param {string|AstNode|Iterable<AstNode>|CollectionCallback<boolean, AstNode>} selector
|
|
223
|
+
*/
|
|
192
224
|
filter(selector) {
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
const matches = matchesGenerator('filter', selector);
|
|
199
|
-
$arr = $(arr.filter(matches));
|
|
200
|
-
}
|
|
201
|
-
$arr.prevObject = this;
|
|
202
|
-
return $arr;
|
|
225
|
+
return new TokenCollection(this.array.filter(
|
|
226
|
+
(ele, i) => typeof selector === 'function'
|
|
227
|
+
? selector.call(ele, i, ele)
|
|
228
|
+
: TokenCollection.#matchesGenerator('filter', selector)(ele),
|
|
229
|
+
), this);
|
|
203
230
|
}
|
|
204
231
|
|
|
205
|
-
/**
|
|
232
|
+
/**
|
|
233
|
+
* 筛选不满足选择器的元素
|
|
234
|
+
* @param {string|AstNode|Iterable<AstNode>|CollectionCallback<boolean, AstNode>} selector
|
|
235
|
+
*/
|
|
206
236
|
not(selector) {
|
|
207
|
-
|
|
208
|
-
let $arr;
|
|
237
|
+
let /** @type {(ele: AstNode, i: number) => boolean} */ callback;
|
|
209
238
|
if (typeof selector === 'function') {
|
|
210
|
-
|
|
211
|
-
} else if (typeof selector === 'string') {
|
|
212
|
-
$arr = $(arr.filter(ele => ele instanceof Token && !ele.matches(selector)));
|
|
239
|
+
callback = /** @implements */ (ele, i) => !selector.call(ele, i, ele);
|
|
213
240
|
} else {
|
|
214
|
-
const matches = matchesGenerator('not', selector);
|
|
215
|
-
|
|
241
|
+
const matches = TokenCollection.#matchesGenerator('not', selector);
|
|
242
|
+
callback = /** @implements */ ele => !matches(ele);
|
|
216
243
|
}
|
|
217
|
-
|
|
218
|
-
return $arr;
|
|
244
|
+
return new TokenCollection(this.array.filter(callback), this);
|
|
219
245
|
}
|
|
220
246
|
|
|
221
|
-
/**
|
|
247
|
+
/**
|
|
248
|
+
* 搜索满足选择器的子节点
|
|
249
|
+
* @param {string|AstNode|Iterable<AstNode>} selector
|
|
250
|
+
*/
|
|
222
251
|
find(selector) {
|
|
223
|
-
let
|
|
224
|
-
if (typeof selector === 'string') {
|
|
225
|
-
|
|
226
|
-
} else if (
|
|
227
|
-
|
|
228
|
-
} else if (selector instanceof
|
|
229
|
-
|
|
252
|
+
let arr;
|
|
253
|
+
if (selector === undefined || typeof selector === 'string') {
|
|
254
|
+
arr = this.array.flatMap(token => token instanceof Token ? token.querySelectorAll(selector) : []);
|
|
255
|
+
} else if (selector?.[Symbol.iterator]) {
|
|
256
|
+
arr = [...selector].filter(ele => this.array.some(token => token.contains(ele)));
|
|
257
|
+
} else if (selector instanceof AstNode) {
|
|
258
|
+
arr = this.array.some(token => token.contains(selector)) ? [selector] : [];
|
|
230
259
|
} else {
|
|
231
|
-
this.typeError('find', 'String', '
|
|
260
|
+
this.typeError('find', 'String', 'AstNode', 'Iterable');
|
|
232
261
|
}
|
|
233
|
-
return this
|
|
262
|
+
return new TokenCollection(arr, this);
|
|
234
263
|
}
|
|
235
264
|
|
|
236
|
-
/**
|
|
265
|
+
/**
|
|
266
|
+
* 是否存在满足条件的后代节点
|
|
267
|
+
* @param {string|AstNode} selector
|
|
268
|
+
*/
|
|
237
269
|
has(selector) {
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
return arr.some(ele => ele.querySelector(selector));
|
|
241
|
-
} else if (selector instanceof Token) {
|
|
242
|
-
return arr.some(ele => ele.contains(selector));
|
|
270
|
+
if (selector === undefined || typeof selector === 'string') {
|
|
271
|
+
return this.array.some(ele => ele instanceof Token && ele.querySelector(selector));
|
|
243
272
|
}
|
|
244
|
-
return
|
|
273
|
+
return selector instanceof AstNode
|
|
274
|
+
? this.array.some(ele => ele.contains(selector))
|
|
275
|
+
: this.typeError('has', 'String', 'AstNode');
|
|
245
276
|
}
|
|
246
277
|
|
|
247
|
-
/**
|
|
278
|
+
/**
|
|
279
|
+
* 最近的祖先
|
|
280
|
+
* @param {string} selector
|
|
281
|
+
*/
|
|
248
282
|
closest(selector) {
|
|
249
|
-
if (
|
|
250
|
-
this.
|
|
283
|
+
if (selector === undefined) {
|
|
284
|
+
return new TokenCollection(this.array.map(ele => ele.parentNode), this);
|
|
251
285
|
}
|
|
252
|
-
return
|
|
286
|
+
return typeof selector === 'string'
|
|
287
|
+
? new TokenCollection(this.#tokens.map(ele => ele.closest(selector)), this)
|
|
288
|
+
: this.typeError('closest', 'String');
|
|
253
289
|
}
|
|
254
290
|
|
|
291
|
+
/** 第一个Token节点在父容器中的序号 */
|
|
255
292
|
index() {
|
|
256
|
-
const
|
|
257
|
-
if (
|
|
258
|
-
|
|
293
|
+
const {array: [firstNode]} = this;
|
|
294
|
+
if (firstNode) {
|
|
295
|
+
const {parentNode} = firstNode;
|
|
296
|
+
return parentNode ? parentNode.childNodes.indexOf(firstNode) : 0;
|
|
259
297
|
}
|
|
260
|
-
|
|
261
|
-
return parentNode ? parentNode.childNodes.indexOf(firstToken) : 0;
|
|
298
|
+
return -1;
|
|
262
299
|
}
|
|
263
300
|
|
|
264
|
-
/**
|
|
301
|
+
/**
|
|
302
|
+
* 添加元素
|
|
303
|
+
* @param {AstNode|Iterable<AstNode>} elements 新增的元素
|
|
304
|
+
*/
|
|
265
305
|
add(elements) {
|
|
266
|
-
|
|
267
|
-
const $arr = $([...this, ...elements]);
|
|
268
|
-
$arr.prevObject = this;
|
|
269
|
-
return $arr;
|
|
306
|
+
return new TokenCollection([...this, ...Symbol.iterator in elements ? elements : [elements]], this);
|
|
270
307
|
}
|
|
271
308
|
|
|
272
|
-
/**
|
|
309
|
+
/**
|
|
310
|
+
* 添加prevObject
|
|
311
|
+
* @param {string} selector
|
|
312
|
+
*/
|
|
273
313
|
addBack(selector) {
|
|
274
314
|
return this.add(selector ? this.prevObject.filter(selector) : this.prevObject);
|
|
275
315
|
}
|
|
276
316
|
|
|
277
|
-
|
|
278
|
-
|
|
317
|
+
/**
|
|
318
|
+
* 带选择器筛选的map
|
|
319
|
+
* @param {string} method
|
|
320
|
+
* @param {(ele: AstNode) => Token} callback
|
|
321
|
+
* @param {string} selector
|
|
322
|
+
*/
|
|
323
|
+
#map(method, callback, selector) {
|
|
324
|
+
return selector === undefined || typeof selector === 'string'
|
|
325
|
+
? new TokenCollection(this.array.map(callback).filter(ele => ele.matches(selector)), this)
|
|
326
|
+
: this.typeError(method, 'String');
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* 带选择器筛选的flatMap
|
|
331
|
+
* @param {string} method
|
|
332
|
+
* @param {(ele: AstNode) => Token|Token[]} callback
|
|
333
|
+
* @param {string} selector
|
|
334
|
+
*/
|
|
335
|
+
#flatMap(method, callback, selector) {
|
|
336
|
+
return selector === undefined || typeof selector === 'string'
|
|
337
|
+
? new TokenCollection(this.array.flatMap(callback).filter(ele => ele.matches(selector)), this)
|
|
338
|
+
: this.typeError(method, 'String');
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* 父元素
|
|
343
|
+
* @param {string} selector
|
|
344
|
+
*/
|
|
345
|
+
parent(selector) {
|
|
346
|
+
return this.#map('parent', ele => ele.parentNode, selector);
|
|
279
347
|
}
|
|
280
348
|
|
|
281
|
-
|
|
282
|
-
|
|
349
|
+
/**
|
|
350
|
+
* 祖先
|
|
351
|
+
* @param {string} selector
|
|
352
|
+
*/
|
|
353
|
+
parents(selector) {
|
|
354
|
+
return this.#flatMap('parents', ele => ele.getAncestors(), selector);
|
|
283
355
|
}
|
|
284
356
|
|
|
285
|
-
|
|
286
|
-
|
|
357
|
+
/**
|
|
358
|
+
* nextElementSibling
|
|
359
|
+
* @param {string} selector
|
|
360
|
+
*/
|
|
361
|
+
next(selector) {
|
|
362
|
+
return this.#map('next', ele => ele.nextElementSibling, selector);
|
|
287
363
|
}
|
|
288
364
|
|
|
289
|
-
|
|
290
|
-
|
|
365
|
+
/**
|
|
366
|
+
* previousElementSibling
|
|
367
|
+
* @param {string} selector
|
|
368
|
+
*/
|
|
369
|
+
prev(selector) {
|
|
370
|
+
return this.#map('prev', ele => ele.previousElementSibling, selector);
|
|
291
371
|
}
|
|
292
372
|
|
|
293
373
|
/**
|
|
294
|
-
*
|
|
295
|
-
* @param {
|
|
374
|
+
* 筛选兄弟
|
|
375
|
+
* @param {string} method
|
|
376
|
+
* @param {(i: number) => number} start 起点
|
|
377
|
+
* @param {(i: number) => number} count 数量
|
|
378
|
+
* @param {string} selector
|
|
296
379
|
*/
|
|
297
|
-
|
|
298
|
-
|
|
380
|
+
#siblings(method, start, count, selector) {
|
|
381
|
+
if (selector !== undefined && typeof selector !== 'string') {
|
|
382
|
+
this.typeError(method, 'String');
|
|
383
|
+
}
|
|
384
|
+
return new TokenCollection(this.array.flatMap(ele => {
|
|
299
385
|
const {parentNode} = ele;
|
|
300
386
|
if (!parentNode) {
|
|
301
|
-
return
|
|
387
|
+
return [];
|
|
302
388
|
}
|
|
303
|
-
const {
|
|
304
|
-
i =
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
);
|
|
309
|
-
return children;
|
|
310
|
-
}), selector);
|
|
389
|
+
const {childNodes} = parentNode,
|
|
390
|
+
i = childNodes.indexOf(ele);
|
|
391
|
+
childNodes.splice(start(i), count(i));
|
|
392
|
+
return childNodes;
|
|
393
|
+
}).filter(ele => ele instanceof Token && ele.matches(selector)), this);
|
|
311
394
|
}
|
|
312
395
|
|
|
313
|
-
|
|
314
|
-
|
|
396
|
+
/**
|
|
397
|
+
* 所有在后的兄弟
|
|
398
|
+
* @param {string} selector
|
|
399
|
+
*/
|
|
400
|
+
nextAll(selector) {
|
|
401
|
+
return this.#siblings('nextAll', () => 0, i => i + 1, selector);
|
|
315
402
|
}
|
|
316
403
|
|
|
317
|
-
|
|
318
|
-
|
|
404
|
+
/**
|
|
405
|
+
* 所有在前的兄弟
|
|
406
|
+
* @param {string} selector
|
|
407
|
+
*/
|
|
408
|
+
prevAll(selector) {
|
|
409
|
+
return this.#siblings('prevAll', i => i, () => Infinity, selector);
|
|
319
410
|
}
|
|
320
411
|
|
|
321
|
-
|
|
322
|
-
|
|
412
|
+
/**
|
|
413
|
+
* 所有在后的兄弟
|
|
414
|
+
* @param {string} selector
|
|
415
|
+
*/
|
|
416
|
+
siblings(selector) {
|
|
417
|
+
return this.#siblings('siblings', i => i, () => 1, selector);
|
|
323
418
|
}
|
|
324
419
|
|
|
325
420
|
/**
|
|
421
|
+
* 直到选择器被满足
|
|
326
422
|
* @param {'parents'|'nextAll'|'prevAll'} method
|
|
327
|
-
* @param {string|Token|Token
|
|
423
|
+
* @param {string|Token|Iterable<Token>} selector
|
|
424
|
+
* @param {string} filter 额外的筛选选择器
|
|
328
425
|
*/
|
|
329
|
-
|
|
330
|
-
const
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
426
|
+
#until(method, selector, filter) {
|
|
427
|
+
const originalMethod = `${method.replace(/All$/u, '')}Until`;
|
|
428
|
+
if (filter !== undefined && typeof filter !== 'string') {
|
|
429
|
+
this.typeError(originalMethod, 'String');
|
|
430
|
+
}
|
|
431
|
+
const matches = TokenCollection.#matchesGenerator(originalMethod, selector);
|
|
432
|
+
return new TokenCollection(this.array.flatMap(ele => {
|
|
433
|
+
const /** @type {{array: Token[]}} */ {array} = $(ele)[method](),
|
|
434
|
+
until = array[method === 'nextAll' ? 'findIndex' : 'findLastIndex'](end => matches(end));
|
|
435
|
+
return method === 'nextAll' ? array.slice(0, until) : array.slice(until + 1);
|
|
436
|
+
}).filter(ele => ele.matches(filter)), this);
|
|
337
437
|
}
|
|
338
438
|
|
|
339
|
-
/**
|
|
340
|
-
|
|
341
|
-
|
|
439
|
+
/**
|
|
440
|
+
* 直到选择器被满足的祖先
|
|
441
|
+
* @param {string|Token|Iterable<Token>} selector
|
|
442
|
+
* @param {string} filter 额外的筛选选择器
|
|
443
|
+
*/
|
|
444
|
+
parentsUntil(selector, filter) {
|
|
445
|
+
return this.#until('parents', selector, filter);
|
|
342
446
|
}
|
|
343
447
|
|
|
344
|
-
/**
|
|
345
|
-
|
|
346
|
-
|
|
448
|
+
/**
|
|
449
|
+
* 直到选择器被满足的后方兄弟
|
|
450
|
+
* @param {string|Token|Iterable<Token>} selector
|
|
451
|
+
* @param {string} filter 额外的筛选选择器
|
|
452
|
+
*/
|
|
453
|
+
nextUntil(selector, filter) {
|
|
454
|
+
return this.#until('nextAll', selector, filter);
|
|
347
455
|
}
|
|
348
456
|
|
|
349
|
-
/**
|
|
350
|
-
|
|
351
|
-
|
|
457
|
+
/**
|
|
458
|
+
* 直到选择器被满足的前方兄弟
|
|
459
|
+
* @param {string|Token|Iterable<Token>} selector
|
|
460
|
+
* @param {string} filter 额外的筛选选择器
|
|
461
|
+
*/
|
|
462
|
+
prevUntil(selector, filter) {
|
|
463
|
+
return this.#until('prevAll', selector, filter);
|
|
352
464
|
}
|
|
353
465
|
|
|
354
|
-
|
|
355
|
-
|
|
466
|
+
/**
|
|
467
|
+
* Token子节点
|
|
468
|
+
* @param {string} selector
|
|
469
|
+
*/
|
|
470
|
+
children(selector) {
|
|
471
|
+
return selector === undefined || typeof selector === 'string'
|
|
472
|
+
? new TokenCollection(this.#tokens.flatMap(ele => ele.children).filter(ele => ele.matches(selector)), this)
|
|
473
|
+
: this.typeError('children', 'String');
|
|
356
474
|
}
|
|
357
475
|
|
|
476
|
+
/** 所有子节点 */
|
|
358
477
|
contents() {
|
|
359
|
-
return this.
|
|
478
|
+
return new TokenCollection(this.array.flatMap(ele => ele.childNodes), this);
|
|
360
479
|
}
|
|
361
480
|
|
|
362
|
-
/**
|
|
481
|
+
/**
|
|
482
|
+
* 存取数据
|
|
483
|
+
* @param {string|Record<string, *>} key 键
|
|
484
|
+
* @param {*} value 值
|
|
485
|
+
*/
|
|
363
486
|
data(key, value) {
|
|
364
487
|
if (value !== undefined && typeof key !== 'string') {
|
|
365
488
|
this.typeError('data', 'String');
|
|
366
|
-
} else if (value === undefined &&
|
|
367
|
-
const data =
|
|
489
|
+
} else if (value === undefined && !isPlainObject(key)) {
|
|
490
|
+
const data = cache.get(this.#firstToken);
|
|
368
491
|
return key === undefined ? data : data?.[key];
|
|
369
492
|
}
|
|
370
|
-
for (const token of this
|
|
371
|
-
if (
|
|
372
|
-
|
|
493
|
+
for (const token of this.#tokens) {
|
|
494
|
+
if (!cache.has(token)) {
|
|
495
|
+
cache.set(token, {});
|
|
373
496
|
}
|
|
374
|
-
const data =
|
|
497
|
+
const data = cache.get(token);
|
|
375
498
|
if (typeof key === 'string') {
|
|
376
499
|
data[key] = value;
|
|
377
500
|
} else {
|
|
@@ -381,19 +504,22 @@ class TokenCollection extends Array {
|
|
|
381
504
|
return this;
|
|
382
505
|
}
|
|
383
506
|
|
|
384
|
-
/**
|
|
507
|
+
/**
|
|
508
|
+
* 删除数据
|
|
509
|
+
* @param {string|string[]} name 键
|
|
510
|
+
*/
|
|
385
511
|
removeData(name) {
|
|
386
512
|
if (name !== undefined && typeof name !== 'string' && !Array.isArray(name)) {
|
|
387
513
|
this.typeError('removeData', 'String', 'Array');
|
|
388
514
|
}
|
|
389
515
|
name = typeof name === 'string' ? name.split(/\s/u) : name;
|
|
390
|
-
for (const token of this
|
|
391
|
-
if (
|
|
516
|
+
for (const token of this.#tokens) {
|
|
517
|
+
if (!cache.has(token)) {
|
|
392
518
|
continue;
|
|
393
519
|
} else if (name === undefined) {
|
|
394
|
-
|
|
520
|
+
cache.delete(token);
|
|
395
521
|
} else {
|
|
396
|
-
const data =
|
|
522
|
+
const data = cache.get(token);
|
|
397
523
|
for (const key of name) {
|
|
398
524
|
delete data[key];
|
|
399
525
|
}
|
|
@@ -403,12 +529,14 @@ class TokenCollection extends Array {
|
|
|
403
529
|
}
|
|
404
530
|
|
|
405
531
|
/**
|
|
406
|
-
*
|
|
532
|
+
* 添加事件监听
|
|
533
|
+
* @param {string|Record<string, AstListener>} events 事件名
|
|
407
534
|
* @param {string|AstListener} selector
|
|
408
|
-
* @param {AstListener} handler
|
|
535
|
+
* @param {AstListener} handler 事件处理
|
|
536
|
+
* @param {boolean} once 是否一次性
|
|
409
537
|
*/
|
|
410
|
-
|
|
411
|
-
if (typeof events !== 'string' &&
|
|
538
|
+
#addEventListener(events, selector, handler, once = false) {
|
|
539
|
+
if (typeof events !== 'string' && !isPlainObject(events)) {
|
|
412
540
|
this.typeError(once ? 'once' : 'on', 'String', 'Object');
|
|
413
541
|
} else if (typeof selector === 'function') {
|
|
414
542
|
handler = selector;
|
|
@@ -417,59 +545,68 @@ class TokenCollection extends Array {
|
|
|
417
545
|
const eventPair = typeof events === 'string'
|
|
418
546
|
? events.split(/\s/u).map(/** @returns {[string, AstListener]} */ event => [event, handler])
|
|
419
547
|
: Object.entries(events);
|
|
420
|
-
for (const token of this
|
|
421
|
-
|
|
422
|
-
|
|
548
|
+
for (const token of this.#tokens) {
|
|
549
|
+
if (token.matches(selector)) {
|
|
550
|
+
for (const [event, listener] of eventPair) {
|
|
551
|
+
token.addEventListener(event, listener, {once});
|
|
552
|
+
}
|
|
423
553
|
}
|
|
424
554
|
}
|
|
425
555
|
return this;
|
|
426
556
|
}
|
|
427
557
|
|
|
428
558
|
/**
|
|
429
|
-
*
|
|
559
|
+
* 添加事件监听
|
|
560
|
+
* @param {string|Record<string, AstListener>} events 事件名
|
|
430
561
|
* @param {string|AstListener} selector
|
|
431
|
-
* @param {AstListener} handler
|
|
562
|
+
* @param {AstListener} handler 事件处理
|
|
432
563
|
*/
|
|
433
564
|
on(events, selector, handler) {
|
|
434
|
-
return this
|
|
565
|
+
return this.#addEventListener(events, selector, handler);
|
|
435
566
|
}
|
|
436
567
|
|
|
437
568
|
/**
|
|
438
|
-
*
|
|
569
|
+
* 添加一次性事件监听
|
|
570
|
+
* @param {string|Record<string, AstListener>} events 事件名
|
|
439
571
|
* @param {string|AstListener} selector
|
|
440
|
-
* @param {AstListener} handler
|
|
572
|
+
* @param {AstListener} handler 事件处理
|
|
441
573
|
*/
|
|
442
574
|
one(events, selector, handler) {
|
|
443
|
-
return this
|
|
575
|
+
return this.#addEventListener(events, selector, handler, true);
|
|
444
576
|
}
|
|
445
577
|
|
|
446
578
|
/**
|
|
447
|
-
*
|
|
579
|
+
* 移除事件监听
|
|
580
|
+
* @param {string|Record<string, AstListener|undefined>|undefined} events 事件名
|
|
448
581
|
* @param {string|AstListener} selector
|
|
449
|
-
* @param {AstListener} handler
|
|
582
|
+
* @param {AstListener} handler 事件处理
|
|
450
583
|
*/
|
|
451
584
|
off(events, selector, handler) {
|
|
452
|
-
if (
|
|
585
|
+
if (events !== undefined && typeof events !== 'string' && !isPlainObject(events)) {
|
|
453
586
|
this.typeError('off', 'String', 'Object');
|
|
587
|
+
} else if (typeof selector === 'function') {
|
|
588
|
+
handler = selector;
|
|
589
|
+
selector = undefined;
|
|
454
590
|
}
|
|
455
|
-
handler = typeof selector === 'function' ? selector : handler;
|
|
456
591
|
let eventPair;
|
|
457
592
|
if (events) {
|
|
458
593
|
eventPair = typeof events === 'string'
|
|
459
594
|
? events.split(/\s/u).map(/** @returns {[string, AstListener]} */ event => [event, handler])
|
|
460
595
|
: Object.entries(events);
|
|
461
596
|
}
|
|
462
|
-
for (const token of this
|
|
463
|
-
if (
|
|
597
|
+
for (const token of this.#tokens) {
|
|
598
|
+
if (!token.matches(selector)) {
|
|
599
|
+
continue;
|
|
600
|
+
} else if (events === undefined) {
|
|
464
601
|
token.removeAllEventListeners();
|
|
465
602
|
} else {
|
|
466
603
|
for (const [event, listener] of eventPair) {
|
|
467
|
-
if (
|
|
468
|
-
|
|
469
|
-
} else if (listener) {
|
|
604
|
+
if (listener === undefined) {
|
|
605
|
+
token.removeAllEventListeners(event);
|
|
606
|
+
} else if (typeof listener === 'function') {
|
|
470
607
|
token.removeEventListener(event, listener);
|
|
471
608
|
} else {
|
|
472
|
-
|
|
609
|
+
this.typeError('off', 'String', 'Function');
|
|
473
610
|
}
|
|
474
611
|
}
|
|
475
612
|
}
|
|
@@ -477,44 +614,52 @@ class TokenCollection extends Array {
|
|
|
477
614
|
return this;
|
|
478
615
|
}
|
|
479
616
|
|
|
480
|
-
/**
|
|
617
|
+
/**
|
|
618
|
+
* 触发事件
|
|
619
|
+
* @param {string|Event} event 事件名
|
|
620
|
+
* @param {*} data 事件数据
|
|
621
|
+
*/
|
|
481
622
|
trigger(event, data) {
|
|
482
|
-
for (const token of this
|
|
623
|
+
for (const token of this) {
|
|
483
624
|
const e = typeof event === 'string' ? new Event(event, {bubbles: true}) : new Event(event.type, event);
|
|
484
625
|
token.dispatchEvent(e, data);
|
|
485
626
|
}
|
|
486
627
|
return this;
|
|
487
628
|
}
|
|
488
629
|
|
|
489
|
-
/**
|
|
630
|
+
/**
|
|
631
|
+
* 伪装触发事件
|
|
632
|
+
* @param {string|Event} event 事件名
|
|
633
|
+
* @param {*} data 事件数据
|
|
634
|
+
*/
|
|
490
635
|
triggerHandler(event, data) {
|
|
491
|
-
const
|
|
492
|
-
if (!
|
|
636
|
+
const {array: [firstNode]} = this;
|
|
637
|
+
if (!firstNode) {
|
|
493
638
|
return undefined;
|
|
494
639
|
}
|
|
495
|
-
const e = typeof event === 'string' ? new Event(event) : event
|
|
496
|
-
listeners = firstToken.listEventListeners(typeof event === 'string' ? event : event.type);
|
|
640
|
+
const e = typeof event === 'string' ? new Event(event) : event;
|
|
497
641
|
let result;
|
|
498
|
-
for (const listener of
|
|
642
|
+
for (const listener of firstNode.listEventListeners(e.type)) {
|
|
499
643
|
result = listener(e, data);
|
|
500
644
|
}
|
|
501
645
|
return result;
|
|
502
646
|
}
|
|
503
647
|
|
|
504
648
|
/**
|
|
649
|
+
* 插入文档
|
|
505
650
|
* @param {'append'|'prepend'|'before'|'after'|'replaceChildren'|'replaceWith'} method
|
|
506
|
-
* @param {
|
|
507
|
-
* @param {...
|
|
651
|
+
* @param {AstNode|Iterable<AstNode>|CollectionCallback<AstNode|Iterable<AstNode>, string>} content 插入内容
|
|
652
|
+
* @param {...AstNode|Iterable<AstNode>} additional 更多插入内容
|
|
508
653
|
*/
|
|
509
|
-
|
|
654
|
+
#insert(method, content, ...additional) {
|
|
510
655
|
if (typeof content === 'function') {
|
|
511
656
|
for (let i = 0; i < this.length; i++) {
|
|
512
|
-
const token = this[i];
|
|
657
|
+
const token = this.array[i];
|
|
513
658
|
if (token instanceof Token) {
|
|
514
659
|
const result = content.call(token, i, token.toString());
|
|
515
660
|
if (typeof result === 'string' || result instanceof Token) {
|
|
516
661
|
token[method](result);
|
|
517
|
-
} else if (
|
|
662
|
+
} else if (result?.[Symbol.iterator]) {
|
|
518
663
|
token[method](...result);
|
|
519
664
|
} else {
|
|
520
665
|
this.typeError(method, 'String', 'Token');
|
|
@@ -524,7 +669,10 @@ class TokenCollection extends Array {
|
|
|
524
669
|
} else {
|
|
525
670
|
for (const token of this) {
|
|
526
671
|
if (token instanceof Token) {
|
|
527
|
-
token[method](
|
|
672
|
+
token[method](
|
|
673
|
+
...Symbol.iterator in content ? content : [content],
|
|
674
|
+
...additional.flatMap(ele => Symbol.iterator in ele ? [...ele] : ele),
|
|
675
|
+
);
|
|
528
676
|
}
|
|
529
677
|
}
|
|
530
678
|
}
|
|
@@ -532,170 +680,238 @@ class TokenCollection extends Array {
|
|
|
532
680
|
}
|
|
533
681
|
|
|
534
682
|
/**
|
|
535
|
-
*
|
|
536
|
-
* @param
|
|
683
|
+
* 在末尾插入
|
|
684
|
+
* @param {AstNode|Iterable<AstNode>|CollectionCallback<AstNode|Iterable<AstNode>, string>} content 插入内容
|
|
685
|
+
* @param {...AstNode|Iterable<AstNode>} additional 更多插入内容
|
|
537
686
|
*/
|
|
538
687
|
append(content, ...additional) {
|
|
539
|
-
return this
|
|
688
|
+
return this.#insert('append', content, ...additional);
|
|
540
689
|
}
|
|
541
690
|
|
|
542
691
|
/**
|
|
543
|
-
*
|
|
544
|
-
* @param
|
|
692
|
+
* 在开头插入
|
|
693
|
+
* @param {AstNode|Iterable<AstNode>|CollectionCallback<AstNode|Iterable<AstNode>, string>} content 插入内容
|
|
694
|
+
* @param {...AstNode|Iterable<AstNode>} additional 更多插入内容
|
|
545
695
|
*/
|
|
546
696
|
prepend(content, ...additional) {
|
|
547
|
-
return this
|
|
697
|
+
return this.#insert('prepend', content, ...additional);
|
|
548
698
|
}
|
|
549
699
|
|
|
550
700
|
/**
|
|
551
|
-
*
|
|
552
|
-
* @param
|
|
701
|
+
* 在后方插入
|
|
702
|
+
* @param {AstNode|Iterable<AstNode>|CollectionCallback<AstNode|Iterable<AstNode>, string>} content 插入内容
|
|
703
|
+
* @param {...AstNode|Iterable<AstNode>} additional 更多插入内容
|
|
553
704
|
*/
|
|
554
705
|
before(content, ...additional) {
|
|
555
|
-
return this
|
|
706
|
+
return this.#insert('before', content, ...additional);
|
|
556
707
|
}
|
|
557
708
|
|
|
558
709
|
/**
|
|
559
|
-
*
|
|
560
|
-
* @param
|
|
710
|
+
* 在前方插入
|
|
711
|
+
* @param {AstNode|Iterable<AstNode>|CollectionCallback<AstNode|Iterable<AstNode>, string>} content 插入内容
|
|
712
|
+
* @param {...AstNode|Iterable<AstNode>} additional 更多插入内容
|
|
561
713
|
*/
|
|
562
714
|
after(content, ...additional) {
|
|
563
|
-
return this
|
|
715
|
+
return this.#insert('after', content, ...additional);
|
|
564
716
|
}
|
|
565
717
|
|
|
566
718
|
/**
|
|
567
|
-
*
|
|
568
|
-
* @param {
|
|
569
|
-
* @
|
|
719
|
+
* 替换所有子节点
|
|
720
|
+
* @param {AstNode|Iterable<AstNode>|CollectionCallback<AstNode|Iterable<AstNode>, string>} content 插入内容
|
|
721
|
+
* @param {...AstNode|Iterable<AstNode>} additional 更多插入内容
|
|
570
722
|
*/
|
|
571
723
|
html(content) {
|
|
572
724
|
if (content === undefined) {
|
|
573
725
|
return this.toString();
|
|
574
726
|
}
|
|
575
|
-
return this
|
|
727
|
+
return this.#insert('replaceChildren', content);
|
|
576
728
|
}
|
|
577
729
|
|
|
578
|
-
/**
|
|
730
|
+
/**
|
|
731
|
+
* 替换自身
|
|
732
|
+
* @param {AstNode|Iterable<AstNode>|CollectionCallback<AstNode|Iterable<AstNode>, string>} content 插入内容
|
|
733
|
+
* @param {...AstNode|Iterable<AstNode>} additional 更多插入内容
|
|
734
|
+
*/
|
|
579
735
|
replaceWith(content) {
|
|
580
|
-
return this
|
|
736
|
+
return this.#insert('replaceWith', content);
|
|
581
737
|
}
|
|
582
738
|
|
|
583
|
-
|
|
739
|
+
/**
|
|
740
|
+
* 移除自身
|
|
741
|
+
* @param {string} selector
|
|
742
|
+
*/
|
|
743
|
+
remove(selector) {
|
|
584
744
|
this.removeData();
|
|
585
|
-
for (const token of this
|
|
586
|
-
token.
|
|
587
|
-
|
|
745
|
+
for (const token of this) {
|
|
746
|
+
if (token instanceof Token && token.matches(selector)) {
|
|
747
|
+
token.remove();
|
|
748
|
+
token.removeAllEventListeners();
|
|
749
|
+
}
|
|
588
750
|
}
|
|
589
751
|
return this;
|
|
590
752
|
}
|
|
591
753
|
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
754
|
+
/**
|
|
755
|
+
* 移除自身
|
|
756
|
+
* @param {string} selector
|
|
757
|
+
*/
|
|
758
|
+
detach(selector) {
|
|
759
|
+
for (const token of this) {
|
|
760
|
+
if (token instanceof Token && token.matches(selector)) {
|
|
761
|
+
token.remove();
|
|
762
|
+
}
|
|
595
763
|
}
|
|
596
764
|
return this;
|
|
597
765
|
}
|
|
598
766
|
|
|
767
|
+
/** 清空子节点 */
|
|
599
768
|
empty() {
|
|
600
|
-
for (const token of this) {
|
|
601
|
-
|
|
602
|
-
token.replaceChildren();
|
|
603
|
-
}
|
|
769
|
+
for (const token of this.#tokens) {
|
|
770
|
+
token.replaceChildren();
|
|
604
771
|
}
|
|
605
772
|
return this;
|
|
606
773
|
}
|
|
607
774
|
|
|
608
775
|
/**
|
|
609
|
-
*
|
|
610
|
-
* @param {
|
|
776
|
+
* 深拷贝
|
|
777
|
+
* @param {boolean} withData 是否复制数据
|
|
778
|
+
*/
|
|
779
|
+
clone(withData) {
|
|
780
|
+
return new TokenCollection(this.#tokens.map(ele => {
|
|
781
|
+
const cloned = ele.cloneNode();
|
|
782
|
+
if (withData && cache.has(ele)) {
|
|
783
|
+
cache.set(cloned, structuredClone(cache.get(ele)));
|
|
784
|
+
}
|
|
785
|
+
return cloned;
|
|
786
|
+
}), this);
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
/**
|
|
790
|
+
* 插入到
|
|
791
|
+
* @param {string} method
|
|
792
|
+
* @param {'append'|'prepend'|'before'|'after'|'replaceWith'} elementMethod 对应的AstElement方法
|
|
793
|
+
* @param {Token|Iterable<Token>} target 目标位置
|
|
611
794
|
*/
|
|
612
|
-
|
|
795
|
+
#insertAdjacent(method, elementMethod, target) {
|
|
613
796
|
if (target instanceof Token) {
|
|
614
|
-
target[
|
|
615
|
-
} else if (
|
|
797
|
+
target[elementMethod](...this);
|
|
798
|
+
} else if (target?.[Symbol.iterator]) {
|
|
616
799
|
for (const token of target) {
|
|
617
800
|
if (token instanceof Token) {
|
|
618
|
-
token[
|
|
801
|
+
token[elementMethod](...this);
|
|
619
802
|
}
|
|
620
803
|
}
|
|
621
804
|
} else {
|
|
622
|
-
this.typeError(method, 'Token', '
|
|
805
|
+
this.typeError(method, 'Token', 'Iterable');
|
|
623
806
|
}
|
|
624
807
|
return this;
|
|
625
808
|
}
|
|
626
809
|
|
|
627
|
-
/**
|
|
810
|
+
/**
|
|
811
|
+
* 插入到末尾
|
|
812
|
+
* @param {Token|Iterable<Token>} target 目标位置
|
|
813
|
+
*/
|
|
628
814
|
appendTo(target) {
|
|
629
|
-
return this
|
|
815
|
+
return this.#insertAdjacent('appendTo', 'append', target);
|
|
630
816
|
}
|
|
631
817
|
|
|
632
|
-
/**
|
|
818
|
+
/**
|
|
819
|
+
* 插入到开头
|
|
820
|
+
* @param {Token|Iterable<Token>} target 目标位置
|
|
821
|
+
*/
|
|
633
822
|
prependTo(target) {
|
|
634
|
-
return this
|
|
823
|
+
return this.#insertAdjacent('prependTo', 'prepend', target);
|
|
635
824
|
}
|
|
636
825
|
|
|
637
|
-
/**
|
|
826
|
+
/**
|
|
827
|
+
* 插入到前方
|
|
828
|
+
* @param {Token|Iterable<Token>} target 目标位置
|
|
829
|
+
*/
|
|
638
830
|
insertBefore(target) {
|
|
639
|
-
return this
|
|
831
|
+
return this.#insertAdjacent('insertBefore', 'before', target);
|
|
640
832
|
}
|
|
641
833
|
|
|
642
|
-
/**
|
|
834
|
+
/**
|
|
835
|
+
* 插入到后方
|
|
836
|
+
* @param {Token|Iterable<Token>} target 目标位置
|
|
837
|
+
*/
|
|
643
838
|
insertAfter(target) {
|
|
644
|
-
return this
|
|
839
|
+
return this.#insertAdjacent('insertAfter', 'after', target);
|
|
645
840
|
}
|
|
646
841
|
|
|
647
|
-
/**
|
|
842
|
+
/**
|
|
843
|
+
* 替换全部
|
|
844
|
+
* @param {Token|Iterable<Token>} target 目标位置
|
|
845
|
+
*/
|
|
648
846
|
replaceAll(target) {
|
|
649
|
-
return this
|
|
847
|
+
return this.#insertAdjacent('replaceAll', 'replaceWith', target);
|
|
650
848
|
}
|
|
651
849
|
|
|
652
|
-
/**
|
|
850
|
+
/**
|
|
851
|
+
* 获取几何属性
|
|
852
|
+
* @param {string|string[]} key 属性键
|
|
853
|
+
*/
|
|
854
|
+
css(key) {
|
|
855
|
+
const /** @type {Record<string, number>} */ style = this.#firstToken?.style;
|
|
856
|
+
if (typeof key === 'string') {
|
|
857
|
+
return style?.[key];
|
|
858
|
+
}
|
|
859
|
+
return Array.isArray(key)
|
|
860
|
+
? Object.fromEntries(key.map(k => [k, style?.[k]]))
|
|
861
|
+
: this.typeError('css', 'String', 'Array');
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
/**
|
|
865
|
+
* 查询或修改值
|
|
866
|
+
* @param {string|boolean|(string|boolean)[]|CollectionCallback<string, string|boolean>} value 值
|
|
867
|
+
*/
|
|
653
868
|
val(value) {
|
|
654
869
|
if (value === undefined) {
|
|
655
|
-
const firstToken = this
|
|
870
|
+
const /** @type {{getValue: () => string|booleand}} */ firstToken = this.#firstToken;
|
|
656
871
|
return firstToken?.getValue && firstToken.getValue();
|
|
657
872
|
}
|
|
658
|
-
let /** @type {(i: number, token:
|
|
659
|
-
if (typeof value === 'string') {
|
|
660
|
-
|
|
873
|
+
let /** @type {(i: number, token: {getValue: () => string|boolean}) => string|boolean} */ getValue;
|
|
874
|
+
if (typeof value === 'string' || typeof value === 'boolean') {
|
|
875
|
+
getValue = /** @implements */ () => value;
|
|
661
876
|
} else if (typeof value === 'function') {
|
|
662
|
-
|
|
877
|
+
getValue = /** @implements */ (i, token) => value.call(token, i, token.getValue && token.getValue());
|
|
663
878
|
} else if (Array.isArray(value)) {
|
|
664
|
-
|
|
879
|
+
getValue = /** @implements */ i => value[i];
|
|
665
880
|
} else {
|
|
666
881
|
this.typeError('val', 'String', 'Array', 'Function');
|
|
667
882
|
}
|
|
668
883
|
for (let i = 0; i < this.length; i++) {
|
|
669
|
-
const token = this[i];
|
|
884
|
+
const /** @type {{setValue: (value: string|boolean) => void}} */ token = this.array[i];
|
|
670
885
|
if (token instanceof Token && typeof token.setValue === 'function' && token.setValue.length === 1) {
|
|
671
|
-
token.setValue(
|
|
886
|
+
token.setValue(getValue(i, token));
|
|
672
887
|
}
|
|
673
888
|
}
|
|
674
889
|
return this;
|
|
675
890
|
}
|
|
676
891
|
|
|
677
892
|
/**
|
|
678
|
-
*
|
|
679
|
-
* @param {'
|
|
680
|
-
* @param {
|
|
681
|
-
* @param {
|
|
893
|
+
* 查询或修改属性
|
|
894
|
+
* @param {'getAttr'|'getAttribute'} getter 属性getter
|
|
895
|
+
* @param {'setAttr'|'setAttribute'} setter 属性setter
|
|
896
|
+
* @param {string|Record<string, string|boolean>} name 属性名
|
|
897
|
+
* @param {string|boolean|CollectionCallback<string|boolean, string|boolean>} value 属性值
|
|
682
898
|
*/
|
|
683
|
-
|
|
899
|
+
#attr(getter, setter, name, value) {
|
|
684
900
|
if (typeof name === 'string' && value === undefined) {
|
|
685
|
-
const firstToken = this
|
|
901
|
+
const firstToken = this.#firstToken;
|
|
686
902
|
return firstToken?.[getter] && firstToken[getter](name);
|
|
687
903
|
}
|
|
688
904
|
for (let i = 0; i < this.length; i++) {
|
|
689
|
-
const token = this[i];
|
|
690
|
-
if (token instanceof Token &&
|
|
691
|
-
if (typeof value === '
|
|
692
|
-
token[setter](name, value);
|
|
693
|
-
} else if (typeof value === 'function') {
|
|
905
|
+
const token = this.array[i];
|
|
906
|
+
if (token instanceof Token && token[setter]) {
|
|
907
|
+
if (typeof value === 'function') {
|
|
694
908
|
token[setter](name, value.call(token, i, token[getter] && token[getter](name)));
|
|
695
|
-
} else if (
|
|
909
|
+
} else if (isPlainObject(name)) {
|
|
696
910
|
for (const [k, v] of Object.entries(name)) {
|
|
697
911
|
token[setter](k, v);
|
|
698
912
|
}
|
|
913
|
+
} else {
|
|
914
|
+
token[setter](name, value);
|
|
699
915
|
}
|
|
700
916
|
}
|
|
701
917
|
}
|
|
@@ -703,216 +919,281 @@ class TokenCollection extends Array {
|
|
|
703
919
|
}
|
|
704
920
|
|
|
705
921
|
/**
|
|
706
|
-
*
|
|
707
|
-
* @param {string|
|
|
922
|
+
* 标签属性
|
|
923
|
+
* @param {string|Record<string, string|boolean>} name 属性名
|
|
924
|
+
* @param {string|boolean|CollectionCallback<string|boolean, string|boolean>} value 属性值
|
|
708
925
|
*/
|
|
709
926
|
attr(name, value) {
|
|
710
|
-
return this
|
|
927
|
+
return this.#attr('getAttr', 'setAttr', name, value);
|
|
711
928
|
}
|
|
712
929
|
|
|
713
930
|
/**
|
|
714
|
-
*
|
|
715
|
-
* @param {
|
|
931
|
+
* 节点属性
|
|
932
|
+
* @param {string|Record<string, string|boolean>} name 属性名
|
|
933
|
+
* @param {string|boolean|CollectionCallback<string|boolean, string|boolean>} value 属性值
|
|
716
934
|
*/
|
|
717
935
|
prop(name, value) {
|
|
718
|
-
return this
|
|
936
|
+
return this.#attr('getAttribute', 'setAttribute', name, value);
|
|
719
937
|
}
|
|
720
938
|
|
|
721
939
|
/**
|
|
940
|
+
* 移除属性
|
|
722
941
|
* @param {'removeAttr'|'removeAttribute'} method
|
|
723
|
-
* @param {string} name
|
|
942
|
+
* @param {string} name 属性名
|
|
724
943
|
*/
|
|
725
|
-
|
|
944
|
+
#removeAttr(method, name) {
|
|
726
945
|
for (const token of this) {
|
|
727
|
-
if (token instanceof Token &&
|
|
946
|
+
if (token instanceof Token && token[method]) {
|
|
728
947
|
token[method](name);
|
|
729
948
|
}
|
|
730
949
|
}
|
|
731
950
|
return this;
|
|
732
951
|
}
|
|
733
952
|
|
|
734
|
-
/**
|
|
953
|
+
/**
|
|
954
|
+
* 标签属性
|
|
955
|
+
* @param {string} name 属性名
|
|
956
|
+
*/
|
|
735
957
|
removeAttr(name) {
|
|
736
|
-
return this
|
|
958
|
+
return this.#removeAttr('removeAttr', name);
|
|
737
959
|
}
|
|
738
960
|
|
|
739
|
-
/**
|
|
961
|
+
/**
|
|
962
|
+
* 节点属性
|
|
963
|
+
* @param {string} name 属性名
|
|
964
|
+
*/
|
|
740
965
|
removeProp(name) {
|
|
741
|
-
return this
|
|
966
|
+
return this.#removeAttr('removeAttribute', name);
|
|
742
967
|
}
|
|
743
968
|
|
|
744
969
|
/**
|
|
745
|
-
*
|
|
746
|
-
* @
|
|
970
|
+
* 添加class
|
|
971
|
+
* @this {TokenCollection & {array: AttributeToken[]}}
|
|
972
|
+
* @param {string|string[]|CollectionCallback<string|string[], string>} className 类名
|
|
747
973
|
*/
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
974
|
+
addClass(className) {
|
|
975
|
+
/** @type {CollectionCallback<string|string[], string>} */
|
|
976
|
+
const callback = typeof className === 'function' ? className : () => className;
|
|
977
|
+
for (let i = 0; i < this.length; i++) {
|
|
978
|
+
const token = this.array[i],
|
|
979
|
+
{classList} = token;
|
|
980
|
+
if (classList) {
|
|
981
|
+
const newClasses = callback.call(token, i, token.className);
|
|
982
|
+
for (const newClass of Array.isArray(newClasses) ? newClasses : [newClasses]) {
|
|
983
|
+
classList.add(newClass);
|
|
984
|
+
}
|
|
985
|
+
token.className = [...classList].join(' ');
|
|
986
|
+
}
|
|
751
987
|
}
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
988
|
+
return this;
|
|
989
|
+
}
|
|
990
|
+
|
|
991
|
+
/**
|
|
992
|
+
* 移除class
|
|
993
|
+
* @this {TokenCollection & {array: AttributeToken[]}}
|
|
994
|
+
* @param {undefined|string|string[]|CollectionCallback<undefined|string|string[], string>} className 类名
|
|
995
|
+
*/
|
|
996
|
+
removeClass(className) {
|
|
997
|
+
/** @type {CollectionCallback<undefined|string|string[], string>} */
|
|
998
|
+
const callback = typeof className === 'function' ? className : () => className;
|
|
999
|
+
for (let i = 0; i < this.length; i++) {
|
|
1000
|
+
const token = this.array[i],
|
|
1001
|
+
{classList} = token;
|
|
1002
|
+
if (classList) {
|
|
1003
|
+
const newClasses = callback.call(token, i, token.className);
|
|
1004
|
+
if (newClasses === undefined) {
|
|
1005
|
+
classList.clear();
|
|
1006
|
+
} else {
|
|
1007
|
+
for (const newClass of Array.isArray(newClasses) ? newClasses : [newClasses]) {
|
|
1008
|
+
classList.delete(newClass);
|
|
1009
|
+
}
|
|
1010
|
+
}
|
|
1011
|
+
token.className = [...classList].join(' ');
|
|
1012
|
+
}
|
|
756
1013
|
}
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
1014
|
+
return this;
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
/**
|
|
1018
|
+
* 增减class
|
|
1019
|
+
* @this {TokenCollection & {array: AttributeToken[]}}
|
|
1020
|
+
* @param {string|string[]|CollectionCallback<string|string[], string>} className 类名
|
|
1021
|
+
* @param {boolean} state 是否增删
|
|
1022
|
+
*/
|
|
1023
|
+
toggleClass(className, state) {
|
|
1024
|
+
if (typeof state === 'boolean') {
|
|
1025
|
+
return this[state ? 'addClass' : 'removeClass'](className);
|
|
1026
|
+
}
|
|
1027
|
+
/** @type {CollectionCallback<string|string[], string>} */
|
|
1028
|
+
const callback = typeof className === 'function' ? className : () => className;
|
|
1029
|
+
for (let i = 0; i < this.length; i++) {
|
|
1030
|
+
const token = this.array[i],
|
|
1031
|
+
{classList} = token;
|
|
1032
|
+
if (classList) {
|
|
1033
|
+
const newClasses = callback.call(token, i, token.className);
|
|
1034
|
+
for (const newClass of Array.isArray(newClasses) ? new Set(newClasses) : [newClasses]) {
|
|
1035
|
+
classList[classList.has(newClass) ? 'delete' : 'add'](newClass);
|
|
1036
|
+
}
|
|
1037
|
+
token.className = [...classList].join(' ');
|
|
766
1038
|
}
|
|
767
1039
|
}
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
1040
|
+
return this;
|
|
1041
|
+
}
|
|
1042
|
+
|
|
1043
|
+
/**
|
|
1044
|
+
* 是否带有某class
|
|
1045
|
+
* @this {{array: AttributeToken[]}}
|
|
1046
|
+
* @param {string} className 类名
|
|
1047
|
+
*/
|
|
1048
|
+
hasClass(className) {
|
|
1049
|
+
return this.array.some(token => token.classList?.has(className));
|
|
1050
|
+
}
|
|
1051
|
+
|
|
1052
|
+
/**
|
|
1053
|
+
* 全包围
|
|
1054
|
+
* @param {string[]|CollectionCallback<string[], undefined>} wrapper 包裹
|
|
1055
|
+
* @throws `Error` 不是连续的兄弟节点
|
|
1056
|
+
*/
|
|
1057
|
+
wrapAll(wrapper) {
|
|
1058
|
+
if (typeof wrapper !== 'function' && !Array.isArray(wrapper)) {
|
|
1059
|
+
this.typeError('wrapAll', 'Array', 'Function');
|
|
772
1060
|
}
|
|
773
|
-
const
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
1061
|
+
const {array} = this,
|
|
1062
|
+
[firstNode] = array,
|
|
1063
|
+
/** @type {Token} */ ancestor = firstNode?.parentNode,
|
|
1064
|
+
error = new Error('wrapAll 的主体应为普通Token的连续子节点!');
|
|
1065
|
+
if (ancestor?.constructor !== Token) {
|
|
1066
|
+
throw error;
|
|
778
1067
|
}
|
|
779
|
-
|
|
780
|
-
|
|
1068
|
+
const {childNodes} = ancestor,
|
|
1069
|
+
i = childNodes.indexOf(firstNode),
|
|
1070
|
+
j = childNodes.findIndex(node => node.contains(array.at(-1)));
|
|
1071
|
+
if (j === -1 || childNodes.slice(i, j + 1).some(node => !array.includes(node))) {
|
|
1072
|
+
throw error;
|
|
781
1073
|
}
|
|
782
|
-
|
|
1074
|
+
const [pre, post] = typeof wrapper === 'function' ? wrapper.call(firstNode) : wrapper,
|
|
1075
|
+
config = ancestor.getAttribute('config'),
|
|
1076
|
+
include = ancestor.getAttribute('include'),
|
|
1077
|
+
token = new Token(`${pre}${String(childNodes.slice(i, j + 1))}${post}`, config).parse(undefined, include);
|
|
1078
|
+
this.detach();
|
|
1079
|
+
(childNodes[i - 1]?.after ?? ancestor.prepend)(...token.childNodes);
|
|
783
1080
|
return this;
|
|
784
1081
|
}
|
|
785
1082
|
|
|
786
1083
|
/**
|
|
1084
|
+
* 局部包裹
|
|
787
1085
|
* @param {'html'|'replaceWith'} method
|
|
788
|
-
* @param {string
|
|
1086
|
+
* @param {string} originalMethod 原方法
|
|
1087
|
+
* @param {string[]|CollectionCallback<string[], undefined>} wrapper 包裹
|
|
1088
|
+
* @returns {this}
|
|
789
1089
|
*/
|
|
790
|
-
|
|
1090
|
+
#wrap(method, originalMethod, wrapper) {
|
|
791
1091
|
if (typeof wrapper !== 'function' && !Array.isArray(wrapper)) {
|
|
792
|
-
this.typeError(
|
|
793
|
-
}
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
if (token.childNodes.length !== 1) {
|
|
809
|
-
throw new RangeError(`非法的 wrapper:\n${noWrap(pre)}\n${noWrap(post)}`);
|
|
810
|
-
}
|
|
811
|
-
return token.firstChild;
|
|
812
|
-
},
|
|
813
|
-
);
|
|
1092
|
+
this.typeError(originalMethod, 'Array', 'Function');
|
|
1093
|
+
}
|
|
1094
|
+
|
|
1095
|
+
/**
|
|
1096
|
+
* @implements {CollectionCallback<AstNode|Iterable<AstNode>, string>}
|
|
1097
|
+
* @this {Token}
|
|
1098
|
+
* @param {number} i 序号
|
|
1099
|
+
* @param {string} string 原文本
|
|
1100
|
+
*/
|
|
1101
|
+
const callback = function(i, string) {
|
|
1102
|
+
const [pre, post] = typeof wrapper === 'function' ? wrapper.call(this, i) : wrapper,
|
|
1103
|
+
config = this.getAttribute('config'),
|
|
1104
|
+
include = this.getAttribute('include');
|
|
1105
|
+
return new Token(`${pre}${string}${post}`, config).parse(undefined, include).childNodes;
|
|
1106
|
+
};
|
|
1107
|
+
return this[method](callback);
|
|
814
1108
|
}
|
|
815
1109
|
|
|
816
|
-
/**
|
|
1110
|
+
/**
|
|
1111
|
+
* 包裹内部
|
|
1112
|
+
* @param {string[]|CollectionCallback<string[], undefined>} wrapper 包裹
|
|
1113
|
+
*/
|
|
817
1114
|
wrapInner(wrapper) {
|
|
818
|
-
return this
|
|
1115
|
+
return this.#wrap('html', 'wrapInner', wrapper);
|
|
819
1116
|
}
|
|
820
1117
|
|
|
821
|
-
/**
|
|
1118
|
+
/**
|
|
1119
|
+
* 包裹自身
|
|
1120
|
+
* @param {string[]|CollectionCallback<string[], undefined>} wrapper 包裹
|
|
1121
|
+
*/
|
|
822
1122
|
wrap(wrapper) {
|
|
823
|
-
return this
|
|
1123
|
+
return this.#wrap('replaceWith', 'wrap', wrapper);
|
|
824
1124
|
}
|
|
825
1125
|
|
|
1126
|
+
/** 相对于文档的位置 */
|
|
826
1127
|
offset() {
|
|
827
|
-
const
|
|
828
|
-
|
|
829
|
-
return undefined;
|
|
830
|
-
}
|
|
831
|
-
const {top, left} = firstToken.getBoundingClientRect();
|
|
832
|
-
return {top, left};
|
|
1128
|
+
const offset = this.#firstToken?.getBoundingClientRect();
|
|
1129
|
+
return offset && {top: offset.top, left: offset.left};
|
|
833
1130
|
}
|
|
834
1131
|
|
|
1132
|
+
/** 相对于父容器的位置 */
|
|
835
1133
|
position() {
|
|
836
|
-
const style = this
|
|
1134
|
+
const style = this.#firstToken?.style;
|
|
837
1135
|
return style && {top: style.top, left: style.left};
|
|
838
1136
|
}
|
|
839
1137
|
|
|
1138
|
+
/** 高度 */
|
|
840
1139
|
height() {
|
|
841
|
-
return this
|
|
1140
|
+
return this.#firstToken?.offsetHeight;
|
|
842
1141
|
}
|
|
843
1142
|
|
|
1143
|
+
/** 宽度 */
|
|
844
1144
|
width() {
|
|
845
|
-
return this
|
|
1145
|
+
return this.#firstToken?.offsetWidth;
|
|
1146
|
+
}
|
|
1147
|
+
|
|
1148
|
+
/** 内部高度 */
|
|
1149
|
+
innerHeight() {
|
|
1150
|
+
return this.#firstToken?.clientHeight;
|
|
1151
|
+
}
|
|
1152
|
+
|
|
1153
|
+
/** 内部宽度 */
|
|
1154
|
+
innerWidth() {
|
|
1155
|
+
return this.#firstToken?.clientWidth;
|
|
846
1156
|
}
|
|
847
1157
|
}
|
|
848
1158
|
|
|
849
|
-
/**
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
return new Proxy(new TokenCollection(...tokens), {
|
|
855
|
-
/** @param {PropertyKey} prop */
|
|
856
|
-
get(obj, prop) {
|
|
857
|
-
if (prop === Symbol.iterator || typeof obj[prop] !== 'function'
|
|
858
|
-
|| !prop.startsWith('_') && Object.getOwnPropertyDescriptor(obj.constructor.prototype, prop)
|
|
859
|
-
|| !externalUse(prop, true)
|
|
860
|
-
) {
|
|
861
|
-
return obj[prop];
|
|
862
|
-
}
|
|
863
|
-
return undefined;
|
|
864
|
-
},
|
|
865
|
-
set(obj, prop, val) {
|
|
866
|
-
if (prop === 'prevObject' && (val === undefined || val instanceof TokenCollection)) {
|
|
867
|
-
obj[prop] = val;
|
|
868
|
-
return true;
|
|
869
|
-
}
|
|
870
|
-
return false;
|
|
871
|
-
},
|
|
872
|
-
});
|
|
873
|
-
};
|
|
1159
|
+
/**
|
|
1160
|
+
* 代替TokenCollection构造器
|
|
1161
|
+
* @param {AstNode|Iterable<AstNode>} arr 节点数组
|
|
1162
|
+
*/
|
|
1163
|
+
const $ = arr => new TokenCollection(arr instanceof AstNode ? [arr] : arr);
|
|
874
1164
|
/* eslint-disable func-names */
|
|
875
1165
|
$.hasData = /** @param {Token} element */ function hasData(element) {
|
|
876
|
-
|
|
877
|
-
typeError(this, 'hasData', 'Token');
|
|
878
|
-
}
|
|
879
|
-
return this.dataStore.has(element);
|
|
1166
|
+
return element instanceof Token ? cache.has(element) : typeError(this, 'hasData', 'Token');
|
|
880
1167
|
};
|
|
881
|
-
$.data = /** @type {function(Token, string,
|
|
1168
|
+
$.data = /** @type {function(Token, string, *): *} */ function data(element, key, value) {
|
|
882
1169
|
if (!(element instanceof Token)) {
|
|
883
1170
|
typeError(this, 'data', 'Token');
|
|
884
1171
|
} else if (key === undefined) {
|
|
885
|
-
return
|
|
1172
|
+
return cache.get(element);
|
|
886
1173
|
} else if (typeof key !== 'string') {
|
|
887
1174
|
typeError(this, 'data', 'String');
|
|
888
1175
|
} else if (value === undefined) {
|
|
889
|
-
return
|
|
890
|
-
} else if (!
|
|
891
|
-
|
|
1176
|
+
return cache.get(element)?.[key];
|
|
1177
|
+
} else if (!cache.has(element)) {
|
|
1178
|
+
cache.set(element, {});
|
|
892
1179
|
}
|
|
893
|
-
|
|
1180
|
+
cache.get(element)[key] = value;
|
|
894
1181
|
return value;
|
|
895
1182
|
};
|
|
896
1183
|
$.removeData = /** @type {function(Token, string): void} */ function removeData(element, name) {
|
|
897
1184
|
if (!(element instanceof Token)) {
|
|
898
1185
|
typeError(this, 'removeData', 'Token');
|
|
899
1186
|
} else if (name === undefined) {
|
|
900
|
-
|
|
1187
|
+
cache.delete(element);
|
|
901
1188
|
} else if (typeof name !== 'string') {
|
|
902
1189
|
typeError(this, 'removeData', 'String');
|
|
903
|
-
} else if (
|
|
904
|
-
const data =
|
|
1190
|
+
} else if (cache.has(element)) {
|
|
1191
|
+
const data = cache.get(element);
|
|
905
1192
|
delete data[name];
|
|
906
1193
|
}
|
|
907
1194
|
};
|
|
908
|
-
|
|
909
|
-
Object.defineProperty($, '
|
|
910
|
-
Object.defineProperty($, 'reload', {
|
|
911
|
-
value() {
|
|
912
|
-
delete require.cache[__filename];
|
|
913
|
-
const $$ = require('.');
|
|
914
|
-
return $$;
|
|
915
|
-
},
|
|
916
|
-
});
|
|
1195
|
+
/* eslint-enable func-names */
|
|
1196
|
+
Object.defineProperty($, 'cache', {value: cache, enumerable: false, writable: false, configurable: false});
|
|
917
1197
|
|
|
1198
|
+
Parser.tool.$ = __filename;
|
|
918
1199
|
module.exports = $;
|