@jinntec/fore 1.0.0-4 → 1.1.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 (66) hide show
  1. package/README.md +26 -38
  2. package/dist/fore-dev.js +43 -0
  3. package/dist/fore-dev.js.map +1 -0
  4. package/dist/fore.js +37 -0
  5. package/dist/fore.js.map +1 -0
  6. package/index.js +4 -0
  7. package/package.json +42 -42
  8. package/resources/fore.css +186 -0
  9. package/resources/toastify.css +87 -0
  10. package/resources/{fore-styles.css → vars.css} +0 -292
  11. package/src/DependencyNotifyingDomFacade.js +10 -16
  12. package/src/ForeElementMixin.js +26 -19
  13. package/src/actions/abstract-action.js +30 -9
  14. package/src/actions/fx-action.js +6 -4
  15. package/src/actions/fx-append.js +8 -17
  16. package/src/actions/fx-confirm.js +5 -3
  17. package/src/actions/fx-delete.js +6 -3
  18. package/src/actions/fx-dispatch.js +9 -8
  19. package/src/actions/fx-hide.js +10 -6
  20. package/src/actions/fx-insert.js +49 -39
  21. package/src/actions/fx-message.js +3 -1
  22. package/src/actions/fx-refresh.js +15 -1
  23. package/src/actions/fx-replace.js +73 -0
  24. package/src/actions/fx-return.js +42 -0
  25. package/src/actions/fx-send.js +3 -1
  26. package/src/actions/fx-setfocus.js +37 -0
  27. package/src/actions/fx-setvalue.js +58 -51
  28. package/src/actions/fx-show.js +12 -4
  29. package/src/actions/fx-toggle.js +15 -10
  30. package/src/actions/fx-update.js +3 -1
  31. package/src/dep_graph.js +4 -2
  32. package/src/drawdown.js +67 -82
  33. package/src/fore.js +158 -12
  34. package/src/functions/fx-function.js +17 -3
  35. package/src/fx-bind.js +42 -202
  36. package/src/fx-fore.js +599 -567
  37. package/src/fx-header.js +3 -1
  38. package/src/fx-instance.js +9 -1
  39. package/src/fx-model.js +59 -23
  40. package/src/fx-submission.js +106 -48
  41. package/src/fx-var.js +7 -4
  42. package/src/getInScopeContext.js +37 -11
  43. package/src/modelitem.js +4 -4
  44. package/src/relevance.js +64 -0
  45. package/src/ui/abstract-control.js +64 -37
  46. package/src/ui/fx-alert.js +7 -1
  47. package/src/ui/fx-case.js +4 -3
  48. package/src/ui/fx-container.js +7 -1
  49. package/src/ui/fx-control.js +309 -34
  50. package/src/ui/fx-dialog.js +54 -40
  51. package/src/ui/fx-group.js +3 -1
  52. package/src/ui/fx-hint.js +4 -1
  53. package/src/ui/fx-inspector.js +120 -17
  54. package/src/ui/fx-items.js +8 -8
  55. package/src/ui/fx-output.js +16 -5
  56. package/src/ui/fx-repeat.js +33 -41
  57. package/src/ui/fx-repeatitem.js +10 -4
  58. package/src/ui/fx-switch.js +5 -3
  59. package/src/ui/fx-trigger.js +3 -1
  60. package/src/xpath-evaluation.js +621 -576
  61. package/src/xpath-util.js +15 -8
  62. package/dist/fore-all.js +0 -140
  63. package/dist/fore-debug.js +0 -140
  64. package/src/.DS_Store +0 -0
  65. package/src/actions/.DS_Store +0 -0
  66. package/src/ui/.DS_Store +0 -0
@@ -1,44 +1,147 @@
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;
39
+ height:100%;
11
40
  }
12
41
  pre{
13
42
  background:var(--inspector-pre-bg);
14
43
  color:var(--inspector-color);
15
- max-height:var(--inspector-instance-height,300px);
16
44
  overflow:scroll;
45
+ padding:0.2rem;
46
+ }
47
+ .handle{
48
+ display:block;
49
+ height:100%;
50
+ width:var(--inspector-handle-width);
51
+ background:var(--inspector-handle-bg);
52
+ opacity:0.7;
53
+ position:absolute;
54
+ left:0;
55
+ color:white;
56
+ cursor:pointer;
57
+ }
58
+ .handle:hover{
59
+ opacity:1;
60
+ }
61
+ .handle::before{
62
+ content: 'Data Inspector';
63
+ white-space: nowrap;
64
+ transform: rotate(-90deg);
65
+ display: inline-block;
66
+ position: absolute;
67
+ left: -85px;
68
+ width: 200px;
69
+ top: 40px;
70
+ }
71
+ summary{
72
+ cursor:pointer;
17
73
  }
18
74
  `;
19
75
 
20
- const instances = Array.from(document.querySelectorAll('fx-instance'));
21
- this.innerHTML = `
76
+ const fore = this.closest('fx-fore');
77
+
78
+ // fore.addEventListener('ready', (e) => {
79
+ this.render(style);
80
+ // });
81
+ fore.addEventListener('refresh-done', () => {
82
+ this.update();
83
+ });
84
+ }
85
+
86
+ update() {
87
+ // console.log('update');
88
+ const pre = this.shadowRoot.querySelectorAll('pre');
89
+ // console.log('pre', pre);
90
+ const fore = this.closest('fx-fore');
91
+
92
+ Array.from(pre).forEach(element => {
93
+ const inst = fore.getModel().getInstance(element.getAttribute('id'));
94
+ if (inst.type === 'xml') {
95
+ element.innerText = this.serializeDOM(inst.instanceData);
96
+ }
97
+ if (inst.type === 'json') {
98
+ element.innerText = JSON.stringify(inst.instanceData, undefined, 2);
99
+ }
100
+ });
101
+ }
102
+
103
+ render(style) {
104
+ const fore = this.closest('fx-fore');
105
+ const instances = Array.from(fore.querySelectorAll('fx-instance'));
106
+ this.shadowRoot.innerHTML = `
22
107
  <style>
23
108
  ${style}
24
109
  </style>
110
+ <div class="main">
25
111
  <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('')}
112
+ <span class="handle"></span>
113
+ ${instances.map(
114
+ (instance, index) => `
115
+ <details>
116
+ <summary>${instance.id}</summary>
117
+ <pre id="${instance.id}"></pre>
118
+ </details>
119
+ `,
120
+ )}
121
+ </div>
36
122
  `;
37
123
 
38
- this.addEventListener('slotchange', e => {
39
- console.log('slotchange ', e);
124
+ /*
125
+ const handle = this.shadowRoot.querySelector('.handle');
126
+ handle.addEventListener('click', e => {
127
+ // console.log('toggling');
128
+ const { target } = e;
129
+ if (this.hasAttribute('open')) {
130
+ this.removeAttribute('open');
131
+ } else {
132
+ this.setAttribute('open', 'open');
133
+ }
40
134
  });
135
+ */
136
+ }
137
+
138
+ serializeDOM(data) {
139
+ // console.log('serializeDOM', data);
140
+ const ser = new XMLSerializer().serializeToString(data);
141
+ return Fore.prettifyXml(ser);
41
142
  }
42
143
  }
43
144
 
44
- customElements.define('fx-inspector', FxInspector);
145
+ if (!customElements.get('fx-inspector')) {
146
+ customElements.define('fx-inspector', FxInspector);
147
+ }
@@ -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';
@@ -7,6 +8,7 @@ import getInScopeContext from '../getInScopeContext.js';
7
8
  * todo: review placing of value. should probably work with value attribute and not allow slotted content.
8
9
  */
9
10
  export class FxOutput extends XfAbstractControl {
11
+ /*
10
12
  static get properties() {
11
13
  return {
12
14
  ...super.properties,
@@ -16,10 +18,13 @@ export class FxOutput extends XfAbstractControl {
16
18
  };
17
19
  }
18
20
 
21
+ */
19
22
  constructor() {
20
23
  super();
21
24
  this.attachShadow({ mode: 'open' });
22
25
  this.valueAttr = this.hasAttribute('value') ? this.getAttribute('value') : null;
26
+ // Outputs are always readonly!
27
+ this.readonly = true;
23
28
  }
24
29
 
25
30
  connectedCallback() {
@@ -85,13 +90,13 @@ export class FxOutput extends XfAbstractControl {
85
90
  try {
86
91
  const inscopeContext = getInScopeContext(this, this.valueAttr);
87
92
  if (this.hasAttribute('html')) {
88
- return evaluateXPath(this.valueAttr, inscopeContext, this);
93
+ return evaluateXPath(this.valueAttr, inscopeContext, this)[0];
89
94
  }
90
95
 
91
96
  return evaluateXPathToStrings(this.valueAttr, inscopeContext, this)[0];
92
97
  } catch (error) {
93
98
  console.error(error);
94
- this.dispatch('error', { message: error });
99
+ Fore.dispatch(this, 'error', { message: error });
95
100
  }
96
101
  return null;
97
102
  }
@@ -101,6 +106,11 @@ export class FxOutput extends XfAbstractControl {
101
106
  return valueWrapper;
102
107
  }
103
108
 
109
+ handleReadonly() {
110
+ // An output is always read-only
111
+ this.setAttribute('readonly', 'readonly');
112
+ }
113
+
104
114
  async updateWidgetValue() {
105
115
  console.log('updateWidgetValue');
106
116
  const valueWrapper = this.shadowRoot.getElementById('value');
@@ -150,9 +160,10 @@ export class FxOutput extends XfAbstractControl {
150
160
  }
151
161
 
152
162
  isReadonly() {
153
- this.readonly = true;
154
- return this.readonly;
163
+ return true;
155
164
  }
156
165
  }
157
166
 
158
- customElements.define('fx-output', FxOutput);
167
+ if (!customElements.get('fx-output')) {
168
+ customElements.define('fx-output', FxOutput);
169
+ }
@@ -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
+ }
@@ -39,7 +39,7 @@ class FxSwitch extends FxContainer {
39
39
  refresh() {
40
40
  super.refresh();
41
41
  console.log('refresh on switch ');
42
- const cases = this.querySelectorAll('fx-case');
42
+ const cases = this.querySelectorAll(':scope > fx-case');
43
43
  if (this.isBound()) {
44
44
  Array.from(cases).forEach(caseElem => {
45
45
  const name = caseElem.getAttribute('name');
@@ -50,7 +50,7 @@ class FxSwitch extends FxContainer {
50
50
  }
51
51
  });
52
52
  } else {
53
- const selected = this.querySelector('.selected-case');
53
+ const selected = this.querySelector(':scope > .selected-case');
54
54
  if (!selected) {
55
55
  cases[0].classList.add('selected-case');
56
56
  }
@@ -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
+ }