@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.
- package/README.md +2 -2
- 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 +4 -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 +6 -99
- package/src/functions/fx-functionlib.js +56 -0
- package/src/functions/registerFunction.js +112 -0
- package/src/fx-bind.js +19 -24
- package/src/fx-connection.js +226 -0
- package/src/fx-fore.js +844 -815
- package/src/fx-header.js +4 -4
- package/src/fx-instance.js +25 -29
- package/src/fx-model.js +405 -380
- package/src/fx-submission.js +399 -397
- package/src/fx-var.js +13 -12
- 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 +73 -53
- 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 -958
- 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,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
|
-
|
|
149
|
-
|
|
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
|
-
|
|
194
|
-
|
|
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
|
-
|
|
234
|
-
|
|
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')
|
|
372
|
+
return !this.hasAttribute('invalid');
|
|
353
373
|
}
|
|
354
374
|
|
|
355
375
|
isReadonly() {
|