beautifier

自定义页面背景图,布局优化

当前为 2022-08-27 提交的版本,查看 最新版本

此脚本不应直接安装。它是供其他脚本使用的外部库,要使用该库请加入元指令 // @require https://update.cn-greasyfork.org/scripts/450211/1086400/beautifier.js

  1. /* eslint-disable no-multi-spaces */
  2. /* eslint-disable no-implicit-globals */
  3. /* eslint-disable userscripts/no-invalid-headers */
  4. /* eslint-disable userscripts/no-invalid-grant */
  5.  
  6. // ==UserScript==
  7. // @name beautifier
  8. // @displayname 页面美化
  9. // @namespace Wenku8++
  10. // @version 0.2.3
  11. // @description 自定义页面背景图,布局优化
  12. // @author PY-DNG
  13. // @license GPL-v3
  14. // @regurl https?://www\.wenku8\.net/.*
  15. // @require https://greasyfork.org/scripts/449412-basic-functions/code/Basic%20Functions.js?version=1085783
  16. // @require https://greasyfork.org/scripts/449583-configmanager/code/ConfigManager.js?version=1085902
  17. // @grant GM_getValue
  18. // @grant GM_setValue
  19. // @grant GM_listValues
  20. // @grant GM_deleteValue
  21. // ==/UserScript==
  22.  
  23. (function __MAIN__() {
  24. const alertify = require('alertify');
  25. const settings = require('settings');
  26. const SettingPanel = require('SettingPanel');
  27.  
  28. const CONST = {
  29. Text: {
  30. CommonBeautify: '通用页面美化',
  31. NovelBeautify: '阅读页面美化',
  32. ReviewBeautify: '书评页面美化',
  33. Enable: '启用',
  34. BackgroundImage: '背景图片',
  35. AlertTitle: '页面美化设置',
  36. InvalidImageUrl: '图片链接格式错误</br>仅仅接受http/https/data链接',
  37. },
  38. ClassName: {
  39. BgImage: 'plus_cbty_image',
  40. BgCover: 'plus_cbty_cover',
  41. CSS: 'plus_beautifier'
  42. },
  43. CSS: {
  44. Common: '.plus_cbty_image {position: fixed;top: 0;left: 0;z-index: -2;}.plus_cbty_cover {position: fixed;top: 0;left: calc((100vw - 960px) / 2);z-Index: -1;background-color: rgba(255,255,255,0.7);width: 960px;height: 100vh;}body {overflow: auto;}body>.main {position: relative;margin-left: 0;margin-right: 0;left: calc((100vw - 960px) / 2);}body.plus_cbty table.grid td, body.plus_cbty .odd, body.plus_cbty .even, body.plus_cbty .blockcontent {background-color: rgba(255,255,255,0) !important;}.textarea, .text {background-color: rgba(255,255,255,0.9);}#headlink{background-color: rgba(255,255,255,0.7);}',
  45. Novel: 'html{background-image: url({BGI});}body {width: 100vw;height: 100vh;overflow: overlay;margin: 0px;background-color: rgba(255,255,255,0.7);}#contentmain {overflow-y: auto;height: calc(100vh - {H});max-width: 100%;min-width: 0px;max-width: 100vw;}#adv1, #adtop, #headlink, #footlink, #adbottom {overflow: overlay;min-width: 0px;max-width: 100vw;}#adv900, #adv5 {max-width: 100vw;}'
  46. },
  47. Config_Ruleset: {
  48. 'version-key': 'config-version',
  49. 'ignores': ["LOCAL-CDN"],
  50. 'defaultValues': {
  51. //'config-key': {},
  52. common: {
  53. enable: false,
  54. image: null
  55. },
  56. novel: {
  57. enable: false,
  58. image: null
  59. },
  60. review: {
  61. enable: false,
  62. image: null
  63. },
  64. image: null
  65. },
  66. 'updaters': {
  67. /*'config-key': [
  68. function() {
  69. // This function contains updater for config['config-key'] from v0 to v1
  70. },
  71. function() {
  72. // This function contains updater for config['config-key'] from v1 to v2
  73. }
  74. ]*/
  75. }
  76. }
  77. };
  78.  
  79. const CM = new ConfigManager(CONST.Config_Ruleset);
  80. const CONFIG = CM.Config;
  81. CM.setDefaults();
  82. const API = getAPI();
  83. switch (API[0]) {
  84. case 'novel':
  85. [...API].pop() !== 'index.htm' && CONFIG.novel.enable && novel();
  86. break;
  87. default:
  88. CONFIG.common.enable && common();
  89. }
  90. settings.registerSettings(MODULE_IDENTIFIER, setter);
  91.  
  92. exports = {
  93. //
  94. };
  95.  
  96. // Beautifier for all wenku pages
  97. function common() {
  98. const src = CONFIG.common.image || CONFIG.image;
  99.  
  100. const img = $CrE('img');
  101. img.src = src;
  102. img.classList.add(CONST.ClassName.BgImage);
  103. document.body.appendChild(img);
  104.  
  105. const cover = $CrE('div');
  106. cover.classList.add(CONST.ClassName.BgCover);
  107. document.body.appendChild(cover);
  108.  
  109. document.body.classList.add('plus_cbty');
  110. addStyle(CONST.CSS.Common, CONST.ClassName.CSS);
  111. return true;
  112. }
  113.  
  114. // Novel reading page
  115. function novel() {
  116. const src = CONFIG.novel.image || CONFIG.image;
  117. const config = CONFIG.BeautifierCfg.getConfig();
  118. const usedHeight = getRestHeight();
  119.  
  120. addStyle(CONST.CSS.Novel
  121. .replaceAll('{BGI}', src)
  122. .replaceAll('{H}', usedHeight), CONST.ClassName.CSS
  123. );
  124.  
  125. unsafeWindow.scrolling = beautiful_scrolling;
  126.  
  127. // Get rest height without #contentmain
  128. function getRestHeight() {
  129. let usedHeight = 0;
  130. ['adv1', 'adtop', 'headlink', 'footlink', 'adbottom'].forEach((id) => {
  131. const node = $('#'+id);
  132. if (node instanceof Element && node.id !== 'contentmain') {
  133. const cs = getComputedStyle(node);
  134. ['height', 'marginTop', 'marginBottom', 'paddingTop', 'paddingBottom', 'borderTop', 'borderBottom'].forEach((style) => {
  135. const reg = cs[style].match(/([\.\d]+)px/);
  136. reg && (usedHeight += Number(reg[1]));
  137. });
  138. };
  139. });
  140. usedHeight = usedHeight.toString() + 'px';
  141. return usedHeight;
  142. }
  143.  
  144. // Mouse dblclick scroll with beautifier applied
  145. function beautiful_scrolling() {
  146. var contentmain = pageResource.elements.contentmain;
  147. var currentpos = contentmain.scrollTop || 0;
  148. contentmain.scrollTo(0, ++currentpos);
  149. var nowpos = contentmain.scrollTop || 0;
  150. if(currentpos != nowpos) unsafeWindow.clearInterval(timer);
  151. }
  152. }
  153.  
  154. // Settings
  155. function setter() {
  156. const storage = {
  157. GM_getValue: GM_getValue,
  158. GM_setValue: GM_setValue,
  159. GM_listValues: GM_listValues,
  160. GM_deleteValue: GM_deleteValue
  161. };
  162. const Panel = SettingPanel.SettingPanel;
  163. const Option = SettingPanel.SettingOption.bind(null, storage);
  164. const SetPanel = new Panel({
  165. tables: [{
  166. rows: [{
  167. blocks: [{
  168. isHeader: true,
  169. colSpan: 2,
  170. innerText: CONST.Text.CommonBeautify
  171. }]
  172. },{
  173. blocks: [{
  174. innerText: CONST.Text.Enable
  175. },{
  176. options: [new Option({
  177. path: 'common/enable',
  178. type: 'boolean'
  179. })]
  180. }]
  181. },{
  182. blocks: [{
  183. innerText: CONST.Text.BackgroundImage
  184. },{
  185. options: [new Option({
  186. path: 'common/image',
  187. type: 'string',
  188. checker: imageUrlChecker,
  189. })]
  190. }]
  191. }]
  192. },{
  193. rows: [{
  194. blocks: [{
  195. isHeader: true,
  196. colSpan: 2,
  197. innerText: CONST.Text.NovelBeautify
  198. }]
  199. },{
  200. blocks: [{
  201. innerText: CONST.Text.Enable
  202. },{
  203. options: [new Option({
  204. path: 'novel/enable',
  205. type: 'boolean'
  206. })]
  207. }]
  208. },{
  209. blocks: [{
  210. innerText: CONST.Text.BackgroundImage
  211. },{
  212. options: [new Option({
  213. path: 'novel/image',
  214. type: 'string',
  215. checker: imageUrlChecker,
  216. })]
  217. }]
  218. }]
  219. },{
  220. rows: [{
  221. blocks: [{
  222. isHeader: true,
  223. colSpan: 2,
  224. innerText: CONST.Text.ReviewBeautify
  225. }]
  226. },{
  227. blocks: [{
  228. innerText: CONST.Text.Enable
  229. },{
  230. options: [new Option({
  231. path: 'review/enable',
  232. type: 'boolean'
  233. })]
  234. }]
  235. },{
  236. blocks: [{
  237. innerText: CONST.Text.BackgroundImage
  238. },{
  239. options: [new Option({
  240. path: 'review/image',
  241. type: 'string',
  242. checker: imageUrlChecker,
  243. })]
  244. }]
  245. }]
  246. }]
  247. });
  248.  
  249. function imageUrlChecker(e, value) {
  250. if (!value.match(/.+:/)) {
  251. alertify.alert(CONST.Text.AlertTitle, CONST.Text.InvalidImageUrl);
  252. return false;
  253. }
  254. e.target.value = value || null;
  255. return true;
  256. }
  257. }
  258. })();