Editing Module:Feedback
Appearance
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 2: | Line 2: | ||
------------------------------------------------------------ | ------------------------------------------------------------ | ||
-- | -- Helpers | ||
------------------------------------------------------------ | ------------------------------------------------------------ | ||
local function isTruthy( | local function isTruthy(v) | ||
if | if v == nil then | ||
return false | return false | ||
end | end | ||
v = mw.text.trim(tostring(v)):lower() | |||
return | return v ~= '' | ||
and v ~= '0' | |||
and v ~= 'false' | |||
and v ~= 'no' | |||
and v ~= 'off' | |||
end | end | ||
local function formatUser(user) | local function formatUser(user) | ||
user = trim(user) | user = mw.text.trim(tostring(user or '')) | ||
if user == '' then | if user == '' or user:lower() == 'anonymous' then | ||
return 'Anonymous' | return 'Anonymous' | ||
end | end | ||
| Line 43: | Line 35: | ||
------------------------------------------------------------ | |||
-- Feedback card | |||
------------------------------------------------------------ | |||
local function renderCard(entry, showInstruction) | |||
local resolved = (entry.status == 'resolved') | |||
local user = | |||
entry.user | |||
or 'Anonymous' | |||
local | local feedback = | ||
entry.feedback | |||
or 'No feedback provided' | |||
local page = | |||
entry.page | |||
local id = | |||
mw.text.trim( | |||
tostring(entry.id or '') | |||
local | |||
mw. | |||
) | ) | ||
local | local resolvedBy = | ||
mw.text.trim( | |||
tostring(entry.resolvedby or '') | |||
) | ) | ||
local resolvedDate = | |||
mw.text.trim( | |||
tostring(entry.resolveddate or '') | |||
) | ) | ||
local root = mw.html.create('div') | |||
:addClass('feedback-box') | |||
' | :addClass( | ||
resolved | |||
and 'feedback-box--resolved' | |||
or 'feedback-box--unresolved' | |||
) | ) | ||
-------------------------------------------------------- | |||
-- Meta | |||
-------------------------------------------------------- | |||
local meta = root:tag('div') | |||
:addClass('feedback-meta') | |||
- | |||
if page and page ~= '' then | |||
page | |||
meta:tag('span') | |||
:addClass('feedback-page') | |||
:wikitext( | |||
string.format( | |||
'[[%s]]', | |||
page | |||
:addClass('feedback- | ) | ||
: | |||
) | ) | ||
meta:tag('span') | |||
:addClass('feedback-separator') | |||
:wikitext(' • ') | |||
: | |||
:wikitext(' | |||
end | end | ||
meta:tag('span') | |||
:addClass('feedback-user') | |||
:wikitext( | |||
formatUser(user) | |||
) | |||
) | ) | ||
meta:tag('span') | |||
:addClass('feedback-separator') | |||
:wikitext(' • ') | |||
meta:tag('span') | |||
:addClass('feedback-status') | :addClass('feedback-status') | ||
:addClass( | :addClass( | ||
| Line 331: | Line 124: | ||
-------------------------------------------------------- | -------------------------------------------------------- | ||
-- Feedback | -- Feedback | ||
-------------------------------------------------------- | -------------------------------------------------------- | ||
root:tag('div') | |||
:addClass('feedback- | :addClass('feedback-body') | ||
:wikitext( | :wikitext(feedback) | ||
-------------------------------------------------------- | -------------------------------------------------------- | ||
-- | -- Resolution information | ||
-------------------------------------------------------- | -------------------------------------------------------- | ||
if resolved and resolvedBy ~= '' then | |||
local resolution = | |||
root:tag('div') | |||
' | :addClass('feedback-resolution') | ||
resolution:wikitext( | |||
'Resolved by ' | |||
.. formatUser(resolvedBy) | |||
) | ) | ||
if resolvedDate ~= '' then | |||
resolution:wikitext( | |||
' on ' | |||
.. mw.text.nowiki(resolvedDate) | |||
) | |||
end | |||
end | end | ||
-------------------------------------------------------- | -------------------------------------------------------- | ||
-- | -- Resolve instruction | ||
-------------------------------------------------------- | -------------------------------------------------------- | ||
if showInstruction and not resolved then | |||
local instruction = | |||
root:tag('div') | |||
:addClass('feedback-instruction') | |||
if id ~= '' then | |||
instruction:wikitext( | |||
'If this feedback has been resolved, click the button below. ' | |||
.. '[#feedback-resolve-' | |||
.. id | |||
' | .. ' Resolve]' | ||
) | ) | ||
else | |||
instruction:wikitext( | |||
'Add an ID to this feedback to enable the Resolve button.' | |||
) | |||
end | |||
end | end | ||
| Line 413: | Line 189: | ||
------------------------------------------------------------ | ------------------------------------------------------------ | ||
-- | -- Save feedback | ||
------------------------------------------------------------ | ------------------------------------------------------------ | ||
local function | local function saveFeedback(data) | ||
if not (mw.ext and mw.ext.bucket) then | |||
return false, 'Bucket extension is not available' | |||
end | |||
local bucket = | |||
mw.ext.bucket('feedback') | |||
local bucket = | |||
if not bucket then | if not bucket then | ||
return false, ' | return false, 'Feedback bucket could not be opened' | ||
end | end | ||
local success, err = pcall(function() | local success, err = pcall(function() | ||
bucket.put({ | bucket.put({ | ||
page = data.page, | page = data.page, | ||
| Line 439: | Line 213: | ||
feedback = data.feedback, | feedback = data.feedback, | ||
id = data.id, | id = data.id, | ||
resolvedby = data.resolvedby, | resolvedby = data.resolvedby, | ||
resolveddate = data.resolveddate | resolveddate = data.resolveddate | ||
}) | }) | ||
end) | end) | ||
| Line 456: | Line 228: | ||
------------------------------------------------------------ | ------------------------------------------------------------ | ||
-- | -- Main | ||
------------------------------------------------------------ | ------------------------------------------------------------ | ||
function p.main(frame) | function p.main(frame) | ||
local parent = frame:getParent() | |||
local parent = | |||
frame:getParent() | |||
local args = | local args = | ||
| Line 471: | Line 243: | ||
if parent and parent.getTitle then | if parent and parent.getTitle then | ||
local title = parent:getTitle() | |||
local title = | |||
parent:getTitle() | |||
if title | if title | ||
| Line 477: | Line 251: | ||
and not title:find('^Template:') | and not title:find('^Template:') | ||
then | then | ||
pageTitle = title | pageTitle = title | ||
end | end | ||
end | end | ||
| Line 489: | Line 265: | ||
function p._main(args, pageTitle) | function p._main(args, pageTitle) | ||
local feedback = | local feedback = | ||
args.feedback | |||
or 'No feedback provided' | |||
local user = | |||
args.user | |||
or 'Anonymous' | |||
local id = | |||
args.id | |||
or '' | |||
local | local resolvedBy = | ||
args.resolvedby | |||
or '' | |||
local resolvedDate = | |||
args.resolveddate | |||
or '' | |||
local resolved = | local resolved = | ||
| Line 512: | Line 295: | ||
local currentPage = | local currentPage = | ||
pageTitle | |||
or mw.title.getCurrentTitle().fullText | |||
-------------------------------------------------------- | -------------------------------------------------------- | ||
| Line 548: | Line 309: | ||
feedback = feedback, | feedback = feedback, | ||
id = id, | id = id, | ||
resolvedby = resolvedBy, | |||
resolveddate = resolvedDate | |||
resolvedby = | |||
resolveddate = | |||
}) | }) | ||
if not saved then | if not saved then | ||
return | |||
return '<strong style="color:red;">Feedback bucket error: ' | |||
.. mw.text.nowiki( | .. mw.text.nowiki( | ||
saveError or 'Unknown error' | saveError or 'Unknown error' | ||
) | ) | ||
.. '</strong>' | .. '</strong>' | ||
end | end | ||
-------------------------------------------------------- | -------------------------------------------------------- | ||
-- Render | -- Render card | ||
-------------------------------------------------------- | -------------------------------------------------------- | ||
local card = | local card = | ||
renderCard({ | |||
page = | page = nil, | ||
user = user, | user = user, | ||
status = status, | status = status, | ||
feedback = feedback, | feedback = feedback, | ||
id = id, | id = id, | ||
resolvedby = resolvedBy, | |||
resolveddate = resolvedDate | |||
}, true) | |||
resolvedby = | |||
resolveddate = | |||
}) | |||
-------------------------------------------------------- | -------------------------------------------------------- | ||
| Line 586: | Line 342: | ||
-------------------------------------------------------- | -------------------------------------------------------- | ||
local | local categories = {} | ||
if resolved then | if resolved then | ||
table.insert( | |||
categories, | |||
'[[Category:Resolved Feedback]]' | '[[Category:Resolved Feedback]]' | ||
) | |||
else | else | ||
table.insert( | |||
categories, | |||
'[[Category:Unresolved Feedback]]' | '[[Category:Unresolved Feedback]]' | ||
) | |||
end | end | ||
if id == '' then | if mw.text.trim( | ||
tostring(id) | |||
) == '' then | |||
table.insert( | |||
categories, | |||
'[[Category:Feedbacks Missing ID]]' | '[[Category:Feedbacks Missing ID]]' | ||
) | |||
end | end | ||
return card .. | return card | ||
.. table.concat(categories) | |||
end | end | ||
------------------------------------------------------------ | ------------------------------------------------------------ | ||
-- | -- Render feedback list | ||
------------------------------------------------------------ | ------------------------------------------------------------ | ||
local function renderFeedbackList(results) | local function renderFeedbackList(results) | ||
if not results or #results == 0 then | if not results or #results == 0 then | ||
return '<em>No feedback entries found.</em>' | return '<em>No feedback entries found.</em>' | ||
| Line 618: | Line 389: | ||
for _, row in ipairs(results) do | for _, row in ipairs(results) do | ||
table.insert( | table.insert( | ||
list, | list, | ||
renderCard( | |||
row, | |||
false | |||
) | |||
) | ) | ||
end | end | ||
| Line 632: | Line 408: | ||
------------------------------------------------------------ | ------------------------------------------------------------ | ||
-- | -- View feedback | ||
------------------------------------------------------------ | ------------------------------------------------------------ | ||
function p. | function p.view(frame) | ||
local | |||
local parent = | |||
frame:getParent() | |||
local args | |||
if frame | |||
and frame.args | |||
and frame.args.status | |||
then | |||
args = | |||
frame.args | |||
elseif parent | |||
and parent.args | |||
and parent.args.status | |||
then | |||
args = | |||
parent.args | |||
elseif frame | |||
and frame.args | |||
then | |||
args = | |||
frame.args | |||
elseif parent | |||
and parent.args | |||
then | |||
args = | |||
parent.args | |||
else | |||
args = {} | |||
end | |||
return p._view( | |||
args, | |||
frame | |||
) | ) | ||
end | |||
function p._view(args, frame) | |||
if not (mw.ext and mw.ext.bucket) then | |||
return '<em>Bucket extension is not available.</em>' | |||
end | end | ||
frame = | |||
frame | |||
or mw.getCurrentFrame() | |||
local rawStatus = | |||
args.status | |||
or args[1] | |||
local filterStatus = | |||
rawStatus | |||
and mw.text.trim(rawStatus):lower() | |||
or nil | |||
-------------------------------------------------------- | -------------------------------------------------------- | ||
-- | -- Filtered views | ||
-------------------------------------------------------- | -------------------------------------------------------- | ||
if filterStatus == 'resolved' | |||
or filterStatus == 'unresolved' | |||
then | |||
local query = | |||
mw.ext.bucket('feedback') | |||
query.select( | |||
'page', | |||
'user', | |||
'status', | |||
'feedback', | |||
'id', | |||
'resolvedby', | |||
'resolveddate' | |||
) | |||
query.where( | |||
'status', | |||
filterStatus | |||
) | |||
return renderFeedbackList( | |||
query.run() | |||
) | |||
end | end | ||
| Line 787: | Line 515: | ||
-------------------------------------------------------- | -------------------------------------------------------- | ||
if filterStatus == 'all' then | |||
local query = | |||
mw.ext.bucket('feedback') | |||
query.select( | |||
'page', | |||
'user', | |||
'status', | |||
'feedback', | |||
'id', | |||
'resolvedby', | |||
'resolveddate' | |||
) | |||
return renderFeedbackList( | |||
query.run() | |||
) | ) | ||
end | |||
-------------------------------------------------------- | |||
-- Default tabbed view | |||
-------------------------------------------------------- | |||
local qAll = | |||
mw.ext.bucket('feedback') | |||
qAll.select( | |||
'page', | |||
'user', | |||
'status', | |||
'feedback', | |||
'id', | |||
'resolvedby', | |||
'resolveddate' | |||
) | ) | ||
local allEntries = | |||
qAll.run() | |||
local allList = {} | |||
local unresolvedList = {} | |||
local resolvedList = {} | |||
if allEntries and #allEntries > 0 then | |||
if | |||
for _, row in ipairs(allEntries) do | |||
local card = | |||
renderCard( | |||
row, | |||
false | |||
) | |||
table.insert( | |||
allList, | |||
card | |||
) | |||
if row.status == 'resolved' then | |||
table.insert( | |||
resolvedList, | |||
card | |||
) | |||
else | |||
table.insert( | |||
unresolvedList, | |||
card | |||
) | |||
end | |||
end | |||
end | |||
-------------------------------------------------------- | |||
-- All content | |||
-------------------------------------------------------- | |||
local allContent | |||
if #allList > 0 then | |||
allContent = | |||
table.concat( | |||
allList, | |||
'\n' | |||
) | ) | ||
else | |||
allContent = | |||
'<em>No feedback entries found.</em>' | |||
end | end | ||
-------------------------------------------------------- | |||
-- Unresolved content | |||
-------------------------------------------------------- | |||
local unresolvedContent | |||
if #unresolvedList > 0 then | |||
unresolvedContent = | |||
table.concat( | |||
unresolvedList, | |||
'\n' | |||
) | |||
else | else | ||
unresolvedContent = | |||
'<em>No unresolved feedback entries found.</em>' | |||
end | end | ||
-------------------------------------------------------- | -------------------------------------------------------- | ||
-- | -- Resolved content | ||
-------------------------------------------------------- | -------------------------------------------------------- | ||
local | local resolvedContent | ||
if #resolvedList > 0 then | |||
resolvedContent = | |||
table.concat( | |||
resolvedList, | |||
'\n' | |||
) | |||
else | |||
resolvedContent = | |||
'<em>No resolved feedback entries found.</em>' | |||
end | end | ||
-------------------------------------------------------- | -------------------------------------------------------- | ||
-- | -- Tabber | ||
-------------------------------------------------------- | -------------------------------------------------------- | ||
local tabberBody = | |||
string.format( | |||
'All=\n%s\n|-|Unresolved=\n%s\n|-|Resolved=\n%s', | |||
allContent, | |||
unresolvedContent, | |||
resolvedContent | |||
) | ) | ||
return frame:callParserFunction( | |||
'#tag', | |||
{ | |||
'tabber', | |||
tabberBody | |||
} | |||
) | |||
end | end | ||
return p | return p | ||