Toggle menu
Toggle personal menu
Not logged in
Your IP address will be publicly visible if you make any edits.

Module:Navplate: Difference between revisions

From CaelemsWiki
en>Alistair3149
No edit summary
m (36 revisions imported)
 
(14 intermediate revisions by one other user not shown)
Line 10: Line 10:
local origArgs = {}
local origArgs = {}
local root
local root
local header
local content


local function union(t1, t2)
local function union( t1, t2 )
    -- Returns the union of the values of two tables, as a sequence.
-- Returns the union of the values of two tables, as a sequence.
    local vals = {}
local vals = {}
    for k, v in pairs(t1) do
for k, v in pairs( t1 ) do
        vals[v] = true
vals[ v ] = true
    end
end
    for k, v in pairs(t2) do
for k, v in pairs( t2 ) do
        vals[v] = true
vals[ v ] = true
    end
end
    local ret = {}
local ret = {}
    for k, v in pairs(vals) do
for k, v in pairs( vals ) do
        table.insert(ret, k)
table.insert( ret, k )
    end
end
    return ret
return ret
end
end


Line 30: Line 32:
-- for the specified prefix. For example, if the prefix was 'data', and
-- for the specified prefix. For example, if the prefix was 'data', and
-- 'data1', 'data2', and 'data5' exist, it would return {1, 2, 5}.
-- 'data1', 'data2', and 'data5' exist, it would return {1, 2, 5}.
local function getArgNums(prefix)
local function getArgNums( prefix )
local nums = {}
local nums = {}
for k, v in pairs(args) do
for k, v in pairs( args ) do
local num = tostring(k):match('^' .. prefix .. '([1-9]%d*)$')
local num = tostring( k ):match( '^' .. prefix .. '([1-9]%d*)$' )
if num then table.insert(nums, tonumber(num)) end
if num then table.insert( nums, tonumber( num ) ) end
end
end
table.sort(nums)
table.sort( nums )
return nums
return nums
end
end


local function addRow(rowArgs, content)
local function addRow( rowArgs, content )
    -- Adds a row to the navplate, with either a header
-- Adds a row to the navplate, with either a header
    -- or a label/list combination.
-- or a label/list combination.
    if rowArgs.header then
if rowArgs.header then
        content
content
            :tag('div')
:tag( 'div' )
                :addClass('template-navplate__groupheader')
:addClass( 'template-navplate__groupheader' )
                :wikitext(rowArgs.header)
:wikitext( rowArgs.header )
    elseif rowArgs.list then
elseif rowArgs.list then
        local row = content:tag('div')
local row = content:tag( 'div' )
        row:addClass('template-navplate-item')
row:addClass( 'template-navplate-item' )
        row
row
            :tag('div')
:tag( 'div' )
            :addClass('template-navplate-item__label')
:addClass( 'template-navplate-item__label' )
                :wikitext(rowArgs.label)
:wikitext( rowArgs.label )
                :done()
:done()
       
 
        local list = row:tag('div')
local list = row:tag( 'div' )
        list
list
            :addClass('template-navplate-item__list')
:addClass( 'template-navplate-item__list' )
            :wikitext(rowArgs.list)
:wikitext( rowArgs.list )
    end
end
end
end


local function renderSubtitle(header)
local function renderTitle( header )
    if not args.subtitle then return end
local headerContent = mw.html.create( 'div' )
headerContent:addClass( 'template-navplate__headerContent' )


header
if not args.title then return end
:tag('div')
if args.subtitle then
:addClass('template-navplate__subtitle')
headerContent
:wikitext(args.subtitle)
:tag( 'div' )
end
:addClass( 'template-navplate__subtitle' )
 
:wikitext( args.subtitle )
local function renderTitle(header)
:done()
    if not args.title then return end
end
headerContent
:tag( 'div' )
:addClass( 'template-navplate__title' )
:wikitext( args.title )


header
header:node( headerContent )
:tag('div')
:addClass('template-navplate__title')
:wikitext(args.title)
end
end


local function renderRows(content)
local function renderRows( content )
    -- Gets the union of the header and list argument numbers,
-- Gets the union of the header and list argument numbers,
    -- and renders them all in order using addRow.
-- and renders them all in order using addRow.
    local rownums = union(getArgNums('header'), getArgNums('list'))
local rownums = union( getArgNums( 'header' ), getArgNums( 'list' ) )
    table.sort(rownums)
table.sort( rownums )
    for k, num in ipairs(rownums) do
for k, num in ipairs( rownums ) do
        addRow({
addRow( {
            header = args['header' .. tostring(num)],
header = args[ 'header' .. tostring( num ) ],
            label = args['label' .. tostring(num)],
label = args[ 'label' .. tostring( num ) ],
            list = args['list' .. tostring(num)]
list = args[ 'list' .. tostring( num ) ]
        },
},
        content)
content )
    end
end
end
end


-- If the argument exists and isn't blank, add it to the argument table.
-- If the argument exists and isn't blank, add it to the argument table.
-- Blank arguments are treated as nil to match the behaviour of ParserFunctions.
-- Blank arguments are treated as nil to match the behaviour of ParserFunctions.
local function preprocessSingleArg(argName)
local function preprocessSingleArg( argName )
if origArgs[argName] and origArgs[argName] ~= '' then
if origArgs[ argName ] and origArgs[ argName ] ~= '' then
args[argName] = origArgs[argName]
args[ argName ] = origArgs[ argName ]
end
end
end
end
Line 112: Line 116:
-- string, but only parses parameters in the "depend" table if the prefix
-- string, but only parses parameters in the "depend" table if the prefix
-- parameter is present and non-blank.
-- parameter is present and non-blank.
local function preprocessArgs(prefixTable, step)
local function preprocessArgs( prefixTable, step )
if type(prefixTable) ~= 'table' then
if type( prefixTable ) ~= 'table' then
error("Non-table value detected for the prefix table", 2)
error( 'Non-table value detected for the prefix table', 2 )
end
end
if type(step) ~= 'number' then
if type( step ) ~= 'number' then
error("Invalid step value detected", 2)
error( 'Invalid step value detected', 2 )
end
end


-- Get arguments without a number suffix, and check for bad input.
-- Get arguments without a number suffix, and check for bad input.
for i,v in ipairs(prefixTable) do
for i, v in ipairs( prefixTable ) do
if type(v) ~= 'table' or type(v.prefix) ~= "string" or
if type( v ) ~= 'table' or type( v.prefix ) ~= 'string' or
(v.depend and type(v.depend) ~= 'table') then
(v.depend and type( v.depend ) ~= 'table') then
error('Invalid input detected to preprocessArgs prefix table', 2)
error( 'Invalid input detected to preprocessArgs prefix table', 2 )
end
end
preprocessSingleArg(v.prefix)
preprocessSingleArg( v.prefix )
-- Only parse the depend parameter if the prefix parameter is present
-- Only parse the depend parameter if the prefix parameter is present
-- and not blank.
-- and not blank.
if args[v.prefix] and v.depend then
if args[ v.prefix ] and v.depend then
for j, dependValue in ipairs(v.depend) do
for j, dependValue in ipairs( v.depend ) do
if type(dependValue) ~= 'string' then
if type( dependValue ) ~= 'string' then
error('Invalid "depend" parameter value detected in preprocessArgs')
error( 'Invalid "depend" parameter value detected in preprocessArgs' )
end
end
preprocessSingleArg(dependValue)
preprocessSingleArg( dependValue )
end
end
end
end
Line 145: Line 149:
moreArgumentsExist = false
moreArgumentsExist = false
for i = a, a + step - 1 do
for i = a, a + step - 1 do
for j,v in ipairs(prefixTable) do
for j, v in ipairs( prefixTable ) do
local prefixArgName = v.prefix .. tostring(i)
local prefixArgName = v.prefix .. tostring( i )
if origArgs[prefixArgName] then
if origArgs[ prefixArgName ] then
-- Do another loop if any arguments are found, even blank ones.
-- Do another loop if any arguments are found, even blank ones.
moreArgumentsExist = true
moreArgumentsExist = true
preprocessSingleArg(prefixArgName)
preprocessSingleArg( prefixArgName )
end
end
-- Process the depend table if the prefix argument is present
-- Process the depend table if the prefix argument is present
-- and not blank, or we are processing "prefix1" and "prefix" is
-- and not blank, or we are processing "prefix1" and "prefix" is
-- present and not blank, and if the depend table is present.
-- present and not blank, and if the depend table is present.
if v.depend and (args[prefixArgName] or (i == 1 and args[v.prefix])) then
if v.depend and (args[ prefixArgName ] or (i == 1 and args[ v.prefix ])) then
for j,dependValue in ipairs(v.depend) do
for j, dependValue in ipairs( v.depend ) do
local dependArgName = dependValue .. tostring(i)
local dependArgName = dependValue .. tostring( i )
preprocessSingleArg(dependArgName)
preprocessSingleArg( dependArgName )
end
end
end
end
Line 168: Line 172:


local function parseDataParameters()
local function parseDataParameters()
preprocessArgs({
preprocessSingleArg( 'id' )
{prefix = 'header'},
preprocessSingleArg( 'subtitle' )
{prefix = 'list', depend = {'label'}},
preprocessSingleArg( 'title' )
}, 50)
preprocessArgs( {
{ prefix = 'header' },
{ prefix = 'list', depend = { 'label' } },
}, 50 )
end
end


local function _navplate()
local function _navplate()
root = mw.html.create('div')
root = mw.html.create( 'div' )
header = mw.html.create('div')
header = mw.html.create( 'div' )
content = mw.html.create('div')
content = mw.html.create( 'div' )


header
header
:addClass('template-navplate__header')
:addClass( 'template-navplate__header' )
:addClass( 'mw-collapsible-toggle' )
:attr( 'role', 'button' )
:attr( 'aria-owns', 'template-navplate__content' )
:tag( 'div' )
:addClass( 'citizen-ui-icon mw-ui-icon-wikimedia-collapse' )
:done()


content
content
:addClass('template-navplate__content')
:addClass( 'template-navplate__content' )
:addClass( 'mw-collapsible-content' )
:attr( 'id', 'template-navplate__content' )


renderSubtitle(header)
renderTitle( header )
renderTitle(header)
renderRows( content )
renderRows(content)


root
root
:addClass('template-navplate')
:addClass( 'template-navplate' )
:node(title)
:addClass( 'mw-collapsible' )
:node(content)
:attr( 'role', 'navigation' )
:node( header )
:node( content )
 
if args.id then root:attr( 'id', 'navplate-' .. args.id ) end


    return mw.getCurrentFrame():extensionTag{
return mw.getCurrentFrame():extensionTag {
name = 'templatestyles', args = { src = 'Module:Navplate/styles.css' }
name = 'templatestyles', args = { src = 'Module:Navplate/styles.css' }
} .. tostring(root)
} .. tostring( root )
end
end


-- If called via #invoke, use the args passed into the invoking template.
-- If called via #invoke, use the args passed into the invoking template.
-- Otherwise, for testing purposes, assume args are being passed directly in.
-- Otherwise, for testing purposes, assume args are being passed directly in.
function p.navplate(frame)
function p.navplate( frame )
    if frame == mw.getCurrentFrame() then
if frame == mw.getCurrentFrame() then
origArgs = frame:getParent().args
origArgs = frame:getParent().args
else
else
origArgs = frame
origArgs = frame
end
end
 
parseDataParameters()
parseDataParameters()
 
return _navplate()
return _navplate()
end
end


-- For calling via #invoke within a template
-- For calling via #invoke within a template
function p.navplateTemplate(frame)
function p.navplateTemplate( frame )
origArgs = {}
origArgs = {}
for k,v in pairs(frame.args) do origArgs[k] = mw.text.trim(v) end
for k, v in pairs( frame.args ) do origArgs[ k ] = mw.text.trim( v ) end
 
parseDataParameters()
parseDataParameters()


return _navplate()
return _navplate()
end
end
return p
return p

Latest revision as of 07:56, 29 July 2024

Module:Navplate implements the {{navplate}} template.


--------------------------------------------------------------------------------
-- Module:Navplate                                                            --
-- This module implements {{Navplate}}                                        --
-- Based on Module:Infobox                                                    --
-- This is a work in progress                                                 --
--------------------------------------------------------------------------------

local p = {}
local args = {}
local origArgs = {}
local root
local header
local content

local function union( t1, t2 )
	-- Returns the union of the values of two tables, as a sequence.
	local vals = {}
	for k, v in pairs( t1 ) do
		vals[ v ] = true
	end
	for k, v in pairs( t2 ) do
		vals[ v ] = true
	end
	local ret = {}
	for k, v in pairs( vals ) do
		table.insert( ret, k )
	end
	return ret
end

-- Returns a table containing the numbers of the arguments that exist
-- for the specified prefix. For example, if the prefix was 'data', and
-- 'data1', 'data2', and 'data5' exist, it would return {1, 2, 5}.
local function getArgNums( prefix )
	local nums = {}
	for k, v in pairs( args ) do
		local num = tostring( k ):match( '^' .. prefix .. '([1-9]%d*)$' )
		if num then table.insert( nums, tonumber( num ) ) end
	end
	table.sort( nums )
	return nums
end

local function addRow( rowArgs, content )
	-- Adds a row to the navplate, with either a header
	-- or a label/list combination.
	if rowArgs.header then
		content
			:tag( 'div' )
			:addClass( 'template-navplate__groupheader' )
			:wikitext( rowArgs.header )
	elseif rowArgs.list then
		local row = content:tag( 'div' )
		row:addClass( 'template-navplate-item' )
		row
			:tag( 'div' )
			:addClass( 'template-navplate-item__label' )
			:wikitext( rowArgs.label )
			:done()

		local list = row:tag( 'div' )
		list
			:addClass( 'template-navplate-item__list' )
			:wikitext( rowArgs.list )
	end
end

local function renderTitle( header )
	local headerContent = mw.html.create( 'div' )
	headerContent:addClass( 'template-navplate__headerContent' )

	if not args.title then return end
	if args.subtitle then
		headerContent
			:tag( 'div' )
			:addClass( 'template-navplate__subtitle' )
			:wikitext( args.subtitle )
			:done()
	end
	headerContent
		:tag( 'div' )
		:addClass( 'template-navplate__title' )
		:wikitext( args.title )

	header:node( headerContent )
end

local function renderRows( content )
	-- Gets the union of the header and list argument numbers,
	-- and renders them all in order using addRow.
	local rownums = union( getArgNums( 'header' ), getArgNums( 'list' ) )
	table.sort( rownums )
	for k, num in ipairs( rownums ) do
		addRow( {
				header = args[ 'header' .. tostring( num ) ],
				label = args[ 'label' .. tostring( num ) ],
				list = args[ 'list' .. tostring( num ) ]
			},
			content )
	end
end

-- If the argument exists and isn't blank, add it to the argument table.
-- Blank arguments are treated as nil to match the behaviour of ParserFunctions.
local function preprocessSingleArg( argName )
	if origArgs[ argName ] and origArgs[ argName ] ~= '' then
		args[ argName ] = origArgs[ argName ]
	end
end

-- Assign the parameters with the given prefixes to the args table, in order, in
-- batches of the step size specified. This is to prevent references etc. from
-- appearing in the wrong order. The prefixTable should be an array containing
-- tables, each of which has two possible fields, a "prefix" string and a
-- "depend" table. The function always parses parameters containing the "prefix"
-- string, but only parses parameters in the "depend" table if the prefix
-- parameter is present and non-blank.
local function preprocessArgs( prefixTable, step )
	if type( prefixTable ) ~= 'table' then
		error( 'Non-table value detected for the prefix table', 2 )
	end
	if type( step ) ~= 'number' then
		error( 'Invalid step value detected', 2 )
	end

	-- Get arguments without a number suffix, and check for bad input.
	for i, v in ipairs( prefixTable ) do
		if type( v ) ~= 'table' or type( v.prefix ) ~= 'string' or
			(v.depend and type( v.depend ) ~= 'table') then
			error( 'Invalid input detected to preprocessArgs prefix table', 2 )
		end
		preprocessSingleArg( v.prefix )
		-- Only parse the depend parameter if the prefix parameter is present
		-- and not blank.
		if args[ v.prefix ] and v.depend then
			for j, dependValue in ipairs( v.depend ) do
				if type( dependValue ) ~= 'string' then
					error( 'Invalid "depend" parameter value detected in preprocessArgs' )
				end
				preprocessSingleArg( dependValue )
			end
		end
	end

	-- Get arguments with number suffixes.
	local a = 1 -- Counter variable.
	local moreArgumentsExist = true
	while moreArgumentsExist == true do
		moreArgumentsExist = false
		for i = a, a + step - 1 do
			for j, v in ipairs( prefixTable ) do
				local prefixArgName = v.prefix .. tostring( i )
				if origArgs[ prefixArgName ] then
					-- Do another loop if any arguments are found, even blank ones.
					moreArgumentsExist = true
					preprocessSingleArg( prefixArgName )
				end
				-- Process the depend table if the prefix argument is present
				-- and not blank, or we are processing "prefix1" and "prefix" is
				-- present and not blank, and if the depend table is present.
				if v.depend and (args[ prefixArgName ] or (i == 1 and args[ v.prefix ])) then
					for j, dependValue in ipairs( v.depend ) do
						local dependArgName = dependValue .. tostring( i )
						preprocessSingleArg( dependArgName )
					end
				end
			end
		end
		a = a + step
	end
end

local function parseDataParameters()
	preprocessSingleArg( 'id' )
	preprocessSingleArg( 'subtitle' )
	preprocessSingleArg( 'title' )
	preprocessArgs( {
		{ prefix = 'header' },
		{ prefix = 'list',  depend = { 'label' } },
	}, 50 )
end

local function _navplate()
	root = mw.html.create( 'div' )
	header = mw.html.create( 'div' )
	content = mw.html.create( 'div' )

	header
		:addClass( 'template-navplate__header' )
		:addClass( 'mw-collapsible-toggle' )
		:attr( 'role', 'button' )
		:attr( 'aria-owns', 'template-navplate__content' )
		:tag( 'div' )
		:addClass( 'citizen-ui-icon mw-ui-icon-wikimedia-collapse' )
		:done()

	content
		:addClass( 'template-navplate__content' )
		:addClass( 'mw-collapsible-content' )
		:attr( 'id', 'template-navplate__content' )

	renderTitle( header )
	renderRows( content )

	root
		:addClass( 'template-navplate' )
		:addClass( 'mw-collapsible' )
		:attr( 'role', 'navigation' )
		:node( header )
		:node( content )

	if args.id then root:attr( 'id', 'navplate-' .. args.id ) end

	return mw.getCurrentFrame():extensionTag {
		name = 'templatestyles', args = { src = 'Module:Navplate/styles.css' }
	} .. tostring( root )
end

-- If called via #invoke, use the args passed into the invoking template.
-- Otherwise, for testing purposes, assume args are being passed directly in.
function p.navplate( frame )
	if frame == mw.getCurrentFrame() then
		origArgs = frame:getParent().args
	else
		origArgs = frame
	end

	parseDataParameters()

	return _navplate()
end

-- For calling via #invoke within a template
function p.navplateTemplate( frame )
	origArgs = {}
	for k, v in pairs( frame.args ) do origArgs[ k ] = mw.text.trim( v ) end

	parseDataParameters()

	return _navplate()
end

return p