@osimatic/helpers-js 1.2.8 → 1.3.1
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/CHANGELOG +2 -0
- package/chartjs.js +309 -0
- package/date_time.js +52 -15
- package/duration.js +1 -2
- package/index.js +6 -4
- package/network.js +3 -447
- package/package.json +1 -1
- package/user.js +36 -0
package/CHANGELOG
CHANGED
package/chartjs.js
ADDED
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
class Chartjs {
|
|
2
|
+
static init() {
|
|
3
|
+
if (typeof Chartjs.initialized == 'undefined' || Chartjs.initialized) {
|
|
4
|
+
return;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
Chartjs.initialized = true;
|
|
8
|
+
|
|
9
|
+
const centerTextPlugin = {
|
|
10
|
+
id: 'centerText',
|
|
11
|
+
afterDraw(chart) {
|
|
12
|
+
if (typeof chart.config.options.centerText == 'undefined' || !chart.config.options.centerText.display) {
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const { ctx, chartArea: { width, height } } = chart;
|
|
17
|
+
ctx.save();
|
|
18
|
+
const total = chart.data.datasets[0].data.reduce((a,b) => a+b, 0);
|
|
19
|
+
const label = chart.config.options.centerText.label || '';
|
|
20
|
+
const fontSize = chart.config.options.centerText.fontSize || 16;
|
|
21
|
+
const textColor = chart.config.options.centerText.color || '#333';
|
|
22
|
+
|
|
23
|
+
ctx.font = `bold ${fontSize}px sans-serif`;
|
|
24
|
+
ctx.fillStyle = textColor;
|
|
25
|
+
ctx.textAlign = 'center';
|
|
26
|
+
ctx.textBaseline = 'middle';
|
|
27
|
+
ctx.fillText(`${total}`, width / 2, height / 2);
|
|
28
|
+
if (label) {
|
|
29
|
+
ctx.font = `12px sans-serif`;
|
|
30
|
+
ctx.fillText(label, width / 2, height / 2 + 20);
|
|
31
|
+
}
|
|
32
|
+
ctx.restore();
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
Chart.register(centerTextPlugin);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
static createStackedChart(chartDiv, chartData, title=null, options={}) {
|
|
40
|
+
chartDiv.empty();
|
|
41
|
+
new Chart(chartDiv.get(0).getContext("2d"), $.extend(true, {}, {
|
|
42
|
+
type: "bar",
|
|
43
|
+
data: {
|
|
44
|
+
labels: chartData.labels,
|
|
45
|
+
datasets: chartData.datasets
|
|
46
|
+
},
|
|
47
|
+
options: {
|
|
48
|
+
responsive: true,
|
|
49
|
+
scales: {
|
|
50
|
+
x: {
|
|
51
|
+
stacked: true
|
|
52
|
+
},
|
|
53
|
+
y: {
|
|
54
|
+
stacked: true,
|
|
55
|
+
beginAtZero: true,
|
|
56
|
+
ticks: {
|
|
57
|
+
precision: 0
|
|
58
|
+
},
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
plugins: {
|
|
62
|
+
title: {
|
|
63
|
+
display: null !== title,
|
|
64
|
+
text: title || '',
|
|
65
|
+
font: { size: 14 },
|
|
66
|
+
color: "#333",
|
|
67
|
+
padding: { top: 10, bottom: 20 }
|
|
68
|
+
},
|
|
69
|
+
legend: {
|
|
70
|
+
position: "bottom",
|
|
71
|
+
labels: {
|
|
72
|
+
usePointStyle: true,
|
|
73
|
+
padding: 15
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
tooltip: {
|
|
77
|
+
callbacks: {
|
|
78
|
+
label: function(context) {
|
|
79
|
+
return `${context.dataset.label}: ${context.parsed.y}`;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}, options));
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
static createBarChart(chartDiv, chartData, title=null, options={}) {
|
|
89
|
+
chartDiv.empty();
|
|
90
|
+
new Chart(chartDiv.get(0).getContext("2d"), $.extend(true, {}, {
|
|
91
|
+
type: "bar",
|
|
92
|
+
data: {
|
|
93
|
+
labels: chartData.labels,
|
|
94
|
+
datasets: chartData.datasets
|
|
95
|
+
},
|
|
96
|
+
options: {
|
|
97
|
+
responsive: false,
|
|
98
|
+
maintainAspectRatio: false,
|
|
99
|
+
aspectRatio: 2,
|
|
100
|
+
scales: {
|
|
101
|
+
x: {
|
|
102
|
+
grid: {
|
|
103
|
+
display: false
|
|
104
|
+
},
|
|
105
|
+
/*ticks: {
|
|
106
|
+
font: { size: 12 }
|
|
107
|
+
}*/
|
|
108
|
+
},
|
|
109
|
+
y: {
|
|
110
|
+
beginAtZero: true,
|
|
111
|
+
ticks: {
|
|
112
|
+
precision: 0
|
|
113
|
+
//stepSize: 10, font: { size: 12 }
|
|
114
|
+
},
|
|
115
|
+
grid: {
|
|
116
|
+
color: "#eee"
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
plugins: {
|
|
121
|
+
title: {
|
|
122
|
+
display: null !== title,
|
|
123
|
+
text: title || '',
|
|
124
|
+
font: { size: 14 },
|
|
125
|
+
color: "#333",
|
|
126
|
+
padding: { top: 10, bottom: 20 }
|
|
127
|
+
},
|
|
128
|
+
legend: {
|
|
129
|
+
display: chartData.datasets.length > 1,
|
|
130
|
+
position: "bottom",
|
|
131
|
+
},
|
|
132
|
+
tooltip: {
|
|
133
|
+
callbacks: {
|
|
134
|
+
label: context => context.dataset.label + ' : ' + context.parsed.y
|
|
135
|
+
//label: (context) => `${context.formattedValue} pointages`
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
},
|
|
139
|
+
animation: {
|
|
140
|
+
duration: 1200,
|
|
141
|
+
easing: "easeOutQuart"
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}, options));
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
static createLineChart(chartDiv, chartData, title=null, options={}) {
|
|
148
|
+
Chartjs.init();
|
|
149
|
+
|
|
150
|
+
chartDiv.empty();
|
|
151
|
+
new Chart(chartDiv.get(0).getContext("2d"), $.extend(true, {}, {
|
|
152
|
+
type: "line",
|
|
153
|
+
data: {
|
|
154
|
+
labels: chartData.labels,
|
|
155
|
+
datasets: chartData.datasets
|
|
156
|
+
},
|
|
157
|
+
options: {
|
|
158
|
+
responsive: false,
|
|
159
|
+
maintainAspectRatio: false,
|
|
160
|
+
aspectRatio: 2,
|
|
161
|
+
scales: {
|
|
162
|
+
y: {
|
|
163
|
+
beginAtZero: true,
|
|
164
|
+
ticks: {
|
|
165
|
+
precision: 0
|
|
166
|
+
},
|
|
167
|
+
grid: {
|
|
168
|
+
color: "#eee"
|
|
169
|
+
}
|
|
170
|
+
},
|
|
171
|
+
x: {
|
|
172
|
+
grid: {
|
|
173
|
+
display: false
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
},
|
|
177
|
+
plugins: {
|
|
178
|
+
title: {
|
|
179
|
+
display: null !== title,
|
|
180
|
+
text: title || '',
|
|
181
|
+
font: { size: 14 },
|
|
182
|
+
color: "#333",
|
|
183
|
+
padding: { top: 10, bottom: 20 }
|
|
184
|
+
},
|
|
185
|
+
legend: {
|
|
186
|
+
display: chartData.datasets.length > 1,
|
|
187
|
+
position: "bottom",
|
|
188
|
+
},
|
|
189
|
+
tooltip: {
|
|
190
|
+
callbacks: {
|
|
191
|
+
label: context => context.dataset.label + ' : ' + context.parsed.y
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}, options));
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
static createDoughnutChart(chartDiv, chartData, title=null, options={}) {
|
|
200
|
+
Chartjs.init();
|
|
201
|
+
|
|
202
|
+
chartDiv.empty();
|
|
203
|
+
new Chart(chartDiv.get(0).getContext("2d"), $.extend(true, {}, {
|
|
204
|
+
type: "doughnut",
|
|
205
|
+
data: {
|
|
206
|
+
labels: chartData.labels,
|
|
207
|
+
datasets: [{
|
|
208
|
+
data: chartData.values,
|
|
209
|
+
backgroundColor: chartData.colors,
|
|
210
|
+
borderWidth: 0,
|
|
211
|
+
hoverOffset: 10
|
|
212
|
+
}]
|
|
213
|
+
},
|
|
214
|
+
options: {
|
|
215
|
+
cutout: "65%",
|
|
216
|
+
responsive: false,
|
|
217
|
+
maintainAspectRatio: false,
|
|
218
|
+
aspectRatio: 2,
|
|
219
|
+
plugins: {
|
|
220
|
+
title: {
|
|
221
|
+
display: null !== title,
|
|
222
|
+
text: title || ''
|
|
223
|
+
},
|
|
224
|
+
legend: {
|
|
225
|
+
position: "right",
|
|
226
|
+
labels: {
|
|
227
|
+
boxWidth: 12,
|
|
228
|
+
font: { size: 12 },
|
|
229
|
+
usePointStyle: true
|
|
230
|
+
}
|
|
231
|
+
},
|
|
232
|
+
tooltip: {
|
|
233
|
+
callbacks: {
|
|
234
|
+
label: function(context) {
|
|
235
|
+
const total = context.dataset.data.reduce((a,b)=>a+b,0);
|
|
236
|
+
const value = context.raw;
|
|
237
|
+
const percent = ((value / total) * 100).toFixed(1);
|
|
238
|
+
return `${context.label}: ${value} (${percent}%)`;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
},
|
|
243
|
+
animation: {
|
|
244
|
+
animateRotate: true,
|
|
245
|
+
animateScale: true
|
|
246
|
+
},
|
|
247
|
+
centerText: {
|
|
248
|
+
display: false,
|
|
249
|
+
fontSize: 18,
|
|
250
|
+
color: "#000"
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}, options));
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
static groupByPeriod(data, period, metrics) {
|
|
257
|
+
const grouped = {};
|
|
258
|
+
|
|
259
|
+
//data = Object.entries(dataObj).map(([date, values]) => ({ date, ...values }));
|
|
260
|
+
|
|
261
|
+
Object.entries(data).forEach(([date, values]) => {
|
|
262
|
+
//data.forEach(entry => {
|
|
263
|
+
const d = new Date(date);
|
|
264
|
+
let key;
|
|
265
|
+
|
|
266
|
+
if (period === 'week') {
|
|
267
|
+
const week = Math.ceil((d.getDate() - d.getDay() + 1) / 7);
|
|
268
|
+
key = `${d.getFullYear()}-S${week}`;
|
|
269
|
+
}
|
|
270
|
+
else if (period === 'month') {
|
|
271
|
+
key = `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}`;
|
|
272
|
+
}
|
|
273
|
+
else {
|
|
274
|
+
key = date;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
if (!grouped[key]) {
|
|
278
|
+
grouped[key] = {};
|
|
279
|
+
metrics.forEach(m => grouped[key][m] = []);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
metrics.forEach(m => {
|
|
283
|
+
if (values[m] !== undefined) grouped[key][m].push(values[m]);
|
|
284
|
+
});
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
return Object.entries(grouped).map(([label, vals]) => {
|
|
288
|
+
const aggregated = {};
|
|
289
|
+
metrics.forEach(m => {
|
|
290
|
+
aggregated[m] = vals[m].reduce((a, b) => a + b, 0) / vals[m].length;
|
|
291
|
+
});
|
|
292
|
+
return { label, ...aggregated };
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
static getPeriodLabels(data, period, locale = 'fr-FR', timeZone = 'Europe/Paris') {
|
|
297
|
+
return DatePeriod.getPeriodLabels(Object.keys(data), period, locale, timeZone);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
static getAutoGranularity(data) {
|
|
301
|
+
const dates = Object.keys(data);
|
|
302
|
+
const days = (new Date(dates[dates.length - 1]) - new Date(dates[0])) / (1000 * 60 * 60 * 24);
|
|
303
|
+
if (days > 90) return 'month';
|
|
304
|
+
if (days > 30) return 'week';
|
|
305
|
+
return 'day_of_month';
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
module.exports = { Chartjs };
|
package/date_time.js
CHANGED
|
@@ -122,7 +122,7 @@ class DateTime {
|
|
|
122
122
|
static getTimeDisplayWithNbDays(jsDate, jsPreviousDate, locale="fr-FR", timeZone="Europe/Paris") {
|
|
123
123
|
let str = this.getTimeDisplay(jsDate, locale, timeZone);
|
|
124
124
|
if (jsPreviousDate !== 0 && jsPreviousDate != null) {
|
|
125
|
-
let nbDaysDiff =
|
|
125
|
+
let nbDaysDiff = DatePeriod.getNbDayBetweenTwo(jsPreviousDate, jsDate, false);
|
|
126
126
|
if (nbDaysDiff > 0) {
|
|
127
127
|
str += ' (J+'+nbDaysDiff+')';
|
|
128
128
|
}
|
|
@@ -277,6 +277,27 @@ class DateTime {
|
|
|
277
277
|
return jsDateTime > today;
|
|
278
278
|
}
|
|
279
279
|
|
|
280
|
+
static addDays(date, days) {
|
|
281
|
+
date.setUTCDate(date.getUTCDate() + days);
|
|
282
|
+
return date;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
static addMonths(date, months) {
|
|
286
|
+
let d = date.getDate();
|
|
287
|
+
date.setMonth(date.getMonth() + +months);
|
|
288
|
+
if (date.getDate() !== d) {
|
|
289
|
+
date.setDate(0);
|
|
290
|
+
}
|
|
291
|
+
return date;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/** @deprecated use DatePeriod.getNbDayBetweenTwo instead */
|
|
295
|
+
static getNbDayBetweenTwo(jsDate1, jsDate2, asPeriod=false, timeZone="Europe/Paris") {
|
|
296
|
+
return DatePeriod.getNbDayBetweenTwo(jsDate1, jsDate2, asPeriod, timeZone);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
class DatePeriod {
|
|
280
301
|
static getNbDayBetweenTwo(jsDate1, jsDate2, asPeriod=false, timeZone="Europe/Paris") {
|
|
281
302
|
//jsDate1.set
|
|
282
303
|
if (jsDate1 == null || jsDate2 == null) {
|
|
@@ -299,18 +320,34 @@ class DateTime {
|
|
|
299
320
|
return parseInt(Math.round((timestamp2-timestamp1)/86400));
|
|
300
321
|
}
|
|
301
322
|
|
|
302
|
-
static
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
323
|
+
static getPeriodLabels(data, period, locale = 'fr-FR', timeZone = 'Europe/Paris') {
|
|
324
|
+
if (!data || data.length === 0) {
|
|
325
|
+
return [];
|
|
326
|
+
}
|
|
306
327
|
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
328
|
+
if (period === 'month') {
|
|
329
|
+
data.map(yearAndMonth => {
|
|
330
|
+
const [year, month] = yearAndMonth.split('-').map(Number);
|
|
331
|
+
return DateTime.getMonthNameByMonth(month, locale).capitalize()+' '+year;
|
|
332
|
+
});
|
|
312
333
|
}
|
|
313
|
-
|
|
334
|
+
if (period === 'week') {
|
|
335
|
+
return data.map(yearAndWeek => {
|
|
336
|
+
const [year, weekStr] = yearAndWeek.split('-S');
|
|
337
|
+
const week = parseInt(weekStr, 10);
|
|
338
|
+
return 'S'+week+' '+year;
|
|
339
|
+
});
|
|
340
|
+
}
|
|
341
|
+
if (period === 'day_of_week') {
|
|
342
|
+
return data.map(weekDay => DateTime.getDayNameByDayOfWeek(weekDay, locale).capitalize());
|
|
343
|
+
}
|
|
344
|
+
if (period === 'day_of_month') {
|
|
345
|
+
return data.map(sqlDate => SqlDate.getDateDigitalDisplay(sqlDate, locale, timeZone));
|
|
346
|
+
}
|
|
347
|
+
if (period === 'hour') {
|
|
348
|
+
return data.map(hour => String(hour).padStart(2, '0')+'h');
|
|
349
|
+
}
|
|
350
|
+
return data;
|
|
314
351
|
}
|
|
315
352
|
}
|
|
316
353
|
|
|
@@ -386,7 +423,7 @@ class TimestampUnix {
|
|
|
386
423
|
}
|
|
387
424
|
|
|
388
425
|
static getNbDayBetweenTwo(timestamp1, timestamp2, asPeriod=false, timeZone="Europe/Paris") {
|
|
389
|
-
return
|
|
426
|
+
return DatePeriod.getNbDayBetweenTwo(this.parse(timestamp1), this.parse(timestamp2), asPeriod, timeZone);
|
|
390
427
|
}
|
|
391
428
|
|
|
392
429
|
static isDateInThePast(timestamp) {
|
|
@@ -452,7 +489,7 @@ class SqlDate {
|
|
|
452
489
|
return DateTime.isDateInTheFuture(SqlDateTime.parse(sqlDate + " 00:00:00"));
|
|
453
490
|
}
|
|
454
491
|
static getNbDayBetweenTwo(sqlDate1, sqlDate2, asPeriod=false) {
|
|
455
|
-
return
|
|
492
|
+
return DatePeriod.getNbDayBetweenTwo(SqlDateTime.parse(sqlDate1 + " 00:00:00"), SqlDateTime.parse(sqlDate2 + " 00:00:00"), asPeriod);
|
|
456
493
|
}
|
|
457
494
|
}
|
|
458
495
|
|
|
@@ -585,9 +622,9 @@ class SqlDateTime {
|
|
|
585
622
|
}
|
|
586
623
|
|
|
587
624
|
static getNbDayBetweenTwo(sqlDateTime1, sqlDateTime2, asPeriod=false) {
|
|
588
|
-
return
|
|
625
|
+
return DatePeriod.getNbDayBetweenTwo(this.parse(sqlDateTime1), this.parse(sqlDateTime2), asPeriod);
|
|
589
626
|
}
|
|
590
627
|
|
|
591
628
|
}
|
|
592
629
|
|
|
593
|
-
module.exports = { DateTime, TimestampUnix, SqlDate, SqlTime, SqlDateTime };
|
|
630
|
+
module.exports = { DateTime, DatePeriod, TimestampUnix, SqlDate, SqlTime, SqlDateTime };
|
package/duration.js
CHANGED
|
@@ -69,9 +69,8 @@ class Duration {
|
|
|
69
69
|
|
|
70
70
|
// Minutes
|
|
71
71
|
let strMinute = '';
|
|
72
|
-
let nbMinutes = 0;
|
|
73
72
|
if (withMinutes) {
|
|
74
|
-
nbMinutes = this.getNbMinutesRemainingOfDurationInSeconds(durationInSeconds);
|
|
73
|
+
let nbMinutes = this.getNbMinutesRemainingOfDurationInSeconds(durationInSeconds);
|
|
75
74
|
strMinute += ' ';
|
|
76
75
|
//strMinute += sprintf('%02d', nbMinutes);
|
|
77
76
|
strMinute += nbMinutes.toString().padStart(2, '0');
|
package/index.js
CHANGED
|
@@ -8,11 +8,11 @@ require('./number');
|
|
|
8
8
|
|
|
9
9
|
// exports d'ojets non natif
|
|
10
10
|
const { HTTPClient } = require('./http_client');
|
|
11
|
-
const {
|
|
11
|
+
const { Cookie, UrlAndQueryString } = require('./network');
|
|
12
12
|
const { IBAN, BankCard } = require('./bank');
|
|
13
13
|
const { AudioMedia, VideoMedia, UserMedia } = require('./media');
|
|
14
14
|
const { PersonName, Email, TelephoneNumber } = require('./contact_details');
|
|
15
|
-
const { DateTime, TimestampUnix, SqlDate, SqlTime, SqlDateTime } = require('./date_time');
|
|
15
|
+
const { DateTime, DatePeriod, TimestampUnix, SqlDate, SqlTime, SqlDateTime } = require('./date_time');
|
|
16
16
|
const { Duration } = require('./duration');
|
|
17
17
|
const { File, CSV, Img } = require('./file');
|
|
18
18
|
const { FormHelper, EditValue } = require('./form_helper');
|
|
@@ -22,6 +22,7 @@ const { SocialNetwork } = require('./social_network');
|
|
|
22
22
|
const { sleep, refresh } = require('./util');
|
|
23
23
|
const { chr, ord, trim, empty } = require('./php.min');
|
|
24
24
|
const { NumberFormatter } = require('./number');
|
|
25
|
+
const { Password } = require('./user');
|
|
25
26
|
|
|
26
27
|
// exports plugins "maison"
|
|
27
28
|
const { Browser, UserAgent } = require('./visitor');
|
|
@@ -41,6 +42,7 @@ const { WebRTC } = require('./web_rtc');
|
|
|
41
42
|
const { EventBus } = require('./event_bus');
|
|
42
43
|
|
|
43
44
|
// exports surcouche lib externe
|
|
45
|
+
const { Chartjs } = require('./chartjs');
|
|
44
46
|
const { GoogleCharts } = require('./google_charts');
|
|
45
47
|
const { GoogleRecaptcha } = require('./google_recaptcha');
|
|
46
48
|
const { GoogleMap } = require('./google_maps');
|
|
@@ -49,8 +51,8 @@ const { WebSocket } = require('./web_socket');
|
|
|
49
51
|
|
|
50
52
|
module.exports = {
|
|
51
53
|
Array, Object, Number, String,
|
|
52
|
-
HTTPClient,
|
|
54
|
+
HTTPClient, Cookie, UrlAndQueryString, IBAN, BankCard, AudioMedia, VideoMedia, UserMedia, PersonName, Email, TelephoneNumber, DateTime, DatePeriod, TimestampUnix, SqlDate, SqlTime, SqlDateTime, Duration, File, CSV, Img, FormHelper, Country, PostalAddress, GeographicCoordinates, HexColor, RgbColor, SocialNetwork, NumberFormatter, Password,
|
|
53
55
|
Browser, DataTable, Pagination, Navigation, DetailsSubArray, SelectAll, MultipleActionInTable, MultipleActionInDivList, EditValue, FormDate, InputPeriod, ShoppingCart, FlashMessage, CountDown, ImportFromCsv, JwtToken, JwtSession, ApiTokenSession, ListBox, WebRTC, WebSocket, EventBus,
|
|
54
56
|
sleep, refresh, chr, ord, trim, empty,
|
|
55
|
-
GoogleCharts, GoogleRecaptcha, GoogleMap, OpenStreetMap
|
|
57
|
+
Chartjs, GoogleCharts, GoogleRecaptcha, GoogleMap, OpenStreetMap
|
|
56
58
|
};
|
package/network.js
CHANGED
|
@@ -221,7 +221,7 @@ class UrlAndQueryString {
|
|
|
221
221
|
if (typeof (object) == 'object') {
|
|
222
222
|
for (var name in object) {
|
|
223
223
|
value = object[name];
|
|
224
|
-
// 06/06/2022 : ajout de ce if pour éviter bug sur fonction
|
|
224
|
+
// 06/06/2022 : ajout de ce if pour éviter bug sur fonction HTTPClient.formatQueryString
|
|
225
225
|
if (typeof (value) == 'undefined') {
|
|
226
226
|
continue;
|
|
227
227
|
}
|
|
@@ -231,7 +231,7 @@ class UrlAndQueryString {
|
|
|
231
231
|
if (typeof (value) == 'object') {
|
|
232
232
|
buildStringFromParam(value, p + name);
|
|
233
233
|
}
|
|
234
|
-
// 06/06/2022 : ajout null !== value pour éviter bug sur fonction
|
|
234
|
+
// 06/06/2022 : ajout null !== value pour éviter bug sur fonction HTTPClient.formatQueryString
|
|
235
235
|
else if (null !== value && typeof (value) != 'function' && name != '') {
|
|
236
236
|
// 27/01/2020 : correction bug boolean affiché en string true/false
|
|
237
237
|
if (typeof (value) == 'boolean') {
|
|
@@ -309,448 +309,4 @@ class UrlAndQueryString {
|
|
|
309
309
|
|
|
310
310
|
}
|
|
311
311
|
|
|
312
|
-
|
|
313
|
-
class HTTPRequest {
|
|
314
|
-
static init() {
|
|
315
|
-
require('whatwg-fetch'); //fetch polyfill loaded in window.fetch
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
static setRefreshTokenUrl(url) {
|
|
319
|
-
this.refreshTokenUrl = url;
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
static setRefreshTokenCallback(callback) {
|
|
323
|
-
this.refreshTokenCallback = callback;
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
static getHeaders(asObject) {
|
|
327
|
-
if (typeof this.headers == 'undefined') {
|
|
328
|
-
this.headers = {};
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
if (typeof asObject != 'undefined' && asObject) {
|
|
332
|
-
return this.headers;
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
let httpHeaders = new Headers();
|
|
336
|
-
Object.entries(this.headers).forEach(([key, value]) => {
|
|
337
|
-
httpHeaders.append(key, value);
|
|
338
|
-
});
|
|
339
|
-
|
|
340
|
-
return httpHeaders;
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
static getHeader(key) {
|
|
344
|
-
if (typeof this.headers == 'undefined') {
|
|
345
|
-
this.headers = {};
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
return this.headers[key];
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
static setHeader(key, value) {
|
|
352
|
-
if (typeof this.headers == 'undefined') {
|
|
353
|
-
this.headers = {};
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
this.headers[key] = value;
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
static setAuthorizationHeader(accessToken) {
|
|
360
|
-
if (typeof this.headers == 'undefined') {
|
|
361
|
-
this.headers = {};
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
this.headers['Authorization'] = 'Bearer ' + accessToken;
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
static convertObjectToFormData(obj) {
|
|
368
|
-
// 30/05/2022 : ancienne version, qui ne fonctionne pas avec des tableaux
|
|
369
|
-
// let formData = new FormData();
|
|
370
|
-
// Object.entries(data).forEach(([key, value]) => formData.append(key, value));
|
|
371
|
-
// return formData;
|
|
372
|
-
|
|
373
|
-
var formData = new FormData();
|
|
374
|
-
|
|
375
|
-
function appendFormData(data, root) {
|
|
376
|
-
//console.log('appendFormData', data, root);
|
|
377
|
-
root = root || '';
|
|
378
|
-
if (data instanceof File) {
|
|
379
|
-
formData.append(root, data);
|
|
380
|
-
} else if (Array.isArray(data)) {
|
|
381
|
-
for (var i = 0; i < data.length; i++) {
|
|
382
|
-
appendFormData(data[i], root + '[' + i + ']');
|
|
383
|
-
}
|
|
384
|
-
} else if (typeof data === 'object' && data) {
|
|
385
|
-
for (var key in data) {
|
|
386
|
-
if (data.hasOwnProperty(key)) {
|
|
387
|
-
if (root === '') {
|
|
388
|
-
appendFormData(data[key], key);
|
|
389
|
-
} else {
|
|
390
|
-
appendFormData(data[key], root + '.' + key);
|
|
391
|
-
}
|
|
392
|
-
}
|
|
393
|
-
}
|
|
394
|
-
} else {
|
|
395
|
-
if (data !== null && typeof data !== 'undefined') {
|
|
396
|
-
formData.append(root, data);
|
|
397
|
-
}
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
appendFormData(obj);
|
|
402
|
-
|
|
403
|
-
return formData;
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
static formatQueryString(data) {
|
|
407
|
-
if (data == null) {
|
|
408
|
-
return '';
|
|
409
|
-
}
|
|
410
|
-
if (typeof data == 'object') {
|
|
411
|
-
data = UrlAndQueryString.buildQuery(data);
|
|
412
|
-
}
|
|
413
|
-
if (data !== '' && data.substring(0, 1) !== '&') {
|
|
414
|
-
data = '&' + data;
|
|
415
|
-
}
|
|
416
|
-
return data;
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
static formatFormData(data) {
|
|
420
|
-
if (!(data instanceof FormData)) {
|
|
421
|
-
return HTTPRequest.convertObjectToFormData(data);
|
|
422
|
-
}
|
|
423
|
-
return data;
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
static logRequestFailure(response, json) {
|
|
427
|
-
console.error('Request failure. Status: ' + response.statusText + ' ; HTTP Code : ' + response.status, json);
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
static logJqueryRequestFailure(jqxhr, status, errorThrown) {
|
|
431
|
-
console.error('Request failure. Status: ' + status + ' ; HTTP Code: ' + jqxhr.status + (null != errorThrown && '' !== errorThrown ? ' ; Error message: ' + errorThrown : ''), jqxhr.responseJSON);
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
static isExpiredToken(response, json) {
|
|
435
|
-
if (response.status !== 401) {
|
|
436
|
-
return false;
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
return (
|
|
440
|
-
response.statusText === 'Expired JWT Token'
|
|
441
|
-
|| (typeof json['message'] != 'undefined' && json['message'] === 'Expired JWT Token')
|
|
442
|
-
|| (typeof json['error'] != 'undefined' && json['error'] === 'expired_token')
|
|
443
|
-
|| (typeof json['error'] != 'undefined' && json['error'] === 'authentification_failure')
|
|
444
|
-
|| (json === 'expired_token')
|
|
445
|
-
|| (json === 'authentification_failure')
|
|
446
|
-
);
|
|
447
|
-
}
|
|
448
|
-
|
|
449
|
-
static async get(url, data, successCallback, errorCallback) {
|
|
450
|
-
url += (!url.includes('?') ? '?' : '') + this.formatQueryString(data);
|
|
451
|
-
data = null;
|
|
452
|
-
|
|
453
|
-
if (window.fetch) {
|
|
454
|
-
const response = await fetch(url, {
|
|
455
|
-
method: 'GET',
|
|
456
|
-
headers: HTTPRequest.getHeaders(),
|
|
457
|
-
mode: 'cors',
|
|
458
|
-
cache: 'no-cache'
|
|
459
|
-
});
|
|
460
|
-
|
|
461
|
-
let jsonData = {};
|
|
462
|
-
try {
|
|
463
|
-
jsonData = await response.json();
|
|
464
|
-
|
|
465
|
-
if (HTTPRequest.isExpiredToken(response, jsonData)) {
|
|
466
|
-
HTTPRequest.refreshToken(() => HTTPRequest.get(url, data, successCallback, errorCallback), errorCallback);
|
|
467
|
-
return;
|
|
468
|
-
}
|
|
469
|
-
|
|
470
|
-
if (response.ok) {
|
|
471
|
-
successCallback(jsonData, response);
|
|
472
|
-
return;
|
|
473
|
-
}
|
|
474
|
-
} catch (e) {
|
|
475
|
-
console.error(e);
|
|
476
|
-
if (typeof errorCallback != 'undefined' && errorCallback != null) {
|
|
477
|
-
errorCallback(response);
|
|
478
|
-
}
|
|
479
|
-
return;
|
|
480
|
-
}
|
|
481
|
-
|
|
482
|
-
HTTPRequest.logRequestFailure(response, jsonData);
|
|
483
|
-
if (typeof errorCallback != 'undefined' && errorCallback != null) {
|
|
484
|
-
errorCallback(response, jsonData);
|
|
485
|
-
}
|
|
486
|
-
return;
|
|
487
|
-
}
|
|
488
|
-
|
|
489
|
-
//l'api fetch n'est pas dispo pour ce navigateur => normalement ce cas ne devrait pas arriver car le polyfill est chargé dans la méthode init
|
|
490
|
-
$.ajax({
|
|
491
|
-
type: 'GET',
|
|
492
|
-
url: url,
|
|
493
|
-
headers: HTTPRequest.getHeaders(true),
|
|
494
|
-
dataType: 'json',
|
|
495
|
-
cache: false,
|
|
496
|
-
success: (data, status, jqxhr) => {
|
|
497
|
-
if (typeof successCallback != 'undefined' && successCallback != null) {
|
|
498
|
-
successCallback(data, jqxhr);
|
|
499
|
-
}
|
|
500
|
-
},
|
|
501
|
-
error: (jqxhr, status, errorThrown) => {
|
|
502
|
-
if (HTTPRequest.isExpiredToken(jqxhr, jqxhr.responseJSON)) {
|
|
503
|
-
HTTPRequest.refreshToken(() => HTTPRequest.get(url, data, successCallback, errorCallback), errorCallback);
|
|
504
|
-
return;
|
|
505
|
-
}
|
|
506
|
-
|
|
507
|
-
HTTPRequest.logJqueryRequestFailure(jqxhr, status, errorThrown);
|
|
508
|
-
if (typeof errorCallback != 'undefined' && errorCallback != null) {
|
|
509
|
-
errorCallback(jqxhr, jqxhr.responseJSON);
|
|
510
|
-
}
|
|
511
|
-
}
|
|
512
|
-
});
|
|
513
|
-
}
|
|
514
|
-
|
|
515
|
-
static async download(url, data, errorCallback, completeCallback, method) {
|
|
516
|
-
method = typeof method == 'undefined' || null == method ? 'GET' : method;
|
|
517
|
-
|
|
518
|
-
if ('POST' !== method) {
|
|
519
|
-
url += (!url.includes('?') ? '?' : '') + this.formatQueryString(data);
|
|
520
|
-
data = null;
|
|
521
|
-
}
|
|
522
|
-
|
|
523
|
-
if (window.fetch) {
|
|
524
|
-
let requestInit = {
|
|
525
|
-
method: 'GET',
|
|
526
|
-
headers: HTTPRequest.getHeaders(),
|
|
527
|
-
mode: 'cors',
|
|
528
|
-
cache: 'no-cache'
|
|
529
|
-
}
|
|
530
|
-
|
|
531
|
-
if ('POST' === method) {
|
|
532
|
-
requestInit['method'] = 'POST';
|
|
533
|
-
requestInit['body'] = this.formatFormData(data);
|
|
534
|
-
}
|
|
535
|
-
|
|
536
|
-
const response = await fetch(url, requestInit);
|
|
537
|
-
try {
|
|
538
|
-
if (response.status === 401 && response.statusText === 'Expired JWT Token') {
|
|
539
|
-
HTTPRequest.refreshToken(() => HTTPRequest.download(url, data, errorCallback, completeCallback, method), errorCallback);
|
|
540
|
-
return;
|
|
541
|
-
}
|
|
542
|
-
|
|
543
|
-
if (response.ok) {
|
|
544
|
-
const blobData = await response.blob();
|
|
545
|
-
File.download(blobData, response.headers.get('content-type'), response.headers.get('content-disposition'));
|
|
546
|
-
} else {
|
|
547
|
-
HTTPRequest.logRequestFailure(response, null);
|
|
548
|
-
if (typeof errorCallback != 'undefined' && errorCallback != null) {
|
|
549
|
-
errorCallback(response);
|
|
550
|
-
}
|
|
551
|
-
}
|
|
552
|
-
} catch (e) {
|
|
553
|
-
console.error(e);
|
|
554
|
-
if (typeof errorCallback != 'undefined' && errorCallback != null) {
|
|
555
|
-
errorCallback(response);
|
|
556
|
-
}
|
|
557
|
-
}
|
|
558
|
-
if (typeof completeCallback != 'undefined' && completeCallback != null) {
|
|
559
|
-
completeCallback(response);
|
|
560
|
-
}
|
|
561
|
-
return;
|
|
562
|
-
}
|
|
563
|
-
|
|
564
|
-
//l'api fetch n'est pas dispo pour ce navigateur => normalement ce cas ne devrait pas arriver car le polyfill est chargé dans la méthode init
|
|
565
|
-
let ajaxOptions = {
|
|
566
|
-
type: 'GET',
|
|
567
|
-
url: url,
|
|
568
|
-
headers: HTTPRequest.getHeaders(true),
|
|
569
|
-
cache: false,
|
|
570
|
-
xhrFields: {
|
|
571
|
-
responseType: 'blob'
|
|
572
|
-
},
|
|
573
|
-
};
|
|
574
|
-
if ('POST' === method) {
|
|
575
|
-
ajaxOptions['type'] = 'POST';
|
|
576
|
-
ajaxOptions['data'] = this.formatFormData(data);
|
|
577
|
-
ajaxOptions['contentType'] = false;
|
|
578
|
-
ajaxOptions['processData'] = false;
|
|
579
|
-
}
|
|
580
|
-
|
|
581
|
-
$.ajax(Object.assign({...ajaxOptions}, {
|
|
582
|
-
success: (data, status, jqxhr) => File.download(data, jqxhr.getResponseHeader('Content-Type'), jqxhr.getResponseHeader('Content-Disposition')),
|
|
583
|
-
error: (jqxhr, status, errorThrown) => {
|
|
584
|
-
if (HTTPRequest.isExpiredToken(jqxhr, jqxhr.responseJSON)) {
|
|
585
|
-
HTTPRequest.refreshToken(() => HTTPRequest.download(url, data, errorCallback, completeCallback, method), errorCallback);
|
|
586
|
-
return;
|
|
587
|
-
}
|
|
588
|
-
|
|
589
|
-
HTTPRequest.logJqueryRequestFailure(jqxhr, status, errorThrown);
|
|
590
|
-
if (typeof errorCallback != 'undefined' && errorCallback != null) {
|
|
591
|
-
errorCallback(jqxhr);
|
|
592
|
-
}
|
|
593
|
-
},
|
|
594
|
-
complete: (jqxhr) => {
|
|
595
|
-
if (typeof completeCallback != 'undefined' && completeCallback != null) {
|
|
596
|
-
completeCallback(jqxhr);
|
|
597
|
-
}
|
|
598
|
-
}
|
|
599
|
-
}));
|
|
600
|
-
}
|
|
601
|
-
|
|
602
|
-
static async post(url, formData, successCallback, errorCallback, formErrorCallback) {
|
|
603
|
-
formData = this.formatFormData(formData);
|
|
604
|
-
|
|
605
|
-
if (window.fetch) {
|
|
606
|
-
const response = await fetch(url, {
|
|
607
|
-
method: 'POST',
|
|
608
|
-
body: formData,
|
|
609
|
-
headers: HTTPRequest.getHeaders(),
|
|
610
|
-
mode: 'cors',
|
|
611
|
-
cache: 'no-cache'
|
|
612
|
-
});
|
|
613
|
-
|
|
614
|
-
let jsonData = {};
|
|
615
|
-
try {
|
|
616
|
-
if (response.status !== 204 && response.statusText !== 'No Content') {
|
|
617
|
-
jsonData = await response.json();
|
|
618
|
-
}
|
|
619
|
-
//console.log(url, jsonData);
|
|
620
|
-
|
|
621
|
-
if (url !== HTTPRequest.refreshTokenUrl && HTTPRequest.isExpiredToken(response, jsonData)) {
|
|
622
|
-
HTTPRequest.refreshToken(() => HTTPRequest.post(url, formData, successCallback, errorCallback, formErrorCallback), errorCallback);
|
|
623
|
-
return;
|
|
624
|
-
}
|
|
625
|
-
|
|
626
|
-
if (response.ok) {
|
|
627
|
-
if (typeof successCallback != 'undefined' && successCallback != null) {
|
|
628
|
-
successCallback(jsonData, response);
|
|
629
|
-
}
|
|
630
|
-
return;
|
|
631
|
-
}
|
|
632
|
-
|
|
633
|
-
if (response.status === 400 && typeof formErrorCallback != 'undefined' && formErrorCallback != null) {
|
|
634
|
-
formErrorCallback(jsonData, response);
|
|
635
|
-
return;
|
|
636
|
-
}
|
|
637
|
-
} catch (e) {
|
|
638
|
-
console.error(e);
|
|
639
|
-
if (typeof errorCallback != 'undefined' && errorCallback != null) {
|
|
640
|
-
errorCallback(response);
|
|
641
|
-
}
|
|
642
|
-
return;
|
|
643
|
-
}
|
|
644
|
-
|
|
645
|
-
HTTPRequest.logRequestFailure(response, jsonData);
|
|
646
|
-
if (typeof errorCallback != 'undefined' && errorCallback != null) {
|
|
647
|
-
errorCallback(response, jsonData);
|
|
648
|
-
}
|
|
649
|
-
return;
|
|
650
|
-
}
|
|
651
|
-
|
|
652
|
-
//l'api fetch n'est pas dispo pour ce navigateur => normalement ce cas ne devrait pas arriver car le polyfill est chargé dans la méthode init
|
|
653
|
-
$.ajax({
|
|
654
|
-
type: 'POST',
|
|
655
|
-
url: url,
|
|
656
|
-
headers: HTTPRequest.getHeaders(true),
|
|
657
|
-
dataType: 'json', // 22/09/2020 : à voir si cette ligne pose pb (utilisé pour requete import et peut être d'autres
|
|
658
|
-
data: formData,
|
|
659
|
-
cache: false,
|
|
660
|
-
contentType: false,
|
|
661
|
-
processData: false,
|
|
662
|
-
success: (data, status, jqxhr) => {
|
|
663
|
-
if (typeof successCallback != 'undefined' && successCallback != null) {
|
|
664
|
-
successCallback(data, jqxhr);
|
|
665
|
-
}
|
|
666
|
-
},
|
|
667
|
-
error: (jqxhr, status, errorThrown) => {
|
|
668
|
-
if (url !== HTTPRequest.refreshTokenUrl && HTTPRequest.isExpiredToken(jqxhr, jqxhr.responseJSON)) {
|
|
669
|
-
HTTPRequest.refreshToken(() => HTTPRequest.post(url, formData, successCallback, errorCallback, formErrorCallback), errorCallback);
|
|
670
|
-
return;
|
|
671
|
-
}
|
|
672
|
-
if (jqxhr.status === 400 && typeof formErrorCallback != 'undefined' && formErrorCallback != null) {
|
|
673
|
-
formErrorCallback(jqxhr.responseJSON, jqxhr);
|
|
674
|
-
return;
|
|
675
|
-
}
|
|
676
|
-
|
|
677
|
-
HTTPRequest.logJqueryRequestFailure(jqxhr, status, errorThrown);
|
|
678
|
-
if (typeof errorCallback != 'undefined' && errorCallback != null) {
|
|
679
|
-
errorCallback(jqxhr, jqxhr.responseJSON);
|
|
680
|
-
}
|
|
681
|
-
}
|
|
682
|
-
});
|
|
683
|
-
}
|
|
684
|
-
|
|
685
|
-
static refreshToken(onCompleteCallback, errorCallback) {
|
|
686
|
-
if (typeof this.refreshTokenCallback == 'function') {
|
|
687
|
-
this.refreshTokenCallback(onCompleteCallback);
|
|
688
|
-
return;
|
|
689
|
-
}
|
|
690
|
-
|
|
691
|
-
if (typeof this.refreshTokenUrl == 'undefined') {
|
|
692
|
-
console.error('URL refresh token non définie. Appeler HTTPRequest.setRefreshTokenUrl(url)');
|
|
693
|
-
return;
|
|
694
|
-
}
|
|
695
|
-
|
|
696
|
-
let payload = new FormData();
|
|
697
|
-
payload.append('refresh_token', JwtSession.getRefreshToken());
|
|
698
|
-
|
|
699
|
-
HTTPRequest.post(this.refreshTokenUrl, payload,
|
|
700
|
-
(data) => {
|
|
701
|
-
JwtSession.setToken(data.token);
|
|
702
|
-
JwtSession.setRefreshToken(data.refresh_token);
|
|
703
|
-
|
|
704
|
-
HTTPRequest.setAuthorizationHeader(JwtSession.getToken());
|
|
705
|
-
|
|
706
|
-
onCompleteCallback();
|
|
707
|
-
},
|
|
708
|
-
() => {
|
|
709
|
-
JwtSession.logout();
|
|
710
|
-
errorCallback();
|
|
711
|
-
}
|
|
712
|
-
);
|
|
713
|
-
}
|
|
714
|
-
|
|
715
|
-
static doRequest(url, strParam, methode, formatRetour, callback) {
|
|
716
|
-
var xhr = null;
|
|
717
|
-
|
|
718
|
-
if (window.XMLHttpRequest || window.ActiveXObject) {
|
|
719
|
-
if (window.ActiveXObject) {
|
|
720
|
-
try {
|
|
721
|
-
xhr = new ActiveXObject('Msxml2.XMLHTTP');
|
|
722
|
-
} catch (e) {
|
|
723
|
-
xhr = new ActiveXObject('Microsoft.XMLHTTP');
|
|
724
|
-
}
|
|
725
|
-
} else {
|
|
726
|
-
xhr = new XMLHttpRequest();
|
|
727
|
-
}
|
|
728
|
-
} else {
|
|
729
|
-
// Votre navigateur ne supporte pas l'objet XMLHTTPRequest!
|
|
730
|
-
return null;
|
|
731
|
-
}
|
|
732
|
-
|
|
733
|
-
xhr.onreadystatechange = function () {
|
|
734
|
-
if (xhr.readyState == 4 && (xhr.status == 200 || xhr.status == 0)) {
|
|
735
|
-
let data;
|
|
736
|
-
if (formatRetour == 'xml') {
|
|
737
|
-
data = xhr.responseXML;
|
|
738
|
-
} else {
|
|
739
|
-
data = eval('(' + xhr.responseText + ')');
|
|
740
|
-
}
|
|
741
|
-
callback(data);
|
|
742
|
-
}
|
|
743
|
-
};
|
|
744
|
-
|
|
745
|
-
if (methode === 'POST') {
|
|
746
|
-
xhr.open('POST', url, true);
|
|
747
|
-
xhr.send();
|
|
748
|
-
} else {
|
|
749
|
-
xhr.open('GET', url + '?' + strParam, true);
|
|
750
|
-
xhr.send(null);
|
|
751
|
-
}
|
|
752
|
-
return false;
|
|
753
|
-
}
|
|
754
|
-
}
|
|
755
|
-
|
|
756
|
-
module.exports = {HTTPRequest, Cookie, UrlAndQueryString};
|
|
312
|
+
module.exports = { Cookie, UrlAndQueryString };
|
package/package.json
CHANGED
package/user.js
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
class Password {
|
|
2
|
+
static getPasswordStrength(password) {
|
|
3
|
+
let score = 0;
|
|
4
|
+
|
|
5
|
+
if (password.length >= 8) score++;
|
|
6
|
+
if (/[A-Z]/.test(password)) score++;
|
|
7
|
+
if (/[a-z]/.test(password)) score++;
|
|
8
|
+
if (/[0-9]/.test(password)) score++;
|
|
9
|
+
if (/[^A-Za-z0-9]/.test(password)) score++;
|
|
10
|
+
|
|
11
|
+
if (password.length > 12 && score >= 4) score++; // Bonus pour long mot de passe
|
|
12
|
+
|
|
13
|
+
return score;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
static updatePasswordStrengthUI(div, password) {
|
|
17
|
+
const score = Password.getPasswordStrength(password);
|
|
18
|
+
|
|
19
|
+
const strengthBar = div.find('.password_strength_bar');
|
|
20
|
+
const strengthText = div.find('.password_strength_text');
|
|
21
|
+
|
|
22
|
+
let width = (score / 6) * 100;
|
|
23
|
+
let color = 'bg-danger';
|
|
24
|
+
let text = 'Très faible';
|
|
25
|
+
|
|
26
|
+
if (score >= 2) { color = 'bg-warning'; text = 'Faible'; }
|
|
27
|
+
if (score >= 4) { color = 'bg-info'; text = 'Moyen'; }
|
|
28
|
+
if (score >= 5) { color = 'bg-success'; text = 'Fort'; }
|
|
29
|
+
|
|
30
|
+
strengthBar.className = `progress-bar ${color}`;
|
|
31
|
+
strengthBar.style.width = `${width}%`;
|
|
32
|
+
strengthText.textContent = text;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
module.exports = { Password };
|