@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.
- package/README.md +16 -8
- package/cli.js +69 -0
- package/core/components/functional/date/date.d.ts +34 -0
- package/core/components/functional/date/date.js +187 -0
- package/core/components/functional/example/example.d.ts +7 -0
- package/core/components/functional/example/example.js +25 -0
- package/core/components/functional/fetch/fetch.d.ts +49 -0
- package/core/components/functional/fetch/fetch.js +38 -0
- package/core/components/functional/functional.d.ts +11 -0
- package/core/components/functional/functional.js +11 -0
- package/core/components/functional/if/if.d.ts +12 -0
- package/core/components/functional/if/if.js +43 -0
- package/core/components/functional/list/list.d.ts +67 -0
- package/core/components/functional/list/list.js +132 -0
- package/core/components/functional/queue/queue.d.ts +42 -0
- package/core/components/functional/queue/queue.js +184 -0
- package/core/components/functional/router/redirect.d.ts +18 -0
- package/core/components/functional/router/redirect.js +57 -0
- package/core/components/functional/router/router.d.ts +26 -0
- package/core/components/functional/router/router.js +104 -0
- package/core/components/functional/states/states.d.ts +28 -0
- package/core/components/functional/states/states.js +139 -0
- package/core/components/functional/submit/submit.d.ts +24 -0
- package/core/components/functional/submit/submit.js +108 -0
- package/{types/core/components → core/components/functional/subscriber}/subscriber.d.ts +5 -1
- package/core/components/functional/subscriber/subscriber.js +30 -0
- package/core/components/ui/alert/alert.d.ts +20 -0
- package/core/components/ui/alert/alert.js +150 -0
- package/core/components/ui/badge/badge.d.ts +24 -0
- package/core/components/ui/badge/badge.js +177 -0
- package/core/components/ui/button/button.d.ts +125 -0
- package/core/components/ui/button/button.js +558 -0
- package/core/components/ui/divider/divider.d.ts +11 -0
- package/core/components/ui/divider/divider.js +144 -0
- package/core/components/ui/form/checkbox/checkbox.d.ts +120 -0
- package/core/components/ui/form/checkbox/checkbox.js +203 -0
- package/core/components/ui/form/css/form-control.d.ts +1 -0
- package/core/components/ui/form/css/form-control.js +219 -0
- package/core/components/ui/form/fieldset/fieldset.d.ts +15 -0
- package/core/components/ui/form/fieldset/fieldset.js +70 -0
- package/core/components/ui/form/fieldset/legend.d.ts +11 -0
- package/core/components/ui/form/fieldset/legend.js +92 -0
- package/core/components/ui/form/form-layout/form-actions.d.ts +6 -0
- package/core/components/ui/form/form-layout/form-actions.js +23 -0
- package/core/components/ui/form/form-layout/form-layout.d.ts +9 -0
- package/core/components/ui/form/form-layout/form-layout.js +58 -0
- package/core/components/ui/form/input/input.d.ts +84 -0
- package/core/components/ui/form/input/input.js +180 -0
- package/core/components/ui/form/radio/radio.d.ts +12 -0
- package/core/components/ui/form/radio/radio.js +55 -0
- package/core/components/ui/form/select/select.d.ts +39 -0
- package/core/components/ui/form/select/select.js +220 -0
- package/core/components/ui/form/textarea/textarea.d.ts +69 -0
- package/core/components/ui/form/textarea/textarea.js +150 -0
- package/core/components/ui/group/group.d.ts +6 -0
- package/core/components/ui/group/group.js +57 -0
- package/core/components/ui/icon/icon.d.ts +17 -0
- package/core/components/ui/icon/icon.js +93 -0
- package/core/components/ui/icon/icons.d.ts +13 -0
- package/core/components/ui/icon/icons.js +25 -0
- package/core/components/ui/icon/icons.json +1 -0
- package/core/components/ui/image/image.d.ts +14 -0
- package/core/components/ui/image/image.js +152 -0
- package/core/components/ui/link/link.d.ts +16 -0
- package/core/components/ui/link/link.js +70 -0
- package/core/components/ui/loader/loader.d.ts +20 -0
- package/core/components/ui/loader/loader.js +94 -0
- package/{types → core}/components/ui/loader/styles/fixed.d.ts +0 -0
- package/core/components/ui/loader/styles/fixed.js +57 -0
- package/{types → core}/components/ui/loader/styles/inline.d.ts +0 -0
- package/core/components/ui/loader/styles/inline.js +71 -0
- package/core/components/ui/menu/menu-item.d.ts +5 -0
- package/core/components/ui/menu/menu-item.js +37 -0
- package/core/components/ui/menu/menu.d.ts +26 -0
- package/core/components/ui/menu/menu.js +125 -0
- package/core/components/ui/modal/modal-actions.d.ts +7 -0
- package/core/components/ui/modal/modal-actions.js +46 -0
- package/core/components/ui/modal/modal-close.d.ts +6 -0
- package/core/components/ui/modal/modal-close.js +38 -0
- package/core/components/ui/modal/modal-content.d.ts +5 -0
- package/core/components/ui/modal/modal-content.js +29 -0
- package/core/components/ui/modal/modal-subtitle.d.ts +5 -0
- package/core/components/ui/modal/modal-subtitle.js +33 -0
- package/core/components/ui/modal/modal-title.d.ts +5 -0
- package/core/components/ui/modal/modal-title.js +33 -0
- package/core/components/ui/modal/modal.d.ts +36 -0
- package/core/components/ui/modal/modal.js +325 -0
- package/core/components/ui/pop/pop.d.ts +28 -0
- package/core/components/ui/pop/pop.js +223 -0
- package/core/components/ui/tabs/tab.d.ts +6 -0
- package/core/components/ui/tabs/tab.js +46 -0
- package/core/components/ui/tabs/tabs.d.ts +14 -0
- package/core/components/ui/tabs/tabs.js +127 -0
- package/core/components/ui/taxonomy/taxonomy.d.ts +41 -0
- package/core/components/ui/taxonomy/taxonomy.js +113 -0
- package/core/components/ui/theme/css/tailwind.css +3 -0
- package/core/components/ui/theme/css/tailwind.d.ts +2 -0
- package/core/components/ui/theme/theme-collection/core-variables.d.ts +1 -0
- package/core/components/ui/theme/theme-collection/core-variables.js +50 -0
- package/{types/components → core/components/ui}/theme/theme-collection/dark.d.ts +0 -0
- package/core/components/ui/theme/theme-collection/dark.js +41 -0
- package/{types/components → core/components/ui}/theme/theme-collection/light.d.ts +0 -0
- package/core/components/ui/theme/theme-collection/light.js +35 -0
- package/core/components/ui/theme/theme.d.ts +11 -0
- package/core/components/ui/theme/theme.js +105 -0
- package/core/components/ui/toast/message-subscriber.d.ts +17 -0
- package/core/components/ui/toast/message-subscriber.js +85 -0
- package/{types → core}/components/ui/toast/toast.d.ts +10 -8
- package/core/components/ui/toast/toast.js +260 -0
- package/core/components/ui/tooltip/tooltip.d.ts +7 -0
- package/core/components/ui/tooltip/tooltip.js +68 -0
- package/core/components/ui/ui.d.ts +27 -0
- package/core/components/ui/ui.js +34 -0
- package/core/core.d.ts +3 -0
- package/core/core.js +7 -0
- package/core/mixins/Fetcher.d.ts +69 -0
- package/core/mixins/Fetcher.js +147 -0
- package/core/mixins/FormCheckable.d.ts +72 -0
- package/core/mixins/FormCheckable.js +144 -0
- package/core/mixins/FormElement.d.ts +21 -0
- package/core/mixins/FormElement.js +229 -0
- package/core/mixins/FormInput.d.ts +49 -0
- package/core/mixins/FormInput.js +33 -0
- package/core/mixins/Subscriber.d.ts +30 -0
- package/core/mixins/Subscriber.js +379 -0
- package/core/mixins/TemplatesContainer.d.ts +12 -0
- package/core/mixins/TemplatesContainer.js +60 -0
- package/core/mixins/mixins.d.ts +6 -0
- package/core/mixins/mixins.js +6 -0
- package/core/utils/Arrays.d.ts +97 -0
- package/core/utils/Arrays.js +136 -0
- package/core/utils/DataBindObserver.d.ts +74 -0
- package/core/utils/DataBindObserver.js +252 -0
- package/core/utils/Format.d.ts +11 -0
- package/core/utils/Format.js +22 -0
- package/core/utils/HTML.d.ts +13 -0
- package/core/utils/HTML.js +26 -0
- package/core/utils/LocationHandler.d.ts +44 -0
- package/core/utils/LocationHandler.js +96 -0
- package/core/utils/Objects.d.ts +23 -0
- package/core/utils/Objects.js +63 -0
- package/core/utils/PublisherProxy.d.mts +110 -0
- package/core/utils/PublisherProxy.mjs +365 -0
- package/core/utils/api.d.ts +66 -0
- package/core/utils/api.js +145 -0
- package/package.json +179 -21
- package/LICENSE +0 -43
- package/dist/concorde.bundle.js +0 -3620
- package/types/components/event/event-card/event-card.d.ts +0 -10
- package/types/components/event/event-title/event-title.d.ts +0 -7
- package/types/components/event/event.d.ts +0 -8
- package/types/components/giftcards/giftcard/giftcard.d.ts +0 -15
- package/types/components/illustration/illustration.d.ts +0 -16
- package/types/components/product/prices-form/price-button/price-button.d.ts +0 -25
- package/types/components/product/prices-form/prices-form.d.ts +0 -23
- package/types/components/theme/theme-collection/bootstrap5.d.ts +0 -1
- package/types/components/theme/theme-collection/dracula.d.ts +0 -1
- package/types/components/theme/theme.d.ts +0 -8
- package/types/components/ui/button/button.d.ts +0 -13
- package/types/components/ui/loader/loader.d.ts +0 -15
- package/types/components/ui/modal/modal.d.ts +0 -17
- package/types/components/ui/tooltip/tooltip.d.ts +0 -9
- package/types/core/components/fetch.d.ts +0 -6
- package/types/core/components/list.d.ts +0 -9
- package/types/core/components/queue.d.ts +0 -15
- package/types/core/components/taxonomy.d.ts +0 -13
- package/types/core/components/text-formatted.d.ts +0 -15
- package/types/core/components/text.d.ts +0 -9
- package/types/core/core.d.ts +0 -7
- package/types/core/mixins/Fetcher.d.ts +0 -9
- package/types/core/mixins/Subscriber.d.ts +0 -13
- package/types/core/utils/api.d.ts +0 -16
- package/types/index.d.ts +0 -12
- package/types/styles/button/button.d.ts +0 -1
- 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 {};
|