Module:Subpages 5

Everything About Fiction You Never Wanted to Know.
Revision as of 14:18, 27 July 2023 by Robkelk (talk | contribs) (standardized the "local pageorder" and "local crowners" lists)

Documentation for this module may be created at Module:Subpages 5/doc

local sp = {}

local pageorder = {
	["trope"] = {
		"Analysis", "Haiku", "Headscratchers", "Image Links", "Laconic",
		"Playing With", "Quotes", "Useful Notes"
	},
	["work"] = {
		"Analysis", "Characters", "Laconic", "Recap", "Trivia", "Setting", "YMMV",
		"Fridge", "Fanfic Recs", "Haiku", "Headscratchers", "Ho Yay", "Image Links", 
		"Memes", "Radar", "Quotes", "Source", "Useful Notes", "WMG"
	},
	["creator"] = {"YMMV", "Quotes", "Fanfic Recs", "Analysis", "Trivia", "WMG",
		"Image Links", "Haiku", "Laconic"}
}
local crowners = {
	["trope"] = { "Advertising", "Anime and Manga", "Comic Books", "Fan Works",
		"Film", "Literature", "Live-Action TV", "Music", "Newspaper Comics",
		"Oral Tradition", "Professional Wrestling", "Puppet Shows", "Radio",
		"Tabletop Games", "Theatre", "Video Games", "Web Animation", 
		"Web Comics", "Web Original", "Western Animation", "Other Media", "Real Life" },
	["work"] = { "Awesome", "Awesome Music", "Funny", "Heartwarming",
		"Nightmare Fuel", "Tear Jerker" },
	["creator"] = { "Awesome", "Funny", "Heartwarming", "Nightmare Fuel", "Tear Jerker" }
}
local crownername = {
	["trope"]   = "By Medium",
	["work"]    = "Crowners",
	["creator"] = "Crowners"
}
local addns = {
	["trope"]   = { },
	["work"]    = { "Reviews" },
	["creator"] = { }
}

-- localize functions
local insert = table.insert
local concat = table.concat
local find = string.find
local len  = string.len
local sub  = string.sub
local rep  = string.rep
local listlevel = { '*', '**', '***', '****', '*****' }

-- This function is the main page menu type, with dropdowns for subpages
function sp.menu ( frame )
	local page	   = frame.args[1] or frame:callParserFunction('TOPLEVELPAGE')
	local template = frame.args[2] or "work"
	local wppage   = frame.args[3] or page
	local nowp     = (frame.args[4] ~= "" )
	if wppage == "" then wppage = page end

	-- create variant top level page variables
	local mainpage = page;
	if template == "index" then
		template = "trope"
		crowners["trope"] = {}
		mainpage = ":" .. page
		page = page:gsub("Category:", "", 1)
	end
	local pageslash = page..'/'

	if pageorder[template] == nil then return "Module error: invalid template argument" end

	local allsptxt = frame:callParserFunction('SUBPAGES', { page, sep = "|" })
	local subpage_list = split(allsptxt, "|")

	local tree = build_tree(page, subpage_list)

	-- initialize result with Main link
	local linkout = { '* [[' .. mainpage .. '|<span id="tm-main"></span>Main]]\n' }
	local crownerout = { }
	local otherout   = { }
	local missingout = { }
	local linkns    = { }
	local missingns  = { }

	for _, subpage in ipairs(pageorder[template]) do
		text = build_list( { [subpage] = tree[subpage] }, pageslash, 1 )
		if text ~= '' then
			insert(linkout, text)
		else
			insert(missingout, subpage)
		end
		tree[subpage] = nil
	end
	for _, subpage in ipairs(crowners[template]) do
		text = build_list( { [subpage] = tree[subpage] }, pageslash, 2 )
		if text ~= '' then
			insert(crownerout, text)
		else
			insert(missingout, subpage)
		end
		tree[subpage] = nil
	end
	--deal with the leftover subpages
	if next(tree) then
		local ordered_keys = {}
		for k in pairs(tree) do
			insert(ordered_keys, k)
		end
		table.sort(ordered_keys)

		for i = 1, #ordered_keys do
			local subpage = ordered_keys[i]
			text = build_list( { [subpage] = tree[subpage] }, pageslash, 2 )
			if text ~= '' then
				insert(otherout, text)
			end
		end
	end

	for _, ns in ipairs(addns[template]) do
		local tobj = mw.title.new( page, ns )
		if tobj.exists then
			insert(linkns, '* [[' .. tobj.fullText .. '|<span id="tm-'..ns..'"></span>'..ns .. ']]\n')
		else
			insert(missingns, ns)
		end
	end

	local jsdata = '<div id="tm-data" style="display:none" '
		.. 'data-toplevelpage="' .. page .. '" '
		.. 'data-wanted="'	   .. concat( missingout, "&#9;" ) .. '" '
		.. 'data-nswanted="'  .. concat( missingns, "&#9;" ) .. '" '
		.. 'data-templatetype="' .. template .. '" '
		.. '></div>'
	local crowner_link = next(crownerout)
		and '* [[#top|<span id="tm-' .. crownername[template].. '"></span>'..crownername[template]..']]\n'
		or ''
	local wikipedia_link = nowp
		and ''
		or "* [[wikipedia:" .. wppage ..
		'|<span id="tm-Wikipedia"'.. (frame.args[3] == "" and ' class="tm-wpdefault"' or '') ..'></span>Wikipedia]]\n'
	local all_sp_link = '* [[Special:PrefixIndex/' .. pageslash .. '|<span id="tm-Allothers"></span>All Subpages]]\n'
	local italictitle = ( template == "work" )
		and italictitle(frame, page)
		or ''

	return concat(linkout)
		.. concat(linkns)
		.. crowner_link
		.. concat(crownerout)
		.. wikipedia_link
		.. all_sp_link
		.. concat(otherout)
		.. '* <strong><span id="tm-New"></span>Create New</strong><ul id="tm-wantedpages"></ul>\n'
		.. jsdata
		.. italictitle
end

-- Another output function, which makes an ordinary bullet tree of subpages
function sp.tree ( frame )
	local page	 = frame.args[1] or frame:callParserFunction('TOPLEVELPAGE')

	local allsptxt = frame:callParserFunction('SUBPAGES', { page, sep = "|" })
	local subpage_list = split(allsptxt, "|")

	local tree = build_tree(page, subpage_list)

	if page:match("^Category:") then page = ":"..page end
	return "; [["..page.."]]\n" ..	build_list( tree, page..'/', 1 )
end

-- transforms an array (table) of subpages into a tree data structure
function build_tree ( page, subpage_list )
	local path_tree = { }
	local pagelenoffset = len(page) + 2

	for _, fullpath in ipairs(subpage_list) do
		local path = sub(fullpath, pagelenoffset)
		local list = split(path, '/')
		local lastdir = path_tree
		
		for i, dir in ipairs(list) do
			if lastdir[dir] == nil then lastdir[dir] = { } end
			lastdir = lastdir[dir]
		end
	end
	return path_tree
end

-- given a tree of subpages, outputs an indented list
-- recursively calls itself to build deeper trees
function build_list ( tree, prefix, level )
	local libase = listlevel[level] or rep('*', level)
	
	local ul = {}

	local ordered_sp = {}
	for page in pairs(tree) do
		insert(ordered_sp, page)
	end
	table.sort(ordered_sp)

	for i = 1, #ordered_sp do
		local page = ordered_sp[i]
		local branch = tree[page]
		local li
		
		if level <= 2 then
			li = libase .. " [["..prefix..page..'|<span id="tm-'..page..'"></span>'..page..']]\n'
		else
			li = libase ..' [['..prefix..page..'|'..page..']]\n'
		end
		insert(ul, li)

		if next(branch) then
			local nextprefix = (prefix..page..'/')
			insert(ul, build_list(branch, nextprefix, level+1))
		end
	end
	return concat(ul)
end

-- split() implementation reproduced from, uh, somewhere
function split(str, sSeparator, nMax, bRegexp)
	assert(sSeparator ~= '')
	assert(nMax == nil or nMax >= 1)

	local aRecord = {}

	if len(str) > 0 then
		local bPlain = not bRegexp
		nMax = nMax or -1

		local nField=1 nStart=1
		local nFirst,nLast = find(str, sSeparator, nStart, bPlain)
		while nFirst and nMax ~= 0 do
			aRecord[nField] = sub(str, nStart, nFirst-1)
			nField = nField+1
			nStart = nLast+1
			nFirst,nLast = find(str, sSeparator, nStart, bPlain)
			nMax = nMax-1
		end
		aRecord[nField] = sub(str, nStart)
	end

	return aRecord
end

-- for work type pages, italicizes the title of the work
function italictitle(frame, basepage)
	local title = mw.title.getCurrentTitle()

	-- don't italicize subpages
	-- but we can't just naively split on '/' due to top level pages with slashes
	local subpages = (len(title.text) > len(basepage))
		and sub(title.text, len( mw.text.decode(basepage, 1))+1 ) or ''
	-- Find the parts before and after the disambiguation parentheses, if any.
	local prefix, parentheses = mw.ustring.match(basepage, '^(.+) (%([^%(%)]+%))$')

	-- If parentheses were found, italicise only the part before them. Otherwise
	-- italicise the whole title.
	local result
	if prefix and parentheses then
		result = "''" .. prefix .. "'' " .. parentheses .. subpages
	else
		result = "''" .. basepage .. "''" .. subpages
	end

	-- Add the namespace if we're not in mainspace.
	if title.namespace ~= 0 then
		result = mw.site.namespaces[title.namespace].name .. ':' .. result
	end

	-- Call displaytitle with the text we generated.
	return mw.getCurrentFrame():callParserFunction(
		'DISPLAYTITLE',
		result
		)
end    


return sp