Module:MonthPageBuilder

-- a new way for coding month pages

local ERROR_NOT_MONTH_PAGE = "Error: Not a month page. "

local p = {}

function ordinal(n) local today = os.date('!*t') if today.month==4 and today.day==1 then local ords = {'th','st','nd','rd'} local o = ords[math.random(1,#ords)] return n .. '' .. o .. ' '   else local x = n % 100 if x>10 and x<14 then return n .. 'th' else x = x % 10 if x==1 then return n .. 'st' elseif x==2 then return n .. 'nd' elseif x==3 then return n .. 'rd' else return n .. 'th' end end end end

local Date = require('Module:Date2')

local Map = {}

Map.meta = { __index = function(t, k)       if type(k)=='number' then return t.rel[t.seq[k]] elseif k == 'add' then return function(t, v)               table.insert(t.seq, v[1]) t.rel[v[1]] = v[2] t.nex[v[1]] = #t.seq+1 end elseif k == 'len' then return #t.seq elseif k == 'has' then return function(t, k)               if t.rel[k] == nil then return false else return true end end elseif k == 'includes' then return function(t, v)               for k, v1 in pairs(t) do                    if v1 == v then return true end end return false end else return t.rel[k] end end, __pairs = function(t) local nex = function(t, k)           local nk            if k == nil then nk = t.seq[1] else nk = t.seq[t.nex[k]] end return nk, t.rel[nk] end return nex, t, nil end, __ipairs = function(t) return ipairs(t.seq) end--, --__len = function(t) --   return #t.seq --end  -- Will only work once updated to Lua 5.2 }

Map.constructor = { __call = function(dummy, ...) local t = {} t.seq = {} t.rel = {} t.nex = {} setmetatable(t, Map.meta) local args = {...} local n = select('#',...) for i=1, n do           t:add(args[i]) end return t   end }

setmetatable(Map, Map.constructor)

--local headers = {   blogs = 'Blog Posts',    chat = 'Chat',    conflicts = 'Conflicts',    discord = 'Discord',    events = 'Events & Holidays',    general = 'General',    gplus = 'Google+',    games = 'Map Games & Contests',    outside = 'Outside the Wikia',    pages = 'Pages',    skype = 'Skype',    threads = 'Threads',    users = 'Users' }

local headers = Map(   {'blogs','Blog Posts'},    {'chat','Chat'},    {'conflicts', 'Conflicts'},    {'discord', 'Discord'},    {'events', 'Events & Holidays'},    {'general', 'General'},    {'gplus', 'Google+'},    {'games', 'Map Games & Contests'},    {'outside', 'Outside the Wikia'},    {'pages', 'Pages'},    {'skype', 'Skype'},    {'threads', 'Threads'},    {'users', 'Users'} )

local newUserHeaders = Map(   {'mappers', 'Mappers'},    {'users', 'Users'},    {'disputed', 'Disputed'} )

function parseMonthCode(raw) local txt = mw.ustring.gsub(raw,'!','!exc;') local preCodeBlocks = {} local preCount = 0 txt = mw.ustring.gsub(txt,' .- ',function(str)       preCount = preCount + 1        local key = '!pre' .. preCount .. ';'        preCodeBlocks[key] = str        return key    end) txt = mw.ustring.gsub(txt,'(%w+):','!spl;!cmd;%1!spl;') txt = mw.ustring.gsub(txt,'\n','!spl;') txt = mw.ustring.gsub(txt,'%s+',' ') txt = mw.ustring.gsub(txt,'\\:',':') txt = mw.ustring.gsub(txt,'!pre%d+;',preCodeBlocks) local code = mw.text.split(txt,'!spl;') local monthPageData = {} local dayCursor = 1 local mode = 'body' local headerCursor = 'general' local customHeader local tabCount = 0 local setMode local userType = 'mappers' monthPageData.body = {} monthPageData.newUsers = {} monthPageData.WAM = {} for i=1, #code do       local isCmd = false local c = mw.ustring.gsub(code[i],'!cmd;',function           isCmd = true            return ''        end) c = mw.ustring.gsub(c,'!exc;','!') c = mw.text.trim(c) if c ~= '' and c ~= ' ' then if isCmd then if mode=='body' and headers:has(c) then headerCursor = c               elseif mode=='newUsers' and newUserHeaders:has(c) then userType = c               elseif tonumber(c) ~= nil then dayCursor = tonumber(c) elseif c == 'body' then mode = 'body' elseif c == 'newUsers' then mode = 'newUsers' elseif c == 'WAM' then mode = 'WAM' elseif c == 'header' then setMode = 'header' elseif c == 'dummyMonth' then setMode = 'dummyMonth' elseif c == 'dummyCurDate' then setMode = 'dummyCurDate' elseif c == 'extra' then setMode = 'extra' elseif c == 't' then tabCount = tabCount + 1 elseif c == 'debugCodeBox' then monthPageData.debugBox = true end else if setMode == 'header' then headerCursor = 'custom' customHeader = c               elseif setMode == 'dummyMonth' then monthPageData.dummyMonth = c               elseif setMode == 'dummyCurDate' then monthPageData.dummyCurDate = c               elseif setMode == 'extra' then monthPageData.extra = c               elseif mode == 'body' then local t = mw.ustring.rep('*',tabCount) .. c                   if monthPageData.body[dayCursor] == nil then monthPageData.body[dayCursor] = {} end if headerCursor == 'custom' then if monthPageData.body[dayCursor].custom == nil then monthPageData.body[dayCursor].custom = {} end if monthPageData.body[dayCursor].custom[customHeader] == nil then monthPageData.body[dayCursor].custom[customHeader] = {} end table.insert(monthPageData.body[dayCursor].custom[customHeader],t) else if monthPageData.body[dayCursor][headerCursor] == nil then monthPageData.body[dayCursor][headerCursor] = {} end table.insert(monthPageData.body[dayCursor][headerCursor],t) end elseif mode == 'newUsers' then if monthPageData.newUsers[userType] == nil then monthPageData.newUsers[userType] = {} end if monthPageData.newUsers[userType][dayCursor] == nil then monthPageData.newUsers[userType][dayCursor] = {} end table.insert(monthPageData.newUsers[userType][dayCursor],c) elseif mode == 'WAM' then local w = mw.text.split(c,' ') if monthPageData.WAM[dayCursor] == nil then monthPageData.WAM[dayCursor] = {} end monthPageData.WAM[dayCursor].rank = w[1] monthPageData.WAM[dayCursor].score = w[2] end tabCount = 0 setMode = nil end end end return monthPageData end

function p.build(frame) local components = {} local compMeta = { __index = { add = function(c,s) table.insert(c,s) return c           end, join = function(t) return table.concat(t) end }   }    setmetatable(components,compMeta) local mPageData = parseMonthCode(tostring(frame.args[1])) local monthYearName if mPageData.dummyMonth ~= nil then monthYearName = mPageData.dummyMonth else monthYearName = mw.title.getCurrentTitle.rootText end local monthDate = Date.fromMonthYearName(monthYearName) if monthDate==nil then return ERROR_NOT_MONTH_PAGE end local curDate = os.date('!*t') curDate = Date(curDate.year,curDate.month,curDate.day) if mPageData.dummyCurDate ~= nil then local dNums = mw.text.split(mPageData.dummyCurDate,'%-') curDate = Date(tonumber(dNums[1]),tonumber(dNums[2]),tonumber(dNums[3])) end local topNavBox = [=[{| class="wikitable mw-collapsible" cellspacing="1" cellpadding="3" align="center" style="border:0px solid #999; font-size: 11px; width: 30%; margin-top:5px; margin-bottom:5px; background:#E5E9DF;" ! colspan="3" style="background-color:#0099FF; color:#FFFFFF; font-size:12px; padding:1em;" | ${monthyear} ! colspan="3" style="background:#E5E9DF; font-size:12px; padding:1em;" | Months in ${year} ! colspan="3" style="background:#E5E9DF; font-size:80%;" | ${yearmonthlinks} ! colspan="3" style="background:#E5E9DF; font-size:11px;" | Please read the Month Page Code of Conduct before editing this page. local navBoxReplacer = {} navBoxReplacer.monthyear = monthDate:toStr('monthyear') local preMon = monthDate:copy:prevMonth if curDate >= preMon:copy:prevDay and preMon >= Date(2012,10,1) then navBoxReplacer.prevmonthlink = '←Previous Month' else navBoxReplacer.prevmonthlink = '←Previous Month' end local nexMon = monthDate:copy:nextMonth if curDate >= nexMon:copy:prevDay then navBoxReplacer.nextmonthlink = 'Next Month→' else navBoxReplacer.nextmonthlink = 'Next Month→' end navBoxReplacer.year = monthDate.year local navBoxYearMonthLinks = {} setmetatable(navBoxYearMonthLinks,compMeta) local yearMonthLinkIndex = monthDate:copy:beginYear if monthDate.year==2012 then yearMonthLinkIndex.month = 10 end local nexYear = monthDate:copy:nextYear while yearMonthLinkIndex <= curDate:copy:nextDay and yearMonthLinkIndex < nexYear do       navBoxYearMonthLinks:add( .. yearMonthLinkIndex:toStr('month') .. ) yearMonthLinkIndex:nextMonth if yearMonthLinkIndex <= curDate:copy:nextDay and yearMonthLinkIndex < nexYear then navBoxYearMonthLinks:add(' • ') end end navBoxReplacer.yearmonthlinks = navBoxYearMonthLinks:join topNavBox = mw.ustring.gsub(topNavBox, '%${(%w+)}', navBoxReplacer) components:add(frame:preprocess(topNavBox)) :add("\n\n '''") :add(monthDate:toStr('monthyear')) :add("''' ") if curDate < nexMon then components:add('is') else components:add('was') end components:add(' the ') :add(ordinal(monthDate.month)) if curDate < monthDate then components:add(' and next') --this will technically say any future month is 'next', but people aren't supposed to make month pages more than a day in advance elseif curDate < nexMon then components:add(' and current') end components:add(' month in ') :add(monthDate.year) :add(' and') if monthDate.year == 2012 then components:add(' ') :add(ordinal(monthDate.month-9)) end components:add(' in Mapperdonia.') if mPageData.extra ~= nil then components:add(' ') :add(mPageData.extra) end components:add(' \n\n\n\n') local mBegin = monthDate:copy:beginMonth if monthDate.year==2012 and monthDate.month==10 then mBegin.day = 7 end local monthHeaderDay = mBegin:copy while monthHeaderDay < nexMon and monthHeaderDay <= curDate do       local d = monthHeaderDay.day components:add('') :add(monthHeaderDay:toStr('monthpageheading')) :add(' ') if mPageData.body[d]==nil then components:add("\n'''Nothing important happened on this day") if monthHeaderDay==curDate then components:add(" yet") end components:add(".'''") else for k, dummy in pairs(headers) do               local v = mPageData.body[d][k] if v ~= nil then components:add("\n==='''") :add(headers[k]) :add("'''===\n") for i=1, #v do                       components:add('*') :add(v[i]) if i~=#v then components:add('\n') end end end end end components:add('\n') monthHeaderDay:nextDay end components:add('\n==New users==') for k, v in pairs(newUserHeaders) do       components:add("\n==='''") :add(v) :add("'''===") local nu = mPageData.newUsers[k] if nu == nil then components:add("\nnone") else monthHeaderDay = mBegin:copy while monthHeaderDay<nexMon and monthHeaderDay<=curDate do               local d = monthHeaderDay.day if nu[d]~=nil then for i=1, #nu[d] do                       components:add('\n* ') :add(nu[d][i]) :add(' (')                           :add(monthHeaderDay:toStr)                            :add(')') end end monthHeaderDay:nextDay end end end if mPageData.debugBox then components:add('\n\n ') :add(tostring(frame.args[1])) :add(' ') end return components:join end
 * ${prevmonthlink}
 * ${nextmonthlink}
 * ${nextmonthlink}
 * }]=]

return p