Create small previews for chosen map providers
// ==UserScript== // @name WME E58 Map's previews // @name:uk WME 🇺🇦 E58 Map's previews // @version 0.6.3 // @description Create small previews for chosen map providers // @description:uk Створює невеличку карту для перегляду // @license MIT License // @author Anton Shevchuk // @namespace https://greasyfork.org/users/227648-anton-shevchuk // @supportURL https://github.com/AntonShevchuk/wme-e58/issues // @match https://*.waze.com/editor* // @match https://*.waze.com/*/editor* // @exclude https://*.waze.com/user/editor* // @icon data:image/png;base64,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 // @grant none // @require https://update.greasyfork.org/scripts/389765/1090053/CommonUtils.js // @require https://update.greasyfork.org/scripts/450160/1218867/WME-Bootstrap.js // @require https://update.greasyfork.org/scripts/450221/1137043/WME-Base.js // @require https://update.greasyfork.org/scripts/450320/1555446/WME-UI.js // ==/UserScript== /* jshint esversion: 8 */ /* global require */ /* global $, jQuery */ /* global W */ /* global I18n */ /* global WME, WMEBase, WMEUI, WMEUIHelper */ /* global Container, Settings, SimpleCache, Tools */ /* global H, google */ (function () { 'use strict' const NAME = 'E58' // Translation const TRANSLATION = { 'en': { // Tab title title: 'Map preview', // Tab description description: 'Open a small preview modal window with the map', // Tab help help: 'You can use the <a href="#keyboard-dialog" target="_blank" rel="noopener noreferrer" data-toggle="modal">Keyboard shortcuts</a> to open the map preview window. It\'s more convenient than clicking on the button.', maps: { // Fieldset's legend title: 'Sources', // Fieldset's description description: 'Choose a map provider', // Description for option `Google` google: 'Google', // Description for option `OSM` osm: 'Open Street Map', }, options: { title: 'Options', description: 'Choose a map provider in the settings', controls: 'Controls on the map', interactive: 'Interaction with the map', }, }, 'uk': { title: 'Карта', description: 'Відкрити маленьку карту', help: 'Використовуйте <a href="#keyboard-dialog" target="_blank" rel="noopener noreferrer" data-toggle="modal">гарячі клавіши</a>, це значно швидше ніж використовувати кнопку', maps: { title: 'Джерела', description: 'Оберіть карту для відображення', google: 'Google', osm: 'Open Street Map', }, options: { title: 'Налаштування', description: 'Оберіть у налаштуваннях карту для відображення', controls: 'Елементи управління', interactive: 'Можливість взаємодіяти с картою', }, }, 'ru': { title: 'Карта', description: 'Открыть маленькую карту', help: 'Используйте <a href="#keyboard-dialog" target="_blank" rel="noopener noreferrer" data-toggle="modal">комбинации клавиш</a>, и не надо будет клацать кнопку', maps: { title: 'Источники', description: 'Выберите карту для отображения', google: 'Google', osm: 'Open Street Map', }, options: { title: 'Настройки', description: 'Выберите в настройках карту для отображения', controls: 'Элементи управления карты', interactive: 'Возможность взаимодествия с картой', }, } } const STYLE = '.e58 .header h5 { padding: 16px 16px 0; font-size: 16px }' + '.e58 legend { cursor:pointer; font-size: 12px; font-weight: bold; width: auto; text-align: right; border: 0; margin: 0; padding: 0 8px; }' + '.e58 fieldset { border: 1px solid #ddd; padding: 4px; }' + '.e58 fieldset p { padding: 0; margin: 0 8px !important; }' + '.e58 fieldset.e58 div.controls label { white-space: normal; font-weight: 400; }' + 'div.e58.e58-text { margin: 15px 0; }' + 'p.e58-info { border-top: 1px solid #ccc; color: #777; font-size: x-small; margin-top: 15px; padding-top: 10px; text-align: center; }' WMEUI.addTranslation(NAME, TRANSLATION) WMEUI.addStyle(STYLE) // Default settings const SETTINGS = { map: 'google', maps: [ 'google', 'osm' ], options: { controls: false, interactive: false, } } /** * Basic Map class */ class MapPreview { constructor (uid, container, settings) { this.uid = uid this.map = null this.wrapper = this._wrapper() container.append(this.wrapper) container.style.height = '256px' this.settings = settings this.controls = settings.get('options', 'controls') this.interactive = settings.get('options', 'interactive') } /** * Load external JS Map library * @param {String} url * @return {Promise<*>} */ async script (url) { return $.ajax({ url: url, cache: true, dataType: 'script', success: () => console.log(NAME, this.uid, 'loaded') }) } /** * Build div for map * @return {HTMLDivElement} * @protected */ _wrapper () { let div = document.createElement('div') div.id = this._uid() div.style.height = '256px' return div } _uid () { return NAME + '-map-' + this.uid } _center () { let center = new OpenLayers.Geometry.Point(W.map.getCenter().lon, W.map.getCenter().lat).transform('EPSG:900913', 'EPSG:4326') return { lon: center.x, lat: center.y, } } _zoom () { return W.map.getZoom() - 1 } update () { let center = this._center() this._update(center.lat, center.lon, this._zoom()) } _update (lat, lon, zoom) { throw new Error('Abstract method') } } /** * Google Maps */ class GooglePreview extends MapPreview { constructor (container, settings) { super('Google', container, settings) } async render () { let pos = this._center() this.map = new google.maps.Map(this.wrapper, { center: new google.maps.LatLng(pos.lat, pos.lon), zoom: this._zoom(), mapTypeId: 'roadmap', mapTypeControl: false, streetViewControl: false, disableDefaultUI: !this.controls, gestureHandling: this.interactive ? 'cooperative ' : 'none', zoomControl: this.controls, }) // Setup handler W.map.events.register('moveend', null, () => this.update()) } _update (lat, lon, zoom) { this.map.setZoom(zoom) this.map.setCenter(new google.maps.LatLng(lat, lon)) } } /** * Open Street Maps */ class OSMPreview extends MapPreview { constructor (container, settings) { super('OSM', container, settings) } async render () { let pos = this._center() this.map = new google.maps.Map(this.wrapper, { center: new google.maps.LatLng(pos.lat, pos.lon), zoom: this._zoom(), mapTypeId: 'OSM', mapTypeControl: false, streetViewControl: false, disableDefaultUI: !this.controls, gestureHandling: this.interactive ? 'cooperative ' : 'none', zoomControl: this.controls, }) // Define OSM map type pointing at the OpenStreetMap tile server this.map.mapTypes.set('OSM', new google.maps.ImageMapType({ getTileUrl: function (coord, zoom) { return 'https://tile.openstreetmap.org/' + zoom + '/' + coord.x + '/' + coord.y + '.png' }, tileSize: new google.maps.Size(256, 256), name: 'OpenStreetMap', maxZoom: 18 })) // Setup handler W.map.events.register('moveend', null, () => this.update()) } _update (lat, lon, zoom) { this.map.setZoom(zoom) this.map.setCenter(new google.maps.LatLng(lat, lon)) } } /** * E58 Map Preview class */ class E58 extends WMEBase { constructor (name, settings) { super(name, settings) this.helper = new WMEUIHelper(name) let tab = this.helper.createTab( I18n.t(name).title, { image: GM_info.script.icon } ) tab.addText('description', I18n.t(name).description) let button = tab.addButton('preview', I18n.t(name).title, '', () => this.toggleMap()) button.html().className += ' waze-btn-blue' // Setup providers map settings let fsMap = this.helper.createFieldset(I18n.t(name).maps.title) for (let i = 0; i < settings.maps.length; i++) { let map = settings.maps[i] fsMap.addRadio( 'maps-' + map, I18n.t(name).maps[map], () => this.settings.set(['map'], map), 'maps', map, this.settings.get('map') === map ) } tab.addElement(fsMap) // Setup options for maps let fsOptions = this.helper.createFieldset(I18n.t(name).options.title) for (let item in settings.options) { if (settings.options.hasOwnProperty(item)) { fsOptions.addCheckbox( 'options-' + item, I18n.t(name).options[item], (event) => this.settings.set(['options', item], event.target.checked), this.settings.get('options', item)) } } tab.addElement(fsOptions) tab.addDiv('text', I18n.t(name).help) tab.addText( 'info', '<a href="' + GM_info.scriptUpdateURL + '">' + GM_info.script.name + '</a> ' + GM_info.script.version ) tab.inject() } /** * Show modal with map preview */ toggleMap () { if (document.getElementById('e58-map-preview')) { this.log('hide preview map') $('#panel-container a.close-panel').click() return } /** @type {WMEUIHelperModal} */ let modal = this.helper.createModal( I18n.t(this.name).title ) // Setup Preview Map element let map = modal.addDiv('map-preview').html() modal.inject() this.log('show preview map', this.settings.get('map')) if (this.settings.get('map') === 'google') { let Google = new GooglePreview(map, this.settings) Google.render() } else if (this.settings.get('map') === 'osm') { let OSM = new OSMPreview(map, this.settings) OSM.render() } else { // disabled map.innerText = I18n.t(this.name).maps.description } } } // Main handler $(document).on('bootstrap.wme', () => { // Create E58 Instance let Instance = new E58(NAME, SETTINGS) // Bind shortcut WMEUI.addShortcut( NAME, I18n.t(NAME).description, NAME, I18n.t(NAME).title + ' 🗺️', 'A+M', () => Instance.toggleMap(), ) }) })()