// ==UserScript== // @name MusicBrainz: Fast cancel edits // @description Mass cancel open edits with optional edit notes. // @version 2015.6.7 // @author Michael Wiencek // @license X11 // @downloadURL https://raw.githubusercontent.com/murdos/musicbrainz-userscripts/master/fast-cancel-edits.user.js // @updateURL https://raw.githubusercontent.com/murdos/musicbrainz-userscripts/master/fast-cancel-edits.user.js // @include *://musicbrainz.org/user/*/edits/open* // @include *://musicbrainz.org/*/*/open_edits* // @include *://musicbrainz.org/*/*/edits* // @include *://musicbrainz.org/search/edits* // @include *://*.musicbrainz.org/user/*/edits/open* // @include *://*.musicbrainz.org/*/*/open_edits* // @include *://*.musicbrainz.org/*/*/edits* // @include *://*.musicbrainz.org/search/edits* // @include *://*.mbsandbox.org/user/*/edits/open* // @include *://*.mbsandbox.org/*/*/open_edits* // @include *://*.mbsandbox.org/*/*/edits* // @include *://*.mbsandbox.org/search/edits* // @match *://musicbrainz.org/user/*/edits/open* // @match *://musicbrainz.org/*/*/open_edits* // @match *://musicbrainz.org/*/*/edits* // @match *://musicbrainz.org/search/edits* // @match *://*.musicbrainz.org/user/*/edits/open* // @match *://*.musicbrainz.org/*/*/open_edits* // @match *://*.musicbrainz.org/*/*/edits* // @match *://*.musicbrainz.org/search/edits* // @match *://*.mbsandbox.org/user/*/edits/open* // @match *://*.mbsandbox.org/*/*/open_edits* // @match *://*.mbsandbox.org/*/*/edits* // @match *://*.mbsandbox.org/search/edits* // @grant none // ==/UserScript== // ==License== // Copyright (C) 2014 Michael Wiencek // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // // Except as contained in this notice, the name(s) of the above copyright // holders shall not be used in advertising or otherwise to promote the sale, // use or other dealings in this Software without prior written // authorization. // ==/License== //**************************************************************************// var scr = document.createElement("script"); scr.textContent = "(" + fastCancelScript + ")();"; document.body.appendChild(scr); function fastCancelScript() { var totalCancels = 0; var $status = $("
") .css({ "position": "fixed", "right": "0", "bottom": "0", "background": "#FFBA58", "border-top": "1px #000 solid", "border-left": "1px #000 solid", "padding": "0.5em" }) .appendTo("body") .hide(); function updateStatus() { if (totalCancels === 0) { $status.hide(); } else { $status.text("Canceling " + totalCancels + " edit" + (totalCancels > 1 ? "s" : "") + "...").show(); } } document.body.addEventListener("click", function (event) { if (event.target && event.target.tagName && event.target.tagName == "A" && event.target.classList.contains("negative")) { event.stopPropagation(); event.preventDefault(); totalCancels += 1; updateStatus(); var $self = $(event.target), $edit = $self.parents("div.edit-list:eq(0)"); pushRequest(function () { var editNote = $edit.find("div.add-edit-note textarea").val(); var data = { "confirm.edit_note": editNote }; $.ajax({ type: "POST", url: $self.attr("href"), data: data, error: function (request, status, error) { $self .css({ "background": "red", "color": "yellow", "cursor": "help" }) .attr("title", "Error cancelling this edit: “" + error + "”"); $edit .css({border: "6px solid red"}) .show(); }, complete: function () { $edit.remove(); totalCancels -= 1; updateStatus(); } }); }); $edit.hide(); } }); $("div#edits > form[action$='/edit/enter_votes']").on("submit", function(event) { if (totalCancels > 0) { event.preventDefault(); alert("Please wait, " + (totalCancels > 1 ? totalCancels + " edits are" : "an edit is") + " being cancelled in the background."); } }); var pushRequest = (function () { var queue = [], last = 0, active = false, rate = 2000; function next() { if (queue.length === 0) { active = false; } else { queue.shift()(); last = new Date().getTime(); setTimeout(next, rate); } } return function (req) { queue.push(req); if (!active) { active = true; var now = new Date().getTime(); if (now - last >= rate) { next(); } else { var timeout = rate - now + last; setTimeout(next, timeout); } } }; }()); }