Pikabu UI++

Улучшение интерфейса

La data de 13-05-2021. Vezi ultima versiune.

// ==UserScript==
// @name         Pikabu UI++
// @namespace    pikabuUIPlusPlus
// @version      1.1
// @description  Улучшение интерфейса
// @author       Array
// @license      CC-BY-SA-4.0
// @match        *://pikabu.ru/*
// @grant        unsafeWindow
// @grant        window.close
// @grant        GM_getValue
// @grant        GM_setValue
// @run-at document-end
// ==/UserScript==

// simbols source http://myhomeinet.ru/smilegenerator/page-274.html
// colors source https://www.w3schools.com/colors/colors_names.asp
// special thanks:
// @nazarpunk
// @moretraher2020
(function() {
    `use strict`;

    const DATA_LIFETIME = 604800000;
    const DATABASE = `db`;
    const DATABASE_VERSION = `1`;

    const EXP_VALUES = [3, 5, 8];
    const EXP_ICO = [`❊`, `•`, `︿`, `︽`, `⁂`, `★`];

    const NOTE_VALUES = [`#добро`, `#интересно`, `#осторожно`, `#неприемлемо`],
          NOTE_ICO = [`❤`, `♞`, `⚠`, `✖`],
          NOTE_COLORS = [`LimeGreen`, `DodgerBlue`, `OrangeRed`, `Violet`];

    const SUBS_VALUES = [40, 900, 4000, 9000],
          SUBS_ICO = [``, `◔`, `◑`, `◕`, `◉`];

    const BAN_ICO = [``, `ϟ`, `†`];
    const GENDER_ICO = [``, `♂`, `♀`];


    // ************************ ENTRY POINT *************************

    const SHOW_EXP = GM_getValue(`SHOW_EXP`, 1);
    const SHOW_NOTE = GM_getValue(`SHOW_NOTE`, 1);
    const SHOW_RATE = GM_getValue(`SHOW_RATE`, 1);
    const SHOW_SUBS = GM_getValue(`SHOW_SUBS`, 1);
    const SHOW_BAN = GM_getValue(`SHOW_BAN`, 1);
    const SHOW_GENDER = GM_getValue(`SHOW_GENDER`, 0);
    const SHOW_QUICK_NOTE = GM_getValue(`SHOW_QUICK_NOTE`, 1);

    var database = new Map();

    var loadingComments = new Map();
    var loadingOrder = [];
    var updateOrder = [];
    var intersectionOrder = new Set();
    var loadingComment = null;

    var enableLoadingNavigator = false;
    var loadingNavigator;

    var userpageRendered = false;


    // Intersections
    const intersector = new IntersectionObserver(
        entries => {
            for (const entry of entries) {
                if (entry.isIntersecting)
                {
                    for (const userName of loadingOrder)
                    {
                        if(entry.target.dataset.name == userName)
                        {
                            intersectionOrder.add(userName);
                            break;
                        }
                    }
                    for (const userName of updateOrder)
                    {
                        if(entry.target.dataset.name == userName)
                        {
                            intersectionOrder.add(userName);
                            break;
                        }
                    }
                }
                else
                {
                    intersectionOrder.delete(entry.target.dataset.name);
                }
            }
        }, {
            threshold: 0
        });


    addCustomCSS();

    renderNavigatorLoading();


    loadDatabase();

    findComments();

    findUsernames();

    checkUserPage();

    checkSettingsPage();

    // Ajax listener
    !function(send) {
        XMLHttpRequest.prototype.send = function(body) {
            send.call(this, body);

            if(body?.includes(`note`))
            {
                checkUserPage();
            }
        };
    }(XMLHttpRequest.prototype.send);


    // Mutation listener
    var mutationObserverTimeout = false;
    new MutationObserver(mutations => {
        for (const mutation of mutations) {
            if(mutationObserverTimeout) break;
            for (const node of mutation.addedNodes) {
                if (!(node instanceof HTMLElement)) continue;
                if(mutationObserverTimeout) break;
                if (node.classList.contains(`comment`) || node.classList.contains(`story`))
                {
                    findUsernames();
                    mutationObserverTimeout = true;
                    setTimeout(() => {mutationObserverTimeout = false}, 200);
                    break;
                }

            }
        }
    }).observe(document.body, {childList: true, subtree: true});




    // ************************ DATABASE *************************

    function loadDatabase()
    {
        let jobject = JSON.parse(GM_getValue(DATABASE, `{}`));
        database = new Map(Object.entries(jobject));

        let ver = GM_getValue(`version`, ``);
        if(ver != DATABASE_VERSION)
        {
            GM_setValue(`version`, DATABASE_VERSION);
            database = new Map();
        }
    }

    function saveDatabase()
    {
        let json = JSON.stringify(Object.fromEntries(database.entries()));
        GM_setValue(DATABASE, json);
    }


    // ************************ BASEMENT *************************

    function checkUserPage()
    {
        let url = window.location.href;
        let key = url.split(`@`)[1];

        if(url.includes(`@`) && !userpageRendered)
        {
            userpageRendered = true;
            renderUserpageTools();
        }

        if(database.has(key))
        {
            database.get(key).timestamp = 0;

            saveDatabase();

            findUsernames(key);
        }
    }

    function checkSettingsPage()
    {
        let url = window.location.href;

        if(url.includes(`settings`)) renderSettings();
    }

    function findComments()
    {
        if(!SHOW_QUICK_NOTE)
        {
            return;
        }

        document.querySelectorAll(`.comment`).forEach((comment) => {

            let meta = comment.getAttribute(`data-meta`);

            if(meta != null && !meta.includes(`ua`))
            {

                let uid = smartSlice(meta, `aid=`, `,`);

                let tools = comment.querySelector(`.comment__tools`);

                renderCommentTools(tools, uid);
            }

        });
    }


    function findUsernames(requestedUser)
    {
        // comemet usernames
        document.querySelectorAll(`.comment__user`).forEach((commentBase) => {

            let comment = commentBase.querySelector(`.user__nick`);

            let userName = commentBase.getAttribute(`data-name`);

            let checkRequest = requestedUser != undefined && requestedUser == userName;

            // reg intersec events for new item
            if(comment?.textContent == userName)
            {
                intersector.observe(commentBase);
            }

            if(comment?.textContent == userName || checkRequest)
            {
                if(checkRequest) intersectionOrder.add(userName);

                addComment(comment, userName);
            }

        });

        //post usernames
        document.querySelectorAll(`.story__user-link`).forEach((post) => {

            let userName = post.getAttribute(`data-name`);

            let checkRequest = requestedUser != undefined && requestedUser == userName;

            // reg intersec events for new item
            if(post?.textContent.trim() == userName)
            {
                intersector.observe(post);
            }

            if(post?.textContent.trim() == userName || checkRequest)
            {
                addComment(post, userName);
            }

        });

        if(loadingComment == null)
        {
            nextLoading();
        }
    }



    function addComment(comment, userName)
    {
        if(database.has(userName))
        {
            let date = new Date();
            let data = database.get(userName);

            renderUsername(userName, comment, data);

            // update data
            if(date.getTime() > (data.timestamp + DATA_LIFETIME))
            {
                if(loadingComments.has(userName))
                {
                    loadingComments.get(userName).push(comment);
                }
                else
                {
                    loadingComments.set(userName, [comment]);
                    updateOrder.push(userName);
                }
            }
        }
        else
        {
            //request data
            if(loadingComments.has(userName))
            {
                loadingComments.get(userName).push(comment);
            }
            else
            {
                loadingComments.set(userName, [comment]);

                loadingOrder.push(userName);

                nextLoading();
            }
        }

        renderLoadingOrder();
    }


    // ************************ LOADING  *************************

    function nextLoading()
    {
        if(loadingComment == null && intersectionOrder.size > 0)
        {
            while (intersectionOrder.size > 0)
            {
                let forcedUsername = intersectionOrder.values().next().value;
                intersectionOrder.delete(forcedUsername);

                if(loadingOrder.includes(forcedUsername))
                {
                    loadingOrder.splice(loadingOrder.indexOf(forcedUsername), 1);

                    loadingComment = forcedUsername;

                    loadData(loadingComment);
                    break;
                }

                if(updateOrder.includes(forcedUsername))
                {
                    updateOrder.splice(updateOrder.indexOf(forcedUsername), 1);

                    loadingComment = forcedUsername;

                    loadData(loadingComment);
                    break;
                }

            }
            // if all intersections check failed
            if(loadingComment == null)
            {
                nextLoading();
                return;
            }
        }
        else if(loadingComment == null && loadingOrder.length > 0)
        {
            loadingComment = loadingOrder.shift();

            loadData(loadingComment);
        }
        else if(loadingComment == null && updateOrder.length > 0)
        {
            // update expired data
            loadingComment = updateOrder.shift();

            loadData(loadingComment);
        }

        renderLoadingOrder();
    }

    function loadData(userName)
    {
        const body = new FormData();
        body.set(`action`, `get_short_profile`);
        body.set(`user_name`, userName);

        fetch(`/ajax/user_info.php`, {
            method: `post`,
            body  : body
        })
            .then(r => r.json())
            .then(result => {
            let data = parseData(result.data.html);

            database.set(userName, data);

            saveDatabase();

            let comments = loadingComments.get(userName);
            loadingComments.delete(userName);

            for (let comment of comments) renderUsername(userName, comment, data);

            loadingComment = null;

            setTimeout(() => {nextLoading(); renderLoadingOrder();}, 100 + 400 * Math.random());
        });
    }


    // ************************ EVENTS  *************************

    var clickTimeout = false;
    function clickUserNote(e)
    {
        if(clickTimeout) return;

        clickTimeout = true;

        let note = e.target.getAttribute(`data-note`);
        let uid = e.target.getAttribute(`data-uid`);

        let url = window.location.href;
        let userName = url.split(`@`)[1];

        let data = database.get(userName);

        let message = ``;
        let mtype = `-`;
        if(data.note != (parseInt(note)+1))
        {
            message = NOTE_VALUES[note];
            mtype = `+`;
        }

        let textarea = document.querySelector(`.page-profile`).querySelector(`.profile-note__textarea`).value = message;
        let textdiv = document.querySelector(`.page-profile`).querySelector(`.profile-note__text`).textContent = message;

        const body = new FormData();
        body.set(`action`, `note`+mtype);
        body.set(`id`, uid);
        body.set(`message`, message);

        fetch(`/ajax/users_actions.php`, {
            method: `post`,
            body  : body
        })
            .then(result => {

            data.timestamp = 0;

            findUsernames(userName);

            clickTimeout = false;
        });
    }


    function clickQuicknote(e)
    {
        if(clickTimeout) return;

        clickTimeout = true;

        let note = e.target.getAttribute(`data-note`);
        let uid = e.target.getAttribute(`data-uid`);

        let comment = e.target?.parentElement?.parentElement?.querySelector(`.comment__user`);
        let userName = comment?.getAttribute(`data-name`);

        let refTool = e.target.parentElement?.querySelector(`a`);
        let ref = refTool?.getAttribute(`href`);

        let data = database.get(userName);

        let message = ``;
        let mtype = `-`;
        if(data.note != (parseInt(note)+1))
        {
            message = NOTE_VALUES[note]+` `+ref;
            mtype = `+`;
        }

        const body = new FormData();
        body.set(`action`, `note`+mtype);
        body.set(`id`, uid);
        body.set(`message`, message);

        fetch(`/ajax/users_actions.php`, {
            method: `post`,
            body  : body
        })
            .then(result => {

            data.timestamp = 0;

            findUsernames(userName);

            clickTimeout = false;
        });
    }

    // ************************ PARSING  *************************

    function smartSlice(text, start, end)
    {
        let strIndex = text.indexOf(start);
        let endIndex = text.indexOf(end, strIndex);

        return text.slice(strIndex+start.length, endIndex);
    }

    function parseData(html)
    {
        let data = new Object();


        let regions = html.split(`information`);

        // user id
        //let uidSource =	smartSlice(regions[0], `id="`, `">`);


        // ban
        let banStat = 0;
        if(regions[0].includes(`ban-status`))
        {
            if(regions[0].includes(`навсегда`))
            {
                banStat = 2;
            }
            else
            {
                banStat = 1;
            }
        }

        // note
        let noteStat = 0;
        if(regions[1].includes(`profile__note`))
        {
            let subRegions = regions[1].split(`profile__note-inner`);
            regions[1] = subRegions[0];

            for (let i = 0; i < NOTE_VALUES.length; i++)
            {
                if(subRegions[1].includes(NOTE_VALUES[i]))
                {
                    noteStat = i + 1;
                }
            }
        }

        // gender
        let genderStat = 0;
        if(regions[1].includes(`шник`))
        {
            genderStat = 1;
        }
        if(regions[1].includes(`шница`))
        {
            genderStat = 2;
        }

        //exp
        let expStat = 0;

        let expSource =	smartSlice(regions[1], `<span>`, `</div>`);

        let y = expSource.includes(`лет`) || expSource.includes(`год`);
        let m = expSource.includes(`месяц`);

        if(y || m)
        {
            if(y)
            {
                let years = parseInt(expSource);

                expStat = 2 + EXP_VALUES.length;
                for (let i = EXP_VALUES.length - 1; i >= 0; i--)
                {
                    if(years < EXP_VALUES[i])
                    {
                        expStat = 2 + i;
                    }
                }
            }
            else
            {
                expStat = 1;
            }
        }


        let digitalRegions = regions[1].split(`profile__digital`);
        // 0 trash
        // 1 rate
        // 2 trash
        // 3 subs

        //rate
        let rateStat = 0;

        let rateRaw = smartSlice(digitalRegions[1], `<b>`, `</b>`);

        if(rateRaw.includes(`К`))
        {
            rateStat = rateRaw.replace(`-`, `▽`);
        }
        else
        {
            rateStat = (Math.round(rateRaw/1000) + `K`).replace(`-`, `▽`);
        }


        // subs
        let subsStat = 0;

        let rawSubs = smartSlice(digitalRegions[3], `<b>`, `</b>`);

        if(rawSubs.includes(`К`))
        {
            subsStat = 4;
        }
        else if(rawSubs > SUBS_VALUES[0])
        {
            subsStat = SUBS_VALUES.length;
            for (let i = SUBS_VALUES.length - 1; i > 0 ; i--)
            {
                if(rawSubs < SUBS_VALUES[i])
                {
                    subsStat = i;
                }
            }
        }

        // timestamp
        let date = new Date();
        data.timestamp = date.getTime();

        data.exp = expStat;
        data.note = noteStat;
        data.rate = rateStat;
        data.subs = subsStat;
        data.ban = banStat;
        data.gender = genderStat;

        return data;
    }

    // ************************ CSS  *************************

    function addCustomCSS()
    {
        var styles = ``;
        for (let i = 0; i < NOTE_COLORS.length; i++)
        {
            styles += `.`+NOTE_COLORS[i]+`_note {background-color: `+NOTE_COLORS[i]+`;}`;
        }

        styles += `.navigator__forced-on {opacity: 1 !important; visibility: visible !important;}`;
        styles += `.navigator__forced-off {opacity: 0 !important; visibility: hidden !important; max-width: 1px !important;}`;
        styles += `.navigator-loading-info {background-color: CornflowerBlue}`;
        styles += `.navigator-update-info {background-color: Gainsboro !important}`;
        styles += `.userpage-note-tools {margin-left: 15px !important; margin-top: 4px !important;}`;
        styles += `.userpage-note-tool {font-size: 18px !important; padding: 5px; padding-left: 8px; padding-right: 8px;}`;


        var styleSheet = document.createElement(`style`);
        styleSheet.type = `text/css`;
        styleSheet.innerText = styles;
        document.head.appendChild(styleSheet);
    }

    // ************************ RENDERING  *************************

    function renderUsername(userName, comment, data)
    {
        if(comment == null)
        {
            return;
        }

        let exp = ``;
        if(SHOW_EXP)
        {
            exp = EXP_ICO[data.exp] + ` `;
        }

        let note = ``;
        if(SHOW_NOTE && data.note > 0)
        {
            note = NOTE_ICO[data.note - 1] + ` `;

            let noteEl = comment?.parentElement?.parentElement?.querySelector(`.avatar__note`);

            if(noteEl == null || noteEl == undefined)
            {
                let avatar = comment?.parentElement?.parentElement?.querySelector(`.avatar`);

                noteEl = document.createElement(`span`);
                noteEl.classList.add(`avatar__note`);

                avatar.appendChild(noteEl);
            }

            // remove prev
            for (let i = 0; i < NOTE_COLORS.length; i++)
            {
                noteEl.classList.toggle(NOTE_COLORS[i]+`_note`, false);
            }

            noteEl.classList.add(NOTE_COLORS[data.note - 1]+`_note`);
        }
        if(SHOW_NOTE && data.note == 0)
        {
            let noteEl = comment?.parentElement?.parentElement?.querySelector(`.avatar__note`);

            if(noteEl != null && noteEl != undefined)
            {
                noteEl.remove();
            }
        }

        let rate = ``;
        if(SHOW_RATE)
        {
            rate = data.rate + ` `;
        }

        let subs = ``;
        if(SHOW_SUBS)
        {
            subs = SUBS_ICO[data.subs] + ` `;
        }

        let ban = ``;
        if(SHOW_BAN && data.ban > 0)
        {
            ban = ` `+BAN_ICO[data.ban];
        }

        let gender = ``;
        if(SHOW_GENDER && data.gender > 0)
        {
            gender = ` `+GENDER_ICO[data.gender];
        }

        if(comment.childNodes.length > 1)
        {
            comment.childNodes[2].textContent = exp + note + rate + subs + userName + ban + gender;
        }
        else
        {
            comment.textContent = exp + note + rate + subs + userName + ban + gender;
        }

    }

    function renderCommentTools(tools, uid)
    {
        if(!SHOW_QUICK_NOTE) return;

        for (let i = 0; i < NOTE_VALUES.length; i++)
        {
            let tool = document.createElement(`div`);
            tool.classList.add(`comment__tool`);
            tool.classList.add(`hint`);

            tool.setAttribute(`aria-label`, `Отметить как `+NOTE_VALUES[i]);
            tool.setAttribute(`data-note`, i);
            tool.setAttribute(`data-uid`, uid);

            tool.textContent = NOTE_ICO[i];

            tool.addEventListener(`click`, clickQuicknote);

            tools.appendChild(tool);
        }
    }

    function renderUserpageTools()
    {
        if(!SHOW_QUICK_NOTE) return;

        let uid = document.querySelector(`.page-profile`).querySelector(`.section-group`).getAttribute(`data-user-id`);

        let root = document.querySelector(`.main__inner`);
        let panel = document.querySelector(`.feed-panel`);

        let tools = document.createElement(`div`);
        tools.classList.add(`comment__tools`);
        tools.classList.add(`navigator__forced-on`);
        tools.classList.add(`userpage-note-tools`);
        root.insertBefore(tools, panel);

        for (let i = 0; i < NOTE_VALUES.length; i++)
        {
            let tool = document.createElement(`div`);
            tool.classList.add(`comment__tool`);
            tool.classList.add(`hint`);
            tool.classList.add(`userpage-note-tool`);

            tool.setAttribute(`aria-label`, `Отметить как `+NOTE_VALUES[i]);
            tool.setAttribute(`data-note`, i);
            tool.setAttribute(`data-uid`, uid);

            tool.textContent = NOTE_ICO[i];

            tool.addEventListener(`click`, clickUserNote);

            tools.appendChild(tool);
        }
    }

    function renderNavigatorLoading()
    {
        let navParent = document.querySelector(`.comments-navigator__scroll`);
        if(navParent == null)
        {
            setTimeout(() => renderNavigatorLoading(), 100);
            return;
        }

        let refresh = navParent.querySelector(`.comments-navigator__refresh`);

        let navBase = document.createElement(`div`);
        navBase.classList.add(`comments-navigator__controls`);
        navBase.classList.add(`navigator__forced-off`);

        let navContent = document.createElement(`div`);
        navContent.classList.add(`comments-navigator__count`);
        navContent.classList.add(`navigator__forced-off`);
        navContent.classList.add(`navigator-loading-info`);
        navContent.setAttribute(`title`, `Количество загружаемых комментариев`);

        navContent.textContent = `0`;

        navBase.appendChild(navContent);


        navParent?.insertBefore(navBase, refresh);

        loadingNavigator = navContent;

        renderLoadingOrder();
    }

    function renderLoadingOrder()
    {
        if(loadingNavigator == null)
        {
            return;
        }

        if(loadingOrder.length > 0 || updateOrder.length > 0 || (loadingComment != null))
        {
            if(!enableLoadingNavigator)
            {
                loadingNavigator.classList.add(`navigator__forced-on`);
                loadingNavigator.classList.remove(`navigator__forced-off`);

                loadingNavigator.parentElement.classList.add(`navigator__forced-on`);
                loadingNavigator.parentElement.classList.remove(`navigator__forced-off`);

                enableLoadingNavigator = true;
            }

            if(loadingOrder.length > 0 || updateOrder.length > 0)
            {
                loadingNavigator.classList.toggle(`navigator-update-info`, (loadingOrder.length == 0));
            }

            loadingNavigator.textContent = loadingOrder.length + updateOrder.length + (loadingComment != null);

        }
        else
        {
            if(enableLoadingNavigator)
            {
                loadingNavigator.classList.remove(`navigator__forced-on`);
                loadingNavigator.classList.add(`navigator__forced-off`);

                loadingNavigator.parentElement.classList.remove(`navigator__forced-on`);
                loadingNavigator.parentElement.classList.add(`navigator__forced-off`);

                enableLoadingNavigator = false;
            }
        }
    }

    // ************************ SETTINGS  *************************

    function renderSettings()
    {

        var enableUISection = false;

        let header = document.querySelector(`.feed-panel`).querySelector(`.menu`);

        let items = [];
        header.querySelectorAll(`.menu__item`).forEach(item => {
            items.push(item);
            item.addEventListener(`click`, (e) => {
                if(enableUISection)
                {
                    settingItem.classList.toggle(`menu__item_current`, false);

                    settings?.remove();

                    if(settingsOld != null)
                    {
                        settingsContainer.appendChild(settingsOld);
                        setTimeout(() => e.target.classList.toggle(`menu__item_current`, true), 100);
                    }

                    enableUISection= false;
                }
            });
        });

        var settingsContainer = document.querySelector(`.settings`);
        var settings;
        var settingsOld;

        let settingItem = document.createElement(`a`);
        settingItem.classList.add(`menu__item`);
        settingItem.classList.add(`menu__item_route`);
        settingItem.textContent = `UI++`;
        header.appendChild(settingItem);

        settingItem.addEventListener(`click`, () => {

            enableUISection = true;

            items.forEach(item => {item.classList.toggle(`menu__item_current`, false);});

            settingItem.classList.toggle(`menu__item_current`, true);

            settingsOld = settingsContainer.querySelector(`.settings-main`)
                        || settingsContainer.querySelector(`.settings-security`)
                        || settingsContainer.querySelector(`.settings-save`)
                        || settingsContainer.querySelector(`.settings-notifications`);

            settingsOld?.remove();

            settings = document.createElement(`div`);
            settings.classList.add(`settings-main`);
            settingsContainer.appendChild(settings);

            let sectionGroup = document.createElement(`div`);
            sectionGroup.classList.add(`section-group`);
            settings.appendChild(sectionGroup);

            let sectionHeader = document.createElement(`section`);
            sectionHeader.classList.add(`section_gray`);
            sectionGroup.appendChild(sectionHeader);

            let h = document.createElement(`h4`);
            h.textContent = `Настройки сторонего скрипта Pikabu UI++`;
            sectionHeader.appendChild(h);

            let sectionBody = document.createElement(`section`);
            //sectionBody.classList.add(`section`);
            sectionBody.classList.add(`section_padding_none`);
            sectionGroup.appendChild(sectionBody);

            let options = document.createElement(`div`);
            options.classList.add(`settings-main__options`);
            sectionBody.appendChild(options);

            const addLine = tittle => {
                let line = document.createElement(`h4`);
                line.classList.add(`settings-main__sub-header`);
                line.textContent = tittle;
                options.appendChild(line);
            };

            const addCheckbox = (tittle, current, name, desc) => {
                let op = document.createElement(`div`);
                op.classList.add(`settings-main__option`);
                options.appendChild(op);

                let l = document.createElement(`label`);
                op.appendChild(l);

                let checkbox = document.createElement(`span`);
                checkbox.classList.add(`checkbox`);
                checkbox.classList.add(`checkbox_switch`);
                checkbox.classList.toggle(`checkbox_checked`, current);
                checkbox.setAttribute(`tabindex`, `0`);
                checkbox.setAttribute(`unselectable`, `on`);
                l.appendChild(checkbox);

                var test = false;

                checkbox.addEventListener(`click`, () => {
                    let value = !GM_getValue(name, 1);
                    GM_setValue(name, value);
                    checkbox.classList.toggle(`checkbox_checked`, value);
                });

                l.insertAdjacentHTML(`beforeend`, tittle);

                if(desc != undefined) l.insertAdjacentHTML(`beforeend`,`<i class="fa fa-question-circle hint" aria-label="`+desc+`"></i>`);
            };

            addLine(`Дополнительная информация о пользователе`);

            addCheckbox(`Показывать маркер даты регистрации `, SHOW_EXP, `SHOW_EXP`, `❊ - Менее месяца<br>• - 1 год<br>︿ - Более 1 года<br>︽ - Более `+EXP_VALUES[0]+` лет<br>⁂ - Более `+EXP_VALUES[1]+` лет<br>★ - Более `+EXP_VALUES[2]+` лет`);
            addCheckbox(`Показывать маркер умной заметки `, SHOW_NOTE, `SHOW_NOTE`, `Оставьте в заметке пользователя один из хэштегов (#добро, #интересно, #агрессивный, #неприемлемый), чтобы показывать специальный маркер, а также изменить цвет заметки`);
            addCheckbox(`Показывать маркер рейтинга `, SHOW_RATE, `SHOW_RATE`);
            addCheckbox(`Показывать маркер подписчиков `, SHOW_SUBS, `SHOW_SUBS`, `◔ - Более `+SUBS_VALUES[0]+` подписчиков<br>◑ - Более `+SUBS_VALUES[1]+` подписчиков<br>◕ - Более `+SUBS_VALUES[2]+` подписчиков<br>◉ - Более `+SUBS_VALUES[3]+` подписчиков`);
            addCheckbox(`Показывать маркер бана `, SHOW_BAN, `SHOW_BAN`, `ϟ - Временныый бан<br>† - Вечный бан` );
            addCheckbox(`Показывать маркер пола `, SHOW_GENDER, `SHOW_GENDER`, `♂ - Пикабушник<br>♀ - Пикабушница` );

            addLine(`Умные заметки`);

            addCheckbox(`Показывать кнопки быстрого добавления умной заметки `, SHOW_QUICK_NOTE, `SHOW_QUICK_NOTE`, `Рядом с комментариями и на странице пользователя будут кнопки для быстрого добавления заметки с хэштегом. Кнопки рядом с комментариями также сохраняют ссылку на комментарий.<br>ОСТОРОЖНО: При добавлении хэтега через кнопку, предыдущая заметка полностью удаляется.` );


            let sectionBottom = document.createElement(`section`);
            sectionBottom.classList.add(`section_gray`);
            sectionBottom.classList.add(`section_center`);
            sectionGroup.appendChild(sectionBottom);

            let buttonClear = document.createElement(`button`);
            buttonClear.classList.add(`button_danger`);
            buttonClear.textContent = `УДАЛИТЬ КЭШИРОВАННЫЕ ДАННЫЕ`;
            sectionBottom.appendChild(buttonClear);


            buttonClear.addEventListener(`click`, () => {
                GM_setValue(DATABASE, {});
            });

        });

    }


})();