Module:Infobox mapframe

From Bharatpedia, an open encyclopedia

Documentation for this module may be created at Module:Infobox mapframe/doc

local mf = require('Module:Mapframe')
local getArgs = require('Module:Arguments').getArgs
local yesno = require('Module:Yesno')
local infoboxImage = require('Module:InfoboxImage').InfoboxImage

-- Defaults
local DEFAULT_FRAME_WIDTH = "270"
local DEFAULT_FRAME_HEIGHT = "200"
local DEFAULT_ZOOM = 10
local DEFAULT_GEOMASK_STROKE_WIDTH = "1"
local DEFAULT_GEOMASK_STROKE_COLOR = "#777777"
local DEFAULT_GEOMASK_FILL = "#888888"
local DEFAULT_GEOMASK_FILL_OPACITY = "0.5"
local DEFAULT_SHAPE_STROKE_WIDTH = "3"
local DEFAULT_SHAPE_STROKE_COLOR = "#FF0000"
local DEFAULT_SHAPE_FILL = "#606060"
local DEFAULT_SHAPE_FILL_OPACITY = "0.5"
local DEFAULT_LINE_STROKE_WIDTH = "5"
local DEFAULT_LINE_STROKE_COLOR = "#FF0000"
local DEFAULT_MARKER_COLOR = "#5E74F3"

-- Trim whitespace from args, and remove empty args
function trimArgs(argsTable)
    local cleanArgs = {}
    for key, val in pairs(argsTable) do
        if type(val) == 'string' then
            val = val:match('^%s*(.-)%s*$')
            if val ~= '' then
                cleanArgs[key] = val
            end
        else
            cleanArgs[key] = val
        end
    end
    return cleanArgs
end

function shouldAutoRun(frame)
    -- Check if should be running
    local explicitlyOn = yesno(mw.text.trim(frame.getParent(frame).args.mapframe or "")) -- true of false or nil
    local onByDefault = (explicitlyOn == nil) and yesno(mw.text.trim(frame.args.onByDefault or ""), false) -- true or false
    return explicitlyOn or onByDefault
end

function argsFromAuto(frame)
    -- Get args from the frame (invoke call) and the parent (template call).
    -- Frame arguments are default values which are overridden by parent values
    -- when both are present
    local args = getArgs(frame, { parentFirst = true })

    -- Discard args not prefixed with "mapframe-", remove that prefix from those that remain
    local fixedArgs = {}
    for name, val in pairs(args) do
        local fixedName = string.match(name, "^mapframe%-(.+)$" )
        if fixedName then
            fixedArgs[fixedName] = val
        -- allow coord, coordinates, etc to be unprefixed
        elseif name == "coordinates" or name == "coord" or name == "coordinate" and not fixedArgs.coord then
            fixedArgs.coord = val
        -- allow id, qid to be unprefixed, map to id (if not already present)
        elseif name == "id" or name == "qid" and not fixedArgs.id then
            fixedArgs.id = val
        end
    end
    return fixedArgs
end

local p = {}

p.autocaption = function(frame)
    if not shouldAutoRun(frame) then return "" end
    local args = argsFromAuto(frame)
    if args.caption then
        return args.caption
    elseif args.switcher then 
        return ""
    end
    return ""
end

function parseCustomWikitext(customWikitext)
    -- infoboxImage will format an image if given wikitext containing an
    -- image, or else pass through the wikitext unmodified
    return infoboxImage({
        args = {
            image = customWikitext
        }
    })
end

p.auto = function(frame)
    if not shouldAutoRun(frame) then return "" end
    local args = argsFromAuto(frame)
    if args.custom then
        return frame:preprocess(parseCustomWikitext(args.custom))
    end
    local mapframe = p._main(args)
    return frame:preprocess(mapframe)
end

p.main = function(frame)
    local parent = frame.getParent(frame)
    local parentArgs = parent.args
    local mapframe = p._main(parentArgs)
    return frame:preprocess(mapframe)
end

function getZoom(value, unit)
    local length_km
    if unit == 'km' then
        length_km = tonumber(value)
    elseif unit == 'mi' then
        length_km = tonumber(value)*1.609344
    elseif unit == 'km2' then
        length_km = math.sqrt(tonumber(value))
    elseif unit == 'mi2' then
        length_km = math.sqrt(tonumber(value))*1.609344
    end
    -- max for zoom 2 is 6400km, for zoom 3 is 3200km, for zoom 4 is 1600km, etc
    local zoom = math.floor(8 - (math.log10(length_km) - 2)/(math.log10(2)))
    -- limit to values below 17
    zoom = math.min(17, zoom)
    -- take off 1 when calculated from area, to account for unusual shapes
    if unit == 'km2' or unit == 'mi2' then
        zoom = zoom - 1
    end
    -- minimum value is 1
    return math.max(1, zoom)
end

p._main = function(_config)
    -- `config` is the args passed to this module
    local config = trimArgs(_config)
    
    -- `args` is the arguments which will be passed to the mapframe module
    local args = {}

    -- Some defaults/overrides for infobox presentation
    args.display = "inline"
    args.frame = "yes"
    args.plain = "yes"
    args["frame-width"]  = config["frame-width"] or config.width or DEFAULT_FRAME_WIDTH
    args["frame-height"] = config["frame-height"] or config.height or DEFAULT_FRAME_HEIGHT
    args["frame-align"]  = "center"

    args["frame-coord"] = config["frame-coordinates"] or ""

    -- deprecated lat and long parameters
    args["frame-lat"]    = config["frame-lat"] or config["frame-latitude"] or ""
    args["frame-long"]   = config["frame-long"] or config["frame-longitude"] or ""

    -- Calculate zoom from length or area (converted to km or km2)
    if config.length_km then
        args.zoom = getZoom(config.length_km, 'km')
    elseif config.length_mi then
        args.zoom = getZoom(config.length_mi, 'mi')
    elseif config.area_km2 then
        args.zoom = getZoom(config.area_km2, 'km2')
    elseif config.area_mi2 then
        args.zoom = getZoom(config.area_mi2, 'mi2')
    else
        args.zoom = config.zoom or DEFAULT_ZOOM
    end

    local mapframe = mf._main(args)
    local tracking = ''
    return mapframe .. tracking
end

return p