Modulenn:Header template

Documentation for this module may be created at Modulenn:Header template/doc

function errorMessage(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 modèle Auteur]]')
	return tostring(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 headerTemplate( frame )
    local parentFrame = frame:getParent()
    local args = parentFrame.args
    local page = mw.title.getCurrentTitle()
    local item = mw.wikibase.getEntity()
    local headerType = args.value
    if args.header_type and 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 == 'taolenn' or headerType == 'toc')

    --Custom page numbers
    local from = ''
    if args.displayed_from and args.displayed_from ~= '' then
        from = args.displayed_from
    elseif args.from then
        from = args.from
    end

    local to = ''
    if args.displayed_to and 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()
    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 and 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 and 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 .. '&#32;— <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 and 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 and args.publication ~= '' then
            titre = titre .. ' <span style="font-size:90%;">(' .. args.publication .. ')</span>'
        end
    end
    if estSommaire and args['sous_titre'] 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 and args.traducteur ~= '' then
        references:wikitext('Troet gant ' .. parseLinkWikitext(args.traducteur, 'translator') .. '.')
            :tag('br')
    end
    if estSommaire and args.illustrateur and args.illustrateur ~= '' then
        references:wikitext('Treset gant ' .. parseLinkWikitext(args.illustrateur, 'illustrator') .. '.')
            :tag('br')
    end

    if estSommaire and args.volume 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 and args.titre ~= '' then
            table.insert( infos, '<i>' .. parseTitleWikitext(args.titre, 'isPartOf') .. '</i>' )
        end
        if args.editeur_scientifique and args.editeur_scientifique ~= '' then
            table.insert( infos, 'Testenn graet gant ' .. parseLinkWikitext( args.editeur_scientifique, 'editor' ) )
        end
        if args.editeur and args.editeur ~= '' then
            table.insert( infos, formatPublisherWithName( args.editeur ) )
        end
        if args.annee and args.annee ~= '' then
            table.insert( infos, formatYear( args.annee, 'datePublished' ) )
        end
        if not estSommaire then
            if args.volume and 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 and args.volume ~= '' then
                table.insert( infos, formatString( args.volume, 'volumeNumber' ) )
            end
        end
        if args.annee and args.annee ~= '' then
            table.insert( infos, formatYear( args.annee, 'datePublished' ) )
        end
    else
        if args.editeur_scientifique and args.editeur_scientifique ~= '' then
            table.insert( infos, 'Texte établi par ' .. parseLinkWikitext( args.editeur_scientifique, 'editor' ) )
        end
        if args.editeur and args.editeur ~= '' then
            table.insert( infos, formatPublisherWithName( args.editeur ) )
        end
        if args.annee and args.annee ~= '' then
            table.insert( infos, formatYear( args.annee, 'datePublished' ) )
        end
    end
    local line = ''
    if infos ~= {} then
        line = table.concat( infos, ',&nbsp;' )
    end

    --Parenthèse
    if not estSommaire and from ~= '' then
        local temp = ''
        if args.volume and args.volume ~= '' and args.type ~= 'collection' and args.type ~= 'journal' then
            temp = formatString( args.volume, 'volumeNumber' ) .. ',&nbsp;'
        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 .. '/a-bezh' )
        if texteEntier and texteEntier.exists then
            subheader:tag('div')
                :css('text-align', 'center')
                :wikitext('[[' .. texteEntier.fullText .. '|Testenn a-bezh]]')
        end
    end

    if (not estSommaire or (args.header_type and args.header_type =='toc')) and ((args.prev and args.prev ~= '') or (args.next and args.next ~= '')) then
        local maxwidth = 50
        if args.type ~= 'collection' and args.current 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 and 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('&#x25C4;&nbsp;&nbsp;')
                        :done()
                    :wikitext(parseLinkWikitext(args.prev, 'previousItem'))
        end
        if args.next and 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('&nbsp;&nbsp;&#x25BA;')
        end
        if args.type ~= 'collection' and args.current 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 and args.epigraphe ~= '' then
            container:wikitext(args.epigraphe)
                :newline()
        end
        container:tag('div')
            :addClass('ws-summary')
            :css('margin-top', '1em')
            :wikitext(args.sommaire)
    elseif headerType == 'taolenn' 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 and 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 and 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 and args.auteur ~= '' then
        datahtml:node( outputMicroformatRow( 'author', args.auteur ) )
        coins['rft.au'] = cleanCoinsParameter( args.auteur )
    end
    if args.traducteur and args.traducteur ~= '' then
        datahtml:node( outputMicroformatRow( 'translator', args.traducteur ) )
    end
    if args.illustrateur and args.illustrateur ~= '' then
        datahtml:node( outputMicroformatRow( 'illustrator', args.illustrateur ) )
    end
    if args.school and args.school ~= '' then
        datahtml:node( outputMicroformatRow( 'school', args.school ) )
    end
    if args.editeur and args.editeur ~= '' then
        datahtml:node( outputMicroformatRow( 'publisher', args.editeur ) )
        coins['rft.pub'] = cleanCoinsParameter( args.editeur )
    end
    if args.annee and args.annee ~= '' then
        datahtml:node( outputMicroformatRow( 'year', args.annee ) )
        coins['rft.date'] = args.annee
    end
    if args.lieu and args.lieu ~= '' then
        datahtml:node( outputMicroformatRow( 'place', args.lieu ) )
        coins['rft.place'] = args.lieu
    end
    if args.avancement and args.avancement ~= '' then
        datahtml:node( outputMicroformatRow( 'progress', args.avancement ) )
    end
    if args.volume and args.volume ~= '' then
        datahtml:node( outputMicroformatRow( 'volume', args.volume ) )
    end
    if args.current and args.current ~= '' then
        datahtml:node( outputMicroformatRow( 'chapter', args.current ) )
    end
    if args.index then
        datahtml:node( outputMicroformatRow( 'scan', args.index ) )
        if args.image and mw.ustring.match(args.image, '^%d+$') ~= nil then
            datahtml:node( outputMicroformatRow( 'cover', args.index .. '/' .. args.image ) )
        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('&nbsp;')
    
    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>&nbsp;' .. formatString( from, 'pagination' )
        else
            return '<abbr title="pages">p.</abbr>&nbsp;' .. 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 = {}
 
function p.headerTemplate( frame )
    return headerTemplate( frame )
end

function p.voirEditions( frame )
	local args = frame:getParent().args
	if not args[1] or args[1] == '' then
		return errorMessage("Le modèle VoirEdition prend en paramètre un lien vers la liste des éditions")
	end

	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(parseTitleWikitext(args[1], 'exampleOfWork'))
		:wikitext('.')

	return tostring(node)
end
 
return p