@schukai/monster 3.71.2 → 3.72.0

Sign up to get free protection for your applications and to get access to all the features.
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>