Commit 38bf7348 authored by ransome1's avatar ransome1
Browse files

Preserve file history, enhanced hidden todos function

parent abf595b2
...@@ -18,8 +18,7 @@ flatpak/com.github.ransome1.sleek.yml ...@@ -18,8 +18,7 @@ flatpak/com.github.ransome1.sleek.yml
assets/icons/bak assets/icons/bak
squashfs-root/ squashfs-root/
.eslintrc.json .eslintrc.json
.stylelintrc.json
package-lock.json package-lock.json
.vs/ .vs/
.vscode/ .vscode/
.stylelintrc.json
src/css/
{ {
"name": "sleek", "name": "sleek",
"productName": "sleek", "productName": "sleek",
"version": "1.1.0-rc.4", "version": "1.1.0-rc.5",
"description": "Todo app based on todo.txt for Linux, Windows and MacOS, free and open-source", "description": "Todo app based on todo.txt for Linux, Windows and MacOS, free and open-source",
"synopsis": "Todo app based on todo.txt for Linux, Windows and MacOS, free and open-source", "synopsis": "Todo app based on todo.txt for Linux, Windows and MacOS, free and open-source",
"category": "ProjectManagement", "category": "ProjectManagement",
...@@ -102,7 +102,7 @@ ...@@ -102,7 +102,7 @@
"pack": "yarn build:css && yarn build:pegjs && electron-builder --dir", "pack": "yarn build:css && yarn build:pegjs && electron-builder --dir",
"lint": "eslint --ext .js, src --ext .mjs, src", "lint": "eslint --ext .js, src --ext .mjs, src",
"test": "mocha --timeout 10000", "test": "mocha --timeout 10000",
"test1": "mocha ./test/createTodos.js --timeout 10000", "test1": "mocha ./test/onboarding.js --timeout 10000",
"sass": "sass -w src/scss/style.scss:src/css/style.css", "sass": "sass -w src/scss/style.scss:src/css/style.css",
"start": "yarn sass & electron ." "start": "yarn sass & electron ."
}, },
......
This diff is collapsed.
This diff is collapsed.
"use strict"; "use strict";
import { resetFilters, resetModal, handleError, userData, appData, setUserData, translations } from "../render.js"; import { resetFilters, resetModal, handleError, userData, appData, setUserData, translations, showOnboarding } from "../render.js";
import { _paq } from "./matomo.mjs"; import { _paq } from "./matomo.mjs";
import { createModalJail } from "../configs/modal.config.mjs"; import { createModalJail } from "../configs/modal.config.mjs";
...@@ -8,22 +8,39 @@ const modalChangeFile = document.getElementById("modalChangeFile"); ...@@ -8,22 +8,39 @@ const modalChangeFile = document.getElementById("modalChangeFile");
const modalChangeFileTable = document.getElementById("modalChangeFileTable"); const modalChangeFileTable = document.getElementById("modalChangeFileTable");
const fileTabBarList = document.querySelector("#fileTabBar ul"); const fileTabBarList = document.querySelector("#fileTabBar ul");
function removeFileFromList(isActive, index) { function removeFileFromList(index, isTabItem) {
try { try {
if(isActive && index-1 === -1) { if(isTabItem) {
userData.files[index+1][0] = 1; let newItemIndex;
} else if(isActive && index-1 >= 0) { userData.files[index][0] = 0;
userData.files[index-1][0] = 1; userData.files[index][2] = 0;
newItemIndex = userData.files.findIndex(file => {
return file[2] === 1;
});
if(newItemIndex >= 0) {
userData.files[newItemIndex][0] = 1;
userData.files[newItemIndex][2] = 1;
resetFilters(true).then(function(response) {
console.log(response);
setUserData("files", userData.files);
window.api.send("startFileWatcher", [userData.files[newItemIndex][1], 1]);
}).catch(function(error) {
handleError(error);
});
} else {
userData.files[index][0] = 0;
userData.files[index][2] = 0;
setUserData("files", userData.files);
if(userData.files.length>0) generateFileList();
showOnboarding(true);
}
} else {
if(userData.files[index][0]) {
showOnboarding(true);
}
userData.files.splice(index, 1);
setUserData("files", userData.files);
} }
userData.files.splice(index, 1);
setUserData("files", userData.files);
resetFilters(true).then(function(response) {
console.info(response);
index = userData.files.findIndex(file => file[0] === 1);
window.api.send("startFileWatcher", userData.files[index][1]);
}).catch(function(error) {
handleError(error);
});
return Promise.resolve("Success: File removed from list"); return Promise.resolve("Success: File removed from list");
} catch (error) { } catch (error) {
return Promise.reject(error); return Promise.reject(error);
...@@ -38,7 +55,7 @@ function selectFileFromList(index) { ...@@ -38,7 +55,7 @@ function selectFileFromList(index) {
handleError(error); handleError(error);
}); });
resetModal().then(response => { resetModal().then(response => {
window.api.send("startFileWatcher", userData.files[index][1]); window.api.send("startFileWatcher", [userData.files[index][1], 1]);
console.info(response); console.info(response);
}).catch(error => { }).catch(error => {
handleError(error); handleError(error);
...@@ -51,40 +68,43 @@ function selectFileFromList(index) { ...@@ -51,40 +68,43 @@ function selectFileFromList(index) {
function generateFileList() { function generateFileList() {
try { try {
if(userData.files.length>1 && userData.fileTabs) { fileTabBar.classList.remove("is-active");
fileTabBar.classList.add("is-active");
} else {
fileTabBar.classList.remove("is-active");
}
fileTabBarList.innerHTML = null; fileTabBarList.innerHTML = null;
modalChangeFileTable.innerHTML = null; modalChangeFileTable.innerHTML = null;
modalChangeFileTable.classList.add("files"); modalChangeFileTable.classList.add("files");
let j = 0;
for (let i = 0; i < userData.files.length; i++) { for (let i = 0; i < userData.files.length; i++) {
let isActive = userData.files[i][0]; let isActive = userData.files[i][0];
let fileName = userData.files[i][1].split("/").pop(); let isTabItem = userData.files[i][2];
if(appData.os === "windows") fileName = userData.files[i][1].split("\\").pop(); if(isTabItem) {
let listItem = document.createElement("li"); j++;
listItem.innerHTML = fileName; let fileName = userData.files[i][1].split("/").pop();
listItem.innerHTML += "<i class=\"fas fa-minus-circle\"></i>"; if(j > 1 && userData.fileTabs) fileTabBar.classList.add("is-active");
if(isActive===1) listItem.classList.add("is-highlighted"); if(appData.os === "windows") fileName = userData.files[i][1].split("\\").pop();
listItem.querySelector("i").onclick = function() { let listItem = document.createElement("li");
removeFileFromList(isActive, i); listItem.setAttribute("title", userData.files[i][1]);
// trigger matomo event listItem.innerHTML = fileName;
if(userData.matomoEvents) _paq.push(["trackEvent", "File-Tab", "Click on remove icon"]); listItem.innerHTML += "<i class=\"fas fa-times\"></i>";
} if(isActive===1) listItem.classList.add("is-highlighted");
if(!isActive) { listItem.querySelector("i").onclick = function() {
listItem.onclick = function(event) { removeFileFromList(i, isTabItem);
if(event.target.classList.contains("fas")) return false;
selectFileFromList(i).then(function(response) {
console.info(response);
}).catch(function(error) {
handleError(error);
});
// trigger matomo event // trigger matomo event
if(userData.matomoEvents) _paq.push(["trackEvent", "File-Tab", "Click on tab"]); if(userData.matomoEvents) _paq.push(["trackEvent", "File-Tab", "Click on remove icon"]);
}
if(!isActive) {
listItem.onclick = function(event) {
if(event.target.classList.contains("fas")) return false;
selectFileFromList(i).then(function(response) {
console.info(response);
}).catch(function(error) {
handleError(error);
});
// trigger matomo event
if(userData.matomoEvents) _paq.push(["trackEvent", "File-Tab", "Click on tab"]);
}
} }
fileTabBarList.appendChild(listItem);
} }
fileTabBarList.appendChild(listItem);
let row = modalChangeFileTable.insertRow(-1); let row = modalChangeFileTable.insertRow(-1);
let cell1 = row.insertCell(0); let cell1 = row.insertCell(0);
let cell2 = row.insertCell(1); let cell2 = row.insertCell(1);
...@@ -107,7 +127,7 @@ function generateFileList() { ...@@ -107,7 +127,7 @@ function generateFileList() {
cell3.innerHTML = "<a href=\"#\" tabindex=\"0\"><i class=\"fas fa-minus-circle\"></i></a>"; cell3.innerHTML = "<a href=\"#\" tabindex=\"0\"><i class=\"fas fa-minus-circle\"></i></a>";
cell3.title = translations.delete; cell3.title = translations.delete;
cell3.onclick = function() { cell3.onclick = function() {
removeFileFromList(isActive, i); removeFileFromList(i);
generateFileList().then(response => { generateFileList().then(response => {
modalChangeFile.classList.add("is-active"); modalChangeFile.classList.add("is-active");
modalChangeFile.focus(); modalChangeFile.focus();
......
...@@ -155,7 +155,7 @@ function filterItems(items) { ...@@ -155,7 +155,7 @@ function filterItems(items) {
} }
// apply filters // apply filters
items = items.filter(function(item) { items = items.filter(function(item) {
if(!item.text && !item.h) return false; //if(!item.text && !item.h) return false;
if(!userData.showHidden && item.h) return false; if(!userData.showHidden && item.h) return false;
if(!userData.showCompleted && item.complete) return false; if(!userData.showCompleted && item.complete) return false;
if(!userData.showDueIsToday && item.due && isToday(item.due)) return false; if(!userData.showDueIsToday && item.due && isToday(item.due)) return false;
......
...@@ -370,12 +370,12 @@ function show(todo, templated) { ...@@ -370,12 +370,12 @@ function show(todo, templated) {
} }
function submitForm() { function submitForm() {
try { try {
if(userData.file === undefined) { // if(userData.file === undefined) {
modalFormAlert.innerHTML = translations.formErrorWritingFile; // modalFormAlert.innerHTML = translations.formErrorWritingFile;
modalFormAlert.parentElement.classList.remove("is-active", 'is-danger'); // modalFormAlert.parentElement.classList.remove("is-active", 'is-danger');
modalFormAlert.parentElement.classList.add("is-active", 'is-warning'); // modalFormAlert.parentElement.classList.add("is-active", 'is-warning');
return Promise.resolve("Info: No todo.txt defined yet"); // return Promise.resolve("Info: No todo.txt defined yet");
} // }
// check if there is an input in the text field, otherwise indicate it to the user // check if there is an input in the text field, otherwise indicate it to the user
// input value and data item are the same, nothing has changed, nothing will be written // input value and data item are the same, nothing has changed, nothing will be written
if(modalForm.getAttribute("data-item") === document.getElementById("modalFormInput").value) { if(modalForm.getAttribute("data-item") === document.getElementById("modalFormInput").value) {
...@@ -440,7 +440,7 @@ function submitForm() { ...@@ -440,7 +440,7 @@ function submitForm() {
} }
//write the data to the file //write the data to the file
// a newline character is added to prevent other todo.txt apps to append new todos to the last line // a newline character is added to prevent other todo.txt apps to append new todos to the last line
window.api.send("writeToFile", [items.objects.join("\n").toString() + "\n", userData.file]); window.api.send("writeToFile", [items.objects.join("\n").toString() + "\n"]);
// close and reset any modal // close and reset any modal
resetModal().then(function(result) { resetModal().then(function(result) {
console.log(result); console.log(result);
...@@ -449,11 +449,11 @@ function submitForm() { ...@@ -449,11 +449,11 @@ function submitForm() {
}); });
// trigger matomo event // trigger matomo event
if(userData.matomoEvents) _paq.push(["trackEvent", "Form", "Submit"]); if(userData.matomoEvents) _paq.push(["trackEvent", "Form", "Submit"]);
return Promise.resolve("Success: Changes written to file: " + userData.file); return Promise.resolve("Success: Changes written to file");
// if the input field is empty, let users know // if the input field is empty, let users know
} catch (error) { } catch (error) {
// if writing into file is denied throw alert // if writing into file is denied throw alert
modalFormAlert.innerHTML = translations.formErrorWritingFile + userData.file; modalFormAlert.innerHTML = translations.formErrorWritingFile;
modalFormAlert.parentElement.classList.add("is-active", 'is-danger'); modalFormAlert.parentElement.classList.add("is-active", 'is-danger');
error.functionName = submitForm.name; error.functionName = submitForm.name;
return Promise.reject(error); return Promise.reject(error);
......
...@@ -115,10 +115,10 @@ function configureTodoTableTemplate(append) { ...@@ -115,10 +115,10 @@ function configureTodoTableTemplate(append) {
function generateItems(content) { function generateItems(content) {
try { try {
items = { objects: TodoTxt.parse(content, [ new DueExtension(), new HiddenExtension(), new RecExtension(), new ThresholdExtension() ]) } items = { objects: TodoTxt.parse(content, [ new DueExtension(), new HiddenExtension(), new RecExtension(), new ThresholdExtension() ]) }
items.objects = items.objects.filter(function(item) { // items.objects = items.objects.filter(function(item) {
if(!item.text && !item.h) return false; // if(!item.text && !item.h) return false;
return true; // return true;
}); // });
items.complete = items.objects.filter(function(item) { return item.complete === true }); items.complete = items.objects.filter(function(item) { return item.complete === true });
items.incomplete = items.objects.filter(function(item) { return item.complete === false }); items.incomplete = items.objects.filter(function(item) { return item.complete === false });
items.objects = items.objects.filter(function(item) { return item.toString() != "" }); items.objects = items.objects.filter(function(item) { return item.toString() != "" });
...@@ -538,16 +538,18 @@ function addTodo(todo) { ...@@ -538,16 +538,18 @@ function addTodo(todo) {
} }
async function archiveTodos() { async function archiveTodos() {
try { try {
const index = userData.files.findIndex(file => file[0]===1);
const file = userData.files[index][1];
// cancel operation if there are no completed todos // cancel operation if there are no completed todos
if(items.complete.length===0) return Promise.resolve("Info: No completed todos found, nothing will be archived") if(items.complete.length===0) return Promise.resolve("Info: No completed todos found, nothing will be archived")
// if user archives within done.txt file, operating is canceled // if user archives within done.txt file, operating is canceled
if(userData.file.includes("_done.")) return Promise.resolve("Info: Current file seems to be a done.txt file, won't archive") if(file.includes("_done.")) return Promise.resolve("Info: Current file seems to be a done.txt file, won't archive")
// define path to done.txt // define path to done.txt
let doneFile = function() { let doneFile = function() {
if(appData.os==="windows") { if(appData.os==="windows") {
return userData.file.replace(userData.file.split("\\").pop(), userData.file.substr(0, userData.file.lastIndexOf(".")).split("\\").pop() + "_done.txt"); return file.replace(file.split("\\").pop(), file.substr(0, file.lastIndexOf(".")).split("\\").pop() + "_done.txt");
} else { } else {
return userData.file.replace(userData.file.split("/").pop(), userData.file.substr(0, userData.file.lastIndexOf(".")).split("/").pop() + "_done.txt"); return file.replace(file.split("/").pop(), file.substr(0, file.lastIndexOf(".")).split("/").pop() + "_done.txt");
} }
} }
const getContentFromDoneFile = new Promise(function(resolve) { const getContentFromDoneFile = new Promise(function(resolve) {
...@@ -573,7 +575,7 @@ async function archiveTodos() { ...@@ -573,7 +575,7 @@ async function archiveTodos() {
//write completed items to done file //write completed items to done file
window.api.send("writeToFile", [contentForDoneFile.join("\n").toString() + "\n", doneFile()]); window.api.send("writeToFile", [contentForDoneFile.join("\n").toString() + "\n", doneFile()]);
// write incompleted items to todo file // write incompleted items to todo file
window.api.send("writeToFile", [items.incomplete.join("\n").toString() + "\n", userData.file]); window.api.send("writeToFile", [items.incomplete.join("\n").toString() + "\n", file]);
// send notifcation on success // send notifcation on success
generateNotification(null, null, translations.archivingCompletedTitle, translations.archivingCompletedBody + doneFile()); generateNotification(null, null, translations.archivingCompletedTitle, translations.archivingCompletedBody + doneFile());
......
...@@ -123,7 +123,7 @@ const createWindow = async function() { ...@@ -123,7 +123,7 @@ const createWindow = async function() {
userData.data.path = path.dirname(file); userData.data.path = path.dirname(file);
userData.set("path", userData.data.path); userData.set("path", userData.data.path);
console.info("Success: Opened file: " + file); console.info("Success: Opened file: " + file);
startFileWatcher(file).then(response => { startFileWatcher(file, 1).then(response => {
console.info(response); console.info(response);
mainWindow.webContents.send("triggerFunction", "resetModal") mainWindow.webContents.send("triggerFunction", "resetModal")
}).catch(error => { }).catch(error => {
...@@ -153,7 +153,7 @@ const createWindow = async function() { ...@@ -153,7 +153,7 @@ const createWindow = async function() {
userData.data.path = path.dirname(file.filePath); userData.data.path = path.dirname(file.filePath);
userData.set("path", userData.data.path); userData.set("path", userData.data.path);
console.info("Success: New file created: " + file.filePath); console.info("Success: New file created: " + file.filePath);
startFileWatcher(file.filePath).then(response => { startFileWatcher(file.filePath, 1).then(response => {
console.info(response); console.info(response);
mainWindow.webContents.send("triggerFunction", "resetModal") mainWindow.webContents.send("triggerFunction", "resetModal")
}).catch(error => { }).catch(error => {
...@@ -167,14 +167,13 @@ const createWindow = async function() { ...@@ -167,14 +167,13 @@ const createWindow = async function() {
break; break;
} }
} }
const startFileWatcher = function(file) { const startFileWatcher = function(file, isTabItem) {
try { try {
if(!fs.existsSync(file)) throw("Error: File not found on disk") if(!fs.existsSync(file)) throw("Error: File not found on disk")
// skip persisted files and go with ENV if set // skip persisted files and go with ENV if set
if(process.env.SLEEK_CUSTOM_FILE && fs.existsSync(process.env.SLEEK_CUSTOM_FILE)) { if(process.env.SLEEK_CUSTOM_FILE && fs.existsSync(process.env.SLEEK_CUSTOM_FILE)) {
file = process.env.SLEEK_CUSTOM_FILE; file = process.env.SLEEK_CUSTOM_FILE;
} }
let args;
if (process.defaultApp) { if (process.defaultApp) {
// electron "unbundled" app -- have to skip "electron" and script name arg eg: "." // electron "unbundled" app -- have to skip "electron" and script name arg eg: "."
args = process.argv.slice(2); args = process.argv.slice(2);
...@@ -192,6 +191,7 @@ const createWindow = async function() { ...@@ -192,6 +191,7 @@ const createWindow = async function() {
// if path is found it is set active // if path is found it is set active
if(element[1]===file) { if(element[1]===file) {
element[0] = 1 element[0] = 1
if(isTabItem) element[2] = 1;
fileFound = true; fileFound = true;
// if this entry is not equal to the new path it is set 0 // if this entry is not equal to the new path it is set 0
} else { } else {
...@@ -202,10 +202,10 @@ const createWindow = async function() { ...@@ -202,10 +202,10 @@ const createWindow = async function() {
userData.data.files = new Array; userData.data.files = new Array;
} }
// only push new path if it is not already in the user data // only push new path if it is not already in the user data
if((!fileFound || !userData.data.files) && file) userData.data.files.push([1, file]); if((!fileFound || !userData.data.files) && file) userData.data.files.push([1, file, 1]);
userData.set("files", userData.data.files); userData.set("files", userData.data.files);
userData.data.file = file; //userData.data.file = file;
userData.set("file", file); //userData.set("file", file);
// TODO describe // TODO describe
if(fileWatcher) fileWatcher.close(); if(fileWatcher) fileWatcher.close();
fileWatcher = chokidar.watch(file); fileWatcher = chokidar.watch(file);
...@@ -589,7 +589,7 @@ const createWindow = async function() { ...@@ -589,7 +589,7 @@ const createWindow = async function() {
type: "radio", type: "radio",
checked: false, checked: false,
click: function() { click: function() {
startFileWatcher(file[1]); startFileWatcher(file[1], 1);
mainWindow.show(); mainWindow.show();
mainWindow.setSkipTaskbar(true); mainWindow.setSkipTaskbar(true);
} }
...@@ -694,8 +694,15 @@ const createWindow = async function() { ...@@ -694,8 +694,15 @@ const createWindow = async function() {
}) })
.on("writeToFile", function(event, args) { .on("writeToFile", function(event, args) {
try { try {
let file;
if(!args[1]) {
const index = userData.data.files.findIndex(file => file[0] ===1 );
file = userData.data.files[index][1];
} else {
file = args[1];
}
// Write content to file // Write content to file
fs.writeFileSync(args[1], args[0], {encoding: "utf-8"}); if(file) fs.writeFileSync(file, args [0], {encoding: "utf-8"});
} catch(error) { } catch(error) {
console.error(error); console.error(error);
error.functionName = "fs.writeFileSync"; error.functionName = "fs.writeFileSync";
...@@ -708,8 +715,8 @@ const createWindow = async function() { ...@@ -708,8 +715,8 @@ const createWindow = async function() {
.on("openOrCreateFile", (event, args) => { .on("openOrCreateFile", (event, args) => {
openDialog(args); openDialog(args);
}) })
.on("startFileWatcher", (event, file) => { .on("startFileWatcher", (event, data) => {
startFileWatcher(file).then(response => { startFileWatcher(data[0], data[1]).then(response => {
console.info(response); console.info(response);
}).catch(error => { }).catch(error => {
console.error(error); console.error(error);
...@@ -763,8 +770,9 @@ const createWindow = async function() { ...@@ -763,8 +770,9 @@ const createWindow = async function() {
// REFRESH WHEN IN BACKGROUND // REFRESH WHEN IN BACKGROUND
// ######################################################################################################################## // ########################################################################################################################
setInterval(() => { setInterval(() => {
if(userData.data.file && !mainWindow.isFocused()) { if(userData.data.files.length > 0 && !mainWindow.isFocused()) {
getContent(userData.data.file).then(content => { const index = userData.data.files.findIndex(file => file[0] ===1 );
getContent(userData.data.files[index][1]).then(content => {
mainWindow.webContents.send("refresh", [content]) mainWindow.webContents.send("refresh", [content])
}).catch(error => { }).catch(error => {
console.error(error); console.error(error);
......
...@@ -134,19 +134,19 @@ function configureMainView() { ...@@ -134,19 +134,19 @@ function configureMainView() {
handleError(error); handleError(error);
}); });
// configure table view // configure table view
if(userData.file && todos.items.objects.length===0) { if(todos.items.objects.length===0) {
addTodoContainer.classList.add("is-active"); addTodoContainer.classList.add("is-active");
todoTableSearchContainer.classList.remove("is-active"); todoTableSearchContainer.classList.remove("is-active");
todoTable.classList.remove("is-active"); todoTable.classList.remove("is-active");
noResultContainer.classList.remove("is-active"); noResultContainer.classList.remove("is-active");
return Promise.resolve("Info: File is empty"); return Promise.resolve("Info: File is empty");
} else if(userData.file && todos.items.filtered.length===0) { } else if(todos.items.filtered.length===0) {
addTodoContainer.classList.remove("is-active"); addTodoContainer.classList.remove("is-active");
todoTableSearchContainer.classList.add("is-active"); todoTableSearchContainer.classList.add("is-active");
noResultContainer.classList.add("is-active"); noResultContainer.classList.add("is-active");
return Promise.resolve("Info: No results"); return Promise.resolve("Info: No results");
// TODO explain // TODO explain
} else if(userData.file && todos.items.filtered.length>0) { } else if(todos.items.filtered.length>0) {
todoTableSearchContainer.classList.add("is-active"); todoTableSearchContainer.classList.add("is-active");
addTodoContainer.classList.remove("is-active"); addTodoContainer.classList.remove("is-active");
noResultContainer.classList.remove("is-active"); noResultContainer.classList.remove("is-active");
...@@ -318,7 +318,19 @@ function registerEvents() { ...@@ -318,7 +318,19 @@ function registerEvents() {
if(userData.matomoEvents) matomo._paq.push(["trackEvent", "Onboarding", "Click on Create file"]); if(userData.matomoEvents) matomo._paq.push(["trackEvent", "Onboarding", "Click on Create file"]);
} }
btnOnboardingOpenTodoFile.onclick = function() { btnOnboardingOpenTodoFile.onclick = function() {
window.api.send("openOrCreateFile", "open"); //TODO: thhis is a duplicate
if(typeof userData.files === "object" && userData.files.length>0) {
files.generateFileList().then(response => {
console.info(response);
modalChangeFile.classList.add("is-active");
modalChangeFile.focus();
createModalJail(modalChangeFile);
}).catch(error => {
handleError(error);
});
} else {
window.api.send("openOrCreateFile", "open");
}
// trigger matomo event // trigger matomo event
if(userData.matomoEvents) matomo._paq.push(["trackEvent", "Onboarding", "Click on Open file"]); if(userData.matomoEvents) matomo._paq.push(["trackEvent", "Onboarding", "Click on Open file"]);
} }
...@@ -386,37 +398,40 @@ function registerKeyboardShortcuts() { ...@@ -386,37 +398,40 @@ function registerKeyboardShortcuts() {
} }
// close tab or window // close tab or window
if((event.ctrlKey || event.metaKey) && event.key === "w") { if((event.ctrlKey || event.metaKey) && event.key === "w") {
if(userData.files.length > 1) { const isTabFound = userData.files.findIndex(file => {
return file[2] === 1;
});
if(isTabFound >= 0) {
let index = userData.files.findIndex(file => file[0] === 1); let index = userData.files.findIndex(file => file[0] === 1);
files.removeFileFromList(1, index); files.removeFileFromList(index, 1);