@pageboard/html 0.10.14 → 0.11.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.
package/lib/nouislider.js CHANGED
@@ -2,7 +2,7 @@
2
2
  typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
3
3
  typeof define === 'function' && define.amd ? define(['exports'], factory) :
4
4
  (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.noUiSlider = {}));
5
- }(this, (function (exports) { 'use strict';
5
+ })(this, (function (exports) { 'use strict';
6
6
 
7
7
  exports.PipsMode = void 0;
8
8
  (function (PipsMode) {
@@ -127,7 +127,7 @@
127
127
  : doc.body.scrollTop;
128
128
  return {
129
129
  x: x,
130
- y: y
130
+ y: y,
131
131
  };
132
132
  }
133
133
  // we provide a function to compute constants instead
@@ -140,18 +140,18 @@
140
140
  ? {
141
141
  start: "pointerdown",
142
142
  move: "pointermove",
143
- end: "pointerup"
143
+ end: "pointerup",
144
144
  }
145
145
  : window.navigator.msPointerEnabled
146
146
  ? {
147
147
  start: "MSPointerDown",
148
148
  move: "MSPointerMove",
149
- end: "MSPointerUp"
149
+ end: "MSPointerUp",
150
150
  }
151
151
  : {
152
152
  start: "mousedown touchstart",
153
153
  move: "mousemove touchmove",
154
- end: "mouseup touchend"
154
+ end: "mouseup touchend",
155
155
  };
156
156
  }
157
157
  // https://github.com/WICG/EventListenerOptions/blob/gh-pages/explainer.md
@@ -163,7 +163,7 @@
163
163
  var opts = Object.defineProperty({}, "passive", {
164
164
  get: function () {
165
165
  supportsPassive = true;
166
- }
166
+ },
167
167
  });
168
168
  // @ts-ignore
169
169
  window.addEventListener("test", null, opts);
@@ -384,18 +384,18 @@
384
384
  stepBefore: {
385
385
  startValue: this.xVal[j - 2],
386
386
  step: this.xNumSteps[j - 2],
387
- highestStep: this.xHighestCompleteStep[j - 2]
387
+ highestStep: this.xHighestCompleteStep[j - 2],
388
388
  },
389
389
  thisStep: {
390
390
  startValue: this.xVal[j - 1],
391
391
  step: this.xNumSteps[j - 1],
392
- highestStep: this.xHighestCompleteStep[j - 1]
392
+ highestStep: this.xHighestCompleteStep[j - 1],
393
393
  },
394
394
  stepAfter: {
395
395
  startValue: this.xVal[j],
396
396
  step: this.xNumSteps[j],
397
- highestStep: this.xHighestCompleteStep[j]
398
- }
397
+ highestStep: this.xHighestCompleteStep[j],
398
+ },
399
399
  };
400
400
  };
401
401
  Spectrum.prototype.countStepDecimals = function () {
@@ -481,7 +481,7 @@
481
481
  to: function (value) {
482
482
  return value === undefined ? "" : value.toFixed(2);
483
483
  },
484
- from: Number
484
+ from: Number,
485
485
  };
486
486
  var cssClasses = {
487
487
  target: "target",
@@ -519,12 +519,12 @@
519
519
  valueVertical: "value-vertical",
520
520
  valueNormal: "value-normal",
521
521
  valueLarge: "value-large",
522
- valueSub: "value-sub"
522
+ valueSub: "value-sub",
523
523
  };
524
524
  // Namespaces of internal event listeners
525
525
  var INTERNAL_EVENT_NS = {
526
526
  tooltips: ".__tooltips",
527
- aria: ".__aria"
527
+ aria: ".__aria",
528
528
  };
529
529
  //endregion
530
530
  function testStep(parsed, entry) {
@@ -731,7 +731,7 @@
731
731
  fixed: fixed,
732
732
  snap: snap,
733
733
  hover: hover,
734
- unconstrained: unconstrained
734
+ unconstrained: unconstrained,
735
735
  };
736
736
  }
737
737
  function testTooltips(parsed, entry) {
@@ -817,7 +817,7 @@
817
817
  animate: true,
818
818
  animationDuration: 300,
819
819
  ariaFormat: defaultFormatter,
820
- format: defaultFormatter
820
+ format: defaultFormatter,
821
821
  };
822
822
  // Tests are executed in the order they are presented here.
823
823
  var tests = {
@@ -844,7 +844,7 @@
844
844
  documentElement: { r: false, t: testDocumentElement },
845
845
  cssPrefix: { r: true, t: testCssPrefix },
846
846
  cssClasses: { r: true, t: testCssClasses },
847
- handleAttributes: { r: false, t: testHandleAttributes }
847
+ handleAttributes: { r: false, t: testHandleAttributes },
848
848
  };
849
849
  var defaults = {
850
850
  connect: false,
@@ -856,7 +856,7 @@
856
856
  cssClasses: cssClasses,
857
857
  keyboardPageMultiplier: 5,
858
858
  keyboardMultiplier: 1,
859
- keyboardDefaultStep: 10
859
+ keyboardDefaultStep: 10,
860
860
  };
861
861
  // AriaFormat defaults to regular format, if any.
862
862
  if (options.format && !options.ariaFormat) {
@@ -888,7 +888,7 @@
888
888
  // Pips don't move, so we can place them using left/top.
889
889
  var styles = [
890
890
  ["left", "top"],
891
- ["right", "bottom"]
891
+ ["right", "bottom"],
892
892
  ];
893
893
  parsed.style = styles[parsed.dir][parsed.ort];
894
894
  return parsed;
@@ -1273,7 +1273,7 @@
1273
1273
  var format = pips.format || {
1274
1274
  to: function (value) {
1275
1275
  return String(Math.round(value));
1276
- }
1276
+ },
1277
1277
  };
1278
1278
  scope_Pips = scope_Target.appendChild(addMarking(spread, filter, format));
1279
1279
  return scope_Pips;
@@ -1509,21 +1509,21 @@
1509
1509
  pageOffset: event.pageOffset,
1510
1510
  handleNumbers: data.handleNumbers,
1511
1511
  buttonsProperty: event.buttons,
1512
- locations: scope_Locations.slice()
1512
+ locations: scope_Locations.slice(),
1513
1513
  });
1514
1514
  var endEvent = attachEvent(actions.end, scope_DocumentElement, eventEnd, {
1515
1515
  target: event.target,
1516
1516
  handle: handle,
1517
1517
  listeners: listeners,
1518
1518
  doNotReject: true,
1519
- handleNumbers: data.handleNumbers
1519
+ handleNumbers: data.handleNumbers,
1520
1520
  });
1521
1521
  var outEvent = attachEvent("mouseout", scope_DocumentElement, documentLeave, {
1522
1522
  target: event.target,
1523
1523
  handle: handle,
1524
1524
  listeners: listeners,
1525
1525
  doNotReject: true,
1526
- handleNumbers: data.handleNumbers
1526
+ handleNumbers: data.handleNumbers,
1527
1527
  });
1528
1528
  // We want to make sure we pushed the listeners in the listener list rather than creating
1529
1529
  // a new one as it has already been passed to the event handlers.
@@ -1668,7 +1668,7 @@
1668
1668
  // These events are only bound to the visual handle
1669
1669
  // element, not the 'real' origin element.
1670
1670
  attachEvent(actions.start, handle.children[0], eventStart, {
1671
- handleNumbers: [index]
1671
+ handleNumbers: [index],
1672
1672
  });
1673
1673
  });
1674
1674
  }
@@ -1679,7 +1679,7 @@
1679
1679
  // Fire hover events
1680
1680
  if (behaviour.hover) {
1681
1681
  attachEvent(actions.move, scope_Base, eventHover, {
1682
- hover: true
1682
+ hover: true,
1683
1683
  });
1684
1684
  }
1685
1685
  // Make the range draggable.
@@ -1710,7 +1710,7 @@
1710
1710
  attachEvent(actions.start, eventHolder, eventStart, {
1711
1711
  handles: handlesToDrag,
1712
1712
  handleNumbers: handleNumbersToDrag,
1713
- connect: connect
1713
+ connect: connect,
1714
1714
  });
1715
1715
  });
1716
1716
  });
@@ -2059,7 +2059,7 @@
2059
2059
  if (options.snap) {
2060
2060
  return [
2061
2061
  value - nearbySteps.stepBefore.startValue || null,
2062
- nearbySteps.stepAfter.startValue - value || null
2062
+ nearbySteps.stepAfter.startValue - value || null,
2063
2063
  ];
2064
2064
  }
2065
2065
  // If the next value in this step moves into the next step,
@@ -2118,7 +2118,7 @@
2118
2118
  "step",
2119
2119
  "format",
2120
2120
  "pips",
2121
- "tooltips"
2121
+ "tooltips",
2122
2122
  ];
2123
2123
  // Only change options that we're actually passed to update.
2124
2124
  updateAble.forEach(function (name) {
@@ -2203,7 +2203,7 @@
2203
2203
  getOrigins: function () {
2204
2204
  return scope_Handles;
2205
2205
  },
2206
- pips: pips // Issue #594
2206
+ pips: pips, // Issue #594
2207
2207
  };
2208
2208
  return scope_Self;
2209
2209
  }
@@ -2228,13 +2228,13 @@
2228
2228
  // A reference to the default classes, allows global changes.
2229
2229
  // Use the cssClasses option for changes to one slider.
2230
2230
  cssClasses: cssClasses,
2231
- create: initialize
2231
+ create: initialize,
2232
2232
  };
2233
2233
 
2234
2234
  exports.create = initialize;
2235
2235
  exports.cssClasses = cssClasses;
2236
- exports['default'] = nouislider;
2236
+ exports["default"] = nouislider;
2237
2237
 
2238
2238
  Object.defineProperty(exports, '__esModule', { value: true });
2239
2239
 
2240
- })));
2240
+ }));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pageboard/html",
3
- "version": "0.10.14",
3
+ "version": "0.11.0",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -24,7 +24,7 @@
24
24
  },
25
25
  "devDependencies": {
26
26
  "formdata-polyfill": "^4.0.10",
27
- "nouislider": "^15.5.0",
27
+ "nouislider": "^15.5.1",
28
28
  "object-fit-images": "^3.2.4",
29
29
  "postinstall-bundle": "^0.7.4"
30
30
  },
@@ -1,62 +1,145 @@
1
+ class WalkIndex {
2
+ #walk;
3
+ #find;
4
+ #index;
5
+ constructor(root, fn) {
6
+ this.#find = fn;
7
+ this.#walk = root.ownerDocument.createTreeWalker(
8
+ root,
9
+ NodeFilter.SHOW_ELEMENT,
10
+ this
11
+ );
12
+ }
13
+ acceptNode(node) {
14
+ const index = this.#find(node);
15
+ if (index != null) {
16
+ this.#index = index;
17
+ return NodeFilter.FILTER_ACCEPT;
18
+ } else {
19
+ return NodeFilter.FILTER_SKIP;
20
+ }
21
+ }
22
+ findBefore(node) {
23
+ this.#index = null;
24
+ this.#walk.currentNode = node;
25
+ this.#walk.previousNode();
26
+ return this.#index;
27
+ }
28
+ }
29
+
1
30
  class HTMLElementFieldsetList extends VirtualHTMLElement {
31
+ #size;
32
+ #prefix;
33
+ #model;
34
+ #walk;
35
+
2
36
  fill(values, scope) {
3
- const list = this.listFromValues(Object.assign({}, values));
4
- this.resize(list.length, scope);
37
+ const list = this.#listFromValues({ ...values });
38
+ this.#resize(list.length, scope);
5
39
  }
6
40
 
7
- patch(state) {
41
+ #prepare() {
8
42
  this.ownTpl.prerender();
9
43
  if (this.isContentEditable) return;
10
- if (!this.size) this.resize(0, state.scope);
44
+ for (const node of this.ownTpl.content.querySelectorAll('[block-id]')) {
45
+ node.removeAttribute('block-id');
46
+ }
47
+ const keys = new Set();
48
+ const inputs = this.ownTpl.content.querySelectorAll('[name]');
49
+ for (const node of inputs) {
50
+ keys.add(node.name);
51
+ }
52
+ const splits = Array.from(keys).map(name => name.split('.'));
53
+ const coms = [];
54
+ let pos = 0, com = null;
55
+ while (splits.every(list => {
56
+ if (com == null) {
57
+ if (pos < list.length) {
58
+ com = list[pos];
59
+ return true;
60
+ } else {
61
+ return false;
62
+ }
63
+ } else {
64
+ return list[pos] == com;
65
+ }
66
+ })) {
67
+ coms.push(com);
68
+ com = null;
69
+ pos++;
70
+ }
71
+ if (coms.length) coms.push('');
72
+ const prefix = coms.join('.');
73
+ this.#prefix = prefix;
74
+ const model = {};
75
+ for (const key of keys) {
76
+ if (key.startsWith(prefix)) model[key.substring(prefix.length)] = null;
77
+ }
78
+ this.#model = model;
11
79
  }
12
80
 
13
- setup(state) {
14
- this.ownTpl.prerender();
81
+ patch(state) {
82
+ this.#prepare();
83
+ if (!this.#size) this.#resize(0, state.scope);
15
84
  }
16
85
 
17
- resize(size, scope) {
18
- const len = Math.max(Number(this.dataset.size) || 0, size);
19
- if (this.size == len) return;
20
- this.size = len;
86
+ setup() {
87
+ this.#prepare();
88
+ }
21
89
 
22
- const tpl = this.ownTpl.content.cloneNode(true);
23
- for (const node of tpl.querySelectorAll('[block-id]')) {
24
- node.removeAttribute('block-id');
25
- }
26
- const anc = tpl.querySelectorAll('[name]:not(button)').ancestor();
90
+ #selector(name) {
91
+ return `[block-type="fieldlist_button"][value="${name}"]`;
92
+ }
27
93
 
28
- for (let i = len - 1; i >= 1; i--) {
29
- const clone = this.updateAncestor(anc.cloneNode(true), i);
30
- clone.fuse({ $fieldset: { index: i } }, scope);
31
- anc.parentNode.insertBefore(clone, anc.nextSibling);
94
+ #resize(size, scope) {
95
+ if (this.isContentEditable) return;
96
+ const len = Math.max(Number(this.dataset.size) || 0, size);
97
+ if (this.#size === len) return;
98
+ this.#size = len;
99
+ let tpl = this.ownTpl.content.cloneNode(true);
100
+ const $fieldset = Array.from(Array(len)).map((x, i) => {
101
+ return { index: i };
102
+ });
103
+ const inputs = tpl.querySelectorAll('[name]');
104
+ const prefix = this.#prefix;
105
+ for (const node of inputs) {
106
+ if (node.name.startsWith(prefix)) {
107
+ node.name = `${prefix}[$field.index].${node.name.substring(prefix.length)}`;
108
+ }
109
+ }
110
+ const subtpl = inputs.ancestor();
111
+ if (!subtpl) {
112
+ console.warn("fieldset-list should contain input[name]", this);
113
+ return;
32
114
  }
33
- this.updateAncestor(anc, 0);
34
- anc.fuse({ $fieldset: { index: 0 } }, scope);
35
- tpl.fuse({ $fieldset: { count: len } }, scope);
115
+ subtpl.appendChild(
116
+ subtpl.ownerDocument.createTextNode('[$fieldset|repeat:*:$field|]')
117
+ );
118
+ if (len == 0) {
119
+ let node = tpl.querySelector(this.#selector('add'));
120
+ while (node != null && node != tpl && node != subtpl) {
121
+ while (node.nextSibling) node.nextSibling.remove();
122
+ while (node.previousSibling) node.previousSibling.remove();
123
+ node = node.parentNode;
124
+ }
125
+ }
126
+ tpl = tpl.fuse({ $fieldset }, scope);
127
+
36
128
  const view = this.ownView;
37
129
  view.textContent = '';
38
130
  view.appendChild(tpl);
39
- }
40
131
 
41
- updateAncestor(node, i) {
42
- const prefix = this.prefix;
43
- for (const child of node.querySelectorAll('[name]:not(button)')) {
44
- child.name = `${prefix}${i}.${child.name}`;
45
- }
46
- return node;
132
+ view.querySelectorAll(this.#selector('up')).forEach((node, i) => {
133
+ node.disabled = i == 0;
134
+ });
135
+ view.querySelectorAll(this.#selector('down')).forEach((node, i, arr) => {
136
+ node.disabled = i == arr.length - 1;
137
+ });
47
138
  }
48
139
 
49
- modelFromTemplate() {
50
- const obj = {};
51
- for (const node of this.ownTpl.content.querySelectorAll('[name]:not(button)')) {
52
- obj[node.name] = null;
53
- }
54
- return obj;
55
- }
56
-
57
- listFromValues(values) {
140
+ #listFromValues(values) {
58
141
  const list = [];
59
- const prefix = this.prefix;
142
+ const prefix = this.#prefix;
60
143
  // just unflatten the array
61
144
  for (const [key, val] of Object.entries(values)) {
62
145
  if (!key.startsWith(prefix)) continue;
@@ -71,8 +154,8 @@ class HTMLElementFieldsetList extends VirtualHTMLElement {
71
154
  return list;
72
155
  }
73
156
 
74
- listToValues(values, list) {
75
- const prefix = this.prefix;
157
+ #listToValues(values, list) {
158
+ const prefix = this.#prefix;
76
159
  for (let i = 0; i < list.length; i++) {
77
160
  const obj = list[i];
78
161
  for (const [key, val] of Object.entries(obj)) {
@@ -83,23 +166,47 @@ class HTMLElementFieldsetList extends VirtualHTMLElement {
83
166
 
84
167
  handleClick(e, state) {
85
168
  if (this.isContentEditable) return;
86
- const btn = e.target.closest('button[type="button"][name]');
169
+ const btn = e.target.closest('button');
87
170
  if (!btn) return;
88
- if (["add", "del"].includes(btn.name) == false) return;
171
+ const action = btn.value;
172
+ if (["add", "del", "up", "down"].includes(action) == false) return;
89
173
 
90
174
  const form = this.closest('form');
91
175
  const values = form.read(true);
92
- const list = this.listFromValues(values);
93
- const index = Number(btn.value);
94
- if (!Number.isInteger(index) || index < 0 || index > list.length) {
95
- throw new Error(`fieldset-list expects ${btn.outerHTML} to have a value with a valid index`);
96
- }
97
- if (btn.name == "add") {
98
- list.splice(index + 1, 0, this.modelFromTemplate());
99
- } else if (btn.name == "del") {
100
- list.splice(index, 1);
176
+ const list = this.#listFromValues(values);
177
+ const prefix = this.#prefix;
178
+ if (!this.#walk) this.#walk = new WalkIndex(this, (node) => {
179
+ if (node.name?.startsWith(prefix)) {
180
+ const index = Number(node.name.substring(prefix.length).split('.').shift());
181
+ if (Number.isInteger(index) || index >= 0 || index < list.length) {
182
+ return index;
183
+ }
184
+ }
185
+ return null;
186
+ });
187
+ let index;
188
+
189
+ switch (action) {
190
+ case "add":
191
+ list.splice((this.#walk.findBefore(btn) ?? -1) + 1, 0, this.#model);
192
+ break;
193
+ case "del":
194
+ list.splice(this.#walk.findBefore(btn) ?? 0, 1);
195
+ break;
196
+ case "up":
197
+ index = this.querySelectorAll(this.#selector('up')).indexOf(btn);
198
+ if (index > 0) {
199
+ list.splice(index - 1, 0, list.splice(index, 1).pop());
200
+ }
201
+ break;
202
+ case "down":
203
+ index = this.querySelectorAll(this.#selector('down')).indexOf(btn);
204
+ if (index < list.length - 1) {
205
+ list.splice(index + 1, 0, list.splice(index, 1).pop());
206
+ }
207
+ break;
101
208
  }
102
- this.listToValues(values, list);
209
+ this.#listToValues(values, list);
103
210
  form.fill(values, state.scope);
104
211
  }
105
212
 
@@ -111,14 +218,6 @@ class HTMLElementFieldsetList extends VirtualHTMLElement {
111
218
  get ownView() {
112
219
  return this.children.find(node => node.matches('.view'));
113
220
  }
114
- get prefix() {
115
- const prefix = this.dataset.prefix;
116
- if (prefix) return prefix + ".";
117
- else return "";
118
- }
119
221
  }
120
222
 
121
223
  VirtualHTMLElement.define('element-fieldset-list', HTMLElementFieldsetList);
122
-
123
-
124
-
package/ui/fieldset.js CHANGED
@@ -15,8 +15,8 @@ class HTMLCustomFieldSetElement extends HTMLFieldSetElement {
15
15
  this.disabled = this.hidden = val != this.options.value;
16
16
  }
17
17
 
18
- patch() {
19
- this.#update();
18
+ patch(state) {
19
+ state.finish(() => this.#update());
20
20
  }
21
21
  setup() {
22
22
  this.form?.addEventListener('change', this);