@lesjoursfr/edith 2.1.3 → 2.1.4
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/build/edith.js +1 -1
- package/dist/core/edit.d.ts +8 -0
- package/dist/core/edit.js +73 -1
- package/dist/core/events.d.ts +0 -43
- package/dist/core/events.js +0 -95
- package/dist/core/index.d.ts +0 -2
- package/dist/core/index.js +0 -2
- package/dist/core/range.js +1 -1
- package/dist/edith.js +2 -1
- package/dist/ui/button.js +2 -1
- package/dist/ui/editor.d.ts +1 -1
- package/dist/ui/editor.js +3 -2
- package/dist/ui/modal.js +1 -1
- package/package.json +12 -9
- package/src/core/edit.ts +94 -2
- package/src/core/events.ts +0 -144
- package/src/core/index.ts +0 -2
- package/src/core/range.ts +1 -1
- package/src/edith.ts +2 -1
- package/src/ui/button.ts +2 -1
- package/src/ui/editor.ts +12 -9
- package/src/ui/modal.ts +1 -1
- package/dist/core/dom.d.ts +0 -224
- package/dist/core/dom.js +0 -480
- package/dist/core/throttle.d.ts +0 -53
- package/dist/core/throttle.js +0 -139
- package/src/core/dom.ts +0 -584
- package/src/core/throttle.ts +0 -172
package/dist/core/dom.js
DELETED
|
@@ -1,480 +0,0 @@
|
|
|
1
|
-
const dataNamespace = "edithData";
|
|
2
|
-
/**
|
|
3
|
-
* Convert a dashed string to camelCase
|
|
4
|
-
*/
|
|
5
|
-
function dashedToCamel(string) {
|
|
6
|
-
return string.replace(/-([a-z])/g, (_match, letter) => letter.toUpperCase());
|
|
7
|
-
}
|
|
8
|
-
/**
|
|
9
|
-
* Check if an node is a tag element
|
|
10
|
-
*/
|
|
11
|
-
function isTagElement(node, tag) {
|
|
12
|
-
return isHTMLElement(node) && node.tagName === tag.toUpperCase();
|
|
13
|
-
}
|
|
14
|
-
/**
|
|
15
|
-
* Check if a node is an HTML Element.
|
|
16
|
-
* @param {Node} node the node to test
|
|
17
|
-
* @returns {boolean} true if the node is an HTMLElement
|
|
18
|
-
*/
|
|
19
|
-
export function isCommentNode(node) {
|
|
20
|
-
return node.nodeType === Node.COMMENT_NODE;
|
|
21
|
-
}
|
|
22
|
-
/**
|
|
23
|
-
* Check if a node is an HTML Element.
|
|
24
|
-
* @param {Node} node the node to test
|
|
25
|
-
* @returns {boolean} true if the node is an HTMLElement
|
|
26
|
-
*/
|
|
27
|
-
export function isTextNode(node) {
|
|
28
|
-
return node.nodeType === Node.TEXT_NODE;
|
|
29
|
-
}
|
|
30
|
-
/**
|
|
31
|
-
* Check if a node is an HTML Element.
|
|
32
|
-
* @param {Node} node the node to test
|
|
33
|
-
* @returns {boolean} true if the node is an HTMLElement
|
|
34
|
-
*/
|
|
35
|
-
export function isHTMLElement(node) {
|
|
36
|
-
return node.nodeType === Node.ELEMENT_NODE;
|
|
37
|
-
}
|
|
38
|
-
/**
|
|
39
|
-
* Create an HTMLElement from the HTML template.
|
|
40
|
-
* @param {string} template the HTML template
|
|
41
|
-
* @returns {HTMLElement} the created HTMLElement
|
|
42
|
-
*/
|
|
43
|
-
export function createFromTemplate(template) {
|
|
44
|
-
const range = document.createRange();
|
|
45
|
-
range.selectNode(document.body);
|
|
46
|
-
return range.createContextualFragment(template).children[0];
|
|
47
|
-
}
|
|
48
|
-
/**
|
|
49
|
-
* Update the given CSS property.
|
|
50
|
-
* If the value is `null` the property will be removed.
|
|
51
|
-
* @param {HTMLElement} node the node to update
|
|
52
|
-
* @param {string|{ [key: string]: string|null }} property multi-word property names are hyphenated (kebab-case) and not camel-cased.
|
|
53
|
-
* @param {string|null} value (default to `null`)
|
|
54
|
-
* @returns {HTMLElement} the element
|
|
55
|
-
*/
|
|
56
|
-
export function updateCSS(node, property, value = null) {
|
|
57
|
-
if (typeof property !== "string") {
|
|
58
|
-
for (const [key, val] of Object.entries(property)) {
|
|
59
|
-
val !== null ? node.style.setProperty(key, val) : node.style.removeProperty(key);
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
else {
|
|
63
|
-
value !== null ? node.style.setProperty(property, value) : node.style.removeProperty(property);
|
|
64
|
-
}
|
|
65
|
-
return node;
|
|
66
|
-
}
|
|
67
|
-
/**
|
|
68
|
-
* Check if the node has the given attribute.
|
|
69
|
-
* @param {HTMLElement} node
|
|
70
|
-
* @param {string} attribute
|
|
71
|
-
* @returns {boolean} true or false
|
|
72
|
-
*/
|
|
73
|
-
export function hasAttribute(node, attribute) {
|
|
74
|
-
return node.hasAttribute(attribute);
|
|
75
|
-
}
|
|
76
|
-
/**
|
|
77
|
-
* Get the given attribute.
|
|
78
|
-
* @param {HTMLElement} node
|
|
79
|
-
* @param {string} attribute
|
|
80
|
-
* @returns {string|null} the value
|
|
81
|
-
*/
|
|
82
|
-
export function getAttribute(node, attribute) {
|
|
83
|
-
return node.getAttribute(attribute);
|
|
84
|
-
}
|
|
85
|
-
/**
|
|
86
|
-
* Set the given attribute.
|
|
87
|
-
* If the value is `null` the attribute will be removed.
|
|
88
|
-
* @param {HTMLElement} node
|
|
89
|
-
* @param {string} attribute
|
|
90
|
-
* @param {string|null} value
|
|
91
|
-
* @returns {HTMLElement} the element
|
|
92
|
-
*/
|
|
93
|
-
export function setAttribute(node, attribute, value) {
|
|
94
|
-
if (value === null) {
|
|
95
|
-
node.removeAttribute(attribute);
|
|
96
|
-
}
|
|
97
|
-
else {
|
|
98
|
-
node.setAttribute(attribute, value);
|
|
99
|
-
}
|
|
100
|
-
return node;
|
|
101
|
-
}
|
|
102
|
-
/**
|
|
103
|
-
* Get the given data.
|
|
104
|
-
* This function does not change the DOM.
|
|
105
|
-
* If there is no key this function return all data
|
|
106
|
-
* @param {HTMLElement} node
|
|
107
|
-
* @param {string|undefined} key
|
|
108
|
-
* @returns {EdithData|string|null} the value
|
|
109
|
-
*/
|
|
110
|
-
export function getData(node, key) {
|
|
111
|
-
if (node[dataNamespace] === undefined) {
|
|
112
|
-
node[dataNamespace] = {};
|
|
113
|
-
for (const [k, v] of Object.entries(node.dataset)) {
|
|
114
|
-
if (v === undefined) {
|
|
115
|
-
continue;
|
|
116
|
-
}
|
|
117
|
-
node[dataNamespace][dashedToCamel(k)] = v;
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
return key === undefined ? node[dataNamespace] : node[dataNamespace][dashedToCamel(key)] ?? null;
|
|
121
|
-
}
|
|
122
|
-
/**
|
|
123
|
-
* Set the given data.
|
|
124
|
-
* If the value is `null` the data will be removed.
|
|
125
|
-
* This function does not change the DOM.
|
|
126
|
-
* @param {HTMLElement} node
|
|
127
|
-
* @param {string} key
|
|
128
|
-
* @param {string|null} value
|
|
129
|
-
* @returns {HTMLElement} the element
|
|
130
|
-
*/
|
|
131
|
-
export function setData(node, key, value) {
|
|
132
|
-
if (node[dataNamespace] === undefined) {
|
|
133
|
-
node[dataNamespace] = {};
|
|
134
|
-
}
|
|
135
|
-
if (value === null) {
|
|
136
|
-
delete node[dataNamespace][dashedToCamel(key)];
|
|
137
|
-
}
|
|
138
|
-
else {
|
|
139
|
-
node[dataNamespace][dashedToCamel(key)] = value;
|
|
140
|
-
}
|
|
141
|
-
return node;
|
|
142
|
-
}
|
|
143
|
-
/**
|
|
144
|
-
* Check if the node has the given tag name, or if its tag name is in the given list.
|
|
145
|
-
* @param {HTMLElement} node the element to check
|
|
146
|
-
* @param {string|Array<string>} tags a tag name or a list of tag name
|
|
147
|
-
* @returns {boolean} true if the node has the given tag name
|
|
148
|
-
*/
|
|
149
|
-
export function hasTagName(node, tags) {
|
|
150
|
-
if (typeof tags === "string") {
|
|
151
|
-
return node.tagName === tags.toUpperCase();
|
|
152
|
-
}
|
|
153
|
-
return tags.some((tag) => node.tagName === tag.toUpperCase());
|
|
154
|
-
}
|
|
155
|
-
/**
|
|
156
|
-
* Check if the node has the given class name.
|
|
157
|
-
* @param {HTMLElement} node the element to check
|
|
158
|
-
* @param {string} className a class name
|
|
159
|
-
* @returns {boolean} true if the node has the given class name
|
|
160
|
-
*/
|
|
161
|
-
export function hasClass(node, className) {
|
|
162
|
-
return node.classList.contains(className);
|
|
163
|
-
}
|
|
164
|
-
/**
|
|
165
|
-
* Add the class to the node's class attribute.
|
|
166
|
-
* @param {HTMLElement} node
|
|
167
|
-
* @param {string|Array<string>} className
|
|
168
|
-
* @returns {HTMLElement} the element
|
|
169
|
-
*/
|
|
170
|
-
export function addClass(node, className) {
|
|
171
|
-
if (typeof className === "string") {
|
|
172
|
-
node.classList.add(className);
|
|
173
|
-
}
|
|
174
|
-
else {
|
|
175
|
-
node.classList.add(...className);
|
|
176
|
-
}
|
|
177
|
-
return node;
|
|
178
|
-
}
|
|
179
|
-
/**
|
|
180
|
-
* Remove the class from the node's class attribute.
|
|
181
|
-
* @param {HTMLElement} node
|
|
182
|
-
* @param {string|Array<string>} className
|
|
183
|
-
* @returns {HTMLElement} the element
|
|
184
|
-
*/
|
|
185
|
-
export function removeClass(node, className) {
|
|
186
|
-
if (typeof className === "string") {
|
|
187
|
-
node.classList.remove(className);
|
|
188
|
-
}
|
|
189
|
-
else {
|
|
190
|
-
node.classList.remove(...className);
|
|
191
|
-
}
|
|
192
|
-
return node;
|
|
193
|
-
}
|
|
194
|
-
/**
|
|
195
|
-
* Test if the node match the given selector.
|
|
196
|
-
* @param {HTMLElement} node
|
|
197
|
-
* @param {string} selector
|
|
198
|
-
* @returns {boolean} true or false
|
|
199
|
-
*/
|
|
200
|
-
export function is(node, selector) {
|
|
201
|
-
return node.matches(selector);
|
|
202
|
-
}
|
|
203
|
-
/**
|
|
204
|
-
* Get the node's offset.
|
|
205
|
-
* @param {HTMLElement} node
|
|
206
|
-
* @returns {{ top: number, left: number }} The node's offset
|
|
207
|
-
*/
|
|
208
|
-
export function offset(node) {
|
|
209
|
-
const rect = node.getBoundingClientRect();
|
|
210
|
-
const win = node.ownerDocument.defaultView;
|
|
211
|
-
return {
|
|
212
|
-
top: rect.top + win.scrollY,
|
|
213
|
-
left: rect.left + win.scrollX,
|
|
214
|
-
};
|
|
215
|
-
}
|
|
216
|
-
/**
|
|
217
|
-
* Create a new node.
|
|
218
|
-
* @param {string} tag the tag name of the node
|
|
219
|
-
* @param {object} options optional parameters
|
|
220
|
-
* @param {string} options.innerHTML the HTML code of the node
|
|
221
|
-
* @param {string} options.textContent the text content of the node
|
|
222
|
-
* @param {object} options.attributes attributes of the node
|
|
223
|
-
* @returns {HTMLElement} the created node
|
|
224
|
-
*/
|
|
225
|
-
export function createNodeWith(tag, { innerHTML, textContent, attributes, } = {}) {
|
|
226
|
-
const node = document.createElement(tag);
|
|
227
|
-
if (attributes) {
|
|
228
|
-
for (const key in attributes) {
|
|
229
|
-
if (Object.hasOwnProperty.call(attributes, key)) {
|
|
230
|
-
node.setAttribute(key, attributes[key]);
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
if (typeof innerHTML === "string") {
|
|
235
|
-
node.innerHTML = innerHTML;
|
|
236
|
-
}
|
|
237
|
-
else if (typeof textContent === "string") {
|
|
238
|
-
node.textContent = textContent;
|
|
239
|
-
}
|
|
240
|
-
return node;
|
|
241
|
-
}
|
|
242
|
-
/**
|
|
243
|
-
* Replace a node.
|
|
244
|
-
* @param {HTMLElement} node the node to replace
|
|
245
|
-
* @param {HTMLElement} replacement the new node
|
|
246
|
-
* @returns {HTMLElement} the new node
|
|
247
|
-
*/
|
|
248
|
-
export function replaceNodeWith(node, replacement) {
|
|
249
|
-
node.replaceWith(replacement);
|
|
250
|
-
return replacement;
|
|
251
|
-
}
|
|
252
|
-
/**
|
|
253
|
-
* Replace the node by its child nodes.
|
|
254
|
-
* @param {HTMLElement} node the node to replace
|
|
255
|
-
* @returns {Array<ChildNode>} its child nodes
|
|
256
|
-
*/
|
|
257
|
-
export function unwrapNode(node) {
|
|
258
|
-
const newNodes = [...node.childNodes];
|
|
259
|
-
node.replaceWith(...newNodes);
|
|
260
|
-
return newNodes;
|
|
261
|
-
}
|
|
262
|
-
/**
|
|
263
|
-
* Replace the node by its text content.
|
|
264
|
-
* @param {HTMLElement} node the node to replace
|
|
265
|
-
* @returns {Text} the created Text node
|
|
266
|
-
*/
|
|
267
|
-
export function textifyNode(node) {
|
|
268
|
-
const newNode = document.createTextNode(node.textContent ?? "");
|
|
269
|
-
node.replaceWith(newNode);
|
|
270
|
-
return newNode;
|
|
271
|
-
}
|
|
272
|
-
/**
|
|
273
|
-
* Know if a tag si a self-closing tag
|
|
274
|
-
* @param {string} tagName
|
|
275
|
-
* @returns {boolean}
|
|
276
|
-
*/
|
|
277
|
-
export function isSelfClosing(tagName) {
|
|
278
|
-
return [
|
|
279
|
-
"AREA",
|
|
280
|
-
"BASE",
|
|
281
|
-
"BR",
|
|
282
|
-
"COL",
|
|
283
|
-
"EMBED",
|
|
284
|
-
"HR",
|
|
285
|
-
"IMG",
|
|
286
|
-
"INPUT",
|
|
287
|
-
"KEYGEN",
|
|
288
|
-
"LINK",
|
|
289
|
-
"META",
|
|
290
|
-
"PARAM",
|
|
291
|
-
"SOURCE",
|
|
292
|
-
"TRACK",
|
|
293
|
-
"WBR",
|
|
294
|
-
].includes(tagName);
|
|
295
|
-
}
|
|
296
|
-
/**
|
|
297
|
-
* Remove all node's child nodes that pass the test implemented by the provided function.
|
|
298
|
-
* @param {ChildNode} node the node to process
|
|
299
|
-
* @param {Function} callbackFn the predicate
|
|
300
|
-
*/
|
|
301
|
-
export function removeNodes(node, callbackFn) {
|
|
302
|
-
for (const el of [...node.childNodes]) {
|
|
303
|
-
if (callbackFn(el)) {
|
|
304
|
-
el.remove();
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
/**
|
|
309
|
-
* Remove recursively all node's child nodes that pass the test implemented by the provided function.
|
|
310
|
-
* @param {ChildNode} node the node to process
|
|
311
|
-
* @param {Function} callbackFn the predicate
|
|
312
|
-
*/
|
|
313
|
-
export function removeNodesRecursively(node, callbackFn) {
|
|
314
|
-
// Remove the node if it meets the condition
|
|
315
|
-
if (callbackFn(node)) {
|
|
316
|
-
node.remove();
|
|
317
|
-
return;
|
|
318
|
-
}
|
|
319
|
-
// Loop through the node’s children
|
|
320
|
-
for (const el of [...node.childNodes]) {
|
|
321
|
-
// Execute the same function if it’s an element node
|
|
322
|
-
removeNodesRecursively(el, callbackFn);
|
|
323
|
-
}
|
|
324
|
-
}
|
|
325
|
-
/**
|
|
326
|
-
* Remove all node's child nodes that are empty text nodes.
|
|
327
|
-
* @param {ChildNode} node the node to process
|
|
328
|
-
*/
|
|
329
|
-
export function removeEmptyTextNodes(node) {
|
|
330
|
-
removeNodes(node, (el) => isTextNode(el) && (el.textContent === null || el.textContent.trim().length === 0));
|
|
331
|
-
}
|
|
332
|
-
/**
|
|
333
|
-
* Remove all node's child nodes that are comment nodes.
|
|
334
|
-
* @param {ChildNode} node the node to process
|
|
335
|
-
*/
|
|
336
|
-
export function removeCommentNodes(node) {
|
|
337
|
-
removeNodes(node, (el) => isCommentNode(el));
|
|
338
|
-
}
|
|
339
|
-
/**
|
|
340
|
-
* Reset all node's attributes to the given list.
|
|
341
|
-
* @param {HTMLElement} node the node
|
|
342
|
-
* @param {object} targetAttributes the requested node's attributes
|
|
343
|
-
*/
|
|
344
|
-
export function resetAttributesTo(node, targetAttributes) {
|
|
345
|
-
for (const name of node.getAttributeNames()) {
|
|
346
|
-
if (targetAttributes[name] === undefined) {
|
|
347
|
-
node.removeAttribute(name);
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
|
-
for (const name of Object.keys(targetAttributes)) {
|
|
351
|
-
node.setAttribute(name, targetAttributes[name]);
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
/**
|
|
355
|
-
* Replace the node's style attribute by some regular nodes (<b>, <i>, <u> or <s>).
|
|
356
|
-
* @param {HTMLElement} node the node to process
|
|
357
|
-
* @returns {HTMLElement} the new node
|
|
358
|
-
*/
|
|
359
|
-
export function replaceNodeStyleByTag(node) {
|
|
360
|
-
// Get the style
|
|
361
|
-
const styleAttr = node.getAttribute("style") || "";
|
|
362
|
-
// Check if a tag is override by the style attribute
|
|
363
|
-
if ((hasTagName(node, "b") && styleAttr.match(/font-weight\s*:\s*(normal|400);/)) ||
|
|
364
|
-
(hasTagName(node, "i") && styleAttr.match(/font-style\s*:\s*normal;/)) ||
|
|
365
|
-
(hasTagName(node, ["u", "s"]) && styleAttr.match(/text-decoration\s*:\s*none;/))) {
|
|
366
|
-
node = replaceNodeWith(node, createNodeWith("span", { attributes: { style: styleAttr }, innerHTML: node.innerHTML }));
|
|
367
|
-
}
|
|
368
|
-
// Infer the tag from the style
|
|
369
|
-
if (styleAttr.match(/font-weight\s*:\s*(bold|700|800|900);/)) {
|
|
370
|
-
node = replaceNodeWith(node, createNodeWith("b", {
|
|
371
|
-
innerHTML: `<span style="${styleAttr.replace(/font-weight\s*:\s*(bold|700|800|900);/, "")}">${node.innerHTML}</span>`,
|
|
372
|
-
}));
|
|
373
|
-
}
|
|
374
|
-
else if (styleAttr.match(/font-style\s*:\s*italic;/)) {
|
|
375
|
-
node = replaceNodeWith(node, createNodeWith("i", {
|
|
376
|
-
innerHTML: `<span style="${styleAttr.replace(/font-style\s*:\s*italic;/, "")}">${node.innerHTML}</span>`,
|
|
377
|
-
}));
|
|
378
|
-
}
|
|
379
|
-
else if (styleAttr.match(/text-decoration\s*:\s*underline;/)) {
|
|
380
|
-
node = replaceNodeWith(node, createNodeWith("u", {
|
|
381
|
-
innerHTML: `<span style="${styleAttr.replace(/text-decoration\s*:\s*underline;/, "")}">${node.innerHTML}</span>`,
|
|
382
|
-
}));
|
|
383
|
-
}
|
|
384
|
-
else if (styleAttr.match(/text-decoration\s*:\s*line-through;/)) {
|
|
385
|
-
node = replaceNodeWith(node, createNodeWith("s", {
|
|
386
|
-
innerHTML: `<span style="${styleAttr.replace(/text-decoration\s*:\s*line-through;/, "")}">${node.innerHTML}</span>`,
|
|
387
|
-
}));
|
|
388
|
-
}
|
|
389
|
-
// Return the node
|
|
390
|
-
return node;
|
|
391
|
-
}
|
|
392
|
-
/**
|
|
393
|
-
* Remove all leading & trailing node's child nodes that match the given tag.
|
|
394
|
-
* @param {HTMLElement} node the node to process
|
|
395
|
-
* @param {string} tag the tag
|
|
396
|
-
*/
|
|
397
|
-
export function trimTag(node, tag) {
|
|
398
|
-
// Children
|
|
399
|
-
const children = node.childNodes;
|
|
400
|
-
// Remove Leading
|
|
401
|
-
while (children.length > 0 && isTagElement(children[0], tag)) {
|
|
402
|
-
children[0].remove();
|
|
403
|
-
}
|
|
404
|
-
// Remove Trailing
|
|
405
|
-
while (children.length > 0 && isTagElement(children[children.length - 1], tag)) {
|
|
406
|
-
children[children.length - 1].remove();
|
|
407
|
-
}
|
|
408
|
-
}
|
|
409
|
-
/**
|
|
410
|
-
* Clean the DOM content of the node
|
|
411
|
-
* @param {HTMLElement} root the node to process
|
|
412
|
-
* @param {object} style active styles for the root
|
|
413
|
-
*/
|
|
414
|
-
export function cleanDomContent(root, style) {
|
|
415
|
-
// Iterate through children
|
|
416
|
-
for (let el of [...root.children]) {
|
|
417
|
-
// Check if the span is an edith-nbsp
|
|
418
|
-
if (hasTagName(el, "span") && hasClass(el, "edith-nbsp")) {
|
|
419
|
-
// Ensure that we have a clean element
|
|
420
|
-
resetAttributesTo(el, { class: "edith-nbsp", contenteditable: "false" });
|
|
421
|
-
el.innerHTML = "¶";
|
|
422
|
-
continue;
|
|
423
|
-
}
|
|
424
|
-
// Check if there is a style attribute on the current node
|
|
425
|
-
if (el.hasAttribute("style")) {
|
|
426
|
-
// Replace the style attribute by tags
|
|
427
|
-
el = replaceNodeStyleByTag(el);
|
|
428
|
-
}
|
|
429
|
-
// Check if the Tag Match a Parent Tag
|
|
430
|
-
if (style[el.tagName]) {
|
|
431
|
-
el = replaceNodeWith(el, createNodeWith("span", { attributes: { style: el.getAttribute("style") || "" }, innerHTML: el.innerHTML }));
|
|
432
|
-
}
|
|
433
|
-
// Save the Current Style Tag
|
|
434
|
-
const newTags = { ...style };
|
|
435
|
-
if (hasTagName(el, ["b", "i", "q", "u", "s"])) {
|
|
436
|
-
newTags[el.tagName] = true;
|
|
437
|
-
}
|
|
438
|
-
// Clean Children
|
|
439
|
-
cleanDomContent(el, newTags);
|
|
440
|
-
// Keep only href & target attributes for <a> tags
|
|
441
|
-
if (hasTagName(el, "a")) {
|
|
442
|
-
const linkAttributes = {};
|
|
443
|
-
if (el.hasAttribute("href")) {
|
|
444
|
-
linkAttributes.href = el.getAttribute("href");
|
|
445
|
-
}
|
|
446
|
-
if (el.hasAttribute("target")) {
|
|
447
|
-
linkAttributes.target = el.getAttribute("target");
|
|
448
|
-
}
|
|
449
|
-
resetAttributesTo(el, linkAttributes);
|
|
450
|
-
continue;
|
|
451
|
-
}
|
|
452
|
-
// Remove all tag attributes for tags in the allowed list
|
|
453
|
-
if (hasTagName(el, ["b", "i", "q", "u", "s", "br", "sup"])) {
|
|
454
|
-
resetAttributesTo(el, {});
|
|
455
|
-
continue;
|
|
456
|
-
}
|
|
457
|
-
// Remove useless tags
|
|
458
|
-
if (hasTagName(el, ["style", "meta", "link"])) {
|
|
459
|
-
el.remove();
|
|
460
|
-
continue;
|
|
461
|
-
}
|
|
462
|
-
// Check if it's a <p> tag
|
|
463
|
-
if (hasTagName(el, "p")) {
|
|
464
|
-
// Check if the element contains text
|
|
465
|
-
if (el.textContent === null || el.textContent.trim().length === 0) {
|
|
466
|
-
// Remove the node
|
|
467
|
-
el.remove();
|
|
468
|
-
continue;
|
|
469
|
-
}
|
|
470
|
-
// Remove all tag attributes
|
|
471
|
-
resetAttributesTo(el, {});
|
|
472
|
-
// Remove leading & trailing <br>
|
|
473
|
-
trimTag(el, "br");
|
|
474
|
-
// Return
|
|
475
|
-
continue;
|
|
476
|
-
}
|
|
477
|
-
// Unwrap the node
|
|
478
|
-
unwrapNode(el);
|
|
479
|
-
}
|
|
480
|
-
}
|
package/dist/core/throttle.d.ts
DELETED
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Based on lodash version of throttle : https://github.com/lodash/lodash/blob/master/throttle.js
|
|
3
|
-
*/
|
|
4
|
-
/**
|
|
5
|
-
* Creates a debounced function that delays invoking `func` until after `wait`
|
|
6
|
-
* milliseconds have elapsed since the last time the debounced function was
|
|
7
|
-
* invoked, or until the next browser frame is drawn. Provide `options` to indicate
|
|
8
|
-
* whether `func` should be invoked on the leading and/or trailing edge of the
|
|
9
|
-
* `wait` timeout. The `func` is invoked with the last arguments provided to the
|
|
10
|
-
* debounced function. Subsequent calls to the debounced function return the
|
|
11
|
-
* result of the last `func` invocation.
|
|
12
|
-
* **Note:** If `leading` and `trailing` options are `true`, `func` is
|
|
13
|
-
* invoked on the trailing edge of the timeout only if the debounced function
|
|
14
|
-
* is invoked more than once during the `wait` timeout.
|
|
15
|
-
* If `wait` is `0` and `leading` is `false`, `func` invocation is deferred
|
|
16
|
-
* until the next tick, similar to `setTimeout` with a timeout of `0`.
|
|
17
|
-
* @param {Function} func The function to debounce
|
|
18
|
-
* @param {number} wait The number of milliseconds to delay
|
|
19
|
-
* @param {Object} [options={}] The options object
|
|
20
|
-
* @param {boolean} [options.leading=false] Specify invoking on the leading edge of the timeout
|
|
21
|
-
* @param {boolean} [options.trailing=true] Specify invoking on the trailing edge of the timeout
|
|
22
|
-
* @param {number} [options.maxWait] The maximum time `func` is allowed to be delayed before it's invoked
|
|
23
|
-
* @returns {Function} Returns the new debounced function
|
|
24
|
-
*/
|
|
25
|
-
declare function debounce<F extends (...args: any) => any>(func: F, wait: number, options?: {
|
|
26
|
-
leading?: boolean;
|
|
27
|
-
trailing?: boolean;
|
|
28
|
-
maxWait?: number;
|
|
29
|
-
}): (...args: Parameters<F>) => ReturnType<F>;
|
|
30
|
-
/**
|
|
31
|
-
* Creates a throttled function that only invokes `func` at most once per
|
|
32
|
-
* every `wait` milliseconds (or once per browser frame). Provide `options` to indicate
|
|
33
|
-
* whether `func` should be invoked on the leading and/or trailing edge of the
|
|
34
|
-
* `wait` timeout. The `func` is invoked with the last arguments provided to the
|
|
35
|
-
* throttled function. Subsequent calls to the throttled function return the
|
|
36
|
-
* result of the last `func` invocation.
|
|
37
|
-
* **Note:** If `leading` and `trailing` options are `true`, `func` is
|
|
38
|
-
* invoked on the trailing edge of the timeout only if the throttled function
|
|
39
|
-
* is invoked more than once during the `wait` timeout.
|
|
40
|
-
* If `wait` is `0` and `leading` is `false`, `func` invocation is deferred
|
|
41
|
-
* until the next tick, similar to `setTimeout` with a timeout of `0`.
|
|
42
|
-
* @param {Function} func The function to throttle
|
|
43
|
-
* @param {number} wait The number of milliseconds to throttle invocations to
|
|
44
|
-
* @param {Object} [options={}] The options object
|
|
45
|
-
* @param {boolean} [options.leading=true] Specify invoking on the leading edge of the timeout
|
|
46
|
-
* @param {boolean} [options.trailing=true] Specify invoking on the trailing edge of the timeout
|
|
47
|
-
* @returns {Function} Returns the new throttled function
|
|
48
|
-
*/
|
|
49
|
-
declare function throttle<F extends (...args: any) => any>(func: F, wait: number, options?: {
|
|
50
|
-
leading?: boolean;
|
|
51
|
-
trailing?: boolean;
|
|
52
|
-
}): (...args: Parameters<F>) => ReturnType<F>;
|
|
53
|
-
export { debounce, throttle };
|
package/dist/core/throttle.js
DELETED
|
@@ -1,139 +0,0 @@
|
|
|
1
|
-
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
-
/**
|
|
3
|
-
* Based on lodash version of throttle : https://github.com/lodash/lodash/blob/master/throttle.js
|
|
4
|
-
*/
|
|
5
|
-
/**
|
|
6
|
-
* Creates a debounced function that delays invoking `func` until after `wait`
|
|
7
|
-
* milliseconds have elapsed since the last time the debounced function was
|
|
8
|
-
* invoked, or until the next browser frame is drawn. Provide `options` to indicate
|
|
9
|
-
* whether `func` should be invoked on the leading and/or trailing edge of the
|
|
10
|
-
* `wait` timeout. The `func` is invoked with the last arguments provided to the
|
|
11
|
-
* debounced function. Subsequent calls to the debounced function return the
|
|
12
|
-
* result of the last `func` invocation.
|
|
13
|
-
* **Note:** If `leading` and `trailing` options are `true`, `func` is
|
|
14
|
-
* invoked on the trailing edge of the timeout only if the debounced function
|
|
15
|
-
* is invoked more than once during the `wait` timeout.
|
|
16
|
-
* If `wait` is `0` and `leading` is `false`, `func` invocation is deferred
|
|
17
|
-
* until the next tick, similar to `setTimeout` with a timeout of `0`.
|
|
18
|
-
* @param {Function} func The function to debounce
|
|
19
|
-
* @param {number} wait The number of milliseconds to delay
|
|
20
|
-
* @param {Object} [options={}] The options object
|
|
21
|
-
* @param {boolean} [options.leading=false] Specify invoking on the leading edge of the timeout
|
|
22
|
-
* @param {boolean} [options.trailing=true] Specify invoking on the trailing edge of the timeout
|
|
23
|
-
* @param {number} [options.maxWait] The maximum time `func` is allowed to be delayed before it's invoked
|
|
24
|
-
* @returns {Function} Returns the new debounced function
|
|
25
|
-
*/
|
|
26
|
-
function debounce(func, wait, options = {}) {
|
|
27
|
-
let lastArgs, lastThis, result, timerId, lastCallTime;
|
|
28
|
-
let lastInvokeTime = 0;
|
|
29
|
-
const leading = !!options.leading;
|
|
30
|
-
const maxing = "maxWait" in options;
|
|
31
|
-
const maxWait = maxing ? Math.max(options.maxWait || 0, wait) : undefined;
|
|
32
|
-
const trailing = "trailing" in options ? !!options.trailing : true;
|
|
33
|
-
function invokeFunc(time) {
|
|
34
|
-
const args = lastArgs;
|
|
35
|
-
const thisArg = lastThis;
|
|
36
|
-
lastArgs = lastThis = undefined;
|
|
37
|
-
lastInvokeTime = time;
|
|
38
|
-
result = func.apply(thisArg, args);
|
|
39
|
-
return result;
|
|
40
|
-
}
|
|
41
|
-
function startTimer(pendingFunc, wait) {
|
|
42
|
-
return setTimeout(pendingFunc, wait);
|
|
43
|
-
}
|
|
44
|
-
function leadingEdge(time) {
|
|
45
|
-
// Reset any `maxWait` timer.
|
|
46
|
-
lastInvokeTime = time;
|
|
47
|
-
// Start the timer for the trailing edge.
|
|
48
|
-
timerId = startTimer(timerExpired, wait);
|
|
49
|
-
// Invoke the leading edge.
|
|
50
|
-
return leading ? invokeFunc(time) : result;
|
|
51
|
-
}
|
|
52
|
-
function remainingWait(time) {
|
|
53
|
-
const timeSinceLastCall = time - lastCallTime;
|
|
54
|
-
const timeSinceLastInvoke = time - lastInvokeTime;
|
|
55
|
-
const timeWaiting = wait - timeSinceLastCall;
|
|
56
|
-
return maxing ? Math.min(timeWaiting, maxWait - timeSinceLastInvoke) : timeWaiting;
|
|
57
|
-
}
|
|
58
|
-
function shouldInvoke(time) {
|
|
59
|
-
const timeSinceLastCall = time - lastCallTime;
|
|
60
|
-
const timeSinceLastInvoke = time - lastInvokeTime;
|
|
61
|
-
// Either this is the first call, activity has stopped and we're at the
|
|
62
|
-
// trailing edge, the system time has gone backwards and we're treating
|
|
63
|
-
// it as the trailing edge, or we've hit the `maxWait` limit.
|
|
64
|
-
return (lastCallTime === undefined ||
|
|
65
|
-
timeSinceLastCall >= wait ||
|
|
66
|
-
timeSinceLastCall < 0 ||
|
|
67
|
-
(maxing && timeSinceLastInvoke >= maxWait));
|
|
68
|
-
}
|
|
69
|
-
function timerExpired() {
|
|
70
|
-
const time = Date.now();
|
|
71
|
-
if (shouldInvoke(time)) {
|
|
72
|
-
return trailingEdge(time);
|
|
73
|
-
}
|
|
74
|
-
// Restart the timer.
|
|
75
|
-
timerId = startTimer(timerExpired, remainingWait(time));
|
|
76
|
-
}
|
|
77
|
-
function trailingEdge(time) {
|
|
78
|
-
timerId = undefined;
|
|
79
|
-
// Only invoke if we have `lastArgs` which means `func` has been
|
|
80
|
-
// debounced at least once.
|
|
81
|
-
if (trailing && lastArgs) {
|
|
82
|
-
return invokeFunc(time);
|
|
83
|
-
}
|
|
84
|
-
lastArgs = lastThis = undefined;
|
|
85
|
-
return result;
|
|
86
|
-
}
|
|
87
|
-
function debounced(...args) {
|
|
88
|
-
const time = Date.now();
|
|
89
|
-
const isInvoking = shouldInvoke(time);
|
|
90
|
-
lastArgs = args;
|
|
91
|
-
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
92
|
-
lastThis = this;
|
|
93
|
-
lastCallTime = time;
|
|
94
|
-
if (isInvoking) {
|
|
95
|
-
if (timerId === undefined) {
|
|
96
|
-
return leadingEdge(lastCallTime);
|
|
97
|
-
}
|
|
98
|
-
if (maxing) {
|
|
99
|
-
// Handle invocations in a tight loop.
|
|
100
|
-
timerId = startTimer(timerExpired, wait);
|
|
101
|
-
return invokeFunc(lastCallTime);
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
if (timerId === undefined) {
|
|
105
|
-
timerId = startTimer(timerExpired, wait);
|
|
106
|
-
}
|
|
107
|
-
return result;
|
|
108
|
-
}
|
|
109
|
-
return debounced;
|
|
110
|
-
}
|
|
111
|
-
/**
|
|
112
|
-
* Creates a throttled function that only invokes `func` at most once per
|
|
113
|
-
* every `wait` milliseconds (or once per browser frame). Provide `options` to indicate
|
|
114
|
-
* whether `func` should be invoked on the leading and/or trailing edge of the
|
|
115
|
-
* `wait` timeout. The `func` is invoked with the last arguments provided to the
|
|
116
|
-
* throttled function. Subsequent calls to the throttled function return the
|
|
117
|
-
* result of the last `func` invocation.
|
|
118
|
-
* **Note:** If `leading` and `trailing` options are `true`, `func` is
|
|
119
|
-
* invoked on the trailing edge of the timeout only if the throttled function
|
|
120
|
-
* is invoked more than once during the `wait` timeout.
|
|
121
|
-
* If `wait` is `0` and `leading` is `false`, `func` invocation is deferred
|
|
122
|
-
* until the next tick, similar to `setTimeout` with a timeout of `0`.
|
|
123
|
-
* @param {Function} func The function to throttle
|
|
124
|
-
* @param {number} wait The number of milliseconds to throttle invocations to
|
|
125
|
-
* @param {Object} [options={}] The options object
|
|
126
|
-
* @param {boolean} [options.leading=true] Specify invoking on the leading edge of the timeout
|
|
127
|
-
* @param {boolean} [options.trailing=true] Specify invoking on the trailing edge of the timeout
|
|
128
|
-
* @returns {Function} Returns the new throttled function
|
|
129
|
-
*/
|
|
130
|
-
function throttle(func, wait, options = {}) {
|
|
131
|
-
const leading = "leading" in options ? !!options.leading : true;
|
|
132
|
-
const trailing = "trailing" in options ? !!options.trailing : true;
|
|
133
|
-
return debounce(func, wait, {
|
|
134
|
-
leading,
|
|
135
|
-
trailing,
|
|
136
|
-
maxWait: wait,
|
|
137
|
-
});
|
|
138
|
-
}
|
|
139
|
-
export { debounce, throttle };
|