@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.
Files changed (66) hide show
  1. package/README.md +26 -38
  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 +4 -0
  7. package/package.json +42 -42
  8. package/resources/fore.css +186 -0
  9. package/resources/toastify.css +87 -0
  10. package/resources/{fore-styles.css → vars.css} +0 -292
  11. package/src/DependencyNotifyingDomFacade.js +10 -16
  12. package/src/ForeElementMixin.js +26 -19
  13. package/src/actions/abstract-action.js +30 -9
  14. package/src/actions/fx-action.js +6 -4
  15. package/src/actions/fx-append.js +8 -17
  16. package/src/actions/fx-confirm.js +5 -3
  17. package/src/actions/fx-delete.js +6 -3
  18. package/src/actions/fx-dispatch.js +9 -8
  19. package/src/actions/fx-hide.js +10 -6
  20. package/src/actions/fx-insert.js +49 -39
  21. package/src/actions/fx-message.js +3 -1
  22. package/src/actions/fx-refresh.js +15 -1
  23. package/src/actions/fx-replace.js +73 -0
  24. package/src/actions/fx-return.js +42 -0
  25. package/src/actions/fx-send.js +3 -1
  26. package/src/actions/fx-setfocus.js +37 -0
  27. package/src/actions/fx-setvalue.js +58 -51
  28. package/src/actions/fx-show.js +12 -4
  29. package/src/actions/fx-toggle.js +15 -10
  30. package/src/actions/fx-update.js +3 -1
  31. package/src/dep_graph.js +4 -2
  32. package/src/drawdown.js +67 -82
  33. package/src/fore.js +158 -12
  34. package/src/functions/fx-function.js +17 -3
  35. package/src/fx-bind.js +42 -202
  36. package/src/fx-fore.js +599 -567
  37. package/src/fx-header.js +3 -1
  38. package/src/fx-instance.js +9 -1
  39. package/src/fx-model.js +59 -23
  40. package/src/fx-submission.js +106 -48
  41. package/src/fx-var.js +7 -4
  42. package/src/getInScopeContext.js +37 -11
  43. package/src/modelitem.js +4 -4
  44. package/src/relevance.js +64 -0
  45. package/src/ui/abstract-control.js +64 -37
  46. package/src/ui/fx-alert.js +7 -1
  47. package/src/ui/fx-case.js +4 -3
  48. package/src/ui/fx-container.js +7 -1
  49. package/src/ui/fx-control.js +309 -34
  50. package/src/ui/fx-dialog.js +54 -40
  51. package/src/ui/fx-group.js +3 -1
  52. package/src/ui/fx-hint.js +4 -1
  53. package/src/ui/fx-inspector.js +120 -17
  54. package/src/ui/fx-items.js +8 -8
  55. package/src/ui/fx-output.js +16 -5
  56. package/src/ui/fx-repeat.js +33 -41
  57. package/src/ui/fx-repeatitem.js +10 -4
  58. package/src/ui/fx-switch.js +5 -3
  59. package/src/ui/fx-trigger.js +3 -1
  60. package/src/xpath-evaluation.js +621 -576
  61. package/src/xpath-util.js +15 -8
  62. package/dist/fore-all.js +0 -140
  63. package/dist/fore-debug.js +0 -140
  64. package/src/.DS_Store +0 -0
  65. package/src/actions/.DS_Store +0 -0
  66. 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,6 +37,7 @@ 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()) {
@@ -51,12 +53,36 @@ 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.value = this.modelItem.node;
60
+ } else {
61
+ this.value = this.modelItem.value;
62
+ }
63
+
64
+ // console.log('value of widget',this.value);
65
+
66
+ /*
67
+ * todo: find out on which foreign modelitems we might be dependant on when no binds are used.
68
+ *
69
+ * e.g. filter expr on 'ref' 'instance('countries')//country[@continent = instance('default')/continent]'
70
+ *
71
+ * the country node is dependant on instance('default')/continent here (foreign node).
72
+ *
73
+ * possible approach:
74
+ * - pipe ref expression through DependencyNotifyingDomFacade to get referred nodes.
75
+ * - lookup modelItems of referred nodes
76
+ * - add ourselves to boundControls of foreign modelItem -> this control will then get refreshed when the foreign modelItem is changed.
77
+ */
78
+
79
+ // const touched = FxBind.getReferencesForRef(this.ref,Array.from(this.nodeset));
80
+ // console.log('touched',touched);
55
81
 
56
82
  /*
57
83
  this is another case that highlights the fact that an init() function might make sense in general.
58
84
  */
59
- if(!this.modelItem.boundControls.includes(this)){
85
+ if (!this.modelItem.boundControls.includes(this)) {
60
86
  this.modelItem.boundControls.push(this);
61
87
  }
62
88
 
@@ -68,15 +94,10 @@ export default class AbstractControl extends foreElementMixin(HTMLElement) {
68
94
  // if(!this.closest('fx-fore').ready) return; // state change event do not fire during init phase (initial refresh)
69
95
  if (!this.getOwnerForm().ready) return; // state change event do not fire during init phase (initial refresh)
70
96
  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 });
97
+ Fore.dispatch(this, 'value-changed', { path: this.modelItem.path });
74
98
  }
75
- // this.requestUpdate();
76
99
  }
77
100
  }
78
- // Fore.refreshChildren(this,force);
79
- // await this.updateComplete;
80
101
  }
81
102
 
82
103
  /**
@@ -89,13 +110,14 @@ export default class AbstractControl extends foreElementMixin(HTMLElement) {
89
110
  }
90
111
 
91
112
  handleModelItemProperties() {
92
- // console.log('form ready', this.getOwnerForm().ready);
113
+ // console.log('handleModelItemProperties',this.modelItem);
93
114
  this.handleRequired();
94
115
  this.handleReadonly();
95
116
  if (this.getOwnerForm().ready) {
96
117
  this.handleValid();
97
118
  }
98
119
  this.handleRelevant();
120
+ // todo: handleType()
99
121
  }
100
122
 
101
123
  _getForm() {
@@ -104,43 +126,46 @@ export default class AbstractControl extends foreElementMixin(HTMLElement) {
104
126
 
105
127
  _dispatchEvent(event) {
106
128
  if (this.getOwnerForm().ready) {
107
- this.dispatch(event, {});
129
+ Fore.dispatch(this, event, {});
108
130
  }
109
131
  }
110
132
 
111
133
  // eslint-disable-next-line class-methods-use-this
112
134
  handleRequired() {
113
135
  // console.log('mip required', this.modelItem.required);
114
- // const control = this.querySelector('#control');
115
136
  this.widget = this.getWidget();
116
- if (this.isRequired() !== this.modelItem.required) {
137
+ // if (this.required !== this.modelItem.required) {
138
+ // if (this.isRequired() !== this.modelItem.required) {
117
139
  if (this.modelItem.required) {
118
- this.widget.setAttribute('required', 'required');
119
- this.classList.add('required');
140
+ if (this.getOwnerForm().ready){
141
+ if(this.widget.value === ''){
142
+ this.classList.add('isRequiredFalse');
143
+ }else{
144
+ this.classList.remove('isRequiredFalse');
145
+ }
146
+ }
147
+ this.widget.setAttribute('required', '');
148
+ this.setAttribute('required', '');
120
149
  this._dispatchEvent('required');
121
150
  } else {
122
151
  this.widget.removeAttribute('required');
123
- this.required = false;
124
- // this.removeAttribute('required');
125
- this.classList.toggle('required');
152
+ this.removeAttribute('required');
126
153
  this._dispatchEvent('optional');
127
154
  }
128
- }
155
+ // }
129
156
  }
130
157
 
131
158
  handleReadonly() {
132
159
  // console.log('mip readonly', this.modelItem.isReadonly);
133
160
  if (this.isReadonly() !== this.modelItem.readonly) {
134
161
  if (this.modelItem.readonly) {
135
- this.widget.setAttribute('readonly', 'readonly');
136
- // this.setAttribute('readonly','readonly');
137
- this.classList.toggle('readonly');
162
+ this.widget.setAttribute('readonly', '');
163
+ this.setAttribute('readonly', '');
138
164
  this._dispatchEvent('readonly');
139
165
  }
140
166
  if (!this.modelItem.readonly) {
141
167
  this.widget.removeAttribute('readonly');
142
- // this.removeAttribute('readonly');
143
- this.classList.toggle('readonly');
168
+ this.removeAttribute('readonly');
144
169
  this._dispatchEvent('readwrite');
145
170
  }
146
171
  }
@@ -153,12 +178,12 @@ export default class AbstractControl extends foreElementMixin(HTMLElement) {
153
178
 
154
179
  if (this.isValid() !== this.modelItem.constraint) {
155
180
  if (this.modelItem.constraint) {
156
- this.classList.remove('invalid');
157
181
  if (alert) alert.style.display = 'none';
158
182
  this._dispatchEvent('valid');
183
+ this.removeAttribute('invalid');
159
184
  } else {
185
+ this.setAttribute('invalid', '');
160
186
  // ### constraint is invalid - handle alerts
161
- this.classList.add('invalid');
162
187
  if (alert) {
163
188
  alert.style.display = 'block';
164
189
  }
@@ -185,6 +210,12 @@ export default class AbstractControl extends foreElementMixin(HTMLElement) {
185
210
 
186
211
  handleRelevant() {
187
212
  // console.log('mip valid', this.modelItem.enabled);
213
+ const item = this.modelItem.node;
214
+ if (Array.isArray(item) && item.length === 0) {
215
+ this._dispatchEvent('nonrelevant');
216
+ this.style.display = 'none';
217
+ return;
218
+ }
188
219
  if (this.isEnabled() !== this.modelItem.relevant) {
189
220
  if (this.modelItem.relevant) {
190
221
  this._dispatchEvent('relevant');
@@ -199,14 +230,12 @@ export default class AbstractControl extends foreElementMixin(HTMLElement) {
199
230
  }
200
231
 
201
232
  isRequired() {
202
- if (this.widget.hasAttribute('required')) {
203
- return true;
204
- }
205
- return false;
233
+ return this.hasAttribute('required');
206
234
  }
207
235
 
208
236
  isValid() {
209
- if (this.classList.contains('invalid')) {
237
+ // return this.valid;
238
+ if (this.hasAttribute('invalid')) {
210
239
  return false;
211
240
  }
212
241
  return true;
@@ -214,10 +243,7 @@ export default class AbstractControl extends foreElementMixin(HTMLElement) {
214
243
 
215
244
  isReadonly() {
216
245
  // const widget = this.querySelector('#widget');
217
- if (this.widget.hasAttribute('readonly')) {
218
- return true;
219
- }
220
- return false;
246
+ return this.hasAttribute('readonly');
221
247
  }
222
248
 
223
249
  isEnabled() {
@@ -257,5 +283,6 @@ export default class AbstractControl extends foreElementMixin(HTMLElement) {
257
283
  })();
258
284
  }
259
285
  }
260
-
261
- window.customElements.define('fx-abstract-control', AbstractControl);
286
+ if (!customElements.get('fx-abstract-control')) {
287
+ window.customElements.define('fx-abstract-control', AbstractControl);
288
+ }
@@ -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,6 +44,10 @@ 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)) {
48
+ this.modelItem.boundControls.push(this);
49
+ }
50
+
47
51
  // this.value = this.modelItem.value;
48
52
  }
49
53
 
@@ -107,4 +111,6 @@ export class FxContainer extends foreElementMixin(HTMLElement) {
107
111
  }
108
112
  }
109
113
 
110
- window.customElements.define('fx-container', FxContainer);
114
+ if (!customElements.get('fx-container')) {
115
+ window.customElements.define('fx-container', FxContainer);
116
+ }