shtrih / Slack Ignore List

// ==UserScript==
// @name         Slack Ignore List
// @namespace    https://gist.github.com/shtrih/be922d9229925bb52617
// @version      1.1
// @description  Add blacklists to channels
// @author       shtrih
// @match        https://*.slack.com/messages/*/
// @grant        none
// ==/UserScript==
/* jshint -W097 */
'use strict';

// https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver

function getActiveChannelId() {
    var pubChanId = $('.star_channel', '#active_channel_name').attr('data-channel-id'),
        privChanId = $('.star_group', '#active_channel_name').attr('data-group-id')
    ;
    return pubChanId || privChanId;
}

function getActivePrivateId() {
    return $('.star_im', '#active_channel_name').attr('data-im-id');
}

function getMemberIdMenu() {
    return $('a.member_preview_link', '#menu_header').attr('data-member-id');
}

function getMemberIdMessage(elMessage) {
    return $('.message_content > a.message_sender', elMessage).attr('data-member-id');
}

var Ignorer = (function () {
    return {
        set: function (channelId, memberId) {
            localStorage.setItem(channelId + memberId, 1);
        },
        get: function (channelId, memberId) {
            return localStorage.getItem(channelId + memberId);
        },
        remove: function (channelId, memberId) {
            localStorage.removeItem(channelId + memberId);
        }
    };
})();

var targetMessages = document.querySelector('#msgs_div'),
    targetUI = document.querySelector('#client-ui'),
    menuIgnoreUser = $('<li id="member-ignore" role="menuitem">\
                            <a><span class="menu_item_label">Ignore user</span></a>\
                       </li>'),
    messageHiderHandler = function (divMessage) {
        var classList = divMessage.classList;
        if (classList && !classList.contains('unprocessed') && classList.contains('message')) {
            var channelId = getActiveChannelId(),
                memberId = getMemberIdMessage(divMessage),
                isIgnored = Ignorer.get(channelId, memberId)
            ;
            if (isIgnored) {
                classList.add('hidden');
            }
        }
    },
    messageReveal = function (memberId) {
        $('ts-message.message.hidden', targetMessages).each(function () {
            if (getMemberIdMessage(this) == memberId)
                $(this).removeClass('hidden');
        });
    },
    refreshHider = function () {
        $('ts-message.message:not(.hidden)', targetMessages).each(function () {
            messageHiderHandler(this);
        });
    },
    // Скрывает новые сообщения от юзеров
    observerMessageHider = new MutationObserver(function(mutations) {
        mutations.forEach(function(mutation) {
            if (mutation && mutation.addedNodes instanceof NodeList && mutation.addedNodes.length) {
                Array.prototype.forEach.call(mutation.addedNodes, messageHiderHandler);
            }
        });    
    }),
    // Добавляет пункт о блокировке во всплывающее меню юзера
    observerUserMenu = new MutationObserver(function(mutations) {
        mutations.forEach(function(mutation) {
            if (mutation && mutation.addedNodes instanceof NodeList && mutation.addedNodes.length) {
                Array.prototype.forEach.call(mutation.addedNodes, function(node){
                    if (node.id == 'menu') {
                        var $node = $(node),
                            channelId = getActiveChannelId()
                        ;
                        // если не меню юзера или меню юзера не в общем чате
                        if ($node.attr('data-qa') || !channelId)
                            return false;

                        $('#menu_items', $node).append(menuIgnoreUser);
                        $('a', menuIgnoreUser).off().on('click', function () {
                            var memberId = getMemberIdMenu();
                            // console.log('ignore user', memberId);

                            $('#menu').remove();
                            Ignorer.set(channelId, memberId);
                            refreshHider();
                            showIgnoredMembers();

                            return false;
                        });
                    }
                });
            }
        });    
    }),
    
    // Обработка списка участников
    targetSidebar = document.querySelector('#details_tab'),
    observerSidebar = new MutationObserver(function(mutations) {
        mutations.forEach(function(mutation) {
            if (mutation && mutation.addedNodes instanceof NodeList && mutation.addedNodes.length) {
                Array.prototype.forEach.call(mutation.addedNodes, function (node) {
                    if ($(node).hasClass('monkey_scroll_hider')) {
                        processIgnoredMembers();
                        observerSidebar.disconnect();
                    }
                });
            }
        });    
    }),
    ignoreIcon = $('<i/>', {
        class: 'ts_icon ts_icon_flag',
        style: 'display: inline-block; font-size: 20px; line-height: 20px; position: absolute; top: -8px; left: -12px; color: red; cursor: pointer;',
        click: function () {
            var parent = $(this).parent(), 
                memberId = parent.attr('data-member-presence'),
                channelId = getActiveChannelId()
            ;
            
            Ignorer.remove(channelId, memberId);
            messageReveal(memberId);
            parent.remove();
        }
    }),
    showIgnoredMembers = function () {
        $('span[data-member-presence]', '#channel_page_all_members').each(function () {
            var self = $(this),
                memberId = self.attr('data-member-presence'),
                channelId = getActiveChannelId()
            ;
            if (Ignorer.get(channelId, memberId)) {
                self.after(
                    self.clone().attr('title', 'Ignored. Click to cancel ignore.').html(
                        ignoreIcon.clone(true)
                    )
                );
            }
        });
    },
    processIgnoredMembers = function () {
        var observerMemberList = new MutationObserver(function(mutations) {
            mutations.forEach(function(mutation) {
                if (mutation && mutation.addedNodes instanceof NodeList && mutation.addedNodes.length) {
                    Array.prototype.forEach.call(mutation.addedNodes, function (node) {
                        if (node.nodeType !== Node.ELEMENT_NODE)
                            return false;

                        showIgnoredMembers();
                    });
                }
            });    
        });

        showIgnoredMembers();
        observerMemberList.observe($('[data-section-name="members"] .channel_page_member_lists').get(0), { childList: true });
    }
;

observerMessageHider.observe(targetMessages, { childList: true });
observerUserMenu.observe(targetUI, { childList: true });
observerSidebar.observe(targetSidebar, { childList: true });