Module:Timeline

require('Module:No globals')

local yesno = require('Module:Yesno') local navbox = require('Module:Navbox')._navbox local getArgs = require('Module:Arguments').getArgs local p = {}

-- Add a blank table cell local function addBlank(args, row, prev, current) if row and prev &#x3c; current then if yesno(args.decades) == false then row:tag('td') :addClass('timeline-blank') :cssText(args.blankstyle) :attr('colspan', current - prev) -- Divide the cell up every decade if showing decades at the top else local year = prev while year &#x3c; current do				local dur = math.min(10 - year % 10, current - year) row:tag('td') :addClass('timeline-blank') :cssText(args.blankstyle) :attr('colspan', dur) year = year + dur end end end end

-- Get timeline entries, start years, and end years local function timelineInfo(args) local info = { startYear = math.huge, startYears = {}, endYear = 0, endYears = {}, entries = {} }	for k, _ in pairs(args) do		if type(k) == 'string' then local num = k:match('^%a+(%d+)$')

if num then table.insert(info.entries, tonumber(num)) end end end table.sort(info.entries) for i, num in ipairs(info.entries) do if args['item' .. i] then if not args['date' .. i] then error('item' .. i .. ' requires a corresponding ' .. 'date' .. i, 0) end local dates = mw.text.split(args['date' .. i], '-', true) local startYear = tonumber(dates[1]) local endYear = tonumber(dates[2]) or tonumber(os.date('%Y')) + 1 if not startYear then error('date' .. i .. ' contains an invalid timerange', 0) end info.startYear = math.min(info.startYear, startYear) info.endYear = math.max(info.endYear, endYear) info.startYears[i] = startYear info.endYears[i] = endYear end end if args.startoffset then info.startYear = info.startYear - tonumber(args.startoffset) end if args.startyear then info.startYear = math.min(info.startYear, tonumber(args.startyear)) end if args.endoffset then info.endYear = info.endYear + tonumber(args.endoffset) end if args.endyear then info.endYear = math.max(info.endYear, tonumber(args.endyear)) end return info end

-- Render the date rows local function renderDates(args, tbl, info) local showDecades = yesno(args.decades) local labelRow = nil if args.label then labelRow = mw.html.create('th') :attr('scope', 'col') :addClass('navbox-group timeline-label') :cssText(args.labelstyle) :attr('rowspan', showDecades ~= false and '2' or '1') :wikitext(args.label or '') end -- Render the decades row if showDecades ~= false then local decadeRow = tbl:tag('tr') :addClass('timeline-row') local year = info.startYear decadeRow:node(labelRow) while year &#x3c; info.endYear do			local dur = math.min(10 - year % 10, info.endYear - year) decadeRow:tag('th') :attr('scope', 'col') :addClass('timeline-decade') :cssText(args.datestyle) :cssText(args.decadestyle) :attr('colspan', dur) :wikitext(math.floor(year / 10) .. '0s') year = year + dur end end

-- Render the years row local yearRow = tbl:tag('tr') :addClass('timeline-row') local width = 100 / (info.endYear - info.startYear) if showDecades == false then yearRow:node(labelRow) end for i = info.startYear, info.endYear - 1 do		yearRow:tag('th') :attr('scope', 'col') :addClass('timeline-year') :cssText(args.datestyle) :cssText(args.yearstyle) :cssText('width:' .. width .. '%') :wikitext(showDecades == false and i or i % 10) end end

-- Render the timeline itself local function renderTimeline(args, tbl, info) local row = nil local prev = info.startYear local prevItem = nil local prevLabel = nil local labelSpan = 0 for i, num in ipairs(info.entries) do if args['row' .. i] or row == nil then addBlank(args, row, prev, info.endYear) row = tbl:tag('tr') :addClass('timeline-row') prev = info.startYear if labelSpan &#x3c;= 0 and args.label then labelSpan = tonumber(args['span' .. i]) or 1 prevLabel = row:tag('th') :attr('scope', 'row') :attr('rowspan', labelSpan) :addClass('navbox-group timeline-label') :cssText(args.labelstyle) :cssText(args['labelstyle' .. i] or '') :wikitext(args['row' .. i]) end labelSpan = labelSpan - 1 end if args['item' .. i] then local content = args['item' .. i] 			local startYear = info.startYears[i] local endYear = info.endYears[i] addBlank(args, row, prev, startYear) -- Shrink previous item so new item can start at the start year if prevItem and prev &#x3e; startYear then prevItem:attr('colspan', prevItem:getAttr('colspan') - prev + startYear); end prevItem = row:tag('td') :addClass('timeline-item') :cssText(args.itemstyle) :cssText(args['style' .. i] or '') :attr('colspan', endYear - startYear) :wikitext(content) prev = endYear end end -- Remove any extra rowspan from the label if prevLabel and labelSpan &#x3e; 0 then prevLabel:attr('rowspan', prevLabel:getAttr('rowspan') - labelSpan); end addBlank(args, row, prev, info.endYear) end

function p.main(frame) local args = getArgs(frame, {		removeBlanks = false,		wrappers = 'Template:Timeline'	}) local targs = { listpadding = '0' }	-- Arguments to passthrough to navbox local passthrough = { 'name', 'title', 'above', 'below', 'state', 'navbar', 'border', 1, 'image', 'imageleft', 'style', 'bodystyle', 'style', 'bodystyle', 'basestyle', 'titlestyle', 'abovestyle', 'belowstyle', 'imagestyle', 'imageleftstyle', 'titleclass', 'aboveclass', 'bodyclass', 'belowclass', 'imageclass' }	local info = timelineInfo(args) local wrapper = mw.html.create('table') :addClass('timeline-wrapper') local tbl = wrapper:tag('tr') :tag('td') :addClass('timeline-wrapper-cell') :tag('table') :addClass('timeline-table') renderDates(args, tbl, info) renderTimeline(args, tbl, info) if yesno(args.footer) then renderDates(args, tbl, info) end for _, name in ipairs(passthrough) do 		targs[name] = args[name] end

targs.list1 = frame:extensionTag{ name = 'templatestyles', args = { src = 'Module:Timeline/styles.css' }	} .. tostring(wrapper) return navbox(targs) end

return p