@jinntec/fore 2.5.0 → 2.7.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 +36088 -9
- package/dist/fore.js +35918 -9
- package/index.js +3 -1
- package/package.json +10 -4
- package/resources/fore.css +30 -5
- package/src/DataObserver.js +181 -0
- package/src/DependencyNotifyingDomFacade.js +27 -21
- package/src/DependentXPathQueries.js +32 -0
- package/src/ForeElementMixin.js +60 -26
- package/src/actions/abstract-action.js +24 -29
- package/src/actions/fx-append.js +25 -2
- package/src/actions/fx-call.js +2 -2
- package/src/actions/fx-delete.js +58 -21
- package/src/actions/fx-hide.js +1 -1
- package/src/actions/fx-insert.js +62 -48
- package/src/actions/fx-load.js +7 -2
- package/src/actions/fx-refresh.js +15 -5
- package/src/actions/fx-replace.js +18 -3
- package/src/actions/fx-reset.js +6 -0
- package/src/actions/fx-send.js +10 -7
- package/src/actions/fx-setattribute.js +12 -0
- package/src/actions/fx-setfocus.js +11 -8
- package/src/actions/fx-setvalue.js +20 -2
- package/src/actions/fx-show.js +4 -2
- package/src/actions/fx-toggle.js +1 -1
- package/src/extract-predicate-deps.js +57 -0
- package/src/extractPredicateDependencies.js +36 -0
- package/src/fore.js +78 -36
- package/src/fx-bind.js +128 -23
- package/src/fx-connection.js +24 -7
- package/src/fx-fore.js +552 -306
- package/src/fx-instance.js +9 -11
- package/src/fx-model.js +154 -65
- package/src/fx-submission.js +45 -51
- package/src/fx-var.js +5 -0
- package/src/getInScopeContext.js +8 -8
- package/src/modelitem.js +218 -72
- package/src/tools/fx-action-log.js +21 -19
- package/src/tools/fx-log-settings.js +4 -2
- package/src/ui/TemplateExpression.js +12 -0
- package/src/ui/UIElement.js +206 -0
- package/src/ui/abstract-control.js +15 -7
- package/src/ui/fx-case.js +15 -3
- package/src/ui/fx-container.js +10 -3
- package/src/ui/fx-control-menu.js +207 -0
- package/src/ui/fx-control.js +116 -32
- package/src/ui/fx-dialog.js +2 -2
- package/src/ui/fx-group.js +14 -0
- package/src/ui/fx-items.js +10 -4
- package/src/ui/fx-repeat-attributes.js +111 -35
- package/src/ui/fx-repeat.js +364 -87
- package/src/ui/fx-repeat.updated.js +821 -0
- package/src/ui/fx-repeatitem.js +23 -20
- package/src/ui/fx-switch.js +5 -3
- package/src/ui/fx-upload.js +36 -40
- package/src/ui/repeat-base.js +532 -0
- package/src/withDraggability.js +8 -4
- package/src/xpath-evaluation.js +26 -8
- package/src/xpath-path.js +79 -0
- package/src/xpath-util.js +107 -11
- package/dist/fore-dev.js.map +0 -1
- package/dist/fore.js.map +0 -1
- package/src/ui/fx-select.js +0 -89
|
@@ -4,6 +4,7 @@ import getInScopeContext from '../getInScopeContext.js';
|
|
|
4
4
|
import { Fore } from '../fore.js';
|
|
5
5
|
import { FxFore } from '../fx-fore.js';
|
|
6
6
|
import { XPathUtil } from '../xpath-util.js';
|
|
7
|
+
import { getDocPath } from '../xpath-path.js';
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* @param {number} howLong How long to wait, in ms
|
|
@@ -122,6 +123,7 @@ export class AbstractAction extends ForeElementMixin {
|
|
|
122
123
|
disconnectedCallback() {}
|
|
123
124
|
|
|
124
125
|
connectedCallback() {
|
|
126
|
+
super.connectedCallback();
|
|
125
127
|
this.setAttribute('inert', 'true');
|
|
126
128
|
this.style.display = 'none';
|
|
127
129
|
this.propagate = this.hasAttribute('propagate') ? this.getAttribute('propagate') : 'continue';
|
|
@@ -176,6 +178,7 @@ export class AbstractAction extends ForeElementMixin {
|
|
|
176
178
|
}
|
|
177
179
|
} else {
|
|
178
180
|
this.targetElement = this.parentNode;
|
|
181
|
+
if (!this.targetElement || this.targetElement.nodeType !== Node.ELEMENT_NODE) return;
|
|
179
182
|
this.targetElement.addEventListener(this.event, e => this.execute(e), {
|
|
180
183
|
capture: this.phase === 'capture',
|
|
181
184
|
});
|
|
@@ -192,7 +195,7 @@ export class AbstractAction extends ForeElementMixin {
|
|
|
192
195
|
await Fore.dispatch(this, 'error', {
|
|
193
196
|
origin: this,
|
|
194
197
|
message: 'Action execution failed',
|
|
195
|
-
expr:
|
|
198
|
+
expr: error,
|
|
196
199
|
level: 'Error',
|
|
197
200
|
});
|
|
198
201
|
// Return false to indicate failure. Any loops must be canceled
|
|
@@ -212,30 +215,22 @@ export class AbstractAction extends ForeElementMixin {
|
|
|
212
215
|
* @param e
|
|
213
216
|
*/
|
|
214
217
|
async execute(e) {
|
|
215
|
-
if(!this.getModel().modelConstructed) return;
|
|
218
|
+
if (!this.getModel().modelConstructed) return;
|
|
216
219
|
// console.log(this, this.event);
|
|
217
|
-
if(this.event){
|
|
218
|
-
if(this.event === 'submit-done'){
|
|
219
|
-
console.info(
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
);
|
|
223
|
-
}else{
|
|
224
|
-
console.info(
|
|
225
|
-
`%cexecuting ${this.constructor.name} ${this.event}`,
|
|
226
|
-
'background:lime; color:black; padding:.5rem; display:inline-block; white-space: nowrap; border-radius:0.3rem;width:100%;',
|
|
227
|
-
);
|
|
220
|
+
if (this.event) {
|
|
221
|
+
if (this.event === 'submit-done') {
|
|
222
|
+
console.info(`📌 ${this.event} #${this?.parentNode?.id}`);
|
|
223
|
+
} else {
|
|
224
|
+
console.info(`📌 ${this.constructor.name} ${this.event}`);
|
|
228
225
|
}
|
|
229
|
-
|
|
230
|
-
}else{
|
|
226
|
+
} else {
|
|
231
227
|
console.info(
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
228
|
+
`%cexecuting ${this.constructor.name}`,
|
|
229
|
+
'background:limegreen; color:black; margin-left:1rem; padding:.5rem; display:inline-block; white-space: nowrap; border-radius:0.3rem;width:100%;',
|
|
230
|
+
this,
|
|
235
231
|
);
|
|
236
232
|
}
|
|
237
233
|
|
|
238
|
-
|
|
239
234
|
if (e && e.target.nodeType !== Node.DOCUMENT_NODE && e.target !== window) {
|
|
240
235
|
/*
|
|
241
236
|
### ignore event if there's a parent fore and the current element is NOT part of it. This avoids
|
|
@@ -260,7 +255,7 @@ export class AbstractAction extends ForeElementMixin {
|
|
|
260
255
|
let resolveThisEvent = () => {};
|
|
261
256
|
if (e && e.listenerPromises) {
|
|
262
257
|
e.listenerPromises.push(
|
|
263
|
-
new Promise(
|
|
258
|
+
new Promise(resolve => {
|
|
264
259
|
resolveThisEvent = resolve;
|
|
265
260
|
}),
|
|
266
261
|
);
|
|
@@ -269,9 +264,9 @@ export class AbstractAction extends ForeElementMixin {
|
|
|
269
264
|
// Outermost handling
|
|
270
265
|
if (FxFore.outermostHandler === null) {
|
|
271
266
|
console.log(
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
267
|
+
`%coutermost Action on ${this.getOwnerForm().id}`,
|
|
268
|
+
'background:darkblue; color:white; padding:0.3rem; display:inline-block; white-space: nowrap; border-radius:0.3rem;',
|
|
269
|
+
this,
|
|
275
270
|
);
|
|
276
271
|
|
|
277
272
|
FxFore.outermostHandler = this;
|
|
@@ -406,9 +401,9 @@ export class AbstractAction extends ForeElementMixin {
|
|
|
406
401
|
this.actionPerformed();
|
|
407
402
|
if (FxFore.outermostHandler === this) {
|
|
408
403
|
console.log(
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
404
|
+
`%cfinalizing outermost Action on ${this.getOwnerForm()?.id}`,
|
|
405
|
+
'background:darkblue; color:white; padding:0.3rem; display:inline-block; white-space: nowrap; border-radius:0.3rem;',
|
|
406
|
+
this,
|
|
412
407
|
);
|
|
413
408
|
|
|
414
409
|
FxFore.outermostHandler = null;
|
|
@@ -467,8 +462,8 @@ export class AbstractAction extends ForeElementMixin {
|
|
|
467
462
|
return;
|
|
468
463
|
}
|
|
469
464
|
if (
|
|
470
|
-
FxFore.outermostHandler
|
|
471
|
-
|
|
465
|
+
FxFore.outermostHandler &&
|
|
466
|
+
!XPathUtil.contains(FxFore.outermostHandler.ownerDocument, FxFore.outermostHandler)
|
|
472
467
|
) {
|
|
473
468
|
// The old outermostHandler fell out of the document. An error has happened.
|
|
474
469
|
// Just remove the old one and act like we are starting anew.
|
|
@@ -480,7 +475,7 @@ export class AbstractAction extends ForeElementMixin {
|
|
|
480
475
|
// console.log('running update cycle for outermostHandler', this);
|
|
481
476
|
model.recalculate();
|
|
482
477
|
model.revalidate();
|
|
483
|
-
|
|
478
|
+
this.getOwnerForm().refresh(false);
|
|
484
479
|
this.dispatchActionPerformed();
|
|
485
480
|
} else if (this.needsUpdate) {
|
|
486
481
|
// console.log('Update delayed!');
|
package/src/actions/fx-append.js
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import { AbstractAction } from './abstract-action.js';
|
|
2
2
|
import { Fore } from '../fore.js';
|
|
3
3
|
import { resolveId } from '../xpath-evaluation.js';
|
|
4
|
+
import { XPathUtil } from '../xpath-util.js';
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* `fx-append` appends an entry to a repeat.
|
|
7
8
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
9
|
* @deprecated - will be replaced with `fx-insert`
|
|
11
10
|
* @fires index-changed - fired after new item is appended
|
|
12
11
|
* @customElement
|
|
@@ -76,6 +75,8 @@ class FxAppend extends AbstractAction {
|
|
|
76
75
|
|
|
77
76
|
actionPerformed() {
|
|
78
77
|
super.actionPerformed();
|
|
78
|
+
const mi = this.getModelItem();
|
|
79
|
+
mi.notify();
|
|
79
80
|
// const repeat = document.getElementById(this.repeat);
|
|
80
81
|
// repeat.setIndex(repeat.nodeset.length);
|
|
81
82
|
this._dispatch();
|
|
@@ -103,12 +104,34 @@ class FxAppend extends AbstractAction {
|
|
|
103
104
|
|
|
104
105
|
// const rootNode = document.createElement(repeat.ref);
|
|
105
106
|
// const rootNode = inscope.ownerDocument.createElement(repeat.ref);
|
|
107
|
+
/**
|
|
108
|
+
* @type {Element}
|
|
109
|
+
*/
|
|
106
110
|
const rootNode = inscope.ownerDocument.createElement(repeat.ref);
|
|
107
111
|
|
|
108
112
|
// const data = this._dataFromRefs(rootNode, templ.content)
|
|
109
113
|
const data = this._generateInstance(templ.content, rootNode);
|
|
110
114
|
// console.log('_dataFromTemplate DATA', data);
|
|
111
115
|
inscope.appendChild(data);
|
|
116
|
+
parentForm.signalChangeToElement(inscope.localName);
|
|
117
|
+
parentForm.signalChangeToElement(data.localName);
|
|
118
|
+
|
|
119
|
+
const instanceId = XPathUtil.resolveInstance(this, this.ref);
|
|
120
|
+
const inst = this.getModel().getInstance(instanceId);
|
|
121
|
+
|
|
122
|
+
const fore = this.getOwnerForm();
|
|
123
|
+
|
|
124
|
+
Fore.dispatch(inst, 'insert', {
|
|
125
|
+
insertedNodes: data,
|
|
126
|
+
insertedParent: inscope,
|
|
127
|
+
ref: this.ref,
|
|
128
|
+
location: data.previousSibling,
|
|
129
|
+
position: 'after',
|
|
130
|
+
instanceId: inst.id,
|
|
131
|
+
foreId: fore.id,
|
|
132
|
+
index: Array.from(inscope.children).indexOf(data),
|
|
133
|
+
});
|
|
134
|
+
|
|
112
135
|
// console.log('appended new item ', data);
|
|
113
136
|
// return data;
|
|
114
137
|
}
|
package/src/actions/fx-call.js
CHANGED
|
@@ -3,7 +3,7 @@ import { AbstractAction } from './abstract-action.js';
|
|
|
3
3
|
import { evaluateXPath } from '../xpath-evaluation.js';
|
|
4
4
|
import { Fore } from '../fore.js';
|
|
5
5
|
import getInScopeContext from '../getInScopeContext.js';
|
|
6
|
-
import {
|
|
6
|
+
import { getDocPath } from '../xpath-path.js';
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* `fx-call`
|
|
@@ -67,7 +67,7 @@ export default class FxCall extends AbstractAction {
|
|
|
67
67
|
Fore.dispatch(this, 'error', {
|
|
68
68
|
origin: this,
|
|
69
69
|
message: `Action '${this.action}' not found`,
|
|
70
|
-
expr:
|
|
70
|
+
expr: getDocPath(this),
|
|
71
71
|
level: 'Error',
|
|
72
72
|
});
|
|
73
73
|
}
|
package/src/actions/fx-delete.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import * as fx from 'fontoxpath';
|
|
2
1
|
import { AbstractAction } from './abstract-action.js';
|
|
3
2
|
import { Fore } from '../fore.js';
|
|
4
|
-
import { evaluateXPathToNodes
|
|
3
|
+
import { evaluateXPathToNodes } from '../xpath-evaluation.js';
|
|
5
4
|
import { XPathUtil } from '../xpath-util.js';
|
|
6
5
|
import getInScopeContext from '../getInScopeContext.js';
|
|
7
6
|
|
|
@@ -52,40 +51,78 @@ class FxDelete extends AbstractAction {
|
|
|
52
51
|
}),
|
|
53
52
|
);
|
|
54
53
|
|
|
54
|
+
const fore = this.getOwnerForm();
|
|
55
|
+
|
|
55
56
|
let parent;
|
|
57
|
+
|
|
58
|
+
const removedNodes = [];
|
|
56
59
|
if (Array.isArray(nodesToDelete)) {
|
|
57
|
-
if (nodesToDelete.length === 0)
|
|
60
|
+
if (nodesToDelete.length === 0) {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
58
63
|
parent = nodesToDelete[0].parentNode;
|
|
64
|
+
|
|
59
65
|
nodesToDelete.forEach(item => {
|
|
60
|
-
this._deleteNode(parent, item)
|
|
66
|
+
if (this._deleteNode(parent, item)) {
|
|
67
|
+
fore.signalChangeToElement(item.localName);
|
|
68
|
+
removedNodes.push(item);
|
|
69
|
+
}
|
|
61
70
|
});
|
|
71
|
+
if (removedNodes.length) {
|
|
72
|
+
fore.signalChangeToElement(parent.localName);
|
|
73
|
+
}
|
|
62
74
|
} else {
|
|
63
75
|
parent = nodesToDelete.parentNode;
|
|
64
|
-
this._deleteNode(parent, nodesToDelete)
|
|
76
|
+
if (this._deleteNode(parent, nodesToDelete)) {
|
|
77
|
+
fore.signalChangeToElement(parent.localName);
|
|
78
|
+
|
|
79
|
+
fore.signalChangeToElement(nodesToDelete.localName);
|
|
80
|
+
removedNodes.push(nodesToDelete);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (removedNodes.length) {
|
|
85
|
+
await Fore.dispatch(instance, 'deleted', {
|
|
86
|
+
ref: path,
|
|
87
|
+
deletedNodes: removedNodes,
|
|
88
|
+
instanceId,
|
|
89
|
+
parent,
|
|
90
|
+
foreId: fore.id,
|
|
91
|
+
});
|
|
92
|
+
this.needsUpdate = true;
|
|
65
93
|
}
|
|
66
|
-
const foreId = this.getOwnerForm().id;
|
|
67
|
-
await Fore.dispatch(instance, 'deleted', { ref: path, deletedNodes: nodesToDelete , instanceId:instanceId, foreId:foreId});
|
|
68
|
-
this.needsUpdate = true;
|
|
69
94
|
}
|
|
70
95
|
|
|
96
|
+
/**
|
|
97
|
+
* Delete a node (if allowed). Does not hold for JSON
|
|
98
|
+
*
|
|
99
|
+
* @param {ParentNode} parent - The parent of the node to remove
|
|
100
|
+
* @param {ChildNode} node - The child to remove
|
|
101
|
+
*
|
|
102
|
+
* @returns {boolean} Whether the delete is allowed and succeeded
|
|
103
|
+
*/
|
|
71
104
|
_deleteNode(parent, node) {
|
|
72
|
-
if (
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
105
|
+
if (
|
|
106
|
+
parent.nodeType === Node.DOCUMENT_NODE ||
|
|
107
|
+
node.nodeType === Node.DOCUMENT_NODE ||
|
|
108
|
+
node.nodeType === Node.DOCUMENT_FRAGMENT_NODE ||
|
|
109
|
+
node.parentNode === null
|
|
110
|
+
) {
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
76
113
|
|
|
77
|
-
const mi = this.getModelItem();
|
|
78
|
-
|
|
114
|
+
const mi = this.getModel().getModelItem(node);
|
|
115
|
+
// Note that the model item can be absent, For elements that had no controls on them.
|
|
116
|
+
// In that case, allow removals
|
|
117
|
+
if (mi?.readonly) {
|
|
118
|
+
return false;
|
|
119
|
+
}
|
|
79
120
|
|
|
80
121
|
parent.removeChild(node);
|
|
81
|
-
}
|
|
82
122
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
actionPerformed() {
|
|
87
|
-
this.getModel().rebuild();
|
|
88
|
-
super.actionPerformed();
|
|
123
|
+
this.getModel().removeModelItem(node);
|
|
124
|
+
|
|
125
|
+
return true;
|
|
89
126
|
}
|
|
90
127
|
}
|
|
91
128
|
|
package/src/actions/fx-hide.js
CHANGED
package/src/actions/fx-insert.js
CHANGED
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
} from '../xpath-evaluation.js';
|
|
8
8
|
import { XPathUtil } from '../xpath-util';
|
|
9
9
|
import { Fore } from '../fore.js';
|
|
10
|
+
import { getPath } from '../xpath-path.js';
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* `fx-insert`
|
|
@@ -60,31 +61,6 @@ export class FxInsert extends AbstractAction {
|
|
|
60
61
|
this.keepValues = !!this.hasAttribute('keep-values');
|
|
61
62
|
}
|
|
62
63
|
|
|
63
|
-
_getOriginSequence(inscope, targetSequence) {
|
|
64
|
-
let originSequence;
|
|
65
|
-
if (this.origin) {
|
|
66
|
-
// ### if there's an origin attribute use it
|
|
67
|
-
let originTarget;
|
|
68
|
-
try {
|
|
69
|
-
originTarget = evaluateXPathToFirstNode(this.origin, inscope, this);
|
|
70
|
-
if (Array.isArray(originTarget) && originTarget.length === 0) {
|
|
71
|
-
console.warn('invalid origin for this insert action - ignoring...', this);
|
|
72
|
-
originSequence = null;
|
|
73
|
-
}
|
|
74
|
-
originSequence = originTarget;
|
|
75
|
-
} catch (error) {
|
|
76
|
-
console.warn('invalid origin for this insert action - ignoring...', this);
|
|
77
|
-
}
|
|
78
|
-
} else if (targetSequence) {
|
|
79
|
-
// ### use last item of targetSequence
|
|
80
|
-
originSequence = targetSequence;
|
|
81
|
-
if (originSequence && !this.keepValues) {
|
|
82
|
-
this._clear(originSequence);
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
return originSequence;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
64
|
_cloneOriginSequence(inscope, targetSequence) {
|
|
89
65
|
let originSequenceClone;
|
|
90
66
|
if (this.origin) {
|
|
@@ -96,13 +72,25 @@ export class FxInsert extends AbstractAction {
|
|
|
96
72
|
*/
|
|
97
73
|
// this.setInScopeVariables(this.detail);
|
|
98
74
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
75
|
+
/*
|
|
76
|
+
if in 'create-nodes' mode and origin targets a repeat, the repeat
|
|
77
|
+
we use the already during initData() created nodeset as a template for insertion
|
|
78
|
+
*/
|
|
79
|
+
if (this.origin.startsWith('#') && this.getOwnerForm().createNodes) {
|
|
80
|
+
const repeat = this.getOwnerForm().querySelector(this.origin);
|
|
81
|
+
originSequenceClone = repeat.createdNodeset.cloneNode(true);
|
|
82
|
+
if (!originSequenceClone) {
|
|
83
|
+
console.error(`createdNodeset for repeat ${this.origin} does not exist`);
|
|
84
|
+
}
|
|
85
|
+
} else {
|
|
86
|
+
// originTarget = evaluateXPathToFirstNode(this.origin, inscope, this);
|
|
87
|
+
originTarget = evaluateXPathToFirstNode(this.origin, inscope, this);
|
|
88
|
+
if (Array.isArray(originTarget) && originTarget.length === 0) {
|
|
89
|
+
console.warn('invalid origin for this insert action - ignoring...', this);
|
|
90
|
+
originSequenceClone = null;
|
|
91
|
+
}
|
|
92
|
+
originSequenceClone = originTarget.cloneNode(true);
|
|
104
93
|
}
|
|
105
|
-
originSequenceClone = originTarget.cloneNode(true);
|
|
106
94
|
} catch (error) {
|
|
107
95
|
console.warn('invalid origin for this insert action - ignoring...', this);
|
|
108
96
|
}
|
|
@@ -136,13 +124,11 @@ export class FxInsert extends AbstractAction {
|
|
|
136
124
|
let targetSequence = [];
|
|
137
125
|
const inscopeContext = getInScopeContext(this);
|
|
138
126
|
|
|
127
|
+
const fore = this.getOwnerForm();
|
|
128
|
+
|
|
139
129
|
// ### 'context' attribute takes precedence over 'ref'
|
|
140
130
|
if (this.hasAttribute('context')) {
|
|
141
|
-
[context] = evaluateXPathToNodes(
|
|
142
|
-
this.getAttribute('context'),
|
|
143
|
-
inscopeContext,
|
|
144
|
-
this.getOwnerForm(),
|
|
145
|
-
);
|
|
131
|
+
[context] = evaluateXPathToNodes(this.getAttribute('context'), inscopeContext, this);
|
|
146
132
|
inscope = inscopeContext;
|
|
147
133
|
}
|
|
148
134
|
|
|
@@ -154,10 +140,18 @@ export class FxInsert extends AbstractAction {
|
|
|
154
140
|
targetSequence = evaluateXPathToNodes(this.ref, inscope, this);
|
|
155
141
|
}
|
|
156
142
|
}
|
|
143
|
+
// const originSequenceClone = this._cloneOriginSequence(inscope, targetSequence);
|
|
144
|
+
|
|
157
145
|
const originSequenceClone = this._cloneOriginSequence(inscope, targetSequence);
|
|
158
146
|
if (!originSequenceClone) return; // if no origin back out without effect
|
|
159
147
|
|
|
148
|
+
/**
|
|
149
|
+
* @type {Node}
|
|
150
|
+
*/
|
|
160
151
|
let insertLocationNode;
|
|
152
|
+
/**
|
|
153
|
+
* @type {number}
|
|
154
|
+
*/
|
|
161
155
|
let index;
|
|
162
156
|
|
|
163
157
|
// if the targetSequence is empty but we got an originSequence use inscope as context and ignore 'at' and 'position'
|
|
@@ -165,12 +159,22 @@ export class FxInsert extends AbstractAction {
|
|
|
165
159
|
if (context) {
|
|
166
160
|
insertLocationNode = context;
|
|
167
161
|
context.appendChild(originSequenceClone);
|
|
162
|
+
fore.signalChangeToElement(insertLocationNode.localName);
|
|
163
|
+
fore.signalChangeToElement(originSequenceClone.localName);
|
|
168
164
|
index = 1;
|
|
169
165
|
} else {
|
|
170
|
-
// No context
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
166
|
+
// No context but creating nodes from UI
|
|
167
|
+
if (!inscope && this.getOwnerForm().createNodes) {
|
|
168
|
+
const repeat = this.getOwnerForm().querySelector(this.origin);
|
|
169
|
+
inscope = getInScopeContext(repeat, repeat.ref);
|
|
170
|
+
insertLocationNode = inscope;
|
|
171
|
+
inscope.appendChild(originSequenceClone);
|
|
172
|
+
index = inscope.length - 1;
|
|
173
|
+
} else {
|
|
174
|
+
insertLocationNode = inscope;
|
|
175
|
+
inscope.appendChild(originSequenceClone);
|
|
176
|
+
index = 1;
|
|
177
|
+
}
|
|
174
178
|
}
|
|
175
179
|
} else {
|
|
176
180
|
/* ### insert at position given by 'at' or use the last item in the targetSequence ### */
|
|
@@ -205,6 +209,8 @@ export class FxInsert extends AbstractAction {
|
|
|
205
209
|
if (this.position && this.position === 'before') {
|
|
206
210
|
// this.at -= 1;
|
|
207
211
|
insertLocationNode.parentNode.insertBefore(originSequenceClone, insertLocationNode);
|
|
212
|
+
fore.signalChangeToElement(insertLocationNode.parentNode);
|
|
213
|
+
fore.signalChangeToElement(originSequenceClone.localName);
|
|
208
214
|
}
|
|
209
215
|
|
|
210
216
|
if (this.position && this.position === 'after') {
|
|
@@ -214,11 +220,17 @@ export class FxInsert extends AbstractAction {
|
|
|
214
220
|
if (this.hasAttribute('context') && this.hasAttribute('ref')) {
|
|
215
221
|
// index=1;
|
|
216
222
|
inscope.append(originSequenceClone);
|
|
223
|
+
fore.signalChangeToElement(insertLocationNode);
|
|
224
|
+
fore.signalChangeToElement(originSequenceClone.localName);
|
|
217
225
|
} else if (this.hasAttribute('context')) {
|
|
218
226
|
index = 1;
|
|
219
227
|
insertLocationNode.prepend(originSequenceClone);
|
|
228
|
+
fore.signalChangeToElement(insertLocationNode);
|
|
229
|
+
fore.signalChangeToElement(originSequenceClone.localName);
|
|
220
230
|
} else {
|
|
221
231
|
insertLocationNode.insertAdjacentElement('afterend', originSequenceClone);
|
|
232
|
+
fore.signalChangeToElement(insertLocationNode);
|
|
233
|
+
fore.signalChangeToElement(originSequenceClone.localName);
|
|
222
234
|
}
|
|
223
235
|
}
|
|
224
236
|
}
|
|
@@ -235,7 +247,7 @@ export class FxInsert extends AbstractAction {
|
|
|
235
247
|
// console.log('<<<<<<< resolved instance', inst);
|
|
236
248
|
// Note: the parent to insert under is always the parent of the inserted node. The 'context' is not always the parent if the sequence is empty, or the position is different
|
|
237
249
|
// const xpath = XPathUtil.getPath(originSequenceClone.parentNode, instanceId);
|
|
238
|
-
const xpath =
|
|
250
|
+
const xpath = getPath(insertLocationNode, instanceId);
|
|
239
251
|
|
|
240
252
|
const path = Fore.getDomNodeIndexString(originSequenceClone);
|
|
241
253
|
this.dispatchEvent(
|
|
@@ -246,13 +258,16 @@ export class FxInsert extends AbstractAction {
|
|
|
246
258
|
detail: { action: this, event: this.event, path },
|
|
247
259
|
}),
|
|
248
260
|
);
|
|
249
|
-
|
|
250
261
|
Fore.dispatch(inst, 'insert', {
|
|
251
|
-
|
|
252
|
-
|
|
262
|
+
insertedNodes: originSequenceClone,
|
|
263
|
+
insertedParent: insertLocationNode.parentNode,
|
|
264
|
+
ref: this.ref,
|
|
265
|
+
location: insertLocationNode,
|
|
253
266
|
position: this.position,
|
|
254
|
-
instanceId
|
|
255
|
-
foreId:
|
|
267
|
+
instanceId,
|
|
268
|
+
foreId: fore.id,
|
|
269
|
+
index,
|
|
270
|
+
xpath,
|
|
256
271
|
});
|
|
257
272
|
|
|
258
273
|
// todo: this actually should dispatch to respective instance
|
|
@@ -269,7 +284,6 @@ export class FxInsert extends AbstractAction {
|
|
|
269
284
|
);
|
|
270
285
|
|
|
271
286
|
this.needsUpdate = true;
|
|
272
|
-
console.log('Changed!', xpath);
|
|
273
287
|
return [xpath];
|
|
274
288
|
}
|
|
275
289
|
|
|
@@ -286,7 +300,7 @@ export class FxInsert extends AbstractAction {
|
|
|
286
300
|
|
|
287
301
|
actionPerformed(changedPaths) {
|
|
288
302
|
// ### make sure the necessary modelItems will get created
|
|
289
|
-
this.getModel().rebuild();
|
|
303
|
+
// this.getModel().rebuild();
|
|
290
304
|
super.actionPerformed();
|
|
291
305
|
}
|
|
292
306
|
|
package/src/actions/fx-load.js
CHANGED
|
@@ -27,12 +27,13 @@ class FxLoad extends AbstractAction {
|
|
|
27
27
|
super();
|
|
28
28
|
this.attachShadow({ mode: 'open' });
|
|
29
29
|
this.url = '';
|
|
30
|
+
this.replace=false;
|
|
30
31
|
}
|
|
31
32
|
|
|
32
33
|
connectedCallback() {
|
|
33
34
|
super.connectedCallback();
|
|
34
35
|
this.attachTo = this.hasAttribute('attach-to') ? this.getAttribute('attach-to') : '_self';
|
|
35
|
-
|
|
36
|
+
this.replace = this.hasAttribute('replace') ? true : false;
|
|
36
37
|
// Add a 'doneEvent' to block the action chain untill the event fired on the element we're
|
|
37
38
|
// loading something into.
|
|
38
39
|
this.awaitEvent = this.hasAttribute('await') ? this.getAttribute('await') : '';
|
|
@@ -88,7 +89,11 @@ class FxLoad extends AbstractAction {
|
|
|
88
89
|
resolved.removeEventListener(this.awaitEvent, eventListener);
|
|
89
90
|
};
|
|
90
91
|
|
|
91
|
-
|
|
92
|
+
if(this.replace){
|
|
93
|
+
this.parentNode.replaceChild(content,resolved);
|
|
94
|
+
}else{
|
|
95
|
+
resolved.appendChild(content);
|
|
96
|
+
}
|
|
92
97
|
resolved.addEventListener(this.awaitEvent, eventListener);
|
|
93
98
|
|
|
94
99
|
await waitForEvent;
|
|
@@ -22,23 +22,33 @@ class FxRefresh extends AbstractAction {
|
|
|
22
22
|
|
|
23
23
|
if (this.hasAttribute('self')) {
|
|
24
24
|
console.log(`### <<<<< refresh() self ${this} >>>>>`);
|
|
25
|
-
const control = XPathUtil.getClosest('fx-control', this);
|
|
25
|
+
const control = XPathUtil.getClosest('fx-control, fx-output, fx-upload', this);
|
|
26
26
|
if (control) {
|
|
27
|
-
control.refresh();
|
|
27
|
+
control.refresh(true);
|
|
28
28
|
return;
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
31
|
if (this.hasAttribute('force')) {
|
|
32
32
|
console.log(`### <<<<< refresh() force ${this} >>>>>`);
|
|
33
|
-
this.getOwnerForm().
|
|
33
|
+
this.getOwnerForm().refresh(true);
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
if(this.hasAttribute('selector')){
|
|
37
|
+
const target = document.querySelector(this.getAttribute('selector'));
|
|
38
|
+
if (target && Fore.isUiElement(target.nodeName) && typeof target.refresh === 'function') {
|
|
39
|
+
target.refresh(true);
|
|
40
|
+
}
|
|
34
41
|
return;
|
|
35
42
|
}
|
|
36
43
|
if (this.hasAttribute('control')) {
|
|
37
44
|
const targetId = this.getAttribute('control');
|
|
38
45
|
console.log(`### <<<<< refresh() control '${targetId}' >>>>>`);
|
|
39
|
-
|
|
46
|
+
let ctrl = resolveId(targetId, this);
|
|
47
|
+
if(!ctrl){
|
|
48
|
+
ctrl = document.querySelector(`#${targetId}`);
|
|
49
|
+
}
|
|
40
50
|
if (ctrl && Fore.isUiElement(ctrl.nodeName) && typeof ctrl.refresh === 'function') {
|
|
41
|
-
ctrl.refresh();
|
|
51
|
+
ctrl.refresh(true);
|
|
42
52
|
}
|
|
43
53
|
return;
|
|
44
54
|
}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import '../fx-model.js';
|
|
3
3
|
import { AbstractAction } from './abstract-action.js';
|
|
4
4
|
import { evaluateXPathToFirstNode } from '../xpath-evaluation.js';
|
|
5
|
+
import { FxBind } from '../fx-bind.js';
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* `fx-replace` - replaces the node referred to with 'ref' with node referred to with 'with' attribute.
|
|
@@ -44,8 +45,9 @@ export default class FxReplace extends AbstractAction {
|
|
|
44
45
|
}
|
|
45
46
|
|
|
46
47
|
actionPerformed() {
|
|
47
|
-
this.getModel().
|
|
48
|
-
|
|
48
|
+
this.getModel().updateModel();
|
|
49
|
+
this.getOwnerForm().refresh(true); //todo: optimize and update only the affected subtree
|
|
50
|
+
this.dispatchActionPerformed();
|
|
49
51
|
}
|
|
50
52
|
|
|
51
53
|
replace(toReplace, replaceWith) {
|
|
@@ -63,7 +65,20 @@ export default class FxReplace extends AbstractAction {
|
|
|
63
65
|
const cloned = replaceWith.cloneNode(true);
|
|
64
66
|
toReplace.replaceWith(cloned);
|
|
65
67
|
}
|
|
66
|
-
//
|
|
68
|
+
// todo: add selective update and create and notify modelItem for toReplace and replaceWith
|
|
69
|
+
/*
|
|
70
|
+
let replaceWithModelItem = this.getModel().getModelItem(replaceWith);
|
|
71
|
+
if (!replaceWithModelItem) {
|
|
72
|
+
const replaceWithModelItem = FxBind.createModelItem(
|
|
73
|
+
this.getAttribute('with'),
|
|
74
|
+
replaceWith,
|
|
75
|
+
this,
|
|
76
|
+
null,
|
|
77
|
+
);
|
|
78
|
+
this.getModel().registerModelItem(replaceWithModelItem);
|
|
79
|
+
this.getOwnerForm().addToBatchedNotifications(replaceWithModelItem);
|
|
80
|
+
}
|
|
81
|
+
*/
|
|
67
82
|
// this.getModel().changed.push(modelitem);
|
|
68
83
|
this.needsUpdate = true;
|
|
69
84
|
}
|
package/src/actions/fx-reset.js
CHANGED
|
@@ -41,6 +41,12 @@ export class FxReset extends AbstractAction {
|
|
|
41
41
|
data.reset();
|
|
42
42
|
this.needsUpdate = true;
|
|
43
43
|
}
|
|
44
|
+
|
|
45
|
+
actionPerformed() {
|
|
46
|
+
this.getModel().updateModel();
|
|
47
|
+
this.getOwnerForm().refresh(true);
|
|
48
|
+
this.dispatchActionPerformed();
|
|
49
|
+
}
|
|
44
50
|
}
|
|
45
51
|
|
|
46
52
|
if (!customElements.get('fx-reset')) {
|