Модуль:chemcard
| Строка 4: | Строка 4: | ||
local function getArgs(frame) | local function getArgs(frame) | ||
if type(frame) == "table" and frame.args then | if type(frame) == "table" and frame.args then return frame.args end | ||
return mw.getCurrentFrame():getParent().args or {} | return mw.getCurrentFrame():getParent().args or {} | ||
end | end | ||
| Строка 15: | Строка 13: | ||
for line in mw.text.gsplit(s, "\n") do | for line in mw.text.gsplit(s, "\n") do | ||
line = mw.text.trim(line) | line = mw.text.trim(line) | ||
if line ~= "" then | if line ~= "" then table.insert(t, line) end | ||
end | end | ||
return t | return t | ||
| Строка 24: | Строка 20: | ||
local function parseLineToItem(l) | local function parseLineToItem(l) | ||
local name, qty = mw.ustring.match(l, "^(.*)%s*%[%s*([%d,%.]+)%s*%]%s*$") | local name, qty = mw.ustring.match(l, "^(.*)%s*%[%s*([%d,%.]+)%s*%]%s*$") | ||
if not name then | if not name then name = l; qty = "1" end | ||
return { name = mw.text.trim(name), qty = qty or "1" } | |||
return { | |||
end | end | ||
local function parseRecipeString(recipeStr) | local function parseRecipeString(recipeStr) | ||
if not recipeStr or recipeStr == "" then | if not recipeStr or recipeStr == "" then return {} end | ||
local lines = splitLines(recipeStr) | local lines = splitLines(recipeStr) | ||
local recipes = {} | |||
local currentInputs = {} | |||
local i = 1 | |||
while i <= #lines do | |||
local | local line = lines[i] | ||
local lower = mw.ustring.lower(line) | |||
if lower:find("смеш") then | |||
if #currentInputs > 0 then | |||
local outputs = {} | |||
i = i + 1 | |||
while i <= #lines do | |||
local nextLine = lines[i] | |||
local nextLower = mw.ustring.lower(nextLine) | |||
if nextLower:find("смеш") then break end | |||
table.insert(outputs, parseLineToItem(nextLine)) | |||
i = i + 1 | |||
end | |||
table.insert(recipes, { | |||
inputs = currentInputs, | |||
outputs = outputs, | |||
action = "Смешайте" | |||
}) | |||
currentInputs = {} | |||
else | |||
table.insert( | i = i + 1 | ||
end | |||
else | |||
table.insert(currentInputs, parseLineToItem(line)) | |||
i = i + 1 | |||
end | end | ||
end | end | ||
if #currentInputs > 0 then | |||
if #inputs = | table.insert(recipes, { inputs = currentInputs, outputs = {}, action = "" }) | ||
end | end | ||
return recipes | |||
return | |||
end | end | ||
local function buildRecipeHtml(rec) | local function buildRecipeHtml(rec, index) | ||
if not rec or (#rec.inputs == 0 and #rec.outputs == 0) then | if not rec or (#rec.inputs == 0 and #rec.outputs == 0) then return nil end | ||
local container = html.create("div"):addClass("chem-recipe-block") | local container = html.create("div"):addClass("chem-recipe-block") | ||
local heading = html.create("div") | if index == 1 then | ||
local heading = html.create("div"):addClass("chem-heading"):attr("data-kind", "recipe") | |||
local hcontent = heading:tag("div"):addClass("chem-heading-content") | |||
hcontent:tag("span"):addClass("heading-text"):wikitext("Рецепты") | |||
hcontent:tag("span"):addClass("collapse-btn"):wikitext("развернуть") | |||
container:node(heading) | |||
end | |||
local collapsible = html.create("div") | local collapsible = html.create("div"):addClass("collapsible collapsed"):attr("data-kind", "recipe") | ||
local inner = html.create("div"):addClass("chem-recipe") | local inner = html.create("div"):addClass("chem-recipe") | ||
| Строка 100: | Строка 82: | ||
local inputsDiv = html.create("div"):addClass("recipe-inputs") | local inputsDiv = html.create("div"):addClass("recipe-inputs") | ||
for _, it in ipairs(rec.inputs) do | for _, it in ipairs(rec.inputs) do | ||
inputsDiv:tag("div") | local item = inputsDiv:tag("div"):addClass("recipe-item") | ||
item:tag("img"):attr("src", "Beaker.png"):attr("alt", "Колба"):addClass("chem-beaker") | |||
item:tag("span"):addClass("recipe-item-text"):wikitext(it.name .. " [" .. it.qty .. "]") | |||
end | end | ||
inner:node(inputsDiv) | inner:node(inputsDiv) | ||
if rec.action ~= "" then | if rec.action ~= "" then | ||
inner:tag("div") | local actionDiv = inner:tag("div"):addClass("recipe-action") | ||
actionDiv:tag("span"):wikitext(rec.action) | |||
end | end | ||
local outputsDiv = html.create("div"):addClass("recipe-outputs") | local outputsDiv = html.create("div"):addClass("recipe-outputs") | ||
for _, it in ipairs(rec.outputs) do | for _, it in ipairs(rec.outputs) do | ||
outputsDiv:tag("div") | local item = outputsDiv:tag("div"):addClass("recipe-item") | ||
item:tag("img"):attr("src", "Beaker.png"):attr("alt", "Колба"):addClass("chem-beaker") | |||
item:tag("span"):addClass("recipe-item-text"):wikitext(it.name .. " [" .. it.qty .. "]") | |||
end | end | ||
inner:node(outputsDiv) | inner:node(outputsDiv) | ||
| Строка 126: | Строка 107: | ||
local function buildEffectsHtml(effects) | local function buildEffectsHtml(effects) | ||
if not effects or effects == "" or effects == "Нет" then | if not effects or effects == "" or effects == "Нет" then return nil end | ||
local container = html.create("div"):addClass("chem-effects-block") | local container = html.create("div"):addClass("chem-effects-block") | ||
local heading = html.create("div") | local heading = html.create("div"):addClass("chem-heading"):attr("data-kind", "effects") | ||
local hcontent = heading:tag("div"):addClass("chem-heading-content") | |||
hcontent:tag("span"):addClass("heading-text"):wikitext("Эффекты") | |||
heading:tag("span"):wikitext("Эффекты") | hcontent:tag("span"):addClass("collapse-btn"):wikitext("развернуть") | ||
container:node(heading) | container:node(heading) | ||
local collapsible = html.create("div") | local collapsible = html.create("div"):addClass("collapsible collapsed"):attr("data-kind", "effects") | ||
local inner = html.create("div"):addClass("chem-effects") | local inner = html.create("div"):addClass("chem-effects") | ||
for effect in mw.text.gsplit(effects, "[;\n]") do | for effect in mw.text.gsplit(effects, "[;\n]") do | ||
effect = mw.text.trim(effect) | effect = mw.text.trim(effect) | ||
if effect ~= "" | if effect ~= "" then | ||
inner:tag("div"):addClass("chem-effect-line"):wikitext(effect) | |||
end | end | ||
end | end | ||
collapsible:node(inner) | collapsible:node(inner) | ||
container:node(collapsible) | container:node(collapsible) | ||
| Строка 162: | Строка 132: | ||
function p.card(frame) | function p.card(frame) | ||
local args = getArgs(frame) | local args = getArgs(frame) | ||
local name = args.name or "—" | local name = args.name or "—" | ||
local color = args.color or "#8cf" | local color = args.color or "#8cf" | ||
local border = args.border or "#444" | local border = args.border or "#444" | ||
local desc = args.desc or "" | local desc = args.desc or "" | ||
| Строка 175: | Строка 143: | ||
local recipeStr = args[key] | local recipeStr = args[key] | ||
if not recipeStr then break end | if not recipeStr then break end | ||
local parsedList = parseRecipeString(recipeStr) | |||
local | for _, rec in ipairs(parsedList) do | ||
table.insert(recipes, rec) | |||
table.insert(recipes, | |||
end | end | ||
i = i + 1 | i = i + 1 | ||
| Строка 186: | Строка 153: | ||
container:attr("style", "border-color:" .. border .. "; --card-accent:" .. color) | container:attr("style", "border-color:" .. border .. "; --card-accent:" .. color) | ||
container:tag(" | container:tag("div"):addClass("chem-name-header"):wikitext(name) | ||
for | if #recipes > 0 then | ||
for idx, rec in ipairs(recipes) do | |||
local block = buildRecipeHtml(rec, idx) | |||
if block then container:node(block) end | |||
end | end | ||
end | end | ||
local effectsBlock = buildEffectsHtml(effects) | local effectsBlock = buildEffectsHtml(args.effects) | ||
if effectsBlock then | if effectsBlock then container:node(effectsBlock) end | ||
if desc ~= "" then | if desc ~= "" then | ||