Module:TOCstyle

--[[	This module (tentatively) implements 	Intended invocation method: 	Normal invocation via application of Template:TOCstyle

The intent of this module is to provide a higher-level "styling" facility to aid in the creation of standard tables-of-contents (TOCs) on (initially) the English WikiSource in a reasonably flexible fashion. To this end there are a number of internal configuration tables (future task: separate these into a configuration helper module if possible?)

All internal variables obeying the naming convention "...Tags" (e.g. "outerTags") designate two-element tables of strings containing HTML tags which shall be used to "wrap around" various output components. The first element content will open any required construct and the second element content will provide the necessary closing tags for that construct. --]] require('strict')

local p = {}

-- emit outputs a single item without detailed formatting. local function emit(args,index,use,para) --mw.log("emit exiting: index+use="..index.."+"..use.."\n") if type(use) ~= 'number' then use = 0 end return index+use, (args[index] or '') end

-- emit384 outputs a single item repeated 384 times. local function emit384(args,index,use,para) if type(use) ~= 'number' then use = 0 end return index+use, string.rep((args[index] or '.'),(args['leaderrepeat'] or 384)) end

-- fmtCell outputs a single table cell and applies simple formatting to it	local function fmtCell(args,index,use,para) local addl		-- somewhere to discard accountancy for arguments consumed by sub-process local cell = ''

-- mw.log("use, args[use]="..use..", "..args[use]) if para then if para.proc then addl, cell = para.proc(args,index,para.use,para.para) end if para.wrap then cell = para.wrap[1] .. cell .. para.wrap[2] end end --mw.log("fmtCell exiting: index+use+addl="..index.."+"..use.."+"..addl.."\n") if type(use) ~= 'number' then use = 0 end return index+use, cell end

-- fmtNCells outputs multiple table cells and applies individual formatting to each one local function fmtNCells(args,index,use,para) local row = ''

if para then local offset = 1 local colcount = table.getn(para)

while offset <= colcount do					local addl		-- somewhere to discard accountancy for arguments consumed by sub-process local cell = ''

if para[offset].proc then addl, cell = para[offset].proc(args,index+offset-1,para[offset].use,para[offset].para) end if para[offset].wrap then cell = para[offset].wrap[1] .. cell .. para[offset].wrap[2] row = row .. cell end offset = offset + 1 end end if type(use) ~= 'number' then use = 0 end return index+use, row end

local function isDemoSpace(demoSpace) local namespace = mw.title.getCurrentTitle.nsText

-- everything eligible for display in Page: namespace return (namespace == 'Page') or				(namespace == demoSpace) end

-- cdlSwrap outputs multiple table cells with individual formatting but closes wrapping only in demonstration name spaces local function cdlSwrap(args,index,use,para) local row = ''

if para then local offset = 1 local colcount = table.getn(para)

while offset <= colcount do					local addl		-- somewhere to discard accountancy for arguments consumed by sub-process local cell = ''

if para[offset].proc then addl, cell = para[offset].proc(args,index+offset-1,para[offset].use,para[offset].para) end if para[offset].wrap then cell = para[offset].wrap[1] .. cell if (para[offset].use ~= 'p') or isDemoSpace(args['demoSpace']) then cell = cell .. para[offset].wrap[2] end row = row .. cell end offset = offset + 1 end end if type(use) ~= 'number' then use = 0 end return index+use, row end

-- cdlEwrap outputs multiple table cells with individual formatting but opens wrapping only in demonstration name spaces local function cdlEwrap(args,index,use,para) local row = ''

if para then local offset = 1 local colcount = table.getn(para)

while offset <= colcount do					local addl		-- somewhere to discard accountancy for arguments consumed by sub-process local cell = ''

if para[offset].proc then addl, cell = para[offset].proc(args,index+offset-1,para[offset].use,para[offset].para) end if para[offset].wrap then if (para[offset].use ~= 'p') or isDemoSpace(args['demoSpace']) then cell = para[offset].wrap[1] .. cell end cell = cell .. para[offset].wrap[2] row = row .. cell end offset = offset + 1 end end if type(use) ~= 'number' then use = 0 end return index+use, row end

local function isnotempty(s) return s and s:match( '^%s*(.-)%s*$' ) ~= '' end

local function isRibbonAllowed(RibbonControl,RibbonRange,demoSpace) -- everything eligible for display in Page: namespace if isDemoSpace(demoSpace) then return true elseif isnotempty(RibbonRange) then return false elseif isnotempty(RibbonControl) then return false else return true end end

function p.toc(frame) local args = (frame.args[1] ~= nil) and frame.args or frame:getParent.args

local outerTags = { -- HTML tags to wrap around /any/ output; also serves as header/footer in page-crossing circumstances '', -- '$CSS$' will be substituted ' ' }

local otDefCSS = ' style="max-width:100%; margin:0; padding:0;"'	-- CSS attributes to apply to outerTags[1] if not explicitly overridden local otCptCSS = ' style="max-width:100%; display: table; margin:0 auto 0 auto; padding:0;"'	-- alternate, "compact" CSS attributes for outerTags[1] use

local rowTags = { -- HTML tags to wrap around /each/ row: does not include columnar formatting '', '' }

local detailTags = { -- additional HTML tags to wrap around each row which may require more detailed formatting ' '	}

local ctrCellTags = { -- additional HTML tags to wrap around a centred table cell '', ' '	}

local jstCellTags = { -- additional HTML tags to wrap around a justified table cell '', ' '	}

local rgtCellTags = { -- additional HTML tags to wrap around a right-aligned table cell '', ' '	}

local hi1CellTags = { -- additional HTML tags to wrap around a "hanging indent" table cell '', ' '	}

local hi2doTags = { -- additional HTML tags to wrap around a large "hanging indent/dot leader" table cell '' .. ' ' ..		'', '  ' .. '' .. '' .. string.rep((args['leadersym'] or '.'), (args['leaderrepeat'] or 384)) .. '  '	}

local hi23CellTags = { -- additional HTML tags to wrap around a indented "hanging indent" table cell '', ' '	}

local hi23sCelTags = { -- additional HTML tags to wrap around a initial portion of indented "hanging indent" table cell ' ',	-- always output ' <td style="width:2em;text-align:right;vertical-align:bottom;"> '							-- Page/demo only }

local hi23eCelTags = { -- additional HTML tags to wrap around terminal portion of indented "hanging indent" table cell '<td style="padding-left:5em;text-indent:0;text-align:justify;"> ',				-- Page/demo only ' '																							-- always output }

local hi23doTags = { -- additional HTML tags to wrap around a indented "hanging indent/dot leader" table cell '<td style="position:relative;"> ' .. '<span style="color:#202122;background:' .. (args['leaderbgcolour'] or args['leaderbgcolor'] or 'white') ..			';padding:0 0.5em 0 0;position:relative;text-align:justify;z-index:2;">', ' <div style="color:#202122;background:' .. (args['leaderbgcolour'] or args['leaderbgcolor'] or 'white') ..			';position:absolute;left:0;bottom:0;width:5em;height:1em;z-index:1;"> ' .. '<div style="overflow:hidden;position:absolute;right:0;bottom:0;text-align:right;white-space:nowrap;width:100%;z-index:0;">' .. '<span style="float:left;letter-spacing:' .. (args['leaderspacing'] or '4px') .. ';">' .. string.rep((args['leadersym'] or '.'),(args['leaderrepeat'] or 384)) .. '  '	}

local hi23edoTags = { -- additional HTML tags to wrap around a indented "hanging indent/dot leader" table cell '<td style="position:relative;"> ' .. '<span style="color:#202122;background:' .. (args['leaderbgcolour'] or args['leaderbgcolor'] or 'white') ..			';padding:0 0.5em 0 0;position:relative;text-align:justify;z-index:2;"> ', '  <div style="color:#202122;background:' .. (args['leaderbgcolour'] or args['leaderbgcolor'] or 'white') ..			';position:absolute;left:0;bottom:0;width:5em;height:1em;z-index:1;"> ' .. '<div style="overflow:hidden;position:absolute;right:0;bottom:0;text-align:right;white-space:nowrap;width:100%;z-index:0;">' .. '<span style="float:left;letter-spacing:' .. (args['leaderspacing'] or '4px') .. ';">' .. string.rep((args['leadersym'] or '.'),(args['leaderrepeat'] or 384)) .. '  '	}

local hi5CellTags = { -- additional HTML tags to wrap around a "wide hanging indent" table cell '<td style="padding-left:5em;text-indent:-5em;text-align:justify;">', ' '	}

local hi5doTags = { -- additional HTML tags to wrap around a wide "hanging indent/dot leader" table cell '<td style="position:relative;"> ' .. '<span style="color:#202122;background:' .. (args['leaderbgcolour'] or args['leaderbgcolor'] or 'white') ..			';padding:0 0.5em 0 0;position:relative;text-align:justify;z-index:2;">', ' <div style="color:#202122;background:' .. (args['leaderbgcolour'] or args['leaderbgcolor'] or 'white') ..			';position:absolute;left:0;bottom:0;width:5em;height:1em;z-index:1;"> ' .. '<div style="overflow:hidden;position:absolute;right:0;bottom:0;text-align:right;white-space:nowrap;width:100%;z-index:0;">' .. '<span style="float:left;letter-spacing:' .. (args['leaderspacing'] or '4px') .. ';">' .. string.rep((args['leadersym'] or '.'),(args['leaderrepeat'] or 384)) .. '  '	}

local hiNdoTags = { -- additional HTML tags to wrap around a wide "hanging indent/dot leader" table cell '<td style="position:relative;"><div style="padding-left:$DEPTH$;text-indent:-$DEPTH$;text-align:justify;">' .. '<span style="color:#202122;background:' .. (args['leaderbgcolour'] or args['leaderbgcolor'] or 'white') ..			';padding:0 0.5em 0 0;position:relative;text-align:justify;z-index:2;">', ' <div class="ws-noexport" style="color:#202122;background:' .. (args['leaderbgcolour'] or args['leaderbgcolor'] or 'white') ..			';position:absolute;left:0;bottom:0;width:$DEPTH$;height:1em;z-index:1;"> ' .. '<div class="ws-noexport" style="overflow:hidden;position:absolute;right:0;bottom:0;text-align:right;white-space:nowrap;width:100%;z-index:0;">' .. '<span style="float:left;letter-spacing:' .. (args['leaderspacing'] or '4px') .. ';">' .. string.rep((args['leadersym'] or '.'),(args['leaderrepeat'] or 384)) .. '  '	}

local hiNdosTags = { -- additional HTML tags to wrap around hanging-description portion of a wide "hanging indent/dot leader" table cell '<td style="position:relative;"><div style="padding-left:$DEPTH$;text-indent:-$DEPTH$;text-align:justify;">' .. '<span style="color:#202122;background:' .. (args['leaderbgcolour'] or args['leaderbgcolor'] or 'white') ..			';padding:0 0.5em 0 0;position:relative;text-align:justify;z-index:2;">', ' '	}

local hiNdoeTags = { -- additional HTML tags to wrap around undercut page portion of a wide "hanging indent/dot leader" table cell '<span style="color:#202122;background:' .. (args['leaderbgcolour'] or args['leaderbgcolor'] or 'white') ..			';float:right;padding:0 0 0 calc( $DEPTH$ + 0.5em );position:relative;text-align:right;white-space:nowrap;width:$PGWIDTH$;z-index:2;">', ' <div class="ws-noexport" style="color:#202122;background:' .. (args['leaderbgcolour'] or args['leaderbgcolor'] or 'white') ..			';position:absolute;left:0;bottom:0;width:$DEPTH$;height:1em;z-index:1;"> ' .. '<div class="ws-noexport" style="overflow:hidden;position:absolute;right:0;bottom:0;text-align:right;white-space:nowrap;width:100%;z-index:0;">' .. '<span style="float:left;letter-spacing:' .. (args['leaderspacing'] or '4px') .. ';">' .. string.rep((args['leadersym'] or '.'),(args['leaderrepeat'] or 384)) .. '  '	}

local hi72CellTags = { -- additional HTML tags to wrap around an indented "hanging indent" table cell with Page clearance '<td style="padding-left:8em;padding-right:2em;text-indent:-1em;text-align:justify;">', ' '	}

local unfCellTags = { -- additional HTML tags to wrap around an "unformatted" table cell ' ',			' '	}

local chprCellTags = { -- additional HTML tags to wrap around a right-aligned, minimal-width table cell '<td style="padding-right:1em;white-space:nowrap;width:5em;text-align:right;vertical-align:top;">', ' '	}

local chpr0CellTags = { -- additional HTML tags to wrap around a right-aligned (unpadded), minimal-width table cell '<td style="white-space:nowrap;width:5em;text-align:right;vertical-align:top;">', ' '	}

local chp2CellTags = { -- additional HTML tags to wrap around a indented, right-aligned, 3em-width table cell '<td style="padding-left:2em;padding-right:1em;white-space:nowrap;width:3em;text-align:right;vertical-align:top;">', ' '	}

local chpMCellTags = { -- additional HTML tags to wrap around a right-aligned, controlled-minimal-width table cell '<td style="padding-right:$PDWIDTH$;white-space:nowrap;width:$CHWIDTH$;text-align:right;vertical-align:top;">', ' '	}

local pagCellTags = { -- additional HTML tags to wrap around a "page number" table cell '<td style="white-space:nowrap;width:2em;text-align:right;vertical-align:bottom;">', ' '	}

local paPCellTags = { -- additional HTML tags to wrap around a controlled-width "page number" table cell '<td style="white-space:nowrap;width:$PGWIDTH$;text-align:right;vertical-align:bottom;">', ' '	}

local l12CellTags = { -- additional HTML tags to wrap around "left" component of runningheader 5-item table cell '<td style="width:12.5%;">', ' '	}

local l20CellTags = { -- additional HTML tags to wrap around "left" component of runningheader 4-item table cell '<td style="width:20%;">', ' '	}

local l33CellTags = { -- additional HTML tags to wrap around "left" component of runningheader 3-item table cell '<td style="width:33%;">', ' '	}

local c25CellTags = { -- additional HTML tags to wrap around "central" components of runningheader 5-item table cell '<td style="text-align:center;width:12.5%;">', ' '	}

local c30CellTags = { -- additional HTML tags to wrap around "central" components of runningheader 4-item table cell '<td style="text-align:center;width:20%;">', ' '	}

local c33CellTags = { -- additional HTML tags to wrap around "central" component of runningheader 3-item table cell '<td style="text-align:center;width:33%;">', ' '	}

local r12CellTags = { -- additional HTML tags to wrap around "right" component of runningheader 5-item table cell '<td style="text-align:right;width:12.5%;">', ' '	}

local r20CellTags = { -- additional HTML tags to wrap around "right" component of runningheader 4-item table cell '<td style="text-align:right;width:20%;">', ' '	}

local r33CellTags = { -- additional HTML tags to wrap around "right" component of runningheader 3-item table cell '<td style="text-align:right;width:33%;">', ' '	}

local dotoutTags = { -- additional HTML tags to wrap around "dot-leader" table cell '<td style="position:relative;"> ' .. '<span style="color:#202122;background:' .. (args['leaderbgcolour'] or args['leaderbgcolor'] or 'white') ..			';padding:0 0.5em 0 0;position:relative;text-align:justify;z-index:2;">', ' ' ..			'<div class="ws-noexport" style="overflow:hidden;position:absolute;right:0;bottom:0;text-align:right;white-space:nowrap;width:100%;z-index:0;">' .. '<span style="float:left;letter-spacing:' .. (args['leaderspacing'] or '4px') .. ';">' .. string.rep((args['leadersym'] or '.'),(args['leaderrepeat'] or 384)) .. '  '	}

local dotouSTags = { -- additional HTML tags to wrap around initial portion of "dot-leader" table cell '<td style="position:relative;"> ' .. '<span style="color:#202122;background:' .. (args['leaderbgcolour'] or args['leaderbgcolor'] or 'white') ..			';padding:0 0.5em 0 0;position:relative;text-align:justify;z-index:2;">', '  <td style="width:2em;text-align:right;vertical-align:bottom;"> ' }

local dotouETags = { -- additional HTML tags to wrap around terminal portion of "dot-leader" table cell '<td style="position:relative;"> ' .. '<span style="color:#202122;background:' .. (args['leaderbgcolour'] or args['leaderbgcolor'] or 'white') ..			';padding:0 0.5em 0 0;position:relative;text-align:justify;z-index:2;">', ' <div style="color:#202122;background:' .. (args['leaderbgcolour'] or args['leaderbgcolor'] or 'white') ..			';position:absolute;left:0;bottom:0;width:5em;height:1em;z-index:1;"> ' .. '<div class="ws-noexport" style="overflow:hidden;position:absolute;right:0;bottom:0;text-align:right;white-space:nowrap;width:100%;z-index:0;">' .. '<span style="float:left;letter-spacing:' .. (args['leaderspacing'] or '4px') .. ';">' .. string.rep((args['leadersym'] or '.'),(args['leaderrepeat'] or 384)) .. '  '	}

local dotldoTags = { -- additional HTML tags to wrap around configurable "dot-leader" table cell and content component span '<td style="position:relative;"> ' .. '<span style="color:#202122;background:' .. (args['leaderbgcolour'] or args['leaderbgcolor'] or 'white') ..			';padding:0 0.5em 0 0;position:relative;text-align:justify;z-index:2;">', ' '	}

local dotleaTags = { -- additional HTML tags to wrap around "dot-leader"/excess-filler table cell component span '<div class="ws-noexport" style="overflow:hidden;position:absolute;right:0;bottom:0;text-align:right;white-space:nowrap;width:100%;z-index:0;">' .. '<span style="float:left;letter-spacing:' .. (args['leaderspacing'] or '4px') .. ';">', '  '	}

local dotoPsTags = { -- additional HTML tags to wrap around first portion of "dot-leader" with embedded page table cell '<td style="position:relative;"> ' .. '<span style="color:#202122;background:' .. (args['leaderbgcolour'] or args['leaderbgcolor'] or 'white') ..			';padding:0 0.5em 0 0;position:relative;text-align:justify;z-index:2;">', ' '	}

local dotoPeTags = { -- additional HTML tags to wrap around final portion of "dot-leader" with embedded page table cell '<span style="color:#202122;background:' .. (args['leaderbgcolour'] or args['leaderbgcolor'] or 'white') ..			';float:right;padding:0 0 0 0.5em;position:relative;text-align:right;z-index:2;">', ' ' ..			'<div class="ws-noexport" style="overflow:hidden;position:absolute;right:0;bottom:0;text-align:right;white-space:nowrap;width:100%;z-index:0;">' .. '<span style="float:left;letter-spacing:' .. (args['leaderspacing'] or '4px') .. ';">' .. string.rep((args['leadersym'] or '.'),(args['leaderrepeat'] or 384)) .. '  '	}

local dec2Tags = { -- additional HTML tags to wrap around a right-aligned, minimal-width table cell '<td style="padding-right:1em;white-space:nowrap;width:1em;text-align:right;vertical-align:top;">', ' '	}

local modelTab = { ["D"] = {	-- default layout use	=1,			-- absorbs a single argument only wrap	=nil,			-- no enclosing structures required proc	=emit,		-- function to output standalone description with no separate page numbers para	=nil			-- no details required },			["DP"] = {	-- unformatted description; right-justified page layout use	=2,			-- absorbs two arguments wrap	=detailTags, -- table enclosing row proc	=fmtNCells,	-- create and apply tags to multiple cells para	={ {				-- Description: wrapped cell content but with no overt formatting applied use		=0,			-- fmtNCells discards this value wrap	=unfCellTags, proc	=emit, para	=nil },								{				-- Page: right-lower-aligned cell with content wraparound suppressed use		=0,			-- fmtNCells discards this value wrap	=pagCellTags, proc	=emit, para	=nil }					}			},			["H5P"] = {	-- wide hanging indented description; right-justified page layout use	=2,			-- absorbs two arguments wrap	=detailTags, -- table enclosing row proc	=fmtNCells,	-- create and apply tags to multiple cells para	={ {				-- Description: wrapped cell content but with no overt formatting applied use		=0,			-- fmtNCells discards this value wrap	=hi5CellTags, proc	=emit, para	=nil },								{				-- Page: right-lower-aligned cell with content wraparound suppressed use		=0,			-- fmtNCells discards this value wrap	=pagCellTags, proc	=emit, para	=nil }					}			},			["2H3P"] = {	-- indented hanging indented description; right-justified page layout use	=2,			-- absorbs two arguments wrap	=detailTags, -- table enclosing row proc	=fmtNCells,	-- create and apply tags to multiple cells para	={ {				-- Description: wrapped cell content but with no overt formatting applied use		=0,			-- fmtNCells discards this value wrap	=hi23CellTags, proc	=emit, para	=nil },								{				-- Page: right-lower-aligned cell with content wraparound suppressed use		=0,			-- fmtNCells discards this value wrap	=pagCellTags, proc	=emit, para	=nil }					}			},			["2H3P/s"] = {	-- indented hanging indented description (initial part; crosses page); right-justified page layout use	=1,			-- absorbs single argument wrap	=detailTags, -- table enclosing row proc	=cdlSwrap,	-- only close wrapping in Page: or demo name spaces para	={ {				-- Description: wrapped cell content but with no overt formatting applied use		='p',		-- flag wrap as namespace dependent to cdlSwrap wrap	=hi23sCelTags, proc	=emit, para	=nil }					}			},			["2H3P/e"] = {	-- indented hanging indented description (terminal part; crosses page); right-justified page layout use	=2,			-- absorbs two arguments wrap	=detailTags, -- table enclosing row proc	=cdlEwrap,	-- only open wrapping in Page: or demo name spaces para	={ {				-- Description: wrapped cell content but with no overt formatting applied use		='p',		-- flag wrap as namespace dependent to cdlEwrap wrap	=hi23eCelTags, proc	=emit, para	=nil },								{				-- Page: right-lower-aligned cell with content wraparound suppressed use		=0,			-- cdlEwrap always wraps this value wrap	=pagCellTags, proc	=emit, para	=nil }					}			},			["CDP"] = {	-- chapter + unformatted description followed right-justified page layout use	=3,			-- absorbs three arguments wrap	=detailTags, -- table enclosing row proc	=fmtNCells,	-- create and apply tags to multiple cells para	={ {				-- Chapter: upper-right-aligned within minimal-width column use		=0,			-- fmtNCells discards this value wrap	=chprCellTags, proc	=emit, para	=nil },								{				-- Description: wrapped cell content but with no overt formatting applied use		=0,			-- fmtNCells discards this value wrap	=unfCellTags, proc	=emit, para	=nil },								{				-- Page: right-lower-aligned cell with content wraparound suppressed use		=0,			-- fmtNCells discards this value wrap	=pagCellTags, proc	=emit, para	=nil }					}			},			["D.P"] = {	-- unformatted description followed by right-lower-dot leader; right-justified page layout use	=2,			-- absorbs two arguments wrap	=detailTags, -- table enclosing row proc	=fmtNCells,	-- create and apply tags to multiple cells para	={ {				-- Description: wrapped cell content but with no overt formatting applied use		=0,			-- fmtNCells discards this value wrap	=dotoutTags, proc	=emit, para	=nil },								{				-- Page: right-lower-aligned cell with content wraparound suppressed use		=0,			-- fmtNCells discards this value wrap	=pagCellTags, proc	=emit, para	=nil }					}			},			["H5.P"] = {	-- wide hanging indented description; right-justified page layout use	=2,			-- absorbs two arguments wrap	=detailTags, -- table enclosing row proc	=fmtNCells,	-- create and apply tags to multiple cells para	={ {				-- Description: wrapped cell content but with no overt formatting applied use		=0,			-- fmtNCells discards this value wrap	=hi5doTags, proc	=emit, para	=nil },								{				-- Page: right-lower-aligned cell with content wraparound suppressed use		=0,			-- fmtNCells discards this value wrap	=pagCellTags, proc	=emit, para	=nil }					}			},			["Hn.P"] = {	-- wide hanging indented description; right-justified page layout use	=2,			-- absorbs two arguments wrap	=detailTags, -- table enclosing row proc	=fmtNCells,	-- create and apply tags to multiple cells para	={ {				-- Description: wrapped cell content but with no overt formatting applied use		=0,			-- fmtNCells discards this value wrap	=hiNdoTags, proc	=emit, para	=nil },								{				-- Page: right-lower-aligned cell with content wraparound suppressed use		=0,			-- fmtNCells discards this value wrap	=pagCellTags, proc	=emit, para	=nil }					}			},			["Hn.upP"] = {	-- wide hanging indented description; undercut controlled-width right-justified page layout use	=2,			-- absorbs two arguments wrap	=detailTags, -- table enclosing row proc	=fmtNCells,	-- create and apply tags to multiple cells para	={ {				-- Description: wrapped cell content but with no overt formatting applied use		=0,			-- fmtNCells discards this value wrap	=hiNdosTags, proc	=emit, para	=nil },								{				-- Page: undercut controlled-width right-lower-aligned cell with content wraparound suppressed use		=0,			-- fmtNCells discards this value wrap	=hiNdoeTags, proc	=emit, para	=nil }					}			},			["2H3.P"] = {	-- indented hanging indented description; right-justified page layout use	=2,			-- absorbs two arguments wrap	=detailTags, -- table enclosing row proc	=fmtNCells,	-- create and apply tags to multiple cells para	={ {				-- Description: wrapped cell content but with no overt formatting applied use		=0,			-- fmtNCells discards this value wrap	=hi23doTags, proc	=emit, para	=nil },								{				-- Page: right-lower-aligned cell with content wraparound suppressed use		=0,			-- fmtNCells discards this value wrap	=pagCellTags, proc	=emit, para	=nil }					}			},			["2H3.P/s"] = {	-- indented hanging indented description (initial part; crosses page); right-justified page layout use	=1,			-- absorbs single argument wrap	=detailTags, -- table enclosing row proc	=cdlSwrap,	-- only close wrapping in Page: or demo name spaces para	={ {				-- Description: wrapped cell content but with no overt formatting applied use		='p',		-- flag wrap as namespace dependent to cdlSwrap wrap	=hi23sCelTags, proc	=emit, para	=nil }					}			},			["2H3.P/e"] = {	-- indented hanging indented description (terminal part; crosses page); right-justified page layout use	=2,			-- absorbs two arguments wrap	=detailTags, -- table enclosing row proc	=cdlEwrap,	-- only open wrapping in Page: or demo name spaces para	={ {				-- Description: wrapped cell content but with no overt formatting applied use		='p',		-- flag wrap as namespace dependent to cdlEwrap wrap	=hi23edoTags, proc	=emit, para	=nil },								{				-- Page: right-lower-aligned cell with content wraparound suppressed use		=0,			-- cdlEwrap always wraps this value wrap	=pagCellTags, proc	=emit, para	=nil }					}			},			["D?P"] = {	-- unformatted description followed by right-lower-dot selectable symbol leader; right-justified page layout use	=3,			-- absorbs three arguments wrap	=detailTags, -- table enclosing row proc	=fmtNCells,	-- create and apply tags to multiple cells para	={ {				-- Description followed by symbol-selectable leader in same table cell use		=0,			-- fmtNCells discards this value wrap	=dotldoTags, proc	=emit, para	=nil },								{				-- second argument: leader symbol to be repeated use		=0,			-- fmtNCells discards this value wrap	=dotleaTags, proc	=emit384, para	=nil },								{				-- Page: right-lower-aligned cell with content wraparound suppressed use		=0,			-- fmtNCells discards this value wrap	=pagCellTags, proc	=emit, para	=nil }							}			},			["CD.P"] = {	-- chapter + unformatted description followed by right-lower-dot leader; right-justified page layout use	=3,			-- absorbs three arguments wrap	=detailTags, -- table enclosing row proc	=fmtNCells,	-- create and apply tags to multiple cells para	={ {				-- Chapter: right-aligned within minimal-width column use		=0,			-- fmtNCells discards this value wrap	=chprCellTags, proc	=emit, para	=nil },								{				-- Description: wrapped cell content but with no overt formatting applied use		=0,			-- fmtNCells discards this value wrap	=dotoutTags, proc	=emit, para	=nil },								{				-- Page: right-lower-aligned cell with content wraparound suppressed use		=0,			-- fmtNCells discards this value wrap	=pagCellTags, proc	=emit, para	=nil }					}			},			["CD.uP"] = {	-- chapter + unformatted description followed by right-lower-dot leader; right-justified (undercut) page layout use	=3,			-- absorbs three arguments wrap	=detailTags, -- table enclosing row proc	=fmtNCells,	-- create and apply tags to multiple cells para	={ {				-- Chapter: right-aligned within minimal-width column use		=0,			-- fmtNCells discards this value wrap	=chprCellTags, proc	=emit, para	=nil },								{				-- Description: wrapped cell content but with no overt formatting applied use		=0,			-- fmtNCells discards this value wrap	=dotoPsTags, proc	=emit, para	=nil },								{				-- Page: right-lower-aligned cell with content wraparound suppressed use		=0,			-- fmtNCells discards this value wrap	=dotoPeTags, proc	=emit, para	=nil }					}			},			["C5D.P"] = {	-- variant of CD.P with no padding following Chapter use	=3,			-- absorbs three arguments wrap	=detailTags, -- table enclosing row proc	=fmtNCells,	-- create and apply tags to multiple cells para	={ {				-- Chapter: right-aligned within minimal-width column use		=0,			-- fmtNCells discards this value wrap	=chpr0CellTags, proc	=emit, para	=nil },								{				-- Description: wrapped cell content but with no overt formatting applied use		=0,			-- fmtNCells discards this value wrap	=dotoutTags, proc	=emit, para	=nil },								{				-- Page: right-lower-aligned cell with content wraparound suppressed use		=0,			-- fmtNCells discards this value wrap	=pagCellTags, proc	=emit, para	=nil }					}			},			["2CD.P"] = {	-- chapter + unformatted description followed by right-lower-dot leader; right-justified page layout use	=3,			-- absorbs three arguments wrap	=detailTags, -- table enclosing row proc	=fmtNCells,	-- create and apply tags to multiple cells para	={ {				-- Chapter: right-aligned within minimal-width column use		=0,			-- fmtNCells discards this value wrap	=chp2CellTags, proc	=emit, para	=nil },								{				-- Description: wrapped cell content but with no overt formatting applied use		=0,			-- fmtNCells discards this value wrap	=dotoutTags, proc	=emit, para	=nil },								{				-- Page: right-lower-aligned cell with content wraparound suppressed use		=0,			-- fmtNCells discards this value wrap	=pagCellTags, proc	=emit, para	=nil }					}			},			["CD.P/s"] = {	-- chapter + unformatted description (presumed incomplete) use	=2,			-- absorbs two arguments wrap	=detailTags, -- table enclosing row proc	=cdlSwrap,	-- only close wrapping in Page: or demo name spaces para	={ {				-- Chapter: right-aligned within minimal-width column use		=0,			-- cdlSwrap always wraps this value wrap	=chprCellTags, proc	=emit, para	=nil },								{				-- Description: wrapped cell content but with no overt formatting applied use		='p',		-- flag wrap as namespace dependent to cdlSwrap wrap	=dotouSTags, proc	=emit, para	=nil }					}			},			["CD.P/e"] = {	-- (remainder of) unformatted description followed by right-lower-dot leader; right-justified page layout use	=2,			-- absorbs two arguments wrap	=detailTags, -- table enclosing row proc	=cdlEwrap,	-- only open wrapping in Page: or demo name spaces para	={ {				-- Description: wrapped cell content but with no overt formatting applied use		='p',		-- flag wrap as namespace dependent to cdlEwrap wrap	=dotouETags, proc	=emit, para	=nil },								{				-- Page: right-lower-aligned cell with content wraparound suppressed use		=0,			-- cdlEwrap always outputs this portion wrap	=pagCellTags, proc	=emit, para	=nil }					}			},			["CH2.P"] = {	-- chapter + large hanging indented description followed by right-lower-dot leader; right-justified page layout use	=3,			-- absorbs three arguments wrap	=detailTags, -- table enclosing row proc	=fmtNCells,	-- create and apply tags to multiple cells para	={ {				-- Chapter: right-aligned within controlled minimal-width column use		=0,			-- fmtNCells discards this value wrap	=chprCellTags, proc	=emit, para	=nil },								{				-- Description: wrapped cell content but with no overt formatting applied use		=0,			-- fmtNCells discards this value wrap	=hi2doTags, proc	=emit, para	=nil },								{				-- Page: right-lower-aligned cell with content wraparound suppressed use		=0,			-- fmtNCells discards this value wrap	=pagCellTags, proc	=emit, para	=nil }					}			},			["mCHn.pP"] = {	-- controlled-width chapter + controlled-depth hanging indented description followed by right-lower-dot leader; controlled-width right-justified page layout use	=3,			-- absorbs three arguments wrap	=detailTags, -- table enclosing row proc	=fmtNCells,	-- create and apply tags to multiple cells para	={ {				-- Chapter: right-aligned within minimal-width column use		=0,			-- fmtNCells discards this value wrap	=chpMCellTags, proc	=emit, para	=nil },								{				-- Description: wrapped cell content but with no overt formatting applied use		=0,			-- fmtNCells discards this value wrap	=hiNdoTags, proc	=emit, para	=nil },								{				-- Page: right-lower-aligned cell with content wraparound suppressed use		=0,			-- fmtNCells discards this value wrap	=paPCellTags, proc	=emit, para	=nil }					}			},			["mCHn.upP"] = {	-- wide hanging indented description; undercut controlled-width right-justified page layout use	=3,			-- absorbs two arguments wrap	=detailTags, -- table enclosing row proc	=fmtNCells,	-- create and apply tags to multiple cells para	={ {				-- Chapter: right-aligned within minimal-width column use		=0,			-- fmtNCells discards this value wrap	=chpMCellTags, proc	=emit, para	=nil },								{				-- Description: wrapped cell content but with no overt formatting applied use		=0,			-- fmtNCells discards this value wrap	=hiNdosTags, proc	=emit, para	=nil },								{				-- Page: undercut controlled-width right-lower-aligned cell with content wraparound suppressed use		=0,			-- fmtNCells discards this value wrap	=hiNdoeTags, proc	=emit, para	=nil }					}			},			["l"] = {	-- left-align items only layout (same as "D" model) use	=1,			-- absorbs a single argument only wrap	=nil,			-- no enclosing structures required proc	=emit,		-- function to output standalone description with no separate page numbers para	=nil			-- no details required },			["c"] = {	-- centre single item only layout use	=1,				-- absorbs a single argument only wrap	=detailTags,	-- table enclosing row proc	=fmtCell,		-- create and apply tags to new table cell para	={ use		=0,			-- fmtCell discards this value wrap	=ctrCellTags, proc	=emit, para	=nil }			},			["j"] = {	-- justified single item only layout use	=1,				-- absorbs a single argument only wrap	=detailTags,	-- table enclosing row proc	=fmtCell,		-- create and apply tags to new table cell para	={ use		=0,			-- fmtCell discards this value wrap	=jstCellTags, proc	=emit, para	=nil }			},			["r"] = {	-- right-align single item only layout use	=1,				-- absorbs a single argument only wrap	=detailTags,	-- table enclosing row proc	=fmtCell,		-- create and apply tags to new table cell para	={ use		=0,			-- fmtCell discards this value wrap	=rgtCellTags, proc	=emit, para	=nil }			},			["h"] = {	-- hanging indent single item layout use	=1,				-- absorbs a single argument only wrap	=detailTags,	-- table enclosing row proc	=fmtCell,		-- create and apply tags to new table cell para	={ use		=0,			-- fmtCell discards this value wrap	=hi1CellTags, proc	=emit, para	=nil }			},			["7h2"] = {	-- wide indented hanging indent single item layout with page clearance use	=1,				-- absorbs a single argument only wrap	=detailTags,	-- table enclosing row proc	=fmtCell,		-- create and apply tags to new table cell para	={ use		=0,			-- fmtCell discards this value wrap	=hi72CellTags, proc	=emit, para	=nil }			},			["lcr"] = {	-- lookalike layout use	=3,			-- absorbs three arguments wrap	=detailTags, -- table enclosing row proc	=fmtNCells,	-- create and apply tags to multiple cells para	={ {				-- left component use		=0,			-- fmtNCells discards this value wrap	=l33CellTags, proc	=emit, para	=nil },								{				-- centred component use		=0,			-- fmtNCells discards this value wrap	=c33CellTags, proc	=emit, para	=nil },								{				-- right component use		=0,			-- fmtNCells discards this value wrap	=r33CellTags, proc	=emit, para	=nil }					}			},			["lr"] = {	-- Two columns: first is left-aligned, second is right-aligned use	=2,			-- absorbs two arguments wrap	=detailTags, -- table enclosing row proc	=fmtNCells,	-- create and apply tags to multiple cells para	={ {				-- left component use		=0,			-- fmtNCells discards this value wrap	=l33CellTags, proc	=emit, para	=nil },								{				-- right component use		=0,			-- fmtNCells discards this value wrap	=r33CellTags, proc	=emit, para	=nil }					}			},			["lccr"] = {	-- lookalike layout use	=4,			-- absorbs four arguments wrap	=detailTags, -- table enclosing row proc	=fmtNCells,	-- create and apply tags to multiple cells para	={ {				-- left component use		=0,			-- fmtNCells discards this value wrap	=l20CellTags, proc	=emit, para	=nil },								{				-- centred component use		=0,			-- fmtNCells discards this value wrap	=c30CellTags, proc	=emit, para	=nil },								{				-- centred component use		=0,			-- fmtNCells discards this value wrap	=c30CellTags, proc	=emit, para	=nil },								{				-- right component use		=0,			-- fmtNCells discards this value wrap	=r20CellTags, proc	=emit, para	=nil }					}			},			["lcccr"] = {	-- lookalike layout use	=5,			-- absorbs five arguments wrap	=detailTags, -- table enclosing row proc	=fmtNCells,	-- create and apply tags to multiple cells para	={ {				-- left component use		=0,			-- fmtNCells discards this value wrap	=l12CellTags, proc	=emit, para	=nil },								{				-- centred component use		=0,			-- fmtNCells discards this value wrap	=c25CellTags, proc	=emit, para	=nil },								{				-- centred component use		=0,			-- fmtNCells discards this value wrap	=c25CellTags, proc	=emit, para	=nil },								{				-- centred component use		=0,			-- fmtNCells discards this value wrap	=c25CellTags, proc	=emit, para	=nil },								{				-- right component use		=0,			-- fmtNCells discards this value wrap	=r12CellTags, proc	=emit, para	=nil }					}			},			["DD.P"] = {	-- unformatted description followed by right-lower-dot leader + right-aligned description; right-justified page layout use	=3,			-- absorbs three arguments wrap	=detailTags, -- table enclosing row proc	=fmtNCells,	-- create and apply tags to multiple cells para	={ {				-- Description: wrapped cell content but with no overt formatting applied use		=0,			-- fmtNCells discards this value wrap	=dotoutTags, proc	=emit, para	=nil },								{				-- Second Description:	right-aligned within minimal-width column use		=0,			-- fmtNCells discards this value wrap	=dec2Tags, proc	=emit, para	=nil },								{				-- Page: right-lower-aligned cell with content wraparound suppressed use		=0,			-- fmtNCells discards this value wrap	=pagCellTags, proc	=emit, para	=nil }					}			}	}

local needheader = true local needfooter = true local needbody = true local html = '' -- output buffer; initially empty local mainhtml = nil -- committed output buffer (in case demo space expectation diverges from 'html' above) local modelranges = {}	-- array of ([row]-->modelspec strings; initially empty	local ribbonranges = {} -- array of ([row]-->demospace directives; initially empty local styleranges = {}	-- array of ([row]-->row styling directives; initially empty

-- extract maximum unnamed argument index local cellcount = table.getn(args)

-- tracking if isnotempty(args['leadersym']) then html = html .. ''	end if isnotempty(args['leaderrepeat']) then html = html .. ''	end if isnotempty(args['leaderspacing']) then html = html .. ''	end if isnotempty(args['leaderbgcolor']) then html = html .. ''	end

if isnotempty(args['debugArgs']) then html = html .. '<p style="margin-left:0;text-indent:0;"> Raw Argument Dump ' end

-- compute the maximum cell index (Depressing: cannot trust table.getn in frame context) -- Also: dump argument details if 'debugArgs' selected -- Also: pass 1 to determine "range m to n" model specifications -- Also: pass 1 to determine "range m to n" pageribbon overrides for k, v in pairs( args ) do	-- pairs appears to access in hash order only(?) if isnotempty(args['debugArgs']) then -- I know: access args to determine whether to dump args! html = html .. ' args(' .. k .. ':type("' .. type(k) .. '"): contains [' .. v .. ']:type("' .. type(v) .. '")'			end

if type(k) == 'number' then if cellcount < k then cellcount = k				end elseif type(k) == 'string' then local rnglow local rnghigh

rnglow, rnghigh = k:match( '^%s*row(%d+)to(%d+)model%s*$' ) if rnglow == nil or rnghigh == nil then rnglow, rnghigh = k:match( '^%s*row(%d+)%-(%d+)model%s*$' ) end if rnglow and rnghigh then -- only if neither are nil if tonumber(rnglow) > tonumber(rnghigh) then	-- swap if order choice was perverse rnglow, rnghigh = rnghigh, rnglow end

for rrow = rnglow, rnghigh, 1 do							modelranges[rrow] = v					end end

rnglow, rnghigh = k:match( '^%s*row(%d+)to(%d+)pageribbon%s*$' ) if rnglow == nil or rnghigh == nil then rnglow, rnghigh = k:match( '^%s*row(%d+)%-(%d+)pageribbon%s*$' ) end if rnglow and rnghigh then -- only if neither are nil if tonumber(rnglow) > tonumber(rnghigh) then	-- swap if order choice was perverse rnglow, rnghigh = rnghigh, rnglow end

for rrow = rnglow, rnghigh, 1 do							ribbonranges[rrow] = v					end end

rnglow, rnghigh = k:match( '^%s*row(%d+)to(%d+)style%s*$' ) if rnglow == nil or rnghigh == nil then rnglow, rnghigh = k:match( '^%s*row(%d+)%-(%d+)style%s*$' ) end if rnglow and rnghigh then -- only if neither are nil if tonumber(rnglow) > tonumber(rnghigh) then	-- swap if order choice was perverse rnglow, rnghigh = rnghigh, rnglow end

for rrow = rnglow, rnghigh, 1 do							styleranges[rrow] = v					end end end end

if isnotempty(args['debugArgs']) then html = html .. ' '	end

-- Now, sadly the above process has to be largely repeated to: -- "correct" modelranges for "multiple single row" specifications -- "correct" ribbonranges for "multiple single row" overrides -- "correct" styleranges for "multiple single row" overrides for k, v in pairs( args ) do			if type(k) == 'string' then local extract = k:match( '^%s*row(%d+,.-%d+)model%s*$' )

while extract do -- only if valid content extracted local rrow

rrow, extract = extract:match( '^(%d+),?(.-%d-)$' ) if rrow then modelranges[tonumber(rrow)] = v					end end

extract = k:match( '^%s*row(%d+,.-%d+)pageribbon%s*$' )

while extract do -- only if valid content extracted local rrow

rrow, extract = extract:match( '^(%d+),?(.-%d-)$' ) if rrow then ribbonranges[tonumber(rrow)] = v					end end

extract = k:match( '^%s*row(%d+,.-%d+)style%s*$' )

while extract do -- only if valid content extracted local rrow

rrow, extract = extract:match( '^(%d+),?(.-%d-)$' ) if rrow then styleranges[tonumber(rrow)] = v					end end end end

if isnotempty(args['starting']) then needheader = true needfooter = false end

if isnotempty(args['continuing']) then needheader = false needfooter = false end

if isnotempty(args['completing']) then needheader = false needfooter = true end

if isnotempty(args['header']) then needheader = true needbody = false needfooter = false end

if isnotempty(args['footer']) then needheader = false needbody = false needfooter = true end

if needheader then local outerCSS = otDefCSS	-- prefill default

local classList = 'table-of-contents ws-summary'

if isnotempty(args['compact']) then outerCSS = otCptCSS		-- override with narrower centred layout if chosen end

if isnotempty(args['class']) then	-- prepend any additional CSS classes classList = classList .. ' ' .. args['class'] end

outerCSS = ' class="' .. classList .. '"' .. outerCSS

if isnotempty(args['width']) then	-- a specified width implies centring (auto left/right margins) will be needed -- probably silly (but not an error) to have selectedi "compact" option as well outerCSS = mw.ustring.gsub(outerCSS, 'margin:0;', 'margin:0 auto 0 auto;') outerCSS = mw.ustring.gsub(outerCSS, '"$', 'width:' .. args['width'] .. ';"') end

if isnotempty(args['style']) then	-- user styling will always be applied *after* defaults outerCSS = mw.ustring.gsub(outerCSS, '"$', args['style'] .. ';"') end

-- yes strictly html is empty at this point (but allow for debugging prefill) html = html .. mw.ustring.gsub(outerTags[1], '%$CSS%$', outerCSS) end

if cellcount~=0 then -- nothing whatsoever to do if no unnamed arguments presented

if needbody then local index = 1 local row = 0 local defmodel = 'D'

if isnotempty(args['model']) then defmodel = args['model'] end

while index <= cellcount do					mainhtml = nil

row =	row + 1

local model = defmodel local outRow = isRibbonAllowed(args['row' .. tostring(row) .. 'pageribbon'],							ribbonranges[row],							args['demoSpace'])

if modelranges[row] then model = modelranges[row] end

if isnotempty(args['row' .. tostring(row) .. 'model']) then model = args['row' .. tostring(row) .. 'model'] end

-- start a new row if outRow then local openTags = rowTags[1]

if isnotempty(args['row' .. tostring(row) .. 'style']) then openTags = mw.ustring.gsub(openTags, '">', args['row' .. tostring(row) .. 'style'] .. ';">') elseif styleranges[row] then openTags = mw.ustring.gsub(openTags, '">', styleranges[row] .. ';">') end

html = html .. openTags end

if modelTab[model] then if modelTab[model].wrap and outRow then html = html .. modelTab[model].wrap[1] end if modelTab[model].proc then local item

index, item = modelTab[model].proc(args,index,modelTab[model].use,modelTab[model].para)

if (modelTab[model].proc == cdlEwrap) and not isDemoSpace(args['demoSpace']) then html = '' -- restart HTML build if processing '.../e' model end

if outRow then html = html .. item end end if modelTab[model].wrap then

if (modelTab[model].proc == cdlSwrap) and not isDemoSpace(args['demoSpace']) then mainhtml = html -- preserve unclosed wrap state end

if outRow then html = html .. modelTab[model].wrap[2] end end else -- unsupported model specified? Just give up and issue first error observed return ' Invalid model: "' ..									model ..									'" apparently requested on behalf of row ' .. row .. '? '					end

-- terminate row if outRow then html = html .. rowTags[2] end end end end

if needfooter then html = html .. outerTags[2] end

-- generalised depth hanging indent/width of chapter, page if mainhtml then mainhtml = mw.ustring.gsub(mainhtml, '%$PDWIDTH%$', args['padding-width'] or '1em') mainhtml = mw.ustring.gsub(mainhtml, '%$CHWIDTH%$', args['chapter-width'] or '5em') mainhtml = mw.ustring.gsub(mainhtml, '%$DEPTH%$', args['depth'] or '5em') mainhtml = mw.ustring.gsub(mainhtml, '%$PGWIDTH%$', args['page-width'] or '2em') end html = mw.ustring.gsub(html, '%$PDWIDTH%$', args['padding-width'] or '1em') html = mw.ustring.gsub(html, '%$CHWIDTH%$', args['chapter-width'] or '5em') html = mw.ustring.gsub(html, '%$DEPTH%$', args['depth'] or '5em') html = mw.ustring.gsub(html, '%$PGWIDTH%$', args['page-width'] or '2em')

-- return generated html if isDemoSpace(args['demoSpace']) then return html else return mainhtml or html end end

return p