跳转到内容

模組:沙盒/Lopullinen

维基百科,自由的百科全书

这是本页的一个历史版本,由For Each element In group ... Next留言 | 贡献2025年4月3日 (四) 14:12编辑。这可能和当前版本存在着巨大的差异。

require("strict")

local getArgs = require("Module:Arguments").getArgs

local issue_item_data = mw.loadData("Module:Current VGNL/items")

--- @alias DATE_TYPE [number, number, number]
--- @alias ISSUE_ITEM table<string, (string | DATE_TYPE)?>
--- @alias ISSUE_ITEMS ISSUE_ITEM[]
--- @alias COLUMN_CODE_TYPE
--- | "issue"  # 期數
--- | "feature"  # 專題報導
--- | "interview"  # 訪談
--- | "news"  # 宣告
--- | "quaility_content"  # 特優內容
--- @alias COLUMN_TYPE COLUMN_CODE_TYPE | nil

local __all__ = {"target", "link", "content", "index"}

local BASE_TITLE = "維基專題:電子遊戲/簡訊"
-- TODO: Two names for the index and the content
local COLUMN_CODE_MAPPING = {
    ["issue"] = "期號",
    ["feature"] = "專題",
    ["interview"] = "訪談",
    ["news"] = "宣告",
    ["quaility_content"] = "特優內容",
}
local DATE_STATUS_MAPPING = {
    ["pending"] = "(待定稿)",
    ["ondraft"] = "(編寫中)",
    ["planning"] = "(待採編)",
    ["cancelled"] = "(未付梓)",
}


-- ===== 何時升級Lua 5.4啊,Lua 5.1要什麼功能什麼沒有🤣 ===== --

--- Check whether there is an item 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 items that meet a condition in a table.
--- @param __function function
--- @param __table table<any, any>
--- @return table<any, any>
local function filter(__function, __table)
    local result = {}
    for k, v in pairs(__table) do
        if __function(v) then
            result[k] = v
        end
    end
    return result
end

-- ===== Some tools. ===== --

-- TODO: filter by id (e.g. '2020-01')
--- Get the first issue by a specified field.
--- @param items ISSUE_ITEMS
--- @param key string
--- @param first "new" | "old"
--- @return ISSUE_ITEM?
local function get_one_issue(items, key, first)
    if #items == 0 then
        return
    end
    local sorter = function(a, b)
        if first == "new" then
            return a[key] >= b[key]
        end
        return a[key] <= b[key]
    end
    table.sort(items, sorter)
    return items[1]
end

--- Get the recent issue data.
--- @param items ISSUE_ITEMS
--- @param status "published" | "pending" | "ondraft" | "planning" | any
--- @return ISSUE_ITEM?
local function get_recent_issue(items, status)
    -- For upcoming issues, get the one with the minimum id.
    if in_list(status, {"pending", "ondraft", "planning"}) then
        local filter_func = function(x)
            return x.date == status
        end
        local issues = filter(filter_func, items)
        return get_one_issue(issues, "id", "old")
    end
    -- Other status but not nil (e.g. "cancelled") leads a nil result.
    if (status ~= nil) and (status ~= "published") then
        return
    end
    -- Now handle the published issues.
    local filter_func = function(x)
        return type(x.date) == "table"
    end
    local issues = filter(filter_func, items)
    return get_one_issue(issues, "id", "new")
end

--- Turn date table to Chinese date, or status code to text.
--- @param date string | DATE_TYPE
--- @return string
local function humanize_date(date)
    if type(date) == "table" then
        return string.format("%s年%s月%s日", date[1], date[2], date[3])
    end
    return DATE_STATUS_MAPPING[date] or ""
end

--- Get the link target (i.e. page title) of a issue data by column.
--- @param item ISSUE_ITEM
--- @param column COLUMN_TYPE
--- @return string
local function get_link_target(item, column)
    local issue_base_title = BASE_TITLE .. "/" .. item.id
    if (column == nil) or (column == "issue") then
        return issue_base_title
    end
    return issue_base_title .. "/" .. COLUMN_CODE_MAPPING[column]
end

--- Get the text.
--- @param item ISSUE_ITEM
--- @param column COLUMN_TYPE
--- @param raw boolean?
--- @return string  -- noqa
local function get_text(item, column, raw)
    local text
    if column == nil then
        text = item.id
    elseif in_list(column, {"issue", "feature"}) then
        text = item[column]
    elseif column == "interview" then
        if (raw == false) and (item.interview == "LEFT") then
            text = item.feature
        else
            text = item.interview
        end
    else
        text = COLUMN_CODE_MAPPING[column]
    end
    return text
end

--- Build a wikilink text.
--- @param item ISSUE_ITEM
--- @param column COLUMN_TYPE
--- @param raw boolean?
--- @return string?
local function get_wikilink(item, column, raw)
    local target = get_link_target(item, column)
    local text = get_text(item, column, raw)
    if target and text then
        return string.format("[[%s|%s]]", target, text)
    end
end

-- ===== Index table builders ===== --

--- Build the header row.
--- @return table<string, any>
local function build_table_header_row()
    local tr, cell = mw.html.create("tr"), nil
    -- Append the id cell.
    cell = mw.html.create("th")
    cell
        :attr("scope", "col")
        :attr("data-sort-type", "number")
        :wikitext("序號")
    tr:node(cell)
    -- Append the id issue.
    cell = mw.html.create("th")
    cell
        :attr("scope", "col")
        :attr("data-sort-type", "text")
        :wikitext("期數")
    tr:node(cell)
    -- Appden the published date cell.
    cell = mw.html.create("th")
    cell
        :attr("scope", "col")
        :addClass("unsortable")
        :wikitext("出刊日期")
    tr:node(cell)
    --Append the content cells.
    local columns = {"feature", "interview", "news", "quaility_content"}
    for _, v in ipairs(columns) do
        cell = mw.html.create("th")
        cell
            :attr("scope", "col")
            :addClass("unsortable")
            :wikitext(COLUMN_CODE_MAPPING[v])
        tr:node(cell)
    end
    return tr
end

--- Build the content row.
--- @param index number
--- @param item ISSUE_ITEM
--- @return table<string, any>
local function build_table_issue_row(index, item)
    local tr, cell = mw.html.create("tr"), nil
    -- Append the row header cell.
    cell = mw.html.create("th")
    cell
        :attr("scope", "row")
        :wikitext(index)
    tr:node(cell)
    -- Append the issue cell.
    cell = mw.html.create("td")
    cell
        :attr("data-sort-value", item.id)
        :wikitext(get_wikilink(item, "issue"))
    tr:node(cell)
    -- Append the published date cell.
    cell = mw.html.create("td")
    cell:wikitext(humanize_date(item.date))
    tr:node(cell)
    -- Append content cells.

    --{"feature", "interview", "news", "quaility_content"}

    -- Append feature and interview cell.
    local feature_text = get_wikilink(item, "feature")
    local interview_text = get_wikilink(item, "interview")
    if interview_text and (interview_text:find("LEFT")) then
        cell = mw.html.create("td")
        cell:attr("colspan", 2):wikitext(feature_text)
        tr:node(cell)
    else
        cell = mw.html.create("td")
        cell:wikitext(feature_text or "—")
        tr:node(cell)
        cell = mw.html.create("td")
        cell:wikitext(interview_text or "—")
        tr:node(cell)
    end
    -- Append news cell.
    cell = mw.html.create("td")
    cell:wikitext(get_wikilink(item, "news"))
    tr:node(cell)
    -- Append quaility_content cell.
    cell = mw.html.create("td")
    cell:wikitext(get_wikilink(item, "quaility_content"))
    tr:node(cell)
    -- Return the row
    return tr
end

--- Build the index table.
--- @param items ISSUE_ITEMS
--- @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_table_header_row()
    result:node(child)
    -- Append the issue rows.
    for id, item in ipairs(items) do
        child = build_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 given args.
--- @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 link target from the most recent one with the given status.
--- @param args table
--- @return string?
function p._target(args)
    local column, released_status = args[1], args.status
    local item = get_recent_issue(issue_item_data, released_status)
    if item then
        return get_link_target(item, column)
    end
end

--- Retrieve link from the most recent one with the given status.
--- @param args table
--- @return string?
function p._link(args)
    local column, released_status = args[1], args.status
    local item = get_recent_issue(issue_item_data, released_status)
    if item then
        return get_wikilink(item, column)
    end
end

--- Retrieve content from the most recent one with the given status.
--- @param args table
--- @return string?
function p._content(args)
    local released_status, style = args.status, args.style
    local item = get_recent_issue(issue_item_data, released_status)
    if not item then
        return
    end
    local result = {}
    local columns = {"feature", "interview", "news", "quaility_content"}
    for _, column in ipairs(columns) do
        local link = get_wikilink(item, column, true)
        if link and (not link:find("LEFT")) then
            table.insert(result, link)
        end
    end
    -- Apply style.
    if style == "inline" then
        return table.concat(result, "、")
    end
    for k, v in ipairs(result) do
        result[k] = "* " .. v
    end
    return table.concat(result, "\n")
end

--- Build and return the index wikitext table.
--- @param args table
--- @return string
function p._index(args)
    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