Permanently protected module
From Wikipedia, the free encyclopedia


-- Implement [[Template:Weather box]].



local _precision = require('Module:Math')._precision

local function precision(text)

	-- Input like 'Jan precipitation inch = trace' calls this with text = 'trace'

	-- which would cause _precision to throw an error since it is not numeric.

	-- Workaround: Return 0 as the precision if an error occurs.

	local success, result = pcall(_precision, text)

	if success then

		return result

	end

	return 0

end



local function stripToNil(text)

	-- If text is a non-empty string, return its trimmed content.

	-- Otherwise, return nothing (text is an empty string or is not a string).

	if type(text) == 'string' then

		return text:match('(%S.-)%s*$')

	end

end



local function isAny(args, suffix)

	local months = { 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' }

	for _, month in ipairs(months) do

		if stripToNil(argsmonth .. suffix]) then

			return true

		end

	end

end



local function makeLabel(args, options, is_first, base, what)

	local first

	if isAny(args, ' ' .. what .. ' cm') then

		first = 'cm'

	elseif isAny(args, ' ' .. what .. ' mm') then

		first = 'mm'

	else

		first = (what:sub(1, 4) == 'snow' or

			precision(args'Jan ' .. what .. ' inch' or '0') < 1)

				and 'cm'

				or 'mm'

	end

	local second = 'inches'

	if not stripToNil(args'metric first']) then

		first, second = second, first

	end

	if is_first then

		if options.wantSingleLine then

			first = first .. ' (' .. second .. ')'

		end

	else

		first = second

	end

	return base .. ' ' .. first

end



local function makeSources(frame, args)

	local source1 = stripToNil(args.source) or stripToNil(args'source 1'])

	local source2 = stripToNil(args'source 2']) or stripToNil(args'source2'])

	local result = '|-\n|colspan="14" style="text-align:center;font-size:95%;"|'

	local text

	if source1 or source2 then

		if source1 and source2 then

			text = 'Source 1: ' .. source1 .. '\n' .. result .. 'Source 2: ' .. source2

		else

			text = 'Source: ' .. (source1 and source1 or source2)

		end

	else

		text = frame:expandTemplate({ title = 'citation needed', args = {date = stripToNil(args.date)} })

	end

	return result .. text .. '\n|}'

end



local function wantSingle(parm)

	--------------------------------------------------------------------------------

	-- Result before July 2022 for single_line setting:

	-- blank/omitted : separate table rows for metric and imperial (two rows)

	-- N             : bug: only one row with either metric or imperial (not both)

	--                      but heading like "cm (inches)"

	-- Y/junk        : single row with both metric/imperial in same cell

	--------------------------------------------------------------------------------

	-- Intend changing in July 2022 so single_line=Y is the default and

	-- need single_line=N for separate lines.

	-- However, this release (1 July 2022) keeps blank/omitted as meaning "no"

	-- so the other large changes can be tested before switching the default.

	parm = (parm or ''):lower()

	return not (parm == 'no' or parm == 'n' or parm == '')

end



local function getDefinitions(frame, args, options)

	-- Return a list of tables or strings that define each row.

	local function _if(parm, a, b)

		return stripToNil(argsparm]) and a or b or ''

	end

	local function _ifset(parm, a)

		return stripToNil(argsparm]) and argsparm or a

	end

	local function _ifany(suffix)

		return isAny(args, suffix)

	end

	local function _ifSingle(a, b)

		return options.wantSingleLine and a or b or ''

	end

	local function _colorscheme(what, default)

		return stripToNil(argswhat .. ' colour']) or stripToNil(argswhat .. ' color']) or default

	end

	local function _margin()

		if stripToNil(args.margin) then

			return 'margin:' .. args.margin .. ';'

		end

		return ''

	end

	local location = _if('location', args.location, '{{{location}}}')  -- show "{{{location}}}" to alert editor if parameter is blank

	local navbarText

	if not stripToNil(args.open) then

		if stripToNil(args.name) then

			local navbar = require('Module:Navbar')._navbar

			navbarText = navbar({'Climate data for ' .. location, args.name, collapsible=1})

		end

	end

	return {



----------- HEADER ----------

'{| class="wikitable ' .. _if('open', '', 'mw-collapsible' .. _if('collapsed', ' mw-collapsed')) ..

'" style="width:' .. _ifset('width', 'auto') ..

'; text-align:center; line-height:1.2em;' ..

_margin() .. '"' ..

_if('open',

	'\n|+Climate data for ' .. location,

	'\n|-' ..

	'\n!colspan="14" | ' .. _if('name', navbarText, 'Climate data for ' .. location)

) ..

[=[



|-

!scope="row" |Month

!scope="col" |Jan

!scope="col" |Feb

!scope="col" |Mar

!scope="col" |Apr

!scope="col" |May

!scope="col" |Jun

!scope="col" |Jul

!scope="col" |Aug

!scope="col" |Sep

!scope="col" |Oct

!scope="col" |Nov

!scope="col" |Dec

!scope="col" style="border-left-width:medium" |Year

]=],



{---------- FIRST LINE MAXIMUM HUMIDEX ----------

	WANTROW = _ifany(' maximum humidex') and (_ifset('metric first') or options.wantSingleLine),

	mode = 'basic',

	group_name = 'maximum humidex',

	color_scheme = _colorscheme('temperature', 't'),

	scale_factor = '1',

	label = 'Record high [[humidex]]',

	annual_mode = 'max',

},

{---------- FIRST LINE RECORD HIGH TEMPERATURES ----------

	WANTROW = _ifany(' record high C') or _ifany(' record high F'),

	mode = 'temperature',

	group_name = 'record high',

	color_scheme = _colorscheme('temperature', 't'),

	scale_factor = '1',

	label = 'Record high °' .. _if('metric first', 'C', 'F') .. _ifSingle(' (°' .. _if('metric first', 'F', 'C') .. ')'),

	annual_mode = 'max',

},

{---------- FIRST-SECOND LINE AVG MONTHLY MAXIMUM TEMPERATURES ----------

	WANTROW = _ifany(' avg record high C') or _ifany(' avg record high F'),

	mode = 'temperature',

	group_name = 'avg record high',

	color_scheme = _colorscheme('temperature', 't'),

	scale_factor = '1',

	label = 'Mean maximum °' .. _if('metric first', 'C', 'F') .. _ifSingle(' (°' .. _if('metric first', 'F', 'C') .. ')'),

	annual_mode = 'max',

},

{---------- FIRST LINE MEAN DAILY MAXIMUM TEMPERATURES ----------

	WANTROW = _ifany(' high C') or _ifany(' high F'),

	mode = 'temperature',

	group_name = 'high',

	color_scheme = _colorscheme('temperature', 't'),

	scale_factor = '1',

	label = 'Mean daily maximum °' .. _if('metric first', 'C', 'F') .. _ifSingle(' (°' .. _if('metric first', 'F', 'C') .. ')'),

	annual_mode = 'avg',

},

{---------- FIRST LINE DAILY MEAN TEMPERATURES ----------

	WANTROW = _ifany(' mean C') or _ifany(' mean F'),

	mode = 'temperature',

	group_name = 'mean',

	color_scheme = _colorscheme('temperature', 't'),

	scale_factor = '1',

	label = 'Daily mean °' .. _if('metric first', 'C', 'F') .. _ifSingle(' (°' .. _if('metric first', 'F', 'C') .. ')'),

	annual_mode = 'avg',

},

{---------- FIRST LINE MEAN DAILY MINIMUM TEMPERATURES ----------

	WANTROW = _ifany(' low C') or _ifany(' low F'),

	mode = 'temperature',

	group_name = 'low',

	color_scheme = _colorscheme('temperature', 't'),

	scale_factor = '1',

	label = 'Mean daily minimum °' .. _if('metric first', 'C', 'F') .. _ifSingle(' (°' .. _if('metric first', 'F', 'C') .. ')'),

	annual_mode = 'avg',

},

{---------- FIRST-SECOND LINE AVG MONTHLY MINIMUM TEMPERATURES ----------

	WANTROW = _ifany(' avg record low C') or _ifany(' avg record low F'),

	mode = 'temperature',

	group_name = 'avg record low',

	color_scheme = _colorscheme('temperature', 't'),

	scale_factor = '1',

	label = 'Mean minimum °' .. _if('metric first', 'C', 'F') .. _ifSingle(' (°' .. _if('metric first', 'F', 'C') .. ')'),

	annual_mode = 'min',

},

{---------- FIRST LINE RECORD LOW TEMPERATURES ----------

	WANTROW = _ifany(' record low C') or _ifany(' record low F'),

	mode = 'temperature',

	group_name = 'record low',

	color_scheme = _colorscheme('temperature', 't'),

	scale_factor = '1',

	label = 'Record low °' .. _if('metric first', 'C', 'F') .. _ifSingle(' (°' .. _if('metric first', 'F', 'C') .. ')'),

	annual_mode = 'min',

},

{---------- FIRST LINE MINIMUM WIND CHILL ----------

	WANTROW = _ifany(' chill') and (_ifset('metric first') or options.wantSingleLine),

	mode = 'basic',

	group_name = 'chill',

	color_scheme = _colorscheme('temperature', 't'),

	scale_factor = '1',

	label = 'Record low [[wind chill]]',

	annual_mode = 'min',

},

{---------- FIRST LINE TOTAL PRECIPITATION ----------

	WANTROW = _ifany(' precipitation cm') or _ifany(' precipitation mm') or _ifany(' precipitation inch'),

	mode = 'precipitation',

	group_name = 'precipitation',

	color_scheme = _colorscheme('precipitation', 'p'),

	date_mode = true,

	scale_factor = '1',

	prefer_cm = precision(_ifset('Jan precipitation inch', '0')) < 1,

	label = makeLabel(args, options, true, 'Average [[precipitation]]', 'precipitation'),

	annual_mode = 'sum',

},

{---------- FIRST LINE RAINFALL ----------

	WANTROW = _ifany(' rain cm') or _ifany(' rain mm') or _ifany(' rain inch'),

	mode = 'precipitation',

	group_name = 'rain',

	color_scheme = _colorscheme('rain', 'p'),

	date_mode = true,

	scale_factor = '1',

	prefer_cm = precision(_ifset('Jan rain inch', '0')) < 1,

	label = makeLabel(args, options, true, 'Average rainfall', 'rain'),

	annual_mode = 'sum',

},

{---------- FIRST LINE SNOWFALL ----------

	WANTROW = _ifany(' snow cm') or _ifany(' snow mm') or _ifany(' snow inch'),

	mode = 'precipitation',

	group_name = 'snow',

	prefer_cm = true,

	color_scheme = _colorscheme('snow', 'p'),

	date_mode = true,

	scale_factor = '1',

	label = makeLabel(args, options, true, 'Average snowfall', 'snow'),

	annual_mode = 'sum',

},

{---------- FIRST LINE AVERAGE EXTREME SNOW DEPTH ----------

	WANTROW = _ifany(' snow depth cm') or _ifany(' snow depth mm') or _ifany(' snow depth inch'),

	mode = 'precipitation',

	group_name = 'snow depth',

	prefer_cm = true,

	color_scheme = _colorscheme('snow', 'p'),

	scale_factor = '0.2',

	label = makeLabel(args, options, true, 'Average extreme snow depth', 'snow depth'),

	annual_mode = 'max',

},

{---------- SECOND LINE MAXIMUM HUMIDEX ----------

	WANTROW = not options.wantSingleLine and _ifany(' maximum humidex'),

	mode = 'basic',

	group_name = 'maximum humidex',

	color_scheme = _colorscheme('temperature', 't'),

	scale_factor = '1',

	label = '[[Humidex]]',

	annual_mode = 'max',

	second_line = true,

},

{---------- SECOND LINE RECORD HIGH TEMPERATURES ----------

	WANTROW = not options.wantSingleLine and (_ifany(' record high C') or _ifany(' record high F')),

	mode = 'temperature',

	group_name = 'record high',

	second_line = true,

	color_scheme = _colorscheme('temperature', 't'),

	scale_factor = '1',

	label = 'Record high °' .. _if('metric first', 'F', 'C'),

	annual_mode = 'max',

},

{---------- SECOND LINE MEAN DAILY MAXIMUM TEMPERATURES ----------

	WANTROW = not options.wantSingleLine and (_ifany(' high C') or _ifany(' high F')),

	mode = 'temperature',

	group_name = 'high',

	second_line = true,

	color_scheme = _colorscheme('temperature', 't'),

	scale_factor = '1',

	label = 'Mean daily maximum °' .. _if('metric first', 'F', 'C'),

	annual_mode = 'avg',

},

{---------- SECOND LINE DAILY MEAN TEMPERATURES ----------

	WANTROW = not options.wantSingleLine and (_ifany(' mean C') or _ifany(' mean F')),

	mode = 'temperature',

	group_name = 'mean',

	second_line = true,

	color_scheme = _colorscheme('temperature', 't'),

	scale_factor = '1',

	label = 'Daily mean °' .. _if('metric first', 'F', 'C'),

	show = _if('metric first', '2', '1'),

	annual_mode = 'avg',

},

{---------- SECOND LINE MEAN DAILY MINIMUM TEMPERATURES ----------

	WANTROW = not options.wantSingleLine and (_ifany(' low C') or _ifany(' low F')),

	mode = 'temperature',

	group_name = 'low',

	second_line = true,

	color_scheme = _colorscheme('temperature', 't'),

	scale_factor = '1',

	label = 'Mean daily minimum °' .. _if('metric first', 'F', 'C'),

	show = _if('metric first', '2', '1'),

	annual_mode = 'avg',

},

{---------- SECOND LINE RECORD LOW TEMPERATURES ----------

	WANTROW = not options.wantSingleLine and (_ifany(' record low C') or _ifany(' record low F')),

	mode = 'temperature',

	group_name = 'record low',

	second_line = true,

	color_scheme = _colorscheme('temperature', 't'),

	scale_factor = '1',

	label = 'Record low °' .. _if('metric first', 'F', 'C'),

	show = _if('metric first', '2', '1'),

	annual_mode = 'min',

},

{---------- SECOND LINE MINIMUM WIND CHILL ----------

	WANTROW = not options.wantSingleLine and (_ifany(' chill') and _if('metric first')),

	mode = 'basic',

	group_name = 'chill',

	color_scheme = _colorscheme('temperature', 't'),

	scale_factor = '1',

	label = '[[Wind chill]]',

	annual_mode = 'min',

},

{---------- SECOND LINE TOTAL PRECIPITATION ----------

	WANTROW = not options.wantSingleLine and (_ifany(' precipitation cm') or _ifany(' precipitation mm') or _ifany(' precipitation inch')),

	mode = 'precipitation',

	group_name = 'precipitation',

	second_line = true,

	color_scheme = _colorscheme('precipitation', 'p'),

	date_mode = true,

	scale_factor = '1',

	prefer_cm = precision(_ifset('Jan precipitation inch', '0')) < 1,

	label = makeLabel(args, options, false, 'Average [[precipitation]]', 'precipitation'),

	annual_mode = 'sum',

},

{---------- SECOND LINE RAINFALL ----------

	WANTROW = not options.wantSingleLine and (_ifany(' rain cm') or _ifany(' rain mm') or _ifany(' rain inch')),

	mode = 'precipitation',

	group_name = 'rain',

	second_line = true,

	color_scheme = _colorscheme('rain', 'p'),

	date_mode = true,

	scale_factor = '1',

	prefer_cm = precision(_ifset('Jan rain inch', '0')) < 1,

	label = makeLabel(args, options, false, 'Average rainfall', 'rain'),

	annual_mode = 'sum',

},

{---------- SECOND LINE SNOWFALL ----------

	WANTROW = not options.wantSingleLine and (_ifany(' snow cm') or _ifany(' snow mm') or _ifany(' snow inch')),

	mode = 'precipitation',

	group_name = 'snow',

	second_line = true,

	prefer_cm = true,

	color_scheme = _colorscheme('snow', 'p'),

	date_mode = true,

	scale_factor = '1',

	label = makeLabel(args, options, false, 'Average snowfall', 'snow'),

	annual_mode = 'sum',

},

{---------- SECOND LINE AVERAGE EXTREME SNOW DEPTH ----------

	WANTROW = not options.wantSingleLine and (_ifany(' snow depth cm') or _ifany(' snow depth mm') or _ifany(' snow depth inch')),

	mode = 'precipitation',

	group_name = 'snow depth',

	second_line = true,

	prefer_cm = true,

	color_scheme = _colorscheme('snow', 'p'),

	scale_factor = '0.2',

	label = makeLabel(args, options, false, 'Average extreme snow depth', 'snow depth'),

	annual_mode = 'max',

},

{---------- PRECIPITATION DAYS ----------

	WANTROW = _ifany(' precipitation days'),

	mode = 'basic',

	group_name = 'precipitation days',

	color_scheme = _colorscheme('precip days', 'd'),

	date_mode = true,

	scale_factor = '1',

	label = 'Average precipitation days' .. _if('unit precipitation days', ' <span style="font-size:90%;" class="nowrap">(≥ ' .. _ifset('unit precipitation days', '') .. ')</span>'),

	annual_mode = 'sum',

},

{---------- RAINY DAYS ----------

	WANTROW = _ifany(' rain days'),

	mode = 'basic',

	group_name = 'rain days',

	color_scheme = _colorscheme('precip days', 'd'),

	date_mode = true,

	scale_factor = '1',

	label = 'Average rainy days' .. _if('unit rain days', ' <span style="font-size:90%;" class="nowrap">(≥ ' .. _ifset('unit rain days', '') .. ')</span>'),

	annual_mode = 'sum',

},

{---------- SNOWY DAYS ----------

	WANTROW = _ifany(' snow days'),

	mode = 'basic',

	group_name = 'snow days',

	color_scheme = _colorscheme('precip days', 'd'),

	date_mode = true,

	scale_factor = '1',

	label = 'Average snowy days' .. _if('unit snow days', ' <span style="font-size:90%;" class="nowrap">(≥ ' .. _ifset('unit snow days', '') .. ')</span>'),

	annual_mode = 'sum',

},

{---------- PERCENT RELATIVE HUMIDITY ----------

	WANTROW = _ifany(' humidity'),

	mode = 'basic',

	group_name = 'humidity',

	color_scheme = _colorscheme('humidity', 'h'),

	scale_factor = '1',

	label = 'Average [[relative humidity]] (%)' ..

		_if('time day', ' <span style="font-size:90%;" class="nowrap">(at ' .. _ifset('time day', '') .. ')</span>') ..

		_if('daily', ' <span style="font-size:90%;" class="nowrap">(daily average)</span>'),

	annual_mode = 'avg',

},

{---------- AFTERNOON PERCENT RELATIVE HUMIDITY ----------

	WANTROW = _ifany(' afthumidity'),

	mode = 'basic',

	group_name = 'afthumidity',

	color_scheme = _colorscheme('humidity', 'h'),

	scale_factor = '1',

	label = 'Average afternoon [[relative humidity]] (%)' ..

		_if('time day', ' <span style="font-size:90%;" class="nowrap">(at ' .. _ifset('time day', '') .. ')</span>') ..

		_if('daily', ' <span style="font-size:90%;" class="nowrap">(daily average)</span>'),

	annual_mode = 'avg',

},

{---------- FIRST LINE AVERAGE DEW POINT ----------

	WANTROW = _ifany(' dew point C') or _ifany(' dew point F'),

	mode = 'temperature',

	group_name = 'dew point',

	color_scheme = _colorscheme('temperature', 't'),

	scale_factor = '1',

	label = 'Average [[dew point]] °' .. _if('metric first', 'C', 'F') .. _ifSingle(' (°' .. _if('metric first', 'F', 'C') .. ')'),

	annual_mode = 'avg',

},

{---------- SECOND LINE AVERAGE DEW POINT----------

	WANTROW = not options.wantSingleLine and (_ifany(' dew point C') or _ifany(' dew point F')),

	mode = 'temperature',

	group_name = 'dew point',

	second_line = true,

	color_scheme = _colorscheme('temperature', 't'),

	scale_factor = '1',

	label = 'Average [[dew point]] °' .. _if('metric first', 'F', 'C'),

	show = _if('metric first', '2', '1'),

	annual_mode = 'avg',

},

{---------- MONTHLY SUNSHINE HOURS ----------

	WANTROW = _ifany(' sun'),

	mode = 'basic',

	group_name = 'sun',

	color_scheme = _colorscheme('sun', 's'),

	date_mode = true,

	scale_factor = '1',

	label = 'Mean monthly [[Sunshine duration|sunshine hours]]',

	annual_mode = 'sum',

},

{---------- DAILY SUNSHINE HOURS ----------

	WANTROW = _ifany('d sun'),

	mode = 'basic',

	group_name = 'd sun',

	color_scheme = _colorscheme('sun', 's'),

	include_space = false,

	scale_factor = '30.44',

	label = 'Mean daily [[Sunshine duration|sunshine hours]]',

	annual_mode = 'avg',

},

{---------- DAILY DAYLIGHT HOURS ----------

	WANTROW = _ifany(' light'),

	mode = 'basic',

	group_name = ' light',

	color_scheme = _colorscheme('sun', 's'),

	include_space = false,

	scale_factor = '30.44',

	label = 'Mean daily [[Daytime|daylight hours]]',

	annual_mode = 'avg',

},

{---------- PERCENT SUNSHINE ----------

	WANTROW = _ifany(' percentsun'),

	mode = 'basic',

	group_name = 'percentsun',

	color_scheme = _colorscheme('sun', 's'),

	scale_factor = '7.2',

	label = 'Percent [[Sunshine duration|possible sunshine]]',

	annual_mode = 'avg',

},

{---------- ULTRAVIOLET INDEX ----------

	WANTROW = _ifany(' uv'),

	mode = 'basic',

	group_name = 'uv',

	color_scheme = _colorscheme('uv', 'u'),

	scale_factor = '1',

	label = 'Average [[ultraviolet index]]',

	annual_mode = 'avg',

},

----------- SOURCES ----------

makeSources(frame, args),

}

end



local function main(frame)

	local sandbox = frame:getTitle():find('sandbox', 1, true) and '/sandbox' or ''

	local buildRow = require('Module:Weather box/row' .. sandbox)._buildRow

	local args = frame:getParent().args

	local options = {

		wantSingleLine = wantSingle(args'single line']),

		sandbox = sandbox,

	}

	local results = {}

	for i, definition in ipairs(getDefinitions(frame, args, options)) do

		local row

		if type(definition) == 'string' then

			row = definition

		elseif definition.WANTROW then

			row = buildRow(definition, args, options)

		else

			row = ''

		end

		resultsi = row

	end

	return '<div>\n'..table.concat(results)..'\n</div>'  -- prevent Scribunto from inserting a blank line before the table

end



return {

	main = main,

}