FANDOM


--
-- wikitext Image object
-- Inputs include
----p.new("Tifa.png", {width=400, caption="Lool", link = ""})
----p.new("[[File:Tifa.png|400px|Lool|link=]]"
----p.new("Tifa.png"):setWidth(400):setCpation("Lool"):setLink("")
-- Invoke directly from articles using
----{{File|Tifa.png|400px|Lool|link=}}
----(I lie, I haven't set up that template yet)
-- This module makes alt the same as caption by default
-- It also accepts "|filter=" with a bunch of values that adds
----a wrapper with relevant classes
--
 
local getArgs = require("Dev:Arguments").getArgs
 
--------------------------------------------------------------------------------
-- Metatable
--------------------------------------------------------------------------------
local meta = {}
 
meta.parse = {}
meta.__type = "image"
meta.func = {}
 
function meta.parse.format(value)
    local values = {
        frame = "frame",
        frameless = "frameless",
        thumb = "thumb",
        thumbnail = "thumb",
        [""] = false
    }
 
    value = mw.text.trim(value:lower())
 
    return values[value]
end
 
function meta.parse.class(value)
    local classList = {}
    for className in string.gmatch(value, "%S+") do
        classList[#classList+1] = className
    end
    if #classList==0 then return {} end
    return classList
end
 
function meta.parse.filter(value)
    local values = {
        gray = "grayscale",
        grayscale = "grayscale",
        monochrome = "grayscale",
        faded = "fade",
        fade = "fade",
        invert = "invert",
        ["horizontal flip"] = "horizontal flip",
        ["flip horizontal"] = "horizontal flip",
        ["horizontal-flip"] = "horizontal flip",
        ["vertical flip"] = "vertical flip",
        ["vertical-flip"] = "vertical flip",
        ["flip vertical"] = "vertical flip",
        ["flip both"] = "horizontal vertical flip",
        ["flip horizontal vertical"] = "horizontal vertical flip",
        ["flip vertical horizontal"] = "horizontal vertical flip",
        ["horizontal vertical flip"] = "horizontal vertical flip",
        ["vertical horizontal flip"] = "horizontal vertical flip",
        ["vertical-flip horizontal-flip"] = "horizontal vertical flip",
        ["horizontal-flip vertical-flip"] = "horizontal vertical flip",
        [""] = false
    }
 
    value = mw.text.trim(value:lower())
 
    return values[value]
end
 
function meta.parse.valign(value)
    local values = {
        baseline = "baseline",
        sub = "sub",
        super = "super",
        top = "top",
        ["text-top"] = "text-top",
        middle = "middle",
        bottom = "bottom",
        ["text-bottom"] = "text-bottom",
        [""] = false
    }
 
    value = mw.text.trim(value:lower())
 
    return values[value]
end
 
function meta.parse.align(value)
    local values = {
        left = "left",
        right = "right",
        none = "none",
        center = "center"
    }
 
    value = mw.text.trim(value:lower())
 
    return values[value]
end
 
function meta.parse.width(value)
    if type(value) == "number" then
        return value
    elseif type(value) == "string" then
        value = mw.text.trim(value:lower())
 
        local value = value:match("^(%d+)p?x?$")
 
        return tonumber(value)
    end
end
 
function meta.parse.height(value)
    if type(value) == "number" then
        return value
    elseif type(value) == "string" then
        value = mw.text.trim(value:lower())
 
        local value = value:match("^(%d+)p?x?$")
 
        return tonumber(value)
    end
end
 
function meta.parse.size(value)
    -- this returns width, height
    if type(value) == "number" then
        return value, nil
    elseif type(value) == "string" then
        value = mw.text.trim(value:lower())
 
        local test = value:match("^(%d+)p?x?$")
 
        if test then
            return tonumber(test), nil
        end
 
        local test = value:match("^x(%d+)p?x?$")
 
        if test then
            return nil, tonumber(test)
        end
 
        local va, vb = value:match("^(%d+)x(%d+)p?x?$")
 
        if value then
            return tonumber(va), tonumber(vb)
        end
    end
end
 
function meta.__tostring(a)
    local this = a._data
    local parts = {this.filename}
    local size = ""
 
    if this.width then
        size = this.width
    end
 
    if this.height then
        size = size .. "x" .. this.height
    end
 
    if size ~= "" then
        table.insert(parts, size .. "px")
    end
 
    if this.format then
        table.insert(parts, this.format)
    end
 
    if this.align then
        table.insert(parts, this.align)
    end
 
    if this.valign then
        table.insert(parts, this.valign)
    end
 
    if this.border then
        table.insert(parts, "border")
    end
 
    local alt = this.alt
 
    if not alt then
        alt = this.caption
    end
 
    if alt then
        table.insert(parts, "alt=" .. alt)
    end
 
    if this.link then
        table.insert(parts, "link=" .. this.link)
    end
 
    if this.caption then
        table.insert(parts, this.caption)
    end
 
    local fullfilename = "[[File:" .. table.concat(parts, "|") .."]]"
 
    if not this.filter and (not this.class or #this.class==0) then
        return fullfilename
    end
 
    local isblock, isfloat, isleft
 
    if this.align
    or (this.format and this.format ~= "frameless")
    or (this.format == "frameless" and this.align)
        then isblock = true
    end
 
    if isblock and this.align ~= "center" and this.align ~= "none" then
        isfloat = true
    end
 
    if isfloat and this.align == "left" then
        isleft = true
    end
 
    local filecont = mw.html.create(isblock and "div" or "span")
 
    if isfloat then
        filecont:css("float", isleft and "left" or "right")
    end
 
    filecont:addClass(this.filter)
    if this.class then filecont:addClass(table.concat(this.class, " ")) end
 
    filecont:wikitext(fullfilename)
 
    return tostring(filecont)
end
 
function meta.__concat(a, b)
    return tostring(a) .. tostring(b)
end
 
function meta.__eq(a, b)
    return tostring(a) == tostring(b)
end
 
function meta.__lt(a, b)
    return tostring(a) < tostring(b)
end
 
function meta.__le(a, b)
    return tostring(a) <= tostring(b)
end
 
function meta.__index(obj, k)
    local mt = getmetatable(obj)
 
    if mt.func[k] then
        return mt.func[k]
    end
end
 
function meta.func.setClass(obj, v)
    obj._data.class = getmetatable(obj).parse.class(v or "") or nil
 
    return obj
end
 
function meta.func.setFormat(obj, v)
    -- "or nil" prevents storing false
    obj._data.format = getmetatable(obj).parse.format(v or "") or nil
 
    return obj
end
 
function meta.func.setAlign(obj, v)
    obj._data.align = getmetatable(obj).parse.align(v or "") or nil
 
    return obj
end
 
function meta.func.setValign(obj, v)
    obj._data.valign = getmetatable(obj).parse.valign(v or "") or nil
 
    return obj
end
 
function meta.func.setFilter(obj, v)
    obj._data.valign = getmetatable(obj).parse.filter(v or "") or nil
 
    return obj
end
 
function meta.func.setWidth(obj, v)
    obj._data.width = getmetatable(obj).parse.width(v or "")
 
    return obj
end
 
function meta.func.setHeight(obj, v)
    obj._data.height = getmetatable(obj).parse.height(v or "")
 
    return obj
end
 
function meta.func.setBorder(obj, v)
    obj._data.border = v or nil
 
    return obj
end
 
function meta.func.setSize(obj, w, h)
    if type(w) == "table" then
        if w.width then
            h = w.height
            w = w.width
        else
            h = w[2]
            w = w[1]
        end
    end
 
    local mt = getmetatable(obj)
 
    obj._data.width = mt.parse.width(w)
    obj._data.height = mt.parse.height(h)
 
    return obj
end
 
function meta.func.setCaption(obj, v)
    obj._data.caption = v or nil
 
    return obj
end
 
function meta.func.setAlt(obj, v)
    obj._data.alt = v or nil
 
    return obj
end
 
function meta.func.setLink(obj, v)
    obj._data.link = v or nil
 
    return obj
end
 
function meta.func.getFormat(obj)
    return obj._data.format
end
 
function meta.func.getAlign(obj)
    return obj._data.align
end
 
function meta.func.getValign(obj)
    return obj._data.valign
end
 
function meta.func.getWidth(obj)
    return obj._data.width
end
 
function meta.func.getHeight(obj)
    return obj._data.height
end
 
function meta.func.getSize(obj)
    return {
        width = obj._data.width,
        height = obj._data.height
    }
end
 
function meta.func.getCaption(obj)
    return obj._data.caption
end
 
function meta.func.getAlt(obj)
    return obj._data.alt
end
 
function meta.func.getLink(obj)
    return obj._data.link
end
 
function meta.func.getClass(obj)
    return table.concat(obj._data.class, " ")
end
 
function meta.func.getFilter(obj)
    return obj._data.filter
end
 
function meta.func.isBorder(obj)
    return not not obj._data.border -- convert nil to false
end
 
function meta.func.getExtension(obj)
    return obj._data.filename:match(".*%.(.+)")
end
 
function meta.func.getPagename(obj)
    return obj._data.filename and ("File:" .. obj._data.filename)
end
 
function meta.func.getFilename(obj)
    return obj._data.filename
end
 
function meta.func.isExist(obj)
    local frame = mw.getCurrentFrame()
 
    if frame then
        local parsetext = "{{filepath:" .. obj._data.filename .. "}}"
 
        return frame:preprocess(parsetext) ~= ""
    else
        -- you're in console, we'll just lie
        return true
    end
end
 
--------------------------------------------------------------------------------
-- Exports
--------------------------------------------------------------------------------
local p = {}
 
function p.invoke(frame)
    local args = getArgs(frame)
    local file = args[1]
 
    if not file then return "" end
 
    for k, v in pairs(args) do
        if k == 1 then
            -- do nothing
        elseif tonumber(k) then
            file = file .. "|" .. v
        else
            file = file .. "|" .. k .. "=" .. v
        end
    end
 
    return p.new("[[" .. file .. "]]")
end
 
function p.filellink(frame)
    local args = getArgs(frame)
    local file = args[1]
 
    local file = p.new(file)
 
    --this is the only way i know how to record a file as a file usage. but it involves two expensives!
    local _ = mw.title.new(file:getFilename(), "File").fileExists
 
    return "[[:File:" .. file:getFilename() .. "|" .. (args[2] or args[1]) .. "]]"
 
end
 
function p.new(a, b)
    local filename
    local values = {}
    local fields = {
        format = true,
        border = true,
        align = true,
        valign = true,
        width = true,
        height = true,
        alt = true,
        link = true,
        caption = true,
        class = true,
        filter = true
    }
 
    if type(a) == "string" then
        if type(b) == "table" then
            for k, v in pairs(b) do
                if fields[k] then
                    local parsefunc = meta.parse[k]
 
                    if parsefunc then
                        values[k] = parsefunc(v)
                    else
                        values[k] = v
                    end
                end
            end
        else
            local contents = a:match("^%s*%[%[(.*)%]%]%s*$")
 
            if contents then
                local aHasChanged = false
 
                for tmp in mw.text.gsplit(contents, "|") do
                    local part = mw.text.trim(tmp)
 
                    if part == "" then
                        -- do nothing
                    elseif not aHasChanged then
                        a = part
                        aHasChanged = true
                    elseif part:find("^class=") then
                        values.class = meta.parse.class(part:sub(7))
                    elseif part:find("^link=") then
                        values.link = part:sub(6)
                    elseif part:find("^alt=") then
                        values.alt = part:sub(5)
                    elseif part:find("^filter=") then
                        values.filter = meta.parse.filter(part:sub(8))
                    elseif part == "border" then
                        values.border = true
                    else
                        local width, height = meta.parse.size(part)
 
                        if width or height then
                            values.width = width
                            values.height = height
                        else
                            local align = meta.parse.align(part)
 
                            if align then
                                values.align = align
                            else
                                local valign = meta.parse.valign(part)
 
                                if valign then
                                    values.valign = valign
                                else
                                    local format = meta.parse.format(part)
 
                                    if format then
                                        values.format = format
                                    else
                                        values.caption = part
                                    end
                                end
                            end
                        end
                    end
                end
            end
        end
 
        local stripfile, filepart = a:match("^%s*(%w+):(.+)")
 
        if stripfile and
        (stripfile:lower() == "file" or stripfile:lower() == "image") then
            filename = filepart
        else
            filename = a
        end
 
        values.filename = mw.uri.decode(mw.text.decode(filename, true), "WIKI")
    end
 
    return setmetatable({_data = values}, meta)
end
 
return p
Community content is available under CC-BY-SA unless otherwise noted.