Permanently protected module
From Wikipedia, the free encyclopedia


-- implements [[template:multiple image]]

local p = {}



local autoscaledimages

local nonautoscaledimages



local function isnotempty(s)

	return s and s:match( '^%s*(.-)%s*$' ) ~= ''

end



local function removepx(s)

	return tostring(s or ''):match('^(.*)[Pp][Xx]%s*$') or s

end



local function getdimensions(s, w, h)

	if tonumber(w) and tonumber(h) then

		nonautoscaledimages = true

		return tonumber(w), tonumber(h)

	end

	local file = s and mw.title.new('File:' .. mw.uri.decode(mw.ustring.gsub(s,'%|.*$',''), 'WIKI'))

	file = file and file.file or {width = 0, height = 0}

	w = tonumber(file.width) or 0

	h = tonumber(file.height) or 0

	autoscaledimages = true

	return w, h

end



local function renderImageCell(image, width, height, link, alt, thumbtime, caption, textalign, istyle, border)

	local root = mw.html.create('')



	local altstr = '|alt=' .. (alt or '')

	local linkstr = link and ('|link=' .. link) or ''

	local widthstr = '|' .. tostring(width) .. 'px'

	local thumbtimestr = ''



	if widthstr == '|-nanpx' then

		widthstr = ''

	end

	if isnotempty( thumbtime ) then

		thumbtimestr = '|thumbtime=' .. thumbtime

	end



	local imagediv = root:tag('div')

	imagediv:addClass((border ~= 'infobox') and 'thumbimage' or nil)

	imagediv:cssText(istyle)

	if( height ) then

		imagediv:css('height', tostring(height) .. 'px')

		imagediv:css('overflow', 'hidden')

	end

	imagediv:wikitext('[[file:' .. image .. widthstr .. linkstr .. altstr .. thumbtimestr .. ']]')

	if isnotempty(caption) then

		local captiondiv = root:tag('div')

		captiondiv:addClass((border ~= 'infobox') and 'thumbcaption' or nil)

		if isnotempty(textalign) then

			captiondiv:addClass('text-align-' .. textalign)

		end

		captiondiv:wikitext(caption)

	end

	return tostring(root)

end



local function getWidth(w1, w2)

	local w

	if isnotempty(w1) then

		w = tonumber(w1)

	elseif isnotempty(w2) then

		w = tonumber(w2)

	end

	return w or 200

end



local function getPerRow(pstr, ic)

	-- split string into array using any non-digit as a dilimiter

	local pr = mw.text.split(pstr or '', '[^%d][^%d]*')

	-- if split failed, assume a single row

	if (#pr < 1) then

		pr = {tostring(ic)}

	end

	-- convert the array of strings to an array of numbers,

	-- adding any implied/missing numbers at the end of the array

	local r = 1

	local thisrow = tonumber(pr1 or ic) or ic

	local prownum = {}

	while( ic > 0 ) do

		prownumr = thisrow

		ic = ic - thisrow

		r = r + 1

		-- use the previous if the next is missing and

		-- make sure we don't overstep the number of images

		thisrow = math.min(tonumber(prr or thisrow) or ic, ic)

	end

	return prownum

end



local function renderMultipleImages(frame)

	local pargs = frame:getParent().args

	local args = frame.args

	local width = removepx(pargs'width' or '')

	local dir = pargs'direction' or ''

	local border = pargs'border' or args'border' or ''

	local align = pargs'align' or args'align' or (border == 'infobox' and 'center' or '')

	local capalign = pargs'caption_align' or args'caption_align' or ''

	local totalwidth = removepx(pargs'total_width' or args'total_width' or '')

	local imgstyle = pargs'image_style' or args'image_style'

	local header = pargs'header' or pargs'title' or ''

	local footer = pargs'footer' or ''

	local imagegap = tonumber(pargs'image_gap' or '1') or 1

	local perrow = nil

	local thumbclass = {

		"left" = 'tleft',

		"none" = 'tnone',

		"center" = 'tnone',

		"centre" = 'tnone',

		"right" = 'tright'

		}



	-- find all the nonempty images

	local imagenumbers = {}

	local imagecount = 0

	for k, v in pairs( pargs ) do

		local i = tonumber(tostring(k):match( '^%s*image([%d]+)%s*$' ) or '0')

		if( i > 0 and isnotempty(v) ) then

			table.insert( imagenumbers, i)

			imagecount = imagecount + 1

		end

	end



	-- sort the imagenumbers

	table.sort(imagenumbers)



	-- create an array with the number of images per row

	perrow = getPerRow(dir == 'vertical' and '1' or pargs'perrow'], imagecount)



	-- compute the number of rows

	local rowcount = #perrow



	-- store the image widths and compute row widths and maximum row width

	local heights = {}

	local widths = {}

	local widthmax = 0

	local widthsum = {}

	local k = 0

	for r=1,rowcount do

		widthsumr = 0

		for c=1,perrowr do

			k = k + 1

			if( k <= imagecount ) then

				local i = imagenumbersk

				if( isnotempty(totalwidth) ) then

					widthsk], heightsk = getdimensions(pargs'image' .. i], pargs'width' .. i], pargs'height' .. i])

				else

					widthsk = getWidth(width, pargs'width' .. i])

				end

				widthsumr = widthsumr + widthsk

			end

		end

		widthmax = math.max(widthmax, widthsumr])

	end



	-- make sure the gap is non-negative

	if imagegap < 0 then imagegap = 0 end



	-- if total_width has been specified, rescale the image widths

	if( isnotempty(totalwidth) ) then

		totalwidth = tonumber(totalwidth)

		widthmax = 0

		local k = 0

		for r=1,rowcount do

			local koffset = k

			local tw = totalwidth - (3 + imagegap) * (perrowr - 1) - 12

			local ar = {}

			local arsum = 0

			for j=1,perrowr do

				k = k + 1

				if( k<= imagecount ) then

					local i = imagenumbersk

					local h = heightsk or 0

					if (h > 0) then

						arj = widthsk/h

						heightsk = h

					else

						arj = widthsk/100

					end

					arsum = arsum + arj

				end

			end

			local ht = tw/arsum

			local ws = 0

			k = koffset

			for j=1,perrowr do

				k = k + 1

				if( k<= imagecount ) then

					local i = imagenumbersk

					widthsk = math.floor(arj*ht + 0.5)

					ws = ws + widthsk

					if heightsk then

						heightsk = math.floor(ht)

					end

				end

			end

			widthsumr = ws

			widthmax = math.max(widthmax, widthsumr])

		end

	end



	-- start building the array of images, if there are images

	if( imagecount > 0 ) then

		-- compute width of outer div

		local bodywidth = 0

		for r=1,rowcount do

			if( widthmax == widthsumr ) then

				bodywidth = widthmax + (3 + imagegap) * (perrowr - 1) + 12

			end

		end

		-- The body has a min-width of 100, which needs to be taken into account on specific widths

		bodywidth = math.max( 100, bodywidth - 8);



		local bg = pargs'background color' or ''

		-- create the array of images

		local root = mw.html.create('div')

		root:addClass('thumb')

		root:addClass('tmulti')

		-- root:addClass('tmulti-sandbox')

		root:addClass(thumbclassalign or 'tright')



		if( align == 'center' or align == 'centre' ) then

			root:addClass('center')

		end

		if( bg ~= '' ) then

			root:css('background-color', bg)

		end



		local div = root:tag('div')

		div:addClass((border ~= 'infobox') and 'thumbinner multiimageinner' or 'multiimageinner')

		div:css('width', tostring(bodywidth) .. 'px')

			:css('max-width', tostring(bodywidth) .. 'px')

		if( bg ~= '' ) then

			div:css('background-color', bg)

		end

		if( border == 'infobox' or border == 'none') then

			div:css('border', 'none')

		end

		-- add the header

		if( isnotempty(header) ) then

			div:tag('div')

				:addClass('trow')

				:tag('div')

					:addClass('theader')

					:css('text-align', pargs'header_align'])

					:css('background-color', 

						(pargs'header_background' ~= '') and pargs'header_background' or nil)

					:wikitext(header)

		end

		-- loop through the images

		local k = 0

		for r=1,rowcount do

			local rowdiv = div:tag('div'):addClass('trow');

			for j=1,perrowr do

				k = k + 1

				if( k <= imagecount ) then

					local imagediv = rowdiv:tag('div')

					imagediv:addClass('tsingle')

					if bg ~= '' then

						imagediv:css('background-color', bg);

					end

					if imagegap > 1 and k < imagecount then

						if dir == 'vertical' then

							imagediv:css('margin-bottom', tostring(imagegap) .. 'px')	

						elseif j < perrowr then

							imagediv:css('margin-right', tostring(imagegap) .. 'px')

						end

					end

					local i = imagenumbersk

					local img = pargs'image' .. i

					local w = widthsk

					imagediv:css('width', tostring(2 + w) .. 'px')

						:css('max-width', tostring(2 + w) .. 'px')

					imagediv:wikitext(renderImageCell(img, w, heightsk],

						pargs'link' .. i], pargs'alt' .. i],

						pargs'thumbtime' .. i], pargs'caption' .. i], capalign, imgstyle, border))

				end

			end

		end

		-- add the footer

		if( isnotempty(footer) ) then

			local falign = string.lower(pargs'footer_align' or args'footer_align' or '')

			falign = (falign == 'centre') and 'center' or falign

			div:tag('div')

				:addClass('trow')

				:css('display', (falign ~= '') and 'flow-root' or 'flex')

				:tag('div')

					:addClass((border ~= 'infobox') and 'thumbcaption' or nil)

					:css('text-align', (falign ~= '') and falign or nil)

					:css('background-color', 

						(pargs'footer_background' ~= '') and pargs'footer_background' or nil)

					:wikitext(footer)

		end

		return tostring(root)

	end

	return ''

end



function p.render( frame )

	autoscaledimages = false

	nonautoscaledimages = false



	return frame:extensionTag {name = 'templatestyles', args = {src = 'Multiple image/styles.css', wrapper = ".tmulti"}}

		.. renderMultipleImages( frame )

		.. (autoscaledimages and '[[Category:Pages using multiple image with auto scaled images]]' or '')

		.. (nonautoscaledimages and '[[Category:Pages using multiple image with manual scaled images]]' or '')

end



p'' = function( frame ) return p.render( frame:newChild{title = frame:getTitle()} ) end



return p