File : core/uiLib/Utilities.js

1
/*
2
Copyright - 2017 2023 - wwwouaiebe - Contact: https://www.ouaie.be/
3
4
This  program is free software;
5
you can redistribute it and/or modify it under the terms of the
6
GNU General Public License as published by the Free Software Foundation;
7
either version 3 of the License, or any later version.
8
This program is distributed in the hope that it will be useful,
9
but WITHOUT ANY WARRANTY; without even the implied warranty of
10
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
GNU General Public License for more details.
12
You should have received a copy of the GNU General Public License
13
along with this program; if not, write to the Free Software
14
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
15
*/
16
/*
17
Changes:
18
    - v4.0.0:
19
        - created from v3.6.0
20
Doc reviewed 202208
21
 */
22
23
import theTranslator from './Translator.js';
24
import { LAT_LNG, ZERO, ONE, TWO, THREE, HEXADECIMAL, DISTANCE } from '../../main/Constants.js';
25
26
/* ------------------------------------------------------------------------------------------------------------------------- */
27
/**
28
This class contains utility methods.
29
See theUtilities for the one and only one instance of this class
30
*/
31
/* ------------------------------------------------------------------------------------------------------------------------- */
32
33
class Utilities {
34
35
    /**
36
    constructor
37
    */
38
39
    constructor ( ) {
40
        Object.freeze ( this );
41
    }
42
43
    /**
44
    Gives an UUID conform to the rfc 4122 section 4.4
45
    @type {String}
46
    */
47
48
    get UUID ( ) {
49
        const UUID_LENGHT = 16;
50
        const UUID_STRLENGHT = 2;
51
        const UUID_SEPARATORS = [ '', '', '', '-', '', '-', '', '-', '', '-', '', '', '', '', '', '' ];
52
        const randomValues = new Uint8Array ( UUID_LENGHT );
53
54
        window.crypto.getRandomValues ( randomValues );
55
56
        /* eslint-disable no-bitwise */
57
        /* eslint-disable no-magic-numbers */
58
        /*
59
        rfc 4122 section 4.4 : Set the four most significant bits (bits 12 through 15) of the
60
        time_hi_and_version field to the 4-bit version number from section 4.1.3.
61
        */
62
63
        randomValues [ 6 ] = ( randomValues [ 6 ] & 0x0f ) | 0x40;
64
65
        /*
66
        rfc 4122 section 4.4 : Set the two most significant bits (bits 6 and 7) of the
67
        clock_seq_hi_and_reserved to zero and one, respectively.
68
        */
69
70
        randomValues [ 8 ] = ( randomValues [ 8 ] & 0x3f ) | 0x80;
71
        /* eslint-enable no-bitwise */
72
        /* eslint-enable no-magic-numbers */
73
74
        let UUID = '';
75
        for ( let counter = ZERO; counter < UUID_LENGHT; counter ++ ) {
76
            UUID += randomValues [ counter ].toString ( HEXADECIMAL ).padStart ( UUID_STRLENGHT, '0' ) +
77
                UUID_SEPARATORS [ counter ];
78
        }
79
80
        return UUID;
81
    }
82
83
    /**
84
    Test the availibility of the storage
85
    @param {String} type The type of storage. Must be 'sessionStorage' or 'localStorage'
86
    */
87
88
    storageAvailable ( type ) {
89
        try {
90
            const storage = window [ type ];
91
            const testString = '__storage_test__';
92
            storage.setItem ( testString, testString );
93
            storage.removeItem ( testString );
94
            return true;
95
        }
96
        catch ( err ) {
97
            return false;
98
        }
99
    }
100
101
    /**
102
    Open a file
103
    @param {function|Object} eventListener a change event listener to use when the file is opened
104
    @param {String} acceptFileType The extension of the file, included the dot.
105
    */
106
107
    openFile ( eventListener, acceptFileType ) {
108
        const openFileInput = document.createElement ( 'input' );
109
        openFileInput.type = 'file';
110
        if ( acceptFileType ) {
111
            openFileInput.accept = acceptFileType;
112
        }
113
        openFileInput.addEventListener (
114
            'change',
115
            eventListener,
116
            false
117
        );
118
        openFileInput.click ( );
119
    }
120
121
    /**
122
    Save a string to a file
123
    @param {String} fileName The file name
124
    @param {String} fileContent The file content
125
    @param {?string} fileMimeType The mime type of the file. Default to 'text/plain'
126
    */
127
128
    saveFile ( fileName, fileContent, fileMimeType ) {
129
        try {
130
            const objURL =
131
                fileMimeType
132
                    ?
133
                    window.URL.createObjectURL ( new File ( [ fileContent ], fileName, { type : fileMimeType } ) )
134
                    :
135
                    URL.createObjectURL ( fileContent );
136
            const element = document.createElement ( 'a' );
137
            element.setAttribute ( 'href', objURL );
138
            element.setAttribute ( 'download', fileName );
139
            element.click ( );
140
            window.URL.revokeObjectURL ( objURL );
141
        }
142
        catch ( err ) {
143
            if ( err instanceof Error ) {
144
                console.error ( err );
145
            }
146
        }
147
    }
148
149
    /**
150
    Transform a time to a string
151
    @param {Number} time The time in seconds
152
    */
153
154
    formatTime ( time ) {
155
        const SECOND_IN_DAY = 86400;
156
        const SECOND_IN_HOUR = 3600;
157
        const SECOND_IN_MINUT = 60;
158
        const iTtime = Math.floor ( time );
159
        if ( ZERO === iTtime ) {
160
            return '';
161
        }
162
        const days = Math.floor ( iTtime / SECOND_IN_DAY );
163
        const hours = Math.floor ( iTtime % SECOND_IN_DAY / SECOND_IN_HOUR );
164
        const minutes = Math.floor ( iTtime % SECOND_IN_HOUR / SECOND_IN_MINUT );
165
        const seconds = Math.floor ( iTtime % SECOND_IN_MINUT );
166
        if ( ZERO < days ) {
167
            return days +
168
                '\u00A0'
169
                + theTranslator.getText ( 'Utilities - Day' ) +
170
                '\u00A0' +
171
                hours +
172
                '\u00A0' +
173
                theTranslator.getText ( 'Utilities - Hour' );
174
        }
175
        else if ( ZERO < hours ) {
176
            return hours +
177
                '\u00A0'
178
                + theTranslator.getText ( 'Utilities - Hour' )
179
                + '\u00A0' +
180
                minutes +
181
                '\u00A0'
182
                + theTranslator.getText ( 'Utilities - Minute' );
183
        }
184
        else if ( ZERO < minutes ) {
185
            return minutes +
186
                '\u00A0' +
187
                theTranslator.getText ( 'Utilities - Minute' );
188
        }
189
        return seconds + '\u00A0' + theTranslator.getText ( 'Utilities - Second' );
190
    }
191
192
    /**
193
    Transform a distance to a string
194
    @param {Number} distance The distance in meters
195
    */
196
197
    formatDistance ( distance ) {
198
        const DISTANCE_ROUND = 10;
199
200
        const iDistance = Math.floor ( distance );
201
        if ( ZERO >= iDistance ) {
202
            return '0\u00A0km';
203
        }
204
        return Math.floor ( iDistance / DISTANCE.metersInKm ) +
205
            ',' +
206
            Math.floor ( ( iDistance % DISTANCE.metersInKm ) / DISTANCE_ROUND ).toFixed ( ZERO )
207
                .padStart ( TWO, '0' )
208
                .padEnd ( THREE, '0' ) +
209
            '\u00A0km';
210
    }
211
212
    /**
213
    Transform a number to a string with degree minutes and seconds
214
    @param {Number} number The number to transform
215
    */
216
217
    numberToDMS ( number ) {
218
        const MINUTES_IN_DEGREE = 60.0;
219
        const SECONDS_IN_DEGREE = 3600.0;
220
        const SECONDS_DECIMALS = 100.0;
221
        let remind = number;
222
        let degrees = Math.floor ( number );
223
        remind -= degrees;
224
        let minutes = Math.floor ( remind * MINUTES_IN_DEGREE );
225
        remind -= minutes / MINUTES_IN_DEGREE;
226
        remind *= SECONDS_IN_DEGREE;
227
        let seconds = Math.floor ( remind );
228
        remind -= seconds;
229
        remind = Math.floor ( remind * SECONDS_DECIMALS );
230
        return degrees.toString ( ) + '° ' + minutes.toString ( ) + '\' ' + seconds + '" ' + remind;
231
    }
232
233
    /**
234
    Transform a latitude to a string with degree minutes and seconds
235
    @param {Number} lat The latitude
236
    */
237
238
    formatLatDMS ( lat ) {
239
        return (
240
            lat > ZERO
241
                ?
242
                this.numberToDMS ( lat ) + '\u00A0N'
243
                :
244
                this.numberToDMS ( -lat ) + '\u00A0S'
245
        );
246
    }
247
248
    /**
249
    Transform a longitude to a string with degree minutes and seconds
250
    @param {Number} lng The longitude
251
    */
252
253
    formatLngDMS ( lng ) {
254
        return (
255
            lng > ZERO
256
                ?
257
                this.numberToDMS ( lng ) + '\u00A0E'
258
                :
259
                this.numberToDMS ( -lng ) + '\u00A0W'
260
        );
261
    }
262
263
    /**
264
    Transform a latitude + longitude to a string with degree minutes and seconds
265
    @param {Array.<Number>} latLng The latitude and longitude
266
    */
267
268
    formatLatLngDMS ( latLng ) {
269
        if ( ZERO === latLng [ ZERO ] && ZERO === latLng [ ONE ] ) {
270
            return '';
271
        }
272
        return this.formatLatDMS ( latLng [ ZERO ] ) + '\u00A0-\u00A0' + this.formatLngDMS ( latLng [ ONE ] );
273
    }
274
275
    /**
276
    Transform a latitude to a string
277
    @param {Number} lat The latitude
278
    */
279
280
    formatLat ( lat ) {
281
        return (
282
            lat > ZERO
283
                ?
284
                lat.toFixed ( LAT_LNG.fixed ) + '\u00A0N'
285
                :
286
                ( -lat ).toFixed ( LAT_LNG.fixed ) + '\u00A0S'
287
        );
288
    }
289
290
    /**
291
    Transform a longitude to a string
292
    @param {Number} lng The longitude
293
    */
294
295
    formatLng ( lng ) {
296
        return (
297
            lng > ZERO
298
                ?
299
                lng.toFixed ( LAT_LNG.fixed ) + '\u00A0E'
300
                :
301
                ( -lng ).toFixed ( LAT_LNG.fixed ) + '\u00A0W'
302
        );
303
    }
304
305
    /**
306
    Transform a latitude + longitude to a string
307
    @param {Array.<Number>} latLng The latitude and longitude
308
    */
309
310
    formatLatLng ( latLng ) {
311
        if ( ZERO === latLng [ ZERO ] && ZERO === latLng [ ONE ] ) {
312
            return '';
313
        }
314
        return this.formatLat ( latLng [ ZERO ] ) + '\u00A0-\u00A0' + this.formatLng ( latLng [ ONE ] );
315
    }
316
}
317
318
/* ------------------------------------------------------------------------------------------------------------------------- */
319
/**
320
The one and only one instance of Utilities class
321
@type {Utilities}
322
*/
323
/* ------------------------------------------------------------------------------------------------------------------------- */
324
325
const theUtilities = new Utilities ( );
326
327
export default theUtilities;
328
329
/* --- End of file --------------------------------------------------------------------------------------------------------- */
330