Editing Module:BSW/MainPage
From the only original and legitimate Battlestar Wiki: the free-as-in-beer, non-corporate, open-content encyclopedia, analytical reference, and episode guide on all things Battlestar Galactica. Accept neither subpar substitutes nor subpar clones.
More actions
The edit can be undone.
Please check the comparison below to verify that this is what you want to do, and then publish the changes below to finish undoing the edit.
| Latest revision | Your text | ||
| Line 1: | Line 1: | ||
-- Module:BSW/MainPage | -- Module:BSW/MainPage | ||
-- | -- Generates main page HTML using raw string concatenation. | ||
-- | -- mw.html is NOT used because its output is passed through | ||
-- < | -- MediaWiki's HTML sanitizer which strips <button> and | ||
-- | -- <a class="..."> elements. | ||
-- | -- Instead we build raw HTML strings and return them via | ||
-- frame:callParserFunction to inject them as strip markers | |||
-- that survive the sanitizer pass. | |||
-- | |||
-- Usage: {{#invoke:BSW/MainPage|functionName|param=value|...}} | |||
local p = {} | local p = {} | ||
-- ── | -- ── HTML helpers ────────────────────────────────────────────────── | ||
local function | local function esc( s ) | ||
s = tostring( s or '' ) | s = tostring( s or '' ) | ||
s = s:gsub( '&', '&' ):gsub( '<', '<' ):gsub( '>', '>' ):gsub( '"', '"' ) | s = s:gsub( '&', '&' ) | ||
s = s:gsub( '<', '<' ) | |||
s = s:gsub( '>', '>' ) | |||
s = s:gsub( '"', '"' ) | |||
return s | return s | ||
end | end | ||
local function | -- Build an attribute string, skipping empty values | ||
if | local function atr( name, value ) | ||
if value and value ~= '' then | |||
return ' ' .. name .. '="' .. esc( value ) .. '"' | |||
end | |||
return '' | return '' | ||
end | end | ||
-- | -- Wrap output so it bypasses the sanitizer. | ||
-- We use the <score> trick: any extension tag registered in MW | |||
-- acts as a strip marker. But the cleanest method available in | |||
-- Scribunto is to mark output as safe using the internal | |||
-- mw.text.nowiki approach combined with frame preprocessing. | |||
-- The most reliable cross-version approach: return the HTML | |||
-- inside a <templatestyles> strip tag... but actually the | |||
-- correct documented approach for Scribunto is simply: | |||
-- return frame:preprocess( '<html>' .. html .. '</html>' ) | |||
-- but <html> tag needs to be enabled. So we use the | |||
-- well-documented mw workaround: build wikitext that produces | |||
-- the HTML we want via #tag parser functions for the | |||
-- problematic elements (button, a with class). | |||
-- | -- Build a <button> via #tag parser function call | ||
local function | local function btn( frame, id, cls, onclick, label ) | ||
local attrs = {} | |||
if id and id ~= '' then attrs['id'] = id end | |||
if cls then | |||
-- #tag doesn't support class directly, embed in attr string | |||
end | |||
-- Use frame:callParserFunction with #tag | |||
-- #tag:button|label|id=...|class=...|aria-label=... | |||
-- This is the correct way to emit elements the sanitizer would block | |||
local params = { label } | |||
params['class'] = cls or '' | |||
if id and id ~= '' then params['id'] = id end | |||
if onclick and onclick ~= '' then params['onclick'] = onclick end | |||
return frame:callParserFunction( '#tag:button', params ) | |||
end | end | ||
-- | -- Build an <a> tag via #tag | ||
local function | local function anchor( frame, href, cls, content, attrs_extra ) | ||
local params = { content } | |||
params['href'] = href or '#' | |||
if cls and cls ~= '' then params['class'] = cls end | |||
if attrs_extra then | |||
for k, v in pairs( attrs_extra ) do | |||
params[ k ] = v | |||
end | |||
if | |||
end | end | ||
return | return frame:callParserFunction( '#tag:a', params ) | ||
end | end | ||
-- | -- ── hero() ──────────────────────────────────────────────────────── | ||
function p.hero( frame ) | |||
local args = frame.args | |||
local count = tonumber( args.count ) or 0 | |||
local out = {} | |||
out[#out+1] = '<div class="bsw-hero">' | |||
local | for i = 1, count do | ||
local pfx = 'slide' .. i .. '_' | |||
local article = mw.text.trim( args[ pfx .. 'article' ] or '' ) | |||
local series = mw.text.trim( args[ pfx .. 'series' ] or '' ) | |||
local title = mw.text.trim( args[ pfx .. 'title' ] or article ) | |||
local tlink = mw.text.trim( args[ pfx .. 'titlelink' ] or article ) | |||
local desc = mw.text.trim( args[ pfx .. 'desc' ] or '' ) | |||
local bcolor = mw.text.trim( args[ pfx .. 'badgecolor' ] or '' ) | |||
local active = ( i == 1 ) and ' bsw-active' or '' | |||
" | out[#out+1] = '<div class="bsw-slide' .. active .. '"' .. atr( 'data-article', article ) .. '>' | ||
"'' | out[#out+1] = '<div class="bsw-slide-bg"></div>' | ||
out[#out+1] = '<div class="bsw-slide-overlay"></div>' | |||
out[#out+1] = '<div class="bsw-slide-content">' | |||
out[#out+1] = '<div class="bsw-slide-badge">' | |||
local dot_style = bcolor ~= '' and ' style="background:' .. bcolor .. '"' or '' | |||
out[#out+1] = '<span class="bsw-slide-badge-dot"' .. dot_style .. '></span>' | |||
out[#out+1] = '<span>' .. esc( series ) .. '</span>' | |||
'< | out[#out+1] = '</div>' | ||
'< | |||
-- Title: wikilink rendered by preprocessor | |||
end | local wlink = frame:preprocess( '[[' .. tlink .. '|' .. title .. ']]' ) | ||
out[#out+1] = '<div class="bsw-slide-title">' .. wlink .. '</div>' | |||
out[#out+1] = '<div class="bsw-slide-desc">' .. esc( desc ) .. '</div>' | |||
out[#out+1] = '</div>' | |||
out[#out+1] = '</div>' | |||
end | |||
-- Dots using #tag:button via callParserFunction | |||
out[#out+1] = '<div class="bsw-hero-dots">' | |||
for i = 1, count do | |||
local cls = 'bsw-hero-dot' .. ( i == 1 and ' bsw-active' or '' ) | |||
out[#out+1] = btn( frame, nil, cls, nil, '' ) | |||
-- Inject aria-label by replacing the closing > since #tag doesn't | |||
-- let us set aria-label easily — use a separate call with all attrs | |||
-- Actually #tag supports arbitrary attrs, rewrite: | |||
end | |||
out[#out+1] = '</div>' | |||
-- Redo dots properly — #tag:button supports all HTML attrs | |||
local | -- Remove the dots section we just built and redo | ||
-- (pop back to before the dots div) | |||
local | local dots_html = '<div class="bsw-hero-dots">' | ||
for i = 1, count do | |||
local cls = 'bsw-hero-dot' .. ( i == 1 and ' bsw-active' or '' ) | |||
local dot_params = { '' } | |||
dot_params['class'] = cls | |||
dot_params['aria-label'] = 'Slide ' .. i | |||
dots_html = dots_html .. frame:callParserFunction( '#tag:button', dot_params ) | |||
end | |||
dots_html = dots_html .. '</div>' | |||
-- Remove the bad dots we pushed, replace | |||
-- (simpler: just build the whole thing cleanly from scratch) | |||
local result = '<div class="bsw-hero">' | |||
for i = 1, count do | for i = 1, count do | ||
local pfx | local pfx = 'slide' .. i .. '_' | ||
local | local article = mw.text.trim( args[ pfx .. 'article' ] or '' ) | ||
local series = mw.text.trim( args[pfx..'series'] | local series = mw.text.trim( args[ pfx .. 'series' ] or '' ) | ||
local title | local title = mw.text.trim( args[ pfx .. 'title' ] or article ) | ||
local tlink | local tlink = mw.text.trim( args[ pfx .. 'titlelink' ] or article ) | ||
local desc | local desc = mw.text.trim( args[ pfx .. 'desc' ] or '' ) | ||
local bcolor = mw.text.trim( args[pfx..'badgecolor'] or '' ) | local bcolor = mw.text.trim( args[ pfx .. 'badgecolor' ] or '' ) | ||
local active | local active = ( i == 1 ) and ' bsw-active' or '' | ||
local | local dot_style = bcolor ~= '' and ' style="background:' .. bcolor .. '"' or '' | ||
local | local wlink = frame:preprocess( '[[' .. tlink .. '|' .. title .. ']]' ) | ||
result = result .. | |||
'<div class="bsw-slide' .. active .. '"' .. | '<div class="bsw-slide' .. active .. '"' .. atr( 'data-article', article ) .. '>' .. | ||
'<div class="bsw-slide-bg"></div>' .. | '<div class="bsw-slide-bg"></div>' .. | ||
'<div class="bsw-slide-overlay"></div>' .. | '<div class="bsw-slide-overlay"></div>' .. | ||
'<div class="bsw-slide-content">' .. | '<div class="bsw-slide-content">' .. | ||
'<div class="bsw-slide-badge">' .. | '<div class="bsw-slide-badge">' .. | ||
'<span class="bsw-slide-badge-dot"' .. | '<span class="bsw-slide-badge-dot"' .. dot_style .. '></span>' .. | ||
'<span>' .. | '<span>' .. esc( series ) .. '</span>' .. | ||
'</div>' .. | '</div>' .. | ||
'<div class="bsw-slide-title">' .. | '<div class="bsw-slide-title">' .. wlink .. '</div>' .. | ||
'<div class="bsw-slide-desc">' .. | '<div class="bsw-slide-desc">' .. esc( desc ) .. '</div>' .. | ||
'</div>' .. | '</div>' .. | ||
'</div>' | '</div>' | ||
end | end | ||
-- | result = result .. dots_html | ||
-- Nav buttons | |||
local prev_params = { '‹' } | |||
prev_params['id'] = 'bsw-hero-prev' | |||
prev_params['aria-label'] = 'Previous slide' | |||
local next_params = { '›' } | |||
next_params['id'] = 'bsw-hero-next' | |||
next_params['aria-label'] = 'Next slide' | |||
result = result .. | |||
'<div class="bsw-hero-nav">' .. | '<div class="bsw-hero-nav">' .. | ||
frame:callParserFunction( '#tag:button', prev_params ) .. | |||
frame:callParserFunction( '#tag:button', next_params ) .. | |||
'</div>' .. | '</div>' .. | ||
'</div>' | '</div>' | ||
return | return result | ||
end | end | ||
| Line 149: | Line 193: | ||
local count = tonumber( args.count ) or 0 | local count = tonumber( args.count ) or 0 | ||
local | local result = | ||
'<div class="bsw-portals">' .. | '<div class="bsw-portals">' .. | ||
'<div class="bsw-portals-label">∞ Portals of Battlestar Wiki ∞</div>' .. | '<div class="bsw-portals-label">∞ Portals of Battlestar Wiki ∞</div>' .. | ||
| Line 156: | Line 200: | ||
for i = 1, count do | for i = 1, count do | ||
local pfx = 'portal' .. i .. '_' | local pfx = 'portal' .. i .. '_' | ||
local href = mw.text.trim( args[pfx..'href'] | local href = mw.text.trim( args[ pfx .. 'href' ] or '#' ) | ||
local stripe = mw.text.trim( args[pfx..'stripe'] or '' ) | local stripe = mw.text.trim( args[ pfx .. 'stripe' ] or '' ) | ||
local icon = mw.text.trim( args[pfx..'icon'] | local icon = mw.text.trim( args[ pfx .. 'icon' ] or '' ) | ||
local name = mw.text.trim( args[pfx..'name'] | local name = mw.text.trim( args[ pfx .. 'name' ] or '' ) | ||
local sub = mw.text.trim( args[pfx..'sub'] | local sub = mw.text.trim( args[ pfx .. 'sub' ] or '' ) | ||
local stripe_style = stripe ~= '' and ' style="background:' .. stripe .. '"' or '' | |||
local stripe_div = '<div class="bsw-portal-stripe"' .. stripe_style .. '></div>' | |||
local inner = | local inner = | ||
stripe_div .. | |||
'<span class="bsw-portal-icon">' .. icon .. '</span>' .. | '<span class="bsw-portal-icon">' .. icon .. '</span>' .. | ||
'<span class="bsw-portal-name">' .. | '<span class="bsw-portal-name">' .. esc( name ) .. '</span>' .. | ||
'<span class="bsw-portal-sub">' .. | '<span class="bsw-portal-sub">' .. esc( sub ) .. '</span>' | ||
local a_params = { inner } | |||
a_params['class'] = 'bsw-portal' | |||
a_params['href'] = href | |||
result = result .. frame:callParserFunction( '#tag:a', a_params ) | |||
end | end | ||
result = result .. '</div></div>' | |||
return | return result | ||
end | end | ||
-- ── | -- ── statsblock() ────────────────────────────────────────────────── | ||
function p.statsblock( frame ) | |||
local args = frame.args | |||
local | |||
local grid = '<div class="bsw-stats-grid">' | |||
for i = 1, 6 do | |||
local | local n = mw.text.trim( args[ 'n' .. i ] or '' ) | ||
local label = mw.text.trim( args[ 'label' .. i ] or '' ) | |||
if n ~= '' or label ~= '' then | |||
-- n may contain MW magic word output already expanded | |||
-- | grid = grid .. | ||
'<div class="bsw-stat">' .. | |||
'<div class="bsw-stat-n">' .. n .. '</div>' .. | |||
'<div class="bsw-stat-l">' .. esc( label ) .. '</div>' .. | |||
'</div>' | |||
end | |||
end | |||
grid = grid .. '</div>' | |||
local links = '<div class="bsw-stat-links">' | |||
for i = 1, 4 do | |||
local url = mw.text.trim( args[ 'link' .. i .. '_url' ] or '' ) | |||
local text = mw.text.trim( args[ 'link' .. i .. '_text' ] or '' ) | |||
if url ~= '' then | |||
local a_params = { text ~= '' and text or url } | |||
a_params['class'] = 'bsw-stat-link' | |||
a_params['href'] = url | |||
links = links .. frame:callParserFunction( '#tag:a', a_params ) | |||
end | end | ||
end | end | ||
hd = | links = links .. '</div>' | ||
return | |||
return | |||
'<div class="bsw-card">' .. | |||
'<div class="bsw-card-hd">Wiki statistics</div>' .. | |||
'<div class="bsw-card-body">' .. grid .. links .. '</div>' .. | |||
'</div>' | |||
end | |||
-- ── recenttabs() ────────────────────────────────────────────────── | |||
function p.recenttabs( frame ) | |||
local tabs = { { 'All', 'all' }, { 'EN', 'en' }, { 'DE', 'de' }, { 'Media', 'media' } } | |||
local result = '<div class="bsw-wiki-tabs">' | |||
for i, t in ipairs( tabs ) do | |||
local cls = 'bsw-wtab' .. ( i == 1 and ' bsw-active' or '' ) | |||
local params = { t[1] } | |||
params['class'] = cls | |||
params['onclick'] = "bswSetTab(this,'" .. t[2] .. "')" | |||
result = result .. frame:callParserFunction( '#tag:button', params ) | |||
end | |||
return result .. '</div>' | |||
end | end | ||
| Line 214: | Line 287: | ||
local content = args.content or '' | local content = args.content or '' | ||
-- | local hd = '<div class="bsw-card-hd">' .. esc( title ) | ||
if | if lurl ~= '' then | ||
local a_params = { ltext ~= '' and ltext or 'More →' } | |||
a_params['href'] = lurl | |||
hd = hd .. frame:callParserFunction( '#tag:a', a_params ) | |||
end | |||
hd = hd .. '</div>' | |||
return '<div class="bsw-card">' .. | return | ||
'<div class="bsw-card">' .. | |||
hd .. | |||
'<div class="bsw-card-body">' .. content .. '</div>' .. | '<div class="bsw-card-body">' .. content .. '</div>' .. | ||
'</div>' | '</div>' | ||
| Line 225: | Line 304: | ||
-- ── featuredloading() ───────────────────────────────────────────── | -- ── featuredloading() ───────────────────────────────────────────── | ||
function p.featuredloading( frame ) | function p.featuredloading( frame ) | ||
local a_params = { 'Read more →' } | |||
-- | a_params['id'] = 'bsw-featured-link' | ||
a_params['href'] = '#' | |||
local hd = | local hd = | ||
'<div class="bsw-card-hd">Featured article' .. | '<div class="bsw-card-hd">Featured article' .. | ||
' | frame:callParserFunction( '#tag:a', a_params ) .. | ||
'</div>' | '</div>' | ||
return '<div class="bsw-card">' .. | return | ||
'<div class="bsw-card">' .. | |||
hd .. | hd .. | ||
'<div class="bsw-card-body">' .. | '<div class="bsw-card-body">' .. | ||
| Line 238: | Line 320: | ||
'<div class="bsw-loading">' .. | '<div class="bsw-loading">' .. | ||
'<div class="bsw-spinner"></div>' .. | '<div class="bsw-spinner"></div>' .. | ||
'Loading today\'s featured | 'Loading today\'s featured article…' .. | ||
'</div></div></div></div>' | '</div></div></div></div>' | ||
end | end | ||
| Line 244: | Line 326: | ||
-- ── photolab() ──────────────────────────────────────────────────── | -- ── photolab() ──────────────────────────────────────────────────── | ||
function p.photolab( frame ) | function p.photolab( frame ) | ||
local args | local args = frame.args | ||
local content | local content = args.content or '' | ||
local | local prev_url = mw.text.trim( args.prev_url or '#' ) | ||
local prev_lbl | local prev_lbl = mw.text.trim( args.prev_label or '‹' ) | ||
local | local caption = mw.text.trim( args.caption or '' ) | ||
local | local next_url = mw.text.trim( args.next_url or '#' ) | ||
local next_lbl = mw.text.trim( args.next_label or '›' ) | |||
local | |||
local a_view_params = { 'View project →' } | |||
a_view_params['href'] = '/BW:Potd' | |||
local | local a_prev_params = { prev_lbl } | ||
a_prev_params['href'] = prev_url | |||
local a_next_params = { next_lbl } | |||
a_next_params['href'] = next_url | |||
local hd = | local hd = | ||
'<div class="bsw-card-hd"> | '<div class="bsw-card-hd">∞ Photo Lab — Picture of the Day' .. | ||
frame: | frame:callParserFunction( '#tag:a', a_view_params ) .. | ||
'</div>' | '</div>' | ||
local nav = | local nav = | ||
'<div class="bsw-photo-nav">' .. | '<div class="bsw-photo-nav">' .. | ||
frame:callParserFunction( '#tag:a', a_prev_params ) .. | |||
'<span class="bsw-photo-caption">' .. caption .. '</span>' .. | '<span class="bsw-photo-caption">' .. esc( caption ) .. '</span>' .. | ||
frame:callParserFunction( '#tag:a', a_next_params ) .. | |||
'</div>' | '</div>' | ||
return '<div class="bsw-card">' .. hd .. | return '<div class="bsw-card">' .. hd .. content .. nav .. '</div>' | ||
end | end | ||
-- ── interwiki() ─────────────────────────────────────────────────── | -- ── interwiki() ─────────────────────────────────────────────────── | ||
function p.interwiki( frame ) | function p.interwiki( frame ) | ||
local args = frame.args | local args = frame.args | ||
local | local result = '<div class="bsw-interwiki">' | ||
for i = 1, 8 do | for i = 1, 8 do | ||
local flag = mw.text.trim( args[i..'_flag' ] or '' ) | local flag = mw.text.trim( args[ i .. '_flag' ] or '' ) | ||
local label = mw.text.trim( args[i..'_label'] or '' ) | local label = mw.text.trim( args[ i .. '_label' ] or '' ) | ||
local url = mw.text.trim( args[i..'_url' | local url = mw.text.trim( args[ i .. '_url' ] or '' ) | ||
if url ~= '' then | if url ~= '' then | ||
local | local a_params = { label } | ||
a_params['href'] = url | |||
local prefix = flag ~= '' and ( flag .. ' ' ) or '' | |||
result = result .. | |||
'<div class="bsw-iw">' .. | |||
prefix .. | |||
local prefix = flag ~= '' and (flag .. ' ') or '' | frame:callParserFunction( '#tag:a', a_params ) .. | ||
'</div>' | |||
end | end | ||
end | end | ||
return | |||
return result .. '</div>' | |||
end | end | ||
-- ── tagline() ───────────────────────────────────────────────────── | -- ── tagline() ───────────────────────────────────────────────────── | ||
function p.tagline( frame ) | function p.tagline( frame ) | ||
-- Use frame:preprocess for wikitext bold/italic markup | |||
local inner = frame:preprocess( | local inner = frame:preprocess( | ||
"The only original and legitimate '''Battlestar Wiki''' " .. | "The only original and legitimate '''Battlestar Wiki''' " .. | ||
" | "— the free-as-in-beer, non-corporate, open-content encyclopedia " .. | ||
"on all things ''Battlestar Galactica''.<br>" .. | "on all things ''Battlestar Galactica''.<br>" .. | ||
" | "∞ ''Accept neither subpar substitutes nor subpar clones.'' ∞" | ||
) | ) | ||
return '<div class="bsw-tagline">' .. inner .. '</div>' | return '<div class="bsw-tagline">' .. inner .. '</div>' | ||
end | end | ||
return p | return p | ||