Module:NavLivreSommaire
Apparence
La documentation pour ce module peut être créée à Module:NavLivreSommaire/Documentation
-- Module:NavLivreSommaire
local p = {}
local function trim(s)
return mw.text.trim(s or '')
end
local function normalizeTitle(s)
s = trim(s)
if s == '' then return nil end
local t = mw.title.new(s)
if not t then return nil end
return t.prefixedText
end
local function extractBetweenMarkers(wikitext, startMarker, endMarker)
startMarker = startMarker and startMarker ~= '' and startMarker or '<!--NAV-START-->'
endMarker = endMarker and endMarker ~= '' and endMarker or '<!--NAV-END-->'
local a = wikitext:find(startMarker, 1, true)
local b = wikitext:find(endMarker, 1, true)
if a and b and b > a then
return wikitext:sub(a + #startMarker, b - 1)
end
return wikitext
end
local function parseLinks(wikitext, baseForRelative)
local items = {}
local seen = {}
-- Capture le contenu de [[...]] sans gérer tous les cas exotiques.
-- Suffisant si le sommaire contient des liens "simples" vers les chapitres.
for inner in mw.ustring.gmatch(wikitext, '%[%[([^%[%]]-)%]%]') do
local target, label = inner:match('^([^|]+)|(.+)$')
target = trim(target or inner)
-- Ignore les ancres seules
if target ~= '' and target:sub(1,1) ~= '#' then
-- Supprime une éventuelle ancre de section
target = target:gsub('#.*$', '')
if baseForRelative and target:sub(1,1) == '/' then
target = baseForRelative .. target
end
local norm = normalizeTitle(target)
if norm and not seen[norm] then
seen[norm] = true
items[#items + 1] = {
target = norm,
label = trim(label) ~= '' and trim(label) or nil
}
end
end
end
return items
end
local function defaultLabelFromTarget(prefixedText)
-- Affiche seulement la dernière portion après "/"
local t = prefixedText:gsub('^.+:', '') -- enlève le namespace si présent
local last = t:match('([^/]+)$') or t
return last
end
local function makeLink(target, label)
return string.format('[[%s|%s]]', target, label)
end
local function renderBanner(position, prevItem, tocTarget, tocLabel, nextItem)
local html = mw.html.create('div')
html:addClass('nav-livre')
html:addClass(position == 'bas' and 'nav-livre--bas' or 'nav-livre--haut')
local left = mw.html.create('span'):addClass('nav-livre__prev')
local center = mw.html.create('span'):addClass('nav-livre__toc')
local right = mw.html.create('span'):addClass('nav-livre__next')
if prevItem then
local lbl = prevItem.label or defaultLabelFromTarget(prevItem.target)
left:wikitext(makeLink(prevItem.target, '← ' .. lbl))
end
center:wikitext(makeLink(tocTarget, tocLabel))
if nextItem then
local lbl = nextItem.label or defaultLabelFromTarget(nextItem.target)
right:wikitext(makeLink(nextItem.target, lbl .. ' →'))
end
html:node(left)
html:node(center)
html:node(right)
return tostring(html)
end
function p.main(frame)
local args = frame.args
local position = trim(args.position or args.pos or 'haut'):lower()
if position ~= 'haut' and position ~= 'bas' then position = 'haut' end
local sommaire = trim(args.sommaire or args.toc or '')
if sommaire == '' then
return ''
end
local tocTitle = mw.title.new(sommaire)
if not tocTitle then
return ''
end
local tocLabel = trim(args.sommaire_label or args.toc_label or 'Sommaire')
local startMarker = args.debut or args.start
local endMarker = args.fin or args["end"]
local content = tocTitle:getContent()
if not content or content == '' then
-- Si le sommaire n’existe pas ou n’est pas lisible, on affiche au moins un lien central
return renderBanner(position, nil, tocTitle.prefixedText, tocLabel, nil)
end
local slice = extractBetweenMarkers(content, startMarker, endMarker)
local baseForRelative = tocTitle.text
local items = parseLinks(slice, baseForRelative)
if #items == 0 then
return renderBanner(position, nil, tocTitle.prefixedText, tocLabel, nil)
end
local current = mw.title.getCurrentTitle().prefixedText
local idx
for i, it in ipairs(items) do
if it.target == current then
idx = i
break
end
end
if not idx then
-- Page non listée dans le sommaire : on affiche seulement le lien vers le sommaire.
return renderBanner(position, nil, tocTitle.prefixedText, tocLabel, nil)
end
local prevItem = idx > 1 and items[idx - 1] or nil
local nextItem = idx < #items and items[idx + 1] or nil
return renderBanner(position, prevItem, tocTitle.prefixedText, tocLabel, nextItem)
end
return p