|
|
(One intermediate revision by the same user not shown) |
Line 1: |
Line 1: |
| -- This module provides a library for formatting file wikilinks. | | -- This module provides a library for formatting file wikilinks. |
| | | |
− | local libraryUtil = require('libraryUtil') | + | local yesno = require('Module:Yesno') |
− | local checkType = libraryUtil.checkType | + | local checkType = require('libraryUtil').checkType |
| | | |
− | local fileLink = {} | + | local p = {} |
| | | |
− | function fileLink.new(filename) | + | function p._main(args) |
− | checkType('fileLink.new', 1, filename, 'string', true) | + | checkType('_main', 1, args, 'table') |
− | local obj, data = {}, {}
| + | |
− | | + | -- This is basically libraryUtil.checkTypeForNamedArg, but we are rolling our |
− | local checkSelf = libraryUtil.makeCheckSelfFunction(
| + | -- own function to get the right error level. |
− | 'fileLink',
| + | local function checkArg(key, val, level) |
− | 'fileLink',
| + | if type(val) ~= 'string' then |
− | obj,
| |
− | 'fileLink object'
| |
− | )
| |
− |
| |
− | -- Set the filename if we were passed it as an input to fileLink.new. | |
− | if filename then | |
− | data.theName = filename
| |
− | end
| |
− |
| |
− | function data:name(s)
| |
− | checkSelf(self, 'name')
| |
− | checkType('fileLink:name', 1, s, 'string') | |
− | data.theName = s
| |
− | return self
| |
− | end
| |
− |
| |
− | function data:format(s, filename)
| |
− | checkSelf(self, 'format')
| |
− | checkType('fileLink:format', 1, s, 'string', true)
| |
− | checkType('fileLink:format', 2, format, 'string', true)
| |
− | local validFormats = {
| |
− | thumb = true,
| |
− | thumbnail = true,
| |
− | frame = true,
| |
− | framed = true,
| |
− | frameless = true
| |
− | }
| |
− | if s == nil or validFormats[s] then
| |
− | data.theFormat = s
| |
− | data.theFormatFilename = filename
| |
− | else
| |
| error(string.format( | | error(string.format( |
− | "bad argument #1 to 'fileLink:format' ('%s' is not a valid format)", | + | "type error in '%s' parameter of '_main' (expected string, got %s)", |
− | s | + | key, type(val) |
− | ), 2) | + | ), level) |
| end | | end |
− | return self
| |
| end | | end |
| | | |
− | local function sizeError(methodName) | + | local ret = {} |
− | -- Used for formatting duplication errors in size-related methods.
| + | |
− | error(string.format(
| + | -- Adds a positional parameter to the buffer. |
− | "duplicate size argument detected in '%s'"
| + | local function addPositional(key) |
− | .. " ('upright' cannot be used in conjunction with height or width)",
| + | local val = args[key] |
− | methodName
| + | if not val then |
− | ), 3)
| + | return nil |
− | end
| |
− |
| |
− | function data:width(px) | |
− | checkSelf(self, 'width') | |
− | checkType('fileLink:width', 1, px, 'number', true)
| |
− | if px and data.isUpright then | |
− | sizeError('fileLink:width') | |
| end | | end |
− | data.theWidth = px | + | checkArg(key, val, 4) |
− | return self | + | ret[#ret + 1] = val |
| end | | end |
− | | + | |
− | function data:height(px) | + | -- Adds a named parameter to the buffer. We assume that the parameter name |
− | checkSelf(self, 'height')
| + | -- is the same as the argument key. |
− | checkType('fileLink:height', 1, px, 'number', true) | + | local function addNamed(key) |
− | if px and data.isUpright then | + | local val = args[key] |
− | sizeError('fileLink:height') | + | if not val then |
| + | return nil |
| end | | end |
− | data.theHeight = px | + | checkArg(key, val, 4) |
− | return self
| + | ret[#ret + 1] = key .. '=' .. val |
| end | | end |
− | | + | |
− | function data:upright(isUpright, factor) | + | -- Filename |
− | checkSelf(self, 'upright')
| + | checkArg('file', args.file, 3) |
− | checkType('fileLink:upright', 1, isUpright, 'boolean', true)
| + | ret[#ret + 1] = 'File:' .. args.file |
− | checkType('fileLink:upright', 2, factor, 'number', true)
| + | |
− | if isUpright and (data.theWidth or data.theHeight) then
| + | -- Format |
− | sizeError('fileLink:upright')
| + | if args.format then |
− | end
| + | checkArg('format', args.format) |
− | data.isUpright = isUpright
| + | if args.formatfile then |
− | data.uprightFactor = factor
| + | checkArg('formatfile', args.formatfile) |
− | return self
| + | ret[#ret + 1] = args.format .. '=' .. args.formatfile |
− | end | |
− | | |
− | function data:resetSize()
| |
− | checkSelf(self, 'resetSize') | |
− | for i, field in ipairs{'theWidth', 'theHeight', 'isUpright', 'uprightFactor'} do | |
− | data[field] = nil | |
− | end
| |
− | return self
| |
− | end
| |
− |
| |
− | function data:location(s)
| |
− | checkSelf(self, 'location')
| |
− | checkType('fileLink:location', 1, s, 'string', true)
| |
− | local validLocations = {
| |
− | right = true, | |
− | left = true,
| |
− | center = true,
| |
− | none = true
| |
− | }
| |
− | if s == nil or validLocations[s] then
| |
− | data.theLocation = s
| |
| else | | else |
− | error(string.format( | + | ret[#ret + 1] = args.format |
− | "bad argument #1 to 'fileLink:location' ('%s' is not a valid location)",
| |
− | s
| |
− | ), 2)
| |
| end | | end |
− | return self
| |
| end | | end |
− |
| + | |
− | function data:alignment(s) | + | -- Border |
− | checkSelf(self, 'alignment')
| + | if yesno(args.border) then |
− | checkType('fileLink:alignment', 1, s, 'string', true)
| + | ret[#ret + 1] = 'border' |
− | local validAlignments = {
| |
− | baseline = true,
| |
− | middle = true,
| |
− | sub = true,
| |
− | super = true,
| |
− | ['text-top'] = true,
| |
− | ['text-bottom'] = true,
| |
− | top = true,
| |
− | bottom = true
| |
− | }
| |
− | if s == nil or validAlignments[s] then
| |
− | data.theAlignment = s
| |
− | else
| |
− | error(string.format(
| |
− | "bad argument #1 to 'fileLink:alignment' ('%s' is not a valid alignment)",
| |
− | s
| |
− | ), 2)
| |
− | end
| |
− | return self
| |
− | end
| |
− |
| |
− | function data:border(hasBorder)
| |
− | checkSelf(self, 'border') | |
− | checkType('fileLink:border', 1, hasBorder, 'boolean', true)
| |
− | data.hasBorder = hasBorder
| |
− | return self
| |
− | end
| |
− |
| |
− | function data:link(s)
| |
− | checkSelf(self, 'link')
| |
− | checkType('fileLink:link', 1, s, 'string', true)
| |
− | data.theLink = s
| |
− | return self
| |
− | end
| |
− |
| |
− | function data:alt(s)
| |
− | checkSelf(self, 'alt')
| |
− | checkType('fileLink:alt', 1, s, 'string', true)
| |
− | data.theAlt = s
| |
− | return self
| |
− | end
| |
− |
| |
− | function data:page(num)
| |
− | checkSelf(self, 'page')
| |
− | checkType('fileLink:page', 1, num, 'number', true)
| |
− | data.thePage = s
| |
− | return self
| |
− | end
| |
− |
| |
− | function data:class(s)
| |
− | checkSelf(self, 'class')
| |
− | checkType('fileLink:class', 1, s, 'string', true)
| |
− | data.theClass = s
| |
− | return self
| |
− | end
| |
− |
| |
− | function data:lang(s)
| |
− | checkSelf(self, 'lang')
| |
− | checkType('fileLink:lang', 1, s, 'string', true)
| |
− | data.theLang = s
| |
− | return self
| |
| end | | end |
| | | |
− | local function checkTypeStringOrNum(funcName, pos, arg) | + | addPositional('location') |
− | local argType = type(arg)
| + | addPositional('alignment') |
− | if argType ~= 'nil' and argType ~= 'string' and argType ~= 'number' then
| + | addPositional('size') |
− | error(string.format(
| + | addNamed('upright') |
− | "bad argument #%d to '%s' (string or number expected, got %s)",
| + | addNamed('link') |
− | pos,
| + | addNamed('alt') |
− | funcName,
| + | addNamed('page') |
− | argType
| + | addNamed('class') |
− | ), 3)
| + | addNamed('lang') |
− | end | + | addNamed('start') |
| + | addNamed('end') |
| + | addNamed('thumbtime') |
| + | addPositional('caption') |
| + | |
| + | return string.format('[[%s]]', table.concat(ret, '|')) |
| + | end |
| + | |
| + | function p.main(frame) |
| + | local origArgs = require('Module:Arguments').getArgs(frame, { |
| + | wrappers = 'Template:File link' |
| + | }) |
| + | if not origArgs.file then |
| + | error("'file' parameter missing from [[Template:File link]]", 0) |
| end | | end |
− |
| |
− | function data:startTime(time)
| |
− | checkSelf(self, 'startTime')
| |
− | checkTypeStringOrNum('fileLink:startTime', 1, time)
| |
− | data.theStartTime = time
| |
− | return self
| |
− | end
| |
− |
| |
− | function data:endTime(time)
| |
− | checkSelf(self, 'endTime')
| |
− | checkTypeStringOrNum('fileLink:endTime', 1, time)
| |
− | data.theEndTime = time
| |
− | return self
| |
− | end
| |
− |
| |
− | function data:thumbTime(time)
| |
− | checkSelf(self, 'thumbTime')
| |
− | checkTypeStringOrNum('fileLink:thumbTime', 1, time)
| |
− | data.theThumbTime = time
| |
− | return self
| |
− | end
| |
− |
| |
− | function data:caption(s)
| |
− | checkSelf(self, 'caption')
| |
− | checkType('fileLink:caption', 1, s, 'string', true)
| |
− | data.theCaption = s
| |
− | return self
| |
− | end
| |
− |
| |
− | function data:render()
| |
− | checkSelf(self, 'render')
| |
− | local ret = {}
| |
− |
| |
− | -- Filename
| |
− | if not data.theName then
| |
− | error('fileLink:render: no filename was found')
| |
− | end
| |
− | ret[#ret + 1] = 'File:' .. data.theName
| |
− |
| |
− | -- Format
| |
− | if data.theFormat and data.theFormatFilename then
| |
− | ret[#ret + 1] = data.theFormat .. '=' .. data.theFormatFilename
| |
− | elseif data.theFormat then
| |
− | ret[#ret + 1] = data.theFormat
| |
− | end
| |
− |
| |
− | -- Border
| |
− | if data.hasBorder then
| |
− | ret[#ret + 1] = 'border'
| |
− | end
| |
− |
| |
− | -- Location
| |
− | ret[#ret + 1] = data.theLocation
| |
| | | |
− | -- Alignment
| + | -- Copy the arguments that were passed to a new table to avoid looking up |
− | ret[#ret + 1] = data.theAlignment
| + | -- every possible parameter in the frame object. |
− |
| + | local args = {} |
− | -- Size
| + | for k, v in pairs(origArgs) do |
− | if data.isUpright and data.uprightFactor then
| + | -- Make _BLANK a special argument to add a blank parameter. For use in |
− | ret[#ret + 1] = 'upright=' .. tostring(data.uprightFactor)
| + | -- conditional templates etc. it is useful for blank arguments to be |
− | elseif data.isUpright then
| + | -- ignored, but we still need a way to specify them so that we can do |
− | ret[#ret + 1] = 'upright'
| + | -- things like [[File:Example.png|link=]]. |
− | elseif data.theWidth and data.theHeight then
| + | if v == '_BLANK' then |
− | ret[#ret + 1] = string.format('%dx%dpx', data.theWidth, data.theHeight)
| + | v = '' |
− | elseif data.theWidth then
| |
− | ret[#ret + 1] = tostring(data.theWidth) .. 'px'
| |
− | elseif data.theHeight then | |
− | ret[#ret + 1] = string.format('x%dpx', data.theHeight)
| |
− | end
| |
− |
| |
− | -- Render named parameters. | |
− | -- That includes link, alt, page, class, lang, start, end, and thumbtime. | |
− | do | |
− | local namedParameters = {
| |
− | {'link', 'theLink'},
| |
− | {'alt', 'theAlt'},
| |
− | {'page', 'thePage'},
| |
− | {'class', 'theClass'},
| |
− | {'lang', 'theLang'},
| |
− | {'start', 'theStartTime'},
| |
− | {'end', 'theEndTime'},
| |
− | {'thumbtime', 'theThumbTime'}
| |
− | }
| |
− | for i, t in ipairs(namedParameters) do
| |
− | local parameter = t[1]
| |
− | local value = data[t[2]]
| |
− | if value then
| |
− | ret[#ret + 1] = parameter .. '=' .. tostring(value)
| |
− | end
| |
− | end
| |
| end | | end |
− | | + | args[k] = v |
− | -- Caption | |
− | ret[#ret + 1] = data.theCaption
| |
− |
| |
− | return string.format('[[%s]]', table.concat(ret, '|'))
| |
| end | | end |
− | | + | return p._main(args) |
− | local privateFields = {
| |
− | theName = true,
| |
− | theFormat = true,
| |
− | theFormatFilename = true,
| |
− | theWidth = true,
| |
− | theHeight = true,
| |
− | isUpright = true,
| |
− | uprightFactor = true,
| |
− | theLocation = true,
| |
− | theAlignment = true,
| |
− | hasBorder = true,
| |
− | theLink = true,
| |
− | theAlt = true,
| |
− | thePage = true,
| |
− | theClass = true,
| |
− | theLang = true,
| |
− | theCaption = true
| |
− | }
| |
− |
| |
− | local readOnlyFields = {}
| |
− | for field in pairs(data) do
| |
− | readOnlyFields[field] = true
| |
− | end
| |
− | readOnlyFields.theName = nil -- This is set if a filename is given to fileLink.new, so remove it.
| |
− |
| |
− | local function restrictedFieldError(key, restriction)
| |
− | error(string.format(
| |
− | "fileLink object field '%s' is %s",
| |
− | tostring(key),
| |
− | restriction
| |
− | ), 3)
| |
− | end
| |
− |
| |
− | setmetatable(obj, {
| |
− | __index = function (t, key)
| |
− | if privateFields[key] then
| |
− | restrictedFieldError(key, 'private')
| |
− | else
| |
− | return data[key]
| |
− | end
| |
− | end,
| |
− | __newindex = function (t, key, value)
| |
− | if privateFields[key] then
| |
− | restrictedFieldError(key, 'private')
| |
− | elseif readOnlyFields[key] then
| |
− | restrictedFieldError(key, 'read-only')
| |
− | else
| |
− | data[key] = value
| |
− | end
| |
− | end,
| |
− | __tostring = function (t)
| |
− | return t:render()
| |
− | end,
| |
− | __pairs = function ()
| |
− | local temp = {}
| |
− | for k, v in pairs(data) do
| |
− | if not privateFields[k] then
| |
− | temp[k] = v
| |
− | end
| |
− | end
| |
− | return pairs(temp)
| |
− | end
| |
− | })
| |
− |
| |
− | return obj
| |
| end | | end |
| | | |
− | return fileLink | + | return p |
-- This module provides a library for formatting file wikilinks.
local yesno = require('Module:Yesno')
local checkType = require('libraryUtil').checkType
local p = {}
function p._main(args)
checkType('_main', 1, args, 'table')
-- This is basically libraryUtil.checkTypeForNamedArg, but we are rolling our
-- own function to get the right error level.
local function checkArg(key, val, level)
if type(val) ~= 'string' then
error(string.format(
"type error in '%s' parameter of '_main' (expected string, got %s)",
key, type(val)
), level)
end
end
local ret = {}
-- Adds a positional parameter to the buffer.
local function addPositional(key)
local val = args[key]
if not val then
return nil
end
checkArg(key, val, 4)
ret[#ret + 1] = val
end
-- Adds a named parameter to the buffer. We assume that the parameter name
-- is the same as the argument key.
local function addNamed(key)
local val = args[key]
if not val then
return nil
end
checkArg(key, val, 4)
ret[#ret + 1] = key .. '=' .. val
end
-- Filename
checkArg('file', args.file, 3)
ret[#ret + 1] = 'File:' .. args.file
-- Format
if args.format then
checkArg('format', args.format)
if args.formatfile then
checkArg('formatfile', args.formatfile)
ret[#ret + 1] = args.format .. '=' .. args.formatfile
else
ret[#ret + 1] = args.format
end
end
-- Border
if yesno(args.border) then
ret[#ret + 1] = 'border'
end
addPositional('location')
addPositional('alignment')
addPositional('size')
addNamed('upright')
addNamed('link')
addNamed('alt')
addNamed('page')
addNamed('class')
addNamed('lang')
addNamed('start')
addNamed('end')
addNamed('thumbtime')
addPositional('caption')
return string.format('%s', table.concat(ret, '|'))
end
function p.main(frame)
local origArgs = require('Module:Arguments').getArgs(frame, {
wrappers = 'Template:File link'
})
if not origArgs.file then
error("'file' parameter missing from Template:File link", 0)
end
-- Copy the arguments that were passed to a new table to avoid looking up
-- every possible parameter in the frame object.
local args = {}
for k, v in pairs(origArgs) do
-- Make _BLANK a special argument to add a blank parameter. For use in
-- conditional templates etc. it is useful for blank arguments to be
-- ignored, but we still need a way to specify them so that we can do
-- things like File:Example.png.
if v == '_BLANK' then
v =
end
args[k] = v
end
return p._main(args)
end
return p