Module:Article item

From The Observatory

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

local p = {}

-- Utility function to convert boolean-like values to numbers
local function booleantonumber(value)
    if value == 'false' or value == false or value == nil or value == 0 or value == '' then
        return 0
    else
        return 1
    end
end

-- Helper function to format a label as a span element
local function format_label(label)
    return '<span class="d-inline-block mb-2">' .. label .. '</span>'
end

-- Generate labels based on input arguments
local function add_labels(args, article, frame)
    local labels = {}

    if booleantonumber(args['Is collaborative research']) == 1 then
        table.insert(labels, format_label('Collaborative Research'))
    end

    if booleantonumber(args['Has map label']) == 1 then
        table.insert(labels, format_label('Has Map'))
    end

    if frame:preprocess('{{NAMESPACENUMBER:' .. article .. '}}') == '3220' then
        table.insert(labels, format_label('Classics'))
    end

    return table.concat(labels, '')
end

-- Helper function to create a form red link (Recipient)
local function create_formredlink(frame, form, page)
	local page_notsub = frame:callParserFunction(
		'#explode',
		page,
		'#',
		'0'
	)
    return frame:callParserFunction(
    	'#formredlink',
        'form=' .. form,
        'link text=' .. page_notsub,
        'existing page link text=' .. page_notsub,
        'target=' .. page
    )
end

-- Helper function to format a list of items as formredlinks
local function formredlinks(frame, form, items, prefix)
    
    local formatted_items = {}

    for item in items:gmatch("[^;]+") do
        item = mw.text.trim(item) -- Trim spaces around the name
        local formatted_item = create_formredlink(frame, form, item)
        table.insert(formatted_items, formatted_item)
    end

    if #formatted_items > 1 then
        local last_item = table.remove(formatted_items) -- Remove the last item
        formatted_list = table.concat(formatted_items, ", ") .. " and " .. last_item
    else
        formatted_list = formatted_items[1] or "" -- Return the single item or an empty string
    end

    -- Add prefix if provided
    if prefix and prefix ~= "" then
        formatted_list = prefix .. formatted_list
    end

    return formatted_list
    
end

-- Helper function to get page language
local function getlang(frame, article)
	local langcode = frame:callParserFunction(
		'#show',
		article,
		'?Language code'
	)
	local formatted_lang = frame:callParserFunction(
		'#language',
		langcode
	)
	return formatted_lang
end

-- Helper date formatter
local function format_date(frame, timestamp, date_format)
	local formattedDate = frame:preprocess("{{#time:" .. date_format .. "|" .. timestamp .. "}}")
    return formattedDate
end


-- Main function to construct the article card
function p.main(frame)

    local args = frame:getParent().args

    -- Retrieve arguments
    local article = args['Article'] or ''
    local teaser = args['Teaser'] or ''
    local editor_notes = args['Notes by the editor'] or ''
    local is_published = booleantonumber(args['Is published'])
    local member_of = frame:preprocess('{{#ask: [[Article in path::' .. article .. ']]|link=none}}')
    local show_author = args['Show author'] or ''
    local author = args['Author'] or {}
    local area = args['Area'] or ''
    local source = args['Source'] or {}
    local display_date = args['Display date'] or ''

    local out = {}

    -- Determine visibility and additional classes
    local guide_member = member_of ~= '' and 'guide-member' or ''

    -- Construct card components
    local card_heading = string.format(
        '<div class="article-item %s" style="display: %s"><div class="article-info"><div class="h5 interface">[[%s]]</div>',
        guide_member, 'flex', article
    )

    local card_labels = string.format(
        '<div class="labels small text-muted interface d-flex flex-wrap">%s</div>',
        add_labels(args, article, frame)
    )

    local card_text = ''
    if teaser ~= '' then
        card_text = '<div class="mb-2">' .. teaser .. '</div>'
    elseif editor_notes ~= '' then
        card_text = '<div class="mb-2">' .. editor_notes .. '</div>'
    end
    
    local separate = ' | '

	-- Handle Display date
    local formatted_display_date = ''
    local preferred_ns_format = ''
    
    if frame:preprocess('{{NAMESPACENUMBER:' .. article .. '}}') == '3220' then
        preferred_ns_format = 'Y'
	else
		preferred_ns_format = 'F j, Y'
    end
    
    if display_date ~= '' then
    	formatted_display_date = string.format( ' | %s',
    		format_date(frame, display_date, preferred_ns_format)
    	)
    end
    
    local join = 'In '
    local author_placeholder = ''
	if #author > 0 then 
    	author_placeholder = formredlinks(frame, 'Author', author, 'By ') 
    	join = ' in '
	end

	local sources_placeholder = ''
	if #source > 0 then 
    	sources_placeholder = formredlinks(frame, 'Organization', source, ' | ') 
    end

	local guides_placeholder = ''
	if #member_of > 0 then 
    	guides_placeholder = formredlinks(frame, 'Guide', member_of, ' | ') 
	end

    local card_footer = string.format(
    	'<div class="area-item-observed interface small text-muted">%s %s [[%s]] %s %s %s %s %s</div>',
    	author_placeholder, 
    	join, 
    	area, 
		sources_placeholder,
    	separate, 
    	getlang(frame, article),
    	formatted_display_date,
    	guides_placeholder
    )
    
    -- Combine all parts into the output table
    table.insert(out, card_heading)
    table.insert(out, card_labels)
    table.insert(out, card_text)
	table.insert(out, card_footer)
    table.insert(out, '</div></div>') -- Closing the card div

    -- Return the complete HTML as a single string
    return table.concat(out, '\n')
end

return p