Module:Portal

From CasperTech Wiki
Jump to navigation Jump to search

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

-- This module implements {{Portal}}

local p = {}
 
local HtmlBuilder = require('Module:HtmlBuilder')
local HtmlError = require('Module:Error')

-- This function generates the html code.
local function _portal(args)

    local root = HtmlBuilder.create('div')
    
    root
        .addClass('noprint')
        .addClass((args.left == 'yes' and 'tleft') or 'tright')
        .addClass('portal')
        .css('border', 'solid #aaa 1px')
        .css('margin', args.margin or (args.left == 'yes' and '0.5em 1em 0.5em 0') or '0.5em 0 0.5em 1em')
        .newline()

    -- Start the table. This corresponds to the start of the wikitext table
    -- in the old [[Template:Portal]].
    local tableroot = root.tag('table')
        .css('background', '#f9f9f9')
        .css('font-size', '85%')
        .css('line-height', '110%')
        .css('max-width', '175px')
        .css('width', args.boxsize and (args.boxsize .. 'px'))
    
    -- If no portals have been specified, display an error and add the page to a tracking category.
    if not args[1] then
        tableroot.wikitext(
            tostring(HtmlError.error{'No portals specified: please specify at least one portal'})
            .. '[[Category:Portal templates without a parameter]]'
        )
    end

    -- Display the portals specified in the positional arguments.
    for i,v in ipairs(args) do
        v = mw.ustring.match(v, '^%s*(.*%S)') or ''  -- Trim whitespace.
        
        -- Portal image names are stored in subtemplates of [[Template:Portal/Images]].
        -- The name of the subtemplate is the portal name in all lower case, but with
        -- the first character in upper case.
        
        -- Work out the image subtemplate location.
        local lang = mw.getContentLanguage()
        local imagetemplatename = 'Portal/Images/' .. lang:ucfirst(lang:lc(v))

        -- Check the image template name. We need three checks: 1) check with pcall to see if
        -- we are over the expensive function call limit; 2) check if the proposed image template
        -- name uses invalid characters (mw.title.new returns nil if this is the case); and 3) 
        -- check if the image subtemplate exists.
        local goodtitlecall, imagetemplateobject = pcall(mw.title.new, imagetemplatename, 'Template')
        if not (goodtitlecall and imagetemplateobject and imagetemplateobject.exists) then
            imagetemplatename = 'Portal/Images/Default'
        end

        -- Expand the image subtemplate to get the image name
        local imagename = mw.getCurrentFrame():expandTemplate{ title = imagetemplatename }
            
        -- Generate the html for the image and the portal name.
        tableroot
            .newline()
            .tag('tr')
                .attr('valign', 'middle')
                .tag('td')
                    .css('text-align', 'center')
                    .wikitext('[[File:' .. imagename .. '|32x28px|alt=Portal icon]]')
                    .done()
                .tag('td')
                    .css('padding', '0 0.2em')
                    .css('vertical-align', 'middle')
                    .css('font-style', 'italic')
                    .css('font-weight', 'bold')
                    .wikitext('[[Portal:' .. v .. '|' .. v .. ((args['break'] == 'yes' and '<br />') or ' ') .. 'portal]]')
    end

    return tostring(root)
end

-- This function gets the arguments passed to the module and passes them
-- to the _portal() function above.
function p.portal(frame)
    local orig_args
    if frame == mw.getCurrentFrame() then
        -- We're being called via #invoke. If the invoking template passed any arguments,
        -- use them. Otherwise, use the arguments that were passed into the template.
        orig_args = frame:getParent().args
        for k, v in pairs(frame.args) do
            orig_args = frame.args
            break
        end
    else
        -- We're being called from another module or from the debug console, so assume
        -- the arguments are passed in directly.
        orig_args = frame
    end
    
    -- We want to list all the portals in the order they were passed to the template. 
    -- We also want to be able to deal with positional arguments passed explicitly, 
    -- for example {{portal|2=Politics}}. However, pairs() doesn't guarantee the correct 
    -- order, and ipairs() will stop after the first nil value. To get around this, we 
    -- create a new table of arguments where nil values have been removed, so that we 
    -- can traverse the numerical arguments using ipairs(). We also remove values which 
    -- only consist of whitespace. ParserFunctions considers these to be false, and by
    -- removing them Lua will consider them false too.
    
    local args = {} -- Arguments table.
    local name_args = {} -- Temporary table for named arguments.
    for k, v in pairs(orig_args) do
        if mw.ustring.match(v, '%S') then -- Remove values that are only whitespace.
            if type(k) == 'number' then
                table.insert(args, k) -- Put positional argument keys into the arguments table so we can sort them.
            else
                -- Put named argument values in their own table while we sort the positional arguments,
                -- so that we don't have to cycle through all the original arguments again.
                name_args[k] = v 
            end
        end
    end
    table.sort(args) -- Sort the positional argument keys into numerical order.
    for i,v in ipairs(args) do
        args[i] = orig_args[v] -- Replace positional argument keys with their corresponding values.
    end
    for k,v in pairs(name_args) do
        args[k] = v -- Add named arguments to the args table
    end

    return _portal(args)
end

return p