Бюрократи, Чек'юзери, Боти для структурованих обговорень, Адміністратори інтерфейсу, Модератори, Адміністратори (Семантична MediaWiki), Куратори (Семантична MediaWiki), Приховувачі, Адміністратори
1655
редагувань
Tviggy (обговорення | внесок) м |
Tviggy (обговорення | внесок) м |
||
Рядок 1: | Рядок 1: | ||
-------------------------------------------------------------------- | |||
--<pre> Navbox Module | |||
-- | -- | ||
-- | -- * Fully CSS styled (inline styles possible but not default) | ||
-- | -- * Supports unlimited rows | ||
-- | -- | ||
-- By User:Tjcool007 from layton.fandom.com | |||
-------------------------------------------------------------------- | |||
local p = {} | local p = {} | ||
local | local args = {} -- Arguments passed to template | ||
local | local navbox -- Actual navbox | ||
local | --local working = {} | ||
local rownums, skiprows = {}, {} | |||
local | local hasrows, alt, hasData, isChild = false, false, false, false | ||
local | local activeSection, sections, cimage, cimageleft | ||
local | local colspan, rowspan | ||
local | |||
local showText, hideText = 'Show', 'Hide' | |||
local | |||
local langCode = mw.getContentLanguage():getCode() | |||
local localization = {} --localized strings table | |||
localization['en'] = {show = 'Show', hide = 'Hide'} | |||
localization['ru'] = {show = 'показать', hide = 'скрыть'} | |||
localization['zh'] = {show = '显示', hide = '隐藏'} | |||
if localization[langCode] then | |||
showText = localization[langCode]['show'] | |||
hideText = localization[langCode]['hide'] | |||
end | |||
------------------------------------------------ | |||
-- Title | |||
------------------------------------------------ | |||
--- Processes the VDE links in the title | |||
local | -- | ||
-- @param titlecell The table cell of the title | |||
local function processVde( titlecell ) | |||
if not args.template then return end | |||
titlecell:wikitext('<span class="navbox-vde">' | |||
.. mw.getCurrentFrame():expandTemplate({ | |||
title = 'vdelinks', | |||
args = { args.template, ['type'] = 'navbox' } | |||
}) .. '</span>') | |||
end | |||
--- Processes the main title row | |||
local function processTitle() | |||
local titlerow = mw.html.create('tr'):addClass('navbox-title') | |||
local function | local titlecell = mw.html.create('th'):attr('colspan',colspan):attr('scope','col') | ||
if not pcall( processVde, titlecell ) then | |||
titlecell:wikitext( '<b class="navbox-vde error" title="Missing Template:Vdelinks">!!!</b>' ) | |||
local | |||
- | |||
end | end | ||
local | |||
if | titlecell:wikitext( args.title or '{{{title}}}' ) | ||
if | |||
-- Padding | |||
local hasTemplate = args.template ~= nil | |||
local hasState = not args.state or args.state ~= 'plain' | |||
if hasTemplate ~= hasState then | |||
if hasTemplate then | |||
titlecell:addClass('navbox-title-padright') | |||
else | else | ||
titlecell:addClass('navbox-title-padleft') | |||
end | end | ||
end | end | ||
if | if args.titleclass then titlerow:addClass( args.titleclass ) end | ||
if args.titlestyle then titlecell:cssText( args.titlestyle ) end | |||
titlerow:node(titlecell) | |||
navbox:node(titlerow) | |||
end | |||
local function _addGutter( parent, incRowspan ) | |||
parent:tag('tr'):addClass('navbox-gutter'):tag('td'):attr('colspan',2) | |||
if incRowspan then | |||
rowspan = rowspan + 1 | |||
end | end | ||
end | end | ||
local function | ------------------------------------------------ | ||
if | -- Above/Below | ||
------------------------------------------------ | |||
--- Processes the above and below rows | |||
-- | |||
-- @param rowtype Either 'above' or 'below' | |||
local function processAboveBelow( rowtype ) | |||
if not args[rowtype] then return end | |||
local abrow = mw.html.create('tr'):addClass('navbox-'..rowtype) | |||
local abcell = mw.html.create('td'):attr('colspan',colspan):wikitext( args[rowtype] ) | |||
if args[rowtype .. 'class'] then abrow:addClass( args[rowtype .. 'class'] ) end | |||
if args[rowtype .. 'style'] then abcell:cssText( args[rowtype .. 'style'] ) end | |||
abrow:node( abcell ) | |||
_addGutter( navbox ) | |||
navbox:node( abrow ) | |||
end | |||
------------------------------------------------ | |||
-- Main Rows | |||
------------------------------------------------ | |||
--- Processes the images | |||
local function _processImage(row, imgtype) | |||
if not args[imgtype] then return end | |||
local iclass = imgtype == 'image' and 'navbox-image-right' or 'navbox-image-left' | |||
local imagecell = mw.html.create('td'):addClass('navbox-image'):addClass(iclass) | |||
local image = args[imgtype] | |||
if image:sub(1,1) ~= '[' then | |||
local width = args[imgtype .. 'width'] or '100px' | |||
imagecell:css('width',width):wikitext('['..'[' .. image .. '|' .. width .. '|link=' .. (args[imgtype .. 'link'] or '') .. ']]') | |||
else | else | ||
imagecell:css('width','0%'):wikitext(image) | |||
end | end | ||
if args[imgtype .. 'class'] then imagecell:addClass( args[imgtype .. 'class'] ) end | |||
if args[imgtype .. 'style'] then imagecell:cssText( args[imgtype .. 'style'] ) end | |||
if | row:node( imagecell ) | ||
if imgtype == 'image' then | |||
cimage = imagecell | |||
else | |||
cimageleft = imagecell | |||
end | end | ||
end | end | ||
- | --- Closes the currently active section (if any) | ||
local function _closeCurrentSection() | |||
-- | if not activeSection then return end | ||
local function | |||
if not | local row = mw.html.create('tr'):addClass('navbox-section-row') | ||
local cell = mw.html.create('td'):attr('colspan',2) | |||
local | |||
if not hasrows then | |||
_processImage(row,'imageleft') | |||
end | end | ||
cell:node(sections[activeSection]) | |||
row:node(cell) | |||
if | |||
local firstRow = false | |||
if not hasrows then | |||
firstRow = true | |||
hasrows = true | |||
_processImage(row,'image') | |||
end | end | ||
_addGutter(navbox,not firstRow) | |||
navbox:node(row) | |||
rowspan = rowspan + 1 | |||
activeSection = false | |||
hasData = false | |||
end | end | ||
--- Handles alternating rows | |||
-- | -- | ||
-- | -- @return Alternatingly returns true or false. Always returns false if alternating rows | ||
-- | -- are disabled with "alternaterows = no" | ||
local function _alternateRow() | |||
local function | if args.alternaterows == 'no' then return false end | ||
if alt then | |||
alt = false | |||
return true | |||
else | |||
end | alt = true | ||
return false | |||
end | |||
if | |||
end | end | ||
--- Process a single Header "row" | |||
-- | -- | ||
-- | -- @param num Number of the row to be processed | ||
- | local function processHeader(num) | ||
if not args['header'..num] then return end | |||
local | |||
_closeCurrentSection() | |||
local subtable = mw.html.create('table'):addClass('navbox-section') | |||
local headerrow = mw.html.create('tr') | |||
local header = mw.html.create('th'):addClass('navbox-header'):attr('colspan',2):attr('scope','col'):wikitext( args['header'..num] ) | |||
local collapseme = args['state'..num] or false | |||
local state = false | |||
if collapseme then | |||
-- Look at this one | |||
if collapseme ~= 'plain' then | |||
state = collapseme == 'expanded' and 'expanded' or 'collapsed' | |||
end | |||
else | |||
-- Look at default | |||
local collapseall = args.defaultstate or false | |||
if collapseall then | |||
state = collapseall == 'expanded' and 'expanded' or 'collapsed' | |||
end | |||
end | |||
if state then | |||
subtable:addClass('mw-collapsible'):attr('data-expandtext',args['expandtext'..num] or args['defaultexpandtext'] or showText):attr('data-collapsetext',args['collapsetext'..num] or args['defaultcollapsetext'] or hideText) | |||
if state == 'collapsed' then | |||
subtable:addClass('mw-collapsed') | |||
end | end | ||
header:addClass('navbox-header-collapsible') | |||
end | end | ||
if args.headerclass then headerrow:addClass( args.headerclass ) end | |||
if args.headerstyle then header:cssText( args.headerstyle ) end | |||
headerrow:node(header) | |||
subtable:node(headerrow) | |||
sections[num] = subtable | |||
activeSection = num | |||
end | end | ||
local function | --- Processes a single list row | ||
-- | |||
-- @param num Number of the row to be processed | |||
local function processList(num) | |||
if not args['list'..num] then return end | |||
local row = mw.html.create('tr'):addClass('navbox-row') | |||
if not hasrows and not activeSection then | |||
_processImage(row, 'imageleft') | |||
end | end | ||
local listcell = mw.html.create('td'):addClass('navbox-list') | |||
local hlistcell = listcell:tag('div'):addClass('hlist') | |||
local data = args['list'..num] | |||
if data:sub(1,1) == '*' then | |||
-- Add newlines to support lists properly | |||
hlistcell | |||
:newline() | |||
:wikitext( data ) | |||
:newline() | |||
: | else | ||
: | hlistcell:wikitext( data ) | ||
:wikitext( | |||
end | end | ||
local | local altRow = _alternateRow() | ||
if altRow then | |||
if (args | row:addClass( args.altrowclass or 'alt' ) | ||
local listclass = args.altlistclass or args.listclass or false | |||
if listclass then listcell:addClass( listclass ) end | |||
local liststyle = args.altliststyle or args.liststyle or false | |||
if liststyle then listcell:cssText( liststyle ) end | |||
else | else | ||
if | if args.rowclass then row:addClass( args.rowclass ) end | ||
if args.listclass then listcell:addClass( args.listclass ) end | |||
if args.liststyle then listcell:cssText( args.liststyle ) end | |||
end | |||
if args['group'..num] then | |||
local groupcell = mw.html.create('th'):addClass('navbox-group'):attr('scope','row'):wikitext( args['group'..num] ) | |||
if altRow then | |||
local groupclass = args.altgroupclass or args.groupclass or false | |||
if groupclass then groupcell:addClass( groupclass ) end | |||
local groupstyle = args.altgroupstyle or args.groupstyle or false | |||
if groupstyle then groupcell:cssText( groupstyle ) end | |||
else | |||
if args.groupclass then groupcell:addClass( args.groupclass ) end | |||
if args.groupstyle then groupcell:cssText( args.groupstyle ) end | |||
end | end | ||
row:node( groupcell ) | |||
else | |||
listcell:attr('colspan',2):addClass('no-group') | |||
end | end | ||
if not | row:node( listcell ) | ||
local firstRow = false | |||
if not hasrows and not activeSection then | |||
firstRow = true | |||
hasrows = true | |||
_processImage(row, 'image') | |||
end | end | ||
if activeSection then | |||
local parent = sections[activeSection] | |||
if | if not isChild or not firstRow then | ||
_addGutter(parent) | |||
end | |||
parent:node(row) | |||
hasData = true | |||
else | |||
if not isChild or not firstRow then | |||
_addGutter(navbox,not firstRow) | |||
: | end | ||
navbox:node( row ) | |||
rowspan = rowspan + 1 | |||
end | end | ||
end | end | ||
- | --- Processes all rows | ||
local function processRows() | |||
-- | sections = {} | ||
local function | for i=1,#rownums do | ||
for i = 1, | local num = rownums[i] | ||
if not skiprows[num] then | |||
processHeader(num) | |||
processList(num) | |||
end | end | ||
end | end | ||
_closeCurrentSection() | |||
if cimageleft then | |||
cimageleft:attr('rowspan',rowspan) | |||
if | |||
end | end | ||
if cimage then | |||
cimage:attr('rowspan',rowspan) | |||
end | end | ||
end | end | ||
------------------------------------------------ | |||
-- ARGUMENTS PREPROCESSOR | |||
-- * Extracts arguments from frame and stores them in args table | |||
-- * At the same time, checks for valid row numbers | |||
------------------------------------------------ | |||
--- Preprocessor for the arguments. | |||
-- Will fill up the args table with the parameters from the frame grouped by their type. | |||
-- | -- | ||
-- | -- @param frame The frame passed to the Module. | ||
local function preProcessArgs(frame) | |||
local function | local tmp = {} | ||
local | |||
if frame == mw.getCurrentFrame() then | |||
tmp = frame:getParent().args | |||
else | |||
if | tmp = frame | ||
end | end | ||
-- Storage tables | |||
local nums = {} | |||
-- Loop over all the args | |||
for k,v in pairs(tmp) do | |||
-- Skip empty args, which are useless | |||
if v ~= '' then | |||
local cat,num = tostring(k):match('^(%a+)([1-9]%d*)$') | |||
: | |||
if cat == 'header' or cat == 'list' then | |||
nums[num] = true | |||
end | |||
args[k] = v -- Simple copy | |||
end | |||
end | end | ||
colspan = args.image and 3 or 2 | |||
if args.imageleft then colspan = colspan + 1 end | |||
end | rowspan = 0 | ||
if args.alternaterows == 'swap' then | |||
args = | alt = true | ||
end | end | ||
for k, v in pairs( | for k, v in pairs(nums) do | ||
rownums[#rownums+1] = tonumber(k) | |||
end | end | ||
table.sort( | table.sort(rownums) | ||
-- Calculate skip rows | |||
local cSection, cSkip | |||
local showall = args.showall | |||
for i=1,#rownums do | |||
local num = rownums[i] | |||
if args['header'..num] then | |||
cSection = true | |||
cSkip = false | |||
local showme = args['show'..num] | |||
if showme == 'no' then | |||
cSkip = true | |||
elseif showme == 'auto' or (showme ~= 'yes' and showall ~= 'yes') then | |||
if not args['list'..num] then | |||
local nextNum = rownums[i+1] | |||
cSkip = not nextNum or args['header'..nextNum] -- If next has a header -> skip | |||
end | |||
end | |||
end | end | ||
if | if cSection and cSkip then | ||
skiprows[num] = true | |||
end | end | ||
end | end | ||
end | end | ||
------------------------------------------------ | |||
-- MAIN FUNCTIONS | |||
------------------------------------------------ | |||
--- Processes the arguments to create the navbox. | |||
-- | |||
-- @return A string with HTML that is the navbox. | |||
local function _navbox() | |||
-- Create the root HTML element | |||
local trim = function(s) | |||
return s and mw.ustring.gsub(s, "^%s*(.-)%s*$", "%1") or '' | |||
end | end | ||
if | local border = args.border or trim(args[1]) or '' | ||
isChild = (border == 'child' or border == 'subgroup') | |||
if isChild then | |||
navbox = mw.html.create('table'):addClass('navbox-subgroup') | |||
else | |||
navbox = mw.html.create('table'):addClass('navbox') | |||
if args.state ~= 'plain' then | |||
navbox:addClass('mw-collapsible'):attr('data-expandtext',args['expandtext'] or args['defaultexpandtext'] or showText):attr('data-collapsetext',args['collapsetext'] or args['defaultcollapsetext'] or hideText) | |||
if args.state == 'collapsed' then | |||
navbox:addClass('mw-collapsed') | |||
end | |||
end | |||
end | end | ||
args | |||
if args.bodyclass then navbox:addClass(args.bodyclass) end | |||
if args.bodystyle then navbox:cssText(args.bodystyle) end | |||
-- Process... | |||
if not isChild then | |||
processTitle() | |||
processAboveBelow('above') | |||
processRows() | |||
processAboveBelow('below') | |||
return tostring(navbox) | |||
else | |||
processRows() | |||
local wrapper = mw.html.create('') | |||
wrapper:wikitext('</div>') | |||
wrapper:node(navbox) | |||
wrapper:wikitext('<div class="hlist">') | |||
return tostring(wrapper) | |||
end | end | ||
end | end | ||
--- Main module entry point. | |||
-- To be called with {{#invoke:navbox|main}} or directly from another module. | |||
-- | |||
-- @param frame The frame passed to the module via the #invoke. If called from another | |||
-- module directly, this should be a table with the parameter definition. | |||
function p.main(frame) | |||
-- Save the arguments in a local variable so other functions can use them. | |||
preProcessArgs(frame) | |||
return _navbox() | |||
end | |||
return p | return p |