@jinntec/fore 2.2.0 → 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.
- package/README.md +1 -1
- package/dist/fore-dev.js +2 -2
- package/dist/fore-dev.js.map +1 -1
- package/dist/fore.js +2 -2
- package/dist/fore.js.map +1 -1
- package/index.js +3 -2
- package/package.json +10 -38
- package/resources/fore.css +263 -262
- package/resources/vars.css +8 -0
- package/src/DependencyNotifyingDomFacade.js +1 -0
- package/src/ForeElementMixin.js +243 -228
- package/src/actions/abstract-action.js +407 -398
- package/src/actions/fx-action.js +6 -6
- package/src/actions/fx-append.js +1 -1
- package/src/actions/fx-call.js +63 -62
- package/src/actions/fx-confirm.js +11 -11
- package/src/actions/fx-construct-done.js +4 -4
- package/src/actions/fx-copy.js +36 -36
- package/src/actions/fx-delete.js +77 -79
- package/src/actions/fx-dispatch.js +14 -14
- package/src/actions/fx-hide.js +15 -15
- package/src/actions/fx-insert.js +9 -12
- package/src/actions/fx-insertchild.js +88 -0
- package/src/actions/fx-load.js +188 -185
- package/src/actions/fx-message.js +18 -19
- package/src/actions/fx-refresh.js +10 -10
- package/src/actions/fx-reload.js +16 -14
- package/src/actions/fx-replace.js +0 -1
- package/src/actions/fx-reset.js +31 -31
- package/src/actions/fx-send.js +59 -52
- package/src/actions/fx-setattribute.js +48 -49
- package/src/actions/fx-setfocus.js +54 -58
- package/src/actions/fx-setvalue.js +85 -81
- package/src/actions/fx-show.js +11 -11
- package/src/actions/fx-toggle.js +2 -2
- package/src/actions/fx-toggleboolean.js +38 -39
- package/src/actions/fx-unmodified.js +27 -0
- package/src/actions/fx-update.js +6 -6
- package/src/dep_graph.js +1 -1
- package/src/drawdown.js +23 -30
- package/src/events.js +19 -19
- package/src/fore.js +143 -125
- package/src/functions/common-function.js +24 -25
- package/src/functions/fx-function.js +4 -6
- package/src/functions/fx-functionlib.js +39 -42
- package/src/functions/registerFunction.js +95 -86
- package/src/fx-bind.js +19 -24
- package/src/fx-connection.js +226 -0
- package/src/fx-fore.js +846 -815
- package/src/fx-header.js +4 -4
- package/src/fx-instance.js +23 -27
- package/src/fx-model.js +405 -383
- package/src/fx-submission.js +399 -397
- package/src/fx-var.js +6 -5
- package/src/getInScopeContext.js +102 -89
- package/src/json-util.js +24 -24
- package/src/lab/fore-component.js +48 -52
- package/src/lab/instance-inspector.js +13 -16
- package/src/modelitem.js +48 -10
- package/src/relevance.js +12 -16
- package/src/tools/adi.js +858 -812
- package/src/tools/fx-action-log.js +377 -295
- package/src/tools/fx-devtools.js +210 -210
- package/src/tools/fx-dom-inspector.js +123 -122
- package/src/tools/fx-json-instance.js +262 -253
- package/src/tools/fx-log-item.js +6 -11
- package/src/tools/fx-log-settings.js +358 -301
- package/src/tools/fx-minimap.js +186 -177
- package/src/tools/helpers.js +1 -1
- package/src/ui/abstract-control.js +74 -56
- package/src/ui/fx-case.js +59 -7
- package/src/ui/fx-container.js +13 -14
- package/src/ui/fx-control.js +572 -538
- package/src/ui/fx-dialog.js +3 -3
- package/src/ui/fx-droptarget.js +3 -4
- package/src/ui/fx-group.js +4 -2
- package/src/ui/fx-hint.js +3 -0
- package/src/ui/fx-inspector.js +5 -5
- package/src/ui/fx-items.js +11 -11
- package/src/ui/fx-output.js +10 -12
- package/src/ui/fx-repeat-attributes.js +23 -27
- package/src/ui/fx-repeat.js +347 -344
- package/src/ui/fx-repeatitem.js +75 -68
- package/src/ui/fx-switch.js +39 -14
- package/src/ui/fx-trigger.js +4 -4
- package/src/withDraggability.js +193 -191
- package/src/xpath-evaluation.js +969 -959
- package/src/xpath-util.js +161 -134
package/src/tools/fx-minimap.js
CHANGED
|
@@ -1,194 +1,203 @@
|
|
|
1
1
|
class FxMinimap extends HTMLElement {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
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
|
-
|
|
123
|
-
|
|
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
|
-
|
|
139
|
-
|
|
140
|
-
|
|
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
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
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
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
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
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
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
|
-
|
|
202
|
+
customElements.define('fx-minimap', FxMinimap);
|
|
194
203
|
}
|
package/src/tools/helpers.js
CHANGED
|
@@ -66,7 +66,7 @@ export function newElement(elem, attrs) {
|
|
|
66
66
|
return el;
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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;
|
|
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',{
|
|
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,23 +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
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
if (this.oldVal
|
|
151
|
-
Fore.dispatch(this, 'value-changed', {
|
|
165
|
+
// if oldVal is null we haven't received a concrete value yet
|
|
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
|
+
});
|
|
152
174
|
}
|
|
153
175
|
}
|
|
154
176
|
}
|
|
155
177
|
}
|
|
156
178
|
|
|
157
|
-
refreshFromModelItem(modelItem){
|
|
158
|
-
|
|
159
|
-
}
|
|
179
|
+
refreshFromModelItem(modelItem) {}
|
|
160
180
|
|
|
161
181
|
/**
|
|
162
182
|
*
|
|
@@ -192,13 +212,13 @@ export default class AbstractControl extends foreElementMixin(HTMLElement) {
|
|
|
192
212
|
// eslint-disable-next-line class-methods-use-this
|
|
193
213
|
handleRequired() {
|
|
194
214
|
// console.log('mip required', this.modelItem.required);
|
|
195
|
-
|
|
196
|
-
|
|
215
|
+
this.widget = this.getWidget();
|
|
216
|
+
const wasRequired = this.isRequired();
|
|
197
217
|
|
|
198
|
-
if(!this.modelItem.required){
|
|
218
|
+
if (!this.modelItem.required) {
|
|
199
219
|
this.widget.removeAttribute('required');
|
|
200
220
|
this.removeAttribute('required');
|
|
201
|
-
if (wasRequired !== this.modelItem.required){
|
|
221
|
+
if (wasRequired !== this.modelItem.required) {
|
|
202
222
|
this._dispatchEvent('optional');
|
|
203
223
|
}
|
|
204
224
|
return;
|
|
@@ -220,20 +240,19 @@ export default class AbstractControl extends foreElementMixin(HTMLElement) {
|
|
|
220
240
|
this._dispatchEvent('required');
|
|
221
241
|
}
|
|
222
242
|
|
|
223
|
-
/*
|
|
243
|
+
/*
|
|
224
244
|
if (this.isRequired() !== this.modelItem.required) {
|
|
225
245
|
this._updateRequired();
|
|
226
246
|
}
|
|
227
247
|
*/
|
|
228
248
|
}
|
|
229
249
|
|
|
230
|
-
|
|
231
250
|
_updateRequired() {
|
|
232
251
|
if (this.modelItem.required) {
|
|
233
252
|
// if (this.getOwnerForm().ready){
|
|
234
253
|
if (this.visited || this.force) {
|
|
235
|
-
|
|
236
|
-
|
|
254
|
+
// if (this.visited ) {
|
|
255
|
+
// if (this.widget.value === '') {
|
|
237
256
|
if (this.modelItem.value === '') {
|
|
238
257
|
this.classList.add('isEmpty');
|
|
239
258
|
this._toggleValid(false);
|
|
@@ -252,13 +271,13 @@ export default class AbstractControl extends foreElementMixin(HTMLElement) {
|
|
|
252
271
|
}
|
|
253
272
|
}
|
|
254
273
|
|
|
255
|
-
_toggleValid(valid){
|
|
256
|
-
if(valid){
|
|
274
|
+
_toggleValid(valid) {
|
|
275
|
+
if (valid) {
|
|
257
276
|
this.removeAttribute('invalid');
|
|
258
|
-
this.setAttribute('valid','');
|
|
259
|
-
}else{
|
|
277
|
+
this.setAttribute('valid', '');
|
|
278
|
+
} else {
|
|
260
279
|
this.removeAttribute('valid');
|
|
261
|
-
this.setAttribute('invalid','');
|
|
280
|
+
this.setAttribute('invalid', '');
|
|
262
281
|
}
|
|
263
282
|
}
|
|
264
283
|
|
|
@@ -287,19 +306,18 @@ export default class AbstractControl extends foreElementMixin(HTMLElement) {
|
|
|
287
306
|
if (this.modelItem.constraint) {
|
|
288
307
|
// if (alert) alert.style.display = 'none';
|
|
289
308
|
this._dispatchEvent('valid');
|
|
290
|
-
this.setAttribute('valid','');
|
|
309
|
+
this.setAttribute('valid', '');
|
|
291
310
|
this.removeAttribute('invalid');
|
|
292
311
|
} else {
|
|
293
312
|
this.setAttribute('invalid', '');
|
|
294
313
|
this.removeAttribute('valid');
|
|
295
314
|
// ### constraint is invalid - handle alerts
|
|
296
|
-
/*
|
|
315
|
+
/*
|
|
297
316
|
if (alert) {
|
|
298
317
|
alert.style.display = 'block';
|
|
299
318
|
}
|
|
300
319
|
*/
|
|
301
320
|
if (this.modelItem.alerts.length !== 0) {
|
|
302
|
-
|
|
303
321
|
const controlAlert = this.querySelector('fx-alert');
|
|
304
322
|
if (!controlAlert) {
|
|
305
323
|
const { alerts } = this.modelItem;
|
|
@@ -327,7 +345,7 @@ export default class AbstractControl extends foreElementMixin(HTMLElement) {
|
|
|
327
345
|
this.removeAttribute('nonrelevant');
|
|
328
346
|
if (Array.isArray(item) && item.length === 0) {
|
|
329
347
|
this._dispatchEvent('nonrelevant');
|
|
330
|
-
this.setAttribute('nonrelevant','');
|
|
348
|
+
this.setAttribute('nonrelevant', '');
|
|
331
349
|
// this.style.display = 'none';
|
|
332
350
|
return;
|
|
333
351
|
}
|
|
@@ -335,12 +353,12 @@ export default class AbstractControl extends foreElementMixin(HTMLElement) {
|
|
|
335
353
|
if (this.modelItem.relevant) {
|
|
336
354
|
this._dispatchEvent('relevant');
|
|
337
355
|
// this._fadeIn(this, this.display);
|
|
338
|
-
this.setAttribute('relevant','');
|
|
356
|
+
this.setAttribute('relevant', '');
|
|
339
357
|
// this.style.display = this.display;
|
|
340
358
|
} else {
|
|
341
359
|
this._dispatchEvent('nonrelevant');
|
|
342
360
|
// this._fadeOut(this);
|
|
343
|
-
this.setAttribute('nonrelevant','');
|
|
361
|
+
this.setAttribute('nonrelevant', '');
|
|
344
362
|
// this.style.display = 'none';
|
|
345
363
|
}
|
|
346
364
|
}
|
|
@@ -351,7 +369,7 @@ export default class AbstractControl extends foreElementMixin(HTMLElement) {
|
|
|
351
369
|
}
|
|
352
370
|
|
|
353
371
|
isValid() {
|
|
354
|
-
return this.hasAttribute('invalid')
|
|
372
|
+
return !this.hasAttribute('invalid');
|
|
355
373
|
}
|
|
356
374
|
|
|
357
375
|
isReadonly() {
|