Module:TOCstyle

From Wikisource
Jump to navigation Jump to search

--[[
   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="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="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="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="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="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="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="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="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="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="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="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="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="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="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="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="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="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="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="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="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]]'
    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