Greasy Fork 支持简体中文。

hipda-ID笔记

来自地板带着爱,记录上网冲浪的美好瞬间

目前為 2021-12-08 提交的版本,檢視 最新版本

// ==UserScript==
// @name         hipda-ID笔记
// @namespace    http://tampermonkey.net/
// @version      0.2
// @description  来自地板带着爱,记录上网冲浪的美好瞬间
// @author       屋大维
// @license      MIT
// @match        https://www.hi-pda.com/forum/viewthread.php?tid*
// @resource     IMPORTED_CSS https://code.jquery.com/ui/1.13.0/themes/base/jquery-ui.css
// @require      https://code.jquery.com/jquery-3.4.1.min.js
// @require      https://code.jquery.com/ui/1.13.0/jquery-ui.js
// @icon         https://icons.iconarchive.com/icons/iconshock/real-vista-project-managment/64/task-notes-icon.png
// @grant        GM.setValue
// @grant        GM.getValue
// @grant        GM.deleteValue
// @grant        GM_getResourceText
// @grant        GM_addStyle
// ==/UserScript==

(async function() {
    'use strict';
    // CSS
    const my_css = GM_getResourceText("IMPORTED_CSS");
    GM_addStyle(my_css);
    GM_addStyle(".no-close .ui-dialog-titlebar-close{display:none} textarea{height:100%;width:100%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}");

    // Your code here...
    // helpers
    function htmlToElement(html) {
        var template = document.createElement('template');
        html = html.trim(); // Never return a text node of whitespace as the result
        template.innerHTML = html;
        return template.content.firstChild;
    }

    // classes
    class HpPost {
        constructor() {
        }

        getPostTid() {
            return location.href.match(/tid=(\d+)/) ? parseInt(location.href.match(/tid=(\d+)/)[1]) : -999;
        }

        getUserUid() {
            return parseInt($("cite > a").attr("href").split("uid=")[1]);
        }

        getHpThreads() {
            let postTid = this.getPostTid();
            let divs = $('#postlist > div').get();
            return divs.map(d => new Hpthread(postTid, d));
        }

        addNoteManagementUI(_notebook) {
            var that = this;
            var button = htmlToElement(`
              <button id="noteButton_management">
                <span><img src="https://icons.iconarchive.com/icons/iconshock/real-vista-project-managment/32/task-notes-icon.png"></img></span>
              </button>
            `);

            // create dialog
            let dialog = htmlToElement(`
              <div id="noteDialog_management" style="display: none;">
                <h3>hipda-ID笔记 v${GM_info.script.version}</h3>
                <p style="margin: 10px auto 10px auto;">来自地板带着爱</p>
                <div>
                  <button id="noteButton_import">导入</button>
                  <button id="noteButton_export">导出</button>
                  <button id="noteButton_reset">重置</button>
                </div>
              </div>
            `);
            $("body").append(dialog);

            $(document).ready( function () {
                $(document).on ("click", "#noteButton_import", function() {
                    let r = confirm("确定要导入ID笔记吗?现有笔记将会被覆盖!");
                    if (!r) {
                      return;
                    }

                    // prompt cannot handle large file, extend it in the future
                    let data = prompt("请将 id笔记.json 中的文本复制粘贴入文本框:");
                    if (data !== null) {
                        // try to load
                        try {
                            let j = JSON.parse(data);
                            _notebook.importNotebook(j);
                        } catch(err) {
                            alert("格式错误!" + err);
                            return;
                        }
                        alert("导入成功!");
                    }
                });
                $(document).on ("click", "#noteButton_export", function() {
                    let r = confirm("确定要导出ID笔记吗?");
                    if (!r) {
                        return;
                    }
                    let a = document.createElement("a");
                    a.href = "data:text," + _notebook.exportNotebook();
                    a.download = "id笔记.json";
                    a.click();
                });
                $(document).on ("click", "#noteButton_reset", function() {
                    let r = confirm("确定要清空ID笔记吗?");
                    if (!r) {
                        return;
                    }
                    _notebook.resetNotebook();
                    alert("ID笔记已经清空!");
                });
                $(document).on ("click", `#noteButton_management`, function () {
                    console.log("open notebook management dialog");
                    $(`#noteDialog_management`).dialog({
                        title: "ID笔记:管理面板",
                        height: 150,
                        width: 300,
                        closeOnEscape: true,
                    });
                });
            });

            // add UI
            let d = $("td.modaction").last();
            d.append(button);

        }

    }

    class Hpthread {
        constructor(postTid, threadDiv) {
            this.postTid = postTid;
            this._thread_div = threadDiv;
        }

        getThreadAuthorName() {
            return $(this._thread_div).find("div.postinfo > a").first().text();
        }

        getThreadAuthorUid() {
            return parseInt($(this._thread_div).find("div.postinfo > a").first().attr("href").split("uid=")[1]);
        }

        getThreadPid() {
            return parseInt($(this._thread_div).attr("id").split("_")[1]);
        }

        getGotoUrl() {
            return `https://www.hi-pda.com/forum/redirect.php?goto=findpost&ptid=${this.postTid}&pid=${this.getThreadPid()}`;
        }

        getThreadContent() {
            // get text without quotes
            return $(this._thread_div).find("td.t_msgfont").first().clone().children().remove().end().text().trim();
        }

        getThreadBrief(n) {
            let content = this.getThreadContent();
            if (content.length <= n) {
              return content;
            }
            return content.slice(0, n) + "\n\n【以上为截取片段】" ;
        }

        addNoteUI(_notebook) {
            let uid = this.getThreadAuthorUid();
            let index = $(this._thread_div).index();
            let userName = this.getThreadAuthorName();

            var that = this;
            // create an UI element which contains data and hooks
            // button
            let button = htmlToElement(`
              <button id="noteButton_${index}" style="color:grey; margin-left:20px;">
                ID笔记
              </button>
            `);
            // note dialog
            let dialog = htmlToElement(`
              <div id="noteDialog_${index}" style="display: none;">
                <textarea rows="10" wrap="hard" placeholder="暂时没有笔记">
              </div>
            `);
            $("body").append(dialog);

            // add event to button
            $(document).ready( function () {
                $(document).on ("click", `#noteButton_${index}`, function () {
                    console.log("open note for", userName);
                    // freshly fetched from DB
                    $(`#noteDialog_${index}`).find('textarea').first().val(_notebook.get(uid));
                    $(`#noteDialog_${index}`).dialog({
                        title: `ID笔记:${userName}`,
                        dialogClass: "no-close",
                        closeText: "hide",
                        closeOnEscape: true,
                        height: 350,
                        width: 600,
                        buttons: [
                            {
                                text: "插入当前楼层",
                                click: function() {
                                    let txt = $(`#noteDialog_${index}`).find('textarea').first();
                                    var caretPos = txt[0].selectionStart;
                                    var textAreaTxt = txt.val();
                                    var txtToAdd = `====\n引用: ${that.getGotoUrl()}\n${that.getThreadAuthorName()} 说:${that.getThreadBrief(200)}\n====`;
                                    txt.val(textAreaTxt.substring(0, caretPos) + txtToAdd + textAreaTxt.substring(caretPos) );
                                }
                            },
                            {
                                text: "确认",
                                click: function() {
                                    // save the new note before close
                                    let newNote = $(`#noteDialog_${index}`).find('textarea').first().val();
                                    _notebook.put(uid, userName, newNote);
                                    $(this).dialog( "close" );
                                }
                            },
                            {
                                text: "取消",
                                click: function() {
                                    // close without saving
                                    $(this).dialog( "close" );
                                }
                            }
                        ]
                    });
                });
            });

            // add UI
            let d = $(this._thread_div).find("td[rowspan='2'].postauthor").first();
            d.append(button);
        }

    }

    class Notebook {
        constructor(user_uid) {
            // initialization
            this._name = "hipda-notebook";
            this._user_uid = user_uid;
            this._notebook = {};
            return (async () => {
                this.loadFromLocalStorage();
                return this;
            })();
        }

        async loadFromLocalStorage() {
            console.log("load ID Notebook from Local Storage");
            let data = await GM.getValue(this._name, null);
            if (data !== null) {
                this._notebook = JSON.parse(data);
            }
        }

        async saveToLocalStorage() {
            console.log("save ID Notebook to Local Storage");
            await GM.setValue(this._name, JSON.stringify(this._notebook));
        }

        put(uid, userName, note) {
            // we need userName here, so user can analyze notes even after export
            this._notebook[uid] = {uid, userName, note};
            this.saveToLocalStorage();
        }

        get(uid) {
            if (uid in this._notebook) {
                return this._notebook[uid].note;
            }
            return "";
        }

        delete(uid) {
            if (uid in this._notebook) {
                delete this._notebook[uid];
                this.saveToLocalStorage();
            }
        }

        exportNotebook() {
            // can add meta data here
            let output = {
                notebook: this._notebook,
                version: GM_info.script.version,
                timestamp: + new Date()
            };
            return JSON.stringify(output);
        }

        importNotebook(input) {
            let attrs = ['notebook', 'version', 'timestamp'];
            for (let i=0; i<attrs.length; i++) {
                if (!input.hasOwnProperty(attrs[i])) {
                    throw(`bad format: ${attrs[i]} does not exist`);
                }
            }
            this._notebook = {...input.notebook};
            this.saveToLocalStorage();
        }

        resetNotebook() {
            this._notebook = {};
            this.saveToLocalStorage();
        }
    }




    // get a post object

    var THIS_POST = new HpPost();

    // get tid and uid; uid for future extension
    var tid = THIS_POST.getPostTid();
    var uid = THIS_POST.getUserUid();


    var notebook = await new Notebook(uid);

    // render UI below
    // ID notes
    var hp_threads = THIS_POST.getHpThreads();
    for (let i=0; i<hp_threads.length; i++) {
        let hp_thread = hp_threads[i];
        hp_thread.addNoteUI(notebook);
    }
    // management panel
    THIS_POST.addNoteManagementUI(notebook);


})();