mb. AUTO-FOCUS + KEYBOARD-SELECT

musicbrainz.org: MOUSE-LESS EDITING ! Cleverly focuses fields in various musicbrainz edit pages and allows keyboard selection of relationship types as well as some release editor keyboard navigation performance features

目前為 2021-02-05 提交的版本,檢視 最新版本

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         mb. AUTO-FOCUS + KEYBOARD-SELECT
// @version      2021.2.5
// @description  musicbrainz.org: MOUSE-LESS EDITING ! Cleverly focuses fields in various musicbrainz edit pages and allows keyboard selection of relationship types as well as some release editor keyboard navigation performance features
// @namespace    https://github.com/jesus2099/konami-command
// @supportURL   https://github.com/jesus2099/konami-command/labels/mb_AUTO-FOCUS-KEYBOARD-SELECT
// @author       jesus2099
// @licence      CC-BY-NC-SA-4.0; https://creativecommons.org/licenses/by-nc-sa/4.0/
// @licence      GPL-3.0-or-later; http://www.gnu.org/licenses/gpl-3.0.txt
// @since        2012-06-08; https://web.archive.org/web/20131103163357/userscripts.org/scripts/show/135547 / https://web.archive.org/web/20141011084007/userscripts-mirror.org/scripts/show/135547
// @icon         data:image/gif;base64,R0lGODlhEAAQAKEDAP+/3/9/vwAAAP///yH/C05FVFNDQVBFMi4wAwEAAAAh/glqZXN1czIwOTkAIfkEAQACAwAsAAAAABAAEAAAAkCcL5nHlgFiWE3AiMFkNnvBed42CCJgmlsnplhyonIEZ8ElQY8U66X+oZF2ogkIYcFpKI6b4uls3pyKqfGJzRYAACH5BAEIAAMALAgABQAFAAMAAAIFhI8ioAUAIfkEAQgAAwAsCAAGAAUAAgAAAgSEDHgFADs=
// @grant        none
// @include      /^https?:\/\/(\w+\.)?musicbrainz\.org\/(recording|release)\/[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}\/delete$/
// @match        *://*.musicbrainz.org/*/*/add-alias
// @match        *://*.musicbrainz.org/*/*/alias/*/delete
// @match        *://*.musicbrainz.org/*/*/alias/*/edit
// @match        *://*.musicbrainz.org/*/*/edit_annotation*
// @match        *://*.musicbrainz.org/*/*/tags*
// @match        *://*.musicbrainz.org/artist/*/edit
// @match        *://*.musicbrainz.org/artist/create
// @match        *://*.musicbrainz.org/cdtoc/*/set-durations?tracklist=*
// @match        *://*.musicbrainz.org/cdtoc/attach*
// @match        *://*.musicbrainz.org/cdtoc/move*
// @match        *://*.musicbrainz.org/cdtoc/remove*
// @match        *://*.musicbrainz.org/edit/*/cancel*
// @match        *://*.musicbrainz.org/isrc/delete*
// @match        *://*.musicbrainz.org/label/*/edit
// @match        *://*.musicbrainz.org/label/create
// @match        *://*.musicbrainz.org/recording/*/add-isrc
// @match        *://*.musicbrainz.org/recording/*/edit
// @match        *://*.musicbrainz.org/recording/*/remove-puid*
// @match        *://*.musicbrainz.org/recording/create*
// @match        *://*.musicbrainz.org/release/*/add-cover-art
// @match        *://*.musicbrainz.org/release/*/edit
// @match        *://*.musicbrainz.org/release/*/edit-cover-art/*
// @match        *://*.musicbrainz.org/release/*/remove-cover-art/*
// @match        *://*.musicbrainz.org/release/*/reorder-cover-art
// @match        *://*.musicbrainz.org/release/add*
// @match        *://*.musicbrainz.org/release-group/*/edit
// @match        *://*.musicbrainz.org/release-group/create*
// @match        *://*.musicbrainz.org/url/*/edit
// @match        *://*.musicbrainz.org/work/*/add-iswc
// @match        *://*.musicbrainz.org/work/*/edit
// @match        *://*.musicbrainz.org/work/create*
// @run-at       document-end
// ==/UserScript==
"use strict";
/* ---------- configuration below ---------- */
var autoFocus = true; /* focuses on most clever field http://tickets.musicbrainz.org/browse/MBS-2213 */
var selectText = false; /* selects the focused field’s text */
var moreURLmatch = true; /* more URL patterns matching in add/edit links (blog, etc.) */
var tracklistEditorEnhancer = true; /* press UP↓/↑DOWN keys to navigate through track positions, names and lengths, auto clean‐up and format track length */
/* ---------- configuration above ---------- */
// work in progress, don't refrain from requesting more pages and/or fields
function mostCleverInputToFocus() {
	var i;
	switch (self.location.pathname.replace(/[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}/, "*").replace(/[0-9]+/, "*")) {
		case "/artist/*/add-alias":
		case "/work/*/add-alias":
		case "/label/*/add-alias":
		case "/artist/*/alias/*/edit":
		case "/label/*/alias/*/edit":
		case "/work/*/alias/*/edit":
			i = document.querySelector("input[id='id-edit-alias.name']");
			break;
		case "/artist/create":
		case "/artist/*/edit":
			i = document.querySelector("input[id='id-edit-artist.name']");
			break;
		case "/artist/*/edit_annotation":
		case "/label/*/edit_annotation":
		case "/recording/*/edit_annotation":
		case "/release/*/edit_annotation":
		case "/release-group/*/edit_annotation":
		case "/work/*/edit_annotation":
			i = document.querySelector("textarea[id='id-edit-annotation.text']");
			break;
		case "/cdtoc/attach":
		case "/cdtoc/move":
			i = (
				document.querySelector("input[id='id-filter-artist.query']")
				|| document.querySelector("input[id='id-filter-release.query']")
			);
			break;
		case "/edit/relationship/create_url":
			i = document.querySelector("input[id='id-ar.url']");
			if (moreURLmatch) {
// TODO: see if those selectors are not included in MBS now
// TODO: convert this code for entity edit case instead of now defunct /edit/relationship/*
				var type = document.querySelector("select[id='id-ar.link_type_id']");
				if (type) {
					i.addEventListener("keyup", function(event) {
						var urlmatch = {
							199: /6109\.jp|ameblo|blog|cocolog|instagram\.com|jugem\.jp|plaza.rakuten\.co\.jp|tumblr\.com/i, // blog
							288: /sonymusic\.co\.jp|\/disco/i, // discography
						};
						for (var utype in urlmatch) if (Object.prototype.hasOwnProperty.call(urlmatch, utype)) {
							var option = type.querySelector("option[value='" + utype + "']");
							if (option && i.value.match(urlmatch[utype])) {
								type.value = utype;
								break;
							}
						}
					}, false);
				}
			}
			break;
		case "/label/create":
		case "/label/*/edit":
			i = document.querySelector("input[id='id-edit-label.name']");
			break;
		case "/recording/create":
		case "/recording/*/edit":
			i = document.querySelector("input[id='id-edit-recording.name']");
			break;
		case "/recording/*/add-isrc":
			i = document.querySelector("input[id='id-add-isrc.isrc']");
			break;
		case "/release/add":
		case "/release/*/edit":
			if (tracklistEditorEnhancer) {
				var tracklist = document.querySelector("div#tracklist");
				if (tracklist) {
					tracklist.addEventListener("keydown", function(event) {
						// detect UP ↑ / DOWN ↓ to push cursor to upper or lower text field
						if (event.target.className.match(/pos|track-(name|length)/) && (event.key == "ArrowUp" || event.key == "ArrowDown")) {
							event.preventDefault();
							var its = tracklist.querySelectorAll("input." + event.target.className);
							var it;
							for (it = 0; it < its.length; it++) {
								if (its[it] == event.target) {
									break;
								}
							}
							it += event.key == "ArrowUp" ? -1 : 1;
							if (it >= 0 && it < its.length) {
								if (
									event.shiftKey && !event.target.className.match(/pos|track-length/)
									|| !event.shiftKey && event.target.className.match(/pos|track-length/)
									|| event.target.selectionStart == 0 && event.target.selectionEnd == event.target.value.length
								) {
									its[it].select();
								} else {
									if (event.target.selectionStart == event.target.selectionEnd && event.target.selectionStart == event.target.value.length) {
										its[it].selectionStart = its[it].value.length;
										its[it].selectionEnd = its[it].value.length;
									} else {
										its[it].selectionStart = event.target.selectionStart;
										its[it].selectionEnd = event.target.selectionEnd;
									}
								}
								its[it].focus();
							}
						}
					}, false);
				}
			}
			i = (
				document.querySelector("input#id-name")
				|| document.querySelector("select[id$='.format_id']")
			);
			break;
		case "/release/*/add-cover-art":
			i = document.querySelector("input[id='id-add-cover-art.comment']");
			break;
		case "/release/*/edit-cover-art/*":
			i = document.querySelector("input[id='id-edit-cover-art.comment']");
			break;
		case "/artist/*/tags":
		case "/label/*/tags":
		case "/recording/*/tags":
		case "/release/*/tags":
		case "/release-group/*/tags":
		case "/work/*/tags":
			i = document.querySelector("textarea[id='id-tag.tags']");
			break;
		case "/release-group/create":
		case "/url/*/edit":
			i = document.querySelector("input[id='id-edit-url.url']");
			break;
		case "/release-group/*/edit":
			i = document.querySelector("input[id='id-edit-release-group.name']");
			break;
		case "/work/create":
		case "/work/*/edit":
			i = document.querySelector("input[id='id-edit-work.name']");
			break;
		case "/work/*/add-iswc":
			i = document.querySelector("input[id='id-add-iswc.iswc']");
			break;
	}
	return i ? i : document.querySelector("textarea[id$='edit_note']");
}
if (autoFocus) {
	var input = mostCleverInputToFocus();
	if (input) {
		input.focus();
		if (input.getAttribute("type") == "text") {
			if (selectText) {
				input.select();
			} else {
				// leave cursor at the text end
				var valueLength = input.value.length;
				if (valueLength) {
					input.setSelectionRange(valueLength, valueLength);
				}
			}
		}
		highlight(input);
	}
	// re‐focus input field after related tool click http://tickets.musicbrainz.org/browse/MBS-7321
	var tools = document.querySelectorAll("input[class*='with-guesscase'] ~ button:not(.guesscase-options)");
	for (var t = 0; t < tools.length; t++) {
		tools[t].addEventListener("click", function(event) {
			var relatedInput = this.parentNode.querySelector("input");
			relatedInput.focus();
			highlight(relatedInput);
		});
	}
}
var hli;
var rgbi;
function highlight(input) {
	rgbi = 0;
	hli = setInterval(function() { hl(input); }, 50);
}
function hl(input) {
	input.style.setProperty("background-color", "rgb(255, 255, " + rgbi + ")");
	rgbi += 50;
	if (rgbi >= 255) {
		clearInterval(hli);
		input.style.removeProperty("background-color");
	}
}