Commit 3604d513 authored by ransome1's avatar ransome1
Browse files

Merge branch 'develop'

parents ece9499e 3eea20d2
......@@ -22,3 +22,4 @@ squashfs-root/
package-lock.json
.vs/
.vscode/
.yarnclean
......@@ -109,6 +109,9 @@ A prioritized backlog of new features and known issues can be found <a href="htt
- Simplified Chinese
- Brazilian Portugese
- Japanese
- Turkish
- Hungarian
- Czech
* sleek can be minimized to tray
* Existing todos can be used as templates for new ones
......
......@@ -6,7 +6,7 @@ The following versions of sleek are provided with security updates.
| Version | Supported |
| ------- | ------------------ |
| 1.0.x | :heavy_check_mark: |
| 1.1.x | :heavy_check_mark: |
## Reporting a Vulnerability
......
{
"name": "sleek",
"productName": "sleek",
<<<<<<< HEAD
"version": "1.1.0",
=======
"version": "1.1.3",
>>>>>>> develop
"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",
"category": "ProjectManagement",
......@@ -102,7 +106,11 @@
"pack": "yarn build:css && yarn build:pegjs && electron-builder --dir",
"lint": "eslint --ext .js, src --ext .mjs, src",
"test": "mocha --timeout 10000",
<<<<<<< HEAD
"test1": "mocha ./test/createTodos.js --timeout 10000",
=======
"test1": "mocha ./test/todoModal.js --timeout 10000",
>>>>>>> develop
"sass": "sass -w src/scss/style.scss:src/css/style.css",
"start": "yarn sass & electron ."
},
......@@ -120,11 +128,11 @@
"vanillajs-datepicker": "^1.1.4"
},
"devDependencies": {
"peggy": "^1.2.0",
"electron": "12.0.10",
"electron": "12.1.0",
"electron-builder": "^22.11.7",
"eslint": "^7.25.0",
"mocha": "^9.0.0",
"peggy": "^1.2.0",
"sass": "^1.34.1",
"spectron": "14.0.0"
}
......
name: sleek
base: core18
<<<<<<< HEAD
version: '1.1.0'
=======
version: '1.1.3'
>>>>>>> develop
summary: Todo app based on the todo.txt format for Linux, free and open-source
description: |
sleek is an open-source todo app that makes use of the todo.txt format. sleeks GUI is modern and simple but still offers a decent set of functions which help users getting things done. sleek is available as a client for Windows, MacOS and Linux.
......
......@@ -7,7 +7,7 @@ const i18nextOptions = {
fallbackLng: "en",
namespace: "translation",
defaultNS: "translation",
supportedLngs: ["de", "en", "it", "es", "fr", "zh", "pt", "jp"],
supportedLngs: ["de", "en", "it", "es", "fr", "zh", "pt", "jp", "tr", "hu", "cs"],
debug: false,
preload: fs.readdirSync(path.join(__dirname, "../locales")).filter((fileName) => {
const joinedPath = path.join(path.join(__dirname, "../locales"), fileName)
......
This diff is collapsed.
This diff is collapsed.
......@@ -380,7 +380,7 @@
<footer class="card-footer">
<button id="btnSave" class="card-footer-item" tabindex="0"></button>
<button id="btnItemStatus" class="card-footer-item" tabindex="0"></button>
<button class="card-footer-item" role="cancel" tabindex="0"></button>
<button id="btnCancel" class="card-footer-item" role="cancel" tabindex="0"></button>
</footer>
</div>
</div>
......@@ -665,7 +665,7 @@
<tr>
<td id="helpTabKeyboardTR14TD1"></td>
<td><span class="tag is-dark is-large">Alt</span>&nbsp;<i class="fas fa-plus"></i>&nbsp;<span class="tag is-info is-large"><i class="fas fa-arrow-left"></i>&nbsp;/&nbsp;<i class="fas fa-arrow-right"></i></span></td>
<td><span class="tag is-dark is-large">Alt</span>&nbsp;<i class="fas fa-plus"></i>&nbsp;<span class="tag is-info is-large"><i class="fas fa-arrow-left"></i>&nbsp;/&nbsp;<i class="fas fa-arrow-right"></i></span></td>
<td></td>
</tr>
<tr>
<td id ="helpTabKeyboardTR15TD1"></td>
......
......@@ -240,6 +240,15 @@ function setFriendlyLanguageNames() {
case "jp":
friendlyLanguageName = "日本語"
break;
case "tr":
friendlyLanguageName = "Türkçe"
break;
case "hu":
friendlyLanguageName = "Magyar"
break;
case "cs":
friendlyLanguageName = "Čeština"
break;
default:
return;
}
......
......@@ -55,11 +55,11 @@ function selectFileFromList(index) {
handleError(error);
});
resetModal().then(response => {
window.api.send("startFileWatcher", [userData.files[index][1], 1]);
console.info(response);
}).catch(error => {
handleError(error);
});
window.api.send("startFileWatcher", [userData.files[index][1], 1]);
return Promise.resolve("Success: File selected");
} catch (error) {
return Promise.reject(error);
......
......@@ -3,6 +3,7 @@ import { userData, handleError, translations, setUserData, startBuilding, getCon
import { createModalJail } from "../configs/modal.config.mjs";
import { _paq } from "./matomo.mjs";
import { items } from "./todos.mjs";
import { getCaretPosition } from "./form.mjs";
import { showContent } from "./content.mjs";
import { isToday, isPast, isFuture } from "./date.mjs";
import * as filterlang from "./filterlang.mjs";
......@@ -33,6 +34,14 @@ filterContextInput.addEventListener("keydown", (event) => {
if(event.code==="Space") event.preventDefault();
})
autoCompleteContainer.addEventListener("keyup", (event) => {
// if there is only one filter shown it will be selected automatically
if(event.code==="Tab" && Object.keys(filtersCounted).length === 1) {
addFilterToInput(Object.keys(filtersCounted)[0], event.target.getAttribute("data-prefix"));
}
})
function saveFilter(newFilter, oldFilter, category) {
try {
items.objects.forEach((item) => {
......@@ -82,6 +91,7 @@ function deleteFilter(filter, category) {
}
function filterItems(items) {
try {
// TODO: this is a duplicate in todos.mjs
// selected filters are empty, unless they were persisted
if(userData.selectedFilters && userData.selectedFilters.length>0) {
selectedFilters = JSON.parse(userData.selectedFilters);
......@@ -365,11 +375,14 @@ function generateFilterData(autoCompleteCategory, autoCompleteValue, autoComplet
// TODO can this be done above already?
// remove empty filter entries
filters = filters.filter(function(filter) {
//console.log(filter[0]);
if(filter[0]) return filter;
});
// Cancel if autcomplete container and no filters available
if(filters.length === 0 && autoCompletePrefix) {
return;
}
// build filter buttons and add them to a fragment
let filterFragment = await generateFilterButtons(category, autoCompleteValue, autoCompletePrefix, caretPosition).then(response => {
let filterFragment = await generateFilterButtons(category, autoCompletePrefix).then(response => {
return response;
}).catch (error => {
handleError(error);
......@@ -408,8 +421,37 @@ function selectFilter(filter, category) {
setUserData("selectedFilters", JSON.stringify(selectedFilters));
startBuilding();
}
function generateFilterButtons(category, autoCompleteValue, autoCompletePrefix, caretPosition) {
function addFilterToInput(filter, autoCompletePrefix) {
let modalFormInput = document.getElementById("modalFormInput");
let caretPosition = getCaretPosition(modalFormInput);
// split string into elements
let inputElements = modalFormInput.value.split(" ");
let i;
let x = 0;
for(i = 0; i < inputElements.length; i++) {
x += inputElements[i].length + 1;
// once caret position is found inside element the index is persisted
if(x > caretPosition) break;
}
inputElements.splice(i, 1, autoCompletePrefix + filter + " ");
modalFormInput.value = inputElements.join(" ");
// empty autoCompleteValue to prevent multiple inputs using multiple Enter presses
autoCompletePrefix = null;
// hide the suggestion container after the filter has been selected
autoCompleteContainer.blur();
autoCompleteContainer.classList.remove("is-active");
// put focus back into input so user can continue writing
modalFormInput.focus();
// trigger matomo event
if(userData.matomoEvents) _paq.push(["trackEvent", "Suggestion-box", "Click on filter tag", category]);
}
function generateFilterButtons(category, autoCompletePrefix) {
try {
let caretPosition = getCaretPosition(document.getElementById("modalFormInput"));
// create a fragment to collect the filters in
let filterFragment = document.createDocumentFragment();
// build one button each
......@@ -420,6 +462,7 @@ function generateFilterButtons(category, autoCompleteValue, autoCompletePrefix,
if(category==="priority") todoFiltersItem.classList.add(filter);
todoFiltersItem.setAttribute("data-filter", filter);
todoFiltersItem.setAttribute("data-category", category);
todoFiltersItem.setAttribute("data-prefix", autoCompletePrefix);
if(autoCompletePrefix===undefined) { todoFiltersItem.setAttribute("tabindex", 0) } else { todoFiltersItem.setAttribute("tabindex", 0) }
todoFiltersItem.innerHTML = filter;
if(autoCompletePrefix==undefined) {
......@@ -483,33 +526,7 @@ function generateFilterButtons(category, autoCompleteValue, autoCompletePrefix,
} else {
// add filter to input
todoFiltersItem.addEventListener("click", (event) => {
if(autoCompletePrefix && autoCompleteValue) {
// split string into elements
let inputElements = document.getElementById("modalFormInput").value.split(" ");
let i;
let x = 0;
for(i = 0; i < inputElements.length; i++) {
x += inputElements[i].length + 1;
// once caret position is found inside element the index is persisted
if(x > caretPosition) break;
}
// replace value at index with prefix and data attribute of filter
inputElements.splice(i, 1, autoCompletePrefix + todoFiltersItem.getAttribute("data-filter"));
document.getElementById("modalFormInput").value = inputElements.join(" ");
} else if(autoCompletePrefix) {
// add button data value to the exact caret position
document.getElementById("modalFormInput").value = [document.getElementById("modalFormInput").value.slice(0, caretPosition), todoFiltersItem.getAttribute('data-filter'), document.getElementById("modalFormInput").value.slice(caretPosition)].join('') + " ";
}
// empty autoCompleteValue to prevent multiple inputs using multiple Enter presses
autoCompleteValue = null;
autoCompletePrefix = null;
// hide the suggestion container after the filter has been selected
autoCompleteContainer.blur();
autoCompleteContainer.classList.remove("is-active");
// put focus back into input so user can continue writing
document.getElementById("modalFormInput").focus();
// trigger matomo event
if(userData.matomoEvents) _paq.push(["trackEvent", "Suggestion-box", "Click on filter tag", category]);
addFilterToInput(todoFiltersItem.getAttribute("data-filter"), autoCompletePrefix);
});
}
filterCounter++;
......
......@@ -5,7 +5,7 @@ import { _paq } from "./matomo.mjs";
import { RecExtension, SugarDueExtension, ThresholdExtension } from "./todotxtExtensions.mjs";
import { generateFilterData } from "./filters.mjs";
import { items, item, setTodoComplete } from "./todos.mjs";
import { datePickerInput } from "./datePicker.mjs";
import { datePickerInput, datePicker } from "./datePicker.mjs";
import { createModalJail } from "../configs/modal.config.mjs";
import * as recurrencePicker from "./recurrencePicker.mjs";
......@@ -232,7 +232,7 @@ function setPriority(priority) {
}
function setDueDate(days) {
try {
const todo = new TodoTxtItem(document.getElementById("modalFormInput").value, [ new DueExtension() ]);
const todo = new TodoTxtItem(document.getElementById("modalFormInput").value, [ new DueExtension(), new HiddenExtension(), new RecExtension(), new ThresholdExtension() ]);
if(days===0) {
todo.due = undefined;
todo.dueString = undefined;
......@@ -243,6 +243,10 @@ function setDueDate(days) {
todo.due = new Date(new Date().setDate(new Date().getDate() + days));
todo.dueString = todo.due.toISOString().substr(0, 10);
}
datePicker.setDate( todo.due );
document.getElementById("modalFormInput").value = todo.toString();
return Promise.resolve("Success: Due date changed to " + todo.dueString)
} catch(error) {
......@@ -252,8 +256,6 @@ function setDueDate(days) {
}
function show(todo, templated) {
try {
// switch to textarea if needed
if(userData.useTextarea) toggleInputSize("input");
// remove any previously set data-item attributes
//modalForm.removeAttribute("data-item");
modalForm.setAttribute("data-item", "");
......@@ -288,11 +290,13 @@ function show(todo, templated) {
modalForm.setAttribute("data-item", todo.toString());
// this is an existing todo task to be edited
// replace special char with line breaks before passing it to textarea
if(userData.useTextarea) document.getElementById("modalFormInput").value = todo.toString().replaceAll(String.fromCharCode(16),"\r\n");
//if(userData.useTextarea) document.getElementById("modalFormInput").value = todo.toString().replaceAll(String.fromCharCode(16),"\r\n");
// replace special char with space before passing it to regular input
if(!userData.useTextarea) document.getElementById("modalFormInput").value = todo.toString().replaceAll(String.fromCharCode(16)," ");
//if(!userData.useTextarea) document.getElementById("modalFormInput").value = todo.toString().replaceAll(String.fromCharCode(16)," ");
//document.getElementById("modalFormInput").value = todo.toString();
//modalTitle.innerHTML = translations.editTodo;
document.getElementById("modalFormInput").value = todo.toString();
btnItemStatus.classList.remove("is-hidden");
}
// only show the complete button on open items
......@@ -317,6 +321,8 @@ function show(todo, templated) {
//modalTitle.innerHTML = translations.addTodo;
btnItemStatus.classList.add("is-hidden");
}
// switch to textarea if needed
if(userData.useTextarea) toggleInputSize("input");
// adjust size of picker inputs
resizeInput(datePickerInput);
resizeInput(recurrencePickerInput);
......@@ -427,15 +433,28 @@ function submitForm() {
function toggleInputSize(type) {
let newInputElement;
let value = "";
if(document.getElementById("modalFormInput").value!=="") {
value = document.getElementById("modalFormInput").value.replaceAll("\n", String.fromCharCode(16));
} /*else if(modalForm.getAttribute("data-item")!=="") {
value = modalForm.getAttribute("data-item").replaceAll("\n", String.fromCharCode(16));
}*/
//modalForm.setAttribute("data-item", document.getElementById("modalFormInput").value);
switch (type) {
case "input":
newInputElement = document.createElement("textarea");
newInputElement.value = value.replaceAll(String.fromCharCode(16),"\r\n");
modalFormInputResize.setAttribute("data-input-type", "textarea");
modalFormInputResize.innerHTML = "<i class=\"fas fa-compress-alt\"></i>";
setUserData("useTextarea", true);
break;
case "textarea":
newInputElement = document.createElement("input");
//newInputElement.value = value.replaceAll(String.fromCharCode(16)," ");
newInputElement.value = value;
newInputElement.type = "text";
modalFormInputResize.setAttribute("data-input-type", "input");
modalFormInputResize.innerHTML = "<i class=\"fas fa-expand-alt\"></i>";
......@@ -445,18 +464,25 @@ function toggleInputSize(type) {
newInputElement.id = "modalFormInput";
newInputElement.setAttribute("tabindex", 0);
newInputElement.setAttribute("class", "input is-medium");
// if(userData.useTextarea) {
// value.replaceAll(String.fromCharCode(16),"\r\n");
// } else {
// value.replaceAll(String.fromCharCode(16)," ");
// }
//newInputElement.value = value;
// replace old element with the new one
document.getElementById("modalFormInput").replaceWith(newInputElement);
// replace special char with line break before passing it to textarea
if(userData.useTextarea && modalForm.getAttribute("data-item")) document.getElementById("modalFormInput").value = document.getElementById("modalForm").getAttribute("data-item").replaceAll(String.fromCharCode(16),"\r\n");
//if(userData.useTextarea && modalForm.getAttribute("data-item")) document.getElementById("modalFormInput").value = document.getElementById("modalForm").getAttribute("data-item").replaceAll(String.fromCharCode(16),"\r\n");
// replace special char with space before passing it to regular input
if(!userData.useTextarea && modalForm.getAttribute("data-item")) document.getElementById("modalFormInput").value = document.getElementById("modalForm").getAttribute("data-item").replaceAll(String.fromCharCode(16)," ");
//if(!userData.useTextarea && modalForm.getAttribute("data-item")) document.getElementById("modalFormInput").value = document.getElementById("modalForm").getAttribute("data-item").replaceAll(String.fromCharCode(16)," ");
positionAutoCompleteContainer();
resizeInput(document.getElementById("modalFormInput"));
// document.getElementById("modalFormInput").addEventListener("keyup", () => {
// modalFormInputEvent();
// });
document.getElementById("modalFormInput").onfocus = function() {
modalForm.classList.add("is-focused");
}
......@@ -484,4 +510,4 @@ window.onresize = function() {
}
}
export { show, resizeInput, setPriority, setDueDate, submitForm, toggleInputSize};
export { show, resizeInput, setPriority, setDueDate, submitForm, toggleInputSize, getCaretPosition};
......@@ -2,7 +2,7 @@
import "../../node_modules/jstodotxt/jsTodoExtensions.js";
import { getActiveFile, userData, appData, handleError, translations, setUserData, startBuilding, getConfirmation, resetModal } from "../render.js";
import { _paq } from "./matomo.mjs";
import { categories } from "./filters.mjs";
import { categories, selectFilter } from "./filters.mjs";
import { generateRecurrence } from "./recurrences.mjs";
import { convertDate, isToday, isTomorrow, isPast } from "./date.mjs";
import { show } from "./form.mjs";
......@@ -47,7 +47,7 @@ const tableContainerContent = document.createDocumentFragment();
const todoTableBodyRowTemplate = document.createElement("div");
const todoTableBodyCellCheckboxTemplate = document.createElement("div");
const todoTableBodyCellTextTemplate = document.createElement("a");
const tableContainerCategoriesTemplate = document.createElement("span");
const tableContainerCategoriesTemplate = document.createElement("div");
const todoTableBodyCellPriorityTemplate = document.createElement("div");
const todoTableBodyCellDueDateTemplate = document.createElement("span");
const todoTableBodyCellRecurrenceTemplate = document.createElement("span");
......@@ -56,16 +56,15 @@ const todoTableBodyCellHiddenTemplate = document.createElement("span");
const item = { previous: "" }
let
items,
clusterCounter,
clusterSize = Math.ceil(window.innerHeight/30), // 35 being the pixel height of one todo in compact mode
clusterThreshold = 0,
//stopBuilding = false,
visibleRows = 0;
clusterCounter = 0,
clusterSize = Math.ceil(window.innerHeight/32), // 32 being the pixel height of one todo in compact mode
clusterThreshold = clusterSize,
visibleRows,
todoRows;
todoTableWrapper.addEventListener("scroll", function(event) {
if(visibleRows>=items.filtered.length) return false;
if(Math.floor(event.target.scrollHeight - event.target.scrollTop) <= event.target.clientHeight) {
//stopBuilding = false;
startBuilding(true);
}
});
......@@ -89,21 +88,14 @@ function showResultStats() {
return Promise.reject(error);
}
}
function configureTodoTableTemplate(append) {
function configureTodoTableTemplate() {
try {
// setting up for the first cluster
if(!append) {
todoTable.innerHTML = "";
visibleRows = 0;
clusterThreshold = 0;
//stopBuilding = false;
}
todoTableBodyRowTemplate.setAttribute("class", "todo");
todoTableBodyCellCheckboxTemplate.setAttribute("class", "cell checkbox");
todoTableBodyCellTextTemplate.setAttribute("class", "cell text");
todoTableBodyCellTextTemplate.setAttribute("tabindex", 0);
todoTableBodyCellTextTemplate.setAttribute("href", "#");
tableContainerCategoriesTemplate.setAttribute("class", "categories");
tableContainerCategoriesTemplate.setAttribute("class", "cell categories");
todoTableBodyCellDueDateTemplate.setAttribute("class", "cell itemDueDate");
todoTableBodyCellRecurrenceTemplate.setAttribute("class", "cell recurrence");
return Promise.resolve("Success: Table templates set up");
......@@ -115,10 +107,6 @@ function configureTodoTableTemplate(append) {
function generateItems(content) {
try {
items = { objects: TodoTxt.parse(content, [ new DueExtension(), new HiddenExtension(), new RecExtension(), new ThresholdExtension() ]) }
// items.objects = items.objects.filter(function(item) {
// if(!item.text && !item.h) return false;
// return true;
// });
items.complete = items.objects.filter(function(item) { return item.complete === true });
items.incomplete = items.objects.filter(function(item) { return item.complete === false });
items.objects = items.objects.filter(function(item) { return item.toString() != "" });
......@@ -166,19 +154,17 @@ function generateGroups(items) {
});
return Promise.resolve(items)
}
async function generateTable(groups, append, loadAll) {
async function generateTable(groups, loadAll) {
try {
todoRows = new Array;
// TODO Overthink due to performance reasons
todoTable.textContent = "";
// configure stats
showResultStats();
// prepare the templates for the table
await configureTodoTableTemplate(append);
await configureTodoTableTemplate();
// reset cluster count for this run
clusterCounter = 0;
for (let group in groups) {
// if(stopBuilding) {
// stopBuilding = false;
// break;
// }
// create a divider row
let dividerRow;
// completed todos
......@@ -202,19 +188,9 @@ async function generateTable(groups, append, loadAll) {
} else {
dividerRow = document.createRange().createContextualFragment("<div class=\"group\"></div>")
}
// add divider row only if it doesn't exist yet
if(!append && !document.getElementById(userData.sortBy[0] + groups[group][0]) && dividerRow) tableContainerContent.appendChild(dividerRow);
if(!document.getElementById(userData.sortBy[0] + groups[group][0]) && dividerRow) todoRows.push(dividerRow);
for (let item in groups[group][1]) {
let todo = groups[group][1][item];
//TODO: Explain this, maybe refactor
if(!loadAll && clusterCounter<clusterThreshold) {
clusterCounter++;
continue;
} else if(!loadAll && (visibleRows===clusterSize+clusterThreshold) || visibleRows===items.filtered.length ) {
clusterThreshold = visibleRows;
//stopBuilding = true;
break;
}
// if this todo is not a recurring one the rec value will be set to null
if(!todo.rec) todo.rec = null;
// incompleted todos with due date
......@@ -234,9 +210,21 @@ async function generateTable(groups, append, loadAll) {
});
}
}
tableContainerContent.appendChild(generateTableRow(todo));
todoRows.push(generateTableRow(todo));
}
}
for (let row in todoRows) {
clusterCounter++;
visibleRows++;
if(clusterCounter === clusterThreshold) {
clusterThreshold = clusterThreshold + clusterCounter;
break;
} else if(visibleRows < clusterThreshold) {
continue;
}
tableContainerContent.appendChild(todoRows[row]);
}
clusterCounter = 0;
todoTable.appendChild(tableContainerContent);
return Promise.resolve("Success: Todo table generated");
} catch(error) {
......@@ -246,8 +234,6 @@ async function generateTable(groups, append, loadAll) {
}
function generateTableRow(todo) {
try {
clusterCounter++;
visibleRows++;
// create nodes from templates
let todoTableBodyRow = todoTableBodyRowTemplate.cloneNode(true);
let todoTableBodyCellCheckbox = todoTableBodyCellCheckboxTemplate.cloneNode(true);
......@@ -332,19 +318,6 @@ function generateTableRow(todo) {
if(userData.matomoEvents) _paq.push(["trackEvent", "Todo-Table", "Click on Todo item"]);
}
}
// cell for the categories
categories.forEach(category => {
if(todo[category] && category!="priority") {
todo[category].forEach(element => {
let todoTableBodyCellCategory = document.createElement("span");
todoTableBodyCellCategory.setAttribute("class", "tag " + category);
todoTableBodyCellCategory.innerHTML = element;
tableContainerCategories.appendChild(todoTableBodyCellCategory);
});
}
});
// only add the categories to text cell if it has child nodes
if(tableContainerCategories.hasChildNodes()) todoTableBodyCellText.appendChild(tableContainerCategories);
// check for and add a given due date
if(todo.due) {
var tag = convertDate(todo.due);
......@@ -372,8 +345,36 @@ function generateTableRow(todo) {
// append the due date to the text item
todoTableBodyCellText.appendChild(todoTableBodyCellRecurrence);
}
// add the text cell to the row
todoTableBodyRow.appendChild(todoTableBodyCellText);
// cell for the categories
categories.forEach(category => {
if(todo[category] && category!="priority") {
todo[category].forEach(element => {
let todoTableBodyCellCategory = document.createElement("a");
todoTableBodyCellCategory.setAttribute("class", "tag " + category);
todoTableBodyCellCategory.onclick = function() {
selectFilter(element, category);
}
todoTableBodyCellCategory.innerHTML = element;
// selected filters are empty, unless they were persisted
if(userData.selectedFilters && userData.selectedFilters.length>0) {
let selectedFilters = JSON.parse(userData.selectedFilters);
selectedFilters.forEach(function(item) {
if(JSON.stringify(item) === '["'+element+'","'+category+'"]') todoTableBodyCellCategory.classList.toggle("is-dark")
});
}
tableContainerCategories.appendChild(todoTableBodyCellCategory);
});
}
});
// only add the categories to text cell if it has child nodes
if(tableContainerCategories.hasChildNodes()) todoTableBodyRow.appendChild(tableContainerCategories);
todoTableBodyRow.addEventListener("contextmenu", event => {
//todoContextUseAsTemplate.focus();
todoContext.style.left = event.x + "px";
......@@ -455,7 +456,7 @@ function setTodoComplete(todo) {
todo.complete = false;
todo.completed = null;
// delete old item from array and add the new one at it's position
items.objects.splice(index, 1, todo);
//items.objects.splice(index, 1, todo);
// Mark item as complete
} else if(!todo.complete) {