<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en-GB">
	<id>https://stockhub.co/index.php?action=history&amp;feed=atom&amp;title=Module%3ASandbox%2FHike395%2FRS</id>
	<title>Module:Sandbox/Hike395/RS - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://stockhub.co/index.php?action=history&amp;feed=atom&amp;title=Module%3ASandbox%2FHike395%2FRS"/>
	<link rel="alternate" type="text/html" href="https://stockhub.co/index.php?title=Module:Sandbox/Hike395/RS&amp;action=history"/>
	<updated>2026-04-20T22:56:23Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.43.5</generator>
	<entry>
		<id>https://stockhub.co/index.php?title=Module:Sandbox/Hike395/RS&amp;diff=145528&amp;oldid=prev</id>
		<title>imported&gt;Hike395: add timer</title>
		<link rel="alternate" type="text/html" href="https://stockhub.co/index.php?title=Module:Sandbox/Hike395/RS&amp;diff=145528&amp;oldid=prev"/>
		<updated>2022-01-03T22:41:34Z</updated>

		<summary type="html">&lt;p&gt;add timer&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;-- Creates a slideshow gallery where the order is randomised. Intended for use on portal pages.&lt;br /&gt;
local getArgs = require(&amp;#039;Module:Arguments&amp;#039;).getArgs&lt;br /&gt;
&lt;br /&gt;
local p = {}&lt;br /&gt;
local excerptModule =  require(&amp;#039;Module:Excerpt/portals&amp;#039;)&lt;br /&gt;
local randomModule = require(&amp;#039;Module:Random&amp;#039;)&lt;br /&gt;
local redirectModule = require(&amp;#039;Module:Redirect&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
local counter = {}&lt;br /&gt;
&lt;br /&gt;
local function initCounter()&lt;br /&gt;
	counter = {}&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function incCounter(s, inc)&lt;br /&gt;
	local val = counter[s]&lt;br /&gt;
	inc = inc or 1&lt;br /&gt;
	if val then&lt;br /&gt;
		counter[s] = val+inc&lt;br /&gt;
	else&lt;br /&gt;
		counter[s] = inc&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function startTimer(s)&lt;br /&gt;
	incCounter(s,-os.clock())&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function stopTimer(s)&lt;br /&gt;
	incCounter(s,os.clock())&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function dumpCounter()&lt;br /&gt;
	local result = nil&lt;br /&gt;
	for k, v in pairs(counter) do&lt;br /&gt;
		if result then&lt;br /&gt;
			result = result..&amp;#039;, &amp;#039;&lt;br /&gt;
		end&lt;br /&gt;
		result = (result or &amp;#039;&amp;#039;)..k..&amp;#039;: &amp;#039;..tostring(v)&lt;br /&gt;
	end&lt;br /&gt;
	return result&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function cleanupArgs(argsTable)&lt;br /&gt;
	local cleanArgs = {}&lt;br /&gt;
	for key, val in pairs(argsTable) do&lt;br /&gt;
		if type(val) == &amp;#039;string&amp;#039; then&lt;br /&gt;
			val = val:match(&amp;#039;^%s*(.-)%s*$&amp;#039;)&lt;br /&gt;
			incCounter(&amp;#039;cleanupArgsMatch&amp;#039;)&lt;br /&gt;
			if val ~= &amp;#039;&amp;#039; then&lt;br /&gt;
				cleanArgs[key] = val&lt;br /&gt;
			end&lt;br /&gt;
		else&lt;br /&gt;
			cleanArgs[key] = val&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return cleanArgs&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function normaliseCssMeasurement(input)&lt;br /&gt;
	local suffix = string.reverse(string.sub(string.reverse(input), 1, 2))&lt;br /&gt;
	if ( suffix == &amp;#039;px&amp;#039; ) or ( suffix == &amp;#039;em&amp;#039; ) or ( string.sub(suffix, 2, 2) == &amp;#039;%&amp;#039; ) then&lt;br /&gt;
		return input&lt;br /&gt;
	else&lt;br /&gt;
		return input .. &amp;#039;px&amp;#039;&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function isDeclined(val)&lt;br /&gt;
	if not val then return false end&lt;br /&gt;
	local declinedWords = &amp;quot; decline declined exclude excluded false none not no n off omit omitted remove removed &amp;quot;&lt;br /&gt;
	incCounter(&amp;#039;declinedFind&amp;#039;)&lt;br /&gt;
	return string.find(declinedWords , &amp;#039; &amp;#039;..val..&amp;#039; &amp;#039;, 1, true ) and true or false&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function makeOutput(galleryLines, maxWidth, containerClassName, nonRandom)&lt;br /&gt;
	local randomiseArgs = {	[&amp;#039;t&amp;#039;] = galleryLines }&lt;br /&gt;
	local sortedLines = nonRandom and galleryLines or randomModule.main(&amp;#039;array&amp;#039;, randomiseArgs)&lt;br /&gt;
	for i = 1, #sortedLines do&lt;br /&gt;
		-- insert a switcher-label span just after the first pipe (which has already been escaped as {{!}} instead the | character)&lt;br /&gt;
		incCounter(&amp;#039;makeOutputGsub&amp;#039;)&lt;br /&gt;
		sortedLines[i] = sortedLines[i]:gsub(&lt;br /&gt;
			&amp;quot;%{%{%!%}%}&amp;quot;,&lt;br /&gt;
			&amp;#039;{{!}}&amp;lt;span class=&amp;quot;switcher-label&amp;quot; style=&amp;quot;display:none&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;randomSlideshow-sr-only&amp;quot;&amp;gt;Image &amp;#039; .. tostring(i) .. &amp;#039;&amp;lt;/span&amp;gt;&amp;lt;/span&amp;gt;&amp;#039;,&lt;br /&gt;
			1)&lt;br /&gt;
	end&lt;br /&gt;
	local galleryContent = table.concat(sortedLines, &amp;#039;\n&amp;#039;)&lt;br /&gt;
	local output = &amp;#039;&amp;lt;div class=&amp;quot;&amp;#039; .. containerClassName .. &amp;#039;&amp;quot; style=&amp;quot;max-width:&amp;#039; .. normaliseCssMeasurement(maxWidth) .. &amp;#039;; margin:-4em auto;&amp;quot;&amp;gt;&amp;lt;div class=&amp;quot;nomobile&amp;quot;&amp;gt;&amp;lt;!--intentionally empty on desktop, and is not present on mobile website (outside template namesapce)--&amp;gt;&amp;lt;/div&amp;gt;{{#tag:gallery|&amp;#039; .. galleryContent  .. &amp;#039;|mode=slideshow|class=switcher-container}}&amp;lt;/div&amp;gt;&amp;#039;&lt;br /&gt;
	stopTimer(&amp;quot;overall&amp;quot;)&lt;br /&gt;
	return dumpCounter()&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function makeGalleryLine(file, caption, credit)&lt;br /&gt;
	local title = mw.title.new(file, &amp;quot;File&amp;quot; )&lt;br /&gt;
	if not title&lt;br /&gt;
	then&lt;br /&gt;
		return &amp;quot;File:Blank.png{{!}}{{Error|File [[:File:&amp;quot; .. file .. &amp;quot;]] does not exist.}}&amp;quot;&lt;br /&gt;
	end&lt;br /&gt;
	local creditLine = ( credit and &amp;#039;&amp;lt;p&amp;gt;&amp;lt;span style=&amp;quot;font-size:88%&amp;quot;&amp;gt;&amp;#039; .. credit .. &amp;#039;&amp;lt;/span&amp;gt;&amp;lt;/p&amp;gt;&amp;#039; or &amp;#039;&amp;#039; )&lt;br /&gt;
	return title.prefixedText .. &amp;#039;{{!}}&amp;#039; .. ( caption or &amp;#039;&amp;#039; ) .. creditLine&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function makeGalleryLinesTable(args)&lt;br /&gt;
	local galleryLinesTable = {}&lt;br /&gt;
	local i = 1&lt;br /&gt;
	while args[i] do&lt;br /&gt;
		table.insert(galleryLinesTable, makeGalleryLine(args[i], args[i+1], args[&amp;#039;credit&amp;#039; .. (i+1)/2]))&lt;br /&gt;
		i = i + 2&lt;br /&gt;
	end&lt;br /&gt;
	return galleryLinesTable &lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function hasCaption(line)&lt;br /&gt;
	incCounter(&amp;#039;hasCaptionMatch&amp;#039;)&lt;br /&gt;
	local caption = mw.ustring.match(line, &amp;quot;.-{{!}}(.*)&amp;quot;)&lt;br /&gt;
	-- require caption to exist with more than 5 characters (avoids sizes etc being mistaken for captions)&lt;br /&gt;
	return caption and #caption&amp;gt;5 and true or false&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function extractGalleryFiles(wikitext)&lt;br /&gt;
	incCounter(&amp;#039;extractGalleryMatch&amp;#039;)&lt;br /&gt;
	local gallery = mw.ustring.match(wikitext, &amp;#039;&amp;lt;gallery.-&amp;gt;%s*(.-)%s*&amp;lt;/gallery&amp;gt;&amp;#039;)&lt;br /&gt;
	if not gallery then&lt;br /&gt;
		return false&lt;br /&gt;
	end&lt;br /&gt;
	incCounter(&amp;#039;extractGalleryGsub&amp;#039;)&lt;br /&gt;
	gallery = mw.ustring.gsub(gallery, &amp;#039;|&amp;#039;, &amp;#039;{{!}}&amp;#039;)&lt;br /&gt;
	return mw.text.split(gallery, &amp;#039;%c&amp;#039;)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function extractRegularFiles(wikitext)&lt;br /&gt;
	startTimer(&amp;#039;regularFileTime&amp;#039;)&lt;br /&gt;
	local files = {}&lt;br /&gt;
	local frame = mw.getCurrentFrame()&lt;br /&gt;
	local expand = function(template)&lt;br /&gt;
		return frame:preprocess(template)&lt;br /&gt;
	end&lt;br /&gt;
	for file in mw.ustring.gmatch(wikitext, &amp;#039;%b[]&amp;#039; ) do&lt;br /&gt;
		incCounter(&amp;#039;extractRegularFiles&amp;#039;)&lt;br /&gt;
		-- remove keywords that don&amp;#039;t work in galleries&lt;br /&gt;
		file = mw.ustring.gsub(file, &amp;#039;|%s*thumb%s*([|%]])&amp;#039;, &amp;#039;%1&amp;#039;)&lt;br /&gt;
		file = mw.ustring.gsub(file, &amp;#039;|%s*thumbnail%s*([|%]])&amp;#039;, &amp;#039;%1&amp;#039;)&lt;br /&gt;
		file = mw.ustring.gsub(file, &amp;#039;|%s*border%s*([|%]])&amp;#039;, &amp;#039;%1&amp;#039;)&lt;br /&gt;
		file = mw.ustring.gsub(file, &amp;#039;|%s*left%s*([|%]])&amp;#039;, &amp;#039;%1&amp;#039;)&lt;br /&gt;
		file = mw.ustring.gsub(file, &amp;#039;|%s*right%s*([|%]])&amp;#039;, &amp;#039;%1&amp;#039;)&lt;br /&gt;
		file = mw.ustring.gsub(file, &amp;#039;|%s*center%s*([|%]])&amp;#039;, &amp;#039;%1&amp;#039;)&lt;br /&gt;
		file = mw.ustring.gsub(file, &amp;#039;|%s*centre%s*([|%]])&amp;#039;, &amp;#039;%1&amp;#039;)&lt;br /&gt;
		file = mw.ustring.gsub(file, &amp;#039;|%s*baseline%s*([|%]])&amp;#039;, &amp;#039;%1&amp;#039;)&lt;br /&gt;
		file = mw.ustring.gsub(file, &amp;#039;|%s*sub%s*([|%]])&amp;#039;, &amp;#039;%1&amp;#039;)&lt;br /&gt;
		file = mw.ustring.gsub(file, &amp;#039;|%s*super%s*([|%]])&amp;#039;, &amp;#039;%1&amp;#039;)&lt;br /&gt;
		file = mw.ustring.gsub(file, &amp;#039;|%s*top%s*([|%]])&amp;#039;, &amp;#039;%1&amp;#039;)&lt;br /&gt;
		file = mw.ustring.gsub(file, &amp;#039;|%s*text%-top%s*([|%]])&amp;#039;, &amp;#039;%1&amp;#039;)&lt;br /&gt;
		file = mw.ustring.gsub(file, &amp;#039;|%s*bottom%s*([|%]])&amp;#039;, &amp;#039;%1&amp;#039;)&lt;br /&gt;
		file = mw.ustring.gsub(file, &amp;#039;|%s*text%-bottom%s*([|%]])&amp;#039;, &amp;#039;%1&amp;#039;)&lt;br /&gt;
		file = mw.ustring.gsub(file, &amp;#039;|%s*framed?%s*([|%]])&amp;#039;, &amp;#039;%1&amp;#039;)&lt;br /&gt;
		file = mw.ustring.gsub(file, &amp;#039;|%s*frameless%s*([|%]])&amp;#039;, &amp;#039;%1&amp;#039;)&lt;br /&gt;
		file = mw.ustring.gsub(file, &amp;#039;|%s*upright%s*[0-9%.]*%s*([|%]])&amp;#039;, &amp;#039;%1&amp;#039;)&lt;br /&gt;
		file = mw.ustring.gsub(file, &amp;#039;|%s*upright%s*=.-([|%]])&amp;#039;, &amp;#039;%1&amp;#039;)&lt;br /&gt;
		file = mw.ustring.gsub(file, &amp;#039;|%s*link%s*=.-([|%]])&amp;#039;, &amp;#039;%1&amp;#039;)&lt;br /&gt;
		-- remove spaces prior to captions (which cause pre-formatted text)&lt;br /&gt;
		file = mw.ustring.gsub(file, &amp;#039;|%s*&amp;#039;, &amp;#039;|&amp;#039;)&lt;br /&gt;
		-- remove sizes, which sometimes get mistaken for captions&lt;br /&gt;
		file = mw.ustring.gsub(file, &amp;#039;|%s*%d*x?%d+%s*px%s*([|%]])&amp;#039;, &amp;#039;%1&amp;#039;)&lt;br /&gt;
		-- expand templates&lt;br /&gt;
		file = mw.ustring.gsub(file, &amp;#039;{%b{}}&amp;#039;, expand)&lt;br /&gt;
		-- remove loose closing braces which don&amp;#039;t have matching opening braces&lt;br /&gt;
		file = mw.ustring.gsub(file, &amp;#039;}}&amp;#039;, &amp;#039;&amp;#039;)&lt;br /&gt;
		-- remove loose opening braces which don&amp;#039;t have matching closing braces (and the subsequent content, which is probably just a template name)&lt;br /&gt;
		file = mw.ustring.gsub(file, &amp;#039;{{.-([|%]])&amp;#039;, &amp;#039;$1&amp;#039;)&lt;br /&gt;
		-- replace pipes and equals (which would otherwise break the {{#tag:}} syntax)&lt;br /&gt;
		file = mw.ustring.gsub(file, &amp;#039;|%s*alt%s*=&amp;#039;, &amp;#039;{{! }}alt=&amp;#039;)&lt;br /&gt;
		file = mw.ustring.gsub(file, &amp;#039;|&amp;#039;, &amp;#039;{{!}}&amp;#039;)&lt;br /&gt;
		file = mw.ustring.gsub(file, &amp;#039;=&amp;#039;, &amp;#039;{{=}}&amp;#039;)&lt;br /&gt;
		-- remove linebreaks&lt;br /&gt;
		file = mw.ustring.gsub(file, &amp;#039;\n\n&amp;#039;, &amp;#039;&amp;lt;br&amp;gt;&amp;#039;)&lt;br /&gt;
		file = mw.ustring.gsub(file, &amp;#039;\n&amp;#039;, &amp;#039;&amp;#039;)&lt;br /&gt;
		-- remove surrounding square brackets&lt;br /&gt;
		file = mw.ustring.gsub(file, &amp;#039;^%[%[&amp;#039;, &amp;#039;&amp;#039;)&lt;br /&gt;
		file = mw.ustring.gsub(file, &amp;#039;%]%]$&amp;#039;, &amp;#039;&amp;#039;)&lt;br /&gt;
		table.insert(files, file)&lt;br /&gt;
	end&lt;br /&gt;
	stopTimer(&amp;#039;regularFileTime&amp;#039;)&lt;br /&gt;
	return files&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function makeTranscludedGalleryLinesTables(args)&lt;br /&gt;
	local namespaceNumber = function(pagetitle)&lt;br /&gt;
		local titleObject = mw.title.new(pagetitle)&lt;br /&gt;
		return titleObject and titleObject.namespace&lt;br /&gt;
	end&lt;br /&gt;
	local lines = {}&lt;br /&gt;
	local i = 1&lt;br /&gt;
	while args[i] do&lt;br /&gt;
		if namespaceNumber(args[i]) == 6 then -- file namespace&lt;br /&gt;
			-- args[i] is either just the filename, or uses syntax File:Name.jpg##Caption##Credit&lt;br /&gt;
			local parts = mw.text.split(args[i], &amp;#039;##%s*&amp;#039;)&lt;br /&gt;
			local filename = parts[1]&lt;br /&gt;
			local caption = args[&amp;#039;caption&amp;#039;..i] or parts[2] or false&lt;br /&gt;
			local credit = args[&amp;#039;credit&amp;#039;..i] or parts[3] or false&lt;br /&gt;
			local line = makeGalleryLine(filename, caption, credit)&lt;br /&gt;
			table.insert(lines, line)&lt;br /&gt;
		else&lt;br /&gt;
			startTimer(&amp;#039;excerptTime&amp;#039;)&lt;br /&gt;
			local content, pagename = excerptModule.getContent(args[i])&lt;br /&gt;
			if not pagename then&lt;br /&gt;
				return error(&amp;#039;Cannot read a valid page for &amp;quot;&amp;#039; .. args[i] .. &amp;#039;&amp;quot;&amp;#039;, 0)&lt;br /&gt;
			elseif not content then&lt;br /&gt;
				return error(&amp;#039;No content found on page &amp;quot;&amp;#039; .. args[i] .. &amp;#039;&amp;quot;&amp;#039;, 0)&lt;br /&gt;
			end&lt;br /&gt;
			if args[&amp;#039;section&amp;#039;..i] then&lt;br /&gt;
				content = excerptModule.getSection(content, args[&amp;#039;section&amp;#039;..i]) or &amp;#039;&amp;#039;&lt;br /&gt;
			end&lt;br /&gt;
			content = excerptModule.cleanupText(content, {keepSubsections=true}) -- true means keep subsections&lt;br /&gt;
			local galleryFiles = extractGalleryFiles(content)&lt;br /&gt;
			if galleryFiles then&lt;br /&gt;
				for _, f in pairs(galleryFiles) do&lt;br /&gt;
					if hasCaption(f) then&lt;br /&gt;
						local filename = string.gsub(f, &amp;#039;{{!}}.*&amp;#039;, &amp;#039;&amp;#039;)&lt;br /&gt;
						local isOkay = excerptModule.checkImage(filename)&lt;br /&gt;
						if isOkay then&lt;br /&gt;
							table.insert(lines, f..&amp;quot; (from &amp;#039;&amp;#039;&amp;#039;[[&amp;quot;..pagename..&amp;quot;]]&amp;#039;&amp;#039;&amp;#039;)&amp;quot;)&lt;br /&gt;
						end&lt;br /&gt;
					end&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
			stopTimer(&amp;#039;excerptTime&amp;#039;)&lt;br /&gt;
			startTimer(&amp;#039;parseTime&amp;#039;)&lt;br /&gt;
			local otherFiles = excerptModule.parse(content, {fileflags=&amp;quot;1-100&amp;quot;, filesOnly=true})&lt;br /&gt;
			stopTimer(&amp;#039;parseTime&amp;#039;)&lt;br /&gt;
			if otherFiles then&lt;br /&gt;
				for _, f in pairs(extractRegularFiles(otherFiles)) do&lt;br /&gt;
					if f and f ~= &amp;#039;&amp;#039; and mw.ustring.sub(f, 1, 5) == &amp;#039;File:&amp;#039; and hasCaption(f) then&lt;br /&gt;
						table.insert(lines, f..&amp;quot; (from &amp;#039;&amp;#039;&amp;#039;[[&amp;quot;..pagename..&amp;quot;]]&amp;#039;&amp;#039;&amp;#039;)&amp;quot;)&lt;br /&gt;
					end&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
		&lt;br /&gt;
		end&lt;br /&gt;
		i = i + 1&lt;br /&gt;
	end&lt;br /&gt;
	return ( #lines &amp;gt; 0 ) and lines or error(&amp;#039;No images found&amp;#039;)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
p._main = function(args, transclude, extraClassName)&lt;br /&gt;
	initCounter()&lt;br /&gt;
	startTimer(&amp;#039;overall&amp;#039;)&lt;br /&gt;
	if not args[1] then&lt;br /&gt;
		return error(linked and &amp;#039;No page specified&amp;#039; or &amp;#039;No page specified&amp;#039;, 0)&lt;br /&gt;
	end&lt;br /&gt;
	local lines = transclude and makeTranscludedGalleryLinesTables(args) or makeGalleryLinesTable(args)&lt;br /&gt;
	local classNames = &amp;#039;randomSlideshow-container&amp;#039;&lt;br /&gt;
	if extraClassName then classNames = classNames .. &amp;#039; &amp;#039; .. extraClassName end&lt;br /&gt;
	return makeOutput(lines, args.width or &amp;#039;100%&amp;#039;, classNames, isDeclined(args.random))&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
p.transclude = function(frame)&lt;br /&gt;
	local args = getArgs(frame)&lt;br /&gt;
	return p._main(args, true)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
return p&lt;/div&gt;</summary>
		<author><name>imported&gt;Hike395</name></author>
	</entry>
</feed>