模块:Navplate:修订间差异
来自INFWiki
更多操作
创建页面,内容为“-------------------------------------------------------------------------------- -- Module:Navplate -- -- This module implements {{Navplate}} -- -- Based on Module:Infobox -- -- This is a work in progress -- ------------------------------------------------------------…” |
无编辑摘要 |
||
| 第9行: | 第9行: | ||
local args = {} | local args = {} | ||
local origArgs = {} | local origArgs = {} | ||
local function union( t1, t2 ) | local function union( t1, t2 ) | ||
| 第17行: | 第14行: | ||
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 = {} | ||
| 第42行: | 第39行: | ||
end | end | ||
local function | --- Get the string of the <details> element | ||
--- TODO: Perhaps we should turn this into another module | |||
--- | |||
--- @param data table | |||
--- @param frame table | |||
--- @return string | |||
local function getDetailsHTML( data, frame ) | |||
local summary = frame:extensionTag { | |||
name = 'summary', | |||
content = data.summary.content, | |||
args = { | |||
class = data.summary.class | |||
} | |||
} | |||
local details = frame:extensionTag { | |||
name = 'details', | |||
content = summary .. data.details.content, | |||
args = { | |||
class = data.details.class, | |||
role = data.details.role, | |||
open = data.details.open or 'no' | |||
} | |||
} | |||
return details | |||
end | |||
--- @param rowArgs table | |||
--- @return mw.html | |||
local function getRowHTML( rowArgs ) | |||
local html = mw.html.create() | |||
-- 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 | ||
html | |||
: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 | ||
html | |||
:tag( 'div' ) | |||
:addClass( 'template-navplate-item' ) | |||
:tag( 'div' ) | :tag( 'div' ) | ||
:addClass( 'template-navplate-item__label' ) | :addClass( 'template-navplate-item__label' ) | ||
:wikitext( rowArgs.label ) | :wikitext( rowArgs.label ) | ||
:done() | :done() | ||
:tag( 'div' ) | |||
:addClass( 'template-navplate-item__list' ) | :addClass( 'template-navplate-item__list' ) | ||
:wikitext( rowArgs.list ) | :wikitext( rowArgs.list ) | ||
end | end | ||
return html | |||
end | end | ||
local function | |||
local | --- @return mw.html | ||
local function getTitleHTML() | |||
local html = mw.html.create( 'div' ) | |||
html:addClass( 'template-navplate__headerContent' ) | |||
if not args.title then return end | if not args.title then return end | ||
if args.subtitle then | if args.subtitle then | ||
html | |||
:tag( 'div' ) | :tag( 'div' ) | ||
:addClass( 'template-navplate__subtitle' ) | :addClass( 'template-navplate__subtitle' ) | ||
| 第78行: | 第106行: | ||
:done() | :done() | ||
end | end | ||
html | |||
:tag( 'div' ) | :tag( 'div' ) | ||
:addClass( 'template-navplate__title' ) | :addClass( 'template-navplate__title' ) | ||
:wikitext( args.title ) | :wikitext( args.title ) | ||
return html | |||
end | end | ||
local function | |||
--- @return mw.html | |||
local function getRowsHTML() | |||
local html = mw.html.create() | |||
-- 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 | for _, num in ipairs( rownums ) do | ||
html:node( getRowHTML( { | |||
header = args['header' .. tostring( num )], | |||
label = args['label' .. tostring( num )], | |||
list = args['list' .. tostring( num )] | |||
} ) ) | |||
end | end | ||
return html | |||
end | end | ||
| 第104行: | 第135行: | ||
-- 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 | ||
| 第133行: | 第164行: | ||
-- 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 | ||
| 第151行: | 第182行: | ||
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 | ||
| 第159行: | 第190行: | ||
-- 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 ) | ||
| 第182行: | 第213行: | ||
local function _navplate() | local function _navplate() | ||
local frame = mw.getCurrentFrame() | |||
local summaryHTML = mw.html.create() | |||
:tag( 'div' ) | :tag( 'div' ) | ||
:addClass( 'citizen-ui-icon mw-ui-icon-wikimedia-collapse' ) | :addClass( 'citizen-ui-icon mw-ui-icon-wikimedia-collapse' ) | ||
:done() | :done() | ||
:node( getTitleHTML() ) | |||
local contentHTML = mw.html.create( 'div' ) | |||
:addClass( 'template-navplate__content citizen-text-small' ) | |||
:addClass( | :node( getRowsHTML() ) | ||
: | |||
local output = getDetailsHTML( { | |||
details = { | |||
class = 'template-navplate', | |||
content = tostring( contentHTML ) | |||
}, | |||
summary = { | |||
class = 'template-navplate__header', | |||
content = tostring( summaryHTML ) | |||
} | |||
}, frame ) | |||
return | return frame:extensionTag { | ||
name = 'templatestyles', args = { src = 'Module:Navplate/styles.css' } | name = 'templatestyles', args = { src = 'Module:Navplate/styles.css' } | ||
} .. | } .. output | ||
end | end | ||
| 第231行: | 第255行: | ||
end | end | ||
-- Legacy method, do not use | |||
-- 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 | |||
-- For calling via other modules | |||
function p.fromData( data ) | |||
local directArgs = {} | |||
if not data or type( data ) ~= 'table' then | |||
-- TODO: Add error state | |||
else | |||
if data.title then | |||
directArgs.title = data.title | |||
end | |||
if data.subtitle then | |||
directArgs.subtitle = data.subtitle | |||
end | |||
if data.id then | |||
directArgs.id = data.id | |||
end | |||
if data.items and type( data.items ) == 'table' and #data.items > 0 then | |||
for i, item in ipairs( data.items ) do | |||
if type( item ) == 'table' then | |||
if item.label then | |||
directArgs['label' .. tostring( i )] = item.label | |||
end | |||
if item.pages then -- 'pages' from Manufacturers.lua maps to 'list' here | |||
directArgs['list' .. tostring( i )] = item.pages | |||
end | |||
if item.header then -- Also support 'header' if needed | |||
directArgs['header' .. tostring( i )] = item.header | |||
end | |||
end | |||
end | |||
else | |||
-- TODO: Add empty state to navplate | |||
end | |||
end | |||
return p.navplateTemplate( { args = directArgs } ) | |||
end | end | ||
return p | return p | ||
2025年8月11日 (一) 13:58的版本
--------------------------------------------------------------------------------
-- Module:Navplate --
-- This module implements {{Navplate}} --
-- Based on Module:Infobox --
-- This is a work in progress --
--------------------------------------------------------------------------------
local p = {}
local args = {}
local origArgs = {}
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
--- Get the string of the <details> element
--- TODO: Perhaps we should turn this into another module
---
--- @param data table
--- @param frame table
--- @return string
local function getDetailsHTML( data, frame )
local summary = frame:extensionTag {
name = 'summary',
content = data.summary.content,
args = {
class = data.summary.class
}
}
local details = frame:extensionTag {
name = 'details',
content = summary .. data.details.content,
args = {
class = data.details.class,
role = data.details.role,
open = data.details.open or 'no'
}
}
return details
end
--- @param rowArgs table
--- @return mw.html
local function getRowHTML( rowArgs )
local html = mw.html.create()
-- Adds a row to the navplate, with either a header
-- or a label/list combination.
if rowArgs.header then
html
:tag( 'div' )
:addClass( 'template-navplate__groupheader' )
:wikitext( rowArgs.header )
elseif rowArgs.list then
html
:tag( 'div' )
:addClass( 'template-navplate-item' )
:tag( 'div' )
:addClass( 'template-navplate-item__label' )
:wikitext( rowArgs.label )
:done()
:tag( 'div' )
:addClass( 'template-navplate-item__list' )
:wikitext( rowArgs.list )
end
return html
end
--- @return mw.html
local function getTitleHTML()
local html = mw.html.create( 'div' )
html:addClass( 'template-navplate__headerContent' )
if not args.title then return end
if args.subtitle then
html
:tag( 'div' )
:addClass( 'template-navplate__subtitle' )
:wikitext( args.subtitle )
:done()
end
html
:tag( 'div' )
:addClass( 'template-navplate__title' )
:wikitext( args.title )
return html
end
--- @return mw.html
local function getRowsHTML()
local html = mw.html.create()
-- 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 _, num in ipairs( rownums ) do
html:node( getRowHTML( {
header = args['header' .. tostring( num )],
label = args['label' .. tostring( num )],
list = args['list' .. tostring( num )]
} ) )
end
return html
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()
local frame = mw.getCurrentFrame()
local summaryHTML = mw.html.create()
:tag( 'div' )
:addClass( 'citizen-ui-icon mw-ui-icon-wikimedia-collapse' )
:done()
:node( getTitleHTML() )
local contentHTML = mw.html.create( 'div' )
:addClass( 'template-navplate__content citizen-text-small' )
:node( getRowsHTML() )
local output = getDetailsHTML( {
details = {
class = 'template-navplate',
content = tostring( contentHTML )
},
summary = {
class = 'template-navplate__header',
content = tostring( summaryHTML )
}
}, frame )
return frame:extensionTag {
name = 'templatestyles', args = { src = 'Module:Navplate/styles.css' }
} .. output
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
-- Legacy method, do not use
-- 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
-- For calling via other modules
function p.fromData( data )
local directArgs = {}
if not data or type( data ) ~= 'table' then
-- TODO: Add error state
else
if data.title then
directArgs.title = data.title
end
if data.subtitle then
directArgs.subtitle = data.subtitle
end
if data.id then
directArgs.id = data.id
end
if data.items and type( data.items ) == 'table' and #data.items > 0 then
for i, item in ipairs( data.items ) do
if type( item ) == 'table' then
if item.label then
directArgs['label' .. tostring( i )] = item.label
end
if item.pages then -- 'pages' from Manufacturers.lua maps to 'list' here
directArgs['list' .. tostring( i )] = item.pages
end
if item.header then -- Also support 'header' if needed
directArgs['header' .. tostring( i )] = item.header
end
end
end
else
-- TODO: Add empty state to navplate
end
end
return p.navplateTemplate( { args = directArgs } )
end
return p