代码片段语法高亮 + 不要翻译页面上的代码

使用 highlight.js 给代码片断添加语法高亮, 并设置更优雅的字体.查看codepen原型快速了解: https://codepen.io/FloatingShuYin/pen/GRRjmOE?editors=0010 不要翻译页面上的代码请参考:https://gf.qytechs.cn/zh-CN/scripts/376658-%E4%B8%8D%E8%A6%81%E7%BF%BB%E8%AF%91github%E4%B8%8A%E7%9A%84%E4%BB%A3%E7%A0%81

  1. // ==UserScript==
  2. // @name 代码片段语法高亮 + 不要翻译页面上的代码
  3. // @namespace https://floatsyi.com/
  4. // @version 0.3.1
  5. // @description 使用 highlight.js 给代码片断添加语法高亮, 并设置更优雅的字体.查看codepen原型快速了解: https://codepen.io/FloatingShuYin/pen/GRRjmOE?editors=0010 不要翻译页面上的代码请参考:https://gf.qytechs.cn/zh-CN/scripts/376658-%E4%B8%8D%E8%A6%81%E7%BF%BB%E8%AF%91github%E4%B8%8A%E7%9A%84%E4%BB%A3%E7%A0%81
  6. // @author floatsyi
  7. // @license MIT
  8. // @require https://cdn.bootcss.com/highlight.js/9.15.10/highlight.min.js
  9. // @require https://cdn.bootcss.com/fontfaceobserver/2.1.0/fontfaceobserver.js
  10. // @require https://unpkg.com/vue@2.6.10/dist/vue.min.js
  11. // @require https://unpkg.com/buefy/dist/buefy.min.js
  12. // @match *://*/*
  13. // @grant GM_addStyle
  14. // @grant GM_deleteValue
  15. // @grant GM_setValue
  16. // @grant GM_getValue
  17. // @grant GM_listValues
  18. // @grant GM_addValueChangeListener
  19. // @grant unsafeWindow
  20. // @grant GM_registerMenuCommand
  21. // ==/UserScript==
  22. // https://www.bootcdn.cn/highlight.js/
  23. // 当前版本号
  24. // FIXME
  25. const currentVersion = '0.3.1'
  26. // debug log
  27. const isDev = false
  28. const log = (...any) => {if (isDev) { console.log(...any) }}
  29. log('GM_listValues', GM_listValues())
  30. // thmem 和 font 列表
  31. // https://highlightjs.org/static/demo/
  32. // ;[...document.querySelectorAll('#styles > li')].map(item =>item.innerText.toLocaleLowerCase().replace(/\s/g, '-').replace(/(-)?(\d+)(-)?/g,'$2').replace(/(qtcreator)(-)(dark|light)/, '$1_$3').replace(/(kimbie)(-)(dark|light)/,'$1.$2'))
  33. const themes = [
  34. 'default',
  35. 'a11y-dark',
  36. 'a11y-light',
  37. 'agate',
  38. 'an-old-hope',
  39. 'androidstudio',
  40. 'arduino-light',
  41. 'arta',
  42. 'ascetic',
  43. 'atelier-cave-dark',
  44. 'atelier-cave-light',
  45. 'atelier-dune-dark',
  46. 'atelier-dune-light',
  47. 'atelier-estuary-dark',
  48. 'atelier-estuary-light',
  49. 'atelier-forest-dark',
  50. 'atelier-forest-light',
  51. 'atelier-heath-dark',
  52. 'atelier-heath-light',
  53. 'atelier-lakeside-dark',
  54. 'atelier-lakeside-light',
  55. 'atelier-plateau-dark',
  56. 'atelier-plateau-light',
  57. 'atelier-savanna-dark',
  58. 'atelier-savanna-light',
  59. 'atelier-seaside-dark',
  60. 'atelier-seaside-light',
  61. 'atelier-sulphurpool-dark',
  62. 'atelier-sulphurpool-light',
  63. 'atom-one-dark-reasonable',
  64. 'atom-one-dark',
  65. 'atom-one-light',
  66. 'brown-paper',
  67. 'codepen-embed',
  68. 'color-brewer',
  69. 'darcula',
  70. 'dark',
  71. 'darkula',
  72. 'docco',
  73. 'dracula',
  74. 'far',
  75. 'foundation',
  76. 'github-gist',
  77. 'github',
  78. 'gml',
  79. 'googlecode',
  80. 'grayscale',
  81. 'gruvbox-dark',
  82. 'gruvbox-light',
  83. 'hopscotch',
  84. 'hybrid',
  85. 'idea',
  86. 'ir-black',
  87. 'isbl-editor-dark',
  88. 'isbl-editor-light',
  89. 'kimbie.dark',
  90. 'kimbie.light',
  91. 'lightfair',
  92. 'magula',
  93. 'mono-blue',
  94. 'monokai-sublime',
  95. 'monokai',
  96. 'nord',
  97. 'obsidian',
  98. 'ocean',
  99. 'paraiso-dark',
  100. 'paraiso-light',
  101. 'pojoaque',
  102. 'purebasic',
  103. 'qtcreator_dark',
  104. 'qtcreator_light',
  105. 'railscasts',
  106. 'rainbow',
  107. 'routeros',
  108. 'school-book',
  109. 'shades-of-purple',
  110. 'solarized-dark',
  111. 'solarized-light',
  112. 'sunburst',
  113. 'tomorrow-night-blue',
  114. 'tomorrow-night-bright',
  115. 'tomorrow-night-eighties',
  116. 'tomorrow-night',
  117. 'tomorrow',
  118. 'vs',
  119. 'vs2015',
  120. 'xcode',
  121. 'xt256',
  122. 'zenburn'
  123. ]
  124. // google Monospace fonts: https://fonts.google.com/?sort=date&category=Monospace
  125. // ;[...document.querySelectorAll('.fonts-module-title')].map(item => item.innerText)
  126. const fonts = [
  127. 'Fira Code',
  128. 'B612 Mono',
  129. 'Major Mono Display',
  130. 'IBM Plex Mono',
  131. 'Nanum Gothic Coding',
  132. 'Overpass Mono',
  133. 'Space Mono',
  134. 'Roboto Mono',
  135. 'Fira Mono',
  136. 'Share Tech Mono',
  137. 'Cutive Mono',
  138. 'Source Code Pro'
  139. ]
  140.  
  141. const shouldClearCacheKeys = ['bulmaStyle']
  142.  
  143. const hash = '662eb72f' // fnv132('Syntax_highlighting')
  144. const hashString = str => `${str}-${hash}`
  145. const getCacheValue = key => GM_getValue(hashString(key))
  146. const setCacheValue = (key, value) => GM_setValue(hashString(key), value)
  147. const deleteCacheValue = key => GM_deleteValue(hashString(key))
  148. const hasCacheValue = key => !!GM_getValue(hashString(key))
  149.  
  150. // 默认字体与主题
  151. const defaultTheme = 'atom-one-dark'
  152. const defaultFont = 'Fira Code'
  153.  
  154. let currentTheme = getCacheValue('currentTheme') || defaultTheme
  155. let currentFont = getCacheValue('currentFont') || defaultFont
  156.  
  157. // hashString
  158. const hashVersion = hashString('version')
  159.  
  160. const clearCache = () => {
  161. for (const key of [...themes, ...fonts, ...shouldClearCacheKeys]) {
  162. deleteCacheValue(key)
  163. }
  164. }
  165.  
  166. // 如果是新版本就清除缓存
  167. GM_addValueChangeListener(hashVersion, function (
  168. name,
  169. old_value,
  170. new_value,
  171. remote
  172. ) {
  173. if (old_value !== new_value) {
  174. clearCache()
  175. // TODO 清除之前 0.1.2 版本的废弃缓存
  176. ;['Fira Code', 'atom-one-dark', 'bulmaStyle'].forEach(key => {GM_deleteValue(key)})
  177. // TODO 清除 0.2.2 版本的废弃缓存
  178. deleteCacheValue('isForcePreBackgroundColors')
  179. }
  180. })
  181.  
  182. // 保存当前版本号, 触发监听
  183. GM_setValue(hashVersion, currentVersion)
  184.  
  185. // 避免 google 网页翻译当前页面的代码
  186. const hasCodeEleChild = ele => !!ele.querySelector('code')
  187.  
  188. function addCodeEle (ele) {
  189. ele.innerHTML = '<code class="doNotTranslate">' + ele.innerHTML + '</code>'
  190. }
  191.  
  192. function doNotTranslateCode () {
  193. const pres = document.querySelectorAll('pre')
  194. pres.forEach(function (pre) {
  195. if (!hasCodeEleChild(pre)) addCodeEle(pre)
  196. })
  197. }
  198.  
  199. const _ = {}
  200. _.debounce = function (func, wait) {
  201. var lastCallTime
  202. var lastThis
  203. var lastArgs
  204. var timerId
  205.  
  206. function startTimer (timerExpired, wait) {
  207. return setTimeout(timerExpired, wait)
  208. }
  209.  
  210. function remainingWait (time) {
  211. const timeSinceLastCall = time - lastCallTime
  212. const timeWaiting = wait - timeSinceLastCall
  213. return timeWaiting
  214. }
  215.  
  216. function shoudInvoking (time) {
  217. return lastCallTime !== undefined && time - lastCallTime >= wait
  218. }
  219.  
  220. function timerExpired () {
  221. const time = Date.now()
  222. if (shoudInvoking(time)) {
  223. return invokeFunc()
  224. }
  225. timerId = startTimer(timerExpired, remainingWait(time))
  226. }
  227.  
  228. function invokeFunc () {
  229. timerId = undefined
  230. const args = lastArgs
  231. const thisArg = lastThis
  232. let result = func.apply(thisArg, args)
  233. lastArgs = lastThis = undefined
  234. return result
  235. }
  236.  
  237. function debounced (...args) {
  238. let time = Date.now()
  239. lastThis = this
  240. lastArgs = args
  241. lastCallTime = time
  242. if (timerId === undefined) {
  243. timerId = startTimer(timerExpired, wait)
  244. }
  245. }
  246.  
  247. return debounced
  248. }
  249. const body = document.body
  250. const option = {
  251. childList: true,
  252. subtree: true
  253. }
  254.  
  255. let time = 0
  256.  
  257. function doNotTranslate (mutations, observer) {
  258. // 处于过于频繁的 DOM 变更时, 暂停监听 50ms, 并放弃累积的未处理的变更事件
  259. if (time >= 20) {
  260. observer.disconnect()
  261. observer.takeRecords()
  262. time = 0
  263. setTimeout(function () {
  264. mo.observe(body, option)
  265. }, 50)
  266. }
  267.  
  268. doNotTranslateCode()
  269.  
  270. time++
  271. log(`第${time}次执行: doNotTranslate`)
  272. }
  273.  
  274. const MutationObserver =
  275. window.MutationObserver ||
  276. window.WebKitMutationObserver ||
  277. window.MozMutationObserver
  278.  
  279. const mo = new MutationObserver(_.debounce(doNotTranslate, 50))
  280.  
  281. const currentHostName = [window.location.host]
  282. let hostNames = getCacheValue('hostNames')
  283.  
  284. if (!hostNames) {
  285. setCacheValue('hostNames', ['www.npmjs.com'])
  286. } else {
  287. if (hostNames.includes(...currentHostName)){
  288. doNotTranslateCode()
  289. mo.observe(body, option)
  290. }
  291. }
  292. // 注册(不可用)设置页
  293. GM_registerMenuCommand('不要翻译这个页面的代码', () => {
  294. hostNames = getCacheValue('hostNames')
  295. if (hostNames.includes(...currentHostName)) return false
  296. doNotTranslateCode()
  297. mo.observe(body, option)
  298. const newhostNames= [...currentHostName, ...hostNames]
  299. setCacheValue('hostNames', newhostNames)
  300. }, 'D')
  301.  
  302. // 环境探测
  303. const envDetection = [
  304. unsafeWindow.Prism,
  305. unsafeWindow.hljs,
  306. unsafeWindow.prettyPrint
  307. ]
  308. if (envDetection.some(item => !!item)) return false
  309. const fontSize = getCacheValue('fontSize') || 16
  310. const isApplyThemeChanges = getCacheValue('isApplyThemeChanges') || 'Yes'
  311. const isApplyFontChanges = getCacheValue('isApplyFontChanges') || 'Yes'
  312. const isGFW = getCacheValue('isGFW') || 'Fuck'
  313. const isForcePreBackground =
  314. getCacheValue('isForcePreBackground') || 'Yes'
  315.  
  316. const getCurrentThemeBackground = styleText =>
  317. styleText.match(/background:(.*?)[;}]/)[1]
  318.  
  319. // 轮询
  320. const poll = ({
  321. condition,
  322. resolve,
  323. reject = () => {},
  324. millisecond = 1000,
  325. retries = 1
  326. }) => {
  327. if (condition()) return resolve()
  328.  
  329. let time = 0
  330. const int = setInterval(() => {
  331. time++
  332. if (condition()) {
  333. clearInterval(int)
  334. return resolve()
  335. } else if (time > retries) {
  336. clearInterval(int)
  337. return reject()
  338. }
  339. }, millisecond)
  340. const stop = () => {
  341. clearInterval(int)
  342. }
  343. return stop
  344. }
  345.  
  346. const fetchStyleText = url =>
  347. fetch(url, {
  348. headers: {
  349. 'Content-Type': 'text/plain'
  350. }
  351. }).then(response => {
  352. return response.text()
  353. })
  354.  
  355. // 获取并设置样式
  356. const setStyle = () => {
  357. // 获取主题样式并添加
  358. const themeStyle = getCacheValue(currentTheme)
  359.  
  360. if (themeStyle) {
  361. GM_addStyle(themeStyle)
  362. } else {
  363. const themeUrl =
  364. this.GFW === 'Fuck'
  365. ? `https://cdn.bootcss.com/highlight.js/9.15.10/styles/${currentTheme}.min.css`
  366. : `https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.15.10/styles/${currentTheme}.min.css`
  367. fetchStyleText(themeUrl).then(style => {
  368. GM_addStyle(style)
  369. setCacheValue(currentTheme, style)
  370. })
  371. }
  372.  
  373. // 获取字体样式并添加
  374. const fontStyle = getCacheValue(currentFont)
  375. if (fontStyle) {
  376. GM_addStyle(fontStyle)
  377. } else {
  378. const fontUrl = isGFW
  379. ? `https://fonts.loli.net/css?family=${currentFont}&display=swap`
  380. : `https://fonts.googleapis.com/css?family=${currentFont}&display=swap`
  381.  
  382. fetchStyleText(fontUrl).then(style => {
  383. GM_addStyle(style)
  384. setCacheValue(currentFont, style)
  385. })
  386. }
  387. }
  388.  
  389. // 为 code 片断应用 highlightBlock 并设置字体样式
  390. const beautify = () => {
  391. setStyle()
  392.  
  393. const font = new window.FontFaceObserver(currentFont)
  394. font.load().then(
  395. () => {
  396. log('Font is available')
  397. for (const pre of Array.from(document.querySelectorAll('pre'))) {
  398. const code = pre.querySelector('code')
  399. if (isApplyThemeChanges && code) {
  400. code.classList.remove('language-text')
  401. window.hljs.highlightBlock(code)
  402. }
  403. if (isApplyFontChanges === 'Yes' && code) {
  404. code.style.fontFamily = currentFont
  405. code.style.fontSize = `${fontSize}px`
  406. }
  407. if (isForcePreBackground === 'Yes') {
  408. pre.style.background = getCurrentThemeBackground(
  409. getCacheValue(currentTheme)
  410. )
  411. }
  412. }
  413. },
  414. () => {
  415. log('Font is not available')
  416. }
  417. )
  418. }
  419.  
  420. // 设置页
  421. let parasitifer = null
  422. const openSetting = () => {
  423. // 非首次调用
  424. if (parasitifer) {
  425. parasitifer.show()
  426. return true
  427. }
  428.  
  429. parasitifer = document.createElement('div') // 此 DOM 节点将用作 shadowDOM 的载体被插入宿主的 DOM 节点中.
  430. parasitifer.id = 'host-element'
  431. parasitifer.style = `position: fixed;top:0;bottom:0;z-index:9999;width:100vw;height:100vh;font-size:16px;background-color:#fff;`
  432. parasitifer.show = () => {
  433. parasitifer.style.display = 'block'
  434. }
  435. parasitifer.hide = () => {
  436. parasitifer.style.display = 'none'
  437. }
  438.  
  439. const shadowRoot = parasitifer.attachShadow({ mode: 'open' })
  440. // 此节点将成为 shadowDOM 的直接子元素, 包裹一切, 所以用 HTML 元素很合适.
  441. // 不仅仅是语义上的合适, 大多数的 UI 库都需要一个结构完整的 DOM 树用来做自适应布局.
  442. const shadowContent = document.createElement('HTML')
  443. const shadowStyleEle = document.createElement('style')
  444. const bulmaStyleEle = document.createElement('style')
  445. const fontStyleEle = document.createElement('style')
  446. const themeStyleEle = document.createElement('style')
  447. const vueContainer = document.createElement('div') // 这个 DOM 节点不会显示在 DOM 树中, 而是作为 vue 的挂载点,同来渲染 vue 的模板.
  448. vueContainer.id = 'vue-root'
  449. // shadow DOM 的样式作用域隔离是非常实用的特性, 完全不受宿主环境影响的样式, 轻盈的开始
  450. shadowStyleEle.innerText = ``
  451. shadowContent.appendChild(shadowStyleEle)
  452. shadowContent.appendChild(bulmaStyleEle)
  453. shadowContent.appendChild(fontStyleEle)
  454. shadowContent.appendChild(themeStyleEle)
  455. shadowContent.appendChild(vueContainer)
  456. shadowRoot.appendChild(shadowContent)
  457. document.body.appendChild(parasitifer)
  458.  
  459. const mount = style => {
  460. bulmaStyleEle.innerText = style
  461.  
  462. const vueRoot = document
  463. .querySelector('#host-element')
  464. .shadowRoot.querySelector('#vue-root')
  465. // 这里使用 body 元素 作为父节点, 结合上面创造的 HTML 元素是为了给 UI 组件一个完整的上下文环境, 就像在一个新的 HTML 页面中一样.
  466. const vueTemplate = `<body style="height: 100vh">
  467. <div id="app-vue" class="container">
  468. <div class="columns is-vcentered is-centered">
  469. <div class="column is-3">
  470. <section>
  471. <b-field label="Themes">
  472. <b-select placeholder="Select a name" @input="changeTheme" v-model="current.theme" rounded>
  473. <option v-for="(item, index) in themes" :value="item" :key="index">
  474. {{item}}
  475. </option>
  476. </b-select>
  477. </b-field>
  478. <b-field label="Monospace Fonts">
  479. <b-select placeholder="Select a name" @input="changeFont" v-model="current.font" rounded>
  480. <option v-for="(item, index) in fonts" :value="item" :key="index">
  481. {{item}}
  482. </option>
  483. </b-select>
  484. </b-field>
  485. <b-field label="Font Size">
  486. <b-slider v-model="fontSize" @input="changeFontSize"></b-slider>
  487. </b-field>
  488. <b-field label="Apply theme changes">
  489. <b-switch v-model="isApplyThemeChanges" true-value="Yes" false-value="No">
  490. {{ isApplyThemeChanges }}
  491. </b-switch>
  492. </b-field>
  493. <b-field label="Apply font changes">
  494. <b-switch v-model="isApplyFontChanges" true-value="Yes" false-value="No">
  495. {{ isApplyFontChanges }}
  496. </b-switch>
  497. </b-field>
  498. <b-field label="Force theme background colors">
  499. <b-switch v-model="isForcePreBackground" true-value="Yes" false-value="No">
  500. {{ isForcePreBackground }}
  501. </b-switch>
  502. </b-field>
  503. <b-field label="铁幕重重困青年">
  504. <b-switch v-model="isGFW" true-value="Fuck" false-value="No thank you">
  505. {{ isGFW }}
  506. </b-switch>
  507. </b-field>
  508. </section>
  509. <section style="margin-top:30px;">
  510. <b-button type="is-primary" rounded @click="apply">Apply</b-button>
  511. <b-button type="is-warning" rounded @click="close">Close</b-button>
  512. <b-button type="is-danger" rounded @click="reset">Reset</b-button>
  513. </section>
  514. </div>
  515. <div class="column">
  516. <section style="overflow:hidden;">
  517. <h1 class="has-text-centered">Real-time preview</h1>
  518. <pre class="has-text-left" :style="styles.pre" ref="pre">
  519. <code :style="styles.code" ref="code">
  520. import something from 'something'
  521.  
  522. // 获取并设置样式
  523. const setStyle = () => {
  524. // 获取主题样式并添加
  525. const themeStyle = GM_getValue(hashString(currentTheme))
  526.  
  527. if (themeStyle) {
  528. GM_addStyle(themeStyle)
  529. } else {
  530. const themeUrl = \`https://cdn.bootcss.com/highlight.js/9.15.10/styles/\${currentTheme}.min.css\`
  531.  
  532. fetchStyleText(themeUrl).then(style => {
  533. GM_addStyle(style)
  534. GM_setValue(hashString(currentTheme), style)
  535. })
  536. }
  537. }
  538.  
  539. export default something
  540.  
  541. </code>
  542. </pre>
  543. </section>
  544. </div>
  545. </div>
  546. </div>
  547. </body>
  548. `
  549. const vm = new window.Vue({
  550. el: vueRoot,
  551. template: vueTemplate,
  552. data () {
  553. return {
  554. current: {
  555. theme: currentTheme,
  556. font: currentFont
  557. },
  558. styles: {
  559. pre: {
  560. maxWidth: '952px',
  561. maxHeight: '631px',
  562. overflow: 'hidden',
  563. },
  564. code: {
  565. overflow: 'hidden',
  566. fontSize: `${fontSize}px`,
  567. fontFamily: currentFont
  568. }
  569. },
  570. fontSize: fontSize,
  571. themes: themes,
  572. fonts: fonts,
  573. isApplyThemeChanges: isApplyThemeChanges,
  574. isApplyFontChanges: isApplyFontChanges,
  575. isForcePreBackground: isForcePreBackground,
  576. isGFW: isGFW,
  577. defaultBackground: ''
  578. }
  579. },
  580. watch: {
  581. isForcePreBackground (value) {
  582. log(value)
  583. if (value === 'No') {
  584. this.$refs.pre.style.background = this.defaultBackground
  585. } else {
  586. poll({
  587. condition: () => hasCacheValue(this.current.theme),
  588. resolve: () => {
  589. this.$refs.pre.style.background = getCurrentThemeBackground(
  590. getCacheValue(this.current.theme)
  591. )
  592. },
  593. millisecond: 1000,
  594. retries: 5
  595. })
  596. }
  597. }
  598. },
  599. methods: {
  600. reset () {
  601. this.fontSize = 16
  602. this.isApplyThemeChanges = 'Yes'
  603. this.isApplyFontChanges = 'Yes'
  604. this.isForcePreBackground = 'No'
  605. this.isGFW = 'Fuck'
  606. this.current.theme = 'atom-one-dark'
  607. this.current.font = 'Fira Code'
  608. this.changeTheme(this.current.theme)
  609. this.changeFont(this.current.font)
  610. },
  611. apply () {
  612. setCacheValue('fontSize', this.fontSize)
  613. setCacheValue('isApplyThemeChanges', this.isApplyThemeChanges)
  614. setCacheValue('isApplyFontChanges', this.isApplyFontChanges)
  615. setCacheValue(
  616. 'isForcePreBackground',
  617. this.isForcePreBackground
  618. )
  619. setCacheValue('isGFW', this.isGFW)
  620. setCacheValue('currentTheme', this.current.theme)
  621. setCacheValue('currentFont', this.current.font)
  622. },
  623. close () {
  624. parasitifer.hide()
  625. },
  626. changeTheme (value) {
  627. if (this.isApplyThemeChanges === 'No') return false
  628.  
  629. const doChangeTheme = (thmemName, themeStyle) => {
  630. themeStyleEle.innerText = themeStyle
  631.  
  632. if (this.isForcePreBackground === 'Yes') {
  633. log(getCurrentThemeBackground(
  634. themeStyle
  635. ))
  636. this.$refs.pre.style.background = getCurrentThemeBackground(
  637. themeStyle
  638. )
  639. log(getCurrentThemeBackground(themeStyle))
  640. }
  641.  
  642. window.hljs.highlightBlock(this.$refs.code)
  643. }
  644.  
  645. if (hasCacheValue(value)) {
  646. doChangeTheme(value, getCacheValue(value))
  647. log(`get theme: ${value} in cache`)
  648. } else {
  649. const url =
  650. this.GFW === 'Fuck'
  651. ? `https://cdn.bootcss.com/highlight.js/9.15.10/styles/${value}.min.css`
  652. : `https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.15.10/styles/${value}.min.css`
  653. log(url)
  654. fetchStyleText(url).then(style => {
  655. setCacheValue(value, style)
  656. doChangeTheme(value, style)
  657. })
  658. }
  659. log('current theme', this.current.theme)
  660. },
  661. changeFont (value) {
  662. if (this.isApplyFontChanges === 'No') return false
  663.  
  664. const doChangeFont = (fontName, fontStyle) => {
  665. fontStyleEle.innerText = fontStyle
  666. this.styles.code.fontFamily = fontName
  667. }
  668.  
  669. if (hasCacheValue(value)) {
  670. doChangeFont(value, getCacheValue(value))
  671. log(`get font: ${value} in cache`)
  672. } else {
  673. const url =
  674. this.GFW === 'Fuck'
  675. ? `https://fonts.loli.net/css?family=${value}&display=swap`
  676. : `https://fonts.googleapis.com/css?family=${value}&display=swap`
  677. fetchStyleText(url).then(style => {
  678. log('font style:', style)
  679. setCacheValue(value, style)
  680. doChangeFont(value, style)
  681. })
  682. }
  683. log(value)
  684. },
  685. changeFontSize (value) {
  686. if (this.isApplyFontChanges === 'No') return false
  687. log(value)
  688. this.styles.code.fontSize = `${value}px`
  689. }
  690. },
  691. mounted () {
  692. this.defaultBackground = this.$refs.pre.style.background
  693. this.changeTheme(this.current.theme)
  694. this.changeFont(this.current.font)
  695. }
  696. })
  697. log('Setting is mounted')
  698. }
  699.  
  700. // 获取 bulmaStyle, 并挂载 设置页
  701. const bulmaStyle = getCacheValue('bulmaStyle')
  702. if (bulmaStyle) {
  703. mount(bulmaStyle)
  704. } else {
  705. const bulmaUrl = 'https://unpkg.com/buefy/dist/buefy.min.css'
  706. fetchStyleText(bulmaUrl).then(style => {
  707. mount(style)
  708. setCacheValue('bulmaStyle', style)
  709. })
  710. }
  711. }
  712.  
  713. // 注册(不可用)设置页
  714. GM_registerMenuCommand('Open Setting', openSetting, 'SH')
  715.  
  716.  
  717. beautify()
  718. log('highlight runing')

QingJ © 2025

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