Module:Feedback: Difference between revisions
Appearance
ReisuDesign (talk | contribs) No edit summary |
ReisuDesign (talk | contribs) No edit summary |
||
| Line 32: | Line 32: | ||
user | user | ||
) | ) | ||
end | end | ||
| Line 50: | Line 43: | ||
local resolved = (entry.status == 'resolved') | local resolved = (entry.status == 'resolved') | ||
local user = entry.user or 'Anonymous' | local user = | ||
local feedback = entry.feedback or 'No feedback provided' | entry.user | ||
local page = entry.page | or 'Anonymous' | ||
local id = | |||
local feedback = | |||
entry.feedback | |||
or 'No feedback provided' | |||
local page = | |||
entry.page | |||
local id = | |||
mw.text.trim( | |||
tostring(entry.id or '') | |||
) | |||
local resolvedBy = | |||
mw.text.trim( | |||
tostring(entry.resolvedby or '') | |||
) | |||
local resolvedDate = | |||
mw.text.trim( | |||
tostring(entry.resolveddate or '') | |||
) | |||
local root = mw.html.create('div') | local root = mw.html.create('div') | ||
| Line 65: | Line 76: | ||
or 'feedback-box--unresolved' | or 'feedback-box--unresolved' | ||
) | ) | ||
-------------------------------------------------------- | -------------------------------------------------------- | ||
-- | -- Meta | ||
-------------------------------------------------------- | -------------------------------------------------------- | ||
local meta = root:tag('div') | local meta = root:tag('div') | ||
:addClass('feedback-meta') | :addClass('feedback-meta') | ||
if page and page ~= '' then | if page and page ~= '' then | ||
meta:tag('span') | meta:tag('span') | ||
:addClass('feedback-page') | :addClass('feedback-page') | ||
:wikitext( | :wikitext( | ||
string.format('[[%s]]', page) | string.format( | ||
'[[%s]]', | |||
page | |||
) | |||
) | ) | ||
| Line 86: | Line 97: | ||
:addClass('feedback-separator') | :addClass('feedback-separator') | ||
:wikitext(' • ') | :wikitext(' • ') | ||
end | end | ||
meta:tag('span') | meta:tag('span') | ||
:addClass('feedback-user') | :addClass('feedback-user') | ||
:wikitext(formatUser(user)) | :wikitext( | ||
formatUser(user) | |||
) | |||
meta:tag('span') | meta:tag('span') | ||
:addClass('feedback-separator') | :addClass('feedback-separator') | ||
:wikitext(' • ') | :wikitext(' • ') | ||
meta:tag('span') | meta:tag('span') | ||
| Line 112: | Line 121: | ||
or 'Unresolved' | or 'Unresolved' | ||
) | ) | ||
-------------------------------------------------------- | -------------------------------------------------------- | ||
-- Feedback | -- Feedback | ||
-------------------------------------------------------- | -------------------------------------------------------- | ||
| Line 121: | Line 129: | ||
:addClass('feedback-body') | :addClass('feedback-body') | ||
:wikitext(feedback) | :wikitext(feedback) | ||
-------------------------------------------------------- | -------------------------------------------------------- | ||
| Line 127: | Line 134: | ||
-------------------------------------------------------- | -------------------------------------------------------- | ||
if resolved | if resolved and resolvedBy ~= '' then | ||
local | local resolution = root:tag('div') | ||
' | :addClass('feedback-resolution') | ||
if | resolution:wikitext( | ||
'Resolved by ' | |||
.. formatUser(resolvedBy) | |||
) | |||
.. resolvedDate | |||
if resolvedDate ~= '' then | |||
resolution:wikitext( | |||
' on ' | |||
.. mw.text.nowiki(resolvedDate) | |||
) | |||
end | end | ||
end | end | ||
-------------------------------------------------------- | -------------------------------------------------------- | ||
-- | -- Resolve instruction | ||
-------------------------------------------------------- | -------------------------------------------------------- | ||
| Line 155: | Line 161: | ||
:addClass('feedback-instruction') | :addClass('feedback-instruction') | ||
if id ~= '' then | |||
instruction:wikitext( | |||
'If this feedback has been resolved, click the button below. ' | |||
'If this feedback has been resolved, | |||
) | ) | ||
instruction:tag('button') | instruction:tag('button') | ||
:addClass('feedback-resolve-button') | :addClass('feedback-resolve-button') | ||
:attr('type', 'button') | :attr('type', 'button') | ||
:attr('data-feedback-id', | :attr('data-feedback-id', id) | ||
:wikitext('Resolve') | :wikitext('Resolve') | ||
else | |||
instruction:wikitext( | |||
'Add an ID to this feedback to enable the Resolve button.' | |||
) | |||
end | end | ||
end | end | ||
return tostring(root) | return tostring(root) | ||
| Line 190: | Line 196: | ||
end | end | ||
local bucket = | |||
local bucket = mw.ext.bucket('feedback') | mw.ext.bucket('feedback') | ||
if not bucket then | if not bucket then | ||
return false, 'Feedback bucket could not be opened' | return false, 'Feedback bucket could not be opened' | ||
end | end | ||
local success, err = pcall(function() | local success, err = pcall(function() | ||
| Line 211: | Line 216: | ||
end) | end) | ||
if not success then | if not success then | ||
return false, tostring(err) | return false, tostring(err) | ||
end | end | ||
return true | return true | ||
| Line 224: | Line 227: | ||
------------------------------------------------------------ | ------------------------------------------------------------ | ||
-- Main | -- Main | ||
------------------------------------------------------------ | ------------------------------------------------------------ | ||
function p.main(frame) | function p.main(frame) | ||
local parent = frame:getParent() | local parent = | ||
frame:getParent() | |||
local args = | local args = | ||
parent and parent.args | parent and parent.args | ||
or frame.args | or frame.args | ||
local pageTitle = nil | local pageTitle = nil | ||
| Line 256: | Line 242: | ||
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 264: | Line 251: | ||
pageTitle = title | pageTitle = title | ||
end | end | ||
end | end | ||
return p._main( | |||
return p._main(args, pageTitle) | args, | ||
pageTitle | |||
) | |||
end | end | ||
| Line 278: | Line 265: | ||
args.feedback | args.feedback | ||
or 'No feedback provided' | or 'No feedback provided' | ||
local user = | local user = | ||
| Line 284: | Line 270: | ||
or 'Anonymous' | or 'Anonymous' | ||
local id = | |||
args.id | |||
or '' | |||
local resolvedBy = | |||
args.resolvedby | |||
or '' | |||
local resolvedDate = | |||
args.resolveddate | |||
or '' | |||
local resolved = | local resolved = | ||
isTruthy(args.resolved) | isTruthy(args.resolved) | ||
local status = | local status = | ||
| Line 293: | Line 289: | ||
and 'resolved' | and 'resolved' | ||
or 'unresolved' | or 'unresolved' | ||
local currentPage = | local currentPage = | ||
pageTitle | pageTitle | ||
or mw.title.getCurrentTitle().fullText | or mw.title.getCurrentTitle().fullText | ||
-------------------------------------------------------- | -------------------------------------------------------- | ||
| Line 322: | Line 298: | ||
-------------------------------------------------------- | -------------------------------------------------------- | ||
local saved, saveError = saveFeedback({ | local saved, saveError = | ||
saveFeedback({ | |||
page = currentPage, | |||
user = user, | |||
status = status, | |||
feedback = feedback, | |||
id = id, | |||
resolvedby = resolvedBy, | |||
resolveddate = resolvedDate | |||
}) | |||
if not saved then | if not saved then | ||
return '<strong style="color:red;">Feedback bucket error: ' | return '<strong style="color:red;">Feedback bucket error: ' | ||
.. mw.text.nowiki(saveError or 'Unknown error') | .. mw.text.nowiki( | ||
saveError or 'Unknown error' | |||
) | |||
.. '</strong>' | .. '</strong>' | ||
end | end | ||
-------------------------------------------------------- | -------------------------------------------------------- | ||
-- Render | -- Render card | ||
-------------------------------------------------------- | -------------------------------------------------------- | ||
local card = renderCard({ | local card = | ||
renderCard({ | |||
page = nil, | |||
user = user, | |||
status = status, | |||
feedback = feedback, | |||
id = id, | |||
resolvedby = resolvedBy, | |||
resolveddate = resolvedDate | |||
}, true) | |||
-------------------------------------------------------- | -------------------------------------------------------- | ||
-- | -- Categories | ||
-------------------------------------------------------- | -------------------------------------------------------- | ||
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 mw.text.trim( | |||
tostring(id) | |||
) == '' then | |||
table.insert( | |||
categories, | |||
'[[Category:Feedbacks Missing ID]]' | |||
) | |||
end | |||
return card | |||
.. table.concat(categories) | |||
end | end | ||
| Line 395: | Line 374: | ||
return '<em>No feedback entries found.</em>' | return '<em>No feedback entries found.</em>' | ||
end | end | ||
local list = {} | local list = {} | ||
for _, row in ipairs(results) do | for _, row in ipairs(results) do | ||
| Line 404: | Line 381: | ||
table.insert( | table.insert( | ||
list, | list, | ||
renderCard(row, false) | renderCard( | ||
row, | |||
false | |||
) | |||
) | ) | ||
end | end | ||
return table.concat( | |||
return table.concat(list, '\n') | list, | ||
'\n' | |||
) | |||
end | end | ||
| Line 421: | Line 402: | ||
function p.view(frame) | function p.view(frame) | ||
local parent = frame:getParent() | local parent = | ||
frame:getParent() | |||
local args | local args | ||
| Line 431: | Line 412: | ||
then | then | ||
args = frame.args | args = | ||
frame.args | |||
elseif parent | elseif parent | ||
| Line 438: | Line 420: | ||
then | then | ||
args = parent.args | args = | ||
parent.args | |||
elseif frame | elseif frame | ||
| Line 444: | Line 427: | ||
then | then | ||
args = frame.args | args = | ||
frame.args | |||
elseif parent | elseif parent | ||
| Line 450: | Line 434: | ||
then | then | ||
args = parent.args | args = | ||
parent.args | |||
else | else | ||
| Line 458: | Line 443: | ||
end | end | ||
return p._view( | |||
return p._view(args, frame) | args, | ||
frame | |||
) | |||
end | end | ||
function p._view(args, frame) | function p._view(args, frame) | ||
if not (mw.ext and mw.ext.bucket) then | if not (mw.ext and mw.ext.bucket) then | ||
return '<em>Bucket extension is not available.</em>' | |||
return | |||
end | end | ||
frame = | |||
frame = frame or mw.getCurrentFrame() | frame | ||
or mw.getCurrentFrame() | |||
local rawStatus = | local rawStatus = | ||
args.status | args.status | ||
or args[1] | or args[1] | ||
local filterStatus = | local filterStatus = | ||
| Line 494: | Line 468: | ||
and mw.text.trim(rawStatus):lower() | and mw.text.trim(rawStatus):lower() | ||
or nil | or nil | ||
-------------------------------------------------------- | -------------------------------------------------------- | ||
-- | -- Filtered views | ||
-------------------------------------------------------- | -------------------------------------------------------- | ||
| Line 506: | Line 479: | ||
local query = | local query = | ||
mw.ext.bucket('feedback') | mw.ext.bucket('feedback') | ||
query.select( | query.select( | ||
| Line 512: | Line 484: | ||
'user', | 'user', | ||
'status', | 'status', | ||
'feedback' | 'feedback', | ||
'id', | |||
'resolvedby', | |||
'resolveddate' | |||
) | ) | ||
query.where( | query.where( | ||
| Line 520: | Line 494: | ||
filterStatus | filterStatus | ||
) | ) | ||
return renderFeedbackList( | return renderFeedbackList( | ||
query.run() | query.run() | ||
) | ) | ||
end | end | ||
-------------------------------------------------------- | -------------------------------------------------------- | ||
-- All | -- All | ||
-------------------------------------------------------- | -------------------------------------------------------- | ||
| Line 537: | Line 508: | ||
local query = | local query = | ||
mw.ext.bucket('feedback') | mw.ext.bucket('feedback') | ||
query.select( | query.select( | ||
| Line 543: | Line 513: | ||
'user', | 'user', | ||
'status', | 'status', | ||
'feedback' | 'feedback', | ||
'id', | |||
'resolvedby', | |||
'resolveddate' | |||
) | ) | ||
return renderFeedbackList( | return renderFeedbackList( | ||
query.run() | query.run() | ||
) | ) | ||
end | end | ||
-------------------------------------------------------- | -------------------------------------------------------- | ||
-- | -- Default tabbed view | ||
-------------------------------------------------------- | -------------------------------------------------------- | ||
local qAll = | local qAll = | ||
mw.ext.bucket('feedback') | mw.ext.bucket('feedback') | ||
qAll.select( | qAll.select( | ||
| Line 566: | Line 535: | ||
'user', | 'user', | ||
'status', | 'status', | ||
'feedback' | 'feedback', | ||
'id', | |||
'resolvedby', | |||
'resolveddate' | |||
) | ) | ||
local allEntries = | local allEntries = | ||
qAll.run() | qAll.run() | ||
local allList = {} | local allList = {} | ||
local unresolvedList = {} | local unresolvedList = {} | ||
local resolvedList = {} | local resolvedList = {} | ||
if allEntries and #allEntries > 0 then | if allEntries and #allEntries > 0 then | ||
| Line 588: | Line 553: | ||
local card = | local card = | ||
renderCard(row, false) | renderCard( | ||
row, | |||
false | |||
) | |||
table.insert( | table.insert( | ||
| Line 595: | Line 562: | ||
card | card | ||
) | ) | ||
if row.status == 'resolved' then | if row.status == 'resolved' then | ||
| Line 612: | Line 578: | ||
end | end | ||
end | end | ||
end | end | ||
-------------------------------------------------------- | -------------------------------------------------------- | ||
-- | -- All content | ||
-------------------------------------------------------- | -------------------------------------------------------- | ||
| Line 627: | Line 590: | ||
allContent = | allContent = | ||
table.concat(allList, '\n') | table.concat( | ||
allList, | |||
'\n' | |||
) | |||
else | else | ||
| Line 636: | Line 602: | ||
end | end | ||
-------------------------------------------------------- | |||
-- Unresolved content | |||
-------------------------------------------------------- | |||
local unresolvedContent | local unresolvedContent | ||
| Line 642: | Line 611: | ||
unresolvedContent = | unresolvedContent = | ||
table.concat(unresolvedList, '\n') | table.concat( | ||
unresolvedList, | |||
'\n' | |||
) | |||
else | else | ||
| Line 651: | Line 623: | ||
end | end | ||
-------------------------------------------------------- | |||
-- Resolved content | |||
-------------------------------------------------------- | |||
local resolvedContent | local resolvedContent | ||
| Line 657: | Line 632: | ||
resolvedContent = | resolvedContent = | ||
table.concat(resolvedList, '\n') | table.concat( | ||
resolvedList, | |||
'\n' | |||
) | |||
else | else | ||
| Line 665: | Line 643: | ||
end | end | ||
-------------------------------------------------------- | -------------------------------------------------------- | ||
| Line 671: | Line 648: | ||
-------------------------------------------------------- | -------------------------------------------------------- | ||
local tabberBody = string.format( | local tabberBody = | ||
string.format( | |||
'All=\n%s\n|-|Unresolved=\n%s\n|-|Resolved=\n%s', | |||
allContent, | |||
unresolvedContent, | |||
resolvedContent | |||
) | |||
return frame:callParserFunction( | return frame:callParserFunction( | ||
| Line 686: | Line 663: | ||
} | } | ||
) | ) | ||
end | end | ||
return p | return p | ||
Revision as of 05:17, 16 September 2026
| Main | Documentation | Usage |
This module implements {{Feedback}}.
local p = {}
------------------------------------------------------------
-- Helpers
------------------------------------------------------------
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
------------------------------------------------------------
-- Feedback card
------------------------------------------------------------
local function renderCard(entry, showInstruction)
local resolved = (entry.status == 'resolved')
local user =
entry.user
or 'Anonymous'
local feedback =
entry.feedback
or 'No feedback provided'
local page =
entry.page
local id =
mw.text.trim(
tostring(entry.id or '')
)
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
meta:tag('span')
:addClass('feedback-page')
:wikitext(
string.format(
'[[%s]]',
page
)
)
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'
)
--------------------------------------------------------
-- Feedback
--------------------------------------------------------
root:tag('div')
:addClass('feedback-body')
: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
--------------------------------------------------------
-- 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. '
)
instruction:tag('button')
:addClass('feedback-resolve-button')
:attr('type', 'button')
:attr('data-feedback-id', id)
:wikitext('Resolve')
else
instruction:wikitext(
'Add an ID to this feedback to enable the Resolve button.'
)
end
end
return tostring(root)
end
------------------------------------------------------------
-- Save feedback
------------------------------------------------------------
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')
if not bucket then
return false, 'Feedback bucket could not be opened'
end
local success, err = pcall(function()
bucket.put({
page = data.page,
user = data.user,
status = data.status,
feedback = data.feedback,
id = data.id,
resolvedby = data.resolvedby,
resolveddate = data.resolveddate
})
end)
if not success then
return false, tostring(err)
end
return true
end
------------------------------------------------------------
-- Main
------------------------------------------------------------
function p.main(frame)
local parent =
frame:getParent()
local args =
parent and parent.args
or frame.args
local pageTitle = nil
if parent and parent.getTitle then
local title =
parent:getTitle()
if title
and title ~= ''
and not title:find('^Template:')
then
pageTitle = title
end
end
return p._main(
args,
pageTitle
)
end
function p._main(args, pageTitle)
local feedback =
args.feedback
or 'No feedback provided'
local user =
args.user
or 'Anonymous'
local id =
args.id
or ''
local resolvedBy =
args.resolvedby
or ''
local resolvedDate =
args.resolveddate
or ''
local resolved =
isTruthy(args.resolved)
local status =
resolved
and 'resolved'
or 'unresolved'
local currentPage =
pageTitle
or mw.title.getCurrentTitle().fullText
--------------------------------------------------------
-- Save to Bucket
--------------------------------------------------------
local saved, saveError =
saveFeedback({
page = currentPage,
user = user,
status = status,
feedback = feedback,
id = id,
resolvedby = resolvedBy,
resolveddate = resolvedDate
})
if not saved then
return '<strong style="color:red;">Feedback bucket error: '
.. mw.text.nowiki(
saveError or 'Unknown error'
)
.. '</strong>'
end
--------------------------------------------------------
-- Render card
--------------------------------------------------------
local card =
renderCard({
page = nil,
user = user,
status = status,
feedback = feedback,
id = id,
resolvedby = resolvedBy,
resolveddate = resolvedDate
}, true)
--------------------------------------------------------
-- Categories
--------------------------------------------------------
local categories = {}
if resolved then
table.insert(
categories,
'[[Category:Resolved Feedback]]'
)
else
table.insert(
categories,
'[[Category:Unresolved Feedback]]'
)
end
if mw.text.trim(
tostring(id)
) == '' then
table.insert(
categories,
'[[Category:Feedbacks Missing ID]]'
)
end
return card
.. table.concat(categories)
end
------------------------------------------------------------
-- Render feedback list
------------------------------------------------------------
local function renderFeedbackList(results)
if not results or #results == 0 then
return '<em>No feedback entries found.</em>'
end
local list = {}
for _, row in ipairs(results) do
table.insert(
list,
renderCard(
row,
false
)
)
end
return table.concat(
list,
'\n'
)
end
------------------------------------------------------------
-- View feedback
------------------------------------------------------------
function p.view(frame)
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
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
--------------------------------------------------------
-- All
--------------------------------------------------------
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
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
--------------------------------------------------------
-- Unresolved content
--------------------------------------------------------
local unresolvedContent
if #unresolvedList > 0 then
unresolvedContent =
table.concat(
unresolvedList,
'\n'
)
else
unresolvedContent =
'<em>No unresolved feedback entries found.</em>'
end
--------------------------------------------------------
-- Resolved content
--------------------------------------------------------
local resolvedContent
if #resolvedList > 0 then
resolvedContent =
table.concat(
resolvedList,
'\n'
)
else
resolvedContent =
'<em>No resolved feedback entries found.</em>'
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
return p