모듈:Mapframe: 두 판 사이의 차이

내용 삭제됨 내용 추가됨
잔글편집 요약 없음
update
8번째 줄:
 
-- Modue dependencies
local transcluder = require("Module:Transcluder") -- local copy of https://www.mediawiki.org/wiki/Module:Transcluder loaded lazily
-- "Module:No globals" should not be used, at least until all other modules which require this module are not using globals.
 
43번째 줄:
frameWidth = "frame-width",
frameHeight = "frame-height",
frameCoordinates = { "frame-coordinates", "frame-coord" },
frameLatitude = { "frame-lat", "frame-latitude" },
frameLongitude = { "frame-long", "frame-longitude" },
frameAlign = "frame-align",
switch = "switch",
overlay = "overlay",
overlayBorder = "overlay-border",
overlayHorizontalAlignment = "overlay-horizontal-alignment",
overlayVerticalAlignment = "overlay-vertical-alignment",
overlayHorizontalOffset = "overlay-horizontal-offset",
overlayVerticalOffset = "overlay-vertical-offset"
}
 
-- Names of other templates this module dependscan onextract coordinates from
L10n.template = {
coord = { -- The coord template, as well as templates with output that contains {{coord}}
Coord = "좌표" -- lowercase template name
"Coord", "Coord/sandbox",
"NRHP row", "NRHP row/sandbox",
"WikidataCoord", "WikidataCoord/sandbox", "Wikidatacoord", "Wikidata coord"
}
}
 
줄 68 ⟶ 78:
noSwitchLists = "At least one parameter must have a SWITCH: list",
switchMismatches = "All SWITCH: lists must have the same number of values",
 
-- "%s" and "%d" tokens will be replaced with strings and numbers when used
oneSwitchValue = "Found only one switch value in |%s=",
줄 78 ⟶ 88:
L10n.str = {
-- valid values for display parameter, e.g. (|display=inline) or (|display=title) or (|display=inline,title) or (|display=title,inline)
inline = "inline",
title = "title",
dsep = ",", -- separator between inline and title (comma in the example above)
 
줄 90 ⟶ 100:
circle = "circle", -- circular area around a point
named = "named", -- all named coordinates in an article or section
 
-- Keyword to indicate a switch list. Must NOT use the special characters ^$()%.[]*+-?
switch = "SWITCH",
 
-- valid values for icon, frame, and plain parameters
affirmedWords = ' '..table.concat({
줄 131 ⟶ 141:
frameWidth = "300",
frameHeight = "200",
frameAlign = "right",
markerColor = "5E74F3",
markerSize = nil,
strokeColor = "#ff0000",
strokeWidth = 6,
edges = 32, -- number of edges used to approximate a circle
overlayBorder = "1px solid white",
overlayHorizontalAlignment = "right",
overlayHorizontalOffset = "0",
overlayVerticalAlignment = "bottom",
overlayVerticalOffset = "0"
}
 
줄 149 ⟶ 165:
optionally a suffix, for parameters that can be suffixed (e.g. type2 is type
with suffix 2).
@param {table} args key-value pairs of parameter names and their values
@param {string} param_id id for parameter name (key from the L10n.para table)
@param {string} [suffix] suffix for parameter name
@returns {string|nil} parameter value if found, or nil if not found
]]--
function util.getParameterValue(args, param_id, suffix)
줄 165 ⟶ 181:
end
return nil
end
 
--[[
줄 180 ⟶ 196:
-- control characters inside json need to be escaped, but stripping them is simpler
-- See also T214984
-- However, *don't* strip control characters from wikitext or you'll break strip markers
cleanArgs[key] = val:gsub('%c',' ')
cleanArgs[key] = (not util.matchesParam('text', key)) and val:gsub('%c',' ') or val
end
else
줄 187 ⟶ 204:
end
return cleanArgs
end
 
--[[
Check if a parameter name matches an unlocalized parameter key
@param {string} key - the unlocalized parameter name to search through
@param {string} name - the localized parameter name to check
@param {string|nil} - an optional suffix to apply to the value(s) from the localization key
@returns {boolean} true if the name matches the parameter, false otherwise
]]--
function util.matchesParam(key, name, suffix)
local param = L10n.para[key]
suffix = suffix or ''
if type(param) == 'table' then
for _, v in pairs(param) do
if (v .. suffix) == name then return true end
end
return false
end
return ((param .. suffix) == name)
end
 
줄 207 ⟶ 243:
if not(val) then return false end
return string.find(L10n.str.declinedWords , ' '..val..' ', 1, true ) and true or false
end
 
--[[
Check if the name of a template matches the known coord templates or wrappers
(in L10n.template.coord). The name is normalised when checked, so e.g. the names
"Coord", "coord", and " Coord" all return true.
@param {string} name
@returns {boolean} true if it is a coord template or wrapper, false otherwise
]]--
function util.isCoordTemplateOrWrapper(name)
name = mw.text.trim(name)
local inputTitle = mw.title.new(name, 'Template')
if not inputTitle then
return false
end
 
-- Create (or reuse) mw.title objects for each known coord template/wrapper.
-- Stored in L10n.template.title so that they don't need to be recreated
-- each time this function is called
if not L10n.template.titles then
L10n.template.titles = {}
for _, v in pairs(L10n.template.coord) do
table.insert(L10n.template.titles, mw.title.new(v, 'Template'))
end
end
 
for _, templateTitle in pairs(L10n.template.titles) do
if mw.title.equals(inputTitle, templateTitle) then
return true
end
end
 
return false
end
 
줄 219 ⟶ 288:
local subtemplates = {}
for template in templates do
local nametemplateName = mw.ustring.match(template, '{{([^}|]+)') -- get the template name
local nameParam = mw.ustring.match(template, "|%s*name%s*=%s*[^}|]+")
if util.isCoordTemplateOrWrapper(templateName) then
if mw.ustring.lower(mw.text.trim(name)) == L10n.template.Coord then
if nameParam then table.insert(output, template) end
elseif mw.ustring.find(mw.ustring.sub(template, L10n.template.Coord2), "{{") then
local subOutput = util.extractCoordTemplates(mw.ustring.sub(template, 2))
for _, t in pairs(subOutput) do
줄 250 ⟶ 319:
]]--
function util.getNamedCoords(page)
if transcluder == nil then
-- load [[Module:Transcluder]] lazily so it is only transcluded on pages that
-- actually use named coordinates
transcluder = require("Module:Transcluder")
end
local parts = mw.text.split(page or "", "#", true)
local name = parts[1] == "" and mw.title.getCurrentTitle().prefixedText or parts[1]
줄 264 ⟶ 338:
local coord = mw.ustring.match(expandedTemplate, "<span class=\"geo%-dec\".->(.-)</span>")
if coord then
local name = (
local name = mw.ustring.match(expandedTemplate, "<span class=\"fn org\">(.-)</span>") or coord
-- name specified by a wrapper template, e.g [[Article|Name]]
mw.ustring.match(expandedTemplate, "<span class=\"mapframe%-coord%-name\">(.-)</span>") or
-- name passed into coord template
mw.ustring.match(expandedTemplate, "<span class=\"fn org\">(.-)</span>") or
-- default to the coordinates if the name can't be retrieved
coord
)
local description = name ~= coord and coord
local coord = mw.ustring.gsub(coord, "[° ]", "_")
줄 278 ⟶ 359:
//tools.wmflabs.org/geohack/geohack.php?pagename=Example&params=1_2_N_3_4_W_ or
//tools.wmflabs.org/geohack/geohack.php?pagename=Example&params=1.23_S_4.56_E_ )
or non-url string in the same format (such as `1_2_N_3_4_W_` or `1.23_S_4.56_E_`)
@param {string} coords
@param {string} coords string containing coordinates
@returns {number, number} latitude, longitude
]]--
function util.parseCoords(coords)
local coordsPatt
local parts = mw.text.split((mw.ustring.match(coords,'[_%.%d]+[NS][_%.%d]+[EW]') or ''), '_')
if mw.ustring.find(coords, "params=", 1, true) then
-- prevent false matches from page name, e.g. ?pagename=Lorem_S._Ipsum
coordsPatt = 'params=([_%.%d]+[NS][_%.%d]+[EW])'
else
-- not actually a geohack url, just the same format
coordsPatt = '[_%.%d]+[NS][_%.%d]+[EW]'
end
local parts = mw.text.split((mw.ustring.match(coords, coordsPatt) or ''), '_')
 
local lat_d = tonumber(parts[1])
줄 312 ⟶ 402:
]]--
function util.wikidataCoords(item_id)
if not (item_id and mw.wikibase.isValidEntityId(item_id)) orand not(mw.wikibase.entityExists(item_id)) then
error(L10n.error.noCoords, 0)
end
줄 319 ⟶ 409:
error(L10n.error.wikidataCoords, 0)
end
local hasNoValue = ( coordStatements[1].mainsnak and (coordStatements[1].mainsnak.snaktype == 'novalue' or coordStatements[1].mainsnak.snaktype == 'somevalue') )
if hasNoValue then
error(L10n.error.wikidataCoords, 0)
줄 338 ⟶ 428:
function util.circleToPolygon(lat, long, radius, n) -- n is number of edges
-- Based on https://github.com/gabzim/circle-to-polygon, ISC licence
 
local function offset(cLat, cLon, distance, bearing)
local lat1 = math.rad(cLat)
줄 353 ⟶ 443:
return {math.deg(lon), math.deg(lat)}
end
 
local coordinates = {};
local i = 0;
줄 440 ⟶ 530:
local argsExpanded = {}
for k, v in pairs(args) do
local index = string.match( k, '^[^0-9]+([0-9]*)$' )
if index ~= nil then
local indexNumber = ''
if index ~= '' then
indexNumber = tonumber(index)
else
indexNumber = 1
end
 
if argsExpanded[indexNumber] == nil then
argsExpanded[indexNumber] = {}
end
argsExpanded[indexNumber][ string.gsub(k, index, '') ] = v
end
end
 
for contentIndex, contentArgs in pairs(argsExpanded) do
local argType = util.getParameterValue(contentArgs, "type")
줄 479 ⟶ 569:
end
end
 
--Single item, no array needed
if #content==1 then return content[1] end
줄 498 ⟶ 588:
for GeoJSON when encoded)
]]--
function make.coords(args, plainOutput)
local coords, lat, long
local frame = mw.getCurrentFrame()
줄 583 ⟶ 673:
end
else -- is a point
data.properties["marker-symbol"]local markerSymbol = util.getParameterValue(contentArgs, 'marker') or L10n.defaults.marker
-- allow blank to be explicitly specified, for overriding infoboxes or other templates with a default value
if markerSymbol ~= "blank" then
data.properties["marker-symbol"] = markerSymbol
end
data.properties["marker-color"] = util.getParameterValue(contentArgs, 'markerColor') or L10n.defaults.markerColor
data.properties["marker-size"] = util.getParameterValue(contentArgs, 'markerSize') or L10n.defaults.markerSize
줄 602 ⟶ 696:
if util.getParameterValue(contentArgs, 'id') or (not (util.getParameterValue(contentArgs, 'from')) and mw.wikibase.getEntityIdForCurrentPage()) then
data.ids = util.getParameterValue(contentArgs, 'id') or mw.wikibase.getEntityIdForCurrentPage()
else
data.title = util.getParameterValue(contentArgs, 'from')
end
줄 637 ⟶ 731:
@param {boolean} [isTitle] Tag is to be displayed in the title of page rather
than inline
@returns {table<string,string>} key-value pairs of attribute names and values
]]--
function make.tagAttribs(args, isTitle)
줄 653 ⟶ 747:
end
if util.isAffirmed(util.getParameterValue(args, 'frame')) and not(isTitle) then
attribs.width = tonumber(util.getParameterValue(args, 'frameWidth')) or L10n.defaults.frameWidth
attribs.height = tonumber(util.getParameterValue(args, 'frameHeight')) or L10n.defaults.frameHeight
if util.getParameterValue(args, 'frameCoordinates') then
local frameLat, frameLong = util.parseCoords(util.getParameterValue(args, 'frameCoordinates'))
줄 696 ⟶ 790:
]]--
function make.titleOutput(args, tagContent)
local titleTag = mw.text.tag('maplink', make.tagAttribs(args, true), tagContent)
local spanAttribs = {
style = "font-size: small;",
줄 734 ⟶ 828:
]]--
function make.switcherHtml(params, options)
ifoptions not= options then option =or {} end
local frame = mw.getCurrentFrame()
local styles = frame:extensionTag{
줄 784 ⟶ 878:
)
return styles .. tostring(outerCountainer)
end
 
--[[
Makes the HTML required for an overlay map to work
tag.
@param {string} overlayMap wikitext for the overlay map
@param {string} baseMap wikitext for the base map
@param {table} options various styling/display options
@param {string} options.align "left" or "center" or "right"
@param {string|number} options.width Width of the base map, e.g. "300"
@param {string|number} options.width Height of the base map, e.g. "200"
@param {string} options.border Border style for the overlayed map, e.g. "1px solid white"
@param {string} options.horizontalAlignment Horizontal alignment for overlay map, "left" or "right"
@param {string|number} options.horizontalOffset Horizontal offset in pixels from the alignment edge, e.g "10"
@param {string} options.verticalAlignment Vertical alignment for overlay map, "top" or "bottom"
@param {string|number} options.verticalOffset Vertical offset in pixels from the alignment edge, e.g. is "10"
@param {boolean} options.isThumbnail Display in a thumbnail
@param {string} [options.caption] Caption wikitext for thumnail
@retruns {string} HTML for basemap with overlay
]]--
function make.overlayHtml(overlayMap, baseMap, options)
options = options or {}
local containerFloatClass = "float"..(options.align or "none")
if options.align == "center" then
containerFloatClass = "center"
end
local containerStyle = {
position = "relative",
width = options.width .. "px",
height = options.height .. "px",
overflow = "hidden" -- mobile/minerva tends to add scrollbars for a couple of pixels
}
if options.align == "center" then
containerStyle["margin-left"] = "auto"
containerStyle["margin-right"] = "auto"
end
local container = mw.html.create("div")
:addClass("mapframe-withOverlay-container")
:addClass(containerFloatClass)
:addClass("noresize")
:css(containerStyle)
 
local overlayStyle = {
position = "absolute",
["z-index"] = "1",
border = options.border or "1px solid white"
}
if options.horizontalAlignment == "right" then
overlayStyle.right = options.horizontalOffset .. "px"
else
overlayStyle.left = options.horizontalOffset .. "px"
end
if options.verticalAlignment == "bottom" then
overlayStyle.bottom = options.verticalOffset .. "px"
else
overlayStyle.top = options.verticalOffset .. "px"
end
local overlayDiv = mw.html.create("div")
:css(overlayStyle)
:wikitext(overlayMap)
 
container
:node(overlayDiv)
:wikitext(baseMap)
 
if not options.isThumbnail then
return tostring(container)
end
local classlist = container:getAttr("class")
classlist = mw.ustring.gsub(classlist, "%a*"..options.align, "")
container:attr("class", classlist)
local outerCountainer = mw.html.create("div")
:addClass("mapframe-withOverlay-outerContainer")
:addClass("mw-kartographer-container")
:addClass("thumb")
if options.align == "left" or options.align == "right" then
outerCountainer:addClass("t"..options.align)
else -- alignment is "center"
outerCountainer
:addClass("tnone")
:addClass("center")
end
outerCountainer
:tag("div")
:addClass("thumbinner")
:css("width", options.width.."px")
:node(container)
:node(options.caption and mw.html.create("div")
:addClass("thumbcaption")
:wikitext(options.caption)
)
return tostring(outerCountainer)
 
end
 
줄 795 ⟶ 982:
function p.main(frame)
local parent = frame.getParent(frame)
-- Check for overlay option
local overlay = util.getParameterValue(parent.args, 'overlay')
local hasOverlay = overlay and mw.text.trim(overlay) ~= ""
-- Check for switch option
local switch = util.getParameterValue(parent.args, 'switch')
local isMulti = switch and mw.text.trim(switch) ~= ""
-- Create output by choosing method to suit options
local output = isMulti and p.multi(parent.args) or p._main(parent.args)
local output
if hasOverlay then
output = p.withOverlay(parent.args)
elseif isMulti then
output = p.multi(parent.args)
else
output = p._main(parent.args)
end
-- Preprocess output before returning it
return frame:preprocess(output)
end
줄 804 ⟶ 1,004:
function p._main(_args)
local args = util.trimArgs(_args)
 
local tagContent = make.content(args)
 
줄 831 ⟶ 1,031:
local switchLabels = util.tableFromList(switchParamValue)
if #switchLabels == 1 then error(L10n.error.oneSwitchLabel, 0) end
 
local mapframeArgs = {}
local switchParams = {}
줄 854 ⟶ 1,054:
end
local switchCount = util.subTablesCount(switchParams)
if not switchCount then
error(L10n.error.switchMismatches, 0)
elseif switchCount > #switchLabels then
error(string.format(L10n.error.fewerSwitchLabels, switchCount, #switchLabels), 0)
end
 
-- Ensure a plain frame will be used (thumbnail will be built by the
-- make.switcherHtml function if required, so that switcher options are
-- inside the thumnail)
mapframeArgs.plain = "yes"
 
local switcher = {}
for i = 1, switchCount do
줄 882 ⟶ 1,082:
caption = args.text
})
end
 
function p.withOverlay(_args)
-- Get and trim wikitext for overlay map
local overlayMap = _args.overlay
if type(overlayMap) == 'string' then
overlayMap = overlayMap:match('^%s*(.-)%s*$')
end
local isThumbnail = (util.getParameterValue(_args, "frame") and not util.getParameterValue(_args, "plain")) and true or false
-- Get base map using the _main function, as a plain map
local args = util.trimArgs(_args)
args.plain = "yes"
local basemap = p._main(args)
-- Extract overlay options from args
local overlayOptions = {
width = util.getParameterValue(args, "frameWidth") or L10n.defaults.frameWidth,
height = util.getParameterValue(args, "frameHeight") or L10n.defaults.frameHeight,
align = util.getParameterValue(args, "frameAlign") or L10n.defaults.frameAlign,
border = util.getParameterValue(args, "overlayBorder") or L10n.defaults.overlayBorder,
horizontalAlignment = util.getParameterValue(args, "overlayHorizontalAlignment") or L10n.defaults.overlayHorizontalAlignment,
horizontalOffset = util.getParameterValue(args, "overlayHorizontalOffset") or L10n.defaults.overlayHorizontalOffset,
verticalAlignment = util.getParameterValue(args, "overlayVerticalAlignment") or L10n.defaults.overlayVerticalAlignment,
verticalOffset = util.getParameterValue(args, "overlayVerticalOffset") or L10n.defaults.overlayVerticalOffset,
isThumbnail = isThumbnail,
caption = util.getParameterValue(args, "text") or L10n.defaults.text
}
-- Make the HTML for the overlaying maps
return make.overlayHtml(overlayMap, basemap, overlayOptions)
end