Module:Location map

Dokumentasie vir hierdie module kan geskep word by: Module:Location map/doc

require('strict')local p = {}local getArgs = require('Module:Arguments').getArgslocal function round(n, decimals)local pow = 10^(decimals or 0)return math.floor(n * pow + 0.5) / powendfunction p.getMapParams(map, frame)if not map thenerror('The name of the location map definition to use must be specified', 2)endlocal moduletitle = mw.title.new('Module:Location map/data/' .. map)if not moduletitle thenerror(string.format('%q is not a valid name for a location map definition', map), 2)elseif moduletitle.exists thenlocal mapData = mw.loadData('Module:Location map/data/' .. map)return function(name, params)if name == nil thenreturn 'Module:Location map/data/' .. mapelseif mapData[name] == nil thenreturn ''elseif params thenreturn mw.message.newRawMessage(tostring(mapData[name]), unpack(params)):plain()elsereturn mapData[name]endendelseerror('Unable to find the specified location map definition: "Module:Location map/data/' .. map .. '" does not exist', 2)endendfunction p.data(frame, args, map)if not args thenargs = getArgs(frame, {frameOnly = true})endif not map thenmap = p.getMapParams(args[1], frame)endlocal params = {}for k,v in ipairs(args) doif k > 2 thenparams[k-2] = vendendreturn map(args[2], #params ~= 0 and params)endlocal hemisphereMultipliers = {longitude = { W = -1, w = -1, O = 1, o = 1, E = 1, e = 1 },latitude = { S = -1, s = -1, N = 1, n = 1 }}local function decdeg(degrees, minutes, seconds, hemisphere, decimal, direction)if decimal thenif degrees thenerror('Decimal and DMS degrees cannot both be provided for ' .. direction, 2)elseif minutes thenerror('Minutes can only be provided with DMS degrees for ' .. direction, 2)elseif seconds thenerror('Seconds can only be provided with DMS degrees for ' .. direction, 2)elseif hemisphere thenerror('A hemisphere can only be provided with DMS degrees for ' .. direction, 2)endlocal retval = tonumber(decimal)if retval thenreturn retvalenderror('The value "' .. decimal .. '" provided for ' .. direction .. ' is not valid', 2)elseif seconds and not minutes thenerror('Seconds were provided for ' .. direction .. ' without minutes also being provided', 2)elseif not degrees thenif minutes thenerror('Minutes were provided for ' .. direction .. ' without degrees also being provided', 2)elseif hemisphere thenerror('A hemisphere was provided for ' .. direction .. ' without degrees also being provided', 2)endreturn nilenddecimal = tonumber(degrees)if not decimal thenerror('The degree value "' .. degrees .. '" provided for ' .. direction .. ' is not valid', 2)elseif minutes and not tonumber(minutes) thenerror('The minute value "' .. minutes .. '" provided for ' .. direction .. ' is not valid', 2)elseif seconds and not tonumber(seconds) thenerror('The second value "' .. seconds .. '" provided for ' .. direction .. ' is not valid', 2)enddecimal = decimal + (minutes or 0)/60 + (seconds or 0)/3600if hemisphere thenlocal multiplier = hemisphereMultipliers[direction][hemisphere]if not multiplier thenerror('The hemisphere "' .. hemisphere .. '" provided for ' .. direction .. ' is not valid', 2)enddecimal = decimal * multiplierendreturn decimalend-- Finds a parameter in a transclusion of {{Coord}}.local function coord2text(para,coord) -- this should be changed for languages which do not use Arabic numerals or the degree signlocal result = mw.text.split(mw.ustring.match(coord,'%-?[%.%d]+°[NS] %-?[%.%d]+°[OW]') or '', '[ °]')if para == 'longitude' then result = {result[3], result[4]} endif not tonumber(result[1]) or not result[2] then return error('Malformed coordinates value', 2) endreturn tonumber(result[1]) * hemisphereMultipliers[para][result[2]]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 thisfunction p.valueFunc(key, value)if value thenvalue = mw.text.trim(value)endif value ~= '' or key == 'caption' or key == 'maplink' thenreturn valueelseif key == 'useWikidata' thenreturn falseendendlocal function getContainerImage(args, map)if args.AlternativeMap thenreturn args.AlternativeMapelseif args.relief and map('image1') ~= '' thenreturn map('image1')elsereturn map('image')endendfunction p.top(frame, args, map)if not args thenargs = getArgs(frame, {frameOnly = true, valueFunc = p.valueFunc})endif not map thenmap = p.getMapParams(args[1], frame)endlocal widthlocal default_as_number = tonumber(mw.ustring.match(tostring(args.default_width),"%d*"))if not args.width thenwidth = round((default_as_number or 240) * (tonumber(map('defaultscale')) or 1))elseif mw.ustring.sub(args.width, -2) == 'px' thenwidth = mw.ustring.sub(args.width, 1, -3)elsewidth = args.widthendlocal width_as_number = tonumber(mw.ustring.match(tostring(width),"%d*")) or 0;    if width_as_number == 0 then    -- check to see if width is junk. If it is, then use default calculation    width = round((default_as_number or 240) * (tonumber(map('defaultscale')) or 1))    width_as_number = tonumber(mw.ustring.match(tostring(width),"%d*")) or 0;    end    if args.max_width ~= "" and args.max_width ~= nil then        -- check to see if width bigger than max_width        local max_as_number = tonumber(mw.ustring.match(args.max_width,"%d*")) or 0;        if width_as_number>max_as_number and max_as_number>0 then            width = args.max_width;        end    endlocal retval = frame:extensionTag{name = 'templatestyles', args = {src = 'Sjabloon:Location map/styles.css'}}if args.float == 'center' thenretval = retval .. '<div class="center">'endif args.caption and args.caption ~= '' and args.border ~= 'infobox' thenretval = retval .. '<div class="locmap noviewer thumb 'if args.float == '"left"' or args.float == 'left' thenretval = retval .. 'tleft'elseif args.float == '"center"' or args.float == 'center' or args.float == '"none"' or args.float == 'none' thenretval = retval .. 'tnone'elseretval = retval .. 'tright'endretval = retval .. '"><div class="thumbinner" style="width:' .. (width + 2) .. 'px'if args.border == 'none' thenretval = retval .. ';border:none'elseif args.border thenretval = retval .. ';border-color:' .. args.borderendretval = retval .. '"><div style="position:relative;width:' .. width .. 'px' .. (args.border ~= 'none' and ';border:1px solid lightgray">' or '">')elseretval = retval .. '<div class="locmap" style="width:' .. width .. 'px;'if args.float == '"left"' or args.float == 'left' thenretval = retval .. 'float:left;clear:left'elseif args.float == '"center"' or args.float == 'center' thenretval = retval .. 'float:none;clear:both;margin-left:auto;margin-right:auto'elseif args.float == '"none"' or args.float == 'none' thenretval = retval .. 'float:none;clear:none'elseretval = retval .. 'float:right;clear:right'endretval = retval .. '"><div style="width:' .. width .. 'px;padding:0"><div style="position:relative;width:' .. width .. 'px">'endlocal image = getContainerImage(args, map)local currentTitle = mw.title.getCurrentTitle()retval = string.format('%s[[File:%s|%spx|%s%s]]',retval,image,width,args.alt or ((args.label or currentTitle.text) .. ' is in ' .. map('name')),args.maplink and ('|link=' .. args.maplink) or '')if args.caption and args.caption ~= '' thenif (currentTitle.namespace == 0) and mw.ustring.find(args.caption, '##') thenretval = retval .. '[[Category:Pages using location map with a double number sign in the caption]]'endendif args.overlay_image thenreturn retval .. '<div style="position:absolute;top:0;left:0">[[File:' .. args.overlay_image .. '|' .. width .. 'px]]</div>'elsereturn retvalendendfunction p.bottom(frame, args, map)if not args thenargs = getArgs(frame, {frameOnly = true, valueFunc = p.valueFunc})endif not map thenmap = p.getMapParams(args[1], frame)endlocal retval = '</div>'local currentTitle = mw.title.getCurrentTitle()if not args.caption or args.border == 'infobox' thenif args.border thenretval = retval .. '<div style="padding-top:0.2em">'elseretval = retval .. '<div style="font-size:91%;padding-top:3px">'endretval = retval.. (args.caption or (args.label or currentTitle.text) .. ' (' .. map('name') .. ')').. '</div>'elseif args.caption ~= ''  then-- This is not the pipe trick. We're creating a link with no text on purpose, so that CSS can give us a nice imageretval = retval .. '<div class="thumbcaption"><div class="magnify">[[:File:' .. getContainerImage(args, map) .. '| ]]</div>' .. args.caption .. '</div>'endif args.switcherLabel thenretval = retval .. '<span class="switcher-label" style="display:none">' .. args.switcherLabel .. '</span>'elseif args.autoSwitcherLabel thenretval = retval .. '<span class="switcher-label" style="display:none">Wys kaart van ' .. map('name') .. '</span>'endretval = retval .. '</div></div>'if args.caption_undefined thenmw.log('Removed parameter caption_undefined used.')local parent = frame:getParent()if parent thenmw.log('Parent is ' .. parent:getTitle())endmw.logObject(args, 'args')if currentTitle.namespace == 0 then    retval = retval .. '[[Category:Location maps with removed parameters|caption_undefined]]'endendif map('skew') ~= '' or map('lat_skew') ~= '' or map('crosses180') ~= '' or map('type') ~= '' thenmw.log('Removed parameter used in map definition ' .. map())if currentTitle.namespace == 0 then    local key = (map('skew') ~= '' and 'skew' or '') ..(map('lat_skew') ~= '' and 'lat_skew' or '') ..(map('crosses180') ~= '' and 'crosses180' or '') ..(map('type') ~= '' and 'type' or '')    retval = retval .. '[[Category:Location maps with removed parameters|' .. key .. ' ]]'endendif string.find(map('name'), '|', 1, true) thenmw.log('Pipe used in name of map definition ' .. map())if currentTitle.namespace == 0 then   retval = retval .. '[[Category:Location maps with a name containing a pipe]]'endendif args.float == 'center' thenretval = retval .. '</div>'endreturn retvalendlocal function markOuterDiv(x, y, imageDiv, labelDiv)return mw.html.create('div'):addClass('od'):cssText('top:' .. round(y, 3) .. '%;left:' .. round(x, 3) .. '%'):node(imageDiv):node(labelDiv)endlocal function markImageDiv(mark, marksize, label, link, alt, title)local builder = mw.html.create('div'):addClass('id'):cssText('left:-' .. round(marksize / 2) .. 'px;top:-' .. round(marksize / 2) .. 'px'):attr('title', title)if marksize ~= 0 thenbuilder:wikitext(string.format('[[File:%s|%dx%dpx|%s|link=%s%s]]',mark,marksize,marksize,label,link,alt and ('|alt=' .. alt) or ''))endreturn builderendlocal function markLabelDiv(label, label_size, label_width, position, background, x, marksize)if tonumber(label_size) == 0 thenreturn mw.html.create('div'):addClass('l0'):wikitext(label)endlocal builder = mw.html.create('div'):cssText('font-size:' .. label_size .. '%;width:' .. label_width .. 'em')local distance = round(marksize / 2 + 1)if position == 'top' then -- specified topbuilder:addClass('pv'):cssText('bottom:' .. distance .. 'px;left:' .. (-label_width / 2) .. 'em')elseif position == 'bottom' then -- specified bottombuilder:addClass('pv'):cssText('top:' .. distance .. 'px;left:' .. (-label_width / 2) .. 'em')elseif position == 'left' or (tonumber(x) > 70 and position ~= 'right') then -- specified left or autodetected to leftbuilder:addClass('pl'):cssText('right:' .. distance .. 'px')else -- specified right or autodetected to rightbuilder:addClass('pr'):cssText('left:' .. distance .. 'px')endbuilder = builder:tag('div'):wikitext(label)if background thenbuilder:cssText('background-color:' .. background)endreturn builder:done()endlocal function getX(longitude, left, right)local width = (right - left) % 360if width == 0 thenwidth = 360endlocal distanceFromLeft = (longitude - left) % 360-- the distance needed past the map to the right equals distanceFromLeft - width. the distance needed past the map to the left equals 360 - distanceFromLeft. to minimize page stretching, go whichever way is shorterif distanceFromLeft - width / 2 >= 180 thendistanceFromLeft = distanceFromLeft - 360endreturn 100 * distanceFromLeft / widthendlocal function getY(latitude, top, bottom)return 100 * (top - latitude) / (top - bottom)endfunction p.mark(frame, args, map)if not args thenargs = getArgs(frame, {wrappers = 'Sjabloon:Location map~'})endlocal mapnames = {}if not map thenif args[1] thenmap = {}for mapname in mw.text.gsplit(args[1], '#', true) domap[#map + 1] = p.getMapParams(mw.ustring.gsub(mapname, '^%s*(.-)%s*$', '%1'), frame)mapnames[#mapnames + 1] = mapnameendif #map == 1 then map = map[1] endelsemap = p.getMapParams('World', frame)args[1] = 'World'endendif type(map) == 'table' thenlocal outputs = {}local oldargs = args[1]for k,v in ipairs(map) doargs[1] = mapnames[k]outputs[k] = tostring(p.mark(frame, args, v))endargs[1] = oldargsreturn table.concat(outputs, '#PlaceList#') .. '#PlaceList#'endlocal x, y, longitude, latitudelongitude = 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')if args.excludefrom then-- If this mark is to be excluded from certain maps entirely (useful in the context of multiple maps)for exclusionmap in mw.text.gsplit(args.excludefrom, '#', true) do-- Check if this map is excluded. If so, return an empty string.if args[1] == exclusionmap thenreturn ''endendendlocal builder = mw.html.create()local currentTitle = mw.title.getCurrentTitle()if args.coordinates then--Temporarily removed to facilitate infobox conversion. See [[Wikipedia:Coordinates in infoboxes]]--if longitude or latitude then--error('Coordinates from [[Module:Coordinates]] and individual coordinates cannot both be provided')--endlongitude = coord2text('longitude', args.coordinates)latitude = coord2text('latitude', args.coordinates)elseif not longitude and not latitude and args.useWikidata then-- If they didn't provide either coordinate, try Wikidata. If they provided one but not the other, don't.local entity = mw.wikibase.getEntity()if entity and entity.claims and entity.claims.P625 and entity.claims.P625[1].mainsnak.snaktype == 'value' thenlocal value = entity.claims.P625[1].mainsnak.datavalue.valuelongitude, latitude = value.longitude, value.latitudeendif args.link and (currentTitle.namespace == 0) thenbuilder:wikitext('[[Category:Location maps with linked markers with coordinates from Wikidata]]')endendif not longitude thenerror('No value was provided for longitude')elseif not latitude thenerror('No value was provided for latitude')endif currentTitle.namespace > 0 thenif (not args.lon_deg) ~= (not args.lat_deg) thenbuilder:wikitext('[[Category:Location maps with different longitude and latitude precisions|Degrees]]')elseif (not args.lon_min) ~= (not args.lat_min) thenbuilder:wikitext('[[Category:Location maps with different longitude and latitude precisions|Minutes]]')elseif (not args.lon_sec) ~= (not args.lat_sec) thenbuilder:wikitext('[[Category:Location maps with different longitude and latitude precisions|Seconds]]')elseif (not args.lon_dir) ~= (not args.lat_dir) thenbuilder:wikitext('[[Category:Location maps with different longitude and latitude precisions|Hemisphere]]')elseif (not args.long) ~= (not args.lat) thenbuilder:wikitext('[[Category:Location maps with different longitude and latitude precisions|Decimal]]')endendif args.skew or args.lon_shift or args.markhigh thenmw.log('Removed parameter used in invocation.')local parent = frame:getParent()if parent thenmw.log('Parent is ' .. parent:getTitle())endmw.logObject(args, 'args')if currentTitle.namespace == 0 thenlocal key = (args.skew and 'skew' or '') ..(args.lon_shift and 'lon_shift' or '') ..(args.markhigh and 'markhigh' or '')builder:wikitext('[[Category:Location maps with removed parameters|' .. key ..' ]]')endendif map('x') ~= '' thenx = tonumber(mw.ext.ParserFunctions.expr(map('x', { latitude, longitude })))elsex = tonumber(getX(longitude, map('left'), map('right')))endif map('y') ~= '' theny = tonumber(mw.ext.ParserFunctions.expr(map('y', { latitude, longitude })))elsey = tonumber(getY(latitude, map('top'), map('bottom')))endif (x < 0 or x > 100 or y < 0 or y > 100) and not args.outside thenmw.log('Mark placed outside map boundaries without outside flag set. x = ' .. x .. ', y = ' .. y)local parent = frame:getParent()if parent thenmw.log('Parent is ' .. parent:getTitle())endmw.logObject(args, 'args')if currentTitle.namespace == 0 thenlocal key = currentTitle.prefixedTextbuilder:wikitext('[[Category:Location maps with marks outside map and outside parameter not set|' .. key .. ' ]]')endendlocal mark = args.mark or map('mark')if mark == '' thenmark = 'Red pog.svg'endlocal marksize = tonumber(args.marksize) or tonumber(map('marksize')) or 8local imageDiv = markImageDiv(mark, marksize, args.label or mw.title.getCurrentTitle().text, args.link or '', args.alt, args[2])local labelDivif args.label and args.position ~= 'none' thenlabelDiv = markLabelDiv(args.label, args.label_size or 91, args.label_width or 6, args.position, args.background, x, marksize)endreturn builder:node(markOuterDiv(x, y, imageDiv, labelDiv))endlocal function switcherSeparate(s)if s == nil then return {} endlocal retval = {}for i in string.gmatch(s .. '#', '([^#]*)#') doi = mw.text.trim(i)retval[#retval + 1] = (i ~= '' and i)endreturn retvalendfunction p.main(frame, args, map)local caption_list = {}if not args thenargs = getArgs(frame, {wrappers = 'Sjabloon:Location map', valueFunc = p.valueFunc})end-- Vertaal Afrikaans parametersif next(args) ~= nil and args.position ~= 'none' then args.position = args.position:gsub('links', 'left'):gsub('regs', 'right'):gsub('bokant', 'top') endif args.useWikidata == nil thenargs.useWikidata = trueendif not map thenif args[1] thenmap = {}for mapname in string.gmatch(args[1], '[^#]+') domap[#map + 1] = p.getMapParams(mw.ustring.gsub(mapname, '^%s*(.-)%s*$', '%1'), frame)endif args['caption'] thenif args['caption'] == "" thenwhile #caption_list < #map docaption_list[#caption_list + 1] = args['caption']endelsefor caption in mw.text.gsplit(args['caption'], '##', true) docaption_list[#caption_list + 1] = captionendendendif #map == 1 then map = map[1] endelsemap = p.getMapParams('World', frame)endendif type(map) == 'table' thenlocal altmaps = switcherSeparate(args.AlternativeMap)if #altmaps > #map thenerror(string.format('%d AlternativeMaps were provided, but only %d maps were provided', #altmaps, #map))endlocal overlays = switcherSeparate(args.overlay_image)if #overlays > #map thenerror(string.format('%d overlay_images were provided, but only %d maps were provided', #overlays, #map))endif #caption_list > #map thenerror(string.format('%d captions were provided, but only %d maps were provided', #caption_list, #map))endlocal outputs = {}args.autoSwitcherLabel = truefor k,v in ipairs(map) doargs.AlternativeMap = altmaps[k]args.overlay_image = overlays[k]args.caption = caption_list[k]outputs[k] = p.main(frame, args, v)endreturn '<div class="switcher-container">' .. table.concat(outputs) .. '</div>'elsereturn p.top(frame, args, map) .. tostring( p.mark(frame, args, map) ) .. p.bottom(frame, args, map)endendreturn p