// ==UserScript==
// @name FlowdockX
// @namespace http://twitter.com/grahammcculloch
// @version 0.9
// @noframes
// @description A small improvement to Flowdock
// @author Graham McCulloch
// @match https://www.flowdock.com/app/*
// @grant none
// @icon http://blog.flowdock.com/wp-content/uploads/2017/05/[email protected]
// ==/UserScript==
(function() {
'use strict';
const storageKey = "flowdockX_withReplies";
console.log(String.raw`
______ _ _ _ __ __
| ___|| | | | | | \ \ / /
| |_ | | ___ __ __ __| | ___ ___ | | __ \ V /
| _| | | / _ \\ \ /\ / // _ | / _ \ / __|| |/ / / \
| | | || (_) |\ V V /| (_| || (_) || (__ | < / /^\ \
\_| |_| \___/ \_/\_/ \__,_| \___/ \___||_|\_\\/ \/
`);
let withReplies = localStorage.getItem(storageKey, 'true') === 'true';
const $headCss = window.$(`
<style type="text/css">
li.chat-message.message {
transition: background-color 0s ease;
}
#toolbar > .right-item-group {
right: 3.8rem;
}
#btn-toggle-threads {
position: absolute;
top: 0;
right: 10px;
z-index: 2;
}
#btn-toggle-threads svg {
padding-top: 3px;
}
body, body>.flow {
z-index: 1;
}
body.hide-replies .flow:not(.private) .left-panel #chat li.chat-message.message:not(.thread-starter) {
display: none;
}
.reply-count {
text-align: center;
font-size: 80%;
font-weight: bold;
}
.theme-flowdark .reply-count {
color: #bbb;
}
.reply-count-wrapper {
display: flex;
}
</style>
`);
const replyIcon = (size) => {
return `
<svg class="vector-icon bubble-icon" x="0px" y="0px" viewBox="0 0 ${size} ${size}" data-reactid=".9.1">
<g data-reactid=".9.1.0">
<path class="vector-icon-path"
d="M11.219297,12.803921 C11.2188795,13.287707 11.5307502,13.723651 12.0095154,13.908981 C12.4877588,14.093921 13.0390642,13.991804 13.4055227,13.650182 L19.6246697,7.847278 C20.1250405,7.380641 20.1250405,6.62344 19.6250872,6.156316 L13.4092801,0.350392 C13.1646266,0.121507 12.8368911,0 12.5033106,0 C12.3381903,0 12.1721307,0.029622 12.0136904,0.090716 C11.5349251,0.275656 11.222637,0.712087 11.222637,1.195483 L11.222637,4.755235 L8.988401,4.755235 C2.057852,4.755235 1.6948031,2.082537 1.1856852,1.074049 C1.018715,0.743306 0.4262512,0.646537 0.2128106,1.072977 C-0.7577142,3.01202 1.4935153,9.173136 8.988401,9.173136 L11.2205495,9.173136 L11.219297,12.803921 Z"
data-reactid=".9.1.0.0">
</path>
</g>
</svg>`;
}
const toolbarBtn = window.$(`
<a id="btn-toggle-threads" class="toolbar-link active" title="Hide replies">
<span class="toolbar-toggle">
${replyIcon(20)}
</span>
</button>
`);
const body = window.$('body');
function updateThreadCounts(flowdockSanityActive) {
const $threadStarters = window.$('.chat-message.thread-starter');
$threadStarters.each((index) => {
const $threadStarter = window.$($threadStarters[index]);
const threadId = $threadStarter.attr('data-parent');
const $threadReplies = window.$(`.chat-message:not(.thread-starter)[data-parent='${threadId}'`);
if ($threadReplies.length) {
const $replyCount = $threadStarter.find('.reply-count');
const replyCountText = flowdockSanityActive ? `${$threadReplies.length} ${$threadReplies.length > 1 ? 'replies' : 'reply'}` : $threadReplies.length;
if (!$replyCount.length) {
if (flowdockSanityActive) {
const $messageAuthor = $threadStarter.find('.message-author');
$messageAuthor.wrap('<div class="reply-count-wrapper"></div>');
const $wrapper = $threadStarter.find('.reply-count-wrapper');
$wrapper.append(`<div class="reply-count">${replyCountText}</div>`);
} else {
const $bubble = $threadStarter.find('.bubble-container .bubble');
$bubble.append(`<div class="reply-count">${$threadReplies.length}</div>`);
}
} else {
$replyCount.text(replyCountText);
}
}
});
}
function initMainChatList($chatList) {
$chatList.attr('data-reply-count-init', true);
const $threadIndicator = window.$('.thread-indicator');
const flowdockSanityActive = $threadIndicator.css('display') === 'none';
updateThreadCounts(flowdockSanityActive);
const observer = new MutationObserver(
(mutationsList, observer) => {
if (mutationsList.find(m => m.type === 'childList' && m.addedNodes && m.addedNodes.length)) {
updateThreadCounts(flowdockSanityActive);
}
}
);
observer.observe($chatList[0], { childList: true });
}
function checkForMainChatList() {
const $mainChatList = window.$('.left-panel .chat-message-list');
if ($mainChatList.length) {
const initialized = $mainChatList.attr('data-reply-count-init');
if (!initialized) {
initMainChatList($mainChatList);
}
}
}
function setWithReplies(newWithReplies) {
withReplies = newWithReplies;
localStorage.setItem(storageKey, withReplies);
if (withReplies) {
body.removeClass('hide-replies');
toolbarBtn.attr('title', 'Hide replies');
toolbarBtn.addClass('active');
} else {
body.addClass('hide-replies');
toolbarBtn.attr('title', 'Show replies');
toolbarBtn.removeClass('active');
}
}
window.$('head').append($headCss);
body.append(toolbarBtn);
setWithReplies(withReplies);
toolbarBtn.on('click', () => { setWithReplies(!withReplies); });
setInterval(checkForMainChatList, 1000);
})();