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