@whitesev/domutils 1.5.9 → 1.5.11

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.umd.js CHANGED
@@ -104,155 +104,168 @@
104
104
  const cache = createCache(LAST_NUMBER_WEAK_MAP);
105
105
  const generateUniqueNumber = createGenerateUniqueNumber(cache, LAST_NUMBER_WEAK_MAP);
106
106
 
107
- const isCallNotification = (message) => {
108
- return message.method !== undefined && message.method === 'call';
107
+ const isMessagePort = (sender) => {
108
+ return typeof sender.start === 'function';
109
109
  };
110
110
 
111
- const isClearResponse = (message) => {
112
- return typeof message.id === 'number' && typeof message.result === 'boolean';
113
- };
111
+ const PORT_MAP = new WeakMap();
114
112
 
115
- const load = (url) => {
116
- // Prefilling the Maps with a function indexed by zero is necessary to be compliant with the specification.
117
- const scheduledIntervalFunctions = new Map([[0, () => { }]]); // tslint:disable-line no-empty
118
- const scheduledTimeoutFunctions = new Map([[0, () => { }]]); // tslint:disable-line no-empty
119
- const unrespondedRequests = new Map();
120
- const worker = new Worker(url);
121
- worker.addEventListener('message', ({ data }) => {
122
- if (isCallNotification(data)) {
123
- const { params: { timerId, timerType } } = data;
124
- if (timerType === 'interval') {
125
- const idOrFunc = scheduledIntervalFunctions.get(timerId);
126
- if (typeof idOrFunc === undefined) {
127
- throw new Error('The timer is in an undefined state.');
128
- }
129
- if (typeof idOrFunc === 'number') {
130
- const timerIdAndTimerType = unrespondedRequests.get(idOrFunc);
131
- if (timerIdAndTimerType === undefined ||
132
- timerIdAndTimerType.timerId !== timerId ||
133
- timerIdAndTimerType.timerType !== timerType) {
134
- throw new Error('The timer is in an undefined state.');
135
- }
136
- }
137
- else if (typeof idOrFunc === 'function') {
138
- idOrFunc();
139
- }
113
+ const extendBrokerImplementation = (partialBrokerImplementation) => ({
114
+ ...partialBrokerImplementation,
115
+ connect: ({ call }) => {
116
+ return async () => {
117
+ const { port1, port2 } = new MessageChannel();
118
+ const portId = await call('connect', { port: port1 }, [port1]);
119
+ PORT_MAP.set(port2, portId);
120
+ return port2;
121
+ };
122
+ },
123
+ disconnect: ({ call }) => {
124
+ return async (port) => {
125
+ const portId = PORT_MAP.get(port);
126
+ if (portId === undefined) {
127
+ throw new Error('The given port is not connected.');
140
128
  }
141
- else if (timerType === 'timeout') {
142
- const idOrFunc = scheduledTimeoutFunctions.get(timerId);
143
- if (typeof idOrFunc === undefined) {
144
- throw new Error('The timer is in an undefined state.');
145
- }
146
- if (typeof idOrFunc === 'number') {
147
- const timerIdAndTimerType = unrespondedRequests.get(idOrFunc);
148
- if (timerIdAndTimerType === undefined ||
149
- timerIdAndTimerType.timerId !== timerId ||
150
- timerIdAndTimerType.timerType !== timerType) {
151
- throw new Error('The timer is in an undefined state.');
152
- }
129
+ await call('disconnect', { portId });
130
+ };
131
+ },
132
+ isSupported: ({ call }) => {
133
+ return () => call('isSupported');
134
+ }
135
+ });
136
+
137
+ const ONGOING_REQUESTS = new WeakMap();
138
+ const createOrGetOngoingRequests = (sender) => {
139
+ if (ONGOING_REQUESTS.has(sender)) {
140
+ // @todo TypeScript needs to be convinced that has() works as expected.
141
+ return ONGOING_REQUESTS.get(sender);
142
+ }
143
+ const ongoingRequests = new Map();
144
+ ONGOING_REQUESTS.set(sender, ongoingRequests);
145
+ return ongoingRequests;
146
+ };
147
+ const createBroker = (brokerImplementation) => {
148
+ const fullBrokerImplementation = extendBrokerImplementation(brokerImplementation);
149
+ return (sender) => {
150
+ const ongoingRequests = createOrGetOngoingRequests(sender);
151
+ sender.addEventListener('message', (({ data: message }) => {
152
+ const { id } = message;
153
+ if (id !== null && ongoingRequests.has(id)) {
154
+ const { reject, resolve } = ongoingRequests.get(id);
155
+ ongoingRequests.delete(id);
156
+ if (message.error === undefined) {
157
+ resolve(message.result);
153
158
  }
154
- else if (typeof idOrFunc === 'function') {
155
- idOrFunc();
156
- // A timeout can be savely deleted because it is only called once.
157
- scheduledTimeoutFunctions.delete(timerId);
159
+ else {
160
+ reject(new Error(message.error.message));
158
161
  }
159
162
  }
163
+ }));
164
+ if (isMessagePort(sender)) {
165
+ sender.start();
160
166
  }
161
- else if (isClearResponse(data)) {
162
- const { id } = data;
163
- const timerIdAndTimerType = unrespondedRequests.get(id);
164
- if (timerIdAndTimerType === undefined) {
165
- throw new Error('The timer is in an undefined state.');
166
- }
167
- const { timerId, timerType } = timerIdAndTimerType;
168
- unrespondedRequests.delete(id);
169
- if (timerType === 'interval') {
170
- scheduledIntervalFunctions.delete(timerId);
171
- }
172
- else {
173
- scheduledTimeoutFunctions.delete(timerId);
174
- }
175
- }
176
- else {
177
- const { error: { message } } = data;
178
- throw new Error(message);
179
- }
180
- });
181
- const clearInterval = (timerId) => {
182
- if (typeof scheduledIntervalFunctions.get(timerId) === 'function') {
183
- const id = generateUniqueNumber(unrespondedRequests);
184
- unrespondedRequests.set(id, { timerId, timerType: 'interval' });
185
- scheduledIntervalFunctions.set(timerId, id);
186
- worker.postMessage({
187
- id,
188
- method: 'clear',
189
- params: { timerId, timerType: 'interval' }
190
- });
191
- }
192
- };
193
- const clearTimeout = (timerId) => {
194
- if (typeof scheduledTimeoutFunctions.get(timerId) === 'function') {
195
- const id = generateUniqueNumber(unrespondedRequests);
196
- unrespondedRequests.set(id, { timerId, timerType: 'timeout' });
197
- scheduledTimeoutFunctions.set(timerId, id);
198
- worker.postMessage({
199
- id,
200
- method: 'clear',
201
- params: { timerId, timerType: 'timeout' }
167
+ const call = (method, params = null, transferables = []) => {
168
+ return new Promise((resolve, reject) => {
169
+ const id = generateUniqueNumber(ongoingRequests);
170
+ ongoingRequests.set(id, { reject, resolve });
171
+ if (params === null) {
172
+ sender.postMessage({ id, method }, transferables);
173
+ }
174
+ else {
175
+ sender.postMessage({ id, method, params }, transferables);
176
+ }
202
177
  });
178
+ };
179
+ const notify = (method, params, transferables = []) => {
180
+ sender.postMessage({ id: null, method, params }, transferables);
181
+ };
182
+ let functions = {};
183
+ for (const [key, handler] of Object.entries(fullBrokerImplementation)) {
184
+ functions = { ...functions, [key]: handler({ call, notify }) };
203
185
  }
186
+ return { ...functions };
204
187
  };
205
- const setInterval = (func, delay = 0, ...args) => {
206
- const timerId = generateUniqueNumber(scheduledIntervalFunctions);
207
- scheduledIntervalFunctions.set(timerId, () => {
208
- func(...args);
209
- // Doublecheck if the interval should still be rescheduled because it could have been cleared inside of func().
210
- if (typeof scheduledIntervalFunctions.get(timerId) === 'function') {
211
- worker.postMessage({
212
- id: null,
213
- method: 'set',
214
- params: {
215
- delay,
216
- now: performance.timeOrigin + performance.now(),
217
- timerId,
218
- timerType: 'interval'
219
- }
188
+ };
189
+
190
+ // Prefilling the Maps with a function indexed by zero is necessary to be compliant with the specification.
191
+ const scheduledIntervalsState = new Map([[0, null]]); // tslint:disable-line no-empty
192
+ const scheduledTimeoutsState = new Map([[0, null]]); // tslint:disable-line no-empty
193
+ const wrap = createBroker({
194
+ clearInterval: ({ call }) => {
195
+ return (timerId) => {
196
+ if (typeof scheduledIntervalsState.get(timerId) === 'symbol') {
197
+ scheduledIntervalsState.set(timerId, null);
198
+ call('clear', { timerId, timerType: 'interval' }).then(() => {
199
+ scheduledIntervalsState.delete(timerId);
220
200
  });
221
201
  }
222
- });
223
- worker.postMessage({
224
- id: null,
225
- method: 'set',
226
- params: {
202
+ };
203
+ },
204
+ clearTimeout: ({ call }) => {
205
+ return (timerId) => {
206
+ if (typeof scheduledTimeoutsState.get(timerId) === 'symbol') {
207
+ scheduledTimeoutsState.set(timerId, null);
208
+ call('clear', { timerId, timerType: 'timeout' }).then(() => {
209
+ scheduledTimeoutsState.delete(timerId);
210
+ });
211
+ }
212
+ };
213
+ },
214
+ setInterval: ({ call }) => {
215
+ return (func, delay = 0, ...args) => {
216
+ const symbol = Symbol();
217
+ const timerId = generateUniqueNumber(scheduledIntervalsState);
218
+ scheduledIntervalsState.set(timerId, symbol);
219
+ const schedule = () => call('set', {
227
220
  delay,
228
221
  now: performance.timeOrigin + performance.now(),
229
222
  timerId,
230
223
  timerType: 'interval'
231
- }
232
- });
233
- return timerId;
234
- };
235
- const setTimeout = (func, delay = 0, ...args) => {
236
- const timerId = generateUniqueNumber(scheduledTimeoutFunctions);
237
- scheduledTimeoutFunctions.set(timerId, () => func(...args));
238
- worker.postMessage({
239
- id: null,
240
- method: 'set',
241
- params: {
224
+ }).then(() => {
225
+ const state = scheduledIntervalsState.get(timerId);
226
+ if (state === undefined) {
227
+ throw new Error('The timer is in an undefined state.');
228
+ }
229
+ if (state === symbol) {
230
+ func(...args);
231
+ // Doublecheck if the interval should still be rescheduled because it could have been cleared inside of func().
232
+ if (scheduledIntervalsState.get(timerId) === symbol) {
233
+ schedule();
234
+ }
235
+ }
236
+ });
237
+ schedule();
238
+ return timerId;
239
+ };
240
+ },
241
+ setTimeout: ({ call }) => {
242
+ return (func, delay = 0, ...args) => {
243
+ const symbol = Symbol();
244
+ const timerId = generateUniqueNumber(scheduledTimeoutsState);
245
+ scheduledTimeoutsState.set(timerId, symbol);
246
+ call('set', {
242
247
  delay,
243
248
  now: performance.timeOrigin + performance.now(),
244
249
  timerId,
245
250
  timerType: 'timeout'
246
- }
247
- });
248
- return timerId;
249
- };
250
- return {
251
- clearInterval,
252
- clearTimeout,
253
- setInterval,
254
- setTimeout
255
- };
251
+ }).then(() => {
252
+ const state = scheduledTimeoutsState.get(timerId);
253
+ if (state === undefined) {
254
+ throw new Error('The timer is in an undefined state.');
255
+ }
256
+ if (state === symbol) {
257
+ // A timeout can be savely deleted because it is only called once.
258
+ scheduledTimeoutsState.delete(timerId);
259
+ func(...args);
260
+ }
261
+ });
262
+ return timerId;
263
+ };
264
+ }
265
+ });
266
+ const load = (url) => {
267
+ const worker = new Worker(url);
268
+ return wrap(worker);
256
269
  };
257
270
 
258
271
  const createLoadOrReturnBroker = (loadBroker, worker) => {
@@ -271,7 +284,7 @@
271
284
  };
272
285
 
273
286
  // This is the minified and stringified code of the worker-timers-worker package.
274
- 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
287
+ const worker = `(()=>{var e={455:function(e,t){!function(e){"use strict";var t=function(e){return function(t){var r=e(t);return t.add(r),r}},r=function(e){return function(t,r){return e.set(t,r),r}},n=void 0===Number.MAX_SAFE_INTEGER?9007199254740991:Number.MAX_SAFE_INTEGER,o=536870912,s=2*o,a=function(e,t){return function(r){var a=t.get(r),i=void 0===a?r.size:a<s?a+1:0;if(!r.has(i))return e(r,i);if(r.size<o){for(;r.has(i);)i=Math.floor(Math.random()*s);return e(r,i)}if(r.size>n)throw new Error("Congratulations, you created a collection of unique numbers which uses all available integers!");for(;r.has(i);)i=Math.floor(Math.random()*n);return e(r,i)}},i=new WeakMap,u=r(i),c=a(u,i),d=t(c);e.addUniqueNumber=d,e.generateUniqueNumber=c}(t)}},t={};function r(n){var o=t[n];if(void 0!==o)return o.exports;var s=t[n]={exports:{}};return e[n].call(s.exports,s,s.exports,r),s.exports}(()=>{"use strict";const e=-32603,t=-32602,n=-32601,o=(e,t)=>Object.assign(new Error(e),{status:t}),s=t=>o('The handler of the method called "'.concat(t,'" returned an unexpected result.'),e),a=(t,r)=>async({data:{id:a,method:i,params:u}})=>{const c=r[i];try{if(void 0===c)throw(e=>o('The requested method called "'.concat(e,'" is not supported.'),n))(i);const r=void 0===u?c():c(u);if(void 0===r)throw(t=>o('The handler of the method called "'.concat(t,'" returned no required result.'),e))(i);const d=r instanceof Promise?await r:r;if(null===a){if(void 0!==d.result)throw s(i)}else{if(void 0===d.result)throw s(i);const{result:e,transferables:r=[]}=d;t.postMessage({id:a,result:e},r)}}catch(e){const{message:r,status:n=-32603}=e;t.postMessage({error:{code:n,message:r},id:a})}};var i=r(455);const u=new Map,c=(e,r,n)=>({...r,connect:({port:t})=>{t.start();const n=e(t,r),o=(0,i.generateUniqueNumber)(u);return u.set(o,(()=>{n(),t.close(),u.delete(o)})),{result:o}},disconnect:({portId:e})=>{const r=u.get(e);if(void 0===r)throw(e=>o('The specified parameter called "portId" with the given value "'.concat(e,'" does not identify a port connected to this worker.'),t))(e);return r(),{result:null}},isSupported:async()=>{if(await new Promise((e=>{const t=new ArrayBuffer(0),{port1:r,port2:n}=new MessageChannel;r.onmessage=({data:t})=>e(null!==t),n.postMessage(t,[t])}))){const e=n();return{result:e instanceof Promise?await e:e}}return{result:!1}}}),d=(e,t,r=()=>!0)=>{const n=c(d,t,r),o=a(e,n);return e.addEventListener("message",o),()=>e.removeEventListener("message",o)},l=e=>t=>{const r=e.get(t);if(void 0===r)return Promise.resolve(!1);const[n,o]=r;return clearTimeout(n),e.delete(t),o(!1),Promise.resolve(!0)},f=(e,t,r)=>(n,o,s)=>{const{expected:a,remainingDelay:i}=e(n,o);return new Promise((e=>{t.set(s,[setTimeout(r,i,a,t,e,s),e])}))},m=(e,t)=>{const r=performance.now(),n=e+t-r-performance.timeOrigin;return{expected:r+n,remainingDelay:n}},p=(e,t,r,n)=>{const o=e-performance.now();o>0?t.set(n,[setTimeout(p,o,e,t,r,n),r]):(t.delete(n),r(!0))},h=new Map,v=l(h),w=new Map,g=l(w),M=f(m,h,p),y=f(m,w,p);d(self,{clear:async({timerId:e,timerType:t})=>({result:await("interval"===t?v(e):g(e))}),set:async({delay:e,now:t,timerId:r,timerType:n})=>({result:await("interval"===n?M:y)(e,t,r)})})})()})();`; // tslint:disable-line:max-line-length
275
288
 
276
289
  const loadOrReturnBroker = createLoadOrReturnBroker(load, worker);
277
290
  const clearInterval = (timerId) => loadOrReturnBroker().clearInterval(timerId);
@@ -1298,16 +1311,17 @@
1298
1311
  },
1299
1312
  };
1300
1313
  }
1301
- selector(selector) {
1302
- return this.selectorAll(selector)[0];
1314
+ selector(selector, parent) {
1315
+ return this.selectorAll(selector, parent)[0];
1303
1316
  }
1304
- selectorAll(selector) {
1317
+ selectorAll(selector, parent) {
1305
1318
  const context = this;
1319
+ parent = parent || context.windowApi.document;
1306
1320
  selector = selector.trim();
1307
1321
  if (selector.match(/[^\s]{1}:empty$/gi)) {
1308
1322
  // empty 语法
1309
1323
  selector = selector.replace(/:empty$/gi, "");
1310
- return Array.from(context.windowApi.document.querySelectorAll(selector)).filter(($ele) => {
1324
+ return Array.from(parent.querySelectorAll(selector)).filter(($ele) => {
1311
1325
  return $ele?.innerHTML?.trim() === "";
1312
1326
  });
1313
1327
  }
@@ -1317,7 +1331,7 @@
1317
1331
  let textMatch = selector.match(/:contains\(("|')(.*)("|')\)$/i);
1318
1332
  let text = textMatch[2];
1319
1333
  selector = selector.replace(/:contains\(("|')(.*)("|')\)$/gi, "");
1320
- return Array.from(context.windowApi.document.querySelectorAll(selector)).filter(($ele) => {
1334
+ return Array.from(parent.querySelectorAll(selector)).filter(($ele) => {
1321
1335
  // @ts-ignore
1322
1336
  return ($ele?.textContent || $ele?.innerText)?.includes(text);
1323
1337
  });
@@ -1335,14 +1349,14 @@
1335
1349
  }
1336
1350
  let regexp = new RegExp(pattern, flags);
1337
1351
  selector = selector.replace(/:regexp\(("|')(.*)("|')\)$/gi, "");
1338
- return Array.from(context.windowApi.document.querySelectorAll(selector)).filter(($ele) => {
1352
+ return Array.from(parent.querySelectorAll(selector)).filter(($ele) => {
1339
1353
  // @ts-ignore
1340
1354
  return Boolean(($ele?.textContent || $ele?.innerText)?.match(regexp));
1341
1355
  });
1342
1356
  }
1343
1357
  else {
1344
1358
  // 普通语法
1345
- return Array.from(context.windowApi.document.querySelectorAll(selector));
1359
+ return Array.from(parent.querySelectorAll(selector));
1346
1360
  }
1347
1361
  }
1348
1362
  /**
@@ -1477,7 +1491,7 @@
1477
1491
  super(option);
1478
1492
  }
1479
1493
  /** 版本号 */
1480
- version = "2025.6.6";
1494
+ version = "2025.6.26";
1481
1495
  attr(element, attrName, attrValue) {
1482
1496
  let DOMUtilsContext = this;
1483
1497
  if (typeof element === "string") {
@@ -2442,10 +2456,10 @@
2442
2456
  if (typeof duration !== "number" || duration <= 0) {
2443
2457
  throw new TypeError("duration must be a positive number");
2444
2458
  }
2445
- if (typeof callback !== "function" && callback !== undefined) {
2459
+ if (typeof callback !== "function" && callback !== void 0) {
2446
2460
  throw new TypeError("callback must be a function or null");
2447
2461
  }
2448
- if (typeof styles !== "object" || styles === undefined) {
2462
+ if (typeof styles !== "object" || styles === void 0) {
2449
2463
  throw new TypeError("styles must be an object");
2450
2464
  }
2451
2465
  if (Object.keys(styles).length === 0) {