Module:ModularCSS

From The Satanic Wiki
Jump to navigation Jump to search

Documentation for this module may be created at Module:ModularCSS/doc

--| Module:ModularCSS (v1.5.0)
--  v1.5.0 - Retrieves MediaWiki messages through mw.message
--by "The JoTS"

--- Lua module that simplifies clutter on wiki's CSS pages
--- by dynamically generating modular CSS code.

-- e.g. CSS that changes the link color of every wiki admin
-- e.g. Infoboxes that change color on a page by page basis

-- <nowiki>

-- [==[ Module Start ]==] ------
local module  = {}
local imports = {}
local configs = {}

local localUrl = mw.uri.localUrl

-- Helper functions
local function parse(pgName)
    -- Avoid incrementing expensive function count
    -- if using a special page, return empty table
    if pgName:sub(1,8):lower() == "special:" then return {} end
    
    -- Find cached parsed results and return
    if configs[pgName] then return configs[pgName] end
    
    -- BEGIN PARSING TASK
    -- Find page and get content
    local page
    if pgName:sub(1,10):lower() == "mediawiki:" then
        page = mw.message.new(pgName:sub(11))
        assert(page:exists(),
            'The config page "' .. pgName .. '" does not exist on this wiki.')
        
        page = tostring(page) .. '\n'
    else
        page = mw.title.new(pgName)
        assert(page, "Invalid page title!")
        assert(page.exists,
            'The config page "' .. pgName .. '" does not exist on this wiki.')
        
        page = (page:getContent() or "") .. '\n'
    end
    
    -- Flags... and stuff
    local parsed = {}
    local parent_obj = parsed
    local last_index
    local curr_lvl = 1
    
    -- Parse bulleted list
    for ast,val in page:gmatch("(\*+)%s*(.-)\n") do
        local lvl = #ast
        local key, true_self = (val:gsub(" ","_")), (val:gsub("_"," "))

        if lvl > curr_lvl then
            parent_obj = parent_obj[last_index]
        elseif lvl < curr_lvl then
            parent_obj = parent_obj.parent
        end
        
        assert(not parent_obj[key], "Duplicate value in the same bullet level!")
        
        parent_obj[key] = setmetatable({},{
            __index = {
                parent = parent_obj,
                self = true_self, -- standardized, unadulterated by underscores; human readable ver.
                
                getLocalUrl = function(t, raw)
                    return tostring(localUrl(t.self))
                        :gsub("%%", {[raw and '' or "%"] = "%%"}) -- this is stupid
                end,
                    
                getValue = function(t)
                    return next(t) and next(t).self
                end
            }
        })
        
        last_index = key
        curr_lvl = lvl
    end
    
    -- cache
    configs[pgName] = parsed;
    
    -- return newly parsed results
    return parsed
end

-- Invoked wikitext functions
local function _render()
    assert(#imports > 0, "No ModularCSS modules were imported!")
    
    local renderedCSS = ""
    
    for modNum,cssMod in pairs(imports) do
        local err_header = "CSS Module #" .. modNum .. ": "
        
        -- CSS module format errors
        assert(cssMod.page and type(cssMod.page) == "string",
            err_header .. '"page" string provided in module is invalid.')
        assert(cssMod.main and type(cssMod.main) == "function",
            err_header .. '"main" function provided in module is invalid.')
        
        local success,css_vars = pcall(parse, cssMod.page)
        assert(success, err_header .. tostring(css_vars))
        
        local success,modCompiledCSS = pcall(cssMod.main, css_vars)
        renderedCSS = renderedCSS
            .. assert(
                assert(success, modCompiledCSS) and modCompiledCSS,
                "The CSS module did not return a value."
            )
    end
    
    return renderedCSS
end

local render = function(frame)
    local success,compiled = pcall(_render)
    if (not success) then return "/*" .. compiled .. "*/" end
    
    return frame:preprocess('/*<syntaxhighlight lang="css" enclose="div" '
        .. 'style="overflow:auto;">*/'
        .. compiled
        .. '/*</syntaxhighlight>*/')
end

-- Meta-module functions
local function import_wrap(lax)
    return function(moduleName)
        assert(type(moduleName) == "string", "Invalid module request! Not a string.")
        local success,reqModule = pcall(require, moduleName)
        assert(success, "Non-existent module requested: " .. moduleName)
        
        table.insert(imports, reqModule)
        reqModule.page = lax and reqModule.public_page or reqModule.page
        
        return module
    end
end

local import    = import_wrap(false)
local importlax = import_wrap(true)

-- en
module.import = import
module.render = render
module.importlax = importlax

return module