Module:Main page
From The Museum of Human Achievement
Documentation for this module may be created at Module:Main page/doc
local p = {}
-- ########### IS VALID URL ###########
local function isValidUrl(target)
return type(target) == "string" and target:match('^https?://[%w%-%._~:/%?#%[%]@!$&\'()*+,;=]+$') ~= nil
end
-- ########### DATE FORMAT ###########
local function formatDate(timestamp, dateformat)
local formattedDate = os.date(dateformat, timestamp)
return formattedDate
end
-- ########### GET MONTH NAME ###########
local function getMonthName(monthNumber)
local months = {
"January", "February", "March", "April", "May", "June",
"July", "August", "September", "October", "November", "December"
}
return months[monthNumber] or "Invalid month"
end
-- ########### FORMAT HOUR ###########
local function formatAMPM(hour)
-- Convert 24-hour format to 12-hour format with AM/PM
local ampm = hour < 12 and "AM" or "PM"
local hour12 = hour % 12
if hour12 == 0 then
hour12 = 12 -- Midnight or noon should be 12
end
return tostring(hour12), ampm
end
-- ########### CREATE TIMESTAMP TABLE ###########
local function getDateTime(timestamp)
-- If no timestamp is provided, use the current time
if not timestamp then
timestamp = os.time()
end
-- Get the date components as a table
local dateTable = os.date('*t', timestamp)
return dateTable
end
-- ########### FORMAT TIMESTAMP ###########
local function formatTimestamp(timestampTable, format)
-- Default format if none is provided
if not format or format == '' then
format = "%s %d, %d" -- Default format: "Full Month Name Day, Year"
end
-- Extract the month, day, and year
local month = timestampTable.month
local day = timestampTable.day
local year = timestampTable.year
local hours = timestampTable.hour
local minutes = timestampTable.min
local seconds = timestampTable.sec
local fullmonth = getMonthName(month)
-- Convert hour to 12-hour format with AM/PM
local hour12, ampm = formatAMPM(hours)
-- Replace placeholders in the format string with actual values
local formattedDate = format:gsub("%%month", string.format("%02d", month))
:gsub("%%fullmonth", fullmonth)
:gsub("%%day", string.format("%02d", day))
:gsub("%%year", tostring(year))
:gsub("%%hour", tostring(hours)) -- 24-hour format
:gsub("%%minute", string.format("%02d", minutes)) -- Minutes with leading zero
:gsub("%%h12", hour12) -- 12-hour format
:gsub("%%ampm", ampm) -- AM/PM
return formattedDate
end
-- ########### CHECK EMPTY TABLE ###########
local function isTableEmpty(tbl)
-- Check if the table has any numeric keys
if next(tbl) == nil then
return true -- Table is empty
end
return false -- Table is not empty
end
-- ########### BUTTON ###########
local function button(frame, value, action, class )
local button = frame:callParserFunction('#widget',
'submit',
'value=' .. value,
'class=' .. class,
'action=' .. action
)
return button
end
-- ########### BUTTON LINK ###########
local function buttonlink(frame, value, action, class, width, buttonclass )
local btnclass = buttonclass or ''
local html = mw.html.create()
local button = frame:preprocess(string.format('[%s <span class="%s">%s</span>]'
, action
, class
, value
))
local autowidth
if width then
autowidth = width
else
autowidth = 'auto'
end
html:tag('div')
:addClass('buttonlink moha-btn ' .. btnclass .. ' mt-4 mb-0 text-center w-' .. autowidth )
:wikitext(button)
return tostring(html)
end
-- ########### BANNER ###########
function p.banner(frame)
local params = frame:getParent().args
local id = params['id'] or 'banner'
local class = params['class'] or 'banner'
local image = params['image'] or ''
local height = params['height'] or 'auto'
local bgcolor = params['background-color'] or '#A8DDBF'
local content = params['content'] or ''
if image ~= '' then
image = frame:preprocess('{{filepath:' .. image .. '}}')
end
local html = mw.html.create()
html:tag('div')
:addClass(class .. ' mx-md-n5')
:attr({
['id'] = id,
['data-bg'] = image
})
:css({
['background-color'] = bgcolor,
['height'] = height
})
:wikitext(content)
:tag('div')
:addClass('overlap')
:attr({
['id'] = 'banner-tagline'
})
:css({
['background-color'] = 'var(--primary)'
})
:wikitext(frame:preprocess('{{int:moha-fancy-tagline}}'))
return html
end
-- ########### VISION ###########
function p.vision(frame)
local params = frame:getParent().args
local id = params['id'] or 'vision'
local class = params['class'] or 'vision'
local image = params['image'] or ''
local bgcolor = params['background-color'] or '#A8DDBF'
local color = params['color'] or 'var(--primary)'
local button1target = params['button1target'] or 'Main Page'
local button1text = params['button1text'] or 'LEARN MORE'
local html = mw.html.create()
local vision = html:tag('div')
:addClass(class .. ' flex-column flex-md-row')
:attr({
['id'] = id
})
:css({
['background-color'] = bgcolor,
['color'] = color
})
if image ~= '' then
vision:tag('div')
:addClass('image-wrapper')
:wikitext('[[File:' .. image .. '|link=]]')
:done()
end
local message = vision:tag('div')
:addClass('py-3 px-4 mx-3 px-md-5')
:wikitext(frame:preprocess('{{int:moha-fancy-vision}}'))
local target1 = frame:preprocess('{{fullurl:' .. button1target .. '}}')
local button1 = buttonlink(frame, button1text, target1, '', 'auto', 'moha-btn-green' )
message:tag('div')
:addClass('mt-4 mb-5 mb-lg-0')
:wikitext(button1)
return html
end
-- ########### ADVENTURE ###########
function p.adventure(frame)
local params = frame.args
local id = params['id'] or 'adventure'
local class = params['class'] or 'adventure'
local image = params['image'] or ''
local bgcolor = params['background-color'] or 'var(--primary)'
local color = params['color'] or '#FFFFFF'
local button1target = params['button1target'] or 'Main Page'
local button1text = params['button1text'] or 'LEARN ABOUT MoHA'
local button2target = params['button2target'] or 'Main Page'
local button2text = params['button2text'] or 'ATTEND AN EVENT'
local button3target = params['button3target'] or 'Main Page'
local button3text = params['button3text'] or 'SUPPORT MoHA WORK'
local button4target = params['button4target'] or 'Main Page'
local button4text = params['button4text'] or 'GET INVOLVED'
local html = mw.html.create()
local vision = html:tag('div')
:addClass(class)
:attr({
['id'] = id
})
:css({
['background-color'] = bgcolor,
['color'] = color
})
local message = vision:tag('div')
:addClass('col py-3 px-4 p-md-5 order-1 order-md-0')
:attr('id', 'adventure-cta')
:wikitext(frame:preprocess('{{int:moha-fancy-adventure}}'))
local target1 = frame:preprocess('{{fullurl:' .. button1target .. '}}')
local target2 = frame:preprocess('{{fullurl:' .. button2target .. '}}')
local target3 = frame:preprocess('{{fullurl:' .. button3target .. '}}')
local target4 = frame:preprocess('{{fullurl:' .. button4target .. '}}')
local button1 = buttonlink(frame, button1text, target1, 'moha-btn-inverted' )
local button2 = buttonlink(frame, button2text, target2, 'moha-btn-inverted' )
local button3 = buttonlink(frame, button3text, target3, 'moha-btn-inverted' )
local button4 = buttonlink(frame, button4text, target4, 'moha-btn-inverted' )
message:tag('div')
:attr('id', 'button-block')
:addClass('text-center text-md-left d-flex flex-column')
:wikitext(button1)
:wikitext(button2)
:wikitext(button3)
:wikitext(button4)
vision:tag('div')
:addClass('image-wrapper order-0 order-md-1 col')
:done()
return html
end
-- ########### PROGRAMS ###########
function p.heading(frame)
local params = frame.args
local heading = params[1] or 'Section Heading'
html = mw.html.create()
html:tag('div')
:addClass('moha-heading')
:wikitext(heading)
return html
end
-- ########### SCROLLER CONTROLS ###########
function p.scroller(frame)
local params = frame.args
local container = params[1] or '#programs-wall'
local goprev = params[2] or 'left'
local gonext = params[3] or 'right'
html = mw.html.create()
local scroller = html:tag('div')
:addClass('moha-scroll ' .. container)
if gonext ~= 'null' then
scroller:tag('div')
:addClass('moha-control')
:attr('data-target', container)
:wikitext('<i class="icono-arrow1-' .. gonext .. '"></i>')
:done()
end
if goprev ~= 'null' then
scroller:tag('div')
:addClass('moha-control')
:attr('data-target', container)
:wikitext('<i class="icono-arrow1-' .. goprev .. '"></i>')
:done()
end
return html
end
-- ########### CARD ###########
function p.card(frame)
local params = frame:getParent().args
local image = params['image'] or 'Moha.wiki logo.png'
local label = params['label'] or 'MoHA'
local content= params['content'] or ''
local target = params['target'] or 'Main Page'
local buttontext = params['buttontext'] or 'LEARN MORE'
local class = params['class'] or 'moha-card'
local imagepath = frame:preprocess('{{filepath:' .. image .. '}}')
target = frame:preprocess('{{fullurl:' .. target .. '}}')
html = mw.html.create()
local card = html:tag('div')
:addClass('card ' .. class)
local cardimage = card:tag('div')
:addClass('card-img-top')
:tag('div')
:addClass('image')
:attr('data-bg', imagepath)
:tag('div')
:tag('div')
:addClass('overlap-label')
:wikitext(label)
:done()
local cardbody = card:tag('div')
:addClass('card-body')
:tag('div')
:addClass('card-text')
:wikitext(content)
:tag('div')
:addClass('mt-auto')
:wikitext(buttonlink(frame, buttontext, target, 'moha-btn-inverted' , '100'))
:done()
return html
end
-- ########### GET PROGRAMS ###########
function p.getprograms(frame)
local data = mw.smw.ask {
'[[Category:Current Programs]]',
'mainlabel=-',
'?#-=program',
'?Program image#-=image',
'?Program short description=description',
'named args=yes',
'limit=7',
'order=random',
'searchlabel='
} or {}
html = mw.html.create()
for _, card in ipairs(data) do
local program = card['program'] or 'MoHA'
local image = card['image'] or 'Moha.wiki logo.png'
local description = card['description'] or ''
local target = frame:preprocess('{{fullurl:' .. program .. '}}')
local imagepath = frame:preprocess('{{filepath:{{PAGENAME:' .. image .. '}}}}')
local card = html:tag('div')
:addClass('card moha-card')
local cardimage = card:tag('div')
:addClass('card-img-top')
:tag('div')
:addClass('image')
:attr('data-bg', imagepath)
:tag('div')
:tag('div')
:addClass('overlap-label')
:wikitext(program)
:done()
local cardbody = card:tag('div')
:addClass('card-body')
:tag('div')
:addClass('card-text')
:tag('div')
:wikitext(description)
:done()
:tag('div')
:addClass('mt-auto')
:wikitext(buttonlink(frame, 'LEARN MORE', target, 'moha-btn-inverted', '100'))
:done()
end
return html
end
-- ########### MORE PROGRAMS ###########
function p.moreprograms(frame)
local params = frame:getParent().args
local id = params['id'] or 'moreprograms'
local class = params['class'] or 'border-0'
local title = params['title'] or ''
local cta = params['cta'] or ''
local target = params['target'] or 'Main Page'
local page = frame:preprocess('{{fullurl:' .. target .. '}}')
local html = mw.html.create()
html:tag('div')
:attr('id', id)
:addClass(class)
:tag('div')
:addClass('h2')
:wikitext(title)
:done()
:tag('div')
:addClass('continue')
:wikitext(string.format('[%s <span class="cta">%s</span><i class="icono-arrow1-left"></i>]'
, page
, cta
))
return html
end
-- ########### COMMUNITY ###########
function p.community(frame)
local params = frame.args
local id = params['id'] or 'community'
local class = params['class'] or 'community'
local image = params['image'] or 'MoHA-Fancy-community.png'
local bgcolor = params['background-color'] or 'var(--primary)'
local color = params['color'] or '#FFFFFF'
local title = params['title'] or 'Card Title'
local content = params['content'] or 'Card content'
local buttontext = params['buttontext'] or 'Click Me'
local target = params['target'] or 'Main Page'
local page = frame:preprocess('{{fullurl:' .. target .. '}}')
image = frame:preprocess('{{filepath:' .. image .. '}}')
local html = mw.html.create()
local community = html:tag('div')
:addClass(class)
:attr({
['id'] = id
})
:css({
['background-color'] = bgcolor,
['color'] = color
})
local message = community:tag('div')
:addClass('w-100 w-md-50 py-3 order-1 order-md-0 card-body')
:attr('id', 'community-cta')
:tag('div')
:addClass('h2')
:wikitext(title)
:done()
:tag('div')
:addClass('my-3 my-md-5 card-text')
:wikitext(content)
:done()
message:tag('div')
:addClass('text-center text-md-left d-flex flex-column')
:wikitext(buttonlink(frame, buttontext, page, 'moha-btn-secondary'))
:done()
community:tag('div')
:addClass('w-100 w-md-50 image-wrapper order-0 order-md-1')
:attr('data-bg', image)
:done()
return html
end
-- ########### EVENTS ###########
function p.getevents(frame)
-- local params = frame.args
local today = formatTimestamp(getDateTime(), '%year-%month-%day' )
local conditions =
'[[Category:Events]]' ..
'[[Is public::true]]' ..
'[[Date Start::>' .. today .. ']]' ..
'[[Modification date::+]]' ..
' OR ' ..
'[[Category:Events]]' ..
'[[Is public::true]]' ..
'[[Date Start::<' .. today .. ']]' ..
'[[Date End::>>' .. today .. ']]' ..
'[[Modification date::+]]'
local data = mw.smw.ask {
conditions,
'mainlabel=-',
'?#-=event',
'?Event image#-=image',
'?Event image caption=caption',
'?Date Start#-F[U]=dstart',
'?Date End#-F[U]=dend',
'?Event format=format',
'?Event location=location',
'?Event admission type=admtype',
'?Event admission price#-=price',
'?Event admission price sliding low#=low',
'?Event admission price sliding high#=high',
'?Associated Program#-=program',
'named args=yes',
'limit=20',
'order=random',
'searchlabel='
} or {}
local html = mw.html.create()
for _, card in ipairs(data) do
local event = card['event'] or ''
local image = card['image'] or 'Moha.wiki logo.png'
local caption = card['caption'] or ''
local program = card['program'] or ''
local dstart = card['dstart'] or ''
local dend = card['dend'] or ''
local admtype = card['admtype'] or ''
local location = card['location'] or ''
local price = card['price'] or ''
local low = card['low'] or ''
local high = card['high'] or ''
local programs = {}
for item in string.gmatch(program, "([^;]+)") do
table.insert(programs, string.format('<div class="overlap-label">%s</div>', mw.text.trim(item))) -- Trim spaces for clean output
end
local labels = ''
if #programs > 0 then
labels = table.concat(programs, '')
end
local target = frame:preprocess('{{fullurl:' .. event .. '}}')
local imagepath = frame:preprocess('{{filepath:{{PAGENAME:' .. image .. '}}}}')
local printdate, printdate_long, printdate_short, printtime_start, printtime_end, printtime, printmin_start, printmin_end, datesep, isCurrent, currentevent, pricerange, printprice
-- Price formatting
if low ~= '' and high ~= '' then
pricerange = low .. '-' .. high
else
pricerange = low .. high
end
if admtype == "Free" or admtype == '' or price == '' or price == '0 USD' then
printprice = 'Free'
else
printprice = (admtype == "Set Price") and '' or admtype .. ' '
printprice = printprice .. price .. pricerange
end
-- Timestamps formatting
local startdate = getDateTime(dstart) or ''
local enddate = getDateTime(dend) or ''
if formatTimestamp(startdate, '%minute') == '00' then
printmin_start = ''
else
printmin_start = ':' .. formatTimestamp(startdate, '%minute')
end
if formatTimestamp(enddate, '%minute') == '00' then
printmin_end = ''
else
printmin_end = ':' .. formatTimestamp(enddate, '%minute')
end
printtime_start = formatTimestamp(startdate, '%h12' .. printmin_start .. '%ampm')
printtime_end = formatTimestamp(enddate, '%h12' .. printmin_end .. '%ampm')
if printtime_end == printtime_start then
printtime = ''
else
printtime = ' | ' .. printtime_start .. '-' .. printtime_end
end
if isTableEmpty(startdate) or isTableEmpty(enddate) then
datesep = ''
else
datesep = '-'
end
printdate_long = formatTimestamp(startdate, '%fullmonth %day, %year') .. printtime
printdate_short = formatTimestamp(startdate, '%month.%day.%year') .. datesep .. formatTimestamp(enddate, '%month.%day.%year')
printdate = (formatTimestamp(startdate,'%year%month%day') == formatTimestamp(enddate,'%year%month%day')) and printdate_long or printdate_short
-- Formatted location (if present)
if location ~= '' then
location = string.format(' | %s', location)
end
-- Special class for the current event cards
isCurrent = frame:callParserFunction('#ask',
'[[' .. event .. ']]' ..
'[[Category:Events]]' ..
'[[Is public::true]]' ..
'[[Date Start::<' .. today .. ']]' ..
'[[Date End::>>' .. today .. ']]' ..
'[[Modification date::+]]'
) or ''
currentevent = (isCurrent ~= '') and 'current' or ''
local card = html:tag('div')
:addClass('card moha-card ' .. currentevent )
local cardimage = card:tag('div')
:addClass('card-img-top')
:tag('div')
:addClass('image')
:attr('data-bg', imagepath)
:tag('div')
:wikitext(labels)
local cardbody = card:tag('div')
:addClass('card-body')
:tag('div')
:addClass('card-title')
:wikitext(string.format('[[%s]]', event))
:done()
:tag('div')
:addClass('card-text')
:tag('div')
:addClass('datetime')
:wikitext(printdate)
:done()
:tag('div')
:addClass('admission')
:wikitext(printprice .. location)
:done()
:tag('div')
:addClass('mt-auto')
:wikitext(buttonlink(frame, 'LEARN MORE', target, 'moha-btn-inverted', '100'))
:done()
end
return html
end
-- ########### BANNER ###########
function p.footerbanner(frame)
local params = frame:getParent().args
local id = params['id'] or 'footerbanner'
local class = params['class'] or 'footerbanner'
local image = params['image'] or ''
local height = params['height'] or 'auto'
local bgcolor = params['background-color'] or '#A8DDBF'
local content = params['content'] or ''
if image ~= '' then
image = frame:preprocess('{{filepath:' .. image .. '}}')
end
local html = mw.html.create()
html:tag('div')
:addClass(class .. ' mx-md-n5')
:attr({
['id'] = id
})
:css({
['background-color'] = bgcolor,
['height'] = height
})
:wikitext(content)
:tag('div')
:addClass('footeroverlap d-flex flex-column flex-lg-row ml-auto justify-content-between')
:attr({
['id'] = 'banner-bottom-tagline'
})
:css({
['background-color'] = 'var(--primary)'
})
:tag('div')
:addClass('bottom-tagline')
:wikitext(frame:preprocess('{{int:moha-fancy-bottom-tagline}}'))
:done()
:tag('div')
:addClass('bottom-details')
:wikitext(frame:preprocess('{{int:moha-fancy-bottom-details}}'))
return html
end
function p.horizontal(frame)
local params = frame:getParent().args
local title = params['title'] or ''
local content = params['content'] or ''
local image = params['image'] or ''
local bgcolor = params['bgcolor'] or 'var(--moha-green)'
local fgcolor = params['fgcolor'] or 'var(--white)'
local linkcolor = params['linkcolor'] or 'var(--white)'
local highlight = params['highlight-text'] or ''
local hlbgcolor = params['highlight-bgcolor'] or 'var(--primary)'
local hlfgcolor = params['highlight-fgcolor'] or 'var(--white)'
local target = params['button-target'] or ''
local label = params['button-text'] or ''
local btnfgcolor = params['button-fgcolor'] or ''
local button = ''
if target and target ~='' and isValidUrl(target) then
button = string.format('[%s <span style="color:%s">%s</span>]'
, target
, btnfgcolor
, label
)
end
if target and target ~='' and not isValidUrl(target) then
button = string.format('[[%s|<span style="color:%s">%s</span>]]'
, target
, btnfgcolor
, label
)
end
if target == '' and label ~= '' then
button = string.format('<span style="color:%s">%s</span>'
, btnfgcolor
, label
)
end
local filename, fileurl
if image ~= '' then
filename = frame:preprocess('{{PAGENAME:' .. image .. '}}')
filenameDecoded = mw.text.decode(frame:preprocess('{{PAGENAME:' .. filename .. '}}'))
fileurl = frame:preprocess('{{filepath:' .. filenameDecoded .. '}}')
end
-- Assemble
local html = mw.html.create()
local card = html:tag('div')
:addClass('d-flex flex-column flex-lg-row moha-card-horizontal mb-4 mb-lg-0')
:css({
['background-color'] = bgcolor,
['color'] = fgcolor,
})
local cardbody = card:tag('div')
:addClass('d-flex flex-column p-5 moha-card-body order-1 order-lg-0 mt-lg-5')
:css({
['gap'] = '1rem 0'
})
local cardtitle = cardbody:tag('div')
:addClass('h4 moha-card-title')
:wikitext(title)
local cardtext = cardbody:tag('div')
:addClass('moha-card-text')
:wikitext(content)
local cardfooter = cardbody:tag('div')
:addClass('d-flex flex-column flex-md-row moha-card-footer')
if highlight ~= '' then
local cardhighlight = cardfooter:tag('div')
:addClass('mb-3')
:css('max-width', 'fit-content')
local message = cardhighlight:tag('div')
:addClass('moha-highlight')
:wikitext(highlight)
end
if button ~= '' then
local cardbutton = cardfooter:tag('div')
:addClass('moha-btn transparent border-white m-0 ml-auto my-lg-5')
:wikitext(button)
end
local cardimage = card:tag('div')
:addClass('d-block moha-card-img order-0 order-lg-1')
:attr('data-bg', fileurl)
return html
end
return p