@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.
Files changed (64) hide show
  1. package/README.md +7 -28
  2. package/dist/fore-dev.js +43 -0
  3. package/dist/fore-dev.js.map +1 -0
  4. package/dist/fore.js +37 -0
  5. package/dist/fore.js.map +1 -0
  6. package/index.js +3 -1
  7. package/package.json +39 -41
  8. package/resources/fore.css +27 -54
  9. package/src/DependencyNotifyingDomFacade.js +5 -13
  10. package/src/ForeElementMixin.js +15 -22
  11. package/src/actions/abstract-action.js +34 -10
  12. package/src/actions/fx-action.js +7 -5
  13. package/src/actions/fx-append.js +8 -17
  14. package/src/actions/fx-confirm.js +5 -3
  15. package/src/actions/fx-delete.js +6 -3
  16. package/src/actions/fx-dispatch.js +9 -8
  17. package/src/actions/fx-hide.js +9 -6
  18. package/src/actions/fx-insert.js +27 -14
  19. package/src/actions/fx-message.js +3 -1
  20. package/src/actions/fx-refresh.js +24 -1
  21. package/src/actions/fx-replace.js +74 -0
  22. package/src/actions/fx-return.js +42 -0
  23. package/src/actions/fx-send.js +3 -1
  24. package/src/actions/fx-setfocus.js +37 -0
  25. package/src/actions/fx-setvalue.js +58 -51
  26. package/src/actions/fx-show.js +12 -4
  27. package/src/actions/fx-toggle.js +13 -9
  28. package/src/actions/fx-update.js +3 -1
  29. package/src/dep_graph.js +1 -1
  30. package/src/drawdown.js +67 -82
  31. package/src/fore.js +143 -26
  32. package/src/functions/fx-function.js +17 -3
  33. package/src/fx-bind.js +40 -200
  34. package/src/fx-fore.js +598 -568
  35. package/src/fx-header.js +3 -1
  36. package/src/fx-instance.js +9 -1
  37. package/src/fx-model.js +60 -27
  38. package/src/fx-submission.js +108 -51
  39. package/src/fx-var.js +7 -4
  40. package/src/getInScopeContext.js +23 -16
  41. package/src/modelitem.js +4 -4
  42. package/src/relevance.js +64 -0
  43. package/src/ui/abstract-control.js +65 -37
  44. package/src/ui/fx-alert.js +7 -1
  45. package/src/ui/fx-case.js +4 -3
  46. package/src/ui/fx-container.js +4 -2
  47. package/src/ui/fx-control.js +315 -34
  48. package/src/ui/fx-dialog.js +50 -45
  49. package/src/ui/fx-group.js +3 -1
  50. package/src/ui/fx-hint.js +4 -1
  51. package/src/ui/fx-inspector.js +118 -17
  52. package/src/ui/fx-items.js +7 -5
  53. package/src/ui/fx-output.js +19 -6
  54. package/src/ui/fx-repeat.js +13 -26
  55. package/src/ui/fx-repeatitem.js +10 -4
  56. package/src/ui/fx-switch.js +5 -3
  57. package/src/ui/fx-trigger.js +3 -1
  58. package/src/xpath-evaluation.js +622 -553
  59. package/src/xpath-util.js +2 -6
  60. package/dist/fore-all.js +0 -140
  61. package/dist/fore-debug.js +0 -140
  62. package/src/.DS_Store +0 -0
  63. package/src/actions/.DS_Store +0 -0
  64. package/src/ui/.DS_Store +0 -0
@@ -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(force) {
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 (this.nodeset === null) {
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.value = this.modelItem.value;
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
- // console.log('dispatching value-changed for ', this);
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('form ready', this.getOwnerForm().ready);
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
- this.dispatch(event, {});
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.widget.setAttribute('required', 'required');
119
- this.classList.add('required');
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 = false;
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', 'readonly');
136
- // this.setAttribute('readonly','readonly');
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
- // this.removeAttribute('readonly');
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
- if (this.widget.hasAttribute('required')) {
203
- return true;
204
- }
205
- return false;
234
+ return this.hasAttribute('required');
206
235
  }
207
236
 
208
237
  isValid() {
209
- if (this.classList.contains('invalid')) {
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
- if (this.widget.hasAttribute('readonly')) {
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
+ }
@@ -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.define('fx-alert', FxAlert);
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
- display: none;
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
- window.customElements.define('fx-case', FxCase);
46
+ if (!customElements.get('fx-case')) {
47
+ window.customElements.define('fx-case', FxCase);
48
+ }
@@ -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
- window.customElements.define('fx-container', FxContainer);
114
+ if (!customElements.get('fx-container')) {
115
+ window.customElements.define('fx-container', FxContainer);
116
+ }