@jinntec/fore 1.0.0-2 → 1.0.0-5
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 +37 -19
- package/dist/fore-all.js +10 -10
- package/dist/fore-debug.js +140 -0
- package/index.js +8 -1
- package/package.json +4 -4
- package/resources/fore.css +55 -0
- package/src/DependencyNotifyingDomFacade.js +9 -7
- package/src/ForeElementMixin.js +25 -3
- package/src/actions/abstract-action.js +5 -2
- package/src/actions/fx-action.js +6 -1
- package/src/actions/fx-hide.js +24 -0
- package/src/actions/fx-insert.js +32 -35
- package/src/actions/fx-setvalue.js +1 -1
- package/src/actions/fx-show.js +23 -0
- package/src/actions/fx-toggle.js +2 -1
- package/src/dep_graph.js +3 -1
- package/src/fore.js +34 -2
- package/src/fx-bind.js +15 -13
- package/src/fx-fore.js +146 -29
- package/src/fx-model.js +6 -2
- package/src/fx-submission.js +3 -0
- package/src/fx-var.js +43 -0
- package/src/getInScopeContext.js +47 -7
- package/src/modelitem.js +1 -0
- package/src/ui/abstract-control.js +9 -1
- package/src/ui/fx-container.js +4 -0
- package/src/ui/fx-dialog.js +77 -0
- package/src/ui/fx-items.js +6 -5
- package/src/ui/fx-output.js +9 -11
- package/src/ui/fx-repeat.js +51 -11
- package/src/ui/fx-trigger.js +3 -0
- package/src/xpath-evaluation.js +150 -97
- package/src/xpath-util.js +18 -2
- package/dist/fore.js +0 -2
package/index.js
CHANGED
|
@@ -5,6 +5,7 @@ import './src/fx-instance.js';
|
|
|
5
5
|
import './src/fx-model.js';
|
|
6
6
|
import './src/fx-submission.js';
|
|
7
7
|
import './src/fx-header.js';
|
|
8
|
+
import './src/fx-var.js';
|
|
8
9
|
|
|
9
10
|
// ui classes
|
|
10
11
|
import './src/ui/fx-alert.js';
|
|
@@ -18,9 +19,11 @@ import './src/ui/fx-switch.js';
|
|
|
18
19
|
import './src/ui/fx-trigger.js';
|
|
19
20
|
import './src/ui/fx-case.js';
|
|
20
21
|
import './src/ui/fx-inspector.js';
|
|
21
|
-
|
|
22
|
+
import './src/ui/fx-dialog.js';
|
|
22
23
|
import './src/ui/fx-items.js';
|
|
23
24
|
|
|
25
|
+
// import './src/ui/fx-checkbox-group.js';
|
|
26
|
+
|
|
24
27
|
// action classes
|
|
25
28
|
import './src/actions/fx-append.js';
|
|
26
29
|
import './src/actions/fx-delete.js';
|
|
@@ -33,5 +36,9 @@ import './src/actions/fx-dispatch.js';
|
|
|
33
36
|
import './src/actions/fx-update.js';
|
|
34
37
|
import './src/actions/fx-refresh.js';
|
|
35
38
|
import './src/actions/fx-confirm.js';
|
|
39
|
+
import './src/actions/fx-show.js';
|
|
40
|
+
import './src/actions/fx-hide.js';
|
|
36
41
|
|
|
37
42
|
import './src/functions/fx-function.js';
|
|
43
|
+
|
|
44
|
+
// import '@teipublisher/pb-components/src/pb-components-bundle.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jinntec/fore",
|
|
3
|
-
"version": "1.0.0-
|
|
3
|
+
"version": "1.0.0-5",
|
|
4
4
|
"description": "Fore - Forms for the Web",
|
|
5
5
|
"module": "./index.js",
|
|
6
6
|
"publishConfig": {
|
|
@@ -23,11 +23,11 @@
|
|
|
23
23
|
"resources/vars.css",
|
|
24
24
|
"resources/toastify.css",
|
|
25
25
|
"src/**/*",
|
|
26
|
-
"dist/fore.js",
|
|
27
|
-
"dist/fore-
|
|
26
|
+
"dist/fore-all.js",
|
|
27
|
+
"dist/fore-debug.js"
|
|
28
28
|
],
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@jinntec/jinn-toast": "^1.0.
|
|
30
|
+
"@jinntec/jinn-toast": "^1.0.3",
|
|
31
31
|
"@polymer/iron-component-page": "^4.0.1",
|
|
32
32
|
"@polymer/iron-demo-helpers": "^3.1.0",
|
|
33
33
|
"@polymer/paper-button": "^3.0.1",
|
package/resources/fore.css
CHANGED
|
@@ -14,6 +14,15 @@ html{
|
|
|
14
14
|
pointer-events: none;
|
|
15
15
|
cursor: default;
|
|
16
16
|
}
|
|
17
|
+
fx-fore{
|
|
18
|
+
opacity: 0;
|
|
19
|
+
}
|
|
20
|
+
fx-fore.fx-ready{
|
|
21
|
+
opacity: 1;
|
|
22
|
+
}
|
|
23
|
+
fx-group, fx-switch, fx-repeat, fx-dialog{
|
|
24
|
+
display: block;
|
|
25
|
+
}
|
|
17
26
|
fx-trigger a[disabled] {
|
|
18
27
|
color:lightgrey;
|
|
19
28
|
}
|
|
@@ -99,6 +108,52 @@ fx-inspector summary{
|
|
|
99
108
|
padding: 0;
|
|
100
109
|
}
|
|
101
110
|
|
|
111
|
+
/* ### FX-DIALOG STYLES ### */
|
|
112
|
+
/* ### FX-DIALOG STYLES ### */
|
|
113
|
+
/* ### FX-DIALOG STYLES ### */
|
|
114
|
+
fx-dialog{
|
|
115
|
+
display: none;
|
|
116
|
+
opacity: 0;
|
|
117
|
+
transition: opacity 1s linear;
|
|
118
|
+
}
|
|
119
|
+
fx-dialog.show{
|
|
120
|
+
display: block;
|
|
121
|
+
min-height: 200px;
|
|
122
|
+
border-radius: 0.5rem;
|
|
123
|
+
opacity: 1;
|
|
124
|
+
background:rgba(0,0,0,0.5);
|
|
125
|
+
z-index: 10;
|
|
126
|
+
transition: opacity 2s linear;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
fx-dialog.show .dialog-content{
|
|
130
|
+
padding: 1rem;
|
|
131
|
+
width:fit-content;
|
|
132
|
+
height:fit-content;
|
|
133
|
+
border:thin solid;
|
|
134
|
+
border-radius: 0.3rem;
|
|
135
|
+
position: absolute;
|
|
136
|
+
left:50%;
|
|
137
|
+
top:50%;
|
|
138
|
+
transform:translateX(-50%) translateY(-50%);
|
|
139
|
+
background: white;
|
|
140
|
+
|
|
141
|
+
}
|
|
142
|
+
fx-dialog a.close-dialog{
|
|
143
|
+
position: absolute;
|
|
144
|
+
right: 0.4rem;
|
|
145
|
+
top:0.2rem;
|
|
146
|
+
color:var(--paper-grey-900);
|
|
147
|
+
text-decoration: none;
|
|
148
|
+
font-size:1.2rem;
|
|
149
|
+
}
|
|
150
|
+
fx-dialog .action{
|
|
151
|
+
width: 100%;
|
|
152
|
+
text-align: center;
|
|
153
|
+
display: block;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
|
|
102
157
|
|
|
103
158
|
/*
|
|
104
159
|
.visible {
|
|
@@ -45,7 +45,7 @@ export class DependencyNotifyingDomFacade {
|
|
|
45
45
|
* @param bucket - The bucket that matches the attribute that will be used.
|
|
46
46
|
*/
|
|
47
47
|
// eslint-disable-next-line class-methods-use-this
|
|
48
|
-
/*
|
|
48
|
+
/*
|
|
49
49
|
getChildNodes(node, bucket) {
|
|
50
50
|
const matchingNodes = Array.from(node.childNodes).filter(
|
|
51
51
|
childNode => !bucket || getBucketsForNode(childNode).includes(bucket),
|
|
@@ -56,10 +56,12 @@ export class DependencyNotifyingDomFacade {
|
|
|
56
56
|
|
|
57
57
|
getChildNodes(node, bucket) {
|
|
58
58
|
const matchingNodes = Array.from(node.childNodes).filter(
|
|
59
|
-
|
|
59
|
+
childNode => !bucket || getBucketsForNode(childNode).includes(bucket),
|
|
60
|
+
);
|
|
60
61
|
matchingNodes.forEach(matchingNode => this._onNodeTouched(matchingNode));
|
|
61
62
|
return matchingNodes;
|
|
62
63
|
}
|
|
64
|
+
|
|
63
65
|
/**
|
|
64
66
|
* Get the data of this node.
|
|
65
67
|
*
|
|
@@ -83,11 +85,11 @@ export class DependencyNotifyingDomFacade {
|
|
|
83
85
|
* @param bucket - The bucket that matches the attribute that will be used.
|
|
84
86
|
*/
|
|
85
87
|
getFirstChild(node, bucket) {
|
|
86
|
-
const
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
88
|
+
for (const child of node.childNodes) {
|
|
89
|
+
if (!bucket || getBucketsForNode(child).includes(bucket)) {
|
|
90
|
+
this._onNodeTouched(node);
|
|
91
|
+
return child;
|
|
92
|
+
}
|
|
91
93
|
}
|
|
92
94
|
return null;
|
|
93
95
|
}
|
package/src/ForeElementMixin.js
CHANGED
|
@@ -7,6 +7,11 @@ import {
|
|
|
7
7
|
} from './xpath-evaluation.js';
|
|
8
8
|
import getInScopeContext from './getInScopeContext.js';
|
|
9
9
|
|
|
10
|
+
/**
|
|
11
|
+
* Mixin containing all general functions that are shared by all Fore element classes.
|
|
12
|
+
* @param superclass
|
|
13
|
+
* @returns {{readonly properties: {ref: {type: StringConstructor}, context: {type: ObjectConstructor}, nodeset: {type: ObjectConstructor}, model: {type: ObjectConstructor}, inScopeVariables: {type: MapConstructor}, modelItem: {type: ObjectConstructor}}, new(): ForeElementMixin, context: null, model: null, modelItem: {}, ref: *|string, inScopeVariables: null, nodeset: *, prototype: ForeElementMixin}}
|
|
14
|
+
*/
|
|
10
15
|
export const foreElementMixin = superclass =>
|
|
11
16
|
class ForeElementMixin extends superclass {
|
|
12
17
|
static get properties() {
|
|
@@ -41,6 +46,9 @@ export const foreElementMixin = superclass =>
|
|
|
41
46
|
ref: {
|
|
42
47
|
type: String,
|
|
43
48
|
},
|
|
49
|
+
inScopeVariables: {
|
|
50
|
+
type: Map,
|
|
51
|
+
},
|
|
44
52
|
};
|
|
45
53
|
}
|
|
46
54
|
|
|
@@ -50,6 +58,7 @@ export const foreElementMixin = superclass =>
|
|
|
50
58
|
this.model = null;
|
|
51
59
|
this.modelItem = {};
|
|
52
60
|
this.ref = this.hasAttribute('ref') ? this.getAttribute('ref') : '';
|
|
61
|
+
this.inScopeVariables = null;
|
|
53
62
|
}
|
|
54
63
|
|
|
55
64
|
getModel() {
|
|
@@ -90,10 +99,19 @@ export const foreElementMixin = superclass =>
|
|
|
90
99
|
*/
|
|
91
100
|
evalInContext() {
|
|
92
101
|
// const inscopeContext = this.getInScopeContext();
|
|
93
|
-
|
|
102
|
+
let inscopeContext;
|
|
103
|
+
if(this.hasAttribute('context')){
|
|
104
|
+
inscopeContext = getInScopeContext(this.getAttributeNode('context') || this, this.context);
|
|
105
|
+
}
|
|
106
|
+
if(this.hasAttribute('ref')){
|
|
107
|
+
inscopeContext = getInScopeContext(this.getAttributeNode('ref') || this, this.ref);
|
|
108
|
+
}
|
|
94
109
|
if (!inscopeContext) {
|
|
110
|
+
// ### always fall back to default context with there's neither a 'context' or 'ref' present
|
|
111
|
+
inscopeContext = this.getModel().getDefaultInstance().getDefaultContext();
|
|
95
112
|
console.warn('no in scopeContext for ', this);
|
|
96
|
-
|
|
113
|
+
console.warn('using default context ', this);
|
|
114
|
+
// return;
|
|
97
115
|
}
|
|
98
116
|
if (this.ref === '') {
|
|
99
117
|
this.nodeset = inscopeContext;
|
|
@@ -217,7 +235,11 @@ export const foreElementMixin = superclass =>
|
|
|
217
235
|
}
|
|
218
236
|
|
|
219
237
|
getInScopeContext() {
|
|
220
|
-
return getInScopeContext(this, this.ref);
|
|
238
|
+
return getInScopeContext(this.getAttributeNode('ref') || this, this.ref);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
setInScopeVariables(inScopeVariables) {
|
|
242
|
+
this.inScopeVariables = inScopeVariables;
|
|
221
243
|
}
|
|
222
244
|
|
|
223
245
|
dispatch(eventName, detail) {
|
|
@@ -124,7 +124,7 @@ export class AbstractAction extends foreElementMixin(HTMLElement) {
|
|
|
124
124
|
}
|
|
125
125
|
|
|
126
126
|
// First check if 'if' condition is true - otherwise exist right away
|
|
127
|
-
if (this.ifExpr && !evaluateXPathToBoolean(this.ifExpr, this.nodeset, this
|
|
127
|
+
if (this.ifExpr && !evaluateXPathToBoolean(this.ifExpr, this.nodeset, this)) {
|
|
128
128
|
return;
|
|
129
129
|
}
|
|
130
130
|
|
|
@@ -139,7 +139,7 @@ export class AbstractAction extends foreElementMixin(HTMLElement) {
|
|
|
139
139
|
return;
|
|
140
140
|
}
|
|
141
141
|
|
|
142
|
-
if (!evaluateXPathToBoolean(this.whileExpr, this.nodeset, this
|
|
142
|
+
if (!evaluateXPathToBoolean(this.whileExpr, this.nodeset, this)) {
|
|
143
143
|
// Done with iterating
|
|
144
144
|
return;
|
|
145
145
|
}
|
|
@@ -198,6 +198,9 @@ export class AbstractAction extends foreElementMixin(HTMLElement) {
|
|
|
198
198
|
}
|
|
199
199
|
|
|
200
200
|
/**
|
|
201
|
+
* dispathes action-performed event
|
|
202
|
+
*
|
|
203
|
+
* @event action-performed - whenever an action has been run
|
|
201
204
|
*/
|
|
202
205
|
dispatchActionPerformed() {
|
|
203
206
|
console.log('action-performed ', this);
|
package/src/actions/fx-action.js
CHANGED
|
@@ -41,7 +41,11 @@ export class FxAction extends AbstractAction {
|
|
|
41
41
|
script.src = this.src;
|
|
42
42
|
this.appendChild(script);
|
|
43
43
|
} else {
|
|
44
|
-
Array.from(children).forEach(
|
|
44
|
+
Array.from(children).forEach(actionOrVar => {
|
|
45
|
+
if (actionOrVar.localName === 'fx-var') {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
const action = actionOrVar;
|
|
45
49
|
action.detail = this.detail;
|
|
46
50
|
// action.perform();
|
|
47
51
|
action.execute();
|
|
@@ -50,6 +54,7 @@ export class FxAction extends AbstractAction {
|
|
|
50
54
|
// this.needsUpdate = false;
|
|
51
55
|
}
|
|
52
56
|
}
|
|
57
|
+
|
|
53
58
|
}
|
|
54
59
|
|
|
55
60
|
window.customElements.define('fx-action', FxAction);
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { FxAction } from './fx-action.js';
|
|
2
|
+
import {AbstractAction} from "./abstract-action";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* `fx-hide`
|
|
6
|
+
* hides a dialog
|
|
7
|
+
*
|
|
8
|
+
* @customElement
|
|
9
|
+
* @demo demo/project.html
|
|
10
|
+
*/
|
|
11
|
+
export class FxHide extends AbstractAction {
|
|
12
|
+
connectedCallback() {
|
|
13
|
+
this.dialog = this.getAttribute('dialog');
|
|
14
|
+
if(!this.dialog){
|
|
15
|
+
this.dispatch('error',{message:'dialog does not exist'})
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
perform() {
|
|
20
|
+
document.getElementById(this.dialog).hide();
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
window.customElements.define('fx-hide', FxHide);
|
package/src/actions/fx-insert.js
CHANGED
|
@@ -85,32 +85,22 @@ export class FxInsert extends AbstractAction {
|
|
|
85
85
|
console.log('this.nodeset', this.nodeset);
|
|
86
86
|
*/
|
|
87
87
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
88
|
+
let inscope;
|
|
89
|
+
// ### 'context' attribute takes precedence over 'ref'
|
|
90
|
+
let targetSequence;
|
|
91
|
+
if(this.hasAttribute('context')){
|
|
92
|
+
inscope = getInScopeContext(this.getAttributeNode('context'), this.getAttribute('context'));
|
|
93
|
+
targetSequence = evaluateXPathToNodes(this.getAttribute('context'), inscope, this.getOwnerForm());
|
|
94
|
+
}
|
|
94
95
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
return;
|
|
104
|
-
}
|
|
105
|
-
originSequence = originTarget.cloneNode(true);
|
|
106
|
-
} else if (targetSequence) {
|
|
107
|
-
// ### use last item of targetSequence
|
|
108
|
-
originSequence = this._cloneTargetSequence(targetSequence);
|
|
109
|
-
if(originSequence && !this.keepValues){
|
|
110
|
-
this._clear(originSequence);
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
*/
|
|
96
|
+
if(this.hasAttribute('ref')){
|
|
97
|
+
if(inscope){
|
|
98
|
+
targetSequence = evaluateXPathToNodes(this.ref, inscope, this.getOwnerForm());
|
|
99
|
+
}else{
|
|
100
|
+
inscope = getInScopeContext(this.getAttributeNode('ref'), this.ref);
|
|
101
|
+
targetSequence = evaluateXPathToNodes(this.ref, inscope, this.getOwnerForm());
|
|
102
|
+
}
|
|
103
|
+
}
|
|
114
104
|
const originSequenceClone = this._cloneOriginSequence(inscope, targetSequence);
|
|
115
105
|
if (!originSequenceClone) return; // if no origin back out without effect
|
|
116
106
|
|
|
@@ -127,13 +117,10 @@ export class FxInsert extends AbstractAction {
|
|
|
127
117
|
index = 1;
|
|
128
118
|
console.log('appended', inscope);
|
|
129
119
|
} else {
|
|
130
|
-
// todo: eval 'at'
|
|
131
120
|
|
|
132
|
-
/*
|
|
133
|
-
insert at position given by 'at' or use the last item in the targetSequence
|
|
134
|
-
*/
|
|
135
|
-
// if (this.at) {
|
|
121
|
+
/* ### insert at position given by 'at' or use the last item in the targetSequence ### */
|
|
136
122
|
if (this.hasAttribute('at')) {
|
|
123
|
+
// todo: eval 'at'
|
|
137
124
|
// index = this.at;
|
|
138
125
|
// insertLocationNode = targetSequence[this.at - 1];
|
|
139
126
|
|
|
@@ -165,7 +152,16 @@ export class FxInsert extends AbstractAction {
|
|
|
165
152
|
// insertLocationNode.parentNode.append(originSequence);
|
|
166
153
|
// const nextSibl = insertLocationNode.nextSibling;
|
|
167
154
|
index += 1;
|
|
168
|
-
|
|
155
|
+
if(this.hasAttribute('context') && this.hasAttribute('ref')){
|
|
156
|
+
// index=1;
|
|
157
|
+
inscope.append(originSequenceClone);
|
|
158
|
+
}else if(this.hasAttribute('context')){
|
|
159
|
+
const contextAttr = this.getAttribute('context');
|
|
160
|
+
index=1;
|
|
161
|
+
insertLocationNode.prepend(originSequenceClone);
|
|
162
|
+
}else{
|
|
163
|
+
insertLocationNode.insertAdjacentElement('afterend', originSequenceClone);
|
|
164
|
+
}
|
|
169
165
|
}
|
|
170
166
|
}
|
|
171
167
|
|
|
@@ -173,16 +169,17 @@ export class FxInsert extends AbstractAction {
|
|
|
173
169
|
// console.log('parent ', insertLocationNode.parentNode);
|
|
174
170
|
// console.log('instance ', this.getModel().getDefaultContext());
|
|
175
171
|
|
|
176
|
-
|
|
177
|
-
|
|
172
|
+
console.log('<<<<<<< at', this.at);
|
|
173
|
+
console.log('<<<<<<< index', index);
|
|
178
174
|
// todo: this actually should dispatch to respective instance
|
|
179
175
|
document.dispatchEvent(
|
|
180
|
-
new CustomEvent('insert', {
|
|
176
|
+
// new CustomEvent('insert', {
|
|
177
|
+
new CustomEvent('index-changed', {
|
|
181
178
|
composed: true,
|
|
182
179
|
bubbles: true,
|
|
183
180
|
detail: {
|
|
184
181
|
insertedNodes: originSequenceClone,
|
|
185
|
-
|
|
182
|
+
index,
|
|
186
183
|
},
|
|
187
184
|
}),
|
|
188
185
|
);
|
|
@@ -44,7 +44,7 @@ export default class FxSetvalue extends AbstractAction {
|
|
|
44
44
|
super.perform();
|
|
45
45
|
let { value } = this;
|
|
46
46
|
if (this.valueAttr !== null) {
|
|
47
|
-
value = evaluateXPath(this.valueAttr, this.nodeset, this
|
|
47
|
+
value = evaluateXPath(this.valueAttr, this.nodeset, this, this.detail);
|
|
48
48
|
} else if (this.textContent !== '') {
|
|
49
49
|
value = this.textContent;
|
|
50
50
|
} else {
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { FxAction } from './fx-action.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* `fx-confirm`
|
|
5
|
+
* Displays a simple confirmation before actually executing the nested actions.
|
|
6
|
+
*
|
|
7
|
+
* @customElement
|
|
8
|
+
* @demo demo/project.html
|
|
9
|
+
*/
|
|
10
|
+
export class FxShow extends FxAction {
|
|
11
|
+
connectedCallback() {
|
|
12
|
+
this.dialog = this.getAttribute('dialog');
|
|
13
|
+
if(!this.dialog){
|
|
14
|
+
this.dispatch('error',{message:'dialog does not exist'})
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
perform() {
|
|
19
|
+
document.getElementById(this.dialog).open();
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
window.customElements.define('fx-show', FxShow);
|
package/src/actions/fx-toggle.js
CHANGED
package/src/dep_graph.js
CHANGED
|
@@ -91,7 +91,9 @@ function createDFS(edges, leavesOnly, result, circular) {
|
|
|
91
91
|
// return;
|
|
92
92
|
// console.log('‘circular path: ' + currentPath);
|
|
93
93
|
// throw new DepGraphCycleError(currentPath);
|
|
94
|
-
|
|
94
|
+
|
|
95
|
+
// Stop all processing. This form is broken and we should not break the browser
|
|
96
|
+
throw new Error(`Cyclic at ${currentPath}`);
|
|
95
97
|
}
|
|
96
98
|
|
|
97
99
|
inCurrentPath[node] = true;
|
package/src/fore.js
CHANGED
|
@@ -13,6 +13,7 @@ export class Fore {
|
|
|
13
13
|
return [
|
|
14
14
|
'FX-DELETE',
|
|
15
15
|
'FX-DISPATCH',
|
|
16
|
+
'FX-HIDE',
|
|
16
17
|
'FX-INSERT',
|
|
17
18
|
'FX-LOAD',
|
|
18
19
|
'FX-MESSAGE',
|
|
@@ -29,6 +30,7 @@ export class Fore {
|
|
|
29
30
|
'FX-SETFOCUS',
|
|
30
31
|
'FX-SETINDEX',
|
|
31
32
|
'FX-SETVALUE',
|
|
33
|
+
'FX-SHOW',
|
|
32
34
|
'FX-TOGGLE',
|
|
33
35
|
'FX-UPDATE',
|
|
34
36
|
];
|
|
@@ -83,6 +85,7 @@ export class Fore {
|
|
|
83
85
|
'FX-TEXTAREA',
|
|
84
86
|
'FX-TRIGGER',
|
|
85
87
|
'FX-UPLOAD',
|
|
88
|
+
'FX-VAR',
|
|
86
89
|
];
|
|
87
90
|
}
|
|
88
91
|
|
|
@@ -187,14 +190,16 @@ export class Fore {
|
|
|
187
190
|
return fadeIn();
|
|
188
191
|
}
|
|
189
192
|
|
|
190
|
-
static fadeOutElement(element) {
|
|
191
|
-
const duration =
|
|
193
|
+
static fadeOutElement(element, duration) {
|
|
194
|
+
// const duration = duration;
|
|
192
195
|
let fadeOut = () => {
|
|
196
|
+
|
|
193
197
|
// Stop all current animations
|
|
194
198
|
if (element.getAnimations) {
|
|
195
199
|
element.getAnimations().map(anim => anim.finish());
|
|
196
200
|
}
|
|
197
201
|
|
|
202
|
+
|
|
198
203
|
// Play the animation with the newly specified duration
|
|
199
204
|
fadeOut = element.animate(
|
|
200
205
|
{
|
|
@@ -217,6 +222,33 @@ export class Fore {
|
|
|
217
222
|
target.dispatchEvent(event);
|
|
218
223
|
}
|
|
219
224
|
|
|
225
|
+
static prettifyXml(source) {
|
|
226
|
+
const xmlDoc = new DOMParser().parseFromString(source, 'application/xml');
|
|
227
|
+
const xsltDoc = new DOMParser().parseFromString(
|
|
228
|
+
[
|
|
229
|
+
// describes how we want to modify the XML - indent everything
|
|
230
|
+
'<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform">',
|
|
231
|
+
' <xsl:strip-space elements="*"/>',
|
|
232
|
+
' <xsl:template match="para[content-style][not(text())]">', // change to just text() to strip space in text nodes
|
|
233
|
+
' <xsl:value-of select="normalize-space(.)"/>',
|
|
234
|
+
' </xsl:template>',
|
|
235
|
+
' <xsl:template match="node()|@*">',
|
|
236
|
+
' <xsl:copy><xsl:apply-templates select="node()|@*"/></xsl:copy>',
|
|
237
|
+
' </xsl:template>',
|
|
238
|
+
' <xsl:output indent="yes"/>',
|
|
239
|
+
'</xsl:stylesheet>',
|
|
240
|
+
].join('\n'),
|
|
241
|
+
'application/xml',
|
|
242
|
+
);
|
|
243
|
+
|
|
244
|
+
const xsltProcessor = new XSLTProcessor();
|
|
245
|
+
xsltProcessor.importStylesheet(xsltDoc);
|
|
246
|
+
const resultDoc = xsltProcessor.transformToDocument(xmlDoc);
|
|
247
|
+
const resultXml = new XMLSerializer().serializeToString(resultDoc);
|
|
248
|
+
return resultXml;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
|
|
220
252
|
/**
|
|
221
253
|
* clear all text nodes and attribute values to get a 'clean' template.
|
|
222
254
|
* @param n
|
package/src/fx-bind.js
CHANGED
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
evaluateXPathToString,
|
|
8
8
|
} from './xpath-evaluation.js';
|
|
9
9
|
import { XPathUtil } from './xpath-util.js';
|
|
10
|
+
import getInScopeContext from './getInScopeContext.js';
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* FxBind declaratively attaches constraints to nodes in the data (instances).
|
|
@@ -229,12 +230,6 @@ export class FxBind extends foreElementMixin(HTMLElement) {
|
|
|
229
230
|
}
|
|
230
231
|
}
|
|
231
232
|
|
|
232
|
-
_addNode(path, node) {
|
|
233
|
-
if (!this.model.mainGraph.hasNode(path)) {
|
|
234
|
-
this.model.mainGraph.addNode(path, { node });
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
|
|
238
233
|
/**
|
|
239
234
|
* Add the dependencies of this bind
|
|
240
235
|
*
|
|
@@ -245,6 +240,7 @@ export class FxBind extends foreElementMixin(HTMLElement) {
|
|
|
245
240
|
* @param {string} property The property with this dependency
|
|
246
241
|
*/
|
|
247
242
|
_addDependencies(refs, node, path, property) {
|
|
243
|
+
// console.log('_addDependencies',path);
|
|
248
244
|
const nodeHash = `${path}:${property}`;
|
|
249
245
|
if (refs.length !== 0) {
|
|
250
246
|
if (!this.model.mainGraph.hasNode(nodeHash)) {
|
|
@@ -252,11 +248,15 @@ export class FxBind extends foreElementMixin(HTMLElement) {
|
|
|
252
248
|
}
|
|
253
249
|
refs.forEach(ref => {
|
|
254
250
|
const otherPath = XPathUtil.getPath(ref);
|
|
251
|
+
// console.log('otherPath', otherPath)
|
|
255
252
|
|
|
256
|
-
|
|
257
|
-
|
|
253
|
+
// todo: nasty hack to prevent duplicate pathes like 'a[1]' and 'a[1]/text()[1]' to end up as separate nodes in the graph
|
|
254
|
+
if (!otherPath.endsWith('text()[1]')) {
|
|
255
|
+
if (!this.model.mainGraph.hasNode(otherPath)) {
|
|
256
|
+
this.model.mainGraph.addNode(otherPath, ref);
|
|
257
|
+
}
|
|
258
|
+
this.model.mainGraph.addDependency(nodeHash, otherPath);
|
|
258
259
|
}
|
|
259
|
-
this.model.mainGraph.addDependency(nodeHash, otherPath);
|
|
260
260
|
});
|
|
261
261
|
} else {
|
|
262
262
|
this.model.mainGraph.addNode(nodeHash, node);
|
|
@@ -321,7 +321,7 @@ export class FxBind extends foreElementMixin(HTMLElement) {
|
|
|
321
321
|
* overwrites
|
|
322
322
|
*/
|
|
323
323
|
_evalInContext() {
|
|
324
|
-
const inscopeContext = this.
|
|
324
|
+
const inscopeContext = getInScopeContext(this.getAttributeNode('ref') || this, this.ref);
|
|
325
325
|
|
|
326
326
|
// reset nodeset
|
|
327
327
|
this.nodeset = [];
|
|
@@ -335,7 +335,7 @@ export class FxBind extends foreElementMixin(HTMLElement) {
|
|
|
335
335
|
} else {
|
|
336
336
|
// eslint-disable-next-line no-lonely-if
|
|
337
337
|
if (this.ref) {
|
|
338
|
-
const localResult = evaluateXPathToNodes(this.ref, n, this
|
|
338
|
+
const localResult = evaluateXPathToNodes(this.ref, n, this);
|
|
339
339
|
localResult.forEach(item => {
|
|
340
340
|
this.nodeset.push(item);
|
|
341
341
|
});
|
|
@@ -351,7 +351,7 @@ export class FxBind extends foreElementMixin(HTMLElement) {
|
|
|
351
351
|
} else {
|
|
352
352
|
const inst = this.getModel().getInstance(this.instanceId);
|
|
353
353
|
if (inst.type === 'xml') {
|
|
354
|
-
this.nodeset = evaluateXPathToNodes(this.ref, inscopeContext, this
|
|
354
|
+
this.nodeset = evaluateXPathToNodes(this.ref, inscopeContext, this);
|
|
355
355
|
} else {
|
|
356
356
|
this.nodeset = this.ref;
|
|
357
357
|
}
|
|
@@ -509,13 +509,15 @@ export class FxBind extends foreElementMixin(HTMLElement) {
|
|
|
509
509
|
* @param {string} propertyExpr The XPath to get the referenced nodes from
|
|
510
510
|
*
|
|
511
511
|
* @return {Node[]} The nodes that are referenced by the XPath
|
|
512
|
+
*
|
|
513
|
+
* todo: DependencyNotifyingDomFacade reports back too much in some cases like 'a[1]' and 'a[1]/text[1]'
|
|
512
514
|
*/
|
|
513
515
|
_getReferencesForProperty(propertyExpr) {
|
|
514
516
|
if (propertyExpr) {
|
|
515
517
|
const touchedNodes = new Set();
|
|
516
518
|
const domFacade = new DependencyNotifyingDomFacade(otherNode => touchedNodes.add(otherNode));
|
|
517
519
|
this.nodeset.forEach(node => {
|
|
518
|
-
evaluateXPathToString(propertyExpr, node, this
|
|
520
|
+
evaluateXPathToString(propertyExpr, node, this, domFacade);
|
|
519
521
|
});
|
|
520
522
|
|
|
521
523
|
return Array.from(touchedNodes.values());
|