diff --git a/README.md b/README.md
index e03454ce..089bbfd0 100644
--- a/README.md
+++ b/README.md
@@ -118,3 +118,6 @@ With the function `register_hook` you can hook into several functions. The follo
* `state-get`: modules can add values into the current state. Parameters: `state`: an object, which can be modified by modules.
* `state-apply`: when a state is applied to the app. Parameters: `state`: state which should be applied.
+* `show-details`: called when details are being displayed. Parameters: data (see properties in doc/TwigJS.md), category, dom, callback.
+* `show-popup`: called when a popup is being displayed. Parameters: data (see properties in doc/TwigJS.md), category, dom, callback.
+* `options_save`: called when options are saved. Parameters: options (the new object), old_options (before save)
diff --git a/ajax.php b/ajax.php
index 85e6f675..0d50087e 100644
--- a/ajax.php
+++ b/ajax.php
@@ -22,6 +22,6 @@ if ($postdata) {
}
$fun = "ajax_{$_REQUEST['__func']}";
-$return = $fun($_REQUEST["param"], $postdata);
+$return = $fun($_REQUEST, $postdata);
print json_encode($return);
diff --git a/doc/TwigJS.md b/doc/TwigJS.md
index d9f39645..7e5bf831 100644
--- a/doc/TwigJS.md
+++ b/doc/TwigJS.md
@@ -24,6 +24,7 @@ There are several extra functions defined for the TwigJS language:
Extra filters:
* filter websiteUrl: return a valid http link. Example: `{{ "www.google.com"|websiteUrl }}` -> "http://www.google.com"; `{{ "https://google.com"|websiteUrl }}` -> "https://google.com"
+* filter `matches`: regular expression match. e.g. `{{ "test"|matches("e(st)$") }}` returns `[ "est", "st" ]`. Returns null if it does not match.
Notes:
* Variables will automatically be HTML escaped, if not the filter raw is used, e.g.: {{ tags.name|raw }}
diff --git a/lang/ast.json b/lang/ast.json
index 2daa5b6c..d6d91532 100644
--- a/lang/ast.json
+++ b/lang/ast.json
@@ -1,5 +1,6 @@
{
"main:options": "Opciones",
+ "more": "más",
"options:data_lang": "Llingua de los datos",
"options:data_lang:local": "Llingua llocal",
"options:ui_lang": "Llingua de la interfaz",
diff --git a/lang/ca.json b/lang/ca.json
index 51ca2664..125c6797 100644
--- a/lang/ca.json
+++ b/lang/ca.json
@@ -1,4 +1,5 @@
{
"main:options": "Opcions",
+ "more": "més",
"save": "Guardar"
}
\ No newline at end of file
diff --git a/lang/cs.json b/lang/cs.json
index f292521b..9ee96b8f 100644
--- a/lang/cs.json
+++ b/lang/cs.json
@@ -1,5 +1,6 @@
{
"main:options": "Nastavení",
+ "more": "více",
"options:data_lang": "Jazyk dat",
"options:data_lang:local": "Místní jazyk",
"options:ui_lang": "Jazyk rozhraní",
diff --git a/lang/da.json b/lang/da.json
index 9a4149f3..8145e1e2 100644
--- a/lang/da.json
+++ b/lang/da.json
@@ -1,5 +1,6 @@
{
"main:options": "Indstillinger",
+ "more": "mere",
"options:data_lang": "Data sprog",
"options:data_lang:local": "Lokalt sprog",
"options:ui_lang": "Brugerfladesprog",
diff --git a/lang/de.json b/lang/de.json
index eb262bf6..5d7ca9c1 100644
--- a/lang/de.json
+++ b/lang/de.json
@@ -1,8 +1,13 @@
{
"closed": "geschlossen",
"default": "Standard",
+ "error": {
+ "message": "Fehler",
+ "!=1": "Fehler"
+ },
"facilities": "Einrichtungen",
"main:options": "Optionen",
+ "more": "mehr",
"open": "geöffnet",
"options:data_lang": "Datensprache",
"options:data_lang:local": "Lokale Sprache",
@@ -13,5 +18,6 @@
"show details": "zeige Details",
"toggle_fullscreen": "(De-)aktiviere Vollbildmodus",
"unknown": "unbekannt",
- "unnamed": "Namenlos"
+ "unnamed": "Namenlos",
+ "wikipedia:no-url-parse": "Konnte Wikipedia Adresse nicht erkennen"
}
diff --git a/lang/el.json b/lang/el.json
index f990b744..c909aa30 100644
--- a/lang/el.json
+++ b/lang/el.json
@@ -1,5 +1,6 @@
{
"main:options": "Επιλογές",
+ "more": "περισσότερα",
"options:data_lang": "Γλωσσα δεδομένων",
"options:data_lang:local": "Τοπική γλώσσα",
"options:ui_lang": "Γλώσσα διεπαφής",
diff --git a/lang/en.json b/lang/en.json
index abab282c..c8e7c5cb 100644
--- a/lang/en.json
+++ b/lang/en.json
@@ -1,8 +1,13 @@
{
"closed": "closed",
"default": "default",
+ "error": {
+ "message": "Error",
+ "!=1": "Errors"
+ },
"facilities": "Facilities",
"main:options": "Options",
+ "more": "more",
"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",
@@ -14,5 +19,6 @@
"show details": "show details",
"toggle_fullscreen": "Toggle full screen mode",
"unknown": "unknown",
- "unnamed": "unnamed"
+ "unnamed": "unnamed",
+ "wikipedia:no-url-parse": "Could not parse Wikipedia URL"
}
diff --git a/lang/es.json b/lang/es.json
index 6040895d..0f4a7c32 100644
--- a/lang/es.json
+++ b/lang/es.json
@@ -1,5 +1,6 @@
{
"main:options": "Opciones",
+ "more": "más",
"options:data_lang": "Idioma de datos",
"options:data_lang:local": "Idioma local",
"options:ui_lang": "Idioma de interfaz",
diff --git a/lang/et.json b/lang/et.json
index 0b73477c..7028b216 100644
--- a/lang/et.json
+++ b/lang/et.json
@@ -1,5 +1,6 @@
{
"main:options": "Valikud",
+ "more": "lisaks",
"options:data_lang": "Andmete keel",
"options:data_lang:local": "Kohalik keel",
"options:ui_lang": "Kasutajaliidese keel",
diff --git a/lang/fr.json b/lang/fr.json
index d84d9a1f..e9c15df0 100644
--- a/lang/fr.json
+++ b/lang/fr.json
@@ -1,5 +1,6 @@
{
"main:options": "Options",
+ "more": "plus",
"options:data_lang": "Langue des données",
"options:data_lang:local": "Langue locale",
"options:ui_lang": "Langue de l'interface",
diff --git a/lang/hu.json b/lang/hu.json
index 279c05f7..0d5c91da 100644
--- a/lang/hu.json
+++ b/lang/hu.json
@@ -1,5 +1,6 @@
{
"main:options": "Beállítások",
+ "more": "több",
"options:data_lang": "Adatnyelv",
"options:data_lang:local": "Helyi nyelv",
"options:ui_lang": "Menünyelv",
diff --git a/lang/it.json b/lang/it.json
index 26dde9f6..3746ee15 100644
--- a/lang/it.json
+++ b/lang/it.json
@@ -1,5 +1,6 @@
{
"main:options": "Opzioni",
+ "more": "altri",
"options:data_lang": "Lingua dei dati",
"options:data_lang:local": "Lingua del tuo browser",
"options:ui_lang": "Lingua dell'interfaccia",
diff --git a/lang/ja.json b/lang/ja.json
index 6f87f45c..7c37bd2f 100644
--- a/lang/ja.json
+++ b/lang/ja.json
@@ -1,5 +1,6 @@
{
"main:options": "オプション設定",
+ "more": "もっと",
"options:data_lang": "データ表示",
"options:data_lang:local": "ブラウザの設定言語",
"options:ui_lang": "インタフェース表示",
diff --git a/lang/nl.json b/lang/nl.json
index 17abe618..7bdb8e7b 100644
--- a/lang/nl.json
+++ b/lang/nl.json
@@ -1,5 +1,6 @@
{
"main:options": "Opties",
+ "more": "meer",
"options:data_lang": "Taal voor data",
"options:data_lang:local": "Lokale taal",
"options:ui_lang": "Interfacetaal",
diff --git a/lang/pl.json b/lang/pl.json
index 5a62a30d..1b281fb5 100644
--- a/lang/pl.json
+++ b/lang/pl.json
@@ -1,5 +1,6 @@
{
"main:options": "Opcje",
+ "more": "więcej",
"options:data_lang": "Język danych",
"options:data_lang:local": "Język lokalny",
"options:ui_lang": "Język interfejsu",
diff --git a/lang/pt-br.json b/lang/pt-br.json
index 9b7b5d9b..8bfccb59 100644
--- a/lang/pt-br.json
+++ b/lang/pt-br.json
@@ -1,4 +1,5 @@
{
+ "more": "mais",
"save": "Salvar",
"unnamed": "sem nome"
}
\ No newline at end of file
diff --git a/lang/ro.json b/lang/ro.json
index b5428f66..b2faa188 100644
--- a/lang/ro.json
+++ b/lang/ro.json
@@ -1,5 +1,6 @@
{
"main:options": "Optiuni",
+ "more": "Mai mult",
"options:data_lang": "Limba date",
"options:data_lang:local": "Limba locala",
"options:ui_lang": "Limba interfata",
diff --git a/lang/ru.json b/lang/ru.json
index 415f3e16..66dac2a2 100644
--- a/lang/ru.json
+++ b/lang/ru.json
@@ -1,5 +1,6 @@
{
"main:options": "Настройки",
+ "more": "Ещё",
"options:data_lang": "Язык информации на карте",
"options:data_lang:local": "Определить язык автоматически",
"options:ui_lang": "Язык интерфейса",
diff --git a/lang/sr.json b/lang/sr.json
index f889c77d..4a52d62d 100644
--- a/lang/sr.json
+++ b/lang/sr.json
@@ -1,5 +1,6 @@
{
"main:options": "Опције",
+ "more": "још",
"options:data_lang": "Језик подетака",
"options:data_lang:local": "Локални језик",
"options:ui_lang": "Језик интерфејса",
diff --git a/lang/template.json b/lang/template.json
index 81e36564..8bdbd5bf 100644
--- a/lang/template.json
+++ b/lang/template.json
@@ -1,6 +1,7 @@
{
"default": "",
"main:options": "",
+ "more": "",
"options:data_lang": "",
"options:data_lang:desc": "",
"options:data_lang:local": "",
diff --git a/lang/uk.json b/lang/uk.json
index 3020b659..93ab3b75 100644
--- a/lang/uk.json
+++ b/lang/uk.json
@@ -1,5 +1,6 @@
{
"main:options": "Налаштування",
+ "more": "Ще",
"options:data_lang": "Мова мапи",
"options:data_lang:local": "Місцева мова",
"options:ui_lang": "Мова інтерфейсу",
diff --git a/modulekit.php b/modulekit.php
index f22fca9e..e552ff51 100644
--- a/modulekit.php
+++ b/modulekit.php
@@ -14,6 +14,7 @@ $include = array(
'src/options.php',
'src/language.php',
'src/ip-location.php',
+ 'src/wikipedia.php',
),
'css' => array(
'style.css',
diff --git a/src/CategoryOverpass.js b/src/CategoryOverpass.js
index 2ea70076..e4559bdc 100644
--- a/src/CategoryOverpass.js
+++ b/src/CategoryOverpass.js
@@ -94,6 +94,10 @@ function CategoryOverpass (id, data) {
}
this.updatePopupContent(ob, ob.popup)
+
+ if (document.getElementById('content').className === 'details') {
+ showDetails(ob, this)
+ }
}.bind(this)
p = document.createElement('div')
@@ -219,6 +223,14 @@ CategoryOverpass.prototype.notifyPopupOpen = function (object, popup) {
}
CategoryOverpass.prototype.updatePopupContent = function (object, popup) {
+ call_hooks_callback('show-popup', object, this, popup._contentNode,
+ function (err) {
+ if (err.length) {
+ console.log('show-popup produced errors:', err)
+ }
+ }
+ )
+
if (object.data.popupDescription || object.data.description) {
var div = document.createElement('div')
div.className = 'description'
diff --git a/src/index.js b/src/index.js
index f104df58..5963a2d5 100644
--- a/src/index.js
+++ b/src/index.js
@@ -26,12 +26,18 @@ require('./fullscreen')
require('./mapLayers')
require('./twigFunctions')
require('./categories')
+require('./wikipedia')
window.onload = function () {
initState = config.defaultView
map = L.map('map')
+ // due to php export, options may be an array -> fix
+ if (Array.isArray(options)) {
+ options = {}
+ }
+
call_hooks('init')
call_hooks_callback('init_callback', initState, onload2.bind(this, initState))
}
@@ -139,17 +145,17 @@ window.setPath = function (path) {
return
}
- options = {
+ var param = {
showDetails: !!path.match(/\/details$/)
}
- show(path, options, function (err) {
+ show(path, param, function (err) {
if (err) {
alert(err)
return
}
- call_hooks('show', path, options)
+ call_hooks('show', path, param)
})
}
@@ -199,7 +205,7 @@ function show (id, options, callback) {
})
}
-function showDetails (data, category) {
+window.showDetails = function (data, category) {
var div, h, dt, dd
var k
var dom = document.getElementById('contentDetails')
@@ -228,6 +234,15 @@ function showDetails (data, category) {
div.innerHTML = result
}.bind(this, div))
+
+ call_hooks_callback('show-details', data, category, dom,
+ function (err) {
+ if (err.length) {
+ console.log('show-details produced errors:', err)
+ }
+ }
+ )
+
h = document.createElement('h3')
h.innerHTML = 'Attributes'
dom.appendChild(h)
diff --git a/src/language.js b/src/language.js
index 06383eb6..aaa651b0 100644
--- a/src/language.js
+++ b/src/language.js
@@ -79,12 +79,15 @@ function langName (code) {
}
register_hook('init_callback', function (initState, callback) {
- if ('data_lang' in options) {
- tagTranslations.setTagLanguage(options.data_lang)
- } else {
- tagTranslations.setTagLanguage(getPreferredDataLanguage())
+ if (!('ui_lang' in options)) {
+ options.ui_lang = ui_lang
}
+ if (!('data_lang' in options)) {
+ options.data_lang = getPreferredDataLanguage()
+ }
+ tagTranslations.setTagLanguage(options.data_lang)
+
callback(null)
})
@@ -108,10 +111,10 @@ register_hook('options_form', function (def) {
}
})
-register_hook('options_save', function (data) {
- if ('data_lang' in data) {
- if ('data_lang' in options && options.data_lang !== data.data_lang) {
- tagTranslations.setTagLanguage(data.data_lang)
+register_hook('options_save', function (options, old_options) {
+ if ('data_lang' in options) {
+ if (old_options.data_lang !== options.data_lang) {
+ tagTranslations.setTagLanguage(options.data_lang)
baseCategory.recalc()
}
}
diff --git a/src/options.js b/src/options.js
index 8a760646..59fc6e8c 100644
--- a/src/options.js
+++ b/src/options.js
@@ -1,5 +1,6 @@
/* globals form, ajax, options:true, showRootContent */
var moduleOptions = {}
+var prevPage
register_hook('init', function () {
var menu = document.getElementById('menu')
@@ -28,6 +29,7 @@ moduleOptions.open = function () {
call_hooks('options_form', def)
var optionsForm = new form('options', def)
+ prevPage = document.getElementById('content').className
document.getElementById('content').className = 'options'
var dom = document.getElementById('contentOptions')
dom.innerHTML = ''
@@ -57,16 +59,17 @@ moduleOptions.submit = function (optionsForm) {
}
}
- if (reload) {
- location.reload()
- }
-
ajax('options_save', null, data, function (ret) {
- call_hooks('options_save', data)
-
+ old_options = options
options = data
- showRootContent()
+ document.getElementById('content').className = prevPage
+
+ call_hooks('options_save', data, old_options)
+
+ if (reload) {
+ location.reload()
+ }
})
return false
diff --git a/src/twigFunctions.js b/src/twigFunctions.js
index a0c40b58..f5e4cd83 100644
--- a/src/twigFunctions.js
+++ b/src/twigFunctions.js
@@ -36,3 +36,6 @@ OverpassLayer.twig.extendFilter('websiteUrl', function (value) {
return 'http://' + value
})
+OverpassLayer.twig.extendFilter('matches', function (value, match) {
+ return value.match(match)
+})
diff --git a/src/wikipedia.js b/src/wikipedia.js
new file mode 100644
index 00000000..31ddac5b
--- /dev/null
+++ b/src/wikipedia.js
@@ -0,0 +1,175 @@
+var cache = {}
+
+function stripLinks (dom) {
+ var as = dom.getElementsByTagName('a')
+ var as = Array.prototype.slice.call(as)
+
+ as.forEach(function (current) {
+ var c
+
+ while (c = current.firstChild) {
+ current.parentNode.insertBefore(c, current)
+ }
+
+ current.parentNode.removeChild(current)
+ })
+}
+
+function prepare (text) {
+ var ret = ''
+ var i
+
+ var div = document.createElement('div')
+ div.innerHTML = text
+
+ var contents = div.getElementsByTagName('div')
+ for (i = 0; i < contents.length; i++) {
+ if (contents[i].id === 'mw-content-text') {
+ var content = contents[i]
+ break
+ }
+ }
+
+ if (!content) {
+ return null
+ }
+
+ var p = content.firstChild.firstChild
+ while (p && p.tagName !== 'P') {
+ p = p.nextSibling
+ }
+
+ if (!p) {
+ return null
+ }
+
+ stripLinks(p)
+
+ // first image
+ var imgs = div.getElementsByTagName('img')
+ for (i = 0; i < imgs.length; i++) {
+ var img = imgs[i]
+
+ // ignore icons
+ if (img.width <= 64 && img.height <= 64) {
+ continue
+ }
+
+ img.removeAttribute('width')
+ img.removeAttribute('height')
+ p.insertBefore(img, p.firstChild)
+
+ break;
+ }
+
+ return p.innerHTML
+}
+
+function get (value, callback) {
+ var cacheId = options.data_lang + ':' + value
+ if (cacheId in cache) {
+ return callback(null, cache[cacheId])
+ }
+
+ ajax('wikipedia',
+ {
+ page: value,
+ lang: options.data_lang
+ },
+ function (result) {
+ if (!result.content) {
+ return callback('error', null)
+ }
+
+ var text = prepare(result.content)
+ text += ' ' + lang('more') + ''
+
+ cache[cacheId] = text
+
+ callback(null, text)
+ }
+ )
+}
+
+register_hook('show-details', function (data, category, dom, callback) {
+ var ob = data.object
+ var found = 0
+ var finished = 0
+ var errs = []
+ var h
+ var div = document.createElement('div')
+ div.className = 'wikipedia'
+
+ if ('wikipedia' in ob.tags) {
+ found++
+ showWikipedia(ob.tags.wikipedia, div, done)
+ }
+
+ for (var k in ob.tags) {
+ var m
+ if (m = k.match(/^(.*):wikipedia$/)) {
+ h = document.createElement('h4')
+ h.appendChild(document.createTextNode(lang('tag:' + m[1])))
+ div.appendChild(h)
+
+ found++
+ showWikipedia(ob.tags[k], div, done)
+ }
+
+ if (m = k.match(/^((.*):)?wikipedia:(.*)$/)) {
+ if (m[1]) {
+ h = document.createElement('h4')
+ h.appendChild(document.createTextNode(lang('tag:' + m[1])))
+ div.appendChild(h)
+ }
+
+ found++
+ showWikipedia(m[3] + ':' + ob.tags[k], div, done)
+ }
+ }
+
+ if (found) {
+ h = document.createElement('h3')
+ h.appendChild(document.createTextNode(lang('tag:wikipedia')))
+ dom.appendChild(h)
+
+ dom.appendChild(div)
+ }
+
+ function done (err) {
+ finished++
+
+ if (err) {
+ errs.push(err)
+ }
+
+ if (found === finished) {
+ callback(errs.length ? errs : null)
+ }
+ }
+})
+
+function showWikipedia (tagValue, dom, callback) {
+ var block = document.createElement('div')
+ block.className = 'loading'
+ dom.appendChild(block)
+
+ var l = document.createElement('div')
+ l.innerHTML = 'Loading...'
+ l.className = 'loadingIndicator'
+ block.appendChild(l)
+
+ get(tagValue, function (err, text) {
+ if (!text) {
+ block.appendChild(document.createTextNode(lang('wikipedia:no-url-parse')))
+ }
+
+ var div = document.createElement('div')
+ div.innerHTML = text
+ block.appendChild(div)
+
+ block.className = ''
+
+ callback(err)
+ })
+}
diff --git a/src/wikipedia.php b/src/wikipedia.php
new file mode 100644
index 00000000..55c2ca76
--- /dev/null
+++ b/src/wikipedia.php
@@ -0,0 +1,41 @@
+ "_")));
+
+ $content = file_get_contents($wp_url);
+
+ $langList = array($wp_lang => $wp_url);
+
+ $dom = new DOMDocument();
+ $dom->loadHTML($content);
+
+ $langDiv = $dom->getElementsByTagName('li');//interlanguage-link interwiki-bar');
+ for ($i = 0; $i < $langDiv->length; $i++) {
+ $li = $langDiv->item($i);
+
+ if (preg_match('/^interlanguage-link interwiki-(.*)$/', $li->getAttribute('class'), $m)) {
+ $a = $li->firstChild;
+ $langList[$m[1]] = $a->getAttribute('href');
+ }
+ }
+
+ if ($wp_lang !== $param['lang'] && array_key_exists($param['lang'], $langList)) {
+ $content = file_get_contents($langList[$param['lang']]);
+ $wp_lang = $param['lang'];
+ }
+
+ return array(
+ 'content' => $content,
+ 'languages' => $langList,
+ 'language' => $wp_lang,
+ );
+}
diff --git a/style.css b/style.css
index 8bc28b8f..252cc339 100644
--- a/style.css
+++ b/style.css
@@ -13,9 +13,7 @@ body {
top: 0px;
bottom: 0px;
left: 0px;
- width: 250px;
- padding-left:10px;
- padding-right:10px;
+ width: 270px;
position: absolute;
}
#map {
@@ -43,6 +41,7 @@ body {
}
#sidebar > #header {
padding-top: 27px;
+ padding-left: 10px;
height:110px;
font-size:18px;
color:#333;
@@ -74,6 +73,8 @@ body {
flex: 1;
flex-shrink: 0;
overflow: auto;
+ padding-left: 10px;
+ padding-right: 10px;
}
#sidebar > #footer {
@@ -488,3 +489,33 @@ a.showDetails {
.leaflet-popup-content ul > li > .key {
font-weight: bold;
}
+
+#contentDetails div > .loadingIndicator {
+ display: none;
+}
+#contentDetails div.loading > .loadingIndicator {
+ float: right;
+ display: block;
+}
+
+/* Wikipedia */
+.wikipedia img {
+ max-width: 100px;
+ max-height: 100px;
+ float: right;
+ margin-left: 0.5em;
+ margin-bottom: 0.5em;
+}
+.wikipedia div {
+ text-align: justify;
+}
+#contentDetails h3 {
+ border-bottom: 1px solid black;
+ clear: both;
+}
+#contentDetails h4 {
+ clear: both;
+}
+.wikipedia .reference {
+ display: none;
+}