模組:Funny update monitor
外观
function p.main(frame)
-- 1. 獲取來自外部調用模板的所有參數
local args = frame:getParent().args
-- 命名空間與頁面型態解析函數
local function get_type_text(ns, title_str)
local clean_title = mw.text.trim(title_str or "")
-- 1. 優先判定特定字首的偽命名空間 (MOS:, LTA:)
if string.match(clean_title, "^[Mm][Oo][Ss]:") then
return '-{zh-hans:格式手册;zh-hant:格式手冊;}-'
elseif string.match(clean_title, "^[Ll][Tt][Aa]:") then
return '-{zh-hans:LTA页面;zh-hant:LTA頁面;}-'
-- 2. 判定其他常見的偽命名空間字首 (WP:, CAT:, T:, H:, P:, D:, M:, I:, N:, R:)
elseif string.match(clean_title, "^[Ww][Pp]:") or
string.match(clean_title, "^[Cc][Aa][Tt]:") or
string.match(clean_title, "^[Tt]:") or
string.match(clean_title, "^[Hh]:") or
string.match(clean_title, "^[Pp]:") or
string.match(clean_title, "^[Dd]:") or
string.match(clean_title, "^[Mm]:") or
string.match(clean_title, "^[Ii]:") or
string.match(clean_title, "^[Nn]:") or
string.match(clean_title, "^[Rr]:") then
return '-{zh-hans:伪命名页面;zh-hant:偽命名頁面;}-'
-- 3. 判定討論命名空間(所有奇數ID皆為討論頁)
elseif ns % 2 == 1 then
return '-{zh-hans:讨论页;zh-hant:討論頁;}-'
-- 4. 標準命名空間判定
elseif ns == 0 then
return '條目'
elseif ns == 2 then
return '-{zh-hans:用户页;zh-hk:用戶頁;zh-tw:使用者頁面}-'
elseif ns == 4 then
return '-{zh-hans:页面;zh-hant:頁面;}-'
elseif ns == 6 then
return '-{zh-hans:文件;zh-hant:檔案;}-'
elseif ns == 8 then
return '頁面'
elseif ns == 10 then
return '模板'
elseif ns == 12 then
return '-{zh-hans:帮助页面;zh-hant:說明頁面;}-'
elseif ns == 14 then
return '分類'
elseif ns == 100 then
return '主題'
elseif ns == 102 then
return '-{zh-hans:维基专题;zh-hant:維基專題;}-'
elseif ns == 118 then
return '草稿'
elseif ns == 828 then
return '-{zh-hans:模块;zh-hant:模組;}-'
end
return '頁面'
end
local currentTitle = mw.title.getCurrentTitle()
-- 載入yesno模組以處理small參數
local yesno = require('Module:Yesno')
local is_small = yesno(args.small) or false
-- 2. 決定目標頁面名稱並判斷是否為跨頁面目標
local target_name = args.target or args[1]
local is_remote = true
if not target_name or mw.text.trim(target_name) == '' then
target_name = currentTitle.fullText
is_remote = false
else
target_name = mw.text.trim(target_name)
end
local timestamp_str
-- 支援demo參數:模擬指定頁面最後編輯於一段時間之前
if args.demo and mw.text.trim(args.demo) ~= '' then
timestamp_str = frame:callParserFunction('#time', { 'YmdHis', 'now - ' .. mw.text.trim(args.demo) })
else
timestamp_str = frame:expandTemplate{ title = 'REVISIONTIMESTAMP', args = { target_name } }
-- 若抓取失敗則退回當前頁面時間
if not timestamp_str or mw.text.trim(timestamp_str) == '' or string.match(timestamp_str, "錯誤") then
timestamp_str = frame:expandTemplate{ title = 'REVISIONTIMESTAMP', args = { currentTitle.fullText } }
end
end
-- 使用#time轉換為Unix時間戳記以利後續的過期邏輯數學計算
local current_ts = tonumber(frame:callParserFunction('#time', { 'U' }))
-- 3. 核心時間解析函數:將 "30 min"、"1 hour" 等轉換為過期時間戳記(未填寫則永久藍色)
local function get_expiry(val)
if not val or mw.text.trim(val) == '' then
return 9999999999
end
local clean_val = string.lower(mw.text.trim(val))
if clean_val == 'disable' or clean_val == 'none' then
return 9999999999
end
local success, result = pcall(function()
return tonumber(frame:callParserFunction('#time', { 'U', timestamp_str .. ' + ' .. val }))
end)
return success and result or 9999999999
end
local red_expiry = get_expiry(args.red)
local yellow_expiry = get_expiry(args.yellow)
local green_expiry = get_expiry(args.green)
-- 4. 狀態機判定(由大到小檢查)
local state = 'blue'
if current_ts >= red_expiry then
state = 'red'
elseif current_ts >= yellow_expiry then
state = 'yellow'
elseif current_ts >= green_expiry then
state = 'green'
end
-- 5. 定義各狀態的CSS樣式與對應圖標(若為 small 模式則縮小圖示為 25px)
local styles = {
blue = 'background-color:var(--background-color-progressive-subtle, #F5FAFF); border: 2px solid var(--border-color-progressive, #36C); color: inherit;',
green = 'background-color:var(--background-color-success-subtle,#DFFFDF); border: 2px solid var(--border-color-success,#008000); color: inherit;',
yellow = 'background-color:var(--background-color-warning-subtle,#FDF1D1); border: 2px solid var(--border-color-warning,orange); color: inherit;',
red = 'background-color:var(--background-color-error-subtle,#FDD); border: 2px solid var(--border-color-error,#DE0000); color: inherit;'
}
local icon_size = is_small and '25px' or '40px'
local images = {
blue = '[[File:Face-wink.svg|' .. icon_size .. '|alt=資訊]]',
green = '[[File:Gnome-face-laugh.svg|' .. icon_size .. '|alt=已確認]]',
yellow = '[[File:Gnome-face-surprise.svg|' .. icon_size .. '|alt=注意]]',
red = '[[File:Skull_and_crossbones.svg|' .. icon_size .. '|alt=警告]]'
}
-- 6. 名詞主體與連結生成(tl支援)
local subject_text
if is_remote then
if string.match(target_name, ":") or mw.title.new(target_name) then
local targetTitle = mw.title.new(target_name) or currentTitle
local ns = targetTitle.namespace
local type_text = get_type_text(ns, target_name)
local display_link
local use_tl = yesno(args.tl)
if use_tl then
if targetTitle.namespace == 10 then -- Template 命名空間
display_link = '{{[[Template:' .. targetTitle.text .. '|' .. targetTitle.text .. ']]}}'
else
display_link = '{{[[' .. targetTitle.prefixedText .. '|' .. targetTitle.text .. ']]}}'
end
else
display_link = '[[' .. target_name .. ']]'
end
if args.this == 'yes' then
subject_text = '此' .. display_link .. type_text
else
subject_text = display_link .. type_text
end
else
local prefix = (args.this == 'yes') and '此' or '本'
subject_text = prefix .. target_name
end
else
local ns = currentTitle.namespace
local type_text = get_type_text(ns, currentTitle.fullText)
local prefix = (args.this == 'yes') and '此' or '本'
subject_text = prefix .. type_text
end
-- 7. 小字說明(支援週、月、年替換)
local function get_note_text(val)
if not val or mw.text.trim(val) == '' then return nil end
local clean = string.lower(mw.text.trim(val))
if clean == 'disable' or clean == 'none' then return nil end
local out = val
out = string.gsub(out, "[Mm][Ii][Nn][Uu][Tt][Ee][Ss]?", "分鐘")
out = string.gsub(out, "[Mm][Ii][Nn]", "分鐘")
out = string.gsub(out, "[Hh][Oo][Uu][Rr][Ss]?", "小時")
out = string.gsub(out, "[Dd][Aa][Yy][Ss]?", "天")
out = string.gsub(out, "[Ww][Ee][Ee][Kk][Ss]?", "週")
out = string.gsub(out, "[Mm][Oo][Nn][Tt][Hh][Ss]?", "個月")
out = string.gsub(out, "[Yy][Ee][Aa][Rr][Ss]?", "年")
out = string.gsub(out, "[Ss][Ee][Cc][Oo][Nn][Dd][Ss]?", "秒")
out = string.gsub(out, "[Ss][Ee][Cc]", "秒")
return out
end
local yellow_note = get_note_text(args.yellow)
local red_note = get_note_text(args.red)
local green_note = get_note_text(args.green)
local small_note = ""
if not green_note and not yellow_note and not red_note then
small_note = "除非設定時間,否則本框恆為藍色。"
else
if green_note then
small_note = small_note .. "更新後本框顯示為藍色;超過" .. green_note .. "本框會變成綠色"
else
small_note = small_note .. "更新後本框顯示為藍色"
end
if yellow_note then
small_note = small_note .. ";超過" .. yellow_note .. "本框會變成黃色"
end
if red_note then
small_note = small_note .. ";超過" .. red_note .. "本框則會變成紅色"
end
small_note = small_note .. "。"
-- 自動修正句尾的分號為句號
if string.sub(small_note, -3) == ";" then
small_note = string.sub(small_note, 1, -4) .. "。"
end
end
-- 8. 組裝文字與動態模板解析(可tittle與text覆蓋)
local main_text = subject_text .. "最後於'''{{Time ago|" .. timestamp_str .. "}}'''破壞"
if args.tittle and mw.text.trim(args.tittle) ~= '' then
main_text = main_text .. "," .. mw.text.trim(args.tittle)
end
main_text = main_text .. "。({{purge|撿拾餅乾屑}})"
local final_note = small_note
if args.text and mw.text.trim(args.text) ~= '' then
final_note = mw.text.trim(args.text)
end
local text_content
if is_small then
-- small模式:上次編輯間距
text_content = main_text
else
-- 一般模式:上次編輯間距+變色說明
text_content = main_text .. "<br>" .. "<small>" .. final_note .. "</small>"
end
local parsed_text = frame:preprocess(text_content)
-- 0分鐘前或-1分鐘前為剛剛更新---small+一般
parsed_text = mw.ustring.gsub(parsed_text, "最後於'''0秒前'''破壞。", "'''剛剛更新'''。")
parsed_text = mw.ustring.gsub(parsed_text, "最後於'''1秒前'''破壞。", "'''剛剛更新'''。")
parsed_text = mw.ustring.gsub(parsed_text, "最後於'''2秒前'''破壞。", "'''剛剛更新'''。")
parsed_text = mw.ustring.gsub(parsed_text, "最後於'''3秒前'''破壞。", "'''剛剛更新'''。")
parsed_text = mw.ustring.gsub(parsed_text, "最後於'''4秒前'''破壞。", "'''剛剛更新'''。")
parsed_text = mw.ustring.gsub(parsed_text, "最後於'''5秒前'''破壞。", "'''剛剛更新'''。")
parsed_text = mw.ustring.gsub(parsed_text, "最後於'''6秒前'''破壞。", "'''剛剛更新'''。")
parsed_text = mw.ustring.gsub(parsed_text, "最後於'''7秒前'''破壞。", "'''剛剛更新'''。")
parsed_text = mw.ustring.gsub(parsed_text, "最後於'''8秒前'''破壞。", "'''剛剛更新'''。")
parsed_text = mw.ustring.gsub(parsed_text, "最後於'''9秒前'''破壞。", "'''剛剛更新'''。")
parsed_text = mw.ustring.gsub(parsed_text, "最後於'''10秒前'''破壞。", "'''剛剛更新'''。")
parsed_text = mw.ustring.gsub(parsed_text, "最後於'''0分鐘前'''破壞。", "'''剛剛更新'''。")
parsed_text = mw.ustring.gsub(parsed_text, "最後於'''0分钟前'''破壞。", "'''剛剛更新'''。")
parsed_text = mw.ustring.gsub(parsed_text, "最後於'''%-1分鐘前'''破壞。", "'''剛剛更新'''。")
parsed_text = mw.ustring.gsub(parsed_text, "最後於'''%-1分钟前'''破壞。", "'''剛剛更新'''。")
-- 9. 輸出
local output = frame:expandTemplate{ title = 'ombox', args = {
style = styles[state],
image = images[state],
text = parsed_text,
small = is_small and 'yes' or nil
}}
local ns = currentTitle.namespace
-- 主要、專案、模板、分類、主題空間才分類
local is_valid_ns = (ns == 0 or ns == 4 or ns == 10 or ns == 14 or ns == 100)
if is_valid_ns then
-- badcat, badcategory:yellow或red分類
local badcat_name = args.badcat or args.badcategory
if badcat_name and mw.text.trim(badcat_name) ~= '' then
if state == 'yellow' or state == 'red' then
output = output .. '[[Category:' .. mw.text.trim(badcat_name) .. ']]'
end
end
-- cat, category:全部分類
local cat_name = args.cat or args.category
if cat_name and mw.text.trim(cat_name) ~= '' then
output = output .. '[[Category:' .. mw.text.trim(cat_name) .. ']]'
end
end
return output
end
return p