@jinntec/fore 1.4.0 → 1.6.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 (71) hide show
  1. package/dist/fore-dev.js +2 -36
  2. package/dist/fore-dev.js.map +1 -1
  3. package/dist/fore.js +2 -30
  4. package/dist/fore.js.map +1 -1
  5. package/index.js +13 -0
  6. package/package.json +9 -5
  7. package/resources/fore.css +178 -92
  8. package/src/DependencyNotifyingDomFacade.js +1 -2
  9. package/src/ForeElementMixin.js +31 -5
  10. package/src/actions/abstract-action.js +379 -270
  11. package/src/actions/fx-action.js +0 -1
  12. package/src/actions/fx-append.js +1 -2
  13. package/src/actions/fx-confirm.js +12 -0
  14. package/src/actions/fx-copy.js +0 -1
  15. package/src/actions/fx-delete.js +31 -9
  16. package/src/actions/fx-dispatch.js +19 -5
  17. package/src/actions/fx-hide.js +19 -0
  18. package/src/actions/fx-insert.js +72 -8
  19. package/src/actions/fx-load.js +253 -0
  20. package/src/actions/fx-message.js +22 -7
  21. package/src/actions/fx-refresh.js +11 -1
  22. package/src/actions/fx-reload.js +12 -2
  23. package/src/actions/fx-replace.js +5 -4
  24. package/src/actions/fx-reset.js +48 -0
  25. package/src/actions/fx-return.js +0 -1
  26. package/src/actions/fx-send.js +40 -2
  27. package/src/actions/fx-setfocus.js +25 -7
  28. package/src/actions/fx-setvalue.js +32 -4
  29. package/src/actions/fx-show.js +14 -2
  30. package/src/actions/fx-toggle.js +0 -1
  31. package/src/actions/fx-update.js +9 -0
  32. package/src/events.js +0 -1
  33. package/src/fore.js +119 -63
  34. package/src/functions/common-function.js +28 -0
  35. package/src/fx-bind.js +7 -7
  36. package/src/fx-fore.js +207 -54
  37. package/src/fx-instance.js +55 -17
  38. package/src/fx-model.js +31 -33
  39. package/src/fx-submission.js +50 -47
  40. package/src/getInScopeContext.js +22 -8
  41. package/src/lab/fore-component.js +90 -0
  42. package/src/lab/instance-inspector.js +56 -0
  43. package/src/lab/template.html +16 -0
  44. package/src/relevance.js +27 -1
  45. package/src/tools/adi.js +1056 -0
  46. package/src/tools/fx-action-log.js +662 -0
  47. package/src/tools/fx-devtools.js +444 -0
  48. package/src/tools/fx-dom-inspector.js +609 -0
  49. package/src/tools/fx-json-instance.js +435 -0
  50. package/src/tools/fx-log-item.js +133 -0
  51. package/src/tools/fx-log-settings.js +474 -0
  52. package/src/tools/fx-minimap.js +194 -0
  53. package/src/tools/helpers.js +132 -0
  54. package/src/ui/abstract-control.js +41 -3
  55. package/src/ui/fx-action-log.js +358 -0
  56. package/src/ui/fx-alert.js +0 -1
  57. package/src/ui/fx-container.js +14 -3
  58. package/src/ui/fx-control.js +553 -474
  59. package/src/ui/fx-dialog.js +2 -0
  60. package/src/ui/fx-dom-inspector.js +1255 -0
  61. package/src/ui/fx-group.js +3 -4
  62. package/src/ui/fx-hint.js +2 -4
  63. package/src/ui/fx-inspector.js +5 -6
  64. package/src/ui/fx-items.js +55 -14
  65. package/src/ui/fx-output.js +36 -17
  66. package/src/ui/fx-repeat-attributes.js +409 -0
  67. package/src/ui/fx-repeat.js +12 -6
  68. package/src/ui/fx-switch.js +14 -3
  69. package/src/ui/fx-trigger.js +13 -1
  70. package/src/xpath-evaluation.js +109 -26
  71. package/src/xpath-util.js +55 -1
@@ -10,9 +10,9 @@ import {
10
10
  registerCustomXPathFunction,
11
11
  registerXQueryModule,
12
12
  } from 'fontoxpath';
13
- import {Fore} from './fore.js';
14
13
 
15
14
  import {XPathUtil} from './xpath-util.js';
15
+ import {prettifyXml} from './functions/common-function.js';
16
16
 
17
17
  const XFORMS_NAMESPACE_URI = 'http://www.w3.org/2002/xforms';
18
18
 
@@ -42,12 +42,15 @@ const xhtmlNamespaceResolver = prefix => {
42
42
  }
43
43
  return undefined;
44
44
  };
45
+ export function isInShadow(node) {
46
+ return node.getRootNode() instanceof ShadowRoot;
47
+ }
45
48
 
46
49
  /**
47
50
  * Resolve an id in scope. Behaves like the algorithm defined on https://www.w3.org/community/xformsusers/wiki/XForms_2.0#idref-resolve
48
51
  */
49
52
  export function resolveId(id, sourceObject, nodeName = null) {
50
- let query = 'outermost(ancestor-or-self::fx-fore[1]/(descendant::fx-fore|descendant::*[@id = $id]))[not(self::fx-fore)]';
53
+ const query = 'outermost(ancestor-or-self::fx-fore[1]/(descendant::fx-fore|descendant::*[@id = $id]))[not(self::fx-fore)]';
51
54
  /*
52
55
  if (nodeName === 'fx-instance') {
53
56
  // Instance elements can only be in the `model` element
@@ -60,6 +63,25 @@ export function resolveId(id, sourceObject, nodeName = null) {
60
63
  return document.getElementById(id);
61
64
  }
62
65
  */
66
+ if (sourceObject.nodeType === Node.TEXT_NODE) {
67
+ sourceObject = sourceObject.parentNode;
68
+ }
69
+ if (sourceObject.nodeType === Node.ATTRIBUTE_NODE) {
70
+ sourceObject = sourceObject.ownerElement;
71
+ }
72
+ if(sourceObject.parentNode.nodeType === Node.DOCUMENT_FRAGMENT_NODE){
73
+ sourceObject = sourceObject.parentNode.host;
74
+ }
75
+ const ownerForm = sourceObject.localName === 'fx-fore' ? sourceObject : sourceObject.closest('fx-fore');
76
+ const elementsWithId = ownerForm.querySelectorAll(`[id='${id}']`);
77
+ if (elementsWithId.length === 1) {
78
+ // A single one is found. Assume no ID reuse.
79
+ const targetObject = elementsWithId[0];
80
+ if (nodeName && targetObject.localName !== nodeName) {
81
+ return null;
82
+ }
83
+ return targetObject;
84
+ }
63
85
 
64
86
  const allMatchingTargetObjects = fxEvaluateXPathToNodes(query,
65
87
  sourceObject,
@@ -116,7 +138,7 @@ export function resolveId(id, sourceObject, nodeName = null) {
116
138
  {namespaceResolver: xhtmlNamespaceResolver},
117
139
  )) {
118
140
  const foundTargetObjects = allMatchingTargetObjects.filter(to =>
119
- ancestorRepeatItem.contains(to),
141
+ XPathUtil.contains(ancestorRepeatItem, to),
120
142
  );
121
143
  switch (foundTargetObjects.length) {
122
144
  case 0:
@@ -159,11 +181,16 @@ export function resolveId(id, sourceObject, nodeName = null) {
159
181
  // Make namespace resolving use the `instance` element that is related to here
160
182
  const xmlDocument = new DOMParser().parseFromString('<xml />', 'text/xml');
161
183
 
184
+ const instanceReferencesByQuery = new Map();
185
+
162
186
  function findInstanceReferences(xpathQuery) {
163
187
  if (!xpathQuery.includes('instance')) {
164
188
  // No call to the instance function anyway: short-circuit and prevent AST processing
165
189
  return [];
166
190
  }
191
+ if (instanceReferencesByQuery.has(xpathQuery)) {
192
+ return instanceReferencesByQuery.get(xpathQuery);
193
+ }
167
194
  const xpathAST = parseScript(xpathQuery, {}, xmlDocument);
168
195
  const instanceReferences = fxEvaluateXPathToStrings(
169
196
  `descendant::xqx:functionCallExpr
@@ -180,6 +207,8 @@ function findInstanceReferences(xpathQuery) {
180
207
  },
181
208
  );
182
209
 
210
+ instanceReferencesByQuery.set(xpathQuery, instanceReferences);
211
+
183
212
  return instanceReferences;
184
213
  }
185
214
 
@@ -307,6 +336,7 @@ function functionNameResolver({prefix, localName}, _arity) {
307
336
  case 'current':
308
337
  case 'depends':
309
338
  case 'event':
339
+ case 'fore-attr':
310
340
  case 'index':
311
341
  case 'instance':
312
342
  case 'log':
@@ -350,10 +380,20 @@ function getVariablesInScope(formElement) {
350
380
  const variables = {};
351
381
  if (closestActualFormElement.inScopeVariables) {
352
382
  for (const key of closestActualFormElement.inScopeVariables.keys()) {
353
- const varElement = closestActualFormElement.inScopeVariables.get(key);
354
- if(varElement){
355
- variables[key] = varElement.value;
356
- }
383
+ const varElementOrValue = closestActualFormElement.inScopeVariables.get(key);
384
+ if (!varElementOrValue) {
385
+ continue;
386
+
387
+ }
388
+ if (varElementOrValue.nodeType) {
389
+ // We are a var element, set the value to the value computed there
390
+ variables[key] = varElementOrValue.value;
391
+ // variables[key] = varElementOrValue.inScopeVariables.get(key);
392
+ } else {
393
+ // We are a direct value. This is used to leak in event variables
394
+ variables[key] = varElementOrValue;
395
+ }
396
+
357
397
  }
358
398
  }
359
399
  return variables;
@@ -584,6 +624,12 @@ const currentFunction = (dynamicContext, string) => {
584
624
  return null;
585
625
  };
586
626
 
627
+ const elementFunction = (dynamicContext, string) => {
628
+ const caller = dynamicContext.currentContext.formElement;
629
+ const newElement = document.createElement(string);
630
+ return newElement;
631
+ };
632
+
587
633
  /**
588
634
  * @param id as string
589
635
  * @return instance data for given id serialized to string.
@@ -613,6 +659,13 @@ registerCustomXPathFunction(
613
659
  currentFunction,
614
660
  );
615
661
 
662
+ registerCustomXPathFunction(
663
+ {namespaceURI: XFORMS_NAMESPACE_URI, localName: 'element'},
664
+ ['xs:string'],
665
+ 'item()?',
666
+ elementFunction,
667
+ );
668
+
616
669
  /**
617
670
  * @param id as string
618
671
  * @return instance data for given id serialized to string.
@@ -630,12 +683,30 @@ registerCustomXPathFunction(
630
683
  // return JSON.stringify(instance.getDefaultContext());
631
684
  } else {
632
685
  const def = new XMLSerializer().serializeToString(instance.getDefaultContext());
633
- return Fore.prettifyXml(def);
686
+ return prettifyXml(def);
634
687
  }
635
688
  }
636
689
  return null;
637
690
  },
638
691
  );
692
+ registerCustomXPathFunction(
693
+ {namespaceURI: XFORMS_NAMESPACE_URI, localName: 'fore-attr'},
694
+ ['xs:string?'],
695
+ 'xs:string?',
696
+ (dynamicContext, string) => {
697
+ const {formElement} = dynamicContext.currentContext;
698
+
699
+ let parent = formElement;
700
+ if(formElement.nodeType === Node.TEXT_NODE){
701
+ parent = formElement.parentNode;
702
+ }
703
+ const foreElement = parent.closest('fx-fore');
704
+ if(foreElement.hasAttribute(string)){
705
+ return foreElement.getAttribute(string);
706
+ }
707
+ return null;
708
+ },
709
+ );
639
710
 
640
711
  registerCustomXPathFunction(
641
712
  {namespaceURI: XFORMS_NAMESPACE_URI, localName: 'parse'},
@@ -827,29 +898,41 @@ registerCustomXPathFunction(
827
898
  ['xs:string?'],
828
899
  'item()?',
829
900
  (dynamicContext, arg) => {
830
- if (!arg) return [];
831
-
832
- if (dynamicContext.currentContext.variables) {
833
- const payload = dynamicContext.currentContext.variables[arg];
834
- if (payload.nodeType) {
835
- console.log('got some node as js object');
836
- }
837
- if (payload) {
838
- return dynamicContext.currentContext.variables[arg];
901
+ if (!arg) return null;
902
+
903
+ for (let ancestor = dynamicContext.currentContext.formElement;
904
+ ancestor;
905
+ ancestor = ancestor.parentNode) {
906
+ if (!ancestor.currentEvent) {
907
+ continue;
908
+ }
909
+
910
+ // We have a current event. read the property either from detail, or from the event
911
+ // itself.
912
+ // Check detail for custom events! This is how that is passed along
913
+ if (ancestor.currentEvent.detail && typeof ancestor.currentEvent.detail === 'object' && arg in ancestor.currentEvent.detail) {
914
+ return ancestor.currentEvent.detail[arg];
915
+ }
916
+
917
+ // arg might be `code`, so currentEvent.code should work
918
+ if(arg.includes('.')){
919
+ return _propertyLookup(ancestor.currentEvent, arg);
839
920
  }
840
- }
841
-
842
- if (dynamicContext.currentContext.formElement.inScopeVariables) {
843
- console.log('event()', dynamicContext.currentContext.formElement.inScopeVariables);
844
- console.log('event()', dynamicContext.currentContext.formElement.inScopeVariables.get(arg));
845
- // dynamicContext.currentContext.variables = dynamicContext.currentContext.formElement.inScopeVariables;
846
- return dynamicContext.currentContext.formElement.inScopeVariables.get(arg);
847
- }
921
+ return ancestor.currentEvent[arg] || null;
848
922
 
849
- return [];
923
+ }
924
+ return null;
850
925
  },
851
926
  );
852
927
 
928
+ function _propertyLookup(obj,path){
929
+ const parts = path.split(".");
930
+ if (parts.length==1){
931
+ return obj[parts[0]];
932
+ }
933
+ return _propertyLookup(obj[parts[0]], parts.slice(1).join("."));
934
+ }
935
+
853
936
  // Implement the XForms standard functions here.
854
937
  registerXQueryModule(`
855
938
  module namespace xf="${XFORMS_NAMESPACE_URI}";
package/src/xpath-util.js CHANGED
@@ -2,6 +2,55 @@ import * as fx from 'fontoxpath';
2
2
 
3
3
  export class XPathUtil {
4
4
 
5
+ /**
6
+ * Alternative to `contains` that respects shadowroots
7
+ */
8
+ static contains(ancestor, descendant) {
9
+ while (descendant) {
10
+ if (descendant === ancestor) {
11
+ return true;
12
+ }
13
+
14
+ if (descendant.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {
15
+ // We are passing a shadow root boundary
16
+ descendant = descendant.host;
17
+ } else {
18
+ descendant = descendant.parentNode;
19
+ }
20
+ }
21
+ return false;
22
+ }
23
+
24
+ /**
25
+ * Alternative to `closest` that respects subcontrol boundaries
26
+ */
27
+ static getClosest(querySelector, start) {
28
+ while (start && !start.matches || !start.matches(querySelector)) {
29
+ if (start.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {
30
+ // We are passing a shadow root boundary
31
+ start = start.host;
32
+ continue;
33
+ }
34
+ if (start.nodeType === Node.ATTRIBUTE_NODE) {
35
+ // We are passing an attribute
36
+ start = start.ownerElement;
37
+ continue;
38
+ }
39
+ if (start.nodeType === Node.TEXT_NODE) {
40
+ start = start.parentNode;
41
+ }
42
+ if (start.matches('fx-fore')) {
43
+ // Subform reached. Bail out
44
+ return null;
45
+ }
46
+ start = start.parentNode;
47
+ if (!start) {
48
+ return null;
49
+ }
50
+ }
51
+ return start;
52
+ }
53
+
5
54
  /**
6
55
  * returns next bound element upwards in tree
7
56
  * @param start where to start the search
@@ -14,11 +63,16 @@ export class XPathUtil {
14
63
  return host;
15
64
  }
16
65
  } else */
17
- if (start.parentNode && start.parentNode.nodeType !== Node.DOCUMENT_NODE) {
66
+ if (start.parentNode &&
67
+ (start.parentNode.nodeType !== Node.DOCUMENT_NODE || start.parentNode.nodeType !== Node.DOCUMENT_FRAGMENT_NODE) ) {
68
+ /*
18
69
  if (start.parentNode.hasAttribute('ref')) {
19
70
  return start.parentNode;
20
71
  }
21
72
  return XPathUtil.getParentBindingElement(start.parentNode);
73
+ */
74
+
75
+ return start.parentNode.closest('[ref]');
22
76
  }
23
77
  return null;
24
78
  }