diff --git a/README.md b/README.md
index 9f5a0ce..15313a8 100644
--- a/README.md
+++ b/README.md
@@ -15,7 +15,7 @@
-
+
@@ -27,7 +27,7 @@
Iris is written in TypeScript and Rust.
-The app currently in early development and may not be 100% stable for daily use.
+The app is currently in early development and may not be 100% stable for daily use.
Only macOS installers are supplied in the early development phase. Other platforms will be supported in the official release.
diff --git a/package.json b/package.json
index 35f93ad..c68ddef 100644
--- a/package.json
+++ b/package.json
@@ -1,8 +1,8 @@
{
"name": "iris",
- "version": "0.2.0-dev-4.3",
+ "version": "0.2.0-dev-5.0",
"productName": "Iris",
- "description": "Iris is a comfortable Markdown note-taking app",
+ "description": "A comfortable note-taking app powered by Markdown",
"main": "./out/main/index.js",
"author": "alexwkleung",
"license": "MIT",
diff --git a/src/main/index.ts b/src/main/index.ts
index a9fa2bb..4838e6d 100644
--- a/src/main/index.ts
+++ b/src/main/index.ts
@@ -1,130 +1,209 @@
-import { app, shell, BrowserWindow, protocol, net, ipcMain } from 'electron'
-import { join } from 'path'
-import { dirname } from 'path'
+import { app, shell, BrowserWindow, protocol, net, ipcMain, dialog } from 'electron'
+import { join, dirname } from 'path'
import { fileURLToPath } from 'url'
import contextMenu from 'electron-context-menu'
//import icon from '../../resources/icon.png?asset'
import { isMacOS, isWindows, isLinux, isDev } from './is-main'
import windowStateKeeper from 'electron-window-state'
-import { dialog } from 'electron'
-//prevent multiple instances of Iris running
-if(!app.requestSingleInstanceLock()) {
- console.log("Another instance of Iris is running. Exiting.");
-
- dialog.showErrorBox("Iris", "Another instance of Iris is running. Closing current instance.");
-
- app.quit();
-}
-
-ipcMain.handle('error-dialog', (event, title, content) => {
- dialog.showErrorBox(title, content);
-})
-
-function createWindow(): void {
- //esm version of __dirname
- const _dirname: string = dirname(fileURLToPath(import.meta.url));
-
- //isomorphic version of __dirname for both cjs/esm compatibility (https://antfu.me/posts/isomorphic-dirname)
- //const _dirname: string = typeof __dirname !== 'undefined' ? __dirname : dirname(fileURLToPath(import.meta.url));
-
- //create window state keeper
- const windowState: windowStateKeeper.State = windowStateKeeper({
- defaultWidth: 1200,
- defaultHeight: 900,
- })
-
- let mainWindow: BrowserWindow = {} as BrowserWindow;
-
- mainWindow = new BrowserWindow({
- width: windowState.width,
- height: windowState.height,
- x: windowState.x,
- y: windowState.y,
- minWidth: 800,
- minHeight: 600,
- show: false,
- autoHideMenuBar: true,
- titleBarStyle: isMacOS() ? 'hiddenInset' : 'default', //only check macOS
- webPreferences: {
- preload: join(_dirname, '../preload/index.js'),
- sandbox: false,
- contextIsolation: true,
- webviewTag: false,
- spellcheck: false
+namespace MainProcess {
+ class AppWindow {
+ /**
+ * Browser window
+ *
+ * @protected
+ */
+ protected mainWindow: BrowserWindow = {} as BrowserWindow;
+
+ /**
+ * Window state
+ *
+ * @private
+ */
+ private windowState: windowStateKeeper.State = {} as windowStateKeeper.State;
+
+ /**
+ * App instance
+ *
+ * @private
+ */
+ private appInstance(): void {
+ //prevent multiple instances of Iris running
+ if(!app.requestSingleInstanceLock()) {
+ console.log("Another instance of Iris is running. Exiting.");
+
+ dialog.showErrorBox("Iris", "Another instance of Iris is running. Closing current instance.");
+
+ app.quit();
+ process.exit(0);
+ }
}
- });
-
- //register windowState listener
- windowState.manage(mainWindow);
-
- //check if platform is darwin
- if(isMacOS()) {
- //log
- console.log("Platform is darwin (macOS)");
- //check if platform is linux
- } else if(isLinux()) {
- //log
- console.log("Platform is Linux");
- //check if platform is windows
- } else if(isWindows()) {
- //log
- console.log("Platform is Windows");
- }
- //set min window size
- mainWindow.setMinimumSize(800, 600);
+ /**
+ * ipcMain handlers
+ *
+ * @private
+ */
+ private ipcMainHandlers(): void {
+ ipcMain.handle('error-dialog', (_: Electron.IpcMainInvokeEvent, title: string, content: string) => {
+ dialog.showErrorBox(title, content);
+ })
+
+ ipcMain.handle('show-message-box', (_: Electron.IpcMainInvokeEvent, message: string) => {
+ dialog.showMessageBox(this.mainWindow, {
+ message: message
+ })
+ })
+ }
- //for now, use electron-context-menu and extend it if necessary.
- //later on, I will implement my own custom context menu so it can be
- //fine-tuned based on the needs of Iris
- contextMenu();
+ /**
+ * Call this after registering `windowState` listener
+ *
+ * @internal
+ * @private
+ */
+ private mainProcLogger(): void {
+ console.log("Current window dimensions: " + this.windowState.width + "x" + this.windowState.height);
+ console.log("Current window coordinates: " + "(" + this.windowState.x + ", " + this.windowState.y + ")");
+ }
- mainWindow.on('ready-to-show', () => {
- mainWindow.show();
- });
+ /**
+ * Initialize main window
+ *
+ * @private
+ */
+ private initializeMainWindow(): void {
+ //esm version of __dirname
+ const _dirname: string = dirname(fileURLToPath(import.meta.url));
+
+ //isomorphic version of __dirname for both cjs/esm compatibility (https://antfu.me/posts/isomorphic-dirname)
+ //const _dirname: string = typeof __dirname !== 'undefined' ? __dirname : dirname(fileURLToPath(import.meta.url));
+
+ this.windowState = windowStateKeeper({
+ defaultWidth: 1200,
+ defaultHeight: 900,
+ });
- mainWindow.webContents.setWindowOpenHandler((details) => {
- shell.openExternal(details.url)
- return {
- action: 'deny'
+ this.mainWindow = new BrowserWindow({
+ width: this.windowState.width,
+ height: this.windowState.height,
+ x: this.windowState.x,
+ y: this.windowState.y,
+ minWidth: 800,
+ minHeight: 600,
+ show: false,
+ autoHideMenuBar: true,
+ titleBarStyle: isMacOS() ? 'hiddenInset' : 'default', //only check macOS
+ webPreferences: {
+ preload: join(_dirname, '../preload/index.js'),
+ sandbox: false,
+ contextIsolation: true,
+ webviewTag: false,
+ spellcheck: false
+ }
+ });
+
+ //register windowState listener
+ this.windowState.manage(this.mainWindow);
+
+ //main process logger
+ this.mainProcLogger();
+
+ //check if platform is darwin
+ if(isMacOS()) {
+ //log
+ console.log("Platform is darwin (macOS)");
+ //check if platform is linux
+ } else if(isLinux()) {
+ //log
+ console.log("Platform is Linux");
+ //check if platform is windows
+ } else if(isWindows()) {
+ //log
+ console.log("Platform is Windows");
}
- });
-
- if(isDev()) {
- //load dev server url in main window
- mainWindow.loadURL('http://localhost:5173/');
+
+ //set min window size
+ this.mainWindow.setMinimumSize(800, 600);
+
+ //for now, use electron-context-menu and extend it if necessary.
+ //later on, I will implement my own custom context menu so it can be
+ //fine-tuned based on the needs of Iris
+ contextMenu();
+
+ this.mainWindow.on('ready-to-show', () => {
+ this.mainWindow.show();
+ });
+
+ this.mainWindow.webContents.setWindowOpenHandler((details) => {
+ shell.openExternal(details.url)
+ return {
+ action: 'deny'
+ }
+ });
+
+ if(isDev()) {
+ //load dev server url in main window
+ this.mainWindow.loadURL('http://localhost:5173/');
+
+ //open dev tools undocked by default
+ this.mainWindow.webContents.openDevTools({
+ mode: 'undocked'
+ });
+ } else {
+ //this is supposed to be production build
+ //path might change once electron-vite is removed
+ this.mainWindow.loadFile(join(__dirname, '../renderer/index.html'));
+ }
+ }
- //open dev tools undocked by default
- mainWindow.webContents.openDevTools({
- mode: 'undocked'
+ /**
+ * Initialize Electron app
+ *
+ * @private
+ */
+ private initializeElectronApp(): void {
+ app.whenReady().then(() => {
+ //initialize main window
+ this.initializeMainWindow();
+
+ app.on('activate', () => {
+ if(BrowserWindow.getAllWindows().length === 0) {
+ this.initializeMainWindow();
+ }
+ });
+
+ //custom protocol to handle local file system absolute paths
+ protocol.handle('local', (request): Promise => {
+ return net.fetch('file://' + request.url.slice('local://'.length)).catch((e) => console.error(e)) as Promise
+ })
+ });
+
+ app.on('window-all-closed', () => {
+ if(isLinux() || isWindows()) {
+ app.quit();
+ } else if(isMacOS()) {
+ return;
+ }
});
- } else {
- //this is supposed to be production build
- //path might change once electron-vite is removed
- mainWindow.loadFile(join(__dirname, '../renderer/index.html'));
+ }
+
+ /**
+ * Build main window
+ *
+ * @public
+ */
+ public buildMainWindow(): void {
+ this.appInstance();
+ this.ipcMainHandlers();
+ this.initializeElectronApp();
+ }
}
+
+ //AppWindow object
+ export const ElectronWindow: AppWindow = new AppWindow();
}
-app.whenReady().then(() => {
- createWindow();
+//build window
+MainProcess.ElectronWindow.buildMainWindow();
- app.on('activate', () => {
- if(BrowserWindow.getAllWindows().length === 0) {
- createWindow();
- }
- });
-
- //custom protocol to handle local file system absolute paths
- protocol.handle('local', (request): Promise => {
- return net.fetch('file://' + request.url.slice('local://'.length)).catch((e) => console.error(e)) as Promise
- })
-});
-
-app.on('window-all-closed', () => {
- if(isLinux() || isWindows()) {
- app.quit();
- } else if(isMacOS()) {
- return;
- }
-});
\ No newline at end of file
diff --git a/src/preload/index.ts b/src/preload/index.ts
index 70b2162..b44550c 100644
--- a/src/preload/index.ts
+++ b/src/preload/index.ts
@@ -3,45 +3,74 @@ import { electronAPI } from '../preload/electron/electron'
import { fsMod } from './mod/fs-mod'
import { settingFiles } from '../renderer/src/settings/create-default-settings'
-function appStartDirectoryCheck(): void {
- if(
- !fsMod._isPathDir(fsMod._baseDir("home") + "/Iris")
- && !fsMod._isPathDir(fsMod._baseDir("home") + "/Iris/Notes")
- && !fsMod._isPathDir(fsMod._baseDir("home") + "/Iris/Images")
- ) {
- console.log("directories don't exist");
-
- //create iris directory
- fsMod._createDir(fsMod._baseDir("home") + "/Iris");
-
- //create notes directory
- fsMod._createDir(fsMod._baseDir("home") + "/Iris/Notes");
-
- //create images directory
- fsMod._createDir(fsMod._baseDir("home") + "/Iris/Images");
-
- //create default settings
- settingFiles.createSettingFile('default');
+namespace PreloadProcess {
+ class PreloadScripts {
+ /**
+ * App start directory check
+ *
+ * @private
+ */
+ private appStartDirectoryCheck(): void {
+ if(!fsMod._isPathDir(fsMod._baseDir("home") + "/Iris") && !fsMod._isPathDir(fsMod._baseDir("home") + "/Iris/Notes") && !fsMod._isPathDir(fsMod._baseDir("home") + "/Iris/Images")) {
+ console.log("directories don't exist");
+
+ //create iris directory
+ fsMod._createDir(fsMod._baseDir("home") + "/Iris");
+
+ //create notes directory
+ fsMod._createDir(fsMod._baseDir("home") + "/Iris/Notes");
+
+ //create images directory
+ fsMod._createDir(fsMod._baseDir("home") + "/Iris/Images");
+
+ //create default settings
+ settingFiles.createSettingFile('default');
+ }
}
-}
-appStartDirectoryCheck();
-if(process.contextIsolated) {
- try {
- //expose electron
- contextBridge.exposeInMainWorld('electron', electronAPI)
+ /**
+ * Context isolation
+ *
+ * @private
+ */
+ private contextIsolation(): void {
+ if(process.contextIsolated) {
+ try {
+ //expose electron
+ contextBridge.exposeInMainWorld('electron', electronAPI)
+
+ //expose fsMod
+ contextBridge.exposeInMainWorld('fsMod', fsMod)
+ } catch(e) {
+ throw console.error(e);
+ }
+ } else {
+ //eslint-disable-next-line
+ //@ts-ignore
+ window.electron = electronAPI
- //expose fsMod
- contextBridge.exposeInMainWorld('fsMod', fsMod)
- } catch(e) {
- throw console.error(e);
+ //eslint-disable-next-line
+ //@ts-ignore
+ window.fsMod = fsMod
+ }
+ }
+
+ /**
+ * Preload scripts
+ *
+ * @public
+ */
+ public preloadScripts(): void {
+ this.appStartDirectoryCheck();
+ this.contextIsolation();
+ }
}
-} else {
- //eslint-disable-next-line
- //@ts-ignore
- window.electron = electronAPI
- //eslint-disable-next-line
- //@ts-ignore
- window.fsMod = fsMod
-}
\ No newline at end of file
+ /**
+ * PreloadScripts object
+ */
+ export const execute: PreloadScripts = new PreloadScripts();
+}
+
+//execute preload scripts
+PreloadProcess.execute.preloadScripts();
\ No newline at end of file
diff --git a/src/renderer/assets/classic-light.min.css b/src/renderer/assets/classic-light.min.css
index 1ca3619..687a8e9 100644
--- a/src/renderer/assets/classic-light.min.css
+++ b/src/renderer/assets/classic-light.min.css
@@ -4,4 +4,4 @@
License: ~ MIT (or more permissive) [via base16-schemes-source]
Maintainer: @highlightjs/core-team
Version: 2021.09.0
-*/pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{color:#303030;background:#d2d1d1}.hljs ::selection,.hljs::selection{background-color:#d0d0d0;color:#303030}.hljs-comment{color:#b0b0b0}.hljs-tag{color:#505050}.hljs-operator,.hljs-punctuation,.hljs-subst{color:#303030}.hljs-operator{opacity:.7}.hljs-bullet,.hljs-deletion,.hljs-name,.hljs-selector-tag,.hljs-template-variable,.hljs-variable{color:#ac4142}.hljs-attr,.hljs-link,.hljs-literal,.hljs-number,.hljs-symbol,.hljs-variable.constant_{color:#d28445}.hljs-class .hljs-title,.hljs-title,.hljs-title.class_{color:#f4bf75}.hljs-strong{font-weight:700;color:#f4bf75}.hljs-addition,.hljs-code,.hljs-string,.hljs-title.class_.inherited__{color:#90a959}.hljs-built_in,.hljs-doctag,.hljs-keyword.hljs-atrule,.hljs-quote,.hljs-regexp{color:#75b5aa}.hljs-attribute,.hljs-function .hljs-title,.hljs-section,.hljs-title.function_,.ruby .hljs-property{color:#6a9fb5}.diff .hljs-meta,.hljs-keyword,.hljs-template-tag,.hljs-type{color:#aa759f}.hljs-emphasis{color:#aa759f;font-style:italic}.hljs-meta,.hljs-meta .hljs-keyword,.hljs-meta .hljs-string{color:#8f5536}.hljs-meta .hljs-keyword,.hljs-meta-keyword{font-weight:700}
\ No newline at end of file
+*/pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{color:#303030;background:#d2d1d1}.hljs ::selection,.hljs::selection{background-color:#d0d0d0;color:#303030}.hljs-comment{color:#b0b0b0}.hljs-tag{color:#505050}.hljs-operator,.hljs-punctuation,.hljs-subst{color:#303030}.hljs-operator{opacity:.7}.hljs-bullet,.hljs-deletion,.hljs-name,.hljs-selector-tag,.hljs-template-variable,.hljs-variable{color:#ac4142}.hljs-attr,.hljs-link,.hljs-literal,.hljs-number,.hljs-symbol,.hljs-variable.constant_{color:#d28445}.hljs-class .hljs-title,.hljs-title,.hljs-title.class_{color:#f0a946}.hljs-strong{font-weight:700;color:#f4bf75}.hljs-addition,.hljs-code,.hljs-string,.hljs-title.class_.inherited__{color:#90a959}.hljs-built_in,.hljs-doctag,.hljs-keyword.hljs-atrule,.hljs-quote,.hljs-regexp{color:#75b5aa}.hljs-attribute,.hljs-function .hljs-title,.hljs-section,.hljs-title.function_,.ruby .hljs-property{color:#6a9fb5}.diff .hljs-meta,.hljs-keyword,.hljs-template-tag,.hljs-type{color:#aa759f}.hljs-emphasis{color:#aa759f;font-style:italic}.hljs-meta,.hljs-meta .hljs-keyword,.hljs-meta .hljs-string{color:#8f5536}.hljs-meta .hljs-keyword,.hljs-meta-keyword{font-weight:700}
\ No newline at end of file
diff --git a/src/renderer/assets/global.css b/src/renderer/assets/global.css
index a61bc0a..1ab893c 100644
--- a/src/renderer/assets/global.css
+++ b/src/renderer/assets/global.css
@@ -722,8 +722,8 @@ body {
#settings-modal-exit {
z-index: 1;
position: fixed;
- width: 42px;
- height: 25px;
+ width: 35px;
+ height: 27px;
color: white;
border: 1px solid;
border-color: grey;
diff --git a/src/renderer/listener-main.ts b/src/renderer/listener-main.ts
index d6eb1c7..efa6b96 100644
--- a/src/renderer/listener-main.ts
+++ b/src/renderer/listener-main.ts
@@ -3,7 +3,6 @@ import { DirectoryTreeUIModalListeners } from "./src/event-listeners/directory-t
import { SettingsModalListeners } from "./src/event-listeners/settings-modal-listeners.js"
import { DirectoryTreeKebabDropdownListeners } from "./src/event-listeners/directory-tree-kebab-dropdown-listener.js"
-//eslint-disable-next-line @typescript-eslint/no-namespace
export namespace ListenerNs {
export function directoryTreeListeners(): void {
const dirTreeListeners = new DirectoryTreeListeners();
diff --git a/src/renderer/src/event-listeners/directory-tree-ui-modal-listeners.ts b/src/renderer/src/event-listeners/directory-tree-ui-modal-listeners.ts
index f705f07..45ecf72 100644
--- a/src/renderer/src/event-listeners/directory-tree-ui-modal-listeners.ts
+++ b/src/renderer/src/event-listeners/directory-tree-ui-modal-listeners.ts
@@ -22,6 +22,8 @@ import { Settings } from "../settings/settings"
import { AdvancedModeSettings } from "../settings/settings"
import { ReadingMode } from "../mode/reading-mode"
import { markdownParser } from "../utils/markdown-parser"
+import { GenericEvent } from "./event"
+import { KeyBinds } from "../keybinds/keybinds"
/**
* @extends DirectoryTreeUIModals
@@ -91,444 +93,322 @@ export class DirectoryTreeUIModalListeners extends DirectoryTreeUIModals impleme
private readonly dirTreeStateListeners = new DirectoryTreeStateListeners();
/**
- * Create file modal exit listener
+ * File name for create file input
+ * @private
*/
- public createFileModalExitListener(): void {
- DirectoryTreeUIModals.createModalExitButton.addEventListener('click', () => {
- const createFileNode: NodeListOf = document.querySelectorAll('.create-new-file');
+ private fileName: string = "" + ".md";
- createFileNode.forEach((elem) => {
- //null check
- if(elem !== null) {
- elem.classList.remove('is-active-create-new-file-modal');
- }
- });
-
- //null check
- if(DirectoryTreeUIModals.createModalContainer !== null) {
- DirectoryTreeUIModals.createModalContainer.remove();
- }
- //invoke parent root listener
- this.directoryTreeListeners.parentRootListener();
-
- //invoke child node listener
- this.directoryTreeListeners.childNodeListener();
-
- //invoke parent root listener again so the directory tree will be in sync
- this.directoryTreeListeners.parentRootListener();
- })
- }
+ /**
+ * Folder name for create folder input
+ * @private
+ */
+ private folderName: string = "";
/**
- * Create file modal continue listener
+ * Create modal exit callback
*
- * @param el Element to attach `keyup` event listener to
+ * @public
*/
- public createFileModalContinueListener(el: HTMLElement): void {
- let fileName: string = "" + ".md";
+ public createModalExitCb: () => void = (): void => {
+ const createFileNode: NodeListOf = document.querySelectorAll('.create-new-file');
- el.addEventListener('keyup', (e) => {
- //assign current value of input element on keyup + extension
- fileName = ((e.target as HTMLInputElement).value).trim() + ".md";
+ createFileNode.forEach((elem) => {
+ //null check
+ if(elem !== null) {
+ elem.classList.remove('is-active-create-new-file-modal');
+ }
+ });
- //log
- console.log(fileName);
- })
+ //null check
+ if(DirectoryTreeUIModals.createModalContainer !== null) {
+ DirectoryTreeUIModals.createModalContainer.remove();
+ }
+
+ //invoke parent root listener
+ this.directoryTreeListeners.parentRootListener();
- DirectoryTreeUIModals.createModalContinueButton.addEventListener('click', async () => {
- if(fileName === ".md") {
- window.electron.ipcRenderer.invoke('error-dialog', "Iris", "A note with an empty file name has been created. It is recommended to rename the note.")
- }
+ //invoke child node listener
+ this.directoryTreeListeners.childNodeListener();
- //mode check
- if(isModeBasic() && fileName !== " ") {
- //log
- console.log((document.querySelector('#create-file-modal-folder-name-input-node') as HTMLElement).textContent)
-
- fsMod.fs._createFile(
- fsMod.fs._baseDir("home")
- + "/Iris/Notes/"
- + (document.querySelector('#create-file-modal-folder-name-input-node') as HTMLElement).textContent
- + "/" + fileName,
- "# " + fileName.split('.md')[0] + " " + '\n'
- );
-
- const createFileModalFolderNameRef: string = (document.querySelector('#create-file-modal-folder-name-input-node') as HTMLElement).textContent as string;
-
- const createFileNode: NodeListOf = document.querySelectorAll('.create-new-file');
-
- createFileNode.forEach((elem) => {
- //null check
- if(elem !== null) {
- elem.classList.remove('is-active-create-new-file-modal');
- }
- });
+ //invoke parent root listener again so the directory tree will be in sync
+ this.directoryTreeListeners.parentRootListener();
- //null check
- if(DirectoryTreeUIModals.createModalContainer !== null) {
- DirectoryTreeUIModals.createModalContainer.remove();
- }
+ //dispose
+ GenericEvent.use.disposeEvent(DirectoryTreeUIModals.createModalExitButton, 'click', this.createModalExitCb, undefined, "Disposed event for create modal exit");
- //log
- console.log(fileName);
-
- //if document contains at least one active child
- if(document.querySelector('.is-active-child')) {
- //select all active children and remove them from the dom (active status)
- //this removes any existing active children files
- document.querySelectorAll('.is-active-child').forEach(
- (isActiveChild) => {
- if(isActiveChild !== null) {
- isActiveChild.classList.remove('is-active-child')
- }
- }
- );
- }
+ GenericEvent.use.disposeEvent(window, 'keydown', KeyBinds.map.bindCb, undefined, "Disposed event for create modal exit (keydown escape)");
- const childFile: HTMLDivElement = document.createElement('div');
- childFile.setAttribute("class", "child-file-name is-active-child");
+ KeyBinds.map.resetMapList();
+ }
- const childFileTextNode: Text = document.createTextNode(fileName.split('.md')[0]);
+ /**
+ * Create file modal exit listener
+ *
+ * @public
+ */
+ public createFileModalExitListener(): void {
+ GenericEvent.use.createDisposableEvent(DirectoryTreeUIModals.createModalExitButton, 'click', this.createModalExitCb, undefined, "Created disposable event for create modal exit");
- document.querySelectorAll('.parent-folder-name').forEach((el) => {
- //this doesn't cover duplicate folder names, so it might cause bugs
- if(el.textContent === createFileModalFolderNameRef) {
- childFile.appendChild(childFileTextNode);
+ KeyBinds.map.bind(this.createModalExitCb, "Escape", false);
+ }
- (el.parentNode as ParentNode).appendChild(childFile);
- }
- })
-
- //execute parent root listener so it understands the new file
- this.directoryTreeListeners.parentRootListener();
+ /**
+ * Create file modal input callback
+ *
+ * @param e Event
+ *
+ * @public
+ */
+ public createFileModalInputCb: (e: Event) => void = (e: Event): void => {
+ //assign current value of input element on keyup + extension
+ this.fileName = ((e.target as HTMLInputElement).value).trim() + ".md";
+
+ //log
+ console.log(this.fileName);
+ }
- //execute child node listener to allow new file to be clicked
- this.directoryTreeListeners.childNodeListener();
+ /**
+ * Create file modal continue callback
+ *
+ * @async
+ * @public
+ */
+ public createFileModalContinueCb: () => Promise = async (): Promise => {
+ if(this.fileName === ".md") {
+ window.electron.ipcRenderer.invoke('show-message-box', "Note name cannot be empty. Enter a valid note name.");
- //execute parent root listener again so everything will be in sync
- this.directoryTreeListeners.parentRootListener();
+ return;
+ }
- //destroy current editor view
- PMEditorView.editorView.destroy();
-
- //create new editor view
- PMEditorView.createEditorView();
+ if(this.fileName !== ".md") {
+ fsMod.fs._createFile(
+ fsMod.fs._baseDir("home")
+ + "/Iris/Notes/"
+ + (document.querySelector('#create-file-modal-folder-name-input-node') as HTMLElement).textContent
+ + "/" + this.fileName,
+ "# " + this.fileName.split('.md')[0] + " " + '\n'
+ );
+ }
- //log
- console.log(createFileModalFolderNameRef);
+ const createFileModalFolderNameRef: string = (document.querySelector('#create-file-modal-folder-name-input-node') as HTMLElement).textContent as string;
+ const createFileNode: NodeListOf = document.querySelectorAll('.create-new-file');
- //log
- console.log(fileName);
-
- //update editor view state
- PMEditorView.editorView.updateState(
- //apply transaction
- PMEditorView.editorView.state.apply(
- //since editor gets destroyed and re-created, the
- //range is 0 to 0
- PMEditorState.editorState.tr.replaceRangeWith(
- 0,
- 0,
- defaultMarkdownParser.parse(
- fsMod.fs._readFileFolder(createFileModalFolderNameRef,
- fileName
- )
- ) as Node
- )));
-
- //set contenteditable
- PMEditorView.setContenteditable(true);
-
- //if contenteditable attribute is set to true
- if((document.querySelector('.ProseMirror') as HTMLElement).getAttribute('contenteditable') === 'true') {
- //show the menubar
- (document.querySelector('.ProseMirror-menubar') as HTMLElement).style.display = "";
- }
+ createFileNode.forEach((elem) => {
+ //null check
+ if(elem !== null) {
+ elem.classList.remove('is-active-create-new-file-modal');
+ }
+ });
- (document.getElementById('kebab-dropdown-menu-container') as HTMLElement).style.display = "";
-
- //invoke auto save listener
- this.editorListeners.autoSaveListener("prosemirror");
-
- //invoke insert tab listener
- this.editorListeners.insertTabListener((document.querySelector('.ProseMirror') as HTMLElement), 2);
-
- //assign references to corresponding key properties
- RefsNs.currentParentChildData.map((props) => {
- //log
- console.log(fileName);
- //log
- console.log(document.querySelector('.child-file-name.is-active-child') as HTMLElement);
-
- //null check
- if(props !== null) {
- //child file name
- props.childFileName = fileName.split('.md')[0];
- props.childFileNode = document.querySelector('.child-file-name.is-active-child') as HTMLElement
+ if(document.querySelector('.is-active-child')) {
+ //select all active children and remove them from the dom (active status)
+ //this removes any existing active children files
+ document.querySelectorAll('.is-active-child').forEach(
+ (isActiveChild) => {
+ if(isActiveChild !== null) {
+ isActiveChild.classList.remove('is-active-child')
}
- });
-
- //apply active state listener
- this.dirTreeStateListeners.activeChildFileStateListener();
+ }
+ );
+ }
- //word count listener
- wordCountListener("prosemirror");
+ //null check
+ if(DirectoryTreeUIModals.createModalContainer !== null) {
+ DirectoryTreeUIModals.createModalContainer.remove();
+ }
- //kebab dropdown menu listener
- this.editorkebabDropdownMenuListeners.kebabDropdownMenuListener();
+ const childFile: HTMLDivElement = document.createElement('div');
+ childFile.setAttribute("class", "child-file-name is-active-child");
- //change document title so it corresponds to the opened file
- await setWindowTitle("Iris", true, createFileModalFolderNameRef + " - " + fileName.split('.md')[0]).catch((e) => { throw console.error(e) });
+ const childFileTextNode: Text = document.createTextNode(this.fileName.split('.md')[0]);
- //add directory info to editor top bar
- this.editorTopBarContainer.directoryInfo();
+ //assign references to corresponding key properties
+ RefsNs.currentParentChildData.map((props) => {
+ //log
+ console.log(this.fileName);
+ //log
+ console.log(document.querySelector('.child-file-name.is-active-child') as HTMLElement);
+
+ //null check
+ if(props !== null) {
+ //child file name
+ props.childFileName = this.fileName.split('.md')[0];
+ props.childFileNode = document.querySelector('.child-file-name.is-active-child') as HTMLElement
+ }
+ });
- (document.getElementById('file-directory-kebab-dropdown-menu-container') as HTMLElement).style.display = "";
+ document.querySelectorAll('.parent-folder-name').forEach((el) => {
+ //this doesn't cover duplicate folder names, so it might cause bugs
+ if(el.textContent === createFileModalFolderNameRef) {
+ childFile.appendChild(childFileTextNode);
- //to-do: sort files...
- } else if(isModeAdvanced() && fileName !== " ") {
- //log
- console.log((document.querySelector('#create-file-modal-folder-name-input-node') as HTMLElement).textContent)
+ (el.parentNode as ParentNode).appendChild(childFile);
+ }
+ })
- fsMod.fs._createFile(
- fsMod.fs._baseDir("home")
- + "/Iris/Notes/"
- + (document.querySelector('#create-file-modal-folder-name-input-node') as HTMLElement).textContent
- + "/" + fileName,
- "# " + fileName.split('.md')[0] + " " + '\n'
- );
-
- const createFileModalFolderNameRef: string = (document.querySelector('#create-file-modal-folder-name-input-node') as HTMLElement).textContent as string;
-
- const createFileNode: NodeListOf = document.querySelectorAll('.create-new-file');
-
- createFileNode.forEach((elem) => {
- //null check
- if(elem !== null) {
- elem.classList.remove('is-active-create-new-file-modal');
- }
- });
+ //execute parent root listener so it understands the new file
+ this.directoryTreeListeners.parentRootListener();
- //null check
- if(DirectoryTreeUIModals.createModalContainer !== null) {
- DirectoryTreeUIModals.createModalContainer.remove();
- }
+ //execute child node listener to allow new file to be clicked
+ this.directoryTreeListeners.childNodeListener();
- //log
- console.log(fileName);
-
- //if document contains at least one active child
- if(document.querySelector('.is-active-child')) {
- //select all active children and remove them from the dom (active status)
- //this removes any existing active children files
- document.querySelectorAll('.is-active-child').forEach(
- (isActiveChild) => {
- if(isActiveChild !== null) {
- isActiveChild.classList.remove('is-active-child')
- }
- }
- );
- }
+ //execute parent root listener again so everything will be in sync
+ this.directoryTreeListeners.parentRootListener();
- const childFile: HTMLDivElement = document.createElement('div');
- childFile.setAttribute("class", "child-file-name is-active-child");
+ //apply active state listener
+ this.dirTreeStateListeners.activeChildFileStateListener();
- const childFileTextNode: Text = document.createTextNode(fileName.split('.md')[0]);
+ //mode check
+ if(isModeBasic()) {
+ //log
+ console.log(this.fileName);
- document.querySelectorAll('.parent-folder-name').forEach((el) => {
- //this doesn't cover duplicate folder names, so it might cause bugs
- if(el.textContent === createFileModalFolderNameRef) {
- childFile.appendChild(childFileTextNode);
+ //destroy current editor view
+ PMEditorView.editorView.destroy();
+
+ //create new editor view
+ PMEditorView.createEditorView();
- (el.parentNode as ParentNode).appendChild(childFile);
- }
- })
+ //log
+ console.log(createFileModalFolderNameRef);
+
+ //log
+ console.log(this.fileName);
+
+ //update editor view state
+ PMEditorView.editorView.updateState(
+ //apply transaction
+ PMEditorView.editorView.state.apply(
+ //since editor gets destroyed and re-created, the
+ //range is 0 to 0
+ PMEditorState.editorState.tr.replaceRangeWith(
+ 0,
+ 0,
+ defaultMarkdownParser.parse(
+ fsMod.fs._readFileFolder(createFileModalFolderNameRef,
+ this.fileName
+ )
+ ) as Node
+ )));
+
+ //set contenteditable
+ PMEditorView.setContenteditable(true);
- //execute parent root listener so it understands the new file
- this.directoryTreeListeners.parentRootListener();
+ //if contenteditable attribute is set to true
+ if((document.querySelector('.ProseMirror') as HTMLElement).getAttribute('contenteditable') === 'true') {
+ //show the menubar
+ (document.querySelector('.ProseMirror-menubar') as HTMLElement).style.display = "";
+ }
- //execute child node listener to allow new file to be clicked
- this.directoryTreeListeners.childNodeListener();
+ (document.getElementById('kebab-dropdown-menu-container') as HTMLElement).style.display = "";
- //execute parent root listener again so everything will be in sync
- this.directoryTreeListeners.parentRootListener();
+ //invoke auto save listener
+ this.editorListeners.autoSaveListener("prosemirror");
- //destroy current editor view
- CMEditorView.editorView.destroy();
-
- //create new editor view
- CMEditorView.createEditorView();
+ //invoke insert tab listener
+ this.editorListeners.insertTabListener((document.querySelector('.ProseMirror') as HTMLElement), 2);
- //log
- console.log(createFileModalFolderNameRef);
+ //word count listener
+ wordCountListener("prosemirror");
- //log
- console.log(fileName);
-
- //dispatch text insertion tr
- CMEditorView.editorView.dispatch({
- changes: {
- from: 0,
- to: 0,
- insert: fsMod.fs._readFileFolder(createFileModalFolderNameRef, fileName)
- }
- })
+ //kebab dropdown menu listener
+ this.editorkebabDropdownMenuListeners.kebabDropdownMenuListener();
+ } else if(isModeAdvanced()) {
+ //log
+ console.log(this.fileName);
- //set contenteditable
- CMEditorView.setContenteditable(true);
+ //destroy current editor view
+ CMEditorView.editorView.destroy();
+
+ //create new editor view
+ CMEditorView.createEditorView();
- //cursor theme
- if(Settings.getSettings.lightTheme) {
- CMEditorView.editorView.dispatch({ effects: CMEditorState.cursorCompartment.reconfigure(cursors[0]) })
- } else if(Settings.getSettings.darkTheme) {
- CMEditorView.editorView.dispatch({ effects: CMEditorState.cursorCompartment.reconfigure(cursors[1]) })
- }
+ //log
+ console.log(createFileModalFolderNameRef);
- //check block cursor
- if(Settings.getSettings.defaultCursor && Settings.getSettings.lightTheme) {
- AdvancedModeSettings.defaultCursor("light");
- } else if(Settings.getSettings.defaultCursor && Settings.getSettings.darkTheme) {
- AdvancedModeSettings.defaultCursor("dark");
- } else if(
- Settings.getSettings.blockCursor && Settings.getSettings.lightTheme
- || Settings.getSettings.blockCursor && Settings.getSettings.darkTheme
- ) {
- AdvancedModeSettings.blockCursor();
+ //log
+ console.log(this.fileName);
+
+ //dispatch text insertion tr
+ CMEditorView.editorView.dispatch({
+ changes: {
+ from: 0,
+ to: 0,
+ insert: fsMod.fs._readFileFolder(createFileModalFolderNameRef, this.fileName)
}
+ })
- (document.getElementById('kebab-dropdown-menu-container') as HTMLElement).style.display = "";
-
- //invoke auto save listener
- this.editorListeners.autoSaveListener("codemirror");
-
- //assign references to corresponding key properties
- RefsNs.currentParentChildData.map((props) => {
- //log
- console.log(fileName);
- //log
- console.log(document.querySelector('.child-file-name.is-active-child') as HTMLElement);
-
- //null check
- if(props !== null) {
- //child file name
- props.childFileName = fileName.split('.md')[0];
- props.childFileNode = document.querySelector('.child-file-name.is-active-child') as HTMLElement
- }
- });
-
- //apply active state listener
- this.dirTreeStateListeners.activeChildFileStateListener();
+ //set contenteditable
+ CMEditorView.setContenteditable(true);
- //word count listener
- wordCountListener("codemirror");
+ //cursor theme
+ if(Settings.getSettings.lightTheme) {
+ CMEditorView.editorView.dispatch({ effects: CMEditorState.cursorCompartment.reconfigure(cursors[0]) })
+ } else if(Settings.getSettings.darkTheme) {
+ CMEditorView.editorView.dispatch({ effects: CMEditorState.cursorCompartment.reconfigure(cursors[1]) })
+ }
- //kebab dropdown menu listener
- this.editorkebabDropdownMenuListeners.kebabDropdownMenuListener();
+ //check block cursor
+ if(Settings.getSettings.defaultCursor && Settings.getSettings.lightTheme) {
+ AdvancedModeSettings.defaultCursor("light");
+ } else if(Settings.getSettings.defaultCursor && Settings.getSettings.darkTheme) {
+ AdvancedModeSettings.defaultCursor("dark");
+ } else if(Settings.getSettings.blockCursor && Settings.getSettings.lightTheme || Settings.getSettings.blockCursor && Settings.getSettings.darkTheme) {
+ AdvancedModeSettings.blockCursor();
+ }
- //change document title so it corresponds to the opened file
- await setWindowTitle("Iris", true, createFileModalFolderNameRef + " - " + fileName.split('.md')[0]).catch((e) => { throw console.error(e) });
+ (document.getElementById('kebab-dropdown-menu-container') as HTMLElement).style.display = "";
- //add directory info to editor top bar
- this.editorTopBarContainer.directoryInfo();
+ //invoke auto save listener
+ this.editorListeners.autoSaveListener("codemirror");
- (document.getElementById('file-directory-kebab-dropdown-menu-container') as HTMLElement).style.display = "";
- } else if(isModeReading() && fileName !== " ") {
- fsMod.fs._createFile(
- fsMod.fs._baseDir("home")
- + "/Iris/Notes/"
- + (document.querySelector('#create-file-modal-folder-name-input-node') as HTMLElement).textContent
- + "/" + fileName,
- "# " + fileName.split('.md')[0] + " " + '\n'
- );
+ //word count listener
+ wordCountListener("codemirror");
- const createFileModalFolderNameRef: string = (document.querySelector('#create-file-modal-folder-name-input-node') as HTMLElement).textContent as string;
- const createFileNode: NodeListOf = document.querySelectorAll('.create-new-file');
+ //kebab dropdown menu listener
+ this.editorkebabDropdownMenuListeners.kebabDropdownMenuListener();
+ } else if(isModeReading()) {
+ //remove reading mode container if present in DOM
+ if((document.getElementById('reading-mode-container') as HTMLElement) !== null) {
+ (document.getElementById('reading-mode-container') as HTMLElement).remove();
+ }
- createFileNode.forEach((elem) => {
- //null check
- if(elem !== null) {
- elem.classList.remove('is-active-create-new-file-modal');
- }
- });
+ //create reading mode node
+ ReadingMode.readingModeNode();
- //null check
- if(DirectoryTreeUIModals.createModalContainer !== null) {
- DirectoryTreeUIModals.createModalContainer.remove();
- }
+ //create fragment and append
+ const content: string = await markdownParser(fsMod.fs._readFileFolder(createFileModalFolderNameRef, this.fileName)).catch((e) => { throw console.error(e) });
+ const contextFragment = new Range().createContextualFragment(content);
+ (document.getElementById('reading-mode-content') as HTMLElement).appendChild(contextFragment);
+ }
- //if document contains at least one active child
- if(document.querySelector('.is-active-child')) {
- //select all active children and remove them from the dom (active status)
- //this removes any existing active children files
- document.querySelectorAll('.is-active-child').forEach(
- (isActiveChild) => {
- if(isActiveChild !== null) {
- isActiveChild.classList.remove('is-active-child')
- }
- }
- );
- }
+ //change document title so it corresponds to the opened file
+ await setWindowTitle("Iris", true, createFileModalFolderNameRef + " - " + this.fileName.split('.md')[0]).catch((e) => { throw console.error(e) });
- const childFile: HTMLDivElement = document.createElement('div');
- childFile.setAttribute("class", "child-file-name is-active-child");
+ //add directory info to editor top bar
+ this.editorTopBarContainer.directoryInfo();
- const childFileTextNode: Text = document.createTextNode(fileName.split('.md')[0]);
+ (document.getElementById('file-directory-kebab-dropdown-menu-container') as HTMLElement).style.display = "";
- document.querySelectorAll('.parent-folder-name').forEach((el) => {
- //this doesn't cover duplicate folder names, so it might cause bugs
- if(el.textContent === createFileModalFolderNameRef) {
- childFile.appendChild(childFileTextNode);
+ //dispose
+ GenericEvent.use.disposeEvent(DirectoryTreeUIModals.createModalContinueButton, 'click', this.createFileModalContinueCb, undefined, "Disposed create file modal continue event");
- (el.parentNode as ParentNode).appendChild(childFile);
- }
- })
-
- //assign references to corresponding key properties
- RefsNs.currentParentChildData.map((props) => {
- //log
- console.log(fileName);
- //log
- console.log(document.querySelector('.child-file-name.is-active-child') as HTMLElement);
-
- //null check
- if(props !== null) {
- //child file name
- props.childFileName = fileName.split('.md')[0];
- props.childFileNode = document.querySelector('.child-file-name.is-active-child') as HTMLElement
- }
- });
-
- //apply active state listener
- this.dirTreeStateListeners.activeChildFileStateListener();
-
- //change document title so it corresponds to the opened file
- await setWindowTitle("Iris", true, createFileModalFolderNameRef + " - " + fileName.split('.md')[0]).catch((e) => { throw console.error(e) });
-
- //add directory info to editor top bar
- this.editorTopBarContainer.directoryInfo();
-
- (document.getElementById('file-directory-kebab-dropdown-menu-container') as HTMLElement).style.display = "";
-
- //remove reading mode container if present in DOM
- if((document.getElementById('reading-mode-container') as HTMLElement) !== null) {
- (document.getElementById('reading-mode-container') as HTMLElement).remove();
- }
+ GenericEvent.use.disposeEvent(window, 'keydown', KeyBinds.map.bindCb, undefined, "Disposed event for bind (keydown enter)");
+ }
- //create reading mode node
- ReadingMode.readingModeNode();
+ /**
+ * Create file modal continue listener
+ *
+ * @param el Element to attach `keyup` event listener to
+ */
+ public createFileModalContinueListener(el: HTMLElement): void {
+ GenericEvent.use.createDisposableEvent(el, 'keyup', this.createFileModalInputCb, undefined, "Created disposable event for create file modal input");
- //create fragment and append
- const content: string = await markdownParser(fsMod.fs._readFileFolder(createFileModalFolderNameRef, fileName)).catch((e) => { throw console.error(e) });
- const contextFragment = new Range().createContextualFragment(content);
- (document.getElementById('reading-mode-content') as HTMLElement).appendChild(contextFragment);
+ GenericEvent.use.createDisposableEvent(DirectoryTreeUIModals.createModalContinueButton, 'click', this.createFileModalContinueCb, undefined, "Created disposable event for create file modal continue");
- //listeners
- this.directoryTreeListeners.parentRootListener();
- this.directoryTreeListeners.childNodeListener();
- }
- })
+ KeyBinds.map.bind(this.createFileModalContinueCb, "Enter", false);
}
-
+
/**
* Create file listener
*/
@@ -537,20 +417,16 @@ export class DirectoryTreeUIModalListeners extends DirectoryTreeUIModals impleme
this.parentTags = document.querySelectorAll('.parent-of-root-folder');
this.parentNameTags = document.querySelectorAll('.parent-folder-name');
-
+
+ //clean this up
for(let i = 0; i < this.parentNameTags.length; i++) {
- //when a parent name tag is clicked
- this.parentNameTags[i].addEventListener('click', () => {
+ GenericEvent.use.createDisposableEvent(this.parentNameTags[i], 'click', () => {
//check if parent tag contains is-active-parent class
if(this.parentTags[i].classList.contains('is-active-parent')) {
//toggle show-create-file class on create-new-file node
createFileNode[i].classList.toggle('show-create-file');
- //when a create-new-file node is clicked
- createFileNode[i].addEventListener('click', (e) => {
- //need stopImmediatePropagation so parentNameTag listener doesn't conflict with the createFileNode listener
- e.stopImmediatePropagation();
-
+ GenericEvent.use.createDisposableEvent(createFileNode[i], 'click', () => {
if(createFileNode[i].classList.contains('show-create-file')) {
//invoke create file modal
this.createFileModal();
@@ -568,11 +444,6 @@ export class DirectoryTreeUIModalListeners extends DirectoryTreeUIModals impleme
//invoke createFileModalCurrentFolderNode
this.createFileModalCurrentFolderNode(props.parentFolderName);
-
- //log
- //console.log(props.parentFolderName);
- //log
- //console.log(props.parentFolderNode);
}
});
@@ -589,155 +460,187 @@ export class DirectoryTreeUIModalListeners extends DirectoryTreeUIModals impleme
} else if(!createFileNode[i].classList.contains('show-create-file')) {
createFileNode[i].classList.remove('show-create-file');
}
- });
+ })
} else if(!this.parentTags[i].classList.contains('is-active-parent')) {
createFileNode[i].classList.remove('show-create-file');
}
- });
+ })
}
}
-
+
/**
- * Create folder continue listener
+ * Create folder input callback
*
- * @param el Element to attach the `keyup` event listener to
+ * @param e Event
+ * @public
*/
- public createFolderContinueListener(el: HTMLElement): void {
- let folderName: string = "";
-
- el.addEventListener('keyup', (e) => {
- folderName = ((e.target as HTMLInputElement).value).trim();
- console.log(folderName);
- });
-
- //console.log(folderName);
+ public createFolderInputCb: (e: Event) => void = (e: Event): void => {
+ this.folderName = ((e.target as HTMLInputElement).value).trim();
+ console.log(this.folderName);
+ }
+ /**
+ * Create folder modal continue callback
+ *
+ * @public
+ */
+ public createFolderModalContinueCb: () => void = (): void => {
let parentFolder: HTMLDivElement = {} as HTMLDivElement;
-
- DirectoryTreeUIModals.createModalContinueButton.addEventListener('click', () => {
- //log
- console.log(folderName);
+
+ if(this.folderName === "" || this.folderName === " ") {
+ window.electron.ipcRenderer.invoke('show-message-box', "Folder name cannot be empty. Enter a valid folder name.")
- if(folderName === "") {
- window.electron.ipcRenderer.invoke('error-dialog', "Iris", "Folder name cannot be empty. Enter a valid folder name.");
+ return;
+ } else if(this.folderName !== "" || this.folderName !== " " as string) {
+ //create directory
+ fsMod.fs._createDir(
+ fsMod.fs._baseDir("home")
+ + "/Iris/Notes/"
+ + this.folderName
+ );
+ }
+
+ parentFolder = document.createElement('div');
+ parentFolder.setAttribute("class", "parent-of-root-folder is-not-active-parent");
+ (document.getElementById('file-directory-tree-container-inner') as HTMLElement).appendChild(parentFolder);
- return;
- } else if(folderName !== " ") {
- //create directory
- fsMod.fs._createDir(
- fsMod.fs._baseDir("home")
- + "/Iris/Notes/"
- + folderName
- );
- }
+ const parentFolderName: HTMLDivElement = document.createElement('div');
+ parentFolderName.setAttribute("class", "parent-folder-name");
+ parentFolder.appendChild(parentFolderName);
+
+ const parentFolderTextNode: Text = document.createTextNode(this.folderName);
+ parentFolderName.appendChild(parentFolderTextNode);
+
+ const parentFolderCaret: HTMLDivElement = document.createElement('div');
+ parentFolderCaret.setAttribute("class", "parent-folder-caret");
+
+ const parentFolderCaretTextNode: Text = document.createTextNode(String.fromCharCode(94));
+ parentFolderCaret.appendChild(parentFolderCaretTextNode);
+ parentFolder.appendChild(parentFolderCaret);
+
+ const parentRoot: NodeListOf = document.querySelectorAll('.parent-of-root-folder');
+
+ for(let i = 0; i < parentRoot.length; i++) {
+ //invoke folder file count
+ this.folderFileCountObject.folderFileCount(parentRoot[i], this.directoryTreeListeners.parentNameTagsArr()[i], true);
+ }
- parentFolder = document.createElement('div');
- parentFolder.setAttribute("class", "parent-of-root-folder is-not-active-parent");
- (document.getElementById('file-directory-tree-container-inner') as HTMLElement).appendChild(parentFolder);
-
- const parentFolderName: HTMLDivElement = document.createElement('div');
- parentFolderName.setAttribute("class", "parent-folder-name");
- parentFolder.appendChild(parentFolderName);
-
- const parentFolderTextNode: Text = document.createTextNode(folderName);
- parentFolderName.appendChild(parentFolderTextNode);
-
- const parentFolderCaret: HTMLDivElement = document.createElement('div');
- parentFolderCaret.setAttribute("class", "parent-folder-caret");
+ //invoke parent root listener (created directory only)
+ this.directoryTreeListeners.parentRootListener();
+
+ //invoke create file node
+ //bug
+ this.createFileNode(parentFolder);
+ this.createFileNode(parentFolder);
+
+ //invoke create file listener
+ this.createFileListener();
+
+ //null check
+ if(DirectoryTreeUIModals.createModalContainer !== null) {
+ DirectoryTreeUIModals.createModalContainer.remove();
+ }
- const parentFolderCaretTextNode: Text = document.createTextNode(String.fromCharCode(94));
- parentFolderCaret.appendChild(parentFolderCaretTextNode);
- parentFolder.appendChild(parentFolderCaret);
+ //invoke parent root listener again so entire directory tree will function normally and be in sync
+ //bug
+ this.directoryTreeListeners.parentRootListener();
+ this.directoryTreeListeners.parentRootListener();
- const parentRoot: NodeListOf = document.querySelectorAll('.parent-of-root-folder');
+ //dispose create file modal continue cb
+ GenericEvent.use.disposeEvent(DirectoryTreeUIModals.createModalContinueButton, 'click', this.createFileModalContinueCb, undefined, "Disposed event for create file modal continue")
- for(let i = 0; i < parentRoot.length; i++) {
- //invoke folder file count
- this.folderFileCountObject.folderFileCount(parentRoot[i], this.directoryTreeListeners.parentNameTagsArr()[i], true);
- }
+ //dispose bind cb
+ GenericEvent.use.disposeEvent(window, 'keydown', KeyBinds.map.bindCb, undefined, "Disposed event for bind (keydown enter)");
+
+ //dispose create folder input cb
+ GenericEvent.use.disposeEvent(document.body, 'keyup', this.createFolderInputCb, undefined, "Disposed event for create folder input");
+ }
- //invoke parent root listener (created directory only)
+ /**
+ * Create folder continue listener
+ *
+ * @param el Element to attach the `keyup` event listener to
+ */
+ public createFolderContinueListener(el: HTMLElement): void {
+ GenericEvent.use.createDisposableEvent(el, 'keyup', this.createFolderInputCb, undefined, "Created disposable event for create folder input")
+
+ GenericEvent.use.createDisposableEvent(DirectoryTreeUIModals.createModalContinueButton, 'click', this.createFolderModalContinueCb, undefined, "Created event for create folder modal continue")
+
+ KeyBinds.map.bind(this.createFolderModalContinueCb, "Enter", false);
+ }
+
+ /**
+ * Create folder modal exit callback
+ * @public
+ */
+ public createFolderModalExitCb: () => void = (): void => {
+ if((document.getElementById('create-modal-container') as HTMLElement) !== null) {
+ (document.getElementById('create-modal-container') as HTMLElement).remove();
+ }
+
+ if(isModeBasic() || isModeAdvanced() || isModeReading()) {
this.directoryTreeListeners.parentRootListener();
+ this.createFileListener();
+ }
+
+ GenericEvent.use.setEventCallbackTimeout(() => {
+ //dispose create folder modal exit cb
+ GenericEvent.use.disposeEvent(DirectoryTreeUIModals.createModalExitButton, 'click', this.createFolderModalExitCb, undefined, "Disposed event for create folder modal exit (click)");
- //invoke create file node
- this.createFileNode(parentFolder);
+ //dispose bind cb
+ GenericEvent.use.disposeEvent(window, 'keydown', KeyBinds.map.bindCb, undefined, "Disposed event for bind (keydown escape)");
- //invoke create file listener
- this.createFileListener();
+ //dispose create folder input cb
+ GenericEvent.use.disposeEvent(document.body, 'keyup', this.createFolderInputCb, undefined, "Disposed event for create folder input");
- //null check
- if(DirectoryTreeUIModals.createModalContainer !== null) {
- DirectoryTreeUIModals.createModalContainer.remove();
- }
-
- //invoke create file listener
- //bug
- this.createFileListener();
- this.createFileListener();
-
- //invoke parent root listener again so entire directory tree will function normally and be in sync
- //bug
- this.directoryTreeListeners.parentRootListener();
- this.directoryTreeListeners.parentRootListener();
- })
+ }, 150)
+
+ KeyBinds.map.resetMapList();
}
/**
* Create folder modal exit listener
*/
- public createFolderModalExitListener(): void {
- DirectoryTreeUIModals.createModalExitButton.addEventListener('click', () => {
- //log
- console.log("Clicked on exit button");
+ public createFolderModalExitListener(): void {
+ GenericEvent.use.createDisposableEvent(DirectoryTreeUIModals.createModalExitButton, 'click', this.createFolderModalExitCb, undefined, "Created event for create folder modal exit (click)");
- if((document.getElementById('create-modal-container') as HTMLElement) !== null) {
- (document.getElementById('create-modal-container') as HTMLElement).remove();
- }
+ KeyBinds.map.bind(this.createFolderModalExitCb, "Escape", false);
+ }
+
+ /**
+ * Create folder callback
+ *
+ * @public
+ */
+ public createFolderCb: () => void = (): void => {
+ GenericEvent.use.setEventCallbackTimeout(
+ () => {
+ //log
+ console.log("clicked create folder");
+
+ //invoke create folder modal
+ this.createFolderModal();
+
+ //invoke create modal exit listener
+ this.createFolderModalExitListener();
+
+ //mode check
+ if(isModeBasic() || isModeAdvanced() || isModeReading()) {
+ //invoke create folder continue listener
+ this.createFolderContinueListener((document.getElementById('create-folder-input-node') as HTMLElement));
+ }
+
+ //dispose create folder cb
+ GenericEvent.use.disposeEvent((document.getElementById('create-folder') as HTMLElement), 'click', () => GenericEvent.use.setEventCallbackTimeout(this.createFolderCb, 50), undefined, "Disposed event for create folder (click)");
+ }, 50
+ )
- //mode check
- if(isModeBasic()) {
- this.directoryTreeListeners.parentRootListener();
-
- this.createFileListener();
- } else if(isModeAdvanced()) {
- this.directoryTreeListeners.parentRootListener();
-
- this.createFileListener();
- } else if(isModeReading()) {
- this.directoryTreeListeners.parentRootListener();
- //invoke again (bug)
- this.directoryTreeListeners.parentRootListener();
-
- this.createFileListener();
- }
- })
}
/**
* Create folder listener
*/
public createFolderListener(): void {
- (document.getElementById('create-folder') as HTMLElement).addEventListener('click', (e) => {
- e.stopImmediatePropagation();
-
- //log
- console.log("clicked create folder");
-
- //invoke create folder modal
- this.createFolderModal();
-
- //invoke create modal exit listener
- this.createFolderModalExitListener();
-
- //mode check
- if(isModeBasic()) {
- //invoke create folder continue listener
- this.createFolderContinueListener((document.getElementById('create-folder-input-node') as HTMLElement));
- } else if(isModeAdvanced()) {
- this.createFolderContinueListener((document.getElementById('create-folder-input-node') as HTMLElement));
- } else if(isModeReading()) {
- this.createFolderContinueListener((document.getElementById('create-folder-input-node') as HTMLElement));
- }
- })
+ GenericEvent.use.createDisposableEvent((document.getElementById('create-folder') as HTMLElement), 'click', () => GenericEvent.use.setEventCallbackTimeout(this.createFolderCb, 50), undefined, "Created event for create folder (click)");
}
}
diff --git a/src/renderer/src/event-listeners/event.ts b/src/renderer/src/event-listeners/event.ts
index 951d29d..f2498e3 100644
--- a/src/renderer/src/event-listeners/event.ts
+++ b/src/renderer/src/event-listeners/event.ts
@@ -1,5 +1,5 @@
interface IEvent<
- T extends HTMLElement,
+ T extends HTMLElement | Window & typeof globalThis | Element,
Z extends string,
K extends any | unknown,
X extends boolean | undefined,
@@ -9,13 +9,15 @@ interface IEvent<
disposeEvent(el: T, type: Z, fn: (...args: K[]) => K, capture?: X, log?: Y): void;
}
+type TEvent = IEvent
+
export namespace GenericEvent {
/**
* Don't export
*
* @internal
*/
- class Event implements IEvent {
+ class Event implements TEvent {
/**
* Create dispoable event listener
*
@@ -25,7 +27,7 @@ export namespace GenericEvent {
* @param useCapture - Optional - Default value is `false`. If `true`, it specifies that the event listener being removed is a capturing listener
* @param log - Optional - Print a message to console
*/
- public createDisposableEvent(el: HTMLElement, type: string, listener: (...args: any[]) => any | unknown, useCapture?: boolean | undefined, log?: string | undefined): void {
+ public createDisposableEvent(el: HTMLElement | Window & typeof globalThis | Element, type: string, listener: (...args: any[]) => any | unknown, useCapture?: boolean | undefined, log?: string | undefined): void {
if(typeof listener === 'function') {
el.addEventListener(type, listener, useCapture);
}
@@ -46,7 +48,7 @@ export namespace GenericEvent {
* @param capture Optional - Default value is `false`. If `true`, it specifies that the event listener being removed is a capturing listener
* @param log Optional - Print a message to console
*/
- public disposeEvent(el: HTMLElement, type: string, fn: (...args: any[]) => any | unknown, capture?: boolean | undefined, log?: string | undefined): void {
+ public disposeEvent(el: HTMLElement | Window & typeof globalThis | Element, type: string, fn: (...args: any[]) => any | unknown, capture?: boolean | undefined, log?: string | undefined): void {
if(typeof fn === 'function') {
el.removeEventListener(type, fn, capture);
}
@@ -57,6 +59,18 @@ export namespace GenericEvent {
return;
}
}
+
+
+ /**
+ * Set event callback timeout
+ *
+ * @param fn Reference callback function to execute after `ms`
+ * @param ms Number to wait until reference function gets executed
+ * @returns Timeout to be executed in event
+ */
+ public setEventCallbackTimeout(fn: () => any | void, ms: number | undefined): NodeJS.Timeout {
+ return setTimeout(fn, ms);
+ }
}
/**
diff --git a/src/renderer/src/event-listeners/file-directory-state-listener.ts b/src/renderer/src/event-listeners/file-directory-state-listener.ts
index 7fac3f9..e4e56c6 100644
--- a/src/renderer/src/event-listeners/file-directory-state-listener.ts
+++ b/src/renderer/src/event-listeners/file-directory-state-listener.ts
@@ -1,6 +1,33 @@
import { RefsNs } from "./directory-tree-listeners"
+import { GenericEvent } from "./event"
export class DirectoryTreeStateListeners {
+ public el: Element = {} as Element;
+
+ public activeChildFileStateCb: () => void = (): void => {
+ //doc title folder name
+ //trim any whitespace from the split if necessary
+ const docTitleFolderName: string = document.title.split('-')[1].trim();
+
+ const childFileName: Element[] | null = Array.from(document.getElementsByClassName('child-file-name'));
+
+ //null check
+ if(childFileName !== null) {
+ for(let i = 0; i < childFileName.length; i++) {
+ //check if docTitleFolderName and docTitleFileName match the respective refs
+ if(docTitleFolderName === RefsNs.currentParentChildData[0].parentFolderName && childFileName[i].textContent === RefsNs.currentParentChildData[0].childFileName) {
+ //compare text content to make sure it's identical
+ if(childFileName[i].textContent === RefsNs.currentParentChildData[0].childFileName) {
+ //add is-active-child class to the child file
+ childFileName[i].classList.add('is-active-child');
+ } else {
+ continue;
+ }
+ }
+ }
+ }
+ }
+
/**
* Active child file state listener
*/
@@ -8,30 +35,13 @@ export class DirectoryTreeStateListeners {
document.querySelectorAll('.parent-folder-name').forEach((el) => {
//null check
if(el !== null) {
- el.addEventListener('click', () => {
- //doc title folder name
- //trim any whitespace from the split if necessary
- const docTitleFolderName: string = document.title.split('-')[1].trim();
-
- const childFileName: Element[] | null = Array.from(document.getElementsByClassName('child-file-name'));
-
- //null check
- if(childFileName !== null) {
- for(let i = 0; i < childFileName.length; i++) {
- //check if docTitleFolderName and docTitleFileName match the respective refs
- if(docTitleFolderName === RefsNs.currentParentChildData[0].parentFolderName && childFileName[i].textContent === RefsNs.currentParentChildData[0].childFileName) {
- console.log(RefsNs.currentParentChildData[0].childFileNode.textContent);
- //compare text content to make sure it's identical
- if(childFileName[i].textContent === RefsNs.currentParentChildData[0].childFileName) {
- //add is-active-child class to the child file
- childFileName[i].classList.add('is-active-child');
- } else {
- continue;
- }
- }
- }
- }
- });
+ this.el = el;
+
+ console.log(this.el);
+
+ GenericEvent.use.createDisposableEvent(this.el, 'click', () => GenericEvent.use.setEventCallbackTimeout(this.activeChildFileStateCb, 20), undefined, "Create disposable event for active child file state (click)");
+
+ return;
}
});
}
diff --git a/src/renderer/src/event-listeners/kebab-dropdown-menu-listener.ts b/src/renderer/src/event-listeners/kebab-dropdown-menu-listener.ts
index 67945b3..3f2ac5a 100644
--- a/src/renderer/src/event-listeners/kebab-dropdown-menu-listener.ts
+++ b/src/renderer/src/event-listeners/kebab-dropdown-menu-listener.ts
@@ -9,6 +9,7 @@ import { CMEditorView } from "../codemirror/editor/cm-editor-view"
import { FolderFileCount } from "../misc-ui/folder-file-count"
import { DirectoryTree } from "../file-directory-tree/file-directory"
import { GenericEvent } from "./event"
+import { KeyBinds } from "../keybinds/keybinds"
/**
* @extends EditorKebabDropdownModals
@@ -17,11 +18,16 @@ export class EditorKebabDropdownMenuListeners extends EditorKebabDropdownModals
private readonly folderFileCount = new FolderFileCount();
private readonly directoryTree = new DirectoryTree();
+ private renameFile: string = "";
public kebabModalContainerCb: () => void = (): void => {
EditorKebabDropdownModals.kebabModalContainerNode.remove();
GenericEvent.use.disposeEvent(EditorKebabDropdownModals.kebabModalExitButtonNode, 'click', this.kebabModalContainerCb, undefined, "Disposed kebab modal container event")
+
+ GenericEvent.use.disposeEvent(window, "keydown", this.kebabModalContainerCb, undefined, "Disposed event for kebab modal container (keydown escape)");
+
+ KeyBinds.map.resetMapList();
}
/**
@@ -29,218 +35,254 @@ export class EditorKebabDropdownMenuListeners extends EditorKebabDropdownModals
*/
public kebabExitModalListener(): void {
GenericEvent.use.createDisposableEvent(EditorKebabDropdownModals.kebabModalExitButtonNode, 'click', this.kebabModalContainerCb, undefined, "Created disposable event for kebab modal container event")
+
+ KeyBinds.map.bind(this.kebabModalContainerCb, "Escape", false);
}
/**
- * Kebab delete file continue modal listener
+ * Kebab delete file continue callback
+ *
+ * @public
*/
- public kebabDeleteFileContinueModalListener(): void {
- EditorKebabDropdownModals.kebabModalContinueButtonNode.addEventListener('click', () => {
- document.querySelectorAll('.child-file-name.is-active-child').forEach(async (el) => {
- //mode check
- if(isModeBasic()) {
- //log
- console.log(
- fsMod.fs._baseDir("home")
- + "/Iris/Notes/"
- + document.title.split('-')[1].trim()
- + "/"
- + el.textContent + ".md"
- );
-
- fsMod.fs._deletePath(
- fsMod.fs._baseDir("home")
- + "/Iris/Notes/"
- + document.title.split('-')[1].trim()
- + "/"
- + el.textContent + ".md"
- );
-
- //destroy editor and respawn
- PMEditorView.editorView.destroy();
- PMEditorView.createEditorView();
- PMEditorView.setContenteditable(false);
-
- //hide prosemirror menubar
- (document.querySelector('.ProseMirror-menubar') as HTMLElement).style.display = "none";
+ public kebabDeleteFileContinueCb: () => void = (): void => {
+ document.querySelectorAll('.child-file-name.is-active-child').forEach(async (el) => {
+ //mode check
+ if(isModeBasic()) {
+ //log
+ console.log(
+ fsMod.fs._baseDir("home")
+ + "/Iris/Notes/"
+ + document.title.split('-')[1].trim()
+ + "/"
+ + el.textContent + ".md"
+ );
+
+ fsMod.fs._deletePath(
+ fsMod.fs._baseDir("home")
+ + "/Iris/Notes/"
+ + document.title.split('-')[1].trim()
+ + "/"
+ + el.textContent + ".md"
+ );
+
+ //destroy editor and respawn
+ PMEditorView.editorView.destroy();
+ PMEditorView.createEditorView();
+ PMEditorView.setContenteditable(false);
+
+ //hide prosemirror menubar
+ (document.querySelector('.ProseMirror-menubar') as HTMLElement).style.display = "none";
+
+ const parentRoot: NodeListOf = document.querySelectorAll('.parent-of-root-folder');
+ const parentNameTags: NodeListOf = document.querySelectorAll('.parent-folder-name');
- const parentRoot: NodeListOf = document.querySelectorAll('.parent-of-root-folder');
- const parentNameTags: NodeListOf = document.querySelectorAll('.parent-folder-name');
-
- let count: number = 0;
- //remove duplicate folder file count nodes
- while(count <= 2) {
- document.querySelectorAll('.folder-file-count-container').forEach((el) => {
- el.remove();
- });
- count++;
- }
-
- for(let i = 0; i < parentNameTags.length; i++) {
- //invoke folder file count
- this.folderFileCount.folderFileCount(parentRoot[i], this.directoryTree.parentNameTagsArr()[i], true);
- }
-
- //hide file directory kebab dropdown menu container
- (document.getElementById('file-directory-kebab-dropdown-menu-container') as HTMLElement).style.display = "none";
- } else if(isModeAdvanced()) {
- fsMod.fs._deletePath(
- fsMod.fs._baseDir("home")
- + "/Iris/Notes/"
- + document.title.split('-')[1].trim()
- + "/"
- + el.textContent + ".md"
- );
+ let count: number = 0;
+ //remove duplicate folder file count nodes
+ while(count <= 2) {
+ document.querySelectorAll('.folder-file-count-container').forEach((el) => {
+ el.remove();
+ });
+ count++;
+ }
+
+ for(let i = 0; i < parentNameTags.length; i++) {
+ //invoke folder file count
+ this.folderFileCount.folderFileCount(parentRoot[i], this.directoryTree.parentNameTagsArr()[i], true);
+ }
+
+ //hide file directory kebab dropdown menu container
+ (document.getElementById('file-directory-kebab-dropdown-menu-container') as HTMLElement).style.display = "none";
+ } else if(isModeAdvanced()) {
+ fsMod.fs._deletePath(
+ fsMod.fs._baseDir("home")
+ + "/Iris/Notes/"
+ + document.title.split('-')[1].trim()
+ + "/"
+ + el.textContent + ".md"
+ );
+
+ CMEditorView.editorView.destroy();
+ CMEditorView.createEditorView();
+ CMEditorView.setContenteditable(false);
+
+ const parentRoot: NodeListOf = document.querySelectorAll('.parent-of-root-folder');
+ const parentNameTags: NodeListOf = document.querySelectorAll('.parent-folder-name');
- CMEditorView.editorView.destroy();
- CMEditorView.createEditorView();
- CMEditorView.setContenteditable(false);
-
- const parentRoot: NodeListOf = document.querySelectorAll('.parent-of-root-folder');
- const parentNameTags: NodeListOf = document.querySelectorAll('.parent-folder-name');
-
- let count: number = 0;
- //remove duplicate folder file count nodes
- while(count <= 2) {
- document.querySelectorAll('.folder-file-count-container').forEach((el) => {
- el.remove();
- });
- count++;
- }
-
- for(let i = 0; i < parentNameTags.length; i++) {
- //invoke folder file count
- this.folderFileCount.folderFileCount(parentRoot[i], this.directoryTree.parentNameTagsArr()[i], true);
- }
+ let count: number = 0;
+ //remove duplicate folder file count nodes
+ while(count <= 2) {
+ document.querySelectorAll('.folder-file-count-container').forEach((el) => {
+ el.remove();
+ });
+ count++;
+ }
+
+ for(let i = 0; i < parentNameTags.length; i++) {
+ //invoke folder file count
+ this.folderFileCount.folderFileCount(parentRoot[i], this.directoryTree.parentNameTagsArr()[i], true);
}
+ }
+
+ //remove kebab modal container node
+ EditorKebabDropdownModals.kebabModalContainerNode.remove();
+
+ //remove active file from tree
+ el.remove();
+
+ //hide kebab dropdown menu container
+ (document.getElementById('kebab-dropdown-menu-container') as HTMLElement).style.display = "none";
+
+ //kebab after click menu container
+ (document.getElementById('kebab-after-click-menu-container') as HTMLElement).style.display = "none";
+ (document.getElementById('kebab-after-click-menu-container') as HTMLElement).classList.remove('is-active');
+
+ //word counter
+ (document.getElementById('word-count-container') as HTMLElement).style.display = "none";
- //remove kebab modal container node
- EditorKebabDropdownModals.kebabModalContainerNode.remove();
+ //set window title to default
+ await setWindowTitle("Iris", false, null);
- //remove active file from tree
- el.remove();
+ //remove top bar directory info node
+ (document.getElementById('top-bar-directory-info') as HTMLElement).remove();
- //hide kebab dropdown menu container
- (document.getElementById('kebab-dropdown-menu-container') as HTMLElement).style.display = "none";
+ (document.getElementById('file-directory-kebab-dropdown-menu-container') as HTMLElement).style.display = "none";
+ })
- //kebab after click menu container
- (document.getElementById('kebab-after-click-menu-container') as HTMLElement).style.display = "none";
- (document.getElementById('kebab-after-click-menu-container') as HTMLElement).classList.remove('is-active');
+ GenericEvent.use.disposeEvent(window, 'keydown', KeyBinds.map.bindCb, undefined, "Disposed event for kebab delete file continue (keydown enter)");
+ }
- //word counter
- (document.getElementById('word-count-container') as HTMLElement).style.display = "none";
-
- //set window title to default
- await setWindowTitle("Iris", false, null);
+ /**
+ * Kebab delete file continue modal listener
+ */
+ public kebabDeleteFileContinueModalListener(): void {
+ GenericEvent.use.createDisposableEvent(EditorKebabDropdownModals.kebabModalContinueButtonNode, 'click', this.kebabDeleteFileContinueCb, undefined, "Created event for kebab modal continue button (click)");
- //remove top bar directory info node
- (document.getElementById('top-bar-directory-info') as HTMLElement).remove();
+ KeyBinds.map.bind(this.kebabDeleteFileContinueCb, "Enter", false);
+ }
- (document.getElementById('file-directory-kebab-dropdown-menu-container') as HTMLElement).style.display = "none";
- })
+ public kebabDropdownDeleteFileCb: () => void = (): void => {
+ //log
+ console.log("clicked kebab delete");
+
+ document.querySelectorAll('#kebab-modal-container-node').forEach((el) => {
+ //null check
+ if(el !== null) {
+ //remove any remaining kebab modal container nodes
+ el.remove();
+ }
+
+ GenericEvent.use.disposeEvent((document.getElementById('kebab-delete-file-button-node') as HTMLElement), 'click', this.kebabDropdownDeleteFileCb, undefined, "Disposed event for kebab dropdown delete file (click)")
})
+
+ //create kebab modal container
+ this.kebabModalDeleteFileContainer();
+
+ //invoke kebab delete file exit modal listener
+ this.kebabExitModalListener();
+
+ //invoke kebab delete file continue modal listener
+ this.kebabDeleteFileContinueModalListener();
}
/**
* Kebab dropdown delete file listener
*/
public kebabDropdownDeleteFileListener(): void {
- (document.getElementById('kebab-delete-file-button-node') as HTMLElement).addEventListener('click', () => {
+ GenericEvent.use.createDisposableEvent((document.getElementById('kebab-delete-file-button-node') as HTMLElement), 'click', this.kebabDropdownDeleteFileCb, undefined, "Created event for kebab dropdown delete file (click)");
+ }
+
+ /**
+ * Kebab rename file continue callback
+ *
+ * @public
+ */
+ public kebabRenameFileContinueCb: () => void = (): void => {
+ console.log(((document.getElementById("top-bar-directory-info") as HTMLElement).textContent as string).split("-")[0]);
+ console.log(fsMod.fs._baseDir("home") + "/Iris/Notes" + ((document.getElementById("top-bar-directory-info") as HTMLElement).textContent as string).split("-")[0].trim() + "/" + (document.querySelector('.child-file-name.is-active-child') as HTMLElement).textContent);
+ console.log(fsMod.fs._baseDir("home") + "/Iris/Notes" + ((document.getElementById("top-bar-directory-info") as HTMLElement).textContent as string).split("-")[0].trim() + "/" + this.renameFile);
+
+ if(this.renameFile === " " || this.renameFile === "" || this.renameFile === (document.querySelector('.child-file-name.is-active-child') as HTMLElement).textContent || (document.getElementById('rename-file-input-node') as HTMLElement).textContent === (document.querySelector('.child-file-name.is-active-child') as HTMLElement).textContent) {
//log
- console.log("clicked kebab delete");
+ console.log("name is equal or empty");
- document.querySelectorAll('#kebab-modal-container-node').forEach((el) => {
- //null check
- if(el !== null) {
- //remove any remaining kebab modal container nodes
- el.remove();
- }
- })
+ window.electron.ipcRenderer.invoke('show-message-box', "Cannot rename note. Name must be different and not empty.");
- //create kebab modal container
- this.kebabModalDeleteFileContainer();
+ return;
+ } else {
+ //log
+ console.log("name is not equal or empty");
- //invoke kebab delete file exit modal listener
- this.kebabExitModalListener();
+ //rename file
+ fsMod.fs._renameFile(
+ fsMod.fs._baseDir("home") + "/Iris/Notes/" + ((document.getElementById("top-bar-directory-info") as HTMLElement).textContent as string).split("-")[0].trim() + "/" + (document.querySelector('.child-file-name.is-active-child') as HTMLElement).textContent + ".md",
+ fsMod.fs._baseDir("home") + "/Iris/Notes/" + ((document.getElementById("top-bar-directory-info") as HTMLElement).textContent as string).split("-")[0].trim() + "/" + this.renameFile + ".md"
+ )
- //invoke kebab delete file continue modal listener
- this.kebabDeleteFileContinueModalListener();
- })
+ //remove kebab modal container node
+ EditorKebabDropdownModals.kebabModalContainerNode.remove();
+
+ //create top bar info
+ const topBarInfo: string = ((document.getElementById("top-bar-directory-info") as HTMLElement).textContent as string).split("-")[0].trim() + " - " + this.renameFile;
+
+ //update top bar directory info
+ (document.getElementById('top-bar-directory-info') as HTMLElement).textContent = topBarInfo;
+
+ //update child file name in directory tree
+ (document.querySelector('.child-file-name.is-active-child') as HTMLElement).textContent = this.renameFile;
+
+ //update child file name reference
+ RefsNs.currentParentChildData.map((props) => {
+ props.childFileName = this.renameFile
+ });
+
+ GenericEvent.use.disposeEvent((document.getElementById('kebab-modal-continue-button') as HTMLElement), 'click', this.kebabRenameFileContinueCb, undefined, "Disposed event for kebab rename file continue (click)");
+ GenericEvent.use.disposeEvent(window, 'keydown', KeyBinds.map.bindCb, undefined, "Disposed event for kebab rename file continue (keydown enter)");
+ }
}
- public kebabRenameFileContinueModalListener(): void {
- let renameFile: string = "";
+ public renameFileCb: (e: KeyboardEvent) => void = (e: KeyboardEvent): void => {
+ this.renameFile = ((e.target as HTMLInputElement).value).trim();
- (document.getElementById('rename-file-input-node') as HTMLElement).addEventListener('keyup', (e) => {
- renameFile = ((e.target as HTMLInputElement).value).trim();
+ (document.getElementById('rename-file-input-node') as HTMLElement).textContent = this.renameFile;
- (document.getElementById('rename-file-input-node') as HTMLElement).textContent = renameFile;
+ //log
+ console.log(this.renameFile);
+ }
- //log
- console.log(renameFile);
- });
+ public kebabRenameFileContinueModalListener(): void {
+ GenericEvent.use.createDisposableEvent((document.getElementById('rename-file-input-node') as HTMLElement), 'keyup', this.renameFileCb, undefined, "Created event for rename file (keyup)");
- (document.getElementById('kebab-modal-continue-button') as HTMLElement).addEventListener('click', () => {
- console.log(((document.getElementById("top-bar-directory-info") as HTMLElement).textContent as string).split("-")[0]);
- console.log(fsMod.fs._baseDir("home") + "/Iris/Notes" + ((document.getElementById("top-bar-directory-info") as HTMLElement).textContent as string).split("-")[0].trim() + "/" + (document.querySelector('.child-file-name.is-active-child') as HTMLElement).textContent);
- console.log(fsMod.fs._baseDir("home") + "/Iris/Notes" + ((document.getElementById("top-bar-directory-info") as HTMLElement).textContent as string).split("-")[0].trim() + "/" + renameFile);
- if(renameFile === " " || renameFile === "" || renameFile === (document.querySelector('.child-file-name.is-active-child') as HTMLElement).textContent || (document.getElementById('rename-file-input-node') as HTMLElement).textContent === (document.querySelector('.child-file-name.is-active-child') as HTMLElement).textContent) {
- //log
- console.log("name is equal or empty");
-
- return;
- } else {
- //log
- console.log("name is not equal or empty");
+ GenericEvent.use.createDisposableEvent((document.getElementById('kebab-modal-continue-button') as HTMLElement), 'click', this.kebabRenameFileContinueCb, undefined, "Created event for kebab rename file continue (click)");
- //rename file
- fsMod.fs._renameFile(
- fsMod.fs._baseDir("home") + "/Iris/Notes/" + ((document.getElementById("top-bar-directory-info") as HTMLElement).textContent as string).split("-")[0].trim() + "/" + (document.querySelector('.child-file-name.is-active-child') as HTMLElement).textContent + ".md",
- fsMod.fs._baseDir("home") + "/Iris/Notes/" + ((document.getElementById("top-bar-directory-info") as HTMLElement).textContent as string).split("-")[0].trim() + "/" + renameFile + ".md"
- )
-
- //remove kebab modal container node
- EditorKebabDropdownModals.kebabModalContainerNode.remove();
-
- //create top bar info
- const topBarInfo: string = ((document.getElementById("top-bar-directory-info") as HTMLElement).textContent as string).split("-")[0].trim() + " - " + renameFile;
-
- //update top bar directory info
- (document.getElementById('top-bar-directory-info') as HTMLElement).textContent = topBarInfo;
-
- //update child file name in directory tree
- (document.querySelector('.child-file-name.is-active-child') as HTMLElement).textContent = renameFile;
-
- //update child file name reference
- RefsNs.currentParentChildData.map((props) => {
- props.childFileName = renameFile
- });
+ KeyBinds.map.bind(this.kebabRenameFileContinueCb, "Enter", false);
+ }
+
+ public kebabDropdownRenameFileCb: () => void = (): void => {
+ //log
+ console.log("clicked kebab rename");
+
+ document.querySelectorAll('#kebab-modal-container-node').forEach((el) => {
+ //null check
+ if(el !== null) {
+ //remove any remaining kebab modal container nodes
+ el.remove();
}
})
+
+ GenericEvent.use.setEventCallbackTimeout(() => {
+ this.kebabDropdownRenameFileContainer();
+
+ this.kebabExitModalListener();
+
+ this.kebabRenameFileContinueModalListener();
+ }, 20);
}
/**
* Kebab dropdown rename file listener
*/
public kebabDropdownRenameFileListener(): void {
- (document.getElementById('kebab-rename-file-button') as HTMLElement).addEventListener('click', () => {
- //log
- console.log("clicked kebab rename");
-
- document.querySelectorAll('#kebab-modal-container-node').forEach((el) => {
- //null check
- if(el !== null) {
- //remove any remaining kebab modal container nodes
- el.remove();
- }
- })
-
- this.kebabDropdownRenameFileContainer();
-
- this.kebabExitModalListener();
-
- this.kebabRenameFileContinueModalListener();
- })
+ GenericEvent.use.createDisposableEvent((document.getElementById('kebab-rename-file-button') as HTMLElement), 'click', () => GenericEvent.use.setEventCallbackTimeout(this.kebabDropdownRenameFileCb, 50), undefined, "Created disposable event for kebab dropdown rename file");
}
/**
diff --git a/src/renderer/src/event-listeners/settings-modal-listeners.ts b/src/renderer/src/event-listeners/settings-modal-listeners.ts
index 1e7b494..9832648 100644
--- a/src/renderer/src/event-listeners/settings-modal-listeners.ts
+++ b/src/renderer/src/event-listeners/settings-modal-listeners.ts
@@ -5,6 +5,9 @@ import { CMEditorView } from "../codemirror/editor/cm-editor-view"
import { CMEditorState } from "../codemirror/editor/cm-editor-state"
import { cursors } from "../codemirror/extensions/cursors"
import { AdvancedModeSettings } from "../settings/settings"
+import { GenericEvent } from "./event"
+import { KeyBinds } from "../keybinds/keybinds"
+
import highlightLight from '../../assets/classic-light.min.css?inline?url'
/**
@@ -12,12 +15,185 @@ import highlightLight from '../../assets/classic-light.min.css?inline?url'
*/
export class SettingsModalListeners extends SettingsModal {
/**
- * Settings modal exit listener
+ * Theme select callback
+ *
+ * @public
*/
- public settingsModalExitListener(): void {
- SettingsModal.settingsModalExitButton.addEventListener('click', () => {
- SettingsModal.settingsModalContainerNode.remove();
- })
+ public themeSelectCb: (e: Event) => void = (e: Event): void => {
+ const currentSelection = (e.currentTarget as HTMLSelectElement);
+
+ //if dark theme exists in dom
+ if((document.querySelector('.editor-dark-theme') as HTMLElement) !== null) {
+ //remove stylesheet node
+ document.querySelectorAll('.editor-dark-theme').forEach((el) => {
+ el.remove();
+ })
+ }
+
+ //if selection is light theme
+ if(currentSelection.value === 'editor-light') {
+ //log
+ console.log("selected editor light");
+
+ (document.querySelector('.dark-option') as HTMLElement).removeAttribute("selected");
+
+ (document.querySelector('.light-option') as HTMLElement).setAttribute("selected", "");
+
+ //check highlight light
+ if((document.querySelector('.highlight-light-theme') as HTMLElement) !== null) {
+ document.querySelectorAll('.highlight-light-theme').forEach((el) => {
+ el.remove();
+ })
+ }
+
+ //check highlight dark
+ if((document.querySelector('.highlight-dark-theme') as HTMLElement) !== null) {
+ document.querySelectorAll('.highlight-dark-theme').forEach((el) => {
+ el.remove();
+ })
+ }
+
+ const highlightTheme: HTMLLinkElement = document.createElement('link');
+ highlightTheme.setAttribute("rel", "stylesheet");
+ highlightTheme.setAttribute("href", highlightLight);
+ highlightTheme.setAttribute("class", "highlight-light-theme");
+ document.body.appendChild(highlightTheme);
+
+ Settings.getSettings.lightTheme = true;
+ Settings.getSettings.darkTheme = false;
+
+ if(!Settings.getSettings.lightTheme) {
+ fsMod.fs._writeToFileAlt(fsMod.fs._baseDir("home") + "/Iris/.settings.json", JSON.stringify(JSON.parse(JSON.stringify(Settings.getSettings, null, 2)), null, 2));
+ } else {
+ fsMod.fs._writeToFileAlt(fsMod.fs._baseDir("home") + "/Iris/.settings.json", JSON.stringify(JSON.parse(JSON.stringify(Settings.getSettings, null, 2)), null, 2));
+ }
+
+ //check mode
+ if(Settings.getSettings.basicMode) {
+ CMEditorView.editorView.dispatch({ effects: CMEditorState.cursorCompartment.reconfigure(cursors[0]) })
+ } else if(Settings.getSettings.advancedMode) {
+ CMEditorView.editorView.dispatch({ effects: CMEditorState.cursorCompartment.reconfigure(cursors[0]) })
+ }
+
+ //check block cursor
+ if(Settings.getSettings.defaultCursor && Settings.getSettings.lightTheme) {
+ AdvancedModeSettings.defaultCursor("light");
+ } else if(Settings.getSettings.defaultCursor && Settings.getSettings.darkTheme) {
+ AdvancedModeSettings.defaultCursor("dark");
+ } else if(Settings.getSettings.blockCursor && Settings.getSettings.lightTheme || Settings.getSettings.blockCursor && Settings.getSettings.darkTheme) {
+ AdvancedModeSettings.blockCursor();
+ }
+ //if selection is dark theme
+ } else if(currentSelection.value === 'editor-dark') {
+ //log
+ console.log("selected editor dark");
+
+ (document.querySelector('.light-option') as HTMLElement).removeAttribute("selected");
+
+ (document.querySelector('.dark-option') as HTMLElement).setAttribute("selected", "");
+
+ //check highlight light
+ if((document.querySelector('.highlight-light-theme') as HTMLElement) !== null) {
+ document.querySelectorAll('.highlight-light-theme').forEach((el) => {
+ el.remove();
+ })
+ }
+
+ //check highlight dark
+ if((document.querySelector('.highlight-dark-theme') as HTMLElement) !== null) {
+ document.querySelectorAll('.highlight-dark-theme').forEach((el) => {
+ el.remove();
+ })
+ }
+
+ //apply dark theme
+ EditorThemes.darkTheme();
+
+ Settings.getSettings.lightTheme = false;
+ Settings.getSettings.darkTheme = true;
+
+ if(!Settings.getSettings.darkTheme) {
+ fsMod.fs._writeToFileAlt(fsMod.fs._baseDir("home") + "/Iris/.settings.json", JSON.stringify(JSON.parse(JSON.stringify(Settings.getSettings, null, 2)), null, 2));
+ } else {
+ fsMod.fs._writeToFileAlt(fsMod.fs._baseDir("home") + "/Iris/.settings.json", JSON.stringify(JSON.parse(JSON.stringify(Settings.getSettings, null, 2)), null, 2));
+ }
+
+ //check mode
+ if(Settings.getSettings.basicMode) {
+ CMEditorView.editorView.dispatch({ effects: CMEditorState.cursorCompartment.reconfigure(cursors[1]) })
+ } else if(Settings.getSettings.advancedMode) {
+ CMEditorView.editorView.dispatch({ effects: CMEditorState.cursorCompartment.reconfigure(cursors[1]) })
+ }
+
+ //check block cursor
+ if(Settings.getSettings.defaultCursor && Settings.getSettings.lightTheme) {
+ AdvancedModeSettings.defaultCursor("light");
+ } else if(Settings.getSettings.defaultCursor && Settings.getSettings.darkTheme) {
+ AdvancedModeSettings.defaultCursor("dark");
+ } else if(Settings.getSettings.blockCursor && Settings.getSettings.lightTheme || Settings.getSettings.darkTheme && Settings.getSettings.darkTheme) {
+ AdvancedModeSettings.blockCursor();
+ }
+ }
+ }
+
+ /**
+ * Cursor settings callback
+ *
+ * @public
+ */
+ public cursorSettingsCb: (e: Event) => void = (e: Event): void => {
+ const currentSelection: HTMLSelectElement = (e.currentTarget as HTMLSelectElement);
+
+ //if current selection is default-cursor and theme is light
+ if(currentSelection.value === 'default-cursor' && Settings.getSettings.lightTheme) {
+ //log
+ console.log("selected default cursor and theme is light");
+
+ (document.querySelector('.block-cursor-option') as HTMLElement).removeAttribute("selected");
+ (document.querySelector('.default-cursor-option') as HTMLElement).setAttribute("selected", "");
+
+ Settings.getSettings.defaultCursor = true;
+ Settings.getSettings.blockCursor = false;
+
+ fsMod.fs._writeToFileAlt(fsMod.fs._baseDir("home") + "/Iris/.settings.json", JSON.stringify(JSON.parse(JSON.stringify(Settings.getSettings, null, 2)), null, 2));
+
+ //dispatch cursor compartment reconfiguration
+ CMEditorView.editorView.dispatch({
+ effects: CMEditorState.cursorCompartment.reconfigure(cursors[0])
+ })
+ //if current selection is default-cursor and theme is dark
+ } else if(currentSelection.value === 'default-cursor' && Settings.getSettings.darkTheme) {
+ //log
+ console.log("selected default cursor and theme is dark");
+
+ (document.querySelector('.block-cursor-option') as HTMLElement).removeAttribute("selected");
+ (document.querySelector('.default-cursor-option') as HTMLElement).setAttribute("selected", "");
+
+ Settings.getSettings.defaultCursor = true;
+ Settings.getSettings.blockCursor = false;
+
+ fsMod.fs._writeToFileAlt(fsMod.fs._baseDir("home") + "/Iris/.settings.json", JSON.stringify(JSON.parse(JSON.stringify(Settings.getSettings, null, 2)), null, 2));
+
+ CMEditorView.editorView.dispatch({
+ effects: CMEditorState.cursorCompartment.reconfigure(cursors[1])
+ })
+ //if current selection is block-cursor
+ } else if(currentSelection.value === 'block-cursor') {
+ //log
+ console.log("selected block cursor");
+
+ (document.querySelector('.default-cursor-option') as HTMLElement).removeAttribute("selected");
+ (document.querySelector('.block-cursor-option') as HTMLElement).setAttribute("selected", "");
+
+ Settings.getSettings.defaultCursor = false;
+ Settings.getSettings.blockCursor = true;
+
+ fsMod.fs._writeToFileAlt(fsMod.fs._baseDir("home") + "/Iris/.settings.json", JSON.stringify(JSON.parse(JSON.stringify(Settings.getSettings, null, 2)), null, 2));
+
+ CMEditorView.editorView.dispatch({
+ effects: CMEditorState.cursorCompartment.reconfigure(cursors[2])
+ })
+ }
}
/**
@@ -34,128 +210,7 @@ export class SettingsModalListeners extends SettingsModal {
return;
} else {
- (document.getElementById("theme-select") as HTMLElement).addEventListener('change', (e) => {
- const currentSelection = (e.currentTarget as HTMLSelectElement);
-
- //if dark theme exists in dom
- if((document.querySelector('.editor-dark-theme') as HTMLElement) !== null) {
- //remove stylesheet node
- document.querySelectorAll('.editor-dark-theme').forEach((el) => {
- el.remove();
- })
- }
-
- //if selection is light theme
- if(currentSelection.value === 'editor-light') {
- //log
- console.log("selected editor light");
-
- (document.querySelector('.dark-option') as HTMLElement).removeAttribute("selected");
-
- (document.querySelector('.light-option') as HTMLElement).setAttribute("selected", "");
-
- //check highlight light
- if((document.querySelector('.highlight-light-theme') as HTMLElement) !== null) {
- document.querySelectorAll('.highlight-light-theme').forEach((el) => {
- el.remove();
- })
- }
-
- //check highlight dark
- if((document.querySelector('.highlight-dark-theme') as HTMLElement) !== null) {
- document.querySelectorAll('.highlight-dark-theme').forEach((el) => {
- el.remove();
- })
- }
-
- const highlightTheme: HTMLLinkElement = document.createElement('link');
- highlightTheme.setAttribute("rel", "stylesheet");
- highlightTheme.setAttribute("href", highlightLight);
- highlightTheme.setAttribute("class", "highlight-light-theme");
- document.body.appendChild(highlightTheme);
-
- Settings.getSettings.lightTheme = true;
- Settings.getSettings.darkTheme = false;
-
- if(!Settings.getSettings.lightTheme) {
- fsMod.fs._writeToFileAlt(fsMod.fs._baseDir("home") + "/Iris/.settings.json", JSON.stringify(JSON.parse(JSON.stringify(Settings.getSettings, null, 2)), null, 2));
- } else {
- fsMod.fs._writeToFileAlt(fsMod.fs._baseDir("home") + "/Iris/.settings.json", JSON.stringify(JSON.parse(JSON.stringify(Settings.getSettings, null, 2)), null, 2));
- }
-
- //check mode
- if(Settings.getSettings.basicMode) {
- CMEditorView.editorView.dispatch({ effects: CMEditorState.cursorCompartment.reconfigure(cursors[0]) })
- } else if(Settings.getSettings.advancedMode) {
- CMEditorView.editorView.dispatch({ effects: CMEditorState.cursorCompartment.reconfigure(cursors[0]) })
- }
-
- //check block cursor
- if(Settings.getSettings.defaultCursor && Settings.getSettings.lightTheme) {
- AdvancedModeSettings.defaultCursor("light");
- } else if(Settings.getSettings.defaultCursor && Settings.getSettings.darkTheme) {
- AdvancedModeSettings.defaultCursor("dark");
- } else if(
- Settings.getSettings.blockCursor && Settings.getSettings.lightTheme
- || Settings.getSettings.blockCursor && Settings.getSettings.darkTheme
- ) {
- AdvancedModeSettings.blockCursor();
- }
- //if selection is dark theme
- } else if(currentSelection.value === 'editor-dark') {
- //log
- console.log("selected editor dark");
-
- (document.querySelector('.light-option') as HTMLElement).removeAttribute("selected");
-
- (document.querySelector('.dark-option') as HTMLElement).setAttribute("selected", "");
-
- //check highlight light
- if((document.querySelector('.highlight-light-theme') as HTMLElement) !== null) {
- document.querySelectorAll('.highlight-light-theme').forEach((el) => {
- el.remove();
- })
- }
-
- //check highlight dark
- if((document.querySelector('.highlight-dark-theme') as HTMLElement) !== null) {
- document.querySelectorAll('.highlight-dark-theme').forEach((el) => {
- el.remove();
- })
- }
-
- //apply dark theme
- EditorThemes.darkTheme();
-
- Settings.getSettings.lightTheme = false;
- Settings.getSettings.darkTheme = true;
-
- if(!Settings.getSettings.darkTheme) {
- fsMod.fs._writeToFileAlt(fsMod.fs._baseDir("home") + "/Iris/.settings.json", JSON.stringify(JSON.parse(JSON.stringify(Settings.getSettings, null, 2)), null, 2));
- } else {
- fsMod.fs._writeToFileAlt(fsMod.fs._baseDir("home") + "/Iris/.settings.json", JSON.stringify(JSON.parse(JSON.stringify(Settings.getSettings, null, 2)), null, 2));
- }
-
- //check mode
- if(Settings.getSettings.basicMode) {
- CMEditorView.editorView.dispatch({ effects: CMEditorState.cursorCompartment.reconfigure(cursors[1]) })
- } else if(Settings.getSettings.advancedMode) {
- CMEditorView.editorView.dispatch({ effects: CMEditorState.cursorCompartment.reconfigure(cursors[1]) })
- }
-
- //check block cursor
- if(Settings.getSettings.defaultCursor && Settings.getSettings.lightTheme) {
- AdvancedModeSettings.defaultCursor("light");
- } else if(Settings.getSettings.defaultCursor && Settings.getSettings.darkTheme) {
- AdvancedModeSettings.defaultCursor("dark");
- } else if(
- Settings.getSettings.blockCursor && Settings.getSettings.lightTheme
- || Settings.getSettings.darkTheme && Settings.getSettings.darkTheme
- ) {
- AdvancedModeSettings.blockCursor();
- }
- }
- })
+ GenericEvent.use.createDisposableEvent((document.getElementById("theme-select") as HTMLElement), 'change', this.themeSelectCb, undefined, "Create disposable event for theme select (change)");
}
}
@@ -165,80 +220,77 @@ export class SettingsModalListeners extends SettingsModal {
* @private
*/
private cursorSettingsListener(): void {
- (document.getElementById('advanced-mode-options-select') as HTMLElement).addEventListener('change', (e) => {
- const currentSelection: HTMLSelectElement = (e.currentTarget as HTMLSelectElement);
-
- //if current selection is default-cursor and theme is light
- if(currentSelection.value === 'default-cursor' && Settings.getSettings.lightTheme) {
- //log
- console.log("selected default cursor and theme is light");
-
- (document.querySelector('.block-cursor-option') as HTMLElement).removeAttribute("selected");
- (document.querySelector('.default-cursor-option') as HTMLElement).setAttribute("selected", "");
-
- Settings.getSettings.defaultCursor = true;
- Settings.getSettings.blockCursor = false;
-
- fsMod.fs._writeToFileAlt(fsMod.fs._baseDir("home") + "/Iris/.settings.json", JSON.stringify(JSON.parse(JSON.stringify(Settings.getSettings, null, 2)), null, 2));
-
- //dispatch cursor compartment reconfiguration
- CMEditorView.editorView.dispatch({
- effects: CMEditorState.cursorCompartment.reconfigure(cursors[0])
- })
- //if current selection is default-cursor and theme is dark
- } else if(currentSelection.value === 'default-cursor' && Settings.getSettings.darkTheme) {
- //log
- console.log("selected default cursor and theme is dark");
+ GenericEvent.use.createDisposableEvent((document.getElementById('advanced-mode-options-select') as HTMLElement), 'change', this.cursorSettingsCb, undefined, "Created disposable event for cursor settings (change)");
+ }
- (document.querySelector('.block-cursor-option') as HTMLElement).removeAttribute("selected");
- (document.querySelector('.default-cursor-option') as HTMLElement).setAttribute("selected", "");
+ /**
+ * Settings modal exit callback
+ *
+ * @public
+ */
+ public settingsModalExitCb: () => void = (): void => {
+ SettingsModal.settingsModalContainerNode.remove();
- Settings.getSettings.defaultCursor = true;
- Settings.getSettings.blockCursor = false;
+ GenericEvent.use.setEventCallbackTimeout(() => {
+ //dispose theme select cb
+ GenericEvent.use.disposeEvent(document.body, 'change', this.themeSelectCb, undefined, "Disposed event for theme select (change)");
- fsMod.fs._writeToFileAlt(fsMod.fs._baseDir("home") + "/Iris/.settings.json", JSON.stringify(JSON.parse(JSON.stringify(Settings.getSettings, null, 2)), null, 2));
+ //dispose cursor settings cb
+ GenericEvent.use.disposeEvent(document.body, 'change', this.cursorSettingsCb, undefined, "Disposed event for cursor settings (change)");
+
+ //dispose settings modal exit cb
+ GenericEvent.use.disposeEvent(SettingsModal.settingsModalExitButton, 'click', this.settingsModalExitCb, undefined, "Disposed event for settings modal exit (click)");
- CMEditorView.editorView.dispatch({
- effects: CMEditorState.cursorCompartment.reconfigure(cursors[1])
- })
- //if current selection is block-cursor
- } else if(currentSelection.value === 'block-cursor') {
- //log
- console.log("selected block cursor");
+ //dispose bind cb
+ GenericEvent.use.disposeEvent(window, 'keydown', KeyBinds.map.bindCb, undefined, "Disposed event for bind (keydown escape)");
+ }, 150)
- (document.querySelector('.default-cursor-option') as HTMLElement).removeAttribute("selected");
- (document.querySelector('.block-cursor-option') as HTMLElement).setAttribute("selected", "");
+ //reset map list
+ KeyBinds.map.resetMapList();
+ }
- Settings.getSettings.defaultCursor = false;
- Settings.getSettings.blockCursor = true;
+ /**
+ * Settings modal exit listener
+ */
+ public settingsModalExitListener(): void {
+ KeyBinds.map.bind(this.settingsModalExitCb, 'Escape', true);
- fsMod.fs._writeToFileAlt(fsMod.fs._baseDir("home") + "/Iris/.settings.json", JSON.stringify(JSON.parse(JSON.stringify(Settings.getSettings, null, 2)), null, 2));
+ GenericEvent.use.createDisposableEvent(SettingsModal.settingsModalExitButton, 'click', this.settingsModalExitCb, undefined, "Created disposable event for settings modal exit (click)");
+ }
- CMEditorView.editorView.dispatch({
- effects: CMEditorState.cursorCompartment.reconfigure(cursors[2])
- })
- }
- })
+ /**
+ * Settings modal callback
+ *
+ * @public
+ */
+ public settingsModalCb: () => void = (): void => {
+ console.log("clicked settings node");
+
+ GenericEvent.use.setEventCallbackTimeout(
+ () => {
+ //create settings modal container
+ this.settingsModalContainer();
+
+ //theme settings listener
+ this.themeSettingsListener();
+
+ //cursor settings listener
+ this.cursorSettingsListener();
+
+ //invoke settings modal exit listener
+ this.settingsModalExitListener();
+
+ //dispose settings modal cb
+ GenericEvent.use.disposeEvent((document.getElementById("settings-node") as HTMLElement), 'click', () => GenericEvent.use.setEventCallbackTimeout(this.settingsModalCb, 50), undefined, "Disposed event for settings modal (click)");
+ }, 50
+ )
}
+
/**
* Settings modal listener
*/
public settingsModalListener(): void {
- (document.getElementById("settings-node") as HTMLElement).addEventListener('click', () => {
- console.log("clicked settings node");
-
- //create settings modal container
- this.settingsModalContainer();
-
- //invoke settings modal exit listener
- this.settingsModalExitListener();
-
- //theme settings listener
- this.themeSettingsListener();
-
- //cursor settings listener
- this.cursorSettingsListener();
- })
+ GenericEvent.use.createDisposableEvent((document.getElementById("settings-node") as HTMLElement), 'click', () => GenericEvent.use.setEventCallbackTimeout(this.settingsModalCb, 50), undefined, "Create disposable event for settings modal (click)");
}
}
\ No newline at end of file
diff --git a/src/renderer/src/file-directory-tree/file-directory.ts b/src/renderer/src/file-directory-tree/file-directory.ts
index 79c08ab..81e9739 100644
--- a/src/renderer/src/file-directory-tree/file-directory.ts
+++ b/src/renderer/src/file-directory-tree/file-directory.ts
@@ -3,7 +3,6 @@ import { fsMod } from '../utils/alias'
import { isFolderNode } from '../utils/is'
import { Settings } from '../settings/settings'
-//eslint-disable-next-line @typescript-eslint/no-namespace
export class FileDirectoryTreeNode {
/**
* File directory tree node
diff --git a/src/renderer/src/keybinds/constants.ts b/src/renderer/src/keybinds/constants.ts
new file mode 100644
index 0000000..7619fd9
--- /dev/null
+++ b/src/renderer/src/keybinds/constants.ts
@@ -0,0 +1,4 @@
+export enum EKeyMap {
+ ESCAPE = 'Escape',
+ ENTER = 'Enter'
+}
diff --git a/src/renderer/src/keybinds/keybinds.ts b/src/renderer/src/keybinds/keybinds.ts
new file mode 100644
index 0000000..781748a
--- /dev/null
+++ b/src/renderer/src/keybinds/keybinds.ts
@@ -0,0 +1,157 @@
+import { EKeyMap } from "./constants"
+import { GenericEvent } from "../event-listeners/event"
+import { GenericArray } from "../utils/array"
+
+interface IFn {
+ fn: (...args: any[]) => any,
+ key: string
+}
+
+export namespace KeyBinds {
+ class KeyMapper {
+ /**
+ * Array of objects to hold key binds and their corresponding functions
+ *
+ * @private
+ */
+ private map: IFn[] = [
+ {
+ fn: {} as (...args: any[]) => any,
+ key: ""
+ },
+ {
+ fn: {} as (...args: any[]) => any,
+ key: ""
+ }
+ ];
+
+ /**
+ * Reset map list
+ *
+ * @public
+ */
+ public resetMapList(): void {
+ GenericEvent.use.setEventCallbackTimeout(() => {
+ this.map = [
+ {
+ fn: {} as (...args: any[]) => any,
+ key: ""
+ },
+ {
+ fn: {} as (...args: any[]) => any,
+ key: ""
+ }
+ ];
+
+ console.log("Reset map");
+ }, 200);
+ }
+
+ /**
+ * Set bind
+ *
+ * @param key Type of key to execute corresponding function (`Escape`, `Enter`)
+ *
+ * @public
+ */
+ public setBind(key: string): void {
+ console.log(this.map.length);
+
+ if(key === 'Escape') {
+ GenericEvent.use.setEventCallbackTimeout(this.map[0].fn, 20);
+ } else if(key === 'Enter') {
+ GenericEvent.use.setEventCallbackTimeout(this.map[1].fn, 20);
+ }
+ }
+
+ /**
+ * Bind callback
+ *
+ * @param e KeyboardEvent
+ *
+ * @public
+ */
+ public bindCb: (e: KeyboardEvent) => any = (e: KeyboardEvent): any => {
+ console.log(this.map);
+ console.log(this.map.length);
+
+ switch(e.code) {
+ case EKeyMap.ESCAPE: {
+ if(this.map[0].key === EKeyMap.ESCAPE) {
+ console.log("Escape bind");
+
+ this.setBind("Escape");
+ }
+ break;
+ }
+ case EKeyMap.ENTER: {
+ if(this.map[1].key === EKeyMap.ENTER) {
+ console.log("Enter bind");
+
+ this.setBind("Enter");
+ }
+ break;
+ }
+ }
+ }
+
+ /**
+ * Remap binding for single key
+ *
+ * @param fn Function
+ * @param key Key type
+ * @returns Remapped binding for single key
+ *
+ * @private
+ */
+ private remapSingle(fn: (...args: any[]) => any, key: string): IFn[] {
+ //empty keybind map before reassigning value to this.map
+ GenericArray.use.empty(this.map, false);
+
+ return this.map = [
+ {
+ fn: fn,
+ key: key
+ }
+ ]
+ }
+
+ /**
+ * Bind a key
+ *
+ * @param fn Function
+ * @param key Key type (`Escape`, `Enter`)
+ * @param singleKey Option for binding a single key only
+ */
+ public bind(fn: (...args: any[]) => any, key: string, singleKey: boolean): void {
+ if(singleKey) {
+ if(key === EKeyMap.ESCAPE) {
+ this.remapSingle(fn, key);
+ } else if(key === EKeyMap.ENTER) {
+ this.remapSingle(fn, key)
+ }
+
+ GenericEvent.use.createDisposableEvent(window, 'keydown', this.bindCb, undefined, "Created disposable event for bind (keydown)");
+
+ return;
+ } else if(!singleKey) {
+ if(key === 'Escape') {
+ this.map[0].fn = fn;
+ this.map[0].key = key
+ } else if(key === 'Enter') {
+ this.map[1].fn = fn;
+ this.map[1].key = key;
+ }
+
+ GenericEvent.use.createDisposableEvent(window, 'keydown', this.bindCb, undefined, "Created disposable event for bind (keydown)");
+
+ return;
+ }
+ }
+ }
+
+ /**
+ * KeyMapper object
+ */
+ export const map: KeyMapper = new KeyMapper();
+}
\ No newline at end of file
diff --git a/src/renderer/src/renderer.ts b/src/renderer/src/renderer.ts
index 1b32c50..1369011 100644
--- a/src/renderer/src/renderer.ts
+++ b/src/renderer/src/renderer.ts
@@ -4,96 +4,134 @@ import { windowNs } from './window/draggable-area'
import { Settings, EditorThemes } from '../src/settings/settings'
import { AdvancedModeSettings } from '../src/settings/settings'
import mermaid from 'mermaid'
-
-export function initRenderer(): void {
- window.addEventListener('DOMContentLoaded', () => {
- //draggable area
- windowNs.draggableArea();
-
- //directory
- directoryNs.directory();
-
- //editor
- EditorNs.editor();
-
- //load themes
- if(Settings.getSettings.lightTheme) {
- //if dark theme exists in dom
- if((document.querySelector('.editor-dark-theme') as HTMLElement) !== null) {
- //remove stylesheet node
- document.querySelectorAll('.editor-dark-theme').forEach((el) => {
- el.remove();
- })
-
- document.querySelectorAll('.highlight-dark-theme').forEach((el) => {
- el.remove();
- })
- }
-
- //initialize mermaid
- mermaid.initialize({
- theme: 'forest'
- })
- //dark theme
- } else if(Settings.getSettings.darkTheme) {
- EditorThemes.darkTheme();
- }
-
- if(Settings.getSettings.darkTheme) {
- document.querySelectorAll('.highlight-light-theme').forEach((el) => {
+import { GenericEvent } from './event-listeners/event'
+
+namespace RendererProcess {
+ class Renderer {
+ /**
+ * Coupled namespace function
+ *
+ * @private
+ */
+ private coupleNs(): void {
+ //draggable area
+ windowNs.draggableArea();
+
+ //directory
+ directoryNs.directory();
+
+ //editor
+ EditorNs.editor();
+ }
+
+ /**
+ * Load theme
+ *
+ * @private
+ */
+ private loadTheme(): void {
+ //load themes
+ if(Settings.getSettings.lightTheme) {
+ //if dark theme exists in dom
+ if((document.querySelector('.editor-dark-theme') as HTMLElement) !== null) {
+ //remove stylesheet node
+ document.querySelectorAll('.editor-dark-theme').forEach((el) => {
el.remove();
})
- //initialize mermaid
- mermaid.initialize({
- theme: 'forest'
+ document.querySelectorAll('.highlight-dark-theme').forEach((el) => {
+ el.remove();
})
}
+ //dark theme
+ } else if(Settings.getSettings.darkTheme) {
+ EditorThemes.darkTheme();
+
+ document.querySelectorAll('.highlight-light-theme').forEach((el) => {
+ el.remove();
+ })
+ }
+
+ //initialize mermaid
+ mermaid.initialize({
+ theme: 'forest',
+ startOnLoad: true
+ })
+ }
+
+ /**
+ * Load mode
+ *
+ * @private
+ */
+ private loadMode(): void {
+ //load mode
+ if(Settings.getSettings.basicMode) {
+ console.log("basic mode active");
+
+ if((document.getElementById('app') as HTMLElement).classList.contains('advanced-mode-is-active')) {
+ (document.getElementById('app') as HTMLElement).classList.remove('advanced-mode-is-active');
+ }
+
+ (document.getElementById('app') as HTMLElement).classList.add('basic-mode-is-active');
+ //advanced mode
+ } else if(Settings.getSettings.advancedMode) {
+ console.log("advanced mode active");
+
+ if((document.getElementById('app') as HTMLElement).classList.contains('basic-mode-is-active')) {
+ (document.getElementById('app') as HTMLElement).classList.remove('basic-mode-is-active');
+ }
+
+ (document.getElementById('app') as HTMLElement).classList.add('advanced-mode-is-active');
+
+ //check block cursor
+ if(Settings.getSettings.defaultCursor && Settings.getSettings.lightTheme) {
+ AdvancedModeSettings.defaultCursor("light");
+ } else if(Settings.getSettings.defaultCursor && Settings.getSettings.darkTheme) {
+ AdvancedModeSettings.defaultCursor("dark");
+ } else if(Settings.getSettings.blockCursor && Settings.getSettings.lightTheme || Settings.getSettings.blockCursor && Settings.getSettings.darkTheme) {
+ AdvancedModeSettings.blockCursor();
+ }
+ } else if(Settings.getSettings.readingMode) {
+ console.log("reading mode active");
- //load mode
- if(Settings.getSettings.basicMode) {
- console.log("basic mode active");
-
- if((document.getElementById('app') as HTMLElement).classList.contains('advanced-mode-is-active')) {
- (document.getElementById('app') as HTMLElement).classList.remove('advanced-mode-is-active');
- }
-
- (document.getElementById('app') as HTMLElement).classList.add('basic-mode-is-active');
- //advanced mode
- } else if(Settings.getSettings.advancedMode) {
- console.log("advanced mode active");
-
- if((document.getElementById('app') as HTMLElement).classList.contains('basic-mode-is-active')) {
- (document.getElementById('app') as HTMLElement).classList.remove('basic-mode-is-active');
- }
-
- (document.getElementById('app') as HTMLElement).classList.add('advanced-mode-is-active');
-
- //check block cursor
- if(Settings.getSettings.defaultCursor && Settings.getSettings.lightTheme) {
- AdvancedModeSettings.defaultCursor("light");
- } else if(Settings.getSettings.defaultCursor && Settings.getSettings.darkTheme) {
- AdvancedModeSettings.defaultCursor("dark");
- } else if(
- Settings.getSettings.blockCursor && Settings.getSettings.lightTheme
- || Settings.getSettings.blockCursor && Settings.getSettings.darkTheme
- ) {
- AdvancedModeSettings.blockCursor();
- }
- } else if(Settings.getSettings.readingMode) {
- console.log("reading mode active");
-
- if((document.getElementById('app') as HTMLElement).classList.contains('basic-mode-is-active')) {
- (document.getElementById('app') as HTMLElement).classList.remove('basic-mode-is-active');
- } else if((document.getElementById('app') as HTMLElement).classList.contains('advanced-mode-is-active')) {
- (document.getElementById('app') as HTMLElement).classList.remove('advanced-mode-is-active');
- }
-
- (document.getElementById('app') as HTMLElement).classList.add('reading-mode-is-active');
+ if((document.getElementById('app') as HTMLElement).classList.contains('basic-mode-is-active')) {
+ (document.getElementById('app') as HTMLElement).classList.remove('basic-mode-is-active');
+ } else if((document.getElementById('app') as HTMLElement).classList.contains('advanced-mode-is-active')) {
+ (document.getElementById('app') as HTMLElement).classList.remove('advanced-mode-is-active');
}
- });
+
+ (document.getElementById('app') as HTMLElement).classList.add('reading-mode-is-active');
+ }
+ }
+
+ /**
+ * Attach window event
+ *
+ * @private
+ */
+ private attachWindowEvent(): void {
+ GenericEvent.use.createDisposableEvent(window, 'DOMContentLoaded', () => {
+ this.coupleNs();
+ this.loadTheme();
+ this.loadMode();
+ })
+ }
+
+ /**
+ * Initialize renderer
+ *
+ * @public
+ */
+ public initializeRenderer(): void {
+ this.attachWindowEvent();
+ }
+ }
+
+ /**
+ * Renderer object
+ */
+ export const execute: Renderer = new Renderer();
}
-initRenderer();
-//log test
-console.log(window.fsMod._getDirectoryName("/Users/alex/Iris"));
\ No newline at end of file
+RendererProcess.execute.initializeRenderer();
diff --git a/src/renderer/src/settings/settings-modal.ts b/src/renderer/src/settings/settings-modal.ts
index 43e300e..48a3704 100644
--- a/src/renderer/src/settings/settings-modal.ts
+++ b/src/renderer/src/settings/settings-modal.ts
@@ -16,7 +16,7 @@ export class SettingsModal {
SettingsModal.settingsModalExitButton.setAttribute("id", "settings-modal-exit");
SettingsModal.settingsModalInnerWindow.appendChild(SettingsModal.settingsModalExitButton);
- const settingsModalExitTextNode: Text = document.createTextNode("Exit");
+ const settingsModalExitTextNode: Text = document.createTextNode("x");
SettingsModal.settingsModalExitButton.appendChild(settingsModalExitTextNode);
}
diff --git a/src/renderer/src/settings/settings.ts b/src/renderer/src/settings/settings.ts
index 81c8055..0fbac50 100644
--- a/src/renderer/src/settings/settings.ts
+++ b/src/renderer/src/settings/settings.ts
@@ -23,6 +23,8 @@ interface ISettingsData {
"blockCursor": T
}
+type TSettings = ISettingsData;
+
export class Settings {
/**
* Get local settings
@@ -30,7 +32,7 @@ export class Settings {
* @static
* @readonly
*/
- static readonly getSettings: ISettingsData = JSON.parse(fsMod.fs._readFile(fsMod.fs._baseDir("home") + "/Iris/.settings.json"))
+ static readonly getSettings: TSettings = JSON.parse(fsMod.fs._readFile(fsMod.fs._baseDir("home") + "/Iris/.settings.json"))
}
export class EditorThemes {
diff --git a/src/renderer/src/utils/alias.ts b/src/renderer/src/utils/alias.ts
index 8a4338d..a13230e 100644
--- a/src/renderer/src/utils/alias.ts
+++ b/src/renderer/src/utils/alias.ts
@@ -1,4 +1,3 @@
-//eslint-disable-next-line @typescript-eslint/no-namespace
export namespace fsMod {
/**
* fsMod API alias
diff --git a/src/renderer/src/utils/array.ts b/src/renderer/src/utils/array.ts
new file mode 100644
index 0000000..e70da57
--- /dev/null
+++ b/src/renderer/src/utils/array.ts
@@ -0,0 +1,33 @@
+interface IArray {
+ empty(arr: T, pop: K): V
+}
+
+export namespace GenericArray {
+ /**
+ * @internal
+ */
+ class Array implements IArray {
+ /**
+ *
+ * @param arr Array to empty
+ * @param pop Option to empty array by popping the stack instead of setting length
+ * @returns Emptied array
+ */
+ public empty(arr: T[], pop: K): V {
+ let empty: number | any[] = {} as number | any[];
+
+ if(!pop && (arr.length !== 0 && arr.length !== -1 || arr.length !== undefined || arr.length !== null)) {
+ empty = (arr.length = 0 as number);
+ } else if(pop) {
+ while(arr.length > 0) {
+ empty = arr.pop() as any[];
+ }
+ }
+
+ return empty as V;
+ }
+ }
+
+ //eslint-disable-next-line
+ export const use: Array = new Array();
+}
\ No newline at end of file