mirror of
https://github.com/th-ch/youtube-music.git
synced 2026-01-17 05:02:06 +00:00
implement keybind prompt
This commit is contained in:
@ -18,7 +18,8 @@ body {
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
#data {
|
#data,
|
||||||
|
.keybindData {
|
||||||
background: unset;
|
background: unset;
|
||||||
color: whitesmoke;
|
color: whitesmoke;
|
||||||
border: 1px solid rgb(54, 54, 54);
|
border: 1px solid rgb(54, 54, 54);
|
||||||
@ -41,12 +42,35 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ok,
|
#ok,
|
||||||
#cancel {
|
#cancel,
|
||||||
|
.clearButton {
|
||||||
background-color: rgb(0, 0, 0);
|
background-color: rgb(0, 0, 0);
|
||||||
color: whitesmoke;
|
color: whitesmoke;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* For Counter Prompt */
|
||||||
.minus,
|
.minus,
|
||||||
.plus {
|
.plus {
|
||||||
background: rgb(0, 0, 0);
|
background: rgb(0, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* For Select Prompt */
|
||||||
|
option {
|
||||||
|
background-color: #07070C;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* For Keybind Prompt */
|
||||||
|
.clearButton:focus {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
.clearButton:hover {
|
||||||
|
background-color: rgb(5, 5, 5);
|
||||||
|
}
|
||||||
|
.keybindData:hover {
|
||||||
|
border: 1px solid rgb(56, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.keybindData:focus {
|
||||||
|
outline: 3px solid #1E0919;
|
||||||
|
border: 1px solid rgb(56, 0, 0);
|
||||||
|
}
|
||||||
|
|||||||
@ -6,9 +6,10 @@ const url = require("url");
|
|||||||
const path = require("path");
|
const path = require("path");
|
||||||
|
|
||||||
const DEFAULT_WIDTH = 370;
|
const DEFAULT_WIDTH = 370;
|
||||||
|
const DEFAULT_KEYBIND_WIDTH = 420;
|
||||||
const DEFAULT_COUNTER_WIDTH = 300;
|
const DEFAULT_COUNTER_WIDTH = 300;
|
||||||
const DEFAULT_HEIGHT = 160;
|
const DEFAULT_HEIGHT = 150;
|
||||||
const DEFAULT_COUNTER_HEIGHT = 150;
|
const DEFAULT_KEYBIND_HEIGHT = options => (options.length * 40) + 100;
|
||||||
|
|
||||||
function electronPrompt(options, parentWindow) {
|
function electronPrompt(options, parentWindow) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
@ -18,8 +19,8 @@ function electronPrompt(options, parentWindow) {
|
|||||||
//custom options override default
|
//custom options override default
|
||||||
const options_ = Object.assign(
|
const options_ = Object.assign(
|
||||||
{
|
{
|
||||||
width: options?.type === "counter" ? DEFAULT_COUNTER_WIDTH : DEFAULT_WIDTH,
|
width: options?.type === "counter" ? DEFAULT_COUNTER_WIDTH : options?.type === "keybind" ? DEFAULT_KEYBIND_WIDTH : DEFAULT_WIDTH,
|
||||||
height: options?.type === "counter" ? DEFAULT_COUNTER_HEIGHT : DEFAULT_HEIGHT,
|
height: options?.type === "keybind" && options?.keybindOptions ? DEFAULT_KEYBIND_HEIGHT(options.keybindOptions) : DEFAULT_HEIGHT,
|
||||||
resizable: false,
|
resizable: false,
|
||||||
title: "Prompt",
|
title: "Prompt",
|
||||||
label: "Please input a value:",
|
label: "Please input a value:",
|
||||||
@ -28,6 +29,7 @@ function electronPrompt(options, parentWindow) {
|
|||||||
value: null,
|
value: null,
|
||||||
type: "input",
|
type: "input",
|
||||||
selectOptions: null,
|
selectOptions: null,
|
||||||
|
keybindOptions: null,
|
||||||
counterOptions: { minimum: null, maximum: null, multiFire: false },
|
counterOptions: { minimum: null, maximum: null, multiFire: false },
|
||||||
icon: null,
|
icon: null,
|
||||||
useHtmlLabel: false,
|
useHtmlLabel: false,
|
||||||
@ -41,22 +43,21 @@ function electronPrompt(options, parentWindow) {
|
|||||||
options || {}
|
options || {}
|
||||||
);
|
);
|
||||||
|
|
||||||
options_.minWidth = options?.minWidth || options?.width || options_.width;
|
|
||||||
options_.minHeight = options?.minHeight || options?.height || options_.height;
|
|
||||||
|
|
||||||
if (options_.customStylesheet === "dark") {
|
if (options_.customStylesheet === "dark") {
|
||||||
options_.customStylesheet = require("path").join(__dirname, "dark-prompt.css");
|
options_.customStylesheet = require("path").join(__dirname, "dark-prompt.css");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options_.type === "counter" && (options_.counterOptions !== null && typeof options_.selectOptions !== "object")) {
|
for (let type of ["counter", "select", "keybind"]) {
|
||||||
reject(new Error('"counterOptions" must be an object if specified'));
|
if (options_.type === type && (!options_[`${type}Options`] || typeof options_[`${type}Options`] !== "object")) {
|
||||||
return;
|
reject(new Error(`"${type}Options" must be an object if type = ${type}`));
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options_.type === "select" && (options_.selectOptions === null || typeof options_.selectOptions !== "object")) {
|
options_.minWidth = options?.minWidth || options?.width || options_.width;
|
||||||
reject(new Error('"selectOptions" must be an object'));
|
options_.minHeight = options?.minHeight || options?.height || options_.height;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let promptWindow = new BrowserWindow({
|
let promptWindow = new BrowserWindow({
|
||||||
frame: options_.frame,
|
frame: options_.frame,
|
||||||
@ -104,6 +105,11 @@ function electronPrompt(options, parentWindow) {
|
|||||||
|
|
||||||
//get input from front
|
//get input from front
|
||||||
const postDataListener = (event, value) => {
|
const postDataListener = (event, value) => {
|
||||||
|
if (options_.type === "keybind" && value) {
|
||||||
|
for (let i=0; i < value.length ;i++) {
|
||||||
|
value[i] = JSON.parse(value[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
resolve(value);
|
resolve(value);
|
||||||
event.returnValue = null;
|
event.returnValue = null;
|
||||||
cleanup();
|
cleanup();
|
||||||
@ -135,7 +141,7 @@ function electronPrompt(options, parentWindow) {
|
|||||||
|
|
||||||
//should never happen
|
//should never happen
|
||||||
promptWindow.webContents.on("did-fail-load", (
|
promptWindow.webContents.on("did-fail-load", (
|
||||||
event,
|
_event,
|
||||||
errorCode,
|
errorCode,
|
||||||
errorDescription,
|
errorDescription,
|
||||||
validatedURL
|
validatedURL
|
||||||
|
|||||||
140
providers/prompt/page/counter.js
Normal file
140
providers/prompt/page/counter.js
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
const { promptCreateInput } = require("./prompt");
|
||||||
|
|
||||||
|
module.exports = { promptCreateCounter , validateCounterInput }
|
||||||
|
|
||||||
|
let options;
|
||||||
|
|
||||||
|
|
||||||
|
function promptCreateCounter(promptOptions, parentElement) {
|
||||||
|
options = promptOptions;
|
||||||
|
if (options.counterOptions?.multiFire) {
|
||||||
|
document.onmouseup = () => {
|
||||||
|
if (nextTimeoutID) {
|
||||||
|
clearTimeout(nextTimeoutID)
|
||||||
|
nextTimeoutID = null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
options.value = validateCounterInput(options.value);
|
||||||
|
|
||||||
|
const dataElement = promptCreateInput();
|
||||||
|
dataElement.onkeypress = function isNumberKey(e) {
|
||||||
|
if (Number.isNaN(parseInt(e.key)) && e.key !== "Backspace" && e.key !== "Delete")
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
dataElement.style.width = "unset";
|
||||||
|
dataElement.style["text-align"] = "center";
|
||||||
|
|
||||||
|
parentElement.append(createMinusButton(dataElement));
|
||||||
|
parentElement.append(dataElement);
|
||||||
|
parentElement.append(createPlusButton(dataElement));
|
||||||
|
|
||||||
|
return dataElement;
|
||||||
|
}
|
||||||
|
|
||||||
|
let nextTimeoutID = null;
|
||||||
|
|
||||||
|
/** Function execute callback in 3 accelerated intervals based on timer.
|
||||||
|
* Terminated from document.onmouseup() that is registered from promptCreateCounter()
|
||||||
|
* @param {function} callback function to execute
|
||||||
|
* @param {object} timer {
|
||||||
|
* * time: First delay in miliseconds
|
||||||
|
* * scaleSpeed: Speed change per tick on first acceleration
|
||||||
|
* * limit: First Speed Limit, gets divided by 2 after $20 calls. $number change exponentially
|
||||||
|
* }
|
||||||
|
* @param {int} stepArgs argument for callback representing Initial steps per click, default to 1
|
||||||
|
* steps starts to increase when speed is too fast to notice
|
||||||
|
* @param {int} counter used internally to decrease timer.limit
|
||||||
|
*/
|
||||||
|
function multiFire(callback, timer = { time: 300, scaleSpeed: 100, limit: 100 }, stepsArg = 1, counter = 0) {
|
||||||
|
callback(stepsArg);
|
||||||
|
|
||||||
|
const nextTimeout = timer.time;
|
||||||
|
|
||||||
|
if (counter > 20) {
|
||||||
|
counter = 0 - stepsArg;
|
||||||
|
if (timer.limit > 1) {
|
||||||
|
timer.limit /= 2;
|
||||||
|
} else {
|
||||||
|
stepsArg *= 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (timer.time !== timer.limit) {
|
||||||
|
timer.time = Math.max(timer.time - timer.scaleSpeed, timer.limit)
|
||||||
|
}
|
||||||
|
|
||||||
|
nextTimeoutID = setTimeout(
|
||||||
|
multiFire, //callback
|
||||||
|
nextTimeout, //timer
|
||||||
|
//multiFire args:
|
||||||
|
callback,
|
||||||
|
timer,
|
||||||
|
stepsArg,
|
||||||
|
counter + 1
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function createMinusButton(dataElement) {
|
||||||
|
function doMinus(steps) {
|
||||||
|
dataElement.value = validateCounterInput(parseInt(dataElement.value) - steps);
|
||||||
|
}
|
||||||
|
|
||||||
|
const minusBtn = document.createElement("span");
|
||||||
|
minusBtn.textContent = "-";
|
||||||
|
minusBtn.classList.add("minus");
|
||||||
|
|
||||||
|
if (options.counterOptions?.multiFire) {
|
||||||
|
minusBtn.onmousedown = () => {
|
||||||
|
multiFire(doMinus);
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
minusBtn.onmousedown = () => {
|
||||||
|
doMinus();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return minusBtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
function createPlusButton(dataElement) {
|
||||||
|
function doPlus(steps) {
|
||||||
|
dataElement.value = validateCounterInput(parseInt(dataElement.value) + steps);
|
||||||
|
}
|
||||||
|
|
||||||
|
const plusBtn = document.createElement("span");
|
||||||
|
plusBtn.textContent = "+";
|
||||||
|
plusBtn.classList.add("plus");
|
||||||
|
|
||||||
|
if (options.counterOptions?.multiFire) {
|
||||||
|
plusBtn.onmousedown = () => {
|
||||||
|
multiFire(doPlus);
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
plusBtn.onmousedown = () => {
|
||||||
|
doPlus();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return plusBtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
//validate counter
|
||||||
|
function validateCounterInput(input) {
|
||||||
|
|
||||||
|
const min = options.counterOptions?.minimum;
|
||||||
|
const max = options.counterOptions?.maximum;
|
||||||
|
//note that !min/max would proc if min/max are 0
|
||||||
|
if (min !== null && min !== undefined && input < min) {
|
||||||
|
return min;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (max !== null && max !== undefined && input > max) {
|
||||||
|
return max;
|
||||||
|
}
|
||||||
|
|
||||||
|
return input;
|
||||||
|
}
|
||||||
305
providers/prompt/page/keybind.js
Normal file
305
providers/prompt/page/keybind.js
Normal file
@ -0,0 +1,305 @@
|
|||||||
|
/* HTML
|
||||||
|
|
||||||
|
<div class="keybind" , id="div">
|
||||||
|
<label id="label" class="keybindLabel">Example</label>
|
||||||
|
<input readonly type="text" id="txt" class="keybindData">
|
||||||
|
<button id="clear" class="clearButton">
|
||||||
|
Clear
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
*/
|
||||||
|
/* CSS
|
||||||
|
|
||||||
|
div.keybind {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: max-content max-content max-content;
|
||||||
|
grid-gap: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.keybind button {
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.keybind label {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.keybind label:after {
|
||||||
|
content: ":";
|
||||||
|
}
|
||||||
|
|
||||||
|
*/
|
||||||
|
const { promptError } = require("./prompt")
|
||||||
|
|
||||||
|
class KeybindGetter {
|
||||||
|
value = null;
|
||||||
|
modifiers = null;
|
||||||
|
key = "";
|
||||||
|
label = null;
|
||||||
|
txt = null;
|
||||||
|
clearButton = null;
|
||||||
|
|
||||||
|
constructor(options, parentElement) {
|
||||||
|
if (!options.label || !options.value) {
|
||||||
|
promptError("keybind option must contain label and value");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.value = options.value
|
||||||
|
this.modifiers = new Set();
|
||||||
|
this.key = "";
|
||||||
|
|
||||||
|
this.label = document.createElement("label");
|
||||||
|
this.label.classList.add("keybindLabel");
|
||||||
|
|
||||||
|
this.txt = document.createElement("input");
|
||||||
|
this.txt.setAttribute('readonly', true);
|
||||||
|
this.txt.classList.add("keybindData");
|
||||||
|
|
||||||
|
this.clearButton = document.createElement("button");
|
||||||
|
this.clearButton.classList.add("clearButton");
|
||||||
|
this.clearButton.textContent = "Clear";
|
||||||
|
this.clearButton.onclick = (e) => e.preventDefault();
|
||||||
|
|
||||||
|
parentElement.append(this.label, this.txt, this.clearButton);
|
||||||
|
|
||||||
|
this.setup(options);
|
||||||
|
if (options.default) {
|
||||||
|
this.setDefault(options.default)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
focus() {
|
||||||
|
this.txt.focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
output() {
|
||||||
|
const output = {value: this.value, accelerator: this.txt.value.replaceAll(" ", "")}
|
||||||
|
return JSON.stringify(output);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateText() {
|
||||||
|
let result = "";
|
||||||
|
for (let modifier of this.modifiers) {
|
||||||
|
result += modifier + " + ";
|
||||||
|
}
|
||||||
|
this.txt.value = result + this.key;
|
||||||
|
}
|
||||||
|
|
||||||
|
setDefault(defaultValue) {
|
||||||
|
const accelerator = parseAccelerator(defaultValue).split("+");
|
||||||
|
for (let key of accelerator) {
|
||||||
|
if (isModifier(key))
|
||||||
|
this.modifiers.add(key);
|
||||||
|
else
|
||||||
|
this.key = key;
|
||||||
|
}
|
||||||
|
this.updateText();
|
||||||
|
}
|
||||||
|
clear() {
|
||||||
|
this.modifiers.clear();
|
||||||
|
this.key = "";
|
||||||
|
this.txt.value = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
setup(options) {
|
||||||
|
this.txt.addEventListener("keydown", (event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
if (event.repeat) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let key = event.code || event.key;
|
||||||
|
if (key in virtualKeyCodes)
|
||||||
|
key = virtualKeyCodes[event.code];
|
||||||
|
else {
|
||||||
|
console.log('Error, key "' + event.code + '" was not found');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isModifier(key)) {
|
||||||
|
if (this.modifiers.size < 3)
|
||||||
|
this.modifiers.add(key);
|
||||||
|
} else { // is key
|
||||||
|
this.key = key;
|
||||||
|
}
|
||||||
|
this.updateText();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.clearButton.addEventListener("click", () => {
|
||||||
|
this.clear()
|
||||||
|
});
|
||||||
|
this.label.textContent = options.label + " ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class keybindContainer {
|
||||||
|
elements = [];
|
||||||
|
|
||||||
|
constructor(options, parentElement) {
|
||||||
|
parentElement.classList.add("keybind");
|
||||||
|
this.elements = options.map(option => new KeybindGetter(option, parentElement));
|
||||||
|
document.querySelector("#buttons").style["padding-top"] = "20px";
|
||||||
|
}
|
||||||
|
|
||||||
|
focus() {
|
||||||
|
if (this.elements.length > 0)
|
||||||
|
this.elements[0].focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
submit() {
|
||||||
|
return this.elements.map(element => element.output());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseAccelerator(a) {
|
||||||
|
let accelerator = a.toString();
|
||||||
|
|
||||||
|
if (process.platform !== 'darwin') {
|
||||||
|
accelerator = accelerator.replace(/(Cmd)|(Command)/gi, '');
|
||||||
|
} else {
|
||||||
|
accelerator = accelerator.replace(/(Ctrl)|(Control)/gi, '');
|
||||||
|
}
|
||||||
|
|
||||||
|
accelerator = accelerator.replace(/(Or)/gi, '');
|
||||||
|
|
||||||
|
return accelerator;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isModifier(key) {
|
||||||
|
for (let modifier of ["Shift", "Control", "Ctrl", "Command", "Cmd", "Alt", "AltGr", "Super"]) {
|
||||||
|
if (key === modifier)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const virtualKeyCodes = {
|
||||||
|
ShiftLeft: "Shift",
|
||||||
|
ShiftRight: "Shift",
|
||||||
|
ControlLeft: "Ctrl",
|
||||||
|
ControlRight: "Ctrl",
|
||||||
|
AltLeft: "Alt",
|
||||||
|
AltRight: "Alt",
|
||||||
|
MetaLeft: "Super",
|
||||||
|
MetaRight: "Super",
|
||||||
|
NumLock: "NumLock",
|
||||||
|
NumpadDivide: "NumDiv",
|
||||||
|
NumpadMultiply: "NumMult",
|
||||||
|
NumpadSubtract: "NumSub",
|
||||||
|
NumpadAdd: "NumAdd",
|
||||||
|
NumpadDecimal: "NumDec ",
|
||||||
|
Numpad0: "Num0",
|
||||||
|
Numpad1: "Num1",
|
||||||
|
Numpad2: "Num2",
|
||||||
|
Numpad3: "Num3",
|
||||||
|
Numpad4: "Num4",
|
||||||
|
Numpad5: "Num5",
|
||||||
|
Numpad6: "Num6",
|
||||||
|
Numpad7: "Num7",
|
||||||
|
Numpad8: "Num8",
|
||||||
|
Numpad9: "Num9",
|
||||||
|
Digit0: "0",
|
||||||
|
Digit1: "1",
|
||||||
|
Digit2: "2",
|
||||||
|
Digit3: "3",
|
||||||
|
Digit4: "4",
|
||||||
|
Digit5: "5",
|
||||||
|
Digit6: "6",
|
||||||
|
Digit7: "7",
|
||||||
|
Digit8: "8",
|
||||||
|
Digit9: "9",
|
||||||
|
Minus: "-",
|
||||||
|
Equal: "=",
|
||||||
|
KeyQ: "Q",
|
||||||
|
KeyW: "W",
|
||||||
|
KeyE: "E",
|
||||||
|
KeyR: "R",
|
||||||
|
KeyT: "T",
|
||||||
|
KeyY: "Y",
|
||||||
|
KeyU: "U",
|
||||||
|
KeyI: "I",
|
||||||
|
KeyO: "O",
|
||||||
|
KeyP: "P",
|
||||||
|
KeyA: "A",
|
||||||
|
KeyS: "S",
|
||||||
|
KeyD: "D",
|
||||||
|
KeyF: "F",
|
||||||
|
KeyG: "G",
|
||||||
|
KeyH: "H",
|
||||||
|
KeyJ: "J",
|
||||||
|
KeyK: "K",
|
||||||
|
KeyL: "L",
|
||||||
|
KeyZ: "Z",
|
||||||
|
KeyX: "X",
|
||||||
|
KeyC: "C",
|
||||||
|
KeyV: "V",
|
||||||
|
KeyB: "B",
|
||||||
|
KeyN: "N",
|
||||||
|
KeyM: "M",
|
||||||
|
BracketLeft: "[",
|
||||||
|
BracketRight: "]",
|
||||||
|
Semicolon: ";",
|
||||||
|
Quote: "'",
|
||||||
|
Backquote: '"',
|
||||||
|
Backslash: "\\",
|
||||||
|
Comma: ",",
|
||||||
|
Period: "'.'",
|
||||||
|
Slash: "/",
|
||||||
|
plus: '+',
|
||||||
|
Space: "Space",
|
||||||
|
Tab: "Tab",
|
||||||
|
Backspace: "Backspace",
|
||||||
|
Delete: "Delete",
|
||||||
|
Insert: "Insert",
|
||||||
|
Return: "Return",
|
||||||
|
Enter: "Enter",
|
||||||
|
ArrowUp: "Up",
|
||||||
|
ArrowDown: "Down",
|
||||||
|
ArrowLeft: "Left",
|
||||||
|
ArrowRight: "Right",
|
||||||
|
Home: "Home",
|
||||||
|
End: "End",
|
||||||
|
PageUp: "PageUp",
|
||||||
|
PageDown: "PageDown",
|
||||||
|
Escape: "Escape",
|
||||||
|
AudioVolumeUp: "VolumeUp",
|
||||||
|
AudioVolumeDown: "VolumeDown",
|
||||||
|
AudioVolumeMute: "VolumeMute",
|
||||||
|
MediaTrackNext: "MediaNextTrack",
|
||||||
|
MediaTrackPrevious: "MediaPreviousTrack",
|
||||||
|
MediaStop: "MediaStop",
|
||||||
|
MediaPlayPause: "MediaPlayPause",
|
||||||
|
ScrollLock: "ScrollLock",
|
||||||
|
PrintScreen: "PrintScreen",
|
||||||
|
F1: "F1",
|
||||||
|
F2: "F2",
|
||||||
|
F3: "F3",
|
||||||
|
F4: "F4",
|
||||||
|
F5: "F5",
|
||||||
|
F6: "F6",
|
||||||
|
F7: "F7",
|
||||||
|
F8: "F8",
|
||||||
|
F9: "F9",
|
||||||
|
F10: "F10",
|
||||||
|
F11: "F11",
|
||||||
|
F12: "F12",
|
||||||
|
F13: "F13",
|
||||||
|
F14: "F14",
|
||||||
|
F15: "F15",
|
||||||
|
F16: "F16",
|
||||||
|
F17: "F17",
|
||||||
|
F18: "F18",
|
||||||
|
F19: "F19",
|
||||||
|
F20: "F20",
|
||||||
|
F21: "F21",
|
||||||
|
F22: "F22",
|
||||||
|
F23: "F23",
|
||||||
|
F24: "F24",
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = function promptCreateKeybind(options, parentElement) {
|
||||||
|
return new keybindContainer(options, parentElement);
|
||||||
|
}
|
||||||
@ -79,7 +79,7 @@ select#data {
|
|||||||
color: black;
|
color: black;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Counter mode css */
|
/* Counter mode */
|
||||||
span {
|
span {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
@ -96,3 +96,25 @@ span {
|
|||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Keybind mode */
|
||||||
|
div.keybind {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: max-content max-content max-content;
|
||||||
|
row-gap: 20px;
|
||||||
|
column-gap: 10px;
|
||||||
|
margin: auto 0;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.keybind button {
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.keybind label {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.keybind label:after {
|
||||||
|
content: ":";
|
||||||
|
}
|
||||||
@ -1,16 +1,15 @@
|
|||||||
const fs = require("fs");
|
const fs = require("fs");
|
||||||
const { ipcRenderer } = require("electron");
|
const { ipcRenderer } = require("electron");
|
||||||
|
|
||||||
let promptId = null;
|
let promptId = null;
|
||||||
let promptOptions = null;
|
let promptOptions = null;
|
||||||
|
let dataElement = null;
|
||||||
|
|
||||||
function $(selector) {
|
function $(selector) { return document.querySelector(selector); }
|
||||||
return document.querySelector(selector);
|
|
||||||
}
|
|
||||||
|
|
||||||
document.addEventListener("DOMContentLoaded", promptRegister);
|
document.addEventListener("DOMContentLoaded", promptRegister);
|
||||||
|
|
||||||
function promptRegister() {
|
function promptRegister() {
|
||||||
|
|
||||||
//get custom session id
|
//get custom session id
|
||||||
promptId = document.location.hash.replace("#", "");
|
promptId = document.location.hash.replace("#", "");
|
||||||
|
|
||||||
@ -56,13 +55,12 @@ function promptRegister() {
|
|||||||
$("#form").addEventListener("submit", promptSubmit);
|
$("#form").addEventListener("submit", promptSubmit);
|
||||||
$("#cancel").addEventListener("click", promptCancel);
|
$("#cancel").addEventListener("click", promptCancel);
|
||||||
|
|
||||||
//create input/select
|
//create input/select/counter/keybind
|
||||||
const dataContainerElement = $("#data-container");
|
const dataContainerElement = $("#data-container");
|
||||||
let dataElement;
|
|
||||||
|
|
||||||
switch (promptOptions.type) {
|
switch (promptOptions.type) {
|
||||||
case "counter":
|
case "counter":
|
||||||
dataElement = promptCreateCounter();
|
dataElement = promptCreateCounter(dataContainerElement);
|
||||||
break;
|
break;
|
||||||
case "input":
|
case "input":
|
||||||
dataElement = promptCreateInput();
|
dataElement = promptCreateInput();
|
||||||
@ -70,22 +68,24 @@ function promptRegister() {
|
|||||||
case "select":
|
case "select":
|
||||||
dataElement = promptCreateSelect();
|
dataElement = promptCreateSelect();
|
||||||
break;
|
break;
|
||||||
|
case "keybind":
|
||||||
|
dataElement = require("./keybind")(promptOptions.keybindOptions, dataContainerElement);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return promptError(`Unhandled input type '${promptOptions.type}'`);
|
return promptError(`Unhandled input type '${promptOptions.type}'`);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (promptOptions.type === "counter") {
|
if (promptOptions.type != "keybind") {
|
||||||
dataContainerElement.append(createMinusButton(dataElement));
|
dataElement.setAttribute("id", "data");
|
||||||
dataContainerElement.append(dataElement);
|
|
||||||
dataContainerElement.append(createPlusButton(dataElement));
|
if (promptOptions.type !== "counter") {
|
||||||
} else {
|
dataContainerElement.append(dataElement);
|
||||||
dataContainerElement.append(dataElement);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dataElement.setAttribute("id", "data");
|
|
||||||
dataElement.focus();
|
dataElement.focus();
|
||||||
|
|
||||||
if (promptOptions.type === "input" || promptOptions.type === "counter") {
|
if (promptOptions.type !== "select" && promptOptions.type !== "keybind") {
|
||||||
dataElement.select();
|
dataElement.select();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -100,10 +100,10 @@ function promptRegister() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
window.addEventListener("error", error => {
|
window.addEventListener("error", event => {
|
||||||
if (promptId) {
|
if (promptId) {
|
||||||
promptError("An error has occured on the prompt window: \n" +
|
promptError("An error has occured on the prompt window: \n" +
|
||||||
JSON.stringify(error, ["message", "arguments", "type", "name"])
|
`Message: ${event.message}\nURL: ${event.url}\nLine: ${event.lineNo}, Column: ${event.columnNo}\nStack: ${event.error.stack}`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -111,7 +111,7 @@ window.addEventListener("error", error => {
|
|||||||
//send error to back
|
//send error to back
|
||||||
function promptError(error) {
|
function promptError(error) {
|
||||||
if (error instanceof Error) {
|
if (error instanceof Error) {
|
||||||
error = error.message;
|
error = error.message + "\n" + error.stack;
|
||||||
}
|
}
|
||||||
|
|
||||||
ipcRenderer.sendSync("prompt-error:" + promptId, error);
|
ipcRenderer.sendSync("prompt-error:" + promptId, error);
|
||||||
@ -124,20 +124,18 @@ function promptCancel() {
|
|||||||
|
|
||||||
//transfer input data to back
|
//transfer input data to back
|
||||||
function promptSubmit() {
|
function promptSubmit() {
|
||||||
const dataElement = $("#data");
|
|
||||||
let data = null;
|
let data = null;
|
||||||
|
|
||||||
switch (promptOptions.type) {
|
switch (promptOptions.type) {
|
||||||
case "input":
|
case "input":
|
||||||
|
case "select":
|
||||||
data = dataElement.value;
|
data = dataElement.value;
|
||||||
break;
|
break;
|
||||||
case "counter":
|
case "counter":
|
||||||
data = validateCounterInput(dataElement.value);
|
data = validateCounterInput(dataElement.value);
|
||||||
break;
|
break;
|
||||||
case "select":
|
case "keybind":
|
||||||
data = promptOptions.selectMultiple ?
|
data = dataElement.submit();
|
||||||
dataElement.querySelectorAll("option[selected]").map(o => o.getAttribute("value")) :
|
|
||||||
dataElement.value;
|
|
||||||
break;
|
break;
|
||||||
default: //will never happen
|
default: //will never happen
|
||||||
return promptError(`Unhandled input type '${promptOptions.type}'`);
|
return promptError(`Unhandled input type '${promptOptions.type}'`);
|
||||||
@ -152,9 +150,6 @@ function promptCreateInput() {
|
|||||||
dataElement.setAttribute("type", "text");
|
dataElement.setAttribute("type", "text");
|
||||||
|
|
||||||
if (promptOptions.value) {
|
if (promptOptions.value) {
|
||||||
if (promptOptions.type === "counter") {
|
|
||||||
promptOptions.value = validateCounterInput(promptOptions.value);
|
|
||||||
}
|
|
||||||
dataElement.value = promptOptions.value;
|
dataElement.value = promptOptions.value;
|
||||||
} else {
|
} else {
|
||||||
dataElement.value = "";
|
dataElement.value = "";
|
||||||
@ -212,21 +207,50 @@ function promptCreateSelect() {
|
|||||||
return dataElement;
|
return dataElement;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function promptCreateCounter(parentElement) {
|
||||||
|
if (promptOptions.counterOptions?.multiFire) {
|
||||||
|
document.onmouseup = () => {
|
||||||
|
if (nextTimeoutID) {
|
||||||
|
clearTimeout(nextTimeoutID)
|
||||||
|
nextTimeoutID = null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
promptOptions.value = validateCounterInput(promptOptions.value);
|
||||||
|
|
||||||
|
const dataElement = promptCreateInput();
|
||||||
|
dataElement.onkeypress = function isNumberKey(e) {
|
||||||
|
if (Number.isNaN(parseInt(e.key)) && e.key !== "Backspace" && e.key !== "Delete")
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
dataElement.style.width = "unset";
|
||||||
|
dataElement.style["text-align"] = "center";
|
||||||
|
|
||||||
|
parentElement.append(createMinusButton(dataElement));
|
||||||
|
parentElement.append(dataElement);
|
||||||
|
parentElement.append(createPlusButton(dataElement));
|
||||||
|
|
||||||
|
return dataElement;
|
||||||
|
}
|
||||||
|
|
||||||
let nextTimeoutID = null;
|
let nextTimeoutID = null;
|
||||||
|
|
||||||
/* Function execute callback in 3 accelerated intervals based on timer.
|
/** Function execute callback in 3 accelerated intervals based on timer.
|
||||||
* Terminated from document.onmouseup() that is registered from promptCreateCounter()
|
* Terminated from document.onmouseup() that is registered from promptCreateCounter()
|
||||||
* @param {function} callback: function to execute
|
* @param {function} callback function to execute
|
||||||
* @param {object} timer: {
|
* @param {object} timer {
|
||||||
* * time: First delay in miliseconds.
|
* * time: First delay in miliseconds
|
||||||
* * limit: First Speed Limit, gets divided by 2 after $20 calls. $number change exponentially
|
|
||||||
* * scaleSpeed: Speed change per tick on first acceleration
|
* * scaleSpeed: Speed change per tick on first acceleration
|
||||||
* }
|
* * limit: First Speed Limit, gets divided by 2 after $20 calls. $number change exponentially
|
||||||
* @param {int} stepArgs: argument for callback representing Initial steps per click, default to 1
|
* }
|
||||||
|
* @param {int} stepArgs argument for callback representing Initial steps per click, default to 1
|
||||||
* steps starts to increase when speed is too fast to notice
|
* steps starts to increase when speed is too fast to notice
|
||||||
* @param {int} counter: used internally to decrease timer.limit
|
* @param {int} counter used internally to decrease timer.limit
|
||||||
*/
|
*/
|
||||||
function multiFire(callback, timer = { time: 500, scaleSpeed: 140, limit: 100 }, stepsArg = 1, counter = 0) {
|
function multiFire(callback, timer = { time: 300, scaleSpeed: 100, limit: 100 }, stepsArg = 1, counter = 0) {
|
||||||
callback(stepsArg);
|
callback(stepsArg);
|
||||||
|
|
||||||
const nextTimeout = timer.time;
|
const nextTimeout = timer.time;
|
||||||
@ -241,9 +265,7 @@ function multiFire(callback, timer = { time: 500, scaleSpeed: 140, limit: 100 },
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (timer.time !== timer.limit) {
|
if (timer.time !== timer.limit) {
|
||||||
timer.time = timer.time > timer.limit ?
|
timer.time = Math.max(timer.time - timer.scaleSpeed, timer.limit)
|
||||||
timer.time - timer.scaleSpeed :
|
|
||||||
timer.limit;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
nextTimeoutID = setTimeout(
|
nextTimeoutID = setTimeout(
|
||||||
@ -301,26 +323,9 @@ function createPlusButton(dataElement) {
|
|||||||
return plusBtn;
|
return plusBtn;
|
||||||
}
|
}
|
||||||
|
|
||||||
function promptCreateCounter() {
|
|
||||||
if (promptOptions.counterOptions?.multiFire) {
|
|
||||||
document.onmouseup = () => {
|
|
||||||
if (nextTimeoutID) {
|
|
||||||
clearTimeout(nextTimeoutID)
|
|
||||||
nextTimeoutID = null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const dataElement = promptCreateInput();
|
|
||||||
|
|
||||||
dataElement.style.width = "unset";
|
|
||||||
dataElement.style["text-align"] = "center";
|
|
||||||
|
|
||||||
return dataElement;
|
|
||||||
}
|
|
||||||
|
|
||||||
//validate counter
|
//validate counter
|
||||||
function validateCounterInput(input) {
|
function validateCounterInput(input) {
|
||||||
|
|
||||||
const min = promptOptions.counterOptions?.minimum;
|
const min = promptOptions.counterOptions?.minimum;
|
||||||
const max = promptOptions.counterOptions?.maximum;
|
const max = promptOptions.counterOptions?.maximum;
|
||||||
//note that !min/max would proc if min/max are 0
|
//note that !min/max would proc if min/max are 0
|
||||||
@ -334,3 +339,6 @@ function validateCounterInput(input) {
|
|||||||
|
|
||||||
return input;
|
return input;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
module.exports.promptError = promptError;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user