-- Categorizes content and display them.
-- Improvements are welcomed.
-- requires
-- forward declarations
local index;
local build_keys;
local build_values;
local as_key_content_function;
local as_value_content_function;
local as_fold_function;
local escape_replacement;
local unstrip_and_strip_nowiki_tags;
local d = {}
-- exposed: categorizes content and display them
-- 'folder', 'table_*', 'content'
index = function(frame)
local args = build_args(frame)
local folder = as_fold_function(args.folder)
local keys = build_keys(args)
local values = build_values(args.content)
local result = ""
for category, key in pairs(keys) do
local value = values[category]
if value == nil then
value = function(category)
return ""
end
end
result = folder(result,
key(
value(category)
)
)
end
return mw.text.nowiki(mw.dumpObject({args = args, keys = keys, values = values, result = result, d = d}))
end
-- builds arguments
-- reads parent frame
build_args = function(frame)
local result = {}
local pframe = frame:getParent()
for key, value in pairs(frame.args) do
result[mw.text.trim(key)] = mw.text.trim(unstrip_and_strip_nowiki_tags(value))
end
for key, value in pairs(pframe.args) do
result[mw.text.trim(key)] = mw.text.trim(unstrip_and_strip_nowiki_tags(value))
end
return result
end
-- builds key mapping
-- reads 'table_*'
build_keys = function(args)
local result = {}
for arg_k, arg_v in pairs(args) do
local arg_k_trim = mw.text.trim(arg_k)
if arg_k_trim:match("^table_") then
local key = arg_k_trim:gsub("table_", "", 1)
result[key] = as_key_content_function(arg_v)
end
end
return result
end
-- builds values mapping
-- magic words: '__M_INDEX__'
-- syntax: '__M_INDEX__ [category1] [category2] ... [categoryN]'
build_values = function(text)
-- need cleanup
local result = {}
local context = {}
local content = ""
for line_number, line in ipairs(mw.text.split(text, "\n", true)) do -- is \n sufficient
if line:match("^__M_INDEX__") then
-- finish result
for index, category in ipairs(context) do
local sub_result = result[category]
if sub_result == nil then
result[category] = content
else
result[category] = sub_result .. content
end
end
content = ""
-- change context
context = {}
for category in line:gmatch("%[([^%]]*)%]") do
table.insert(context, category)
end
else
-- append content
content = content .. line .. "\n"
end
end
-- one more round of finishing result
for index, category in ipairs(context) do
local sub_result = result[category]
if sub_result == nil then
result[category] = content
else
result[category] = sub_result .. content
end
end
-- turn into content function
for key, value in pairs(result) do
result[key] = as_value_content_function(value)
end
return result
end
-- converts text to key content function
-- magic words: '__M_CONTENT__'
as_key_content_function = function(text)
local function func(content)
table.insert(d, {concatype = 'key', text = text, content = content, result = text:gsub("__M_CONTENT__", escape_replacement(content))})
return text:gsub("__M_CONTENT__", escape_replacement(content))
end
return func
end
-- converts text to value content function
-- magic words: '__M_CATEGORY__'
as_value_content_function = function(text)
local function func(category)
table.insert(d, {concatype = 'value', text = text, category = category, result = text:gsub("__M_CATEGORY__", escape_replacement(category))})
return text:gsub("__M_CATEGORY__", escape_replacement(category))
end
return func
end
-- converts text to folding function
-- magic words: '__M_LEFT__', '__M_RIGHT__'
as_fold_function = function(text)
local function func(left, right)
-- some improvements could be made here
table.insert(d, {concatype = 'fold', text = text, left = left, right = right, result = text:gsub("__M_LEFT__", escape_replacement(left)):gsub("__M_RIGHT__", escape_replacement(right))})
return text:gsub("__M_LEFT__", escape_replacement(left)):gsub("__M_RIGHT__", escape_replacement(right))
end
return func
end
-- escapes replacement, replace '%' with '%%'
escape_replacement = function(text)
return text:gsub("%%", "%%%%")
end
unstrip_and_strip_nowiki_tags = function(text)
return mw.text.unstripNoWiki(text):gsub("<nowiki>", ""):gsub("</nowiki>", "")
end
return {index = index}