Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
130 lines
6.1 KiB
JavaScript
130 lines
6.1 KiB
JavaScript
// ==UserScript==
|
|
// @name BIPP: sneltoetsen voor knoppen
|
|
// @namespace https://github.com/glgoose/ua-userscripts
|
|
// @version 1.3.0
|
|
// @description Sneltoetsen per rol van de knop, in het Nederlands en het Engels: Ctrl+Enter (Bevestigen/Authorization/Approve, anders Indienen/Submit), Ctrl+S (Opslaan/Save), Ctrl+[ (Terug/Back), Alt+S (Zoeken/Search), Alt+R (Reset), Alt+N (Nieuw/New), Alt+C (Annuleren/Cancel), Alt+H (In wachtstand/On hold). Bij ingedrukte Ctrl, Cmd of Alt verschijnt de sneltoets onder de knop.
|
|
// @author glgoose
|
|
// @license GPL-3.0-or-later
|
|
// @homepageURL https://gitea.flw.uantwerpen.be/glenn/ua-userscripts/src/branch/main/scripts/bipp-sneltoetsen
|
|
// @supportURL https://gitea.flw.uantwerpen.be/glenn/ua-userscripts/issues
|
|
// @downloadURL https://gitea.flw.uantwerpen.be/glenn/ua-userscripts/raw/branch/main/scripts/bipp-sneltoetsen/bipp-sneltoetsen.user.js
|
|
// @updateURL https://gitea.flw.uantwerpen.be/glenn/ua-userscripts/raw/branch/main/scripts/bipp-sneltoetsen/bipp-sneltoetsen.user.js
|
|
// @match https://bipp.biotechpartner.be/web/*
|
|
// @run-at document-idle
|
|
// @grant none
|
|
// ==/UserScript==
|
|
(function () {
|
|
'use strict';
|
|
|
|
// Een sneltoets hangt aan de rol van de knop, niet aan een letter uit het label, dus NL en EN delen dezelfde toets.
|
|
// labels: kleine letters, in volgorde van voorrang (de eerste die op de pagina staat wint).
|
|
// match: welke toetscombinatie het is. hint: wat de tooltip en de hint onder de knop tonen.
|
|
var KEYS = [
|
|
{ labels: ['bevestigen', 'authorization', 'approve', 'goedkeuren', 'confirm', 'indienen', 'submit'],
|
|
// Op een Mac werkt Cmd+Enter ook, maar de hint blijft overal Ctrl+Enter.
|
|
hint: 'Ctrl+Enter',
|
|
match: function (e) { return (e.code === 'Enter' || e.code === 'NumpadEnter') && (e.ctrlKey || e.metaKey) && !(e.ctrlKey && e.metaKey) && !e.altKey && !e.shiftKey; } },
|
|
{ labels: ['zoeken', 'search'], hint: 'Alt+S', match: alt('KeyS') },
|
|
{ labels: ['opslaan', 'save'], hint: 'Ctrl+S', match: ctrl('KeyS') },
|
|
{ labels: ['terug', 'back'], hint: 'Ctrl+[', match: ctrl('BracketLeft') },
|
|
{ labels: ['reset'], hint: 'Alt+R', match: alt('KeyR') },
|
|
{ labels: ['nieuw', 'new'], hint: 'Alt+N', match: alt('KeyN') },
|
|
{ labels: ['annuleren', 'cancel'], hint: 'Alt+C', match: alt('KeyC') },
|
|
{ labels: ['in wachtstand', 'on hold'], hint: 'Alt+H', match: alt('KeyH') }
|
|
];
|
|
var MARK = 'data-bipp-sneltoets';
|
|
|
|
// Alt voor de zijacties: Ctrl+N, Ctrl+F en Ctrl+R zijn browsertoetsen, en Ctrl+Alt is AltGr op Windows.
|
|
function alt(code) {
|
|
return function (e) { return e.code === code && e.altKey && !e.ctrlKey && !e.metaKey && !e.shiftKey; };
|
|
}
|
|
|
|
// Alleen Ctrl: Cmd blijft bij de browser (Cmd+F, Cmd+S, Cmd+R zijn zoeken, opslaan en herladen).
|
|
function ctrl(code) {
|
|
return function (e) { return e.code === code && e.ctrlKey && !e.metaKey && !e.altKey && !e.shiftKey; };
|
|
}
|
|
|
|
function norm(s) { return (s || '').replace(/\s+/g, ' ').trim().toLowerCase(); }
|
|
|
|
function visible(el) { return !!(el.offsetWidth || el.offsetHeight || el.getClientRects().length); }
|
|
|
|
// Per label (op volgorde van voorrang) de eerste zichtbare, actieve knop. Een postback-pagina kan er verborgen kopieën van hebben.
|
|
function findButton(k) {
|
|
var btns = document.querySelectorAll('input[type="submit"], input[type="button"], button');
|
|
for (var l = 0; l < k.labels.length; l++) {
|
|
for (var i = 0; i < btns.length; i++) {
|
|
var b = btns[i];
|
|
if (norm(b.value || b.textContent) === k.labels[l] && !b.disabled && visible(b)) return b;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
function mark(btn, k) {
|
|
if (btn.getAttribute(MARK)) return;
|
|
btn.setAttribute(MARK, k.hint);
|
|
// BIPP zet soms zelf een title (Bevestigen): dan komt de sneltoets op een eigen regel eronder.
|
|
btn.title = btn.title ? btn.title + '\n' + k.hint : k.hint;
|
|
}
|
|
|
|
var tips = [];
|
|
function showTips() {
|
|
hideTips();
|
|
KEYS.forEach(function (k) {
|
|
var btn = findButton(k);
|
|
if (!btn) return;
|
|
var r = btn.getBoundingClientRect();
|
|
var tip = document.createElement('span');
|
|
tip.textContent = k.hint;
|
|
tip.style.cssText = 'position:absolute;z-index:99999;pointer-events:none;white-space:nowrap;' +
|
|
'font:11px ui-monospace,Menlo,Consolas,monospace;background:#1f2937;color:#fff;border-radius:4px;padding:1px 6px;' +
|
|
'left:' + (r.left + window.scrollX + r.width / 2) + 'px;top:' + (r.bottom + window.scrollY + 4) + 'px;transform:translateX(-50%)';
|
|
document.body.appendChild(tip);
|
|
tips.push(tip);
|
|
});
|
|
spread();
|
|
}
|
|
|
|
// Smalle knoppen naast elkaar geven hints die elkaar raken: schuif de volgende hint naar rechts, met een kleine tussenruimte.
|
|
function spread() {
|
|
var prevRight = -Infinity;
|
|
tips.slice().sort(function (a, b) { return a.getBoundingClientRect().left - b.getBoundingClientRect().left; })
|
|
.forEach(function (tip) {
|
|
var r = tip.getBoundingClientRect();
|
|
var shift = Math.max(0, prevRight + 4 - r.left);
|
|
if (shift) tip.style.left = (parseFloat(tip.style.left) + shift) + 'px';
|
|
prevRight = r.right + shift;
|
|
});
|
|
}
|
|
function hideTips() {
|
|
tips.forEach(function (t) { if (t.parentNode) t.parentNode.removeChild(t); });
|
|
tips = [];
|
|
}
|
|
|
|
document.addEventListener('keydown', function (e) {
|
|
if (e.key === 'Control' || e.key === 'Meta' || e.key === 'Alt') { if (!e.repeat) showTips(); return; }
|
|
for (var i = 0; i < KEYS.length; i++) {
|
|
if (!KEYS[i].match(e)) continue;
|
|
var btn = findButton(KEYS[i]);
|
|
if (!btn) return;
|
|
e.preventDefault();
|
|
hideTips();
|
|
btn.click();
|
|
return;
|
|
}
|
|
}, true);
|
|
document.addEventListener('keyup', function (e) { if (e.key === 'Control' || e.key === 'Meta' || e.key === 'Alt') hideTips(); }, true);
|
|
window.addEventListener('blur', hideTips);
|
|
|
|
// De pagina bouwt de knoppen soms pas na een postback op: probeer het een paar keer.
|
|
var tries = 0;
|
|
(function init() {
|
|
var left = 0;
|
|
KEYS.forEach(function (k) {
|
|
var btn = findButton(k);
|
|
if (btn) mark(btn, k); else left++;
|
|
});
|
|
if (left && ++tries < 30) setTimeout(init, 500);
|
|
})();
|
|
})();
|