@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.amd.js CHANGED
@@ -100,155 +100,168 @@ define((function () { 'use strict';
100
100
  const cache = createCache(LAST_NUMBER_WEAK_MAP);
101
101
  const generateUniqueNumber = createGenerateUniqueNumber(cache, LAST_NUMBER_WEAK_MAP);
102
102
 
103
- const isCallNotification = (message) => {
104
- return message.method !== undefined && message.method === 'call';
103
+ const isMessagePort = (sender) => {
104
+ return typeof sender.start === 'function';
105
105
  };
106
106
 
107
- const isClearResponse = (message) => {
108
- return typeof message.id === 'number' && typeof message.result === 'boolean';
109
- };
107
+ const PORT_MAP = new WeakMap();
110
108
 
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
- }
109
+ const extendBrokerImplementation = (partialBrokerImplementation) => ({
110
+ ...partialBrokerImplementation,
111
+ connect: ({ call }) => {
112
+ return async () => {
113
+ const { port1, port2 } = new MessageChannel();
114
+ const portId = await call('connect', { port: port1 }, [port1]);
115
+ PORT_MAP.set(port2, portId);
116
+ return port2;
117
+ };
118
+ },
119
+ disconnect: ({ call }) => {
120
+ return async (port) => {
121
+ const portId = PORT_MAP.get(port);
122
+ if (portId === undefined) {
123
+ throw new Error('The given port is not connected.');
136
124
  }
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
- }
125
+ await call('disconnect', { portId });
126
+ };
127
+ },
128
+ isSupported: ({ call }) => {
129
+ return () => call('isSupported');
130
+ }
131
+ });
132
+
133
+ const ONGOING_REQUESTS = new WeakMap();
134
+ const createOrGetOngoingRequests = (sender) => {
135
+ if (ONGOING_REQUESTS.has(sender)) {
136
+ // @todo TypeScript needs to be convinced that has() works as expected.
137
+ return ONGOING_REQUESTS.get(sender);
138
+ }
139
+ const ongoingRequests = new Map();
140
+ ONGOING_REQUESTS.set(sender, ongoingRequests);
141
+ return ongoingRequests;
142
+ };
143
+ const createBroker = (brokerImplementation) => {
144
+ const fullBrokerImplementation = extendBrokerImplementation(brokerImplementation);
145
+ return (sender) => {
146
+ const ongoingRequests = createOrGetOngoingRequests(sender);
147
+ sender.addEventListener('message', (({ data: message }) => {
148
+ const { id } = message;
149
+ if (id !== null && ongoingRequests.has(id)) {
150
+ const { reject, resolve } = ongoingRequests.get(id);
151
+ ongoingRequests.delete(id);
152
+ if (message.error === undefined) {
153
+ resolve(message.result);
149
154
  }
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);
155
+ else {
156
+ reject(new Error(message.error.message));
154
157
  }
155
158
  }
159
+ }));
160
+ if (isMessagePort(sender)) {
161
+ sender.start();
156
162
  }
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' }
163
+ const call = (method, params = null, transferables = []) => {
164
+ return new Promise((resolve, reject) => {
165
+ const id = generateUniqueNumber(ongoingRequests);
166
+ ongoingRequests.set(id, { reject, resolve });
167
+ if (params === null) {
168
+ sender.postMessage({ id, method }, transferables);
169
+ }
170
+ else {
171
+ sender.postMessage({ id, method, params }, transferables);
172
+ }
198
173
  });
174
+ };
175
+ const notify = (method, params, transferables = []) => {
176
+ sender.postMessage({ id: null, method, params }, transferables);
177
+ };
178
+ let functions = {};
179
+ for (const [key, handler] of Object.entries(fullBrokerImplementation)) {
180
+ functions = { ...functions, [key]: handler({ call, notify }) };
199
181
  }
182
+ return { ...functions };
200
183
  };
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
- }
184
+ };
185
+
186
+ // Prefilling the Maps with a function indexed by zero is necessary to be compliant with the specification.
187
+ const scheduledIntervalsState = new Map([[0, null]]); // tslint:disable-line no-empty
188
+ const scheduledTimeoutsState = new Map([[0, null]]); // tslint:disable-line no-empty
189
+ const wrap = createBroker({
190
+ clearInterval: ({ call }) => {
191
+ return (timerId) => {
192
+ if (typeof scheduledIntervalsState.get(timerId) === 'symbol') {
193
+ scheduledIntervalsState.set(timerId, null);
194
+ call('clear', { timerId, timerType: 'interval' }).then(() => {
195
+ scheduledIntervalsState.delete(timerId);
216
196
  });
217
197
  }
218
- });
219
- worker.postMessage({
220
- id: null,
221
- method: 'set',
222
- params: {
198
+ };
199
+ },
200
+ clearTimeout: ({ call }) => {
201
+ return (timerId) => {
202
+ if (typeof scheduledTimeoutsState.get(timerId) === 'symbol') {
203
+ scheduledTimeoutsState.set(timerId, null);
204
+ call('clear', { timerId, timerType: 'timeout' }).then(() => {
205
+ scheduledTimeoutsState.delete(timerId);
206
+ });
207
+ }
208
+ };
209
+ },
210
+ setInterval: ({ call }) => {
211
+ return (func, delay = 0, ...args) => {
212
+ const symbol = Symbol();
213
+ const timerId = generateUniqueNumber(scheduledIntervalsState);
214
+ scheduledIntervalsState.set(timerId, symbol);
215
+ const schedule = () => call('set', {
223
216
  delay,
224
217
  now: performance.timeOrigin + performance.now(),
225
218
  timerId,
226
219
  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: {
220
+ }).then(() => {
221
+ const state = scheduledIntervalsState.get(timerId);
222
+ if (state === undefined) {
223
+ throw new Error('The timer is in an undefined state.');
224
+ }
225
+ if (state === symbol) {
226
+ func(...args);
227
+ // Doublecheck if the interval should still be rescheduled because it could have been cleared inside of func().
228
+ if (scheduledIntervalsState.get(timerId) === symbol) {
229
+ schedule();
230
+ }
231
+ }
232
+ });
233
+ schedule();
234
+ return timerId;
235
+ };
236
+ },
237
+ setTimeout: ({ call }) => {
238
+ return (func, delay = 0, ...args) => {
239
+ const symbol = Symbol();
240
+ const timerId = generateUniqueNumber(scheduledTimeoutsState);
241
+ scheduledTimeoutsState.set(timerId, symbol);
242
+ call('set', {
238
243
  delay,
239
244
  now: performance.timeOrigin + performance.now(),
240
245
  timerId,
241
246
  timerType: 'timeout'
242
- }
243
- });
244
- return timerId;
245
- };
246
- return {
247
- clearInterval,
248
- clearTimeout,
249
- setInterval,
250
- setTimeout
251
- };
247
+ }).then(() => {
248
+ const state = scheduledTimeoutsState.get(timerId);
249
+ if (state === undefined) {
250
+ throw new Error('The timer is in an undefined state.');
251
+ }
252
+ if (state === symbol) {
253
+ // A timeout can be savely deleted because it is only called once.
254
+ scheduledTimeoutsState.delete(timerId);
255
+ func(...args);
256
+ }
257
+ });
258
+ return timerId;
259
+ };
260
+ }
261
+ });
262
+ const load = (url) => {
263
+ const worker = new Worker(url);
264
+ return wrap(worker);
252
265
  };
253
266
 
254
267
  const createLoadOrReturnBroker = (loadBroker, worker) => {
@@ -267,7 +280,7 @@ define((function () { 'use strict';
267
280
  };
268
281
 
269
282
  // 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
283
+ 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
271
284
 
272
285
  const loadOrReturnBroker = createLoadOrReturnBroker(load, worker);
273
286
  const clearInterval = (timerId) => loadOrReturnBroker().clearInterval(timerId);
@@ -1294,16 +1307,17 @@ define((function () { 'use strict';
1294
1307
  },
1295
1308
  };
1296
1309
  }
1297
- selector(selector) {
1298
- return this.selectorAll(selector)[0];
1310
+ selector(selector, parent) {
1311
+ return this.selectorAll(selector, parent)[0];
1299
1312
  }
1300
- selectorAll(selector) {
1313
+ selectorAll(selector, parent) {
1301
1314
  const context = this;
1315
+ parent = parent || context.windowApi.document;
1302
1316
  selector = selector.trim();
1303
1317
  if (selector.match(/[^\s]{1}:empty$/gi)) {
1304
1318
  // empty 语法
1305
1319
  selector = selector.replace(/:empty$/gi, "");
1306
- return Array.from(context.windowApi.document.querySelectorAll(selector)).filter(($ele) => {
1320
+ return Array.from(parent.querySelectorAll(selector)).filter(($ele) => {
1307
1321
  return $ele?.innerHTML?.trim() === "";
1308
1322
  });
1309
1323
  }
@@ -1313,7 +1327,7 @@ define((function () { 'use strict';
1313
1327
  let textMatch = selector.match(/:contains\(("|')(.*)("|')\)$/i);
1314
1328
  let text = textMatch[2];
1315
1329
  selector = selector.replace(/:contains\(("|')(.*)("|')\)$/gi, "");
1316
- return Array.from(context.windowApi.document.querySelectorAll(selector)).filter(($ele) => {
1330
+ return Array.from(parent.querySelectorAll(selector)).filter(($ele) => {
1317
1331
  // @ts-ignore
1318
1332
  return ($ele?.textContent || $ele?.innerText)?.includes(text);
1319
1333
  });
@@ -1331,14 +1345,14 @@ define((function () { 'use strict';
1331
1345
  }
1332
1346
  let regexp = new RegExp(pattern, flags);
1333
1347
  selector = selector.replace(/:regexp\(("|')(.*)("|')\)$/gi, "");
1334
- return Array.from(context.windowApi.document.querySelectorAll(selector)).filter(($ele) => {
1348
+ return Array.from(parent.querySelectorAll(selector)).filter(($ele) => {
1335
1349
  // @ts-ignore
1336
1350
  return Boolean(($ele?.textContent || $ele?.innerText)?.match(regexp));
1337
1351
  });
1338
1352
  }
1339
1353
  else {
1340
1354
  // 普通语法
1341
- return Array.from(context.windowApi.document.querySelectorAll(selector));
1355
+ return Array.from(parent.querySelectorAll(selector));
1342
1356
  }
1343
1357
  }
1344
1358
  /**
@@ -1473,7 +1487,7 @@ define((function () { 'use strict';
1473
1487
  super(option);
1474
1488
  }
1475
1489
  /** 版本号 */
1476
- version = "2025.6.6";
1490
+ version = "2025.6.26";
1477
1491
  attr(element, attrName, attrValue) {
1478
1492
  let DOMUtilsContext = this;
1479
1493
  if (typeof element === "string") {
@@ -2438,10 +2452,10 @@ define((function () { 'use strict';
2438
2452
  if (typeof duration !== "number" || duration <= 0) {
2439
2453
  throw new TypeError("duration must be a positive number");
2440
2454
  }
2441
- if (typeof callback !== "function" && callback !== undefined) {
2455
+ if (typeof callback !== "function" && callback !== void 0) {
2442
2456
  throw new TypeError("callback must be a function or null");
2443
2457
  }
2444
- if (typeof styles !== "object" || styles === undefined) {
2458
+ if (typeof styles !== "object" || styles === void 0) {
2445
2459
  throw new TypeError("styles must be an object");
2446
2460
  }
2447
2461
  if (Object.keys(styles).length === 0) {