Module:Bar

require('Module:Lua class')
require('strict')

local frame = mw.getCurrentFrame()
local metatable = {	-- Append to array by calling it
	__call = function (t, v) t[#t+1] = v end,
	__tostring = function(t) return table.concat(t) end
}
local function notblank(v) return (v or '') ~= '' end
local function ifblank(v, a) return notblank(v) and v or a end

local BarBox = class('BarBox', {

	_css = 'Module:Bar/styles.css',

	__init = function (self, args)
		self.css			 = args[1]  or args.css
		self.float			 = args[2]  or args.float or 'none'
		self.backgroundcolor = args[3]  or args.backgroundcolor or 'white'
		self.borderwidth	 = args[4]  or args.borderwidth or '1'
		self.style			 = args[5]  or args.style
		self.width			 = args[6]  or args.width-- or 'auto'
		self.barwidth		 = args[7]  or args.barwidth or '100px'
		self.lineheight		 = args[8]  or args.lineheight-- or '1.6'
		self.title			 = args[9]  or args.title
		self.titlebar		 = args[10] or args.titlebar-- or 'none'
		self.left1			 = args[11] or args.left1
		self.left2			 = args[12] or args.left2
		self.right1			 = args[13] or args.right1
		self.right2			 = args[14] or args.right2
		self.bars			 = args[15] or args.bars
		self.caption		 = args[16] or args.caption -- deprecated
		self.footer			 = args[17] or args.footer or args[16] or args.caption
	end,

	create = function (cls, args)
		args = mw.clone(args)
		args.float	  = args.float and args.float:lower()
		args.width	  = tonumber(args.width) and args.width .. 'px' or args.width and args.width:lower()
		args.barwidth = tonumber(args.barwidth) and args.barwidth .. 'px' or args.barwidth and args.barwidth:lower()
		return cls(args)
	end,

	_sDefaultAlign = 'lrlr',
	_tDefaultAlign = {false, 'r', false, 'r'},

	_setAlign = function (obj, align)
		obj._alignClasses = {}
		for i, d in ipairs(obj._tDefaultAlign) do
			local a = align:sub(i,i)
			if a == 'l' then
				a = false
			elseif a == 'd' then
				a = d
			elseif a ~= 'c' and a ~= 'r' then
				error('unrecognized align[' .. i .. ']')
			end
			obj._alignClasses[i] = a and 'class=bb-' .. a
		end
	end,

	html = function (self)
		local output = setmetatable({}, metatable)

		output(frame:extensionTag('templatestyles', '', {src=self._css}) .. '\n')
		output(self.css and frame:extensionTag('templatestyles', '', {src=self.css}) .. '\n' or '')

		local class = 'barbox'
		if self.float == 'left' or self.float == 'right' then
			class = class .. ' t' .. self.float
		end

		output('<div class="' .. class .. '" style="background:' ..
			self.backgroundcolor .. '; border:' .. self.borderwidth .. 'px solid silver'
		)
		if self.float == 'center' then output('; margin:0 auto') end
		if self.width then output('; width:' .. self.width) end
		if self.style then output('; ' .. self.style) end
		output('">\n')
			output('{|')
			if self.lineheight then	output(' style="line-height:' .. self.lineheight .. '"') end
			output('\n')
			if self.title then output(
				'|+ class=bb-default' .. (self.titlebar and ' style="background:' .. self.titlebar .. '"' or '') .. ' |\n' ..
				self.title .. '\n'
			) end

			output('|- class=bb-default style="font-size:88%; min-height:4px"\n')
				if self._alignClasses then -- same as self.__class._alignClasses
					self._alignClasses = self._alignClasses
					self.__class._alignClasses = nil
				else
					self._setAlign(self, self._sDefaultAlign)
				end

				local attributes =
					not self.left2 and 'colspan=2' .. (self._alignClasses[1] and ' ' .. self._alignClasses[1] or '') or self._alignClasses[1]
				output('!' .. (attributes and attributes .. '|' or '') .. (self.left1 or ' '))
				output(self.left2 and '!!' .. (self._alignClasses[2] and self._alignClasses[2] .. '|' or '') .. self.left2 or '')
				output('!!style="width:' .. self.barwidth .. '"| ')
				attributes =
					not self.right2 and 'colspan=2' .. (self._alignClasses[4] and ' ' .. self._alignClasses[4] or '') or self._alignClasses[3]
				output('!!' .. (attributes and attributes .. '|' or '') .. (self.right1 or self.right2 and ' ' or ''))
				output(self.right2 and '!!' .. (self._alignClasses[4] and self._alignClasses[4] .. '|' or '') .. self.right2 or '')
			output('\n')

			if self.bars then output(self.bars .. '\n') end

			if self.caption then output('\n[[Category:Pages using bar box with deprecated caption parameter]]') end
			
			if self.footer then output(
				'|- class=bb-default\n| colspan=5 style="padding:5px 0" | ' .. -- <p> is created if \n precedes the footer
				self.footer .. '\n'
			) end
		output('|}\n</div>')

		return tostring(output)
	end,

	__tostring = function (self)
		return self.html()
	end,

	percent = function (args)
		local output = setmetatable({'|-'}, metatable)
		local percentage = (args[3] or '0') .. '%'
		if args.bg then output(args.bg and 'style="background:' .. args.bg .. '"') end
		output('\n')
			output('|colspan=2 class=bb-min8|' .. (args[1] or ' '))
			output('||class=bb-b|')
				output('<div style="background:' .. (args[2] or 'gray') .. '; width:' .. percentage .. '">&#8203;</div>')
			output('||' .. (args.note and '' or 'colspan=2 class=bb-r|') .. (args[4] or percentage))
			if args.note then output('||class=bb-r|' .. args.note) end

		return tostring(output)
	end,

	pixel = function (args)
		local output = setmetatable({'|-'}, metatable)
		local pixels = (args[3] or '0')
		if args.bg then output('style="background:' .. args.bg .. '"') end
		output('\n')
			output('|colspan=2|' .. (args[1] or ' '))
			output('||class=bb-b|')
				output('<div style="background:' .. (args[2] or 'gray') .. '; width:' .. pixels .. 'px">&#8203;</div>')
			output('||class="bb-min3' .. (args.note and '"' or ' bb-r" colspan=2') .. '|' .. (args[5] or pixels .. (args[4] or '')))
			if args.note then output('||class=bb-r|' .. args.note) end

		return tostring(output)
	end,

	stacked = function (cls, args)
		local output = setmetatable({'|-'}, metatable)

		if args.id then
			output('class="mw-collapsible' ..
				(args.collapsed and ' mw-collapsed' or '') ..
				'" id=mw-customcollapsible-' .. args.id
			)
		end
		output('\n')
			if not cls._alignClasses then
				cls._setAlign(cls, args.align and args.align:lower() or cls._sDefaultAlign)
			end

			local attributes =
				not args.note1 and 'colspan=2' .. (cls._alignClasses[1] and ' ' .. cls._alignClasses[1] or '') or cls._alignClasses[1]
			output('|' .. (attributes and attributes .. '|' or '') .. (args[1] or ' '))
			if args.note1 then
				output('||' .. (cls._alignClasses[2] and cls._alignClasses[2] .. '|' or '') .. args.note1)
			end
			output('||class=bb-b|')

				local len = 0 -- can't use #args because of [[Module:Arguments#Known limitations]]
				for k in pairs(args) do
					local idx = tonumber(k) or 0
					if idx > len then len = idx end
				end

				if args.bkgclasses then -- used when wikitext minimization is essential
					for i = 1, len-2 do
						local width, delim, title --is delim reset every cycle?
						width = args[i+2] or 0
						width = tonumber(('%.2f'):format(width))
						if width > 0 then
							if not delim then -- assuming title types are consistent
								delim = tonumber(args['title' .. i]) and '' or '"'
							end
							title = args['title' .. i] and ' title=' .. delim .. args['title' .. i] .. delim or ''
							output(
								'<div' .. title .. ' class=' .. args.bkgclasses[i] .. ' style=width:' .. width .. 'px></div>'
							)
						end
					end
				else
					for i = 1, (len-2) / 2 do
						local width, title, background
						width = args[2*i + 2] or 0
						width = tonumber(('%.2f'):format(width))
						if width > 0 then
							title = args['title' .. i] and ' title="' .. args['title' .. i] .. '"' or ''
							background = args[2*i + 1] or 'gray'
							output(
								'<div' .. title .. ' style="background:' .. background .. ';width:' .. width .. 'px"></div>'
							)
						end
					end
				end

				if #output == 4 then output(' ') end

			attributes =
				not args.note2 and 'colspan=2' .. (cls._alignClasses[4] and ' ' .. cls._alignClasses[4] or '') or cls._alignClasses[3]
			output('||')
			if attributes then output(attributes .. '|') end
			if (args[2] or args.note2) then output(' ') end
			if args.note2 then
				output('||')
				if cls._alignClasses[4] then output (cls._alignClasses[4] .. '|') end
				output(args.note2)
			end

		return tostring(output)
	end,

	gap = function (args)
		local output = setmetatable({'|-\n'}, metatable)
		local height = tonumber(args.height) and args.height .. 'px' or args.height and args.height:lower() or '10px'

			output('|colspan=5 style="height:' .. height .. '"|' .. (args[1] or ''))

		return tostring(output)
	end,
	
	['table'] = function (args)
		local function expr(v, a)
			v = frame:callParserFunction('formatnum', {ifblank(v, a), 'R'})
			v = frame:callParserFunction('#expr', v)
			return tonumber(ifblank(v, a)) or a
		end
		
		local barValue = expr(args[1], 0)	
		local scale = expr(args[3], 1)
		local width = math.abs(scale * barValue)
		local height = ifblank(args[4], '2ex')

		local output = setmetatable({}, metatable)
		-- Handle the display of the value and unit (parameters 1 and 2) --
		if notblank(args[2]) then -- If a unit (parameter 2) is provided
			local titleparts = mw.text.split(args[2], '/', true)
			if notblank(titleparts[2]) then -- If unit has multiple parts (e.g., 'km|mi'), attempt conversion
				if notblank(titleparts[1]) then -- If unit has a single part, display value and unit directly
					output((args[1] or '') .. args[2])
				else -- Otherwise, use the convert template to handle unit conversion
					local cvtArgs = {
						[1] = tostring(barValue),
						[2] = titleparts[2] or '',
						[3] = titleparts[3] or '',
						[4] = titleparts[4] or '',
						abbr= 'on'
					}
					local convert = require('Module:Convert')._convert
					output(convert({}, cvtArgs))
				end
			else -- If unit is simple, display value and unit without conversion
				output((args[1] or '') .. args[2])
			end
		else -- If no unit is provided, display value or default to em dash
			output(ifblank(args[1], '&mdash;'))
		end
		-- Handle the bar visualization --
		local sortString = 'data-sort-value="' .. barValue .. '"|'
		local barString = sortString ..
			'<div style="width:' .. width .. 'px;height:' .. height .. 
			';background:#aaa;color:inherit;' .. (args[5] or '') ..
			'" title="' .. barValue .. '">&nbsp;</div>'
		
		if scale < 0 then -- If scale (parameter 3) is negative, add extra column
			output('||')
			if barValue < 0 then -- If value (parameter 1) is negative, align bar to the right & scale
				output('align="right" ' .. barString)
			else -- output hidden sort key for sortable wikitables
				output(sortString)
			end
		end
		
		output('\n|')
		
		if barValue > 0 then -- if display value is positive, align bar to the left
			output('align="left" ' .. barString)
		else -- output hidden sort key for sortable wikitables
			output(sortString)
		end
		
		return tostring(output)
	end,

	__classmethods = {'create', 'stacked'},
	__staticmethods = {'_setAlign', 'percent', 'pixel', 'gap'},
	__slots = {'_alignClasses'}
})


local getArgs = require('Module:Arguments').getArgs

local p = {BarBox}

function p.box(frame)
	local args = getArgs(frame)
	local box = BarBox.create(args)
	return tostring(box)
end

function p.percent(frame)
	local args = getArgs(frame)
	return BarBox.percent(args)
end

function p.pixel(frame)
	local args = getArgs(frame)
	return BarBox.pixel(args)
end

function p.log(frame)
	local args = getArgs(frame)
	local outArgs = {[1] = args[2], [2] = args[3]}
	outArgs[3] = math.log((tonumber(args[4]) ~= nil) and (args[4] + 1) or 100)/
		math.log((tonumber(args[1]) ~= nil) and args[1] or 2)*30
	outArgs[5] = ifblank(args[6], ((args[4] or '') .. (args[5] or '')))
	return BarBox.pixel(outArgs)
end

function p.stacked(frame)
	local yesno = require('Module:Yesno')
	local args = getArgs(frame, {
		valueFunc = function (key, value)
			if value then
				if key == 'collapsed' then
					return yesno(value)
				elseif key == 'bkgclasses' then
					return mw.text.jsonDecode(value) -- string to table
				end
				value = mw.text.trim(value)
				if value ~= '' then
					return value
				end
			end
			return nil
		end
	})
	return BarBox.stacked(args)
end

function p.gap(frame)
	local args = getArgs(frame)
	return BarBox.gap(args)
end

function p.bartable(frame)
	local args = frame.args
	return BarBox['table'](args)
end
p['table'] = p.bartable

function p.tableTemplate(frame)
	local args = frame:getParent().args
	return BarBox['table'](args)
end

return p

Content Disclaimer

Informasi ini disarikan dari Wikipedia dan disajikan kembali untuk tujuan edukasi. Konten tersedia di bawah lisensi CC BY-SA 3.0. Kami tidak bertanggung jawab atas ketidakakuratan data yang bersumber dari kontribusi publik tersebut.

  1. The information displayed on this website is sourced in part or in whole from Wikipedia and has been adapted for the purpose of restating it. We strive to provide accurate and relevant information, however:
  2. There is no guarantee of absolute accuracy. Wikipedia is an open, collaborative project that can be edited by anyone, so information is subject to change.
  3. It is not intended to constitute professional advice. The content displayed is for informational and educational purposes only. For important decisions (e.g., medical, legal, or financial), please consult a professional.
  4. Content copyright. Wikipedia is licensed under the Creative Commons Attribution-ShareAlike License (CC BY-SA). This means that content may be reused with appropriate attribution and shared under a similar license.
  5. Responsible use. Any risk arising from the use of information from this website is entirely the responsibility of the user.