@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/relevance.js
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
export class Relevance {
|
|
2
|
+
static selectRelevant(element, type) {
|
|
3
|
+
console.log('selectRelevant', type);
|
|
4
|
+
switch (type) {
|
|
5
|
+
case 'xml':
|
|
6
|
+
return Relevance._relevantXmlNodes(element);
|
|
7
|
+
default:
|
|
8
|
+
console.warn(`relevance selection not supported for type:${element.type}`);
|
|
9
|
+
return element.nodeset;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
static _relevantXmlNodes(element) {
|
|
14
|
+
// ### no relevance selection - current nodeset is used 'as-is'
|
|
15
|
+
const nonrelevant = element.getAttribute('nonrelevant');
|
|
16
|
+
if (nonrelevant === 'keep') {
|
|
17
|
+
return element.nodeset;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// first check if nodeset of submission is relevant - otherwise bail out
|
|
21
|
+
const mi = element.getModel().getModelItem(element.nodeset);
|
|
22
|
+
if (mi && !mi.relevant) return null;
|
|
23
|
+
|
|
24
|
+
const root = element.nodeset.cloneNode(false);
|
|
25
|
+
|
|
26
|
+
if (element.nodeset.children.length === 0 && Relevance._isRelevant(element, element.nodeset)) {
|
|
27
|
+
return element.nodeset;
|
|
28
|
+
}
|
|
29
|
+
return Relevance._filterRelevant(element, element.nodeset, root);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
static _filterRelevant(element, node, result) {
|
|
33
|
+
const { childNodes } = node;
|
|
34
|
+
Array.from(childNodes).forEach(n => {
|
|
35
|
+
if (Relevance._isRelevant(element, n)) {
|
|
36
|
+
const clone = n.cloneNode(false);
|
|
37
|
+
result.appendChild(clone);
|
|
38
|
+
const { attributes } = n;
|
|
39
|
+
if (attributes) {
|
|
40
|
+
Array.from(attributes).forEach(attr => {
|
|
41
|
+
if (Relevance._isRelevant(element, attr)) {
|
|
42
|
+
clone.setAttribute(attr.nodeName, attr.value);
|
|
43
|
+
} else if (element.nonrelevant === 'empty') {
|
|
44
|
+
clone.setAttribute(attr.nodeName, '');
|
|
45
|
+
} else {
|
|
46
|
+
clone.removeAttribute(attr.nodeName);
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
return Relevance._filterRelevant(element, n, clone);
|
|
51
|
+
}
|
|
52
|
+
return null;
|
|
53
|
+
});
|
|
54
|
+
return result;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
static _isRelevant(element, node) {
|
|
58
|
+
const mi = element.getModel().getModelItem(node);
|
|
59
|
+
if (!mi || mi.relevant) {
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import '../fx-model.js';
|
|
2
2
|
import { foreElementMixin } from '../ForeElementMixin.js';
|
|
3
3
|
import { ModelItem } from '../modelitem.js';
|
|
4
|
+
import { Fore } from '../fore.js';
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* `AbstractControl` -
|
|
@@ -26,7 +27,7 @@ export default class AbstractControl extends foreElementMixin(HTMLElement) {
|
|
|
26
27
|
/**
|
|
27
28
|
* (re)apply all modelItem state properties to this control. model -> UI
|
|
28
29
|
*/
|
|
29
|
-
async refresh(
|
|
30
|
+
async refresh() {
|
|
30
31
|
// console.log('### AbstractControl.refresh on : ', this);
|
|
31
32
|
|
|
32
33
|
const currentVal = this.value;
|
|
@@ -36,12 +37,13 @@ export default class AbstractControl extends foreElementMixin(HTMLElement) {
|
|
|
36
37
|
|
|
37
38
|
// await this.updateComplete;
|
|
38
39
|
// await this.getWidget();
|
|
40
|
+
this.oldVal = this.nodeset ? this.nodeset : null;
|
|
39
41
|
this.evalInContext();
|
|
40
42
|
|
|
41
43
|
if (this.isBound()) {
|
|
42
44
|
// this.control = this.querySelector('#control');
|
|
43
45
|
|
|
44
|
-
if
|
|
46
|
+
if(!this.nodeset){
|
|
45
47
|
this.style.display = 'none';
|
|
46
48
|
return;
|
|
47
49
|
}
|
|
@@ -51,12 +53,37 @@ export default class AbstractControl extends foreElementMixin(HTMLElement) {
|
|
|
51
53
|
if (this.modelItem instanceof ModelItem) {
|
|
52
54
|
// console.log('### XfAbstractControl.refresh modelItem : ', this.modelItem);
|
|
53
55
|
|
|
54
|
-
this.
|
|
56
|
+
if (this.hasAttribute('as') && this.getAttribute('as') === 'node') {
|
|
57
|
+
// console.log('as', this.nodeset);
|
|
58
|
+
// this.modelItem.value = this.nodeset;
|
|
59
|
+
this.modelItem.node = this.nodeset;
|
|
60
|
+
this.value = this.modelItem.node;
|
|
61
|
+
} else {
|
|
62
|
+
this.value = this.modelItem.value;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// console.log('value of widget',this.value);
|
|
66
|
+
|
|
67
|
+
/*
|
|
68
|
+
* todo: find out on which foreign modelitems we might be dependant on when no binds are used.
|
|
69
|
+
*
|
|
70
|
+
* e.g. filter expr on 'ref' 'instance('countries')//country[@continent = instance('default')/continent]'
|
|
71
|
+
*
|
|
72
|
+
* the country node is dependant on instance('default')/continent here (foreign node).
|
|
73
|
+
*
|
|
74
|
+
* possible approach:
|
|
75
|
+
* - pipe ref expression through DependencyNotifyingDomFacade to get referred nodes.
|
|
76
|
+
* - lookup modelItems of referred nodes
|
|
77
|
+
* - add ourselves to boundControls of foreign modelItem -> this control will then get refreshed when the foreign modelItem is changed.
|
|
78
|
+
*/
|
|
79
|
+
|
|
80
|
+
// const touched = FxBind.getReferencesForRef(this.ref,Array.from(this.nodeset));
|
|
81
|
+
// console.log('touched',touched);
|
|
55
82
|
|
|
56
83
|
/*
|
|
57
84
|
this is another case that highlights the fact that an init() function might make sense in general.
|
|
58
85
|
*/
|
|
59
|
-
if(!this.modelItem.boundControls.includes(this)){
|
|
86
|
+
if (!this.modelItem.boundControls.includes(this)) {
|
|
60
87
|
this.modelItem.boundControls.push(this);
|
|
61
88
|
}
|
|
62
89
|
|
|
@@ -68,15 +95,10 @@ export default class AbstractControl extends foreElementMixin(HTMLElement) {
|
|
|
68
95
|
// if(!this.closest('fx-fore').ready) return; // state change event do not fire during init phase (initial refresh)
|
|
69
96
|
if (!this.getOwnerForm().ready) return; // state change event do not fire during init phase (initial refresh)
|
|
70
97
|
if (currentVal !== this.value) {
|
|
71
|
-
|
|
72
|
-
// console.log('value-changed path ', this.modelItem.path);
|
|
73
|
-
this.dispatch('value-changed', { path: this.modelItem.path });
|
|
98
|
+
Fore.dispatch(this, 'value-changed', { path: this.modelItem.path });
|
|
74
99
|
}
|
|
75
|
-
// this.requestUpdate();
|
|
76
100
|
}
|
|
77
101
|
}
|
|
78
|
-
// Fore.refreshChildren(this,force);
|
|
79
|
-
// await this.updateComplete;
|
|
80
102
|
}
|
|
81
103
|
|
|
82
104
|
/**
|
|
@@ -89,13 +111,14 @@ export default class AbstractControl extends foreElementMixin(HTMLElement) {
|
|
|
89
111
|
}
|
|
90
112
|
|
|
91
113
|
handleModelItemProperties() {
|
|
92
|
-
// console.log('
|
|
114
|
+
// console.log('handleModelItemProperties',this.modelItem);
|
|
93
115
|
this.handleRequired();
|
|
94
116
|
this.handleReadonly();
|
|
95
117
|
if (this.getOwnerForm().ready) {
|
|
96
118
|
this.handleValid();
|
|
97
119
|
}
|
|
98
120
|
this.handleRelevant();
|
|
121
|
+
// todo: handleType()
|
|
99
122
|
}
|
|
100
123
|
|
|
101
124
|
_getForm() {
|
|
@@ -104,25 +127,30 @@ export default class AbstractControl extends foreElementMixin(HTMLElement) {
|
|
|
104
127
|
|
|
105
128
|
_dispatchEvent(event) {
|
|
106
129
|
if (this.getOwnerForm().ready) {
|
|
107
|
-
|
|
130
|
+
Fore.dispatch(this, event, {});
|
|
108
131
|
}
|
|
109
132
|
}
|
|
110
133
|
|
|
111
134
|
// eslint-disable-next-line class-methods-use-this
|
|
112
135
|
handleRequired() {
|
|
113
136
|
// console.log('mip required', this.modelItem.required);
|
|
114
|
-
// const control = this.querySelector('#control');
|
|
115
137
|
this.widget = this.getWidget();
|
|
138
|
+
// if (this.required !== this.modelItem.required) {
|
|
116
139
|
if (this.isRequired() !== this.modelItem.required) {
|
|
117
140
|
if (this.modelItem.required) {
|
|
118
|
-
this.
|
|
119
|
-
|
|
141
|
+
if (this.getOwnerForm().ready){
|
|
142
|
+
if(this.widget.value === ''){
|
|
143
|
+
this.classList.add('isRequiredFalse');
|
|
144
|
+
}else{
|
|
145
|
+
this.classList.remove('isRequiredFalse');
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
this.widget.setAttribute('required', '');
|
|
149
|
+
this.setAttribute('required', '');
|
|
120
150
|
this._dispatchEvent('required');
|
|
121
151
|
} else {
|
|
122
152
|
this.widget.removeAttribute('required');
|
|
123
|
-
this.required
|
|
124
|
-
// this.removeAttribute('required');
|
|
125
|
-
this.classList.toggle('required');
|
|
153
|
+
this.removeAttribute('required');
|
|
126
154
|
this._dispatchEvent('optional');
|
|
127
155
|
}
|
|
128
156
|
}
|
|
@@ -132,15 +160,13 @@ export default class AbstractControl extends foreElementMixin(HTMLElement) {
|
|
|
132
160
|
// console.log('mip readonly', this.modelItem.isReadonly);
|
|
133
161
|
if (this.isReadonly() !== this.modelItem.readonly) {
|
|
134
162
|
if (this.modelItem.readonly) {
|
|
135
|
-
this.widget.setAttribute('readonly', '
|
|
136
|
-
|
|
137
|
-
this.classList.toggle('readonly');
|
|
163
|
+
this.widget.setAttribute('readonly', '');
|
|
164
|
+
this.setAttribute('readonly', '');
|
|
138
165
|
this._dispatchEvent('readonly');
|
|
139
166
|
}
|
|
140
167
|
if (!this.modelItem.readonly) {
|
|
141
168
|
this.widget.removeAttribute('readonly');
|
|
142
|
-
|
|
143
|
-
this.classList.toggle('readonly');
|
|
169
|
+
this.removeAttribute('readonly');
|
|
144
170
|
this._dispatchEvent('readwrite');
|
|
145
171
|
}
|
|
146
172
|
}
|
|
@@ -153,18 +179,18 @@ export default class AbstractControl extends foreElementMixin(HTMLElement) {
|
|
|
153
179
|
|
|
154
180
|
if (this.isValid() !== this.modelItem.constraint) {
|
|
155
181
|
if (this.modelItem.constraint) {
|
|
156
|
-
this.classList.remove('invalid');
|
|
157
182
|
if (alert) alert.style.display = 'none';
|
|
158
183
|
this._dispatchEvent('valid');
|
|
184
|
+
this.removeAttribute('invalid');
|
|
159
185
|
} else {
|
|
186
|
+
this.setAttribute('invalid', '');
|
|
160
187
|
// ### constraint is invalid - handle alerts
|
|
161
|
-
this.classList.add('invalid');
|
|
162
188
|
if (alert) {
|
|
163
189
|
alert.style.display = 'block';
|
|
164
190
|
}
|
|
165
191
|
if (this.modelItem.alerts.length !== 0) {
|
|
166
192
|
const { alerts } = this.modelItem;
|
|
167
|
-
console.log('alerts from bind: ', alerts);
|
|
193
|
+
// console.log('alerts from bind: ', alerts);
|
|
168
194
|
|
|
169
195
|
const controlAlert = this.querySelector('fx-alert');
|
|
170
196
|
if (!controlAlert) {
|
|
@@ -185,6 +211,12 @@ export default class AbstractControl extends foreElementMixin(HTMLElement) {
|
|
|
185
211
|
|
|
186
212
|
handleRelevant() {
|
|
187
213
|
// console.log('mip valid', this.modelItem.enabled);
|
|
214
|
+
const item = this.modelItem.node;
|
|
215
|
+
if (Array.isArray(item) && item.length === 0) {
|
|
216
|
+
this._dispatchEvent('nonrelevant');
|
|
217
|
+
this.style.display = 'none';
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
188
220
|
if (this.isEnabled() !== this.modelItem.relevant) {
|
|
189
221
|
if (this.modelItem.relevant) {
|
|
190
222
|
this._dispatchEvent('relevant');
|
|
@@ -199,14 +231,12 @@ export default class AbstractControl extends foreElementMixin(HTMLElement) {
|
|
|
199
231
|
}
|
|
200
232
|
|
|
201
233
|
isRequired() {
|
|
202
|
-
|
|
203
|
-
return true;
|
|
204
|
-
}
|
|
205
|
-
return false;
|
|
234
|
+
return this.hasAttribute('required');
|
|
206
235
|
}
|
|
207
236
|
|
|
208
237
|
isValid() {
|
|
209
|
-
|
|
238
|
+
// return this.valid;
|
|
239
|
+
if (this.hasAttribute('invalid')) {
|
|
210
240
|
return false;
|
|
211
241
|
}
|
|
212
242
|
return true;
|
|
@@ -214,10 +244,7 @@ export default class AbstractControl extends foreElementMixin(HTMLElement) {
|
|
|
214
244
|
|
|
215
245
|
isReadonly() {
|
|
216
246
|
// const widget = this.querySelector('#widget');
|
|
217
|
-
|
|
218
|
-
return true;
|
|
219
|
-
}
|
|
220
|
-
return false;
|
|
247
|
+
return this.hasAttribute('readonly');
|
|
221
248
|
}
|
|
222
249
|
|
|
223
250
|
isEnabled() {
|
|
@@ -257,5 +284,6 @@ export default class AbstractControl extends foreElementMixin(HTMLElement) {
|
|
|
257
284
|
})();
|
|
258
285
|
}
|
|
259
286
|
}
|
|
260
|
-
|
|
261
|
-
window.customElements.define('fx-abstract-control', AbstractControl);
|
|
287
|
+
if (!customElements.get('fx-abstract-control')) {
|
|
288
|
+
window.customElements.define('fx-abstract-control', AbstractControl);
|
|
289
|
+
}
|
package/src/ui/fx-alert.js
CHANGED
|
@@ -29,9 +29,15 @@ export class FxAlert extends AbstractControl {
|
|
|
29
29
|
`;
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
+
getWidget() {
|
|
33
|
+
return this;
|
|
34
|
+
}
|
|
35
|
+
|
|
32
36
|
async updateWidgetValue() {
|
|
33
37
|
console.log('alert update', this);
|
|
34
38
|
this.innerHTML = this.value;
|
|
35
39
|
}
|
|
36
40
|
}
|
|
37
|
-
customElements.
|
|
41
|
+
if (!customElements.get('fx-alert')) {
|
|
42
|
+
customElements.define('fx-alert', FxAlert);
|
|
43
|
+
}
|
package/src/ui/fx-case.js
CHANGED
|
@@ -26,7 +26,7 @@ class FxCase extends HTMLElement {
|
|
|
26
26
|
|
|
27
27
|
const style = `
|
|
28
28
|
:host {
|
|
29
|
-
|
|
29
|
+
visibility: none;
|
|
30
30
|
}
|
|
31
31
|
`;
|
|
32
32
|
const html = `
|
|
@@ -40,8 +40,9 @@ class FxCase extends HTMLElement {
|
|
|
40
40
|
${html}
|
|
41
41
|
`;
|
|
42
42
|
|
|
43
|
-
this.style.display = 'none';
|
|
44
43
|
}
|
|
45
44
|
}
|
|
46
45
|
|
|
47
|
-
|
|
46
|
+
if (!customElements.get('fx-case')) {
|
|
47
|
+
window.customElements.define('fx-case', FxCase);
|
|
48
|
+
}
|
package/src/ui/fx-container.js
CHANGED
|
@@ -44,7 +44,7 @@ export class FxContainer extends foreElementMixin(HTMLElement) {
|
|
|
44
44
|
if (this.isBound()) {
|
|
45
45
|
this.evalInContext();
|
|
46
46
|
this.modelItem = this.getModelItem();
|
|
47
|
-
if(!this.modelItem.boundControls.includes(this)){
|
|
47
|
+
if (this.modelItem && !this.modelItem.boundControls.includes(this)) {
|
|
48
48
|
this.modelItem.boundControls.push(this);
|
|
49
49
|
}
|
|
50
50
|
|
|
@@ -111,4 +111,6 @@ export class FxContainer extends foreElementMixin(HTMLElement) {
|
|
|
111
111
|
}
|
|
112
112
|
}
|
|
113
113
|
|
|
114
|
-
|
|
114
|
+
if (!customElements.get('fx-container')) {
|
|
115
|
+
window.customElements.define('fx-container', FxContainer);
|
|
116
|
+
}
|