Module:Message box: Difference between revisions

From Vigyanwiki
Template>Mr. Stradivarius
(initial code for ambox)
Template>Mr. Stradivarius
(more ambox stuff - still a little broken)
Line 18: Line 18:
     end
     end
     return page or mw.title.getCurrentTitle()
     return page or mw.title.getCurrentTitle()
end
local function generateBoxStructure()
    local root = htmlBuilder.create() -- Includes error messages and categories added after the box.
    local substCheck = root.tag('b').addClass('error')
    local box = root.tag('table')
    local row = box.tag('tr')
    local imageLeftCell = row.tag('td')
    return root, substCheck, box, row, imageLeftCell
end
end


Line 49: Line 40:
]]
]]


     -- Process config data.
     ------------------------ Process config data ----------------------------
 
    -- Type data.
     local typeData = data.types[args.type]
     local typeData = data.types[args.type]
     local invalidType = args.type and not typeData and true or false
     local invalidType = args.type and not typeData and true or false
     typeData = typeData or data.types[data.default]
     typeData = typeData or data.types[data.default]


    -- Process data for collapsible text fields
    local text, talk, fix, date, info
    if data.useCollapsibleTextFields then
        text = args.issue
        talk = args.talk
        fix = args.fix
        date = args.date
        info = args.info
    else
        text = args.text
    end
    -- Find whether we are using a small message box and process our data accordingly.
     local isSmall = data.allowSmall and (args.small == 'yes' or args.small == true) and true or false
     local isSmall = data.allowSmall and (args.small == 'yes' or args.small == true) and true or false
     local smallClass, image, imageRight, text, imageSize
     local smallClass, image, imageRight, imageSize
     if isSmall then
     if isSmall then
         smallClass = data.smallClass or 'mbox-small'
         smallClass = data.smallClass or 'mbox-small'
         image = args.smallimage or args.image
         image = args.smallimage or args.image
         imageRight = args.smallimageright or args.imageright
         imageRight = args.smallimageright or args.imageright
         text = args.smalltext or args.text
         text = args.smalltext or text
         imageSize = data.imageSmallSize or '30x30px'
         imageSize = data.imageSmallSize or '30x30px'
     else
     else
         image = args.image
         image = args.image
         imageRight = args.imageright
         imageRight = args.imageright
        text = args.text
         imageSize = '40x40px'
         imageSize = '40x40px'
     end
     end


     -- Get the box structure.
     ------------------------ Get the box structure ----------------------------
     local root, substCheck, box, row, imageLeftCell = generateBoxStructure()
 
    local root = htmlBuilder.create() -- Includes error messages and categories added after the box.
     local substCheck = root.tag('b').addClass('error')
    local box = root.tag('table')
    local row = box.tag('tr')
    local imageLeftCell = row.tag('td').addClass('mbox-image')
    local textCell = row.tag('td').addClass('mbox-text')
    local imageRightCell = row.tag('td').addClass('mbox-imageright')
 
    ------------------------ Build the box ----------------------------


     -- Do the subst check.
     -- Do the subst check.
Line 104: Line 118:
     local imageCheckBlank = data.imageCheckBlank
     local imageCheckBlank = data.imageCheckBlank
     if image ~= 'none' and not imageCheckBlank or image ~= 'none' and imageCheckBlank and image ~= 'blank' then
     if image ~= 'none' and not imageCheckBlank or image ~= 'none' and imageCheckBlank and image ~= 'blank' then
        imageLeftCell
            .addClass('mbox-image')
         if not isSmall and data.imageCellDiv then
         if not isSmall and data.imageCellDiv then
             imageLeftCell = imageLeftCell.tag('div').css('width', '52px') -- If we are using a div, redefine imageLeftCell so that the image is inside it.
             imageLeftCell = imageLeftCell.tag('div').css('width', '52px') -- If we are using a div, redefine imageLeftCell so that the image is inside it.
Line 118: Line 130:


     -- Add the text.
     -- Add the text.
     row.tag('td')
     if data.useCollapsibleTextFields then
         .addClass('mbox-text')
        textCell
         .cssText(args.textstyle)
            .cssText(args.textstyle)
        .wikitext(text)
        local textCellSpan = textCell.tag('span')
         textCellSpan
            .addClass('mbox-text-span')
            .wikitext(text)
         if not isSmall then
            textCellSpan
                .tag('span')
                    .addClass('hide-when-compact')
                    .wikitext(talk)
                    .wikitext(fix)
                    .done()
        end
        textCellSpan
            .wikitext(date and mw.ustring.format(" <small>''(%s)''</small>", date))
        if not isSmall then
            textCellSpan
                .tag('span')
                    .addClass('hide-when-compact')
                    .wikitext(info and ' ' .. info)
        end
    else
        textCell
            .cssText(args.textstyle)
            .wikitext(text)
    end


     -- Add the right-hand image.
     -- Add the right-hand image.
     if imageRight and not (data.imageRightNone and imageRight == 'none') then
     if imageRight and not (data.imageRightNone and imageRight == 'none') then
         row.tag('td')
         if not isSmall and data.imageCellDiv then
            .addClass('mbox-imageright')
            imageRightCell = imageRightCell.tag('div').css('width', '52px') -- If we are using a div, redefine imageRightCell so that the image is inside it.
        end
        imageRightCell
             .wikitext(imageRight)
             .wikitext(imageRight)
     end
     end
Line 140: Line 178:
     end
     end


     -- Add error messages and tracking categories.
     ------------------------ Add error messages and categories ----------------------------
 
    -- Add error message and tracking category for invalid type parameters.
     if invalidType then
     if invalidType then
         local catsort = (nsid == 0 and 'Main:' or '') .. title.prefixedText
         local catsort = (nsid == 0 and 'Main:' or '') .. title.prefixedText
Line 199: Line 239:
     data.imageSmallSize = '20x20px'
     data.imageSmallSize = '20x20px'
     data.imageCellDiv = true
     data.imageCellDiv = true
     data.talkLink = true
     data.useCollapsibleTextFields = true
    data.imageRightNone = true
     return p.build(data, args)
     return p.build(data, args)
end
end
Line 414: Line 455:
                 v = mw.text.trim(v)
                 v = mw.text.trim(v)
             end
             end
             if v ~= '' then
             if v ~= '' or k == 'talk' or k == 'sect' or k == 'date' then
                 args[k] = v
                 args[k] = v
             end
             end

Revision as of 12:08, 23 September 2013

Lua error in package.lua at line 80: module 'Module:HtmlBuilder' not found. Lua error in package.lua at line 80: module 'Module:HtmlBuilder' not found. Lua error in package.lua at line 80: module 'Module:HtmlBuilder' not found. Lua error in package.lua at line 80: module 'Module:HtmlBuilder' not found.

This is a meta-module that implements the message box templates {{mbox}}, {{ambox}}, {{cmbox}}, {{fmbox}}, {{imbox}}, {{ombox}}, and {{tmbox}}. It is intended to be used from Lua modules, and should not be used directly from wiki pages. If you want to use this module's functionality from a wiki page, please use the individual message box templates instead.

Usage

To use this module from another Lua module, first you need to load it.

local messageBox = require('Module:Message box')

To create a message box, use the main function. It takes two parameters: the first is the box type (as a string), and the second is a table containing the message box parameters.

local box = messageBox.main( boxType, {
    param1 = param1,
    param2 = param2,
    -- More parameters...
})

There are seven available box types:

Box type Template Purpose
mbox {{mbox}} For message boxes to be used in multiple namespaces
ambox {{ambox}} For article message boxes
cmbox {{cmbox}} For category message boxes
fmbox {{fmbox}} For interface message boxes
imbox {{imbox}} For file namespace message boxes
tmbox {{tmbox}} For talk page message boxes
ombox {{ombox}} For message boxes in other namespaces

See the template page of each box type for the available parameters.

Usage from #invoke

As well as the main function, this module has separate functions for each box type. They are accessed using the code {{#invoke:Message box|mbox|...}}, {{#invoke:Message box|ambox|...}}, etc. These will work when called from other modules, but they access code used to process arguments passed from #invoke, and so calling them will be less efficient than calling main.

Technical details

The module uses the same basic code for each of the templates listed above; the differences between each of them are configured using the data at Module:Message box/configuration. Here are the various configuration options and what they mean:

  • types – a table containing data used by the type parameter of the message box. The table keys are the values that can be passed to the type parameter, and the table values are tables containing the class and the image used by that type.
  • default – the type to use if no value was passed to the type parameter, or if an invalid value was specified.
  • showInvalidTypeError – whether to show an error if the value passed to the type parameter was invalid.
  • allowBlankParams – usually blank values are stripped from parameters passed to the module. However, whitespace is preserved for the parameters included in the allowBlankParams table.
  • allowSmall – whether a small version of the message box can be produced with "small=yes".
  • smallParam – a custom name for the small parameter. For example, if set to "left" you can produce a small message box using "small=left".
  • smallClass – the class to use for small message boxes.
  • substCheck – whether to perform a subst check or not.
  • classes – an array of classes to use with the message box.
  • imageEmptyCell – whether to use an empty ‎<td>...‎</td> cell if there is no image set. This is used to preserve spacing for message boxes with a width of less than 100% of the screen.
  • imageEmptyCellStyle – whether empty image cells should be styled.
  • imageCheckBlank – whether "image=blank" results in no image being displayed.
  • imageSmallSize – usually, images used in small message boxes are set to 30x30px. This sets a custom size.
  • imageCellDiv – whether to enclose the image in a div enforcing a maximum image size.
  • useCollapsibleTextFields – whether to use text fields that can be collapsed, i.e. "issue", "fix", "talk", etc. Currently only used in ambox.
  • imageRightNone – whether imageright=none results in no image being displayed on the right-hand side of the message box.
  • sectionDefault – the default name for the "section" parameter. Depends on useCollapsibleTextFields.
  • allowMainspaceCategories – allow categorisation in the main namespace.
  • templateCategory – the name of a category to be placed on the template page.
  • templateCategoryRequireName – whether the name parameter is required to display the template category.
  • templateErrorCategory – the name of the error category to be used on the template page.
  • templateErrorParamsToCheck – an array of parameter names to check. If any are absent, the templateErrorCategory is applied to the template page.

-- This is a meta-module for producing message box templates, including {{mbox}}, {{ambox}}, {{imbox}}, {{tmbox}}, {{ombox}}, {{cmbox}} and {{fmbox}}.

local htmlBuilder = require('Module:HtmlBuilder')
local nsDetect = require('Module:Namespace detect')
local yesno = require('Module:Yesno')

local p = {}

local function getTitleObject(page)
    if type(page) == 'string' then
        -- Get the title object, passing the function through pcall 
        -- in case we are over the expensive function count limit.
        local success
        success, page = pcall(mw.title.new, page)
        if not success then
            page = nil
        end
    end
    return page or mw.title.getCurrentTitle()
end

function p.build(data, args)
    -- Get the title object and the namespace.
    local title = mw.title.getCurrentTitle()
    local nsid = title.namespace
    
-- Commenting this out for now - this will require tinkering with Namespace detect to differentiate between
-- invalid titles and pages where the expensive parser function count has been exceeded.
--[[
    local title = nsDetect.getPageObject(args.page)
    local namespace = nsDetect.main{
        page = args.page,
        demospace = args.demospace,
        main = 'main',
        talk = 'talk',
        file = 'file',
        category = 'category',
        other = 'other'
    }
]]

    ------------------------ Process config data ----------------------------

    -- Type data.
    local typeData = data.types[args.type]
    local invalidType = args.type and not typeData and true or false
    typeData = typeData or data.types[data.default]

    -- Process data for collapsible text fields
    local text, talk, fix, date, info
    if data.useCollapsibleTextFields then
        text = args.issue
        talk = args.talk
        fix = args.fix
        date = args.date
        info = args.info
    else
        text = args.text
    end

    -- Find whether we are using a small message box and process our data accordingly.
    local isSmall = data.allowSmall and (args.small == 'yes' or args.small == true) and true or false
    local smallClass, image, imageRight, imageSize
    if isSmall then
        smallClass = data.smallClass or 'mbox-small'
        image = args.smallimage or args.image
        imageRight = args.smallimageright or args.imageright
        text = args.smalltext or text
        imageSize = data.imageSmallSize or '30x30px'
    else
        image = args.image
        imageRight = args.imageright
        imageSize = '40x40px'
    end

    ------------------------ Get the box structure ----------------------------

    local root = htmlBuilder.create() -- Includes error messages and categories added after the box.
    local substCheck = root.tag('b').addClass('error')
    local box = root.tag('table')
    local row = box.tag('tr')
    local imageLeftCell = row.tag('td').addClass('mbox-image')
    local textCell = row.tag('td').addClass('mbox-text')
    local imageRightCell = row.tag('td').addClass('mbox-imageright')

    ------------------------ Build the box ----------------------------

    -- Do the subst check.
    if data.substCheck and args.subst == 'SUBST' then
        if type(args.name) == 'string' then
            substCheck
                .wikitext(mw.ustring.format(
                    'Template <code>%s%s%s</code> has been incorrectly substituted.',
                    mw.text.nowiki('{{'),
                    args.name,
                    mw.text.nowiki('}}')
                ))
        end
        root.wikitext('[[Category:Pages with incorrectly substituted templates]]') -- This puts the category at the *end* of the output, rather than after the subst error message.
    end

    -- Build the box.
    box
        .attr('id', args.id)
    for i, class in ipairs(data.classes) do
        box
            .addClass(class)
    end
    box
        .addClass(isSmall and smallClass)
        .addClass(data.classPlainlinksYesno and yesno(args.plainlinks or true) and 'plainlinks')
        .addClass(typeData.class)
        .addClass(args.class)
        .cssText(args.style)
        .attr('role', 'presentation')

    -- Add the left-hand image.
    local imageCheckBlank = data.imageCheckBlank
    if image ~= 'none' and not imageCheckBlank or image ~= 'none' and imageCheckBlank and image ~= 'blank' then
        if not isSmall and data.imageCellDiv then
            imageLeftCell = imageLeftCell.tag('div').css('width', '52px') -- If we are using a div, redefine imageLeftCell so that the image is inside it.
        end
        imageLeftCell
            .wikitext(image or mw.ustring.format('[[File:%s|%s|link=|alt=]]', typeData.image, imageSize))
    elseif data.imageEmptyCell then
        row.tag('td')
            .addClass('mbox-empty-cell') -- No image. Cell with some width or padding necessary for text cell to have 100% width.
            .cssText(data.imageEmptyCellStyle and 'border:none;padding:0px;width:1px')
    end

    -- Add the text.
    if data.useCollapsibleTextFields then
        textCell
            .cssText(args.textstyle)
        local textCellSpan = textCell.tag('span')
        textCellSpan
            .addClass('mbox-text-span')
            .wikitext(text)
        if not isSmall then
            textCellSpan
                .tag('span')
                    .addClass('hide-when-compact')
                    .wikitext(talk)
                    .wikitext(fix)
                    .done()
        end
        textCellSpan
            .wikitext(date and mw.ustring.format(" <small>''(%s)''</small>", date))
        if not isSmall then
            textCellSpan
                .tag('span')
                    .addClass('hide-when-compact')
                    .wikitext(info and ' ' .. info)
        end
    else
        textCell
            .cssText(args.textstyle)
            .wikitext(text)
    end

    -- Add the right-hand image.
    if imageRight and not (data.imageRightNone and imageRight == 'none') then
        if not isSmall and data.imageCellDiv then
            imageRightCell = imageRightCell.tag('div').css('width', '52px') -- If we are using a div, redefine imageRightCell so that the image is inside it.
        end
        imageRightCell
            .wikitext(imageRight)
    end

    -- Add the below row.
    if data.below and args.below then
        box.tag('tr')
            .tag('td')
                .attr('colspan', args.imageright and '3' or '2')
                .addClass('mbox-text')
                .cssText(args.textstyle)
                .wikitext(args.below)
    end

    ------------------------ Add error messages and categories ----------------------------

    -- Add error message and tracking category for invalid type parameters.
    if invalidType then
        local catsort = (nsid == 0 and 'Main:' or '') .. title.prefixedText
        root
            .tag('div')
                .css('text-align', 'center')
                .wikitext(mw.ustring.format('This message box is using an invalid "type=%s" parameter and needs fixing.', args.type or ''))
                .done()
            .wikitext(mw.ustring.format('[[Category:Wikipedia message box parameter needs fixing|%s]]', catsort))
    end

    -- Categorise template pages.
    if data.category and nsid == 10 and not title.isSubpage and not yesno(args.nocat) then
            root.wikitext(mw.ustring.format('[[Category:%s]]', data.category))
    end
    return tostring(root)
end

function p._ambox(args)
    local data = {}
    data.types = {
        speedy = {
            class = 'ambox-speedy',
            image = 'Ambox speedy deletion.png'
        },
        delete = {
            class = 'ambox-delete',
            image = 'Ambox deletion.png'
        },
        content = {
            class = 'ambox-content',
            image = 'Ambox content.png'
        },
        style = {
            class = 'ambox-style',
            image = 'Edit-clear.svg'
        },
        move = {
            class = 'ambox-move',
            image = 'Ambox move.png'
        },
        protection = {
            class = 'ambox-protection',
            image = 'Ambox protection.png'
        },
        notice = {
            class = 'ambox-notice',
            image = 'Ambox notice.png'
        }
    }
    data.default = 'notice'
    data.allowSmall = true
    data.substCheck = true
    data.classes = {'metadata', 'plainlinks', 'ambox'}
    data.smallClass = 'mbox-small-left'
    data.imageEmptyCell = true
    data.imageCheckBlank = true
    data.imageSmallSize = '20x20px'
    data.imageCellDiv = true
    data.useCollapsibleTextFields = true
    data.imageRightNone = true
    return p.build(data, args)
end

function p._fmbox(args)
    local data = {}
    data.types = {
        warning = {
            class = 'fmbox-warning',
            image = 'Cmbox deletion.png'
        },
        editnotice = {
            class = 'fmbox-editnotice',
            image = 'Imbox notice.png'
        },
        system = {
            class = 'fmbox-system',
            image = 'Imbox notice.png'
        }
    }
    data.default = 'system'
    data.classes = { 'plainlinks', 'fmbox' }
    data.imageEmptyCell = false
    data.imageRightNone = false
    return p.build(data, args)
end

function p._ombox(args)
    local data = {}
    data.types = {
        speedy = {
            class = 'ombox-speedy',
            image = 'Imbox speedy deletion.png'
        },
        delete = {
            class = 'ombox-delete',
            image = 'Imbox deletion.png'
        },
        content = {
            class = 'ombox-content',
            image = 'Imbox content.png'
        },
        style = {
            class = 'ombox-style',
            image = 'Edit-clear.svg'
        },
        move = {
            class = 'ombox-move',
            image = 'Imbox move.png'
        },
        protection = {
            class = 'ombox-protection',
            image = 'Imbox protection.png'
        },
        notice = {
            class = 'ombox-notice',
            image = 'Imbox notice.png'
        }
    }
    data.default = 'notice'
    data.classes = {'plainlinks', 'ombox'}
    data.allowSmall = true
    data.imageEmptyCell = true
    data.imageRightNone = true
    return p.build(data, args)
end

function p._imbox(args)
    local data = {}
    data.types = {
        speedy = {
            class = 'imbox-speedy',
            image = 'Imbox speedy deletion.png'
        },
        delete = {
            class = 'imbox-delete',
            image = 'Imbox deletion.png'
        },
        content = {
            class = 'imbox-content',
            image = 'Imbox content.png'
        },
        style = {
            class = 'imbox-style',
            image = 'Edit-clear.svg'
        },
        move = {
            class = 'imbox-move',
            image = 'Imbox move.png'
        },
        protection = {
            class = 'imbox-protection',
            image = 'Imbox protection.png'
        },
        license = {
            class = 'imbox-license',
            image = 'Imbox license.png'
        },
        featured = {
            class = 'imbox-featured',
            image = 'Imbox featured.png'
        },
        notice = {
            class = 'imbox-notice',
            image = 'Imbox notice.png'
        }
    }
    data.default = 'notice'
    data.classes = {'imbox'}
    data.classPlainlinksYesno = true
    data.imageEmptyCell = true
    data.below = true
    return p.build(data, args)
end

function p._cmbox(args)
    local data = {}
    data.types = {
        speedy = {
            class = 'cmbox-speedy',
            image = 'Cmbox deletion.png'
        },
        delete = {
            class = 'cmbox-delete',
            image = 'Cmbox deletion.png'
        },
        content = {
            class = 'cmbox-content',
            image = 'Cmbox content.png'
        },
        style = {
            class = 'cmbox-style',
            image = 'Edit-clear.svg'
        },
        move = {
            class = 'cmbox-move',
            image = 'Cmbox move.png'
        },
        protection = {
            class = 'cmbox-protection',
            image = 'Cmbox protection.png'
        },
        notice = {
            class = 'cmbox-notice',
            image = 'Cmbox notice.png'
        }
    }
    data.default = 'notice'
    data.classes = {'plainlinks', 'cmbox'}
    return p.build(data, args)
end

function p._tmbox(args)
    local data = {}
    data.types = {
        speedy = {
            class = 'tmbox-speedy',
            image = 'Imbox speedy deletion.png'
        },
        delete = {
            class = 'tmbox-delete',
            image = 'Imbox deletion.png'
        },
        content = {
            class = 'tmbox-content',
            image = 'Imbox content.png'
        },
        style = {
            class = 'tmbox-style',
            image = 'Edit-clear.svg '
        },
        move = {
            class = 'tmbox-move',
            image = 'Imbox move.png'
        },
        protection = {
            class = 'tmbox-protection',
            image = 'Imbox protection.png'
        },
        notice = {
            class = 'tmbox-notice',
            image = 'Imbox notice.png'
        }
    }
    data.default = 'notice'
    data.classes = {'plainlinks', 'tmbox'}
    data.allowSmall = true
    data.imageRightNone = true
    data.imageEmptyCellStyle = true
    data.category = 'Talk message boxes'
    return p.build(data, args)
end

local function makeWrapper(func)
    return function (frame)
        -- If called via #invoke, use the args passed into the invoking
        -- template, or the args passed to #invoke if any exist. Otherwise
        -- assume args are being passed directly in from the debug console
        -- or from another Lua module.
        local origArgs
        if frame == mw.getCurrentFrame() then
            origArgs = frame:getParent().args
            for k, v in pairs(frame.args) do
                origArgs = frame.args
                break
            end
        else
            origArgs = frame
        end
        -- Trim whitespace and remove blank arguments.
        local args = {}
        for k, v in pairs(origArgs) do
            if type(v) == 'string' then
                v = mw.text.trim(v)
            end
            if v ~= '' or k == 'talk' or k == 'sect' or k == 'date' then
                args[k] = v
            end
        end
        return func(args)
    end
end

p.ambox = makeWrapper(p._ambox)
p.fmbox = makeWrapper(p._fmbox)
p.imbox = makeWrapper(p._imbox)
p.ombox = makeWrapper(p._ombox)
p.cmbox = makeWrapper(p._cmbox)
p.tmbox = makeWrapper(p._tmbox)

return p