Module:Sandbox/Aidan9382/RSP

From Wikipedia, the free encyclopedia
Jump to navigation Jump to search

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