« Module:Roadmap » : différence entre les versions
De Nefald
Autres actions
Annulation des modifications 5246 de Hiob (discussion) Balises : Annulation Révoqué |
Aucun résumé des modifications |
||
| (3 versions intermédiaires par le même utilisateur non affichées) | |||
| Ligne 68 : | Ligne 68 : | ||
end | end | ||
return nil | return nil | ||
end | |||
local function sanitizeClass(s) | |||
if not s then return "" end | |||
s = s:lower() | |||
s = s:gsub("[^%w%-]", "") | |||
return s | |||
end | end | ||
-- ------------------------------------------------------------ | -- ------------------------------------------------------------ | ||
-- PARSEUR | -- PARSEUR (séparateur ;; au lieu de |) | ||
-- ------------------------------------------------------------ | -- ------------------------------------------------------------ | ||
| Ligne 79 : | Ligne 86 : | ||
line = trim(line) | line = trim(line) | ||
if line == "" or line:match("^%-%-") then | if line == "" or line:match("^%-%-") then | ||
-- skip | -- skip | ||
elseif line:match("^@section%s+") then | elseif line:match("^@section%s+") then | ||
local titre = line:match("^@section%s+(.+)$") | local titre = line:match("^@section%s+(.+)$") | ||
| Ligne 86 : | Ligne 93 : | ||
titre = trim(titre or "Section"), | titre = trim(titre or "Section"), | ||
}) | }) | ||
elseif line:match("^item%s* | elseif line:match("^item%s*;;") then | ||
local parts = {} | local parts = {} | ||
for part in line:gmatch("( | for part in (line .. ";;"):gmatch("(.-);;") do | ||
table.insert(parts, trim(part)) | table.insert(parts, trim(part)) | ||
end | end | ||
-- parts[1] = "item", parts[2] = statut, parts[3] = titre, etc. | |||
local statut = trim(parts[2] or "planned"):lower() | local statut = trim(parts[2] or "planned"):lower() | ||
local titre = trim(parts[3] or "") | local titre = trim(parts[3] or "") | ||
| Ligne 153 : | Ligne 161 : | ||
local s = CONFIG.statuts[statut] or CONFIG.statuts.planned | local s = CONFIG.statuts[statut] or CONFIG.statuts.planned | ||
return string.format( | return string.format( | ||
'<span class="roadmap-badge" title="%s">%s</span>', | '<span class="roadmap-badge roadmap-badge-%s" title="%s">%s</span>', | ||
escapeHtml(s.label), s.icon | statut, escapeHtml(s.label), s.icon | ||
) | ) | ||
end | end | ||
| Ligne 163 : | Ligne 171 : | ||
for _, tag in ipairs(tags) do | for _, tag in ipairs(tags) do | ||
table.insert(parts, string.format( | table.insert(parts, string.format( | ||
'<span class="roadmap-tag | '<span class="roadmap-tag roadmap-tag-%s">%s</span>', | ||
sanitizeClass(tag), escapeHtml(tag) | |||
)) | )) | ||
end | end | ||
| Ligne 217 : | Ligne 225 : | ||
'<div class="roadmap-progress-wrap">' | '<div class="roadmap-progress-wrap">' | ||
.. '<div class="roadmap-progress-label">' | .. '<div class="roadmap-progress-label">' | ||
.. 'Progression : <strong>%d%%</strong> — %d / %d fonctionnalités' | .. 'Progression\194\160: <strong>%d%%</strong> — %d / %d fonctionnalités' | ||
.. '</div>' | .. '</div>' | ||
.. '<div class="roadmap-progress-bar">' | .. '<div class="roadmap-progress-bar">' | ||
| Ligne 234 : | Ligne 242 : | ||
if s then | if s then | ||
table.insert(parts, string.format( | table.insert(parts, string.format( | ||
'<span class="roadmap-legend-item | '<span class="roadmap-legend-item roadmap-%s">' | ||
.. '%s %s</span>', | |||
key, htmlBadge(key), escapeHtml(s.label) | |||
.. '%s | |||
)) | )) | ||
end | end | ||
| Ligne 246 : | Ligne 252 : | ||
local function htmlStats(elements) | local function htmlStats(elements) | ||
local counts = { | local counts = { done = 0, inprogress = 0, planned = 0, idea = 0, cancelled = 0 } | ||
for _, el in ipairs(elements) do | for _, el in ipairs(elements) do | ||
if el.type == "item" and counts[el.statut] then | if el.type == "item" and counts[el.statut] then | ||
| Ligne 253 : | Ligne 258 : | ||
end | end | ||
end | end | ||
local | local order = { | ||
{ key = "done", label = "Terminé" }, | |||
for _, | { key = "inprogress", label = "En cours" }, | ||
if counts[ | { key = "planned", label = "Planifié" }, | ||
{ key = "idea", label = "Idée" }, | |||
{ key = "cancelled", label = "Annulé" }, | |||
} | |||
local parts = { '<div class="roadmap-stats">' } | |||
for _, s in ipairs(order) do | |||
if counts[s.key] > 0 then | |||
table.insert(parts, string.format( | table.insert(parts, string.format( | ||
'< | '<div class="roadmap-stat roadmap-stat-%s">' | ||
.. '<span class="roadmap-stat-count">%d</span>' | .. '<span class="roadmap-stat-count">%d</span>' | ||
.. '<span class="roadmap-stat-label">%s</span>' | .. '<span class="roadmap-stat-label">%s</span>' | ||
.. '</ | .. '</div>', | ||
counts[key], | s.key, counts[s.key], s.label | ||
)) | )) | ||
end | end | ||
end | end | ||
table.insert(parts, '</div>') | |||
return table.concat(parts, "\n") | |||
end | end | ||
| Ligne 276 : | Ligne 287 : | ||
function p.render(frame) | function p.render(frame) | ||
local args = frame:getParent().args | local args = frame:getParent().args | ||
local titre = getParam(args, "titre") or "Roadmap" | local rawContenu = trim(args["contenu"] or args[1] or "") | ||
-- | |||
local titre = getParam(args, "titre", "title") or "Roadmap" | |||
local subtitle = getParam(args, "subtitle") | local subtitle = getParam(args, "subtitle") | ||
-- | |||
local elements = parseContenu(rawContenu) | local elements = parseContenu(rawContenu) | ||
local pct, done, total = calcProgression(elements) | local pct, done, total = calcProgression(elements) | ||
local | -- | ||
table.insert( | local out = {} | ||
-- | table.insert(out, '<div class="roadmap-container">') | ||
table.insert( | -- En-tête | ||
table.insert( | table.insert(out, '<div class="roadmap-header">') | ||
' | table.insert(out, string.format('<div class="roadmap-title">%s</div>', escapeHtml(titre))) | ||
escapeHtml(titre) | |||
)) | |||
if subtitle then | if subtitle then | ||
table.insert( | table.insert(out, string.format('<div class="roadmap-subtitle">%s</div>', escapeHtml(subtitle))) | ||
'<div class="roadmap-subtitle">%s</div>', | |||
escapeHtml(subtitle) | |||
)) | |||
end | end | ||
table.insert( | table.insert(out, htmlProgressBar(pct, done, total)) | ||
table.insert(out, htmlStats(elements)) | |||
table.insert(out, htmlLegende()) | |||
table.insert( | table.insert(out, '</div>') | ||
-- Corps | |||
local sectionOpen = false | |||
table.insert( | |||
-- | |||
local | |||
for _, el in ipairs(elements) do | for _, el in ipairs(elements) do | ||
if el.type == "section" then | if el.type == "section" then | ||
if | if sectionOpen then | ||
table.insert( | table.insert(out, '</div>') | ||
end | end | ||
table.insert( | table.insert(out, htmlSection(el)) | ||
sectionOpen = true | |||
elseif el.type == "item" then | elseif el.type == "item" then | ||
table.insert( | table.insert(out, htmlItem(el)) | ||
end | end | ||
end | end | ||
if sectionOpen then | |||
if | table.insert(out, '</div>') | ||
table.insert( | |||
end | end | ||
table.insert( | table.insert(out, '</div>') | ||
return table.concat( | return table.concat(out, "\n") | ||
end | end | ||
-- ------------------------------------------------------------ | -- ------------------------------------------------------------ | ||
-- ITEM INLINE | -- ITEM INLINE | ||
-- ------------------------------------------------------------ | -- ------------------------------------------------------------ | ||