Module:Biglist

MyWikiBiz, Author Your Legacy — Friday November 15, 2024
Revision as of 20:50, 15 July 2021 by Zoran (talk | contribs) (Pywikibot 6.4.0)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigationJump to search

This module helps avoid problems with templates that might exceed expand size or time and which might put a page in an error tracking category:

Using this module to replace a large list of entries can significantly reduce the resources required to generate the page, making editing and viewing an uncached page faster.

Columns-list

Some articles use {{columns-list}} to show lists of items in multiple columns. The module only supports cases using colwidth and no other parameters. Given that limitation, using the module requires an expansion size only a little more than the size of the wikitext, while the template requires an amount three times larger. The following example is from List of least concern fishes.

Wikitext

{{#invoke:biglist|columns-list|colwidth=30em|*[[Aptychotrema rostrata|Eastern shovelnose ray]] ''(Aptychotrema rostrata)''
*[[Aptychotrema vincentiana|Southern shovelnose ray]] ''(Aptychotrema vincentiana)''
*[[Rhinobatos annulatus|Lesser guitarfish]] ''(Rhinobatos annulatus)''
*[[Rhinobatos blochii|Bluntnose guitarfish]] ''(Rhinobatos blochii)''
*[[Rhinobatos sainsburyi|Goldeneye shovelnose ray]] ''(Rhinobatos sainsburyi)''
*[[Trygonorrhina dumerilli|Southern fiddler ray]] ''(Trygonorrhina dumerilli)''
*[[Trygonorrhina fasciata|Eastern fiddler ray]] ''(Trygonorrhina fasciata)''}}

Result

<templatestyles src="Div col/styles.css"></templatestyles>

Search

Some project pages list hundreds of topics using {{search}}. An alternative would be to use the module as in the following example.

Wikitext

{{#invoke:biglist|topicsearch|prefix=*|list=
Aalenilla compressa
Aalenirhynchia
}}

Result

Userlinks

Some WP:LTA pages list hundreds of users using {{userlinks}}. An alternative would be to use the module as in the following example.

Wikitext

{{#invoke:biglist|userlinks|prefix=#|list=
Example
Jimbo Wales
}}

Result

  1. Example (talk · contribs · deleted contribs · logs · edit filter log · block user · block log)
  2. Jimbo Wales (talk · contribs · deleted contribs · logs · edit filter log · block user · block log)

Weatherboxcols

List of cities by sunshine duration has many tables with cells that show the average hours of sunlight in a particular month and location; each cell is colored according to the number of hours. Using {{Weather box/cols}}, the article had script errors which were removed by replacing entries such as:

| style="{{Weather box/cols|183.0 }};"|183.0

with

| {{#invoke:biglist|weatherboxcols|183.0}}

Storms

The policy section Wikipedia is not a crystal ball (WP:CRYSTAL) includes an example of an item from a "predetermined list" of names. The key point of the example is that an event may be likely to occur within a few months, but is not suitable for an article if no encyclopedic information is available. The storm function selects a suitable title from a built-in list. The title is not linked. From January to October (inclusive) in the current year, the entry for that year is shown. That entry should be for an event expected in the next year. In November and December of the current year, the entry for the following year is shown. The result is that the selected event is always at least two months in the future.

If the list that is built-in to the module is not updated before the last entry is used, the default entry is displayed.

The following example is supposed to show a red link for an article that should not be created until encyclopedic information is available.
[[{{#invoke:biglist|storm}}]]Tropical Storm Alberto (2030)


-- This module provides some functions to help avoid problems with templates
-- that might exceed expand size or time and which might put the page in
-- [[:Category:Pages where template include size is exceeded]] or
-- [[:Category:Pages with script errors]] (time exceeding 10 seconds).

local function collection()
	-- Return a table to hold items.
	return {
		n = 0,
		add = function (self, item)
			self.n = self.n + 1
			self[self.n] = item
		end,
		join = function (self, sep)
			return table.concat(self, sep)
		end,
	}
end

local function strip_to_nil(text)
	-- If text is a non-empty string, return its trimmed content,
	-- otherwise return nothing (empty string or not a string).
	if type(text) == 'string' then
		return text:match('(%S.-)%s*$')
	end
end

local function message(msg, nocat)
	-- Return formatted message text for an error.
	-- Can append "#FormattingError" to URL of a page with a problem to find it.
	-- This should not be called because there is no validity checking.
	local anchor = '<span id="FormattingError"></span>'
	local category = nocat and '' or '[[Category:Biglist errors]]'
	return anchor ..
		'<strong class="error">Error: ' ..
		msg ..
		'</strong>' ..
		category .. '\n'
end

local function urlencode(text)
	-- Return equivalent of {{urlencode:text}}.
	local function byte(char)
		return string.format('%%%02X', string.byte(char))
	end
	return text:gsub('[^ %w%-._]', byte):gsub(' ', '+')
end

local function replace2(text, template)
	-- Return template after substituting text and urlencoded text.
	local plain = text:gsub('%%', '%%%%')  -- for gsub, '%' has a special meaning in replacement
	local plainp = plain:gsub(' ', '+')    -- plain and space replaced with plus
	local encoded = urlencode(text):gsub('%%', '%%%%')
	return template:gsub('<TXT>', plain):gsub('<TXTP>', plainp):gsub('<UENC>', encoded)
end

local function clean(text, default)
	-- Return text, if not empty, after trimming leading/trailing whitespace.
	-- Otherwise return default which may be nil.
	if text then
		text = text:match("^%s*(.-)%s*$")
		if text ~= '' then
			return text
		end
	end
	return default
end

local function make_list(args, formatter, template)
	-- Return a list of formatted items.
	-- Input is a string of multiple lines, one item per line.
	local text = args.list or args[1] or ''
	local prefix = clean(args.prefix) or ''
	local comment = clean(args.comment)
	local results = collection()
	for line in string.gmatch(text .. '\n', '[\t ]*(.-)[\t\r ]*\n') do
		-- Skip line if empty or a comment.
		if line ~= '' then
			if not (comment and line:sub(1, #comment) == comment) then
				results:add(prefix .. formatter(line, template))
			end
		end
	end
	return results:join('\n')
end

local templates = {
	-- Equivalent of {{userlinks|text}}.
	userlinks = [=[
<span class="plainlinks userlinks">[[User:<TXT>|<TXT>]] <span class="plainlinks">([[User talk:<TXT>|talk]] '''·''' [[Special:Contributions/<TXT>|contribs]]<span class="sysop-show"> '''·''' [[Special:DeletedContributions/<TXT>|deleted contribs]]</span> '''·''' [//en.wikipedia.org/w/index.php?title=Special:Log&user=<UENC> logs] '''·''' [//en.wikipedia.org/w/index.php?title=Special:AbuseLog&wpSearchUser=<UENC> edit filter log]<span class="sysop-show"> '''·''' [[Special:Block/<TXT>|block user]]</span> '''·''' [//en.wikipedia.org/w/index.php?title=Special:Log&type=block&page=User:<UENC> block log])</span></span>]=],
	-- Equivalent of how {{search|topic}} is used.
	topicsearch = [=[
[[<TXT>]] – <span class="plainlinks">([//en.wikipedia.org/w/index.php?title=Special:Search&search=<UENC> wp] [https://www.google.com/search?q=site%3Awikipedia.org+<TXTP> gwp] [https://www.google.com/search?q=<TXTP> g] [https://www.bing.com/search?q=site%3Awikipedia.org+<TXTP> bwp] [https://www.bing.com/search?q=<TXTP> b] | [https://www.britannica.com/search?nop&query=<TXTP> eb] [https://www.google.com/custom?sitesearch=1911encyclopedia.org&q=<TXTP> 1911] [http://www.bartleby.com/cgi-bin/texis/webinator/65search?query=<TXTP> co] [https://www.google.com/search?q=site%3Ahttp%3A%2F%2Fwww.pcmag.com%2Fencyclopedia_term%2F+<TXTP> gct] [http://scienceworld.wolfram.com/search/index.cgi?as_q=<TXTP> sw] [https://archive.org/search.php?query=<UENC> arc] [http://babel.hathitrust.org/cgi/ls?field1=ocr;q1=<UENC>;a=srchls;lmt=ft ht])</span>]=],
}

local function main(formatter, tname)
	local template = templates[tname]
	if template then
		return function (frame)
			local args = frame.args
			local success, result = pcall(make_list, args, formatter, template)
			if success then
				return result
			end
			return message(result, clean(args.nocat))
		end
	else
		return function (frame)
			local args = frame.args
			return message('Unknown template name "' .. tname .. '"', clean(args.nocat))
		end
	end
end

local function coltit(frame)
	-- [[List of RAL colors]] has "node-count limit exceeded" problem.
	-- Following are equivalent:
	--   {{coltit|xxx}}
	--   {{#invoke:biglist|coltit|xxx}}
	-- or
	--   {{coltit|rgb=xxx}}
	--   {{#invoke:biglist|coltit|rgb=xxx}}
	-- Output is an empty cell for a table; the cell has the given background color.
	-- This does not emulate other features of the template.
	local args = frame.args
	local hex = strip_to_nil(args[1])  -- should be hex color code such as 'AABBCC'
	if hex then
		return string.format('title="color %s" style="background:#%s;"| ', hex, hex)
	end
	local rgb = strip_to_nil(args.rgb)  -- should be decimal triple such as '123,123,123'
	if rgb then
		return string.format('title="color %s" style="background:rgb(%s);"| ', rgb, rgb)
	end
	error('biglist coltit: need parameter 1 or rgb', 0)
end

local function columnslist(frame)
	-- [[List of least concern fishes]] has problem exceeding template expansion size.
	-- Will possibly be other articles with similar problems.
	-- Following are equivalent:
	--   {{columns-list|colwidth=30em|xxx}}
	--   {{#invoke:biglist|columns-list|colwidth=30em|xxx}}
	-- Output is:
	--   <div ...>xxx</div>
	-- This assumes colwidth is wanted and does not emulate other features of the template.
	local args = frame.args
	local content = strip_to_nil(args[1]) or ''
	local colwidth = strip_to_nil(args.colwidth) or ''
	if colwidth ~= '' then
		colwidth = ' style="column-width: ' .. colwidth .. '"'
	end
	return frame:extensionTag{
		name = 'templatestyles', args = { src = 'Div col/styles.css' }
	} .. '<div class="div-col"' .. colwidth .. '>\n' .. content .. '</div>'
end

local function storm(frame)
	-- [[Wikipedia:What Wikipedia is not]] has an example at [[WP:CRYSTAL]]
	-- where the name of a "virtually certain" future storm is needed.
	-- This function returns the next such name (unlinked) depending on the current date.
	-- Usage:
	--   {{#invoke:biglist|storm}}
	-- Output example:
	--   Tropical Storm Alex (2022)
	local storms = {
		[2017] = 'Tropical Storm Alberto (2018)',
		[2018] = 'Tropical Storm Andrea (2019)',
		[2019] = 'Tropical Storm Arthur (2020)',
		[2020] = 'Tropical Storm Ana (2021)',
		[2021] = 'Tropical Storm Alex (2022)',
		default = 'Tropical Storm Alberto (2030)',
	}
	local date = os.date('!*t')  -- today's UTC date
	local y, m = date.year, date.month  -- full year, month (1-12)
	if m >= 11 then
		y = y + 1
	end
	return storms[y] or storms.default
end

local function weatherboxcols(frame)
	-- [[List of cities by sunshine duration]] has problem exceeding time available.
	-- Examples:
	--   {{#invoke:biglist|weatherboxcols|123.4}}         → style="background:#B9B94C; font-size:85%;"|123.4
	--   {{#invoke:biglist|weatherboxcols|123.4|1,823.0}} → style="background:#B9B94C; font-size:85%;"|1,823.0
	local args = frame.args
	local display = strip_to_nil(args[1]) or ''
	local value = tonumber((display:gsub(',', '')))
	local function show(bg, fg)
		local text = strip_to_nil(args[2]) or display
		if not fg and (value and value < 62) then
			fg = 'FFFFFF'
		end
		if fg then
			fg = 'color:#' .. fg .. ';'
		else
			fg = ''
		end
		return 'style="background:#' .. bg .. ';' .. fg .. ' font-size:85%;"' .. '|' .. text
	end
	if not value then
		return show('FFFFFF', '000000')
	end
	local redgreen, blue
	if value <= 0 then
		redgreen = 0
	elseif value <= 90 then
		redgreen = 1.889 * value
	elseif value <= 180 then
		redgreen = 0.472 * (270.169 + value)
	elseif value < 360 then
		redgreen = 0.236 * (720.424 + value)
	else
		redgreen = 255
	end
	if value <= 0 then
		blue = 0
	elseif value <= 90 then
		blue = 1.889 * value
	elseif value < 150 then
		blue = 2.883 * (150 - value)
	elseif value <= 270 then
		blue = 0
	elseif value < 719.735 then
		blue = 0.567 * (value - 270)
	else
		blue = 255
	end
	return show(string.format('%02X%02X%02X', redgreen, redgreen, blue))
end

return {
	coltit = coltit,
	['columns-list'] = columnslist,
	storm = storm,
	topicsearch = main(replace2, 'topicsearch'),
	userlinks = main(replace2, 'userlinks'),
	weatherboxcols = weatherboxcols,
}