Module:Navbox timeline: Difference between revisions
AZMindroma (talk | contribs) Trying out months change (AI) Tag: Reverted |
AZMindroma (talk | contribs) No edit summary Tag: Reverted |
||
| Line 5: | Line 5: | ||
local getArgs = require('Module:Arguments').getArgs | local getArgs = require('Module:Arguments').getArgs | ||
local p = {} | local p = {} | ||
-- Convert date string to fractional year for timeline positioning | |||
local function parseDate(dateStr) | |||
if not dateStr then return nil end | |||
-- Handle year-month format (YYYY-MM or YYYY/MM) | |||
local year, month = dateStr:match('^(%d%d%d%d)[%-/](%d%d?)$') | |||
if year and month then | |||
year = tonumber(year) | |||
month = tonumber(month) | |||
if month < 1 or month > 12 then | |||
error('Invalid month: ' .. month .. ' (must be 1-12)', 0) | |||
end | |||
-- Convert to fractional year (e.g., 2020.5 for June 2020) | |||
return year + (month - 1) / 12 | |||
end | |||
-- Handle year only | |||
local yearOnly = dateStr:match('^(%d%d%d%d)$') | |||
if yearOnly then | |||
return tonumber(yearOnly) | |||
end | |||
return nil | |||
end | |||
-- Add blank table cells | -- Add blank table cells | ||
| Line 15: | Line 40: | ||
while date < current do | while date < current do | ||
local dur = math.min(1, current - date) -- 1 month duration | local dur = math.min(1/12, current - date) -- 1 month duration in fractional years | ||
local colspanMonths = math.max(1, math.round(dur * 12)) | |||
row:tag('td') | row:tag('td') | ||
:addClass('timeline-blank') | :addClass('timeline-blank') | ||
:cssText(args.blankstyle) | :cssText(args.blankstyle) | ||
:attr('colspan', | :attr('colspan', colspanMonths) | ||
date = date + dur | date = date + dur | ||
end | end | ||
else | else | ||
local yearDiff = current - prev | |||
row:tag('td') | row:tag('td') | ||
:addClass('timeline-blank') | :addClass('timeline-blank') | ||
:cssText(args.blankstyle) | :cssText(args.blankstyle) | ||
:attr('colspan', | :attr('colspan', math.max(1, math.round(yearDiff))) | ||
end | end | ||
else | else | ||
-- Divide the cell up every decade if showing decades at the top | -- Divide the cell up every decade if showing decades at the top | ||
local year = prev | local year = math.floor(prev) | ||
local endYear = math.ceil(current) | |||
while year < | while year < endYear do | ||
local dur = math.min(10 - year % 10, | local dur = math.min(10 - year % 10, endYear - year) | ||
row:tag('td') | row:tag('td') | ||
| Line 84: | Line 112: | ||
then | then | ||
local dates = mw.text.split(fullVal, '-', true) | local dates = mw.text.split(fullVal, '-', true) | ||
local startYear = | local startYear = parseDate(dates[1]) | ||
local endYear = | local endYear = parseDate(dates[2]) or (tonumber(os.date('%Y')) + 1) | ||
if startYear == nil then | if startYear == nil then | ||
| Line 111: | Line 139: | ||
end | end | ||
-- Add overrides from arguments | -- Add overrides from arguments (handle fractional years) | ||
if args.startoffset then | if args.startoffset then | ||
rows.minYear = rows.minYear - tonumber(args.startoffset) | rows.minYear = rows.minYear - tonumber(args.startoffset) | ||
end | end | ||
if args.startyear | if args.startyear then | ||
local startOverride = parseDate(args.startyear) or tonumber(args.startyear) | |||
if startOverride and startOverride < rows.minYear then | |||
rows.minYear = startOverride | |||
end | |||
end | end | ||
| Line 124: | Line 155: | ||
end | end | ||
if args.endyear | if args.endyear then | ||
local endOverride = parseDate(args.endyear) or tonumber(args.endyear) | |||
if endOverride and endOverride > rows.maxYear then | |||
rows.maxYear = endOverride | |||
end | |||
end | end | ||
| Line 168: | Line 202: | ||
local decadeRow = tbl:tag('tr') | local decadeRow = tbl:tag('tr') | ||
:addClass('timeline-row') | :addClass('timeline-row') | ||
local year = rows.minYear | local year = math.floor(rows.minYear) | ||
local maxYear = math.ceil(rows.maxYear) | |||
-- Move decade row | -- Move decade row | ||
| Line 175: | Line 210: | ||
end | end | ||
while year < | while year < maxYear do | ||
local dur = math.min(10 - year % 10, | local dur = math.min(10 - year % 10, maxYear - year) | ||
decadeRow:tag('th') | decadeRow:tag('th') | ||
| Line 199: | Line 234: | ||
-- Calculate total months in range | -- Calculate total months in range | ||
local totalMonths = (rows.maxYear - rows.minYear) * 12 | local totalMonths = math.ceil((rows.maxYear - rows.minYear) * 12) | ||
local monthWidth = 100 / totalMonths | local monthWidth = 100 / totalMonths | ||
local currentDate = rows.minYear | |||
while currentDate < rows.maxYear do | |||
local year = math.floor(currentDate) | |||
local month = math.floor((currentDate - year) * 12) + 1 | |||
monthRow:tag('th') | |||
:attr('scope', 'col') | |||
:addClass('timeline-month') | |||
:cssText(args.datestyle) | |||
:cssText(args.monthstyle) | |||
:cssText('width:' .. monthWidth .. '%') | |||
:wikitext(getMonthAbbr(month)) | |||
currentDate = currentDate + 1/12 | |||
end | end | ||
end | end | ||
| Line 218: | Line 257: | ||
if showDecades == false and showMonths ~= false then | if showDecades == false and showMonths ~= false then | ||
-- When showing months, each year spans 12 columns | -- When showing months, each year spans 12 columns | ||
local year = math.floor(rows.minYear) | |||
local maxYear = math.ceil(rows.maxYear) | |||
for currentYear = year, maxYear - 1 do | |||
yearRow:tag('th') | yearRow:tag('th') | ||
:attr('scope', 'col') | :attr('scope', 'col') | ||
| Line 225: | Line 267: | ||
:cssText(args.yearstyle) | :cssText(args.yearstyle) | ||
:attr('colspan', '12') | :attr('colspan', '12') | ||
:wikitext(tostring( | :wikitext(tostring(currentYear)) | ||
end | end | ||
else | else | ||
-- Normal year display | -- Normal year display | ||
local | local yearSpan = rows.maxYear - rows.minYear | ||
local width = 100 / yearSpan | |||
local year = math.floor(rows.minYear) | |||
local maxYear = math.ceil(rows.maxYear) | |||
for i = year, maxYear - 1 do | |||
yearRow:tag('th') | yearRow:tag('th') | ||
:attr('scope', 'col') | :attr('scope', 'col') | ||
| Line 276: | Line 322: | ||
-- Shrink previous item so new item can start at the start year | -- Shrink previous item so new item can start at the start year | ||
if prevItem and prev > prevEndYear then | if prevItem and prev > prevEndYear then | ||
local colspan = prevItem:getAttr('colspan') | local colspan = tonumber(prevItem:getAttr('colspan')) or 1 | ||
local adjustment = prev - prevEndYear | |||
if yesno(args.decades) == false and yesno(args.months) ~= false then | if yesno(args.decades) == false and yesno(args.months) ~= false then | ||
-- Adjust for months | -- Adjust for months | ||
adjustment = math.round(adjustment * 12) | |||
else | else | ||
adjustment = math.round(adjustment) | |||
end | end | ||
prevItem:attr('colspan', math.max(1, colspan - adjustment)) | |||
end | end | ||
| Line 294: | Line 344: | ||
local colspan = cell.endYear - cell.startYear | local colspan = cell.endYear - cell.startYear | ||
if yesno(args.decades) == false and yesno(args.months) ~= false then | if yesno(args.decades) == false and yesno(args.months) ~= false then | ||
-- Each | -- Each month is one column | ||
colspan = colspan * 12 | colspan = math.max(1, math.round(colspan * 12)) | ||
else | |||
colspan = math.max(1, math.round(colspan)) | |||
end | end | ||
| Line 314: | Line 366: | ||
-- Remove any extra rowspan from the label | -- Remove any extra rowspan from the label | ||
if prevLabel and labelSpan > 0 then | if prevLabel and labelSpan > 0 then | ||
prevLabel:attr('rowspan', prevLabel:getAttr('rowspan') - labelSpan); | prevLabel:attr('rowspan', (tonumber(prevLabel:getAttr('rowspan')) or 1) - labelSpan); | ||
end | end | ||
end | end | ||