| 1 | |
| 2 | |
| 3 | |
| 4 | |
| 5 | |
| 6 | |
| 7 | |
| 8 | |
| 9 | |
| 10 | |
| 11 | |
| 12 | |
| 13 | |
| 14 | |
| 15 | |
| 16 | |
| 17 | |
| 18 | |
| 19 | |
| 20 | |
| 21 | |
| 22 | |
| 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 | |
| 39 | |
| 40 | |
| 41 | |
| 42 | class RouteHTMLViewsFactory { |
| 43 | |
| 44 | |
| 45 | |
| 46 | |
| 47 | |
| 48 | |
| 49 | |
| 50 | |
| 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 | |
| 155 | |
| 156 | |
| 157 | constructor ( ) { |
| 158 | Object.freeze ( this ); |
| 159 | } |
| 160 | |
| 161 | |
| 162 | |
| 163 | |
| 164 | |
| 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 | |
| 177 | |
| 178 | |
| 179 | |
| 180 | |
| 181 | |
| 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 | |
| 248 | |
| 249 | |
| 250 | |
| 251 | |
| 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 | |
| 341 | |
| 342 | |
| 343 | |
| 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 | |
| 374 | |
| 375 | |
| 376 | |
| 377 | |
| 378 | const theRouteHTMLViewsFactory = new RouteHTMLViewsFactory ( ); |
| 379 | |
| 380 | export default theRouteHTMLViewsFactory; |
| 381 | |
| 382 | |
| 383 | |