Editing Module:User:Kai/sandboxGive feedback
The edit can be undone.
Please check the comparison below to verify that this is what you want to do, and then publish the changes below to finish undoing the edit.
| Latest revision | Your text | ||
| Line 1: | Line 1: | ||
local p = {} | |||
local function isTruthy(v) | |||
if v == nil then | |||
return false | |||
end | |||
v = mw.text.trim(tostring(v)):lower() | |||
return v ~= '' and v ~= '0' and v ~= 'false' and v ~= 'no' and v ~= 'off' | |||
end | |||
local function formatUser(user) | |||
user = mw.text.trim(tostring(user or '')) | |||
if user == '' or user:lower() == 'anonymous' then | |||
return 'Anonymous' | |||
end | |||
return string.format('[[User:%s|%s]]', user, user) | |||
end | |||
-- Renders the individual feedback visual card | |||
local function renderCard(user, feedback, resolved, pageName) | |||
local root = mw.html.create('div') | |||
:addClass('feedback-box') | |||
:addClass(resolved and 'feedback-box--resolved' or 'feedback-box--unresolved') | |||
local meta = root:tag('div') | |||
:addClass('feedback-meta') | |||
if pageName and pageName ~= '' then | |||
meta:tag('span') | |||
:addClass('feedback-page') | |||
:wikitext(string.format("'''[[%s]]'''", pageName)) | |||
meta:tag('span') | |||
:addClass('feedback-separator') | |||
:wikitext(' • ') | |||
end | |||
meta:tag('span') | |||
:addClass('feedback-user') | |||
:wikitext(formatUser(user)) | |||
meta:tag('span') | |||
:addClass('feedback-separator') | |||
:wikitext(' • ') | |||
meta:tag('span') | |||
:addClass('feedback-status') | |||
:addClass(resolved and 'feedback-status--resolved' or 'feedback-status--unresolved') | |||
:wikitext(resolved and 'Resolved' or 'Unresolved') | |||
root:tag('div') | |||
:addClass('feedback-body') | |||
:wikitext(feedback) | |||
if not resolved and (not pageName or pageName == '') then | |||
root:tag('div') | |||
:addClass('feedback-instruction') | |||
:wikitext('If this feedback has been resolved, edit this page and set <code>|resolved=true</code>.') | |||
end | |||
return tostring(root) | |||
end | |||
-- ========================================================================= | |||
-- 1. ARTICLE INGESTION & DISPLAY: {{#invoke:Feedback|main|...}} | |||
-- ========================================================================= | |||
function p.main(frame) | |||
local parent = frame:getParent() | |||
local args = parent and parent.args or frame.args | |||
return p._main(args) | |||
end | |||
function p._main(args) | |||
local feedback = args.feedback or "No feedback provided" | |||
local user = args.user or "Anonymous" | |||
local resolved = isTruthy(args.resolved) | |||
local statusStr = resolved and 'resolved' or 'unresolved' | |||
local currentPage = mw.title.getCurrentTitle().fullText | |||
-- Ingest to Bucket | |||
if mw.ext and mw.ext.bucket and mw.ext.bucket.put then | |||
mw.ext.bucket.put('feedback', { | |||
page = currentPage, | |||
user = user, | |||
status = statusStr, | |||
feedback = feedback | |||
}) | |||
elseif mw.ext and mw.ext.bucket then | |||
pcall(function() | |||
mw.ext.bucket('feedback').put({ | |||
page = currentPage, | |||
user = user, | |||
status = statusStr, | |||
feedback = feedback | |||
}) | |||
end) | |||
end | |||
local card = renderCard(user, feedback, resolved, nil) | |||
local category = resolved and '[[Category:Resolved Feedback]]' or '[[Category:Unresolved Feedback]]' | |||
return card .. category | |||
end | |||
-- ========================================================================= | |||
-- 2. DASHBOARD QUERY WITH TABBER: {{#invoke:Feedback|dashboard}} | |||
-- ========================================================================= | |||
function p.dashboard(frame) | |||
local rows = nil | |||
-- Method 1: mw.ext.bucket:select() syntax (common Scribunto Bucket API) | |||
if not rows and mw.ext and mw.ext.bucket and type(mw.ext.bucket) == 'function' then | |||
pcall(function() | |||
rows = mw.ext.bucket('feedback'):select('page', 'user', 'status', 'feedback'):run() | |||
end) | |||
end | |||
-- Method 2: mw.ext.bucket.query() or mw.ext.bucket.select() direct table syntax | |||
if not rows and mw.ext and mw.ext.bucket then | |||
if type(mw.ext.bucket.query) == 'function' then | |||
pcall(function() | |||
rows = mw.ext.bucket.query('feedback', { | |||
fields = { 'page', 'user', 'status', 'feedback' } | |||
}) | |||
end) | |||
elseif type(mw.ext.bucket.select) == 'function' then | |||
pcall(function() | |||
rows = mw.ext.bucket.select('feedback', { 'page', 'user', 'status', 'feedback' }) | |||
end) | |||
end | |||
end | |||
-- Method 3: Global mw.bucket syntax | |||
if not rows and mw.bucket then | |||
pcall(function() | |||
if type(mw.bucket) == 'function' then | |||
rows = mw.bucket('feedback'):select('page', 'user', 'status', 'feedback'):run() | |||
elseif type(mw.bucket.query) == 'function' then | |||
rows = mw.bucket.query('feedback', { | |||
fields = { 'page', 'user', 'status', 'feedback' } | |||
}) | |||
end | |||
end) | |||
end | |||
rows = rows or {} | |||
local allCards = {} | |||
local unresolvedCards = {} | |||
local resolvedCards = {} | |||
for _, row in ipairs(rows) do | |||
-- Support both string keys and positional keys | |||
local pageName = row.page or row[1] or '' | |||
local user = row.user or row[2] or 'Anonymous' | |||
local status = tostring(row.status or row[3] or 'unresolved'):lower() | |||
local feedbackText = row.feedback or row[4] or '' | |||
local isResolved = status == 'resolved' or status == 'true' or status == '1' | |||
local card = renderCard(user, feedbackText, isResolved, pageName) | |||
table.insert(allCards, card) | |||
if isResolved then | |||
table.insert(resolvedCards, card) | |||
else | |||
table.insert(unresolvedCards, card) | |||
end | |||
end | |||
local function getListHtml(cards, emptyMsg) | |||
if #cards == 0 then | |||
return string.format('<div class="feedback-empty" style="padding: 12px; color: #72777d; font-style: italic;">%s</div>', emptyMsg) | |||
end | |||
return table.concat(cards, '\n\n') | |||
end | |||
-- Construct the raw wikitext for the <tabber> extension | |||
local tabberWikitext = string.format( | |||
'<tabber>\n' .. | |||
'Unresolved (%d)=\n%s\n' .. | |||
'|-|\n' .. | |||
'Resolved (%d)=\n%s\n' .. | |||
'|-|\n' .. | |||
'All (%d)=\n%s\n' .. | |||
'</tabber>', | |||
#unresolvedCards, getListHtml(unresolvedCards, 'No unresolved feedback found.'), | |||
#resolvedCards, getListHtml(resolvedCards, 'No resolved feedback found.'), | |||
#allCards, getListHtml(allCards, 'No feedback records found.') | |||
) | |||
return frame:preprocess(tabberWikitext) | |||
end | |||
return p | |||