NGA论坛显示优化,全面功能增强,优雅的摸鱼
// ==UserScript== // @name NGA优化摸鱼体验 // @namespace https://github.com/kisshang1993/NGA-BBS-Script // @version 4.5.4 // @author HLD // @description NGA论坛显示优化,全面功能增强,优雅的摸鱼 // @license MIT // @require https://lf3-cdn-tos.bytecdntp.com/cdn/expire-1-y/jquery/3.4.0/jquery.min.js#sha512=Pa4Jto+LuCGBHy2/POQEbTh0reuoiEXQWXGn8S7aRlhcwpVkO8+4uoZVSOqUjdCsE+77oygfu2Tl+7qGHGIWsw== // @require https://lf26-cdn-tos.bytecdntp.com/cdn/expire-1-y/spectrum/1.8.0/spectrum.min.js#sha512=Bx3FZ9S4XKYq5P1Yxfqp36JifotqAAAl5eotNaGWE1zSSLifBZlbKExLh2NKHA4CTlqHap7xdFzo39W+CTKrWQ== // @require https://lf9-cdn-tos.bytecdntp.com/cdn/expire-1-y/localforage/1.10.0/localforage.min.js#sha512=+BMamP0e7wn39JGL8nKAZ3yAQT2dL5oaXWr4ZYlTGkKOaoXM/Yj7c4oy50Ngz5yoUutAG17flueD4F6QpTlPng== // @require https://lf9-cdn-tos.bytecdntp.com/cdn/expire-1-y/echarts/5.3.0/echarts.min.js#sha512=dvHO84j/D1YX7AWkAPC/qwRTfEgWRHhI3n7J5EAqMwm4r426sTkcOs6OmqCtmkg0QXNKtiFa67Tp77JWCRRINg== // @require https://greasyfork.org/scripts/424901-nga-script-resource/code/NGA-Script-Resource.js?version=1268947 // @icon https://i.loli.net/2021/04/07/8x3yFj2pWEKluSY.png // @match *://bbs.nga.cn/* // @match *://ngabbs.com/* // @match *://nga.178.com/* // @match *://g.nga.cn/* // @grant GM_registerMenuCommand // @grant GM_setValue // @grant GM_getValue // @grant GM_deleteValue // @grant GM_listValues // @grant unsafeWindow // @inject-into content // ==/UserScript== (function () { 'use strict'; /** * NGA摸鱼主脚本 * @class NGABBSScript * @constructor */ class NGABBSScript { constructor() { // 配置 this.setting = { original: [], normal: {}, advanced: {} } // 模块 this.modules = [] // 样式 this.style = '' // 数据存储 this.store = {} // 引用库 this.libs = {$, echarts, localforage} } /** * 获取模块对象 * @method getModule * @param {String} name 模块name * @return {Object} 模块对象 */ getModule(name) { for (const m of this.modules) { if (m.name && m.name === name) { return m } } return null } /** * 全程渲染函数 * @method renderAlways */ renderAlways() { for (const module of this.modules) { try { module.renderAlwaysFunc && module.renderAlwaysFunc(this) } catch (error) { this.printLog(`[${module.name}]模块在[renderAlwaysFunc()]中运行失败!`) console.log(error) } } } /** * 列表页渲染函数 * @method renderThreads */ renderThreads() { $('.topicrow[hld-threads-render!=ok]').each((index, dom) => { const $el = $(dom) for (const module of this.modules) { try { module.renderThreadsFunc && module.renderThreadsFunc($el, this) } catch (error) { this.printLog(`[${module.name}]模块在[renderThreadsFunc()]中运行失败!`) console.log(error) } } $el.attr('hld-threads-render', 'ok') }) } /** * 详情页渲染函数 * @method renderForms */ renderForms() { $('.forumbox.postbox[hld-forms-render!=ok]').each((index, dom) => { const $el = $(dom) // 等待NGA页面渲染完成 if ($el.find('.small_colored_text_btn').length == 0) return true for (const module of this.modules) { try { module.renderFormsFunc && module.renderFormsFunc($el, this) } catch (error) { this.printLog(`[${module.name}]模块在[renderFormsFunc()]中运行失败!`) console.log(error) } } $el.attr('hld-forms-render', 'ok') }) } /** * 添加模块 * @method addModule * @param {Object} module 模块对象 * @param {Boolean} plugin 是否为插件 */ addModule(module) { // 组件预处理函数 if (module.preProcFunc) { try { module.preProcFunc(this) } catch (error) { this.printLog(`[${module.name}]模块在[preProcFunc()]中运行失败!`) console.log(error) } } // 添加设置 const addSetting = setting => { // 标准模块配置 if (setting.shortCutCode && this.setting.normal.shortcutKeys) { this.setting.normal.shortcutKeys.push(setting.shortCutCode) } if (setting.key) { this.setting[setting.type || 'normal'][setting.key] = setting.default ?? '' this.setting.original.push(setting) } } // 功能板块 if (module.setting && !Array.isArray(module.setting)) { addSetting(module.setting) } if (module.settings && Array.isArray(module.settings)) { for (const setting of module.settings) { addSetting(setting) } } // 添加样式 if (module.style) { this.style += module.style } this.modules.push(module) } /** * 判断当前页面是否为列表页 * @method isThreads * @return {Boolean} 判断状态 */ isThreads() { return $('#m_threads').length > 0 } /** * 判断当前页面是否为详情页 * @method isForms * @return {Boolean} 判断状态 */ isForms() { return $('#m_posts').length > 0 } /** * 抛出异常 * @method throwError * @param {String} msg 异常信息 */ throwError(msg) { alert(msg) throw(msg) } /** * 初始化 * @method init */ init() { // 开始初始化 this.printLog('初始化...') localforage.config({name: 'NGA BBS Script DB'}) const startInitTime = new Date().getTime() const modulesTable = [] //同步配置 this.loadSetting() // 组件初始化函数 for (const module of this.modules) { if (module.initFunc) { try { module.initFunc(this) } catch (error) { this.printLog(`[${module.name}]模块在[initFunc()]中运行失败!`) console.log(error) } } } // 组件后处理函数 for (const module of this.modules) { if (module.postProcFunc) { try { module.postProcFunc(this) } catch (error) { this.printLog(`[${module.name}]模块在[postProcFunc()]中运行失败!`) console.log(error) } } } // 动态样式 for (const module of this.modules) { if (module.asyncStyle) { try { this.style += module.asyncStyle(this) } catch (error) { this.printLog(`[${module.name}]模块在[asyncStyle()]中运行失败!`) console.log(error) } } modulesTable.push({ name: module.title || module.name || 'UNKNOW', type: module.type == 'plugin' ? '插件' : '标准模块', version: module.version || '-' }) } // 插入样式 const style = document.createElement("style") style.appendChild(document.createTextNode(this.style)) document.getElementsByTagName('head')[0].appendChild(style) // 初始化完成 const endInitTime = new Date().getTime() console.table(modulesTable) this.printLog(`[v${this.getInfo().version}] 初始化完成: 共加载${this.modules.length}个模块,总耗时${endInitTime-startInitTime}ms`) console.log('%c反馈问题请前往: https://github.com/kisshang1993/NGA-BBS-Script/issues', 'color:orangered;font-weight:bolder') } /** * 通知弹框 * @method popNotification * @param {String} msg 消息内容 * @param {Number} duration 显示时长(ms) */ popNotification(msg, duration=1000) { $('#hld__noti_container').length == 0 && $('body').append('<div id="hld__noti_container"></div>') let $msgBox = $(`<div class="hld__noti-msg">${msg}</div>`) $('#hld__noti_container').append($msgBox) $msgBox.slideDown(100) setTimeout(() => { $msgBox.fadeOut(500) }, duration) setTimeout(() => { $msgBox.remove() }, duration + 500) } /** * 消息弹框 * @method popMsg * @param {String} msg 消息内容 * @param {String} type 消息类型 [ok, err, warn] */ popMsg(msg, type='ok') { $('.hld__msg').length > 0 && $('.hld__msg').remove() let $msg = $(`<div class="hld__msg hld__msg-${type}">${msg}</div>`) $('body').append($msg) $msg.slideDown(200) setTimeout(() => { $msg.fadeOut(500) }, type == 'ok' ? 2000 : 5000) setTimeout(() => { $msg.remove() }, type == 'ok' ? 2500 : 5500) } /** * 打印控制台消息 * @method printLog * @param {String} msg 消息内容 */ printLog(msg) { console.log(`%cNGA%cScript%c ${msg}`, 'background: #222;color: #fff;font-weight:bold;padding:2px 2px 2px 4px;border-radius:4px 0 0 4px;', 'background: #fe9a00;color: #000;font-weight:bold;padding:2px 4px 2px 2px;border-radius:0px 4px 4px 0px;', 'background:none;color:#000;' ) } /** * 读取值 * @method saveSetting * @param {String} key */ getValue(key) { try { return GM_getValue(key) || window.localStorage.getItem(key) } catch { // 兼容性代码: 计划将在5.0之后废弃 return window.localStorage.getItem(key) } } /** * 写入值 * @method setValue * @param {String} key * @param {String} value */ setValue(key, value) { try { GM_setValue(key, value) } catch {} } /** * 删除值 * @method deleteValue * @param {String} key */ deleteValue(key) { try { GM_deleteValue(key) } catch {} // 兼容性代码: 计划将在5.0之后飞起 window.localStorage.removeItem(key) } /** * 保存配置到本地 * @method saveSetting * @param {String} msg 自定义消息信息 */ saveSetting(msg='保存配置成功,刷新页面生效') { // 基础设置 for (let k in this.setting.normal) { $('input#hld__cb_' + k).length > 0 && (this.setting.normal[k] = $('input#hld__cb_' + k)[0].checked) } script.setValue('hld__NGA_setting', JSON.stringify(this.setting.normal)) // 高级设置 for (let k in this.setting.advanced) { if ($('#hld__adv_' + k).length > 0) { const originalSetting = this.setting.original.find(s => s.type == 'advanced' && s.key == k) const valueType = typeof originalSetting.default const inputType = $('#hld__adv_' + k)[0].nodeName if (inputType == 'SELECT') { this.setting.advanced[k] = $('#hld__adv_' + k).val() } else { if (valueType == 'boolean') { this.setting.advanced[k] = $('#hld__adv_' + k)[0].checked } if (valueType == 'number') { this.setting.advanced[k] = +$('#hld__adv_' + k).val() } if (valueType == 'string') { this.setting.advanced[k] = $('#hld__adv_' + k).val() } } } } script.setValue('hld__NGA_advanced_setting', JSON.stringify(this.setting.advanced)) msg && this.popMsg(msg) } /** * 从本地读取配置 * @method loadSetting */ loadSetting() { // 基础设置 try { const settingStr = script.getValue('hld__NGA_setting') if (settingStr) { let localSetting = JSON.parse(settingStr) for (let k in this.setting.normal) { !localSetting.hasOwnProperty(k) && (localSetting[k] = this.setting.normal[k]) if (k == 'shortcutKeys') { if (localSetting[k].length < this.setting.normal[k].length) { const offset_count = this.setting.normal[k].length - localSetting[k].length localSetting[k] = localSetting[k].concat(this.setting.normal[k].slice(-offset_count)) } // 更改默认按键 let index = 0 for (const module of this.modules) { if (module.setting && module.setting.shortCutCode) { if (localSetting[k][index] != module.setting.shortCutCode) { module.setting.rewriteShortCutCode = localSetting[k][index] } index += 1 }else if (module.settings) { for (const setting of module.settings) { if (setting.shortCutCode) { if (localSetting[k][index] != setting.shortCutCode) { setting.rewriteShortCutCode = localSetting[k][index] } index += 1 } } } } } } for (let k in localSetting) { !this.setting.normal.hasOwnProperty(k) && delete localSetting[k] } this.setting.normal = localSetting } // 高级设置 const advancedSettingStr = script.getValue('hld__NGA_advanced_setting') if (advancedSettingStr) { let localAdvancedSetting = JSON.parse(advancedSettingStr) for (let k in this.setting.advanced) { !localAdvancedSetting.hasOwnProperty(k) && (localAdvancedSetting[k] = this.setting.advanced[k]) } for (let k in localAdvancedSetting) { !this.setting.advanced.hasOwnProperty(k) && delete localAdvancedSetting[k] } this.setting.advanced = localAdvancedSetting } } catch(e) { script.throwError(`【NGA-Script】读取配置文件出现错误,无法加载配置文件!\n错误问题: ${e}\n\n请尝试使用【修复脚本】来修复此问题`) } } /** * 检查是否更新 * @method checkUpdate */ checkUpdate() { // 字符串版本转数字 const vstr2num = str => { let num = 0 str.split('.').forEach((n, i) => num += i < 2 ? +n * 1000 / Math.pow(10, i) : +n) return num } // 字符串中版本截取 const vstr2mid = str => { return str.substring(0, str.lastIndexOf('.')) } //检查更新 const cver = script.getValue('hld__NGA_version') if (cver) { const local_version = vstr2num(cver) const current_version = vstr2num(GM_info.script.version) if (current_version > local_version) { const lv_mid = +vstr2mid(cver) const cv_mid = +vstr2mid(GM_info.script.version) script.setValue('hld__NGA_version', GM_info.script.version) if (cv_mid > lv_mid) { const focus = '' $('body').append(`<div id="hld__updated" class="animated-1s bounce"><p><a href="javascript:void(0)" class="hld__setting-close">×</a><b>NGA-Script已更新至v${GM_info.script.version}</b></p>${focus}<p><a class="hld__readme" href="https://greasyfork.org/zh-CN/scripts/393991-nga%E4%BC%98%E5%8C%96%E6%91%B8%E9%B1%BC%E4%BD%93%E9%AA%8C" target="_blank">查看更新内容</a></p></div>`) $('body').on('click', '#hld__updated a', function () { $(this).parents('#hld__updated').remove() }) } } } else script.setValue('hld__NGA_version', GM_info.script.version) } /** * 创建储存对象实例 * @param {String} instanceName 实例名称 */ createStorageInstance(instanceName) { if (!instanceName || Object.keys(this.store).includes(instanceName)) { this.throwError('【NGA-Script】创建储存对象实例失败,实例名称不能为空或实例名称已存在') } const lfInstance = localforage.createInstance({name: instanceName}) this.store[instanceName] = lfInstance return lfInstance } /** * 运行脚本 * @method run */ run() { this.checkUpdate() this.init() setInterval(() => { this.renderAlways() this.isThreads() && this.renderThreads() this.isForms() && this.renderForms() }, 100) } /** * 获取脚本信息 * @method getInfo * @return {Object} 脚本信息对象 */ getInfo() { return { version: GM_info.script.version, author: 'HLD', github: 'https://github.com/kisshang1993/NGA-BBS-Script', update: 'https://greasyfork.org/zh-CN/scripts/393991-nga%E4%BC%98%E5%8C%96%E6%91%B8%E9%B1%BC%E4%BD%93%E9%AA%8C' } } } /* 注册菜单按钮 */ try { // 设置面板 GM_registerMenuCommand('设置面板', function () { $('#hld__setting_cover').css('display', 'block') $('html, body').animate({scrollTop: 0}, 500) }) // 清理缓存 GM_registerMenuCommand('清理缓存', function () { if (window.confirm('此操作为清理Local Storage与IndexedDB部分缓存内容,不会清理配置\n\n继续请点击【确定】')) { script.deleteValue('hld__NGA_post_author') localforage.clear() alert('操作成功,请刷新页面重试') } }) // 修复脚本 GM_registerMenuCommand('修复脚本', function () { if (window.confirm('如脚本运行失败或无效,尝试修复脚本,这会清除脚本的所有数据\n* 数据包含配置,各种名单等\n* 此操作不可逆转,请谨慎操作\n\n继续请点击【确定】')) { try { GM_listValues().forEach(key => GM_deleteValue(key)) } catch {} // 兼容性代码: 计划将在5.0之后废弃 window.localStorage.clear() alert('操作成功,请刷新页面重试') } }) // 反馈问题 GM_registerMenuCommand('反馈问题', function () { if (window.confirm('如脚本运行失败而且修复后也无法运行,请反馈问题报告\n* 问题报告请包含使用的: [浏览器],[脚本管理器],[脚本版本]\n* 描述问题最好以图文并茂的形式\n* 如脚本运行失败,建议提供F12控制台的红色错误输出以辅助排查\n\n默认打开的为Greasy Fork的反馈页面,有能力最好去Github Issue反馈问题,可以获得优先处理\n\n即将打开反馈页面,继续请点击【确定】')) { window.open('https://greasyfork.org/zh-CN/scripts/393991-nga%E4%BC%98%E5%8C%96%E6%91%B8%E9%B1%BC%E4%BD%93%E9%AA%8C/feedback') } }) } catch (e) { // 不支持此命令 console.warn(`【NGA Script】警告: 此脚本管理器不支持菜单按钮,可能会导致新特性无法正常使用,建议更改脚本管理器为 Tampermonkey[https://www.tampermonkey.net/] 或 Violentmonkey[https://violentmonkey.github.io/]`) } /* 标准模块 */ /** * 设置模块 * @name SettingPanel * @description 提供脚本的设置面板,提供配置修改,保存等基础功能 */ const SettingPanel = { name: 'SettingPanel', title: '设置模块', initFunc() { //设置面板 let $panelDom = $(` <div id="hld__setting_cover" class="animated zoomIn"> <div id="hld__setting_panel"> <a href="javascript:void(0)" id="hld__setting_close" class="hld__setting-close" close-type="hide">×</a> <p class="hld__sp-title"><a title="更新地址" href="https://greasyfork.org/zh-CN/scripts/393991-nga%E4%BC%98%E5%8C%96%E6%91%B8%E9%B1%BC%E4%BD%93%E9%AA%8C" target="_blank">NGA优化摸鱼体验<span class="hld__script-info">v${script.getInfo().version}</span></a></p> <div class="hld__field"> <p class="hld__sp-section">显示优化</p> <div id="hld__normal_left"></div> </div> <div class="hld__field"> <p class="hld__sp-section">功能增强</p> <div id="hld__normal_right"></div> </div> <div style="clear:both"></div> <div class="hld__advanced-setting"> <button id="hld__advanced_button">+</button><span>高级设置</span> <div class="hld__advanced-setting-panel"> <p><svg t="1590560820184" class="icon" viewBox="0 0 1040 ####" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2738" width="200" height="200"><path d="M896.355855 975.884143 127.652332 975.884143c-51.575656 0-92.993974-19.771299-113.653503-54.238298-20.708648-34.515095-18.194384-79.5815 6.9022-123.5632L408.803663 117.885897c25.244964-44.376697 62.767556-69.77004 102.953813-69.77004 40.136116 0 77.658707 25.393343 103.002932 69.671803L1003.006873 798.131763c25.097608 44.030819 27.711132 89.049129 6.952342 123.514081C989.348806 956.159916 947.881368 975.884143 896.355855 975.884143L896.355855 975.884143 896.355855 975.884143 896.355855 975.884143 896.355855 975.884143zM511.805572 119.511931c-12.769838 0-27.414373 12.376888-39.298028 33.134655L84.656075 832.892451c-12.130272 21.350261-14.989389 40.530089-7.741311 52.611242 7.297197 12.08013 25.787316 19.033495 50.737568 19.033495l768.703523 0c24.997324 0 43.439348-6.903224 50.736545-19.033495 7.197936-12.031011 4.387937-31.210839-7.791453-52.5611L551.055504 152.646586C539.220968 131.888819 524.527314 119.511931 511.805572 119.511931L511.805572 119.511931 511.805572 119.511931 511.805572 119.511931 511.805572 119.511931zM512.004093 653.807726c-20.1182 0-36.488029-15.975856-36.488029-35.69906L475.516064 296.773124c0-19.723204 16.369829-35.698037 36.488029-35.698037 20.117177 0 36.485983 15.975856 36.485983 35.698037l0 321.335543C548.490076 637.832893 532.12127 653.807726 512.004093 653.807726L512.004093 653.807726 512.004093 653.807726 512.004093 653.807726zM511.757476 828.308039c31.359218 0 56.851822-24.950252 56.851822-55.717999s-25.491581-55.716976-56.851822-55.716976c-31.408337 0-56.851822 24.949228-56.851822 55.716976S480.349139 828.308039 511.757476 828.308039L511.757476 828.308039 511.757476 828.308039 511.757476 828.308039z" p-id="2739"></path></svg> 鼠标停留在<span class="hld__help" title="详细描述">选项文字</span>上可以显示详细描述,设置有误可能会导致插件异常或者无效!</p> <table id="hld__advanced_left"></table> <table id="hld__advanced_right"></table> </div> </div> <div class="hld__buttons"> <span id="hld_setting_panel_buttons"></span> <span> <button class="hld__btn" id="hld__save__data">保存设置</button> </span> </div> </div> </div> `) const insertDom = setting => { if (setting.type === 'normal') { $panelDom.find(`#hld__normal_${setting.menu || 'left'}`).append(` <p><label ${setting.desc ? 'class="hld__help" help="'+setting.desc+'"' : ''}><input type="checkbox" id="hld__cb_${setting.key}"> ${setting.title || setting.key}${setting.shortCutCode ? '(快捷键切换[<b>'+script.getModule('ShortCutKeys').getCodeName(setting.rewriteShortCutCode || setting.shortCutCode)+'</b>])' : ''}</label></p> `) if (setting.extra) { $panelDom.find(`#hld__cb_${setting.key}`).attr('enable', `hld__${setting.key}_${setting.extra.mode || 'fold'}`) $panelDom.find(`#hld__normal_${setting.menu || 'left'}`).append(` <div class="hld__sp-${setting.extra.mode || 'fold'}" id="hld__${setting.key}_${setting.extra.mode || 'fold'}" data-id="hld__${setting.key}"> <p><button id="${setting.extra.id}">${setting.extra.label}</button></p> </div> `) } } if (setting.type === 'advanced') { let formItem = '' const valueType = typeof setting.default if (valueType === 'boolean') { formItem = `<input type="checkbox" id="hld__adv_${setting.key}">` } if (valueType === 'number') { formItem = `<input type="number" id="hld__adv_${setting.key}">` } if (valueType === 'string') { if (setting.options) { let t = '' for (const option of setting.options) { t += `<option value="${option.value}">${option.label}</option>` } formItem = `<select id="hld__adv_${setting.key}">${t}</select>` } else { formItem = `<input type="text" id="hld__adv_${setting.key}">` } } $panelDom.find(`#hld__advanced_${setting.menu || 'left'}`).append(` <tr> <td><span class="hld__help" help="${setting.desc || ''}">${setting.title || setting.key}</span></td> <td>${formItem}</td> </tr>`) } } for (const module of script.modules) { if (module.setting && module.setting.key) { insertDom(module.setting) } if (module.settings) { for (const setting of module.settings) { setting.key && insertDom(setting) } } } /** * Bind:Mouseover Mouseout * 提示信息Tips */ $('body').on('mouseover', '.hld__help', function(e){ if (!$(this).attr('help')) return const $help = $(`<div class="hld__help-tips">${$(this).attr('help').replace(/\n/g, '<br>')}</div>`) $help.css({ top: ($(this).offset().top + $(this).height() + 5) + 'px', left: $(this).offset().left + 'px' }) $('body').append($help) }).on('mouseout', '.hld__help', ()=>$('.hld__help-tips').remove()) $('body').append($panelDom) //本地恢复设置 //基础设置 for (let k in script.setting.normal) { if ($('#hld__cb_' + k).length > 0) { $('#hld__cb_' + k)[0].checked = script.setting.normal[k] const enableDomID = $('#hld__cb_' + k).attr('enable') if (enableDomID) { script.setting.normal[k] ? $('#' + enableDomID).show() : $('#' + enableDomID).hide() $('#' + enableDomID).find('input').each(function () { $(this).val() == script.setting.normal[$(this).attr('name').substring(8)] && ($(this)[0].checked = true) }) $('#hld__cb_' + k).on('click', function () { $(this)[0].checked ? $('#' + enableDomID).slideDown() : $('#' + enableDomID).slideUp() }) } } } //高级设置 for (let k in script.setting.advanced) { if ($('#hld__adv_' + k).length > 0) { const valueType = typeof script.setting.advanced[k] if (valueType == 'boolean') { $('#hld__adv_' + k)[0].checked = script.setting.advanced[k] } if (valueType == 'number' || valueType == 'string') { $('#hld__adv_' + k).val(script.setting.advanced[k]) } } } /** * Bind:Click * 设置面板-展开切换高级设置 */ $('body').on('click', '#hld__advanced_button', function () { if ($('.hld__advanced-setting-panel').is(':hidden')) { $('.hld__advanced-setting-panel').css('display', 'flex') $(this).text('-') } else { $('.hld__advanced-setting-panel').css('display', 'none') $(this).text('+') } }) /** * Bind:Click * 关闭面板(通用) */ $('body').on('click', '.hld__list-panel .hld__setting-close', function () { if ($(this).attr('close-type') == 'hide') { $(this).parent().hide() } else { $(this).parent().remove() } }) /** * Bind:Click * 保存配置 */ $('body').on('click', '#hld__save__data', () => { script.saveSetting() $('#hld__setting_cover').fadeOut(200) }) }, renderAlwaysFunc() { if($('.hld__setting-box').length == 0) { $('#startmenu > tbody > tr > td.last').append('<div><div class="item hld__setting-box"></div></div>') let $entry = $('<a id="hld__setting" title="打开NGA优化摸鱼插件设置面板">NGA优化摸鱼插件设置</a>') $entry.click(()=>{ $('#hld__setting_cover').css('display', 'block') $('html, body').animate({scrollTop: 0}, 500) }) $('#hld__setting_close').click(()=>$('#hld__setting_cover').fadeOut(200)) $('.hld__setting-box').append($entry) } }, addButton(button) { const $button = $(`<button class="hld__btn" id="${button.id}" title="${button.desc}">${button.title}</button>`) if (typeof button.click == 'function') { $button.on('click', function() { button.click($(this)) }) } $('#hld_setting_panel_buttons').append($button) }, style: ` .animated {animation-duration:.3s;animation-fill-mode:both;} .animated-1s {animation-duration:1s;animation-fill-mode:both;} .zoomIn {animation-name:zoomIn;} .bounce {-webkit-animation-name:bounce;animation-name:bounce;-webkit-transform-origin:center bottom;transform-origin:center bottom;} .fadeInUp {-webkit-animation-name:fadeInUp;animation-name:fadeInUp;} #loader {display:none;position:absolute;top:50%;left:50%;margin-top:-10px;margin-left:-10px;width:20px;height:20px;border:6px dotted #FFF;border-radius:50%;-webkit-animation:1s loader linear infinite;animation:1s loader linear infinite;} @keyframes loader {0% {-webkit-transform:rotate(0deg);transform:rotate(0deg);}100% {-webkit-transform:rotate(360deg);transform:rotate(360deg);}} @keyframes zoomIn {from {opacity:0;-webkit-transform:scale3d(0.3,0.3,0.3);transform:scale3d(0.3,0.3,0.3);}50% {opacity:1;}} @keyframes bounce {from,20%,53%,80%,to {-webkit-animation-timing-function:cubic-bezier(0.215,0.61,0.355,1);animation-timing-function:cubic-bezier(0.215,0.61,0.355,1);-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);}40%,43% {-webkit-animation-timing-function:cubic-bezier(0.755,0.05,0.855,0.06);animation-timing-function:cubic-bezier(0.755,0.05,0.855,0.06);-webkit-transform:translate3d(0,-30px,0);transform:translate3d(0,-30px,0);}70% {-webkit-animation-timing-function:cubic-bezier(0.755,0.05,0.855,0.06);animation-timing-function:cubic-bezier(0.755,0.05,0.855,0.06);-webkit-transform:translate3d(0,-15px,0);transform:translate3d(0,-15px,0);}90% {-webkit-transform:translate3d(0,-4px,0);transform:translate3d(0,-4px,0);}} @keyframes fadeInUp {from {opacity:0;-webkit-transform:translate3d(-50%,100%,0);transform:translate3d(-50%,100%,0);}to {opacity:1;-webkit-transform:translate3d(-50%,0,0);transform:translate3d(-50%,0,0);}} .hld__msg{display:none;position:fixed;top:10px;left:50%;transform:translateX(-50%);color:#fff;text-align:center;z-index:99###;padding:10px 30px 10px 45px;font-size:16px;border-radius:10px;background-image:url("${SVG_ICON_MSG}");background-size:25px;background-repeat:no-repeat;background-position:15px} .hld__msg a{color:#fff;text-decoration: underline;} .hld__msg-ok{background:#4bcc4b} .hld__msg-err{background:#c33} .hld__msg-warn{background:#FF9900} .hld__flex{display:flex;} .hld__float-left{float: left;} .clearfix {clear: both;} #hld__noti_container {position:fixed;top:10px;left:10px;z-index:99;} .hld__noti-msg {display:none;padding:10px 20px;font-size:14px;font-weight:bold;color:#fff;margin-bottom:10px;background:rgba(0,0,0,0.6);border-radius:10px;cursor:pointer;} .hld__btn-groups {display:flex;justify-content:center !important;margin-top:10px;} button.hld__btn {padding:3px 8px;border:1px solid #591804;background:#fff8e7;color:#591804;} button.hld__btn:hover {background:#591804;color:#fff0cd;} button.hld__btn[disabled] {opacity:.5;} #hld__updated {position:fixed;top:20px;right:20px;width:230px;padding:10px;border-radius:5px;box-shadow:0 0 15px #666;border:1px solid #591804;background:#fff8e7;z-index: 9999;} #hld__updated .hld__readme {text-decoration:underline;color:#591804;} .hld__script-info {margin-left:4px;font-size:70%;color:#666;} #hld__setting {color:#6666CC;cursor:pointer;} #hld__setting_cover {display:none;padding-top: 70px;position:absolute;top:0;left:0;right:0;bottom:0;z-index:999;} #hld__setting_panel {position:relative;background:#fff8e7;width:600px;left: 50%;transform: translateX(-50%);padding:15px 20px;border-radius:10px;box-shadow:0 0 10px #666;border:1px solid #591804;} #hld__setting_panel > div.hld__field {float:left;width:50%;} #hld__setting_panel p {margin-bottom:10px;} #hld__setting_panel .hld__sp-title {font-size:15px;font-weight:bold;text-align:center;} #hld__setting_panel .hld__sp-section {font-weight:bold;margin-top:20px;} .hld__setting-close {position:absolute;top:5px;right:5px;padding:3px 6px;background:#fff0cd;color:#591804;transition:all .2s ease;cursor:pointer;border-radius:4px;text-decoration:none;z-index:9999;} .hld__setting-close:hover {background:#591804;color:#fff0cd;text-decoration:none;} #hld__setting_panel button {transition:all .2s ease;cursor:pointer;} .hld__advanced-setting {border-top: 1px solid #e0c19e;border-bottom: 1px solid #e0c19e;padding: 3px 0;margin-top:25px;} .hld__advanced-setting >span {font-weight:bold} .hld__advanced-setting >button {padding: 0px;margin-right:5px;width: 18px;text-align: center;} .hld__advanced-setting-panel {display:none;padding:5px 0;flex-wrap: wrap;} .hld__advanced-setting-panel>p {width:100%;} .hld__advanced-setting-panel>table {width:50%;} .hld__advanced-setting-panel>p {margin: 7px 0 !important;font-weight:bold;} .hld__advanced-setting-panel>p svg {height:16px;width:16px;vertical-align: top;margin-right:3px;} .hld__advanced-setting-panel>table td {padding-right:10px} .hld__advanced-setting-panel input[type=text],.hld__advanced-setting-panel input[type=number] {width:80px} .hld__advanced-setting-panel input[type=number] {border: 1px solid #e6c3a8;box-shadow: 0 0 2px 0 #7c766d inset;border-radius: 0.25em;} .hld__help {cursor:help;text-decoration: underline;} .hld__buttons {clear:both;display:flex;justify-content:space-between;padding-top:15px;} button.hld__btn {padding:3px 8px;border:1px solid #591804;background:#fff8e7;color:#591804;} button.hld__btn:hover {background:#591804;color:#fff0cd;} .hld__sp-fold {padding-left:23px;} .hld__sp-fold .hld__f-title {font-weight:bold;} .hld__help-tips {position: absolute;padding: 5px 10px;background: rgba(0,0,0,.8);color: #FFF;border-radius: 5px;z-index: 9999;} ` } /** * 快捷键模块 * @name ShortCutKeys * @description 为模块提供快捷键切换的能力,提供修改,保存快捷键等 */ const ShortCutKeys = { name: 'ShortCutKeys', title: '快捷键支持', setting: { type: 'advanced', key: 'dynamicEnable', default: true, title: '动态功能启用', desc: '此配置表示部分可以快捷键切换的功能默认行为策略\n选中时: 关闭功能(如隐藏头像)也可以通过快捷键切换显示/隐藏\n取消时: 关闭功能(如隐藏头像)将彻底关闭功能,快捷键会失效', menu: 'left' }, preProcFunc() { script.setting.normal.shortcutKeys = [] }, initFunc() { const _this = this // 添加到配置面板的设置入口 script.getModule('SettingPanel').addButton({ id: 'hld__shortcut_manage', title: '编辑快捷键', desc: '编辑快捷键' }) /** * Bind:keyup * 注册监听按键 */ $('body').keyup(event => { if (/textarea|select|input/i.test(event.target.nodeName) || /text|password|number|email|url|range|date|month/i.test(event.target.type)) { return } if (event.ctrlKey || event.altKey || event.shiftKey) return for (const keyCode of script.setting.normal.shortcutKeys) { if (event.keyCode === keyCode) { for (const module of script.modules) { if (module.setting && module.shortcutFunc) { if (module.setting.rewriteShortCutCode) { if (module.setting.rewriteShortCutCode === event.keyCode) { module.shortcutFunc[module.setting.key].call(module) } } else if (module.setting.shortCutCode === event.keyCode) { module.shortcutFunc[module.setting.key].call(module) } } if (module.settings) { for (const setting of module.settings) { if (module.shortcutFunc) { if (setting.rewriteShortCutCode) { if (setting.rewriteShortCutCode === event.keyCode) { module.shortcutFunc[setting.key].call(module) } } else if (setting.shortCutCode === event.keyCode) { module.shortcutFunc[setting.key].call(module) } } } } } } } }) /** * Bind:Click * 快捷键编辑面板 */ $('body').on('click', '#hld__shortcut_manage', () => { if($('#hld__shortcut_panel').length > 0) return let $shortcutPanel = $(`<div id="hld__shortcut_panel" class="hld__list-panel animated fadeInUp"> <a href="javascript:void(0)" class="hld__setting-close">×</a> <div> <div><p><b>编辑快捷键</b></p><div class="hld__float-left"><table class="hld__table hld__table-keyword"><thead><tr><td>功能</td><td width="60">快捷键</td></tr></thead> <tbody></tbody></table></div><div class="hld__float-left hld__shortcut-desc"><p><b>支持的快捷键范围</b></p><p>键盘 <code>A</code>~<code>Z</code></p><p>左箭头 <code>LEFT</code></p><p>右箭头 <code>RIGHT</code></p><p>上箭头 <code>UP</code></p><p>下箭头 <code>DOWN</code></p><p><i>* 留空则取消快捷键</i></p><br><p>如按键异常请尝试重置按键</p> </div> <div class="clearfix"></div></div> </div> <div class="hld__btn-groups"> <button class="hld__btn" id="hld__reset_shortcut">重置按键</button> <button class="hld__btn" id="hld__save_shortcut">保存快捷键</button> </div> </div>`) const insertDom = setting => $shortcutPanel.find('.hld__table tbody').append(`<tr><td>${setting.title || setting.key}</td><td><input type="text" value="${this.getCodeName(setting.rewriteShortCutCode || setting.shortCutCode)}"></td></tr>`) for (const module of script.modules) { if (module.setting && module.setting.shortCutCode) { insertDom(module.setting) } if (module.settings) { for (const setting of module.settings) { if (setting.shortCutCode) { insertDom(setting) } } } } $('#hld__setting_cover').append($shortcutPanel) }) /** * Bind:Click * 重置快捷键 */ $('body').on('click', '#hld__reset_shortcut', () => { const defaultShortcut = [] for (const module of script.modules) { if (module.setting && module.setting.shortCutCode) { defaultShortcut.push(module.setting.shortCutCode) } if (module.settings) { for (const setting of module.settings) { setting.shortCutCode && defaultShortcut.push(setting.shortCutCode) } } } script.setting.normal.shortcutKeys = defaultShortcut script.saveSetting('重置按键成功,刷新页面生效') $('#hld__shortcut_panel').remove() }) /** * Bind:Click * 保存快捷键 */ $('body').on('click', '#hld__save_shortcut', () => { const _this = this let shortcutKeys = [] $('.hld__table tbody>tr').each(function () { const v = $(this).find('input').val().trim().toUpperCase() if (v == '') { shortcutKeys.push(-1) } else { const code = _this.getCodeName(v, 'name') if (code > 0) shortcutKeys.push(code) else script.popMsg(`${v}是个无效的快捷键`, 'err') } }) if (shortcutKeys.length != script.setting.normal.shortcutKeys.length) return script.setting.normal.shortcutKeys = shortcutKeys script.saveSetting('保存按键成功,刷新页面生效') $('#hld__shortcut_panel').remove() }) }, getCodeName(val, valType='code') { const shortcutCode = { 'A': 65, 'B': 66, 'C': 67, 'D': 68, 'E': 69, 'F': 70, 'G': 71, 'H': 72, 'I': 73, 'J': 74, 'K': 75, 'L': 76, 'M': 77, 'N': 78, 'O': 79, 'P': 80, 'Q': 81, 'R': 82, 'S': 83, 'T': 84, 'U': 85, 'V': 86, 'W': 87, 'X': 88, 'Y': 89, 'Z': 90, '0': 48, '1': 49, '2': 50, '3': 51, '4': 52, '5': 53, '6': 54, '7': 55, '8': 56, '9': 57, 'LEFT': 37, 'RIGHT': 39, 'UP': 38, 'DOWN': 40, '': 0, '': -1 } if (valType == 'code') { let keyname = '' for (let [n, c] of Object.entries(shortcutCode)) { c == val && (keyname = n) } return keyname } else { let code = -1 for (let [n, c] of Object.entries(shortcutCode)) { n == val && (code = c) } return code } }, style: ` code {padding:2px 4px;font-size:90%;font-weight:bold;color:#c7254e;background-color:#f9f2f4;border-radius:4px;} .hld__list-panel {position:absolute;top: 100px;left: 50%;background:#fff8e7;padding:15px 20px;border-radius:10px;box-shadow:0 0 10px #666;border:1px solid #591804;z-index:9999;} .hld__list-panel .hld__list-c {width:45%;} .hld__list-panel .hld__list-c textarea {box-sizing:border-box;padding:0;margin:0;height:200px;width:100%;resize:none;} .hld__list-panel .hld__list-desc {margin-top:5px;font-size:9px;color:#666;cursor:help;text-decoration: underline;} .hld__list-panel .hld__list-c > p:first-child {font-weight:bold;font-size:14px;margin-bottom:10px;} .hld__table-keyword {margin-top:10px;width:200px;} .hld__table-keyword tr td:last-child {text-align:center;} .hld__table-keyword input[type=text] {width:48px;text-transform:uppercase;text-align:center;} .hld__table{table-layout:fixed;border-top:1px solid #ead5bc;border-left:1px solid #ead5bc} .hld__table-banlist-buttons{margin-top:10px} .hld__table thead{background:#591804;border:1px solid #591804;color:#fff} .hld__table td,.hld__table th{padding:3px 5px;border-bottom:1px solid #ead5bc;border-right:1px solid #ead5bc;white-space:nowrap;overflow:hidden;text-overflow:ellipsis} .hld__shortcut-desc {width:120px;margin-left:20px;padding-top:6px} .hld__shortcut-desc p {margin-bottom:5px;} ` } /** * 配置备份模块 * @name BackupModule * @description 提供配置的导入,导出功能 */ const BackupModule = { name: 'BackupModule', title: '配置备份', backupItems: [], initFunc() { /** * 导入导出设置面板 */ const _this = this // 在设置面板上添加按钮 script.getModule('SettingPanel').addButton({ id: 'hld__backup_panel', title: '导入/导出', desc: '导入/导出配置字符串,包含设置,黑名单,标记名单等等' }) /** * Bind:Click * 导入导出面板 */ $('body').on('click', '#hld__backup_panel', function () { if($('#hld__export_panel').length > 0) return $('#hld__setting_cover').append(` <div id="hld__export_panel" class="hld__list-panel animated fadeInUp"> <a href="javascript:void(0)" class="hld__setting-close">×</a> <div class="hld__ep-container"> <div> <p><b>选择导出的设置</b></p> <div id="hld__export_panel_cb"> <p><label><input type="checkbox" id="hld__cb_export_setting" checked="checked"> 配置</label></p> </div> <br> <p><button id="hld__export__data">导出</button> <button id="hld__import__data">导入</button></p> </div> <div> <p> <b class="hld__help" help="【导出】\n选择要导出的内容,点击导出,复制以下字符串用于备份,分享等\n【导入】\n将字符串复制到以下输入框中,点击导入,将会自动导入字符串中包含的内容">字符串</b> <label><input type="checkbox" id="hld__cb_export_encode" checked="checked"> Base64编码</label> </p> <textarea id="hld__export_str" rows="9"></textarea> <p><a href="https://greasyfork.org/zh-CN/scripts?q=NGA%E4%BC%98%E5%8C%96%E6%91%B8%E9%B1%BC%E4%BD%93%E9%AA%8C%E6%8F%92%E4%BB%B6" target="_blank">使用WebDAV进行配置同步</a></p> </div> </div> <div><p id="hld__export_msg"></p></div> </div> `) // 加载其他模组备份项 for (const item of _this.backupItems) { $('#hld__export_panel_cb').append(` <p><label><input type="checkbox" id="hld__cb_export_${item.writeKey}" checked="checked"> ${item.title}</label></p> `) } /** * Bind:Click * 导出配置 */ $('#hld__export__data').click(function(){ let exportItems = [] // 基础配置 if ($('#hld__cb_export_setting').prop('checked')) { exportItems.push('setting') } // 其他模组备份项 for (const item of _this.backupItems) { const $c = $(`#hld__cb_export_${item.writeKey}`) if ($c.length > 0 && $c.prop('checked')) { exportItems.push(item.writeKey) } } if (Object.keys(exportItems).length == 0) { $('#hld__export_msg').html('<span style="color:#CC0000">没有选择任何项目可供导出!</span>') return } const backupB64 = _this.export(exportItems, $('#hld__cb_export_encode').prop('checked')) $('#hld__export_str').val(backupB64) $('#hld__export_msg').html(`<span style="color:#009900">导出成功(${_this.calculateSize(backupB64.length)}),请复制右侧字符串以备份</span>`) }) /** * Bind:Click * 导入配置 */ $('#hld__import__data').click(function(){ const dataStr = $('#hld__export_str').val() if (dataStr) { try { const importStatus = _this.import(dataStr, $('#hld__cb_export_encode').prop('checked')) importStatus && $('#hld__export_msg').html('<span style="color:#009900">导入成功,刷新浏览器以生效</span>') } catch (err){ script.printLog(`JSON解析失败: ${err}`) $('#hld__export_msg').html('<span style="color:#CC0000">字符串有误,解析失败!</span>') } } }) }) }, addItem(item) { this.backupItems.push(item) }, // 字符串版本转数字 vstr2num(str) { let num = 0 str.split('.').forEach((n, i) => num += i < 2 ? +n * 1000 / Math.pow(10, i) : +n) return num }, calculateSize(num) { if (num == 0) return '0 B' let k = #### let sizeStr = ['B','KB','MB','GB'] let i = 0 for(let l=0;l<8;l++){ if(num / Math.pow(k, l) < 1) break i = l } return (num / Math.pow(k, i)).toFixed(2) + ' ' + sizeStr[i] }, export(items, encode=true) { const exportData = { name: 'NGA-BBS-SCRIPT', ver: script.getInfo().version, exportDate: new Date().toLocaleString(), timestamp: new Date().getTime() } Array.isArray(items) || (items = [items]) // 基础配置 if (items.includes('setting') || items.includes('*')) { exportData['setting'] = script.setting.normal exportData['advanced_setting'] = script.setting.advanced } // 其他模组备份项 for (const item of this.backupItems) { if (items.includes(item.writeKey) || items.includes('*')) { exportData[item.writeKey] = item.module[item.valueKey] } } const exportDataStr = JSON.stringify(exportData) return encode ? this.Base64.encode(exportDataStr) : exportDataStr }, import(dataStr, isEncode=true) { dataStr = isEncode ? this.Base64.decode(dataStr) : dataStr let obj = JSON.parse(dataStr) const unsupported = '3.3.0' const currentVer = script.getInfo().version const objVer = this.vstr2num(obj.ver) if (objVer != 0 && objVer > this.vstr2num(currentVer)) { script.popMsg(`此配置是由更高版本(v${obj.ver})的脚本导出,请升级您的脚本 <a title="更新地址" href="https://greasyfork.org/zh-CN/scripts/393991-nga%E4%BC%98%E5%8C%96%E6%91%B8%E9%B1%BC%E4%BD%93%E9%AA%8C" target="_blank">[脚本地址]</a>`, 'warn') return } if (objVer != 0 && objVer < this.vstr2num(unsupported)) { script.popMsg(`此配置是由低版本(v${obj.ver})的脚本导出,当前版本(v${currentVer})已不支持!`, 'err') return } let confirm = window.confirm('此操作会覆盖你的配置,确认吗?') if (!confirm) return if (Object.keys(obj).includes('setting')) { obj.setting && (script.setting.normal = obj.setting) obj.advanced_setting && (script.setting.advanced = obj.advanced_setting) script.setValue('hld__NGA_setting', JSON.stringify(script.setting.normal)) script.setValue('hld__NGA_advanced_setting', JSON.stringify(script.setting.advanced)) } // 其他模组备份项 for (const item of this.backupItems) { if (Object.keys(obj).includes(item.writeKey)) { item.module[item.valueKey] = obj[item.writeKey] script.setValue(`hld__NGA_${item.writeKey}`, JSON.stringify(obj[item.writeKey])) } } script.popMsg('导入成功,刷新页面生效') return true }, /** * Base64互转 */ Base64: { encode: (str) => { return window.btoa(unescape(encodeURIComponent(str))) }, decode: (str) => { return decodeURIComponent(escape(window.atob(str))) } }, style: ` .hld__ep-container{display:flex;width:300px;margin-bottom: 7px;} .hld__ep-container p {margin-bottom:10px;} .hld__ep-container >div{width:50%;} .hld__ep-container textarea {width: 100%;padding:0;margin:0;resize:none;} ` } /** * 赏面板 * @name RewardPanel * @description 别问,好活当赏 */ const RewardPanel = { name: 'RewardPanel', title: '赏面板', initFunc() { /** * 打赏 */ script.getModule('SettingPanel').addButton({ id: 'hld__reward', title: '<span style="margin-right:3px">¥</span>赏', desc: '好活当赏' }) /** * Bind:Click * 打赏面板 */ $('body').on('click', '#hld__reward', function () { $('#hld__setting_cover').append(` <div class="hld__list-panel hld__reward-panel animated fadeInUp"> <a href="javascript:void(0)" class="hld__setting-close">×</a> <div class="hld__reward-info"> <p><b>喜欢此脚本请可以去作者<a href="${script.getInfo().github}" target="_blank"><b>Github</b></a>点个⭐️</p> <p>如果觉得脚本好用<span class="hld__delete-line">摸到鱼了</span>,也可以请作者喝杯☕意思意思,打多少零看缘分😎</p> <p>如若有功能需求或者建议,欢迎在社区进行反馈</p> </div> <div class="hld__flex"> <div class="hld__list-c"><img src="${IMG_REWARD_ALIPAY}"></div> <div class="hld__list-c"><img src="${IMG_REWARD_WXPAY}"></div> </div> <div class="hld__source"> <a href="${script.getInfo().github}" target="_blank"><img alt="Mozilla Add-on" src="https://img.shields.io/github/stars/kisshang1993/NGA-BBS-Script?label=Star&style=social"></a> <a href="${script.getInfo().update}" target="_blank"><img alt="Mozilla Add-on" src="https://img.shields.io/badge/Greasy%20Fork-NGA优化摸鱼体验-brightgreen"></a> </div> </div> `) }) }, style: ` .hld__reward-panel {width:500px;} .hld__reward-panel .hld__reward-info {display:block;font-size:15px;margin-bottom:20px;line-height:20px;} .hld__reward-panel .hld__reward-info p {margin-bottom:5px;} .hld__delete-line {text-decoration:line-through;color:#666;} .hld__reward-panel .hld__list-c {width:50%;} .hld__reward-panel .hld__list-c:first-child {margin-right:15px;} .hld__reward-panel .hld__list-c>img {width:100%;height:auto;} .hld__reward-panel .hld__source {margin-top:15px;} .hld__reward-panel .hld__source > a {margin-right:10px;} ` } /** * 隐藏头像模块 * @name HideAvatar * @description 此模块提供了可以快捷键切换显示隐藏头像 */ const HideAvatar = { name: 'HideAvatar', title: '隐藏头像', setting: { shortCutCode: 81, // Q type: 'normal', key: 'hideAvatar', default: true, title: '隐藏头像', menu: 'left' }, renderFormsFunc($el) { if (script.setting.normal.hideAvatar) { $el.find('.avatar, .avatar+img').css('display', 'none') $el.find('.c1').css('background-image', 'none') } }, shortcutFunc: { hideAvatar() { if (script.setting.normal.hideAvatar || script.setting.advanced.dynamicEnable) { $('.avatar, .avatar+img').toggle() script.popNotification(`${$('.avatar:hidden').length == 0 ? '显示' : '隐藏'}头像`) } } }, asyncStyle() { return ` .posterinfo .avatar+img {display:${script.setting.normal.hideAvatar ? 'none' : 'inline'};} ` } } /** * 隐藏头像模块 * @name HideSmile * @description 此模块提供了可以快捷键切换显示隐藏表情 * 其中隐藏的表情会用文字来替代 */ const HideSmile = { name: 'HideSmile', title: '隐藏头像', setting: { shortCutCode: 87, // W type: 'normal', key: 'hideSmile', default: false, title: '隐藏表情', menu: 'left' }, renderFormsFunc($el) { $el.find('.c2 img').each(function () { const classs = $(this).attr('class') if (classs && classs.includes('smile') && !$(this).is(':hidden')) { const alt = $(this).attr('alt') const $alt = $('<span class="smile_alt_text">[' + alt + ']</span>') script.setting.normal.hideSmile ? $(this).hide() : $alt.hide() $(this).after($alt) } }) }, shortcutFunc: { hideSmile() { if (script.setting.normal.hideSmile || script.setting.advanced.dynamicEnable) { $('.c2 img').each(function () { const classs = $(this).attr('class'); if (classs && classs.includes('smile')) $(this).toggle() }) $('.smile_alt_text').toggle() script.popNotification(`${$('.smile_alt_text:hidden').length > 0 ? '显示' : '隐藏'}表情`) } } } } /** * 贴内图片缩放模块 * @name ImgResize * @description 此模块提供了可以调整贴内图片的尺寸 */ const ImgResize = { name: 'ImgResize', title: '贴内图片缩放', settings: [{ type: 'normal', key: 'imgResize', title: '贴内图片缩放', default: true, menu: 'left' }, { type: 'advanced', key: 'imgResizeWidth', default: 200, title: '图片缩放宽度', desc: '贴内图片缩放的宽度,高度自适应,单位px', menu: 'left' }], renderFormsFunc($el) { $el.find('.c2 img').each(function () { const classs = $(this).attr('class') if ((!classs || !classs.includes('smile')) && script.setting.normal.imgResize) { $(this).addClass('hld__img-resize').attr('hld-img-resize', 'ok').attr('title', '点击大图显示') } }) }, asyncStyle: () => { return ` .hld__img-resize {outline:none !important;outline-offset:'';cursor:alias;min-width:auto !important;min-height:auto !important;max-width:${script.setting.advanced.imgResizeWidth || 200}px !important;max-height:none !important;margin:5px;} ` } } /** * 隐藏图片模块 * @name HideImage * @description 此模块提供了可以快捷键切换显示隐藏图片 * 其中隐藏的图片会用一个按钮来替代 */ const HideImage = { name: 'HideImage', title: '隐藏图片', setting: { shortCutCode: 69, // E type: 'normal', key: 'hideImage', default: false, title: '隐藏贴内图片', menu: 'left' }, renderFormsFunc($el) { $el.find('.c2 img').each(function () { const classs = $(this).attr('class') if ((!classs || !classs.includes('smile')) && !$(this).is(':hidden')) { $(this).addClass('hld__img-postimg') // 显示原图 $(this).attr('src', $(this).attr('src').replace('.medium.jpg', '')).attr('hld-hideimg', 'ok') let $imgB = $('<button class="switch-img" style="display:none">图</button>') $imgB.on('click', function () { $(this).prev('img').toggle() $(this).text($(this).prev('img').is(':hidden') ? '图' : '隐藏') }) if (script.setting.normal.hideImage) { $(this).hide(); $imgB.show() } $(this).after($imgB) } }) }, shortcutFunc: { hideImage() { if (!script.setting.advanced.dynamicEnable) return if ($('.hld__img-postimg:hidden').length < $('.switch-img').length) { $('.hld__img-postimg').hide() $('.switch-img').text('图').show() script.popNotification(`隐藏图片`) return } $('.hld__img-postimg').each(function () { $(this).toggle() $(this).is(':hidden') ? $(this).next('button.switch-img').show() : $(this).next('button.switch-img').hide() }) script.popNotification(`${$('.switch-img:hidden').length > 0 ? '显示' : '隐藏'}图片`) } } } /** * 隐藏签名模块 * @name HideSign * @description 此模块提供了可以配置默认隐藏签名 */ const HideSign = { name: 'HideSign', title: '隐藏签名', setting: { type: 'normal', key: 'hideSign', default: true, title: '隐藏签名', menu: 'left' }, renderFormsFunc($el) { script.setting.normal.hideSign && $el.find('.sign, .sigline').css('display', 'none') } } /** * 隐藏图片模块 * @name HideHeader * @description 此模块提供了可以配置默认隐藏版头 * 以及一个高级配置可选一起隐藏顶部背景 */ const HideHeader = { name: 'HideHeader', title: '隐藏图片', settings: [{ type: 'normal', key: 'hideHeader', default: true, title: '隐藏版头/版规/子版入口', menu: 'left' }, { type: 'advanced', key: 'hideCustomBg', default: true, title: '隐藏背景图片', desc: '选中时: 隐藏版头的同时顶部背景图片\n取消时: 无操作', menu: 'right' }], renderAlwaysFunc($el) { //隐藏版头 if (script.setting.normal.hideHeader && $('#hld__switch_header').length == 0) { $('#toppedtopic').hide() $('#toppedtopic').length > 0 && $('#sub_forums').hide() let $toggleHeaderBtn = $('<button style="position: absolute;right: 16px;" id="hld__switch_header">切换显示版头</button>') $toggleHeaderBtn.click(() => $('#toppedtopic, #sub_forums').toggle()) $('#toptopics > div > h3').append($toggleHeaderBtn) } if(script.setting.normal.hideHeader && script.setting.advanced.hideCustomBg) { $('#custombg').hide() $('#mainmenu').css('margin', '0px') } }, style: ` #m_threads .toptopicsRight {float:none;width:auto;} .topicrowsLeftC {margin-right:0;} ` } /** * Excel模块 * @name ExcelMode * @description 此模块提供了可以快捷键切换Excel模式 * 以及一个高级配置可选更改Excel左侧序号的类型 */ const ExcelMode = { name: 'ExcelMode', title: 'Excel模式', settings: [{ shortCutCode: 82, // R type: 'normal', key: 'excelMode', default: false, title: 'Excel模式', menu: 'left' }, { type: 'advanced', key: 'excelTheme', default: 'tencent', options: [{ label: '腾讯文档', value: 'tencent' }, { label: 'WPS', value: 'wps' }, { label: 'Office', value: 'office' }], title: 'Excel皮肤', desc: 'Excel的皮肤\n腾云文档是矢量图形绘制,适应各种分辨率,不会失真,推荐优先使用\nWPS与Office为图片拼接而成,分辨率为1080P,高于此分辨率可能会失真', menu: 'left' }, { type: 'advanced', key: 'excelNoMode', default: false, title: 'Excel左列序号', desc: 'Excel最左列的显示序号,此策略为尽可能的更像Excel\n选中时: Excel最左栏为从1开始往下,逐行+1\n取消时: Excel最左栏为原始的回帖数\n*此功能仅在贴列表有效', menu: 'left' }, { type: 'advanced', key: 'excelTitle', default: '工作簿1', title: 'Excel覆盖标题', desc: 'Excel模式下标签栏的名称, 如留空, 则显示原始标题', menu: 'left' }], beforeUrl: window.location.href, initFunc() { // 生成列标题字母列表 const columnLetters = () => { let capital = [] let columnLetters = [] for (let i=65;i<91;i++) capital.push(String.fromCharCode(i)) Array('', 'A', 'B', 'C').forEach(n => capital.forEach(c => columnLetters.push(`${n}${c}`))) return columnLetters } if (script.setting.advanced.excelTheme == 'tencent') { // 腾讯文档元素 // 插入Excel头部 $('body').append(` <div class="hld__excel-div hld__excel-header"> <div class="hld__excel-titlebar"> <div class="hld__excel-titlebar-content hld__excel-icon24" style="margin:2px 2px 2px 10px;background-image:url(${getExcelTheme(script.setting.advanced.excelTheme, 'icon_1')});"></div> <div class="hld__excel-titlebar-content hld__excel-icon12" style="background-image:url(${getExcelTheme(script.setting.advanced.excelTheme, 'icon_2')});"></div> <div style="height: 24px;border-right: 1px solid rgb(0, 0, 0);opacity: 0.06;margin: 0 12px;vertical-align: middle;"></div> <div class="hld__excel-titlebar-title"></div> <div class="hld__excel-titlebar-content hld__excel-icon16" style="margin-left: 10px;background-image:url(${getExcelTheme(script.setting.advanced.excelTheme, 'icon_3')});"></div> <div class="hld__excel-titlebar-content hld__excel-icon16" style="margin-left: 12px;background-image:url(${getExcelTheme(script.setting.advanced.excelTheme, 'icon_4')});"></div> <div class="hld__excel-titlebar-content hld__excel-icon16" style="margin-left: 10px;background-image:url(${getExcelTheme(script.setting.advanced.excelTheme, 'icon_5')});"></div> <div style="margin-left: 5px;font-size: 12px;line-height: 20px;height: 18px;;color: #000;opacity: 0.48;font-weight:400;">上次修改是在2小时前进行的</div> <div style="flex-grow: 1;"></div> <div style="height: 24px;border-right: 1px solid rgb(0, 0, 0);opacity: 0.06;margin: 0 12px;vertical-align: middle;"></div> <div style="width:28px;height:28px;border-radius: 4px;background: #e9e9e9;text-align: center;line-height: 32px;">🐟︎</div> </div> <div class="hld__excel-toolbar"> ${Array.from({length: 4}, (_, i) => '<div class="hld__excel-titlebar-content hld__excel-icon20" style="margin:0 6px;background-image:url(' + getExcelTheme(script.setting.advanced.excelTheme, "icon_"+(10+i)) + ');"></div>').join('')} <div style="height: 16px;border-right: 1px solid rgb(0, 0, 0);opacity: 0.06;margin: 0 4px;vertical-align: middle;"></div> <div class="hld__excel-titlebar-content hld__excel-icon20" style="margin-left: 8px;background-image:url(${getExcelTheme(script.setting.advanced.excelTheme, 'icon_14')});"></div> <div style="padding: 0 2px;">插入</div> <div class="hld__excel-titlebar-content hld__excel-icon12" style="background-image:url(${getExcelTheme(script.setting.advanced.excelTheme, 'icon_2')});"></div> <div style="height: 16px;border-right: 1px solid rgb(0, 0, 0);opacity: 0.06;margin: 0 8px;vertical-align: middle;"></div> <div style="padding: 0 30px 0 4px;">常规</div> <div class="hld__excel-titlebar-content hld__excel-icon12" style="background-image:url(${getExcelTheme(script.setting.advanced.excelTheme, 'icon_2')});"></div> <div class="hld__excel-titlebar-content hld__excel-icon20" style="margin-left: 12px;background-image:url(${getExcelTheme(script.setting.advanced.excelTheme, 'icon_15')});"></div> <div style="margin-left: 1px;"> <div class="hld__excel-titlebar-content hld__excel-icon12" style="transform: rotate(180deg);background-image:url(${getExcelTheme(script.setting.advanced.excelTheme, 'icon_2')});"></div> <div class="hld__excel-titlebar-content hld__excel-icon12" style="background-image:url(${getExcelTheme(script.setting.advanced.excelTheme, 'icon_2')});"></div> </div> <div style="height: 16px;border-right: 1px solid #000;opacity: 0.06;margin: 0 4px;vertical-align: middle;"></div> <div style="padding: 0 4px 0 16px;">默认字体</div> <div class="hld__excel-titlebar-content hld__excel-icon12" style="background-image:url(${getExcelTheme(script.setting.advanced.excelTheme, 'icon_2')});"></div> <div style="padding: 0 4px 0 13px;">10</div> <div class="hld__excel-titlebar-content hld__excel-icon12" style="background-image:url(${getExcelTheme(script.setting.advanced.excelTheme, 'icon_2')});"></div> <div class="hld__excel-titlebar-content hld__excel-icon20" style="margin-left: 10px;background-image:url(${getExcelTheme(script.setting.advanced.excelTheme, 'icon_16')});"></div> <div class="hld__excel-titlebar-pick"> <div class="hld__excel-titlebar-content hld__excel-icon20" style="background-image:url(${getExcelTheme(script.setting.advanced.excelTheme, 'icon_17')});"></div> <div class="hld__excel-titlebar-indication" style="background-color: #000;"></div> </div> <div class="hld__excel-titlebar-content hld__excel-icon12" style="margin-left: 4px;background-image:url(${getExcelTheme(script.setting.advanced.excelTheme, 'icon_2')});"></div> <div class="hld__excel-titlebar-pick"> <div class="hld__excel-titlebar-content hld__excel-icon20" style="background-image:url(${getExcelTheme(script.setting.advanced.excelTheme, 'icon_18')});"></div> <div class="hld__excel-titlebar-indication" style="background-color: #8cddfa;"></div> </div> <div class="hld__excel-titlebar-content hld__excel-icon12" style="margin-left: 4px;background-image:url(${getExcelTheme(script.setting.advanced.excelTheme, 'icon_2')});"></div> <div class="hld__excel-titlebar-content hld__excel-icon20" style="margin-left: 10px;background-image:url(${getExcelTheme(script.setting.advanced.excelTheme, 'icon_19')});"></div> <div class="hld__excel-titlebar-content hld__excel-icon12" style="margin-left: 2px;background-image:url(${getExcelTheme(script.setting.advanced.excelTheme, 'icon_2')});"></div> <div class="hld__excel-titlebar-content hld__excel-icon20" style="margin-left: 10px;background-image:url(${getExcelTheme(script.setting.advanced.excelTheme, 'icon_20')});"></div> <div style="height: 16px;border-right: 1px solid #000;opacity: 0.06;margin: 0 10px;vertical-align: middle;"></div> ${Array.from({length: 4}, (_, i) => '<div class="hld__excel-titlebar-content hld__excel-icon20" style="background-image:url(' + getExcelTheme(script.setting.advanced.excelTheme, "icon_"+(21+i)) + ');"></div><div class="hld__excel-titlebar-content hld__excel-icon12" style="margin-left: 2px;margin-right: '+ (i==3?'0':'10') +'px;background-image:url(' + getExcelTheme(script.setting.advanced.excelTheme, "icon_2") + ');"></div>').join('')} <div style="height: 16px;border-right: 1px solid #000;opacity: 0.06;margin: 0 10px;vertical-align: middle;"></div> <div class="hld__excel-titlebar-content hld__excel-icon20" style="background-image:url(${getExcelTheme(script.setting.advanced.excelTheme, 'icon_25')});"></div> <div class="hld__excel-titlebar-content hld__excel-icon12" style="margin-left: 4px;background-image:url(${getExcelTheme(script.setting.advanced.excelTheme, 'icon_2')});"></div> <div style="height: 16px;border-right: 1px solid #000;opacity: 0.06;margin: 0 10px;vertical-align: middle;"></div> ${Array.from({length: 4}, (_, i) => '<div class="hld__excel-titlebar-content hld__excel-icon20" style="background-image:url(' + getExcelTheme(script.setting.advanced.excelTheme, "icon_"+(26+i)) + ');"></div><div class="hld__excel-titlebar-content hld__excel-icon12" style="margin-left: 2px;margin-right: '+ (i==3?'0':'10') +'px;background-image:url(' + getExcelTheme(script.setting.advanced.excelTheme, "icon_2") + ');"></div>').join('')} <div style="height: 16px;border-right: 1px solid #000;opacity: 0.06;margin: 0 10px;vertical-align: middle;"></div> <div class="hld__excel-titlebar-content hld__excel-icon20" style="margin-left: 10px;background-image:url(${getExcelTheme(script.setting.advanced.excelTheme, 'icon_20')});"></div> <div style="flex-grow: 1;"></div> </div> <div class="hld__excel-formulabar"> <div style="border-right: 1px solid #e0e2e4;color: #777;text-align: center;width: 50px;font-size: 12px;height: 25px;line-height: 25px;font-weight:400;">A1</div> </div> <div class="hld__excel-h4"> <div class="hld__excel-sub"><div></div></div> ${(columnLetters().map(c => '<div class="hld__excel-column">'+c+'</div>')).join('')} </div> </div> `) // 插入Excel尾部 $('body').append(` <div class="hld__excel-div hld__excel-footer"> <div class="hld__excel-icon24" style="margin-left: 10px;background-image:url(${getExcelTheme(script.setting.advanced.excelTheme, 'icon_33')});"></div> <div class="hld__excel-icon24" style="margin-left: 10px;background-image:url(${getExcelTheme(script.setting.advanced.excelTheme, 'icon_34')});"></div> <div class="hld__excel-sheet-tab"> <div class="hld__excel-sheet-name"> <div>工作表1</div> <div class="hld__excel-icon12" style="margin-left: 4px;background-image:url(${getExcelTheme(script.setting.advanced.excelTheme, 'icon_2')});"></div> </div> <div class="hld__excel-sheet-underblock"></div> </div> <div style="flex-grow: 1;"></div> <div class="hld__excel-icon24" style="margin-left: 10px;background-image:url(${getExcelTheme(script.setting.advanced.excelTheme, 'icon_35')});"></div> <div class="hld__excel-icon12" style="margin-left: 2px;background-image:url(${getExcelTheme(script.setting.advanced.excelTheme, 'icon_2')});"></div> <div style="height: 16px;border-right: 1px solid #000;opacity: 0.12;margin: 0 10px;vertical-align: middle;"></div> <div class="hld__excel-icon24" style="background-image:url(${getExcelTheme(script.setting.advanced.excelTheme, 'icon_36')});"></div> <div class="hld__excel-footer-item" style="font-size: 20px;margin-left:20px;">-</div> <div class="hld__excel-footer-item" style="font-weight: 400">100%</div> <div class="hld__excel-footer-item" style="font-size: 20px;">+</div> <div style="width:10px;"></div> </div> `) } else { // WPS与Office元素 // 插入Excel头部 $('body').append(` <div class="hld__excel-div hld__excel-header"> <div class="hld__excel-h1"> <div class="hld__excel-title">${script.setting.advanced.excelTitle || document.title} - Excel</div> <img class="hld__excel-img-h1-l1" src="${getExcelTheme(script.setting.advanced.excelTheme, 'H_L_1')}"> <img class="hld__excel-img-h1-r1" src="${getExcelTheme(script.setting.advanced.excelTheme, 'H_R_1')}"> </div> <div class="hld__excel-h2"> <img class="hld__excel-img-h2-l1" src="${getExcelTheme(script.setting.advanced.excelTheme, 'H_L_2')}"> <img class="hld__excel-img-h2-r1" src="${getExcelTheme(script.setting.advanced.excelTheme, 'H_R_2')}"> </div> <div class="hld__excel-h3"> <img class="hld__excel-img-h3-l1" src="${getExcelTheme(script.setting.advanced.excelTheme, 'H_L_3')}"> <img class="hld__excel-img-h3-r1" src="${getExcelTheme(script.setting.advanced.excelTheme, 'H_R_3')}"> <div class="hld__excel-fx"></div> </div> <div class="hld__excel-h4"> <div class="hld__excel-sub"><div></div></div> ${(columnLetters().map(c => '<div class="hld__excel-column">'+c+'</div>')).join('')} </div> </div> `) // 插入Excel尾部 $('body').append(` <div class="hld__excel-div hld__excel-footer"> <div class="hld__excel-f1"> <img class="hld__excel-img-f1-l1" src="${getExcelTheme(script.setting.advanced.excelTheme, 'F_L_1')}"> <img class="hld__excel-img-f1-r1" src="${getExcelTheme(script.setting.advanced.excelTheme, 'F_R_1')}"> </div> <div class="hld__excel-f2"> <img class="hld__excel-img-fl2" src="${getExcelTheme(script.setting.advanced.excelTheme, 'F_L_2')}"> <img class="hld__excel-img-fr2" src="${getExcelTheme(script.setting.advanced.excelTheme, 'F_R_2')}"> </div> </div> `) } $('#hld__excel_setting').click(()=>$('#hld__setting_cover').css('display', 'block')) $('#mainmenu .half').parent().append($('#mainmenu .half').clone(true).addClass('hld__half-clone').text($('#mainmenu .half').text().replace('你好', ''))) if(script.setting.normal.excelMode) { if(this.beforeUrl.includes('thread.php') || this.beforeUrl.includes('read.php')) { this.switchExcelMode() } } }, renderAlwaysFunc($el) { $('.hld__excel-theme-' + script.setting.advanced.excelTheme).length == 0 && $('body').addClass('hld__excel-theme-' + script.setting.advanced.excelTheme) if(script.setting.normal.excelMode && window.location.href != this.beforeUrl) { this.beforeUrl = window.location.href if(this.beforeUrl.includes('thread.php') || this.beforeUrl.includes('read.php')) { $('.hld__excel-body').length == 0 && $('body').addClass('hld__excel-body') }else { $('.hld__excel-body').length > 0 && $('body').removeClass('hld__excel-body') } $('body').toggleClass('hld__excel-original-no', !script.setting.advanced.excelNoMode) } if(script.setting.normal.excelMode && $('.hld__excel-body').length > 0 && $('#mmc').length == 0) { $('body').addClass('hld__excel-body-err') }else { $('body').removeClass('hld__excel-body-err') } // Excel Title if ($('.hld__excel-body').length > 0) { const excelTitle = script.setting.advanced.excelTitle if (excelTitle) { $(document).attr('title') != excelTitle && $(document).attr('title', excelTitle) } $('.hld__excel-titlebar-title').html(excelTitle || $(document).attr('title')) $('#hld__excel_icon').length == 0 && $('head').append(`<link id= "hld__excel_icon" rel="shortcut icon" type="image/png" href="${IMG_EXCEL_ICON}" />`) } }, renderFormsFunc($el) { $el.find('.postrow>td:first-child').before('<td class="c0"></td>') }, shortcutFunc: { excelMode() { if (script.setting.normal.excelMode || script.setting.advanced.dynamicEnable) { this.switchExcelMode() script.popNotification($('.hld__excel-body').length > 0 ? 'Excel模式' : '普通模式') } } }, /** * 切换Excel模式 * @method switchExcelMode */ switchExcelMode: () => { $('body').toggleClass('hld__excel-body') !script.setting.advanced.excelNoMode && $('body').addClass('hld__excel-original-no') script.setting.normal.darkMode && script.popMsg('Excel模式与暗黑模式不兼容, 请勿重合使用', 'warn') }, style: ` /* WPS风格 */ .hld__excel-body-err {padding-top: 200px} .hld__excel-header, .hld__excel-footer, .hld__excel-setting, .hld__half-clone {display: none;} .hld__excel-header>div, .hld__excel-footer>div {position: relative;box-sizing: border-box;} .hld__excel-header img, .hld__excel-footer img {position: absolute;} .hld__excel-header {border-bottom:1px solid #bbbbbb;} .hld__excel-title {display:none;} .hld__excel-h1 {height:30px;background:#f3f5f8;border-bottom:1px solid #c5cbd6;} .hld__excel-h2 {height:102px;background:#f4f4f4;} .hld__excel-img-h1-l1, .hld__excel-img-h2-l1, .hld__excel-img-f1-l1, .hld__excel-img-fl2 {top:0;left:0;} .hld__excel-img-h1-r1, .hld__excel-img-h2-r1, .hld__excel-img-f1-r1, .hld__excel-img-fr2 {top:0;right:0;} .hld__excel-h3 {height:44px;background:#e8e8e8;box-shadow: inset 0 3px 5px #d9d9d9;} .hld__excel-img-h3-l1 {top:12px;left:0;} .hld__excel-img-h3-r1 {toP:8px;right:0;} .hld__excel-fx {position: absolute;top:12px;left:253px;right:45px;height:24px;box-sizing: border-box;border:1px solid #cccccc;border-radius:4px;background:#ffffff;} .hld__excel-h4 {height:21px;display:flex;overflow: hidden;} .hld__excel-h4 > div {height:21px;border-right:1px solid #c8c8c8;box-sizing:border-box;flex-shrink: 0;} .hld__excel-sub {width:34px;position: relative;} .hld__excel-sub > div {position: absolute;right:4px;bottom:4px;width: 0px;height: 0px;border-top: 6px solid transparent;border-left: 6px solid transparent;border-right: 6px solid #b8b8b8;border-bottom: 6px solid #b8b8b8;} .hld__excel-column {width: 72px;line-height:21px;text-align:center;color:#444444;font-family: sans-serif;font-weight:100;font-size:14px;} .hld__excel-f1 {height:22px;background:#e8e8e8;} .hld__excel-f2 {height:28px;background:#f4f4f4;} .hld__excel-body {background:#fff !important;} .hld__excel-body #mainmenu {position: fixed;top: 5px;right: 75px;width: 425px;z-index: 98;} .hld__excel-body #mainmenu .right {float:none;} .hld__excel-body #mainmenu .stdbtn {background:none;box-shadow:none;} .hld__excel-body #mainmenu .half {display:none;} .hld__excel-body #mainmenu .hld__half-clone {display:block;width: 150px;text-align: right;overflow: hidden;text-overflow:ellipsis;white-space: nowrap;} .hld__excel-body #mainmenu .half {color:#f4f4f4 !important;} .hld__excel-body #mainmenu .stdbtn a:hover {background:none;text-decoration:underline;color:#2c5787 !important;} .hld__excel-body #mainmenu .mmdefault.cell input {padding:0;margin:0;background:#ededed;border:1px solid #c9d0dc;border-radius:10px;box-shadow:none;font-size:13px !important;} .hld__excel-body #mainmenu, .hld__excel-body #mainmenu .half, .hld__excel-body #mainmenu td a, .hld__excel-body #mainmenu .stdbtn .innerbg, .hld__excel-body #mainmenu, .hld__excel-body #mainmenu .stdbtn a, .hld__excel-body #mainmenu .stdbtn .td {height: 20px !important;line-height: 20px !important;padding: 0 5px !important;background:none;color:#424242 !important;} .hld__excel-body #mainmenu .innerbg > div:nth-child(2) > div:first-child {display:none;} .hld__excel-body .single_ttip2 {position: fixed !important;z-index:999 !important;top:30px !important;border-color:#888;} .hld__excel-body .hld__excel-body #mainmenu, .hld__excel-body .catenew,.hld__excel-body #toptopics,.hld__excel-body #m_pbtntop,.hld__excel-body #m_fopts,.hld__excel-body #b_nav,.hld__excel-body #fast_post_c,.hld__excel-body #custombg,.hld__excel-body #m_threads th,.hld__excel-body #m_posts th,.hld__excel-body .r_container,.hld__excel-body #footer,.hld__excel-body .clickextend {display:none !important;} .hld__excel-body #mmc {margin-top:195px;margin-bottom:35px;} .hld__excel-body .postBtnPos > div, .hld__excel-body .postBtnPos .stdbtn a {background:#fff !important;border-color:#bbb;} .hld__excel-body .hld__excel-div,.hld__excel-body .hld__excel-setting {display:block;} .hld__excel-body .hld__excel-setting {position:fixed;width:60px;height:20px;top:5px;right:95px;background:#f2f4f7;z-index:999;} .hld__excel-body .hld__excel-setting img {width:20px;height:auto;vertical-align:middle;} .hld__excel-body .hld__excel-setting a {margin-left:5px;vertical-align:middle;} .hld__excel-body .hld__excel-header {position:fixed;top:0;left:0;height:196px;} .hld__excel-body .hld__excel-footer {position:fixed;bottom:0;left:0;height:50px;} .hld__excel-body .hld__excel-header, .hld__excel-body .hld__excel-footer {width: 100%;text-align: center;font-size: 16px;font-weight: bold;background:#e8e8e8;color:#337ab7;line-height: 45px;} .hld__excel-body .hld__excel-header>img, .hld__excel-body .hld__excel-footer>img{position:absolute;top:0;left:0} .hld__excel-body #m_nav {position:fixed;top:136px;left:261px;margin:0;padding:0;z-index:99;width: 9999px;} .hld__excel-body #m_nav .nav_spr {display:block;border:0;border-radius:0;padding:0;box-shadow:none;background:none;margin-top: 18px;margin-left: 10px;} .hld__excel-body #m_nav .nav_spr span {color:#000;font-size:16px;vertical-align:unset;font-weight:normal;} .hld__excel-body #m_nav .nav_root,.hld__excel-body #m_nav .nav_link {background:none;border:none;box-shadow:none;padding:0;color:#000;border-radius:0;font-weight:normal;} .hld__excel-body .nav {font-size:14px !important;} .hld__excel-body #mainmenu .stdbtn a {font-size:13px !important;} .hld__excel-body #m_threads {margin:0;} .hld__excel-body .postBtnPos > div {z-index:9991;} .hld__excel-body #topicrows {border:none;box-shadow:none;border-radius:0;margin:0;background-color:#fff;counter-reset:num;border-spacing:0;} .hld__excel-body #topicrows tbody {border-spacing:0;} .hld__excel-body .topicrow {border-spacing:0;} .hld__excel-body #topicrows td {background:#fff;padding:5px 0;margin:0;border:none;border-right:1px solid #bbbbbb;border-bottom:1px solid #bbbbbb;margin-right:-1px;} .hld__excel-body .topicrow .c1 {width:33px;background:#e8e8e8 !important;} .hld__excel-body .topicrow .c1 a {display:none;color: #777777 !important;font-size: 16px !important;font-family: auto;} .hld__excel-body.hld__excel-original-no .topicrow .c1:before {display:none;} .hld__excel-body.hld__excel-original-no .topicrow .c1 a {display:inline-block;} .hld__excel-body.hld__excel-original-no .topicrow .c1 img {width:20px;} .hld__excel-body .topicrow .c1:before {content:counter(num);counter-increment:num;color:#777777;font-size:16px;} .hld__excel-body .topicrow .c2 {padding-left:5px !important;} .hld__excel-body .topicrow .c3 {color:#1a3959 !important;} .hld__excel-body .topicrow .c3 > div, .hld__excel-body .topicrow .c4 > div {background:#FFF !important;} .hld__excel-body .topicrow .c3 > div a, .hld__excel-body .topicrow .c4 > div a {color:#888 !important;} .hld__excel-body .block_txt {background:#fff !important;color:#1a3959 !important;border-radius:0;padding:0 !important;min-width:0 !important;font-weight:normal;} .hld__excel-body .quote {background:#fff !important;} .hld__excel-body #m_posts .block_txt {font-weight:bold;} .hld__excel-body .topicrow .postdate,.hld__excel-body .topicrow .replydate {display:inline;margin:10px;} .hld__excel-body #m_pbtnbtm {margin:0;border-bottom:1px solid #bbbbbb;} .hld__excel-body .hld__country-flag {border:.5px solid rgba(0,0,0,.2);} .hld__excel-body #pagebbtm,.hld__excel-body #m_pbtnbtm .right_ {margin:0;} .hld__excel-body #pagebbtm:before {display:block;line-height:35px;width:33px;float:left;content:"#";border-right:1px solid #bbbbbb;color:#777;font-size:16px;background:#e8e8e8;} .hld__excel-body #m_pbtnbtm td {line-height:35px;padding:0 5px;} .hld__excel-body #m_pbtnbtm .stdbtn {box-shadow:none;border:none !important;padding:0;padding-left:5px;background:#fff;border-radius:0;font-size:13px !important;} .hld__excel-body #m_pbtnbtm .stdbtn .invert {color:#591804;} .hld__excel-body #m_pbtnbtm td a {background:#fff;padding:0;border:0;} .hld__excel-body #m_posts .comment_c .comment_c_1 {border-top-color:#bbbbbb;} .hld__excel-body #m_posts .comment_c .comment_c_2 {border-color:#bbbbbb;} .hld__excel-body #m_posts {border:0;box-shadow:none;padding-bottom:0;margin:0;counter-reset:num;} .hld__excel-body #m_posts td {background:#fff;border-top:1px solid #bbbbbb;border-right:1px solid #bbbbbb;border-bottom:1px solid #bbbbbb;} .hld__excel-body #m_posts .c0 {width:32px;color:#777;font-size:16px;background:#e8e8e8;text-align:center;} .hld__excel-body #m_posts .c0:before {content:counter(num);counter-increment:num;} .hld__excel-body #m_posts .vertmod {background:#fff !important;color:#ccc;} .hld__excel-body #m_posts a[name="uid"]:before {content:"UID:"} .hld__excel-body #m_posts .white,.hld__excel-body #m_posts .block_txt_c2,.hld__excel-body #m_posts .block_txt_c0 {background:#fff !important;color:#777777;} .hld__excel-body #m_posts .quote {background:#fff;border-color:#bbbbbb;} .hld__excel-body #m_posts .postrow .postinfob .iconfont,.hld__excel-body #m_posts .ogoodbtn a:hover .iconfont {fill: #10273f;} .hld__excel-body #m_posts .postInfo svg {fill:#10273f !important;} .hld__excel-body #m_posts .recommendvalue {color:#10273f !important;} .hld__excel-body #m_posts button {background:#eee;} .hld__excel-body #m_posts button:active {outline-color:#bbbbbb;} .hld__excel-body #m_posts .postbox {border:none !important;} .hld__excel-body .posterInfoLine {background: #FFF !important;border-bottom-color: #FFF !important;} .hld__excel-body.hld__reply-fixed #postbbtm {position:fixed;right:30px;top:75px;z-index:999;border-radius: 10px;overflow: hidden;} .hld__excel-body .row2 .comment_c .comment_c_1_1 {border-top-color: #FFF;} .hld__excel-body #m_posts .comment_c .comment_c_1 {border-color: #FFF;border-top-color: #BBB;} /* Office风格 */ .hld__excel-body.hld__excel-theme-office .hld__excel-header {height:221px;} .hld__excel-body.hld__excel-theme-office .hld__excel-h1 {height:59px;background:#227447;display:flex;justify-content: center;} .hld__excel-body.hld__excel-theme-office .hld__excel-title {display: block;color:#FFF;font-size: 12px;font-weight: 400;font-family: sans-serif;line-height:30px;} .hld__excel-body.hld__excel-theme-office .hld__excel-h2 {height:95px;background:#f1f1f1;border-bottom:1px solid #d5d5d5;} .hld__excel-body.hld__excel-theme-office .hld__excel-h3 {height:48px;background:#e6e6e6;box-shadow:none;} .hld__excel-body.hld__excel-theme-office .hld__excel-fx {left:250px;right: 5px;border-color:#c6c6c6;border-radius:0;height:28px;} .hld__excel-body.hld__excel-theme-office .hld__excel-h4 {height:20px;} .hld__excel-body.hld__excel-theme-office .hld__excel-f1 {height:29px;} .hld__excel-body.hld__excel-theme-office .hld__excel-f2 {height:21px;} .hld__excel-body.hld__excel-theme-office .hld__excel-f1 {border-top:1px solid #999999;border-bottom:1px solid #bfbfbf;} .hld__excel-body.hld__excel-theme-office .hld__excel-img-f1-l1, .hld__excel-body.hld__excel-theme-office .hld__excel-img-f1-r1 {top:-1px;} .hld__excel-body.hld__excel-theme-office #mmc {margin-top:221px;} .hld__excel-body.hld__excel-theme-office #m_nav {top:160px;} .hld__excel-body.hld__excel-theme-office #m_posts .c0, .hld__excel-body.hld__excel-theme-office .topicrow .c1 {width:32px;} .hld__excel-body.hld__excel-theme-office #pagebbtm:before, .hld__excel-body.hld__excel-theme-office .topicrow .c1 a {width:28px;} .hld__excel-body.hld__excel-theme-office .hld__excel-setting {top: 36px;background:none;text-align: center;} .hld__excel-body.hld__excel-theme-office .hld__excel-setting a {color:#FFFFFF;} .hld__excel-body.hld__excel-theme-office .hld__excel-setting img {display:none;} .hld__excel-body.hld__excel-theme-office.hld__reply-fixed #postbbtm {top: 162px;} .hld__excel-body.hld__excel-theme-office #m_pbtnbtm td a, .hld__excel-body.hld__excel-theme-office #m_pbtnbtm .stdbtn {background: none;} .hld__excel-body.hld__excel-theme-office #mainmenu {top:35px;right:45px;} .hld__excel-body.hld__excel-theme-office #mainmenu .mmdefault.cell input {border-radius:0;} .hld__excel-body.hld__excel-theme-office #mainmenu .stdbtn a, .hld__excel-body.hld__excel-theme-office #mainmenu .hld__half-clone {color:#FFF !important;} .hld__excel-body.hld__excel-theme-office .single_ttip2 {top:59px !important;} /* 腾讯文档风格 */ .hld__excel-body.hld__excel-theme-tencent {font-family: -apple-system, Helvetica Neue, Helvetica, PingFang SC, Microsoft YaHei, Source Han Sans SC, Noto Sans CJK SC, WenQuanYi Micro Hei, sans-serif !important;} .hld__excel-body.hld__excel-theme-tencent .hld__excel-header {height:125px;background:#FFF;} .hld__excel-body.hld__excel-theme-tencent .hld__excel-titlebar-title {height: 36px;line-height: 36px;font-size: 18px;font-weight: 500;color: #000;opacity: 0.88;margin: 0 9px;max-width: 30%;overflow: hidden;text-overflow: ellipsis;white-space: nowrap;} .hld__excel-body.hld__excel-theme-tencent #mmc {margin-top: 145px;} .hld__excel-body.hld__excel-theme-tencent #m_nav {top: 94px;left: 65px;} .hld__excel-body.hld__excel-theme-tencent .hld__excel-sub {width: 51px;} .hld__excel-body.hld__excel-theme-tencent .hld__excel-titlebar {height:56px;display: flex;align-items: center;flex-shrink: 0;padding: 0 4px;border-bottom:1px solid #ebebeb;} .hld__excel-body.hld__excel-theme-tencent .hld__excel-toolbar {height:44px;display: flex;align-items: center;flex-shrink: 0;padding: 0 12px;border-bottom:1px solid #ebebeb;line-height: 24px;font-size: 12px;color:rgba(0, 0, 0, 0.88);font-weight:400;} .hld__excel-body.hld__excel-theme-tencent .hld__excel-toolbar > div {flex-shrink: 0;} .hld__excel-body.hld__excel-theme-tencent .hld__excel-titlebar-pick {margin-left: 12px;margin-top: -2px;} .hld__excel-body.hld__excel-theme-tencent .hld__excel-titlebar-pick .hld__excel-titlebar-content {width:17px;height:17px} .hld__excel-body.hld__excel-theme-tencent .hld__excel-titlebar-pick .hld__excel-titlebar-indication {height: 3px;width: 14px;margin-left: 2px;margin-top: -2px;} .hld__excel-body.hld__excel-theme-tencent .hld__excel-formulabar {height:25px;} .hld__excel-body.hld__excel-theme-tencent .hld__excel-icon24 {width:24px;height:24px;background-size: 100% 100%;} .hld__excel-body.hld__excel-theme-tencent .hld__excel-icon20 {width:20px;height:20px;background-size: 100% 100%;} .hld__excel-body.hld__excel-theme-tencent .hld__excel-icon16 {width:16px;height:16px;background-size: 100% 100%;} .hld__excel-body.hld__excel-theme-tencent .hld__excel-icon12 {width:12px;height:12px;background-size: 100% 100%;} .hld__excel-body.hld__excel-theme-tencent .hld__excel-h4 > div {background-color:#f9fafb;border-bottom: 1px solid #ebebeb;border-top: 1px solid #ebebeb;border-color:#ebebeb;} .hld__excel-body.hld__excel-theme-tencent #m_posts .c0, .hld__excel-body.hld__excel-theme-tencent .topicrow .c1, .hld__excel-body.hld__excel-theme-tencent #pagebbtm:before {width:50px;background-color:#f9fafb !important;} .hld__excel-body.hld__excel-theme-tencent #topicrows td, .hld__excel-body.hld__excel-theme-tencent #m_posts td {border-color:#ebebeb;} .hld__excel-body.hld__excel-theme-tencent .hld__excel-footer {height:32px;background:#FFF;display:flex;align-items: center;border-top: 1px solid #e0e0e0;padding: 0 10px;} .hld__excel-body.hld__excel-theme-tencent .hld__excel-sheet-tab {margin-left: 8px;width:104px;border: 1px solid #e0e0e0;border-top: 1px solid #fff;text-align:center;height: 30px;} .hld__excel-body.hld__excel-theme-tencent .hld__excel-sheet-tab .hld__excel-sheet-name {font-size: 14px;color: rgba(0,0,0,.88);font-weight: 400;height: 26px;line-height: 26px;border-bottom:2px solid #1e6fff;display:flex;justify-content: center;align-items: center;} .hld__excel-body.hld__excel-theme-tencent .hld__excel-footer-item {color:#464d5a;font-size:14px;margin:0 4px;height: 32px;line-height: 32px;} .hld__excel-body.hld__excel-theme-tencent #mainmenu {top: 18px;right: 20px;} .hld__excel-body.hld__excel-theme-tencent #postbbtm {top: 60px;right: 5px;} .hld__excel-body.hld__excel-theme-tencent #m_pbtnbtm .stdbtn, .hld__excel-body.hld__excel-theme-tencent #m_pbtnbtm .stdbtn a {background: none;font-weight:400;} .hld__excel-body.hld__excel-theme-tencent #m_pbtnbtm .uitxt1 span {font-size: 1em !important;color: #10273f;} .hld__excel-body.hld__excel-theme-tencent #mainmenu .mmdefault.cell input {background: #FFF;} ` } /** * 折叠引用模块 * @name FoldQuote * @description 此模块提供了可以选择配置自动折叠过长引用 * 提供一个高级配置可以设置折叠的阈值 */ const FoldQuote = { name: 'FoldQuote', title: '折叠引用', settings: [{ type: 'normal', key: 'foldQuote', default: true, title: '折叠过长引用与附件', menu: 'left' },{ type: 'advanced', key: 'foldQuoteHeight', default: 300, title: '自动折叠引用高度', desc: '自动折叠引用的高度阈值,单位为像素(px)', menu: 'right' }], renderFormsFunc($el) { if (script.setting.normal.foldQuote) { // 自动折叠过长引用 $el.find('.postcontent .quote').each(function() { const $quote = $(this) if ($quote.height() > (script.setting.advanced.foldQuoteHeight || 300)) { const originalHeight = $quote.height() $quote.addClass('hld__quote-fold') const foldHeight = $quote.height() const $openBtn = $(`<div class="hld__quote-box"><button>查看全部 (剩余${100-parseInt(foldHeight/originalHeight*100)}%)</button></div>`) $openBtn.on('click', 'button', function(){ $(this).parent().remove() $quote.removeClass('hld__quote-fold') }) $quote.append($openBtn) } }) // 折叠附件 if ($el.find('h4.silver.subtitle').length > 0) { $el.find('h4.silver.subtitle').each(function (){ if ($(this).html() === '附件' && $(this).next().attr('id').includes('postattach')) { const $attach = $(this).next() $attach.hide() const $openBtn = $(`<button>显示附件</button>`) $openBtn.on('click', function(){ $(this).remove() $attach.show() }) $(this).next().after($openBtn) } }) } } }, style: ` .hld__quote-fold{height:150px;overflow:hidden;position: relative;} .hld__quote-box{padding:10px;position: absolute;left:0;right:0;bottom:0;background:#f2eddf;} .hld__excel-body .hld__quote-box{background:#FFF;} ` } /** * 新页面打开模块 * @name LinkTargetBlank * @description 此模块提供了可以选择配置在新页面打开链接 */ const LinkTargetBlank = { name: 'LinkTargetBlank', title: '新页面打开', setting: { type: 'normal', key: 'linkTargetBlank', default: false, title: '论坛列表新窗口打开', menu: 'right' }, renderThreadsFunc($el) { if (script.setting.normal.linkTargetBlank) { let $link = $el.find('.topic') $link.data('href', $link.attr('href')).attr('href', 'javascript:void(0)') $link.click(() => { window.open($link.data('href')) return false }) } } } /** * 链接直接跳转 * @name DirectLinkJump * @description 此模块提供了超链接等直接跳转无须弹窗确认 */ const DirectLinkJump = { name: 'DirectLinkJump', title: '链接直接跳转', setting: { type: 'normal', key: 'directLinkJump', default: true, title: '链接直接跳转', menu: 'right' }, renderFormsFunc($el) { if (script.setting.normal.directLinkJump) { $el.find('a[onclick]').each(function(){ if ($(this).attr('onclick').includes('showUrlAlert')) { $(this).removeAttr('onclick onmouseover onmouseout') } }) } } } /** * 图片增强模块 * @name ImgEnhance * @description 此模块提供了图片增强功能,使用一个独立的图层打开图片 * 可以快速切换,缩放,旋转等 */ const ImgEnhance = { name: 'ImgEnhance', title: '图片增强', settings: [{ type: 'normal', key: 'imgEnhance', default: true, title: '贴内图片功能增强', menu: 'right' }, { shortCutCode: 37, // LEFT key: 'imgEnhancePrev', title: '楼内上一张图' }, { shortCutCode: 39, // RIGHT key: 'imgEnhanceNext', title: '楼内上一张图' }], renderFormsFunc($el) { $el.find('img').each(function () { const classs = $(this).attr('class') if (!classs || (classs && !classs.includes('smile'))) { $(this).attr('hld__imglist', 'ready').removeAttr('onload').removeAttr('onclick') } }) //图片增强 if (script.setting.normal.imgEnhance) { const _this = this $('#mc').on('click', '.postcontent img[hld__imglist=ready]', function () { _this.resizeImg($(this)) return false }) } }, resizeImg(el) { if ($('#hld__img_full').length > 0) return let urlList = [] let currentIndex = el.parent().find('[hld__imglist=ready]').index(el) el.parent().find('[hld__imglist=ready]').each(function () { if ($(this).attr('src') != 'about:blank') { urlList.push($(this).data('srcorg') || $(this).data('srclazy') || $(this).attr('src')) } }) let $imgBox = $('<div id="hld__img_full" title="点击背景关闭"><div id="loader"></div></div>') let $imgContainer = $('<div class="hld__img_container hld__zoom-target"></div>') let $img = $('<img title="鼠标滚轮放大/缩小\n左键拖动移动" class="hld__img hld__zoom-target">') const renderImg = (index) => { let timer = null $('#loader').show() $imgContainer.css({ 'top': $(window).height() * 0.03 + 'px', 'left': (($(window).width() - ($(window).height()) * 0.85) / 2) + 'px', 'width': $(window).height() * 0.85 + 'px', 'height': $(window).height() * 0.85 + 'px' }) $img.css({ 'width': '', 'height': '' }).attr('src', urlList[index]).hide() timer = setInterval(() => { const w = $img.width() const h = $img.height() if (w > 0) { w > h ? $img.css({ 'width': '100%', 'height': 'auto' }) : $img.css({ 'height': '100%', 'width': 'auto' }) $img.show() $('#loader').hide() clearInterval(timer) } }, 1) } //当前图片 renderImg(currentIndex) $img.mousedown(function (e) { let endx = 0; let endy = 0; let left = parseInt($imgContainer.css("left")) let top = parseInt($imgContainer.css("top")) let downx = e.pageX let downy = e.pageY e.preventDefault() $(document).on("mousemove", function (es) { endx = es.pageX - downx + left endy = es.pageY - downy + top $imgContainer.css("left", endx + "px").css("top", endy + "px") return false }); }) $img.mouseup(function () { $(document).unbind("mousemove") }) $imgContainer.append($img) $imgBox.append($imgContainer) $imgBox.click(function (e) { !$(e.target).hasClass('hld__img') && $(this).remove() }) $imgBox.append(` <div class="hld__if_control"> <div class="change prev-img" title="本楼内上一张"><div></div></div> <div class="change rotate-right" title="逆时针旋转90°"><div></div></div> <div class="change rotate-left" title="顺时针旋转90°"><div></div></div> <div class="change next-img" title="本楼内下一张"><div></div></div> </div> `) /** * Bind:Click * 切换图片 */ $imgBox.on('click', '.change', function () { if ($(this).hasClass('prev-img') && currentIndex - 1 >= 0) renderImg(--currentIndex) if ($(this).hasClass('next-img') && currentIndex + 1 < urlList.length) renderImg(++currentIndex) if ($(this).hasClass('rotate-right') || $(this).hasClass('rotate-left')) { let deg = ($img.data('rotate-deg') || 0) - ($(this).hasClass('rotate-right') ? 90 : -90) if (deg >= 360 || deg <= -360) deg = 0 $img.css('transform', `rotate(${deg}deg)`) $img.data('rotate-deg', deg) } else { $img.css('transform', '') $img.data('rotate-deg', 0) } window.getSelection ? window.getSelection().removeAllRanges() : document.selection.empty() return false; }) /** * Bind:MouseWheel * 大图鼠标滚动缩放 */ $imgBox.on("mousewheel DOMMouseScroll", function (e) { const delta = (e.originalEvent.wheelDelta && (e.originalEvent.wheelDelta > 0 ? 1 : -1)) || (e.originalEvent.detail && (e.originalEvent.detail > 0 ? -1 : 1)); if ($imgContainer.width() > 50 || delta > 0) { const offsetY = $imgContainer.height() * 0.2 const offsetX = $imgContainer.width() * 0.2 let offsetTop = offsetY / 2 let offsetLeft = offsetX / 2 if ($(e.target).hasClass('hld__zoom-target')) { const targetOffsetX = Math.round(e.clientX - $imgContainer.position().left) const targetOffsetY = Math.round(e.clientY - $imgContainer.position().top) offsetLeft = (targetOffsetX / ($imgContainer.height() / 2)) * offsetLeft offsetTop = (targetOffsetY / ($imgContainer.height() / 2)) * offsetTop } if (delta > 0) { $imgContainer.css({ 'width': ($imgContainer.height() + offsetY) + 'px', 'height': ($imgContainer.height() + offsetY) + 'px', 'top': ($imgContainer.position().top - offsetTop) + 'px', 'left': ($imgContainer.position().left - offsetLeft) + 'px' }) } if (delta < 0) { $imgContainer.css({ 'width': ($imgContainer.height() - offsetY) + 'px', 'height': ($imgContainer.height() - offsetY) + 'px', 'top': ($imgContainer.position().top + offsetTop) + 'px', 'left': ($imgContainer.position().left + offsetLeft) + 'px' }) } } e.stopPropagation() return false }) /** * Bind:Keyup * Esc关闭大图 */ $('body').keyup(event => (event.keyCode == 27 && $('#hld__img_full').length > 0) && $('#hld__img_full').remove()) $('body').append($imgBox) }, shortcutFunc: { imgEnhancePrev() { if ($('#hld__img_full').length > 0) { $('#hld__img_full .prev-img').click() } }, imgEnhanceNext() { if ($('#hld__img_full').length > 0) { $('#hld__img_full .next-img').click() } } }, style: ` .hld__img_container {position:absolute;display:flex;justify-content:center;align-items:center;} .hld__if_control {position:absolute;display:flex;left:50%;bottom:15px;width:160px;margin-left:-80px;height:40px;background:rgba(0,0,0,0.6);z-index:9999999;} .postcontent img {margin:0 5px 5px 0 !important;box-shadow:none !important;outline:none !important;max-height: none !important;} #hld__img_full {position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,0.6);z-index:99999;} #hld__img_full img {cursor:move;transition:transform .2s ease;} #hld__img_full .hld__imgcenter {top:50%;left:50%;transform:translate(-50%,-50%);} #hld__img_full .change {width:40px;height:40px;cursor:pointer;} #hld__img_full .rotate-right,#hld__img_full .rotate-left {background:url(${IMG_ICON_REFRESH}) center no-repeat;background-size:25px;} #hld__img_full .rotate-right {transform:rotateY(180deg);} #hld__img_full .rotate-left:hover {transform:scale(1.2);} #hld__img_full .rotate-right:hover {transform:scale(1.2) rotateY(180deg);} #hld__img_full .next-img:hover {transform:scale(1.2) rotate(180deg);} #hld__img_full .prev-img,#hld__img_full .next-img {background:url(${IMG_ICON_LEFT}) center no-repeat;} #hld__img_full .next-img {transform:rotate(180deg);} #hld__img_full .prev-img:hover {transform:scale(1.2);} #hld__img_full .next-img:hover {transform:scale(1.2) rotate(180deg);} ` } /** * 标记楼主模块 * @name AuthorMark * @requires https://cdn.staticfile.org/spectrum/1.8.0/spectrum.js * @description 此模块提供了自动标记楼主,使其更醒目 * 提供了高级设置可选标记楼主的颜色 * 以及为其他模块提供一个spectrum的配置文件 */ const AuthorMark = { name: 'AuthorMark', title: '标记楼主', settings: [{ type: 'normal', key: 'authorMark', default: true, title: '高亮楼主', menu: 'right' }, { type: 'advanced', key: 'authorMarkColor', default: '#F00', title: '标记楼主颜色', desc: '标记楼主中的[楼主]的背景颜色,单位为16进制颜色代码', menu: 'left' }], // spectrum配置对象 colorPickerConfig: { type: 'color', preferredFormat: 'hex', showPaletteOnly: 'true', togglePaletteOnly: 'true', hideAfterPaletteSelect: 'true', showAlpha: 'false', togglePaletteMoreText: '更多选项', togglePaletteLessText: '隐藏', palette: [ ['#000000','#444444','#5b5b5b','#999999','#bcbcbc','#eeeeee','#f3f6f4','#ffffff'], ['#f44336','#744700','#ce7e00','#8fce00','#2986cc','#16537e','#6a329f','#c90076'], ['#f4cccc','#fce5cd','#fff2cc','#d9ead3','#d0e0e3','#cfe2f3','#d9d2e9','#ead1dc'], ['#ea9999','#f9cb9c','#ffe599','#b6d7a8','#a2c4c9','#9fc5e8','#b4a7d6','#d5a6bd'], ['#e06666','#f6b26b','#ffd966','#93c47d','#76a5af','#6fa8dc','#8e7cc3','#c27ba0'], ['#cc0000','#e69138','#f1c232','#6aa84f','#45818e','#3d85c6','#674ea7','#a64d79'], ['#990000','#b45f06','#bf9000','#38761d','#134f5c','#0b5394','#351c75','#741b47'], ['#660000','#783f04','#7f6000','#274e13','#0c343d','#073763','#20124d','#4c1130'] ] }, postAuthor: [], initFunc() { const localPostAuthor = script.getValue('hld__NGA_post_author') localPostAuthor && (this.postAuthor = localPostAuthor.split(',')) // 初始化颜色选择器 this.initSpectrum('#hld__setting_cover #hld__adv_authorMarkColor') }, renderFormsFunc($el) { const _this = this if (script.setting.normal.authorMark) { const author = $('#postauthor0').text().replace('楼主', '') const tid = this.getQueryString('tid') const authorStr = `${tid}:${author}` if (author && !this.postAuthor.includes(authorStr) && ['authorid=', 'pid='].every(k => !window.location.href.includes(k))) { this.postAuthor.unshift(authorStr) > 10 && this.postAuthor.pop() script.setValue('hld__NGA_post_author', this.postAuthor.join(',')) } $el.find('a.b').each(function () { const name = $(this).attr('hld-mark-before-name') || $(this).text().replace('[', '').replace(']', '') if (name && _this.postAuthor.includes(`${tid}:${name}`)) { $(this).append('<span class="hld__post-author">楼主</span>') } }) } }, /** * 获取URL参数 * @method getQueryString * @param {String} name key * @param {String} url 要解析的URL * @return {String|null} value */ getQueryString(name, url='') { url ||= decodeURIComponent(window.location.href.replace(/&/g, "&")) let reg = new RegExp("(?:\\?|&)" + name + "=([^&]*)(&|$)") let r = url.substring(1).match(reg) if (r != null) return encodeURIComponent(r[1]) return null }, /** * 初始化颜色选择器 * @method initSpectrum * @param {str} selector 元素选择器 */ initSpectrum(selector) { if (selector instanceof jQuery) { selector.spectrum(this.colorPickerConfig) } else { $(selector).spectrum(this.colorPickerConfig) } }, asyncStyle() { return ` .hld__post-author {background:${script.setting.advanced.authorMarkColor || '#F00'};color: #FFF;display: inline-block;padding:0 5px;margin-left: 5px;border-radius: 5px;font-weight:bold;line-height: 1.4em;padding-top: 0.1em;padding-bottom: 0;} ` }, style: ` .cp-color-picker{z-index:99997} .sp-container{position:absolute;top:0;left:0;display:inline-block;z-index:9999994;overflow:hidden} .sp-original-input-container{position:relative;display:inline-flex} .sp-original-input-container input{margin:0!important} .sp-original-input-container .sp-add-on{width:40px;border-top-right-radius:0!important;border-bottom-right-radius:0!important} input.spectrum.with-add-on{border-top-left-radius:0;border-bottom-left-radius:0;border-left:0} .sp-original-input-container .sp-add-on .sp-colorize{height:100%;width:100%;border-radius:inherit} .sp-colorize-container{background-image:url(${IMG_ICON_ALPHA})} .sp-container.sp-flat{position:relative} .sp-container,.sp-container *{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box} .sp-top{position:relative;width:100%;display:inline-block} .sp-top-inner{position:absolute;top:0;left:0;bottom:0;right:0} .sp-color{position:absolute;top:0;left:0;bottom:0;right:20px!important} .sp-hue{position:absolute;top:0;right:0;bottom:0;width:12px;height:100%;left:initial!important} .sp-clear-enabled .sp-hue{top:15%;height:85%} .sp-fill{padding-top:80%} .sp-sat,.sp-val{position:absolute;top:0;left:0;right:0;bottom:0} .sp-alpha-enabled .sp-top{margin-bottom:28px!important} .sp-alpha-enabled .sp-alpha{display:block} .sp-alpha-handle{position:absolute;top:-3px;cursor:pointer;height:16px;border-radius:50%;width:16px;margin-right:5px;left:-2px;right:0;background:#f9f9f9;box-shadow:0 0 2px 0 #3a3a3a} .sp-alpha{display:none;position:absolute;bottom:-18px;right:0;left:0;height:10px} .sp-alpha-inner{border-radius:4px} .sp-clear{display:none} .sp-clear.sp-clear-display{background-position:center} .sp-clear-enabled .sp-clear{display:block;position:absolute;top:3px;right:0;bottom:0;cursor:pointer;left:initial;height:12px;width:12px} .sp-alpha,.sp-alpha-handle,.sp-clear,.sp-container,.sp-container button,.sp-container.sp-dragging .sp-input,.sp-dragger,.sp-preview,.sp-replacer,.sp-slider{-webkit-user-select:none;-moz-user-select:-moz-none;-o-user-select:none;user-select:none} .sp-container.sp-input-disabled .sp-input-container{display:none} .sp-container.sp-buttons-disabled .sp-button-container{display:none} .sp-container.sp-palette-buttons-disabled .sp-palette-button-container{display:none} .sp-palette-only .sp-picker-container{display:none} .sp-palette-disabled .sp-palette-container{display:none} .sp-initial-disabled .sp-initial{display:none} .sp-sat{background-image:-webkit-gradient(linear,0 0,100% 0,from(#fff),to(rgba(204,154,129,0)));background-image:-webkit-linear-gradient(left,#fff,rgba(204,154,129,0));background-image:-moz-linear-gradient(left,#fff,rgba(204,154,129,0));background-image:-o-linear-gradient(left,#fff,rgba(204,154,129,0));background-image:-ms-linear-gradient(left,#fff,rgba(204,154,129,0));background-image:linear-gradient(to right,#fff,rgba(204,154,129,0))} .sp-val{border-radius:4px;background-image:-webkit-gradient(linear,0 100%,0 0,from(#000),to(rgba(204,154,129,0)));background-image:-webkit-linear-gradient(bottom,#000,rgba(204,154,129,0));background-image:-moz-linear-gradient(bottom,#000,rgba(204,154,129,0));background-image:-o-linear-gradient(bottom,#000,rgba(204,154,129,0));background-image:-ms-linear-gradient(bottom,#000,rgba(204,154,129,0));background-image:linear-gradient(to top,#000,rgba(204,154,129,0))} .sp-hue{background:-moz-linear-gradient(top,red 0,#ff0 17%,#0f0 33%,#0ff 50%,#00f 67%,#f0f 83%,red 100%);background:-ms-linear-gradient(top,red 0,#ff0 17%,#0f0 33%,#0ff 50%,#00f 67%,#f0f 83%,red 100%);background:-o-linear-gradient(top,red 0,#ff0 17%,#0f0 33%,#0ff 50%,#00f 67%,#f0f 83%,red 100%);background:-webkit-gradient(linear,left top,left bottom,from(red),color-stop(.17,#ff0),color-stop(.33,#0f0),color-stop(.5,#0ff),color-stop(.67,#00f),color-stop(.83,#f0f),to(red));background:-webkit-linear-gradient(top,red 0,#ff0 17%,#0f0 33%,#0ff 50%,#00f 67%,#f0f 83%,red 100%);background:linear-gradient(to bottom,red 0,#ff0 17%,#0f0 33%,#0ff 50%,#00f 67%,#f0f 83%,red 100%)} .sp-1{height:17%} .sp-2{height:16%} .sp-3{height:17%} .sp-4{height:17%} .sp-5{height:16%} .sp-6{height:17%} .sp-hidden{display:none!important} .sp-cf:after,.sp-cf:before{content:"";display:table} .sp-cf:after{clear:both} @media (max-device-width:480px){.sp-color{right:40%} .sp-hue{left:63%} .sp-fill{padding-top:60%} } .sp-dragger{border-radius:5px;height:10px;width:10px;border:1px solid #fff;cursor:pointer;position:absolute;top:0;left:0;margin-left:3px;margin-top:3px;box-shadow:0 0 2px 1px rgba(0,0,0,.2)} .sp-slider{position:absolute;top:0;cursor:pointer;height:16px;border-radius:50%;width:16px;left:-2px;background:#f9f9f9;box-shadow:0 0 2px 0 #3a3a3a;margin-top:8px} .sp-container{display:inline-flex;border-radius:0;background-color:#fff;padding:0;border-radius:4px;color:#000;box-shadow:0 0 0 1px rgba(99,114,130,.16),0 8px 16px rgba(27,39,51,.08)} .sp-clear,.sp-color,.sp-container,.sp-container button,.sp-container input,.sp-hue{font-size:12px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box} .sp-top{margin-bottom:10px} .sp-clear,.sp-color,.sp-hue,.sp-sat,.sp-val{border-radius:3px} .sp-input-container{margin-top:-5px} .sp-button-container.sp-cf,.sp-initial.sp-thumb.sp-cf,.sp-input-container.sp-cf{height:25px} .sp-picker-container .sp-cf{margin-bottom:10px} .sp-palette-row-initial>span:first-child{cursor:pointer} .sp-initial-disabled .sp-input-container{width:100%} .sp-input{padding:0 5px!important;margin:0;width:100%;box-shadow:none!important;height:100%!important;background:0 0;color:#3a3a3a;border-radius:2px!important;border:1px solid #e0e0e0!important;text-align:center;font-family:monospace;font-size:inherit!important} .sp-input.sp-validation-error{border:1px solid red;background:#fdd} .sp-palette-container,.sp-picker-container{position:relative;padding:10px} .sp-picker-container{width:200px;padding-bottom:0} .sp-palette-container{border-right:solid 1px #ccc} .sp-palette-only .sp-palette-container{border:0} .sp-palette .sp-thumb-el{display:block;position:relative;float:left;width:24px;height:15px;margin:3px;cursor:pointer;border:solid 2px transparent} .sp-palette .sp-thumb-el.sp-thumb-active,.sp-palette .sp-thumb-el:hover{border-color:orange} .sp-thumb-el{position:relative} .sp-initial{float:left} .sp-initial span{width:30px;height:25px;border:none;display:block;float:left;margin:0} .sp-initial .spe-thumb-el.sp-thumb-active{border-radius:0 5px 5px 0} .sp-initial .spe-thumb-el{border-radius:5px 0 0 5px} .sp-initial .sp-clear-display{background-position:center} .sp-button-container{float:right;display:none;} .sp-palette-button-container{margin-top:10px} .sp-replacer{position:relative;overflow:hidden;cursor:pointer;display:inline-block;border-radius:3px;border:1px solid #aaa;color:#666;transition:border-color .3s;vertical-align:middle;width:40px;height:20px;margin: 1.5px 3px;} .sp-replacer.sp-active,.sp-replacer:hover{border:1px solid #666;color:#000} .sp-replacer.sp-disabled{cursor:default;border-color:silver;color:silver} .sp-dd{position:absolute;font-size:10px;right:0;top:0;bottom:0;padding:0 1px;line-height:22px;background-color:#fff;border-left: 1px solid #aaa;} .sp-preview{position:relative;width:100%;height:100%;float:left;z-index:0} .sp-preview-inner{transition:background-color .2s} .sp-preview-inner.sp-clear-display{display:none} .sp-palette .sp-thumb-el{width:16px;height:16px;margin:3px;border:none;border-radius:3px} .sp-container button{border-radius:3px;border:none;background:0 0;line-height:1;padding:0 8px;height:25px;text-transform:capitalize;text-align:center;vertical-align:middle;cursor:pointer;color:#606c72;font-weight:700} .sp-container button.sp-choose{background-color:#3cab3b;color:#fff;margin-left:5px} .sp-container button:hover{opacity:.8} .sp-container button.sp-palette-toggle{width:100%;background-color:#f3f3f3;margin:0} .sp-palette span.sp-thumb-active,.sp-palette span:hover{border-color:#000} .sp-alpha,.sp-preview,.sp-thumb-el{position:relative;background-image:url(${IMG_ICON_ALPHA})} .sp-alpha-inner,.sp-preview-inner,.sp-thumb-inner{display:block;position:absolute;top:0;left:0;bottom:0;right:0} .sp-palette .sp-thumb-inner{border-radius:3px;background-position:50% 50%;background-repeat:no-repeat} .sp-palette .sp-thumb-light.sp-thumb-active .sp-thumb-inner{background-image:url(${IMG_ICON_CHECK_BLACK})} .sp-palette .sp-thumb-dark.sp-thumb-active .sp-thumb-inner{background-image:url(${IMG_ICON_CHECK_WHITE})} .sp-clear-display{background-repeat:no-repeat;background-position:center;background-image:url(${IMG_ICON_BLOCK})} ` } /** * 自动翻页模块 * @name AutoPage * @description 此模块提供了脚本自动翻页的功能 * 提供一个高级配置可以设置自动翻页的检测阈值 */ const AutoPage = { name: 'AutoPage', title: '自动翻页', settings: [{ type: 'normal', key: 'autoPage', default: true, title: '自动翻页', menu: 'right' }], $window: $(window), initFunc() { script.setting.normal.autoPage && $('body').addClass('hld__reply-fixed') }, renderAlwaysFunc() { const _this = this if(script.setting.normal.autoPage) { if($('#hld__next_page').length > 0) return $('#pagebbtm>.stdbtn[hld-auto-page!=ok] td').each(function(){ if($(this).children('a').text() == '>') { $(this).children('a').attr('id', 'hld__next_page') _this.$window.on('scroll.autoPage', function(){ if ($(document).scrollTop() != 0 && (Math.ceil($(document).scrollTop()) + $(window).height() >= ($(document).height() - 20))) { if($('#hld__next_page').length > 0) { document.getElementById('hld__next_page').click() $('#hld__next_page').removeAttr('id') _this.$window.off('scroll.autoPage') } } }) } }) $('#pagebbtm>.stdbtn').attr('hld-auto-page', 'ok') } } } /** * 关键字屏蔽模块 * @name KeywordsBlock * @description 此模块提供了关键字屏蔽功能 * 提供一个高级配置可以设置是否过滤标题 */ const KeywordsBlock = { name: 'KeywordsBlock', title: '关键字屏蔽', settings: [{ type: 'normal', key: 'keywordsBlock', default: true, title: '关键字屏蔽', menu: 'right', extra: { type: 'button', label: '关键字管理', id: 'hld__keywords_manage' } }, { type: 'advanced', key: 'kwdBlockContent', default: 'ALL', options: [{ label: '标题跟正文', value: 'ALL' }, { label: '仅标题', value: 'TITLE' }, { label: '仅正文', value: 'BODY' }], title: '关键字屏蔽方式', desc: '此配置表示关键字的屏蔽方式', menu: 'right' }], keywordsList: [], initFunc() { const _this = this // 同步本地数据 const localKeywordsList = script.getValue('hld__NGA_keywords_list') try { localKeywordsList && (_this.keywordsList = JSON.parse(localKeywordsList)) } catch { localKeywordsList && (_this.keywordsList = localKeywordsList.split(',')) script.setValue('hld__NGA_keywords_list', JSON.stringify(_this.keywordsList)) } // 添加到导入导出配置 script.getModule('BackupModule').addItem({ title: '关键字列表', writeKey: 'keywords_list', valueKey: 'keywordsList', module: this }) /** * Bind:Click * 管理弹窗面板 */ $('body').on('click', '#hld__keywords_manage', function () { if($('#hld__keywords_panel').length > 0) return $('#hld__setting_cover').append(`<div id="hld__keywords_panel" class="hld__list-panel animated fadeInUp"> <a href="javascript:void(0)" class="hld__setting-close">×</a> <div> <div class="hld__list-c"><p>屏蔽关键字</p><textarea row="20" id="hld__keywords_list_textarea"></textarea><p class="hld__list-desc">一行一条</p></div> </div> <div class="hld__btn-groups"><button class="hld__btn" id="hld__save_keywords">保存列表</button></div> </div>`) $('#hld__keywords_list_textarea').val(_this.keywordsList.join('\n')) }) /** * Bind:Click * 保存关键字 */ $('body').on('click', '#hld__save_keywords', function () { let keywordsList = $('#hld__keywords_list_textarea').val().split('\n') keywordsList = _this.removeBlank(keywordsList) keywordsList = _this.uniq(keywordsList) _this.keywordsList = keywordsList script.setValue('hld__NGA_keywords_list', JSON.stringify(_this.keywordsList)) $('#hld__keywords_panel').remove() script.popMsg('保存成功,刷新页面生效') }) }, renderThreadsFunc($el) { const title = $el.find('.c2>a').text() if ((script.setting.advanced.kwdBlockContent === 'ALL' || script.setting.advanced.kwdBlockContent === 'TITLE') && script.setting.normal.keywordsBlock && this.keywordsList.length > 0) { for (let keyword of this.keywordsList) { if (title.includes(keyword)) { script.printLog(`关键字屏蔽: 标题: ${title} 连接: ${$el.find('.c2>a').attr('href')}`) $el.remove() break } } } }, renderFormsFunc($el) { const _this = this if (script.setting.normal.keywordsBlock && this.keywordsList.length > 0 && (script.setting.advanced.kwdBlockContent === 'ALL' || script.setting.advanced.kwdBlockContent === 'BODY')) { const $postcontent = $el.find('.postcontent') const $postcontentClone = $postcontent.clone() const consoleLog = (text) => script.printLog(`关键字屏蔽: 内容: ${text}`) let postcontentQuote = '' let postcontentText = '' if ($postcontent.find('.quote').length > 0) { $postcontentClone.find('.quote').remove() let postcontentText = $postcontent.find('.quote').text() const endIndex = postcontentText.indexOf(')') postcontentQuote = postcontentText.substring(endIndex + 1) } postcontentText = $postcontentClone.text() let blockCount = 0 for (let keyword of this.keywordsList) { if (postcontentText && postcontentText.includes(keyword)) { consoleLog(postcontentText) $el.remove() blockCount += 1 break } if (postcontentQuote && postcontentQuote.includes(keyword)) { consoleLog(postcontentQuote) blockCount += 1 $postcontent.find('.quote').remove() } } const $commentCList = $el.find('.comment_c') if ($commentCList.length > 0) { let postcontentReply = '' $commentCList.each(function () { let postcontentReplyText = $el.find('.u###ode').text() const end_index = postcontentReplyText.indexOf(')') postcontentReply = postcontentReplyText.substring(end_index + 1) for (let keyword of _this.keywordsList) { if (postcontentReply && postcontentReply.includes(keyword)) { consoleLog(postcontentReply) blockCount += 1 $(this).remove() } } }) } } }, /** * 列表去空 * @method removeBlank * @param {Array} array 列表 * @return {Array} 处理后的列表 */ removeBlank(array) { let r = [] array.map(function (val, index) { if (val !== '' && val != undefined) { r.push(val) } }); return r }, /** * 列表去重 * @method uniq * @param {Array} array 列表 * @return {Array} 处理后的列表 */ uniq(array) { return [...new Set(array)] }, style: ` #hld__keywords_panel {width:182px;} #hld__keywords_panel .hld__list-c {width:100%;} ` } /** * 黑名单标记模块 * @name MarkAndBan * @description 此模块提供了黑名单屏蔽功能,标签标记功能 * 提供高级配置可以设置标记/备注风格 * 提供高级配置可以设置功能面板显示方式 * 提供高级配置可以设置黑名单屏蔽策略 */ const MarkAndBan = { name: 'MarkAndBan', title: '黑名单标记', settings: [{ type: 'normal', key: 'markAndBan', default: true, title: '拉黑/标签功能', menu: 'right', extra: { type: 'button', label: '名单管理', id: 'hld__list_manage' } }, { type: 'advanced', key: 'classicRemark', default: false, title: '经典备注风格', desc: '此配置表示标记功能的风格显示\n选中时: v2.9及以前的备注风格(仿微博),此风格不能更改颜色\n取消时: 新版标记风格', menu: 'right' }, { type: 'advanced', key: 'autoHideBanIcon', default: false, title: '按需显示标注拉黑按钮', desc: '选中时: 默认隐藏标注与拉黑按钮, 当鼠标停留区域时, 才会显示\n取消时: 一直显示', menu: 'right' }, { type: 'advanced', key: 'banStrictMode', default: 'HIDE', options: [{ label: '屏蔽', value: 'HIDE' }, { label: '删除', value: 'REMOVE' }, { label: '全部删除', value: 'ALL' }], title: '拉黑模式', desc: '此配置表示拉黑某人后对帖子的屏蔽策略\n屏蔽: 保留楼层, 仅会屏蔽用户的回复\n删除: 将会删除楼层\n全部删除: 回复被拉黑用户的回复也会被删除', menu: 'right' }], banList: [], markList: [], markedTags: [], initFunc() { const _this = this // 读取本地数据 const localBanList = script.getValue('hld__NGA_ban_list') try { localBanList && (_this.banList = JSON.parse(localBanList)) } catch(e) { script.throwError(`【NGA-Script】无法加载黑名单列表,数据解析失败!\n错误问题: ${e}\n\n请尝试使用【修复脚本】来修复此问题`) } const localMarkList = script.getValue('hld__NGA_mark_list') try { if (localMarkList) { _this.markList = JSON.parse(localMarkList) // 统计已添加过的标签 _this.markList.forEach(item => { item.marks.forEach(mark => { const exist_tag = _this.markedTags.find(t => t.mark == mark.mark) if (exist_tag) { exist_tag.count += 1 } else { _this.markedTags.push({ mark: mark.mark, text_color: mark.text_color, bg_color: mark.bg_color, count: 1 }) } }) }) _this.markedTags.sort((a, b) => {return b.count - a.count}) } } catch(e) { script.throwError(`【NGA-Script】无法加载标记列表,数据解析失败!\n错误问题: ${e}\n\n请尝试使用【修复脚本】来修复此问题`) } // 添加到导入导出配置 script.getModule('BackupModule').addItem({ title: '黑名单列表', writeKey: 'ban_list', valueKey: 'banList', module: this }) script.getModule('BackupModule').addItem({ title: '标记名单列表', writeKey: 'mark_list', valueKey: 'markList', module: this }) // 拉黑标签-名单 if (script.setting.normal.markAndBan) { /** * Bind:Click * 操作按钮点击事件 */ $('body').on('click', '.hld__extra-icon', function () { const type = $(this).data('type') const name = $(this).data('name') const uid = $(this).data('uid') + '' $('.hld__dialog').length > 0 && $('.hld__dialog').remove() if (type == 'ban') { _this.banlistPopup({ type: 'confirm', name, uid, top: $(this).offset().top+20, left: $(this).offset().left-10 }) } if (type == 'mark') { _this.userMarkPopup({ name, uid, top: $(this).offset().top+20, left: $(this).offset().left-10 }) } }) /** * Bind:Click * 屏蔽按钮 */ $('body').on('click', '.hld__banned-block', function(){ if ($(this).parent().hasClass('quote')) { $(this).parent().prev().show() $(this).parent().hide() } else { $(this).prev().show() $(this).hide() } }) /** * Bind:Click * 名单管理 */ $('body').on('click', '#hld__list_manage', function () { if($('#hld__banlist_panel').length > 0) return $('#hld__setting_cover').append(`<div id="hld__banlist_panel" class="hld__list-panel animated fadeInUp"> <a href="javascript:void(0)" class="hld__setting-close">×</a> <div class="hld__tab-header"><span class="hld__table-active">简易模式</span><span>原始数据</span></div> <div class="hld__tab-content hld__format-list hld__table-active"> <div class="hld__list-c"><p>黑名单</p> <div class="hld__scroll-area"> <table class="hld__table hld__table-banlist"> <thead><tr><th width="175">用户名</th><th>UID</th><th>备注</th><th width="25">操作</th></tr></thead><tbody id="hld__banlist"></tbody></table> </div> <div class="hld__table-banlist-buttons"><button id="hld__banlist_add_btn" class="hld__btn">+添加用户</button></div> </div> <div class="hld__list-c"><p>标签名单</p> <div class="hld__scroll-area"> <table class="hld__table hld__table-banlist"> <thead><tr><th width="100">用户名</th><th>UID</th><th width="50">标签数</th><th width="50">操作</th></tr></thead><tbody id="hld__marklist"></tbody></table> </div> <div class="hld__table-banlist-buttons"><button id="hld__marklist_add_btn" class="hld__btn">+添加用户</button></div> </div> </div> <div class="hld__tab-content hld__source-list"> <div class="hld__list-c"><p>黑名单</p><textarea row="20" id="hld__ban_list_textarea"></textarea><p class="hld__list-desc" title='[{\n "uid": "UID",\n "name": "用户名"\n }, ...]'>查看数据结构</p></div> <div class="hld__list-c"><p>标签名单</p><textarea row="20" id="hld__mark_list_textarea"></textarea><p class="hld__list-desc" title='[{\n "uid": "UID",\n "name": "用户名",\n "marks": [{\n "mark": "标记",\n "text_color": "文字色",\n "bg_color": "背景色"\n }, ...]\n }, ...]'>查看数据结构</p></div> <div class="hld__btn-groups" style="width: 100%;"><button class="hld__btn" id="hld__save_banlist">保存列表</button></div> </div> </div>`) /** * Bind:Click * 切换选项卡 */ $('body').on('click', '.hld__tab-header > span', function(){ $('.hld__tab-header > span, .hld__tab-content').removeClass('hld__table-active') $(this).addClass('hld__table-active') $('.hld__tab-content').eq($(this).index()).addClass('hld__table-active') }) /** * Bind:Click * 移除黑名单 */ $('body').on('click', '.hld__bl-del', function(){ const index = $(this).data('index') _this.banList.splice(index, 1) script.setValue('hld__NGA_ban_list', JSON.stringify(_this.banList)) _this.reloadBanlist() }) /** * Bind:Click * 添加黑名单 */ $('body').on('click', '#hld__banlist_add_btn', function(){ _this.banlistPopup({ type: 'add', name: $(this).data('name'), uid: $(this).data('uid'), top: $(this).offset().top + 30, left: $(this).offset().left - 5, callback: () => {_this.reloadBanlist()} }) }) /** * Bind:Click * 保存黑名单 */ $('body').on('click', '#hld__save_banlist', function(){ const banList = $('#hld__ban_list_textarea').val() const markList = $('#hld__mark_list_textarea').val() try { _this.banList = JSON.parse(banList) script.setValue('hld__NGA_ban_list', banList) _this.reloadBanlist() } catch { script.popMsg('黑名单数据有误!', 'err') return } try { _this.markList = JSON.parse(markList) script.setValue('hld__NGA_mark_list', markList) _this.reloadMarklist() } catch { script.popMsg('标记单数据有误!', 'err') return } script.popMsg('数据已成功') }) /** * Bind:Click * 修改标记 */ $('body').on('click', '.hld__ml-edit', function(){ const name = $(this).data('name') const uid = $(this).data('uid') + '' _this.userMarkPopup({ name, uid, top: $(this).offset().top + 30, left: $(this).offset().left - 5, callback: () => {_this.reloadMarklist()} }) }) /** * Bind:Click * 删除标记 */ $('body').on('click', '.hld__ml-del', function(){ const index = $(this).data('index') _this.markList.splice(index, 1) script.setValue('hld__NGA_mark_list', JSON.stringify(_this.markList)) _this.reloadMarklist() }) /** * Bind:Click * 添加标记 */ $('body').on('click', '#hld__marklist_add_btn', function(){ _this.userMarkPopup({ type: 'add', name: $(this).data('name'), uid: $(this).data('uid'), top: $(this).offset().top + 30, left: $(this).offset().left - 5, callback: () => {_this.reloadMarklist()} }) }) //重载名单 _this.reloadBanlist() _this.reloadMarklist() }) } }, renderThreadsFunc($el) { const title = $el.find('.c2>a').text() const uid = ($el.find('.author').attr('href') && $el.find('.author').attr('href').indexOf('uid=') > -1) ? $el.find('.author').attr('href').split('uid=')[1] + '' : '' const name = $el.find('.author').text() if (script.setting.normal.markAndBan) { const banUser = this.getBanUser({name, uid}) //黑名单屏蔽 if (this.banList.length > 0 && banUser) { script.printLog(`黑名单屏蔽: 标题: ${title} 连接: ${$el.find('.c2>a').attr('href')}`) $el.parents('tbody').remove() } } }, renderFormsFunc($el) { const _this = this if (script.setting.normal.markAndBan) { // 插入操作面板 const currentUid = $el.find('[name=uid]').text() + '' $el.find('.small_colored_text_btn.block_txt_c2.stxt').each(function () { let currentName = '' if ($(this).parents('td').prev('td').html() == '') { currentName = $(this).parents('table').prev('.posterinfo').children('.author').text() } else { currentName = $(this).parents('td').prev('td').find('.author').text() } currentName.endsWith('楼主') && (currentName = currentName.substring(0, currentName.length - 2)) const mbDom = ` <a class="hld__extra-icon hld__help" data-type="mark" help="标签此用户" data-name="${currentName}" data-uid="${currentUid}">🏷️</a> <a class="hld__extra-icon hld__help" help="拉黑此用户(屏蔽所有言论)" data-type="ban" data-name="${currentName}" data-uid="${currentUid}">⛔</a> ` script.setting.advanced.autoHideBanIcon ? $(this).after(`<span class="hld__extra-icon-box">${mbDom}</span>`) : $(this).append(mbDom) }) // 标记DOm $el.find('a.b').each(function () { const uid = ($(this).attr('href') && $(this).attr('href').indexOf('uid=') > -1) ? $(this).attr('href').split('uid=')[1] + '' : '' let name = '' if ($(this).find('span.hld__post-author').length > 0 || $(this).find('span.hld__remark').length > 0) { const $a = $(this).clone() $a.find('span.hld__post-author, span.hld__remark').remove() name = $a.text() } else { name = $(this).attr('hld-mark-before-name') || $(this).text().replace('[', '').replace(']', '') } const banUser = _this.getBanUser({name, uid}) if (banUser) { //拉黑用户实现 if (script.setting.advanced.banStrictMode == 'HIDE') { if ($(this).hasClass('author')) { const $blocktips = $('<div class="hld__banned hld__banned-block">此用户在你的黑名单中,已屏蔽其言论,点击查看</div>') if ($(this).parents('div.comment_c').length > 0) { $(this).parents('div.comment_c').find('.u###ode').hide() $(this).parents('div.comment_c').find('.u###ode').after($blocktips) } else { $(this).parents('.forumbox.postbox').find('.c2 .postcontent').hide() $(this).parents('.forumbox.postbox').find('.c2 .postcontent').after($blocktips) } } else { if (!$(this).parent().is(':hidden')) { $(this).parent().hide() $(this).parent().after('<div class="quote"><div class="hld__banned hld__banned-block">此用户在你的黑名单中,已屏蔽其言论,点击查看</div></div>') } } } else if (script.setting.advanced.banStrictMode == 'ALL') { if ($(this).parents('div.comment_c').length > 0) $(this).parents('div.comment_c').remove() else $(this).parents('.forumbox.postbox').remove() } else { if ($(this).hasClass('author')) { if ($(this).parents('div.comment_c').length > 0) $(this).parents('div.comment_c').remove() else $(this).parents('.forumbox.postbox').remove() } else { $(this).parent().html('<div class="hld__banned">此用户在你的黑名单中,已删除其言论</div>') } } if (banUser.desc) { $(this).parents('.postrow').find('.hld__banned').append(`<div>备注: ${banUser.desc}</div>`) } script.printLog(`黑名单屏蔽: 用户: ${name}, UID:${uid}, 备注:${banUser.desc}`) } if(script.setting.advanced.classicRemark) { //经典备注风格 const userMarks = _this.getUserMarks({name, uid}) if (userMarks) { let f = [] userMarks.marks.forEach(e => f.push(e.mark)) $(this).attr('hld-mark-before-name', name).append(`<span class="hld__remark"> (${f.join(', ')}) </span>`) } }else { //新版标签风格 const userMarks = _this.getUserMarks({name, uid}) if(userMarks) { const $el = $(this).parents('.c1').find('.clickextend') let marksDom = '' userMarks.marks.forEach(item => marksDom += `<span ${item.desc ? 'class="hld__help" help="'+item.desc+'"' : ''} style="color: ${item.text_color};background-color: ${item.bg_color};">${item.mark}</span>`); $el.before(`<div class="hld__marks-container">标签: ${marksDom}</div>`) } } }) } }, /** * 黑名单弹窗 * @method banlistPopup * @param {Object} setting 设置项 * @param {String} setting.name 用户昵称 * @param {String} setting.uid UID * @param {String} setting.type 模式 * @param {Number} setting.top pos.top位置 * @param {Number} setting.left pos.left 位置 * @param {Function} setting.callback 回调函数 */ banlistPopup(setting) { const _this = this $('.hld__dialog').length > 0 && $('.hld__dialog').remove() let $banDialog = $(`<div class="hld__dialog hld__dialog-sub-top hld__list-panel animated zoomIn" style="top: ${setting.top}px;left: ${setting.left}px;"><a href="javascript:void(0)" class="hld__setting-close">×</a><div id="container_dom"></div><div class="hld__dialog-buttons"></div></div>`) if (setting.type == 'confirm') { $banDialog.find('#container_dom').append(`<div><span>您确定要拉黑用户</span><span class="hld__dialog-user">${setting.name}</span><span>吗?</span></div><div><input type="text" class="hld__ban-desc" placeholder="可选备注"></div>`) let $okBtn = $('<button class="hld__btn">拉黑</button>') $okBtn.click(function(){ _this.setBanUser({ name: setting.name, uid: setting.uid, desc: $('.hld__ban-desc').val().trim() }) $('.hld__dialog').remove() script.popMsg('拉黑成功,重载页面生效') }) $banDialog.find('.hld__dialog-buttons').append($okBtn) }else if (setting.type == 'add') { $banDialog.find('#container_dom').append(`<div>添加用户: </div><div><input id="hld__dialog_add_uid" type="text" value="" placeholder="UID"></div><div><input id="hld__dialog_add_name" type="text" value="" placeholder="用户名"></div><div><input type="text" id="hld__dialog_add_desc" placeholder="可选备注"></div>`) let $okBtn = $('<button class="hld__btn">添加</button>') $okBtn.click(function(){ const name = $banDialog.find('#hld__dialog_add_name').val().trim() const uid = $banDialog.find('#hld__dialog_add_uid').val().trim() + '' const desc = $banDialog.find('#hld__dialog_add_desc').val().trim() if (!name && !uid) { script.popMsg('UID与用户名必填一个,其中UID权重较大', 'err') return } !_this.getBanUser({name, uid}) && _this.banList.push({name, uid, desc}) script.setValue('hld__NGA_ban_list', JSON.stringify(_this.banList)) $('.hld__dialog').remove() setting.callback() }) $banDialog.find('.hld__dialog-buttons').append($okBtn) } $('body').append($banDialog) }, /** * 获取黑名单用户 * @method getBanUser * @param {Object} banObj 黑名单对象 * @return {Object|null} 获取的用户对象 */ getBanUser(banObj) { const _this = this for (let u of _this.banList) { if ((u.uid && banObj.uid && u.uid == banObj.uid) || (u.name && banObj.name && u.name == banObj.name)) { if ((!u.uid && banObj.uid) || (!u.name && banObj.name)) { u.uid = banObj.uid + '' || '' u.name = banObj.name || '' script.setValue('hld__NGA_ban_list', JSON.stringify(_this.banList)) } return u } } return null }, /** * 拉黑用户 * @method setBanUser * @param {Object} banObj 黑名单对象, {uid, name} */ setBanUser(banObj) { !this.getBanUser(banObj) && this.banList.push(banObj) script.setValue('hld__NGA_ban_list', JSON.stringify(this.banList)) }, /** * 重新渲染黑名单列表 * @method reloadBanlist */ reloadBanlist() { const _this = this $('#hld__banlist').empty() _this.banList.forEach((item, index) => $('#hld__banlist').append(` <tr> <td title="${item.name}">${item.name}</td> <td title="${item.uid}">${item.uid}</td> <td title="${item.desc}">${item.desc || ''}</td> <td> <span class="hld__us-action hld__us-del hld__bl-del" title="删除" data-index="${index}" data-name="${item.name}" data-uid="${item.uid}"> <svg t="1686881304570" class="icon" viewBox="0 0 #### ####" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2976" width="48" height="48"><path d="M341.312 85.312l64-85.312h213.376l64 85.312H960v85.376H64V85.312h277.312zM170.688 256h682.624v768H170.688V256zM256 341.312v597.376h512V341.312H256z m213.312 85.376v426.624H384V426.688h85.312z m170.688 0v426.624H554.688V426.688H640z" fill="#111111" p-id="2977"></path></svg> </span> </td> </tr> `)) $('#hld__ban_list_textarea').val(JSON.stringify(_this.banList)) }, /** * 重新渲染标签列表 * @method reloadMarklist */ reloadMarklist() { const _this = this $('#hld__marklist').empty() _this.markList.forEach((user_mark, index) => { $('#hld__marklist').append(` <tr> <td title="${user_mark.name}">${user_mark.name}</td> <td title="${user_mark.uid}">${user_mark.uid}</td> <td title="${user_mark.marks.length}">${user_mark.marks.length}</td> <td> <span class="hld__us-action hld__us-edit hld__ml-edit" title="编辑" data-index="${index}" data-name="${user_mark.name}" data-uid="${user_mark.uid}"> <svg t="1686881523486" class="icon" viewBox="0 0 #### ####" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4234" width="48" height="48"><path d="M652.4 156.6125a112.5 112.5 0 1 1 155.925 161.15625L731.375 394.71875 572.3 235.5875l79.5375-79.5375 0.5625 0.5625zM333.63125 792.40625v0.1125H174.5v-159.1875l358.03125-357.975 159.075 159.13125-357.975 357.91875zM62 849.5h900v112.5H62v-112.5z" fill="#111111" p-id="4235"></path></svg> </span> <span class="hld__us-action hld__us-del hld__ml-del" title="删除" data-index="${index}" data-name="${user_mark.name}" data-uid="${user_mark.uid}"> <svg t="1686881304570" class="icon" viewBox="0 0 #### ####" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2976" width="48" height="48"><path d="M341.312 85.312l64-85.312h213.376l64 85.312H960v85.376H64V85.312h277.312zM170.688 256h682.624v768H170.688V256zM256 341.312v597.376h512V341.312H256z m213.312 85.376v426.624H384V426.688h85.312z m170.688 0v426.624H554.688V426.688H640z" fill="#111111" p-id="2977"></path></svg> </span> </td> </tr> `) }) $('#hld__mark_list_textarea').val(JSON.stringify(_this.markList)) }, /** * 标记弹窗 * @method userMarkPopup * @param {Object} setting 设置项 * @param {String} setting.name 用户名 * @param {String} setting.uid UID * @param {String} setting.type 模式 * @param {Number} setting.top pos.top位置 * @param {Number} setting.left pos.left 位置 * @param {Function} setting.callback 回调函数 */ userMarkPopup(setting) { const _this = this $('.hld__dialog').length > 0 && $('.hld__dialog').remove() let $markDialog = $(`<div class="hld__dialog hld__dialog-sub-top hld__list-panel animated zoomIn" style="top: ${setting.top}px;left: ${setting.left}px;"> <a href="javascript:void(0)" class="hld__setting-close">×</a> ${setting.type == 'add' ? `<div style="display:block;">添加用户: <input id="hld__dialog_add_uid" type="text" value="" placeholder="UID"><input id="hld__dialog_add_name" type="text" value="" placeholder="用户名"></div>` : ''} <table class="hld__dialog-mark-table"> <thead> <tr> <th width="100">标签</th><th width="50">文字</th><th width="50">背景</th><th>备注</th><th>操作</th> </tr> </thead> <tbody id="hld__mark_body"></tbody> </table> <div class="hld__dialog-buttons hld__button-insert" style="justify-content: left !important;"></div> <div class="hld__mark_history"><div class="hld__mark_history-title">选择已添加过的标签</div><div class="hld__mark_history-content"><div class="hld__mark_history-scrollarea">暂无</div></div></div> <div class="hld__dialog-buttons hld__button-save" style="justify-content: right !important;"></div> </div>`) const insertRemarkRow = (r='', t='#ffffff', b='#1f72f1', d='', n=true) => { let $tr = $(`<tr> <td><input type="text" class="hld__mark-mark" value="${r}"></td> <td><input class="hld__dialog-color-picker hld__mark-text-color" value="${t}"></td> <td><input class="hld__dialog-color-picker hld__mark-bg-color" value="${b}"></td> <td><textarea rows="1" class="hld__mark-desc"/></td> <td><button title="删除此标签" class="hld__mark-del">x</button></td> </tr>`) $tr.find('.hld__mark-del').click(function(){$(this).parents('tr').remove()}) $tr.find('.hld__mark-desc').val(d) script.getModule('AuthorMark').initSpectrum($tr.find('.hld__dialog-color-picker')) $markDialog.find('#hld__mark_body').append($tr) n && $tr.find('.hld__mark-mark').focus() } _this.markedTags.length > 0 && $markDialog.find('.hld__mark_history-scrollarea').empty() _this.markedTags.forEach(tag => { $markDialog.find('.hld__mark_history-scrollarea').append(` <span title="${tag.mark}" textcolor="${tag.text_color}" bgcolor="${tag.bg_color}" desc="${tag.desc}" style="color: ${tag.text_color};background-color: ${tag.bg_color};">${tag.mark} (${tag.count})</span> `) }) $markDialog.on('click', '.hld__mark_history-scrollarea > span', function (e) { insertRemarkRow($(this).attr('title'), $(this).attr('textcolor'), $(this).attr('bgcolor'), '', false) }) //恢复标签 const existMark = _this.getUserMarks({name: setting.name, uid: setting.uid}) existMark !== null && existMark.marks.forEach(item => insertRemarkRow(item.mark, item.text_color, item.bg_color, item.desc, false)) let $addBtn = $('<button class="hld__btn">+添加新标签</button>') $addBtn.click(() => insertRemarkRow()) $markDialog.find('.hld__button-insert').append($addBtn) let $okBtn = $('<button class="hld__btn">保存</button>') $okBtn.click(function(){ let userMarks = {marks: []} if (setting.type == 'add') { userMarks.name = $markDialog.find('#hld__dialog_add_name').val().trim() userMarks.uid = $markDialog.find('#hld__dialog_add_uid').val().trim() + '' } else { userMarks.name = setting.name userMarks.uid = setting.uid + '' } if (!userMarks.name && !userMarks.uid) { script.popMsg('UID与用户名必填一个,其中UID权重较大', 'err') return } $('#hld__mark_body > tr').each(function(){ const mark = $(this).find('.hld__mark-mark').val().trim() const textColor = $(this).find('.hld__mark-text-color').val() const bgColor = $(this).find('.hld__mark-bg-color').val() const desc = $(this).find('.hld__mark-desc').val().trim() if(mark) { userMarks.marks.push({mark, text_color: textColor, bg_color: bgColor, desc}) } }) if (setting.type == 'add' && userMarks.marks.length == 0) { script.popMsg('至少添加一个标签内容', 'err') return } _this.setUserMarks(userMarks) script.popMsg('保存成功,重载页面生效') $('.hld__dialog').remove() setting.callback() }) $markDialog.find('.hld__button-save').append($okBtn) $('body').append($markDialog) script.getModule('AuthorMark').initSpectrum('.hld__dialog-color-picker') }, /** * 获取用户标签对象 * @method getUserMarks * @param {String} uid UID * @param {String} user 用户名 * @return {Object|null} 标签对象 */ getUserMarks(user) { const check = this.markList.findIndex(v => (v.uid && user.uid && v.uid == user.uid) || (v.name && user.name && v.name == user.name)) if(check > -1) { let userMark = this.markList[check] if ((!userMark.uid && user.uid) || (!userMark.name && user.name)) { userMark.uid = user.uid + '' || '' userMark.name = user.name || '' script.setValue('hld__NGA_mark_list', JSON.stringify(this.markList)) } return userMark } else { return null } }, /** * 保存标签 * @method setUserMarks * @param {Object} userMarks 标签对象 */ setUserMarks(userMarks) { // 检查是否已有标签 const _this = this const check = _this.markList.findIndex(v => (v.uid && userMarks.uid && v.uid == userMarks.uid) || (v.name && userMarks.name && v.name == userMarks.name)) if(check > -1) { if (userMarks.marks.length == 0) { _this.markList.splice(check, 1) } else { _this.markList[check] = userMarks } }else { _this.markList.push(userMarks) } script.setValue('hld__NGA_mark_list', JSON.stringify(_this.markList)) }, style: ` #hld__setting {color:#6666CC !important;cursor:pointer;} .hld__list-panel {position:fixed;background:#fff8e7;padding:15px 20px;border-radius:10px;box-shadow:0 0 10px #666;border:1px solid #591804;z-index:9999;} #hld__banlist_panel {width:500px;} #hld__keywords_panel {width:182px;} .hld__extra-icon-box {padding: 5px 5px 5px 0;opacity: 0;transition: all ease .2s;} .hld__extra-icon-box:hover {opacity: 1;} .hld__extra-icon {position: relative;padding:0 2px;text-decoration:none;cursor:pointer;} .hld__extra-icon {text-decoration:none !important;} span.hld__remark {color:#666;font-size:0.8em;} .hld__banned {display: inline-block;color:#ba2026;border: 1px dashed #ba2026;padding: 10px 20px;font-weight: bold;} .hld__banned > div {font-weight: normal;} .hld__banned-block:hover {text-decoration: underline;cursor: pointer;} .hld__dialog{position:absolute;padding-right:35px} .hld__dialog>div{line-height:30px} .hld__dialog:before{position:absolute;content:' ';width:10px;height:10px;background-color:#fff6df;left:10px;transform:rotate(45deg)} .hld__dialog-sub-top:before{top:-6px;border-top:1px solid #591804;border-left:1px solid #591804} .hld__dialog-sub-bottom:before{bottom:-5px;border-bottom:1px solid #591804;border-right:1px solid #591804} .hld__dialog-buttons{display:flex;justify-content:flex-end!important;margin-top:10px} .hld__dialog-buttons>button{cursor:pointer} .hld__dialog-user{font-size:1.5em;color:red;margin:0 5px} .hld__dialog input[type=text]{width:100px;margin-right:15px} .hld__dialog-mark-table td{padding-bottom:3px} .hld__dialog-mark-table button{padding:0 6px;margin:0;height:20px;line-height:20px;width:20px;text-align:center;cursor:pointer} .hld__mark_history {margin-top: 10px;} .hld__mark_history .hld__mark_history-title {font-weight: bold;} .hld__mark_history .hld__mark_history-content {max-height: 200px;overflow: hidden;overflow-y: scroll;} .hld__mark_history .hld__mark_history-scrollarea {display: flex;flex-wrap: wrap;width:250px;} .hld__mark_history .hld__mark_history-content span {display: inline-block;padding: 2px 5px;border-radius: 3px;margin-right: 5px;margin-top: 5px;line-height: 20px;cursor: pointer;} .hld__ban-desc {width: 100% !important;} .hld__mark-desc {width: 50px;resize: none;} .hld__mark-desc:focus {width:150px;height:3em;} .hld__tab-content {display:flex;justify-content:space-between;flex-wrap: wrap;} .hld__table-keyword {margin-top:10px;width:200px;} .hld__table-keyword tr td:last-child {text-align:center;} .hld__table-keyword input[type=text] {width:48px;text-transform:uppercase;text-align:center;} .hld__tab-header{height:40px} .hld__tab-header>span{margin-right:10px;padding:5px;cursor:pointer} .hld__tab-header .hld__table-active,.hld__tab-header>span:hover{color:#591804;font-weight:700;border-bottom:3px solid #591804} .hld__tab-content{display:none} .hld__tab-content.hld__table-active{display:flex} .hld__marks-container>span{display: inline-block;padding:1px 5px;border-radius:3px;margin-right:5px;margin-top:5px;color:#fff;background-color:#1f72f1} .hld__table{table-layout:fixed;border-top:1px solid #ead5bc;border-left:1px solid #ead5bc} .hld__table-banlist-buttons{margin-top:10px} .hld__table thead{background:#591804;border:1px solid #591804;color:#fff} .hld__scroll-area{position:relative;height:200px;overflow:auto;border:1px solid #ead5bc} .hld__scroll-area::-webkit-scrollbar{width:6px;height:6px} .hld__scroll-area::-webkit-scrollbar-thumb{border-radius:10px;box-shadow:inset 0 0 5px rgba(0,0,0,.2);background:#591804} .hld__scroll-area::-webkit-scrollbar-track{box-shadow:inset 0 0 5px rgba(0,0,0,.2);border-radius:10px;background:#ededed} .hld__table td,.hld__table th{padding:3px 5px;border-bottom:1px solid #ead5bc;border-right:1px solid #ead5bc;white-space:nowrap;overflow:hidden;text-overflow:ellipsis} .hld__us-action{display: inline-block;width:18px;height:18px;margin:0 3px;} .hld__us-action svg{width:100%;height:100%;} .hld__us-action:hover{opacity:.8} ` } /** * 护眼模式 * @name EyeCareMode * @description 此模块提供了护眼模式(绿色) */ const EyeCareMode = { name: 'EyeCareMode', title: '护眼模式', setting: { type: 'normal', key: 'eyeCareMode', default: false, title: '护眼模式', desc: 'NGA自带的界面色调会与此功能有一定冲突\n使用前请先将NGA的界面色调设置为默认', menu: 'left' }, mainColor: '#cce8cc', // 主背景颜色 textColor: '#10273f', //文字颜色 buttonColor: '#c7edcc', // 按钮颜色 borderColor: '#ffffff', // 边框颜色 initFunc() { script.setting.normal.eyeCareMode && $('body').addClass('hld__eye-care') }, asyncStyle() { return ` body.hld__eye-care, .hld__eye-care #msg_block_c .menu a, #msg_block_c .pager a, .hld__eye-care .nav_link, .hld__eye-care button.hld__btn:hover {color: ${this.textColor} !important;} .hld__eye-care body, .hld__eye-care .stdbtn, .hld__eye-care .stdbtn .innerbg, .hld__eye-care .stdbtn a, .hld__eye-care .nav_root, .hld__eye-care .nav_link, .hld__eye-care .nav_spr, .hld__eye-care .stdbtn a:hover, .hld__eye-care .row2c1, .hld__eye-care .row1c1, .hld__eye-care .c1, .hld__eye-care .c2, .hld__eye-care .c3, .hld__eye-care .c4, .hld__eye-care .catenew, .hld__eye-care .cateblock, .hld__eye-care .forumbox, .hld__eye-care .quote, .hld__eye-care textarea, .hld__eye-care select, .hld__eye-care input, .hld__eye-care #m_posts .white, .hld__eye-care #m_posts .block_txt_c0, .hld__eye-care #m_posts .block_txt_c2, .hld__eye-care .block_txt_c3, .hld__eye-care .block_txt, .hld__eye-care .hld__docker-sidebar, .hld__eye-care .hld__docker-btns > div, .hld__eye-care .forumbox th, .hld__eye-care .contentBlock, .hld__eye-care .catenew .b2, .hld__eye-care .catenew .b3, .hld__eye-care .catenew h2, .hld__eye-care .catenew div, .hld__eye-care .topicrow .c2 > span:first-child, .hld__eye-care .urltip.nobr, .hld__eye-care #hld__setting_panel, .hld__eye-care .hld__list-panel, .hld__eye-care .single_ttip2 .tip_title, .hld__eye-care .single_ttip2 .div2, .hld__eye-care .postBtnPos > div, .hld__eye-care .postBtnPos .stdbtn a, .hld__eye-care .postbtnsc td, .hld__eye-care #mc > div:not(.module_wrap):not(#mainmenu), .hld__eye-care #m_nav > div:not(.nav), .hld__eye-care {background-color: ${this.mainColor} !important;} .hld__eye-care .nav_root, .hld__eye-care .nav_link, .hld__eye-care .nav_spr, .hld__eye-care .stdbtn, .hld__eye-care .quote, .hld__eye-care textarea, .hld__eye-care select, .hld__eye-care input, .hld__eye-care .block_txt_c2, .hld__eye-care .block_txt_c3, .hld__eye-care .hld__docker-btns>div, .hld__eye-care .r_container, .hld__eye-care .forumbox .postrow .stat {border:1px solid ${this.borderColor} !important;} .hld__eye-care .b .block_txt, .hld__eye-care .block_txt.block_txt_c0 {color: #1a3959 !important;padding:0 !important;} .hld__eye-care .forumbox.postbox {border-bottom: 2px solid ${this.borderColor} !important;border: none !important;} .hld__eye-care .r_bar {background-color: ${this.borderColor};} .hld__eye-care .forumbox .postrow .sigline, .hld__eye-care #m_posts .block_txt_c0 {color: ${this.borderColor} !important;border-color: ${this.borderColor} !important;} .hld__eye-care .nav_root, .hld__eye-care .invert, .hld__eye-care #mainmenu .stdbtn .half, .hld__eye-care .catenew .invert .uitxt1, .hld__eye-care .catenew .invert .uitxt3 {color:#591804;} .hld__eye-care:not(.hld__excel-body) #mainmenu {border-bottom: 1px solid ${this.borderColor} !important;} .hld__eye-care #m_posts, .hld__eye-care #toptopics, .hld__eye-care #topicrows, .hld__eye-care #mc > div:not(.module_wrap):not(#mainmenu), .hld__eye-care #msg_block_c .subblock {box-shadow:none;border-color: ${this.borderColor} !important;} .hld__eye-care .stdbtn a, .hld__eye-care .hld__advanced-setting, .hld__eye-care .hld__docker-sidebar {border-color: ${this.borderColor};} .hld__eye-care .block_txt.block_txt_c3 {border:none !important;} .hld__eye-care button, .hld__eye-care .hld__setting-close, .hld__eye-care .colored_text_btn, .hld__eye-care .rep.block_txt_big {border: 1px solid ${this.borderColor} !important;background: ${this.buttonColor} !important;} .hld__eye-care #toppedtopic table, .hld__eye-care .single_ttip2 .tip_title, .hld__eye-care .collapse_btn {border-color: ${this.borderColor} !important;} .hld__eye-care .apd {color: ${this.borderColor} !important;} .hld__eye-care .forumbox td:not(.c0) {border-color: ${this.borderColor} !important;border-bottom: 1px solid ${this.borderColor};border-right: 1px solid ${this.borderColor};} .hld__eye-care .c4 {border-right:none !important;} /* Excel 适配 */ .hld__eye-care.hld__excel-body .hld__quote-box, .hld__eye-care.hld__excel-body #m_pbtnbtm td a {background: ${this.mainColor};} .hld__eye-care.hld__excel-body #postbbtm .stdbtn, .hld__eye-care.hld__excel-body #postbbtm td a {background: #FFF !important;} .hld__eye-care.hld__excel-body .nav_root, .hld__eye-care.hld__excel-body .nav_spr,.hld__eye-care.hld__excel-body .nav_link, .hld__eye-care.hld__excel-body #mainmenu .stdbtn, .hld__eye-care.hld__excel-body #mainmenu .innerbg, .hld__eye-care.hld__excel-body #mainmenu .stdbtn a {background: none !important;border: none !important;} .hld__eye-care.hld__excel-body #mainmenu .mmdefault.cell input {background-color:#ededed !important;border-color: #c9d0dc !important;} ` } } /** * 暗黑模式 * @name DarkMode * @description 此模块提供了暗黑主题(仿Github Dark efault Theme) */ const DarkMode = { name: 'DarkMode', title: '暗黑模式', setting: { type: 'normal', key: 'darkMode', default: false, title: '暗黑模式', desc: 'NGA自带的界面色调会与此功能有一定冲突\n使用前请先将NGA的界面色调设置为默认\n与Excel模式不兼容,请勿混用', menu: 'left' }, mainColor: '#0c1117', // 主背景颜色 minorColor: '#141b22', // 次要背景颜色 textColor: '#e6edf3', // 文字颜色 muteColor: '#7d8590', // 次要文字颜色 linkColor: '#2f81f7', // 主链接颜色 buttonColor: '#1f262d', // 按钮颜色 buttonHoverColor: '#2e363d', // 按钮停留颜色 borderColor: '#21262d', // 边框颜色 initFunc() { script.setting.normal.darkMode && $('body').removeClass('hld__eye-care').addClass('hld__dark-mode') }, asyncStyle() { return ` body.hld__dark-mode, .hld__dark-mode #msg_block_c .menu a, .hld__dark-mode #msg_block_c .pager a, .hld__dark-mode .nav_link, .hld__dark-mode button.hld__btn:hover {color: ${this.textColor} !important;} .hld__dark-mode #m_threads a, .hld__dark-mode .forumbox h2, .hld__dark-mode .forumbox h1, .hld__dark-mode textarea, .hld__dark-mode select, .hld__dark-mode input, .hld__dark-mode .catetitle {color:${this.textColor} !important;} .hld__dark-mode #m_threads a:hover {background-color:${this.buttonHoverColor} !important;} .hld__dark-mode svg, .hld__dark-mode svg path {fill:${this.textColor} !important;} .hld__dark-mode a, .hld__dark-mode .uitxt1, .hld__dark-mode #hld__setting_panel .hld__sp-title a, .hld__dark-mode .author, .hld__dark-mode #m_post .author .block_txt, .hld__dark-mode #m_posts .urlincontent, .hld__dark-mode .cell.rep, .hld__dark-mode .uitxt1 {color:${this.linkColor} !important;} .hld__dark-mode #hld__setting_panel, .hld__dark-mode .hld__list-panel, .hld__dark-mode .single_ttip2 {border-color:${this.borderColor};box-shadow:0 8px 24px #010409;} .hld__dark-mode #mainmenu .stdbtn a:hover {border-bottom:4px solid ${this.linkColor} !important;} .hld__dark-mode #m_threads .block_txt_c0, .hld__dark-mode .block_txt_c0 .iconfont, .hld__dark-mode .nav_root {background-color:${this.buttonColor} !important;} .hld__dark-mode .invert {color:${this.linkColor} !important;background-color:${this.minorColor} !important;} .hld__dark-mode .hld__scroll-area::-webkit-scrollbar-thumb {background:#9f9f9f !important;} .hld__dark-mode .innerbg, .hld__dark-mode .innerbg .mmdefault, .hld__dark-mode #usernamebg, .hld__dark-mode .hld__table thead {background-color:${this.minorColor} !important;color:${this.textColor} !important;} .hld__dark-mode .hld__tab-header > span.hld__table-active, .hld__dark-mode .hld__tab-header > span:hover {color:${this.linkColor} !important;border-color:${this.linkColor} !important;} .hld__dark-mode .hld__dialog-sub-top:before, .hld__dark-mode .nav_root_c {background-color:${this.mainColor} !important;border-color:${this.borderColor} !important;} .hld__dark-mode body, .hld__dark-mode .stdbtn, .hld__dark-mode .forumbox .topicrow .c3 > div:first-child, .hld__dark-mode .forumbox .topicrow .c4 > div:first-child, .hld__dark-mode .nav_link, .hld__dark-mode .nav_spr, .hld__dark-mode .row2c1, .hld__dark-mode .row1c1, .hld__dark-mode .uitxt1, .hld__dark-mode .nav_link, .hld__dark-mode .c1, .hld__dark-mode .c2, .hld__dark-mode .c3, .hld__dark-mode .c4, .hld__dark-mode .catenew, .hld__dark-mode .stdbtn a, .hld__dark-mode .block_txt, .hld__dark-mode .cateblock, .hld__dark-mode .forumbox, .hld__dark-mode .quote, .hld__dark-mode textarea, .hld__dark-mode select, .hld__dark-mode input, .hld__dark-mode #m_posts .white, .hld__dark-mode #m_posts .block_txt_c2, .hld__dark-mode .block_txt_c3, .hld__dark-mode .hld__docker-sidebar, .hld__dark-mode #hld__updated, .hld__dark-mode .hld__docker-btns > div, .hld__dark-mode .forumbox th, .hld__dark-mode .contentBlock, .hld__dark-mode .catenew .b2, .hld__dark-mode .catenew .b3, .hld__dark-mode .catenew h2, .hld__dark-mode .catenew div, .hld__dark-mode .topicrow .c2 > span:first-child, .hld__dark-mode .urltip.nobr, .hld__dark-mode #m_posts .small_colored_text_btn, .hld__dark-mode #hld__setting_panel, .hld__dark-mode .hld__list-panel, .hld__dark-mode .single_ttip2 .tip_title, .hld__dark-mode .single_ttip2 .div2, .hld__dark-mode #startmenu .recent, .hld__dark-mode .postBtnPos > div, .hld__dark-mode .postBtnPos .stdbtn a, .hld__dark-mode .postbtnsc td, .hld__dark-mode #mc > div:not(.module_wrap):not(#mainmenu), .hld__dark-mode #m_nav > div:not(.nav), .hld__dark-mode {background-color: ${this.mainColor} !important;} .hld__dark-mode .nav_root, .hld__dark-mode .nav_link, .hld__dark-mode .nav_spr, .hld__dark-mode .stdbtn, .hld__dark-mode .quote, .hld__dark-mode textarea, .hld__dark-mode select, .hld__dark-mode input, .hld__dark-mode .block_txt_c2, .hld__dark-mode .block_txt_c3, .hld__dark-mode .hld__docker-btns>div, .hld__dark-mode .r_container, .hld__dark-mode .forumbox .postrow .stat {border:1px solid ${this.borderColor} !important;} .hld__dark-mode .b .block_txt, .hld__dark-mode .block_txt.block_txt_c0 {color: ${this.linkColor} !important;padding:0 !important;} .hld__dark-mode .forumbox.postbox {border-bottom: 2px solid ${this.borderColor} !important;border: none !important;} .hld__dark-mode .r_bar {background-color: ${this.borderColor};} .hld__dark-mode .nav_root, .hld__dark-mode .invert, .hld__dark-mode #mainmenu .stdbtn .half, .hld__dark-mode .catenew .invert .uitxt1, .hld__dark-mode .catenew .invert .uitxt3, .hld__dark-mode .single_ttip2 .tip_title, .hld__dark-mode #startmenu .item > a {color:${this.textColor} !important;} .hld__dark-mode:not(.hld__excel-body) #mainmenu {border-bottom: 1px solid ${this.borderColor} !important;} .hld__dark-mode #m_posts, .hld__dark-mode #toptopics, .hld__dark-mode #topicrows, .hld__dark-mode #mc > div:not(.module_wrap):not(#mainmenu), .hld__dark-mode #msg_block_c .subblock, .hld__dark-mode #hld__updated {box-shadow:none;border-color: ${this.borderColor} !important;} .hld__dark-mode .stdbtn a, .hld__dark-mode .hld__advanced-setting, .hld__dark-mode .hld__docker-sidebar {border-color: ${this.borderColor};} .hld__dark-mode .block_txt.block_txt_c3 {border:none !important;} .hld__dark-mode button, .hld__dark-mode .hld__setting-close, .hld__dark-mode .colored_text_btn, .hld__dark-mode .rep.block_txt_big, .hld__dark-mode #main a {border: 1px solid ${this.borderColor} !important;background: ${this.buttonColor} !important;color:#c9d1d9 !important;box-shadow:none !important;} .hld__dark-mode button:hover {background:${this.buttonHoverColor} !important;} .hld__dark-mode button:active {outline:none !important;} .hld__dark-mode #toppedtopic table, .hld__dark-mode .single_ttip2 .tip_title, .hld__dark-mode .collapse_btn {border-color: ${this.borderColor} !important;} .hld__dark-mode .apd {color: ${this.borderColor} !important;} .hld__dark-mode .forumbox td:not(.c0) {border-color: ${this.borderColor} !important;border-bottom: 1px solid ${this.borderColor};border-right: 1px solid ${this.borderColor};} .hld__dark-mode .c4 {border-right:none !important;} .hld__dark-mode #m_threads .replyer, .hld__dark-mode #m_threads .replyer > b, .hld__dark-mode .small_colored_text_btn, .hld__dark-mode .forumbox .postrow .stat, .hld__dark-mode #m_posts .postrow .userval, .hld__dark-mode #m_nav .bbsinfo, .hld__dark-mode .catenew p {color:${this.muteColor} !important;} ` } } /** * 字体大小调整 * @name FontResize * @description 此模块提供了调整字体大小的功能 */ const FontResize = { name: 'FontResize', title: '字体大小调整', setting: { type: 'advanced', key: 'fontResize', default: 12, title: '字体大小调整', desc: '字体大小调整,单位为像素(px),初始值是12,注意: 此值调整过大会导致页面混乱', menu: 'left' }, initFunc() { const fontResizeInput = script.setting.advanced.fontResize try { const fontSize = parseInt(fontResizeInput) if (fontSize && fontSize != 12) { $('body').css('font-size', fontSize + 'px') } } catch { script.printLog(`字体大小的值${script.setting.advanced.fontResize}无效,不是一个有效的数字`) } } } /** * 扩展坞模块 * @name ExtraDocker * @description 此模块提供了一个悬浮的扩展坞,来添加某些功能 * 目前添加的功能有: * 返回顶部: 无跳转返回当前页面的第一页/刷新当页 * 打开菜单: 打开个人主菜单 * 收藏: 收藏主题 * 回复: 回复主题 * 跳转尾页: 跳转到当前帖子的尾页 */ const ExtraDocker = { name: 'ExtraDocker', title: '扩展坞', settings: [{ shortCutCode: 84, // T key: 'backTop', title: '返回顶部' }, { shortCutCode: 66, // B key: 'backBottom', title: '跳转尾页' }], initFunc() { const _this = this const $dockerDom = $(` <div class="hld__docker"> <div class="hld__docker-sidebar"> <svg t="1603961015993" class="icon" viewBox="0 0 #### ####" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3634" width="64" height="64"><path d="M518.344359 824.050365c-7.879285 0-15.758569-2.967523-21.693614-9.004897l-281.403018-281.403018c-5.730389-5.730389-9.004897-13.609673-9.004897-21.693614s3.274508-15.963226 9.004897-21.693614l281.403018-281.403018c11.972419-11.972419 31.41481-11.972419 43.387229 0 11.972419 11.972419 11.972419 31.41481 0 43.387229L280.32857 511.948836l259.709403 259.709403c11.972419 11.972419 11.972419 31.41481 0 43.387229C534.0006 821.082842 526.223643 824.050365 518.344359 824.050365z" p-id="3635" fill="#888888"></path><path d="M787.160987 772.88618c-7.879285 0-15.758569-2.967523-21.693614-9.004897l-230.238833-230.238833c-11.972419-11.972419-11.972419-31.41481 0-43.387229l230.238833-230.238833c11.972419-11.972419 31.41481-11.972419 43.387229 0 11.972419 11.972419 11.972419 31.41481 0 43.387229L600.309383 511.948836l208.545218 208.545218c11.972419 11.972419 11.972419 31.41481 0 43.387229C802.817228 769.918657 794.937943 772.88618 787.160987 772.88618z" p-id="3636" fill="#888888"></path></svg> </div> <div class="hld__docker-btns"> <div data-type="TOP" id="hld__jump_top"><svg t="1603962702679" title="返回顶部" class="icon" viewBox="0 0 #### ####" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="9013" width="64" height="64"><path d="M528.73 161.5c-9.39-9.38-24.6-9.38-33.99 0L319.65 336.59a24.028 24.028 0 0 0-7.05 23.59A24.04 24.04 0 0 0 330 377.6c8.56 2.17 17.62-0.52 23.6-7.02l158.14-158.14 158.1 158.14a23.901 23.901 0 0 0 17 7.09c6.39 0 12.5-2.55 17-7.09 9.38-9.39 9.38-24.61 0-34L528.73 161.5zM63.89 607.09h102.79V869.5h48.04V607.09h102.79v-48.04H63.89v48.04z m518.69-48.05h-127.3c-15.37 0-30.75 5.85-42.49 17.59a59.846 59.846 0 0 0-17.59 42.49v190.3c0 15.37 5.89 30.75 17.59 42.49 11.74 11.74 27.12 17.59 42.49 17.59h127.3c15.37 0 30.75-5.85 42.49-17.59 11.7-11.74 17.59-27.12 17.59-42.49V619.17a59.903 59.903 0 0 0-17.53-42.55 59.912 59.912 0 0 0-42.55-17.54v-0.04z m12 250.38c0 2.31-0.6 5.59-3.5 8.54a11.785 11.785 0 0 1-8.5 3.5h-127.3c-3.2 0.02-6.26-1.26-8.5-3.54a11.785 11.785 0 0 1-3.5-8.5V619.17c0-2.31 0.6-5.59 3.5-8.54 2.24-2.27 5.31-3.53 8.5-3.5h127.3c2.27 0 5.55 0.64 8.5 3.55 2.27 2.24 3.53 5.31 3.5 8.5v190.29-0.05z m347.4-232.78a59.846 59.846 0 0 0-42.49-17.59H734.74V869.5h48.04V733.32h116.71a59.94 59.94 0 0 0 42.54-17.55 59.923 59.923 0 0 0 17.55-42.54v-54.07c0-15.37-5.85-30.74-17.59-42.49v-0.03z m-30.44 96.64c0 2.26-0.64 5.55-3.55 8.5a11.785 11.785 0 0 1-8.5 3.5H782.78v-78.15h116.71c2.27 0 5.59 0.6 8.54 3.5 2.27 2.24 3.53 5.31 3.5 8.5v54.15z m0 0" p-id="9014" fill="#591804"></path></svg></div> <div data-type="MENU" id="hld__jump_menu"><svg t="1687167394269" class="icon" viewBox="0 0 #### ####" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5137" width="48" height="48"><path d="M708.367 353.656c0-56.745-22.729-110.092-63.###-150.218s-96.132-62.224-154.494-62.224-113.229 22.099-154.498 62.224-63.### 93.473-63.### 150.218c0 43.987 13.713 86.196 39.651 122.064 7.273 10.060 21.559 12.479 31.904 5.406 10.343-7.073 12.834-20.963 5.561-31.019-20.486-28.329-31.315-61.684-31.315-96.451 0-92.585 77.471-167.911 172.694-167.911s172.689 75.325 172.689 167.911-77.471 167.906-172.694 167.906c-47.055 0-92.711 8.965-135.702 26.646-41.516 17.076-78.796 41.509-110.806 72.632-32.007 31.123-57.142 67.371-74.705 107.736-18.181 41.808-27.401 86.199-27.401 131.948 0 12.298 10.252 22.266 22.898 22.266s22.898-9.968 22.898-22.266c0-162.35 135.843-294.425 302.816-294.425 58.361 0 113.229-22.099 154.497-62.22s63.###-93.477 63.###-150.221zM530.991 631.551c0 12.298 10.252 22.266 22.898 22.266h304.337c12.647 0 22.898-9.968 22.898-22.266s-10.252-22.266-22.898-22.266h-304.337c-12.647 0-22.898 9.968-22.898 22.266zM858.229 722.671h-304.337c-12.65 0-22.898 9.968-22.898 22.266s10.252 22.266 22.898 22.266h304.337c12.647 0 22.898-9.968 22.898-22.266 0-12.294-10.252-22.266-22.898-22.266zM858.229 836.056h-304.337c-12.65 0-22.898 9.967-22.898 22.266s10.252 22.266 22.898 22.266h304.337c12.647 0 22.898-9.968 22.898-22.266 0-12.294-10.252-22.266-22.898-22.266z" fill="#591804" p-id="5138"></path></svg></div> <div data-type="FAVOR" id="hld__jump_favor"><svg t="1687168828546" class="icon" viewBox="0 0 #### ####" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6134" width="48" height="48"><path d="M512 776.533333l-238.933333 85.333334 8.533333-251.733334L128 405.333333l243.2-72.533333L512 128l140.8 209.066667L896 405.333333l-153.6 200.533334 8.533333 251.733333-238.933333-81.066667z m0-93.866666l149.333333 51.2-4.266666-157.866667 98.133333-123.733333-153.6-42.666667L512 277.333333 422.4 409.6l-153.6 42.666667 98.133333 123.733333-4.266666 157.866667L512 682.666667z" fill="#591804" p-id="6135"></path></svg></div> <div data-type="REPLY" id="hld__jump_reply"><svg t="1687169791224" class="icon" viewBox="0 0 1025 ####" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="8570" width="48" height="48"><path d="M415.937331 320 415.937331 96 20.001331 438.176C-6.718669 461.28-6.622669 498.784 20.033331 521.824L415.937331 864 415.937331 640C639.937331 640 847.937331 688 1023.937331 928 943.937331 480 607.937331 320 415.937331 320" p-id="8571" fill="#591804"></path></svg></div> <div data-type="BOTTOM" id="hld__jump_bottom"><svg t="1603962680160" title="跳转至最后一页" class="icon" viewBox="0 0 #### ####" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7501" width="64" height="64"><path d="M792.855 465.806c-6.24-6.208-14.369-9.312-22.56-9.312s-16.447 3.169-22.688 9.44l-207.91 207.74v-565.28c0-17.697-14.336-32-32-32s-32.002 14.303-32.002 32v563.712l-206.24-206.164c-6.271-6.209-14.432-9.344-22.624-9.344-8.224 0-16.417 3.135-22.656 9.407-12.511 12.513-12.48 32.768 0.032 45.248L483.536 770.38c3.265 3.263 7.104 5.6 11.136 7.135 4 1.793 8.352 2.88 13.024 2.88 1.12 0 2.08-0.544 3.2-0.64 8.288 0.064 16.608-3.009 22.976-9.408l259.11-259.292c12.48-12.511 12.448-32.8-0.127-45.248z m99.706 409.725c0 17.665-14.303 32.001-31.999 32.001h-704c-17.665 0-32-14.334-32-31.999s14.335-32 32-32h704c17.696 0 32 14.334 32 31.998z" p-id="7502" fill="#591804"></path></svg></div> </div> </div> `) $('body').append($dockerDom) /** * Bind:Click * 按钮点击事件 */ $('body').on('click', '.hld__docker-btns>div', function (e) { const type = $(this).data('type') if (type == 'TOP') { const $nav_link = $('#m_nav a.nav_link') if ($nav_link.length > 0) { $nav_link[$nav_link.length-1].click() } } if (type == 'MENU') { unsafeWindow.commonui.mainMenu.menuOpen() unsafeWindow.commonui.mainMenu.menuOpenAct({ clientX: window.screen.width - 30, clientY: 30, pageX: window.screen.width - 30, pageY: 30 }, null, 8) } if (type == 'FAVOR') { const tid = script.getModule('AuthorMark').getQueryString('tid') if (script.isForms() && tid) { unsafeWindow.commonui.favor(e, null, tid) } } if (type == 'REPLY') { if (script.isForms()) { window.location.href = $('#postbbtm a.rep.uitxt1').attr('href') } } if (type == 'BOTTOM') { let queryset = _this.getQuerySet() queryset.page = 9999 let search = '' for (let key in queryset) { search += `${search == '' ? '?' : '&'}${key}=${queryset[key]}` } window.location.href = `${window.location.origin}${window.location.pathname}${search}` } }) }, renderAlwaysFunc(script) { (script.isThreads() || script.isForms()) ? $('.hld__docker').show() : $('.hld__docker').hide() $('#hld__jump_favor').toggle(script.isForms()) $('#hld__jump_reply').toggle(script.isForms()) }, shortcutFunc: { backTop() { $('#hld__jump_top').click() script.popNotification('返回顶部') }, backBottom() { $('#hld__jump_bottom').click() script.popNotification('最后一页') } }, /** * 获取URL参数对象 * @method getQuerySet * @return {Object} 参数对象 */ getQuerySet() { let queryList = {} let url = decodeURI(window.location.search.replace(/&/g, "&")) url.startsWith('?') && (url = url.substring(1)) url.split('&').forEach(item => { let t = item.split('=') if (t[0] && t[1]) { queryList[t[0]] = t[1] } }) return queryList }, style: ` .hld__docker{position:fixed;height:80px;width:30px;bottom:180px;right:0;transition:all ease .2s} .hld__docker:hover{width:150px;height:300px;bottom:75px} .hld__docker-sidebar{background:#0f0;position:fixed;height:50px;width:20px;bottom:195px;right:0;display:flex;justify-content:center;align-items:center;background:#fff6df;border:1px solid #591804;box-shadow:0 0 1px #333;border-right:none;border-radius:5px 0 0 5px} .hld__excel-body .hld__docker-sidebar{background:#fff;border:1px solid #bbb} .hld__docker-btns{position:absolute;top:0;left:50px;bottom:0;right:50px;display:flex;justify-content:center;align-items:center;flex-direction:column} .hld__docker .hld__docker-btns>div{opacity:0;flex-shrink: 0;} .hld__docker:hover .hld__docker-btns>div{opacity:1} .hld__docker-btns>div{background:#fff6df;border:1px solid #591804;box-shadow:0 0 5px #444;width:50px;height:50px;border-radius:50%;margin:10px 0;cursor:pointer;display:flex;justify-content:center;align-items:center} .hld__excel-body .hld__docker-btns>div{background:#fff;border:1px solid #bbb} .hld__docker-btns svg{width:30px;height:30px;transition:all ease .2s} .hld__docker-btns svg:hover{width:40px;height:40px} .hld__excel-body .hld__docker-sidebar{background:#fff;border:1px solid #bbb} .hld__excel-body .hld__docker-btns>div{background:#fff;border:1px solid #bbb} ` } /** * 域名重定向 * @name DomainRedirect * @description 此模块提供了将不同域名重定向到一个指定的目标域名 */ const DomainRedirect = { name: 'DomainRedirect', title: '域名重定向', setting: { type: 'advanced', key: 'domainRedirectTarget', default: '', options: [{ label: '未配置', value: '' }, { label: 'bbs.nga.cn', value: 'bbs.nga.cn' }, { label: 'ngabbs.com', value: 'ngabbs.com' }, { label: 'nga.178.com', value: 'nga.178.com' }], title: '域名重定向目标', desc: '此配置设置将域名重定向到的目标域名\n警告:不同域名的配置文件中的此配置应该保持一致,如不一致将会反复重定向陷入死循环!', menu: 'left' }, initFunc() { const domainRedirectTarget = script.setting.advanced.domainRedirectTarget if (domainRedirectTarget && window.location.host != domainRedirectTarget) { const newRedirectUrl = window.location.href.replace(window.location.host, domainRedirectTarget) window.location.replace(newRedirectUrl) } } } /** * 用户增强 * @name UserEnhance * @description 此模块提供了用户功能类的增强,如显示注册天数,IP所属地等 */ const UserEnhance = { name: 'UserEnhance', title: '用户增强', settings: [{ type: 'normal', key: 'userEnhance', default: true, title: '用户增强', menu: 'right' }, { type: 'advanced', key: 'locationFlagMode', default: 'FLAG_AND_TEXT', options: [{ label: '国旗', value: 'FLAG' }, { label: '文字', value: 'TEXT' }, { label: '国旗加文字', value: 'FLAG_AND_TEXT' }], title: '属地显示模式', desc: '调整属地显示模式: \n全部国旗: 显示国旗不显示文字\n全部文字: 显示文字不显示国旗\n国旗加文字: 前面显示国旗后面显示文字', menu: 'right' }], forumData: { '108': '垃圾处理' }, chart: null, activeCount: [], requestTasks: [], currentUserInfo: {}, pageInfo: {}, queryTimer: null, store: null, initFunc() { // 创建storage示例 this.store = script.createStorageInstance('NGA_BBS_Script__UserInfoCache') this.preprocessing() }, renderFormsFunc($el) { if (!script.setting.normal.userEnhance) return const uid = parseInt($el.find('a[name="uid"]').text()) const userInfo = unsafeWindow.commonui.userInfo.users[uid] if (!userInfo || uid <= 0) return const regSeconds = Math.ceil(new Date().getTime() / 1000) - userInfo.regdate const regDays = Math.round(regSeconds / 3600 / 24) const regYear = (regSeconds / 3600 / 24 / 365).toFixed(1) // 插入UI const $userEnhanceContainer = $(`<div class="hld__user-enhance hld__user-enhance-${uid}"></div>`) const $node = $el.find('.posterinfo div.stat .clickextend').siblings('div:first-child') $node.after($userEnhanceContainer) $userEnhanceContainer.append(`<div><span title="注册天数: ${regDays}天\n注册年数: ${regYear}年">坛龄: <span class="numeric userval" name="regday">${regDays}天</span></span></div>`) $userEnhanceContainer.append(`<div><span title="发帖数量: ${userInfo.postnum}">发帖: <span class="numeric userval" name="regday">${userInfo.postnum}</span></span></div>`) $userEnhanceContainer.append(`<div><span style="display: inline-flex;align-items: center;" class="hld__user-location">属地: <span class="userval numeric hld__req-retry" style="margin-left:5px;">点击获取</span></span></div>`) $userEnhanceContainer.append(`<div class="hld__qbc"><button>查看用户活动记录</button></div>`) $userEnhanceContainer.find('.hld__user-location > span').click(e => { if (!$(e.target).hasClass('hld__req-retry')) return this.getUserLocation(uid) }) $el.find('.hld__qbc > button').click(() => this.queryUserActivityRecords(userInfo)) // this.getUserLocation(uid) }, /** * 预处理 */ preprocessing() { // 非实时性的任务使用异步处理 new Promise(async (resolve, reject) => { // 初始化的时候清理超过一定时间的数据,避免无限增长数据 // 出于性能考虑,每日只执行一次 const currentDate = new Date() const lastClear = await this.store.getItem('USERENHANCE_CLEAR_DAY') if (lastClear != currentDate.getDate()) { const exprieSeconds = 7 * 24 * 3600 // 7天 const currentTime = Math.ceil(currentDate.getTime() / 1000) let removedCount = 0 this.store.iterate((value, key, iterationNumber) => { if (key.startsWith('USERINFO_')) { if (!value._queryTime || currentTime - value._queryTime >= exprieSeconds) { this.store.removeItem(key) removedCount += 1 } } }) .then(() => { this.store.setItem('USERENHANCE_CLEAR_DAY', currentDate.getDate()) script.printLog(`用户增强: 已清除${removedCount}条用户超期数据`) }) .catch(err => { console.error('用户增强清除超期数据失败,错误原因:', err) }) } // 获取所有版面字典,扁平化提纯fid:name if (!window?.script_muti_get_var_store?.data) { await $.ajax({ url: unsafeWindow.__API.indexForumList(), dataType: 'script', cache: true }) } const _forumData = script_muti_get_var_store.data?.['0']?.all if (_forumData && typeof _forumData == 'object') { for (const v1 of Object.values(_forumData)) { if (v1.content && typeof v1.content == 'object') { for (const v2 of Object.values(v1.content)) { if (v2.content && typeof v2.content == 'object') { for (const v3 of Object.values(v2.content)) { this.forumData[v3.fid] = v3.name } } } } } } }) }, getUserLocation(uid) { $('.hld__user-enhance-'+uid).find('.hld__user-location > span').attr('class', 'userval numeric loading').empty() // 调用数据接口获取属地 this.getRemoteUserInfo(uid) .then(remoteUserInfo => { $('.hld__user-enhance-'+uid).find('.hld__user-location').attr('title', `IP属地: ${remoteUserInfo.ipLoc}`) $('.hld__user-enhance-'+uid).find('.hld__user-location > span').replaceWith(this.getCountryFlag(remoteUserInfo.ipLoc)) }) .catch(err => { $('.hld__user-enhance-'+uid).find('.hld__user-location > span').attr('class', 'userval numeric hld__req-retry').html(`获取失败(${err.status}), 点击重试`) }) }, /** * 调用接口获取用户信息 * @param {String} uid 用户UID * @returns Promise 用户信息对象 */ getRemoteUserInfo(uid) { const storageKey = `USERINFO_${uid}` return new Promise((resolve, reject) => { this.store.getItem(storageKey) .then(value => { if (value) { resolve(value) } else { $.ajax({url: `https://${window.location.host}/nuke.php?__output=11&__act=get&__lib=ucp&uid=${uid}`}) .then(res => { if (res.data && Array.isArray(res.data) && res.data.length > 0) { const remoteUserInfo = res.data[0] remoteUserInfo['_queryTime'] = res.time this.store.setItem(storageKey, remoteUserInfo) resolve(res.data[0]) } }) .catch(err => reject(err)) } }) }) }, /** * 获取属地标识代码 * @param {String} chsName 中文国家名称 * @returns HTML代码 */ getCountryFlag(chsName) { let textElement = `<span class="numeric userval" name="location">${chsName}</span>` let flagElement = '' if (script.setting.advanced.locationFlagMode != 'TEXT') { const flagUrl = `https://www.huuua.com/zi/scss/icons/flag-icon-css/flags` if (CHINESE_CONVERT_ISO3166_1[chsName]) { flagElement = `<img class="hld__country-flag" onerror="this.style.width='auto'" alt="${chsName}" src="${flagUrl}/${CHINESE_CONVERT_ISO3166_1[chsName].toLowerCase()}.svg"/>` } else if (#####_PROVINCE.includes(chsName)) { flagElement = `<img class="hld__country-flag" onerror="this.style.width='auto'" alt="##" src="${flagUrl}/cn.svg"/> ` const specialArea = ['##', '#门', '##'].find(name => chsName.endsWith(name)) if (specialArea) { flagElement += `<img class="hld__country-flag" onerror="this.style.width='auto'" alt="##${chsName}" src="${flagUrl}/${CHINESE_CONVERT_ISO3166_1['##'+chsName].toLowerCase()}.svg"/> ` } } } switch (script.setting.advanced.locationFlagMode) { case 'FLAG': return flagElement case 'TEXT': return textElement case 'FLAG_AND_TEXT': return flagElement + textElement default: return textElement } }, /** * 查询用户最近活动记录(3页) * @param {Object} userInfo 用户信息对象 */ async queryUserActivityRecords(userInfo) { $('#hld__chart_cover').remove() if (typeof echarts === 'undefined') { script.popMsg('该功能所需资源库正在加载,请稍后再试', 'warn') return } $('body').append(` <div id="hld__chart_cover" class="animated zoomIn"> <a href="javascript:void(0)" class="hld__setting-close">×</a> <div id="hld__chart_container"> <div class="loading"></div> </div> <div class="hld__chart-statistics"> <div class="hld__statistics-status"> <div class="hld__st-t">🏷️ 当前统计的数据量</div> <div class="hld__st-s1">用户发布的主题(页):</div> <div class="hld__st-s1-1">- 已统计 <span class="hld__st-c" id="hld__statistics_post_pages">0</span>页 <span class="hld__st-l" id="hld__statistics_post_status"></span> </div> <div class="hld__st-s1">用户回复的主题(页)</div> <div class="hld__st-s1-1">- 已统计 <span class="hld__st-c" id="hld__statistics_reply_pages">0</span>页 <span class="hld__st-l" id="hld__statistics_reply_status"></span> </div> <div class="hld__st-s1">数据天数跨度</div> <div class="hld__st-s1-1">- 已统计 <span class="hld__st-c" id="hld__statistics_days_range">-</span>天内 </div> <div class="hld__st-t">🏷️ 统计结果</div> <div class="hld__st-s2">✔️ 发布主题: <span class="hld__st-c" id="hld__statistics_post_count">-</span></div> <div class="hld__st-s2">✔️ 回复主题: <span class="hld__st-c" id="hld__statistics_reply_count">-</span></div> <div class="hld__st-s2">✔️ 总计发帖: <span class="hld__st-c" id="hld__statistics_total_count">-</span></div> </div> <button id="hld__chart_deep_query">深度统计</button> </div> </div> `) $('#hld__chart_cover .hld__setting-close').click(() => { this.queryUserDeepRecords('end') $('#hld__chart_cover').remove() }) $('#hld__chart_cover #hld__chart_deep_query').click(() => this.queryUserDeepRecords()) this.activeCount = [] this.requestTasks = [] this.currentUserInfo = userInfo this.pageInfo = { post: { label: '发布主题', pages: 0, status: '', earliestPostdate: new Date().getTime() / 1000 }, reply: { label: '回复主题', pages: 0, status: '', earliestPostdate: new Date().getTime() / 1000 } } // 查询发帖记录 // tips: 由于NGA限流, 此处暂先拉取一页回复记录 for (let i=0;i<1;i++) { // 查询发帖记录 // this.requestTasks.push(this.requestUserRecords(userInfo.uid, 'post', i+1)) // 查询回复记录 this.requestTasks.push(this.requestUserRecords(userInfo.uid, 'reply', i+1)) } Promise.allSettled(this.requestTasks) .then(() => { // 渲染chart const chartContainer = document.getElementById('hld__chart_container') if (!chartContainer) return this.chart = echarts.init(chartContainer) this.statisticsCount() this.updateChart() }) .catch(err => { script.popMsg(`查询【${this.pageInfo[err.type].label}第${err.page}页】数据接口失败! 原因: ${err.errMsg}`, 'err') }) }, /** * 查询当前用户深度活动记录(到上限) */ async queryUserDeepRecords(status) { if (status != 'end' && !$('#hld__chart_deep_query').hasClass('hld__query-loading')) { // 步进统计 $('#hld__chart_deep_query').addClass('hld__query-loading').text('暂停统计') this.queryTimer = setInterval(async () => { try { if (!this.pageInfo.post.status.endsWith('max')) { await this.requestUserRecords(this.currentUserInfo.uid, 'post', this.pageInfo.post.pages + 1) } else if (!this.pageInfo.reply.status.endsWith('max')) { await this.requestUserRecords(this.currentUserInfo.uid, 'reply', this.pageInfo.reply.pages + 1) } if (this.pageInfo.post.status.endsWith('max') && this.pageInfo.reply.status.endsWith('max')) { this.queryUserDeepRecords('end') // 停止(完成)统计 } } catch (err) { script.popMsg(`查询【${this.pageInfo[err.type].label}第${err.page}页】数据接口失败! 原因: ${err.errMsg}`, 'err') this.queryUserDeepRecords('pause') // 停止(暂停)统计 } finally { this.statisticsCount() this.updateChart() } }, 2000) } else { // 暂停&完成统计 $('#hld__chart_deep_query').removeClass('hld__query-loading').text('继续统计') if (status == 'end') { $('#hld__chart_deep_query').attr('disabled', 'disabled').text('统计完成') } if (this.queryTimer) { clearInterval(this.queryTimer) this.queryTimer = null } } }, /** * 统计数量 */ statisticsCount(validList, incrField) { if (validList && incrField) { validList.forEach(item => { const pName = item.parent && item.parent['2'] ? item.parent['2'] : '' let existRecord = this.activeCount.find(p => p.fid == item.fid) if (!existRecord) { existRecord = {fid: item.fid, name: pName, postdate: item.postdate, value: 0, post: 0, reply: 0} this.activeCount.push(existRecord) } existRecord['fid'] = item.fid existRecord['name'] ||= pName existRecord['value'] += 1 existRecord[incrField] += 1 }) } const postCount = this.activeCount.reduce((p, c) => p + c.post, 0) const replyCount = this.activeCount.reduce((p, c) => p + c.reply, 0) // 计算统计数据 $('#hld__statistics_post_pages').text(this.pageInfo.post.pages) $('#hld__statistics_post_status').attr('class', `hld__st-l ${this.pageInfo.post.status}`) $('#hld__statistics_reply_pages').text(this.pageInfo.reply.pages) $('#hld__statistics_reply_status').attr('class', `hld__st-l ${this.pageInfo.reply.status}`) $('#hld__statistics_post_count').text(postCount) $('#hld__statistics_reply_count').text(replyCount) $('#hld__statistics_total_count').text(postCount + replyCount) // 计算时间跨度 const minPostDate = Math.min(this.pageInfo.post.earliestPostdate, this.pageInfo.reply.earliestPostdate) const daysRange = Math.ceil((new Date().getTime() / 1000 - minPostDate) / 86400) $('#hld__statistics_days_range').text(daysRange) }, /** * 发起查询用户记录 */ requestUserRecords(uid, type, page) { return new Promise((resolve, reject) => { let url = `https://${window.location.host}/thread.php?__output=11&authorid=${uid}&page=${page}` if (type == 'reply') { url += '&searchpost=1' } $.ajax({url}) .then(postRes => { const err = postRes.error if (postRes.data && postRes.data.__T) { if (page > this.pageInfo[type].pages) { this.pageInfo[type].pages = page } if (this.pageInfo[type].status != 'hld__grab-max') { this.pageInfo[type].status = '' } postRes.data.__T.forEach(item => { if (item?.__P?.postdate && item.__P.postdate < this.pageInfo[type].earliestPostdate) { this.pageInfo[type].earliestPostdate = item.__P.postdate } }) this.statisticsCount(postRes.data.__T, type) } if (err) { const errMsg = (err && Array.isArray(err)) ? err.join(' ') : err if (errMsg.includes('没有符合条件的结果')) { this.pageInfo[type].status = 'hld__grab-max' } else { this.pageInfo[type].status = 'hld__grab-err' reject({errMsg, type, page}) return } } resolve() }) .catch(err => reject({ errMsg: `服务器HTTP返回:${err.status}`, type, page })) }) }, /** * 更新图表 */ updateChart() { // 处理未命名板块 this.activeCount.forEach(item => item.name ||= (this.forumData[item.fid] || `板块FID: ${item.fid}`)) this.chart.setOption({ title: { text: '用户活跃板块记录', subtext: this.currentUserInfo.username || `UID: ${this.currentUserInfo.username}`, top: 10, left: 'center' }, tooltip: { formatter: function(row) { return `${row.data.name}<br />总计: ${row.data.value}<br>发布: ${row.data.post}<br>回复: ${row.data.reply}` } }, toolbox: { show: true, bottom: 10, left: 10, itemSize: 16, feature: { saveAsImage: {show: true}, }, }, legend: { type: 'scroll', orient: 'vertical', left: 10, top: 'middle' }, series: [{ name: '板块', type: 'pie', radius: '50%', label: { formatter: function(row) { return `{name|${row.data.name}}\n{detail|发布: ${row.data.post}} {detail|回复: ${row.data.reply}}` }, minMargin: 5, edgeDistance: 10, lineHeight: 15, rich: {detail: { fontSize: 10, color: '#999' }} }, labelLine: { length: 15, length2: 0, maxSurfaceAngle: 80 }, labelLayout: params => { const isLeft = params.labelRect.x < this.chart.getWidth() / 2 const points = params.labelLinePoints if (points) { points[2][0] = isLeft ? params.labelRect.x : params.labelRect.x + params.labelRect.width } return {labelLinePoints: points} }, data: this.activeCount, emphasis: { itemStyle: {shadowBlur: 10, shadowOffsetX: 0, shadowColor: 'rgba(0, 0, 0, 0.5)'} } }], graphic: [{ type: 'image', right: 10, bottom: 30, style: { image: POWER_BY_NGASCRIPT, width: 150 } }] }) $('.hld__chart-statistics').show() }, style: ` .hld__user-enhance {display:flex;flex-wrap:wrap;} .hld__user-enhance > div {box-sizing:border-box;width:50%;padding-right:3px;} .hld__user-enhance span[name=location] {margin-left:5px;} .hld__country-flag {width:20px;height:auto;margin-left:5px;} .hld__user-location .loading {width:8px;height:8px;border:1px solid #9c958b;border-top-color:transparent;border-radius:100%;animation:loading-circle infinite 0.75s linear;} .hld__user-location .hld__req-retry:hover {text-decoration: underline;cursor: pointer;} .hld__qbc {width:100% !important;padding:5px 0;} .hld__qbc > button {margin:0;} #hld__chart_cover {position:fixed;top:50%;left:50%;transform:translate(-50%, -50%);border-radius:10px;background:#FFF;border:1px solid #AAA;box-shadow:0 0 10px rgba(0,0,0,.3);z-index:9993;} #hld__chart_cover > .hld__setting-close {background:#FFF;border:1px solid #AAA;color:#AAA;} #hld__chart_cover > .hld__setting-close:hover {background:#AAA;border:1px solid #FFF;color:#FFF;} #hld__chart_container {width:1000px;height:600px;} #hld__chart_cover .loading {position:absolute;top: 50%;left:50%;margin-top:-20px;margin-left:-25px;width:40px;height:40px;border:2px solid #AAA;border-top-color:transparent;border-radius:100%;animation:loading-circle infinite 0.75s linear;} .hld__chart-statistics {display:none;position:absolute;top:calc(50% - 220px);right:10px;min-width:140px;height:400px;} .hld__statistics-status > div {padding: 2px 0;} .hld__statistics-status > .hld__st-t {font-weight:bold;font-size:1.1em;padding-top: 25px;} .hld__statistics-status > .hld__st-s1 {margin-top: 10px;} .hld__statistics-status > .hld__st-s1-1 {font-size:0.9em;color:#00000073;} .hld__statistics-status .hld__st-c {font-weight:bold;font-size:18px;color:#1677ff;margin:0px 2px;} .hld__statistics-status .hld__st-l {display: inline-block;padding: 1px 5px;color: #FFF;transform: scale(0.8);border-radius: 5px;} .hld__statistics-status .hld__st-l.hld__grab-max {background: #67c23a;} .hld__statistics-status .hld__st-l.hld__grab-max:after {content: '最大';} .hld__statistics-status .hld__st-l.hld__grab-err {background: #f56c6c;} .hld__statistics-status .hld__st-l.hld__grab-err:after {content: '错误';} #hld__chart_deep_query {display:flex;align-items:center;margin-top:30px;background:#1677ff;border-color:#1677ff;color:#FFF;padding:6px 15px;border-radius:8px;text-align:center;cursor:pointer;} #hld__chart_deep_query:not(disabled):hover {opacity:.7;} #hld__chart_deep_query:disabled {background: #67c23a;} .hld__query-loading:before {content:"";display: inline-block;margin-right: 5px;width: 8px;height: 8px;border: 2px solid #fff;border-top-color: transparent;border-radius: 100%;animation: loading-circle infinite 0.75s linear;} .hld__statistics-status. {padding:10px 0;} @keyframes loading-circle {0% {transform:rotate(0);}100% {transform:rotate(360deg);}} ` } /** * 插件支持模块 * @name PluginSupport * @description 此模块提供了插件支持的能力 */ const PluginSupport = { name: 'PluginSupport', title: '插件支持', pluginSetting: null, preProcFunc() { script.setting.plugin = {} this.pluginSetting = script.setting.plugin }, initFunc() { // 添加到配置面板的设置入口 script.getModule('SettingPanel').addButton({ title: '插件管理', desc: '插件管理', click: () => $('#hld__plugin_panel').show() }) try { // 注册插件管理面板 GM_registerMenuCommand('插件管理', () => $('#hld__plugin_panel').show()) } catch {} // 添加插件到导入导出配置 script.getModule('BackupModule').addItem({ title: '插件配置', writeKey: 'plugin_setting', valueKey: 'pluginSetting', module: this }) // 添加插件 if (unsafeWindow.ngaScriptPlugins) { script.printLog(`检测到个${unsafeWindow.ngaScriptPlugins.length}插件`) unsafeWindow.ngaScriptPlugins.forEach(module => { module.name && this.addPlugin(module) }) } // 加载配置 this.loadSetting() this.initSettingPanel() }, initSettingPanel() { const _this = this // 插件设置面板 const $pluginPanel = $(` <div id="hld__plugin_panel" class="hld__list-panel animated fadeInUp"> <a href="javascript:void(0)" class="hld__setting-close" close-type="hide">×</a> <div class="hld__plugin-header"><b>插件管理</b></div> <div class="hld__plugin-scorllarea"> <div class="hld__plugin-content"></div> </div> <div class="hld__plugin-footer"> <button class="hld__btn" id="hld__plugin_getmore">获取更多插件</button> <button class="hld__btn" id="hld__plugin_save">保存</button> </div> </div> `) const ngaScriptPlugins = unsafeWindow?.ngaScriptPlugins || [] ngaScriptPlugins.forEach(module => { const $plugin = $(` <div class="hld__plugin"> <div class="hld__plugin-info"> <div class="hld__plugin-name"> <a href="${module.meta.updateURL || module.meta.namespace}" target="_blank">${module.title || module.name}<span>v${module.version}</span></a> </div> <div class="hld__plugin-desc" title="${module.desc}">${module.desc}</div> </div> </div> `) if (module.error) { // 插件有误 $plugin.addClass('hld__plugin-error hld__help') $plugin.attr('error', module.error).attr('help', '插件未执行,原因: ' + module.errorMsg) } const pluginID = this.getPluginID(module) if (!module.error && (module.setting || module.settings)) { let settings = [] if (Array.isArray(module.settings)) { settings.push(...module.settings) } else if (Array.isArray(module.setting)) { settings.push(...module.setting) } else if (typeof module.setting == 'object') { settings.push(module.setting) } const $pluginSettings = $('<div class="hld__plugin-settings"><table></table></div>') // 渲染表单 settings.forEach(setting => { let formItem = '' const valueType = typeof setting.default if (valueType === 'boolean') { formItem = `<input type="checkbox" plugin-id="${pluginID}" plugin-setting-key="${setting.key}">` } if (valueType === 'number') { formItem = `<input type="number" plugin-id="${pluginID}" plugin-setting-key="${setting.key}">` } if (valueType === 'string') { if (setting.options) { let t = '' for (const option of setting.options) { t += `<option value="${option.value}">${option.label}</option>` } formItem = `<select plugin-id="${pluginID}" plugin-setting-key="${setting.key}">${t}</select>` } else if (setting.type == 'textarea') { formItem = `<textarea rows="3" plugin-id="${pluginID}" plugin-setting-key="${setting.key}" />` } else { formItem = `<input type="text" plugin-id="${pluginID}" plugin-setting-key="${setting.key}" />` } } $pluginSettings.find('table').append(` <tr> <td><span ${setting.desc ? 'class="hld__help" help="' + setting.desc + '" ' : ''}>${setting.title || setting.key}</span></td> <td>${formItem}</td> </tr> `) // 恢复设置 let defaultValue = setting.default if (script.setting.plugin?.[pluginID]?.[setting.key] != undefined) { defaultValue = script.setting.plugin[pluginID][setting.key] } const $input = $pluginSettings.find(`[plugin-id="${pluginID}"][plugin-setting-key="${setting.key}"]`) if (typeof defaultValue == 'boolean') { $input[0].checked = defaultValue } if (typeof defaultValue == 'number' || typeof defaultValue == 'string') { $input.val(defaultValue) } setting.$el = $input }) // 添加按钮及设置面板 $plugin.append($pluginSettings) $plugin.find('.hld__plugin-info').append(`<div class="hld__plugin-expand hld__help" help="查看插件设置"><img src="${SVG_ICON_SETTING}"></div>`) } // 自定义按钮 if (module.buttons && Array.isArray(module.buttons) && module.buttons.length > 0) { const $pluginButtons = $('<div class="hld__plugin-buttons"></div>') module.buttons.forEach((button, index) => { const buttonid = `${pluginID}_button_${index}` const $button = $(`<button class="hld__btn" id="${buttonid}">${button.title || '未命名按钮'}</button>`) $button.click(() => { // 插件注入对象 const moduleProxy = this.createModuleProxy(module) if (typeof button.action == 'string' && typeof module[button.action] == 'function') { module[button.action].apply(moduleProxy, [button.args]) } if (typeof button.action == 'function') { button.action.apply(moduleProxy, [button.args]) } }) button.$el = $button $pluginButtons.append($button) }) $plugin.find('.hld__plugin-settings').append($pluginButtons) } if ($plugin.find('.hld__plugin-settings tr').length == 0 && $plugin.find('.hld__plugin-settings button').length == 0) { $plugin.find('.hld__plugin-settings').append('<div class="hld__plugin-nosettings">暂无可配置项</div>') } $pluginPanel.find('.hld__plugin-content').append($plugin) }) if (ngaScriptPlugins.length == 0) { $pluginPanel.find('.hld__plugin-content').html('<div class="hld_plugin-empty">未安装任何插件</div>') } // 展开设置 $pluginPanel.find('.hld__plugin-expand').click(function(){ $(this).parent().siblings('.hld__plugin-settings').slideToggle(100) }) // 获取更多插件 $pluginPanel.find('#hld__plugin_getmore').click(function(){ window.open('https://greasyfork.org/zh-CN/scripts?q=NGA%E4%BC%98%E5%8C%96%E6%91%B8%E9%B1%BC%E4%BD%93%E9%AA%8C%E6%8F%92%E4%BB%B6') }) // 保存设置 $pluginPanel.find('#hld__plugin_save').click(function(){ _this.saveSetting() }) $('body').append($pluginPanel) }, /** * 添加插件 * @param {*} module 插件模块 */ addPlugin(module) { module.type = 'plugin' module.title = module.title || module.meta.name module.desc = module.desc || module.meta.description module.author = module.author || module.meta.author || 'Unknown' module.version = module.meta.version || '1.0.0' // 检测是否与标准模块命名冲突,此检测是为了未来可以合并插件功能进主脚本内而做的预设性检查 const pluginID = this.getPluginID(module) const existBasicModule = script.modules.find(m => m.type != 'plugin' && m.name == module.name) if (existBasicModule) { module.error = 'UNIQUE_BASIC' module.errorMsg = `插件[${module.name}]与标准模块重名,可能是标准模块已有此功能` script.printLog(`[${module.name}]${module.errorMsg}`) return } // 检测重复插件,插件Name@Author字符串为唯一key值,如重复导入将不会运行 const duplicatePlugin = script.modules.find(m => m.type == 'plugin' && `${m.name}@${this.hashCode(m.author)}` == pluginID) if (duplicatePlugin) { module.error = 'DUPLICATED' module.errorMsg = `重复导入,插件[${pluginID}]当前已加载` script.printLog(`[${module.name}]${module.errorMsg}`) return } // 插件预处理函数 if (module.preProcFunc) { try { module.preProcFunc() } catch (error) { this.printLog(`[${module.name}]插件在[preProcFunc()]中运行失败!`) console.log(error) } } // 添加设置 const addSetting = setting => { // // 插件配置 // if (setting.shortCutCode && script.setting.plugin.shortcutKeys) { // script.setting.plugin.shortcutKeys.push(setting.shortCutCode) // } if (setting.key) { if (!script.setting.plugin[pluginID]) { script.setting.plugin[pluginID] = {} } script.setting.plugin[pluginID][setting.key] = setting.default ?? '' script.setting.original.push(Object.assign({type: 'plugin', pluginID}, setting)) } } // 功能板块 if (module.setting && !Array.isArray(module.setting)) { addSetting(module.setting) } if (module.settings && Array.isArray(module.settings)) { for (const setting of module.settings) { addSetting(setting) } } // 添加样式 if (module.style) { script.style += module.style } const moduleProxy = this.createModuleProxy(module) script.modules.push(moduleProxy) }, /** * 插件注入对象 * @param {*} module 插件模块 */ createModuleProxy(module) { const pluginID = this.getPluginID(module) return new Proxy(module, { get: function (target, key) { if (key == 'mainScript') return script // 主脚本 if (key == 'pluginID') return pluginID // 插件ID if (key == 'pluginSettings') return script.setting.plugin[pluginID] // 插件保存配置 // 插件输入控件dom if (key == 'pluginInputs') { const pluginInputs = {} Object.keys(script.setting.plugin[pluginID]).forEach(key => { pluginInputs[key] = $(`[plugin-id="${pluginID}"][plugin-setting-key="${key}"]`) }) return pluginInputs } return target[key] }, set: function (target, key, newValue) { if (['mainScript', 'pluginID', 'pluginSettings', 'pluginInputs'].includes(key)) { throw new TypeError(`[${key}]为插件保留字段,不可手动设值`) } target[key] = newValue return true } }) }, /** * 读取插件配置 * @method loadSetting */ loadSetting() { try { // 插件设置 const pluginSettingStr = script.getValue('hld__NGA_plugin_setting') if (pluginSettingStr) { let localPluginSetting = JSON.parse(pluginSettingStr) for (const pluginName of Object.keys(localPluginSetting)) { let currentSetting = script.setting.plugin[pluginName] let localSetting = localPluginSetting[pluginName] if (currentSetting) { for (let k in currentSetting) { !localSetting.hasOwnProperty(k) && (localSetting[k] = currentSetting[k]) } for (let k in localSetting) { !currentSetting.hasOwnProperty(k) && delete localSetting[k] } } script.setting.plugin[pluginName] = localSetting } } } catch(e) { script.throwError(`【NGA-Script】读取插件配置文件出现错误,无法加载配置文件!\n错误问题: ${e}\n\n请尝试使用【修复脚本】来修复此问题`) } }, /** * 保存插件配置 * @method saveSetting * @param {String} msg 自定义消息信息 */ saveSetting (msg='保存插件配置成功,刷新页面生效') { script.modules.forEach(module => { if (module.type == 'plugin' && module.name) { const pluginID = this.getPluginID(module) const pluginSetting = Object.assign({}, script.setting.plugin[pluginID]) const $controls = $(`[plugin-id="${pluginID}"]`) if (pluginSetting && $controls) { $controls.each((index, element) => { const k = $(element).attr('plugin-setting-key') const inputType = $(element)[0].nodeName const originalSetting = script.setting.original.find(s => s.type == 'plugin' && s.pluginID == pluginID && s.key == k) const valueType = typeof originalSetting.default if (inputType == 'SELECT') { pluginSetting[k] = $(element).val() } else { if (valueType == 'boolean') { pluginSetting[k] = $(element)[0].checked } if (valueType == 'number') { pluginSetting[k] = +$(element).val() } if (valueType == 'string') { pluginSetting[k] = $(element).val() } } }) // 预检查配置参数 if (module.beforeSaveSettingFunc) { const errorMsg = module.beforeSaveSettingFunc(pluginSetting) if (errorMsg && typeof errorMsg === 'string') { script.throwError(`插件【${module.title || module.name || 'UNKNOW'}】检查配置返回错误: \n${'-'.repeat(50)}\n${errorMsg}`) } } script.setting.plugin[pluginID] = Object.assign({}, pluginSetting) } } }) script.setValue('hld__NGA_plugin_setting', JSON.stringify(script.setting.plugin)) msg && script.popMsg(msg) $('#hld__plugin_panel').hide() }, /** * 获取插件的唯一ID * @param {obj} module 插件对象 */ getPluginID(module) { return `${module.name}@${this.hashCode(module.author)}` }, /** * 生成字符串哈希值 * @param {String} str 字符串 * @returns 哈希值 */ hashCode(str) { return str.split('').reduce((prevHash, currVal) => (((prevHash << 5) - prevHash) + currVal.charCodeAt(0))|0, 0) }, style: ` #hld__plugin_panel {display:none;width:400px;min-height:300px;} #hld__plugin_panel .hld__plugin-header {min-height:20px;} #hld__plugin_panel .hld__plugin-scorllarea {margin:10px 0;height:300px;padding-right:10px;overflow-y:auto;border-top:1px solid #e0c19e;border-bottom:1px solid #e0c19e;} #hld__plugin_panel .hld__plugin-content {height:auto;} #hld__plugin_panel .hld_plugin-empty {margin-top:20%;text-align:center;font-size:16px;color:#666;} #hld__plugin_panel .hld__plugin-footer {min-height:32px;display:flex;justify-content:space-between;} #hld__plugin_panel button {transition:all .2s ease;cursor:pointer;} .hld__plugin {padding:10px 0;border-bottom:1px dashed #666;} .hld__plugin-error {text-decoration: line-through;} .hld__plugin-info {position:relative;padding-right:30px;box-sizing:border-box;} .hld__plugin-name {margin-bottom:5px;} .hld__plugin-name a {font-weight:bold;font-size:16px;color:#591804;} .hld__plugin-name span {margin-left:4px;font-size:70%;color:#666;} .hld__plugin-desc {white-space:nowrap;overflow:hidden;text-overflow:ellipsis;} .hld__plugin-expand {width:20px;display:flex;align-items:center;cursor:pointer;position:absolute;top:10px;right:0px;} .hld__plugin-expand img {width:100%;transition:all .2s ease} .hld__plugin-expand:hover img {width:100%;transform:rotate(45deg);} .hld__plugin-settings {display:none;width:100%;height:auto;border-top:1px dashed #999;margin-top:10px;padding-top:10px;} .hld__plugin-settings table td {padding-right:10px;} .hld__plugin-settings textarea {resize:none;} .hld__plugin-settings input[type=number] {border: 1px solid #e6c3a8;box-shadow: 0 0 2px 0 #7c766d inset;border-radius: 0.25em;} .hld__plugin-buttons {padding-top:5px;} .hld__plugin-buttons > button {margin-right:5px;margin-top:5px;} .hld__plugin-nosettings {color:#666;} ` } /** * 初始化脚本 */ const script = new NGABBSScript() /** * 添加模块 */ script.addModule(SettingPanel) script.addModule(ShortCutKeys) script.addModule(BackupModule) script.addModule(PluginSupport) script.addModule(RewardPanel) script.addModule(HideAvatar) script.addModule(HideSmile) script.addModule(HideImage) script.addModule(ImgResize) script.addModule(HideSign) script.addModule(HideHeader) script.addModule(ExcelMode) script.addModule(FoldQuote) script.addModule(UserEnhance) script.addModule(LinkTargetBlank) script.addModule(DirectLinkJump) script.addModule(ImgEnhance) script.addModule(AuthorMark) script.addModule(AutoPage) script.addModule(KeywordsBlock) script.addModule(MarkAndBan) script.addModule(EyeCareMode) script.addModule(DarkMode) script.addModule(FontResize) script.addModule(ExtraDocker) script.addModule(DomainRedirect) /** * 运行脚本 */ script.run() })();