@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 CHANGED
@@ -73,4 +73,6 @@ Toutes les fonctions des classes SqlTime, SqlDate et SqlDateTime prennent mainte
73
73
  1.1.66
74
74
  Duration.convertToDurationAsCentieme() -> Duration.convertToDurationAsHundredthOfAnHour()
75
75
 
76
+ 1.3.0
77
+ HTTPRequest -> HTTPClient
76
78
 
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 = this.getNbDayBetweenTwo(jsPreviousDate, jsDate, false);
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 addDays(date, days) {
303
- date.setUTCDate(date.getUTCDate() + days);
304
- return date;
305
- }
323
+ static getPeriodLabels(data, period, locale = 'fr-FR', timeZone = 'Europe/Paris') {
324
+ if (!data || data.length === 0) {
325
+ return [];
326
+ }
306
327
 
307
- static addMonths(date, months) {
308
- let d = date.getDate();
309
- date.setMonth(date.getMonth() + +months);
310
- if (date.getDate() !== d) {
311
- date.setDate(0);
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
- return date;
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 DateTime.getNbDayBetweenTwo(this.parse(timestamp1), this.parse(timestamp2), asPeriod, timeZone);
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 DateTime.getNbDayBetweenTwo(SqlDateTime.parse(sqlDate1 + " 00:00:00"), SqlDateTime.parse(sqlDate2 + " 00:00:00"), asPeriod);
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 DateTime.getNbDayBetweenTwo(this.parse(sqlDateTime1), this.parse(sqlDateTime2), asPeriod);
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 { HTTPRequest, Cookie, UrlAndQueryString } = require('./network');
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, HTTPRequest, Cookie, UrlAndQueryString, IBAN, BankCard, AudioMedia, VideoMedia, UserMedia, PersonName, Email, TelephoneNumber, DateTime, TimestampUnix, SqlDate, SqlTime, SqlDateTime, Duration, File, CSV, Img, FormHelper, Country, PostalAddress, GeographicCoordinates, HexColor, RgbColor, SocialNetwork, NumberFormatter
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 HTTPRequest.formatQueryString
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 HTTPRequest.formatQueryString
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
- /** @deprecated */
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@osimatic/helpers-js",
3
- "version": "1.2.8",
3
+ "version": "1.3.1",
4
4
  "main": "main.js",
5
5
  "scripts": {
6
6
  "test": "echo \"Error: no test specified\" && exit 1"
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 };