Module:Area

From The Observatory

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

-- Module:Area (orchestrator)
-- Wires Query → IO → Render for area portal pages.
local data = require('Module:AreaData')
local q = require('Module:Area/Query')
local io = require('Module:Area/IO')
local r = require('Module:Area/Render')
local imageConfig = mw.loadData('Module:ImageConfig')
local p = {}

-- Main area portal renderer
function p.areas(frame)
    local page = (mw and mw.title and mw.title.getCurrentTitle and mw.title.getCurrentTitle().baseText) or 'Animals'
    local parentFrame = frame and frame.getParent and frame:getParent()
    local template = (parentFrame and parentFrame.args) or (frame and frame.args) or {}
    local html = mw.html.create()

    local banner = template['Area banner background'] or ''
    local bannerpath = io.resolvePhotoUrl(frame, banner, imageConfig.defaultCoverImage, nil)
    local description = template['Area description'] or ''
    local card_image = template['Area card image'] or imageConfig.defaultCoverImage
    local featured = template['Area featured articles'] or ''
    local featuredList = data.splitString(featured, ';')

    -- Set SMW properties (pcall'd — SMW hiccup won't crash the page)
    if mw.smw and mw.smw.set then
        pcall(mw.smw.set, {
            'Has description=' .. description,
            'Has parent page=All Areas',
            'Area card image=' .. card_image,
            'Area banner background=' .. banner
        })
    end

    -- Widgets (notitle, nopagemenupanel)
    local notitle = io.getWidget(frame, 'notitle')
    local nopagemenupanel = io.getWidget(frame, 'nopagemenupanel')

    -- Query for conditional tabs (guides, news, feeds, events)
    local guides = q.areaGuides(page) or {}
    local news = q.areaNews(page) or {}
    local feeds = q.areaFeeds(page) or {}
    local events = q.areaEvents(page) or {}

    local tabOpts = {
        guides = #guides > 0,
        news = #news > 0,
        feeds = #feeds > 0,
        events = #events > 0,
        page = page,
    }
    html:node(r.areaTabs(tabOpts))

    local tab_content = html:tag('div'):attr('id', 'area-tab-content'):addClass('tab-content')
    if banner ~= '' then
        local bEl = r.areaBanner(bannerpath)
        if bEl then tab_content:node(bEl) end
    end
    tab_content:tag('h1'):addClass('mb-3'):wikitext(page)

    local articles = q.areaArticles(page, 500)
    local cards = {}

    for _, rawArt in ipairs(articles or {}) do
        local art = data.normalizeArticle(rawArt)
        local isFeatured = data.hasValue(featuredList, art.Article)
        if not isFeatured then
            art._imagepath = io.resolvePhotoUrl(frame, art['Cover image'], card_image, '800')
            local subtitle = art.Teaser or ''
            local notes = art['Notes by the editor'] or subtitle
            if subtitle ~= '' and subtitle ~= notes then
                art._teaserHtml = string.format('<div class="interface mb-2">%s</div><div>%s</div>', subtitle, notes)
            else
                art._teaserHtml = string.format('<div>%s</div>', notes)
            end
            if art['Text author'] and art['Text author'] ~= '' then
                art._authorsHtml = io.formredlinks(frame, 'Author', art['Text author'], 'By ')
            end
            if art.Source and art.Source ~= '' then
                art._sourcesHtml = io.formredlinks(frame, 'Organization', art.Source, '')
            end
            if art['Display date'] and art['Display date'] ~= '' then
                art._formattedDate = io.formatDate(frame, art['Display date'], 'F j, Y')
            end
            table.insert(cards, r.articleCard(art, false))
        end
    end

    local wall = r.cardWall(cards)
    local sectionDiv = tab_content:tag('div'):attr('id', 'observatory-articles'):addClass('tab-pane active border-0 p-0')
    sectionDiv:node(wall)

    -- Authors sidebar
    local rawAuthors = q.areaAuthors(page, 50)
    local authorCards = {}
    for _, rawAuth in ipairs(rawAuthors or {}) do
        local auth = {
            title = rawAuth.title or '',
            name = rawAuth.name or rawAuth.title or '',
            _imagepath = io.resolvePhotoUrl(frame, rawAuth.image or 'File:Johndoe.png', 'Observatory_Logo_for_Writers_bg.png', nil)
        }
        table.insert(authorCards, r.authorCard(auth, false))
    end
    sectionDiv:node(r.authorSidebar(authorCards))

    return tostring(html)
end

-- Classics portal renderer
function p.classics(frame)
    local page = 'Classics'
    local parentFrame = frame and frame.getParent and frame:getParent()
    local template = (parentFrame and parentFrame.args) or (frame and frame.args) or {}
    local html = mw.html.create()

    local banner = template['Area banner background'] or ''
    local bannerpath = io.resolvePhotoUrl(frame, banner, imageConfig.defaultCoverImage, nil)
    local card_image = template['Area card image'] or imageConfig.defaultCoverImage

    html:node(r.areaTabs({}))
    local tab_content = html:tag('div'):attr('id', 'area-tab-content'):addClass('tab-content')
    if banner ~= '' then
        local bEl = r.areaBanner(bannerpath)
        if bEl then tab_content:node(bEl) end
    end
    tab_content:tag('h1'):addClass('mb-3'):wikitext(page)

    local articles = q.classicsArticles(500)
    local cards = {}

    for _, rawArt in ipairs(articles or {}) do
        local art = data.normalizeArticle(rawArt)
        art._imagepath = io.resolvePhotoUrl(frame, art['Cover image'], card_image, '800')
        local subtitle = art.Teaser or ''
        local notes = art['Notes by the editor'] or subtitle
        if subtitle ~= '' and subtitle ~= notes then
            art._teaserHtml = string.format('<div class="interface mb-2">%s</div><div>%s</div>', subtitle, notes)
        else
            art._teaserHtml = string.format('<div>%s</div>', notes)
        end
        if art['Text author'] and art['Text author'] ~= '' then
            art._authorsHtml = io.formredlinks(frame, 'Author', art['Text author'], 'By ')
        end
        if art['Display date'] and art['Display date'] ~= '' then
            art._formattedDate = io.formatDate(frame, art['Display date'], 'Y')
        end
        table.insert(cards, r.articleCard(art, true))
    end

    local wall = r.cardWall(cards)
    local sectionDiv = tab_content:tag('div'):attr('id', 'observatory-articles'):addClass('tab-pane active border-0 p-0')
    sectionDiv:node(wall)

    return tostring(html)
end

p.main = p.areas

return p