模块:CardData:修订间差异
来自夜幕之下
更多操作
无编辑摘要 标签:已被回退 |
无编辑摘要 标签:已被回退 |
||
| 第24行: | 第24行: | ||
:addClass("card_content-item-title") | :addClass("card_content-item-title") | ||
:addClass("card_content-item-title--mt") | :addClass("card_content-item-title--mt") | ||
if extraClass then div:addClass(extraClass) end | if extraClass then div:addClass(extraClass) end | ||
div:wikitext(titleText) | div:wikitext(titleText) | ||
div:tag("span"):addClass("card_content-item-subtitle"):wikitext(subtitleText) | div:tag("span") | ||
:addClass("card_content-item-subtitle") | |||
:wikitext(subtitleText) | |||
return div | return div | ||
end | end | ||
local function makeHr(extraClass) | local function makeHr(extraClass) | ||
local div = mw.html.create("div"):addClass("card_content-item-hr") | local div = mw.html.create("div") | ||
:addClass("card_content-item-hr") | |||
if extraClass then div:addClass(extraClass) end | if extraClass then div:addClass(extraClass) end | ||
return div | return div | ||
end | end | ||
local function | local function makeStoryTimeline(stories, cardTitle) | ||
local | |||
local timeline = mw.html.create("div") | |||
:addClass("card_timeline card_content_story-timeline") | |||
timeline:tag("div") | |||
:addClass("card_timeline-line") | |||
-- 更安全获取 entry | |||
local entry | |||
if type(stories) == "table" then | |||
for _,v in pairs(stories) do | |||
entry = v | |||
break | |||
local | |||
end | end | ||
end | end | ||
local chapters = entry and entry.story or {} | |||
local | |||
if not chapters or type(chapters) ~= "table" then | |||
chapters = {} | |||
if not | |||
end | end | ||
if next(chapters) == nil then | |||
timeline:tag("div") | |||
:addClass("card_timeline-item") | |||
:wikitext("(小传数据待补充)") | |||
timeline:tag("div"):addClass("card_timeline-item"):wikitext("(小传数据待补充)") | |||
return timeline | return timeline | ||
end | end | ||
local romans | |||
local unlockLevels = { "Lv.20 解锁", "Lv.40 解锁", "Lv.60 解锁", "Lv.80 解锁", "Lv.100 解锁" } | local romans = { "Ⅰ","Ⅱ","Ⅲ","Ⅳ","Ⅴ","Ⅵ","Ⅶ","Ⅷ" } | ||
for | local unlockLevels = { | ||
local item = timeline:tag("div"):addClass("card_timeline-item") | "Lv.20 解锁", | ||
"Lv.40 解锁", | |||
item:tag("div"):addClass("card_timeline-dot") | "Lv.60 解锁", | ||
item:tag("div"):addClass("card_timeline-unlock") | "Lv.80 解锁", | ||
:wikitext(unlockLevels[idx] or ("Lv." .. (idx * 20) .. " 解锁")) | "Lv.100 解锁" | ||
local titleDiv = item:tag("div"):addClass("card_timeline-title") | } | ||
titleDiv:tag("span"):addClass("card_timeline-numeral"):wikitext(romans[idx] or | |||
titleDiv:tag("span"):addClass("card_timeline-chapter"):wikitext(cardTitle or "") | local idx = 1 | ||
titleDiv:tag("span"):addClass("card_timeline-label"):wikitext("/ Story") | |||
local bodyDiv = item:tag("div"):addClass("card_timeline-body") | for _, chapter in pairs(chapters) do | ||
local item = timeline:tag("div") | |||
:addClass("card_timeline-item") | |||
item:tag("div") | |||
:addClass("card_timeline-dot") | |||
item:tag("div") | |||
:addClass("card_timeline-unlock") | |||
:wikitext(unlockLevels[idx] or ("Lv."..(idx*20).." 解锁")) | |||
local titleDiv = item:tag("div") | |||
:addClass("card_timeline-title") | |||
titleDiv:tag("span") | |||
:addClass("card_timeline-numeral") | |||
:wikitext(romans[idx] or idx) | |||
titleDiv:tag("span") | |||
:addClass("card_timeline-chapter") | |||
:wikitext(cardTitle or "") | |||
titleDiv:tag("span") | |||
:addClass("card_timeline-label") | |||
:wikitext("/ Story") | |||
local bodyDiv = item:tag("div") | |||
:addClass("card_timeline-body") | |||
local text = chapter.text or "" | local text = chapter.text or "" | ||
if text ~= "" then | if text ~= "" then | ||
local lines = mw.text.split(text, "\n") | |||
for i, line in ipairs(lines) do | local lines = mw.text.split(text,"\n") | ||
if line ~= "" then bodyDiv:wikitext(line) end | |||
if i < #lines then bodyDiv:tag("br") end | for i,line in ipairs(lines) do | ||
if line ~= "" then | |||
bodyDiv:wikitext(line) | |||
end | |||
if i < #lines then | |||
bodyDiv:tag("br") | |||
end | |||
end | end | ||
end | end | ||
idx = idx + 1 | |||
end | end | ||
return timeline | return timeline | ||
end | end | ||
function p.render(frame) | function p.render(frame) | ||
local name = mw.text.trim(frame.args[1] or frame.args.name or "") | local name = mw.text.trim(frame.args[1] or frame.args.name or "") | ||
if name == "" then | if name == "" then | ||
return '<span class="error">错误:请提供卡片名称</span>' | return '<span class="error">错误:请提供卡片名称</span>' | ||
end | end | ||
-- 关键:stories.story.* | |||
local fields = table.concat({ | local fields = table.concat({ | ||
"stylename", "rarity", | |||
"character.name", "profession.name", "desire.name", | "stylename", | ||
"skill_normal_attack.name", "skill_normal_attack.type", | "rarity", | ||
"skill_normal_attack.weapon", "skill_normal_attack.description", | |||
"character.name", | |||
"profession.name", | |||
"desire.name", | |||
"skill_normal_attack.name", | |||
"skill_normal_attack.type", | |||
"skill_normal_attack.weapon", | |||
"skill_normal_attack.description", | |||
"skill_normal_attack.levels.*", | "skill_normal_attack.levels.*", | ||
"skill_passive.name", "skill_passive.type", | |||
"skill_passive.trigger_type", "skill_passive.trigger_value", | "skill_passive.name", | ||
"skill_passive.tags", "skill_passive.description", | "skill_passive.type", | ||
"skill_passive.trigger_type", | |||
"skill_passive.trigger_value", | |||
"skill_passive.tags", | |||
"skill_passive.description", | |||
"skill_passive.levels.*", | "skill_passive.levels.*", | ||
"skill_ultimate.name", "skill_ultimate.type", | |||
"skill_ultimate.desire_cost", "skill_ultimate.tags", | "skill_ultimate.name", | ||
"skill_ultimate.description", "skill_ultimate.levels.*", | "skill_ultimate.type", | ||
"skill_ultimate.desire_cost", | |||
"skill_ultimate.tags", | |||
"skill_ultimate.description", | |||
"skill_ultimate.levels.*", | |||
"feats.stages", | "feats.stages", | ||
local encodedName = mw.uri.encode(name, "QUERY") | -- 修复 stories | ||
local apiUrl = "https://data.saltedkiss.org/items/cards" | "stories.*", | ||
.. "?fields=" .. mw.uri.encode(fields, "QUERY") | "stories.story.*" | ||
},",") | |||
local encodedName = mw.uri.encode(name,"QUERY") | |||
local apiUrl = | |||
"https://data.saltedkiss.org/items/cards" | |||
.. "?fields=" .. mw.uri.encode(fields,"QUERY") | |||
.. "&filter[stylename][_eq]=" .. encodedName | .. "&filter[stylename][_eq]=" .. encodedName | ||
local rawResponse = frame:preprocess( | local rawResponse = frame:preprocess( | ||
'{{#get_web_data:url=' .. apiUrl | '{{#get_web_data:url='..apiUrl | ||
.. '|format=text|data=responseText=__text}}' | ..'|format=text|data=responseText=__text}}' | ||
.. '{{#external_value:responseText}}' | ..'{{#external_value:responseText}}' | ||
) | ) | ||
rawResponse = mw.text.trim(rawResponse or "") | rawResponse = mw.text.trim(rawResponse or "") | ||
local parsed = parseJson(rawResponse) | local parsed = parseJson(rawResponse) | ||
local card | |||
local card = | |||
parsed | |||
and type(parsed.data) == "table" | |||
and parsed.data[1] | |||
or nil | |||
if not card then | if not card then | ||
return '<span class="error">⚠ | return '<span class="error">⚠ 无法加载卡片数据</span>' | ||
end | end | ||
local | local stories = card.stories or {} | ||
local root = mw.html.create("div") | local root = mw.html.create("div") | ||
:addClass("ron-card | :addClass("ron-card") | ||
root:tag("div | local rightCol = root:tag("div") | ||
:addClass("card_content_right") | |||
local | local storySection = rightCol:tag("div") | ||
:addClass("card_content_story") | |||
local storyHeader = storySection:tag("div") | |||
:addClass("card_content_story-header") | |||
local | local storyLeft = storyHeader:tag("div") | ||
:addClass("card_content_story-header-left") | |||
storyLeft:node(makeTitle("小传","Story")) | |||
storyLeft:node(makeHr("card_content-item-hr--mb12")) | storyLeft:node(makeHr("card_content-item-hr--mb12")) | ||
storyHeader:node( | |||
makeStoryTimeline(stories,card.stylename) | |||
) | |||
return tostring(root) | return tostring(root) | ||
end | end | ||
return p | return p | ||
2026年3月11日 (三) 21:13的版本
此模块的文档可以在模块:CardData/doc创建
-- Module:CardData
-- 用法:{{#invoke:CardData|render|复仇童谣}}
local p = {}
local function val(v, fallback)
if v == nil or v == "" then return fallback or "—" end
return v
end
local function rarityStars(n)
n = tonumber(n) or 0
return string.rep("★", n)
end
local function parseJson(str)
if not str or str == "" then return nil end
local ok, result = pcall(mw.text.jsonDecode, str)
if ok then return result else return nil end
end
local function makeTitle(titleText, subtitleText, extraClass)
local div = mw.html.create("div")
:addClass("card_content-item-title")
:addClass("card_content-item-title--mt")
if extraClass then div:addClass(extraClass) end
div:wikitext(titleText)
div:tag("span")
:addClass("card_content-item-subtitle")
:wikitext(subtitleText)
return div
end
local function makeHr(extraClass)
local div = mw.html.create("div")
:addClass("card_content-item-hr")
if extraClass then div:addClass(extraClass) end
return div
end
local function makeStoryTimeline(stories, cardTitle)
local timeline = mw.html.create("div")
:addClass("card_timeline card_content_story-timeline")
timeline:tag("div")
:addClass("card_timeline-line")
-- 更安全获取 entry
local entry
if type(stories) == "table" then
for _,v in pairs(stories) do
entry = v
break
end
end
local chapters = entry and entry.story or {}
if not chapters or type(chapters) ~= "table" then
chapters = {}
end
if next(chapters) == nil then
timeline:tag("div")
:addClass("card_timeline-item")
:wikitext("(小传数据待补充)")
return timeline
end
local romans = { "Ⅰ","Ⅱ","Ⅲ","Ⅳ","Ⅴ","Ⅵ","Ⅶ","Ⅷ" }
local unlockLevels = {
"Lv.20 解锁",
"Lv.40 解锁",
"Lv.60 解锁",
"Lv.80 解锁",
"Lv.100 解锁"
}
local idx = 1
for _, chapter in pairs(chapters) do
local item = timeline:tag("div")
:addClass("card_timeline-item")
item:tag("div")
:addClass("card_timeline-dot")
item:tag("div")
:addClass("card_timeline-unlock")
:wikitext(unlockLevels[idx] or ("Lv."..(idx*20).." 解锁"))
local titleDiv = item:tag("div")
:addClass("card_timeline-title")
titleDiv:tag("span")
:addClass("card_timeline-numeral")
:wikitext(romans[idx] or idx)
titleDiv:tag("span")
:addClass("card_timeline-chapter")
:wikitext(cardTitle or "")
titleDiv:tag("span")
:addClass("card_timeline-label")
:wikitext("/ Story")
local bodyDiv = item:tag("div")
:addClass("card_timeline-body")
local text = chapter.text or ""
if text ~= "" then
local lines = mw.text.split(text,"\n")
for i,line in ipairs(lines) do
if line ~= "" then
bodyDiv:wikitext(line)
end
if i < #lines then
bodyDiv:tag("br")
end
end
end
idx = idx + 1
end
return timeline
end
function p.render(frame)
local name = mw.text.trim(frame.args[1] or frame.args.name or "")
if name == "" then
return '<span class="error">错误:请提供卡片名称</span>'
end
-- 关键:stories.story.*
local fields = table.concat({
"stylename",
"rarity",
"character.name",
"profession.name",
"desire.name",
"skill_normal_attack.name",
"skill_normal_attack.type",
"skill_normal_attack.weapon",
"skill_normal_attack.description",
"skill_normal_attack.levels.*",
"skill_passive.name",
"skill_passive.type",
"skill_passive.trigger_type",
"skill_passive.trigger_value",
"skill_passive.tags",
"skill_passive.description",
"skill_passive.levels.*",
"skill_ultimate.name",
"skill_ultimate.type",
"skill_ultimate.desire_cost",
"skill_ultimate.tags",
"skill_ultimate.description",
"skill_ultimate.levels.*",
"feats.stages",
-- 修复 stories
"stories.*",
"stories.story.*"
},",")
local encodedName = mw.uri.encode(name,"QUERY")
local apiUrl =
"https://data.saltedkiss.org/items/cards"
.. "?fields=" .. mw.uri.encode(fields,"QUERY")
.. "&filter[stylename][_eq]=" .. encodedName
local rawResponse = frame:preprocess(
'{{#get_web_data:url='..apiUrl
..'|format=text|data=responseText=__text}}'
..'{{#external_value:responseText}}'
)
rawResponse = mw.text.trim(rawResponse or "")
local parsed = parseJson(rawResponse)
local card =
parsed
and type(parsed.data) == "table"
and parsed.data[1]
or nil
if not card then
return '<span class="error">⚠ 无法加载卡片数据</span>'
end
local stories = card.stories or {}
local root = mw.html.create("div")
:addClass("ron-card")
local rightCol = root:tag("div")
:addClass("card_content_right")
local storySection = rightCol:tag("div")
:addClass("card_content_story")
local storyHeader = storySection:tag("div")
:addClass("card_content_story-header")
local storyLeft = storyHeader:tag("div")
:addClass("card_content_story-header-left")
storyLeft:node(makeTitle("小传","Story"))
storyLeft:node(makeHr("card_content-item-hr--mb12"))
storyHeader:node(
makeStoryTimeline(stories,card.stylename)
)
return tostring(root)
end
return p