Module:Excerpt: Difference between revisions

Content deleted Content added
Change parameter name to "subsections" per being more intuitive to its intended use
Use infobox CSS class if it exists (mainly for dark mode compatibility)
 
(12 intermediate revisions by 2 users not shown)
Line 1:
-- Module:Excerpt implements the Excerpt template
local Transcluder = require('Module:Transcluder')
-- Documentation and master version: https://en.wikipedia.org/wiki/Module:Excerpt
-- Authors: User:Sophivorus, User:Certes, User:Aidan9382 & others
-- License: CC-BY-SA-3.0
 
local yesnoTranscluder = require( 'Module:YesnoTranscluder' )
 
local ok, configyesno = pcall(require,( 'Module:Excerpt/configYesno' )
 
local ok, config = pcall( require, 'Module:Excerpt/config' )
if not ok then config = {} end
 
Line 10 ⟶ 15:
-- Helper function to get arguments
local args
local function getArg( key, default )
local value = args[ key ]
if value and mw.text.trim( value ) ~= '' then
return value
end
Line 19 ⟶ 24:
 
-- Helper function to handle errors
local function getError( message, value )
if type( message ) == 'string' then
message = Transcluder.getError( message, value )
end
if config.categories and config.categories.errors and mw.title.getCurrentTitle().isContentPage then
message:node( '[[Category:' .. config.categories.errors .. ']]' )
end
return message
Line 30 ⟶ 35:
 
-- Helper function to get localized messages
local function getMessage( key )
local ok, TNT = pcall( require, 'Module:TNT' )
if not ok then return key end
return TNT.format( 'I18n/Module:Excerpt.tab', key )
end
 
-- Main entry point for templates
function p.main(frame)
argsfunction = Transcluderp.parseArgsmain( frame )
args = Transcluder.parseArgs( frame )
 
-- Make sure the requested page exists
local page = getArg(1, getArg('article')1 )
if not page or page == '{{{1}}}' then return getError( 'no-page' ) end
local title = mw.title.new(page)
if not title then return getError( 'noinvalid-pagetitle', page ) end
if title.isRedirect then title = title.redirectTarget end
if not title.exists then return getError( 'page-not-found', page ) end
page = title.prefixedText
 
-- Set variables from the template parameters
local fragmentsection = getArg( 2, mw.ustring.match( getArg( 1 ), 'fragment[^#]+#(.+)' ) )
local sectionhat = fragment or getArgyesno(2, getArg('section', mw.ustring.match( getArg(1, getArg('articlehat') ), '[^#]+#([^#]+)')true ) )
local hatedit = yesno( getArg( 'hatedit', true ) )
local editthis = yesnogetArg( getArg('editthis', true) )
local thisonly = getArg( 'thisonly' )
local onlyfiles = getArg( 'files', getArg( 'file', ( only == 'file' and 1 ) ) )
local fileslists = getArg( 'fileslists', getArg( 'filelist', ( only == 'filelist' and 1 ) ) )
local liststables = getArg( 'liststables', getArg( 'listtable', ( only == 'listtable' and 1 ) ) )
local tablestemplates = getArg( 'tablestemplates', getArg( 'tabletemplate', ( only == 'tabletemplate' and 1 ) ) )
local templatesparagraphs = getArg( 'templatesparagraphs', getArg( 'templateparagraph', ( only == 'templateparagraph' and 1 ) ) )
local paragraphsreferences = getArg('paragraphs', getArg('paragraphreferences', ( only == 'paragraph' and 1 ) ) )
local referencessubsections = getArgnot yesno('references', getArg('reference', ( only == 'referencesubsections' and 1 ) ) )
local subsectionsnoLinks = not yesno( getArg( 'subsectionslinks', true ) )
local noBold = not yesno( getArg( 'bold' ) )
local inlineonlyFreeFiles = yesno( getArg( 'inlineonlyfreefiles', true ) )
local quotebriefDates = yesno( getArg( 'quotebriefdates', false ) )
local moreinline = yesno( getArg( 'moreinline' ) )
local classquote = yesno( getArg( 'classquote' ) )
local blacklistmore = table.concatyesno( getArg(config.templates or'more' {}), ',')
local class = getArg( 'class' )
local displaytitle = getArg( 'displaytitle' ) or page
 
-- Build the hatnote
Line 74 ⟶ 82:
hat = this
elseif quote then
hat = getMessage( 'this' )
elseif only then
hat = getMessage( only )
else
hat = getMessage( 'section' )
end
hat = hat .. ' ' .. getMessage( 'excerpt' ) .. ' '
if section and not fragment then
hat = hat .. '[[:' .. page .. '#' .. mw.uri.anchorEncode( section ) .. '|' .. pagedisplaytitle
.. ' § ' .. mw.ustring.gsub( section, '%[%[([^]|]+)|?[^]]*%]%]', '%1' ) .. ']].' -- remove nested links
else
hat = hat .. '[[:' .. page .. '|' .. pagedisplaytitle .. ']].'
end
if edit then
hat = hat .. "''" .. '<span class="mw-editsection-like plainlinks"><span class="mw-editsection-bracket">[</span>['
hat = hat .. title:fullUrl( 'action=edit' ) .. ' ' .. mw.message.new( 'editsection' ):plain()
hat = hat .. ']<span class="mw-editsection-bracket">]</span></span>' .. "''"
end
if config.hat then
hat = config.hat .. hat .. '}}'
hat = frame:preprocess( hat )
else
hat = mw.html.create( 'div' ):addClass( 'dablink excerpt-hat' ):wikitext( hat )
end
else
Line 104 ⟶ 112:
-- Build the "Read more" link
if more and not inline then
more = "'''[[" .. page .. '#' .. ( section or '' ) .. "|" .. getMessage( 'more' ) .. "]]'''"
more = mw.html.create( 'div' ):addClass( 'noprint excerpt-more' ):wikitext( more )
else
more = nil
end
 
-- Build the options for Module:Transcluder out of the template argumentsparameters and the desired defaults
local options = {
files = files,
Line 116 ⟶ 124:
tables = tables,
paragraphs = paragraphs,
templates = templates or '-' .. blacklist,
sections = subsections,
categories = 0,
references = references,
only = only and mw.text.trim( only, 's' ) .. 's',
noLinks = noLinks,
noBold = noBold,
noSelfLinks = true,
noNonFreeFiles = trueonlyFreeFiles,
noBehaviorSwitches = true,
fixReferences = true,
Line 130 ⟶ 138:
 
-- Get the excerpt itself
local title = page .. '#' .. ( section or '' )
local ok, excerpt = pcall( Transcluder.get, title, options )
if not ok then return getError( excerpt ) end
if mw.text.trim( excerpt ) == '' and not only then
if section then return getError( 'section-empty', section ) else return getError( 'lead-empty' ) end
end
 
-- Fix birth and death dates, but only in the first paragraph
-- Add a line break in case the excerpt starts with a table or list
if briefDates then
excerpt = '\n' .. excerpt
local startpos = 1 -- skip initial templates
local s
local e = 0
repeat
startpos = e + 1
s, e = mw.ustring.find( excerpt, "%s*%b{}%s*", startpos )
until not s or s > startpos
s, e = mw.ustring.find( excerpt, "%b()", startpos ) -- get (...), which may be (year–year)
if s and s < startpos + 100 then -- look only near the start
local year1, conjunction, year2 = mw.ustring.match( mw.ustring.sub( excerpt, s, e ), '(%d%d%d+)(.-)(%d%d%d+)' )
if year1 and year2 and (mw.ustring.match( conjunction, '[%-–—]' ) or mw.ustring.match( conjunction, '{{%s*[sS]nd%s*}}' )) then
local y1 = tonumber(year1)
local y2 = tonumber(year2)
if y2 > y1 and y2 < y1 + 125 and y1 <= tonumber( os.date( "%Y" )) then
excerpt = mw.ustring.sub( excerpt, 1, s ) .. year1 .. "–" .. year2 .. mw.ustring.sub( excerpt, e )
end
end
end
end
 
-- If no file was found, try to excerptget one from the removed infoboxesinfobox
local fileNamespaces = Transcluder.getNamespaces( 'File' )
if ( ( only == 'file' or only == 'files' ) or ( not only and ( files ~= '0' or not files ) ) ) and -- caller asked for files
not Transcluder.matchAny( excerpt, '%[%[', fileNamespaces, ':' ) and -- and there are no files in Transcluder's output
config.captions -- and we have the config option required to try finding files in templates
then
-- We cannot distinguish the infobox from the other templates so we search them all
local templates = Transcluder.get(title, { only = 'templates', templates = blacklist, fixReferences = true } )
local parametersinfobox = Transcluder.getParametersgetTemplates(templates excerpt );
infobox = table.concat( infobox )
local file, captions, caption
local parameters = Transcluder.getParameters( infobox )
for _, pair in pairs(config.captions) do
local file, captions, caption, cssclasses, cssclass
for _, pair in pairs( config.captions ) do
file = pair[1]
file = parameters[file]
if file and Transcluder.matchAny( file, '^.*%.', { '[Jj][Pp][Ee]?[Gg]', '[Pp][Nn][Gg]', '[Gg][Ii][Ff]', '[Ss][Vv][Gg]' }, '.*' ) then
file = mw.ustring.match( file, '%[?%[?.-:([^{|]+)%]?%]?' ) or file -- [[File:Example.jpg{{!}}upright=1.5]] to Example.jpg
captions = pair[2]
for _, p in pairs( captions ) do
if parameters[ p ] then caption = parameters[ p ] break end
end
-- Check for CSS classes
-- We opt to use skin-invert-image instead of skin-invert
-- in all other cases, the CSS provided in the infobox is used
if pair[3] then
cssclasses = pair[3]
for _, p in pairs(cssclasses) do
if parameters[p] then
cssclass = ((parameters[p] == 'skin-invert') and 'skin-invert-image' or parameters[p])
break
end
end
end
excerpt = '[[File:' .. file ..
(cssclass and ('|class=' .. cssclass) or '') ..
'|thumb|' .. (caption or '') .. ']]' .. excerpt
if ( onlyFreeFiles ) then
excerpt = Transcluder.removeNonFreeFiles( excerpt )
end
excerpt = '[[File:' .. file .. '|thumb|' .. (caption or '') .. ']]' .. excerpt
excerpt = Transcluder.removeNonFreeFiles(excerpt)
break
end
end
end
 
-- Unlike other elements, templates are filtered here
-- because we had to search the infoboxes for files
local trash
if only and ( only == 'template' or only == 'templates' ) then
trash, excerpt = Transcluder.getTemplates( excerpt, templates );
else -- Remove blacklisted templates
local blacklist = config.blacklist and table.concat( config.blacklist, ',' ) or ''
if templates then
if string.sub( templates, 1, 1 ) == '-' then --Unwanted templates. Append to blacklist
blacklist = templates .. ',' .. blacklist
else --Wanted templates. Replaces blacklist and acts as whitelist
blacklist = templates
end
else
blacklist = '-' .. blacklist
end
trash, excerpt = Transcluder.getTemplates( excerpt, blacklist );
end
 
-- Remove extra line breaks but leave one before and after so the parser interprets lists, tables, etc. correctly
excerpt = mw.text.trim( excerpt )
excerpt = string.gsub( excerpt, '\n\n\n+', '\n\n' )
excerpt = '\n' .. excerpt .. '\n'
 
-- Remove nested categories
excerpt = frame:preprocess( excerpt )
local categories, excerpt = Transcluder.getCategories( excerpt, options.categories )
 
-- Add tracking categories
Line 188 ⟶ 259:
 
-- Combine and return the elements
local tag1 = 'div'
local tag2 = 'div'
if inline then
return mw.text.trim( excerpt )
tag1 = 'span'
end
tag2 = 'span'
local tag = 'div'
elseif quote then
if quote then
tag2 = 'blockquote'
tag = 'blockquote'
end
excerpt = mw.html.create(tag1 'div' ):addClass( 'excerpt' ):wikitext( excerpt )
local block = mw.html.create(tag2 tag ):addClass( 'excerpt-block' ):addClass( class )
return block:node( styles ):node( hat ):node( excerpt ):node( more )
end
 
-- Entry points for backwards compatibility
function p.lead( frame ) return p.main( frame ) end
function p.excerpt( frame ) return p.main( frame ) end
 
return p