diff --git a/index.php b/index.php
index 4cc57487..a9ca721c 100644
--- a/index.php
+++ b/index.php
@@ -65,6 +65,7 @@ html_export_var(array(
diff --git a/lang/ast.json b/lang/ast.json
index 6792c3f9..14e3629d 100644
--- a/lang/ast.json
+++ b/lang/ast.json
@@ -3,9 +3,10 @@
"category-info-tooltip": "",
"closed": "",
"default": "",
- "download:geojson": "",
"edit": "",
"error": "",
+ "export:GeoJSON": "",
+ "export:OSMXML": null,
"facilities": "",
"header:attributes": "",
"header:export": "",
diff --git a/lang/ca.json b/lang/ca.json
index 92fbcbad..09abd388 100644
--- a/lang/ca.json
+++ b/lang/ca.json
@@ -3,9 +3,10 @@
"category-info-tooltip": "",
"closed": "",
"default": "",
- "download:geojson": "",
"edit": "",
"error": "",
+ "export:GeoJSON": "",
+ "export:OSMXML": null,
"facilities": "",
"header:attributes": "",
"header:export": "",
diff --git a/lang/cs.json b/lang/cs.json
index 6a00b20d..2a7bdff8 100644
--- a/lang/cs.json
+++ b/lang/cs.json
@@ -3,9 +3,10 @@
"category-info-tooltip": "",
"closed": "",
"default": "",
- "download:geojson": "",
"edit": "",
"error": "",
+ "export:GeoJSON": "",
+ "export:OSMXML": null,
"facilities": "",
"header:attributes": "",
"header:export": "",
diff --git a/lang/da.json b/lang/da.json
index 246c041a..1a01e3e8 100644
--- a/lang/da.json
+++ b/lang/da.json
@@ -3,9 +3,10 @@
"category-info-tooltip": "",
"closed": "",
"default": "",
- "download:geojson": "",
"edit": "",
"error": "",
+ "export:GeoJSON": "",
+ "export:OSMXML": null,
"facilities": "",
"header:attributes": "",
"header:export": "",
diff --git a/lang/de.json b/lang/de.json
index 36a8c64e..76e55319 100644
--- a/lang/de.json
+++ b/lang/de.json
@@ -3,12 +3,13 @@
"category-info-tooltip": "Info & Legende",
"closed": "geschlossen",
"default": "Standard",
- "download:geojson": "Als GeoJSON runterladen",
"edit": "bearbeiten",
"error": {
"message": "Fehler",
"!=1": "Fehler"
},
+ "export:GeoJSON": "Als GeoJSON runterladen",
+ "export:OSMXML": null,
"facilities": "Einrichtungen",
"header:attributes": "Attribute",
"header:export": "Export",
diff --git a/lang/el.json b/lang/el.json
index 92acb3fc..82412698 100644
--- a/lang/el.json
+++ b/lang/el.json
@@ -3,9 +3,10 @@
"category-info-tooltip": "",
"closed": "",
"default": "",
- "download:geojson": "",
"edit": "",
"error": "",
+ "export:GeoJSON": "",
+ "export:OSMXML": null,
"facilities": "",
"header:attributes": "",
"header:export": "",
diff --git a/lang/en.json b/lang/en.json
index 62a959c0..1791c258 100644
--- a/lang/en.json
+++ b/lang/en.json
@@ -3,12 +3,15 @@
"category-info-tooltip": "Info & Map key",
"closed": "closed",
"default": "default",
- "download:geojson": "Download as GeoJSON",
"edit": "edit",
"error": {
"message": "Error",
"!=1": "Errors"
},
+ "export-all": "Export all visible map features",
+ "export-prepare": "Prepare download",
+ "export:GeoJSON": "Download as GeoJSON",
+ "export:OSMXML": "Download as OSMXML",
"facilities": "Facilities",
"header:attributes": "Attributes",
"header:export": "Export",
diff --git a/lang/es.json b/lang/es.json
index 62837550..4f34b83a 100644
--- a/lang/es.json
+++ b/lang/es.json
@@ -3,9 +3,10 @@
"category-info-tooltip": "",
"closed": "",
"default": "",
- "download:geojson": "",
"edit": "",
"error": "",
+ "export:GeoJSON": "",
+ "export:OSMXML": null,
"facilities": "",
"header:attributes": "",
"header:export": "",
diff --git a/lang/et.json b/lang/et.json
index 9e346130..2cfc0df7 100644
--- a/lang/et.json
+++ b/lang/et.json
@@ -3,9 +3,10 @@
"category-info-tooltip": "",
"closed": "",
"default": "",
- "download:geojson": "",
"edit": "",
"error": "",
+ "export:GeoJSON": "",
+ "export:OSMXML": null,
"facilities": "",
"header:attributes": "",
"header:export": "",
diff --git a/lang/fr.json b/lang/fr.json
index 2e9720c6..afd65d26 100644
--- a/lang/fr.json
+++ b/lang/fr.json
@@ -3,9 +3,10 @@
"category-info-tooltip": "Info & Légende",
"closed": "Fermé",
"default": "Par défaut",
- "download:geojson": "Télécharger comme GeoJSON",
"edit": "éditer",
"error": "Erreur",
+ "export:GeoJSON": "Télécharger comme GeoJSON",
+ "export:OSMXML": null,
"facilities": "Aménagements",
"header:attributes": "Attributs",
"header:export": "Export",
diff --git a/lang/hu.json b/lang/hu.json
index 49fe6e02..c8a12808 100644
--- a/lang/hu.json
+++ b/lang/hu.json
@@ -3,9 +3,10 @@
"category-info-tooltip": "Információk és jelmagyarázat",
"closed": "Lezárva",
"default": "Alapértelmezett",
- "download:geojson": "Letöltés GeoJSON formátumban",
"edit": "Szerkesztés",
"error": "Hiba",
+ "export:GeoJSON": "Letöltés GeoJSON formátumban",
+ "export:OSMXML": null,
"facilities": "Létesítmények",
"header:attributes": "Tulajdonságok",
"header:export": "Exportálás",
diff --git a/lang/it.json b/lang/it.json
index caa1f358..f100e93c 100644
--- a/lang/it.json
+++ b/lang/it.json
@@ -3,9 +3,10 @@
"category-info-tooltip": "",
"closed": "",
"default": "",
- "download:geojson": "",
"edit": "",
"error": "",
+ "export:GeoJSON": "",
+ "export:OSMXML": null,
"facilities": "",
"header:attributes": "",
"header:export": "",
diff --git a/lang/ja.json b/lang/ja.json
index d1d9466f..9685ac1b 100644
--- a/lang/ja.json
+++ b/lang/ja.json
@@ -3,9 +3,10 @@
"category-info-tooltip": "",
"closed": "",
"default": "",
- "download:geojson": "",
"edit": "",
"error": "",
+ "export:GeoJSON": "",
+ "export:OSMXML": null,
"facilities": "",
"header:attributes": "",
"header:export": "",
diff --git a/lang/nl.json b/lang/nl.json
index 0c555511..ef7ccbee 100644
--- a/lang/nl.json
+++ b/lang/nl.json
@@ -3,9 +3,10 @@
"category-info-tooltip": "",
"closed": "",
"default": "",
- "download:geojson": "",
"edit": "",
"error": "",
+ "export:GeoJSON": "",
+ "export:OSMXML": null,
"facilities": "",
"header:attributes": "",
"header:export": "",
diff --git a/lang/pl.json b/lang/pl.json
index 2dbff807..bf0c7120 100644
--- a/lang/pl.json
+++ b/lang/pl.json
@@ -3,9 +3,10 @@
"category-info-tooltip": "",
"closed": "",
"default": "",
- "download:geojson": "",
"edit": "",
"error": "",
+ "export:GeoJSON": "",
+ "export:OSMXML": null,
"facilities": "",
"header:attributes": "",
"header:export": "",
diff --git a/lang/pt-br.json b/lang/pt-br.json
index 008e8b05..607fc336 100644
--- a/lang/pt-br.json
+++ b/lang/pt-br.json
@@ -3,12 +3,13 @@
"category-info-tooltip": "Info & Legenda",
"closed": "fechado",
"default": "padrão",
- "download:geojson": "Baixar como GeoJSON",
"edit": "editar",
"error": {
"message": "Erro",
"!=1": "Erros"
},
+ "export:GeoJSON": "Baixar como GeoJSON",
+ "export:OSMXML": null,
"facilities": "Instalações",
"header:attributes": "Atributos",
"header:export": "Exportar",
diff --git a/lang/pt.json b/lang/pt.json
index 42293725..372bc6f0 100644
--- a/lang/pt.json
+++ b/lang/pt.json
@@ -3,12 +3,13 @@
"category-info-tooltip": "Info & Legenda",
"closed": "fechado",
"default": "padrão",
- "download:geojson": "Descarregar como GeoJSON",
"edit": "editar",
"error": {
"message": "Erro",
"!=1": "Erros"
},
+ "export:GeoJSON": "Descarregar como GeoJSON",
+ "export:OSMXML": null,
"facilities": "Instalações",
"header:attributes": "Atributos",
"header:export": "Exportar",
diff --git a/lang/ro.json b/lang/ro.json
index 393b5e82..46d1fe29 100644
--- a/lang/ro.json
+++ b/lang/ro.json
@@ -3,9 +3,10 @@
"category-info-tooltip": "",
"closed": "",
"default": "",
- "download:geojson": "",
"edit": "",
"error": "",
+ "export:GeoJSON": "",
+ "export:OSMXML": null,
"facilities": "",
"header:attributes": "",
"header:export": "",
diff --git a/lang/ru.json b/lang/ru.json
index 1c8389ad..fc7c04a8 100644
--- a/lang/ru.json
+++ b/lang/ru.json
@@ -3,9 +3,10 @@
"category-info-tooltip": "",
"closed": "",
"default": "",
- "download:geojson": "",
"edit": "",
"error": "",
+ "export:GeoJSON": "",
+ "export:OSMXML": null,
"facilities": "",
"header:attributes": "",
"header:export": "",
diff --git a/lang/sr.json b/lang/sr.json
index b53e0904..d07af30e 100644
--- a/lang/sr.json
+++ b/lang/sr.json
@@ -3,9 +3,10 @@
"category-info-tooltip": "",
"closed": "",
"default": "",
- "download:geojson": "",
"edit": "",
"error": "",
+ "export:GeoJSON": "",
+ "export:OSMXML": null,
"facilities": "",
"header:attributes": "",
"header:export": "",
diff --git a/lang/template.json b/lang/template.json
index 09c4e48c..16e3970e 100644
--- a/lang/template.json
+++ b/lang/template.json
@@ -3,9 +3,10 @@
"category-info-tooltip": "",
"closed": "",
"default": "",
- "download:geojson": "",
"edit": "",
"error": "",
+ "export:GeoJSON": "",
+ "export:OSMXML": null,
"facilities": "",
"header:attributes": "",
"header:export": "",
diff --git a/lang/uk.json b/lang/uk.json
index 11018c7e..8f514591 100644
--- a/lang/uk.json
+++ b/lang/uk.json
@@ -3,9 +3,10 @@
"category-info-tooltip": "",
"closed": "",
"default": "",
- "download:geojson": "",
"edit": "",
"error": "",
+ "export:GeoJSON": "",
+ "export:OSMXML": null,
"facilities": "",
"header:attributes": "",
"header:export": "",
diff --git a/lib/modulekit/form b/lib/modulekit/form
index 8a2d3015..5d39b2f6 160000
--- a/lib/modulekit/form
+++ b/lib/modulekit/form
@@ -1 +1 @@
-Subproject commit 8a2d3015ec181b14441037a79e7db3869453b135
+Subproject commit 5d39b2f61b7eda9a635414acaeb3c4e0dc524490
diff --git a/package.json b/package.json
index 39329b25..5d6c1690 100644
--- a/package.json
+++ b/package.json
@@ -16,6 +16,7 @@
"babel-core": "^6.26.0",
"babel-preset-env": "^1.6.1",
"color-interpolate": "^1.0.2",
+ "file-saver": "^2.0.0",
"i18next-client": "^1.11.4",
"ip-location": "^1.0.1",
"json-multiline-strings": "^0.1.0",
diff --git a/src/CategoryBase.js b/src/CategoryBase.js
index 7b7a489f..261767b2 100644
--- a/src/CategoryBase.js
+++ b/src/CategoryBase.js
@@ -204,4 +204,8 @@ CategoryBase.prototype.notifyChildLoadEnd = function (category) {
}
}
+CategoryBase.prototype.allMapFeatures = function (callback) {
+ callback(null, [])
+}
+
module.exports = CategoryBase
diff --git a/src/CategoryIndex.js b/src/CategoryIndex.js
index dc2d0828..0a44e85c 100644
--- a/src/CategoryIndex.js
+++ b/src/CategoryIndex.js
@@ -106,5 +106,24 @@ CategoryIndex.prototype.toggleCategory = function (id) {
}.bind(this))
}
+CategoryIndex.prototype.allMapFeatures = function (callback) {
+ let result = []
+
+ async.each(this.childrenCategories,
+ (category, done) => category.allMapFeatures(
+ (err, data) => {
+ if (err) {
+ return done(err)
+ }
+
+ result = result.concat(data)
+
+ global.setTimeout(done, 0)
+ }
+ ),
+ (err) => callback(err, result)
+ )
+}
+
OpenStreetBrowserLoader.registerType('index', CategoryIndex)
module.exports = CategoryIndex
diff --git a/src/CategoryOverpass.js b/src/CategoryOverpass.js
index 2b8fd58f..35e79922 100644
--- a/src/CategoryOverpass.js
+++ b/src/CategoryOverpass.js
@@ -491,5 +491,13 @@ CategoryOverpass.prototype.renderTemplate = function (object, templateId, callba
})
}
+CategoryOverpass.prototype.allMapFeatures = function (callback) {
+ if (!this.isOpen) {
+ return callback(null, [])
+ }
+
+ callback(null, Object.values(this.layer.mainlayer.visibleFeatures))
+}
+
OpenStreetBrowserLoader.registerType('overpass', CategoryOverpass)
module.exports = CategoryOverpass
diff --git a/src/ExportGeoJSON.js b/src/ExportGeoJSON.js
new file mode 100644
index 00000000..4a9434f5
--- /dev/null
+++ b/src/ExportGeoJSON.js
@@ -0,0 +1,34 @@
+class ExportGeoJSON {
+ constructor (conf) {
+ this.conf = conf
+ }
+
+ each (ob, callback) {
+ ob.object.exportGeoJSON(this.conf, callback)
+ }
+
+ finishOne (object) {
+ return {
+ content: JSON.stringify(object, null, ' '),
+ fileType: 'application/json',
+ extension: 'geojson'
+ }
+ }
+
+ finish (list) {
+ if (list.length) {
+ list = {
+ type: 'FeatureCollection',
+ features: list
+ }
+ }
+
+ return {
+ content: JSON.stringify(list, null, ' '),
+ fileType: 'application/json',
+ extension: 'geojson'
+ }
+ }
+}
+
+module.exports = ExportGeoJSON
diff --git a/src/ExportOSMJSON.js b/src/ExportOSMJSON.js
new file mode 100644
index 00000000..1929c478
--- /dev/null
+++ b/src/ExportOSMJSON.js
@@ -0,0 +1,24 @@
+class ExportOSMXML {
+ constructor (conf) {
+ this.conf = conf
+ this.elements = {}
+ }
+
+ each (ob, callback) {
+ ob.object.exportOSMJSON(this.conf, this.elements, callback)
+ }
+
+ finish (list) {
+ return {
+ content: JSON.stringify({
+ version: '0.6',
+ generator: 'OpenStreetBrowser',
+ elements: Object.values(this.elements)
+ }, null, ' '),
+ fileType: 'application/json',
+ extension: 'osm.json'
+ }
+ }
+}
+
+module.exports = ExportOSMXML
diff --git a/src/ExportOSMXML.js b/src/ExportOSMXML.js
new file mode 100644
index 00000000..9858b6e0
--- /dev/null
+++ b/src/ExportOSMXML.js
@@ -0,0 +1,20 @@
+class ExportOSMXML {
+ constructor (conf) {
+ this.conf = conf
+ this.parentNode = document.createElement('osm')
+ }
+
+ each (ob, callback) {
+ ob.object.exportOSMXML(this.conf, this.parentNode, callback)
+ }
+
+ finish (list) {
+ return {
+ content: '
' + this.parentNode.innerHTML + '',
+ fileType: 'application/xml',
+ extension: 'osm.xml'
+ }
+ }
+}
+
+module.exports = ExportOSMXML
diff --git a/src/chunkSplit.js b/src/chunkSplit.js
new file mode 100644
index 00000000..c850b879
--- /dev/null
+++ b/src/chunkSplit.js
@@ -0,0 +1,9 @@
+module.exports = function chunkSplit (data, size=1000) {
+ let result = []
+
+ for (let i = 0; i < data.length; i += size) {
+ result.push(data.slice(i, i + size))
+ }
+
+ return result
+}
diff --git a/src/exportAll.js b/src/exportAll.js
new file mode 100644
index 00000000..4cf06bca
--- /dev/null
+++ b/src/exportAll.js
@@ -0,0 +1,148 @@
+const tabs = require('modulekit-tabs')
+const async = require('async')
+const FileSaver = require('file-saver')
+
+const chunkSplit = require('./chunkSplit')
+
+const types = {
+ GeoJSON: require('./ExportGeoJSON'),
+ OSMXML: require('./ExportOSMXML'),
+ OSMJSON: require('./ExportOSMJSON')
+}
+
+let tab
+let formExport
+
+function prepareDownload (callback) {
+ let conf = formExport.get_data()
+
+ global.baseCategory.allMapFeatures((err, data) => {
+ if (err) {
+ return callback(err)
+ }
+
+ createDownload(conf, data, callback)
+ })
+}
+
+function createDownload (conf, data, callback) {
+ let type = types[conf.type]
+ let exportFun = new type(conf)
+
+ let chunks = chunkSplit(data, 1000)
+ let parentNode
+
+ async.mapLimit(
+ chunks,
+ 1,
+ (chunk, done) => {
+ async.map(chunk,
+ (ob, done) => exportFun.each(ob, done),
+ (err, result) => {
+ global.setTimeout(() => done(err, result), 0)
+ }
+ )
+ },
+ (err, data) => {
+ if (err) {
+ return callback(err)
+ }
+
+ data = data.reduce((all, chunk) => all.concat(chunk))
+
+ let result = exportFun.finish(data)
+
+ var blob = new Blob([ result.content ], { type: result.fileType + ';charset=utf-8' })
+ FileSaver.saveAs(blob, 'openstreetbrowser.' + result.extension)
+
+ callback()
+ }
+ )
+}
+
+function formDef () {
+ let values = {}
+ Object.keys(types).forEach(type =>
+ values[type] = lang('export:' + type)
+ )
+
+ return {
+ type: {
+ name: 'Type',
+ type: 'radio',
+ values,
+ default: Object.keys(types)[0]
+ }
+ }
+}
+
+register_hook('init', function () {
+ tab = new tabs.Tab({
+ id: 'export'
+ })
+ global.tabs.add(tab)
+
+ tab.header.innerHTML = '
'
+ tab.header.title = lang('export-all')
+ tab.content.innerHTML = '
' + lang('export-all') + '
'
+
+ formExport = new form('export', formDef())
+
+ let domForm = document.createElement('form')
+ tab.content.appendChild(domForm)
+ formExport.show(domForm)
+
+ let submit = document.createElement('input')
+ submit.type = 'submit'
+ submit.value = lang('export-prepare')
+ submit.onclick = () => {
+ let progressIndicator = document.createElement('div')
+ progressIndicator.innerHTML = '
' + lang('loading')
+ tab.content.appendChild(progressIndicator)
+ submit.style.display = 'none'
+
+ prepareDownload((err) => {
+ if (err) {
+ alert(err)
+ }
+
+ submit.style.display = 'block'
+ tab.content.removeChild(progressIndicator)
+ tab.unselect()
+ })
+ }
+ tab.content.appendChild(submit)
+
+ tab.on('select', () => {
+ formExport.resize()
+ })
+})
+
+module.exports = (data, div) => {
+ let formExport = new form('exportOne', formDef())
+
+ let domForm = document.createElement('form')
+ div.appendChild(domForm)
+ formExport.show(domForm)
+
+ let submit = document.createElement('input')
+ submit.type = 'submit'
+ submit.value = lang('export-prepare')
+ submit.onclick = () => {
+ let progressIndicator = document.createElement('div')
+ progressIndicator.innerHTML = '
' + lang('loading')
+ div.appendChild(progressIndicator)
+ submit.style.display = 'none'
+
+ let conf = formExport.get_data()
+ createDownload(conf, [ data ], (err) => {
+ if (err) {
+ alert(err)
+ }
+
+ submit.style.display = 'block'
+ div.removeChild(progressIndicator)
+ })
+ }
+ div.appendChild(submit)
+}
diff --git a/src/index.js b/src/index.js
index 0dab30bf..ebf7bff7 100644
--- a/src/index.js
+++ b/src/index.js
@@ -1,6 +1,7 @@
/* globals map:true, overpassFrontend:true, currentPath:true, options:true, baseCategory:true, overpassUrl:true showDetails */
var LeafletGeoSearch = require('leaflet-geosearch')
+const tabs = require('modulekit-tabs')
var OverpassFrontend = require('overpass-frontend')
var OpenStreetBrowserLoader = require('./OpenStreetBrowserLoader')
@@ -17,6 +18,7 @@ global.baseCategory = null
global.overpassUrl = null
global.overpassFrontend = null
global.currentPath = null
+global.tabs = null
var lastPopupClose = 0
// Optional modules
@@ -31,6 +33,7 @@ require('./categories')
require('./wikipedia')
require('./image')
require('./addCategories')
+let exportAll = require('./exportAll')
window.onload = function () {
var initState = config.defaultView
@@ -42,6 +45,8 @@ window.onload = function () {
options = {}
}
+ global.tabs = new tabs.Tabs(document.getElementById('globalTabs'))
+
call_hooks('init')
call_hooks_callback('init_callback', initState, onload2.bind(this, initState))
@@ -163,6 +168,10 @@ function onload2 (initState) {
call_hooks('initFinish')
}
+global.allMapFeatures = function (callback) {
+ global.baseCategory.allMapFeatures(callback)
+}
+
window.setPath = function (path, state) {
currentPath = path
@@ -285,17 +294,9 @@ window.showDetails = function (data, category) {
h.innerHTML = lang('header:export')
dom.appendChild(h)
- div = document.createElement('ul')
+ div = document.createElement('div')
dom.appendChild(div)
-
- li = document.createElement('li')
- div.appendChild(li)
-
- a = document.createElement('a')
- a.download = data.id + '.json'
- a.href = 'data:application/json;charset=UTF-8,' + encodeURIComponent(JSON.stringify(data.object.GeoJSON(), null, ' '))
- a.innerHTML = lang('download:geojson')
- li.appendChild(a)
+ exportAll(data, div)
h = document.createElement('h3')
h.innerHTML = lang('header:attributes')
diff --git a/style.css b/style.css
index ddc416e2..ee0a8534 100644
--- a/style.css
+++ b/style.css
@@ -77,6 +77,11 @@ a:active {
font-size: 16px;
}
+#sidebar > #globalTabs {
+ padding-left: 10px;
+ padding-right: 10px;
+}
+
#sidebar > #content {
flex: 1;
flex-shrink: 0;