Permanently protected module
From Wikipedia, the free encyclopedia


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 formatDate = function(_date)

	local month = _date.month or 0

	month = month<=9 and ('0'..tostring(month)) or tostring(month)

	return tostring(_date.year) .. month

end

local current_month = formatDate(currentDate)

local last_month = formatDate({

	year = currentDate.year,

	month = currentDate.month-1

})

if currentDate.month==1 then

	last_month = formatDate({

		year = currentDate.year-1,

		month = 12

	})

end



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 = datatonumber(event)]

	if data and datafield then

		return datafield

	else

		return default

	end

end



p.main = function()

	local ret = value(args1], args2], args3])

	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(args1], 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.nested = function()

-- Function to produce year for nested display in project banner

	local year = value(args1], 'year')

	if not year and value(args1], 'start') and value(args1], 'start').year==value(args1], 'end').year then

		year = value(args1], 'start').year

	end

	return _name(args1]) .. (year and (' (' .. year .. ')') or '')

end



p.text = function()

	local meetup = args1

	return '[[Wikipedia:WikiProject Women in Red/Meetup/' .. meetup

		.. '|' .. _name(meetup) 

		.. ' ' .. value(meetup, 'type', 'edit-a-thon')

		.. ']] '

		.. _date(meetup, true, false)

end



p.name = function()

	return mw.text.nowiki(_name(args1]))

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 '[[Wikipedia:WikiProject Women in Red/Meetup/' .. n .. '|' .. 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 optioncol 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 '[[File:' .. event.image .. '|50px]]'

				row:tag('td'):wikitext(logo):done()

			end

			if option.series then

				local series = event.series and '[[:Category:WikiProject Women in Red ' .. event.series .. ' articles|' .. event.series .. ']]' or ''

				row:tag('td')

				:wikitext(series)

				:done()

			end

			local name = option.series and event.name or _name(n)

			local link = '[[Wikipedia:WikiProject Women in Red/Meetup/' .. n .. '|' .. name .. ']]'

			row:tag('td'):wikitext(link):done()

			:node(showDate(n))

			if option.template then

				local template = frame:extensionTag('code', '{{WIR|' .. n .. '}}')

				row:tag('td'):css('text-align', 'center'):wikitext(template):done()

			end

			if option.wrapper then

				row:tag('td')

				:css('text-align', 'center')

				:wikitext('{{[[:Template:WIR-' .. n .. '|WIR-' .. n .. ']]}}')

				: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 = '[[' .. ':Category:' .. cat .. '|' .. 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

		optionkey = yesno(value)

	end

	return buildTable(

		option,

		function(n, _) return n>=first and n<=last end

	)

end



p.count_banners = function()

	local title = mw.title.getCurrentTitle()

	if title.namespace==1 then

		local wikitext = title:getContent()

		local _, count = mw.ustring.gsub(wikitext,'%{%{%s*[Ww]ikiProject Women in Red','')

		if count>1 then

			return '[[Category:Pages with ' .. tostring(count) .. ' WikiProject Women in Red banners]]'

		end

	end

end



local eventStatus = function(event)

--function to decide whether an event is upcoming, current, recently completed or past

	local year = event.year or event.start.year

	if formatDate(event)==current_month then

		return 'current'

	elseif formatDate(event)==last_month then

		return 'recent'

	elseif year==currentDate.year and not event.month then

		if event'start' and event'end' then

			if event'start'].month<=currentDate.month and event'end'].month>=currentDate.month then

				return 'ongoing'

			end

		else

			return 'ongoing'

		end

	elseif year>currentDate.year or (event.month and year==currentDate.year and event.month>currentDate.month) then

		return 'upcoming'

	else

		return 'past'

	end

end



local searchEvents = function()

	local events = {current = {}, recent = {}, ongoing = {}, upcoming = {}, past = {}}

	for n, event in ipairs(data) do

		local status = eventStatus(event)

		table.insert(eventsstatus], n)

	end

	table.sort(events.past, function(a, b) return a > b end)

	return events

end



p.current_events = function()

	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 events1 then

			for _, n in ipairs(events) do

				table.insert(list, button(

					'[[Wikipedia:WikiProject Women in Red/Meetup/' .. n .. '|' .. _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()

	local ret = mw.html.create('table')

		:node(links('Recently completed', events.recent))

		:node(links(monthName(currentDate.month) .. ' ' .. currentDate.year, events.current))

		:node(links('Ongoing initiatives', events.ongoing))

		:node(links('Upcoming events', events.upcoming, '[[Wikipedia:WikiProject Women in Red/Ideas|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 ecclass or not argsclass then

			return nil

		end

		ret:tag('h3'):wikitext(argsclass]):done()

		if ecclass][1 then

			ret:tag('ul')

			for _, n in ipairs(ecclass]) 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 = args1

	if not ecclass then

		return nil

	end

	local ret = mw.html.create('ul')

	for _, n in ipairs(ecclass]) 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 = args1 and tonumber(args1]) 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 eventstype then

				eventstype = {}

			end

			local month = value(n, 'month', 0)

			if not eventstype][month then

				eventstype][month = {}

			end

			table.insert(eventstype][month], n)

		end

	end

	for type, eventsOfType in pairs(events) do

		ret:wikitext(lang:uc(type)..'S: ')

		for _, n in ipairs(eventsOfType0 or {}) do

			ret:tag('li'):wikitext(link(n, true)):done()

		end

		for month = 1, 12 do

			if eventsOfTypemonth then

				local sublist = mw.html.create('ul')

				for _, n in ipairs(eventsOfTypemonth]) 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 <b>[[Wikipedia:WikiProject Women in Red/Meetup/'

		.. n .. '|' .. _name(n) .. ' ' .. value(n, 'type', 'edit-a-thon') .. ']]</b> hosted by the [[Wikipedia:WikiProject Women in Red|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

		}} .. '.'

		.. '[[Category:WikiProject Women in Red articles by meetup|' .. n .. ']]'

	local _start, _end = getDates(n, true)

	for year = _start.year, _end.year do

		text = text .. '[[Category:WikiProject Women in Red ' .. year .. ' articles|' .. n .. ']]'

	end

	if value(n, 'series') then

		text = text .. '[[Category:WikiProject Women in Red ' .. value(n, 'series'):gsub('#', '') .. ' articles|' .. n .. ']]'

	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 .. '</table></div>'

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 [[Wikipedia:WikiProject Women in Red|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

			))

		) .. '[[Category:WikiProject Women in Red in ' .. year .. '|Articles]]'

		.. '[[Category:WikiProject Women in Red articles by year|' .. year .. ']]'

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 [[Wikipedia:WikiProject Women in Red|Women in Red project]].'

	.. collapse(

		'Articles improved during ' .. series .. ' events',

		tostring(buildTable(

			{category = true},

			function(_, event) return event.series==series end

		))

	) .. '[[Category:WikiProject Women in Red articles by series|' .. series .. ']]'

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 = '[[File:' .. image .. '|40px]]',

		text = text

	}} .. (categorySeriesNavigation and frame:expandTemplate{title = 'Category series navigation'} or '')

	.. frame:expandTemplate{title = 'CatAutoTOC'}

	.. emptyCat

end



p.addDateCategories = function()

	local n = args1

	local test = yesno(args.test) and ':' or ''

	local cats = {}

	local makeCat = function(cat, key)

		local key2 = key and ('|' .. key) or ''

		table.insert(cats, '[[' .. test .. '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 formatDate(_start)==formatDate(_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.args1])

	local month = monthName(_start.month or 1)

	local label = month .. '-' .. _start.year .. '-editathons'

	return '[https://www.pinterest.com/wikiwomeninred/' .. label .. ' ' .. label .. ']'

end



return p