@jinntec/fore 2.3.2 → 2.4.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/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/package.json +1 -1
- package/resources/fore.css +3 -0
- package/src/DependentXPathQueries.js +51 -0
- package/src/ForeElementMixin.js +6 -0
- package/src/fore.js +24 -7
- package/src/fx-fore.js +5 -2
- package/src/ui/abstract-control.js +7 -1
- package/src/ui/fx-group.js +3 -1
- package/src/ui/fx-repeat.js +1 -1
package/package.json
CHANGED
package/resources/fore.css
CHANGED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
export default class DependentXPathQueries {
|
|
2
|
+
constructor() {
|
|
3
|
+
/**
|
|
4
|
+
* @type {Set<string>}
|
|
5
|
+
*/
|
|
6
|
+
this._xpaths = new Set();
|
|
7
|
+
|
|
8
|
+
this._parentDependencies = null;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Returns true if this Fore element should be refreshed if a result of an index function changes
|
|
13
|
+
*
|
|
14
|
+
* @returns {boolean}
|
|
15
|
+
*/
|
|
16
|
+
isInvalidatedByIndexFunction() {
|
|
17
|
+
for (const xpath of this._xpaths) {
|
|
18
|
+
// TODO: this can be done a lot better with parsing / checking for function references
|
|
19
|
+
if (xpath.includes('index(')) {
|
|
20
|
+
return true;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// We can also depend on the index function if it was used in our ancestry
|
|
25
|
+
return !!this._parentDependencies?.isInvalidatedByIndexFunction();
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Add an XPath to the dependencies
|
|
30
|
+
*
|
|
31
|
+
* @param {string} xpath the XPath to add
|
|
32
|
+
*/
|
|
33
|
+
addXPath(xpath) {
|
|
34
|
+
this._xpaths.add(xpath);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Reset the dependencies on refresh
|
|
39
|
+
*
|
|
40
|
+
*/
|
|
41
|
+
resetDependencies() {
|
|
42
|
+
this._xpaths.clear();
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* @param {DependentXPathQueries} deps
|
|
47
|
+
*/
|
|
48
|
+
setParentDependencies(deps) {
|
|
49
|
+
this._parentDependencies = deps;
|
|
50
|
+
}
|
|
51
|
+
}
|
package/src/ForeElementMixin.js
CHANGED
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
} from './xpath-evaluation.js';
|
|
8
8
|
import getInScopeContext from './getInScopeContext.js';
|
|
9
9
|
import { Fore } from './fore.js';
|
|
10
|
+
import DependentXPathQueries from './DependentXPathQueries.js';
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* Mixin containing all general functions that are shared by all Fore element classes.
|
|
@@ -61,6 +62,9 @@ export default class ForeElementMixin extends HTMLElement {
|
|
|
61
62
|
* @type {Map<string, import('./fx-var.js').FxVariable>}
|
|
62
63
|
*/
|
|
63
64
|
this.inScopeVariables = new Map();
|
|
65
|
+
|
|
66
|
+
this._dependencies = new DependentXPathQueries();
|
|
67
|
+
this._dependencies.setParentDependencies(this.parent?.closest('[ref]')?._dependencies);
|
|
64
68
|
}
|
|
65
69
|
|
|
66
70
|
/**
|
|
@@ -103,6 +107,7 @@ export default class ForeElementMixin extends HTMLElement {
|
|
|
103
107
|
* evaluation of fx-bind and UiElements differ in details so that each class needs it's own implementation.
|
|
104
108
|
*/
|
|
105
109
|
evalInContext() {
|
|
110
|
+
this._dependencies.resetDependencies();
|
|
106
111
|
// const inscopeContext = this.getInScopeContext();
|
|
107
112
|
const model = this.getModel();
|
|
108
113
|
if (!model) {
|
|
@@ -114,6 +119,7 @@ export default class ForeElementMixin extends HTMLElement {
|
|
|
114
119
|
}
|
|
115
120
|
if (this.hasAttribute('ref')) {
|
|
116
121
|
inscopeContext = getInScopeContext(this.getAttributeNode('ref') || this, this.ref);
|
|
122
|
+
this._dependencies.addXPath(this.ref);
|
|
117
123
|
}
|
|
118
124
|
if (!inscopeContext && this.getModel().instances.length !== 0) {
|
|
119
125
|
// ### always fall back to default context with there's neither a 'context' or 'ref' present
|
package/src/fore.js
CHANGED
|
@@ -275,7 +275,8 @@ export class Fore {
|
|
|
275
275
|
* recursively refreshes all UI Elements.
|
|
276
276
|
*
|
|
277
277
|
* @param {HTMLElement} startElement
|
|
278
|
-
* @param {boolean} force
|
|
278
|
+
* @param {(boolean|{reason:'index-function'})} force Whether to do a forced refresh. Forced
|
|
279
|
+
* refreshes are very bad for performance, try to limit them. If the forced refresh is because index functions may change, it is better to pass the reason
|
|
279
280
|
* @returns {Promise<void>}
|
|
280
281
|
*/
|
|
281
282
|
static async refreshChildren(startElement, force) {
|
|
@@ -298,19 +299,35 @@ export class Fore {
|
|
|
298
299
|
*/
|
|
299
300
|
const { children } = startElement;
|
|
300
301
|
if (children) {
|
|
301
|
-
Array.from(children)
|
|
302
|
+
for (const element of Array.from(children)) {
|
|
302
303
|
if (element.nodeName.toUpperCase() === 'FX-FORE') {
|
|
303
|
-
|
|
304
|
-
return;
|
|
304
|
+
break;
|
|
305
305
|
}
|
|
306
|
-
if (Fore.isUiElement(element.nodeName)
|
|
306
|
+
if (Fore.isUiElement(element.nodeName)) {
|
|
307
|
+
/**
|
|
308
|
+
* @type {import('./ForeElementMixin.js').default}
|
|
309
|
+
*/
|
|
310
|
+
const foreElement = element;
|
|
311
|
+
|
|
312
|
+
if (typeof foreElement.refresh === 'function') {
|
|
313
|
+
if (
|
|
314
|
+
force &&
|
|
315
|
+
typeof force === 'object' &&
|
|
316
|
+
force.reason === 'index-function' &&
|
|
317
|
+
foreElement._dependencies.isInvalidatedByIndexFunction()
|
|
318
|
+
) {
|
|
319
|
+
element.refresh(force);
|
|
320
|
+
continue;
|
|
321
|
+
} else if (force === true) {
|
|
322
|
+
element.refresh(force);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
307
325
|
// console.log('refreshing', element, element?.ref);
|
|
308
326
|
// console.log('refreshing ',element);
|
|
309
|
-
element.refresh(force);
|
|
310
327
|
} else if (element.nodeName.toUpperCase() !== 'FX-MODEL') {
|
|
311
328
|
Fore.refreshChildren(element, force);
|
|
312
329
|
}
|
|
313
|
-
}
|
|
330
|
+
}
|
|
314
331
|
}
|
|
315
332
|
resolve('done');
|
|
316
333
|
});
|
package/src/fx-fore.js
CHANGED
|
@@ -484,6 +484,9 @@ export class FxFore extends HTMLElement {
|
|
|
484
484
|
}
|
|
485
485
|
|
|
486
486
|
// async refresh(force, changedPaths) {
|
|
487
|
+
/**
|
|
488
|
+
* @param {(boolean|{reason:'index-function'})} [force]fx-fore
|
|
489
|
+
*/
|
|
487
490
|
async refresh(force) {
|
|
488
491
|
/*
|
|
489
492
|
|
|
@@ -578,7 +581,7 @@ export class FxFore extends HTMLElement {
|
|
|
578
581
|
*/
|
|
579
582
|
|
|
580
583
|
if (this.inited) {
|
|
581
|
-
Fore.refreshChildren(this,
|
|
584
|
+
Fore.refreshChildren(this, force);
|
|
582
585
|
}
|
|
583
586
|
// console.timeEnd('refreshChildren');
|
|
584
587
|
}
|
|
@@ -620,7 +623,7 @@ export class FxFore extends HTMLElement {
|
|
|
620
623
|
for (const subFore of subFores) {
|
|
621
624
|
// subFore.refresh(false, changedPaths);
|
|
622
625
|
if (subFore.ready) {
|
|
623
|
-
await subFore.refresh(
|
|
626
|
+
await subFore.refresh(force);
|
|
624
627
|
}
|
|
625
628
|
}
|
|
626
629
|
this.isRefreshing = false;
|
|
@@ -9,6 +9,11 @@ function isDifferent(oldNodeValue, oldControlValue, newControlValue) {
|
|
|
9
9
|
if (oldNodeValue === null) {
|
|
10
10
|
return false;
|
|
11
11
|
}
|
|
12
|
+
/*
|
|
13
|
+
if the oldControlValue is null we know the widget is used for the first time and is not considered
|
|
14
|
+
a value change.
|
|
15
|
+
*/
|
|
16
|
+
if(oldControlValue === null) return false;
|
|
12
17
|
|
|
13
18
|
if (newControlValue && oldControlValue && newControlValue.nodeType && oldControlValue.nodeType) {
|
|
14
19
|
return newControlValue.outerHTML !== oldControlValue.outerHTML;
|
|
@@ -165,7 +170,8 @@ export default class AbstractControl extends ForeElementMixin {
|
|
|
165
170
|
// if oldVal is null we haven't received a concrete value yet
|
|
166
171
|
|
|
167
172
|
if (this.localName !== 'fx-control') return;
|
|
168
|
-
if (isDifferent(this.oldVal, this.value
|
|
173
|
+
if (isDifferent(this.oldVal, oldValue, this.value)) {
|
|
174
|
+
const model = this.getModel();
|
|
169
175
|
Fore.dispatch(this, 'value-changed', {
|
|
170
176
|
path: this.modelItem.path,
|
|
171
177
|
value: this.modelItem.value,
|
package/src/ui/fx-group.js
CHANGED
|
@@ -91,7 +91,9 @@ class FxGroup extends FxContainer {
|
|
|
91
91
|
|
|
92
92
|
async refresh(force) {
|
|
93
93
|
super.refresh(force);
|
|
94
|
-
|
|
94
|
+
// Make the maybe filtered refresh an unconditional forced refresh: This fx-group changes the
|
|
95
|
+
// context item
|
|
96
|
+
Fore.refreshChildren(this, !!force);
|
|
95
97
|
}
|
|
96
98
|
}
|
|
97
99
|
|
package/src/ui/fx-repeat.js
CHANGED
|
@@ -80,7 +80,7 @@ export class FxRepeat extends withDraggability(ForeElementMixin, false) {
|
|
|
80
80
|
const rItems = this.querySelectorAll(':scope > fx-repeatitem');
|
|
81
81
|
this.applyIndex(rItems[this.index - 1]);
|
|
82
82
|
|
|
83
|
-
this.getOwnerForm().refresh(
|
|
83
|
+
this.getOwnerForm().refresh({ reason: 'index-function' });
|
|
84
84
|
}
|
|
85
85
|
|
|
86
86
|
applyIndex(repeatItem) {
|