Skip to content

Commit ffeaaab

Browse files
BeksOmegatcrammond
authored andcommitted
feat: Added workflowy.com integration
1 parent 67a02da commit ffeaaab

File tree

5 files changed

+186
-5
lines changed

5 files changed

+186
-5
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ Add Toggl one-click time tracking to popular web tools.
121121
- [Waffle](https://waffle.io/)
122122
- [WordPress](https://wordpress.com)
123123
- [Workast](https://workast.io)
124+
- [Workflowy](https://workflowy.com)
124125
- [Workfront](https://www.workfront.com/)
125126
- [Worksection](http://worksection.com/)
126127
- [Wrike](https://www.wrike.com/)

src/scripts/common.js

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -172,11 +172,16 @@ window.togglbutton = {
172172
let len;
173173

174174
const elems = document.querySelectorAll(selector);
175+
if (!elems.length) {
176+
return;
177+
}
178+
175179
for (i = 0, len = elems.length; i < len; i += 1) {
176180
elems[i].classList.add('toggl');
177181
}
178182

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

211216
const description = togglbutton.mainDescription.toLowerCase();
212217

213-
const projectId = togglbutton.findProjectIdByName(togglbutton.currentProject);
218+
const projectId = togglbutton.findProjectIdByName(
219+
togglbutton.currentProject);
214220

215221
if (togglbutton.entries) {
216222
togglbutton.entries.forEach(function (entry) {
@@ -300,7 +306,8 @@ window.togglbutton = {
300306

301307
const elemRect = togglbutton.element.getBoundingClientRect();
302308
editForm = $('#toggl-button-edit-form');
303-
const position = togglbutton.topPosition(elemRect, editFormWidth, editFormHeight);
309+
const position = togglbutton.topPosition(
310+
elemRect, editFormWidth, editFormHeight);
304311

305312
if (editForm !== null) {
306313
togglButtonDescription = $('#toggl-button-description');
@@ -529,7 +536,8 @@ window.togglbutton = {
529536
return;
530537
}
531538

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

535543
if (current) {
@@ -555,7 +563,8 @@ window.togglbutton = {
555563
},
556564

557565
deactivateAllTimerLinks: function () {
558-
const allActive = document.querySelectorAll('.toggl-button.active:not(.toggl-button-edit-form-button)');
566+
const allActive = document.querySelectorAll(
567+
'.toggl-button.active:not(.toggl-button-edit-form-button)');
559568
for (const active of allActive) {
560569
togglbutton.deactivateTimerLink(active);
561570
}

src/scripts/content/workflowy.js

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
'use strict';
2+
/* global togglbutton, $ */
3+
4+
/* Hover on Bullet Popup */
5+
togglbutton.render(
6+
// TODO: Change selector if the popup ever gets a constant class.
7+
'.name:not(.toggl) > div:not(.content)',
8+
{ observe: true },
9+
$container => {
10+
const $bulletInfo = $('.content', $container.parentElement);
11+
12+
const descriptionSelector = () => {
13+
return getDescription($bulletInfo);
14+
};
15+
16+
const tagsSelector = () => {
17+
return getTags($bulletInfo);
18+
};
19+
20+
const link = togglbutton.createTimerLink({
21+
className: 'workflowy',
22+
description: descriptionSelector,
23+
tags: tagsSelector
24+
});
25+
26+
insertLink($container, link);
27+
}
28+
);
29+
30+
/* More Options Menu Popup */
31+
togglbutton.render(
32+
// TODO: Change selector if the popup ever gets a constant class.
33+
'.selected:not(.mainTreeRoot) ~ .pageControls > .pageMenu:not(.toggl) >' +
34+
' div:nth-child(2)',
35+
{ observe: true },
36+
$container => {
37+
// Get the content of the top bullet.
38+
const $bulletInfo = $('.content');
39+
40+
const descriptionSelector = () => {
41+
return getDescription($bulletInfo);
42+
};
43+
44+
const tagsSelector = () => {
45+
return getTags($bulletInfo);
46+
};
47+
48+
const link = togglbutton.createTimerLink({
49+
className: 'workflowy',
50+
description: descriptionSelector,
51+
tags: tagsSelector
52+
});
53+
54+
insertLink($container, link);
55+
}
56+
);
57+
58+
function getDescription (bulletInfo) {
59+
let description = '';
60+
let currentNode = bulletInfo.childNodes[0];
61+
while (currentNode !== bulletInfo) {
62+
// If it is a text node.
63+
if (currentNode.nodeType === 3) {
64+
description += currentNode.textContent;
65+
}
66+
67+
// Try to go down the tree.
68+
let nextNode = currentNode.firstChild || currentNode.nextSibling;
69+
// Span means it is a tag, and tag text should not be included.
70+
while (nextNode && nextNode.nodeName === 'SPAN') {
71+
nextNode = nextNode.nextSibling;
72+
}
73+
// If we couldn't go down try to go back up the tree.
74+
if (!nextNode) {
75+
nextNode = currentNode.parentNode;
76+
while (nextNode !== bulletInfo) {
77+
// We are valid again!
78+
if (nextNode.nextSibling) {
79+
nextNode = nextNode.nextSibling;
80+
break;
81+
}
82+
// Try to go up again. If we reach the bulletInfo node that
83+
// means we've reached the top and we will break out of both loops.
84+
nextNode = nextNode.parentNode;
85+
}
86+
}
87+
currentNode = nextNode;
88+
}
89+
return description.trim();
90+
}
91+
92+
function getTags (bulletInfo) {
93+
const tagsArray = [];
94+
let currentNode = bulletInfo.childNodes[0];
95+
while (currentNode !== bulletInfo) {
96+
if (currentNode.classList &&
97+
currentNode.classList.contains('contentTagText')) {
98+
tagsArray.push(currentNode.textContent.trim());
99+
}
100+
101+
// Try to go down the tree.
102+
let nextNode = currentNode.firstChild || currentNode.nextSibling;
103+
// If we can't go down try to go back up the tree.
104+
if (!nextNode) {
105+
nextNode = currentNode.parentNode;
106+
while (nextNode !== bulletInfo) {
107+
// We are valid again!
108+
if (nextNode.nextSibling) {
109+
nextNode = nextNode.nextSibling;
110+
break;
111+
}
112+
// Try to go up again. If we reach the bulletInfo node that
113+
// means we've reached the top and we will break out of both loops.
114+
nextNode = nextNode.parentNode;
115+
}
116+
}
117+
currentNode = nextNode;
118+
}
119+
return tagsArray;
120+
}
121+
122+
function insertLink (popup, link) {
123+
const INSERT_POSITION = 3;
124+
125+
/* Massage the DOM */
126+
const wrapper = document.createElement('div');
127+
wrapper.classList.add('workflowy-toggl-wrapper');
128+
// This makes sure the 'Start timer' link matches the style of the other
129+
// options (even when the theme is changed).
130+
wrapper.classList.add(popup.children[0].classList[0]);
131+
wrapper.appendChild(link);
132+
popup.insertBefore(wrapper, popup.children[INSERT_POSITION]);
133+
134+
// We have to add the toggl class to the parent of the popup,
135+
// because the popup's classes get overwritten by workflowy.
136+
const parent = popup.parentElement;
137+
parent.classList.add('toggl');
138+
139+
// And remove the class when the parent element's children change (meaning
140+
// the popup is deleted).
141+
const observer = new MutationObserver(function (mutationsList, observer) {
142+
parent.classList.remove('toggl');
143+
observer.disconnect();
144+
});
145+
observer.observe(parent, { childList: true });
146+
}

src/scripts/origins.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -587,6 +587,10 @@ export default {
587587
url: '*://*.workast.io/*',
588588
name: 'Workast'
589589
},
590+
'workflowy.com': {
591+
url: '*://workflowy.com/*',
592+
name: 'Workflowy'
593+
},
590594
'my.workfront.com': {
591595
url: '*://*.my.workfront.com/*',
592596
name: 'Workfront'

src/styles/style.css

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1612,3 +1612,24 @@ label > .toggl-button.outlook {
16121612
background-color: #f5f5f5 !important;
16131613
color: #6a7479;
16141614
}
1615+
1616+
/****** WORKFLOWY ******/
1617+
.workflowy-toggl-wrapper {
1618+
display: flex !important;
1619+
}
1620+
1621+
.toggl-button.workflowy:not(.toggl-button-edit-form-button) {
1622+
background-position-x: right;
1623+
background-position-y: center;
1624+
background-size: 14px 14px;
1625+
line-height: 24px;
1626+
height: 24px;
1627+
font-size: 100%;
1628+
padding-left: 0;
1629+
padding-right: 23px;
1630+
flex-grow: 1;
1631+
-webkit-box-flex: 1;
1632+
color: inherit !important;
1633+
cursor: default !important;
1634+
text-decoration: none !important;
1635+
}

0 commit comments

Comments
 (0)