Browse Source

Merge branch '3-common-popup-body'

master
parent
commit
4eca5ac2b1
  1. 5
      README.md
  2. 3
      lang/de.json
  3. 3
      lang/en.json
  4. 3
      package.json
  5. 63
      src/CategoryOverpass.js
  6. 35
      src/OpenStreetBrowserLoader.js
  7. 17
      src/index.js
  8. 31
      src/twigFunctions.js
  9. 57
      style.css

5
README.md

@ -69,7 +69,7 @@ File: foo.json
"markerSign": "{% if tags.highway == 'motorway_junction' %}↗{% elseif tags.highway == 'mini_roundabout' %}↻{% elseif tags.highway == 'crossing' %}▤{% endif %}",
"title": "{{ localizedTag(tags, 'name') |default(localizedTag(tags, 'operator')) | default(localizedTag(tags, 'ref')) | default(trans('unnamed')) }}",
"description": "{{ tagTrans('highway', tags.highway) }}",
"body": "{{ tagTrans('highway', tags.highway) }}<br/>Foo value: {{ const.foo }}"
"body": "Foo value: {{ const.foo }}"
},
"const": {
"foo": "foo value"
@ -104,6 +104,7 @@ The following values are possible for categories (the only mandatory value is qu
* title: the title of the feature popup, the object in the list and the details page. (default: localized tags for 'name', 'operator' or 'ref', default: 'unknown')
* body: the body for the feature popup and the details page.
* description: a short description shown in the list next to the title.
* popupDescription: like description, but an alternative if the description in popups should be different from the list.
* markerSign: a HTML string which will be shown within the marker and in the list. (default: '')
* priority: a numeric value by which the elements in the list will be sorted (lower values first)
* const: an object variable which is available as prefix in twig functions.
@ -131,6 +132,8 @@ There are several extra functions defined for the TwigJS language:
* function `tagTransList`: return the translations of the given tag for tags with multiple values separated by ';' (e.g. 'cuisine'). Parameters: key (required, e.g. 'cuisine'), value (required, e.g. 'kebab' or 'kebab;pizza;noodles;burger').
* function `localizedTag`: return a localized tag if available (e.g. 'name:de' for the german translation of the tag). Parameters: tags (the tags property), key prefix (e.g. 'name'). Which language will be returned depends on the "data language" which can be set via Options. If no localized tag is available, the tag value itself will be returned (e.g. value of 'name').
* function `trans`: return the translation of the given string (e.g. 'save', 'unknown', 'unnamed', ...). Parameters: string (the string to translate).
* function `tagsPrefix(tags, prefix)`: return all tags with the specified prefix. The result will be an array with `{ "en": "name:en", "de": "name:de" }` (for the input `{ "name": "foo", "name:en": "english foo", "name:de": "german foo" }` and the prefix "name:").
* function openingHoursState(opening_hours_definition): returns state of object as string: 'closed', 'open' or 'unknown'.
Notes:
* Variables will automatically be HTML escaped, if not the filter raw is used, e.g.: {{ tags.name|raw }}

3
lang/de.json

@ -1,6 +1,9 @@
{
"closed": "geschlossen",
"default": "Standard",
"facilities": "Einrichtungen",
"main:options": "Optionen",
"open": "geöffnet",
"options:data_lang": "Datensprache",
"options:data_lang:local": "Lokale Sprache",
"options:overpassUrl": "OverpassAPI Adresse",

3
lang/en.json

@ -1,6 +1,9 @@
{
"closed": "closed",
"default": "default",
"facilities": "Facilities",
"main:options": "Options",
"open": "open",
"options:data_lang": "Data language",
"options:data_lang:desc": "Many map features have their name (and other tags) translated to different languages (e.g. with 'name:en', 'name:de'). Specify which language should be used for displaying, or 'Local language' so that always the untranslated value (e.g. 'name') will be used",
"options:data_lang:local": "Local language",

3
package.json

@ -8,10 +8,13 @@
"license": "GPL-3.0",
"dependencies": {
"font-awesome": "^4.7.0",
"i18next-client": "^1.11.4",
"ip-location": "^1.0.1",
"leaflet": "^1.0.3",
"leaflet-geosearch": "^2.4.0",
"leaflet.locatecontrol": "^0.61.0",
"moment": "^2.18.1",
"opening_hours": "^3.5.0",
"openstreetbrowser-categories-main": "https://github.com/plepe/openstreetbrowser-categories-main",
"openstreetmap-tag-translations": "https://github.com/plepe/openstreetmap-tag-translations",
"overpass-layer": "https://github.com/plepe/overpass-layer",

63
src/CategoryOverpass.js

@ -55,7 +55,6 @@ function CategoryOverpass (id, data) {
}
data.feature.appUrl = '#' + this.id + '/{{ id }}'
data.feature.body = (typeof data.feature.body === 'string' ? data.feature.body : '') + '<a class="showDetails" href="#' + this.id + '/{{ id }}/details">show details</a>'
this.layer = new OverpassLayer(data)
@ -86,6 +85,13 @@ function CategoryOverpass (id, data) {
}.bind(this, ob.id)
}
}.bind(this)
this.layer.onUpdate = function (ob) {
if (!ob.popup || !ob.popup._contentNode) {
return
}
this.updatePopupContent(ob, ob.popup)
}.bind(this)
var p = document.createElement('div')
p.className = 'loadingIndicator'
@ -103,6 +109,18 @@ function CategoryOverpass (id, data) {
this.dom.appendChild(this.domStatus)
}
CategoryOverpass.prototype.load = function (callback) {
OpenStreetBrowserLoader.getTemplate('commonBody', function (err, template) {
if (err) {
console.log("can't load commonBody.html")
} else {
this.commonBodyTemplate = template
}
callback(null)
}.bind(this))
}
CategoryOverpass.prototype.setMap = function (map) {
CategoryBase.prototype.setMap.call(this, map)
@ -162,5 +180,48 @@ CategoryOverpass.prototype.show = function (id, options, callback) {
this.layer.show(id, options, callback)
}
CategoryOverpass.prototype.notifyPopupOpen = function (object, popup) {
this.updatePopupContent(object, popup)
}
CategoryOverpass.prototype.updatePopupContent = function (object, popup) {
if (object.data.popupDescription || object.data.description) {
var div = document.createElement('div')
div.className = 'description'
div.innerHTML = object.data.popupDescription || object.data.description
popup._contentNode.insertBefore(div, popup._contentNode.firstChild.nextSibling)
}
if (this.commonBodyTemplate) {
var commonBody = document.createElement('div')
commonBody.className = 'commonBody'
popup._contentNode.appendChild(commonBody)
var data = this.layer.twigData(object.object)
commonBody.innerHTML = this.commonBodyTemplate.render(data)
}
var footer = document.createElement('div')
footer.className = 'footer'
var footerContent = '<a class="showDetails" href="#' + this.id + '/' + object.id + '/details">show details</a>'
footer.innerHTML = footerContent
popup._contentNode.appendChild(footer)
}
CategoryOverpass.prototype.renderTemplate = function (object, templateId, callback) {
OpenStreetBrowserLoader.getTemplate(templateId, function (err, template) {
if (err) {
err = "can't load " + templateId + ": " + err
return callback(err, null)
}
var data = this.layer.twigData(object.object)
var result = template.render(data)
callback(null, result)
}.bind(this))
}
OpenStreetBrowserLoader.registerType('overpass', CategoryOverpass)
module.exports = CategoryOverpass

35
src/OpenStreetBrowserLoader.js

@ -1,6 +1,9 @@
var OverpassLayer = require('overpass-layer')
function OpenStreetBrowserLoader () {
this.types = {}
this.categories = {}
this.templates = {}
}
OpenStreetBrowserLoader.prototype.setMap = function (map) {
@ -38,6 +41,30 @@ OpenStreetBrowserLoader.prototype.getCategory = function (id, callback) {
}
OpenStreetBrowserLoader.prototype.getTemplate = function (id, callback) {
if (id in this.templates) {
callback(null, this.templates[id])
return
}
function reqListener (req) {
if (req.status !== 200) {
console.log(req)
return callback(req.statusText, null)
}
this.templates[id] = OverpassLayer.twig.twig({ data: req.responseText, autoescape: true })
callback(null, this.templates[id])
}
var req = new XMLHttpRequest()
req.addEventListener("load", reqListener.bind(this, req))
req.open("GET", config.categoriesDir + '/' + id + ".html?" + config.categoriesRev)
req.send()
}
OpenStreetBrowserLoader.prototype.getCategoryFromData = function (id, data, callback) {
if (!data.type) {
callback('no type defined', null)
@ -52,7 +79,13 @@ OpenStreetBrowserLoader.prototype.getCategoryFromData = function (id, data, call
this.categories[id] = layer
callback(null, layer)
if ('load' in layer) {
layer.load(function (err) {
callback(err, layer)
})
} else {
callback(null, layer)
}
}
}

17
src/index.js

@ -22,6 +22,7 @@ require('./location')
require('./overpassChooser')
require('./fullscreen')
require('./mapLayers')
require('./twigFunctions')
window.onload = function() {
map = L.map('map')
@ -79,6 +80,11 @@ function onload2 () {
if (location.hash !== url) {
history.pushState(null, null, '#' + url)
}
OpenStreetBrowserLoader.getCategory(e.popup.object.layer_id, function (err, category) {
category.notifyPopupOpen(e.popup.object, e.popup)
})
}
})
map.on('popupclose', function (e) {
@ -153,7 +159,9 @@ function show (id, options, callback) {
return callback('error loading object "' + id[0] + '/' + id[1] +'": ' + err)
}
data.feature.openPopup()
if (!map._popup || map._popup !== data.popup) {
data.feature.openPopup()
}
if (options.showDetails) {
showDetails(data, category)
@ -182,6 +190,13 @@ function showDetails (data, category) {
div.innerHTML = data.data.body
dom.appendChild(div)
var div = document.createElement('div')
div.className = 'body'
dom.appendChild(div)
category.renderTemplate(data, 'detailsBody', function (div, err, result) {
div.innerHTML = result
}.bind(this, div))
var h = document.createElement('h3')
h.innerHTML = 'Attributes'
dom.appendChild(h)

31
src/twigFunctions.js

@ -0,0 +1,31 @@
var OverpassLayer = require('overpass-layer')
var OpeningHours = require('opening_hours')
OverpassLayer.twig.extendFunction('tagsPrefix', function (tags, prefix) {
var ret = {}
var count = 0
for (var k in tags) {
if (k.substr(0, prefix.length) === prefix) {
ret[k.substr(prefix.length)] = k
count++
}
}
if (count == 0) {
return null
}
return ret
})
OverpassLayer.twig.extendFunction('openingHoursState', function (opening_hours) {
try {
var oh = new OpeningHours(opening_hours)
} catch (err) {
console.log("Error in opening_hours: " + err)
return 'unknown'
}
return oh.getStateString(new Date(), true)
})

57
style.css

@ -422,3 +422,60 @@ a.showDetails {
margin-left: 100%;
}
}
.leaflet-popup-content {
min-width: 200px;
}
.leaflet-popup-content > h1 {
margin: 0;
}
.yes {
color: green;
}
.limited {
color: orange;
}
.no {
color: red;
}
.body .description,
.leaflet-popup-content .description {
display: block;
text-align: right;
font-style: italic;
}
.body .description:after,
.leaflet-popup-content .description:after {
content: '';
clear: right;
}
.body ul,
.leaflet-popup-content ul {
margin: 0;
padding-left: 20px;
}
.body ul > li,
.leaflet-popup-content ul > li {
position: relative;
}
.body ul > li.hasSymbol,
.leaflet-popup-content ul > li.hasSymbol {
list-style: none;
}
.body ul > li.hasSymbol > i,
.leaflet-popup-content ul > li.hasSymbol > i,
.body ul > li.hasSymbol > .symbol,
.leaflet-popup-content ul > li.hasSymbol > .symbol,
.body ul > li.hasSymbol > img,
.leaflet-popup-content ul > li.hasSymbol > img {
position: absolute;
margin-left: -15px;
padding-top: 2px;
}
.body ul > li > .key,
.leaflet-popup-content ul > li > .key {
font-weight: bold;
}
Loading…
Cancel
Save