Stephan Bösch-Plepelits
4 years ago
9 changed files with 271 additions and 12 deletions
-
4bin/download_dependencies
-
52bin/tag2link-converter
-
7lib/tag2link-sophox.qry
-
15lib/tag2link-wikidata.qry
-
23src/category.css
-
15src/index.js
-
63src/tagsDisplay-tag2link.js
-
96src/tagsDisplay.js
-
8src/wikipedia.js
@ -1,3 +1,7 @@ |
|||||
#!/bin/sh |
#!/bin/sh |
||||
|
|
||||
|
curl -H "Accept: application/json" -H "Content-Type: application/sparql-query" -H "User-Agent: OpenStreetBrowser" -XPOST -d @'lib/tag2link-wikidata.qry' https://query.wikidata.org/sparql > data/tag2link-wikidata.json |
||||
|
curl -H "Accept: application/json" -H "Content-Type: application/sparql-query" -H "User-Agent: OpenStreetBrowser" -XPOST -d @'lib/tag2link-sophox.qry' https://sophox.org/sparql > data/tag2link-sophox.json |
||||
|
bin/tag2link-converter |
||||
|
|
||||
bin/download_geoip2 |
bin/download_geoip2 |
@ -0,0 +1,52 @@ |
|||||
|
#!/usr/bin/php |
||||
|
<?php |
||||
|
$tag2link = array(); |
||||
|
|
||||
|
$files = array('data/tag2link-wikidata.json', 'data/tag2link-sophox.json'); |
||||
|
foreach ($files as $file) { |
||||
|
$data = json_decode(file_get_contents($file), true); |
||||
|
|
||||
|
foreach ($data['results']['bindings'] as $entry) { |
||||
|
$key = substr($entry['OSM_key']['value'], 4); |
||||
|
$link = $entry['formatter_URL']['value']; |
||||
|
|
||||
|
if (array_key_exists($key, $tag2link)) { |
||||
|
// avoid duplicates |
||||
|
$duplicates = array_filter($tag2link[$key]['formatter'], function ($e) use ($link) { |
||||
|
return $e['link'] === $link; |
||||
|
}); |
||||
|
|
||||
|
if (sizeof($duplicates)) { |
||||
|
if (array_key_exists('operatorLabel', $entry)) { |
||||
|
foreach ($duplicates as $i => $d) { |
||||
|
$tag2link[$key]['formatter'][$i]['operator'] = $entry['operatorLabel']['value']; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
continue; |
||||
|
} |
||||
|
} |
||||
|
else { |
||||
|
$tag2link[$key] = array( |
||||
|
'label' => $entry['itemLabel']['value'], |
||||
|
'formatter' => array(), |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
$formatter = array( |
||||
|
'link' => $link, |
||||
|
); |
||||
|
|
||||
|
if (array_key_exists('operatorLabel', $entry)) { |
||||
|
$formatter['operator'] = $entry['operatorLabel']['value']; |
||||
|
print "{$formatter['operator']}\n"; |
||||
|
} |
||||
|
else if (preg_match("/^https?:\/\/([^\/]*)(\/.*|)$/", $link, $m)) { |
||||
|
$formatter['operator'] = $m[1]; |
||||
|
} |
||||
|
|
||||
|
$tag2link[$key]['formatter'][] = $formatter; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
file_put_contents('dist/tag2link.json', json_encode($tag2link, JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES|JSON_UNESCAPED_UNICODE)); |
@ -0,0 +1,7 @@ |
|||||
|
SELECT ?item ?itemLabel (CONCAT("Key:", ?permanent_key_ID) as ?OSM_key) ?formatter_URL WHERE { |
||||
|
FILTER(?permanent_key_ID NOT IN ('image', 'url', 'website', 'wikidata', 'wikimedia_commons')). |
||||
|
?item osmdt:P2 osmd:Q7. |
||||
|
SERVICE wikibase:label { bd:serviceParam wikibase:language "en". } |
||||
|
?item osmdt:P16 ?permanent_key_ID. |
||||
|
?item osmdt:P8 ?formatter_URL. |
||||
|
} |
@ -0,0 +1,15 @@ |
|||||
|
SELECT ?itemLabel ?OSM_key ?formatter_URL ?operatorLabel WHERE { |
||||
|
?item wdt:P1282 ?OSM_key . |
||||
|
FILTER(?OSM_key NOT IN("Key:image", "Key:url", "Key:website", "Key:wikidata", "Key:wikimedia_commons")) |
||||
|
SERVICE wikibase:label { bd:serviceParam wikibase:language "en". } |
||||
|
{ |
||||
|
?item p:P1630 ?statement. |
||||
|
?statement ps:P1630 ?formatter_URL. |
||||
|
} |
||||
|
UNION |
||||
|
{ |
||||
|
?item p:P3303 ?statement. |
||||
|
?statement ps:P3303 ?formatter_URL. |
||||
|
} |
||||
|
OPTIONAL { ?statement pq:P137 ?operator. } |
||||
|
} |
@ -0,0 +1,63 @@ |
|||||
|
const httpGet = require('./httpGet') |
||||
|
const formatter = require('./tagsDisplay').formatter |
||||
|
|
||||
|
let tag2link |
||||
|
|
||||
|
register_hook('init_callback', (initState, callback) => { |
||||
|
httpGet('dist/tag2link.json', {}, (err, result) => { |
||||
|
if (err) { |
||||
|
console.error('Can\'t read dist/tag2link.json - execute bin/download_dependencies') |
||||
|
return callback() |
||||
|
} |
||||
|
|
||||
|
tag2link = JSON.parse(result.body) |
||||
|
|
||||
|
Object.keys(tag2link).forEach(key => { |
||||
|
let tag = tag2link[key] |
||||
|
let link = tag.formatter[0].link.replace('$1', '{{ value }}') |
||||
|
|
||||
|
if (tag.formatter.length > 1) { |
||||
|
link = "#\" onclick=\"return tag2link(this, " + JSON.stringify(key).replace(/"/g, '"') + ", {{ value|json_encode }})" |
||||
|
} |
||||
|
|
||||
|
formatter.push({ |
||||
|
regexp: new RegExp("^" + key + "$"), |
||||
|
link |
||||
|
}) |
||||
|
}) |
||||
|
|
||||
|
callback() |
||||
|
}) |
||||
|
}) |
||||
|
|
||||
|
global.tag2link = function (dom, key, value) { |
||||
|
let div = document.createElement('div') |
||||
|
div.className = 'tag2link' |
||||
|
dom.parentNode.appendChild(div) |
||||
|
|
||||
|
let closeButton = document.createElement('div') |
||||
|
closeButton.className = 'closeButton' |
||||
|
closeButton.innerHTML = '❌' |
||||
|
closeButton.onclick = () => { |
||||
|
dom.parentNode.removeChild(div) |
||||
|
} |
||||
|
div.appendChild(closeButton) |
||||
|
|
||||
|
let selector = document.createElement('ul') |
||||
|
div.appendChild(selector) |
||||
|
|
||||
|
let tag = tag2link[key] |
||||
|
tag.formatter.forEach(formatter => { |
||||
|
let li = document.createElement('li') |
||||
|
|
||||
|
let a = document.createElement('a') |
||||
|
a.target = '_blank' |
||||
|
a.href = formatter.link.replace('$1', value) |
||||
|
a.appendChild(document.createTextNode(formatter.operator)) |
||||
|
|
||||
|
li.appendChild(a) |
||||
|
selector.appendChild(li) |
||||
|
}) |
||||
|
|
||||
|
return false |
||||
|
} |
@ -0,0 +1,96 @@ |
|||||
|
const OverpassLayer = require('overpass-layer') |
||||
|
|
||||
|
const formatter = [ |
||||
|
{ |
||||
|
regexp: /^(.*:)?wikidata$/, |
||||
|
link: 'https://wikidata.org/wiki/{{ value }}' |
||||
|
}, |
||||
|
{ |
||||
|
regexp: /^(.*:)?wikipedia$/, |
||||
|
link: '{% set v = value|split(":") %}https://{{ v[0] }}.wikipedia.org/wiki/{{ v[1]|replace({" ": "_"}) }}' |
||||
|
}, |
||||
|
{ |
||||
|
regexp: /^(.*:)?wikipedia:([a-zA-Z]+)$/, |
||||
|
link: '{% set v = key|matches(":([a-zA-Z]+)") %}https://{{ v[1] }}.wikipedia.org/wiki/{{ value|replace({" ": "_"}) }}' |
||||
|
}, |
||||
|
{ |
||||
|
regexp: /^((.*:)?website(:.*)?|(.*:)?url(:.*)?|contact:website)$/, |
||||
|
link: '{{ value|websiteUrl }}' |
||||
|
}, |
||||
|
{ |
||||
|
regexp: /^(image|wikimedia_commons)$/, |
||||
|
link: '{% if value matches "/^(File|Category):/" %}' + |
||||
|
'https://commons.wikimedia.org/wiki/{{ value|replace({" ": "_"}) }}' + |
||||
|
'{% else %}' + |
||||
|
'{{ value|websiteUrl }}' + |
||||
|
'{% endif %}' |
||||
|
}, |
||||
|
{ |
||||
|
regexp: /^(species)$/, |
||||
|
link: 'https://species.wikimedia.org/wiki/{{ value|replace({" ": "_"}) }}' |
||||
|
}, |
||||
|
{ |
||||
|
regexp: /^(phone|contact:phone|fax|contact:fax)(:.*|)$/, |
||||
|
link: 'tel:{{ value }}' |
||||
|
}, |
||||
|
{ |
||||
|
regexp: /^(email|contact:email)(:.*|)$/, |
||||
|
link: 'mailto:{{ value }}' |
||||
|
} |
||||
|
] |
||||
|
|
||||
|
let compiled = false |
||||
|
let defaultTemplate |
||||
|
|
||||
|
function tagsDisplay (tags) { |
||||
|
if (!compiled) { |
||||
|
defaultTemplate = OverpassLayer.twig.twig({ data: '{{ value }}', autoescape: true }) |
||||
|
for (let i in formatter) { |
||||
|
if (formatter[i].format) { |
||||
|
formatter[i].template = OverpassLayer.twig.twig({ data: formatter[i].format, autoescape: true }) |
||||
|
} else { |
||||
|
formatter[i].template = OverpassLayer.twig.twig({ data: '<a target="_blank" href="' + formatter[i].link + '">{{ value }}</a>', autoescape: true }) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
compiled = true |
||||
|
} |
||||
|
|
||||
|
const div = document.createElement('dl') |
||||
|
div.className = 'tags' |
||||
|
for (let k in tags) { |
||||
|
const dt = document.createElement('dt') |
||||
|
dt.appendChild(document.createTextNode(k)) |
||||
|
div.appendChild(dt) |
||||
|
|
||||
|
let template = defaultTemplate |
||||
|
|
||||
|
const dd = document.createElement('dd') |
||||
|
for (let i = 0; i < formatter.length; i++) { |
||||
|
if (k.match(formatter[i].regexp)) { |
||||
|
template = formatter[i].template |
||||
|
break |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
let value = tags[k].split(/;/g) |
||||
|
value = value.map(v => { |
||||
|
// trim whitespace (but add it around the formatted value later)
|
||||
|
let m = v.match(/^( *)([^ ].*[^ ]|[^ ])( *)$/) |
||||
|
if (m) { |
||||
|
return m[1] + template.render({ key: k, value: m[2] }) + m[3] |
||||
|
} |
||||
|
return v |
||||
|
}).join(';') |
||||
|
|
||||
|
dd.innerHTML = value |
||||
|
div.appendChild(dd) |
||||
|
} |
||||
|
|
||||
|
return div |
||||
|
} |
||||
|
|
||||
|
module.exports = { |
||||
|
display: tagsDisplay, |
||||
|
formatter |
||||
|
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue