Module:More in area

From The Observatory
Jump to navigation Jump to search

Documentation for this module may be created at Module:More in area/doc

local p = {}

-- Helper function to check if a value exists in a table
local function isInTable(value, table)
    for _, v in pairs(table) do
        if v == value then
            return true
        end
    end
    return false
end

-- Helper function to split a string by a delimiter
local function splitString(input, delimiter)
    if input ~= nil and input ~= '' then
        local result = {}
        for value in string.gmatch(input, "([^" .. delimiter .. "]+)") do
            table.insert(result, value)
        end
        return result
    else
        return
    end
end

-- Helper function for nice enumeration
local function enumeration(source_table, prefix)
    -- Create a copy of the source table to avoid modifying the original
    local temp_table = {}
    for i = 1, #source_table do
        temp_table[i] = source_table[i]
    end

    -- Handle formatting based on the number of elements
    local formatted_list
    if #temp_table > 1 then
        local last_item = temp_table[#temp_table] -- Get the last item
        table.remove(temp_table) -- Remove the last item from the temporary table
        formatted_list = table.concat(temp_table, ", ") .. " and " .. last_item
    else
        formatted_list = temp_table[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 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 = {}

    if type(items) == 'table' then
        for _, item in ipairs(items) 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
    else
        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
    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 date formatted
local function format_date(frame, timestamp, date_format)
    local formattedDate = frame:preprocess(
                              "{{#time:" .. date_format .. "|" .. timestamp ..
                                  "}}")
    return formattedDate
end

-- Helper function: Check if a value exists in a table (set-like structure)
local function isInSet(value, set)
    return set[value] == true
end

-- Helper function: Create a <div> tag with class and content
local function createDiv(parent, className, content)
    return parent:tag('div')
        :addClass(className)
        :wikitext(content)
end

function p.main(frame)
	
    local param  = frame:getParent().args
    local area   = param[1] or ''
    local limit  = param[2] or 10
    local offset = param[3] or 10

	local featuredSet = {}
	local featured = mw.smw.ask {
		'[[' .. area .. ']]',
		'?Area featured list#-=',
		'mainlabel=-'
	} or {}
	for _, t in ipairs(featured[1]) do
    	featuredSet[t] = true
	end
	
    local articles = mw.smw.ask {
        '[[:+]][[Category:Articles]][[Area::' .. area ..
            ']][[Modification date::+]]', 'sort=Modification date',
        'order=desc', 'mainlabel=-', '?#-=Article', '?Article headline',
        '?Cover image', '?Subtitle', '?Source', '?Notes by the editor',
        '?Teaser', '?Modification date', '?Display date', '?Is featured',
        '?Is collaborative research', '?Has map label', '?Section',
        '?Text author', '?Audio file', '?Video source', 'valuesep=;',
        'limit=' .. limit, 'offset=' .. offset, 'searchlabel='
    } or {}

    local wall = mw.html.create()

    for _, article in ipairs(articles) do
			
			local headline = article['Article headline'] or ''
			if not featuredSet[headline] then
			
            -- Getting image URL
            local file = article['Cover image'] or ''
            local filename, imagepath
            if file ~= '' then
                filename = file:match("^File:(.+)$") or
                               card_image:match("^File:(.+)$")
                imagepath = frame:preprocess('{{filepath:' .. filename .. '}}')
            end

            -- Horizontal card layout in Classics
            local classics = ''
            if page == 'Classics' then
                classics = 'flex-row card-img-left'
            else
                classics = 'flex-column card-img-top'
            end

            -- CARD
            
            local card = wall:tag('div'):addClass(
                             'card card-info rounded border border-primary')
                             :addClass(classics)
                             :attr('data-headline', headline)

            -- BADGES
            local labels = card:tag('div'):attr('id', 'area-item-labels')
                               :addClass(
                                   'interface small order-3 d-flex flex-column')
                               :css({['right'] = '0'})
            if article['Has map label'] == 'true' then
                labels:tag('span'):wikitext('Has map')
            end
            if article['Is collaborative research'] == 'true' then
                labels:tag('span'):wikitext('Collaborative Research')
            end
            if article['Section'] ~= 'Observatory' then
                labels:tag('span'):wikitext(section)
            end

            -- CARD IMAGE
            if imagepath ~= '' then
                card:tag('div'):addClass('card-image rounded-top'):attr(
                    'data-bg', imagepath)
            end
            -- CARD BODY
            local cardbody = card:tag('div'):addClass('card-body')
            -- HEADLINE
            cardbody:tag('div'):addClass('card-title h4 font-weight-bold')
                :wikitext(string.format('[[%s|%s]]', article['Article'],
                                        article['Article headline'])):css({
                    ['font-size'] = '150%'
                })
            -- CREDENTIALS
            local credentials = cardbody:tag('div')
            -- AUTHORS
            local authors = article['Text author'] or ''
            if authors ~= '' then
                credentials:tag('div'):addClass('interface mt-2'):wikitext(
                    formredlinks(frame, 'Author', authors, 'By '))
            end
            -- SOURCES
            local sources = article['Source'] or ''
            if sources ~= '' then
                credentials:tag('div'):addClass('interface'):wikitext(
                    formredlinks(frame, 'Organization', sources, ''))
            end
            -- DATE
            local display_date = article['Display date'] or ''
            local formatted_display_date = ''
            local preferred_ns_format = ''

            if frame:preprocess('{{NAMESPACENUMBER:' .. article['Article'] ..
                                    '}}') == '3220' then
                preferred_ns_format = 'Y'
            else
                preferred_ns_format = 'F j, Y'
            end

            if display_date ~= '' then
                formatted_display_date =
                    format_date(frame, display_date, preferred_ns_format)

                credentials:tag('div'):addClass('interface'):wikitext(
                    formatted_display_date)
            end
        end
    end

    return wall
end

function p.datatable(frame)

    local param  = frame:getParent().args
    local area   = param[1] or ''

    local articles = mw.smw.ask {
        '[[Category:Articles]]' .. 
        '[[Area::' .. area .. ']]' ..
        '[[Modification date::+]]', 
        'mainlabel=-', 
        '?#-=article', 
        '?Article headline=headline',
        '?Subtitle=subtitle', 
        '?Source=source', 
        '?Notes by the editor=notes',
        '?Teaser=teaser', 
        '?Modification date#-F[Y-m-d]=modified', 
        '?Display date#-F[Y-m-d]=displaydate', 
        '?Is featured=isfeatured',
        '?Is collaborative research=iscollab', 
        '?Has map label=hasmap', 
        '?Section=section',
        '?Text author=author', 
        '?Audio file=audio', 
        '?Video source=video', 
        '?Tag=tag',
        'valuesep=;',
        'limit=500', 
        'offset=0', 
        'searchlabel='
    } or {}

    local datatable = mw.html.create()
    
    local articlepath = datatable:tag('div')
    	:attr('id', 'inpagenav')
    	:addClass( 'interface d-flex align-items-center justify-content-between' )
    	:addClass( 'font-weight-bold text-uppercase d-print-none screenonly noprint' )

		articlepath:tag('h2')
    		:attr('id', 'observatory-path')
    		:addClass( 'd-print-none noprint' )
    		:wikitext(area)
    		:done()
    	
    	articlepath:tag('div')
    		:addClass('order-2 btn btn-light font-weight-bold')
    		:attr('title', 'Explore ' .. area )
    		:wikitext('[[' .. area .. '|Explore]]')

    local areafilter = datatable:tag('table')
    	:attr('id', 'area-filter')

-- Main loop
for i, article in pairs(articles) do

    -- Create row and cell
    local row = areafilter:tag('tr')
    local cell = row:tag('td')
        :attr('data-sort', article.displaydate or article.modified)

    -- Create card structure
    local card = cell:tag('div')
        :addClass('card rounded border-0 flex-column flex-md-row shadow')

    local cardbody = card:tag('div')
        :addClass('card-body')

    -- Define sets for classification
    local hiddenClasses = {
        tag = true,
        modified = true,
        headline = true
    }

    local badges = {
        isfeatured = true,
        iscollab = true,
        hasmap = true,
        section = true,
        audio = true,
        video = true
    }

    local links = {
        author = true,
        source = true
    }

    -- Default display title
    local displaytitle = article.headline or article.article

	-- Handle display date format
	local displaydate = article.displaydate or ''
	local formatted_display_date = ''
    local preferred_ns_format = ''

	if displaydate ~= '' then
    	if frame:preprocess('{{NAMESPACENUMBER:' .. article.article ..'}}') == '3220' then
			preferred_ns_format = 'Y'
		else
    		preferred_ns_format = 'F j, Y'
		end
		formatted_display_date = format_date(frame, displaydate, preferred_ns_format)
    end
    
    -- Iterate over article properties
    for key, property in pairs(article) do
        -- Determine visibility class
        local class = ''
        if isInSet(key, hiddenClasses) or (key == 'section' and tostring(property) == 'Observatory') then
            class = 'd-none'
        elseif isInSet(key, badges) then
        	class = 'badge'
        end

        -- Handle table properties
        if type(property) == 'table' then
            local values = {}
            for _, value in ipairs(property) do
                if isInSet(key, links) then
                    value = string.format('[[%s]]', value)
                end
                table.insert(values, value)
            end
            local credentials = enumeration(values, '')
            if key == 'author' then
            	credentials = enumeration(values, 'By ')
            end
            createDiv(cardbody, key .. ' ' .. class, credentials)

        -- Handle non-table properties
        else
            local printout = tostring(property)

            -- Format links
            if isInSet(key, links) then
                printout = string.format('[[%s]]', printout)
            end

            -- Handle badges
            if isInSet(key, badges) then
                if tostring(property) ~= 'false' then
                	local label = ''
                		if key == 'isfeatured' then
                			label = 'Featured'
                		elseif key == 'iscollab' then
                			label= 'Collaborative research'
                		elseif key == 'hasmap' then
                			label= 'Has map'
                		elseif key == 'section' then
    						label = tostring(property)
                		elseif key == 'audio' then
							label = 'Has audio'
						elseif key == 'video' then
        					label = 'Has video'
        				end
                   createDiv(cardbody, key .. ' ' .. class, label)
                end
            -- Handle article links
            elseif key == 'article' then
                createDiv(cardbody, key .. ' ' .. class, string.format('[[%s|%s]]', printout, displaytitle))
            -- Handle display date
            elseif key == 'displaydate' then
            	createDiv(cardbody, key .. ' ' .. class, formatted_display_date )
            -- Handle other properties
            else
            	local by = ''
            	if key == 'author' then 
            		by = 'By '
            	end
                createDiv(cardbody, key .. ' ' .. class, by .. printout)
            end
        end
    end
    createDiv(cardbody, 'badge-container d-flex', '')
end

    return datatable
	
end

function p.test()
	local featuredSet = {}
	local featured = mw.smw.ask {
		'[[Education]]',
		'?Area featured list#-=',
		'mainlabel=-'
	} or {}
	if #featured > 0 then 
		for _, t in ipairs(featured[1]) do
    		featuredSet[t] = true
		end
	end
    return featuredSet
end

return p