v2ex+

auto load item detail when mouseover title

当前为 2023-11-21 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

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

// ==/UserScript==

(function() {
    'use strict';
    console.log("script")
    let TopicsNode = document.getElementById("TopicsNode")
    let items
    if (TopicsNode) {
        // alert("TopicsNode")
        items = document.querySelectorAll("#TopicsNode>.cell")
    } else {
        // alert("No TopicsNode")
        items = document.querySelectorAll(".cell.item")
    }
    items.forEach((element, index) => {
        let topic_item = element.querySelector(".topic-link")

        // 创建新的列
        let new_tr = document.createElement("td")
        new_tr.setAttribute("width", "20")
        new_tr.innerHTML = '<div class="triangle">▼</div>'
        element.querySelector("tr").appendChild(new_tr)
        cursor_style(new_tr)
        new_tr.onclick = function () {
            let id = topic_item.href.replace("https://www.v2ex.com/t/", "")
            let content = document.getElementById(id)
            if (content) {
                if (content.style.display === "none") {
                    content.style.display = "block"
                    this.firstElementChild.innerText = "▲"
                } else {
                    content.style.display = "none"
                    this.firstElementChild.innerText = "▼"
                }
            } else {
                this.firstElementChild.innerText = "加载中"
                document.body.style.cursor = "wait";
                this.firstElementChild.className = "content-loaded"
                load_item(topic_item, topic_item.href, new_tr, element)
            }
        }

    })


    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 {
                    ele.innerText = "加入收藏"
                    ele.style.backgroundColor = ""
                    ele.href = url.replace("unfav", "fav")
                }
            }
        }
        xhr.send();

    }


    function load_item(topic_ele, url, load_btn, target_ele) {
        // 创建一个临时容器元素来容纳加载的内容
        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 = url.replace("https://www.v2ex.com/t/", "")
                contents.className = "woDeStyle"

                // 绑定Escape折叠contents
                contents.addEventListener('mouseover', function () {
                    document.addEventListener('keydown', escKeyPressed);
                });

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

                function escKeyPressed(event) {
                    if (event.key === 'Escape') {
                        contents.style.display = 'none';
                        contents.parentElement.querySelector(".content-loaded").innerText = "▼"
                    }
                }


                // 获得 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)
                })

                // 添加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)

                // 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)
                // 修改折叠按钮为展开,切换样式
                load_btn.firstElementChild.innerText = "▲"
                load_btn.firstElementChild.className = "content-loaded"
                document.body.style.cursor = "auto";


            }
        };
        xhr.send();
    }

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



    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 {
        font-size: medium;
        color: gray;
    }

    .content-loaded {
        font-size: medium;
        color: greenyellow;
    }

    `
    GM_addStyle(css)



})();