v2ex+

auto load item detail when mouseover title

目前為 2023-11-21 提交的版本,檢視 最新版本

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 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)



})();