@whitesev/domutils 1.5.4 → 1.5.6
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 +288 -4
- package/dist/index.amd.js.map +1 -1
- package/dist/index.cjs.js +288 -4
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.esm.js +288 -4
- package/dist/index.esm.js.map +1 -1
- package/dist/index.iife.js +288 -4
- package/dist/index.iife.js.map +1 -1
- package/dist/index.system.js +288 -4
- package/dist/index.system.js.map +1 -1
- package/dist/index.umd.js +288 -4
- package/dist/index.umd.js.map +1 -1
- package/dist/types/src/DOMUtils.d.ts +5 -3
- package/dist/types/src/DOMUtilsCommonUtils.d.ts +16 -0
- package/package.json +1 -1
- package/src/DOMUtils.ts +14 -8
- package/src/DOMUtilsCommonUtils.ts +52 -0
- package/src/DOMUtilsEvent.ts +1 -1
package/dist/index.cjs.js
CHANGED
|
@@ -43,6 +43,238 @@ class WindowApi {
|
|
|
43
43
|
}
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
+
const createCache = (lastNumberWeakMap) => {
|
|
47
|
+
return (collection, nextNumber) => {
|
|
48
|
+
lastNumberWeakMap.set(collection, nextNumber);
|
|
49
|
+
return nextNumber;
|
|
50
|
+
};
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
/*
|
|
54
|
+
* The value of the constant Number.MAX_SAFE_INTEGER equals (2 ** 53 - 1) but it
|
|
55
|
+
* is fairly new.
|
|
56
|
+
*/
|
|
57
|
+
const MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER === undefined ? 9007199254740991 : Number.MAX_SAFE_INTEGER;
|
|
58
|
+
const TWO_TO_THE_POWER_OF_TWENTY_NINE = 536870912;
|
|
59
|
+
const TWO_TO_THE_POWER_OF_THIRTY = TWO_TO_THE_POWER_OF_TWENTY_NINE * 2;
|
|
60
|
+
const createGenerateUniqueNumber = (cache, lastNumberWeakMap) => {
|
|
61
|
+
return (collection) => {
|
|
62
|
+
const lastNumber = lastNumberWeakMap.get(collection);
|
|
63
|
+
/*
|
|
64
|
+
* Let's try the cheapest algorithm first. It might fail to produce a new
|
|
65
|
+
* number, but it is so cheap that it is okay to take the risk. Just
|
|
66
|
+
* increase the last number by one or reset it to 0 if we reached the upper
|
|
67
|
+
* bound of SMIs (which stands for small integers). When the last number is
|
|
68
|
+
* unknown it is assumed that the collection contains zero based consecutive
|
|
69
|
+
* numbers.
|
|
70
|
+
*/
|
|
71
|
+
let nextNumber = lastNumber === undefined ? collection.size : lastNumber < TWO_TO_THE_POWER_OF_THIRTY ? lastNumber + 1 : 0;
|
|
72
|
+
if (!collection.has(nextNumber)) {
|
|
73
|
+
return cache(collection, nextNumber);
|
|
74
|
+
}
|
|
75
|
+
/*
|
|
76
|
+
* If there are less than half of 2 ** 30 numbers stored in the collection,
|
|
77
|
+
* the chance to generate a new random number in the range from 0 to 2 ** 30
|
|
78
|
+
* is at least 50%. It's benifitial to use only SMIs because they perform
|
|
79
|
+
* much better in any environment based on V8.
|
|
80
|
+
*/
|
|
81
|
+
if (collection.size < TWO_TO_THE_POWER_OF_TWENTY_NINE) {
|
|
82
|
+
while (collection.has(nextNumber)) {
|
|
83
|
+
nextNumber = Math.floor(Math.random() * TWO_TO_THE_POWER_OF_THIRTY);
|
|
84
|
+
}
|
|
85
|
+
return cache(collection, nextNumber);
|
|
86
|
+
}
|
|
87
|
+
// Quickly check if there is a theoretical chance to generate a new number.
|
|
88
|
+
if (collection.size > MAX_SAFE_INTEGER) {
|
|
89
|
+
throw new Error('Congratulations, you created a collection of unique numbers which uses all available integers!');
|
|
90
|
+
}
|
|
91
|
+
// Otherwise use the full scale of safely usable integers.
|
|
92
|
+
while (collection.has(nextNumber)) {
|
|
93
|
+
nextNumber = Math.floor(Math.random() * MAX_SAFE_INTEGER);
|
|
94
|
+
}
|
|
95
|
+
return cache(collection, nextNumber);
|
|
96
|
+
};
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
const LAST_NUMBER_WEAK_MAP = new WeakMap();
|
|
100
|
+
const cache = createCache(LAST_NUMBER_WEAK_MAP);
|
|
101
|
+
const generateUniqueNumber = createGenerateUniqueNumber(cache, LAST_NUMBER_WEAK_MAP);
|
|
102
|
+
|
|
103
|
+
const isCallNotification = (message) => {
|
|
104
|
+
return message.method !== undefined && message.method === 'call';
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
const isClearResponse = (message) => {
|
|
108
|
+
return typeof message.id === 'number' && typeof message.result === 'boolean';
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
const load = (url) => {
|
|
112
|
+
// Prefilling the Maps with a function indexed by zero is necessary to be compliant with the specification.
|
|
113
|
+
const scheduledIntervalFunctions = new Map([[0, () => { }]]); // tslint:disable-line no-empty
|
|
114
|
+
const scheduledTimeoutFunctions = new Map([[0, () => { }]]); // tslint:disable-line no-empty
|
|
115
|
+
const unrespondedRequests = new Map();
|
|
116
|
+
const worker = new Worker(url);
|
|
117
|
+
worker.addEventListener('message', ({ data }) => {
|
|
118
|
+
if (isCallNotification(data)) {
|
|
119
|
+
const { params: { timerId, timerType } } = data;
|
|
120
|
+
if (timerType === 'interval') {
|
|
121
|
+
const idOrFunc = scheduledIntervalFunctions.get(timerId);
|
|
122
|
+
if (typeof idOrFunc === undefined) {
|
|
123
|
+
throw new Error('The timer is in an undefined state.');
|
|
124
|
+
}
|
|
125
|
+
if (typeof idOrFunc === 'number') {
|
|
126
|
+
const timerIdAndTimerType = unrespondedRequests.get(idOrFunc);
|
|
127
|
+
if (timerIdAndTimerType === undefined ||
|
|
128
|
+
timerIdAndTimerType.timerId !== timerId ||
|
|
129
|
+
timerIdAndTimerType.timerType !== timerType) {
|
|
130
|
+
throw new Error('The timer is in an undefined state.');
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
else if (typeof idOrFunc === 'function') {
|
|
134
|
+
idOrFunc();
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
else if (timerType === 'timeout') {
|
|
138
|
+
const idOrFunc = scheduledTimeoutFunctions.get(timerId);
|
|
139
|
+
if (typeof idOrFunc === undefined) {
|
|
140
|
+
throw new Error('The timer is in an undefined state.');
|
|
141
|
+
}
|
|
142
|
+
if (typeof idOrFunc === 'number') {
|
|
143
|
+
const timerIdAndTimerType = unrespondedRequests.get(idOrFunc);
|
|
144
|
+
if (timerIdAndTimerType === undefined ||
|
|
145
|
+
timerIdAndTimerType.timerId !== timerId ||
|
|
146
|
+
timerIdAndTimerType.timerType !== timerType) {
|
|
147
|
+
throw new Error('The timer is in an undefined state.');
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
else if (typeof idOrFunc === 'function') {
|
|
151
|
+
idOrFunc();
|
|
152
|
+
// A timeout can be savely deleted because it is only called once.
|
|
153
|
+
scheduledTimeoutFunctions.delete(timerId);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
else if (isClearResponse(data)) {
|
|
158
|
+
const { id } = data;
|
|
159
|
+
const timerIdAndTimerType = unrespondedRequests.get(id);
|
|
160
|
+
if (timerIdAndTimerType === undefined) {
|
|
161
|
+
throw new Error('The timer is in an undefined state.');
|
|
162
|
+
}
|
|
163
|
+
const { timerId, timerType } = timerIdAndTimerType;
|
|
164
|
+
unrespondedRequests.delete(id);
|
|
165
|
+
if (timerType === 'interval') {
|
|
166
|
+
scheduledIntervalFunctions.delete(timerId);
|
|
167
|
+
}
|
|
168
|
+
else {
|
|
169
|
+
scheduledTimeoutFunctions.delete(timerId);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
else {
|
|
173
|
+
const { error: { message } } = data;
|
|
174
|
+
throw new Error(message);
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
const clearInterval = (timerId) => {
|
|
178
|
+
if (typeof scheduledIntervalFunctions.get(timerId) === 'function') {
|
|
179
|
+
const id = generateUniqueNumber(unrespondedRequests);
|
|
180
|
+
unrespondedRequests.set(id, { timerId, timerType: 'interval' });
|
|
181
|
+
scheduledIntervalFunctions.set(timerId, id);
|
|
182
|
+
worker.postMessage({
|
|
183
|
+
id,
|
|
184
|
+
method: 'clear',
|
|
185
|
+
params: { timerId, timerType: 'interval' }
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
};
|
|
189
|
+
const clearTimeout = (timerId) => {
|
|
190
|
+
if (typeof scheduledTimeoutFunctions.get(timerId) === 'function') {
|
|
191
|
+
const id = generateUniqueNumber(unrespondedRequests);
|
|
192
|
+
unrespondedRequests.set(id, { timerId, timerType: 'timeout' });
|
|
193
|
+
scheduledTimeoutFunctions.set(timerId, id);
|
|
194
|
+
worker.postMessage({
|
|
195
|
+
id,
|
|
196
|
+
method: 'clear',
|
|
197
|
+
params: { timerId, timerType: 'timeout' }
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
};
|
|
201
|
+
const setInterval = (func, delay = 0, ...args) => {
|
|
202
|
+
const timerId = generateUniqueNumber(scheduledIntervalFunctions);
|
|
203
|
+
scheduledIntervalFunctions.set(timerId, () => {
|
|
204
|
+
func(...args);
|
|
205
|
+
// Doublecheck if the interval should still be rescheduled because it could have been cleared inside of func().
|
|
206
|
+
if (typeof scheduledIntervalFunctions.get(timerId) === 'function') {
|
|
207
|
+
worker.postMessage({
|
|
208
|
+
id: null,
|
|
209
|
+
method: 'set',
|
|
210
|
+
params: {
|
|
211
|
+
delay,
|
|
212
|
+
now: performance.timeOrigin + performance.now(),
|
|
213
|
+
timerId,
|
|
214
|
+
timerType: 'interval'
|
|
215
|
+
}
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
});
|
|
219
|
+
worker.postMessage({
|
|
220
|
+
id: null,
|
|
221
|
+
method: 'set',
|
|
222
|
+
params: {
|
|
223
|
+
delay,
|
|
224
|
+
now: performance.timeOrigin + performance.now(),
|
|
225
|
+
timerId,
|
|
226
|
+
timerType: 'interval'
|
|
227
|
+
}
|
|
228
|
+
});
|
|
229
|
+
return timerId;
|
|
230
|
+
};
|
|
231
|
+
const setTimeout = (func, delay = 0, ...args) => {
|
|
232
|
+
const timerId = generateUniqueNumber(scheduledTimeoutFunctions);
|
|
233
|
+
scheduledTimeoutFunctions.set(timerId, () => func(...args));
|
|
234
|
+
worker.postMessage({
|
|
235
|
+
id: null,
|
|
236
|
+
method: 'set',
|
|
237
|
+
params: {
|
|
238
|
+
delay,
|
|
239
|
+
now: performance.timeOrigin + performance.now(),
|
|
240
|
+
timerId,
|
|
241
|
+
timerType: 'timeout'
|
|
242
|
+
}
|
|
243
|
+
});
|
|
244
|
+
return timerId;
|
|
245
|
+
};
|
|
246
|
+
return {
|
|
247
|
+
clearInterval,
|
|
248
|
+
clearTimeout,
|
|
249
|
+
setInterval,
|
|
250
|
+
setTimeout
|
|
251
|
+
};
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
const createLoadOrReturnBroker = (loadBroker, worker) => {
|
|
255
|
+
let broker = null;
|
|
256
|
+
return () => {
|
|
257
|
+
if (broker !== null) {
|
|
258
|
+
return broker;
|
|
259
|
+
}
|
|
260
|
+
const blob = new Blob([worker], { type: 'application/javascript; charset=utf-8' });
|
|
261
|
+
const url = URL.createObjectURL(blob);
|
|
262
|
+
broker = loadBroker(url);
|
|
263
|
+
// Bug #1: Edge up until v18 didn't like the URL to be revoked directly.
|
|
264
|
+
setTimeout(() => URL.revokeObjectURL(url));
|
|
265
|
+
return broker;
|
|
266
|
+
};
|
|
267
|
+
};
|
|
268
|
+
|
|
269
|
+
// This is the minified and stringified code of the worker-timers-worker package.
|
|
270
|
+
const worker = `(()=>{"use strict";const e=new Map,t=new Map,r=t=>{const r=e.get(t);return void 0!==r&&(clearTimeout(r),e.delete(t),!0)},s=e=>{const r=t.get(e);return void 0!==r&&(clearTimeout(r),t.delete(e),!0)},o=(e,t)=>{const r=performance.now(),s=e+t-r-performance.timeOrigin;return{expected:r+s,remainingDelay:s}},i=(e,t,r,s)=>{const o=r-performance.now();o>0?e.set(t,setTimeout(i,o,e,t,r,s)):(e.delete(t),postMessage({id:null,method:"call",params:{timerId:t,timerType:s}}))};addEventListener("message",(({data:n})=>{try{if("clear"===n.method){const{id:e,params:{timerId:t,timerType:o}}=n;if("interval"===o)postMessage({id:e,result:r(t)});else{if("timeout"!==o)throw new Error('The given type "'.concat(o,'" is not supported'));postMessage({id:e,result:s(t)})}}else{if("set"!==n.method)throw new Error('The given method "'.concat(n.method,'" is not supported'));{const{params:{delay:r,now:s,timerId:a,timerType:m}}=n;if("interval"===m)((t,r,s)=>{const{expected:n,remainingDelay:a}=o(t,s);e.set(r,setTimeout(i,a,e,r,n,"interval"))})(r,a,s);else{if("timeout"!==m)throw new Error('The given type "'.concat(m,'" is not supported'));((e,r,s)=>{const{expected:n,remainingDelay:a}=o(e,s);t.set(r,setTimeout(i,a,t,r,n,"timeout"))})(r,a,s)}}}}catch(e){postMessage({error:{message:e.message},id:n.id,result:null})}}))})();`; // tslint:disable-line:max-line-length
|
|
271
|
+
|
|
272
|
+
const loadOrReturnBroker = createLoadOrReturnBroker(load, worker);
|
|
273
|
+
const clearInterval = (timerId) => loadOrReturnBroker().clearInterval(timerId);
|
|
274
|
+
const clearTimeout = (timerId) => loadOrReturnBroker().clearTimeout(timerId);
|
|
275
|
+
const setInterval = (...args) => loadOrReturnBroker().setInterval(...args);
|
|
276
|
+
const setTimeout$1 = (...args) => loadOrReturnBroker().setTimeout(...args);
|
|
277
|
+
|
|
46
278
|
/** 通用工具类 */
|
|
47
279
|
const DOMUtilsCommonUtils = {
|
|
48
280
|
windowApi: new WindowApi({
|
|
@@ -176,6 +408,58 @@ const DOMUtilsCommonUtils = {
|
|
|
176
408
|
delete target[propName];
|
|
177
409
|
}
|
|
178
410
|
},
|
|
411
|
+
/**
|
|
412
|
+
* 自动使用 Worker 执行 setTimeout
|
|
413
|
+
*/
|
|
414
|
+
setTimeout(callback, timeout = 0) {
|
|
415
|
+
try {
|
|
416
|
+
return setTimeout$1(callback, timeout);
|
|
417
|
+
}
|
|
418
|
+
catch (error) {
|
|
419
|
+
return globalThis.setTimeout(callback, timeout);
|
|
420
|
+
}
|
|
421
|
+
},
|
|
422
|
+
/**
|
|
423
|
+
* 配合 .setTimeout 使用
|
|
424
|
+
*/
|
|
425
|
+
clearTimeout(timeId) {
|
|
426
|
+
try {
|
|
427
|
+
if (timeId != null) {
|
|
428
|
+
clearTimeout(timeId);
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
catch (error) {
|
|
432
|
+
}
|
|
433
|
+
finally {
|
|
434
|
+
globalThis.clearTimeout(timeId);
|
|
435
|
+
}
|
|
436
|
+
},
|
|
437
|
+
/**
|
|
438
|
+
* 自动使用 Worker 执行 setInterval
|
|
439
|
+
*/
|
|
440
|
+
setInterval(callback, timeout = 0) {
|
|
441
|
+
try {
|
|
442
|
+
return setInterval(callback, timeout);
|
|
443
|
+
}
|
|
444
|
+
catch (error) {
|
|
445
|
+
return globalThis.setInterval(callback, timeout);
|
|
446
|
+
}
|
|
447
|
+
},
|
|
448
|
+
/**
|
|
449
|
+
* 配合 .setInterval 使用
|
|
450
|
+
*/
|
|
451
|
+
clearInterval(timeId) {
|
|
452
|
+
try {
|
|
453
|
+
if (timeId != null) {
|
|
454
|
+
clearInterval(timeId);
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
catch (error) {
|
|
458
|
+
}
|
|
459
|
+
finally {
|
|
460
|
+
globalThis.clearInterval(timeId);
|
|
461
|
+
}
|
|
462
|
+
},
|
|
179
463
|
};
|
|
180
464
|
|
|
181
465
|
/* 数据 */
|
|
@@ -596,7 +880,7 @@ class DOMUtilsEvent {
|
|
|
596
880
|
}
|
|
597
881
|
if (checkDOMReadyState()) {
|
|
598
882
|
/* 检查document状态 */
|
|
599
|
-
setTimeout(callback);
|
|
883
|
+
DOMUtilsCommonUtils.setTimeout(callback);
|
|
600
884
|
}
|
|
601
885
|
else {
|
|
602
886
|
/* 添加监听 */
|
|
@@ -1062,7 +1346,7 @@ class DOMUtils extends DOMUtilsEvent {
|
|
|
1062
1346
|
super(option);
|
|
1063
1347
|
}
|
|
1064
1348
|
/** 版本号 */
|
|
1065
|
-
version = "2025.5.
|
|
1349
|
+
version = "2025.5.26";
|
|
1066
1350
|
attr(element, attrName, attrValue) {
|
|
1067
1351
|
let DOMUtilsContext = this;
|
|
1068
1352
|
if (typeof element === "string") {
|
|
@@ -2044,7 +2328,7 @@ class DOMUtils extends DOMUtilsEvent {
|
|
|
2044
2328
|
DOMUtilsContext.windowApi.globalThis.getComputedStyle(element)[prop];
|
|
2045
2329
|
to[prop] = styles[prop];
|
|
2046
2330
|
}
|
|
2047
|
-
let timer = setInterval(function () {
|
|
2331
|
+
let timer = DOMUtilsCommonUtils.setInterval(function () {
|
|
2048
2332
|
let timePassed = performance.now() - start;
|
|
2049
2333
|
let progress = timePassed / duration;
|
|
2050
2334
|
if (progress > 1) {
|
|
@@ -2055,7 +2339,7 @@ class DOMUtils extends DOMUtilsEvent {
|
|
|
2055
2339
|
from[prop] + (to[prop] - from[prop]) * progress + "px";
|
|
2056
2340
|
}
|
|
2057
2341
|
if (progress === 1) {
|
|
2058
|
-
clearInterval(timer);
|
|
2342
|
+
DOMUtilsCommonUtils.clearInterval(timer);
|
|
2059
2343
|
if (callback) {
|
|
2060
2344
|
callback();
|
|
2061
2345
|
}
|