@jinntec/fore 1.0.0-4 → 1.1.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/README.md +26 -38
- package/dist/fore-dev.js +43 -0
- package/dist/fore-dev.js.map +1 -0
- package/dist/fore.js +37 -0
- package/dist/fore.js.map +1 -0
- package/index.js +4 -0
- package/package.json +42 -42
- package/resources/fore.css +186 -0
- package/resources/toastify.css +87 -0
- package/resources/{fore-styles.css → vars.css} +0 -292
- package/src/DependencyNotifyingDomFacade.js +10 -16
- package/src/ForeElementMixin.js +26 -19
- package/src/actions/abstract-action.js +30 -9
- package/src/actions/fx-action.js +6 -4
- package/src/actions/fx-append.js +8 -17
- package/src/actions/fx-confirm.js +5 -3
- package/src/actions/fx-delete.js +6 -3
- package/src/actions/fx-dispatch.js +9 -8
- package/src/actions/fx-hide.js +10 -6
- package/src/actions/fx-insert.js +49 -39
- package/src/actions/fx-message.js +3 -1
- package/src/actions/fx-refresh.js +15 -1
- package/src/actions/fx-replace.js +73 -0
- package/src/actions/fx-return.js +42 -0
- package/src/actions/fx-send.js +3 -1
- package/src/actions/fx-setfocus.js +37 -0
- package/src/actions/fx-setvalue.js +58 -51
- package/src/actions/fx-show.js +12 -4
- package/src/actions/fx-toggle.js +15 -10
- package/src/actions/fx-update.js +3 -1
- package/src/dep_graph.js +4 -2
- package/src/drawdown.js +67 -82
- package/src/fore.js +158 -12
- package/src/functions/fx-function.js +17 -3
- package/src/fx-bind.js +42 -202
- package/src/fx-fore.js +599 -567
- package/src/fx-header.js +3 -1
- package/src/fx-instance.js +9 -1
- package/src/fx-model.js +59 -23
- package/src/fx-submission.js +106 -48
- package/src/fx-var.js +7 -4
- package/src/getInScopeContext.js +37 -11
- package/src/modelitem.js +4 -4
- package/src/relevance.js +64 -0
- package/src/ui/abstract-control.js +64 -37
- package/src/ui/fx-alert.js +7 -1
- package/src/ui/fx-case.js +4 -3
- package/src/ui/fx-container.js +7 -1
- package/src/ui/fx-control.js +309 -34
- package/src/ui/fx-dialog.js +54 -40
- package/src/ui/fx-group.js +3 -1
- package/src/ui/fx-hint.js +4 -1
- package/src/ui/fx-inspector.js +120 -17
- package/src/ui/fx-items.js +8 -8
- package/src/ui/fx-output.js +16 -5
- package/src/ui/fx-repeat.js +33 -41
- package/src/ui/fx-repeatitem.js +10 -4
- package/src/ui/fx-switch.js +5 -3
- package/src/ui/fx-trigger.js +3 -1
- package/src/xpath-evaluation.js +621 -576
- package/src/xpath-util.js +15 -8
- package/dist/fore-all.js +0 -140
- package/dist/fore-debug.js +0 -140
- package/src/.DS_Store +0 -0
- package/src/actions/.DS_Store +0 -0
- package/src/ui/.DS_Store +0 -0
package/src/ui/fx-control.js
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import XfAbstractControl from './abstract-control.js';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
evaluateXPath,
|
|
4
|
+
evaluateXPathToString,
|
|
5
|
+
evaluateXPathToFirstNode,
|
|
6
|
+
} from '../xpath-evaluation.js';
|
|
3
7
|
import getInScopeContext from '../getInScopeContext.js';
|
|
4
8
|
import { Fore } from '../fore.js';
|
|
5
9
|
|
|
@@ -14,6 +18,16 @@ const WIDGETCLASS = 'widget';
|
|
|
14
18
|
* @customElement
|
|
15
19
|
* @demo demo/index.html
|
|
16
20
|
*/
|
|
21
|
+
|
|
22
|
+
function debounce(func, timeout = 300) {
|
|
23
|
+
let timer;
|
|
24
|
+
return (...args) => {
|
|
25
|
+
clearTimeout(timer);
|
|
26
|
+
timer = setTimeout(() => {
|
|
27
|
+
func.apply(this, args);
|
|
28
|
+
}, timeout);
|
|
29
|
+
};
|
|
30
|
+
}
|
|
17
31
|
export default class FxControl extends XfAbstractControl {
|
|
18
32
|
constructor() {
|
|
19
33
|
super();
|
|
@@ -22,6 +36,12 @@ export default class FxControl extends XfAbstractControl {
|
|
|
22
36
|
}
|
|
23
37
|
|
|
24
38
|
connectedCallback() {
|
|
39
|
+
this.initial = this.hasAttribute('initial') ? this.getAttribute('initial') : null;
|
|
40
|
+
this.url = this.hasAttribute('url') ? this.getAttribute('url') : null;
|
|
41
|
+
this.loaded = false;
|
|
42
|
+
this.initialNode = null;
|
|
43
|
+
this.debounceDelay = this.hasAttribute('debounce') ? this.getAttribute('debounce') : null;
|
|
44
|
+
|
|
25
45
|
this.updateEvent = this.hasAttribute('update-event')
|
|
26
46
|
? this.getAttribute('update-event')
|
|
27
47
|
: 'blur';
|
|
@@ -33,21 +53,6 @@ export default class FxControl extends XfAbstractControl {
|
|
|
33
53
|
}
|
|
34
54
|
`;
|
|
35
55
|
|
|
36
|
-
/*
|
|
37
|
-
const controlHtml = `
|
|
38
|
-
<slot></slot>
|
|
39
|
-
<fx-setvalue id="setvalue" ref="${this.ref}"></fx-setvalue>
|
|
40
|
-
`;
|
|
41
|
-
*/
|
|
42
|
-
|
|
43
|
-
/*
|
|
44
|
-
this.shadowRoot.innerHTML = `
|
|
45
|
-
<style>
|
|
46
|
-
${style}
|
|
47
|
-
</style>
|
|
48
|
-
${controlHtml}
|
|
49
|
-
`
|
|
50
|
-
*/
|
|
51
56
|
this.shadowRoot.innerHTML = `
|
|
52
57
|
<style>
|
|
53
58
|
${style}
|
|
@@ -57,7 +62,15 @@ export default class FxControl extends XfAbstractControl {
|
|
|
57
62
|
|
|
58
63
|
this.widget = this.getWidget();
|
|
59
64
|
// console.log('widget ', this.widget);
|
|
65
|
+
let listenOn = this.widget // default: usually listening on widget
|
|
60
66
|
|
|
67
|
+
if(this.hasAttribute('listen-on')){
|
|
68
|
+
const q = this.getAttribute('listen-on');
|
|
69
|
+
const target = this.querySelector(q);
|
|
70
|
+
if(target){
|
|
71
|
+
listenOn = target;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
61
74
|
// ### convenience marker event
|
|
62
75
|
if (this.updateEvent === 'enter') {
|
|
63
76
|
this.widget.addEventListener('keyup', event => {
|
|
@@ -69,32 +82,119 @@ export default class FxControl extends XfAbstractControl {
|
|
|
69
82
|
});
|
|
70
83
|
this.updateEvent = 'blur'; // needs to be registered too
|
|
71
84
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
85
|
+
if (this.debounceDelay) {
|
|
86
|
+
listenOn.addEventListener(
|
|
87
|
+
this.updateEvent,
|
|
88
|
+
debounce(() => {
|
|
89
|
+
console.log('eventlistener ', this.updateEvent);
|
|
90
|
+
this.setValue(this.widget[this.valueProp]);
|
|
91
|
+
}, this.debounceDelay),
|
|
92
|
+
);
|
|
93
|
+
} else {
|
|
94
|
+
listenOn.addEventListener(this.updateEvent, () => {
|
|
95
|
+
console.log('eventlistener ', this.updateEvent);
|
|
96
|
+
this.setValue(this.widget[this.valueProp]);
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
this.addEventListener('return', e => {
|
|
101
|
+
console.log('catched return action on ', this);
|
|
102
|
+
console.log('return detail', e.detail);
|
|
103
|
+
|
|
104
|
+
console.log('return triggered on ', this);
|
|
105
|
+
console.log('this.ref', this.ref);
|
|
106
|
+
console.log('current outer instance', this.getInstance());
|
|
107
|
+
|
|
108
|
+
console.log(
|
|
109
|
+
'???? why ???? current nodeset should point to the node of the outer control',
|
|
110
|
+
e.currentTarget.nodeset,
|
|
111
|
+
);
|
|
112
|
+
console.log(
|
|
113
|
+
'???? why ???? current nodeset should point to the node of the outer control',
|
|
114
|
+
this.nodeset,
|
|
115
|
+
);
|
|
116
|
+
const newNodes = e.detail.nodeset;
|
|
117
|
+
console.log('new nodeset', newNodes);
|
|
118
|
+
console.log('currentTarget', e.currentTarget);
|
|
119
|
+
console.log('target', e.target);
|
|
120
|
+
|
|
121
|
+
e.stopPropagation();
|
|
122
|
+
|
|
123
|
+
this._replaceNode(newNodes);
|
|
75
124
|
});
|
|
76
125
|
|
|
77
|
-
const slot = this.shadowRoot.querySelector('slot');
|
|
78
126
|
this.template = this.querySelector('template');
|
|
79
127
|
// console.log('template',this.template);
|
|
80
128
|
}
|
|
81
129
|
|
|
130
|
+
_debounce(func, timeout = 300) {
|
|
131
|
+
let timer;
|
|
132
|
+
return (...args) => {
|
|
133
|
+
const context = this;
|
|
134
|
+
clearTimeout(timer);
|
|
135
|
+
timer = setTimeout(() => {
|
|
136
|
+
func.apply(context, args);
|
|
137
|
+
}, timeout);
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* updates the model with a new value by executing it's `<fx-setvalue>` action.
|
|
143
|
+
*
|
|
144
|
+
* In case the `as='node'` is given the bound node is replaced with the widgets' value with is
|
|
145
|
+
* expected to be a node again.
|
|
146
|
+
*
|
|
147
|
+
* @param val the new value to be set
|
|
148
|
+
*/
|
|
82
149
|
setValue(val) {
|
|
83
150
|
const modelitem = this.getModelItem();
|
|
151
|
+
|
|
152
|
+
if (modelitem?.readonly){
|
|
153
|
+
console.warn('attempt to change readonly node', modelitem);
|
|
154
|
+
return; // do nothing when modelItem is readonly
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if (this.getAttribute('as') === 'node') {
|
|
158
|
+
const widgetValue = this.getWidget().value;
|
|
159
|
+
const replace = this.shadowRoot.getElementById('replace');
|
|
160
|
+
replace.replace(this.nodeset, this.getWidget().value);
|
|
161
|
+
if (modelitem && widgetValue && widgetValue !== modelitem.value) {
|
|
162
|
+
modelitem.value = widgetValue;
|
|
163
|
+
replace.actionPerformed();
|
|
164
|
+
}
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
84
167
|
const setval = this.shadowRoot.getElementById('setvalue');
|
|
85
168
|
setval.setValue(modelitem, val);
|
|
86
169
|
setval.actionPerformed();
|
|
87
170
|
}
|
|
88
171
|
|
|
172
|
+
_replaceNode(node) {
|
|
173
|
+
// Note: clone the node while replacing to prevent the instances to leak through
|
|
174
|
+
this.modelItem.node.replaceWith(node.cloneNode(true));
|
|
175
|
+
this.getOwnerForm().refresh();
|
|
176
|
+
}
|
|
177
|
+
|
|
89
178
|
renderHTML(ref) {
|
|
90
179
|
return `
|
|
91
180
|
${this.label ? `${this.label}` : ''}
|
|
92
181
|
<slot></slot>
|
|
93
|
-
|
|
182
|
+
${
|
|
183
|
+
this.hasAttribute('as') && this.getAttribute('as') === 'node'
|
|
184
|
+
? `<fx-replace id="replace" ref=".">`
|
|
185
|
+
: `<fx-setvalue id="setvalue" ref="${ref}"></fx-setvalue>`
|
|
186
|
+
}
|
|
187
|
+
|
|
94
188
|
`;
|
|
95
189
|
}
|
|
96
190
|
|
|
97
191
|
/**
|
|
192
|
+
* The widget is the actual control being used in the UI e.g. a native input control or any
|
|
193
|
+
* other component that presents a control that can be interacted with.
|
|
194
|
+
*
|
|
195
|
+
* This function returns the widget by querying the children of this control for an element
|
|
196
|
+
* with `class="widget"`. If that cannot be found it searches for an native `input` of any type.
|
|
197
|
+
* If either cannot be found a `<input type="text">` is created.
|
|
98
198
|
*
|
|
99
199
|
* @returns {HTMLElement|*}
|
|
100
200
|
*/
|
|
@@ -114,37 +214,201 @@ export default class FxControl extends XfAbstractControl {
|
|
|
114
214
|
return widget;
|
|
115
215
|
}
|
|
116
216
|
|
|
117
|
-
|
|
217
|
+
/**
|
|
218
|
+
* updates the widget from the modelItem value. During refresh the a control
|
|
219
|
+
* evaluates it's binding expression to determine the bound node. The bound node corresponds
|
|
220
|
+
* to a modelItem which acts a the state object of a node. The modelItem determines the value
|
|
221
|
+
* and the state of the node and set the `value` property of this class.
|
|
222
|
+
*
|
|
223
|
+
* @returns {Promise<void>}
|
|
224
|
+
*/
|
|
118
225
|
async updateWidgetValue() {
|
|
119
226
|
// this.widget[this.valueProp] = this.value;
|
|
227
|
+
|
|
228
|
+
let { widget } = this;
|
|
229
|
+
if (!widget) {
|
|
230
|
+
widget = this;
|
|
231
|
+
}
|
|
232
|
+
// ### value is bound to checkbox
|
|
120
233
|
if (this.valueProp === 'checked') {
|
|
121
234
|
if (this.value === 'true') {
|
|
122
|
-
|
|
235
|
+
widget.checked = true;
|
|
123
236
|
} else {
|
|
124
|
-
|
|
237
|
+
widget.checked = false;
|
|
125
238
|
}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
if (this.hasAttribute('as')) {
|
|
243
|
+
const as = this.getAttribute('as');
|
|
244
|
+
|
|
245
|
+
// ### when there's an `as=text` attribute serialize nodeset to prettified string
|
|
246
|
+
if (as === 'text') {
|
|
247
|
+
const serializer = new XMLSerializer();
|
|
248
|
+
const pretty = Fore.prettifyXml(serializer.serializeToString(this.nodeset));
|
|
249
|
+
widget.value = pretty;
|
|
250
|
+
}
|
|
251
|
+
if (as === 'node' && this.nodeset !== widget.value) {
|
|
252
|
+
// const oldVal = this.nodeset.innerHTML;
|
|
253
|
+
const oldVal = this.nodeset;
|
|
254
|
+
if (widget.value) {
|
|
255
|
+
if (oldVal !== this.widget.value) {
|
|
256
|
+
console.log('changed');
|
|
257
|
+
widget.value = this.nodeset.cloneNode(true);
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
widget.value = this.nodeset.cloneNode(true);
|
|
263
|
+
// todo: should be more like below but that can cause infinite loop when controll trigger update event due to calling a setter for property
|
|
264
|
+
// widget[this.valueProp] = this.nodeset.cloneNode(true);
|
|
265
|
+
console.log('passed value to widget', widget.value);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// ### when there's a url Fore is used as widget and will be loaded from external file
|
|
272
|
+
if (this.url && !this.loaded) {
|
|
273
|
+
// ### evaluate initial data if necessary
|
|
274
|
+
if (this.initial) {
|
|
275
|
+
this.initialNode = evaluateXPathToFirstNode(this.initial, this.nodeset, this);
|
|
276
|
+
console.log('initialNodes', this.initialNode);
|
|
130
277
|
}
|
|
278
|
+
|
|
279
|
+
// ### load the markup from Url
|
|
280
|
+
await this._loadForeFromUrl();
|
|
281
|
+
this.loaded = true;
|
|
282
|
+
|
|
283
|
+
// ### replace default instance of embedded Fore with initial nodes
|
|
284
|
+
// const innerInstance = this.querySelector('fx-instance');
|
|
285
|
+
// console.log('innerInstance',innerInstance);
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/*
|
|
290
|
+
if(this.url && !this.loaded){
|
|
291
|
+
this._loadForeFromUrl();
|
|
292
|
+
this.loaded=true;
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
*/
|
|
296
|
+
if (widget.value !== this.value) {
|
|
131
297
|
widget.value = this.value;
|
|
132
298
|
}
|
|
133
299
|
}
|
|
134
300
|
|
|
301
|
+
/**
|
|
302
|
+
* loads an external Fore from an HTML file given by `url` attribute.
|
|
303
|
+
*
|
|
304
|
+
* Will look for the `<fx-fore>` element within the returned HTML file and return that element.
|
|
305
|
+
*
|
|
306
|
+
* If that cannot be found an error is dispatched.
|
|
307
|
+
*
|
|
308
|
+
* todo: dispatch link error
|
|
309
|
+
* @private
|
|
310
|
+
*/
|
|
311
|
+
async _loadForeFromUrl() {
|
|
312
|
+
console.log('########## loading Fore from ', this.src, '##########');
|
|
313
|
+
try {
|
|
314
|
+
const response = await fetch(this.url, {
|
|
315
|
+
method: 'GET',
|
|
316
|
+
mode: 'cors',
|
|
317
|
+
credentials: 'include',
|
|
318
|
+
headers: {
|
|
319
|
+
'Content-Type': 'text/html',
|
|
320
|
+
},
|
|
321
|
+
});
|
|
322
|
+
const responseContentType = response.headers.get('content-type').toLowerCase();
|
|
323
|
+
console.log('********** responseContentType *********', responseContentType);
|
|
324
|
+
let data;
|
|
325
|
+
if (responseContentType.startsWith('text/html')) {
|
|
326
|
+
data = await response.text().then(result =>
|
|
327
|
+
// console.log('xml ********', result);
|
|
328
|
+
new DOMParser().parseFromString(result, 'text/html'),
|
|
329
|
+
);
|
|
330
|
+
} else {
|
|
331
|
+
data = 'done';
|
|
332
|
+
}
|
|
333
|
+
// const theFore = fxEvaluateXPathToFirstNode('//fx-fore', data.firstElementChild);
|
|
334
|
+
const theFore = data.querySelector('fx-fore');
|
|
335
|
+
// console.log('thefore', theFore)
|
|
336
|
+
theFore.classList.add('widget'); // is the new widget
|
|
337
|
+
const dummy = this.querySelector('input');
|
|
338
|
+
if (this.hasAttribute('shadow')) {
|
|
339
|
+
dummy.parentNode.removeChild(dummy);
|
|
340
|
+
this.shadowRoot.appendChild(theFore);
|
|
341
|
+
} else {
|
|
342
|
+
dummy.replaceWith(theFore);
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
console.log(`########## loaded fore as component ##### ${this.url}`);
|
|
346
|
+
theFore.addEventListener(
|
|
347
|
+
'model-construct-done',
|
|
348
|
+
e => {
|
|
349
|
+
console.log('subcomponent ready', e.target);
|
|
350
|
+
const defaultInst = theFore.querySelector('fx-instance');
|
|
351
|
+
console.log('defaultInst', defaultInst);
|
|
352
|
+
if(this.initialNode){
|
|
353
|
+
const doc = new DOMParser().parseFromString('<data></data>', 'application/xml');
|
|
354
|
+
// Note: Clone the input to prevent the inner fore from editing the outer node
|
|
355
|
+
doc.firstElementChild.appendChild(this.initialNode.cloneNode(true));
|
|
356
|
+
// defaultinst.setInstanceData(this.initialNode);
|
|
357
|
+
defaultInst.setInstanceData(doc);
|
|
358
|
+
}
|
|
359
|
+
console.log('new data', defaultInst.getInstanceData());
|
|
360
|
+
// theFore.getModel().modelConstruct();
|
|
361
|
+
theFore.getModel().updateModel();
|
|
362
|
+
theFore.refresh();
|
|
363
|
+
},
|
|
364
|
+
{ once: true },
|
|
365
|
+
);
|
|
366
|
+
|
|
367
|
+
if (!theFore) {
|
|
368
|
+
this.dispatchEvent(
|
|
369
|
+
new CustomEvent('error', {
|
|
370
|
+
detail: {
|
|
371
|
+
message: `Fore element not found in '${this.src}'. Maybe wrapped within 'template' element?`,
|
|
372
|
+
},
|
|
373
|
+
}),
|
|
374
|
+
);
|
|
375
|
+
}
|
|
376
|
+
console.log('loaded');
|
|
377
|
+
this.dispatchEvent(new CustomEvent('loaded', { detail: { fore: theFore } }));
|
|
378
|
+
} catch (error) {
|
|
379
|
+
console.log('error', error);
|
|
380
|
+
this.getOwnerForm().dispatchEvent(
|
|
381
|
+
new CustomEvent('error', { detail: { message: `${this.url} not found` } }),
|
|
382
|
+
);
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
|
|
135
386
|
getTemplate() {
|
|
136
387
|
return this.querySelector('template');
|
|
137
388
|
}
|
|
138
389
|
|
|
139
390
|
async refresh(force) {
|
|
140
391
|
// console.log('fx-control refresh', this);
|
|
141
|
-
super.refresh();
|
|
392
|
+
super.refresh(force);
|
|
142
393
|
// console.log('refresh template', this.template);
|
|
143
394
|
// const {widget} = this;
|
|
144
395
|
|
|
145
396
|
// ### if we find a ref on control we have a 'select' control of some kind
|
|
146
397
|
const widget = this.getWidget();
|
|
147
|
-
|
|
398
|
+
this._handleBoundWidget(widget);
|
|
399
|
+
Fore.refreshChildren(this, force);
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
/**
|
|
403
|
+
* If the widget itself has a `ref` it binds to another nodeset to provide some
|
|
404
|
+
* dynamic items to be created from a template usually. Examples are dynamic select option lists
|
|
405
|
+
* or a set of checkboxes.
|
|
406
|
+
*
|
|
407
|
+
* @param widget the widget to handle
|
|
408
|
+
* @private
|
|
409
|
+
*/
|
|
410
|
+
_handleBoundWidget(widget) {
|
|
411
|
+
if (widget && widget.hasAttribute('ref')) {
|
|
148
412
|
// ### eval nodeset for list control
|
|
149
413
|
const ref = widget.getAttribute('ref');
|
|
150
414
|
/*
|
|
@@ -158,6 +422,9 @@ export default class FxControl extends XfAbstractControl {
|
|
|
158
422
|
// const nodeset = evaluateXPathToNodes(ref, inscope, this);
|
|
159
423
|
const nodeset = evaluateXPath(ref, inscope, this);
|
|
160
424
|
|
|
425
|
+
// ### bail out when nodeset is array and empty
|
|
426
|
+
if (Array.isArray(nodeset) && nodeset.length === 0) return;
|
|
427
|
+
|
|
161
428
|
// ### clear items
|
|
162
429
|
const { children } = widget;
|
|
163
430
|
Array.from(children).forEach(child => {
|
|
@@ -168,6 +435,14 @@ export default class FxControl extends XfAbstractControl {
|
|
|
168
435
|
|
|
169
436
|
// ### build the items
|
|
170
437
|
if (this.template) {
|
|
438
|
+
if(this.widget.nodeName === "SELECT" &&
|
|
439
|
+
this.widget.hasAttribute('selection') &&
|
|
440
|
+
this.widget.getAttribute('selection') === 'open'){
|
|
441
|
+
const firstTemplateChild=this.template.firstElementChild;
|
|
442
|
+
const option = document.createElement('option');
|
|
443
|
+
this.widget.insertBefore(option,firstTemplateChild);
|
|
444
|
+
}
|
|
445
|
+
|
|
171
446
|
if (nodeset.length) {
|
|
172
447
|
// console.log('nodeset', nodeset);
|
|
173
448
|
Array.from(nodeset).forEach(node => {
|
|
@@ -184,7 +459,6 @@ export default class FxControl extends XfAbstractControl {
|
|
|
184
459
|
}
|
|
185
460
|
}
|
|
186
461
|
}
|
|
187
|
-
Fore.refreshChildren(this, force);
|
|
188
462
|
}
|
|
189
463
|
|
|
190
464
|
updateEntry(newEntry, node) {
|
|
@@ -194,7 +468,7 @@ export default class FxControl extends XfAbstractControl {
|
|
|
194
468
|
const valueAttribute = this._getValueAttribute(newEntry);
|
|
195
469
|
const valueExpr = valueAttribute.value;
|
|
196
470
|
const cutted = valueExpr.substring(1, valueExpr.length - 1);
|
|
197
|
-
const evaluated =
|
|
471
|
+
const evaluated = evaluateXPathToString(cutted, node, newEntry);
|
|
198
472
|
valueAttribute.value = evaluated;
|
|
199
473
|
|
|
200
474
|
if (this.value === evaluated) {
|
|
@@ -230,5 +504,6 @@ export default class FxControl extends XfAbstractControl {
|
|
|
230
504
|
return result;
|
|
231
505
|
}
|
|
232
506
|
}
|
|
233
|
-
|
|
234
|
-
window.customElements.define('fx-control', FxControl);
|
|
507
|
+
if (!customElements.get('fx-control')) {
|
|
508
|
+
window.customElements.define('fx-control', FxControl);
|
|
509
|
+
}
|
package/src/ui/fx-dialog.js
CHANGED
|
@@ -1,20 +1,21 @@
|
|
|
1
|
+
import { Fore } from '../fore.js';
|
|
2
|
+
|
|
1
3
|
export class FxDialog extends HTMLElement {
|
|
4
|
+
static get properties() {
|
|
5
|
+
return {
|
|
6
|
+
id: String,
|
|
7
|
+
};
|
|
8
|
+
}
|
|
2
9
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
}
|
|
10
|
+
constructor() {
|
|
11
|
+
super();
|
|
12
|
+
this.attachShadow({ mode: 'open' });
|
|
13
|
+
}
|
|
8
14
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
this.attachShadow({mode: 'open'});
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
connectedCallback() {
|
|
15
|
-
const style = `
|
|
15
|
+
connectedCallback() {
|
|
16
|
+
const style = `
|
|
16
17
|
:host {
|
|
17
|
-
display:
|
|
18
|
+
display:none;
|
|
18
19
|
height: 100vh;
|
|
19
20
|
width:100vw;
|
|
20
21
|
position:fixed;
|
|
@@ -22,47 +23,60 @@ export class FxDialog extends HTMLElement {
|
|
|
22
23
|
top:0;
|
|
23
24
|
right:0;
|
|
24
25
|
bottom:0;
|
|
26
|
+
transition:opacity 0.4s linear;
|
|
25
27
|
}
|
|
26
|
-
`;
|
|
27
28
|
|
|
28
|
-
|
|
29
|
-
this.id = this.getAttribute('id');
|
|
29
|
+
`;
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
this.shadowRoot.innerHTML = this.render(style);
|
|
32
|
+
this.id = this.getAttribute('id');
|
|
32
33
|
|
|
33
|
-
|
|
34
|
-
if (closeBtn) {
|
|
35
|
-
closeBtn.addEventListener('click', (e) => {
|
|
36
|
-
document.getElementById(this.id).classList.remove('show');
|
|
37
|
-
});
|
|
38
|
-
}
|
|
34
|
+
// const dialog = document.getElementById(this.id);
|
|
39
35
|
|
|
40
|
-
|
|
36
|
+
const closeBtn = this.querySelector('.close-dialog');
|
|
37
|
+
if (closeBtn) {
|
|
38
|
+
closeBtn.addEventListener('click', () => {
|
|
39
|
+
this.classList.remove('show');
|
|
40
|
+
});
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
|
|
44
|
-
|
|
43
|
+
this.addEventListener('transitionend', () => {
|
|
44
|
+
console.log('transitionend');
|
|
45
|
+
// this.style.display = 'none';
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
this.focus();
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
render(styles) {
|
|
52
|
+
return `
|
|
45
53
|
<style>
|
|
46
54
|
${styles}
|
|
47
55
|
</style>
|
|
48
56
|
<slot></slot>
|
|
49
57
|
`;
|
|
50
|
-
|
|
58
|
+
}
|
|
51
59
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
60
|
+
open() {
|
|
61
|
+
window.addEventListener(
|
|
62
|
+
'keyup',
|
|
63
|
+
e => {
|
|
64
|
+
if (e.key === 'Escape') {
|
|
65
|
+
this.hide();
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
{ once: true },
|
|
69
|
+
);
|
|
61
70
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
}
|
|
71
|
+
this.classList.add('show');
|
|
72
|
+
}
|
|
65
73
|
|
|
74
|
+
async hide() {
|
|
75
|
+
await Fore.fadeOutElement(this, 400);
|
|
76
|
+
this.classList.remove('show');
|
|
77
|
+
}
|
|
66
78
|
}
|
|
67
79
|
|
|
68
|
-
customElements.
|
|
80
|
+
if (!customElements.get('fx-dialog')) {
|
|
81
|
+
customElements.define('fx-dialog', FxDialog);
|
|
82
|
+
}
|
package/src/ui/fx-group.js
CHANGED