NGA优化摸鱼体验

NGA论坛显示优化,功能增强,防止突然蹦出一对??而导致的突然性的社会死亡

目前为 2021-03-12 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name NGA优化摸鱼体验
  3. // @namespace https://github.com/kisshang1993/NGA-BBS-Script
  4. // @version 3.7.0
  5. // @author HLD
  6. // @description NGA论坛显示优化,功能增强,防止突然蹦出一对??而导致的突然性的社会死亡
  7. // @license MIT
  8. // @require https://cdn.staticfile.org/jquery/3.4.0/jquery.min.js
  9. // @require https://cdn.staticfile.org/spectrum/1.8.0/spectrum.js
  10. // @icon https://s1.ax1x.com/2020/06/28/N25WBF.png
  11. // @match *://bbs.nga.cn/*
  12. // @match *://ngabbs.com/*
  13. // @match *://nga.178.com/*
  14. // @grant GM_registerMenuCommand
  15. // @inject-into content
  16. // ==/UserScript==
  17.  
  18. (function () {
  19. 'use strict';
  20.  
  21. /**
  22. * NGA摸鱼主脚本
  23. * @class NGABBSScript
  24. * @constructor
  25. */
  26. class NGABBSScript {
  27. constructor () {
  28. // 配置
  29. this.setting = {
  30. normal: {},
  31. advanced: {},
  32. plugin: {}
  33. }
  34. // 模块
  35. this.modules = []
  36. // 样式
  37. this.style = ''
  38. }
  39. /**
  40. * 获取模块对象
  41. * @method getModule
  42. * @param {String} name 模块name
  43. * @return {Object} 模块对象
  44. */
  45. getModule (name) {
  46. for (const m of this.modules) {
  47. if (m.name && m.name === name) {
  48. return m
  49. }
  50. }
  51. return null
  52. }
  53. /**
  54. * 全程渲染函数
  55. * @method renderAlways
  56. */
  57. renderAlways() {
  58. for (const module of this.modules) {
  59. module.renderAlwaysFunc && module.renderAlwaysFunc(null)
  60. }
  61. }
  62. /**
  63. * 列表页渲染函数
  64. * @method renderThreads
  65. */
  66. renderThreads () {
  67. $('.topicrow[hld-threads-render!=ok]').each((index, dom) => {
  68. const $el = $(dom)
  69. for (const module of this.modules) {
  70. module.renderThreadsFunc && module.renderThreadsFunc($el)
  71. }
  72. $el.attr('hld-threads-render', 'ok')
  73. })
  74. }
  75. /**
  76. * 详情页渲染函数
  77. * @method renderForms
  78. */
  79. renderForms () {
  80. $('.forumbox.postbox[hld-forms-render!=ok]').each((index, dom) => {
  81. const $el = $(dom)
  82. for (const module of this.modules) {
  83. module.renderFormsFunc && module.renderFormsFunc($el)
  84. }
  85. $el.attr('hld-forms-render', 'ok')
  86. })
  87. }
  88. /**
  89. * 添加模块
  90. * @method addModule
  91. * @param {Object} module 模块对象
  92. */
  93. addModule (module) {
  94. // 组件预处理函数
  95. if (module.beforeFunc) {
  96. module.beforeFunc()
  97. }
  98. // 添加模块
  99. const addModule = setting => {
  100. if (setting.shortCutCode && this.setting.normal.shortcutKeys) this.setting.normal.shortcutKeys.push(setting.shortCutCode)
  101. if (setting.key) {
  102. this.setting[setting.type || 'normal'][setting.key] = setting.default
  103. }
  104. }
  105. // 功能板块
  106. if (module.setting && !Array.isArray(module.setting)) {
  107. addModule(module.setting)
  108. }
  109. if (module.settings && Array.isArray(module.settings)) {
  110. for (const setting of module.settings) {
  111. addModule(setting)
  112. }
  113. }
  114. // 添加样式
  115. if (module.style) {
  116. this.style += module.style
  117. }
  118. this.modules.push(module)
  119. }
  120. /**
  121. * 判断当前页面是否为列表页
  122. * @method isThreads
  123. * @return {Boolean} 判断状态
  124. */
  125. isThreads () {
  126. return $('#m_threads').length > 0
  127. }
  128. /**
  129. * 判断当前页面是否为详情页
  130. * @method isForms
  131. * @return {Boolean} 判断状态
  132. */
  133. isForms () {
  134. return $('#m_posts').length > 0
  135. }
  136. /**
  137. * 抛出异常
  138. * @method throwError
  139. * @param {String} msg 异常信息
  140. */
  141. throwError (msg) {
  142. alert(msg)
  143. throw(msg)
  144. }
  145. /**
  146. * 初始化
  147. * @method init
  148. */
  149. init () {
  150. // 开始初始化
  151. const startInitTime = new Date().getTime()
  152. //同步配置
  153. this.loadSetting()
  154.  
  155. // 组件初始化函数
  156. for (const module of this.modules) {
  157. if (module.initFunc) {
  158. module.initFunc()
  159. }
  160. }
  161. // 组件后处理函数
  162. for (const module of this.modules) {
  163. if (module.afterFunc) {
  164. module.afterFunc()
  165. }
  166. }
  167. // 异步样式
  168. for (const module of this.modules) {
  169. if (module.asyncStyle) {
  170. this.style += module.asyncStyle()
  171. }
  172. }
  173. // 插入样式
  174. const style = document.createElement("style")
  175. style.appendChild(document.createTextNode(this.style))
  176. document.getElementsByTagName('head')[0].appendChild(style)
  177. // 初始化完成
  178. const endInitTime = new Date().getTime()
  179. console.warn(`【NGA-Script[v${this.getInfo().version}]】初始化完成:共加载${this.modules.length}个模块,总耗时${endInitTime-startInitTime}ms`)
  180. }
  181. /**
  182. * 通知弹框
  183. * @method popNotification
  184. * @param {String} msg 消息内容
  185. * @param {Number} duration 显示市场(ms)
  186. */
  187. popNotification (msg, duration=1000) {
  188. $('#hld__noti_container').length == 0 && $('body').append('<div id="hld__noti_container"></div>')
  189. let $msgBox = $(`<div class="hld__noti-msg">${msg}</div>`)
  190. $('#hld__noti_container').append($msgBox)
  191. $msgBox.slideDown(100)
  192. setTimeout(() => { $msgBox.fadeOut(500) }, duration)
  193. setTimeout(() => { $msgBox.remove() }, duration + 500)
  194. }
  195. /**
  196. * 消息弹框
  197. * @method popMsg
  198. * @param {String} msg 消息内容
  199. * @param {String} type 消息类型 [ok, err, warn]
  200. */
  201. popMsg(msg, type='ok') {
  202. $('.hld__msg').length > 0 && $('.hld__msg').remove()
  203. let $msg = $(`<div class="hld__msg hld__msg-${type}">${msg}</div>`)
  204. $('body').append($msg)
  205. $msg.slideDown(200)
  206. setTimeout(() => { $msg.fadeOut(500) }, type == 'ok' ? 2000 : 5000)
  207. setTimeout(() => { $msg.remove() }, type == 'ok' ? 2500 : 5500)
  208. }
  209. /**
  210. * 保存配置到本地
  211. * @method saveSetting
  212. * @param {String} msg 自定义消息信息
  213. */
  214. saveSetting (msg='保存配置成功,刷新页面生效') {
  215. for (let k in this.setting.normal) {
  216. $('input#hld__cb_' + k).length > 0 && (this.setting.normal[k] = $('input#hld__cb_' + k)[0].checked)
  217. }
  218. window.localStorage.setItem('hld__NGA_setting', JSON.stringify(this.setting.normal))
  219. for (let k in this.setting.advanced) {
  220. if ($('#hld__adv_' + k).length > 0) {
  221. const valueType = typeof this.setting.advanced[k]
  222. const inputType = $('#hld__adv_' + k)[0].nodeName
  223. if (inputType == 'SELECT') {
  224. this.setting.advanced[k] = $('#hld__adv_' + k).val()
  225. } else {
  226. if (valueType == 'boolean') {
  227. this.setting.advanced[k] = $('#hld__adv_' + k)[0].checked
  228. }
  229. if (valueType == 'number') {
  230. this.setting.advanced[k] = +$('#hld__adv_' + k).val()
  231. }
  232. if (valueType == 'string') {
  233. this.setting.advanced[k] = $('#hld__adv_' + k).val()
  234. }
  235. }
  236. }
  237. }
  238. window.localStorage.setItem('hld__NGA_advanced_setting', JSON.stringify(this.setting.advanced))
  239. msg && this.popMsg(msg)
  240. }
  241. /**
  242. * 从本地读取配置
  243. * @method loadSetting
  244. */
  245. loadSetting () {
  246. // 基础设置
  247. try {
  248. if (window.localStorage.getItem('hld__NGA_setting')) {
  249. let localSetting = JSON.parse(window.localStorage.getItem('hld__NGA_setting'))
  250. for (let k in this.setting.normal) {
  251. !localSetting.hasOwnProperty(k) && (localSetting[k] = this.setting.normal[k])
  252. if (k == 'shortcutKeys') {
  253. if (localSetting[k].length < this.setting.normal[k].length) {
  254. const offset_count = this.setting.normal[k].length - localSetting[k].length
  255. localSetting[k] = localSetting[k].concat(this.setting.normal[k].slice(-offset_count))
  256. }
  257. // 更改默认按键
  258. let index = 0
  259. for (const module of this.modules) {
  260. if (module.setting && module.setting.shortCutCode) {
  261. if (localSetting[k][index] != module.setting.shortCutCode) {
  262. module.setting.rewriteShortCutCode = localSetting[k][index]
  263. }
  264. index += 1
  265. }else if (module.settings) {
  266. for (const setting of module.settings) {
  267. if (setting.shortCutCode) {
  268. if (localSetting[k][index] != setting.shortCutCode) {
  269. setting.rewriteShortCutCode = localSetting[k][index]
  270. }
  271. index += 1
  272. }
  273. }
  274. }
  275. }
  276. }
  277. }
  278. for (let k in localSetting) {
  279. !this.setting.normal.hasOwnProperty(k) && delete localSetting[k]
  280. }
  281. this.setting.normal = localSetting
  282. }
  283. // 高级设置
  284. if (window.localStorage.getItem('hld__NGA_advanced_setting')) {
  285. let localAdvancedSetting = JSON.parse(window.localStorage.getItem('hld__NGA_advanced_setting'))
  286. for (let k in this.setting.advanced) {
  287. !localAdvancedSetting.hasOwnProperty(k) && (localAdvancedSetting[k] = this.setting.advanced[k])
  288. }
  289. for (let k in localAdvancedSetting) {
  290. !this.setting.advanced.hasOwnProperty(k) && delete localAdvancedSetting[k]
  291. }
  292. this.setting.advanced = localAdvancedSetting
  293. }
  294. } catch {
  295. this.throwError('【NGA-Script】配置文件出现错误,无法加载配置文件!\n遇到此问题请清空浏览器缓存并重新刷新页面\n如还有问题,请前往脚本发布页提出反馈')
  296. }
  297.  
  298. }
  299. /**
  300. * 检查是否更新
  301. * @method checkUpdate
  302. */
  303. checkUpdate() {
  304. // 字符串版本转数字
  305. const vstr2num = str => {
  306. let num = 0
  307. str.split('.').forEach((n, i) => num += i < 2 ? +n * 1000 / Math.pow(10, i) : +n)
  308. return num
  309. }
  310. // 字符串中版本截取
  311. const vstr2mid = str => {
  312. return str.substring(0, str.lastIndexOf('.'))
  313. }
  314. //检查更新
  315. if (window.localStorage.getItem('hld__NGA_version')) {
  316. const local_version = vstr2num(window.localStorage.getItem('hld__NGA_version'))
  317. const current_version = vstr2num(GM_info.script.version)
  318. if (current_version > local_version) {
  319. const lv_mid = +vstr2mid(window.localStorage.getItem('hld__NGA_version'))
  320. const cv_mid = +vstr2mid(GM_info.script.version)
  321. if (cv_mid > lv_mid) {
  322. const focus = ''
  323. $('body').append(`<div id="hld__updated" class="animated-1s bounce"><p><a href="javascript:void(0)" class="hld__setting-close">×</a><b>NGA-Script已更新至v${GM_info.script.version}</b></p>${focus}<p><a class="hld__readme" href="https://gf.qytechs.cn/zh-CN/scripts/393991-nga%E4%BC%98%E5%8C%96%E6%91%B8%E9%B1%BC%E4%BD%93%E9%AA%8C" target="_blank">查看更新内容</a></p></div>`)
  324. $('body').on('click', '#hld__updated a', function () {
  325. $(this).parents('#hld__updated').remove()
  326. window.localStorage.setItem('hld__NGA_version', GM_info.script.version)
  327. })
  328. } else {
  329. window.localStorage.setItem('hld__NGA_version', GM_info.script.version)
  330. }
  331. }
  332. } else window.localStorage.setItem('hld__NGA_version', GM_info.script.version)
  333. }
  334. /**
  335. * 运行脚本
  336. * @method run
  337. */
  338. run() {
  339. this.checkUpdate()
  340. this.init()
  341. setInterval(() => {
  342. this.renderAlways()
  343. this.isThreads() && this.renderThreads()
  344. this.isForms() && this.renderForms()
  345. }, 100)
  346. }
  347. /**
  348. * 获取脚本信息
  349. * @method getInfo
  350. * @return {Object} 脚本信息对象
  351. */
  352. getInfo() {
  353. return {
  354. version: GM_info.script.version,
  355. author: 'HLD',
  356. github: 'https://github.com/kisshang1993/NGA-BBS-Script',
  357. update: 'https://gf.qytechs.cn/zh-CN/scripts/393991-nga%E4%BC%98%E5%8C%96%E6%91%B8%E9%B1%BC%E4%BD%93%E9%AA%8C'
  358. }
  359. }
  360. }
  361. /* 注册(不可用)菜单按钮 */
  362. // 设置面板
  363. GM_registerMenuCommand('设置面板', function () {
  364. $('#hld__setting_cover').css('display', 'flex')
  365. })
  366. // 修复脚本
  367. GM_registerMenuCommand('修复脚本', function () {
  368. if (window.confirm('如脚本运行失败或无效,尝试修复脚本,这会清除脚本的本地缓存信息\n* 本地缓存信息包含配置,各种名单等\n* 此操作不可逆转,如果需要备份,请手动备份localStorage内的hld__*的字段\n\n继续请点击【确定】')) {
  369. window.localStorage.removeItem('hld__NGA_setting')
  370. window.localStorage.removeItem('hld__NGA_mark_list_bak')
  371. window.localStorage.removeItem('hld__NGA_ban_list')
  372. window.localStorage.removeItem('hld__NGA_keywords_list')
  373. window.localStorage.removeItem('hld__NGA_post_author')
  374. window.localStorage.removeItem('hld__NGA_version')
  375. alert('操作成功,请刷新页面重试')
  376. }
  377. })
  378. // 反馈问题
  379. GM_registerMenuCommand('反馈问题', function () {
  380. if (window.confirm('如脚本运行失败而且修复后也无法运行,请反馈问题报告\n* 问题报告请包含使用的:[浏览器],[脚本管理器],[脚本版本]\n* 描述问题最好以图文并茂的形式\n* 如脚本运行失败,建议提供F12控制台的红色错误输出以辅助排查\n\n即将打开反馈页面,继续请点击【确定】')) {
  381. window.open('https://gf.qytechs.cn/zh-CN/scripts/393991-nga%E4%BC%98%E5%8C%96%E6%91%B8%E9%B1%BC%E4%BD%93%E9%AA%8C/feedback')
  382. }
  383. })
  384. /* 标准模块 */
  385. /**
  386. * 默认样式
  387. * @name defaultStyle
  388. * @description 脚本的初始样式
  389. */
  390. const defaultStyle = {
  391. style: `
  392. .animated {animation-duration:.3s;animation-fill-mode:both;}
  393. .animated-1s {animation-duration:1s;animation-fill-mode:both;}
  394. .zoomIn {animation-name:zoomIn;}
  395. .bounce {-webkit-animation-name:bounce;animation-name:bounce;-webkit-transform-origin:center bottom;transform-origin:center bottom;}
  396. .fadeInUp {-webkit-animation-name:fadeInUp;animation-name:fadeInUp;}
  397. #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;}
  398. @keyframes loader {0% {-webkit-transform:rotate(0deg);transform:rotate(0deg);}100% {-webkit-transform:rotate(360deg);transform:rotate(360deg);}}
  399. @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;}}
  400. @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);}}
  401. @keyframes fadeInUp {from {opacity:0;-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0);}to {opacity:1;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);}}
  402. .hld__msg{display:none;position:fixed;top:10px;left:40%;color:#fff;text-align:center;z-index:99996;padding:10px 30px 10px 45px;font-size:16px;border-radius:10px;background-image:url("data:image/svg+xml,%3Csvg t='1595842925125' class='icon' viewBox='0 0 1024 1024' version='1.1' xmlns='http://www.w3.org/2000/svg' p-id='2280' width='200' height='200'%3E%3Cpath d='M89.216226 575.029277c-6.501587-7.223986-10.47478-15.892769-12.641975-26.367549-1.805996-10.47478-0.722399-20.22716 3.973192-29.257143l4.695591-10.47478c5.05679-8.307584 11.558377-13.725573 19.865961-15.892769 7.946384-2.167196 15.892769-0.361199 23.477954 5.417989L323.995767 639.322751c8.307584 5.779189 17.698765 8.668783 27.812346 8.307584 10.11358-0.361199 18.782363-3.611993 26.006349-10.11358L898.302646 208.411993c7.585185-5.779189 16.253968-8.307584 26.006349-7.585185 9.752381 0.722399 18.059965 4.334392 24.922751 10.47478l-12.641975-12.641975c6.501587 7.223986 9.752381 15.17037 9.752381 24.561552 0 9.391182-3.250794 17.337566-9.752381 24.561552L376.008466 816.310406c-7.223986 7.223986-15.17037 10.47478-24.200353 10.47478-9.029982 0-16.976367-3.250794-24.200353-9.752381L89.216226 575.029277z' p-id='2281' fill='%23ffffff'%3E%3C/path%3E%3C/svg%3E");background-size:25px;background-repeat:no-repeat;background-position:15px}
  403. .hld__msg a{color:#fff;text-decoration: underline;}
  404. .hld__msg-ok{background:#4bcc4b}
  405. .hld__msg-err{background:#c33}
  406. .hld__msg-warn{background:#FF9900}
  407. .hld__flex{display:flex;}
  408. .hld__float-left{float: left;}
  409. .clearfix {clear: both;}
  410. #hld__noti_container {position:fixed;top:10px;left:10px;z-index:99;}
  411. .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;}
  412. .hld__btn-groups {display:flex;justify-content:center !important;margin-top:10px;}
  413. button.hld__btn {padding:3px 8px;border:1px solid #591804;background:#fff8e7;color:#591804;}
  414. button.hld__btn:hover {background:#591804;color:#fff0cd;}
  415. #hld__updated {position:fixed;top:20px;right:20px;width:200px;padding:10px;border-radius:5px;box-shadow:0 0 15px #666;border:1px solid #591804;background:#fff8e7;z-index: 9999;}
  416. #hld__updated .hld__readme {text-decoration:underline;color:#591804;}
  417. .hld__script-info {margin-left:4px;font-size:70%;color:#666;}
  418. `
  419. }
  420. /**
  421. * 设置模块
  422. * @name settingPanel
  423. * @description 提供脚本的设置面板,提供配置修改,保存等基础功能
  424. */
  425. const settingPanel = {
  426. name: 'settingPanel',
  427. initFunc: function () {
  428. const _this = this
  429. //设置面板
  430. let $panelDom = $(`
  431. <div id="hld__setting_cover" class="animated zoomIn">
  432. <div id="hld__setting_panel">
  433. <a href="javascript:void(0)" id="hld__setting_close" class="hld__setting-close">×</a>
  434. <p class="hld__sp-title"><a title="更新地址" href="https://gf.qytechs.cn/zh-CN/scripts/393991-nga%E4%BC%98%E5%8C%96%E6%91%B8%E9%B1%BC%E4%BD%93%E9%AA%8C" target="_blank">NGA优化摸鱼插件<span class="hld__script-info">v${script.getInfo().version}</span></a></p>
  435. <div class="hld__field">
  436. <p class="hld__sp-section">显示优化</p>
  437. <div id="hld__normal_left"></div>
  438. </div>
  439. <div class="hld__field">
  440. <p class="hld__sp-section">功能增强</p>
  441. <div id="hld__normal_right"></div>
  442. </div>
  443. <div style="clear:both"></div>
  444. <div class="hld__advanced-setting">
  445. <button id="hld__advanced_button">+</button><span>高级设置</span>
  446. <div class="hld__advanced-setting-panel">
  447. <p><svg t="1590560820184" class="icon" viewBox="0 0 1040 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2738" width="200" height="200"><path d="M896.355855 975.884143 127.652332 975.884143c-51.575656 0-92.993974-19.771299-113.653503-54.238298-20.708648-34.515095-18.194384-79.5815 6.9022-123.5632L408.803663 117.885897c25.244964-44.376697 62.767556-69.77004 102.953813-69.77004 40.136116 0 77.658707 25.393343 103.002932 69.671803L1003.006873 798.131763c25.097608 44.030819 27.711132 89.049129 6.952342 123.514081C989.348806 956.159916 947.881368 975.884143 896.355855 975.884143L896.355855 975.884143 896.355855 975.884143 896.355855 975.884143 896.355855 975.884143zM511.805572 119.511931c-12.769838 0-27.414373 12.376888-39.298028 33.134655L84.656075 832.892451c-12.130272 21.350261-14.989389 40.530089-7.741311 52.611242 7.297197 12.08013 25.787316 19.033495 50.737568 19.033495l768.703523 0c24.997324 0 43.439348-6.903224 50.736545-19.033495 7.197936-12.031011 4.387937-31.210839-7.791453-52.5611L551.055504 152.646586C539.220968 131.888819 524.527314 119.511931 511.805572 119.511931L511.805572 119.511931 511.805572 119.511931 511.805572 119.511931 511.805572 119.511931zM512.004093 653.807726c-20.1182 0-36.488029-15.975856-36.488029-35.69906L475.516064 296.773124c0-19.723204 16.369829-35.698037 36.488029-35.698037 20.117177 0 36.485983 15.975856 36.485983 35.698037l0 321.335543C548.490076 637.832893 532.12127 653.807726 512.004093 653.807726L512.004093 653.807726 512.004093 653.807726 512.004093 653.807726zM511.757476 828.308039c31.359218 0 56.851822-24.950252 56.851822-55.717999s-25.491581-55.716976-56.851822-55.716976c-31.408337 0-56.851822 24.949228-56.851822 55.716976S480.349139 828.308039 511.757476 828.308039L511.757476 828.308039 511.757476 828.308039 511.757476 828.308039z" p-id="2739"></path></svg> 鼠标停留在<span class="hld__adv-help" title="详细描述">选项文字</span>上可以显示详细描述,设置有误可能会导致插件异常或者无效!</p>
  448. <table id="hld__advanced_left"></table>
  449. <table id="hld__advanced_right"></table>
  450. </div>
  451. </div>
  452. <div class="hld__buttons">
  453. <span id="hld_setting_panel_buttons"></span>
  454. <span>
  455. <button class="hld__btn" id="hld__save__data">保存设置</button>
  456. </span>
  457. </div>
  458. </div>
  459. </div>
  460. `)
  461. const insertDom = setting => {
  462. if (setting.type === 'normal') {
  463. $panelDom.find(`#hld__normal_${setting.menu || 'left'}`).append(`
  464. <p><label title="${setting.desc || ''}"><input type="checkbox" id="hld__cb_${setting.key}"> ${setting.title || setting.key}${setting.shortCutCode ? '(快捷键切换[<b>'+script.getModule('shortCutKeys').getCodeName(setting.rewriteShortCutCode || setting.shortCutCode)+'</b>])' : ''}</label></p>
  465. `)
  466. if (setting.extra) {
  467. $panelDom.find(`#hld__cb_${setting.key}`).attr('enable', `hld__${setting.key}_${setting.extra.mode || 'fold'}`)
  468. $panelDom.find(`#hld__normal_${setting.menu || 'left'}`).append(`
  469. <div class="hld__sp-${setting.extra.mode || 'fold'}" id="hld__${setting.key}_${setting.extra.mode || 'fold'}" data-id="hld__${setting.key}">
  470. <p><button id="${setting.extra.id}">${setting.extra.label}</button></p>
  471. </div>
  472. `)
  473. }
  474. }
  475. if (setting.type === 'advanced') {
  476. let formItem = ''
  477. const valueType = typeof setting.default
  478. if (valueType === 'boolean') {
  479. formItem = `<input type="checkbox" id="hld__adv_${setting.key}">`
  480. }
  481. if (valueType === 'number') {
  482. formItem = `<input type="number" id="hld__adv_${setting.key}">`
  483. }
  484. if (valueType === 'string') {
  485. if (setting.options) {
  486. let t = ''
  487. for (const option of setting.options) {
  488. t += `<option value="${option.value}">${option.label}</option>`
  489. }
  490. formItem = `<select id="hld__adv_${setting.key}">${t}</select>`
  491. } else {
  492. formItem = `<input type="text" id="hld__adv_${setting.key}">`
  493. }
  494. }
  495. $panelDom.find(`#hld__advanced_${setting.menu || 'left'}`).append(`
  496. <tr>
  497. <td><span class="hld__adv-help" title="${setting.desc || ''}">${setting.title || setting.key}</span></td>
  498. <td>${formItem}</td>
  499. </tr>`)
  500. }
  501. }
  502. for (const module of script.modules) {
  503. if (module.setting && module.setting.key) {
  504. insertDom(module.setting)
  505. }
  506. if (module.settings) {
  507. for (const setting of module.settings) {
  508. setting.key && insertDom(setting)
  509. }
  510. }
  511. }
  512. $('body').append($panelDom)
  513. //本地恢复设置
  514. //基础设置
  515. for (let k in script.setting.normal) {
  516. if ($('#hld__cb_' + k).length > 0) {
  517. $('#hld__cb_' + k)[0].checked = script.setting.normal[k]
  518. const enableDomID = $('#hld__cb_' + k).attr('enable')
  519. if (enableDomID) {
  520. script.setting.normal[k] ? $('#' + enableDomID).show() : $('#' + enableDomID).hide()
  521. $('#' + enableDomID).find('input').each(function () {
  522. $(this).val() == script.setting.normal[$(this).attr('name').substr(8)] && ($(this)[0].checked = true)
  523. })
  524. $('#hld__cb_' + k).on('click', function () {
  525. $(this)[0].checked ? $('#' + enableDomID).slideDown() : $('#' + enableDomID).slideUp()
  526. })
  527. }
  528. }
  529. }
  530. //高级设置
  531. for (let k in script.setting.advanced) {
  532. if ($('#hld__adv_' + k).length > 0) {
  533. const valueType = typeof script.setting.advanced[k]
  534. if (valueType == 'boolean') {
  535. $('#hld__adv_' + k)[0].checked = script.setting.advanced[k]
  536. }
  537. if (valueType == 'number' || valueType == 'string') {
  538. $('#hld__adv_' + k).val(script.setting.advanced[k])
  539. }
  540. }
  541. }
  542. /**
  543. * 设置面板-展开切换高级设置
  544. */
  545. $('body').on('click', '#hld__advanced_button', function () {
  546. if ($('.hld__advanced-setting-panel').is(':hidden')) {
  547. $('.hld__advanced-setting-panel').css('display', 'flex')
  548. $(this).text('-')
  549. } else {
  550. $('.hld__advanced-setting-panel').css('display', 'none')
  551. $(this).text('+')
  552. }
  553. })
  554. $('body').on('click', '.hld__list-panel .hld__setting-close', function () {
  555. $(this).parent().remove()
  556. })
  557. /**
  558. * 保存配置
  559. */
  560. $('body').on('click', '#hld__save__data', () => {
  561. script.saveSetting()
  562. $('#hld__setting_cover').fadeOut(200)
  563. })
  564. },
  565. renderAlwaysFunc: function () {
  566. if($('.hld__setting-box').length == 0) {
  567. $('#startmenu > tbody > tr > td.last').append('<div><div class="item hld__setting-box"></div></div>')
  568. let $entry = $('<a id="hld__setting" title="打开NGA优化摸鱼插件设置面板">NGA优化摸鱼插件设置</a>')
  569. $entry.click(()=>$('#hld__setting_cover').css('display', 'flex'))
  570. $('#hld__setting_close').click(()=>$('#hld__setting_cover').fadeOut(200))
  571. $('.hld__setting-box').append($entry)
  572. }
  573. },
  574. addButton: function (button) {
  575. $('#hld_setting_panel_buttons').append(`
  576. <button class="hld__btn" id="${button.id}" title="${button.desc}">${button.title}</button>
  577. `)
  578. },
  579. style: `
  580. #hld__setting {color:#6666CC;cursor:pointer;}
  581. #hld__setting_cover {display:none;justify-content:center;align-items:center;position:fixed;top:0;left:0;right:0;bottom:0;z-index:999;}
  582. #hld__setting_panel {position:relative;background:#fff8e7;width:526px;padding:15px 20px;border-radius:10px;box-shadow:0 0 10px #666;border:1px solid #591804;}
  583. #hld__setting_panel > div.hld__field {float:left;width:50%;}
  584. #hld__setting_panel p {margin-bottom:10px;}
  585. #hld__setting_panel .hld__sp-title {font-size:15px;font-weight:bold;text-align:center;}
  586. #hld__setting_panel .hld__sp-section {font-weight:bold;margin-top:20px;}
  587. .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;}
  588. .hld__setting-close:hover {background:#591804;color:#fff0cd;text-decoration:none;}
  589. #hld__setting_panel button {transition:all .2s ease;cursor:pointer;}
  590. .hld__advanced-setting {border-top: 1px solid #e0c19e;border-bottom: 1px solid #e0c19e;padding: 3px 0;margin-top:25px;}
  591. .hld__advanced-setting >span {font-weight:bold}
  592. .hld__advanced-setting >button {padding: 0px;margin-right:5px;width: 18px;text-align: center;}
  593. .hld__advanced-setting-panel {display:none;padding:5px 0;flex-wrap: wrap;}
  594. .hld__advanced-setting-panel>p {width:100%;}
  595. .hld__advanced-setting-panel>table {width:50%;}
  596. .hld__advanced-setting-panel>p {margin: 7px 0 !important;font-weight:bold;}
  597. .hld__advanced-setting-panel>p svg {height:16px;width:16px;vertical-align: top;margin-right:3px;}
  598. .hld__advanced-setting-panel>table td {padding-right:10px}
  599. .hld__advanced-setting-panel input[type=text],.hld__advanced-setting-panel input[type=number] {width:80px}
  600. .hld__advanced-setting-panel .hld__adv-help {cursor:help;text-decoration: underline;}
  601. .hld__buttons {clear:both;display:flex;justify-content:space-between;padding-top:15px;}
  602. button.hld__btn {padding:3px 8px;border:1px solid #591804;background:#fff8e7;color:#591804;}
  603. button.hld__btn:hover {background:#591804;color:#fff0cd;}
  604. .hld__sp-fold {padding-left:23px;}
  605. .hld__sp-fold .hld__f-title {font-weight:bold;}
  606.  
  607. `
  608. }
  609. /**
  610. * 快捷键模块
  611. * @name shortCutKeys
  612. * @description 为模块提供快捷键切换的能力,提供修改,保存快捷键等
  613.  
  614. */
  615. const shortCutKeys = {
  616. name: 'shortCutKeys',
  617. beforeFunc: function () {
  618. script.setting.normal.shortcutKeys = []
  619. },
  620. afterFunc: function () {
  621. // 快捷键编辑面板
  622. $('#hld__normal_left').append('<p><button id="hld__shortcut_manage">编辑快捷键</button></p>')
  623. },
  624. initFunc: function () {
  625. const _this = this
  626. //注册(不可用)按键
  627. $('body').keyup(event => {
  628. if (/textarea|select|input/i.test(event.target.nodeName)
  629. || /text|password|number|email|url|range|date|month/i.test(event.target.type)) {
  630. return
  631. }
  632. if (event.ctrlKey || event.altKey || event.shiftKey) return
  633. for (const keyCode of script.setting.normal.shortcutKeys) {
  634. if (event.keyCode === keyCode) {
  635. for (const module of script.modules) {
  636. if (module.setting && module.shortcutFunc) {
  637. if (module.setting.rewriteShortCutCode) {
  638. if (module.setting.rewriteShortCutCode === event.keyCode) {
  639. module.shortcutFunc[module.setting.key].call(module)
  640. }
  641. } else if (module.setting.shortCutCode === event.keyCode) {
  642. module.shortcutFunc[module.setting.key].call(module)
  643. }
  644. }
  645. if (module.settings) {
  646. for (const setting of module.settings) {
  647. if (module.shortcutFunc) {
  648. if (setting.rewriteShortCutCode) {
  649. if (setting.rewriteShortCutCode === event.keyCode) {
  650. module.shortcutFunc[setting.key].call(module)
  651. }
  652. } else if (setting.shortCutCode === event.keyCode) {
  653. module.shortcutFunc[setting.key].call(module)
  654. }
  655. }
  656. }
  657. }
  658. }
  659. }
  660. }
  661. })
  662. /**
  663. * 展开快捷键编辑列表
  664. */
  665. $('body').on('click', '#hld__shortcut_manage', () => {
  666. if($('#hld__shortcut_panel').length > 0) return
  667. let $shortcutPanel = $(`<div id="hld__shortcut_panel" class="hld__list-panel animated fadeInUp">
  668. <a href="javascript:void(0)" class="hld__setting-close">×</a>
  669. <div>
  670. <div><p>编辑快捷键</p><div class="hld__float-left"><table class="hld__table hld__table-keyword"><thead><tr><td>功能</td><td width="60">快捷键</td></tr></thead>
  671. <tbody></tbody></table></div><div class="hld__float-left hld__shortcut-desc"><p><b>支持的快捷键范围</b></p><p>键盘 <code>A</code>~<code>Z</code></p><p>左箭头 <code>LEFT</code></p><p>右箭头 <code>RIGHT</code></p><p>上箭头 <code>UP</code></p><p>下箭头 <code>DOWN</code></p><p><i>* 留空则取消快捷键</i></p><br><p>如按键异常请尝试重置按键</p>
  672. </div>
  673. <div class="clearfix"></div></div>
  674. </div>
  675. <div class="hld__btn-groups">
  676. <button class="hld__btn" id="hld__reset_shortcut">重置按键</button>
  677. <button class="hld__btn" id="hld__save_shortcut">保存快捷键</button>
  678. </div>
  679. </div>`)
  680. for (const module of script.modules) {
  681. const insertDom = setting => $shortcutPanel.find('.hld__table tbody').append(`<tr><td>${setting.title || setting.key}</td><td><input type="text" value="${this.getCodeName(setting.rewriteShortCutCode || setting.shortCutCode)}"></td></tr>`)
  682. if (module.setting && module.setting.shortCutCode) {
  683. insertDom(module.setting)
  684. }
  685. if (module.settings) {
  686. for (const setting of module.settings) {
  687. if (setting.shortCutCode) {
  688. insertDom(setting)
  689. }
  690. }
  691. }
  692. }
  693. $('#hld__setting_cover').append($shortcutPanel)
  694. })
  695. /**
  696. * 重置快捷键
  697. */
  698. $('body').on('click', '#hld__reset_shortcut', () => {
  699. const defaultShortcut = []
  700. for (const module of script.modules) {
  701. if (module.setting && module.setting.shortCutCode) {
  702. defaultShortcut.push(module.setting.shortCutCode)
  703. }
  704. if (module.settings) {
  705. for (const setting of module.settings) {
  706. setting.shortCutCode && defaultShortcut.push(setting.shortCutCode)
  707. }
  708. }
  709. }
  710. script.setting.normal.shortcutKeys = defaultShortcut
  711. script.saveSetting('重置按键成功,刷新页面生效')
  712. $('#hld__shortcut_panel').remove()
  713. })
  714. /**
  715. * 保存快捷键
  716. */
  717. $('body').on('click', '#hld__save_shortcut', () => {
  718. const _this = this
  719. let shortcutKeys = []
  720. $('.hld__table tbody>tr').each(function () {
  721. const v = $(this).find('input').val().trim().toUpperCase()
  722. if (v == '') {
  723. shortcutKeys.push(-1)
  724. } else {
  725. const code = _this.getCodeName(v, 'name')
  726. if (code > 0) shortcutKeys.push(code)
  727. else script.popMsg(`${v}是个无效的快捷键`, 'err')
  728. }
  729. })
  730. if (shortcutKeys.length != script.setting.normal.shortcutKeys.length) return
  731. script.setting.normal.shortcutKeys = shortcutKeys
  732. script.saveSetting('保存按键成功,刷新页面生效')
  733. $('#hld__shortcut_panel').remove()
  734. })
  735. },
  736. getCodeName (val, valType='code') {
  737. const shortcutCode = {
  738. 'A': 65, 'B': 66, 'C': 67, 'D': 68, 'E': 69, 'F': 70, 'G': 71,
  739. 'H': 72, 'I': 73, 'J': 74, 'K': 75, 'L': 76, 'M': 77, 'N': 78,
  740. 'O': 79, 'P': 80, 'Q': 81, 'R': 82, 'S': 83, 'T': 84,
  741. 'U': 85, 'V': 86, 'W': 87, 'X': 88, 'Y': 89, 'Z': 90,
  742. '0': 48, '1': 49, '2': 50, '3': 51, '4': 52, '5': 53, '6': 54, '7': 55, '8': 56, '9': 57,
  743. 'LEFT': 37, 'RIGHT': 39, 'UP': 38, 'DOWN': 40, '': 0, '': -1
  744. }
  745. if (valType == 'code') {
  746. let keyname = ''
  747. for (let [n, c] of Object.entries(shortcutCode)) {
  748. c == val && (keyname = n)
  749. }
  750. return keyname
  751. } else {
  752. let code = -1
  753. for (let [n, c] of Object.entries(shortcutCode)) {
  754. n == val && (code = c)
  755. }
  756. return code
  757. }
  758. },
  759. style: `
  760. code {padding:2px 4px;font-size:90%;font-weight:bold;color:#c7254e;background-color:#f9f2f4;border-radius:4px;}
  761. .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;}
  762. .hld__list-panel .hld__list-c {width:45%;}
  763. .hld__list-panel .hld__list-c textarea {box-sizing:border-box;padding:0;margin:0;height:200px;width:100%;resize:none;}
  764. .hld__list-panel .hld__list-desc {margin-top:5px;font-size:9px;color:#666;cursor:help;text-decoration: underline;}
  765. .hld__list-panel .hld__list-c > p:first-child {font-weight:bold;font-size:14px;margin-bottom:10px;}
  766. .hld__table-keyword {margin-top:10px;width:200px;}
  767. .hld__table-keyword tr td:last-child {text-align:center;}
  768. .hld__table-keyword input[type=text] {width:48px;text-transform:uppercase;text-align:center;}
  769. .hld__table{table-layout:fixed;border-top:1px solid #ead5bc;border-left:1px solid #ead5bc}
  770. .hld__table-banlist-buttons{margin-top:10px}
  771. .hld__table thead{background:#591804;border:1px solid #591804;color:#fff}
  772. .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}
  773. .hld__shortcut-desc {width:120px;margin-left:20px;padding-top:6px}
  774. .hld__shortcut-desc p {margin-bottom:5px;}
  775.  
  776. `
  777. }
  778. /**
  779. * 配置备份模块
  780. * @name backupModule
  781. * @description 提供配置的导入,导出功能
  782. */
  783. const backupModule = {
  784. name: 'backupModule',
  785. backupItems: [],
  786. initFunc: function () {
  787. /**
  788. * 导入导出设置面板
  789. */
  790. const _this = this
  791. script.getModule('settingPanel').addButton({
  792. id: 'hld__backup_panel',
  793. title: '导入/导出',
  794. desc: '导入/导出配置字符串,包含设置,黑名单,标记名单等等'
  795. })
  796. $('body').on('click', '#hld__backup_panel', function () {
  797. const unsupported = '3.3.0'
  798. const currentVer = script.getInfo().version
  799. if($('#hld__export_panel').length > 0) return
  800. $('#hld__setting_cover').append(`
  801. <div id="hld__export_panel" class="hld__list-panel animated fadeInUp">
  802. <a href="javascript:void(0)" class="hld__setting-close">×</a>
  803. <div class="hld__ep-container">
  804. <div>
  805. <p><b>选择导出的设置</b></p>
  806. <div id="hld__export_panel_cb">
  807. <p><label><input type="checkbox" id="hld__cb_export_setting" checked="checked"> 配置</label></p>
  808. </div>
  809. <br>
  810. <p><button id="hld__export__data">导出</button> <button id="hld__import__data">导入</button></p>
  811. </div>
  812. <div>
  813. <p><b style="text-decoration: underline;cursor:help;" title="【导出】\n选择要导出的内容,点击导出,复制以下字符串用于备份,分享等\n【导入】\n将字符串复制到以下输入框中,点击导入,将会自动导入字符串中包含的内容">字符串</b></p>
  814. <textarea id="hld__export_str" rows="9"></textarea>
  815. </div>
  816. </div>
  817. <div><p id="hld__export_msg"></p></div>
  818. </div>
  819. `)
  820. // 加载其他模组备份项
  821. for (const item of _this.backupItems) {
  822. $('#hld__export_panel_cb').append(`
  823. <p><label><input type="checkbox" id="hld__cb_export_${item.writeKey}" checked="checked"> ${item.title}</label></p>
  824. `)
  825. }
  826. /**
  827. * 导出配置
  828. */
  829. $('#hld__export__data').click(function(){
  830. let obj = {}
  831. // 基础配置
  832. if ($('#hld__cb_export_setting').prop('checked')) {
  833. obj['setting'] = script.setting.normal
  834. obj['advanced_setting'] = script.setting.advanced
  835. }
  836. // 其他模组备份项
  837. for (const item of _this.backupItems) {
  838. const $c = $(`#hld__cb_export_${item.writeKey}`)
  839. if ($c.length > 0 && $c.prop('checked')) {
  840. obj[item.writeKey] = item.module[item.valueKey]
  841. }
  842. }
  843.  
  844. if (Object.keys(obj).length == 0) {
  845. $('#hld__export_msg').html('<span style="color:#CC0000">没有选择任何项目可供导出!</span>')
  846. return
  847. }
  848. obj['name'] = 'HLD-NGA-BBS'
  849. obj['ver'] = script.getInfo().version
  850. $('#hld__export_str').val(_this.Base64.encode(JSON.stringify(obj)))
  851. $('#hld__export_msg').html('<span style="color:#009900">导出成功,请复制右侧字符串以备份</span>')
  852. })
  853. /**
  854. * 导入配置
  855. */
  856. $('#hld__import__data').click(function(){
  857. if ($('#hld__export_str').val()) {
  858. try {
  859. let obj = JSON.parse(_this.Base64.decode($('#hld__export_str').val()))
  860. const objVer = _this.vstr2num(obj.ver)
  861. if (objVer != 0 && objVer > _this.vstr2num(currentVer)) {
  862. script.popMsg(`此配置是由更高版本(v${obj.ver})的脚本导出,请升级您的脚本 <a title="更新地址" href="https://gf.qytechs.cn/zh-CN/scripts/393991-nga%E4%BC%98%E5%8C%96%E6%91%B8%E9%B1%BC%E4%BD%93%E9%AA%8C" target="_blank">[脚本地址]</a>`, 'warn')
  863. return
  864. }
  865. if (objVer != 0 && objVer < _this.vstr2num(unsupported)) {
  866. script.popMsg(`此配置是由低版本(v${obj.ver})的脚本导出,当前版本(v${currentVer})已不支持!`, 'err')
  867. return
  868. }
  869. let confirm = window.confirm('此操作会覆盖你的配置,确认吗?')
  870. if (!confirm) return
  871. if (Object.keys(obj).includes('setting')) {
  872. obj.setting && (script.setting.normal = obj.setting)
  873. obj.advanced_setting && (script.setting.advanced = obj.advanced_setting)
  874. window.localStorage.setItem('hld__NGA_setting', JSON.stringify(script.setting.normal))
  875. window.localStorage.setItem('hld__NGA_advanced_setting', JSON.stringify(script.setting.advanced))
  876. }
  877. // 其他模组备份项
  878. for (const item of _this.backupItems) {
  879. if (Object.keys(obj).includes(item.writeKey)) {
  880. item.module[item.valueKey] = obj[item.writeKey]
  881. window.localStorage.setItem(`hld__NGA_${item.writeKey}`, JSON.stringify(obj[item.writeKey]))
  882. }
  883. }
  884. $('#hld__export_msg').html('<span style="color:#009900">导入成功,刷新浏览器以生效</span>')
  885.  
  886. } catch (err){
  887. console.error('【NGA-Script】JSON解析失败:', err)
  888. $('#hld__export_msg').html('<span style="color:#CC0000">字符串有误,解析失败!</span>')
  889. }
  890. }
  891. })
  892. })
  893. },
  894. addItem: function(item) {
  895. this.backupItems.push(item)
  896. },
  897. // 字符串版本转数字
  898. vstr2num: function(str) {
  899. let num = 0
  900. str.split('.').forEach((n, i) => num += i < 2 ? +n * 1000 / Math.pow(10, i) : +n)
  901. return num
  902. },
  903. /**
  904. * Base64互转
  905. */
  906. Base64: {
  907. encode: (str) => {
  908. return window.btoa(unescape(encodeURIComponent(str)))
  909. },
  910. decode: (str) => {
  911. return decodeURIComponent(escape(window.atob(str)))
  912. }
  913. },
  914. style: `
  915. .hld__ep-container{display:flex;width:300px;margin-bottom: 7px;}
  916. .hld__ep-container p {margin-bottom:10px;}
  917. .hld__ep-container >div{width:50%;}
  918. .hld__ep-container textarea {width: 100%;padding:0;margin:0;resize:none;}
  919. `
  920. }
  921. /**
  922. * 赏面板
  923. * @name rewardPanel
  924. * @description 别问,好活当赏
  925. */
  926. const rewardPanel = {
  927. initFunc: function () {
  928. /**
  929. * 打赏
  930. */
  931. script.getModule('settingPanel').addButton({
  932. id: 'hld__reward',
  933. title: '<span style="margin-right:3px">¥</span>赏',
  934. desc: '好活当赏'
  935. })
  936. $('body').on('click', '#hld__reward', function () {
  937. $('#hld__setting_cover').append(`
  938. <div class="hld__list-panel hld__reward-panel animated fadeInUp">
  939. <a href="javascript:void(0)" class="hld__setting-close">×</a>
  940. <div class="hld__reward-info">
  941. <p><b>本脚本完全开源,并且长期维护,您喜欢请可以去点个Star!</p>
  942. <p>您若有好的功能需求或者建议,欢迎反馈</p>
  943. <p>如果您觉得脚本好用<span class="hld__delete-line">帮助到更好的摸鱼</span>,也可以请作者喝杯咖啡~<img src="https://s1.ax1x.com/2020/06/28/N25w7Q.png"></p>
  944. </div>
  945. <div class="hld__flex">
  946. <div class="hld__list-c"><img src="https://s1.ax1x.com/2020/06/28/N25Bkj.png"></div>
  947. <div class="hld__list-c"><img src="https://s1.ax1x.com/2020/06/28/N25Dts.png"></div>
  948. </div>
  949. <div class="hld__source">
  950. <a href="${script.getInfo().github}" target="_blank"><img alt="Mozilla Add-on" src="https://img.shields.io/github/stars/kisshang1993/NGA-BBS-Script?label=Star&style=social"></a>
  951. <a href="${script.getInfo().update}" target="_blank"><img alt="Mozilla Add-on" src="https://img.shields.io/badge/Greasy%20Fork-NGA优化摸鱼体验-brightgreen"></a>
  952. </div>
  953. </div>
  954. `)
  955. })
  956. },
  957. style: `
  958. .hld__reward-panel {width:500px;}
  959. .hld__reward-panel .hld__reward-info {display:block;font-size:15px;margin-bottom:20px;line-height:20px;}
  960. .hld__reward-panel .hld__reward-info p {margin-bottom:5px;}
  961. .hld__delete-line {text-decoration:line-through;color:#666;}
  962. .hld__reward-panel .hld__list-c {width:50%;}
  963. .hld__reward-panel .hld__list-c:first-child {margin-right:15px;}
  964. .hld__reward-panel .hld__list-c>img {width:100%;height:auto;}
  965. .hld__reward-panel .hld__source {margin-top:15px;}
  966. .hld__reward-panel .hld__source > a {margin-right:10px;}
  967. `
  968. }
  969. /**
  970. * 动态启用配置模块
  971. * @name dynamicEnable
  972. * @description 此模块提供了快捷键动态启用的功能
  973. */
  974. const dynamicEnable = {
  975. setting: {
  976. type: 'advanced',
  977. key: 'dynamicEnable',
  978. default: true,
  979. title: '动态功能启用',
  980. desc: '此配置表示部分可以快捷键切换的功能默认行为策略\n选中时:关闭功能(如隐藏头像)也可以通过快捷键切换显示/隐藏\n取消时:关闭功能(如隐藏头像)将彻底关闭功能,快捷键会失效',
  981. menu: 'left'
  982. }
  983. }
  984. /**
  985. * 隐藏头像模块
  986. * @name hideAvatar
  987. * @description 此模块提供了可以快捷键切换显示隐藏头像
  988. */
  989. const hideAvatar = {
  990. setting: {
  991. shortCutCode: 81, // Q
  992. type: 'normal',
  993. key: 'hideAvatar',
  994. default: true,
  995. title: '隐藏头像',
  996. menu: 'left'
  997. },
  998. renderFormsFunc: function ($el) {
  999. script.setting.normal.hideAvatar && $el.find('.avatar').css('display', 'none')
  1000. },
  1001. shortcutFunc: {
  1002. hideAvatar: function () {
  1003. if (script.setting.normal.hideAvatar || script.setting.advanced.dynamicEnable) {
  1004. $('.avatar').toggle()
  1005. script.popNotification(`${$('.avatar:hidden').length == 0 ? '显示' : '隐藏'}头像`)
  1006. }
  1007. }
  1008. }
  1009. }
  1010. /**
  1011. * 隐藏头像模块
  1012. * @name hideSmile
  1013. * @description 此模块提供了可以快捷键切换显示隐藏表情
  1014. * 其中隐藏的表情会用文字来替代
  1015. */
  1016. const hideSmile = {
  1017. setting: {
  1018. shortCutCode: 87, // W
  1019. type: 'normal',
  1020. key: 'hideSmile',
  1021. default: true,
  1022. title: '隐藏表情',
  1023. menu: 'left'
  1024. },
  1025. renderFormsFunc: function ($el) {
  1026. $el.find('.c2 img').each(function () {
  1027. const classs = $(this).attr('class')
  1028. if (classs && classs.includes('smile') && !$(this).is(':hidden')) {
  1029. const alt = $(this).attr('alt')
  1030. const $alt = $('<span class="smile_alt_text">[' + alt + ']</span>')
  1031. script.setting.normal.hideSmile ? $(this).hide() : $alt.hide()
  1032. $(this).after($alt)
  1033. }
  1034. })
  1035. },
  1036. shortcutFunc: {
  1037. hideSmile: function () {
  1038. if (script.setting.normal.hideSmile || script.setting.advanced.dynamicEnable) {
  1039. $('.c2 img').each(function () {
  1040. const classs = $(this).attr('class');
  1041. if (classs && classs.includes('smile')) $(this).toggle()
  1042. })
  1043. $('.smile_alt_text').toggle()
  1044. script.popNotification(`${$('.smile_alt_text:hidden').length > 0 ? '显示' : '隐藏'}表情`)
  1045. }
  1046. }
  1047. }
  1048. }
  1049. /**
  1050. * 贴内图片缩放模块
  1051. * @name imgResize
  1052. * @description 此模块提供了可以调整贴内图片的尺寸
  1053. */
  1054. const imgResize = {
  1055. setting: {
  1056. type: 'normal',
  1057. key: 'imgResize',
  1058. default: 200,
  1059. title: '贴内图片缩放',
  1060. menu: 'left'
  1061. },
  1062. renderFormsFunc: function ($el) {
  1063. $el.find('.c2 img').each(function () {
  1064. const classs = $(this).attr('class')
  1065. if ((!classs || !classs.includes('smile')) && script.setting.normal.imgResize) {
  1066. $(this).addClass('hld__img-resize').attr('hld-img-resize', 'ok').attr('title', '点击大图显示')
  1067. }
  1068. })
  1069. },
  1070. asyncStyle: () => {
  1071. return `
  1072. .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;margin:5px;}
  1073. `
  1074. }
  1075. }
  1076. /**
  1077. * 隐藏图片模块
  1078. * @name hideImage
  1079. * @description 此模块提供了可以快捷键切换显示隐藏图片
  1080. * 其中隐藏的图片会用一个按钮来替代
  1081. */
  1082. const hideImage = {
  1083. setting: {
  1084. shortCutCode: 69, // E
  1085. type: 'normal',
  1086. key: 'hideImage',
  1087. default: false,
  1088. title: '隐藏贴内图片',
  1089. menu: 'left'
  1090. },
  1091. renderFormsFunc: function ($el) {
  1092. $el.find('.c2 img').each(function () {
  1093. const classs = $(this).attr('class')
  1094. if ((!classs || !classs.includes('smile')) && !$(this).is(':hidden')) {
  1095. $(this).addClass('hld__img-postimg')
  1096. // 显示原图
  1097. $(this).attr('src', $(this).attr('src').replace('.medium.jpg', '')).attr('hld-hideimg', 'ok')
  1098. let $imgB = $('<button class="switch-img" style="display:none">图</button>')
  1099. $imgB.on('click', function () {
  1100. $(this).prev('img').toggle()
  1101. $(this).text($(this).prev('img').is(':hidden') ? '图' : '隐藏')
  1102. })
  1103. if (script.setting.normal.hideImage) {
  1104. $(this).hide();
  1105. $imgB.show()
  1106. }
  1107. $(this).after($imgB)
  1108. }
  1109. })
  1110. },
  1111. shortcutFunc: {
  1112. hideImage: function () {
  1113. if (!script.setting.advanced.dynamicEnable) return
  1114. if ($('.hld__img-postimg:hidden').length < $('.switch-img').length) {
  1115. $('.hld__img-postimg').hide()
  1116. $('.switch-img').text('图').show()
  1117. script.popNotification(`隐藏图片`)
  1118. return
  1119. }
  1120. $('.hld__img-postimg').each(function () {
  1121. $(this).toggle()
  1122. $(this).is(':hidden') ? $(this).next('button.switch-img').show() : $(this).next('button.switch-img').hide()
  1123. })
  1124. script.popNotification(`${$('.switch-img:hidden').length > 0 ? '显示' : '隐藏'}图片`)
  1125. }
  1126. }
  1127. }
  1128. /**
  1129. * 隐藏签名模块
  1130. * @name hideSign
  1131. * @description 此模块提供了可以配置默认隐藏签名
  1132. */
  1133. const hideSign = {
  1134. setting: {
  1135. type: 'normal',
  1136. key: 'hideSign',
  1137. default: true,
  1138. title: '隐藏签名',
  1139. menu: 'left'
  1140. },
  1141. renderFormsFunc: function ($el) {
  1142. script.setting.normal.hideSign && $el.find('.sign, .sigline').css('display', 'none')
  1143. }
  1144. }
  1145. /**
  1146. * 隐藏图片模块
  1147. * @name hideHeader
  1148. * @description 此模块提供了可以配置默认隐藏版头
  1149. * 以及一个高级配置可选一起隐藏顶部背景
  1150. */
  1151. const hideHeader = {
  1152. settings: [{
  1153. type: 'normal',
  1154. key: 'hideHeader',
  1155. default: true,
  1156. title: '隐藏版头/版规/子版入口',
  1157. menu: 'left'
  1158. }, {
  1159. type: 'advanced',
  1160. key: 'hideCustomBg',
  1161. default: true,
  1162. title: '隐藏版头同时隐藏背景图片',
  1163. desc: '选中时:隐藏版头顶部背景图片\n取消时:无操作',
  1164. menu: 'right'
  1165. }],
  1166. renderAlwaysFunc: function ($el) {
  1167. //隐藏版头
  1168. if (script.setting.normal.hideHeader && $('#hld__switch_header').length == 0) {
  1169. $('#toppedtopic, #sub_forums').hide()
  1170. let $toggleHeaderBtn = $('<button style="position: absolute;right: 16px;" id="hld__switch_header">切换显示版头</button>')
  1171. $toggleHeaderBtn.click(() => $('#toppedtopic, #sub_forums').toggle())
  1172. $('#toptopics > div > h3').append($toggleHeaderBtn)
  1173. }
  1174. if(script.setting.normal.hideHeader && script.setting.advanced.hideCustomBg) {
  1175. $('#custombg').hide()
  1176. $('#mainmenu').css('margin', '0px')
  1177. }
  1178. }
  1179. }
  1180. /**
  1181. * Excel模块
  1182. * @name excelMode
  1183. * @description 此模块提供了可以快捷键切换Excel模式
  1184. * 以及一个高级配置可选更改Excel左侧序号的类型
  1185. */
  1186. const excelMode = {
  1187. settings: [{
  1188. shortCutCode: 82, // R
  1189. type: 'normal',
  1190. key: 'excelMode',
  1191. default: false,
  1192. title: 'Excel模式',
  1193. menu: 'left'
  1194. }, {
  1195. type: 'advanced',
  1196. key: 'excelTheme',
  1197. default: 'wps',
  1198. options: [{
  1199. label: 'WPS',
  1200. value: 'wps'
  1201. }, {
  1202. label: 'Office',
  1203. value: 'office'
  1204. }],
  1205. title: 'Excel皮肤',
  1206. desc: 'Excel的皮肤',
  1207. menu: 'left'
  1208. }, {
  1209. type: 'advanced',
  1210. key: 'excelNoMode',
  1211. default: false,
  1212. title: 'Excel左列序号',
  1213. desc: 'Excel最左列的显示序号,此策略为尽可能的更像Excel\n选中时:Excel最左栏为从1开始往下,逐行+1\n取消时:Excel最左栏为原始的回帖数\n*此功能仅在贴列表有效',
  1214. menu: 'left'
  1215. }],
  1216. beforeUrl: window.location.href,
  1217. initFunc: function() {
  1218. const headerTheme = {
  1219. 'wps': 'https://s1.ax1x.com/2020/06/28/N25bjK.png',
  1220. 'office': 'https://s3.ax1x.com/2021/02/22/y7wJtf.png'
  1221. }
  1222. const footerTheme = {
  1223. 'wps': 'https://s1.ax1x.com/2020/06/28/N2I93t.jpg',
  1224. 'office': 'https://s3.ax1x.com/2021/02/22/y7w23F.png'
  1225. }
  1226. $('body').append(`<div class="hld__excel-div hld__excel-header"><img src="${headerTheme[script.setting.advanced.excelTheme]}"></div>`)
  1227. $('body').append(`<div class="hld__excel-div hld__excel-footer"><img src="${footerTheme[script.setting.advanced.excelTheme]}"></div>`)
  1228. $('.hld__excel-header, .hld__excel-footer').append('【这里应该是一张仿造Excel的图片,如不显示,请刷新重试,如还不显示,请及时反馈!】')
  1229. $('body').append('<div class="hld__excel-div hld__excel-setting"><img src="https://s1.ax1x.com/2020/06/28/N25WBF.png"><a id="hld__excel_setting" href="javascript:void(0)" title="打开NGA优化摸鱼插件设置面板">摸鱼</div>')
  1230. $('#hld__excel_setting').click(()=>$('#hld__setting_cover').css('display', 'flex'))
  1231. if(script.setting.normal.excelMode) {
  1232. if(this.beforeUrl.includes('thread.php') || this.beforeUrl.includes('read.php')) {
  1233. this.switchExcelMode()
  1234. }
  1235. }
  1236. },
  1237. renderAlwaysFunc: function ($el) {
  1238. $('.hld__excel-theme-' + script.setting.advanced.excelTheme).length == 0 && $('body').addClass('hld__excel-theme-' + script.setting.advanced.excelTheme)
  1239. if(script.setting.normal.excelMode && window.location.href != this.beforeUrl) {
  1240. this.beforeUrl = window.location.href
  1241. if(this.beforeUrl.includes('thread.php') || this.beforeUrl.includes('read.php')) {
  1242. $('.hld__excel-body').length == 0 && $('body').addClass('hld__excel-body')
  1243. }else {
  1244. $('.hld__excel-body').length > 0 && $('body').removeClass('hld__excel-body')
  1245. }
  1246. }
  1247. if(script.setting.normal.excelMode && $('.hld__excel-body').length > 0 && $('#mmc').length == 0) {
  1248. $('body').addClass('hld__excel-body-err')
  1249. }else {
  1250. $('body').removeClass('hld__excel-body-err')
  1251. }
  1252. },
  1253. renderFormsFunc: function ($el) {
  1254. $el.find('.postrow>td:first-child').before('<td class="c0"></td>')
  1255. },
  1256. shortcutFunc: {
  1257. excelMode: function () {
  1258. if (script.setting.normal.excelMode || script.setting.advanced.dynamicEnable) {
  1259. this.switchExcelMode()
  1260. script.popNotification($('.hld__excel-body').length > 0 ? 'Excel模式' : '普通模式')
  1261. }
  1262. }
  1263. },
  1264. /**
  1265. * 切换Excel模式
  1266. * @method switchExcelMode
  1267. */
  1268. switchExcelMode: () => {
  1269. $('body').toggleClass('hld__excel-body')
  1270. !script.setting.advanced.excelNoMode && $('body').addClass('hld__excel-original-no')
  1271. },
  1272. style: `
  1273. /* 默认风格(WPS) */
  1274. .hld__excel-body-err {padding-top: 200px}
  1275. .hld__excel-header, .hld__excel-footer, .hld__excel-setting {display: none;}
  1276. .hld__excel-body {background:#fff !important;}
  1277. .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;}
  1278. .hld__excel-body #mmc {margin-top:195px;margin-bottom:35px;}
  1279. .hld__excel-body .postBtnPos > div, .hld__excel-body .postBtnPos .stdbtn a {background:#fff !important;border-color:#bbb;}
  1280. .hld__excel-body .hld__excel-div,.hld__excel-body .hld__excel-setting {display:block;}
  1281. .hld__excel-body .hld__excel-setting {position:fixed;width:60px;height:20px;top:5px;right:95px;background:#f2f4f7;z-index:999;}
  1282. .hld__excel-body .hld__excel-setting img {width:20px;height:auto;vertical-align:middle;}
  1283. .hld__excel-body .hld__excel-setting a {margin-left:5px;vertical-align:middle;}
  1284. .hld__excel-body .hld__excel-header {position:fixed;top:0;left:0;height:196px;}
  1285. .hld__excel-body .hld__excel-footer {position:fixed;bottom:0;left:0;height:50px;}
  1286. .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;}
  1287. .hld__excel-body .hld__excel-header>img, .hld__excel-body .hld__excel-footer>img{position:absolute;top:0;left:0}
  1288. .hld__excel-body #m_nav {position:fixed;top:136px;left:261px;margin:0;padding:0;z-index:99;width: 9999px;}
  1289. .hld__excel-body #m_nav .nav_spr {display:block;border:0;border-radius:0;padding:0;box-shadow:none;background:none;}
  1290. .hld__excel-body #m_nav .nav_spr span {color:#000;font-size:16px;vertical-align:unset;font-weight:normal;}
  1291. .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;}
  1292. .hld__excel-body #m_threads {margin:0;}
  1293. .hld__excel-body #topicrows {border:none;box-shadow:none;border-radius:0;margin:0;background-color:#fff;counter-reset:num;border-spacing:0;}
  1294. .hld__excel-body #topicrows tbody {border-spacing:0;}
  1295. .hld__excel-body .topicrow {border-spacing:0;}
  1296. .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;}
  1297. .hld__excel-body .topicrow .c1 {width:33px;background:#e8e8e8 !important;}
  1298. .hld__excel-body .topicrow .c1 a {display:none;color: #777777 !important;font-size: 16px !important;font-family: auto;width: 30px;overflow: hidden;text-overflow: ellipsis;white-space: nowrap;}
  1299. .hld__excel-body.hld__excel-original-no .topicrow .c1:before {display:none;}
  1300. .hld__excel-body.hld__excel-original-no .topicrow .c1 a {display:inline-block;}
  1301. .hld__excel-body.hld__excel-original-no .topicrow .c1 img {width:20px;}
  1302. .hld__excel-body .topicrow .c1:before {content:counter(num);counter-increment:num;color:#777777;font-size:16px;}
  1303. .hld__excel-body .topicrow .c2 {padding-left:5px !important;}
  1304. .hld__excel-body .topicrow .c3 {color:#1a3959 !important;}
  1305. .hld__excel-body .block_txt {background:#fff !important;color:#1a3959 !important;border-radius:0;padding:0 !important;min-width:0 !important;font-weight:normal;}
  1306. .hld__excel-body .quote {background:#fff !important;}
  1307. .hld__excel-body #m_posts .block_txt {font-weight:bold;}
  1308. .hld__excel-body .topicrow .postdate,.hld__excel-body .topicrow .replydate {display:inline;margin:10px;}
  1309. .hld__excel-body #m_pbtnbtm {margin:0;border-bottom:1px solid #bbbbbb;}
  1310. .hld__excel-body #pagebbtm,.hld__excel-body #m_pbtnbtm .right_ {margin:0;}
  1311. .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;}
  1312. .hld__excel-body #m_pbtnbtm td {line-height:35px;padding:0 5px;}
  1313. .hld__excel-body #m_pbtnbtm .stdbtn {box-shadow:none;border:none;padding:0;padding-left:5px;background:#fff;border-radius:0;}
  1314. .hld__excel-body #m_pbtnbtm .stdbtn .invert {color:#591804;}
  1315. .hld__excel-body #m_pbtnbtm td a {background:#fff;padding:0;border:0;}
  1316. .hld__excel-body #m_posts .comment_c .comment_c_1 {border-top-color:#bbbbbb;}
  1317. .hld__excel-body #m_posts .comment_c .comment_c_2 {border-color:#bbbbbb;}
  1318. .hld__excel-body #m_posts {border:0;box-shadow:none;padding-bottom:0;margin:0;counter-reset:num;}
  1319. .hld__excel-body #m_posts td {background:#fff;border-right:1px solid #bbbbbb;border-bottom:1px solid #bbbbbb;}
  1320. .hld__excel-body #m_posts .c0 {width:32px;color:#777;font-size:16px;background:#e8e8e8;text-align:center;}
  1321. .hld__excel-body #m_posts .c0:before {content:counter(num);counter-increment:num;}
  1322. .hld__excel-body #m_posts .vertmod {background:#fff !important;color:#ccc;}
  1323. .hld__excel-body #m_posts a[name="uid"]:before {content:"UID:"}
  1324. .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;}
  1325. .hld__excel-body #m_posts .quote {background:#fff;border-color:#bbbbbb;}
  1326. .hld__excel-body #m_posts button {background:#eee;}
  1327. .hld__excel-body #m_posts .postbox {border:none !important;}
  1328. .hld__excel-body .posterInfoLine {background: #FFF !important;border-bottom-color: #FFF !important;}
  1329. .hld__excel-body.hld__reply-fixed #postbbtm {position:fixed;right:30px;top:75px;z-index:999;border-radius: 10px;overflow: hidden;}
  1330. /* Office风格 */
  1331. .hld__excel-body.hld__excel-theme-office .hld__excel-header {height:221px;}
  1332. .hld__excel-body.hld__excel-theme-office #mmc {margin-top:221px;}
  1333. .hld__excel-body.hld__excel-theme-office #m_nav {top:158px;}
  1334. .hld__excel-body.hld__excel-theme-office #m_posts .c0,
  1335. .hld__excel-body.hld__excel-theme-office .topicrow .c1 {width:27px;}
  1336. .hld__excel-body.hld__excel-theme-office #pagebbtm:before,
  1337. .hld__excel-body.hld__excel-theme-office .topicrow .c1 a {width:28px;}
  1338. .hld__excel-body.hld__excel-theme-office .hld__excel-setting {top: 36px;background:none;text-align: center;}
  1339. .hld__excel-body.hld__excel-theme-office .hld__excel-setting a {color:#FFFFFF;}
  1340. .hld__excel-body.hld__excel-theme-office .hld__excel-setting img {display:none;}
  1341. .hld__excel-body.hld__excel-theme-office.hld__reply-fixed #postbbtm {top: 160px;}
  1342. .hld__excel-body.hld__excel-theme-office #m_pbtnbtm td a,
  1343. .hld__excel-body.hld__excel-theme-office #m_pbtnbtm .stdbtn {background: none;}
  1344. `
  1345. }
  1346. /**
  1347. * Excel标题栏标题模块
  1348. * @name excelTitle
  1349. * @description 此模块提供了在Excel模式下可以更改标题的功能
  1350. * 提供一个高级配置输入自定义标题
  1351. */
  1352. const excelTitle = {
  1353. setting: {
  1354. type: 'advanced',
  1355. key: 'excelTitle',
  1356. default: '工作簿1',
  1357. title: 'Excel覆盖标题',
  1358. desc: 'Excel模式下标签栏的名称, 如留空, 则显示原始标题',
  1359. menu: 'left'
  1360. },
  1361. renderAlwaysFunc: function ($el) {
  1362. if ($('.hld__excel-body').length > 0) {
  1363. const excelTitle = script.setting.advanced.excelTitle
  1364. if (excelTitle) {
  1365. $(document).attr('title') != excelTitle && $(document).attr('title', excelTitle)
  1366. }
  1367. $('#hld__excel_icon').length == 0 && $('head').append('<link id= "hld__excel_icon" rel="shortcut icon" type="image/png" href="https://s1.ax1x.com/2020/06/28/N25Jpt.png" />')
  1368. }
  1369. }
  1370. }
  1371. /**
  1372. * 折叠引用模块
  1373. * @name foldQuote
  1374. * @description 此模块提供了可以选择配置自动折叠过长引用
  1375. * 提供一个高级配置可以设置折叠的阈值
  1376. */
  1377. const foldQuote = {
  1378. settings: [{
  1379. type: 'normal',
  1380. key: 'foldQuote',
  1381. default: true,
  1382. title: '折叠过长引用与附件',
  1383. menu: 'left'
  1384. },{
  1385. type: 'advanced',
  1386. key: 'foldQuoteHeight',
  1387. default: 300,
  1388. title: '自动折叠引用高度',
  1389. desc: '自动折叠引用的高度阈值,单位为像素(px)',
  1390. menu: 'right'
  1391. }],
  1392. renderFormsFunc: function ($el) {
  1393. if (script.setting.normal.foldQuote) {
  1394. // 自动折叠过长引用
  1395. if ($el.find('.postcontent .quote').length > 0) {
  1396. let $quote = $el.find('.postcontent .quote')
  1397. if ($quote.height() > (script.setting.advanced.foldQuoteHeight || 300)) {
  1398. const originalHeight = $quote.height()
  1399. $quote.addClass('hld__quote-fold')
  1400. const foldHeight = $quote.height()
  1401. const $openBtn = $(`<div class="hld__quote-box"><button>查看全部 (剩余${100-parseInt(foldHeight/originalHeight*100)}%)</button></div>`)
  1402. $openBtn.on('click', 'button', function(){
  1403. $(this).parent().remove()
  1404. $quote.removeClass('hld__quote-fold')
  1405. })
  1406. $quote.append($openBtn)
  1407. }
  1408. }
  1409. // 折叠附件
  1410. if ($el.find('h4.silver.subtitle').length > 0) {
  1411. $el.find('h4.silver.subtitle').each(function (){
  1412. if ($(this).html() === '附件' && $(this).next().attr('id').includes('postattach')) {
  1413. const $attach = $(this).next()
  1414. $attach.hide()
  1415. const $openBtn = $(`<button>显示附件</button>`)
  1416. $openBtn.on('click', function(){
  1417. $(this).remove()
  1418. $attach.show()
  1419. })
  1420. $(this).next().after($openBtn)
  1421. }
  1422. })
  1423. }
  1424. }
  1425. },
  1426. style: `
  1427. .hld__quote-fold{height:150px;overflow:hidden;position: relative;}
  1428. .hld__quote-box{padding:10px;position: absolute;left:0;right:0;bottom:0;background:#f2eddf;}
  1429. .hld__excel-body .hld__quote-box{background:#FFF;}
  1430. `
  1431. }
  1432. /**
  1433. * 新页面打开模块
  1434. * @name linkTargetBlank
  1435. * @description 此模块提供了可以选择配置在新页面打开链接
  1436. */
  1437. const linkTargetBlank = {
  1438. setting: {
  1439. type: 'normal',
  1440. key: 'linkTargetBlank',
  1441. default: false,
  1442. title: '论坛列表新窗口打开',
  1443. menu: 'right'
  1444. },
  1445. renderThreadsFunc: function ($el) {
  1446. if (script.setting.normal.linkTargetBlank) {
  1447. let $link = $el.find('.topic')
  1448. $link.data('href', $link.attr('href')).attr('href', 'javascript:void(0)')
  1449. $link.click(() => {
  1450. window.open($link.data('href'))
  1451. return false
  1452. })
  1453. }
  1454. }
  1455. }
  1456. /**
  1457. * 图片增强模块
  1458. * @name imgEnhance
  1459. * @description 此模块提供了图片增强功能,使用一个独立的图层打开图片
  1460. * 可以快速切换,缩放,旋转等
  1461. */
  1462. const imgEnhance = {
  1463. settings: [{
  1464. type: 'normal',
  1465. key: 'imgEnhance',
  1466. default: true,
  1467. title: '贴内图片功能增强',
  1468. menu: 'right'
  1469. }, {
  1470. shortCutCode: 37, // LEFT
  1471. key: 'imgEnhancePrev',
  1472. title: '楼内上一张图'
  1473. }, {
  1474. shortCutCode: 39, // RIGHT
  1475. key: 'imgEnhanceNext',
  1476. title: '楼内上一张图'
  1477. }],
  1478. renderFormsFunc: function ($el) {
  1479. $el.find('img').each(function () {
  1480. const classs = $(this).attr('class')
  1481. if (!classs || (classs && !classs.includes('smile'))) {
  1482. $(this).attr('hld__imglist', 'ready').removeAttr('onload')
  1483. }
  1484. })
  1485. //图片增强
  1486. if (script.setting.normal.imgEnhance) {
  1487. const _this = this
  1488. $('#mc').on('click', '.postcontent img[hld__imglist=ready]', function () {
  1489. _this.resizeImg($(this))
  1490. return false
  1491. })
  1492. }
  1493. },
  1494. resizeImg: (el) => {
  1495. if ($('#hld__img_full').length > 0) return
  1496. let urlList = []
  1497. let currentIndex = el.parent().find('[hld__imglist=ready]').index(el)
  1498. el.parent().find('[hld__imglist=ready]').each(function () {
  1499. if ($(this).attr('src') != 'about:blank') {
  1500. urlList.push($(this).data('srcorg') || $(this).data('srclazy') || $(this).attr('src'))
  1501. }
  1502. })
  1503. let $imgBox = $('<div id="hld__img_full" title="点击背景关闭"><div id="loader"></div></div>')
  1504. let $imgContainer = $('<div class="hld__img_container hld__zoom-target"></div>')
  1505. let $img = $('<img title="鼠标滚轮放大/缩小\n左键拖动移动" class="hld__img hld__zoom-target">')
  1506.  
  1507. const renderImg = (index) => {
  1508. let timer = null
  1509. $('#loader').show()
  1510. $imgContainer.css({
  1511. 'top': $(window).height() * 0.03 + 'px',
  1512. 'left': (($(window).width() - ($(window).height()) * 0.85) / 2) + 'px',
  1513. 'width': $(window).height() * 0.85 + 'px',
  1514. 'height': $(window).height() * 0.85 + 'px'
  1515. })
  1516. $img.css({ 'width': '', 'height': '' }).attr('src', urlList[index]).hide()
  1517. timer = setInterval(() => {
  1518. const w = $img.width()
  1519. const h = $img.height()
  1520. if (w > 0) {
  1521. w > h ? $img.css({ 'width': '100%', 'height': 'auto' }) : $img.css({ 'height': '100%', 'width': 'auto' })
  1522. $img.show()
  1523. $('#loader').hide()
  1524. clearInterval(timer)
  1525. }
  1526. }, 1)
  1527. }
  1528. //当前图片
  1529. renderImg(currentIndex)
  1530. $img.mousedown(function (e) {
  1531. let endx = 0;
  1532. let endy = 0;
  1533. let left = parseInt($imgContainer.css("left"))
  1534. let top = parseInt($imgContainer.css("top"))
  1535. let downx = e.pageX
  1536. let downy = e.pageY
  1537. e.preventDefault()
  1538. $(document).on("mousemove", function (es) {
  1539. let endx = es.pageX - downx + left
  1540. let endy = es.pageY - downy + top
  1541. $imgContainer.css("left", endx + "px").css("top", endy + "px")
  1542. return false
  1543. });
  1544. })
  1545. $img.mouseup(function () { $(document).unbind("mousemove") })
  1546.  
  1547. $imgContainer.append($img)
  1548. $imgBox.append($imgContainer)
  1549. $imgBox.click(function (e) { !$(e.target).hasClass('hld__img') && $(this).remove() })
  1550. $imgBox.append(`
  1551. <div class="hld__if_control">
  1552. <div class="change prev-img" title="本楼内上一张"><div></div></div>
  1553. <div class="change rotate-right" title="逆时针旋转90°"><div></div></div>
  1554. <div class="change rotate-left" title="顺时针旋转90°"><div></div></div>
  1555. <div class="change next-img" title="本楼内下一张"><div></div></div>
  1556. </div>
  1557. `)
  1558. $imgBox.on('click', '.change', function () {
  1559. if ($(this).hasClass('prev-img') && currentIndex - 1 >= 0)
  1560. renderImg(--currentIndex)
  1561.  
  1562. if ($(this).hasClass('next-img') && currentIndex + 1 < urlList.length)
  1563. renderImg(++currentIndex)
  1564.  
  1565. if ($(this).hasClass('rotate-right') || $(this).hasClass('rotate-left')) {
  1566. let deg = ($img.data('rotate-deg') || 0) - ($(this).hasClass('rotate-right') ? 90 : -90)
  1567. if (deg >= 360 || deg <= -360) deg = 0
  1568. $img.css('transform', `rotate(${deg}deg)`)
  1569. $img.data('rotate-deg', deg)
  1570. } else {
  1571. $img.css('transform', '')
  1572. $img.data('rotate-deg', 0)
  1573. }
  1574. window.getSelection ? window.getSelection().removeAllRanges() : document.selection.empty()
  1575. return false;
  1576. })
  1577.  
  1578. $imgBox.on("mousewheel DOMMouseScroll", function (e) {
  1579. const delta = (e.originalEvent.wheelDelta && (e.originalEvent.wheelDelta > 0 ? 1 : -1)) ||
  1580. (e.originalEvent.detail && (e.originalEvent.detail > 0 ? -1 : 1));
  1581.  
  1582. if ($imgContainer.width() > 50 || delta > 0) {
  1583. const offsetY = $imgContainer.height() * 0.2
  1584. const offsetX = $imgContainer.width() * 0.2
  1585. let offsetTop = offsetY / 2
  1586. let offsetLeft = offsetX / 2
  1587.  
  1588. if ($(e.target).hasClass('hld__zoom-target')) {
  1589. const targetOffsetX = Math.round(e.clientX - $imgContainer.position().left)
  1590. const targetOffsetY = Math.round(e.clientY - $imgContainer.position().top)
  1591. offsetLeft = (targetOffsetX / ($imgContainer.height() / 2)) * offsetLeft
  1592. offsetTop = (targetOffsetY / ($imgContainer.height() / 2)) * offsetTop
  1593. }
  1594.  
  1595. if (delta > 0) {
  1596. $imgContainer.css({
  1597. 'width': ($imgContainer.height() + offsetY) + 'px',
  1598. 'height': ($imgContainer.height() + offsetY) + 'px',
  1599. 'top': ($imgContainer.position().top - offsetTop) + 'px',
  1600. 'left': ($imgContainer.position().left - offsetLeft) + 'px'
  1601. })
  1602. }
  1603. if (delta < 0) {
  1604. $imgContainer.css({
  1605. 'width': ($imgContainer.height() - offsetY) + 'px',
  1606. 'height': ($imgContainer.height() - offsetY) + 'px',
  1607. 'top': ($imgContainer.position().top + offsetTop) + 'px',
  1608. 'left': ($imgContainer.position().left + offsetLeft) + 'px'
  1609. })
  1610. }
  1611. }
  1612. e.stopPropagation()
  1613. return false
  1614. })
  1615.  
  1616. $('body').append($imgBox)
  1617. },
  1618. shortcutFunc: {
  1619. imgEnhancePrev: function () {
  1620. if ($('#hld__img_full').length > 0) {
  1621. $('#hld__img_full .prev-img').click()
  1622. }
  1623. },
  1624. imgEnhanceNext: function () {
  1625. if ($('#hld__img_full').length > 0) {
  1626. $('#hld__img_full .next-img').click()
  1627. }
  1628. }
  1629. },
  1630. style: `
  1631. .hld__img_container {position:absolute;display:flex;justify-content:center;align-items:center;}
  1632. .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;}
  1633. .postcontent img {margin:0 5px 5px 0 !important;box-shadow:none !important;outline:none !important;}
  1634. #hld__img_full {position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,0.6);z-index:99999;/*display:flex;*//*align-items:center;*//*justify-content:center;*/}
  1635. #hld__img_full img {cursor:move;transition:transform .2s ease;}
  1636. #hld__img_full .hld__imgcenter {top:50%;left:50%;transform:translate(-50%,-50%);}
  1637. #hld__img_full .change {width:40px;height:40px;cursor:pointer;}
  1638. #hld__img_full .rotate-right,#hld__img_full .rotate-left {background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAgCAYAAAB6kdqOAAADYElEQVRYR8WYS8hWVRSGn3cipg0qCExBKYxKQVJRIh1olF0GXpIIoVIUBZWahZeJOpDEQYMcWCBZQRFCZkpGJGgD0yJSwSyVIO0yMrpObPLK+tvnY3f8zu1Tfxfsydlrrf3uve5HXAPZfgR4HJiY1r3Av8BvwCXgOPChpCNtj1FbxoLPdhy+AHgaeLil/DngHWCHpL/qZDoBsj0P+LQliH5s3yVQO6t0dAW0GdhUUvYP8DXwc1q3AncBYb4pFQfvlrS8314nQKHA9n5gDnAKWCfpi6rbJvM+CSwFppf4jkiaW5btDGhQc9leBbwKjM50vC5pda5z2ACl170P+AS4OwOxRVK4whANK6AsUk8DkzNQiyXtvZmAJqVAuCWB6vnTTXmhZL5yxK6UtOsqQLaD8UdJbw3qwG3kbEdqiHQxNvHvlbT4f4Bsn08lIHg2SNrWRnm68e3APUBk4ouSLjfJ2n4DiOgLuiTpzh4g248Cn5WUrJFUmVUzJ80Vx+efgBeaapjtZ4A92ZnTckCvAOv73Oo5Se9W3db2i8BrFfuTJZ2peynbzvYX5IC+AaZWCM+XdKC8Z/s24PeaA49Kmt0A6JfMj1YMAbIdQAJQFf0JLCybwPaDwIkauSG/aAAUjl2UlXUFoJeB7Q1OeBFYJKkH3Hbkk29r5H6VNG4QQMeAh5qiAjgpqWdW2yOBePI7KmQPSJrfyWS2J0TeaQGmYJmbm64UumU1EyX90MmpG6KkrOsPYLykv/MN2wuBjcCM9D3q0kuS4vUqyfYyYHfGME22D6f+pk72SyD6nv11ucV2NGSRFAN4I9l+D1iSGP9LjLYPAtFEVdEhSY81au/IYPuB8ElgRPGqvdJhO7JlhOfnwAfAE6WoWyHpzY5n1rLb3prMXPD1L67Fru3IsHGLoJgaZkmK0eaayfZMINygoOb2w/azwPuZ0EfA82WHHgRdqVyEinYNmu2PgafymwDLJF0YEEj4avhsTu1bWNsxykRhLcI5FIUjhpJ9XUClJj+6gpy6N/mpkYqpM9qTnGI8fruukbthY5DtGP4C1KI+rxI5JzJ9rHD+UcM2KNpeC6wBoqgOQtd3lA4E6bUKYONbooqxJyL2+v5syA+3PSaVnPuBGACLFb9ivgfOAl9FyWkqsLneKyNmUcarECm7AAAAAElFTkSuQmCC) center no-repeat;background-size:25px;}
  1639. #hld__img_full .rotate-right {transform:rotateY(180deg);}
  1640. #hld__img_full .rotate-left:hover {transform:scale(1.2);}
  1641. #hld__img_full .rotate-right:hover {transform:scale(1.2) rotateY(180deg);}
  1642. #hld__img_full .next-img:hover {transform:scale(1.2) rotate(180deg);}
  1643. #hld__img_full .prev-img,#hld__img_full .next-img {background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAABmUlEQVRYR+3WsUtWURjH8e8z+J/4J7QF4vL+C5ZBiAoh6lCDDQmBoIMOOiiIoBCBU+DiUENRQUWigiAuCjoo5JAmkQ41/OTCEzxEwznnvr4u750vfD/nOfdcjnHLj91ynzagqROQ1AC2zOxH6tY2DSBpAnju4Ttmtp2CaApA0hTwLAT7zexFSwCSZoCxENsDuszs/MYBkuaAxyG0A9wzs/2UePVO8RZIWgBGQmgTuG9mh6nxYoCkJeBRCH3x+HFOvAggaQUYCKGPQK+ZfcuNZwMkvQQehtA7X/n3kngWQNIn4G4IvfGVX5TGkwGSDoDOEFr3+GWdeA7gN9DhsV9Aw8y+1o3nAN4D3SF45BPYqItI/g9IGgcmQ7A6ctXX/7kOIhlQRSQ9BaZD8NQRH0oRWQBHPAFmQ/DMj+LbEkQ2wBGjwHwI/nTE61xEEcARQ8BiCF45ojqiyU8xwBGDwHKo/XHEWqqgFsARfcC/l4+W34geAKth1T1m9iplCrUn8DciqceP6C4wbGYnLQWkxP73TtMm0Aa0J1A6gWvfCH8hDgZXwQAAAABJRU5ErkJggg==) center no-repeat;}
  1644. #hld__img_full .next-img {transform:rotate(180deg);}
  1645. #hld__img_full .prev-img:hover {transform:scale(1.2);}
  1646. #hld__img_full .next-img:hover {transform:scale(1.2) rotate(180deg);}
  1647. `
  1648. }
  1649. /**
  1650. * 标记楼主模块
  1651. * @name authorMark
  1652. * @description 此模块提供了自动标记楼主,使其更醒目
  1653. */
  1654. const authorMark = {
  1655. setting: {
  1656. type: 'normal',
  1657. key: 'authorMark',
  1658. default: true,
  1659. title: '高亮楼主',
  1660. menu: 'right'
  1661. },
  1662. postAuthor: [],
  1663. renderFormsFunc: function ($el) {
  1664. if (script.setting.normal.authorMark) {
  1665. const author = $('#postauthor0').text().replace('[楼主]', '')
  1666. if (author && $('#hld__post-author').val() != author) {
  1667. const localPostAuthor = window.localStorage.getItem('hld__NGA_post_author')
  1668. localPostAuthor && (this.postAuthor = localPostAuthor.split(','))
  1669. const tid = this.getQueryString('tid')
  1670. if (tid) {
  1671. const authorStr = `${tid}:${author}`
  1672. if (!this.postAuthor.includes(authorStr))
  1673. this.postAuthor.unshift(authorStr) > 10 && this.postAuthor.pop()
  1674. window.localStorage.setItem('hld__NGA_post_author', this.postAuthor.join(','))
  1675. }
  1676. for (let pa of this.postAuthor) {
  1677. const t = pa.split(':')
  1678. if (t[0] == tid) {
  1679. if ($('#hld__post-author').length == 0) $('body').append(`<input type="hidden" value="${t[1]}" id="hld__post-author">`)
  1680. else $('#hld__post-author').val(t[1])
  1681. break
  1682. }
  1683. }
  1684. }
  1685. }
  1686. $el.find('a.b').each(function () {
  1687. const name = $(this).attr('hld-mark-before-name') || $(this).text().replace('[', '').replace(']', '')
  1688. if (script.setting.normal.authorMark) {
  1689. if (name == $('#hld__post-author').val() && $(this).find('span.hld__post-author').length == 0)
  1690. $(this).append('<span class="hld__post-author">[楼主]</span>')
  1691. }
  1692. })
  1693. },
  1694. /**
  1695. * 获取URL参数
  1696. * @method getQueryString
  1697. * @param {String} name key
  1698. * @return {String|null} value
  1699. */
  1700. getQueryString: (name) => {
  1701. let url = decodeURI(window.location.search.replace(/&amp;/g, "&"))
  1702. let reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)")
  1703. let r = url.substr(1).match(reg)
  1704. if (r != null) return unescape(r[2])
  1705. return null
  1706. },
  1707. asyncStyle: () => {
  1708. return `
  1709. .hld__post-author {color:${script.setting.advanced.authorMarkColor || '#F00'};font-weight:bold;}
  1710. `
  1711. }
  1712. }
  1713. /**
  1714. * 标记楼主可选颜色模块
  1715. * @name authorMarkColor
  1716. * @requires https://cdn.staticfile.org/spectrum/1.8.0/spectrum.js
  1717. * @description 此模块提供了高级设置可选标记楼主的颜色
  1718. * 以及为其他模块提供一个spectrum的配置文件
  1719. */
  1720. const authorMarkColor = {
  1721. name: 'authorMarkColor',
  1722. setting: {
  1723. type: 'advanced',
  1724. key: 'authorMarkColor',
  1725. default: '#F00',
  1726. title: '标记楼主颜色',
  1727. desc: '标记楼主中的[楼主]的颜色,单位为16进制颜色代码',
  1728. menu: 'left'
  1729. },
  1730. // spectrum配置对象
  1731. colorPickerConfig: {
  1732. type: 'color',
  1733. preferredFormat: 'hex',
  1734. showPaletteOnly: 'true',
  1735. togglePaletteOnly: 'true',
  1736. hideAfterPaletteSelect: 'true',
  1737. showAlpha: 'false',
  1738. togglePaletteMoreText: '更多选项',
  1739. togglePaletteLessText: '隐藏',
  1740. palette: [
  1741. ['#000000','#444444','#5b5b5b','#999999','#bcbcbc','#eeeeee','#f3f6f4','#ffffff'],
  1742. ['#f44336','#744700','#ce7e00','#8fce00','#2986cc','#16537e','#6a329f','#c90076'],
  1743. ['#f4cccc','#fce5cd','#fff2cc','#d9ead3','#d0e0e3','#cfe2f3','#d9d2e9','#ead1dc'],
  1744. ['#ea9999','#f9cb9c','#ffe599','#b6d7a8','#a2c4c9','#9fc5e8','#b4a7d6','#d5a6bd'],
  1745. ['#e06666','#f6b26b','#ffd966','#93c47d','#76a5af','#6fa8dc','#8e7cc3','#c27ba0'],
  1746. ['#cc0000','#e69138','#f1c232','#6aa84f','#45818e','#3d85c6','#674ea7','#a64d79'],
  1747. ['#990000','#b45f06','#bf9000','#38761d','#134f5c','#0b5394','#351c75','#741b47'],
  1748. ['#660000','#783f04','#7f6000','#274e13','#0c343d','#073763','#20124d','#4c1130']
  1749. ]
  1750. },
  1751. initFunc: function() {
  1752. $('#hld__setting_cover').find('#hld__adv_authorMarkColor').spectrum(this.colorPickerConfig)
  1753. },
  1754. style: `
  1755. .cp-color-picker{z-index:99997}
  1756. .sp-container{position:absolute;top:0;left:0;display:inline-block;z-index:9999994;overflow:hidden}
  1757. .sp-original-input-container{position:relative;display:inline-flex}
  1758. .sp-original-input-container input{margin:0!important}
  1759. .sp-original-input-container .sp-add-on{width:40px;border-top-right-radius:0!important;border-bottom-right-radius:0!important}
  1760. input.spectrum.with-add-on{border-top-left-radius:0;border-bottom-left-radius:0;border-left:0}
  1761. .sp-original-input-container .sp-add-on .sp-colorize{height:100%;width:100%;border-radius:inherit}
  1762. .sp-colorize-container{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==)}
  1763. .sp-container.sp-flat{position:relative}
  1764. .sp-container,.sp-container *{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}
  1765. .sp-top{position:relative;width:100%;display:inline-block}
  1766. .sp-top-inner{position:absolute;top:0;left:0;bottom:0;right:0}
  1767. .sp-color{position:absolute;top:0;left:0;bottom:0;right:20px!important}
  1768. .sp-hue{position:absolute;top:0;right:0;bottom:0;width:12px;height:100%;left:initial!important}
  1769. .sp-clear-enabled .sp-hue{top:15%;height:85%}
  1770. .sp-fill{padding-top:80%}
  1771. .sp-sat,.sp-val{position:absolute;top:0;left:0;right:0;bottom:0}
  1772. .sp-alpha-enabled .sp-top{margin-bottom:28px!important}
  1773. .sp-alpha-enabled .sp-alpha{display:block}
  1774. .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}
  1775. .sp-alpha{display:none;position:absolute;bottom:-18px;right:0;left:0;height:10px}
  1776. .sp-alpha-inner{border-radius:4px}
  1777. .sp-clear{display:none}
  1778. .sp-clear.sp-clear-display{background-position:center}
  1779. .sp-clear-enabled .sp-clear{display:block;position:absolute;top:3px;right:0;bottom:0;cursor:pointer;left:initial;height:12px;width:12px}
  1780. .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}
  1781. .sp-container.sp-input-disabled .sp-input-container{display:none}
  1782. .sp-container.sp-buttons-disabled .sp-button-container{display:none}
  1783. .sp-container.sp-palette-buttons-disabled .sp-palette-button-container{display:none}
  1784. .sp-palette-only .sp-picker-container{display:none}
  1785. .sp-palette-disabled .sp-palette-container{display:none}
  1786. .sp-initial-disabled .sp-initial{display:none}
  1787. .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))}
  1788. .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))}
  1789. .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%)}
  1790. .sp-1{height:17%}
  1791. .sp-2{height:16%}
  1792. .sp-3{height:17%}
  1793. .sp-4{height:17%}
  1794. .sp-5{height:16%}
  1795. .sp-6{height:17%}
  1796. .sp-hidden{display:none!important}
  1797. .sp-cf:after,.sp-cf:before{content:"";display:table}
  1798. .sp-cf:after{clear:both}
  1799. @media (max-device-width:480px){.sp-color{right:40%}
  1800. .sp-hue{left:63%}
  1801. .sp-fill{padding-top:60%}
  1802. }
  1803. .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)}
  1804. .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}
  1805. .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)}
  1806. .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}
  1807. .sp-top{margin-bottom:10px}
  1808. .sp-clear,.sp-color,.sp-hue,.sp-sat,.sp-val{border-radius:3px}
  1809. .sp-input-container{margin-top:-5px}
  1810. .sp-button-container.sp-cf,.sp-initial.sp-thumb.sp-cf,.sp-input-container.sp-cf{height:25px}
  1811. .sp-picker-container .sp-cf{margin-bottom:10px}
  1812. .sp-palette-row-initial>span:first-child{cursor:pointer}
  1813. .sp-initial-disabled .sp-input-container{width:100%}
  1814. .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}
  1815. .sp-input.sp-validation-error{border:1px solid red;background:#fdd}
  1816. .sp-palette-container,.sp-picker-container{position:relative;padding:10px}
  1817. .sp-picker-container{width:200px;padding-bottom:0}
  1818. .sp-palette-container{border-right:solid 1px #ccc}
  1819. .sp-palette-only .sp-palette-container{border:0}
  1820. .sp-palette .sp-thumb-el{display:block;position:relative;float:left;width:24px;height:15px;margin:3px;cursor:pointer;border:solid 2px transparent}
  1821. .sp-palette .sp-thumb-el.sp-thumb-active,.sp-palette .sp-thumb-el:hover{border-color:orange}
  1822. .sp-thumb-el{position:relative}
  1823. .sp-initial{float:left}
  1824. .sp-initial span{width:30px;height:25px;border:none;display:block;float:left;margin:0}
  1825. .sp-initial .spe-thumb-el.sp-thumb-active{border-radius:0 5px 5px 0}
  1826. .sp-initial .spe-thumb-el{border-radius:5px 0 0 5px}
  1827. .sp-initial .sp-clear-display{background-position:center}
  1828. .sp-button-container{float:right;display:none;}
  1829. .sp-palette-button-container{margin-top:10px}
  1830. .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;}
  1831. .sp-replacer.sp-active,.sp-replacer:hover{border:1px solid #666;color:#000}
  1832. .sp-replacer.sp-disabled{cursor:default;border-color:silver;color:silver}
  1833. .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;}
  1834. .sp-preview{position:relative;width:100%;height:100%;float:left;z-index:0}
  1835. .sp-preview-inner{transition:background-color .2s}
  1836. .sp-preview-inner.sp-clear-display{display:none}
  1837. .sp-palette .sp-thumb-el{width:16px;height:16px;margin:3px;border:none;border-radius:3px}
  1838. .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}
  1839. .sp-container button.sp-choose{background-color:#3cab3b;color:#fff;margin-left:5px}
  1840. .sp-container button:hover{opacity:.8}
  1841. .sp-container button.sp-palette-toggle{width:100%;background-color:#f3f3f3;margin:0}
  1842. .sp-palette span.sp-thumb-active,.sp-palette span:hover{border-color:#000}
  1843. .sp-alpha,.sp-preview,.sp-thumb-el{position:relative;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==)}
  1844. .sp-alpha-inner,.sp-preview-inner,.sp-thumb-inner{display:block;position:absolute;top:0;left:0;bottom:0;right:0}
  1845. .sp-palette .sp-thumb-inner{border-radius:3px;background-position:50% 50%;background-repeat:no-repeat}
  1846. .sp-palette .sp-thumb-light.sp-thumb-active .sp-thumb-inner{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAIVJREFUeNpiYBhsgJFMffxAXABlN5JruT4Q3wfi/0DsT64h8UD8HmpIPCWG/KemIfOJCUB+Aoacx6EGBZyHBqI+WsDCwuQ9mhxeg2A210Ntfo8klk9sOMijaURm7yc1UP2RNCMbKE9ODK1HM6iegYLkfx8pligC9lCD7KmRof0ZhjQACDAAceovrtpVBRkAAAAASUVORK5CYII=)}
  1847. .sp-palette .sp-thumb-dark.sp-thumb-active .sp-thumb-inner{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAAMdJREFUOE+tkgsNwzAMRMugEAahEAahEAZhEAqlEAZhEAohEAYh81X2dIm8fKpEspLGvudPOsUYpxE2BIJCroJmEW9qJ+MKaBFhEMNabSy9oIcIPwrB+afvAUFoK4H0tMaQ3XtlrggDhOVVMuT4E5MMG0FBbCEYzjYT7OxLEvIHQLY2zWwQ3D+9luyOQTfKDiFD3iUIfPk8VqrKjgAiSfGFPecrg6HN6m/iBcwiDAo7WiBeawa+Kwh7tZoSCGLMqwlSAzVDhoK+6vH4G0P5wdkAAAAASUVORK5CYII=)}
  1848. .sp-clear-display{background-repeat:no-repeat;background-position:center;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAABe0lEQVQokYXSsUtcQRTF4d8Jj+VhHSxkEQuLsEUKK0nhTBFTmLSSUhBCMCAWsmgIwWrBLk0akfwLCaSQKBJmtrIIISwpRFKIhViETScphGMzysMtvOVwvpm5d0bGNCuGWAOPgYdl6S8wSDn9b+bUhDHEKWAdeAFMANg+l/TV9ofcz6cjMIbYBvaBMds7QCqZ58CmpBNgPuV0DvAAIMyFGugWtJr7eTv38xEwkPRPErY7QDeG2LqFkjrAgu0dSd/KDVqSNmxvAZ8lfbS9AHRuYemnLWkv5XRVBrQMbAI/gTXgEzAJtJuwBVS2L2OIle03QA/4Lmkl5XQBXEqqbFcAVYFDYChpFngiqWf7l6TXKaezMt2Zkhk24THwG+jZriX9AFZvUAyxLbRke2D75O5zPAO+ADXwEtizjaRHwDvbTyUtppwOmicCHAJvbXcl9YA1SQDjtseA97YPRz7ATcUQp2y/kjRdevsjaTfldNrMjcDGBjXA3T96L7yvrgFzP69+0Ao/HAAAAABJRU5ErkJggg==)}
  1849. `
  1850. }
  1851. /**
  1852. * 自动翻页模块
  1853. * @name autoPage
  1854. * @description 此模块提供了脚本自动翻页的功能
  1855. * 提供一个高级配置可以设置自动翻页的检测阈值
  1856. */
  1857. const autoPage = {
  1858. settings: [{
  1859. type: 'normal',
  1860. key: 'autoPage',
  1861. default: true,
  1862. title: '自动翻页',
  1863. menu: 'right'
  1864. }],
  1865. $window: $(window),
  1866. initFunc: function () {
  1867. script.setting.normal.autoPage && $('body').addClass('hld__reply-fixed')
  1868. },
  1869. renderAlwaysFunc: function () {
  1870. const _this = this
  1871. if(script.setting.normal.autoPage) {
  1872. if($('#hld__next_page').length > 0) return
  1873. $('#pagebbtm>.stdbtn[hld-auto-page!=ok] td').each(function(){
  1874. if($(this).children('a').text() == '>') {
  1875. $(this).children('a').attr('id', 'hld__next_page')
  1876. _this.$window.on('scroll.autoPage', function(){
  1877. if ($(document).scrollTop() != 0 && (Math.ceil($(document).scrollTop()) + $(window).height() >= ($(document).height() - 20))) {
  1878. if($('#hld__next_page').length > 0) {
  1879. console.warn('Auto Page')
  1880. document.getElementById('hld__next_page').click()
  1881. $('#hld__next_page').removeAttr('id')
  1882. _this.$window.off('scroll.autoPage')
  1883. }
  1884. }
  1885. })
  1886. }
  1887. })
  1888. $('#pagebbtm>.stdbtn').attr('hld-auto-page', 'ok')
  1889. }
  1890. }
  1891. }
  1892. /**
  1893. * 关键字屏蔽模块
  1894. * @name keywordsBlock
  1895. * @description 此模块提供了关键字屏蔽功能
  1896. * 提供一个高级配置可以设置是否过滤标题
  1897. */
  1898. const keywordsBlock = {
  1899. name: 'keywordsBlock',
  1900. settings: [{
  1901. type: 'normal',
  1902. key: 'keywordsBlock',
  1903. default: true,
  1904. title: '关键字屏蔽',
  1905. menu: 'right',
  1906. extra: {
  1907. type: 'button',
  1908. label: '关键字管理',
  1909. id: 'hld__keywords_manage'
  1910. }
  1911. }, {
  1912. type: 'advanced',
  1913. key: 'kwdBlockContent',
  1914. default: 'ALL',
  1915. options: [{
  1916. label: '标题跟正文',
  1917. value: 'ALL'
  1918. }, {
  1919. label: '仅标题',
  1920. value: 'TITLE'
  1921. }, {
  1922. label: '仅正文',
  1923. value: 'BODY'
  1924. }],
  1925. title: '关键字屏蔽方式',
  1926. desc: '此配置表示关键字的屏蔽方式',
  1927. menu: 'right'
  1928. }],
  1929. keywordsList: [],
  1930. initFunc: function () {
  1931. const _this = this
  1932. // 同步本地数据
  1933. const localKeywordsList = window.localStorage.getItem('hld__NGA_keywords_list')
  1934. try {
  1935. localKeywordsList && (_this.keywordsList = JSON.parse(localKeywordsList))
  1936. } catch {
  1937. localKeywordsList && (_this.keywordsList = localKeywordsList.split(','))
  1938. window.localStorage.setItem('hld__NGA_keywords_list', JSON.stringify(_this.keywordsList))
  1939. }
  1940. // 添加到导入导出配置
  1941. script.getModule('backupModule').addItem({
  1942. title: '关键字列表',
  1943. writeKey: 'keywords_list',
  1944. valueKey: 'keywordsList',
  1945. module: this
  1946. })
  1947. // 管理弹窗
  1948. $('body').on('click', '#hld__keywords_manage', function () {
  1949. if($('#hld__keywords_panel').length > 0) return
  1950. $('#hld__setting_cover').append(`<div id="hld__keywords_panel" class="hld__list-panel animated fadeInUp">
  1951. <a href="javascript:void(0)" class="hld__setting-close">×</a>
  1952. <div>
  1953. <div class="hld__list-c"><p>屏蔽关键字</p><textarea row="20" id="hld__keywords_list_textarea"></textarea><p class="hld__list-desc">一行一条</p></div>
  1954. </div>
  1955. <div class="hld__btn-groups"><button class="hld__btn" id="hld__save_keywords">保存列表</button></div>
  1956. </div>`)
  1957. $('#hld__keywords_list_textarea').val(_this.keywordsList.join('\n'))
  1958. })
  1959. // 保存关键字
  1960. $('body').on('click', '#hld__save_keywords', function () {
  1961. let keywordsList = $('#hld__keywords_list_textarea').val().split('\n')
  1962. keywordsList = _this.removeBlank(keywordsList)
  1963. keywordsList = _this.uniq(keywordsList)
  1964. _this.keywordsList = keywordsList
  1965. window.localStorage.setItem('hld__NGA_keywords_list', JSON.stringify(_this.keywordsList))
  1966. $('.hld__list-panel').remove()
  1967. script.popMsg('保存成功,刷新页面生效')
  1968. })
  1969. },
  1970. renderThreadsFunc: function ($el) {
  1971. const title = $el.find('.c2>a').text()
  1972. if ((script.setting.advanced.kwdBlockContent === 'ALL' || script.setting.advanced.kwdBlockContent === 'TITLE') && script.setting.normal.keywordsBlock && this.keywordsList.length > 0) {
  1973. for (let keyword of this.keywordsList) {
  1974. if (title.includes(keyword)) {
  1975. console.warn(`【NGA-Script-关键字屏蔽】标题:${title} 连接:${$el.find('.c2>a').attr('href')}`)
  1976. $el.remove()
  1977. break
  1978. }
  1979. }
  1980. }
  1981. },
  1982. renderFormsFunc: function ($el) {
  1983. const _this = this
  1984. if (script.setting.normal.keywordsBlock && this.keywordsList.length > 0 && (script.setting.advanced.kwdBlockContent === 'ALL' || script.setting.advanced.kwdBlockContent === 'BODY')) {
  1985. const $postcontent = $el.find('.postcontent')
  1986. const $postcontentClone = $postcontent.clone()
  1987. const consoleLog = (text) => console.warn(`【NGA优化摸鱼体验脚本-关键字屏蔽】内容:${text}`)
  1988. let postcontentQuote = ''
  1989. let postcontentText = ''
  1990.  
  1991. if ($postcontent.find('.quote').length > 0) {
  1992. $postcontentClone.find('.quote').remove()
  1993. let postcontentText = $postcontent.find('.quote').text()
  1994. const endIndex = postcontentText.indexOf(')')
  1995. postcontentQuote = postcontentText.substring(endIndex + 1)
  1996. }
  1997.  
  1998. postcontentText = $postcontentClone.text()
  1999. let blockCount = 0
  2000. for (let keyword of this.keywordsList) {
  2001. if (postcontentText && postcontentText.includes(keyword)) {
  2002. consoleLog(postcontentText)
  2003. $el.remove()
  2004. blockCount += 1
  2005. break
  2006. }
  2007. if (postcontentQuote && postcontentQuote.includes(keyword)) {
  2008. consoleLog(postcontentQuote)
  2009. blockCount += 1
  2010. $postcontent.find('.quote').remove()
  2011. }
  2012. }
  2013. const $commentCList = $el.find('.comment_c')
  2014. if ($commentCList.length > 0) {
  2015. let postcontentReply = ''
  2016. $commentCList.each(function () {
  2017. let postcontentReplyText = $el.find('.ubbcode').text()
  2018. const end_index = postcontentReplyText.indexOf(')')
  2019. postcontentReply = postcontentReplyText.substring(end_index + 1)
  2020. for (let keyword of _this.keywordsList) {
  2021. if (postcontentReply && postcontentReply.includes(keyword)) {
  2022. consoleLog(postcontentReply)
  2023. blockCount += 1
  2024. $(this).remove()
  2025. }
  2026. }
  2027. })
  2028. }
  2029. }
  2030. },
  2031. /**
  2032. * 列表去空
  2033. * @method removeBlank
  2034. * @param {Array} array 列表
  2035. * @return {Array} 处理后的列表
  2036. */
  2037. removeBlank: function (array) {
  2038. let r = []
  2039. array.map(function (val, index) {
  2040. if (val !== '' && val != undefined) {
  2041. r.push(val)
  2042. }
  2043. });
  2044. return r
  2045. },
  2046. /**
  2047. * 列表去重
  2048. * @method uniq
  2049. * @param {Array} array 列表
  2050. * @return {Array} 处理后的列表
  2051. */
  2052. uniq: function (array) {
  2053. return [...new Set(array)]
  2054. },
  2055. style: `
  2056. #hld__keywords_panel {width:182px;}
  2057. #hld__keywords_panel .hld__list-c {width:100%;}
  2058. `
  2059. }
  2060. /**
  2061. * 黑名单标记模块
  2062. * @name markAndBan
  2063. * @description 此模块提供了黑名单屏蔽功能,标签标记功能
  2064. * 提供高级配置可以设置标记/备注风格
  2065. * 提供高级配置可以设置功能面板显示方式
  2066. * 提供高级配置可以设置黑名单屏蔽策略
  2067. */
  2068. const markAndBan = {
  2069. name: 'markAndBan',
  2070. settings: [{
  2071. type: 'normal',
  2072. key: 'markAndBan',
  2073. default: true,
  2074. title: '拉黑/标签功能',
  2075. menu: 'right',
  2076. extra: {
  2077. type: 'button',
  2078. label: '名单管理',
  2079. id: 'hld__list_manage'
  2080. }
  2081. }, {
  2082. type: 'advanced',
  2083. key: 'classicRemark',
  2084. default: false,
  2085. title: '经典备注风格',
  2086. desc: '此配置表示标记功能的风格显示\n选中时:v2.9及以前的备注风格(仿微博),此风格不能更改颜色\n取消时:新版标记风格',
  2087. menu: 'right'
  2088. }, {
  2089. type: 'advanced',
  2090. key: 'autoHideBanIcon',
  2091. default: false,
  2092. title: '按需显示标注拉黑按钮',
  2093. desc: '选中时:默认隐藏标注与拉黑按钮, 当鼠标停留区域时, 才会显示\n取消时:一直显示',
  2094. menu: 'right'
  2095. }, {
  2096. type: 'advanced',
  2097. key: 'banStrictMode',
  2098. default: 'HIDE',
  2099. options: [{
  2100. label: '屏蔽',
  2101. value: 'HIDE'
  2102. }, {
  2103. label: '删除',
  2104. value: 'REMOVE'
  2105. }, {
  2106. label: '全部删除',
  2107. value: 'ALL'
  2108. }],
  2109. title: '拉黑模式',
  2110. desc: '此配置表示拉黑某人后对帖子的屏蔽策略\n屏蔽:保留楼层, 仅会屏蔽用户的回复\n删除:将会删除楼层\n全部删除: 回复被拉黑用户的回复也会被删除',
  2111. menu: 'right'
  2112. }],
  2113. banList: [],
  2114. markList: [],
  2115. initFunc: function () {
  2116. const _this = this
  2117. // 读取本地数据
  2118. const localBanList = window.localStorage.getItem('hld__NGA_ban_list')
  2119. try {
  2120. localBanList && (_this.banList = JSON.parse(localBanList))
  2121. } catch {
  2122. window.localStorage.setItem('hld__NGA_ban_list_bak', localBanList)
  2123. window.localStorage.removeItem('hld__NGA_ban_list')
  2124. script.throwError('【NGA-Script】无法加载黑名单列表,数据解析失败\n黑名单已清空,之前的数据已经备份到hld__NGA_ban_list_bak\n请在控制台中的localStorage中查看')
  2125. }
  2126. const localMarkList = window.localStorage.getItem('hld__NGA_mark_list')
  2127. try {
  2128. localMarkList && (_this.markList = JSON.parse(localMarkList))
  2129. } catch {
  2130. window.localStorage.setItem('hld__NGA_mark_list_bak', localMarkList)
  2131. window.localStorage.removeItem('hld__NGA_mark_list')
  2132. script.throwError('【NGA-Script】无法加载标记列表,数据解析失败\n标记列表已清空,之前的数据已经备份到hld__NGA_mark_list_bak\n请在控制台中的localStorage中查看')
  2133. }
  2134. // 添加到导入导出配置
  2135. script.getModule('backupModule').addItem({
  2136. title: '黑名单列表',
  2137. writeKey: 'ban_list',
  2138. valueKey: 'banList',
  2139. module: this
  2140. })
  2141. script.getModule('backupModule').addItem({
  2142. title: '标记名单列表',
  2143. writeKey: 'mark_list',
  2144. valueKey: 'markList',
  2145. module: this
  2146. })
  2147. // 拉黑标签-名单
  2148. if (script.setting.normal.markAndBan) {
  2149. //绑定事件
  2150. $('body').on('click', '.hld__extra-icon', function () {
  2151. const type = $(this).data('type')
  2152. const name = $(this).data('name')
  2153. const uid = $(this).data('uid') + ''
  2154. $('.hld__dialog').length > 0 && $('.hld__dialog').remove()
  2155. if (type == 'ban') {
  2156. _this.banlistPopup({
  2157. type: 'confirm',
  2158. name,
  2159. uid,
  2160. top: $(this).offset().top+20,
  2161. left: $(this).offset().left-10
  2162. })
  2163. }
  2164. if (type == 'mark') {
  2165. _this.userMarkPopup({
  2166. name,
  2167. uid,
  2168. top: $(this).offset().top+20,
  2169. left: $(this).offset().left-10
  2170. })
  2171. }
  2172. })
  2173. $('body').on('click', '.hld__banned-block', function(){
  2174. if ($(this).parent().hasClass('quote')) {
  2175. $(this).parent().prev().show()
  2176. $(this).parent().hide()
  2177. } else {
  2178. $(this).prev().show()
  2179. $(this).hide()
  2180. }
  2181. })
  2182. //名单管理
  2183. $('body').on('click', '#hld__list_manage', function () {
  2184. if($('#hld__banlist_panel').length > 0) return
  2185. $('#hld__setting_cover').append(`<div id="hld__banlist_panel" class="hld__list-panel animated fadeInUp">
  2186. <a href="javascript:void(0)" class="hld__setting-close">×</a>
  2187. <div class="hld__tab-header"><span class="hld__table-active">简易模式</span><span>原始数据</span></div>
  2188. <div class="hld__tab-content hld__format-list hld__table-active">
  2189. <div class="hld__list-c"><p>黑名单</p>
  2190. <div class="hld__scroll-area">
  2191. <table class="hld__table hld__table-banlist">
  2192. <thead><tr><th width="175">用户名</th><th>UID</th><th width="25">操作</th></tr></thead><tbody id="hld__banlist"></tbody></table>
  2193. </div>
  2194. <div class="hld__table-banlist-buttons"><button id="hld__banlist_add_btn" class="hld__btn">+添加用户</button></div>
  2195. </div>
  2196. <div class="hld__list-c"><p>标签名单</p>
  2197. <div class="hld__scroll-area">
  2198. <table class="hld__table hld__table-banlist">
  2199. <thead><tr><th width="100">用户名</th><th>UID</th><th width="50">标签数</th><th width="50">操作</th></tr></thead><tbody id="hld__marklist"></tbody></table>
  2200. </div>
  2201. <div class="hld__table-banlist-buttons"><button id="hld__marklist_add_btn" class="hld__btn">+添加用户</button></div>
  2202. </div>
  2203. </div>
  2204. <div class="hld__tab-content hld__source-list">
  2205. <div class="hld__list-c"><p>黑名单</p><textarea row="20" id="hld__ban_list_textarea"></textarea><p class="hld__list-desc" title='[{\n "uid": "UID",\n "name": "用户名"\n }, ...]'>查看数据结构</p></div>
  2206. <div class="hld__list-c"><p>标签名单</p><textarea row="20" id="hld__mark_list_textarea"></textarea><p class="hld__list-desc" title='[{\n "uid": "UID",\n "name": "用户名",\n "marks": [{\n "mark": "标记",\n "text_color": "文字色",\n "bg_color": "背景色"\n }, ...]\n }, ...]'>查看数据结构</p></div>
  2207. <div class="hld__btn-groups" style="width: 100%;"><button class="hld__btn" id="hld__save_banlist">保存列表</button></div>
  2208. </div>
  2209. </div>`)
  2210. //切换选项卡
  2211. $('body').on('click', '.hld__tab-header > span', function(){
  2212. $('.hld__tab-header > span, .hld__tab-content').removeClass('hld__table-active')
  2213. $(this).addClass('hld__table-active')
  2214. $('.hld__tab-content').eq($(this).index()).addClass('hld__table-active')
  2215. })
  2216. //移除黑名单用户
  2217. $('body').on('click', '.hld__bl-del', function(){
  2218. const index = $(this).data('index')
  2219. _this.banList.splice(index, 1)
  2220. window.localStorage.setItem('hld__NGA_ban_list', JSON.stringify(_this.banList))
  2221. _this.reloadBanlist()
  2222. })
  2223. //添加黑名单用户
  2224. $('body').on('click', '#hld__banlist_add_btn', function(){
  2225. _this.banlistPopup({
  2226. type: 'add',
  2227. name: $(this).data('name'),
  2228. uid: $(this).data('uid'),
  2229. top: $(this).offset().top + 30,
  2230. left: $(this).offset().left - 5,
  2231. callback: () => {_this.reloadBanlist()}
  2232. })
  2233. })
  2234. $('body').on('click', '#hld__save_banlist', function(){
  2235. const banList = $('#hld__ban_list_textarea').val()
  2236. const markList = $('#hld__mark_list_textarea').val()
  2237. try {
  2238. _this.banList = JSON.parse(banList)
  2239. window.localStorage.setItem('hld__NGA_ban_list', banList)
  2240. _this.reloadBanlist()
  2241. } catch {
  2242. script.popMsg('黑名单数据有误!', 'err')
  2243. return
  2244. }
  2245. try {
  2246. _this.markList = JSON.parse(markList)
  2247. window.localStorage.setItem('hld__NGA_mark_list', markList)
  2248. _this.reloadMarklist()
  2249. } catch {
  2250. script.popMsg('标记单数据有误!', 'err')
  2251. return
  2252. }
  2253. script.popMsg('数据已成功')
  2254. })
  2255. //修改标记
  2256. $('body').on('click', '.hld__ml-edit', function(){
  2257. const name = $(this).data('name')
  2258. const uid = $(this).data('uid') + ''
  2259. _this.userMarkPopup({
  2260. name,
  2261. uid,
  2262. top: $(this).offset().top + 30,
  2263. left: $(this).offset().left - 5,
  2264. callback: () => {_this.reloadMarklist()}
  2265. })
  2266. })
  2267. //删除标记
  2268. $('body').on('click', '.hld__ml-del', function(){
  2269. const index = $(this).data('index')
  2270. _this.markList.splice(index, 1)
  2271. window.localStorage.setItem('hld__NGA_mark_list', JSON.stringify(_this.markList))
  2272. _this.reloadMarklist()
  2273. })
  2274. //添加标记
  2275. $('body').on('click', '#hld__marklist_add_btn', function(){
  2276. _this.userMarkPopup({
  2277. type: 'add',
  2278. name: $(this).data('name'),
  2279. uid: $(this).data('uid'),
  2280. top: $(this).offset().top + 30,
  2281. left: $(this).offset().left - 5,
  2282. callback: () => {_this.reloadMarklist()}
  2283. })
  2284. })
  2285. //重载名单
  2286. _this.reloadBanlist()
  2287. _this.reloadMarklist()
  2288. })
  2289. }
  2290. },
  2291. renderThreadsFunc: function($el) {
  2292. const title = $el.find('.c2>a').text()
  2293. const uid = ($el.find('.author').attr('href') && $el.find('.author').attr('href').indexOf('uid=') > -1) ? $el.find('.author').attr('href').split('uid=')[1] + '' : ''
  2294. const name = $el.find('.author').text()
  2295. if (script.setting.normal.markAndBan) {
  2296. const banUser = this.getBanUser({name, uid})
  2297. //黑名单屏蔽
  2298. if (this.banList.length > 0 && banUser) {
  2299. console.warn(`【NGA-Script-黑名单屏蔽】标题:${title} 连接:${$el.find('.c2>a').attr('href')}`)
  2300. $el.parents('tbody').remove()
  2301. }
  2302. }
  2303. },
  2304. renderFormsFunc: function($el) {
  2305. const _this = this
  2306. if (script.setting.normal.markAndBan) {
  2307. // 插入操作面板
  2308. const currentUid = $el.find('[name=uid]').text() + ''
  2309. $el.find('.small_colored_text_btn.block_txt_c2.stxt').each(function () {
  2310. let currentName = ''
  2311. if ($(this).parents('td').prev('td').html() == '') {
  2312. currentName = $(this).parents('table').prev('.posterinfo').children('.author').text()
  2313. } else {
  2314. currentName = $(this).parents('td').prev('td').find('.author').text()
  2315. }
  2316. currentName.endsWith('[楼主]') && (currentName = currentName.substr(0, currentName.length - 4))
  2317. const mbDom = `<a class="hld__extra-icon" data-type="mark" title="标签此用户" data-name="${currentName}" data-uid="${currentUid}"><svg t="1578453291663" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="15334" width="32" height="32"><path d="M978.488889 494.933333l-335.644445 477.866667-415.288888 45.511111c-45.511111 5.688889-91.022222-28.444444-102.4-73.955555L22.755556 540.444444 358.4 56.888889C398.222222 0 477.866667-11.377778 529.066667 28.444444l420.977777 295.822223c56.888889 39.822222 68.266667 113.777778 28.444445 170.666666zM187.733333 927.288889c5.688889 11.377778 17.066667 22.755556 28.444445 22.755555l386.844444-39.822222 318.577778-455.111111c22.755556-22.755556 17.066667-56.888889-11.377778-73.955555L489.244444 85.333333c-22.755556-17.066667-56.888889-11.377778-79.644444 11.377778l-318.577778 455.111111 96.711111 375.466667z" fill="#3970fe" p-id="15335" data-spm-anchor-id="a313x.7781069.0.i43" class="selected"></path><path d="M574.577778 745.244444c-56.888889 85.333333-176.355556 108.088889-261.688889 45.511112-85.333333-56.888889-108.088889-176.355556-45.511111-261.688889s176.355556-108.088889 261.688889-45.511111c85.333333 56.888889 102.4 176.355556 45.511111 261.688888z m-56.888889-39.822222c39.822222-56.888889 22.755556-130.844444-28.444445-170.666666s-130.844444-22.755556-170.666666 28.444444c-39.822222 56.888889-22.755556 130.844444 28.444444 170.666667s130.844444 22.755556 170.666667-28.444445z" fill="#3970fe" p-id="15336" data-spm-anchor-id="a313x.7781069.0.i44" class="selected"></path></svg></a><a class="hld__extra-icon" title="拉黑此用户(屏蔽所有言论)" data-type="ban" data-name="${currentName}" data-uid="${currentUid}"><svg t="1578452808565" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="9668" data-spm-anchor-id="a313x.7781069.0.i27" width="32" height="32"><path d="M512 1024A512 512 0 1 1 512 0a512 512 0 0 1 0 1024z m0-146.285714A365.714286 365.714286 0 1 0 512 146.285714a365.714286 365.714286 0 0 0 0 731.428572z" fill="#a20106" p-id="9669" data-spm-anchor-id="a313x.7781069.0.i28" class="selected"></path><path d="M828.708571 329.142857l-633.417142 365.714286 633.417142-365.714286z m63.341715-36.571428a73.142857 73.142857 0 0 1-26.770286 99.913142l-633.417143 365.714286a73.142857 73.142857 0 0 1-73.142857-126.683428l633.417143-365.714286A73.142857 73.142857 0 0 1 892.050286 292.571429z" fill="#a20106" p-id="9670" data-spm-anchor-id="a313x.7781069.0.i31" class="selected"></path></svg></a>`
  2318. script.setting.advanced.autoHideBanIcon ? $(this).after(`<span class="hld__extra-icon-box">${mbDom}</span>`) : $(this).append(mbDom)
  2319. })
  2320. // 标记DOm
  2321. $el.find('a.b').each(function () {
  2322. const uid = ($(this).attr('href') && $(this).attr('href').indexOf('uid=') > -1) ? $(this).attr('href').split('uid=')[1] + '' : ''
  2323. let name = ''
  2324. if ($(this).find('span.hld__post-author').length > 0 || $(this).find('span.hld__remark').length > 0) {
  2325. const $a = $(this).clone()
  2326. $a.find('span.hld__post-author, span.hld__remark').remove()
  2327. name = $a.text()
  2328. } else {
  2329. name = $(this).attr('hld-mark-before-name') || $(this).text().replace('[', '').replace(']', '')
  2330. }
  2331. const banUser = _this.getBanUser({name, uid})
  2332. if (banUser) {
  2333. //拉黑用户实现
  2334. if (script.setting.advanced.banStrictMode == 'HIDE') {
  2335. if ($(this).hasClass('author')) {
  2336. if ($(this).parents('div.comment_c').length > 0) {
  2337. $(this).parents('div.comment_c').find('.ubbcode').hide()
  2338. $(this).parents('div.comment_c').find('.ubbcode').after('<span class="hld__banned hld__banned-block">此用户在你的黑名单中,已屏蔽其言论,点击查看</span>')
  2339. } else {
  2340. $(this).parents('.forumbox.postbox').find('.c2 .postcontent').hide()
  2341. $(this).parents('.forumbox.postbox').find('.c2 .postcontent').after('<span class="hld__banned hld__banned-block">此用户在你的黑名单中,已屏蔽其言论,点击查看</span>')
  2342. }
  2343. } else {
  2344. if (!$(this).parent().is(':hidden')) {
  2345. $(this).parent().hide()
  2346. $(this).parent().after('<div class="quote"><span class="hld__banned hld__banned-block">此用户在你的黑名单中,已屏蔽其言论,点击查看</span></div>')
  2347. }
  2348. }
  2349. } else if (script.setting.advanced.banStrictMode == 'ALL') {
  2350. if ($(this).parents('div.comment_c').length > 0) $(this).parents('div.comment_c').remove()
  2351. else $(this).parents('.forumbox.postbox').remove()
  2352. } else {
  2353. if ($(this).hasClass('author')) {
  2354. if ($(this).parents('div.comment_c').length > 0) $(this).parents('div.comment_c').remove()
  2355. else $(this).parents('.forumbox.postbox').remove()
  2356. } else {
  2357. $(this).parent().html('<span class="hld__banned">此用户在你的黑名单中,已删除其言论</span>')
  2358. }
  2359. }
  2360. console.warn(`【NGA-Script-黑名单屏蔽】用户:${name}, UID:${uid}`)
  2361. }
  2362. if(script.setting.advanced.classicRemark) {
  2363. //经典备注风格
  2364. const userMarks = _this.getUserMarks({name, uid})
  2365. if (userMarks) {
  2366. let f = []
  2367. userMarks.marks.forEach(e => f.push(e.mark))
  2368. $(this).attr('hld-mark-before-name', name).append(`<span class="hld__remark"> (${f.join(', ')}) </span>`)
  2369. }
  2370. }else {
  2371. //新版标签风格
  2372. const userMarks = _this.getUserMarks({name, uid})
  2373. if(userMarks) {
  2374. const $el = $(this).parents('.c1').find('.clickextend')
  2375. let marksDom = ''
  2376. userMarks.marks.forEach(item => marksDom += `<span style="color: ${item.text_color};background-color: ${item.bg_color};" title="${item.mark}">${item.mark}</span>`);
  2377. $el.before(`<div class="hld__marks-container">标签: ${marksDom}</div>`)
  2378. }
  2379. }
  2380. })
  2381. }
  2382. },
  2383. /**
  2384. * 黑名单弹窗
  2385. * @method banlistPopup
  2386. * @param {Object} setting 设置项
  2387. * @param {String} setting.name 用户昵称
  2388. * @param {String} setting.uid UID
  2389. * @param {String} setting.type 模式
  2390. * @param {Number} setting.top pos.top位置
  2391. * @param {Number} setting.left pos.left 位置
  2392. * @param {Function} setting.callback 回调函数
  2393. */
  2394. banlistPopup: function (setting) {
  2395. const _this = this
  2396. $('.hld__dialog').length > 0 && $('.hld__dialog').remove()
  2397. const retainWord = [':', '(', ')', '&', '#', '^', ',']
  2398. let $banDialog = $(`<div class="hld__dialog hld__dialog-sub-top hld__list-panel animated zoomIn" style="top: ${setting.top}px;left: ${setting.left}px;"><a href="javascript:void(0)" class="hld__setting-close">×</a><div id="container_dom"></div><div class="hld__dialog-buttons"></div></div>`)
  2399. if (setting.type == 'confirm') {
  2400. $banDialog.find('#container_dom').append(`<div><span>您确定要拉黑用户</span><span class="hld__dialog-user">${setting.name}</span><span>吗?</span></div>`)
  2401. let $okBtn = $('<button class="hld__btn">拉黑</button>')
  2402. $okBtn.click(function(){
  2403. const banObj = {name: setting.name, uid: setting.uid}
  2404. !_this.getBanUser(banObj) && _this.banList.push(banObj)
  2405. window.localStorage.setItem('hld__NGA_ban_list', JSON.stringify(_this.banList))
  2406. $('.hld__dialog').remove()
  2407. script.popMsg('拉黑成功,重载页面生效')
  2408. })
  2409. $banDialog.find('.hld__dialog-buttons').append($okBtn)
  2410. }else if (setting.type == 'add') {
  2411. $banDialog.find('#container_dom').append(`<div>添加用户:</div><div><input id="hld__dialog_add_uid" type="text" value="" placeholder="UID"></div><div><input id="hld__dialog_add_name" type="text" value="" placeholder="用户名"></div>`)
  2412. let $okBtn = $('<button class="hld__btn">添加</button>')
  2413. $okBtn.click(function(){
  2414. const name = $banDialog.find('#hld__dialog_add_name').val().trim()
  2415. const uid = $banDialog.find('#hld__dialog_add_uid').val().trim() + ''
  2416. if (!name && !uid) {
  2417. script.popMsg('UID与用户名必填一个,其中UID权重较大', 'err')
  2418. return
  2419. }
  2420. !_this.getBanUser({name, uid}) && _this.banList.push({name, uid})
  2421. window.localStorage.setItem('hld__NGA_ban_list', JSON.stringify(_this.banList))
  2422. $('.hld__dialog').remove()
  2423. setting.callback()
  2424. })
  2425. $banDialog.find('.hld__dialog-buttons').append($okBtn)
  2426. }
  2427. $('body').append($banDialog)
  2428. },
  2429. /**
  2430. * 获取黑名单用户
  2431. * @method getBanUser
  2432. * @param {Object} banObj 黑名单对象
  2433. * @return {Object|null} 获取的用户对象
  2434. */
  2435. getBanUser: function (banObj) {
  2436. const _this = this
  2437. for (let u of _this.banList) {
  2438. if ((u.uid && banObj.uid && u.uid == banObj.uid) ||
  2439. (u.name && banObj.name && u.name == banObj.name)) {
  2440. if ((!u.uid && banObj.uid) || (!u.name && banObj.name)) {
  2441. u.uid = banObj.uid + '' || ''
  2442. u.name = banObj.name || ''
  2443. window.localStorage.setItem('hld__NGA_ban_list', JSON.stringify(banList))
  2444. }
  2445. return u
  2446. }
  2447. }
  2448. return null
  2449. },
  2450. /**
  2451. * 重新渲染黑名单列表
  2452. * @method reloadBanlist
  2453. */
  2454. reloadBanlist: function () {
  2455. const _this = this
  2456. $('#hld__banlist').empty()
  2457. _this.banList.forEach((item, index) => $('#hld__banlist').append(`<tr><td title="${item.name}">${item.name}</td><td title="${item.uid}">${item.uid}</td><td><span class="hld__us-action hld__us-del hld__bl-del" title="删除" data-index="${index}" data-name="${item.name}" data-uid="${item.uid}"></span></td></tr>`))
  2458. $('#hld__ban_list_textarea').val(JSON.stringify(_this.banList))
  2459. },
  2460. /**
  2461. * 重新渲染标签列表
  2462. * @method reloadMarklist
  2463. */
  2464. reloadMarklist: function () {
  2465. const _this = this
  2466. $('#hld__marklist').empty()
  2467. _this.markList.forEach((user_mark, index) => {
  2468. $('#hld__marklist').append(`<tr><td title="${user_mark.name}">${user_mark.name}</td><td title="${user_mark.uid}">${user_mark.uid}</td><td title="${user_mark.marks.length}">${user_mark.marks.length}</td><td><span class="hld__us-action hld__us-edit hld__ml-edit" title="编辑" data-index="${index}" data-name="${user_mark.name}" data-uid="${user_mark.uid}"></span><span class="hld__us-action hld__us-del hld__ml-del" title="删除" data-index="${index}" data-name="${user_mark.name}" data-uid="${user_mark.uid}"></span></td></tr>`)
  2469. })
  2470. $('#hld__mark_list_textarea').val(JSON.stringify(_this.markList))
  2471. },
  2472. /**
  2473. * 标记弹窗
  2474. * @method userMarkPopup
  2475. * @param {Object} setting 设置项
  2476. * @param {String} setting.name 用户名
  2477. * @param {String} setting.uid UID
  2478. * @param {String} setting.type 模式
  2479. * @param {Number} setting.top pos.top位置
  2480. * @param {Number} setting.left pos.left 位置
  2481. * @param {Function} setting.callback 回调函数
  2482. */
  2483. userMarkPopup: function (setting) {
  2484. const _this = this
  2485. $('.hld__dialog').length > 0 && $('.hld__dialog').remove()
  2486. const retain_word = [':', '(', ')', '&', '#', '^', ',']
  2487. let $markDialog = $(`<div class="hld__dialog hld__dialog-sub-top hld__list-panel animated zoomIn" style="top: ${setting.top}px;left: ${setting.left}px;">
  2488. <a href="javascript:void(0)" class="hld__setting-close">×</a>
  2489. ${setting.type == 'add' ? `<div style="display:block;">添加用户:<input id="hld__dialog_add_uid" type="text" value="" placeholder="UID"><input id="hld__dialog_add_name" type="text" value="" placeholder="用户名"></div>` : ''}
  2490. <table class="hld__dialog-mark-table">
  2491. <thead>
  2492. <tr>
  2493. <th width="100">标签</th><th width="50">文字</th><th width="50">背景</th><th>操作</th>
  2494. </tr>
  2495. </thead>
  2496. <tbody id="hld__mark_body"></tbody>
  2497. </table>
  2498. <div class="hld__dialog-buttons" style="justify-content: space-between !important;"></div>
  2499. </div>`)
  2500. const insertRemarkRow = (r='', t='#ffffff', b='#1f72f1', n=true) => {
  2501. let $tr = $(`<tr>
  2502. <td><input type="text" class="hld__mark-mark" value="${r}"></td>
  2503. <td><input class="hld__dialog-color-picker hld__mark-text-color" value="${t}"></td>
  2504. <td><input class="hld__dialog-color-picker hld__mark-bg-color" value="${b}"></td>
  2505. <td><button title="删除此标签" class="hld__mark-del">x</button></td>
  2506. </tr>`)
  2507. $tr.find('.hld__mark-del').click(function(){$(this).parents('tr').remove()})
  2508. $tr.find('.hld__dialog-color-picker').spectrum(script.getModule('authorMarkColor').colorPickerConfig)
  2509. $markDialog.find('#hld__mark_body').append($tr)
  2510. n && $tr.find('.hld__mark-mark').focus()
  2511. }
  2512.  
  2513. //恢复标签
  2514. const existMark = _this.getUserMarks({name: setting.name, uid: setting.uid})
  2515. existMark !== null && existMark.marks.forEach(item => insertRemarkRow(item.mark, item.text_color, item.bg_color, false))
  2516.  
  2517. let $addBtn = $('<button class="hld__btn">+添加标签</button>')
  2518. $addBtn.click(() => insertRemarkRow())
  2519. $markDialog.find('.hld__dialog-buttons').append($addBtn)
  2520. let $okBtn = $('<button class="hld__btn">保存</button>')
  2521.  
  2522. $okBtn.click(function(){
  2523. let userMarks = {marks: []}
  2524. if (setting.type == 'add') {
  2525. userMarks.name = $markDialog.find('#hld__dialog_add_name').val().trim()
  2526. userMarks.uid = $markDialog.find('#hld__dialog_add_uid').val().trim() + ''
  2527. } else {
  2528. userMarks.name = setting.name
  2529. userMarks.uid = setting.uid + ''
  2530. }
  2531. if (!userMarks.name && !userMarks.uid) {
  2532. script.popMsg('UID与用户名必填一个,其中UID权重较大', 'err')
  2533. return
  2534. }
  2535. $('#hld__mark_body > tr').each(function(){
  2536. const mark = $(this).find('.hld__mark-mark').val().trim()
  2537. const textColor = $(this).find('.hld__mark-text-color').val()
  2538. const bgColor = $(this).find('.hld__mark-bg-color').val()
  2539. if(mark) {
  2540. userMarks.marks.push({mark, text_color: textColor, bg_color: bgColor})
  2541. }
  2542. })
  2543. if (setting.type == 'add' && userMarks.marks.length == 0) {
  2544. script.popMsg('至少添加一个标签内容', 'err')
  2545. return
  2546. }
  2547. _this.setUserMarks(userMarks)
  2548. script.popMsg('保存成功,重载页面生效')
  2549. $('.hld__dialog').remove()
  2550. setting.callback()
  2551. })
  2552. $markDialog.find('.hld__dialog-buttons').append($okBtn)
  2553. $('body').append($markDialog)
  2554. $('.hld__dialog-color-picker').spectrum(script.getModule('authorMarkColor').colorPickerConfig)
  2555. },
  2556. /**
  2557. * 获取用户标签对象
  2558. * @method getUserMarks
  2559. * @param {String} uid UID
  2560. * @param {String} user 用户名
  2561. * @return {Object|null} 标签对象
  2562. */
  2563. getUserMarks: function (user) {
  2564. const _this = this
  2565. const check = _this.markList.findIndex(v => (v.uid && user.uid && v.uid == user.uid) ||
  2566. (v.name && user.name && v.name == user.name))
  2567. if(check > -1) {
  2568. let userMark = _this.markList[check]
  2569. if ((!userMark.uid && user.uid) || (!userMark.name && user.name)) {
  2570. userMark.uid = user.uid + '' || ''
  2571. userMark.name = user.name || ''
  2572. window.localStorage.setItem('hld__NGA_mark_list', JSON.stringify(_this.markList))
  2573. }
  2574. return _this.markList[check]
  2575. } else {
  2576. return null
  2577. }
  2578. },
  2579. /**
  2580. * 保存标签
  2581. * @method setUserMarks
  2582. * @param {Object} userMarks 标签对象
  2583. */
  2584. setUserMarks: function (userMarks) {
  2585. // 检查是否已有标签
  2586. const _this = this
  2587. const check = _this.markList.findIndex(v => (v.uid && userMarks.uid && v.uid == userMarks.uid) ||
  2588. (v.name && userMarks.name && v.name == userMarks.name))
  2589. if(check > -1) {
  2590. if (userMarks.marks.length == 0) {
  2591. _this.markList.splice(check, 1)
  2592. } else {
  2593. _this.markList[check] = userMarks
  2594. }
  2595. }else {
  2596. _this.markList.push(userMarks)
  2597. }
  2598. window.localStorage.setItem('hld__NGA_mark_list', JSON.stringify(_this.markList))
  2599. },
  2600. style: `
  2601. #hld__setting {color:#6666CC;cursor:pointer;}
  2602. .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;}
  2603. #hld__banlist_panel {width:500px;}
  2604. #hld__keywords_panel {width:182px;}
  2605. .hld__extra-icon-box {padding: 5px 5px 5px 0;opacity: 0;transition: all ease .2s;}
  2606. .hld__extra-icon-box:hover {opacity: 1;}
  2607. .hld__extra-icon {position: relative;padding:0 2px;background-repeat:no-repeat;background-position:center;}
  2608. .hld__extra-icon svg {width:10px;height:10px;vertical-align:-0.15em;fill:currentColor;overflow:hidden;cursor:pointer;}
  2609. .hld__extra-icon:hover {text-decoration:none;}
  2610. span.hld__remark {color:#666;font-size:0.8em;}
  2611. span.hld__banned {color:#ba2026;}
  2612. span.hld__banned-block:hover {text-decoration: underline;cursor: pointer;}
  2613. .hld__dialog{position:absolute;padding-right:35px}
  2614. .hld__dialog>div{line-height:30px}
  2615. .hld__dialog:before{position:absolute;content:' ';width:10px;height:10px;background-color:#fff6df;left:10px;transform:rotate(45deg)}
  2616. .hld__dialog-sub-top:before{top:-6px;border-top:1px solid #591804;border-left:1px solid #591804}
  2617. .hld__dialog-sub-bottom:before{bottom:-5px;border-bottom:1px solid #591804;border-right:1px solid #591804}
  2618. .hld__dialog-buttons{display:flex;justify-content:flex-end!important;margin-top:10px}
  2619. .hld__dialog-buttons>button{cursor:pointer}
  2620. .hld__dialog-user{font-size:1.5em;color:red;margin:0 5px}
  2621. .hld__dialog input[type=text]{width:100px;margin-right:15px}
  2622. .hld__dialog-mark-table td{padding-bottom:3px}
  2623. .hld__dialog-mark-table button{padding:0 6px;margin:0;height:20px;line-height:20px;width:20px;text-align:center;cursor:pointer}
  2624. .hld__tab-content {display:flex;justify-content:space-between;flex-wrap: wrap;}
  2625. .hld__table-keyword {margin-top:10px;width:200px;}
  2626. .hld__table-keyword tr td:last-child {text-align:center;}
  2627. .hld__table-keyword input[type=text] {width:48px;text-transform:uppercase;text-align:center;}
  2628. .hld__tab-header{height:40px}
  2629. .hld__tab-header>span{margin-right:10px;padding:5px;cursor:pointer}
  2630. .hld__tab-header .hld__table-active,.hld__tab-header>span:hover{color:#591804;font-weight:700;border-bottom:3px solid #591804}
  2631. .hld__tab-content{display:none}
  2632. .hld__tab-content.hld__table-active{display:flex}
  2633. .hld__marks-container>span{padding:1px 5px;border-radius:3px;margin-right:5px;color:#fff;background-color:#1f72f1}
  2634. .hld__table{table-layout:fixed;border-top:1px solid #ead5bc;border-left:1px solid #ead5bc}
  2635. .hld__table-banlist-buttons{margin-top:10px}
  2636. .hld__table thead{background:#591804;border:1px solid #591804;color:#fff}
  2637. .hld__scroll-area{position:relative;height:200px;overflow:auto;border:1px solid #ead5bc}
  2638. .hld__scroll-area::-webkit-scrollbar{width:6px;height:6px}
  2639. .hld__scroll-area::-webkit-scrollbar-thumb{border-radius:10px;box-shadow:inset 0 0 5px rgba(0,0,0,.2);background:#591804}
  2640. .hld__scroll-area::-webkit-scrollbar-track{box-shadow:inset 0 0 5px rgba(0,0,0,.2);border-radius:10px;background:#ededed}
  2641. .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}
  2642. .hld__us-action{display: inline-block;width:18px;height:18px;margin:0 3px;}
  2643. .hld__us-action:hover{opacity:.8}
  2644. .hld__us-edit{background-size:20px;background-image:url("data:image/svg+xml,%3Csvg t='1595910222437' class='icon' viewBox='0 0 1024 1024' version='1.1' xmlns='http://www.w3.org/2000/svg' p-id='3699'%3E%3Cpath d='M533.333333 106.666667v85.333333H213.333333v618.666667h618.666667V490.666667h85.333333v405.333333H128V106.666667h405.333333z m355.114667 97.237333L501.504 590.826667l-64.426667-64.426667L824.021333 139.498667l64.426667 64.426666z' p-id='3700'%3E%3C/path%3E%3C/svg%3E")}
  2645. .hld__us-del{background-image:url("data:image/svg+xml,%3Csvg t='1595910451854' class='icon' viewBox='0 0 1024 1024' version='1.1' xmlns='http://www.w3.org/2000/svg' p-id='4969'%3E%3Cpath d='M769.214785 190.785215V0h-511.488511v190.785215H2.365634v65.918082H1022.977023V190.785215h-253.762238zM320.959041 61.954046h384.383616v128.895105H320.959041V61.954046zM386.621379 382.593407h61.954046v446.593406h-61.954046V382.593407zM577.406593 382.593407H639.360639v446.593406h-61.954046V382.593407z' p-id='4970'%3E%3C/path%3E%3Cpath d='M832.191808 959.040959h-639.360639V318.657343h-63.936064v705.342657h767.616384V318.657343h-64.319681V959.040959z' p-id='4971'%3E%3C/path%3E%3C/svg%3E")}
  2646. `
  2647. }
  2648. /**
  2649. * 扩展坞模块
  2650. * @name extraDocker
  2651. * @description 此模块提供了一个悬浮的扩展坞,来添加某些功能
  2652. * 目前添加的功能有:
  2653. * 返回顶部:无跳转返回当前页面的第一页/刷新当页
  2654. * 跳转尾页:跳转到当前帖子的尾页
  2655. */
  2656. const extraDocker = {
  2657. settings: [{
  2658. shortCutCode: 84, // T
  2659. key: 'backTop',
  2660. title: '返回顶部'
  2661. }, {
  2662. shortCutCode: 66, // B
  2663. key: 'backBottom',
  2664. title: '跳转尾页'
  2665. }],
  2666. initFunc: function () {
  2667. const _this = this
  2668. const $dockerDom = $(`<div class="hld__docker"><div class="hld__docker-sidebar"><svg t="1603961015993" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3634" width="64" height="64"><path d="M518.344359 824.050365c-7.879285 0-15.758569-2.967523-21.693614-9.004897l-281.403018-281.403018c-5.730389-5.730389-9.004897-13.609673-9.004897-21.693614s3.274508-15.963226 9.004897-21.693614l281.403018-281.403018c11.972419-11.972419 31.41481-11.972419 43.387229 0 11.972419 11.972419 11.972419 31.41481 0 43.387229L280.32857 511.948836l259.709403 259.709403c11.972419 11.972419 11.972419 31.41481 0 43.387229C534.0006 821.082842 526.223643 824.050365 518.344359 824.050365z" p-id="3635" fill="#888888"></path><path d="M787.160987 772.88618c-7.879285 0-15.758569-2.967523-21.693614-9.004897l-230.238833-230.238833c-11.972419-11.972419-11.972419-31.41481 0-43.387229l230.238833-230.238833c11.972419-11.972419 31.41481-11.972419 43.387229 0 11.972419 11.972419 11.972419 31.41481 0 43.387229L600.309383 511.948836l208.545218 208.545218c11.972419 11.972419 11.972419 31.41481 0 43.387229C802.817228 769.918657 794.937943 772.88618 787.160987 772.88618z" p-id="3636" fill="#888888"></path></svg></div>
  2669. <div class="hld__docker-btns">
  2670. <div data-type="TOP" id="hld__jump_top"><svg t="1603962702679" title="返回顶部" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="9013" width="64" height="64"><path d="M528.73 161.5c-9.39-9.38-24.6-9.38-33.99 0L319.65 336.59a24.028 24.028 0 0 0-7.05 23.59A24.04 24.04 0 0 0 330 377.6c8.56 2.17 17.62-0.52 23.6-7.02l158.14-158.14 158.1 158.14a23.901 23.901 0 0 0 17 7.09c6.39 0 12.5-2.55 17-7.09 9.38-9.39 9.38-24.61 0-34L528.73 161.5zM63.89 607.09h102.79V869.5h48.04V607.09h102.79v-48.04H63.89v48.04z m518.69-48.05h-127.3c-15.37 0-30.75 5.85-42.49 17.59a59.846 59.846 0 0 0-17.59 42.49v190.3c0 15.37 5.89 30.75 17.59 42.49 11.74 11.74 27.12 17.59 42.49 17.59h127.3c15.37 0 30.75-5.85 42.49-17.59 11.7-11.74 17.59-27.12 17.59-42.49V619.17a59.903 59.903 0 0 0-17.53-42.55 59.912 59.912 0 0 0-42.55-17.54v-0.04z m12 250.38c0 2.31-0.6 5.59-3.5 8.54a11.785 11.785 0 0 1-8.5 3.5h-127.3c-3.2 0.02-6.26-1.26-8.5-3.54a11.785 11.785 0 0 1-3.5-8.5V619.17c0-2.31 0.6-5.59 3.5-8.54 2.24-2.27 5.31-3.53 8.5-3.5h127.3c2.27 0 5.55 0.64 8.5 3.55 2.27 2.24 3.53 5.31 3.5 8.5v190.29-0.05z m347.4-232.78a59.846 59.846 0 0 0-42.49-17.59H734.74V869.5h48.04V733.32h116.71a59.94 59.94 0 0 0 42.54-17.55 59.923 59.923 0 0 0 17.55-42.54v-54.07c0-15.37-5.85-30.74-17.59-42.49v-0.03z m-30.44 96.64c0 2.26-0.64 5.55-3.55 8.5a11.785 11.785 0 0 1-8.5 3.5H782.78v-78.15h116.71c2.27 0 5.59 0.6 8.54 3.5 2.27 2.24 3.53 5.31 3.5 8.5v54.15z m0 0" p-id="9014" fill="#591804"></path></svg></div>
  2671. <div data-type="BOTTOM" id="hld__jump_bottom"><svg t="1603962680160" title="跳转至最后一页" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7501" width="64" height="64"><path d="M792.855 465.806c-6.24-6.208-14.369-9.312-22.56-9.312s-16.447 3.169-22.688 9.44l-207.91 207.74v-565.28c0-17.697-14.336-32-32-32s-32.002 14.303-32.002 32v563.712l-206.24-206.164c-6.271-6.209-14.432-9.344-22.624-9.344-8.224 0-16.417 3.135-22.656 9.407-12.511 12.513-12.48 32.768 0.032 45.248L483.536 770.38c3.265 3.263 7.104 5.6 11.136 7.135 4 1.793 8.352 2.88 13.024 2.88 1.12 0 2.08-0.544 3.2-0.64 8.288 0.064 16.608-3.009 22.976-9.408l259.11-259.292c12.48-12.511 12.448-32.8-0.127-45.248z m99.706 409.725c0 17.665-14.303 32.001-31.999 32.001h-704c-17.665 0-32-14.334-32-31.999s14.335-32 32-32h704c17.696 0 32 14.334 32 31.998z" p-id="7502" fill="#591804"></path></svg></div></div></div>`)
  2672. $('body').append($dockerDom)
  2673. $('body').on('click', '.hld__docker-btns>div', function () {
  2674. const type = $(this).data('type')
  2675. if (type == 'TOP') {
  2676. const $nav_link = $('#m_nav a.nav_link')
  2677. if ($nav_link.length > 0) {
  2678. $nav_link[$nav_link.length-1].click()
  2679. }
  2680. }
  2681. if (type == 'BOTTOM') {
  2682. let queryset = _this.getQuerySet()
  2683. queryset.page = 9999
  2684. let search = ''
  2685. for (let key in queryset) {
  2686. search += `${search == '' ? '?' : '&'}${key}=${queryset[key]}`
  2687. }
  2688. window.location.href = `${window.location.origin}${window.location.pathname}${search}`
  2689. }
  2690. })
  2691. },
  2692. shortcutFunc: {
  2693. backTop: function () {
  2694. $('#hld__jump_top').click()
  2695. script.popNotification('返回顶部')
  2696. },
  2697. backBottom: function () {
  2698. $('#hld__jump_bottom').click()
  2699. script.popNotification('最后一页')
  2700. }
  2701. },
  2702. /**
  2703. * 获取URL参数对象
  2704. * @method getQuerySet
  2705. * @return {Object} 参数对象
  2706. */
  2707. getQuerySet: function () {
  2708. let queryList = {}
  2709. let url = decodeURI(window.location.search.replace(/&amp;/g, "&"))
  2710. url.startsWith('?') && (url = url.substring(1))
  2711. url.split('&').forEach(item => {
  2712. let t = item.split('=')
  2713. if (t[0] && t[1]) {
  2714. queryList[t[0]] = t[1]
  2715. }
  2716. })
  2717. return queryList
  2718. },
  2719. style: `
  2720. .hld__docker{position:fixed;height:80px;width:30px;bottom:135px;right:0;transition:all ease .2s}
  2721. .hld__docker:hover{width:150px;height:200px;bottom:80px}
  2722. .hld__docker-sidebar{background:#0f0;position:fixed;height:50px;width:20px;bottom:150px;right:0;display:flex;justify-content:center;align-items:center;background:#fff6df;border:1px solid #591804;box-shadow:0 0 5px #444;border-right:none;border-radius:5px 0 0 5px}
  2723. .hld__excel-body .hld__docker-sidebar{background:#fff;border:1px solid #bbb}
  2724. .hld__docker-btns{position:absolute;top:0;left:50px;bottom:0;right:50px;display:flex;justify-content:center;align-items:center;flex-direction:column}
  2725. .hld__docker .hld__docker-btns>div{opacity:0}
  2726. .hld__docker:hover .hld__docker-btns>div{opacity:1}
  2727. .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}
  2728. .hld__excel-body .hld__docker-btns>div{background:#fff;border:1px solid #bbb}
  2729. .hld__docker-btns svg{width:30px;height:30px;transition:all ease .2s}
  2730. .hld__docker-btns svg:hover{width:40px;height:40px}
  2731. .hld__excel-body .hld__docker-sidebar{background:#fff;border:1px solid #bbb}
  2732. .hld__excel-body .hld__docker-btns>div{background:#fff;border:1px solid #bbb}
  2733. `
  2734. }
  2735. /* 插件 */
  2736. // ......
  2737.  
  2738. /**
  2739. * 初始化脚本
  2740. */
  2741. const script = new NGABBSScript()
  2742. /**
  2743. * 添加模块
  2744. */
  2745. script.addModule(defaultStyle)
  2746. script.addModule(settingPanel)
  2747. script.addModule(shortCutKeys)
  2748. script.addModule(backupModule)
  2749. script.addModule(rewardPanel)
  2750. script.addModule(dynamicEnable)
  2751. script.addModule(hideAvatar)
  2752. script.addModule(hideSmile)
  2753. script.addModule(hideImage)
  2754. script.addModule(imgResize)
  2755. script.addModule(hideSign)
  2756. script.addModule(hideHeader)
  2757. script.addModule(excelMode)
  2758. script.addModule(excelTitle)
  2759. script.addModule(foldQuote)
  2760. script.addModule(linkTargetBlank)
  2761. script.addModule(imgEnhance)
  2762. script.addModule(authorMark)
  2763. script.addModule(authorMarkColor)
  2764. script.addModule(autoPage)
  2765. script.addModule(keywordsBlock)
  2766. script.addModule(markAndBan)
  2767. script.addModule(extraDocker)
  2768. /**
  2769. * 运行脚本
  2770. */
  2771. script.run()
  2772. })();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址