Module:File link: Difference between revisions

From escforumwiki
Jump to navigation Jump to search
en>Mr. Stradivarius
m (Mr. Stradivarius moved page Module:Image to Module:File link without leaving a redirect: this is applicable to all file links, not just images)
en>Mr. Stradivarius
(rename the image table to a fileLink table, seeing as this code is applicable to all file links)
Line 1: Line 1:
-- This module provides a library for formatting image wikilinks.
-- This module provides a library for formatting file wikilinks.


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


local image = {}
local fileLink = {}


function image.new(filename)
function fileLink.new(filename)
checkType('image.new', 1, filename, 'string', true)
checkType('fileLink.new', 1, filename, 'string', true)
local obj, data = {}, {}
local obj, data = {}, {}
local checkSelf = libraryUtil.makeCheckSelfFunction(
local checkSelf = libraryUtil.makeCheckSelfFunction(
'image',
'fileLink',
'image',
'fileLink',
obj,
obj,
'image object'
'fileLink object'
)
)
-- Set the filename if we were passed it as an input to image.new.
-- Set the filename if we were passed it as an input to fileLink.new.
if filename then
if filename then
data.theName = filename
data.theName = filename
Line 23: Line 23:
function data:name(s)
function data:name(s)
checkSelf(self, 'image:name')
checkSelf(self, 'fileLink:name')
checkType('image:name', 1, s, 'string')
checkType('fileLink:name', 1, s, 'string')
data.theName = s
data.theName = s
return self
return self
Line 30: Line 30:
function data:format(s, filename)
function data:format(s, filename)
checkSelf(self, 'image:format')
checkSelf(self, 'fileLink:format')
checkType('image:format', 1, s, 'string', true)
checkType('fileLink:format', 1, s, 'string', true)
checkType('image:format', 2, format, 'string', true)
checkType('fileLink:format', 2, format, 'string', true)
local validFormats = {
local validFormats = {
thumb = true,
thumb = true,
Line 45: Line 45:
else
else
error(string.format(
error(string.format(
"bad argument #1 to 'image:format' ('%s' is not a valid format)",
"bad argument #1 to 'fileLink:format' ('%s' is not a valid format)",
s
s
), 2)
), 2)
Line 62: Line 62:
function data:width(px)
function data:width(px)
checkSelf(self, 'image:width')
checkSelf(self, 'fileLink:width')
checkType('image:width', 1, px, 'number', true)
checkType('fileLink:width', 1, px, 'number', true)
if px and data.isUpright then
if px and data.isUpright then
sizeError('image:width')
sizeError('fileLink:width')
end
end
data.theWidth = px
data.theWidth = px
Line 72: Line 72:
function data:height(px)
function data:height(px)
checkSelf(self, 'image:height')
checkSelf(self, 'fileLink:height')
checkType('image:height', 1, px, 'number', true)
checkType('fileLink:height', 1, px, 'number', true)
if px and data.isUpright then
if px and data.isUpright then
sizeError('image:height')
sizeError('fileLink:height')
end
end
data.theHeight = px
data.theHeight = px
Line 82: Line 82:
function data:upright(isUpright, factor)
function data:upright(isUpright, factor)
checkSelf(self, 'image:upright')
checkSelf(self, 'fileLink:upright')
checkType('image:upright', 1, isUpright, 'boolean', true)
checkType('fileLink:upright', 1, isUpright, 'boolean', true)
checkType('image:upright', 2, factor, 'number', true)
checkType('fileLink:upright', 2, factor, 'number', true)
if isUpright and (data.theWidth or data.theHeight) then
if isUpright and (data.theWidth or data.theHeight) then
sizeError('image:upright')
sizeError('fileLink:upright')
end
end
data.isUpright = isUpright
data.isUpright = isUpright
Line 94: Line 94:
function data:resetSize()
function data:resetSize()
checkSelf(self, 'image:resetSize')
checkSelf(self, 'fileLink:resetSize')
for i, field in ipairs{'theWidth', 'theHeight', 'isUpright', 'uprightFactor'} do
for i, field in ipairs{'theWidth', 'theHeight', 'isUpright', 'uprightFactor'} do
data[field] = nil
data[field] = nil
Line 102: Line 102:
function data:location(s)
function data:location(s)
checkSelf(self, 'image:location')
checkSelf(self, 'fileLink:location')
checkType('image:location', 1, s, 'string', true)
checkType('fileLink:location', 1, s, 'string', true)
local validLocations = {
local validLocations = {
right = true,
right = true,
Line 114: Line 114:
else
else
error(string.format(
error(string.format(
"bad argument #1 to 'image:location' ('%s' is not a valid location)",
"bad argument #1 to 'fileLink:location' ('%s' is not a valid location)",
s
s
), 2)
), 2)
Line 122: Line 122:
function data:alignment(s)
function data:alignment(s)
checkSelf(self, 'image:alignment')
checkSelf(self, 'fileLink:alignment')
checkType('image:alignment', 1, s, 'string', true)
checkType('fileLink:alignment', 1, s, 'string', true)
local validAlignments = {
local validAlignments = {
baseline = true,
baseline = true,
Line 138: Line 138:
else
else
error(string.format(
error(string.format(
"bad argument #1 to 'image:alignment' ('%s' is not a valid alignment)",
"bad argument #1 to 'fileLink:alignment' ('%s' is not a valid alignment)",
s
s
), 2)
), 2)
Line 146: Line 146:
function data:border(hasBorder)
function data:border(hasBorder)
checkSelf(self, 'image:border')
checkSelf(self, 'fileLink:border')
checkType('image:border', 1, hasBorder, 'boolean', true)
checkType('fileLink:border', 1, hasBorder, 'boolean', true)
data.hasBorder = hasBorder
data.hasBorder = hasBorder
return self
return self
Line 153: Line 153:
function data:link(s)
function data:link(s)
checkSelf(self, 'image:link')
checkSelf(self, 'fileLink:link')
checkType('image:link', 1, s, 'string', true)
checkType('fileLink:link', 1, s, 'string', true)
data.theLink = s
data.theLink = s
return self
return self
Line 160: Line 160:
function data:alt(s)
function data:alt(s)
checkSelf(self, 'image:alt')
checkSelf(self, 'fileLink:alt')
checkType('image:alt', 1, s, 'string', true)
checkType('fileLink:alt', 1, s, 'string', true)
data.theAlt = s
data.theAlt = s
return self
return self
Line 167: Line 167:
function data:page(num)
function data:page(num)
checkSelf(self, 'image:page')
checkSelf(self, 'fileLink:page')
checkType('image:page', 1, num, 'number', true)
checkType('fileLink:page', 1, num, 'number', true)
data.thePage = s
data.thePage = s
return self
return self
Line 174: Line 174:
function data:class(s)
function data:class(s)
checkSelf(self, 'image:class')
checkSelf(self, 'fileLink:class')
checkType('image:class', 1, s, 'string', true)
checkType('fileLink:class', 1, s, 'string', true)
data.theClass = s
data.theClass = s
return self
return self
Line 181: Line 181:
function data:lang(s)
function data:lang(s)
checkSelf(self, 'image:lang')
checkSelf(self, 'fileLink:lang')
checkType('image:lang', 1, s, 'string', true)
checkType('fileLink:lang', 1, s, 'string', true)
data.theLang = s
data.theLang = s
return self
return self
Line 188: Line 188:
function data:caption(s)
function data:caption(s)
checkSelf(self, 'image:caption')
checkSelf(self, 'fileLink:caption')
checkType('image:caption', 1, s, 'string', true)
checkType('fileLink:caption', 1, s, 'string', true)
data.theCaption = s
data.theCaption = s
return self
return self
Line 195: Line 195:
function data:render()
function data:render()
checkSelf(self, 'image:render')
checkSelf(self, 'fileLink:render')
local ret = {}
local ret = {}
-- Image name.
-- Filename
if not data.theName then
if not data.theName then
error('image:render: no image name was found')
error('fileLink:render: no filename was found')
end
end
ret[#ret + 1] = 'File:' .. data.theName
ret[#ret + 1] = 'File:' .. data.theName
-- Image format
-- Format
if data.theFormat and data.theFormatFilename then
if data.theFormat and data.theFormatFilename then
ret[#ret + 1] = data.theFormat .. '=' .. data.theFormatFilename
ret[#ret + 1] = data.theFormat .. '=' .. data.theFormatFilename
Line 277: Line 277:
readOnlyFields[field] = true
readOnlyFields[field] = true
end
end
readOnlyFields.theName = nil -- This is set if a filename is given to image.new, so remove it.
readOnlyFields.theName = nil -- This is set if a filename is given to fileLink.new, so remove it.
local function restrictedFieldError(key, restriction)
local function restrictedFieldError(key, restriction)
error(string.format(
error(string.format(
"image object field '%s' is %s",
"fileLink object field '%s' is %s",
tostring(key),
tostring(key),
restriction
restriction
Line 321: Line 321:
end
end


return image
return fileLink

Revision as of 15:21, 30 May 2014

This module is used to construct wikitext links to files. It is primarily useful for templates and modules that use complicated logic to make file links. Simple file links should be made with wikitext markup directly, as it uses less resources than calling this module. For help with wikitext file markup please refer to the documentation at mediawiki.org.

Usage from wikitext

From wikitext, this module should be called from a template, usually {{file link}}. Please see the template page for documentation. However, it can also be called using the syntax {{#invoke:File link|main|arguments}}.

Usage from Lua

First, you need to import the module.

local mFileLink = require('Module:File link')

Then you can make file links using the _main function.

mFileLink._main(args)

args is a table of arguments that can have the following keys:

  • file - the filename. (required)
  • format - the file format, e.g. 'thumb', 'thumbnail', 'frame', 'framed', or 'frameless'.
  • formatfile - a filename to specify with the 'thumbnail' format option. The filename specified will be used instead of the automatically generated thumbnail.
  • border - set this to true or "yes" (or any other value recognized as true by Module:Yesno) to set a border for the image.
  • location - the horizontal alignment of the file, e.g. 'right', 'left', 'center', or 'none'.
  • alignment - the vertical alignment of the file, e.g. 'baseline', 'middle', 'sub', 'super', 'text-top', 'text-bottom', 'top', or 'bottom'.
  • size - the size of the image, e.g. '100px', 'x100px' or '100x100px'.
  • upright - the 'upright' parameter, used for setting the size of tall and thin images.
  • link - the page that the file should link to. Use the blank string to suppress the default link to the file description page.
  • alt - the alt text. Use the blank string to suppress the default alt text.
  • caption - a caption for the file.
  • page - sets a page number for multi-paged files such as PDFs.
  • class - adds a class parameter to image links. The MediaWiki software adds this parameter to the class="..." attribute of the image's <img /> element when the page is rendered into HTML.
  • lang - adds a language attribute to specify what language to render the file in.
  • start - specifies a start time for audio and video files.
  • end - specifies an end time for audio and video files.
  • thumbtime - specifies the time to use to generate the thumbnail image for video files.

To see the effect of each of these parameters, see the images help page on mediawiki.org.

Examples

With the file only:

mFileLink.main{file = 'Example.png'}
-- Renders as [[File:Example.png]]

With format, size, link and caption options:

mFileLink.main{
	file = 'Example.png',
	format = 'thumb',
	size = '220px',
	link = 'Wikipedia:Sandbox',
	caption = 'An example.'
}
-- Renders as [[File:Example.png|thumb|220px|link=Wikipedia:Sandbox|An example.]]

With format, size, and border:

mFileLink.main{
	file = 'Example.png',
	format = 'frameless',
	size = '220px',
	border = true
}
-- Renders as [[File:Example.png|frameless|border|220px]]



-- This module provides a library for formatting file wikilinks.

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

local fileLink = {}

function fileLink.new(filename)
	checkType('fileLink.new', 1, filename, 'string', true)
	local obj, data = {}, {}
	
	local checkSelf = libraryUtil.makeCheckSelfFunction(
		'fileLink',
		'fileLink',
		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, 'fileLink:name')
		checkType('fileLink:name', 1, s, 'string')
		data.theName = s
		return self
	end
	
	function data:format(s, filename)
		checkSelf(self, 'fileLink: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(
				"bad argument #1 to 'fileLink:format' ('%s' is not a valid format)",
				s
			), 2)
		end
		return self
	end

	local function sizeError(methodName)
		-- Used for formatting duplication errors in size-related methods.
		error(string.format(
			"duplicate size argument detected in '%s'"
			.. " ('upright' cannot be used in conjunction with height or width)",
			methodName
		), 3)
	end
	
	function data:width(px)
		checkSelf(self, 'fileLink:width')
		checkType('fileLink:width', 1, px, 'number', true)
		if px and data.isUpright then
			sizeError('fileLink:width')
		end
		data.theWidth = px
		return self
	end
	
	function data:height(px)
		checkSelf(self, 'fileLink:height')
		checkType('fileLink:height', 1, px, 'number', true)
		if px and data.isUpright then
			sizeError('fileLink:height')
		end
		data.theHeight = px
		return self
	end
	
	function data:upright(isUpright, factor)
		checkSelf(self, 'fileLink:upright')
		checkType('fileLink:upright', 1, isUpright, 'boolean', true)
		checkType('fileLink:upright', 2, factor, 'number', true)
		if isUpright and (data.theWidth or data.theHeight) then
			sizeError('fileLink:upright')
		end
		data.isUpright = isUpright
		data.uprightFactor = factor
		return self
	end
	
	function data:resetSize()
		checkSelf(self, 'fileLink:resetSize')
		for i, field in ipairs{'theWidth', 'theHeight', 'isUpright', 'uprightFactor'} do
			data[field] = nil
		end
		return self
	end
	
	function data:location(s)
		checkSelf(self, 'fileLink: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
			error(string.format(
				"bad argument #1 to 'fileLink:location' ('%s' is not a valid location)",
				s
			), 2)
		end
		return self
	end
	
	function data:alignment(s)
		checkSelf(self, 'fileLink:alignment')
		checkType('fileLink:alignment', 1, s, 'string', true)
		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, 'fileLink:border')
		checkType('fileLink:border', 1, hasBorder, 'boolean', true)
		data.hasBorder = hasBorder
		return self
	end
	
	function data:link(s)
		checkSelf(self, 'fileLink:link')
		checkType('fileLink:link', 1, s, 'string', true)
		data.theLink = s
		return self
	end
	
	function data:alt(s)
		checkSelf(self, 'fileLink:alt')
		checkType('fileLink:alt', 1, s, 'string', true)
		data.theAlt = s
		return self
	end
	
	function data:page(num)
		checkSelf(self, 'fileLink:page')
		checkType('fileLink:page', 1, num, 'number', true)
		data.thePage = s
		return self
	end
	
	function data:class(s)
		checkSelf(self, 'fileLink:class')
		checkType('fileLink:class', 1, s, 'string', true)
		data.theClass = s
		return self
	end
	
	function data:lang(s)
		checkSelf(self, 'fileLink:lang')
		checkType('fileLink:lang', 1, s, 'string', true)
		data.theLang = s
		return self
	end
	
	function data:caption(s)
		checkSelf(self, 'fileLink:caption')
		checkType('fileLink:caption', 1, s, 'string', true)
		data.theCaption = s
		return self
	end
	
	function data:render()
		checkSelf(self, 'fileLink: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
		ret[#ret + 1] = data.theAlignment
		
		-- Size
		if data.isUpright and data.uprightFactor then
			ret[#ret + 1] = 'upright=' .. tostring(data.uprightFactor)
		elseif data.isUpright then
			ret[#ret + 1] = 'upright'
		elseif data.theWidth and data.theHeight then
			ret[#ret + 1] = string.format('%dx%dpx', data.theWidth, data.theHeight)
		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, and lang.
		do
			local namedParameters = {'link', 'alt', 'page', 'class', 'lang'}
			for i, parameter in ipairs(namedParameters) do
				local dataField = 'the' .. parameter:sub(1, 1):upper() .. parameter:sub(2, -1)
				local value = data[dataField]
				if value then
					ret[#ret + 1] = parameter .. '=' .. tostring(value)
				end
			end
		end

		-- Caption
		ret[#ret + 1] = data.theCaption
		
		return string.format('[[%s]]', table.concat(ret, '|'))
	end
	
	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

return fileLink