본문으로 이동

모듈:Sidebar

KANOTYPE WIKI

이 모듈에 대한 설명문서는 모듈:Sidebar/설명문서에서 만들 수 있습니다

  1 require('strict')
  2 local cfg = mw.loadData('Module:Sidebar/configuration')
  3 
  4 local p = {}
  5 
  6 local getArgs = require('Module:Arguments').getArgs
  7 
  8 --[[
  9 Categorizes calling templates and modules with a 'style' parameter of any sort
 10 for tracking to convert to TemplateStyles.
 11 
 12 TODO after a long cleanup: Catch sidebars in other namespaces than Template and Module.
 13 TODO would probably want to remove /log and /archive as CS1 does
 14 ]]
 15 local function categorizeTemplatesWithInlineStyles(args)
 16 	local title = mw.title.getCurrentTitle()
 17 	if title.namespace ~= 10 and title.namespace ~= 828 then return '' end
 18 	for _, pattern in ipairs (cfg.i18n.pattern.uncategorized_conversion_titles) do
 19 		if title.text:match(pattern) then return '' end
 20 	end
 21 	
 22 	for key, _ in pairs(args) do
 23 		if mw.ustring.find(key, cfg.i18n.pattern.style_conversion) or key == 'width' then
 24 			return cfg.i18n.category.conversion
 25 		end
 26 	end
 27 end
 28 
 29 --[[
 30 For compatibility with the original {{sidebar with collapsible lists}}
 31 implementation, which passed some parameters through {{#if}} to trim their
 32 whitespace. This also triggered the automatic newline behavior.
 33 ]]
 34 -- See ([[meta:Help:Newlines and spaces#Automatic newline]])
 35 local function trimAndAddAutomaticNewline(s)
 36 	s = mw.ustring.gsub(s, "^%s*(.-)%s*$", "%1")
 37 	if mw.ustring.find(s, '^[#*:;]') or mw.ustring.find(s, '^{|') then
 38 		return '\n' .. s
 39 	else
 40 		return s
 41 	end
 42 end
 43 
 44 --[[
 45 Finds whether a sidebar has a subgroup sidebar.
 46 ]]
 47 local function hasSubgroup(s)
 48 	if mw.ustring.find(s, cfg.i18n.pattern.subgroup) then
 49 		return true
 50 	else
 51 		return false
 52 	end
 53 end
 54 
 55 local function has_navbar(navbar_mode, sidebar_name)
 56 	return navbar_mode ~= cfg.i18n.navbar_none and
 57 		navbar_mode ~= cfg.i18n.navbar_off and
 58 		(
 59 			sidebar_name or
 60 			mw.getCurrentFrame():getParent():getTitle():gsub(cfg.i18n.pattern.sandbox, '') ~=
 61 			cfg.i18n.title_not_to_add_navbar
 62 		)
 63 end
 64 
 65 local function has_list_class(args, htmlclass)
 66 	local patterns = {
 67 		'^' .. htmlclass .. '$',
 68 		'%s' .. htmlclass .. '$',
 69 		'^' .. htmlclass .. '%s',
 70 		'%s' .. htmlclass .. '%s'
 71 	}
 72 	
 73 	for arg, value in pairs(args) do
 74 		if type(arg) == 'string' and mw.ustring.find(arg, 'class') then
 75 			for _, pattern in ipairs(patterns) do
 76 				if mw.ustring.find(args[arg] or '', pattern) then
 77 					return true
 78 				end
 79 			end
 80 		end
 81 	end
 82 	return false
 83 end
 84 
 85 -- there are a lot of list classes in the wild, so we add their TemplateStyles
 86 local function add_list_styles(args)
 87 	local frame = mw.getCurrentFrame()
 88 	local function add_list_templatestyles(htmlclass, templatestyles)
 89 		if has_list_class(args, htmlclass) then
 90 			return frame:extensionTag{
 91 				name = 'templatestyles', args = { src = templatestyles }
 92 			}
 93 		else
 94 			return ''
 95 		end
 96 	end
 97 	
 98 	local plainlist_styles = add_list_templatestyles('plainlist', cfg.i18n.plainlist_templatestyles)
 99 	local hlist_styles = add_list_templatestyles('hlist', cfg.i18n.hlist_templatestyles)
100 	
101 	-- a second workaround for [[phab:T303378]]
102 	-- when that issue is fixed, we can actually use has_navbar not to emit the
103 	-- tag here if we want
104 	if has_navbar(args.navbar, args.name) and hlist_styles == '' then
105 		hlist_styles = frame:extensionTag{
106 			name = 'templatestyles', args = { src = cfg.i18n.hlist_templatestyles}
107 		}
108 	end
109 
110 	-- hlist -> plainlist is best-effort to preserve old Common.css ordering. [hlist_note]
111 	return hlist_styles .. plainlist_styles
112 end
113 
114 -- work around [[phab:T303378]]
115 -- for each arg: find all the templatestyles strip markers, insert them into a
116 -- table. then remove all templatestyles markers from the arg
117 local function move_hiding_templatestyles(args)
118 	local gfind = string.gfind
119 	local gsub = string.gsub
120 	local templatestyles_markers = {}
121 	local strip_marker_pattern = '(\127[^\127]*UNIQ%-%-templatestyles%-%x+%-QINU[^\127]*\127)'
122 	for k, arg in pairs(args) do
123 		for marker in gfind(arg, strip_marker_pattern) do
124 			table.insert(templatestyles_markers, marker)
125 		end
126 		args[k] = gsub(arg, strip_marker_pattern, '')
127 	end
128 	return templatestyles_markers
129 end
130 
131 --[[
132 Main sidebar function. Takes the frame, args, and an optional collapsibleClass.
133 The collapsibleClass is and should be used only for sidebars with collapsible
134 lists, as in p.collapsible.
135 ]]
136 function p.sidebar(frame, args, collapsibleClass)
137 	if not args then
138 		args = getArgs(frame)
139 	end
140 	local hiding_templatestyles = table.concat(move_hiding_templatestyles(args))
141 	local root = mw.html.create()
142 	local child = args.child and mw.text.trim(args.child) == cfg.i18n.child_yes
143 
144 	root = root:tag('table')
145 	if not child then
146 		root 
147 			:addClass(cfg.i18n.class.sidebar)
148 			-- force collapsibleclass to be sidebar-collapse otherwise output nothing
149 			:addClass(collapsibleClass == cfg.i18n.class.collapse and cfg.i18n.class.collapse or nil)
150 			:addClass('nomobile')
151 			:addClass(args.float == cfg.i18n.float_none and cfg.i18n.class.float_none or nil)
152 			:addClass(args.float == cfg.i18n.float_left and cfg.i18n.class.float_left or nil)
153 			:addClass(args.wraplinks ~= cfg.i18n.wrap_true and cfg.i18n.class.wraplinks or nil)
154 			:addClass(args.bodyclass or args.class)
155 			:css('width', args.width or nil)
156 			:cssText(args.bodystyle or args.style)
157 
158 		if args.outertitle then
159 			root
160 				:tag('caption')
161 					:addClass(cfg.i18n.class.outer_title)
162 					:addClass(args.outertitleclass)
163 					:cssText(args.outertitlestyle)
164 					:wikitext(args.outertitle)
165 		end
166 
167 		if args.topimage then
168 			local imageCell = root:tag('tr'):tag('td')
169 
170 			imageCell
171 				:addClass(cfg.i18n.class.top_image)
172 				:addClass(args.topimageclass)
173 				:cssText(args.topimagestyle)
174 				:wikitext(args.topimage)
175 
176 			if args.topcaption then
177 				imageCell
178 					:tag('div')
179 						:addClass(cfg.i18n.class.top_caption)
180 						:cssText(args.topcaptionstyle)
181 						:wikitext(args.topcaption)
182 			end
183 		end
184 
185 		if args.pretitle then
186 			root
187 				:tag('tr')
188 					:tag('td')
189 						:addClass(args.topimage and cfg.i18n.class.pretitle_with_top_image
190 							or cfg.i18n.class.pretitle)
191 						:addClass(args.pretitleclass)
192 						:cssText(args.basestyle)
193 						:cssText(args.pretitlestyle)
194 						:wikitext(args.pretitle)
195 		end
196 	else
197 		root
198 			:addClass(cfg.i18n.class.subgroup)
199 			:addClass(args.bodyclass or args.class)
200 			:cssText(args.bodystyle or args.style)
201 	end
202 
203 	if args.title then
204 		if child then
205 			root
206 				:wikitext(args.title)
207 		else
208 			root
209 				:tag('tr')
210 					:tag('th')
211 						:addClass(args.pretitle and cfg.i18n.class.title_with_pretitle
212 							or cfg.i18n.class.title)
213 						:addClass(args.titleclass)
214 						:cssText(args.basestyle)
215 						:cssText(args.titlestyle)
216 						:wikitext(args.title)
217 		end
218 	end
219 
220 	if args.image then
221 		local imageCell = root:tag('tr'):tag('td')
222 
223 		imageCell
224 			:addClass(cfg.i18n.class.image)
225 			:addClass(args.imageclass)
226 			:cssText(args.imagestyle)
227 			:wikitext(args.image)
228 
229 		if args.caption then
230 			imageCell
231 				:tag('div')
232 					:addClass(cfg.i18n.class.caption)
233 					:cssText(args.captionstyle)
234 					:wikitext(args.caption)
235 		end
236 	end
237 
238 	if args.above then
239 		root
240 			:tag('tr')
241 				:tag('td')
242 					:addClass(cfg.i18n.class.above)
243 					:addClass(args.aboveclass)
244 					:cssText(args.abovestyle)
245 					:newline() -- newline required for bullet-points to work
246 					:wikitext(args.above)
247 	end
248 
249 	local rowNums = {}
250 	for k, v in pairs(args) do
251 		k = '' .. k
252 		local num = k:match('^heading(%d+)$') or k:match('^content(%d+)$')
253 		if num then table.insert(rowNums, tonumber(num)) end
254 	end
255 	table.sort(rowNums)
256 	-- remove duplicates from the list (e.g. 3 will be duplicated if both heading3
257 	-- and content3 are specified)
258 	for i = #rowNums, 1, -1 do
259 		if rowNums[i] == rowNums[i - 1] then
260 			table.remove(rowNums, i)
261 		end
262 	end
263 
264 	for i, num in ipairs(rowNums) do
265 		local heading = args['heading' .. num]
266 		if heading then
267 			root
268 				:tag('tr')
269 					:tag('th')
270 						:addClass(cfg.i18n.class.heading)
271 						:addClass(args.headingclass)
272 						:addClass(args['heading' .. num .. 'class'])
273 						:cssText(args.basestyle)
274 						:cssText(args.headingstyle)
275 						:cssText(args['heading' .. num .. 'style'])
276 						:newline()
277 						:wikitext(heading)
278 		end
279 
280 		local content = args['content' .. num]
281 		if content then
282 			root
283 				:tag('tr')
284 					:tag('td')
285 						:addClass(hasSubgroup(content) and cfg.i18n.class.content_with_subgroup
286 							or cfg.i18n.class.content)
287 						:addClass(args.contentclass)
288 						:addClass(args['content' .. num .. 'class'])
289 						:cssText(args.contentstyle)
290 						:cssText(args['content' .. num .. 'style'])
291 						:newline()
292 						:wikitext(content)
293 						:done()
294 					 -- Without a linebreak after the </td>, a nested list like
295 					 -- "* {{hlist| ...}}" doesn't parse correctly.
296 					:newline()
297 		end
298 	end
299 
300 	if args.below then
301 		root
302 			:tag('tr')
303 				:tag('td')
304 					:addClass(cfg.i18n.class.below)
305 					:addClass(args.belowclass)
306 					:cssText(args.belowstyle)
307 					:newline()
308 					:wikitext(args.below)
309 	end
310 
311 	if not child and has_navbar(args.navbar, args.name) then
312 		root
313 			:tag('tr')
314 				:tag('td')
315 					:addClass(cfg.i18n.class.navbar)
316 					:cssText(args.navbarstyle)
317 					:wikitext(require('Module:Navbar')._navbar{
318 						args.name,
319 						mini = 1,
320 						fontstyle = args.navbarfontstyle
321 					})
322 	end
323 	
324 	local base_templatestyles = frame:extensionTag{
325 		name = 'templatestyles', args = { src = cfg.i18n.templatestyles }
326 	}
327 	
328 	local templatestyles = ''
329 	if args['templatestyles'] and args['templatestyles'] ~= '' then
330 		templatestyles = frame:extensionTag{
331 			name = 'templatestyles', args = { src = args['templatestyles'] }
332 		}
333 	end
334 	
335 	local child_templatestyles = ''
336 	if args['child templatestyles'] and args['child templatestyles'] ~= '' then
337 		child_templatestyles = frame:extensionTag{
338 			name = 'templatestyles', args = { src = args['child templatestyles'] }
339 		}
340 	end
341 	
342 	local grandchild_templatestyles = ''
343 	if args['grandchild templatestyles'] and args['grandchild templatestyles'] ~= '' then
344 		grandchild_templatestyles = frame:extensionTag{
345 			name = 'templatestyles', args = { src = args['grandchild templatestyles'] }
346 		}
347 	end
348 
349 	return table.concat({
350 		add_list_styles(args), -- see [hlist_note] above about ordering
351 		base_templatestyles,
352 		templatestyles,
353 		child_templatestyles,
354 		grandchild_templatestyles,
355 		hiding_templatestyles,
356 		tostring(root),
357 		(child and cfg.i18n.category.child or ''),
358 		categorizeTemplatesWithInlineStyles(args)
359 	})
360 end
361 
362 local function list_title(args, is_centered_list_titles, num)
363 	
364 	local title_text = trimAndAddAutomaticNewline(args['list' .. num .. 'title']
365 		or cfg.i18n.default_list_title)
366 
367 	local title
368 	if is_centered_list_titles then
369 		-- collapsible can be finicky, so provide some CSS/HTML to support
370 		title = mw.html.create('div')
371 			:addClass(cfg.i18n.class.list_title_centered)
372 			:wikitext(title_text)
373 	else
374 		title = mw.html.create()
375 			:wikitext(title_text)
376 	end
377 		
378 	local title_container = mw.html.create('div')
379 		:addClass(cfg.i18n.class.list_title)
380 		-- don't /need/ a listnumtitleclass because you can do
381 		-- .templateclass .listnumclass .sidebar-list-title
382 		:addClass(args.listtitleclass)
383 		:cssText(args.basestyle)
384 		:cssText(args.listtitlestyle)
385 		:cssText('color: var(--color-base)')
386 		:cssText(args['list' .. num .. 'titlestyle'])
387 		:node(title)
388 		:done()
389 	
390 	return title_container
391 end
392 
393 --[[
394 Main entry point for sidebar with collapsible lists.
395 Does the work of creating the collapsible lists themselves and including them
396 into the args.
397 ]]
398 function p.collapsible(frame)
399 	local args = getArgs(frame)
400 	if not args.name and
401 		frame:getParent():getTitle():gsub(cfg.i18n.pattern.collapse_sandbox, '') ==
402 		cfg.i18n.collapse_title_not_to_add_navbar then
403 		args.navbar = cfg.i18n.navbar_none
404 	end
405 
406 	local contentArgs = {}
407 	
408 	local is_centered_list_titles = false
409 	if args['centered list titles'] and args['centered list titles'] ~= '' then
410 		is_centered_list_titles = true
411 	end
412 
413 	for k, v in pairs(args) do
414 		local num = string.match(k, '^list(%d+)$')
415 		if num then
416 			local expand = args.expanded and
417 				(args.expanded == 'all' or args.expanded == args['list' .. num .. 'name'])
418 			local row = mw.html.create('div')
419 			row
420 				:addClass(cfg.i18n.class.list)
421 				:addClass('mw-collapsible')
422 				:addClass((not expand) and 'mw-collapsed' or nil)
423 				:addClass(args['list' .. num .. 'class'])
424 				:cssText(args.listframestyle)
425 				:cssText(args['list' .. num .. 'framestyle'])
426 				:node(list_title(args, is_centered_list_titles, num))
427 				:tag('div')
428 					:addClass(cfg.i18n.class.list_content)
429 					:addClass('mw-collapsible-content')
430 					-- don't /need/ a listnumstyleclass because you can do
431 					-- .templatename .listnumclass .sidebar-list
432 					:addClass(args.listclass)
433 					:cssText(args.liststyle)
434 					:cssText(args['list' .. num .. 'style'])
435 					:wikitext(trimAndAddAutomaticNewline(args['list' .. num]))
436 
437 			contentArgs['content' .. num] = tostring(row)
438 		end
439 	end
440 
441 	for k, v in pairs(contentArgs) do
442 		args[k] = v
443 	end
444 
445 	return p.sidebar(frame, args, cfg.i18n.class.collapse)
446 end
447 
448 return p