territories-dashboard-lib 0.1.0__py3-none-any.whl → 0.1.2__py3-none-any.whl

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.

Potentially problematic release.


This version of territories-dashboard-lib might be problematic. Click here for more details.

Files changed (138) hide show
  1. territories_dashboard_lib/commons/__init__.py +0 -0
  2. territories_dashboard_lib/commons/decorators.py +36 -0
  3. territories_dashboard_lib/commons/models.py +9 -0
  4. territories_dashboard_lib/geo_lib/__init__.py +0 -0
  5. territories_dashboard_lib/geo_lib/admin.py +64 -0
  6. territories_dashboard_lib/geo_lib/enums.py +7 -0
  7. territories_dashboard_lib/geo_lib/migrations/0001_initial.py +51 -0
  8. territories_dashboard_lib/geo_lib/migrations/__init__.py +0 -0
  9. territories_dashboard_lib/geo_lib/models.py +58 -0
  10. territories_dashboard_lib/geo_lib/urls.py +27 -0
  11. territories_dashboard_lib/geo_lib/views.py +239 -0
  12. territories_dashboard_lib/indicators_lib/__init__.py +0 -0
  13. territories_dashboard_lib/indicators_lib/admin.py +140 -0
  14. territories_dashboard_lib/indicators_lib/enums.py +59 -0
  15. territories_dashboard_lib/indicators_lib/export.py +29 -0
  16. territories_dashboard_lib/indicators_lib/format.py +34 -0
  17. territories_dashboard_lib/indicators_lib/methodo_pdf.py +99 -0
  18. territories_dashboard_lib/indicators_lib/migrations/0001_initial.py +138 -0
  19. territories_dashboard_lib/indicators_lib/migrations/__init__.py +0 -0
  20. territories_dashboard_lib/indicators_lib/models.py +230 -0
  21. territories_dashboard_lib/indicators_lib/payloads.py +54 -0
  22. territories_dashboard_lib/indicators_lib/query/commons.py +223 -0
  23. territories_dashboard_lib/indicators_lib/query/comparison.py +70 -0
  24. territories_dashboard_lib/indicators_lib/query/details.py +64 -0
  25. territories_dashboard_lib/indicators_lib/query/histogram.py +82 -0
  26. territories_dashboard_lib/indicators_lib/query/indicator_card.py +102 -0
  27. territories_dashboard_lib/indicators_lib/query/top_10.py +100 -0
  28. territories_dashboard_lib/indicators_lib/query/utils.py +20 -0
  29. territories_dashboard_lib/indicators_lib/refresh_filters.py +17 -0
  30. territories_dashboard_lib/indicators_lib/table.py +154 -0
  31. territories_dashboard_lib/indicators_lib/urls.py +97 -0
  32. territories_dashboard_lib/indicators_lib/views.py +490 -0
  33. territories_dashboard_lib/superset_lib/__init__.py +0 -0
  34. territories_dashboard_lib/superset_lib/admin.py +22 -0
  35. territories_dashboard_lib/superset_lib/guest_token.py +64 -0
  36. territories_dashboard_lib/superset_lib/logic.py +67 -0
  37. territories_dashboard_lib/superset_lib/migrations/0001_initial.py +45 -0
  38. territories_dashboard_lib/superset_lib/migrations/__init__.py +0 -0
  39. territories_dashboard_lib/superset_lib/models.py +52 -0
  40. territories_dashboard_lib/superset_lib/serializers.py +10 -0
  41. territories_dashboard_lib/superset_lib/urls.py +10 -0
  42. territories_dashboard_lib/superset_lib/views.py +19 -0
  43. territories_dashboard_lib/tracking_lib/__init__.py +0 -0
  44. territories_dashboard_lib/tracking_lib/enums.py +7 -0
  45. territories_dashboard_lib/tracking_lib/logic.py +78 -0
  46. territories_dashboard_lib/tracking_lib/migrations/0001_initial.py +45 -0
  47. territories_dashboard_lib/tracking_lib/migrations/__init__.py +0 -0
  48. territories_dashboard_lib/tracking_lib/models.py +79 -0
  49. territories_dashboard_lib/website_lib/__init__.py +0 -0
  50. territories_dashboard_lib/website_lib/admin.py +40 -0
  51. territories_dashboard_lib/website_lib/context_processors.py +27 -0
  52. territories_dashboard_lib/website_lib/forms.py +47 -0
  53. territories_dashboard_lib/website_lib/migrations/0001_initial.py +91 -0
  54. territories_dashboard_lib/website_lib/migrations/__init__.py +0 -0
  55. territories_dashboard_lib/website_lib/models.py +148 -0
  56. territories_dashboard_lib/website_lib/navigation.py +124 -0
  57. territories_dashboard_lib/website_lib/params.py +268 -0
  58. territories_dashboard_lib/website_lib/serializers.py +105 -0
  59. territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/css/website.css +956 -0
  60. territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/chart.js +13 -0
  61. territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/chartjs-plugin-datalabels.js +1 -0
  62. territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/html2canvas.js +20 -0
  63. territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/comparaison/data.mjs +62 -0
  64. territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/comparaison/history.mjs +98 -0
  65. territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/comparaison/main-values.mjs +30 -0
  66. territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/comparaison/page.mjs +105 -0
  67. territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/comparaison/territory-chart.mjs +141 -0
  68. territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/details/data.mjs +59 -0
  69. territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/details/histogram.mjs +130 -0
  70. territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/details/map.mjs +25 -0
  71. territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/details/page.mjs +96 -0
  72. territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/details/proportions.mjs +77 -0
  73. territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/details/sankey.mjs +27 -0
  74. territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/details/table.mjs +229 -0
  75. territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/details/top10.mjs +76 -0
  76. territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/details/utils.mjs +8 -0
  77. territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/dom.mjs +92 -0
  78. territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/enums.mjs +104 -0
  79. territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/export-graph.mjs +15 -0
  80. territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/export.mjs +20 -0
  81. territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/filters.mjs +159 -0
  82. territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/format.mjs +54 -0
  83. territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/side_panel.mjs +103 -0
  84. territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/theme/history.mjs +89 -0
  85. territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/theme/main-value.mjs +22 -0
  86. territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/theme/page.mjs +162 -0
  87. territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/theme/statistics.mjs +42 -0
  88. territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/utils.mjs +93 -0
  89. territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/static/page.mjs +35 -0
  90. territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/patternomaly.js +1452 -0
  91. territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/react18.js +31 -0
  92. territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/reactdom18.js +267 -0
  93. territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/supersetEmbed.js +355 -0
  94. territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/react/indicatorMap.bundle.js +2 -0
  95. territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/react/sankeyGraph.bundle.js +2 -0
  96. territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/react/vendors-node_modules_mapbox-gl_dist_mapbox-gl_js.bundle.js +2 -0
  97. territories_dashboard_lib/website_lib/static_content.py +20 -0
  98. territories_dashboard_lib/website_lib/templates/admin/indicators_lib/indicator/change_form.html +8 -0
  99. territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/404.html +10 -0
  100. territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/500.html +10 -0
  101. territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/layout/base.html +42 -0
  102. territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/layout/base.js +47 -0
  103. territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/layout/footer.html +96 -0
  104. territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/layout/header.html +101 -0
  105. territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/layout/header.js +102 -0
  106. territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/indicators/comparaison/[theme]/components/indicateur-card.html +48 -0
  107. territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/indicators/comparaison/[theme]/page.html +52 -0
  108. territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/indicators/components/chart-buttons.html +29 -0
  109. territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/indicators/components/geo_params.html +71 -0
  110. territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/indicators/components/indicator-card.html +52 -0
  111. territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/indicators/components/loader.html +28 -0
  112. territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/indicators/components/side_panel.html +27 -0
  113. territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/indicators/components/side_panel_geo.html +80 -0
  114. territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/indicators/components/side_panel_geo.js +85 -0
  115. territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/indicators/components/side_panel_methodo.html +45 -0
  116. territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/indicators/components/side_panel_methodo.js +19 -0
  117. territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/indicators/components/themes-list.html +9 -0
  118. territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/indicators/components/themes-nav.html +33 -0
  119. territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/indicators/components/title.html +28 -0
  120. territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/indicators/details/components/filters-reminder.html +19 -0
  121. territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/indicators/details/components/table.html +123 -0
  122. territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/indicators/details/page.html +166 -0
  123. territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/indicators/themes/components/extremum.html +15 -0
  124. territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/indicators/themes/components/indicateur-card.html +76 -0
  125. territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/indicators/themes/page.html +66 -0
  126. territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/lexique/page.html +17 -0
  127. territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/page.html +14 -0
  128. territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/sitemap/page.html +71 -0
  129. territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/static/page.html +16 -0
  130. territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/superset/page.html +55 -0
  131. territories_dashboard_lib/website_lib/templatetags/htmlparams.py +75 -0
  132. territories_dashboard_lib/website_lib/templatetags/other_filters.py +30 -0
  133. territories_dashboard_lib/website_lib/views.py +212 -0
  134. {territories_dashboard_lib-0.1.0.dist-info → territories_dashboard_lib-0.1.2.dist-info}/METADATA +1 -1
  135. territories_dashboard_lib-0.1.2.dist-info/RECORD +138 -0
  136. territories_dashboard_lib-0.1.0.dist-info/RECORD +0 -5
  137. {territories_dashboard_lib-0.1.0.dist-info → territories_dashboard_lib-0.1.2.dist-info}/WHEEL +0 -0
  138. {territories_dashboard_lib-0.1.0.dist-info → territories_dashboard_lib-0.1.2.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,159 @@
1
+ function getIndicatorFilters(indicator) {
2
+ return Array.from(
3
+ document.querySelectorAll(
4
+ `.filter-tag[aria-pressed="true"][data-indicator="${indicator.id}"]`
5
+ )
6
+ ).map((button) => [button.dataset.dimension, button.innerText]);
7
+ }
8
+
9
+ function getCurrentFiltersForIndicatorAndDimension(indicator, dimension) {
10
+ return Array.from(
11
+ document.querySelectorAll(
12
+ `.filter-tag[aria-pressed="true"][data-indicator="${indicator.id}"][data-dimension="${dimension}"]`
13
+ )
14
+ ).map((button) => button.innerText);
15
+ }
16
+
17
+ function arrayAreSameSet(arr1, arr2) {
18
+ const xs = new Set(arr1);
19
+ const ys = new Set(arr2);
20
+ return xs.size === ys.size && [...xs].every((x) => ys.has(x));
21
+ }
22
+
23
+ async function handleFilterClick(indicator) {
24
+ // need for DOM to update
25
+ const smallAmountOfTime = 10;
26
+ await new Promise((resolve) => {
27
+ setTimeout(resolve, smallAmountOfTime);
28
+ });
29
+
30
+ let indicatorStorage = localStorage.getItem(indicator.name);
31
+ if (indicatorStorage === null) {
32
+ localStorage.setItem(indicator.name, "{}");
33
+ indicatorStorage = localStorage.getItem(indicator.name);
34
+ }
35
+ const indicatorLocalData = JSON.parse(indicatorStorage);
36
+
37
+ const filtersToSet = {};
38
+ indicator.filters.forEach(([dimensionObj, filtersObj]) => {
39
+ const filters = filtersObj.map((filterOb) => filterOb.db_name);
40
+ const dimension = dimensionObj.db_name;
41
+ const currentFilters = getCurrentFiltersForIndicatorAndDimension(
42
+ indicator,
43
+ dimension
44
+ );
45
+ filtersToSet[dimension] = arrayAreSameSet(filters, currentFilters)
46
+ ? null
47
+ : currentFilters;
48
+ });
49
+ indicatorLocalData.filtersByDimension = filtersToSet;
50
+
51
+ localStorage.setItem(indicator.name, JSON.stringify(indicatorLocalData));
52
+ }
53
+
54
+ function updateUrlWithFilters() {
55
+ const excludeFilters = Array.from(
56
+ document.querySelectorAll(
57
+ '.filter-tag[data-default="true"][aria-pressed="false"]'
58
+ )
59
+ ).map((b) => [b.dataset.dimension, `!${b.innerText}`]);
60
+ const includeFilters = Array.from(
61
+ document.querySelectorAll(
62
+ '.filter-tag[data-default="false"][aria-pressed="true"]'
63
+ )
64
+ ).map((b) => [b.dataset.dimension, b.innerText]);
65
+ const stringFilters = includeFilters.concat(excludeFilters);
66
+ const dimensions = new Set(
67
+ Array.from(document.querySelectorAll(".filter-tag")).map(
68
+ (b) => b.dataset.dimension
69
+ )
70
+ );
71
+ const currentUrl = new URL(window.location);
72
+ dimensions.forEach((dimension) => {
73
+ currentUrl.searchParams.delete(dimension);
74
+ });
75
+ stringFilters.forEach((f) => {
76
+ currentUrl.searchParams.append(f[0], f[1]);
77
+ });
78
+ window.history.replaceState({}, "", currentUrl.toString());
79
+ }
80
+
81
+ function initialFiltersByDimension(indicator, dimension) {
82
+ let initialFilters = [];
83
+ let initializedLocally = false;
84
+ const localRawData = localStorage.getItem(indicator.name);
85
+ if (localRawData) {
86
+ const localData = JSON.parse(localRawData);
87
+ if (
88
+ localData.filtersByDimension &&
89
+ localData.filtersByDimension[dimension] !== null
90
+ ) {
91
+ initialFilters = localData.filtersByDimension[dimension];
92
+ initializedLocally = true;
93
+ }
94
+ }
95
+ if (initializedLocally === false) {
96
+ initialFilters = Array.from(
97
+ document.querySelectorAll(
98
+ `.filter-tag[data-indicator="${indicator.id}"][data-default="true"][data-dimension="${dimension}"]`
99
+ )
100
+ ).map((button) => button.innerText);
101
+ }
102
+ Array.from(
103
+ document.querySelectorAll(
104
+ `.filter-tag[data-indicator="${indicator.id}"][data-dimension="${dimension}"]`
105
+ )
106
+ ).forEach((button) => {
107
+ if (button.dataset.setfromurl === "true") {
108
+ return;
109
+ }
110
+ const pressed = initialFilters.includes(button.innerText)
111
+ ? "true"
112
+ : "false";
113
+ button.setAttribute("aria-pressed", pressed);
114
+ });
115
+ }
116
+
117
+ function initializeFilters(indicator) {
118
+ indicator.filters.forEach(([dimension]) => {
119
+ initialFiltersByDimension(indicator, dimension.db_name);
120
+ });
121
+ }
122
+
123
+ function updateFiltersReminder(indicator) {
124
+ if (indicator.filters.length > 1) {
125
+ indicator.filters.forEach(([dimension]) => {
126
+ if (!dimension.is_breakdown) {
127
+ const currentFilters = Array.from(
128
+ document.querySelectorAll(
129
+ `.filters-dimension button[data-dimension="${dimension.db_name}"][aria-pressed="true"]`
130
+ )
131
+ );
132
+ const currentFiltersHtml =
133
+ currentFilters.length > 0
134
+ ? currentFilters
135
+ .map(
136
+ (filter) =>
137
+ `<p class="fr-tag">${filter.textContent.trim()}</p>`
138
+ )
139
+ .join("")
140
+ : "<p class=fr-tag>Aucun filtre</p>";
141
+ Array.from(
142
+ document.querySelectorAll(
143
+ `.filters-reminder-dimension[data-dimension="${dimension.db_name}"]`
144
+ )
145
+ ).forEach((container) => {
146
+ container.innerHTML = currentFiltersHtml;
147
+ });
148
+ }
149
+ });
150
+ }
151
+ }
152
+
153
+ export {
154
+ initializeFilters,
155
+ handleFilterClick,
156
+ getIndicatorFilters,
157
+ updateUrlWithFilters,
158
+ updateFiltersReminder,
159
+ };
@@ -0,0 +1,54 @@
1
+ /* eslint-disable no-magic-numbers */
2
+ import { MILLIONS, THOUSANDS } from "./enums.mjs";
3
+
4
+ function removeUseless0(value) {
5
+ let newValue = value;
6
+ if (newValue.indexOf(".") > 0) {
7
+ if (newValue.slice(-2) === "00") {
8
+ newValue = newValue.slice(0, -2);
9
+ }
10
+ if (newValue.slice(-1) === "0") {
11
+ newValue = newValue.slice(0, -1);
12
+ }
13
+ if (newValue.slice(-1) === ".") {
14
+ newValue = newValue.slice(0, -1);
15
+ }
16
+ }
17
+ return newValue;
18
+ }
19
+
20
+ function getPrecision(value, forceInteger) {
21
+ if (forceInteger) {
22
+ return value.toFixed(0);
23
+ }
24
+ return value.toFixed(1);
25
+ }
26
+
27
+ function formatIndicatorValue(value, forceInteger) {
28
+ if (value === undefined || isNaN(value) || value === null) {
29
+ return "-";
30
+ }
31
+ let nb = null;
32
+ if (Math.abs(value) > 999999) {
33
+ nb =
34
+ removeUseless0(
35
+ getPrecision(
36
+ (Math.sign(value) * Math.abs(value)) / 1000000,
37
+ forceInteger
38
+ )
39
+ ) + MILLIONS;
40
+ } else if (Math.abs(value) > 999) {
41
+ nb =
42
+ removeUseless0(
43
+ getPrecision(
44
+ (Math.sign(value) * Math.abs(value)) / 1000,
45
+ forceInteger
46
+ )
47
+ ) + THOUSANDS;
48
+ } else {
49
+ nb = removeUseless0(getPrecision(value, forceInteger));
50
+ }
51
+ return nb.replace(".", ",");
52
+ }
53
+
54
+ export { formatIndicatorValue };
@@ -0,0 +1,103 @@
1
+ import { fillMethodoSidePanel } from "./dom.mjs";
2
+
3
+ let buttonWhichOpenedPanel = null;
4
+
5
+ function closeSidePanel() {
6
+ const sidePanelGeo = document.getElementById("slide-panel-geo");
7
+ const sidePanelMethodo = document.getElementById("slide-panel-methodo");
8
+ sidePanelGeo.classList.remove("tdbmd-slide-panel--show");
9
+ sidePanelMethodo.classList.remove("tdbmd-slide-panel--show");
10
+ if (sidePanelGeo.style.display === "block") {
11
+ setTimeout(() => {
12
+ sidePanelGeo.style.display = "none";
13
+ }, 500);
14
+ }
15
+ if (sidePanelMethodo.style.display === "block") {
16
+ setTimeout(() => {
17
+ sidePanelMethodo.style.display = "none";
18
+ }, 500);
19
+ }
20
+ document.querySelectorAll(".validate-territory-btn").forEach((btn) => {
21
+ delete btn.dataset.comparison;
22
+ });
23
+ releaseFocusTrap();
24
+ if (buttonWhichOpenedPanel) {
25
+ buttonWhichOpenedPanel.focus();
26
+ } else {
27
+ document.getElementById("contenu").focus();
28
+ }
29
+ }
30
+
31
+ function openSidePanel(button, type, comparison = false) {
32
+ buttonWhichOpenedPanel = button;
33
+ const panelId = `slide-panel-${type}`;
34
+ const sidePanel = document.getElementById(panelId);
35
+ sidePanel.style.display = "block";
36
+ setTimeout(() => sidePanel.classList.add("tdbmd-slide-panel--show"), 100);
37
+ if (comparison) {
38
+ document.querySelectorAll(".validate-territory-btn").forEach((btn) => {
39
+ btn.dataset.comparison = "true";
40
+ });
41
+ }
42
+ sidePanel.querySelector("button").focus();
43
+ trapFocus(sidePanel);
44
+ }
45
+
46
+ let focusTrapListener;
47
+
48
+ function trapFocus(container) {
49
+ const focusableSelectors =
50
+ 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])';
51
+ const focusableElements = container.querySelectorAll(focusableSelectors);
52
+ const firstElement = focusableElements[0];
53
+ const lastElement = focusableElements[focusableElements.length - 1];
54
+
55
+ focusTrapListener = function (e) {
56
+ if (e.key === "Tab") {
57
+ if (e.shiftKey && document.activeElement === firstElement) {
58
+ e.preventDefault();
59
+ lastElement.focus();
60
+ } else if (!e.shiftKey && document.activeElement === lastElement) {
61
+ e.preventDefault();
62
+ firstElement.focus();
63
+ }
64
+ } else if (e.key === "Escape") {
65
+ closeSidePanel();
66
+ }
67
+ };
68
+
69
+ document.addEventListener("keydown", focusTrapListener);
70
+ }
71
+
72
+ function releaseFocusTrap() {
73
+ document.removeEventListener("keydown", focusTrapListener);
74
+ }
75
+
76
+ function openMethodoSidePanel(indicator, button) {
77
+ fillMethodoSidePanel(indicator);
78
+ openSidePanel(button, "methodo");
79
+ }
80
+
81
+ function addSidePanelListener() {
82
+ const button = document.querySelector(
83
+ 'button[aria-controls="slide-panel-geo"][data-comparison="false"]'
84
+ );
85
+ if (button) {
86
+ button.addEventListener("click", () => openSidePanel(button, "geo"));
87
+ }
88
+ const cmpButton = document.querySelector(
89
+ 'button[aria-controls="slide-panel-geo"][data-comparison="true"]'
90
+ );
91
+ if (cmpButton) {
92
+ cmpButton.addEventListener("click", () =>
93
+ openSidePanel(cmpButton, "geo", true)
94
+ );
95
+ }
96
+ document
97
+ .querySelectorAll('button[data-side-panel-close="true"]')
98
+ .forEach((closeButton) => {
99
+ closeButton.addEventListener("click", () => closeSidePanel());
100
+ });
101
+ }
102
+
103
+ export { openMethodoSidePanel, addSidePanelListener };
@@ -0,0 +1,89 @@
1
+ import {
2
+ getDataset,
3
+ getDates,
4
+ makeChart,
5
+ setBackgroundInDatasets,
6
+ } from "../utils.mjs";
7
+ import { getIndicatorDataScript, getParams } from "../dom.mjs";
8
+ import { formatIndicatorValue } from "../format.mjs";
9
+
10
+ function getScales(indicatorData) {
11
+ const { minDate, maxDate } = getDates(indicatorData);
12
+
13
+ function xTicksCallback(value) {
14
+ if (typeof value === "string") {
15
+ return value;
16
+ }
17
+ return value % 1 === 0 ? value.toString() : "";
18
+ }
19
+ function yTicksCallback(value) {
20
+ if (typeof value === "string") {
21
+ return value;
22
+ }
23
+
24
+ return formatIndicatorValue(value);
25
+ }
26
+
27
+ return {
28
+ x: {
29
+ type: "linear",
30
+ position: "bottom",
31
+ suggestedMax: maxDate,
32
+ suggestedMin: minDate,
33
+ ticks: {
34
+ stepSize: 0.2,
35
+ callback: xTicksCallback,
36
+ },
37
+ },
38
+ y: {
39
+ beginAtZero: true,
40
+ ticks: {
41
+ callback: yTicksCallback,
42
+ },
43
+ },
44
+ };
45
+ }
46
+
47
+ function makeHistoryChart(indicator, indicatorData) {
48
+ const ctx = document.querySelector(`#card-${indicator.id} .history-chart`);
49
+ const params = getParams();
50
+ const datasets = [
51
+ getDataset(params.territory_name, indicatorData, indicator),
52
+ ];
53
+ setBackgroundInDatasets(datasets);
54
+ const data = {
55
+ datasets,
56
+ };
57
+ const options = {
58
+ layout: {
59
+ padding: {
60
+ top: 40,
61
+ right: 100,
62
+ },
63
+ },
64
+ maintainAspectRatio: false,
65
+ plugins: {
66
+ legend: {
67
+ display: false,
68
+ },
69
+ datalabels: {
70
+ align: "top",
71
+ anchor: "end",
72
+ color: "black",
73
+ },
74
+ },
75
+ scales: getScales(indicatorData),
76
+ };
77
+ const chartType = indicatorData.length > 1 ? "line" : "bar";
78
+ makeChart(ctx, chartType, data, options);
79
+ }
80
+
81
+ function updateHistoryDOM(indicator) {
82
+ const indicatorData = getIndicatorDataScript(indicator, "values");
83
+ if (!indicatorData) {
84
+ return;
85
+ }
86
+ makeHistoryChart(indicator, indicatorData.values);
87
+ }
88
+
89
+ export { updateHistoryDOM };
@@ -0,0 +1,22 @@
1
+ import {
2
+ getIndicatorDataScript,
3
+ getIsAlternativeUnit,
4
+ removeDelaySpinner,
5
+ } from "../dom.mjs";
6
+ import { formatIndicatorValue } from "../format.mjs";
7
+
8
+ function updateMainValueDOM(indicator) {
9
+ const mainData = getIndicatorDataScript(indicator, "values");
10
+ if (!mainData) {
11
+ return;
12
+ }
13
+ const data = mainData.values[0];
14
+ const displayAlternative = getIsAlternativeUnit(indicator.id);
15
+ const val = displayAlternative ? data.valeur_alternative : data.valeur;
16
+ removeDelaySpinner(`#card-${indicator.id} .delay-spinner`);
17
+ document.querySelector(
18
+ `#card-${indicator.id} .main-value span:first-child`
19
+ ).textContent = `${formatIndicatorValue(val)}`;
20
+ }
21
+
22
+ export { updateMainValueDOM };
@@ -0,0 +1,162 @@
1
+ /* globals Chart, ChartDataLabels */
2
+
3
+ import {
4
+ delaySpinner,
5
+ getApiUrls,
6
+ getClosestIndicator,
7
+ getParams,
8
+ makeIndicatorDataScript,
9
+ } from "../dom.mjs";
10
+
11
+ import {
12
+ getIndicatorFilters,
13
+ handleFilterClick,
14
+ initializeFilters,
15
+ } from "../filters.mjs";
16
+ import { addSidePanelListener, openMethodoSidePanel } from "../side_panel.mjs";
17
+
18
+ import { exportImageAsync } from "../export-graph.mjs";
19
+ import { exportToCSV } from "../export.mjs";
20
+
21
+ import { updateHistoryDOM } from "./history.mjs";
22
+ import { updateMainValueDOM } from "./main-value.mjs";
23
+ import { updateStatisticsDOM } from "./statistics.mjs";
24
+
25
+ Chart.register(
26
+ Chart.CategoryScale,
27
+ Chart.LinearScale,
28
+ Chart.BarElement,
29
+ Chart.Title,
30
+ Chart.Tooltip,
31
+ Chart.Legend,
32
+ ChartDataLabels
33
+ );
34
+
35
+ function getSearchParams(indicator) {
36
+ const params = getParams();
37
+ const filters = getIndicatorFilters(indicator);
38
+ const filtersQuery = filters
39
+ .map(([dimension, filter]) => `&${dimension}=${filter}`)
40
+ .join("");
41
+ const searchParams = new URLSearchParams(
42
+ `territory=${params.territory_id}-${params.territory_mesh}&submesh=${params.mesh}${filtersQuery}`
43
+ ).toString();
44
+ return searchParams;
45
+ }
46
+
47
+ function callData(indicator) {
48
+ const apiUrls = getApiUrls(indicator);
49
+ const searchParams = getSearchParams(indicator);
50
+ [
51
+ [
52
+ "values",
53
+ (ind) => {
54
+ updateMainValueDOM(ind);
55
+ updateHistoryDOM(ind);
56
+ },
57
+ ],
58
+ ["statistics", updateStatisticsDOM],
59
+ ].forEach(async ([key, callbackUpdateDOM]) => {
60
+ const response = await fetch(`${apiUrls[key]}?${searchParams}`);
61
+ if (response.ok) {
62
+ const data = await response.json();
63
+ makeIndicatorDataScript(indicator, key, data);
64
+ callbackUpdateDOM(indicator);
65
+ }
66
+ });
67
+ }
68
+
69
+ function makeIndicatorCards() {
70
+ const subThemes = JSON.parse(
71
+ document.getElementById("sub-themes-js").textContent
72
+ );
73
+ subThemes.forEach((subTheme) => {
74
+ subTheme.indicators.forEach((indicator) => {
75
+ initializeFilters(indicator);
76
+ callData(indicator);
77
+ });
78
+ });
79
+ }
80
+
81
+ function toggleIndicatorUnit(input) {
82
+ const indicator = getClosestIndicator(input);
83
+ const unity = input.checked ? indicator.unite_alternative : indicator.unite;
84
+ const accessibleName = input.checked
85
+ ? indicator.unite_alternative_nom_accessible
86
+ : indicator.unite_nom_accessible;
87
+ Array.from(
88
+ document.querySelectorAll(`#card-${indicator.id} .unite`)
89
+ ).forEach((node) => {
90
+ node.innerText = unity;
91
+ node.setAttribute("aria-label", accessibleName);
92
+ });
93
+ const ariaLiveMessage = input.checked
94
+ ? `L'unité affichée est : ${indicator.unite_alternative_nom_accessible}`
95
+ : `L'unité affichée est : ${indicator.unite_nom_accessible}`;
96
+ document.getElementById(`${indicator.id}-toggle-unit-messages`).innerText =
97
+ ariaLiveMessage;
98
+ updateMainValueDOM(indicator);
99
+ updateStatisticsDOM(indicator);
100
+ updateHistoryDOM(indicator);
101
+ }
102
+
103
+ delaySpinner();
104
+ makeIndicatorCards();
105
+ document.querySelectorAll(".indicator-card").forEach((indicatorCard) => {
106
+ const indicator = getClosestIndicator(indicatorCard);
107
+
108
+ indicatorCard.querySelectorAll(".filter-tag").forEach((button) => {
109
+ button.addEventListener("click", async () => {
110
+ await handleFilterClick(indicator);
111
+ callData(indicator);
112
+ });
113
+ });
114
+
115
+ indicatorCard.querySelectorAll(".toggle-unite").forEach((input) => {
116
+ input.addEventListener("input", (event) => {
117
+ toggleIndicatorUnit(event.target);
118
+ });
119
+ });
120
+
121
+ indicatorCard
122
+ .querySelectorAll('button[aria-controls="slide-panel-methodo"]')
123
+ .forEach((button) => {
124
+ button.addEventListener("click", () => {
125
+ openMethodoSidePanel(indicator, button);
126
+ });
127
+ });
128
+ });
129
+
130
+ document.addEventListener("DOMContentLoaded", () => {
131
+ document.querySelectorAll(".toggle-unite").forEach((input) => {
132
+ toggleIndicatorUnit(input);
133
+ });
134
+ addSidePanelListener();
135
+ });
136
+
137
+ document
138
+ .querySelectorAll('button[data-type="export-csv"]')
139
+ .forEach((button) => {
140
+ const indicator = getClosestIndicator(button);
141
+ button.addEventListener("click", () => {
142
+ button.setAttribute("disabled", "true");
143
+ const searchParams = getSearchParams(indicator);
144
+ exportToCSV(button, indicator, button.dataset.route, searchParams);
145
+ });
146
+ });
147
+
148
+ document
149
+ .querySelectorAll('button[data-type="export-png"]')
150
+ .forEach((button) => {
151
+ const indicator = getClosestIndicator(button);
152
+ button.addEventListener("click", async () => {
153
+ button.setAttribute("disabled", "true");
154
+ // need to wait a small amount of time for DOM update
155
+ await new Promise((resolve) => setTimeout(resolve, 50));
156
+ await exportImageAsync(
157
+ button.parentElement.previousElementSibling,
158
+ `${indicator.name} - ${button.dataset.title}`
159
+ );
160
+ button.removeAttribute("disabled");
161
+ });
162
+ });
@@ -0,0 +1,42 @@
1
+ import {
2
+ getIndicatorDataScript,
3
+ getIsAlternativeUnit,
4
+ removeDelaySpinner,
5
+ } from "../dom.mjs";
6
+ import { formatIndicatorValue } from "../format.mjs";
7
+
8
+ function updateStatisticsDOM(indicator) {
9
+ const data = getIndicatorDataScript(indicator, "statistics");
10
+ if (!data) {
11
+ return;
12
+ }
13
+ const displayAlternative = getIsAlternativeUnit(indicator.id);
14
+ const alternative = displayAlternative ? "_alternative" : "";
15
+ ["min", "med", "max"].forEach((prefix) => {
16
+ removeDelaySpinner(`#card-${indicator.id} .delay-spinner`);
17
+ const key = `${prefix}${alternative}`;
18
+ const name = data[`code_${key}_name`];
19
+ if (name !== undefined) {
20
+ document.querySelector(
21
+ `#card-${indicator.id} .${prefix}-name`
22
+ ).textContent = name;
23
+ }
24
+ const value = data[key];
25
+ document.querySelector(
26
+ `#card-${indicator.id} .${prefix}-value > span:first-child`
27
+ ).textContent =
28
+ value === undefined ? "-" : `${formatIndicatorValue(value)}`;
29
+ const count = data[`count_${key}`];
30
+ if (count !== undefined) {
31
+ const text =
32
+ count > 1
33
+ ? `+${count - 1} autre${count - 1 > 1 ? "s" : ""}`
34
+ : "";
35
+ document.querySelector(
36
+ `#card-${indicator.id} .${prefix}-count`
37
+ ).textContent = text;
38
+ }
39
+ });
40
+ }
41
+
42
+ export { updateStatisticsDOM };