From a5913897d86eb8079576793a9a87db1d8f4ff8aa Mon Sep 17 00:00:00 2001 From: Felix Berkemeier Date: Mon, 29 Jun 2020 06:42:54 +0200 Subject: [PATCH] feat: Add checkvist integration --- README.md | 1 + src/scripts/content/checkvist.js | 77 ++++++++++++++++++++++++++++++++ src/scripts/origins.js | 4 ++ src/styles/style.css | 42 +++++++++++++++++ 4 files changed, 124 insertions(+) create mode 100644 src/scripts/content/checkvist.js diff --git a/README.md b/README.md index 0b7b86ef7..d0ca24892 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,7 @@ out of the way and focus on real work. - [Bugherd](https://www.bugherd.com/) - [Bugzilla](https://bugzilla.mozilla.org/) - [CapsuleCRM](http://www.capsulecrm.com/) +- [Checkvist](https://checkvist.com) - [ClickUp](https://clickup.com/) - [CLOUDES](http://cloudes.me/) - [Clubhouse](https://clubhouse.io/) diff --git a/src/scripts/content/checkvist.js b/src/scripts/content/checkvist.js new file mode 100644 index 000000000..90dae1eaa --- /dev/null +++ b/src/scripts/content/checkvist.js @@ -0,0 +1,77 @@ +'use strict'; +/* global togglbutton, $ */ + +togglbutton.render( + '.task:not(.toggl)', + { observe: true }, + element => { + // by default the toggl button is shown on the right + // however, if the list title is tagged with #togglLeft, the toggl button is shown on the left + const tasksBlock = $('#tasks_block'); + if ($('#header_span ~ .tag_togglLeft') && !tasksBlock.matches('.togglLeft')) { + tasksBlock.classList.add('togglLeft'); + } + + // parents is a function to get all parent nodes of a node + // taken from https://stackoverflow.com/questions/8729193/how-to-get-all-parent-nodes-of-given-element-in-pure-javascript#comment85476662_8729274 + const parents = node => ( + node.parentElement + ? parents(node.parentElement) + : [] + ).concat([node]); + + // most information (e.g. tags) of a task is stored in its coreDiv + // therefore parentTasks is a list of all parent tasks' coreDivs + // the order is reversed so that closer parents come first + const parentTasks = parents(element) + .filter(parent => parent.matches('.task')) + .map(parent => $('.coreDiv', parent)) + .reverse(); + const currentTask = parentTasks.shift(); + + // by default only leaf tasks are togglized + // however, togglization can be limited to branches tagged with #togglize or #togglizeAll: + // - in a branch tagged with #togglizeAll, all tasks are togglized + // - in a branch tagged with #togglize, only its leaf tasks are togglized + const togglizeTaggedOnly = $('.tag_togglize') || $('.tag_togglizeAll'); + const togglizeThis = !currentTask.matches('.task_closed') && ( + togglizeTaggedOnly + ? ( + $('#header_span ~ .tag_togglizeAll') || parentTasks.some(parent => parent.matches('.tag_togglizeAll')) + ) || ( + ($('#header_span ~ .tag_togglize') || parentTasks.some(parent => parent.matches('.tag_togglize'))) && + element.matches('.leafItem') + ) + : element.matches('.leafItem') + ); + if (!togglizeThis) { + return; + } + + // helper function to extract the task text of a task + const getTaskText = elem => $('.userContent', elem).textContent.trim(); + + const descriptionSelector = () => getTaskText(currentTask); + + // by default the project is the text of the immediate parent + // however, if a parent is tagged with #togglProject, the project is the text of this parent + const projectSelector = () => { + const taggedParent = parentTasks.find(parent => parent.matches('.tag_togglProject')); + return getTaskText(taggedParent || parentTasks[0]); + }; + + const tagsSelector = () => [...currentTask.classList] + .filter(item => item.startsWith('tag_') && !item.startsWith('tag_toggl')) + .map(item => item.substring(4)); + + const link = togglbutton.createTimerLink({ + className: 'checkvist', + buttonType: 'minimal', + description: descriptionSelector, + projectName: projectSelector, + tags: tagsSelector + }); + + currentTask.appendChild(link); + } +); diff --git a/src/scripts/origins.js b/src/scripts/origins.js index c67daf5dc..e83e0bf88 100644 --- a/src/scripts/origins.js +++ b/src/scripts/origins.js @@ -83,6 +83,10 @@ export default { url: '*://*.capsulecrm.com/*', name: 'CapsuleCRM' }, + 'checkvist.com': { + url: '*://checkvist.com/*', + name: 'Checkvist' + }, 'clickup.com': { url: '*://*.clickup.com/*', name: 'ClickUp' diff --git a/src/styles/style.css b/src/styles/style.css index 8e0ccb367..42b305996 100644 --- a/src/styles/style.css +++ b/src/styles/style.css @@ -1552,3 +1552,45 @@ body.notion-body.dark .toggl-button.notion { font-weight: bold; position: relative; top: -3px; +} + +/********* CHECKVIST *********/ +.toggl-button.checkvist { + position: absolute; + top: 7px; + right: -43px; + opacity: 0; +} + +.toggl-button.checkvist.active, +.toggl-button.checkvist:hover, +.selectedTask > .toggl-button.checkvist, +.task.toggl > .coreDiv:hover .toggl-button.checkvist { + opacity: 1; +} + +#tasks_block:not(.togglLeft) .coreDiv { + margin-right: 35px; +} + +#tasks_block.togglLeft ul.topLevel { + padding-left: 48px; +} + +#tasks_block.togglLeft .toggl-button.checkvist { + left: -43px; +} + +#tasks_block.togglLeft .task.toggl > .coreDiv::before { + content: ''; + position: absolute; + top: 0; + bottom: 0; + right: 100%; + width: 45px; +} + +.tag[class^="tag_toggl"], +.tag[class*=" tag_toggl"] { + display: none; +}