From 8dc486f18fe02a218b149838dc7ab939ec1b698a Mon Sep 17 00:00:00 2001 From: Araxeus Date: Wed, 28 Apr 2021 02:51:19 +0300 Subject: [PATCH] remove local prompt --- menu.js | 37 --- providers/prompt/custom-titlebar.js | 14 -- providers/prompt/dark-prompt.css | 76 ------ providers/prompt/index.js | 170 -------------- providers/prompt/page/counter.js | 140 ----------- providers/prompt/page/keybind.js | 305 ------------------------ providers/prompt/page/prompt.css | 120 ---------- providers/prompt/page/prompt.html | 18 -- providers/prompt/page/prompt.js | 344 ---------------------------- providers/prompt/readme.md | 80 ------- 10 files changed, 1304 deletions(-) delete mode 100644 providers/prompt/custom-titlebar.js delete mode 100644 providers/prompt/dark-prompt.css delete mode 100644 providers/prompt/index.js delete mode 100644 providers/prompt/page/counter.js delete mode 100644 providers/prompt/page/keybind.js delete mode 100644 providers/prompt/page/prompt.css delete mode 100644 providers/prompt/page/prompt.html delete mode 100644 providers/prompt/page/prompt.js delete mode 100644 providers/prompt/readme.md diff --git a/menu.js b/menu.js index dddce721..0ab62c7f 100644 --- a/menu.js +++ b/menu.js @@ -6,7 +6,6 @@ const is = require("electron-is"); const { getAllPlugins } = require("./plugins/utils"); const config = require("./config"); -const prompt = require('./providers/prompt'); const pluginEnabledMenu = (win, plugin, label = "", hasSubmenu = false) => ({ label: label || plugin, @@ -309,39 +308,3 @@ module.exports.setApplicationMenu = (win) => { const menu = Menu.buildFromTemplate(menuTemplate); Menu.setApplicationMenu(menu); }; - -const iconPath = path.join(__dirname, "assets", "youtube-music-tray.png"); -const example = `Example: "socks5://127.0.0.1:9999"`; -function setProxy(item, win) { - let options = { - title: 'Set Proxy', - label: 'Enter Proxy Address: (leave empty to disable)', - value: config.get("options.proxy") || example, - inputAttrs: { - type: 'text' - }, - type: 'input', - icon: iconPath, - customStylesheet: "dark", - }; - //TODO: custom bar on prompt need testing on macOS - if (!is.macOS()) { - Object.assign(options, { - frame: false, - customScript: path.join(__dirname, "providers", "prompt", "custom-titlebar.js"), - enableRemoteModule: true, - height: 200, - width: 450, - }); - } - prompt(options, win) - .then(input => { - if (input !== null && input !== example) { - config.set("options.proxy", input); - item.checked = input !== ""; - } else { //user pressed cancel - item.checked = !item.checked; //reset checkbox - } - }) - .catch(console.error); -} diff --git a/providers/prompt/custom-titlebar.js b/providers/prompt/custom-titlebar.js deleted file mode 100644 index c36ce5f5..00000000 --- a/providers/prompt/custom-titlebar.js +++ /dev/null @@ -1,14 +0,0 @@ -const customTitlebar = require("custom-electron-titlebar"); - -module.exports = () => { - const bar = new customTitlebar.Titlebar({ - backgroundColor: customTitlebar.Color.fromHex("#050505"), - minimizable: false, - maximizable: false, - menu: null - }); - const mainStyle = document.querySelector("#container").style; - mainStyle.width = "100%"; - mainStyle.position = "fixed"; - mainStyle.border = "unset"; -}; diff --git a/providers/prompt/dark-prompt.css b/providers/prompt/dark-prompt.css deleted file mode 100644 index 768b9e52..00000000 --- a/providers/prompt/dark-prompt.css +++ /dev/null @@ -1,76 +0,0 @@ -body { - background-color: rgba(0, 0, 0, 0.3); - background-image: linear-gradient(315deg, #200000 0%, #13253a 74%); - color: whitesmoke; -} - -#label { - text-align: center; -} - -#container { - background: rgba(0, 0, 0, 0.7); - box-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.37); - backdrop-filter: blur(10px); - -webkit-backdrop-filter: blur(10px); - border-radius: 10px; - border: 1px solid rgba(80, 0, 0, 0.4); - overflow: hidden; -} - -#data, -.keybindData { - background: unset; - color: whitesmoke; - border: 1px solid rgb(54, 54, 54); -} - -#data:hover { - border: 1px solid rgb(85, 85, 85); -} - -#data:focus { - outline: unset; - border: 1px solid rgb(85, 85, 85); -} - -#ok:hover, -#ok:focus, -#cancel:hover, -#cancel:focus { - outline: rgba(60, 0, 0, 0.4) solid 2px; -} - -#ok, -#cancel, -.clearButton { - background-color: rgb(0, 0, 0); - color: whitesmoke; -} - -/* For Counter Prompt */ -.minus, -.plus { - 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); -} diff --git a/providers/prompt/index.js b/providers/prompt/index.js deleted file mode 100644 index a5c2230c..00000000 --- a/providers/prompt/index.js +++ /dev/null @@ -1,170 +0,0 @@ -const electron = require("electron"); - -const BrowserWindow = electron.BrowserWindow || electron.remote.BrowserWindow; -const ipcMain = electron.ipcMain || electron.remote.ipcMain; -const url = require("url"); -const path = require("path"); - -const DEFAULT_WIDTH = 370; -const DEFAULT_KEYBIND_WIDTH = 420; -const DEFAULT_COUNTER_WIDTH = 300; -const DEFAULT_HEIGHT = 150; -const DEFAULT_KEYBIND_HEIGHT = options => (options.length * 40) + 100; - -function electronPrompt(options, parentWindow) { - return new Promise((resolve, reject) => { - //id used to ensure unique listeners per window - const id = `${Date.now()}-${Math.random()}`; - - //custom options override default - const options_ = Object.assign( - { - width: options?.type === "counter" ? DEFAULT_COUNTER_WIDTH : options?.type === "keybind" ? DEFAULT_KEYBIND_WIDTH : DEFAULT_WIDTH, - height: options?.type === "keybind" && options?.keybindOptions ? DEFAULT_KEYBIND_HEIGHT(options.keybindOptions) : DEFAULT_HEIGHT, - resizable: false, - title: "Prompt", - label: "Please input a value:", - buttonLabels: null, - alwaysOnTop: false, - value: null, - type: "input", - selectOptions: null, - keybindOptions: null, - counterOptions: { minimum: null, maximum: null, multiFire: false }, - icon: null, - useHtmlLabel: false, - customStylesheet: null, - menuBarVisible: false, - skipTaskbar: true, - frame: true, - customScript: null, - enableRemoteModule: false - }, - options || {} - ); - - - - if (options_.customStylesheet === "dark") { - options_.customStylesheet = require("path").join(__dirname, "dark-prompt.css"); - } - - for (let type of ["counter", "select", "keybind"]) { - if (options_.type === type && (!options_[`${type}Options`] || typeof options_[`${type}Options`] !== "object")) { - reject(new Error(`"${type}Options" must be an object if type = ${type}`)); - return; - } - } - - options_.minWidth = options?.minWidth || options?.width || options_.width; - options_.minHeight = options?.minHeight || options?.height || options_.height; - - let promptWindow = new BrowserWindow({ - frame: options_.frame, - width: options_.width, - height: options_.height, - minWidth: options_.minWidth, - minHeight: options_.minHeight, - resizable: options_.resizable, - minimizable: !options_.skipTaskbar && !parentWindow && !options_.alwaysOnTop, - fullscreenable: options_.resizable, - maximizable: options_.resizable, - parent: parentWindow, - skipTaskbar: options_.skipTaskbar, - alwaysOnTop: options_.alwaysOnTop, - useContentSize: options_.resizable, - modal: Boolean(parentWindow), - title: options_.title, - icon: options_.icon || undefined, - webPreferences: { - nodeIntegration: true, - contextIsolation: false, - enableRemoteModule: options_.enableRemoteModule - } - }); - - promptWindow.setMenu(null); - promptWindow.setMenuBarVisibility(options_.menuBarVisible); - - //called on exit - const cleanup = () => { - ipcMain.removeListener("prompt-get-options:" + id, getOptionsListener); - ipcMain.removeListener("prompt-post-data:" + id, postDataListener); - ipcMain.removeListener("prompt-error:" + id, errorListener); - - if (promptWindow) { - promptWindow.close(); - promptWindow = null; - } - }; - - ///transfer options to front - const getOptionsListener = event => { - event.returnValue = JSON.stringify(options_); - }; - - //get input from front - 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); - event.returnValue = null; - cleanup(); - }; - - const unresponsiveListener = () => { - reject(new Error("Window was unresponsive")); - cleanup(); - }; - - //get error from front - const errorListener = (event, message) => { - reject(new Error(message)); - event.returnValue = null; - cleanup(); - }; - - //attach listeners - ipcMain.on("prompt-get-options:" + id, getOptionsListener); - ipcMain.on("prompt-post-data:" + id, postDataListener); - ipcMain.on("prompt-error:" + id, errorListener); - promptWindow.on("unresponsive", unresponsiveListener); - - promptWindow.on("closed", () => { - promptWindow = null; - cleanup(); - resolve(null); - }); - - //should never happen - promptWindow.webContents.on("did-fail-load", ( - _event, - errorCode, - errorDescription, - validatedURL - ) => { - const log = { - error: "did-fail-load", - errorCode, - errorDescription, - validatedURL - }; - reject(new Error("prompt.html did-fail-load, log:\n" + log.toString())); - }); - - const promptUrl = url.format({ - protocol: "file", - slashes: true, - pathname: path.join(__dirname, "page", "prompt.html"), - hash: id - }); - - //Finally, load prompt - promptWindow.loadURL(promptUrl); - }); -} - -module.exports = electronPrompt; diff --git a/providers/prompt/page/counter.js b/providers/prompt/page/counter.js deleted file mode 100644 index 6f773d97..00000000 --- a/providers/prompt/page/counter.js +++ /dev/null @@ -1,140 +0,0 @@ -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; -} diff --git a/providers/prompt/page/keybind.js b/providers/prompt/page/keybind.js deleted file mode 100644 index 2406f736..00000000 --- a/providers/prompt/page/keybind.js +++ /dev/null @@ -1,305 +0,0 @@ -/* HTML - -
- - - -
- -*/ -/* 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); -} diff --git a/providers/prompt/page/prompt.css b/providers/prompt/page/prompt.css deleted file mode 100644 index 6e52379a..00000000 --- a/providers/prompt/page/prompt.css +++ /dev/null @@ -1,120 +0,0 @@ -body { - font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, - Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", Helvetica, Arial, - sans-serif; - line-height: 1.5em; - color: #333; - background-color: #fff; - overflow-y: hidden; -} - -::-webkit-scrollbar { - width: 0 !important; - display: none; -} - -#container { - align-items: center; - justify-content: center; - display: flex; - height: 100%; - overflow-y: hidden; -} - -#form { - width: 100%; - padding-top: 0.5em; -} - -#label { - max-width: 100%; - max-height: 100%; - margin-bottom: 0.8em; - padding: 0 0.5em; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} - -#data { - border-radius: 2px; - background: #fff; - width: 90%; - padding: 0.4em 0.5em; - border: 1px solid black; - min-height: 2em; - margin: 0 0 1.2em; -} - -select#data { - height: 2em; -} - -#data-container { - text-align: center; -} - -#buttons { - text-align: right; - padding: 0 0.5em 0 0; -} - -#buttons > button, -#buttons > input[type="submit"] { - border-radius: 2px; - border: 0; - margin: 0 0 0 0.5em; - font-size: 0.8em; - line-height: 1em; - padding: 0.6em 1em; -} - -#ok { - background-color: #3879d9; - color: white; -} - -#cancel { - background-color: #ddd; - color: black; -} - -/* Counter mode */ -span { - cursor: pointer; -} -.minus, -.plus { - user-select: none; - width: 20px; - height: 20px; - background: #f2f2f2; - border-radius: 4px; - padding: 8px 5px 8px 5px; - border: 1px solid #ddd; - display: inline-block; - vertical-align: middle; - 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: ":"; - } \ No newline at end of file diff --git a/providers/prompt/page/prompt.html b/providers/prompt/page/prompt.html deleted file mode 100644 index cdbfa544..00000000 --- a/providers/prompt/page/prompt.html +++ /dev/null @@ -1,18 +0,0 @@ - - - - - -
-
-
...
-
-
- - -
-
-
- - - diff --git a/providers/prompt/page/prompt.js b/providers/prompt/page/prompt.js deleted file mode 100644 index e09816d3..00000000 --- a/providers/prompt/page/prompt.js +++ /dev/null @@ -1,344 +0,0 @@ -const fs = require("fs"); -const { ipcRenderer } = require("electron"); -let promptId = null; -let promptOptions = null; -let dataElement = null; - -function $(selector) { return document.querySelector(selector); } - -document.addEventListener("DOMContentLoaded", promptRegister); - -function promptRegister() { - - //get custom session id - promptId = document.location.hash.replace("#", ""); - - //get options from back - try { - promptOptions = JSON.parse(ipcRenderer.sendSync("prompt-get-options:" + promptId)); - } catch (error) { - return promptError(error); - } - - //set label - if (promptOptions.useHtmlLabel) { - $("#label").innerHTML = promptOptions.label; - } else { - $("#label").textContent = promptOptions.label; - } - - //set button label - if (promptOptions.buttonLabels && promptOptions.buttonLabels.ok) { - $("#ok").textContent = promptOptions.buttonLabels.ok; - } - - if (promptOptions.buttonLabels && promptOptions.buttonLabels.cancel) { - $("#cancel").textContent = promptOptions.buttonLabels.cancel; - } - - //inject custom stylesheet from options - if (promptOptions.customStylesheet) { - try { - const customStyleContent = fs.readFileSync(promptOptions.customStylesheet); - if (customStyleContent) { - const customStyle = document.createElement("style"); - customStyle.setAttribute("rel", "stylesheet"); - customStyle.append(document.createTextNode(customStyleContent)); - document.head.append(customStyle); - } - } catch (error) { - return promptError(error); - } - } - - //add button listeners - $("#form").addEventListener("submit", promptSubmit); - $("#cancel").addEventListener("click", promptCancel); - - //create input/select/counter/keybind - const dataContainerElement = $("#data-container"); - - switch (promptOptions.type) { - case "counter": - dataElement = promptCreateCounter(dataContainerElement); - break; - case "input": - dataElement = promptCreateInput(); - break; - case "select": - dataElement = promptCreateSelect(); - break; - case "keybind": - dataElement = require("./keybind")(promptOptions.keybindOptions, dataContainerElement); - break; - default: - return promptError(`Unhandled input type '${promptOptions.type}'`); - } - - if (promptOptions.type != "keybind") { - dataElement.setAttribute("id", "data"); - - if (promptOptions.type !== "counter") { - dataContainerElement.append(dataElement); - } - } - - dataElement.focus(); - - if (promptOptions.type !== "select" && promptOptions.type !== "keybind") { - dataElement.select(); - } - - //load custom script from options - if (promptOptions.customScript) { - try { - const customScript = require(promptOptions.customScript); - customScript(); - } catch (error) { - return promptError(error); - } - } -} - -window.addEventListener("error", event => { - if (promptId) { - promptError("An error has occured on the prompt window: \n" + - `Message: ${event.message}\nURL: ${event.url}\nLine: ${event.lineNo}, Column: ${event.columnNo}\nStack: ${event.error.stack}` - ); - } -}); - -//send error to back -function promptError(error) { - if (error instanceof Error) { - error = error.message + "\n" + error.stack; - } - - ipcRenderer.sendSync("prompt-error:" + promptId, error); -} - -//send to back: input=null -function promptCancel() { - ipcRenderer.sendSync("prompt-post-data:" + promptId, null); -} - -//transfer input data to back -function promptSubmit() { - let data = null; - - switch (promptOptions.type) { - case "input": - case "select": - data = dataElement.value; - break; - case "counter": - data = validateCounterInput(dataElement.value); - break; - case "keybind": - data = dataElement.submit(); - break; - default: //will never happen - return promptError(`Unhandled input type '${promptOptions.type}'`); - } - - ipcRenderer.sendSync("prompt-post-data:" + promptId, data); -} - -//creates input box -function promptCreateInput() { - const dataElement = document.createElement("input"); - dataElement.setAttribute("type", "text"); - - if (promptOptions.value) { - dataElement.value = promptOptions.value; - } else { - dataElement.value = ""; - } - - //insert custom input attributes if in options - if (promptOptions.inputAttrs && typeof (promptOptions.inputAttrs) === "object") { - for (const k in promptOptions.inputAttrs) { - if (!Object.prototype.hasOwnProperty.call(promptOptions.inputAttrs, k)) { - continue; - } - - dataElement.setAttribute(k, promptOptions.inputAttrs[k]); - } - } - - //Cancel/Exit on 'Escape' - dataElement.addEventListener("keyup", event => { - if (event.key === "Escape") { - promptCancel(); - } - }); - - //Confirm on 'Enter' - dataElement.addEventListener("keypress", event => { - if (event.key === "Enter") { - event.preventDefault(); - $("#ok").click(); - } - }); - - return dataElement; -} - -//create multiple select -function promptCreateSelect() { - const dataElement = document.createElement("select"); - let optionElement; - - for (const k in promptOptions.selectOptions) { - if (!Object.prototype.hasOwnProperty.call(promptOptions.selectOptions, k)) { - continue; - } - - optionElement = document.createElement("option"); - optionElement.setAttribute("value", k); - optionElement.textContent = promptOptions.selectOptions[k]; - if (k === promptOptions.value) { - optionElement.setAttribute("selected", "selected"); - } - - dataElement.append(optionElement); - } - - 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; - -/** 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 (promptOptions.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 (promptOptions.counterOptions?.multiFire) { - plusBtn.onmousedown = () => { - multiFire(doPlus); - }; - } else { - plusBtn.onmousedown = () => { - doPlus(); - }; - } - - return plusBtn; -} - -//validate counter -function validateCounterInput(input) { - - const min = promptOptions.counterOptions?.minimum; - const max = promptOptions.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; -} - -module.exports.promptError = promptError; - diff --git a/providers/prompt/readme.md b/providers/prompt/readme.md deleted file mode 100644 index 613b4676..00000000 --- a/providers/prompt/readme.md +++ /dev/null @@ -1,80 +0,0 @@ -# Prompt Component Documentation - -

Simplest Prompt with no stylesheet:
prompt-preview

- -## Usage -```js -prompt([options, parentBrowserWindow]).then(...).catch(...) -``` -Promise resolve returns input - -If user presses cancel/exit window, input = null; - -On error, Prompise reject returns custom error message -## Example - -```js -const prompt = require('./providers/prompt'); - -prompt({ - title: 'Prompt example', - label: 'URL:', - value: 'http://example.org', - inputAttrs: { - type: 'url' - }, - type: 'input' -}) -.then((r) => { - if(r === null) { - console.log('user cancelled'); - } else { - console.log('result', r); - } -}) -.catch(console.error); -``` - -### Options object (optional) - -| Key | Explanation | -| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| title | (optional, string) The title of the prompt window. Defaults to 'Prompt'. | -| label | (optional, string) The label which appears on the prompt for the input field. Defaults to 'Please input a value:'. | -| buttonLabels | (optional, object) The text for the OK/cancel buttons. Properties are 'ok' and 'cancel'. Defaults to null. | -| value | (optional, string) The default value for the input field. Defaults to null. | -| type | (optional, string) The type of input field, either 'input' for a standard text input field or 'select' for a dropdown type input or 'counter' for a number counter with buttons. Defaults to 'input'. | -| inputAttrs | (optional, object) The attributes of the input field, analagous to the HTML attributes: `{type: 'text', required: true}` -> ``. Used if the type is 'input' -| counterOptions | (optional, object) minimum and maximum of counter, and if continuous input is enabled. format: `{minimum: %int%, maximum: %int%, multiFire: %boolean%`. min+max values defaults to null and multiFire defaults to false. | -| selectOptions | (optional, object) The items for the select dropdown if using the 'select' type in the format 'value': 'display text', where the value is what will be given to the then block and the display text is what the user will see. | -| useHtmlLabel | (optional, boolean) Whether the label should be interpreted as HTML or not. Defaults to false. | -| width | (optional, integer) The width of the prompt window. Defaults to 370. | -| minWidth | (optional, integer) The minimum allowed width for the prompt window. Default to width if specified or default_width(370). | | -| height | (optional, integer) The height of the prompt window. Defaults to 130. | -| minHeight | (optional, integer) The minimum allowed height for the prompt window. Same default value as height. | -| resizable | (optional, boolean) Whether the prompt window can be resized or not (also sets useContentSize). Defaults to false. | -| alwaysOnTop | (optional, boolean) Whether the window should always stay on top of other windows. Defaults to false | -| icon | (optional, string) The path to an icon image to use in the title bar. Defaults to null and uses electron's icon. | -| customStylesheet | (optional, string) The local path of a CSS file to customize the style of the prompt window, you can use just "dark" to use the premade dark skin. Defaults to null. | -| menuBarVisible | (optional, boolean) Whether to show the menubar or not. Defaults to false. | -| skipTaskbar | (optional, boolean) Whether to show the prompt window icon in taskbar. Defaults to true. | -| frame | (optional, boolean) Wether to create prompt with frame. Defaults to true. | -| customScript | (optional, string) The local path of a JS file to run on preload. Defaults to null. | -| enableRemoteModule | (optional, boolean) Wether the prompt window have remote modules activated, Defaults to false. | - -If not supplied, it uses the defaults listed in the table above. - -### parentBrowserWindow (optional) - -The window in which to display the prompt on. If not supplied, the parent window of the prompt will be null. - -### customScript (optional) - -Create the script with the following template: - -```node -module.exports = () => { - // This function will be called as a preload script - // So you can use front features like `document.querySelector` -}; -```