Module:Calendar widget: Difference between revisions

Content deleted Content added
No edit summary
No edit summary
 
(39 intermediate revisions by 3 users not shown)
Line 3:
 
--]]
require('Module:No globalsstrict');
local getArgs = require ('Module:Arguments').getArgs;
 
local lang_obj = mw.language.getContentLanguage();
 
local daysinmonth = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
local p = {}
local dayname = {'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'}
 
local daysinmonth = {
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
}
local dayname = {
"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"
}
local dayabbr = {}
for i, v in ipairs(dayname) do
dayabbr[i] = v:sub(1, 2)
end
 
local monthname = {
local iso_dayname = {'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'}
"January", "February", "March", "April", "May", "June",
local iso_dayabbr = {}
"July", "August", "September", "October", "November", "December"
for i, v in ipairs(iso_dayname) do
}
iso_dayabbr[i] = v:sub(1, 2)
local monthabbr = {}
for i, v in ipairs(monthname) do
monthabbr[i] = v:sub(1, 3)
end
 
local monthnumber = {}
local monthname = {}
for i, v in ipairs(monthabbr) do
local monthabbr = {}
monthnumber[v] = i
if 0 == #monthname then
for m = 1, 12 do
monthname[m] = lang_obj:formatDate ("F", '2019-' .. m); -- table of long month names
monthabbr[m] = lang_obj:formatDate ("M", '2019-' .. m); -- table of abbreviated month names
end
end
local thisyear = tonumber( lang_obj:formatDate ("Y") )
local thismonth = tonumber( lang_obj:formatDate ("n") )
 
 
local function isleap(year)
--[[--------------------------< I S _ L E A P >----------------------------------------------------------------
 
returns true when <year> is a leapyear
 
]]
 
local function is_leap (year)
return '1' == lang_obj:formatDate ('L', tostring(year));
-- year = tonumber(year) or 1
-- return year % 4 == 0
-- and year % 100 ~= 0
-- or year % 1000 == 0
end
 
 
--[[
--[[--------------------------< D A Y _ O F _ W E E K >--------------------------------------------------------
Sakamoto's method: 1 <= month <= 12; year is Gregorian
 
dayofweek returns 1 to 7 or nil if bad arguments
returns 1 to 7; 1 == Sunday; 1 == Monday when iso true
--]]
 
local function dayofweek(year, month, day)
]]
return lang_obj:formatDate ('w', year .. '-' .. month .. '-' .. day) + 1;
 
-- local y = tonumber(year)
-- local mfunction =day_of_week tonumber(year, month, day, iso)
return
-- local d = tonumber(day)
iso and lang_obj:formatDate ('N', year .. '-' .. month .. '-' .. day) or -- ISO: 1 = monday
-- if not (y and m and d) then return nil end
lang_obj:formatDate ('w', year .. '-' .. month .. '-' .. day) + 1; -- 1 = sunday
-- local t = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4}
-- if m < 3 then y = y - 1 end
-- return (y + math.floor(y/4) - math.floor(y/100) + math.floor(y/400) + t[m] + d) % 7 + 1
end
 
 
-- year and month both numeric:
--[[--------------------------< I S _ S E T >------------------------------------------------------------------
local function monthstart(year, month)
 
return dayofweek(year, month, 1)
Returns true if argument is set; false otherwise. Argument is 'set' when it exists (not nil) or when it is not an empty string.
 
]]
 
local function is_set( var )
return not (var == nil or var == '');
end
 
 
-- generate the html to display a month calendar
--[=[-------------------------< M A K E _ W I K I L I N K >----------------------------------------------------
local function displaymonth(props, mnum)
 
local year = props.year
Makes a wikilink; when both link and display text is provided, returns a wikilink in the form [[L|D]]; if only
if isleap(year) then daysinmonth[2] = 29 end
link is provided, returns a wikilink in the form [[L]]; if neither are provided or link is omitted, returns an
local firstday = monthstart(year, mnum)
empty string.
local monthcal = {}
 
local hdr_year = props.show_year and year or '';
]=]
table.insert(monthcal, '<table class="mcal">')
 
table.insert(monthcal, '<tr class="mcalhdr">')
local function make_wikilink (link, display)
-- table.insert(monthcal, '<th class="mcal" colspan="7">' .. monthname[mnum] .. ' ' .. year .. '</th>')
if is_set (link) then
table.insert(monthcal, '<th class="mcal" colspan="7">' .. monthname[mnum] .. ' ' .. hdr_year .. '</th>')
if is_set (display) then
table.insert(monthcal, '</tr>')
return table.insertconcat (monthcal{'[[', link, '<tr|', class="mcalhdr">display, ']]'});
else
for c = 1, 7 do
return table.concat ({'[[', link, ']]'});
table.insert(monthcal, '<th class="mcal" scope="col">' .. dayabbr[c] .. '</th>')
end
else
return '';
end
table.insert(monthcal, '</tr>')
local numrows = math.ceil( (firstday + daysinmonth[mnum] - 1) / 7 )
for r = 1, numrows do
table.insert(monthcal, '</tr>')
for c = 1, 7 do
local dom = 7 * (r-1) + c + 1 - firstday
if dom < 1 or dom > daysinmonth[mnum] then dom = "&nbsp;" end
table.insert(monthcal, '<td class="mcal">' .. dom .. '</td>')
end --columns
table.insert(monthcal, '<tr class="mcal">')
end --rows
table.insert(monthcal, '</table>')
return table.concat(monthcal, '\n')
end
 
 
local function displayyear(props)
--[[--------------------------< G E T _ D I S P L A Y _ Y E A R >----------------------------------------------
local year = props.year
 
local rows = props.rows
returns year from props with prefixed and suffixed wikilink if appropriate; this function used for both yearly
local cols = props.cols or 4
and stand-alone calendars
local mnum;
 
]]
 
local function get_display_year (props)
local year_text = props.year;
local lk_prefix = props.lk_pref_y or props.lk_pref;
local lk_suffix = props.lk_suff_y or props.lk_suff;
 
if props.lk_y then -- if to be linked
if lk_prefix or lk_suffix then -- when prefix or suffix, [[prefix .. link .. suffix|label]]
year_text = make_wikilink ((lk_prefix or '') .. year_text .. (lk_suffix or ''), year_text);
else
year_text = make_wikilink (year_text); -- just year
end
end
return year_text;
if rows then
end
cols = math.ceil(12 / rows)
 
else
 
rows = math.ceil(12 / cols)
--[[--------------------------< G E T _ D I S P L A Y _ M O N T H >--------------------------------------------
 
returns month from argument or props with wikilink, prefix, suffix ...
 
argument mnum is nil when rendering stand-alone calendar
 
]]
 
local function get_display_month (mnum, props)
local month_text = mnum or props.month_num;
month_text = monthname[month_text];
 
local lk_prefix = props.lk_pref_m or props.lk_pref;
local lk_suffix = props.lk_suff_m or props.lk_suff;
 
if props['lk_m&y'] then -- stand-alone month calendars only
month_text = month_text .. ' ' .. props.year; -- composite month and year link
end
 
local yearcal = {}
if props.lk_m or props['lk_m&y'] then
table.insert(yearcal, '<table class="ycal">')
if lk_prefix or lk_suffix then -- when prefix or suffix, [[prefix .. link .. suffix|label]]
table.insert(yearcal, '<tr class="ycalhdr">')
month_text = make_wikilink ((lk_prefix or '') .. month_text .. (lk_suffix or ''), month_text);
table.insert(yearcal, '<th class="ycal" colspan="' .. cols .. '>' .. year .. '</th>')
else
for r = 1, rows do
month_text = make_wikilink (month_text); -- just month name or composite month/year
table.insert(yearcal, '<tr class="ycal" style="vertical-align:top;">')
end
for c = 1, cols do
end
mnum = cols * (r - 1) + c
if mnum < 13 then
return month_text;
table.insert(yearcal, '<td class="ycal">' .. displaymonth(props, mnum) .. '</td>')
end
else
 
table.insert(yearcal, '&nbsp;')
 
--[[--------------------------< G E T _ D I S P L A Y _ D A Y >------------------------------------------------
 
returns day with wikilink (month and day), link prefix, link suffix ... (text doesn't get prefix / suffix)
 
]]
 
local function get_display_day (day_text, mnum, props)
local lk_prefix = props.lk_pref_d or props.lk_pref;
local lk_suffix = props.lk_suff_d or props.lk_suff;
 
if props.lk_d then
local link_text = (lk_prefix or '') .. monthname[mnum] .. ' ' .. day_text .. (lk_suffix or '');
day_text = make_wikilink (link_text, day_text);
end
return day_text;
end
 
 
--[[--------------------------< R E P E A T _ T A G S >--------------------------------------------------------
 
create <tag> ... </tag>... string to be included into another tag as :wikitext(...)
 
items is a table of items, each of which will be wrapped in <tag>...</tag>
options is a table of optional class, css, and attribute settings for these tags
options.attr is a table of attribute / value pairs: {['attribute'] = 'value', ...}
options.css is a table of attribute / value pairs: {['attribute'] = 'value', ...}
 
]]
 
local function repeat_tags (tag, items, options)
local tags = {}; -- table of <tag>...</tag> tag strings
local opt_attr = options.attr or {}; -- if options not supplied, use empty table
local css_opts = options.css or {};
for i, item in ipairs (items) do
local repeat_tag = mw.html.create (tag); -- new td object
repeat_tag
:addClass (options.class)
:attr (opt_attr)
:css (css_opts)
:wikitext (item) -- the item to be wrapped in <tag>...</tag>
:done() -- close <td>
table.insert (tags, tostring (repeat_tag)); -- make a string of this object
end
 
return table.concat (tags); -- concatenate them all together
end
 
 
--[[--------------------------< G E T _ R O W _ D A T E S >----------------------------------------------------
 
gets a week (row) of calendar dates each in its own <td>...</td>; inserts iso week number <td> tag ahead of column 1
when props.iso_wk true.
 
]]
 
local function get_row_dates (firstday, mnum, row, props)
local options = {['class']='mcal'}; -- table of otions for these td tags
local td_items = {}; -- table of <td>...</td> tag strings
local result = {};
local hilite;
local hilite_two;
for col = 1, 7 do
local dom = 7 * (row-1) + col + 1 - firstday -- calculate day of month for row/col position
local day;
if props.iso_wk and 1 == col then -- when column 1, insert iso week number <td> ahead of first 'dom'
local iso_wk = lang_obj:formatDate ('W', props.year .. '-' .. mnum .. '-' .. ((1 > dom) and 1 or dom));
local css_opts = props.wknum_color and {['background'] = props.wknum_color} or {};
table.insert (result, repeat_tags ('td', {iso_wk}, {['class']='mcal_iso', ['css'] = css_opts}));
end
if dom < 1 or dom > daysinmonth[mnum] then
day = "&nbsp;" -- before or after month, blank cell
else
day = get_display_day (dom, mnum, props); -- make wikilinks from month and day if required
end
 
if props.today then -- highlight today's date when displayed
if (props.year == props.this_ynum) and (mnum == props.this_mnum) and (dom == props.this_dnum) then
hilite = col;
end
end --cols
if props.aday then -- highlight arbitrary date when displayed
table.insert(yearcal, '</tr>')
if (props.year == props.this_ynum) and (mnum == props.this_mnum) and (dom == props.this_dnum) then
hilite_two = col;
end
end
table.insert (td_items, day);
end
 
table.insert(yearcal, '</table>')
for i, td_item in ipairs (td_items) do
return table.concat(yearcal, '\n')
if i == hilite then
table.insert (result, repeat_tags ('td', {td_item}, {['class']='mcal', ['css'] = {['background-color'] = props.today_color or '#cfc'}}));
else
if i == hilite_two then
table.insert (result, repeat_tags ('td', {td_item}, {['class']='mcal', ['css'] = {['background-color'] = props.aday_color or '#cfc'}}));
end
table.insert (result, repeat_tags ('td', {td_item}, options));
end
end
 
return table.concat (result);
end
 
 
local function calendar(props)
--[[--------------------------< G E T _ W E E K _ D A Y _ H D R >----------------------------------------------
-- local year = args.year or thisyear
 
-- local year = args.year
create header row of day-of-week abbreviations with title attributes
-- local month = props.month
 
-- if month then
]]
-- local mnum = tonumber(month)
 
-- if not mnum then
local function get_week_day_hdr (props)
-- if month == "current" then
local headers = {};
-- mnum = thismonth
local css_opts = props.week_color and {['background'] = props.week_color} or {}
-- year = thisyear
 
-- elseif month == "last" then
if props.iso_wk or props.iso then
-- mnum = thismonth - 1
-- if mnum == 0props.iso_wk then
table.insert (headers, repeat_tags ('th', {'Wk'}, {['class']='mcal', ['attr']={['title'] = 'ISO week number'}, ['css'] = css_opts})); -- iso week header
-- mnum = 12
end
-- year = thisyear - 1
for i, abbr in ipairs (iso_dayabbr) do
-- end
table.insert (headers, repeat_tags ('th', {iso_dayabbr[i]}, {['class']='mcal', ['attr']={['title'] = iso_dayname[i]}, ['css'] = css_opts}));
-- elseif month == "next" then
end
-- mnum = thismonth + 1
-- if mnum == 13 then
-- mnum = 1
-- year = thisyear + 1
-- end
-- else
-- mnum = monthnumber[month:sub(1,3)] or thismonth
-- end
-- end
-- args.year = year
if props.month then
-- if mnum > 0 and mnum <13 then
props.show_year = true; -- show year in individual month calendars
return displaymonth(props, props.month);
-- return displaymonth(props, mnum)
-- else
-- return displayyear(props)
-- end
else
for i, abbr in ipairs (dayabbr) do
-- args.year = year
table.insert (headers, repeat_tags ('th', {dayabbr[i]}, {['class']='mcal', ['attr']={['title'] = dayname[i]}, ['css'] = css_opts}));
return displayyear(props)
end
end
 
return table.concat (headers);
end
 
 
--------------------------------------------------
--[[--------------------------< G E T _ M O N T H _ H D R >----------------------------------------------------
--[[
 
Sakamoto's method: ISO date
create main header row for month calendars, with or without year and with or without previous / next links
returns day name or nil if bad arguments
 
--]]
]]
function p.dayofweek(frame)
 
local isodate = mw.text.trim(frame.args[1] or "")
local function get_month_hdr (mnum, props)
local y, m, d = isodate:match("(%d+)%p(%d+)%p(%d+)")
local dowresult = dayofweek(y, m, d){};
local prev = '';
if not dow then return "" end
local next = '';
return dayname[dow]
local hdr_year = '';
local col_span = (props.iso_wk and 8) or 7; -- assume no prev/next
 
if not props.hide_year and props.month_num then -- props.month_num has value only for stand-alone month calendars
hdr_year = get_display_year (props); -- if to be shown, add wikilink, etc when required
end
 
if props.prevnext then
prev = monthname[(0 < mnum-1) and mnum-1 or 12];
next = monthname[(13 > mnum+1) and mnum+1 or 1];
 
if is_set (hdr_year) then
prev = prev .. ' ' .. ((0 < mnum-1) and hdr_year or hdr_year-1); -- january-1 = december previous year
next = next .. ' ' .. ((13 > mnum+1) and hdr_year or hdr_year+1); -- december+1 = january next year
end
local link_text = (props.lk_pref_mprev or '') .. prev .. (props.lk_suff_mprev or '')
prev = make_wikilink (link_text, '<<');
link_text = (props.lk_pref_mnext or '') .. next .. (props.lk_suff_mnext or '')
next = make_wikilink (link_text, '>>');
 
table.insert (result, repeat_tags ('td', {prev}, {['css']={['text-align']='center'}})); -- insert prev now, insert next later
col_span = col_span - 2; -- narrow the month year <th>
end
 
if props['lk_m&y'] then -- for composite links
table.insert (result, repeat_tags ('th', {get_display_month (mnum, props)}, {['class']='mcal', ['attr']={['colspan']=col_span}}));
else
table.insert (result, repeat_tags ('th', {get_display_month (mnum, props) .. ' ' .. hdr_year}, {['class']='mcal', ['attr']={['colspan']=col_span}}));
end
 
if props.prevnext then
table.insert (result, repeat_tags ('td', {next}, {['css']={['text-align']='center'}}));
end
 
return table.concat (result);
end
 
 
--[[
--[[--------------------------< D I S P L A Y M O N T H >------------------------------------------------------
isleap returns "leap" if passed a leap year
 
otherwise returns nothing
generate the html to display a month calendar
 
]]
 
function p.isleap(frame)
local function display_month (mnum, props)
if isleap(frame.args[1]) then return "leap" end
if props.leap then daysinmonth[2] = 29 end
return ""
local firstday = day_of_week (props.year, mnum, 1, props.iso); -- get first day number of the first day of the month; 1 == Sunday
 
local table_css = {};
if props.m_center then
table_css = { -- TODO: make a separate class in styles.css?
['clear'] = 'both',
['margin-left'] = 'auto',
['margin-right'] = 'auto',
}
end
if props.month_num then -- month_num only set when doing stand-alone month calendars
table_css.border = '1px solid grey'; -- put this is styles.css as a separate class?
end
local month_cal = mw.html.create ('table');
month_cal
:addClass ('mcal' .. (props.m_float_r and ' floatright' or '')) -- float table right; leading space required to separate classes
:css (table_css)
:tag ('tr') -- for month name header
:addClass ('mcalhdr')
:css (props.title_color and {['background'] = props.title_color} or {})
:wikitext (get_month_hdr (mnum, props))
:done() -- close <tr>
:tag ('tr') -- for weekday header
:addClass ('mcalhdr')
:wikitext (get_week_day_hdr (props))
:done() -- close <tr>
 
local numrows = math.ceil ((firstday + daysinmonth[mnum] - 1) / 7); -- calculate number of rows needed for this calendar
for row = 1, numrows do
month_cal
:tag ('tr') -- for this week
:addClass ('mcal')
:wikitext (get_row_dates (firstday, mnum, row, props)); -- get dates for this week
end
month_cal:done() -- close <table>
--mw.log (tostring (month_cal))
return tostring (month_cal)
end
 
 
--[[
--[[--------------------------< G E T _ R O W _ C A L E N D A R S >--------------------------------------------
Main entry point for widget
 
--]]
create <td> ... </td>... string to be included into <tr>...</tr> as :wikitext(...)
function p.calendar(frame)
 
-- local args = {}
]]
-- for k, v in pairs(frame:getParent().args) do
 
-- if v ~= "" then args[k] = v end
local function get_row_calendars (cols, row_num, props)
-- end
local mnum; -- month number
-- for k, v in pairs(frame.args) do
local options = {['class']='ycal'}; -- table of otions for these td tags
-- if v ~= "" then args[k] = v end
local td_items = {}; -- table of <td>...</td> tag strings
-- end
local args=getArgs (frame);
local cal_props = {}; -- separate calendar properties table to preserve arguments as originally provided
for col_num = 1, cols do
cal_props.year = args.year and tonumber(args.year) or thisyear;
mnum = cols * (row_num - 1) + col_num -- calculate month number from row and column values
if mnum < 13 then -- some sort of error return if ever 13+?
table.insert (td_items, display_month (mnum, props)); -- get a calendar for month number mnum
end
end
 
return repeat_tags ('td', td_items, options)
end
 
 
--[[--------------------------< G E T _ Y E A R _ H E A D E R >------------------------------------------------
 
create html header for yearly calendar;
 
]]
 
local function get_year_header (props)
local css_opts = {};
if props.hide_year then -- for accesibility, when |hide_year=yes
css_opts['display'] = 'none'; -- use css to hide the year header (but not when |title= has a value)
end
local header = mw.html.create('tr');
header
:addClass ('ycalhdr')
:tag ('th')
:addClass ('ycal')
:css(css_opts)
:attr ('colspan', props.cols)
:wikitext (props.title or get_display_year (props)); --
return tostring (header)
end
 
 
--[[--------------------------< D I S P L A Y _ Y E A R >------------------------------------------------------
 
create a twelve-month calendar; default is 4 columns × 3 rows
 
]]
 
local function display_year(props)
local year = props.year
local cols = props.cols
local rows = math.ceil (12 / cols);
local mnum;
local year_cal = mw.html.create('table');
year_cal
:addClass ('ycal' .. (props.y_float_r and ' floatright' or '')) -- float table right; leading space required to separate classes
:css (props.y_center and {['clear'] = 'both', ['margin-left'] = 'auto', ['margin-right'] = 'auto'} or {}) -- centers table; TODO: add to styles.css?
:wikitext (get_year_header(props)); -- get year header if not hidden
 
for row_num = 1, rows do
year_cal
:tag('tr')
:addClass ('ycal')
:wikitext(get_row_calendars (cols, row_num, props)) -- get calendars for this row each wrapped in <td>...</td> tags as wikitext for this <tr>...</tr>
end
year_cal:done() -- close <table>
--mw.log (tostring (year_cal))
return tostring (year_cal)
end
 
 
--[[--------------------------< _ C A L E N D A R >------------------------------------------------------------
 
module entry point. args is the parent frame args table
 
]]
 
local function _calendar (args)
local props = {}; -- separate calendar properties table to preserve arguments as originally provided
local this_year_num = tonumber (lang_obj:formatDate ('Y'));
local this_month_num = tonumber (lang_obj:formatDate ('n'));
 
props.this_ynum = this_year_num; -- for highlighting 'today' in a calendar display
props.this_mnum = this_month_num;
props.this_dnum = tonumber (lang_obj:formatDate ('j'));
 
props.year = args.year and tonumber(args.year) or this_year_num;
if (1583 > props.year) or (1582 == props.year and 10 > props.month_num) then -- gregorian calendar only (1583 for yearly calendar because gregorian started in October of 1582)
props.year = this_year_num; -- so use this year
end
 
props.leap = is_leap (props.year)
props.title = args.title; -- year calendar title
 
props.cols = tonumber(args.cols or 4); -- yearly calendar number of columns
if 1 > props.cols or 12 < props.cols then
props.cols = 4;
end
if args.month then
local mnum = tonumber(args.month)
if not mnum then -- month provided as some sort of text string
if args.month == "current" then
props.month_num = this_month_num
-- mnum = thismonth
-- props.year = thisyearthis_year_num
cal_props.month = thismonth
cal_props.year = thisyear
elseif args.month == "last" then
mnum = thismonththis_month_num - 1
if mnum == 0 then
props.month_num = 12 -- december last year
-- mnum = 12
-- props.year = thisyearthis_year_num - 1 -- last year
cal_props.month = 12 -- december last year
cal_props.year = thisyear - 1 -- last year
else
cal_propsprops.monthmonth_num = mnum; -- previous month
end
elseif args.month == "next" then
mnum = thismonththis_month_num + 1
if mnum == 13 then
props.month_num = 1 -- january next year
-- mnum = 1
-- props.year = thisyearthis_year_num + 1 -- next year
cal_props.month = 1 -- january next year
cal_props.year = thisyear + 1 -- next year
else
cal_propsprops.monthmonth_num = mnum; -- next month
end
else
-- mnum = monthnumber[month:sub(1,3)] or thismonth
local good
good, cal_propsprops.monthmonth_num = pcall (lang_obj.formatDate, lang_obj, 'n', args.month);
if not good then
cal_propsprops.monthmonth_num = thismonththis_month_num
else
cal_propsprops.monthmonth_num = tonumber (cal_propsprops.monthmonth_num)
end
end
else
cal_propsprops.monthmonth_num = (13 > mnum and 0 < mnum) and mnum or thismonththis_month_num; -- month provided as a number
end
 
props.prevnext = 'yes' == (args.prevnext and args.prevnext:lower()); -- show previous / next links in month header only in single month calendars
 
if args.lk_pref_mprev or args.lk_suff_mprev then
props.lk_pref_mprev = args.lk_pref_mprev;
props.lk_suff_mprev = args.lk_suff_mprev;
props.prevnext = true;
end
 
if args.lk_pref_mnext or args.lk_suff_mnext then
props.lk_pref_mnext = args.lk_pref_mnext;
props.lk_suff_mnext = args.lk_suff_mnext;
props.prevnext = true;
end
 
props.m_center = 'center' == (args.float and args.float:lower()); -- month calendar positions; default is left
props.m_float_r = 'right' == (args.float and args.float:lower());
end
props.iso_wk = 'yes' == (args.iso_wk and args.iso_wk:lower()); -- show iso format with week numbers when true
props.iso = 'yes' == (args.iso and args.iso:lower()) or props.iso_wk; -- iso format without week number unless props.iso_wk true; always true when props.iso_wk true
args.lk = args.lk and args.lk:lower();
if args.lk and ({['yes']=1, ['m&y']=1, ['dm&y']=1, ['dm']=1, ['my']=1, ['dy']=1, ['d']=1, ['m']=1, ['y']=1})[args.lk] then -- if valid keywords
if 'yes' == args.lk then -- all date components are individually linked
props.lk_d = true;
props.lk_m = true;
props.lk_y = true;
elseif 'm&y' == args.lk and props.month_num then -- stand-alone month calendars only; month and year as a single composite link
props['lk_m&y'] = true;
elseif 'dm&y' == args.lk and props.month_num then -- stand-alone month calendars only; month and year as a single composite link
props['lk_m&y'] = true;
props.lk_d = true;
else
props.lk_d = 'd' == args.lk:match ('d'); -- decode the keywords to know which components are to be linked
props.lk_m = 'm' == args.lk:match ('m');
props.lk_y = 'y' == args.lk:match ('y');
end
end
 
if not (props.title or props.lk_y or props['lk_m&y']) then
return calendar(cal_props)
props.hide_year = ('yes' == args.hide_year) or ('off' == args.show_year); -- year normally displayed; this hides year display but not when linked or replaced with title
end
 
props.lk_pref = args.lk_pref; -- prefix for all links except previous and next
props.lk_suff = args.lk_suff; -- suffix for all links except previous and next
 
for _, v in ipairs ({'y', 'm', 'd'}) do -- loop through calendar parts for link prefix and suffix parameters
props['lk_pref_' .. v] = args['lk_pref_' .. v] or args.lk_pref; -- set prefix values
props['lk_suff_' .. v] = args['lk_suff_' .. v] or args.lk_suff; -- set suffix values
if props['lk_pref_' .. v] or props['lk_suff_' .. v] then -- set the calendar link flags as necessary
props['lk_' .. v] = true;
end
end
if not (props.m_center or props.m_float_r) then -- these may aleady be set for stand-alone month calendar
props.y_center = 'center' == (args.float and args.float:lower());
props.y_float_r = 'right' == (args.float and args.float:lower());
end
 
props.today = 'yes' == (args.show_today and args.show_today:lower()); -- highlight today's date in calendars where it is displayed
props.today_color = args.today_color or args.today_colour;
props.aday = 'yes' == (args.show_a_day and args.show_a_day:lower()); -- highlight arbitrary date in calendars where it is displayed
props.aday_color = args.a_day_color or args.a_day_colour;
props.title_color = args.title_color or args.title_colour or args.color or args.colour;
props.week_color = args.week_color or args.week_colour or args.color or args.colour;
props.wknum_color = args.wknum_color or args.wknum_colour;
-- TODO: add all other args{} from template or invoke to props{} modified as appropriate
 
if props.month_num then -- set only when rendering stand-alone month calendar
return display_month (props.month_num, props);
else
return display_year (props);
end
end
 
 
--[[--------------------------< C A L E N D A R >--------------------------------------------------------------
return p
 
template entry point. All parameters are template parameters; there are no special invoke parameters
 
]]
 
local function calendar (frame)
local args=getArgs (frame);
return _calendar (args);
end
 
 
--[[--------------------------< E X P O R T E D F U N C T I O N S >------------------------------------------
]]
 
return {
calendar = calendar,
}