flyink13 / VK IM Filter

// ==UserScript==
// @name         VK IM Filter
// @namespace    http://tampermonkey.net/
// @version      0.0.3
// @description  Фильтрация и каталогизация списка диалогов на vk.com :3
// @author       Flyink13
// @match        https://vk.com/*
// @copyright 2018, flyink13 (https://openuserjs.org/users/flyink13)
// @updateURL https://openuserjs.org/meta/flyink13/VK_IM_Filter.meta.js
// @license MIT
// ==/UserScript==
/* global cur, uiActionsMenu, stManager, FlyVK */

function VkImFilter() {
    var ge = document.getElementById.bind(document);
    var qs = document.querySelector.bind(document);
    var qsa = document.querySelectorAll.bind(document);
    var cats = localStorage.imFilter ? JSON.parse(localStorage.imFilter) : {
        list: ['f44336', 'c377e0', '2196f3', '4caf50', 'ffeb3b', 'ff9800', '9e9e9e'],
        active: ['f44336', 'c377e0', '2196f3', '4caf50', 'ffeb3b', 'ff9800', '9e9e9e'],
        ids: { }
    };

    function ce(tagName, tags, style) {
        var el = document.createElement(tagName);
        Object.assign(el, tags);
        Object.assign(el.style, style);
        return el;
    }

    VkImFilter.editStyle = function editStyle() {
        var style = "";

        var hideAll = !qs('#VkImFilterBar .VkImFilterCat.cat_9e9e9e.active');
        if (hideAll) style += "#im_dialogs ._im_dialog{ display: none; }\n\n";

        style += cats.list.filter(function checkExist(color) {
            return cats.ids.hasOwnProperty("cat_" + color);
        }).map(function getStyleByList(color) {
            var hide = !qs('#VkImFilterBar .VkImFilterCat.cat_' + color + '.active');

            var catStyle = "";
            catStyle += cats.ids["cat_" + color].map(function peerToStyle(pid) {
                return '#im_dialogs [data-list-id="' + pid + '"] .nim-peer--photo-w:after';
            }).join(", ") + '{' +
            'content: " ";' +
            'background: #' + color + ';' +
            '}\n';

            catStyle += cats.ids["cat_" + color].map(function peerToStyle(pid) {
                return '#im_dialogs [data-list-id="' + pid + '"]';
            }).join(", ") + '{' +
            'display: ' + (hide ? 'none' : 'block') + ';' +
            '}';

            return catStyle;
        }).join("\n\n");

        VkImFilter.imStyle.innerHTML = style;
        return hideAll;
    };

    VkImFilter.toggleCat = function toggleCat(event) {
        switch (event.type) {
            case 'contextmenu':
                [].forEach.call(qsa('.VkImFilterCat'), function swClass(cat) {
                    cat.classList.add('active');
                });
                this.classList.remove('active');
                break;
            case 'dblclick':
                [].forEach.call(qsa('.VkImFilterCat'), function swClass(cat) {
                    cat.classList.remove('active');
                });
                this.classList.add('active');
                break;
            case 'click':
                this.classList.toggle('active');
                break;
            default: console.log(event);
        }

        var hideAll = VkImFilter.editStyle();
        if (hideAll) ge('im_dialogs').classList.add('hideAll');

        cats.active = [];
        [].forEach.call(qsa('#VkImFilterBar .VkImFilterCat.active'), function swClass(cat) {
            cats.active.push(cat.id.substr(4));
        });
        localStorage.imFilter = JSON.stringify(cats);

        return false;
    };

    VkImFilter.togglePeerCategory = function togglePeerCategory(color) {
        var peerIndex;

        // remove peer from categories
        for (var _color in cats.ids) {
            peerIndex = cats.ids[_color].indexOf(cur.peer);
            if (peerIndex > -1) cats.ids[_color].splice(peerIndex, 1);
        }

        var activeCats = this.parentNode.querySelectorAll('.active');
        [].forEach.call(activeCats, function removeActiveClass(activeCat) {
            activeCat.classList.remove('active');
        });

        // add peer to category
        if (!cats.ids["cat_" + color]) cats.ids["cat_" + color] = [];
        cats.ids["cat_" + color].push(cur.peer);
        this.classList.add('active');

        // update style
        var hideAll = VkImFilter.editStyle();
        if (hideAll) ge('im_dialogs').classList.add('hideAll');

        localStorage.imFilter = JSON.stringify(cats);
    };

    VkImFilter.insertStyles = function insertStyles() {
        VkImFilter.imStyle = ce('style', { id: 'VkImFilterImStyle' });
        VkImFilter.mainStyle = ce('style', {
            id: 'VkImFilterMainStyle',
            innerHTML: "" +
                "#VkImFilterBar{" +
                "height: 35px;" +
                "text-align: center;" +
                "border: 1px solid #e7e8ec;" +
                "margin-left: -1px;" +
                "position: absolute;" +
                "z-index: 2;" +
                "width: 100%;" +
                "background: white;" +
                "}" +
                ".im-page_classic #VkImFilterBar { position: relative; z-index: 0; margin-bottom: -37px; }" +
                "#im_dialogs .ui_scroll_bar_container, #im_dialogs._im_page_dcontent { padding-top: 36px; }" +
                ".VkImFilterCat{ " +
                "box-shadow: 0px 0px 0px 2px #e7e8ec; border-radius: 15px;" +
                "height: 15px; width: 15px; margin: 11px 10px;" +
                "display: inline-block; opacity: 0.3; " +
                "}" +
                ".VkImFilterCat.active{ opacity: 1; }" +
                "#im_dialogs .nim-peer--photo-w:after{" +
                "width: 10px;" +
                "height: 10px;" +
                "position: absolute;" +
                "margin: 0px;" +
                "top: 0;" +
                "border-radius: 100%;" +
                "border: 2px solid #fff;" +
                "}" +
                "#VkImFilterSelector{ text-align: center; }" +
                "#VkImFilterSelector .VkImFilterCat{ margin: 6px 6px 3px 6px; opacity:1; }" +
                "#VkImFilterSelector .VkImFilterCat.active{ box-shadow: 0px 0px 0px 2px #4C77A6; }" +
                // Сфоткай типа ниже костыль:
                "#im_dialogs.hideAll .ui_scroll_content li:nth-last-child(4)," +
                "#im_dialogs.hideAll .ui_scroll_content li:nth-last-child(3)," +
                "#im_dialogs.hideAll .ui_scroll_content li:nth-last-child(2)," +
                "#im_dialogs.hideAll .ui_scroll_content li:last-child{ opacity: 0; pointer-events: none; height: 900px; display: block; }"
        });
        document.head.appendChild(VkImFilter.mainStyle);
        document.head.appendChild(VkImFilter.imStyle);
    };

    VkImFilter.insertFilterBar = function insertFilterBar() {
        var im_dialogs = ge('im_dialogs');
        if (!im_dialogs) return;
        VkImFilter.bar = ce('div', { id: 'VkImFilterBar', oncontextmenu: function rf() { return false; } });
        im_dialogs.parentNode.insertBefore(VkImFilter.bar, im_dialogs);

        var fragment = document.createDocumentFragment();
        cats.list.forEach(function addTag(color) {
            var cat = ce("span", {
                className: 'VkImFilterCat cat_' + color + ' ' + (cats.active.indexOf(color) > -1 ? 'active' : ''),
                id: 'cat_' + color,
                onclick: VkImFilter.toggleCat,
                ondblclick: VkImFilter.toggleCat,
                oncontextmenu: VkImFilter.toggleCat
            }, { background: '#' + color });
            fragment.appendChild(cat);
        });
        VkImFilter.bar.appendChild(fragment);
    };

    VkImFilter.insertMenu = function insertMenu(args) {
        var cm = args[0].querySelector('.im-action_search');
        if (!cm || cm.tagInjected) return;
        cm.tagInjected = 1;
        var catSelector = ce('div', { id: 'VkImFilterSelector' });
        cm.parentNode.insertBefore(catSelector, cm.nextElementSibling);
        cm.parentNode.insertBefore(ce("div", { className: "ui_actions_menu_sep" }), cm.nextElementSibling);

        var fragment = document.createDocumentFragment();
        cats.list.forEach(function addTag(color, i) {
            var active = "";
            if (cats.ids.hasOwnProperty("cat_" + color) && cats.ids["cat_" + color].indexOf(cur.peer) > -1) {
                active = ' active';
                catSelector.catSelector = "cat_" + color;
            }

            if (cats.list.length - 1 == i && !catSelector.catSelector) {
                active = ' active';
                catSelector.catSelector = "cat_" + color;
            }

            var cat = ce("span", {
                className: 'VkImFilterCat' + active,
                id: 'cat_' + color,
            }, { background: '#' + color });

            cat.onclick = VkImFilter.togglePeerCategory.bind(cat, color);
            fragment.appendChild(cat);
        });
        catSelector.appendChild(fragment);
    };

    VkImFilter.insertImWaiter = function insertImWaiter() {
        if (ge('im_dialogs') && !ge('VkImFilterBar')) {
            VkImFilter.insertFilterBar();
            VkImFilter.editStyle();
        }
    };

    function injectFunction(org, func) {
        return function FakeFunction() {
            func(arguments);
            return org.apply(this, arguments);
        };
    }

    VkImFilter.insertStyles();
    VkImFilter.insertFilterBar();
    VkImFilter.editStyle();
    window.addEventListener('load', function onLoad() {
        stManager.add(["ui_common.js"], function functionName() {
            uiActionsMenu.show = injectFunction(uiActionsMenu.show, VkImFilter.insertMenu);
        });
        stManager.add = injectFunction(stManager.add, VkImFilter.insertImWaiter);

        var hideAll = VkImFilter.editStyle();
        if (hideAll && ge('im_dialogs')) ge('im_dialogs').classList.add('hideAll');
        if (typeof FlyVK !== 'undefined' && FlyVK.module) FlyVK.module.loaded('oujs_VK_IM_Filter.user.js', VkImFilter, {});
    });
}

(function injectScript() {
    var script = document.createElement('script');
    script.appendChild(document.createTextNode('!' + VkImFilter + '();'));
    (document.body || document.head || document.documentElement).appendChild(script);
})();