Module:Header template
- Voir Aide:Transclusion pour l’utilisation de la commande <pages index=… />.
- Modèle utilisé par la balise <pages/> pour générer les boîtes titres
- Les paramètres acceptés par ce modèle proviennent de la page d’index.
- Les paramètres peuvent aussi être passés à la commande "pages".
- Exemple :
<pages index=foo header=1 auteur="[[Balzac]]" />
- Détails techniques
Ce modèle est implémenté en Lua via le module Header Template. Il utilise les paramètres suivants définis par l’extension ProofreadPage :
paramètre | description |
---|---|
from | la valeur from définie par l’utilisateur, 1 par défaut |
displayed_from | le numéro de page à afficher pour la première page (par défaut celui défini dans la page Livre:) |
to | la valeur to définie par l’utilisateur, par défaut la dernière page |
displayed_to | le numéro de page à afficher pour la dernière page (par défaut celui défini dans la page Livre:) |
current | le nom du lien pointant vers la page courante dans le sommaire de la page d’index du Livre |
prev | le nom du lien pointant vers la page précédant la page courante dans le sommaire de la page d’index du Livre |
next | le nom du lien pointant vers la page suivant la page courante dans le sommaire de la page d’index du Livre |
value | la valeur de l’attribut header de la balise <pages />, ou toc si ni from ni to ne sont précisés |
Les autres paramètres sont les noms des champs apparaissant dans le formulaire de l’index du Livre. Leur valeur est celle qui apparaît dans le formulaire, sauf si l’utilisateur l'a redéfinie dans la balise <pages />, auquel cas, la valeur de la balise a priorité sur celle de l’index.
Pour le paramètre type, la valeur apparaissant dans le menu déroulant du formulaire de la page d’index est convertie en un nom à usage interne suivant le tableau de correspondance suivant :
valeur interne | valeur du menu déroulant |
---|---|
book | Livre |
collection | Recueil |
journal | Journal ou revue |
phdthesis | Thèse, rapport |
dictionary | Dictionnaire, encyclopédie, ouvrage de référence |
C’est la valeur interne qui est utilisée par le modèle. De même, si l’utilisateur souhaite redéfinir la valeur du champ type à l’intérieur de la balise <pages />, il doit utiliser la valeur interne.
function errorMessageNode(text)
-- Return a html formated version of text stylized as an error.
local html = mw.html.create('div')
html:addClass('error')
:wikitext(text)
:wikitext('[[Catégorie:Pages faisant un appel erroné au module Header template]]')
return html
end
function cleanCoinsParameter( param )
param = string.gsub( param, "%[%[.*|(.*)%]%]", "%1" )
return string.gsub( param, "%[%[(.*)%]%]", "%1" )
end
function toAbsoluteTitle( relative_title, base_title )
--TODO: hacky implementation
return mw.getCurrentFrame():callParserFunction( '#rel2abs', { relative_title, tostring( base_title or mw.title.getCurrentTitle() ) } )
end
function formatString( str, schema_property )
return tostring(mw.html.create('span')
:attr('itemprop', schema_property)
:wikitext(str)
)
end
function formatYear( date, schema_property )
local year = tonumber( date )
if year == nil or year < 1000 then
return tostring(mw.html.create('span')
:attr('itemprop', schema_property)
:wikitext(date))
else
return tostring(mw.html.create('time')
:attr('datetime', year)
:attr('itemprop', schema_property)
:wikitext(date))
end
end
function formatPublisherWithName( name )
return tostring(mw.html.create('span')
:attr('itemprop', 'publisher')
:attr('itemscope', '')
:attr('itemtype', 'http://schema.org/Thing') --TODO: better types
:tag('span')
:attr('itemprop', 'name')
:wikitext(name)
:done()
)
end
function formatLink( page, label, schema_property )
local title = mw.title.new( toAbsoluteTitle( page ) )
if title == nil then
return tostring(mw.html.create('span')
:attr('itemprop', schema_property)
:attr('itemscope', '')
:attr('itemtype', 'http://schema.org/Thing') --TODO: better types
:wikitext('[[' .. page .. '|<span itemprop="name">' .. label .. '</span>]]')
)
end
if title.isRedirect then
title = title.redirectTarget
end
local tag = mw.html.create('span')
:attr('itemprop', schema_property)
:attr('itemscope', '')
:attr('itemtype', 'http://schema.org/Thing') --TODO: better types
:wikitext('[[' .. title.fullText .. '|<span itemprop="name">' .. label .. '</span>]]')
:tag('link')
:attr('itemprop', 'mainEntityOfPage')
:attr('href', title:fullUrl(nil, 'canonical'))
:done()
local itemId = mw.wikibase.getEntityIdForTitle(title.fullText)
if itemId ~= nil then
tag:attr('itemid', 'http://www.wikidata.org/entity/' .. itemId)
end
return tostring(tag)
end
function parseLinkWikitext( wikitext, schema_property )
wikitext = mw.ustring.gsub( wikitext, '%[%[([^|]*)|(.*)%]%]', function( page, link )
return formatLink( page, link, schema_property )
end )
wikitext = mw.ustring.gsub( wikitext, '%[%[([^|]*)%]%]', function( page )
return formatLink( page, mw.ustring.gsub( page, '%.*/', '') , schema_property )
end )
return wikitext
end
function formatTitleLink( page, label, schema_property )
local title = mw.title.new( toAbsoluteTitle( page ) )
if title == nil then
return '[[' .. page .. '|' .. label .. ']]'
end
if title.isRedirect then
title = title.redirectTarget
end
local tag = mw.html.create('span')
:attr('itemprop', schema_property)
:attr('itemscope', '')
:attr('itemtype', 'http://schema.org/CreativeWork') --TODO: find a more relenvant type
:wikitext('[[' .. title.fullText .. '|<span itemprop="name">' .. label .. '</span>]]')
:tag('link')
:attr('itemprop', 'mainEntityOfPage')
:attr('href', title:fullUrl(nil, 'canonical'))
:done()
local itemId = mw.wikibase.getEntityIdForTitle(title.fullText)
if itemId ~= nil then
tag:attr('itemid', 'http://www.wikidata.org/entity/' .. itemId)
end
return tostring(tag)
end
function parseTitleWikitext( wikitext, schema_property )
wikitext = mw.ustring.gsub( wikitext, '%[%[([^|]*)|(.*)%]%]', function( page, link )
return formatTitleLink( page, link, schema_property )
end )
wikitext = mw.ustring.gsub( wikitext, '%[%[([^|]*)%]%]', function( page )
return formatTitleLink( page, page, schema_property )
end )
return wikitext
end
function splitFileNameInFileAndPage(title)
local slashPosition = string.find(title.text, "/")
if slashPosition == nil then
return title.text,nil
else
return string.sub(title.text, 1, slashPosition - 1), string.sub(title.text, slashPosition + 1)
end
end
function headerTemplate( frame )
local parentFrame = frame:getParent()
local data = (require 'Module:Index_data').indexDataWithWikidata(parentFrame)
local args = data.args
local page = mw.title.getCurrentTitle()
local item = mw.wikibase.getEntity()
local headerType = args.value
if args.header_type then
headerType = args.header_type
end
headerType = mw.ustring.lower( headerType ) --Permet d'écrire le type en majuscule ou en minuscule
local estSommaire = (headerType == 'sommaire' or headerType == 'toc')
--Custom page numbers
local from = ''
if args.displayed_from then
from = args.displayed_from
elseif args.from then
from = args.from
end
local to = ''
if args.displayed_to then
to = args.displayed_to
elseif args.to then
to = args.to
end
local schema_type = 'http://schema.org/CreativeWork'
if args.type then
if args.type == 'book' then
if estSommaire then
schema_type = 'http://schema.org/Book'
else
schema_type = 'http://schema.org/Chapter'
end
elseif args.type == 'collection' then
if estSommaire then
schema_type = 'https://schema.org/Collection'
end
elseif args.type == 'journal' then
if estSommaire then
schema_type = 'https://schema.org/PublicationVolume'
else
schema_type = 'http://schema.org/Article'
end
elseif args.type == 'phdthesis' then
if estSommaire then
schema_type = 'http://schema.org/Thesis'
else
schema_type = 'http://schema.org/Chapter'
end
end
end
--Début du header
local html = mw.html.create()
-- Lien vers l'œuvre (si elle existe dans Wikidata avec un sitelink sur frwikisource)
if item and args.header_type ~= 'empty' then
local workStatements = item:getBestStatements('P629')
if workStatements[1] and workStatements[1].mainsnak.datatype == 'wikibase-item'
and workStatements[1].mainsnak.datavalue and workStatements[1].mainsnak.datavalue.value then
local workId = workStatements[1].mainsnak.datavalue.value.id
local workLink = mw.wikibase.getSitelink(workId)
local workLabel = mw.wikibase.label(workId) or workLink
if workLink ~= nil then
html:tag("p")
:node(nodeEditions(formatTitleLink(workLink, workLabel, 'exampleOfWork')))
:wikitext("[[Catégorie:Éditions liées à une œuvre par Header template]]")
end
end
end
-- Bloc-titre
local container = html:tag('div')
:attr('itemscope', '')
:attr('itemtype', schema_type)
if item ~= nil then
container:attr('itemid', 'http://www.wikidata.org/entity/' .. item.id)
end
classement( parentFrame, page, args )
if args.header_type == 'empty' then
if args.sommaire then
container:tag( 'div' )
:addClass('ws-summary')
:css('margin-top', '1em')
:newline()
:wikitext(args.sommaire)
end
return html
end
local headertemplate = container:tag('div')
:attr('id', 'headertemplate')
:addClass('ws-noexport')
:tag('div')
if args.type == 'journal' then
headertemplate:addClass('headertemplate-journal')
else
headertemplate:addClass('headertemplate')
end
--Auteur
if args.auteur then
headertemplate:tag('div')
:addClass('headertemplate-author')
:wikitext(parseLinkWikitext(args.auteur, 'author'))
end
--Titre
local titre = formatString( page.baseText, 'name' )
if args.type == 'collection' then
if args.recueil then
-- Commenté pour tester avec uniquement le nom du recueil, le titre lui est déjà
-- dans le navigateur et fréquemment en début de la page.
-- titre = titre .. ' — <i>' .. args.recueil .. '</i>'
titre = '<i>' .. parseTitleWikitext(args.recueil, 'isPartOf') .. '</i>'
elseif args.current then
titre = formatString( args.current, 'name' )
else
if estSommaire then
titre = formatString( titre, 'name' )
else
titre = parseTitleWikitext(titre, 'isPartOf')
end
end
if args.publication then
titre = titre .. ' <span style="font-size:90%;">(' .. args.publication .. ')</span>'
end
elseif args.type == 'journal' then
if estSommaire then
titre = formatString( args.titre, 'name' )
elseif args.current then
titre = formatString( args.current, 'name' )
else
titre = parseTitleWikitext(titre, 'isPartOf')
end
else
if args.titre then
titre = args.titre
end
if estSommaire then
titre = formatString( titre, 'name' )
else
titre = parseTitleWikitext(titre, 'isPartOf')
end
if args.publication then
titre = titre .. ' <span style="font-size:90%;">(' .. args.publication .. ')</span>'
end
end
if estSommaire and args.sous_titre then
titre = titre .. ' <br/><small>' .. args['sous_titre'] .. '</small>'
end
headertemplate:tag('div')
:addClass('headertemplate-title')
:wikitext(titre)
--References
local references = headertemplate:tag('div')
:addClass('headertemplate-reference')
if args.traducteur then
references:wikitext('Traduction par ' .. parseLinkWikitext(args.traducteur, 'translator') .. '.')
:tag('br')
end
if estSommaire and args.illustrateur then
references:wikitext('Illustrations par ' .. parseLinkWikitext(args.illustrateur, 'illustrator') .. '.')
:tag('br')
end
if estSommaire and args.volume then
references:wikitext( formatString( args.volume, 'volumeNumber' ) )
:tag('br')
end
local infos = {} --Liste des données à afficher séparés par une virgule
if args.type == 'collection' then
if args.titre then
table.insert( infos, '<i>' .. parseTitleWikitext(args.titre, 'isPartOf') .. '</i>' )
end
if args.editeur_scientifique then
table.insert( infos, 'Texte établi par ' .. parseLinkWikitext( args.editeur_scientifique, 'editor' ) )
end
if args.editeur then
table.insert( infos, formatPublisherWithName( args.editeur ) )
end
if args.annee then
table.insert( infos, formatYear( args.annee, 'datePublished' ) )
end
if not estSommaire then
if args.volume then
table.insert( infos, formatString( args.volume, 'volumeNumber' ) )
end
end
elseif args.type == 'journal' then
if not estSommaire then
table.insert( infos, '<i>' .. parseTitleWikitext( args.titre, 'isPartOf' ) .. '</i>' )
if args.volume then
table.insert( infos, formatString( args.volume, 'volumeNumber' ) )
end
end
if args.annee then
table.insert( infos, formatYear( args.annee, 'datePublished' ) )
end
else
if args.editeur_scientifique then
table.insert( infos, 'Texte établi par ' .. parseLinkWikitext( args.editeur_scientifique, 'editor' ) )
end
if args.editeur then
table.insert( infos, formatPublisherWithName( args.editeur ) )
end
if args.annee then
table.insert( infos, formatYear( args.annee, 'datePublished' ) )
end
end
local line = ''
if infos ~= {} then
line = table.concat( infos, ', ' )
end
--Parenthèse
if not estSommaire and from ~= '' then
local temp = ''
if args.volume and args.type ~= 'collection' and args.type ~= 'journal' then
temp = formatString( args.volume, 'volumeNumber' ) .. ', '
end
if from ~= to or from ~= '-' then
temp = temp .. pagination( from, to )
end
if temp ~= '' then
line = line .. ' (' .. temp .. ')'
end
end
if line ~= '' then
references:wikitext(line .. '.')
end
local subheader = container:tag('div')
:attr('id', 'subheader')
:addClass('ws-noexport')
:css('margin-bottom', '1.5em')
if estSommaire then
local texteEntier = mw.title.new( page.prefixedText .. '/Texte entier' )
if texteEntier and texteEntier.exists then
subheader:tag('div')
:css('text-align', 'center')
:wikitext('[[' .. texteEntier.fullText .. '|Texte sur une seule page]]')
end
end
if (not estSommaire or (args.header_type and args.header_type =='toc')) and (args.prev or args.next) then
local maxwidth = 50
if args.type ~= 'collection' and args.current then
maxwidth = 33
end
local footer = subheader:tag('div')
:addClass('footertemplate')
:addClass('ws-noexport')
local nav = footer:tag('div')
:css('width', '100%')
:css('padding-left', '0px')
:css('padding-right', '0px')
:css('background-color', 'transparent')
if args.prev then
nav:tag('div')
:css('text-align', 'left')
:css('float', 'left')
:css('max-width', maxwidth .. '%')
:tag('span')
:attr('id', 'headerprevious')
:tag('span')
:css('color', '#808080')
:wikitext('◄ ')
:done()
:wikitext(parseLinkWikitext(args.prev, 'previousItem'))
end
if args.next then
nav:tag('div')
:css('text-align', 'right')
:css('float', 'right')
:css('max-width', maxwidth .. '%')
:tag('span')
:attr('id', 'headernext')
:wikitext(parseLinkWikitext(args.next, 'nextItem'))
:tag('span')
:css('color', '#808080')
:wikitext(' ►')
end
if args.type ~= 'collection' and args.current then
nav:tag('div')
:attr('itemprop', 'name')
:css('text-align', 'center')
:css('margin-left', '25%')
:css('margin-right', '25%')
:wikitext(args.current)
end
footer:tag('div')
:css('clear', 'both')
end
-- Catégories
if estSommaire and (not item or not item['claims'] or not item['claims']['P629']) then
container:wikitext('[[Catégorie:Éditions sans œuvre liée]]')
end
-- Inclusion de l'épigraphe et du sommaire
if headerType == 'toc' then
if args.epigraphe then
container:wikitext(args.epigraphe)
:newline()
end
container:tag('div')
:addClass('ws-summary')
:css('margin-top', '1em')
:wikitext(args.sommaire)
elseif headerType == 'sommaire' then
html:wikitext('<div id="ws-summary">') --Bad hack, outputs unbalanced HTML
end
--Métadonnées schema.org supplémentaires
container:tag('link')
:attr('itemprop', 'mainEntityOfPage')
:attr('href', page:fullUrl(nil, 'canonical'))
container:tag('meta')
:attr('itemprop', 'inLanguage')
:attr('content', 'fr') --TODO: que faire pour l'ancien français...
if args.lieu then
container:tag('meta')
:attr('itemprop', 'http://purl.org/library/placeOfPublication')
:attr('content', args.lieu) --TODO: is it the best property URI and the best value format?
end
if args.index then
local indexFile = mw.title.makeTitle('File', args.index)
if indexFile ~= nil and indexFile.file.exists then
container:tag('span')
:attr('itemprop', 'associatedMedia')
:attr('itemscope', '')
:attr('itemtype', 'http://schema.org/MediaObject')
:tag('link')
:attr('itemprop', 'mainEntityOfPage')
:attr('href', indexFile:fullUrl(nil, 'canonical'))
:done()
:tag('meta')
:attr('itemprop', 'width')
:attr('content', indexFile.file.width)
:done()
:tag('meta')
:attr('itemprop', 'height')
:attr('content', indexFile.file.height)
:done()
:tag('meta')
:attr('itemprop', 'fileFormat')
:attr('content', indexFile.file.mimeType)
:done()
end
end
-- Métadonnées, see http://ocoins.info/ for coins.
local coins = {}
local uriCoins = 'ctx_ver=Z39.88-2004&rft_val_fmt=info%3Aofi%2Ffmt%3Akev%3Amtx%3A'
coins['rft.genre'] = 'unknown'
coins['rfr_id'] = tostring( page:fullUrl( nil, "canonical" ) )
local datahtml = container:tag('div')
:attr('id', 'ws-data')
:addClass('ws-noexport')
:css('display', 'none')
:css('speak', 'none')
if args.type then
datahtml:node( outputMicroformatRow( 'type', args.type ) )
end
if args.type and args.type == 'journal' then
uriCoins = uriCoins .. 'journal'
if estSommaire then
coins['rft.genre'] = 'publication'
coins['rft.jtitle'] = cleanCoinsParameter( titre )
else
coins['rft.genre'] = 'article'
coins['rft.atitle'] = cleanCoinsParameter( titre )
if args.titre then
coins['rft.jtitle'] = cleanCoinsParameter( args.titre )
datahtml:node( outputMicroformatRow( 'periodical', cleanCoinsParameter( args.titre ) ) )
end
end
else
uriCoins = uriCoins .. 'book'
if estSommaire then
coins['rft.btitle'] = cleanCoinsParameter( titre )
else
coins['rft.atitle'] = cleanCoinsParameter( titre )
end
if args.type and args.type == 'book' then
if estSommaire then
coins['rft.genre'] = 'book'
else
coins['rft.genre'] = 'bookitem'
end
end
end
datahtml:node( outputMicroformatRow( 'title', titre ) )
if args.auteur then
datahtml:node( outputMicroformatRow( 'author', args.auteur ) )
coins['rft.au'] = cleanCoinsParameter( args.auteur )
end
if args.traducteur then
datahtml:node( outputMicroformatRow( 'translator', args.traducteur ) )
end
if args.illustrateur then
datahtml:node( outputMicroformatRow( 'illustrator', args.illustrateur ) )
end
if args.school then
datahtml:node( outputMicroformatRow( 'school', args.school ) )
end
if args.editeur then
datahtml:node( outputMicroformatRow( 'publisher', args.editeur ) )
coins['rft.pub'] = cleanCoinsParameter( args.editeur )
end
if args.annee then
datahtml:node( outputMicroformatRow( 'year', args.annee ) )
coins['rft.date'] = args.annee
end
if args.lieu then
datahtml:node( outputMicroformatRow( 'place', args.lieu ) )
coins['rft.place'] = args.lieu
end
if args.avancement then
datahtml:node( outputMicroformatRow( 'progress', args.avancement ) )
end
if args.volume then
datahtml:node( outputMicroformatRow( 'volume', args.volume ) )
end
if args.current then
datahtml:node( outputMicroformatRow( 'chapter', args.current ) )
end
if args.index then
datahtml:node( outputMicroformatRow( 'scan', args.index ) )
local imageTitle = nil
if tonumber(args.image) ~= nil then
imageTitle = mw.title.new(args.index, "Media"):subPageTitle(args.image)
elseif args.image ~= nil then
imageTitle = mw.title.new(args.image, "Media")
end
if imageTitle ~= nil then
datahtml:node( outputMicroformatRow( 'cover', imageTitle.text ) )
end
end
if from ~= '' and to ~= '' then
if from == to then
datahtml:node( outputMicroformatRow( 'pages', from ) )
else
datahtml:node( outputMicroformatRow( 'pages', from .. '-' .. to ) )
end
coins['rft.spage'] = from
coins['rft.epage'] = to
end
datahtml:tag('span')
:addClass('Z3988')
:attr('title', uriCoins .. '&' .. mw.uri.buildQueryString( coins ))
:wikitext(' ')
return html
end
function classement( frame, page, args )
local classement = require 'Module:Classement'
local key = ''
if args.type and args.type == 'journal' then
key = classement.getSortKey( {args= {page.text}} )
elseif args.type and (args.type == 'dictionary' or args.type == 'collection') then
key = classement.getSortKey( {args= {page.subpageText}} )
elseif not page.isSubpage then
key = classement.getSortKey( {args= {page.text}} )
end
if key ~= '' then
--Evite le parse des paramètres passés à la page.
local child = frame:newChild{ title = page.text, args = {} }
child:preprocess( '{{DEFAULTSORT:' .. key .. '}}\n' )
end
end
function pagination( from, to )
if from ~= '' and to ~= '' then
if from == to then
return '<abbr title="page">p.</abbr> ' .. formatString( from, 'pagination' )
else
return '<abbr title="pages">p.</abbr> ' .. formatString( from, 'pageStart' ) .. '-' .. formatString( to, 'pageEnd' )
end
end
end
function outputMicroformatRow( name, value )
return mw.html.create('span')
:addClass('ws-' .. name)
:wikitext(value)
end
local p = {
['headerTemplate'] = headerTemplate
}
function nodeEditions( wikilinktext )
local node = mw.html.create("small")
:addClass('ws-noexport')
:css({
['text-align'] = 'center',
['font-style'] = 'italic'
})
:attr('itemscope', '')
:attr('itemtype', 'http://schema.org/CreativeWork')
local itemId = mw.wikibase.getEntityIdForCurrentPage()
if itemId ~= nil then
node:attr('itemid', 'http://www.wikidata.org/entity/' .. itemId)
end
node:wikitext('[[Image:List2.svg|25px|lien=]] Pour les autres éditions de ce texte, voir ')
:wikitext(wikilinktext)
:wikitext('.')
return node
end
function p.voirEditions( frame )
local args = frame:getParent().args
if not args[1] or args[1] == '' then
return tostring(errorMessageNode("Le [[modèle:Voir éditions]] prend en paramètre un lien vers la liste des éditions."))
end
local node = nodeEditions(parseTitleWikitext(args[1], 'exampleOfWork'))
return tostring(node)
end
return p