Module:FeaturedExtract
From Landrace.Wiki - The Landrace Cannabis Wiki
More actions
Documentation for this module may be created at Module:FeaturedExtract/doc
-- Module:FeaturedExtract
-- Pulls content from articles for use in homepage cards.
--
-- p.lead — lead-section text. Strips the leading infobox, all <ref>
-- blocks, {{cn}} markers, clips at the first == heading,
-- then truncates to a clean length. Emits explicit <p> tags
-- so paragraph breaks survive when wrapped in a block
-- element on the calling page. Set nomore=1 to suppress
-- the trailing "read more" link.
--
-- p.heroDiv — float-image div for the featured-article panel. Image
-- source priority: explicit Has image value (arg 1), then
-- first [[File:...]] in page wikitext, then |image=
-- parameter from the leading infobox call. Returns empty
-- string when none yields an image so no broken markup
-- renders. Detects image orientation (landscape, portrait,
-- square-ish) and emits a modifier class so CSS can set a
-- different display width per orientation. Picks a thumb
-- size hint appropriate to the orientation so retina
-- sharpness holds. Caller may override the hint via arg 3.
local p = {}
-- Strip a balanced {{...}} template block at the start of the text.
local function stripLeadingTemplate(text)
while true do
local s = text:match("^%s*()")
if not s or text:sub(s, s+1) ~= "{{" then return text end
local depth, i = 0, s
local closed = false
while i <= #text do
local c2 = text:sub(i, i+1)
if c2 == "{{" then
depth = depth + 1
i = i + 2
elseif c2 == "}}" then
depth = depth - 1
i = i + 2
if depth == 0 then
text = text:sub(i)
closed = true
break
end
else
i = i + 1
end
end
if not closed then return text end
end
end
-- Take everything up to the first level-2+ heading.
local function takeLead(text)
local heading = text:find("\n==")
if heading then return text:sub(1, heading - 1) end
return text
end
-- Truncate at the last sentence boundary (. ! ?) before max chars.
-- Falls back to the last word boundary if no sentence ends in range.
local function truncate(text, maxChars)
if #text <= maxChars then return text, false end
local clip = text:sub(1, maxChars)
local lastSentence = clip:find("[%.%?%!]%s+%u[^%.%?%!]*$")
if lastSentence then
local upTo = clip:sub(1, lastSentence)
upTo = upTo:gsub("%s+$", "")
return upTo, true
end
local lastSpace = clip:find("%s+[^%s]*$")
if lastSpace then
return clip:sub(1, lastSpace - 1), true
end
return clip, true
end
-- Find the first [[File:...]] or [[Image:...]] filename in wikitext.
local function firstFileIn(content)
if not content or content == "" then return "" end
local img = content:match("%[%[%s*[Ff]ile%s*:%s*([^%[%]|]+)")
or content:match("%[%[%s*[Ii]mage%s*:%s*([^%[%]|]+)")
or ""
return mw.text.trim(img)
end
-- Read |image= parameter from the leading infobox call. Handles bare
-- filename, [[File:Foo.jpg]] wrappers, and parameter values with sized
-- options. Limited to the first 3000 chars to scope to the infobox
-- region only.
local function imageFromInfobox(content)
if not content or content == "" then return "" end
local head = content:sub(1, 3000)
local raw = head:match("|%s*image%s*=%s*([^|}\n]+)")
if not raw then return "" end
raw = mw.text.trim(raw)
if raw == "" then return "" end
local fromLink = raw:match("^%[%[%s*[Ff]ile%s*:%s*([^%[%]|]+)")
if fromLink then return mw.text.trim(fromLink) end
return raw
end
-- Classify image as landscape, portrait, or square based on dimensions.
-- Returns modifier class fragment and a thumbnail size hint matched
-- to the display width of that orientation tier (~2x for retina).
-- Falls back to square-ish defaults when dimensions can't be read.
local function orientationFor(filename)
local fileTitle = mw.title.new("File:" .. filename)
if fileTitle and fileTitle.file and fileTitle.file.exists then
local w = fileTitle.file.width or 0
local h = fileTitle.file.height or 0
if w > 0 and h > 0 then
local ratio = w / h
if ratio >= 1.2 then
return "home-featured__float--landscape", "800px"
elseif ratio <= 0.85 then
return "home-featured__float--portrait", "560px"
end
end
end
return "home-featured__float--square", "640px"
end
function p.lead(frame)
local args = frame.args
local pagename = args[1] or args.article
if not pagename or pagename == "" then return "" end
local maxChars = tonumber(args.chars or args[2]) or 600
local nomore = args.nomore and args.nomore ~= "" and args.nomore ~= "0"
local title = mw.title.new(pagename)
if not title or not title.exists then return "" end
local content = title:getContent()
if not content then return "" end
content = stripLeadingTemplate(content)
content = takeLead(content)
content = content:gsub("<ref[^/>]*/>", "")
content = content:gsub("<ref[^>]*>.-</ref>", "")
content = content:gsub("{{[Cc]n}}", "")
content = content:gsub("{{[Cc]itation needed}}", "")
content = content:gsub("^%s+", ""):gsub("%s+$", "")
local truncated
content, truncated = truncate(content, maxChars)
local readMore = nomore and '' or (' <span class="home-featured__more">[[' .. pagename .. '|read more →]]</span>')
local tail = (truncated and ' …' or '') .. readMore
local paragraphs = {}
for para in (content .. "\n\n"):gmatch("(.-)\n\n+") do
para = para:gsub("^%s+", ""):gsub("%s+$", "")
if para ~= "" then
table.insert(paragraphs, para)
end
end
if #paragraphs == 0 then return "" end
paragraphs[#paragraphs] = paragraphs[#paragraphs] .. tail
local out = {}
for _, para in ipairs(paragraphs) do
table.insert(out, "<p>" .. para .. "</p>")
end
return table.concat(out, "\n")
end
function p.heroDiv(frame)
local explicit = mw.text.trim(frame.args[1] or "")
local pageName = mw.text.trim(frame.args[2] or "")
local sizeOverride = mw.text.trim(frame.args[3] or "")
local img = explicit
if img == "" and pageName ~= "" then
local title = mw.title.new(pageName)
if title and title.exists then
local content = title:getContent() or ""
img = firstFileIn(content)
if img == "" then
img = imageFromInfobox(content)
end
end
end
if img == "" then return "" end
local orientationClass, thumbHint = orientationFor(img)
local size = sizeOverride ~= "" and sizeOverride or thumbHint
return string.format(
'<div class="home-featured__float %s">[[File:%s|%s|link=%s|alt=%s]]</div>',
orientationClass, img, size, pageName, pageName
)
end
return p