Edge Rewrite
// HTMLRewriter · presentation

This page was redesigned at the edge.

Cloudflare fetched the original article and streamed it through HTMLRewriter to apply an entirely new visual system without rebuilding the source page.

Jump to content

Module:Sandbox/Aidan9382/RSP

From Wikipedia, the free encyclopedia

local p = {}

local TopLevelPage = "Wikipedia:Reliable sources/Perennial sources"

local function getWikilinks(str)
	local out = {}
	for part in str:gmatch("%[%b[]%]") do
		table.insert(out, part:sub(3, -3))
	end
	return out
end

local function uniqueletter(n) -- generates A-Z AA-AZ BA-BZ etc. for discussions
	return n > 26 and string.char(64+math.floor((n-1)/26), 65+((n-1)%26)) or string.char(64+n)
end

-- temporary lazy table version
local RSPStatuses = {
	gr = "data-sort-value=0|[[File:Yes Check Circle.svg|20px|Generally reliable|link=%s#Generally reliable]]",
	nc = "data-sort-value=1|[[File:Achtung-orange.svg|20px|No consensus|link=%s#No consensus]]",
	gu = "data-sort-value=2|[[File:Argentina - NO symbol.svg|20px|Generally unreliable|link=%s#Generally unreliable]]",
	d  = "data-sort-value=3|[[File:Stop hand.svg|20px|Deprecated|link=%s#Deprecated]]",
}
RSPStatuses.m = RSPStatuses.nc -- alias

-- Experimental tetmplate-entry testing
function p.status(frame)
	local args = require("Module:Arguments").getArgs(frame)
	local status = args[1] or args.status
	local blacklisted = args.b or args.blacklisted
	local full_link = mw.title.getCurrentTitle().prefixedText == TopLevelPage and "" or TopLevelPage
	local class = blacklisted and "b" or status
	local status_str = RSPStatuses[status]:format(full_link)
	if blacklisted then
		local blacklist_image = ("[[File:X-circle.svg|20px|Blacklisted|link=%s#Blacklisted]] "):format(full_link)
		-- super stupid way of doing this for now
		status_str = status_str:gsub("data%-sort%-value=(%d)|", "data-sort-value=1%1|" .. blacklist_image)
	end
	return status_str
end

local EmittedShortcutStyle = false
local function RSPShortcut(title)
	local templatestyle = ""
	if not EmittedShortcutStyle then
		local frame = mw.getCurrentFrame()
		templatestyle = frame:extensionTag({name="templatestyles", args={src="Wikipedia:Reliable sources/Perennial sources/Shortcut/styles.css"}})
		EmittedShortcutStyle = true
	end
	local shortcut_url = tostring(mw.uri.fullUrl(title, {redirect="no"}))
	local shortcut_link = "<span class=\"plainlinks\">["..shortcut_url.." "..title.."]</span><span style=\"display: none\">[["..title.."]]</span>"
	return "<br/>" .. templatestyle .. "<span class=\"wp-rsp-sc\">" .. shortcut_link .. "&nbsp;📌</span>"
end

-- Experimental tetmplate-entry testing
function p.shortcut(frame)
	local args = require("Module:Arguments").getArgs(frame)
	return RSPShortcut(args[1] or args.title)
end

local function GatherDiscussions(rfcs, discussions)
	local discussion_lists = {}
	if rfcs then
		local segment = {}
		local rfc_image = "[[File:Treffpunkt.svg|20px|Request for comment|link=]]&nbsp;"
		local blacklist_image = "[[File:X-circle.svg|20px|alt=Spam blacklist request|link=]]&nbsp;"
		for i, rfc in ipairs(rfcs) do
			-- Check for the convenience RSN shorthand
			if rfc:match("^/Archive[ _]%d+") or rfc:match("^#") then
				rfc = "WP:Reliable sources/Noticeboard" .. rfc
			end
			local image = rfc_image
			-- Check if it's for the spam blacklist
			if rfc:match("^/%a+[ _]2%d%d%d#") then
				rfc = "MediaWiki talk:Spam-blacklist/archives" .. rfc
				image = blacklist_image
			elseif rfc:match("^/archives/") then
				rfc = "MediaWiki talk:Spam-blacklist" .. rfc
				image = blacklist_image
			elseif rfc:match(":Spam-blacklist/") then
				image = blacklist_image
			end
			table.insert(segment, image .. "[[" .. rfc .. "]]")
		end
		table.insert(discussion_lists, table.concat(segment, " "))
	end
	if discussions then
		local segment = {}
		local rsn_count = 0
		local other_count = 0
		for i, discussion in ipairs(discussions) do
			discussion = discussion:match("^(.-)|") or discussion -- ignore user-provided piping
			-- Check if it's an RSN discussion
			local is_rsn = false
			if discussion:match("^/Archive[ _]%d+") or discussion:match("^#") then
				discussion = "WP:Reliable sources/Noticeboard" .. discussion
				is_rsn = true
			elseif discussion:match(":Reliable[ _]sources/Noticeboard") or discussion:match(":RSN") then
				is_rsn = true
			end
			if is_rsn then
				rsn_count = rsn_count + 1
				discussion = discussion .. "|" .. rsn_count
			else
				other_count = other_count + 1
				discussion = discussion .. "|" .. uniqueletter(other_count)
			end
			table.insert(segment, "[[" .. discussion .. "]]")
		end
		if #discussions >= 8 then
			local combined = table.concat(segment, " ")
			local frame = mw.getCurrentFrame()
			-- TODO: Provide a simple name here instead of just saying "oh look more discussions!"
			local ref_text = frame:extensionTag({name="ref", content="See also these discussions: " .. combined, args={group="lower-alpha"}})
			table.insert(discussion_lists, "+"..#discussions .. ref_text)
		else
			table.insert(discussion_lists, table.concat(segment, " "))
		end
	end
	return table.concat(discussion_lists, "\n")
end

-- Experimental tetmplate-entry testing
function p.discussions(frame)
	local args = require("Module:Arguments").getArgs(frame)
	return GatherDiscussions(getWikilinks(args.rfcs or ""), getWikilinks(args.discussions or ""))
end

local function RSPLast(year, inprogress, stale)
	if not year then
		return "data-sort-value=0|(Unknown)"
	end
	inprogress = inprogress and inprogress ~= ""
	stale = stale or "auto"
	local full_link = mw.title.getCurrentTitle().prefixedText == TopLevelPage and "" or TopLevelPage
	local out = "data-sort-value=" .. (inprogress and "1" or "") .. year .. "|"
	if inprogress then
		out = out .. "[[File:Pictogram voting wait.svg|20px|Discussion in progress|link="..full_link.."#Discussion in progress]]"
	else
		local cur_year = os.date("*t").year
		local is_stale = stale == "y" or (stale ~= "n" and cur_year-3 > tonumber(year))
		if is_stale then
			out = out .. "[[File:Farm-Fresh hourglass delete.png|20px|Stale discussions|link=" ..full_link.."#Stale discussions]]"
		end
	end
	return out .. "\n" .. year
end

-- Experimental tetmplate-entry testing
function p.last(frame)
	local args = require("Module:Arguments").getArgs(frame)
	return RSPLast(args[1] or args.year, args.inprogress, args.stale)
end

local function DomainUses(domains)
	local out = {}
	for i, domain in ipairs(domains) do
		local encoded = mw.uri.encode(domain, "PATH")
		table.insert(out,
			"[[Special:Search/insource:\""..domain.."\"|"..i.."]]&nbsp;" ..
			"[[File:OOjs UI icon link-ltr.svg|16px|Links|link=Special:Linksearch/*."..encoded.."|class=skin-invert]]&nbsp;" ..
			"[[File:OOjs UI icon check.svg|16px|Spamcheck|link=https://spamcheck.toolforge.org/by-domain?q="..encoded.."|class=skin-invert]]"
		)
	end
	out = table.concat(out, "<br>")
	if #domains >= 4 then
		-- TODO: this is a lazy solution :(
		local frame = mw.getCurrentFrame()
		out = frame:preprocess("{{show begin}}") .. '<div class="center" style="width:auto;margin-left:auto;margin-right:auto;clear:both">' ..  out .. '</div></div></div>'
	end
	return out
end

-- Experimental tetmplate-entry testing
function p.domains(frame)
	local args = require("Module:Arguments").getArgs(frame)
	local domains = {}
	local i = 1
	while true do
		if not args[i] then
			break
		end
		domains[i] = args[i]
		i = i + 1
	end
	return DomainUses(domains)
end

-- Module entry point for generating a row
function p._row(args)
	assert(args.name, "A name is required")
	assert(args.status and RSPStatuses[args.status], "A valid status is required")
	assert(args.id, "An id is required")
	assert(args.summary, "A summary is required")
	
	-- Create shortcut if it exists
	local shortcut_text = args.shortcut and " " .. RSPShortcut(args.shortcut) or ""
	
	-- Handle the status info
	local full_link = mw.title.getCurrentTitle().prefixedText == TopLevelPage and "" or TopLevelPage
	local class = args.blacklisted and "b" or args.status
	local status = RSPStatuses[args.status]:format(full_link)
	if args.blacklisted then
		local blacklist_image = ("[[File:X-circle.svg|20px|Blacklisted|link=%s#Blacklisted]]&nbsp;"):format(full_link)
		-- super stupid way of doing this for now
		status = status:gsub("data%-sort%-value=(%d)|", "data-sort-value=1%1|" .. blacklist_image)
	end
	
	-- Gather discussion links
	local discussion_text = args.discussions_raw -- fallback, just in case
	if not discussion_text then
		discussion_text = GatherDiscussions(args.rfcs, args.discussions)
	end
	
	-- Add a name sort if specified
	local sort_value = args.sort and "data-sort-value=\"" .. args.sort .. "\"|" or ""
	
	-- Sort domain links
	local domain_text = args.domains and DomainUses(args.domains) or ""
	
	-- Put it all together
	local row_text = 
		"|- class=\"s-" .. class .. "\" id=\"" .. args.id .. "\"" ..
		"\n| " .. sort_value .. args.name .. shortcut_text ..
		"\n| " .. status .. 
		"\n| " .. discussion_text ..
		"\n| " .. RSPLast(args.last or args.year, args.inprogress, args.stale) ..
		"\n| " .. args.summary ..
		"\n| " .. domain_text

	-- Mark deprecated entries with a <section> tag
	if args.status == "d" then
		local frame = mw.getCurrentFrame()
		local section_begin = frame:extensionTag({name="section", args={begin="deprecated"}})
		local section_end = frame:extensionTag({name="section", args={['end']="deprecated"}})
		row_text = section_begin .. "\n" .. row_text .. "\n" .. section_end
	end

	return row_text
end

-- Template entry point for generating a row
function p.row(frame)
	local args = require("Module:Arguments").getArgs(frame)
	-- turn string arguments into a table form
	args.domains = args.domains and mw.text.split(args.domains, ", ?\n?")
	args.rfcs = getWikilinks(args.rfcs or "")
	args.discussions = getWikilinks(args.discussions or "")
	return p._row(args)
end

return p