@jinntec/fore 2.1.1 → 2.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 (88) hide show
  1. package/README.md +2 -2
  2. package/dist/fore-dev.js +2 -2
  3. package/dist/fore-dev.js.map +1 -1
  4. package/dist/fore.js +2 -2
  5. package/dist/fore.js.map +1 -1
  6. package/index.js +4 -2
  7. package/package.json +10 -38
  8. package/resources/fore.css +263 -262
  9. package/resources/vars.css +8 -0
  10. package/src/DependencyNotifyingDomFacade.js +1 -0
  11. package/src/ForeElementMixin.js +243 -228
  12. package/src/actions/abstract-action.js +407 -398
  13. package/src/actions/fx-action.js +6 -6
  14. package/src/actions/fx-append.js +1 -1
  15. package/src/actions/fx-call.js +63 -62
  16. package/src/actions/fx-confirm.js +11 -11
  17. package/src/actions/fx-construct-done.js +4 -4
  18. package/src/actions/fx-copy.js +36 -36
  19. package/src/actions/fx-delete.js +77 -79
  20. package/src/actions/fx-dispatch.js +14 -14
  21. package/src/actions/fx-hide.js +15 -15
  22. package/src/actions/fx-insert.js +9 -12
  23. package/src/actions/fx-insertchild.js +88 -0
  24. package/src/actions/fx-load.js +188 -185
  25. package/src/actions/fx-message.js +18 -19
  26. package/src/actions/fx-refresh.js +10 -10
  27. package/src/actions/fx-reload.js +16 -14
  28. package/src/actions/fx-replace.js +0 -1
  29. package/src/actions/fx-reset.js +31 -31
  30. package/src/actions/fx-send.js +59 -52
  31. package/src/actions/fx-setattribute.js +48 -49
  32. package/src/actions/fx-setfocus.js +54 -58
  33. package/src/actions/fx-setvalue.js +85 -81
  34. package/src/actions/fx-show.js +11 -11
  35. package/src/actions/fx-toggle.js +2 -2
  36. package/src/actions/fx-toggleboolean.js +38 -39
  37. package/src/actions/fx-unmodified.js +27 -0
  38. package/src/actions/fx-update.js +6 -6
  39. package/src/dep_graph.js +1 -1
  40. package/src/drawdown.js +23 -30
  41. package/src/events.js +19 -19
  42. package/src/fore.js +143 -125
  43. package/src/functions/common-function.js +24 -25
  44. package/src/functions/fx-function.js +6 -99
  45. package/src/functions/fx-functionlib.js +56 -0
  46. package/src/functions/registerFunction.js +112 -0
  47. package/src/fx-bind.js +19 -24
  48. package/src/fx-connection.js +226 -0
  49. package/src/fx-fore.js +844 -815
  50. package/src/fx-header.js +4 -4
  51. package/src/fx-instance.js +25 -29
  52. package/src/fx-model.js +405 -380
  53. package/src/fx-submission.js +399 -397
  54. package/src/fx-var.js +13 -12
  55. package/src/getInScopeContext.js +102 -89
  56. package/src/json-util.js +24 -24
  57. package/src/lab/fore-component.js +48 -52
  58. package/src/lab/instance-inspector.js +13 -16
  59. package/src/modelitem.js +48 -10
  60. package/src/relevance.js +12 -16
  61. package/src/tools/adi.js +858 -812
  62. package/src/tools/fx-action-log.js +377 -295
  63. package/src/tools/fx-devtools.js +210 -210
  64. package/src/tools/fx-dom-inspector.js +123 -122
  65. package/src/tools/fx-json-instance.js +262 -253
  66. package/src/tools/fx-log-item.js +6 -11
  67. package/src/tools/fx-log-settings.js +358 -301
  68. package/src/tools/fx-minimap.js +186 -177
  69. package/src/tools/helpers.js +1 -1
  70. package/src/ui/abstract-control.js +73 -53
  71. package/src/ui/fx-case.js +59 -7
  72. package/src/ui/fx-container.js +13 -14
  73. package/src/ui/fx-control.js +572 -538
  74. package/src/ui/fx-dialog.js +3 -3
  75. package/src/ui/fx-droptarget.js +3 -4
  76. package/src/ui/fx-group.js +4 -2
  77. package/src/ui/fx-hint.js +3 -0
  78. package/src/ui/fx-inspector.js +5 -5
  79. package/src/ui/fx-items.js +11 -11
  80. package/src/ui/fx-output.js +10 -12
  81. package/src/ui/fx-repeat-attributes.js +23 -27
  82. package/src/ui/fx-repeat.js +347 -344
  83. package/src/ui/fx-repeatitem.js +75 -68
  84. package/src/ui/fx-switch.js +39 -14
  85. package/src/ui/fx-trigger.js +4 -4
  86. package/src/withDraggability.js +193 -191
  87. package/src/xpath-evaluation.js +969 -958
  88. package/src/xpath-util.js +161 -134
@@ -1,194 +1,203 @@
1
1
  class FxMinimap extends HTMLElement {
2
- constructor() {
3
- super();
4
- this.canvas = document.createElement('canvas');
5
- this.options = this.getAttribute('options') ? JSON.parse(this.getAttribute('options')) : {};
6
- this.attachShadow({mode: 'open'});
7
- this.shadowRoot.appendChild(this.canvas);
8
- this.WIN = window;
9
- this.DOC = this.WIN.document;
10
- this.DOC_EL = this.DOC.documentElement;
11
- this.BODY = this.DOC.querySelector('body');
12
-
13
- }
14
-
15
- connectedCallback() {
16
- this.ctx = this.canvas.getContext('2d');
17
- this.black = pc => `rgba(0,0,0,${pc / 100})`;
18
- this.viewport = this.querySelector(this.getAttribute('selector'));
19
- this.settings = Object.assign(
20
- {
21
- viewport: this.viewport,
22
- styles: {
23
- 'header,footer,section,article': this.black(8),
24
- 'h1,a': this.black(10),
25
- 'h2,h3,h4': this.black(8),
26
- },
27
- back: this.black(2),
28
- view: this.black(5),
29
- drag: this.black(10),
30
- interval: null,
31
- },
32
- this.options
33
- );
34
-
35
- const _listener = (el, method, types, fn) => types.split(/\s+/).forEach(type => el[method](type, fn));
36
- this.on = (el, types, fn) => _listener(el, 'addEventListener', types, fn);
37
- this.off = (el, types, fn) => _listener(el, 'removeEventListener', types, fn);
38
-
39
- this.Rect = (x, y, w, h) => {
40
- return {x, y, w, h};
41
- };
42
-
43
- this.rect_rel_to = (rect, pos = {x: 0, y: 0}) => {
44
- return this.Rect(rect.x - pos.x, rect.y - pos.y, rect.w, rect.h);
45
- };
46
-
47
- this.rect_of_doc = () => {
48
- return this.Rect(0, 0, document.documentElement.scrollWidth, document.documentElement.scrollHeight);
49
- };
50
-
51
- this.rect_of_win = () => {
52
- return this.Rect(window.pageXOffset, window.pageYOffset, document.documentElement.clientWidth, document.documentElement.clientHeight);
53
- };
54
-
55
- this.el_get_offset = el => {
56
- const br = el.getBoundingClientRect();
57
- return {x: br.left + window.pageXOffset, y: br.top + window.pageYOffset};
58
- };
59
-
60
- this.rect_of_el = el => {
61
- const {x, y} = this.el_get_offset(el);
62
- return this.Rect(x, y, el.offsetWidth, el.offsetHeight);
63
- };
64
-
65
- this.rect_of_viewport = el => {
66
- const {x, y} = this.el_get_offset(el);
67
- return this.Rect(x + el.clientLeft, y + el.clientTop, el.clientWidth, el.clientHeight);
68
- };
69
-
70
- this.rect_of_content = el => {
71
- const {x, y} = this.el_get_offset(el);
72
- return this.Rect(x + el.clientLeft - el.scrollLeft, y + el.clientTop - el.scrollTop, el.scrollWidth, el.scrollHeight);
73
- };
74
-
75
- this.calc_scale = (() => {
76
- const width = this.canvas.clientWidth;
77
- const height = this.canvas.clientHeight;
78
- return (w, h) => Math.min(width / w, height / h);
79
- })();
80
-
81
- this.resize_canvas = (w, h) => {
82
- this.canvas.width = w;
83
- this.canvas.height = h;
84
- this.canvas.style.width = `${w}px`;
85
- this.canvas.style.height = `${h}px`;
86
- };
87
-
88
- this.viewport = this.settings.viewport;
89
- this.find = sel => Array.from((this.viewport || document).querySelectorAll(sel));
90
-
91
- this.drag = false;
92
- this.root_rect = null;
93
- this.view_rect = null;
94
- this.scale = null;
95
- this.drag_rx = null
96
- this. drag_ry = null;
97
- }
98
-
99
- draw_rect(rect, col){
100
- if (col) {
101
- this.ctx.beginPath();
102
- this.ctx.rect(rect.x, rect.y, rect.w, rect.h);
103
- this.ctx.fillStyle = col;
104
- this.ctx.fill();
105
- }
2
+ constructor() {
3
+ super();
4
+ this.canvas = document.createElement('canvas');
5
+ this.options = this.getAttribute('options') ? JSON.parse(this.getAttribute('options')) : {};
6
+ this.attachShadow({ mode: 'open' });
7
+ this.shadowRoot.appendChild(this.canvas);
8
+ this.WIN = window;
9
+ this.DOC = this.WIN.document;
10
+ this.DOC_EL = this.DOC.documentElement;
11
+ this.BODY = this.DOC.querySelector('body');
12
+ }
13
+
14
+ connectedCallback() {
15
+ this.ctx = this.canvas.getContext('2d');
16
+ this.black = pc => `rgba(0,0,0,${pc / 100})`;
17
+ this.viewport = this.querySelector(this.getAttribute('selector'));
18
+ this.settings = {
19
+ viewport: this.viewport,
20
+ styles: {
21
+ 'header,footer,section,article': this.black(8),
22
+ 'h1,a': this.black(10),
23
+ 'h2,h3,h4': this.black(8),
24
+ },
25
+ back: this.black(2),
26
+ view: this.black(5),
27
+ drag: this.black(10),
28
+ interval: null,
29
+ ...this.options,
106
30
  };
107
31
 
108
- find(sel) {
109
- return Array.from((this.viewport || this.DOC).querySelectorAll(sel));
110
- }
111
-
112
- apply_styles(styles) {
113
- Object.keys(styles).forEach(sel => {
114
- const col = styles[sel];
115
- this.find(sel).forEach(el => {
116
- this.draw_rect(this.rect_rel_to(this.rect_of_el(el), this.root_rect), col);
117
- });
118
- });
32
+ const _listener = (el, method, types, fn) =>
33
+ types.split(/\s+/).forEach(type => el[method](type, fn));
34
+ this.on = (el, types, fn) => _listener(el, 'addEventListener', types, fn);
35
+ this.off = (el, types, fn) => _listener(el, 'removeEventListener', types, fn);
36
+
37
+ this.Rect = (x, y, w, h) => ({
38
+ x,
39
+ y,
40
+ w,
41
+ h,
42
+ });
43
+
44
+ this.rect_rel_to = (rect, pos = { x: 0, y: 0 }) =>
45
+ this.Rect(rect.x - pos.x, rect.y - pos.y, rect.w, rect.h);
46
+
47
+ this.rect_of_doc = () =>
48
+ this.Rect(0, 0, document.documentElement.scrollWidth, document.documentElement.scrollHeight);
49
+
50
+ this.rect_of_win = () =>
51
+ this.Rect(
52
+ window.pageXOffset,
53
+ window.pageYOffset,
54
+ document.documentElement.clientWidth,
55
+ document.documentElement.clientHeight,
56
+ );
57
+
58
+ this.el_get_offset = el => {
59
+ const br = el.getBoundingClientRect();
60
+ return { x: br.left + window.pageXOffset, y: br.top + window.pageYOffset };
119
61
  };
120
62
 
121
-
122
- draw () {
123
- this.root_rect = this.viewport ? this.rect_of_content(this.viewport) : this.rect_of_doc();
124
- this.view_rect = this.viewport ? this.rect_of_viewport(this.viewport) : this.rect_of_win();
125
- this.scale = this.calc_scale(this.root_rect.w, this.root_rect.h);
126
-
127
- this.resize_canvas(this.root_rect.w * this.scale, this.root_rect.h * this.scale);
128
-
129
- this.ctx.setTransform(1, 0, 0, 1, 0, 0);
130
- this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
131
- this.ctx.scale(this.scale, this.scale);
132
-
133
- this.draw_rect(this.rect_rel_to(this.root_rect, this.root_rect), this.settings.back);
134
- this.apply_styles(this.settings.styles);
135
- this.draw_rect(this.rect_rel_to(this.view_rect, this.root_rect), this.drag ? this.settings.drag : this.settings.view);
63
+ this.rect_of_el = el => {
64
+ const { x, y } = this.el_get_offset(el);
65
+ return this.Rect(x, y, el.offsetWidth, el.offsetHeight);
136
66
  };
137
67
 
138
- on_drag(ev) {
139
- ev.preventDefault();
140
- const cr = this.rect_of_viewport(this.canvas);
141
- const x = (ev.pageX - cr.x) / this.scale - this.view_rect.w * this.drag_rx;
142
- const y = (ev.pageY - cr.y) / this.scale - this.view_rect.h * this.drag_ry;
143
-
144
- if (this.viewport) {
145
- this.viewport.scrollLeft = x;
146
- this.viewport.scrollTop = y;
147
- } else {
148
- this.WIN.scrollTo(x, y);
149
- }
150
- this.draw();
68
+ this.rect_of_viewport = el => {
69
+ const { x, y } = this.el_get_offset(el);
70
+ return this.Rect(x + el.clientLeft, y + el.clientTop, el.clientWidth, el.clientHeight);
151
71
  };
152
72
 
153
- on_drag_end (ev) {
154
- this.drag = false;
155
- this.canvas.style.cursor = 'pointer';
156
- this.BODY.style.cursor = 'auto';
157
- this.off(this.WIN, 'mousemove', this.on_drag);
158
- this.off(this.WIN, 'mouseup', this.on_drag_end);
159
- this.on_drag(ev);
73
+ this.rect_of_content = el => {
74
+ const { x, y } = this.el_get_offset(el);
75
+ return this.Rect(
76
+ x + el.clientLeft - el.scrollLeft,
77
+ y + el.clientTop - el.scrollTop,
78
+ el.scrollWidth,
79
+ el.scrollHeight,
80
+ );
160
81
  };
161
82
 
162
- on_drag_start (ev) {
163
- this.drag = true;
164
-
165
- const cr = this.rect_of_viewport(this.canvas);
166
- const vr = this.rect_rel_to(this.view_rect, this.root_rect);
167
- this.drag_rx = ((ev.pageX - cr.x) / this.scale - vr.x) / vr.w;
168
- this.drag_ry = ((ev.pageY - cr.y) / this.scale - vr.y) / vr.h;
169
- if (this.drag_rx < 0 || this.drag_rx > 1 || this.drag_ry < 0 || this.drag_ry > 1) {
170
- this.drag_rx = 0.5;
171
- this.drag_ry = 0.5;
172
- }
173
-
174
- this.canvas.style.cursor = 'crosshair';
175
- this.BODY.style.cursor = 'crosshair';
176
- this.on(this.WIN, 'mousemove', this.on_drag);
177
- this.on(this.WIN, 'mouseup', this.on_drag_end);
178
- this.on_drag(ev);
83
+ this.calc_scale = (() => {
84
+ const width = this.canvas.clientWidth;
85
+ const height = this.canvas.clientHeight;
86
+ return (w, h) => Math.min(width / w, height / h);
87
+ })();
88
+
89
+ this.resize_canvas = (w, h) => {
90
+ this.canvas.width = w;
91
+ this.canvas.height = h;
92
+ this.canvas.style.width = `${w}px`;
93
+ this.canvas.style.height = `${h}px`;
179
94
  };
180
95
 
181
- init () {
182
- this.canvas.style.cursor = 'pointer';
183
- this.on(this.canvas, 'mousedown', this.on_drag_start);
184
- this.on(this.viewport || this.WIN, 'load resize scroll', this.draw());
185
- if (this.settings.interval > 0) {
186
- setInterval(() => this.draw(), this.settings.interval);
187
- }
188
- this.draw();
189
- };
96
+ this.viewport = this.settings.viewport;
97
+ this.find = sel => Array.from((this.viewport || document).querySelectorAll(sel));
98
+
99
+ this.drag = false;
100
+ this.root_rect = null;
101
+ this.view_rect = null;
102
+ this.scale = null;
103
+ this.drag_rx = null;
104
+ this.drag_ry = null;
105
+ }
106
+
107
+ draw_rect(rect, col) {
108
+ if (col) {
109
+ this.ctx.beginPath();
110
+ this.ctx.rect(rect.x, rect.y, rect.w, rect.h);
111
+ this.ctx.fillStyle = col;
112
+ this.ctx.fill();
113
+ }
114
+ }
115
+
116
+ find(sel) {
117
+ return Array.from((this.viewport || this.DOC).querySelectorAll(sel));
118
+ }
119
+
120
+ apply_styles(styles) {
121
+ Object.keys(styles).forEach(sel => {
122
+ const col = styles[sel];
123
+ this.find(sel).forEach(el => {
124
+ this.draw_rect(this.rect_rel_to(this.rect_of_el(el), this.root_rect), col);
125
+ });
126
+ });
127
+ }
128
+
129
+ draw() {
130
+ this.root_rect = this.viewport ? this.rect_of_content(this.viewport) : this.rect_of_doc();
131
+ this.view_rect = this.viewport ? this.rect_of_viewport(this.viewport) : this.rect_of_win();
132
+ this.scale = this.calc_scale(this.root_rect.w, this.root_rect.h);
133
+
134
+ this.resize_canvas(this.root_rect.w * this.scale, this.root_rect.h * this.scale);
135
+
136
+ this.ctx.setTransform(1, 0, 0, 1, 0, 0);
137
+ this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
138
+ this.ctx.scale(this.scale, this.scale);
139
+
140
+ this.draw_rect(this.rect_rel_to(this.root_rect, this.root_rect), this.settings.back);
141
+ this.apply_styles(this.settings.styles);
142
+ this.draw_rect(
143
+ this.rect_rel_to(this.view_rect, this.root_rect),
144
+ this.drag ? this.settings.drag : this.settings.view,
145
+ );
146
+ }
147
+
148
+ on_drag(ev) {
149
+ ev.preventDefault();
150
+ const cr = this.rect_of_viewport(this.canvas);
151
+ const x = (ev.pageX - cr.x) / this.scale - this.view_rect.w * this.drag_rx;
152
+ const y = (ev.pageY - cr.y) / this.scale - this.view_rect.h * this.drag_ry;
153
+
154
+ if (this.viewport) {
155
+ this.viewport.scrollLeft = x;
156
+ this.viewport.scrollTop = y;
157
+ } else {
158
+ this.WIN.scrollTo(x, y);
159
+ }
160
+ this.draw();
161
+ }
162
+
163
+ on_drag_end(ev) {
164
+ this.drag = false;
165
+ this.canvas.style.cursor = 'pointer';
166
+ this.BODY.style.cursor = 'auto';
167
+ this.off(this.WIN, 'mousemove', this.on_drag);
168
+ this.off(this.WIN, 'mouseup', this.on_drag_end);
169
+ this.on_drag(ev);
170
+ }
171
+
172
+ on_drag_start(ev) {
173
+ this.drag = true;
174
+
175
+ const cr = this.rect_of_viewport(this.canvas);
176
+ const vr = this.rect_rel_to(this.view_rect, this.root_rect);
177
+ this.drag_rx = ((ev.pageX - cr.x) / this.scale - vr.x) / vr.w;
178
+ this.drag_ry = ((ev.pageY - cr.y) / this.scale - vr.y) / vr.h;
179
+ if (this.drag_rx < 0 || this.drag_rx > 1 || this.drag_ry < 0 || this.drag_ry > 1) {
180
+ this.drag_rx = 0.5;
181
+ this.drag_ry = 0.5;
182
+ }
190
183
 
184
+ this.canvas.style.cursor = 'crosshair';
185
+ this.BODY.style.cursor = 'crosshair';
186
+ this.on(this.WIN, 'mousemove', this.on_drag);
187
+ this.on(this.WIN, 'mouseup', this.on_drag_end);
188
+ this.on_drag(ev);
189
+ }
190
+
191
+ init() {
192
+ this.canvas.style.cursor = 'pointer';
193
+ this.on(this.canvas, 'mousedown', this.on_drag_start);
194
+ this.on(this.viewport || this.WIN, 'load resize scroll', this.draw());
195
+ if (this.settings.interval > 0) {
196
+ setInterval(() => this.draw(), this.settings.interval);
197
+ }
198
+ this.draw();
199
+ }
191
200
  }
192
201
  if (!customElements.get('fx-minimap')) {
193
- customElements.define('fx-minimap', FxMinimap);
202
+ customElements.define('fx-minimap', FxMinimap);
194
203
  }
@@ -66,7 +66,7 @@ export function newElement(elem, attrs) {
66
66
  return el;
67
67
  }
68
68
 
69
- // Helper function for options view
69
+ // Helper function for options view
70
70
  export function drawOptionRow(optionCode, optionText) {
71
71
  const row = newElement('span', { class: 'adi-opt' });
72
72
  row.innerHTML = `<label><input type="checkbox" data-opt="${optionCode}">${optionText}</label>`;
@@ -1,18 +1,32 @@
1
1
  import '../fx-model.js';
2
- import { foreElementMixin } from '../ForeElementMixin.js';
2
+ import ForeElementMixin from '../ForeElementMixin.js';
3
3
  import { ModelItem } from '../modelitem.js';
4
4
  import { Fore } from '../fore.js';
5
- import { XPathUtil } from '../xpath-util.js';
6
5
  import getInScopeContext from '../getInScopeContext.js';
7
- import { evaluateXPathToFirstNode} from '../xpath-evaluation.js';
8
- import {Relevance} from "../relevance.js";
6
+ import { evaluateXPathToFirstNode } from '../xpath-evaluation.js';
7
+
8
+ function isDifferent(oldNodeValue, oldControlValue, newControlValue) {
9
+ if (oldNodeValue === null) {
10
+ return false;
11
+ }
12
+
13
+ if (newControlValue && oldControlValue && newControlValue.nodeType && oldControlValue.nodeType) {
14
+ return newControlValue.outerHTML !== oldControlValue.outerHTML;
15
+ }
16
+
17
+ if (oldControlValue === newControlValue) {
18
+ return false;
19
+ }
20
+
21
+ return true;
22
+ }
9
23
 
10
24
  /**
11
25
  * `AbstractControl` -
12
26
  * is a general base class for control elements.
13
27
  *
14
28
  */
15
- export default class AbstractControl extends foreElementMixin(HTMLElement) {
29
+ export default class AbstractControl extends ForeElementMixin {
16
30
  constructor() {
17
31
  super();
18
32
  this.value = null;
@@ -34,10 +48,11 @@ export default class AbstractControl extends foreElementMixin(HTMLElement) {
34
48
  * (re)apply all modelItem state properties to this control. model -> UI
35
49
  */
36
50
  async refresh(force) {
37
- if(force) this.force=true;
51
+ if (force) this.force = true;
38
52
  // console.log('### AbstractControl.refresh on : ', this);
39
53
 
40
- const currentVal = this.value;
54
+ // Save the old value of this control. this may be the stringified version, contrast to the node in `nodeset`
55
+ const oldValue = this.value;
41
56
 
42
57
  // if(this.repeated) return
43
58
  if (this.isNotBound()) return;
@@ -53,42 +68,45 @@ export default class AbstractControl extends foreElementMixin(HTMLElement) {
53
68
  if (this.isBound()) {
54
69
  // this.control = this.querySelector('#control');
55
70
 
56
- if(!this.nodeset){
57
-
71
+ if (!this.nodeset) {
58
72
  const create = this.closest('[create]');
59
- if(create){
73
+ if (create) {
60
74
  // ### check if parent element exists
61
- let attrName; let parentPath; let parentNode;
75
+ let attrName;
76
+ let parentPath;
77
+ let parentNode;
62
78
 
63
- if(this.ref.includes('/')){
79
+ if (this.ref.includes('/')) {
64
80
  parentPath = this.ref.substring(0, this.ref.indexOf('/'));
65
81
  const inscope = getInScopeContext(this.parentNode, this.ref);
66
- parentNode = evaluateXPathToFirstNode(parentPath,inscope,this);
67
-
68
- if(parentNode && parentNode.nodeType === Node.ELEMENT_NODE){
69
- if(this.ref.includes('@')){
70
- attrName = this.ref.substring(this.ref.indexOf('/')+2);
71
- parentNode.setAttribute(attrName,'');
72
- }else{
73
- Fore.dispatch(this,'warn',{message:'"create" is not implemented for elements'})
82
+ parentNode = evaluateXPathToFirstNode(parentPath, inscope, this);
83
+
84
+ if (parentNode && parentNode.nodeType === Node.ELEMENT_NODE) {
85
+ if (this.ref.includes('@')) {
86
+ attrName = this.ref.substring(this.ref.indexOf('/') + 2);
87
+ parentNode.setAttribute(attrName, '');
88
+ } else {
89
+ Fore.dispatch(this, 'warn', {
90
+ message: '"create" is not implemented for elements',
91
+ });
74
92
  }
75
93
  }
76
- }else{
94
+ } else {
77
95
  const inscope = getInScopeContext(this, this.ref);
78
96
 
79
- if(this.ref.includes('@')) {
97
+ if (this.ref.includes('@')) {
80
98
  attrName = this.ref.substring(this.ref.indexOf('@') + 1);
81
99
  inscope.setAttribute(attrName, '');
82
- }else{
83
- Fore.dispatch(this,'warn',{message:'"create" is not implemented for elements'})
100
+ } else {
101
+ Fore.dispatch(this, 'warn', { message: '"create" is not implemented for elements' });
84
102
  // inscope = getInScopeContext(this.parentNode, this.ref);
85
103
  }
86
104
  }
87
- }else{
105
+ } else {
88
106
  // ### this actually makes the control nonrelevant
89
107
  // todo: we should call a template function here to allow detachment of event-listeners and resetting eventual state
90
108
  // this.style.display = 'none';
91
- this.setAttribute('nonrelevant','');
109
+ this.setAttribute('nonrelevant', '');
92
110
  }
93
111
  return;
94
112
  }
@@ -140,21 +158,25 @@ export default class AbstractControl extends foreElementMixin(HTMLElement) {
140
158
  this.handleModelItemProperties();
141
159
 
142
160
  // if(!this.closest('fx-fore').ready) return; // state change event do not fire during init phase (initial refresh)
143
- if(this.getOwnerForm().initialRun){
144
- Fore.dispatch(this,'init',{});
161
+ if (this.getOwnerForm().initialRun) {
162
+ Fore.dispatch(this, 'init', {});
145
163
  }
146
164
  if (!this.getOwnerForm().ready) return; // state change event do not fire during init phase (initial refresh)
147
165
  // if oldVal is null we haven't received a concrete value yet
148
- if (this.oldVal !== null && currentVal !== this.value) {
149
- Fore.dispatch(this, 'value-changed', { path: this.modelItem.path , value:this.modelItem.value});
166
+
167
+ if (this.localName !== 'fx-control') return;
168
+ if (isDifferent(this.oldVal, this.value, oldValue)) {
169
+ Fore.dispatch(this, 'value-changed', {
170
+ path: this.modelItem.path,
171
+ value: this.modelItem.value,
172
+ oldvalue: this.oldVal,
173
+ });
150
174
  }
151
175
  }
152
176
  }
153
177
  }
154
178
 
155
- refreshFromModelItem(modelItem){
156
-
157
- }
179
+ refreshFromModelItem(modelItem) {}
158
180
 
159
181
  /**
160
182
  *
@@ -190,13 +212,13 @@ export default class AbstractControl extends foreElementMixin(HTMLElement) {
190
212
  // eslint-disable-next-line class-methods-use-this
191
213
  handleRequired() {
192
214
  // console.log('mip required', this.modelItem.required);
193
- this.widget = this.getWidget();
194
- const wasRequired = this.isRequired();
215
+ this.widget = this.getWidget();
216
+ const wasRequired = this.isRequired();
195
217
 
196
- if(!this.modelItem.required){
218
+ if (!this.modelItem.required) {
197
219
  this.widget.removeAttribute('required');
198
220
  this.removeAttribute('required');
199
- if (wasRequired !== this.modelItem.required){
221
+ if (wasRequired !== this.modelItem.required) {
200
222
  this._dispatchEvent('optional');
201
223
  }
202
224
  return;
@@ -218,20 +240,19 @@ export default class AbstractControl extends foreElementMixin(HTMLElement) {
218
240
  this._dispatchEvent('required');
219
241
  }
220
242
 
221
- /*
243
+ /*
222
244
  if (this.isRequired() !== this.modelItem.required) {
223
245
  this._updateRequired();
224
246
  }
225
247
  */
226
248
  }
227
249
 
228
-
229
250
  _updateRequired() {
230
251
  if (this.modelItem.required) {
231
252
  // if (this.getOwnerForm().ready){
232
253
  if (this.visited || this.force) {
233
- // if (this.visited ) {
234
- // if (this.widget.value === '') {
254
+ // if (this.visited ) {
255
+ // if (this.widget.value === '') {
235
256
  if (this.modelItem.value === '') {
236
257
  this.classList.add('isEmpty');
237
258
  this._toggleValid(false);
@@ -250,13 +271,13 @@ export default class AbstractControl extends foreElementMixin(HTMLElement) {
250
271
  }
251
272
  }
252
273
 
253
- _toggleValid(valid){
254
- if(valid){
274
+ _toggleValid(valid) {
275
+ if (valid) {
255
276
  this.removeAttribute('invalid');
256
- this.setAttribute('valid','');
257
- }else{
277
+ this.setAttribute('valid', '');
278
+ } else {
258
279
  this.removeAttribute('valid');
259
- this.setAttribute('invalid','');
280
+ this.setAttribute('invalid', '');
260
281
  }
261
282
  }
262
283
 
@@ -285,19 +306,18 @@ export default class AbstractControl extends foreElementMixin(HTMLElement) {
285
306
  if (this.modelItem.constraint) {
286
307
  // if (alert) alert.style.display = 'none';
287
308
  this._dispatchEvent('valid');
288
- this.setAttribute('valid','');
309
+ this.setAttribute('valid', '');
289
310
  this.removeAttribute('invalid');
290
311
  } else {
291
312
  this.setAttribute('invalid', '');
292
313
  this.removeAttribute('valid');
293
314
  // ### constraint is invalid - handle alerts
294
- /*
315
+ /*
295
316
  if (alert) {
296
317
  alert.style.display = 'block';
297
318
  }
298
319
  */
299
320
  if (this.modelItem.alerts.length !== 0) {
300
-
301
321
  const controlAlert = this.querySelector('fx-alert');
302
322
  if (!controlAlert) {
303
323
  const { alerts } = this.modelItem;
@@ -325,7 +345,7 @@ export default class AbstractControl extends foreElementMixin(HTMLElement) {
325
345
  this.removeAttribute('nonrelevant');
326
346
  if (Array.isArray(item) && item.length === 0) {
327
347
  this._dispatchEvent('nonrelevant');
328
- this.setAttribute('nonrelevant','');
348
+ this.setAttribute('nonrelevant', '');
329
349
  // this.style.display = 'none';
330
350
  return;
331
351
  }
@@ -333,12 +353,12 @@ export default class AbstractControl extends foreElementMixin(HTMLElement) {
333
353
  if (this.modelItem.relevant) {
334
354
  this._dispatchEvent('relevant');
335
355
  // this._fadeIn(this, this.display);
336
- this.setAttribute('relevant','');
356
+ this.setAttribute('relevant', '');
337
357
  // this.style.display = this.display;
338
358
  } else {
339
359
  this._dispatchEvent('nonrelevant');
340
360
  // this._fadeOut(this);
341
- this.setAttribute('nonrelevant','');
361
+ this.setAttribute('nonrelevant', '');
342
362
  // this.style.display = 'none';
343
363
  }
344
364
  }
@@ -349,7 +369,7 @@ export default class AbstractControl extends foreElementMixin(HTMLElement) {
349
369
  }
350
370
 
351
371
  isValid() {
352
- return this.hasAttribute('invalid') ? false : true;
372
+ return !this.hasAttribute('invalid');
353
373
  }
354
374
 
355
375
  isReadonly() {