Jump to content

Module:DailyFeatured: Difference between revisions

From the Vrienden Universe, a fictional wiki
No edit summary
No edit summary
Line 1: Line 1:
local p = {}
local p = {}
local POOL_TEMPLATE = "Featured pool"


local function getPool()
local function getPool()
local content = mw.getCurrentFrame():expandTemplate{ title = "Featured pool" }
local content = mw.getCurrentFrame():expandTemplate{ title = POOL_TEMPLATE }
local pages = {}
local pages = {}


for line in mw.text.gsplit(content or "", "\n", true) do
for line in mw.text.gsplit(content or "", "\n", true) do
line = mw.text.trim(line)
line = mw.text.trim(line or "")
line = line:gsub("<!%-%-.-%-%->", "")
line = line:gsub("<!%-%-.-%-%->", "")
line = mw.text.trim(line)
line = mw.text.trim(line)
Line 18: Line 20:
line = linkedTitle
line = linkedTitle
end
end
line = mw.text.trim(line)


if line ~= "" then
if line ~= "" then
Line 51: Line 55:
s = s:gsub("%[%[[Ii]mage:.-%]%]", "")
s = s:gsub("%[%[[Ii]mage:.-%]%]", "")
s = removeTemplates(s)
s = removeTemplates(s)
s = s:gsub("'''", "")
s = s:gsub("''", "")
s = s:gsub("%[%[([^%]|]+)|([^%]]+)%]%]", "%2")
s = s:gsub("%[%[([^%]]+)%]%]", "%1")
s = s:gsub("%[https?://[^%s%]]+%s+([^%]]+)%]", "%1")
s = s:gsub("%[https?://[^%s%]]+%]", "")
s = s:gsub("<br%s*/?>", "\n")
s = s:gsub("<[^>]+>", "")
s = s:gsub("\r", "")


local cleanedLines = {}
local cleanedLines = {}
Line 118: Line 131:
end
end


if value:lower() == "none" or value:lower() == "no" then
local lower = mw.ustring.lower(value)
 
if lower == "none" or lower == "no" or lower == "n/a" then
return nil
return nil
end
end
Line 132: Line 147:
for line in mw.text.gsplit(wikitext, "\n", true) do
for line in mw.text.gsplit(wikitext, "\n", true) do
local value = line:match("^%s*|%s*image%d*%s*=%s*(.-)%s*$")
local value = line:match("^%s*|%s*image%d*%s*=%s*(.-)%s*$")
or line:match("^%s*|%s*logo%d*%s*=%s*(.-)%s*$")
or line:match("^%s*|%s*flag%d*%s*=%s*(.-)%s*$")


if value then
if value then
Line 198: Line 215:
if args.imageonly == "1" then
if args.imageonly == "1" then
return data.image or ""
return data.image or ""
end
local imageBlock = ""
if data.image then
imageBlock = string.format(
'<div style="float:right; width:105px; margin:0 0 0.5em 0.75em; padding:4px; border:1px solid #a2a9b1; background:#f8f9fa; border-radius:6px; text-align:center;">[[%s|frameless|100x100px|link=%s|%s]]</div>',
data.image,
data.title,
data.title
)
end
end


return string.format(
return string.format(
"'''[[%s]]'''<div style=\"margin-top:0.35em;\"><small>%s</small></div>",
'%s\'\'\'[[%s]]\'\'\'<div style="margin-top:0.35em; line-height:1.5;">%s</div>',
imageBlock,
data.title,
data.title,
data.lead
data.lead
Line 211: Line 240:


if not data then
if not data then
return '<div class="featured-box"><div class="featured-box-title">Featured page</div><div class="featured-box-body">' .. err .. '</div></div>'
return '<div style="width:100%; max-width:820px; margin:0.5em 0; border:1px solid #a2a9b1; border-radius:8px; background:#ffffff; overflow:hidden;"><div style="padding:0.5em 0.75em; font-size:110%; font-weight:bold; background:#eaecf0; border-bottom:1px solid #a2a9b1;">Featured page</div><div style="padding:0.8em;">' .. err .. '</div></div>'
end
end


Line 218: Line 247:
if data.image then
if data.image then
imageBlock = string.format(
imageBlock = string.format(
'<div class="featured-box-image">[[%s|frameless|170x170px|link=%s|%s]]</div>',
'<div style="float:right; width:105px; margin:0 0 0.5em 0.75em; padding:4px; border:1px solid #a2a9b1; background:#f8f9fa; border-radius:6px; text-align:center;">[[%s|frameless|100x100px|link=%s|%s]]</div>',
data.image,
data.image,
data.title,
data.title,
Line 226: Line 255:


return string.format(
return string.format(
'<div class="featured-box">' ..
'<div style="width:100%; max-width:820px; margin:0.5em 0; border:1px solid #a2a9b1; border-radius:8px; background:#ffffff; overflow:hidden;">' ..
'<div class="featured-box-title">Featured page</div>' ..
'<div style="padding:0.5em 0.75em; font-size:110%; font-weight:bold; background:#eaecf0; border-bottom:1px solid #a2a9b1;">Featured page</div>' ..
'<div class="featured-box-body">' ..
'<div style="padding:0.8em; font-size:105%; line-height:1.5;">' ..
'%s' ..
'%s' ..
'<div class="featured-box-text">' ..
'<div style="font-size:110%; margin-bottom:0.35em;">\'\'\'[[%s]]\'\'\'</div>' ..
'<div class="featured-box-page-title">\'\'\'[[%s]]\'\'\'</div>' ..
'<div>%s</div>' ..
'<div class="featured-box-lead">%s</div>' ..
'<div style="margin-top:0.6em; clear:both;">[[:%s|Open page]]</div>' ..
'<div class="featured-box-open">[[:%s|Open page]]</div>' ..
'</div>' ..
'</div>' ..
'</div>' ..
'</div>',
'</div>',

Revision as of 10:03, 14 May 2026


local p = {}

local POOL_TEMPLATE = "Featured pool"

local function getPool()
	local content = mw.getCurrentFrame():expandTemplate{ title = POOL_TEMPLATE }
	local pages = {}

	for line in mw.text.gsplit(content or "", "\n", true) do
		line = mw.text.trim(line or "")
		line = line:gsub("<!%-%-.-%-%->", "")
		line = mw.text.trim(line)

		if line ~= "" then
			line = line:gsub("^%*%s*", "")
			line = mw.text.trim(line)

			local linkedTitle = line:match("^%[%[([^%]|]+)|?.-%]%]$")
			if linkedTitle then
				line = linkedTitle
			end

			line = mw.text.trim(line)

			if line ~= "" then
				table.insert(pages, line)
			end
		end
	end

	return pages
end

local function removeTemplates(s)
	local previous

	repeat
		previous = s
		s = s:gsub("%b{}", "")
	until s == previous

	return s
end

local function cleanLeadWikitext(s)
	if not s or s == "" then
		return ""
	end

	s = s:gsub("<!%-%-.-%-%->", "")
	s = s:gsub("<ref[^>/]-/>", "")
	s = s:gsub("<ref.->.-</ref>", "")
	s = s:gsub("<ref.->", "")
	s = s:gsub("%[%[[Ff]ile:.-%]%]", "")
	s = s:gsub("%[%[[Ii]mage:.-%]%]", "")
	s = removeTemplates(s)
	s = s:gsub("'''", "")
	s = s:gsub("''", "")
	s = s:gsub("%[%[([^%]|]+)|([^%]]+)%]%]", "%2")
	s = s:gsub("%[%[([^%]]+)%]%]", "%1")
	s = s:gsub("%[https?://[^%s%]]+%s+([^%]]+)%]", "%1")
	s = s:gsub("%[https?://[^%s%]]+%]", "")
	s = s:gsub("<br%s*/?>", "\n")
	s = s:gsub("<[^>]+>", "")
	s = s:gsub("\r", "")

	local cleanedLines = {}

	for line in mw.text.gsplit(s, "\n", true) do
		local trimmed = mw.text.trim(line)

		if trimmed ~= ""
			and not trimmed:match("^__%u+__$")
			and not trimmed:match("^%[%[[Cc]ategory:")
			and not trimmed:match("^%s*|")
			and not trimmed:match("^%s*}") then
			table.insert(cleanedLines, trimmed)
		end
	end

	return mw.text.trim(table.concat(cleanedLines, "\n\n"))
end

local function extractLeadFromContent(wikitext)
	if not wikitext or wikitext == "" then
		return ""
	end

	local leadLines = {}

	for line in mw.text.gsplit(wikitext, "\n", true) do
		if line:match("^%s*==+%s*[^=].-==+%s*$") then
			break
		end

		table.insert(leadLines, line)
	end

	return cleanLeadWikitext(table.concat(leadLines, "\n"))
end

local function normalizeFileName(value)
	if not value or value == "" then
		return nil
	end

	value = mw.text.trim(value)
	value = value:gsub("<!%-%-.-%-%->", "")
	value = mw.text.trim(value)

	if value == "" then
		return nil
	end

	local linkedFile = value:match("%[%[%s*[Ff]ile%s*:%s*([^%]|%]]+)")
		or value:match("%[%[%s*[Ii]mage%s*:%s*([^%]|%]]+)")

	if linkedFile then
		value = linkedFile
	else
		value = value:gsub("^%s*[Ff]ile%s*:%s*", "")
		value = value:gsub("^%s*[Ii]mage%s*:%s*", "")
		value = value:gsub("|.*$", "")
		value = value:gsub("%]%].*$", "")
	end

	value = mw.text.trim(value)

	if value == "" then
		return nil
	end

	local lower = mw.ustring.lower(value)

	if lower == "none" or lower == "no" or lower == "n/a" then
		return nil
	end

	return "File:" .. value
end

local function extractImageFromContent(wikitext)
	if not wikitext or wikitext == "" then
		return nil
	end

	for line in mw.text.gsplit(wikitext, "\n", true) do
		local value = line:match("^%s*|%s*image%d*%s*=%s*(.-)%s*$")
			or line:match("^%s*|%s*logo%d*%s*=%s*(.-)%s*$")
			or line:match("^%s*|%s*flag%d*%s*=%s*(.-)%s*$")

		if value then
			local file = normalizeFileName(value)

			if file then
				return file
			end
		end
	end

	local fallback = wikitext:match("%[%[%s*[Ff]ile%s*:%s*([^%]|%]]+)")
		or wikitext:match("%[%[%s*[Ii]mage%s*:%s*([^%]|%]]+)")

	if fallback then
		return normalizeFileName(fallback)
	end

	return nil
end

local function getFeaturedData()
	local pages = getPool()

	if #pages == 0 then
		return nil, "No featured pages defined."
	end

	local day = tonumber(os.date("%j")) or 1
	local index = ((day - 1) % #pages) + 1
	local title = pages[index]

	local page = mw.title.new(title)
	local lead = ""
	local image = nil

	if page and page.exists then
		local content = page:getContent() or ""
		lead = extractLeadFromContent(content)
		image = extractImageFromContent(content)
	end

	if lead == "" then
		lead = "Featured page for " .. os.date("%d %B %Y") .. "."
	end

	return {
		title = title,
		lead = lead,
		image = image
	}
end

function p.main(frame)
	local args = frame and frame.args or {}
	local data, err = getFeaturedData()

	if not data then
		return err
	end

	if args.titleonly == "1" then
		return data.title
	end

	if args.imageonly == "1" then
		return data.image or ""
	end

	local imageBlock = ""

	if data.image then
		imageBlock = string.format(
			'<div style="float:right; width:105px; margin:0 0 0.5em 0.75em; padding:4px; border:1px solid #a2a9b1; background:#f8f9fa; border-radius:6px; text-align:center;">[[%s|frameless|100x100px|link=%s|%s]]</div>',
			data.image,
			data.title,
			data.title
		)
	end

	return string.format(
		'%s\'\'\'[[%s]]\'\'\'<div style="margin-top:0.35em; line-height:1.5;">%s</div>',
		imageBlock,
		data.title,
		data.lead
	)
end

function p.box()
	local data, err = getFeaturedData()

	if not data then
		return '<div style="width:100%; max-width:820px; margin:0.5em 0; border:1px solid #a2a9b1; border-radius:8px; background:#ffffff; overflow:hidden;"><div style="padding:0.5em 0.75em; font-size:110%; font-weight:bold; background:#eaecf0; border-bottom:1px solid #a2a9b1;">Featured page</div><div style="padding:0.8em;">' .. err .. '</div></div>'
	end

	local imageBlock = ""

	if data.image then
		imageBlock = string.format(
			'<div style="float:right; width:105px; margin:0 0 0.5em 0.75em; padding:4px; border:1px solid #a2a9b1; background:#f8f9fa; border-radius:6px; text-align:center;">[[%s|frameless|100x100px|link=%s|%s]]</div>',
			data.image,
			data.title,
			data.title
		)
	end

	return string.format(
		'<div style="width:100%; max-width:820px; margin:0.5em 0; border:1px solid #a2a9b1; border-radius:8px; background:#ffffff; overflow:hidden;">' ..
		'<div style="padding:0.5em 0.75em; font-size:110%; font-weight:bold; background:#eaecf0; border-bottom:1px solid #a2a9b1;">Featured page</div>' ..
		'<div style="padding:0.8em; font-size:105%; line-height:1.5;">' ..
		'%s' ..
		'<div style="font-size:110%; margin-bottom:0.35em;">\'\'\'[[%s]]\'\'\'</div>' ..
		'<div>%s</div>' ..
		'<div style="margin-top:0.6em; clear:both;">[[:%s|Open page]]</div>' ..
		'</div>' ..
		'</div>',
		imageBlock,
		data.title,
		data.lead,
		data.title
	)
end

return p