Merge pull request #1295 from umap-project/load-all-before-download

Make sure we load all data before downloading it
This commit is contained in:
Yohan Boniface 2023-09-01 16:59:30 +02:00 committed by GitHub
commit f57ef51bf6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 284 additions and 21 deletions

View file

@ -986,9 +986,10 @@ L.U.Map.include({
const status = this.permissions.getShareStatusDisplay() const status = this.permissions.getShareStatusDisplay()
name.textContent = this.getDisplayName() name.textContent = this.getDisplayName()
// status is not set until map is saved once // status is not set until map is saved once
if (status) share_status.textContent = L._('Visibility: {status}', { if (status)
status: status, share_status.textContent = L._('Visibility: {status}', {
}) status: status,
})
} }
update() update()
this.once('saved', L.bind(update, this)) this.once('saved', L.bind(update, this))
@ -1129,19 +1130,38 @@ L.U.Map.include({
toggleCaveat() toggleCaveat()
const download = L.DomUtil.create('a', 'button', container) const download = L.DomUtil.create('a', 'button', container)
download.textContent = L._('Download data') download.textContent = L._('Download data')
L.DomEvent.on(download, 'click', () => this.download(typeInput.value), this) L.DomEvent.on(
download,
'click',
() => {
if (typeInput.value === 'umap') this.fullDownload()
else this.download(typeInput.value)
}
)
this.ui.openPanel({ data: { html: container } }) this.ui.openPanel({ data: { html: container } })
}, },
download: function (mode) { fullDownload: function () {
// Make sure all data is loaded before downloading
this.once('dataloaded', () => this.download())
this.loadDatalayers(true) // Force load
},
format: function (mode) {
const type = this.EXPORT_TYPES[mode || 'umap'] const type = this.EXPORT_TYPES[mode || 'umap']
const content = type.formatter(this) const content = type.formatter(this)
let name = this.options.name || 'data' let name = this.options.name || 'data'
name = name.replace(/[^a-z0-9]/gi, '_').toLowerCase() name = name.replace(/[^a-z0-9]/gi, '_').toLowerCase()
const filename = name + type.ext
return {content, filetype: type.filetype, filename}
},
download: function (mode) {
const {content, filetype, filename} = this.format(mode)
const blob = new Blob([content], { type: filetype })
window.URL = window.URL || window.webkitURL window.URL = window.URL || window.webkitURL
const blob = new Blob([content], { type: type.filetype })
const el = document.createElement('a') const el = document.createElement('a')
el.download = name + type.ext el.download = filename
el.href = window.URL.createObjectURL(blob) el.href = window.URL.createObjectURL(blob)
el.style.display = 'none' el.style.display = 'none'
document.body.appendChild(el) document.body.appendChild(el)

View file

@ -379,33 +379,41 @@ L.U.Map.include({
}, },
initDatalayers: function () { initDatalayers: function () {
let toload = (dataToload = seen = this.options.datalayers.length) for (let j = 0; j < this.options.datalayers.length; j++) {
const self = this this.createDataLayer(this.options.datalayers[j])
}
this.loadDatalayers()
},
loadDatalayers: function (force) {
force = force || L.Util.queryString('download') // In case we are in download mode, let's go strait to loading all data
let toload = (dataToload = total = this.datalayers_index.length)
let datalayer let datalayer
const loaded = () => { const loaded = () => {
self.datalayersLoaded = true this.datalayersLoaded = true
self.fire('datalayersloaded') this.fire('datalayersloaded')
} }
const decrementToLoad = () => { const decrementToLoad = () => {
toload-- toload--
if (toload === 0) loaded() if (toload === 0) loaded()
} }
const dataLoaded = () => { const dataLoaded = () => {
self.dataLoaded = true this.dataLoaded = true
self.fire('dataloaded') this.fire('dataloaded')
} }
const decrementDataToLoad = () => { const decrementDataToLoad = () => {
dataToload-- dataToload--
if (dataToload === 0) dataLoaded() if (dataToload === 0) dataLoaded()
} }
for (let j = 0; j < this.options.datalayers.length; j++) { this.eachDataLayer(function (datalayer) {
datalayer = this.createDataLayer(this.options.datalayers[j]) if (force && !datalayer.hasDataLoaded()) datalayer.show()
if (datalayer.displayedOnLoad()) datalayer.onceLoaded(decrementToLoad) if (datalayer.displayedOnLoad() || force) datalayer.onceLoaded(decrementToLoad)
else decrementToLoad() else decrementToLoad()
if (datalayer.displayedOnLoad()) datalayer.onceDataLoaded(decrementDataToLoad) if (datalayer.displayedOnLoad() || force)
datalayer.onceDataLoaded(decrementDataToLoad)
else decrementDataToLoad() else decrementDataToLoad()
} })
if (seen === 0) { if (total === 0) {
// no datalayer // no datalayer
loaded() loaded()
dataLoaded() dataLoaded()
@ -1128,9 +1136,11 @@ L.U.Map.include({
}, },
serialize: function () { serialize: function () {
// Do not use local path during unit tests
const uri = window.location.protocol === 'file:' ? null : window.location.href
const umapfile = { const umapfile = {
type: 'umap', type: 'umap',
uri: window.location.href, uri: uri,
properties: this.exportOptions(), properties: this.exportOptions(),
geometry: this.geometry(), geometry: this.geometry(),
layers: [], layers: [],

View file

@ -0,0 +1,230 @@
describe('L.U.Map.Export', function () {
before(function () {
this.server = sinon.fakeServer.create()
this.server.respondWith(
/\/datalayer\/62\/\?.*/,
JSON.stringify(RESPONSES.datalayer62_GET)
)
this.options = {
umap_id: 99,
}
this.map = initMap({ umap_id: 99 })
this.server.respond()
this.datalayer = this.map.getDataLayerByUmapId(62)
})
after(function () {
this.server.restore()
clickCancel()
resetMap()
})
describe('#formatters()', function () {
it('should export to geojson', function () {
const { content, filetype, filename } = this.map.format('geojson')
assert.equal(filetype, 'application/json')
assert.equal(filename, 'name_of_the_map.geojson')
assert.deepEqual(JSON.parse(content), {
type: 'FeatureCollection',
features: [
{
type: 'Feature',
properties: {
name: 'name poly',
},
geometry: {
type: 'Polygon',
coordinates: [
[
[11.25, 53.585984],
[10.151367, 52.975108],
[12.689209, 52.167194],
[14.084473, 53.199452],
[12.634277, 53.618579],
[11.25, 53.585984],
[11.25, 53.585984],
],
],
},
},
{
type: 'Feature',
properties: {
_umap_options: {
color: 'OliveDrab',
},
name: 'test',
},
geometry: {
type: 'Point',
coordinates: [-0.274658, 52.57635],
},
},
{
type: 'Feature',
properties: {
_umap_options: {
fill: false,
},
name: 'test',
},
geometry: {
type: 'LineString',
coordinates: [
[-0.571289, 54.476422],
[0.439453, 54.610255],
[1.724854, 53.448807],
[4.163818, 53.988395],
[5.306396, 53.533778],
[6.591797, 53.709714],
[7.042236, 53.350551],
],
},
},
],
})
})
it('should export to gpx', function () {
const { content, filetype, filename } = this.map.format('gpx')
assert.equal(filetype, 'application/gpx+xml')
assert.equal(filename, 'name_of_the_map.gpx')
const expected =
'<gpx xmlns="http://www.topografix.com/GPX/1/1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd" version="1.1" creator="togpx"><metadata/><wpt lat="52.57635" lon="-0.274658"><name>test</name><desc>name=test</desc></wpt><trk><name>name poly</name><desc>name=name poly</desc><trkseg><trkpt lat="53.585984" lon="11.25"/><trkpt lat="52.975108" lon="10.151367"/><trkpt lat="52.167194" lon="12.689209"/><trkpt lat="53.199452" lon="14.084473"/><trkpt lat="53.618579" lon="12.634277"/><trkpt lat="53.585984" lon="11.25"/><trkpt lat="53.585984" lon="11.25"/></trkseg></trk><trk><name>test</name><desc>name=test</desc><trkseg><trkpt lat="54.476422" lon="-0.571289"/><trkpt lat="54.610255" lon="0.439453"/><trkpt lat="53.448807" lon="1.724854"/><trkpt lat="53.988395" lon="4.163818"/><trkpt lat="53.533778" lon="5.306396"/><trkpt lat="53.709714" lon="6.591797"/><trkpt lat="53.350551" lon="7.042236"/></trkseg></trk></gpx>'
assert.equal(content, expected)
})
it('should export to gpx', function () {
const { content, filetype, filename } = this.map.format('kml')
assert.equal(filetype, 'application/vnd.google-earth.kml+xml')
assert.equal(filename, 'name_of_the_map.kml')
const expected =
'<?xml version="1.0" encoding="UTF-8"?><kml xmlns="http://www.opengis.net/kml/2.2"><Document><Placemark><name>name poly</name><ExtendedData><Data name="name"><value>name poly</value></Data></ExtendedData><Polygon><outerBoundaryIs><LinearRing><coordinates>11.25,53.585984 10.151367,52.975108 12.689209,52.167194 14.084473,53.199452 12.634277,53.618579 11.25,53.585984 11.25,53.585984</coordinates></LinearRing></outerBoundaryIs></Polygon></Placemark><Placemark><name>test</name><ExtendedData><Data name="_umap_options"><value>[object Object]</value></Data><Data name="name"><value>test</value></Data></ExtendedData><Point><coordinates>-0.274658,52.57635</coordinates></Point></Placemark><Placemark><name>test</name><ExtendedData><Data name="_umap_options"><value>[object Object]</value></Data><Data name="name"><value>test</value></Data></ExtendedData><LineString><coordinates>-0.571289,54.476422 0.439453,54.610255 1.724854,53.448807 4.163818,53.988395 5.306396,53.533778 6.591797,53.709714 7.042236,53.350551</coordinates></LineString></Placemark></Document></kml>'
assert.equal(content, expected)
})
it('should export to umap', function () {
const { content, filetype, filename } = this.map.format('umap')
assert.equal(filetype, 'application/json')
assert.equal(filename, 'name_of_the_map.umap')
const expected = {
type: 'umap',
uri: null,
properties: {
easing: false,
embedControl: true,
fullscreenControl: true,
searchControl: true,
datalayersControl: true,
zoomControl: true,
permanentCreditBackground: true,
slideshow: {},
captionMenus: true,
captionBar: false,
limitBounds: {},
overlay: null,
tilelayer: {
attribution: 'HOT and friends',
name: 'HOT OSM-fr server',
url_template: 'http://{s}.tile.openstreetmap.fr/hot/{z}/{x}/{y}.png',
rank: 99,
minZoom: 0,
maxZoom: 20,
id: 2,
},
licence: '',
description: 'The description of the map',
name: 'name of the map',
displayPopupFooter: false,
miniMap: false,
moreControl: true,
scaleControl: true,
scrollWheelZoom: true,
zoom: 6,
},
geometry: {
type: 'Point',
coordinates: [5.0592041015625, 52.05924589011585],
},
layers: [
{
type: 'FeatureCollection',
features: [
{
type: 'Feature',
properties: {
name: 'name poly',
},
geometry: {
type: 'Polygon',
coordinates: [
[
[11.25, 53.585984],
[10.151367, 52.975108],
[12.689209, 52.167194],
[14.084473, 53.199452],
[12.634277, 53.618579],
[11.25, 53.585984],
[11.25, 53.585984],
],
],
},
},
{
type: 'Feature',
properties: {
_umap_options: {
color: 'OliveDrab',
},
name: 'test',
},
geometry: {
type: 'Point',
coordinates: [-0.274658, 52.57635],
},
},
{
type: 'Feature',
properties: {
_umap_options: {
fill: false,
},
name: 'test',
},
geometry: {
type: 'LineString',
coordinates: [
[-0.571289, 54.476422],
[0.439453, 54.610255],
[1.724854, 53.448807],
[4.163818, 53.988395],
[5.306396, 53.533778],
[6.591797, 53.709714],
[7.042236, 53.350551],
],
},
},
],
_umap_options: {
displayOnLoad: true,
browsable: true,
iconClass: 'Default',
name: 'Elephants',
id: 62,
pictogram_url: null,
opacity: null,
weight: null,
fillColor: '',
color: '',
stroke: true,
smoothFactor: null,
dashArray: '',
fillOpacity: null,
fill: true,
},
},
],
}
assert.deepEqual(JSON.parse(content), expected)
})
})
})

View file

@ -1,4 +1,4 @@
describe('L.Utorage.Polyline', function () { describe('L.U.Polyline', function () {
var p2ll, map var p2ll, map
before(function () { before(function () {

View file

@ -23,6 +23,8 @@
<script src="../vendors/measurable/Leaflet.Measurable.js"></script> <script src="../vendors/measurable/Leaflet.Measurable.js"></script>
<script src="../vendors/locatecontrol/L.Control.Locate.js"></script> <script src="../vendors/locatecontrol/L.Control.Locate.js"></script>
<script src="../vendors/dompurify/purify.js"></script> <script src="../vendors/dompurify/purify.js"></script>
<script src="../vendors/togpx/togpx.js"></script>
<script src="../vendors/tokml/tokml.js"></script>
<script src="../js/umap.core.js"></script> <script src="../js/umap.core.js"></script>
<script src="../js/umap.autocomplete.js"></script> <script src="../js/umap.autocomplete.js"></script>
<script src="../js/umap.popup.js"></script> <script src="../js/umap.popup.js"></script>
@ -68,6 +70,7 @@
<script src="./_pre.js"></script> <script src="./_pre.js"></script>
<script src="./Map.js"></script> <script src="./Map.js"></script>
<script src="./Map.Init.js"></script> <script src="./Map.Init.js"></script>
<script src="./Map.Export.js"></script>
<script src="./DataLayer.js"></script> <script src="./DataLayer.js"></script>
<script src="./TableEditor.js"></script> <script src="./TableEditor.js"></script>
<script src="./Feature.js"></script> <script src="./Feature.js"></script>