Skip to content

Commit

Permalink
feat: Added workflowy.com integration
Browse files Browse the repository at this point in the history
  • Loading branch information
BeksOmega authored and tcrammond committed Apr 10, 2019
1 parent 67a02da commit ffeaaab
Show file tree
Hide file tree
Showing 5 changed files with 186 additions and 5 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ Add Toggl one-click time tracking to popular web tools.
- [Waffle](https://waffle.io/)
- [WordPress](https://wordpress.com)
- [Workast](https://workast.io)
- [Workflowy](https://workflowy.com)
- [Workfront](https://www.workfront.com/)
- [Worksection](http://worksection.com/)
- [Wrike](https://www.wrike.com/)
Expand Down
19 changes: 14 additions & 5 deletions src/scripts/common.js
Original file line number Diff line number Diff line change
Expand Up @@ -172,11 +172,16 @@ window.togglbutton = {
let len;

const elems = document.querySelectorAll(selector);
if (!elems.length) {
return;
}

for (i = 0, len = elems.length; i < len; i += 1) {
elems[i].classList.add('toggl');
}

// Catch content errors here as well as render() in case of async rendering (MutationObserver)
// Catch content errors here as well as render() in case of async rendering
// (MutationObserver)
try {
for (i = 0, len = elems.length; i < len; i += 1) {
renderer(elems[i]);
Expand Down Expand Up @@ -210,7 +215,8 @@ window.togglbutton = {

const description = togglbutton.mainDescription.toLowerCase();

const projectId = togglbutton.findProjectIdByName(togglbutton.currentProject);
const projectId = togglbutton.findProjectIdByName(
togglbutton.currentProject);

if (togglbutton.entries) {
togglbutton.entries.forEach(function (entry) {
Expand Down Expand Up @@ -300,7 +306,8 @@ window.togglbutton = {

const elemRect = togglbutton.element.getBoundingClientRect();
editForm = $('#toggl-button-edit-form');
const position = togglbutton.topPosition(elemRect, editFormWidth, editFormHeight);
const position = togglbutton.topPosition(
elemRect, editFormWidth, editFormHeight);

if (editForm !== null) {
togglButtonDescription = $('#toggl-button-description');
Expand Down Expand Up @@ -529,7 +536,8 @@ window.togglbutton = {
return;
}

const current = Array.from(document.querySelectorAll('.toggl-button:not(.toggl-button-edit-form-button)'))
const current = Array.from(document.querySelectorAll(
'.toggl-button:not(.toggl-button-edit-form-button)'))
.find(button => button.title.indexOf(entry.description) !== -1);

if (current) {
Expand All @@ -555,7 +563,8 @@ window.togglbutton = {
},

deactivateAllTimerLinks: function () {
const allActive = document.querySelectorAll('.toggl-button.active:not(.toggl-button-edit-form-button)');
const allActive = document.querySelectorAll(
'.toggl-button.active:not(.toggl-button-edit-form-button)');
for (const active of allActive) {
togglbutton.deactivateTimerLink(active);
}
Expand Down
146 changes: 146 additions & 0 deletions src/scripts/content/workflowy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
'use strict';
/* global togglbutton, $ */

/* Hover on Bullet Popup */
togglbutton.render(
// TODO: Change selector if the popup ever gets a constant class.
'.name:not(.toggl) > div:not(.content)',
{ observe: true },
$container => {
const $bulletInfo = $('.content', $container.parentElement);

const descriptionSelector = () => {
return getDescription($bulletInfo);
};

const tagsSelector = () => {
return getTags($bulletInfo);
};

const link = togglbutton.createTimerLink({
className: 'workflowy',
description: descriptionSelector,
tags: tagsSelector
});

insertLink($container, link);
}
);

/* More Options Menu Popup */
togglbutton.render(
// TODO: Change selector if the popup ever gets a constant class.
'.selected:not(.mainTreeRoot) ~ .pageControls > .pageMenu:not(.toggl) >' +
' div:nth-child(2)',
{ observe: true },
$container => {
// Get the content of the top bullet.
const $bulletInfo = $('.content');

const descriptionSelector = () => {
return getDescription($bulletInfo);
};

const tagsSelector = () => {
return getTags($bulletInfo);
};

const link = togglbutton.createTimerLink({
className: 'workflowy',
description: descriptionSelector,
tags: tagsSelector
});

insertLink($container, link);
}
);

function getDescription (bulletInfo) {
let description = '';
let currentNode = bulletInfo.childNodes[0];
while (currentNode !== bulletInfo) {
// If it is a text node.
if (currentNode.nodeType === 3) {
description += currentNode.textContent;
}

// Try to go down the tree.
let nextNode = currentNode.firstChild || currentNode.nextSibling;
// Span means it is a tag, and tag text should not be included.
while (nextNode && nextNode.nodeName === 'SPAN') {
nextNode = nextNode.nextSibling;
}
// If we couldn't go down try to go back up the tree.
if (!nextNode) {
nextNode = currentNode.parentNode;
while (nextNode !== bulletInfo) {
// We are valid again!
if (nextNode.nextSibling) {
nextNode = nextNode.nextSibling;
break;
}
// Try to go up again. If we reach the bulletInfo node that
// means we've reached the top and we will break out of both loops.
nextNode = nextNode.parentNode;
}
}
currentNode = nextNode;
}
return description.trim();
}

function getTags (bulletInfo) {
const tagsArray = [];
let currentNode = bulletInfo.childNodes[0];
while (currentNode !== bulletInfo) {
if (currentNode.classList &&
currentNode.classList.contains('contentTagText')) {
tagsArray.push(currentNode.textContent.trim());
}

// Try to go down the tree.
let nextNode = currentNode.firstChild || currentNode.nextSibling;
// If we can't go down try to go back up the tree.
if (!nextNode) {
nextNode = currentNode.parentNode;
while (nextNode !== bulletInfo) {
// We are valid again!
if (nextNode.nextSibling) {
nextNode = nextNode.nextSibling;
break;
}
// Try to go up again. If we reach the bulletInfo node that
// means we've reached the top and we will break out of both loops.
nextNode = nextNode.parentNode;
}
}
currentNode = nextNode;
}
return tagsArray;
}

function insertLink (popup, link) {
const INSERT_POSITION = 3;

/* Massage the DOM */
const wrapper = document.createElement('div');
wrapper.classList.add('workflowy-toggl-wrapper');
// This makes sure the 'Start timer' link matches the style of the other
// options (even when the theme is changed).
wrapper.classList.add(popup.children[0].classList[0]);
wrapper.appendChild(link);
popup.insertBefore(wrapper, popup.children[INSERT_POSITION]);

// We have to add the toggl class to the parent of the popup,
// because the popup's classes get overwritten by workflowy.
const parent = popup.parentElement;
parent.classList.add('toggl');

// And remove the class when the parent element's children change (meaning
// the popup is deleted).
const observer = new MutationObserver(function (mutationsList, observer) {
parent.classList.remove('toggl');
observer.disconnect();
});
observer.observe(parent, { childList: true });
}
4 changes: 4 additions & 0 deletions src/scripts/origins.js
Original file line number Diff line number Diff line change
Expand Up @@ -587,6 +587,10 @@ export default {
url: '*://*.workast.io/*',
name: 'Workast'
},
'workflowy.com': {
url: '*://workflowy.com/*',
name: 'Workflowy'
},
'my.workfront.com': {
url: '*://*.my.workfront.com/*',
name: 'Workfront'
Expand Down
21 changes: 21 additions & 0 deletions src/styles/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -1612,3 +1612,24 @@ label > .toggl-button.outlook {
background-color: #f5f5f5 !important;
color: #6a7479;
}

/****** WORKFLOWY ******/
.workflowy-toggl-wrapper {
display: flex !important;
}

.toggl-button.workflowy:not(.toggl-button-edit-form-button) {
background-position-x: right;
background-position-y: center;
background-size: 14px 14px;
line-height: 24px;
height: 24px;
font-size: 100%;
padding-left: 0;
padding-right: 23px;
flex-grow: 1;
-webkit-box-flex: 1;
color: inherit !important;
cursor: default !important;
text-decoration: none !important;
}

0 comments on commit ffeaaab

Please sign in to comment.