@jinntec/fore 1.0.0-1 → 1.0.0-2

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.
@@ -23,12 +23,6 @@ export const foreElementMixin = superclass =>
23
23
  model: {
24
24
  type: Object,
25
25
  },
26
- /**
27
- * XPath binding expression pointing to bound node
28
- */
29
- ref: {
30
- type: String,
31
- },
32
26
  /**
33
27
  * The modelitem object associated to the bound node holding the evaluated state.
34
28
  */
@@ -41,6 +35,12 @@ export const foreElementMixin = superclass =>
41
35
  nodeset: {
42
36
  type: Object,
43
37
  },
38
+ /**
39
+ * XPath binding expression pointing to bound node
40
+ */
41
+ ref: {
42
+ type: String,
43
+ },
44
44
  };
45
45
  }
46
46
 
@@ -98,26 +98,26 @@ export const foreElementMixin = superclass =>
98
98
  if (this.ref === '') {
99
99
  this.nodeset = inscopeContext;
100
100
  } else if (Array.isArray(inscopeContext)) {
101
+ /*
101
102
  inscopeContext.forEach(n => {
102
103
  if (XPathUtil.isSelfReference(this.ref)) {
103
104
  this.nodeset = inscopeContext;
104
105
  } else {
105
- const localResult = evaluateXPathToFirstNode(this.ref, n, null);
106
+ const localResult = evaluateXPathToFirstNode(this.ref, n, this);
106
107
  // console.log('local result: ', localResult);
107
108
  this.nodeset.push(localResult);
108
109
  }
109
110
  });
111
+ */
112
+ this.nodeset = evaluateXPathToFirstNode(this.ref, inscopeContext[0], this);
110
113
  } else {
111
114
  // this.nodeset = fx.evaluateXPathToFirstNode(this.ref, inscopeContext, null, {namespaceResolver: this.namespaceResolver});
112
-
113
- // todo: code below fails - why?
114
- const formElement = this.getOwnerForm();
115
- if (inscopeContext.nodeType) {
116
- this.nodeset = evaluateXPathToFirstNode(this.ref, inscopeContext, formElement);
115
+ const { nodeType } = inscopeContext;
116
+ if (nodeType) {
117
+ this.nodeset = evaluateXPathToFirstNode(this.ref, inscopeContext, this);
117
118
  } else {
118
- this.nodeset = evaluateXPath(this.ref, inscopeContext, formElement);
119
+ this.nodeset = evaluateXPath(this.ref, inscopeContext, this);
119
120
  }
120
- // this.nodeset = evaluateXPath(this.ref,inscopeContext,formElement)
121
121
  }
122
122
  // console.log('UiElement evaluated to nodeset: ', this.nodeset);
123
123
  }
@@ -226,7 +226,7 @@ export const foreElementMixin = superclass =>
226
226
  bubbles: true,
227
227
  detail,
228
228
  });
229
- console.log('firing', event);
229
+ // console.log('firing', event);
230
230
  this.dispatchEvent(event);
231
231
  }
232
232
  };
@@ -81,7 +81,9 @@ export class AbstractAction extends foreElementMixin(HTMLElement) {
81
81
 
82
82
  this.target = this.getAttribute('target');
83
83
  if (this.target) {
84
- if (this.target === '#document') {
84
+ if (this.target === '#window') {
85
+ window.addEventListener(this.event, e => this.execute(e));
86
+ } else if (this.target === '#document') {
85
87
  document.addEventListener(this.event, e => this.execute(e));
86
88
  } else {
87
89
  this.targetElement = document.getElementById(this.target);
@@ -190,15 +192,14 @@ export class AbstractAction extends foreElementMixin(HTMLElement) {
190
192
  const model = this.getModel();
191
193
  model.recalculate();
192
194
  model.revalidate();
193
- model.parentNode.refresh();
194
- this._dispatchActionPerformed();
195
+ model.parentNode.refresh(true);
196
+ this.dispatchActionPerformed();
195
197
  }
196
198
  }
197
199
 
198
200
  /**
199
- * @private
200
201
  */
201
- _dispatchActionPerformed() {
202
+ dispatchActionPerformed() {
202
203
  console.log('action-performed ', this);
203
204
  this.dispatchEvent(
204
205
  new CustomEvent('action-performed', { composed: true, bubbles: true, detail: {} }),
@@ -46,6 +46,7 @@ export class FxAction extends AbstractAction {
46
46
  // action.perform();
47
47
  action.execute();
48
48
  });
49
+ this.dispatchActionPerformed();
49
50
  // this.needsUpdate = false;
50
51
  }
51
52
  }
@@ -1,5 +1,6 @@
1
1
  import { AbstractAction } from './abstract-action.js';
2
- import { evaluateXPath } from '../xpath-evaluation.js';
2
+ import { evaluateXPath, resolveId } from '../xpath-evaluation.js';
3
+ import { XPathUtil } from '../xpath-util.js';
3
4
 
4
5
  /**
5
6
  * `fx-dispatch`
@@ -89,7 +90,14 @@ export class FxDispatch extends AbstractAction {
89
90
 
90
91
  // ### when targetid is given dispatch to that if present (throw an error if not) - otherwise dispatch to document
91
92
  if (this.targetid) {
92
- const target = document.getElementById(this.targetid);
93
+ // const target = document.getElementById(this.targetid);
94
+ let target;
95
+ if (XPathUtil.isRepeated(this)) {
96
+ target = resolveId(this.targetid, this.parentNode, null);
97
+ } else {
98
+ target = document.getElementById(this.targetid);
99
+ }
100
+ console.log('target', target);
93
101
  if (!target) {
94
102
  throw new Error(`targetid ${this.targetid} does not exist in document`);
95
103
  }
@@ -77,7 +77,7 @@ export class FxInsert extends AbstractAction {
77
77
  }
78
78
 
79
79
  perform() {
80
- super.perform();
80
+ // super.perform();
81
81
 
82
82
  /*
83
83
  todo: !!! calling super here does not correctly give the nodeset - it's likely still a bug in ForeElementMixin !!!
@@ -90,7 +90,7 @@ export class FxInsert extends AbstractAction {
90
90
 
91
91
  // @ts-ignore
92
92
  const targetSequence = evaluateXPathToNodes(this.ref, inscope, this.getOwnerForm());
93
- console.log('insert nodeset ', targetSequence);
93
+ // console.log('insert nodeset ', targetSequence);
94
94
 
95
95
  // ### obtaining originSequence
96
96
  /*
@@ -117,8 +117,8 @@ export class FxInsert extends AbstractAction {
117
117
  let insertLocationNode;
118
118
  let index;
119
119
 
120
- const idx = this._getInsertIndex(inscope, targetSequence);
121
- console.log('insert index', idx);
120
+ // const idx = this._getInsertIndex(inscope, targetSequence);
121
+ // console.log('insert index', idx);
122
122
 
123
123
  // if the targetSequence is empty but we got an originSequence use inscope as context and ignore 'at' and 'position'
124
124
  if (targetSequence.length === 0) {
@@ -151,7 +151,7 @@ export class FxInsert extends AbstractAction {
151
151
 
152
152
  insertLocationNode = targetSequence;
153
153
  const context = evaluateXPath('count(preceding::*)', targetSequence, this.getOwnerForm());
154
- console.log('context', context);
154
+ // console.log('context', context);
155
155
  index = context + 1;
156
156
  // index = targetSequence.findIndex(insertLocationNode);
157
157
  }
@@ -171,10 +171,10 @@ export class FxInsert extends AbstractAction {
171
171
 
172
172
  // console.log('insert context item ', insertLocationNode);
173
173
  // console.log('parent ', insertLocationNode.parentNode);
174
- console.log('instance ', this.getModel().getDefaultContext());
174
+ // console.log('instance ', this.getModel().getDefaultContext());
175
175
 
176
- console.log('<<<<<<< at', this.at);
177
- console.log('<<<<<<< index', index);
176
+ // console.log('<<<<<<< at', this.at);
177
+ // console.log('<<<<<<< index', index);
178
178
  // todo: this actually should dispatch to respective instance
179
179
  document.dispatchEvent(
180
180
  new CustomEvent('insert', {
@@ -17,7 +17,7 @@ class FxSend extends AbstractAction {
17
17
  connectedCallback() {
18
18
  // eslint-disable-next-line wc/guard-super-call
19
19
  super.connectedCallback();
20
- console.log('connectedCallback ', this);
20
+ // console.log('connectedCallback ', this);
21
21
  this.submission = this.getAttribute('submission');
22
22
  }
23
23
 
@@ -62,10 +62,8 @@ export default class FxSetvalue extends AbstractAction {
62
62
 
63
63
  if (item.value !== newVal) {
64
64
  item.value = newVal;
65
- item.changed = true;
66
-
65
+ this.getModel().changed.push(modelItem);
67
66
  this.needsUpdate = true;
68
-
69
67
  console.log('setvalue[2] ', item, newVal);
70
68
  }
71
69
  }
package/src/dep_graph.js CHANGED
@@ -320,6 +320,15 @@ DepGraph.prototype = {
320
320
  }
321
321
  throw new Error(`Node does not exist: ${node}`);
322
322
  },
323
+
324
+ /**
325
+ * Get an array of nodes that have no dependants (i.e. nothing depends on them).
326
+ */
327
+ entryNodes() {
328
+ const self = this;
329
+ return Object.keys(this.nodes).filter(node => self.incomingEdges[node].length === 0);
330
+ },
331
+
323
332
  /**
324
333
  * Construct the overall processing order for the dependency graph.
325
334
  *
@@ -0,0 +1,172 @@
1
+ /**
2
+ * drawdown.js
3
+ * (c) Adam Leggett
4
+ */
5
+
6
+ function markdown(src) {
7
+ var rx_lt = /</g;
8
+ var rx_gt = />/g;
9
+ var rx_space = /\t|\r|\uf8ff/g;
10
+ var rx_escape = /\\([\\\|`*_{}\[\]()#+\-~])/g;
11
+ var rx_hr = /^([*\-=_] *){3,}$/gm;
12
+ var rx_blockquote = /\n *&gt; *([^]*?)(?=(\n|$){2})/g;
13
+ var rx_list = /\n( *)(?:[*\-+]|((\d+)|([a-z])|[A-Z])[.)]) +([^]*?)(?=(\n|$){2})/g;
14
+ var rx_listjoin = /<\/(ol|ul)>\n\n<\1>/g;
15
+ var rx_highlight = /(^|[^A-Za-z\d\\])(([*_])|(~)|(\^)|(--)|(\+\+)|`)(\2?)([^<]*?)\2\8(?!\2)(?=\W|_|$)/g;
16
+ var rx_code = /\n((```|~~~).*\n?([^]*?)\n?\2|(( .*?\n)+))/g;
17
+ var rx_link = /((!?)\[(.*?)\]\((.*?)( ".*")?\)|\\([\\`*_{}\[\]()#+\-.!~]))/g;
18
+ var rx_table = /\n(( *\|.*?\| *\n)+)/g;
19
+ var rx_thead = /^.*\n( *\|( *\:?-+\:?-+\:? *\|)* *\n|)/;
20
+ var rx_row = /.*\n/g;
21
+ var rx_cell = /\||(.*?[^\\])\|/g;
22
+ var rx_heading = /(?=^|>|\n)([>\s]*?)(#{1,6}) (.*?)( #*)? *(?=\n|$)/g;
23
+ var rx_para = /(?=^|>|\n)\s*\n+([^<]+?)\n+\s*(?=\n|<|$)/g;
24
+ var rx_stash = /-\d+\uf8ff/g;
25
+
26
+ function replace(rex, fn) {
27
+ src = src.replace(rex, fn);
28
+ }
29
+
30
+ function element(tag, content) {
31
+ return '<' + tag + '>' + content + '</' + tag + '>';
32
+ }
33
+
34
+ function blockquote(src) {
35
+ return src.replace(rx_blockquote, function(all, content) {
36
+ return element('blockquote', blockquote(highlight(content.replace(/^ *&gt; */gm, ''))));
37
+ });
38
+ }
39
+
40
+ function list(src) {
41
+ return src.replace(rx_list, function(all, ind, ol, num, low, content) {
42
+ var entry = element(
43
+ 'li',
44
+ highlight(
45
+ content
46
+ .split(RegExp('\n ?' + ind + '(?:(?:\\d+|[a-zA-Z])[.)]|[*\\-+]) +', 'g'))
47
+ .map(list)
48
+ .join('</li><li>'),
49
+ ),
50
+ );
51
+
52
+ return (
53
+ '\n' +
54
+ (ol
55
+ ? '<ol start="' +
56
+ (num
57
+ ? ol + '">'
58
+ : parseInt(ol, 36) -
59
+ 9 +
60
+ '" style="list-style-type:' +
61
+ (low ? 'low' : 'upp') +
62
+ 'er-alpha">') +
63
+ entry +
64
+ '</ol>'
65
+ : element('ul', entry))
66
+ );
67
+ });
68
+ }
69
+
70
+ function highlight(src) {
71
+ return src.replace(rx_highlight, function(all, _, p1, emp, sub, sup, small, big, p2, content) {
72
+ return (
73
+ _ +
74
+ element(
75
+ emp
76
+ ? p2
77
+ ? 'strong'
78
+ : 'em'
79
+ : sub
80
+ ? p2
81
+ ? 's'
82
+ : 'sub'
83
+ : sup
84
+ ? 'sup'
85
+ : small
86
+ ? 'small'
87
+ : big
88
+ ? 'big'
89
+ : 'code',
90
+ highlight(content),
91
+ )
92
+ );
93
+ });
94
+ }
95
+
96
+ function unesc(str) {
97
+ return str.replace(rx_escape, '$1');
98
+ }
99
+
100
+ var stash = [];
101
+ var si = 0;
102
+
103
+ src = '\n' + src + '\n';
104
+
105
+ replace(rx_lt, '&lt;');
106
+ replace(rx_gt, '&gt;');
107
+ replace(rx_space, ' ');
108
+
109
+ // blockquote
110
+ src = blockquote(src);
111
+
112
+ // horizontal rule
113
+ replace(rx_hr, '<hr/>');
114
+
115
+ // list
116
+ src = list(src);
117
+ replace(rx_listjoin, '');
118
+
119
+ // code
120
+ replace(rx_code, function(all, p1, p2, p3, p4) {
121
+ stash[--si] = element('pre', element('code', p3 || p4.replace(/^ /gm, '')));
122
+ return si + '\uf8ff';
123
+ });
124
+
125
+ // link or image
126
+ replace(rx_link, function(all, p1, p2, p3, p4, p5, p6) {
127
+ stash[--si] = p4
128
+ ? p2
129
+ ? '<img src="' + p4 + '" alt="' + p3 + '"/>'
130
+ : '<a href="' + p4 + '">' + unesc(highlight(p3)) + '</a>'
131
+ : p6;
132
+ return si + '\uf8ff';
133
+ });
134
+
135
+ // table
136
+ replace(rx_table, function(all, table) {
137
+ var sep = table.match(rx_thead)[1];
138
+ return (
139
+ '\n' +
140
+ element(
141
+ 'table',
142
+ table.replace(rx_row, function(row, ri) {
143
+ return row == sep
144
+ ? ''
145
+ : element(
146
+ 'tr',
147
+ row.replace(rx_cell, function(all, cell, ci) {
148
+ return ci ? element(sep && !ri ? 'th' : 'td', unesc(highlight(cell || ''))) : '';
149
+ }),
150
+ );
151
+ }),
152
+ )
153
+ );
154
+ });
155
+
156
+ // heading
157
+ replace(rx_heading, function(all, _, p1, p2) {
158
+ return _ + element('h' + p1.length, unesc(highlight(p2)));
159
+ });
160
+
161
+ // paragraph
162
+ replace(rx_para, function(all, content) {
163
+ return element('p', unesc(highlight(content)));
164
+ });
165
+
166
+ // stash
167
+ replace(rx_stash, function(all) {
168
+ return stash[parseInt(all)];
169
+ });
170
+
171
+ return src.trim();
172
+ }
package/src/fore.js CHANGED
@@ -34,6 +34,21 @@ export class Fore {
34
34
  ];
35
35
  }
36
36
 
37
+ static createUUID() {
38
+ // http://www.ietf.org/rfc/rfc4122.txt
39
+ const s = [];
40
+ const hexDigits = '0123456789abcdef';
41
+ for (let i = 0; i < 36; i += 1) {
42
+ s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
43
+ }
44
+ s[14] = '4'; // bits 12-15 of the time_hi_and_version field to 0010
45
+ s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1); // bits 6-7 of the clock_seq_hi_and_reserved to 01
46
+ s[8] = s[13] = s[18] = s[23] = '-';
47
+
48
+ const uuid = s.join('');
49
+ return uuid;
50
+ }
51
+
37
52
  static get XFORMS_NAMESPACE_URI() {
38
53
  // todo: should be centralized somewhere as constant. Exists in several? places
39
54
  return 'http://www.w3.org/2002/xforms';
@@ -55,7 +70,7 @@ export class Fore {
55
70
  'FX-GROUP',
56
71
  'FX-HINT',
57
72
  'FX-INPUT',
58
- 'FX-ITEMSET',
73
+ 'FX-ITEMS',
59
74
  'FX-LABEL',
60
75
  'FX-OUTPUT',
61
76
  'FX-RANGE',
@@ -79,15 +94,40 @@ export class Fore {
79
94
  return Fore.UI_ELEMENTS.includes(elementName);
80
95
  }
81
96
 
82
- static async refreshChildren(startElement) {
97
+ /**
98
+ * recursively refreshes all UI Elements.
99
+ *
100
+ * todo: this could probably made more efficient with significant impact on rendering perf
101
+ *
102
+ * @param startElement
103
+ * @param force
104
+ * @returns {Promise<unknown>}
105
+ */
106
+ static async refreshChildren(startElement, force) {
83
107
  const refreshed = new Promise(resolve => {
108
+ /*
109
+ if there's an 'refresh-on-view' attribute the element wants to be handled by
110
+ handleIntersect function that calls the refresh of the respective element and
111
+ not the global one.
112
+ */
113
+ // if(!force && startElement.hasAttribute('refresh-on-view')) return;
114
+
115
+ /* ### attempt with querySelectorAll is even slower than iterating recursively
116
+
117
+ const children = startElement.querySelectorAll('[ref]');
118
+ Array.from(children).forEach(uiElement => {
119
+ if (Fore.isUiElement(uiElement.nodeName) && typeof uiElement.refresh === 'function') {
120
+ uiElement.refresh();
121
+ }
122
+ });
123
+ */
84
124
  const { children } = startElement;
85
125
  if (children) {
86
126
  Array.from(children).forEach(element => {
87
127
  if (Fore.isUiElement(element.nodeName) && typeof element.refresh === 'function') {
88
128
  element.refresh();
89
129
  } else if (element.nodeName.toUpperCase() !== 'FX-MODEL') {
90
- Fore.refreshChildren(element);
130
+ Fore.refreshChildren(element, force);
91
131
  }
92
132
  });
93
133
  }
@@ -167,6 +207,16 @@ export class Fore {
167
207
  return fadeOut();
168
208
  }
169
209
 
210
+ static dispatch(target, eventName, detail) {
211
+ const event = new CustomEvent(eventName, {
212
+ composed: true,
213
+ bubbles: true,
214
+ detail,
215
+ });
216
+ console.log('firing', event);
217
+ target.dispatchEvent(event);
218
+ }
219
+
170
220
  /**
171
221
  * clear all text nodes and attribute values to get a 'clean' template.
172
222
  * @param n
package/src/fx-bind.js CHANGED
@@ -182,12 +182,11 @@ export class FxBind extends foreElementMixin(HTMLElement) {
182
182
  if (this.bindType === 'xml') {
183
183
  this.nodeset.forEach(node => {
184
184
  const path = XPathUtil.getPath(node);
185
+ this.model.mainGraph.addNode(path, node);
185
186
 
186
187
  if (this.calculate) {
187
188
  this.model.mainGraph.addNode(`${path}:calculate`, node);
188
189
  // Calculated values are a dependency of the model item.
189
- // Make `model1` depend on `model1:calculate`
190
- this.model.mainGraph.addNode(path, node);
191
190
  this.model.mainGraph.addDependency(path, `${path}:calculate`);
192
191
  }
193
192
 
@@ -196,11 +195,13 @@ export class FxBind extends foreElementMixin(HTMLElement) {
196
195
  this._addDependencies(calculateRefs, node, path, 'calculate');
197
196
  }
198
197
 
199
- const readonlyRefs = this._getReferencesForProperty(this.readonly, node);
200
- if (readonlyRefs.length !== 0) {
201
- this._addDependencies(readonlyRefs, node, path, 'readonly');
202
- } else if (this.readonly) {
203
- this.model.mainGraph.addNode(`${path}:readonly`, node);
198
+ if (!this.calculate) {
199
+ const readonlyRefs = this._getReferencesForProperty(this.readonly, node);
200
+ if (readonlyRefs.length !== 0) {
201
+ this._addDependencies(readonlyRefs, node, path, 'readonly');
202
+ } else if (this.readonly) {
203
+ this.model.mainGraph.addNode(`${path}:readonly`, node);
204
+ }
204
205
  }
205
206
 
206
207
  // const requiredRefs = this.requiredReferences;