Module:Sandbox/DVRTed
local plain_text = require("Module:Plain text")._main
local section_link = require('Module:Section link')._main
-- helper functs
local function trim(s) return s:match("^%s*(.-)%s*$") end
local function case_insensitive_pattern(str)
local pattern = {}
for c in str:gmatch(".") do
if c:match("%a") then
table.insert(pattern, string.format("[%s%s]", c:upper(), c:lower()))
else
table.insert(pattern, c)
end
end
return table.concat(pattern)
end
-- actual functions
local function get_thread_details(page_content)
local signatures = 0
local thread_author_username = ""
local thread_timestamp = ""
for line in page_content:gmatch("[^\r\n]+") do
-- match and count timestamp
-- at the end of the line
local timestamp_pattern = "%d%d:%d%d, %d+ [^ ]+ %d%d%d%d %(UTC%)"
local timestamp = line:match(timestamp_pattern)
if timestamp then
signatures = signatures + 1
-- currently, we don't do anything with threads that may
-- have replies
if signatures >= 2 then return nil end
-- set the last found timestamp in the thread
thread_timestamp = timestamp
-- try and get the username from the same line as timestamp.
-- it updates to the last found username.
local ci_user = case_insensitive_pattern("user")
local username_pattern = "%[%[" .. ci_user ..
"[^:]*:([^%]%|]+).-%]%]"
for match in line:gmatch(username_pattern) do
thread_author_username = match
end
end
end
return {
author_username = trim(thread_author_username),
timestamp = thread_timestamp
}
end
local function get_unanswered_threads(page_content)
local threads = {}
local current_title = nil
local current_body = ""
local threads_with_data = {}
for line in page_content:gmatch("[^\r\n]+") do
local thread_title = line:match("^==%s*(.-)%s*==$")
if thread_title then
current_body = trim(current_body)
if current_title and current_body then
table.insert(threads,
{title = current_title, body = current_body})
end
current_title = thread_title
current_body = ""
else
if current_title then
current_body = current_body .. trim(line) .. "\n"
end
end
end
current_body = trim(current_body)
if current_title and current_body then
table.insert(threads, {title = current_title, body = current_body})
end
for _, thread in ipairs(threads) do
local details = get_thread_details(thread.body)
if details and details.author_username ~= "" then
table.insert(threads_with_data, {
title = thread.title,
body = thread.body,
author_username = details.author_username,
timestamp = details.timestamp
})
end
end
return threads_with_data
end
local function wrap_in_custom_div(frame, thread, page_name)
local title = thread.title
local body = thread.body
local author_username = thread.author_username
local timestamp = thread.timestamp
local timeago = frame:preprocess("{{time ago|" .. timestamp .. "}}")
body = plain_text(body)
if mw.ustring.len(body) > 300 then
body = mw.ustring.sub(body, 1, 300) .. "…"
end
local author_link = string.format("[[User:%s]]", author_username)
local thread_link = section_link(page_name, plain_text(title),
{nopage = true})
local div_html = string.format(
'<div style="background: #fff; border-radius: 6px; padding: 12px 16px; border: 1px solid #e9ecef; box-shadow: 0 2px 4px rgba(0,0,0,0.05);">' ..
'<div style="color: #6c757d; font-size: 12px; margin-bottom: 4px;">%s • %s</div>' ..
'<div style="font-size: 16px; font-weight: bold; margin-bottom: 6px;">%s</div>' ..
'<p style="margin: 0; color: #212529; font-size: 14px;">%s</p>' ..
'</div>', author_link, timeago, thread_link, body)
return div_html
end
local function unanswered(frame)
local page_name = frame.args[1] or nil
local max_threads = tonumber(frame.args[2]) or 10
if not page_name then return "No page name provided." end
local page = mw.title.new(page_name)
local page_content = page and page.getContent and page:getContent()
if not page_content then return "Could not retrieve page content" end
local unanswered_threads = get_unanswered_threads(page_content)
local result = string.format(
'<div style="background: #f8f9fa; border-radius: 8px; padding: 20px; margin: 16px 0; border: 1px solid #dee2e6;">' ..
'<div style="margin-bottom: 16px;">' ..
'<div style="font-size: 18px; font-weight: bold; color: #212529; margin-bottom: 4px;">[[%s]]</div>' ..
'<div style="font-size: 14px; color: #6c757d; font-weight: 500;">%d unanswered threads</div>' ..
'</div>', page_name, #unanswered_threads)
if #unanswered_threads == 0 then
result = result .. '</div>'
return result
end
result = result ..
'<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 20px;">'
-- if there's fewer threads than max_threads
-- set it to threads count, otherwise set it to max_threads
local display_count = math.min(#unanswered_threads, max_threads)
for i = 1, display_count do
local thread = unanswered_threads[i]
local wrapped = wrap_in_custom_div(frame, thread, page_name)
result = result .. wrapped
end
result = result .. '</div></div>'
return result
end
return {unanswered = unanswered}
Content Disclaimer
Informasi ini disarikan dari Wikipedia dan disajikan kembali untuk tujuan edukasi. Konten tersedia di bawah lisensi CC BY-SA 3.0. Kami tidak bertanggung jawab atas ketidakakuratan data yang bersumber dari kontribusi publik tersebut.
- The information displayed on this website is sourced in part or in whole from Wikipedia and has been adapted for the purpose of restating it. We strive to provide accurate and relevant information, however:
- There is no guarantee of absolute accuracy. Wikipedia is an open, collaborative project that can be edited by anyone, so information is subject to change.
- It is not intended to constitute professional advice. The content displayed is for informational and educational purposes only. For important decisions (e.g., medical, legal, or financial), please consult a professional.
- Content copyright. Wikipedia is licensed under the Creative Commons Attribution-ShareAlike License (CC BY-SA). This means that content may be reused with appropriate attribution and shared under a similar license.
- Responsible use. Any risk arising from the use of information from this website is entirely the responsibility of the user.