@jinntec/fore 1.2.0 → 1.3.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 (42) hide show
  1. package/dist/fore-dev.js +8 -8
  2. package/dist/fore-dev.js.map +1 -1
  3. package/dist/fore.js +7 -7
  4. package/dist/fore.js.map +1 -1
  5. package/index.js +1 -0
  6. package/package.json +2 -2
  7. package/resources/fore.css +95 -72
  8. package/src/actions/abstract-action.js +48 -6
  9. package/src/actions/fx-action.js +1 -2
  10. package/src/actions/fx-confirm.js +2 -2
  11. package/src/actions/fx-delete.js +53 -62
  12. package/src/actions/fx-hide.js +3 -1
  13. package/src/actions/fx-message.js +25 -1
  14. package/src/actions/fx-reload.js +30 -0
  15. package/src/actions/fx-send.js +11 -1
  16. package/src/actions/fx-setfocus.js +32 -5
  17. package/src/actions/fx-setvalue.js +4 -4
  18. package/src/actions/fx-show.js +1 -0
  19. package/src/actions/fx-toggle.js +5 -0
  20. package/src/events.js +24 -0
  21. package/src/fore.js +71 -8
  22. package/src/fx-bind.js +1 -1
  23. package/src/fx-fore.js +65 -14
  24. package/src/fx-instance.js +33 -8
  25. package/src/fx-model.js +435 -441
  26. package/src/fx-submission.js +76 -62
  27. package/src/getInScopeContext.js +91 -83
  28. package/src/modelitem.js +2 -2
  29. package/src/relevance.js +1 -1
  30. package/src/ui/abstract-control.js +108 -22
  31. package/src/ui/fx-alert.js +0 -1
  32. package/src/ui/fx-container.js +22 -26
  33. package/src/ui/fx-control.js +84 -34
  34. package/src/ui/fx-group.js +5 -0
  35. package/src/ui/fx-inspector.js +5 -0
  36. package/src/ui/fx-output.js +14 -14
  37. package/src/ui/fx-repeat.js +2 -2
  38. package/src/ui/fx-repeatitem.js +5 -3
  39. package/src/ui/fx-switch.js +11 -7
  40. package/src/ui/fx-trigger.js +15 -9
  41. package/src/xpath-evaluation.js +28 -17
  42. package/src/xpath-util.js +13 -0
@@ -81,11 +81,12 @@ export class FxSubmission extends foreElementMixin(HTMLElement) {
81
81
  if (this.validate==='true') {
82
82
  const valid = model.revalidate();
83
83
  if (!valid) {
84
- console.log('validation failed. Bubmission stopped');
84
+ console.log('validation failed. Submission stopped');
85
+ this.getOwnerForm().classList.add('submit-validation-failed');
85
86
  // ### allow alerts to pop up
86
87
  // this.dispatch('submit-error', {});
87
88
  Fore.dispatch(this, 'submit-error', {});
88
- this.getModel().parentNode.refresh();
89
+ this.getModel().parentNode.refresh(true);
89
90
  return;
90
91
  }
91
92
  }
@@ -152,29 +153,39 @@ export class FxSubmission extends foreElementMixin(HTMLElement) {
152
153
  return;
153
154
  }
154
155
 
155
- if(resolvedUrl.startsWith('localStore:') && this.method === 'post'){
156
- // let data = this._parse(serialized, instance);
157
- const key = resolvedUrl.substring(resolvedUrl.indexOf(':')+1);
158
- localStorage.setItem(key,serialized);
159
- Fore.dispatch(this, 'submit-done', {});
160
- return;
161
- }
156
+ if(resolvedUrl.startsWith('localStore:')){
162
157
 
163
- if(resolvedUrl.startsWith('localStore:') && (this.method === 'consume' || this.method === 'get')){
164
- // let data = this._parse(serialized, instance);
165
- this.replace = 'instance';
166
- const key = resolvedUrl.substring(resolvedUrl.indexOf(':')+1);
167
- const serialized = localStorage.getItem(key);
168
- if(!serialized){
169
- Fore.dispatch(this, 'submit-error', { message: `Error reading key ${key} from localstorage` });
170
- return;
158
+ if(this.method === 'get' || this.method === 'consume'){
159
+ // let data = this._parse(serialized, instance);
160
+ this.replace = 'instance';
161
+ const key = resolvedUrl.substring(resolvedUrl.indexOf(':')+1);
162
+ const serialized = localStorage.getItem(key);
163
+ if(!serialized){
164
+ Fore.dispatch(this, 'submit-error', { message: `Error reading key ${key} from localstorage` });
165
+ return;
166
+ }
167
+ let data = this._parse(serialized, instance);
168
+ this._handleResponse(data);
169
+ if(this.method === 'consume'){
170
+ localStorage.removeItem(key);
171
+ }
172
+ Fore.dispatch(this, 'submit-done', {});
171
173
  }
172
- let data = this._parse(serialized, instance);
173
- this._handleResponse(data);
174
- if(this.method === 'consume'){
174
+ if(this.method === 'post'){
175
+ // let data = this._parse(serialized, instance);
176
+ const key = resolvedUrl.substring(resolvedUrl.indexOf(':')+1);
177
+ localStorage.setItem(key,serialized);
178
+ this._handleResponse(instance.instanceData);
179
+ Fore.dispatch(this, 'submit-done', {});
180
+ }
181
+ if(this.method === 'delete'){
182
+ const key = resolvedUrl.substring(resolvedUrl.indexOf(':')+1);
175
183
  localStorage.removeItem(key);
184
+ const newInst = new DOMParser().parseFromString('<data></data>', 'application/xml');
185
+ this._handleResponse(newInst);
186
+ Fore.dispatch(this, 'submit-done', {});
176
187
  }
177
- Fore.dispatch(this, 'submit-done', {});
188
+
178
189
  return;
179
190
  }
180
191
 
@@ -182,52 +193,51 @@ export class FxSubmission extends foreElementMixin(HTMLElement) {
182
193
  const headers = this._getHeaders();
183
194
  console.log('headers', headers);
184
195
 
185
- // ### map urlencoded-post to post for fetch
186
- if (this.method === 'urlencoded-post') {
187
- this.method = 'post';
188
- }
189
-
190
196
  if (!this.methods.includes(this.method.toLowerCase())) {
191
197
  // this.dispatch('error', { message: `Unknown method ${this.method}` });
192
198
  Fore.dispatch(this, 'error', { message: `Unknown method ${this.method}` });
193
199
  return;
194
200
  }
195
- const response = await fetch(resolvedUrl, {
196
- method: this.method,
197
- mode: 'cors',
198
- credentials: 'include',
199
- headers,
200
- body: serialized,
201
- });
201
+ try{
202
+ const response = await fetch(resolvedUrl, {
203
+ method: this.method,
204
+ mode: 'cors',
205
+ credentials: 'include',
206
+ headers,
207
+ body: serialized,
208
+ });
202
209
 
203
- if (!response.ok || response.status > 400) {
204
- // this.dispatch('submit-error', { message: `Error while submitting ${this.id}` });
205
- Fore.dispatch(this, 'submit-error', { message: `Error while submitting ${this.id}` });
206
- return;
207
- }
210
+ if (!response.ok || response.status > 400) {
211
+ // this.dispatch('submit-error', { message: `Error while submitting ${this.id}` });
212
+ Fore.dispatch(this, 'submit-error', { message: `Error while submitting ${this.id}` });
213
+ return;
214
+ }
208
215
 
209
- const contentType = response.headers.get('content-type').toLowerCase();
210
- if (
211
- contentType.startsWith('text/plain') ||
212
- contentType.startsWith('text/html') ||
213
- contentType.startsWith('text/markdown')
214
- ) {
215
- const text = await response.text();
216
- this._handleResponse(text);
217
- } else if (contentType.startsWith('application/json')) {
218
- const json = await response.json();
219
- this._handleResponse(json);
220
- } else if (contentType.startsWith('application/xml')) {
221
- const text = await response.text();
222
- const xml = new DOMParser().parseFromString(text, 'application/xml');
223
- this._handleResponse(xml);
224
- } else {
225
- const blob = await response.blob();
226
- this._handleResponse(blob);
227
- }
216
+ const contentType = response.headers.get('content-type').toLowerCase();
217
+ if (
218
+ contentType.startsWith('text/plain') ||
219
+ contentType.startsWith('text/html') ||
220
+ contentType.startsWith('text/markdown')
221
+ ) {
222
+ const text = await response.text();
223
+ this._handleResponse(text);
224
+ } else if (contentType.startsWith('application/json')) {
225
+ const json = await response.json();
226
+ this._handleResponse(json);
227
+ } else if (contentType.startsWith('application/xml')) {
228
+ const text = await response.text();
229
+ const xml = new DOMParser().parseFromString(text, 'application/xml');
230
+ this._handleResponse(xml);
231
+ } else {
232
+ const blob = await response.blob();
233
+ this._handleResponse(blob);
234
+ }
228
235
 
229
- // this.dispatch('submit-done', {});
230
- Fore.dispatch(this, 'submit-done', {});
236
+ // this.dispatch('submit-done', {});
237
+ Fore.dispatch(this, 'submit-done', {});
238
+ } catch (error){
239
+ Fore.dispatch(this, 'submit-error', {error:error.message});
240
+ }
231
241
  }
232
242
 
233
243
  _parse(serialized, instance) {
@@ -242,7 +252,7 @@ export class FxSubmission extends foreElementMixin(HTMLElement) {
242
252
  }
243
253
 
244
254
  _serialize(instanceType, relevantNodes) {
245
- if (this.method === 'urlencoded-post') {
255
+ if (this.serialization === 'application/x-www-form-urlencoded') {
246
256
  // this.method = 'post';
247
257
  const params = new URLSearchParams();
248
258
  // console.log('nodes to serialize', relevantNodes);
@@ -267,7 +277,7 @@ export class FxSubmission extends foreElementMixin(HTMLElement) {
267
277
 
268
278
  // ### set content-type header according to type of instance
269
279
  const instance = this.getInstance();
270
- const contentType = Fore.getContentType(instance, this.method);
280
+ const contentType = Fore.getContentType(instance, this.serialization);
271
281
  headers.append('Content-Type', contentType);
272
282
  // ### needed to overwrite browsers' setting of 'Accept' header
273
283
  if (headers.has('Accept')) {
@@ -340,7 +350,11 @@ export class FxSubmission extends foreElementMixin(HTMLElement) {
340
350
  this,
341
351
  );
342
352
  console.log('theTarget', theTarget);
343
- theTarget.innerHTML = data;
353
+ if(data.nodeType === Node.DOCUMENT_NODE){
354
+ theTarget.appendChild( data.firstElementChild);
355
+ }else{
356
+ theTarget.innerHTML = data;
357
+ }
344
358
  } else {
345
359
  const instanceData = data;
346
360
  targetInstance.instanceData = instanceData;
@@ -1,106 +1,114 @@
1
- import { evaluateXPathToFirstNode } from './xpath-evaluation.js';
2
- import { Fore } from './fore.js';
1
+ import {evaluateXPathToFirstNode} from './xpath-evaluation.js';
2
+ import {Fore} from './fore.js';
3
3
 
4
- import { XPathUtil } from './xpath-util.js';
4
+ import {XPathUtil} from './xpath-util.js';
5
5
 
6
6
  function _getElement(node) {
7
- if (node && node.nodeType && node.nodeType === Node.ATTRIBUTE_NODE) {
8
- // The context of an attribute is the ref of the element it's defined on
9
- return node.ownerElement;
10
- }
11
-
12
- if (node.nodeType === Node.ELEMENT_NODE) {
13
- // The context of a query should be the element having a ref
14
- return node;
15
- }
16
-
17
- // For text nodes, just start looking from the parent element
18
- return node.parentNode;
7
+ if (node && node.nodeType && node.nodeType === Node.ATTRIBUTE_NODE) {
8
+ // The context of an attribute is the ref of the element it's defined on
9
+ return node.ownerElement;
10
+ }
11
+
12
+ if (node.nodeType === Node.ELEMENT_NODE) {
13
+ // The context of a query should be the element having a ref
14
+ return node;
15
+ }
16
+
17
+ // For text nodes, just start looking from the parent element
18
+ return node.parentNode;
19
19
  }
20
20
 
21
21
  function _getForeContext(node) {
22
- return node.closest('fx-fore');
22
+ return node.closest('fx-fore');
23
23
  }
24
24
 
25
25
  function _getModelInContext(node) {
26
- // const ownerForm = node.closest('fx-fore');
27
- const ownerForm = _getForeContext(node);
28
- return ownerForm.getModel();
26
+ // const ownerForm = node.closest('fx-fore');
27
+ const ownerForm = _getForeContext(node);
28
+ return ownerForm.getModel();
29
29
  }
30
30
 
31
31
  function _getInitialContext(node, ref) {
32
- const parentBind = Fore.getClosest('[ref]', node);
33
- const localFore = Fore.getClosest('fx-fore', node);
34
-
35
- const model = _getModelInContext(node);
36
-
37
- if (parentBind !== null) {
38
- /*
39
- make sure that the closest ref belongs to the same fx-fore element
40
- */
41
- const parentBindFore = parentBind.closest('fx-fore');
42
- if (localFore === parentBindFore) {
43
- return parentBind.nodeset;
32
+ const parentBind = Fore.getClosest('[ref]', node);
33
+ const localFore = Fore.getClosest('fx-fore', node);
34
+
35
+ const model = _getModelInContext(node);
36
+
37
+ if (parentBind !== null) {
38
+ /*
39
+ make sure that the closest ref belongs to the same fx-fore element
40
+ */
41
+ const parentBindFore = parentBind.closest('fx-fore');
42
+ if (localFore === parentBindFore) {
43
+ return parentBind.nodeset;
44
+ }
45
+ return model.getDefaultInstance().getDefaultContext();
44
46
  }
45
- return model.getDefaultInstance().getDefaultContext();
46
- }
47
47
 
48
- if (XPathUtil.isAbsolutePath(ref)) {
49
- const instanceId = XPathUtil.getInstanceId(ref);
50
- if (instanceId) {
51
- return model.getInstance(instanceId).getDefaultContext();
48
+ if (XPathUtil.isAbsolutePath(ref)) {
49
+ const instanceId = XPathUtil.getInstanceId(ref);
50
+ if (instanceId) {
51
+ return model.getInstance(instanceId).getDefaultContext();
52
+ }
53
+ return model.getDefaultInstance().getDefaultContext();
54
+ }
55
+ if (model.getDefaultInstance() !== null && model.inited) {
56
+ return model.getDefaultInstance().getDefaultContext();
52
57
  }
53
- return model.getDefaultInstance().getDefaultContext();
54
- }
55
- if (model.getDefaultInstance() !== null && model.inited) {
56
- return model.getDefaultInstance().getDefaultContext();
57
- }
58
- return [];
58
+ return [];
59
59
  }
60
60
 
61
61
  export default function getInScopeContext(node, ref) {
62
- const parentElement = _getElement(node);
63
-
64
- const repeatItem = Fore.getClosest('fx-repeatitem', parentElement);
65
- if (repeatItem) {
66
- if (node.nodeName === 'context') {
67
- return evaluateXPathToFirstNode(
68
- node.nodeValue,
69
- repeatItem.nodeset,
70
- _getForeContext(parentElement),
71
- );
62
+ const parentElement = _getElement(node);
63
+
64
+ if(parentElement.nodeName === 'FX-FORE'){
65
+ return parentElement.getModel().getDefaultInstance().getDefaultContext();
72
66
  }
73
- return repeatItem.nodeset;
74
- }
75
-
76
- if (parentElement.hasAttribute('context')) {
77
- const initialContext = _getInitialContext(parentElement.parentNode, ref);
78
- const contextAttr = parentElement.getAttribute('context');
79
- return evaluateXPathToFirstNode(contextAttr, initialContext, _getForeContext(parentElement));
80
- }
81
-
82
- if (node.nodeType === Node.ATTRIBUTE_NODE && node.nodeName === 'context') {
83
- const initialContext = _getInitialContext(node.ownerElement.parentNode, ref);
84
- const contextAttr = node.ownerElement.getAttribute('context');
85
- return evaluateXPathToFirstNode(contextAttr, initialContext, _getForeContext(parentElement));
86
- }
87
- if (node.nodeType === Node.ATTRIBUTE_NODE && node.nodeName === 'ref') {
88
- // Note: do not consider the ref of the owner element since it should not be used to define the
89
- // context
90
- if (node.ownerElement.hasAttribute('context')) {
91
- const initialContext = _getInitialContext(node.ownerElement.parentNode, ref);
92
- const contextAttr = node.ownerElement.getAttribute('context');
93
- return evaluateXPathToFirstNode(contextAttr, initialContext, _getForeContext(parentElement));
67
+ const parentBind = Fore.getClosest('[ref]', parentElement.parentNode);
68
+ if (parentBind && parentBind.nodeName === 'FX-GROUP') {
69
+ return parentBind.nodeset;
94
70
  }
95
71
 
96
- // Never resolve the context from a ref itself!
97
- return _getInitialContext(parentElement.parentNode, ref);
98
- }
72
+ const repeatItem = Fore.getClosest('fx-repeatitem', parentElement);
73
+ if (repeatItem) {
74
+ if (node.nodeName === 'context') {
75
+ return evaluateXPathToFirstNode(
76
+ node.nodeValue,
77
+ repeatItem.nodeset,
78
+ _getForeContext(parentElement),
79
+ );
80
+ }
81
+ return repeatItem.nodeset;
82
+ }
83
+
84
+ if (parentElement.hasAttribute('context')) {
85
+ const initialContext = _getInitialContext(parentElement.parentNode, ref);
86
+ const contextAttr = parentElement.getAttribute('context');
87
+ return evaluateXPathToFirstNode(contextAttr, initialContext, _getForeContext(parentElement));
88
+ }
89
+
90
+ if (node.nodeType === Node.ATTRIBUTE_NODE && node.nodeName === 'context') {
91
+ const initialContext = _getInitialContext(node.ownerElement.parentNode, ref);
92
+ const contextAttr = node.ownerElement.getAttribute('context');
93
+ return evaluateXPathToFirstNode(contextAttr, initialContext, _getForeContext(parentElement));
94
+ }
95
+ if (node.nodeType === Node.ATTRIBUTE_NODE && node.nodeName === 'ref') {
96
+ // Note: do not consider the ref of the owner element since it should not be used to define the
97
+ // context
98
+ if (node.ownerElement.hasAttribute('context')) {
99
+ const initialContext = _getInitialContext(node.ownerElement.parentNode, ref);
100
+ const contextAttr = node.ownerElement.getAttribute('context');
101
+ return evaluateXPathToFirstNode(contextAttr, initialContext, _getForeContext(parentElement));
102
+ }
103
+
104
+ // Never resolve the context from a ref itself!
105
+ return _getInitialContext(parentElement.parentNode, ref);
106
+ }
99
107
 
100
- // if (node.nodeType === Node.ELEMENT_NODE && node.hasAttribute('context')) {
101
- // const initialContext = _getInitialContext(node.parentNode, ref);
102
- // const contextAttr = node.getAttribute('context');
103
- // return evaluateXPathToFirstNode(contextAttr, initialContext, _getForeContext(parentElement));
104
- // }
105
- return _getInitialContext(parentElement, ref);
108
+ // if (node.nodeType === Node.ELEMENT_NODE && node.hasAttribute('context')) {
109
+ // const initialContext = _getInitialContext(node.parentNode, ref);
110
+ // const contextAttr = node.getAttribute('context');
111
+ // return evaluateXPathToFirstNode(contextAttr, initialContext, _getForeContext(parentElement));
112
+ // }
113
+ return _getInitialContext(parentElement, ref);
106
114
  }
package/src/modelitem.js CHANGED
@@ -50,8 +50,8 @@ export class ModelItem {
50
50
  }
51
51
 
52
52
  set value(newVal) {
53
- console.log('modelitem.setvalue oldVal', this.value);
54
- console.log('modelitem.setvalue newVal', newVal);
53
+ // console.log('modelitem.setvalue oldVal', this.value);
54
+ // console.log('modelitem.setvalue newVal', newVal);
55
55
 
56
56
  if (newVal.nodeType === Node.DOCUMENT_NODE) {
57
57
  this.node.replaceWith(newVal.firstElementChild);
package/src/relevance.js CHANGED
@@ -1,6 +1,6 @@
1
1
  export class Relevance {
2
2
  static selectRelevant(element, type) {
3
- console.log('selectRelevant', type);
3
+ // console.log('selectRelevant', type);
4
4
  switch (type) {
5
5
  case 'xml':
6
6
  return Relevance._relevantXmlNodes(element);
@@ -16,9 +16,32 @@ export default class AbstractControl extends foreElementMixin(HTMLElement) {
16
16
  this.required = false;
17
17
  this.readonly = false;
18
18
  this.widget = null;
19
+ this.visited = false;
20
+ this.force = false;
19
21
  // this.attachShadow({ mode: 'open' });
20
22
  }
21
23
 
24
+
25
+ // todo: discuss - this is a hack to circumvent that modelItems in toRefresh diverge from the modelItems in
26
+ // the model in some situations. This code first looks for refresh
27
+ /*
28
+ getModelItem() {
29
+ console.log('toRefreshModelItems', this.getOwnerForm().toRefresh);
30
+ const s = this.modelItem.path;
31
+ console.log('toRefreshModelItems path', s);
32
+
33
+ const toRefresh = this.getOwnerForm().toRefresh;
34
+ let mi;
35
+ if(toRefresh){
36
+ mi = this.getOwnerForm().toRefresh.find(m => m.path === s);
37
+ }
38
+
39
+ return mi? mi: super.getModelItem();
40
+ // console.log('toRefreshModelItems realitem', mi);
41
+
42
+ }
43
+ */
44
+
22
45
  // eslint-disable-next-line class-methods-use-this
23
46
  getWidget() {
24
47
  throw new Error('You have to implement the method getWidget!');
@@ -27,7 +50,8 @@ export default class AbstractControl extends foreElementMixin(HTMLElement) {
27
50
  /**
28
51
  * (re)apply all modelItem state properties to this control. model -> UI
29
52
  */
30
- async refresh() {
53
+ async refresh(force) {
54
+ if(force) this.force=true;
31
55
  // console.log('### AbstractControl.refresh on : ', this);
32
56
 
33
57
  const currentVal = this.value;
@@ -40,6 +64,7 @@ export default class AbstractControl extends foreElementMixin(HTMLElement) {
40
64
  this.oldVal = this.nodeset ? this.nodeset : null;
41
65
  this.evalInContext();
42
66
 
67
+ // todo this if should be removed - see above
43
68
  if (this.isBound()) {
44
69
  // this.control = this.querySelector('#control');
45
70
 
@@ -49,6 +74,7 @@ export default class AbstractControl extends foreElementMixin(HTMLElement) {
49
74
  }
50
75
 
51
76
  this.modelItem = this.getModelItem();
77
+ // console.log('refresh modelItem', this.modelItem);
52
78
 
53
79
  if (this.modelItem instanceof ModelItem) {
54
80
  // console.log('### XfAbstractControl.refresh modelItem : ', this.modelItem);
@@ -94,13 +120,19 @@ export default class AbstractControl extends foreElementMixin(HTMLElement) {
94
120
 
95
121
  // if(!this.closest('fx-fore').ready) return; // state change event do not fire during init phase (initial refresh)
96
122
  if (!this.getOwnerForm().ready) return; // state change event do not fire during init phase (initial refresh)
97
- if (currentVal !== this.value) {
98
- Fore.dispatch(this, 'value-changed', { path: this.modelItem.path });
123
+ if (currentVal !== this.value ) {
124
+ // todo: discuss how to prevent unnecessary/unwanted value-changes e.g. when repeatitems are inserted
125
+ // if (currentVal !== this.value && this.visited) {
126
+ Fore.dispatch(this, 'value-changed', { path: this.modelItem.path , value:this.modelItem.value});
99
127
  }
100
128
  }
101
129
  }
102
130
  }
103
131
 
132
+ refreshFromModelItem(modelItem){
133
+
134
+ }
135
+
104
136
  /**
105
137
  *
106
138
  * @returns {Promise<void>}
@@ -135,24 +167,71 @@ export default class AbstractControl extends foreElementMixin(HTMLElement) {
135
167
  handleRequired() {
136
168
  // console.log('mip required', this.modelItem.required);
137
169
  this.widget = this.getWidget();
138
- // if (this.required !== this.modelItem.required) {
170
+
171
+ if(!this.modelItem.required){
172
+ this.widget.removeAttribute('required');
173
+ this.removeAttribute('required');
174
+ if (this.isRequired() !== this.modelItem.required){
175
+ this._dispatchEvent('optional');
176
+ }
177
+ return;
178
+ }
179
+
180
+ // ### modelItem is required
181
+ if (this.visited || this.force) {
182
+ if (this.modelItem.value === '') {
183
+ this.classList.add('isEmpty');
184
+ this._toggleValid(false);
185
+ } else {
186
+ this.classList.remove('isEmpty');
187
+ this._toggleValid(true);
188
+ }
189
+ }
190
+ this.widget.setAttribute('required', '');
191
+ this.setAttribute('required', '');
139
192
  if (this.isRequired() !== this.modelItem.required) {
140
- if (this.modelItem.required) {
141
- if (this.getOwnerForm().ready){
142
- if(this.widget.value === ''){
143
- this.classList.add('isRequiredFalse');
144
- }else{
145
- this.classList.remove('isRequiredFalse');
146
- }
193
+ this._dispatchEvent('required');
194
+ }
195
+
196
+ /*
197
+ if (this.isRequired() !== this.modelItem.required) {
198
+ this._updateRequired();
199
+ }
200
+ */
201
+ }
202
+
203
+
204
+ _updateRequired() {
205
+ if (this.modelItem.required) {
206
+ // if (this.getOwnerForm().ready){
207
+ if (this.visited || this.force) {
208
+ // if (this.visited ) {
209
+ // if (this.widget.value === '') {
210
+ if (this.modelItem.value === '') {
211
+ this.classList.add('isEmpty');
212
+ this._toggleValid(false);
213
+ } else {
214
+ this.classList.remove('isEmpty');
215
+ this._toggleValid(true);
147
216
  }
148
- this.widget.setAttribute('required', '');
149
- this.setAttribute('required', '');
150
- this._dispatchEvent('required');
151
- } else {
152
- this.widget.removeAttribute('required');
153
- this.removeAttribute('required');
154
- this._dispatchEvent('optional');
155
217
  }
218
+ this.widget.setAttribute('required', '');
219
+ this.setAttribute('required', '');
220
+ this._dispatchEvent('required');
221
+ } else {
222
+ this.widget.removeAttribute('required');
223
+ this.removeAttribute('required');
224
+ this._dispatchEvent('optional');
225
+ }
226
+ }
227
+
228
+ _toggleValid(valid){
229
+ if(valid){
230
+ this.removeAttribute('invalid');
231
+ this.setAttribute('valid','');
232
+ }else{
233
+ this.removeAttribute('valid');
234
+ this.setAttribute('invalid','');
156
235
  }
157
236
  }
158
237
 
@@ -177,28 +256,35 @@ export default class AbstractControl extends foreElementMixin(HTMLElement) {
177
256
  // console.log('mip valid', this.modelItem.required);
178
257
  const alert = this.querySelector('fx-alert');
179
258
 
259
+ const mi = this.getModelItem();
260
+ console.log('late modelItem', mi);
180
261
  if (this.isValid() !== this.modelItem.constraint) {
181
262
  if (this.modelItem.constraint) {
182
- if (alert) alert.style.display = 'none';
263
+ // if (alert) alert.style.display = 'none';
183
264
  this._dispatchEvent('valid');
265
+ this.setAttribute('valid','');
184
266
  this.removeAttribute('invalid');
185
267
  } else {
186
268
  this.setAttribute('invalid', '');
269
+ this.removeAttribute('valid');
187
270
  // ### constraint is invalid - handle alerts
271
+ /*
188
272
  if (alert) {
189
273
  alert.style.display = 'block';
190
274
  }
275
+ */
191
276
  if (this.modelItem.alerts.length !== 0) {
192
- const { alerts } = this.modelItem;
193
- // console.log('alerts from bind: ', alerts);
194
277
 
195
278
  const controlAlert = this.querySelector('fx-alert');
196
279
  if (!controlAlert) {
280
+ const { alerts } = this.modelItem;
281
+ // console.log('alerts from bind: ', alerts);
197
282
  alerts.forEach(modelAlert => {
198
283
  const newAlert = document.createElement('fx-alert');
284
+ // const newAlert = document.createElement('span');
199
285
  newAlert.innerHTML = modelAlert;
200
286
  this.appendChild(newAlert);
201
- newAlert.style.display = 'block';
287
+ // newAlert.style.display = 'block';
202
288
  });
203
289
  }
204
290
  }
@@ -13,7 +13,6 @@ export class FxAlert extends AbstractControl {
13
13
  font-size: 0.8em;
14
14
  font-weight: 400;
15
15
  color: red;
16
- display: none;
17
16
  }
18
17
  `;
19
18