×
Create a new article
Write your page title here:
We currently have 179 articles on NBITTRPG Wiki. Type your article name above or click on one of the titles below and start writing!



NBITTRPG Wiki

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

-- <nowiki>
--------------------------------------------------------------------------------
-- A feature-packed example generator for brace-based wikitext.
--
-- @module T
-- @alias p
-- @version 0.6.4
-- @release experimental
-- @requires [[Global Lua Modules/Arguments|Module:Arguments]]
-- @requires [[Global Lua Modules/User error|Module:User error]]
-- @requires [[Global Lua Modules/Yesno|Module:Yesno]]
-- @author [[User:DarthKitty]]
-- @author [[User:Speedit]]
-- @author [[User:ExE Boss]]
--
-- @todo Extract CSS to stylesheet; transition from data-attributes to classes.
-- @todo Consider adding i18n for error messages, flags, &c.
-- @todo Consider adding generator(s?) for magic words and parser functions.
--------------------------------------------------------------------------------

local libraryUtil = require("libraryUtil")
local checkType = libraryUtil.checkType

local getArgs = require("Module:Arguments").getArgs
local userError = require("Module:User error")
local yesno = require("Module:Yesno")

local p = {}

--------------------------------------------------------------------------------
-- Parses a parameter to get its components: its name (optional), and either its
-- value or its description (but not both).
--
-- @param {string} param
--     A parameter.
-- @returns {table}
--     The components of a parameter.
--------------------------------------------------------------------------------
local function parseParam(param)
    local tmp = param
    local name, value, description

    -- the parameter's name is anything to the left of the first equals sign;
    -- the equals sign can be escaped, for wikis that don't have [[Template:=]]
    if tmp:find("=") or tmp:find(mw.text.nowiki("=")) then
        name, tmp = tmp
            :gsub(mw.text.nowiki("="), "=", 1)
            :match("^(.-)%s*=%s*(.-)$")
    end

    -- if the remaining text is wrapped in matching quotes, then it's a literal
    -- value; otherwise, it's a description of the parameter
    local first = tmp:sub(1, 1)
    local last = tmp:sub(-1)

    if (first == '"' and last == '"') or (first == "'" and last == "'") then
        value = tmp:sub(2, -2)
    elseif tmp == "" then
        description = "..." -- the description cannot be an empty string
    else
        description = tmp
    end

    return {
        name = name,
        value = value,
        description = description
    }
end

--------------------------------------------------------------------------------
-- The heart of the module. Transforms a list of parameters into wikitext
-- syntax.
--
-- @param {string} mode
--     Which kind of brace-based wikitext we're dealing with.
-- @param {string} opener
--     Text to insert between the two left-braces and the first parameter.
-- @param[opt] {table|nil} params
--     A sequentual table of parameters.
-- @param[opt] {table|nil} options
--     A table with configuration flags.
-- @param[opt] {boolean|nil} options.multiline
-- @param[opt] {boolean|nil} options.subst
-- @returns {string}
--     A blob of wikitext describing any brace-based syntax.
--------------------------------------------------------------------------------
local function builder(mode, opener, params, options)
    checkType("builder", 2, opener, "string")
    checkType("builder", 3, params, "table", true)
    checkType("builder", 4, options, "table", true)

    params = params or {}
    options = options or {}

    local html = mw.html.create("code")
        :attr("data-t-role", "wrapper")
        :attr("data-t-mode", mode)
        :css("all", "unset")
        :css("font-family", "monospace")

    local openerSpan =
        html:tag("span")
            :attr("data-t-role", "opener")
            :wikitext(mw.text.nowiki("{"):rep(2))

	if options.subst then
		openerSpan:wikitext("subst:")
	end

    openerSpan:wikitext(opener)

    if options.multiline then
        html:attr("data-t-multiline", "data-t-multiline")
    end

    for i, param in ipairs(params) do
        if type(param) ~= "string" then
            error("invalid entry #" .. i .. " in parameter list", 3)
        end

        local components = parseParam(param)
        local paramHtml = html:tag("span")
            :attr("data-t-role", "parameter")
            :attr("data-t-index", i)
            :wikitext(mw.text.nowiki("|"))

        if options.multiline then
            paramHtml:css("display", "block")
        end

        if components.name then
            paramHtml:tag("span")
                :attr("data-t-role", "parameter-name")
                :css("font-weight", "bold")
                :wikitext(components.name)

            paramHtml:wikitext(" = ")
        end

        if components.value then
            paramHtml:tag("span")
                :attr("data-t-role", "parameter-value")
                :wikitext(components.value)
        end

        if components.description then
            paramHtml:tag("span")
                :attr("data-t-role", "parameter-description")
                :css("opacity", "0.65")
                :wikitext(mw.text.nowiki("<"))
                :wikitext(components.description)
                :wikitext(mw.text.nowiki(">"))
        end
    end

    html:tag("span")
        :attr("data-t-role", "closer")
        :wikitext(mw.text.nowiki("}"):rep(2))

    return tostring(html)
end

--------------------------------------------------------------------------------
-- Resolves a transclusion according to the MediaWiki
-- transclusion resolution algorithm.
--
-- @param {string} title
--        The name of the transclusion to resolve.
-- @return {string}
--         The resolved transclusion with the namespace prefix.
-- @see [[w:Template:Transclude]]
--------------------------------------------------------------------------------
local function resolveTransclusion(title)
	checkType("resolveTransclusion", 1, title, "string")
	local i = mw.ustring.find(title, "%:")
	if i == 1 then
		return mw.ustring.sub(title, 2)
	elseif i ~= nil then
		return title
	end
	return "Template:" .. title
end

--------------------------------------------------------------------------------
-- Generator for transclusion syntax, e.g. `{{foo}}`, `{{:foo}}`,
-- or `{{Template:Foo}}`.
--
-- @param {string} title
--     The name of the template to link to.
-- @param[opt] {table|nil} params
--     A sequentual table of parameters.
-- @param[opt] {table|nil} options
--     A table with configuration flags.
-- @param[opt] {boolean|nil} options.multiline
-- @param[opt] {boolean|nil} options.subst
-- @returns {string}
--     A blob of wikitext describing a template.
--------------------------------------------------------------------------------
function p.transclusion(title, params, options)
    if type(title) ~= "string" or title == "" then
        error("no title specified", 2)
    end

    return builder(
        "transclusion",
        "[[:" .. resolveTransclusion(title) .. "|" .. title .. "]]",
        params,
        options
    )
end

--------------------------------------------------------------------------------
-- Generator for invocation syntax, e.g. `{{#invoke:foo|bar}}`.
--
-- @param {string} title
--     The name of the module to link to, without the namespace prefix.
-- @param {string} func
--     The name of the function to call.
-- @param[opt] {table|nil} params
--     A sequentual table of parameters.
-- @param[opt] {table|nil} options
--     A table with configuration flags.
-- @param[opt] {boolean|nil} options.multiline
-- @param[opt] {boolean|nil} options.subst
-- @returns {string}
--     A blob of wikitext describing a module.
--------------------------------------------------------------------------------
function p.invocation(title, func, params, options)
    if type(title) ~= "string" or title == "" then
        error("no module specified", 2)
    end

    if type(func) ~= "string" or func == "" then
        error("no function specified", 2)
    end

    local link = "[[Module:" .. title .. "|" .. title .. "]]"

    return builder(
        "invocation",
        "#invoke:" .. link .. mw.text.nowiki("|") .. func,
        params,
        options
    )
end

--------------------------------------------------------------------------------
-- Entry point from the wikitext side. Determines which generator to use based
-- on the provided arguments.
--
-- @param {table|Frame} frame
--     A frame object whose arguments will determine the correct generator
--     to use.
-- @returns {string}
--     A blob of wikitext describing any brace-based syntax.
--------------------------------------------------------------------------------
function p.main(frame)
    local args = getArgs(frame, {removeBlanks = false})
    local mode, minimumArity

    if yesno(args.invocation) or yesno(args.i) then
        mode = "invocation"
        minimumArity = 2
    else
        mode = "transclusion"
        minimumArity = 1
    end

    local params = {}
    local options = {
        multiline = yesno(args.multiline) or yesno(args.m),
        subst = yesno(args.subst) or yesno(args.s),
    }

    -- a dynamically-generated list of arguments to the generator
    -- required arguments are inserted before `params` and `options`
    local varargs = {params, options}

    for i, value in ipairs(args) do
        if i <= minimumArity then
            -- pass the first few values directly to the generator
            -- these are used to calculate the opener
            table.insert(varargs, i, value)
        else
            -- put the remaining values in a table, and pass it to the generator
            -- these are shown as parameters in the resulting wikitext
            params[#params + 1] = value
        end
    end

    local success, response = pcall(p[mode], unpack(varargs))

    return success and response or userError(response)
end

return p

Recent changes

  • Zaptrap • Friday at 22:20
  • Zaptrap • Friday at 22:18
  • Zaptrap • Friday at 22:15
  • Ember • Friday at 22:03
  • AndrewFBR • Friday at 00:24
  • AndrewFBR • Friday at 00:24
  • AndrewFBR • Friday at 00:24
  • AndrewFBR • Friday at 00:24