@pageboard/html 0.11.28 → 0.12.0

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.
Files changed (52) hide show
  1. package/elements/accordion.js +0 -1
  2. package/elements/card.js +5 -5
  3. package/elements/consent.js +1 -1
  4. package/elements/embed.js +1 -1
  5. package/elements/fieldsets.js +2 -2
  6. package/elements/form.js +2 -2
  7. package/elements/grid.js +3 -3
  8. package/elements/heading.js +1 -1
  9. package/elements/image.js +4 -4
  10. package/elements/input-date.js +3 -4
  11. package/elements/inputs.js +12 -12
  12. package/elements/layout.js +8 -9
  13. package/elements/link.js +1 -1
  14. package/elements/menu.js +7 -7
  15. package/elements/navigation.js +3 -16
  16. package/elements/pagination.js +1 -1
  17. package/elements/paragraph.js +2 -2
  18. package/elements/sitemap.js +8 -8
  19. package/elements/sticky.js +2 -2
  20. package/elements/tab.js +1 -1
  21. package/elements/table.js +10 -10
  22. package/elements/template.js +1 -1
  23. package/lib/nouislider.js +28 -0
  24. package/package.json +1 -1
  25. package/ui/accordion.js +3 -21
  26. package/ui/consent.css +3 -3
  27. package/ui/consent.js +9 -13
  28. package/ui/embed.js +11 -17
  29. package/ui/fieldset-list.js +9 -9
  30. package/ui/fieldset.js +4 -8
  31. package/ui/form.js +143 -158
  32. package/ui/heading-helper.js +13 -19
  33. package/ui/image.js +19 -30
  34. package/ui/input-date-slot.js +2 -2
  35. package/ui/input-date.js +2 -7
  36. package/ui/input-file.js +58 -61
  37. package/ui/input-range.js +4 -8
  38. package/ui/layout.js +2 -6
  39. package/ui/media.js +15 -28
  40. package/ui/menu.js +23 -27
  41. package/ui/pagination.js +2 -2
  42. package/ui/query-tags.js +4 -4
  43. package/ui/rating.js +2 -2
  44. package/ui/scroll-link.js +2 -9
  45. package/ui/select.js +21 -23
  46. package/ui/sitemap-helper.js +5 -5
  47. package/ui/sitemap.js +15 -15
  48. package/ui/sticky.js +2 -6
  49. package/ui/tab-helper.js +32 -34
  50. package/ui/tab.js +2 -4
  51. package/ui/time.js +2 -7
  52. package/ui/transition.js +21 -21
package/ui/consent.js CHANGED
@@ -1,8 +1,4 @@
1
- class HTMLCustomConsentElement extends HTMLFormElement {
2
- constructor() {
3
- super();
4
- if (this.init) this.init();
5
- }
1
+ class HTMLElementConsent extends Page.create(HTMLFormElement) {
6
2
  static defaults = {
7
3
  dataTransient: false
8
4
  };
@@ -27,7 +23,7 @@ class HTMLCustomConsentElement extends HTMLFormElement {
27
23
  state.consent(this);
28
24
  }
29
25
  chainConsent(state) {
30
- window.HTMLCustomFormElement.prototype.fill.call(this, {
26
+ window.HTMLElementForm.prototype.fill.call(this, {
31
27
  consent: state.scope.$consent
32
28
  });
33
29
  if (this.options.transient) this.classList.remove('visible');
@@ -35,7 +31,7 @@ class HTMLCustomConsentElement extends HTMLFormElement {
35
31
  handleSubmit(e, state) {
36
32
  if (e.type == "submit") e.preventDefault();
37
33
  if (this.isContentEditable) return;
38
- const fd = window.HTMLCustomFormElement.prototype.read.call(this);
34
+ const fd = window.HTMLElementForm.prototype.read.call(this);
39
35
  const consent = fd.consent;
40
36
  if (consent == null) {
41
37
  return;
@@ -63,9 +59,9 @@ class HTMLCustomConsentElement extends HTMLFormElement {
63
59
  }
64
60
  }
65
61
 
66
- Page.ready(() => {
67
- VirtualHTMLElement.define(`element-consent`, HTMLCustomConsentElement, 'form');
68
- });
62
+
63
+ Page.define(`element-consent`, HTMLElementConsent, 'form');
64
+
69
65
 
70
66
  Page.constructor.prototype.consent = function (fn) {
71
67
  const initial = this.scope.$consent === undefined;
@@ -74,7 +70,7 @@ Page.constructor.prototype.consent = function (fn) {
74
70
  this.scope.$consent = consent;
75
71
  this.chain('consent', fn);
76
72
  if (consent === undefined) {
77
- HTMLCustomConsentElement.waiting = true;
73
+ HTMLElementConsent.waiting = true;
78
74
  } else if (consent === null) {
79
75
  // setup finished but no consent is done yet, ask consent
80
76
  this.reconsent();
@@ -86,7 +82,7 @@ Page.constructor.prototype.reconsent = function (fn) {
86
82
  const consent = this.scope.$consent;
87
83
  let asking = false;
88
84
  if (consent != "yes") {
89
- asking = HTMLCustomConsentElement.ask();
85
+ asking = HTMLElementConsent.ask();
90
86
  }
91
87
  if (!asking) {
92
88
  if (consent == null) this.scope.$consent = "yes";
@@ -97,7 +93,7 @@ Page.constructor.prototype.reconsent = function (fn) {
97
93
  Page.paint(state => {
98
94
  state.finish(() => {
99
95
  let run = true;
100
- if (HTMLCustomConsentElement.waiting) {
96
+ if (HTMLElementConsent.waiting) {
101
97
  if (state.reconsent()) run = false;
102
98
  }
103
99
  if (run) state.runChain('consent');
package/ui/embed.js CHANGED
@@ -1,21 +1,15 @@
1
- class HTMLElementEmbed extends VirtualHTMLElement {
1
+ class HTMLElementEmbed extends Page.Element {
2
2
  static defaults = {
3
3
  src: null,
4
4
  hash: null
5
5
  };
6
6
  static revealRatio = 0.2;
7
- init() {
8
- this.promise = Promise.resolve();
9
- this.promise.done = function() {};
10
- }
7
+ #defer = new Deferred();
8
+
11
9
  reveal(state) {
12
- let done;
13
- this.promise = new Promise(resolve => done = resolve);
14
- this.promise.done = done;
15
10
  this.classList.add('waiting');
16
-
17
11
  state.consent(this);
18
- return this.promise;
12
+ return this.#defer;
19
13
  }
20
14
  consent(state) {
21
15
  const consent = state.scope.$consent;
@@ -25,7 +19,7 @@ class HTMLElementEmbed extends VirtualHTMLElement {
25
19
  this.iframe = this.querySelector('iframe');
26
20
  if (consent != "yes") {
27
21
  if (this.iframe) this.iframe.remove();
28
- this.promise.done();
22
+ this.#defer.resolve();
29
23
  return;
30
24
  }
31
25
  if (!this.iframe) {
@@ -52,18 +46,18 @@ class HTMLElementEmbed extends VirtualHTMLElement {
52
46
  this.iframe.setAttribute('src', this.currentSrc);
53
47
  }
54
48
  }
55
- this.promise.done();
49
+ this.#defer.resolve();
56
50
  }
57
51
  }
58
52
  captureClick(e, state) {
59
53
  if (this.matches('.denied')) state.reconsent();
60
54
  }
61
55
  captureLoad() {
62
- this.promise.done();
56
+ this.#defer.resolve();
63
57
  this.classList.remove('loading');
64
58
  }
65
59
  captureError() {
66
- this.promise.done();
60
+ this.#defer.resolve();
67
61
  this.classList.add('error');
68
62
  }
69
63
  handleAllMessage(e, state) {
@@ -79,6 +73,6 @@ class HTMLElementEmbed extends VirtualHTMLElement {
79
73
  }
80
74
  }
81
75
 
82
- Page.ready(() => {
83
- VirtualHTMLElement.define('element-embed', HTMLElementEmbed);
84
- });
76
+
77
+ Page.define('element-embed', HTMLElementEmbed);
78
+
@@ -27,7 +27,7 @@ class WalkIndex {
27
27
  }
28
28
  }
29
29
 
30
- class HTMLElementFieldsetList extends VirtualHTMLElement {
30
+ class HTMLElementFieldsetList extends Page.Element {
31
31
  #size;
32
32
  #initialSize;
33
33
  #prefix;
@@ -115,29 +115,29 @@ class HTMLElementFieldsetList extends VirtualHTMLElement {
115
115
  if (this.#size === len) return;
116
116
  this.#size = len;
117
117
  let tpl = this.ownTpl.content.cloneNode(true);
118
- const $fieldset = Array.from(Array(len)).map((x, i) => {
118
+ const fieldlist = Array.from(Array(len)).map((x, i) => {
119
119
  return { index: i };
120
120
  });
121
121
  const inputs = tpl.querySelectorAll('[name]');
122
122
  const prefix = this.#prefix;
123
123
  for (const node of inputs) {
124
124
  if (node.name.startsWith(prefix)) {
125
- node.name = `${prefix}[$field.index].${node.name.substring(prefix.length)}`;
125
+ node.name = `${prefix}[fielditem.index].${node.name.substring(prefix.length)}`;
126
126
  if (node.id?.startsWith('for-' + prefix)) {
127
- node.id = `for-${prefix}[$field.index].${node.id.substring(4 + prefix.length)}`;
127
+ node.id = `for-${prefix}[fielditem.index].${node.id.substring(4 + prefix.length)}`;
128
128
  }
129
129
  }
130
130
  }
131
131
  const conditionalFieldsets = tpl.querySelectorAll('[is="element-fieldset"]');
132
132
  for (const node of conditionalFieldsets) {
133
133
  if (node.dataset.name?.startsWith(prefix)) {
134
- node.dataset.name = `${prefix}[$field.index].${node.dataset.name.substring(prefix.length)}`;
134
+ node.dataset.name = `${prefix}[fielditem.index].${node.dataset.name.substring(prefix.length)}`;
135
135
  }
136
136
  }
137
137
  const labels = tpl.querySelectorAll('label[for]');
138
138
  for (const node of labels) {
139
139
  if (node.htmlFor?.startsWith('for-' + prefix)) {
140
- node.htmlFor = `for-${prefix}[$field.index].${node.htmlFor.substring(4 + prefix.length)}`;
140
+ node.htmlFor = `for-${prefix}[fielditem.index].${node.htmlFor.substring(4 + prefix.length)}`;
141
141
  }
142
142
  }
143
143
 
@@ -147,7 +147,7 @@ class HTMLElementFieldsetList extends VirtualHTMLElement {
147
147
  return;
148
148
  }
149
149
  subtpl.appendChild(
150
- subtpl.ownerDocument.createTextNode('[$fieldset|repeat:*:$field|]')
150
+ subtpl.ownerDocument.createTextNode('[fieldlist|at:*|repeat:fielditem|]')
151
151
  );
152
152
  if (len == 0) {
153
153
  let node = tpl.querySelector(this.#selector('add'));
@@ -163,7 +163,7 @@ class HTMLElementFieldsetList extends VirtualHTMLElement {
163
163
  tpl.appendChild(hidden);
164
164
  }
165
165
  }
166
- tpl = tpl.fuse({ $fieldset }, scope);
166
+ tpl = tpl.fuse({ fieldlist }, scope);
167
167
 
168
168
  const view = this.ownView;
169
169
  view.textContent = '';
@@ -282,4 +282,4 @@ class HTMLElementFieldsetList extends VirtualHTMLElement {
282
282
  }
283
283
  }
284
284
 
285
- VirtualHTMLElement.define('element-fieldset-list', HTMLElementFieldsetList);
285
+ Page.define('element-fieldset-list', HTMLElementFieldsetList);
package/ui/fieldset.js CHANGED
@@ -1,12 +1,8 @@
1
- class HTMLCustomFieldSetElement extends HTMLFieldSetElement {
1
+ class HTMLElementFieldSet extends Page.create(HTMLFieldSetElement) {
2
2
  static defaults = {
3
3
  dataName: null,
4
4
  dataValue: null
5
5
  };
6
- constructor() {
7
- super();
8
- this.init?.();
9
- }
10
6
 
11
7
  fill(query) {
12
8
  if (this.isContentEditable || !this.options?.name || !this.form) return;
@@ -36,6 +32,6 @@ class HTMLCustomFieldSetElement extends HTMLFieldSetElement {
36
32
  }
37
33
  }
38
34
 
39
- Page.ready(() => {
40
- VirtualHTMLElement.define(`element-fieldset`, HTMLCustomFieldSetElement, 'fieldset');
41
- });
35
+
36
+ Page.define(`element-fieldset`, HTMLElementFieldSet, 'fieldset');
37
+
package/ui/form.js CHANGED
@@ -1,10 +1,99 @@
1
- class HTMLCustomFormElement extends HTMLFormElement {
2
- constructor() {
3
- super();
4
- if (this.init) this.init();
1
+ class HTMLElementForm extends Page.create(HTMLFormElement) {
2
+ getMethodLater = Page.debounce((e, state) => this.getMethod(e, state), 300);
3
+
4
+ static linearizeValues(query, obj = {}, prefix) {
5
+ if (Array.isArray(query) && query.every(val => {
6
+ return val == null || typeof val != "object";
7
+ })) {
8
+ // do not linearize array-as-value
9
+ obj[prefix] = query;
10
+ } else for (let key of Object.keys(query)) {
11
+ const val = query[key];
12
+ if (prefix) key = prefix + '.' + key;
13
+ if (val === undefined) continue;
14
+ if (val == null) obj[key] = val;
15
+ else if (typeof val == "object") this.linearizeValues(val, obj, key);
16
+ else obj[key] = val;
17
+ }
18
+ return obj;
5
19
  }
6
- init() {
7
- this.getMethodLater = Pageboard.debounce(this.getMethod, 300);
20
+
21
+ static patch(state) {
22
+ state.scope.$filters.form = (ctx, val, action, name) => {
23
+ const form = name
24
+ ? document.querySelector(`form[name="${name}"]`)
25
+ : ctx.dest.node.closest('form');
26
+ if (!form) {
27
+ // eslint-disable-next-line no-console
28
+ console.warn("No parent form found");
29
+ return val;
30
+ }
31
+ if (action == "toggle") {
32
+ action = val ? "enable" : "disable";
33
+ }
34
+
35
+ state.finish(() => {
36
+ if (action == "enable") {
37
+ form.enable();
38
+ } else if (action == "disable") {
39
+ form.disable();
40
+ } else if (action == "fill") {
41
+ if (val == null) {
42
+ form.reset();
43
+ } else if (typeof val == "object") {
44
+ let values = val;
45
+ if (val.id && val.data) {
46
+ // old way
47
+ values = { ...val.data };
48
+ for (const key of Object.keys(val)) {
49
+ if (key != "data") values['$' + key] = val[key];
50
+ }
51
+ } else {
52
+ // new way
53
+ }
54
+ form.fill(this.linearizeValues(values), state.scope);
55
+ form.save();
56
+ }
57
+ }
58
+ });
59
+
60
+ return val;
61
+ };
62
+ }
63
+
64
+ static setup(state) {
65
+ // https://daverupert.com/2017/11/happier-html5-forms/
66
+ state.connect({
67
+ captureBlur: (e, state) => blurHandler(e, false),
68
+ captureInvalid: (e, state) => blurHandler(e, true),
69
+ captureFocus: (e, state) => {
70
+ const el = e.target;
71
+ if (!el.matches || !el.matches('input,textarea,select')) return;
72
+ if (e.relatedTarget?.type == "submit") return;
73
+ updateClass(el.closest('.field') || el, el.validity, true);
74
+ }
75
+ }, document);
76
+
77
+ function updateClass(field, validity, remove) {
78
+ for (const [key, has] of Object.entries(validity)) {
79
+ if (key == "valid") continue;
80
+ field.classList.toggle(key, !remove && has);
81
+ }
82
+ field.classList.toggle('error', !remove && !validity.valid);
83
+ }
84
+ function blurHandler(e, checked) {
85
+ const el = e.target;
86
+ if (!el.matches || !el.matches('input,textarea,select')) return;
87
+ if (!checked) el.checkValidity();
88
+ updateClass(el.closest('.field') || el, el.validity);
89
+ }
90
+ }
91
+
92
+ toggleMessages(status) {
93
+ return window.HTMLElementTemplate.prototype.toggleMessages.call(this, status, this);
94
+ }
95
+ getRedirect(status) {
96
+ return window.HTMLElementTemplate.prototype.getRedirect.call(this, status, this);
8
97
  }
9
98
  patch(state) {
10
99
  if (this.isContentEditable) return;
@@ -73,6 +162,7 @@ class HTMLCustomFormElement extends HTMLFormElement {
73
162
  if (val == "") val = null;
74
163
  let defVal = node.defaultValue;
75
164
  if (defVal == "") defVal = null;
165
+ else if (type == "select-one" && defVal === undefined) defVal = null;
76
166
 
77
167
  switch (type) {
78
168
  case "file":
@@ -220,75 +310,66 @@ class HTMLCustomFormElement extends HTMLFormElement {
220
310
  this.toggleMessages(status);
221
311
  });
222
312
  }
223
- postMethod(e, state) {
313
+ async postMethod(e, state) {
224
314
  if (e.type != "submit") return;
225
315
  const form = this;
226
- const $query = this.dataset;
227
-
228
316
  form.classList.add('loading');
229
317
 
230
- const data = { $query };
231
- return Promise.all(Array.from(form.elements).filter(node => {
318
+ await Promise.all(Array.from(form.elements).filter(node => {
232
319
  return Boolean(node.presubmit);
233
- }).map(input => {
234
- return input.presubmit();
235
- })).then(() => {
236
- data.$query = state.query;
237
- data.$request = form.read(true);
238
- form.disable();
239
- return Pageboard.fetch(form.method, Page.format({
240
- pathname: form.getAttribute('action'),
241
- query: data.$query
242
- }), data.$request);
243
- }).catch(err => err).then(res => {
244
- if (res?.grants) state.data.$grants = res.grants;
245
- state.scope.$response = res;
246
- form.enable();
320
+ }).map(input => input.presubmit()));
247
321
 
248
- form.classList.remove('loading');
322
+ const { scope } = state;
323
+ scope.$request = form.read(true);
324
+ form.disable();
249
325
 
250
- // messages shown inside form, no navigation
251
- const hasMsg = form.toggleMessages(res.status);
252
- const ok = res.status >= 200 && res.status < 300;
253
- let redirect = form.getRedirect(res.status);
326
+ const res = await Pageboard.fetch(form.method, Page.format({
327
+ pathname: form.getAttribute('action'),
328
+ query: state.query
329
+ }), scope.$request).catch(err => err);
254
330
 
255
- if (ok) {
256
- form.forget();
257
- form.save();
258
- if (!redirect && form.closest('element-template') && !hasMsg) {
259
- redirect = state.toString();
260
- }
261
- }
331
+ if (res?.grants) scope.$grants = res.grants;
332
+ scope.$response = res;
333
+ scope.$status = res.status;
334
+ form.enable();
262
335
 
263
- if (!redirect) return;
336
+ form.classList.remove('loading');
264
337
 
265
- data.$response = res;
266
- data.$status = res.status;
267
- if (!redirect) {
268
- if (res.granted) redirect = state.toString();
269
- else return;
270
- }
271
- if (redirect && !ok) {
272
- form.backup();
338
+ // messages shown inside form, no navigation
339
+ const hasMsg = form.toggleMessages(res.status);
340
+ const ok = res.status >= 200 && res.status < 300;
341
+ let redirect = form.getRedirect(res.status);
342
+
343
+ if (ok) {
344
+ form.forget();
345
+ form.save();
346
+ if (!redirect && form.closest('element-template') && !hasMsg) {
347
+ redirect = state.toString();
273
348
  }
349
+ }
350
+ if (!redirect) {
351
+ if (res.granted) redirect = state.toString();
352
+ else return;
353
+ }
354
+ if (redirect && !ok) {
355
+ form.backup();
356
+ }
274
357
 
275
- const loc = Page.parse(redirect).fuse(data, state.scope);
276
- let vary = false;
277
- if (loc.samePathname(state)) {
278
- if (res.granted) {
279
- vary = true;
280
- } else {
281
- vary = "patch";
282
- }
283
- state.data.$vary = vary;
358
+ const loc = Page.parse(redirect).fuse({}, scope);
359
+ let vary = false;
360
+ if (loc.samePathname(state)) {
361
+ if (res.granted) {
362
+ vary = true;
363
+ } else {
364
+ vary = "patch";
284
365
  }
285
- return state.push(loc, {
286
- vary: vary
287
- });
288
- });
366
+ scope.$vary = vary;
367
+ }
368
+ return state.push(loc, { vary });
289
369
  }
290
370
  }
291
- window.HTMLCustomFormElement = HTMLCustomFormElement;
371
+ window.HTMLElementForm = HTMLElementForm;
372
+ Page.define(`element-form`, HTMLElementForm, 'form');
292
373
 
293
374
  /* these methods must be available even on non-upgraded elements */
294
375
  HTMLFormElement.prototype.enable = function () {
@@ -305,17 +386,8 @@ HTMLFormElement.prototype.disable = function () {
305
386
  }
306
387
  };
307
388
 
308
- Page.ready(() => {
309
- const Cla = window.customElements.get('element-template');
310
- HTMLCustomFormElement.prototype.toggleMessages = function (status) {
311
- return Cla.prototype.toggleMessages.call(this, status, this);
312
- };
313
- HTMLCustomFormElement.prototype.getRedirect = function (status) {
314
- return Cla.prototype.getRedirect.call(this, status, this);
315
- };
316
389
 
317
- VirtualHTMLElement.define(`element-form`, HTMLCustomFormElement, 'form');
318
- });
390
+
319
391
 
320
392
  HTMLSelectElement.prototype.fill = function (val) {
321
393
  if (!Array.isArray(val)) val = [val];
@@ -335,6 +407,7 @@ HTMLInputElement.prototype.fill = function (val) {
335
407
  this.checked = true;
336
408
  } else {
337
409
  this.checked = (Array.isArray(val) ? val : [val]).some(str => {
410
+ if (str == false && this.value == "") return true;
338
411
  return str.toString() == this.value;
339
412
  });
340
413
  }
@@ -396,91 +469,3 @@ Object.defineProperty(HTMLInputElement.prototype, 'defaultValue', {
396
469
  }
397
470
  });
398
471
 
399
- Page.setup(state => {
400
- // https://daverupert.com/2017/11/happier-html5-forms/
401
- Page.connect({
402
- captureBlur: (e, state) => blurHandler(e, false),
403
- captureInvalid: (e, state) => blurHandler(e, true),
404
- captureFocus: (e, state) => {
405
- const el = e.target;
406
- if (!el.matches || !el.matches('input,textarea,select')) return;
407
- if (e.relatedTarget?.type == "submit") return;
408
- updateClass(el.closest('.field') || el, el.validity, true);
409
- }
410
- }, document);
411
-
412
- function updateClass(field, validity, remove) {
413
- for (const [key, has] of Object.entries(validity)) {
414
- if (key == "valid") continue;
415
- field.classList.toggle(key, !remove && has);
416
- }
417
- field.classList.toggle('error', !remove && !validity.valid);
418
- }
419
- function blurHandler(e, checked) {
420
- const el = e.target;
421
- if (!el.matches || !el.matches('input,textarea,select')) return;
422
- if (!checked) el.checkValidity();
423
- updateClass(el.closest('.field') || el, el.validity);
424
- }
425
- });
426
-
427
- Page.patch(state => {
428
- const filters = state.scope.$filters;
429
-
430
- function linearizeValues(query, obj = {}, prefix) {
431
- if (Array.isArray(query) && query.every(val => {
432
- return val == null || typeof val != "object";
433
- })) {
434
- // do not linearize array-as-value
435
- obj[prefix] = query;
436
- } else for (let key of Object.keys(query)) {
437
- const val = query[key];
438
- if (prefix) key = prefix + '.' + key;
439
- if (val === undefined) continue;
440
- if (val == null) obj[key] = val;
441
- else if (typeof val == "object") linearizeValues(val, obj, key);
442
- else obj[key] = val;
443
- }
444
- return obj;
445
- }
446
- filters.form = function (val, what, action, name) {
447
- const form = name
448
- ? document.querySelector(`form[name="${name}"]`)
449
- : what.parent.closest('form');
450
- if (!form) {
451
- // eslint-disable-next-line no-console
452
- console.warn("No parent form found");
453
- return val;
454
- }
455
- if (action == "toggle") {
456
- action = val ? "enable" : "disable";
457
- }
458
-
459
- state.finish(() => {
460
- if (action == "enable") {
461
- form.enable();
462
- } else if (action == "disable") {
463
- form.disable();
464
- } else if (action == "fill") {
465
- if (val == null) {
466
- form.reset();
467
- } else if (typeof val == "object") {
468
- let values = val;
469
- if (val.id && val.data) {
470
- // old way
471
- values = { ...val.data };
472
- for (const key of Object.keys(val)) {
473
- if (key != "data") values['$' + key] = val[key];
474
- }
475
- } else {
476
- // new way
477
- }
478
- form.fill(linearizeValues(values), state.scope);
479
- form.save();
480
- }
481
- }
482
- });
483
-
484
- return val;
485
- };
486
- });
@@ -1,17 +1,11 @@
1
- class HTMLElementHeadingHelper extends HTMLHeadingElement {
2
- constructor() {
3
- super();
4
- if (this.init) this.init();
5
- }
6
- init() {
7
- this.willSync = Pageboard.debounce(this.sync, 100);
1
+ class HTMLElementHeadingHelper extends Page.create(HTMLHeadingElement) {
2
+ setup(state) {
3
+ this.willSync = state.debounce(() => this.sync(), 100);
8
4
  this.observer = new MutationObserver(records => {
9
5
  if (records.some(mut => {
10
6
  return mut.type == "characterData" || mut.type == "childList" && mut.addedNodes.length;
11
- })) this.willSync();
7
+ })) this.willSync();
12
8
  });
13
- }
14
- setup() {
15
9
  this.observer.observe(this, {
16
10
  childList: true,
17
11
  subtree: true,
@@ -32,13 +26,13 @@ class HTMLElementHeadingHelper extends HTMLHeadingElement {
32
26
  }
33
27
  }
34
28
 
35
- Page.setup(() => {
36
- for (let i = 1; i <= 6; i++) {
37
- VirtualHTMLElement.define(
38
- `h${i}-helper`,
39
- class extends HTMLElementHeadingHelper { },
40
- `h${i}`
41
- );
42
- }
43
- });
29
+
30
+ for (let i = 1; i <= 6; i++) {
31
+ Page.define(
32
+ `h${i}-helper`,
33
+ class extends HTMLElementHeadingHelper { },
34
+ `h${i}`
35
+ );
36
+ }
37
+
44
38