Satisfy ESLint
[GitHub/WoltLab/WCF.git] / wcfsetup / install / files / js / WoltLabSuite / Core / Controller / Map / Route / Planner.js
CommitLineData
84de180d
MS
1/**
2 * Map route planner based on Google Maps.
3 *
867c4493
AE
4 * @author Matthias Schmidt
5 * @copyright 2001-2019 WoltLab GmbH
6 * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
7 * @module WoltLabSuite/Core/Controller/Map/Route/Planner
a99dfb92 8 * @woltlabExcludeBundle all
84de180d 9 */
867c4493
AE
10define(["require", "exports", "tslib", "../../../Ajax/Status", "../../../Core", "../../../Dom/Util", "../../../Language", "../../../Ui/Dialog"], function (require, exports, tslib_1, AjaxStatus, Core, Util_1, Language, Dialog_1) {
11 "use strict";
716617cf
TD
12 AjaxStatus = tslib_1.__importStar(AjaxStatus);
13 Core = tslib_1.__importStar(Core);
14 Util_1 = tslib_1.__importDefault(Util_1);
15 Language = tslib_1.__importStar(Language);
16 Dialog_1 = tslib_1.__importDefault(Dialog_1);
867c4493
AE
17 class ControllerMapRoutePlanner {
18 constructor(buttonId, destination) {
19 this.didInitDialog = false;
20 this.directionsRenderer = undefined;
21 this.directionsService = undefined;
22 this.googleLink = undefined;
23 this.lastOrigin = undefined;
24 this.map = undefined;
25 this.originInput = undefined;
26 this.travelMode = undefined;
27 const button = document.getElementById(buttonId);
28 if (button === null) {
29 throw new Error(`Unknown button with id '${buttonId}'`);
30 }
31 this.button = button;
32 this.button.addEventListener("click", (ev) => this.openDialog(ev));
33 this.destination = destination;
50aa3a01 34 }
50aa3a01
TD
35 /**
36 * Calculates the route based on the given result of a location search.
50aa3a01 37 */
867c4493
AE
38 _calculateRoute(data) {
39 const dialog = Dialog_1.default.getDialog(this).dialog;
50aa3a01 40 if (data.label) {
867c4493 41 this.originInput.value = data.label;
50aa3a01 42 }
867c4493
AE
43 if (this.map === undefined) {
44 const mapContainer = dialog.querySelector(".googleMap");
45 this.map = new google.maps.Map(mapContainer, {
46 disableDoubleClickZoom: window.WCF.Location.GoogleMaps.Settings.get("disableDoubleClickZoom"),
47 draggable: window.WCF.Location.GoogleMaps.Settings.get("draggable"),
50aa3a01 48 mapTypeId: google.maps.MapTypeId.ROADMAP,
867c4493
AE
49 scaleControl: window.WCF.Location.GoogleMaps.Settings.get("scaleControl"),
50 scrollwheel: window.WCF.Location.GoogleMaps.Settings.get("scrollwheel"),
50aa3a01 51 });
867c4493
AE
52 this.directionsService = new google.maps.DirectionsService();
53 this.directionsRenderer = new google.maps.DirectionsRenderer();
54 this.directionsRenderer.setMap(this.map);
55 const directionsContainer = dialog.querySelector(".googleMapsDirections");
56 this.directionsRenderer.setPanel(directionsContainer);
57 this.googleLink = dialog.querySelector(".googleMapsDirectionsGoogleLink");
50aa3a01 58 }
867c4493
AE
59 const request = {
60 destination: this.destination,
50aa3a01
TD
61 origin: data.location,
62 provideRouteAlternatives: true,
867c4493 63 travelMode: google.maps.TravelMode[this.travelMode.value.toUpperCase()],
50aa3a01
TD
64 };
65 AjaxStatus.show();
5ffe7716
TD
66 // .route() returns a promise, but we rely on the callback API for compatibility reasons.
67 void this.directionsService.route(request, (result, status) => this.setRoute(result, status));
867c4493
AE
68 this.googleLink.href = this.getGoogleMapsLink(data.location, this.travelMode.value);
69 this.lastOrigin = data.location;
70 }
50aa3a01
TD
71 /**
72 * Returns the Google Maps link based on the given optional directions origin
73 * and optional travel mode.
50aa3a01 74 */
867c4493 75 getGoogleMapsLink(origin, travelMode) {
50aa3a01 76 if (origin) {
867c4493 77 let link = `https://www.google.com/maps/dir/?api=1&origin=${origin.lat()},${origin.lng()}&destination=${this.destination.lat()},${this.destination.lng()}`;
50aa3a01 78 if (travelMode) {
867c4493 79 link += `&travelmode=${travelMode}`;
50aa3a01
TD
80 }
81 return link;
82 }
867c4493
AE
83 return `https://www.google.com/maps/search/?api=1&query=${this.destination.lat()},${this.destination.lng()}`;
84 }
50aa3a01
TD
85 /**
86 * Initializes the route planning dialog.
87 */
867c4493
AE
88 initDialog() {
89 if (!this.didInitDialog) {
90 const dialog = Dialog_1.default.getDialog(this).dialog;
50aa3a01 91 // make input element a location search
867c4493
AE
92 this.originInput = dialog.querySelector('input[name="origin"]');
93 new window.WCF.Location.GoogleMaps.LocationSearch(this.originInput, (data) => this._calculateRoute(data));
94 this.travelMode = dialog.querySelector('select[name="travelMode"]');
95 this.travelMode.addEventListener("change", this.updateRoute.bind(this));
96 this.didInitDialog = true;
50aa3a01 97 }
867c4493 98 }
50aa3a01
TD
99 /**
100 * Opens the route planning dialog.
101 */
867c4493
AE
102 openDialog(event) {
103 event.preventDefault();
104 Dialog_1.default.open(this);
105 }
50aa3a01
TD
106 /**
107 * Handles the response of the direction service.
50aa3a01 108 */
867c4493 109 setRoute(result, status) {
50aa3a01 110 AjaxStatus.hide();
6b64df9d 111 if (status === google.maps.DirectionsStatus.OK) {
867c4493
AE
112 Util_1.default.show(this.map.getDiv().parentElement);
113 google.maps.event.trigger(this.map, "resize");
114 this.directionsRenderer.setDirections(result);
115 Util_1.default.show(this.travelMode.closest("dl"));
116 Util_1.default.show(this.googleLink);
117 Util_1.default.innerError(this.originInput, false);
50aa3a01
TD
118 }
119 else {
120 // map irrelevant errors to not found error
6b64df9d
TD
121 if (status !== google.maps.DirectionsStatus.OVER_QUERY_LIMIT &&
122 status !== google.maps.DirectionsStatus.REQUEST_DENIED) {
867c4493 123 status = google.maps.DirectionsStatus.NOT_FOUND;
50aa3a01 124 }
867c4493 125 Util_1.default.innerError(this.originInput, Language.get(`wcf.map.route.error.${status.toLowerCase()}`));
50aa3a01 126 }
867c4493 127 }
50aa3a01
TD
128 /**
129 * Updates the route after the travel mode has been changed.
130 */
867c4493 131 updateRoute() {
50aa3a01 132 this._calculateRoute({
867c4493 133 location: this.lastOrigin,
50aa3a01
TD
134 });
135 }
867c4493
AE
136 /**
137 * Sets up the route planner dialog.
138 */
139 _dialogSetup() {
140 return {
141 id: this.button.id + "Dialog",
142 options: {
143 onShow: this.initDialog.bind(this),
144 title: Language.get("wcf.map.route.planner"),
145 },
146 source: `
147<div class="googleMapsDirectionsContainer" style="display: none;">
148 <div class="googleMap"></div>
149 <div class="googleMapsDirections"></div>
150</div>
151<small class="googleMapsDirectionsGoogleLinkContainer">
152 <a href="${this.getGoogleMapsLink()}" class="googleMapsDirectionsGoogleLink" target="_blank" style="display: none;">${Language.get("wcf.map.route.viewOnGoogleMaps")}</a>
153</small>
154<dl>
155 <dt>${Language.get("wcf.map.route.origin")}</dt>
156 <dd>
157 <input type="text" name="origin" class="long" autofocus>
158 </dd>
159</dl>
160<dl style="display: none;">
161 <dt>${Language.get("wcf.map.route.travelMode")}</dt>
162 <dd>
163 <select name="travelMode">
164 <option value="driving">${Language.get("wcf.map.route.travelMode.driving")}</option>
165 <option value="walking">${Language.get("wcf.map.route.travelMode.walking")}</option>
166 <option value="bicycling">${Language.get("wcf.map.route.travelMode.bicycling")}</option>
167 <option value="transit">${Language.get("wcf.map.route.travelMode.transit")}</option>
168 </select>
169 </dd>
170</dl>`,
171 };
172 }
173 }
174 Core.enableLegacyInheritance(ControllerMapRoutePlanner);
175 return ControllerMapRoutePlanner;
84de180d 176});