您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
使用历史列表记录发送过的评论, 可收藏评论, 双击可跳转到评论来源页面. 可自定义发送评论的快捷键 (默认为 Ctrl + Enter)
当前为
// ==UserScript== // @name 评论历史记录与评论收藏(哔哩哔哩|B站|bilibili) // @namespace https://gf.qytechs.cn/zh-CN/users/1196880-ling2ling4 // @version 2.0.3 // @author Ling2Ling4 // @description 使用历史列表记录发送过的评论, 可收藏评论, 双击可跳转到评论来源页面. 可自定义发送评论的快捷键 (默认为 Ctrl + Enter) // @license AGPL-3.0-or-later // @icon data:image/png;base64,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 // @match *://*.bilibili.com/* // @run-at document-end // @grant GM_setValue // @grant GM_getValue // @grant GM_registerMenuCommand // @compatible chrome // @compatible edge // @compatible firefox // ==/UserScript== (() => { "use strict"; function getBiliPageType(location) { const url = location.href; return ("www.bilibili.com" !== location.host && "www.bilibili.com" !== location.hostname) || "/" !== location.pathname ? url.includes("www.bilibili.com/video") ? "视频" : url.includes("space.bilibili.com") ? "主页" : url.includes("t.bilibili.com") || url.includes("www.bilibili.com/opus") ? "动态" : url.includes("www.bilibili.com/read") ? "专栏" : url.includes("www.bilibili.com/bangumi") ? "番剧" : url.includes("live.bilibili.com") ? "直播" : url.includes("message.bilibili.com") ? "消息" : "其他" : "首页"; } function addCss(cssText, box = document.body, id = "") { const style = document.createElement("style"); return ( id && (style.id = id), box.appendChild(style), (style.innerHTML = cssText), style ); } const base_id = "ll_comment_history_", info = { pageType: "", base_id, cssId: base_id + "css", settings: { isHiddenBtn: { name: "是否隐藏按钮", value: !1, base: !1, key: base_id + "isHiddenBtn", txt: "是否隐藏评论列表的按钮 (隐藏后鼠标移入按钮区域后按钮会显示出来)\n默认: base\n当前: current", }, position: { name: "显示位置", value: "4, 4", base: "4, 4", key: base_id + "position", txt: "设置按钮的显示位置 (按钮距左侧 和 顶部的距离), 可以为负值, 中间用 , 分隔\n如: 10,10 表示距离左侧10像素距离顶部10像素\n默认: base", }, listSize: { name: "列表宽度与最大高度", value: "400, 500", base: "400, 500", key: base_id + "listSize", txt: "设置列表的宽度与列表的最大高度, 中间用 , 分隔\n如: 400,300 表示列表宽度400像素, 列表最大高度300像素\n默认: base", }, scale: { name: "缩放倍率", value: 1, base: 1, key: base_id + "scale", txt: "设置缩放倍率, 默认: base", }, listMaxLen: { name: "列表最大长度", value: 200, base: 200, key: base_id + "listMaxLen", txt: "设置历史列表的最大长度, 超出时最早的数据会被删除, 默认: base", }, sendKeys: { name: "评论快捷键", value: "ctrl+enter", base: "ctrl+enter", key: base_id + "sendKeys", txt: "设置发送消息时的快捷键, 每个键用 + 分隔, 特殊字符请用英文符号 (不支持shift+enter)\n例如: ctrl + enter, 表示按下ctrl和回车键发送消息\n可使用单个按键, 支持 ctrl shift alt win/meta 字母 数字 等的组合键\n默认: base", }, addItemKeys: { name: "评论收藏的组合键", value: "ctrl", base: "ctrl", key: base_id + "addItemKeys", txt: "设置评论加入评论收藏的组合键, 按下组合键后'双击'评论的文本可将文本添加到评论收藏的列表中, 仅支持 ctrl shift alt win/meta 的组合键\n默认: base", }, isHiddenList: { name: "双击列表项后是否收起列表", value: !0, base: !0, key: base_id + "isHiddenList", txt: "是否在双击列表的一条评论记录后收起列表\n默认: base\n当前: current", }, }, history: { width: 30, height: 30, data: { saveName: base_id + "list", suki_info: { saveName: base_id + "sukiList", callback: {} }, callback: {}, }, color: { main: "#addeee", bd: "#dfedfe", font: "#4f4f4f", h_font: "#75beff", listBtnObj: { bg: "#fff", bd: "", hover: "#75b3ff", hover_bg: "#fff", hover_bd: "", click: "#75b3ff", click_bg: "#fff", click_bd: "", }, }, doms: { box: { id: base_id + "box", title: "" }, btn: { class: "btn", title: "评论记录列表" }, options: { class: "options", title: "" }, comment: { option: { text: "历史评论", class: "comment" }, list: { class: "suki-comment" }, }, suki_comment: { option: { text: "评论收藏", class: "comment" }, list: { class: "suki-comment" }, }, }, }, customKeys: { isBtnClickEvent: !0, curDoms: {}, curClassList: {}, classList: { focus: "focus", 视频: { focusDom: "reply-box-textarea", box: "box-normal", textarea: "reply-box-textarea", sendBtn: "reply-box-send", reply: "reply-content", subReply: "reply-content", replyParent: "sub-reply-content", user: "user-name", subUser: "sub-user-name", replyUser: "user", }, 番剧: { focusDom: "reply-box-textarea", box: "box-normal", textarea: "reply-box-textarea", sendBtn: "reply-box-send", reply: "reply-content", subReply: "reply-content", replyParent: "sub-reply-content", user: "user-name", subUser: "sub-user-name", replyUser: "user", }, 主页: { focusDom: "reply-box-textarea", box: "box-normal", textarea: "reply-box-textarea", sendBtn: "reply-box-send", reply: "reply-content", subReply: "reply-content", replyParent: "sub-reply-content", user: "user-name", subUser: "sub-user-name", replyUser: "user", }, 动态: { focusDom: "reply-box-textarea", box: "box-normal", textarea: "reply-box-textarea", sendBtn: "reply-box-send", reply: "reply-content", subReply: "reply-content", replyParent: "sub-reply-content", user: "user-name", subUser: "sub-user-name", replyUser: "user", }, 专栏: { focusDom: "textarea-container", box: "textarea-container", textarea: "ipt-txt", sendBtn: "comment-submit", reply: "text", subReply: "text-con", replyParent: "user", user: "name", subUser: "name", replyUser: { type: "dataset", value: "usercardMid" }, }, 消息: { focusDom: "", box: "reply-box", textarea: "reply-textarea", sendBtn: "send-button", }, }, }, }; function getValue({ base = null, key, valType = "string", isReSet = !0, getVal, setVal, } = {}) { let val = getVal ? getVal(key) : localStorage.getItem(key); return ( null !== base && null == val && ((val = base), isReSet && (setVal ? setVal(key, val) : localStorage.setItem(key, val))), "string" === valType ? val : "boolean" === valType || "number" === valType ? JSON.parse(val) : "object" === valType ? JSON.parse(val || {}) : "array" === valType ? JSON.parse(val || []) : val ); } const settings = info.settings; const curInfo = info.history, doms = curInfo.doms, css_settings = info.settings; function boolTxt(val) { return val ? "是 (确定)" : "否 (取消)"; } function setIsItem({ txt, base, key, isChangeTxt = !0, isTxtVal = !0, getValue = null, setValue = null, } = {}) { let val = JSON.parse(getValue ? getValue(key) : localStorage.getItem(key)); null == val && ((val = base), setValue ? setValue(key, val) : localStorage.setItem(key, val)), isChangeTxt && (txt = isTxtVal ? txt.replace("base", boolTxt(base)).replace("current", boolTxt(val)) : txt.replace("base", base).replace("current", val)); const newVal = confirm(txt); return ( newVal !== val && (setValue ? setValue(key, newVal) : localStorage.setItem(key, newVal), !0) ); } function setTextItem({ txt, base, key, isChangeTxt = !0, verification = null, getValue = null, setValue = null, } = {}) { let val = getValue ? getValue(key) : localStorage.getItem(key); null == val && ((val = base), setValue ? setValue(key, base) : localStorage.setItem(key, base)), isChangeTxt && (txt = txt.replace("base", base).replace("current", val)); let newVal = prompt(txt, val); return ( null !== newVal && (!verification || ((newVal = verification(newVal, val)), null !== newVal)) && newVal !== val && (setValue ? setValue(key, newVal) : localStorage.setItem(key, newVal), !0) ); } const registerMenu_settings = info.settings; function formatDate({ timestamp, isYear = !0, isExact = !1, delimiter = ".", midDelimiter = " ", delimiter2 = ":", } = {}) { if (!timestamp) return -1; const date = new Date(timestamp), year = isYear ? date.getFullYear() : "", month = (date.getMonth() + 1).toString().padStart(2, "0"), day = date.getDate().toString().padStart(2, "0"); let leftTime; leftTime = 3 === delimiter.length ? `${isYear ? year + delimiter[0] : ""}${month}${delimiter[1]}${day}${ delimiter[2] }` : `${isYear ? year + delimiter : ""}${month}${delimiter}${day}`; let rigthTime = ""; if (isExact) { const hour = date.getHours().toString().padStart(2, "0"), minute = date.getMinutes().toString().padStart(2, "0"), second = date.getSeconds().toString().padStart(2, "0"); rigthTime = 3 === delimiter2.length ? `${midDelimiter}${hour}${delimiter2[0]}${minute}${delimiter2[1]}${second}${delimiter2[2]}` : `${midDelimiter}${hour}${delimiter2}${minute}${delimiter2}${second}`; } return leftTime + rigthTime; } let searchBox, searchEndTimerId, msgBox, msgDom, msgId, useOne, msgZIndex, msgTimerId, msgEndTimerId, message_msgBox, message_msgDom, message_msgId, message_useOne, message_msgZIndex, message_msgTimerId, message_msgEndTimerId; function createSearch({ id = "history-search-box", box = document.body, title = "以'标题='开头表示按标题搜索, '内容='表示按内容搜索, '描述='表示按描述搜索, '日期='表示按日期搜索", width = 200, height = 30, color = "#333", bg = "#fff", fontSize = 13, bd = "1px solid #aaa", hover_bdColor = "#cee4ff", pd = "0 8px", radius = 5, transition = 0.5, btnText = "搜索", btn_class = "", btn_fontSize = 13, btn_color = "#65aaff", btn_bg = "#dfedfe", btn_bd = "1px solid #dfedfe", btn_pd = "0 10px", btn_radius = 6, btn_hover = "#65aaff", btn_hover_bg = "#cee4ff", btn_hover_bd = "1px solid #dfedfe", zIndex = 901, placeholder = "请输入搜索的内容", isBtn = !0, isAutoSearch = !0, interval = 500, } = {}) { const ele = document.createElement("div"); (ele.id = id), (ele.isAutoSearch = isAutoSearch), (ele.interval = interval), (ele.transition = transition), (ele.style.cssText = `display: flex;\nopacity: 0;\nposition: absolute;\nleft: -2000px;\ntop: 0;\nz-index: ${zIndex};\ntransition: opacity ${transition}s`); const text_css = `width: ${width}px;\nheight: ${height}px;\nline-height: ${height}px;\ncolor: ${color};\nborder: ${bd};\npadding: ${pd};\nborder-radius: ${radius}px;\noutline: ${hover_bdColor};\nbox-sizing: border-box;`; ele.innerHTML = `<input class="search-text ll-scroll-style-1" style="${text_css}"></input>${ isBtn ? "<div class='search-btn'></div>" : "" }`; const textEle = ele.querySelector(".search-text"); (ele.title = title), (ele.textEle = textEle), (textEle.placeholder = placeholder), (textEle.style.fontSize = fontSize + "px"), (textEle.style.background = bg), (textEle.style.fontFamily = "math"); const btnEle = ele.querySelector(".search-btn"); return ( btnEle && ((btnEle.style.cssText = `height: ${height}px;\nline-height: ${height}px;\nfont-size: ${btn_fontSize}px;\ncolor: ${btn_color};\nbackground: ${btn_bg};\nborder: ${btn_bd};\npadding: ${btn_pd};\nborder-radius: ${btn_radius}px;\nbox-sizing: border-box;\nwhite-space: nowrap;\nfont-family: math;\ncursor:pointer;`), (btnEle.className += " " + btn_class), (btnEle.innerHTML = btnText), (btnEle.style.fontSize = btn_fontSize), (btnEle.style.color = btn_color), (btnEle.style.fontSize = fontSize + "px"), (ele.btnEle = btnEle), btnEle.addEventListener("mouseenter", () => { (btnEle.style.color = btn_hover), (btnEle.style.background = btn_hover_bg), (btnEle.style.border = btn_hover_bd); }), btnEle.addEventListener("mouseleave", () => { (btnEle.style.color = btn_color), (btnEle.style.background = btn_bg), (btnEle.style.border = btn_bd); })), box.appendChild(ele), (function bindSearchEvents(ele) { const inputEle = ele.textEle, searchBtn = ele.btnEle; let timerId; searchBtn.addEventListener("click", () => { searchEle(); }), inputEle.addEventListener("keydown", (e) => { (13 !== e.keyCode && "enter" !== e.key.toLowerCase()) || 0 == +ele.style.opacity || searchEle(); }), inputEle.addEventListener("input", () => { ele.isAutoSearch && (clearTimeout(timerId), (timerId = setTimeout(() => { searchEle(); }, ele.interval))); }); })(ele), (searchBox = ele), ele ); } function showSearchBox(isShow = !0, originEle = null) { const ele = searchBox; if (isShow) { let left, top, scrollTop; if ((clearTimeout(searchEndTimerId), originEle)) { const rect = originEle.getBoundingClientRect(); (left = rect.left), (top = rect.top), (scrollTop = document.documentElement.scrollTop); } const h = parseInt(ele.textEle.style.height); left && top ? ((ele.style.left = left + "px"), (ele.style.top = top + scrollTop - h - 12 + "px")) : ((ele.style.left = ""), (ele.style.right = "12px"), (ele.style.top = "12px")), (ele.style.opacity = 1); } else (ele.style.opacity = 0), clearTimeout(searchEndTimerId), (searchEndTimerId = setTimeout(() => { ele.style.left = "-2000px"; }, 1e3 * ele.transition)), hidcenEle(ele.listEle, ""); } function hidcenEle(listEle, text, searchType = "标题") { if (!listEle) return; "时间" === searchType && (searchType = "日期"), text && console.log("搜索" + searchType + ": " + text); const liArr = listEle.querySelectorAll(".item-box"), len = liArr.length; for (let i = 0; i < len; i++) { const item = liArr[i]; text ? ("标题" === searchType && item.querySelector(".item-tt").innerText.includes(text)) || ("描述" === searchType && item.querySelector(".item-tt").title.includes(text)) || ("内容" === searchType && item.querySelector(".hItem").innerText.includes(text)) || ("日期" === searchType && item.querySelector(".item-control").title.includes(text)) ? (item.style.display = "block") : (item.style.display = "none") : (item.style.display = "block"); } } function searchEle() { const textEle = searchBox.textEle, listEle = searchBox.listEle; if (!listEle) return; let text = textEle.value, searchType = text.slice(0, 3); ["标题=", "描述=", "内容=", "日期=", "时间="].includes(searchType) ? ((searchType = searchType.slice(0, 2)), (text = text.slice(3, text.length))) : (searchType = textEle.searchType ? textEle.searchType : "标题"), hidcenEle(listEle, text, searchType); } function message({ ele, title = "", content = "", msg = "", color, fontSize, tt_color, tt_fontSize, bg, bd, pd, radius, time = "auto", disTime = 0, postion = "right-top", fn, } = {}) { useOne && (msgDom = null), ele || (ele = msgDom) || (msgId && !useOne && (ele = msgDom = document.querySelector("#" + msgId)), ele || (ele = msgDom = (function createMsg({ id = "ll-autoCloseMsg", box = document.body, isUseOne = !0, maxWidth = 224, color = "#666", fontSize = 14, tt_color = "#333", tt_fontSize = 16, bg = "#fff", bd = "2px solid #dfedfe", pd = "7px 12px", radius = 7, zIndex = 1100, transition = 0.8, } = {}) { const ele = document.createElement("div"); (ele.id = id), (ele.className = id), (msgId = id), (ele.style.cssText = `max-width: ${maxWidth}px;\nbackground: ${bg};\nmargin-bottom: 10px;\nborder: ${bd};\npadding: ${pd};\nbox-sizing: border-box;\nborder-radius: ${radius}px;\nopacity: 0;\ntransition: opacity ${transition}s;\nletter-spacing: 1px;`), (ele.innerHTML = '<div class="title" style="margin-bottom:5px;font-weight:bold;"></div><div class="msg"></div>'), (ele.transition = transition); const ttEle = ele.querySelector(".title"); (ele.ttEle = ttEle), (ttEle.style.color = tt_color), (ttEle.style.fontSize = tt_fontSize + "px"); const msgEle = ele.querySelector(".msg"); return ( (ele.msgEle = msgEle), (msgEle.style.color = color), (msgEle.style.fontSize = fontSize + "px"), (useOne = isUseOne), (ele.isUseOne = isUseOne), (msgDom = ele), msgBox || ((msgBox = document.createElement("div")), (msgBox.style.cssText = `\ndisplay: flex;\nflex-direction: column;\nposition: fixed;\nleft: -2000px;\ntop: 0;\nz-index: ${ isUseOne ? msgZIndex : zIndex };`), box.appendChild(msgBox)), msgBox.appendChild(ele), ele ); })())), (msg = content || msg); const msgEle = ele.msgEle; (msgEle.innerText = msg), bd && (ele.style.border = bd), pd && (ele.style.padding = pd), bg && (ele.style.background = bg), radius && (ele.style.borderRadius = radius + "px"), color && (msgEle.style.color = color), fontSize && (msgEle.style.fontSize = fontSize + "px"), (msgBox.style.left = ""); const placeArr = postion.split(/-|_/); if ( ((msgBox.style[placeArr[0]] = placeArr[0] ? "12px" : ""), (msgBox.style[placeArr[1]] = placeArr[1] ? "12px" : ""), title) ) { const ttEle = ele.ttEle; (ttEle.innerHTML = title), tt_color && (ttEle.style.color = tt_color), tt_fontSize && (ttEle.style.fontSize = tt_fontSize + "px"); } "auto" === time ? (time = (function getShowTime(text) { return 410 * text.length + 1500; })(msg)) : (time *= 1e3), (time += disTime), useOne || (clearTimeout(msgTimerId), clearTimeout(msgEndTimerId)), (ele.style.opacity = 1), (msgTimerId = setTimeout(() => { (ele.style.opacity = 0), (msgEndTimerId = setTimeout(() => { (msgBox.style.left = -ele.maxWidth - 100 + "px"), fn && fn(), useOne && ele.remove(); }, 1e3 * ele.transition)); }, time)); } function message_message({ ele, title = "", content = "", msg = "", color, fontSize, tt_color, tt_fontSize, bg, bd, pd, radius, time = "auto", disTime = 0, postion = "right-top", fn, } = {}) { message_useOne && (message_msgDom = null), ele || (ele = message_msgDom) || (message_msgId && !message_useOne && (ele = message_msgDom = document.querySelector("#" + message_msgId)), ele || (ele = message_msgDom = (function message_createMsg({ id = "ll-autoCloseMsg", box = document.body, isUseOne = !0, maxWidth = 224, color = "#666", fontSize = 14, tt_color = "#333", tt_fontSize = 16, bg = "#fff", bd = "2px solid #dfedfe", pd = "7px 12px", radius = 7, zIndex = 1100, transition = 0.8, } = {}) { const ele = document.createElement("div"); (ele.id = id), (ele.className = id), (message_msgId = id), (ele.style.cssText = `max-width: ${maxWidth}px;\nbackground: ${bg};\nmargin-bottom: 10px;\nborder: ${bd};\npadding: ${pd};\nbox-sizing: border-box;\nborder-radius: ${radius}px;\nopacity: 0;\ntransition: opacity ${transition}s;\nletter-spacing: 1px;`), (ele.innerHTML = '<div class="title" style="margin-bottom:5px;font-weight:bold;"></div><div class="msg"></div>'), (ele.transition = transition); const ttEle = ele.querySelector(".title"); (ele.ttEle = ttEle), (ttEle.style.color = tt_color), (ttEle.style.fontSize = tt_fontSize + "px"); const msgEle = ele.querySelector(".msg"); return ( (ele.msgEle = msgEle), (msgEle.style.color = color), (msgEle.style.fontSize = fontSize + "px"), (message_useOne = isUseOne), (ele.isUseOne = isUseOne), (message_msgDom = ele), message_msgBox || ((message_msgBox = document.createElement("div")), (message_msgBox.style.cssText = `\ndisplay: flex;\nflex-direction: column;\nposition: fixed;\nleft: -2000px;\ntop: 0;\nz-index: ${ isUseOne ? message_msgZIndex : zIndex };`), box.appendChild(message_msgBox)), message_msgBox.appendChild(ele), ele ); })())), (msg = content || msg); const msgEle = ele.msgEle; (msgEle.innerText = msg), bd && (ele.style.border = bd), pd && (ele.style.padding = pd), bg && (ele.style.background = bg), radius && (ele.style.borderRadius = radius + "px"), color && (msgEle.style.color = color), fontSize && (msgEle.style.fontSize = fontSize + "px"), (message_msgBox.style.left = ""); const placeArr = postion.split(/-|_/); if ( ((message_msgBox.style[placeArr[0]] = placeArr[0] ? "12px" : ""), (message_msgBox.style[placeArr[1]] = placeArr[1] ? "12px" : ""), title) ) { const ttEle = ele.ttEle; (ttEle.innerHTML = title), tt_color && (ttEle.style.color = tt_color), tt_fontSize && (ttEle.style.fontSize = tt_fontSize + "px"); } "auto" === time ? (time = (function message_getShowTime(text) { return 410 * text.length + 1500; })(msg)) : (time *= 1e3), (time += disTime), message_useOne || (clearTimeout(message_msgTimerId), clearTimeout(message_msgEndTimerId)), (ele.style.opacity = 1), (message_msgTimerId = setTimeout(() => { (ele.style.opacity = 0), (message_msgEndTimerId = setTimeout(() => { (message_msgBox.style.left = -ele.maxWidth - 100 + "px"), fn && fn(), message_useOne && ele.remove(); }, 1e3 * ele.transition)); }, time)); } function createEle({ className = "", id = "", title = "", css, box = document.body, type = "div", } = {}) { const ele = document.createElement(type); return ( id && (ele.id = id), className && (ele.className = className), title && (ele.title = title), css && (ele.style.cssText = css), box.appendChild(ele), ele ); } const edit = { isEditing: !1, editText: {}, eleList: {}, callback: { confirmBefore: null, finished: null }, }, eleList = edit.eleList; function showEditArea(isShow = !0) { (edit.isEditing = isShow), (eleList.wrap.style.display = isShow ? "block" : "none"); } function clearEditData() { (eleList.title.value = ""), (eleList.desc.value = ""), (eleList.value.value = ""); } function changeShow(controlObj, isShow = "") { for (let key in controlObj) { const curStyle = controlObj[key].style; curStyle.display = "" === isShow ? "none" === curStyle.display ? "block" : "none" : isShow ? "block" : "none"; } } function showItemControlEvent(control, info) { const listEle = info.listEle, moveBox = control.eleList.move_control; changeShow(control.move_eleList, !1), listEle.addEventListener("click", (e) => { const item = e.target; if (item.classList.contains("hItem")) { if ( (item === listEle.curClickEle ? changeShow(control.move_eleList) : changeShow(control.move_eleList, !0), (moveBox.style.top = item.offsetTop - control.cfg.move_height - 3 + "px"), (listEle.oldClickEle = listEle.curClickEle), (listEle.curClickEle = item), (listEle.curId = item.id), control.info.move && control.info.move.isMoving && item !== listEle.oldClickEle) ) { const move = control.info.move; (!move.warnText || confirm(move.warnText)) && (!(function moveItem({ info, ele, toEle, id, toId } = {}) { const listEle = info.listEle; !ele && id ? (ele = listEle.querySelector(`[id='${id}'`)) : ele || id || (ele = listEle.oldClickEle); !toEle && toId ? (toEle = listEle.querySelector(`[id='${id}'`)) : toEle || toId || (toEle = listEle.curClickEle); !id && (id = +ele.id), !toId && (toId = +toEle.id); const list_info = listEle.list_info, newDataList = updateDataList(info), dataList = info.dataList, index = dataList.map((item) => +item.id).indexOf(id); if (-1 === index) return ( console.log("操作失败, 当前项的数据可能在其他页面中已删除"), void message({ title: "移动", msg: info.listEle.list_info.errorSyncText, }) ); const data = dataList.splice(index, 1)[0]; let toIndex = dataList.map((item) => +item.id).indexOf(toId); list_info.isAddUp && (toIndex += 1), dataList.splice(toIndex, 0, data), newDataList ? initHisListDom(info) : (listEle.insertBefore( ele.parentElement, toEle.parentElement ), resetNum(listEle)); (ele = toEle = null), list_info.setValue ? list_info.setValue( list_info.saveName, JSON.stringify(dataList) ) : localStorage.setItem( list_info.saveName, JSON.stringify(dataList) ); })({ info }), message({ title: move.text, msg: move.endText }), changeShow(control.move_eleList, !1)), (move.isMoving = !1); } if ( control.info.changePlace && control.info.changePlace.isChangePlaceing && item !== listEle.oldClickEle ) { const changeP = control.info.changePlace; (!changeP.warnText || confirm(changeP.warnText)) && (!(function changePlace({ info, ele, toEle, id, toId } = {}) { const listEle = info.listEle; !ele && id ? (ele = listEle.querySelector(`[id='${id}'`)) : ele || (ele = listEle.oldClickEle); !toEle && toId ? (toEle = listEle.querySelector(`[id='${id}'`)) : toEle || (toEle = listEle.curClickEle); if ( (!id && (id = +ele.id), !toId && (toId = +toEle.id), ele && toEle) ) { const eleData = getItemData({ info, ele }), toEleData = getItemData({ info, ele: toEle }); if (!eleData || !toEleData) return void console.log("数据获取失败"); toEleData.id = 1234; const changeInfo = updateItem({ info, ele, data: toEleData, isSave: !1, }); updateItem({ info, ele: toEle, data: eleData, isSave: !1 }), (info.dataList[changeInfo.index].id = toId), (changeInfo.ele.id = toId), resetNum(listEle); const list_info = listEle.list_info; list_info.setValue ? list_info.setValue( list_info.saveName, JSON.stringify(info.dataList) ) : localStorage.setItem( list_info.saveName, JSON.stringify(info.dataList) ); } })({ info }), message({ title: move.text, msg: move.endText }), changeShow(control.move_eleList, !1)), (changeP.isChangePlaceing = !1); } } e.stopPropagation(); }); } function controlEvents(control, info, searchEle, editInfo) { if (!control) return; const listEle = info.listEle, control_info = control.info; if ( (showItemControlEvent(control, info), control_info.add && control_info.add.ele.addEventListener("click", (e) => { showEditArea(), (editInfo.msg = { noneText: control_info.add.noneText }), (editInfo.callback.finished = (data) => { addItem({ title: data.title, desc: data.desc, value: data.value, info, }), message({ title: control_info.add.text, msg: control_info.add.endText, }); }), e.stopPropagation(); }), control_info.clear && control_info.clear.ele.addEventListener("click", (e) => { if (confirm(control_info.clear.warnText)) { confirm(control_info.clear.twoWarnText) && (!(function clearList(info) { (info.listEle.innerHTML = ""), (info.dataList = []), bottomText(info); const list_info = info.listEle.list_info; list_info.setValue ? list_info.setValue(list_info.saveName, "[]") : localStorage.removeItem(list_info.saveName); })(info), changeShow(control.move_eleList, !1)); } e.stopPropagation(); }), control_info.search) ) { const search = control_info.search; (search.eleList = {}), search.ele.addEventListener("click", (e) => { let isShow = 0 == +searchEle.style.opacity; listEle !== searchEle.listEle && (isShow = !0), isShow && message({ title: search.text, msg: search.title }), (searchEle.textEle.value = ""), (searchEle.listEle = listEle), (searchEle.textEle.searchType = search.searchType), showSearchBox(isShow, search.ele), e.stopPropagation(); }); const inputEle = searchEle.textEle; searchEle.btnEle.addEventListener("click", () => { changeShow(control.move_eleList, !1); }), inputEle.addEventListener("keydown", (e) => { 13 === e.keyCode && 0 != +searchEle.style.opacity && changeShow(control.move_eleList, !1); }), inputEle.addEventListener("input", () => { searchEle.isAutoSearch && changeShow(control.move_eleList, !1); }); } if (control_info.import) { const uploadFile = control_info.import; uploadFile.ele.addEventListener("click", (e) => { if (uploadFile.isUploading) return ( message({ title: uploadFile.text, msg: uploadFile.uploadingText }), void console.log(uploadFile.uploadingText) ); message({ title: uploadFile.text, msg: uploadFile.startTipText }), (function fileUpload_fileUpload({ uploadObj, startTt = "上传", startText = "开始上传", endTt = "上传", endText = "上传完成", errorTt = "文件上传", errorMsg = "上传失败", startFn, finishFn, errorFn, timeoutFn, } = {}) { let input = document.createElement("input"); (input.type = "file"), input.click(), input.addEventListener("change", (e) => { startText && message_message({ title: startTt, msg: startText }); const fileObj = e.target.files[0], reader = new FileReader(); reader.readAsText(fileObj); const data = { info: fileObj, data: {} }; (startFn && null === startFn(data)) || (uploadObj.timer && clearTimeout(uploadObj.timer), (uploadObj.timer = setTimeout(() => { uploadObj && uploadObj.isUploading && (timeoutFn && timeoutFn(), message_message({ title: errorTt, msg: "'" + fileObj.name + "'" + errorMsg, }), console.log("文件上传超时")); }, 12e4)), (reader.onload = function (readRes) { try { data.data = readRes.target.result; const msg = "'" + fileObj.name + "'" + endText; endText && message_message({ title: endTt, msg }), console.log("上传成功: ", data.data), finishFn && finishFn(data); } catch (e) { errorFn && errorFn(data), message_message({ title: errorTt, msg: "'" + fileObj.name + "'" + errorMsg, }); } finally { clearTimeout(uploadObj.timer); } }), (reader.onerror = (e) => { (data.data = e), errorFn && errorFn(data), message_message({ title: errorTt, msg: "'" + fileObj.name + "'" + errorMsg, }), console.log(e), clearTimeout(uploadObj.timer); })); }), input.remove(); })({ uploadObj: uploadFile, startTt: uploadFile.text, startText: "开始上传", endTt: uploadFile.text, endText: "上传完成", errorTt: uploadFile.text, errorMsg: "数据导入失败", startFn: () => { uploadFile.isUploading = !0; }, finishFn: (data) => { uploadFile.isUploading = !1; if (!confirm(uploadFile.submitText)) return; info.dataList = JSON.parse(data.data || null) || []; const list_info = listEle.list_info; list_info.setValue ? list_info.setValue( list_info.saveName, JSON.stringify(info.dataList) ) : localStorage.setItem( list_info.saveName, JSON.stringify(info.dataList) ), initHisListDom(info), message({ title: uploadFile.text, msg: uploadFile.endText }), console.log(uploadFile.endText); }, errorFn: () => { uploadFile.isUploading = !1; }, timeoutFn: () => { uploadFile.isUploading = !1; }, }), e.stopPropagation(); }); } if (control_info.out) { const outFile = control_info.out; outFile.ele.addEventListener("click", (e) => { let outName = listEle.list_info.outName || listEle.list_info.saveName || "dataList"; outFile.isTime && (outName = formatDate({ timestamp: new Date().getTime(), isExact: !0, midDelimiter: "-", delimiter2: ".", }) + " " + outName); updateDataList(info) && initHisListDom(info), (function saveJson({ data = "", fileName = "outData", type = "json", } = {}) { "string" != typeof data && "json" === type && (data = JSON.stringify(data)); const blob = new Blob( [data], "json" === type ? { type: "application/json" } : { type: "text/plain" } ), href = URL.createObjectURL(blob), alink = document.createElement("a"); (alink.style.display = "none"), (fileName += "." + type), (alink.download = fileName), (alink.href = href), document.body.appendChild(alink), alink.click(), document.body.removeChild(alink), URL.revokeObjectURL(href); })({ data: info.dataList, fileName: outName }), message({ title: outFile.text, msg: outFile.startText }), e.stopPropagation(); }); } if ((control_info.skip, control_info.fold)) { function setLineH( isFold = null, listEle = info.listEle, fold = control.info.fold ) { fold.ele.innerText = fold.isFold ? fold.noFoldText : fold.text; const textArr = listEle.querySelectorAll(".hItem"), len = textArr.length; let newH = fold.isFold ? fold.maxHeight : fold.oldMaxH; null !== isFold && ((newH = isFold ? fold.maxHeight : fold.oldMaxH), (fold.isFold = isFold)), (listEle.list_info.liMaxHeight = newH), (newH += "px"), (listEle.display = "none"); for (let i = 0; i < len; i++) { textArr[i].style.maxHeight = newH; } listEle.display = "block"; } const fold = control_info.fold, list_info = listEle.list_info; let isFold; (fold.oldMaxH = list_info.liMaxHeight), (isFold = list_info.getValue ? list_info.getValue(listEle.list_info.list_id + "_" + fold.name) : localStorage.getItem(listEle.list_info.list_id + "_" + fold.name)), (fold.isFold = null != isFold && JSON.parse(isFold)), setLineH(), fold.ele.addEventListener("click", (e) => { (fold.isFold = !fold.isFold), setLineH(), list_info.setValue ? list_info.setValue( list_info.list_id + "_" + fold.name, JSON.stringify(fold.isFold) ) : localStorage.setItem( list_info.list_id + "_" + fold.name, JSON.stringify(fold.isFold) ), bottomText(info), changeShow(control.move_eleList, !1), e.stopPropagation(); }); } if (control_info.delete) { const del = control_info.delete; del.ele.addEventListener("click", (e) => { confirm(del.warnText) && (!(function delItem({ info, id, ele } = {}) { const newDataList = updateDataList(info), listEle = info.listEle, dataList = info.dataList; if (!id && !ele && !(ele = listEle.curClickEle)) return; ele ? (id = ele.id) : (ele = listEle.querySelector(`[id='${id}'`)); const len = dataList.length; for (let i = 0; i < len; i++) if (+dataList[i].id == +id) { const del = dataList.splice(i, 1); console.log("删除一项", del[0]); break; } newDataList ? initHisListDom(info) : (ele.parentElement.remove(), resetNum(listEle), bottomText(info)); const list_info = listEle.list_info; list_info.setValue ? list_info.setValue(list_info.saveName, JSON.stringify(dataList)) : localStorage.setItem( list_info.saveName, JSON.stringify(dataList) ); })({ info }), message({ title: del.text, msg: del.endText }), changeShow(control.move_eleList, !1)), e.stopPropagation(); }); } if (control_info.update) { const update = control_info.update; update.ele.addEventListener("click", (e) => { editInfo.msg = { noneText: control_info.add.noneText }; const itemData = getItemData({ info, ele: info.listEle.curClickEle }); itemData ? (!(function inputEditData({ title = "", desc = "", value = "", data = {}, } = {}) { (eleList.title.value = data.title || title), (eleList.desc.value = data.desc || desc), (eleList.value.value = data.value || value); })(itemData), (editInfo.callback.finished = (data) => { (data.id = new Date().getTime()), updateItem({ info, data }), message({ title: update.text, msg: update.endText }), changeShow(control.move_eleList, !1); }), showEditArea(!0), e.stopPropagation()) : console.log("未获取到当前修改项的数据"); }); } if (control_info.move) { const move = control_info.move; move.ele.addEventListener("click", (e) => { if (!move.isMoving) return ( (move.isMoving = !0), void message({ title: move.text, msg: move.tipText + "\n请在提示存在期间完成该操作", fn: () => { move.isMoving = !1; }, }) ); message({ title: move.text, msg: "已取消" + move.text + "操作" }), (move.isMoving = !1), e.stopPropagation(); }); } if (control_info.changePlace) { const changeP = control_info.changePlace; changeP.ele.addEventListener("click", (e) => { if (!changeP.isChangePlaceing) return ( (changeP.isChangePlaceing = !0), void message({ title: changeP.text, msg: changeP.tipText + "\n请在提示存在期间完成该操作", fn: () => { changeP.isChangePlaceing = !1; }, }) ); message({ title: changeP.text, msg: "已取消" + changeP.text + "操作" }), (changeP.isChangePlaceing = !1), e.stopPropagation(); }); } if ((control_info.desc, control_info.toSuki)) { const toSuki = control_info.toSuki; toSuki.ele.addEventListener("click", (e) => { !(function itemToSuki({ info, ele, id } = {}) { if (!id && !ele && !(ele = info.listEle.curClickEle)) return; let data = getItemData({ info, ele, id }); if (!data) return ( console.log(info.listEle.list_info.control.info.toSuki.errorText), void message({ title: "收藏", msg: info.listEle.list_info.control.info.toSuki.errorText, }) ); if (info.callback && info.callback.toSuki) { let newData; const func = info.callback.toSuki; Array.isArray(func) ? func.curFn ? ((newData = func[curFn](data)), (func.curFn = null)) : func.forEach((fn) => { newData = fn(data); }) : (newData = func(data)), (data = newData || data); } addItem({ info: info.suki_info, data }); })({ info }), message({ title: toSuki.text, msg: toSuki.endText }), e.stopPropagation(); }); } control_info.copy && control_info.copy.ele.addEventListener("click", (e) => { !(function copyText(text) { if (window.clipboardData) window.clipboardData.clearData(), window.clipboardData.setData("text", text); else if (document.execCommand) { var ele = document.createElement("SPAN"); if ( ((ele.textContent = text), document.body.appendChild(ele), document.selection) ) (range = document.body.createTextRange()).moveToElementText(ele), range.select(); else if (window.getSelection) { var range; (range = document.createRange()).selectNode(ele), window.getSelection().removeAllRanges(), window.getSelection().addRange(range); } document.execCommand("copy"), ele.remove ? ele.remove() : ele.removeNode(!0); } })(listEle.curClickEle.innerText), message({ title: control_info.copy.text, msg: control_info.copy.endText, }), e.stopPropagation(); }), control_info.toBottom && control_info.toBottom.ele.addEventListener("click", (e) => { (info.listEle.parentElement.scrollTop = info.listEle.parentElement.scrollHeight), e.stopPropagation(); }); } function getValue_getValue({ base = null, key, valType = "string", isReSet = !0, getVal, setVal, } = {}) { let val = getVal ? getVal(key) : localStorage.getItem(key); return ( null !== base && null == val && ((val = base), isReSet && (setVal ? setVal(key, val) : localStorage.setItem(key, val))), "string" === valType ? val : "boolean" === valType || "number" === valType ? JSON.parse(val) : "object" === valType ? JSON.parse(val || {}) : "array" === valType ? JSON.parse(val || []) : val ); } function setBtnColor(listEle, btnEle, isClicked = "") { if (!listEle && !btnEle) return; let transformText; const btn_info = btnEle.btn_info; btn_info.isChangeColor && ("" === isClicked && ((transformText = listEle.parentElement.style.transform), (isClicked = "scaleY(1)" === transformText), (btnEle.isClicked = isClicked)), isClicked ? isClicked && ((btnEle.style.color = btn_info.click), (btnEle.style.background = btn_info.click_bg), (btnEle.style.borderColor = btn_info.click_bd), btn_info.isSvg && btnEle.children[0] && (btnEle.children[0].style.fill = btn_info.click)) : btnEle.isHover ? ((btnEle.style.color = btn_info.hover), (btnEle.style.background = btn_info.hover_bg), btn_info.bd && (btnEle.style.border = btn_info.hover_bd), btn_info.isSvg && btnEle.children[0] && (btnEle.children[0].style.fill = btn_info.hover)) : ((btnEle.style.color = btn_info.color), (btnEle.style.background = btn_info.bg), btn_info.bd && (btnEle.style.border = btn_info.bd), btn_info.isSvg && btnEle.children[0] && (btnEle.children[0].style.fill = btn_info.color))); } function getTitle({ text, isGetTt = !1, maxLen, addText = "..." } = {}) { if (!text) return ""; let title = text, isZs = !1, isEnd_l = !1; if (isGetTt) { "\n" === text[0] && (text = text.slice(1, text.length)); title = text.split(/(?<=[|\n\r])/)[0].trim(); } return ( "/" === title[0] && "/" === title[1] && "|" === title[title.length - 1] && ((title = title.slice(2, title.length - 1).trim()), (isZs = !0)), "\n\r".includes(title[title.length - 1]) && (title = title.slice(0, title.length - 1)), (title = title.replaceAll("\n", " ").replaceAll("\r", " ")), maxLen && title.length >= maxLen && (title = title.slice(0, maxLen) + addText), "|" === title[title.length - 1] && ((title = title.slice(0, title.length - 1).trim()), (isEnd_l = !0)), title.length < 8 && !isZs && !isEnd_l && (title = text .trim() .replaceAll("\n", " ") .replaceAll("\r", " ") .slice(0, 8)), title ); } function getNum(isDesc, isAddUp, len, index) { return (isDesc && !isAddUp) || (!isDesc && isAddUp) ? len - index : index + 1; } function resetNum(listEle, liArr = []) { 0 === liArr.length && (liArr = listEle.getElementsByClassName("item-box")); const len = liArr.length; for (let i = 0; i < len; i++) liArr[i].querySelector(".num").innerHTML = getNum( listEle.list_info.isDesc, !1, len, i ); } function bottomText(info) { const listEle = info.listEle, dataList = info.dataList, list_info = listEle.list_info; let bt_box = listEle.querySelector(".bottom_text"); if (bt_box) { let text = list_info.bottomText; if (!text) return; let isAdd = 50 * dataList.length > list_info.maxHeight - 5; isAdd || (isAdd = listEle.offsetHeight + list_info.control.offsetHeight >= list_info.maxHeight - 5), isAdd ? (bt_box.innerText = text) : bt_box && ((text = list_info.initialText), 0 === dataList.length ? (bt_box.innerHTML = text) : bt_box.remove()); } else if (0 === dataList.length) { const text = list_info.initialText; text && (listEle.innerHTML = `<div class="bottom_text" title="${list_info.bottomTT}">${text}</div>`); } else { const text = list_info.bottomText; if (!text) return; let isAdd = 50 * dataList.length > list_info.maxHeight - 5; isAdd || (isAdd = listEle.offsetHeight + list_info.control.offsetHeight >= list_info.maxHeight - 5), isAdd && ((bt_box = document.createElement("div")), (bt_box.className = "bottom_text"), (bt_box.title = list_info.bottomTT), (bt_box.innerText = text), listEle.appendChild(bt_box)); } } function hiddenBtnList(info, name = "") { "btn" === name ? (info.btnEle.style.display = "none") : ("list" === name || ("显示" !== info.btnEle.btn_info.showMode && (info.btnEle.style.display = "none")), (info.listEle.parentElement.style.transform = "scaleY(0)")), (info.btnEle.style.borderColor = "#ccc"), setBtnColor(info.listEle, info.btnEle), showSearchBox(!1); } function initHisListDom(info) { const listEle = info.listEle; let curContent, dataList = info.dataList; listEle.innerHTML = ""; let curHtml = ""; const list_info = listEle.list_info; dataList || (console.log("本地读取数据"), list_info.getValue ? (info.dataList = JSON.parse(list_info.getValue(list_info.saveName) || null) || []) : (info.dataList = JSON.parse(localStorage.getItem(list_info.saveName) || null) || [])); const maxLen = list_info.maxLen; list_info.isDelete && dataList.length > maxLen && dataList.splice(0, dataList.length - maxLen); const isDesc = list_info.isDesc, isAddUp = list_info.isAddUp; let htmlItem; const len = dataList.length, liMaxHeight = list_info.liMaxHeight, num_color = list_info.num_color, tt_color = list_info.tt_color; dataList.forEach((item, i) => { (curContent = item.value.replaceAll("\n", "<br>")), (htmlItem = `<div class="item-box"><div class="item-control" title="${formatDate( { timestamp: item.id || new Date().getTime(), isExact: !0, delimiter2: "时分秒", } )}" style="color:${num_color}"><span class="num">${getNum( isDesc, isAddUp, len, i )}</span> <span title="${ item.desc }" class="item-tt" style="color:${tt_color}">${ item.title || "" }</span></div><div id="${ item.id }" class="hItem" style="max-height:${liMaxHeight}px">${curContent}</div></div>`), isAddUp ? (curHtml = htmlItem + curHtml) : (curHtml += htmlItem); }), (listEle.innerHTML = curHtml), bottomText(info), (info.updateDate = new Date().getTime()); } function addItem({ info, title = "", desc = "", value, id, data, isUpdateDom = !0, } = {}) { if (!value && !data) return -1; updateDataList(info) && initHisListDom(info); const listEle = info.listEle, dataList = info.dataList; let deleteId, curItem, isOverLenDel = !1; if ( (data ? ((value = data.value), (title = data.title || ""), (desc = data.desc || ""), (data.title = title), (data.desc = desc), (id = data.id || new Date().getTime()), (curItem = { ...data }), (curItem.id = id)) : (curItem = { value, id: id || new Date().getTime(), desc }), !curItem.value) ) return -1; console.log("添加一项", curItem), (curItem.title = getTitle({ text: title || curItem.value, isGetTt: !0 })); const list_info = listEle.list_info; if (list_info.isDelRepeat) for (let i = 0; i < dataList.length; i++) { const cur = dataList[i]; if ( cur.value === value && (!list_info.isDataStrict || (cur.title === curItem.title && cur.desc === desc)) ) { (deleteId = cur.id), dataList.splice(i, 1); break; } } if ( (dataList.push(curItem), list_info.isDelete && dataList.length > list_info.maxLen && (dataList.shift(), (isOverLenDel = !0)), list_info.setValue ? list_info.setValue(list_info.saveName, JSON.stringify(dataList)) : localStorage.setItem(list_info.saveName, JSON.stringify(dataList)), isUpdateDom) ) { let liArr; (deleteId || isOverLenDel) && (liArr = listEle.getElementsByClassName("item-box")), deleteId && listEle.querySelector(`[id='${deleteId}'`).parentElement.remove(), isOverLenDel && liArr[liArr.length - 1].remove(), (function addLi(info, item) { if (!item.value) return; const listEle = info.listEle, dataList = info.dataList, list_info = listEle.list_info, content = item.value.replaceAll("\n", "<br>"), hItem = document.createElement("div"); (hItem.className = "item-box"), (hItem.innerHTML = `<div class="item-control" title="${formatDate({ timestamp: item.id || new Date().getTime(), isExact: !0, delimiter2: "时分秒", })}" style="color:${ list_info.tt_color };"><span class="num">${getNum( list_info.isDesc, list_info.isAddUp, dataList.length, dataList.length - 1 )}</span> <span title="${item.desc}" class="item-tt" style="color:${ list_info.tt_color }">${item.title || ""}</span></div><div id="${ item.id }" class="hItem" style="max-height:${ list_info.liMaxHeight }px">${content}</div>`), list_info.isAddUp ? listEle.insertBefore(hItem, listEle.children[0]) : listEle.querySelector(".bottom_text") ? listEle.insertBefore( hItem, listEle.children[listEle.children.length - 1] ) : listEle.appendChild(hItem); resetNum(listEle), bottomText(info); })(info, curItem); } return { deleteId, isOverLenDel }; } function getItemData({ info, id, ele } = {}) { if ( (updateDataList(info) && initHisListDom(info), !id && !ele && !(ele = info.listEle.curClickEle)) ) return; ele && (id = +ele.id); const data = info.dataList.find((i) => +i.id == +id); return data ? { ...data } : (console.log("操作失败, 当前项的数据可能在其他页面中已删除"), null); } function updateItem({ info, id, ele, newId, title = "", desc = "", value = "", data = {}, isSave = !0, } = {}) { if (!id && !ele && !(ele = info.listEle.curClickEle)) return; data ? ((newId = +data.id), (title = data.title || ""), (desc = data.desc || ""), (value = data.value || "")) : (data = { id, title, desc, value }), ele ? (id = +ele.id) : (ele = info.listEle.querySelector(`[id='${id}'`)); const newDataList = updateDataList(info); newDataList && initHisListDom(info); const dataList = info.dataList; let index; const len = dataList.length; for (let i = 0; i < len; i++) if (+dataList[i].id == +id) { (data.id = dataList[i].id), (dataList[i] = data), newId && (dataList[i].id = +newId), (index = i); break; } if (!newDataList) { const tt = ele.parentElement.querySelector(".item-tt"); (tt.innerHTML = getTitle({ text: title })), (tt.title = desc); const content = value.replaceAll("\n", "<br>"); (ele.innerHTML = content), newId && (ele.id = newId); } if (isSave) { const list_info = info.listEle.list_info; list_info.setValue ? list_info.setValue(list_info.saveName, JSON.stringify(dataList)) : localStorage.setItem(list_info.saveName, JSON.stringify(dataList)); } return { index, ele }; } function updateDataList(info) { if (!info.listEle.list_info.isDataSync) return !1; let curGetValue, curSetValue, list_info = info.listEle.list_info; (curGetValue = list_info.getValue ? list_info.getValue : localStorage.getItem), (curSetValue = list_info.setValue ? list_info.setValue : localStorage.setItem); const time = new Date().getTime(), oldUpdateDate = info.updateDate || time, updateDate = getValue_getValue({ key: list_info.list_id + "_updateDate", base: time, getVal: curGetValue, setVal: curSetValue, }); if (((info.updateDate = updateDate), +updateDate != +oldUpdateDate)) { let dataList = getValue_getValue({ key: list_info.saveName, base: "[]", valType: "array", getVal: curGetValue, setVal: curSetValue, }); return (info.dataList = dataList), dataList; } return !1; } function bindHistoryEvents(info) { const textEle = info.textEle, btnEle = info.btnEle, listEle = info.listEle; let mode = btnEle.btn_info.showMode; if ("显示" !== mode) { let eventName = "click"; "单击" === mode ? (eventName = "click") : "双击" === mode && (eventName = "dblclick"), textEle && textEle.addEventListener(eventName, function historyBtn(e) { if (this !== e.target) return; !(function btnShow(isShow) { (btnEle.style.display = isShow ? "block" : "none"), (listEle.parentElement.style.transform = "scaleY(0)"), isShow || showSearchBox(!1), setBtnColor(listEle, btnEle); })("none" === btnEle.style.display), e && e.stopPropagation(); }); } btnEle.addEventListener("click", function historyList(e) { if ( this !== e.target && "svg" !== e.target.tagName.toLowerCase() && "path" !== e.target.tagName.toLowerCase() ) return; const isClicked = "scaleY(0)" === listEle.parentElement.style.transform; if (((btnEle.isClicked = isClicked), isClicked)) { updateDataList(info) && initHisListDom(info); } (listEle.parentElement.style.transform = isClicked ? "scaleY(1)" : "scaleY(0)"), setBtnColor(listEle, btnEle, isClicked), showSearchBox(!1), changeShow(listEle.list_info.control.move_eleList, !1), e && e.stopPropagation(); }), listEle.list_info.isOut && listEle.addEventListener("dblclick", function useHistoryText(e) { const item = e.target; if ("hItem" === item.className) { const clickText = item.innerText; if ( (textEle && ((textEle.value = clickText), listEle.list_info.isExit && (function emitEvent(ele, eventType) { try { if (ele.dispatchEvent) { var evt = new Event(eventType, { bubbles: !1, cancelable: !1, }); ele.dispatchEvent(evt); } else ele.fireEvent && ele.fireEvent("on" + eventType); } catch (e) {} })(textEle, "input")), info.callback && info.callback.clickItem) ) { const itemId = +item.id, data = info.dataList.find((i) => i.id === itemId), func = info.callback.clickItem; Array.isArray(func) ? func.curFn ? (func[curFn](data), (func.curFn = null)) : func.forEach((fn) => { fn(data); }) : func(data); } listEle.list_info.isClickClose && ((listEle.parentElement.style.transform = "scaleY(0)"), setBtnColor(listEle, btnEle), showSearchBox(!1), changeShow(listEle.list_info.control.move_eleList, !1)); } else listEle.parentElement.scrollTop = 0; e.stopPropagation(); }), listEle.addEventListener("click", function toTop(e) { "bottom_text" === e.target.className && (listEle.parentElement.scrollTop = 0); }), listEle.parentElement.addEventListener("dblclick", (e) => { (listEle.parentElement.scrollTop = 0), e.stopPropagation(); }); } const listCss = "\n.ll-history-list {\n scroll-behavior: smooth;\n}\n.ll-history-list .history-list .item-control {\n display: flex;\n gap: 4px;\n height: 25px;\n line-height: 25px;\n font-size: 17px;\n border-bottom: 1px solid #ccc;\n overflow: hidden;\n cursor: default;\n}\n.ll-history-list .history-list .hItem {\n font-size: 13px;\n cursor: pointer;\n padding: 6px 0;\n overflow-y: auto\n}\n.ll-history-list .history-list .item-tt {\n font-size: 13px;\n line-height: 27px;\n white-space: nowrap;\n text-overflow: ellipsis;\n overflow: hidden;\n}\n.ll-history-list .history-list .bottom_text {\n padding: 8px 0;\n text-align: center;\n color: #aaa;\n cursor: pointer;\n}\n", scrollCss = "\n.ll-scroll-style-1::-webkit-scrollbar,\n.ll-scroll-style-1 ::-webkit-scrollbar {\n width: 8px;\n}\n.ll-scroll-1-size-2::-webkit-scrollbar,\n.ll-scroll-style-1 .ll-scroll-1-size-2::-webkit-scrollbar {\n width: 10px;\n}\n.ll-scroll-1-size-3::-webkit-scrollbar,\n.ll-scroll-style-1 .ll-scroll-1-size-3::-webkit-scrollbar {\n width: 12px;\n}\n.ll-scroll-style-1::-webkit-scrollbar-thumb,\n.ll-scroll-style-1 ::-webkit-scrollbar-thumb {\n border-radius: 10px;\n -webkit-box-shadow: inset 0 0 8px rgba(0, 0, 0, 0.05);\n opacity: 0.2;\n background: #daedff;\n}\n.ll-scroll-style-1::-webkit-scrollbar-track,\n.ll-scroll-style-1 ::-webkit-scrollbar-track {\n -webkit-box-shadow: inset 0 0 8px rgba(0, 0, 0, 0.08);\n border-radius: 0;\n background: #fff;\n border-radius: 5px;\n}"; function createSwitchBtn({ box, svg, text = ">", size = 25, lineHeight, top = 1, right = -28, titleText = "显示/隐藏历史记录", className = "", fontSize = 14, fontWeight = 400, zIndex = 900, color = "#65aaff", bg = "#fff", bd = "1px solid #b7cffe", hover = "#65aaff", hover_bg = "#f7fbff", hover_bd = "1px solid #b7cffe", click = "#65aaff", click_bg = "#f7fbff", click_bd = "1px solid #b7cffe", fontFamily = "initial", showMode = "单击", isChangeColor = !0, isPosition = !0, child, } = {}) { if (!box) return; let width = size, height = size; if ("string" == typeof size && size.includes("x")) { const sizeArr = size.split("x"); (width = sizeArr[0]), (height = sizeArr[1]); } const btnEle = document.createElement("div"); (btnEle.innerHTML = svg || text), child && btnEle.appendChild(child), (btnEle.title = titleText), (btnEle.className = className + " ll-history-btn"); const positionCss = isPosition ? `\nposition: absolute;\nz-index: ${zIndex};\ntop: ${top}px;\nright: ${right}px;` : ""; (btnEle.style.cssText = `\n${child ? "display: flex;" : ""}\nmin-width: 10px;\nwidth: ${ "auto" === width ? "auto" : width + "px" };\nheight: ${ "auto" === height ? "auto" : height + "px" };\nline-height: ${ lineHeight || parseInt(height) - 3 }px;\nfont-size: ${fontSize}px;\nfont-weight: ${fontWeight};\ntext-align: center;\ncolor: ${color};\nbackground: ${bg};\n${ bd ? "border:" + bd + ";" : "" }\nborder-radius: 6px;\nbox-sizing: border-box;\ncursor: pointer;\ndisplay: ${ "显示" === showMode ? "block" : "none" };\nfont-family: ${fontFamily};` + positionCss), (btnEle.btn_info = { isSvg: !!svg, showMode, isChangeColor, color, bg, bd, hover, hover_bg, hover_bd, click, click_bg, click_bd, }); const btn_info = btnEle.btn_info; return ( btnEle.addEventListener("mouseenter", () => { btn_info.isChangeColor && ((btnEle.style.color = hover), (btnEle.style.fill = hover), (btnEle.style.background = hover_bg), bd && (btnEle.style.border = hover_bd), (btnEle.isHover = !0), btn_info.isSvg && btnEle.children[0] && (btnEle.children[0].style.fill = btn_info.hover)); }), btnEle.addEventListener("mouseleave", () => { btn_info.isChangeColor && (btnEle.isClicked || ((btnEle.style.color = color), (btnEle.style.fill = color), (btnEle.style.background = bg), bd && (btnEle.style.border = bd), btn_info.isSvg && btnEle.children[0] && (btnEle.children[0].style.fill = btn_info.color)), (btnEle.isHover = !1)); }), box.appendChild(btnEle), btnEle ); } function createHistoryList({ list_id = "SD_list_1", box, width = 350, maxHeight = 500, liMaxHeight = 220, top = 1, right = -382, fontSize = 12, maxLen = 100, title = "双击返回顶部", cssText = "", hoverColor = "#f7fbff", num_color = "#b5d6ff", tt_color = "#b5d6ff", tt_maxLen, saveName = "ll-history-list", outName = "列表数据", controlTitle = "这里是工具栏", listTitle = "双击一条记录即可使用", bottomTT = "点击返回顶部", className = "", initialText = "无历史记录", bottomText = "没有更多的数据了", dataSyncText = "正在同步其他页面的数据, 请稍后再试", syncEndText = "数据同步完成, 请重新操作", errorSyncText = "操作失败, 当前项的数据可能在其他页面中已删除", zIndex = 900, color = "#333", bg = "#fff", bd = "3px solid #dfedfe", pd = "6px 5px 6px 10px", fontFamily = "math", isCenter = !1, isDelete = !0, isDelRepeat = !0, isExit = !1, isOut = !0, isClickClose = !0, isDesc = !0, isAddUp = !0, isDataStrict = !0, isScrollStyle = !0, isDataSync = !1, controlCfg, controlArr = [], setValue, getValue, } = {}) { if (!box) return; "relative" !== box.style.position && "absolute" !== box.style.position && "fixed" !== box.style.position && (box.style.position = "relative"); const hList = document.createElement("div"); (hList.id = list_id || ""), (hList.className = className + " ll-history-list ll-scroll-style-1 ll-scroll-1-size-2"), (hList.title = title), (hList.style.scrollBehavior = "smooth"), (hList.innerHTML = '<div class="list-control"></div><div class="move-control-box"></div><div class="history-list text-list"></div>'); const control = hList.querySelector(".list-control"), moveControlBox = hList.querySelector(".move-control-box"), listEle = hList.querySelector(".text-list"); (control.title = controlTitle), (listEle.title = listTitle); const topEle = document.createElement("div"); (topEle.className = "to-top"), (topEle.innerHTML = "^"), (listEle.list_info = { className, saveName, outName, maxLen, maxHeight, liMaxHeight, num_color, tt_color, tt_maxLen, initialText, bottomText, dataSyncText, syncEndText, errorSyncText, isDelete, isDelRepeat, isExit, isOut, isClickClose, isDesc, isAddUp, isDataStrict, isDataSync, control, bottomTT, list_id, setValue, getValue, }), (control.eleList = { move_control: moveControlBox }), (control.info = {}), (control.style.cssText = "display: flex;\nflex-wrap: wrap;"), (moveControlBox.style.cssText = "display: flex;\nposition: absolute;\nright: 0;\ntop: 0;"), (hList.style.cssText = `width: ${width}px;\nmax-height: ${maxHeight}px;\nline-height: ${ fontSize + 5 }px;\nfont-size: ${fontSize}px;\ncolor: ${color};\nbackground: ${bg};\nposition: absolute;\nz-index: ${zIndex};\ntop: ${top}px;\nright: ${right}px;\nbox-sizing: border-box;\nborder: ${bd};\nborder-radius: 8px;\npadding: ${pd};\noverflow-y: auto;\ntransition: all 0.4s cubic-bezier(0.32, 0.1, 0.16, 1) 0s;\ntransform-origin: top;\ntransform: scaleY(0);\nfont-family: ${fontFamily};`), (listEle.style.cssText = `\n ${ isCenter ? "text-align: center" : "" };\n word-break: break-all;\n white-space: pre-wrap`), "none" !== cssText && (isScrollStyle ? addCss(cssText + listCss + scrollCss, box, "ll-scroll-style-1") : addCss(cssText + listCss, box)), (control.cfg = { name: "cfg", height: 24, fontSize: 12, color: "#65aaff", bg: "#dfedfe", mg: "0 2px 4px 2px", bd: "1px solid #dfedfe", pd: "0 5px", radius: 6, hover: "#65aaff", hover_bg: "#cee4ff", hover_bd: "1px solid #dfedfe", move_height: 24, move_fontSize: 12, move_mg: "0 4px 0 0", move_pd: "0 5px", move_radius: 5, ...controlCfg, }); const defaControls = { add: { name: "add", text: "添加", type: "top", title: "添加一项记录至列表顶部", class: "control-add", noneText: "请填写内容!!", endText: "添加成功", }, search: { name: "search", text: "搜索", type: "top", searchType: "标题", title: "搜索所有记录的标题, 若要按描述搜索请先输入'描述=', 按内容搜索输入'内容=', 按日期搜索输入'日期='", class: "control-search", }, clear: { name: "clear", text: "清空", type: "top", title: "清空列表所有记录", class: "control-clear", hover_bg: "#fff", warnText: "是否清空列表?", twoWarnText: "请再次确认是否清空列表?清空数据后将无法复原!", }, import: { name: "import", text: "导入", type: "top", title: "导入含数据记录的json文件", class: "control-import", startTipText: "导入数据后当前列表数据将会被覆盖, 建议导入数据前先备份数据", submitText: "导入数据后当前列表数据将会被覆盖, 建议导入数据前先备份数据, 是否确认导入?", uploadingText: "当前已存在上传任务", timeoutText: "文件上传超时", endText: "导入成功", isUploading: !1, }, out: { name: "out", text: "导出", type: "top", title: "将列表的所有记录导出为json文件", class: "control-out", startText: "开始下载", isTime: !0, isFormat: !1, }, skip: { name: "skip", text: "跳转", type: "top", title: "快速跳转到对应名称的记录的位置", class: "control-skip", }, fold: { name: "fold", text: "折叠", maxHeight: 45, noFoldText: "展开", type: "top", title: "将每条记录收起, 以节省空间", class: "control-fold", isFold: !1, }, delete: { name: "delete", text: "删除", type: "move", title: "删除此条记录", class: "control-delete", bg: "#fff", hover: "#ff8b8b", hover_bg: "#fff", hover_bd: "1px solid #ffd4d4", warnText: "是否确认删除?", endText: "删除成功", }, update: { name: "update", text: "修改", type: "move", title: "修改此条记录", class: "control-update", noneText: "请填写内容!!", submitText: "是否确认修改?", endText: "修改成功", }, move: { name: "move", text: "移动", type: "move", title: "将当前项移动到下次点击的项的的上方", class: "control-move", tipText: "请选择目标位置的项", warnText: "是否将当前项移动到该项之前?", endText: "移动完成", isMoving: !1, }, changePlace: { name: "changePlace", text: "换位", type: "move", title: "将当前项和点击的另一项进行位置交换", class: "control-changePlace", tipText: "请选择需要交换位置的项", warnText: "是否交换两项的位置?", endText: "换位成功", isChangePlaceing: !1, }, desc: { name: "desc", text: "描述", type: "move", title: "当前记录的描述文本", class: "control-desc", }, toSuki: { name: "toSuki", text: "收藏", type: "move", title: "将当前记录添加到收藏列表中", class: "control-toSuki", endText: "已添加至收藏", }, copy: { name: "copy", text: "复制", type: "move", title: "复制到剪贴板", class: "control-copy", endText: "已复制到剪贴板", }, toTop: { width: 20, height: 20, name: "toTop", text: "^", type: "other", title: "返回顶部", class: "control-toTop", bg: "#fff", hover_bg: "#fff", bd: "1px solid #dfedfe", color: "#65aaff", hover: "#65aaff", hover_bd: "1px solid #65aaff", fontSize: 14, pd: "3px 0 0 0", isCenter: !0, css: "position:absolute; bottom:4px; right:4px;", }, toBottom: { name: "toBottom", text: "底部", type: "top", title: "滚动到列表底部", class: "control-toBottom", }, }; return ( controlArr.forEach((item) => { control.info[item.name] = { ...defaControls[item.name], ...item }; }), (control.top_eleList = {}), (control.move_eleList = {}), (control.other_eleList = {}), listEle.addEventListener("mouseover", (e) => { const item = e.target; item.classList.contains("hItem") && (item.style.backgroundColor = hoverColor); }), listEle.addEventListener("mouseout", (e) => { const item = e.target; item.classList.contains("hItem") && (item.style.backgroundColor = "#fff"); }), (function addControlDom(control) { function createControl({ obj, box, type } = {}) { (type = type ? type + "_" : ""), (box = box || obj.box || null); const dom = document.createElement("div"), cfg = control.cfg; (dom.className = obj.class), (dom.title = obj.title), (dom.innerText = obj.text); const width = obj.width || cfg[type + "width"] || cfg.width; return ( (dom.style.cssText = `\nheight: ${ obj.height || cfg[type + "height"] || cfg.height }px;\nline-height: ${ obj.height || cfg[type + "height"] || cfg.height }px;\nwidth: ${width ? width + "px" : "auto"};\nfont-size: ${ obj.fontSize || cfg[type + "fontSize"] || cfg.fontSize }px;\ncolor: ${ obj.color || cfg[type + "color"] || cfg.color };\nbackground: ${obj.bg || cfg[type + "bg"] || cfg.bg};\nmargin: ${ ("move_" === type ? obj[type + "mg"] : obj.mg) || cfg.mg };\nborder: ${ obj.bd || cfg[type + "bd"] || cfg.bd };\nborder-radius: ${ obj.radius || cfg[type + "radius"] || cfg.radius }px;\nbox-sizing: border-box;\npadding: ${ obj.pd || cfg[type + "pd"] || cfg.pd };\ncursor:pointer;\n${ obj.isCenter ? "text-align: center;" : "" }\n${obj.css ? obj.css : ""}`), dom.addEventListener("mouseenter", () => { (dom.style.color = obj.hover || cfg.hover), (dom.style.background = obj.hover_bg || cfg.hover_bg), (dom.style.border = obj.hover_bd || cfg.hover_bd); }), dom.addEventListener("mouseleave", () => { (dom.style.color = obj.color || cfg.color), (dom.style.background = obj.bg || cfg.bg), (dom.style.border = obj.bd || cfg.bd); }), box ? box.appendChild(dom) : control.appendChild(dom), dom ); } const info = control.info; if (!control.info) return; for (let key in info) { const item = info[key]; "move" === item.type ? ((item.ele = createControl({ obj: item, box: control.eleList.move_control, type: item.type, })), (item.ele.info = item)) : (item.ele = createControl({ obj: item })), (control[item.type + "_eleList"][key] = item.ele); } })(control), box.appendChild(hList), { value: listEle, list_info: listEle.list_info, control, control_info: control.info, } ); } const icons = { base: { color: "#666", width: "100%", height: "80%", marginTop: "10%", html: "", }, lishi: { color: "#8a8a8a", width: "100%", height: "80%", marginTop: "10%", html: '<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1700314086069" style="svgStyleFlag" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4255" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M512.5 98.29c-227.84 0-412.54 184.7-412.54 412.54s184.7 412.54 412.54 412.54 412.54-184.7 412.54-412.54S740.34 98.29 512.5 98.29z m249.28 661.82c-32.4 32.4-70.1 57.82-112.08 75.58-43.42 18.37-89.59 27.68-137.21 27.68-47.62 0-93.78-9.31-137.2-27.68-41.97-17.75-79.68-43.18-112.08-75.58-32.4-32.4-57.82-70.1-75.58-112.08-18.37-43.42-27.68-89.59-27.68-137.21 0-47.62 9.31-93.78 27.68-137.21 17.75-41.97 43.18-79.68 75.58-112.08s70.1-57.82 112.08-75.58c43.42-18.37 89.59-27.68 137.21-27.68 47.62 0 93.78 9.31 137.21 27.68 41.97 17.75 79.68 43.18 112.08 75.58s57.82 70.1 75.58 112.08c18.37 43.42 27.68 89.59 27.68 137.21 0 47.62-9.31 93.78-27.68 137.21-17.77 41.97-43.19 79.68-75.59 112.08z" p-id="4256"></path><path d="M738.68 674.81L542 497.48V248.27c0-16.57-13.43-30-30-30s-30 13.43-30 30v262.55c0 8.5 3.6 16.59 9.91 22.28L698.5 719.37a29.906 29.906 0 0 0 20.08 7.72c8.2 0 16.37-3.34 22.29-9.91 11.1-12.3 10.12-31.27-2.19-42.37z" p-id="4257"></path></svg>', }, shoucang: { color: "#fe9850", width: "100%", height: "80%", marginTop: "10%", html: '<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1700314090785" style="svgStyleFlag" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4405" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M949.888 457.258667c26.069333-29.824 13.866667-67.52-24.789333-76.309334L681.728 325.546667l-127.786667-214.677334c-20.266667-34.069333-59.925333-34.090667-80.213333 0l-127.786667 214.677334-243.370666 55.381333c-38.442667 8.746667-50.858667 46.506667-24.789334 76.309333l164.394667 188.053334-22.613333 248.917333c-3.584 39.466667 28.458667 62.805333 64.896 47.146667l237.781333-102.037334a21.333333 21.333333 0 0 0-16.810667-39.210666L267.626667 902.186667c-6.698667 2.88-6.229333 3.221333-5.568-4.096l24.277333-267.093334-176.426667-201.813333c-4.757333-5.461333-4.906667-5.034667 2.133334-6.634667l261.205333-59.434666 137.152-230.4c3.733333-6.293333 3.136-6.293333 6.869333 0l137.173334 230.4 261.205333 59.434666c7.125333 1.621333 6.954667 1.088 2.133333 6.613334l-176.426666 201.813333 24.256 267.093333a21.333333 21.333333 0 1 0 42.496-3.84l-22.613334-248.917333 164.394667-188.053333z" p-id="4406"></path></svg>', }, }; const commentHistory_curInfo = info.history, commentHistory_doms = commentHistory_curInfo.doms, svg = (function getIconHTML({ name = "", svg, color, width, height, marginTop, css, } = {}) { let icon; if ( (svg ? ((icon = { ...icons.base }), (icon.html = svg)) : (icon = icons[name]), icon) ) return ( css || (css = `\n fill:${ color || icon.color || icons.base.fill };\n width:${ width || icon.width || icons.base.width };\n height:${ height || icon.height || icons.base.height };\n margin-top:${ marginTop || icon.marginTop || icons.base.marginTop };`), icon.html.replace("svgStyleFlag", css) ); })({ svg: '<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1700396681111" style="svgStyleFlag" class="" viewBox="0 0 1129 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="15893" xmlns:xlink="http://www.w3.org/1999/xlink" width="220.5078125" height="200"><path d="M669.489367 1016.496894c-85.292857 2.785872-189.356466-2.386815-292.381021-29.349537C148.937907 927.424287-6.152335 732.202431 0.187406 497.45884 6.73797 255.283749 172.038056 65.520695 404.560478 15.774058 576.109953-20.939216 737.517347 5.669626 884.799618 103.822669c122.465423 81.618517 190.493403 199.45337 219.790235 340.855193 24.922259 120.206608 25.04273 240.84992-6.166565 360.265943-36.434687 139.368889-127.359522 201.350774-265.990532 211.026032-47.427587 3.312929-95.284349 0.527057-162.93586 0.527057" fill="#ADDEEE" p-id="15894"></path><path d="M389.795357 745.070147c-21.594272-42.932545-21.669566-91.391657-33.761756-136.816428-5.391039-20.231454-13.831478-27.903895-30.65212-35.674219-29.417301-13.605596-58.277429-28.890245-85.73709-46.079827-29.010715-18.145814-27.949072-26.74437 3.056929-42.480782 107.090422-54.339561 218.374711-99.222216 329.576176-144.112401 69.435975-28.024365 139.820652-53.729681 210.145095-79.434996 13.138774-4.796217 30.441298-15.322295 41.426668-3.91528 10.089374 10.488431 4.39716 28.536364 0.639997 43.128309-20.63804 80.135229-54.866618 155.316123-86.723439 231.174663-25.148141 59.873658-54.550384 117.98544-83.064159 176.405926-20.841334 42.691605-25.012612 44.235128-68.299038 22.414975-31.096354-15.676177-60.747066-34.168342-91.037776-51.410631-6.159036 2.763284-12.129837 1.355289-18.017815-0.873408-41.637491-15.774058-41.276081-15.623471-59.331542 26.87237-6.490329 15.314766-7.604677 35.011633-28.22013 40.801729" fill="#FDFEFE" p-id="15895"></path><path d="M389.795357 745.070147c11.858779-26.99284 25.931197-53.277918 34.921281-81.204401 7.785383-24.18438 16.173116-22.324622 32.654936-8.606086 11.24137 9.366553 25.223435 15.457824 37.99327 23.009796-11.72325 28.58154-75.256188 68.788448-105.569487 66.800691" fill="#0294C9" p-id="15896"></path></svg>', }); const pageType = getBiliPageType(window.location); console.log("当前页面:", pageType), "直播" !== pageType && "其他" !== pageType && ((document.comment_list_info = info), (info.pageType = pageType), (function setZIndex(val) { msgZIndex = val; })(12e3), (info.edit = (function createEditEle({ id, box, placeholder = { title: "请输入标题", desc: "请输入描述", value: "请输入内容", }, zIndex = 2e3, } = {}) { return ( addCss( `.ll-edit-wrap {\n position: fixed;\n left: 0;\n top: 0;\n width: 100%;\n height: 100%;\n z-index: ${zIndex};\n background: rgba(0, 0, 0, 0.12);\n}\n.ll-edit-wrap .edit-box {\n position: relative;\n width: 480px;\n top: calc(50% - 250px);\n margin: auto;\n color: #333;\n background: #fff;\n font-size: 16px;\n font-family: math;\n border: 3px solid #dfedfe;\n border-radius: 10px;\n box-sizing: border-box;\n padding: 20px;\n}\n.ll-edit-wrap .edit-box > div {\n margin-bottom: 15px;\n}\n.ll-edit-wrap .edit-box .edit-item {\n display: flex;\n}\n.ll-edit-wrap .edit-box textarea {\n width: 100%;\n line-height: 18px;\n border-radius: 6px;\n padding: 5px 7px;\n outline-color: #cee4ff;\n border: 1px solid #aaa;\n box-sizing: border-box;\n font-size: 13px;\n font-family: math;\n /* 保留空格 */\n white-space: pre-wrap;\n /* 允许词内换行 */\n word-break: break-all;\n letter-spacing: 1px;\n}\n.ll-edit-wrap .edit-box textarea::placeholder {\n color: #bbb;\n}\n.ll-edit-wrap .edit-box .title {\n width: 15%;\n font-weight: bold;\n font-size: 18px;\n}\n.ll-edit-wrap .edit-box .content-box .title {\n width: 100%;\n margin-bottom: 8px;\n}\n.ll-edit-wrap .edit-box .name-box textarea {\n height: 30px;\n}\n.ll-edit-wrap .edit-box .desc-box textarea {\n height: 100px;\n}\n.ll-edit-wrap .edit-box .content-box textarea {\n width: 100%;\n height: 200px;\n}\n.ll-edit-wrap .edit-box .btn-box {\n justify-content: flex-end;\n margin-bottom: 0;\n}\n.ll-edit-wrap .edit-box .btn-box button {\n font-size: 16px;\n color: #65aaff;\n background: #dfedfe;\n outline: none;\n border: none;\n border-radius: 6px;\n padding: 8px 16px;\n box-sizing: border-box;\n cursor: pointer;\n}\n.ll-edit-wrap .edit-box .btn-box .cancel-btn {\n color: #888;\n background: #f4f4f4;\n margin-right: 20px;\n}\n.ll-edit-wrap .edit-box .btn-box .cancel-btn:hover {\n color: #666;\n background: #eee;\n}\n.ll-edit-wrap .edit-box .btn-box .confirm-btn:hover {\n background: #cee4ff;\n}` ), (eleList.wrap = createEle({ className: "ll-edit-wrap", box })), (eleList.wrap.id = id), (eleList.wrap.innerHTML = '<div class="edit-box">\n <div class="edit-item name-box">\n <div class="name title">标 题</div>\n <textarea class="edit-name" placeholder="" title="拖动右下角可调节宽高"></textarea>\n </div>\n <div class="edit-item desc-box">\n <div class="desc title">描 述</div>\n <textarea class="edit-desc" placeholder="" title="拖动右下角可调节宽高"></textarea>\n </div>\n <div class="content content-box">\n <div class="desc title">内 容</div>\n <textarea class="edit-content" placeholder="" title="拖动右下角可调节宽高"></textarea>\n </div>\n <div class="edit-item btn-box">\n <button class="cancel-btn">取 消</button>\n <button class="confirm-btn">确 认</button>\n </div>\n</div>'), (eleList.wrap.style.display = "none"), (eleList.box = eleList.wrap.children[0]), (eleList.box.className = eleList.box.className + " ll-scroll-style-1"), (eleList.title = eleList.box.querySelector(".edit-name")), (eleList.desc = eleList.box.querySelector(".edit-desc")), (eleList.value = eleList.box.querySelector(".edit-content")), (eleList.cancel = eleList.box.querySelector(".cancel-btn")), (eleList.confirm = eleList.box.querySelector(".confirm-btn")), (eleList.title.placeholder = placeholder.title), (eleList.desc.placeholder = placeholder.desc), (eleList.value.placeholder = placeholder.value), (function bindEvents() { function cancelEdit(e) { ("ll-edit-wrap" !== e.target.className && "cancel-btn" !== e.target.className) || (showEditArea(!1), clearEditData()); } function confirmEdit() { const data = (function getEditData() { return { title: eleList.title.value, desc: eleList.desc.value, value: eleList.value.value, }; })(); if (edit.callback.confirmBefore) { let result; const func = edit.callback.confirmBefore; if ( (Array.isArray(func) ? func.curFn ? ((result = func[curFn](data)), (func.curFn = null)) : func.forEach((fn) => { result = fn(data); }) : (result = func(data)), !1 === result) ) return; } if (eleList.value.value) { if ( (showEditArea(!1), clearEditData(), edit.callback.finished) ) { const func = edit.callback.finished; Array.isArray(func) ? func.curFn ? (func[curFn](data), (func.curFn = null)) : func.forEach((fn) => { fn(data); }) : func(data); } } else alert(edit.msg.noneText || "请填写内容!!"); } eleList.wrap.addEventListener("click", cancelEdit), eleList.cancel.addEventListener("click", cancelEdit), eleList.confirm.addEventListener("click", confirmEdit); })(), edit ); })({ placeholder: { title: "请输入标题", desc: "请输入描述\n鼠标对准标题时将显示描述信息\n鼠标对准序号时将显示日期", value: "请 输 入 内 容", }, zIndex: 12e3, })), (function getData() { (settings.isHiddenBtn.value = getValue({ base: settings.isHiddenBtn.base, key: settings.isHiddenBtn.key, valType: "boolean", getVal: GM_getValue, setVal: GM_setValue, })), (settings.position.value = getValue({ base: settings.position.base, key: settings.position.key, getVal: GM_getValue, setVal: GM_setValue, })), (settings.listSize.value = getValue({ base: settings.listSize.base, key: settings.listSize.key, getVal: GM_getValue, setVal: GM_setValue, })), (settings.scale.value = getValue({ base: settings.scale.base, key: settings.scale.key, valType: "number", getVal: GM_getValue, setVal: GM_setValue, })), (settings.listMaxLen.value = getValue({ base: settings.listMaxLen.base, key: settings.listMaxLen.key, valType: "number", getVal: GM_getValue, setVal: GM_setValue, })), (settings.sendKeys.value = getValue({ base: settings.sendKeys.base, key: settings.sendKeys.key, getVal: GM_getValue, setVal: GM_setValue, })), (settings.addItemKeys.value = getValue({ base: settings.addItemKeys.base, key: settings.addItemKeys.key, getVal: GM_getValue, setVal: GM_setValue, })), (settings.isHiddenList.value = getValue({ base: settings.isHiddenList.base, key: settings.isHiddenList.key, valType: "boolean", getVal: GM_getValue, setVal: GM_setValue, })); })(), addCss( (function getCss() { return `\n#${doms.box.id} {\n opacity: ${ +css_settings.isHiddenBtn.value ? 0 : 1 };\n transform: scale(${ css_settings.scale.value });\n transform-origin: left top;\n transition: ease 1s 3s all;\n display:flex;\n position:fixed;\n z-index:11000;\n left:${css_settings.position.value .split(/,|,/)[0] .trim()}px;\n top:${css_settings.position.value .split(/,|,/)[1] .trim()}px;\n font-family:math;\n gap:${Math.floor( curInfo.height / 4 )}px;\n}\n#${ doms.box.id }:hover {\n opacity: 1;\n transition: ease 1s all;\n}\n#${ doms.box.id } .${doms.btn.class} {\n width:${curInfo.width}px;\n height:${ curInfo.height }px;\n background:#fff;\n border:1px solid #ccc;\n border-radius:6px;\n box-sizing:border-box;\n cursor:pointer;\n}\n#${ doms.box.id } .${doms.btn.class}:hover {\n border:1px solid ${ curInfo.color.main };\n}\n#${doms.box.id} .${ doms.options.class } {\n display:flex;\n height:${curInfo.height}px;\n line-height:${ curInfo.height + 1 }px;\n font-size:${ curInfo.height - 9 }px;\n background:#fff;\n border:2px solid ${ curInfo.color.bd };\n border-radius:${Math.floor( curInfo.height / 6 )}px;\n box-sizing:border-box;\n padding:0 ${Math.floor( curInfo.height / 2 )}px;\n gap:${Math.floor( curInfo.height / 2 )}px;\n transition:all 0.5s;\n transform:scaleX(0);\n transform-origin:left top;\n}\n#${ doms.box.id } .${doms.btn.class}.opened {\n border:1px solid ${ curInfo.color.main };\n}\n#${doms.box.id} .${ doms.options.class }.opened {\n transform:scaleX(1);\n}\n.ll-scroll-style-1::-webkit-scrollbar,\n.ll-scroll-style-1 ::-webkit-scrollbar {\n width: 8px;\n}\n.ll-scroll-1-size-2::-webkit-scrollbar,\n.ll-scroll-style-1 .ll-scroll-1-size-2::-webkit-scrollbar {\n width: 10px;\n}\n.ll-scroll-1-size-3::-webkit-scrollbar,\n.ll-scroll-style-1 .ll-scroll-1-size-3::-webkit-scrollbar {\n width: 12px;\n}\n.ll-scroll-style-1::-webkit-scrollbar-thumb,\n.ll-scroll-style-1 ::-webkit-scrollbar-thumb {\n border-radius: 10px;\n -webkit-box-shadow: inset 0 0 8px rgba(0, 0, 0, 0.05);\n opacity: 0.2;\n background: #daedff;\n}\n.ll-scroll-style-1::-webkit-scrollbar-track,\n.ll-scroll-style-1 ::-webkit-scrollbar-track {\n -webkit-box-shadow: inset 0 0 8px rgba(0, 0, 0, 0.08);\n border-radius: 0;\n background: #fff;\n border-radius: 5px;\n}\n`; })() ), (function registerMenu() { GM_registerMenuCommand("基础设置", () => { const f1 = setIsItem({ txt: registerMenu_settings.isHiddenBtn.txt, base: registerMenu_settings.isHiddenBtn.base, key: registerMenu_settings.isHiddenBtn.key, setValue: GM_setValue, getValue: GM_getValue, }), f2 = setTextItem({ txt: registerMenu_settings.position.txt, base: registerMenu_settings.position.base, key: registerMenu_settings.position.key, verification: (newVal) => newVal.includes(",") || newVal.includes(",") ? newVal : registerMenu_settings.position.base, setValue: GM_setValue, getValue: GM_getValue, }), f3 = setTextItem({ txt: registerMenu_settings.listSize.txt, base: registerMenu_settings.listSize.base, key: registerMenu_settings.listSize.key, verification: (newVal) => newVal.split(/,|,/).every((i) => +i.trim()) ? newVal : registerMenu_settings.listSize.base, setValue: GM_setValue, getValue: GM_getValue, }), f4 = setTextItem({ txt: registerMenu_settings.scale.txt, base: registerMenu_settings.scale.base, key: registerMenu_settings.scale.key, verification: (newVal) => +newVal ? newVal : registerMenu_settings.scale.base, setValue: GM_setValue, getValue: GM_getValue, }); (f1 || f2 || f3 || f4) && history.go(0); }), GM_registerMenuCommand("其他设置", () => { const f1 = setTextItem({ txt: registerMenu_settings.listMaxLen.txt, base: registerMenu_settings.listMaxLen.base, key: registerMenu_settings.listMaxLen.key, verification: (newVal) => +newVal ? newVal : registerMenu_settings.listMaxLen.base, setValue: GM_setValue, getValue: GM_getValue, }), f2 = setTextItem({ txt: registerMenu_settings.sendKeys.txt, base: registerMenu_settings.sendKeys.base, key: registerMenu_settings.sendKeys.key, verification: (newVal) => newVal.replaceAll(" ", "").toLowerCase(), setValue: GM_setValue, getValue: GM_getValue, }), f3 = setTextItem({ txt: registerMenu_settings.addItemKeys.txt, base: registerMenu_settings.addItemKeys.base, key: registerMenu_settings.addItemKeys.key, verification: (newVal) => newVal.replaceAll(" ", "").toLowerCase(), setValue: GM_setValue, getValue: GM_getValue, }), f5 = setIsItem({ txt: registerMenu_settings.isHiddenList.txt, base: registerMenu_settings.isHiddenList.base, key: registerMenu_settings.isHiddenList.key, setValue: GM_setValue, getValue: GM_getValue, }); (f1 || f2 || f3 || f4 || f5) && history.go(0); }); })(), "首页" !== pageType && (function main() { const pageType = info.pageType, curInfo = info.customKeys, settings = info.settings, classList = curInfo.classList; function genericGetTextarea(textareaClass, box = null) { if (box) return box.querySelector(`.${textareaClass}`); { const focus = document.activeElement; return focus.classList.contains(textareaClass) ? focus : null; } } function getTextarea(classObj, box = null) { let textarea; return ( classObj.focusDom && (textarea = classObj.focusDom === classObj.box ? (box = box || document.querySelector( `.${classObj.box}.${classList.focus}` ) || document).querySelector(`.${classObj.textarea}`) : box ? box.querySelector( `.${classObj.textarea}.${classList.focus}` ) : document.querySelector( `.${classObj.textarea}.${classList.focus}` )), (textarea = textarea || genericGetTextarea(classObj.textarea, box)), { box, textarea } ); } function getContainer(dom, boxClass) { for (let i = 0; i < 2; i++) if ((dom = dom.parentElement).classList.contains(boxClass)) return dom; return dom; } function getBtn(box, btnClass) { let btn = box.querySelector(`.${btnClass}`); if (btn) return btn; if (((btn = box.querySelector("button")), btn)) return btn; { const divArr = box.querySelectorAll("div"); for (let i = 0; i < divArr.length; i++) { const div = divArr[i], className = div.className; if ( ["send", "submit", "btn", "button"].some((item) => className.includes(item) ) ) return div; } } } function getSendDoms(classObj, textarea = null, btn = null) { let box; if (!textarea && !btn) { const result = getTextarea(classObj); return ( (box = result.box), (textarea = result.textarea) ? ((box = box || getContainer(textarea, classObj.box)), { box, textarea, btn: getBtn(box, classObj.btn) }) : {} ); } return !textarea && btn ? ((box = getContainer(btn, classObj.box)), { box, textarea: (textarea = getTextarea(classObj, box).textarea), btn, }) : textarea && !btn ? ((box = getContainer(textarea, classObj.box)), { box, textarea, btn: getBtn(box, classObj.btn) }) : void 0; } function verifyKeys(e, key, keys, canShiftEnter = !0) { if (!keys) return console.log("未设置快捷键"), !1; let keyArr = keys.split("+"); if (key && key !== keyArr[keyArr.length - 1]) return; const keyObj = { control: e.ctrlKey, ctrl: e.ctrlKey, shift: e.shiftKey, alt: e.altKey, meta: e.metaKey, win: e.metaKey, window: e.metaKey, }; if ( !canShiftEnter && "enter" === key && keyObj.shift && !keyObj.control && !keyObj.ctrl && !keyObj.alt && !keyObj.meta && !keyObj.win && !keyObj.window ) return !1; for (let i = 0; i < keyArr.length; i++) { const item = keyArr[i]; if (void 0 !== keyObj[item] && !keyObj[item]) return !1; } return !0; } function getCommentInfo(allData = {}) { const location = window.location, host = location.hostname, path = location.pathname.split("/"), pageType = getBiliPageType(location), data = { id: new Date().getTime(), pageType, url: location.href, ...allData.data, }, longTime = formatDate({ timestamp: data.id, isExact: !0, delimiter2: "时分秒", }), shortTime = formatDate({ timestamp: data.id }), pageTitle = document.head.querySelector("title").innerText; let listTitle; if ("视频" === pageType) { const bv = path.find((i) => "BV" === i.slice(0, 2)) || "", h1 = document.querySelector("h1"); (data.bv = bv), (listTitle = h1 ? h1.innerText : pageTitle.split("_哔哩哔哩")[0]); } else if ("主页" === pageType) listTitle = pageTitle.split("-哔哩哔哩")[0]; else if ("动态" === pageType) listTitle = pageTitle.split("的动态")[0] + "的动态"; else if ("专栏" === pageType) { const h1 = document.querySelector("h1"); listTitle = h1 ? h1.innerText : host; } else listTitle = "番剧" === pageType ? pageTitle.split("-番剧")[0] : "消息" === pageType ? "消息中心" : host; return ( (data.title = `${shortTime} [${pageType}] ${listTitle}`), (data.desc = `评论的相关信息:\n${ data.user ? "收藏日期" : "评论日期" }: ${longTime}\n来源: ${data.pageType}`), "视频" === pageType ? ((data.desc += "\n视频标题: " + listTitle), (data.desc += "\n视频ID: " + data.bv)) : "主页" === pageType ? (data.desc += "\n主页名称: " + listTitle) : "动态" === pageType ? (data.desc += "\n动态名称: " + listTitle) : "专栏" === pageType ? (data.desc += "\n专栏名称: " + listTitle) : "番剧" === pageType && (data.desc += "\n番剧名称: " + listTitle), (data.desc += `\n评论用户: ${data.user ? data.user : "自己"}`), data.uid && (data.desc += `\nUID: ${data.uid}`), allData.replyUser && ((data.desc += `\n回复用户: ${allData.replyUser}`), allData.replyUid && (data.desc += `\nUID: ${allData.replyUid}`)), (data.desc += "\n地址: " + data.url), data ); } function addComment({ info, doms, replyDom, isSub }) { let data, allData = { data: {} }; if (replyDom) { const curClass = curInfo.curClassList; let userDom, replyBox = replyDom.parentElement; if ( ("专栏" === pageType ? (userDom = isSub || replyBox.classList.contains(curClass.replyParent) ? replyBox.querySelector("." + curClass.subUser) : replyBox.querySelector("." + curClass.user)) : isSub || replyBox.classList.contains(curClass.replyParent) ? ((replyBox = replyBox.parentElement), (userDom = replyBox.querySelector("." + curClass.subUser))) : ((replyBox = replyBox.parentElement.parentElement), (userDom = replyBox.querySelector("." + curClass.user))), userDom) ) { const location = window.location; let curUrl = location.href; (allData.data.user = userDom.innerText), (allData.data.uid = userDom.dataset.userId || userDom.dataset.usercardMid), (allData.data.url = curUrl); const rootId = userDom.dataset.rootReplyId; if (rootId) { if (location.hash) { const urlArr = curUrl.split("#reply"); 1 === urlArr.length ? (curUrl += `#reply${rootId}`) : (curUrl = urlArr[0] + "#reply" + rootId); } else curUrl += `#reply${rootId}`; allData.data.url = curUrl; } } else console.log("评论用户的数据获取失败"); const subAllData = (function getText(dom) { const nodeArr = dom.childNodes, allData = { data: {} }; let text = ""; for (let i = 0; i < nodeArr.length; i++) { const node = nodeArr[i]; "IMG" === node.tagName ? (text += node.alt) : (node.classList && node.classList.contains( curInfo.curClassList.replyUser ) && ((allData.replyUser = node.textContent.replace( "@", "" )), (allData.replyUid = node.dataset ? node.dataset.userId : "")), node.dataset && "string" != typeof curInfo.replyUser && node.dataset[curInfo.curClassList.replyUser.value] && ((allData.replyUser = node.textContent.replace( "@", "" )), (allData.replyUid = node.dataset[curInfo.curClassList.replyUser.value])), (text += node.textContent)); } return (allData.data.value = text), allData; })(replyDom); (allData.replyUser = subAllData.replyUser), (allData.replyUid = subAllData.replyUid), (allData.data.value = subAllData.data.value), (data = getCommentInfo(allData)); } else data = getCommentInfo({ data: { value: doms.textarea.value } }); addItem({ info, data }); } function dblClickHandle(e) { let isSub = !1; const curClass = curInfo.curClassList; let flag = e.target.classList.contains(curClass.reply); flag || curClass.reply === curClass.subReply || ((flag = e.target.classList.contains(curClass.subReply)), (isSub = flag)); let replyDom = flag ? e.target : null; if ( (replyDom || ((flag = e.target.parentElement.classList.contains( curClass.reply )), flag || curClass.reply === curClass.subReply || ((flag = e.target.parentElement.classList.contains( curClass.subReply )), (isSub = flag)), (replyDom = flag ? e.target.parentElement : null)), flag) ) { if (!verifyKeys(e, null, settings.addItemKeys.value)) return; message({ title: "收藏", msg: "已添加评论到收藏列表" }), addComment({ info: info.history.data.suki_info, replyDom, isSub, }); } } function handleKeyDown(e) { const key = (function getKeyDown(e) { const keyCode = e.keyCode || e.which || e.charCode; let key = e.key || String.fromCharCode(keyCode); return (key = key.toLowerCase()), console.log("按下", key), key; })(e); if (!key) return; if (!verifyKeys(e, key, settings.sendKeys.value, !1)) return; const doms = getSendDoms(curInfo.curClassList), btn = doms.btn; btn && ((curInfo.curSendBtn = btn), document.activeElement.blur(), doms.textarea.blur(), (curInfo.isBtnClickEvent = !1), btn.click(), addComment({ info: info.history.data, doms }), (curInfo.isBtnClickEvent = !0)); } function clickBtn() { curInfo.isBtnClickEvent && addComment({ info: info.history.data, doms: curInfo.curDoms }); } function clickHandle(e) { let textarea, flag = "TEXTAREA" === e.target.tagName; if ( (flag || ((textarea = genericGetTextarea(curInfo.curClassList.textarea)), (flag = flag || textarea)), flag) ) { if (e.target === curInfo.curTextarea) return; let doms = curInfo.curDoms; if ( ((curInfo.curTextarea = textarea || e.target), (curInfo.curDoms = getSendDoms( curInfo.curClassList, curInfo.curTextarea )), (doms = curInfo.curDoms), !doms.btn) ) return void (curInfo.curTextarea = null); (curInfo.curSendBtn = doms.btn), doms.btn.addEventListener("click", clickBtn, !0); } } function magClickHandle(e) { if ("BUTTON" === e.target.tagName) { const btn = e.target, doms = getSendDoms(curInfo.curClassList, null, btn); if (!doms.textarea) return; (curInfo.curDoms = doms), (curInfo.curSendBtn = btn), addComment({ info: info.history.data, doms }); } } !(function main() { curInfo.curClassList = classList[pageType]; const clickFn = "消息" === pageType ? magClickHandle : clickHandle; document.addEventListener("click", clickFn, !0), document.addEventListener("dblclick", dblClickHandle, !0), document.addEventListener("keydown", handleKeyDown); })(); })(), (function commentHistory_main() { !(function commentHistory_getData() { const dataList = JSON.parse( GM_getValue(commentHistory_curInfo.data.saveName) || null ) || [], suki_dataList = JSON.parse( GM_getValue(commentHistory_curInfo.data.suki_info.saveName) || null ) || []; (commentHistory_curInfo.data.dataList = dataList), (commentHistory_curInfo.data.suki_info.dataList = suki_dataList); })(), (function createDoms() { const box = createEle({ id: commentHistory_doms.box.id, title: commentHistory_doms.box.title, }), btn = createEle({ className: commentHistory_doms.btn.class, title: commentHistory_doms.btn.title, box, }), options = createEle({ className: commentHistory_doms.options.class, title: commentHistory_doms.options.title, box, }); (btn.innerHTML = svg), (commentHistory_doms.box.ele = box), (commentHistory_doms.btn.ele = btn), (commentHistory_doms.options.ele = options); })(), (info.searchEle = createSearch({ box: commentHistory_doms.box.ele, zIndex: 12e3, })), (function createHisBtnList() { const settings = info.settings, colorObj = commentHistory_curInfo.color.listBtnObj, listBtn = createSwitchBtn({ titleText: `按下${settings.sendKeys.value}即可发送评论`, color: commentHistory_curInfo.color.font, size: "autoxauto", text: commentHistory_doms.comment.option.text, box: commentHistory_doms.options.ele, ...colorObj, showMode: "显示", isPosition: !1, }), suki_listBtn = createSwitchBtn({ titleText: `按下${settings.addItemKeys.value}后双击页面中的一条评论即可加入收藏`, color: commentHistory_curInfo.color.font, size: "autoxauto", text: commentHistory_doms.suki_comment.option.text, box: commentHistory_doms.options.ele, ...colorObj, showMode: "显示", isPosition: !1, }); (listBtn.style.lineHeight = commentHistory_curInfo.height - 3 + "px"), (suki_listBtn.style.lineHeight = commentHistory_curInfo.height - 3 + "px"); const wh = settings.listSize.value.split(/,|,/), w = +wh[0].trim() || settings.listSize.base.split(/,|,/)[0].trim(), h = +wh[1].trim() || settings.listSize.base.split(/,|,/)[1].trim(); let commentListInfo = createHistoryList({ list_id: "ll_comment_list", box: commentHistory_doms.options.ele, width: w, maxHeight: h, right: -430, top: 36, right: -241, saveName: commentHistory_curInfo.data.saveName, outName: commentHistory_doms.comment.option.text, className: "autoImg-hList", maxLen: settings.listMaxLen.value, listTitle: "双击跳转到评论来源的页面", initialText: "暂无评论记录", isScrollStyle: !1, isDataSync: !0, isClickClose: settings.isHiddenList.value, setValue: GM_setValue, getValue: GM_getValue, controlArr: [ { name: "add" }, { name: "search", title: "搜索所有评论的内容, 若要按标题搜索请先输入'标题=', 按描述搜索输入'描述=', 按日期搜索输入'日期='", }, { name: "clear" }, { name: "out" }, { name: "import" }, { name: "fold" }, { name: "update" }, { name: "move", warnText: "" }, { name: "toSuki" }, { name: "copy" }, { name: "delete" }, { name: "toBottom" }, ], }), suki_commentListInfo = createHistoryList({ list_id: "ll_comment_cukiList", box: commentHistory_doms.options.ele, width: w, maxHeight: h, right: -460, top: 36, right: -315, cssText: "none", saveName: commentHistory_curInfo.data.suki_info.saveName, outName: commentHistory_doms.suki_comment.option.text, className: "suki_autoImg-hList", maxLen: settings.listMaxLen.value, listTitle: "双击跳转到评论来源的页面", initialText: "暂无收藏评论", isDesc: !1, isAddUp: !1, isDelete: !1, isScrollStyle: !1, isDataSync: !0, isClickClose: settings.isHiddenList.value, setValue: GM_setValue, getValue: GM_getValue, controlArr: [ { name: "add" }, { name: "search", title: "搜索所有评论的内容, 若要按标题搜索请先输入'标题=', 按描述搜索输入'描述=', 按日期搜索输入'日期='", }, { name: "clear" }, { name: "out" }, { name: "import" }, { name: "fold" }, { name: "update" }, { name: "move", warnText: "" }, { name: "toSuki" }, { name: "copy" }, { name: "delete" }, { name: "toBottom" }, ], }); (commentHistory_curInfo.data.btnEle = listBtn), (commentHistory_curInfo.data.listEle = commentListInfo.value), (commentHistory_curInfo.data.suki_info.btnEle = suki_listBtn), (commentHistory_curInfo.data.suki_info.listEle = suki_commentListInfo.value), initHisListDom(commentHistory_curInfo.data), initHisListDom(commentHistory_curInfo.data.suki_info), bindHistoryEvents(commentHistory_curInfo.data), bindHistoryEvents(commentHistory_curInfo.data.suki_info), controlEvents( commentListInfo.control, commentHistory_curInfo.data, info.searchEle, info.edit ), controlEvents( suki_commentListInfo.control, commentHistory_curInfo.data.suki_info, info.searchEle, info.edit ); })(), (function setToSukiCallback() { info.history.data.callback.toSuki = (data) => { const sukiDate = formatDate({ timestamp: new Date().getTime(), isExact: !0, delimiter2: "时分秒", }); return ( data.desc && data.desc.includes("评论的相关信息:") ? (data.desc = data.desc.replace( "评论的相关信息:", `评论的相关信息:\n收藏日期: ${sukiDate}` )) : (data.desc += `\n收藏日期: ${sukiDate}`), data ); }; })(), (function commentHistory_bindEvents() { (commentHistory_curInfo.data.listEle.parentElement.style.opacity = 0), (commentHistory_curInfo.data.suki_info.listEle.parentElement.style.opacity = 0), commentHistory_doms.btn.ele.addEventListener("click", () => { const isClose = commentHistory_doms.options.ele.classList.contains("opened"); commentHistory_doms.btn.ele.classList.toggle("opened"), commentHistory_doms.options.ele.classList.toggle("opened"), hiddenBtnList(commentHistory_curInfo.data), hiddenBtnList(commentHistory_curInfo.data.suki_info), isClose ? (changeShow( commentHistory_curInfo.data.listEle.list_info.control .move_eleList, !1 ), changeShow( commentHistory_curInfo.data.suki_info.listEle.list_info .control.move_eleList, !1 ), (commentHistory_curInfo.data.listEle.parentElement.style.opacity = 0), (commentHistory_curInfo.data.suki_info.listEle.parentElement.style.opacity = 0)) : ((commentHistory_curInfo.data.listEle.parentElement.style.opacity = 1), (commentHistory_curInfo.data.suki_info.listEle.parentElement.style.opacity = 1)); }), commentHistory_curInfo.data.btnEle.addEventListener( "click", () => { hiddenBtnList(commentHistory_curInfo.data.suki_info); } ), commentHistory_curInfo.data.suki_info.btnEle.addEventListener( "click", () => { hiddenBtnList(commentHistory_curInfo.data); } ), (commentHistory_curInfo.data.callback.clickItem = (data) => { data.url && window.open(data.url); }), (commentHistory_curInfo.data.suki_info.callback.clickItem = ( data ) => { data.url && window.open(data.url); }); })(); })()); })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址