MediaWiki:Gadget-articlefeedback-core.js: Difference between revisions

From RuneRealm Wiki
Jump to navigation Jump to search
Content added Content deleted
(Created page with "→‎* <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...")
 
No edit summary
 
(3 intermediate revisions by the same user not shown)
Line 5: Line 5:


'use strict';
'use strict';
(function($, mw){
var conf = mw.config.get([
'wgNamespaceNumber',
'wgTitle',
'wgAction',
'wgArticleId',
'wgUserGroups'
]),


(function ($, mw) {
self = {
var conf = mw.config.get(['wgNamespaceNumber', 'wgTitle', 'wgAction', 'wgArticleId', 'wgUserGroups']),
// Constants
self = {
API_ENDPOINT: 'https://api.weirdgloop.org/wiki/feedback',
RESTRICTED_PAGES: [
// Constants
API_ENDPOINT: 'https://api.weirdgloop.org/wiki/feedback',
// List of pages where only logged-in users should see the feedback button
RESTRICTED_PAGES: [
'Gender', 'Makeover Mage', 'Pronouns', 'Body type'
// 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 init() {
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 buildTrigger() {
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 buildModal() {
var init = function init(modal) {
self.panel1 = new OO.ui.PanelLayout({
padded: true,
expanded: false
});


// Variables
// 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');
selectedRating: 0,
var stars = [star.clone(), star.clone(), star.clone(), star.clone(), star.clone()];
submitBtn: null,
$trigger: null,
var i;
$feedbackInput: null,
stars.map(function (star) {
stack: null,
// When we click on a star...
panel1: null,
star.on('click', function () {
panel2: null,
i = stars.indexOf(star);
var selectedLength = $('.rs-feedback-star-selected').length - 1;
window: null,


// 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
/**
* Startup method
*/
init: function () {
if (self.RESTRICTED_PAGES.includes(conf.wgTitle) && !conf.wgUserGroups.includes('autoconfirmed')) {
return;
}
self.buildModal();
self.buildTrigger();
},


if (!star.hasClass('rs-feedback-star-selected')) {
/**
// ...if this DOES NOT have selected class, give this star + all previous ones it
* Build the element that triggers the modal.
for (i; i >= 0; --i) stars[i].addClass('rs-feedback-star-selected');
*/
buildTrigger: function () {
} else if (selectedLength === 0 && selectedLength === i) {
var trigger = new OO.ui.ButtonWidget( {
// ...if this DOES have the selected class, but it's the only star, remove it
label: 'Give feedback',
$('.rs-feedback-star-selected').removeClass('rs-feedback-star-selected');
icon: 'feedback',
} 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');

trigger.on('click', function() {
} else {
// ...if this DOES have the selected class, but this is not the last star, remove everything after this
self.openModal();
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 close(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 openModal(e) {
if (e) {
e.preventDefault();
}
window.OOUIWindowManager.openWindow('feedback');
},
/**
* Close the modal
*/
closeModal: function closeModal() {
self.resetForm();
window.OOUIWindowManager.closeWindow('feedback');
self.stack.setItem(self.panel1);
},
/**
* Reset the form entirely
*/
resetForm: function resetForm() {
self.setError('');
self.submitBtn.setDisabled(false);
$('.rs-feedback-star-selected').removeClass('rs-feedback-star-selected');
self.selectedRating = 0;
},
/**
* Actually do the submission
*/
submit: function submit() {
self.submitBtn.setDisabled(true);
self.setError('');


// Ensure that feedback was provided
$('#firstHeading').append(
var feedbackInputValue = self.$feedbackInput.value.trim();
$('<div>').addClass('wgl-feedback-container').append(trigger.$element)
);
if (!feedbackInputValue) {
},
self.setError('Please provide feedback!');
self.submitBtn.setDisabled(false);

/**
return;
}
* 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();
}
};


// Make API call to save feedback
mw.loader.using(['mediawiki.api', 'ext.gadget.rsw-util', 'oojs-ui-core', 'oojs-ui.styles.icons-interactions'], function () {
$(self.init);
self.submitToAPI(self.selectedRating, feedbackInputValue);
});
},
showResultPage: function showResultPage() {
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 submitToAPI(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 setError(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);
})(window.$, window.mw);
// </nowiki>
// </nowiki>

Latest revision as of 12:06, 20 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 init() {
        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 buildTrigger() {
        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 buildModal() {
        var init = function init(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 close(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 openModal(e) {
        if (e) {
          e.preventDefault();
        }
        window.OOUIWindowManager.openWindow('feedback');
      },
      /**
       * Close the modal
       */
      closeModal: function closeModal() {
        self.resetForm();
        window.OOUIWindowManager.closeWindow('feedback');
        self.stack.setItem(self.panel1);
      },
      /**
       * Reset the form entirely
       */
      resetForm: function resetForm() {
        self.setError('');
        self.submitBtn.setDisabled(false);
        $('.rs-feedback-star-selected').removeClass('rs-feedback-star-selected');
        self.selectedRating = 0;
      },
      /**
       * Actually do the submission
       */
      submit: function submit() {
        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 showResultPage() {
        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 submitToAPI(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 setError(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>