Module:WikitextProcessor: Difference between revisions

// via Wikitext Extension for VSCode
Tag: Reverted
// via Wikitext Extension for VSCode
 
(6 intermediate revisions by the same user not shown)
Line 1: Line 1:
-- Module:WikitextProcessor
--[[
-- Generalized content processor for wikitext formatting and frontend display, regardless of source (JSON, XML, database, user input, etc.)
* Name: WikitextProcessor
-- Features: Error handling; Three wiki link patterns: [[Page]], [[Page|text]], [[#anchor|text]]; Placeholder replacement with $VARIABLE$ syntax; Content normalization and whitespace cleanup
* Author: Mark W. Datysgeld
* Description: Generalized content processor for wikitext formatting and frontend display, regardless of source (JSON, XML, database, user input, etc.)
* Notes: Error handling; three wiki link patterns for page links, page links with custom text, and anchor links; placeholder replacement with $VARIABLE$ syntax; content normalization and whitespace cleanup; JavaScript escape hatch factory for NoticeHandler.js gadget integration to work around Scribunto/Lua environment-specific bugs
]]


local p = {}
local p = {}
Line 115: Line 118:


-- Replaces placeholder patterns ($VARIABLE$) with actual values
-- Replaces placeholder patterns ($VARIABLE$) with actual values
function p.replacePlaceholders(content, placeholderMap, errorContext)
function p.replacePlaceholders(content, placeholderMap)
     if not content then
     if not content or not placeholderMap then
         return content
         return content
    end
   
    -- DEFENSIVE: Input validation with detailed logging
    if not placeholderMap or type(placeholderMap) ~= "table" then
        if errorContext then
            ErrorHandling.addStatus(errorContext, CONTEXT_NAME, 'Invalid placeholder map', 'Type: ' .. type(placeholderMap))
        end
        return content
    end
   
    -- DEFENSIVE: Validate critical placeholders with detailed logging
    local validPlaceholders = {}
    local invalidPlaceholders = {}
   
    for key, value in pairs(placeholderMap) do
        if value and type(value) == "string" and value ~= "" then
            validPlaceholders[key] = value
            if errorContext then
                ErrorHandling.addStatus(errorContext, CONTEXT_NAME, 'Valid placeholder received', 'Key: ' .. key .. ', Value: "' .. value .. '"')
            end
        else
            invalidPlaceholders[key] = tostring(value)
            if errorContext then
                ErrorHandling.addStatus(errorContext, CONTEXT_NAME, 'Invalid placeholder detected', 'Key: ' .. key .. ', Value: "' .. tostring(value) .. '", Type: ' .. type(value))
            end
        end
     end
     end
      
      
Line 149: Line 126:
      
      
     -- Apply placeholder replacement exactly like the original T-Campaign code
     -- Apply placeholder replacement exactly like the original T-Campaign code
     for key, value in pairs(validPlaceholders) do
     for key, value in pairs(placeholderMap) do
         local beforeReplace = result
         if value and value ~= "" then
        result = result:gsub("%$" .. key .. "%$", value)
            result = result:gsub("%$" .. key .. "%$", value)
       
        -- Log successful replacements
        if beforeReplace ~= result and errorContext then
            ErrorHandling.addStatus(errorContext, CONTEXT_NAME, 'Placeholder replaced successfully', 'Key: ' .. key .. ', Replacements made')
         end
         end
     end
     end
      
      
     -- Clean up any remaining unfilled placeholders (TemplateStarter's removeEmptyPlaceholders logic)
     -- Clean up any remaining unfilled placeholders (TemplateStarter's removeEmptyPlaceholders logic)
    local beforeCleanup = result
     result = result:gsub("%$[A-Z_]+%$", "")
     result = result:gsub("%$[A-Z_]+%$", "")
     result = result:gsub("%s+", " "):gsub("^%s+", ""):gsub("%s+$", "")
     result = result:gsub("%s+", " "):gsub("^%s+", ""):gsub("%s+$", "")
   
    -- Log cleanup if any unfilled placeholders were removed
    if beforeCleanup ~= result and errorContext then
        ErrorHandling.addStatus(errorContext, CONTEXT_NAME, 'Unfilled placeholders cleaned up', 'Content normalized')
    end
      
      
     return result
     return result
Line 207: Line 174:
     -- Step 2: Replace placeholders if provided
     -- Step 2: Replace placeholders if provided
     if placeholders then
     if placeholders then
         processedContent = p.replacePlaceholders(processedContent, placeholders, errorContext)
         processedContent = p.replacePlaceholders(processedContent, placeholders)
     end
     end
      
      
Line 214: Line 181:
      
      
     return processedContent
     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
end


return p
return p