From: Alexander Ebert Date: Sat, 2 Jan 2021 12:47:39 +0000 (+0100) Subject: Convert `Controller/Map/Route/Planner` to TypeScript X-Git-Tag: 5.4.0_Alpha_1~484^2~13 X-Git-Url: https://git.stricted.de/?a=commitdiff_plain;h=867c4493f3f92ac54fd4a20208546156264eabcf;p=GitHub%2FWoltLab%2FWCF.git Convert `Controller/Map/Route/Planner` to TypeScript --- diff --git a/package-lock.json b/package-lock.json index be241647fe..f6b9ced5c6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -131,6 +131,12 @@ "resolved": "https://registry.npmjs.org/@types/facebook-js-sdk/-/facebook-js-sdk-3.3.1.tgz", "integrity": "sha512-jRVPdOu237QxDDoBjc9/xzGsDz75FmdvcwVZdCEg1AjHAQxGmXoHfACUyUVtz7DSWA4E+jgj5MQME4snjGwOng==" }, + "@types/googlemaps": { + "version": "3.43.0", + "resolved": "https://registry.npmjs.org/@types/googlemaps/-/googlemaps-3.43.0.tgz", + "integrity": "sha512-4k6N1LKTmwHEG6zKNMfINqQS08jd3wYdmlBRfJpcKqUYC9A9uXzuO3irV6muI+PWg1DRAjlBuLfrQTmHNjzlGA==", + "dev": true + }, "@types/jquery": { "version": "3.5.4", "resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.5.4.tgz", diff --git a/package.json b/package.json index 24987ad4c3..0d5efc7c55 100644 --- a/package.json +++ b/package.json @@ -2,6 +2,7 @@ "name": "@woltlab/wcf", "version": "5.4.0", "devDependencies": { + "@types/googlemaps": "^3.43.0", "@types/perfect-scrollbar": "^0.6.1", "@typescript-eslint/eslint-plugin": "^4.6.0", "@typescript-eslint/parser": "^4.6.0", diff --git a/wcfsetup/install/files/js/WoltLabSuite/Core/Controller/Map/Route/Planner.js b/wcfsetup/install/files/js/WoltLabSuite/Core/Controller/Map/Route/Planner.js index 6acb7655d7..f4368facc9 100644 --- a/wcfsetup/install/files/js/WoltLabSuite/Core/Controller/Map/Route/Planner.js +++ b/wcfsetup/install/files/js/WoltLabSuite/Core/Controller/Map/Route/Planner.js @@ -1,169 +1,173 @@ /** * Map route planner based on Google Maps. * - * @author Matthias Schmidt - * @copyright 2001-2019 WoltLab GmbH - * @license GNU Lesser General Public License - * @module WoltLabSuite/Core/Controller/Map/Route/Planner + * @author Matthias Schmidt + * @copyright 2001-2019 WoltLab GmbH + * @license GNU Lesser General Public License + * @module WoltLabSuite/Core/Controller/Map/Route/Planner */ -define([ - 'Dom/Traverse', - 'Dom/Util', - 'Language', - 'Ui/Dialog', - 'WoltLabSuite/Core/Ajax/Status' -], function (DomTraverse, DomUtil, Language, UiDialog, AjaxStatus) { - /** - * @constructor - */ - function Planner(buttonId, destination) { - this._button = elById(buttonId); - if (this._button === null) { - throw new Error("Unknown button with id '" + buttonId + "'"); +define(["require", "exports", "tslib", "../../../Ajax/Status", "../../../Core", "../../../Dom/Util", "../../../Language", "../../../Ui/Dialog"], function (require, exports, tslib_1, AjaxStatus, Core, Util_1, Language, Dialog_1) { + "use strict"; + AjaxStatus = tslib_1.__importStar(AjaxStatus); + Core = tslib_1.__importStar(Core); + Util_1 = tslib_1.__importDefault(Util_1); + Language = tslib_1.__importStar(Language); + Dialog_1 = tslib_1.__importDefault(Dialog_1); + class ControllerMapRoutePlanner { + constructor(buttonId, destination) { + this.didInitDialog = false; + this.directionsRenderer = undefined; + this.directionsService = undefined; + this.googleLink = undefined; + this.lastOrigin = undefined; + this.map = undefined; + this.originInput = undefined; + this.travelMode = undefined; + const button = document.getElementById(buttonId); + if (button === null) { + throw new Error(`Unknown button with id '${buttonId}'`); + } + this.button = button; + this.button.addEventListener("click", (ev) => this.openDialog(ev)); + this.destination = destination; } - this._button.addEventListener('click', this._openDialog.bind(this)); - this._destination = destination; - } - Planner.prototype = { - /** - * Sets up the route planner dialog. - */ - _dialogSetup: function () { - return { - id: this._button.id + 'Dialog', - options: { - onShow: this._initDialog.bind(this), - title: Language.get('wcf.map.route.planner') - }, - source: '' + - '' + - '
' + - '
' + Language.get('wcf.map.route.origin') + '
' + - '
' + - '
' + - '
' + - '
' + Language.get('wcf.map.route.travelMode') + '
' + - '
' + - '' + - '
' + - '
' - }; - }, /** * Calculates the route based on the given result of a location search. - * - * @param {object} data */ - _calculateRoute: function (data) { - var dialog = UiDialog.getDialog(this).dialog; + _calculateRoute(data) { + const dialog = Dialog_1.default.getDialog(this).dialog; if (data.label) { - this._originInput.value = data.label; + this.originInput.value = data.label; } - if (this._map === undefined) { - this._map = new google.maps.Map(elByClass('googleMap', dialog)[0], { - disableDoubleClickZoom: WCF.Location.GoogleMaps.Settings.get('disableDoubleClickZoom'), - draggable: WCF.Location.GoogleMaps.Settings.get('draggable'), + if (this.map === undefined) { + const mapContainer = dialog.querySelector(".googleMap"); + this.map = new google.maps.Map(mapContainer, { + disableDoubleClickZoom: window.WCF.Location.GoogleMaps.Settings.get("disableDoubleClickZoom"), + draggable: window.WCF.Location.GoogleMaps.Settings.get("draggable"), mapTypeId: google.maps.MapTypeId.ROADMAP, - scaleControl: WCF.Location.GoogleMaps.Settings.get('scaleControl'), - scrollwheel: WCF.Location.GoogleMaps.Settings.get('scrollwheel') + scaleControl: window.WCF.Location.GoogleMaps.Settings.get("scaleControl"), + scrollwheel: window.WCF.Location.GoogleMaps.Settings.get("scrollwheel"), }); - this._directionsService = new google.maps.DirectionsService(); - this._directionsRenderer = new google.maps.DirectionsRenderer(); - this._directionsRenderer.setMap(this._map); - this._directionsRenderer.setPanel(elByClass('googleMapsDirections', dialog)[0]); - this._googleLink = elByClass('googleMapsDirectionsGoogleLink', dialog)[0]; + this.directionsService = new google.maps.DirectionsService(); + this.directionsRenderer = new google.maps.DirectionsRenderer(); + this.directionsRenderer.setMap(this.map); + const directionsContainer = dialog.querySelector(".googleMapsDirections"); + this.directionsRenderer.setPanel(directionsContainer); + this.googleLink = dialog.querySelector(".googleMapsDirectionsGoogleLink"); } - var request = { - destination: this._destination, + const request = { + destination: this.destination, origin: data.location, provideRouteAlternatives: true, - travelMode: google.maps.TravelMode[this._travelMode.value.toUpperCase()] + travelMode: google.maps.TravelMode[this.travelMode.value.toUpperCase()], }; AjaxStatus.show(); - this._directionsService.route(request, this._setRoute.bind(this)); - elAttr(this._googleLink, 'href', this._getGoogleMapsLink(data.location, this._travelMode.value)); - this._lastOrigin = data.location; - }, + this.directionsService.route(request, (result, status) => this.setRoute(result, status)); + this.googleLink.href = this.getGoogleMapsLink(data.location, this.travelMode.value); + this.lastOrigin = data.location; + } /** * Returns the Google Maps link based on the given optional directions origin * and optional travel mode. - * - * @param {google.maps.LatLng} origin - * @param {string} travelMode - * @return {string} */ - _getGoogleMapsLink: function (origin, travelMode) { + getGoogleMapsLink(origin, travelMode) { if (origin) { - var link = 'https://www.google.com/maps/dir/?api=1' + - '&origin=' + origin.lat() + ',' + origin.lng() + '' + - '&destination=' + this._destination.lat() + ',' + this._destination.lng(); + let link = `https://www.google.com/maps/dir/?api=1&origin=${origin.lat()},${origin.lng()}&destination=${this.destination.lat()},${this.destination.lng()}`; if (travelMode) { - link += '&travelmode=' + travelMode; + link += `&travelmode=${travelMode}`; } return link; } - return 'https://www.google.com/maps/search/?api=1&query=' + this._destination.lat() + ',' + this._destination.lng(); - }, + return `https://www.google.com/maps/search/?api=1&query=${this.destination.lat()},${this.destination.lng()}`; + } /** * Initializes the route planning dialog. */ - _initDialog: function () { - if (!this._didInitDialog) { - var dialog = UiDialog.getDialog(this).dialog; + initDialog() { + if (!this.didInitDialog) { + const dialog = Dialog_1.default.getDialog(this).dialog; // make input element a location search - this._originInput = elBySel('input[name="origin"]', dialog); - new WCF.Location.GoogleMaps.LocationSearch(this._originInput, this._calculateRoute.bind(this)); - this._travelMode = elBySel('select[name="travelMode"]', dialog); - this._travelMode.addEventListener('change', this._updateRoute.bind(this)); - this._didInitDialog = true; + this.originInput = dialog.querySelector('input[name="origin"]'); + new window.WCF.Location.GoogleMaps.LocationSearch(this.originInput, (data) => this._calculateRoute(data)); + this.travelMode = dialog.querySelector('select[name="travelMode"]'); + this.travelMode.addEventListener("change", this.updateRoute.bind(this)); + this.didInitDialog = true; } - }, + } /** * Opens the route planning dialog. */ - _openDialog: function () { - UiDialog.open(this); - }, + openDialog(event) { + event.preventDefault(); + Dialog_1.default.open(this); + } /** * Handles the response of the direction service. - * - * @param {object} result - * @param {string} status */ - _setRoute: function (result, status) { + setRoute(result, status) { AjaxStatus.hide(); - if (status === 'OK') { - elShow(this._map.getDiv().parentNode); - google.maps.event.trigger(this._map, 'resize'); - this._directionsRenderer.setDirections(result); - elShow(DomTraverse.parentByTag(this._travelMode, 'DL')); - elShow(this._googleLink); - elInnerError(this._originInput, false); + if (status === "OK") { + Util_1.default.show(this.map.getDiv().parentElement); + google.maps.event.trigger(this.map, "resize"); + this.directionsRenderer.setDirections(result); + Util_1.default.show(this.travelMode.closest("dl")); + Util_1.default.show(this.googleLink); + Util_1.default.innerError(this.originInput, false); } else { // map irrelevant errors to not found error - if (status !== 'OVER_QUERY_LIMIT' && status !== 'REQUEST_DENIED') { - status = 'NOT_FOUND'; + if (status !== "OVER_QUERY_LIMIT" && status !== "REQUEST_DENIED") { + status = google.maps.DirectionsStatus.NOT_FOUND; } - elInnerError(this._originInput, Language.get('wcf.map.route.error.' + status.toLowerCase())); + Util_1.default.innerError(this.originInput, Language.get(`wcf.map.route.error.${status.toLowerCase()}`)); } - }, + } /** * Updates the route after the travel mode has been changed. */ - _updateRoute: function () { + updateRoute() { this._calculateRoute({ - location: this._lastOrigin + location: this.lastOrigin, }); } - }; - return Planner; + /** + * Sets up the route planner dialog. + */ + _dialogSetup() { + return { + id: this.button.id + "Dialog", + options: { + onShow: this.initDialog.bind(this), + title: Language.get("wcf.map.route.planner"), + }, + source: ` + + + + +
+
${Language.get("wcf.map.route.origin")}
+
+ +
+
+
+
${Language.get("wcf.map.route.travelMode")}
+
+ +
+
`, + }; + } + } + Core.enableLegacyInheritance(ControllerMapRoutePlanner); + return ControllerMapRoutePlanner; }); diff --git a/wcfsetup/install/files/ts/WoltLabSuite/Core/Controller/Map/Route/Planner.js b/wcfsetup/install/files/ts/WoltLabSuite/Core/Controller/Map/Route/Planner.js deleted file mode 100644 index 730fbe1e69..0000000000 --- a/wcfsetup/install/files/ts/WoltLabSuite/Core/Controller/Map/Route/Planner.js +++ /dev/null @@ -1,205 +0,0 @@ -/** - * Map route planner based on Google Maps. - * - * @author Matthias Schmidt - * @copyright 2001-2019 WoltLab GmbH - * @license GNU Lesser General Public License - * @module WoltLabSuite/Core/Controller/Map/Route/Planner - */ -define([ - 'Dom/Traverse', - 'Dom/Util', - 'Language', - 'Ui/Dialog', - 'WoltLabSuite/Core/Ajax/Status' -], function( - DomTraverse, - DomUtil, - Language, - UiDialog, - AjaxStatus -) { - /** - * @constructor - */ - function Planner(buttonId, destination) { - this._button = elById(buttonId); - if (this._button === null) { - throw new Error("Unknown button with id '" + buttonId + "'"); - } - - this._button.addEventListener('click', this._openDialog.bind(this)); - - this._destination = destination; - } - Planner.prototype = { - /** - * Sets up the route planner dialog. - */ - _dialogSetup: function() { - return { - id: this._button.id + 'Dialog', - options: { - onShow: this._initDialog.bind(this), - title: Language.get('wcf.map.route.planner') - }, - source: '' + - '' + - '
' + - '
' + Language.get('wcf.map.route.origin') + '
' + - '
' + - '
' + - '
' + - '
' + Language.get('wcf.map.route.travelMode') + '
' + - '
' + - '' + - '
' + - '
' - } - }, - - /** - * Calculates the route based on the given result of a location search. - * - * @param {object} data - */ - _calculateRoute: function(data) { - var dialog = UiDialog.getDialog(this).dialog; - - if (data.label) { - this._originInput.value = data.label; - } - - if (this._map === undefined) { - this._map = new google.maps.Map(elByClass('googleMap', dialog)[0], { - disableDoubleClickZoom: WCF.Location.GoogleMaps.Settings.get('disableDoubleClickZoom'), - draggable: WCF.Location.GoogleMaps.Settings.get('draggable'), - mapTypeId: google.maps.MapTypeId.ROADMAP, - scaleControl: WCF.Location.GoogleMaps.Settings.get('scaleControl'), - scrollwheel: WCF.Location.GoogleMaps.Settings.get('scrollwheel') - }); - - this._directionsService = new google.maps.DirectionsService(); - this._directionsRenderer = new google.maps.DirectionsRenderer(); - - this._directionsRenderer.setMap(this._map); - this._directionsRenderer.setPanel(elByClass('googleMapsDirections', dialog)[0]); - - this._googleLink = elByClass('googleMapsDirectionsGoogleLink', dialog)[0]; - } - - var request = { - destination: this._destination, - origin: data.location, - provideRouteAlternatives: true, - travelMode: google.maps.TravelMode[this._travelMode.value.toUpperCase()] - }; - - AjaxStatus.show(); - this._directionsService.route(request, this._setRoute.bind(this)); - - elAttr(this._googleLink, 'href', this._getGoogleMapsLink(data.location, this._travelMode.value)); - - this._lastOrigin = data.location; - }, - - /** - * Returns the Google Maps link based on the given optional directions origin - * and optional travel mode. - * - * @param {google.maps.LatLng} origin - * @param {string} travelMode - * @return {string} - */ - _getGoogleMapsLink: function(origin, travelMode) { - if (origin) { - var link = 'https://www.google.com/maps/dir/?api=1' + - '&origin=' + origin.lat() + ',' + origin.lng() + '' + - '&destination=' + this._destination.lat() + ',' + this._destination.lng(); - - if (travelMode) { - link += '&travelmode=' + travelMode; - } - - return link; - } - - return 'https://www.google.com/maps/search/?api=1&query=' + this._destination.lat() + ',' + this._destination.lng(); - }, - - /** - * Initializes the route planning dialog. - */ - _initDialog: function() { - if (!this._didInitDialog) { - var dialog = UiDialog.getDialog(this).dialog; - - // make input element a location search - this._originInput = elBySel('input[name="origin"]', dialog); - new WCF.Location.GoogleMaps.LocationSearch(this._originInput, this._calculateRoute.bind(this)); - - this._travelMode = elBySel('select[name="travelMode"]', dialog); - this._travelMode.addEventListener('change', this._updateRoute.bind(this)); - - this._didInitDialog = true; - } - }, - - /** - * Opens the route planning dialog. - */ - _openDialog: function() { - UiDialog.open(this); - }, - - /** - * Handles the response of the direction service. - * - * @param {object} result - * @param {string} status - */ - _setRoute: function(result, status) { - AjaxStatus.hide(); - - if (status === 'OK') { - elShow(this._map.getDiv().parentNode); - - google.maps.event.trigger(this._map, 'resize'); - - this._directionsRenderer.setDirections(result); - - elShow(DomTraverse.parentByTag(this._travelMode, 'DL')); - elShow(this._googleLink); - - elInnerError(this._originInput, false); - } - else { - // map irrelevant errors to not found error - if (status !== 'OVER_QUERY_LIMIT' && status !== 'REQUEST_DENIED') { - status = 'NOT_FOUND'; - } - - elInnerError(this._originInput, Language.get('wcf.map.route.error.' + status.toLowerCase())); - } - }, - - /** - * Updates the route after the travel mode has been changed. - */ - _updateRoute: function() { - this._calculateRoute({ - location: this._lastOrigin - }); - } - }; - - return Planner; -}); diff --git a/wcfsetup/install/files/ts/WoltLabSuite/Core/Controller/Map/Route/Planner.ts b/wcfsetup/install/files/ts/WoltLabSuite/Core/Controller/Map/Route/Planner.ts new file mode 100644 index 0000000000..6630979bdd --- /dev/null +++ b/wcfsetup/install/files/ts/WoltLabSuite/Core/Controller/Map/Route/Planner.ts @@ -0,0 +1,215 @@ +/** + * Map route planner based on Google Maps. + * + * @author Matthias Schmidt + * @copyright 2001-2019 WoltLab GmbH + * @license GNU Lesser General Public License + * @module WoltLabSuite/Core/Controller/Map/Route/Planner + */ + +import * as AjaxStatus from "../../../Ajax/Status"; +import * as Core from "../../../Core"; +import DomUtil from "../../../Dom/Util"; +import * as Language from "../../../Language"; +import UiDialog from "../../../Ui/Dialog"; +import { DialogCallbackObject, DialogCallbackSetup } from "../../../Ui/Dialog/Data"; + +interface LocationData { + label?: string; + location: google.maps.LatLng; +} + +class ControllerMapRoutePlanner implements DialogCallbackObject { + private readonly button: HTMLElement; + private readonly destination: google.maps.LatLng; + private didInitDialog = false; + private directionsRenderer?: google.maps.DirectionsRenderer = undefined; + private directionsService?: google.maps.DirectionsService = undefined; + private googleLink?: HTMLAnchorElement = undefined; + private lastOrigin?: google.maps.LatLng = undefined; + private map?: google.maps.Map = undefined; + private originInput?: HTMLInputElement = undefined; + private travelMode?: HTMLSelectElement = undefined; + + constructor(buttonId: string, destination: google.maps.LatLng) { + const button = document.getElementById(buttonId); + if (button === null) { + throw new Error(`Unknown button with id '${buttonId}'`); + } + this.button = button; + + this.button.addEventListener("click", (ev) => this.openDialog(ev)); + + this.destination = destination; + } + + /** + * Calculates the route based on the given result of a location search. + */ + _calculateRoute(data: LocationData): void { + const dialog = UiDialog.getDialog(this)!.dialog; + + if (data.label) { + this.originInput!.value = data.label; + } + + if (this.map === undefined) { + const mapContainer = dialog.querySelector(".googleMap") as HTMLElement; + this.map = new google.maps.Map(mapContainer, { + disableDoubleClickZoom: window.WCF.Location.GoogleMaps.Settings.get("disableDoubleClickZoom"), + draggable: window.WCF.Location.GoogleMaps.Settings.get("draggable"), + mapTypeId: google.maps.MapTypeId.ROADMAP, + scaleControl: window.WCF.Location.GoogleMaps.Settings.get("scaleControl"), + scrollwheel: window.WCF.Location.GoogleMaps.Settings.get("scrollwheel"), + }); + + this.directionsService = new google.maps.DirectionsService(); + this.directionsRenderer = new google.maps.DirectionsRenderer(); + + this.directionsRenderer.setMap(this.map); + const directionsContainer = dialog.querySelector(".googleMapsDirections") as HTMLElement; + this.directionsRenderer.setPanel(directionsContainer); + + this.googleLink = dialog.querySelector(".googleMapsDirectionsGoogleLink") as HTMLAnchorElement; + } + + const request = { + destination: this.destination, + origin: data.location, + provideRouteAlternatives: true, + travelMode: google.maps.TravelMode[this.travelMode!.value.toUpperCase()], + }; + + AjaxStatus.show(); + this.directionsService!.route(request, (result, status) => this.setRoute(result, status)); + + this.googleLink!.href = this.getGoogleMapsLink(data.location, this.travelMode!.value); + + this.lastOrigin = data.location; + } + + /** + * Returns the Google Maps link based on the given optional directions origin + * and optional travel mode. + */ + private getGoogleMapsLink(origin?: google.maps.LatLng, travelMode?: string): string { + if (origin) { + let link = `https://www.google.com/maps/dir/?api=1&origin=${origin.lat()},${origin.lng()}&destination=${this.destination.lat()},${this.destination.lng()}`; + + if (travelMode) { + link += `&travelmode=${travelMode}`; + } + + return link; + } + + return `https://www.google.com/maps/search/?api=1&query=${this.destination.lat()},${this.destination.lng()}`; + } + + /** + * Initializes the route planning dialog. + */ + private initDialog(): void { + if (!this.didInitDialog) { + const dialog = UiDialog.getDialog(this)!.dialog; + + // make input element a location search + this.originInput = dialog.querySelector('input[name="origin"]') as HTMLInputElement; + new window.WCF.Location.GoogleMaps.LocationSearch(this.originInput, (data) => this._calculateRoute(data)); + + this.travelMode = dialog.querySelector('select[name="travelMode"]') as HTMLSelectElement; + this.travelMode.addEventListener("change", this.updateRoute.bind(this)); + + this.didInitDialog = true; + } + } + + /** + * Opens the route planning dialog. + */ + private openDialog(event: Event): void { + event.preventDefault(); + + UiDialog.open(this); + } + + /** + * Handles the response of the direction service. + */ + private setRoute(result: google.maps.DirectionsResult, status: google.maps.DirectionsStatus): void { + AjaxStatus.hide(); + + if (status === "OK") { + DomUtil.show(this.map!.getDiv().parentElement!); + + google.maps.event.trigger(this.map, "resize"); + + this.directionsRenderer!.setDirections(result); + + DomUtil.show(this.travelMode!.closest("dl")!); + DomUtil.show(this.googleLink!); + + DomUtil.innerError(this.originInput!, false); + } else { + // map irrelevant errors to not found error + if (status !== "OVER_QUERY_LIMIT" && status !== "REQUEST_DENIED") { + status = google.maps.DirectionsStatus.NOT_FOUND; + } + + DomUtil.innerError(this.originInput!, Language.get(`wcf.map.route.error.${status.toLowerCase()}`)); + } + } + + /** + * Updates the route after the travel mode has been changed. + */ + private updateRoute(): void { + this._calculateRoute({ + location: this.lastOrigin!, + }); + } + + /** + * Sets up the route planner dialog. + */ + _dialogSetup(): ReturnType { + return { + id: this.button.id + "Dialog", + options: { + onShow: this.initDialog.bind(this), + title: Language.get("wcf.map.route.planner"), + }, + source: ` + + + + +
+
${Language.get("wcf.map.route.origin")}
+
+ +
+
+
+
${Language.get("wcf.map.route.travelMode")}
+
+ +
+
`, + }; + } +} + +Core.enableLegacyInheritance(ControllerMapRoutePlanner); + +export = ControllerMapRoutePlanner;