@supersoniks/concorde 1.0.5 → 1.0.8

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 (175) hide show
  1. package/README.md +16 -8
  2. package/cli.js +69 -0
  3. package/core/components/functional/date/date.d.ts +34 -0
  4. package/core/components/functional/date/date.js +187 -0
  5. package/core/components/functional/example/example.d.ts +7 -0
  6. package/core/components/functional/example/example.js +25 -0
  7. package/core/components/functional/fetch/fetch.d.ts +49 -0
  8. package/core/components/functional/fetch/fetch.js +38 -0
  9. package/core/components/functional/functional.d.ts +11 -0
  10. package/core/components/functional/functional.js +11 -0
  11. package/core/components/functional/if/if.d.ts +12 -0
  12. package/core/components/functional/if/if.js +43 -0
  13. package/core/components/functional/list/list.d.ts +67 -0
  14. package/core/components/functional/list/list.js +132 -0
  15. package/core/components/functional/queue/queue.d.ts +42 -0
  16. package/core/components/functional/queue/queue.js +184 -0
  17. package/core/components/functional/router/redirect.d.ts +18 -0
  18. package/core/components/functional/router/redirect.js +57 -0
  19. package/core/components/functional/router/router.d.ts +26 -0
  20. package/core/components/functional/router/router.js +104 -0
  21. package/core/components/functional/states/states.d.ts +28 -0
  22. package/core/components/functional/states/states.js +139 -0
  23. package/core/components/functional/submit/submit.d.ts +24 -0
  24. package/core/components/functional/submit/submit.js +108 -0
  25. package/{types/core/components → core/components/functional/subscriber}/subscriber.d.ts +5 -1
  26. package/core/components/functional/subscriber/subscriber.js +30 -0
  27. package/core/components/ui/alert/alert.d.ts +20 -0
  28. package/core/components/ui/alert/alert.js +150 -0
  29. package/core/components/ui/badge/badge.d.ts +24 -0
  30. package/core/components/ui/badge/badge.js +177 -0
  31. package/core/components/ui/button/button.d.ts +125 -0
  32. package/core/components/ui/button/button.js +558 -0
  33. package/core/components/ui/divider/divider.d.ts +11 -0
  34. package/core/components/ui/divider/divider.js +144 -0
  35. package/core/components/ui/form/checkbox/checkbox.d.ts +120 -0
  36. package/core/components/ui/form/checkbox/checkbox.js +203 -0
  37. package/core/components/ui/form/css/form-control.d.ts +1 -0
  38. package/core/components/ui/form/css/form-control.js +219 -0
  39. package/core/components/ui/form/fieldset/fieldset.d.ts +15 -0
  40. package/core/components/ui/form/fieldset/fieldset.js +70 -0
  41. package/core/components/ui/form/fieldset/legend.d.ts +11 -0
  42. package/core/components/ui/form/fieldset/legend.js +92 -0
  43. package/core/components/ui/form/form-layout/form-actions.d.ts +6 -0
  44. package/core/components/ui/form/form-layout/form-actions.js +23 -0
  45. package/core/components/ui/form/form-layout/form-layout.d.ts +9 -0
  46. package/core/components/ui/form/form-layout/form-layout.js +58 -0
  47. package/core/components/ui/form/input/input.d.ts +84 -0
  48. package/core/components/ui/form/input/input.js +180 -0
  49. package/core/components/ui/form/radio/radio.d.ts +12 -0
  50. package/core/components/ui/form/radio/radio.js +55 -0
  51. package/core/components/ui/form/select/select.d.ts +39 -0
  52. package/core/components/ui/form/select/select.js +220 -0
  53. package/core/components/ui/form/textarea/textarea.d.ts +69 -0
  54. package/core/components/ui/form/textarea/textarea.js +150 -0
  55. package/core/components/ui/group/group.d.ts +6 -0
  56. package/core/components/ui/group/group.js +57 -0
  57. package/core/components/ui/icon/icon.d.ts +17 -0
  58. package/core/components/ui/icon/icon.js +93 -0
  59. package/core/components/ui/icon/icons.d.ts +13 -0
  60. package/core/components/ui/icon/icons.js +25 -0
  61. package/core/components/ui/icon/icons.json +1 -0
  62. package/core/components/ui/image/image.d.ts +14 -0
  63. package/core/components/ui/image/image.js +152 -0
  64. package/core/components/ui/link/link.d.ts +16 -0
  65. package/core/components/ui/link/link.js +70 -0
  66. package/core/components/ui/loader/loader.d.ts +20 -0
  67. package/core/components/ui/loader/loader.js +94 -0
  68. package/{types → core}/components/ui/loader/styles/fixed.d.ts +0 -0
  69. package/core/components/ui/loader/styles/fixed.js +57 -0
  70. package/{types → core}/components/ui/loader/styles/inline.d.ts +0 -0
  71. package/core/components/ui/loader/styles/inline.js +71 -0
  72. package/core/components/ui/menu/menu-item.d.ts +5 -0
  73. package/core/components/ui/menu/menu-item.js +37 -0
  74. package/core/components/ui/menu/menu.d.ts +26 -0
  75. package/core/components/ui/menu/menu.js +125 -0
  76. package/core/components/ui/modal/modal-actions.d.ts +7 -0
  77. package/core/components/ui/modal/modal-actions.js +46 -0
  78. package/core/components/ui/modal/modal-close.d.ts +6 -0
  79. package/core/components/ui/modal/modal-close.js +38 -0
  80. package/core/components/ui/modal/modal-content.d.ts +5 -0
  81. package/core/components/ui/modal/modal-content.js +29 -0
  82. package/core/components/ui/modal/modal-subtitle.d.ts +5 -0
  83. package/core/components/ui/modal/modal-subtitle.js +33 -0
  84. package/core/components/ui/modal/modal-title.d.ts +5 -0
  85. package/core/components/ui/modal/modal-title.js +33 -0
  86. package/core/components/ui/modal/modal.d.ts +36 -0
  87. package/core/components/ui/modal/modal.js +325 -0
  88. package/core/components/ui/pop/pop.d.ts +28 -0
  89. package/core/components/ui/pop/pop.js +223 -0
  90. package/core/components/ui/tabs/tab.d.ts +6 -0
  91. package/core/components/ui/tabs/tab.js +46 -0
  92. package/core/components/ui/tabs/tabs.d.ts +14 -0
  93. package/core/components/ui/tabs/tabs.js +127 -0
  94. package/core/components/ui/taxonomy/taxonomy.d.ts +41 -0
  95. package/core/components/ui/taxonomy/taxonomy.js +113 -0
  96. package/core/components/ui/theme/css/tailwind.css +3 -0
  97. package/core/components/ui/theme/css/tailwind.d.ts +2 -0
  98. package/core/components/ui/theme/theme-collection/core-variables.d.ts +1 -0
  99. package/core/components/ui/theme/theme-collection/core-variables.js +50 -0
  100. package/{types/components → core/components/ui}/theme/theme-collection/dark.d.ts +0 -0
  101. package/core/components/ui/theme/theme-collection/dark.js +41 -0
  102. package/{types/components → core/components/ui}/theme/theme-collection/light.d.ts +0 -0
  103. package/core/components/ui/theme/theme-collection/light.js +35 -0
  104. package/core/components/ui/theme/theme.d.ts +11 -0
  105. package/core/components/ui/theme/theme.js +105 -0
  106. package/core/components/ui/toast/message-subscriber.d.ts +17 -0
  107. package/core/components/ui/toast/message-subscriber.js +85 -0
  108. package/{types → core}/components/ui/toast/toast.d.ts +10 -8
  109. package/core/components/ui/toast/toast.js +260 -0
  110. package/core/components/ui/tooltip/tooltip.d.ts +7 -0
  111. package/core/components/ui/tooltip/tooltip.js +68 -0
  112. package/core/components/ui/ui.d.ts +27 -0
  113. package/core/components/ui/ui.js +34 -0
  114. package/core/core.d.ts +3 -0
  115. package/core/core.js +7 -0
  116. package/core/mixins/Fetcher.d.ts +69 -0
  117. package/core/mixins/Fetcher.js +147 -0
  118. package/core/mixins/FormCheckable.d.ts +72 -0
  119. package/core/mixins/FormCheckable.js +144 -0
  120. package/core/mixins/FormElement.d.ts +21 -0
  121. package/core/mixins/FormElement.js +229 -0
  122. package/core/mixins/FormInput.d.ts +49 -0
  123. package/core/mixins/FormInput.js +33 -0
  124. package/core/mixins/Subscriber.d.ts +30 -0
  125. package/core/mixins/Subscriber.js +379 -0
  126. package/core/mixins/TemplatesContainer.d.ts +12 -0
  127. package/core/mixins/TemplatesContainer.js +60 -0
  128. package/core/mixins/mixins.d.ts +6 -0
  129. package/core/mixins/mixins.js +6 -0
  130. package/core/utils/Arrays.d.ts +97 -0
  131. package/core/utils/Arrays.js +136 -0
  132. package/core/utils/DataBindObserver.d.ts +74 -0
  133. package/core/utils/DataBindObserver.js +252 -0
  134. package/core/utils/Format.d.ts +11 -0
  135. package/core/utils/Format.js +22 -0
  136. package/core/utils/HTML.d.ts +13 -0
  137. package/core/utils/HTML.js +26 -0
  138. package/core/utils/LocationHandler.d.ts +44 -0
  139. package/core/utils/LocationHandler.js +96 -0
  140. package/core/utils/Objects.d.ts +23 -0
  141. package/core/utils/Objects.js +63 -0
  142. package/core/utils/PublisherProxy.d.mts +110 -0
  143. package/core/utils/PublisherProxy.mjs +365 -0
  144. package/core/utils/api.d.ts +66 -0
  145. package/core/utils/api.js +145 -0
  146. package/package.json +179 -21
  147. package/LICENSE +0 -43
  148. package/dist/concorde.bundle.js +0 -3620
  149. package/types/components/event/event-card/event-card.d.ts +0 -10
  150. package/types/components/event/event-title/event-title.d.ts +0 -7
  151. package/types/components/event/event.d.ts +0 -8
  152. package/types/components/giftcards/giftcard/giftcard.d.ts +0 -15
  153. package/types/components/illustration/illustration.d.ts +0 -16
  154. package/types/components/product/prices-form/price-button/price-button.d.ts +0 -25
  155. package/types/components/product/prices-form/prices-form.d.ts +0 -23
  156. package/types/components/theme/theme-collection/bootstrap5.d.ts +0 -1
  157. package/types/components/theme/theme-collection/dracula.d.ts +0 -1
  158. package/types/components/theme/theme.d.ts +0 -8
  159. package/types/components/ui/button/button.d.ts +0 -13
  160. package/types/components/ui/loader/loader.d.ts +0 -15
  161. package/types/components/ui/modal/modal.d.ts +0 -17
  162. package/types/components/ui/tooltip/tooltip.d.ts +0 -9
  163. package/types/core/components/fetch.d.ts +0 -6
  164. package/types/core/components/list.d.ts +0 -9
  165. package/types/core/components/queue.d.ts +0 -15
  166. package/types/core/components/taxonomy.d.ts +0 -13
  167. package/types/core/components/text-formatted.d.ts +0 -15
  168. package/types/core/components/text.d.ts +0 -9
  169. package/types/core/core.d.ts +0 -7
  170. package/types/core/mixins/Fetcher.d.ts +0 -9
  171. package/types/core/mixins/Subscriber.d.ts +0 -13
  172. package/types/core/utils/api.d.ts +0 -16
  173. package/types/index.d.ts +0 -12
  174. package/types/styles/button/button.d.ts +0 -1
  175. package/types/styles/prose/prose.d.ts +0 -2
@@ -0,0 +1,136 @@
1
+ class Arrays {
2
+ /**
3
+ * Vérifie si les deux tableaux ont le même contenu
4
+ */
5
+ static areEqual(array1, array2) {
6
+ if (array1.length === array2.length) {
7
+ return array1.every((element, index) => {
8
+ if (element === array2[index]) {
9
+ return true;
10
+ }
11
+ return false;
12
+ });
13
+ }
14
+ return false;
15
+ }
16
+ /**
17
+ * Fournie une fonction to1D qui transforme un tableau 2D en un tableau 1D par concaténation
18
+ */
19
+ static from2d(source) {
20
+ return {
21
+ to1D: () => {
22
+ let result = [];
23
+ source.forEach((elt) => (result = result.concat(elt)));
24
+ return this.from(result);
25
+ },
26
+ };
27
+ }
28
+ /**
29
+ * Fournie des méthodes pour manipuler un tableau
30
+ * A l'écriture cela permet d'avoir des phrases du type:
31
+ * let data = Arrays.from(mon tableau)
32
+ * puis data.everyItem().has().same().value().forkey("key");
33
+ * Peu mieux faire. ou voir a remplacer un jour par loadHash par exemple.
34
+ **/
35
+ static from(source) {
36
+ return {
37
+ /**Obtenir le tableau final*/
38
+ get: () => source || [],
39
+ everyItem: () => {
40
+ return {
41
+ has: () => {
42
+ return {
43
+ same: () => {
44
+ return {
45
+ value: () => {
46
+ return {
47
+ forKey: (key) => {
48
+ if (source.length < 1)
49
+ return true;
50
+ let first = (source[0] || {})[key];
51
+ return source.every((item) => (item || {})[key] == first);
52
+ },
53
+ };
54
+ },
55
+ };
56
+ },
57
+ };
58
+ },
59
+ value: () => {
60
+ return {
61
+ forKey: (key) => {
62
+ return Arrays.from(source.map((item) => item[key]));
63
+ },
64
+ };
65
+ },
66
+ copy: () => {
67
+ return {
68
+ fromKey: (atKey) => {
69
+ return {
70
+ toKey: (toKey) => {
71
+ source.forEach((item) => {
72
+ item[toKey] = Array.isArray(item[atKey])
73
+ ? [...item[atKey]]
74
+ : typeof item[atKey] === "object" && item[atKey] != null
75
+ ? Object.assign({}, item[atKey]) : item[atKey];
76
+ });
77
+ },
78
+ };
79
+ },
80
+ };
81
+ },
82
+ };
83
+ },
84
+ map: (f) => Arrays.from(source.map(f)),
85
+ filter: (f) => Arrays.from(source.filter(f)),
86
+ find: (f) => source.find(f),
87
+ some: (f) => source.some(f),
88
+ every: (f) => source.every(f),
89
+ group: () => {
90
+ return {
91
+ byKey: (key) => {
92
+ let result = [];
93
+ let keys = new Map();
94
+ for (let item of source) {
95
+ let value = item[key];
96
+ if (!keys.has(value)) {
97
+ let idx = result.length;
98
+ keys.set(value, idx);
99
+ let pushable = { items: [] };
100
+ pushable[key] = value;
101
+ result.push(pushable);
102
+ }
103
+ result[keys.get(value)].items.push(item);
104
+ }
105
+ return Arrays.from(result);
106
+ },
107
+ };
108
+ },
109
+ without: () => {
110
+ return {
111
+ duplicates: () => {
112
+ return {
113
+ forKey: (key) => {
114
+ let set = [...new Set(source.map((item) => item[key]))];
115
+ return Arrays.from(set.map((value) => source.find((item) => item[key] == value)));
116
+ },
117
+ };
118
+ },
119
+ itemsIn: (toRemoveFromSource) => {
120
+ return {
121
+ havingSameValue: () => {
122
+ return {
123
+ forKey: (key) => {
124
+ let areValuesDifferentForKey = (compared1, key) => (compared2) => compared1[key] != compared2[key];
125
+ return Arrays.from(source.filter((elt) => toRemoveFromSource.every(areValuesDifferentForKey(elt, key))));
126
+ },
127
+ };
128
+ },
129
+ };
130
+ },
131
+ };
132
+ },
133
+ };
134
+ }
135
+ }
136
+ export default Arrays;
@@ -0,0 +1,74 @@
1
+ declare type BindedVariablesDescriptor = {
2
+ expression: String;
3
+ variables: Array<Array<string>>;
4
+ };
5
+ declare type DataBindItem = {
6
+ propertyToUpdate: string;
7
+ bindedVariablesDescriptor: BindedVariablesDescriptor;
8
+ };
9
+ /**
10
+ * En appelant DataBindObserver.observe(HTMLElement) sun un élément html, tout les éléments peuvent être liés à au publisher a l'adresse déterminée parl'attribut dataProvider de l'un de ses ancêtres.
11
+ * Pour cela un MutationObserver est créé pour observer les changements d'attributs de l'élément.
12
+ * On peut alors ecrire ce genre de choses de manière a lier dynamiquement les données du publisher à l'élément html.
13
+ * <img data-bind ::src="$img.avatar" ::title="ucFirst|$img.caption" />
14
+ * <a data-bind ::href="mailto:$email" ::inner-html="$email"></a>
15
+ * Voir la doc de subscriber à ce sujet car il l'utilise par défaut.
16
+ */
17
+ export default class DataBindObserver {
18
+ /**
19
+ * Maintient la liste des éléments observés de manière à pouvoir les désinscrire quand ils sont supprimés.
20
+ */
21
+ static observedElements: Map<Node, MutationObserver>;
22
+ /**
23
+ * Commencer à observer un élément html.
24
+ */
25
+ static observe(element: HTMLElement): void;
26
+ /**
27
+ * Arrêter à observer un élément html.
28
+ */
29
+ static unObserve(element: HTMLElement): void;
30
+ static onAdded(elt: HTMLElement): void;
31
+ static onRemoved(elt: HTMLElement): void;
32
+ /**
33
+ * Callback appelé par le MutationObserver
34
+ */
35
+ static onMutation(list: MutationRecord[]): void;
36
+ static publisherListeners: Map<HTMLElement, any[]>;
37
+ /**
38
+ * La liaison avec le publisher supprimée ici.
39
+ */
40
+ static removePublisherListeners(target: HTMLElement): void;
41
+ /**
42
+ *
43
+ * Cette fonction prend l'expression fournie et trouves toutes les occurences du type $.clef1.clef2.clef3 ou $a.b par exemple.
44
+ * Les occurences sont ensuite mises dans un table de la forme [["clef1", "clef2", "clef3"],["a", "b"],...]
45
+ * Note : si une clef contien un point, on peut l'échapper en écrivant par exemple "$a.b.c\.d\.e" pour cibler value dans {a:{b:{"c.d.e":value}}}
46
+ * Propriétés du retour (du type BindedVariablesDescriptor) :
47
+ * * expression : l'expression initiale sans les échappements
48
+ * * variables : le tableau d'"adresses" de variables décrit ci-dessus
49
+ */
50
+ static getVariablesDescriptor(expression: string): BindedVariablesDescriptor;
51
+ /**
52
+ * Extrait des "DataBindItems" a partir d'un élément html.
53
+ * Pour chaque attribut dont le nom commence par ::, un dataBindItem est créé.
54
+ * * Proriété "propertyToUpdate" du DataBindItem :
55
+ * Le nom de l'attribut modifié en transformant La notation en hyphen ("-") en KamelCase.
56
+ * un cas spécial est créé pour *-html qui retourne *HTML par exemple inner-html devient innerHTML
57
+ * Cela représente la propriété à mettre à jour sur l'élément lors de la modification d'une des variables liées dans le publicheur.
58
+ * * Propriété "bindedVariablesDescriptor" du DataBindItem : voir la fonction getVariablesDescriptor
59
+ */
60
+ static getDataBindItems(element: HTMLElement): DataBindItem[];
61
+ /**
62
+ * Cette fonction récuperer le (sous) publisher a l'adresse donnée.
63
+ * Si l'une des clef de l'adresse est _self_, on garde le publisher courant et on passe à la suite.
64
+ * Ceci est un cas spécial, c'est pour ça qu'on utilisa pes Objects.traverse.
65
+ * Il y a toujours un publisher quelque soit l'adresse ce qui permet de cibler des valeurs qui n'existent pas encore
66
+ */
67
+ static getSubPublisher(pub: any, pathArray: string[]): any;
68
+ /**
69
+ * La liaison avec le publisher est faite ici.
70
+ * TODO Sans doute factoriser
71
+ */
72
+ static addPublisherListeners(target: HTMLElement): void;
73
+ }
74
+ export {};
@@ -0,0 +1,252 @@
1
+ import Objects from "@supersoniks/concorde/core/utils/Objects";
2
+ import Format from "@supersoniks/concorde/core/utils/Format";
3
+ import HTML from "@supersoniks/concorde/core/utils/HTML";
4
+ import { PublisherManager } from "@supersoniks/concorde/core/utils/PublisherProxy.mjs";
5
+ /**
6
+ * En appelant DataBindObserver.observe(HTMLElement) sun un élément html, tout les éléments peuvent être liés à au publisher a l'adresse déterminée parl'attribut dataProvider de l'un de ses ancêtres.
7
+ * Pour cela un MutationObserver est créé pour observer les changements d'attributs de l'élément.
8
+ * On peut alors ecrire ce genre de choses de manière a lier dynamiquement les données du publisher à l'élément html.
9
+ * <img data-bind ::src="$img.avatar" ::title="ucFirst|$img.caption" />
10
+ * <a data-bind ::href="mailto:$email" ::inner-html="$email"></a>
11
+ * Voir la doc de subscriber à ce sujet car il l'utilise par défaut.
12
+ */
13
+ export default class DataBindObserver {
14
+ /**
15
+ * Commencer à observer un élément html.
16
+ */
17
+ static observe(element) {
18
+ if (DataBindObserver.observedElements.has(element))
19
+ return;
20
+ let obs = new MutationObserver(DataBindObserver.onMutation);
21
+ let opt = {};
22
+ opt.childList = true;
23
+ opt.subtree = true;
24
+ opt.attributes = true;
25
+ opt.attributeFilter = ["data-bind"];
26
+ obs.observe(element, opt);
27
+ element.querySelectorAll("[data-bind]").forEach((e) => DataBindObserver.addPublisherListeners(e));
28
+ DataBindObserver.observedElements.set(element, obs);
29
+ }
30
+ /**
31
+ * Arrêter à observer un élément html.
32
+ */
33
+ static unObserve(element) {
34
+ let observer = this.observedElements.get(element);
35
+ if (!observer)
36
+ return;
37
+ observer.disconnect();
38
+ element.querySelectorAll("[data-bind]").forEach((e) => DataBindObserver.removePublisherListeners(e));
39
+ }
40
+ static onAdded(elt) {
41
+ if (elt.hasAttribute && elt.hasAttribute("data-bind"))
42
+ DataBindObserver.addPublisherListeners(elt);
43
+ if (elt.querySelectorAll)
44
+ elt.querySelectorAll("[data-bind]").forEach((e) => DataBindObserver.addPublisherListeners(e));
45
+ else
46
+ elt.childNodes.forEach((elt) => DataBindObserver.onAdded(elt));
47
+ }
48
+ static onRemoved(elt) {
49
+ if (elt.hasAttribute && elt.hasAttribute("data-bind"))
50
+ DataBindObserver.removePublisherListeners(elt);
51
+ if (elt.querySelectorAll)
52
+ elt
53
+ .querySelectorAll("[data-bind]")
54
+ .forEach((e) => DataBindObserver.removePublisherListeners(e));
55
+ else
56
+ elt.childNodes.forEach((elt) => DataBindObserver.onRemoved(elt));
57
+ }
58
+ /**
59
+ * Callback appelé par le MutationObserver
60
+ */
61
+ static onMutation(list) {
62
+ for (let l of list) {
63
+ switch (l.type) {
64
+ case "attributes":
65
+ DataBindObserver.addPublisherListeners(l.target);
66
+ break;
67
+ case "childList":
68
+ var added = l.addedNodes;
69
+ var removed = l.removedNodes;
70
+ added.forEach((elt) => {
71
+ DataBindObserver.onAdded(elt);
72
+ });
73
+ removed.forEach((elt) => {
74
+ DataBindObserver.onRemoved(elt);
75
+ });
76
+ break;
77
+ }
78
+ }
79
+ }
80
+ /**
81
+ * La liaison avec le publisher supprimée ici.
82
+ */
83
+ static removePublisherListeners(target) {
84
+ let conf = DataBindObserver.publisherListeners.get(target);
85
+ if (!conf)
86
+ return;
87
+ DataBindObserver.publisherListeners.delete(target);
88
+ conf.forEach((currentConf) => {
89
+ currentConf.publisher.offAssign(currentConf.onAssign);
90
+ });
91
+ }
92
+ /**
93
+ *
94
+ * Cette fonction prend l'expression fournie et trouves toutes les occurences du type $.clef1.clef2.clef3 ou $a.b par exemple.
95
+ * Les occurences sont ensuite mises dans un table de la forme [["clef1", "clef2", "clef3"],["a", "b"],...]
96
+ * Note : si une clef contien un point, on peut l'échapper en écrivant par exemple "$a.b.c\.d\.e" pour cibler value dans {a:{b:{"c.d.e":value}}}
97
+ * Propriétés du retour (du type BindedVariablesDescriptor) :
98
+ * * expression : l'expression initiale sans les échappements
99
+ * * variables : le tableau d'"adresses" de variables décrit ci-dessus
100
+ */
101
+ static getVariablesDescriptor(expression) {
102
+ let variables = expression.match(/(\$(?:\w+\\?\.?)+)/g);
103
+ if (!variables)
104
+ variables = [expression];
105
+ else
106
+ variables = variables.map((v) => v.replace("$", ""));
107
+ variables = variables.filter((v) => v.length > 0);
108
+ return {
109
+ expression: expression.replace("\\", ""),
110
+ variables: variables.map((v) => v.split(/\b\.\b/).map((e) => e.replace("\\", ""))),
111
+ };
112
+ }
113
+ /**
114
+ * Extrait des "DataBindItems" a partir d'un élément html.
115
+ * Pour chaque attribut dont le nom commence par ::, un dataBindItem est créé.
116
+ * * Proriété "propertyToUpdate" du DataBindItem :
117
+ * Le nom de l'attribut modifié en transformant La notation en hyphen ("-") en KamelCase.
118
+ * un cas spécial est créé pour *-html qui retourne *HTML par exemple inner-html devient innerHTML
119
+ * Cela représente la propriété à mettre à jour sur l'élément lors de la modification d'une des variables liées dans le publicheur.
120
+ * * Propriété "bindedVariablesDescriptor" du DataBindItem : voir la fonction getVariablesDescriptor
121
+ */
122
+ static getDataBindItems(element) {
123
+ return Array.from(element.attributes)
124
+ .filter((attribute) => attribute.name.indexOf("::") == 0)
125
+ .map((e) => {
126
+ let name = e.name.substring(2);
127
+ return {
128
+ propertyToUpdate: name.replace(/\-((html)|\w)/g, (match) => match.substring(1).toUpperCase()),
129
+ bindedVariablesDescriptor: DataBindObserver.getVariablesDescriptor(e.value),
130
+ };
131
+ });
132
+ }
133
+ /**
134
+ * Cette fonction récuperer le (sous) publisher a l'adresse donnée.
135
+ * Si l'une des clef de l'adresse est _self_, on garde le publisher courant et on passe à la suite.
136
+ * Ceci est un cas spécial, c'est pour ça qu'on utilisa pes Objects.traverse.
137
+ * Il y a toujours un publisher quelque soit l'adresse ce qui permet de cibler des valeurs qui n'existent pas encore
138
+ */
139
+ static getSubPublisher(pub, pathArray) {
140
+ for (let key of pathArray) {
141
+ if (key == "_self_")
142
+ continue;
143
+ pub = pub[key];
144
+ }
145
+ return pub;
146
+ }
147
+ /**
148
+ * La liaison avec le publisher est faite ici.
149
+ * TODO Sans doute factoriser
150
+ */
151
+ static addPublisherListeners(target) {
152
+ DataBindObserver.removePublisherListeners(target);
153
+ /**
154
+ * On récupère le publisher viea le dataProvider d'un ancêtre de l'élément.
155
+ */
156
+ let node = target;
157
+ let dataProviderId = HTML.getAncestorAttributeValue(node.parentNode || node.host || node, "dataProvider");
158
+ if (!dataProviderId)
159
+ return;
160
+ let publisher = PublisherManager.getInstance().get(dataProviderId);
161
+ let dataBindItems = DataBindObserver.getDataBindItems(target);
162
+ let conf = [];
163
+ /**
164
+ * Pour chaque attribut => dataBindItems on fait la liaison avec les (sous) publishers associés aux variables extraites
165
+ * Lorsqu'une assignation est faite sur un des publishers liés, on met à jour la propriété de target dont le nom est renseigne dans l'attribut "propertyToUpdate du databindItem".
166
+ * Cette mise à jour est effectuée dans la fonction onAssign.
167
+ * On peut utiliser les fonctions présentes dans Format.ts notamment Format.js qui permet par exemple d'interpréter des expressions js simples.
168
+ * Attentions, les Objets/tableaus sont rendus en chaine avant l'interprétation dans ce cas.
169
+ */
170
+ dataBindItems.forEach((dataBindItem) => {
171
+ let bindedVariablesDescriptor = dataBindItem.bindedVariablesDescriptor;
172
+ let propertyToUpdate = dataBindItem.propertyToUpdate;
173
+ for (let value of bindedVariablesDescriptor.variables) {
174
+ let publisherPathArray = value;
175
+ let pub = publisher;
176
+ pub = DataBindObserver.getSubPublisher(publisher, publisherPathArray);
177
+ let rec = target;
178
+ let currentConf = {
179
+ publisher: pub,
180
+ onAssign: () => {
181
+ let values = bindedVariablesDescriptor.variables.map((dataPath) => {
182
+ return DataBindObserver.getSubPublisher(publisher, dataPath).get();
183
+ });
184
+ let expression = bindedVariablesDescriptor.expression;
185
+ let hasUndeterminatedValue = false;
186
+ /*
187
+ * Si il n'y a qu'une variable on injecte la variable brute ce qui permet d'utiliser des objets composites
188
+ * Dans le cas des des expressions complexes (plus bas, avec plusieurs variables) les objets deviennent des chaines de caractères.)
189
+ */
190
+ if (values.length == 1 && bindedVariablesDescriptor.variables[0].join(".") == expression.substring(1)) {
191
+ let value = values[0];
192
+ if (Objects.isObject(value) &&
193
+ value.hasOwnProperty("__value") &&
194
+ (Objects.isUndefindOrNull(value.__value) || value.__value === "")) {
195
+ value = "";
196
+ }
197
+ rec[propertyToUpdate] = value;
198
+ return;
199
+ }
200
+ /**
201
+ * Expressions avec plusieurs variables
202
+ */
203
+ for (let i = 0; i < values.length; i++) {
204
+ let value = values[i];
205
+ let variable = bindedVariablesDescriptor.variables[i];
206
+ if (Objects.isObject(value) &&
207
+ value.hasOwnProperty("__value") &&
208
+ Objects.isUndefindOrNull(value.__value)) {
209
+ hasUndeterminatedValue = true;
210
+ value = undefined;
211
+ }
212
+ expression = expression.replace("$" + variable.join("."), value);
213
+ }
214
+ /**
215
+ * Ce bout de code doit être un relicat
216
+ */
217
+ // if (Objects.isObject(expression) && !expression.hasOwnProperty("__value")) {
218
+ // rec[propertyToUpdate] = expression;
219
+ // return;
220
+ // } else if (Objects.isObject(expression) && !expression.__value) expression = "";
221
+ // else
222
+ if (expression.indexOf("|") != -1) {
223
+ let funcDelimiterIdx = expression.indexOf("|");
224
+ if (funcDelimiterIdx == 0) {
225
+ expression = Format.js(expression.substring(1));
226
+ }
227
+ else {
228
+ let funcName = expression.substring(0, funcDelimiterIdx);
229
+ let funcArgs = expression.substring(funcDelimiterIdx + 1);
230
+ let fmt = Format;
231
+ expression = hasUndeterminatedValue ? "" : fmt[funcName] ? fmt[funcName](funcArgs) : expression;
232
+ }
233
+ }
234
+ else {
235
+ expression = hasUndeterminatedValue ? "" : expression;
236
+ }
237
+ rec[propertyToUpdate] = expression;
238
+ },
239
+ };
240
+ pub.onAssign(currentConf.onAssign);
241
+ conf.push(currentConf);
242
+ }
243
+ });
244
+ DataBindObserver.publisherListeners.set(target, conf);
245
+ }
246
+ }
247
+ /**
248
+ * Maintient la liste des éléments observés de manière à pouvoir les désinscrire quand ils sont supprimés.
249
+ */
250
+ DataBindObserver.observedElements = new Map();
251
+ DataBindObserver.publisherListeners = new Map();
252
+ DataBindObserver.observe(document.documentElement);
@@ -0,0 +1,11 @@
1
+ declare class Format {
2
+ /**
3
+ * Passe le premier caractère de la chaine en majuscule
4
+ */
5
+ static ucFirst(str: string): string;
6
+ /**
7
+ * Retourne le résultat de l'évaluation de la chaine fournie
8
+ */
9
+ static js(value: string): any;
10
+ }
11
+ export default Format;
@@ -0,0 +1,22 @@
1
+ class Format {
2
+ /**
3
+ * Passe le premier caractère de la chaine en majuscule
4
+ */
5
+ static ucFirst(str) {
6
+ if (typeof str != "string")
7
+ return str;
8
+ return str.charAt(0).toUpperCase() + str.substring(1);
9
+ }
10
+ /**
11
+ * Retourne le résultat de l'évaluation de la chaine fournie
12
+ */
13
+ static js(value) {
14
+ try {
15
+ return Function("return " + value)();
16
+ }
17
+ catch (e) {
18
+ return "";
19
+ }
20
+ }
21
+ }
22
+ export default Format;
@@ -0,0 +1,13 @@
1
+ declare class HTML {
2
+ /**
3
+ * retourne la langue de la page courante telle que défini via l'attribut lang de la balise html
4
+ */
5
+ static getLanguage(): string;
6
+ /**
7
+ * Va de parent en parent en partant de node pour trouver un attribut
8
+ * @param attributeName nom de l'attribut
9
+ * @returns valeur de l'attribut ou null si l'attribut n'est pas trouvé
10
+ */
11
+ static getAncestorAttributeValue(node: any, attributeName: string): string | null;
12
+ }
13
+ export default HTML;
@@ -0,0 +1,26 @@
1
+ class HTML {
2
+ /**
3
+ * retourne la langue de la page courante telle que défini via l'attribut lang de la balise html
4
+ */
5
+ static getLanguage() {
6
+ return document.getElementsByTagName("html")[0].getAttribute("lang");
7
+ }
8
+ /**
9
+ * Va de parent en parent en partant de node pour trouver un attribut
10
+ * @param attributeName nom de l'attribut
11
+ * @returns valeur de l'attribut ou null si l'attribut n'est pas trouvé
12
+ */
13
+ static getAncestorAttributeValue(node, attributeName) {
14
+ while (!(node.hasAttribute && node.hasAttribute(attributeName))) {
15
+ const newNode = node.parentNode || node.host;
16
+ if (!newNode)
17
+ break;
18
+ node = node.parentNode || node.host;
19
+ }
20
+ if (!node.hasAttribute) {
21
+ return null;
22
+ }
23
+ return node.getAttribute(attributeName);
24
+ }
25
+ }
26
+ export default HTML;
@@ -0,0 +1,44 @@
1
+ declare type Listener = {
2
+ location: string;
3
+ };
4
+ declare type ActivableLink = {
5
+ location: string;
6
+ href: string;
7
+ setAttribute(name: string, value: string): void;
8
+ removeAttribute(name: string): void;
9
+ };
10
+ /**
11
+ * Gestionnaire d'écoute des modifications sur l'url courante.
12
+ * On peut s'y abonner via la methode statique onChange()
13
+ * Utilisé par sonic-bouton pour lm'affichage de l'état actif et par le router.
14
+ */
15
+ export default class LocationHandler {
16
+ static listeners: Array<Listener>;
17
+ static listening: boolean;
18
+ static prevURL: string;
19
+ static listen(): void;
20
+ /**
21
+ * Arrête l'écoute des changements de location pour le listener fournit
22
+ */
23
+ static offChange(listener: Listener): void;
24
+ /**
25
+ * Ecoute les changements de location et l'assigne à la propriété location de chaque listener
26
+ */
27
+ static onChange(listener: Listener): void;
28
+ /**
29
+ *
30
+ * @param component HTMLElement
31
+ * Recupère la proprité to ou href de l'élément et lance la navigation
32
+ * Si l'attribut pushState est présent la naviguation se fait via un pushState
33
+ * Si l'attribut replaceState est présent la naviguation se fait via un replaceState
34
+ * Voir link et button pour les exemples d'implémentation
35
+ **/
36
+ static changeFromComponent(component: any): void;
37
+ /**
38
+ *
39
+ * @param component ActivableLink
40
+ * Ajoute l'attribut "active" à l'élément si l'url correspond à la location
41
+ */
42
+ static updateComponentActiveState(component: ActivableLink): void;
43
+ }
44
+ export {};