Aller au contenu

Module:Excerpt

Une page de Wikipédia, l'encyclopédie libre.
Ceci est une version archivée de cette page, en date du 13 mai 2018 à 22:31 et modifiée en dernier par Avicenno (discuter | contributions) (Nouvelle page : local p = {} local mRedirect = require('Module:Redirect') local errors -- Return blank text, or an error message if requested local function err(text) if errors then error(text,...). Elle peut contenir des erreurs, des inexactitudes ou des contenus vandalisés non présents dans la version actuelle.
(diff) ← Version précédente | Voir la version actuelle (diff) | Version suivante → (diff)

 Documentation[voir] [modifier] [historique] [purger]
local p = {}
local mRedirect = require('Module:Redirect')

local errors
-- Return blank text, or an error message if requested
local function err(text)
	if errors then error(text, 2) end
	return ""
end

-- Check image for suitablity
local function checkimage(image)
	local page = mw.ustring.match(image, "([Ff]ile%s*:[^|%]]*)") -- File:(name) ...
	 or mw.ustring.match(image, "([Ii]mage%s*:[^|%]]*)") -- or Image:(name) ...
	if not page then return nil end

	local title = mw.title.new(":" .. page) -- Read description page (for :File:Foo rather than File:Foo)
	if not title then return nil end

	local redir = mRedirect.getTarget(title)
	if redir then title = mw.title.new(redir) end

	local frame = mw.getCurrentFrame()
	local desc = frame:preprocess("{{" .. title.prefixedText .. "}}")
	return desc and desc ~= "" and not mw.ustring.match(desc, "[Nn]on%-free") -- hide non-free image
end

-- Attempt to parse [[File:...]] or [[Image:...]], either anywhere or at the start
local function parseimage(text, start)
	local startre = ""
	if start then startre = "^" end -- a true flag restricts search to start of string
	local image = mw.ustring.match(text, startre .. "%[%[%s*[Ff]ile%s*:.*") -- [[File: ...
	 or mw.ustring.match(text, startre .. "%[%[%s*[Ii]mage%s*:.*") -- or [[Image: ...
	if image then
		image = mw.ustring.match(image, "%b[]%s*") -- match [[...]] to handle nesting
	end
	return image
end

-- Attempt to construct a [[File:...]] block from {{infobox ... |image= ...}}
local function argimage(text)
	local token = nil
	if mw.ustring.match(text, "%{%{%s*[Ii]nfobox") then
		local image = mw.ustring.match(text, "|%s*image%s*=%s*([^%}|]*)") -- parse image= argument...
		 or mw.ustring.match(text, "|%s*Cover%s*=%s*([^%}|]-)") -- or Cover= from Infobox album
		if image then -- add in relevant parameters: caption, alt text and image size
			token = "[[File:" .. image
			local caption = mw.ustring.match(text, "|%s*[Cc]aption%s*=%s*([^%}|]*)")
			if caption then token = token .. "|" .. caption end
			local alt = mw.ustring.match(text, "|%s*alt%s*=%s*([^%}|]*)")
			if alt then token = token .. "|alt=" .. alt end
			local image_size = mw.ustring.match(text, "|%s*image_size%s*=%s*([^%}|]*)")
			if image_size then token = token .. "|" .. image_size end
			token = mw.ustring.gsub(token, "\n","") .. "]]\n"
		end
	end

	return token
end

-- Entry point for Lua callers
-- Returns a string value: text of the lead of a page
function p._lead(pagenames, options)
	errors = options.errors

	if not pagenames or #pagenames < 1 then return err("No page names given") end
	local pagename
	local text
	local pagecount = #pagenames
	local firstpage = pagenames[1] or "(nil)" -- save for error message, as it the name will be deleted

	-- read the page, or a random one if multiple pages were provided
	if pagecount > 1 then math.randomseed(os.time()) end
	while not text and pagecount > 0 do
		local pagenum = 1
		if pagecount > 1 then pagenum = math.random(pagecount) end -- pick a random title
		pagename = pagenames[pagenum]
		if pagename and pagename ~= "" then
			pagename = mw.ustring.match(pagename, "%[%[%s*(.-)[]|#]") or pagename -- "[[Foo|Bar]]" → "Foo"
			pagename = mw.ustring.match(pagename, "%S.*%S") -- strip leading and trailing white space

			if pagename and pagename ~= "" then
				local title = mw.title.new(pagename) -- Find the lead section of the named page
				if not title then return err("No title for page name " .. pagename) end
				local redir = mRedirect.getTarget(title)
				if redir then title = mw.title.new(redir) end

				text = title:getContent()
			end
		end
		if not text then table.remove(pagenames, pagenum) end -- this one didn't work; try another
		pagecount = pagecount - 1 -- ensure that we exit the loop eventually
	end
	if not text then return err("Cannot read a valid page: first name is " .. firstpage) end

	text = mw.ustring.gsub(text, "<!%-%-.-%-%->","") -- remove HTML comments
	text = mw.ustring.gsub(text, "%c%s*==.*","") -- remove first heading and everything after it
	text = mw.ustring.gsub(text, "<noinclude>.-</noinclude>", "") -- remove noinclude bits
	text = mw.ustring.gsub(text, "<%s*ref[^>]-/%s*>", "") -- remove refs cited elsewhere
	text = mw.ustring.gsub(text, "<%s*ref.->.-<%s*/%s*ref%s*>", "") -- remove refs
	text = mw.ustring.gsub(text, "<%s*imagemap.->.-<%s*/%s*imagemap%s*>", "") -- remove imagemaps
	for _, t in pairs {"[Ee]fn", "[Ee]fn-la", "[Ee]l[mn]", "[Rr]p?", "[Ss]fn[bp]", "[Ss]f[bn]", "NoteTag", "#[Tt]ag:%s*[Rr]ef",
	 "[CcDd]n", "Citation needed", "Disambiguation needed"} do
		text = mw.ustring.gsub(text, "{{%s*" .. t .. "%s*|.-}}", "") -- remove ref and footnote templates
	end
	text = mw.ustring.gsub(text, "\n%s*{{%s*[Tt][Oo][Cc].-}}", "\n") -- remove most common tables of contents

	local allparas = true -- keep all paragraphs?
	if options.paraflags then
		for _, v in pairs(options.paraflags) do
			if v then allparas = false end -- if any para specifically requested, don't keep all
		end
	end

	local maxfile = 0 -- for efficiency, stop checking images after this many have been found
	if options.fileflags then
		for k, v in pairs(options.fileflags) do
			if v and k > maxfile then maxfile = k end
		end
	end

	-- a basic parser to trim down the lead
	local inlead = false -- have we found some text yet?
	local t = "" -- the stripped down output text
	local files = 0 -- how many [[Image: or [[File: so far
	local paras = 0 -- how many paragraphs so far

	text = mw.ustring.gsub(text,"^%s*","") -- remove initial white space
	repeat -- loop around parsing a template, image or paragraph
		local token = mw.ustring.match(text, "^%b{}%s*") or false -- {{Template}}
		if token then
			if inlead then -- keep comments and templates only within text body
				t = t .. token
			elseif files < maxfile then -- look for [[File:... embedded in an infobox etc. in the preamble
				local image = parseimage(token, false) or argimage(token)
				if image and checkimage(image) then -- keep comments and templates only within text body
					files = files + 1
					if options.fileflags and options.fileflags[files] then
						image = mw.ustring.gsub(image, "|%s*frameless%s*%f[|%]]", "") -- make image a thumbnail, not frameless etc.
						image = mw.ustring.gsub(image, "|%s*framed?%s*%f[|%]]", "")
						if not mw.ustring.match(image, "|%s*thumb%s*%f[|%]]")
						 and not mw.ustring.match(image, "|%s*thumbnail%s*%f[|%]]") then
							image = mw.ustring.gsub(image, "(%]%]%s*)$", "|thumb%1")
						end
						if options.fileargs then image = mw.ustring.gsub(image, "(%]%]%s*)$", "|" .. options.fileargs .. "%1") end
						t = t .. image
					end
				end
			end
		else
			token = parseimage(text, true)
			if token then
				if files < maxfile and checkimage(token) then
					files = files + 1
					if options.fileflags and options.fileflags[files] then
						local image = token
						if options.fileargs then image = mw.ustring.gsub(image, "(%]%]%s*)$", "|" .. options.fileargs .. "%1") end
						t = t .. image
					end
				end
			else -- got a paragraph, which ends at a file, image, blank line or end of text
				local afterend = mw.ustring.len(text) + 1
				local blankpos = mw.ustring.find(text, "\n%s*\n") or afterend
				local endpos = math.min(
				 mw.ustring.find(text, "%[%[%s*[Ff]ile%s*:") or afterend,
				 mw.ustring.find(text, "%[%[%s*[Ff]ile%s*:") or afterend,
				 blankpos)
				token = mw.ustring.sub(text, 1, endpos-1)
				if blankpos < afterend and blankpos == endpos then -- paragraph ends with a blank line
					token = token .. mw.ustring.match(text, "\n%s*\n", blankpos)
				end
				inlead = true
				paras = paras + 1
				if allparas or (options.paraflags and options.paraflags[paras]) then t = t .. token end
			end
		end

		if token then text = mw.ustring.sub(text, mw.ustring.len(token)+1) end
	until not text or text == "" or not token or token == ""

	text = mw.ustring.gsub(t, "\n+$", "") -- remove  trailing line feeds, so "{{Transclude text excerpt|Foo}} more" flows on one line

	if options.more then text = text .. " '''[[" .. pagename .. "|" .. options.more .. "]]'''" end
	return text
end

-- Convert a comma-separated list of numbers or min-max ranges into a list of booleans, e.g. "1,3-5" → {1=true,2=false,3=true,4=true,5=true}
local function numberflags(str)
	local ranges = mw.text.split(str, ",") -- parse ranges, e.g. "1,3-5" → {"1","3-5"}
	local flags = {}
	for _, r in pairs(ranges) do
		local min, max = mw.ustring.match(r, "^%s*(%d+)%s*%-%s*(%d+)%s*$") -- "3-5" → min=3 max=5
		if not max then	min, max = mw.ustring.match(r, "^%s*((%d+))%s*$") end -- "1" → min=1 max=1
		if max then
			for p = min, max do flags[p] = true end
		end
	end
	return flags
end

-- Shared template invocation code for lead and random functions
local function leadrandom(frame, israndom)
	-- args = { 1,2,... = page names, paragraphs = list e.g. "1,3-5", files = list, more = text}
	local args = frame.args -- from calling module
	local pargs = frame:getParent().args -- from template

	local pagenames = { args[1] or pargs[1] } -- For lead, ignore all but the first unnamed argument
	if israndom then
		-- For random, accept any number of page names.  If more than one, we'll pick one randomly
		for i, p in pairs(args) do
			if p and type(i) == 'number' and i > 1 then table.insert(pagenames, p) end
		end
		for i, p in pairs(pargs) do
			if p and type(i) == 'number' and i > 1 and not args[i] then table.insert(pagenames, p) end
		end
	end

	local options = {}
	options.paraflags = numberflags(args["paragraphs"] or pargs["paragraphs"] or "") -- parse paragraphs, e.g. "1,3-5" → {"1","3-5"}
	options.fileflags = numberflags(args["files"] or pargs["files"] or "") -- parse file numbers
	options.fileargs = args["fileargs"] or pargs["fileargs"]
	options.more = args["more"] or pargs["more"]
	if options.more and options.more == "" then options.more = "Read more..." end -- more= is short for this default text
	options.errors = args["errors"] or pargs["errors"]

	local text = p._lead(pagenames, options)
	return frame:preprocess(text)
end

-- Entry points for template callers using #invoke:
function p.lead(frame) return leadrandom(frame, false) end
function p.random(frame) return leadrandom(frame, true) end

return p