From 883f5ec35d898502cbcd7646f1bf23d80fd4c515 Mon Sep 17 00:00:00 2001 From: Mathis Gauthey Date: Thu, 4 Jan 2024 11:09:25 +0100 Subject: [PATCH] update: add scripts -> taskCalendar modified and QuickAdd --- _Scripts/passionsync.js | 85 +++ _Scripts/projectsync.js | 96 ++++ _Scripts/somedaysync.js | 85 +++ _Scripts/tasksync.js | 96 ++++ _Scripts/view.css | 722 +++++++++++++++++++++++ _Scripts/view.js | 1207 +++++++++++++++++++++++++++++++++++++++ 6 files changed, 2291 insertions(+) create mode 100644 _Scripts/passionsync.js create mode 100644 _Scripts/projectsync.js create mode 100644 _Scripts/somedaysync.js create mode 100644 _Scripts/tasksync.js create mode 100644 _Scripts/view.css create mode 100644 _Scripts/view.js diff --git a/_Scripts/passionsync.js b/_Scripts/passionsync.js new file mode 100644 index 0000000..8d69346 --- /dev/null +++ b/_Scripts/passionsync.js @@ -0,0 +1,85 @@ +module.exports = { + SelectFromAllTasks: SelectFromAllTasks, + GetAllTasksFromProject: GetAllTasksFromProject, + GetAllTasksFromSection: GetAllTasksFromSection, +}; + +const getTodoistPluginApi = (t) => t.plugins.plugins["todoist-sync-plugin"].api; +async function SelectFromAllTasks(t) { + const s = await getAllTasks(t); + if (0 === s.length) return void new Notice("No tasks."); + const e = await selectTasks(t, s); + return await closeSelectedTasks(t.app, e), formatTasksToTasksPluginTask(e); +} +async function GetAllTasksFromProject(t) { + const [s, e] = await Promise.all([getAllTasks(t), getProjects(t.app)]), + a = await t.quickAddApi.suggester( + (t) => ( + (t.tasks = s.filter((s) => s.projectID === t.id)), + `${t.name} (${t.tasks.length})` + ), + e + ); + if (a) { + if (0 !== a.tasks.length) + return ( + new Notice(`Added ${a.tasks.length} tasks from '${a.name}'.`), + await closeSelectedTasks(t.app, a.tasks), + formatTasksToTasksPluginTask(a.tasks) + ); + new Notice(`No tasks in '${a.name}'.`); + } +} +async function GetAllTasksFromSection(t) { + const [s, e, a] = await Promise.all([ + getProjects(t.app), + getSections(t.app), + getAllTasks(t), + ]), + n = await t.quickAddApi.suggester((t) => { + const e = s.find((s) => s.id === t.project_id); + return ( + (t.tasks = a.filter((s) => s.sectionID === t.id)), + `${e.name} > ${t.name} (${t.tasks.length})` + ); + }, e); + if (0 !== n.tasks.length) + return ( + new Notice(`Added ${n.tasks.length} tasks from '${n.name}'.`), + await closeSelectedTasks(n.tasks), + formatTasksToTasksPluginTask(n.tasks) + ); + new Notice(`No tasks in '${n.name}'.`); +} +async function getAllTasks(t) { + const s = getTodoistPluginApi(t.app), + { ok: e } = await s.getTasks(); + return e; +} +async function selectTasks(t, s) { + const e = await t.quickAddApi.checkboxPrompt(s.map((t) => t.content)); + return s.filter((t) => e.some((s) => s.contains(t.content))); +} +async function closeSelectedTasks(t, s) { + const e = getTodoistPluginApi(t); + s.forEach(async (t) => await e.closeTask(t.id)); +} +function formatTasksToTasksPluginTask(t) { + const todayDate = moment().format("YYYY-MM-DD HH:mm:ss"); + return t.map((t) => `- [ ] ${t.content}`).join("\n"); +} +async function getTasksGroupedByProject(t) { + const s = getTodoistPluginApi(t), + { ok: e } = await s.getTasksGroupedByProject(); + return e; +} +async function getProjects(t) { + const s = getTodoistPluginApi(t), + { ok: e } = await s.getProjects(); + return e; +} +async function getSections(t) { + const s = getTodoistPluginApi(t), + { ok: e } = await s.getSections(); + return e; +} diff --git a/_Scripts/projectsync.js b/_Scripts/projectsync.js new file mode 100644 index 0000000..d174839 --- /dev/null +++ b/_Scripts/projectsync.js @@ -0,0 +1,96 @@ +module.exports = { + SelectFromAllTasks: SelectFromAllTasks, + GetAllTasksFromProject: GetAllTasksFromProject, + GetAllTasksFromSection: GetAllTasksFromSection, +}; + +const getTodoistPluginApi = (t) => t.plugins.plugins["todoist-sync-plugin"].api; +async function SelectFromAllTasks(t) { + const s = await getAllTasks(t); + if (0 === s.length) return void new Notice("No tasks."); + const e = await selectTasks(t, s); + return await closeSelectedTasks(t.app, e), formatTasksToTasksPluginTask(e); +} +async function GetAllTasksFromProject(t) { + const [s, e] = await Promise.all([getAllTasks(t), getProjects(t.app)]), + a = await t.quickAddApi.suggester( + (t) => ( + (t.tasks = s.filter((s) => s.projectID === t.id)), + `${t.name} (${t.tasks.length})` + ), + e + ); + if (a) { + if (0 !== a.tasks.length) + return ( + new Notice(`Added ${a.tasks.length} tasks from '${a.name}'.`), + await closeSelectedTasks(t.app, a.tasks), + formatTasksToTasksPluginTask(a.tasks) + ); + new Notice(`No tasks in '${a.name}'.`); + } +} +async function GetAllTasksFromSection(t) { + const [s, e, a] = await Promise.all([ + getProjects(t.app), + getSections(t.app), + getAllTasks(t), + ]), + n = await t.quickAddApi.suggester((t) => { + const e = s.find((s) => s.id === t.project_id); + return ( + (t.tasks = a.filter((s) => s.sectionID === t.id)), + `${e.name} > ${t.name} (${t.tasks.length})` + ); + }, e); + if (0 !== n.tasks.length) + return ( + new Notice(`Added ${n.tasks.length} tasks from '${n.name}'.`), + await closeSelectedTasks(n.tasks), + formatTasksToTasksPluginTask(n.tasks) + ); + new Notice(`No tasks in '${n.name}'.`); +} +async function getAllTasks(t) { + const s = getTodoistPluginApi(t.app), + { ok: e } = await s.getTasks(); + return e; +} +async function selectTasks(t, s) { + const e = await t.quickAddApi.checkboxPrompt(s.map((t) => t.content)); + return s.filter((t) => e.some((s) => s.contains(t.content))); +} +async function closeSelectedTasks(t, s) { + const e = getTodoistPluginApi(t); + s.forEach(async (t) => await e.closeTask(t.id)); +} +function formatTasksToTasksPluginTask(t) { + const todayDate = new Date().toISOString().split("T")[0]; // Get today's date in YYYY-MM-DD format + return ( + t + .map( + (t) => + (t = t.rawDatetime + ? `- [ ] [[${t.content}]] \u2795 ${todayDate} \ud83d\udcc5 ${t.rawDatetime.format( + "YYYY-MM-DD" + )}` + : `- [ ] [[${t.content}]] \u2795 ${todayDate}`) + ) + .join("\n") + "\n" + ); +} +async function getTasksGroupedByProject(t) { + const s = getTodoistPluginApi(t), + { ok: e } = await s.getTasksGroupedByProject(); + return e; +} +async function getProjects(t) { + const s = getTodoistPluginApi(t), + { ok: e } = await s.getProjects(); + return e; +} +async function getSections(t) { + const s = getTodoistPluginApi(t), + { ok: e } = await s.getSections(); + return e; +} diff --git a/_Scripts/somedaysync.js b/_Scripts/somedaysync.js new file mode 100644 index 0000000..18821bf --- /dev/null +++ b/_Scripts/somedaysync.js @@ -0,0 +1,85 @@ +module.exports = { + SelectFromAllTasks: SelectFromAllTasks, + GetAllTasksFromProject: GetAllTasksFromProject, + GetAllTasksFromSection: GetAllTasksFromSection, +}; + +const getTodoistPluginApi = (t) => t.plugins.plugins["todoist-sync-plugin"].api; +async function SelectFromAllTasks(t) { + const s = await getAllTasks(t); + if (0 === s.length) return void new Notice("No tasks."); + const e = await selectTasks(t, s); + return await closeSelectedTasks(t.app, e), formatTasksToTasksPluginTask(e); +} +async function GetAllTasksFromProject(t) { + const [s, e] = await Promise.all([getAllTasks(t), getProjects(t.app)]), + a = await t.quickAddApi.suggester( + (t) => ( + (t.tasks = s.filter((s) => s.projectID === t.id)), + `${t.name} (${t.tasks.length})` + ), + e + ); + if (a) { + if (0 !== a.tasks.length) + return ( + new Notice(`Added ${a.tasks.length} tasks from '${a.name}'.`), + await closeSelectedTasks(t.app, a.tasks), + formatTasksToTasksPluginTask(a.tasks) + ); + new Notice(`No tasks in '${a.name}'.`); + } +} +async function GetAllTasksFromSection(t) { + const [s, e, a] = await Promise.all([ + getProjects(t.app), + getSections(t.app), + getAllTasks(t), + ]), + n = await t.quickAddApi.suggester((t) => { + const e = s.find((s) => s.id === t.project_id); + return ( + (t.tasks = a.filter((s) => s.sectionID === t.id)), + `${e.name} > ${t.name} (${t.tasks.length})` + ); + }, e); + if (0 !== n.tasks.length) + return ( + new Notice(`Added ${n.tasks.length} tasks from '${n.name}'.`), + await closeSelectedTasks(n.tasks), + formatTasksToTasksPluginTask(n.tasks) + ); + new Notice(`No tasks in '${n.name}'.`); +} +async function getAllTasks(t) { + const s = getTodoistPluginApi(t.app), + { ok: e } = await s.getTasks(); + return e; +} +async function selectTasks(t, s) { + const e = await t.quickAddApi.checkboxPrompt(s.map((t) => t.content)); + return s.filter((t) => e.some((s) => s.contains(t.content))); +} +async function closeSelectedTasks(t, s) { + const e = getTodoistPluginApi(t); + s.forEach(async (t) => await e.closeTask(t.id)); +} +function formatTasksToTasksPluginTask(t) { + const todayDate = moment().format("YYYY-MM-DD HH:mm:ss"); + return t.map((t) => `- ${t.content}`).join("\n"); +} +async function getTasksGroupedByProject(t) { + const s = getTodoistPluginApi(t), + { ok: e } = await s.getTasksGroupedByProject(); + return e; +} +async function getProjects(t) { + const s = getTodoistPluginApi(t), + { ok: e } = await s.getProjects(); + return e; +} +async function getSections(t) { + const s = getTodoistPluginApi(t), + { ok: e } = await s.getSections(); + return e; +} diff --git a/_Scripts/tasksync.js b/_Scripts/tasksync.js new file mode 100644 index 0000000..3752325 --- /dev/null +++ b/_Scripts/tasksync.js @@ -0,0 +1,96 @@ +module.exports = { + SelectFromAllTasks: SelectFromAllTasks, + GetAllTasksFromProject: GetAllTasksFromProject, + GetAllTasksFromSection: GetAllTasksFromSection, +}; + +const getTodoistPluginApi = (t) => t.plugins.plugins["todoist-sync-plugin"].api; +async function SelectFromAllTasks(t) { + const s = await getAllTasks(t); + if (0 === s.length) return void new Notice("No tasks."); + const e = await selectTasks(t, s); + return await closeSelectedTasks(t.app, e), formatTasksToTasksPluginTask(e); +} +async function GetAllTasksFromProject(t) { + const [s, e] = await Promise.all([getAllTasks(t), getProjects(t.app)]), + a = await t.quickAddApi.suggester( + (t) => ( + (t.tasks = s.filter((s) => s.projectID === t.id)), + `${t.name} (${t.tasks.length})` + ), + e + ); + if (a) { + if (0 !== a.tasks.length) + return ( + new Notice(`Added ${a.tasks.length} tasks from '${a.name}'.`), + await closeSelectedTasks(t.app, a.tasks), + formatTasksToTasksPluginTask(a.tasks) + ); + new Notice(`No tasks in '${a.name}'.`); + } +} +async function GetAllTasksFromSection(t) { + const [s, e, a] = await Promise.all([ + getProjects(t.app), + getSections(t.app), + getAllTasks(t), + ]), + n = await t.quickAddApi.suggester((t) => { + const e = s.find((s) => s.id === t.project_id); + return ( + (t.tasks = a.filter((s) => s.sectionID === t.id)), + `${e.name} > ${t.name} (${t.tasks.length})` + ); + }, e); + if (0 !== n.tasks.length) + return ( + new Notice(`Added ${n.tasks.length} tasks from '${n.name}'.`), + await closeSelectedTasks(n.tasks), + formatTasksToTasksPluginTask(n.tasks) + ); + new Notice(`No tasks in '${n.name}'.`); +} +async function getAllTasks(t) { + const s = getTodoistPluginApi(t.app), + { ok: e } = await s.getTasks(); + return e; +} +async function selectTasks(t, s) { + const e = await t.quickAddApi.checkboxPrompt(s.map((t) => t.content)); + return s.filter((t) => e.some((s) => s.contains(t.content))); +} +async function closeSelectedTasks(t, s) { + const e = getTodoistPluginApi(t); + s.forEach(async (t) => await e.closeTask(t.id)); +} +function formatTasksToTasksPluginTask(t) { + const todayDate = new Date().toISOString().split("T")[0]; // Get today's date in YYYY-MM-DD format + return ( + t + .map( + (t) => + (t = t.rawDatetime + ? `- [ ] ${t.content} \u2795 ${todayDate} \ud83d\udcc5 ${t.rawDatetime.format( + "YYYY-MM-DD" + )}` + : `- [ ] ${t.content} \u2795 ${todayDate}`) + ) + .join("\n") + "\n" + ); +} +async function getTasksGroupedByProject(t) { + const s = getTodoistPluginApi(t), + { ok: e } = await s.getTasksGroupedByProject(); + return e; +} +async function getProjects(t) { + const s = getTodoistPluginApi(t), + { ok: e } = await s.getProjects(); + return e; +} +async function getSections(t) { + const s = getTodoistPluginApi(t), + { ok: e } = await s.getSections(); + return e; +} diff --git a/_Scripts/view.css b/_Scripts/view.css new file mode 100644 index 0000000..26f1aed --- /dev/null +++ b/_Scripts/view.css @@ -0,0 +1,722 @@ +.tasksCalendar span { + display: contents; +} +.tasksCalendar .buttons { + cursor: default; + width: 100%; + height: 30px; + display: flex; + flex-wrap: nowrap; + flex-direction: row; + margin-bottom: 4px; +} +.tasksCalendar[view='list'] button.listView, +.tasksCalendar[view='week'] button.weekView, +.tasksCalendar[view='month'] button.monthView, +.tasksCalendar.filter button.filter { + background: var(--background-modifier-active-hover); +} +body:not(.is-mobile) .tasksCalendar button.listView:hover, +body:not(.is-mobile) .tasksCalendar button.weekView:hover, +body:not(.is-mobile) .tasksCalendar button.monthView:hover, +body:not(.is-mobile) .tasksCalendar button.previous:hover, +body:not(.is-mobile) .tasksCalendar button.next:hover, +body:not(.is-mobile) .tasksCalendar button.current:hover, +body:not(.is-mobile) .tasksCalendar button.filter:hover, +body:not(.is-mobile) .tasksCalendar button.statistic:hover { + background: var(--background-modifier-hover); +} +.tasksCalendar[view='list'] button.listView svg, +.tasksCalendar[view='month'] button.monthView svg, +.tasksCalendar[view='week'] button.weekView svg, +.tasksCalendar.filter button.filter svg { + stroke: var(--icon-color-active) !important; +} +.tasksCalendar button { + background-color: transparent; + display: inline-flex; + align-items: center; + justify-content: center; + cursor: pointer; + border-radius: 5px; + color: var(--icon-color); + height: 30px; + box-shadow: none; + border: 1px solid var(--nav-item-background-active); + font-weight: normal; + font-size: 14px; + background: var(--background-secondary); + padding: 4px 6px; + outline: none; + user-select: none; + white-space: nowrap; + flex: 0; +} +.tasksCalendar button:nth-child(2), +.tasksCalendar button:nth-child(3), +.tasksCalendar button:nth-child(6) { + border-top-right-radius: 0; + border-bottom-right-radius: 0; + border-right: 0.5px solid var(--nav-item-background-active); + margin-right: 0; +} +.tasksCalendar button:nth-child(3), +.tasksCalendar button:nth-child(4), +.tasksCalendar button:nth-child(7) { + border-top-left-radius: 0; + border-bottom-left-radius: 0; + border-left: 0.5px solid var(--nav-item-background-active); + margin-left: 0; +} +.tasksCalendar .current { + margin: 0 4px; + display: inline; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + flex: 1; +} +.tasksCalendar .current span:first-child { + font-weight: bold; + color: var(--icon-color); +} +.tasksCalendar .current span:last-child { + font-weight: normal; + color: var(--icon-color-active); +} +.tasksCalendar button:nth-child(1) { + margin-right: 4px; +} +.tasksCalendar button:nth-child(8) { + margin-left: 4px; +} +.tasksCalendar svg { + height: var(--icon-size); + width: var(--icon-size); + stroke-width: var(--icon-stroke); +} +.tasksCalendar .statisticPopup, +.tasksCalendar .weekViewContext { + display: none; + border-radius: 5px; + font-size: 10px; + border: 1px solid var(--nav-item-background-active); + position: absolute; + height: auto; + width: 150px; + width: auto; + background: var(--icon-color); + margin: 0 !important; + list-style: none; + padding: 2px !important; + z-index: 99; + box-shadow: 0px 0px 10px 0px var(--nav-item-background-active); + background: var(--background-secondary); +} +.tasksCalendar .statisticPopup { + right: 0; +} +.tasksCalendar .weekViewContext { + left: 65px; +} +.tasksCalendar .statisticPopup:before, +.tasksCalendar .weekViewContext:before { + content: ""; + width: 0px; + height: 0px; + -webkit-transform:rotate(360deg); + border-style: solid; + border-width: 0 10px 10px 10px; + border-color: transparent transparent var(--background-secondary) transparent; + position: absolute; +} +.tasksCalendar .statisticPopup:before { + top: -10px; + right: 5px; +} +.tasksCalendar .weekViewContext:before { + top: -10px; + left: 5px; +} +.tasksCalendar .statisticPopup.active, +.tasksCalendar .weekViewContext.active { + display: block; +} +.tasksCalendar .statisticPopup li, +.tasksCalendar .weekViewContext li { + display: flex; + flex-direction: row; + flex-wrap: nowrap; + align-items: center; + height: auto; + font-size: 14px; + list-style: none; + color: var(--text-normal); + padding: 5px 10px; + border-radius: 5px; + cursor: pointer; +} +.tasksCalendar .statisticPopup li.active, +.tasksCalendar .weekViewContext li.active { + background: var(--background-modifier-active-hover); + color: var(--icon-color-active) !important; +} +body:not(.is-mobile) .tasksCalendar .statisticPopup li:not(.active):hover, +body:not(.is-mobile) .tasksCalendar .weekViewContext li:not(.active):hover { + background: var(--background-modifier-hover); +} +.tasksCalendar .statisticPopup li.break, +.tasksCalendar .weekViewContext li.break { + height: 1px !important; + background: var(--nav-item-background-active); + margin: 2px 5px !important; + border-radius: 0 !important; + padding: 0 !important; +} +.tasksCalendar .statisticPopup > div, +.tasksCalendar .weekViewContext > div { + height: 13px; + margin: auto 0; +} +.tasksCalendar button.statistic { + position: relative; +} +.tasksCalendar button.statistic svg { + stroke: var(--icon-color); +} +.tasksCalendar button.statistic[data-percentage="100"]:after { + display: none !important; +} +.tasksCalendar button.statistic:after { + content: attr(data-remaining); + position: absolute; + height: 14px; + width: 14px; + top: -8px; + right: -8px; + border-radius: 50%; + text-align: center; + line-height: 14px; + font-size: 9px; + font-weight: bold; + border: 1px solid var(--nav-item-background-active); + overflow: hidden; + color: var(--icon-color); + background: var(--background-secondary); +} +.tasksCalendar .weekViewContext .liIcon { + display: grid !important; + height: 18px; + width: 18px; + margin-right: 5px; + padding: 2px; +} +.tasksCalendar .weekViewContext .liIcon .box { + background: var(--icon-color); + z-index: 1; + display: grid; + overflow: hidden; + margin: 0.5px; + border-radius: 1px; +} +.tasksCalendar .weekViewContext li.active .liIcon .box { + background: var(--icon-color-active) !important; +} +.tasksCalendar .grid { + overflow: hidden; + cursor: default; + width: 100%; + height: 75vH; +} +.tasksCalendar .list { + overflow-x: hidden; + overflow-y: auto; + cursor: default; + width: 100%; + height: 75vH; +} +.tasksCalendar .cell { + z-index: 1; + display: grid; + grid-template-rows: auto 1fr; + grid-template-columns: 1fr; + overflow: hidden; + margin: 1px 0; +} +.tasksCalendar .cellContent { + overflow-x: hidden; + overflow-y: auto; + align-content: start; + padding: 1px 0; +} +.tasksCalendar .cellContent::-webkit-scrollbar { + display: none; +} +.tasksCalendar .cellName { + display: block; + font-weight: normal; + padding: 0 2px; + color: var(--text-normal); + flex-shrink: 0; + flex-grow: 0; + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; + text-align: left; + margin: 0; + font-size: 14px; + opacity: 0.8; +} +body:not(.is-mobile) .tasksCalendar .cellName:hover { + opacity: 1; +} +.tasksCalendar .task { + overflow: hidden; + padding: 1px; + background: var(--task-background); + border-radius: 3px; + overflow: hidden; + margin: 1px 1px 2px 1px; + font-size: 14px; + opacity: 0.8; + display: block; +} +body.theme-dark .tasksCalendar .task { color: var(--light-task-text-color); } +body.theme-light .tasksCalendar .task { color: var(--dark-task-text-color); } +body.theme-dark .tasksCalendar .task .note { color: var(--light-task-text-color); } +body.theme-light .tasksCalendar .task .note { color: var(--dark-task-text-color); } +body:not(.is-mobile) .tasksCalendar .task:hover { + opacity: 1; +} +.tasksCalendar .task.hide { + opacity: 0.2; +} +.tasksCalendar .task .inner { + overflow: hidden; + text-overflow: ellipsis; + display: -webkit-box; + -webkit-line-clamp: 1; + -webkit-box-orient: vertical; + text-decoration: none; + word-break: break-all !important; + -webkit-hyphens: none !important; + line-height: 1.3; + text-decoration: none !important; + border-radius: 3px; + overflow: hidden; +} +.tasksCalendar a { + text-decoration: none !important; +} +.tasksCalendar .task .note { + display: block; + width: 100%; + font-size: 9px; + background: var(--task-background); + padding: 1px; + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; +} +.tasksCalendar .task .icon { + display: inline; + width: 18px; + height: 18px; + text-align: center; + margin-right: 3px; +} +.tasksCalendar .task .description { + display: inline; + padding: 1px; +} +.tasksCalendar .task .description:before { + display: inline; + content: attr(data-relative); + margin-right: 3px; + border-radius: 3px; + margin-right: 3px; + padding: 0 3px; + font-size: 9px; + vertical-align: middle; +} +.tasksCalendar .task.overdue .description:before { + color: white; + background: #ff443a; +} +.tasksCalendar .task:not(.overdue) .description:before { + display: none; + background: black; + color: white; +} +.tasksCalendar .task.dailyNote .description:before, +.tasksCalendar .task.done .description:before, +.tasksCalendar .task.cancelled .description:before { + display: none !important; +} +.tasksCalendar .task.cancelled .note, +.tasksCalendar .task.done .note { + background: var(--nav-item-background-active) !important; + color: var(--text-faint) !important; +} +.tasksCalendar .task.cancelled .description, +.tasksCalendar .task.done .description { + text-decoration: line-through !important; + color: var(--text-faint) !important; +} +.tasksCalendar .task.cancelled, +.tasksCalendar .task.done { + background: none !important; +} +.tasksCalendar .task.overdue .inner { + background: repeating-linear-gradient(45deg, var(--task-background), var(--task-background) 5px, transparent 5px, transparent 10px) !important; +} + + +/* Today & Weekends */ +.tasksCalendar .cell.today .cellName { + font-weight: bold; + color: var(--text-normal); + opacity: 1; +} +.tasksCalendar .cell[data-weekday="0"].today .cellName { + font-weight: bold; + color: var(--icon-color-active); + opacity: 1; +} +.tasksCalendar[view='month'] .cell.today { + background: var(--background-modifier-active-hover) !important; + border: 1px solid hsla(var(--interactive-accent-hsl), 0.25) !important; + border-radius: 5px; +} +.tasksCalendar[view='week'] .cell.today { + background: var(--background-modifier-active-hover) !important; + border: 1px solid hsla(var(--interactive-accent-hsl), 0.25) !important; +} +.tasksCalendar .cell[data-weekday="0"] .cellName, +.tasksCalendar .gridHead[data-weekday="0"] { + color: var(--icon-color-active); +} + + +/* Month View */ +.tasksCalendar[view='month'] .grid { + display: grid; + gap: 4px; + grid-template-rows: 20px 1fr !important; + grid-template-columns: 1fr !important; +} +.tasksCalendar[view='month'] .gridHeads { + display: grid; + grid-template-columns: 20px 1fr 1fr 1fr 1fr 1fr 1fr 1fr !important; + width: 100%; + height: 20px; + border: 1px solid var(--nav-item-background-active); + border-radius: 5px; +} +.tasksCalendar[view='month'] .gridHead { + display: inline; + box-sizing: border-box; + overflow: hidden; + text-align: center; + font-weight: bold; + text-overflow: ellipsis; + white-space: nowrap; + margin: 0; + font-size: 14px; + height: 20px; + line-height: 20px; + font-size: 10px; +} +.tasksCalendar[view='month'] .wrappers { + display: grid; + grid-template-rows: repeat(6, calc(100% / 6)); + grid-template-columns: 1fr !important; + min-height: 0; + height: calc(100% - 20px); + gap: 4px 4px; +} +.tasksCalendar[view='month'] .wrappers, +.tasksCalendar[view='week'] .grid { + position: relative; +} +.tasksCalendar[view='month'] .wrappers:before, +.tasksCalendar[view='week'] .grid:before, +.tasksCalendar[view='list'] .list:before { + z-index: 0; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + font-size: 120px; + font-weight: bold; + color: var(--background-modifier-active-hover); +} +.tasksCalendar[view='month'] .wrappers:before, +.tasksCalendar[view='list'] .list:before { + content: attr(data-month); +} +.tasksCalendar[view='week'] .grid:before { + content: attr(data-week); +} +.tasksCalendar[view='month'] .wrapper { + z-index: 1; + display: grid; + grid-template-rows: 1fr !important; + grid-template-columns: 22px 1fr 1fr 1fr 1fr 1fr 1fr 1fr !important; + width: 100%; + height: 100%; + border: 1px solid var(--nav-item-background-active); + border-radius: 5px; + overflow: hidden; +} +.tasksCalendar[view='month'] .wrapperButton { + display: flex; + writing-mode: vertical-lr; + transform: rotate(180deg); + background: none; + text-align: center; + align-items: center; + justify-content: center; + font-size: 10px; + font-weight: normal; + color: var(--text-normal); + color: var(--icon-color-active); + cursor: pointer; + width: 100%; + overflow: hidden; + /* background: var(--background-primary); */ + background: var(--background-secondary); +} +.tasksCalendar[view='month'] .wrapperButton:hover { + background: var(--background-modifier-hover); +} +.tasksCalendar[view='month'] .cell { + margin: 0; +} +.tasksCalendar[view='month'] .prevMonth, +.tasksCalendar[view='month'] .nextMonth { + background: var(--background-secondary); +} + + +/* Week view */ +.tasksCalendar[view='week'] .grid { + display: grid; + gap: 2px 4px; +} +.tasksCalendar[view='week'] .cell { + border: 1px solid var(--nav-item-background-active); + border-radius: 5px; + overflow: hidden; +} + + +/* List View */ +.tasksCalendar[view='list'] .list { + border: 1px solid var(--nav-item-background-active); + border-radius: 5px; +} +.tasksCalendar[view='list'] .list .task, +.tasksCalendar[view='list'] .list .task.done, +.tasksCalendar[view='list'] .list .task .note, +.tasksCalendar[view='list'] .list .task.done .note{ + background: transparent !important; +} +.tasksCalendar[view='list'] .list .task .inner { + display: flex !important; + flex-direction: row; + flex-wrap: nowrap; + padding: 0 10px; + white-space: nowrap; +} +.tasksCalendar[view='list'] .list .task .note { + display: inline-block; + width: 150px; + flex-shrink: 0; + flex-grow: 0; +} +.tasksCalendar[view='list'] .list .task .description { + width: 100%; + flex-shrink: 1; + flex-grow: 1; +} +.tasksCalendar[view='list'] .list .task.done .note, +.tasksCalendar[view='list'] .list .task.done .description, +.tasksCalendar[view='list'] .list .task.cancelled .note, +.tasksCalendar[view='list'] .list .task.cancelled .description { + color: var(--text-faint) !important; +} +.tasksCalendar[view='list'] .list .task .note, +.tasksCalendar[view='list'] .list .task .description { + color: var(--task-color) !important; + line-clamp: 0 !important; + white-space: nowrap !important; + text-overflow: ellipsis; + overflow: hidden; + font-size: 14px; +} +.tasksCalendar summary::marker, +.tasksCalendar summary::-webkit-details-marker { + display: none !important; + content: "" !important; +} +.tasksCalendar[view='list'] details.today { + background: var(--background-modifier-active-hover); + border: 1px solid hsla(var(--interactive-accent-hsl), 0.25); +} +.tasksCalendar[view='list'] details.today summary { + font-weight: bold; + background: none; +} +.tasksCalendar[view='list'] details.today .content { + margin: 3px; +} +.tasksCalendar[view='list'] details { + display: block; + margin: 5px; + border-radius: 5px; + overflow: hidden; + /*background: var(--background-secondary);*/ + border: 1px solid var(--nav-item-background-active); +} +.tasksCalendar[view='list'] summary { + background: var(--background-secondary); + padding: 0 10px; + border-radius: 5px; +} +.tasksCalendar[view='list'] summary span.weekNr { + font-size: 11px; + color: var(--text-faint); +} + + +/* Style classes */ +.tasksCalendar[view='week'].style1 .grid, .iconStyle1 { grid-template-columns: repeat(4, 1fr); grid-template-rows: repeat(6, 1fr); } +.tasksCalendar[view='week'].style1 .grid .cell:nth-child(1), .iconStyle1 .box:nth-child(1) { grid-area: 1 / 1 / 3 / 3; } +.tasksCalendar[view='week'].style1 .grid .cell:nth-child(2), .iconStyle1 .box:nth-child(2) { grid-area: 3 / 1 / 5 / 3; } +.tasksCalendar[view='week'].style1 .grid .cell:nth-child(3), .iconStyle1 .box:nth-child(3) { grid-area: 5 / 1 / 7 / 3; } +.tasksCalendar[view='week'].style1 .grid .cell:nth-child(4), .iconStyle1 .box:nth-child(4) { grid-area: 1 / 3 / 3 / 5; } +.tasksCalendar[view='week'].style1 .grid .cell:nth-child(5), .iconStyle1 .box:nth-child(5) { grid-area: 3 / 3 / 5 / 5; } +.tasksCalendar[view='week'].style1 .grid .cell:nth-child(6), .iconStyle1 .box:nth-child(6) { grid-area: 5 / 3 / 6 / 5; } +.tasksCalendar[view='week'].style1 .grid .cell:nth-child(7), .iconStyle1 .box:nth-child(7) { grid-area: 6 / 3 / 7 / 5; } +.tasksCalendar[view='week'].style2 .grid, .iconStyle2 { grid-template-columns: repeat(4, 1fr); grid-template-rows: repeat(6, 1fr); } +.tasksCalendar[view='week'].style2 .grid .cell:nth-child(1), .iconStyle2 .box:nth-child(1) { grid-area: 1 / 1 / 3 / 3; } +.tasksCalendar[view='week'].style2 .grid .cell:nth-child(3), .iconStyle2 .box:nth-child(3) { grid-area: 3 / 1 / 5 / 3; } +.tasksCalendar[view='week'].style2 .grid .cell:nth-child(5), .iconStyle2 .box:nth-child(5) { grid-area: 5 / 1 / 7 / 3; } +.tasksCalendar[view='week'].style2 .grid .cell:nth-child(2), .iconStyle2 .box:nth-child(2) { grid-area: 1 / 3 / 3 / 5; } +.tasksCalendar[view='week'].style2 .grid .cell:nth-child(4), .iconStyle2 .box:nth-child(4) { grid-area: 3 / 3 / 5 / 5; } +.tasksCalendar[view='week'].style2 .grid .cell:nth-child(6), .iconStyle2 .box:nth-child(6) { grid-area: 5 / 3 / 6 / 5; } +.tasksCalendar[view='week'].style2 .grid .cell:nth-child(7), .iconStyle2 .box:nth-child(7) { grid-area: 6 / 3 / 7 / 5; } +.tasksCalendar[view='week'].style3 .grid, .iconStyle3 { grid-template-rows: 1fr 1fr 1fr 1fr 1fr 1fr 1fr; grid-template-columns: 1fr; } +.tasksCalendar[view='week'].style4 .grid, .iconStyle4 { grid-template-rows: 1fr; grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr 1fr; } +.tasksCalendar[view='week'].style5 .grid, .iconStyle5 { grid-template-columns: repeat(2, 1fr); grid-template-rows: repeat(10, 1fr); } +.tasksCalendar[view='week'].style5 .grid .cell:nth-child(1), .iconStyle5 .box:nth-child(1) { grid-area: 1 / 1 / 3 / 2; } +.tasksCalendar[view='week'].style5 .grid .cell:nth-child(2), .iconStyle5 .box:nth-child(2) { grid-area: 3 / 1 / 5 / 2; } +.tasksCalendar[view='week'].style5 .grid .cell:nth-child(3), .iconStyle5 .box:nth-child(3) { grid-area: 5 / 1 / 7 / 2; } +.tasksCalendar[view='week'].style5 .grid .cell:nth-child(4), .iconStyle5 .box:nth-child(4) { grid-area: 7 / 1 / 9 / 2; } +.tasksCalendar[view='week'].style5 .grid .cell:nth-child(5), .iconStyle5 .box:nth-child(5) { grid-area: 9 / 1 / 11 / 2; } +.tasksCalendar[view='week'].style5 .grid .cell:nth-child(6), .iconStyle5 .box:nth-child(6) { grid-area: 1 / 2 / 6 / 3; } +.tasksCalendar[view='week'].style5 .grid .cell:nth-child(7), .iconStyle5 .box:nth-child(7) { grid-area: 6 / 2 / 11 / 3; } +.tasksCalendar[view='week'].style6 .grid, .iconStyle6 { grid-template-columns: repeat(3, 1fr); grid-template-rows: repeat(10, 1fr); } +.tasksCalendar[view='week'].style6 .grid .cell:nth-child(1), .iconStyle6 .box:nth-child(1) { grid-area: 1 / 1 / 3 / 3; } +.tasksCalendar[view='week'].style6 .grid .cell:nth-child(2), .iconStyle6 .box:nth-child(2) { grid-area: 3 / 1 / 5 / 3; } +.tasksCalendar[view='week'].style6 .grid .cell:nth-child(3), .iconStyle6 .box:nth-child(3) { grid-area: 5 / 1 / 7 / 3; } +.tasksCalendar[view='week'].style6 .grid .cell:nth-child(4), .iconStyle6 .box:nth-child(4) { grid-area: 7 / 1 / 9 / 3; } +.tasksCalendar[view='week'].style6 .grid .cell:nth-child(5), .iconStyle6 .box:nth-child(5) { grid-area: 9 / 1 / 11 / 3; } +.tasksCalendar[view='week'].style6 .grid .cell:nth-child(6), .iconStyle6 .box:nth-child(6) { grid-area: 1 / 3 / 6 / 4; } +.tasksCalendar[view='week'].style6 .grid .cell:nth-child(7), .iconStyle6 .box:nth-child(7) { grid-area: 6 / 3 / 11 / 4; } +.tasksCalendar[view='week'].style7 .grid, .iconStyle7 { grid-template-columns: repeat(2, 1fr); grid-template-rows: repeat(8, 1fr); } +.tasksCalendar[view='week'].style7 .grid .cell:nth-child(1), .iconStyle7 .box:nth-child(1) { grid-area: 1 / 1 / 3 / 2; } +.tasksCalendar[view='week'].style7 .grid .cell:nth-child(2), .iconStyle7 .box:nth-child(2) { grid-area: 3 / 1 / 5 / 2; } +.tasksCalendar[view='week'].style7 .grid .cell:nth-child(3), .iconStyle7 .box:nth-child(3) { grid-area: 5 / 1 / 7 / 2; } +.tasksCalendar[view='week'].style7 .grid .cell:nth-child(4), .iconStyle7 .box:nth-child(4) { grid-area: 7 / 1 / 9 / 2; } +.tasksCalendar[view='week'].style7 .grid .cell:nth-child(5), .iconStyle7 .box:nth-child(5) { grid-area: 1 / 2 / 3 / 3; } +.tasksCalendar[view='week'].style7 .grid .cell:nth-child(6), .iconStyle7 .box:nth-child(6) { grid-area: 3 / 2 / 6 / 3; } +.tasksCalendar[view='week'].style7 .grid .cell:nth-child(7), .iconStyle7 .box:nth-child(7) { grid-area: 6 / 2 / 9 / 3; } +.tasksCalendar[view='week'].style8 .grid, .iconStyle8 { grid-template-columns: repeat(3, 1fr); grid-template-rows: repeat(5, 1fr); } +.tasksCalendar[view='week'].style8 .grid .cell:nth-child(1), .iconStyle8 .box:nth-child(1) { grid-area: 1 / 1 / 3 / 2; } +.tasksCalendar[view='week'].style8 .grid .cell:nth-child(2), .iconStyle8 .box:nth-child(2) { grid-area: 1 / 2 / 3 / 3; } +.tasksCalendar[view='week'].style8 .grid .cell:nth-child(3), .iconStyle8 .box:nth-child(3) { grid-area: 1 / 3 / 3 / 4; } +.tasksCalendar[view='week'].style8 .grid .cell:nth-child(4), .iconStyle8 .box:nth-child(4) { grid-area: 3 / 1 / 5 / 2; } +.tasksCalendar[view='week'].style8 .grid .cell:nth-child(5), .iconStyle8 .box:nth-child(5) { grid-area: 3 / 2 / 5 / 3; } +.tasksCalendar[view='week'].style8 .grid .cell:nth-child(6), .iconStyle8 .box:nth-child(6) { grid-area: 3 / 3 / 5 / 4; } +.tasksCalendar[view='week'].style8 .grid .cell:nth-child(7), .iconStyle8 .box:nth-child(7) { grid-area: 5 / 1 / 6 / 4; } +.tasksCalendar[view='week'].style9 .grid, .iconStyle9 { grid-template-columns: repeat(10, 1fr); grid-template-rows: repeat(3, 1fr); } +.tasksCalendar[view='week'].style9 .grid .cell:nth-child(1), .iconStyle9 .box:nth-child(1) { grid-area: 1 / 1 / 3 / 3; } +.tasksCalendar[view='week'].style9 .grid .cell:nth-child(2), .iconStyle9 .box:nth-child(2) { grid-area: 1 / 3 / 3 / 5; } +.tasksCalendar[view='week'].style9 .grid .cell:nth-child(3), .iconStyle9 .box:nth-child(3) { grid-area: 1 / 5 / 3 / 7; } +.tasksCalendar[view='week'].style9 .grid .cell:nth-child(4), .iconStyle9 .box:nth-child(4) { grid-area: 1 / 7 / 3 / 9; } +.tasksCalendar[view='week'].style9 .grid .cell:nth-child(5), .iconStyle9 .box:nth-child(5) { grid-area: 1 / 9 / 3 / 11; } +.tasksCalendar[view='week'].style9 .grid .cell:nth-child(6), .iconStyle9 .box:nth-child(6) { grid-area: 3 / 1 / 4 / 6; } +.tasksCalendar[view='week'].style9 .grid .cell:nth-child(7), .iconStyle9 .box:nth-child(7) { grid-area: 3 / 6 / 4 / 11; } +.tasksCalendar[view='week'].style10 .grid, .iconStyle10 { grid-template-columns: repeat(10, 1fr); grid-template-rows: repeat(3, 1fr); } +.tasksCalendar[view='week'].style10 .grid .cell:nth-child(1), .iconStyle10 .box:nth-child(1) { grid-area: 1 / 1 / 4 / 3; } +.tasksCalendar[view='week'].style10 .grid .cell:nth-child(2), .iconStyle10 .box:nth-child(2) { grid-area: 1 / 3 / 4 / 5; } +.tasksCalendar[view='week'].style10 .grid .cell:nth-child(3), .iconStyle10 .box:nth-child(3) { grid-area: 1 / 5 / 4 / 7; } +.tasksCalendar[view='week'].style10 .grid .cell:nth-child(4), .iconStyle10 .box:nth-child(4) { grid-area: 1 / 7 / 3 / 9; } +.tasksCalendar[view='week'].style10 .grid .cell:nth-child(5), .iconStyle10 .box:nth-child(5) { grid-area: 1 / 9 / 3 / 11; } +.tasksCalendar[view='week'].style10 .grid .cell:nth-child(6), .iconStyle10 .box:nth-child(6) { grid-area: 3 / 7 / 4 / 9; } +.tasksCalendar[view='week'].style10 .grid .cell:nth-child(7), .iconStyle10 .box:nth-child(7) { grid-area: 3 / 9 / 4 / 11; } +.tasksCalendar[view='week'].style11 .grid, .iconStyle11 { grid-template-rows: 1fr; grid-template-columns: 1fr 1fr 1fr 1fr 1fr; } +.tasksCalendar[view='week'].style11 .grid { height: 300px } +.tasksCalendar[view='week'].style11 .cell[data-weekday="0"], .iconStyle11 { display: none !important } +.tasksCalendar[view='week'].style11 .cell[data-weekday="6"], .iconStyle11 { display: none !important } + +/* Options classes */ +.tasksCalendar.noIcons .task .icon { display: none !important; } +.tasksCalendar:not(.noFilename) .task.noNoteIcon .icon { display: none !important; } +.tasksCalendar.noFilename .task .note { display: none !important; } +.tasksCalendar.filter .task.done, .tasksCalendar.filter .task.cancelled { display: none !important; } +.tasksCalendar.filter #statisticDone { pointer-events: none !important; color: var(--text-faint) !important; } +.tasksCalendar.noScheduled .task.scheduled { display: none !important; } +.tasksCalendar.noStart .task.start { display: none !important; } +.tasksCalendar.noDue .task.due { display: none !important; } +.tasksCalendar.noDone .task.done { display: none !important; } +.tasksCalendar.noProcess .task.process { display: none !important; } +.tasksCalendar.noRecurrence .task.recurrence { display: none !important; } +.tasksCalendar.noOverdue .task.overdue { display: none !important; } +.tasksCalendar.noDailyNote .task.dailyNote { display: none !important; } +.tasksCalendar.noCellNameEvent .cellName { pointer-events: none !important; } +.tasksCalendar.noLayer .grid .wrappers:before, +.tasksCalendar.noLayer .grid:before, +.tasksCalendar.noLayer .list:before { display: none !important;} +.tasksCalendar.focusDone .task { opacity: 0.25 !important; } +.tasksCalendar.focusDone .task.done { opacity: 1 !important; } +.tasksCalendar.focusDue .task { opacity: 0.25 !important; } +.tasksCalendar.focusDue .task.due { opacity: 1 !important; } +.tasksCalendar.focusOverdue .task { opacity: 0.25 !important; } +.tasksCalendar.focusOverdue .task.overdue { opacity: 1 !important; } +.tasksCalendar.focusStart .task { opacity: 0.25 !important; } +.tasksCalendar.focusStart .task.start { opacity: 1 !important; } +.tasksCalendar.focusScheduled .task { opacity: 0.25 !important; } +.tasksCalendar.focusScheduled .task.scheduled { opacity: 1 !important; } +.tasksCalendar.focusRecurrence .task { opacity: 0.25 !important; } +.tasksCalendar.focusRecurrence .task.recurrence { opacity: 1 !important; } +.tasksCalendar.focusDailyNote .task { opacity: 0.25 !important; } +.tasksCalendar.focusDailyNote .task.dailyNote { opacity: 1 !important; } +.tasksCalendar.mini { max-width: 500px !important; margin: 0 auto; } +.tasksCalendar.mini .grid { height: 400px !important; } +.tasksCalendar.mini .gridHead, +.tasksCalendar.mini .cellName, +.tasksCalendar.mini .task, +.tasksCalendar.mini .wrapperButton { font-size: 9px !important; } +.tasksCalendar.mini .wrappers:before, +.tasksCalendar.mini .grid:before { font-size: 70px !important; } +.tasksCalendar.mini .statisticPopup li, +.tasksCalendar.mini .weekViewContext li { font-size: 9px !important; } +.tasksCalendar.noWeekNr .wrapperButton { visibility: hidden !important; width: 0 !important; } +.tasksCalendar.noWeekNr .gridHead:first-child { visibility: hidden !important; width: 0 !important; } +.tasksCalendar.noWeekNr .wrapper { grid-template-columns: 0px 1fr 1fr 1fr 1fr 1fr 1fr 1fr !important; } +.tasksCalendar.noWeekNr .gridHeads { grid-template-columns: 0px 1fr 1fr 1fr 1fr 1fr 1fr 1fr !important; } +.tasksCalendar.noWeekNr .list .weekNr { display: none !important; } +.tasksCalendar.lineClamp1 .task .inner { -webkit-line-clamp: 1 !important; white-space: nowrap !important; } +.tasksCalendar.lineClamp2 .task .inner { -webkit-line-clamp: 2 !important; } +.tasksCalendar.lineClamp3 .task .inner { -webkit-line-clamp: 3 !important; } +.tasksCalendar.noLineClamp .task .inner { display: block !important; } +.tasksCalendar.noOverdueFlag .task .description:before { display: none !important; } + +/* Mobile View */ +body.is-mobile .tasksCalendar .gridHead, body.is-mobile .tasksCalendar .cellName, body.is-mobile .tasksCalendar .task { font-size: 9px; } +body.is-mobile .tasksCalendar[view='week']:not(.style4) .cellName, +body.is-mobile .tasksCalendar[view='week']:not(.style4) .task { font-size: 13px !important; } +body.is-mobile .tasksCalendar .statisticPopup li { font-size: 13px !important; } diff --git a/_Scripts/view.js b/_Scripts/view.js new file mode 100644 index 0000000..093db2c --- /dev/null +++ b/_Scripts/view.js @@ -0,0 +1,1207 @@ +let { + pages, + view, + firstDayOfWeek, + globalTaskFilter, + dailyNoteFolder, + dailyNoteFormat, + startPosition, + upcomingDays, + css, + options, +} = input; + +// Error Handling +if (!pages && pages != "") { + dv.span( + '> [!ERROR] Missing pages parameter\n> \n> Please set the pages parameter like\n> \n> `pages: ""`' + ); + return false; +} +if (!options.includes("style")) { + dv.span( + '> [!ERROR] Missing style parameter\n> \n> Please set a style inside options parameter like\n> \n> `options: "style1"`' + ); + return false; +} +if (!view) { + dv.span( + '> [!ERROR] Missing view parameter\n> \n> Please set a default view inside view parameter like\n> \n> `view: "month"`' + ); + return false; +} +if (firstDayOfWeek) { + if (firstDayOfWeek.match(/[|\\0123456]/g) == null) { + dv.span( + "> [!ERROR] Wrong value inside firstDayOfWeek parameter\n> \n> Please choose a number between 0 and 6" + ); + return false; + } +} else { + dv.span( + '> [!ERROR] Missing firstDayOfWeek parameter\n> \n> Please set the first day of the week inside firstDayOfWeek parameter like\n> \n> `firstDayOfWeek: "1"`' + ); + return false; +} +if (startPosition) { + if (!startPosition.match(/\d{4}\-\d{1,2}/gm)) { + dv.span( + "> [!ERROR] Wrong startPosition format\n> \n> Please set a startPosition with the following format\n> \n> Month: `YYYY-MM` | Week: `YYYY-ww`" + ); + return false; + } +} +if (dailyNoteFormat) { + if ( + dailyNoteFormat.match(/[|\\YMDWwd.,-: \[\]]/g).length != + dailyNoteFormat.length + ) { + dv.span("> [!ERROR] The `dailyNoteFormat` contains invalid characters"); + return false; + } +} + +// Get, Set, Eval Pages +if (pages == "") { + var tasks = dv.pages().file.tasks; +} else if (typeof pages === "string" && pages.startsWith("dv.pages")) { + var tasks = eval(pages); +} else if (typeof pages && pages.every((p) => p.task)) { + var tasks = pages; +} else { + var tasks = dv.pages(pages).file.tasks; +} + +// Variables +var done, + doneWithoutCompletionDate, + due, + recurrence, + overdue, + start, + scheduled, + process, + progress, + cancelled, + dailyNote, + dailyNoteRegEx; +if (!dailyNoteFormat) { + dailyNoteFormat = "YYYY-MM-DD"; +} +var dailyNoteRegEx = momentToRegex(dailyNoteFormat); +var tToday = moment().format("YYYY-MM-DD"); +var tMonth = moment().format("M"); +var tDay = moment().format("d"); +var tYear = moment().format("YYYY"); +var tid = new Date().getTime(); +if (startPosition) { + var selectedMonth = moment(startPosition, "YYYY-MM").date(1); + var selectedList = moment(startPosition, "YYYY-MM").date(1); + var selectedWeek = moment(startPosition, "YYYY-ww").startOf("week"); +} else { + var selectedMonth = moment(startPosition).date(1); + var selectedWeek = moment(startPosition).startOf("week"); + var selectedList = moment(startPosition).date(1); +} +var selectedDate = eval("selected" + capitalize(view)); +var arrowLeftIcon = + ''; +var arrowRightIcon = + ''; +var filterIcon = + ''; +var monthIcon = + ''; +var weekIcon = + ''; +var listIcon = + ''; +var calendarClockIcon = + ''; +var calendarCheckIcon = + ''; +var calendarHeartIcon = + ''; +var cellTemplate = + "
{{cellName}}
{{cellContent}}
"; +var taskTemplate = + "
{{note}}
{{icon}}
{{taskContent}}
"; +const rootNode = dv.el("div", "", { + cls: "tasksCalendar " + options, + attr: { + id: "tasksCalendar" + tid, + view: view, + style: "position:relative;-webkit-user-select:none!important", + }, +}); +if (css) { + var style = document.createElement("style"); + style.innerHTML = css; + rootNode.append(style); +} +var taskDoneIcon = "βœ…"; +var taskDueIcon = "πŸ“…"; +var taskScheduledIcon = "⏳"; +var taskRecurrenceIcon = "πŸ”"; +var taskOverdueIcon = "⚠️"; +var taskProcessIcon = "⏺️"; +var taskProgressIcon = "⏯️"; +var taskCancelledIcon = "🚫"; +var taskStartIcon = "πŸ›«"; +var taskDailyNoteIcon = "πŸ“„"; + +// Initialze +getMeta(tasks); +setButtons(); +setStatisticPopUp(); +setWeekViewContext(); +eval("get" + capitalize(view))(tasks, selectedDate); + +function getMeta(tasks) { + for (i = 0; i < tasks.length; i++) { + var taskText = tasks[i].text; + var taskFile = getFilename(tasks[i].path); + var dailyNoteMatch = taskFile.match(eval(dailyNoteRegEx)); + var dailyTaskMatch = taskText.match(/(\d{4}\-\d{2}\-\d{2})/); + if (dailyNoteMatch) { + if (!dailyTaskMatch) { + tasks[i].dailyNote = moment(dailyNoteMatch[1], dailyNoteFormat).format( + "YYYY-MM-DD" + ); + } + } + var dueMatch = taskText.match(/\πŸ“…\W(\d{4}\-\d{2}\-\d{2})/); + if (dueMatch) { + tasks[i].due = dueMatch[1]; + tasks[i].text = tasks[i].text.replace(dueMatch[0], ""); + } + var startMatch = taskText.match(/\πŸ›«\W(\d{4}\-\d{2}\-\d{2})/); + if (startMatch) { + tasks[i].start = startMatch[1]; + tasks[i].text = tasks[i].text.replace(startMatch[0], ""); + } + var scheduledMatch = taskText.match(/\⏳\W(\d{4}\-\d{2}\-\d{2})/); + if (scheduledMatch) { + tasks[i].scheduled = scheduledMatch[1]; + tasks[i].text = tasks[i].text.replace(scheduledMatch[0], ""); + } + var completionMatch = taskText.match(/\βœ…\W(\d{4}\-\d{2}\-\d{2})/); + if (completionMatch) { + tasks[i].completion = completionMatch[1]; + tasks[i].text = tasks[i].text.replace(completionMatch[0], ""); + } + var repeatMatch = taskText.includes("πŸ”"); + if (repeatMatch) { + tasks[i].recurrence = true; + tasks[i].text = tasks[i].text.substring(0, taskText.indexOf("πŸ”")); + } + var lowMatch = taskText.includes("πŸ”½"); + if (lowMatch) { + tasks[i].priority = "D"; + } + var mediumMatch = taskText.includes("πŸ”Ό"); + if (mediumMatch) { + tasks[i].priority = "B"; + } + var highMatch = taskText.includes("⏫"); + if (highMatch) { + tasks[i].priority = "A"; + } + if (!lowMatch && !mediumMatch && !highMatch) { + tasks[i].priority = "C"; + } + if (globalTaskFilter) { + tasks[i].text = tasks[i].text.replaceAll(globalTaskFilter, ""); + } else { + tasks[i].text = tasks[i].text.replaceAll("#task", ""); + } + tasks[i].text = tasks[i].text.replaceAll("[[", ""); + tasks[i].text = tasks[i].text.replaceAll("]]", ""); + tasks[i].text = tasks[i].text.replace(/\[.*?\]/gm, ""); + } +} + +function getFilename(path) { + var filename = path.match(/^(?:.*\/)?([^\/]+?|)(?=(?:\.[^\/.]*)?$)/)[1]; + return filename; +} + +function capitalize(str) { + return str[0].toUpperCase() + str.slice(1); +} + +function getMetaFromNote(task, metaName) { + var meta = dv.pages('"' + task.link.path + '"')[metaName][0]; + if (meta) { + return meta; + } else { + return ""; + } +} + +function transColor(color, percent) { + var num = parseInt(color.replace("#", ""), 16), + amt = Math.round(2.55 * percent), + R = (num >> 16) + amt, + B = ((num >> 8) & 0x00ff) + amt, + G = (num & 0x0000ff) + amt; + return ( + "#" + + ( + 0x1000000 + + (R < 255 ? (R < 1 ? 0 : R) : 255) * 0x10000 + + (B < 255 ? (B < 1 ? 0 : B) : 255) * 0x100 + + (G < 255 ? (G < 1 ? 0 : G) : 255) + ) + .toString(16) + .slice(1) + ); +} + +function momentToRegex(momentFormat) { + momentFormat = momentFormat.replaceAll(".", "\\."); + momentFormat = momentFormat.replaceAll(",", "\\,"); + momentFormat = momentFormat.replaceAll("-", "\\-"); + momentFormat = momentFormat.replaceAll(":", "\\:"); + momentFormat = momentFormat.replaceAll(" ", "\\s"); + + momentFormat = momentFormat.replace("dddd", "\\w{1,}"); + momentFormat = momentFormat.replace("ddd", "\\w{1,3}"); + momentFormat = momentFormat.replace("dd", "\\w{2}"); + momentFormat = momentFormat.replace("d", "\\d{1}"); + + momentFormat = momentFormat.replace("YYYY", "\\d{4}"); + momentFormat = momentFormat.replace("YY", "\\d{2}"); + + momentFormat = momentFormat.replace("MMMM", "\\w{1,}"); + momentFormat = momentFormat.replace("MMM", "\\w{3}"); + momentFormat = momentFormat.replace("MM", "\\d{2}"); + + momentFormat = momentFormat.replace("DDDD", "\\d{3}"); + momentFormat = momentFormat.replace("DDD", "\\d{1,3}"); + momentFormat = momentFormat.replace("DD", "\\d{2}"); + momentFormat = momentFormat.replace("D", "\\d{1,2}"); + + momentFormat = momentFormat.replace("ww", "\\d{1,2}"); + + regEx = "/^(" + momentFormat + ")$/"; + + return regEx; +} + +function getTasks(date) { + done = tasks + .filter( + (t) => + t.completed && + t.checked && + t.completion && + moment(t.completion.toString()).isSame(date) + ) + .sort((t) => t.completion); + doneWithoutCompletionDate = tasks + .filter( + (t) => + t.completed && + t.checked && + !t.completion && + t.due && + moment(t.due.toString()).isSame(date) + ) + .sort((t) => t.due); + done = done.concat(doneWithoutCompletionDate); + due = tasks + .filter( + (t) => + !t.completed && + !t.checked && + !t.recurrence && + t.due && + moment(t.due.toString()).isSame(date) + ) + .sort((t) => t.due); + recurrence = tasks + .filter( + (t) => + !t.completed && + !t.checked && + t.recurrence && + t.due && + moment(t.due.toString()).isSame(date) + ) + .sort((t) => t.due); + overdue = tasks + .filter( + (t) => + !t.completed && + t.due && + t.status != "-" && + moment(t.due.toString()).isBefore(date) + ) + .sort((t) => t.due); + start = tasks + .filter( + (t) => + !t.completed && + !t.checked && + t.start && + moment(t.start.toString()).isSame(date) + ) + .sort((t) => t.start); + scheduled = tasks + .filter( + (t) => + !t.completed && + !t.checked && + t.scheduled && + moment(t.scheduled.toString()).isSame(date) + ) + .sort((t) => t.scheduled); + process = tasks.filter( + (t) => + !t.completed && + !t.checked && + t.due && + t.start && + moment(t.due.toString()).isAfter(date) && + moment(t.start.toString()).isBefore(date) + ); + progress = tasks + .filter( + (t) => + !t.completed && + t.checked && + t.status == "/" && + ((t.due && moment(t.due.toString()).isSame(date)) || + (t.scheduled && moment(t.scheduled.toString()).isSame(date)) || + (t.start && moment(t.start.toString()).isSame(date))) + ) + .sort((t) => t.due); + cancelled = tasks + .filter( + (t) => + !t.completed && + t.checked && + t.status == "-" && + t.due && + moment(t.due.toString()).isSame(date) + ) + .sort((t) => t.due); + dailyNote = tasks + .filter( + (t) => + !t.completed && + !t.checked && + t.dailyNote && + moment(t.dailyNote.toString()).isSame(date) + ) + .sort((t) => t.dailyNote); +} + +function setTask(obj, cls) { + var lighter = 25; + var darker = -40; + var noteColor = getMetaFromNote(obj, "color"); + var textColor = getMetaFromNote(obj, "textColor"); + var noteIcon = getMetaFromNote(obj, "icon"); + var taskText = obj.text.replace("'", "'"); + var taskPath = obj.link.path.replace("'", "'"); + var taskIcon = eval("task" + capitalize(cls) + "Icon"); + if (obj.due) { + var relative = moment(obj.due).fromNow(); + } else { + var relative = ""; + } + var noteFilename = getFilename(taskPath); + if (noteIcon) { + noteFilename = noteIcon + " " + noteFilename; + } else { + noteFilename = taskIcon + " " + noteFilename; + cls += " noNoteIcon"; + } + var taskSubpath = obj.header.subpath; + var taskLine = taskSubpath ? taskPath + "#" + taskSubpath : taskPath; + if (noteColor && textColor) { + var style = + "--task-background:" + + noteColor + + "33;--task-color:" + + noteColor + + ";--dark-task-text-color:" + + textColor + + ";--light-task-text-color:" + + textColor; + } else if (noteColor && !textColor) { + var style = + "--task-background:" + + noteColor + + "33;--task-color:" + + noteColor + + ";--dark-task-text-color:" + + transColor(noteColor, darker) + + ";--light-task-text-color:" + + transColor(noteColor, lighter); + var style = + "--task-background:" + + noteColor + + "33;--task-color:" + + noteColor + + ";--dark-task-text-color:" + + transColor(noteColor, darker) + + ";--light-task-text-color:" + + transColor(noteColor, lighter); + } else if (!noteColor && textColor) { + var style = + "--task-background:#7D7D7D33;--task-color:#7D7D7D;--dark-task-text-color:" + + transColor(textColor, darker) + + ";--light-task-text-color:" + + transColor(textColor, lighter); + } else { + var style = + "--task-background:#7D7D7D33;--task-color:#7D7D7D;--dark-task-text-color:" + + transColor("#7D7D7D", darker) + + ";--light-task-text-color:" + + transColor("#7D7D7D", lighter); + } + var newTask = taskTemplate + .replace("{{taskContent}}", taskText) + .replace("{{class}}", cls) + .replace("{{taskPath}}", taskLine) + .replace("{{due}}", "done") + .replaceAll("{{style}}", style) + .replace("{{title}}", noteFilename + ": " + taskText) + .replace("{{note}}", noteFilename) + .replace("{{icon}}", taskIcon) + .replace("{{relative}}", relative); + return newTask; +} + +function setTaskContentContainer(currentDate) { + var cellContent = ""; + + function compareFn(a, b) { + if (a.priority.toUpperCase() < b.priority.toUpperCase()) { + return -1; + } + if (a.priority.toUpperCase() > b.priority.toUpperCase()) { + return 1; + } + if (a.priority == b.priority) { + if (a.text.toUpperCase() < b.text.toUpperCase()) { + return -1; + } + if (a.text.toUpperCase() > b.text.toUpperCase()) { + return 1; + } + return 0; + } + } + + function showTasks(tasksToShow, type) { + const sorted = [...tasksToShow].sort(compareFn); + for (var t = 0; t < sorted.length; t++) { + cellContent += setTask(sorted[t], type); + } + } + + if (tToday == currentDate) { + showTasks(overdue, "overdue"); + } + showTasks(due, "due"); + showTasks(scheduled, "scheduled"); + showTasks(start, "start"); + showTasks(process, "process"); + showTasks(progress, "progress"); + showTasks(dailyNote, "dailyNote"); + showTasks(recurrence, "recurrence"); + showTasks(done, "done"); + showTasks(cancelled, "cancelled"); + return cellContent; +} + +function setButtons() { + var buttons = + ""; + rootNode + .querySelector("span") + .appendChild(dv.el("div", buttons, { cls: "buttons", attr: {} })); + setButtonEvents(); +} + +function setButtonEvents() { + rootNode.querySelectorAll("button").forEach((btn) => + btn.addEventListener("click", () => { + var activeView = rootNode.getAttribute("view"); + if (btn.className == "previous") { + if (activeView == "month") { + selectedDate = moment(selectedDate).subtract(1, "months"); + getMonth(tasks, selectedDate); + } else if (activeView == "week") { + selectedDate = moment(selectedDate) + .subtract(7, "days") + .startOf("week"); + getWeek(tasks, selectedDate); + } else if (activeView == "list") { + selectedDate = moment(selectedDate).subtract(1, "months"); + getList(tasks, selectedDate); + } + } else if (btn.className == "current") { + if (activeView == "month") { + selectedDate = moment().date(1); + getMonth(tasks, selectedDate); + } else if (activeView == "week") { + selectedDate = moment().startOf("week"); + getWeek(tasks, selectedDate); + } else if (activeView == "list") { + selectedDate = moment().date(1); + getList(tasks, selectedDate); + } + } else if (btn.className == "next") { + if (activeView == "month") { + selectedDate = moment(selectedDate).add(1, "months"); + getMonth(tasks, selectedDate); + } else if (activeView == "week") { + selectedDate = moment(selectedDate).add(7, "days").startOf("week"); + getWeek(tasks, selectedDate); + } else if (activeView == "list") { + selectedDate = moment(selectedDate).add(1, "months"); + getList(tasks, selectedDate); + } + } else if (btn.className == "filter") { + rootNode.classList.toggle("filter"); + rootNode.querySelector("#statisticDone").classList.remove("active"); + rootNode.classList.remove("focusDone"); + } else if (btn.className == "monthView") { + if ( + moment().format("ww-YYYY") == moment(selectedDate).format("ww-YYYY") + ) { + selectedDate = moment().date(1); + } else { + selectedDate = moment(selectedDate).date(1); + } + getMonth(tasks, selectedDate); + } else if (btn.className == "listView") { + if ( + moment().format("ww-YYYY") == moment(selectedDate).format("ww-YYYY") + ) { + selectedDate = moment().date(1); + } else { + selectedDate = moment(selectedDate).date(1); + } + getList(tasks, selectedDate); + } else if (btn.className == "weekView") { + if (rootNode.getAttribute("view") == "week") { + var leftPos = rootNode.querySelector("button.weekView").offsetLeft; + rootNode.querySelector(".weekViewContext").style.left = + leftPos + "px"; + rootNode.querySelector(".weekViewContext").classList.toggle("active"); + if ( + rootNode + .querySelector(".weekViewContext") + .classList.contains("active") + ) { + var closeContextListener = function () { + rootNode + .querySelector(".weekViewContext") + .classList.remove("active"); + rootNode.removeEventListener( + "click", + closeContextListener, + false + ); + }; + setTimeout(function () { + rootNode.addEventListener("click", closeContextListener, false); + }, 100); + } + } else { + if ( + moment().format("MM-YYYY") != moment(selectedDate).format("MM-YYYY") + ) { + selectedDate = moment(selectedDate) + .startOf("month") + .startOf("week"); + } else { + selectedDate = moment().startOf("week"); + } + getWeek(tasks, selectedDate); + } + } else if (btn.className == "statistic") { + rootNode.querySelector(".statisticPopup").classList.toggle("active"); + } + btn.blur(); + }) + ); + rootNode.addEventListener("contextmenu", function (event) { + event.preventDefault(); + }); +} + +function setWrapperEvents() { + rootNode.querySelectorAll(".wrapperButton").forEach((wBtn) => + wBtn.addEventListener("click", () => { + var week = wBtn.getAttribute("data-week"); + var year = wBtn.getAttribute("data-year"); + selectedDate = moment(moment(year).add(week, "weeks")).startOf("week"); + rootNode.querySelector(`#tasksCalendar${tid} .grid`).remove(); + getWeek(tasks, selectedDate); + }) + ); +} + +function setStatisticPopUpEvents() { + rootNode.querySelectorAll(".statisticPopup li").forEach((li) => + li.addEventListener("click", () => { + var group = li.getAttribute("data-group"); + const liElements = rootNode.querySelectorAll(".statisticPopup li"); + if (li.classList.contains("active")) { + const liElements = rootNode.querySelectorAll(".statisticPopup li"); + for (const liElement of liElements) { + liElement.classList.remove("active"); + } + rootNode.classList.remove("focus" + capitalize(group)); + } else { + for (const liElement of liElements) { + liElement.classList.remove("active"); + } + li.classList.add("active"); + rootNode.classList.remove.apply( + rootNode.classList, + Array.from(rootNode.classList).filter((v) => v.startsWith("focus")) + ); + rootNode.classList.add("focus" + capitalize(group)); + } + }) + ); +} + +function setStatisticPopUp() { + var statistic = "
  • "; + statistic += "
  • "; + statistic += "
  • "; + statistic += "
  • "; + statistic += "
  • "; + statistic += "
  • "; + statistic += "
  • "; + statistic += "
  • "; + statistic += "
  • "; + rootNode + .querySelector("span") + .appendChild(dv.el("ul", statistic, { cls: "statisticPopup" })); + setStatisticPopUpEvents(); +} + +function setWeekViewContextEvents() { + rootNode.querySelectorAll(".weekViewContext li").forEach((li) => + li.addEventListener("click", () => { + var selectedStyle = li.getAttribute("data-style"); + const liElements = rootNode.querySelectorAll(".weekViewContext li"); + if (!li.classList.contains("active")) { + for (const liElement of liElements) { + liElement.classList.remove("active"); + } + li.classList.add("active"); + rootNode.classList.remove.apply( + rootNode.classList, + Array.from(rootNode.classList).filter((v) => v.startsWith("style")) + ); + rootNode.classList.add(selectedStyle); + } + rootNode.querySelector(".weekViewContext").classList.toggle("active"); + }) + ); +} + +function setWeekViewContext() { + var activeStyle = Array.from(rootNode.classList).filter((v) => + v.startsWith("style") + ); + var liElements = ""; + var styles = 11; + for (i = 1; i < styles + 1; i++) { + var liIcon = + "
    "; + liElements += + "
  • " + liIcon + "Style " + i + "
  • "; + } + rootNode + .querySelector("span") + .appendChild(dv.el("ul", liElements, { cls: "weekViewContext" })); + rootNode + .querySelector(".weekViewContext li[data-style=" + activeStyle + "]") + .classList.add("active"); + setWeekViewContextEvents(); +} + +function setStatisticValues( + dueCounter, + doneCounter, + overdueCounter, + startCounter, + scheduledCounter, + recurrenceCounter, + dailyNoteCounter +) { + var taskCounter = parseInt(dueCounter + doneCounter + overdueCounter); + var tasksRemaining = taskCounter - doneCounter; + var percentage = Math.round( + (100 / (dueCounter + doneCounter + overdueCounter)) * doneCounter + ); + percentage = isNaN(percentage) ? 100 : percentage; + + if (dueCounter == 0 && doneCounter == 0) { + rootNode.querySelector("button.statistic").innerHTML = calendarHeartIcon; + } else if (tasksRemaining > 0) { + rootNode.querySelector("button.statistic").innerHTML = calendarClockIcon; + } else if (dueCounter == 0 && doneCounter != 0) { + rootNode.querySelector("button.statistic").innerHTML = calendarCheckIcon; + } + if (tasksRemaining > 99) { + tasksRemaining = "⚠️"; + } + rootNode + .querySelector("button.statistic") + .setAttribute("data-percentage", percentage); + rootNode + .querySelector("button.statistic") + .setAttribute("data-remaining", tasksRemaining); + rootNode.querySelector("#statisticDone").innerText = + "βœ… Done: " + doneCounter + "/" + taskCounter; + rootNode.querySelector("#statisticDue").innerText = "πŸ“… Due: " + dueCounter; + rootNode.querySelector("#statisticOverdue").innerText = + "⚠️ Overdue: " + overdueCounter; + rootNode.querySelector("#statisticStart").innerText = + "πŸ›« Start: " + startCounter; + rootNode.querySelector("#statisticScheduled").innerText = + "⏳ Scheduled: " + scheduledCounter; + rootNode.querySelector("#statisticRecurrence").innerText = + "πŸ” Recurrence: " + recurrenceCounter; + rootNode.querySelector("#statisticDailyNote").innerText = + "πŸ“„ Daily Notes: " + dailyNoteCounter; +} + +function removeExistingView() { + if (rootNode.querySelector(`#tasksCalendar${tid} .grid`)) { + rootNode.querySelector(`#tasksCalendar${tid} .grid`).remove(); + } else if (rootNode.querySelector(`#tasksCalendar${tid} .list`)) { + rootNode.querySelector(`#tasksCalendar${tid} .list`).remove(); + } +} + +function getMonth(tasks, month) { + removeExistingView(); + var currentTitle = + "" + + moment(month).format("MMMM") + + " " + + moment(month).format("YYYY") + + ""; + rootNode.querySelector("button.current").innerHTML = currentTitle; + var gridContent = ""; + var firstDayOfMonth = moment(month).format("d"); + var firstDateOfMonth = moment(month).startOf("month").format("D"); + var lastDateOfMonth = moment(month).endOf("month").format("D"); + var dueCounter = 0; + var doneCounter = 0; + var overdueCounter = 0; + var startCounter = 0; + var scheduledCounter = 0; + var recurrenceCounter = 0; + var dailyNoteCounter = 0; + + // Move First Week Of Month To Second Week In Month View + if (firstDayOfMonth == 0) { + firstDayOfMonth = 7; + } + + // Set Grid Heads + var gridHeads = ""; + for ( + h = 0 - firstDayOfMonth + parseInt(firstDayOfWeek); + h < 7 - firstDayOfMonth + parseInt(firstDayOfWeek); + h++ + ) { + var weekDayNr = moment(month).add(h, "days").format("d"); + var weekDayName = moment(month).add(h, "days").format("ddd"); + if ( + tDay == weekDayNr && + tMonth == moment(month).format("M") && + tYear == moment(month).format("YYYY") + ) { + gridHeads += + "
    " + + weekDayName + + "
    "; + } else { + gridHeads += + "
    " + + weekDayName + + "
    "; + } + } + + // Set Wrappers + var wrappers = ""; + var starts = 0 - firstDayOfMonth + parseInt(firstDayOfWeek); + for (w = 1; w < 7; w++) { + var wrapper = ""; + var weekNr = ""; + var yearNr = ""; + var monthName = moment(month) + .format("MMM") + .replace(".", "") + .substring(0, 3); + for (i = starts; i < starts + 7; i++) { + if (i == starts) { + weekNr = moment(month).add(i, "days").format("w"); + yearNr = moment(month).add(i, "days").format("YYYY"); + } + var currentDate = moment(month).add(i, "days").format("YYYY-MM-DD"); + if (!dailyNoteFolder) { + var dailyNotePath = currentDate; + } else { + var dailyNotePath = dailyNoteFolder + "/" + currentDate; + } + var weekDay = moment(month).add(i, "days").format("d"); + var shortDayName = moment(month).add(i, "days").format("D"); + var longDayName = moment(month).add(i, "days").format("D. MMM"); + var shortWeekday = moment(month).add(i, "days").format("ddd"); + + // Filter Tasks + getTasks(currentDate); + + // Count Events Only From Selected Month + if ( + moment(month).format("MM") == moment(month).add(i, "days").format("MM") + ) { + dueCounter += due.length; + dueCounter += recurrence.length; + dueCounter += scheduled.length; + dueCounter += dailyNote.length; + doneCounter += done.length; + startCounter += start.length; + scheduledCounter += scheduled.length; + recurrenceCounter += recurrence.length; + dailyNoteCounter += dailyNote.length; + // Get Overdue Count From Today + if ( + moment().format("YYYY-MM-DD") == + moment(month).add(i, "days").format("YYYY-MM-DD") + ) { + overdueCounter = overdue.length; + } + } + + // Set New Content Container + var cellContent = setTaskContentContainer(currentDate); + + // Set Cell Name And Weekday + if (moment(month).add(i, "days").format("D") == 1) { + var cell = cellTemplate + .replace("{{date}}", currentDate) + .replace("{{cellName}}", longDayName) + .replace("{{cellContent}}", cellContent) + .replace("{{weekday}}", weekDay) + .replace("{{dailyNote}}", dailyNotePath); + cell = cell.replace("{{class}}", "{{class}} newMonth"); + } else { + var cell = cellTemplate + .replace("{{date}}", currentDate) + .replace("{{cellName}}", shortDayName) + .replace("{{cellContent}}", cellContent) + .replace("{{weekday}}", weekDay) + .replace("{{dailyNote}}", dailyNotePath); + } + + // Set prevMonth, currentMonth, nextMonth + if (i < 0) { + cell = cell.replace("{{class}}", "prevMonth"); + } else if (i >= 0 && i < lastDateOfMonth && tToday !== currentDate) { + cell = cell.replace("{{class}}", "currentMonth"); + } else if (i >= 0 && i < lastDateOfMonth && tToday == currentDate) { + cell = cell.replace("{{class}}", "currentMonth today"); + } else if (i >= lastDateOfMonth) { + cell = cell.replace("{{class}}", "nextMonth"); + } + wrapper += cell; + } + wrappers += + "
    W" + + weekNr + + "
    " + + wrapper + + "
    "; + starts += 7; + } + gridContent += + "
    " + + gridHeads + + "
    "; + gridContent += + "
    " + + wrappers + + "
    "; + rootNode + .querySelector("span") + .appendChild(dv.el("div", gridContent, { cls: "grid" })); + setWrapperEvents(); + setStatisticValues( + dueCounter, + doneCounter, + overdueCounter, + startCounter, + scheduledCounter, + recurrenceCounter, + dailyNoteCounter + ); + rootNode.setAttribute("view", "month"); +} + +function getWeek(tasks, week) { + removeExistingView(); + var currentTitle = + "" + + moment(week).format("YYYY") + + " " + + moment(week).format("[W]w") + + ""; + rootNode.querySelector("button.current").innerHTML = currentTitle; + var gridContent = ""; + var currentWeekday = moment(week).format("d"); + var weekNr = moment(week).format("[W]w"); + var dueCounter = 0; + var doneCounter = 0; + var overdueCounter = 0; + var startCounter = 0; + var scheduledCounter = 0; + var recurrenceCounter = 0; + var dailyNoteCounter = 0; + + for ( + i = 0 - currentWeekday + parseInt(firstDayOfWeek); + i < 7 - currentWeekday + parseInt(firstDayOfWeek); + i++ + ) { + var currentDate = moment(week).add(i, "days").format("YYYY-MM-DD"); + if (!dailyNoteFolder) { + var dailyNotePath = currentDate; + } else { + var dailyNotePath = dailyNoteFolder + "/" + currentDate; + } + var weekDay = moment(week).add(i, "days").format("d"); + var dayName = moment(currentDate).format("ddd D."); + var longDayName = moment(currentDate).format("ddd, D. MMM"); + + // Filter Tasks + getTasks(currentDate); + + // Count Events From Selected Week + dueCounter += due.length; + dueCounter += recurrence.length; + dueCounter += scheduled.length; + dueCounter += dailyNote.length; + doneCounter += done.length; + startCounter += start.length; + scheduledCounter += scheduled.length; + recurrenceCounter += recurrence.length; + dailyNoteCounter += dailyNote.length; + if ( + moment().format("YYYY-MM-DD") == + moment(week).add(i, "days").format("YYYY-MM-DD") + ) { + overdueCounter = overdue.length; + } + + // Set New Content Container + var cellContent = setTaskContentContainer(currentDate); + + // Set Cell Name And Weekday + var cell = cellTemplate + .replace("{{date}}", currentDate) + .replace("{{cellName}}", longDayName) + .replace("{{cellContent}}", cellContent) + .replace("{{weekday}}", weekDay) + .replace("{{dailyNote}}", dailyNotePath); + + // Set Cell Name And Weekday + if (moment(week).add(i, "days").format("D") == 1) { + var cell = cellTemplate + .replace("{{date}}", currentDate) + .replace("{{cellName}}", longDayName) + .replace("{{cellContent}}", cellContent) + .replace("{{weekday}}", weekDay) + .replace("{{dailyNote}}", dailyNotePath); + } else { + var cell = cellTemplate + .replace("{{date}}", currentDate) + .replace("{{cellName}}", dayName) + .replace("{{cellContent}}", cellContent) + .replace("{{weekday}}", weekDay) + .replace("{{dailyNote}}", dailyNotePath); + } + + // Set Today, Before Today, After Today + if (currentDate < tToday) { + cell = cell.replace("{{class}}", "beforeToday"); + } else if (currentDate == tToday) { + cell = cell.replace("{{class}}", "today"); + } else if (currentDate > tToday) { + cell = cell.replace("{{class}}", "afterToday"); + } + gridContent += cell; + } + rootNode + .querySelector("span") + .appendChild( + dv.el("div", gridContent, { cls: "grid", attr: { "data-week": weekNr } }) + ); + setStatisticValues( + dueCounter, + doneCounter, + overdueCounter, + startCounter, + scheduledCounter, + recurrenceCounter, + dailyNoteCounter + ); + rootNode.setAttribute("view", "week"); +} + +function getList(tasks, month) { + removeExistingView(); + var currentTitle = + "" + + moment(month).format("MMMM") + + " " + + moment(month).format("YYYY") + + ""; + rootNode.querySelector("button.current").innerHTML = currentTitle; + var listContent = ""; + var dueCounter = 0; + var doneCounter = 0; + var overdueCounter = 0; + var startCounter = 0; + var scheduledCounter = 0; + var recurrenceCounter = 0; + var dailyNoteCounter = 0; + + // Loop Days From Current Month + for (i = 0; i < moment(month).endOf("month").format("D"); i++) { + var currentDate = moment(month) + .startOf("month") + .add(i, "days") + .format("YYYY-MM-DD"); + var monthName = moment(month) + .format("MMM") + .replace(".", "") + .substring(0, 3); + + // Filter Tasks + getTasks(currentDate); + + // Count Events + dueCounter += due.length; + dueCounter += recurrence.length; + dueCounter += scheduled.length; + dueCounter += dailyNote.length; + doneCounter += done.length; + startCounter += start.length; + scheduledCounter += scheduled.length; + recurrenceCounter += recurrence.length; + dailyNoteCounter += dailyNote.length; + if (moment().format("YYYY-MM-DD") == currentDate) { + overdueCounter = overdue.length; + var overdueDetails = + "
    Overdue" + + setTaskContentContainer(currentDate) + + "
    "; + var todayDetails = + "
    Today" + + setTaskContentContainer(currentDate) + + "
    "; + + // Upcoming + if (!upcomingDays) { + upcomingDays = "7"; + } + var upcomingContent = ""; + for (t = 1; t < parseInt(upcomingDays) + 1; t++) { + var next = moment(currentDate).add(t, "days").format("YYYY-MM-DD"); + getTasks(next); + upcomingContent += setTaskContentContainer(next); + } + var upcomingDetails = + "
    Upcoming" + + upcomingContent + + "
    "; + + listContent += + "
    " + + moment(currentDate).format("dddd, D") + + " " + + moment(currentDate).format("[W]w") + + "
    " + + overdueDetails + + todayDetails + + upcomingDetails + + "
    "; + } else { + listContent += + "
    " + + moment(currentDate).format("dddd, D") + + " " + + moment(currentDate).format("[W]w") + + "
    " + + setTaskContentContainer(currentDate) + + "
    "; + } + } + rootNode.querySelector("span").appendChild( + dv.el("div", listContent, { + cls: "list", + attr: { "data-month": monthName }, + }) + ); + setStatisticValues( + dueCounter, + doneCounter, + overdueCounter, + startCounter, + scheduledCounter, + recurrenceCounter, + dailyNoteCounter + ); + rootNode.setAttribute("view", "list"); + + // Scroll To Today If Selected Month Is Current Month + if (moment().format("YYYY-MM") == moment(month).format("YYYY-MM")) { + var listElement = rootNode.querySelector(".list"); + var todayElement = rootNode.querySelector(".today"); + var scrollPos = todayElement.offsetTop - todayElement.offsetHeight + 85; + listElement.scrollTo(0, scrollPos); + } +}