File : viewsFactories/RouteHTMLViewsFactory.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
9
This program is distributed in the hope that it will be useful,
10
but WITHOUT ANY WARRANTY; without even the implied warranty of
11
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
GNU General Public License for more details.
13
14
You should have received a copy of the GNU General Public License
15
along with this program; if not, write to the Free Software
16
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17
*/
18
/*
19
Changes:
20
    - v4.0.0:
21
        - created from v3.6.0
22
Doc reviewed 202208
23
 */
24
25
import ObjId from '../data/ObjId.js';
26
import SvgProfileBuilder from '../core/lib/SvgProfileBuilder.js';
27
import theHTMLElementsFactory from '../core/uiLib/HTMLElementsFactory.js';
28
import theHTMLSanitizer from '../core/htmlSanitizer/HTMLSanitizer.js';
29
import theTranslator from '../core/uiLib/Translator.js';
30
import theUtilities from '../core/uiLib/Utilities.js';
31
import theNoteHTMLViewsFactory from '../viewsFactories/NoteHTMLViewsFactory.js';
32
import theTravelNotesData from '../data/TravelNotesData.js';
33
34
import { ZERO, DISTANCE, ICON_DIMENSIONS } from '../main/Constants.js';
35
36
/* ------------------------------------------------------------------------------------------------------------------------- */
37
/**
38
This class creates HTMLElements for routes
39
*/
40
/* ------------------------------------------------------------------------------------------------------------------------- */
41
42
class RouteHTMLViewsFactory {
43
44
    /**
45
    Gives an HTMLElement with the icon, instruction, distance since the beginning of the travel (if the instruction is
46
    linked to a chained route), distance since the beginning of the route and distance till the next maneuver
47
    @param {String} classPrefix A string that will be added to all the className of the created HTMLElements
48
    @param {Object} routeAndManeuver An object with the maneuver, the route to witch the maneuver is linked and the distance
49
    between the beginning of the route and the maneuver
50
    @return {HTMLElement} An HTMLElement with the Maneuver
51
    */
52
53
    #getManeuverHTML ( classPrefix, routeAndManeuver ) {
54
        const maneuverHTML = theHTMLElementsFactory.create ( 'div' );
55
        const maneuverIconHTML = theHTMLElementsFactory.create (
56
            'div',
57
            {
58
                className :
59
                    classPrefix + 'Route-ManeuversAndNotes-IconCell'
60
            },
61
            maneuverHTML
62
        );
63
64
        theHTMLElementsFactory.create (
65
            'div',
66
            {
67
                className :
68
                    'TravelNotes-ManeuverNote TravelNotes-ManeuverNote-' +
69
                    routeAndManeuver.maneuver.iconName
70
            },
71
            maneuverIconHTML
72
        );
73
74
        maneuverIconHTML.dataset.tanWidth = String ( ICON_DIMENSIONS.width ) + 'px';
75
        maneuverIconHTML.dataset.tanHeight = String ( ICON_DIMENSIONS.height ) + 'px';
76
77
        const maneuverTextHTML = theHTMLElementsFactory.create (
78
            'div',
79
            {
80
                className : classPrefix + 'Route-ManeuversAndNotes-Cell'
81
            },
82
            maneuverHTML
83
        );
84
85
        theHTMLElementsFactory.create (
86
            'div',
87
            {
88
                className : classPrefix + 'Route-Maneuver-TooltipContent',
89
                textContent : theTranslator.getText ( 'RouteHTMLViewsFactory - ' + routeAndManeuver.maneuver.iconName )
90
            },
91
            maneuverTextHTML
92
        );
93
94
        theHTMLSanitizer.sanitizeToHtmlElement (
95
            routeAndManeuver.maneuver.instruction,
96
            theHTMLElementsFactory.create (
97
                'div',
98
                {
99
                    className : classPrefix + 'Route-Maneuver-Instruction'
100
                },
101
                maneuverTextHTML
102
            )
103
        );
104
105
        if ( routeAndManeuver.route.chain ) {
106
            theHTMLSanitizer.sanitizeToHtmlElement (
107
                '<span>' +
108
                    theTranslator.getText ( 'RouteHTMLViewsFactory - Distance from start of travel' ) +
109
                    '</span>\u00a0:\u00a0' +
110
                    theUtilities.formatDistance ( routeAndManeuver.route.chainedDistance + routeAndManeuver.maneuverDistance ),
111
                theHTMLElementsFactory.create (
112
                    'div',
113
                    {
114
                        className : classPrefix + 'Route-Maneuver-TravelDistance'
115
                    },
116
                    maneuverTextHTML
117
                )
118
            );
119
        }
120
121
        theHTMLSanitizer.sanitizeToHtmlElement (
122
            '<span>' +
123
                theTranslator.getText ( 'RouteHTMLViewsFactory - Distance from start of route' ) +
124
                '</span>\u00a0:\u00a0' +
125
                theUtilities.formatDistance ( routeAndManeuver.maneuverDistance ),
126
            theHTMLElementsFactory.create (
127
                'div',
128
                {
129
                    className : classPrefix + 'Route-Maneuver-RouteDistance'
130
                },
131
                maneuverTextHTML
132
            )
133
        );
134
135
        if ( DISTANCE.defaultValue < routeAndManeuver.maneuver.distance ) {
136
            theHTMLSanitizer.sanitizeToHtmlElement (
137
                '<span>' +
138
                    theTranslator.getText ( 'RouteHTMLViewsFactory - Next maneuver after' ) +
139
                    '</span>\u00a0:\u00a0' +
140
                    theUtilities.formatDistance ( routeAndManeuver.maneuver.distance ),
141
                theHTMLElementsFactory.create (
142
                    'div',
143
                    {
144
                        className : classPrefix + 'Route-Maneuver-NextDistance'
145
                    },
146
                    maneuverTextHTML
147
                )
148
            );
149
        }
150
        return maneuverHTML;
151
    }
152
153
    /**
154
    The constructor
155
    */
156
157
    constructor ( ) {
158
        Object.freeze ( this );
159
    }
160
161
    /**
162
    Gives an HTMLElement with the SVG profile of a route
163
    @param {String} classPrefix A string that will be added to all the className of the created HTMLElements
164
    @param {Route} route The route for witch the HTMLElement will be created
165
    */
166
167
    getRouteProfileHTML ( classPrefix, route ) {
168
        const profileDiv = theHTMLElementsFactory.create ( 'div', { className : classPrefix + 'RouteProfile' } );
169
        theHTMLSanitizer.sanitizeToHtmlElement ( theTranslator.getText ( 'RouteHTMLViewsFactory - Profile' ), profileDiv );
170
        profileDiv.appendChild ( new SvgProfileBuilder ( ).createSvg ( route ) );
171
172
        return profileDiv;
173
    }
174
175
    /**
176
    Gives an HTMLElement with all the notes and maneuvers linked to a route, ordered by distance since the
177
    beginning of the route
178
    @param {String} classPrefix A string that will be added to all the className of the created HTMLElements
179
    @param {Route} route The route for witch the HTMLElement will be created
180
    @param {Boolean} addDataset When true, objId and objType are added to the dataset of the HTMLElement
181
    @return {HTMLElement} An HTMLElement with all the notes and maneuvers linked to the route
182
    */
183
184
    getRouteManeuversAndNotesHTML ( classPrefix, route, addDataset ) {
185
        const notesAndManeuvers = [];
186
        const notesIterator = route.notes.iterator;
187
        while ( ! notesIterator.done ) {
188
            notesAndManeuvers.push (
189
                {
190
                    data : notesIterator.value,
191
                    distance : notesIterator.value.distance
192
                }
193
            );
194
        }
195
        const maneuversIterator = route.itinerary.maneuvers.iterator;
196
        let maneuverDistance = ZERO;
197
        while ( ! maneuversIterator.done ) {
198
            notesAndManeuvers.push (
199
                {
200
                    data : maneuversIterator.value,
201
                    distance : maneuverDistance
202
                }
203
            );
204
            maneuverDistance += maneuversIterator.value.distance;
205
        }
206
        notesAndManeuvers.sort ( ( first, second ) => first.distance - second.distance );
207
        const routeNotesAndManeuversHTML = theHTMLElementsFactory.create (
208
            'div',
209
            {
210
                className : classPrefix + 'Route-ManeuversAndNotes'
211
            }
212
        );
213
        notesAndManeuvers.forEach (
214
            noteOrManeuver => {
215
                let noteOrManeuverHTML = null;
216
                if ( 'Note' === noteOrManeuver.data.objType.name ) {
217
                    noteOrManeuverHTML = theNoteHTMLViewsFactory.getNoteTextAndIconHTML (
218
                        classPrefix,
219
                        { note : noteOrManeuver.data, route : route }
220
                    );
221
                    noteOrManeuverHTML.className = classPrefix + 'Route-Notes-Row';
222
                }
223
                else {
224
                    noteOrManeuverHTML = this.#getManeuverHTML (
225
                        classPrefix,
226
                        {
227
                            route : route,
228
                            maneuver : noteOrManeuver.data,
229
                            maneuverDistance : noteOrManeuver.distance
230
                        }
231
                    );
232
                    noteOrManeuverHTML.className = classPrefix + 'Route-Maneuvers-Row';
233
                }
234
                if ( addDataset ) {
235
                    noteOrManeuverHTML.dataset.tanObjId = noteOrManeuver.data.objId;
236
                    noteOrManeuverHTML.dataset.tanMarkerObjId = ObjId.nextObjId;
237
                    noteOrManeuverHTML.dataset.tanObjType = noteOrManeuver.data.objType.name;
238
                }
239
                routeNotesAndManeuversHTML.appendChild ( noteOrManeuverHTML );
240
            }
241
        );
242
243
        return routeNotesAndManeuversHTML;
244
    }
245
246
    /**
247
    Gives an HTMLElement with a route name, route distance, route duration ( except for bike),
248
    route ascent (if any) and route descent (if any)
249
    @param {String} classPrefix A string that will be added to all the className of the created HTMLElements
250
    @param {Route} route The route for witch the HTMLElement will be created
251
    @return {HTMLElement} An HTMLElement with the Route header
252
    */
253
254
    getRouteHeaderHTML ( classPrefix, route ) {
255
        const routeHeaderHTML = theHTMLElementsFactory.create (
256
            'div',
257
            {
258
                className : classPrefix + 'Route-Header',
259
                id : 'route' + route.objId
260
            }
261
        );
262
263
        theHTMLSanitizer.sanitizeToHtmlElement (
264
            route.computedName,
265
            theHTMLElementsFactory.create (
266
                'div',
267
                {
268
                    className : classPrefix + 'Route-Header-Name'
269
                },
270
                routeHeaderHTML
271
            )
272
        );
273
274
        if ( ZERO !== route.distance ) {
275
            theHTMLSanitizer.sanitizeToHtmlElement (
276
                '<span>' +
277
                    theTranslator.getText ( 'RouteHTMLViewsFactory - Route distance' ) +
278
                    '</span>\u00a0:\u00a0' +
279
                    theUtilities.formatDistance ( route.distance ),
280
                theHTMLElementsFactory.create (
281
                    'div',
282
                    {
283
                        className : classPrefix + 'Route-Header-Distance'
284
                    },
285
                    routeHeaderHTML
286
                )
287
            );
288
        }
289
290
        if ( ! theTravelNotesData.travel.readOnly && 'bike' !== route.itinerary.transitMode ) {
291
            theHTMLSanitizer.sanitizeToHtmlElement (
292
                '<span>' +
293
                    theTranslator.getText ( 'RouteHTMLViewsFactory - Duration' ) +
294
                    '</span>\u00a0:\u00a0' +
295
                    theUtilities.formatTime ( route.duration ),
296
                theHTMLElementsFactory.create (
297
                    'div',
298
                    {
299
                        className : classPrefix + 'Route-Header-Duration'
300
                    },
301
                    routeHeaderHTML
302
                )
303
            );
304
        }
305
306
        if ( route.itinerary.hasProfile ) {
307
            theHTMLSanitizer.sanitizeToHtmlElement (
308
                '<span>' +
309
                    theTranslator.getText ( 'RouteHTMLViewsFactory - Ascent' ) +
310
                    '</span>\u00a0:\u00a0' +
311
                    String ( route.itinerary.ascent.toFixed ( ZERO ) ) +
312
                    ' m.',
313
                theHTMLElementsFactory.create (
314
                    'div',
315
                    {
316
                        className : classPrefix + 'Route-Header-Ascent'
317
                    },
318
                    routeHeaderHTML
319
                )
320
            );
321
            theHTMLSanitizer.sanitizeToHtmlElement (
322
                '<span>' +
323
                    theTranslator.getText ( 'RouteHTMLViewsFactory - Descent' ) +
324
                    '</span>\u00a0:\u00a0' +
325
                    String ( route.itinerary.descent.toFixed ( ZERO ) ) +
326
                    ' m.',
327
                theHTMLElementsFactory.create (
328
                    'div',
329
                    {
330
                        className : classPrefix + 'Route-Header-Descent'
331
                    },
332
                    routeHeaderHTML
333
                )
334
            );
335
        }
336
        return routeHeaderHTML;
337
    }
338
339
    /**
340
    Gives an HTMLElement with the provider and transit mode used for the itinerary creation
341
    @param {String} classPrefix A string that will be added to all the className of the created HTMLElements
342
    @param {Route} route The route for witch the HTMLElement will be created
343
    @return {HTMLElement} An HTMLElement with the Route footer
344
    */
345
346
    getRouteFooterHTML ( classPrefix, route ) {
347
        let footerText =
348
            ( ( '' !== route.itinerary.provider ) && ( '' !== route.itinerary.transitMode ) )
349
                ?
350
                theTranslator.getText (
351
                    'RouteHTMLViewsFactory - Itinerary computed by {provider} and optimized for {transitMode}',
352
                    {
353
                        provider : route.itinerary.provider,
354
                        transitMode : theTranslator.getText (
355
                            'RouteHTMLViewsFactory - TransitMode ' + route.itinerary.transitMode
356
                        )
357
                    }
358
                )
359
                :
360
                '';
361
362
        const footerHTML = theHTMLElementsFactory.create ( 'div', { className : classPrefix + 'RouteFooter' } );
363
364
        theHTMLSanitizer.sanitizeToHtmlElement ( footerText, footerHTML );
365
366
        return footerHTML;
367
    }
368
369
}
370
371
/* ------------------------------------------------------------------------------------------------------------------------- */
372
/**
373
The one and only one instance of RouteHTMLViewsFactory  class
374
@type {RouteHTMLViewsFactory }
375
*/
376
/* ------------------------------------------------------------------------------------------------------------------------- */
377
378
const theRouteHTMLViewsFactory = new RouteHTMLViewsFactory ( );
379
380
export default theRouteHTMLViewsFactory;
381
382
/* --- End of file --------------------------------------------------------------------------------------------------------- */
383