objs-core 2.0.0 → 2.0.2

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/EXAMPLES.md CHANGED
@@ -125,14 +125,14 @@ function Counter() {
125
125
 
126
126
  **Objs**
127
127
  ```js
128
- // State lives in the element, not in a reactive variable
128
+ // State lives in the element; events in state no separate .on() needed
129
+ let counterRef;
129
130
  const counter = o.init({
130
131
  name: 'Counter',
131
- render: { tag: 'button', html: '0' },
132
+ render: { tag: 'button', html: '0', events: { click: () => counterRef.inc() } },
132
133
  inc: ({ self }) => { self.html(+self.el.textContent + 1); },
133
134
  }).render().appendInside('#app');
134
-
135
- counter.on('click', () => counter.inc());
135
+ counterRef = counter;
136
136
  ```
137
137
 
138
138
  > In React/Vue/Solid, the framework schedules a re-render when state changes.
@@ -315,33 +315,12 @@ function ProductList() {
315
315
 
316
316
  **Objs**
317
317
  ```js
318
- const listStates = {
319
- name: 'ProductList',
320
- render: { tag: 'ul' },
321
- // Initial load — creates all items, stores by ID
322
- load: ({ self }, products) => {
323
- self.el.innerHTML = '';
324
- self.store.items = {};
325
- products.forEach(p => {
326
- const item = o.initState({ tag: 'li', html: p.name });
327
- item.appendInside(self.el);
328
- self.store.items[p.id] = item;
329
- });
330
- },
331
- // Update one item — O(1), only that text node changes
332
- updateName: ({ self }, { id, name }) => { self.store.items[id]?.html(name); },
333
- // Remove one item — only that node is removed
334
- remove: ({ self }, id) => { self.store.items[id]?.unmount(); delete self.store.items[id]; },
335
- // Add one item — no list re-render
336
- addItem: ({ self }, p) => {
337
- const item = o.initState({ tag: 'li', html: p.name });
338
- item.appendInside(self.el);
339
- self.store.items[p.id] = item;
340
- },
341
- };
342
- const list = o.init(listStates).render().appendInside('#app');
343
- list.load(products);
344
- list.updateName({ id: 42, name: 'New name' }); // one write
318
+ // One init, render(array) — one element per item (native)
319
+ const listStates = { name: 'ProductList', render: { tag: 'li', html: (p) => p.name } };
320
+ const ul = o.init({ render: { tag: 'ul' } }).render().appendInside('#app');
321
+ const list = o.init(listStates).render(products);
322
+ list.appendInside(ul.el);
323
+ // Re-render: list.render(products). Append/remove: list.select(i).el.remove(), then list.render(newProducts), etc.
345
324
  ```
346
325
 
347
326
  ---
@@ -405,18 +384,15 @@ function Form() {
405
384
  ```js
406
385
  // The company field is a full atom — show/hide are state methods on it
407
386
  const companyField = o.init(FieldStates).render({ name: 'company', label: 'Company name' });
408
- companyField.hide(); // display:none on the atom's root element
387
+ companyField.hide();
409
388
 
389
+ // events in state — change bubbles from the input to the label root
410
390
  const bizBox = o.initState({
411
391
  tag: 'label', class: 'field',
412
392
  html: '<input type="checkbox" class="biz-check"> Business account',
393
+ events: { change: (e) => { e.target.checked ? companyField.show() : companyField.hide(); } },
413
394
  });
414
-
415
- bizBox.first('.biz-check').on('change', e => {
416
- e.target.checked ? companyField.show() : companyField.hide();
417
- });
418
- // DOM node is never removed — toggled with display:none/''
419
- // To fully unmount and remount use .unmount() / .appendInside()
395
+ // DOM node is never removed — toggled with display:none/''. To unmount/remount use .unmount() / .appendInside()
420
396
  ```
421
397
 
422
398
  ---
@@ -549,19 +525,16 @@ function ProductList() {
549
525
  const listStates = {
550
526
  name: 'ProductList',
551
527
  render: { tag: 'div', html: '<p class="loading">Loading…</p>' },
552
- // Called by the loader when data arrives — success state
553
528
  load: ({ self }, products) => {
554
529
  self.el.innerHTML = '';
555
- products.forEach(p => o.initState({ tag: 'p', html: p.name }).appendInside(self.el));
530
+ o.init({ render: { tag: 'p', html: (p) => p.name } }).render(products).appendInside(self.el);
556
531
  },
557
- // Called by the loader on network error fail state
558
- loadFailed: ({ self }) => { self.first('.loading').html('Failed to load. Retry?'); },
532
+ loadFailed: ({ self }) => { self.el.innerHTML = '<p class="loading">Failed to load. Retry?</p>'; },
559
533
  };
560
534
 
561
535
  const list = o.init(listStates).render().appendInside('#app');
562
536
  const loader = o.newLoader(o.get('/api/products'));
563
537
  list.connect(loader, 'load', 'loadFailed');
564
- // loader fires the request; .connect wires success → load, failure → loadFailed
565
538
  ```
566
539
 
567
540
  ---
@@ -576,14 +549,14 @@ list.connect(loader, 'load', 'loadFailed');
576
549
  | Update a value | `setV(newVal)` → re-render | `v.value = newVal` → patch | `setV(newVal)` → fine patch | `comp.setState(newVal)` → direct write |
577
550
  | Read in template | `{v}` | `{{ v }}` | `{v()}` | Not needed — state methods write directly |
578
551
  | Props | function parameter | `defineProps()` | function parameter | `render(props)` argument |
579
- | Events | `onClick={handler}` | `@click="handler"` | `onClick={handler}` | `.on('click', handler)` |
552
+ | Events | `onClick={handler}` | `@click="handler"` | `onClick={handler}` | `events: { click }` in state or `.on('click', handler)` |
580
553
  | Child ref | `useRef()` | `ref="name"` | `let el` / `ref` | `self.store.child = childInstance` |
581
554
  | Lifecycle: mount | `useEffect(fn, [])` | `onMounted(fn)` | `onMount(fn)` | `init` state method called after render |
582
555
  | Lifecycle: unmount | `useEffect` return fn | `onBeforeUnmount(fn)` | `onCleanup(fn)` | `comp.unmount()` |
583
556
  | Shared state | Context / Zustand | Pinia | Signals / store | Plain observer or `o.connectRedux` |
584
557
  | Fetch on mount | `useEffect` + `useState` | `onMounted` + `ref` | `createResource` | `o.newLoader` + `.connect()` |
585
558
  | Conditional render | `{flag && <El/>}` | `v-if="flag"` | `<Show when={flag}>` | `comp.show()` / `comp.hide()` |
586
- | List render | `arr.map(x => <El key>)` | `v-for="x in arr"` | `<For each={arr}>` | `arr.forEach` in a state method |
559
+ | List render | `arr.map(x => <El key>)` | `v-for="x in arr"` | `<For each={arr}>` | `render(arr)` — one element per item; or forEach in a state method |
587
560
  | CSS class toggle | `className={flag?'a':'b'}` | `:class="{a: flag}"` | `classList={{a: flag}}` | `comp.toggleClass('a', flag)` |
588
561
 
589
562
  ---
@@ -718,6 +691,7 @@ grid.reconcile(cards);
718
691
  Add a `ref="name"` attribute to any element in an HTML-string render. After `init`, every such element is available on the component as `component.refs.name` — an ObjsInstance wrapper, not a raw DOM node.
719
692
 
720
693
  ```js
694
+ let cardRef;
721
695
  const cardStates = {
722
696
  name: 'ProductCard',
723
697
  render: ({ title, price }) => ({
@@ -726,8 +700,8 @@ const cardStates = {
726
700
  html: `<h3 ref="title">${title}</h3>
727
701
  <p ref="price">$${price}</p>
728
702
  <button ref="addBtn">Add to cart</button>`,
703
+ events: { click: (e) => { if (e.target.closest('button')) cardRef?.setAdded(); } },
729
704
  }),
730
- // Destructure refs for clean, selector-free access
731
705
  setAdded: ({ self }) => {
732
706
  const { addBtn } = self.refs;
733
707
  addBtn.html('✓ Added').attr('disabled', '');
@@ -738,9 +712,8 @@ const cardStates = {
738
712
  };
739
713
 
740
714
  const card = o.init(cardStates).render({ title: 'Widget', price: 9.99 }).appendInside('#app');
741
- // card.refs.addBtn — ObjsInstance wrapping the <button ref="addBtn">
742
- // card.refs.title ObjsInstance wrapping the <h3 ref="title">
743
- card.refs.addBtn.on('click', () => card.setAdded());
715
+ cardRef = card;
716
+ // card.refs.addBtn, card.refs.title refs for selector-free updates
744
717
  ```
745
718
 
746
719
  > In React, `useRef` accesses a single DOM node. Objs `refs` auto-collects all named children at init time — no `useRef` call per element, no `ref={myRef}` on every JSX tag.
@@ -826,9 +799,41 @@ const FieldStates = {
826
799
 
827
800
  ## 3. Nesting & composition
828
801
 
829
- Three patterns for building composite components. Choose based on how the parent and children relate.
802
+ Four patterns for building composite components. Choose based on how the parent and children relate.
803
+
804
+ ### Pattern A — refs (`ref` attribute in innerHTML)
805
+
806
+ Best for: a single component whose render output has named regions you need to update or wire (buttons, labels, blocks). No child components — just one root element with marked descendants.
807
+
808
+ Add `ref="name"` to elements in the `html` string. After init, `self.refs.name` is an ObjsInstance for that element — use it in state methods for selector-free updates and events.
809
+
810
+ ```js
811
+ let cardRef;
812
+ const cardStates = {
813
+ name: 'ProductCard',
814
+ render: ({ title, price }) => ({
815
+ tag: 'article',
816
+ className: 'card',
817
+ html: `<h3 ref="title">${title}</h3>
818
+ <p ref="price">$${price}</p>
819
+ <button ref="addBtn">Add to cart</button>`,
820
+ events: { click: (e) => { if (e.target.closest('button')) cardRef?.setAdded(); } },
821
+ }),
822
+ setAdded: ({ self }) => {
823
+ self.refs.addBtn.html('✓ Added').attr('disabled', '');
824
+ },
825
+ updatePrice: ({ self }, newPrice) => {
826
+ self.refs.price.html('$' + newPrice);
827
+ },
828
+ };
829
+
830
+ const card = o.init(cardStates).render({ title: 'Widget', price: 9.99 }).appendInside('#app');
831
+ cardRef = card;
832
+ ```
833
+
834
+ **When to update:** call `self.refs.name.html(...)`, `.attr()`, `.on()`, etc. No selectors, no child components to mount.
830
835
 
831
- ### Pattern A — Slot pattern
836
+ ### Pattern B — Slot pattern
832
837
 
833
838
  Best for: containers with named regions (cards, dialogs, panels, toolbars).
834
839
 
@@ -885,7 +890,7 @@ title.setLabel('New Product Name'); // only touches card__header's <button>
885
890
  price.setCount(39); // only touches card__body's <span>
886
891
  ```
887
892
 
888
- ### Pattern B — append in render
893
+ ### Pattern C — append in render
889
894
 
890
895
  Best for: molecules assembled from known atoms at creation time. Children are immutable after render.
891
896
 
@@ -927,9 +932,11 @@ const searchBar = createSearchBar().appendInside('.toolbar');
927
932
  document.addEventListener('search', (e) => console.log('query:', e.detail));
928
933
  ```
929
934
 
930
- ### Pattern C — factory function with lazy child creation
935
+ ### Pattern D — factory function with lazy child creation
936
+
937
+ Best for: dynamic lists with **complex per-item components** (e.g. cards with slots), O(1) per-item updates, or when children change at runtime.
931
938
 
932
- Best for: dynamic lists, data-driven components, components where children change at runtime.
939
+ For **simple lists** (one element per item, e.g. `<li>` text), use native `render(array)` and `.appendInside(ul.el)` — see Pattern 5.
933
940
 
934
941
  Children are created inside a state method (not in render). The parent stores all child references and exposes methods to add, update, or remove individual items.
935
942
 
@@ -1221,7 +1228,8 @@ const productCardStates = {
1221
1228
  },
1222
1229
  };
1223
1230
 
1224
- // ── Product list (factory pattern children in self.store) ───────────────
1231
+ // ── Product list (complex items: each row is a card with button; store refs for O(1) updates)
1232
+ // For a simple list (e.g. just names), use render(products) and appendInside(ul.el) — see Pattern 5.
1225
1233
  const productListStates = {
1226
1234
  name: 'ProductList',
1227
1235
  render: { tag: 'div', class: 'card-list' },
@@ -1230,11 +1238,7 @@ const productListStates = {
1230
1238
  products.forEach((product) => {
1231
1239
  const card = o.init(productCardStates).render(product);
1232
1240
  card.appendInside(self.el);
1233
- // Wire button no DOM query needed, card has .first()
1234
- card.first('.card__btn').on('click', () => {
1235
- cartAdd(product);
1236
- card.setAdded(); // only this card's button changes
1237
- });
1241
+ card.first('.card__btn').on('click', () => { cartAdd(product); card.setAdded(); });
1238
1242
  self.store.cards[product.id] = card;
1239
1243
  });
1240
1244
  },
@@ -1251,6 +1255,7 @@ Promo dialog triggered by `?promo=CODE` URL parameter. sessionStorage prevents r
1251
1255
  ```js
1252
1256
  const PROMO_KEY = 'oTest-promo-shown';
1253
1257
 
1258
+ let dialogRef;
1254
1259
  const dialogStates = {
1255
1260
  name: 'PromoDialog',
1256
1261
  render: {
@@ -1261,6 +1266,9 @@ const dialogStates = {
1261
1266
  <p class="dialog__body"></p>
1262
1267
  <a class="dialog__cta" href="#">Get offer</a>
1263
1268
  </div>`,
1269
+ events: {
1270
+ click: (e) => { if (e.target.closest('.dialog__close') || e.target === dialogRef?.el) dialogRef?.close(); },
1271
+ },
1264
1272
  },
1265
1273
  open: ({ self }, { title, body, cta, ctaUrl }) => {
1266
1274
  self.first('.dialog__title').html(title);
@@ -1273,8 +1281,7 @@ const dialogStates = {
1273
1281
  };
1274
1282
 
1275
1283
  const dialog = o.init(dialogStates).render().appendInside('body');
1276
- dialog.first('.dialog__close').on('click', () => dialog.close());
1277
- dialog.on('click', (e) => { if (e.target === dialog.el) dialog.close(); });
1284
+ dialogRef = dialog;
1278
1285
 
1279
1286
  const promoCode = o.getParams('promo');
1280
1287
  if (promoCode && !sessionStorage.getItem(PROMO_KEY)) {
@@ -1299,6 +1306,7 @@ const applyFilters = (filters, productsLoader) => {
1299
1306
  productsLoader.reload(o.get('/api/products?' + params.toString()));
1300
1307
  };
1301
1308
 
1309
+ let drawerRef;
1302
1310
  const drawerStates = {
1303
1311
  name: 'FilterDrawer',
1304
1312
  render: {
@@ -1310,6 +1318,15 @@ const drawerStates = {
1310
1318
  <input class="drawer__max" type="number" placeholder="Max $">
1311
1319
  <button class="drawer__apply">Apply</button>
1312
1320
  <button class="drawer__reset">Reset</button>`,
1321
+ events: {
1322
+ click: (e) => {
1323
+ const d = drawerRef;
1324
+ if (!d) return;
1325
+ if (e.target.closest('.drawer__close')) d.close();
1326
+ else if (e.target.closest('.drawer__apply')) { applyFilters(d.getValues(), productsLoader); d.close(); }
1327
+ else if (e.target.closest('.drawer__reset')) { applyFilters({ category: '', minPrice: '', maxPrice: '' }, productsLoader); d.restore({ category: '', minPrice: '', maxPrice: '' }); }
1328
+ },
1329
+ },
1313
1330
  },
1314
1331
  open: ({ self }) => { self.css({ transform: 'translateX(0)' }); },
1315
1332
  close: ({ self }) => { self.css({ transform: 'translateX(-100%)' }); },
@@ -1326,19 +1343,9 @@ const drawerStates = {
1326
1343
  };
1327
1344
 
1328
1345
  const drawer = o.init(drawerStates).render().appendInside('body');
1346
+ drawerRef = drawer;
1329
1347
  drawer.restore(getFilters());
1330
1348
 
1331
- drawer.first('.drawer__close').on('click', () => drawer.close());
1332
- drawer.first('.drawer__apply').on('click', () => {
1333
- applyFilters(drawer.getValues(), productsLoader);
1334
- drawer.close();
1335
- });
1336
- drawer.first('.drawer__reset').on('click', () => {
1337
- const empty = { category: '', minPrice: '', maxPrice: '' };
1338
- applyFilters(empty, productsLoader);
1339
- drawer.restore(empty);
1340
- });
1341
-
1342
1349
  o.first('#open-filters').on('click', () => drawer.open());
1343
1350
  ```
1344
1351
 
package/README.md CHANGED
@@ -1,11 +1,11 @@
1
1
  # Objs
2
- > Fast and simple library to speed up developing by AI context friendly architecture, auto-tests recording, cache control and other. Develop new features without rewriting anything. Works standalone or alongside React. Examples and full documentation: [Full Documentation](https://en.fous.name/objs)
2
+ > Fast and simple library to speed up developing by AI context friendly architecture, auto-tests recording, cache control and other. Develop new features without rewriting anything. Works standalone or alongside React. Examples and full documentation: [Full Documentation](https://en.fous.name/objs/documentation)
3
3
 
4
4
  **AI-friendly** — one file, `SKILL.md` primer (~6,000 tokens). An LLM generates correct Objs code from a description without JSX, virtual DOM, or React lifecycle knowledge.
5
5
 
6
6
  **React-developer-friendly** — familiar `className`, `ref`/`refs`, `o.createStore`. Add one script tag to an existing React app and get Playwright test generation without touching any components.
7
7
 
8
- **Live examples** — real patterns in [`examples/`](examples/index.html), narrative walkthroughs in [`EXAMPLES.md`](EXAMPLES.md).
8
+ **Live examples** — real patterns in [`examples/`](https://foggysq.github.io/objs/examples/), narrative walkthroughs in [`EXAMPLES.md`](EXAMPLES.md).
9
9
 
10
10
  ---
11
11
 
@@ -21,7 +21,7 @@
21
21
  - **Works standalone or with React** — Add one script tag to an existing React app; no architecture change. Familiar `className`, `ref`/`refs`, `o.createStore`. Built-in SSR (Node) with `DocumentMVP` and in-browser hydration.
22
22
  - **AI-friendly** — One file, ~6,000-token `SKILL.md` primer. No JSX, virtual DOM, or React lifecycle; fewer tokens than typical React context for runnable output. No stale closures, dependency arrays, or re-render cascades. Same code runs in Node (SSR) so tools can verify output without a browser — **verify generated code without user review**: run `o.init(states).render()` in Node, serialize or assert structure before returning to the user.
23
23
 
24
- → [Full comparison and live demo](examples/ai-workflow/index.html)
24
+ → [Full comparison and live demo](https://foggysq.github.io/objs/examples/ai-workflow/index.html)
25
25
 
26
26
  ---
27
27
 
@@ -174,12 +174,12 @@ timer.stop();
174
174
  `o.errors` – an array of all hidden errors, can be logged by `o.logErrors()` for debug
175
175
  `o.onError` – a function than will be called with an error as an argument
176
176
 
177
- > This and some more complex live examples are in the [full documentation](https://fous.name/objs). There are lots of useful methods and settings.
177
+ > This and some more complex live examples are in the [full documentation](https://fous.name/objs/documentation). There are lots of useful methods and settings.
178
178
 
179
179
 
180
180
  ### Tests - unit tests, e2e, recording etc.
181
181
 
182
- Testing is a first-class part of Objs: use `o.test()` and `o.addTest()` for sync and async unit tests, including tests with page reload and autorun. Record user sessions with `o.startRecording()` / `o.stopRecording()`, then export to Objs-style tests (`o.exportTest()`) or Playwright (`.spec.ts`) with `o.exportPlaywrightTest()` for e2e in CI. Replay with `o.playRecording()` (all builds); call `o.testOverlay()` to show a results panel so assessors can see if all auto tests passed and which manual checks failed. Use `o.testConfirm()` for manual checks (e.g. hover effects). Dev-only: `o.assertSize()` / `o.assertVisible()` for layout assertions. See the [recording example](examples/recording/index.html) and the full documentation for details.
182
+ Testing is a first-class part of Objs: use `o.test()` and `o.addTest()` for sync and async unit tests, including tests with page reload and autorun. Record user sessions with `o.startRecording()` / `o.stopRecording()`, then export to Objs-style tests (`o.exportTest()`) or Playwright (`.spec.ts`) with `o.exportPlaywrightTest()` for e2e in CI. Replay with `o.playRecording()` (all builds); call `o.testOverlay()` to show a results panel so assessors can see if all auto tests passed and which manual checks failed. Use `o.testConfirm()` for manual checks (e.g. hover effects). Dev-only: `o.assertSize()` / `o.assertVisible()` for layout assertions. See the [recording example](https://foggysq.github.io/objs/examples/recording/index.html) and the full documentation for details.
183
183
 
184
184
 
185
185
 
@@ -435,7 +435,7 @@ Use for design system or UI verification tests (e.g. button height 24px, contain
435
435
 
436
436
  `o.testOverlay()` – Renders a fixed overlay button (🧪 Tests). Click to see pass/fail results for all test runs (auto steps and manual checks). For assessors: after replay, open the overlay to see if all auto tests passed and which manual checks failed. Available in all builds.
437
437
 
438
- `o.testConfirm(label, items?, opts?)` – Shows a draggable overlay titled "Label: Paused" with an optional checklist; returns `Promise<{ ok: boolean, errors?: string[] }>`. Use after replay for manual checks (e.g. hover effects). Available in all builds. See the [recording example](examples/recording/index.html) for a live demo.
438
+ `o.testConfirm(label, items?, opts?)` – Shows a draggable overlay titled "Label: Paused" with an optional checklist; returns `Promise<{ ok: boolean, errors?: string[] }>`. Use after replay for manual checks (e.g. hover effects). Available in all builds. See the [recording example](https://foggysq.github.io/objs/examples/recording/index.html) for a live demo.
439
439
 
440
440
  ### SSR and Node
441
441
  In Node, **o.D** is **o.DocumentMVP** (no real DOM); **o.init().render()** builds a virtual tree and you can serialize with the same code path that produces HTML for SSR. See full docs for getSSR and hydration.
package/objs.built.js CHANGED
@@ -20,6 +20,7 @@ const o = (query) => {
20
20
  isRoot: false,
21
21
  _parent: null
22
22
  }, ONE = 1, TWO = 2, THREE = 3, booleanType = "boolean", objectType = "object", functionType = "function", stringType = "string", numberType = "number", notEmptyStringType = "notEmptyString", undefinedType = "undefined", _reactProp = "dangerouslySetInnerHTML", u, D = o.D, start = -1, finish = 0, select = 0, ssr = typeof process !== "undefined" || o.D === o.DocumentMVP, i = 0, j = 0;
23
+ const self = result;
23
24
  const type = (obj) => typeof obj;
24
25
  const cycleObj = (obj, func) => {
25
26
  for (const item in obj) if (Object.hasOwn(obj, item)) func(item, obj);
@@ -190,7 +191,8 @@ const o = (query) => {
190
191
  result[state] = returner((props = [{}]) => {
191
192
  result.currentState = state;
192
193
  const data = states[state] || { tag: "div" };
193
- const els = result.els.slice(finish, start + ONE);
194
+ const slice = Array.isArray(result.els) ? result.els.slice(finish, start + ONE) : [];
195
+ const els = slice.length ? slice : result.els || [];
194
196
  if (type(data) === objectType) {
195
197
  data.state = state;
196
198
  data["data-o-init"] = initN;
@@ -290,7 +292,7 @@ const o = (query) => {
290
292
  [state, [notEmptyStringType]],
291
293
  [fail, [stringType, undefinedType]]
292
294
  ]);
293
- loader.connect(result, state, fail);
295
+ loader.connect(self, state, fail);
294
296
  }, "connect");
295
297
  result.getSSR = returner((initId) => {
296
298
  typeVerify([[initId, [numberType, undefinedType]]]);
@@ -964,6 +966,7 @@ o.createStore = (defaults) => {
964
966
  };
965
967
  return store;
966
968
  };
969
+ o.U = void 0;
967
970
  o.W = 2;
968
971
  o.H = 100;
969
972
  o.F = false;
@@ -1316,7 +1319,7 @@ o.newLoader = (promise) => {
1316
1319
  if (finished) {
1317
1320
  if (error) {
1318
1321
  fail ? listener[fail]() : "";
1319
- } else {
1322
+ } else if (typeof listener[state] === "function") {
1320
1323
  listener[state](data);
1321
1324
  }
1322
1325
  } else {
@@ -1699,9 +1702,8 @@ o.test = (title = "", ...tests) => {
1699
1702
  sessionStorage.getItem(`oTest-Status-${testN2}`) || "[]"
1700
1703
  );
1701
1704
  for (let i = 0; i < o.tStatus[testN2].length; i++) {
1702
- if (o.tStatus[testN2]) {
1703
- done++;
1704
- }
1705
+ const s = o.tStatus[testN2][i];
1706
+ if (s === true || s === false) done++;
1705
1707
  }
1706
1708
  }
1707
1709
  if (o.tStyled) {
@@ -1839,7 +1841,7 @@ o.testUpdate = (info, res = o.F, suff = "") => {
1839
1841
  }
1840
1842
  }
1841
1843
  };
1842
- if (o.tStatus[testN2][info.i] === o.U) {
1844
+ if (o.tStatus[testN2][info.i] === o.U || o.tStatus[testN2][info.i] === null) {
1843
1845
  o.tStatus[testN2][info.i] = res === true;
1844
1846
  if (res === true) {
1845
1847
  if (info.tShowOk) {
@@ -1863,7 +1865,7 @@ o.testUpdate = (info, res = o.F, suff = "") => {
1863
1865
  }
1864
1866
  let fails = 0, n = 0;
1865
1867
  for (const s of o.tStatus[testN2]) {
1866
- if (s === o.U) {
1868
+ if (s === o.U || s === null) {
1867
1869
  return;
1868
1870
  }
1869
1871
  if (!s) {
package/objs.built.min.js CHANGED
@@ -3,15 +3,15 @@
3
3
  * @version 2.0
4
4
  * @author Roman Torshin
5
5
  * @license Apache-2.0
6
- */const X=!0,t=n=>{let e={els:[],ie:{},delegated:{},parented:{},store:{},refs:{},states:[],isDebug:!1,currentState:"",savedStates:{},isRoot:!1,_parent:null},o=1,r=2,c=3,w="boolean",a="object",b="function",S="string",N="number",l="notEmptyString",E="undefined",m="dangerouslySetInnerHTML",k,f=t.D,v=-1,u=0,h=0,x=typeof process<"u"||t.D===t.DocumentMVP,y=0,D=0;const C=s=>typeof s,R=(s,i)=>{for(const g in s)Object.hasOwn(s,g)&&i(g,s)},j=t.onError,L=s=>t.verify(s),T=(s,i="")=>(...g)=>{(t.debug||e.isDebug)&&console.log(i?`${i}()`:s,g.length?"with "+g.join(", "):"without parameters");try{const p=s(g[0],g[o],g[r],g[c]);return p!==k?p:e}catch(p){j(p,i)}},O=s=>{for(y=u;y<=v;y++)s()},A=s=>s?.els?s.el:(C(s)!==a&&(s=t.first(s).el),s),_=(s=!0,i=e.els)=>{const g=i.length;e.length=g,v=g-o,u=0,e.el=g?i[0]:k,e.last=g?i[v]:k,s&&(R(e.states,(p,d)=>{delete e[d[p]]}),e.states=[],e.ie={})};e.reset=t;const H=(s,i,g)=>{R(i,p=>{let d=i[p];C(d)===b&&(d=d(g)),p==="append"&&C(d)===a&&(d.els&&(d=[d]),d[0]?.els&&(valueBuff=[],R(d,$=>{valueBuff.push(...d[$].els)}),d=valueBuff)),d!==k&&s.getAttribute(p)!==d&&!["tag","tagName","name","sample","state","events","ssr","nodeName","revertChildren","root","ref"].includes(p)&&(["html","innerHTML"].includes(p)?s.innerHTML=d:p==="className"?s.setAttribute("class",d):p==="dataset"&&C(d)===a?R(d,$=>{s.dataset[$]=d[$]}):p==="toggleClass"?s.classList.toggle(d):p==="addClass"?C(d)===a?s.classList.add(...d):s.classList.add(d):p==="removeClass"?s.classList.remove(d):p==="style"&&C(d)===a?R(d,$=>{s.style[$]=d[$]}):(p==="append"||p==="children"||p==="childNodes")&&C(d)===a?R(d.length?d:[d],$=>{p==="append"||!s.childNodes[$]?s.appendChild(d[$]):s.childNodes[$]!==d[$]&&s.childNodes[$].replaceWith(d[$])}):s.setAttribute(p,d))}),s.dataset.oState=i.state,t.autotag&&i.name&&(s.dataset[t.autotag]=t.camelToKebab(i.name))};e.debug=T(()=>{e.isDebug=!0},"debug ON"),e.saveAs=T(s=>{L([[s,[l]]]),t.getSaved[s]?(t.debug||e.isDebug)&&console.warn("the key exists (not saved):"+s):t.getSaved[s]=e},"saveAs"),e.unmount=()=>((t.debug||e.isDebug)&&console.log("unmount() for initID:"+e.initID),C(e.remove)===b?e.remove():e.els?.length&&e.els.forEach(s=>{s?.parentNode&&s.parentNode.removeChild(s)}),t.inits[e.initID]=void 0,e={},!0),e.init=T(s=>{L([[s,[a,b]]]);const i=e.initID||t.inits.length||0;if(e.initID=i,_(),t.inits[e.initID]=e,C(s)==="function"){e.render=T(p=>{const d=f.createElement("div");setTimeout(()=>{t.reactRender(s,d,p)}),e.add(d)});return}(C(s)!==a||s.render===k)&&(s={render:s}),R(s,p=>{e?.render&&p==="render"||(e.states.push(p),e[p]=T((d=[{}])=>{e.currentState=p;const $=s[p]||{tag:"div"},I=e.els.slice(u,v+o);C($)===a&&($.state=p,$["data-o-init"]=i);const U=(M,B={})=>{if(C($)===a)return f.createElement($.tag||$.tagName||"div");{const F=f.createElement("div");return F.innerHTML=C($)===b?$(B):$,F.children.length>o||!F.firstElementChild?(F.dataset.oInit=M,F):(F.firstElementChild.dataset.oInit=M,F.firstElementChild)}},P=d;d.length||(d=[d]);const q=!I[0]&&p==="render";d=d.map((M,B)=>{const F=Object.assign({},C(M)===a?M:{},{self:e,o:t,i:M.i===k?B:M.i,parent:e._parent,data:Array.isArray(P)?P[B]:P});return q&&(!$.ssr||x)&&I.push(U(i,F)),F}),q&&(e.els=I,_(!1));const z=()=>{R($.events,M=>{e.on(M,$.events[M])})};I&&(D=I.length===d.length,I.map((M,B)=>{d[D?B:0].i=B+u;const F=C($)===b?$(d[D?B:0]):$;C(F)===a&&(F.state=p,q&&(F["data-o-init"]=i,F["data-o-init-i"]=B),H(M,F,d[D?B:0]))}),q&&(e.refs={},e.els.forEach(M=>{M.querySelectorAll&&M.querySelectorAll("[ref]").forEach(B=>{e.refs[B.getAttribute("ref")]=t(B),B.removeAttribute("ref")})}))),q&&C($)===a&&$.events&&!x&&!$.ssr&&z()}))});const g=s.render||s;!x&&C(g)===a&&g.events&&g.ssr&&(e.initSSRAfterGettingSSR=()=>{e.refs={},e.els.forEach(p=>{p.querySelectorAll&&p.querySelectorAll("[ref]").forEach(d=>{e.refs[d.getAttribute("ref")]=t(d),d.removeAttribute("ref")})}),R(g.events,p=>{e.on(p,g.events[p])})})},"init"),e.connect=T((s,i="render",g)=>{L([[s,[a]],[i,[l]],[g,[S,E]]]),s.connect(e,i,g)},"connect"),e.getSSR=T(s=>{L([[s,[N,E]]]);const i=s!==void 0?s:e.initID;if(x||C(s)===E&&C(e.initID)===E)return;const g=t.D.querySelectorAll(`[data-o-init="${i}"]`);g.length&&!e.els.length&&(e.els=Array.from(g),e.initID=s,t.inits[s]=e,_(!1),C(e.initSSRAfterGettingSSR)===b&&(e.initSSRAfterGettingSSR(),delete e.initSSRAfterGettingSSR))},"getSSR"),e.initState=T((s,i)=>{L([[s,[a]],[i,[a,E]]]),e.init(s).render(i)},"initState");const J=(s,i,g)=>{const p=s.attributes,d={tagName:s.tagName.toLowerCase()};for(const $ of p)d[$.nodeName]=$.value;if(g){d.innerHTML=s.innerHTML,d.revertChildren=[];const $=s.querySelectorAll("[data-o-init]");for(const I of $){const U=I.getAttribute("data-o-init");d.revertChildren.push(U),t.inits[U]?.saveState(i,!1)}}return d};return e.saveState=T((s,i=!0)=>{if(L([[s,[l,E]],[i,[w]]]),!e.el)throw Error("saveState(): There are no elements to save");const g=s||"fastSavedState",p={els:[],parentNode:e.el.parentNode,root:i};O(()=>{p.els.push(J(e.els[y],g,i))}),p.ie=Object.assign({},e.ie),p.delegated=Object.assign({},e.delegated),p.store=Object.assign({},e.store),e.isRoot=e.isRoot||i,e.savedStates[g]=p},"saveState"),e.revertState=T(s=>{L([[s,[l,E]]]);const i=s||"fastSavedState";if(!e.savedStates[i])throw Error(`revertState(): The state "${i}" should have been saved by saveState()`);const g=e.savedStates[i];e.offAll(),e.offDelegate(),e.store=Object.assign({},g.store),g.els.forEach((p,d)=>{if(!e.els[d]){const $=t.D.createElement(p.tagName);g.parentNode&&(d?e.els[d-1].after($):g.parentNode.append($)),e.add($)}H(e.els[d],p)}),e.delegated=Object.assign({},g.delegated),e.ie=Object.assign({},g.ie),e.onAll(),R(g.delegated,p=>{g.delegated[p].forEach(d=>{O(()=>{e.els[y].addEventListener(p,d)})})}),e.currentState=i,g.root&&g.els.forEach(({rootElement:p})=>{p.revertChildren.forEach(d=>{t.inits[d]?.revertState(i),t('[data-o-init="'+d+'"]').els.forEach(($,I)=>{$.replaceWith(t.inits[d]?.els[I])})})})},"revertState"),e.loseState=T(s=>{L([[s,[l]]]),e.savedStates[s]&&(delete e.savedStates[s],O(()=>{const i=e.els[y].querySelectorAll("[data-o-init]");for(const g of i){const p=g.getAttribute("data-o-init");t.inits[p]?.loseState(s)}}))},"sample"),e.sample=T((s="render")=>(L([[s,[l]]]),{[s]:J(e.els[u])}),"sample"),e.select=T(s=>{L([[s,[N,E]]]),s===k&&(s=e.length-o),v=s,u=s,e.el=e.els[s],h=o},"select"),e.all=T(()=>{v=e.length-o,u=0,e.el=e.els[0],h=0},"all"),e.remove=T(s=>{if(L([[s,[N,E]]]),s===k&&h&&(s=u),s!==k){const i=e.els[s];i?.parentNode?i.parentNode.removeChild(i):i===void 0&&s>=e.els.length&&t.onError&&t.onError("remove("+s+"): index out of bounds","remove")}else O(()=>{const i=e.els[y];i?.parentNode&&i.parentNode.removeChild(i)});_(!1)},"remove"),e.skip=T(s=>{L([[s,[N,E]]]),s===k&&(s=u),e.els.splice(y,o),_()},"skip"),e.add=T(s=>{L([[s,[S,a,N]]]),e.initID===k&&(C(s)==="string"&&s!==""?e.els.push(...Array.from(f.querySelectorAll(s))):C(s)===a?s.tagName?e.els.push(s):s.els?e.els.push(...s.els):s.length&&s[0].tagName&&e.els.push(...s):C(s)==="number"&&t.inits[s]&&(e=t.inits[s]),_(!1),e.initID!==k&&e.dataset({oInit:e.initID}))},"add"),e.appendInside=T(s=>{L([[s,[a,l]]]),s?.els&&(e._parent=s),O(()=>{A(s).appendChild(e.els[y])})},"appendInside"),e.appendBefore=T(s=>{L([[s,[a,l]]]),O(()=>{A(s).parentNode.insertBefore(e.els[y],A(s))})},"appendBefore"),e.appendAfter=T(s=>{L([[s,[a,l]]]),O(()=>{A(s).after(...e.els)})},"appendAfter"),e.find=T((s="")=>{L([[s,S]]);const i=[];return O(()=>{i.push(...Array.from(e.els[y].querySelectorAll(":scope "+s)))}),t(i)},"find"),e.first=T((s="")=>{L([[s,S]]);let i=k;const g=[];return O(()=>{i=e.els[y].querySelector(s),i&&g.push(i)}),t(g)},"first"),e.attr=T((s,i)=>{if(i!==null&&L([[s,S],[i,[S,E]]]),i===k){const g=[];return O(()=>{g[y]=e.els[y].getAttribute(s)}),h?g[0]:g}else O(i!==null?()=>{e.els[y].setAttribute(s,i)}:()=>{e.els[y].removeAttribute(s)})},"attr"),e.attrs=T(()=>{const s=[];return O(()=>{const i={};[...e.els[y].attributes].forEach(g=>{i[g.nodeName]=g.nodeValue}),s.push(i)}),h?s[0]:s},"attrs"),e.dataset=T(s=>{if(L([[s,[a,E]]]),typeof s===a)O(()=>{R(s,i=>{e.els[y].dataset[i]=s[i]})});else{const i=[];return O(()=>{i.push({...e.els[y].dataset})}),h?i[0]:i}},"dataset"),e.style=T(s=>{s!==null&&L([[s,[S,E]]]),e.attr("style",s)},"style"),e.css=T((s={})=>{if(s===null){e.style(null);return}L([[s,a]]);let i="";R(s,g=>{i+=g+":"+s[g].replace('"',"'")+";"}),e.style(i||null)},"css"),e.setClass=T(s=>{L([[s,S]]),O(()=>{e.els[y].setAttribute("class",s)})},"setClass"),e.addClass=T((...s)=>{O(()=>{e.els[y].classList.add(...s)})},"addClass"),e.removeClass=T((...s)=>{O(()=>{e.els[y].classList.remove(...s)})},"removeClass"),e.toggleClass=T((s,i)=>{L([[s,l],[i,[w,E]]]),O(()=>{e.els[y].classList.toggle(s,i)})},"toggleClass"),e.haveClass=s=>{L([[s,l]]);let i=!0;return O(()=>{e.els[y].classList.contains(s)||(i=!1)}),(e.isDebug||t.debug)&&console.log("haveClass() with",s),i},e.innerHTML=T(s=>{if(L([[s,[S,E]]]),s!==k)O(()=>{e.els[y].innerHTML=s});else{let i="";return O(()=>{i+=x&&e.els[y].innerHTML.length===0?t.D.parseElement(e.els[y],!1):e.els[y].innerHTML}),i}},"innerHTML"),e.innerText=T(s=>{L([[s,[S]]]),O(()=>{e.els[y].innerText=s})},"innerText"),e.textContent=T(s=>{L([[s,[S]]]),O(()=>{e.els[y].textContent=s})},"textContent"),e.html=T(s=>{if(L([[s,[S,E]]]),s!==void 0)e.innerHTML(s);else{let i="";return O(()=>{i+=x?e.els[y].outerHTML():e.els[y].outerHTML}),i}},"html"),e.val=T(s=>{if(s===void 0)return e.el?.value;O(()=>{e.els[y].value=s})},"val"),e.forEach=T(s=>{L([[s,[b]]]),O(()=>{s({self:e,i:y,o:t,el:e.els[y]})})},"forEach"),e.prepareFor=T((s,i)=>{L([[s,[a,b,E]],[i,[b,E]]]);const g=s&&C(s)===a&&s.createElement;if(!g&&C(s)!==b)throw Error("prepareFor(): pass React (full object) or React.createElement as first argument");const p=g?s.createElement:s,d=g?s.useEffect:void 0;return $=>{if($.ref===k)throw Error("No ref property to convert Objs to React");const I=Object.assign({},$),U=p("div",{ref:$.ref});return delete I.ref,d(()=>{R(I,P=>{if(P.substring(0,1)==="on"){const q=t.camelToKebab(P).split("-")[1];e.on(q,I[P]),delete I[P]}}),e.render(I),e.appendInside(U.ref.current)},[]),U}},"prepareFor"),e.on=T((s,i,g,p)=>{L([[s,[l]],[i,[b]],[g,[a,E]],[p,[w,E]]]),s.split(", ").forEach(d=>{O(()=>{e.els[y].addEventListener(d,i,g,p)}),e.ie[d]||(e.ie[d]=[]),e.ie[d].push([i,g,p])})},"on"),e.off=T((s,i,g)=>{L([[s,[l]],[i,[b]],[g,[a,E]]]),s.split(", ").forEach(p=>{O(()=>{e.els[y].removeEventListener(p,i,g)}),e.ie[p]&&(e.ie[p]=e.ie[p].filter(d=>d[0]!==i))})},"off"),e.onDelegate=T((s,i,g)=>{L([[s,[l]],[i,[l]],[g,[b]]]),s.split(", ").forEach(p=>{const d=$=>{const I=$.target.closest(i);I&&($.delegate=I,$.objs=e,g($))};O(()=>{e.els[y].addEventListener(p,d)}),e.delegated[p]||(e.delegated[p]=[]),e.delegated[p].push(d)})},"onDelegate"),e.offDelegate=T(s=>{L([[s,[l]]]),R(e.delegated,i=>{if(!s||s===i)for(;e.delegated[i].length;){const g=e.delegated[i].pop();O(()=>{e.els[y].removeEventListener(i,g)})}}),e.delegated={}},"offDelegate"),e.onParent=T((s,i,g)=>{L([[s,[l]],[i,[l,a]],[g,[b]]]);const p=C(i)===a?i:t.D.querySelector(i);s.split(", ").forEach(d=>{const $=I=>{I.objs=e,g(I)};p.addEventListener(d,$),e.parented[d]||(e.parented[d]=[]),e.parented[d].push($)})},"onParent"),e.offParent=T((s,i)=>{L([[s,[l]],[i,[l,a]]]);const g=C(i)===a?i:t.D.querySelector(i);R(e.parented,p=>{(!s||s===p)&&(e.parented[p].forEach(d=>{g.removeEventListener(p,d)}),delete e.parented[p])})},"offParent"),e.onAll=T((s,i)=>{L([[s,[l,E]],[i,[w,E]]]),R(e.ie,(g,p)=>{(!s||s===g)&&p[g].forEach(d=>{O(()=>{i?e.els[y].removeEventListener(g,d[0]):e.els[y].addEventListener(g,d[0],d[o],d[r])})})})},"onAll"),e.offAll=T(s=>{L([[s,[l]]]),e.onAll(s,o)},"offAll"),n&&e.add(n),e.take=s=>{if(L([[s,[S,a,N]]]),e.add(s),e.el){const i=e.el.dataset.oInit;if(i!==k&&t.inits[i])return e.length===o?(D=e.els[0],Object.assign(e,t.inits[i]),e.els=[D]):e=t.inits[i],_(!1,e.els),e}},e};t.first=n=>(t.verify([[n,["notEmptyString"]]]),t.debug&&console.log(n," -> ","o.first()"),t(t.D.querySelector(n)).select(0)),t.inits=[],t.getSaved={},t.errors=[],t.showErrors=!1,t.logErrors=()=>{t.errors.length?t.errors.forEach(n=>console.error(n)):console.log("No errors")},t.onError=(n,e)=>{t.showErrors?console.error(n,e):(t.errors.push(n),e&&t.errors.push(e))},t.reactRender=()=>new Error("React render function is not defined"),t.autotag=void 0,t.reactQA=n=>({["data-"+(t.autotag||"qa")]:n.replace(/([A-Z])/g,(e,o)=>"-"+o.toLowerCase()).replace(/^-/,"")}),t.specialTypes={notEmptyString:(n,e)=>e==="string"&&n.length,array:n=>Array.isArray(n),promise:n=>n instanceof Promise||!!(n&&typeof n.then=="function")},t.verify=(n,e=!1)=>{for(const o of n){const r=typeof o[0];let c=Array.isArray(o[1])?o[1]:[o[1]],w=!1;if(c.includes(r))return!0;c=c.filter(a=>!!t.specialTypes[a]);for(const a of c)if(w=t.specialTypes[a](o[0],r),w)return!0}return e?!1:new Error("Type verification failed")},t.safeVerify=n=>t.verify(n,!0),t.init=(n,e)=>t().init(n,e),t.initState=(n,e)=>t().init(n).render(e),t.take=n=>t().take(n),t.getStates=()=>t.inits.reduce((n,e)=>(n.push(e?.states),n),[]),t.getStores=()=>t.inits.reduce((n,e)=>(n.push(e?.store),n),[]),t.getListeners=()=>t.inits.reduce((n,e)=>(n.push(e?.ie),n),[]),t.createStore=n=>{const e=Object.assign({},n);return e._defaults=Object.assign({},n),e._listeners=[],e.subscribe=function(o,r){return this._listeners.push(c=>o[r]?.(c)),this},e.notify=function(){this._listeners.forEach(o=>o(this))},e.reset=function(){const o={_listeners:1,subscribe:1,notify:1,_defaults:1,reset:1};for(const r of Object.keys(this._defaults))o[r]||(this[r]=this._defaults[r])},e},t.W=2,t.H=100,t.F=!1,t.C=(n,e)=>Object.hasOwn(n,e),t.kebabToCamel=n=>n.replace(/-./g,e=>e.toUpperCase()[1]),t.camelToKebab=n=>n.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase(),t.route=(n,e)=>{t.verify([[n,["notEmptyString","function","boolean"]],[e,["function","object"]]]);const o=typeof n=="function"?n(window.location.pathname):n;return o===!0||window.location.pathname===o?e?typeof e=="function"?(e(),!0):e:t:typeof e=="function"?!1:{}},t.router=(n={})=>{t.verify([[n,["object"]]]);for(const e in n)if(t.C(n,e)&&window.location.pathname===e)return typeof n[e]=="function"?(n[e](),!0):n[e];return!1},t.DocumentMVP={addEventListener:()=>{},parseElement:(n,e=!0)=>{t.verify([[n,["object","string"]],[e,["boolean"]]]);const o=(r,c="")=>{let w="";for(const a in r)t.C(r,a)&&(w+=` ${c}${t.camelToKebab(a)}="${typeof r[a]!="object"?r[a]:Object.entries(r[a]).map(b=>`${b[0]}: ${b[1]};`).join(" ")}"`);return w};if(typeof n=="string")return n;if(e){const r=["area","base","br","col","embed","hr","img","input","link","meta","param","source","track","wbr"],c=n.tagName.toLowerCase(),w=n.attributes["data-o-init"],a=w!==void 0?` data-o-init="${w}"`:"";return`<${c}${n.className?` class="${n.className}"`:""}${o(n.attributes)}${a}${o(n.dataset,"data-")}${r.includes(c)?"/":""}>${r.includes(c)?"":n.innerHTML.length?n.innerHTML:n.children.map(b=>t.D.parseElement(b)).join("")}${r.includes(c)?"":`</${c}>`}`}return n.innerHTML.length?n.innerHTML:n.children.map(r=>t.D.parseElement(r)).join("")},createElement:n=>{t.verify([[n,["notEmptyString"]]]);const e={tagName:n.toUpperCase(),attributes:{},innerHTML:"",children:[],dataset:{},className:"",classArray:[],style:{},addEventListener:()=>{},removeEventListener:()=>{}};return e.classList={add:(...o)=>{t.verify([[o,["array"]]]),e.classArray.push(o),e.className=e.classArray.join(" ")},has:o=>(t.verify([[o,["notEmptyString"]]]),e.classArray.includes(o)),remove:o=>{t.verify([[o,["notEmptyString"]]]),e.classArray=e.classArray.filter(r=>o!==r),e.className=e.classArray.join(" ")}},e.classList.toggle=o=>{t.verify([[o,["notEmptyString"]]]),e.classList.has(o)?e.classList.remove(o):e.classList.add(o)},e.setAttribute=(o,r)=>{t.verify([[o,["notEmptyString"]],[r,["string","number","boolean","undefined"]]]),e.attributes[o]=r},e.getAttribute=o=>(t.verify([[o,["notEmptyString"]]]),e.attributes[o]),e.removeAttribute=o=>{t.verify([[o,["notEmptyString"]]]),delete e.attributes[o]},e.appendChild=o=>{t.verify([[o,["object"]]]),e.children.push(o),e.firstElementChild=e.children[0]},e.outerHTML=()=>t.D.parseElement(e),e}},t.D=typeof document<"u"&&typeof process>"u"?document:t.DocumentMVP,t.setCookie=(n,e="",o={})=>{if(t.verify([[n,["notEmptyString"]],[e,["string","number","boolean"]],[o,["object"]]]),t.D.cookie===void 0){console.log("Cookies are not supported on server side");return}let r=encodeURIComponent(n)+"="+encodeURIComponent(e);o={path:"/",...o},o.expires instanceof Date?o.expires=o.expires.toUTCString():typeof o.expires=="number"&&(o.expires=new Date(o.expires).toUTCString());for(const c in o){r+="; "+c;const w=o[c];w!==!0&&(r+="="+w)}t.D.cookie=r},t.getCookie=n=>{if(t.verify([[n,["notEmptyString"]]]),t.D.cookie===void 0){console.log("Cookies are not supported on server side");return}const e=t.D.cookie.match(RegExp("(?:^|; )"+n.replace(/([.$?*|{}()[\]\\/+^])/g,"\\$1")+"=([^;]*)"));return e?decodeURIComponent(e[1]):void 0},t.deleteCookie=n=>{t.verify([[n,["notEmptyString"]]]),t.setCookie(n,"",{"max-age":0})},t.clearCookies=()=>{if(t.D.cookie===void 0){console.log("Cookies are not supported on server side");return}const n=t.D.cookie.split(";");for(;n.length;){let e=n.pop();for(;e.charAt(0)===" ";)e=e.substring(1);const o=e.split("=")[0];t.deleteCookie(o)}},t.clearLocalStorage=n=>{if(t.verify([[n,["boolean","undefined"]]]),!(typeof localStorage>"u"))if(n)localStorage.clear();else for(let e=localStorage.length-1;e>=0;e--){const o=localStorage.key(e);o.indexOf("oInc-")===-1&&o.indexOf("oTest-")===-1&&localStorage.removeItem(o)}},t.clearSessionStorage=n=>{if(t.verify([[n,["boolean","undefined"]]]),!(typeof sessionStorage>"u"))if(!n)sessionStorage.clear();else for(let e=sessionStorage.length-1;e>=0;e--){const o=sessionStorage.key(e);o&&o.indexOf("oTest-")===0&&sessionStorage.removeItem(o)}},t.clearTestsStorage=()=>{t.clearSessionStorage(1)},t.clearAfterTests=()=>{t.clearCookies(),t.clearLocalStorage(!1),t.clearTestsStorage()},t.ajax=(n,e={})=>{t.verify([[n,["notEmptyString"]],[e,["object"]]]);const o=new URLSearchParams;if(e.data&&typeof e.data=="object"){for(const r in e.data)t.C(e.data,r)&&(typeof e.data[r]=="object"?o.set(r,encodeURIComponent(JSON.stringify(e.data[r]))):o.set(r,e.data[r]));e.method.toLowerCase()==="get"?n+="?"+o.toString():e.body||(e.body=o),delete e.data}return e.headers||(e.headers={"X-Requested-With":"XMLHttpRequest"}),fetch(n,e)},t.get=(n,e={})=>(t.verify([[n,["notEmptyString"]],[e,["object"]]]),t.ajax(n,{...e,method:"GET"})),t.post=(n,e={})=>(t.verify([[n,["notEmptyString"]],[e,["object"]]]),t.ajax(n,{...e,method:"POST"})),t.newLoader=n=>{t.verify([[n,["promise","undefined"]]]);let e=[],o=null,r=!1,c=!1;const w=a=>{r=!1,c=!1,o=null,setTimeout(()=>{a.then(b=>{r=!0,!b.ok&&typeof b.ok<"u"?(c=!0,e.forEach(([S,N,l])=>{l&&S[l](b)})):typeof b.json=="function"?b.json().then(S=>{o=S,e.forEach(([N,l])=>{N[l](o)})}):(o=b,e.forEach(([S,N])=>{S[N](o)}))}).catch(b=>{c=!0,e.forEach(([S,N,l])=>{l&&S[l](b)})})},33)};return n&&w(n),{reload:w,isObjsLoader:!0,listeners:e,isFinished:()=>r,getStore:()=>o,connect:(a,b="render",S)=>{t.verify([[a,["object"]],[b,["notEmptyString"]],[S,["string","undefined"]]]),r?c?S&&a[S]():a[b](o):e.push([a,b,S])},disconnect:a=>{t.verify([[a,["object"]]]),e=e.filter(([b])=>b!==a)}}},t.getParams=n=>{t.verify([[n,["string","undefined"]]]);const e={},o=new URLSearchParams(window.location.search).entries();for(const r of o)e[r[0]]=r[1];return n?e[n]:e},t.incCache=!0,t.incCacheExp=1e3*60*60*24,t.incTimeout=6e3,t.incSource="",t.incForce=t.F,t.incAsync=!0,t.incCors=t.F,t.incSeparator="?",t.incFns={},t.incSet=[0],t.incReady=[0],t.incN=0,t.incGetHash=n=>n.split(t.incSeparator)[1]||"",t.incCheck=(n=0,e,o=0)=>(t.verify([[n,["number"]],[e,["number","undefined"]],[o,["number"]]]),!o&&n&&e===t.U&&t.incReady[n]?t.incSet[n]===1:t.incReady[n]===t.U||t.incReady[n][e]===t.U?t.F:(t.incReady[n][e].loaded=o,t.incFns[t.incReady[n][e].name]=o,t.incReady[n][0]+=o,n&&t.incReady[n].length===t.incReady[n][0]&&(typeof t.incSet[n]=="function"&&t.incSet[n](n),t.incSet[n]=1),t.incSet[n]===1)),t.incCacheClear=(n=t.F)=>{t.verify([[n,["boolean"]]]);for(const e in t.incFns)t.C(t.incFns,e)&&(localStorage.removeItem("oInc-"+e),localStorage.removeItem("oInc-"+e+"-expires"));return n&&(t.incReady.forEach((e,o)=>{o&&e.forEach((r,c)=>{c&&t("#oInc-"+o+"-"+c).remove()})}),t.incN=0,t.incFns={},t.incSet=[0],t.incReady=[0]),!0},t.inc=(n,e,o)=>{if(t.verify([[n,["object","undefined"]],[e,["function","undefined"]],[o,["function","undefined"]]]),typeof localStorage>"u")return;let r=0,c=0,w="",a=!1;const b="function",S=-1;if(typeof n!="object"||!n)return t.incSet[0];t.incSet[0]++;const N=t.incSet[0];t.incSet[N]=e||0,t.incReady[N]=[];const l=t.incReady[N];l[0]=1;const E={};for(const m in n)if(t.C(n,m)){if(m==="preload"){a=!0;continue}w=t.incGetHash(n[m]),r++,t.incN++;const k=n[m].indexOf(".css")>S?"style":"script";if(n[m]=(t.incSource?t.incSource+"/":"")+n[m],Number.isNaN(Number(m))&&t.C(t.incFns,m)&&t.incFns[m]&&!t.incForce){l[r]={name:m,loaded:1},c++;continue}if(l[r]={name:m,loaded:0},Number.isNaN(Number(m))&&(t.incFns[m]=0),Number.isNaN(Number(m))&&t.incCache&&(n[m].substring(0,4)!=="http"||!t.incCors)&&window.location.protocol!=="file:"&&(n[m].indexOf(".css")>S||n[m].indexOf(".js")>S)){const f=localStorage,v=f.getItem("oInc-"+m),u=f.getItem("oInc-"+m+"-expires"),h=f.getItem("oInc-"+m+"-hash");v&&u&&Date.now()<u&&h===w?(a||t.initState({tag:k,id:"oInc-"+N+"-"+r,innerHTML:v,"data-o-inc":N}).appendInside("head"),l[r].loaded=1,t.incFns[m]=1,c++):(E[m]=r,t.get(n[m],{mode:t.incCors?"cors":"same-origin"}).then(x=>{if(x.status!==200){t.onError&&t.onError({message:t.incSource+n[m]+" was not loaded"});return}x.text().then(y=>{f.setItem("oInc-"+m,y),f.setItem("oInc-"+m+"-expires",Date.now()+t.incCacheExp),f.setItem("oInc-"+m+"-hash",w),a||t.initState({tag:k,id:"oInc-"+N+"-"+E[m],innerHTML:y,"data-o-inc":N}).appendInside("head"),t.incCheck(N,E[m],1)})}))}else{const f={tag:k,id:"oInc-"+N+"-"+r,"data-o-inc":N,async:t.incAsync,onload:"o.incCheck("+N+","+r+",1)"};n[m].indexOf(".css")>S?(f.tag="link",f.rel="stylesheet",f.href=n[m]):(n[m].indexOf(".js")>S||(f.tag="img",f.style="display:none;"),f.src=n[m]),t.initState(f).appendInside(f.style?"body":"head")}}return l[0]+=c,r!==0&&(c===r?typeof e===b&&e(N):setTimeout(m=>{t.incReady[m]&&t.incReady[m].length<t.incReady[m][0]&&(t.incSet[m]=0,typeof o===b&&o(N))},t.incTimeout,N)),t.incSet[0]},t.connectRedux=(n,e,o,r="render")=>{t.verify([[n,["object"]],[e,["function"]],[o,["object"]],[r,["notEmptyString"]]]);const c=()=>{if(typeof o[r]=="function"){const w=e(n.getState());o[r](w!==null&&typeof w=="object"?w:{value:w})}};return c(),n.subscribe(c)},t.connectMobX=(n,e,o,r,c="render")=>(t.verify([[n,["object"]],[e,["object"]],[o,["function"]],[r,["object"]],[c,["notEmptyString"]]]),n.autorun(()=>{if(typeof r[c]=="function"){const w=o(e);r[c](w!==null&&typeof w=="object"?w:{value:w})}})),t.ObjsContext=null,t.withReactContext=(n,e,o,r,c="render")=>function(){const a=n.useContext(e);return n.useEffect(()=>{if(typeof r[c]=="function"){const b=o(a);r[c](b!==null&&typeof b=="object"?b:{value:b})}},[a]),null},t.debug=!1,t.tLog=[],t.tRes=[],t.tStatus=[],t.tFns=[],t.tShowOk=t.F,t.tStyled=t.F,t.tTime=2e3,t.tests=[],t.tAutolog=t.F,t.tBeforeEach=void 0,t.tAfterEach=void 0,t.addTest=(n,...e)=>{t.verify([[n,["notEmptyString"]],[e,["array"]]]);let o={};e.length&&typeof e[e.length-1]=="object"&&!Array.isArray(e[e.length-1])&&(o=e.pop());const r=t.tests.length;return t.tests[r]={title:n,tests:e,hooks:o},{run:()=>{typeof o.before=="function"&&(t.tBeforeEach=o.before),typeof o.after=="function"&&(t.tAfterEach=o.after),t.runTest(r)},autorun:()=>{typeof o.before=="function"&&(t.tBeforeEach=o.before),typeof o.after=="function"&&(t.tAfterEach=o.after),t.runTest(r,!0)},testId:r}},t.updateLogs=()=>{for(let n=0;n<t.tests.length;n++)t.tLog[n]=t.tLog[testN]=sessionStorage.getItem(`oTest-Log-${testN}`)||"";return t.tLog},t.runTest=(n=0,e,o)=>{if(t.verify([[n,["number"]],[e,["boolean","undefined"]],[o,["boolean","undefined"]]]),!t.tests[n])return;o||(sessionStorage?.removeItem(`oTest-Log-${n}`),sessionStorage?.removeItem(`oTest-Res-${n}`),sessionStorage?.removeItem(`oTest-Status-${n}`)),sessionStorage?.setItem("oTest-Run",n),e?sessionStorage?.setItem("oTest-Autorun",e):sessionStorage?.removeItem("oTest-Autorun");const r=t.tests[n];let c=r.tests.pop();typeof c!="function"&&(r.tests.push(c),c=()=>{}),r.tests.push(w=>{c(w),sessionStorage.setItem("dddd",1),sessionStorage?.removeItem("oTest-Run"),e&&t.runTest(n+1,e)}),t.test(r.title,...r.tests)},t.tPre='<div style="font-family:monospace;text-align:left;">',t.tOk='<span style="background:#cfc;padding: 0 15px;">OK</span> ',t.tXx='<div style="background:#fcc;padding:3px;">',t.tDc="</div>",t.test=(n="",...e)=>{t.verify([[n,["notEmptyString"]],[e,["array"]]]);const o=sessionStorage?.getItem("oTest-Run"),r=o||t.tLog.length;let c=0,w="\u251C OK: ",a="\u251C \u2718 ",b=`
6
+ */const Y=!0,t=n=>{let e={els:[],ie:{},delegated:{},parented:{},store:{},refs:{},states:[],isDebug:!1,currentState:"",savedStates:{},isRoot:!1,_parent:null},o=1,r=2,c=3,w="boolean",a="object",h="function",S="string",C="number",l="notEmptyString",k="undefined",m="dangerouslySetInnerHTML",E,f=t.D,v=-1,u=0,y=0,x=typeof process<"u"||t.D===t.DocumentMVP,b=0,D=0;const I=e,O=s=>typeof s,R=(s,i)=>{for(const g in s)Object.hasOwn(s,g)&&i(g,s)},U=t.onError,L=s=>t.verify(s),$=(s,i="")=>(...g)=>{(t.debug||e.isDebug)&&console.log(i?`${i}()`:s,g.length?"with "+g.join(", "):"without parameters");try{const p=s(g[0],g[o],g[r],g[c]);return p!==E?p:e}catch(p){U(p,i)}},N=s=>{for(b=u;b<=v;b++)s()},M=s=>s?.els?s.el:(O(s)!==a&&(s=t.first(s).el),s),P=(s=!0,i=e.els)=>{const g=i.length;e.length=g,v=g-o,u=0,e.el=g?i[0]:E,e.last=g?i[v]:E,s&&(R(e.states,(p,d)=>{delete e[d[p]]}),e.states=[],e.ie={})};e.reset=t;const H=(s,i,g)=>{R(i,p=>{let d=i[p];O(d)===h&&(d=d(g)),p==="append"&&O(d)===a&&(d.els&&(d=[d]),d[0]?.els&&(valueBuff=[],R(d,T=>{valueBuff.push(...d[T].els)}),d=valueBuff)),d!==E&&s.getAttribute(p)!==d&&!["tag","tagName","name","sample","state","events","ssr","nodeName","revertChildren","root","ref"].includes(p)&&(["html","innerHTML"].includes(p)?s.innerHTML=d:p==="className"?s.setAttribute("class",d):p==="dataset"&&O(d)===a?R(d,T=>{s.dataset[T]=d[T]}):p==="toggleClass"?s.classList.toggle(d):p==="addClass"?O(d)===a?s.classList.add(...d):s.classList.add(d):p==="removeClass"?s.classList.remove(d):p==="style"&&O(d)===a?R(d,T=>{s.style[T]=d[T]}):(p==="append"||p==="children"||p==="childNodes")&&O(d)===a?R(d.length?d:[d],T=>{p==="append"||!s.childNodes[T]?s.appendChild(d[T]):s.childNodes[T]!==d[T]&&s.childNodes[T].replaceWith(d[T])}):s.setAttribute(p,d))}),s.dataset.oState=i.state,t.autotag&&i.name&&(s.dataset[t.autotag]=t.camelToKebab(i.name))};e.debug=$(()=>{e.isDebug=!0},"debug ON"),e.saveAs=$(s=>{L([[s,[l]]]),t.getSaved[s]?(t.debug||e.isDebug)&&console.warn("the key exists (not saved):"+s):t.getSaved[s]=e},"saveAs"),e.unmount=()=>((t.debug||e.isDebug)&&console.log("unmount() for initID:"+e.initID),O(e.remove)===h?e.remove():e.els?.length&&e.els.forEach(s=>{s?.parentNode&&s.parentNode.removeChild(s)}),t.inits[e.initID]=void 0,e={},!0),e.init=$(s=>{L([[s,[a,h]]]);const i=e.initID||t.inits.length||0;if(e.initID=i,P(),t.inits[e.initID]=e,O(s)==="function"){e.render=$(p=>{const d=f.createElement("div");setTimeout(()=>{t.reactRender(s,d,p)}),e.add(d)});return}(O(s)!==a||s.render===E)&&(s={render:s}),R(s,p=>{e?.render&&p==="render"||(e.states.push(p),e[p]=$((d=[{}])=>{e.currentState=p;const T=s[p]||{tag:"div"},A=Array.isArray(e.els)?e.els.slice(u,v+o):[],B=A.length?A:e.els||[];O(T)===a&&(T.state=p,T["data-o-init"]=i);const q=(_,F={})=>{if(O(T)===a)return f.createElement(T.tag||T.tagName||"div");{const j=f.createElement("div");return j.innerHTML=O(T)===h?T(F):T,j.children.length>o||!j.firstElementChild?(j.dataset.oInit=_,j):(j.firstElementChild.dataset.oInit=_,j.firstElementChild)}},z=d;d.length||(d=[d]);const X=!B[0]&&p==="render";d=d.map((_,F)=>{const j=Object.assign({},O(_)===a?_:{},{self:e,o:t,i:_.i===E?F:_.i,parent:e._parent,data:Array.isArray(z)?z[F]:z});return X&&(!T.ssr||x)&&B.push(q(i,j)),j}),X&&(e.els=B,P(!1));const V=()=>{R(T.events,_=>{e.on(_,T.events[_])})};B&&(D=B.length===d.length,B.map((_,F)=>{d[D?F:0].i=F+u;const j=O(T)===h?T(d[D?F:0]):T;O(j)===a&&(j.state=p,X&&(j["data-o-init"]=i,j["data-o-init-i"]=F),H(_,j,d[D?F:0]))}),X&&(e.refs={},e.els.forEach(_=>{_.querySelectorAll&&_.querySelectorAll("[ref]").forEach(F=>{e.refs[F.getAttribute("ref")]=t(F),F.removeAttribute("ref")})}))),X&&O(T)===a&&T.events&&!x&&!T.ssr&&V()}))});const g=s.render||s;!x&&O(g)===a&&g.events&&g.ssr&&(e.initSSRAfterGettingSSR=()=>{e.refs={},e.els.forEach(p=>{p.querySelectorAll&&p.querySelectorAll("[ref]").forEach(d=>{e.refs[d.getAttribute("ref")]=t(d),d.removeAttribute("ref")})}),R(g.events,p=>{e.on(p,g.events[p])})})},"init"),e.connect=$((s,i="render",g)=>{L([[s,[a]],[i,[l]],[g,[S,k]]]),s.connect(I,i,g)},"connect"),e.getSSR=$(s=>{L([[s,[C,k]]]);const i=s!==void 0?s:e.initID;if(x||O(s)===k&&O(e.initID)===k)return;const g=t.D.querySelectorAll(`[data-o-init="${i}"]`);g.length&&!e.els.length&&(e.els=Array.from(g),e.initID=s,t.inits[s]=e,P(!1),O(e.initSSRAfterGettingSSR)===h&&(e.initSSRAfterGettingSSR(),delete e.initSSRAfterGettingSSR))},"getSSR"),e.initState=$((s,i)=>{L([[s,[a]],[i,[a,k]]]),e.init(s).render(i)},"initState");const J=(s,i,g)=>{const p=s.attributes,d={tagName:s.tagName.toLowerCase()};for(const T of p)d[T.nodeName]=T.value;if(g){d.innerHTML=s.innerHTML,d.revertChildren=[];const T=s.querySelectorAll("[data-o-init]");for(const A of T){const B=A.getAttribute("data-o-init");d.revertChildren.push(B),t.inits[B]?.saveState(i,!1)}}return d};return e.saveState=$((s,i=!0)=>{if(L([[s,[l,k]],[i,[w]]]),!e.el)throw Error("saveState(): There are no elements to save");const g=s||"fastSavedState",p={els:[],parentNode:e.el.parentNode,root:i};N(()=>{p.els.push(J(e.els[b],g,i))}),p.ie=Object.assign({},e.ie),p.delegated=Object.assign({},e.delegated),p.store=Object.assign({},e.store),e.isRoot=e.isRoot||i,e.savedStates[g]=p},"saveState"),e.revertState=$(s=>{L([[s,[l,k]]]);const i=s||"fastSavedState";if(!e.savedStates[i])throw Error(`revertState(): The state "${i}" should have been saved by saveState()`);const g=e.savedStates[i];e.offAll(),e.offDelegate(),e.store=Object.assign({},g.store),g.els.forEach((p,d)=>{if(!e.els[d]){const T=t.D.createElement(p.tagName);g.parentNode&&(d?e.els[d-1].after(T):g.parentNode.append(T)),e.add(T)}H(e.els[d],p)}),e.delegated=Object.assign({},g.delegated),e.ie=Object.assign({},g.ie),e.onAll(),R(g.delegated,p=>{g.delegated[p].forEach(d=>{N(()=>{e.els[b].addEventListener(p,d)})})}),e.currentState=i,g.root&&g.els.forEach(({rootElement:p})=>{p.revertChildren.forEach(d=>{t.inits[d]?.revertState(i),t('[data-o-init="'+d+'"]').els.forEach((T,A)=>{T.replaceWith(t.inits[d]?.els[A])})})})},"revertState"),e.loseState=$(s=>{L([[s,[l]]]),e.savedStates[s]&&(delete e.savedStates[s],N(()=>{const i=e.els[b].querySelectorAll("[data-o-init]");for(const g of i){const p=g.getAttribute("data-o-init");t.inits[p]?.loseState(s)}}))},"sample"),e.sample=$((s="render")=>(L([[s,[l]]]),{[s]:J(e.els[u])}),"sample"),e.select=$(s=>{L([[s,[C,k]]]),s===E&&(s=e.length-o),v=s,u=s,e.el=e.els[s],y=o},"select"),e.all=$(()=>{v=e.length-o,u=0,e.el=e.els[0],y=0},"all"),e.remove=$(s=>{if(L([[s,[C,k]]]),s===E&&y&&(s=u),s!==E){const i=e.els[s];i?.parentNode?i.parentNode.removeChild(i):i===void 0&&s>=e.els.length&&t.onError&&t.onError("remove("+s+"): index out of bounds","remove")}else N(()=>{const i=e.els[b];i?.parentNode&&i.parentNode.removeChild(i)});P(!1)},"remove"),e.skip=$(s=>{L([[s,[C,k]]]),s===E&&(s=u),e.els.splice(b,o),P()},"skip"),e.add=$(s=>{L([[s,[S,a,C]]]),e.initID===E&&(O(s)==="string"&&s!==""?e.els.push(...Array.from(f.querySelectorAll(s))):O(s)===a?s.tagName?e.els.push(s):s.els?e.els.push(...s.els):s.length&&s[0].tagName&&e.els.push(...s):O(s)==="number"&&t.inits[s]&&(e=t.inits[s]),P(!1),e.initID!==E&&e.dataset({oInit:e.initID}))},"add"),e.appendInside=$(s=>{L([[s,[a,l]]]),s?.els&&(e._parent=s),N(()=>{M(s).appendChild(e.els[b])})},"appendInside"),e.appendBefore=$(s=>{L([[s,[a,l]]]),N(()=>{M(s).parentNode.insertBefore(e.els[b],M(s))})},"appendBefore"),e.appendAfter=$(s=>{L([[s,[a,l]]]),N(()=>{M(s).after(...e.els)})},"appendAfter"),e.find=$((s="")=>{L([[s,S]]);const i=[];return N(()=>{i.push(...Array.from(e.els[b].querySelectorAll(":scope "+s)))}),t(i)},"find"),e.first=$((s="")=>{L([[s,S]]);let i=E;const g=[];return N(()=>{i=e.els[b].querySelector(s),i&&g.push(i)}),t(g)},"first"),e.attr=$((s,i)=>{if(i!==null&&L([[s,S],[i,[S,k]]]),i===E){const g=[];return N(()=>{g[b]=e.els[b].getAttribute(s)}),y?g[0]:g}else N(i!==null?()=>{e.els[b].setAttribute(s,i)}:()=>{e.els[b].removeAttribute(s)})},"attr"),e.attrs=$(()=>{const s=[];return N(()=>{const i={};[...e.els[b].attributes].forEach(g=>{i[g.nodeName]=g.nodeValue}),s.push(i)}),y?s[0]:s},"attrs"),e.dataset=$(s=>{if(L([[s,[a,k]]]),typeof s===a)N(()=>{R(s,i=>{e.els[b].dataset[i]=s[i]})});else{const i=[];return N(()=>{i.push({...e.els[b].dataset})}),y?i[0]:i}},"dataset"),e.style=$(s=>{s!==null&&L([[s,[S,k]]]),e.attr("style",s)},"style"),e.css=$((s={})=>{if(s===null){e.style(null);return}L([[s,a]]);let i="";R(s,g=>{i+=g+":"+s[g].replace('"',"'")+";"}),e.style(i||null)},"css"),e.setClass=$(s=>{L([[s,S]]),N(()=>{e.els[b].setAttribute("class",s)})},"setClass"),e.addClass=$((...s)=>{N(()=>{e.els[b].classList.add(...s)})},"addClass"),e.removeClass=$((...s)=>{N(()=>{e.els[b].classList.remove(...s)})},"removeClass"),e.toggleClass=$((s,i)=>{L([[s,l],[i,[w,k]]]),N(()=>{e.els[b].classList.toggle(s,i)})},"toggleClass"),e.haveClass=s=>{L([[s,l]]);let i=!0;return N(()=>{e.els[b].classList.contains(s)||(i=!1)}),(e.isDebug||t.debug)&&console.log("haveClass() with",s),i},e.innerHTML=$(s=>{if(L([[s,[S,k]]]),s!==E)N(()=>{e.els[b].innerHTML=s});else{let i="";return N(()=>{i+=x&&e.els[b].innerHTML.length===0?t.D.parseElement(e.els[b],!1):e.els[b].innerHTML}),i}},"innerHTML"),e.innerText=$(s=>{L([[s,[S]]]),N(()=>{e.els[b].innerText=s})},"innerText"),e.textContent=$(s=>{L([[s,[S]]]),N(()=>{e.els[b].textContent=s})},"textContent"),e.html=$(s=>{if(L([[s,[S,k]]]),s!==void 0)e.innerHTML(s);else{let i="";return N(()=>{i+=x?e.els[b].outerHTML():e.els[b].outerHTML}),i}},"html"),e.val=$(s=>{if(s===void 0)return e.el?.value;N(()=>{e.els[b].value=s})},"val"),e.forEach=$(s=>{L([[s,[h]]]),N(()=>{s({self:e,i:b,o:t,el:e.els[b]})})},"forEach"),e.prepareFor=$((s,i)=>{L([[s,[a,h,k]],[i,[h,k]]]);const g=s&&O(s)===a&&s.createElement;if(!g&&O(s)!==h)throw Error("prepareFor(): pass React (full object) or React.createElement as first argument");const p=g?s.createElement:s,d=g?s.useEffect:void 0;return T=>{if(T.ref===E)throw Error("No ref property to convert Objs to React");const A=Object.assign({},T),B=p("div",{ref:T.ref});return delete A.ref,d(()=>{R(A,q=>{if(q.substring(0,1)==="on"){const z=t.camelToKebab(q).split("-")[1];e.on(z,A[q]),delete A[q]}}),e.render(A),e.appendInside(B.ref.current)},[]),B}},"prepareFor"),e.on=$((s,i,g,p)=>{L([[s,[l]],[i,[h]],[g,[a,k]],[p,[w,k]]]),s.split(", ").forEach(d=>{N(()=>{e.els[b].addEventListener(d,i,g,p)}),e.ie[d]||(e.ie[d]=[]),e.ie[d].push([i,g,p])})},"on"),e.off=$((s,i,g)=>{L([[s,[l]],[i,[h]],[g,[a,k]]]),s.split(", ").forEach(p=>{N(()=>{e.els[b].removeEventListener(p,i,g)}),e.ie[p]&&(e.ie[p]=e.ie[p].filter(d=>d[0]!==i))})},"off"),e.onDelegate=$((s,i,g)=>{L([[s,[l]],[i,[l]],[g,[h]]]),s.split(", ").forEach(p=>{const d=T=>{const A=T.target.closest(i);A&&(T.delegate=A,T.objs=e,g(T))};N(()=>{e.els[b].addEventListener(p,d)}),e.delegated[p]||(e.delegated[p]=[]),e.delegated[p].push(d)})},"onDelegate"),e.offDelegate=$(s=>{L([[s,[l]]]),R(e.delegated,i=>{if(!s||s===i)for(;e.delegated[i].length;){const g=e.delegated[i].pop();N(()=>{e.els[b].removeEventListener(i,g)})}}),e.delegated={}},"offDelegate"),e.onParent=$((s,i,g)=>{L([[s,[l]],[i,[l,a]],[g,[h]]]);const p=O(i)===a?i:t.D.querySelector(i);s.split(", ").forEach(d=>{const T=A=>{A.objs=e,g(A)};p.addEventListener(d,T),e.parented[d]||(e.parented[d]=[]),e.parented[d].push(T)})},"onParent"),e.offParent=$((s,i)=>{L([[s,[l]],[i,[l,a]]]);const g=O(i)===a?i:t.D.querySelector(i);R(e.parented,p=>{(!s||s===p)&&(e.parented[p].forEach(d=>{g.removeEventListener(p,d)}),delete e.parented[p])})},"offParent"),e.onAll=$((s,i)=>{L([[s,[l,k]],[i,[w,k]]]),R(e.ie,(g,p)=>{(!s||s===g)&&p[g].forEach(d=>{N(()=>{i?e.els[b].removeEventListener(g,d[0]):e.els[b].addEventListener(g,d[0],d[o],d[r])})})})},"onAll"),e.offAll=$(s=>{L([[s,[l]]]),e.onAll(s,o)},"offAll"),n&&e.add(n),e.take=s=>{if(L([[s,[S,a,C]]]),e.add(s),e.el){const i=e.el.dataset.oInit;if(i!==E&&t.inits[i])return e.length===o?(D=e.els[0],Object.assign(e,t.inits[i]),e.els=[D]):e=t.inits[i],P(!1,e.els),e}},e};t.first=n=>(t.verify([[n,["notEmptyString"]]]),t.debug&&console.log(n," -> ","o.first()"),t(t.D.querySelector(n)).select(0)),t.inits=[],t.getSaved={},t.errors=[],t.showErrors=!1,t.logErrors=()=>{t.errors.length?t.errors.forEach(n=>console.error(n)):console.log("No errors")},t.onError=(n,e)=>{t.showErrors?console.error(n,e):(t.errors.push(n),e&&t.errors.push(e))},t.reactRender=()=>new Error("React render function is not defined"),t.autotag=void 0,t.reactQA=n=>({["data-"+(t.autotag||"qa")]:n.replace(/([A-Z])/g,(e,o)=>"-"+o.toLowerCase()).replace(/^-/,"")}),t.specialTypes={notEmptyString:(n,e)=>e==="string"&&n.length,array:n=>Array.isArray(n),promise:n=>n instanceof Promise||!!(n&&typeof n.then=="function")},t.verify=(n,e=!1)=>{for(const o of n){const r=typeof o[0];let c=Array.isArray(o[1])?o[1]:[o[1]],w=!1;if(c.includes(r))return!0;c=c.filter(a=>!!t.specialTypes[a]);for(const a of c)if(w=t.specialTypes[a](o[0],r),w)return!0}return e?!1:new Error("Type verification failed")},t.safeVerify=n=>t.verify(n,!0),t.init=(n,e)=>t().init(n,e),t.initState=(n,e)=>t().init(n).render(e),t.take=n=>t().take(n),t.getStates=()=>t.inits.reduce((n,e)=>(n.push(e?.states),n),[]),t.getStores=()=>t.inits.reduce((n,e)=>(n.push(e?.store),n),[]),t.getListeners=()=>t.inits.reduce((n,e)=>(n.push(e?.ie),n),[]),t.createStore=n=>{const e=Object.assign({},n);return e._defaults=Object.assign({},n),e._listeners=[],e.subscribe=function(o,r){return this._listeners.push(c=>o[r]?.(c)),this},e.notify=function(){this._listeners.forEach(o=>o(this))},e.reset=function(){const o={_listeners:1,subscribe:1,notify:1,_defaults:1,reset:1};for(const r of Object.keys(this._defaults))o[r]||(this[r]=this._defaults[r])},e},t.U=void 0,t.W=2,t.H=100,t.F=!1,t.C=(n,e)=>Object.hasOwn(n,e),t.kebabToCamel=n=>n.replace(/-./g,e=>e.toUpperCase()[1]),t.camelToKebab=n=>n.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase(),t.route=(n,e)=>{t.verify([[n,["notEmptyString","function","boolean"]],[e,["function","object"]]]);const o=typeof n=="function"?n(window.location.pathname):n;return o===!0||window.location.pathname===o?e?typeof e=="function"?(e(),!0):e:t:typeof e=="function"?!1:{}},t.router=(n={})=>{t.verify([[n,["object"]]]);for(const e in n)if(t.C(n,e)&&window.location.pathname===e)return typeof n[e]=="function"?(n[e](),!0):n[e];return!1},t.DocumentMVP={addEventListener:()=>{},parseElement:(n,e=!0)=>{t.verify([[n,["object","string"]],[e,["boolean"]]]);const o=(r,c="")=>{let w="";for(const a in r)t.C(r,a)&&(w+=` ${c}${t.camelToKebab(a)}="${typeof r[a]!="object"?r[a]:Object.entries(r[a]).map(h=>`${h[0]}: ${h[1]};`).join(" ")}"`);return w};if(typeof n=="string")return n;if(e){const r=["area","base","br","col","embed","hr","img","input","link","meta","param","source","track","wbr"],c=n.tagName.toLowerCase(),w=n.attributes["data-o-init"],a=w!==void 0?` data-o-init="${w}"`:"";return`<${c}${n.className?` class="${n.className}"`:""}${o(n.attributes)}${a}${o(n.dataset,"data-")}${r.includes(c)?"/":""}>${r.includes(c)?"":n.innerHTML.length?n.innerHTML:n.children.map(h=>t.D.parseElement(h)).join("")}${r.includes(c)?"":`</${c}>`}`}return n.innerHTML.length?n.innerHTML:n.children.map(r=>t.D.parseElement(r)).join("")},createElement:n=>{t.verify([[n,["notEmptyString"]]]);const e={tagName:n.toUpperCase(),attributes:{},innerHTML:"",children:[],dataset:{},className:"",classArray:[],style:{},addEventListener:()=>{},removeEventListener:()=>{}};return e.classList={add:(...o)=>{t.verify([[o,["array"]]]),e.classArray.push(o),e.className=e.classArray.join(" ")},has:o=>(t.verify([[o,["notEmptyString"]]]),e.classArray.includes(o)),remove:o=>{t.verify([[o,["notEmptyString"]]]),e.classArray=e.classArray.filter(r=>o!==r),e.className=e.classArray.join(" ")}},e.classList.toggle=o=>{t.verify([[o,["notEmptyString"]]]),e.classList.has(o)?e.classList.remove(o):e.classList.add(o)},e.setAttribute=(o,r)=>{t.verify([[o,["notEmptyString"]],[r,["string","number","boolean","undefined"]]]),e.attributes[o]=r},e.getAttribute=o=>(t.verify([[o,["notEmptyString"]]]),e.attributes[o]),e.removeAttribute=o=>{t.verify([[o,["notEmptyString"]]]),delete e.attributes[o]},e.appendChild=o=>{t.verify([[o,["object"]]]),e.children.push(o),e.firstElementChild=e.children[0]},e.outerHTML=()=>t.D.parseElement(e),e}},t.D=typeof document<"u"&&typeof process>"u"?document:t.DocumentMVP,t.setCookie=(n,e="",o={})=>{if(t.verify([[n,["notEmptyString"]],[e,["string","number","boolean"]],[o,["object"]]]),t.D.cookie===void 0){console.log("Cookies are not supported on server side");return}let r=encodeURIComponent(n)+"="+encodeURIComponent(e);o={path:"/",...o},o.expires instanceof Date?o.expires=o.expires.toUTCString():typeof o.expires=="number"&&(o.expires=new Date(o.expires).toUTCString());for(const c in o){r+="; "+c;const w=o[c];w!==!0&&(r+="="+w)}t.D.cookie=r},t.getCookie=n=>{if(t.verify([[n,["notEmptyString"]]]),t.D.cookie===void 0){console.log("Cookies are not supported on server side");return}const e=t.D.cookie.match(RegExp("(?:^|; )"+n.replace(/([.$?*|{}()[\]\\/+^])/g,"\\$1")+"=([^;]*)"));return e?decodeURIComponent(e[1]):void 0},t.deleteCookie=n=>{t.verify([[n,["notEmptyString"]]]),t.setCookie(n,"",{"max-age":0})},t.clearCookies=()=>{if(t.D.cookie===void 0){console.log("Cookies are not supported on server side");return}const n=t.D.cookie.split(";");for(;n.length;){let e=n.pop();for(;e.charAt(0)===" ";)e=e.substring(1);const o=e.split("=")[0];t.deleteCookie(o)}},t.clearLocalStorage=n=>{if(t.verify([[n,["boolean","undefined"]]]),!(typeof localStorage>"u"))if(n)localStorage.clear();else for(let e=localStorage.length-1;e>=0;e--){const o=localStorage.key(e);o.indexOf("oInc-")===-1&&o.indexOf("oTest-")===-1&&localStorage.removeItem(o)}},t.clearSessionStorage=n=>{if(t.verify([[n,["boolean","undefined"]]]),!(typeof sessionStorage>"u"))if(!n)sessionStorage.clear();else for(let e=sessionStorage.length-1;e>=0;e--){const o=sessionStorage.key(e);o&&o.indexOf("oTest-")===0&&sessionStorage.removeItem(o)}},t.clearTestsStorage=()=>{t.clearSessionStorage(1)},t.clearAfterTests=()=>{t.clearCookies(),t.clearLocalStorage(!1),t.clearTestsStorage()},t.ajax=(n,e={})=>{t.verify([[n,["notEmptyString"]],[e,["object"]]]);const o=new URLSearchParams;if(e.data&&typeof e.data=="object"){for(const r in e.data)t.C(e.data,r)&&(typeof e.data[r]=="object"?o.set(r,encodeURIComponent(JSON.stringify(e.data[r]))):o.set(r,e.data[r]));e.method.toLowerCase()==="get"?n+="?"+o.toString():e.body||(e.body=o),delete e.data}return e.headers||(e.headers={"X-Requested-With":"XMLHttpRequest"}),fetch(n,e)},t.get=(n,e={})=>(t.verify([[n,["notEmptyString"]],[e,["object"]]]),t.ajax(n,{...e,method:"GET"})),t.post=(n,e={})=>(t.verify([[n,["notEmptyString"]],[e,["object"]]]),t.ajax(n,{...e,method:"POST"})),t.newLoader=n=>{t.verify([[n,["promise","undefined"]]]);let e=[],o=null,r=!1,c=!1;const w=a=>{r=!1,c=!1,o=null,setTimeout(()=>{a.then(h=>{r=!0,!h.ok&&typeof h.ok<"u"?(c=!0,e.forEach(([S,C,l])=>{l&&S[l](h)})):typeof h.json=="function"?h.json().then(S=>{o=S,e.forEach(([C,l])=>{C[l](o)})}):(o=h,e.forEach(([S,C])=>{S[C](o)}))}).catch(h=>{c=!0,e.forEach(([S,C,l])=>{l&&S[l](h)})})},33)};return n&&w(n),{reload:w,isObjsLoader:!0,listeners:e,isFinished:()=>r,getStore:()=>o,connect:(a,h="render",S)=>{t.verify([[a,["object"]],[h,["notEmptyString"]],[S,["string","undefined"]]]),r?c?S&&a[S]():typeof a[h]=="function"&&a[h](o):e.push([a,h,S])},disconnect:a=>{t.verify([[a,["object"]]]),e=e.filter(([h])=>h!==a)}}},t.getParams=n=>{t.verify([[n,["string","undefined"]]]);const e={},o=new URLSearchParams(window.location.search).entries();for(const r of o)e[r[0]]=r[1];return n?e[n]:e},t.incCache=!0,t.incCacheExp=1e3*60*60*24,t.incTimeout=6e3,t.incSource="",t.incForce=t.F,t.incAsync=!0,t.incCors=t.F,t.incSeparator="?",t.incFns={},t.incSet=[0],t.incReady=[0],t.incN=0,t.incGetHash=n=>n.split(t.incSeparator)[1]||"",t.incCheck=(n=0,e,o=0)=>(t.verify([[n,["number"]],[e,["number","undefined"]],[o,["number"]]]),!o&&n&&e===t.U&&t.incReady[n]?t.incSet[n]===1:t.incReady[n]===t.U||t.incReady[n][e]===t.U?t.F:(t.incReady[n][e].loaded=o,t.incFns[t.incReady[n][e].name]=o,t.incReady[n][0]+=o,n&&t.incReady[n].length===t.incReady[n][0]&&(typeof t.incSet[n]=="function"&&t.incSet[n](n),t.incSet[n]=1),t.incSet[n]===1)),t.incCacheClear=(n=t.F)=>{t.verify([[n,["boolean"]]]);for(const e in t.incFns)t.C(t.incFns,e)&&(localStorage.removeItem("oInc-"+e),localStorage.removeItem("oInc-"+e+"-expires"));return n&&(t.incReady.forEach((e,o)=>{o&&e.forEach((r,c)=>{c&&t("#oInc-"+o+"-"+c).remove()})}),t.incN=0,t.incFns={},t.incSet=[0],t.incReady=[0]),!0},t.inc=(n,e,o)=>{if(t.verify([[n,["object","undefined"]],[e,["function","undefined"]],[o,["function","undefined"]]]),typeof localStorage>"u")return;let r=0,c=0,w="",a=!1;const h="function",S=-1;if(typeof n!="object"||!n)return t.incSet[0];t.incSet[0]++;const C=t.incSet[0];t.incSet[C]=e||0,t.incReady[C]=[];const l=t.incReady[C];l[0]=1;const k={};for(const m in n)if(t.C(n,m)){if(m==="preload"){a=!0;continue}w=t.incGetHash(n[m]),r++,t.incN++;const E=n[m].indexOf(".css")>S?"style":"script";if(n[m]=(t.incSource?t.incSource+"/":"")+n[m],Number.isNaN(Number(m))&&t.C(t.incFns,m)&&t.incFns[m]&&!t.incForce){l[r]={name:m,loaded:1},c++;continue}if(l[r]={name:m,loaded:0},Number.isNaN(Number(m))&&(t.incFns[m]=0),Number.isNaN(Number(m))&&t.incCache&&(n[m].substring(0,4)!=="http"||!t.incCors)&&window.location.protocol!=="file:"&&(n[m].indexOf(".css")>S||n[m].indexOf(".js")>S)){const f=localStorage,v=f.getItem("oInc-"+m),u=f.getItem("oInc-"+m+"-expires"),y=f.getItem("oInc-"+m+"-hash");v&&u&&Date.now()<u&&y===w?(a||t.initState({tag:E,id:"oInc-"+C+"-"+r,innerHTML:v,"data-o-inc":C}).appendInside("head"),l[r].loaded=1,t.incFns[m]=1,c++):(k[m]=r,t.get(n[m],{mode:t.incCors?"cors":"same-origin"}).then(x=>{if(x.status!==200){t.onError&&t.onError({message:t.incSource+n[m]+" was not loaded"});return}x.text().then(b=>{f.setItem("oInc-"+m,b),f.setItem("oInc-"+m+"-expires",Date.now()+t.incCacheExp),f.setItem("oInc-"+m+"-hash",w),a||t.initState({tag:E,id:"oInc-"+C+"-"+k[m],innerHTML:b,"data-o-inc":C}).appendInside("head"),t.incCheck(C,k[m],1)})}))}else{const f={tag:E,id:"oInc-"+C+"-"+r,"data-o-inc":C,async:t.incAsync,onload:"o.incCheck("+C+","+r+",1)"};n[m].indexOf(".css")>S?(f.tag="link",f.rel="stylesheet",f.href=n[m]):(n[m].indexOf(".js")>S||(f.tag="img",f.style="display:none;"),f.src=n[m]),t.initState(f).appendInside(f.style?"body":"head")}}return l[0]+=c,r!==0&&(c===r?typeof e===h&&e(C):setTimeout(m=>{t.incReady[m]&&t.incReady[m].length<t.incReady[m][0]&&(t.incSet[m]=0,typeof o===h&&o(C))},t.incTimeout,C)),t.incSet[0]},t.connectRedux=(n,e,o,r="render")=>{t.verify([[n,["object"]],[e,["function"]],[o,["object"]],[r,["notEmptyString"]]]);const c=()=>{if(typeof o[r]=="function"){const w=e(n.getState());o[r](w!==null&&typeof w=="object"?w:{value:w})}};return c(),n.subscribe(c)},t.connectMobX=(n,e,o,r,c="render")=>(t.verify([[n,["object"]],[e,["object"]],[o,["function"]],[r,["object"]],[c,["notEmptyString"]]]),n.autorun(()=>{if(typeof r[c]=="function"){const w=o(e);r[c](w!==null&&typeof w=="object"?w:{value:w})}})),t.ObjsContext=null,t.withReactContext=(n,e,o,r,c="render")=>function(){const a=n.useContext(e);return n.useEffect(()=>{if(typeof r[c]=="function"){const h=o(a);r[c](h!==null&&typeof h=="object"?h:{value:h})}},[a]),null},t.debug=!1,t.tLog=[],t.tRes=[],t.tStatus=[],t.tFns=[],t.tShowOk=t.F,t.tStyled=t.F,t.tTime=2e3,t.tests=[],t.tAutolog=t.F,t.tBeforeEach=void 0,t.tAfterEach=void 0,t.addTest=(n,...e)=>{t.verify([[n,["notEmptyString"]],[e,["array"]]]);let o={};e.length&&typeof e[e.length-1]=="object"&&!Array.isArray(e[e.length-1])&&(o=e.pop());const r=t.tests.length;return t.tests[r]={title:n,tests:e,hooks:o},{run:()=>{typeof o.before=="function"&&(t.tBeforeEach=o.before),typeof o.after=="function"&&(t.tAfterEach=o.after),t.runTest(r)},autorun:()=>{typeof o.before=="function"&&(t.tBeforeEach=o.before),typeof o.after=="function"&&(t.tAfterEach=o.after),t.runTest(r,!0)},testId:r}},t.updateLogs=()=>{for(let n=0;n<t.tests.length;n++)t.tLog[n]=t.tLog[testN]=sessionStorage.getItem(`oTest-Log-${testN}`)||"";return t.tLog},t.runTest=(n=0,e,o)=>{if(t.verify([[n,["number"]],[e,["boolean","undefined"]],[o,["boolean","undefined"]]]),!t.tests[n])return;o||(sessionStorage?.removeItem(`oTest-Log-${n}`),sessionStorage?.removeItem(`oTest-Res-${n}`),sessionStorage?.removeItem(`oTest-Status-${n}`)),sessionStorage?.setItem("oTest-Run",n),e?sessionStorage?.setItem("oTest-Autorun",e):sessionStorage?.removeItem("oTest-Autorun");const r=t.tests[n];let c=r.tests.pop();typeof c!="function"&&(r.tests.push(c),c=()=>{}),r.tests.push(w=>{c(w),sessionStorage.setItem("dddd",1),sessionStorage?.removeItem("oTest-Run"),e&&t.runTest(n+1,e)}),t.test(r.title,...r.tests)},t.tPre='<div style="font-family:monospace;text-align:left;">',t.tOk='<span style="background:#cfc;padding: 0 15px;">OK</span> ',t.tXx='<div style="background:#fcc;padding:3px;">',t.tDc="</div>",t.test=(n="",...e)=>{t.verify([[n,["notEmptyString"]],[e,["array"]]]);const o=sessionStorage?.getItem("oTest-Run"),r=o||t.tLog.length;let c=0,w="\u251C OK: ",a="\u251C \u2718 ",h=`
7
7
  `,S=`
8
- `,N="",l=e.length,E=0;const m=(k="",f=!1,v=!1)=>{t.tAutolog&&(f?console.error(k):(t.tShowOk||v)&&console.log(k))};if(typeof e[l-1]=="function"&&(t.tFns[r]=e[l-1],l--),o){t.tLog[r]=sessionStorage.getItem(`oTest-Log-${r}`)||"",t.tRes[r]=sessionStorage.getItem(`oTest-Res-${r}`)||!1,t.tStatus[r]=JSON.parse(sessionStorage.getItem(`oTest-Status-${r}`)||"[]");for(let k=0;k<t.tStatus[r].length;k++)t.tStatus[r]&&E++}t.tStyled&&(w=t.tPre+t.tOk,a=t.tPre+t.tXx,b=t.tDc,S=b+b),(!o||t.tLog[r].length===0)&&(m("\u2552 "+n+" #"+r,!1,!0),t.tStyled?t.tLog[r]="<div><b>"+n+" #"+r+"</b></div>":t.tLog[r]="\u2552 "+n+" #"+r+`
9
- `,t.tRes[r]=t.F,t.tStatus[r]=[]);for(let k=t.tStatus[r].length;k<l;k++){const f={n:r,i:k,title:e[k][0],tShowOk:t.tShowOk,tStyled:t.tStyled};let v=e[k][1];if(typeof v>"u"){t.tStyled?t.tLog[r]+="<div>"+f.title+"</div>":t.tLog[r]+=f.title+`
10
- `,m("\u251C "+f.title,!1,!0),t.tStatus[r][k]=!0,E++;continue}if(typeof t.tBeforeEach=="function"&&t.tBeforeEach(f),typeof v=="function")try{v=v(f)}catch(u){v=u.message,t.onError&&t.onError(u)}if(typeof t.tAfterEach=="function"&&t.tAfterEach(f,v),v&&typeof v.then=="function"){c++;const u=setTimeout(()=>{f.title+=" (timeout)",t.testUpdate(f)},t.tTime);v.then(h=>{clearTimeout(u);const x=h===!0||h&&h.ok===!0,y=h&&h.errors&&h.errors.length?h.errors.join("; "):typeof h=="string"?h:"";t.testUpdate(f,x,x?"":y?": "+y:"")}).catch(h=>{clearTimeout(u),t.testUpdate(f,!1,h.message||"Promise rejected")});continue}if(typeof t.tStatus[r][k]>"u")t.tStatus[r][k]=typeof v=="string"?t.F:v;else{sessionStorage.setItem(`oTest-Status-${r}`,JSON.stringify(t.tStatus[r]));return}v===!0?(E++,t.tShowOk&&(t.tLog[r]+=w+e[k][0]+b,m("\u251C OK: "+e[k][0]))):v!==t.U?(t.tLog[r]+=a+e[k][0]+(v!==t.F?": "+v:"")+S,m("\u251C \u2718 "+e[k][0]+(v!==t.F?": "+v:""),!0)):(c++,setTimeout(u=>{u.title+=" (timeout)",t.testUpdate(u)},t.tTime,f))}return t.tRes[r]=E===l,N=c?"\u251C ":"\u2558 ",N+="DONE "+E+"/"+l+(c?", waiting: "+c:""),m(N,E+c!==l),c||m(),t.tStyled?t.tLog[r]+=t.tPre+'<div style="color:'+(E+c!==l?"red":"green")+';"><b>DONE '+E+"/"+l+(c?", waiting: "+c:"")+"</b>"+t.tDc+t.tDc:t.tLog[r]+=N+`
11
- `,o&&(sessionStorage.setItem(`oTest-Log-${r}`,t.tLog[r]),sessionStorage.setItem(`oTest-Res-${r}`,t.tRes[r]),sessionStorage.setItem(`oTest-Status-${r}`,JSON.stringify(t.tStatus[r]))),!c&&typeof t.tFns[r]=="function"&&t.tFns[r](r),r},t.testUpdate=(n,e=t.F,o="")=>{t.verify([[n,["object"]],[e,["boolean","string"]],[o,["string"]]]);let r="";const c=n.n,w=(a="",b=!1)=>{t.tAutolog&&(b?console.error(a):console.log(a))};if(t.tStatus[c][n.i]===t.U){t.tStatus[c][n.i]=e===!0,e===!0?n.tShowOk&&(r="\u251C OK: "+n.title+o,w(r),n.tStyled?t.tLog[c]+=t.tPre+t.tOk+n.title+o+t.tDc:t.tLog[c]+=r+`
8
+ `,C="",l=e.length,k=0;const m=(E="",f=!1,v=!1)=>{t.tAutolog&&(f?console.error(E):(t.tShowOk||v)&&console.log(E))};if(typeof e[l-1]=="function"&&(t.tFns[r]=e[l-1],l--),o){t.tLog[r]=sessionStorage.getItem(`oTest-Log-${r}`)||"",t.tRes[r]=sessionStorage.getItem(`oTest-Res-${r}`)||!1,t.tStatus[r]=JSON.parse(sessionStorage.getItem(`oTest-Status-${r}`)||"[]");for(let E=0;E<t.tStatus[r].length;E++){const f=t.tStatus[r][E];(f===!0||f===!1)&&k++}}t.tStyled&&(w=t.tPre+t.tOk,a=t.tPre+t.tXx,h=t.tDc,S=h+h),(!o||t.tLog[r].length===0)&&(m("\u2552 "+n+" #"+r,!1,!0),t.tStyled?t.tLog[r]="<div><b>"+n+" #"+r+"</b></div>":t.tLog[r]="\u2552 "+n+" #"+r+`
9
+ `,t.tRes[r]=t.F,t.tStatus[r]=[]);for(let E=t.tStatus[r].length;E<l;E++){const f={n:r,i:E,title:e[E][0],tShowOk:t.tShowOk,tStyled:t.tStyled};let v=e[E][1];if(typeof v>"u"){t.tStyled?t.tLog[r]+="<div>"+f.title+"</div>":t.tLog[r]+=f.title+`
10
+ `,m("\u251C "+f.title,!1,!0),t.tStatus[r][E]=!0,k++;continue}if(typeof t.tBeforeEach=="function"&&t.tBeforeEach(f),typeof v=="function")try{v=v(f)}catch(u){v=u.message,t.onError&&t.onError(u)}if(typeof t.tAfterEach=="function"&&t.tAfterEach(f,v),v&&typeof v.then=="function"){c++;const u=setTimeout(()=>{f.title+=" (timeout)",t.testUpdate(f)},t.tTime);v.then(y=>{clearTimeout(u);const x=y===!0||y&&y.ok===!0,b=y&&y.errors&&y.errors.length?y.errors.join("; "):typeof y=="string"?y:"";t.testUpdate(f,x,x?"":b?": "+b:"")}).catch(y=>{clearTimeout(u),t.testUpdate(f,!1,y.message||"Promise rejected")});continue}if(typeof t.tStatus[r][E]>"u")t.tStatus[r][E]=typeof v=="string"?t.F:v;else{sessionStorage.setItem(`oTest-Status-${r}`,JSON.stringify(t.tStatus[r]));return}v===!0?(k++,t.tShowOk&&(t.tLog[r]+=w+e[E][0]+h,m("\u251C OK: "+e[E][0]))):v!==t.U?(t.tLog[r]+=a+e[E][0]+(v!==t.F?": "+v:"")+S,m("\u251C \u2718 "+e[E][0]+(v!==t.F?": "+v:""),!0)):(c++,setTimeout(u=>{u.title+=" (timeout)",t.testUpdate(u)},t.tTime,f))}return t.tRes[r]=k===l,C=c?"\u251C ":"\u2558 ",C+="DONE "+k+"/"+l+(c?", waiting: "+c:""),m(C,k+c!==l),c||m(),t.tStyled?t.tLog[r]+=t.tPre+'<div style="color:'+(k+c!==l?"red":"green")+';"><b>DONE '+k+"/"+l+(c?", waiting: "+c:"")+"</b>"+t.tDc+t.tDc:t.tLog[r]+=C+`
11
+ `,o&&(sessionStorage.setItem(`oTest-Log-${r}`,t.tLog[r]),sessionStorage.setItem(`oTest-Res-${r}`,t.tRes[r]),sessionStorage.setItem(`oTest-Status-${r}`,JSON.stringify(t.tStatus[r]))),!c&&typeof t.tFns[r]=="function"&&t.tFns[r](r),r},t.testUpdate=(n,e=t.F,o="")=>{t.verify([[n,["object"]],[e,["boolean","string"]],[o,["string"]]]);let r="";const c=n.n,w=(a="",h=!1)=>{t.tAutolog&&(h?console.error(a):console.log(a))};if(t.tStatus[c][n.i]===t.U||t.tStatus[c][n.i]===null){t.tStatus[c][n.i]=e===!0,e===!0?n.tShowOk&&(r="\u251C OK: "+n.title+o,w(r),n.tStyled?t.tLog[c]+=t.tPre+t.tOk+n.title+o+t.tDc:t.tLog[c]+=r+`
12
12
  `):(t.tRes[c]=t.F,r="\u251C \u2718 "+n.title+(e?": "+e:"")+o,w(r,!0),n.tStyled?t.tLog[c]+=t.tPre+t.tXx+n.title+o+(e?": "+e:"")+t.tDc+t.tDc:t.tLog[c]+=r+`
13
- `);let a=0,b=0;for(const S of t.tStatus[c]){if(S===t.U)return;S||a++,b++}if(sessionStorage?.getItem("oTest-Run")===c&&(sessionStorage.setItem(`oTest-Log-${c}`,t.tLog[c]),sessionStorage.setItem(`oTest-Res-${c}`,t.tRes[c]),sessionStorage.setItem(`oTest-Status-${c}`,JSON.stringify(t.tStatus[c])),b<t.tests[c].tests.length))return;t.tRes[c]=!a,r=a?"FAILED "+a+"/"+b:"DONE "+b+"/"+b,w("\u2558 "+r,!!a),w(),n.tStyled?t.tLog[c]+=t.tPre+'<b style="color:'+(a?"red":"green")+';">'+r+"</b>"+t.tDc:t.tLog[c]+="\u2558 "+r+`
14
- `,typeof t.tFns[c]=="function"&&t.tFns[c](c)}},sessionStorage?.getItem("oTest-Run")&&window?.addEventListener("load",()=>{t.runTest(sessionStorage?.getItem("oTest-Run"),sessionStorage?.getItem("oTest-Autorun")||t.F,!0)},!1),t.measure=n=>{if(!n)return{};const e=n.getBoundingClientRect(),o=window.getComputedStyle(n);return{width:e.width,height:e.height,top:e.top,left:e.left,visible:o.display!=="none"&&o.visibility!=="hidden"&&e.width>0,opacity:o.opacity,zIndex:o.zIndex}},t.assertVisible=n=>!!t.measure(n).visible,t.assertSize=(n,e={})=>{if(!n)return"element is null";const o=t.measure(n);if(e.w!==void 0&&Math.round(o.width)!==e.w)return`width: expected ${e.w}, got ${Math.round(o.width)}`;if(e.h!==void 0&&Math.round(o.height)!==e.h)return`height: expected ${e.h}, got ${Math.round(o.height)}`;const r=c=>{const w=window.getComputedStyle(n).getPropertyValue(c);return w?parseFloat(w):0};return e.padding!==void 0&&r("padding-top")!==e.padding?`padding: expected ${e.padding}, got ${r("padding-top")}`:e.paddingTop!==void 0&&r("padding-top")!==e.paddingTop?`paddingTop: expected ${e.paddingTop}, got ${r("padding-top")}`:e.paddingRight!==void 0&&r("padding-right")!==e.paddingRight?`paddingRight: expected ${e.paddingRight}, got ${r("padding-right")}`:e.paddingBottom!==void 0&&r("padding-bottom")!==e.paddingBottom?`paddingBottom: expected ${e.paddingBottom}, got ${r("padding-bottom")}`:e.paddingLeft!==void 0&&r("padding-left")!==e.paddingLeft?`paddingLeft: expected ${e.paddingLeft}, got ${r("padding-left")}`:e.margin!==void 0&&r("margin-top")!==e.margin?`margin: expected ${e.margin}, got ${r("margin-top")}`:e.marginTop!==void 0&&r("margin-top")!==e.marginTop?`marginTop: expected ${e.marginTop}, got ${r("margin-top")}`:e.marginRight!==void 0&&r("margin-right")!==e.marginRight?`marginRight: expected ${e.marginRight}, got ${r("margin-right")}`:e.marginBottom!==void 0&&r("margin-bottom")!==e.marginBottom?`marginBottom: expected ${e.marginBottom}, got ${r("margin-bottom")}`:e.marginLeft!==void 0&&r("margin-left")!==e.marginLeft?`marginLeft: expected ${e.marginLeft}, got ${r("margin-left")}`:!0},t.recorder={active:!1,actions:[],mocks:{},initialData:{},assertions:[],observeRoot:null,_originalFetch:null,_listeners:[],_observer:null},t.startRecording=(n,e,o)=>{if(t.recorder.active)return;const r=["click","mouseover","scroll","input","change"],c={click:100,mouseover:50,scroll:30,input:50,change:50},w=e||r,a=Object.assign({},c,o||{}),b={scroll:30,mouseover:50},S=t.recorder;S.active=!0,S.actions=[],S.mocks={},S.stepDelays=a,S.initialData={url:window.location.href,timestamp:Date.now()},S.observeRoot=n||null,S.assertions=[],t.inits.forEach((f,v)=>{f?.store&&(S.initialData["init_"+v]=JSON.parse(JSON.stringify(f.store)))}),S._originalFetch=window.fetch,window.fetch=async(f,v={})=>{const u=(v.method||"GET").toUpperCase();let h;try{h=v.body?JSON.parse(v.body):void 0}catch{h=v.body}const x=await S._originalFetch(f,v),y=x.clone();let D;try{D=await y.json()}catch{D=await y.text().catch(()=>null)}const C=u+":"+f;return S.mocks[C]={url:f,method:u,request:h,response:D,status:x.status},x};const N={"data-o-init":1,"data-o-init-i":1,"data-o-state":1},l=(f,v)=>{if(t.D.querySelectorAll(f).length<=1)return f;let u=v;for(;u&&u!==t.D.body;){let h=u.id?"#"+u.id:null;if(!h&&u.attributes){const x=t.autotag?"data-"+t.autotag:null;if(x){const y=u.getAttribute(x);y!=null&&(h=`[${x}="${y}"]`)}if(!h){for(const y of u.attributes)if(y.name.startsWith("data-")&&!N[y.name]){h=`[${y.name}="${y.value}"]`;break}}}if(h){const x=h+" "+f;if(t.D.querySelectorAll(x).length===1)return x}u=u.parentElement}return f},E=f=>{if(!f||f.nodeType!==1)return"";let v="";if(f.dataset){const u=t.autotag&&f.dataset[t.autotag];u&&(v=l(`[data-${t.autotag}="${u}"]`,f.parentElement))}if(!v&&f.tagName){const u=f.id?"#"+f.id:f.className?f.tagName.toLowerCase()+"."+[...f.classList].join("."):f.tagName.toLowerCase();v=f.id?u:l(u,f.parentElement)}return v},m=n&&t.D.querySelector(n)||t.D.body;S._observer=new MutationObserver(f=>{const v=S.actions.length-1;v<0||f.forEach(u=>{const h=(x,y)=>{let D,C;if(x&&m&&m.querySelectorAll(x).length>1){let j=y;for(;j&&j!==m&&j.nodeType===1;){const L=t.autotag&&j.dataset&&j.dataset[t.autotag];if(L){const T=`[data-${t.autotag}="${L}"]`,O=m.querySelectorAll(T);if(O.length>1){const A=[...O].indexOf(j);if(A!==-1){D=T,C=A;break}}}j=j.parentElement}}return{listSelector:D,index:C}};if(u.type==="childList"&&u.addedNodes.forEach(x=>{if(x.nodeType!==1||!x.offsetParent)return;const y=E(x);if(!y||S.assertions.some(T=>T.actionIdx===v&&T.selector===y&&T.type==="visible"))return;const C=((x.querySelector?.(".task-text")||x).textContent?.trim()||x.textContent?.trim()||"").slice(0,80)||void 0,{listSelector:R,index:j}=h(y,x),L={actionIdx:v,type:"visible",selector:y,text:C};R!=null&&(L.listSelector=R),j!=null&&(L.index=j),S.assertions.push(L)}),u.type==="attributes"){const x=E(u.target);if(!x||S.assertions.some(R=>R.actionIdx===v&&R.selector===x&&R.type==="class"))return;const{listSelector:y,index:D}=h(x,u.target),C={actionIdx:v,type:"class",selector:x,className:u.target.className};y!=null&&(C.listSelector=y),D!=null&&(C.index=D),S.assertions.push(C)}})}),S._observer.observe(m,{childList:!0,subtree:!0,attributes:!0,attributeFilter:["class","style","hidden","disabled","aria-expanded","aria-checked"]});const k={};w.forEach(f=>{const v=u=>{const h=u.target;if(n&&m&&h?.nodeType===1&&!m.contains(h))return;let x="";if(h?.dataset){const A=t.autotag&&h.dataset[t.autotag];A&&(x=l(`[data-${t.autotag}="${A}"]`,h.parentElement))}if(!x&&h?.tagName){const A=h.id?"#"+h.id:h.className?h.tagName.toLowerCase()+"."+[...h.classList].join("."):h.tagName.toLowerCase();x=h.id?A:l(A,h.parentElement)}let y,D;if(x&&m&&m.querySelectorAll(x).length>1){let _=h;for(;_&&_!==m&&_.nodeType===1;){const H=t.autotag&&_.dataset&&_.dataset[t.autotag];if(H){const J=`[data-${t.autotag}="${H}"]`,s=m.querySelectorAll(J);if(s.length>1){const i=[...s].indexOf(_);if(i!==-1){y=J,D=i;break}}}_=_.parentElement}}const C=h?.tagName?h.tagName.toLowerCase()+(h.type?":"+h.type:""):void 0,R=f==="scroll"?window.scrollY:void 0,j=f==="input"||f==="change"?h?.value:void 0,L=f==="change"&&(h?.type==="checkbox"||h?.type==="radio")?h?.checked:void 0,T=a[f]!==void 0?a[f]:b[f]??0,O=()=>{const A={type:f,target:x,time:Date.now()};C&&(A.targetType=C),R!==void 0&&(A.scrollY=R),j!==void 0&&(A.value=j),L!==void 0&&(A.checked=L),y!=null&&(A.listSelector=y),D!=null&&(A.targetIndex=D),S.actions.push(A)};T===0?O():(clearTimeout(k[f]),k[f]=setTimeout(O,T))};t.D.addEventListener(f,v,!0),S._listeners.push({ev:f,handler:v})})},t.stopRecording=()=>{const n=t.recorder;return n.active=!1,n._originalFetch&&(window.fetch=n._originalFetch,n._originalFetch=null),n._listeners.forEach(({ev:e,handler:o})=>{t.D.removeEventListener(e,o,!0)}),n._listeners=[],n._observer&&(n._observer.disconnect(),n._observer=null),{actions:[...n.actions],mocks:{...n.mocks},initialData:{...n.initialData},stepDelays:{...n.stepDelays},assertions:[...n.assertions||[]],observeRoot:n.observeRoot||null}},t.clearRecording=n=>{if(n!==void 0)sessionStorage?.removeItem("oTest-Recording-"+n);else for(let e=sessionStorage?.length-1;e>=0;e--){const o=sessionStorage?.key(e);o&&o.indexOf("oTest-Recording-")===0&&sessionStorage?.removeItem(o)}},t.exportTest=n=>{const e=n.actions.map(r=>{let c;return r.type==="scroll"?c=` window.scrollTo(0, ${r.scrollY||0}); return true;
13
+ `);let a=0,h=0;for(const S of t.tStatus[c]){if(S===t.U||S===null)return;S||a++,h++}if(sessionStorage?.getItem("oTest-Run")===c&&(sessionStorage.setItem(`oTest-Log-${c}`,t.tLog[c]),sessionStorage.setItem(`oTest-Res-${c}`,t.tRes[c]),sessionStorage.setItem(`oTest-Status-${c}`,JSON.stringify(t.tStatus[c])),h<t.tests[c].tests.length))return;t.tRes[c]=!a,r=a?"FAILED "+a+"/"+h:"DONE "+h+"/"+h,w("\u2558 "+r,!!a),w(),n.tStyled?t.tLog[c]+=t.tPre+'<b style="color:'+(a?"red":"green")+';">'+r+"</b>"+t.tDc:t.tLog[c]+="\u2558 "+r+`
14
+ `,typeof t.tFns[c]=="function"&&t.tFns[c](c)}},sessionStorage?.getItem("oTest-Run")&&window?.addEventListener("load",()=>{t.runTest(sessionStorage?.getItem("oTest-Run"),sessionStorage?.getItem("oTest-Autorun")||t.F,!0)},!1),t.measure=n=>{if(!n)return{};const e=n.getBoundingClientRect(),o=window.getComputedStyle(n);return{width:e.width,height:e.height,top:e.top,left:e.left,visible:o.display!=="none"&&o.visibility!=="hidden"&&e.width>0,opacity:o.opacity,zIndex:o.zIndex}},t.assertVisible=n=>!!t.measure(n).visible,t.assertSize=(n,e={})=>{if(!n)return"element is null";const o=t.measure(n);if(e.w!==void 0&&Math.round(o.width)!==e.w)return`width: expected ${e.w}, got ${Math.round(o.width)}`;if(e.h!==void 0&&Math.round(o.height)!==e.h)return`height: expected ${e.h}, got ${Math.round(o.height)}`;const r=c=>{const w=window.getComputedStyle(n).getPropertyValue(c);return w?parseFloat(w):0};return e.padding!==void 0&&r("padding-top")!==e.padding?`padding: expected ${e.padding}, got ${r("padding-top")}`:e.paddingTop!==void 0&&r("padding-top")!==e.paddingTop?`paddingTop: expected ${e.paddingTop}, got ${r("padding-top")}`:e.paddingRight!==void 0&&r("padding-right")!==e.paddingRight?`paddingRight: expected ${e.paddingRight}, got ${r("padding-right")}`:e.paddingBottom!==void 0&&r("padding-bottom")!==e.paddingBottom?`paddingBottom: expected ${e.paddingBottom}, got ${r("padding-bottom")}`:e.paddingLeft!==void 0&&r("padding-left")!==e.paddingLeft?`paddingLeft: expected ${e.paddingLeft}, got ${r("padding-left")}`:e.margin!==void 0&&r("margin-top")!==e.margin?`margin: expected ${e.margin}, got ${r("margin-top")}`:e.marginTop!==void 0&&r("margin-top")!==e.marginTop?`marginTop: expected ${e.marginTop}, got ${r("margin-top")}`:e.marginRight!==void 0&&r("margin-right")!==e.marginRight?`marginRight: expected ${e.marginRight}, got ${r("margin-right")}`:e.marginBottom!==void 0&&r("margin-bottom")!==e.marginBottom?`marginBottom: expected ${e.marginBottom}, got ${r("margin-bottom")}`:e.marginLeft!==void 0&&r("margin-left")!==e.marginLeft?`marginLeft: expected ${e.marginLeft}, got ${r("margin-left")}`:!0},t.recorder={active:!1,actions:[],mocks:{},initialData:{},assertions:[],observeRoot:null,_originalFetch:null,_listeners:[],_observer:null},t.startRecording=(n,e,o)=>{if(t.recorder.active)return;const r=["click","mouseover","scroll","input","change"],c={click:100,mouseover:50,scroll:30,input:50,change:50},w=e||r,a=Object.assign({},c,o||{}),h={scroll:30,mouseover:50},S=t.recorder;S.active=!0,S.actions=[],S.mocks={},S.stepDelays=a,S.initialData={url:window.location.href,timestamp:Date.now()},S.observeRoot=n||null,S.assertions=[],t.inits.forEach((f,v)=>{f?.store&&(S.initialData["init_"+v]=JSON.parse(JSON.stringify(f.store)))}),S._originalFetch=window.fetch,window.fetch=async(f,v={})=>{const u=(v.method||"GET").toUpperCase();let y;try{y=v.body?JSON.parse(v.body):void 0}catch{y=v.body}const x=await S._originalFetch(f,v),b=x.clone();let D;try{D=await b.json()}catch{D=await b.text().catch(()=>null)}const I=u+":"+f;return S.mocks[I]={url:f,method:u,request:y,response:D,status:x.status},x};const C={"data-o-init":1,"data-o-init-i":1,"data-o-state":1},l=(f,v)=>{if(t.D.querySelectorAll(f).length<=1)return f;let u=v;for(;u&&u!==t.D.body;){let y=u.id?"#"+u.id:null;if(!y&&u.attributes){const x=t.autotag?"data-"+t.autotag:null;if(x){const b=u.getAttribute(x);b!=null&&(y=`[${x}="${b}"]`)}if(!y){for(const b of u.attributes)if(b.name.startsWith("data-")&&!C[b.name]){y=`[${b.name}="${b.value}"]`;break}}}if(y){const x=y+" "+f;if(t.D.querySelectorAll(x).length===1)return x}u=u.parentElement}return f},k=f=>{if(!f||f.nodeType!==1)return"";let v="";if(f.dataset){const u=t.autotag&&f.dataset[t.autotag];u&&(v=l(`[data-${t.autotag}="${u}"]`,f.parentElement))}if(!v&&f.tagName){const u=f.id?"#"+f.id:f.className?f.tagName.toLowerCase()+"."+[...f.classList].join("."):f.tagName.toLowerCase();v=f.id?u:l(u,f.parentElement)}return v},m=n&&t.D.querySelector(n)||t.D.body;S._observer=new MutationObserver(f=>{const v=S.actions.length-1;v<0||f.forEach(u=>{const y=(x,b)=>{let D,I;if(x&&m&&m.querySelectorAll(x).length>1){let R=b;for(;R&&R!==m&&R.nodeType===1;){const U=t.autotag&&R.dataset&&R.dataset[t.autotag];if(U){const L=`[data-${t.autotag}="${U}"]`,$=m.querySelectorAll(L);if($.length>1){const N=[...$].indexOf(R);if(N!==-1){D=L,I=N;break}}}R=R.parentElement}}return{listSelector:D,index:I}};if(u.type==="childList"&&u.addedNodes.forEach(x=>{if(x.nodeType!==1||!x.offsetParent)return;const b=k(x);if(!b||S.assertions.some(L=>L.actionIdx===v&&L.selector===b&&L.type==="visible"))return;const I=((x.querySelector?.(".task-text")||x).textContent?.trim()||x.textContent?.trim()||"").slice(0,80)||void 0,{listSelector:O,index:R}=y(b,x),U={actionIdx:v,type:"visible",selector:b,text:I};O!=null&&(U.listSelector=O),R!=null&&(U.index=R),S.assertions.push(U)}),u.type==="attributes"){const x=k(u.target);if(!x||S.assertions.some(O=>O.actionIdx===v&&O.selector===x&&O.type==="class"))return;const{listSelector:b,index:D}=y(x,u.target),I={actionIdx:v,type:"class",selector:x,className:u.target.className};b!=null&&(I.listSelector=b),D!=null&&(I.index=D),S.assertions.push(I)}})}),S._observer.observe(m,{childList:!0,subtree:!0,attributes:!0,attributeFilter:["class","style","hidden","disabled","aria-expanded","aria-checked"]});const E={};w.forEach(f=>{const v=u=>{const y=u.target;if(n&&m&&y?.nodeType===1&&!m.contains(y))return;let x="";if(y?.dataset){const N=t.autotag&&y.dataset[t.autotag];N&&(x=l(`[data-${t.autotag}="${N}"]`,y.parentElement))}if(!x&&y?.tagName){const N=y.id?"#"+y.id:y.className?y.tagName.toLowerCase()+"."+[...y.classList].join("."):y.tagName.toLowerCase();x=y.id?N:l(N,y.parentElement)}let b,D;if(x&&m&&m.querySelectorAll(x).length>1){let M=y;for(;M&&M!==m&&M.nodeType===1;){const P=t.autotag&&M.dataset&&M.dataset[t.autotag];if(P){const H=`[data-${t.autotag}="${P}"]`,J=m.querySelectorAll(H);if(J.length>1){const s=[...J].indexOf(M);if(s!==-1){b=H,D=s;break}}}M=M.parentElement}}const I=y?.tagName?y.tagName.toLowerCase()+(y.type?":"+y.type:""):void 0,O=f==="scroll"?window.scrollY:void 0,R=f==="input"||f==="change"?y?.value:void 0,U=f==="change"&&(y?.type==="checkbox"||y?.type==="radio")?y?.checked:void 0,L=a[f]!==void 0?a[f]:h[f]??0,$=()=>{const N={type:f,target:x,time:Date.now()};I&&(N.targetType=I),O!==void 0&&(N.scrollY=O),R!==void 0&&(N.value=R),U!==void 0&&(N.checked=U),b!=null&&(N.listSelector=b),D!=null&&(N.targetIndex=D),S.actions.push(N)};L===0?$():(clearTimeout(E[f]),E[f]=setTimeout($,L))};t.D.addEventListener(f,v,!0),S._listeners.push({ev:f,handler:v})})},t.stopRecording=()=>{const n=t.recorder;return n.active=!1,n._originalFetch&&(window.fetch=n._originalFetch,n._originalFetch=null),n._listeners.forEach(({ev:e,handler:o})=>{t.D.removeEventListener(e,o,!0)}),n._listeners=[],n._observer&&(n._observer.disconnect(),n._observer=null),{actions:[...n.actions],mocks:{...n.mocks},initialData:{...n.initialData},stepDelays:{...n.stepDelays},assertions:[...n.assertions||[]],observeRoot:n.observeRoot||null}},t.clearRecording=n=>{if(n!==void 0)sessionStorage?.removeItem("oTest-Recording-"+n);else for(let e=sessionStorage?.length-1;e>=0;e--){const o=sessionStorage?.key(e);o&&o.indexOf("oTest-Recording-")===0&&sessionStorage?.removeItem(o)}},t.exportTest=n=>{const e=n.actions.map(r=>{let c;return r.type==="scroll"?c=` window.scrollTo(0, ${r.scrollY||0}); return true;
15
15
  `:r.type==="input"||r.type==="change"?c=(r.value!==void 0?` el.value = ${JSON.stringify(r.value)};
16
16
  `:"")+(r.checked!==void 0?` el.checked = ${r.checked};
17
17
  `:"")+` el.dispatchEvent(new Event('${r.type}', {bubbles:true})); return true;
@@ -29,18 +29,18 @@ ${e}
29
29
  ], () => {
30
30
  // teardown
31
31
  });
32
- `},t.exportPlaywrightTest=(n,e={})=>{const o=e.testName||"Recorded session",r=n.initialData?.url??"/";let c="/";try{c=new URL(r).pathname||"/"}catch{c=r}const w=e.baseUrl||c,a=Object.values(n.mocks).map(l=>{const E=l.url.startsWith("/")?l.url:"/"+l.url,m=JSON.stringify(l.response);return` await page.route('**${E}', async route => {
32
+ `},t.exportPlaywrightTest=(n,e={})=>{const o=e.testName||"Recorded session",r=n.initialData?.url??"/";let c="/";try{c=new URL(r).pathname||"/"}catch{c=r}const w=e.baseUrl||c,a=Object.values(n.mocks).map(l=>{const k=l.url.startsWith("/")?l.url:"/"+l.url,m=JSON.stringify(l.response);return` await page.route('**${k}', async route => {
33
33
  await route.fulfill({ status: ${l.status||200}, contentType: 'application/json',
34
34
  body: JSON.stringify(${m}) });
35
35
  });`}).join(`
36
- `),b=Object.assign({click:100,mouseover:50,scroll:30,input:50,change:50},n.stepDelays||{}),S=n.actions.map((l,E)=>{const m=l.listSelector!=null&&l.targetIndex!=null?l.target!==l.listSelector?`page.locator(${JSON.stringify(l.listSelector)}).nth(${l.targetIndex}).locator(${JSON.stringify(l.target)})`:`page.locator(${JSON.stringify(l.listSelector)}).nth(${l.targetIndex})`:`page.locator(${JSON.stringify(l.target)})`,k=` await page.waitForTimeout(${b[l.type]||50});`;let f;if(l.type==="scroll")f=` await page.evaluate(() => window.scrollTo(0, ${l.scrollY||0}));`;else if(l.type==="mouseover")f=` await ${m}.hover();
36
+ `),h=Object.assign({click:100,mouseover:50,scroll:30,input:50,change:50},n.stepDelays||{}),S=n.actions.map((l,k)=>{const m=l.listSelector!=null&&l.targetIndex!=null?l.target!==l.listSelector?`page.locator(${JSON.stringify(l.listSelector)}).nth(${l.targetIndex}).locator(${JSON.stringify(l.target)})`:`page.locator(${JSON.stringify(l.listSelector)}).nth(${l.targetIndex})`:`page.locator(${JSON.stringify(l.target)})`,E=` await page.waitForTimeout(${h[l.type]||50});`;let f;if(l.type==="scroll")f=` await page.evaluate(() => window.scrollTo(0, ${l.scrollY||0}));`;else if(l.type==="mouseover")f=` await ${m}.hover();
37
37
  // Pure CSS :hover \u2014 no DOM mutation to assert.
38
- // Fix: toggle a class in a mouseover handler, or add a page.screenshot() visual check.`;else if(l.type==="input")f=` await ${m}.fill(${JSON.stringify(l.value||"")});`;else if(l.type==="change"){const u=l.targetType||"";if(u.indexOf(":checkbox")!==-1||u.indexOf(":radio")!==-1){const h=l.checked!==void 0?l.checked:l.value==="true"||l.value==="on";f=` await ${m}.${h?"check":"uncheck"}();`}else u.indexOf("select")!==-1?f=` await ${m}.selectOption(${JSON.stringify(l.value||"")});`:f=` await ${m}.fill(${JSON.stringify(l.value||"")});`}else f=` await ${m}.click();`;const v=(n.assertions||[]).filter(u=>u.actionIdx===E).filter((u,h,x)=>x.findIndex(y=>y.selector===u.selector&&y.type===u.type&&y.index===u.index)===h).map(u=>{const h=u.listSelector!=null&&u.index!=null?u.selector!==u.listSelector?`page.locator(${JSON.stringify(u.listSelector)}).nth(${u.index}).locator(${JSON.stringify(u.selector)})`:`page.locator(${JSON.stringify(u.listSelector)}).nth(${u.index})`:`page.locator(${JSON.stringify(u.selector)})`;if(u.type==="visible"){let x=` await expect(${h}).toBeVisible();`;return u.text&&(x+=`
39
- await expect(${h}).toContainText(${JSON.stringify(u.text)});`),x}return u.type==="class"?` // class on ${u.selector} changed to: "${u.className}"`:""}).filter(Boolean).join(`
38
+ // Fix: toggle a class in a mouseover handler, or add a page.screenshot() visual check.`;else if(l.type==="input")f=` await ${m}.fill(${JSON.stringify(l.value||"")});`;else if(l.type==="change"){const u=l.targetType||"";if(u.indexOf(":checkbox")!==-1||u.indexOf(":radio")!==-1){const y=l.checked!==void 0?l.checked:l.value==="true"||l.value==="on";f=` await ${m}.${y?"check":"uncheck"}();`}else u.indexOf("select")!==-1?f=` await ${m}.selectOption(${JSON.stringify(l.value||"")});`:f=` await ${m}.fill(${JSON.stringify(l.value||"")});`}else f=` await ${m}.click();`;const v=(n.assertions||[]).filter(u=>u.actionIdx===k).filter((u,y,x)=>x.findIndex(b=>b.selector===u.selector&&b.type===u.type&&b.index===u.index)===y).map(u=>{const y=u.listSelector!=null&&u.index!=null?u.selector!==u.listSelector?`page.locator(${JSON.stringify(u.listSelector)}).nth(${u.index}).locator(${JSON.stringify(u.selector)})`:`page.locator(${JSON.stringify(u.listSelector)}).nth(${u.index})`:`page.locator(${JSON.stringify(u.selector)})`;if(u.type==="visible"){let x=` await expect(${y}).toBeVisible();`;return u.text&&(x+=`
39
+ await expect(${y}).toContainText(${JSON.stringify(u.text)});`),x}return u.type==="class"?` // class on ${u.selector} changed to: "${u.className}"`:""}).filter(Boolean).join(`
40
40
  `);return f+`
41
- `+k+(v?`
41
+ `+E+(v?`
42
42
  `+v:"")}).join(`
43
- `),N=(n.assertions||[]).length>0;return`// Auto-generated by o.exportPlaywrightTest() \u2014 review and anonymize mocks before committing
43
+ `),C=(n.assertions||[]).length>0;return`// Auto-generated by o.exportPlaywrightTest() \u2014 review and anonymize mocks before committing
44
44
  // Prerequisites: npm install @playwright/test && npx playwright install chromium
45
45
  // Run: npx playwright test recorded.spec.ts
46
46
  import { test, expect } from '@playwright/test';
@@ -54,13 +54,13 @@ test(${JSON.stringify(o)}, async ({ page }) => {
54
54
 
55
55
  `+(S?S+`
56
56
 
57
- `:"")+(N?` // Auto-generated assertions above \u2014 review for correctness before committing
57
+ `:"")+(C?` // Auto-generated assertions above \u2014 review for correctness before committing
58
58
  `:` // TODO: Add assertions before committing, e.g.:
59
59
  // await expect(page.locator('[data-qa="success-panel"]')).toBeVisible();
60
60
  // await expect(page).toHaveURL(/\\/confirmation/);
61
61
  // await expect(page.locator('[data-qa="error-banner"]')).not.toBeVisible();
62
62
  `)+`});
63
- `},t.playRecording=(n,e={})=>{const o=Object.assign({},n.mocks,e),r=window.fetch;window.fetch=(a,b={})=>{const N=(b.method||"GET").toUpperCase()+":"+a;if(o[N]){const l=o[N],E=typeof l.response=="string"?l.response:JSON.stringify(l.response);return Promise.resolve(new Response(E,{status:l.status||200}))}return r(a,b)};const c=n.actions.map(a=>[`${a.type} on ${a.target}`,()=>{let b=null;if(a.target)if(a.listSelector!=null&&a.targetIndex!=null){const N=t.D.querySelectorAll(a.listSelector)[a.targetIndex];N&&(b=a.target!==a.listSelector?N.querySelector(a.target):N,!b&&a.target!==a.listSelector&&(b=N))}else b=t.D.querySelector(a.target);return!b&&a.type!=="scroll"?`element not found: ${a.target}`:(a.type==="scroll"?window.scrollTo(0,a.scrollY||0):a.type==="input"||a.type==="change"?(a.value!==void 0&&(b.value=a.value),a.checked!==void 0&&(b.checked=a.checked),b.dispatchEvent(new Event(a.type,{bubbles:!0}))):a.type==="click"?b.click():b.dispatchEvent(new MouseEvent(a.type,{bubbles:!0,cancelable:!0})),!0)}]);return t.test("Recorded playback",...c,()=>{window.fetch=r})},t.testOverlay=()=>{const n="o-test-overlay-btn",e="o-test-overlay-panel";if(t("#"+n).el)return;const o=()=>{const l=t("#"+e);if(!l.el)return;const E=t.tRes.length;let k=`<b>Tests: ${t.tRes.filter(Boolean).length}/${E}</b><hr style="margin:4px 0">`;t.tLog.forEach((f,v)=>{const u=t.tRes[v];k+=`<div style="margin:2px 0;padding:2px 4px;border-radius:3px;background:${u?"#d4edda":"#f8d7da"};color:${u?"#155724":"#721c24"};font-size:11px;white-space:pre-wrap">${f||"Test #"+v}</div>`}),k+='<button id="o-test-export" style="margin-top:6px;padding:4px 8px;font-size:11px;cursor:pointer">Export results</button>',l.html(k),t("#o-test-export").on("click",()=>{const f=JSON.stringify({results:t.tRes,logs:t.tLog},null,2),v=new Blob([f],{type:"application/json"}),u=t.D.createElement("a");u.href=URL.createObjectURL(v),u.download="objs-test-results.json",u.click()})},r={position:"fixed",left:"50%",bottom:"50px",transform:"translateX(-50%)","z-index":"999999",width:"fit-content","max-width":"min(90vw, 420px)","font-family":"system-ui,sans-serif",cursor:"grab","user-select":"text"},c=t.initState({tag:"div",id:n,className:"o-test-overlay",style:"position:fixed;left:50%;bottom:50px;transform:translateX(-50%);z-index:999999;width:fit-content;max-width:min(90vw,420px);font-family:system-ui,sans-serif;cursor:grab;user-select:text;",html:`<div class="o-test-overlay-bar" style="display:flex;flex-direction:column;align-items:stretch;padding:10px 14px;background:#1e293b;color:#e2e8f0;border:1px solid #334155;border-radius:8px;font-size:14px;cursor:grab;min-width:200px;"><div style="display:flex;align-items:center;gap:12px;"><span class="o-test-overlay-summary" style="flex:1;font-size:13px;">Tests: 0/0</span><button type="button" class="o-test-overlay-toggle" style="padding:6px 10px;background:#334155;color:#e2e8f0;border:none;border-radius:6px;cursor:pointer;font-size:12px;">List</button><button type="button" class="o-test-overlay-close" style="padding:4px 8px;background:transparent;color:#94a3b8;border:none;border-radius:4px;cursor:pointer;font-size:16px;line-height:1;" title="Close">\xD7</button></div></div><div id="${e}" style="display:none;margin-top:4px;padding:8px;background:#fff;border:1px solid #334155;border-radius:6px;max-height:60vh;overflow-y:auto;box-shadow:0 2px 8px rgba(0,0,0,.15);font-size:11px;user-select:text;cursor:text;"></div>`}).appendInside("body"),w=()=>{c.css(r)};let a=null;const b=l=>{a&&(r.left=a.left+(l.clientX-a.startX)+"px",r.top=a.top+(l.clientY-a.startY)+"px",delete r.bottom,r.transform="none",w())},S=()=>{a&&(r.cursor="grab",w()),a=null};c.on("mousedown",l=>{if(l.target.closest(".o-test-overlay-close")||l.target.closest(".o-test-overlay-toggle")||l.target.closest("#"+e))return;const E=c.el.getBoundingClientRect();a={startX:l.clientX,startY:l.clientY,left:E.left,top:E.top},r.cursor="grabbing",w()}),t.D.addEventListener("mousemove",b),t.D.addEventListener("mouseup",S);const N=()=>{const l=t(".o-test-overlay-summary");l.els.length&&l.innerText(`Tests: ${t.tRes.filter(Boolean).length}/${t.tRes.length}`)};c.first(".o-test-overlay-toggle").on("click",()=>{const l=t("#"+e);if(!l.el)return;const E=l.el.style.display!=="none";l.css({display:E?"none":"block"}),E||o()}),c.first(".o-test-overlay-close").on("click",()=>{t.D.removeEventListener("mousemove",b),t.D.removeEventListener("mouseup",S),c.remove()}),t.testOverlay.showPanel=()=>{const l=t("#"+e);l.el&&(l.css({display:"block"}),o(),N())},t._testOverlayBase||(t._testOverlayBase=t.test),t.test=(...l)=>{const E=t._testOverlayBase(...l),m=t.tFns[E];return t.tFns[E]=k=>{typeof m=="function"&&m(k);const f=t("#"+e);f.el&&f.el.style.display!=="none"&&o(),N()},E}},t.testConfirm=(n,e=[],o={})=>new Promise(r=>{t(".o-tc-overlay").remove();const c=o.confirm||"Continue",w=e.length>0,a=w?"#dc2626":"#2563eb",b=e.map((h,x)=>"o-tc-cb-"+x),N=w?`<style>.o-tc-item-cb{appearance:none;-webkit-appearance:none;width:16px;height:16px;border:2px solid #ef4444;border-radius:3px;background:#fef2f2;flex-shrink:0;cursor:pointer;}.o-tc-item-cb:checked{border-color:#22c55e;background:#22c55e;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'/%3E%3C/svg%3E");background-size:12px 12px;background-position:center;}</style><ul class="o-tc-list" style="margin:8px 0 0;padding:0;list-style:none;font-size:13px;color:#cbd5e1;">`+e.map((h,x)=>`<li style="margin-bottom:4px;"><label for="${b[x]}" style="display:flex;align-items:center;gap:8px;cursor:pointer;user-select:none;"><input type="checkbox" id="${b[x]}" class="o-tc-item-cb"> <span>${h}</span></label></li>`).join("")+"</ul>":"",l=t.initState({tag:"div",className:"o-tc-overlay",style:"position:fixed;left:50%;bottom:50px;transform:translateX(-50%);z-index:999999;width:fit-content;max-width:min(90vw,400px);font-family:system-ui,sans-serif;cursor:grab;user-select:text;",html:`<div class="o-tc-bar" style="display:flex;flex-direction:column;align-items:stretch;padding:10px 14px;background:#1e293b;color:#e2e8f0;border:1px solid #334155;border-radius:8px;font-size:14px;cursor:grab;min-width:280px;"><div style="display:flex;align-items:center;gap:12px;"><span class="o-tc-label" style="flex:1;">${n}: Paused</span><button type="button" class="o-tc-ok" style="padding:6px 14px;background:${a};color:#fff;border:none;border-radius:6px;font-weight:600;cursor:pointer;font-size:13px;flex-shrink:0;">${c}</button></div>`+N+"</div>"}).appendInside("body"),E={padding:"6px 14px",background:w?"#dc2626":"#2563eb",color:"#fff",border:"none","border-radius":"6px","font-weight":"600",cursor:"pointer","font-size":"13px","flex-shrink":"0"};if(w){const h=l.first(".o-tc-ok"),x=t(".o-tc-overlay .o-tc-item-cb"),y=()=>{const D=x.length>0&&x.els.every(C=>C.checked);h.css({...E,background:D?"#16a34a":"#dc2626"})};x.on("change",y)}let m=null;const k={position:"fixed",left:"50%",bottom:"50px",transform:"translateX(-50%)","z-index":"999999",width:"fit-content","max-width":"min(90vw, 400px)","font-family":"system-ui,sans-serif",cursor:"grab","user-select":"text"},f=()=>{l.css(k)},v=h=>{m&&(k.left=m.left+(h.clientX-m.startX)+"px",k.top=m.top+(h.clientY-m.startY)+"px",delete k.bottom,k.transform="none",f())},u=()=>{m&&(k.cursor="grab",f()),m=null};l.on("mousedown",h=>{if(h.target.closest(".o-tc-ok"))return;const x=l.el.getBoundingClientRect();m={startX:h.clientX,startY:h.clientY,left:x.left,top:x.top},k.cursor="grabbing",f()}),t.D.addEventListener("mousemove",v),t.D.addEventListener("mouseup",u),l.first(".o-tc-ok").on("click",()=>{t.D.removeEventListener("mousemove",v),t.D.removeEventListener("mouseup",u);let h=[];w&&t(".o-tc-overlay .o-tc-item-cb").els.forEach((y,D)=>{!y.checked&&e[D]!==void 0&&h.push(e[D])}),l.remove(),h.length===0?r({ok:!0}):r({ok:!1,errors:h})})});
63
+ `},t.playRecording=(n,e={})=>{const o=Object.assign({},n.mocks,e),r=window.fetch;window.fetch=(a,h={})=>{const C=(h.method||"GET").toUpperCase()+":"+a;if(o[C]){const l=o[C],k=typeof l.response=="string"?l.response:JSON.stringify(l.response);return Promise.resolve(new Response(k,{status:l.status||200}))}return r(a,h)};const c=n.actions.map(a=>[`${a.type} on ${a.target}`,()=>{let h=null;if(a.target)if(a.listSelector!=null&&a.targetIndex!=null){const C=t.D.querySelectorAll(a.listSelector)[a.targetIndex];C&&(h=a.target!==a.listSelector?C.querySelector(a.target):C,!h&&a.target!==a.listSelector&&(h=C))}else h=t.D.querySelector(a.target);return!h&&a.type!=="scroll"?`element not found: ${a.target}`:(a.type==="scroll"?window.scrollTo(0,a.scrollY||0):a.type==="input"||a.type==="change"?(a.value!==void 0&&(h.value=a.value),a.checked!==void 0&&(h.checked=a.checked),h.dispatchEvent(new Event(a.type,{bubbles:!0}))):a.type==="click"?h.click():h.dispatchEvent(new MouseEvent(a.type,{bubbles:!0,cancelable:!0})),!0)}]);return t.test("Recorded playback",...c,()=>{window.fetch=r})},t.testOverlay=()=>{const n="o-test-overlay-btn",e="o-test-overlay-panel";if(t("#"+n).el)return;const o=()=>{const l=t("#"+e);if(!l.el)return;const k=t.tRes.length;let E=`<b>Tests: ${t.tRes.filter(Boolean).length}/${k}</b><hr style="margin:4px 0">`;t.tLog.forEach((f,v)=>{const u=t.tRes[v];E+=`<div style="margin:2px 0;padding:2px 4px;border-radius:3px;background:${u?"#d4edda":"#f8d7da"};color:${u?"#155724":"#721c24"};font-size:11px;white-space:pre-wrap">${f||"Test #"+v}</div>`}),E+='<button id="o-test-export" style="margin-top:6px;padding:4px 8px;font-size:11px;cursor:pointer">Export results</button>',l.html(E),t("#o-test-export").on("click",()=>{const f=JSON.stringify({results:t.tRes,logs:t.tLog},null,2),v=new Blob([f],{type:"application/json"}),u=t.D.createElement("a");u.href=URL.createObjectURL(v),u.download="objs-test-results.json",u.click()})},r={position:"fixed",left:"50%",bottom:"50px",transform:"translateX(-50%)","z-index":"999999",width:"fit-content","max-width":"min(90vw, 420px)","font-family":"system-ui,sans-serif",cursor:"grab","user-select":"text"},c=t.initState({tag:"div",id:n,className:"o-test-overlay",style:"position:fixed;left:50%;bottom:50px;transform:translateX(-50%);z-index:999999;width:fit-content;max-width:min(90vw,420px);font-family:system-ui,sans-serif;cursor:grab;user-select:text;",html:`<div class="o-test-overlay-bar" style="display:flex;flex-direction:column;align-items:stretch;padding:10px 14px;background:#1e293b;color:#e2e8f0;border:1px solid #334155;border-radius:8px;font-size:14px;cursor:grab;min-width:200px;"><div style="display:flex;align-items:center;gap:12px;"><span class="o-test-overlay-summary" style="flex:1;font-size:13px;">Tests: 0/0</span><button type="button" class="o-test-overlay-toggle" style="padding:6px 10px;background:#334155;color:#e2e8f0;border:none;border-radius:6px;cursor:pointer;font-size:12px;">List</button><button type="button" class="o-test-overlay-close" style="padding:4px 8px;background:transparent;color:#94a3b8;border:none;border-radius:4px;cursor:pointer;font-size:16px;line-height:1;" title="Close">\xD7</button></div></div><div id="${e}" style="display:none;margin-top:4px;padding:8px;background:#fff;border:1px solid #334155;border-radius:6px;max-height:60vh;overflow-y:auto;box-shadow:0 2px 8px rgba(0,0,0,.15);font-size:11px;user-select:text;cursor:text;"></div>`}).appendInside("body"),w=()=>{c.css(r)};let a=null;const h=l=>{a&&(r.left=a.left+(l.clientX-a.startX)+"px",r.top=a.top+(l.clientY-a.startY)+"px",delete r.bottom,r.transform="none",w())},S=()=>{a&&(r.cursor="grab",w()),a=null};c.on("mousedown",l=>{if(l.target.closest(".o-test-overlay-close")||l.target.closest(".o-test-overlay-toggle")||l.target.closest("#"+e))return;const k=c.el.getBoundingClientRect();a={startX:l.clientX,startY:l.clientY,left:k.left,top:k.top},r.cursor="grabbing",w()}),t.D.addEventListener("mousemove",h),t.D.addEventListener("mouseup",S);const C=()=>{const l=t(".o-test-overlay-summary");l.els.length&&l.innerText(`Tests: ${t.tRes.filter(Boolean).length}/${t.tRes.length}`)};c.first(".o-test-overlay-toggle").on("click",()=>{const l=t("#"+e);if(!l.el)return;const k=l.el.style.display!=="none";l.css({display:k?"none":"block"}),k||o()}),c.first(".o-test-overlay-close").on("click",()=>{t.D.removeEventListener("mousemove",h),t.D.removeEventListener("mouseup",S),c.remove()}),t.testOverlay.showPanel=()=>{const l=t("#"+e);l.el&&(l.css({display:"block"}),o(),C())},t._testOverlayBase||(t._testOverlayBase=t.test),t.test=(...l)=>{const k=t._testOverlayBase(...l),m=t.tFns[k];return t.tFns[k]=E=>{typeof m=="function"&&m(E);const f=t("#"+e);f.el&&f.el.style.display!=="none"&&o(),C()},k}},t.testConfirm=(n,e=[],o={})=>new Promise(r=>{t(".o-tc-overlay").remove();const c=o.confirm||"Continue",w=e.length>0,a=w?"#dc2626":"#2563eb",h=e.map((y,x)=>"o-tc-cb-"+x),C=w?`<style>.o-tc-item-cb{appearance:none;-webkit-appearance:none;width:16px;height:16px;border:2px solid #ef4444;border-radius:3px;background:#fef2f2;flex-shrink:0;cursor:pointer;}.o-tc-item-cb:checked{border-color:#22c55e;background:#22c55e;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'/%3E%3C/svg%3E");background-size:12px 12px;background-position:center;}</style><ul class="o-tc-list" style="margin:8px 0 0;padding:0;list-style:none;font-size:13px;color:#cbd5e1;">`+e.map((y,x)=>`<li style="margin-bottom:4px;"><label for="${h[x]}" style="display:flex;align-items:center;gap:8px;cursor:pointer;user-select:none;"><input type="checkbox" id="${h[x]}" class="o-tc-item-cb"> <span>${y}</span></label></li>`).join("")+"</ul>":"",l=t.initState({tag:"div",className:"o-tc-overlay",style:"position:fixed;left:50%;bottom:50px;transform:translateX(-50%);z-index:999999;width:fit-content;max-width:min(90vw,400px);font-family:system-ui,sans-serif;cursor:grab;user-select:text;",html:`<div class="o-tc-bar" style="display:flex;flex-direction:column;align-items:stretch;padding:10px 14px;background:#1e293b;color:#e2e8f0;border:1px solid #334155;border-radius:8px;font-size:14px;cursor:grab;min-width:280px;"><div style="display:flex;align-items:center;gap:12px;"><span class="o-tc-label" style="flex:1;">${n}: Paused</span><button type="button" class="o-tc-ok" style="padding:6px 14px;background:${a};color:#fff;border:none;border-radius:6px;font-weight:600;cursor:pointer;font-size:13px;flex-shrink:0;">${c}</button></div>`+C+"</div>"}).appendInside("body"),k={padding:"6px 14px",background:w?"#dc2626":"#2563eb",color:"#fff",border:"none","border-radius":"6px","font-weight":"600",cursor:"pointer","font-size":"13px","flex-shrink":"0"};if(w){const y=l.first(".o-tc-ok"),x=t(".o-tc-overlay .o-tc-item-cb"),b=()=>{const D=x.length>0&&x.els.every(I=>I.checked);y.css({...k,background:D?"#16a34a":"#dc2626"})};x.on("change",b)}let m=null;const E={position:"fixed",left:"50%",bottom:"50px",transform:"translateX(-50%)","z-index":"999999",width:"fit-content","max-width":"min(90vw, 400px)","font-family":"system-ui,sans-serif",cursor:"grab","user-select":"text"},f=()=>{l.css(E)},v=y=>{m&&(E.left=m.left+(y.clientX-m.startX)+"px",E.top=m.top+(y.clientY-m.startY)+"px",delete E.bottom,E.transform="none",f())},u=()=>{m&&(E.cursor="grab",f()),m=null};l.on("mousedown",y=>{if(y.target.closest(".o-tc-ok"))return;const x=l.el.getBoundingClientRect();m={startX:y.clientX,startY:y.clientY,left:x.left,top:x.top},E.cursor="grabbing",f()}),t.D.addEventListener("mousemove",v),t.D.addEventListener("mouseup",u),l.first(".o-tc-ok").on("click",()=>{t.D.removeEventListener("mousemove",v),t.D.removeEventListener("mouseup",u);let y=[];w&&t(".o-tc-overlay .o-tc-item-cb").els.forEach((b,D)=>{!b.checked&&e[D]!==void 0&&y.push(e[D])}),l.remove(),y.length===0?r({ok:!0}):r({ok:!1,errors:y})})});
64
64
 
65
65
  export { o };
66
66
  export default o;
package/objs.js CHANGED
@@ -48,6 +48,7 @@ const o = (query) => {
48
48
  ssr = typeof process !== "undefined" || o.D === o.DocumentMVP,
49
49
  i = 0,
50
50
  j = 0;
51
+ const self = result; // capture so connect() always passes this instance to loader
51
52
 
52
53
  /**
53
54
  * Shortcut for typeof operator
@@ -313,7 +314,10 @@ const o = (query) => {
313
314
  result[state] = returner((props = [{}]) => {
314
315
  result.currentState = state;
315
316
  const data = states[state] || { tag: "div" };
316
- const els = result.els.slice(finish, start + ONE);
317
+ const slice = Array.isArray(result.els)
318
+ ? result.els.slice(finish, start + ONE)
319
+ : [];
320
+ const els = slice.length ? slice : (result.els || []);
317
321
 
318
322
  if (type(data) === objectType) {
319
323
  data.state = state;
@@ -439,8 +443,7 @@ const o = (query) => {
439
443
  [state, [notEmptyStringType]],
440
444
  [fail, [stringType, undefinedType]],
441
445
  ]);
442
-
443
- loader.connect(result, state, fail);
446
+ loader.connect(self, state, fail);
444
447
  }, "connect");
445
448
 
446
449
  /**
@@ -1491,7 +1494,8 @@ o.createStore = (defaults) => {
1491
1494
  return store;
1492
1495
  };
1493
1496
 
1494
- // Short values
1497
+ // Short values (o.U = async "waiting" sentinel for tests)
1498
+ o.U = undefined;
1495
1499
  o.W = 2;
1496
1500
  o.H = 100;
1497
1501
  o.F = false;
@@ -1974,7 +1978,7 @@ o.newLoader = (promise) => {
1974
1978
  if (finished) {
1975
1979
  if (error) {
1976
1980
  fail ? listener[fail]() : "";
1977
- } else {
1981
+ } else if (typeof listener[state] === "function") {
1978
1982
  listener[state](data);
1979
1983
  }
1980
1984
  } else {
@@ -2550,9 +2554,8 @@ o.test = (title = "", ...tests) => {
2550
2554
  sessionStorage.getItem(`oTest-Status-${testN}`) || "[]",
2551
2555
  );
2552
2556
  for (let i = 0; i < o.tStatus[testN].length; i++) {
2553
- if (o.tStatus[testN]) {
2554
- done++;
2555
- }
2557
+ const s = o.tStatus[testN][i];
2558
+ if (s === true || s === false) done++;
2556
2559
  }
2557
2560
  }
2558
2561
 
@@ -2737,7 +2740,7 @@ o.testUpdate = (info, res = o.F, suff = "") => {
2737
2740
  }
2738
2741
  };
2739
2742
 
2740
- if (o.tStatus[testN][info.i] === o.U) {
2743
+ if (o.tStatus[testN][info.i] === o.U || o.tStatus[testN][info.i] === null) {
2741
2744
  o.tStatus[testN][info.i] = res === true;
2742
2745
  if (res === true) {
2743
2746
  if (info.tShowOk) {
@@ -2765,8 +2768,8 @@ o.testUpdate = (info, res = o.F, suff = "") => {
2765
2768
  n = 0;
2766
2769
 
2767
2770
  for (const s of o.tStatus[testN]) {
2768
- if (s === o.U) {
2769
- // if waiting tests there
2771
+ if (s === o.U || s === null) {
2772
+ // if waiting tests there (null = restored from JSON)
2770
2773
  return;
2771
2774
  }
2772
2775
  if (!s) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "objs-core",
3
- "version": "2.0.0",
3
+ "version": "2.0.2",
4
4
  "type": "module",
5
5
  "description": "Lightweight (~6 kB) library for fast, AI-friendly front-end development: samples and state control, built-in store (createStore), routing, caching, and recording → Playwright tests. No build step; split design into samples and give them data and actions. Works standalone or alongside React; SSR and hydrate from server-rendered DOM. v2.0: exportPlaywrightTest(), refs, TypeScript definitions, recording in all builds.",
6
6
  "homepage": "https://en.fous.name/objs/",