Module:ElementNavigation: Difference between revisions
Appearance
// via Wikitext Extension for VSCode |
// via Wikitext Extension for VSCode |
||
| Line 193: | Line 193: | ||
-- Create navigation row | -- Create navigation row | ||
local output = { | local output = { | ||
'|-', | -- Add template-data-row class to <tr> for consistent row styling | ||
'|- class="template-data-row"', | |||
'| class="' .. prevClass .. '" height="' .. rowHeight .. '" valign="middle" |' | '| class="' .. prevClass .. '" height="' .. rowHeight .. '" valign="middle" |' | ||
} | } | ||
Revision as of 02:53, 27 April 2025
Documentation for this module may be created at Module:ElementNavigation/doc
--[[
* Module:ElementNavigation
* Provides navigation detection and rendering for sequential content
*
* This module detects previous/next pages based on naming patterns
* and renders navigation links. It's designed to be used as a block
* in the Blueprint template system.
*
* Features:
* - Automatic detection of previous/next pages based on patterns
* - Support for both series+number and series+year patterns
* - Caching of detection results for performance
* - Configurable field names and styling
* - Blueprint integration as a custom block
]]
local p = {}
p.elementName = "navigation"
p.defaultConfig = {
autoDetect = true,
patterns = {
seriesNumber = "([^%d]+)%s+(%d+)$",
seriesYear = "([^%d]+)%s+(%d%d%d%d)$"
},
prevField = "has_previous",
nextField = "has_next",
prevClass = "element-navigation-prev",
nextClass = "element-navigation-next",
linkPrevClass = "element-nav-prev",
linkNextClass = "element-nav-next",
prevLabel = "← Previous",
nextLabel = "Next →",
rowHeight = "40"
}
-- Cache for navigation detection results
local navigationCache = {}
-- ========== Navigation Detection ==========
-- Detect navigation links based on patterns
-- @param pageName string The current page name
-- @param patterns table Table of patterns to use
-- @return table Navigation result with prev and next properties
function p.detectNavigation(pageName, patterns)
-- Check cache first
local cacheKey = pageName
if navigationCache[cacheKey] ~= nil then
return navigationCache[cacheKey]
end
local result = nil
-- Try Series + Number pattern: "ICANN 76"
local series, number = pageName:match(patterns.seriesNumber or "([^%d]+)%s+(%d+)$")
if series and number then
number = tonumber(number)
local prev = (number > 1) and string.format("%s %d", series, number - 1) or nil
local next = string.format("%s %d", series, number + 1)
-- Check if pages exist
local prevPage = prev and mw.title.new(prev) or nil
local nextPage = mw.title.new(next)
result = {
prev = prevPage and prevPage.exists and prev or nil,
next = nextPage and nextPage.exists and next or nil
}
end
-- If no result yet, try Series + Year pattern: "IGF 2023"
if not result then
local series, year = pageName:match(patterns.seriesYear or "([^%d]+)%s+(%d%d%d%d)$")
if series and year then
year = tonumber(year)
local prev = string.format("%s %d", series, year - 1)
local next = string.format("%s %d", series, year + 1)
-- Check if pages exist
local prevPage = mw.title.new(prev)
local nextPage = mw.title.new(next)
result = {
prev = prevPage and prevPage.exists and prev or nil,
next = nextPage and nextPage.exists and next or nil
}
end
end
-- Store in cache (including nil results)
navigationCache[cacheKey] = result
return result
end
-- ========== Blueprint Integration ==========
-- Create a navigation block for Blueprint
-- @return function Block rendering function for Blueprint
function p.createBlock()
return function(template, args)
-- Get error context from template if available
local errorContext = template._errorContext
-- Protected execution if error context is available
local execute = function(func, ...)
if errorContext and errorContext.protect then
return errorContext.protect(
errorContext,
"NavigationBlock",
func,
"",
...
)
else
return func(...)
end
end
return execute(function()
-- Merge default config with template overrides
local rawCfg = template.config.navigation or {}
local config = {}
for k, v in pairs(p.defaultConfig) do
config[k] = v
end
for k, v in pairs(rawCfg) do
config[k] = v
end
-- Get current page name
local pageName = mw.title.getCurrentTitle().text
-- Detect navigation
local autoNavigation = nil
if config.autoDetect ~= false then
autoNavigation = p.detectNavigation(pageName, config.patterns or {})
end
-- Get field names
local prevField = config.prevField or "has_previous"
local nextField = config.nextField or "has_next"
-- Check for user-provided navigation values
local hasPrev = args[prevField]
local hasNext = args[nextField]
-- If no navigation is provided at all, return empty string
if (not hasPrev or hasPrev == "") and (not hasNext or hasNext == "") and not autoNavigation then
return ""
end
-- Determine previous and next pages
local prevPage = nil
local nextPage = nil
-- Process previous page
if hasPrev and hasPrev ~= "" then
if hasPrev ~= "yes" and hasPrev ~= "true" then
prevPage = hasPrev
elseif autoNavigation and autoNavigation.prev then
prevPage = autoNavigation.prev
end
elseif autoNavigation and autoNavigation.prev then
prevPage = autoNavigation.prev
end
-- Process next page
if hasNext and hasNext ~= "" then
if hasNext ~= "yes" and hasNext ~= "true" then
nextPage = hasNext
elseif autoNavigation and autoNavigation.next then
nextPage = autoNavigation.next
end
elseif autoNavigation and autoNavigation.next then
nextPage = autoNavigation.next
end
-- If no actual navigation links were found, return empty string
if not prevPage and not nextPage then
return ""
end
-- Get styling options
local prevClass = config.prevClass
local nextClass = config.nextClass
local linkPrevClass = config.linkPrevClass
local linkNextClass = config.linkNextClass
local prevLabel = config.prevLabel
local nextLabel = config.nextLabel
local rowHeight = config.rowHeight
-- Create navigation row
local output = {
-- Add template-data-row class to <tr> for consistent row styling
'|- class="template-data-row"',
'| class="' .. prevClass .. '" height="' .. rowHeight .. '" valign="middle" |'
}
-- Add previous link
if prevPage then
table.insert(output, string.format(
'<div class="%s">[[%s|%s]]</div>',
linkPrevClass, prevPage, prevLabel
))
else
table.insert(output, " ")
end
-- Add next link cell
table.insert(output, '| class="' .. nextClass .. '" height="' .. rowHeight .. '" valign="middle" |')
if nextPage then
table.insert(output, string.format(
'<div class="%s">[[%s|%s]]</div>',
linkNextClass, nextPage, nextLabel
))
else
table.insert(output, " ")
end
return table.concat(output, "\n")
end)
end
end
return p