Module:FreedImg

-- This is an module to implement FreedImg -- Argument to the functions are as described on Template:FI and Template:FIS. -- -- 2021-01-13:	Implementation copying original FI and FIS templates, but with --             added max-width handing to reduce image sizes for very large images -- 2021-01-16:	Removed complex HTML and reduce complexity -- 2021-01-21: Further reduce complexity of captions and allow captions to contain --             divs (e.g. centered text) -- 2021-06-03  Handle blank and missing images require('strict')

local p = {} --p stands for package local getArgs = require('Module:Arguments').getArgs

-- this is a limit on the max default image size to avoid multi-MB full-size images -- being loaded. if the image is smaller than this, it is loaded at full resolution local max_image_size = 1000 -- this is a nominal "max" screen size used when computing the maximum size of an -- image with a width in percent. For example, on a 2048px screen, an image at -- 10% will be 204px at most, so there's no point loading a 1000px image. local max_screen_size = 2048

local function arg_or_nil(args, name) if args[name] ~= nil and args[name] ~= "" then return args[name] end return nil end

-- add to a table if the variable is not nil or empty local function add_if(t, key, var) if var ~= nil and var ~= "" then t[key] = var end end

-- append a CSS style to a table so we can use mw.html:css on it local function add_style_to_table(t, s)	if s == nil or s == "" then return end for rule in string.gmatch(s, "([^;]+)") do   	local idx, _ idx, _ = string.find(rule, ":") if idx then t[string.sub(rule, 0, idx - 1)] = string.sub(rule, idx + 1) end end end

local function construct_image_markup(img_name, args)

-- get the image info -- NOTE: we will use the file attribute, this is an expensive function local img_title = mw.title.makeTitle("File", img_name)

-- Whatever we were given it was not a valid file name if not img_title then local error = "The specified image (" .. img_name .. ") is invalid" return require('Module:Error').error({message = error}) end

-- The filename given does not exist if not img_title.file.exists then local error = "The specified image (" .. img_name .. ") does not exist" return require('Module:Error').error({message = error}) end

local img_width_px if arg_or_nil(args, "imgwidth") then -- the user told us what they want -- This assumes the imgwidth will be specified in pixels, which isn't always the case, Nor does the template documentation mention this. img_width_px = string.gsub(args['imgwidth'], "px", "") elseif arg_or_nil(args, "width") then -- if the width parameter is in px or %, use that to get the image as the -- image is at most the size of the container local arg_px_width = string.match(args["width"], '(%d+)px$') local arg_pc_width = string.match(args["width"], '(%d+)%%$') if arg_px_width then -- use what the parameter said img_width_px = arg_px_width elseif arg_pc_width then -- use a nominal huge screen and find the image size upper bound img_width_px = math.floor((max_screen_size * tonumber(arg_pc_width)) / 100) -- still limit to the max size as well img_width_px = math.min(max_image_size, img_width_px) end end if img_width_px == nil then -- use the default size, or the image size, whichever is smaller img_width_px = math.min(img_title.file["width"], max_image_size) end -- construct the image markup we will use local img_markup = "" return img_markup end

local function construct_caption(parent, is_div, args, caption, class) local tag = is_div and "div" or "span" local pstyle = {} add_if(pstyle, "text-align", args["talign"]) add_if(pstyle, "margin-right", args["tmright"]) add_if(pstyle, "margin-left", args["tmleft"]) add_if(pstyle, "text-indent", args["indent"]) add_style_to_table(pstyle, arg_or_nil(args, "tstyle")) local para = parent:tag(tag) para :css(pstyle) :addClass("imgCaption wst-freedimg-caption") :wikitext(caption) -- additional classes if class then para:addClass(class) end

return para end

local function freedImg(is_div, args) local cats = {}

local img_markup -- construct the image markup we will use if args['type'] == "math" or args['type'] == "score" or args['type'] == "user" then -- math, score and user just place the markup directly img_markup = args["file"] elseif args.file == nil then local error = "The file parameter must be given (use \"missing\" if the image needs to be added later)" return require('Module:Error').error({message = error}) elseif args.file == "missing" then img_markup = mw.html.create("span") :addClass("wst-freedimg-missing") :wikitext('An image should appear at this position in the text.') img_markup = tostring(img_markup) table.insert(cats, "Pages with missing images") elseif args.file == "removed" then img_markup = mw.html.create("span") :addClass("wst-freedimg-missing") :wikitext('A non free image has been removed. It can be viewed in the original at '.. args["srcdoc"] .. '.' ) img_markup = tostring(img_markup) table.insert(cats, "Pages with redacted images") else img_markup = construct_image_markup(args["file"], args) end local outer_tag = is_div and "div" or "span" local caption_tag = is_div and "p" or "span"

local outer_div_class = {"freedImg", "wst-freedimg"} if arg_or_nil(args, "cclass") then table.insert(outer_div_class, args["cclass"]) end

local outer_div_style = {} add_if(outer_div_style, "width", args["width"]) add_if(outer_div_style, "margin-right", args["margin-right"]) add_if(outer_div_style, "margin-left", args["margin-left"]) add_if(outer_div_style, "float", args["float"]) add_if(outer_div_style, "clear", args["clear"])

if not is_div then outer_div_style["display"] = "inline-block" end add_style_to_table(outer_div_style, args["cstyle"])

local outer = mw.html.create(outer_tag) outer :addClass(table.concat(outer_div_class, " ")) :css(outer_div_style) -- add the top caption, if there is one, to the outer div if arg_or_nil(args, 'top-caption') then construct_caption(outer, is_div, args, args['top-caption'], 'wst-freedimg-caption-top') end

outer:wikitext(img_markup)

-- add the bottom caption, if there is one, to the outer div if arg_or_nil(args, 'caption') then construct_caption(outer, is_div, args, args['caption'], 'wst-freedimg-caption-bottom') end outer = tostring(outer) for k, v in pairs(cats) do outer = outer .. ""	end

return outer

end -- function freedimg

--[=[ Construct a "block" FreedImg ]=] function p.freedImg(frame) local args = getArgs(frame) return freedImg(true, args) end

--[=[ Construct an "inline" FreedImg ]=] function p.freedImg_span(frame) local args = getArgs(frame) return freedImg(false, args) end

return p