Module:Sandbox/Razimantv/Location map explained

require('strict') local p = local getArgs = require('Module:Arguments').getArgs function p.getMapParams(map, frame) mw.log('test') error('The name of the location map definition to use must be specified', 2) if not map then error('The name of the location map definition to use must be specified', 2) end local moduletitle = mw.title.new('Module:Location map/data/' .. map) if not moduletitle then error('"' .. map .. '" is not a valid name for a location map definition', 2) elseif moduletitle.exists then local mapData = mw.loadData('Module:Location map/data/' .. map) return function(name, params) if mapData[name]

nil then return elseif params then return mw.message.newRawMessage(tostring(mapData[name]), unpack(params)):plain else return mapData[name] end end elseif mw.title.new('Template:Location map ' .. map).exists then local cache = return function(name, params) if params then return frame:expandTemplate else if cache[name]

nil then cache[name] = frame:expandTemplate end return cache[name] end end else error('Unable to find the specified location map definition. Neither "Module:Location map/data/' .. map .. '" nor "Template:Location map ' .. map .. '" exists', 2) endend function p.data(frame, args, map) if not args then args = getArgs(frame,) end if not map then map = p.getMapParams(args[1], frame) end local params = for k,v in ipairs(args) do if k > 2 then params[k-2] = v end end return map(args[2], #params ~= 0 and params)end local hemisphereMultipliers = local function decdeg(degrees, minutes, seconds, hemisphere, decimal, direction) if not degrees then if not decimal then error('No value was provided for ' .. direction, 2) end local retval = tonumber(decimal) if retval then return retval end error('The value "' .. decimal .. '" provided for ' .. direction .. ' is not valid', 2) end decimal = tonumber(degrees) if not decimal then error('The degree value "' .. degrees .. '" provided for ' .. direction .. ' is not valid', 2) end if minutes and not tonumber(minutes) then error('The minute value "' .. minutes .. '" provided for ' .. direction .. ' is not valid', 2) end if seconds and not tonumber(seconds) then error('The second value "' .. seconds .. '" provided for ' .. direction .. ' is not valid', 2) end decimal = decimal + (minutes or 0)/60 + (seconds or 0)/3600 if hemisphere then local multiplier = hemisphereMultipliers[direction][hemisphere] if not multiplier then error('The hemisphere "' .. hemisphere .. '" provided for ' .. direction .. ' is not valid', 2) end decimal = decimal * multiplier end return decimalend -- effectively make removeBlanks false for caption and maplink, and true for everything else-- p.top, p.bottom, and their callers need to use thislocal function valueFunc(key, value) if value then value = mw.text.trim(value) end if value ~= or key

'caption' or key

'maplink' then return value endend 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') endend function p.top(frame, args, map) if not args then args = getArgs(frame,) end if not map then map = p.getMapParams(args[1], frame) end local width if not args.width then width = math.floor((args.default_width or 240) * (tonumber(map('defaultscale')) or 1) + 0.5) elseif mw.ustring.sub(args.width, -2)

'px' then width = mw.ustring.sub(args.width, 1, -3) else width = args.width end local retval = args.float

'center' and '

' or if args.caption and args.caption ~= then retval = retval .. '

' or '">') else retval = retval .. '

' end local image = getContainerImage(args, map) retval = string.format('%s', retval, image, width, args.alt or ((args.label or mw.title.getCurrentTitle.text) .. ' is located in ' .. map('name')), args.maplink and ('|link=' .. args.maplink) or ) if args.overlay_image then return retval .. '

' else return retval endend function p.bottom(frame, args, map) if not args then args = getArgs(frame,) end if not map then map = p.getMapParams(args[1], frame) end local retval = '

' if not args.caption then retval = retval .. '

' .. ((args.label or mw.title.getCurrentTitle.text) .. ' (' .. map('name') .. ')') .. '

' elseif args.caption

then retval = retval .. '

' else retval = retval .. '

' .. args.caption .. '

' end retval = retval .. '

' 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 .. '' end if args.float

'center' then retval = retval .. '

' end return retvalend function p.container(frame, args, map) if not args then args = getArgs(frame,) end if not map then 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, imageDiv, labelDiv) return mw.html.create('div') :cssText('position:absolute;top:' .. y .. '%;left:' .. x .. '%;height:0;width:0;margin:0;padding:0') :node(imageDiv) :node(labelDiv)end local function markImageDiv(mark, marksize, label, link, alt, title) local builder = mw.html.create('div') :cssText('position:absolute;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') :attr('title', title) if marksize ~= 0 then builder:wikitext(string.format('', mark, marksize, marksize, label, link, alt and ('|alt=' .. alt) or )) end return builderend local function markLabelDiv(label, label_size, label_width, position, background, x, marksize) local builder = mw.html.create('div') :cssText('font-size:' .. label_size .. '%;line-height:110%;position:absolute;width:' .. label_width .. 'em') local distance = math.floor(marksize / 2 + 1.5) local spanCss if position

'top' then -- specified top builder:cssText('bottom:' .. distance .. 'px;left:' .. (-label_width / 2) .. 'em;text-align:center') elseif position

'bottom' then -- specified bottom 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 builder:cssText('top:-0.75em;right:' .. distance .. 'px;text-align:right') spanCss = 'float:right' else -- specified right or autodetected to right builder:cssText('top:-0.75em;left:' .. distance .. 'px;text-align:left') spanCss = 'float:left' end builder = builder:tag('span') :cssText('padding:1px') :cssText(spanCss) :wikitext(label) if background then builder:cssText('background-color:' .. background) end return builder:doneend local function getX(longitude, left, right) local width = (right - left) % 360 if width

0 then width = 360 end local 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 shorter if distanceFromLeft - width / 2 >= 180 then distanceFromLeft = distanceFromLeft - 360 end return 100 * distanceFromLeft / widthend local function getY(latitude, top, bottom) return 100 * (top - latitude) / (top - bottom)end function p.mark(frame, args, map) if not args then args = getArgs(frame,) end if not map then map = p.getMapParams(args[1], frame) end local x, y, longitude, latitude 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') local builder = mw.html.create 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') ~= ) then mw.log('Removed parameter used in map definition. Map definition name is ' .. args[1]) builder:wikitext('') end if map('x') ~= then x = tonumber(mw.ext.ParserFunctions.expr(map('x',))) else x = tonumber(getX(longitude, map('left'), map('right'))) end if map('y') ~= then y = tonumber(mw.ext.ParserFunctions.expr(map('y',))) else 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 local mark = args.mark or map('mark') if mark

then mark = 'Red pog.svg' end 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 labelDiv = markLabelDiv(args.label, args.label_size or 90, args.label_width or 6, args.position, args.background, x, marksize) end return builder:node(markOuterDiv(x, y, imageDiv, labelDiv))end function p.main(frame, args, map) if not args then args = getArgs(frame,) 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) .. tostring(p.mark(frame, args, map)) .. p.bottom(frame, args, map)end local function manyMakeArgs(fullArgs, n) if n

1 then return else return endend function p.many(frame, args, map) if not args then args = getArgs(frame,) end if not args[1] then args[1] = 'World' end if not map then map = p.getMapParams(args[1], frame) end local marks = local markhigh if args.markhigh then mw.log('Removed parameter markhigh used.') local parent = frame:getParent if parent then mw.log('Parent is ' .. parent:getTitle) end mw.logObject(args, 'args') markhigh = true end 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 end table.sort(marks) if marks[1] ~= 1 and (args.lat or args.lat_deg) then table.insert(marks, 1, 1) end local body = 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 .. tostring(p.mark(frame, manyMakeArgs(args, v), map)) if args['mark' .. v .. 'high'] then mw.log('Removed parameter mark' .. v .. 'high used.') local parent = frame:getParent if parent then mw.log('Parent is ' .. parent:getTitle) end mw.logObject(args, 'args') markhigh = true 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 return p