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