diff --git a/build.bat b/build.bat new file mode 100644 index 0000000..d66153f --- /dev/null +++ b/build.bat @@ -0,0 +1,2 @@ +@echo off +npx electron-builder \ No newline at end of file diff --git a/electron-builder.json b/electron-builder.json index 48ceb75..4188f8e 100644 --- a/electron-builder.json +++ b/electron-builder.json @@ -4,8 +4,14 @@ "directories": { "output": "dist" }, - "files": ["!filePresets/**"], - "extraResources": [{ "from": "filePresets", "to": "../filePresets" }], + "files": ["!filePresets/**", "!front/editor/highlighter.css"], + "extraResources": [ + { "from": "filePresets", "to": "../filePresets" }, + { + "from": "front/editor/highlighter.css", + "to": "../front/editor/highlighter.css" + } + ], "icon": "resources/icon/icon.ico", "win": { "target": "zip", diff --git a/front/editor/editor.html b/front/editor/editor.html index c9a3e4e..776b367 100644 --- a/front/editor/editor.html +++ b/front/editor/editor.html @@ -4,7 +4,6 @@ WebBox - diff --git a/front/editor/editor.js b/front/editor/editor.js index 8cd0253..28bccb4 100644 --- a/front/editor/editor.js +++ b/front/editor/editor.js @@ -1,6 +1,6 @@ /* /////////////////////////////////////////////////////////////// - Index - Search with Ctrl + F (VSCode) + editor.js / Index - Search with Ctrl + F (VSCode) /////////////////////////////////////////////////////////////// - Module Import @@ -22,6 +22,8 @@ - New File Dialog - Open Viewer - Pick Opened Display Dialog + - Load Highlighter + - Handle Window Deletion - Others */ @@ -41,6 +43,7 @@ const { const highlighter = require("./highlight"); const { getCaretPosition, setCaretPosition } = require("./modules/caret"); const fs = require("fs"); +const path = require("path"); /////////////////////////////////////////////////////////////// // Setup Needle DB @@ -382,11 +385,9 @@ document.addEventListener("keydown", async (event) => { } } else if (event.key.toLowerCase() === "w") { event.preventDefault(); + if (currentFile === null) return; if (event.shiftKey) { - if ( - currentFile === null || - (!currentFile.endsWith(".html") && !currentFile.endsWith(".htm")) - ) { + if (!currentFile.endsWith(".html") && !currentFile.endsWith(".htm")) { ipcRenderer.send("new-window"); } else { ipcRenderer.invoke("new-window-set", currentFile).then((response) => { @@ -575,8 +576,19 @@ async function refreshEditor() { }); OpenedDisplays.forEach((e) => { + Array.from(document.getElementById("windowPicker").children).forEach( + (child) => { + child.remove(); + } + ); + // + const noOption = document.createElement("option"); + noOption.value = "none"; + noOption.innerHTML = "(none)"; + document.getElementById("windowPicker").appendChild(noOption); + const option = document.createElement("option"); - option.value = e.window; + option.value = e.fileLink; const splittedFileLink = e.fileLink.split("\\"); option.innerHTML = `${splittedFileLink[splittedFileLink.length - 2]}\\${splittedFileLink[splittedFileLink.length - 1]}`; document.getElementById("windowPicker").appendChild(option); @@ -746,20 +758,33 @@ createBtn.addEventListener("click", () => { 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"); + let filedata = ""; + + if (args.preset !== "none") { + filedata = fs.readFileSync(args.preset, { encoding: "utf-8" }); + } + + let ans = 0; + + fs.writeFile(`${args.dir}\\${args.name}`, filedata, function (err) { + if (err) { + ans = err; + throw err; } }); + + if (ans == 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"); + } } }); @@ -770,11 +795,9 @@ createBtn.addEventListener("click", () => { const openViewerBtn = document.getElementById("OpenViewerBtn"); openViewerBtn.addEventListener("click", (event) => { + if (currentFile === null) return; if (event.shiftKey) { - if ( - currentFile === null || - (!currentFile.endsWith(".html") && !currentFile.endsWith(".htm")) - ) { + if (!currentFile.endsWith(".html") && !currentFile.endsWith(".htm")) { ipcRenderer.send("new-window"); } else { ipcRenderer.invoke("new-window-set", currentFile).then((response) => { @@ -807,7 +830,7 @@ cancelDisplayPickBtn.addEventListener("click", () => { const pickWindowBtn = document.getElementById("pickWindowBtn"); pickWindowBtn.addEventListener("click", () => { - if (document.getElementById("windowPicker").value != "none") { + if (document.getElementById("windowPicker").value !== "none") { OpenedFiles.SET( OpenedFiles.FINDQUICKINDEX("fileLink", currentFile), "linkedDisplay", @@ -815,9 +838,34 @@ pickWindowBtn.addEventListener("click", () => { ); pickOpenedDisplayDialog.close(); document.getElementById("windowPicker").value = "none"; + } else { + pickOpenedDisplayDialog.close(); } }); +////////////////////////////////////////////////////////// +// Load Highlighter +///////////////////////////////////////////////////////// + +const cssPath = path.join(process.cwd(), "front", "editor", "highlighter.css"); + +const link = document.createElement("link"); +link.rel = "stylesheet"; +link.href = `file://${cssPath}`; +document.head.appendChild(link); + +////////////////////////////////////////////////////////// +// Handle Window Deletion +///////////////////////////////////////////////////////// + +ipcRenderer.on("deleteWindow", (event, fileLink) => { + const linkedEditors = OpenedFiles.SEARCH("linkedDisplay", fileLink); + + linkedEditors.forEach((e) => { + OpenedFiles.SET(e, "linkedDisplay", null); + }); +}); + ///////////////////////////////////////////////////////// // Others ///////////////////////////////////////////////////////// diff --git a/main.js b/main.js index 1b72816..c59f556 100644 --- a/main.js +++ b/main.js @@ -1,36 +1,53 @@ -// Import libraries -const { - app, - BrowserWindow, - ipcMain, - dialog, - webContents -} = require("electron"); -const fs = require("fs"); -const needle = require("needle-db"); +/* +/////////////////////////////////////////////////////////////// + main.js / Index - Search with Ctrl + F (VSCode) +/////////////////////////////////////////////////////////////// + + - Module Import + - Setup Needle DB + - Setup Main Editor + - Handle New Window Creation + - Handle file picking + - Handle directory picking + - Handle window closures + - Handle Display Restart + - Others + +*/ + +/////////////////////////////////////////////////////////////// +// Module Import +/////////////////////////////////////////////////////////////// -// Setup OpenedDisplaysDB +const { app, BrowserWindow, ipcMain, dialog } = require("electron"); +const launchWindow = require("./modules/launchWindow"); + +/////////////////////////////////////////////////////////////// +// Setup Needle DB +/////////////////////////////////////////////////////////////// + +const needle = require("needle-db"); const openedDisplays = new needle(); openedDisplays.NEWCOLUMN("fileLink"); openedDisplays.NEWCOLUMN("window"); -// Import Dependencies -const launchWindow = require("./modules/launchWindow"); - -// Setup Window +/////////////////////////////////////////////////////////////// +// Setup Main Editor +/////////////////////////////////////////////////////////////// +let mainWindow = null; const createWindow = () => { - const window = launchWindow("./front/editor/editor.html", { + mainWindow = launchWindow("./front/editor/editor.html", { width: 600, height: 600, minWidth: 600, minHeight: 400, webPreferences: { nodeIntegration: true, contextIsolation: false } + //autoHideMenuBar: true // Commented out for debugging }); - window.on("closed", () => { - // TODO: Save editor state + mainWindow.on("closed", () => { app.quit(); }); }; @@ -45,6 +62,36 @@ app.on("window-all-closed", () => { if (process.platform !== "darwin") app.quit(); }); +/////////////////////////////////////////////////////////////// +// Handle New Window Creation +// - Handle set window creation +/////////////////////////////////////////////////////////////// + +function createNewDisplay(fileLink) { + const newWdwFMT = openedDisplays.FORMAT(); + + newWdwFMT.SET("fileLink", fileLink); + newWdwFMT.SET( + "window", + launchWindow(fileLink, { + width: 500, + height: 500, + webPreferences: { nodeIntegration: true } + }) + ); + + openedDisplays.PUSH(newWdwFMT); + + openedDisplays + .READ(openedDisplays.FINDQUICKINDEX("fileLink", fileLink), "window") + .webContents.on("destroyed", () => { + openedDisplays.DELETE( + openedDisplays.FINDQUICKINDEX("fileLink", fileLink) + ); + mainWindow.webContents.send("deleteWindow", fileLink); + }); +} + ipcMain.on("new-window", async () => { const result = await dialog.showOpenDialog({ properties: ["openFile"], @@ -59,29 +106,14 @@ ipcMain.on("new-window", async () => { }); } if (!result.canceled && result.filePaths && result.filePaths[0] && flag) { - const newWdwFMT = openedDisplays.FORMAT(); - - newWdwFMT.SET("fileLink", result.filePaths[0]); - newWdwFMT.SET( - "window", - launchWindow(result.filePaths[0], { width: 500, height: 500 }) - ); - - openedDisplays.PUSH(newWdwFMT); - - openedDisplays - .READ( - openedDisplays.FINDQUICKINDEX("fileLink", result.filePaths[0]), - "window" - ) - .webContents.on("destroyed", () => { - openedDisplays.DELETE( - openedDisplays.FINDQUICKINDEX("fileLink", result.filePaths[0]) - ); - }); + createNewDisplay(result.filePaths[0]); } }); +/////////////////////////////////////////////////////////////// +// Handle New Window Creation: Handle set window creation +/////////////////////////////////////////////////////////////// + ipcMain.handle("new-window-set", async (event, args) => { var flag = true; if (openedDisplays.GETJSONDATA().length > 0) { @@ -92,22 +124,14 @@ ipcMain.handle("new-window-set", async (event, args) => { }); } if (flag == false) return -1; - 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)); - }); - - return openedDisplays.FINDQUICKINDEX("fileLink", args); + createNewDisplay(args); + return args; }); +/////////////////////////////////////////////////////////////// +// Handle file picking +/////////////////////////////////////////////////////////////// + ipcMain.handle("filePickerDialog", async () => { const result = await dialog.showOpenDialog({ properties: ["openFile"], @@ -136,6 +160,10 @@ ipcMain.handle("filePickerDialog", async () => { return result.filePaths[0]; }); +/////////////////////////////////////////////////////////////// +// Handle directory picking +/////////////////////////////////////////////////////////////// + ipcMain.handle("get-dir", async () => { const result = await dialog.showOpenDialog({ properties: ["openDirectory"] @@ -148,24 +176,10 @@ ipcMain.handle("get-dir", async () => { } }); -ipcMain.handle("createFile", (event, args) => { - let filedata = ""; - - if (args.preset !== "none") { - filedata = fs.readFileSync(args.preset, { encoding: "utf-8" }); - } - - let ans = 0; - - fs.writeFile(`${args.dir}\\${args.name}`, filedata, function (err) { - if (err) { - ans = err; - throw err; - } - }); - - return ans; -}); +/////////////////////////////////////////////////////////////// +// Handle window closures +// - Force Close +/////////////////////////////////////////////////////////////// ipcMain.on("closeWindow", (event) => { const senderWindow = BrowserWindow.getAllWindows().find( @@ -177,6 +191,10 @@ ipcMain.on("closeWindow", (event) => { } }); +/////////////////////////////////////////////////////////////// +// Handle window closure: Force Close +/////////////////////////////////////////////////////////////// + ipcMain.on("forceCloseWindow", (event) => { const senderWindow = BrowserWindow.getAllWindows().find( (win) => win.webContents === event.sender @@ -187,6 +205,25 @@ ipcMain.on("forceCloseWindow", (event) => { } }); +/////////////////////////////////////////////////////////////// +// Handle Display Restart +/////////////////////////////////////////////////////////////// + +ipcMain.on("restartDisplay", (event, args) => { + openedDisplays + .READ(openedDisplays.FINDQUICKINDEX("fileLink", args), "window") + .loadFile( + openedDisplays.READ( + openedDisplays.FINDQUICKINDEX("fileLink", args), + "fileLink" + ) + ); +}); + +/////////////////////////////////////////////////////////////// +// Others +/////////////////////////////////////////////////////////////// + ipcMain.on("printOnBackConsole", (event, args) => { console.log(args); }); @@ -199,23 +236,8 @@ ipcMain.handle("pickOpenedDisplay", async () => { return openedDisplaysReduced; }); -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") - .loadFile(openedDisplays.READ(args, "fileLink")); -});