@jinntec/fore 1.0.0-3 → 1.0.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.
Files changed (62) hide show
  1. package/README.md +25 -34
  2. package/dist/fore-dev.js +43 -0
  3. package/dist/fore-dev.js.map +1 -0
  4. package/dist/fore.js +36 -1
  5. package/dist/fore.js.map +1 -0
  6. package/index.js +3 -0
  7. package/package.json +34 -38
  8. package/resources/fore.css +35 -50
  9. package/src/DependencyNotifyingDomFacade.js +10 -16
  10. package/src/ForeElementMixin.js +25 -18
  11. package/src/actions/abstract-action.js +17 -9
  12. package/src/actions/fx-action.js +6 -4
  13. package/src/actions/fx-append.js +8 -17
  14. package/src/actions/fx-confirm.js +3 -1
  15. package/src/actions/fx-delete.js +6 -3
  16. package/src/actions/fx-dispatch.js +9 -8
  17. package/src/actions/fx-hide.js +10 -6
  18. package/src/actions/fx-insert.js +49 -39
  19. package/src/actions/fx-message.js +3 -1
  20. package/src/actions/fx-refresh.js +11 -1
  21. package/src/actions/fx-replace.js +68 -0
  22. package/src/actions/fx-return.js +42 -0
  23. package/src/actions/fx-send.js +3 -1
  24. package/src/actions/fx-setvalue.js +58 -51
  25. package/src/actions/fx-show.js +8 -4
  26. package/src/actions/fx-toggle.js +15 -10
  27. package/src/actions/fx-update.js +3 -1
  28. package/src/dep_graph.js +4 -2
  29. package/src/drawdown.js +67 -82
  30. package/src/fore.js +158 -11
  31. package/src/functions/fx-function.js +11 -3
  32. package/src/fx-bind.js +42 -202
  33. package/src/fx-fore.js +105 -70
  34. package/src/fx-header.js +3 -1
  35. package/src/fx-instance.js +9 -1
  36. package/src/fx-model.js +31 -23
  37. package/src/fx-submission.js +73 -47
  38. package/src/fx-var.js +7 -4
  39. package/src/getInScopeContext.js +37 -11
  40. package/src/modelitem.js +4 -4
  41. package/src/relevance.js +65 -0
  42. package/src/ui/abstract-control.js +55 -35
  43. package/src/ui/fx-alert.js +7 -1
  44. package/src/ui/fx-case.js +3 -1
  45. package/src/ui/fx-container.js +7 -1
  46. package/src/ui/fx-control.js +283 -33
  47. package/src/ui/fx-dialog.js +54 -40
  48. package/src/ui/fx-group.js +3 -1
  49. package/src/ui/fx-hint.js +4 -1
  50. package/src/ui/fx-inspector.js +117 -17
  51. package/src/ui/fx-items.js +8 -8
  52. package/src/ui/fx-output.js +14 -5
  53. package/src/ui/fx-repeat.js +33 -41
  54. package/src/ui/fx-repeatitem.js +10 -4
  55. package/src/ui/fx-switch.js +3 -1
  56. package/src/ui/fx-trigger.js +3 -1
  57. package/src/xpath-evaluation.js +121 -131
  58. package/src/xpath-util.js +14 -7
  59. package/dist/fore-all.js +0 -140
  60. package/src/.DS_Store +0 -0
  61. package/src/actions/.DS_Store +0 -0
  62. package/src/ui/.DS_Store +0 -0
@@ -1,44 +1,144 @@
1
+ import { Fore } from '../fore.js';
2
+
1
3
  /**
2
4
  * lists out all live instances in html 'details' and 'summary' elements.
3
5
  */
4
6
  export class FxInspector extends HTMLElement {
7
+ constructor() {
8
+ super();
9
+ this.attachShadow({ mode: 'open' });
10
+ }
11
+
5
12
  connectedCallback() {
6
13
  const style = `
7
14
  :host {
15
+ position:absolute;
8
16
  display: block;
9
- width:100%;
17
+ width:var(--inspector-handle-width);
10
18
  background:var(--inspector-bg);
19
+ top:0;
20
+ right:0;
21
+ bottom:0;
22
+ height: 100%;
23
+ background: var(--inspector-bg);
24
+ color: white;
25
+ /*max-height: 33%;*/
26
+ overflow: scroll;
27
+ transition:width 0.3s ease;
28
+ }
29
+ :host([open]){
30
+ width: 30%;
31
+ }
32
+ details{
33
+ margin:1rem;
34
+ }
35
+ .main{
36
+ padding-left:var(--inspector-handle-width);
37
+ color:var(--inspector-color);
38
+ overflow:scroll;
11
39
  }
12
40
  pre{
13
41
  background:var(--inspector-pre-bg);
14
42
  color:var(--inspector-color);
15
- max-height:var(--inspector-instance-height,300px);
16
43
  overflow:scroll;
44
+ padding:0.2rem;
45
+ }
46
+ .handle{
47
+ display:block;
48
+ height:100vh;
49
+ width:var(--inspector-handle-width);
50
+ background:var(--inspector-handle-bg);
51
+ opacity:0.7;
52
+ position:absolute;
53
+ left:0;
54
+ color:white;
55
+ cursor:pointer;
56
+ }
57
+ .handle:hover{
58
+ opacity:1;
59
+ }
60
+ .handle::before{
61
+ content: 'Data Inspector';
62
+ white-space: nowrap;
63
+ transform: rotate(-90deg);
64
+ display: inline-block;
65
+ position: absolute;
66
+ left: -85px;
67
+ width: 200px;
68
+ top: 40px;
69
+ }
70
+ summary{
71
+ cursor:pointer;
17
72
  }
18
73
  `;
19
74
 
20
- const instances = Array.from(document.querySelectorAll('fx-instance'));
21
- this.innerHTML = `
75
+ const fore = this.closest('fx-fore');
76
+
77
+ // fore.addEventListener('ready', (e) => {
78
+ this.render(style);
79
+ // });
80
+ fore.addEventListener('refresh-done', () => {
81
+ this.update();
82
+ });
83
+ }
84
+
85
+ update() {
86
+ console.log('update');
87
+ const pre = this.shadowRoot.querySelectorAll('pre');
88
+ console.log('pre', pre);
89
+ const fore = this.closest('fx-fore');
90
+
91
+ Array.from(pre).forEach(element => {
92
+ const inst = fore.getModel().getInstance(element.getAttribute('id'));
93
+ if (inst.type === 'xml') {
94
+ element.innerText = this.serializeDOM(inst.instanceData);
95
+ }
96
+ if (inst.type === 'json') {
97
+ element.innerText = JSON.stringify(inst.instanceData, undefined, 2);
98
+ }
99
+ });
100
+ }
101
+
102
+ render(style) {
103
+ const fore = this.closest('fx-fore');
104
+ const instances = Array.from(fore.querySelectorAll('fx-instance'));
105
+ this.shadowRoot.innerHTML = `
22
106
  <style>
23
107
  ${style}
24
108
  </style>
109
+ <div class="main">
25
110
  <slot></slot>
26
- ${instances
27
- .map(
28
- (instance, index) => `
29
- <details ${index === 0 ? `open` : ''}>
30
- <summary>${instance.id}</summary>
31
- <pre>{log('${instance.id}')}</pre>
32
- </details>
33
- `,
34
- )
35
- .join('')}
111
+ <span class="handle"></span>
112
+ ${instances.map(
113
+ (instance, index) => `
114
+ <details open>
115
+ <summary>${instance.id}</summary>
116
+ <pre id="${instance.id}"></pre>
117
+ </details>
118
+ `,
119
+ )}
120
+ </div>
36
121
  `;
37
122
 
38
- this.addEventListener('slotchange', e => {
39
- console.log('slotchange ', e);
123
+ const handle = this.shadowRoot.querySelector('.handle');
124
+ handle.addEventListener('click', e => {
125
+ console.log('toggling');
126
+ const { target } = e;
127
+ if (this.hasAttribute('open')) {
128
+ this.removeAttribute('open');
129
+ } else {
130
+ this.setAttribute('open', 'open');
131
+ }
40
132
  });
41
133
  }
134
+
135
+ serializeDOM(data) {
136
+ console.log('serializeDOM', data);
137
+ const ser = new XMLSerializer().serializeToString(data);
138
+ return Fore.prettifyXml(ser);
139
+ }
42
140
  }
43
141
 
44
- customElements.define('fx-inspector', FxInspector);
142
+ if (!customElements.get('fx-inspector')) {
143
+ customElements.define('fx-inspector', FxInspector);
144
+ }
@@ -1,6 +1,4 @@
1
- import XfAbstractControl from './abstract-control.js';
2
- import { evaluateXPath, evaluateXPathToString, evaluateXPathToNodes } from '../xpath-evaluation.js';
3
- import getInScopeContext from '../getInScopeContext.js';
1
+ import { evaluateXPathToString, resolveId } from '../xpath-evaluation.js';
4
2
  import FxControl from './fx-control.js';
5
3
  import { Fore } from '../fore.js';
6
4
 
@@ -35,7 +33,7 @@ export class FxItems extends FxControl {
35
33
 
36
34
  let target;
37
35
  if (e.target.nodeName === 'LABEL') {
38
- target = document.getElementById(e.target.getAttribute('for'));
36
+ target = resolveId(e.target.getAttribute('for'), this);
39
37
  target.checked = !target.checked;
40
38
  }
41
39
 
@@ -48,7 +46,7 @@ export class FxItems extends FxControl {
48
46
  this.setAttribute('value', val.trim());
49
47
 
50
48
  // ### check for parent control
51
- const parentBind = this.parentNode.closest('[ref]');
49
+ const parentBind = Fore.getClosest('[ref]', this.parentNode);
52
50
  if (!parentBind) return;
53
51
  const modelitem = parentBind.getModelItem();
54
52
  const setval = this.shadowRoot.getElementById('setvalue');
@@ -64,7 +62,7 @@ export class FxItems extends FxControl {
64
62
  async updateWidgetValue() {
65
63
  // console.log('setting items value');
66
64
 
67
- const parentBind = this.parentNode.closest('[ref]');
65
+ const parentBind = Fore.getClosest('[ref]', this.parentNode);
68
66
  if (parentBind) {
69
67
  this.value = parentBind.value;
70
68
  }
@@ -103,7 +101,7 @@ export class FxItems extends FxControl {
103
101
  // getting expr
104
102
  const expr = input.value;
105
103
  const cutted = expr.substring(1, expr.length - 1);
106
- const evaluated = evaluateXPath(cutted, node, newEntry);
104
+ const evaluated = evaluateXPathToString(cutted, node, newEntry);
107
105
 
108
106
  // adding space around value to allow matching of 'words'
109
107
  const spaced = ` ${evaluated} `;
@@ -117,4 +115,6 @@ export class FxItems extends FxControl {
117
115
  }
118
116
  }
119
117
 
120
- customElements.define('fx-items', FxItems);
118
+ if (!customElements.get('fx-items')) {
119
+ customElements.define('fx-items', FxItems);
120
+ }
@@ -1,3 +1,4 @@
1
+ import { Fore } from '../fore.js';
1
2
  import XfAbstractControl from './abstract-control.js';
2
3
  import { evaluateXPath, evaluateXPathToStrings } from '../xpath-evaluation.js';
3
4
  import getInScopeContext from '../getInScopeContext.js';
@@ -20,6 +21,8 @@ export class FxOutput extends XfAbstractControl {
20
21
  super();
21
22
  this.attachShadow({ mode: 'open' });
22
23
  this.valueAttr = this.hasAttribute('value') ? this.getAttribute('value') : null;
24
+ // Outputs are always readonly!
25
+ this.readonly = true;
23
26
  }
24
27
 
25
28
  connectedCallback() {
@@ -85,13 +88,13 @@ export class FxOutput extends XfAbstractControl {
85
88
  try {
86
89
  const inscopeContext = getInScopeContext(this, this.valueAttr);
87
90
  if (this.hasAttribute('html')) {
88
- return evaluateXPath(this.valueAttr, inscopeContext, this);
91
+ return evaluateXPath(this.valueAttr, inscopeContext, this)[0];
89
92
  }
90
93
 
91
94
  return evaluateXPathToStrings(this.valueAttr, inscopeContext, this)[0];
92
95
  } catch (error) {
93
96
  console.error(error);
94
- this.dispatch('error', { message: error });
97
+ Fore.dispatch(this, 'error', { message: error });
95
98
  }
96
99
  return null;
97
100
  }
@@ -101,6 +104,11 @@ export class FxOutput extends XfAbstractControl {
101
104
  return valueWrapper;
102
105
  }
103
106
 
107
+ handleReadonly() {
108
+ // An output is always read-only
109
+ this.setAttribute('readonly', 'readonly');
110
+ }
111
+
104
112
  async updateWidgetValue() {
105
113
  console.log('updateWidgetValue');
106
114
  const valueWrapper = this.shadowRoot.getElementById('value');
@@ -150,9 +158,10 @@ export class FxOutput extends XfAbstractControl {
150
158
  }
151
159
 
152
160
  isReadonly() {
153
- this.readonly = true;
154
- return this.readonly;
161
+ return true;
155
162
  }
156
163
  }
157
164
 
158
- customElements.define('fx-output', FxOutput);
165
+ if (!customElements.get('fx-output')) {
166
+ customElements.define('fx-output', FxOutput);
167
+ }
@@ -4,7 +4,7 @@ import { Fore } from '../fore.js';
4
4
  import { foreElementMixin } from '../ForeElementMixin.js';
5
5
  import { evaluateXPath } from '../xpath-evaluation.js';
6
6
  import getInScopeContext from '../getInScopeContext.js';
7
- import {XPathUtil} from "../xpath-util";
7
+ import { XPathUtil } from '../xpath-util.js';
8
8
 
9
9
  /**
10
10
  * `fx-repeat`
@@ -18,6 +18,8 @@ import {XPathUtil} from "../xpath-util";
18
18
  *
19
19
  * @customElement
20
20
  * @demo demo/todo.html
21
+ *
22
+ * todo: it should be seriously be considered to extend FxContainer instead but needs refactoring first.
21
23
  */
22
24
  export class FxRepeat extends foreElementMixin(HTMLElement) {
23
25
  static get properties() {
@@ -100,41 +102,46 @@ export class FxRepeat extends foreElementMixin(HTMLElement) {
100
102
  this.index = idx + 1;
101
103
  });
102
104
  // todo: review - this is just used by append action - event consolidation ?
103
- this.addEventListener('index-changed', e => {
105
+ document.addEventListener('index-changed', e => {
104
106
  e.stopPropagation();
105
107
  if (!e.target === this) return;
106
108
  console.log('handle index event ', e);
107
109
  // const { item } = e.detail;
108
110
  // const idx = Array.from(this.children).indexOf(item);
109
111
  const { index } = e.detail;
110
- this.index = index;
112
+ this.index = Number(index);
111
113
  this.applyIndex(this.children[index - 1]);
112
114
  });
115
+ /*
113
116
  document.addEventListener('insert', e => {
114
117
  const nodes = e.detail.insertedNodes;
115
118
  this.index = e.detail.position;
116
119
  console.log('insert catched', nodes, this.index);
117
120
  });
121
+ */
118
122
 
119
123
  // if (this.getOwnerForm().lazyRefresh) {
120
- this.mutationObserver = new MutationObserver(mutations => {
121
- console.log('mutations', mutations);
122
-
123
- if(mutations[0].type === "childList"){
124
- const added = mutations[0].addedNodes[0];
125
- if(added){
126
- const path = XPathUtil.getPath(added);
127
- console.log('path mutated',path);
128
- // this.dispatch('path-mutated',{'path':path,'nodeset':this.nodeset,'index': this.index});
129
- this.dispatch('path-mutated',{'path':path,'index': this.index});
130
- }
131
-
124
+ this.mutationObserver = new MutationObserver(mutations => {
125
+ console.log('mutations', mutations);
126
+
127
+ if (mutations[0].type === 'childList') {
128
+ const added = mutations[0].addedNodes[0];
129
+ if (added) {
130
+ const path = XPathUtil.getPath(added);
131
+ console.log('path mutated', path);
132
+ // this.dispatch('path-mutated',{'path':path,'nodeset':this.nodeset,'index': this.index});
133
+ // this.index = index;
134
+ // const prev = mutations[0].previousSibling.previousElementSibling;
135
+ // const index = prev.index();
136
+ // this.applyIndex(this.index -1);
137
+
138
+ Fore.dispatch(this, 'path-mutated', { path, index: this.index });
132
139
  }
133
- });
140
+ }
141
+ });
134
142
  // }
135
143
  this.getOwnerForm().registerLazyElement(this);
136
144
 
137
-
138
145
  const style = `
139
146
  :host{
140
147
  }
@@ -192,31 +199,13 @@ export class FxRepeat extends foreElementMixin(HTMLElement) {
192
199
  });
193
200
  }
194
201
 
195
- const seq = evaluateXPath(this.ref, inscope, this.getOwnerForm());
196
- // const seq = evaluateXPathToNodes(this.ref, inscope, this.getOwnerForm());
197
- if (seq === null) {
198
- // Empty sequence
199
- this.nodeset = [];
202
+ const rawNodeset = evaluateXPath(this.ref, inscope, this);
203
+ if (rawNodeset.length === 1 && Array.isArray(rawNodeset[0])) {
204
+ // This XPath likely returned an XPath array. Just collapse to that array
205
+ this.nodeset = rawNodeset[0];
200
206
  return;
201
207
  }
202
-
203
- if (typeof seq === 'object') {
204
- // Either a node or an array
205
- if ('nodeType' in seq) {
206
- // Node
207
- this.nodeset = [seq];
208
- return;
209
- }
210
-
211
- // if (Array.isArray(seq) && seq.every(item => typeof item === 'object')) {
212
- if (Array.isArray(seq)) {
213
- // multiple Nodes or maps
214
- this.nodeset = seq;
215
- return;
216
- }
217
- }
218
-
219
- throw new Error(`Unexpected result of repeat nodeset: ${seq}`);
208
+ this.nodeset = rawNodeset;
220
209
  }
221
210
 
222
211
  async refresh(force) {
@@ -264,6 +253,7 @@ export class FxRepeat extends foreElementMixin(HTMLElement) {
264
253
 
265
254
  newItem.nodeset = this.nodeset[position - 1];
266
255
  newItem.index = position;
256
+ this.getOwnerForm().someInstanceDataStructureChanged = true;
267
257
  }
268
258
  }
269
259
 
@@ -405,4 +395,6 @@ export class FxRepeat extends foreElementMixin(HTMLElement) {
405
395
  }
406
396
  }
407
397
 
408
- window.customElements.define('fx-repeat', FxRepeat);
398
+ if (!customElements.get('fx-repeat')) {
399
+ window.customElements.define('fx-repeat', FxRepeat);
400
+ }
@@ -73,16 +73,20 @@ export class FxRepeatitem extends foreElementMixin(HTMLElement) {
73
73
  this.inited = true;
74
74
  }
75
75
 
76
+ /*
76
77
  getModelItem() {
77
78
  super.getModelItem();
78
79
  // console.log('modelItem in repeatitem ', this.getModelItem()[this.index]);
79
80
  return this.getModelItem()[this.index];
80
81
  }
82
+ */
81
83
 
82
84
  refresh(force) {
83
- // console.log('refresh repeatitem: ',this.nodeset);
84
- // console.log('refresh repeatitem nodeset: ',this.nodeset);
85
- this.modelItem = this.getModel().getModelItem(this.nodeset);
85
+ this.modelItem = this.getModelItem();
86
+ // ### register ourselves as boundControl
87
+ if (!this.modelItem.boundControls.includes(this)) {
88
+ this.modelItem.boundControls.push(this);
89
+ }
86
90
 
87
91
  if (this.modelItem && !this.modelItem.relevant) {
88
92
  // await Fore.fadeOutElement(this)
@@ -105,4 +109,6 @@ export class FxRepeatitem extends foreElementMixin(HTMLElement) {
105
109
  }
106
110
  }
107
111
 
108
- window.customElements.define('fx-repeatitem', FxRepeatitem);
112
+ if (!customElements.get('fx-repeatitem')) {
113
+ window.customElements.define('fx-repeatitem', FxRepeatitem);
114
+ }
@@ -74,4 +74,6 @@ class FxSwitch extends FxContainer {
74
74
  }
75
75
  }
76
76
 
77
- window.customElements.define('fx-switch', FxSwitch);
77
+ if (!customElements.get('fx-switch')) {
78
+ window.customElements.define('fx-switch', FxSwitch);
79
+ }
@@ -110,4 +110,6 @@ export class FxTrigger extends XfAbstractControl {
110
110
  */
111
111
  }
112
112
 
113
- customElements.define('fx-trigger', FxTrigger);
113
+ if (!customElements.get('fx-trigger')) {
114
+ customElements.define('fx-trigger', FxTrigger);
115
+ }