Greasy Fork is available in English.

v2ex+

auto load item detail when mouseover title

// ==UserScript==
// @name         v2ex+
// @namespace    http://tampermonkey.net/
// @version      0.19
// @description  auto load item detail when mouseover title
// @author       Silvio27
// @match        https://*.v2ex.com/*
// @match        https://v2ex.com/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=v2ex.com
// @license      GPLv3
// @grant        GM_addStyle
// @grant        GM_registerMenuCommand

// ==/UserScript==

(function() {
    'use strict';
    console.log("script")
    topics_node_page(true, true, true, 600)
    member_replies_page(true, false, false, 0)
    linksToImgs()


    const menu_command_id = GM_registerMenuCommand("加载页面全部内容", function () {
        document.querySelectorAll(".triangle").forEach(e => {setTimeout(e.click(), 500)})
    }, "a");


    function topics_node_page(show_topic, show_fav_btn, show_reply, defaultHeight) {
        let topics
        if (document.getElementById("TopicsNode")) {
            // alert("TopicsNode")
            topics = document.querySelectorAll("#TopicsNode>.cell")
        } else {
            // alert("No TopicsNode")
            topics = document.querySelectorAll(".cell.item")
        }
        topics.forEach((element, index) => {
            let new_item = create_item("td", element.querySelector("tr"), element.querySelector("tr").lastElementChild,
                                       '▼', "triangle", 30)
            // 修改cursor_style
            cursor_style(new_item)
            new_item.onclick = function () {
                let url = element.querySelector(".topic-link").href
                let id = url.replace("https://www.v2ex.com/t/", "").split("#")[0] + "_topic"
                load_item_change_btn(element, id, url, new_item, show_topic, show_fav_btn, show_reply, defaultHeight)

            }

        })
    }

    function member_replies_page(show_topic, show_fav_btn, show_reply, defaultHeight) {
        let dock_areas = document.querySelectorAll(".dock_area")
        dock_areas.forEach((element, index) => {
            // 创建新的列
            let new_item = create_item("span", element.querySelector("td"), "",
                                       '▼', "triangle", 30)
            cursor_style(new_item)
            new_item.onclick = function () {
                let url = element.querySelectorAll("a")[2].href
                let id = url.replace("https://www.v2ex.com/t/", "").split("#")[0] + "_reply"
                load_item_change_btn(element, id, url, new_item, show_topic, show_fav_btn, show_reply, defaultHeight)
            }
        })
    }

    function load_item_change_btn(element, id, url, btn, show_topic, show_fav_btn, show_reply, defaultHeight) {
        let content = document.getElementById(id)
        if (content) {
            if (content.style.display === "none") {
                content.style.display = "block"
                btn.innerText = "▲"
            } else {
                content.style.display = "none"
                btn.innerText = "▼"
            }
        } else {
            btn.innerText = "加载中"
            document.body.style.cursor = "wait";
            btn.className = "content-loaded"
            load_item_topic_favBtn_reply(element, url, id, btn, show_topic, show_fav_btn, show_reply, defaultHeight)

        }
    }

    function load_item_topic_favBtn_reply(target_ele, url, id, load_btn, show_topic, show_fav_btn, show_reply, defaultHeight) {
        // 创建一个临时容器元素来容纳加载的内容
        const tempContainer = document.createElement('div');
        // 使用Ajax异步加载下一页的内容
        const xhr = new XMLHttpRequest();
        xhr.open('GET', url, true);
        xhr.onload = function () {
            if (xhr.status === 200) {
                tempContainer.innerHTML = xhr.responseText
                // 创建返回的内容元素
                let contents = document.createElement('div')
                contents.id = id
                contents.className = "woDeStyle"

                // 绑定Escape折叠contents
                mouse_escape(contents)

                if (show_topic) {
                    // 获得 topic_content
                    let topic_contents = tempContainer.querySelectorAll(".topic_content")
                    contents.innerHTML += '<div class="topic-content-box"></div>'
                    topic_contents.forEach((e) => {
                        // 即 .topic-content-box
                        contents.firstChild.appendChild(e.parentElement)
                    })
                }

                if (show_fav_btn) {
                    // 添加topic_buttons
                    let favorite_btn = tempContainer.querySelector(".topic_buttons")
                    // 点击收藏,页面在新标签中打开
                    let fav_ele = favorite_btn.querySelector("a")
                    fav_ele.onclick = function (e) {
                        // 阻止原始a标签打开新页面
                        e.preventDefault()
                        // 后台发送xhr
                        mark_favourite(this)
                    }
                    contents.firstElementChild.appendChild(favorite_btn)
                }

                if (show_reply) {
                    // todo 展示不清楚为什么box会出现不同的情况,待研究
                    // 获得 reply_content
                    let reply_box = tempContainer.querySelectorAll(".box")
                    reply_box.forEach((e, index) => {
                        if (e.innerText.includes("条回复")) {
                            contents.appendChild(e)
                        }
                    })

                    // 去除reply_content中头像及空格
                    contents.querySelectorAll("tbody>tr").forEach((e) => {
                        e.removeChild(e.firstElementChild)
                        e.removeChild(e.firstElementChild)
                    })

                    // 添加一个折叠按钮 todo 是否可以直接把tr中添加的拿来用?
                    let hideBtn = document.createElement("div")
                    hideBtn.innerText = "▲"
                    hideBtn.className = "content-loaded"
                    hideBtn.style.textAlign = "right"
                    hideBtn.onclick = (() => {
                        // 隐藏主题详情
                        contents.style.display = "none"
                        // 切换主题展开为关闭
                        contents.parentElement.querySelector(".content-loaded").innerText = "▼"
                    })
                    cursor_style(hideBtn)
                    contents.appendChild(hideBtn)
                }

                // content添加到target_ele
                target_ele.appendChild(contents)
                // 解析markdown图片
                linksToImgs()

                // 设置默认高度
                set_content_default_height(contents, defaultHeight)

                // 修改折叠按钮为展开,切换样式
                set_btn_up(load_btn)
            }
        };
        xhr.send();
    }

    function cursor_style(element) {
        element.addEventListener("mouseover", function () {
            document.body.style.cursor = "pointer";
        });
        element.addEventListener("mouseout", function () {
            document.body.style.cursor = "auto";
        });
    }

    function create_item(tagName, element, element_place, inner_text, class_name, width) {
        let item = document.createElement(tagName)
        item.setAttribute("width", width)
        item.setAttribute("align", "center")
        item.setAttribute("class", class_name)
        item.innerText = inner_text
        if (element_place) {
            element.insertBefore(item, element_place)
        } else {
            element.appendChild(item)
        }
        return item
    }

    function mark_favourite(ele) {
        let url = ele.href
        const xhr = new XMLHttpRequest();
        xhr.open('GET', url, true);
        xhr.onload = function () {
            if (xhr.status === 200) {
                if (ele.innerText !== "取消收藏") {
                    ele.innerText = "取消收藏"
                    ele.style.backgroundColor = "gold"
                    ele.href = url.replace("fav", "unfav")
                } else {
                    // todo 取消收藏,好像有页面重定向的问题
                    console("目前需要手动处理")
                    // ele.innerText = "加入收藏"
                    // ele.style.backgroundColor = ""
                    // ele.href = url.replace("unfav", "fav")
                }
            }
        }
        xhr.send();

    }

    function mouse_escape(element) {
        element.addEventListener('mouseover', function () {
            document.addEventListener('keydown', escKeyPressed);
        });

        element.addEventListener('mouseout', function () {
            document.removeEventListener('keydown', escKeyPressed);
        });

        function escKeyPressed(event) {
            if (event.key === 'Escape') {
                element.style.display = 'none';
                // todo 这个位置应该需要结构
                element.parentElement.querySelector(".content-loaded").innerText = "▼"
            }
        }
    }

    function set_content_default_height(element, defaultHeight) {
        // 如果没有设置,默认高度600px;如果输入0,完整显示
        if (defaultHeight === 0) {
            defaultHeight = element.offsetHeight
        } else if (!defaultHeight) {
            defaultHeight = 600
        }

        if (element.offsetHeight > defaultHeight) {
            element.style.height = defaultHeight + "px"
        } else {
            element.style.height = element.offsetHeight
        }
    }

    function set_btn_up(element) {
        element.innerText = "▲"
        element.className = "content-loaded"
        document.body.style.cursor = "auto";
    }


    // 链接转图片
    // 修改自 https://greasyfork.org/zh-CN/scripts/424246
    // size调整为30%;考虑可以点击图片,窗口最大化
    // todo 可以考虑把外面的括号进行替换
    function linksToImgs() {
        let links = document.links;
        Array.from(links).forEach(function (_this) {
            if (/^https.*\.(?:jpg|jpeg|jpe|bmp|png|gif)/i.test(_this.href) && !(/<img\s/i.test(_this.innerHTML))) {
                _this.innerHTML = `<img src="${_this.href}" style="max-width: 30%!important;" />`;
                // alert("有图片被替换了")
            } else if (/^https:\/\/imgur\.com\/[a-z]+$/i.test(_this.href)) { // 针对没有文件后缀的 imgur 图床链接
                _this.innerHTML = `<img src="${_this.href}.png" style="max-width: 30%!important;" />`;
            }
        });
    }





    let css = `
         .woDeStyle {
        /*height: 600px;*/
        padding: 10px;
        margin: 10px auto;
        border: 1px solid gray;
        border-radius: 10px;
        overflow: scroll;
    }

    .topic-content-box {
        border-bottom: 2px dashed gray;
        padding-bottom: 10px;
        margin-bottom: 10px;
    }

    .triangle {
        color: gray;
        padding-left: 10px;
    }

    .content-loaded {
        color: greenyellow;
        padding-left: 10px;
    }

    #Wrapper {
        background-color: var(--box-background-color) !important;
        background-image: none !important;
    }

    .toggle-more-nodes {
        display: none;
    }

    #nodes-more-children, #nodes-more-related {
        display: block !important;
    }


    `
    GM_addStyle(css)



})();