Module:Excerpt/templates

From The League Wiki
Jump to navigation Jump to search
-- Invocation functions for English Wikipedia templates
-- May not work properly or at all on other wikis

local e = require("Module:Excerpt")
local p = {}

-- Shared invocation function used by templates meant for portals
local function portal(frame, template)
	local args = e.parseArgs(frame)

	errors = args['errors'] or false -- disable error reporting unless requested

	-- There should be at least one argument except with selected=Foo and Foo=Somepage
	if #args < 1 and not (template == "selected" and args[template] and args[args[template]]) then
		return e.wikiError("noPage")
	end

	-- Figure out the page to excerpt
	local page
	local candidates = {}

	if template == "lead" then
		page = args[1]
		page = mw.text.trim(page)
		if not page or page == "" then return e.wikiError("noPage") end
		candidates = { page }

	elseif template == "selected" then
		local key = args[template]
		local count = #args
		if tonumber(key) then -- normalise article number into the range 1..#args
			key = key % count
			if key == 0 then key = count end
		end
		page = args[key]
		page = mw.text.trim(page)
		if not page or page == "" then return e.wikiError("noPage") end
		candidates = { page }

	elseif template == "linked" or template == "listitem" then
		local source = args[1]
		local text, source = e.getContent(source)
		if not source then
			return e.wikiError("noPage")
		elseif not text then
			return e.wikiError("noPage")
		end
		local section = args.section
		if section then -- check relevant section only
			text = e.getSection(text, section)
			if not text then return e.wikiError("sectionNotFound", section) end
		end
		-- Replace annotated links with real links
		text = mw.ustring.gsub(text, "{{%s*[Aa]nnotated[ _]link%s*|%s*(.-)%s*}}", "[[%1]]")
		if template == "linked" then
			for candidate in mw.ustring.gmatch(text, "%[%[%s*([^%]|\n]*)") do table.insert(candidates, candidate) end
		else -- listitem: first wikilink on a line beginning *, :#, etc. except in "See also" or later section
			text = mw.ustring.gsub(text, "\n== *See also.*", "")
			for candidate in mw.ustring.gmatch(text, "\n:*[%*#][^\n]-%[%[%s*([^%]|\n]*)") do table.insert(candidates, candidate) end
		end

	elseif template == "random" then
		for key, value in pairs(args) do
			if value and type(key) == "number" then table.insert(candidates, value) end
		end
	end

	-- Build an options array for the Excerpt module out of the arguments and the desired defaults
	local options = {
		errors = args['errors'] or false,
		fileargs = args['fileargs'],
		fileflags = e.numberFlags( args['files'] ),
		paraflags = e.numberFlags( args['paragraphs'] )
	}

	-- Select a random candidate and make sure its valid
	local text
	local candidateCount = #candidates
	if candidateCount > 0 then
		local candidateKey = 1
		local candidateString
		local candidateArgs
		if candidateCount > 1 then math.randomseed(os.time()) end
		while (not text or text == "") and candidateCount > 0 do
			if candidateCount > 1 then candidateKey = math.random(candidateCount) end -- pick a random candidate
			candidateString = candidates[candidateKey]
			if candidateString and candidateString ~= "" then
				-- We have page or [[page]] or [[page|text]], possibly followed by |opt1|opt2...
				page, candidateArgs = mw.ustring.match(candidateString, "^%s*(%[%b[]%])%s*|?(.*)")
				if page and page ~= "" then
					page = mw.ustring.match(page, "%[%[([^|%]]*)") -- turn [[page|text]] into page, discarding text
				else -- we have page or page|opt...
					page, candidateArgs = mw.ustring.match(candidateString, "%s*([^|]*[^|%s])%s*|?(.*)")
				end
				-- candidate arguments (even if value is "") have priority over global arguments
				if candidateArgs and candidateArgs ~= "" then
					for _, t in pairs(mw.text.split(candidateArgs, "|")) do
						local k, v = mw.ustring.match(t, "%s*([^=]-)%s*=(.-)%s*$")
						if k == 'files' then options.fileflags = e.numberFlags(v)
						elseif k == 'paragraphs' then options.paraflags = e.numberFlags(v)
						elseif k == 'more' then args.more = v
						else options[k] = v end
					end
				end
				if page and page ~= "" then
					local section = mw.ustring.match(page, "[^#]+#?([^#]*)") -- save the section
					text, page = e.getContent(page) -- make sure the page exists
					if page and page ~= "" and text and text ~= "" then
						if args.nostubs then
							local isStub = mw.ustring.find(text, "%s*{{[^{|}]*%-[Ss]tub%s*}}")
							if isStub then text = nil end
						end
						page = page .. '#' .. section -- restore the section
						text = e.get(page, options)
					end
				end
			end
			table.remove(candidates, candidateKey) -- candidate processed
			candidateCount = candidateCount - 1 -- ensure that we exit the loop after all candidates are done
		end
	end
	if not text or text == "" then return e.wikiError("No valid pages found") end

	if args.showall then
		local separator = args.showall
		if separator == "" then separator = "{{clear}}{{hr}}" end
		for _, candidate in pairs(candidates) do
			local t = e.get(candidate, options)
			if t ~= "" then
				text = text .. separator .. t
			end
		end
	end

	-- If more= then append a link to article for more info
	if args.more then
		local more = "Read more..." -- default text
		if args.more ~= "" then more = args.more end -- use the given text
		text = text .. " '''[[" .. page .. "|" .. more .. "]]'''"
	end

	-- Add a collapsed list of pages which might appear
	if args.list and not args.showall then
		local list = args.list
		if list == "" then list = "Other articles" end
		text = text .. "{{collapse top|title={{resize|85%|" ..list .. "}}|bg=fff}}{{hlist"
		for _, candidate in pairs(candidates) do
			if mw.ustring.match(candidate, "%S") then text = text .. "|[[" .. mw.text.trim(candidate) .. "]]" end
		end
		text = text .. "}}\n{{collapse bottom}}"
	end

	return frame:preprocess(text)
end

-- Invocation function used by {{Excerpt}}
local function excerpt(frame)
	local args = e.parseArgs(frame)

	-- Make sure the requested page exists
	local page = args[1] or args.article or args.source or args.page
	if not page then return e.wikiError("noPage") end
	local title = mw.title.new(page)
	if not title then return e.wikiError("noPage") end
	if title.isRedirect then title = title.redirectTarget end
	if not title.exists then return e.wikiError("pageNotFound", page) end
	page = title.prefixedText

	-- Define some useful variables
	local section = args[2] or args.section or mw.ustring.match(args[1], "[^#]+#([^#]+)")
	local tag = args.tag or 'div'

	-- Define the HTML elements
	local block = mw.html.create(tag):addClass('excerpt-block')
	if e.is(args.indicator) then block:addClass('excerpt-indicator') end

	local style = frame:extensionTag{ name = 'templatestyles', args = { src = 'Excerpt/styles.css' } }

	local hatnote
	if not args.nohat then
		if args.this then
			hatnote = args.this
		elseif args.indicator then
			hatnote = 'This is'
		elseif args.only == 'file' then
			hatnote = 'This file is'
		elseif args.only == 'file' then
			hatnote = 'These files are'
		elseif args.only == 'list' then
			hatnote = 'This list is'
		elseif args.only == 'lists' then
			hatnote = 'These lists are'
		elseif args.only == 'table' then
			hatnote = 'This table is'
		elseif args.only == 'tables' then
			hatnote = 'These tables are'
		else
			hatnote = 'This section is'
		end
		hatnote = hatnote .. ' an excerpt from '
		if section then
			hatnote = hatnote .. '[[' .. page .. '#' .. section .. '|' .. page .. ' ยง ' .. section .. ']]'
		else
			hatnote = hatnote .. '[[' .. page .. ']]'
		end
		hatnote = hatnote .. "''" .. '<span class="mw-editsection-like plainlinks"><span class="mw-editsection-bracket">[</span>['
		hatnote = hatnote .. title:fullUrl('action=edit') .. ' edit'
		hatnote = hatnote .. ']<span class="mw-editsection-bracket">]</span></span>' .. "''"
		hatnote = require('Module:Hatnote')._hatnote(hatnote, {selfref=true}) or e.wikiError('Error generating hatnote')
	end

	-- Build the module options out of the template arguments and the desired defaults
	local options = {
		fileflags = e.numberFlags( args['files'] or 1 ),
		paraflags = e.numberFlags( args['paragraphs'] ),
		filesOnly = e.is( args['only'] == 'file' or args['only'] == 'files' ),
		listsOnly = e.is( args['only'] == 'list' or args['only'] == 'lists'),
		tablesOnly = e.is( args['only'] == 'table' or args['only'] == 'tables' ),
		keepTables = e.is( args['tables'] or true ),
		keepRefs = e.is( args['references']  or true ),
		keepSubsections = e.is( args['subsections'] ),
		nobold = not e.is( args['bold'] ),
		fragment = args['fragment']
	}

	-- Get the excerpt itself
	if section then page = page .. '#' .. section end
	local ok, excerpt = pcall(e.get, page, options)
	if not ok then return e.wikiError(excerpt) end
	excerpt = "\n" .. excerpt -- line break is necessary to prevent broken tables and lists
	if mw.title.getCurrentTitle().isContentPage then excerpt = excerpt .. '[[Category:Articles with excerpts]]' end
	excerpt = frame:preprocess(excerpt)
	excerpt = mw.html.create(tag):addClass('excerpt'):wikitext(excerpt)

	-- Combine and return the elements
	return block:node(style):node(hatnote):node(excerpt)
end

-- Entry points for English Wikipedia templates
function p.lead(frame) return portal(frame, "lead") end -- {{Transclude lead excerpt}} reads a randomly selected article linked from the given page
function p.linked(frame) return portal(frame, "linked") end -- {{Transclude linked excerpt}} reads a randomly selected article linked from the given page
function p.listitem(frame) return portal(frame, "listitem") end -- {{Transclude list item excerpt}} reads a randomly selected article listed on the given page
function p.random(frame) return portal(frame, "random") end -- {{Transclude random excerpt}} reads any article (default for invoke with one argument)
function p.selected(frame) return portal(frame, "selected") end -- {{Transclude selected excerpt}} reads the article whose key is in the selected= parameter
function p.excerpt(frame) return excerpt(frame) end -- {{Excerpt}} transcludes part of an article into another article

return p