MediaWiki:Gadget-articlefeedback-core.js: Difference between revisions
Jump to navigation
Jump to search
Content added Content deleted
No edit summary Tag: Reverted |
No edit summary Tag: Reverted |
||
Line 1: | Line 1: | ||
/** <nowiki> * Gadget for the wiki article feedback feature. * @author Jayden */'use strict';(function($, mw){ var conf = mw.config.get([ 'wgNamespaceNumber', 'wgTitle', 'wgAction', 'wgArticleId', 'wgUserGroups' ]), self = { // Constants API_ENDPOINT: 'https://api.weirdgloop.org/wiki/feedback', RESTRICTED_PAGES: [ // List of pages where only logged-in users should see the feedback button 'Gender', 'Makeover Mage', 'Pronouns', 'Body type' ], // Variables selectedRating: 0, submitBtn: null, $trigger: null, $feedbackInput: null, stack: null, panel1: null, panel2: null, window: null, /** * Startup method */ init: function () { if (self.RESTRICTED_PAGES.includes(conf.wgTitle) && !conf.wgUserGroups.includes('autoconfirmed')) { return; } self.buildModal(); self.buildTrigger(); }, /** * Build the element that triggers the modal. */ buildTrigger: function () { var trigger = new OO.ui.ButtonWidget( { label: 'Give feedback', icon: 'feedback', } ); trigger.on('click', function() { self.openModal(); }); $('#firstHeading').append( $('<div>').addClass('wgl-feedback-container').append(trigger.$element) ); }, /** * Build the modal we will show for providing article feedback. */ buildModal: function () { var init = function (modal) { self.panel1 = new OO.ui.PanelLayout( { padded: true, expanded: false } ); // Create star rating UI var star = $("<svg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'><path d='M12 .587l3.668 7.568 8.332 1.151-6.064 5.828 1.48 8.279-7.416-3.967-7.417 3.967 1.481-8.279-6.064-5.828 8.332-1.151z'/></svg>").addClass('rs-feedback-star'); var stars = [star.clone(), star.clone(), star.clone(), star.clone(), star.clone()]; var i; stars.map(function (star) { // When we click on a star... star.on('click', function () { i = stars.indexOf(star); var selectedLength = $('.rs-feedback-star-selected').length - 1; // This whole if statement could probably be 10x cleaner but I lack the brain capacity right now to try and do something nice without ES6 syntax if (!star.hasClass('rs-feedback-star-selected')) { // ...if this DOES NOT have selected class, give this star + all previous ones it for (i; i >= 0; --i) stars[i].addClass('rs-feedback-star-selected'); } else if (selectedLength === 0 && selectedLength === i) { // ...if this DOES have the selected class, but it's the only star, remove it $('.rs-feedback-star-selected').removeClass('rs-feedback-star-selected'); } else if (($('.rs-feedback-star-selected').length - 1) === i) { // ...if this DOES have the selected class, and this is the last star, remove the selected class for (i; i < stars.length; ++i) stars[i].removeClass('rs-feedback-star-selected'); } else { // ...if this DOES have the selected class, but this is not the last star, remove everything after this stars.forEach(function (ele, ix) { if (ix > i) { ele.removeClass('rs-feedback-star-selected'); } }) } self.selectedRating = $('.rs-feedback-star-selected').length; }) }); var finalStarUi = $('<div>').append( $('<h5>').text('Give feedback on this page'), $('<div>').addClass('rs-feedback-star-container').append( $('<div>').addClass('rs-feedback-stars').append(stars), $('<p>').addClass('text-grey small').text('(optional)') ) ); self.$feedbackInput = new OO.ui.MultilineTextInputWidget( { placeholder: 'What can be improved on this page?', id: 'rs-feedback-feedback', rows: 5, autosize: true, autofocus: true} ); self.submitBtn = new OO.ui.ButtonInputWidget( { label: 'Submit', flags: [ 'primary', 'progressive' ] } ); var b1click = ('click', function(modal) { // When the submit button is clicked, do the submission... self.submit(); }); self.submitBtn.on('click', b1click, [modal]); var cancelBtn = new OO.ui.ButtonInputWidget( { label: 'Cancel', } ); var close = function(modal) { self.closeModal(); }; cancelBtn.on('click', close, [modal]); self.panel1.$element.append(finalStarUi, self.$feedbackInput.$element, $('<p>').addClass('wgl-feedback-error'), self.submitBtn.$element, cancelBtn.$element ); self.panel2 = new OO.ui.PanelLayout( { padded: true, expanded: false } ); self.panel2.$element.append( $('<h3>').text('Thank you!'), $('<p>').html('Your feedback has been brought up for discussion on our Discord server. You can join by clicking <strong>Open Discord App</strong>.'), $('<iframe>') .addClass('rs-feedback-discord') .css('border-top', '1px') .css('margin', '1em 0') .attr('width', '100%') .attr('height', '500px') .attr('frameBorder', '0') ) self.stack = new OO.ui.StackLayout({ items: [self.panel1, self.panel2] }) modal.$body.append( self.stack.$element ); }; rs.createOOUIWindow('feedback', 'Submit feedback for ' + conf.wgTitle, {size: 'large', classes: ['rs-feedback-modal']}, init, false, true, true).then(function (w) { self.window = w; self.window.$element.on('click', function (e) { if (e.target !== this) return; self.closeModal(); }) }); }, /** * Open the modal */ openModal: function (e) { if (e) { e.preventDefault(); } window.OOUIWindowManager.openWindow( 'feedback' ); }, /** * Close the modal */ closeModal: function () { self.resetForm(); window.OOUIWindowManager.closeWindow( 'feedback' ); self.stack.setItem(self.panel1); }, /** * Reset the form entirely */ resetForm: function () { self.setError(''); self.submitBtn.setDisabled(false); $('.rs-feedback-star-selected').removeClass('rs-feedback-star-selected'); self.selectedRating = 0; }, /** * Actually do the submission */ submit: function () { self.submitBtn.setDisabled(true); self.setError(''); // Ensure that feedback was provided var feedbackInputValue = self.$feedbackInput.value.trim(); if (!feedbackInputValue) { self.setError('Please provide feedback!'); self.submitBtn.setDisabled(false); return; }; // Make API call to save feedback self.submitToAPI(self.selectedRating, feedbackInputValue); }, showResultPage: function () { self.stack.setItem(self.panel2); // This is here so that we don't load the iframe until the result page is displayed $('.rs-feedback-discord').attr('src', 'https://e.widgetbot.io/channels/177206626514632704/269673599554551808'); self.window.updateSize(); }, /** * Make API call */ submitToAPI: function (rating, feedback) { $.ajax(self.API_ENDPOINT, { data: JSON.stringify({wiki: 'osw', page: conf.wgArticleId, rating: rating, feedback: feedback}), type: 'POST', contentType: 'application/json' }) .done(function () { self.showResultPage(); }) .fail(function (jqXHR) { self.setError('There was a problem. Please try again later.'); self.submitBtn.setDisabled(false); }) ; }, /** * Set an error message */ setError: function(error) { $('.wgl-feedback-error').text(error); self.window.updateSize(); } }; mw.loader.using(['mediawiki.api', 'ext.gadget.rsw-util', 'oojs-ui-core', 'oojs-ui.styles.icons-interactions'], function () { $(self.init); });})(window.$, window.mw);// </nowiki> |
|||
/** <nowiki> |
|||
* Gadget for the wiki article feedback feature. |
|||
* @author Jayden |
|||
*/ |
|||
'use strict'; |
|||
(function($, mw){ |
|||
var conf = mw.config.get([ |
|||
'wgNamespaceNumber', |
|||
'wgTitle', |
|||
'wgAction', |
|||
'wgArticleId', |
|||
'wgUserGroups' |
|||
]), |
|||
self = { |
|||
// Constants |
|||
API_ENDPOINT: 'https://api.weirdgloop.org/wiki/feedback', |
|||
RESTRICTED_PAGES: [ |
|||
// List of mw.pages where only logged-in users should see the feedback button |
|||
'Gender', 'Makeover Mage', 'Pronouns', 'Body type' |
|||
], |
|||
// Variables |
|||
selectedRating: 0, |
|||
submitBtn: null, |
|||
$trigger: null, |
|||
$feedbackInput: null, |
|||
stack: null, |
|||
panel1: null, |
|||
panel2: null, |
|||
window: null, |
|||
/** |
|||
* Startup method |
|||
*/ |
|||
init: function () { |
|||
if (self.RESTRICTED_PAGES.includes(conf.wgTitle) && !conf.wgUserGroups.includes('autoconfirmed')) { |
|||
return; |
|||
} |
|||
self.buildModal(); |
|||
self.buildTrigger(); |
|||
}, |
|||
/** |
|||
* Build the element that triggers the modal. |
|||
*/ |
|||
buildTrigger: function () { |
|||
var trigger = new OO.ui.ButtonWidget( { |
|||
label: 'Give feedback', |
|||
icon: 'feedback', |
|||
} ); |
|||
trigger.on('click', function() { |
|||
self.openModal(); |
|||
}); |
|||
$('#firstHeading').append( |
|||
$('<div>').addClass('wgl-feedback-container').append(trigger.$element) |
|||
); |
|||
}, |
|||
/** |
|||
* Build the modal we will show for providing article feedback. |
|||
*/ |
|||
buildModal: function () { |
|||
var init = function (modal) { |
|||
self.panel1 = new OO.ui.PanelLayout( { padded: true, expanded: false } ); |
|||
// Create star rating UI |
|||
var star = $("<svg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'><path d='M12 .587l3.668 7.568 8.332 1.151-6.064 5.828 1.48 8.279-7.416-3.967-7.417 3.967 1.481-8.279-6.064-5.828 8.332-1.151z'/></svg>").addClass('rs-feedback-star'); |
|||
var stars = [star.clone(), star.clone(), star.clone(), star.clone(), star.clone()]; |
|||
var i; |
|||
stars.map(function (star) { |
|||
// When we click on a star... |
|||
star.on('click', function () { |
|||
i = stars.indexOf(star); |
|||
var selectedLength = $('.rs-feedback-star-selected').length - 1; |
|||
// This whole if statement could probably be 10x cleaner but I lack the brain capacity right now to try and do something nice without ES6 syntax |
|||
if (!star.hasClass('rs-feedback-star-selected')) { |
|||
// ...if this DOES NOT have selected class, give this star + all previous ones it |
|||
for (i; i >= 0; --i) stars[i].addClass('rs-feedback-star-selected'); |
|||
} else if (selectedLength === 0 && selectedLength === i) { |
|||
// ...if this DOES have the selected class, but it's the only star, remove it |
|||
$('.rs-feedback-star-selected').removeClass('rs-feedback-star-selected'); |
|||
} else if (($('.rs-feedback-star-selected').length - 1) === i) { |
|||
// ...if this DOES have the selected class, and this is the last star, remove the selected class |
|||
for (i; i < stars.length; ++i) stars[i].removeClass('rs-feedback-star-selected'); |
|||
} else { |
|||
// ...if this DOES have the selected class, but this is not the last star, remove everything after this |
|||
stars.forEach(function (ele, ix) { |
|||
if (ix > i) { |
|||
ele.removeClass('rs-feedback-star-selected'); |
|||
} |
|||
}) |
|||
} |
|||
self.selectedRating = $('.rs-feedback-star-selected').length; |
|||
}) |
|||
}); |
|||
var finalStarUi = $('<div>').append( |
|||
$('<h5>').text('Give feedback on this page'), |
|||
$('<div>').addClass('rs-feedback-star-container').append( |
|||
$('<div>').addClass('rs-feedback-stars').append(stars), |
|||
$('<p>').addClass('text-grey small').text('(optional)') |
|||
) |
|||
); |
|||
self.$feedbackInput = new OO.ui.MultilineTextInputWidget( { placeholder: 'What can be improved on this page?', id: 'rs-feedback-feedback', rows: 5, autosize: true, autofocus: true} ); |
|||
self.submitBtn = new OO.ui.ButtonInputWidget( { |
|||
label: 'Submit', |
|||
flags: [ 'primary', 'progressive' ] |
|||
} ); |
|||
var b1click = ('click', function(modal) { |
|||
// When the submit button is clicked, do the submission... |
|||
self.submit(); |
|||
}); |
|||
self.submitBtn.on('click', b1click, [modal]); |
|||
var cancelBtn = new OO.ui.ButtonInputWidget( { |
|||
label: 'Cancel', |
|||
} ); |
|||
var close = function(modal) { |
|||
self.closeModal(); |
|||
}; |
|||
cancelBtn.on('click', close, [modal]); |
|||
self.panel1.$element.append(finalStarUi, self.$feedbackInput.$element, $('<p>').addClass('wgl-feedback-error'), self.submitBtn.$element, cancelBtn.$element ); |
|||
self.panel2 = new OO.ui.PanelLayout( { padded: true, expanded: false } ); |
|||
self.panel2.$element.append( |
|||
$('<h3>').text('Thank you!'), |
|||
$('<p>').html('Your feedback has been brought up for discussion on our Discord server. You can join by clicking <strong>Open Discord App</strong>.'), |
|||
$('<iframe>') |
|||
.addClass('rs-feedback-discord') |
|||
.css('border-top', '1px') |
|||
.css('margin', '1em 0') |
|||
.attr('width', '100%') |
|||
.attr('height', '500px') |
|||
.attr('frameBorder', '0') |
|||
) |
|||
self.stack = new OO.ui.StackLayout({ |
|||
items: [self.panel1, self.panel2] |
|||
}) |
|||
modal.$body.append( self.stack.$element ); |
|||
}; |
|||
rs.createOOUIWindow('feedback', 'Submit feedback for ' + conf.wgTitle, {size: 'large', classes: ['rs-feedback-modal']}, init, false, true, true).then(function (w) { |
|||
self.window = w; |
|||
self.window.$element.on('click', function (e) { |
|||
if (e.target !== this) return; |
|||
self.closeModal(); |
|||
}) |
|||
}); |
|||
}, |
|||
/** |
|||
* Open the modal |
|||
*/ |
|||
openModal: function (e) { |
|||
if (e) { e.preventDefault(); } |
|||
window.OOUIWindowManager.openWindow( 'feedback' ); |
|||
}, |
|||
/** |
|||
* Close the modal |
|||
*/ |
|||
closeModal: function () { |
|||
self.resetForm(); |
|||
window.OOUIWindowManager.closeWindow( 'feedback' ); |
|||
self.stack.setItem(self.panel1); |
|||
}, |
|||
/** |
|||
* Reset the form entirely |
|||
*/ |
|||
resetForm: function () { |
|||
self.setError(''); |
|||
self.submitBtn.setDisabled(false); |
|||
$('.rs-feedback-star-selected').removeClass('rs-feedback-star-selected'); |
|||
self.selectedRating = 0; |
|||
}, |
|||
/** |
|||
* Actually do the submission |
|||
*/ |
|||
submit: function () { |
|||
self.submitBtn.setDisabled(true); |
|||
self.setError(''); |
|||
// Ensure that feedback was provided |
|||
var feedbackInputValue = self.$feedbackInput.value.trim(); |
|||
if (!feedbackInputValue) { |
|||
self.setError('Please provide feedback!'); |
|||
self.submitBtn.setDisabled(false); |
|||
return; |
|||
}; |
|||
// Make API call to save feedback |
|||
self.submitToAPI(self.selectedRating, feedbackInputValue); |
|||
}, |
|||
showResultPage: function () { |
|||
self.stack.setItem(self.panel2); |
|||
// This is here so that we don't load the iframe until the result page is displayed |
|||
$('.rs-feedback-discord').attr('src', 'https://e.widgetbot.io/channels/177206626514632704/269673599554551808'); |
|||
self.window.updateSize(); |
|||
}, |
|||
/** |
|||
* Make API call |
|||
*/ |
|||
submitToAPI: function (rating, feedback) { |
|||
$.ajax(self.API_ENDPOINT, { |
|||
data: JSON.stringify({wiki: 'osw', page: conf.wgArticleId, rating: rating, feedback: feedback}), |
|||
type: 'POST', |
|||
contentType: 'application/json' |
|||
}) |
|||
.done(function () { |
|||
self.showResultPage(); |
|||
}) |
|||
.fail(function (jqXHR) { |
|||
self.setError('There was a problem. Please try again later.'); |
|||
self.submitBtn.setDisabled(false); |
|||
}) |
|||
; |
|||
}, |
|||
/** |
|||
* Set an error message |
|||
*/ |
|||
setError: function(error) { |
|||
$('.wgl-feedback-error').text(error); |
|||
self.window.updateSize(); |
|||
} |
|||
}; |
|||
mw.loader.using(['mediawiki.api', 'ext.gadget.rsw-mw.util', 'oojs-ui-core', 'oojs-ui.styles.icons-interactions'], function () { |
|||
$(self.init); |
|||
}); |
|||
})(window.$, window.mw); |
|||
// </nowiki> |
Revision as of 17:12, 17 October 2024
/** <nowiki> * Gadget for the wiki article feedback feature. * @author Jayden */'use strict';(function($, mw){ var conf = mw.config.get([ 'wgNamespaceNumber', 'wgTitle', 'wgAction', 'wgArticleId', 'wgUserGroups' ]), self = { // Constants API_ENDPOINT: 'https://api.weirdgloop.org/wiki/feedback', RESTRICTED_PAGES: [ // List of pages where only logged-in users should see the feedback button 'Gender', 'Makeover Mage', 'Pronouns', 'Body type' ], // Variables selectedRating: 0, submitBtn: null, $trigger: null, $feedbackInput: null, stack: null, panel1: null, panel2: null, window: null, /** * Startup method */ init: function () { if (self.RESTRICTED_PAGES.includes(conf.wgTitle) && !conf.wgUserGroups.includes('autoconfirmed')) { return; } self.buildModal(); self.buildTrigger(); }, /** * Build the element that triggers the modal. */ buildTrigger: function () { var trigger = new OO.ui.ButtonWidget( { label: 'Give feedback', icon: 'feedback', } ); trigger.on('click', function() { self.openModal(); }); $('#firstHeading').append( $('<div>').addClass('wgl-feedback-container').append(trigger.$element) ); }, /** * Build the modal we will show for providing article feedback. */ buildModal: function () { var init = function (modal) { self.panel1 = new OO.ui.PanelLayout( { padded: true, expanded: false } ); // Create star rating UI var star = $("<svg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'><path d='M12 .587l3.668 7.568 8.332 1.151-6.064 5.828 1.48 8.279-7.416-3.967-7.417 3.967 1.481-8.279-6.064-5.828 8.332-1.151z'/></svg>").addClass('rs-feedback-star'); var stars = [star.clone(), star.clone(), star.clone(), star.clone(), star.clone()]; var i; stars.map(function (star) { // When we click on a star... star.on('click', function () { i = stars.indexOf(star); var selectedLength = $('.rs-feedback-star-selected').length - 1; // This whole if statement could probably be 10x cleaner but I lack the brain capacity right now to try and do something nice without ES6 syntax if (!star.hasClass('rs-feedback-star-selected')) { // ...if this DOES NOT have selected class, give this star + all previous ones it for (i; i >= 0; --i) stars[i].addClass('rs-feedback-star-selected'); } else if (selectedLength === 0 && selectedLength === i) { // ...if this DOES have the selected class, but it's the only star, remove it $('.rs-feedback-star-selected').removeClass('rs-feedback-star-selected'); } else if (($('.rs-feedback-star-selected').length - 1) === i) { // ...if this DOES have the selected class, and this is the last star, remove the selected class for (i; i < stars.length; ++i) stars[i].removeClass('rs-feedback-star-selected'); } else { // ...if this DOES have the selected class, but this is not the last star, remove everything after this stars.forEach(function (ele, ix) { if (ix > i) { ele.removeClass('rs-feedback-star-selected'); } }) } self.selectedRating = $('.rs-feedback-star-selected').length; }) }); var finalStarUi = $('<div>').append( $('<h5>').text('Give feedback on this page'), $('<div>').addClass('rs-feedback-star-container').append( $('<div>').addClass('rs-feedback-stars').append(stars), $('<p>').addClass('text-grey small').text('(optional)') ) ); self.$feedbackInput = new OO.ui.MultilineTextInputWidget( { placeholder: 'What can be improved on this page?', id: 'rs-feedback-feedback', rows: 5, autosize: true, autofocus: true} ); self.submitBtn = new OO.ui.ButtonInputWidget( { label: 'Submit', flags: [ 'primary', 'progressive' ] } ); var b1click = ('click', function(modal) { // When the submit button is clicked, do the submission... self.submit(); }); self.submitBtn.on('click', b1click, [modal]); var cancelBtn = new OO.ui.ButtonInputWidget( { label: 'Cancel', } ); var close = function(modal) { self.closeModal(); }; cancelBtn.on('click', close, [modal]); self.panel1.$element.append(finalStarUi, self.$feedbackInput.$element, $('<p>').addClass('wgl-feedback-error'), self.submitBtn.$element, cancelBtn.$element ); self.panel2 = new OO.ui.PanelLayout( { padded: true, expanded: false } ); self.panel2.$element.append( $('<h3>').text('Thank you!'), $('<p>').html('Your feedback has been brought up for discussion on our Discord server. You can join by clicking <strong>Open Discord App</strong>.'), $('<iframe>') .addClass('rs-feedback-discord') .css('border-top', '1px') .css('margin', '1em 0') .attr('width', '100%') .attr('height', '500px') .attr('frameBorder', '0') ) self.stack = new OO.ui.StackLayout({ items: [self.panel1, self.panel2] }) modal.$body.append( self.stack.$element ); }; rs.createOOUIWindow('feedback', 'Submit feedback for ' + conf.wgTitle, {size: 'large', classes: ['rs-feedback-modal']}, init, false, true, true).then(function (w) { self.window = w; self.window.$element.on('click', function (e) { if (e.target !== this) return; self.closeModal(); }) }); }, /** * Open the modal */ openModal: function (e) { if (e) { e.preventDefault(); } window.OOUIWindowManager.openWindow( 'feedback' ); }, /** * Close the modal */ closeModal: function () { self.resetForm(); window.OOUIWindowManager.closeWindow( 'feedback' ); self.stack.setItem(self.panel1); }, /** * Reset the form entirely */ resetForm: function () { self.setError(''); self.submitBtn.setDisabled(false); $('.rs-feedback-star-selected').removeClass('rs-feedback-star-selected'); self.selectedRating = 0; }, /** * Actually do the submission */ submit: function () { self.submitBtn.setDisabled(true); self.setError(''); // Ensure that feedback was provided var feedbackInputValue = self.$feedbackInput.value.trim(); if (!feedbackInputValue) { self.setError('Please provide feedback!'); self.submitBtn.setDisabled(false); return; }; // Make API call to save feedback self.submitToAPI(self.selectedRating, feedbackInputValue); }, showResultPage: function () { self.stack.setItem(self.panel2); // This is here so that we don't load the iframe until the result page is displayed $('.rs-feedback-discord').attr('src', 'https://e.widgetbot.io/channels/177206626514632704/269673599554551808'); self.window.updateSize(); }, /** * Make API call */ submitToAPI: function (rating, feedback) { $.ajax(self.API_ENDPOINT, { data: JSON.stringify({wiki: 'osw', page: conf.wgArticleId, rating: rating, feedback: feedback}), type: 'POST', contentType: 'application/json' }) .done(function () { self.showResultPage(); }) .fail(function (jqXHR) { self.setError('There was a problem. Please try again later.'); self.submitBtn.setDisabled(false); }) ; }, /** * Set an error message */ setError: function(error) { $('.wgl-feedback-error').text(error); self.window.updateSize(); } }; mw.loader.using(['mediawiki.api', 'ext.gadget.rsw-util', 'oojs-ui-core', 'oojs-ui.styles.icons-interactions'], function () { $(self.init); });})(window.$, window.mw);// </nowiki>