Module:WikitextProcessor: Difference between revisions
Appearance
// via Wikitext Extension for VSCode |
// via Wikitext Extension for VSCode |
||
| Line 181: | Line 181: | ||
--[[ | --[[ | ||
The "JavaScript Escape Hatch" Factory | |||
This is | |||
functions | This function creates a data-only div intended to be processed by the | ||
NoticeHandler.js gadget. It serves as a workaround for a complex, | |||
environment-specific bug in Scribunto/Lua where string values would | |||
mysteriously disappear when passed through certain table operations. | |||
How it works: | |||
1. Problem: Direct string processing and placeholder replacement in Lua | |||
was failing unpredictably. Byte-level analysis confirmed the string | |||
data was valid, but it would be lost during processing. | |||
2. Solution: Instead of processing the content in Lua, we "escape" from | |||
the Lua environment. This function packages the raw, unprocessed | |||
content and any necessary parameters (like a title) into data-* | |||
attributes on an HTML element. | |||
3. Handoff: This HTML element is then passed to the client-side, where | |||
the NoticeHandler.js gadget picks it up. | |||
4. Execution: The JavaScript, running in the user's browser, reads the | |||
data attributes, performs the string replacements and wikitext | |||
processing, and injects the final HTML into the page. | |||
Architectural Note: | |||
This function is deliberately self-contained and does NOT call any other | |||
functions within this module (like processContentForFrontend). This is | |||
critical to prevent circular dependencies, as this function may be called | |||
by modules that are themselves dependencies of this one. It is a pure | |||
utility for generating the required HTML structure. | |||
--]] | --]] | ||
function p.createNoticeForJS(options) | function p.createNoticeForJS(options) | ||
Revision as of 03:41, 2 August 2025
Documentation for this module may be created at Module:WikitextProcessor/doc
-- Module:WikitextProcessor
-- Generalized content processor for wikitext formatting and frontend display, regardless of source (JSON, XML, database, user input, etc.)
-- Features: Error handling; Three wiki link patterns: [[Page]], [[Page|text]], [[#anchor|text]]; Placeholder replacement with $VARIABLE$ syntax; Content normalization and whitespace cleanup
local p = {}
-- Dependencies
local ErrorHandling = require('Module:ErrorHandling')
-- Constants for performance
local CONTEXT_NAME = 'wikitextProcessor'
local ERROR_MESSAGES = {
urlFailed = 'URL generation failed for wiki link',
encodeFailed = 'Text encoding failed for wiki link',
formatFailed = 'HTML formatting failed for wiki link'
}
-- Clean error handling
local function handleError(errorContext, operation, fallbackValue)
if errorContext then
ErrorHandling.addStatus(errorContext, CONTEXT_NAME, ERROR_MESSAGES[operation] or ERROR_MESSAGES.urlFailed, nil)
end
return fallbackValue
end
-- Constants as upvalues for performance
local WIKI_LINK_PATTERNS = {
-- Pattern 1: [[Page Name]] -> HTML page links
{
pattern = '%[%[([^#|%]]+)%]%]',
processor = function(pageName, errorContext)
local spacesReplaced = (pageName:gsub(' ', '_'))
local success, pageUrl = pcall(function()
return tostring(mw.uri.fullUrl(spacesReplaced))
end)
if not success then
return handleError(errorContext, 'urlFailed', '[[' .. pageName .. ']]')
end
local pageNameStr = type(pageName) == "string" and pageName or tostring(pageName)
success, pageNameStr = pcall(mw.text.encode, pageNameStr)
if not success then
return handleError(errorContext, 'encodeFailed', '[[' .. pageName .. ']]')
end
success, pageUrl = pcall(string.format, '<a href="%s">%s</a>', pageUrl, pageNameStr)
if not success then
return handleError(errorContext, 'formatFailed', '[[' .. pageName .. ']]')
end
return pageUrl
end
},
-- Pattern 2: [[Page|text]] -> HTML page links with custom text
{
pattern = '%[%[([^#|%]]+)|([^%]]+)%]%]',
processor = function(pageName, text, errorContext)
local success, pageUrl = pcall(function()
return tostring(mw.uri.fullUrl((pageName:gsub(' ', '_'))))
end)
if not success then
return handleError(errorContext, 'urlFailed', '[[' .. pageName .. '|' .. text .. ']]')
end
local textStr = type(text) == "string" and text or tostring(text)
success, textStr = pcall(mw.text.encode, textStr)
if not success then
return handleError(errorContext, 'encodeFailed', '[[' .. pageName .. '|' .. text .. ']]')
end
success, pageUrl = pcall(string.format, '<a href="%s">%s</a>', pageUrl, textStr)
if not success then
return handleError(errorContext, 'formatFailed', '[[' .. pageName .. '|' .. text .. ']]')
end
return pageUrl
end
},
-- Pattern 3: [[#anchor|text]] -> HTML anchor links
{
pattern = '%[%[#([^|%]]+)|([^%]]+)%]%]',
processor = function(anchor, text, errorContext)
local success, encodedAnchor = pcall(mw.uri.anchorEncode, anchor)
if not success then
return handleError(errorContext, 'urlFailed', '[[#' .. anchor .. '|' .. text .. ']]')
end
local textStr = type(text) == "string" and text or tostring(text)
success, textStr = pcall(mw.text.encode, textStr)
if not success then
return handleError(errorContext, 'encodeFailed', '[[#' .. anchor .. '|' .. text .. ']]')
end
success, encodedAnchor = pcall(string.format, '<a href="#%s">%s</a>', encodedAnchor, textStr)
if not success then
return handleError(errorContext, 'formatFailed', '[[#' .. anchor .. '|' .. text .. ']]')
end
return encodedAnchor
end
}
}
-- Normalizes content string by cleaning up whitespace
function p.normalizeContentString(content)
if not content or content == "" then
return content
end
-- Apply string normalization exactly like the original T-Campaign code
return content:gsub("%s+", " "):gsub("^%s+", ""):gsub("%s+$", "")
end
-- Replaces placeholder patterns ($VARIABLE$) with actual values
function p.replacePlaceholders(content, placeholderMap)
if not content or not placeholderMap then
return content
end
local result = content
-- Apply placeholder replacement exactly like the original T-Campaign code
for key, value in pairs(placeholderMap) do
if value and value ~= "" then
result = result:gsub("%$" .. key .. "%$", value)
end
end
-- Clean up any remaining unfilled placeholders (TemplateStarter's removeEmptyPlaceholders logic)
result = result:gsub("%$[A-Z_]+%$", "")
result = result:gsub("%s+", " "):gsub("^%s+", ""):gsub("%s+$", "")
return result
end
-- Processes wiki links in content and converts them to HTML
function p.processWikiLinksToHTML(content, errorContext)
if not content or content == "" then
return content
end
-- UNIFIED PIPELINE: Process ALL wiki links with custom patterns (no frame:preprocess)
local originalContent = content
local result = content
-- Process each wiki link pattern in sequence exactly like the original T-Campaign code
for _, patternInfo in ipairs(WIKI_LINK_PATTERNS) do
result = result:gsub(patternInfo.pattern, function(...)
return patternInfo.processor(..., errorContext)
end)
end
return result
end
-- Main entry point: Processes JSON content with wikitext formatting for frontend display
-- @param content The content string to process
-- @param placeholders Optional table of placeholder values for $VARIABLE$ replacement
-- @param errorContext Optional error context for error reporting
-- @return Processed content ready for frontend display
function p.processContentForFrontend(content, placeholders, errorContext)
if not content or content == "" then
return content
end
-- Step 1: Normalize content string
local processedContent = p.normalizeContentString(content)
-- Step 2: Replace placeholders if provided
if placeholders then
processedContent = p.replacePlaceholders(processedContent, placeholders)
end
-- Step 3: Process wiki links to HTML
processedContent = p.processWikiLinksToHTML(processedContent, errorContext)
return processedContent
end
--[[
The "JavaScript Escape Hatch" Factory
This function creates a data-only div intended to be processed by the
NoticeHandler.js gadget. It serves as a workaround for a complex,
environment-specific bug in Scribunto/Lua where string values would
mysteriously disappear when passed through certain table operations.
How it works:
1. Problem: Direct string processing and placeholder replacement in Lua
was failing unpredictably. Byte-level analysis confirmed the string
data was valid, but it would be lost during processing.
2. Solution: Instead of processing the content in Lua, we "escape" from
the Lua environment. This function packages the raw, unprocessed
content and any necessary parameters (like a title) into data-*
attributes on an HTML element.
3. Handoff: This HTML element is then passed to the client-side, where
the NoticeHandler.js gadget picks it up.
4. Execution: The JavaScript, running in the user's browser, reads the
data attributes, performs the string replacements and wikitext
processing, and injects the final HTML into the page.
Architectural Note:
This function is deliberately self-contained and does NOT call any other
functions within this module (like processContentForFrontend). This is
critical to prevent circular dependencies, as this function may be called
by modules that are themselves dependencies of this one. It is a pure
utility for generating the required HTML structure.
--]]
function p.createNoticeForJS(options)
options = options or {}
local noticeData = {
type = options.type or "notice",
position = options.position or "top",
content = options.content or "",
title = options.title or "",
cssClass = options.cssClass or "notice-box"
}
local success, result = pcall(function()
return string.format(
'<div style="display:none" class="notice-data" data-notice-type="%s" data-notice-position="%s" data-banner-template="%s" data-banner-title="%s" data-notice-css="%s"></div>',
mw.text.encode(noticeData.type),
mw.text.encode(noticeData.position),
mw.text.encode(noticeData.content),
mw.text.encode(noticeData.title),
mw.text.encode(noticeData.cssClass)
)
end)
if success then
return result
else
-- In case of error, return a simple error message.
return '<span class="error">Error creating notice.</span>'
end
end
return p