Greasy Fork is available in English.

语雀标签(状态)小工具 - yuque.com

2022/12/19 03:46:53

// ==UserScript==
// @name        语雀标签(状态)小工具 - yuque.com
// @namespace   Violentmonkey Scripts
// @match       https://www.yuque.com/*/*/*
// @grant       none
// @version     1.0
// @author      -
// @description 2022/12/19 03:46:53
// @license MIT
// ==/UserScript==

(function a(startTime, lastELCount) {
    'use strict';

    startTime = startTime || Date.now();
    lastELCount = lastELCount || 0;
    if (Date.now() - startTime > 10000) {
        return;
    }
    // let thisElCount = document.querySelectorAll('*')?.length || 0;
    // if (thisElCount !== lastELCount || Date.now() - startTime > 10000) {
    //     setTimeout(a, 300, startTime, thisElCount);
    //     return;
    // }
    let $main = document.querySelector('#main') || document.getElementById('lark-text-editor');
    if (!$main) {
        setTimeout(a, 300, startTime);
        return;
    }

    document.getElementById('wl-yq-label-panel')?.remove();

    let div = document.createElement('div', {});
    div.id = 'wl-yq-label-panel'
    div.innerHTML = `
<style>
#wl-yq-label-panel {
    position: fixed;
    top: 68px;
    right: 20px;
    max-height: calc(100% - 100px);
    width: 200px;
    box-shadow: 0 0 5px -1px #cccccc;
    border-radius: 5px;
    padding: 10px;
    z-index: 1000;
    overflow: auto;
    opacity: 0;
    transition: opacity 0.5s;
}

.wl-drag {
    position: absolute;
    width: 100%;
    height: 10px;
    left: 0;
    top: 0;
    cursor: move;
}
.no-select {
    -moz-user-select:none; /*火狐*/
    -webkit-user-select:none; /*webkit浏览器*/
    -ms-user-select:none; /*IE10*/
    /*-khtml-user-select:none; !*早期浏览器*!*/
    user-select:none;
}
.wl-animate {
    transition: left 1s, top 1s !important;
}
.wl-choose-label {
    outline: 1px solid #ac6363;
}

.wl-label-item {
    text-overflow: ellipsis;
    OVERFLOW: hidden;
    word-break: keep-all;
    white-space: nowrap;
}
</style>

<div class="wl-drag"></div>

<!--<p> 标签1..... </p>-->
<!--<p> 标签1..... </p>-->
<!--<p> 标签1..... </p>-->
<!--<p> 标签1..... </p>-->
<!--<p> 标签1..... </p>-->
<div class="wl-label-content"></div>
`
    document.body.append(div);

    let mousedownOffsetX, mousedownOffsetY;
    let $wlYqLabelPanel = document.getElementById('wl-yq-label-panel');
    document.getElementsByClassName('wl-drag')[0].addEventListener('mousedown', function (e) {
        document.body.setAttribute('class', document.body.getAttribute('class') + ' no-select');
        mousedownOffsetX = e.offsetX;
        mousedownOffsetY = e.offsetY;
        document.addEventListener('mousemove', wlMousemoveFun);
    });

    function wlMousemoveFun(e) {
        $wlYqLabelPanel.style.left = (e.x - mousedownOffsetX) + 'px';
        $wlYqLabelPanel.style.top = (e.y - mousedownOffsetY) + 'px';
    }

    document.addEventListener('mouseup', e => {
        document.body.setAttribute('class', document.body.getAttribute('class').replace('no-select', ''));
        document.removeEventListener('mousemove', wlMousemoveFun);
        if (parseInt($wlYqLabelPanel.style.left.replace('px', '')) < 20
            || parseInt($wlYqLabelPanel.style.top.replace('px', '')) < 20
            || parseInt($wlYqLabelPanel.style.left.replace('px', '')) > document.body.clientWidth - 200 - 20
            || parseInt($wlYqLabelPanel.style.top.replace('px', '')) > document.body.clientHeight - $wlYqLabelPanel.clientHeight - 20) {
            $wlYqLabelPanel.setAttribute('class', ($wlYqLabelPanel.getAttribute('class') || '') + ' wl-animate');
            if (parseInt($wlYqLabelPanel.style.left.replace('px', '')) < 20) {
                $wlYqLabelPanel.style.left = '20px';
            }
            if (parseInt($wlYqLabelPanel.style.top.replace('px', '')) < 20) {
                $wlYqLabelPanel.style.top = '20px';
            }
            if (parseInt($wlYqLabelPanel.style.left.replace('px', '')) > document.body.clientWidth - 200 - 20) {
                $wlYqLabelPanel.style.left = document.body.clientWidth - 200 - 20 + 'px';
            }
            if (parseInt($wlYqLabelPanel.style.top.replace('px', '')) > document.body.clientHeight - $wlYqLabelPanel.clientHeight - 20) {
                $wlYqLabelPanel.style.top = document.body.clientHeight - $wlYqLabelPanel.clientHeight - 20 + 'px';
            }
            setTimeout(() => $wlYqLabelPanel.setAttribute('class', $wlYqLabelPanel.getAttribute('class').replace('wl-animate', '')), 1000);
        }
    });

    let $labelContent = document.getElementsByClassName('wl-label-content')[0];
    function refreshLabels(a) {
        $wlYqLabelPanel.style.opacity = '0';
        setTimeout(refreshLabelsDo, 500)
    }
    function refreshLabelsDo() {
        let $labels = [...document.querySelectorAll('[class="article-content"] [data-card-name="label"], #lark-text-editor [data-card-name="label"]')];
        $labels.sort((a, b) => {
            let sor = a.childNodes[0].childNodes[0].childNodes[0].getAttribute('class') > b.childNodes[0].childNodes[0].childNodes[0].getAttribute('class') ? 1
                : a.childNodes[0].childNodes[0].childNodes[0].getAttribute('class') < b.childNodes[0].childNodes[0].childNodes[0].getAttribute('class') ? -1 : 0;
            if (sor !== 0) return sor;
            return a.innerText > b.innerText ? 1 : a.innerText < b.innerText ? -1 : 0;
        })
        let content = ``;
        for (let $label of $labels) {
            let labelContent = ($label?.nextElementSibling?.innerText || '') + ($label?.nextElementSibling?.nextElementSibling?.innerText || '') + ($label?.nextElementSibling?.nextElementSibling?.nextElementSibling?.innerText || '');
            content += `
                <div id="${$label.id}" class="wl-label-item"><a href="#${$label.id}"><object><div style="display: inline-block">${$label.outerHTML}</div><span>${labelContent}</span></object></a></div>
            `;
        }
        $labelContent.innerHTML = content;
        setTimeout(()=>$wlYqLabelPanel.style.opacity = '1', 300);
    }
    $labelContent.addEventListener('mouseover', function (e) {
        let $e = e.target;
        while (true) {
            if ($e.classList.contains('wl-label-item')) {
                break;
            }
            $e = $e.parentElement;
            if ($e == null) return;
        }

        for (let $label of document.querySelectorAll('#' + $e.id)) {
            if (($label.getAttribute('class') || '').indexOf('wl-label-item') > -1) {
                $label.setAttribute('class', $label.getAttribute('class') + ' wl-choose-label');
            } else {
                $label.parentElement.setAttribute('class', $label.parentElement.getAttribute('class') + ' wl-choose-label');
            }
        }
    })
    $labelContent.addEventListener('mouseout', function (e) {
        for (let $label of document.querySelectorAll('.wl-choose-label')) {
            $label.setAttribute('class', $label.getAttribute('class').replace('wl-choose-label', ''));
        }
    })
    // refreshLabels();

    // let lastRefReshLabelsTime;
    let lastElCount = 0;
    let MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
    let observer = new MutationObserver( (mutationList) => {
        // console.log(mutationList)
        let thisELCount = (document.querySelectorAll('[class="article-content"] [data-card-name="label"], #lark-text-editor [data-card-name="label"]')?.length || 0);
        if (lastElCount === thisELCount) return;
        lastElCount = thisELCount || 0;
        refreshLabels();
    })
    observer.observe($main, {
        // attributes: true,
        // attributeFilter: ['class'],
        // attributeOldValue: true,
        subtree: true,
        childList: true
    })

    let $focusTag = null;
    document.body.addEventListener('focus', function (e) {
        // console.log(e)
        let $e = e.target;
        while (true) {
            if ($e.getAttribute('ne-role') === 'render-unit') {
                break;
            }
            $e = $e.parentElement;
            if ($e == null) return;
        }
        $focusTag = $el.querySelector('[data-card-name="label"]');
    });
    document.body.addEventListener('keyup', function (e) {
        let $e = document.getSelection().focusNode;
        while (true) {
            if (($e.getAttribute && $e.getAttribute('ne-role')) === 'render-unit') {
                break;
            }
            $e = $e.parentElement;
            if ($e == null) return;
        }
        if ($e.querySelector('[data-card-name="label"]')) refreshLabels();
    })


})();