@jinntec/fore 2.4.2 → 2.6.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/src/fx-model.js CHANGED
@@ -51,7 +51,7 @@ export class FxModel extends HTMLElement {
51
51
  <slot></slot>
52
52
  `;
53
53
 
54
- /*
54
+ /*
55
55
  this.addEventListener('model-construct-done', () => {
56
56
  // this.modelConstructed = true;
57
57
  // console.log('model-construct-done fired ', this.modelConstructed);
@@ -65,12 +65,38 @@ export class FxModel extends HTMLElement {
65
65
  this.fore = this.parentNode;
66
66
  }
67
67
 
68
- static lazyCreateModelItem(model, ref, node) {
68
+ /**
69
+ * @param {FxModel} model The model to create a model item for
70
+ * @param {string} ref The XPath ref that led to this model item
71
+ * @param {Node} node The node the XPath led to
72
+ * @param {ForeElementMixin} formElement The form element making this model. Used to resolve variables against
73
+ */
74
+ static lazyCreateModelItem(model, ref, node, formElement) {
69
75
  // console.log('lazyCreateModelItem ', node);
70
-
76
+ const instanceId = XPathUtil.resolveInstance(formElement, ref);
77
+
78
+ if (model.parentNode.createNodes && (node === null || node === undefined)) {
79
+ // ### intializing ModelItem with default values (as there is no <fx-bind> matching for given ref)
80
+ const mi = new ModelItem(
81
+ undefined,
82
+ ref,
83
+ Fore.READONLY_DEFAULT,
84
+ false,
85
+ Fore.REQUIRED_DEFAULT,
86
+ Fore.CONSTRAINT_DEFAULT,
87
+ Fore.TYPE_DEFAULT,
88
+ null,
89
+ this,
90
+ instanceId,
91
+ );
92
+
93
+ // console.log('new ModelItem is instanceof ModelItem ', mi instanceof ModelItem);
94
+ model.registerModelItem(mi);
95
+ return mi;
96
+ }
71
97
  let targetNode = {};
72
98
  if (node === null || node === undefined) return null;
73
- if (node.nodeType === node.TEXT_NODE) {
99
+ if (node.nodeType === Node.TEXT_NODE) {
74
100
  // const parent = node.parentNode;
75
101
  // console.log('PARENT ', parent);
76
102
  targetNode = node.parentNode;
@@ -81,9 +107,7 @@ export class FxModel extends HTMLElement {
81
107
  // const path = fx.evaluateXPath('path()',node);
82
108
  let path;
83
109
  if (node.nodeType) {
84
- const instance = XPathUtil.resolveInstance(model, ref);
85
-
86
- path = XPathUtil.getPath(node, instance);
110
+ path = XPathUtil.getPath(node, instanceId);
87
111
  } else {
88
112
  path = null;
89
113
  targetNode = node;
@@ -101,6 +125,7 @@ export class FxModel extends HTMLElement {
101
125
  Fore.TYPE_DEFAULT,
102
126
  targetNode,
103
127
  this,
128
+ instanceId,
104
129
  );
105
130
 
106
131
  // console.log('new ModelItem is instanceof ModelItem ', mi instanceof ModelItem);
@@ -118,7 +143,11 @@ export class FxModel extends HTMLElement {
118
143
  *
119
144
  */
120
145
  async modelConstruct() {
121
- console.log(`### <<<<< dispatching model-construct for '${this.fore.id}' >>>>>`);
146
+ console.info(
147
+ `%cdispatching model-construct for #${this.parentNode.id}`,
148
+ 'background:lightblue; color:black; padding:.5rem; display:inline-block; white-space: nowrap; border-radius:0.3rem;width:100%;',
149
+ );
150
+
122
151
  // this.dispatchEvent(new CustomEvent('model-construct', { detail: this }));
123
152
  Fore.dispatch(this, 'model-construct', { model: this });
124
153
 
@@ -132,25 +161,25 @@ export class FxModel extends HTMLElement {
132
161
 
133
162
  // Wait until all the instances are built
134
163
  await Promise.all(promises);
135
- this.instances = Array.from(instances);
136
- // console.log('_modelConstruct this.instances ', this.instances);
137
- // Await until the model-construct-done event is handled off
138
- this.modelConstructed = true;
139
- await Fore.dispatch(this, 'model-construct-done', {model: this});
140
- this.inited = true;
141
- this.updateModel();
142
- } else {
143
- // ### if there's no instance one will created
144
- console.log(`### <<<<< dispatching model-construct-done for '${this.fore.id}' >>>>>`);
145
- this.modelConstructed = true;
146
- await this.dispatchEvent(
147
- new CustomEvent('model-construct-done', {
148
- composed: false,
149
- bubbles: true,
150
- detail: {model: this},
151
- }),
152
- );
153
- }
164
+ this.instances = Array.from(instances);
165
+ // console.log('_modelConstruct this.instances ', this.instances);
166
+ // Await until the model-construct-done event is handled off
167
+ this.modelConstructed = true;
168
+ await Fore.dispatch(this, 'model-construct-done', { model: this });
169
+ this.inited = true;
170
+ this.updateModel();
171
+ } else {
172
+ // ### if there's no instance one will created
173
+ console.log(`### <<<<< dispatching model-construct-done for '${this.fore.id}' >>>>>`);
174
+ this.modelConstructed = true;
175
+ await this.dispatchEvent(
176
+ new CustomEvent('model-construct-done', {
177
+ composed: false,
178
+ bubbles: true,
179
+ detail: { model: this },
180
+ }),
181
+ );
182
+ }
154
183
 
155
184
  const functionlibImports = Array.from(this.querySelectorAll('fx-functionlib'));
156
185
  await Promise.all(functionlibImports.map(lib => lib.readyPromise));
@@ -416,7 +445,7 @@ export class FxModel extends HTMLElement {
416
445
  modelItem.required = compute;
417
446
  this.formElement.addToRefresh(modelItem); // let fore know that modelItem needs refresh
418
447
  if (!modelItem.node.textContent) {
419
- /*
448
+ /*
420
449
  console.log(
421
450
  'node is required but has no value ',
422
451
  XPathUtil.getDocPath(modelItem.node),
@@ -468,17 +497,17 @@ export class FxModel extends HTMLElement {
468
497
  /**
469
498
  * @returns {import('./fx-instance.js').FxInstance}
470
499
  */
471
- getDefaultInstance() {
472
- /*
500
+ getDefaultInstance() {
501
+ /*
473
502
  if (this.instances.length === 0) {
474
503
  throw new Error('No instances defined. Fore cannot work without any <data/> elements.');
475
504
  }
476
505
  */
477
- if (this.instances.length) {
478
- return this.instances[0];
479
- }
480
- return this.getInstance('default');
506
+ if (this.instances.length) {
507
+ return this.instances[0];
481
508
  }
509
+ return this.getInstance('default');
510
+ }
482
511
 
483
512
  getDefaultInstanceData() {
484
513
  return this.instances[0].getInstanceData();
@@ -83,10 +83,9 @@ export class FxSubmission extends ForeElementMixin {
83
83
  }
84
84
 
85
85
  async _submit() {
86
- console.log('submitting....', this.getAttribute('id'));
87
86
  console.info(
88
- `%csubmitting #${this.id}`,
89
- 'background:yellow; color:black; padding:.5rem; display:inline-block; white-space: nowrap; border-radius:0.3rem;width:100%;',
87
+ `%csubmitting #${this.id}`,
88
+ 'background:yellow; color:black; padding:.5rem; display:inline-block; white-space: nowrap; border-radius:0.3rem;width:100%;',
90
89
  );
91
90
 
92
91
  this.evalInContext();
@@ -101,7 +100,7 @@ export class FxSubmission extends ForeElementMixin {
101
100
  this.getOwnerForm().classList.add('submit-validation-failed');
102
101
  // ### allow alerts to pop up
103
102
  // this.dispatch('submit-error', {});
104
- Fore.dispatch(this, 'submit-error', {});
103
+ Fore.dispatch(this, 'submit-error', { status: 0, message: 'validation failed' });
105
104
  this.getModel().parentNode.refresh(true);
106
105
  return;
107
106
  }
@@ -184,6 +183,7 @@ export class FxSubmission extends ForeElementMixin {
184
183
  const serialized = localStorage.getItem(key);
185
184
  if (!serialized) {
186
185
  Fore.dispatch(this, 'submit-error', {
186
+ status: 400,
187
187
  message: `Error reading key ${key} from localstorage`,
188
188
  });
189
189
  this.parameters.clear();
@@ -238,11 +238,14 @@ export class FxSubmission extends ForeElementMixin {
238
238
  if (!response.ok || response.status > 400) {
239
239
  // this.dispatch('submit-error', { message: `Error while submitting ${this.id}` });
240
240
  console.info(
241
- `%csubmit-error #${this.id}`,
242
- 'background:red; color:black; padding:.5rem; display:inline-block; white-space: nowrap; border-radius:0.3rem;width:100%;',
241
+ `%csubmit-error #${this.id}`,
242
+ 'background:red; color:black; padding:.5rem; display:inline-block; white-space: nowrap; border-radius:0.3rem;width:100%;',
243
243
  );
244
244
 
245
- Fore.dispatch(this, 'submit-error', { message: `Error while submitting ${this.id}` });
245
+ Fore.dispatch(this, 'submit-error', {
246
+ status: response.status,
247
+ message: `Error during submit ${this.id}`,
248
+ });
246
249
  return;
247
250
  }
248
251
 
@@ -265,13 +268,14 @@ export class FxSubmission extends ForeElementMixin {
265
268
  // this.dispatch('submit-done', {});
266
269
  // console.log(`### <<<<< ${this.id} submit-done >>>>>`);
267
270
  Fore.dispatch(this, 'submit-done', {});
271
+ /*
268
272
  console.info(
269
273
  `%csubmit-done #${this.id}`,
270
274
  'background:green; color:white; padding:.5rem; display:inline-block; white-space: nowrap; border-radius:0.3rem;width:100%;',
271
275
  );
272
-
276
+ */
273
277
  } catch (error) {
274
- Fore.dispatch(this, 'submit-error', { error: error.message });
278
+ Fore.dispatch(this, 'submit-error', { status: 500, error: error.message });
275
279
  } finally {
276
280
  this.parameters.clear();
277
281
  const download = document.querySelector('[download]');
@@ -394,26 +398,27 @@ export class FxSubmission extends ForeElementMixin {
394
398
  if (this.replace === 'instance') {
395
399
  if (targetInstance) {
396
400
  if (this.targetref) {
397
-
398
401
  const [theTarget] = evaluateXPath(
399
- this.targetref,
400
- targetInstance.instanceData.firstElementChild,
401
- this,
402
+ this.targetref,
403
+ targetInstance.instanceData.firstElementChild,
404
+ this,
402
405
  );
403
406
  console.log('theTarget', theTarget);
404
- if(this.responseMediatype === 'application/xml' || this.responseMediatype === 'text/html'){
407
+ if (
408
+ this.responseMediatype === 'application/xml' ||
409
+ this.responseMediatype === 'text/html'
410
+ ) {
405
411
  const clone = data.firstElementChild;
406
412
  const parent = theTarget.parentNode;
407
413
  parent.replaceChild(clone, theTarget);
408
414
  console.log('finally ', parent);
409
415
  }
410
- if(this.responseMediatype.startsWith('text/')){
416
+ if (this.responseMediatype.startsWith('text/')) {
411
417
  theTarget.textContent = data;
412
418
  }
413
- if(this.responseMediatype === 'application/json'){
414
- console.warn('targetref is not supported for application/json responses')
419
+ if (this.responseMediatype === 'application/json') {
420
+ console.warn('targetref is not supported for application/json responses');
415
421
  }
416
-
417
422
  } else if (this.into) {
418
423
  const [theTarget] = evaluateXPath(
419
424
  this.into,
@@ -465,12 +470,21 @@ export class FxSubmission extends ForeElementMixin {
465
470
  }
466
471
  // document.getElementsByTagName('html')[0].innerHTML = data;
467
472
  }
468
- if (this.replace === 'target' && contentType.startsWith('text/html')) {
473
+ if (this.replace === 'target') {
469
474
  // const target = this.getAttribute('target');
470
475
  const target = this._getProperty('target');
471
476
  const targetNode = document.querySelector(target);
472
477
  if (targetNode) {
473
- targetNode.innerHTML = data;
478
+ if (contentType.startsWith('text/html')) {
479
+ targetNode.innerHTML = data;
480
+ }
481
+ if (this.responseMediatype.startsWith('image/svg')) {
482
+ const parser = new DOMParser();
483
+ const svgDoc = parser.parseFromString(data, 'image/svg+xml');
484
+
485
+ const objectURL = URL.createObjectURL(data);
486
+ targetNode.src = objectURL;
487
+ }
474
488
  } else {
475
489
  Fore.dispatch(this, 'submit-error', {
476
490
  message: `targetNode for selector ${target} not found`,
@@ -482,10 +496,11 @@ export class FxSubmission extends ForeElementMixin {
482
496
  }
483
497
  }
484
498
 
499
+ /*
485
500
  _handleError() {
486
501
  // this.dispatch('submit-error', {});
487
502
  Fore.dispatch(this, 'submit-error', {});
488
- /*
503
+ /!*
489
504
  console.log('ERRRORRRRR');
490
505
  this.dispatchEvent(
491
506
  new CustomEvent('submit-error', {
@@ -494,8 +509,9 @@ export class FxSubmission extends ForeElementMixin {
494
509
  detail: {},
495
510
  }),
496
511
  );
497
- */
512
+ *!/
498
513
  }
514
+ */
499
515
 
500
516
  /*
501
517
  mergeNodes(node1, node2) {
@@ -48,7 +48,7 @@ function _getInitialContext(node, ref) {
48
48
  }
49
49
 
50
50
  if (XPathUtil.isAbsolutePath(ref)) {
51
- const instanceId = XPathUtil.getInstanceId(ref);
51
+ const instanceId = XPathUtil.getInstanceId(ref, node);
52
52
  if (instanceId) {
53
53
  return model.getInstance(instanceId).getDefaultContext();
54
54
  }
@@ -69,6 +69,7 @@ function _getInitialContext(node, ref) {
69
69
  export default function getInScopeContext(node, ref) {
70
70
  // console.log('getInScopeContext', ref, node);
71
71
 
72
+ //todo: check for multi-step pathes
72
73
  const parentElement = _getElement(node);
73
74
  // console.log('getInScopeContext parent', parentElement);
74
75
 
package/src/modelitem.js CHANGED
@@ -6,111 +6,127 @@
6
6
  * Each bound node in an instance has exactly one ModelItem associated with it.
7
7
  */
8
8
  export class ModelItem {
9
- /**
10
- *
11
- * @param {string} path calculated normalized path expression linking to data
12
- * @param {string} ref relative binding expression
13
- * @param {boolean} readonly - boolean to signal readonly/readwrite state
14
- * @param {boolean} relevant - boolean to signal relevant/non-relevant state
15
- * @param {boolean} required - boolean to signal required/optional state
16
- * @param {boolean} constraint - boolean boolean to signal valid/invalid state
17
- * @param {string} type - string expression to set a datatype
18
- * @param {Node} node - the node the 'ref' expression is referring to
19
- * @param {import('./fx-bind').FxBind} bind - the fx-bind element having created this modelItem
20
- */
21
- constructor(path, ref, readonly, relevant, required, constraint, type, node, bind) {
22
9
  /**
23
- * @type {string}
10
+ *
11
+ * @param {string} path calculated normalized path expression linking to data
12
+ * @param {string} ref relative binding expression
13
+ * @param {boolean} readonly - boolean to signal readonly/readwrite state
14
+ * @param {boolean} relevant - boolean to signal relevant/non-relevant state
15
+ * @param {boolean} required - boolean to signal required/optional state
16
+ * @param {boolean} constraint - boolean boolean to signal valid/invalid state
17
+ * @param {string} type - string expression to set a datatype
18
+ * @param {Node} node - the node the 'ref' expression is referring to
19
+ * @param {import('./fx-bind').FxBind} bind - the fx-bind element having created this modelItem
20
+ * @param {string} instance - the fx-instance id having created this modelItem
24
21
  */
25
- this.path = path;
26
- /**
27
- * @type {string}
28
- */
29
- this.ref = ref;
30
- /**
31
- * @type {boolean}
32
- */
33
- this.constraint = constraint;
34
- /**
35
- * @type {boolean}
36
- */
37
- this.readonly = readonly;
38
- /**
39
- * @type {boolean}
40
- */
41
- this.relevant = relevant;
42
- /**
43
- * @type {boolean}
44
- */
45
- this.required = required;
46
- /**
47
- * @type {string}
48
- */
49
- this.type = type;
50
- /**
51
- * @type {Node}
52
- */
53
- this.node = node;
54
- /**
55
- * @type {import('./fx-bind').FxBind}
56
- */
57
- this.bind = bind;
58
- this.changed = false;
59
- /**
60
- * @type {import('./ui/fx-alert').FxAlert[]}
61
- */
62
- this.alerts = [];
63
- /**
64
- * @type {import('./ui/fx-control').default[]}
65
- */
66
- this.boundControls = [];
67
- // this.value = this._getValue();
68
- }
22
+ constructor(
23
+ path,
24
+ ref,
25
+ readonly,
26
+ relevant,
27
+ required,
28
+ constraint,
29
+ type,
30
+ node,
31
+ bind,
32
+ instance,
33
+ ) {
34
+ /**
35
+ * @type {string}
36
+ */
37
+ this.path = path;
38
+ /**
39
+ * @type {string}
40
+ */
41
+ this.ref = ref;
42
+ /**
43
+ * @type {boolean}
44
+ */
45
+ this.constraint = constraint;
46
+ /**
47
+ * @type {boolean}
48
+ */
49
+ this.readonly = readonly;
50
+ /**
51
+ * @type {boolean}
52
+ */
53
+ this.relevant = relevant;
54
+ /**
55
+ * @type {boolean}
56
+ */
57
+ this.required = required;
58
+ /**
59
+ * @type {string}
60
+ */
61
+ this.type = type;
62
+ /**
63
+ * @type {Node}
64
+ */
65
+ this.node = node;
66
+ /**
67
+ * @type {import('./fx-bind').FxBind}
68
+ */
69
+ this.bind = bind;
70
+ this.changed = false;
71
+ /**
72
+ * @type {import('./ui/fx-alert').FxAlert[]}
73
+ */
74
+ this.alerts = [];
75
+ /**
76
+ * @type {import('./ui/abstract-control').default[]}
77
+ */
78
+ this.boundControls = [];
79
+ // this.value = this._getValue();
80
+ this.instanceId = instance;
81
+ }
69
82
 
70
- /*
83
+ /*
71
84
  get ref(){
72
85
  return this.bind.ref;
73
86
  }
74
87
  */
75
88
 
76
- get value() {
77
- if (!this.node.nodeType) return this.node;
89
+ get value() {
90
+ if (!this.node) {
91
+ return null;
92
+ }
93
+ if (!this.node.nodeType) return this.node;
78
94
 
79
- if (this.node.nodeType === Node.ATTRIBUTE_NODE) {
80
- return this.node.nodeValue;
95
+ if (this.node.nodeType === Node.ATTRIBUTE_NODE) {
96
+ return this.node.nodeValue;
97
+ }
98
+ return this.node.textContent;
81
99
  }
82
- return this.node.textContent;
83
- }
84
100
 
85
- /**
86
- * @param {Node} newVal
87
- */
88
- set value(newVal) {
89
- // console.log('modelitem.setvalue oldVal', this.value);
90
- // console.log('modelitem.setvalue newVal', newVal);
101
+ /**
102
+ * @param {Node} newVal
103
+ */
104
+ set value(newVal) {
105
+ // console.log('modelitem.setvalue oldVal', this.value);
106
+ // console.log('modelitem.setvalue newVal', newVal);
91
107
 
92
- if (newVal.nodeType === Node.DOCUMENT_NODE) {
93
- this.node.replaceWith(newVal.firstElementChild);
94
- this.node = newVal.firstElementChild;
95
- // this.node.appendChild(newVal.firstElementChild);
96
- } else if (newVal.nodeType === Node.ELEMENT_NODE) {
97
- this.node.replaceWith(newVal);
98
- this.node = newVal;
99
- // this.node.appendChild(newVal);
100
- } else if (this.node.nodeType === Node.ATTRIBUTE_NODE) {
101
- this.node.nodeValue = newVal;
102
- } else {
103
- this.node.textContent = newVal;
108
+ if (newVal.nodeType === Node.DOCUMENT_NODE) {
109
+ this.node.replaceWith(newVal.firstElementChild);
110
+ this.node = newVal.firstElementChild;
111
+ // this.node.appendChild(newVal.firstElementChild);
112
+ } else if (newVal.nodeType === Node.ELEMENT_NODE) {
113
+ this.node.replaceWith(newVal);
114
+ this.node = newVal;
115
+ // this.node.appendChild(newVal);
116
+ } else if (this.node.nodeType === Node.ATTRIBUTE_NODE) {
117
+ this.node.nodeValue = newVal;
118
+ } else {
119
+ this.node.textContent = newVal;
120
+ }
104
121
  }
105
- }
106
122
 
107
- addAlert(alert) {
108
- if (!this.alerts.includes(alert)) {
109
- this.alerts.push(alert);
123
+ addAlert(alert) {
124
+ if (!this.alerts.includes(alert)) {
125
+ this.alerts.push(alert);
126
+ }
110
127
  }
111
- }
112
128
 
113
- cleanAlerts() {
114
- this.alerts = [];
115
- }
129
+ cleanAlerts() {
130
+ this.alerts = [];
131
+ }
116
132
  }
@@ -0,0 +1,91 @@
1
+ import ForeElementMixin from '../ForeElementMixin.js';
2
+ import { Fore } from '../fore.js';
3
+
4
+ export class UIElement extends ForeElementMixin {
5
+ constructor() {
6
+ super();
7
+ }
8
+
9
+ connectedCallback() {
10
+ super.connectedCallback();
11
+ this.ondemand = this.hasAttribute('on-demand') ? true : false;
12
+ this.wasOnDemandInitially = this.ondemand;
13
+ if (this.ondemand) {
14
+ this.addEventListener('show-control', () => {
15
+ this.removeAttribute('on-demand');
16
+ });
17
+ this.addTrashIcon();
18
+ }
19
+ }
20
+
21
+ activate() {
22
+ console.log('UIElement.activate() called');
23
+ this.removeAttribute('on-demand');
24
+ this.style.display = '';
25
+ if (this.isBound()) {
26
+ this.refresh(true);
27
+ }
28
+ Fore.dispatch(this, 'show-group', {});
29
+ }
30
+
31
+ attributeChangedCallback(name, _oldValue, newValue) {
32
+ if (name === 'on-demand') {
33
+ this.ondemand = newValue !== null;
34
+ if (!newValue && !this.wasOnDemandInitially) {
35
+ this.removeTrashIcon();
36
+ } else {
37
+ this.wasOnDemandInitially = true;
38
+ this.addTrashIcon();
39
+ }
40
+ }
41
+ }
42
+
43
+ static get observedAttributes() {
44
+ return ['on-demand'];
45
+ }
46
+
47
+ addTrashIcon() {
48
+ // Only show icon if explicitly marked by control-menu
49
+
50
+ if (!this.closest('[show-icon]')) return;
51
+
52
+ // const wrapper = this.shadowRoot.querySelector('.wrapper');
53
+ // if (!wrapper || wrapper.querySelector('.trash')) return;
54
+ const trash = this.querySelector('.trash');
55
+ if (trash) return;
56
+ const icon = document.createElement('span');
57
+ // icon.innerHTML = '&#128465;'; // trash icon
58
+ icon.innerHTML = `
59
+ <svg width="24" height="24" viewBox="0 0 24 24" fill="none"
60
+ stroke="currentColor" stroke-width="2" stroke-linecap="round"
61
+ stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg">
62
+ <path d="M17.94 17.94C16.13 19.12 14.13 20 12 20C7 20 2.73 15.88 1 12C1.6 10.66 2.43 9.47 3.46 8.48M10.58 10.58C10.21 11.01 10 11.5 10 12C10 13.11 10.89 14 12 14C12.5 14 12.99 13.79 13.42 13.42M6.53 6.53C7.87 5.54 9.39 5 12 5C17 5 21.27 9.12 23 12C22.4 13.34 21.57 14.53 20.54 15.52M1 1L23 23"/>
63
+ </svg>
64
+ `;
65
+
66
+ icon.classList.add('trash');
67
+ icon.setAttribute('title', 'Hide');
68
+ // icon.setAttribute('part', 'trash');
69
+ icon.style.cursor = 'pointer';
70
+ icon.style.marginLeft = '0.5em';
71
+
72
+ icon.addEventListener('click', e => {
73
+ e.stopPropagation();
74
+ this.setAttribute('on-demand', 'true');
75
+ this.style.display = 'none';
76
+ document.dispatchEvent(new CustomEvent('update-control-menu'));
77
+ Fore.dispatch(this, 'hide-control', {});
78
+ });
79
+
80
+ this.appendChild(icon);
81
+ }
82
+
83
+ removeTrashIcon() {
84
+ debugger;
85
+ const icon = this.querySelector('.trash');
86
+ if (icon) icon.remove();
87
+ }
88
+ }
89
+ if (!customElements.get('ui-element')) {
90
+ customElements.define('ui-element', UIElement);
91
+ }