Module:Women in Red event

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 or 0 return _date.year*100+month end local relativeMonths = function(_date) local last_month = {year=_date.year, month=_date.month-1} if _date.month==1 then last_month = {year=_date.year-1, month=12} end local next_month = {year=_date.year, month=_date.month+1} if _date.month==12 then next_month = {year=_date.year+1, month=1} end return { current = format_date(_date), last = format_date(last_month), next = format_date(next_month) } end local relative_month = relativeMonths(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 _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

p.main = function local ret = value(args[1], args[2], args[3]) return ret and mw.text.nowiki(ret) -- prevent # character from starting a list 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 date, _ = _date(args[1], yesno(frame.args.sentence or 'false'), yesno(frame.args.abbrev or 'false')) return date 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 '' .. _name(meetup) 		.. ' ' .. value(meetup, 'type', 'edit-a-thon')		.. ' ' .. _date(meetup, true, false) end

local showDate = function(meetup) local date, sortkey = _date(meetup, false, true) return mw.html.create('td'):attr('data-sort-value', sortkey):wikitext(date):done end

local link = function(n, name) local label = name and _name(n) or n	return  .. label ..  end

local buildTable = function(option, show) local meetupCell = function(n) return mw.html.create('th') :css('background-color', value(n, 'background') and ('#' .. value(n, 'background'))) :css('text-align', 'center') :wikitext(n) :done 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', 'logo', 'series', 'name', 'date', 'template', 'wrapper', 'category'}) do		if option[col] then cols = cols + 1 header:tag('th'):wikitext(lang:ucfirst(col)):done end end local rows = {} for n, event in pairs(data) do		if not show or show(n, event) then local row = mw.html.create('tr') :node(meetupCell(n)) if option.logo then local logo = event.image and '' row:tag('td'):wikitext(logo):done end if option.series then local series = event.series and  .. event.series ..  or '' row:tag('td') :wikitext(series) :done end local name = option.series and event.name or _name(n) local link =  .. name ..  row:tag('td'):wikitext(link):done :node(showDate(n)) if option.template then local template = frame:extensionTag('code', '') row:tag('td'):css('text-align', 'center'):wikitext(template):done end if option.wrapper then row:tag('td') :css('text-align', 'center') :wikitext('') :done 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 row:tag('td') :css('text-align', 'center') :wikitext(catText) :done 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 return buildTable(		option,		function(n, _) return n>=first and n<=last end	) end

local eventStatus = function(event, _date) --function to decide whether an event is upcoming, current, ongoing, recently completed or past local month = relative_month if _date then month = relativeMonths(_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<month.last then -- event ended before previous month return 'past' elseif _end==month.last then -- event ended on previous month return 'recent' elseif _start==month.current then -- event has started on current month return 'current' elseif _start==month.next then -- event starts after current month return 'upcoming' elseif _start b end) return events end

p.current_events = function(frame) local _date = currentDate if frame.args.year and frame.args.year~='' then _date = { year = tonumber(frame.args.year), month = tonumber(frame.args.month) or 1 }	end local mClickableButton2 = require('Module:Clickable button 2').main local button = function(text, colour) return mClickableButton2{ [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(  .. _name(n) .. , 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) local text = 'This category contains talk pages of articles which were created or improved during the ' .. _name(n) .. ' ' .. value(n, 'type', 'edit-a-thon') .. ' hosted by the Women in Red project ' .. _date(n, true, false) .. '. It is automatically populated by ' .. frame:expandTemplate{title = 'tlx', args = { [1] = 'WikiProject Women in Red', [2] = n }} .. '.'		.. ''	local _start, _end = getDates(n, true) for year = _start.year, _end.year do text = text .. ''	end if value(n, 'series') then text = text .. ''	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, value(n, 'image', 'Women in Red logo.svg'), empty and future end

local collapse = function(title, text) return frame:expandTemplate{title = 'Collapsed top', args = { bg = 'transparent', width = '80%', [1] = title }} .. text .. ' ' end local yearHeader = function(year) 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 return 'This category contains talk pages of articles which were created or improved in ' .. year .. ' as part of the Women in Red project. The category is automatically populated by ' .. frame:expandTemplate{title = 'tlx',	args = { [1] = 'WikiProject Women in Red', [2] = 'year=' .. year }} .. '.' .. collapse(			'Articles improved during ' .. year,			tostring(buildTable(				{category = true},				inYear			))		) .. 		..  end

local seriesHeader = function(series) return '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		))	) .. '' end

p.category_header = function local page = mw.title.getCurrentTitle.text local n = page:match('WikiProject Women in Red meetup (%d+) articles') local year = page:match('WikiProject Women in Red (%d+) articles') local series = page:match('WikiProject Women in Red (.+)') local text, image, emptyCat, categorySeriesNavigation = '', 'Women in Red logo.svg', false, false if n then text, image, emptyCat = meetupHeader(n) categorySeriesNavigation = true elseif year then text = yearHeader(tonumber(year)) categorySeriesNavigation = true elseif series then text = seriesHeader(series:gsub('%sarticles', ''):gsub('1day1woman', '#1day1woman')) end emptyCat = emptyCat and frame:expandTemplate{ title = 'Possibly empty category', args = {[1] = 'This category should be populated soon.'} } or '' return frame:expandTemplate{title = 'cmbox', args = { image = '', text = text }} .. (categorySeriesNavigation and frame:expandTemplate{title = 'Category series navigation'} or '') .. frame:expandTemplate{title = 'CatAutoTOC'} .. emptyCat end

p.addDateCategories = function local n = args[1] local test = yesno(args.test) local cats = {} local makeCat = function(cat, key) local key2 = key and not test and ('|' .. key) or '' table.insert(cats, 			.. (test and ':' or )			.. 'Category:' .. cat			.. key2 .. '') end local _start, _end = getDates(n, true) for year = _start.year, _end.year do makeCat('WikiProject Women in Red in ' .. year, n)	end if _start.month and format_date(_start)==format_date(_end) then -- event starts and ends on same month makeCat('Wikipedia meetups in ' .. monthName(_start.month) .. ' ' .. _start.year) else -- event spans more than one month, so just use yearly categories for year = _start.year, _end.year do makeCat('Wikipedia meetups in ' .. year) end 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 _start = getDates(frame.args[1]) local month = monthName(_start.month or 1) local label = month .. '-' .. _start.year .. '-editathons' return '[https://www.pinterest.com/wikiwomeninred/' .. label .. ' ' .. label .. ']' end

return p