模組:VGNL
外观
![]() | 此模块使用Lua语言: |
本模组可生成最新出刊的《电子游戏专题简讯》页面名和标签。
示例
[编辑]{{#invoke:VGNL|link}}
⇒ 2024年第四季{{#invoke:VGNL|target|upcoming}}
⇒ 維基專題:電子遊戲/簡訊/2025-04{{#invoke:VGNL|date|2024-01}}
⇒ 2024年2月11日{{#invoke:VGNL|toc|style=inline}}
⇒ 專題報導:2024年年終回顧、宣告、高品質內容變動{{#invoke:VGNL|toc}}
⇒ (以点列生成上方内容){{#invoke:VGNL|index}}
⇒ (生成简讯的目录表)
目录
[编辑]資料定義於子模組Module:VGNL/items。
序號 | 期數 | 出刊日期 | 專題 | 訪談 | 宣告 | 特優內容 |
---|---|---|---|---|---|---|
1 | 2020-01 | 2020年1月1日 | 電子遊戲專題工作組 | Lopullinen | 連結 | 連結 |
2 | 2020-04 | 2020年4月1日 | 維基ACG專題創作獎 | Vozhuo | 連結 | 連結 |
3 | 2020-07 | 2020年7月1日 | 電子遊戲專題的星章們 | — | 連結 | 連結 |
4 | 2020-10 | 2020年10月3日 | 電子遊戲條目資訊框模板介紹 | SilverReaper | 連結 | 連結 |
5 | 2021-01 | 2021年1月1日 | 電子遊戲專題的典優內容 | — | 連結 | 連結 |
6 | 2021-04 | 2021年4月1日 | 學會用好圖片 | — | 連結 | 連結 |
7 | 2021-07 | 2021年7月3日 | — | — | 連結 | 連結 |
8 | 2021-10 | 2021年10月3日 | ACG特別貢獻 | Cp111 | 連結 | 連結 |
9 | 2022-01 | 2021年1月14日 | 2021年年终回顾 | 連結 | 連結 | |
10 | 2022-04 | 2022年4月5日 | — | — | 連結 | 連結 |
11 | 2022-07 | 2022年7月17日 | 甲級、乙上級——高品質條目評審新方向? | — | 連結 | 連結 |
12 | 2022-10 | 2022年10月21日 | — | — | 連結 | 連結 |
13 | 2023-01 | 2023年1月11日 | 2022年年终回顾 | 連結 | 連結 | |
14 | 2023-04 | 2023年4月21日 | 專題簡訊的未來 | Ericliu1912 | 連結 | 連結 |
15 | 2023-07 | 2023年8月4日 | — | — | 連結 | 連結 |
16 | 2023-10 | 2023年11月4日 | — | — | 連結 | 連結 |
17 | 2024-01 | 2024年2月11日 | 2023年年终回顾 | 連結 | 連結 | |
18 | 2024-04 | 2024年10月4日 | — | — | 連結 | 連結 |
19 | 2024-07 | 2024年10月4日 | — | — | 連結 | 連結 |
20 | 2024-10 | 2024年10月4日 | 聊聊虛構事物的關注度 | — | 連結 | 連結 |
21 | 2025-01 | 2025年1月14日 | 2024年年終回顧 | 連結 | 連結 | |
22 | 2025-04 | (編輯中) | (待定) | (待定) | 連結 | 連結 |
23 | 2025-07 | (編輯中) | (待定) | (待定) | 連結 | 連結 |
require("strict")
local getArgs = require("Module:Arguments").getArgs
-- Assume that the data has been sorted by issue id.
local issue_item_data = mw.loadData("Module:VGNL/items")
local __all__ = {
"date",
"target",
"link",
"index",
"toc",
}
local ROOT_PATH = "維基專題:電子遊戲/簡訊"
-- The following indicators can be loaded from [[Module:VGNL/items]] instead of
-- being hard-coded here.
-- The data for `issue_item_data` should be fetched using `require` instead of
-- `mw.loadData`. ([[mw:Extension:Scribunto/Lua reference_manual#mw.loadData]])
local MERGE_TO_FEATURE = "<MERGED>"
local UPCOMING = "<UPCOMING>"
local CANCELLED = "<CANCELLED>"
--- @alias IssueId [number, number]
--- @alias Date [number, number, number]
--- @alias Released Date | `UPCOMING` | `CANCELLED`
--- @alias ColumnName "feature" | "interview" | "news" | "quality_content"
--- @class IssueItem
--- @field id IssueId
--- @field issue string
--- @field date Released
--- @field feature string | nil
--- @field interview string | `MERGE_TO_FEATURE` | nil
--- @alias IssueItemList IssueItem[]
-- ===== 跪求Lua 5.4,Lua 5.1要什麼功能什麼沒有🤣 ===== --
--- Check if an item exists in a list-like table.
--- @param __item any
--- @param __list any[]
--- @return boolean
local function in_list(__item, __list)
for _, v in ipairs(__list) do
if __item == v then
return true
end
end
return false
end
--- Filter an item in a list-like table based on a condition.
--- @param __function function
--- @param __list any[]
--- @return any
local function filter_one(__function, __list)
for _, v in ipairs(__list) do
if __function(v) then
return v
end
end
end
--- Filter all items in a list-like table met the condition.
--- @param __function function
--- @param __list any[]
--- @return any[]
local function filter_all(__function, __list)
local result = {}
for _, v in ipairs(__list) do
if __function(v) then
table.insert(result, v)
end
end
return result
end
--- Filter item(s) in a list-like table met the condition.
--- @param __function function
--- @param __list any[]
--- @param __mode "all" | "one" | nil @Default to "all".
--- @return any | any[]
local function filter(__function, __list, __mode)
if __mode == "one" then
return filter_one(__function, __list)
end
return filter_all(__function, __list)
end
-- ===== Some tools. ===== --
--- Format an issue ID tuple into a string.
--- For example: `{2024, 07}` becomes "2024-07".
--- @param val IssueId
--- @return string
local function format_issue_id(val)
local vol, iss = val[1], val[2]
return vol .. "-" .. string.format("%02d", iss)
end
--- Parse an issue ID string into an ID tuple.
--- For example: "2024-07" becomes `{2024, 07}`.
--- @param val string
--- @return IssueId
local function parse_issue_id(val)
local _, _, _y, _m = mw.ustring.find(val, "(%d%d%d%d)%-(%d%d)")
local y, m = tonumber(_y), tonumber(_m)
return {y, m}
end
--- Format a date tuple into a Chinese date string.
--- For example: `{2025, 3, 25}` becomes "2025年3月25日".
--- @param val Date
--- @return string
local function format_date(val)
local y, m, d = val[1], val[2], val[3]
return string.format("%s年%s月%s日", y, m, d)
end
--- Convert an issue's release date or status code into a string.
--- @param val Released
--- @return string
local function get_index_date_str(val)
if type(val) == "table" then
return format_date(val)
end
if val == UPCOMING then
return "(編輯中)"
end
if val == CANCELLED then
return "(未出刊)"
end
error('unexpected relased date or status code')
end
--- Retrieve the first issue by its ID or status.
--- @param items IssueItemList
--- @param id
--- | string # e.g. "2024-01"
--- | "released" # the most recently released issue
--- | "upcoming" # the next upcoming issue
--- | nil # defaults to "released"
--- @return IssueItem
local function get_issue_item(items, id)
local cond
-- Match recently released issue.
if (id == nil) or (id == "released") then
cond = function(item)
return type(item.date) == "table"
end
local filtered_items = filter(cond, items)
return filtered_items[#filtered_items]
end
-- Match the next upcoming issue
if id == "upcoming" then
cond = function(item)
return item.date == UPCOMING
end
local filtered_items = filter(cond, items)
return filtered_items[1]
end
-- Match issue id text (e.g. "2020-01")
local parsed_id = parse_issue_id(id)
cond = function(item)
return (item.id[1] == parsed_id[1]) and (item.id[2] == parsed_id[2])
end
return filter(cond, items, "one")
end
--- Get the link target (i.e. page title) of an issue's data by column.
--- @param item IssueItem
--- @param column ColumnName?
--- @return string
local function get_link_target(item, column)
local id_path = format_issue_id(item.id)
local issue_base_path = ROOT_PATH .. "/" .. id_path
if column == nil then
return issue_base_path
end
local code_to_path_mapping = {
["feature"] = "專題",
["interview"] = "訪談",
["news"] = "宣告",
["quality_content"] = "特優內容",
}
return issue_base_path .. "/" .. code_to_path_mapping[column]
end
--- Get the column title for use in the index page.
--- @param item IssueItem
--- @param column ColumnName?
--- @return string?
local function get_index_text(item, column)
if column == nil then
return format_issue_id(item.id)
end
if in_list(column, {"news", "quality_content"}) then
return "連結"
end
if in_list(column, {"feature", "interview"}) then
return item[column]
end
end
--- Get the column title for use in a content environment.
--- @param item IssueItem
--- @param column ColumnName?
--- @return string?
local function get_toc_text(item, column)
if column == nil then
return item.issue
end
if column == "feature" then
local title = item[column]
if title == nil then
return
end
return "專題報導:" .. title
end
if (column == "interview") then
local title = item[column]
if (title == nil) or (title == MERGE_TO_FEATURE) then
return
end
return "訪談:" .. title
end
if column == "news" then
return "宣告"
end
if column == "quality_content" then
return "高品質內容變動"
end
end
--- I bet five cents that you wouldn't understand my docstrings if I
--- wrote it.
--- @param target string?
--- @param display string?
--- @return string?
local function build_linked_text(target, display)
if target == nil then
return display
end
if display == nil then
return "[[" .. target .. "]]"
end
return "[[" .. target .. "|" .. display .. "]]"
end
-- ===== Index table builders ===== --
--- Build the header row for the index table.
--- @return table<string, any>
local function _build_index_table_header_row()
local row, cell = mw.html.create("tr"), nil
-- Append the no. header cell.
cell = mw.html.create("th")
cell
:attr("scope", "col")
:attr("data-sort-type", "number")
:wikitext("序號")
row:node(cell)
--Append the other header cells.
local headers = {"期數", "出刊日期", "專題", "訪談", "宣告", "特優內容"}
for _, header in ipairs(headers) do
cell = mw.html.create("th")
cell
:attr("scope", "col")
:addClass("unsortable")
:wikitext(header)
row:node(cell)
end
return row
end
--- Build the table cell for an issue row in the index table.
--- @param item IssueItem
--- @param column ColumnName?
--- @return table<string, any>
local function _build_index_table_issue_cell(item, column)
local text
local display = get_index_text(item, column)
if display == nil then
text = "—"
else
local target = get_link_target(item, column)
text = build_linked_text(target, display)
end
return mw.html.create("td"):wikitext(text)
end
--- Build the content row for an issue in the index table.
--- @param index number
--- @param item IssueItem
--- @return table<string, any>
local function _build_index_table_issue_row(index, item)
local build_cell = _build_index_table_issue_cell
local row, cell = mw.html.create("tr"), nil
-- Append the row header cell.
cell = mw.html.create("th")
cell:attr("scope", "row"):wikitext(index)
row:node(cell)
-- Append the issue cell.
cell = build_cell(item)
row:node(cell)
-- Append the published date cell.
cell = mw.html.create("td")
cell:wikitext(get_index_date_str(item.date))
row:node(cell)
-- Append feature and interview cell.
if get_index_text(item, "interview") == MERGE_TO_FEATURE then
-- Append the spanning feature cell.
cell = build_cell(item, "feature"):attr("colspan", 2)
row:node(cell)
else
-- Append the feature cell.
cell = build_cell(item, "feature")
row:node(cell)
-- Append the interview cell.
cell = build_cell(item, "interview")
row:node(cell)
end
-- Append the news cell.
cell = build_cell(item, "news")
row:node(cell)
-- Append the quaility content cell.
cell = build_cell(item, "quality_content")
row:node(cell)
-- Return the row
return row
end
--- Build and return the index table in wikitext format.
--- @param items IssueItemList
--- @return table<string, any>
local function build_table(items)
local table_title = "《電子遊戲專題簡訊》目錄"
local result, child = mw.html.create("table"), nil
result
:addClass("wikitable")
:addClass("sortable")
:css("text-align", "center")
-- Append caption.
child = mw.html.create("caption")
child:wikitext(table_title)
result:node(child)
-- Append the header row.
child = _build_index_table_header_row()
result:node(child)
-- Append the issue rows.
for id, item in ipairs(items) do
child = _build_index_table_issue_row(id, item)
result:node(child)
end
-- We done.
return result
end
-- ===== Function to be called. ===== --
local p = {}
--- Create a function that invokes a module function with the given
--- arguments.
--- @param func_name string
--- @return function
local function create_invoke_wrapper(func_name)
return function(frame)
local args = getArgs(frame)
return p[func_name](args)
end
end
--- Retrieve the link target from the most recent issue with the given
--- status.
--- @param args table
--- @return string?
function p._target(args)
local id, column = args[1], args.column
local item = get_issue_item(issue_item_data, id)
return get_link_target(item, column)
end
--- Retrieve the linked text from the most recent issue with the given
--- status.
--- @param args table
--- @return string?
function p._link(args)
local id, column = args[1], args.column
local item = get_issue_item(issue_item_data, id)
local target = get_link_target(item, column)
local text = get_toc_text(item, column)
return build_linked_text(target, text)
end
--- Retrieve the released date (or status) from the most recent issue.
--- @param args table
--- @return string?
function p._date(args)
local id = args[1]
local item = get_issue_item(issue_item_data, id)
return get_index_date_str(item.date)
end
--- Retrieve the content from the most recent issue with the given
--- status.
--- @param args table
--- @return string?
function p._toc(args)
local id, style = args[1], args.style
local item = get_issue_item(issue_item_data, id)
local linked_texts = {}
local columns = {"feature", "interview", "news", "quality_content"}
for _, column in ipairs(columns) do
local text = get_toc_text(item, column)
if (text ~= nil) and (text ~= MERGE_TO_FEATURE) then
local target = get_link_target(item, column)
local link = build_linked_text(target, text)
table.insert(linked_texts, link)
end
end
-- Apply style.
if style == "inline" then
return table.concat(linked_texts, "、")
end
for k, v in ipairs(linked_texts) do
linked_texts[k] = "* " .. v
end
return table.concat(linked_texts, "\n")
end
--- Build and return the index table in wikitext format.
--- @param args table
--- @return string
function p._index(args) -- noqa
return tostring(build_table(issue_item_data))
end
-- ===== Return results ===== --
for _, v in ipairs(__all__) do
p[v] = create_invoke_wrapper("_" .. v)
end
return p