@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/dist/fore-dev.js +34262 -3
- package/dist/fore.js +34124 -3
- package/index.js +2 -0
- package/package.json +2 -2
- package/resources/fore.css +30 -1
- package/src/DataObserver.js +181 -0
- package/src/DependentXPathQueries.js +32 -0
- package/src/ForeElementMixin.js +289 -254
- package/src/actions/abstract-action.js +38 -5
- package/src/actions/fx-append.js +2 -0
- package/src/actions/fx-delete.js +13 -1
- package/src/actions/fx-hide.js +1 -1
- package/src/actions/fx-insert.js +47 -39
- package/src/actions/fx-load.js +7 -2
- package/src/actions/fx-send.js +0 -2
- package/src/actions/fx-setvalue.js +104 -82
- package/src/actions/fx-show.js +4 -2
- package/src/fore.js +40 -22
- package/src/fx-bind.js +3 -2
- package/src/fx-fore.js +320 -164
- package/src/fx-instance.js +3 -2
- package/src/fx-model.js +63 -34
- package/src/fx-submission.js +38 -22
- package/src/getInScopeContext.js +2 -1
- package/src/modelitem.js +107 -91
- package/src/ui/UIElement.js +91 -0
- package/src/ui/abstract-control.js +14 -9
- package/src/ui/fx-container.js +7 -4
- package/src/ui/fx-control-menu.js +198 -0
- package/src/ui/fx-control.js +64 -41
- package/src/ui/fx-dialog.js +2 -2
- package/src/ui/fx-group.js +14 -0
- package/src/ui/fx-repeat.js +42 -3
- package/src/ui/fx-repeatitem.js +3 -0
- package/src/ui/fx-upload.js +304 -0
- package/src/xpath-util.js +310 -168
- package/dist/fore-dev.js.map +0 -1
- package/dist/fore.js.map +0 -1
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
|
-
|
|
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 ===
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
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
|
-
|
|
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
|
-
|
|
478
|
-
|
|
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();
|
package/src/fx-submission.js
CHANGED
|
@@ -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
|
-
|
|
89
|
-
|
|
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
|
-
|
|
242
|
-
|
|
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', {
|
|
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
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
+
this.targetref,
|
|
403
|
+
targetInstance.instanceData.firstElementChild,
|
|
404
|
+
this,
|
|
402
405
|
);
|
|
403
406
|
console.log('theTarget', theTarget);
|
|
404
|
-
if(
|
|
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'
|
|
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
|
-
|
|
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) {
|
package/src/getInScopeContext.js
CHANGED
|
@@ -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
|
-
*
|
|
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
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
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
|
-
|
|
77
|
-
|
|
89
|
+
get value() {
|
|
90
|
+
if (!this.node) {
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
if (!this.node.nodeType) return this.node;
|
|
78
94
|
|
|
79
|
-
|
|
80
|
-
|
|
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
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
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
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
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
|
-
|
|
108
|
-
|
|
109
|
-
|
|
123
|
+
addAlert(alert) {
|
|
124
|
+
if (!this.alerts.includes(alert)) {
|
|
125
|
+
this.alerts.push(alert);
|
|
126
|
+
}
|
|
110
127
|
}
|
|
111
|
-
}
|
|
112
128
|
|
|
113
|
-
|
|
114
|
-
|
|
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 = '🗑'; // 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
|
+
}
|