You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

432 lines
9.6 KiB

const async = require('async')
const OverpassLayer = require('overpass-layer')
var wikidata = require('./wikidata')
const displayBlock = require('./displayBlock')
var cache = {}
var getAbstractCache = {}
var loadClash = {}
function stripLinks (dom) {
var as = dom.getElementsByTagName('a')
as = Array.prototype.slice.call(as)
as.forEach(function (current) {
while (current.firstChild) {
current.parentNode.insertBefore(current.firstChild, current)
}
current.parentNode.removeChild(current)
})
}
function prepare (div) {
var i
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.className !== '' || p.textContent.match(/^\s*$/) || p.querySelector('span#coordinates'))) {
p = p.nextSibling
}
if (!p) {
return null
}
stripLinks(p)
// first image
var imgs = content.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])
}
if (cacheId in loadClash) {
loadClash[cacheId].push(callback)
return
}
loadClash[cacheId] = []
ajax('wikipedia',
{
page: value,
lang: options.data_lang
},
function (result) {
if (!result.content) {
return callback(new Error('error'), null)
}
cache[cacheId] = result
callback(null, result)
loadClash[cacheId].forEach(function (d) {
d(null, result)
})
delete loadClash[cacheId]
}
)
}
function getAbstract (value, callback) {
const cacheId = options.data_lang + ':' + value
if (cacheId in getAbstractCache) {
callback(null, getAbstractCache[cacheId])
return getAbstractCache[cacheId]
}
get(value,
function (err, result) {
var text = null
if (result) {
var div = document.createElement('div')
div.innerHTML = result.content
text = prepare(div)
text += ' <a target="_blank" href="' + result.languages[result.language] + '">' + lang('more') + '</a>'
}
getAbstractCache[cacheId] = text
callback(err, text)
}
)
}
function updateDomWikipedia (dom, callback) {
const wikipediaQueries = dom.querySelectorAll('.wikipedia')
async.each(
wikipediaQueries,
(div, done) => {
if (div.hasAttribute('data-done')) {
return done()
}
getAbstract(div.getAttribute('data-id'),
(err, result) => {
if (result) {
div.innerHTML = result
div.setAttribute('data-done', 'true')
}
done()
}
)
},
() => {
callback()
}
)
}
register_hook('show-popup', function (data, category, dom, callback) {
updateDomWikipedia(dom, () => updateDomWikipedia(dom, () => {}))
callback()
})
register_hook('show-details', function (data, category, dom, callback) {
var ob = data.object
var found = 0
var foundPrefixes = []
var finished = 0
var errs = []
var h, k, m
var div = document.createElement('div')
div.className = 'wikipedia'
const mainBlock = document.createElement('div')
div.appendChild(mainBlock)
if ('wikipedia' in ob.tags) {
foundPrefixes.push('')
ob.tags.wikipedia.split(/;/g).forEach(value => {
value = value.trim()
found++
showWikipedia(value, mainBlock, done)
})
}
for (k in ob.tags) {
m = k.match(/^(.*):wikipedia$/)
if (m) {
let prefix = m[1]
const block = document.createElement('div')
div.appendChild(block)
h = document.createElement('h4')
h.appendChild(document.createTextNode(lang('tag:' + prefix)))
block.appendChild(h)
foundPrefixes.push(prefix)
ob.tags[k].split(/;/g).forEach(value => {
value = value.trim()
found++
showWikipedia(value, block, done)
})
}
m = k.match(/^((.*):)?wikipedia:(.*)$/)
if (m) {
let prefix = m[1]
if (typeof prefix === 'undefined' && foundPrefixes.indexOf('') !== -1) {
continue
}
if (foundPrefixes.indexOf(prefix) !== -1) {
continue
}
let block = mainBlock
if (prefix) {
block = document.createElement('div')
div.appendChild(block)
h = document.createElement('h4')
h.appendChild(document.createTextNode(lang('tag:' + prefix)))
block.appendChild(h)
}
foundPrefixes.push(prefix)
;(m[3] + ':' + ob.tags[k]).split(/;/g).forEach(value => {
found++
showWikipedia(value, block, done)
})
}
}
if (ob.tags.wikidata && foundPrefixes.indexOf('') === -1) {
foundPrefixes.push('')
ob.tags.wikidata.split(/;/g).forEach(value => {
value = value.trim()
found++
wikidata.load(value, function (err, result) {
var x
if (err) {
return done(err)
}
if (!result.sitelinks) {
return done(new Error('No Wikipedia links defined for Wikidata'))
}
if (options.data_lang + 'wiki' in result.sitelinks) {
x = result.sitelinks[options.data_lang + 'wiki']
return showWikipedia(options.data_lang + ':' + x.title, mainBlock, done)
}
for (k in result.sitelinks) {
if (k === 'commonswiki') {
continue
}
x = result.sitelinks[k]
m = k.match(/^(.*)wiki$/)
return showWikipedia(m[1] + ':' + x.title, mainBlock, done)
}
done()
})
})
}
for (k in ob.tags) {
m = k.match(/^(.*):wikidata$/)
if (m) {
let prefix = m[1]
found++
if (foundPrefixes.indexOf(prefix) !== -1) {
continue
}
foundPrefixes.push(prefix)
const block = document.createElement('div')
div.appendChild(block)
h = document.createElement('h4')
h.appendChild(document.createTextNode(lang('tag:' + prefix)))
block.appendChild(h)
ob.tags[k].split(/;/g).forEach(value => {
value = value.trim()
wikidata.load(value, (err, result) => {
var x
if (err) {
return done(err)
}
if (!result.sitelinks) {
return done()
}
if (options.data_lang + 'wiki' in result.sitelinks) {
x = result.sitelinks[options.data_lang + 'wiki']
return showWikipedia(options.data_lang + ':' + x.title, block, done)
}
for (k in result.sitelinks) {
if (k === 'commonswiki') {
continue
}
x = result.sitelinks[k]
m = k.match(/^(.*)wiki$/)
return showWikipedia(m[1] + ':' + x.title, block, done)
}
done()
})
})
}
}
if (found) {
displayBlock({
dom,
title: lang('tag:wikipedia'),
content: div,
order: 1
})
} else {
callback()
}
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 = '<i class="fa fa-spinner fa-pulse fa-fw"></i><span class="sr-only">Loading...</span>'
l.className = 'loadingIndicator'
block.appendChild(l)
getAbstract(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.removeChild(l)
block.className = 'clearfix'
callback(err)
})
}
function getImages (tagValue, callback) {
var i
get(tagValue, function (err, result) {
if (err) {
return callback(err, null)
}
var div = document.createElement('div')
div.innerHTML = result.content
var imgs = div.getElementsByTagName('img')
var ret = []
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')
var m = img.src.match(/^https?:\/\/upload.wikimedia.org\/wikipedia\/commons\/thumb\/\w+\/\w+\/([^/]+)/)
if (m) {
var file = decodeURIComponent(m[1]).replace(/_/g, ' ')
ret.push({
id: file,
width: img.getAttribute('data-file-width'),
height: img.getAttribute('data-file-height')
})
}
}
callback(null, ret)
})
}
module.exports = {
getImages: getImages
}
OverpassLayer.twig.extendFilter('wikipediaAbstract', function (value, param) {
let result
const cacheId = options.data_lang + ':' + value
if (cacheId in getAbstractCache) {
const text = getAbstractCache[cacheId]
result = '<div class="wikipedia" data-id="' + value + '" data-done="true">' + text + '</div>'
} else {
result = '<div class="wikipedia" data-id="' + value + '"><a href="https://wikidata.org/wiki/' + value + '">' + value + '</a></div>'
}
return OverpassLayer.twig.filters.raw(result)
})