Module:ElementNavigation: Difference between revisions
Appearance
// via Wikitext Extension for VSCode |
// via Wikitext Extension for VSCode |
||
| Line 19: | Line 19: | ||
p.elementName = "navigation" | p.elementName = "navigation" | ||
p.defaultConfig = { | p.defaultConfig = { | ||
autoDetect | autoDetect = true, | ||
patterns | patterns = { | ||
seriesNumber = "([^%d]+)%s+(%d+)$", | seriesNumber = "([^%d]+)%s+(%d+)$", | ||
seriesYear = "([^%d]+)%s+(%d%d%d%d)$" | seriesYear = "([^%d]+)%s+(%d%d%d%d)$" | ||
}, | }, | ||
prevField | prevField = "has_previous", | ||
nextField | nextField = "has_next", | ||
prevClass | prevClass = "element-navigation-prev", | ||
nextClass | nextClass = "element-navigation-next", | ||
prevLabel = "← Previous", | |||
nextLabel = "Next →", | |||
prevLabel | rowHeight = "40" | ||
nextLabel | |||
rowHeight | |||
} | } | ||
| Line 119: | Line 117: | ||
return execute(function() | return execute(function() | ||
-- | -- Get configuration from template | ||
local | local config = template.config.navigation or {} | ||
-- Get current page name | -- Get current page name | ||
| Line 183: | Line 174: | ||
-- Get styling options | -- Get styling options | ||
local prevClass = config.prevClass or "element-navigation-prev" | |||
local nextClass = config.nextClass or "element-navigation-next" | |||
local prevLabel = config.prevLabel or "← Previous" | |||
local nextLabel = config.nextLabel or "Next →" | |||
local prevLabel | local rowHeight = config.rowHeight or "40" | ||
local nextLabel | |||
local rowHeight | |||
-- Create navigation row | -- Create navigation row | ||
local output = { | local output = { | ||
'|-', | |||
'|- | |||
'| class="' .. prevClass .. '" height="' .. rowHeight .. '" valign="middle" |' | '| class="' .. prevClass .. '" height="' .. rowHeight .. '" valign="middle" |' | ||
} | } | ||
| Line 201: | Line 189: | ||
if prevPage then | if prevPage then | ||
table.insert(output, string.format( | table.insert(output, string.format( | ||
'<div class=" | '<div class="element-navigation-prev">[[%s|%s]]</div>', | ||
prevPage, prevLabel | |||
)) | )) | ||
else | else | ||
| Line 213: | Line 201: | ||
if nextPage then | if nextPage then | ||
table.insert(output, string.format( | table.insert(output, string.format( | ||
'<div class=" | '<div class="element-navigation-next">[[%s|%s]]</div>', | ||
nextPage, nextLabel | |||
)) | )) | ||
else | else | ||
Revision as of 02:59, 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",
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()
-- Get configuration from template
local config = template.config.navigation or {}
-- 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 or "element-navigation-prev"
local nextClass = config.nextClass or "element-navigation-next"
local prevLabel = config.prevLabel or "← Previous"
local nextLabel = config.nextLabel or "Next →"
local rowHeight = config.rowHeight or "40"
-- Create navigation row
local output = {
'|-',
'| class="' .. prevClass .. '" height="' .. rowHeight .. '" valign="middle" |'
}
-- Add previous link
if prevPage then
table.insert(output, string.format(
'<div class="element-navigation-prev">[[%s|%s]]</div>',
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="element-navigation-next">[[%s|%s]]</div>',
nextPage, nextLabel
))
else
table.insert(output, " ")
end
return table.concat(output, "\n")
end)
end
end
return p