From ffe83c1452e17eec591a5175bd06233f4d04a600 Mon Sep 17 00:00:00 2001 From: Ethan Mahlstedt Date: Fri, 7 Feb 2025 10:10:37 -0700 Subject: [PATCH 001/126] Dynamic Display Update Added dynamic displays functionality, still has lots of styling work to do. --- front/editor/editor.js | 19 ++++++++---- .../pickOpenedDisplay/pickOpenedDisplay.html | 2 +- front/pickOpenedDisplay/pickOpenedDisplay.js | 17 ++++++----- main.js | 30 +++++++++++++++---- 4 files changed, 49 insertions(+), 19 deletions(-) diff --git a/front/editor/editor.js b/front/editor/editor.js index 891d4e1..19953cb 100644 --- a/front/editor/editor.js +++ b/front/editor/editor.js @@ -28,8 +28,7 @@ let currentFile = null; // TODO: Make a scrollbar on FileDivContainer for overflow -function printOnBackConsole(args) { - // eslint-disable-line +function printOnBackConsole(args) {// eslint-disable-line // Debug function ipcRenderer.send("printOnBackConsole", args); @@ -211,8 +210,10 @@ saveButton.addEventListener("click", () => { ipcRenderer.send( "save-file", currentFile, - OpenedFiles.READ(OpenedFiles.FINDQUICKINDEX("fileLink", currentFile)), - "data", + OpenedFiles.READ( + OpenedFiles.FINDQUICKINDEX("fileLink", currentFile), + "data", + ), ); }); @@ -270,9 +271,17 @@ document.getElementById("RefreshEditor").addEventListener("click", () => { "pickOpenedDisplay", OpenedFiles.FINDQUICKINDEX("fileLink", currentFile), ); + } else { + ipcRenderer.send( + "restartDisplay", + OpenedFiles.READ( + OpenedFiles.FINDQUICKINDEX("fileLink", currentFile), + "linkedDisplay", + ), + ); } }); -ipcRenderer.on("linkEditor", (event, display, fileID) => { +ipcRenderer.on("syncLinkedDisplay", (event, fileID, display) => { OpenedFiles.SET(fileID, "linkedDisplay", display); }); diff --git a/front/pickOpenedDisplay/pickOpenedDisplay.html b/front/pickOpenedDisplay/pickOpenedDisplay.html index 41b0902..981355f 100644 --- a/front/pickOpenedDisplay/pickOpenedDisplay.html +++ b/front/pickOpenedDisplay/pickOpenedDisplay.html @@ -3,7 +3,7 @@ - New File + Pick Window... diff --git a/front/pickOpenedDisplay/pickOpenedDisplay.js b/front/pickOpenedDisplay/pickOpenedDisplay.js index f7cbda3..e7225e5 100644 --- a/front/pickOpenedDisplay/pickOpenedDisplay.js +++ b/front/pickOpenedDisplay/pickOpenedDisplay.js @@ -1,4 +1,4 @@ -const { ipcRenderer, webContents } = require("electron"); +const { ipcRenderer } = require("electron"); let CallerWindow = null; let OpenedDisplays = null; let CallerEditor = null; @@ -6,7 +6,7 @@ let CallerFile = null; ipcRenderer.on("loadOpenedEditors", (event, args) => { CallerWindow = args.callerWindowId; OpenedDisplays = args.openedDisplays; - CallerEditor = webContents.fromId(args.callerWindowId); + CallerEditor = args.callerWindowId; CallerFile = args.caller; OpenedDisplays.forEach((e) => { const option = document.createElement("option"); @@ -24,11 +24,14 @@ document.getElementById("pickWindowBtn").addEventListener("click", () => { CallerEditor != null || CallerFile != null ) { - CallerEditor.send( - "linkEditor", - document.getElementById("windowPicker").value, - CallerFile, - ); + if (document.getElementById("windowPicker").value != "none") { + ipcRenderer.send( + "connectWindowSelection", + document.getElementById("windowPicker").value, + CallerFile, + CallerWindow, + ); + } } else { alert("Missing caller argument"); console.log("Missing Caller Argument, variables are:"); diff --git a/main.js b/main.js index dac8b67..fd9ab1c 100644 --- a/main.js +++ b/main.js @@ -1,5 +1,11 @@ // Import libraries -const { app, BrowserWindow, ipcMain, dialog } = require("electron"); +const { + app, + BrowserWindow, + ipcMain, + dialog, + webContents, +} = require("electron"); const fs = require("fs"); const needle = require("needle-db"); @@ -186,18 +192,17 @@ ipcMain.handle("pickOpenedDisplay", (event, callerFileIndex) => { let dialog = launchWindow( "./front/pickOpenedDisplay/pickOpenedDisplay.html", { - width: 450, + width: 800, height: 135, - resizable: false, + resizable: true, // Debug fullscreenable: false, webPreferences: { nodeIntegration: true, contextIsolation: false }, }, ); let openedDisplaysReduced = []; - openedDisplays.GETJSONDATA().forEach((e) => { - openedDisplaysReduced.push({ fileLink: e.fileLink, window: e.window.id }); + openedDisplays.GETJSONDATA().forEach((e, i) => { + openedDisplaysReduced.push({ fileLink: e.fileLink, window: i }); }); - console.log(openedDisplaysReduced); dialog.webContents.send("loadOpenedEditors", { callerWindowId: event.sender.id, openedDisplays: openedDisplaysReduced, @@ -207,8 +212,21 @@ ipcMain.handle("pickOpenedDisplay", (event, callerFileIndex) => { // Handling Idea: Send the editor who called the new display and the file looking to link to the dialog, so it can call the window itself and handle the file link }); +ipcMain.on( + "connectWindowSelection", + (event, value, callerFile, CallerWindow) => { + webContents + .fromId(CallerWindow) + .send("syncLinkedDisplay", callerFile, value); + }, +); + ipcMain.on("printOpenedDisplays", () => { // Function for debugging console.log(openedDisplays.GETJSONDATA()); }); + +ipcMain.on("restartDisplay", (event, args) => { + openedDisplays.READ(args, "window").webContents.reload(); +}); From 1ee2c27174bd1378ae7f72c856eda174e753a947 Mon Sep 17 00:00:00 2001 From: Ethan Mahlstedt Date: Sat, 8 Feb 2025 14:29:54 -0700 Subject: [PATCH 002/126] Add developer scripts --- .gitignore | 9 +-------- .prettierignore | 1 + .prettierrc | 21 +++++++++++++++++++++ eslint.config.mjs | 11 +++++++++++ install.bat | 1 + lint.bat | 2 ++ pretty.bat | 2 ++ 7 files changed, 39 insertions(+), 8 deletions(-) create mode 100644 .prettierignore create mode 100644 .prettierrc create mode 100644 eslint.config.mjs create mode 100644 install.bat create mode 100644 lint.bat create mode 100644 pretty.bat diff --git a/.gitignore b/.gitignore index e3c052b..b512c09 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1 @@ -node_modules -.prettierignore -.prettierrc -eslint.config.mjs -buglist -featuremindstorm -lint.bat -pretty.bat \ No newline at end of file +node_modules \ No newline at end of file diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..b512c09 --- /dev/null +++ b/.prettierignore @@ -0,0 +1 @@ +node_modules \ No newline at end of file diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..329d11f --- /dev/null +++ b/.prettierrc @@ -0,0 +1,21 @@ +{ + "arrowParens": "always", + "bracketSameLine": false, + "bracketSpacing": true, + "semi": true, + "experimentalTernaries": false, + "singleQuote": false, + "jsxSingleQuote": false, + "quoteProps": "as-needed", + "trailingComma": "all", + "singleAttributePerLine": false, + "htmlWhitespaceSensitivity": "css", + "vueIndentScriptAndStyle": false, + "proseWrap": "preserve", + "insertPragma": false, + "printWidth": 80, + "requirePragma": false, + "tabWidth": 2, + "useTabs": true, + "embeddedLanguageFormatting": "auto" +} diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 0000000..38ae6cc --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,11 @@ +import globals from "globals"; +import pluginJs from "@eslint/js"; +import eslintConfigPrettier from "eslint-config-prettier"; + +/** @type {import('eslint').Linter.Config[]} */ +export default [ + { files: ["**/*.js"], languageOptions: { sourceType: "commonjs" } }, + { languageOptions: { globals: { ...globals.browser, ...globals.node } } }, + pluginJs.configs.recommended, + eslintConfigPrettier, +]; diff --git a/install.bat b/install.bat new file mode 100644 index 0000000..59a8e22 --- /dev/null +++ b/install.bat @@ -0,0 +1 @@ +npm i \ No newline at end of file diff --git a/lint.bat b/lint.bat new file mode 100644 index 0000000..82f4c93 --- /dev/null +++ b/lint.bat @@ -0,0 +1,2 @@ +@echo off +npx eslint . \ No newline at end of file diff --git a/pretty.bat b/pretty.bat new file mode 100644 index 0000000..93c4043 --- /dev/null +++ b/pretty.bat @@ -0,0 +1,2 @@ +@echo off +npx prettier . --write \ No newline at end of file From e9ea3e1704592c5c2e4244ee5de99ff0ed059776 Mon Sep 17 00:00:00 2001 From: Ethan Mahlstedt Date: Sat, 8 Feb 2025 14:32:28 -0700 Subject: [PATCH 003/126] Update .prettierrc --- .prettierrc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.prettierrc b/.prettierrc index 329d11f..2912e49 100644 --- a/.prettierrc +++ b/.prettierrc @@ -7,7 +7,7 @@ "singleQuote": false, "jsxSingleQuote": false, "quoteProps": "as-needed", - "trailingComma": "all", + "trailingComma": "none", "singleAttributePerLine": false, "htmlWhitespaceSensitivity": "css", "vueIndentScriptAndStyle": false, From 9bda46bb46d0a9f35fe5def12a3e5926bbb92448 Mon Sep 17 00:00:00 2001 From: Ethan Mahlstedt Date: Wed, 5 Mar 2025 10:53:17 -0700 Subject: [PATCH 004/126] Add Highlights --- .gitignore | 9 ++--- front/editor/editor.html | 7 ++-- front/editor/highlight.js | 43 ++++++++++++++++++++++++ front/editor/highlightertest.js | 1 + front/editor/highlights/highlights1.json | 19 +++++++++++ front/editor/highlights/highlights2.json | 1 + front/editor/highlights/highlights3.json | 10 ++++++ front/editor/highlights/highlights4.json | 6 ++++ 8 files changed, 84 insertions(+), 12 deletions(-) create mode 100644 front/editor/highlight.js create mode 100644 front/editor/highlightertest.js create mode 100644 front/editor/highlights/highlights1.json create mode 100644 front/editor/highlights/highlights2.json create mode 100644 front/editor/highlights/highlights3.json create mode 100644 front/editor/highlights/highlights4.json diff --git a/.gitignore b/.gitignore index e3c052b..e850850 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,3 @@ node_modules -.prettierignore -.prettierrc -eslint.config.mjs -buglist -featuremindstorm -lint.bat -pretty.bat \ No newline at end of file +.vscode +.hintrc \ No newline at end of file diff --git a/front/editor/editor.html b/front/editor/editor.html index a45fd6d..ce3100b 100644 --- a/front/editor/editor.html +++ b/front/editor/editor.html @@ -15,11 +15,8 @@
- +
+

 		
diff --git a/front/editor/highlight.js b/front/editor/highlight.js new file mode 100644 index 0000000..58321b3 --- /dev/null +++ b/front/editor/highlight.js @@ -0,0 +1,43 @@ +const highlights1 = require("./highlights/highlights1.json") +const highlights2 = require("./highlights/highlights2.json") +const highlights3 = require("./highlights/highlights3.json") +const highlights4 = require("./highlights/highlights4.json") + +module.exports = (code) => { + let fragmentatedCode = "" + let arrayedCode = code.split(" ") + + arrayedCode.forEach((e, i)=>{ + highlights1.forEach(he =>{ + if(e.toUpperCase() === he){ + // Handle case, paint red + console.log(e) + arrayedCode[i] = `${e}` + } + }) + highlights2.forEach(he =>{ + if(e.toUpperCase() === he){ + // Handle case, paint green + console.log(e) + arrayedCode[i] = `${e}` + } + }) + highlights3.forEach(he =>{ + if(e.toUpperCase() === he){ + // Handle case, paint blue + console.log(e) + arrayedCode[i] = `${e}` + } + }) + highlights4.forEach(he =>{ + if(e.toUpperCase() === he){ + // Handle case, paint yellow + console.log(e) + arrayedCode[i] = `${e}` + } + }) + }) + + fragmentatedCode = arrayedCode.join(" ") + return fragmentatedCode +} \ No newline at end of file diff --git a/front/editor/highlightertest.js b/front/editor/highlightertest.js new file mode 100644 index 0000000..a2017de --- /dev/null +++ b/front/editor/highlightertest.js @@ -0,0 +1 @@ +require("./highlight")("const jdbalsdaldhalsdj = djaspdjasd\nfunctionsa function ;") \ No newline at end of file diff --git a/front/editor/highlights/highlights1.json b/front/editor/highlights/highlights1.json new file mode 100644 index 0000000..8660b0d --- /dev/null +++ b/front/editor/highlights/highlights1.json @@ -0,0 +1,19 @@ +[ + "CONST", + "LET", + "FUNCTION", + "VAR", + "IF", + "ELSE", + "FOR", + "WHILE", + "DO", + "SWITCH", + "CASE", + "DEFAULT", + "BREAK", + "CONTINUE", + "RETURN", + "TRY", + "CATCH" +] \ No newline at end of file diff --git a/front/editor/highlights/highlights2.json b/front/editor/highlights/highlights2.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/front/editor/highlights/highlights2.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/front/editor/highlights/highlights3.json b/front/editor/highlights/highlights3.json new file mode 100644 index 0000000..f14073d --- /dev/null +++ b/front/editor/highlights/highlights3.json @@ -0,0 +1,10 @@ +[ + "=", + "!=", + "!==", + "==", + "===", + "=>", + "(", + ")" +] \ No newline at end of file diff --git a/front/editor/highlights/highlights4.json b/front/editor/highlights/highlights4.json new file mode 100644 index 0000000..31e6e1d --- /dev/null +++ b/front/editor/highlights/highlights4.json @@ -0,0 +1,6 @@ +[ + "[", + "]", + "{", + "}" +] \ No newline at end of file From 6bf9e9b9b322770a22b03e4d4fb02deaeda0f08a Mon Sep 17 00:00:00 2001 From: Ethan Mahlstedt Date: Wed, 5 Mar 2025 10:53:38 -0700 Subject: [PATCH 005/126] Change textarea to div --- front/editor/editor.css | 10 +++++--- front/editor/editor.js | 51 +++++++++++++++++++++++++++++++++-------- 2 files changed, 48 insertions(+), 13 deletions(-) diff --git a/front/editor/editor.css b/front/editor/editor.css index bb8ab6c..d297516 100644 --- a/front/editor/editor.css +++ b/front/editor/editor.css @@ -121,8 +121,7 @@ button:hover { overflow: hidden; white-space: pre; } - -textarea { +#TextArea { flex-grow: 1; background-color: rgb(32, 32, 32); color: white; @@ -135,5 +134,10 @@ textarea { resize: none; overflow-y: scroll; tab-size: 4; - white-space: pre; + white-space: pre-wrap; + word-wrap: break-word; + min-height: 100px; /* Ensure it has height */ + padding: 5px; + overflow-wrap: break-word; + box-sizing: border-box; } diff --git a/front/editor/editor.js b/front/editor/editor.js index 891d4e1..8f4ae7a 100644 --- a/front/editor/editor.js +++ b/front/editor/editor.js @@ -6,6 +6,7 @@ const { getFileDivIdFromLink, getFileNameFromLink, } = require("../../modules/fileStringFunctions"); +const hightlighter = require("./highlight") // Setup needle table @@ -28,8 +29,7 @@ let currentFile = null; // TODO: Make a scrollbar on FileDivContainer for overflow -function printOnBackConsole(args) { - // eslint-disable-line +function printOnBackConsole(args) {// eslint-disable-line // Debug function ipcRenderer.send("printOnBackConsole", args); @@ -94,7 +94,7 @@ function newFileDiv(file) { lcfDiv.classList.add("fileDiv"); const oldFileIndex = OpenedFiles.indexOf(lastCurrentFile) - cacheData[oldFileIndex] = textArea.value + cacheData[oldFileIndex] = textArea.innerText const Div = new FileDiv(response.file); Div.displayFileDiv(); @@ -107,7 +107,7 @@ function newFileDiv(file) { document.title = `${Div.fileName} - HTMLEditor` - textArea.value = response.filedata + textArea.innerText = response.filedata const fileIndex = OpenedFiles.indexOf(response.file) cacheData[fileIndex] = response.filedata updateLineNumbers(); @@ -154,7 +154,7 @@ function closeFile(file) { } function updateLineNumbers() { - const lines = textArea.value.split("\n").length; + const lines = textArea.innerText.split("\n").length; let lineNumberContent = ""; for (let i = 1; i <= lines; i++) { lineNumberContent += i + "\n"; @@ -166,17 +166,36 @@ textArea.addEventListener("scroll", () => { lineNumbers.scrollTop = textArea.scrollTop; }); -textArea.addEventListener("input", updateLineNumbers); - textArea.addEventListener("input", () => { + const selection = window.getSelection(); + const range = selection.getRangeAt(0); + const cursorPosition = range.startOffset; + const scrollPosition = textArea.scrollTop; + + updateLineNumbers(); + OpenedFiles.SET( OpenedFiles.FINDQUICKINDEX("fileLink", currentFile), "data", - textArea.value, + textArea.innerText, ); + + textArea.innerHTML = hightlighter(textArea.innerText) + //textArea.innerHTML = getCode(); + + const newRange = document.createRange(); + newRange.setStart(textArea.firstChild, cursorPosition); + newRange.setEnd(textArea.firstChild, cursorPosition); + selection.removeAllRanges(); + selection.addRange(newRange); + textArea.scrollTop = scrollPosition; }); textArea.addEventListener("keydown", (event) => { + if (event.key === "Enter") { + event.preventDefault(); + document.execCommand("insertLineBreak"); // Insert
+ } if (event.key === "Tab") { event.preventDefault(); @@ -190,6 +209,18 @@ textArea.addEventListener("keydown", (event) => { } }); +function getCode() { + let code = textArea.innerHTML; + + // Convert real
elements to \n + code = code.replace(//gi, "\n"); + + // Convert user-typed "<br>" back to "
" + code = code.replace(/<br\s*\/?>/gi, "
"); + + return code; + } + ipcRenderer.on("open-editor", (event, file) => { document.addEventListener("DOMContentLoaded", () => { openFile(file, () => { @@ -238,11 +269,11 @@ function loadFileIntoEditor(file) { OpenedFiles.SET( OpenedFiles.FINDQUICKINDEX("fileLink", lastCurrentFile), "data", - textArea.value, + textArea.innerText, ); } currentFile = file; - textArea.value = OpenedFiles.READ( + textArea.innerText = OpenedFiles.READ( OpenedFiles.FINDQUICKINDEX("fileLink", currentFile), "data", ); From 57d67c64123839ba24a7720e8a1b8c208e6138b6 Mon Sep 17 00:00:00 2001 From: Ethan Mahlstedt Date: Wed, 5 Mar 2025 13:21:26 -0700 Subject: [PATCH 006/126] Rework cursor when highlighting --- front/editor/editor.js | 64 +++++++++++++++++++++++++++------------ front/editor/highlight.js | 4 --- 2 files changed, 45 insertions(+), 23 deletions(-) diff --git a/front/editor/editor.js b/front/editor/editor.js index 8f4ae7a..2cfab3f 100644 --- a/front/editor/editor.js +++ b/front/editor/editor.js @@ -167,30 +167,56 @@ textArea.addEventListener("scroll", () => { }); textArea.addEventListener("input", () => { - const selection = window.getSelection(); - const range = selection.getRangeAt(0); - const cursorPosition = range.startOffset; - const scrollPosition = textArea.scrollTop; - - updateLineNumbers(); + const selection = window.getSelection(); + let caretOffset = 0; // Store cursor position relative to text content + + if (selection.rangeCount > 0) { + const range = selection.getRangeAt(0); + const preCaretRange = range.cloneRange(); // Clone range for measurement + preCaretRange.selectNodeContents(textArea); + preCaretRange.setEnd(range.startContainer, range.startOffset); + caretOffset = preCaretRange.toString().length; // Get offset in characters + } - OpenedFiles.SET( - OpenedFiles.FINDQUICKINDEX("fileLink", currentFile), - "data", - textArea.innerText, - ); + const scrollPosition = textArea.scrollTop; // Preserve scroll position + + // Update content + OpenedFiles.SET( + OpenedFiles.FINDQUICKINDEX("fileLink", currentFile), + "data", + textArea.innerText, + ); + + textArea.innerHTML = hightlighter(textArea.innerText); + + // Restore cursor position + const newRange = document.createRange(); + const newSelection = window.getSelection(); + let charIndex = 0; + let found = false; + + function setCaret(node) { + if (node.nodeType === Node.TEXT_NODE) { + const nextCharIndex = charIndex + node.length; + if (!found && caretOffset >= charIndex && caretOffset <= nextCharIndex) { + newRange.setStart(node, caretOffset - charIndex); + newRange.setEnd(node, caretOffset - charIndex); + found = true; + } + charIndex = nextCharIndex; + } else { + node.childNodes.forEach(setCaret); + } + } - textArea.innerHTML = hightlighter(textArea.innerText) - //textArea.innerHTML = getCode(); + setCaret(textArea); - const newRange = document.createRange(); - newRange.setStart(textArea.firstChild, cursorPosition); - newRange.setEnd(textArea.firstChild, cursorPosition); - selection.removeAllRanges(); - selection.addRange(newRange); - textArea.scrollTop = scrollPosition; + newSelection.removeAllRanges(); + newSelection.addRange(newRange); + textArea.scrollTop = scrollPosition; // Restore scroll position }); + textArea.addEventListener("keydown", (event) => { if (event.key === "Enter") { event.preventDefault(); diff --git a/front/editor/highlight.js b/front/editor/highlight.js index 58321b3..0ad3ba2 100644 --- a/front/editor/highlight.js +++ b/front/editor/highlight.js @@ -11,28 +11,24 @@ module.exports = (code) => { highlights1.forEach(he =>{ if(e.toUpperCase() === he){ // Handle case, paint red - console.log(e) arrayedCode[i] = `${e}` } }) highlights2.forEach(he =>{ if(e.toUpperCase() === he){ // Handle case, paint green - console.log(e) arrayedCode[i] = `${e}` } }) highlights3.forEach(he =>{ if(e.toUpperCase() === he){ // Handle case, paint blue - console.log(e) arrayedCode[i] = `${e}` } }) highlights4.forEach(he =>{ if(e.toUpperCase() === he){ // Handle case, paint yellow - console.log(e) arrayedCode[i] = `${e}` } }) From a847997053fa92e126f9e46436bc6487e71f8304 Mon Sep 17 00:00:00 2001 From: Ethan Mahlstedt Date: Mon, 10 Mar 2025 08:36:56 -0700 Subject: [PATCH 007/126] Highlight rework pt1 --- front/editor/editor.js | 7 +- front/editor/highlight.js | 78 ++++++++++--------- front/editor/highlights/highlights1.json | 19 ----- front/editor/highlights/highlights3.json | 10 --- front/editor/highlights/highlights4.json | 6 -- front/editor/highlights/js/highlights1.json | 20 +++++ .../highlights/{ => js}/highlights2.json | 0 front/editor/highlights/js/highlights3.json | 14 ++++ front/editor/highlights/js/highlights4.json | 6 ++ front/editor/highlights/js/highlights5.json | 4 + 10 files changed, 91 insertions(+), 73 deletions(-) delete mode 100644 front/editor/highlights/highlights1.json delete mode 100644 front/editor/highlights/highlights3.json delete mode 100644 front/editor/highlights/highlights4.json create mode 100644 front/editor/highlights/js/highlights1.json rename front/editor/highlights/{ => js}/highlights2.json (100%) create mode 100644 front/editor/highlights/js/highlights3.json create mode 100644 front/editor/highlights/js/highlights4.json create mode 100644 front/editor/highlights/js/highlights5.json diff --git a/front/editor/editor.js b/front/editor/editor.js index 2cfab3f..69030d1 100644 --- a/front/editor/editor.js +++ b/front/editor/editor.js @@ -186,7 +186,8 @@ textArea.addEventListener("input", () => { "data", textArea.innerText, ); - + console.log(textArea.innerText) + console.log(typeof textArea.innerText) textArea.innerHTML = hightlighter(textArea.innerText); // Restore cursor position @@ -265,11 +266,11 @@ ipcRenderer.on("open-editor", (event, file) => { const saveButton = document.getElementById("SaveBtn"); saveButton.addEventListener("click", () => { + console.log(OpenedFiles.FINDQUICKINDEX("fileLink", currentFile)) ipcRenderer.send( "save-file", currentFile, - OpenedFiles.READ(OpenedFiles.FINDQUICKINDEX("fileLink", currentFile)), - "data", + OpenedFiles.READ(OpenedFiles.FINDQUICKINDEX("fileLink", currentFile), "data"), ); }); diff --git a/front/editor/highlight.js b/front/editor/highlight.js index 0ad3ba2..3835073 100644 --- a/front/editor/highlight.js +++ b/front/editor/highlight.js @@ -1,39 +1,47 @@ -const highlights1 = require("./highlights/highlights1.json") -const highlights2 = require("./highlights/highlights2.json") -const highlights3 = require("./highlights/highlights3.json") -const highlights4 = require("./highlights/highlights4.json") +module.exports = (code, filename) => { + if(filename.endsWith(".js")){ + const highlights1 = require("./highlights/js/highlights1.json") + const highlights2 = require("./highlights/js/highlights2.json") + const highlights3 = require("./highlights/js/highlights3.json") + const highlights4 = require("./highlights/js/highlights4.json") + const highlights5 = require("./highlights/js/highlights5.json") -module.exports = (code) => { - let fragmentatedCode = "" - let arrayedCode = code.split(" ") + let fragmentatedCode = "" + let arrayedCode = code.split(" ") - arrayedCode.forEach((e, i)=>{ - highlights1.forEach(he =>{ - if(e.toUpperCase() === he){ - // Handle case, paint red - arrayedCode[i] = `${e}` - } + arrayedCode.forEach((e, i)=>{ + highlights1.forEach(he =>{ + if(e.toUpperCase() === he.keyword){ + // Handle case, paint red + arrayedCode[i] = `${e}` + if(he.type === "declaration"){ + arrayedCode[i + 1] = `${arrayedCode[i + 1]}` + } + } + }) + highlights2.forEach(he =>{ + if(e.toUpperCase() === he){ + // Handle case, paint green + arrayedCode[i] = `${e}` + } + }) + highlights3.forEach(he =>{ + if(e.toUpperCase() === he){ + // Handle case, paint blue + arrayedCode[i] = `${e}` + } + }) + highlights4.forEach(he =>{ + if(e.toUpperCase() === he){ + // Handle case, paint yellow + arrayedCode[i] = `${e}` + } + }) }) - highlights2.forEach(he =>{ - if(e.toUpperCase() === he){ - // Handle case, paint green - arrayedCode[i] = `${e}` - } - }) - highlights3.forEach(he =>{ - if(e.toUpperCase() === he){ - // Handle case, paint blue - arrayedCode[i] = `${e}` - } - }) - highlights4.forEach(he =>{ - if(e.toUpperCase() === he){ - // Handle case, paint yellow - arrayedCode[i] = `${e}` - } - }) - }) - - fragmentatedCode = arrayedCode.join(" ") - return fragmentatedCode + + fragmentatedCode = arrayedCode.join(" ") + return fragmentatedCode + }else{ + return code; + } } \ No newline at end of file diff --git a/front/editor/highlights/highlights1.json b/front/editor/highlights/highlights1.json deleted file mode 100644 index 8660b0d..0000000 --- a/front/editor/highlights/highlights1.json +++ /dev/null @@ -1,19 +0,0 @@ -[ - "CONST", - "LET", - "FUNCTION", - "VAR", - "IF", - "ELSE", - "FOR", - "WHILE", - "DO", - "SWITCH", - "CASE", - "DEFAULT", - "BREAK", - "CONTINUE", - "RETURN", - "TRY", - "CATCH" -] \ No newline at end of file diff --git a/front/editor/highlights/highlights3.json b/front/editor/highlights/highlights3.json deleted file mode 100644 index f14073d..0000000 --- a/front/editor/highlights/highlights3.json +++ /dev/null @@ -1,10 +0,0 @@ -[ - "=", - "!=", - "!==", - "==", - "===", - "=>", - "(", - ")" -] \ No newline at end of file diff --git a/front/editor/highlights/highlights4.json b/front/editor/highlights/highlights4.json deleted file mode 100644 index 31e6e1d..0000000 --- a/front/editor/highlights/highlights4.json +++ /dev/null @@ -1,6 +0,0 @@ -[ - "[", - "]", - "{", - "}" -] \ No newline at end of file diff --git a/front/editor/highlights/js/highlights1.json b/front/editor/highlights/js/highlights1.json new file mode 100644 index 0000000..c0f4f35 --- /dev/null +++ b/front/editor/highlights/js/highlights1.json @@ -0,0 +1,20 @@ +[ + {"keyword": "CONST", "type": "declaration"}, + {"keyword": "LET", "type": "declaration"}, + {"keyword": "FUNCTION", "type": "declaration"}, + {"keyword": "VAR", "type": "declaration"}, + {"keyword": "NEW", "type": "declaration"}, + {"keyword": "IF", "type": "keyword"}, + {"keyword": "ELSE", "type": "keyword"}, + {"keyword": "FOR", "type": "keyword"}, + {"keyword": "WHILE", "type": "keyword"}, + {"keyword": "DO", "type": "keyword"}, + {"keyword": "SWITCH", "type": "keyword"}, + {"keyword": "CASE", "type": "keyword"}, + {"keyword": "DEFAULT", "type": "keyword"}, + {"keyword": "BREAK", "type": "keyword"}, + {"keyword": "CONTINUE", "type": "keyword"}, + {"keyword": "RETURN", "type": "keyword"}, + {"keyword": "TRY", "type": "keyword"}, + {"keyword": "CATCH", "type": "keyword"} +] \ No newline at end of file diff --git a/front/editor/highlights/highlights2.json b/front/editor/highlights/js/highlights2.json similarity index 100% rename from front/editor/highlights/highlights2.json rename to front/editor/highlights/js/highlights2.json diff --git a/front/editor/highlights/js/highlights3.json b/front/editor/highlights/js/highlights3.json new file mode 100644 index 0000000..ac054d3 --- /dev/null +++ b/front/editor/highlights/js/highlights3.json @@ -0,0 +1,14 @@ +[ + {"keyword": "=", "type": "keyword"}, + {"keyword": "!=", "type": "keyword"}, + {"keyword": "!==", "type": "keyword"}, + {"keyword": "==", "type": "keyword"}, + {"keyword": "===", "type": "keyword"}, + {"keyword": "=>", "type": "keyword"}, + {"keyword": "(", "type": "keyword"}, + {"keyword": ")", "type": "keyword"}, + {"keyword": ">=", "type": "keyword"}, + {"keyword": "<=", "type": "keyword"}, + {"keyword": "<", "type": "keyword"}, + {"keyword": ">", "type": "keyword"} +] \ No newline at end of file diff --git a/front/editor/highlights/js/highlights4.json b/front/editor/highlights/js/highlights4.json new file mode 100644 index 0000000..a767beb --- /dev/null +++ b/front/editor/highlights/js/highlights4.json @@ -0,0 +1,6 @@ +[ + {"keyword": "[", "type": "keyword"}, + {"keyword": "]", "type": "keyword"}, + {"keyword": "{", "type": "keyword"}, + {"keyword": "}", "type": "keyword"} +] \ No newline at end of file diff --git a/front/editor/highlights/js/highlights5.json b/front/editor/highlights/js/highlights5.json new file mode 100644 index 0000000..b6191cd --- /dev/null +++ b/front/editor/highlights/js/highlights5.json @@ -0,0 +1,4 @@ +[ + {"keyword": "//", "type": "comment1"}, + {"keyword": "/*", "type": "comment2"} +] \ No newline at end of file From 06c2bebd47afe444e28d22b3f105357590235064 Mon Sep 17 00:00:00 2001 From: Ethan Mahlstedt Date: Mon, 10 Mar 2025 13:34:10 -0700 Subject: [PATCH 008/126] Correct highlighter call --- front/editor/editor.js | 7 ++++--- front/editor/highlight.js | 18 +++++++++++++++--- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/front/editor/editor.js b/front/editor/editor.js index 69030d1..d279285 100644 --- a/front/editor/editor.js +++ b/front/editor/editor.js @@ -6,7 +6,7 @@ const { getFileDivIdFromLink, getFileNameFromLink, } = require("../../modules/fileStringFunctions"); -const hightlighter = require("./highlight") +const highlighter = require("./highlight") // Setup needle table @@ -188,7 +188,7 @@ textArea.addEventListener("input", () => { ); console.log(textArea.innerText) console.log(typeof textArea.innerText) - textArea.innerHTML = hightlighter(textArea.innerText); + textArea.innerHTML = highlighter(textArea.innerText, currentFile); // Restore cursor position const newRange = document.createRange(); @@ -277,7 +277,7 @@ saveButton.addEventListener("click", () => { function loadFileIntoEditor(file) { if (currentFile !== null) { const lastCurrentFile = currentFile; - currentFile = file; + currentFile = file document .getElementById(getFileDivIdFromLink(lastCurrentFile)) @@ -304,6 +304,7 @@ function loadFileIntoEditor(file) { OpenedFiles.FINDQUICKINDEX("fileLink", currentFile), "data", ); + textArea.innerHTML = highlighter(textArea.innerText, currentFile); updateLineNumbers(); document.title = `${getFileNameFromLink(file)} - HTMLEditor`; diff --git a/front/editor/highlight.js b/front/editor/highlight.js index 3835073..9d8b798 100644 --- a/front/editor/highlight.js +++ b/front/editor/highlight.js @@ -20,23 +20,35 @@ module.exports = (code, filename) => { } }) highlights2.forEach(he =>{ - if(e.toUpperCase() === he){ + if(e.toUpperCase() === he.keyword){ // Handle case, paint green arrayedCode[i] = `${e}` } }) highlights3.forEach(he =>{ - if(e.toUpperCase() === he){ + if(e.toUpperCase() === he.keyword){ // Handle case, paint blue arrayedCode[i] = `${e}` } }) highlights4.forEach(he =>{ - if(e.toUpperCase() === he){ + if(e.toUpperCase() === he.keyword){ // Handle case, paint yellow arrayedCode[i] = `${e}` } }) + highlights5.forEach(he =>{ + if(e.toUpperCase() === he.keyword){ + // Handle case, paint yellow + arrayedCode[i] = `${e}` + if(he.type === "comment1"){ + for (let index = 0; arrayedCode[i + index].includes("\n") == false; index++) { + arrayedCode[i + index] = `${arrayedCode[i+index]}` + } + } + } + }) + }) fragmentatedCode = arrayedCode.join(" ") From 9ba7fe4b2938c539664a3e37b85c1d62e5e10c59 Mon Sep 17 00:00:00 2001 From: Ethan Mahlstedt Date: Mon, 10 Mar 2025 14:27:34 -0700 Subject: [PATCH 009/126] Highlighter Rework Adds the highlight.js library and sets it up --- front/editor/editor.css | 2 +- front/editor/editor.html | 1 + front/editor/editor.js | 14 ------ front/editor/highlight.js | 56 ++------------------- front/editor/highlighter.css | 1 + front/editor/highlights/js/highlights1.json | 20 -------- front/editor/highlights/js/highlights2.json | 1 - front/editor/highlights/js/highlights3.json | 14 ------ front/editor/highlights/js/highlights4.json | 6 --- front/editor/highlights/js/highlights5.json | 4 -- package-lock.json | 10 ++++ package.json | 1 + 12 files changed, 17 insertions(+), 113 deletions(-) create mode 100644 front/editor/highlighter.css delete mode 100644 front/editor/highlights/js/highlights1.json delete mode 100644 front/editor/highlights/js/highlights2.json delete mode 100644 front/editor/highlights/js/highlights3.json delete mode 100644 front/editor/highlights/js/highlights4.json delete mode 100644 front/editor/highlights/js/highlights5.json diff --git a/front/editor/editor.css b/front/editor/editor.css index d297516..7d60e64 100644 --- a/front/editor/editor.css +++ b/front/editor/editor.css @@ -140,4 +140,4 @@ button:hover { padding: 5px; overflow-wrap: break-word; box-sizing: border-box; -} +} \ No newline at end of file diff --git a/front/editor/editor.html b/front/editor/editor.html index ce3100b..175a95d 100644 --- a/front/editor/editor.html +++ b/front/editor/editor.html @@ -4,6 +4,7 @@ Code Editor + diff --git a/front/editor/editor.js b/front/editor/editor.js index d279285..66a3aa9 100644 --- a/front/editor/editor.js +++ b/front/editor/editor.js @@ -186,8 +186,6 @@ textArea.addEventListener("input", () => { "data", textArea.innerText, ); - console.log(textArea.innerText) - console.log(typeof textArea.innerText) textArea.innerHTML = highlighter(textArea.innerText, currentFile); // Restore cursor position @@ -236,18 +234,6 @@ textArea.addEventListener("keydown", (event) => { } }); -function getCode() { - let code = textArea.innerHTML; - - // Convert real
elements to \n - code = code.replace(//gi, "\n"); - - // Convert user-typed "<br>" back to "
" - code = code.replace(/<br\s*\/?>/gi, "
"); - - return code; - } - ipcRenderer.on("open-editor", (event, file) => { document.addEventListener("DOMContentLoaded", () => { openFile(file, () => { diff --git a/front/editor/highlight.js b/front/editor/highlight.js index 9d8b798..8afb6f8 100644 --- a/front/editor/highlight.js +++ b/front/editor/highlight.js @@ -1,58 +1,8 @@ +const { highlight } = require('highlight.js') + module.exports = (code, filename) => { if(filename.endsWith(".js")){ - const highlights1 = require("./highlights/js/highlights1.json") - const highlights2 = require("./highlights/js/highlights2.json") - const highlights3 = require("./highlights/js/highlights3.json") - const highlights4 = require("./highlights/js/highlights4.json") - const highlights5 = require("./highlights/js/highlights5.json") - - let fragmentatedCode = "" - let arrayedCode = code.split(" ") - - arrayedCode.forEach((e, i)=>{ - highlights1.forEach(he =>{ - if(e.toUpperCase() === he.keyword){ - // Handle case, paint red - arrayedCode[i] = `${e}` - if(he.type === "declaration"){ - arrayedCode[i + 1] = `${arrayedCode[i + 1]}` - } - } - }) - highlights2.forEach(he =>{ - if(e.toUpperCase() === he.keyword){ - // Handle case, paint green - arrayedCode[i] = `${e}` - } - }) - highlights3.forEach(he =>{ - if(e.toUpperCase() === he.keyword){ - // Handle case, paint blue - arrayedCode[i] = `${e}` - } - }) - highlights4.forEach(he =>{ - if(e.toUpperCase() === he.keyword){ - // Handle case, paint yellow - arrayedCode[i] = `${e}` - } - }) - highlights5.forEach(he =>{ - if(e.toUpperCase() === he.keyword){ - // Handle case, paint yellow - arrayedCode[i] = `${e}` - if(he.type === "comment1"){ - for (let index = 0; arrayedCode[i + index].includes("\n") == false; index++) { - arrayedCode[i + index] = `${arrayedCode[i+index]}` - } - } - } - }) - - }) - - fragmentatedCode = arrayedCode.join(" ") - return fragmentatedCode + return highlight(code, {language: "javascript"}).value }else{ return code; } diff --git a/front/editor/highlighter.css b/front/editor/highlighter.css new file mode 100644 index 0000000..247e2e9 --- /dev/null +++ b/front/editor/highlighter.css @@ -0,0 +1 @@ +pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{background:#23241f;color:#f8f8f2}.hljs-subst,.hljs-tag{color:#f8f8f2}.hljs-emphasis,.hljs-strong{color:#a8a8a2}.hljs-bullet,.hljs-link,.hljs-literal,.hljs-number,.hljs-quote,.hljs-regexp{color:#ae81ff}.hljs-code,.hljs-section,.hljs-selector-class,.hljs-title{color:#a6e22e}.hljs-strong{font-weight:700}.hljs-emphasis{font-style:italic}.hljs-attr,.hljs-keyword,.hljs-name,.hljs-selector-tag{color:#f92672}.hljs-attribute,.hljs-symbol{color:#66d9ef}.hljs-class .hljs-title,.hljs-params,.hljs-title.class_{color:#f8f8f2}.hljs-addition,.hljs-built_in,.hljs-selector-attr,.hljs-selector-id,.hljs-selector-pseudo,.hljs-string,.hljs-template-variable,.hljs-type,.hljs-variable{color:#e6db74}.hljs-comment,.hljs-deletion,.hljs-meta{color:#75715e} \ No newline at end of file diff --git a/front/editor/highlights/js/highlights1.json b/front/editor/highlights/js/highlights1.json deleted file mode 100644 index c0f4f35..0000000 --- a/front/editor/highlights/js/highlights1.json +++ /dev/null @@ -1,20 +0,0 @@ -[ - {"keyword": "CONST", "type": "declaration"}, - {"keyword": "LET", "type": "declaration"}, - {"keyword": "FUNCTION", "type": "declaration"}, - {"keyword": "VAR", "type": "declaration"}, - {"keyword": "NEW", "type": "declaration"}, - {"keyword": "IF", "type": "keyword"}, - {"keyword": "ELSE", "type": "keyword"}, - {"keyword": "FOR", "type": "keyword"}, - {"keyword": "WHILE", "type": "keyword"}, - {"keyword": "DO", "type": "keyword"}, - {"keyword": "SWITCH", "type": "keyword"}, - {"keyword": "CASE", "type": "keyword"}, - {"keyword": "DEFAULT", "type": "keyword"}, - {"keyword": "BREAK", "type": "keyword"}, - {"keyword": "CONTINUE", "type": "keyword"}, - {"keyword": "RETURN", "type": "keyword"}, - {"keyword": "TRY", "type": "keyword"}, - {"keyword": "CATCH", "type": "keyword"} -] \ No newline at end of file diff --git a/front/editor/highlights/js/highlights2.json b/front/editor/highlights/js/highlights2.json deleted file mode 100644 index 0637a08..0000000 --- a/front/editor/highlights/js/highlights2.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/front/editor/highlights/js/highlights3.json b/front/editor/highlights/js/highlights3.json deleted file mode 100644 index ac054d3..0000000 --- a/front/editor/highlights/js/highlights3.json +++ /dev/null @@ -1,14 +0,0 @@ -[ - {"keyword": "=", "type": "keyword"}, - {"keyword": "!=", "type": "keyword"}, - {"keyword": "!==", "type": "keyword"}, - {"keyword": "==", "type": "keyword"}, - {"keyword": "===", "type": "keyword"}, - {"keyword": "=>", "type": "keyword"}, - {"keyword": "(", "type": "keyword"}, - {"keyword": ")", "type": "keyword"}, - {"keyword": ">=", "type": "keyword"}, - {"keyword": "<=", "type": "keyword"}, - {"keyword": "<", "type": "keyword"}, - {"keyword": ">", "type": "keyword"} -] \ No newline at end of file diff --git a/front/editor/highlights/js/highlights4.json b/front/editor/highlights/js/highlights4.json deleted file mode 100644 index a767beb..0000000 --- a/front/editor/highlights/js/highlights4.json +++ /dev/null @@ -1,6 +0,0 @@ -[ - {"keyword": "[", "type": "keyword"}, - {"keyword": "]", "type": "keyword"}, - {"keyword": "{", "type": "keyword"}, - {"keyword": "}", "type": "keyword"} -] \ No newline at end of file diff --git a/front/editor/highlights/js/highlights5.json b/front/editor/highlights/js/highlights5.json deleted file mode 100644 index b6191cd..0000000 --- a/front/editor/highlights/js/highlights5.json +++ /dev/null @@ -1,4 +0,0 @@ -[ - {"keyword": "//", "type": "comment1"}, - {"keyword": "/*", "type": "comment2"} -] \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index cea66c5..a81080b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "version": "1.0.0", "license": "ISC", "dependencies": { + "highlight.js": "^11.11.1", "needle-db": "^1.1.3" }, "devDependencies": { @@ -1202,6 +1203,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/highlight.js": { + "version": "11.11.1", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.11.1.tgz", + "integrity": "sha512-Xwwo44whKBVCYoliBQwaPvtd/2tYFkRQtXDWj1nackaV2JPXx3L0+Jvd8/qCJ2p+ML0/XVkJ2q+Mr+UVdpJK5w==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/http-cache-semantics": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", diff --git a/package.json b/package.json index efe8db6..cbeb8de 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ "prettier": "3.4.2" }, "dependencies": { + "highlight.js": "^11.11.1", "needle-db": "^1.1.3" } } From 911306f0c20903879e10f32f7e15b8323ff772a3 Mon Sep 17 00:00:00 2001 From: Ethan Mahlstedt Date: Tue, 11 Mar 2025 15:03:51 -0700 Subject: [PATCH 010/126] Add CSS, TS, JSX, HTML / JSON --- eslint.config.mjs | 2 +- front/editor/editor.css | 6 +- front/editor/editor.html | 2 +- front/editor/editor.js | 117 ++++++++++--------- front/editor/highlight.js | 22 ++-- front/editor/highlighter.css | 72 +++++++++++- front/editor/highlightertest.js | 4 +- front/newFileDialog/newFileDialog.js | 2 +- front/pickOpenedDisplay/pickOpenedDisplay.js | 2 +- main.js | 42 +++---- modules/fileStringFunctions.js | 2 +- 11 files changed, 178 insertions(+), 95 deletions(-) diff --git a/eslint.config.mjs b/eslint.config.mjs index 38ae6cc..27ede42 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -7,5 +7,5 @@ export default [ { files: ["**/*.js"], languageOptions: { sourceType: "commonjs" } }, { languageOptions: { globals: { ...globals.browser, ...globals.node } } }, pluginJs.configs.recommended, - eslintConfigPrettier, + eslintConfigPrettier ]; diff --git a/front/editor/editor.css b/front/editor/editor.css index 7d60e64..891dad4 100644 --- a/front/editor/editor.css +++ b/front/editor/editor.css @@ -137,7 +137,7 @@ button:hover { white-space: pre-wrap; word-wrap: break-word; min-height: 100px; /* Ensure it has height */ - padding: 5px; - overflow-wrap: break-word; + padding: 5px; + overflow-wrap: break-word; box-sizing: border-box; -} \ No newline at end of file +} diff --git a/front/editor/editor.html b/front/editor/editor.html index 175a95d..a01ef56 100644 --- a/front/editor/editor.html +++ b/front/editor/editor.html @@ -4,7 +4,7 @@ Code Editor - + diff --git a/front/editor/editor.js b/front/editor/editor.js index 6f4277e..9d22f56 100644 --- a/front/editor/editor.js +++ b/front/editor/editor.js @@ -4,9 +4,9 @@ const lineNumbers = document.getElementById("lineNumbers"); const { getFileDirFromLink, getFileDivIdFromLink, - getFileNameFromLink, + getFileNameFromLink } = require("../../modules/fileStringFunctions"); -const highlighter = require("./highlight") +const highlighter = require("./highlight"); // Setup needle table @@ -29,7 +29,8 @@ let currentFile = null; // TODO: Make a scrollbar on FileDivContainer for overflow -function printOnBackConsole(args) {// eslint-disable-line +// prettier-ignore +function printOnBackConsole(args) { // eslint-disable-line // Debug function ipcRenderer.send("printOnBackConsole", args); @@ -167,60 +168,59 @@ textArea.addEventListener("scroll", () => { }); textArea.addEventListener("input", () => { - const selection = window.getSelection(); - let caretOffset = 0; // Store cursor position relative to text content - - if (selection.rangeCount > 0) { - const range = selection.getRangeAt(0); - const preCaretRange = range.cloneRange(); // Clone range for measurement - preCaretRange.selectNodeContents(textArea); - preCaretRange.setEnd(range.startContainer, range.startOffset); - caretOffset = preCaretRange.toString().length; // Get offset in characters - } + const selection = window.getSelection(); + let caretOffset = 0; // Store cursor position relative to text content + + if (selection.rangeCount > 0) { + const range = selection.getRangeAt(0); + const preCaretRange = range.cloneRange(); // Clone range for measurement + preCaretRange.selectNodeContents(textArea); + preCaretRange.setEnd(range.startContainer, range.startOffset); + caretOffset = preCaretRange.toString().length; // Get offset in characters + } - const scrollPosition = textArea.scrollTop; // Preserve scroll position - - // Update content - OpenedFiles.SET( - OpenedFiles.FINDQUICKINDEX("fileLink", currentFile), - "data", - textArea.innerText, - ); - textArea.innerHTML = highlighter(textArea.innerText, currentFile); - - // Restore cursor position - const newRange = document.createRange(); - const newSelection = window.getSelection(); - let charIndex = 0; - let found = false; - - function setCaret(node) { - if (node.nodeType === Node.TEXT_NODE) { - const nextCharIndex = charIndex + node.length; - if (!found && caretOffset >= charIndex && caretOffset <= nextCharIndex) { - newRange.setStart(node, caretOffset - charIndex); - newRange.setEnd(node, caretOffset - charIndex); - found = true; - } - charIndex = nextCharIndex; - } else { - node.childNodes.forEach(setCaret); - } - } + const scrollPosition = textArea.scrollTop; // Preserve scroll position - setCaret(textArea); + // Update content + OpenedFiles.SET( + OpenedFiles.FINDQUICKINDEX("fileLink", currentFile), + "data", + textArea.innerText + ); + textArea.innerHTML = highlighter(textArea.innerText, currentFile); - newSelection.removeAllRanges(); - newSelection.addRange(newRange); - textArea.scrollTop = scrollPosition; // Restore scroll position -}); + // Restore cursor position + const newRange = document.createRange(); + const newSelection = window.getSelection(); + let charIndex = 0; + let found = false; + + function setCaret(node) { + if (node.nodeType === Node.TEXT_NODE) { + const nextCharIndex = charIndex + node.length; + if (!found && caretOffset >= charIndex && caretOffset <= nextCharIndex) { + newRange.setStart(node, caretOffset - charIndex); + newRange.setEnd(node, caretOffset - charIndex); + found = true; + } + charIndex = nextCharIndex; + } else { + node.childNodes.forEach(setCaret); + } + } + + setCaret(textArea); + newSelection.removeAllRanges(); + newSelection.addRange(newRange); + textArea.scrollTop = scrollPosition; // Restore scroll position +}); textArea.addEventListener("keydown", (event) => { if (event.key === "Enter") { event.preventDefault(); document.execCommand("insertLineBreak"); // Insert
- } + } if (event.key === "Tab") { event.preventDefault(); @@ -252,18 +252,21 @@ ipcRenderer.on("open-editor", (event, file) => { const saveButton = document.getElementById("SaveBtn"); saveButton.addEventListener("click", () => { - console.log(OpenedFiles.FINDQUICKINDEX("fileLink", currentFile)) + console.log(OpenedFiles.FINDQUICKINDEX("fileLink", currentFile)); ipcRenderer.send( "save-file", currentFile, - OpenedFiles.READ(OpenedFiles.FINDQUICKINDEX("fileLink", currentFile), "data"), + OpenedFiles.READ( + OpenedFiles.FINDQUICKINDEX("fileLink", currentFile), + "data" + ) ); }); function loadFileIntoEditor(file) { if (currentFile !== null) { const lastCurrentFile = currentFile; - currentFile = file + currentFile = file; document .getElementById(getFileDivIdFromLink(lastCurrentFile)) @@ -282,13 +285,13 @@ function loadFileIntoEditor(file) { OpenedFiles.SET( OpenedFiles.FINDQUICKINDEX("fileLink", lastCurrentFile), "data", - textArea.innerText, + textArea.innerText ); } currentFile = file; textArea.innerText = OpenedFiles.READ( OpenedFiles.FINDQUICKINDEX("fileLink", currentFile), - "data", + "data" ); textArea.innerHTML = highlighter(textArea.innerText, currentFile); updateLineNumbers(); @@ -308,20 +311,20 @@ document.getElementById("RefreshEditor").addEventListener("click", () => { if ( OpenedFiles.READ( OpenedFiles.FINDQUICKINDEX("fileLink", currentFile), - "linkedDisplay", + "linkedDisplay" ) == null ) { ipcRenderer.invoke( "pickOpenedDisplay", - OpenedFiles.FINDQUICKINDEX("fileLink", currentFile), + OpenedFiles.FINDQUICKINDEX("fileLink", currentFile) ); } else { ipcRenderer.send( "restartDisplay", OpenedFiles.READ( OpenedFiles.FINDQUICKINDEX("fileLink", currentFile), - "linkedDisplay", - ), + "linkedDisplay" + ) ); } }); diff --git a/front/editor/highlight.js b/front/editor/highlight.js index 8afb6f8..67f6023 100644 --- a/front/editor/highlight.js +++ b/front/editor/highlight.js @@ -1,9 +1,17 @@ -const { highlight } = require('highlight.js') +const { highlight } = require("highlight.js"); module.exports = (code, filename) => { - if(filename.endsWith(".js")){ - return highlight(code, {language: "javascript"}).value - }else{ - return code; - } -} \ No newline at end of file + if (filename.endsWith(".js") || filename.endsWith(".jsx")) { + return highlight(code, { language: "javascript" }).value; + } else if (filename.endsWith(".html") || filename.endsWith(".htm")) { + return highlight(code, { language: "html" }).value; + } else if (filename.endsWith(".css")) { + return highlight(code, { language: "css" }).value; + } else if (filename.endsWith(".json")){ + return highlight(code, { language: "json" }).value; + }else if (filename.endsWith(".ts")){ + return highlight(code, { language: "typescript" }).value; + } else { + return code; + } +}; diff --git a/front/editor/highlighter.css b/front/editor/highlighter.css index 247e2e9..5c1d9f2 100644 --- a/front/editor/highlighter.css +++ b/front/editor/highlighter.css @@ -1 +1,71 @@ -pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{background:#23241f;color:#f8f8f2}.hljs-subst,.hljs-tag{color:#f8f8f2}.hljs-emphasis,.hljs-strong{color:#a8a8a2}.hljs-bullet,.hljs-link,.hljs-literal,.hljs-number,.hljs-quote,.hljs-regexp{color:#ae81ff}.hljs-code,.hljs-section,.hljs-selector-class,.hljs-title{color:#a6e22e}.hljs-strong{font-weight:700}.hljs-emphasis{font-style:italic}.hljs-attr,.hljs-keyword,.hljs-name,.hljs-selector-tag{color:#f92672}.hljs-attribute,.hljs-symbol{color:#66d9ef}.hljs-class .hljs-title,.hljs-params,.hljs-title.class_{color:#f8f8f2}.hljs-addition,.hljs-built_in,.hljs-selector-attr,.hljs-selector-id,.hljs-selector-pseudo,.hljs-string,.hljs-template-variable,.hljs-type,.hljs-variable{color:#e6db74}.hljs-comment,.hljs-deletion,.hljs-meta{color:#75715e} \ No newline at end of file +pre code.hljs { + display: block; + overflow-x: auto; + padding: 1em; +} +code.hljs { + padding: 3px 5px; +} +.hljs { + background: #23241f; + color: #f8f8f2; +} +.hljs-subst, +.hljs-tag { + color: #f8f8f2; +} +.hljs-emphasis, +.hljs-strong { + color: #a8a8a2; +} +.hljs-bullet, +.hljs-link, +.hljs-literal, +.hljs-number, +.hljs-quote, +.hljs-regexp { + color: #ae81ff; +} +.hljs-code, +.hljs-section, +.hljs-selector-class, +.hljs-title { + color: #a6e22e; +} +.hljs-strong { + font-weight: 700; +} +.hljs-emphasis { + font-style: italic; +} +.hljs-attr, +.hljs-keyword, +.hljs-name, +.hljs-selector-tag { + color: #f92672; +} +.hljs-attribute, +.hljs-symbol { + color: #66d9ef; +} +.hljs-class .hljs-title, +.hljs-params, +.hljs-title.class_ { + color: #f8f8f2; +} +.hljs-addition, +.hljs-built_in, +.hljs-selector-attr, +.hljs-selector-id, +.hljs-selector-pseudo, +.hljs-string, +.hljs-template-variable, +.hljs-type, +.hljs-variable { + color: #e6db74; +} +.hljs-comment, +.hljs-deletion, +.hljs-meta { + color: #75715e; +} diff --git a/front/editor/highlightertest.js b/front/editor/highlightertest.js index a2017de..3352807 100644 --- a/front/editor/highlightertest.js +++ b/front/editor/highlightertest.js @@ -1 +1,3 @@ -require("./highlight")("const jdbalsdaldhalsdj = djaspdjasd\nfunctionsa function ;") \ No newline at end of file +require("./highlight")( + "const jdbalsdaldhalsdj = djaspdjasd\nfunctionsa function ;" +); diff --git a/front/newFileDialog/newFileDialog.js b/front/newFileDialog/newFileDialog.js index 8bb385b..391feab 100644 --- a/front/newFileDialog/newFileDialog.js +++ b/front/newFileDialog/newFileDialog.js @@ -31,7 +31,7 @@ createBtn.addEventListener("click", () => { const args = { name: document.getElementById("filenameField").value, dir: dir, - preset: document.getElementById("presetPicker").value, + preset: document.getElementById("presetPicker").value }; if (args.dir == null || args.name == null || args.preset == null) { diff --git a/front/pickOpenedDisplay/pickOpenedDisplay.js b/front/pickOpenedDisplay/pickOpenedDisplay.js index e7225e5..b67db44 100644 --- a/front/pickOpenedDisplay/pickOpenedDisplay.js +++ b/front/pickOpenedDisplay/pickOpenedDisplay.js @@ -29,7 +29,7 @@ document.getElementById("pickWindowBtn").addEventListener("click", () => { "connectWindowSelection", document.getElementById("windowPicker").value, CallerFile, - CallerWindow, + CallerWindow ); } } else { diff --git a/main.js b/main.js index fd9ab1c..0ec206e 100644 --- a/main.js +++ b/main.js @@ -4,7 +4,7 @@ const { BrowserWindow, ipcMain, dialog, - webContents, + webContents } = require("electron"); const fs = require("fs"); const needle = require("needle-db"); @@ -28,8 +28,8 @@ const createWindow = () => { fullscreenable: false, webPreferences: { nodeIntegration: true, - contextIsolation: false, - }, + contextIsolation: false + } }); window.on("closed", () => { @@ -50,7 +50,7 @@ app.on("window-all-closed", () => { ipcMain.on("new-window", async () => { const result = await dialog.showOpenDialog({ properties: ["openFile"], - filters: [{ name: "HTML Files", extensions: ["html"] }], + filters: [{ name: "HTML Files", extensions: ["html"] }] }); if (!result.canceled && result.filePaths && result.filePaths[0]) { const newWdwFMT = openedDisplays.FORMAT(); @@ -58,7 +58,7 @@ ipcMain.on("new-window", async () => { newWdwFMT.SET("fileLink", result.filePaths[0]); newWdwFMT.SET( "window", - launchWindow(result.filePaths[0], { width: 500, height: 500 }), + launchWindow(result.filePaths[0], { width: 500, height: 500 }) ); openedDisplays.PUSH(newWdwFMT); @@ -66,7 +66,7 @@ ipcMain.on("new-window", async () => { openedDisplays .READ( openedDisplays.FINDQUICKINDEX("fileLink", result.filePaths[0]), - "window", + "window" ) .webContents.on("destroyed", () => { // Handle window closed @@ -80,15 +80,15 @@ ipcMain.on("new-editor", async () => { filters: [ { name: "Web development files", - extensions: ["html", "css", "js", "json"], - }, - ], + extensions: ["html", "css", "js", "json"] + } + ] }); if (!result.canceled && result.filePaths && result.filePaths[0]) { let editWindow = launchWindow("./front/editor/editor.html", { width: 500, height: 500, - webPreferences: { nodeIntegration: true, contextIsolation: false }, + webPreferences: { nodeIntegration: true, contextIsolation: false } }); editWindow.webContents.send("open-editor", result.filePaths[0]); } @@ -110,9 +110,9 @@ ipcMain.handle("filePickerDialog", async () => { filters: [ { name: "Web development files", - extensions: ["html", "css", "js", "json"], - }, - ], + extensions: ["html", "css", "js", "json"] + } + ] }); return result.filePaths[0]; }); @@ -125,14 +125,14 @@ ipcMain.on("new-file-wdw", () => { fullscreenable: false, webPreferences: { nodeIntegration: true, - contextIsolation: false, - }, + contextIsolation: false + } }); }); ipcMain.handle("get-dir", async () => { const result = await dialog.showOpenDialog({ - properties: ["openDirectory"], + properties: ["openDirectory"] }); if (result.canceled == false && result.filePaths.length == 1) { @@ -176,7 +176,7 @@ ipcMain.handle("createFile", (event, args) => { ipcMain.on("closeWindow", (event) => { const senderWindow = BrowserWindow.getAllWindows().find( - (win) => win.webContents === event.sender, + (win) => win.webContents === event.sender ); if (senderWindow) { @@ -196,8 +196,8 @@ ipcMain.handle("pickOpenedDisplay", (event, callerFileIndex) => { height: 135, resizable: true, // Debug fullscreenable: false, - webPreferences: { nodeIntegration: true, contextIsolation: false }, - }, + webPreferences: { nodeIntegration: true, contextIsolation: false } + } ); let openedDisplaysReduced = []; openedDisplays.GETJSONDATA().forEach((e, i) => { @@ -206,7 +206,7 @@ ipcMain.handle("pickOpenedDisplay", (event, callerFileIndex) => { dialog.webContents.send("loadOpenedEditors", { callerWindowId: event.sender.id, openedDisplays: openedDisplaysReduced, - caller: callerFileIndex, + caller: callerFileIndex }); // Handling Idea: Send the editor who called the new display and the file looking to link to the dialog, so it can call the window itself and handle the file link @@ -218,7 +218,7 @@ ipcMain.on( webContents .fromId(CallerWindow) .send("syncLinkedDisplay", callerFile, value); - }, + } ); ipcMain.on("printOpenedDisplays", () => { diff --git a/modules/fileStringFunctions.js b/modules/fileStringFunctions.js index 8931494..1be6372 100644 --- a/modules/fileStringFunctions.js +++ b/modules/fileStringFunctions.js @@ -25,5 +25,5 @@ function getFileDivIdFromLink(file) { module.exports = { getFileDirFromLink, getFileDivIdFromLink, - getFileNameFromLink, + getFileNameFromLink }; From 73e12a9cc9645e4ab1cbf11043cdfb6b2af51fb8 Mon Sep 17 00:00:00 2001 From: Ethan Mahlstedt Date: Fri, 14 Mar 2025 09:57:46 -0700 Subject: [PATCH 011/126] Add more language support --- front/editor/highlight.js | 15 ++-- front/editor/highlighter.css | 123 +++++++++++++++++--------------- front/editor/highlightertest.js | 3 - main.js | 4 +- 4 files changed, 78 insertions(+), 67 deletions(-) delete mode 100644 front/editor/highlightertest.js diff --git a/front/editor/highlight.js b/front/editor/highlight.js index 67f6023..e21264f 100644 --- a/front/editor/highlight.js +++ b/front/editor/highlight.js @@ -1,17 +1,24 @@ const { highlight } = require("highlight.js"); module.exports = (code, filename) => { - if (filename.endsWith(".js") || filename.endsWith(".jsx")) { + if (filename.endsWith(".js") || filename.endsWith(".jsx") || filename.endsWith(".mjs") || filename.endsWith(".cjs")) { return highlight(code, { language: "javascript" }).value; } else if (filename.endsWith(".html") || filename.endsWith(".htm")) { return highlight(code, { language: "html" }).value; } else if (filename.endsWith(".css")) { return highlight(code, { language: "css" }).value; - } else if (filename.endsWith(".json")){ + } else if (filename.endsWith(".json")) { return highlight(code, { language: "json" }).value; - }else if (filename.endsWith(".ts")){ + } else if (filename.endsWith(".ts") || filename.endsWith(".tsx")) { return highlight(code, { language: "typescript" }).value; - } else { + } else if(filename.endsWith(".md")) { + return highlight(code, { language: "markdown" }).value; + } else if(filename.endsWith(".php")) { + return highlight(code, { language: "php" }).value; + } else if(filename.endsWith(".xml")) { + return highlight(code, {language: "xml"}).value; + } + else{ return code; } }; diff --git a/front/editor/highlighter.css b/front/editor/highlighter.css index 5c1d9f2..18258ed 100644 --- a/front/editor/highlighter.css +++ b/front/editor/highlighter.css @@ -1,71 +1,78 @@ -pre code.hljs { - display: block; - overflow-x: auto; - padding: 1em; -} -code.hljs { - padding: 3px 5px; -} +/* Uses Highlight.js schemes, available at: https://github.com/highlightjs/highlight.js/tree/main/src/styles */ + +/* Default theme: Monokai Sublime - https://github.com/highlightjs/highlight.js/blob/main/src/styles/monokai-sublime.css */ + .hljs { background: #23241f; color: #f8f8f2; -} -.hljs-subst, -.hljs-tag { + } + + .hljs-tag, + .hljs-subst { color: #f8f8f2; -} -.hljs-emphasis, -.hljs-strong { + } + + .hljs-strong, + .hljs-emphasis { color: #a8a8a2; -} -.hljs-bullet, -.hljs-link, -.hljs-literal, -.hljs-number, -.hljs-quote, -.hljs-regexp { + } + + .hljs-bullet, + .hljs-quote, + .hljs-number, + .hljs-regexp, + .hljs-literal, + .hljs-link { color: #ae81ff; -} -.hljs-code, -.hljs-section, -.hljs-selector-class, -.hljs-title { + } + + .hljs-code, + .hljs-title, + .hljs-section, + .hljs-selector-class { color: #a6e22e; -} -.hljs-strong { - font-weight: 700; -} -.hljs-emphasis { + } + + .hljs-strong { + font-weight: bold; + } + + .hljs-emphasis { font-style: italic; -} -.hljs-attr, -.hljs-keyword, -.hljs-name, -.hljs-selector-tag { + } + + .hljs-keyword, + .hljs-selector-tag, + .hljs-name, + .hljs-attr { color: #f92672; -} -.hljs-attribute, -.hljs-symbol { + } + + .hljs-symbol, + .hljs-attribute { color: #66d9ef; -} -.hljs-class .hljs-title, -.hljs-params, -.hljs-title.class_ { + } + + .hljs-params, + .hljs-title.class_, + .hljs-class .hljs-title { color: #f8f8f2; -} -.hljs-addition, -.hljs-built_in, -.hljs-selector-attr, -.hljs-selector-id, -.hljs-selector-pseudo, -.hljs-string, -.hljs-template-variable, -.hljs-type, -.hljs-variable { + } + + .hljs-string, + .hljs-type, + .hljs-built_in, + .hljs-selector-id, + .hljs-selector-attr, + .hljs-selector-pseudo, + .hljs-addition, + .hljs-variable, + .hljs-template-variable { color: #e6db74; -} -.hljs-comment, -.hljs-deletion, -.hljs-meta { + } + + .hljs-comment, + .hljs-deletion, + .hljs-meta { color: #75715e; -} + } \ No newline at end of file diff --git a/front/editor/highlightertest.js b/front/editor/highlightertest.js deleted file mode 100644 index 3352807..0000000 --- a/front/editor/highlightertest.js +++ /dev/null @@ -1,3 +0,0 @@ -require("./highlight")( - "const jdbalsdaldhalsdj = djaspdjasd\nfunctionsa function ;" -); diff --git a/main.js b/main.js index 0ec206e..d4e0a45 100644 --- a/main.js +++ b/main.js @@ -80,7 +80,7 @@ ipcMain.on("new-editor", async () => { filters: [ { name: "Web development files", - extensions: ["html", "css", "js", "json"] + extensions: ["html", "htm", "mjs", "cjs", "jsx", "ts", "css", "js", "json", "tsx", "md", "txt", "php", "xml"] } ] }); @@ -110,7 +110,7 @@ ipcMain.handle("filePickerDialog", async () => { filters: [ { name: "Web development files", - extensions: ["html", "css", "js", "json"] + extensions: ["html", "htm", "mjs", "cjs", "jsx", "ts", "css", "js", "json", "tsx", "md", "txt", "php", "xml"] } ] }); From 91eb765734ad2c8c3c051741012085104757a4b0 Mon Sep 17 00:00:00 2001 From: Ethan Mahlstedt Date: Fri, 14 Mar 2025 11:39:58 -0700 Subject: [PATCH 012/126] Clean up Clean up unused button.css and some lines at the .gitignore --- .gitignore | 4 +--- front/stdResources/button.css | 22 ---------------------- 2 files changed, 1 insertion(+), 25 deletions(-) delete mode 100644 front/stdResources/button.css diff --git a/.gitignore b/.gitignore index def0b19..b512c09 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1 @@ -node_modules -.vscode -.hintrc +node_modules \ No newline at end of file diff --git a/front/stdResources/button.css b/front/stdResources/button.css deleted file mode 100644 index 3dea533..0000000 --- a/front/stdResources/button.css +++ /dev/null @@ -1,22 +0,0 @@ -.defbtn { - background-color: gray; - font-family: Arial; - color: black; - padding: 5px 10px; - border-radius: 5px; - border: 1px ridge black; - font-size: 24; - font-weight: bold; -} - -.defbtn:hover { - background-color: rgb(64, 64, 64); - font-family: Arial; - align-self: center; - color: white; - padding: 5px 10px; - border-radius: 5px; - border: 1px ridge black; - font-size: 24; - font-weight: bold; -} From 2195e45b54289b051cdf8ce68b71c7cebb4044c6 Mon Sep 17 00:00:00 2001 From: Ethan Mahlstedt Date: Fri, 14 Mar 2025 11:42:06 -0700 Subject: [PATCH 013/126] Handle file closing Handle File Closing TODO: Handle case of an unsaved file --- front/editor/editor.js | 142 +++++++++++++++-------------------------- 1 file changed, 50 insertions(+), 92 deletions(-) diff --git a/front/editor/editor.js b/front/editor/editor.js index 9d22f56..067bd87 100644 --- a/front/editor/editor.js +++ b/front/editor/editor.js @@ -55,25 +55,6 @@ function newFileDiv(file) { fileDivBtn.addEventListener("click", () => { closeFile(file); - /* TODO: - fileDiv.remove(); - let idx = null - OpenedFile.forEach((element, index) => { - - if(element.file == this.file){ - - idx = index - - } - - }); - if (idx > -1) { - OpenedFiles.splice(idx, 1); - } - if(OpenedFiles.length == 0){ - window.close() - } - */ }); fileDiv.appendChild(fileDivText); @@ -81,47 +62,6 @@ function newFileDiv(file) { document.getElementById("FilePicker").appendChild(fileDiv); } -/* - - DELETE AFTER OPENFILE FUNCTION IS DONE - - ipcRenderer.invoke('open-file').then((response)=>{ - - if(!response.status == -1){ - - const lastCurrentFile = currentFile - const lcfDiv = document.getElementById(`filediv-${lastCurrentFile}`) - lcfDiv.classList.remove("curFileDiv"); - lcfDiv.classList.add("fileDiv"); - - const oldFileIndex = OpenedFiles.indexOf(lastCurrentFile) - cacheData[oldFileIndex] = textArea.innerText - - const Div = new FileDiv(response.file); - Div.displayFileDiv(); - currentFile = response.file - OpenedFiles.push(response.file) - - const cfDiv = document.getElementById(`filediv-${response.file}`) - cfDiv.classList.add("curFileDiv"); - cfDiv.classList.remove("fileDiv"); - - document.title = `${Div.fileName} - HTMLEditor` - - textArea.innerText = response.filedata - const fileIndex = OpenedFiles.indexOf(response.file) - cacheData[fileIndex] = response.filedata - updateLineNumbers(); - - }else{ - - alert("Error in opening file.") - - } - }) - -*/ - function openFile(file, callback) { if (OpenedFiles.FINDQUICKINDEX("fileLink", file) === -1) { const fileFMT = OpenedFiles.FORMAT(); @@ -145,13 +85,23 @@ function openFile(file, callback) { } function closeFile(file) { - // TODO: Handle current file closing case // TODO: Handle case if file is not saved - const div = getFileDivIdFromLink(file); + const div = document.getElementById(getFileDivIdFromLink(file)); div.remove(); OpenedFiles.DELETE(OpenedFiles.FINDQUICKINDEX("fileLink", file)); + + if(OpenedFiles.GETJSONDATA().length == 0){ + ipcRenderer.send("closeWindow"); + }else{ + if(currentFile == file){ + console.log(OpenedFiles.GETJSONDATA()); + const nextFile = OpenedFiles.GETJSONDATA()[0].fileLink; + console.log(nextFile) + loadFileIntoEditor(nextFile); + } + } } function updateLineNumbers() { @@ -264,39 +214,47 @@ saveButton.addEventListener("click", () => { }); function loadFileIntoEditor(file) { - if (currentFile !== null) { - const lastCurrentFile = currentFile; - currentFile = file; + if(document.getElementById(getFileDivIdFromLink(file))){ + if (currentFile !== null) { + const lastCurrentFile = currentFile; + currentFile = file; + + if(document.getElementById(getFileDivIdFromLink(lastCurrentFile))){ + document + .getElementById(getFileDivIdFromLink(lastCurrentFile)) + .classList.remove("curFileDiv"); + + document + .getElementById(getFileDivIdFromLink(lastCurrentFile)) + .classList.add("fileDiv"); + } + + document + .getElementById(getFileDivIdFromLink(currentFile)) + .classList.add("curFileDiv"); + document + .getElementById(getFileDivIdFromLink(currentFile)) + .classList.remove("fileDiv"); + + if(document.getElementById(getFileDivIdFromLink(lastCurrentFile))){ + OpenedFiles.SET( + OpenedFiles.FINDQUICKINDEX("fileLink", lastCurrentFile), + "data", + textArea.innerText + ); + } - document - .getElementById(getFileDivIdFromLink(lastCurrentFile)) - .classList.remove("curFileDiv"); - document - .getElementById(getFileDivIdFromLink(lastCurrentFile)) - .classList.add("fileDiv"); - - document - .getElementById(getFileDivIdFromLink(currentFile)) - .classList.add("curFileDiv"); - document - .getElementById(getFileDivIdFromLink(currentFile)) - .classList.remove("fileDiv"); - - OpenedFiles.SET( - OpenedFiles.FINDQUICKINDEX("fileLink", lastCurrentFile), - "data", - textArea.innerText + } + currentFile = file; + textArea.innerText = OpenedFiles.READ( + OpenedFiles.FINDQUICKINDEX("fileLink", currentFile), + "data" ); - } - currentFile = file; - textArea.innerText = OpenedFiles.READ( - OpenedFiles.FINDQUICKINDEX("fileLink", currentFile), - "data" - ); - textArea.innerHTML = highlighter(textArea.innerText, currentFile); - updateLineNumbers(); + textArea.innerHTML = highlighter(textArea.innerText, currentFile); + updateLineNumbers(); - document.title = `${getFileNameFromLink(file)} - HTMLEditor`; + document.title = `${getFileNameFromLink(file)} - HTMLEditor`; + } } document.getElementById("openFile").addEventListener("click", () => { From 709ad27a83fd8d46bbaacccd578845a1c06612bc Mon Sep 17 00:00:00 2001 From: Ethan Mahlstedt Date: Fri, 14 Mar 2025 12:44:45 -0700 Subject: [PATCH 014/126] Create not saved condition - Creates not saved condition - Creates lineCount using cloc (for dev) --- front/editor/editor.js | 11 ++++++++--- lineCount.bat | 2 ++ 2 files changed, 10 insertions(+), 3 deletions(-) create mode 100644 lineCount.bat diff --git a/front/editor/editor.js b/front/editor/editor.js index 067bd87..d048764 100644 --- a/front/editor/editor.js +++ b/front/editor/editor.js @@ -86,6 +86,14 @@ function openFile(file, callback) { function closeFile(file) { // TODO: Handle case if file is not saved + let savedData + ipcRenderer.invoke("get-file-data", file).then((response) => { + savedData = response; + }) + + if(OpenedFiles.READ(OpenedFiles.FINDQUICKINDEX("fileLink", file), "data") != savedData){ + alert("File not saved"); + } const div = document.getElementById(getFileDivIdFromLink(file)); @@ -96,9 +104,7 @@ function closeFile(file) { ipcRenderer.send("closeWindow"); }else{ if(currentFile == file){ - console.log(OpenedFiles.GETJSONDATA()); const nextFile = OpenedFiles.GETJSONDATA()[0].fileLink; - console.log(nextFile) loadFileIntoEditor(nextFile); } } @@ -202,7 +208,6 @@ ipcRenderer.on("open-editor", (event, file) => { const saveButton = document.getElementById("SaveBtn"); saveButton.addEventListener("click", () => { - console.log(OpenedFiles.FINDQUICKINDEX("fileLink", currentFile)); ipcRenderer.send( "save-file", currentFile, diff --git a/lineCount.bat b/lineCount.bat new file mode 100644 index 0000000..a977ad5 --- /dev/null +++ b/lineCount.bat @@ -0,0 +1,2 @@ +@echo off +cloc modules front filePresets main.js \ No newline at end of file From 381fddb0e3a0f04fa8852e9f886b277c9c1fea4a Mon Sep 17 00:00:00 2001 From: Ethan Mahlstedt Date: Mon, 24 Mar 2025 13:48:52 -0700 Subject: [PATCH 015/126] Create and Handle Save Dialog - Handle overflows - Create file not saved dialog --- .hintrc | 8 ++++ front/editor/editor.css | 22 +++++++++- front/editor/editor.html | 6 +++ front/editor/editor.js | 89 +++++++++++++++++++++++++++++++--------- 4 files changed, 103 insertions(+), 22 deletions(-) create mode 100644 .hintrc diff --git a/.hintrc b/.hintrc new file mode 100644 index 0000000..67b893a --- /dev/null +++ b/.hintrc @@ -0,0 +1,8 @@ +{ + "extends": [ + "development" + ], + "hints": { + "compat-api/css": "off" + } +} \ No newline at end of file diff --git a/front/editor/editor.css b/front/editor/editor.css index 891dad4..2cf7364 100644 --- a/front/editor/editor.css +++ b/front/editor/editor.css @@ -18,6 +18,12 @@ body { width: calc(100% - 1%); box-sizing: border-box; border-radius: 5px; + scrollbar-width: thin; +} + +#FilePicker { + overflow-y: hidden; + overflow-x: auto; } .fileDiv { @@ -83,7 +89,7 @@ button { color: black; padding: 5px 10px; border-radius: 5px; - border: 0px ridge black; + border: 1px ridge black; font-size: 16px; font-weight: bold; cursor: pointer; @@ -132,7 +138,8 @@ button:hover { border: none; outline: none; resize: none; - overflow-y: scroll; + overflow: auto; + scrollbar-width: thin; tab-size: 4; white-space: pre-wrap; word-wrap: break-word; @@ -141,3 +148,14 @@ button:hover { overflow-wrap: break-word; box-sizing: border-box; } + +#saveDialog { + background-color: rgb(48, 48, 48); +} + +#saveDialogText { + font-family: Arial; + font-weight: bold; + color: white; + justify-content: center; +} \ No newline at end of file diff --git a/front/editor/editor.html b/front/editor/editor.html index a01ef56..b627d38 100644 --- a/front/editor/editor.html +++ b/front/editor/editor.html @@ -20,5 +20,11 @@

 		
 		
+		
+			

File is not saved

+ + + +
diff --git a/front/editor/editor.js b/front/editor/editor.js index d048764..bdce436 100644 --- a/front/editor/editor.js +++ b/front/editor/editor.js @@ -36,7 +36,7 @@ function printOnBackConsole(args) { // eslint-disable-line ipcRenderer.send("printOnBackConsole", args); } -function newFileDiv(file) { +async function newFileDiv(file) { const fileDiv = document.createElement("div"); fileDiv.classList.add("fileDiv"); fileDiv.id = getFileDivIdFromLink(file); @@ -53,8 +53,8 @@ function newFileDiv(file) { fileDivBtn.classList.add("fileDivBtn"); fileDivBtn.textContent = "X"; - fileDivBtn.addEventListener("click", () => { - closeFile(file); + fileDivBtn.addEventListener("click", async() => { + await closeFile(file); }); fileDiv.appendChild(fileDivText); @@ -84,29 +84,69 @@ function openFile(file, callback) { } } -function closeFile(file) { +async function closeFile(file) { // TODO: Handle case if file is not saved let savedData - ipcRenderer.invoke("get-file-data", file).then((response) => { + await ipcRenderer.invoke("get-file-data", file).then((response) => { savedData = response; }) - if(OpenedFiles.READ(OpenedFiles.FINDQUICKINDEX("fileLink", file), "data") != savedData){ - alert("File not saved"); - } - - const div = document.getElementById(getFileDivIdFromLink(file)); + console.log(OpenedFiles.READ(OpenedFiles.FINDQUICKINDEX("fileLink", file), "data") != savedData) - div.remove(); - OpenedFiles.DELETE(OpenedFiles.FINDQUICKINDEX("fileLink", file)); - - if(OpenedFiles.GETJSONDATA().length == 0){ - ipcRenderer.send("closeWindow"); - }else{ - if(currentFile == file){ - const nextFile = OpenedFiles.GETJSONDATA()[0].fileLink; - loadFileIntoEditor(nextFile); - } + if(OpenedFiles.READ(OpenedFiles.FINDQUICKINDEX("fileLink", file), "data") != savedData){ + + const div = document.getElementById(getFileDivIdFromLink(file)); + const dialog = document.getElementById("saveDialog"); + dialog.showModal() + + const saveButton = document.getElementById("saveButtonDialog"); + const dontSaveButton = document.getElementById("notSaveButtonDialog"); + const cancelButton = document.getElementById("cancelSaveButtonDialog"); + + cancelButton.addEventListener('click', ()=>{ + dialog.close(); + }) + + dontSaveButton.addEventListener('click', ()=>{ + OpenedFiles.DELETE(OpenedFiles.FINDQUICKINDEX("fileLink", file)); + div.remove(); + dialog.close() + + if(OpenedFiles.GETJSONDATA().length == 0){ + ipcRenderer.send("closeWindow"); + }else{ + if(currentFile == file){ + const nextFile = OpenedFiles.GETJSONDATA()[0].fileLink; + loadFileIntoEditor(nextFile); + } + } + }) + + saveButton.addEventListener('click', ()=>{ + //TODO: HANDLE SAVE + + ipcRenderer.send( + "save-file", + file, + OpenedFiles.READ( + OpenedFiles.FINDQUICKINDEX("fileLink", file), + "data" + ) + ); + + OpenedFiles.DELETE(OpenedFiles.FINDQUICKINDEX("fileLink", file)); + div.remove(); + dialog.close(); + + if(OpenedFiles.GETJSONDATA().length == 0){ + ipcRenderer.send("closeWindow"); + }else{ + if(currentFile == file){ + const nextFile = OpenedFiles.GETJSONDATA()[0].fileLink; + loadFileIntoEditor(nextFile); + } + } + }) } } @@ -295,3 +335,12 @@ document.getElementById("RefreshEditor").addEventListener("click", () => { ipcRenderer.on("syncLinkedDisplay", (event, fileID, display) => { OpenedFiles.SET(fileID, "linkedDisplay", display); }); + +window.addEventListener("beforeunload", (event) => { + if(OpenedFiles.GETJSONDATA().length > 0){ + event.preventDefault(); + OpenedFiles.GETJSONDATA().forEach((e)=>{ + closeFile(e.fileLink) + }) + } +}); \ No newline at end of file From bec6bee0de2ff9d042c5d11c16e40cb7a7491831 Mon Sep 17 00:00:00 2001 From: Ethan Mahlstedt Date: Mon, 24 Mar 2025 18:44:59 -0700 Subject: [PATCH 016/126] Disable spellcheck --- front/editor/editor.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/front/editor/editor.html b/front/editor/editor.html index b627d38..4546e57 100644 --- a/front/editor/editor.html +++ b/front/editor/editor.html @@ -14,7 +14,7 @@ -
+


From b96724e12abc9da306c19213091b0e4f47d1c797 Mon Sep 17 00:00:00 2001
From: Ethan Mahlstedt 
Date: Mon, 31 Mar 2025 20:48:48 -0700
Subject: [PATCH 017/126] Preserve Scroll and Cursor position

- Preserve scroll and cursor position
- Separated some functions into modules
- Fixed wrapping and overflow for once and for all
---
 front/editor/editor.css                       |  10 +-
 front/editor/editor.html                      |   9 +-
 front/editor/editor.js                        | 230 ++++++++++--------
 front/editor/highlight.js                     |  18 +-
 front/editor/highlighter.css                  | 120 ++++-----
 front/editor/modules/caret.js                 |  47 ++++
 .../editor/modules}/fileStringFunctions.js    |   0
 main.js                                       |  34 ++-
 8 files changed, 297 insertions(+), 171 deletions(-)
 create mode 100644 front/editor/modules/caret.js
 rename {modules => front/editor/modules}/fileStringFunctions.js (100%)

diff --git a/front/editor/editor.css b/front/editor/editor.css
index 2cf7364..72e65e6 100644
--- a/front/editor/editor.css
+++ b/front/editor/editor.css
@@ -141,12 +141,12 @@ button:hover {
 	overflow: auto;
 	scrollbar-width: thin;
 	tab-size: 4;
-	white-space: pre-wrap;
-	word-wrap: break-word;
+	white-space: pre; /* Prevent wrapping */
+	word-wrap: normal;
 	min-height: 100px; /* Ensure it has height */
-	padding: 5px;
-	overflow-wrap: break-word;
 	box-sizing: border-box;
+	overflow-x: auto; /* Add horizontal scrollbar */
+	overflow-y: auto; /* Add vertical scrollbar */
 }
 
 #saveDialog {
@@ -158,4 +158,4 @@ button:hover {
 	font-weight: bold;
 	color: white;
 	justify-content: center;
-}
\ No newline at end of file
+}
diff --git a/front/editor/editor.html b/front/editor/editor.html
index 4546e57..27040bd 100644
--- a/front/editor/editor.html
+++ b/front/editor/editor.html
@@ -14,9 +14,14 @@
 			
 			
 		
-
+
-
+

 		
diff --git a/front/editor/editor.js b/front/editor/editor.js index bdce436..41c5c34 100644 --- a/front/editor/editor.js +++ b/front/editor/editor.js @@ -5,34 +5,31 @@ const { getFileDirFromLink, getFileDivIdFromLink, getFileNameFromLink -} = require("../../modules/fileStringFunctions"); +} = require("./modules/fileStringFunctions"); const highlighter = require("./highlight"); // Setup needle table - // Import Library const needle = require("needle-db"); - // Setup Table let OpenedFiles = new needle(); - // Setup Table Columns - OpenedFiles.NEWCOLUMN("fileLink"); // E:\\example\\example.js OpenedFiles.NEWCOLUMN("fileName"); // example.js OpenedFiles.NEWCOLUMN("fileDir"); // E:\\example OpenedFiles.NEWCOLUMN("linkedDisplay"); OpenedFiles.NEWCOLUMN("data"); OpenedFiles.NEWCOLUMN("fileDivId"); +OpenedFiles.NEWCOLUMN("savedScroll"); +OpenedFiles.NEWCOLUMN("savedCursor"); -let currentFile = null; +const { getCaretPosition, setCaretPosition } = require("./modules/caret"); -// TODO: Make a scrollbar on FileDivContainer for overflow +let currentFile = null; // prettier-ignore function printOnBackConsole(args) { // eslint-disable-line // Debug function - ipcRenderer.send("printOnBackConsole", args); } @@ -53,7 +50,7 @@ async function newFileDiv(file) { fileDivBtn.classList.add("fileDivBtn"); fileDivBtn.textContent = "X"; - fileDivBtn.addEventListener("click", async() => { + fileDivBtn.addEventListener("click", async () => { await closeFile(file); }); @@ -70,6 +67,8 @@ function openFile(file, callback) { fileFMT.SET("fileDir", getFileDirFromLink(file)); fileFMT.SET("linkedDisplay", null); fileFMT.SET("fileDivId", getFileDivIdFromLink(file)); + fileFMT.SET("savedScroll", null); + fileFMT.SET("savedCursor", null); newFileDiv(file); @@ -85,68 +84,76 @@ function openFile(file, callback) { } async function closeFile(file) { - // TODO: Handle case if file is not saved - let savedData + let savedData; await ipcRenderer.invoke("get-file-data", file).then((response) => { savedData = response; - }) - - console.log(OpenedFiles.READ(OpenedFiles.FINDQUICKINDEX("fileLink", file), "data") != savedData) + }); - if(OpenedFiles.READ(OpenedFiles.FINDQUICKINDEX("fileLink", file), "data") != savedData){ - + if ( + OpenedFiles.READ(OpenedFiles.FINDQUICKINDEX("fileLink", file), "data") !== + savedData + ) { const div = document.getElementById(getFileDivIdFromLink(file)); const dialog = document.getElementById("saveDialog"); - dialog.showModal() + dialog.showModal(); const saveButton = document.getElementById("saveButtonDialog"); const dontSaveButton = document.getElementById("notSaveButtonDialog"); const cancelButton = document.getElementById("cancelSaveButtonDialog"); - cancelButton.addEventListener('click', ()=>{ + cancelButton.addEventListener("click", () => { dialog.close(); - }) + }); - dontSaveButton.addEventListener('click', ()=>{ + dontSaveButton.addEventListener("click", () => { OpenedFiles.DELETE(OpenedFiles.FINDQUICKINDEX("fileLink", file)); div.remove(); - dialog.close() - - if(OpenedFiles.GETJSONDATA().length == 0){ + dialog.close(); + + if (OpenedFiles.GETJSONDATA().length === 0) { ipcRenderer.send("closeWindow"); - }else{ - if(currentFile == file){ + } else { + if (currentFile === file) { const nextFile = OpenedFiles.GETJSONDATA()[0].fileLink; loadFileIntoEditor(nextFile); } } - }) - - saveButton.addEventListener('click', ()=>{ - //TODO: HANDLE SAVE + }); + saveButton.addEventListener("click", () => { ipcRenderer.send( "save-file", file, - OpenedFiles.READ( - OpenedFiles.FINDQUICKINDEX("fileLink", file), - "data" - ) + OpenedFiles.READ(OpenedFiles.FINDQUICKINDEX("fileLink", file), "data") ); OpenedFiles.DELETE(OpenedFiles.FINDQUICKINDEX("fileLink", file)); div.remove(); dialog.close(); - - if(OpenedFiles.GETJSONDATA().length == 0){ + + if (OpenedFiles.GETJSONDATA().length === 0) { ipcRenderer.send("closeWindow"); - }else{ - if(currentFile == file){ + } else { + if (currentFile === file) { const nextFile = OpenedFiles.GETJSONDATA()[0].fileLink; loadFileIntoEditor(nextFile); } } - }) + }); + } else { + OpenedFiles.DELETE(OpenedFiles.FINDQUICKINDEX("fileLink", file)); + + const div = document.getElementById(getFileDivIdFromLink(file)); + div.remove(); + + if (OpenedFiles.GETJSONDATA().length === 0) { + ipcRenderer.send("closeWindow"); + } else { + if (currentFile === file) { + const nextFile = OpenedFiles.GETJSONDATA()[0].fileLink; + loadFileIntoEditor(nextFile); + } + } } } @@ -164,18 +171,8 @@ textArea.addEventListener("scroll", () => { }); textArea.addEventListener("input", () => { - const selection = window.getSelection(); - let caretOffset = 0; // Store cursor position relative to text content - - if (selection.rangeCount > 0) { - const range = selection.getRangeAt(0); - const preCaretRange = range.cloneRange(); // Clone range for measurement - preCaretRange.selectNodeContents(textArea); - preCaretRange.setEnd(range.startContainer, range.startOffset); - caretOffset = preCaretRange.toString().length; // Get offset in characters - } - const scrollPosition = textArea.scrollTop; // Preserve scroll position + const caretOffset = getCaretPosition(); // Update content OpenedFiles.SET( @@ -186,29 +183,7 @@ textArea.addEventListener("input", () => { textArea.innerHTML = highlighter(textArea.innerText, currentFile); // Restore cursor position - const newRange = document.createRange(); - const newSelection = window.getSelection(); - let charIndex = 0; - let found = false; - - function setCaret(node) { - if (node.nodeType === Node.TEXT_NODE) { - const nextCharIndex = charIndex + node.length; - if (!found && caretOffset >= charIndex && caretOffset <= nextCharIndex) { - newRange.setStart(node, caretOffset - charIndex); - newRange.setEnd(node, caretOffset - charIndex); - found = true; - } - charIndex = nextCharIndex; - } else { - node.childNodes.forEach(setCaret); - } - } - - setCaret(textArea); - - newSelection.removeAllRanges(); - newSelection.addRange(newRange); + setCaretPosition(caretOffset); textArea.scrollTop = scrollPosition; // Restore scroll position }); @@ -220,13 +195,13 @@ textArea.addEventListener("keydown", (event) => { if (event.key === "Tab") { event.preventDefault(); - const start = textArea.selectionStart; + const caretOffset = getCaretPosition(); const indent = "\t"; document.execCommand("insertText", false, indent); - textArea.selectionStart = textArea.selectionEnd = start + indent.length; + setCaretPosition(caretOffset + indent.length); } }); @@ -258,37 +233,60 @@ saveButton.addEventListener("click", () => { ); }); +textArea.addEventListener("focusout", () => { + if (currentFile !== null) { + // Save Caret Position + const savedCursor = getCaretPosition(); + OpenedFiles.SET( + OpenedFiles.FINDQUICKINDEX("fileLink", currentFile), + "savedCursor", + savedCursor + ); + // Save Scroll Position + const savedScroll = textArea.scrollTop; + OpenedFiles.SET( + OpenedFiles.FINDQUICKINDEX("fileLink", currentFile), + "savedScroll", + savedScroll + ); + } +}); + function loadFileIntoEditor(file) { - if(document.getElementById(getFileDivIdFromLink(file))){ + textArea.focus(); + if (document.getElementById(getFileDivIdFromLink(file))) { if (currentFile !== null) { const lastCurrentFile = currentFile; currentFile = file; - if(document.getElementById(getFileDivIdFromLink(lastCurrentFile))){ + if (document.getElementById(getFileDivIdFromLink(lastCurrentFile))) { document - .getElementById(getFileDivIdFromLink(lastCurrentFile)) - .classList.remove("curFileDiv"); + .getElementById(getFileDivIdFromLink(lastCurrentFile)) + .classList.remove("curFileDiv"); document - .getElementById(getFileDivIdFromLink(lastCurrentFile)) - .classList.add("fileDiv"); - } - - document - .getElementById(getFileDivIdFromLink(currentFile)) - .classList.add("curFileDiv"); - document - .getElementById(getFileDivIdFromLink(currentFile)) - .classList.remove("fileDiv"); - - if(document.getElementById(getFileDivIdFromLink(lastCurrentFile))){ + .getElementById(getFileDivIdFromLink(lastCurrentFile)) + .classList.add("fileDiv"); + OpenedFiles.SET( OpenedFiles.FINDQUICKINDEX("fileLink", lastCurrentFile), "data", textArea.innerText ); + + OpenedFiles.SET( + OpenedFiles.FINDQUICKINDEX("fileLink", lastCurrentFile), + "savedScroll", + textArea.scrollTop + ); } + document + .getElementById(getFileDivIdFromLink(currentFile)) + .classList.add("curFileDiv"); + document + .getElementById(getFileDivIdFromLink(currentFile)) + .classList.remove("fileDiv"); } currentFile = file; textArea.innerText = OpenedFiles.READ( @@ -296,6 +294,25 @@ function loadFileIntoEditor(file) { "data" ); textArea.innerHTML = highlighter(textArea.innerText, currentFile); + + const scroll = OpenedFiles.READ( + OpenedFiles.FINDQUICKINDEX("fileLink", currentFile), + "savedScroll" + ); + + const cursor = OpenedFiles.READ( + OpenedFiles.FINDQUICKINDEX("fileLink", currentFile), + "savedCursor" + ); + + if (scroll !== null) { + textArea.scrollTop = scroll; + } + + if (cursor !== null) { + setCaretPosition(cursor); + } + updateLineNumbers(); document.title = `${getFileNameFromLink(file)} - HTMLEditor`; @@ -337,10 +354,33 @@ ipcRenderer.on("syncLinkedDisplay", (event, fileID, display) => { }); window.addEventListener("beforeunload", (event) => { - if(OpenedFiles.GETJSONDATA().length > 0){ + if (OpenedFiles.GETJSONDATA().length > 0) { event.preventDefault(); - OpenedFiles.GETJSONDATA().forEach((e)=>{ - closeFile(e.fileLink) - }) + OpenedFiles.GETJSONDATA().forEach((e) => { + closeFile(e.fileLink); + }); + } +}); + +window.addEventListener("focus", () => { + if (currentFile) { + textArea.focus(); + const savedCursor = OpenedFiles.READ( + OpenedFiles.FINDQUICKINDEX("fileLink", currentFile), + "savedCursor" + ); + if (savedCursor !== null) { + setCaretPosition(savedCursor); + } + } +}); + +window.addEventListener("blur", () => { + if (currentFile && getCaretPosition() !== null) { + OpenedFiles.SET( + OpenedFiles.FINDQUICKINDEX("fileLink", currentFile), + "savedCursor", + getCaretPosition() + ); } -}); \ No newline at end of file +}); diff --git a/front/editor/highlight.js b/front/editor/highlight.js index e21264f..96788a6 100644 --- a/front/editor/highlight.js +++ b/front/editor/highlight.js @@ -1,7 +1,12 @@ const { highlight } = require("highlight.js"); module.exports = (code, filename) => { - if (filename.endsWith(".js") || filename.endsWith(".jsx") || filename.endsWith(".mjs") || filename.endsWith(".cjs")) { + if ( + filename.endsWith(".js") || + filename.endsWith(".jsx") || + filename.endsWith(".mjs") || + filename.endsWith(".cjs") + ) { return highlight(code, { language: "javascript" }).value; } else if (filename.endsWith(".html") || filename.endsWith(".htm")) { return highlight(code, { language: "html" }).value; @@ -11,14 +16,13 @@ module.exports = (code, filename) => { return highlight(code, { language: "json" }).value; } else if (filename.endsWith(".ts") || filename.endsWith(".tsx")) { return highlight(code, { language: "typescript" }).value; - } else if(filename.endsWith(".md")) { + } else if (filename.endsWith(".md")) { return highlight(code, { language: "markdown" }).value; - } else if(filename.endsWith(".php")) { + } else if (filename.endsWith(".php")) { return highlight(code, { language: "php" }).value; - } else if(filename.endsWith(".xml")) { - return highlight(code, {language: "xml"}).value; - } - else{ + } else if (filename.endsWith(".xml")) { + return highlight(code, { language: "xml" }).value; + } else { return code; } }; diff --git a/front/editor/highlighter.css b/front/editor/highlighter.css index 18258ed..2bf249e 100644 --- a/front/editor/highlighter.css +++ b/front/editor/highlighter.css @@ -5,74 +5,74 @@ .hljs { background: #23241f; color: #f8f8f2; - } - - .hljs-tag, - .hljs-subst { +} + +.hljs-tag, +.hljs-subst { color: #f8f8f2; - } - - .hljs-strong, - .hljs-emphasis { +} + +.hljs-strong, +.hljs-emphasis { color: #a8a8a2; - } - - .hljs-bullet, - .hljs-quote, - .hljs-number, - .hljs-regexp, - .hljs-literal, - .hljs-link { +} + +.hljs-bullet, +.hljs-quote, +.hljs-number, +.hljs-regexp, +.hljs-literal, +.hljs-link { color: #ae81ff; - } - - .hljs-code, - .hljs-title, - .hljs-section, - .hljs-selector-class { +} + +.hljs-code, +.hljs-title, +.hljs-section, +.hljs-selector-class { color: #a6e22e; - } - - .hljs-strong { +} + +.hljs-strong { font-weight: bold; - } - - .hljs-emphasis { +} + +.hljs-emphasis { font-style: italic; - } - - .hljs-keyword, - .hljs-selector-tag, - .hljs-name, - .hljs-attr { +} + +.hljs-keyword, +.hljs-selector-tag, +.hljs-name, +.hljs-attr { color: #f92672; - } - - .hljs-symbol, - .hljs-attribute { +} + +.hljs-symbol, +.hljs-attribute { color: #66d9ef; - } - - .hljs-params, - .hljs-title.class_, - .hljs-class .hljs-title { +} + +.hljs-params, +.hljs-title.class_, +.hljs-class .hljs-title { color: #f8f8f2; - } - - .hljs-string, - .hljs-type, - .hljs-built_in, - .hljs-selector-id, - .hljs-selector-attr, - .hljs-selector-pseudo, - .hljs-addition, - .hljs-variable, - .hljs-template-variable { +} + +.hljs-string, +.hljs-type, +.hljs-built_in, +.hljs-selector-id, +.hljs-selector-attr, +.hljs-selector-pseudo, +.hljs-addition, +.hljs-variable, +.hljs-template-variable { color: #e6db74; - } - - .hljs-comment, - .hljs-deletion, - .hljs-meta { +} + +.hljs-comment, +.hljs-deletion, +.hljs-meta { color: #75715e; - } \ No newline at end of file +} diff --git a/front/editor/modules/caret.js b/front/editor/modules/caret.js new file mode 100644 index 0000000..b85dd26 --- /dev/null +++ b/front/editor/modules/caret.js @@ -0,0 +1,47 @@ +const textArea = document.getElementById("TextArea"); + +module.exports.getCaretPosition = () => { + const selection = window.getSelection(); + let caretOffset = 0; // Store cursor position relative to text content + + if (selection.rangeCount > 0) { + const range = selection.getRangeAt(0); + + if (!textArea.contains(range.startContainer)) { + console.warn("Selection is outside the textArea or invalid"); + return null; + } + + const preCaretRange = range.cloneRange(); + preCaretRange.selectNodeContents(textArea); + preCaretRange.setEnd(range.startContainer, range.startOffset); + caretOffset = preCaretRange.toString().length; // Get offset in characters + } + + return caretOffset; +}; + +module.exports.setCaretPosition = (offset) => { + const range = document.createRange(); + const selection = window.getSelection(); + let charIndex = 0; + let found = false; + + function traverseNodes(node) { + if (node.nodeType === Node.TEXT_NODE) { + const nextCharIndex = charIndex + node.length; + if (!found && offset >= charIndex && offset <= nextCharIndex) { + range.setStart(node, offset - charIndex); + range.setEnd(node, offset - charIndex); + found = true; + } + charIndex = nextCharIndex; + } else { + node.childNodes.forEach(traverseNodes); + } + } + + traverseNodes(textArea); + selection.removeAllRanges(); + selection.addRange(range); +}; diff --git a/modules/fileStringFunctions.js b/front/editor/modules/fileStringFunctions.js similarity index 100% rename from modules/fileStringFunctions.js rename to front/editor/modules/fileStringFunctions.js diff --git a/main.js b/main.js index d4e0a45..7fce3d0 100644 --- a/main.js +++ b/main.js @@ -80,7 +80,22 @@ ipcMain.on("new-editor", async () => { filters: [ { name: "Web development files", - extensions: ["html", "htm", "mjs", "cjs", "jsx", "ts", "css", "js", "json", "tsx", "md", "txt", "php", "xml"] + extensions: [ + "html", + "htm", + "mjs", + "cjs", + "jsx", + "ts", + "css", + "js", + "json", + "tsx", + "md", + "txt", + "php", + "xml" + ] } ] }); @@ -110,7 +125,22 @@ ipcMain.handle("filePickerDialog", async () => { filters: [ { name: "Web development files", - extensions: ["html", "htm", "mjs", "cjs", "jsx", "ts", "css", "js", "json", "tsx", "md", "txt", "php", "xml"] + extensions: [ + "html", + "htm", + "mjs", + "cjs", + "jsx", + "ts", + "css", + "js", + "json", + "tsx", + "md", + "txt", + "php", + "xml" + ] } ] }); From f1c864ead3c4c4b6215da85975800b5c29f0b343 Mon Sep 17 00:00:00 2001 From: Ethan Mahlstedt <76834762+ImSpeddy@users.noreply.github.com> Date: Mon, 31 Mar 2025 20:55:22 -0700 Subject: [PATCH 018/126] Create TODOs --- TODOs | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 TODOs diff --git a/TODOs b/TODOs new file mode 100644 index 0000000..4c9990c --- /dev/null +++ b/TODOs @@ -0,0 +1,9 @@ += for VERSION 1.0 = +Create README +Add Keyboard Shortcuts +Fix link editor window size +Mark unsaved file +Branding (Icons, Coloring, and maybe a rename) + += for Version 1.1 = +Add Dynamic Skins From 0bc6ad72e7a70a3662a95d9f8d74caa49f251a93 Mon Sep 17 00:00:00 2001 From: Ethan Mahlstedt Date: Mon, 31 Mar 2025 21:04:53 -0700 Subject: [PATCH 019/126] Mark unsaved file --- front/editor/editor.css | 4 ++++ front/editor/editor.js | 19 +++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/front/editor/editor.css b/front/editor/editor.css index 72e65e6..f2c8ac8 100644 --- a/front/editor/editor.css +++ b/front/editor/editor.css @@ -159,3 +159,7 @@ button:hover { color: white; justify-content: center; } + +.unsavedFile { + font-style: italic; +} \ No newline at end of file diff --git a/front/editor/editor.js b/front/editor/editor.js index 41c5c34..a701955 100644 --- a/front/editor/editor.js +++ b/front/editor/editor.js @@ -22,6 +22,7 @@ OpenedFiles.NEWCOLUMN("data"); OpenedFiles.NEWCOLUMN("fileDivId"); OpenedFiles.NEWCOLUMN("savedScroll"); OpenedFiles.NEWCOLUMN("savedCursor"); +OpenedFiles.NEWCOLUMN("savedFile") const { getCaretPosition, setCaretPosition } = require("./modules/caret"); @@ -45,6 +46,7 @@ async function newFileDiv(file) { const fileDivText = document.createElement("p"); fileDivText.classList.add("fileDivText"); fileDivText.textContent = getFileNameFromLink(file); + fileDivText.id = getFileDivIdFromLink(file) + "-lbl"; const fileDivBtn = document.createElement("button"); fileDivBtn.classList.add("fileDivBtn"); @@ -74,6 +76,7 @@ function openFile(file, callback) { ipcRenderer.invoke("get-file-data", file).then((response) => { fileFMT.SET("data", response); + fileFMT.SET("savedFile", response); OpenedFiles.PUSH(fileFMT); if (typeof callback == "function") callback(); @@ -180,6 +183,12 @@ textArea.addEventListener("input", () => { "data", textArea.innerText ); + + if(OpenedFiles.READ(OpenedFiles.FINDQUICKINDEX("fileLink", currentFile), "savedFile") !== textArea.innerText) { + document.getElementById(getFileDivIdFromLink(currentFile) + "-lbl").classList.add("unsavedFile"); + } else { + document.getElementById(getFileDivIdFromLink(currentFile) + "-lbl").classList.remove("unsavedFile"); + } textArea.innerHTML = highlighter(textArea.innerText, currentFile); // Restore cursor position @@ -231,6 +240,16 @@ saveButton.addEventListener("click", () => { "data" ) ); + OpenedFiles.SET( + OpenedFiles.FINDQUICKINDEX("fileLink", currentFile), + "savedFile", + OpenedFiles.READ( + OpenedFiles.FINDQUICKINDEX("fileLink", currentFile), + "data" + ) + ); + + document.getElementById(getFileDivIdFromLink(currentFile) + "-lbl").classList.remove("unsavedFile"); }); textArea.addEventListener("focusout", () => { From b077bb4facc7d3c1eaca83557c2ab2a47af9e2b1 Mon Sep 17 00:00:00 2001 From: Ethan Mahlstedt Date: Mon, 31 Mar 2025 21:05:12 -0700 Subject: [PATCH 020/126] Remove TODO --- TODOs | 1 - 1 file changed, 1 deletion(-) diff --git a/TODOs b/TODOs index 4c9990c..9dda2ee 100644 --- a/TODOs +++ b/TODOs @@ -2,7 +2,6 @@ Create README Add Keyboard Shortcuts Fix link editor window size -Mark unsaved file Branding (Icons, Coloring, and maybe a rename) = for Version 1.1 = From 5540866ad0d6759613a591a6b81f4eb51218b239 Mon Sep 17 00:00:00 2001 From: Ethan Mahlstedt <76834762+ImSpeddy@users.noreply.github.com> Date: Mon, 31 Mar 2025 21:11:40 -0700 Subject: [PATCH 021/126] Update TODOs --- TODOs | 1 + 1 file changed, 1 insertion(+) diff --git a/TODOs b/TODOs index 9dda2ee..cf4b162 100644 --- a/TODOs +++ b/TODOs @@ -2,6 +2,7 @@ Create README Add Keyboard Shortcuts Fix link editor window size +Add Github Actions Branding (Icons, Coloring, and maybe a rename) = for Version 1.1 = From 3dc3cfeb162e28a993f835f81e72ba7fd4cb31fb Mon Sep 17 00:00:00 2001 From: Ethan Mahlstedt Date: Wed, 2 Apr 2025 12:19:17 -0700 Subject: [PATCH 022/126] Add Keyboard Shortcuts --- TODOs | 5 +++++ front/editor/editor.js | 42 +++++++++++++++++++++++++++++++++--------- 2 files changed, 38 insertions(+), 9 deletions(-) diff --git a/TODOs b/TODOs index cf4b162..a27e0d4 100644 --- a/TODOs +++ b/TODOs @@ -1,9 +1,14 @@ = for VERSION 1.0 = Create README Add Keyboard Shortcuts +<<<<<<< Updated upstream Fix link editor window size Add Github Actions +======= +Fix link editor window size (or turn it into a HTML dialog) +>>>>>>> Stashed changes Branding (Icons, Coloring, and maybe a rename) +Add New File Button to the editor = for Version 1.1 = Add Dynamic Skins diff --git a/front/editor/editor.js b/front/editor/editor.js index a701955..cc04591 100644 --- a/front/editor/editor.js +++ b/front/editor/editor.js @@ -203,15 +203,32 @@ textArea.addEventListener("keydown", (event) => { } if (event.key === "Tab") { event.preventDefault(); - const caretOffset = getCaretPosition(); - const indent = "\t"; document.execCommand("insertText", false, indent); - setCaretPosition(caretOffset + indent.length); } + + if(event.ctrlKey){ + if(event.key === "S"){ + event.preventDefault() + saveFile(); + }else if(event.key === "N"){ + event.preventDefault() + // TODO: Handle new file + }else if(event.key === "R"){ + event.preventDefault() + refreshEditor(); + }else if(event.key === "O"){ + event.preventDefault() + openNewFile(); + } + } + + if(event.altKey){ + // TODO: Handle tab change using Alt+Number + } }); ipcRenderer.on("open-editor", (event, file) => { @@ -231,7 +248,7 @@ ipcRenderer.on("open-editor", (event, file) => { const saveButton = document.getElementById("SaveBtn"); -saveButton.addEventListener("click", () => { +function saveFile(){ ipcRenderer.send( "save-file", currentFile, @@ -250,7 +267,9 @@ saveButton.addEventListener("click", () => { ); document.getElementById(getFileDivIdFromLink(currentFile) + "-lbl").classList.remove("unsavedFile"); -}); +} + +saveButton.addEventListener("click", saveFile); textArea.addEventListener("focusout", () => { if (currentFile !== null) { @@ -338,15 +357,17 @@ function loadFileIntoEditor(file) { } } -document.getElementById("openFile").addEventListener("click", () => { +function openNewFile(){ ipcRenderer.invoke("filePickerDialog").then((data) => { openFile(data, () => { loadFileIntoEditor(data); }); }); -}); +} + +document.getElementById("openFile").addEventListener("click", openNewFile); -document.getElementById("RefreshEditor").addEventListener("click", () => { +function refreshEditor(){ if ( OpenedFiles.READ( OpenedFiles.FINDQUICKINDEX("fileLink", currentFile), @@ -366,7 +387,10 @@ document.getElementById("RefreshEditor").addEventListener("click", () => { ) ); } -}); + +} + +document.getElementById("RefreshEditor").addEventListener("click", refreshEditor); ipcRenderer.on("syncLinkedDisplay", (event, fileID, display) => { OpenedFiles.SET(fileID, "linkedDisplay", display); From 1ac93fcea1a3feec0bf718739df38794f7bfa99c Mon Sep 17 00:00:00 2001 From: Ethan Mahlstedt <76834762+ImSpeddy@users.noreply.github.com> Date: Wed, 2 Apr 2025 12:20:52 -0700 Subject: [PATCH 023/126] Update TODOs --- TODOs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/TODOs b/TODOs index a27e0d4..ceedb38 100644 --- a/TODOs +++ b/TODOs @@ -1,12 +1,8 @@ = for VERSION 1.0 = Create README Add Keyboard Shortcuts -<<<<<<< Updated upstream -Fix link editor window size Add Github Actions -======= Fix link editor window size (or turn it into a HTML dialog) ->>>>>>> Stashed changes Branding (Icons, Coloring, and maybe a rename) Add New File Button to the editor From 370912d17010198608bc00fcf7d006f4a2f6c87c Mon Sep 17 00:00:00 2001 From: Ethan Mahlstedt Date: Fri, 4 Apr 2025 09:56:13 -0700 Subject: [PATCH 024/126] Fix key combinations --- front/editor/editor.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/front/editor/editor.js b/front/editor/editor.js index cc04591..1f574fd 100644 --- a/front/editor/editor.js +++ b/front/editor/editor.js @@ -211,16 +211,16 @@ textArea.addEventListener("keydown", (event) => { } if(event.ctrlKey){ - if(event.key === "S"){ + if(event.key === "s"){ event.preventDefault() saveFile(); - }else if(event.key === "N"){ + }else if(event.key === "n"){ event.preventDefault() // TODO: Handle new file - }else if(event.key === "R"){ + }else if(event.key === "r"){ event.preventDefault() refreshEditor(); - }else if(event.key === "O"){ + }else if(event.key === "o"){ event.preventDefault() openNewFile(); } From eaa480e6db628d15510d6b085472176d192067ba Mon Sep 17 00:00:00 2001 From: Ethan Mahlstedt Date: Fri, 4 Apr 2025 09:56:58 -0700 Subject: [PATCH 025/126] Fix TODOs Conflicts --- TODOs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/TODOs b/TODOs index ceedb38..4b14afe 100644 --- a/TODOs +++ b/TODOs @@ -3,8 +3,10 @@ Create README Add Keyboard Shortcuts Add Github Actions Fix link editor window size (or turn it into a HTML dialog) +Turn the new file window to an HTML Dialog Branding (Icons, Coloring, and maybe a rename) Add New File Button to the editor = for Version 1.1 = Add Dynamic Skins +Fully integrate main window onto editor From 788671e7d78038f2335377a909d67302be92d188 Mon Sep 17 00:00:00 2001 From: Ethan Mahlstedt Date: Fri, 4 Apr 2025 09:59:05 -0700 Subject: [PATCH 026/126] Handle file closing shortcut --- front/editor/editor.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/front/editor/editor.js b/front/editor/editor.js index 1f574fd..d8b3c58 100644 --- a/front/editor/editor.js +++ b/front/editor/editor.js @@ -223,6 +223,9 @@ textArea.addEventListener("keydown", (event) => { }else if(event.key === "o"){ event.preventDefault() openNewFile(); + }else if(event.key === "q"){ + event.preventDefault() + closeFile(currentFile); } } From f19c4ae9d54f05a9f6b7bbe0e37b98523f684cd4 Mon Sep 17 00:00:00 2001 From: Ethan Mahlstedt Date: Fri, 4 Apr 2025 10:01:57 -0700 Subject: [PATCH 027/126] Update TODOs --- TODOs | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/TODOs b/TODOs index 4b14afe..bdd68d3 100644 --- a/TODOs +++ b/TODOs @@ -1,12 +1,18 @@ = for VERSION 1.0 = -Create README -Add Keyboard Shortcuts -Add Github Actions -Fix link editor window size (or turn it into a HTML dialog) -Turn the new file window to an HTML Dialog -Branding (Icons, Coloring, and maybe a rename) -Add New File Button to the editor + Branding + Rename + Icons + New Coloring + Dynamic Skins + Create README -= for Version 1.1 = -Add Dynamic Skins -Fully integrate main window onto editor + Add Keyboard Shortcuts + Change tabs using alt + + Add Github Actions + + Fully integrate main window onto editor + Add New File Button to the editor + HTML Dialogs + Fix link editor window size (or turn it into a HTML dialog) + Turn the new file window to an HTML Dialog \ No newline at end of file From de8ef909a349224db35c4b9096f22d8fa13efb61 Mon Sep 17 00:00:00 2001 From: Ethan Mahlstedt Date: Mon, 7 Apr 2025 13:37:38 -0700 Subject: [PATCH 028/126] Alt Change Tabs --- TODOs | 4 +--- front/editor/editor.js | 22 ++++++++++++++++++++-- front/newFileDialog/newFileDialog.html | 2 +- 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/TODOs b/TODOs index bdd68d3..56758c8 100644 --- a/TODOs +++ b/TODOs @@ -5,14 +5,12 @@ New Coloring Dynamic Skins Create README - - Add Keyboard Shortcuts - Change tabs using alt Add Github Actions Fully integrate main window onto editor Add New File Button to the editor + Add Open Window from the editor HTML Dialogs Fix link editor window size (or turn it into a HTML dialog) Turn the new file window to an HTML Dialog \ No newline at end of file diff --git a/front/editor/editor.js b/front/editor/editor.js index d8b3c58..325bd0e 100644 --- a/front/editor/editor.js +++ b/front/editor/editor.js @@ -174,6 +174,7 @@ textArea.addEventListener("scroll", () => { }); textArea.addEventListener("input", () => { + updateLineNumbers(); const scrollPosition = textArea.scrollTop; // Preserve scroll position const caretOffset = getCaretPosition(); @@ -199,7 +200,7 @@ textArea.addEventListener("input", () => { textArea.addEventListener("keydown", (event) => { if (event.key === "Enter") { event.preventDefault(); - document.execCommand("insertLineBreak"); // Insert
+ document.execCommand("insertLineBreak"); } if (event.key === "Tab") { event.preventDefault(); @@ -230,7 +231,24 @@ textArea.addEventListener("keydown", (event) => { } if(event.altKey){ - // TODO: Handle tab change using Alt+Number + console.log(event.key) + const num = Number(event.key); + if(!isNaN(num)){ + event.preventDefault(); + + switch (num) { + case 0: + if(OpenedFiles.GETJSONDATA()[9]){ + loadFileIntoEditor(OpenedFiles.GETJSONDATA()[9].fileLink) + } + break; + default: + if(OpenedFiles.GETJSONDATA()[num-1]){ + loadFileIntoEditor(OpenedFiles.GETJSONDATA()[num-1].fileLink) + } + break; + } + } } }); diff --git a/front/newFileDialog/newFileDialog.html b/front/newFileDialog/newFileDialog.html index 4375767..fda0e52 100644 --- a/front/newFileDialog/newFileDialog.html +++ b/front/newFileDialog/newFileDialog.html @@ -10,7 +10,7 @@
- +
From 30490eb90237d9ce49eafad2b17b3ee5e9337f8a Mon Sep 17 00:00:00 2001 From: Ethan Mahlstedt Date: Mon, 7 Apr 2025 14:15:44 -0700 Subject: [PATCH 029/126] Create Buttons --- front/editor/editor.css | 5 +++++ front/editor/editor.html | 11 ++++++++++- main.js | 6 ++++-- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/front/editor/editor.css b/front/editor/editor.css index f2c8ac8..4f43520 100644 --- a/front/editor/editor.css +++ b/front/editor/editor.css @@ -162,4 +162,9 @@ button:hover { .unsavedFile { font-style: italic; +} + +.verticalLine { + border-left: 1px solid rgb(192, 192, 192); + height: 80%; } \ No newline at end of file diff --git a/front/editor/editor.html b/front/editor/editor.html index 27040bd..47f1347 100644 --- a/front/editor/editor.html +++ b/front/editor/editor.html @@ -10,8 +10,11 @@
+ +
+
@@ -24,12 +27,18 @@ >

 		
-

File is not saved

+ + + + + + + diff --git a/main.js b/main.js index 7fce3d0..8223284 100644 --- a/main.js +++ b/main.js @@ -101,8 +101,10 @@ ipcMain.on("new-editor", async () => { }); if (!result.canceled && result.filePaths && result.filePaths[0]) { let editWindow = launchWindow("./front/editor/editor.html", { - width: 500, - height: 500, + width: 600, + height: 600, + minWidth: 600, + minHeight: 400, webPreferences: { nodeIntegration: true, contextIsolation: false } }); editWindow.webContents.send("open-editor", result.filePaths[0]); From 3946804283dbd23a69f27e68dc9b05c7a40b9307 Mon Sep 17 00:00:00 2001 From: Ethan Mahlstedt Date: Wed, 9 Apr 2025 09:49:15 -0700 Subject: [PATCH 030/126] Prevent closing window upon file closing --- front/editor/editor.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/front/editor/editor.js b/front/editor/editor.js index 325bd0e..322fed5 100644 --- a/front/editor/editor.js +++ b/front/editor/editor.js @@ -114,7 +114,9 @@ async function closeFile(file) { dialog.close(); if (OpenedFiles.GETJSONDATA().length === 0) { - ipcRenderer.send("closeWindow"); + return; + // TODO: Show a "Not opened file text indicator and hide the text area" + } else { if (currentFile === file) { const nextFile = OpenedFiles.GETJSONDATA()[0].fileLink; @@ -135,7 +137,8 @@ async function closeFile(file) { dialog.close(); if (OpenedFiles.GETJSONDATA().length === 0) { - ipcRenderer.send("closeWindow"); + return; + // TODO: Show a "Not opened file text indicator and hide the text area" } else { if (currentFile === file) { const nextFile = OpenedFiles.GETJSONDATA()[0].fileLink; @@ -150,7 +153,8 @@ async function closeFile(file) { div.remove(); if (OpenedFiles.GETJSONDATA().length === 0) { - ipcRenderer.send("closeWindow"); + return; + // TODO: Show a "Not opened file text indicator and hide the text area" } else { if (currentFile === file) { const nextFile = OpenedFiles.GETJSONDATA()[0].fileLink; From a85c82bc0cfba57f1b6be5364f4e26e19d953aa3 Mon Sep 17 00:00:00 2001 From: Ethan Mahlstedt Date: Wed, 9 Apr 2025 17:30:51 -0600 Subject: [PATCH 031/126] Hide field upon closing all tabs --- front/editor/editor.js | 36 ++++++++++++++++++++++++++++++++--- front/editor/modules/caret.js | 1 - 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/front/editor/editor.js b/front/editor/editor.js index 322fed5..37173b1 100644 --- a/front/editor/editor.js +++ b/front/editor/editor.js @@ -8,6 +8,8 @@ const { } = require("./modules/fileStringFunctions"); const highlighter = require("./highlight"); +var fieldShown = false; + // Setup needle table // Import Library const needle = require("needle-db"); @@ -84,9 +86,11 @@ function openFile(file, callback) { } else { alert("File already opened"); } + checkField(); } async function closeFile(file) { + if (OpenedFiles.GETJSONDATA().length === 0) return; let savedData; await ipcRenderer.invoke("get-file-data", file).then((response) => { savedData = response; @@ -114,6 +118,7 @@ async function closeFile(file) { dialog.close(); if (OpenedFiles.GETJSONDATA().length === 0) { + unloadFiles(); return; // TODO: Show a "Not opened file text indicator and hide the text area" @@ -137,6 +142,7 @@ async function closeFile(file) { dialog.close(); if (OpenedFiles.GETJSONDATA().length === 0) { + unloadFiles(); return; // TODO: Show a "Not opened file text indicator and hide the text area" } else { @@ -153,6 +159,7 @@ async function closeFile(file) { div.remove(); if (OpenedFiles.GETJSONDATA().length === 0) { + unloadFiles(); return; // TODO: Show a "Not opened file text indicator and hide the text area" } else { @@ -162,6 +169,7 @@ async function closeFile(file) { } } } + checkField(); } function updateLineNumbers() { @@ -268,12 +276,14 @@ ipcRenderer.on("open-editor", (event, file) => { loadFileIntoEditor(file); }); + checkField(); }); }); const saveButton = document.getElementById("SaveBtn"); function saveFile(){ + if(currentFile === null) return; ipcRenderer.send( "save-file", currentFile, @@ -380,19 +390,23 @@ function loadFileIntoEditor(file) { document.title = `${getFileNameFromLink(file)} - HTMLEditor`; } + checkField(); } function openNewFile(){ ipcRenderer.invoke("filePickerDialog").then((data) => { - openFile(data, () => { - loadFileIntoEditor(data); - }); + if(data){ + openFile(data, () => { + loadFileIntoEditor(data); + }); + } }); } document.getElementById("openFile").addEventListener("click", openNewFile); function refreshEditor(){ + if(currentFile === null) return; if ( OpenedFiles.READ( OpenedFiles.FINDQUICKINDEX("fileLink", currentFile), @@ -452,3 +466,19 @@ window.addEventListener("blur", () => { ); } }); + +function checkField() { + fieldShown = (OpenedFiles.GETJSONDATA().length > 0) ? true : false; + if (fieldShown) { + document.getElementById("TextAreaContainer").style.display = "flex"; + } else { + document.getElementById("TextAreaContainer").style.display = "none"; + } +} + +function unloadFiles(){ + currentFile = null; + textArea.innerText = ""; + updateLineNumbers(); + checkField(); +} \ No newline at end of file diff --git a/front/editor/modules/caret.js b/front/editor/modules/caret.js index b85dd26..6016429 100644 --- a/front/editor/modules/caret.js +++ b/front/editor/modules/caret.js @@ -8,7 +8,6 @@ module.exports.getCaretPosition = () => { const range = selection.getRangeAt(0); if (!textArea.contains(range.startContainer)) { - console.warn("Selection is outside the textArea or invalid"); return null; } From 012f74900a23d6cc033b577688c9e42221347885 Mon Sep 17 00:00:00 2001 From: Ethan Mahlstedt Date: Thu, 10 Apr 2025 09:04:12 -0600 Subject: [PATCH 032/126] Hide text area upon no files opened --- front/editor/editor.css | 35 +++++++++++++++++++++++++++++++++++ front/editor/editor.html | 8 +++++++- front/editor/editor.js | 5 +++++ 3 files changed, 47 insertions(+), 1 deletion(-) diff --git a/front/editor/editor.css b/front/editor/editor.css index 4f43520..bd40fb6 100644 --- a/front/editor/editor.css +++ b/front/editor/editor.css @@ -24,6 +24,15 @@ body { #FilePicker { overflow-y: hidden; overflow-x: auto; + height: 56px; + min-height: 56px; + max-height: 56px; +} + +#Controls { + height: 48px; + min-height: 48px; + max-height: 48px; } .fileDiv { @@ -167,4 +176,30 @@ button:hover { .verticalLine { border-left: 1px solid rgb(192, 192, 192); height: 80%; +} + +h1, h2 { + color: white; + font-family: 'Arial'; +} + +h1 { + font-weight: bold; +} + +h2 { + font-weight: lighter; +} + +#noOpenedFileContainer { + display: flex; + justify-content: center; + align-items: center; + height: 100%; + width: 100%; +} + +#noOpenedFileDialog{ + text-align: center; + padding: 5px; } \ No newline at end of file diff --git a/front/editor/editor.html b/front/editor/editor.html index 47f1347..0a07124 100644 --- a/front/editor/editor.html +++ b/front/editor/editor.html @@ -12,11 +12,17 @@
- +
+
+
+

No opened file...

+

Open one using the "Open" button

+
+
{ function checkField() { fieldShown = (OpenedFiles.GETJSONDATA().length > 0) ? true : false; if (fieldShown) { + document.getElementById("noOpenedFileContainer").style.display = "none"; + document.getElementById("noOpenedFileDialog").style.display = "none"; document.getElementById("TextAreaContainer").style.display = "flex"; } else { + document.getElementById("noOpenedFileContainer").style.display = "flex"; + document.getElementById("noOpenedFileDialog").style.display = "block"; document.getElementById("TextAreaContainer").style.display = "none"; } } function unloadFiles(){ + document.title = `HTMLEditor`; currentFile = null; textArea.innerText = ""; updateLineNumbers(); From b71a3eae5efe49844a978c49206b3ef77ddc45b6 Mon Sep 17 00:00:00 2001 From: Ethan Mahlstedt Date: Thu, 10 Apr 2025 11:14:30 -0600 Subject: [PATCH 033/126] Integrate NewFileDialog to Editor - Integrate NewFileDialog to Editor - Lint & Prettier --- TODOs | 11 +- front/editor/editor.css | 95 ++++++++++++++- front/editor/editor.html | 39 +++++- front/editor/editor.js | 157 +++++++++++++++++++------ front/index/index.html | 3 - front/newFileDialog/newFileDialog.css | 83 ------------- front/newFileDialog/newFileDialog.html | 34 ------ front/newFileDialog/newFileDialog.js | 51 -------- 8 files changed, 255 insertions(+), 218 deletions(-) delete mode 100644 front/newFileDialog/newFileDialog.css delete mode 100644 front/newFileDialog/newFileDialog.html delete mode 100644 front/newFileDialog/newFileDialog.js diff --git a/TODOs b/TODOs index 56758c8..f4536a7 100644 --- a/TODOs +++ b/TODOs @@ -9,8 +9,13 @@ Add Github Actions Fully integrate main window onto editor - Add New File Button to the editor - Add Open Window from the editor HTML Dialogs Fix link editor window size (or turn it into a HTML dialog) - Turn the new file window to an HTML Dialog \ No newline at end of file + Turn the new file window to an HTML Dialog + + Save last state of the editor upon close + +BUGS: + Editor window remains open upon closing the window + HTML files becoming single lined + \ No newline at end of file diff --git a/front/editor/editor.css b/front/editor/editor.css index bd40fb6..5a5dd7d 100644 --- a/front/editor/editor.css +++ b/front/editor/editor.css @@ -178,9 +178,10 @@ button:hover { height: 80%; } -h1, h2 { +h1, +h2 { color: white; - font-family: 'Arial'; + font-family: "Arial"; } h1 { @@ -199,7 +200,93 @@ h2 { width: 100%; } -#noOpenedFileDialog{ +#noOpenedFileDialog { text-align: center; padding: 5px; -} \ No newline at end of file +} + +/* New file dialog */ + +#newFileDialog { + background-color: rgb(48, 48, 48); + border-radius: 5px; + padding: 1%; + gap: 10px; +} + +label { + color: white; + font-family: "Arial"; + font-weight: bold; + vertical-align: middle; +} + +textarea { + position: relative; + resize: none; + vertical-align: middle; + border: 1px solid black; + font-size: 16px; + height: 20px; + font-family: Arial; + width: calc(100% - 2%); + margin: 0.5% auto; + overflow: hidden; +} + +.containerDiv { + background-color: rgb(64, 64, 64); + border-radius: 5px; + padding: 1%; + display: flex; + flex-direction: row; + box-sizing: border-box; + gap: 10px; + align-items: center; +} + +.mainContainerDiv { + background-color: rgb(48, 48, 48); + padding: 1%; + border-radius: 5px; + gap: 10px; + display: flex; + flex-direction: column; + height: 100%; +} + +#fileDirLbl { + font-weight: normal; + font-size: 12; + text-wrap: wrap; + overflow-wrap: anywhere; +} + +button { + background-color: gray; + font-family: Arial; + color: black; + padding: 5px 10px; + border-radius: 5px; + border: 2px ridge black; + font-size: 16px; + font-weight: bold; + cursor: pointer; + transition: + background-color 0.3s ease, + color 0.3s ease; +} + +button:hover { + background-color: rgb(64, 64, 64); + color: white; +} + +#createFileBtnDiv { + display: flex; + align-items: center; + justify-content: center; + align-self: flex-end; + justify-self: center; + width: 100%; +} diff --git a/front/editor/editor.html b/front/editor/editor.html index 0a07124..a9426df 100644 --- a/front/editor/editor.html +++ b/front/editor/editor.html @@ -20,7 +20,10 @@

No opened file...

-

Open one using the "Open" button

+

+ Open one using the "Open" button or create a new one using the "New + File" button +

@@ -40,11 +43,37 @@

Open one using the "Open" button

- - - - +
+
+ + +
+
+ + +
+
+ +
+
+ + +
+
+ + +
+
+ diff --git a/front/editor/editor.js b/front/editor/editor.js index 49499d9..3173554 100644 --- a/front/editor/editor.js +++ b/front/editor/editor.js @@ -24,7 +24,7 @@ OpenedFiles.NEWCOLUMN("data"); OpenedFiles.NEWCOLUMN("fileDivId"); OpenedFiles.NEWCOLUMN("savedScroll"); OpenedFiles.NEWCOLUMN("savedCursor"); -OpenedFiles.NEWCOLUMN("savedFile") +OpenedFiles.NEWCOLUMN("savedFile"); const { getCaretPosition, setCaretPosition } = require("./modules/caret"); @@ -121,7 +121,6 @@ async function closeFile(file) { unloadFiles(); return; // TODO: Show a "Not opened file text indicator and hide the text area" - } else { if (currentFile === file) { const nextFile = OpenedFiles.GETJSONDATA()[0].fileLink; @@ -197,10 +196,19 @@ textArea.addEventListener("input", () => { textArea.innerText ); - if(OpenedFiles.READ(OpenedFiles.FINDQUICKINDEX("fileLink", currentFile), "savedFile") !== textArea.innerText) { - document.getElementById(getFileDivIdFromLink(currentFile) + "-lbl").classList.add("unsavedFile"); + if ( + OpenedFiles.READ( + OpenedFiles.FINDQUICKINDEX("fileLink", currentFile), + "savedFile" + ) !== textArea.innerText + ) { + document + .getElementById(getFileDivIdFromLink(currentFile) + "-lbl") + .classList.add("unsavedFile"); } else { - document.getElementById(getFileDivIdFromLink(currentFile) + "-lbl").classList.remove("unsavedFile"); + document + .getElementById(getFileDivIdFromLink(currentFile) + "-lbl") + .classList.remove("unsavedFile"); } textArea.innerHTML = highlighter(textArea.innerText, currentFile); @@ -223,40 +231,39 @@ textArea.addEventListener("keydown", (event) => { setCaretPosition(caretOffset + indent.length); } - if(event.ctrlKey){ - if(event.key === "s"){ - event.preventDefault() + if (event.ctrlKey) { + if (event.key === "s") { + event.preventDefault(); saveFile(); - }else if(event.key === "n"){ - event.preventDefault() + } else if (event.key === "n") { + event.preventDefault(); // TODO: Handle new file - }else if(event.key === "r"){ - event.preventDefault() + } else if (event.key === "r") { + event.preventDefault(); refreshEditor(); - }else if(event.key === "o"){ - event.preventDefault() + } else if (event.key === "o") { + event.preventDefault(); openNewFile(); - }else if(event.key === "q"){ - event.preventDefault() + } else if (event.key === "q") { + event.preventDefault(); closeFile(currentFile); } } - if(event.altKey){ - console.log(event.key) + if (event.altKey) { const num = Number(event.key); - if(!isNaN(num)){ + if (!isNaN(num)) { event.preventDefault(); switch (num) { case 0: - if(OpenedFiles.GETJSONDATA()[9]){ - loadFileIntoEditor(OpenedFiles.GETJSONDATA()[9].fileLink) + if (OpenedFiles.GETJSONDATA()[9]) { + loadFileIntoEditor(OpenedFiles.GETJSONDATA()[9].fileLink); } break; default: - if(OpenedFiles.GETJSONDATA()[num-1]){ - loadFileIntoEditor(OpenedFiles.GETJSONDATA()[num-1].fileLink) + if (OpenedFiles.GETJSONDATA()[num - 1]) { + loadFileIntoEditor(OpenedFiles.GETJSONDATA()[num - 1].fileLink); } break; } @@ -282,8 +289,8 @@ ipcRenderer.on("open-editor", (event, file) => { const saveButton = document.getElementById("SaveBtn"); -function saveFile(){ - if(currentFile === null) return; +function saveFile() { + if (currentFile === null) return; ipcRenderer.send( "save-file", currentFile, @@ -301,7 +308,9 @@ function saveFile(){ ) ); - document.getElementById(getFileDivIdFromLink(currentFile) + "-lbl").classList.remove("unsavedFile"); + document + .getElementById(getFileDivIdFromLink(currentFile) + "-lbl") + .classList.remove("unsavedFile"); } saveButton.addEventListener("click", saveFile); @@ -393,9 +402,9 @@ function loadFileIntoEditor(file) { checkField(); } -function openNewFile(){ +function openNewFile() { ipcRenderer.invoke("filePickerDialog").then((data) => { - if(data){ + if (data) { openFile(data, () => { loadFileIntoEditor(data); }); @@ -405,8 +414,8 @@ function openNewFile(){ document.getElementById("openFile").addEventListener("click", openNewFile); -function refreshEditor(){ - if(currentFile === null) return; +function refreshEditor() { + if (currentFile === null) return; if ( OpenedFiles.READ( OpenedFiles.FINDQUICKINDEX("fileLink", currentFile), @@ -426,10 +435,11 @@ function refreshEditor(){ ) ); } - } -document.getElementById("RefreshEditor").addEventListener("click", refreshEditor); +document + .getElementById("RefreshEditor") + .addEventListener("click", refreshEditor); ipcRenderer.on("syncLinkedDisplay", (event, fileID, display) => { OpenedFiles.SET(fileID, "linkedDisplay", display); @@ -468,7 +478,7 @@ window.addEventListener("blur", () => { }); function checkField() { - fieldShown = (OpenedFiles.GETJSONDATA().length > 0) ? true : false; + fieldShown = OpenedFiles.GETJSONDATA().length > 0 ? true : false; if (fieldShown) { document.getElementById("noOpenedFileContainer").style.display = "none"; document.getElementById("noOpenedFileDialog").style.display = "none"; @@ -480,10 +490,87 @@ function checkField() { } } -function unloadFiles(){ +function unloadFiles() { document.title = `HTMLEditor`; currentFile = null; textArea.innerText = ""; updateLineNumbers(); checkField(); -} \ No newline at end of file +} + +document.getElementById("newFileBtn").addEventListener("click", () => { + const dialog = document.getElementById("newFileDialog"); + if (dialog.open) { + dialog.close(); + } else { + dialog.showModal(); + } +}); + +// New File Dialog + +const dirBtn = document.getElementById("PickFolderBtn"); +let dir = null; + +dirBtn.addEventListener("click", () => { + ipcRenderer.invoke("get-dir").then((response) => { + if (response.status == 0) { + document.getElementById("fileDirLbl").innerHTML = response.dir; + dir = response.dir; + } + }); +}); + +document.addEventListener("DOMContentLoaded", () => { + const list = document.getElementById("presetPicker"); + ipcRenderer.invoke("get-preset-list").then((data) => { + data.forEach((element) => { + const option = document.createElement("option"); + option.value = `${element.parentPath}\\${element.name}`; + option.innerHTML = element.name; + + list.appendChild(option); + }); + }); +}); + +document + .getElementById("cancelFileCreationBtn") + .addEventListener("click", () => { + const dialog = document.getElementById("newFileDialog"); + dialog.close(); + document.getElementById("filenameField").value = ""; + dir = null; + document.getElementById("fileDirLbl").innerHTML = "No folder selected"; + document.getElementById("presetPicker").value = "none"; + document.getElementById("newFileDialog").close(); + }); + +const createBtn = document.getElementById("createFileBtn"); + +createBtn.addEventListener("click", () => { + const args = { + name: document.getElementById("filenameField").value, + dir: dir, + preset: document.getElementById("presetPicker").value + }; + + if (args.dir == null || args.name == null || args.preset == null) { + alert("Argument missing."); + } else { + ipcRenderer.invoke("createFile", args).then((response) => { + if (response == 0) { + openFile(`${args.dir}\\${args.name}`, () => { + loadFileIntoEditor(`${args.dir}\\${args.name}`); + }); + document.getElementById("filenameField").value = ""; + dir = null; + document.getElementById("fileDirLbl").innerHTML = "No folder selected"; + document.getElementById("presetPicker").value = "none"; + document.getElementById("newFileDialog").close(); + } else { + alert("Error in file creation"); + } + }); + } +}); diff --git a/front/index/index.html b/front/index/index.html index 332c7bd..87ab49d 100644 --- a/front/index/index.html +++ b/front/index/index.html @@ -8,9 +8,6 @@

HTML Editor

- -
-


diff --git a/front/newFileDialog/newFileDialog.css b/front/newFileDialog/newFileDialog.css deleted file mode 100644 index 6cab501..0000000 --- a/front/newFileDialog/newFileDialog.css +++ /dev/null @@ -1,83 +0,0 @@ -html, -body { - background-color: rgb(32, 32, 32); -} - -label { - color: white; - font-family: "Arial"; - font-weight: bold; - vertical-align: middle; -} - -textarea { - position: relative; - resize: none; - vertical-align: middle; - border: 2px solid black; - font-size: 16px; - height: 20px; - font-family: Arial; - width: calc(100% - 2%); - margin: 0.5% auto; - overflow: hidden; -} - -.containerDiv { - background-color: rgb(64, 64, 64); - border-radius: 5px; - padding: 1%; - display: flex; - flex-direction: row; - box-sizing: border-box; - gap: 10px; - align-items: center; -} - -.mainContainerDiv { - background-color: rgb(48, 48, 48); - padding: 1%; - border-radius: 5px; - gap: 10px; - display: flex; - flex-direction: column; - height: 92vh; -} - -#fileDirLbl { - font-weight: normal; - font-size: 12; - text-wrap: wrap; - overflow-wrap: anywhere; -} - -button { - background-color: gray; - font-family: Arial; - color: black; - padding: 5px 10px; - border-radius: 5px; - border: 2px ridge black; - font-size: 16px; - font-weight: bold; - cursor: pointer; - transition: - background-color 0.3s ease, - color 0.3s ease; -} - -button:hover { - background-color: rgb(64, 64, 64); - color: white; -} - -#createFileBtnDiv { - display: flex; - align-items: center; - justify-content: center; - align-self: flex-end; - width: 94%; - position: absolute; - bottom: 20px; - left: 10px; -} diff --git a/front/newFileDialog/newFileDialog.html b/front/newFileDialog/newFileDialog.html deleted file mode 100644 index fda0e52..0000000 --- a/front/newFileDialog/newFileDialog.html +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - New File - - - -
-
- - -
-
- - -
-
- -
-
- - -
-
- -
-
- - - diff --git a/front/newFileDialog/newFileDialog.js b/front/newFileDialog/newFileDialog.js deleted file mode 100644 index 391feab..0000000 --- a/front/newFileDialog/newFileDialog.js +++ /dev/null @@ -1,51 +0,0 @@ -const { ipcRenderer } = require("electron"); - -const dirBtn = document.getElementById("PickFolderBtn"); -let dir = null; - -dirBtn.addEventListener("click", () => { - ipcRenderer.invoke("get-dir").then((response) => { - if (response.status == 0) { - document.getElementById("fileDirLbl").innerHTML = response.dir; - dir = response.dir; - } - }); -}); - -document.addEventListener("DOMContentLoaded", () => { - const list = document.getElementById("presetPicker"); - ipcRenderer.invoke("get-preset-list").then((data) => { - data.forEach((element) => { - const option = document.createElement("option"); - option.value = `${element.parentPath}\\${element.name}`; - option.innerHTML = element.name; - - list.appendChild(option); - }); - }); -}); - -const createBtn = document.getElementById("createFileBtnDiv"); - -createBtn.addEventListener("click", () => { - const args = { - name: document.getElementById("filenameField").value, - dir: dir, - preset: document.getElementById("presetPicker").value - }; - - if (args.dir == null || args.name == null || args.preset == null) { - alert("Argument missing."); - console.log("Error in file creation, null argument"); - } else { - ipcRenderer.invoke("createFile", args).then((response) => { - if (response == 0) { - alert("File created successfully"); - ipcRenderer.send("closeWindow"); - } else { - alert("Error in file creation"); - console.log(response); - } - }); - } -}); From 536315f63f093670157cc28ccd65132d106b141b Mon Sep 17 00:00:00 2001 From: Ethan Mahlstedt Date: Thu, 10 Apr 2025 15:40:57 -0600 Subject: [PATCH 034/126] Open a viewer from the editor --- TODOs | 5 +++-- front/editor/editor.js | 29 +++++++++++++++++++++++++++ main.js | 45 +++++++++++++++++++++++++++++++----------- 3 files changed, 65 insertions(+), 14 deletions(-) diff --git a/TODOs b/TODOs index f4536a7..0f87dd7 100644 --- a/TODOs +++ b/TODOs @@ -11,11 +11,12 @@ Fully integrate main window onto editor HTML Dialogs Fix link editor window size (or turn it into a HTML dialog) - Turn the new file window to an HTML Dialog Save last state of the editor upon close + Backside event handler + BUGS: Editor window remains open upon closing the window HTML files becoming single lined - \ No newline at end of file + Blank lines counted as double \ No newline at end of file diff --git a/front/editor/editor.js b/front/editor/editor.js index 3173554..0065aa2 100644 --- a/front/editor/editor.js +++ b/front/editor/editor.js @@ -247,6 +247,9 @@ textArea.addEventListener("keydown", (event) => { } else if (event.key === "q") { event.preventDefault(); closeFile(currentFile); + }else if(event.key === "w"){ + event.preventDefault(); + // TODO: Open new window / Open current window with Shift } } @@ -271,6 +274,10 @@ textArea.addEventListener("keydown", (event) => { } }); +document.addEventListener("DOMContentLoaded", () => { + checkField(); +}) + ipcRenderer.on("open-editor", (event, file) => { document.addEventListener("DOMContentLoaded", () => { openFile(file, () => { @@ -507,7 +514,9 @@ document.getElementById("newFileBtn").addEventListener("click", () => { } }); +////////////////////////////////////////////////////////// // New File Dialog +////////////////////////////////////////////////////////// const dirBtn = document.getElementById("PickFolderBtn"); let dir = null; @@ -574,3 +583,23 @@ createBtn.addEventListener("click", () => { }); } }); + +////////////////////////////////////////////////////////// +// Open Viewer +////////////////////////////////////////////////////////// + +const openViewerBtn = document.getElementById("OpenViewerBtn"); + +openViewerBtn.addEventListener("click", (event) => { + if(event.shiftKey) { + console.log("Shift key pressed"); + if(currentFile === null || (!currentFile.endsWith(".html") && !currentFile.endsWith(".htm"))){ + ipcRenderer.send("new-window"); + }else{ + ipcRenderer.send("new-window-set", currentFile); + }; + }else{ + ipcRenderer.send("new-window"); + } + +}); \ No newline at end of file diff --git a/main.js b/main.js index 8223284..3b09fd1 100644 --- a/main.js +++ b/main.js @@ -21,18 +21,16 @@ const launchWindow = require("./modules/launchWindow"); // Setup Window const createWindow = () => { - const window = launchWindow("./front/index/index.html", { - width: 350, - height: 350, - resizable: false, - fullscreenable: false, - webPreferences: { - nodeIntegration: true, - contextIsolation: false - } + const window = launchWindow("./front/editor/editor.html", { + width: 600, + height: 600, + minWidth: 600, + minHeight: 400, + webPreferences: { nodeIntegration: true, contextIsolation: false } }); window.on("closed", () => { + // TODO: Save editor state app.quit(); }); }; @@ -69,11 +67,36 @@ ipcMain.on("new-window", async () => { "window" ) .webContents.on("destroyed", () => { - // Handle window closed + openedDisplays.DELETE( + openedDisplays.FINDQUICKINDEX("fileLink", result.filePaths[0]) + ); }); } }); +ipcMain.on("new-window-set", async(event, args)=> { + const newWdwFMT = openedDisplays.FORMAT(); + + newWdwFMT.SET("fileLink", args); + newWdwFMT.SET( + "window", + launchWindow(args, { width: 500, height: 500 }) + ); + + openedDisplays.PUSH(newWdwFMT); + + openedDisplays + .READ( + openedDisplays.FINDQUICKINDEX("fileLink", args), + "window" + ) + .webContents.on("destroyed", () => { + openedDisplays.DELETE( + openedDisplays.FINDQUICKINDEX("fileLink", args) + ); + }); +}) + ipcMain.on("new-editor", async () => { const result = await dialog.showOpenDialog({ properties: ["openFile"], @@ -240,8 +263,6 @@ ipcMain.handle("pickOpenedDisplay", (event, callerFileIndex) => { openedDisplays: openedDisplaysReduced, caller: callerFileIndex }); - - // Handling Idea: Send the editor who called the new display and the file looking to link to the dialog, so it can call the window itself and handle the file link }); ipcMain.on( From c03cf352e7b8832aa51375a080ac44695cd39633 Mon Sep 17 00:00:00 2001 From: Ethan Mahlstedt Date: Thu, 10 Apr 2025 16:51:40 -0600 Subject: [PATCH 035/126] Move dialogs and main screen to editor --- .hintrc | 3 +- TODOs | 6 +- front/editor/editor.css | 2 +- front/editor/editor.html | 13 +- front/editor/editor.js | 116 +++++++++++++++--- front/index/index.html | 17 --- front/index/index.js | 27 ---- front/index/main.css | 43 ------- front/pickOpenedDisplay/pickOpenedDisplay.css | 54 -------- .../pickOpenedDisplay/pickOpenedDisplay.html | 19 --- front/pickOpenedDisplay/pickOpenedDisplay.js | 43 ------- main.js | 43 ++++--- 12 files changed, 136 insertions(+), 250 deletions(-) delete mode 100644 front/index/index.html delete mode 100644 front/index/index.js delete mode 100644 front/index/main.css delete mode 100644 front/pickOpenedDisplay/pickOpenedDisplay.css delete mode 100644 front/pickOpenedDisplay/pickOpenedDisplay.html delete mode 100644 front/pickOpenedDisplay/pickOpenedDisplay.js diff --git a/.hintrc b/.hintrc index 67b893a..d9cb2bc 100644 --- a/.hintrc +++ b/.hintrc @@ -3,6 +3,7 @@ "development" ], "hints": { - "compat-api/css": "off" + "compat-api/css": "off", + "no-inline-styles": "off" } } \ No newline at end of file diff --git a/TODOs b/TODOs index 0f87dd7..e012bae 100644 --- a/TODOs +++ b/TODOs @@ -8,14 +8,12 @@ Add Github Actions - Fully integrate main window onto editor - HTML Dialogs - Fix link editor window size (or turn it into a HTML dialog) - Save last state of the editor upon close Backside event handler + Cleanup before release + BUGS: Editor window remains open upon closing the window HTML files becoming single lined diff --git a/front/editor/editor.css b/front/editor/editor.css index 5a5dd7d..6ce8464 100644 --- a/front/editor/editor.css +++ b/front/editor/editor.css @@ -207,7 +207,7 @@ h2 { /* New file dialog */ -#newFileDialog { +#newFileDialog, #pickOpenedDisplay { background-color: rgb(48, 48, 48); border-radius: 5px; padding: 1%; diff --git a/front/editor/editor.html b/front/editor/editor.html index a9426df..80fe9d5 100644 --- a/front/editor/editor.html +++ b/front/editor/editor.html @@ -26,7 +26,7 @@

-
+ - + +
+ + + + +
+
diff --git a/front/editor/editor.js b/front/editor/editor.js index 0065aa2..06b14cd 100644 --- a/front/editor/editor.js +++ b/front/editor/editor.js @@ -217,7 +217,7 @@ textArea.addEventListener("input", () => { textArea.scrollTop = scrollPosition; // Restore scroll position }); -textArea.addEventListener("keydown", (event) => { +textArea.addEventListener("keydown", async (event) => { if (event.key === "Enter") { event.preventDefault(); document.execCommand("insertLineBreak"); @@ -230,26 +230,45 @@ textArea.addEventListener("keydown", (event) => { document.execCommand("insertText", false, indent); setCaretPosition(caretOffset + indent.length); } +}); +document.addEventListener("keydown", async(event) => { if (event.ctrlKey) { + console.log(event.key) if (event.key === "s") { event.preventDefault(); saveFile(); - } else if (event.key === "n") { + } else if (event.key.toLowerCase() === "n") { event.preventDefault(); - // TODO: Handle new file - } else if (event.key === "r") { + document.getElementById("newFileDialog").showModal(); + } else if (event.key.toLowerCase() === "r") { event.preventDefault(); - refreshEditor(); - } else if (event.key === "o") { + await refreshEditor(); + } else if (event.key.toLowerCase() === "o") { event.preventDefault(); openNewFile(); - } else if (event.key === "q") { + } else if (event.key.toLowerCase() === "q") { event.preventDefault(); closeFile(currentFile); - }else if(event.key === "w"){ + } else if(event.key.toLowerCase() === "w"){ event.preventDefault(); - // TODO: Open new window / Open current window with Shift + if(event.shiftKey) { + if(currentFile === null || (!currentFile.endsWith(".html") && !currentFile.endsWith(".htm"))){ + ipcRenderer.send("new-window"); + }else{ + ipcRenderer.invoke("new-window-set", currentFile).then((response) => { + if(response !== -1){ + OpenedFiles.SET( + OpenedFiles.FINDQUICKINDEX("fileLink", currentFile), + "linkedDisplay", + response + ); + } + }); + }; + }else{ + ipcRenderer.send("new-window"); + } } } @@ -272,7 +291,7 @@ textArea.addEventListener("keydown", (event) => { } } } -}); +}) document.addEventListener("DOMContentLoaded", () => { checkField(); @@ -421,18 +440,31 @@ function openNewFile() { document.getElementById("openFile").addEventListener("click", openNewFile); -function refreshEditor() { +async function refreshEditor() { if (currentFile === null) return; if ( OpenedFiles.READ( - OpenedFiles.FINDQUICKINDEX("fileLink", currentFile), + OpenedFiles.FINDQUICKINDEX("fileLink", currentFile), "linkedDisplay" ) == null ) { - ipcRenderer.invoke( - "pickOpenedDisplay", - OpenedFiles.FINDQUICKINDEX("fileLink", currentFile) - ); + let OpenedDisplays = []; + + await ipcRenderer.invoke("pickOpenedDisplay").then((response) => { + OpenedDisplays = response; + }) + + console.log(OpenedDisplays) + + OpenedDisplays.forEach((e) => { + const option = document.createElement("option"); + option.value = e.window; + const splittedFileLink = e.fileLink.split("\\"); + option.innerHTML = `${splittedFileLink[splittedFileLink.length - 2]}\\${splittedFileLink[splittedFileLink.length - 1]}`; + document.getElementById("windowPicker").appendChild(option); + }) + + document.getElementById("pickOpenedDisplay").showModal(); } else { ipcRenderer.send( "restartDisplay", @@ -446,7 +478,7 @@ function refreshEditor() { document .getElementById("RefreshEditor") - .addEventListener("click", refreshEditor); + .addEventListener("click", async()=>{await refreshEditor()}); ipcRenderer.on("syncLinkedDisplay", (event, fileID, display) => { OpenedFiles.SET(fileID, "linkedDisplay", display); @@ -461,6 +493,10 @@ window.addEventListener("beforeunload", (event) => { } }); +////////////////////////////////////////////////////////////////// +// Save cursor position on blur +////////////////////////////////////////////////////////////////// + window.addEventListener("focus", () => { if (currentFile) { textArea.focus(); @@ -484,6 +520,10 @@ window.addEventListener("blur", () => { } }); +/////////////////////////////////////////////////////////////// +// Hides field if no file is opened +/////////////////////////////////////////////////////////////// + function checkField() { fieldShown = OpenedFiles.GETJSONDATA().length > 0 ? true : false; if (fieldShown) { @@ -505,6 +545,10 @@ function unloadFiles() { checkField(); } +////////////////////////////////////////////////////////// +// New File Button +////////////////////////////////////////////////////////// + document.getElementById("newFileBtn").addEventListener("click", () => { const dialog = document.getElementById("newFileDialog"); if (dialog.open) { @@ -592,14 +636,46 @@ const openViewerBtn = document.getElementById("OpenViewerBtn"); openViewerBtn.addEventListener("click", (event) => { if(event.shiftKey) { - console.log("Shift key pressed"); if(currentFile === null || (!currentFile.endsWith(".html") && !currentFile.endsWith(".htm"))){ ipcRenderer.send("new-window"); }else{ - ipcRenderer.send("new-window-set", currentFile); + ipcRenderer.invoke("new-window-set", currentFile).then((response) => { + if(response !== -1){ + OpenedFiles.SET( + OpenedFiles.FINDQUICKINDEX("fileLink", currentFile), + "linkedDisplay", + response + ); + } + }); }; }else{ ipcRenderer.send("new-window"); } +}); + +///////////////////////////////////////////////////////// +// Pick Opened Display Dialog +///////////////////////////////////////////////////////// + +const pickOpenedDisplayDialog = document.getElementById("pickOpenedDisplay"); +const cancelDisplayPickBtn = document.getElementById("cancelPickWindowBtn"); -}); \ No newline at end of file +cancelDisplayPickBtn.addEventListener("click", () => { + pickOpenedDisplayDialog.close(); + document.getElementById("windowPicker").value = "none"; +}) + +const pickWindowBtn = document.getElementById("pickWindowBtn"); + +pickWindowBtn.addEventListener("click", () => { + if (document.getElementById("windowPicker").value != "none") { + OpenedFiles.SET( + OpenedFiles.FINDQUICKINDEX("fileLink", currentFile), + "linkedDisplay", + document.getElementById("windowPicker").value + ); + pickOpenedDisplayDialog.close(); + document.getElementById("windowPicker").value = "none"; + } +}) \ No newline at end of file diff --git a/front/index/index.html b/front/index/index.html deleted file mode 100644 index 87ab49d..0000000 --- a/front/index/index.html +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - HTML Editor - - - -

HTML Editor

- -
-
- - - - diff --git a/front/index/index.js b/front/index/index.js deleted file mode 100644 index 5ac0e78..0000000 --- a/front/index/index.js +++ /dev/null @@ -1,27 +0,0 @@ -// Imports - -// Import Electron -const { ipcRenderer } = require("electron"); - -// Import tags from HTML -const ProjectChooseBtn = document.getElementById("ProjectChooseBtn"); -const OpenEditorBtn = document.getElementById("OpenEditorBtn"); -const NewFileBtn = document.getElementById("NewFileBtn"); - -// Import Files - -// Main Code - -document.addEventListener("DOMContentLoaded", () => { - ProjectChooseBtn.onclick = () => { - ipcRenderer.send("new-window"); - }; - - OpenEditorBtn.onclick = () => { - ipcRenderer.send("new-editor"); - }; - - NewFileBtn.onclick = () => { - ipcRenderer.send("new-file-wdw"); - }; -}); diff --git a/front/index/main.css b/front/index/main.css deleted file mode 100644 index 23d21b3..0000000 --- a/front/index/main.css +++ /dev/null @@ -1,43 +0,0 @@ -body { - background-color: rgb(64, 64, 64); -} - -h1 { - color: rgb(255, 255, 255); - font-family: Arial; - text-align: center; -} - -button { - background-color: gray; - font-family: Arial; - align-self: center; - color: black; - padding: 5px 10px; - border-radius: 5px; - border: 1px ridge black; - font-size: 24; - font-weight: bold; - height: auto; - position: absolute; - left: 50%; - -ms-transform: translate(-50%, -50%); - transform: translate(-50%, -50%); -} - -button:hover { - background-color: rgb(64, 64, 64); - font-family: Arial; - align-self: center; - color: white; - padding: 5px 10px; - border-radius: 5px; - border: 1px ridge black; - font-size: 24; - font-weight: bold; - height: auto; - position: absolute; - left: 50%; - -ms-transform: translate(-50%, -50%); - transform: translate(-50%, -50%); -} diff --git a/front/pickOpenedDisplay/pickOpenedDisplay.css b/front/pickOpenedDisplay/pickOpenedDisplay.css deleted file mode 100644 index 644a99d..0000000 --- a/front/pickOpenedDisplay/pickOpenedDisplay.css +++ /dev/null @@ -1,54 +0,0 @@ -html, -body { - background-color: rgb(32, 32, 32); -} - -label { - color: white; - font-family: "Arial"; - font-weight: bold; - vertical-align: middle; - font-size: 14; -} - -.containerDiv { - background-color: rgb(64, 64, 64); - border-radius: 5px; - padding: 1%; - display: flex; - flex-direction: row; - box-sizing: border-box; - gap: 10px; -} - -.mainContainerDiv { - background-color: rgb(48, 48, 48); - padding: 1%; - border-radius: 5px; - gap: 10px; - display: flex; - flex-direction: row; - align-items: center; - height: 65vh; - margin: 1%; -} - -button { - background-color: gray; - font-family: Arial; - color: black; - padding: 5px 10px; - border-radius: 5px; - border: 2px ridge black; - font-size: 14px; - font-weight: bold; - cursor: pointer; - transition: - background-color 0.3s ease, - color 0.3s ease; -} - -button:hover { - background-color: rgb(64, 64, 64); - color: white; -} diff --git a/front/pickOpenedDisplay/pickOpenedDisplay.html b/front/pickOpenedDisplay/pickOpenedDisplay.html deleted file mode 100644 index 981355f..0000000 --- a/front/pickOpenedDisplay/pickOpenedDisplay.html +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - Pick Window... - - - -
- - - -
- - - diff --git a/front/pickOpenedDisplay/pickOpenedDisplay.js b/front/pickOpenedDisplay/pickOpenedDisplay.js deleted file mode 100644 index b67db44..0000000 --- a/front/pickOpenedDisplay/pickOpenedDisplay.js +++ /dev/null @@ -1,43 +0,0 @@ -const { ipcRenderer } = require("electron"); -let CallerWindow = null; -let OpenedDisplays = null; -let CallerEditor = null; -let CallerFile = null; -ipcRenderer.on("loadOpenedEditors", (event, args) => { - CallerWindow = args.callerWindowId; - OpenedDisplays = args.openedDisplays; - CallerEditor = args.callerWindowId; - CallerFile = args.caller; - OpenedDisplays.forEach((e) => { - const option = document.createElement("option"); - option.value = e.window; - const splittedFileLink = e.fileLink.split("\\"); - option.innerHTML = `${splittedFileLink[splittedFileLink.length - 2]}\\${splittedFileLink[splittedFileLink.length - 1]}`; - document.getElementById("windowPicker").appendChild(option); - }); -}); - -document.getElementById("pickWindowBtn").addEventListener("click", () => { - if ( - CallerWindow != null || - OpenedDisplays != null || - CallerEditor != null || - CallerFile != null - ) { - if (document.getElementById("windowPicker").value != "none") { - ipcRenderer.send( - "connectWindowSelection", - document.getElementById("windowPicker").value, - CallerFile, - CallerWindow - ); - } - } else { - alert("Missing caller argument"); - console.log("Missing Caller Argument, variables are:"); - console.log(`CallerWindow: ${CallerWindow}`); - console.log(`OpenedDisplays: ${OpenedDisplays}`); - console.log(`CallerEditor: ${CallerEditor}`); - console.log(`CallerFile: ${CallerFile}`); - } -}); diff --git a/main.js b/main.js index 3b09fd1..25e4797 100644 --- a/main.js +++ b/main.js @@ -50,7 +50,15 @@ ipcMain.on("new-window", async () => { properties: ["openFile"], filters: [{ name: "HTML Files", extensions: ["html"] }] }); - if (!result.canceled && result.filePaths && result.filePaths[0]) { + var flag = true; + if (openedDisplays.GETJSONDATA().length > 0) { + openedDisplays.GETJSONDATA().forEach((e) => { + if (e.fileLink == result.filePaths[0]) { + flag = false; + } + }); + } + if (!result.canceled && result.filePaths && result.filePaths[0] && flag) { const newWdwFMT = openedDisplays.FORMAT(); newWdwFMT.SET("fileLink", result.filePaths[0]); @@ -74,7 +82,16 @@ ipcMain.on("new-window", async () => { } }); -ipcMain.on("new-window-set", async(event, args)=> { +ipcMain.handle("new-window-set", async(event, args)=> { + var flag = true; + if (openedDisplays.GETJSONDATA().length > 0) { + openedDisplays.GETJSONDATA().forEach((e) => { + if (e.fileLink == args) { + flag = false; + } + }); + } + if (flag == false) return -1; const newWdwFMT = openedDisplays.FORMAT(); newWdwFMT.SET("fileLink", args); @@ -95,6 +112,8 @@ ipcMain.on("new-window-set", async(event, args)=> { openedDisplays.FINDQUICKINDEX("fileLink", args) ); }); + + return openedDisplays.FINDQUICKINDEX("fileLink", args); }) ipcMain.on("new-editor", async () => { @@ -243,26 +262,12 @@ ipcMain.on("printOnBackConsole", (event, args) => { console.log(args); }); -ipcMain.handle("pickOpenedDisplay", (event, callerFileIndex) => { - let dialog = launchWindow( - "./front/pickOpenedDisplay/pickOpenedDisplay.html", - { - width: 800, - height: 135, - resizable: true, // Debug - fullscreenable: false, - webPreferences: { nodeIntegration: true, contextIsolation: false } - } - ); +ipcMain.handle("pickOpenedDisplay", async() => { let openedDisplaysReduced = []; - openedDisplays.GETJSONDATA().forEach((e, i) => { + await openedDisplays.GETJSONDATA().forEach((e, i) => { openedDisplaysReduced.push({ fileLink: e.fileLink, window: i }); }); - dialog.webContents.send("loadOpenedEditors", { - callerWindowId: event.sender.id, - openedDisplays: openedDisplaysReduced, - caller: callerFileIndex - }); + return openedDisplaysReduced; }); ipcMain.on( From 72eadc7a7d892b9f1e4c6eecae8074660684e46d Mon Sep 17 00:00:00 2001 From: Ethan Mahlstedt Date: Thu, 10 Apr 2025 16:58:11 -0600 Subject: [PATCH 036/126] Remove unknown library --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index cbeb8de..eeb2564 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,6 @@ "electron": "^33.3.1", "eslint": "^9.19.0", "eslint-config-prettier": "^10.0.1", - "globals": "^15.14.0", "prettier": "3.4.2" }, "dependencies": { From 127f8eb7092a2fbb6f64540ded88747011bf400e Mon Sep 17 00:00:00 2001 From: Ethan Mahlstedt Date: Thu, 10 Apr 2025 17:11:47 -0600 Subject: [PATCH 037/126] Bugfix - Window remains open when closing - Bugfix: Window remains open when closing - Lint - Pretty --- TODOs | 3 +- front/editor/editor.css | 3 +- front/editor/editor.html | 2 +- front/editor/editor.js | 92 ++++++++++++++++++++++++++-------------- main.js | 30 +++++-------- 5 files changed, 75 insertions(+), 55 deletions(-) diff --git a/TODOs b/TODOs index e012bae..fa209dd 100644 --- a/TODOs +++ b/TODOs @@ -14,7 +14,8 @@ Cleanup before release + Remove Linked Display if Display is closed + BUGS: - Editor window remains open upon closing the window HTML files becoming single lined Blank lines counted as double \ No newline at end of file diff --git a/front/editor/editor.css b/front/editor/editor.css index 6ce8464..e0c9336 100644 --- a/front/editor/editor.css +++ b/front/editor/editor.css @@ -207,7 +207,8 @@ h2 { /* New file dialog */ -#newFileDialog, #pickOpenedDisplay { +#newFileDialog, +#pickOpenedDisplay { background-color: rgb(48, 48, 48); border-radius: 5px; padding: 1%; diff --git a/front/editor/editor.html b/front/editor/editor.html index 80fe9d5..c5df946 100644 --- a/front/editor/editor.html +++ b/front/editor/editor.html @@ -26,7 +26,7 @@

-