Module:Navbox

local p = {} local h = {}

local utilsArg = require("Module:UtilsArg")

local CATEGORY_INVALID_ARGS = "" local CLASS_PIXEL_ART = require("Module:Constants/class/pixelArt") local DEFAULT_IMG_SIZE = "150x150px"

local title = mw.title.getCurrentTitle local isTemplate = title.nsText == "Template" local isManualNavboxPage = title.nsText == "Template" and title.rootText ~= "Categories" and title.baseText ~= "Navbox"

function p.Main(frame) local args, err = utilsArg.parse(frame:getParent.args, p.Templates.Navbox) local errCategories = err and err.categoryText or "" if not args.title then if isManualNavboxPage then return "", errCategories.."" elseif isTemplate then return "", errCategories else return "" end end local navbox, categories = h.printNavbox(args) categories = categories..errCategories if isManualNavboxPage then return navbox, categories.."", h.printReport elseif isTemplate then return navbox, categories else return navbox end end

function h.printNavbox(args) local categories = "" -- MediaWiki:Gadget-Site.js automatically removes the "mw-collapsed" when there is only one navbox on the page. local navbox = mw.html.create("div") -- MediaWiki (Timeless?) automatically removes elements with class "navbox" on mobile -- we _want_ to show navboxes on mobile since we've made them mobile friendly, so we use a different class name :addClass("zw-navbox mw-collapsible mw-collapsed") local id = args.id and "navbox-"..string.gsub(string.lower(args.id), " ", "-") -- to kebab case which is the standard for IDs if id then navbox:attr("id", id) end local navboxContent = navbox :tag("div") :addClass("zw-navbox__header mw-collapsible-toggle") :tag("span") -- Used to center the heading - see Template:Navbox/Styles.css :addClass("zw-navbox__toggle-button-counterbalance") :done :tag("span") :addClass("zw-navbox__title") :wikitext(args.title) :done :tag("span") :addClass("zw-navbox__toggle-button") :tag("span") :addClass("zw-navbox__toggle-button-text mw-collapsible-text") :wikitext("hide ▲") :done :done :done :done :tag("div") :addClass("zw-navbox__content mw-collapsible-content") local body = navboxContent:tag("div") :addClass("zw-navbox__body") local rows = body:tag("div") :addClass("zw-navbox__rows") for i, row in ipairs(args.rows) do		if row.group then rows:tag("div") :addClass("zw-navbox__row-header") :wikitext(row.group) :done elseif i ~= 1 or #args.rows > 1 then local utilsError = require("Module:UtilsError") utilsError.warn(string.format(" parameter is required when there is more than one group.", i)) categories = categories..CATEGORY_INVALID_ARGS end local links = {} for j, link in ipairs(row.links or {}) do			link = h.killBacklinks(link) table.insert(links, ''..link..' ') end

local evenOdd = (i % 2 == 0) and "even" or "odd" local rowModifiers = " zw-navbox__row-links--"..evenOdd if #args.rows == 1 and not args.rows[1].group then rowModifiers = rowModifiers.." zw-navbox__row-links--nogroups" end local links = table.concat(links, " • ") rows:tag("div") :addClass("zw-navbox__row-links"..rowModifiers) :tag("div") :addClass("zw-navbox__row-links-content") :wikitext(links) :done :done end if args.image then local filename = args.image if not string.find(filename, "^File:") then filename = "File:"..filename end local thumbnail = string.format("%s", filename, DEFAULT_IMG_SIZE) body:tag("div") :addClass("zw-navbox__image "..CLASS_PIXEL_ART) :wikitext(thumbnail) end if args.footer then navboxContent:tag("div") :addClass("zw-navbox__footer") :wikitext(args.footer) end local result = tostring(navboxContent:allDone) return result, categories end

-- Turns links like Link into Link -- Prevents navbox entries from appearing in the Special:WhatLinksHere of every other navbox entry -- Copied from Module:UtilsMarkup/Link for job queue optimization, plus some modifications function h.killBacklinks(links) return string.gsub(links, "%[%^%+%]%]", h.killBacklink) end function h.killBacklink(link) local linkParts = string.gsub(link, "^%[%[:?", "") linkParts = string.gsub(linkParts, "%]%]$", "") local pipe = string.find(linkParts, "|") local page = string.sub(linkParts, 1, pipe and pipe - 1) h.storePage(page) local display = pipe and string.sub(linkParts, pipe + 1) local url = mw.site.server.."/"..mw.uri.encode(page, "WIKI") return string.format(' [%s %s] ', url, display or page) end

-- Store data for the report function below local VAR_PAGES = "navbox-pages" function h.storePage(page) page = string.gsub(page, "#.*", "") if isManualNavboxPage then local utilsVar = require("Module:UtilsVar") utilsVar.add(VAR_PAGES, page) end end

-- Ensures that every page linked in the navbox uses that navbox -- and that every page that uses the navbox is linked in the navbox -- so that the navigation is bidirectional and doesn't have "dead ends" function h.printReport local utilsError = require("Module:UtilsError") local utilsMarkup = require("Module:UtilsMarkup") local utilsPage = require("Module:UtilsPage") local utilsTable = require("Module:UtilsTable") local utilsVar = require("Module:UtilsVar") local pagesInNav = utilsVar.get(VAR_PAGES) local pagesUsingNav = utilsPage.dpl({		uses = "Template:"..title.baseText,		notnamespace = "User"	}) local missingPages = utilsTable.difference(pagesUsingNav, pagesInNav) local missingUses = utilsTable.difference(pagesInNav, pagesUsingNav) local wantedPages = utilsTable.filter(pagesInNav, function(page)		return not utilsPage.exists(page)	end) local redirects = utilsTable.filter(pagesInNav, function(page)		return mw.title.new(page).isRedirect	end)

local report = "\n==Report==\n" if #missingUses > 0 or #missingPages > 0 or #wantedPages > 0 or #redirects > 0 then report = report..utilsError.error("", false).."" else report = report.." This navbox is fully bidirectional—all pages that use it are included within it, and vice-versa. " end if #wantedPages > 0 then wantedPages = utilsTable.map(wantedPages, utilsMarkup.link) report = report.."The above navbox contains links to pages which do not exist. Please create these pages or remove them from the navbox:" report = report..utilsMarkup.bulletList(wantedPages) end if #redirects > 0 then redirects = utilsTable.map(redirects, utilsMarkup.link) report = report.."The above navbox contains links to redirects. Please update these links to refer to the redirect targets:" report = report..utilsMarkup.bulletList(redirects) end if #missingUses > 0 then missingUses = utilsTable.map(missingUses, utilsMarkup.link) report = report.."The above navbox is missing from the following pages. Please add  to these pages to ensure that the navigation does not have dead ends. " report = report..utilsMarkup.bulletList(missingUses) end if #missingPages > 0 then missingPages = utilsTable.map(missingPages, utilsMarkup.link) report = report.."The above navbox is missing the following links to pages that use it. Please add these pages to the navbox to ensure that the navigation does not have dead ends." report = report..utilsMarkup.bulletList(missingPages) end return report end

p.Templates = { ["Navbox"] = { format = "block", purpose = "Creates navbox templates.", categories = {"Metatemplates"}, boilerplate = { separateRequiredParams = false, },		paramOrder = {"id", "title", "image", "group", "links", "footer"}, repeatedGroup = { name = "rows", params = {"group", "links"}, counts = {2, 3, 4, 5, 6, 7}, },		params = { id = { type = "string", desc = "A unique ID for the navbox. Sets the id HTML attribute so that the navbox can be linked to.", trim = true, nilIfEmpty = true, },			title = { required = true, type = "content", desc = " The navbox title. It is recommended not to place links in the title as this can create confusion between the clickable navbox header and the link within it. Category links should be placed in the footer. ", trim = true, nilIfEmpty = true, },			image = { type = "wiki-file-name", desc = "A file name, with the  prefix.", trim = true, nilIfEmpty = true, },			group = { type = "string", desc = "A header for the given row in the navbox. Required if there is more than one row.", trim = true, nilIfEmpty = true, },			links = { type = "content", required = true, desc = "A comma-separated list of links for the given row.", trim = true, nilIfEmpty = true, split = true, },			footer = { type = "content", desc = "The navbox footer. Usually contains links to relevant categories.", trim = true, nilIfEmpty = true, },		},	}, }

return p