Module:ⵜⴰⴼⵍⵓⵖⵎⵉⵙⵜ ⴰⵎⵏⵥⴰⵡ
ⵜⵉⴼⵔⴰⵙ
local p = {}
local function trimWhitespace(s)
if type(s) ~= 'string' then return nil end
s = s:match('^%s*(.-)%s*$')
if s == '' then return nil end
return s
end
local function getArgs(frame)
local args = {}
local parent = frame:getParent()
if parent and parent.args then
for k, v in pairs(parent.args) do
args[k] = trimWhitespace(v)
end
end
for k, v in pairs(frame.args) do
args[k] = trimWhitespace(v)
end
return args
end
local function getEntity(entityId)
if not mw.wikibase then return nil end
if entityId == '' then entityId = nil end
entityId = entityId or mw.wikibase.getEntityIdForCurrentPage()
if not entityId or entityId == '' then return nil end
local success, entity = pcall(function() return mw.wikibase.getEntity(entityId) end)
if success and entity then
entity.getBestStatements = function(self, propertyId)
if not self.claims or not self.claims[propertyId] then return {} end
local statements = {}
for _, claim in pairs(self.claims[propertyId]) do
if claim.mainsnak.snaktype == 'value' then
table.insert(statements, claim)
end
end
return statements
end
return entity
end
return nil
end
local function getCoordinates(entity)
local statements = entity:getBestStatements('P625')
if #statements > 0 then
local val = statements[1].mainsnak.datavalue.value
return val.latitude, val.longitude
end
return nil, nil
end
local function getLatestPopulation(entity, raw)
local claims = entity:getBestStatements('P1082')
if #claims == 0 then return nil end
local bestClaim = nil
local maxYear = -9999
for _, claim in ipairs(claims) do
local year = 0
if claim.qualifiers and claim.qualifiers['P585'] then
local timeValue = claim.qualifiers['P585'][1].datavalue.value.time
local yearStr = string.match(timeValue, "^[%+%-](%d+)")
if yearStr then year = tonumber(yearStr) end
end
if year > maxYear then
maxYear = year
bestClaim = claim
elseif not bestClaim then
bestClaim = claim
end
end
if bestClaim then
local amount = tonumber(bestClaim.mainsnak.datavalue.value.amount)
if raw then return amount end
local lang = mw.getContentLanguage()
local formattedNum = lang:formatNum(amount)
if maxYear > 0 then
return formattedNum .. ' <small>(' .. maxYear .. ')</small>'
else
return formattedNum
end
end
return nil
end
local function getLatestOutOfSchool(entity)
local claims = entity:getBestStatements('P2573')
if #claims == 0 then return nil end
local bestClaim = nil
local maxYear = -9999
for _, claim in ipairs(claims) do
local year = 0
if claim.qualifiers and claim.qualifiers['P585'] then
local timeValue = claim.qualifiers['P585'][1].datavalue.value.time
local yearStr = string.match(timeValue, "^[%+%-](%d+)")
if yearStr then year = tonumber(yearStr) end
end
if year > maxYear then
maxYear = year
bestClaim = claim
elseif not bestClaim then
bestClaim = claim
end
end
if bestClaim then
local amount = tonumber(bestClaim.mainsnak.datavalue.value.amount)
local lang = mw.getContentLanguage()
local formattedNum = lang:formatNum(amount)
if maxYear > 0 then
return formattedNum .. ' <small>(' .. maxYear .. ')</small>'
else
return formattedNum
end
end
return nil
end
local function getLatestArea(entity, raw)
local claims = entity:getBestStatements('P2046')
if #claims == 0 then return nil end
local bestClaim = nil
local maxDate = -9999999999999
for _, claim in ipairs(claims) do
local currentTimestamp = -9999999999999
if claim.qualifiers and claim.qualifiers['P585'] then
local timeValue = claim.qualifiers['P585'][1].datavalue.value.time
local yearStr = string.match(timeValue, "^[%+%-](%d+)")
if yearStr then currentTimestamp = tonumber(yearStr) end
end
if currentTimestamp > maxDate then
maxDate = currentTimestamp
bestClaim = claim
elseif not bestClaim then
bestClaim = claim
end
end
if bestClaim then
local val = bestClaim.mainsnak.datavalue.value
local amount = tonumber(val.amount)
if raw then return amount end
local lang = mw.getContentLanguage()
return amount and lang:formatNum(amount) or nil
end
return nil
end
local function getLatestDensity(entity)
local claims = entity:getBestStatements('P7959')
if #claims > 0 then
local val = claims[1].mainsnak.datavalue.value
local amount = tonumber(val.amount)
local lang = mw.getContentLanguage()
return amount and lang:formatNum(amount) or nil
end
local pop = getLatestPopulation(entity, true)
local area = getLatestArea(entity, true)
if pop and area and area > 0 then
local density = pop / area
local mult = 100
density = math.floor(density * mult + 0.5) / mult
local lang = mw.getContentLanguage()
return lang:formatNum(density)
end
return nil
end
local function makeRequest(entityId, property)
local entity = getEntity(entityId)
if not entity then return nil, false end
if property == 'P1082' then
local popValue = getLatestPopulation(entity)
if popValue then return popValue, true end
return nil, false
end
if property == 'P2573' then
local outOfSchoolValue = getLatestOutOfSchool(entity)
if outOfSchoolValue then return outOfSchoolValue, true end
return nil, false
end
if property == 'P2046' then
local areaValue = getLatestArea(entity)
if areaValue then return areaValue, true end
return nil, false
end
if property == 'P7959' then
local densityValue = getLatestDensity(entity)
if densityValue then return densityValue, true end
return nil, false
end
local statements = entity:getBestStatements(property)
if #statements > 0 then
local valuesWithLinks = {}
for _, statement in ipairs(statements) do
local datavalue = statement.mainsnak.datavalue
local valueToAdd = nil
if datavalue.type == 'string' then
valueToAdd = datavalue.value
elseif datavalue.type == 'wikibase-entityid' then
local targetEntityId = datavalue.value.id
local label = mw.wikibase.getLabel(targetEntityId)
if not label then
local targetEntity = mw.wikibase.getEntity(targetEntityId)
if targetEntity and targetEntity.labels then
if targetEntity.labels.en then
label = targetEntity.labels.en.value
elseif targetEntity.labels.fr then
label = targetEntity.labels.fr.value
end
end
end
label = label or targetEntityId
local sitelink = mw.wikibase.getSitelink(targetEntityId)
if sitelink then
valueToAdd = string.format("[[%s|%s]]", sitelink, label)
else
valueToAdd = string.format("[[:d:%s|%s]]", targetEntityId, label)
end
if property == 'P17' then
local flags = mw.wikibase.getBestStatements(targetEntityId, 'P41')
if #flags > 0 and flags[1].mainsnak.datavalue then
valueToAdd = '[[ⴰⴼⴰⵢⵍⵓ:' .. flags[1].mainsnak.datavalue.value .. '|20px|border|link=]] ' .. valueToAdd
end
end
elseif datavalue.type == 'quantity' then
local amount = tonumber(datavalue.value.amount)
local lang = mw.getContentLanguage()
valueToAdd = amount and lang:formatNum(amount) or datavalue.value.amount
elseif datavalue.type == 'time' then
valueToAdd = string.sub(datavalue.value.time, 9, 10)
end
if valueToAdd then
table.insert(valuesWithLinks, valueToAdd)
end
end
if #valuesWithLinks > 0 then
if (property == 'P421' or property == 'P17') and #valuesWithLinks > 1 then
local container = mw.html.create('div')
container:addClass('mw-collapsible mw-collapsed')
container:tag('div')
:css('font-weight', 'normal')
:wikitext('ⵜⴰⵍⴳⴰⵎⵜ [[ⴰⴼⴰⵢⵍⵓ:Incomplete list.svg|17px|link=]] (' .. #valuesWithLinks .. ')')
local contentDiv = container:tag('div'):addClass('mw-collapsible-content')
local ul = contentDiv:tag('ul')
for _, v in ipairs(valuesWithLinks) do
ul:tag('li'):wikitext(v)
end
return tostring(container), true
end
return table.concat(valuesWithLinks, ", "), true
end
end
return nil, false
end
local function getValueOrWikidata(args, paramName, propertyId)
local value = args[paramName]
local fromWikidata = false
if value then value = trimWhitespace(value) end
if not value then
if propertyId and args.qid ~= '' then
value, fromWikidata = makeRequest(args.qid, propertyId)
end
end
return value, fromWikidata
end
function p.main(frame)
local args = getArgs(frame)
local entityId = args.qid
if entityId == '' then entityId = nil end
entityId = entityId or mw.wikibase.getEntityIdForCurrentPage()
local entity = getEntity(entityId)
frame:extensionTag('templatestyles', '', {src = 'ⴰⵍⴱⵓⴹ:ⵜⴰⴼⵍⵓⵖⵎⵉⵙⵜ ⴰⵎⵏⵥⴰⵡ/styles.css'})
local infobox = mw.html.create('table')
infobox:addClass('infobox geography vcard')
infobox:css({
['border'] = '1px solid #a2a9b1',
['background-color'] = '#f8f9fa',
['color'] = 'black',
['margin'] = '0.5em 0 0.5em 1em',
['float'] = 'right',
['clear'] = 'right',
['font-size'] = '90%',
['width'] = '18em',
})
local headerValue = args['ⵉⵙⵎ']
if not headerValue and entityId then
headerValue = mw.wikibase.getLabel(entityId)
if not headerValue and entity and entity.labels and entity.labels.en then
headerValue = entity.labels.en.value
end
end
headerValue = headerValue or mw.title.getCurrentTitle().text
local headerRow = infobox:tag('tr')
local headerCell = headerRow:tag('th')
:attr('colspan', 2)
:css({
['background-color'] = '#006400',
['color'] = '#ffffff',
['padding'] = '0.4em',
['text-align'] = 'center',
['font-weight'] = 'bold',
['font-size'] = '125%',
['position'] = 'relative'
})
local headerContainer = mw.html.create('div')
:css({
['padding-right'] = '50px',
['padding-left'] = '50px',
})
:wikitext(headerValue)
headerCell:node(headerContainer)
local iconContainer = mw.html.create('div')
:css({
['position'] = 'absolute',
['top'] = '1px',
['right'] = '1px',
})
:wikitext('[[ⴰⴼⴰⵢⵍⵓ:Picto_infobox_map.png|95px|alt=ⵜⴰⵢⴽⵓⵏⵜ|link=]]')
headerCell:node(iconContainer)
if entity then
local maps = entity:getBestStatements('P242')
if #maps > 0 then
local lat, lon = getCoordinates(entity)
local caption = 'ⴰⴷⵖⴰⵔ ⵏ ' .. headerValue .. ' ⴳ ⵜⴽⴰⵕⴹⴰ'
if lat and lon then
local coordStr = frame:expandTemplate{ title = 'Coord', args = { lat, lon, display='inline', format='dms' } }
caption = caption .. '<br /><div style="display:inline-block; margin-top:2px;">[[ⴰⴼⴰⵢⵍⵓ:OOjs_UI_icon_mapPin-progressive.svg|12px]] ' .. coordStr .. '</div>'
end
infobox:tag('tr'):tag('td')
:attr('colspan', 2)
:css('text-align', 'center')
:wikitext('[[ⴰⴼⴰⵢⵍⵓ:' .. maps[1].mainsnak.datavalue.value .. '|260px|frameless]]')
:tag('div')
:css({
['padding-top'] = '3px',
['font-size'] = '90%',
['line-height'] = '1.3'
})
:wikitext(caption)
end
end
local sectionHeaderStyle = {
['background-color'] = '#006400',
['color'] = '#ffffff',
['text-align'] = 'center',
['font-weight'] = 'normal',
['padding'] = '2px',
}
local sections = {
{
title = 'ⵜⴰⵔⴰⴽⴰⵍⵜ',
properties = {
{ 'ⴰⴳⵣⵣⵓⵎ ⵙⴳ', 'ⴰⴳⵣⵣⵓⵎ ⵙⴳ', 'P361' },
{ 'ⵜⴰⵊⵓⵎⵎⴰ', 'ⵜⴰⵊⵓⵎⵎⴰ', 'P2046' },
{ 'ⵉⵡⵜⵜⴰ ⴰⴽⴷ', 'ⵉⵡⵜⵜⴰ ⴰⴽⴷ', 'P47' },
{ 'ⴰⴷⵖⴰⵔ ⴰⵏⴰⴼⵍⵍⴰ', 'ⴰⴷⵖⴰⵔ ⴰⵏⴰⴼⵍⵍⴰ', 'P610' },
{ 'ⴰⴷⵖⴰⵔ ⴰⵏⴰⴷⴷⴰⵡ', 'ⴰⴷⵖⴰⵔ ⴰⵏⴰⴷⴷⴰⵡ', 'P1589' },
{ 'ⴰⵙⵉⴼ ⴰⵖⵣⵣⴰⴼ', 'ⴰⵙⵉⴼ ⴰⵖⵣⵣⴰⴼ', 'P2053' },
}
},
{
title = 'ⵜⴰⵔⴰⵖⵔⴼⵜ',
properties = {
{ 'ⵉⵎⵣⴷⴰⵖⵏ', 'ⵉⵎⵣⴷⴰⵖ', 'P1082' },
{ 'ⵜⴰⵏⵥⵥⵉ', 'ⵜⴰⵏⵥⵥⵉ', 'P7959' },
{ 'ⵉⵙⵎ ⵏ ⵉⵎⵣⴷⴰⵖⵏ', 'ⵉⵙⵎ ⵉⵎⵣⴷⴰⵖⵏ', 'P1549' },
{ 'ⵓⵟⵟⵓⵏ ⵏ ⵉⵛⵉⵔⵔⴰⵏ ⴱⵕⵕⴰ ⵏ ⵜⵉⵏⵎⵍ', 'ⵓⵟⵟⵓⵏ ⵏ ⵉⵛⵉⵔⵔⴰⵏ ⴱⵕⵕⴰ ⵏ ⵜⵉⵏⵎⵍ', 'P2573' },
}
},
{
title = 'ⵓⵎⵍⴰⵏ ⵢⴰⴹⵏⵉⵏ',
properties = {
{ 'ⵉⵜⵜⵓⵙⵎⵎⴰ ⵙ', 'ⵉⵜⵜⵓⵙⵎⵎⴰ ⵙ', 'P138' },
{ 'ⵜⵉⵎⵓⵔⴰ', 'ⵜⵉⵎⵓⵔⴰ', 'P17' },
{ 'ⴰⴽⵓⴷ', 'ⴰⴽⵓⴷ', 'P421' },
{ 'ⵖⵓⵔⵙ ⴰⴳⵣⵣⵓⵎ ⵙⴳ', 'ⵖⵓⵔⵙ ⴰⴳⵣⵣⵓⵎ ⵙⴳ', 'P527' },
{ 'ⴰⴳⵍⴰ ⵏ ⵡⴰⵏⵜⵉⵔⵏⵉⵜ', 'ⴰⴳⵍⴰ ⵏ ⵡⴰⵏⵜⵉⵔⵏⵉⵜ', 'P78' },
{ 'ⵜⵉⵎⴷⵉⵏⵉⵏ', 'ⵜⵉⵎⴷⵉⵏⵉⵏ', nil },
}
}
}
for _, section in ipairs(sections) do
local sectionContent = mw.html.create('')
local hasData = false
for _, prop in ipairs(section.properties) do
local label, param, pid = unpack(prop)
local value, fromWikidata = getValueOrWikidata(args, param, pid)
if value then
hasData = true
local row = sectionContent:tag('tr')
row:tag('th')
:wikitext(label)
:css({
['text-align'] = 'left',
['width'] = '50%',
['padding-right'] = '10px',
['font-weight'] = 'normal',
['background-color'] = '#F3F3F3',
['vertical-align'] = 'top'
})
local cell = row:tag('td'):css({['padding'] = '2px', ['width'] = '50%'})
if param == 'ⵜⴰⵏⵥⵥⵉ' then
value = value .. ' ⵣⴷⵖ/ⴽⵎ²'
end
if param == 'ⵜⴰⵊⵓⵎⵎⴰ' then
value = value .. ' ⴽⵎ²'
end
if fromWikidata and pid and entityId then
cell:wikitext(value .. ' [[ⴰⴼⴰⵢⵍⵓ:Edit-icon.svg|15px|link=https://www.wikidata.org/wiki/' .. entityId .. '#' .. pid .. '|ⵙⵏⴼⵍ ⴳ ⵡⵉⴽⵉⴷⴰⵜⴰ]]')
else
cell:wikitext(value)
end
end
end
if hasData then
infobox:tag('tr'):tag('th')
:attr('colspan', 2)
:css(sectionHeaderStyle)
:wikitext(section.title)
infobox:node(sectionContent)
end
end
if entityId then
local lat, lon = getCoordinates(entity)
if lat and lon then
local mapFeatures = {}
table.insert(mapFeatures, {
type = "ExternalData",
service = "geoshape",
ids = entityId,
properties = {
["stroke-width"] = 2,
stroke = "#FF0000",
["fill-opacity"] = 0.2
}
})
table.insert(mapFeatures, {
type = "Feature",
geometry = {
type = "Point",
coordinates = { lon, lat }
},
properties = {
--["marker-symbol"] = "star",
["marker-color"] = "#3d7c35",
["marker-size"] = "small"
}
})
local mapFrame = frame:extensionTag{
name = 'mapframe',
content = mw.text.jsonEncode(mapFeatures),
args = {
width = "290",
height = "190",
zoom = "2",
align = "center",
frameless = "frameless"
}
}
infobox:tag('tr'):tag('th')
:attr('colspan', 2)
:css(sectionHeaderStyle)
:wikitext('ⴰⴷⵖⴰⵔ ⴰⵔⴰⴽⴰⵍ')
infobox:tag('tr'):tag('td')
:attr('colspan', 2)
:css('text-align', 'center')
:wikitext(mapFrame)
end
end
local separatorRow = infobox:tag('tr')
local separatorCell = separatorRow:tag('td')
:attr('colspan', 2)
:css({
['padding'] = '0',
['border-top'] = '2px dashed #006400',
})
separatorCell:tag('div'):css({['height'] = '1px', ['background-color'] = 'transparent'})
local currentTitle = mw.title.getCurrentTitle()
local editSourceUrl = currentTitle:fullUrl({action='edit', section='0'})
local editVisualUrl = currentTitle:fullUrl({veaction='edit'})
local templateDocUrl = mw.title.new('ⴰⵍⴱⵓⴹ:ⵜⴰⴼⵍⵓⵖⵎⵉⵙⵜ ⴰⵎⵏⵥⴰⵡ'):fullUrl()
local footerRow = infobox:tag('tr')
local footerCell = footerRow:tag('td')
:attr('colspan', 2)
:css({
['padding'] = '0.2em',
['font-size'] = '85%',
['text-align'] = 'left',
['background-color'] = '#f8f8f8',
})
local footerContainer = mw.html.create('div')
:css({
['display'] = 'flex',
['justify-content'] = 'space-between',
['align-items'] = 'center',
})
local editLinksSpan = footerContainer:tag('span'):addClass('plainlinks')
if entityId and entityId ~= '' then
local wikidataUrl = 'https://www.wikidata.org/wiki/Special:EntityPage/' .. entityId
editLinksSpan:wikitext('[' .. editSourceUrl .. ' <span style="color:#002bb8;">ⵙⵏⴼⵍ ⴰⵙⴰⴳⵎ</span>] - [' ..
editVisualUrl .. ' <span style="color:#002bb8;">ⵙⵏⴼⵍ</span>] - [' ..
wikidataUrl .. ' <span style="color:#002bb8;">ⵡⵉⴽⵉⴷⴰⵜⴰ</span>]')
else
editLinksSpan:wikitext('[' .. editSourceUrl .. ' <span style="color:#002bb8;">ⵙⵏⴼⵍ ⴰⵙⴰⴳⵎ</span>] - [' ..
editVisualUrl .. ' <span style="color:#002bb8;">ⵙⵏⴼⵍ</span>]')
end
footerContainer:tag('span')
:css({['float'] = 'right', ['margin-left'] = '5px'})
:wikitext('[[ⴰⴼⴰⵢⵍⵓ:Info Simple.svg|18px|ⵥⵕ ⵓⴳⴳⴰⵔ ⵅⴼ ⵡⴰⵍⴱⵓⴹ ⴰⴷ |link=' .. templateDocUrl .. ']]')
footerCell:node(footerContainer)
return tostring(infobox)
end
return p