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 | ||
------------------------------------------------------------ | ------------------------------------------------------------ | ||
| Line 12: | Line 12: | ||
value = mw.text.trim(tostring(value)):lower() | value = mw.text.trim(tostring(value)):lower() | ||
return value == ' | return value ~= '' | ||
and value ~= '0' | |||
and value ~= 'false' | |||
and value ~= 'no' | |||
and value ~= 'off' | |||
end | end | ||
local function trim(value) | local function trim(value) | ||
return mw.text.trim( | |||
tostring(value or '') | |||
) | |||
return mw.text.trim(tostring(value)) | |||
end | end | ||
| Line 31: | Line 30: | ||
user = trim(user) | user = trim(user) | ||
if user == '' then | if user == '' or user:lower() == 'anonymous' then | ||
return 'Anonymous' | return 'Anonymous' | ||
end | end | ||
| Line 44: | Line 43: | ||
local function currentSubjectPage() | local function currentSubjectPage() | ||
local title = mw.title.getCurrentTitle() | local title = | ||
mw.title.getCurrentTitle() | |||
return title.fullText | return title.subjectPageTitle.fullText | ||
end | end | ||
| Line 56: | Line 52: | ||
local function getBucket() | local function getBucket() | ||
if not (mw.ext and mw.ext.bucket) then | if not (mw.ext and mw.ext.bucket) then | ||
return nil | return nil, 'Bucket extension is not available' | ||
end | |||
local bucket = | |||
mw.ext.bucket('feedback') | |||
if not bucket then | |||
return nil, 'Feedback bucket could not be opened' | |||
end | end | ||
return | return bucket | ||
end | end | ||
local function sortNewestFirst( | local function sortNewestFirst(results) | ||
if not results then | |||
return {} | |||
end | |||
table.sort( | table.sort( | ||
results, | |||
function(a, b) | function(a, b) | ||
return aDate > bDate | local aDate = | ||
trim(a.createddate) | |||
local bDate = | |||
trim(b.createddate) | |||
-- Entries without a date go last. | |||
if aDate == '' and bDate ~= '' then | |||
return false | |||
end | |||
if aDate ~= '' and bDate == '' then | |||
return true | |||
end | |||
if aDate ~= bDate then | |||
return aDate > bDate | |||
end | |||
-- Stable-ish fallback. | |||
return trim(a.id) > trim(b.id) | |||
end | end | ||
) | ) | ||
return | return results | ||
end | end | ||
local function queryFeedback(page) | local function queryFeedback(page, status) | ||
local bucket = getBucket() | local bucket, err = | ||
getBucket() | |||
if not bucket then | if not bucket then | ||
return | return nil, err | ||
end | |||
local query = | |||
bucket.select( | |||
'page', | |||
'user', | |||
'status', | |||
'feedback', | |||
'id', | |||
'createddate', | |||
'link', | |||
'image', | |||
'resolvedby', | |||
'resolveddate' | |||
) | |||
if page and page ~= '' then | |||
query.where( | |||
'page', | |||
page | |||
) | |||
end | |||
if status | |||
and status ~= '' | |||
and status ~= 'all' | |||
then | |||
query.where( | |||
'status', | |||
status | |||
) | |||
end | end | ||
local query | local success, results = | ||
pcall(function() | |||
return query.run() | |||
end) | |||
if not success then | |||
return nil, tostring(results) | |||
end | |||
return sortNewestFirst( | |||
results or {} | |||
) | ) | ||
end | |||
------------------------------------------------------------ | |||
-- Save feedback | |||
------------------------------------------------------------ | |||
local function saveFeedback(data) | |||
local bucket, err = | |||
getBucket() | |||
if not bucket then | |||
return false, err | |||
end | |||
local success, saveError = | |||
pcall(function() | |||
bucket.put({ | |||
page = data.page, | |||
user = data.user, | |||
status = data.status, | |||
feedback = data.feedback, | |||
id = data.id, | |||
createddate = data.createddate, | |||
link = data.link, | |||
image = data.image, | |||
resolvedby = data.resolvedby, | |||
resolveddate = data.resolveddate | |||
}) | |||
end) | |||
if not success | if not success then | ||
return | return false, tostring(saveError) | ||
end | end | ||
return | return true | ||
end | end | ||
------------------------------------------------------------ | ------------------------------------------------------------ | ||
-- | -- Shared metadata | ||
------------------------------------------------------------ | ------------------------------------------------------------ | ||
local function renderAttachments(entry) | local function renderMetadata(root, entry) | ||
local | |||
local meta = | |||
root:tag('div') | |||
:addClass('feedback-meta') | |||
if entry.user and entry.user ~= '' then | |||
meta:tag('span') | |||
:addClass('feedback-user') | |||
:wikitext( | |||
formatUser(entry.user) | |||
) | |||
end | |||
if entry.createddate | |||
and entry.createddate ~= '' | |||
then | |||
meta:tag('span') | |||
:addClass('feedback-meta-date') | |||
:wikitext( | |||
' · ' | |||
.. mw.text.nowiki( | |||
entry.createddate | |||
) | |||
) | |||
end | |||
end | |||
------------------------------------------------------------ | |||
-- Attachments | |||
------------------------------------------------------------ | |||
local function renderAttachments(root, entry) | |||
local link = | |||
trim(entry.link) | |||
local image = | |||
trim(entry.image) | |||
if link == '' | |||
and image == '' | |||
then | |||
return | |||
end | |||
local attachments = | |||
root:tag('div') | |||
:addClass('feedback-attachments') | :addClass('feedback-attachments') | ||
if link ~= '' then | |||
attachments:tag('span') | |||
:addClass('feedback-attachment') | |||
:wikitext( | |||
'🔗 ' | |||
.. '[' | |||
.. link | |||
.. ' Link]' | |||
) | |||
end | end | ||
if image ~= '' then | |||
attachments:tag('span') | |||
:addClass('feedback-attachment') | |||
'' | |||
attachments:tag('span') | |||
:addClass('feedback-image-icon') | |||
:wikitext('▣') | |||
attachments:tag('span') | |||
:addClass('feedback-image-link') | |||
:wikitext( | |||
'[[Media:' | |||
.. image | |||
.. '|Picture]]' | |||
'[' | |||
) | ) | ||
end | end | ||
end | end | ||
------------------------------------------------------------ | ------------------------------------------------------------ | ||
-- | -- Resolution information | ||
------------------------------------------------------------ | ------------------------------------------------------------ | ||
local function renderResolution( | local function renderResolution(root, entry) | ||
local resolvedBy = trim(entry.resolvedby | |||
local resolvedBy = | |||
trim(entry.resolvedby) | |||
if resolvedBy == '' and resolvedDate == '' then | local resolvedDate = | ||
trim(entry.resolveddate) | |||
if resolvedBy == '' | |||
and resolvedDate == '' | |||
then | |||
return | return | ||
end | end | ||
local resolution = | local resolution = | ||
root:tag('div') | |||
:addClass('feedback-resolution') | :addClass('feedback-resolution') | ||
resolution:wikitext('Resolved by ') | resolution:wikitext('↳ Resolved by ') | ||
if resolvedBy ~= '' then | if resolvedBy ~= '' then | ||
| Line 203: | Line 325: | ||
if resolvedDate ~= '' then | if resolvedDate ~= '' then | ||
resolution:wikitext( | resolution:wikitext( | ||
' on ' .. mw.text.nowiki(resolvedDate) | ' on ' | ||
.. mw.text.nowiki(resolvedDate) | |||
) | ) | ||
end | end | ||
| Line 210: | Line 333: | ||
------------------------------------------------------------ | ------------------------------------------------------------ | ||
-- | -- Resolve control | ||
------------------------------------------------------------ | ------------------------------------------------------------ | ||
| Line 216: | Line 339: | ||
parent, | parent, | ||
id, | id, | ||
compact | compact | ||
) | ) | ||
if | |||
if not id or id == '' then | |||
return | return | ||
end | end | ||
local control = | local control = | ||
parent:tag('span') | |||
:addClass('feedback-resolve-button') | :addClass('feedback-resolve-button') | ||
if compact then | if compact then | ||
control | control | ||
:addClass( | :addClass('feedback-resolve-button--compact') | ||
:attr('aria-label', 'Resolve feedback') | |||
) | :attr('title', 'Resolve feedback') | ||
:attr( | |||
:wikitext('✓') | :wikitext('✓') | ||
else | else | ||
control:wikitext('Resolve') | |||
control | |||
:attr('role', 'button') | |||
:attr('tabindex', '0') | |||
:attr('aria-label', 'Resolve feedback') | |||
:wikitext('Resolve') | |||
end | end | ||
control:attr( | |||
'data-feedback-id', | |||
id | |||
) | |||
end | end | ||
------------------------------------------------------------ | ------------------------------------------------------------ | ||
-- | -- Full feedback card | ||
------------------------------------------------------------ | ------------------------------------------------------------ | ||
local function renderFullCard(entry) | local function renderFullCard(entry) | ||
local resolved = | local resolved = | ||
entry.status == 'resolved' | |||
local id = trim(entry.id | local id = | ||
trim(entry.id) | |||
local root = | local root = | ||
| Line 296: | Line 402: | ||
) | ) | ||
end | end | ||
-------------------------------------------------------- | -------------------------------------------------------- | ||
| Line 310: | Line 408: | ||
local main = | local main = | ||
root:tag('div') | |||
:addClass('feedback-main-line') | :addClass('feedback-main-line') | ||
main:tag('span') | main:tag('span') | ||
| Line 326: | Line 420: | ||
:wikitext( | :wikitext( | ||
resolved | resolved | ||
and ' | and 'RESOLVED' | ||
or ' | or 'UNRESOLVED' | ||
) | ) | ||
main:tag('span') | main:tag('span') | ||
:addClass('feedback-text') | :addClass('feedback-text') | ||
:wikitext( | :wikitext( | ||
entry.feedback | |||
or 'No feedback provided' | or 'No feedback provided' | ||
) | ) | ||
| Line 346: | Line 435: | ||
-------------------------------------------------------- | -------------------------------------------------------- | ||
local | local metadata = | ||
main:tag('span') | main:tag('span') | ||
:addClass('feedback-inline-meta') | :addClass('feedback-inline-meta') | ||
if user ~= '' then | if entry.user | ||
and entry.user ~= '' | |||
' · ' .. formatUser(user) | then | ||
metadata:wikitext( | |||
' · ' | |||
.. formatUser(entry.user) | |||
) | |||
end | |||
if entry.createddate | |||
and entry.createddate ~= '' | |||
then | |||
metadata:wikitext( | |||
' ' | |||
.. mw.text.nowiki( | |||
entry.createddate | |||
) | |||
) | ) | ||
end | end | ||
if | -------------------------------------------------------- | ||
-- Resolve button | |||
-------------------------------------------------------- | |||
if not resolved | |||
and id ~= '' | |||
then | |||
renderResolveControl( | |||
main, | |||
id, | |||
false | |||
) | ) | ||
end | end | ||
| Line 365: | Line 482: | ||
-- Attachments | -- Attachments | ||
-------------------------------------------------------- | -------------------------------------------------------- | ||
renderAttachments( | |||
root, | |||
entry | |||
) | ) | ||
-------------------------------------------------------- | -------------------------------------------------------- | ||
-- Resolution | -- Resolution | ||
-------------------------------------------------------- | -------------------------------------------------------- | ||
renderResolution( | if resolved then | ||
renderResolution( | |||
root, | |||
entry | |||
) | |||
end | |||
-------------------------------------------------------- | -------------------------------------------------------- | ||
| Line 383: | Line 503: | ||
-------------------------------------------------------- | -------------------------------------------------------- | ||
if id == '' then | if not resolved | ||
and id == '' | |||
then | |||
root:tag('div') | |||
:addClass('feedback-missing-id') | :addClass('feedback-missing-id') | ||
:wikitext( | :wikitext( | ||
' | 'Add an ID to enable the Resolve button.' | ||
) | ) | ||
end | end | ||
| Line 413: | Line 520: | ||
------------------------------------------------------------ | ------------------------------------------------------------ | ||
-- | -- Compact article card | ||
------------------------------------------------------------ | ------------------------------------------------------------ | ||
local function renderCompactCard(entry) | local function renderCompactCard(entry) | ||
local resolved = | |||
entry.status == 'resolved' | |||
local id = | |||
trim(entry.id) | |||
local | local root = | ||
mw.html.create('div') | |||
:addClass('feedback-page-card') | |||
:addClass( | |||
resolved | |||
and 'feedback-page-card--resolved' | |||
or 'feedback-page-card--unresolved' | |||
) | |||
if | if id ~= '' then | ||
root:attr( | |||
'data-feedback-id', | |||
id | |||
) | |||
end | end | ||
local | local content = | ||
root:tag('div') | |||
page | :addClass('feedback-page-card-content') | ||
local firstLine = | |||
content:tag('div') | |||
:addClass('feedback-page-card-line') | |||
firstLine:tag('span') | |||
:addClass('feedback-status') | |||
:addClass( | |||
resolved | |||
and 'feedback-status--resolved' | |||
or 'feedback-status--unresolved' | |||
) | |||
:wikitext( | |||
resolved | |||
and 'RESOLVED' | |||
or 'UNRESOLVED' | |||
) | |||
firstLine:tag('span') | |||
:addClass('feedback-page-card-text') | |||
:wikitext( | |||
entry.feedback | |||
or 'No feedback provided' | |||
) | |||
local meta = | |||
content:tag('div') | |||
:addClass('feedback-page-card-meta') | |||
if entry.user | |||
and entry.user ~= '' | |||
then | |||
meta:wikitext( | |||
formatUser(entry.user) | |||
) | |||
end | end | ||
if entry.createddate | |||
and entry.createddate ~= '' | |||
then | |||
meta:wikitext( | |||
' · ' | |||
.. mw.text.nowiki( | |||
entry.createddate | |||
) | |||
) | |||
end | end | ||
if resolved then | |||
local resolvedBy = | |||
trim(entry.resolvedby) | |||
local resolvedDate = | |||
trim(entry.resolveddate) | |||
if resolvedBy ~= '' | |||
or resolvedDate ~= '' | |||
then | |||
or ' | |||
local resolution = | |||
content:tag('div') | |||
:addClass( | |||
'feedback-page-card-resolution' | |||
) | |||
resolution:wikitext( | |||
'↳ Resolved by ' | |||
) | ) | ||
if resolvedBy ~= '' then | |||
resolution:wikitext( | |||
formatUser(resolvedBy) | |||
) | |||
else | |||
resolution:wikitext( | |||
'Unknown' | |||
) | |||
end | |||
if resolvedDate ~= '' then | |||
resolution:wikitext( | |||
' · ' | |||
.. mw.text.nowiki( | |||
resolvedDate | |||
) | |||
) | |||
end | |||
end | |||
else | else | ||
if id ~= '' then | |||
renderResolveControl( | |||
root, | |||
id, | |||
true | |||
) | |||
end | |||
end | end | ||
renderAttachments( | |||
content, | |||
entry | |||
) | |||
return tostring(root) | |||
return | |||
end | end | ||
------------------------------------------------------------ | ------------------------------------------------------------ | ||
-- | -- Page feedback section | ||
------------------------------------------------------------ | ------------------------------------------------------------ | ||
function p.page(frame) | function p.page(frame) | ||
local page = | local page = | ||
currentSubjectPage() | currentSubjectPage() | ||
local | local allEntries, err = | ||
queryFeedback(page) | queryFeedback(page) | ||
if not allEntries then | |||
return '' | |||
end | |||
if #allEntries == 0 then | |||
return '' | |||
end | |||
local unresolved = {} | local unresolved = {} | ||
local resolved = {} | local resolved = {} | ||
for _, | for _, row in ipairs(allEntries) do | ||
if | |||
if row.status == 'resolved' then | |||
table.insert( | table.insert( | ||
resolved, | resolved, | ||
row | |||
) | ) | ||
else | else | ||
table.insert( | table.insert( | ||
unresolved, | unresolved, | ||
row | |||
) | ) | ||
end | end | ||
end | end | ||
| Line 663: | Line 711: | ||
local root = | local root = | ||
mw.html.create('section') | mw.html.create('section') | ||
:addClass('feedback-page-section') | |||
:attr('id', 'feedback-section') | |||
:attr( | |||
'data-unresolved-count', | |||
#unresolved | |||
) | |||
:attr( | :attr( | ||
' | 'data-resolved-count', | ||
#resolved | |||
) | ) | ||
-------------------------------------------------------- | -------------------------------------------------------- | ||
| Line 674: | Line 727: | ||
root:tag('h2') | root:tag('h2') | ||
:addClass('feedback-page- | :addClass('feedback-page-heading') | ||
:wikitext('Feedbacks') | :wikitext('Feedbacks') | ||
-------------------------------------------------------- | -------------------------------------------------------- | ||
-- | -- Filter controls | ||
-------------------------------------------------------- | -------------------------------------------------------- | ||
local filters = | local filters = | ||
root:tag('div') | root:tag('div') | ||
:addClass('feedback-filters') | :addClass('feedback-page-filters') | ||
local | local unresolvedFilter = | ||
filters:tag('span') | |||
:addClass('feedback-page-filter') | |||
:addClass( | |||
'feedback-page-filter--active' | |||
) | |||
:attr( | :attr( | ||
' | 'role', | ||
'button' | 'button' | ||
) | |||
:attr( | |||
'tabindex', | |||
'0' | |||
) | ) | ||
:attr( | :attr( | ||
'data-feedback-filter', | 'data-feedback-filter', | ||
'unresolved' | |||
) | ) | ||
unresolvedFilter:wikitext( | |||
'Unresolved' | 'Unresolved ' | ||
) | ) | ||
unresolvedFilter:tag('span') | |||
' | :addClass('feedback-page-filter-count') | ||
' | :wikitext( | ||
tostring(#unresolved) | |||
) | |||
if #resolved > 0 then | |||
local resolvedFilter = | |||
filters:tag('span') | |||
:addClass('feedback-page-filter') | |||
:attr( | |||
'role', | |||
'button' | |||
) | |||
:attr( | |||
'tabindex', | |||
'0' | |||
) | |||
:attr( | |||
'data-feedback-filter', | |||
'resolved' | |||
) | |||
resolvedFilter:wikitext( | |||
'Resolved ' | |||
) | |||
resolvedFilter:tag('span') | |||
:addClass('feedback-page-filter-count') | |||
:wikitext( | |||
tostring(#resolved) | |||
) | |||
end | |||
-------------------------------------------------------- | -------------------------------------------------------- | ||
-- Unresolved | -- Unresolved list | ||
-------------------------------------------------------- | -------------------------------------------------------- | ||
| Line 738: | Line 809: | ||
'feedback-page-list--unresolved' | 'feedback-page-list--unresolved' | ||
) | ) | ||
if #unresolved | if #unresolved > 0 then | ||
for _, row in ipairs(unresolved) do | |||
unresolvedList:node( | |||
renderCompactCard(row) | |||
for _, | |||
unresolvedList: | |||
renderCompactCard( | |||
) | ) | ||
end | end | ||
else | |||
unresolvedList:tag('div') | |||
:addClass( | :addClass( | ||
'feedback-page- | 'feedback-page-empty' | ||
) | ) | ||
: | :wikitext( | ||
'feedback | 'No unresolved feedback.' | ||
) | ) | ||
end | end | ||
-------------------------------------------------------- | -------------------------------------------------------- | ||
-- | -- Resolved list | ||
-------------------------------------------------------- | -------------------------------------------------------- | ||
local | if #resolved > 0 then | ||
local resolvedList = | |||
root:tag('div') | |||
:addClass( | |||
'feedback-page-list' | |||
) | |||
:addClass( | |||
'feedback-page-list--resolved' | |||
) | |||
for _, row in ipairs(resolved) do | |||
resolvedList:node( | |||
renderCompactCard(row) | |||
for _, | |||
renderCompactCard( | |||
) | ) | ||
end | end | ||
end | end | ||
| Line 815: | Line 858: | ||
------------------------------------------------------------ | ------------------------------------------------------------ | ||
-- | -- Feedback counts | ||
------------------------------------------------------------ | ------------------------------------------------------------ | ||
function p.counts(frame) | function p.counts(frame) | ||
local page = | |||
currentSubjectPage() | |||
local entries = | local entries = | ||
queryFeedback( | queryFeedback(page) | ||
if not entries then | |||
return '' | |||
end | |||
local unresolved = 0 | local unresolved = 0 | ||
local resolved = 0 | local resolved = 0 | ||
for _, | for _, row in ipairs(entries) do | ||
if | |||
if row.status == 'resolved' then | |||
resolved = resolved + 1 | resolved = resolved + 1 | ||
else | else | ||
unresolved = unresolved + 1 | unresolved = unresolved + 1 | ||
end | end | ||
end | end | ||
| Line 853: | Line 902: | ||
------------------------------------------------------------ | ------------------------------------------------------------ | ||
-- | -- Main / individual feedback | ||
------------------------------------------------------------ | ------------------------------------------------------------ | ||
local | function p.main(frame) | ||
return '< | local parent = | ||
frame:getParent() | |||
local args = | |||
parent and parent.args | |||
or frame.args | |||
local feedback = | |||
args.feedback | |||
or 'No feedback provided' | |||
local user = | |||
args.user | |||
or 'Anonymous' | |||
local id = | |||
trim(args.id) | |||
local createdDate = | |||
trim(args.createddate) | |||
local link = | |||
trim(args.link) | |||
local image = | |||
trim(args.image) | |||
local resolvedBy = | |||
trim(args.resolvedby) | |||
local resolvedDate = | |||
trim(args.resolveddate) | |||
local resolved = | |||
isTruthy(args.resolved) | |||
local status = | |||
resolved | |||
and 'resolved' | |||
or 'unresolved' | |||
local page = | |||
currentSubjectPage() | |||
local saved, saveError = | |||
saveFeedback({ | |||
page = page, | |||
user = user, | |||
status = status, | |||
feedback = feedback, | |||
id = id, | |||
createddate = createdDate, | |||
link = link, | |||
image = image, | |||
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 | end | ||
local table = | local card = | ||
renderFullCard({ | |||
page = page, | |||
user = user, | |||
status = status, | |||
feedback = feedback, | |||
id = id, | |||
createddate = createdDate, | |||
link = link, | |||
image = image, | |||
resolvedby = resolvedBy, | |||
resolveddate = resolvedDate | |||
}) | |||
local categories = {} | |||
if resolved then | |||
table.insert( | |||
categories, | |||
'[[Category:Resolved Feedback]]' | |||
) | |||
else | |||
table.insert( | |||
categories, | |||
'[[Category:Unresolved Feedback]]' | |||
) | |||
end | |||
if id == '' then | |||
table.insert( | |||
categories, | |||
'[[Category:Feedbacks Missing ID]]' | |||
) | |||
end | |||
return card | |||
.. table.concat(categories) | |||
end | |||
------------------------------------------------------------ | |||
-- Feedback table | |||
------------------------------------------------------------ | |||
local function renderTable(entries, includeResolved) | |||
local tableRoot = | |||
mw.html.create('table') | mw.html.create('table') | ||
:addClass('feedback-table') | :addClass('feedback-table') | ||
local | local header = | ||
tableRoot:tag('tr') | |||
if includeResolved then | |||
header:tag('th') | |||
:wikitext('Status') | |||
end | |||
header:tag('th') | |||
:wikitext('Page') | :wikitext('Page') | ||
header:tag('th') | |||
:wikitext('Username') | |||
header:tag('th') | |||
:wikitext('Date') | |||
header:tag('th') | |||
:wikitext('Feedback') | :wikitext('Feedback') | ||
if includeResolved then | |||
header:tag('th') | |||
:wikitext(' | :wikitext('Resolved by') | ||
header:tag('th') | |||
:wikitext('Resolved date') | |||
end | |||
if #entries == 0 then | |||
local row = | local row = | ||
tableRoot:tag('tr') | |||
local | local colspan = | ||
includeResolved | |||
and '7' | |||
or '4' | |||
row:tag('td') | row:tag('td') | ||
:attr( | |||
'colspan', | |||
colspan | |||
) | |||
:addClass( | :addClass( | ||
'feedback-table-empty' | |||
) | ) | ||
:wikitext( | :wikitext( | ||
'No feedback entries found.' | |||
) | ) | ||
return tostring(tableRoot) | |||
end | |||
for _, entry in ipairs(entries) do | |||
local row = | |||
tableRoot:tag('tr') | |||
:addClass( | |||
entry.status == 'resolved' | |||
and 'feedback-table-row--resolved' | |||
or 'feedback-table-row--unresolved' | |||
) | |||
if includeResolved then | |||
row:tag('td') | |||
:addClass('feedback-table-status') | |||
:wikitext( | |||
entry.status == 'resolved' | |||
and 'Resolved' | |||
or 'Unresolved' | |||
) | |||
end | |||
row:tag('td') | row:tag('td') | ||
:addClass('feedback-table-page') | :addClass('feedback-table-page') | ||
:wikitext( | :wikitext( | ||
entry.page | '[[' | ||
.. entry.page | |||
.. ']]' | |||
) | ) | ||
row:tag('td') | row:tag('td') | ||
:addClass('feedback-table- | :addClass('feedback-table-user') | ||
:wikitext( | :wikitext( | ||
entry. | formatUser(entry.user) | ||
) | ) | ||
row:tag('td') | row:tag('td') | ||
:addClass('feedback-table-date') | |||
:wikitext( | :wikitext( | ||
mw.text.nowiki( | |||
entry.createddate | |||
or '—' | |||
) | |||
) | ) | ||
row:tag('td') | row:tag('td') | ||
:addClass('feedback-table-feedback') | |||
:wikitext( | :wikitext( | ||
entry. | entry.feedback | ||
or '' | |||
) | ) | ||
if includeResolved then | |||
row:tag('td') | |||
:addClass( | |||
'feedback-table-resolved-by' | |||
) | |||
:wikitext( | |||
entry.resolvedby | |||
and formatUser( | |||
entry.resolvedby | |||
) | |||
or '—' | |||
) | |||
row:tag('td') | |||
:addClass( | |||
'feedback-table-resolved-date' | |||
) | |||
:wikitext( | |||
entry.resolveddate | |||
and mw.text.nowiki( | |||
entry.resolveddate | |||
) | |||
or '—' | |||
) | |||
end | |||
end | end | ||
return tostring( | return tostring(tableRoot) | ||
end | end | ||
------------------------------------------------------------ | |||
-- Global feedback page | |||
------------------------------------------------------------ | |||
function p.view(frame) | function p.view(frame) | ||
local parent = | local parent = | ||
frame:getParent() | frame:getParent() | ||
local args | local args = | ||
parent and parent.args | |||
or frame.args | |||
local status = | |||
trim( | |||
args.status | |||
or '' | |||
):lower() | |||
-------------------------------------------------------- | |||
-- Specific table | |||
-------------------------------------------------------- | |||
if status == 'resolved' | |||
or status == 'unresolved' | |||
then | then | ||
local entries = | |||
queryFeedback( | |||
nil, | |||
status | |||
) | |||
if not entries then | |||
return '' | |||
end | |||
return renderTable( | |||
entries, | |||
false | |||
) | |||
end | end | ||
-------------------------------------------------------- | -------------------------------------------------------- | ||
-- | -- Dashboard | ||
-------------------------------------------------------- | -------------------------------------------------------- | ||
local | local unresolved = | ||
queryFeedback( | |||
nil, | |||
'unresolved' | |||
) | |||
local all = | |||
queryFeedback( | |||
nil, | |||
'all' | |||
) | |||
if | if not unresolved then | ||
unresolved = {} | |||
end | end | ||
if not all then | |||
all = {} | |||
if not | |||
end | end | ||
local root = | |||
mw.html.create('div') | |||
:addClass('feedback-dashboard') | |||
root:tag('h2') | |||
:addClass('feedback-dashboard-heading') | |||
:wikitext('Unresolved Feedback') | |||
root:node( | |||
renderTable( | |||
unresolved, | |||
false | |||
) | ) | ||
) | |||
root:tag('h2') | |||
:addClass('feedback-dashboard-heading') | |||
:wikitext('All Feedback') | |||
root:node( | |||
renderTable( | |||
all, | |||
true | |||
) | |||
) | |||
return | return tostring(root) | ||
end | end | ||
------------------------------------------------------------ | |||
-- Aliases | |||
------------------------------------------------------------ | |||
p.table = p.view | p.table = p.view | ||
return p | return p | ||