Module:columns: Difference between revisions

no edit summary
No edit summary
No edit summary
 
(2 intermediate revisions by the same user not shown)
Line 3: Line 3:
local m_links = require("Module:links")
local m_links = require("Module:links")
local m_languages = require("Module:languages")
local m_languages = require("Module:languages")
local m_table = require("Module:table")




local function format_list_items(items, lang)
local function format_list_items(items, lang, sc)
local result = {}
local result = {}
 
for i, item in ipairs(items) do
local function term_already_linked(term)
if lang and not string.find(item, "<span") then
-- FIXME: "<span" is an ugly hack to prevent double-linking of terms already run through {{l|...}}:
item = m_links.full_link({lang = lang, term = item})
-- [[Thread:User talk:CodeCat/MewBot adding lang to column templates]]
return term:find("<span")
end
for _, item in ipairs(items) do
if type(item) == "table" then
local link = term_already_linked(item.term.term) and item.term.term or m_links.full_link(item.term)
if item.q then
link = require("Module:qualifier").format_qualifier(item.q) .. " " .. link
end
if item.qq then
link = link .. " " .. require("Module:qualifier").format_qualifier(item.qq)
end
item = link
elseif lang and not term_already_linked(item) then
item = m_links.full_link {lang = lang, term = item, sc = sc}  
end
end
 
result[i] = '\n* ' .. item
table.insert(result, '\n* ' .. item)
end
end
 
return table.concat(result)
return table.concat(result)
end
end
Line 36: Line 51:
error("expected table, got " .. type(args))
error("expected table, got " .. type(args))
end
end
 
args.class = args.class or "derivedterms"
args.class = args.class or "derivedterms"
args.column_count = args.column_count or 1
args.column_count = args.column_count or 1
args.toggle_category = args.toggle_category or "derived terms"
args.toggle_category = args.toggle_category or "derived terms"
 
local output = {}
local output = {}
 
if args.header then
if args.header then
if args.format_header then
if args.format_header then
Line 53: Line 68:
end
end
table.insert(output, (column_header:gsub('{{{(.-)}}}', args)))
table.insert(output, (column_header:gsub('{{{(.-)}}}', args)))
 
     if args.alphabetize then
     if args.alphabetize then
require("Module:collation").sort(args.content, args.lang)
    local function keyfunc(item)
    if type(item) == "table" then
    item = item.term.term
    end
    return item
    end
require("Module:collation").sort(args.content, args.lang, keyfunc)
end
end
table.insert(output, format_list_items(args.content, args.lang))
table.insert(output, format_list_items(args.content, args.lang, args.sc))
 
table.insert(output, '</div>')
table.insert(output, '</div>')
if args.collapse then
if args.collapse then
table.insert(output, button .. '</div>')
table.insert(output, button .. '</div>')
end
end
 
return table.concat(output)
return table.concat(output)
end
end
Line 77: Line 98:
args.collapse, args.class, args.header, args.column_width,
args.collapse, args.class, args.header, args.column_width,
args.line_start, args.lang = ...
args.line_start, args.lang = ...
 
args.format_header = true
args.format_header = true
 
return export.create_list(args)
return export.create_list(args)
end
end




function export.display(frame)
local param_mods = {"t", "alt", "tr", "ts", "pos", "lit", "id", "sc", "g", "q", "qq"}
local param_mod_set = m_table.listToSet(param_mods)
 
function export.display_from(column_args, list_args)
local iparams = {
local iparams = {
["class"] = {},
["class"] = {},
Line 105: Line 129:
["toggle_category"] = {},
["toggle_category"] = {},
}
}
 
local frame_args = require("Module:parameters").process(frame.args, iparams)
local frame_args = require("Module:parameters").process(column_args, iparams, nil, "columns", "display_from")
local parent_args = frame:getParent().args
 
local compat = frame_args["lang"] or list_args["lang"]
local compat = frame_args["lang"] or parent_args["lang"]
local lang_param = compat and "lang" or 1
local lang_param = compat and "lang" or 1
local columns_param = compat and 1 or 2
local columns_param = compat and 1 or 2
Line 118: Line 141:
[columns_param] = not frame_args["columns"] and {required = true, default = 2} or nil,
[columns_param] = not frame_args["columns"] and {required = true, default = 2} or nil,
[first_content_param] = {list = true},
[first_content_param] = {list = true},
 
["title"] = {},
["title"] = {},
["collapse"] = {type = "boolean"},
["collapse"] = {type = "boolean"},
["sort"] = {type = "boolean"},
["sort"] = {type = "boolean"},
["sc"] = {},
}
}
 
local args = require("Module:parameters").process(parent_args, params)
local args = require("Module:parameters").process(list_args, params, nil, "columns", "display_from")
 
local lang = frame_args["lang"] or args[lang_param]
local lang = frame_args["lang"] or args[lang_param]
lang = m_languages.getByCode(lang) or m_languages.err(lang, lang_param)
lang = m_languages.getByCode(lang, lang_param)
 
local sc = args["sc"] and require("Module:scripts").getByCode(sc, "sc") or nil
 
local sort = frame_args["sort"]
local sort = frame_args["sort"]
if args["sort"] ~= nil then
if args["sort"] ~= nil then
Line 137: Line 163:
collapse = args["collapse"]
collapse = args["collapse"]
end
end
 
local put
for i, item in ipairs(args[first_content_param]) do
-- Parse off an initial language code (e.g. 'la:minūtia' or 'grc:[[σκῶρ|σκατός]]'). Don't parse if there's a spac
-- after the colon (happens e.g. if the user uses {{desc|...}} inside of {{col}}, grrr ...).
local termlang, actual_term = item:match("^([A-Za-z._-]+):([^ ].*)$")
-- Make sure that only real language codes are handled as language links, so as to not catch interwiki
-- or namespaces links.
if termlang and (
mw.loadData("Module:languages/code to canonical name")[termlang] or
mw.loadData("Module:etymology languages/code to canonical name")[termlang]
) then
-- -1 since i is one-based
termlang = m_languages.getByCode(termlang, first_content_param + i - 1, "allow etym")
item = actual_term
else
termlang = lang
end
local termobj = {term = {lang = termlang, sc = sc}}
 
-- Check for inline modifier, e.g. מרים<tr:Miryem>. But exclude HTML entry with <span ...>, <i ...>, <br/> or
-- similar in it, caused by wrapping an argument in {{l|...}}, {{af|...}} or similar. Basically, all tags of
-- the sort we parse here should consist of a less-than sign, plus letters, plus a colon, e.g. <tr:...>, so if
-- we see a tag on the outer level that isn't in this format, we don't try to parse it. The restriction to the
-- outer level is to allow generated HTML inside of e.g. qualifier tags, such as foo<q:similar to {{m|fr|bar}}>.
if item:find("<") and not item:find("^[^<]*<[a-z]*[^a-z:]") then
if not put then
put = require("Module:parse utilities")
end
local run = put.parse_balanced_segment_run(item, "<", ">")
local orig_param = first_content_param + i - 1
local function parse_err(msg)
error(msg .. ": " .. orig_param .. "= " .. table.concat(run))
end
termobj.term.term = run[1]
 
for j = 2, #run - 1, 2 do
if run[j + 1] ~= "" then
parse_err("Extraneous text '" .. run[j + 1] .. "' after modifier")
end
local modtext = run[j]:match("^<(.*)>$")
if not modtext then
parse_err("Internal error: Modifier '" .. modtext .. "' isn't surrounded by angle brackets")
end
local prefix, arg = modtext:match("^([a-z]+):(.*)$")
if not prefix then
parse_err("Modifier " .. run[j] .. " lacks a prefix, should begin with one of '" ..
table.concat(param_mods, ":', '") .. ":'")
end
if param_mod_set[prefix] then
local obj_to_set
if prefix == "q" or prefix == "qq" then
obj_to_set = termobj
else
obj_to_set = termobj.term
end
if prefix == "t" then
prefix = "gloss"
elseif prefix == "g" then
prefix = "genders"
arg = mw.text.split(arg, ",")
elseif prefix == "sc" then
arg = require("Module:scripts").getByCode(arg, orig_param .. ":sc")
end
if obj_to_set[prefix] then
parse_err("Modifier '" .. prefix .. "' occurs twice, second occurrence " .. run[j])
end
obj_to_set[prefix] = arg
else
parse_err("Unrecognized prefix '" .. prefix .. "' in modifier " .. run[j])
end
end
else
termobj.term.term = item
end
args[first_content_param][i] = termobj
end
 
return export.create_list { column_count = frame_args["columns"] or args[columns_param],
return export.create_list { column_count = frame_args["columns"] or args[columns_param],
content = args[first_content_param],
content = args[first_content_param],
Line 144: Line 247:
collapse = collapse,
collapse = collapse,
toggle_category = frame_args["toggle_category"],
toggle_category = frame_args["toggle_category"],
class = frame_args["class"], lang = lang, format_header = true }
class = frame_args["class"], lang = lang, sc = sc, format_header = true }
end
end


function export.display(frame)
return export.display_from(frame.args, frame:getParent().args)
end
-- A version of col which substs any automatically generated forms in order to save memory (e.g. for Chinese).
function export.generated_forms(frame)
local column_args, list_args = frame.args, frame:getParent().args
local iparams = {
["columns"] = {type = "number"},
["name"] = {required = true},
["toggle_category"] = {},
}
local frame_args = require("Module:parameters").process(column_args, iparams, nil, "columns", "generated_forms")
local first_content_param = 2 + (frame_args["columns"] and 0 or 1)
frame_args["name"] = frame_args["columns"] and frame_args["name"] .. frame_args["columns"] or frame_args["name"]
local params = {
[1] = {required = true, default = "und"},
[2] = not frame_args["columns"] and {required = true, default = 2} or nil,
[first_content_param] = {list = true},
["title"] = {},
["collapse"] = {type = "boolean"},
["sort"] = {type = "boolean"},
["sc"] = {},
}
local args = require("Module:parameters").process(list_args, params, nil, "columns", "generated_forms")
local lang = args[1]
lang = m_languages.getByCode(lang, lang_param)
args["sc"] = args["sc"] or ""
if sc and sc ~= "" then
sc = require "Module:scripts".getByCode(sc)
or error("|sc= does not contain a valid script code")
end
args[2] = args[2] or ""
args["title"] = args["title"] or ""
args["collapse"] = args["collapse"] or ""
args["sort"] = args["sort"] or ""
local items = {}
for i, item in ipairs(args[first_content_param]) do
if item:find("<") and not item:find("^[^<]*<[a-z]*[^a-z:]") then
item = item:gsub("^([^<]*)(<[a-z]*[a-z:])", function(m1, m2)
return table.concat(lang:generateForms(m1), "//")
end)
else
item = table.concat(lang:generateForms(item), "//")
end
table.insert(items, item)
end
for k, arg in pairs(args) do
if type(arg) == "string" then
if arg ~= "" then
if type(k) == "string" then
args[k] = k .. "=" .. args[k] .. "|"
else
args[k] = args[k] .. "|"
end
end
elseif type(arg) == "boolean" then
args[k] = k .. "=1|"
end
end
local prefix = "{{" .. frame_args["name"] .. "|" .. args[1] .. args["sc"]
prefix = not frame_args["columns"] and prefix .. args[2] or prefix
return prefix ..  args["title"] ..  args["collapse"] ..  args["sort"] ..  table.concat(items, "|") .. "}}"
end


return export
return export