「モジュール:Location map」の版間の差分

モジュール:Location map/sandbox 2015年3月14日 (土) 16:40‎(UTC)より
template>K-iczn
(修正)
template>K-iczn
(モジュール:Location map/sandbox 2015年3月14日 (土) 16:40‎(UTC)より)
4行目: 4行目:


local getArgs = require('Module:Arguments').getArgs
local getArgs = require('Module:Arguments').getArgs
local function round(n, decimals)
local pow = 10^(decimals or 0)
return math.floor(n * pow + 0.5) / pow
end


function p.getMapParams(map, frame)
function p.getMapParams(map, frame)
15行目: 20行目:
local mapData = mw.loadData('Module:Location map/data/' .. map)
local mapData = mw.loadData('Module:Location map/data/' .. map)
return function(name, params)
return function(name, params)
if mapData[name] == nil then
if name == nil then
return 'Module:Location map/data/' .. map
elseif mapData[name] == nil then
return ''
return ''
elseif params then
elseif params then
25行目: 32行目:
elseif mw.title.new('Template:Location map ' .. map).exists then
elseif mw.title.new('Template:Location map ' .. map).exists then
local cache = {}
local cache = {}
if type(frame) ~= 'table' or type(frame.expandTemplate) ~= 'function' then
error('A frame must be provided when using a legacy location map')
end
return function(name, params)
return function(name, params)
if params then
if params then
return frame:expandTemplate{title = 'Location map ' .. map, args = { name, unpack(params) }}
return frame:expandTemplate{title = 'Location map ' .. map, args = { name, unpack(params) }}
else
else
if cache[name] == nil then
if name == nil then
return 'Template:Location map ' .. map
elseif cache[name] == nil then
cache[name] = frame:expandTemplate{title = 'Location map ' .. map, args = { name }}
cache[name] = frame:expandTemplate{title = 'Location map ' .. map, args = { name }}
end
end
42行目: 54行目:
function p.data(frame, args, map)
function p.data(frame, args, map)
if not args then
if not args then
args = getArgs(frame)
args = getArgs(frame, {frameOnly = true})
end
end
if not map then
if not map then
53行目: 65行目:
end
end
end
end
return map(args[2], #params and params)
return map(args[2], #params ~= 0 and params)
end
end


62行目: 74行目:


local function decdeg(degrees, minutes, seconds, hemisphere, decimal, direction)
local function decdeg(degrees, minutes, seconds, hemisphere, decimal, direction)
if not degrees then
if decimal then
if not decimal then
if degrees then
error('No value was provided for ' .. direction, 2)
error('Decimal and DMS degrees cannot both be provided for ' .. direction, 2)
elseif minutes then
error('Minutes can only be provided with DMS degrees for ' .. direction, 2)
elseif seconds then
error('Seconds can only be provided with DMS degrees for ' .. direction, 2)
elseif hemisphere then
error('A hemisphere can only be provided with DMS degrees for ' .. direction, 2)
end
end
local retval = tonumber(decimal)
local retval = tonumber(decimal)
71行目: 89行目:
end
end
error('The value "' .. decimal .. '" provided for ' .. direction .. ' is not valid', 2)
error('The value "' .. decimal .. '" provided for ' .. direction .. ' is not valid', 2)
elseif seconds and not minutes then
error('Seconds were provided for ' .. direction .. ' without minutes also being provided', 2)
elseif not degrees then
if minutes then
error('Minutes were provided for ' .. direction .. ' without degrees also being provided', 2)
elseif hemisphere then
error('A hemisphere was provided for ' .. direction .. ' without degrees also being provided', 2)
end
return nil
end
end
decimal = tonumber(degrees)
decimal = tonumber(degrees)
if not decimal then
if not decimal then
error('The degree value "' .. degrees .. '" provided for ' .. direction .. ' is not valid', 2)
error('The degree value "' .. degrees .. '" provided for ' .. direction .. ' is not valid', 2)
end
elseif minutes and not tonumber(minutes) then
if minutes and not tonumber(minutes) then
error('The minute value "' .. minutes .. '" provided for ' .. direction .. ' is not valid', 2)
error('The minute value "' .. minutes .. '" provided for ' .. direction .. ' is not valid', 2)
end
elseif seconds and not tonumber(seconds) then
if seconds and not tonumber(seconds) then
error('The second value "' .. seconds .. '" provided for ' .. direction .. ' is not valid', 2)
error('The second value "' .. seconds .. '" provided for ' .. direction .. ' is not valid', 2)
end
end
91行目: 116行目:
end
end
return decimal
return decimal
end
-- effectively make removeBlanks false for caption and maplink, and true for everything else
-- if useWikidata is present but blank, convert it to false instead of nil
-- p.top, p.bottom, and their callers need to use this
function p.valueFunc(key, value)
if value then
value = mw.text.trim(value)
end
if value ~= '' or key == 'caption' or key == 'maplink' then
return value
elseif key == 'useWikidata' then
return false
end
end
local function getContainerImage(args, map)
if args.AlternativeMap then
return args.AlternativeMap
elseif args.relief and map('image1') ~= '' then
return map('image1')
else
return map('image')
end
end
end


function p.top(frame, args, map)
function p.top(frame, args, map)
if not args then
if not args then
args = getArgs(frame)
args = getArgs(frame, {frameOnly = true, valueFunc = p.valueFunc})
end
end
if not map then
if not map then
102行目: 151行目:
local width
local width
if not args.width then
if not args.width then
width = math.floor((args.default_width or 240) * (tonumber(map('defaultscale')) or 1) + 0.5)
width = round((args.default_width or 240) * (tonumber(map('defaultscale')) or 1))
elseif mw.ustring.sub(args.width, -2) == 'px' then
elseif mw.ustring.sub(args.width, -2) == 'px' then
width = mw.ustring.sub(args.width, 1, -3)
width = mw.ustring.sub(args.width, 1, -3)
109行目: 158行目:
end
end
local retval = args.float == 'center' and '<div class="center">' or ''
local retval = args.float == 'center' and '<div class="center">' or ''
if args.caption then
if args.caption and args.caption ~= '' then
retval = retval .. '<div class="thumb '
retval = retval .. '<div class="noviewer thumb '
if args.float == '"left"' or args.float == 'left' then
if args.float == '"left"' or args.float == 'left' then
retval = retval .. 'tleft'
retval = retval .. 'tleft'
138行目: 187行目:
retval = retval .. '"><div style="width:' .. width .. 'px;padding:0"><div style="position:relative;width:' .. width .. 'px">'
retval = retval .. '"><div style="width:' .. width .. 'px;padding:0"><div style="position:relative;width:' .. width .. 'px">'
end
end
local image
local image = getContainerImage(args, map)
if args.AlternativeMap then
retval = string.format(
image = args.AlternativeMap
'%s[[File:%s|%spx|%s%s]]',
elseif args.relief and map('image1') ~= '' then
retval,
image = map('image1')
image,
else
width,
image = map('image')
args.alt or ((args.label or mw.title.getCurrentTitle().text) .. 'の位置(' .. map('name')) .. '内)',
end
args.maplink and ('|link=' .. args.maplink) or ''
retval = retval .. '[[File:' .. image .. '|' .. width .. 'px|' .. (args.alt or ((args.label or mw.title.getCurrentTitle().text) .. 'の位置(' .. map('name')) .. '内)' ) .. ']]'
)
if args.overlay_image then
if args.overlay_image then
return retval .. '<div style="position:absolute;top:0;left:0">[[File:' .. args.overlay_image .. '|' .. width .. 'px|link=File:' .. image .. ']]</div>'
return retval .. '<div style="position:absolute;top:0;left:0">[[File:' .. args.overlay_image .. '|' .. width .. 'px]]</div>'
else
else
return retval
return retval
156行目: 205行目:
function p.bottom(frame, args, map)
function p.bottom(frame, args, map)
if not args then
if not args then
args = getArgs(frame)
args = getArgs(frame, {frameOnly = true, valueFunc = p.valueFunc})
end
end
if not map then
if not map then
map = p.getMapParams(args[1], frame)
map = p.getMapParams(args[1], frame)
end
end
local retval = '</div><div ' .. (args.caption and 'class="thumbcaption">' or 'style="font-size:90%;padding-top:3px">')
local retval = '</div>'
local caption = frame.args.caption or frame:getParent().args.caption
if caption and not args.caption_undefined then
if not args.caption then
retval = retval .. mw.text.trim(caption)
retval = retval .. '<div style="font-size:90%;padding-top:3px">'
.. ((args.label or mw.title.getCurrentTitle().text) .. ' (' .. map('name') .. ')')
.. '</div>'
elseif args.caption == ''  then
retval = retval .. '<div style="font-size:90%;padding-top:3px"></div>'
else
else
retval = retval .. (args.label or mw.title.getCurrentTitle().text) .. ' (' .. map('name') .. ')'
-- This is not the pipe trick. We're creating a link with no text on purpose, so that CSS can give us a nice image
retval = retval .. '<div class="thumbcaption"><div class="magnify">[[:File:' .. getContainerImage(args, map) .. '| ]]</div>' .. args.caption .. '</div>'
end
end
retval = retval .. '</div></div></div>'
 
if args.float == 'center' then
if args.switcherLabel then
retval = retval .. '</div>'
retval = retval .. '<span class="switcher-label" style="display:none">' .. args.switcherLabel .. '</span>'
elseif args.autoSwitcherLabel then
retval = retval .. '<span class="switcher-label" style="display:none">Show map of ' .. map('name') .. '</span>'
end
end
retval = retval .. '</div></div>'
if args.caption_undefined then
if args.caption_undefined then
mw.log('Removed parameter caption_undefined used.')
local parent = frame:getParent()
if parent then
mw.log('Parent is ' .. parent:getTitle())
end
mw.logObject(args, 'args')
retval = retval .. ''
retval = retval .. ''
end
if args.float == 'center' then
retval = retval .. '</div>'
end
end
return retval
return retval
end
end


function p.container(frame, args, map)
local function markOuterDiv(x, y, imageDiv, labelDiv)
if not args then
return mw.html.create('div')
args = getArgs(frame)
:cssText('position:absolute;z-index:1;top:' .. round(y, 3) .. '%;left:' .. round(x, 3) .. '%;height:0;width:0;margin:0;padding:0')
end
:node(imageDiv)
if not map then
:node(labelDiv)
map = p.getMapParams(args[1], frame)
end
return p.top(frame, args, map) .. (args.places or '') .. p.bottom(frame, args, map)
end
 
local function markOuterDiv(x, y, content)
return '<div style="position:absolute;z-index:1;top:' .. y .. '%;left:' .. x .. '%;height:0;width:0;margin:0;padding:0">' .. content .. '</div>'
end
end


local function markImageDiv(mark, marksize, label, link, alt, title)
local function markImageDiv(mark, marksize, label, link, alt, title)
local retval = '<div style="position:relative;text-align:center;left:-' .. math.floor(marksize / 2 + 0.5) .. 'px;top:-' .. math.floor(marksize / 2 + 0.5) .. 'px;width:' .. marksize .. 'px;font-size:' .. marksize .. 'px;line-height:0"' .. (title and (' title="' .. title .. '">') or '>')
local builder = mw.html.create('div')
:cssText('position:absolute;text-align:center;left:-' .. round(marksize / 2) .. 'px;top:-' .. round(marksize / 2) .. 'px;width:' .. marksize .. 'px;font-size:' .. marksize .. 'px;line-height:0')
:attr('title', title)
if marksize ~= 0 then
if marksize ~= 0 then
retval = retval .. '[[File:' .. mark .. '|' .. marksize .. 'x' .. marksize .. 'px|' .. label .. '|link=' .. link
builder:wikitext(string.format(
if alt then
'[[File:%s|%dx%dpx|%s|link=%s%s]]',
retval = retval .. '|alt=' .. alt
mark,
end
marksize,
retval = retval .. ']]'
marksize,
label,
link,
alt and ('|alt=' .. alt) or ''
))
end
end
return retval .. '</div>'
return builder
end
end


local function markLabelDiv(label, label_size, label_width, position, background, x)
local function markLabelDiv(label, label_size, label_width, position, background, x, marksize)
local retval = '<div style="font-size:' .. label_size .. '%;line-height:110%;position:relative;top:-1.5em;width:' .. label_width .. 'em;'
local builder = mw.html.create('div')
:cssText('font-size:' .. label_size .. '%;line-height:110%;position:absolute;width:' .. label_width .. 'em')
local distance = round(marksize / 2 + 1)
local spanCss
if position == 'top' then -- specified top
if position == 'top' then -- specified top
retval = retval .. 'top:-2.65em;left:-3em;text-align:center'
builder:cssText('bottom:' .. distance .. 'px;left:' .. (-label_width / 2) .. 'em;text-align:center')
elseif position == 'bottom' then -- specified bottom
elseif position == 'bottom' then -- specified bottom
retval = retval .. 'top:-0.15em;left:-3em;text-align:center'
builder:cssText('top:' .. distance .. 'px;left:' .. (-label_width / 2) .. 'em;text-align:center')
elseif position == 'left' or (tonumber(x) > 70 and position ~= 'right') then -- specified left or autodetected to left
elseif position == 'left' or (tonumber(x) > 70 and position ~= 'right') then -- specified left or autodetected to left
retval = retval .. 'left:-6.5em;text-align:right'
builder:cssText('top:-0.75em;right:' .. distance .. 'px;text-align:right')
spanCss = 'float:right'
else -- specified right or autodetected to right
else -- specified right or autodetected to right
retval = retval .. 'left:0.5em;text-align:left'
builder:cssText('top:-0.75em;left:' .. distance .. 'px;text-align:left')
spanCss = 'float:left'
end
end
retval = retval .. '"><span style="padding:1px'
builder = builder:tag('span')
:cssText('padding:1px')
:cssText(spanCss)
:wikitext(label)
if background then
if background then
retval = retval .. ';background-color:' .. background
builder:cssText('background-color:' .. background)
end
end
return retval .. '">' .. label .. '</span></div>'
return builder:done()
end
end


241行目: 315行目:
function p.mark(frame, args, map)
function p.mark(frame, args, map)
if not args then
if not args then
args = getArgs(frame)
args = getArgs(frame, {wrappers = 'Template:Location map~'})
end
end
if not map then
if not map then
249行目: 323行目:
longitude = decdeg(args.lon_deg, args.lon_min, args.lon_sec, args.lon_dir, args.long, 'longitude')
longitude = decdeg(args.lon_deg, args.lon_min, args.lon_sec, args.lon_dir, args.long, 'longitude')
latitude = decdeg(args.lat_deg, args.lat_min, args.lat_sec, args.lat_dir, args.lat, 'latitude')
latitude = decdeg(args.lat_deg, args.lat_min, args.lat_sec, args.lat_dir, args.lat, 'latitude')
local retval = ''
if not longitude and not latitude and args.useWikidata then
if args.skew or args.lon_shift or (map('skew') ~= '') or (map('lat_skew') ~= '') or (map('crosses180') ~= '') then
-- If they didn't provide either coordinate, try Wikidata. If they provided one but not the other, don't.
retval = retval .. ''
local entity = mw.wikibase.getEntity()
if entity and entity.claims and entity.claims.p625 and entity.claims.p625[0].mainsnak.snaktype == 'value' then
local value = entity.claims.p625[0].mainsnak.datavalue.value
longitude, latitude = value.longitude, value.latitude
end
end
if not longitude then
error('No value was provided for longitude')
end
if not latitude then
error('No value was provided for latitude')
end
local builder = mw.html.create()
if (not args.lon_deg) ~= (not args.lat_deg) then
builder:wikitext('')
elseif (not args.lon_min) ~= (not args.lat_min) then
builder:wikitext('')
elseif (not args.lon_sec) ~= (not args.lat_sec) then
builder:wikitext('')
elseif (not args.lon_dir) ~= (not args.lat_dir) then
builder:wikitext('')
elseif (not args.long) ~= (not args.lat) then
builder:wikitext('')
end
if args.skew or args.lon_shift or args.markhigh then
mw.log('Removed parameter used in invocation.')
local parent = frame:getParent()
if parent then
mw.log('Parent is ' .. parent:getTitle())
end
mw.logObject(args, 'args')
builder:wikitext('')
end
if map('skew') ~= '' or map('lat_skew') ~= '' or map('crosses180') ~= '' or map('type') ~= '' then
mw.log('Removed parameter used in map definition ' .. map())
builder:wikitext('')
end
end
if map('x') ~= '' then
if map('x') ~= '' then
x = frame:callParserFunction('#expr', map('x', { latitude, longitude }))
x = tonumber(mw.ext.ParserFunctions.expr(map('x', { latitude, longitude })))
else
else
x = getX(longitude, map('left'), map('right'))
x = tonumber(getX(longitude, map('left'), map('right')))
end
end
if map('y') ~= '' then
if map('y') ~= '' then
y = frame:callParserFunction('#expr', map('y', { latitude, longitude }))
y = tonumber(mw.ext.ParserFunctions.expr(map('y', { latitude, longitude })))
else
else
y = getY(latitude, map('top'), map('bottom'))
y = tonumber(getY(latitude, map('top'), map('bottom')))
end
if (x < 0 or x > 100 or y < 0 or y > 100) and not args.outside then
mw.log('Mark placed outside map boundaries without outside flag set. x = ' .. x .. ', y = ' .. y)
local parent = frame:getParent()
if parent then
mw.log('Parent is ' .. parent:getTitle())
end
mw.logObject(args, 'args')
builder:wikitext('')
end
end
local mark = args.mark or map('mark')
local mark = args.mark or map('mark')
267行目: 385行目:
mark = 'Red pog.svg'
mark = 'Red pog.svg'
end
end
local divContent = markImageDiv(mark, tonumber(args.marksize) or tonumber(map('marksize')) or 8, args.label or mw.title.getCurrentTitle().text, args.link or '', args.alt, args[2])
local marksize = tonumber(args.marksize) or tonumber(map('marksize')) or 8
local imageDiv = markImageDiv(mark, marksize, args.label or mw.title.getCurrentTitle().text, args.link or '', args.alt, args[2])
local labelDiv
if args.label and args.position ~= 'none' then
if args.label and args.position ~= 'none' then
divContent = divContent .. markLabelDiv(args.label, args.label_size or 90, args.label_width or 6, args.position, args.background, x)
labelDiv = markLabelDiv(args.label, args.label_size or 90, args.label_width or 6, args.position, args.background, x, marksize)
end
end
return retval .. markOuterDiv(x, y, divContent)
return builder:node(markOuterDiv(x, y, imageDiv, labelDiv))
end
end


function p.main(frame, args, map)
function p.main(frame, args, map)
if not args then
if not args then
args = getArgs(frame)
args = getArgs(frame, {wrappers = 'Template:Location map', valueFunc = p.valueFunc})
end
if not args[1] then
args[1] = 'World'
end
if not map then
map = p.getMapParams(args[1], frame)
end
return p.top(frame, args, map) .. p.mark(frame, args, map) .. p.bottom(frame, args, map)
end
 
local function manyMakeArgs(fullArgs, n)
if n == 1 then
return {
fullArgs[1],
lat = fullArgs.lat1 or fullArgs.lat,
long = fullArgs.long1 or fullArgs.long,
lat_deg = fullArgs.lat1_deg or fullArgs.lat_deg,
lat_min = fullArgs.lat1_min or fullArgs.lat_min,
lat_sec = fullArgs.lat1_sec or fullArgs.lat_sec,
lat_dir = fullArgs.lat1_dir or fullArgs.lat_dir,
lon_deg = fullArgs.lon1_deg or fullArgs.lon_deg,
lon_min = fullArgs.lon1_min or fullArgs.lon_min,
lon_sec = fullArgs.lon1_sec or fullArgs.lon_sec,
lon_dir = fullArgs.lon1_dir or fullArgs.lon_dir,
mark = fullArgs.mark1 or fullArgs.mark,
marksize = fullArgs.mark1size or fullArgs.marksize,
link = fullArgs.link1 or fullArgs.link,
label = fullArgs.label1 or fullArgs.label,
label_size = fullArgs.label1_size or fullArgs.label_size,
position = fullArgs.position1 or fullArgs.pos1 or fullArgs.position or fullArgs.pos,
background = fullArgs.background1 or fullArgs.bg1 or fullArgs.background or fullArgs.bg
}
else
return {
fullArgs[1],
lat = fullArgs['lat' .. n],
long = fullArgs['long' .. n],
lat_deg = fullArgs['lat' .. n .. '_deg'],
lat_min = fullArgs['lat' .. n .. '_min'],
lat_sec = fullArgs['lat' .. n .. '_sec'],
lat_dir = fullArgs['lat' .. n .. '_dir'],
lon_deg = fullArgs['lon' .. n .. '_deg'],
lon_min = fullArgs['lon' .. n .. '_min'],
lon_sec = fullArgs['lon' .. n .. '_sec'],
lon_dir = fullArgs['lon' .. n .. '_dir'],
mark = fullArgs['mark' .. n],
marksize = fullArgs['mark' .. n .. 'size'],
link = fullArgs['link' .. n],
label = fullArgs['label' .. n],
label_size = fullArgs['label' .. n .. '_size'],
position = fullArgs['position' .. n] or fullArgs['pos' .. n],
background = fullArgs['background' .. n] or fullArgs['bg' .. n]
}
end
end
 
function p.many(frame, args, map)
if not args then
args = getArgs(frame)
end
end
if not args[1] then
if args.useWikidata == nil then
args[1] = 'World'
args.useWikidata = true
end
end
if not map then
if not map then
map = p.getMapParams(args[1], frame)
if args[1] then
end
map = {}
local marks = {}
for mapname in string.gmatch(args[1], '[^#]+') do
local markhigh = args.markhigh
map[#map + 1] = p.getMapParams(mapname, frame)
for k, v in pairs(args) do -- @todo change to uargs once we have that
if v then
if string.sub(k, -4) == '_deg' then
k = string.sub(k, 1, -5)
end
if string.sub(k, 1, 3) == 'lat' then
k = tonumber(string.sub(k, 4))
if k then
table.insert(marks, k)
end
end
end
if #map == 1 then map = map[1] end
else
map = p.getMapParams('World', frame)
end
end
end
end
table.sort(marks)
if type(map) == 'table' then
if marks[1] ~= 1 and (args.lat or args.lat_deg) then
local outputs = {}
table.insert(marks, 1, 1)
args.autoSwitcherLabel = true
end
for k,v in ipairs(map) do
local body = ''
outputs[k] = p.main(frame, args, v)
for _, v in ipairs(marks) do
-- don't try to consolidate this into the above loop. ordering of elements from pairs() is unspecified
body = body .. p.mark(frame, manyMakeArgs(args, v), map)
if args['mark' .. v .. 'high'] then
markhigh = true
end
end
return '<div class="switcher-container">' .. table.concat(outputs) .. '</div>'
else
return p.top(frame, args, map) .. tostring( p.mark(frame, args, map) ) .. p.bottom(frame, args, map)
end
end
args.label = nil -- there is no global label
return p.top(frame, args, map) .. body .. p.bottom(frame, args, map) .. (markhigh and '' or '')
end
end


return p
return p
匿名利用者