Module:Women in Red event/sandbox
require('strict')
local p = {}
local data = mw.loadJsonData('Wikipedia:WikiProject Women in Red/events')
local currentDate = os.date('*t')
local lang = mw.getContentLanguage()
local frame = mw.getCurrentFrame()
local args = frame.args
local yesno = require('Module:Yesno')
local format_date = function(_date)
local month = _date.month and _date.month-1 or 0
return _date.year*12+month
end
local currentMonth = format_date(currentDate)
local monthName = function(month, abbrev)
local monthcode = month<10 and ('0'..tostring(month)) or tostring(month)
local timestamp = '2024' .. monthcode .. '01000000'
local _format = abbrev and 'M' or 'F'
return lang:formatDate(_format, timestamp)
end
local _findLatest = function()
local _max = 1
for n, _ in pairs(data) do
local val = tonumber(n) or 0
if val<1000 and val>_max then
_max = val
end
end
return _max
end
p.findLatest = function()
return _findLatest() + (tonumber(args.add) or 0)
end
local value = function(event, field, default)
local data = data[tonumber(event)]
if data and data[field] then
return data[field]
else
return default
end
end
local makeCat = function(cat, key, test)
local key2 = key and not test and ('|' .. key) or ''
return '' .. (test and ':' or '') .. 'Category:' .. cat .. key2 .. ''
end
local collapse = function(title, text)
return frame:expandTemplate{title = 'Collapsed top', args = {
bg = 'transparent',
width = '80%',
[1] = title
}} .. text .. '
end
p.main = function()
local ret = value(args[1], args[2], args[3] or '')
if args.hash=='no' and type(ret)=='string' then
ret = ret:gsub('#', '')
end
if ret and type(ret)=='string' and ret:sub(1,1)=='#' then -- prevent # character from starting a list
ret = mw.text.nowiki(ret)
end
return ret
end
local getDates = function(event, endDefaultsToStart)
local _start = value(event, 'start') or {
month = value(event, 'month'),
year = value(event, 'year')
}
local _end = value(event, 'end')
if not _end and endDefaultsToStart then
_end = _start
end
return _start, _end
end
local _date = function(event, sentence, abbrev)
local _start, _end = getDates(event)
local ret = ''
if sentence then
ret = _end and 'from ' or 'in '
end
ret = ret .. (_start.month and monthName(_start.month, abbrev) or '')
if not _end or _start.year~=_end.year then
ret = ret .. (_start.month and ' ' or '') .. tostring(_start.year)
end
if _end then
local to
if sentence then
to = ' to '
else
if _start.year==_end.year then
to = '–' -- en dash
else
to = ' – ' -- spaced en dash
end
end
ret = ret .. to .. monthName(_end.month, abbrev) .. ' ' .. tostring(_end.year)
end
local sortkey = os.time{
year = _start.year or 0,
month = _start.month or 1,
day = _start.month and 2 or 1
}
return ret, sortkey
end
p.date = function(frame)
local event = tonumber(args[1])
if data[event] then
local date, _ = _date(
event,
yesno(frame.args.sentence or 'false'),
yesno(frame.args.abbrev or 'false')
)
return date
end
end
local _name = function(meetup)
local series = value(meetup, 'series')
local name = value(meetup, 'name')
local out = series or ''
if series and name then
out = out .. ': '
end
out = out .. (name or '')
return out
end
p.name = function()
return mw.text.nowiki(_name(args[1]))
end
p.nested = function()
-- Function to produce year for nested display in project banner
local year = value(args[1], 'year')
if not year and value(args[1], 'start') and value(args[1], 'start').year==value(args[1], 'end').year then
year = value(args[1], 'start').year
end
return _name(args[1]) .. (year and (' (' .. year .. ')') or '')
end
p.text = function()
local meetup = args[1]
return '[[Wikipedia:WikiProject Women in Red/Meetup/' .. meetup
.. '|' .. _name(meetup)
.. ' ' .. value(meetup, 'type', 'edit-a-thon')
.. ']] '
.. _date(meetup, true, false)
end
local link = function(n, name)
local label = name and _name(n) or n
return '' .. label .. ''
end
local buildTable = function(option, show, _sort)
local meetupCell = function(n)
local background = value(n, 'background') and ('#' .. value(n, 'background')) or nil
return mw.html.create('th')
:css('background-color', background)
:css('text-align', 'center')
:wikitext(n)
end
local total = 0
option.meetup = true
option.name = true
option.date = true
local header = mw.html.create('tr')
local cols = 0
for _, col in ipairs({'meetup', 'icon', 'series', 'name', 'date', 'image', 'template', 'wrapper', 'category'}) do
if option[col] then
cols = cols + 1
local col = mw.html.create('th'):wikitext(lang:ucfirst(col))
header:node(col)
end
end
local sorted_data = {}
for n, _ in pairs(data) do
table.insert(sorted_data, n)
end
if _sort then
table.sort(sorted_data, _sort)
end
local showDate = function(meetup)
local dates, sortkey = _date(meetup, false, true)
return mw.html.create('td'):attr('data-sort-value', sortkey):wikitext(dates):done()
end
local rows = {}
for _, n in ipairs(sorted_data) do
local event = data[n]
if not show or show(n, event) then
local row = mw.html.create('tr'):node(meetupCell(n))
if option.icon then
local icon = event.icon and 'File:' .. event.icon .. ''
local cell = mw.html.create('td'):wikitext(icon)
row:node(cell)
end
if option.series then
local series = event.series and '' .. event.series .. '' or
local cell = mw.html.create('td'):wikitext(series)
row:node(cell)
end
local name = option.series and event.name or _name(n)
local link = '' .. name .. ''
local name_cell = mw.html.create('td'):wikitext(link)
row:node(name_cell)
:node(showDate(n))
if option.image then
local pic = event.image and 'File:' .. event.image .. ''
local cell = mw.html.create('td'):wikitext(pic)
row:node(cell)
end
if option.template then
local template = frame:extensionTag('code', '{{WIR|' .. n .. '}}')
local cell = mw.html.create('td'):css('text-align', 'center'):wikitext(template)
row:node(cell)
end
if option.wrapper then
local wrapper = '{{WIR-' .. n .. '}}'
local cell = mw.html.create('td'):css('text-align', 'center'):wikitext(wrapper)
row:node(cell)
end
if option.category then
local cat = 'WikiProject Women in Red meetup ' .. n .. ' articles'
local url = mw.uri.fullUrl(':Category:' .. cat, {
action = 'edit',
preload = 'Template:WIR category/preload',
summary = 'Create meetup category for Women in Red'
})
local pagesInCat = mw.site.stats.pagesInCategory(cat)
total = total + pagesInCat
local catText = '' .. pagesInCat .. ''
if pagesInCat==0 and not mw.title.new(':Category:' .. cat).exists then
catText = catText .. ' ([' .. tostring(url) .. ' create])'
end
local cell = mw.html.create('td'):css('text-align', 'center'):wikitext(catText)
row:node(cell)
end
table.insert(rows, tostring(row))
end
end
local footer
if option.category then
footer = mw.html.create('tr')
:tag('th'):attr('colspan', cols-1):wikitext('Total'):done()
:tag('th'):css('text-align', 'center'):wikitext(tostring(total)):done()
end
return mw.html.create('table')
:addClass('wikitable'):addClass('sortable')
:node(header)
:node(table.concat(rows))
:node(footer)
end
p.list = function()
local first = tonumber(args.first) or 1
local last = tonumber(args.last) or 9999
if args.latest then
last = _findLatest()
first = last - tonumber(args.latest) + 1
end
local option = {}
for key, value in pairs(args) do
option[key] = yesno(value)
end
local order = function(m, n)
local start1, _ = getDates(m)
start1 = format_date(start1)
local start2, _ = getDates(n)
start2 = format_date(start2)
local earlier = start1 if start1==start2 then earlier = m end return earlier end return buildTable( option, function(n, _) return n>=first and n<=last end, order ) end local eventStatus = function(event, _date) --function to decide whether an event is upcoming, current, ongoing, recently completed or past local month = currentMonth if _date then month = format_date(_date) end local _start = format_date(event['start'] or { year = event.year, month = event.month or 1 }) local _end = format_date(event['end'] or { year = event.year, month = event.month or 12 }) if _end return 'past' elseif _end==month-1 then -- event ended on previous month return 'recent' elseif _start==month then -- event has started on current month return 'current' elseif _start==month+1 then -- event starts after current month return 'upcoming' elseif _start return 'ongoing' end end local searchEvents = function(_date) local events = {current = {}, recent = {}, ongoing = {}, upcoming = {}, past = {}} for n, event in pairs(data) do local status = eventStatus(event, _date) if status then table.insert(events[status], n) end end table.sort(events.past, function(a, b) return a > b end) return events end p.current_events = function(frame) local _date = currentDate if frame.args[1] then _date = getDates(frame.args[1]) elseif frame.args.year and frame.args.year~='' then _date = { year = tonumber(frame.args.year), month = tonumber(frame.args.month) or 1 } end local mClickableButton = require('Module:Clickable button').main local button = function(text, colour) return mClickableButton{ [1] = text, color = 'white', style = colour and ('background-color: #' .. colour) } end local links = function(text, events, extra) local list = {} if events[1] or extra then for _, n in ipairs(events) do table.insert(list, button( value(n, 'background') ) .. ' ') end if extra then table.insert(list, button(extra)) end return mw.html.create('tr') :tag('td'):wikitext(text .. ': '):done() :tag('td'):wikitext(table.concat(list)):done() end end local events = searchEvents(_date) local ret = mw.html.create('table') :node(links(frame.args.recent or 'Recently completed', events.recent)) :node(links(frame.args.current or monthName(_date.month) .. ' ' .. _date.year, events.current)) :node(links(frame.args.ongoing or 'Ongoing initiatives', events.ongoing)) :node(links(frame.args.upcoming or 'Upcoming events', events.upcoming, 'Ideas')) return tostring(ret) end p.events = function() -- function to produce automated list of events on Wikipedia:WikiProject Women in Red/Events local ret = mw.html.create('div') local ec = searchEvents() local links = function(class) if not ec[class] or not args[class] then return nil end ret:tag('h3'):wikitext(args[class]):done() if ec[class][1] then ret:tag('ul') for _, n in ipairs(ec[class]) do local date2 = _date(n, false, false) if date2==tostring(tonumber(date2)) then date2 = date2 .. ' year-long ' .. value(n, 'type', 'editathon') end ret:tag('li'):wikitext(date2 .. ': ' .. link(n, true)):done() end else ret:tag('p'):css('font-style', 'italic'):wikitext('None to display.'):done() end end links('ongoing') links('current') links('recent') links('upcoming') links('past') return tostring(ret) end p.event_list = function() -- function to produce bulleted list of events for Template:Women in Red navigation local ec = searchEvents() local class = args[1] if not ec[class] then return nil end local ret = mw.html.create('ul') for _, n in ipairs(ec[class]) do ret:tag('li'):wikitext(link(n, true)):done() end return tostring(ret) end p.event_list_by_year = function() -- function to produce bulleted list of past events for Template:Women in Red navigation local ret = mw.html.create('ul') local year = args[1] and tonumber(args[1]) or 2023 local events = {} for n, event in ipairs(data) do if (event.year==year or (event.start and event.start.year==year)) and eventStatus(event)=='past' then local type = event.type or 'edit-a-thon' if not events[type] then events[type] = {} end local month = value(n, 'month', 0) if not events[type][month] then events[type][month] = {} end table.insert(events[type][month], n) end end for type, eventsOfType in pairs(events) do ret:wikitext(lang:uc(type)..'S: ') for _, n in ipairs(eventsOfType[0] or {}) do ret:tag('li'):wikitext(link(n, true)):done() end for month = 1, 12 do if eventsOfType[month] then local sublist = mw.html.create('ul') for _, n in ipairs(eventsOfType[month]) do sublist:tag('li'):wikitext(link(n, true)):done() end ret:tag('li'):wikitext(monthName(month, true) .. ': '):node(sublist):done() end end end return tostring(ret) end local meetupHeader = function(n, test) local text = 'This category contains talk pages of articles which were created or improved' .. ' during the [[Wikipedia:WikiProject Women in Red/Meetup/' .. n .. '|' .. _name(n) .. ' ' .. value(n, 'type', 'edit-a-thon') .. ']]' .. ' hosted by the Women in Red project ' .. _date(n, true, false) .. '.' local cats = {makeCat('WikiProject Women in Red articles by meetup', n, test)} local _start, _end = getDates(n, true) for year = _start.year, _end.year do table.insert(cats, makeCat('WikiProject Women in Red ' .. year .. ' articles', n, test)) end if value(n, 'series') then table.insert(cats, makeCat('WikiProject Women in Red ' .. value(n, 'series'):gsub('#', '') .. ' articles', n, test)) end local empty = mw.site.stats.pagesInCategory('WikiProject Women in Red meetup ' .. n .. ' articles')==0 local future = false if _start.year>currentDate.year then future = true elseif _start.year==currentDate.year then if _start.month and _start.month>=currentDate.month then future = true end end return { text = text, cat = cats, image_left = value(n, 'icon', 'Women in Red logo.svg'), image_right = value(n, 'image') and 'File:' .. value(n, 'image') .. '', empty = empty and future, nav = true } end local yearHeader = function(year, test) local inYear = function(_, event) if event.start and event['end'] then return event.start.year<=year and event['end'].year>=year else return event.year==year end end local text = 'This category contains talk pages of articles which were created or improved in ' .. year .. ' as part of the Women in Red project.' .. collapse( 'Articles improved during ' .. year, tostring(buildTable( {category = true}, inYear )) ) return { text = text, cat = { makeCat('WikiProject Women in Red in ' .. year, 'Articles', test), makeCat('WikiProject Women in Red articles by year', year, test) }, nav = true } end local seriesHeader = function(series, test) local text = 'This category contains talk pages of articles which were created or improved as part of the ' .. series .. ' series of meetups hosted by the Women in Red project.' .. collapse( 'Articles improved during ' .. series .. ' events', tostring(buildTable( {category = true}, function(_, event) return event.series==series end )) ) return { text = text, cat = {makeCat('WikiProject Women in Red articles by series', series, test)} } end p.category_header = function(frame) local pargs = frame:getParent().args local page = mw.title.getCurrentTitle().text local n = pargs.test and pargs.n or page:match('WikiProject Women in Red meetup (%d+) articles') local year = pargs.test and pargs.year or page:match('WikiProject Women in Red (%d+) articles') local series = pargs.test and pargs.series or page:match('WikiProject Women in Red (.+)') local cfg, out = {}, {} if n then cfg = meetupHeader(n, pargs.test) elseif year then cfg = yearHeader(tonumber(year), pargs.test) elseif series then cfg = seriesHeader(series:gsub('%sarticles', ''):gsub('1day1woman', '#1day1woman'), pargs.test) end local image = cfg.image_left or 'Women in Red logo.svg' table.insert(out, frame:expandTemplate{ title = 'cmbox', args = { image = '40px', text = cfg.text or '', imageright = cfg.image_right } }) table.insert(out, not(pargs.test) and cfg.nav and frame:expandTemplate{ title = 'Category series navigation', args = {min = '1'} } or '') table.insert(out, frame:expandTemplate{title = 'CatAutoTOC'}) table.insert(out, cfg.empty and frame:expandTemplate{ title = 'Possibly empty category', args = {[1] = 'This category should be populated soon.'} } or '') table.insert(out, table.concat(cfg.cat or {}) or '') return table.concat(out) end p.addDateCategories = function() local n = tonumber(args[1]) local test = yesno(args.test) local cats = {} local _start, _end = getDates(n, true) local start_id, end_id = format_date(_start), format_date(_end) for year = _start.year, _end.year do table.insert(cats, makeCat('WikiProject Women in Red in ' .. year, n, test)) end if _start.month and start_id+2>=end_id then -- event spans at most three months for monthid = start_id, end_id do -- add monthly categories local year = math.floor(monthid/12) local month = monthid - year*12 + 1 table.insert(cats, makeCat('Wikipedia meetups in ' .. monthName(month) .. ' ' .. year, 'Women in Red', test)) end else -- event spans more than three months, just use yearly categories for year = _start.year, _end.year do table.insert(cats, makeCat('Wikipedia meetups in ' .. year, 'Women in Red', test)) end end if value(n, 'type')=='contest' then table.insert(cats, makeCat('Wikipedia competitions', test)) end return table.concat(cats) end p.pinterest = function() -- Function to generate the correct link to pinterest based on the month of the start of the event local event = tonumber(frame.args[1]) if data[event] then local _start = getDates(event) local month = monthName(_start.month or 1) local label = month .. '-' .. _start.year .. '-editathons' return '[https://www.pinterest.com/wikiwomeninred/' .. label .. ' ' .. label .. ']' end end return p