// ==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
// @downloadURL https://update.greasyfork.cloud/scripts/393991/NGA%E4%BC%98%E5%8C%96%E6%91%B8%E9%B1%BC%E4%BD%93%E9%AA%8C.user.js
// @updateURL https://update.greasyfork.cloud/scripts/393991/NGA%E4%BC%98%E5%8C%96%E6%91%B8%E9%B1%BC%E4%BD%93%E9%AA%8C.meta.js
// ==/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('
')
let $msgBox = $(`${msg}
`)
$('#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 = $(`${msg}
`)
$('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(`×NGA-Script已更新至v${GM_info.script.version}
${focus}
查看更新内容
`)
$('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 = $(`
`)
const insertDom = setting => {
if (setting.type === 'normal') {
$panelDom.find(`#hld__normal_${setting.menu || 'left'}`).append(`
`)
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(`
`)
}
}
if (setting.type === 'advanced') {
let formItem = ''
const valueType = typeof setting.default
if (valueType === 'boolean') {
formItem = ``
}
if (valueType === 'number') {
formItem = ``
}
if (valueType === 'string') {
if (setting.options) {
let t = ''
for (const option of setting.options) {
t += ``
}
formItem = ``
} else {
formItem = ``
}
}
$panelDom.find(`#hld__advanced_${setting.menu || 'left'}`).append(`
${setting.title || setting.key} |
${formItem} |
`)
}
}
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 = $(`${$(this).attr('help').replace(/\n/g, '
')}
`)
$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('')
let $entry = $('NGA优化摸鱼插件设置')
$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 = $(``)
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:99996;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 = $(`
×
编辑快捷键
支持的快捷键范围
键盘 A
~Z
左箭头 LEFT
右箭头 RIGHT
上箭头 UP
下箭头 DOWN
* 留空则取消快捷键
如按键异常请尝试重置按键
`)
const insertDom = setting => $shortcutPanel.find('.hld__table tbody').append(`${setting.title || setting.key} | |
`)
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(`
`)
// 加载其他模组备份项
for (const item of _this.backupItems) {
$('#hld__export_panel_cb').append(`
`)
}
/**
* 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('没有选择任何项目可供导出!')
return
}
const backupB64 = _this.export(exportItems, $('#hld__cb_export_encode').prop('checked'))
$('#hld__export_str').val(backupB64)
$('#hld__export_msg').html(`导出成功(${_this.calculateSize(backupB64.length)}),请复制右侧字符串以备份`)
})
/**
* 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('导入成功,刷新浏览器以生效')
} catch (err){
script.printLog(`JSON解析失败: ${err}`)
$('#hld__export_msg').html('字符串有误,解析失败!')
}
}
})
})
},
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 = 1024
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})的脚本导出,请升级您的脚本 [脚本地址]`, '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: '¥赏',
desc: '好活当赏'
})
/**
* Bind:Click
* 打赏面板
*/
$('body').on('click', '#hld__reward', function () {
$('#hld__setting_cover').append(`
×
喜欢此脚本请可以去作者Github点个⭐️
如果觉得脚本好用摸到鱼了,也可以请作者喝杯☕意思意思,打多少零看缘分😎
如若有功能需求或者建议,欢迎在社区进行反馈
`)
})
},
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 = $('[' + alt + ']')
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 = $('')
$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 = $('')
$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(`
`)
// 插入Excel尾部
$('body').append(`
`)
} else {
// WPS与Office元素
// 插入Excel头部
$('body').append(`
`)
// 插入Excel尾部
$('body').append(`
`)
}
$('#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(``)
}
},
renderFormsFunc($el) {
$el.find('.postrow>td:first-child').before(' | ')
},
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 = $(``)
$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 = $(``)
$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 = $('')
let $imgContainer = $('')
let $img = $('
')
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(`
`)
/**
* 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('楼主')
}
})
}
},
/**
* 获取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(``)
$('#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('.ubbcode').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(``)
/**
* 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 = `
`
script.setting.advanced.autoHideBanIcon ? $(this).after(``) : $(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 = $('此用户在你的黑名单中,已屏蔽其言论,点击查看
')
if ($(this).parents('div.comment_c').length > 0) {
$(this).parents('div.comment_c').find('.ubbcode').hide()
$(this).parents('div.comment_c').find('.ubbcode').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('')
}
}
} 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('此用户在你的黑名单中,已删除其言论
')
}
}
if (banUser.desc) {
$(this).parents('.postrow').find('.hld__banned').append(`备注: ${banUser.desc}
`)
}
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(``)
}
}else {
//新版标签风格
const userMarks = _this.getUserMarks({name, uid})
if(userMarks) {
const $el = $(this).parents('.c1').find('.clickextend')
let marksDom = ''
userMarks.marks.forEach(item => marksDom += `${item.mark}`);
$el.before(`标签: ${marksDom}
`)
}
}
})
}
},
/**
* 黑名单弹窗
* @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 = $(``)
if (setting.type == 'confirm') {
$banDialog.find('#container_dom').append(`您确定要拉黑用户${setting.name}吗?
`)
let $okBtn = $('')
$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(`添加用户:
`)
let $okBtn = $('')
$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(`
${item.name} |
${item.uid} |
${item.desc || ''} |
|
`))
$('#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(`
${user_mark.name} |
${user_mark.uid} |
${user_mark.marks.length} |
|
`)
})
$('#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 = $(``)
const insertRemarkRow = (r='', t='#ffffff', b='#1f72f1', d='', n=true) => {
let $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(`
${tag.mark} (${tag.count})
`)
})
$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 = $('')
$addBtn.click(() => insertRemarkRow())
$markDialog.find('.hld__button-insert').append($addBtn)
let $okBtn = $('')
$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 = $(`
`)
$('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 = $(``)
const $node = $el.find('.posterinfo div.stat .clickextend').siblings('div:first-child')
$node.after($userEnhanceContainer)
$userEnhanceContainer.append(`坛龄: ${regDays}天
`)
$userEnhanceContainer.append(`发帖: ${userInfo.postnum}
`)
$userEnhanceContainer.append(`属地: 点击获取
`)
$userEnhanceContainer.append(``)
$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 = `${chsName}`
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 = `
`
} else if (CHINA_PROVINCE.includes(chsName)) {
flagElement = `
`
const specialArea = ['香港', '澳门', '台湾'].find(name => chsName.endsWith(name))
if (specialArea) {
flagElement += `
`
}
}
}
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(`
×
🏷️ 当前统计的数据量
用户发布的主题(页):
- 已统计
0页
用户回复的主题(页)
- 已统计
0页
数据天数跨度
- 已统计
-天内
🏷️ 统计结果
✔️ 发布主题: -
✔️ 回复主题: -
✔️ 总计发帖: -
`)
$('#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}
总计: ${row.data.value}
发布: ${row.data.post}
回复: ${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 = $(`
`)
const ngaScriptPlugins = unsafeWindow?.ngaScriptPlugins || []
ngaScriptPlugins.forEach(module => {
const $plugin = $(`
`)
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 = $('')
// 渲染表单
settings.forEach(setting => {
let formItem = ''
const valueType = typeof setting.default
if (valueType === 'boolean') {
formItem = ``
}
if (valueType === 'number') {
formItem = ``
}
if (valueType === 'string') {
if (setting.options) {
let t = ''
for (const option of setting.options) {
t += ``
}
formItem = ``
} else if (setting.type == 'textarea') {
formItem = ``
} else {
formItem = ``
}
}
$pluginSettings.find('table').append(`
${setting.title || setting.key} |
${formItem} |
`)
// 恢复设置
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(``)
}
// 自定义按钮
if (module.buttons && Array.isArray(module.buttons) && module.buttons.length > 0) {
const $pluginButtons = $('')
module.buttons.forEach((button, index) => {
const buttonid = `${pluginID}_button_${index}`
const $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('暂无可配置项
')
}
$pluginPanel.find('.hld__plugin-content').append($plugin)
})
if (ngaScriptPlugins.length == 0) {
$pluginPanel.find('.hld__plugin-content').html('未安装任何插件
')
}
// 展开设置
$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()
})();