Jump to content

Module:TOCstyle

From Wikisource

--[[
	This module (tentatively) implements {{TOCstyle}}
	Intended invocation method: {{#invoke:TOCstyle|toc}}
	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
			'<div$CSS$><ol style="list-style:none;margin:0; padding:0;">', -- '$CSS$' will be substituted
			'</ol></div>'
	}

	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
			'<li style="margin:0; padding:0;">',
			'</li>'
	}

	local detailTags = { -- additional HTML tags to wrap around each row which may require more detailed formatting
			'<table ' ..
			'style="border-collapse:collapse;border-spacing:0 0;display:inline-table;vertical-align:middle;width:100%;">' ..
			'<tr>',
			'</tr></table>'
	}

	local ctrCellTags = { -- additional HTML tags to wrap around a centred table cell
			'<td style="text-align:center;">',
			'</td>'
	}

	local jstCellTags = { -- additional HTML tags to wrap around a justified table cell
			'<td style="text-align:justify;">',
			'</td>'
	}

	local rgtCellTags = { -- additional HTML tags to wrap around a right-aligned table cell
			'<td style="text-align:right;">',
			'</td>'
	}

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

	local hi2doTags = {
		-- additional HTML tags to wrap around a large "hanging indent/dot leader" table cell
		'<td style="position:relative;">' ..
		'<div style="padding-left:2em;text-indent:-2em;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;">',
		'</span></div><div class="ws-noexport" style="color:#202122;background:' .. (args['leaderbgcolour'] or args['leaderbgcolor'] or 'white') ..
		';position:absolute;left:0;bottom:0;width:2em;height:1em;z-index:1;"></div>' ..
		'<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)) ..
		'</span></div></td>'
	}

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

	local hi23sCelTags = { -- additional HTML tags to wrap around a initial portion of indented "hanging indent" table cell
			'<td style="padding-left:5em;text-indent:-3em;text-align:justify;"><p>',	-- always output
			'</p></td><td style="width:2em;text-align:right;vertical-align:bottom;">&nbsp;</td>'							-- 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;"><p>',				-- Page/demo only
			'</p></td>'																							-- always output
	}

	local hi23doTags = { -- additional HTML tags to wrap around a indented "hanging indent/dot leader" table cell
			'<td style="position:relative;"><div style="padding-left:5em;text-indent:-3em;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;">',
			'</span></div><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>' ..
			'<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)) ..
			'</span></div></td>'
	}

	local hi23edoTags = { -- additional HTML tags to wrap around a indented "hanging indent/dot leader" table cell
			'<td style="position:relative;"><div style="padding-left:5em;text-indent:-3em;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;"><p>',
			'</p></span></div><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>' ..
			'<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)) ..
			'</span></div></td>'
	}

	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;">',
			'</td>'
	}

	local hi5doTags = { -- additional HTML tags to wrap around a wide "hanging indent/dot leader" table cell
			'<td style="position:relative;"><div style="padding-left:5em;text-indent:-5em;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;">',
			'</span></div><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>' ..
			'<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)) ..
			'</span></div></td>'
	}

	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;">',
			'</span></div><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>' ..
			'<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)) ..
			'</span></div></td>'
	}

	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;">',
			'</span>'
	}

	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;">',
			'</span></div><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>' ..
			'<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)) ..
			'</span></div></td>'
	}

	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;">',
			'</td>'
	}

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

	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;">',
			'</td>'
	}

	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;">',
			'</td>'
	}

	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;">',
			'</td>'
	}

	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;">',
			'</td>'
	}

	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;">',
			'</td>'
	}

	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;">',
			'</td>'
	}

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

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

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

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

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

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

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

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

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

	local dotoutTags = { -- additional HTML tags to wrap around "dot-leader" table cell
			'<td style="position:relative;"><div style="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;">',
			'</span></div>' ..
			'<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)) ..
			'</span></div></td>'
	}

	local dotouSTags = { -- additional HTML tags to wrap around initial portion of "dot-leader" table cell
			'<td style="position:relative;"><div style="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;">',
			'</span></div></td><td style="width:2em;text-align:right;vertical-align:bottom;">&nbsp;</td>'
	}

		local dotouETags = { -- additional HTML tags to wrap around terminal portion of "dot-leader" table cell
			'<td style="position:relative;"><div style="padding-left:5em;text-indent:0;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;">',
			'</span></div><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>' ..
			'<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)) ..
			'</span></div></td>'
	}

	local dotldoTags = { -- additional HTML tags to wrap around configurable "dot-leader" table cell and content component span
			'<td style="position:relative;"><div style="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;">',
			'</span></div>'
	}

	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') .. ';">',
			'</span></div></td>'
	}

	local dotoPsTags = { -- additional HTML tags to wrap around first portion of "dot-leader" with embedded page table cell
			'<td style="position:relative;"><div style="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;">',
			'</span>'
	}

	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;">',
			'</span></div>' ..
			'<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)) ..
			'</span></div></td>'
	}

	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;">',
			'</td>'
	}

	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"] = {	-- {{RunningHeader}} 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"] = {	-- {{RunningHeader}} 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"] = {	-- {{rh/5}} 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 .. '[[Category:Pages using a custom leader in TOC or Index content]]'
	end
	if isnotempty(args['leaderrepeat']) then
			html = html .. '[[Category:Pages using a custom leader repeat in TOC or Index content]]'
	end
	if isnotempty(args['leaderspacing']) then
			html = html .. '[[Category:Pages using a custom leader spacing in TOC or Index content]]\n'
	end
	if isnotempty(args['leaderbgcolor']) then
			html = html .. '[[Category:Pages using a custom leader color in TOC or Index content]]'
	end

	if isnotempty(args['debugArgs']) then
			html = html .. '<p style="margin-left:0;text-indent:0;"><strong>Raw Argument Dump</strong>'
	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 .. '<br/>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 .. '</p>'
	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 '<br/><strong class="error">Invalid model: "' ..
									model ..
									'" apparently requested on behalf of row ' ..
									row ..
									'?</strong>'
					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