# Module:Storm categories/demo

---
-- This module handles demonstration and list of possible values for all storm  
-- category templates! Please test this module on Module:Storm categories/demo/doc  
-- before publishing to avoid errros. Thank you!  
---
local colorRatio = require("Module:Color contrast")._ratio  
local TableTools = require("Module:TableTools")  
local stormcats = require("Module:Storm categories")  
local cats = require("Module:Storm categories/categories").cats  
local colors = require("Module:Storm categories/colors").colors  
local icons = require("Module:Storm categories/icons").icons  
local p = {}  

local customKeys = {}  
for k, v in pairs(colors) do  
table.insert(customKeys, k)  
end  
for k, v in pairs(icons) do  
table.insert(customKeys, k)  
end  
TableTools.removeDuplicates(customKeys)  

function tableEmpty(_table)  
for k, v in pairs(_table) do  
return false  
end  
return true  
end  

--- Generates and renderds the demo table.  
-- @param The Scribunto .  
function p.demo  
local plain = (.args["plain"] or :getParent.args["plain"] or "") ~= ""  
local verbose = (.args["verbose"] or :getParent.args["verbose"] or "") ~= ""  

local legend = setmetatable({}, { refgroupname = "" })  
local errors = setmetatable({}, { refgroupname = "E" })  
local warnings = setmetatable({}, { refgroupname = "W" })  

--- Builds the entire reflist  
-- @param _group The group to build for. Uses `legend` by default.  
function buildReflist(_group)  
group = _group or legend  
return :expandTemplate{ title = 'reflist', args = {  
group = getmetatable(group)["refgroupname"]  
} }  
end  

--- Returns a single  
name = 'ref',  
content = mw.ustring.gsub(details, "%[%[File:([^%|]+)[^%]]*%]%]", ""),  
args = {  
name = hash,  
group = getmetatable(group)["refgroupname"]  
}  
}  
end  

---
return plain and "" or :extensionTag{ name = 'ref', args = {  
name = hash,  
group = getmetatable(group)["refgroupname"]  
} }  
end  

--- Checks for color contrast issues and tags accordingly.  
-- Returns the refernce tag, so this should be used in conjunction with an  
-- HTML node's :wikitext function.  
function contrastCheck(color)  
local catColorBlackRatio = colorRatio({ "#" .. color, "black" })  
local catColorLinkRatio = colorRatio({ "#" .. color, "#0645ad" })  
local catColorVisitedLinkRatio = colorRatio({ "#" .. color, "#0b0080" })  

local finalWikitext = ""  
if catColorBlackRatio == "?" or catColorLinkRatio == "?" or catColorVisitedLinkRatio == "?" then  
finalWikitext = finalWikitext ..  
createLegend("This color must be a hexadecimal color.", errors)  
else  
if catColorBlackRatio < 4.5 then  
finalWikitext = finalWikitext ..  
createLegend("This color has contrast issues with black (not WCAG 2.0 AA-compatible). It will be unusable on all infoboxes and storm season summaries.", errors)  
end  
if catColorLinkRatio < 4.5 then  
finalWikitext = finalWikitext ..  
createLegend("This color has contrast issues with links (not WCAG 2.0 AA-compatible). It should not be used in conjunction with a link.", warnings)  
end  
if catColorVisitedLinkRatio < 4.5 then  
finalWikitext = finalWikitext ..  
createLegend("This color has contrast issues with visited links (not WCAG 2.0 AA-compatible with #0b0080). It should not be used in conjunction with a visited link.", warnings)  
end  
if actualCat == "c0c0c0" and cat[sortkey] ~= 0 then  
finalWikitext = finalWikitext ..  
createLegend("This category is using a color reserved specifically for the \"unknown\" category.", warnings)  
end  
end  
return finalWikitext  
end  

function colorInfo(color, verbose, extra)  
local catColorBlackRatio = colorRatio({ "#" .. color, "black" })  
local catColorLinkRatio = colorRatio({ "#" .. color, "#0645ad" })  
local catColorVisitedLinkRatio = colorRatio({ "#" .. color, "#0b0080" })  

local nc = tostring(mw.html.create("abbr")  
:wikitext("NC")  
:attr("title", "Does not satisfy the minimum WCAG 2.1 compliance level for color contrast (AA)")  
);  
local aa = tostring(mw.html.create("abbr")  
:wikitext("AA")  
:attr("title", "WCAG 2.1 Level AA: Acceptable compliance")  
);  
local aaa = tostring(mw.html.create("abbr")  
:wikitext("AAA")  
:attr("title", "WCAG 2.1 Level AAA: Optimal compliance")  
);  

function contrastLevel(contrast)  
return contrast >= 7 and aaa or (contrast >= 4.5 and aa or nc)  
end  

return mw.html.create("td")  
:attr("data-sort-value", math.min(catColorBlackRatio))  
:wikitext(  
"#" .. color .. (extra or "") .. contrastCheck(color) .. (verbose and ("  
"  
.. tostring(  
mw.html.create("abbr")  
:attr("title", "Contrast to black")  
:wikitext("CTB")  
) .. ": " .. string.format("%.2f", catColorBlackRatio) .. " (" .. contrastLevel(catColorBlackRatio) .. ")  
"  
.. tostring(  
mw.html.create("abbr")  
:attr("title", "Contrast to links")  
:wikitext("CTL")  
) .. ": " .. string.format("%.2f", catColorLinkRatio) .. " (" .. contrastLevel(catColorLinkRatio) .. ")  
"  
.. tostring(  
mw.html.create("abbr")  
:attr("title", "Contrast to visited links")  
:wikitext("CTVL")  
) .. ": " .. string.format("%.2f", catColorVisitedLinkRatio) .. " (" .. contrastLevel(catColorVisitedLinkRatio) .. ")") or "")  
end  

local categoryTable = mw.html.create("table")  
:addClass("wikitable")  
:addClass("sortable")  
:attr("style", "width: 100%")  

categoryTable  
:node(  
mw.html.create("tr")  
:node(mw.html.create("th"):wikitext("Icon")  
:attr("class", "unsortable")  
:attr("rowspan", "2")  
:css("width", "0"))  
:node(mw.html.create("th"):wikitext("ID")  
:attr("rowspan", "2"))  
:node(mw.html.create("th"):wikitext("Name")  
:attr("colspan", "2"))  
:node(mw.html.create("th"):wikitext("Color")  
:attr("rowspan", "2")  
:attr("colspan", "2"))  
:node(mw.html.create("th"):wikitext("Sortkey")  
:attr("colspan", "2"))  
):node(  
mw.html.create("tr")  
:node(mw.html.create("th"):wikitext("Basin"))  
:node(mw.html.create("th"):wikitext("Name"))  
:node(mw.html.create("th"):wikitext("Basin"))  
:node(mw.html.create("th"):wikitext("Sortkey")  
:attr("data-sort-type", "number"))  

for name, cat in TableTools.sortedPairs(cats) do  
local rows = { mw.html.create("tr") }  
local row = rows[1]  

local actualIcon = stormcats._icon(name)  
local icon = mw.html.create("td")  
:wikitext(actualIcon)  
if cat["icon"] ~= nil and actualIcon ~= cat["icon"] then  
icon:wikitext(  
createLegend("Overriden from original icon (" .. cat["icon"] .. ")")  
end  

local id = mw.html.create("td")  
:wikitext(name)  
local actualColor = stormcats._color(name)  
local colorPreview = mw.html.create("td")  
:attr("style", "background-color: #" .. actualColor .. "; padding: 0; width: 1.8em")  
local color = colorInfo(  
actualColor,  
verbose,  
actualColor ~= cat["color"] and createLegend(  
"Overriden from original color ( #"  
.. cat["color"]  
.. ")"  
) or ""  
):css("width", "0"):css("white-space", "nowrap")  

local sortkeyCategory = mw.html.create("td")  
:attr("data-sort-value", cat["sortkey"])  
local sortkey = mw.html.create("td")  
:attr("data-sort-value", cat["sortkey"])  
:wikitext(cat["sortkey"])  

if cat["sortkey"] < 0 then  
sortkeyCategory:wikitext("Invalid")  
elseif cat["sortkey"] < 20000 then  
sortkeyCategory:wikitext("Global")  
elseif cat["sortkey"] < 30000 then  
sortkeyCategory:wikitext("Historical")  
elseif cat["sortkey"] < 40000 then  
sortkeyCategory:wikitext("SWIO")  
elseif cat["sortkey"] < 50000 then  
sortkeyCategory:wikitext("Aus/Fiji")  
elseif cat["sortkey"] < 60000 then  
sortkeyCategory:wikitext("NIO")  
elseif cat["sortkey"] < 80000 then  
sortkeyCategory:wikitext("WPAC")  
elseif cat["sortkey"] < 90000 then  
sortkeyCategory:wikitext("Atl/EPac/SAtl")  
elseif cat["sortkey"] < 100000 then  
sortkeyCategory:attr("style", "color: gray")  
sortkeyCategory:wikitext("*Global*")  
else  
sortkeyCategory:wikitext("Invalid")  
end  

if type(cat["name"]) == "string" then  
local name = mw.html.create("td")  
:attr("colspan", "2")  
:wikitext(cat["name"])  
row:node(icon)  
row:node(id)  
row:node(name)  
else  
local nameTableLength = TableTools.size(cat["name"])  
icon:attr("rowspan", nameTableLength)  
id:attr("rowspan", nameTableLength)  
colorPreview:attr("rowspan", nameTableLength)  
color:attr("rowspan", nameTableLength)  
sortkeyCategory:attr("rowspan", nameTableLength)  
sortkey:attr("rowspan", nameTableLength)  

row:node(icon)  
row:node(id)  
local firstDone = false  
for key, basinName in TableTools.sortedPairs(cat["name"]) do  
if firstDone then  
local nameRow = mw.html.create("tr")  

nameRow  
:node(mw.html.create("td"):wikitext(key))  
:node(mw.html.create("td"):wikitext(basinName))  

table.insert(rows, nameRow)  
else  
firstDone = true  
row  
:node(mw.html.create("td"):wikitext(key))  
:node(mw.html.create("td"):wikitext(basinName))  
end  
end  
end  

row:node(colorPreview)  
row:node(color)  
row:node(sortkeyCategory)  
row:node(sortkey)  

for _, _row in TableTools.sortedPairs(rows) do  
categoryTable:node(_row)  
end  
end  

for name, _ in TableTools.sortedPairs(TableTools.listToSet(customKeys)) do  
if cats[name] == nil then  
local row = mw.html.create("tr")  

local icon = stormcats._icon(name, true)  
row  
:node(mw.html.create("td")  
:wikitext(  
icon ~= nil  
and icon  
or "*<span style=\"color:gray\">N/A</span>*"  
))  
:node(mw.html.create("td"):wikitext(name))  

local color = stormcats._color(name, true)  
-- Add more conditions eventually  
if color ~= nil then  
row  
:node(mw.html.create("td")  
:attr("colspan", "2")  
:wikitext("*<span style=\"color:gray\">not available</span>*"))  
:node(mw.html.create("td")  
:attr("style", "background-color: #" .. color .. "; padding: 0; width: 1.8em"))  
:node(colorInfo(color, verbose))  
:css("width", "0")  
:css("white-space", "nowrap")  
:node(mw.html.create("td")  
:attr("colspan", "2")  
:wikitext("*<span style=\"color:gray\">not available</span>*"))  
else  
row  
:node(mw.html.create("td")  
:attr("colspan", "6")  
:wikitext("*<span style=\"color:gray\">not available</span>*"))  
end  
categoryTable:node(row)  
end  
end  

out = ""  
if not plain and not tableEmpty(errors) then  
out = out  
.. tostring(mw.html.create("h4"):wikitext("Error"))  
.. tostring(mw.html.create("p"):wikitext("This table contains errors than need to be addressed immediately, as it may cause errors on a large amount of pages."))  
.. buildReflist(errors)  
end  
if not plain and not tableEmpty(legend) then  
out = out  
.. tostring(mw.html.create("h4"):wikitext("Legend"))  
.. buildReflist(legend)  
end  
out = out .. tostring(categoryTable)  
if not plain and not tableEmpty(warnings) then  
out = out  
.. tostring(mw.html.create("h4"):wikitext("Warnings"))  
.. tostring(mw.html.create("p"):wikitext("This table contains warnings than should be addressed. Please note that some warnings cannot be fully addressed without changes that would require consensus."))  
.. buildReflist(warnings)  
end  

return mw.text.trim(out)  
end  

return p