Jump to content

Editing Module:Sidebar

Warning: You are not logged in. Your IP address will be publicly visible if you make any edits. If you log in or create an account, your edits will be attributed to your username, along with other benefits.

The edit can be undone. Please check the comparison below to verify that this is what you want to do, and then publish the changes below to finish undoing the edit.

Latest revision Your text
Line 1: Line 1:
require('strict')
--
local cfg = mw.loadData('Module:Sidebar/configuration')
-- This module implements {{Sidebar}}
 
--
local p = {}
local p = {}
 
local getArgs = require('Module:Arguments').getArgs
local getArgs
 
local HtmlBuilder = require('Module:HtmlBuilder')
--[[
local navbar = require('Module:Navbar')._navbar
Categorizes calling templates and modules with a 'style' parameter of any sort
for tracking to convert to TemplateStyles.
 
TODO after a long cleanup: Catch sidebars in other namespaces than Template and Module.
TODO would probably want to remove /log and /archive as CS1 does
]]
local function categorizeTemplatesWithInlineStyles(args)
local title = mw.title.getCurrentTitle()
if title.namespace ~= 10 and title.namespace ~= 828 then return '' end
for _, pattern in ipairs (cfg.i18n.pattern.uncategorized_conversion_titles) do
if title.text:match(pattern) then return '' end
end
for key, _ in pairs(args) do
if mw.ustring.find(key, cfg.i18n.pattern.style_conversion) or key == 'width' then
return cfg.i18n.category.conversion
end
end
end
 
--[[
For compatibility with the original {{sidebar with collapsible lists}}
implementation, which passed some parameters through {{#if}} to trim their
whitespace. This also triggered the automatic newline behavior.
]]
-- See ([[meta:Help:Newlines and spaces#Automatic newline]])
local function trimAndAddAutomaticNewline(s)
local function trimAndAddAutomaticNewline(s)
-- For compatibility with the original {{sidebar with collapsible lists}}
-- implementation, which passed some parameters through {{#if}} to trim
-- their whitespace. This also triggered the automatic newline behavior.
-- ([[meta:Help:Newlines and spaces#Automatic newline]])
s = mw.ustring.gsub(s, "^%s*(.-)%s*$", "%1")
s = mw.ustring.gsub(s, "^%s*(.-)%s*$", "%1")
if mw.ustring.find(s, '^[#*:;]') or mw.ustring.find(s, '^{|') then
if mw.ustring.find(s, '^[#*:;]') or mw.ustring.find(s, '^{|') then
Line 42: Line 22:
end
end


--[[
local function _sidebar(args)
Finds whether a sidebar has a subgroup sidebar.
local root = HtmlBuilder.create()
]]
local child = args.child and mw.text.trim(args.child) == 'yes'
local function hasSubgroup(s)
if mw.ustring.find(s, cfg.i18n.pattern.subgroup) then
return true
else
return false
end
end
 
local function has_navbar(navbar_mode, sidebar_name)
return navbar_mode ~= cfg.i18n.navbar_none and
navbar_mode ~= cfg.i18n.navbar_off and
(
sidebar_name or
mw.getCurrentFrame():getParent():getTitle():gsub(cfg.i18n.pattern.sandbox, '') ~=
cfg.i18n.title_not_to_add_navbar
)
end
 
local function has_list_class(args, htmlclass)
local patterns = {
'^' .. htmlclass .. '$',
'%s' .. htmlclass .. '$',
'^' .. htmlclass .. '%s',
'%s' .. htmlclass .. '%s'
}
for arg, value in pairs(args) do
if not child then
if type(arg) == 'string' and mw.ustring.find(arg, 'class') then
root = root
for _, pattern in ipairs(patterns) do
.tag('table')
if mw.ustring.find(args[arg] or '', pattern) then
.addClass('vertical-navbox')
return true
.addClass(args.wraplinks ~= 'true' and 'nowraplinks')
end
.addClass(args.bodyclass or args.class)
end
.css('float', args.float or 'right')
end
.css('clear', (args.float == 'none' and 'both') or args.float or 'right')
end
.css('width', args.width or '22.0em')
return false
.css('margin', args.float == 'left' and '0 1.0em 1.0em 0' or '0 0 1.0em 1.0em')
end
.css('background', '#f9f9f9')
 
.css('border', '1px solid #aaa')
-- there are a lot of list classes in the wild, so we add their TemplateStyles
.css('padding', '0.2em')
local function add_list_styles(args)
.css('border-spacing', '0.4em 0')
local frame = mw.getCurrentFrame()
.css('text-align', 'center')
local function add_list_templatestyles(htmlclass, templatestyles)
.css('line-height', '1.4em')
if has_list_class(args, htmlclass) then
.css('font-size', '88%')
return frame:extensionTag{
.cssText(args.bodystyle or args.style)
name = 'templatestyles', args = { src = templatestyles }
}
else
return ''
end
end
local plainlist_styles = add_list_templatestyles('plainlist', cfg.i18n.plainlist_templatestyles)
local hlist_styles = add_list_templatestyles('hlist', cfg.i18n.hlist_templatestyles)
-- a second workaround for [[phab:T303378]]
-- when that issue is fixed, we can actually use has_navbar not to emit the
-- tag here if we want
if has_navbar(args.navbar, args.name) and hlist_styles == '' then
hlist_styles = frame:extensionTag{
name = 'templatestyles', args = { src = cfg.i18n.hlist_templatestyles}
}
end
-- hlist -> plainlist is best-effort to preserve old Common.css ordering. [hlist_note]
return hlist_styles .. plainlist_styles
end
-- work around [[phab:T303378]]
-- for each arg: find all the templatestyles strip markers, insert them into a
-- table. then remove all templatestyles markers from the arg
local function move_hiding_templatestyles(args)
local gfind = string.gfind
local gsub = string.gsub
local templatestyles_markers = {}
local strip_marker_pattern = '(\127[^\127]*UNIQ%-%-templatestyles%-%x+%-QINU[^\127]*\127)'
for k, arg in pairs(args) do
for marker in gfind(arg, strip_marker_pattern) do
table.insert(templatestyles_markers, marker)
end
args[k] = gsub(arg, strip_marker_pattern, '')
end
return templatestyles_markers
end
--[[
Main sidebar function. Takes the frame, args, and an optional collapsibleClass.
The collapsibleClass is and should be used only for sidebars with collapsible
lists, as in p.collapsible.
]]
function p.sidebar(frame, args, collapsibleClass)
if not args then
args = getArgs(frame)
end
local hiding_templatestyles = table.concat(move_hiding_templatestyles(args))
local root = mw.html.create()
local child = args.child and mw.text.trim(args.child) == cfg.i18n.child_yes
root = root:tag('table')
if not child then
root
:addClass(cfg.i18n.class.sidebar)
-- force collapsibleclass to be sidebar-collapse otherwise output nothing
:addClass(collapsibleClass == cfg.i18n.class.collapse and cfg.i18n.class.collapse or nil)
:addClass('nomobile')
:addClass(args.float == cfg.i18n.float_none and cfg.i18n.class.float_none or nil)
:addClass(args.float == cfg.i18n.float_left and cfg.i18n.class.float_left or nil)
:addClass(args.wraplinks ~= cfg.i18n.wrap_true and cfg.i18n.class.wraplinks or nil)
:addClass(args.bodyclass or args.class)
:css('width', args.width or nil)
:cssText(args.bodystyle or args.style)
if args.outertitle then
if args.outertitle then
root
root
:tag('caption')
.tag('caption')
:addClass(cfg.i18n.class.outer_title)
.addClass(args.outertitleclass)
:addClass(args.outertitleclass)
.css('padding-bottom', '0.2em')
:cssText(args.outertitlestyle)
.css('font-size', '125%')
:wikitext(args.outertitle)
.css('line-height', '1.2em')
.css('font-weight', 'bold')
.cssText(args.outertitlestyle)
.wikitext(args.outertitle)
end
end
 
if args.topimage then
if args.topimage then
local imageCell = root:tag('tr'):tag('td')
local imageCell = root.tag('tr').tag('td')
 
imageCell
imageCell
:addClass(cfg.i18n.class.top_image)
.addClass(args.topimageclass)
:addClass(args.topimageclass)
.css('padding', '0.4em 0')
:cssText(args.topimagestyle)
.cssText(args.topimagestyle)
:wikitext(args.topimage)
.wikitext(args.topimage)
 
if args.topcaption then
if args.topcaption then
imageCell
imageCell
:tag('div')
.tag('div')
:addClass(cfg.i18n.class.top_caption)
.css('padding-top', '0.2em')
:cssText(args.topcaptionstyle)
.css('line-height', '1.2em')
:wikitext(args.topcaption)
.cssText(args.topcaptionstyle)
.wikitext(args.topcaption)
end
end
end
end
 
if args.pretitle then
if args.pretitle then
root
root
:tag('tr')
.tag('tr')
:tag('td')
.tag('td')
:addClass(args.topimage and cfg.i18n.class.pretitle_with_top_image
.addClass(args.pretitleclass)
or cfg.i18n.class.pretitle)
.cssText(args.basestyle)
:addClass(args.pretitleclass)
.css('padding-top', args.topimage and '0.2em' or '0.4em')
:cssText(args.basestyle)
.css('line-height', '1.2em')
:cssText(args.pretitlestyle)
.cssText(args.pretitlestyle)
:wikitext(args.pretitle)
.wikitext(args.pretitle)
end
end
else
 
root
:addClass(cfg.i18n.class.subgroup)
:addClass(args.bodyclass or args.class)
:cssText(args.bodystyle or args.style)
end
end


Line 204: Line 93:
if child then
if child then
root
root
:wikitext(args.title)
.wikitext(args.title)
.tag('/th', {unclosed = true})
.tag('/tr', {unclosed = true})
else
else
root
root
:tag('tr')
.tag('tr')
:tag('th')
.tag('th')
:addClass(args.pretitle and cfg.i18n.class.title_with_pretitle
.addClass(args.titleclass)
or cfg.i18n.class.title)
.cssText(args.basestyle)
:addClass(args.titleclass)
.css('padding', '0.2em 0.4em 0.2em')
:cssText(args.basestyle)
.css('padding-top', args.pretitle and 0)
:cssText(args.titlestyle)
.css('font-size', '145%')
:wikitext(args.title)
.css('line-height', '1.2em')
.cssText(args.titlestyle)
.wikitext(args.title)
end
end
end
end


if args.image then
if args.image then
local imageCell = root:tag('tr'):tag('td')
local imageCell = root.tag('tr').tag('td')
 
imageCell
imageCell
:addClass(cfg.i18n.class.image)
.addClass(args.imageclass)
:addClass(args.imageclass)
.css('padding', '0.2em 0 0.4em')
:cssText(args.imagestyle)
.cssText(args.imagestyle)
:wikitext(args.image)
.wikitext(args.image)
 
if args.caption then
if args.caption then
imageCell
imageCell
:tag('div')
.tag('div')
:addClass(cfg.i18n.class.caption)
.css('padding-top', '0.2em')
:cssText(args.captionstyle)
.css('line-height', '1.2em')
:wikitext(args.caption)
.cssText(args.captionstyle)
.wikitext(args.caption)
end
end
end
end
 
if args.above then
if args.above then
root
root
:tag('tr')
.tag('tr')
:tag('td')
.tag('td')
:addClass(cfg.i18n.class.above)
.addClass(args.aboveclass)
:addClass(args.aboveclass)
.css('padding', '0.3em 0.4em 0.3em')
:cssText(args.abovestyle)
.css('font-weight', 'bold')
:newline() -- newline required for bullet-points to work
.cssText(args.abovestyle)
:wikitext(args.above)
.newline()   -- newline required for bullet-points to work
.wikitext(args.above)
end
end


Line 254: Line 149:
end
end
table.sort(rowNums)
table.sort(rowNums)
-- remove duplicates from the list (e.g. 3 will be duplicated if both heading3
-- remove duplicates from the list (e.g. 3 will be duplicated if both heading3 and content3 are specified)
-- and content3 are specified)
for i = #rowNums, 1, -1 do
for i = #rowNums, 1, -1 do
if rowNums[i] == rowNums[i - 1] then
if rowNums[i] == rowNums[i - 1] then
Line 266: Line 160:
if heading then
if heading then
root
root
:tag('tr')
.tag('tr')
:tag('th')
.tag('th')
:addClass(cfg.i18n.class.heading)
.addClass(args.headingclass)
:addClass(args.headingclass)
.css('padding', '0.1em')
:addClass(args['heading' .. num .. 'class'])
.cssText(args.basestyle)
:cssText(args.basestyle)
.cssText(args.headingstyle)
:cssText(args.headingstyle)
.cssText(args['heading' .. num .. 'style'])
:cssText(args['heading' .. num .. 'style'])
.newline()
:newline()
.wikitext(heading)
:wikitext(heading)
end
end
 
local content = args['content' .. num]
local content = args['content' .. num]
if content then
if content then
root
root
:tag('tr')
.tag('tr')
:tag('td')
.tag('td')
:addClass(hasSubgroup(content) and cfg.i18n.class.content_with_subgroup
.addClass(args.contentclass)
or cfg.i18n.class.content)
.css('padding', '0 0.1em 0.4em')
:addClass(args.contentclass)
.cssText(args.contentstyle)
:addClass(args['content' .. num .. 'class'])
.cssText(args['content' .. num .. 'style'])
:cssText(args.contentstyle)
.newline()
:cssText(args['content' .. num .. 'style'])
.wikitext(content)
:newline()
.done()
:wikitext(content)
.newline()  -- Without a linebreak after the </td>, a nested list like "* {{hlist| ...}}" doesn't parse correctly.
:done()
-- Without a linebreak after the </td>, a nested list like
-- "* {{hlist| ...}}" doesn't parse correctly.
:newline()
end
end
end
end
Line 300: Line 189:
if args.below then
if args.below then
root
root
:tag('tr')
.tag('tr')
:tag('td')
.tag('td')
:addClass(cfg.i18n.class.below)
.addClass(args.belowclass)
:addClass(args.belowclass)
.css('padding', '0.3em 0.4em 0.3em')
:cssText(args.belowstyle)
.css('font-weight', 'bold')
:newline()
.cssText(args.belowstyle)
:wikitext(args.below)
.newline()
.wikitext(args.below)
end
end


if not child and has_navbar(args.navbar, args.name) then
if not child then
root
local navbarArg = args.navbar or args.tnavbar
:tag('tr')
if navbarArg ~= 'none' and navbarArg ~= 'off' then
:tag('td')
root
:addClass(cfg.i18n.class.navbar)
.tag('tr')
:cssText(args.navbarstyle)
.tag('td')
:wikitext(require('Module:Navbar')._navbar{
.css('text-align', 'right')
args.name,
.css('font-size', '115%')
mini = 1,
.cssText(args.navbarstyle or args.tnavbarstyle)
fontstyle = args.navbarfontstyle
.wikitext(navbar{
})
args.name,
end
mini = 1,
fontstyle = args.navbarfontstyle or args.tnavbarfontstyle
local base_templatestyles = frame:extensionTag{
})
name = 'templatestyles', args = { src = cfg.i18n.templatestyles }
end
}
local templatestyles = ''
if args['templatestyles'] and args['templatestyles'] ~= '' then
templatestyles = frame:extensionTag{
name = 'templatestyles', args = { src = args['templatestyles'] }
}
end
local child_templatestyles = ''
if args['child templatestyles'] and args['child templatestyles'] ~= '' then
child_templatestyles = frame:extensionTag{
name = 'templatestyles', args = { src = args['child templatestyles'] }
}
end
local grandchild_templatestyles = ''
if args['grandchild templatestyles'] and args['grandchild templatestyles'] ~= '' then
grandchild_templatestyles = frame:extensionTag{
name = 'templatestyles', args = { src = args['grandchild templatestyles'] }
}
end
end


return table.concat({
return tostring(root)
add_list_styles(args), -- see [hlist_note] above about ordering
base_templatestyles,
templatestyles,
child_templatestyles,
grandchild_templatestyles,
hiding_templatestyles,
tostring(root),
(child and cfg.i18n.category.child or ''),
categorizeTemplatesWithInlineStyles(args)
})
end
end


local function list_title(args, is_centered_list_titles, num)
function _collapsibleSidebar(args)
args.abovestyle = 'border-top: 1px solid #aaa; border-bottom: 1px solid #aaa;' .. (args.abovestyle or '')
local title_text = trimAndAddAutomaticNewline(args['list' .. num .. 'title']
args.belowstyle = 'border-top: 1px solid #aaa; border-bottom: 1px solid #aaa;' .. (args.belowstyle or '')
or cfg.i18n.default_list_title)
args.navbarstyle = 'padding-top: 0.6em;' .. (args.navbarstyle or args.tnavbarstyle or '')
 
local title
if is_centered_list_titles then
-- collapsible can be finicky, so provide some CSS/HTML to support
title = mw.html.create('div')
:addClass(cfg.i18n.class.list_title_centered)
:wikitext(title_text)
else
title = mw.html.create()
:wikitext(title_text)
end
local title_container = mw.html.create('div')
:addClass(cfg.i18n.class.list_title)
-- don't /need/ a listnumtitleclass because you can do
-- .templateclass .listnumclass .sidebar-list-title
:addClass(args.listtitleclass)
:cssText(args.basestyle)
:cssText(args.listtitlestyle)
:cssText('color: var(--color-base)')
:cssText(args['list' .. num .. 'titlestyle'])
:node(title)
:done()
return title_container
end
--[[
Main entry point for sidebar with collapsible lists.
Does the work of creating the collapsible lists themselves and including them
into the args.
]]
function p.collapsible(frame)
local args = getArgs(frame)
if not args.name and
frame:getParent():getTitle():gsub(cfg.i18n.pattern.collapse_sandbox, '') ==
cfg.i18n.collapse_title_not_to_add_navbar then
args.navbar = cfg.i18n.navbar_none
end
local contentArgs = {}
local contentArgs = {}
local is_centered_list_titles = false
if args['centered list titles'] and args['centered list titles'] ~= '' then
is_centered_list_titles = true
end
for k, v in pairs(args) do
for k, v in pairs(args) do
local num = string.match(k, '^list(%d+)$')
local num = ('' .. k):match('^list(%d+)$')
if num then
if num then  
local expand = args.expanded and
local expand = args.expanded and (args.expanded == 'all' or args.expanded == args['list' .. num .. 'name'])
(args.expanded == 'all' or args.expanded == args['list' .. num .. 'name'])
local row = mw.html.create('div')
local row = HtmlBuilder.create('div')
row
row
:addClass(cfg.i18n.class.list)
.addClass('NavFrame')
:addClass('mw-collapsible')
.addClass((not expand) and 'collapsed')
:addClass((not expand) and 'mw-collapsed' or nil)
.css('border', 'none')
:addClass(args['list' .. num .. 'class'])
.css('padding', 0)
:cssText(args.listframestyle)
.cssText(args.listframestyle)
:cssText(args['list' .. num .. 'framestyle'])
.cssText(args['list' .. num .. 'framestyle'])
:node(list_title(args, is_centered_list_titles, num))
.tag('div')
:tag('div')
.addClass('NavHead')
:addClass(cfg.i18n.class.list_content)
.addClass(args.listtitleclass)
:addClass('mw-collapsible-content')
.css('font-size', '105%')
-- don't /need/ a listnumstyleclass because you can do
.css('background', 'transparent')
-- .templatename .listnumclass .sidebar-list
.css('text-align', 'left')
:addClass(args.listclass)
.cssText(args.basestyle)
:cssText(args.liststyle)
.cssText(args.listtitlestyle)
:cssText(args['list' .. num .. 'style'])
.cssText(args['list' .. num .. 'titlestyle'])
:wikitext(trimAndAddAutomaticNewline(args['list' .. num]))
.wikitext(trimAndAddAutomaticNewline(args['list' .. num .. 'title'] or 'List'))
 
.done()
.tag('div')
.addClass('NavContent')
.addClass(args.listclass)
.addClass(args['list' .. num .. 'class'])
.css('font-size', '105%')
.css('padding', '0.2em 0 0.4em')
.css('text-align', 'center')
.cssText(args.liststyle)
.cssText(args['list' .. num .. 'style'])
.wikitext(trimAndAddAutomaticNewline(args['list' .. num]))
contentArgs['content' .. num] = tostring(row)
contentArgs['content' .. num] = tostring(row)
end
end
Line 442: Line 268:
args[k] = v
args[k] = v
end
end
 
return p.sidebar(frame, args, cfg.i18n.class.collapse)
return _sidebar(args)
end
 
function makeWrapper(func)
return function(frame)
if not getArgs then
getArgs = require('Module:Arguments').getArgs
end
return func(getArgs(frame))
end
end
end


return p
return {
sidebar = makeWrapper(_sidebar),
collapsible = makeWrapper(_collapsibleSidebar)
}
Please note that all contributions to OrangDev Labs Wiki may be edited, altered, or removed by other contributors. If you do not want your writing to be edited mercilessly, then do not submit it here.
You are also promising us that you wrote this yourself, or copied it from a public domain or similar free resource (see OrangDev Labs Wiki:Copyrights for details). Do not submit copyrighted work without permission!
Cancel Editing help (opens in new window)
Preview page with this template

Template used on this page: