mirror of
https://github.com/umap-project/umap.git
synced 2025-05-06 06:21:49 +02:00
Merge 76d30e8602
into d0738e93e7
This commit is contained in:
commit
8d8acdd19e
7 changed files with 199 additions and 177 deletions
|
@ -1,10 +1,20 @@
|
||||||
import * as L from '../../vendors/leaflet/leaflet-src.esm.js'
|
import * as L from '../../vendors/leaflet/leaflet-src.esm.js'
|
||||||
import URLs from './urls.js'
|
import URLs from './urls.js'
|
||||||
import Browser from './browser.js'
|
import Browser from './browser.js'
|
||||||
|
import Importer from './importer.js'
|
||||||
import { Request, ServerRequest, RequestError, HTTPError, NOKError } from './request.js'
|
import { Request, ServerRequest, RequestError, HTTPError, NOKError } from './request.js'
|
||||||
// Import modules and export them to the global scope.
|
// Import modules and export them to the global scope.
|
||||||
// For the not yet module-compatible JS out there.
|
// For the not yet module-compatible JS out there.
|
||||||
|
|
||||||
// Copy the leaflet module, it's expected by leaflet plugins to be writeable.
|
// Copy the leaflet module, it's expected by leaflet plugins to be writeable.
|
||||||
window.L = { ...L }
|
window.L = { ...L }
|
||||||
window.U = { URLs, Request, ServerRequest, RequestError, HTTPError, NOKError, Browser }
|
window.U = {
|
||||||
|
URLs,
|
||||||
|
Request,
|
||||||
|
ServerRequest,
|
||||||
|
RequestError,
|
||||||
|
HTTPError,
|
||||||
|
NOKError,
|
||||||
|
Browser,
|
||||||
|
Importer,
|
||||||
|
}
|
||||||
|
|
143
umap/static/umap/js/modules/importer.js
Normal file
143
umap/static/umap/js/modules/importer.js
Normal file
|
@ -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(
|
||||||
|
`<option value="${L.stamp(datalayer)}">${datalayer.options.name}</option>`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
options.push(`<option value="">${L._('Import in a new layer')}</option>`)
|
||||||
|
layerSelect.innerHTML = options.join('')
|
||||||
|
}
|
||||||
|
|
||||||
|
_buildPresetsOptions(presetSelect) {
|
||||||
|
const presets = this.map.options.importPresets
|
||||||
|
if (!presets.length) return
|
||||||
|
const options = []
|
||||||
|
presetSelect.parentElement.removeAttribute('hidden')
|
||||||
|
options.push(
|
||||||
|
`<option value="${L._('Choose a preset')}">${L._('Choose a preset')}</option>`
|
||||||
|
)
|
||||||
|
for (const preset of presets) {
|
||||||
|
options.push(`<option value="${preset.url}">${preset.label}</option>`)
|
||||||
|
}
|
||||||
|
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
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -598,12 +598,10 @@ U.Help = L.Class.extend({
|
||||||
return typeof this[name] === 'function' ? this[name]() : this[name]
|
return typeof this[name] === 'function' ? this[name]() : this[name]
|
||||||
},
|
},
|
||||||
|
|
||||||
button: function (container, entries, classname) {
|
button: function (container, entries, classname, button) {
|
||||||
const helpButton = L.DomUtil.createButton(
|
const helpButton =
|
||||||
classname || 'umap-help-button',
|
button ||
|
||||||
container,
|
L.DomUtil.createButton(classname || 'umap-help-button', container, L._('Help'))
|
||||||
L._('Help')
|
|
||||||
)
|
|
||||||
if (entries) {
|
if (entries) {
|
||||||
L.DomEvent.on(helpButton, 'click', L.DomEvent.stop).on(
|
L.DomEvent.on(helpButton, 'click', L.DomEvent.stop).on(
|
||||||
helpButton,
|
helpButton,
|
||||||
|
|
|
@ -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
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
})
|
|
|
@ -44,7 +44,6 @@
|
||||||
<script src="../js/umap.controls.js" defer></script>
|
<script src="../js/umap.controls.js" defer></script>
|
||||||
<script src="../js/umap.slideshow.js" defer></script>
|
<script src="../js/umap.slideshow.js" defer></script>
|
||||||
<script src="../js/umap.tableeditor.js" defer></script>
|
<script src="../js/umap.tableeditor.js" defer></script>
|
||||||
<script src="../js/umap.importer.js" defer></script>
|
|
||||||
<script src="../js/umap.share.js" defer></script>
|
<script src="../js/umap.share.js" defer></script>
|
||||||
<script src="../js/umap.js" defer></script>
|
<script src="../js/umap.js" defer></script>
|
||||||
<script src="../js/umap.ui.js" defer></script>
|
<script src="../js/umap.ui.js" defer></script>
|
||||||
|
|
|
@ -56,7 +56,6 @@
|
||||||
<script src="{% static 'umap/js/umap.controls.js' %}" defer></script>
|
<script src="{% static 'umap/js/umap.controls.js' %}" defer></script>
|
||||||
<script src="{% static 'umap/js/umap.slideshow.js' %}" defer></script>
|
<script src="{% static 'umap/js/umap.slideshow.js' %}" defer></script>
|
||||||
<script src="{% static 'umap/js/umap.tableeditor.js' %}" defer></script>
|
<script src="{% static 'umap/js/umap.tableeditor.js' %}" defer></script>
|
||||||
<script src="{% static 'umap/js/umap.importer.js' %}" defer></script>
|
|
||||||
<script src="{% static 'umap/js/umap.share.js' %}" defer></script>
|
<script src="{% static 'umap/js/umap.share.js' %}" defer></script>
|
||||||
<script src="{% static 'umap/js/umap.js' %}" defer></script>
|
<script src="{% static 'umap/js/umap.js' %}" defer></script>
|
||||||
<script src="{% static 'umap/js/umap.ui.js' %}" defer></script>
|
<script src="{% static 'umap/js/umap.ui.js' %}" defer></script>
|
||||||
|
|
|
@ -1,5 +1,45 @@
|
||||||
{% load umap_tags %}
|
{% load i18n umap_tags %}
|
||||||
<div id="map"></div>
|
<div id="map"></div>
|
||||||
|
|
||||||
|
<template id="umap-upload">
|
||||||
|
<form class="umap-upload">
|
||||||
|
<h4>{% blocktrans %}Import data{% endblocktrans %}</h4>
|
||||||
|
<div id="preset-box" class="formbox" hidden>
|
||||||
|
<select name="preset-select"></select>
|
||||||
|
</div>
|
||||||
|
<div class="formbox">
|
||||||
|
<input type="file" name="file-input" multiple>
|
||||||
|
</div>
|
||||||
|
<input type="url" name="url-input" placeholder="{% blocktrans %}Provide an URL here{% endblocktrans %}">
|
||||||
|
<textarea name="raw-input" placeholder="{% blocktrans %}Paste your data here{% endblocktrans %}"></textarea>
|
||||||
|
|
||||||
|
<label id="type-label">
|
||||||
|
{% blocktrans %}Choose the format of the data to import{% endblocktrans %}
|
||||||
|
<button class="umap-help-button" type="button">{% blocktrans %}Help{% endblocktrans %}</button>
|
||||||
|
<select name="format">
|
||||||
|
<option value disabled selected>
|
||||||
|
{% blocktrans %}Choose the data format{% endblocktrans %}
|
||||||
|
</option>
|
||||||
|
<option value="geojson">geojson</option>
|
||||||
|
<option value="csv">csv</option>
|
||||||
|
<option value="gpx">gpx</option>
|
||||||
|
<option value="kml">kml</option>
|
||||||
|
<option value="osm">osm</option>
|
||||||
|
<option value="georss">georss</option>
|
||||||
|
<option value="umap">umap</option>
|
||||||
|
</select>
|
||||||
|
</label>
|
||||||
|
<label id="layer-label">
|
||||||
|
{% blocktrans %}Choose the layer to import in{% endblocktrans %}
|
||||||
|
<select name="datalayer"></select>
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
{% blocktrans %}Replace layer content{% endblocktrans %}
|
||||||
|
<input type="checkbox" name="clear">
|
||||||
|
</label>
|
||||||
|
<input type="button" class="button" name="submit-input" value="{% blocktrans %}Import{% endblocktrans %}">
|
||||||
|
</form>
|
||||||
|
</template>
|
||||||
<!-- djlint:off -->
|
<!-- djlint:off -->
|
||||||
<script defer type="text/javascript">
|
<script defer type="text/javascript">
|
||||||
window.addEventListener('DOMContentLoaded', (event) => {
|
window.addEventListener('DOMContentLoaded', (event) => {
|
||||||
|
|
Loading…
Reference in a new issue