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 += ' ' + lang('more') + '' } 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 = 'Loading...' 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 = '
' + text + '
' } else { result = '
' + value + '
' } return OverpassLayer.twig.filters.raw(result) })