- // ==UserScript==
- // @name StackOverflow close votes shortcuts
- // @namespace albireo.stackoverflow.close-votes-shortcuts
- // @version 1.0.0-rc.5
- // @description A script to add keyboard shortcuts to StackOverflow's close votes review queue
- // @author Albireo
- // @match http://stackoverflow.com/review/close*
- // @grant none
- // ==/UserScript==
-
- (function () {
- 'use strict';
-
- $(document).ready(function () {
- var keys = {
- '1': 49,
- '2': 50,
- '3': 51,
- '4': 52,
- '5': 53,
- '6': 54,
- '7': 55,
- '8': 56,
- '9': 57,
- '0': 48
- };
-
- var configuration = {
- 'actions': {
- 'leaveOpen': { 'key': '1', 'value': '8' },
- 'close': { 'key': '2', 'value': '6' },
- 'edit': { 'key': '3', 'value': '5' },
- 'skip': { 'key': '4', 'value': '1' }
- },
- 'closeReasons': {
- 'duplicate': { 'key': '1', 'value': 'Duplicate' },
- 'offTopic': { 'key': '2', 'value': 'OffTopic' },
- 'unclear': { 'key': '3', 'value': 'Unclear' },
- 'tooBroad': { 'key': '4', 'value': 'TooBroad' },
- 'opinionBased': { 'key': '5', 'value': 'OpinionBased' }
- },
- 'offTopicReasons': {
- 'superUser': { 'key': '1', 'value': '4' },
- 'serverFault': { 'key': '2', 'value': '7' },
- 'recommend': { 'key': '3', 'value': '16' },
- 'minimalProgram': { 'key': '4', 'value': '13' },
- 'typo': { 'key': '5', 'value': '11' },
- 'migration': { 'key': '6', 'value': '2' },
- 'other': { 'key': '7', 'value': '3' },
- },
- 'migrationReasons': {
- 'meta': { 'key': '1', 'value': 'meta.stackoverflow.com' },
- 'superUser': { 'key': '2', 'value': 'superuser.com' },
- 'tex': { 'key': '3', 'value': 'tex.stackexchange.com' },
- 'dba': { 'key': '4', 'value': 'dba.stackexchange.com' },
- 'stats': { 'key': '5', 'value': 'stats.stackexchange.com' },
- }
- };
-
- (function () {
- var states = {
- atQuestion: 1,
- atCloseReason: 2,
- atDuplicate: 3,
- atOffTopic: 4,
- atOtherSite: 5
- };
-
- var state = states.atQuestion;
-
- var clickElement = function (selector) {
- $(selector).focus().click();
- };
-
- var clickAction = function (action) {
- clickElement('.review-actions [data-result-type="' + action + '"]');
- };
-
- var clickCloseReason = function (reason) {
- clickElement('[name="close-reason"][value="' + reason + '"]');
- };
-
- var clickOffTopicReason = function (reason) {
- clickElement('[name="close-as-off-topic-reason"][value="' + reason + '"][data-other-comment-id=""]');
- };
-
- var clickOtherSite = function (site) {
- clickElement('[name="migration"][value="' + site + '"]');
- };
-
- var keyHandler = function(key) {
- switch (state) {
- case states.atQuestion:
- actionHandler(key);
- break;
- case states.atCloseReason:
- closeReasonHandler(key);
- break;
- case states.atOffTopic:
- offTopicHandler(key);
- break;
- case states.atOtherSite:
- otherSiteHandler(key);
- break;
- }
- };
-
- var actionHandler = function (key) {
- switch (key) {
- case keys[configuration.actions.leaveOpen.key]:
- clickAction(configuration.actions.leaveOpen.value);
- resetState();
- break;
- case keys[configuration.actions.close.key]:
- state = states.atCloseReason;
- clickAction(configuration.actions.close.value);
- break;
- case keys[configuration.actions.edit.key]:
- clickAction(configuration.actions.edit.value);
- resetState();
- break;
- case keys[configuration.actions.skip.key]:
- clickAction(configuration.actions.skip.value);
- resetState();
- break;
- }
- };
-
- var closeReasonHandler = function (key) {
- switch (key) {
- case keys[configuration.closeReasons.duplicate.key]:
- clickCloseReason(configuration.closeReasons.duplicate.value);
- state = states.atDuplicate;
- break;
- case keys[configuration.closeReasons.offTopic.key]:
- clickCloseReason(configuration.closeReasons.offTopic.value);
- state = states.atOffTopic;
- break;
- case keys[configuration.closeReasons.unclear.key]:
- clickCloseReason(configuration.closeReasons.unclear.value);
- break;
- case keys[configuration.closeReasons.tooBroad.key]:
- clickCloseReason(configuration.closeReasons.tooBroad.value);
- break;
- case keys[configuration.closeReasons.opinionBased.key]:
- clickCloseReason(configuration.closeReasons.opinionBased.value);
- break;
- }
- };
-
- var offTopicHandler = function (key) {
- switch (key) {
- case keys[configuration.offTopicReasons.superUser.key]:
- clickOffTopicReason(configuration.offTopicReasons.superUser.value);
- break;
- case keys[configuration.offTopicReasons.serverFault.key]:
- clickOffTopicReason(configuration.offTopicReasons.serverFault.value);
- break;
- case keys[configuration.offTopicReasons.recommend.key]:
- clickOffTopicReason(configuration.offTopicReasons.recommend.value);
- break;
- case keys[configuration.offTopicReasons.minimalProgram.key]:
- clickOffTopicReason(configuration.offTopicReasons.minimalProgram.value);
- break;
- case keys[configuration.offTopicReasons.typo.key]:
- clickOffTopicReason(configuration.offTopicReasons.typo.value);
- break;
- case keys[configuration.offTopicReasons.migration.key]:
- state = states.atOtherSite;
- clickOffTopicReason(configuration.offTopicReasons.migration.value);
- break;
- case keys[configuration.offTopicReasons.other.key]:
- clickOffTopicReason(configuration.offTopicReasons.other.value);
- break;
- }
- };
-
- var otherSiteHandler = function (key) {
- switch (key) {
- case keys[configuration.migrationReasons.meta.key]:
- clickOtherSite(configuration.migrationReasons.meta.value);
- break;
- case keys[configuration.migrationReasons.superUser.key]:
- clickOtherSite(configuration.migrationReasons.superUser.value);
- break;
- case keys[configuration.migrationReasons.tex.key]:
- clickOtherSite(configuration.migrationReasons.tex.value);
- break;
- case keys[configuration.migrationReasons.dba.key]:
- clickOtherSite(configuration.migrationReasons.dba.value);
- break;
- case keys[configuration.migrationReasons.stats.key]:
- clickOtherSite(configuration.migrationReasons.stats.value);
- break;
- }
- };
-
- var resetState = function () {
- state = states.atQuestion;
- };
-
- $(document).on('click', '#popup-close-question .popup-close a', function () {
- resetState();
- });
-
- $(document).on('click', '#popup-close-question .popup-submit', function () {
- resetState();
- });
-
- $(document).on('keyup', function (e) {
- if (e.keyCode === 27) {
- resetState();
- return;
- }
-
- if ((e.target.tagName === 'INPUT' && e.target.type === 'text') || e.target.tagName === 'TEXTAREA') {
- return;
- }
-
- keyHandler(e.keyCode);
- });
- })();
-
- (function () {
- var lookup = { };
- lookup[configuration.actions.leaveOpen.value] = configuration.actions.leaveOpen.key;
- lookup[configuration.actions.close.value] = configuration.actions.close.key;
- lookup[configuration.actions.edit.value] = configuration.actions.edit.key;
- lookup[configuration.actions.skip.value] = configuration.actions.skip.key;
-
- var observer = new MutationObserver(function (mutations) {
- mutations.forEach(function (mutation) {
- for (var i = 0, j = mutation.addedNodes.length; i < j; i++) {
- var node = $(mutation.addedNodes[i]);
- if (node.prop('tagName') !== 'INPUT' || node.prop('type') !== 'button') {
- continue;
- }
- var key = lookup[node.data('result-type')];
- if (!key) {
- continue;
- }
- node.val('[' + key + '] ' + node.val());
- }
- });
- });
-
- observer.observe(document.querySelector('.review-actions'), { 'childList': true });
- })();
-
- (function () {
- var addSiblingHelper = function (root, selector, key) {
- var element = $(root).find(selector).next();
- element.html('[' + key + '] ' + element.html());
- };
-
- var addCousinHelper = function (root, selector, key) {
- var element = $(root).find(selector).parent().next().next();
- element.html('[' + key + '] ' + element.html());
- };
-
- var addCloseReasonHelper = function (root, reason, key) {
- addSiblingHelper(root, '[name="close-reason"][value="' + reason + '"]', key);
- };
-
- var addOffTopicReasonHelper = function (root, reason, key) {
- addSiblingHelper(root, '[name="close-as-off-topic-reason"][value="' + reason +'"][data-other-comment-id=""]', key);
- };
-
- var addMigrationHelper = function (root, reason, key) {
- addCousinHelper(root, '[name="migration"][value="' + reason + '"]', key);
- };
-
- var addHelpers = function (root) {
- addCloseReasonHelper(root, configuration.closeReasons.duplicate.value, configuration.closeReasons.duplicate.key);
- addCloseReasonHelper(root, configuration.closeReasons.offTopic.value, configuration.closeReasons.offTopic.key);
- addCloseReasonHelper(root, configuration.closeReasons.unclear.value, configuration.closeReasons.unclear.key);
- addCloseReasonHelper(root, configuration.closeReasons.tooBroad.value, configuration.closeReasons.tooBroad.key);
- addCloseReasonHelper(root, configuration.closeReasons.opinionBased.value, configuration.closeReasons.opinionBased.key);
- addOffTopicReasonHelper(root, configuration.offTopicReasons.superUser.value, configuration.offTopicReasons.superUser.key);
- addOffTopicReasonHelper(root, configuration.offTopicReasons.serverFault.value, configuration.offTopicReasons.serverFault.key);
- addOffTopicReasonHelper(root, configuration.offTopicReasons.recommend.value, configuration.offTopicReasons.recommend.key);
- addOffTopicReasonHelper(root, configuration.offTopicReasons.minimalProgram.value, configuration.offTopicReasons.minimalProgram.key);
- addOffTopicReasonHelper(root, configuration.offTopicReasons.typo.value, configuration.offTopicReasons.typo.key);
- addOffTopicReasonHelper(root, configuration.offTopicReasons.migration.value, configuration.offTopicReasons.migration.key);
- addOffTopicReasonHelper(root, configuration.offTopicReasons.other.value, configuration.offTopicReasons.other.key);
- addMigrationHelper(root, configuration.migrationReasons.meta.value, configuration.migrationReasons.meta.key);
- addMigrationHelper(root, configuration.migrationReasons.superUser.value, configuration.migrationReasons.superUser.key);
- addMigrationHelper(root, configuration.migrationReasons.tex.value, configuration.migrationReasons.tex.key);
- addMigrationHelper(root, configuration.migrationReasons.dba.value, configuration.migrationReasons.dba.key);
- addMigrationHelper(root, configuration.migrationReasons.stats.value, configuration.migrationReasons.stats.key);
- };
-
- var observer = new MutationObserver(function (mutations) {
- mutations.forEach(function (mutation) {
- for (var i = 0, j = mutation.addedNodes.length; i < j; i++) {
- var node = mutation.addedNodes[i];
- if (node.tagName === 'DIV' && node.id === 'popup-close-question') {
- addHelpers(node);
- }
- }
- });
- });
-
- observer.observe(document.querySelector('.review-content'), { 'childList': true, 'subtree': true });
- })();
- });
- })();