Toggle menu
Toggle preferences menu
Toggle personal menu
Not logged in
Your IP address will be publicly visible if you make any edits.

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.
Warning: You are not logged in. Your IP address will be publicly visible if you make any edits. If you log in or create an account, your edits will be attributed to your username, along with other benefits.
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
-- MW 1.45 compatible. Uses only sanitizer-safe HTML elements.
-- Generates all main page HTML components via mw.html,
-- <button> is NOT on the MW 1.45 allowed list — replaced with
-- bypassing the wikitext parser entirely.
-- <span role="button"> which IS allowed and is wired by JS.
-- Usage: {{#invoke:BSW/MainPage|functionName|param=value|...}}
-- External <a class="..."> replaced with wikitext [url text]
-- processed via frame:preprocess().


local p = {}
local p = {}


-- ── Helpers ───────────────────────────────────────────────────────
-- ── Shared helpers ────────────────────────────────────────────────


local function e( s )
-- Safe attribute setter — skips nil/empty values
     s = tostring( s or '' )
local function attr( el, name, value )
    s = s:gsub( '&', '&amp;' ):gsub( '<', '&lt;' ):gsub( '>', '&gt;' ):gsub( '"', '&quot;' )
     if value and value ~= '' then
     return s
        el:attr( name, value )
    end
     return el
end
end


local function a( name, val )
-- ── hero() ────────────────────────────────────────────────────────
     if val and val ~= '' then return ' ' .. name .. '="' .. e(val) .. '"' end
-- Renders the entire hero slideshow: slides + dots + nav buttons.
    return ''
-- Called ONCE from the main page with all slide data packed as
end
-- numbered parameter groups.
--
-- Usage:
-- {{#invoke:BSW/MainPage|hero
-- |slide1_article  = Battlestar Galactica (RDM)
-- |slide1_series  = Re-imagined Series
-- |slide1_title    = Battlestar Galactica
-- |slide1_titlelink= Battlestar Galactica (RDM)
-- |slide1_desc     = The last surviving...
-- |slide1_badgecolor=
-- |slide2_article  = Number Eight
-- ...
-- |count          = 3
-- }}
 
function p.hero( frame )
    local args  = frame.args
    local count = tonumber( args.count ) or 0
    local root  = mw.html.create( 'div' ):addClass( 'bsw-hero' )


-- Wikitext internal link: [[target|label]]
    for i = 1, count do
local function wlink( frame, target, label )
        local pfx     = 'slide' .. i .. '_'
     return frame:preprocess( '[[' .. target .. '|' .. (label or target) .. ']]' )
        local article = args[ pfx .. 'article'  ] or ''
end
        local series  = args[ pfx .. 'series'    ] or ''
        local title  = args[ pfx .. 'title'    ] or article
        local tlink  = args[ pfx .. 'titlelink' ] or article
        local desc    = args[ pfx .. 'desc'      ] or ''
        local bcolor  = args[ pfx .. 'badgecolor'] or ''


-- External link via wikitext: [url label] — survives sanitizer
        local slide = root:tag( 'div' )
local function xlink( frame, url, label )
            :addClass( 'bsw-slide' )
    return frame:preprocess( '[' .. url .. ' ' .. (label or url) .. ']' )
            :attr( 'data-article', article )
end


-- Span acting as a button — sanitizer-safe, JS wires the behaviour
         if i == 1 then slide:addClass( 'bsw-active' ) end
local function spanBtn( id, cls, onclick, label )
    return '<span' ..
         a('id', id) ..
        a('class', cls) ..
        a('role', 'button') ..
        a('tabindex', '0') ..
        a('onclick', onclick) ..
        '>' .. (label or '') .. '</span>'
end


-- Check if transcluded content is just a red link (page doesn't exist).
        -- Background image container (populated by JS)
-- Returns true if content should be hidden.
        slide:tag( 'div' ):addClass( 'bsw-slide-bg' ):done()
local function isRedlink( content )
    if not content or mw.text.trim( content ) == '' then return true end
    -- MW renders missing transclusions as red links with class="new"
    -- Check if content is ONLY a red link and nothing else meaningful
    local stripped = mw.text.trim( content )
    -- If it starts with the page title link pattern for a missing page
    -- (the whole content is just one red link), hide it
    if stripped:match( '^<a[^>]+class="[^"]*new[^"]*"' ) and
      not stripped:match( '</a>%s*%S' ) then
        return true
    end
    return false
end


-- Wrap a card so JS can hide it if content is a red link
        -- Gradient overlay
local function conditionalCard( id, html )
        slide:tag( 'div' ):addClass( 'bsw-slide-overlay' ):done()
    return '<div class="bsw-conditional-card"' .. a('id', id) .. '>' .. html .. '</div>'
end


-- ── hero() ────────────────────────────────────────────────────────
        -- Content
function p.hero( frame )
        local content = slide:tag( 'div' ):addClass( 'bsw-slide-content' )
    local args  = frame.args
    local count = tonumber( args.count ) or 0
    local html  = '<div class="bsw-hero">'


    for i = 1, count do
         -- Badge
         local pfx    = 'slide' .. i .. '_'
         local badge = content:tag( 'div' ):addClass( 'bsw-slide-badge' )
         local art    = mw.text.trim( args[pfx..'article']    or '' )
         local dot  = badge:tag( 'span' ):addClass( 'bsw-slide-badge-dot' )
         local series = mw.text.trim( args[pfx..'series']    or '' )
         if bcolor ~= '' then dot:attr( 'style', 'background:' .. bcolor ) end
        local title  = mw.text.trim( args[pfx..'title']      or art )
         badge:tag( 'span' ):wikitext( series )
         local tlink  = mw.text.trim( args[pfx..'titlelink']  or art )
        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 ''
         -- Title as wikilink
        local dot_sty  = bcolor ~= '' and ' style="background:' .. bcolor .. '"' or ''
        content:tag( 'div' )
        local wl      = wlink( frame, tlink, title )
            :addClass( 'bsw-slide-title' )
            :wikitext( '[[' .. tlink .. '|' .. title .. ']]' )


         html = html ..
         -- Description
            '<div class="bsw-slide' .. active .. '"' .. a('data-article', art) .. '>' ..
        content:tag( 'div' )
            '<div class="bsw-slide-bg"></div>' ..
             :addClass( 'bsw-slide-desc' )
            '<div class="bsw-slide-overlay"></div>' ..
             :wikitext( desc )
            '<div class="bsw-slide-content">' ..
            '<div class="bsw-slide-badge">' ..
             '<span class="bsw-slide-badge-dot"' .. dot_sty .. '></span>' ..
            '<span>' .. e(series) .. '</span>' ..
            '</div>' ..
            '<div class="bsw-slide-title">' .. wl .. '</div>' ..
             '<div class="bsw-slide-desc">' .. e(desc) .. '</div>' ..
            '</div>' ..
            '</div>'
     end
     end


     -- Dots: span[role=button] — sanitizer safe
     -- Dots
     html = html .. '<div class="bsw-hero-dots">'
     local dots = root:tag( 'div' ):addClass( 'bsw-hero-dots' )
     for i = 1, count do
     for i = 1, count do
         local cls = 'bsw-hero-dot' .. (i == 1 and ' bsw-active' or '')
         local dot = dots:tag( 'button' )
        html = html .. spanBtn(nil, cls, 'bswGoSlide(' .. (i-1) .. ')', '')
            :addClass( 'bsw-hero-dot' )
            :attr( 'aria-label', 'Slide ' .. i )
            :wikitext( '' )
        if i == 1 then dot:addClass( 'bsw-active' ) end
     end
     end
    html = html .. '</div>'


     -- Prev/next: span[role=button]
     -- Prev / next buttons
     html = html ..
     local nav = root:tag( 'div' ):addClass( 'bsw-hero-nav' )
        '<div class="bsw-hero-nav">' ..
    nav:tag( 'button' )
         spanBtn('bsw-hero-prev', 'bsw-hero-btn', 'bswPrevSlide()', '&#8249;') ..
         :attr( 'id', 'bsw-hero-prev' )
         spanBtn('bsw-hero-next', 'bsw-hero-btn', 'bswNextSlide()', '&#8250;') ..
        :attr( 'aria-label', 'Previous slide' )
         '</div>' ..
        :wikitext( '‹' )
        '</div>'
    nav:tag( 'button' )
         :attr( 'id', 'bsw-hero-next' )
        :attr( 'aria-label', 'Next slide' )
         :wikitext( '' )


     return html
     return tostring( root )
end
end


-- ── portals() ─────────────────────────────────────────────────────
-- ── portals() ─────────────────────────────────────────────────────
-- Renders the full portals bar.
-- Usage:
-- {{#invoke:BSW/MainPage|portals
-- |portal1_href  = /Portal:Battlestar_Galactica_(TOS)
-- |portal1_stripe= #ef9f27
-- |portal1_icon  = 📺
-- |portal1_name  = Original Series
-- |portal1_sub  = TOS · 1978
-- |count        = 5
-- }}
function p.portals( frame )
function p.portals( frame )
     local args  = frame.args
     local args  = frame.args
     local count = tonumber( args.count ) or 0
     local count = tonumber( args.count ) or 0


     local html =
     local wrap = mw.html.create( 'div' ):addClass( 'bsw-portals' )
        '<div class="bsw-portals">' ..
    wrap:tag( 'div' )
         '<div class="bsw-portals-label">∞ Portals of Battlestar Wiki ∞</div>' ..
         :addClass( 'bsw-portals-label' )
        '<div class="bsw-portals-grid">'
        :wikitext( '∞ Portals of Battlestar Wiki ∞' )
 
    local grid = wrap:tag( 'div' ):addClass( 'bsw-portals-grid' )


     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']   or '#' )
         local href  = args[ pfx .. 'href'   ] or '#'
         local stripe = mw.text.trim( args[pfx..'stripe'] or '' )
         local stripe = args[ pfx .. 'stripe' ] or ''
         local icon  = mw.text.trim( args[pfx..'icon']   or '' )
         local icon  = args[ pfx .. 'icon'   ] or ''
         local name  = mw.text.trim( args[pfx..'name']   or '' )
         local name  = args[ pfx .. 'name'   ] or ''
         local sub    = mw.text.trim( args[pfx..'sub']   or '' )
         local sub    = args[ pfx .. 'sub'   ] or ''


        -- Internal links (/Portal:...) work as wikitext links
         local card = grid:tag( 'a' )
        -- Use span wrapper styled as link block via CSS
             :addClass( 'bsw-portal' )
         local stripe_sty = stripe ~= '' and ' style="background:' .. stripe .. '"' or ''
             :attr( 'href', href )
        local inner =
             '<div class="bsw-portal-stripe"' .. stripe_sty .. '></div>' ..
             '<span class="bsw-portal-icon">' .. icon .. '</span>' ..
            '<span class="bsw-portal-name">' .. e(name) .. '</span>' ..
            '<span class="bsw-portal-sub">'  .. e(sub) .. '</span>'


         -- Use MW internal link syntax — href is a /Wiki_Path
         -- Colour stripe
         -- Strip leading slash to get page title
         local stripeEl = card:tag( 'div' ):addClass( 'bsw-portal-stripe' )
         local page = href:gsub('^/', '')
         if stripe ~= '' then
         local link = frame:preprocess( '[[' .. page .. '|<div class="bsw-portal">' .. inner .. '</div>]]' )
            stripeEl:attr( 'style', 'background:' .. stripe )
         html = html .. link
         end
 
        card:tag( 'span' ):addClass( 'bsw-portal-icon' ):wikitext( icon )
        card:tag( 'span' ):addClass( 'bsw-portal-name' ):wikitext( name )
         card:tag( 'span' ):addClass( 'bsw-portal-sub'  ):wikitext( sub  )
     end
     end


    html = html .. '</div></div>'
     return tostring( wrap )
     return html
end
end


-- ── card header helper ────────────────────────────────────────────
-- ── card() ────────────────────────────────────────────────────────
-- Returns card-hd div; link is rendered as wikitext [url text]
-- Renders a single card with a header bar.
local function cardHd( frame, title, linktext, linkurl )
-- |title    = Card title (plain text)
    local hd = '<div class="bsw-card-hd">' .. e(title)
-- |linktext = Link text (optional)
    if linkurl and linkurl ~= '' then
-- |linkurl = Link URL (optional)
        -- Internal links start with /
-- |id      = Optional id on the card-body div
        local link
-- |content  = Wikitext/HTML body content
        if linkurl:match('^/') or linkurl:match('^#') then
            local page = linkurl:gsub('^/', '')
            if page == '' or page:match('^#') then
                -- anchor-only or hash — can't wikilink, use span
                link = '<span class="bsw-card-hd-link">' .. e(linktext or 'More') .. '</span>'
            else
                link = frame:preprocess( '[[' .. page .. '|' .. (linktext or 'More →') .. ']]' )
            end
        else
            link = xlink( frame, linkurl, linktext or 'More →' )
        end
        hd = hd .. link
    end
    hd = hd .. '</div>'
    return hd
end


-- ── card() ────────────────────────────────────────────────────────
function p.card( frame )
function p.card( frame )
     local args    = frame.args
     local args    = frame.args
     local title  = mw.text.trim( args.title    or '' )
     local title  = args.title    or ''
     local ltext  = mw.text.trim( args.linktext or '' )
     local ltext  = args.linktext or ''
     local lurl    = mw.text.trim( args.linkurl  or '' )
     local lurl    = args.linkurl  or ''
     local content = args.content or ''
    local bodyid  = args.id      or ''
     local content = args.content or ''


     -- Hide card entirely if content resolved to only a red link
     local wrap = mw.html.create( 'div' ):addClass( 'bsw-card' )
    if isRedlink( content ) then return '' end


     return '<div class="bsw-card">' ..
     local hd = wrap:tag( 'div' ):addClass( 'bsw-card-hd' )
        cardHd( frame, title, ltext, lurl ) ..
    hd:wikitext( title )
         '<div class="bsw-card-body">' .. content .. '</div>' ..
    if lurl ~= '' then
        '</div>'
         hd:tag( 'a' ):attr( 'href', lurl ):wikitext( ltext ~= '' and ltext or 'More →' )
end
    end


-- ── featuredloading() ─────────────────────────────────────────────
    local body = wrap:tag( 'div' ):addClass( 'bsw-card-body' )
function p.featuredloading( frame )
     if bodyid ~= '' then body:attr( 'id', bodyid ) end
    -- "Read more" link points to '#' — JS will update href
    body:wikitext( content )
    -- Use a span since we can't href to '#' cleanly in wikitext
     local hd =
        '<div class="bsw-card-hd">Featured article' ..
        '<span class="bsw-card-hd-link" id="bsw-featured-link">Read more →</span>' ..
        '</div>'


     return '<div class="bsw-card">' ..
     return tostring( wrap )
        hd ..
        '<div class="bsw-card-body">' ..
        '<div id="bsw-featured-inner">' ..
        '<div class="bsw-loading">' ..
        '<div class="bsw-spinner"></div>' ..
        'Loading today\'s featured article\226\128\166' ..
        '</div></div></div></div>'
end
end


-- ── photolab() ────────────────────────────────────────────────────
-- ── statbox() ─────────────────────────────────────────────────────
function p.photolab( frame )
-- Single statistic box.
    local args     = frame.args
-- |n     = number (use MW magic word e.g. {{NUMBEROFARTICLES}})
    local content  = mw.text.trim( args.content or '' )
-- |label = label text
    local prev_url = mw.text.trim( args.prev_url  or '' )
 
     local prev_lbl = mw.text.trim( args.prev_label or '‹' )
function p.statbox( frame )
     local next_url = mw.text.trim( args.next_url  or '' )
     local args  = frame.args
     local next_lbl = mw.text.trim( args.next_label or '' )
     local n    = args.n    or ''
     local label = args.label or ''


    -- Caption: use the parent frame's raw (unexpanded) argument to avoid
     local wrap = mw.html.create( 'div' ):addClass( 'bsw-stat' )
    -- double-processing strip markers from nowiki/apostrophe markup.
     wrap:tag( 'div' ):addClass( 'bsw-stat-n' ):wikitext( n )
    -- frame.args values are already expanded by MW before Lua sees them,
    wrap:tag( 'div' ):addClass( 'bsw-stat-l' ):wikitext( label )
    -- which corrupts complex markup. Getting via expandTemplate on the
    -- raw caption transclusion gives a clean single-pass expansion.
     local caption_page = mw.text.trim( args.caption_page or '' )
    local caption = ''
     if caption_page ~= '' then
        caption = frame:preprocess( '{{' .. caption_page .. '}}' )
    else
        -- Fallback: use already-expanded value as-is (may have strip markers
        -- in complex captions, but simple text captions will be fine)
        caption = args.caption or ''
    end


     -- Hide if today's PotD subpage doesn't exist yet
     return tostring( wrap )
    if isRedlink( content ) then return '' end
end


    -- The Potd: subpage stores just the bare filename without "File:" prefix.
-- ── statsblock() ──────────────────────────────────────────────────
    local rendered_content = content
-- Full statistics card including grid + action links.
    if content ~= '' and not content:match( '%[%[' ) and not content:match( '<' ) then
-- Accepts |n1|label1 ... |n6|label6 for the six stat boxes,
        local filename = mw.text.trim( content )
-- plus |link1_url, |link1_text, |link2_url, |link2_text.
        if filename ~= '' then
            rendered_content = frame:preprocess(
                '[[File:' .. filename .. '|center|frameless|400px]]'
            )
        end
    end


     local hd =
function p.statsblock( frame )
        '<div class="bsw-card-hd">\226\136\158 Photo Lab \226\128\148 Picture of the Day' ..
     local args = frame.args
        frame:preprocess( '[[BW:Potd|View project →]]' ) ..
        '</div>'


     local prev_link = prev_url ~= '' and frame:preprocess( '[[' .. prev_url:gsub('^/','') .. '|' .. prev_lbl .. ']]' ) or prev_lbl
     local wrap = mw.html.create( 'div' ):addClass( 'bsw-card' )
    local next_link = next_url ~= '' and frame:preprocess( '[[' .. next_url:gsub('^/','') .. '|' .. next_lbl .. ']]' ) or next_lbl


     local nav =
     -- Header
        '<div class="bsw-photo-nav">' ..
    wrap:tag( 'div' ):addClass( 'bsw-card-hd' ):wikitext( 'Wiki statistics' )
        prev_link ..
        '<span class="bsw-photo-caption">' .. caption .. '</span>' ..
        next_link ..
        '</div>'


     return '<div class="bsw-card">' .. hd .. rendered_content .. nav .. '</div>'
     local body = wrap:tag( 'div' ):addClass( 'bsw-card-body' )
end
    local grid = body:tag( 'div' ):addClass( 'bsw-stats-grid' )


-- ── statsblock() ──────────────────────────────────────────────────
function p.statsblock( frame )
    local args = frame.args
    local grid = '<div class="bsw-stats-grid">'
     for i = 1, 6 do
     for i = 1, 6 do
         local n    = mw.text.trim( args['n'    .. i] or '' )
         local n    = args[ 'n'    .. i ] or ''
         local label = mw.text.trim( args['label' .. i] or '' )
         local label = args[ 'label' .. i ] or ''
         if n ~= '' or label ~= '' then
         if n ~= '' or label ~= '' then
             grid = grid ..
             local box = grid:tag( 'div' ):addClass( 'bsw-stat' )
                '<div class="bsw-stat">' ..
            box:tag( 'div' ):addClass( 'bsw-stat-n' ):wikitext( n )
                '<div class="bsw-stat-n">' .. n .. '</div>' ..
            box:tag( 'div' ):addClass( 'bsw-stat-l' ):wikitext( label )
                '<div class="bsw-stat-l">' .. e(label) .. '</div>' ..
                '</div>'
         end
         end
     end
     end
    grid = grid .. '</div>'


     local links = '<div class="bsw-stat-links">'
    -- Action links
     local links = body:tag( 'div' ):addClass( 'bsw-stat-links' )
     for i = 1, 4 do
     for i = 1, 4 do
         local url  = mw.text.trim( args['link' .. i .. '_url' ] or '' )
         local url  = args[ 'link' .. i .. '_url' ] or ''
         local text = mw.text.trim( args['link' .. i .. '_text'] or '' )
         local text = args[ 'link' .. i .. '_text' ] or ''
         if url ~= '' then
         if url ~= '' then
             local page = url:gsub('^/', '')
             links:tag( 'a' )
            links = links .. frame:preprocess( '[[' .. page .. '|<span class="bsw-stat-link">' .. e(text) .. '</span>]]' )
                :addClass( 'bsw-stat-link' )
                :attr( 'href', url )
                :wikitext( text ~= '' and text or url )
         end
         end
     end
     end
    links = links .. '</div>'


     return
     return tostring( wrap )
        '<div class="bsw-card">' ..
        '<div class="bsw-card-hd">Wiki statistics</div>' ..
        '<div class="bsw-card-body">' .. grid .. links .. '</div>' ..
        '</div>'
end
end


-- ── recenttabs() ──────────────────────────────────────────────────
-- ── recenttabs() ──────────────────────────────────────────────────
-- Renders the wiki-tab bar for Recent Changes.
-- Tabs are wired to bswSetTab() in Common.js.
function p.recenttabs( frame )
function p.recenttabs( frame )
     local tabs = { {'All','all'}, {'EN','en'}, {'DE','de'}, {'Media','media'} }
     local tabs = { 'All', 'EN', 'DE', 'Media' }
     local html = '<div class="bsw-wiki-tabs">'
    local keys  = { 'all', 'en', 'de', 'media' }
     for i, t in ipairs(tabs) do
 
         local cls = 'bsw-wtab' .. (i == 1 and ' bsw-active' or '')
     local wrap = mw.html.create( 'div' ):addClass( 'bsw-wiki-tabs' )
        html = html .. spanBtn(nil, cls, "bswSetTab(this,'" .. t[2] .. "')", t[1])
     for i, label in ipairs( tabs ) do
         local btn = wrap:tag( 'button' )
            :addClass( 'bsw-wtab' )
            :attr( 'onclick', "bswSetTab(this,'" .. keys[i] .. "')" )
            :wikitext( label )
        if i == 1 then btn:addClass( 'bsw-active' ) end
     end
     end
     return html .. '</div>'
 
     return tostring( wrap )
end
end


-- ── interwiki() ───────────────────────────────────────────────────
-- ── interwiki() ───────────────────────────────────────────────────
-- Renders the interwiki bar.
-- |1_flag, |1_label, |1_url ... up to 8 entries.
function p.interwiki( frame )
function p.interwiki( frame )
     local args = frame.args
     local args = frame.args
     local html = '<div class="bsw-interwiki">'
     local wrap = mw.html.create( 'div' ):addClass( 'bsw-interwiki' )
 
     for i = 1, 8 do
     for i = 1, 8 do
         local flag  = mw.text.trim( args[i..'_flag' ] or '' )
         local flag  = args[ i .. '_flag' ] or ''
         local label = mw.text.trim( args[i..'_label'] or '' )
         local label = args[ i .. '_label' ] or ''
         local url  = mw.text.trim( args[i..'_url' ] or '' )
         local url  = args[ i .. '_url'   ] or ''
         if url ~= '' then
         if url ~= '' then
             local link
             local iw = wrap:tag( 'div' ):addClass( 'bsw-iw' )
            if url:match('^/') then
             if flag ~= '' then iw:wikitext( flag .. ' ' ) end
                link = frame:preprocess( '[[' .. url:gsub('^/','') .. '|' .. label .. ']]' )
             iw:tag( 'a' ):attr( 'href', url ):wikitext( label )
             else
                link = xlink( frame, url, label )
            end
            local prefix = flag ~= '' and (flag .. ' ') or ''
             html = html .. '<div class="bsw-iw">' .. prefix .. link .. '</div>'
         end
         end
     end
     end
     return html .. '</div>'
 
     return tostring( wrap )
end
 
-- ── featuredloading() ─────────────────────────────────────────────
-- Renders the featured article card shell with loading state.
-- JS replaces the inner content after fetching.
 
function p.featuredloading( frame )
    local wrap = mw.html.create( 'div' ):addClass( 'bsw-card' )
 
    local hd = wrap:tag( 'div' ):addClass( 'bsw-card-hd' )
    hd:wikitext( 'Featured article' )
    hd:tag( 'a' )
        :attr( 'id', 'bsw-featured-link' )
        :attr( 'href', '#' )
        :wikitext( 'Read more →' )
 
    local body = wrap:tag( 'div' ):addClass( 'bsw-card-body' )
    local inner = body:tag( 'div' ):attr( 'id', 'bsw-featured-inner' )
    local loading = inner:tag( 'div' ):addClass( 'bsw-loading' )
    loading:tag( 'div' ):addClass( 'bsw-spinner' ):wikitext( '' )
    loading:wikitext( 'Loading today\'s featured article…' )
 
    return tostring( wrap )
end
 
-- ── photolab() ────────────────────────────────────────────────────
-- Renders the Photo Lab card shell.
-- Content (the actual PotD image) is passed as |content=
-- via a nested template call on the main page.
-- |prev_label, |prev_url, |caption, |next_label, |next_url
 
function p.photolab( frame )
    local args    = frame.args
    local content  = args.content  or ''
    local prev_url = args.prev_url  or '#'
    local prev_lbl = args.prev_label or '‹'
    local caption  = args.caption  or ''
    local next_url = args.next_url  or '#'
    local next_lbl = args.next_label or '›'
 
    local wrap = mw.html.create( 'div' ):addClass( 'bsw-card' )
 
    local hd = wrap:tag( 'div' ):addClass( 'bsw-card-hd' )
    hd:wikitext( '∞ Photo Lab — Picture of the Day' )
    hd:tag( 'a' ):attr( 'href', '/BW:Potd' ):wikitext( 'View project →' )
 
    -- PotD image transcluded as wikitext
    wrap:wikitext( content )
 
    -- Nav row
    local nav = wrap:tag( 'div' ):addClass( 'bsw-photo-nav' )
    nav:tag( 'a' ):attr( 'href', prev_url ):wikitext( prev_lbl )
    nav:tag( 'span' ):addClass( 'bsw-photo-caption' ):wikitext( caption )
    nav:tag( 'a' ):attr( 'href', next_url ):wikitext( next_lbl )
 
    return tostring( wrap )
end
end


-- ── tagline() ─────────────────────────────────────────────────────
-- ── tagline() ─────────────────────────────────────────────────────
function p.tagline( frame )
function p.tagline( frame )
     local inner = frame:preprocess(
     local wrap = mw.html.create( 'div' ):addClass( 'bsw-tagline' )
    wrap:wikitext(
         "The only original and legitimate '''Battlestar Wiki''' " ..
         "The only original and legitimate '''Battlestar Wiki''' " ..
         "\226\128\148 the free-as-in-beer, non-corporate, open-content encyclopedia " ..
         "the free-as-in-beer, non-corporate, open-content encyclopedia " ..
         "on all things ''Battlestar Galactica''.<br>" ..
         "on all things ''Battlestar Galactica''.<br>" ..
         "\226\136\158 ''Accept neither subpar substitutes nor subpar clones.'' \226\136\158"
         "''Accept neither subpar substitutes nor subpar clones.'' "
     )
     )
     return '<div class="bsw-tagline">' .. inner .. '</div>'
     return tostring( wrap )
end
 
-- ── sisterprojects() ──────────────────────────────────────────────
-- Dedicated card for sister wiki links.
-- Uses numbered params: |1_label, |1_url, |2_label, |2_url ...
-- External URLs rendered via frame:preprocess [url label] syntax.
function p.sisterprojects( frame )
    local args = frame.args
    local body = '<div style="display:flex;flex-direction:column;gap:0.375rem">'
    for i = 1, 8 do
        local label = mw.text.trim( args[i .. '_label'] or '' )
        local url  = mw.text.trim( args[i .. '_url'  ] or '' )
        if url ~= '' and label ~= '' then
            -- Wrap in span.bsw-sister-link for styling
            -- Use preprocess so [url text] becomes a real hyperlink
            local link = frame:preprocess( '[' .. url .. ' ' .. label .. ']' )
            body = body .. '<div class="bsw-sister-link">' .. link .. '</div>'
        end
    end
    body = body .. '</div>'
 
    return
        '<div class="bsw-card">' ..
        '<div class="bsw-card-hd">Sister projects</div>' ..
        '<div class="bsw-card-body">' .. body .. '</div>' ..
        '</div>'
end
end


To edit this page, please enter the words that appear below in the box (more info):

Refresh
Cancel Editing help (opens in new window)

  [] · [[]] · [[|]] · {{}} · · “” ‘’ «» ‹› „“ ‚‘ · ~ | ° &nbsp; · ± × ÷ ² ³ ½ · §
     [[Category:]] · [[:File:]] · [[Special:MyLanguage/]] · <code></code> · <nowiki></nowiki> <code><nowiki></nowiki></code> · <syntaxhighlight></syntaxhighlight> · <includeonly></includeonly> · <noinclude></noinclude> · #REDIRECT[[]] · <translate></translate> · <languages/> · {{#translation:}} · <tvar|></> · {{DEFAULTSORT:}} · <categorytree></categorytree> · <div style="clear:both;"></div> <s></s>


Your changes will be visible immediately.
  • For testing, please use the sandbox instead.
  • On talk pages, please sign your comment by typing four tildes (~~~~).

Page included on this page: