Module:Guide
Documentation for this module may be created at Module:Guide/doc
-- Module:Guide
-- Renders a guide page with article path, cover image, editors, sources, and sidebar.
-- Sidebar lists all other guides — fixed nil rendering of guide titles.
local p = {}
-- Helper message extractor
local function getMessage(msg)
return mw.message.new(msg):plain()
end
-- Helper function to format a list of items as formatted links
local function formatted_list(items, prefix)
local formatted_items = {}
if type(items) == "table" then
for _, item in ipairs(items) do
item = mw.text.trim(item)
table.insert(formatted_items, '[[' .. item .. ']]')
end
else
for item in items:gmatch("[^;]+") do
item = mw.text.trim(item)
table.insert(formatted_items, '[[' .. item .. ']]')
end
end
local formatted_list
if #formatted_items > 1 then
local last_item = table.remove(formatted_items)
formatted_list = table.concat(formatted_items, ", ") .. " and " .. last_item
else
formatted_list = formatted_items[1] or ""
end
if prefix and prefix ~= "" then
formatted_list = prefix .. formatted_list
end
return formatted_list
end
function p.main(frame)
local getTitle = mw.title.getCurrentTitle()
local page = getTitle.fullText
local template = frame:getParent().args
local category = '[[Category:Guides]]'
local display_name = template['Display name'] or page or ''
local teaser = template['About'] or ''
local guide_editor = template['Guide editor'] or ''
local associate_editor = template['Associate editor'] or ''
local source = template['Source'] or ''
local cover_image = template['Cover image'] or ''
local filename = ''
if cover_image ~= '' then
filename = frame:preprocess('File:{{PAGENAME:' .. cover_image .. '}}') or ''
end
local suppress_caption = template['Suppress uploaded media caption'] or 'No'
local caption = ''
if suppress_caption == 'Yes' then
caption = template['Cover image caption'] or ''
else
caption = tostring(frame:callParserFunction('#ask',
'[[' .. filename .. ']][[License short::+]]',
'?License URL',
'?License short',
'?Media credits URL',
'?Media credits text',
'?Other text',
'named args=yes',
'format=plainlist',
'mainlabel=-',
'headers=hide',
'link=none',
'template=Image attribution'
))
end
local limit_img_width = template['Limit uploaded media width'] or 'No'
local limit = template['Limit'] or ''
local img_width = ''
if limit_img_width == 'Yes' and limit ~= '' then
img_width = limit .. 'px'
end
if display_name ~= '' then
frame:preprocess('{{DISPLAYTITLE:' .. display_name .. '|noreplace|noerror}}')
frame:preprocess('{{DEFAULTSORT:' .. display_name .. '}}')
end
local articles = template['Articles'] or {}
local set_properties = frame:callParserFunction('#set',
'Teaser=' .. teaser,
'Cover image=' .. filename,
'Guide editor=' .. guide_editor,
'+sep=;',
'Associate editor=' .. associate_editor,
'+sep=;',
'Source=' .. source,
'+sep=;'
)
local html = mw.html.create()
-- ARTICLE PATH
local articlepath = html:tag('div')
:attr('id', 'article-path')
:addClass('interface d-flex align-items-center justify-content-between')
:addClass('font-weight-bold text-uppercase d-print-none screenonly noprint')
articlepath:tag('span')
:attr('id', 'observatory-path')
:addClass('d-print-none noprint')
:wikitext('[[' ..
frame:preprocess('{{int:mainpage}}|{{SITENAME}}') ..
']] » ' ..
'[[Guides]]'
)
local areas = mw.smw.ask{
'[[' .. page .. ']]',
'mainlabel=-',
'?Path area#-=Area'
} or {}
local searchCategory = 'Guides'
local deepSearchCategory = 'Guides'
local areaNames = {}
if #areas > 0 then
if type(areas[1]['Area']) == "table" then
for _, area in ipairs(areas[1]['Area']) do
table.insert(areaNames, area)
end
else
table.insert(areaNames, areas[1]['Area'])
end
searchCategory = table.concat(areaNames, ',')
deepSearchCategory = table.concat(areaNames, '%22%2C%22')
end
articlepath:tag('span'):wikitext(frame:expandTemplate({
title = 'Article buttons', args = {
['Area'] = searchCategory,
['DeepArea'] = deepSearchCategory
}
}))
html:tag('div')
:addClass('d-none')
:wikitext()
if cover_image ~= '' then
html:tag('div')
:attr('id', 'cover-image')
:wikitext('[[' .. filename .. '|thumb|' .. caption .. '|' .. img_width .. ']]')
end
local authorship = html:tag('div')
:addClass('d-flex w-100 flex-column flex-md-row justify-content-between')
local editors = authorship:tag('div')
:addClass('interface')
editors:tag('div'):wikitext(formatted_list(guide_editor, 'Editor: '))
if associate_editor and associate_editor ~= '' then
editors:tag('div'):wikitext(formatted_list(associate_editor, 'Associate Editor: ')):done()
end
authorship:tag('div')
:addClass('interface mb-3')
:wikitext(formatted_list(source, 'Source: '))
html:tag('div')
:addClass('mt-3 mb-5 text-muted')
:newline()
:wikitext(teaser)
html:tag('div')
:wikitext(articles)
-- Initialize the sideblock — list all other guides
local sideblock = html:tag('div')
:attr('id', 'article-sources')
:addClass('my-4 text-left interface')
:css('flex', '0 0 280px')
-- FIX: Use table-form query with mainlabel to get page titles reliably
local all_guides = mw.smw.ask {
'[[Category:Guides]][[!' .. page .. ']]',
'mainlabel=-',
'?#-=title',
'limit=500',
'searchlabel='
} or {}
if #all_guides > 0 then
for _, guide in ipairs(all_guides) do
-- guide.title is the page title (named via ?#-=title)
-- fallback to guide[1] for backward compat
local guideTitle = guide.title or guide[1] or ''
if guideTitle == '' or guideTitle == nil then
-- skip entries with no title
else
sideblock:tag('div')
:addClass('py-1')
:wikitext('<i class="far fa-map mr-2"></i>[[' .. tostring(guideTitle) .. ']]')
end
end
end
local guide_output = tostring(html) .. tostring(sideblock) .. category
frame:callParserFunction(
'#counter',
'stepcount',
'type=numeric',
'set=0'
)
return guide_output
end
function p.test()
local areas = mw.smw.ask{
'[[Guide to Animals in Science and Research]]',
'mainlabel=-',
'?Path area#-=Area'
} or {}
return areas
end
return p
