@schukai/monster 3.71.2 → 3.72.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 (117) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/package.json +1 -1
  3. package/source/components/datatable/dataset.mjs +272 -272
  4. package/source/components/datatable/datasource/dom.mjs +1 -1
  5. package/source/components/datatable/datasource/rest.mjs +408 -410
  6. package/source/components/datatable/filter.mjs +0 -1
  7. package/source/components/datatable/style/datatable.pcss +7 -5
  8. package/source/components/datatable/style/embedded-pagination.pcss +1 -1
  9. package/source/components/datatable/style/pagination.pcss +1 -1
  10. package/source/components/datatable/stylesheet/change-button.mjs +2 -4
  11. package/source/components/datatable/stylesheet/column-bar.mjs +2 -4
  12. package/source/components/datatable/stylesheet/dataset.mjs +2 -4
  13. package/source/components/datatable/stylesheet/datasource.mjs +1 -3
  14. package/source/components/datatable/stylesheet/datatable.mjs +2 -4
  15. package/source/components/datatable/stylesheet/embedded-pagination.mjs +1 -1
  16. package/source/components/datatable/stylesheet/filter-button.mjs +1 -3
  17. package/source/components/datatable/stylesheet/filter-controls-defaults.mjs +14 -7
  18. package/source/components/datatable/stylesheet/filter-date-range.mjs +1 -3
  19. package/source/components/datatable/stylesheet/filter-range.mjs +1 -3
  20. package/source/components/datatable/stylesheet/filter.mjs +2 -4
  21. package/source/components/datatable/stylesheet/pagination.mjs +2 -4
  22. package/source/components/datatable/stylesheet/save-button.mjs +2 -4
  23. package/source/components/datatable/stylesheet/select-filter.mjs +2 -4
  24. package/source/components/datatable/stylesheet/status.mjs +2 -4
  25. package/source/components/form/context-error.mjs +0 -2
  26. package/source/components/form/context-help.mjs +1 -2
  27. package/source/components/form/field-set.mjs +219 -219
  28. package/source/components/form/form.mjs +137 -187
  29. package/source/components/form/reload.mjs +211 -211
  30. package/source/components/form/select.mjs +12 -13
  31. package/source/components/form/style/field-set.pcss +2 -2
  32. package/source/components/form/style/form.pcss +8 -0
  33. package/source/components/form/stylesheet/action-button.mjs +2 -4
  34. package/source/components/form/stylesheet/api-button.mjs +1 -3
  35. package/source/components/form/stylesheet/button-bar.mjs +2 -4
  36. package/source/components/form/stylesheet/button.mjs +2 -4
  37. package/source/components/form/stylesheet/confirm-button.mjs +2 -4
  38. package/source/components/form/stylesheet/context-error.mjs +2 -4
  39. package/source/components/form/stylesheet/context-help.mjs +2 -4
  40. package/source/components/form/stylesheet/field-set.mjs +14 -7
  41. package/source/components/form/stylesheet/form.mjs +1 -1
  42. package/source/components/form/stylesheet/message-state-button.mjs +1 -3
  43. package/source/components/form/stylesheet/popper-button.mjs +2 -4
  44. package/source/components/form/stylesheet/select.mjs +14 -7
  45. package/source/components/form/stylesheet/state-button.mjs +2 -4
  46. package/source/components/form/stylesheet/tree-select.mjs +1 -3
  47. package/source/components/host/stylesheet/call-button.mjs +2 -4
  48. package/source/components/host/stylesheet/config-manager.mjs +1 -3
  49. package/source/components/host/stylesheet/host.mjs +2 -4
  50. package/source/components/host/stylesheet/overlay.mjs +2 -4
  51. package/source/components/host/stylesheet/toggle-button.mjs +2 -4
  52. package/source/components/host/stylesheet/viewer.mjs +2 -4
  53. package/source/components/layout/style/collapse.pcss +2 -2
  54. package/source/components/layout/style/details.pcss +2 -2
  55. package/source/components/layout/stylesheet/collapse.mjs +14 -7
  56. package/source/components/layout/stylesheet/details.mjs +2 -4
  57. package/source/components/layout/stylesheet/panel.mjs +2 -4
  58. package/source/components/layout/stylesheet/popper.mjs +2 -4
  59. package/source/components/layout/stylesheet/split-panel.mjs +1 -3
  60. package/source/components/layout/stylesheet/tabs.mjs +2 -4
  61. package/source/components/layout/stylesheet/width-toggle.mjs +1 -3
  62. package/source/components/navigation/stylesheet/table-of-content.mjs +2 -4
  63. package/source/components/notify/stylesheet/message.mjs +2 -4
  64. package/source/components/notify/stylesheet/notify.mjs +2 -4
  65. package/source/components/state/stylesheet/log.mjs +2 -4
  66. package/source/components/state/stylesheet/state.mjs +2 -4
  67. package/source/components/style/control.pcss +5 -0
  68. package/source/components/style/data-grid.pcss +2 -2
  69. package/source/components/style/mixin/typography.pcss +7 -1
  70. package/source/components/style/normalize.pcss +1 -1
  71. package/source/components/stylesheet/badge.mjs +1 -3
  72. package/source/components/stylesheet/border.mjs +1 -3
  73. package/source/components/stylesheet/button.mjs +1 -3
  74. package/source/components/stylesheet/card.mjs +1 -3
  75. package/source/components/stylesheet/color.mjs +1 -3
  76. package/source/components/stylesheet/common.mjs +1 -3
  77. package/source/components/stylesheet/control.mjs +2 -4
  78. package/source/components/stylesheet/data-grid.mjs +2 -4
  79. package/source/components/stylesheet/display.mjs +1 -3
  80. package/source/components/stylesheet/floating-ui.mjs +1 -3
  81. package/source/components/stylesheet/form.mjs +13 -6
  82. package/source/components/stylesheet/host.mjs +1 -3
  83. package/source/components/stylesheet/icons.mjs +1 -3
  84. package/source/components/stylesheet/mixin/badge.mjs +1 -3
  85. package/source/components/stylesheet/mixin/button.mjs +1 -3
  86. package/source/components/stylesheet/mixin/form.mjs +13 -6
  87. package/source/components/stylesheet/mixin/hover.mjs +1 -3
  88. package/source/components/stylesheet/mixin/icon.mjs +1 -3
  89. package/source/components/stylesheet/mixin/media.mjs +1 -3
  90. package/source/components/stylesheet/mixin/property.mjs +13 -6
  91. package/source/components/stylesheet/mixin/skeleton.mjs +1 -3
  92. package/source/components/stylesheet/mixin/spinner.mjs +1 -3
  93. package/source/components/stylesheet/mixin/typography.mjs +1 -3
  94. package/source/components/stylesheet/normalize.mjs +1 -3
  95. package/source/components/stylesheet/popper.mjs +1 -3
  96. package/source/components/stylesheet/property.mjs +2 -4
  97. package/source/components/stylesheet/ripple.mjs +1 -3
  98. package/source/components/stylesheet/skeleton.mjs +1 -3
  99. package/source/components/stylesheet/space.mjs +1 -3
  100. package/source/components/stylesheet/spinner.mjs +1 -3
  101. package/source/components/stylesheet/table.mjs +1 -3
  102. package/source/components/stylesheet/theme.mjs +1 -3
  103. package/source/components/stylesheet/typography.mjs +13 -6
  104. package/source/components/tree-menu/dragable-tree-menu.mjs +693 -0
  105. package/source/components/tree-menu/style/tree-menu.pcss +69 -42
  106. package/source/components/tree-menu/stylesheet/tree-menu.mjs +8 -17
  107. package/source/components/tree-menu/tree-menu.mjs +468 -532
  108. package/source/data/datasource/server/restapi.mjs +194 -191
  109. package/source/data/datasource/server.mjs +107 -105
  110. package/source/data/diff.mjs +1 -1
  111. package/source/dom/customelement.mjs +2 -6
  112. package/source/dom/slotted.mjs +89 -85
  113. package/test/cases/components/host/details.mjs +1 -1
  114. package/test/cases/components/host/host.mjs +1 -1
  115. package/test/cases/components/host/overlay.mjs +1 -1
  116. package/test/cases/dom/customcontrol.mjs +1 -1
  117. package/test/cases/dom/customelement.mjs +2 -2
@@ -12,87 +12,61 @@
12
12
  * SPDX-License-Identifier: AGPL-3.0
13
13
  */
14
14
 
15
- import { buildTree } from "../../data/buildtree.mjs";
16
- import { Datasource } from "../../data/datasource.mjs";
17
- import { addAttributeToken } from "../../dom/attributes.mjs";
15
+ import {buildTree} from "../../data/buildtree.mjs";
16
+ import {Datasource} from "../datatable/datasource.mjs";
17
+ import {addAttributeToken} from "../../dom/attributes.mjs";
18
18
  import {
19
- ATTRIBUTE_DISABLED,
20
- ATTRIBUTE_ERRORMESSAGE,
21
- ATTRIBUTE_ROLE,
22
- ATTRIBUTE_UPDATER_INSERT_REFERENCE,
19
+ ATTRIBUTE_ERRORMESSAGE,
20
+ ATTRIBUTE_ROLE,
21
+ ATTRIBUTE_UPDATER_INSERT_REFERENCE,
23
22
  } from "../../dom/constants.mjs";
24
23
  import {
25
- assembleMethodSymbol,
26
- CustomElement,
27
- initMethodSymbol,
28
- registerCustomElement,
24
+ assembleMethodSymbol,
25
+ CustomElement, getSlottedElements,
26
+ initMethodSymbol,
27
+ registerCustomElement,
29
28
  } from "../../dom/customelement.mjs";
30
- import { findTargetElementFromEvent } from "../../dom/events.mjs";
31
- import { Formatter } from "../../text/formatter.mjs";
32
- import { isObject } from "../../types/is.mjs";
33
- import { Node } from "../../types/node.mjs";
34
- import { NodeRecursiveIterator } from "../../types/noderecursiveiterator.mjs";
35
- import { Observer } from "../../types/observer.mjs";
36
- import { ProxyObserver } from "../../types/proxyobserver.mjs";
37
- import { validateInstance } from "../../types/validate.mjs";
38
- import { ATTRIBUTE_INTEND } from "./../constants.mjs";
39
- import { CommonStyleSheet } from "../stylesheet/common.mjs";
40
- import { TreeMenuStyleSheet } from "./stylesheet/tree-menu.mjs";
41
-
42
- export { TreeMenu };
43
-
44
- /**
45
- * @private
46
- * @type {symbol}
47
- */
48
- const internalNodesSymbol = Symbol("internalNodes");
49
-
50
- /**
51
- * @private
52
- * @type {symbol}
53
- */
54
- const controlElementSymbol = Symbol("controlElement");
55
-
56
- /**
57
- * @private
58
- * @type {symbol}
59
- */
60
- const openEntryEventHandlerSymbol = Symbol("openEntryEventHandler");
29
+ import {findTargetElementFromEvent} from "../../dom/events.mjs";
30
+ import {findElementWithSelectorUpwards} from "../../dom/util.mjs";
31
+ import {Formatter} from "../../text/formatter.mjs";
32
+ import {isFunction, isString} from "../../types/is.mjs";
33
+ import {Node} from "../../types/node.mjs";
34
+ import {NodeRecursiveIterator} from "../../types/noderecursiveiterator.mjs";
35
+ import {Observer} from "../../types/observer.mjs";
36
+ import {validateInstance} from "../../types/validate.mjs";
37
+ import {
38
+ datasourceLinkedElementSymbol,
39
+ handleDataSourceChanges,
40
+ } from "../datatable/util.mjs";
41
+ import {ATTRIBUTE_INTEND} from "./../constants.mjs";
42
+ import {CommonStyleSheet} from "../stylesheet/common.mjs";
43
+ import {TreeMenuStyleSheet} from "./stylesheet/tree-menu.mjs";
61
44
 
62
- /**
63
- * @private
64
- * @type {symbol}
65
- */
66
- const dragstartEventHandlerSymbol = Symbol("dragstartEventHandler");
67
- /**
68
- * @private
69
- * @type {symbol}
70
- */
71
- const dragenterEventHandlerSymbol = Symbol("dragenterEventHandler");
45
+ export {TreeMenu};
72
46
 
73
47
  /**
74
48
  * @private
75
49
  * @type {symbol}
76
50
  */
77
- const dragleaveEventHandlerSymbol = Symbol("dragleaveEventHandler");
51
+ const internalNodesSymbol = Symbol("internalNodes");
78
52
 
79
53
  /**
80
54
  * @private
81
55
  * @type {symbol}
82
56
  */
83
- const dragEventHandlerSymbol = Symbol("dragEventHandler");
57
+ const preventChangeSymbol = Symbol("preventChangeCounter");
84
58
 
85
59
  /**
86
60
  * @private
87
61
  * @type {symbol}
88
62
  */
89
- const dragoverEventHandlerSymbol = Symbol("dragoverEventHandler");
63
+ const controlElementSymbol = Symbol("controlElement");
90
64
 
91
65
  /**
92
66
  * @private
93
67
  * @type {symbol}
94
68
  */
95
- const dropEventHandlerSymbol = Symbol("dropEventHandlerSymbol");
69
+ const openEntryEventHandlerSymbol = Symbol("openEntryEventHandler");
96
70
 
97
71
  /**
98
72
  * TreeMenu
@@ -121,540 +95,502 @@ const dropEventHandlerSymbol = Symbol("dropEventHandlerSymbol");
121
95
  * @enduml
122
96
  * @since 1.0.0
123
97
  * @copyright schukai GmbH
124
- * @memberOf Monster.Components.TreeMenu
125
98
  * @summary A TreeMenu control
126
99
  * @fires Monster.Components.TreeMenu.event:monster-fetched
127
100
  */
128
101
  class TreeMenu extends CustomElement {
129
- /**
130
- * This method is called internal and should not be called directly.
131
- *
132
- * The defaults can be set either directly in the object or via an attribute in the HTML tag.
133
- * The value of the attribute `data-monster-options` in the HTML tag must be a JSON string.
134
- *
135
- * ```
136
- * <monster-treemenu data-monster-options="{}"></monster-treemenu>
137
- * ```
138
- *
139
- * Since 1.18.0 the JSON can be specified as a DataURI.
140
- *
141
- * ```
142
- * new Monster.Types.DataUrl(btoa(JSON.stringify({
143
- * shadowMode: 'open',
144
- * })),'application/json',true).toString()
145
- * ```
146
- * @property {Object} toggleEventType=click,touch List of event types to be observed for opening the dropdown
147
- * @property {Object} templates Template definitions
148
- * @property {string} templates.main Main template
149
- * @property {Datasource} datasource data source
150
- * @property {Object} mapping
151
- * @property {String} mapping.selector=* Path to select the appropriate entries
152
- * @property {String} mapping.labelTemplate="" template with the label placeholders in the form ${name}, where name is the key
153
- * @property {String} mapping.keyTemplate="" template with the key placeholders in the form ${name}, where name is the key
154
- * @property {String} mapping.rootReferences=['0', undefined, null]
155
- * @property {String} mapping.idTemplate=id
156
- * @property {String} mapping.parentTemplate=parent
157
- * @property {String} mapping.selection
158
- */
159
- get defaults() {
160
- return Object.assign(
161
- {},
162
- super.defaults,
163
- {
164
- toggleEventType: ["click", "touch"],
165
- mapping: {
166
- rootReferences: ["0", undefined, null],
167
- idTemplate: "id",
168
- parentTemplate: "parent",
169
- selector: "*",
170
- labelTemplate: "",
171
- valueTemplate: "",
172
- filter: undefined,
173
- },
174
- templates: {
175
- main: getTemplate(),
176
- },
177
- datasource: undefined,
178
- entries: [],
179
- },
180
- initOptionsFromArguments.call(this),
181
- );
182
- }
183
-
184
- /**
185
- * This method determines which attributes are to be monitored by `attributeChangedCallback()`.
186
- *
187
- * @return {string[]}
188
- * @since 1.15.0
189
- */
190
- static get observedAttributes() {
191
- const list = super.observedAttributes;
192
- //list.push(ATTRIBUTE_FORM_URL);
193
- return list;
194
- }
195
-
196
- /**
197
- *
198
- */
199
- [initMethodSymbol]() {
200
- super[initMethodSymbol]();
201
- }
202
-
203
- /**
204
- *
205
- * @return {Monster.Components.TreeMenu.Form}
206
- */
207
- [assembleMethodSymbol]() {
208
- super[assembleMethodSymbol]();
209
-
210
- initControlReferences.call(this);
211
- initEventHandler.call(this);
212
- importEntriesFromDatasource.call(this);
213
- initObserver.call(this);
214
-
215
- return this;
216
- }
217
-
218
- /**
219
- * This method is called internal and should not be called directly.
220
- *
221
- * @return {CSSStyleSheet[]}
222
- */
223
- static getCSSStyleSheet() {
224
- return [CommonStyleSheet, TreeMenuStyleSheet];
225
- }
226
-
227
- /**
228
- * This method is called internal and should not be called directly.
229
- *
230
- * @return {string}
231
- */
232
- static getTag() {
233
- return "monster-tree-menu";
234
- }
102
+
103
+ constructor() {
104
+ super();
105
+ this[preventChangeSymbol] = false;
106
+ }
107
+
108
+ /**
109
+ * This method is called internal and should not be called directly.
110
+ *
111
+ * The defaults can be set either directly in the object or via an attribute in the HTML tag.
112
+ * The value of the attribute `data-monster-options` in the HTML tag must be a JSON string.
113
+ *
114
+ * ```
115
+ * <monster-treemenu data-monster-options="{}"></monster-treemenu>
116
+ * ```
117
+ *
118
+ * Since 1.18.0 the JSON can be specified as a DataURI.
119
+ *
120
+ * ```
121
+ * new Monster.Types.DataUrl(btoa(JSON.stringify({
122
+ * shadowMode: 'open',
123
+ * })),'application/json',true).toString()
124
+ * ```
125
+ * @property {Object} templates Template definitions
126
+ * @property {string} templates.main Main template
127
+ * @property {Datasource} datasource data source
128
+ * @property {Object} mapping
129
+ * @property {String} mapping.selector=* Path to select the appropriate entries
130
+ * @property {String} mapping.labelTemplate="" template with the label placeholders in the form ${name}, where name is the key
131
+ * @property {String} mapping.keyTemplate="" template with the key placeholders in the form ${name}, where name is the key
132
+ * @property {String} mapping.rootReferences=['0', undefined, null]
133
+ * @property {String} mapping.idTemplate=id
134
+ * @property {String} mapping.parentKey=parent
135
+ * @property {String} mapping.selection
136
+ */
137
+ get defaults() {
138
+ return Object.assign({}, super.defaults, {
139
+
140
+ classes: {
141
+ control: "monster-theme-primary-1",
142
+ label: "monster-theme-primary-1"
143
+ },
144
+
145
+ mapping: {
146
+ rootReferences: ["0", undefined, null],
147
+ idTemplate: "id",
148
+ parentKey: "parent",
149
+ selector: "*",
150
+ labelTemplate: "",
151
+ valueTemplate: "",
152
+ iconTemplate: "",
153
+ filter: undefined,
154
+ },
155
+
156
+ templates: {
157
+ main: getTemplate(),
158
+ },
159
+
160
+ datasource: {
161
+ selector: null,
162
+ },
163
+
164
+ actions: {
165
+ "open": null,
166
+ "close": null,
167
+ "select": (entry) => {
168
+ throw new Error("no action defined for select");
169
+ },
170
+
171
+ },
172
+
173
+ data: [],
174
+ entries: [],
175
+ });
176
+ }
177
+
178
+ /**
179
+ *
180
+ */
181
+ [initMethodSymbol]() {
182
+ super[initMethodSymbol]();
183
+ }
184
+
185
+ /**
186
+ * @return {void}
187
+ */
188
+ [assembleMethodSymbol]() {
189
+ super[assembleMethodSymbol]();
190
+
191
+ initControlReferences.call(this);
192
+ initEventHandler.call(this);
193
+ initObserver.call(this);
194
+ setTimeout(() => {
195
+ copyIconMap.call(this);
196
+ }, 0)
197
+ }
198
+
199
+ /**
200
+ * This method is called internal and should not be called directly.
201
+ *
202
+ * @return {CSSStyleSheet[]}
203
+ */
204
+ static getCSSStyleSheet() {
205
+ return [CommonStyleSheet, TreeMenuStyleSheet];
206
+ }
207
+
208
+ /**
209
+ * This method is called internal and should not be called directly.
210
+ *
211
+ * @return {string}
212
+ */
213
+ static getTag() {
214
+ return "monster-tree-menu";
215
+ }
216
+
217
+ /**
218
+ * @param {string} value
219
+ * @param value
220
+ */
221
+ selectEntry(value) {
222
+ this.shadowRoot.querySelectorAll("[data-monster-role=entry]").forEach((entry) => {
223
+ entry.classList.remove("selected");
224
+ })
225
+
226
+ value = String(value);
227
+
228
+ const entries = this.getOption("entries");
229
+ const index = entries.findIndex((entry) => entry.value === value);
230
+
231
+ if (index === -1) {
232
+ return;
233
+ }
234
+
235
+ const currentNode = this.shadowRoot.querySelector("[data-monster-insert-reference=entries-" + index + "]")
236
+
237
+ console.log(currentNode)
238
+
239
+ currentNode.click();
240
+
241
+ let intend = parseInt(currentNode.getAttribute(ATTRIBUTE_INTEND));
242
+
243
+ if (intend > 0) {
244
+ let ref = currentNode.previousElementSibling;
245
+ while (ref && ref.hasAttribute(ATTRIBUTE_INTEND)) {
246
+ const i = parseInt(ref.getAttribute(ATTRIBUTE_INTEND));
247
+
248
+ if (isNaN(i)) {
249
+ break;
250
+ }
251
+
252
+ if (i < intend) {
253
+
254
+ if (ref.getAttribute("data-monster-state") !== "open") {
255
+ ref.click()
256
+ }
257
+
258
+ if (i === 0) {
259
+ break;
260
+ }
261
+ intend = i;
262
+ }
263
+ ref = ref.previousElementSibling;
264
+ }
265
+ }
266
+
267
+ }
268
+
269
+
270
+ }
271
+
272
+ /**
273
+ * @private
274
+ */
275
+ function copyIconMap() {
276
+ const nodes = getSlottedElements.call(this, "svg", null);
277
+ if (nodes.size > 0) {
278
+ for (const node of nodes) {
279
+ this.shadowRoot.appendChild(node);
280
+ }
281
+ }
235
282
  }
236
283
 
237
284
  /**
238
285
  * @private
239
286
  */
240
287
  function initEventHandler() {
241
- switchToConfig.call(this);
242
-
243
- this[openEntryEventHandlerSymbol] = (event) => {
244
- const container = findTargetElementFromEvent(
245
- event,
246
- ATTRIBUTE_ROLE,
247
- "entry",
248
- );
249
- if (!(container instanceof HTMLElement)) {
250
- return;
251
- }
252
-
253
- //let container = findClosestByAttribute(element, ATTRIBUTE_ROLE, 'option');
254
- const index = container
255
- .getAttribute(ATTRIBUTE_UPDATER_INSERT_REFERENCE)
256
- .split("-")
257
- .pop();
258
-
259
- const currentState = this.getOption("entries." + index + ".state");
260
-
261
- const newState = currentState === "close" ? "open" : "close";
262
- this.setOption("entries." + index + ".state", newState);
263
-
264
- const newVisibility = newState === "open" ? "visible" : "hidden";
265
-
266
- if (container.hasAttribute(ATTRIBUTE_INTEND)) {
267
- const intend = container.getAttribute(ATTRIBUTE_INTEND);
268
-
269
- let ref = container.nextElementSibling;
270
- const childIntend = parseInt(intend) + 1;
271
-
272
- const cmp = (a, b) => {
273
- if (newState === "open") {
274
- return a === b;
275
- }
276
-
277
- return a >= b;
278
- };
279
-
280
- while (
281
- ref &&
282
- ref.hasAttribute(ATTRIBUTE_INTEND) &&
283
- cmp(parseInt(ref.getAttribute(ATTRIBUTE_INTEND)), childIntend)
284
- ) {
285
- const refIndex = ref
286
- .getAttribute(ATTRIBUTE_UPDATER_INSERT_REFERENCE)
287
- .split("-")
288
- .pop();
289
- this.setOption("entries." + refIndex + ".visibility", newVisibility);
290
-
291
- if (newState === "close") {
292
- this.setOption("entries." + refIndex + ".state", "close");
293
- }
294
-
295
- ref = ref.nextElementSibling;
296
- }
297
- }
298
- };
299
-
300
- const types = this.getOption("toggleEventType", ["click"]);
301
- for (const [, type] of Object.entries(types)) {
302
- this.shadowRoot.addEventListener(type, this[openEntryEventHandlerSymbol]);
303
- }
304
-
305
- // for (const [, type] of Object.entries(types)) {
306
- //
307
- // self[controlElementSymbol].addEventListener(type, function (event) {
308
- //
309
- // const element = findTargetElementFromEvent(event, ATTRIBUTE_ROLE, 'entry');
310
- // if (!(element instanceof HTMLElement)) {
311
- // return;
312
- // }
313
- //
314
- // toggle.call(self);
315
- //
316
- //
317
- // })
318
- //
319
- // }
320
-
321
- return this;
288
+ const selector = this.getOption("datasource.selector");
289
+
290
+ if (isString(selector)) {
291
+ const element = findElementWithSelectorUpwards(this, selector);
292
+ if (element === null) {
293
+ throw new Error("the selector must match exactly one element");
294
+ }
295
+
296
+ if (!(element instanceof HTMLElement)) {
297
+ throw new TypeError("the element must be an HTMLElement");
298
+ }
299
+
300
+ customElements.whenDefined(element.tagName.toLocaleLowerCase()).then(() => {
301
+ if (!(element instanceof Datasource)) {
302
+ throw new TypeError("the element must be a datasource");
303
+ }
304
+
305
+ this[datasourceLinkedElementSymbol] = element;
306
+
307
+ handleDataSourceChanges.call(this);
308
+ element.datasource.attachObserver(
309
+ new Observer(handleDataSourceChanges.bind(this)),
310
+ );
311
+
312
+ this.attachObserver(
313
+ new Observer(() => {
314
+ if (this[preventChangeSymbol] === true) {
315
+ return
316
+ }
317
+ this[preventChangeSymbol] = true
318
+ importEntries.call(this);
319
+ }),
320
+ );
321
+ });
322
+ }
323
+
324
+ this[openEntryEventHandlerSymbol] = (event) => {
325
+
326
+ const container = findTargetElementFromEvent(
327
+ event,
328
+ ATTRIBUTE_ROLE,
329
+ "entry",
330
+ );
331
+
332
+ if (!(container instanceof HTMLElement)) {
333
+ return;
334
+ }
335
+
336
+ const index = container
337
+ .getAttribute(ATTRIBUTE_UPDATER_INSERT_REFERENCE)
338
+ .split("-")
339
+ .pop();
340
+
341
+ const currentEntry = this.getOption("entries." + index);
342
+
343
+ if (currentEntry["has-children"] === false) {
344
+ const doAction = this.getOption("actions.select");
345
+
346
+ this.shadowRoot.querySelectorAll("[data-monster-role=entry].selected").forEach((entry) => {
347
+ entry.classList.remove("selected");
348
+ })
349
+
350
+ let intend = currentEntry.intend;
351
+ if (intend > 0) {
352
+ let ref = container.previousElementSibling;
353
+ while (ref && ref.hasAttribute(ATTRIBUTE_INTEND)) {
354
+ const i = parseInt(ref.getAttribute(ATTRIBUTE_INTEND));
355
+
356
+ if (isNaN(i)) {
357
+ break;
358
+ }
359
+
360
+ if (i < intend) {
361
+ ref.classList.add("selected");
362
+ if (i === 0) {
363
+ break;
364
+ }
365
+ intend = i;
366
+ }
367
+ ref = ref.previousElementSibling;
368
+ }
369
+ }
370
+
371
+ container.classList.add("selected");
372
+
373
+ if (isFunction(doAction)) {
374
+ doAction.call(this, currentEntry, index);
375
+ }
376
+ return;
377
+ }
378
+
379
+ const currentState = this.getOption("entries." + index + ".state");
380
+
381
+ const newState = currentState === "close" ? "open" : "close";
382
+
383
+ const doAction = this.getOption("actions." + newState);
384
+ if (isFunction(doAction)) {
385
+ doAction.call(this, this.getOption("entries." + index), index);
386
+ }
387
+
388
+ this.setOption("entries." + index + ".state", newState);
389
+ const newVisibility = (newState === "open") ? "visible" : "hidden";
390
+
391
+ if (container.hasAttribute(ATTRIBUTE_INTEND)) {
392
+ const intend = container.getAttribute(ATTRIBUTE_INTEND);
393
+ let ref = container.nextElementSibling;
394
+ const childIntend = parseInt(intend) + 1;
395
+
396
+ const cmp = (a, b) => {
397
+ if (newState === "open") {
398
+ return a === b;
399
+ }
400
+
401
+ return a >= b;
402
+ };
403
+
404
+ while (
405
+ ref &&
406
+ ref.hasAttribute(ATTRIBUTE_INTEND)
407
+ ) {
408
+
409
+ const refIntend = ref.getAttribute(ATTRIBUTE_INTEND);
410
+
411
+ if (!cmp(parseInt(refIntend), childIntend)) {
412
+ if (refIntend === intend) {
413
+ break;
414
+ }
415
+ ref = ref.nextElementSibling;
416
+ continue;
417
+ }
418
+
419
+ const refIndex = ref
420
+ .getAttribute(ATTRIBUTE_UPDATER_INSERT_REFERENCE)
421
+ .split("-")
422
+ .pop();
423
+
424
+ this.setOption("entries." + refIndex + ".visibility", newVisibility);
425
+
426
+ if (newState === "close") {
427
+ this.setOption("entries." + refIndex + ".state", "close");
428
+ }
429
+
430
+ ref = ref.nextElementSibling;
431
+ }
432
+ }
433
+ };
434
+
435
+ const types = this.getOption("toggleEventType", ["click"]);
436
+ for (const [, type] of Object.entries(types)) {
437
+ this.shadowRoot.addEventListener(type, this[openEntryEventHandlerSymbol]);
438
+ }
439
+
440
+ return this;
322
441
  }
323
442
 
324
443
  /**
325
444
  * @private
326
- * @this Form
445
+ * @this {TreeMenu}
327
446
  */
328
- function initObserver() {}
447
+ function initObserver() {
448
+ }
329
449
 
330
450
  /**
331
451
  * Import Menu Entries from dataset
332
452
  *
333
453
  * @since 1.0.0
334
- * @param {array|object|Map|Set} data
335
454
  * @return {TreeMenu}
336
455
  * @throws {Error} map is not iterable
337
456
  * @private
338
457
  */
339
- function importEntries(data) {
340
- this[internalNodesSymbol] = new Map();
341
-
342
- const mappingOptions = this.getOption("mapping", {});
343
-
344
- const filter = mappingOptions?.["filter"];
345
- const rootReferences = mappingOptions?.["rootReferences"];
346
-
347
- const id = this.getOption("mapping.idTemplate", "id");
348
- const parentID = this.getOption("mapping.parentTemplate", "parent");
349
-
350
- const selector = mappingOptions?.["selector"];
351
-
352
- const nodes = buildTree(data, selector, id, parentID, {
353
- filter,
354
- rootReferences,
355
- });
356
-
357
- const options = [];
358
- for (const node of nodes) {
359
- const iterator = new NodeRecursiveIterator(node);
360
- for (const n of iterator) {
361
- const formattedValues = formatKeyLabel.call(this, n);
362
-
363
- const label = formattedValues.label;
364
- const value = formattedValues.value;
365
- const intend = n.level;
366
-
367
- const visibility = intend > 0 ? "hidden" : "visible";
368
- const state = "close";
369
-
370
- this[internalNodesSymbol].set(value, n);
371
-
372
- options.push({
373
- value,
374
- label,
375
- intend,
376
- state,
377
- visibility,
378
- ["has-children"]: n.hasChildNodes(),
379
- });
380
- }
381
- }
382
-
383
- this.setOption("entries", options);
384
- return this;
385
- }
386
-
387
- /**
388
- * @private
389
- */
390
- function importEntriesFromDatasource() {
391
- const self = this;
392
- self.setAttribute(ATTRIBUTE_DISABLED, ATTRIBUTE_DISABLED);
393
-
394
- const datasource = self.getOption("datasource");
395
- if (!(datasource instanceof Datasource)) {
396
- addAttributeToken(
397
- self,
398
- ATTRIBUTE_ERRORMESSAGE,
399
- "datasource is not defined",
400
- );
401
- return;
402
- }
403
-
404
- datasource.attachObserver(
405
- new Observer(function () {
406
- if (isObject(this) && this instanceof ProxyObserver) {
407
- importEntries.call(self, datasource.get());
408
- }
409
- }),
410
- );
411
-
412
- datasource
413
- .read()
414
- .then(() => {
415
- new Processing(() => {
416
- self.removeAttribute(ATTRIBUTE_DISABLED);
417
- }).run();
418
- })
419
- .catch((e) => {
420
- addAttributeToken(self, ATTRIBUTE_ERRORMESSAGE, e.toString());
421
- });
422
-
423
- return self;
458
+ function importEntries() {
459
+
460
+ const data = this.getOption("data")
461
+ this[internalNodesSymbol] = new Map();
462
+
463
+ const mappingOptions = this.getOption("mapping", {});
464
+
465
+ const filter = mappingOptions?.["filter"];
466
+ const rootReferences = mappingOptions?.["rootReferences"];
467
+
468
+ const id = this.getOption("mapping.idTemplate");
469
+ const parentKey = this.getOption("mapping.parentKey");
470
+
471
+ const selector = mappingOptions?.["selector"];
472
+
473
+ let nodes;
474
+ try {
475
+ nodes = buildTree(data, selector, id, parentKey, {
476
+ filter,
477
+ rootReferences,
478
+ });
479
+ } catch (error) {
480
+ addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, String(error));
481
+ }
482
+
483
+ const options = [];
484
+ for (const node of nodes) {
485
+ const iterator = new NodeRecursiveIterator(node);
486
+ for (const n of iterator) {
487
+ const formattedValues = formatKeyLabel.call(this, n);
488
+
489
+ const label = formattedValues?.label;
490
+ const value = formattedValues?.value;
491
+ const icon = formattedValues?.icon;
492
+ const intend = n.level;
493
+
494
+ const visibility = (intend > 0) ? "hidden" : "visible";
495
+ const state = "close";
496
+
497
+ this[internalNodesSymbol].set(value, n);
498
+
499
+ options.push({
500
+ value,
501
+ label,
502
+ icon,
503
+ intend,
504
+ state,
505
+ visibility,
506
+ ["has-children"]: n.hasChildNodes(),
507
+ });
508
+ }
509
+ }
510
+
511
+ this.setOption("entries", options);
512
+
513
+ return this;
424
514
  }
425
515
 
426
516
  /**
427
517
  *
428
518
  * @param {Node} node
429
519
  * @return {array<label, value>}
430
- * @memberOf Monster.Components.TreeMenu
431
520
  * @private
432
521
  */
433
522
  function formatKeyLabel(node) {
434
- validateInstance(node, Node);
435
-
436
- const label = new Formatter(node.value).format(
437
- this.getOption("mapping.labelTemplate", ""),
438
- );
439
- const value = new Formatter(node.value).format(
440
- this.getOption("mapping.valueTemplate", ""),
441
- );
442
-
443
- return {
444
- value,
445
- label,
446
- };
447
- }
523
+ validateInstance(node, Node);
448
524
 
449
- /**
450
- * @private
451
- * @return {Monster.Components.TreeMenu.Form}
452
- */
453
- function initControlReferences() {
454
- if (!this.shadowRoot) {
455
- throw new Error("no shadow-root is defined");
456
- }
457
-
458
- this[controlElementSymbol] = this.shadowRoot.querySelector(
459
- "[data-monster-role=control]",
460
- );
461
- return this;
525
+ const label = new Formatter(node.value).format(
526
+ this.getOption("mapping.labelTemplate"),
527
+ );
528
+
529
+ const value = new Formatter(node.value).format(
530
+ this.getOption("mapping.valueTemplate"),
531
+ );
532
+
533
+ const iconID = new Formatter(node.value).format(
534
+ this.getOption("mapping.iconTemplate"),
535
+ );
536
+
537
+ const icon = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><use xlink:href="#${iconID}"></use></svg>`;
538
+
539
+ return {
540
+ value,
541
+ label,
542
+ icon,
543
+ };
462
544
  }
463
545
 
464
546
  /**
465
- *
466
- * ```
467
- * <monster-tree-menu data-monster-url="https://example.com/"></monster-tree-menu>
468
- * ```
469
-
470
547
  * @private
471
- * @return {object}
548
+ * @return {TreeMenu}
472
549
  */
473
- function initOptionsFromArguments() {
474
- const options = {};
550
+ function initControlReferences() {
551
+ if (!this.shadowRoot) {
552
+ throw new Error("no shadow-root is defined");
553
+ }
475
554
 
476
- // let url = self.getAttribute(ATTRIBUTE_FORM_URL);
477
- //
478
- // if (isString(url)) {
479
- // options['url'] = new URL(url, document.location).toString()
480
- // }
555
+ this[controlElementSymbol] = this.shadowRoot.querySelector(
556
+ "[data-monster-role=control]",
557
+ );
481
558
 
482
- return options;
559
+ return this;
483
560
  }
484
561
 
485
- function switchToConfig() {
486
- if (!this.shadowRoot) {
487
- throw new Error("no shadow-root is defined");
488
- }
489
-
490
- this[dragoverEventHandlerSymbol] = (event) => {
491
- const element = findTargetElementFromEvent(event, ATTRIBUTE_ROLE, "entry");
492
- event.preventDefault();
493
- if (!(element instanceof HTMLElement)) {
494
- return;
495
- }
496
-
497
- const dropzone = document.createElement("div");
498
- dropzone.classList.add("dropzone");
499
-
500
- element.prepend(dropzone);
501
-
502
- console.log("over", element.outerHTML, event);
503
-
504
- event.dataTransfer.dropEffect = "move";
505
- };
506
-
507
- this[dragenterEventHandlerSymbol] = (event) => {
508
- const element = findTargetElementFromEvent(event, ATTRIBUTE_ROLE, "entry");
509
- console.log("enter", element.outerHTML, event);
510
-
511
- event.dataTransfer.dropEffect = "move";
512
- event.preventDefault();
513
- };
514
-
515
- this[dragleaveEventHandlerSymbol] = (event) => {
516
- const element = findTargetElementFromEvent(event, ATTRIBUTE_ROLE, "entry");
517
-
518
- event.preventDefault();
519
- if (!(element instanceof HTMLElement)) {
520
- return;
521
- }
522
-
523
- console.log("leave", element.outerHTML, event);
524
-
525
- event.dataTransfer.dropEffect = "move";
526
- event.preventDefault();
527
- };
528
-
529
- this[dragEventHandlerSymbol] = (event) => {
530
- event.preventDefault();
531
- };
532
-
533
- this[dropEventHandlerSymbol] = (event) => {
534
- const element = findTargetElementFromEvent(event, ATTRIBUTE_ROLE, "entry");
535
- console.log("drop", element.outerHTML, event);
536
- event.preventDefault();
537
- };
538
-
539
- this[dragstartEventHandlerSymbol] = (event) => {
540
- const element = findTargetElementFromEvent(event, ATTRIBUTE_ROLE, "entry");
541
- if (!(element instanceof HTMLElement)) {
542
- return;
543
- }
544
-
545
- //let container = findClosestByAttribute(element, ATTRIBUTE_ROLE, 'option');
546
- const index = element
547
- .getAttribute(ATTRIBUTE_UPDATER_INSERT_REFERENCE)
548
- .split("-")
549
- .pop();
550
-
551
- const currentState = this.getOption("entries." + index + ".state");
552
- event.dataTransfer.setData("text/plain", "22");
553
- event.dataTransfer.setData("text/html", "22");
554
- event.dataTransfer.effectAllowed = "move";
555
- };
556
-
557
- this[controlElementSymbol].addEventListener(
558
- "dragstart",
559
- this[dragstartEventHandlerSymbol],
560
- );
561
- this[controlElementSymbol].addEventListener(
562
- "dragenter",
563
- this[dragenterEventHandlerSymbol],
564
- );
565
- this[controlElementSymbol].addEventListener(
566
- "dragleave",
567
- this[dragleaveEventHandlerSymbol],
568
- );
569
- this[controlElementSymbol].addEventListener(
570
- "dragover",
571
- this[dragoverEventHandlerSymbol],
572
- );
573
- this[controlElementSymbol].addEventListener(
574
- "drop",
575
- this[dropEventHandlerSymbol],
576
- );
577
- }
578
-
579
- // /**
580
- // * @private
581
- // * @throws {Error} missing default slot
582
- // * @throws {Error} no shadow-root is defined
583
- // * @throws {Error} missing url
584
- // * @throws {Error} we won't be able to read the data
585
- // * @throws {Error} request failed
586
- // * @throws {Error} not found
587
- // * @throws {Error} undefined status or type
588
- // * @fires Monster.Components.TreeMenu.event:monster-fetched
589
- // */
590
- // function initIntersectionObserver() {
591
- // const self = this;
592
- //
593
- // if (self[intersectionObserverWasInitialized] === true) {
594
- // return
595
- // }
596
- //
597
- // self[intersectionObserverWasInitialized] = true;
598
- //
599
- // let options = {
600
- // threshold: [0.5]
601
- // }
602
- //
603
- // const callback = (entries, observer) => {
604
- //
605
- // for (const [, entry] of entries.entries()) {
606
- // if (entry.isIntersecting === true) {
607
- // if (!self.hasAttribute(ATTRIBUTE_FORM_RELOAD) || self.getAttribute(ATTRIBUTE_FORM_RELOAD).toLowerCase() === 'onshow') {
608
- // observer.disconnect();
609
- // }
610
- //
611
- // try {
612
- // loadContent.call(self);
613
- // } catch (e) {
614
- // self.setAttribute(ATTRIBUTE_ERRORMESSAGE, e.toString());
615
- // }
616
- //
617
- //
618
- // }
619
- // }
620
- // }
621
- //
622
- // const observer = new IntersectionObserver(callback, options);
623
- // observer.observe(self);
624
- //
625
- //
626
- // }
627
-
628
562
  /**
629
563
  * @private
630
564
  * @return {string}
631
565
  */
632
566
  function getTemplate() {
633
- // language=HTML
634
- return `
567
+ // language=HTML
568
+ return `
569
+ <slot></slot>
570
+
635
571
  <template id="entries">
636
572
  <div data-monster-role="entry"
637
- draggable="true"
638
573
  data-monster-attributes="
639
574
  data-monster-intend path:entries.intend,
640
575
  data-monster-state path:entries.state,
641
576
  data-monster-visibility path:entries.visibility,
642
577
  data-monster-filtered path:entries.filtered,
643
578
  data-monster-has-children path:entries.has-children">
644
-
645
- <button data-monster-role="button"
646
- data-monster-attributes="
647
- type path:type,
648
- role path:role,
649
- value path:entries.value,
650
- name path:name,
651
- part path:type | prefix:option- | suffix: form" tabindex="-1">
652
- <span data-monster-role="folder-handler"></span>
653
- <span data-monster-replace="path:entries | index:label" part="entry-label"></span>
654
- </button>
579
+ <div data-monster-role="button"
580
+ data-monster-attributes="
581
+ value path:entries.value | tostring
582
+ " tabindex="0">
583
+ <div data-monster-role="status-badges"></div>
584
+ <div data-monster-role="icon" data-monster-replace="path:entries.icon">
585
+
586
+ </div>
587
+ <div data-monster-replace="path:entries.label"
588
+ part="entry-label"
589
+ data-monster-attributes="class static:id"></div>
590
+ </div>
655
591
  </template>
656
592
 
657
- <div data-monster-role="control" part="control">
593
+ <div data-monster-role="control" part="control" data-monster-attributes="class path:classes.control">
658
594
  <div part="entries" data-monster-role="entries"
659
595
  data-monster-insert="entries path:entries"
660
596
  tabindex="-1"></div>