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

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.
Revision as of 16:03, 11 April 2026 by Joe Beaudoin Jr. (talk | contribs) (Created page with "-- Module:BSW/MainPage -- Generates all main page HTML components via mw.html, -- bypassing the wikitext parser entirely. -- Usage: {{#invoke:BSW/MainPage|functionName|param=value|...}} local p = {} -- ── Shared helpers ──────────────────────────────────────────────── -- Safe attribute setter — skips nil/empty values local function attr( el, name, value ) if value...")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

Documentation for this module may be created at Module:BSW/MainPage/doc

-- Module:BSW/MainPage
-- Generates all main page HTML components via mw.html,
-- bypassing the wikitext parser entirely.
-- Usage: {{#invoke:BSW/MainPage|functionName|param=value|...}}

local p = {}

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

-- Safe attribute setter — skips nil/empty values
local function attr( el, name, value )
    if value and value ~= '' then
        el:attr( name, value )
    end
    return el
end

-- ── hero() ────────────────────────────────────────────────────────
-- Renders the entire hero slideshow: slides + dots + nav buttons.
-- Called ONCE from the main page with all slide data packed as
-- 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' )

    for i = 1, count do
        local pfx     = 'slide' .. i .. '_'
        local article = args[ pfx .. 'article'   ] or ''
        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 ''

        local slide = root:tag( 'div' )
            :addClass( 'bsw-slide' )
            :attr( 'data-article', article )

        if i == 1 then slide:addClass( 'bsw-active' ) end

        -- Background image container (populated by JS)
        slide:tag( 'div' ):addClass( 'bsw-slide-bg' ):done()

        -- Gradient overlay
        slide:tag( 'div' ):addClass( 'bsw-slide-overlay' ):done()

        -- Content
        local content = slide:tag( 'div' ):addClass( 'bsw-slide-content' )

        -- Badge
        local badge = content:tag( 'div' ):addClass( 'bsw-slide-badge' )
        local dot   = badge:tag( 'span' ):addClass( 'bsw-slide-badge-dot' )
        if bcolor ~= '' then dot:attr( 'style', 'background:' .. bcolor ) end
        badge:tag( 'span' ):wikitext( series )

        -- Title as wikilink
        content:tag( 'div' )
            :addClass( 'bsw-slide-title' )
            :wikitext( '[[' .. tlink .. '|' .. title .. ']]' )

        -- Description
        content:tag( 'div' )
            :addClass( 'bsw-slide-desc' )
            :wikitext( desc )
    end

    -- Dots
    local dots = root:tag( 'div' ):addClass( 'bsw-hero-dots' )
    for i = 1, count do
        local dot = dots:tag( 'button' )
            :addClass( 'bsw-hero-dot' )
            :attr( 'aria-label', 'Slide ' .. i )
            :wikitext( '' )
        if i == 1 then dot:addClass( 'bsw-active' ) end
    end

    -- Prev / next buttons
    local nav = root:tag( 'div' ):addClass( 'bsw-hero-nav' )
    nav:tag( 'button' )
        :attr( 'id', 'bsw-hero-prev' )
        :attr( 'aria-label', 'Previous slide' )
        :wikitext( '‹' )
    nav:tag( 'button' )
        :attr( 'id', 'bsw-hero-next' )
        :attr( 'aria-label', 'Next slide' )
        :wikitext( '›' )

    return tostring( root )
end

-- ── 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 )
    local args  = frame.args
    local count = tonumber( args.count ) or 0

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

    local grid = wrap:tag( 'div' ):addClass( 'bsw-portals-grid' )

    for i = 1, count do
        local pfx    = 'portal' .. i .. '_'
        local href   = args[ pfx .. 'href'   ] or '#'
        local stripe = args[ pfx .. 'stripe' ] or ''
        local icon   = args[ pfx .. 'icon'   ] or ''
        local name   = args[ pfx .. 'name'   ] or ''
        local sub    = args[ pfx .. 'sub'    ] or ''

        local card = grid:tag( 'a' )
            :addClass( 'bsw-portal' )
            :attr( 'href', href )

        -- Colour stripe
        local stripeEl = card:tag( 'div' ):addClass( 'bsw-portal-stripe' )
        if stripe ~= '' then
            stripeEl:attr( 'style', 'background:' .. stripe )
        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

    return tostring( wrap )
end

-- ── card() ────────────────────────────────────────────────────────
-- Renders a single card with a header bar.
-- |title    = Card title (plain text)
-- |linktext = Link text (optional)
-- |linkurl  = Link URL (optional)
-- |id       = Optional id on the card-body div
-- |content  = Wikitext/HTML body content

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

    local wrap = mw.html.create( 'div' ):addClass( 'bsw-card' )

    local hd = wrap:tag( 'div' ):addClass( 'bsw-card-hd' )
    hd:wikitext( title )
    if lurl ~= '' then
        hd:tag( 'a' ):attr( 'href', lurl ):wikitext( ltext ~= '' and ltext or 'More →' )
    end

    local body = wrap:tag( 'div' ):addClass( 'bsw-card-body' )
    if bodyid ~= '' then body:attr( 'id', bodyid ) end
    body:wikitext( content )

    return tostring( wrap )
end

-- ── statbox() ─────────────────────────────────────────────────────
-- Single statistic box.
-- |n     = number (use MW magic word e.g. {{NUMBEROFARTICLES}})
-- |label = label text

function p.statbox( frame )
    local args  = frame.args
    local n     = args.n     or ''
    local label = args.label or ''

    local wrap = mw.html.create( 'div' ):addClass( 'bsw-stat' )
    wrap:tag( 'div' ):addClass( 'bsw-stat-n' ):wikitext( n )
    wrap:tag( 'div' ):addClass( 'bsw-stat-l' ):wikitext( label )

    return tostring( wrap )
end

-- ── statsblock() ──────────────────────────────────────────────────
-- Full statistics card including grid + action links.
-- Accepts |n1|label1 ... |n6|label6 for the six stat boxes,
-- plus |link1_url, |link1_text, |link2_url, |link2_text.

function p.statsblock( frame )
    local args = frame.args

    local wrap = mw.html.create( 'div' ):addClass( 'bsw-card' )

    -- Header
    wrap:tag( 'div' ):addClass( 'bsw-card-hd' ):wikitext( 'Wiki statistics' )

    local body = wrap:tag( 'div' ):addClass( 'bsw-card-body' )
    local grid = body:tag( 'div' ):addClass( 'bsw-stats-grid' )

    for i = 1, 6 do
        local n     = args[ 'n'     .. i ] or ''
        local label = args[ 'label' .. i ] or ''
        if n ~= '' or label ~= '' then
            local box = grid:tag( 'div' ):addClass( 'bsw-stat' )
            box:tag( 'div' ):addClass( 'bsw-stat-n' ):wikitext( n )
            box:tag( 'div' ):addClass( 'bsw-stat-l' ):wikitext( label )
        end
    end

    -- Action links
    local links = body:tag( 'div' ):addClass( 'bsw-stat-links' )
    for i = 1, 4 do
        local url  = args[ 'link' .. i .. '_url'  ] or ''
        local text = args[ 'link' .. i .. '_text' ] or ''
        if url ~= '' then
            links:tag( 'a' )
                :addClass( 'bsw-stat-link' )
                :attr( 'href', url )
                :wikitext( text ~= '' and text or url )
        end
    end

    return tostring( wrap )
end

-- ── recenttabs() ──────────────────────────────────────────────────
-- Renders the wiki-tab bar for Recent Changes.
-- Tabs are wired to bswSetTab() in Common.js.

function p.recenttabs( frame )
    local tabs  = { 'All', 'EN', 'DE', 'Media' }
    local keys  = { 'all', 'en', 'de', 'media' }

    local wrap = mw.html.create( 'div' ):addClass( 'bsw-wiki-tabs' )
    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

    return tostring( wrap )
end

-- ── interwiki() ───────────────────────────────────────────────────
-- Renders the interwiki bar.
-- |1_flag, |1_label, |1_url ... up to 8 entries.

function p.interwiki( frame )
    local args = frame.args
    local wrap = mw.html.create( 'div' ):addClass( 'bsw-interwiki' )

    for i = 1, 8 do
        local flag  = args[ i .. '_flag'  ] or ''
        local label = args[ i .. '_label' ] or ''
        local url   = args[ i .. '_url'   ] or ''
        if url ~= '' then
            local iw = wrap:tag( 'div' ):addClass( 'bsw-iw' )
            if flag ~= '' then iw:wikitext( flag .. ' ' ) end
            iw:tag( 'a' ):attr( 'href', url ):wikitext( label )
        end
    end

    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

-- ── tagline() ─────────────────────────────────────────────────────
function p.tagline( frame )
    local wrap = mw.html.create( 'div' ):addClass( 'bsw-tagline' )
    wrap:wikitext(
        "The only original and legitimate '''Battlestar Wiki''' " ..
        "— the free-as-in-beer, non-corporate, open-content encyclopedia " ..
        "on all things ''Battlestar Galactica''.<br>" ..
        "∞ ''Accept neither subpar substitutes nor subpar clones.'' ∞"
    )
    return tostring( wrap )
end

return p