Jump to content
Main menu
Main menu
move to sidebar
hide
Navigation
Main page
Recent changes
Special pages
Random page
Wiki Discord
Contents
Neighbors
Galaxy
> Hexia
> Norvan
> Pashah
> Taffeh
Creatures
> Insects
> Fishes
> Shore-Dwellers
Items
> Dishes
> Furniture
Game Systems
> Dress Up
> Luca Arbor
> Loomix Footprints
> Loomix Vehicle Services
> Loomix Homes
Search
Search
Appearance
Log in
Personal tools
Log in
Editing
Module
:
Feedback
Module
Discussion
English
Read
Edit source
View history
Tools
Tools
move to sidebar
hide
Actions
Read
Edit source
View history
General
What links here
Related changes
Page information
Appearance
move to sidebar
hide
Warning:
You are not logged in. Your IP address will be publicly visible if you make any edits. If you
log in
or
create an account
, your edits will be attributed to your username, along with other benefits.
Anti-spam check. Do
not
fill this in!
local p = {} ------------------------------------------------------------ -- HELPERS ------------------------------------------------------------ local function isTruthy(value) if value == nil then return false end value = mw.text.trim(tostring(value)):lower() return value == 'true' or value == 'yes' or value == '1' or value == 'resolved' end local function trim(value) if value == nil then return '' end return mw.text.trim(tostring(value)) end local function formatUser(user) user = trim(user) if user == '' then return 'Anonymous' end return string.format( '[[User:%s|%s]]', user, user ) end local function currentSubjectPage() local title = mw.title.getCurrentTitle() if title.subjectPageTitle then return title.subjectPageTitle.fullText end return title.fullText end local function getBucket() if not (mw.ext and mw.ext.bucket) then return nil end return mw.ext.bucket('feedback') end local function sortNewestFirst(entries) table.sort( entries, function(a, b) local aDate = trim(a.createddate) local bDate = trim(b.createddate) return aDate > bDate end ) return entries end local function queryFeedback(page) local bucket = getBucket() if not bucket then return {} end local query = bucket query.select( 'page', 'user', 'status', 'feedback', 'id', 'createddate', 'link', 'image', 'resolvedby', 'resolveddate' ) query.where( 'page', page ) local success, results = pcall(function() return query.run() end) if not success or not results then return {} end return sortNewestFirst(results) end ------------------------------------------------------------ -- ATTACHMENTS ------------------------------------------------------------ local function renderAttachments(entry) local wrapper = mw.html.create('div') :addClass('feedback-attachments') local link = trim(entry.link) if link ~= '' then local linkWrapper = wrapper:tag('span') :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 image = mw.ustring.gsub( image, '^File:', '' ) local title = mw.title.new('File:' .. image) if title then 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 end ------------------------------------------------------------ -- RESOLUTION ------------------------------------------------------------ local function renderResolution(parent, entry) local resolvedBy = trim(entry.resolvedby) local resolvedDate = trim(entry.resolveddate) if resolvedBy == '' and resolvedDate == '' then return end local resolution = parent:tag('div') :addClass('feedback-resolution') resolution:wikitext('Resolved by ') if resolvedBy ~= '' then resolution:wikitext( formatUser(resolvedBy) ) else resolution:wikitext('Unknown') end if resolvedDate ~= '' then resolution:wikitext( ' on ' .. mw.text.nowiki(resolvedDate) ) end end ------------------------------------------------------------ -- RESOLVE CONTROL ------------------------------------------------------------ local function renderResolveControl( parent, id, page, compact ) if trim(id) == '' then return end local wrapper = parent:tag('div') :addClass('feedback-resolve') local control = 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 ------------------------------------------------------------ -- FULL FEEDBACK CARD ------------------------------------------------------------ local function renderFullCard(entry) local 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 = mw.html.create('div') :addClass('feedback-box') :addClass( resolved and 'feedback-box--resolved' or 'feedback-box--unresolved' ) if id ~= '' then root:attr( 'data-feedback-id', id ) end -------------------------------------------------------- -- Main content column -------------------------------------------------------- local content = root:tag('div') :addClass('feedback-content') -------------------------------------------------------- -- Main line -------------------------------------------------------- local main = content:tag('div') :addClass('feedback-main-line') -------------------------------------------------------- -- Status -------------------------------------------------------- main:tag('span') :addClass('feedback-status') :addClass( resolved and 'feedback-status--resolved' or 'feedback-status--unresolved' ) :wikitext( resolved and 'Resolved' or 'Unresolved' ) -------------------------------------------------------- -- Feedback text -------------------------------------------------------- main:tag('span') :addClass('feedback-text') :wikitext( feedback ~= '' and feedback or 'No feedback provided' ) -------------------------------------------------------- -- Metadata -------------------------------------------------------- local meta = main:tag('span') :addClass('feedback-inline-meta') if user ~= '' then meta:wikitext( ' · ' .. formatUser(user) ) end if createddate ~= '' then meta:wikitext( ' · ' .. mw.text.nowiki(createddate) ) end -------------------------------------------------------- -- Attachments -------------------------------------------------------- content:node( renderAttachments(entry) ) -------------------------------------------------------- -- Resolution information -------------------------------------------------------- renderResolution( content, entry ) -------------------------------------------------------- -- Missing ID warning -------------------------------------------------------- if id == '' then content:tag('div') :addClass('feedback-missing-id') :wikitext( 'This feedback entry is missing an ID.' ) end -------------------------------------------------------- -- Resolve button -- -- IMPORTANT: -- This is outside .feedback-content so it -- remains on the right. -------------------------------------------------------- if not resolved then renderResolveControl( root, id, page, false ) end return tostring(root) end ------------------------------------------------------------ -- COMPACT CARD ------------------------------------------------------------ local function renderCompactCard(entry) return renderFullCard(entry) end ------------------------------------------------------------ -- SAVE FEEDBACK ------------------------------------------------------------ local function saveFeedback(data) local bucket = getBucket() if not bucket then return false, 'Bucket extension is not available' 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 return false, tostring(err) end return true end ------------------------------------------------------------ -- MAIN -- -- Used by Template:Feedback ------------------------------------------------------------ function p.main(frame) local parent = frame:getParent() local args = parent and parent.args or frame.args local pageTitle = nil if parent and parent.getTitle then local title = parent:getTitle() if title and title ~= '' and not title:find('^Template:') then pageTitle = title end end return p._main( args, pageTitle ) end function p._main(args, pageTitle) local feedback = trim(args.feedback) if feedback == '' then feedback = 'No feedback provided' end local user = trim(args.user) if user == '' then user = 'Anonymous' end local resolved = isTruthy(args.resolved) local status = resolved and 'resolved' or 'unresolved' local currentPage = trim(pageTitle) if currentPage == '' then currentPage = mw.title.getCurrentTitle().fullText end 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) -------------------------------------------------------- -- Save to Bucket -------------------------------------------------------- local saved, saveError = 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 -------------------------------------------------------- -- Render -------------------------------------------------------- local card = renderFullCard({ page = currentPage, user = user, status = status, feedback = feedback, id = id, createddate = createddate, link = link, image = image, resolvedby = resolvedby, resolveddate = resolveddate }) -------------------------------------------------------- -- Categories -------------------------------------------------------- local category if resolved then category = '[[Category:Resolved Feedback]]' else category = '[[Category:Unresolved Feedback]]' end if id == '' then category = category .. '[[Category:Feedbacks Missing ID]]' end return card .. category end ------------------------------------------------------------ -- RENDER FEEDBACK LIST ------------------------------------------------------------ local function renderFeedbackList(results) if not results or #results == 0 then return '<em>No feedback entries found.</em>' end local list = {} for _, row in ipairs(results) do table.insert( list, renderFullCard(row) ) end return table.concat( list, '\n' ) end ------------------------------------------------------------ -- PAGE FEEDBACK ------------------------------------------------------------ function p.page(frame) local page = currentSubjectPage() local entries = queryFeedback(page) local unresolved = {} local resolved = {} for _, entry in ipairs(entries) do if trim(entry.status):lower() == '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') -------------------------------------------------------- -- Heading -------------------------------------------------------- root:tag('h2') :addClass('feedback-page-title') :wikitext('Feedbacks') -------------------------------------------------------- -- Filters -------------------------------------------------------- local filters = root:tag('div') :addClass('feedback-filters') local function addFilter( label, 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( 'Unresolved', 'unresolved', true ) addFilter( 'Resolved', 'resolved', false ) addFilter( 'All', 'all', false ) -------------------------------------------------------- -- Unresolved -------------------------------------------------------- local unresolvedList = root:tag('div') :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 -------------------------------------------------------- -- Resolved -------------------------------------------------------- local resolvedList = root:tag('div') :addClass( 'feedback-page-list' ) :addClass( 'feedback-page-list--resolved' ) if #resolved == 0 then resolvedList:tag('div') :addClass('feedback-empty') :wikitext( 'No resolved feedback.' ) else for _, entry in ipairs(resolved) do resolvedList:wikitext( renderCompactCard(entry) ) end end -------------------------------------------------------- -- All -------------------------------------------------------- local allList = root:tag('div') :addClass( 'feedback-page-list' ) :addClass( 'feedback-page-list--all' ) if #entries == 0 then allList:tag('div') :addClass('feedback-empty') :wikitext( 'No feedback.' ) else for _, entry in ipairs(entries) do allList:wikitext( renderCompactCard(entry) ) end end return tostring(root) end ------------------------------------------------------------ -- COUNTS ------------------------------------------------------------ function p.counts(frame) local entries = queryFeedback( currentSubjectPage() ) local unresolved = 0 local resolved = 0 for _, entry in ipairs(entries) do if trim(entry.status):lower() == 'resolved' then resolved = resolved + 1 else unresolved = unresolved + 1 end end return tostring( mw.html.create('span') :addClass('feedback-count-data') :attr( 'data-unresolved', unresolved ) :attr( 'data-resolved', resolved ) ) end ------------------------------------------------------------ -- TABLE / DASHBOARD ------------------------------------------------------------ local function renderTable(entries) if not entries or #entries == 0 then return '<em>No feedback entries found.</em>' end local table = mw.html.create('table') :addClass('feedback-table') local head = table:tag('thead') :tag('tr') head:tag('th') :wikitext('Status') head:tag('th') :wikitext('Page') head:tag('th') :wikitext('Feedback') head:tag('th') :wikitext('User') head:tag('th') :wikitext('Date') local body = table:tag('tbody') for _, entry in ipairs(entries) do local row = body:tag('tr') local resolved = trim(entry.status):lower() == 'resolved' row:tag('td') :addClass( resolved and 'feedback-table-status--resolved' or 'feedback-table-status--unresolved' ) :wikitext( resolved and 'Resolved' or 'Unresolved' ) row:tag('td') :addClass('feedback-table-page') :wikitext( entry.page or '' ) row:tag('td') :addClass('feedback-table-text') :wikitext( entry.feedback or '' ) row:tag('td') :wikitext( formatUser(entry.user) ) row:tag('td') :wikitext( entry.createddate or '' ) end return tostring(table) end function p.view(frame) local parent = frame:getParent() local args if frame and frame.args and frame.args.status then args = frame.args elseif parent and parent.args and parent.args.status then args = parent.args elseif frame and frame.args then args = frame.args elseif parent and parent.args then args = parent.args else args = {} end return p._view( args, frame ) end function p._view(args, frame) local bucket = getBucket() if not bucket then return '<em>Bucket extension is not available.</em>' end local rawStatus = args.status or args[1] local filterStatus = rawStatus and trim(rawStatus):lower() or nil -------------------------------------------------------- -- Query -------------------------------------------------------- local query = bucket query.select( 'page', 'user', 'status', 'feedback', 'id', 'createddate', 'link', 'image', 'resolvedby', 'resolveddate' ) if filterStatus == 'resolved' or filterStatus == 'unresolved' then query.where( 'status', filterStatus ) end local success, entries = pcall(function() return query.run() end) if not success or not entries then return '<em>Could not load feedback.</em>' end entries = sortNewestFirst(entries) -------------------------------------------------------- -- Specific status -------------------------------------------------------- if filterStatus == 'resolved' or filterStatus == 'unresolved' then return renderFeedbackList( entries ) end -------------------------------------------------------- -- All -------------------------------------------------------- return renderTable(entries) end p.table = p.view return p
Summary:
Please note that all contributions to The Petit Planet Wiki are considered to be released under the Creative Commons Attribution-ShareAlike (see
Petit Planet Wiki:Copyrights
for details). If you do not want your writing to be edited mercilessly and redistributed at will, then do not submit it here.
You are also promising us that you wrote this yourself, or copied it from a public domain or similar free resource.
Do not submit copyrighted work without permission!
Cancel
Editing help
(opens in new window)
Preview page with this template
Below are commonly used wikitext from
MediaWiki:Edittools
. Click on any to insert them in the edit box.
File Pages
==Summary==
==Licensing==
{{Fairuse}}
{{File|}}
Dynamic Page List
¦
²
«
»
²{¦}²
«»
«/»
«!----»
Array in DPL
¹
^2{
}^2
^2{¹}^2
Parser Functions
{{#if:||}}
{{#if:<condition>|<result if true>|<result if false>}}
{{#ifeq:|||}}
{{#ifeq:<text1>|<text2>|<result if text1=text2>|<result if text1≠text2>}}
{{#expr:}}
{{#expr:<mathematical expression>}}
{{#switch:||#default=}}
{{#switch:<text1>|<text2>=<result if text1=text2>|<text3>=<result if text1=text3>|#default=<result if no valid match>}}
{{#replace:||}}
{{#replace:<text1>|<plain text to find in text1>|<plain text to insert in place of the text found>}}
{{#titleparts:}}
{{#replace:<page name>}}
{{#tag:|}}
{{#tag:<name of html tag>|<content inside html tag>}}
Markup
{{}}
|
[]
[[]]
[[Category:]]
#REDIRECT [[]] [[Category:Redirect Pages]]
<code></code>
<includeonly></includeonly>
<noinclude></noinclude>
<nowiki></nowiki>
<!---->
<br>
§
Notices
{{Stub|}}
{{Stub Dialogue}}
{{Upcoming}}
{{Under Construction}}
{{Placeholder|}}
Magic Words
{{!}}
{{formatnum:}}
{{lc:}}
{{uc:}}
{{PAGENAME}}
{{FULLPAGENAME}}
{{ROOTPAGENAME}}
{{BASEPAGENAME}}
{{SUBPAGENAME}}
{{DISPLAYTITLE:|noreplace}}
__TOC__
__NOTOC__
__EXPECTUNUSEDCATEGORY__
__HIDDENCAT__
HTML Entities
—
,
­
Pages included on this page:
Template:Documentation/Header
(
edit
)
Template:Documentation/styles.css
(
edit
)
Template:T
(
edit
)
Template:TOC Right
(
edit
)
Module:Arguments
(
edit
)
Module:Arguments/i18n
(
edit
)
Module:Common/i18n
(
edit
)
Module:Config
(
edit
)
Module:Documentation
(
edit
)
Module:Documentation/config
(
edit
)
Module:Documentation/i18n
(
edit
)
Module:Entrypoint
(
edit
)
Module:Exists
(
edit
)
Module:Fallbacklist
(
edit
)
Module:Feature
(
edit
)
Module:Feedback/doc
(
edit
)
Module:Formatting
(
edit
)
Module:I18n
(
edit
)
Module:Languages
(
edit
)
Module:TableTools
(
edit
)
Module:Yesno
(
edit
)
This page is a member of 2 hidden categories:
Category:Pages using DynamicPageList4 parser function
Category:Pages using DynamicPageList4
Search
Search
Editing
Module
:
Feedback
Add topic