Module:Feedback: Difference between revisions
From The Petit Planet Wiki
More actions
ReisuDesign (talk | contribs) No edit summary |
ReisuDesign (talk | contribs) Undo revision 24119 by ReisuDesign (talk) Tag: Undo |
||
| Line 1: | Line 1: | ||
local p = {} | local p = {} | ||
------------------------------------------------------------ | ------------------------------------------------------------ | ||
-- | -- Helpers | ||
------------------------------------------------------------ | ------------------------------------------------------------ | ||
local function isTruthy(value) | local function isTruthy(value) | ||
if value == nil then | if value == nil then | ||
return false | return false | ||
end | end | ||
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)) | return mw.text.trim( | ||
tostring(value or '') | |||
) | |||
end | end | ||
local function formatUser(user) | local function formatUser(user) | ||
if user == '' then | user = | ||
trim(user) | |||
if user == '' | |||
or user:lower() == 'anonymous' | |||
then | |||
return 'Anonymous' | return 'Anonymous' | ||
end | end | ||
| Line 40: | Line 50: | ||
user | user | ||
) | ) | ||
end | end | ||
local function currentSubjectPage() | local function currentSubjectPage() | ||
local title = | |||
mw.title.getCurrentTitle() | |||
return title.subjectPageTitle.fullText | |||
end | end | ||
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 | end | ||
local bucket = | |||
mw.ext.bucket('feedback') | |||
if not bucket then | |||
return nil, 'Feedback bucket could not be opened' | |||
end | |||
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) | |||
if aDate == '' | |||
and bDate ~= '' | |||
then | |||
return false | |||
end | |||
if aDate ~= '' | |||
and bDate == '' | |||
then | |||
return true | |||
end | |||
if aDate ~= bDate then | |||
return aDate > bDate | |||
end | |||
return trim(a.id) > trim(b.id) | |||
end | end | ||
) | ) | ||
return | |||
return results | |||
end | end | ||
local function queryFeedback(page) | local function queryFeedback( | ||
local bucket = getBucket() | page, | ||
status | |||
) | |||
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 | |||
local success, results = | |||
pcall( | |||
function() | |||
return query.run() | |||
end | |||
) | |||
if not success then | |||
return nil, tostring(results) | |||
end | 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 then | |||
return false, tostring(saveError) | |||
end | |||
return true | |||
end | |||
------------------------------------------------------------ | |||
-- Shared metadata | |||
------------------------------------------------------------ | |||
local function renderMetadata( | |||
root, | |||
entry | |||
) | |||
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 | ||
end | end | ||
------------------------------------------------------------ | ------------------------------------------------------------ | ||
-- | -- Attachments | ||
------------------------------------------------------------ | ------------------------------------------------------------ | ||
local function renderAttachments( | local function renderAttachments( | ||
root, | |||
entry | |||
) | |||
if link == '' and image == '' then | local link = | ||
trim(entry.link) | |||
local image = | |||
trim(entry.image) | |||
if link == '' | |||
and image == '' | |||
then | |||
return | return | ||
end | end | ||
local attachments = | local attachments = | ||
root:tag('div') | |||
:addClass('feedback-attachments') | :addClass( | ||
'feedback-attachments' | |||
) | |||
if link ~= '' then | if link ~= '' then | ||
attachments:tag(' | |||
:addClass('feedback- | attachments:tag('span') | ||
:addClass( | |||
: | 'feedback-attachment' | ||
) | |||
:wikitext( | |||
'🔗 ' .. | |||
'[' .. | |||
link .. | |||
' Link]' | |||
) | |||
end | end | ||
if image ~= '' then | if image ~= '' then | ||
attachments:tag(' | local imageAttachment = | ||
:addClass('feedback-image- | attachments:tag('span') | ||
: | :addClass( | ||
' | 'feedback-attachment' | ||
' | ) | ||
imageAttachment:tag('span') | |||
:addClass( | |||
'feedback-image-icon' | |||
) | |||
:wikitext('▣') | |||
imageAttachment:tag('span') | |||
:addClass( | |||
'feedback-image-link' | |||
) | |||
:wikitext( | |||
'[[Media:' .. | |||
image .. | |||
'|Picture]]' | |||
) | ) | ||
end | end | ||
end | end | ||
------------------------------------------------------------ | ------------------------------------------------------------ | ||
-- | -- Resolution information | ||
------------------------------------------------------------ | ------------------------------------------------------------ | ||
local function renderResolution( | local function renderResolution( | ||
local resolvedBy = trim(entry.resolvedby) | root, | ||
local resolvedDate = trim(entry.resolveddate) | entry | ||
) | |||
local resolvedBy = | |||
trim(entry.resolvedby) | |||
local resolvedDate = | |||
trim(entry.resolveddate) | |||
if resolvedBy == '' and resolvedDate == '' then | 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 ' | |||
) | |||
if resolvedBy ~= '' then | if resolvedBy ~= '' then | ||
resolution:wikitext( | resolution:wikitext( | ||
formatUser(resolvedBy) | formatUser( | ||
resolvedBy | |||
) | |||
) | ) | ||
else | else | ||
resolution:wikitext('Unknown') | |||
resolution:wikitext( | |||
'Unknown' | |||
) | |||
end | end | ||
if resolvedDate ~= '' then | if resolvedDate ~= '' then | ||
resolution:wikitext( | resolution:wikitext( | ||
' on ' .. mw.text.nowiki(resolvedDate) | ' on ' .. | ||
mw.text.nowiki( | |||
resolvedDate | |||
) | |||
) | ) | ||
end | end | ||
end | end | ||
------------------------------------------------------------ | ------------------------------------------------------------ | ||
-- | -- Resolve control | ||
------------------------------------------------------------ | ------------------------------------------------------------ | ||
| Line 202: | Line 480: | ||
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' | |||
) | ) | ||
control:attr( | |||
'data-feedback-id', | |||
id | |||
) | |||
if page | |||
and page ~= '' | |||
then | |||
control:attr( | |||
'data-feedback-page', | |||
page | |||
) | |||
end | |||
if compact then | |||
control | |||
:addClass( | |||
'feedback-resolve-button--compact' | |||
) | ) | ||
:attr( | :attr( | ||
| Line 233: | Line 532: | ||
'Resolve feedback' | 'Resolve feedback' | ||
) | ) | ||
:attr( | |||
'title', | |||
'Resolve feedback' | |||
) | |||
:wikitext( | |||
'✓' | |||
) | |||
else | |||
control | control | ||
: | :attr( | ||
' | 'role', | ||
'button' | |||
) | |||
:attr( | |||
'tabindex', | |||
'0' | |||
) | ) | ||
:attr( | :attr( | ||
' | 'aria-label', | ||
'Resolve feedback' | 'Resolve feedback' | ||
) | ) | ||
:wikitext( | :wikitext( | ||
'Resolve' | |||
) | |||
end | end | ||
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 page = | |||
trim(entry.page) | |||
local root = | local root = | ||
mw.html.create('div') | mw.html.create('div') | ||
:addClass('feedback-box') | :addClass( | ||
'feedback-box' | |||
) | |||
:addClass( | :addClass( | ||
resolved | resolved | ||
| Line 272: | Line 594: | ||
or 'feedback-box--unresolved' | or 'feedback-box--unresolved' | ||
) | ) | ||
if id ~= '' then | if id ~= '' then | ||
root:attr( | root:attr( | ||
'data-feedback-id', | 'data-feedback-id', | ||
id | id | ||
) | ) | ||
end | end | ||
-------------------------------------------------------- | -------------------------------------------------------- | ||
| Line 293: | Line 611: | ||
local main = | local main = | ||
root:tag('div') | |||
:addClass('feedback-main-line') | :addClass( | ||
'feedback-main-line' | |||
) | |||
main:tag('span') | main:tag('span') | ||
:addClass('feedback-status') | :addClass( | ||
'feedback-status' | |||
) | |||
:addClass( | :addClass( | ||
resolved | resolved | ||
| Line 309: | Line 628: | ||
: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' | ||
) | ) | ||
-------------------------------------------------------- | -------------------------------------------------------- | ||
-- | -- Inline metadata | ||
-------------------------------------------------------- | -------------------------------------------------------- | ||
local | local metadata = | ||
main:tag('span') | main:tag('span') | ||
:addClass('feedback-inline-meta') | :addClass( | ||
'feedback-inline-meta' | |||
) | |||
if entry.user | |||
and entry.user ~= '' | |||
then | |||
metadata:wikitext( | |||
' · ' .. | |||
formatUser( | |||
entry.user | |||
) | |||
) | |||
end | |||
if | 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, | |||
page, | |||
false | |||
) | ) | ||
end | end | ||
-------------------------------------------------------- | -------------------------------------------------------- | ||
| Line 350: | Line 705: | ||
renderAttachments( | renderAttachments( | ||
root, | |||
entry | entry | ||
) | ) | ||
-------------------------------------------------------- | -------------------------------------------------------- | ||
-- Resolution | -- Resolution | ||
-------------------------------------------------------- | -------------------------------------------------------- | ||
renderResolution( | if resolved then | ||
renderResolution( | |||
root, | |||
entry | |||
) | |||
end | |||
-------------------------------------------------------- | -------------------------------------------------------- | ||
-- Missing ID | -- Missing ID | ||
-------------------------------------------------------- | -------------------------------------------------------- | ||
if id == '' then | if not resolved | ||
and id == '' | |||
:addClass('feedback-missing-id') | then | ||
root:tag('div') | |||
:addClass( | |||
'feedback-missing-id' | |||
) | |||
:wikitext( | :wikitext( | ||
' | 'Add an ID to enable the Resolve button.' | ||
) | ) | ||
end | end | ||
return tostring(root) | |||
end | end | ||
------------------------------------------------------------ | ------------------------------------------------------------ | ||
-- | -- Compact article card | ||
------------------------------------------------------------ | ------------------------------------------------------------ | ||
local function renderCompactCard(entry) | local function renderCompactCard( | ||
entry | |||
) | |||
local resolved = | |||
entry.status == 'resolved' | |||
local id = | |||
trim(entry.id) | |||
local page = | |||
trim(entry.page) | |||
-- | 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 | |||
) | |||
id | |||
end | end | ||
local content = | |||
root:tag('div') | |||
: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' | |||
) | |||
-------------------------------------------------------- | |||
-- Metadata | |||
-------------------------------------------------------- | |||
local meta = | |||
content:tag('div') | |||
:addClass( | |||
'feedback-page-card-meta' | |||
) | |||
if | 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 | ||
local | -------------------------------------------------------- | ||
-- Resolution | |||
-------------------------------------------------------- | |||
if resolved then | |||
local resolvedBy = | |||
trim(entry.resolvedby) | |||
local resolvedDate = | |||
trim(entry.resolveddate) | |||
if resolvedBy ~= '' | |||
or resolvedDate ~= '' | |||
then | |||
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, | |||
page, | |||
true | |||
) | |||
end | |||
end | end | ||
-------------------------------------------------------- | |||
-- Attachments | |||
-------------------------------------------------------- | |||
renderAttachments( | |||
content, | |||
entry | |||
) | ) | ||
return tostring(root) | |||
end | end | ||
------------------------------------------------------------ | ------------------------------------------------------------ | ||
-- | -- Page feedback section | ||
------------------------------------------------------------ | ------------------------------------------------------------ | ||
function p.page(frame) | function p.page(frame) | ||
local page = | local page = | ||
currentSubjectPage() | currentSubjectPage() | ||
local | |||
queryFeedback(page) | local allEntries = | ||
queryFeedback( | |||
page | |||
) | |||
if not allEntries then | |||
return '' | |||
end | |||
if #allEntries == 0 then | |||
return '' | |||
end | |||
local unresolved = {} | local unresolved = {} | ||
local resolved = {} | local resolved = {} | ||
for _, | |||
if | for _, row in ipairs(allEntries) do | ||
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 | ||
local root = | local root = | ||
mw.html.create('section') | mw.html.create('section') | ||
:addClass( | |||
'feedback-page-section' | |||
) | |||
:attr( | :attr( | ||
'id', | 'id', | ||
'feedback-section' | 'feedback-section' | ||
) | ) | ||
: | :attr( | ||
'data-unresolved-count', | |||
#unresolved | |||
) | |||
:attr( | |||
'data-resolved-count', | |||
#resolved | |||
) | |||
-------------------------------------------------------- | -------------------------------------------------------- | ||
| Line 658: | Line 1,034: | ||
root:tag('h2') | root:tag('h2') | ||
:addClass('feedback-page- | :addClass( | ||
:wikitext('Feedbacks') | 'feedback-page-heading' | ||
) | |||
:wikitext( | |||
'Feedbacks' | |||
) | |||
-------------------------------------------------------- | -------------------------------------------------------- | ||
| Line 667: | Line 1,048: | ||
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' | |||
) | ) | ||
:addClass('feedback-filter') | |||
unresolvedFilter:wikitext( | |||
'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( | :addClass( | ||
'feedback-page-filter-count' | |||
) | |||
:wikitext( | |||
tostring( | |||
#resolved | |||
) | |||
) | ) | ||
end | end | ||
-------------------------------------------------------- | -------------------------------------------------------- | ||
-- Unresolved | -- Unresolved list | ||
-------------------------------------------------------- | -------------------------------------------------------- | ||
| Line 722: | Line 1,142: | ||
'feedback-page-list--unresolved' | 'feedback-page-list--unresolved' | ||
) | ) | ||
: | |||
if #unresolved > 0 then | |||
for _, row in ipairs(unresolved) do | |||
unresolvedList:node( | |||
renderCompactCard( | |||
row | |||
) | |||
) | ) | ||
end | |||
else | |||
unresolvedList:tag('div') | unresolvedList:tag('div') | ||
:addClass('feedback-empty') | :addClass( | ||
'feedback-page-empty' | |||
) | |||
:wikitext( | :wikitext( | ||
'No unresolved feedback.' | 'No unresolved feedback.' | ||
) | ) | ||
end | end | ||
-------------------------------------------------------- | -------------------------------------------------------- | ||
-- Resolved | -- Resolved list | ||
-------------------------------------------------------- | -------------------------------------------------------- | ||
local resolvedList = | 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 | ||
) | |||
) | ) | ||
end | end | ||
end | end | ||
return tostring(root) | return tostring(root) | ||
end | end | ||
------------------------------------------------------------ | ------------------------------------------------------------ | ||
-- | -- 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 _, | |||
if | for _, row in ipairs(entries) do | ||
if row.status == 'resolved' then | |||
resolved = resolved + 1 | resolved = resolved + 1 | ||
else | else | ||
unresolved = unresolved + 1 | unresolved = unresolved + 1 | ||
end | end | ||
end | end | ||
return tostring( | return tostring( | ||
mw.html.create('span') | mw.html.create('span') | ||
:addClass('feedback-count-data') | :addClass( | ||
'feedback-count-data' | |||
) | |||
:attr( | :attr( | ||
'data-unresolved', | 'data-unresolved', | ||
| Line 832: | Line 1,253: | ||
resolved | resolved | ||
) | ) | ||
) | ) | ||
end | end | ||
------------------------------------------------------------ | ------------------------------------------------------------ | ||
-- | -- 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 header = | |||
tableRoot:tag('tr') | |||
if includeResolved then | |||
header:tag('th') | |||
:wikitext( | |||
'Status' | |||
) | |||
end | |||
header:tag('th') | |||
:wikitext( | |||
'Page' | |||
) | |||
header:tag('th') | |||
:wikitext( | |||
'Username' | |||
) | |||
header:tag('th') | |||
:wikitext( | |||
'Date' | |||
) | |||
header:tag('th') | |||
:wikitext( | |||
'Feedback' | |||
) | |||
if includeResolved then | |||
header:tag('th') | |||
:wikitext( | |||
'Resolved by' | |||
) | |||
header:tag('th') | |||
:wikitext( | |||
'Resolved date' | |||
) | |||
end | |||
if #entries == 0 then | |||
local row = | local row = | ||
tableRoot:tag('tr') | |||
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 = | |||
and | parent | ||
and parent.args | |||
or frame.args | |||
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 | |||
end | |||
return renderTable( | |||
entries, | |||
false | |||
) | |||
end | end | ||
-------------------------------------------------------- | -------------------------------------------------------- | ||
-- | -- Dashboard | ||
-------------------------------------------------------- | -------------------------------------------------------- | ||
local | local unresolved = | ||
queryFeedback( | |||
nil, | |||
'unresolved' | |||
) | |||
local all = | |||
queryFeedback( | |||
nil, | |||
'all' | |||
) | ) | ||
if not unresolved then | |||
unresolved = {} | |||
end | end | ||
if not | if not all then | ||
all = {} | |||
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 tostring( | |||
root | |||
) | |||
end | end | ||
------------------------------------------------------------ | |||
-- Aliases | |||
------------------------------------------------------------ | |||
p.table = p.view | p.table = p.view | ||
return p | return p | ||