Modul:Gegner Ehemalige Spieler
Die Dokumentation für dieses Modul kann unter Modul:Gegner Ehemalige Spieler/Doku erstellt werden
local p = {}
local DEFAULT_KASSEL_PLAYER_CATEGORIES = {
"Spieler",
}
local function trim(s)
return mw.text.trim(s or "")
end
local function getArg(frame, name)
local value = trim(frame.args[name])
if value ~= "" then
return value
end
local parent = frame:getParent()
if parent then
return trim(parent.args[name])
end
return ""
end
local function surnameSortKey(name)
local clean = trim(name)
if clean == "" then
return ""
end
if clean:find(",", 1, true) then
local last, first = clean:match("^([^,]+),%s*(.*)$")
return mw.ustring.lower(trim((last or "") .. " " .. (first or "")))
end
local parts = {}
for part in clean:gmatch("%S+") do
table.insert(parts, part)
end
if #parts <= 1 then
return mw.ustring.lower(clean)
end
local particles = {
["de"] = true,
["del"] = true,
["der"] = true,
["den"] = true,
["di"] = true,
["la"] = true,
["le"] = true,
["st."] = true,
["st"] = true,
["van"] = true,
["von"] = true,
}
local last = table.remove(parts)
local previous = parts[#parts]
if previous and particles[mw.ustring.lower(previous)] then
last = previous .. " " .. last
table.remove(parts)
end
return mw.ustring.lower(last .. " " .. table.concat(parts, " "))
end
local function getCategoryMembers(category)
if not (mw.ext and mw.ext.dpl and type(mw.ext.dpl.getPagenames) == "function") then
mw.addWarning("DynamicPageListEngine/Lua ist nicht verfügbar.")
return {}
end
category = trim(category):gsub("^Kategorie:%s*", "")
if category == "" then
return {}
end
local ok, pages = pcall(mw.ext.dpl.getPagenames, {
category = category,
namespace = "main",
redirects = "exclude",
ordermethod = "sortkey",
order = "ascending",
count = 5000,
})
if not ok then
mw.addWarning("DynamicPageListEngine-Fehler: " .. tostring(pages))
return {}
end
return pages or {}
end
local function parseCategoryList(raw)
local categories = {}
local seen = {}
for part in (raw or ""):gmatch("[^|]+") do
local category = trim(part)
if category ~= "" and not seen[category] then
seen[category] = true
table.insert(categories, category)
end
end
return categories
end
local function buildIntersection(opponentCategory, kasselCategories)
local kasselSet = {}
for _, category in ipairs(kasselCategories) do
for _, title in ipairs(getCategoryMembers(category)) do
kasselSet[title] = true
end
end
local entries = {}
local seen = {}
for _, title in ipairs(getCategoryMembers(opponentCategory)) do
if kasselSet[title] and not seen[title] then
seen[title] = true
table.insert(entries, {
title = title,
label = title,
sort = surnameSortKey(title),
})
end
end
table.sort(entries, function(a, b)
return a.sort < b.sort
end)
return entries
end
local function renderLink(entry)
return string.format("* [[%s|%s]]", entry.title, entry.label)
end
local function splitIntoColumns(entries, count)
local columns = {}
for i = 1, count do
columns[i] = {}
end
if #entries == 0 then
return columns
end
local perColumn = math.ceil(#entries / count)
for index, entry in ipairs(entries) do
local target = math.floor((index - 1) / perColumn) + 1
if target > count then
target = count
end
table.insert(columns[target], renderLink(entry))
end
return columns
end
local function renderColumn(lines)
if #lines == 0 then
return " "
end
return table.concat(lines, "<br>")
end
local function getStyleConfig(style)
local normalized = mw.ustring.lower(trim(style))
if normalized ~= "spielerstatistik" and normalized ~= "spielerstatistik2526" then
return {
tableClass = "wikitable",
tableStyle = "font-size:95%; width:100%; table-layout:fixed;",
headerStyle = "background:#00205B; color:#FFFFFF; text-align:center;",
cellStyles = {
"width:25%; background:#eeeeee; vertical-align:top;",
"width:25%; background:#f7f7f7; vertical-align:top;",
"width:25%; background:#eeeeee; vertical-align:top;",
"width:25%; background:#f7f7f7; vertical-align:top;",
},
}
end
return {
tableClass = "wikitable plainrowheaders",
tableStyle = "font-size:95%; width:100%; table-layout:fixed;",
headerStyle = "background-color:#eef3f8; text-align:center;",
cellStyles = {
"width:25%; background-color:#f8fafc; vertical-align:top;",
"width:25%; background-color:#eef3f8; vertical-align:top;",
"width:25%; background-color:#f8fafc; vertical-align:top;",
"width:25%; background-color:#eef3f8; vertical-align:top;",
},
}
end
function p.render(frame)
local opponentCategory = getArg(frame, "opponentPlayerCategory")
if opponentCategory == "" then
return "<strong>Fehler:</strong> Parameter <code>opponentPlayerCategory</code> fehlt."
end
local kasselRaw = getArg(frame, "kasselPlayerCategories")
local kasselCategories = {}
if kasselRaw == "" then
for _, category in ipairs(DEFAULT_KASSEL_PLAYER_CATEGORIES) do
table.insert(kasselCategories, category)
end
else
kasselCategories = parseCategoryList(kasselRaw)
end
local entries = buildIntersection(opponentCategory, kasselCategories)
local columns = splitIntoColumns(entries, 4)
local title = getArg(frame, "title")
if title == "" then
title = string.format("Ehemalige Spieler beider Teams <small>(%d)</small>", #entries)
end
local emptyText = getArg(frame, "emptyText")
if emptyText == "" then
emptyText = "Keine gemeinsamen ehemaligen Spieler erfasst."
end
local styleConfig = getStyleConfig(getArg(frame, "style"))
if #entries == 0 then
return table.concat({
string.format('{| class="%s" style="%s"', styleConfig.tableClass, styleConfig.tableStyle),
string.format('! colspan=4 style="%s"|%s', styleConfig.headerStyle, title),
"|-",
string.format('| colspan=4 style="%s"|%s', styleConfig.cellStyles[1], emptyText),
"|}",
}, "\n")
end
return table.concat({
string.format('{| class="%s" style="%s"', styleConfig.tableClass, styleConfig.tableStyle),
string.format('! colspan=4 style="%s"|%s', styleConfig.headerStyle, title),
"|-",
'| style="' .. styleConfig.cellStyles[1] .. '"|' .. renderColumn(columns[1]),
'| style="' .. styleConfig.cellStyles[2] .. '"|' .. renderColumn(columns[2]),
'| style="' .. styleConfig.cellStyles[3] .. '"|' .. renderColumn(columns[3]),
'| style="' .. styleConfig.cellStyles[4] .. '"|' .. renderColumn(columns[4]),
"|}",
}, "\n")
end
return p