Browse Source

Merge branch '4-filter'

master
parent
commit
710fffbb0e
  1. 70
      doc/Filters.md
  2. 3
      lang/ast.json
  3. 3
      lang/ca.json
  4. 3
      lang/cs.json
  5. 3
      lang/da.json
  6. 3
      lang/de.json
  7. 3
      lang/el.json
  8. 3
      lang/en.json
  9. 3
      lang/es.json
  10. 3
      lang/et.json
  11. 3
      lang/fr.json
  12. 3
      lang/hu.json
  13. 3
      lang/it.json
  14. 3
      lang/ja.json
  15. 3
      lang/nl.json
  16. 3
      lang/pl.json
  17. 3
      lang/pt-br.json
  18. 3
      lang/pt.json
  19. 3
      lang/ro.json
  20. 3
      lang/ru.json
  21. 3
      lang/sr.json
  22. 3
      lang/template.json
  23. 3
      lang/uk.json
  24. 2
      lib/modulekit/form
  25. 8
      package.json
  26. 3
      src/CategoryBase.js
  27. 4
      src/CategoryIndex.js
  28. 58
      src/CategoryOverpass.js
  29. 234
      src/CategoryOverpassFilter.js
  30. 26
      src/OpenStreetBrowserLoader.js
  31. 8
      src/Repository.js
  32. 2
      src/RepositoryDir.php
  33. 2
      src/RepositoryGit.php
  34. 16
      src/categories.js
  35. 11
      src/getPathFromJSON.js
  36. 1
      src/index.js
  37. 2
      src/tagTranslations.js
  38. 4
      style.css
  39. 25
      test/getPathFromJSON.js

70
doc/Filters.md

@ -0,0 +1,70 @@
Each category can define a list of filters. This is an additional JSON value with the key "filter", e.g.:
```json
{
"query": {
"13": "nwr[amenity]"
},
"filter": {
"type": {
"name": "{{ keyTrans('amenity') }}",
"type": "select",
"values": {
"bar": {
"nwr[
},
}
}
}
```
This defines a filter with the ID 'type' and the translated name of the key 'amenity'. It's of type 'select' and has several possible values.
Each filter can define the following values:
* name: Name of the filter. String, which can make use of twig functions, e.g. `keyTrans` as in the above example.
* type: A form type, e.g. 'text', 'select', 'radio', 'checkbox'
* values: Possible values. Can either be an array, an object or a html string with several `<option>` tags (even for radio and checkbox). See below for more information.
* valueName: if the values do not have names (resp. an `<option>` without text content), use this twig template to create a each name. Use `{{ value }}` for the current value.
* query: A twig template which builds a query from the selected value (if the value has not a query defined), e.g. `nwr[amenity={{ value }}]`. If not defined the query will be built from `key` (or the filter ID), `op` and the selected value.
* key: If not overridden by query, use this key for searching. If not defined, use the filter's ID. Can also be an array with a list of keys. You can use wildcards too, e.g. "name:*" to query all localized name tags.
* op: operator to use (if not overridden by query):
* '=' exact match (default)
* '!=' any value nut this
* '~' regular expression, case sensitive
* '~i' regular expression, case insensitive
* '!~', '!~i' regular expression, negated
* 'has' query in semicolon-separated lists like `cuisine=kebap;noodles`
* 'strsearch' query string parts (e.g. "kai keb" would match "Kaiser Kebap") and query character variants (e.g. "cafe" would match "café").
* show_default: if true, this filter will be shown by default, others need to be added via the select box.
### Values
#### Array
Values can either be an array, e.g.
```json
[ "bar", "restaurant", ... ]
```
#### Object
Values can be an object, e.g.
```json
{ "bar":
{
"name": "Bar",
"query": "nwr[amenity=bar]"
}
}
```
* Name is optional and can be created via `valueName`.
* Query is optional, it can be created from key (or filter id), op and the value.
#### Twig template
Values can be a twig template (string). It has access to the `const` part of the category. It can create a list of options:
```html
{% for k in const %}
<option value="{{ k }}"></option>
{% endfor %}
<option value="restaurant" query="nwr[amenity=restaurant]">Restaurant</option>
```
* Name is generated from text content. If it is empty, it can be created via `valueName`.
* Query is optional, it can be created from key (or filter id), op and the value.

3
lang/ast.json

@ -1,4 +1,5 @@
{
"add_filter": "",
"available_branches": "",
"back": "",
"categories": "",
@ -13,6 +14,8 @@
"export:OSMJSON": "",
"export:OSMXML": "",
"facilities": "",
"filter:title": "",
"filter:type": "",
"header:attributes": "",
"header:export": "",
"header:osm_meta": "",

3
lang/ca.json

@ -1,4 +1,5 @@
{
"add_filter": "",
"available_branches": "",
"back": "",
"categories": "",
@ -13,6 +14,8 @@
"export:OSMJSON": "",
"export:OSMXML": "",
"facilities": "",
"filter:title": "",
"filter:type": "",
"header:attributes": "",
"header:export": "",
"header:osm_meta": "",

3
lang/cs.json

@ -1,4 +1,5 @@
{
"add_filter": "",
"available_branches": "",
"back": "",
"categories": "",
@ -13,6 +14,8 @@
"export:OSMJSON": "",
"export:OSMXML": "",
"facilities": "",
"filter:title": "",
"filter:type": "",
"header:attributes": "",
"header:export": "",
"header:osm_meta": "",

3
lang/da.json

@ -1,4 +1,5 @@
{
"add_filter": "",
"available_branches": "",
"back": "",
"categories": "",
@ -13,6 +14,8 @@
"export:OSMJSON": "",
"export:OSMXML": "",
"facilities": "",
"filter:title": "",
"filter:type": "",
"header:attributes": "",
"header:export": "",
"header:osm_meta": "",

3
lang/de.json

@ -1,4 +1,5 @@
{
"add_filter": "Filter hinzufügen",
"available_branches": "",
"back": "zurück",
"categories": "",
@ -16,6 +17,8 @@
"export:OSMJSON": "",
"export:OSMXML": "",
"facilities": "Einrichtungen",
"filter:title": "Titel",
"filter:type": "Typ",
"header:attributes": "Attribute",
"header:export": "Export",
"header:osm_meta": "OSM Meta",

3
lang/el.json

@ -1,4 +1,5 @@
{
"add_filter": "",
"available_branches": "",
"back": "",
"categories": "",
@ -13,6 +14,8 @@
"export:OSMJSON": "",
"export:OSMXML": "",
"facilities": "",
"filter:title": "",
"filter:type": "",
"header:attributes": "",
"header:export": "",
"header:osm_meta": "",

3
lang/en.json

@ -1,4 +1,5 @@
{
"add_filter": "Add filter",
"available_branches": "Available branches",
"back": "back",
"categories": "Categories",
@ -16,6 +17,8 @@
"export:OSMJSON": "Download as OSM JSON",
"export:OSMXML": "Download as OSM XML",
"facilities": "Facilities",
"filter:title": "Title",
"filter:type": "Type",
"header:attributes": "Attributes",
"header:export": "Export",
"header:osm_meta": "OSM Meta",

3
lang/es.json

@ -1,4 +1,5 @@
{
"add_filter": "",
"available_branches": "",
"back": "",
"categories": "",
@ -13,6 +14,8 @@
"export:OSMJSON": "",
"export:OSMXML": "",
"facilities": "",
"filter:title": "",
"filter:type": "",
"header:attributes": "",
"header:export": "",
"header:osm_meta": "",

3
lang/et.json

@ -1,4 +1,5 @@
{
"add_filter": "",
"available_branches": "",
"back": "",
"categories": "",
@ -13,6 +14,8 @@
"export:OSMJSON": "",
"export:OSMXML": "",
"facilities": "",
"filter:title": "",
"filter:type": "",
"header:attributes": "",
"header:export": "",
"header:osm_meta": "",

3
lang/fr.json

@ -1,4 +1,5 @@
{
"add_filter": "",
"available_branches": "Branches disponibles",
"back": "Retour",
"categories": "",
@ -13,6 +14,8 @@
"export:OSMJSON": "Format OSM JSON",
"export:OSMXML": "Format OSM XML",
"facilities": "Aménagements",
"filter:title": "",
"filter:type": "",
"header:attributes": "Attributs",
"header:export": "Export",
"header:osm_meta": "Métadonnées OSM",

3
lang/hu.json

@ -1,4 +1,5 @@
{
"add_filter": "",
"available_branches": "",
"back": "Vissza",
"categories": "",
@ -13,6 +14,8 @@
"export:OSMJSON": "",
"export:OSMXML": "",
"facilities": "Létesítmények",
"filter:title": "",
"filter:type": "",
"header:attributes": "Tulajdonságok",
"header:export": "Exportálás",
"header:osm_meta": "OSM metaadatok",

3
lang/it.json

@ -1,4 +1,5 @@
{
"add_filter": "",
"available_branches": "",
"back": "",
"categories": "",
@ -13,6 +14,8 @@
"export:OSMJSON": "",
"export:OSMXML": "",
"facilities": "",
"filter:title": "",
"filter:type": "",
"header:attributes": "",
"header:export": "",
"header:osm_meta": "",

3
lang/ja.json

@ -1,4 +1,5 @@
{
"add_filter": "",
"available_branches": "",
"back": "",
"categories": "",
@ -13,6 +14,8 @@
"export:OSMJSON": "",
"export:OSMXML": "",
"facilities": "",
"filter:title": "",
"filter:type": "",
"header:attributes": "",
"header:export": "",
"header:osm_meta": "",

3
lang/nl.json

@ -1,4 +1,5 @@
{
"add_filter": "",
"available_branches": "",
"back": "",
"categories": "",
@ -13,6 +14,8 @@
"export:OSMJSON": "",
"export:OSMXML": "",
"facilities": "",
"filter:title": "",
"filter:type": "",
"header:attributes": "",
"header:export": "",
"header:osm_meta": "",

3
lang/pl.json

@ -1,4 +1,5 @@
{
"add_filter": "",
"available_branches": "",
"back": "Wstecz",
"categories": "Kategorie",
@ -13,6 +14,8 @@
"export:OSMJSON": "",
"export:OSMXML": "",
"facilities": "",
"filter:title": "",
"filter:type": "",
"header:attributes": "",
"header:export": "Eksport",
"header:osm_meta": "",

3
lang/pt-br.json

@ -1,4 +1,5 @@
{
"add_filter": "",
"available_branches": "Redes disponíveis",
"back": "voltar",
"categories": "Categorias",
@ -16,6 +17,8 @@
"export:OSMJSON": "Baixar como OSMJSON",
"export:OSMXML": "Baixar como OSMXML",
"facilities": "Instalações",
"filter:title": "",
"filter:type": "",
"header:attributes": "Atributos",
"header:export": "Exportar",
"header:osm_meta": "OSM Meta",

3
lang/pt.json

@ -1,4 +1,5 @@
{
"add_filter": "",
"available_branches": "",
"back": "voltar",
"categories": "",
@ -16,6 +17,8 @@
"export:OSMJSON": "",
"export:OSMXML": "",
"facilities": "Instalações",
"filter:title": "",
"filter:type": "",
"header:attributes": "Atributos",
"header:export": "Exportar",
"header:osm_meta": "OSM Meta",

3
lang/ro.json

@ -1,4 +1,5 @@
{
"add_filter": "",
"available_branches": "",
"back": "",
"categories": "",
@ -13,6 +14,8 @@
"export:OSMJSON": "",
"export:OSMXML": "",
"facilities": "",
"filter:title": "",
"filter:type": "",
"header:attributes": "",
"header:export": "",
"header:osm_meta": "",

3
lang/ru.json

@ -1,4 +1,5 @@
{
"add_filter": "",
"available_branches": "",
"back": "",
"categories": "",
@ -13,6 +14,8 @@
"export:OSMJSON": "",
"export:OSMXML": "",
"facilities": "",
"filter:title": "",
"filter:type": "",
"header:attributes": "",
"header:export": "",
"header:osm_meta": "",

3
lang/sr.json

@ -1,4 +1,5 @@
{
"add_filter": "",
"available_branches": "",
"back": "",
"categories": "",
@ -13,6 +14,8 @@
"export:OSMJSON": "",
"export:OSMXML": "",
"facilities": "",
"filter:title": "",
"filter:type": "",
"header:attributes": "",
"header:export": "",
"header:osm_meta": "",

3
lang/template.json

@ -1,4 +1,5 @@
{
"add_filter": "",
"available_branches": "",
"back": "",
"categories": "",
@ -13,6 +14,8 @@
"export:OSMJSON": "",
"export:OSMXML": "",
"facilities": "",
"filter:title": "",
"filter:type": "",
"header:attributes": "",
"header:export": "",
"header:osm_meta": "",

3
lang/uk.json

@ -1,4 +1,5 @@
{
"add_filter": "",
"available_branches": "",
"back": "",
"categories": "",
@ -13,6 +14,8 @@
"export:OSMJSON": "",
"export:OSMXML": "",
"facilities": "",
"filter:title": "",
"filter:type": "",
"header:attributes": "",
"header:export": "",
"header:osm_meta": "",

2
lib/modulekit/form

@ -1 +1 @@
Subproject commit 50f1ea5eb822240876ed89504e3180f9c7dcbc05
Subproject commit 5198dc8e00d46893bd93ed3b3d71c8ea7994e1c2

8
package.json

@ -11,13 +11,14 @@
"@mapbox/maki": "^5.0.0",
"async": "^2.5.0",
"async-foreach": "^0.1.3",
"babelify": "^8.0.0",
"babel-cli": "^6.26.0",
"babel-core": "^6.26.0",
"babel-preset-env": "^1.6.1",
"babelify": "^8.0.0",
"color-interpolate": "^1.0.2",
"event-emitter": "^0.3.5",
"file-saver": "^2.0.0",
"font-awesome": "^4.7.0",
"i18next-client": "^1.11.4",
"ip-location": "^1.0.1",
"json-multiline-strings": "^0.1.0",
@ -28,7 +29,7 @@
"leaflet.locatecontrol": "^0.61.0",
"leaflet.polylinemeasure": "https://github.com/ppete2/Leaflet.PolylineMeasure.git",
"md5": "^2.2.1",
"modulekit-tabs": "^0.2.0",
"modulekit-tabs": "^0.2.1",
"moment": "^2.18.1",
"natsort": "^1.0.6",
"opening_hours": "^3.5.0",
@ -67,7 +68,7 @@
]
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"test": "mocha --bail",
"build": "npm run build-locales && browserify -g browserify-css src/index.js -o dist/tmp1.js && babel --presets env dist/tmp1.js > dist/tmp2.js && mv dist/tmp2.js dist/openstreetbrowser.js && rm dist/tmp1.js",
"build-locales": "for i in `ls locales/` ; do browserify locales/$i -o dist/locale-$i ; done",
"watch": "npm run build-locales && watchify --debug -g browserify-css src/index.js -o dist/openstreetbrowser.js -v",
@ -78,6 +79,7 @@
"browserify": "^14.4.0",
"browserify-css": "^0.14.0",
"leaflet-polylinedecorator": "https://github.com/plepe/Leaflet.PolylineDecorator.git",
"mocha": "^5.2.0",
"standard": "^10.0.2",
"watchify": "^3.9.0"
},

3
src/CategoryBase.js

@ -4,7 +4,7 @@ var OpenStreetBrowserLoader = require('./OpenStreetBrowserLoader')
var tabs = require('modulekit-tabs')
const ee = require('event-emitter')
function CategoryBase (options, data) {
function CategoryBase (options, data, repository) {
if (typeof options === 'string') {
this.id = options
this.options = {}
@ -12,6 +12,7 @@ function CategoryBase (options, data) {
this.id = options.id
this.options = options
}
this.repository = repository
this.parentCategory = null
this.childrenLoadingCount = 0
this.data = data

4
src/CategoryIndex.js

@ -5,8 +5,8 @@ var CategoryBase = require('./CategoryBase')
CategoryIndex.prototype = Object.create(CategoryBase.prototype)
CategoryIndex.prototype.constructor = CategoryIndex
function CategoryIndex (options, data) {
CategoryBase.call(this, options, data)
function CategoryIndex (options, data, repository) {
CategoryBase.call(this, options, data, repository)
this.childrenDoms = {}
this.childrenCategories = null

58
src/CategoryOverpass.js

@ -3,6 +3,8 @@
var OpenStreetBrowserLoader = require('./OpenStreetBrowserLoader')
var OverpassLayer = require('overpass-layer')
var OverpassLayerList = require('overpass-layer').List
var queryString = require('query-string')
var CategoryBase = require('./CategoryBase')
var state = require('./state')
var tabs = require('modulekit-tabs')
@ -33,10 +35,10 @@ var defaultValues = {
CategoryOverpass.prototype = Object.create(CategoryBase.prototype)
CategoryOverpass.prototype.constructor = CategoryOverpass
function CategoryOverpass (options, data) {
function CategoryOverpass (options, data, repository) {
var p
CategoryBase.call(this, options, data)
CategoryBase.call(this, options, data, repository)
data.id = this.id
@ -114,7 +116,10 @@ function CategoryOverpass (options, data) {
}
)
p = document.createElement('div')
call_hooks('category-overpass-init', this)
var p = document.createElement('div')
p.className = 'loadingIndicator'
p.innerHTML = '<i class="fa fa-spinner fa-pulse fa-fw"></i><span class="sr-only">' + lang('loading') + '</span>'
this.dom.appendChild(p)
@ -141,7 +146,22 @@ function CategoryOverpass (options, data) {
state.categories = ''
}
state.categories += this.id
let id = this.id
let param = {}
this.emit('stateGet', param)
for (var k in param) {
if (!param[k]) {
delete param[k]
}
}
if (param && Object.keys(param).length) {
id += '[' + queryString.stringify(param) + ']'
}
state.categories += id
}
}.bind(this))
@ -150,8 +170,17 @@ function CategoryOverpass (options, data) {
return
}
var list = state.categories.split(',')
if (list.indexOf(this.id) === -1) {
let list = state.categories.split(',')
let found = list.filter(id => {
let m = id.match(/^([0-9A-Z_-]+)(\[(.*)\])/i)
if (m) {
id = m[1]
}
return id === this.id
}).length
if (!found) {
this.close()
}
@ -159,6 +188,15 @@ function CategoryOverpass (options, data) {
}.bind(this))
}
CategoryOverpass.prototype.setParam = function (param) {
this.emit('setParam', param)
this._applyParam(param)
}
CategoryOverpass.prototype._applyParam = function (param) {
this.emit('applyParam', param)
}
CategoryOverpass.prototype.updateAssets = function (div) {
var imgs = div.getElementsByTagName('img')
for (var i = 0; i < imgs.length; i++) {
@ -199,6 +237,10 @@ CategoryOverpass.prototype.load = function (callback) {
}.bind(this))
}
CategoryOverpass.prototype.setParentDom = function (parentDom) {
CategoryBase.prototype.setParentDom.call(this, parentDom)
}
CategoryOverpass.prototype.setMap = function (map) {
CategoryBase.prototype.setMap.call(this, map)
@ -350,6 +392,8 @@ CategoryOverpass.prototype.open = function () {
this.updateInfo()
}
this.emit('open')
}
CategoryOverpass.prototype.updateInfo = function () {
@ -519,5 +563,7 @@ CategoryOverpass.prototype.allMapFeatures = function (callback) {
callback(null, Object.values(this.layer.mainlayer.visibleFeatures))
}
CategoryOverpass.defaultValues = defaultValues
OpenStreetBrowserLoader.registerType('overpass', CategoryOverpass)
module.exports = CategoryOverpass

234
src/CategoryOverpassFilter.js

@ -0,0 +1,234 @@
const OverpassLayer = require('overpass-layer')
const tabs = require('modulekit-tabs')
const state = require('./state')
const Filter = require('overpass-frontend').Filter
const getPathFromJSON = require('./getPathFromJSON')
const CategoryOverpass = require('./CategoryOverpass')
CategoryOverpass.defaultValues.filter = {
title: {
type: 'text',
key: [ 'name', 'name:*', 'operator', 'operator:*', 'ref', 'ref:*' ],
name: '{{ trans("filter:title") }}',
op: 'strsearch',
weight: -1,
show_default: true
}
}
class CategoryOverpassFilter {
constructor (master) {
this.master = master
this.data = this.master.data.filter
this.tabFilter = new tabs.Tab({
id: 'filter'
})
this.master.tools.add(this.tabFilter)
this.tabFilter.header.innerHTML = '<i class="fa fa-filter" aria-hidden="true"></i>'
this.tabFilter.header.title = lang('filter')
this.domFilter = document.createElement('form')
this.tabFilter.content.appendChild(this.domFilter)
this.tabFilter.on('select', () => {
this.formFilter.resize()
this.formFilter.focus()
})
for (var k in this.data) {
let f = this.data[k]
if ('name' in f && typeof f.name === 'string') {
global.currentCategory = this.master
let t = OverpassLayer.twig.twig({ data: f.name, autoescape: true })
f.name = t.render({}).toString()
} else if (!('name' in f)) {
f.name = lang('tag:' + k)
}
if ('query' in f) {
f.queryTemplate = OverpassLayer.twig.twig({ data: f.query, autoescape: false })
}
if ('values' in f) {
let valueNameTemplate = OverpassLayer.twig.twig({ data: f.valueName || '{{ value }}', autoescape: true })
if (typeof f.values === 'string') {
let valuesTemplate = OverpassLayer.twig.twig({ data: f.values, autoescape: true })
let div = document.createElement('div')
div.innerHTML = valuesTemplate.render(this.master.data)
let options = div.getElementsByTagName('option')
f.values = {}
for (let i = 0; i < options.length; i++) {
let option = options[i]
let k = option.value
f.values[k] = {}
if (option.textContent) {
f.values[k].name = option.textContent
}
if (option.hasAttribute('query')) {
f.values[k].query = option.getAttribute('query')
}
}
}
if (Array.isArray(f.values) && f.valueName) {
let newValues = {}
f.values.forEach(value => {
newValues[value] = valueNameTemplate.render({ value }).toString()
})
f.values = newValues
} else if (typeof f.values === 'object') {
for (var k1 in f.values) {
if (typeof f.values[k1] === 'string') {
let t = OverpassLayer.twig.twig({ data: f.values[k1], autoescape: true })
f.values[k1] = t.render({}).toString()
} else if (typeof f.values[k1] === 'object') {
if (!('name' in f.values[k1])) {
f.values[k1].name = valueNameTemplate.render({ value: k1 }).toString()
} else if (f.values[k1].name) {
let t = OverpassLayer.twig.twig({ data: f.values[k1].name, autoescape: true })
f.values[k1].name = t.render({}).toString()
}
}
}
}
}
}
let masterOptions = {}
if (Object.keys(this.data).length > 1) {
masterOptions = {
'type': 'form_chooser',
'button:add_element': '-- ' + lang('add_filter') + ' --',
'order': false,
'change_on_input': true
}
}
this.formFilter = new form('filter-' + this.master.id, this.data, masterOptions)
this.formFilter.show(this.domFilter)
this.formFilter.onchange = function () {
let param = JSON.parse(JSON.stringify(this.formFilter.get_data()))
this.applyParam(param)
this.master.layer.check_update_map()
state.update()
}.bind(this)
this.master.on('setParam', this.setParam.bind(this))
this.master.on('applyParam', this.applyParam.bind(this))
this.master.on('open', this.openCategory.bind(this))
this.master.on('stateGet', this.stateGet.bind(this))
}
setParam (param) {
this.formFilter.set_data(param)
}
applyParam (param) {
this.additionalFilter = []
let kvFilter = []
for (var k in param) {
if (param[k] === null) {
continue
}
var d = this.data[k]
if ('values' in d && param[k] in d.values && typeof d.values[param[k]] === 'object' && 'query' in d.values[param[k]]) {
let f = new Filter(d.values[param[k]].query)
this.additionalFilter.push(f.def)
continue
} else if (d.queryTemplate) {
let f = new Filter(d.queryTemplate.render({ value: param[k] }).toString())
this.additionalFilter.push(f.def)
continue
}
var v = {
key: 'key' in d ? d.key : k,
value: param[k],
op: '='
}
if ('op' in d) {
if (d.op === 'has_key_value') {
v = {
key: param[k],
op: 'has_key'
}
} else {
v.op = d.op
}
}
if (Array.isArray(v.key)) {
v = {
"or": v.key.map(
key => {
let v1 = { key, value: v.value, op: v.op }
let m = key.match(/^(.*)\*(.*)/)
if (m) {
v1.key = '^' + m[1] + '.*' + m[2]
v1.keyRegexp = true
}
return [ v1 ]
}
)
}
}
kvFilter.push(v)
}
if (kvFilter.length) {
this.additionalFilter.push(kvFilter)
}
if (this.additionalFilter.length === 0) {
this.additionalFilter = []
} else if (this.additionalFilter.length === 1) {
this.additionalFilter = this.additionalFilter[0]
} else {
this.additionalFilter = { and: this.additionalFilter }
}
this.master.layer.options.queryOptions.filter = this.additionalFilter
if (!this.tabFilter.isSelected()) {
this.tabFilter.select()
}
}
openCategory () {
this.formFilter.resize()
}
stateGet (param) {
let data = this.formFilter.get_data()
for (var k in data) {
if (data[k]) {
param[k] = data[k]
}
}
}
}
register_hook('category-overpass-init', (category) => {
if (category.data.filter) {
new CategoryOverpassFilter(category)
}
})

26
src/OpenStreetBrowserLoader.js

@ -1,9 +1,12 @@
var OverpassLayer = require('overpass-layer')
const Repository = require('./Repository')
function OpenStreetBrowserLoader () {
this.types = {}
this.categories = {}
this.repoCache = {}
this.repositories = {}
this.templates = {}
this._loadClash = {} // if a category is being loaded multiple times, collect callbacks
}
@ -58,7 +61,6 @@ OpenStreetBrowserLoader.prototype.getCategory = function (id, options, callback)
this.getCategoryFromData(ids.id, opt, repoData.categories[ids.entityId], function (err, category) {
if (category) {
category.setMap(this.map)
category.lang = repoData.lang
}
callback(err, category)
@ -94,7 +96,9 @@ OpenStreetBrowserLoader.prototype.getRepo = function (repo, options, callback) {
this.repoCache[repo] = [ req.statusText, null ]
} else {
try {
this.repoCache[repo] = [ null, JSON.parse(req.responseText) ]
let repoData = JSON.parse(req.responseText)
this.repositories[repo] = new Repository(repo, repoData)
this.repoCache[repo] = [ null, repoData ]
} catch (err) {
console.log('couldn\'t parse repository', req.responseText)
this.repoCache[repo] = [ 'couldn\t parse repository', null ]
@ -123,6 +127,20 @@ OpenStreetBrowserLoader.prototype.getRepo = function (repo, options, callback) {
req.send()
}
OpenStreetBrowserLoader.prototype.getRepository = function (id, options, callback) {
if (id in this.repositories) {
return callback(null, this.repositories[id])
}
this.getRepo(id, options, (err, repoData) => {
if (err) {
return callback(err)
}
callback(null, this.repositories[id])
})
}
/**
* @param string id ID of the template
* @parapm [object] options Options.
@ -184,9 +202,11 @@ OpenStreetBrowserLoader.prototype.getCategoryFromData = function (id, options, d
return callback(new Error('unknown type'), null)
}
let repository = this.repositories[ids.repositoryId]
var opt = JSON.parse(JSON.stringify(options))
opt.id = ids.id
var layer = new this.types[data.type](opt, data)
var layer = new this.types[data.type](opt, data, repository)
layer.setMap(this.map)

8
src/Repository.js

@ -0,0 +1,8 @@
module.exports = class Repository {
constructor (id, data) {
this.id = id
this.data = data
this.lang = this.data.lang || {}
}
}

2
src/RepositoryDir.php

@ -38,7 +38,7 @@ class RepositoryDir extends RepositoryBase {
continue;
}
$data['categories'][$m[1]] = jsonMultilineStringsJoin($d1, array('exclude' => array(array('const'))));
$data['categories'][$m[1]] = jsonMultilineStringsJoin($d1, array('exclude' => array(array('const'), array('filter'))));
}
if (preg_match("/^(detailsBody|popupBody).html$/", $f, $m)) {

2
src/RepositoryGit.php

@ -60,7 +60,7 @@ class RepositoryGit extends RepositoryBase {
continue;
}
$data['categories'][$id] = jsonMultilineStringsJoin($d1, array('exclude' => array(array('const'))));
$data['categories'][$id] = jsonMultilineStringsJoin($d1, array('exclude' => array(array('const'), array('filter'))));
}
if (preg_match("/^[0-9]{6} blob [0-9a-f]{40}\t((detailsBody|popupBody)\.html)$/", $r, $m)) {

16
src/categories.js

@ -1,3 +1,5 @@
var queryString = require('query-string')
var OpenStreetBrowserLoader = require('./OpenStreetBrowserLoader')
register_hook('state-apply', function (state) {
@ -7,6 +9,14 @@ register_hook('state-apply', function (state) {
var list = state.categories.split(',')
list.forEach(function (id) {
let param
let m = id.match(/^([0-9A-Z_-]+)(\[(.*)\])/i)
if (m) {
id = m[1]
param = queryString.parse(m[3])
}
OpenStreetBrowserLoader.getCategory(id, function (err, category) {
if (err) {
console.log("Can't load category " + id + ': ', err)
@ -14,11 +24,15 @@ register_hook('state-apply', function (state) {
}
if (category) {
category.open()
if (param) {
category.setParam(param)
}
if (!category.parentDom) {
category.setParentDom(document.getElementById('contentListAddCategories'))
}
category.open()
}
})
})

11
src/getPathFromJSON.js

@ -0,0 +1,11 @@
module.exports = function getPathFromJSON (path, json) {
if (typeof path === 'string') {
path = path.split(/\./)
}
if (path.length === 0) {
return json
}
return getPathFromJSON(path.slice(1), json[path[0]])
}

1
src/index.js

@ -36,6 +36,7 @@ require('./addCategories')
require('./permalink')
//require('./leaflet-geo-search')
require('./nominatim-search')
require('./CategoryOverpassFilter')
let exportAll = require('./exportAll')
window.onload = function () {

2
src/tagTranslations.js

@ -26,7 +26,7 @@ OverpassLayer.twig.extendFunction('isTranslated', function (str) {
return tagTranslationsIsTranslated(str)
})
OverpassLayer.twig.extendFunction('repoTrans', function (str) {
let lang = global.currentCategory.lang
let lang = global.currentCategory.repository.lang
return str in lang ? lang[str] : str
})

4
style.css

@ -427,3 +427,7 @@ a:active {
.overpass-layer-icon .sign {
white-space: nowrap;
}
.tabs-section > form > span.form_element_form_chooser {
border: none;
}

25
test/getPathFromJSON.js

@ -0,0 +1,25 @@
const getPathFromJSON = require('../src/getPathFromJSON')
const assert = require('assert')
describe('getPathFromJSON', function () {
it('const', function () {
assert.deepEqual(
getPathFromJSON('const', { const: { 'foo': 'foo', 'bar': 'bar' } }),
{ 'foo': 'foo', 'bar': 'bar' }
)
})
it('const.x', function () {
assert.deepEqual(
getPathFromJSON('const.x', { const: { x: { 'foo': 'foo', 'bar': 'bar' } } }),
{ 'foo': 'foo', 'bar': 'bar' }
)
})
it('const.y (not exist)', function () {
assert.deepEqual(
getPathFromJSON('const.y', { const: { x: { 'foo': 'foo', 'bar': 'bar' } } }),
undefined
)
})
})
Loading…
Cancel
Save