diff --git a/umap/static/umap/js/modules/global.js b/umap/static/umap/js/modules/global.js index c7fce53f1..fa6f4d933 100644 --- a/umap/static/umap/js/modules/global.js +++ b/umap/static/umap/js/modules/global.js @@ -1,10 +1,20 @@ import * as L from '../../vendors/leaflet/leaflet-src.esm.js' import URLs from './urls.js' import Browser from './browser.js' +import Importer from './importer.js' import { Request, ServerRequest, RequestError, HTTPError, NOKError } from './request.js' // Import modules and export them to the global scope. // For the not yet module-compatible JS out there. // Copy the leaflet module, it's expected by leaflet plugins to be writeable. window.L = { ...L } -window.U = { URLs, Request, ServerRequest, RequestError, HTTPError, NOKError, Browser } +window.U = { + URLs, + Request, + ServerRequest, + RequestError, + HTTPError, + NOKError, + Browser, + Importer, +} diff --git a/umap/static/umap/js/modules/importer.js b/umap/static/umap/js/modules/importer.js new file mode 100644 index 000000000..2135ab009 --- /dev/null +++ b/umap/static/umap/js/modules/importer.js @@ -0,0 +1,143 @@ +export default class Importer { + constructor(map) { + this.map = map + } + + open() { + if (!this.form) this._build() + this.map.ui.openPanel({ + data: { html: this.form }, + className: 'dark', + }) + } + + openFiles() { + this.open() + this.fileInput.showPicker() + } + + _build() { + const template = document.querySelector('#umap-upload') + this.form = template.content.firstElementChild.cloneNode(true) + + this.typeLabel = this.form.querySelector('#type-label') + const helpButton = this.typeLabel.querySelector('button') + this.map.help.button(this.typeLabel, 'importFormats', '', helpButton) + + this.layerSelect = this.form.querySelector('[name="datalayer"]') + this._buildDatalayerOptions(this.layerSelect) + this.presetSelect = this.form.querySelector('[name="preset-select"]') + this._buildPresetsOptions(this.presetSelect) + + this.fileInput = this.form.querySelector('[name="file-input"]') + this.formatSelect = this.form.querySelector('[name="format"]') + + this._connectedCallback() + } + + _buildDatalayerOptions(layerSelect) { + const options = [] + this.map.eachDataLayerReverse((datalayer) => { + if (datalayer.isLoaded() && !datalayer.isRemoteLayer()) { + options.push( + `` + ) + } + }) + options.push(``) + layerSelect.innerHTML = options.join('') + } + + _buildPresetsOptions(presetSelect) { + const presets = this.map.options.importPresets + if (!presets.length) return + const options = [] + presetSelect.parentElement.removeAttribute('hidden') + options.push( + `` + ) + for (const preset of presets) { + options.push(``) + } + presetSelect.innerHTML = options.join('') + } + + _connectedCallback() { + const controller = new AbortController() + const signal = controller.signal + this.form + .querySelector('[name="submit-input"]') + .addEventListener('click', this._submit.bind(this), { signal }) + + this.fileInput.addEventListener( + 'change', + (e) => { + let type = '' + let newType + for (const file of e.target.files) { + newType = L.Util.detectFileType(file) + if (!type && newType) { + type = newType + } + if (type && newType !== type) { + type = '' + break + } + } + this.formatSelect.value = type + }, + { signal } + ) + + this.map.ui.once( + 'panel:closed', + () => { + this.fileInput.value = null + controller.abort() + }, + { signal } + ) + } + + _submit() { + const urlInputValue = this.form.querySelector('[name="url-input"]').value + const rawInputValue = this.form.querySelector('[name="raw-input"]').value + const clearFlag = this.form.querySelector('[name="clear"]') + const type = this.formatSelect.value + const layerId = this.layerSelect[this.layerSelect.selectedIndex].value + let layer + if (type === 'umap') { + this.map.once('postsync', this.map._setDefaultCenter) + } + if (layerId) layer = this.map.datalayers[layerId] + if (layer && clearFlag.checked) layer.empty() + if (this.fileInput.files.length) { + for (const file of this.fileInput.files) { + this.map.processFileToImport(file, layer, type) + } + } else { + if (!type) + return this.map.ui.alert({ + content: L._('Please choose a format'), + level: 'error', + }) + if (rawInputValue && type === 'umap') { + try { + this.map.importRaw(rawInputValue, type) + } catch (e) { + this.ui.alert({ content: L._('Invalid umap data'), level: 'error' }) + console.error(e) + } + } else { + if (!layer) layer = this.map.createDataLayer() + if (rawInputValue) layer.importRaw(rawInputValue, type) + else if (urlInputValue) layer.importFromUrl(urlInputValue, type) + else if (this.presetSelect.selectedIndex > 0) + layer.importFromUrl( + this.presetSelect[this.presetSelect.selectedIndex].value, + type + ) + } + } + } +} diff --git a/umap/static/umap/js/umap.core.js b/umap/static/umap/js/umap.core.js index 1dcda4b2f..2edba8637 100644 --- a/umap/static/umap/js/umap.core.js +++ b/umap/static/umap/js/umap.core.js @@ -598,12 +598,10 @@ U.Help = L.Class.extend({ return typeof this[name] === 'function' ? this[name]() : this[name] }, - button: function (container, entries, classname) { - const helpButton = L.DomUtil.createButton( - classname || 'umap-help-button', - container, - L._('Help') - ) + button: function (container, entries, classname, button) { + const helpButton = + button || + L.DomUtil.createButton(classname || 'umap-help-button', container, L._('Help')) if (entries) { L.DomEvent.on(helpButton, 'click', L.DomEvent.stop).on( helpButton, diff --git a/umap/static/umap/js/umap.importer.js b/umap/static/umap/js/umap.importer.js deleted file mode 100644 index 461932000..000000000 --- a/umap/static/umap/js/umap.importer.js +++ /dev/null @@ -1,167 +0,0 @@ -U.Importer = L.Class.extend({ - TYPES: ['geojson', 'csv', 'gpx', 'kml', 'osm', 'georss', 'umap'], - initialize: function (map) { - this.map = map - this.presets = map.options.importPresets - }, - - build: function () { - this.container = L.DomUtil.create('div', 'umap-upload') - this.title = L.DomUtil.add('h3', '', this.container, L._('Import data')) - this.presetBox = L.DomUtil.create('div', 'formbox', this.container) - this.presetSelect = L.DomUtil.create('select', '', this.presetBox) - this.fileBox = L.DomUtil.create('div', 'formbox', this.container) - this.fileInput = L.DomUtil.element( - 'input', - { type: 'file', multiple: 'multiple', autofocus: true }, - this.fileBox - ) - this.map.ui.once('panel:closed', () => (this.fileInput.value = null)) - this.urlInput = L.DomUtil.element( - 'input', - { type: 'text', placeholder: L._('Provide an URL here') }, - this.container - ) - this.rawInput = L.DomUtil.element( - 'textarea', - { placeholder: L._('Paste your data here') }, - this.container - ) - this.typeLabel = L.DomUtil.add( - 'label', - '', - this.container, - L._('Choose the format of the data to import') - ) - this.layerLabel = L.DomUtil.add( - 'label', - '', - this.container, - L._('Choose the layer to import in') - ) - this.clearLabel = L.DomUtil.add( - 'label', - '', - this.container, - L._('Replace layer content') - ) - this.submitInput = L.DomUtil.element( - 'input', - { type: 'button', value: L._('Import'), className: 'button' }, - this.container - ) - this.map.help.button(this.typeLabel, 'importFormats') - this.typeInput = L.DomUtil.element('select', { name: 'format' }, this.typeLabel) - this.layerInput = L.DomUtil.element( - 'select', - { name: 'datalayer' }, - this.layerLabel - ) - this.clearFlag = L.DomUtil.element( - 'input', - { type: 'checkbox', name: 'clear' }, - this.clearLabel - ) - let option - this.map.eachDataLayerReverse((datalayer) => { - if (datalayer.isLoaded() && !datalayer.isRemoteLayer()) { - const id = L.stamp(datalayer) - option = L.DomUtil.add('option', '', this.layerInput, datalayer.options.name) - option.value = id - } - }) - L.DomUtil.element( - 'option', - { value: '', textContent: L._('Import in a new layer') }, - this.layerInput - ) - L.DomUtil.element( - 'option', - { value: '', textContent: L._('Choose the data format') }, - this.typeInput - ) - for (let i = 0; i < this.TYPES.length; i++) { - option = L.DomUtil.create('option', '', this.typeInput) - option.value = option.textContent = this.TYPES[i] - } - if (this.presets.length) { - const noPreset = L.DomUtil.create('option', '', this.presetSelect) - noPreset.value = noPreset.textContent = L._('Choose a preset') - for (let j = 0; j < this.presets.length; j++) { - option = L.DomUtil.create('option', '', presetSelect) - option.value = this.presets[j].url - option.textContent = this.presets[j].label - } - } else { - this.presetBox.style.display = 'none' - } - L.DomEvent.on(this.submitInput, 'click', this.submit, this) - L.DomEvent.on( - this.fileInput, - 'change', - (e) => { - let type = '', - newType - for (let i = 0; i < e.target.files.length; i++) { - newType = L.Util.detectFileType(e.target.files[i]) - if (!type && newType) type = newType - if (type && newType !== type) { - type = '' - break - } - } - this.typeInput.value = type - }, - this - ) - }, - - open: function () { - if (!this.container) this.build() - this.map.ui.openPanel({ data: { html: this.container }, className: 'dark' }) - }, - - openFiles: function () { - this.open() - this.fileInput.showPicker() - }, - - submit: function () { - let type = this.typeInput.value - const layerId = this.layerInput[this.layerInput.selectedIndex].value - let layer - if (type === 'umap') { - this.map.once('postsync', this.map._setDefaultCenter) - } - if (layerId) layer = this.map.datalayers[layerId] - if (layer && this.clearFlag.checked) layer.empty() - if (this.fileInput.files.length) { - for (let i = 0, file; (file = this.fileInput.files[i]); i++) { - this.map.processFileToImport(file, layer, type) - } - } else { - if (!type) - return this.map.ui.alert({ - content: L._('Please choose a format'), - level: 'error', - }) - if (this.rawInput.value && type === 'umap') { - try { - this.map.importRaw(this.rawInput.value, type) - } catch (e) { - this.ui.alert({ content: L._('Invalid umap data'), level: 'error' }) - console.error(e) - } - } else { - if (!layer) layer = this.map.createDataLayer() - if (this.rawInput.value) layer.importRaw(this.rawInput.value, type) - else if (this.urlInput.value) layer.importFromUrl(this.urlInput.value, type) - else if (this.presetSelect.selectedIndex > 0) - layer.importFromUrl( - this.presetSelect[this.presetSelect.selectedIndex].value, - type - ) - } - } - }, -}) diff --git a/umap/static/umap/test/index.html b/umap/static/umap/test/index.html index 23c9d52fd..068a9ce55 100644 --- a/umap/static/umap/test/index.html +++ b/umap/static/umap/test/index.html @@ -44,7 +44,6 @@ - diff --git a/umap/templates/umap/js.html b/umap/templates/umap/js.html index ca839ae1d..2f1221929 100644 --- a/umap/templates/umap/js.html +++ b/umap/templates/umap/js.html @@ -45,7 +45,6 @@ - diff --git a/umap/templates/umap/map_init.html b/umap/templates/umap/map_init.html index 91713b35d..398022e4a 100644 --- a/umap/templates/umap/map_init.html +++ b/umap/templates/umap/map_init.html @@ -1,5 +1,45 @@ -{% load umap_tags %} +{% load i18n umap_tags %}
+ +