@schukai/monster 3.80.0 → 3.80.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -11,683 +11,683 @@
11
11
  *
12
12
  * SPDX-License-Identifier: AGPL-3.0
13
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
-
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
+ //
607
49
  // /**
608
50
  // * @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
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
616
131
  // * @fires Monster.Components.TreeMenu.event:monster-fetched
617
132
  // */
618
- // function initIntersectionObserver() {
619
- // const self = this;
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
+ // },
620
186
  //
621
- // if (self[intersectionObserverWasInitialized] === true) {
622
- // return
623
- // }
187
+ // data: [],
188
+ // },
189
+ // initOptionsFromArguments.call(this),
190
+ // );
191
+ // }
624
192
  //
625
- // self[intersectionObserverWasInitialized] = true;
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);
626
251
  //
627
- // let options = {
628
- // threshold: [0.5]
629
- // }
252
+ // const selector = this.getOption("datasource.selector");
630
253
  //
631
- // const callback = (entries, observer) => {
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
+ // }
632
259
  //
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
- // }
260
+ // if (!(element instanceof Datasource)) {
261
+ // throw new TypeError("the element must be a datasource");
262
+ // }
638
263
  //
639
- // try {
640
- // loadContent.call(self);
641
- // } catch (e) {
642
- // self.setAttribute(ATTRIBUTE_ERRORMESSAGE, e.toString());
643
- // }
264
+ // this[datasourceLinkedElementSymbol] = element;
265
+ // element.datasource.attachObserver(
266
+ // new Observer(handleDataSourceChanges.bind(this)),
267
+ // );
268
+ // }
644
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
+ // }
645
279
  //
646
- // }
647
- // }
648
- // }
280
+ // //let container = findClosestByAttribute(element, ATTRIBUTE_ROLE, 'option');
281
+ // const index = container
282
+ // .getAttribute(ATTRIBUTE_UPDATER_INSERT_REFERENCE)
283
+ // .split("-")
284
+ // .pop();
649
285
  //
650
- // const observer = new IntersectionObserver(callback, options);
651
- // observer.observe(self);
286
+ // const currentState = this.getOption("data." + index + ".state");
652
287
  //
288
+ // const newState = currentState === "close" ? "open" : "close";
289
+ // this.setOption("data." + index + ".state", newState);
653
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;
654
349
  // }
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);
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);