| Latest revision |
Your text |
| Line 2: |
Line 2: |
|
| |
|
| ------------------------------------------------------------ | | ------------------------------------------------------------ |
| -- HELPERS | | -- Helpers |
| ------------------------------------------------------------ | | ------------------------------------------------------------ |
|
| |
|
| local function isTruthy(value) | | local function isTruthy(v) |
| if value == nil then
| | if v == nil then |
| return false
| | return false |
| end
| | end |
|
| |
|
| value = mw.text.trim(tostring(value)):lower()
| | v = mw.text.trim(tostring(v)):lower() |
|
| |
|
| return value == 'true'
| | return v ~= '' |
| or value == 'yes'
| | and v ~= '0' |
| or value == '1'
| | and v ~= 'false' |
| or value == 'resolved'
| | and v ~= 'no' |
| | and v ~= 'off' |
| end | | end |
|
| |
|
|
| |
|
| local function trim(value) | | local function formatUser(user) |
| if value == nil then
| | user = mw.text.trim(tostring(user or '')) |
| return ''
| |
| end
| |
|
| |
|
| return mw.text.trim(tostring(value))
| | if user == '' or user:lower() == 'anonymous' then |
| | return 'Anonymous' |
| | end |
| | |
| | return string.format( |
| | '[[User:%s|%s]]', |
| | user, |
| | user |
| | ) |
| end | | end |
|
| |
|
|
| |
|
| local function formatUser(user) | | ------------------------------------------------------------ |
| user = trim(user)
| | -- 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 root = mw.html.create('div') |
| | :addClass('feedback-box') |
| | :addClass( |
| | resolved |
| | and 'feedback-box--resolved' |
| | or 'feedback-box--unresolved' |
| | ) |
| | |
| | |
| | -------------------------------------------------------- |
| | -- Metadata |
| | -------------------------------------------------------- |
|
| |
|
| if user == '' then
| | local meta = root:tag('div') |
| return 'Anonymous'
| | :addClass('feedback-meta') |
| end
| |
|
| |
|
| return string.format(
| |
| '[[User:%s|%s]]',
| |
| user,
| |
| user
| |
| )
| |
| end
| |
|
| |
|
| | if page and page ~= '' then |
|
| |
|
| local function currentSubjectPage()
| | meta:tag('span') |
| local title = mw.title.getCurrentTitle()
| | :addClass('feedback-page') |
| | :wikitext( |
| | string.format('[[%s]]', page) |
| | ) |
|
| |
|
| if title.subjectPageTitle then
| | meta:tag('span') |
| return title.subjectPageTitle.fullText
| | :addClass('feedback-separator') |
| end
| | :wikitext(' • ') |
|
| |
|
| return title.fullText
| | end |
| end | |
|
| |
|
|
| |
|
| local function getBucket()
| | meta:tag('span') |
| if not (mw.ext and mw.ext.bucket) then
| | :addClass('feedback-user') |
| return nil
| | :wikitext(formatUser(user)) |
| end
| |
|
| |
|
| return mw.ext.bucket('feedback')
| |
| end
| |
|
| |
|
| | meta:tag('span') |
| | :addClass('feedback-separator') |
| | :wikitext(' • ') |
|
| |
|
| local function sortNewestFirst(entries)
| |
| table.sort(
| |
| entries,
| |
| function(a, b)
| |
| local aDate = trim(a.createddate)
| |
| local bDate = trim(b.createddate)
| |
|
| |
|
| return aDate > bDate
| | meta:tag('span') |
| end
| | :addClass('feedback-status') |
| )
| | :addClass( |
| | resolved |
| | and 'feedback-status--resolved' |
| | or 'feedback-status--unresolved' |
| | ) |
| | :wikitext( |
| | resolved |
| | and 'Resolved' |
| | or 'Unresolved' |
| | ) |
|
| |
|
| return entries
| |
| end
| |
|
| |
|
| | -------------------------------------------------------- |
| | -- Feedback text |
| | -------------------------------------------------------- |
|
| |
|
| local function queryFeedback(page)
| | root:tag('div') |
| local bucket = getBucket()
| | :addClass('feedback-body') |
| | :wikitext(feedback) |
|
| |
|
| if not bucket then
| |
| return {}
| |
| end
| |
|
| |
|
| local query = bucket
| | -------------------------------------------------------- |
| | -- Resolution instruction |
| | -------------------------------------------------------- |
|
| |
|
| query.select(
| | if showInstruction and not resolved then |
| 'page',
| |
| 'user',
| |
| 'status',
| |
| 'feedback',
| |
| 'id',
| |
| 'createddate',
| |
| 'link',
| |
| 'image',
| |
| 'resolvedby',
| |
| 'resolveddate'
| |
| )
| |
|
| |
|
| query.where(
| | root:tag('div') |
| 'page',
| | :addClass('feedback-instruction') |
| page
| | :wikitext( |
| )
| | 'If this feedback has been resolved, edit this page ' |
| | .. 'and set <code>|resolved=true</code>.' |
| | ) |
|
| |
|
| local success, results = pcall(function()
| | end |
| return query.run()
| |
| end)
| |
|
| |
|
| if not success or not results then
| |
| return {}
| |
| end
| |
|
| |
|
| return sortNewestFirst(results)
| | return tostring(root) |
| end | | end |
|
| |
|
|
| |
|
| ------------------------------------------------------------ | | ------------------------------------------------------------ |
| -- ATTACHMENTS | | -- Save feedback |
| ------------------------------------------------------------ | | ------------------------------------------------------------ |
|
| |
|
| local function renderAttachments(entry) | | local function saveFeedback(data) |
| local wrapper =
| | |
| mw.html.create('div')
| | if not (mw.ext and mw.ext.bucket) then |
| :addClass('feedback-attachments')
| | return false |
| | end |
|
| |
|
| local link = trim(entry.link)
| | local bucket = mw.ext.bucket('feedback') |
|
| |
|
| if link ~= '' then
| | if not bucket then |
| local linkWrapper =
| | return false |
| wrapper:tag('span')
| | end |
| :addClass('feedback-attachment-link')
| |
|
| |
| linkWrapper:tag('span')
| |
| :addClass('feedback-attachment-icon')
| |
|
| |
| linkWrapper:wikitext(
| |
| '[' .. link .. ' ' .. mw.text.nowiki(link) .. ']'
| |
| )
| |
| end
| |
|
| |
|
| local image = trim(entry.image)
| |
|
| |
|
| if image ~= '' then
| | local success = pcall(function() |
| image = mw.ustring.gsub(
| |
| image,
| |
| '^File:',
| |
| ''
| |
| )
| |
|
| |
|
| local title =
| | bucket.put({ |
| mw.title.new('File:' .. image)
| | page = data.page, |
| | user = data.user, |
| | status = data.status, |
| | feedback = data.feedback |
| | }) |
|
| |
|
| if title then
| | end) |
| local imageWrapper =
| |
| wrapper:tag('span')
| |
| :addClass('feedback-attachment-image')
| |
|
| |
| imageWrapper:tag('span')
| |
| :addClass('feedback-attachment-icon')
| |
|
| |
| imageWrapper:wikitext(
| |
| '[' ..
| |
| title:fullUrl() ..
| |
| ' ' ..
| |
| mw.text.nowiki(image) ..
| |
| ']'
| |
| )
| |
| end
| |
| end
| |
|
| |
|
| return wrapper
| | |
| | return success |
| end | | end |
|
| |
|
|
| |
|
| ------------------------------------------------------------ | | ------------------------------------------------------------ |
| -- RESOLUTION | | -- Main |
| | -- |
| | -- Used by Template:Feedback |
| | -- |
| | -- Example: |
| | -- |
| | -- {{Feedback |
| | -- |feedback=Something could be improved here. |
| | -- |user=Rei |
| | -- |resolved=false |
| | -- }} |
| ------------------------------------------------------------ | | ------------------------------------------------------------ |
|
| |
|
| local function renderResolution(parent, entry)
| | function p.main(frame) |
| local resolvedBy = trim(entry.resolvedby)
| |
| local resolvedDate = trim(entry.resolveddate)
| |
|
| |
|
| if resolvedBy == '' and resolvedDate == '' then
| | local parent = frame:getParent() |
| return
| |
| end
| |
|
| |
|
| local resolution =
| | local args = |
| parent:tag('div')
| | parent and parent.args |
| :addClass('feedback-resolution')
| | or frame.args |
|
| |
|
| resolution:wikitext('Resolved by ')
| |
|
| |
|
| if resolvedBy ~= '' then
| | -------------------------------------------------------- |
| resolution:wikitext(
| | -- Get page title |
| formatUser(resolvedBy)
| | -------------------------------------------------------- |
| )
| |
| else
| |
| resolution:wikitext('Unknown')
| |
| end
| |
|
| |
|
| if resolvedDate ~= '' then
| | local pageTitle = nil |
| resolution:wikitext(
| | |
| ' on ' .. mw.text.nowiki(resolvedDate)
| | if parent and parent.getTitle then |
| )
| |
| end
| |
| end
| |
|
| |
|
| | local title = parent:getTitle() |
|
| |
|
| ------------------------------------------------------------
| | if title |
| -- RESOLVE CONTROL
| | and title ~= '' |
| ------------------------------------------------------------
| | and not title:find('^Template:') |
| | then |
| | pageTitle = title |
| | end |
|
| |
|
| local function renderResolveControl(
| | end |
| parent,
| |
| id,
| |
| page,
| |
| compact
| |
| )
| |
| if trim(id) == '' then
| |
| return
| |
| end
| |
|
| |
|
| local wrapper =
| |
| parent:tag('div')
| |
| :addClass('feedback-resolve')
| |
|
| |
|
| local control =
| | return p._main(args, pageTitle) |
| wrapper:tag('span')
| |
| :addClass('feedback-resolve-button')
| |
| :attr(
| |
| 'data-feedback-id',
| |
| id
| |
| )
| |
| :attr(
| |
| 'data-feedback-page',
| |
| page or ''
| |
| )
| |
| :attr(
| |
| 'role',
| |
| 'button'
| |
| )
| |
| :attr(
| |
| 'tabindex',
| |
| '0'
| |
| )
| |
| :attr(
| |
| 'aria-label',
| |
| 'Resolve feedback'
| |
| )
| |
|
| |
|
| if compact then
| |
| control
| |
| :addClass(
| |
| 'feedback-resolve-button--compact'
| |
| )
| |
| :attr(
| |
| 'title',
| |
| 'Resolve feedback'
| |
| )
| |
| :wikitext('✓')
| |
| else
| |
| control:wikitext('Resolve')
| |
| end
| |
| end | | end |
|
| |
|
|
| |
|
| ------------------------------------------------------------
| | function p._main(args, pageTitle) |
| -- FULL FEEDBACK CARD
| | |
| ------------------------------------------------------------
| | local feedback = |
| | args.feedback |
| | or 'No feedback provided' |
| | |
| | |
| | local user = |
| | args.user |
| | or 'Anonymous' |
| | |
|
| |
|
| local function renderFullCard(entry)
| | local resolved = |
| local resolved =
| | isTruthy(args.resolved) |
| trim(entry.status):lower() == 'resolved'
| |
|
| |
|
| local id = trim(entry.id)
| |
| local page = trim(entry.page)
| |
| local feedback = trim(entry.feedback)
| |
| local user = trim(entry.user)
| |
| local createddate = trim(entry.createddate)
| |
|
| |
|
| local root =
| | local status = |
| mw.html.create('div')
| | resolved |
| :addClass('feedback-box')
| | and 'resolved' |
| :addClass(
| | or 'unresolved' |
| resolved
| |
| and 'feedback-box--resolved'
| |
| or 'feedback-box--unresolved'
| |
| )
| |
|
| |
|
| if id ~= '' then
| |
| root:attr(
| |
| 'data-feedback-id',
| |
| id
| |
| )
| |
| end
| |
|
| |
|
| --------------------------------------------------------
| | local currentPage = |
| -- Main content column
| | pageTitle |
| --------------------------------------------------------
| | or mw.title.getCurrentTitle().fullText |
|
| |
|
| local content =
| |
| root:tag('div')
| |
| :addClass('feedback-content')
| |
|
| |
|
| --------------------------------------------------------
| | -------------------------------------------------------- |
| -- Main line
| | -- Save to Bucket |
| --------------------------------------------------------
| | -------------------------------------------------------- |
|
| |
|
| local main =
| | saveFeedback({ |
| content:tag('div')
| | page = currentPage, |
| :addClass('feedback-main-line')
| | user = user, |
| | status = status, |
| | feedback = feedback |
| | }) |
|
| |
|
| --------------------------------------------------------
| |
| -- Status
| |
| --------------------------------------------------------
| |
|
| |
|
| main:tag('span')
| | -------------------------------------------------------- |
| :addClass('feedback-status')
| | -- Render the feedback card |
| :addClass(
| | -------------------------------------------------------- |
| resolved
| |
| and 'feedback-status--resolved'
| |
| or 'feedback-status--unresolved'
| |
| )
| |
| :wikitext(
| |
| resolved
| |
| and 'Resolved'
| |
| or 'Unresolved'
| |
| )
| |
|
| |
|
| --------------------------------------------------------
| | local card = renderCard({ |
| -- Feedback text
| |
| --------------------------------------------------------
| |
|
| |
|
| main:tag('span')
| | page = nil, |
| :addClass('feedback-text')
| |
| :wikitext(
| |
| feedback ~= ''
| |
| and feedback
| |
| or 'No feedback provided'
| |
| )
| |
|
| |
|
| --------------------------------------------------------
| | user = user, |
| -- Metadata
| |
| --------------------------------------------------------
| |
|
| |
|
| local meta =
| | status = status, |
| main:tag('span')
| |
| :addClass('feedback-inline-meta')
| |
|
| |
|
| if user ~= '' then
| | feedback = feedback |
| meta:wikitext(
| |
| ' · ' .. formatUser(user)
| |
| )
| |
| end
| |
|
| |
|
| if createddate ~= '' then
| | }, true) |
| meta:wikitext(
| |
| ' · ' .. mw.text.nowiki(createddate)
| |
| )
| |
| end
| |
|
| |
|
| --------------------------------------------------------
| |
| -- Attachments
| |
| --------------------------------------------------------
| |
|
| |
| content:node(
| |
| renderAttachments(entry)
| |
| )
| |
|
| |
|
| --------------------------------------------------------
| | -------------------------------------------------------- |
| -- Resolution information
| | -- Categorize feedback |
| --------------------------------------------------------
| | -------------------------------------------------------- |
|
| |
|
| renderResolution(
| | local category |
| content,
| |
| entry
| |
| )
| |
|
| |
|
| --------------------------------------------------------
| | if resolved then |
| -- Missing ID warning
| |
| --------------------------------------------------------
| |
|
| |
|
| if id == '' then
| | category = |
| content:tag('div')
| | '[[Category:Resolved Feedback]]' |
| :addClass('feedback-missing-id')
| |
| :wikitext(
| |
| 'This feedback entry is missing an ID.'
| |
| )
| |
| end
| |
|
| |
|
| --------------------------------------------------------
| | else |
| -- Resolve button
| |
| --
| |
| -- IMPORTANT:
| |
| -- This is outside .feedback-content so it
| |
| -- remains on the right.
| |
| --------------------------------------------------------
| |
|
| |
|
| if not resolved then
| | category = |
| renderResolveControl(
| | '[[Category:Unresolved Feedback]]' |
| root,
| |
| id,
| |
| page,
| |
| false
| |
| )
| |
| end
| |
|
| |
|
| return tostring(root)
| | end |
| end | |
|
| |
|
|
| |
|
| ------------------------------------------------------------
| | return card .. category |
| -- COMPACT CARD
| |
| ------------------------------------------------------------
| |
|
| |
|
| local function renderCompactCard(entry)
| |
| return renderFullCard(entry)
| |
| end | | end |
|
| |
|
|
| |
|
| ------------------------------------------------------------ | | ------------------------------------------------------------ |
| -- SAVE FEEDBACK | | -- Render feedback list |
| ------------------------------------------------------------ | | ------------------------------------------------------------ |
|
| |
|
| local function saveFeedback(data) | | local function renderFeedbackList(results) |
| local bucket = getBucket()
| |
|
| |
|
| if not bucket then
| | if not results or #results == 0 then |
| return false, 'Bucket extension is not available'
| | return '<em>No feedback entries found.</em>' |
| end
| | end |
|
| |
|
| local success, err = 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
| | local list = {} |
| return false, tostring(err)
| |
| end
| |
|
| |
|
| return true
| |
| end
| |
|
| |
|
| |
| ------------------------------------------------------------
| |
| -- MAIN
| |
| --
| |
| -- Used by Template:Feedback
| |
| ------------------------------------------------------------
| |
|
| |
|
| function p.main(frame)
| | for _, row in ipairs(results) do |
| local parent = frame:getParent()
| |
|
| |
|
| local args =
| | table.insert( |
| parent and parent.args
| | list, |
| or frame.args
| | renderCard(row, false) |
| | ) |
|
| |
|
| local pageTitle = nil
| | end |
|
| |
|
| if parent and parent.getTitle then
| |
| local title = parent:getTitle()
| |
|
| |
|
| if title
| | return table.concat(list, '\n') |
| and title ~= ''
| |
| and not title:find('^Template:')
| |
| then
| |
| pageTitle = title
| |
| end
| |
| end
| |
|
| |
|
| return p._main(
| |
| args,
| |
| pageTitle
| |
| )
| |
| end | | end |
|
| |
|
|
| |
|
| function p._main(args, pageTitle)
| | ------------------------------------------------------------ |
| local feedback =
| | -- View feedback |
| trim(args.feedback)
| | -- |
| | -- Examples: |
| | -- |
| | -- {{#invoke:Feedback|view}} |
| | -- |
| | -- {{#invoke:Feedback|view|status=all}} |
| | -- |
| | -- {{#invoke:Feedback|view|status=resolved}} |
| | -- |
| | -- {{#invoke:Feedback|view|status=unresolved}} |
| | ------------------------------------------------------------ |
|
| |
|
| if feedback == '' then
| | function p.view(frame) |
| feedback = 'No feedback provided'
| |
| end
| |
|
| |
|
| local user =
| | local parent = frame:getParent() |
| trim(args.user)
| |
|
| |
|
| if user == '' then
| |
| user = 'Anonymous'
| |
| end
| |
|
| |
|
| local resolved =
| | local args |
| isTruthy(args.resolved)
| |
|
| |
|
| local status =
| | if frame |
| resolved
| | and frame.args |
| and 'resolved'
| | and frame.args.status |
| or 'unresolved'
| | then |
|
| |
|
| local currentPage =
| | args = frame.args |
| trim(pageTitle)
| |
|
| |
|
| if currentPage == '' then
| | elseif parent |
| currentPage =
| | and parent.args |
| mw.title.getCurrentTitle().fullText
| | and parent.args.status |
| end
| | then |
|
| |
|
| local id =
| | args = parent.args |
| trim(args.id)
| |
|
| |
|
| local createddate =
| | elseif frame |
| trim(args.createddate)
| | and frame.args |
| | then |
|
| |
|
| local link =
| | args = frame.args |
| trim(args.link)
| |
|
| |
|
| local image =
| | elseif parent |
| trim(args.image)
| | and parent.args |
| | then |
|
| |
|
| local resolvedby =
| | args = parent.args |
| trim(args.resolvedby)
| |
|
| |
|
| local resolveddate =
| | else |
| trim(args.resolveddate)
| |
|
| |
|
| --------------------------------------------------------
| | args = {} |
| -- Save to Bucket
| |
| --------------------------------------------------------
| |
|
| |
|
| local saved, saveError =
| | end |
| saveFeedback({
| |
| page = currentPage,
| |
| 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
| |
|
| |
|
| --------------------------------------------------------
| | return p._view(args, frame) |
| -- Render
| |
| --------------------------------------------------------
| |
|
| |
|
| local card =
| | end |
| renderFullCard({
| |
| page = currentPage,
| |
| user = user,
| |
| status = status,
| |
| feedback = feedback,
| |
| id = id,
| |
| createddate = createddate,
| |
| link = link,
| |
| image = image,
| |
| resolvedby = resolvedby,
| |
| resolveddate = resolveddate
| |
| })
| |
|
| |
|
| --------------------------------------------------------
| |
| -- Categories
| |
| --------------------------------------------------------
| |
|
| |
|
| local category
| | function p._view(args, frame) |
|
| |
|
| if resolved then
| | -------------------------------------------------------- |
| category =
| | -- Check Bucket |
| '[[Category:Resolved Feedback]]'
| | -------------------------------------------------------- |
| else
| |
| category =
| |
| '[[Category:Unresolved Feedback]]'
| |
| end
| |
|
| |
|
| if id == '' then
| | if not (mw.ext and mw.ext.bucket) then |
| category =
| |
| category ..
| |
| '[[Category:Feedbacks Missing ID]]'
| |
| end
| |
|
| |
|
| return card .. category
| | return |
| end
| | '<em>Bucket extension is not available.</em>' |
|
| |
|
| | end |
|
| |
|
| ------------------------------------------------------------
| |
| -- RENDER FEEDBACK LIST
| |
| ------------------------------------------------------------
| |
|
| |
|
| local function renderFeedbackList(results)
| | frame = frame or mw.getCurrentFrame() |
| 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(
| | -- Determine requested status |
| list,
| | -------------------------------------------------------- |
| renderFullCard(row)
| |
| )
| |
| end
| |
|
| |
|
| return table.concat(
| | local rawStatus = |
| list,
| | args.status |
| '\n'
| | or args[1] |
| )
| |
| end
| |
|
| |
|
|
| |
|
| ------------------------------------------------------------
| | local filterStatus = |
| -- PAGE FEEDBACK
| | rawStatus |
| ------------------------------------------------------------
| | and mw.text.trim(rawStatus):lower() |
| | or nil |
|
| |
|
| function p.page(frame)
| |
| local page =
| |
| currentSubjectPage()
| |
|
| |
|
| local entries =
| | -------------------------------------------------------- |
| queryFeedback(page)
| | -- Specific status |
| | -------------------------------------------------------- |
|
| |
|
| local unresolved = {}
| | if filterStatus == 'resolved' |
| local resolved = {}
| | or filterStatus == 'unresolved' |
| | then |
|
| |
|
| for _, entry in ipairs(entries) do
| | local query = |
| if trim(entry.status):lower()
| | mw.ext.bucket('feedback') |
| == 'resolved'
| |
| then
| |
| table.insert(
| |
| resolved,
| |
| entry
| |
| )
| |
| else
| |
| table.insert(
| |
| unresolved,
| |
| entry
| |
| )
| |
| end
| |
| end
| |
|
| |
|
| local root =
| |
| mw.html.create('section')
| |
| :attr(
| |
| 'id',
| |
| 'feedback-section'
| |
| )
| |
| :addClass('feedback-page')
| |
|
| |
|
| --------------------------------------------------------
| | query.select( |
| -- Heading
| | 'page', |
| --------------------------------------------------------
| | 'user', |
| | 'status', |
| | 'feedback' |
| | ) |
|
| |
|
| root:tag('h2')
| |
| :addClass('feedback-page-title')
| |
| :wikitext('Feedbacks')
| |
|
| |
|
| --------------------------------------------------------
| | query.where( |
| -- Filters
| | 'status', |
| --------------------------------------------------------
| | filterStatus |
| | ) |
|
| |
|
| local filters =
| |
| root:tag('div')
| |
| :addClass('feedback-filters')
| |
|
| |
|
| local function addFilter(
| | return renderFeedbackList( |
| label,
| | query.run() |
| value,
| | ) |
| active
| |
| )
| |
| return filters:tag('button')
| |
| :attr(
| |
| 'type',
| |
| 'button'
| |
| )
| |
| :attr(
| |
| 'data-feedback-filter',
| |
| value
| |
| )
| |
| :addClass('feedback-filter')
| |
| :addClass(
| |
| active
| |
| and 'feedback-filter--active'
| |
| or nil
| |
| )
| |
| :wikitext(label)
| |
| end
| |
|
| |
|
| addFilter(
| | end |
| 'Unresolved',
| |
| 'unresolved',
| |
| true
| |
| )
| |
|
| |
|
| addFilter(
| |
| 'Resolved',
| |
| 'resolved',
| |
| false
| |
| )
| |
|
| |
|
| addFilter(
| | -------------------------------------------------------- |
| 'All',
| | -- All feedback |
| 'all',
| | -------------------------------------------------------- |
| false
| |
| )
| |
|
| |
|
| --------------------------------------------------------
| | if filterStatus == 'all' then |
| -- Unresolved
| |
| --------------------------------------------------------
| |
|
| |
|
| local unresolvedList =
| | local query = |
| root:tag('div')
| | mw.ext.bucket('feedback') |
| :addClass(
| |
| 'feedback-page-list'
| |
| )
| |
| :addClass(
| |
| 'feedback-page-list--unresolved'
| |
| )
| |
| :addClass(
| |
| 'feedback-page-list--visible'
| |
| )
| |
|
| |
|
| if #unresolved == 0 then
| |
| unresolvedList:tag('div')
| |
| :addClass('feedback-empty')
| |
| :wikitext(
| |
| 'No unresolved feedback.'
| |
| )
| |
| else
| |
| for _, entry in ipairs(unresolved) do
| |
| unresolvedList:wikitext(
| |
| renderCompactCard(entry)
| |
| )
| |
| end
| |
| end
| |
|
| |
|
| --------------------------------------------------------
| | query.select( |
| -- Resolved
| | 'page', |
| --------------------------------------------------------
| | 'user', |
| | 'status', |
| | 'feedback' |
| | ) |
|
| |
|
| local resolvedList =
| |
| root:tag('div')
| |
| :addClass(
| |
| 'feedback-page-list'
| |
| )
| |
| :addClass(
| |
| 'feedback-page-list--resolved'
| |
| )
| |
|
| |
|
| if #resolved == 0 then
| | return renderFeedbackList( |
| resolvedList:tag('div')
| | query.run() |
| :addClass('feedback-empty')
| | ) |
| :wikitext(
| |
| 'No resolved feedback.'
| |
| )
| |
| else
| |
| for _, entry in ipairs(resolved) do
| |
| resolvedList:wikitext(
| |
| renderCompactCard(entry)
| |
| )
| |
| end
| |
| end
| |
|
| |
|
| --------------------------------------------------------
| | end |
| -- All
| |
| --------------------------------------------------------
| |
|
| |
|
| local allList =
| |
| root:tag('div')
| |
| :addClass(
| |
| 'feedback-page-list'
| |
| )
| |
| :addClass(
| |
| 'feedback-page-list--all'
| |
| )
| |
|
| |
|
| if #entries == 0 then
| | -------------------------------------------------------- |
| allList:tag('div')
| | -- Tabber mode |
| :addClass('feedback-empty')
| | -- |
| :wikitext(
| | -- Default: |
| 'No feedback.'
| | -- |
| )
| | -- All |
| else
| | -- Unresolved |
| for _, entry in ipairs(entries) do
| | -- Resolved |
| allList:wikitext(
| | -------------------------------------------------------- |
| renderCompactCard(entry)
| |
| )
| |
| end
| |
| end
| |
|
| |
|
| return tostring(root)
| | local qAll = |
| end
| | mw.ext.bucket('feedback') |
|
| |
|
|
| |
|
| ------------------------------------------------------------
| | qAll.select( |
| -- COUNTS
| | 'page', |
| ------------------------------------------------------------
| | 'user', |
| | 'status', |
| | 'feedback' |
| | ) |
|
| |
|
| function p.counts(frame)
| |
| local entries =
| |
| queryFeedback(
| |
| currentSubjectPage()
| |
| )
| |
|
| |
|
| local unresolved = 0
| | local allEntries = |
| local resolved = 0
| | qAll.run() |
|
| |
|
| for _, entry in ipairs(entries) do
| |
| if trim(entry.status):lower()
| |
| == 'resolved'
| |
| then
| |
| resolved = resolved + 1
| |
| else
| |
| unresolved = unresolved + 1
| |
| end
| |
| end
| |
|
| |
|
| return tostring(
| | local allList = {} |
| mw.html.create('span')
| | local unresolvedList = {} |
| :addClass('feedback-count-data')
| | local resolvedList = {} |
| :attr(
| |
| 'data-unresolved',
| |
| unresolved
| |
| )
| |
| :attr(
| |
| 'data-resolved',
| |
| resolved
| |
| )
| |
| )
| |
| end
| |
|
| |
|
|
| |
|
| ------------------------------------------------------------
| | -------------------------------------------------------- |
| -- TABLE / DASHBOARD | | -- Split entries by status |
| ------------------------------------------------------------
| | -------------------------------------------------------- |
|
| |
|
| local function renderTable(entries)
| | if allEntries and #allEntries > 0 then |
| if not entries or #entries == 0 then
| |
| return '<em>No feedback entries found.</em>'
| |
| end
| |
|
| |
|
| local table =
| | for _, row in ipairs(allEntries) do |
| mw.html.create('table')
| |
| :addClass('feedback-table')
| |
|
| |
|
| local head =
| | local card = |
| table:tag('thead')
| | renderCard(row, false) |
| :tag('tr')
| |
|
| |
|
| head:tag('th')
| |
| :wikitext('Status')
| |
|
| |
|
| head:tag('th')
| | table.insert( |
| :wikitext('Page')
| | allList, |
| | card |
| | ) |
|
| |
|
| head:tag('th')
| |
| :wikitext('Feedback')
| |
|
| |
|
| head:tag('th')
| | if row.status == 'resolved' then |
| :wikitext('User')
| |
|
| |
|
| head:tag('th')
| | table.insert( |
| :wikitext('Date')
| | resolvedList, |
| | card |
| | ) |
|
| |
|
| local body =
| | else |
| table:tag('tbody')
| |
|
| |
|
| for _, entry in ipairs(entries) do
| | table.insert( |
| local row =
| | unresolvedList, |
| body:tag('tr')
| | card |
| | ) |
|
| |
|
| local resolved =
| | end |
| trim(entry.status):lower()
| |
| == 'resolved'
| |
|
| |
|
| row:tag('td')
| | end |
| :addClass(
| |
| resolved
| |
| and 'feedback-table-status--resolved'
| |
| or 'feedback-table-status--unresolved'
| |
| )
| |
| :wikitext(
| |
| resolved
| |
| and 'Resolved'
| |
| or 'Unresolved'
| |
| )
| |
|
| |
|
| row:tag('td')
| | end |
| :addClass('feedback-table-page')
| |
| :wikitext(
| |
| entry.page or ''
| |
| )
| |
|
| |
|
| row:tag('td')
| |
| :addClass('feedback-table-text')
| |
| :wikitext(
| |
| entry.feedback or ''
| |
| )
| |
|
| |
|
| row:tag('td')
| | -------------------------------------------------------- |
| :wikitext(
| | -- Build tab contents |
| formatUser(entry.user)
| | -------------------------------------------------------- |
| )
| |
|
| |
|
| row:tag('td')
| | local allContent |
| :wikitext(
| |
| entry.createddate or ''
| |
| )
| |
| end
| |
|
| |
|
| return tostring(table)
| | if #allList > 0 then |
| end
| |
|
| |
|
| | allContent = |
| | table.concat(allList, '\n') |
|
| |
|
| function p.view(frame)
| | else |
| local parent =
| |
| frame:getParent()
| |
|
| |
|
| local args
| | allContent = |
| | '<em>No feedback entries found.</em>' |
|
| |
|
| if frame
| | end |
| 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
| | local unresolvedContent |
| and frame.args
| |
| then
| |
| args = frame.args
| |
|
| |
|
| elseif parent
| | if #unresolvedList > 0 then |
| and parent.args
| |
| then
| |
| args = parent.args
| |
|
| |
|
| else
| | unresolvedContent = |
| args = {}
| | table.concat(unresolvedList, '\n') |
| end
| |
| | |
| return p._view(
| |
| args,
| |
| frame
| |
| )
| |
| end
| |
|
| |
|
| | else |
|
| |
|
| function p._view(args, frame)
| | unresolvedContent = |
| local bucket =
| | '<em>No unresolved feedback entries found.</em>' |
| getBucket()
| |
|
| |
|
| if not bucket then
| | end |
| return
| |
| '<em>Bucket extension is not available.</em>'
| |
| end
| |
|
| |
|
| local rawStatus =
| |
| args.status
| |
| or args[1]
| |
|
| |
|
| local filterStatus =
| | local resolvedContent |
| rawStatus
| |
| and trim(rawStatus):lower()
| |
| or nil
| |
|
| |
|
| --------------------------------------------------------
| | if #resolvedList > 0 then |
| -- Query
| |
| --------------------------------------------------------
| |
|
| |
|
| local query =
| | resolvedContent = |
| bucket
| | table.concat(resolvedList, '\n') |
|
| |
|
| query.select(
| | else |
| 'page',
| |
| 'user',
| |
| 'status',
| |
| 'feedback',
| |
| 'id',
| |
| 'createddate',
| |
| 'link',
| |
| 'image',
| |
| 'resolvedby',
| |
| 'resolveddate'
| |
| )
| |
|
| |
|
| if filterStatus == 'resolved'
| | resolvedContent = |
| or filterStatus == 'unresolved'
| | '<em>No resolved feedback entries found.</em>' |
| then
| |
| query.where(
| |
| 'status',
| |
| filterStatus
| |
| )
| |
| end
| |
|
| |
|
| local success, entries =
| | end |
| pcall(function()
| |
| return query.run()
| |
| end)
| |
|
| |
|
| if not success or not entries then
| |
| return
| |
| '<em>Could not load feedback.</em>'
| |
| end
| |
|
| |
|
| entries =
| | -------------------------------------------------------- |
| sortNewestFirst(entries)
| | -- Tabber |
| | -------------------------------------------------------- |
|
| |
|
| --------------------------------------------------------
| | local tabberBody = string.format( |
| -- Specific status
| | 'All=\n%s\n|-|Unresolved=\n%s\n|-|Resolved=\n%s', |
| --------------------------------------------------------
| | allContent, |
| | unresolvedContent, |
| | resolvedContent |
| | ) |
|
| |
|
| if filterStatus == 'resolved'
| |
| or filterStatus == 'unresolved'
| |
| then
| |
| return renderFeedbackList(
| |
| entries
| |
| )
| |
| end
| |
|
| |
|
| --------------------------------------------------------
| | return frame:callParserFunction( |
| -- All
| | '#tag', |
| --------------------------------------------------------
| | { |
| | 'tabber', |
| | tabberBody |
| | } |
| | ) |
|
| |
|
| return renderTable(entries)
| |
| end | | end |
|
| |
|
|
| |
| p.table = p.view
| |
|
| |
|
| return p | | return p |