PageSourceSearch

https://odf.univ-spn.fr/plugins/cms/resources/js/AmetysFront/Utils.fr.js

js univ-spn.fr collected 2026-10-01 10:38:25 UTC 13,772 bytes, 391 lines download raw bytes

1/*
2 *  Copyright 2023 Anyware Services
3 *
4 *  Licensed under the Apache License, Version 2.0 (the "License");
5 *  you may not use this file except in compliance with the License.
6 *  You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 *  Unless required by applicable law or agreed to in writing, software
11 *  distributed under the License is distributed on an "AS IS" BASIS,
12 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 *  See the License for the specific language governing permissions and
14 *  limitations under the License.
15 */
16 
17AmetysFront.Utils = {
18
19    /**
20     * OBSOLETE Use toRelativeDate
21     * Get a readable date, with relative time (eg: '4 days ago') for duration less that 7 days by default.
22     * @param {String} date The raw date
23     * @param {Number} [relativeLimit=7] limit in days for relative date 
24     * @param {Number} [withoutRelativeSuffix=false] true to get the relative time without the suffix (eg: '4 days'). UNUSED
25     * @param {Boolean} [withTime=false] true to format date with hours
26     * @return {String} the readable date
27     */
28    toMomentDate: function (date, relativeLimit, withoutRelativeSuffix, withTime)
29    {
30        return AmetysFront.Utils.toRelativeDate(date, {
31            relativeLimit: relativeLimit,
32            withTime: withTime === false ? false : true
33        })
34    },
35        
36    /**
37     * Get a readable date, with relative time (eg: '4 days ago') for duration less that 7 days by default.
38     * @param {String} date The raw date
39     * @param {Object} config The transformation config
40     * @param {Number} [config.relativeLimit=7] limit in days for relative date 
41     * @param {String} [config.weekday=undefined] Can be "long", "short", "narrow" or undefined.
42     * @param {String} [config.month="long"] Can be "numeric", "2-digit", "long", "short" or "narrow".
43     * @param {Boolean} [config.withTime=false] To display time
44     * @param {Boolean} [config.withSeconds=false] Only when withTime is true, to display seconds
45     * @param {Boolean} [config.locale=AmetysFront.getAppParameter("locale")] The locale code such as: en, fr...
46     * @return {String} the readable relative date
47     */
48    toRelativeDate: function (date, config)
49    {
50        // The number of days of diff
51        function _daysDiff(d1, d2)
52        {
53            d1 = new Date(d1);
54            d1.setHours(0, 0, 0, 0); // at midnight
55            
56            d2 = new Date(d2);
57            d2.setHours(0, 0, 0, 0); // at midnight
58            
59            return (d1 - d2) / (24 * 60 * 60 * 1000);
60        }
61        
62        config = config || {};
63        
64        let locale = config.locale || AmetysFront.getAppParameter("locale");
65        
66        let relativeLimit = config.relativeLimit || 7;
67        
68        let withTime = config.withTime === true;
69        let month = config.month || "long";
70        
71        let now = new Date();
72        let relativeDate = new Date(date);
73        
74        let daysDiff = _daysDiff(now, relativeDate);
75        let timeDiff = (now - relativeDate) / 1000;
76        
77        if (timeDiff < -59) // issue in user/server time-sync can lead to a close past event to appear in the near future
78        {
79            // Future dates are not supported
80            return AmetysFront.Utils.toReadableDate(date, {
81                "weekday": config.weekday,
82                "month": month,
83                "withTime": withTime,
84                "withSeconds": config.withSeconds,
85                "locale": locale
86            });
87        }
88        
89        let dayText = "";
90        if (Math.min(relativeLimit, 7) <= daysDiff)
91        {
92            if (now.getFullYear() === relativeDate.getFullYear())
93            {
94                // novembre 12
95                dayText = relativeDate.toLocaleString(locale, {
96                    "weekday": config.weekday,
97                    "day": "numeric", 
98                    "month": month
99                });
100            }
101            else
102            {
103                // november 12, 2023
104                dayText = relativeDate.toLocaleString(locale, {
105                    "weekday": config.weekday,
106                    "day": "numeric", 
107                    "month": month,
108                    "year": "numeric"
109                });
110            }
111        }
112        else
113        {
114            // Less than a week, and less than the configured limit
115            switch(daysDiff)
116            {
117                case 0: // today
118                    dayText = new Intl.RelativeTimeFormat(locale, { numeric: "auto" }).format(0, "day");
119                    break;
120                case 1: // yesterday
121                    dayText = new Intl.RelativeTimeFormat(locale, { numeric: "auto" }).format(-1, "day");
122                    break;
123                default: // friday
124                    dayText = relativeDate.toLocaleString(locale, {
125                        "weekday": "long" // not using config.weekday that is for long dates
126                    });
127            }
128        }
129        
130        if (withTime && daysDiff == 0)
131        {
132            if (timeDiff < 60) // a few seconds ago
133            {
134                return "il y a quelques secondes"; 
135            }
136            else if (timeDiff < 3600) // x minutes ago
137            {
138                return new Intl.RelativeTimeFormat(locale, { numeric: "auto" }).format(- Math.floor(timeDiff/60), "minutes");
139            }
140            else if (timeDiff < 3*3600) // x hours ago
141            {
142                return new Intl.RelativeTimeFormat(locale, { numeric: "auto" }).format(- Math.floor(timeDiff/60/60), "hours");
143            }
144            else // xx:yy
145            {
146                return relativeDate.toLocaleTimeString(locale, {
147                    hour: 'numeric', 
148                    minute:'2-digit'
149                });
150            }
151        }
152        else
153        {
154            return dayText;
155        }
156    },
157
158    /**
159     * Get ellapsed time between given date and nox, such as '4 days ago'
160     * @param {String} date The raw date
161     * @param {Object} config The transformation config
162     * @return {String} the readable relative date
163     */
164    fromNow: function(date, config)
165    {
166        config = config || {};
167        
168        let locale = config.locale || AmetysFront.getAppParameter("locale");
169        const now = new Date();
170        const then = new Date(date);
171        const rtf = new Intl.RelativeTimeFormat(locale, { numeric: "auto" });
172
173        const seconds = Math.round((now - then) / 1000);
174        const minutes = Math.round(seconds / 60);
175        const hours = Math.round(minutes / 60);
176        const days = Math.round(hours / 24);
177        const months = Math.round(days / 30.44);
178        const years = Math.round(days / 365.25);
179
180        if (seconds < 45)
181        {
182            return rtf.format(-minutes, "second");
183        }    
184        else if (minutes < 45)
185        {
186            return rtf.format(-minutes, "minute");
187        }
188        else if (hours < 22)
189        {
190            return rtf.format(-hours, "hour");
191        }
192        else if (days < 26)
193        {
194            return rtf.format(-days, "day");
195        }
196        else if (months < 11)
197        {
198            return rtf.format(-months, "month");
199        }
200        else
201        {
202            return rtf.format(-years, "year");
203        }
204    },
205    
206    /**
207     * Convert an iso date to a readable date such as "Monday, nov. 6, 2024"
208     * @param {String} date The date in ISO format
209     * @param {Object} [config] Options to change the output format
210     * @param {String} [config.weekday=undefined] Can be "long", "short", "narrow" or undefined.
211     * @param {String} [config.month="short"] Can be "numeric", "2-digit", "long", "short" or "narrow".
212     * @param {Boolean} [config.withTime=false] To display time
213     * @param {Boolean} [config.withSeconds=false] Only when withTime is true, to display seconds
214     * @param {Boolean} [config.locale=AmetysFront.getAppParameter("locale")] The locale code such as: en, fr...
215     */
216    toReadableDate(date, config)
217    {
218        config = config || {};
219        
220        let locale = config.locale || AmetysFront.getAppParameter("locale");
221        
222        let dateConfig = {
223            "weekday": config.weekday,
224            "day": "numeric", 
225            "month": config.month || "short", 
226            "year": "numeric"
227        };
228        
229        if (config.withTime)
230        {
231            dateConfig.hour = "numeric";
232            dateConfig.minute = "2-digit";
233            if (config.withSeconds)
234            {
235                dateConfig.second = "2-digit";
236            }
237        } 
238        
239        return new Date(date).toLocaleString(locale, dateConfig);
240    },
241    
242    /**
243     * Format file size in readable size with units
244     * @param {Number} bytes the file length in bytes
245     * @param {Object} [config] Options to change the output format
246     * @param {String} [config.fixedValue=2] Number of digits after the decimal point.
247     */
248    getReadableSize: function(bytes, config) 
249    {
250        config = config || {};
251        
252        let fixedValue = config.fixedValue != undefined ? config.fixedValue : 1;
253        
254        let limit = 1024;
255        let i = 0;
256        
257        let units = [' ' + "Ko",
258        ' ' + "Mo",
259        ' ' + "Go",
260        ' ' + "Go"];
261        
262        let size = bytes;
263    
264        if (Math.abs(bytes) <= limit) {
265            return bytes + ' ' + "octet";
266        }
267        else {
268            while (size > limit) {
269                size = size / limit;
270                i++;
271            }
272        }
273    
274        return Math.max(size, 0.1).toFixed(fixedValue) + units[i-1];
275    },
276
277    /**
278     * Remove special languages characters to allow easy comparison
279     * @param {String} s The string to deemphasize
280     * @return {String} The modified string
281     */
282    deemphasize: function(s)
283    {
284        if (!s) return s;
285          
286        s = s.replace(new RegExp(/[ÀÁÂÃÄÅ]/g),"A");
287        s = s.replace(new RegExp(/[àáâãäå]/g),"a");
288        s = s.replace(new RegExp(/Æ/g),"AE");
289        s = s.replace(new RegExp(/æ/g),"ae");
290        s = s.replace(new RegExp(/Ç/g),"C");
291        s = s.replace(new RegExp(/ç/g),"c");
292        s = s.replace(new RegExp(/[ÈÉÊË]/g),"E");
293        s = s.replace(new RegExp(/[èéêë]/g),"e");
294        s = s.replace(new RegExp(/[ÌÍÎÏ]/g),"I");
295        s = s.replace(new RegExp(/[ìíîï]/g),"i");
296        s = s.replace(new RegExp(/Ñ/g),"N");
297        s = s.replace(new RegExp(/ñ/g),"n");
298        s = s.replace(new RegExp(/[ÒÓÔÕÖ]/g),"O");
299        s = s.replace(new RegExp(/[òóôõö]/g),"o");
300        s = s.replace(new RegExp(/Œ/g),"OE");
301        s = s.replace(new RegExp(/œ/g),"oe");
302        s = s.replace(new RegExp(/[ÙÚÛÜ]/g),"U");
303        s = s.replace(new RegExp(/[ùúûü]/g),"u");
304        s = s.replace(new RegExp(/[ÝŸ]/g),"y");
305        s = s.replace(new RegExp(/[ýÿ]/g),"y");
306    
307        return s;
308    },
309    
310    confirm: function(title, message, okFn)
311    {
312         $j('<div class="ui-confirm-box"></div>').html( message ).dialog({
313            open: function(event, ui) { 
314                $j(this).closest("[role=dialog]").find(".ui-dialog-titlebar-close").hide(); // Remove the closing 'X' from the dialog
315                $j(this).closest("[role=dialog]").attr("aria-modal", true); // aria attributes
316            }, 
317            title: title,
318            resizable: true,
319            minWidth: 500,
320            maxWidth: 600,
321            modal: true,
322            zIndex: 10000,
323            buttons: {
324                "Oui": function()  {
325                    $j( this ).dialog( 'destroy' );
326                    okFn();
327                },
328                "Non": function()  {
329                    $j( this ).dialog( 'destroy' );
330                }
331            }
332        });
333    },
334    
335    info: function(title, message)
336    {
337        if ( !title )
338            title = "Information";
339            
340        if ( !message )
341            message = 'No Message to Display.';
342            
343        $j('<div class="ui-state-info ui-corner-all"></div>').html( message ).dialog({
344            open: function(event, ui) { 
345                $j(this).closest("[role=dialog]").find(".ui-dialog-titlebar-close").hide(); // Remove the closing 'X' from the dialog
346                $j(this).closest("[role=dialog]").attr("aria-modal", true); // aria attributes
347            }, 
348            title: title,
349            resizable: true,
350            minWidth: 500,
351            maxWidth: 600,
352            modal: true,
353            zIndex: 10000,
354            buttons: {
355                "Ok": function()  {
356                    $j( this ).dialog( 'destroy' );
357                }
358            }
359        });
360    },
361    
362    error: function(message, title)
363    {
364        if ( !title )
365            title = "Attention!";
366
367        if ( !message )
368            message = 'No Message to Display.';
369
370        $j('<div class="ui-state-error ui-corner-all"></div>').html( message ).dialog({
371            open: function(event, ui) { 
372                $j(this).closest("[role=dialog]").find(".ui-dialog-titlebar-close").hide(); // Remove the closing 'X' from the dialog
373                $j(this).closest("[role=dialog]").attr("aria-modal", true); // aria attributes
374            }, 
375            classes: {
376              "ui-dialog": "ametys-ui-dialog-error"
377            },
378            title: title,
379            resizable: true,
380            minWidth: 500,
381            maxWidth: 600,
382            modal: true,
383            zIndex: 10000,
384            buttons: {
385                "Ok": function()  {
386                    $j( this ).dialog( 'destroy' );
387                }
388            }
389        });
390    }
391}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.