GitHub 时间格式化

用自定义的日期时间格式替换 GitHub 时间显示(<relative-time>)

  1. // ==UserScript==
  2. // @name GitHub Relative Time Format
  3. // @name:zh-CN GitHub 时间格式化
  4. // @namespace https://greasyfork.org/zh-CN/scripts/480032-github-relative-time-format
  5. // @version 0.2.0
  6. // @description replacing GitHub relative timestamps(<relative-time>) with customizable date and time formats
  7. // @description:zh-CN 用自定义的日期时间格式替换 GitHub 时间显示(<relative-time>)
  8. // @author MuXiu1997 (https://github.com/MuXiu1997)
  9. // @license MIT
  10. // @homepageURL https://github.com/MuXiu1997/github-relative-time-format
  11. // @supportURL https://github.com/MuXiu1997/github-relative-time-format
  12. // @match https://github.com/**
  13. // @icon https://www.google.com/s2/favicons?sz=64&domain=github.com
  14. // @require https://cdn.jsdelivr.net/npm/dayjs@1.11.10/dayjs.min.js
  15. // @grant GM_getValue
  16. // @grant GM_setValue
  17. // @grant GM_registerMenuCommand
  18. // @grant GM_unregisterMenuCommand
  19. // ==/UserScript==
  20.  
  21. (function () {
  22. 'use strict'
  23.  
  24. const DISPLAY_FORMAT = useOption('DISPLAY_FORMAT', 'Change display format', 'YY-MM-DD HH:mm')
  25. const TOOLTIP_FORMAT = useOption('TOOLTIP_FORMAT', 'Change tooltip format', 'YYYY-MM-DD HH:mm:ss')
  26.  
  27. function replaceRelativeTimeText() {
  28. const relativeTimeElements = document.getElementsByTagName('relative-time')
  29. for (const e of relativeTimeElements) {
  30. const datetime = e.getAttribute('datetime')
  31. const format = e.getAttribute('format')
  32.  
  33. const dateObj = dayjs(datetime)
  34.  
  35. e.title = dateObj.format(TOOLTIP_FORMAT.value)
  36.  
  37. if (format ==='duration' || format === 'elapsed')
  38. continue
  39.  
  40. e.disconnectedCallback()
  41. e.shadowRoot.innerHTML = dateObj.format(DISPLAY_FORMAT.value)
  42. }
  43. }
  44.  
  45. replaceRelativeTimeText()
  46.  
  47. /**
  48. * @type {MutationObserver}
  49. */
  50. let observer
  51.  
  52. const setupObserve = () => {
  53. observer?.observe(
  54. document.querySelector('body'),
  55. {
  56. childList: true,
  57. subtree: true,
  58. attributes: true,
  59. },
  60. )
  61. }
  62. const debounceReplaceRelativeTimeText = debounce(
  63. () => {
  64. observer?.disconnect()
  65. replaceRelativeTimeText()
  66. setupObserve()
  67. },
  68. 50
  69. )
  70. observer = new MutationObserver(debounceReplaceRelativeTimeText)
  71. setupObserve()
  72.  
  73.  
  74. /**
  75. * Create UI for the options
  76. * The following code is based on the work of the original author Anthony Fu, and the original code can be found at https://github.com/antfu/refined-github-notifications/blob/main/index.js
  77. * The copyright of the original code belongs to John Doe and is released under the MIT license
  78. * Any modifications follow the terms of the MIT license
  79. * @template T
  80. * @param {string} key
  81. * @param {string} title
  82. * @param {T} defaultValue
  83. * @returns {{ value: T }}
  84. */
  85. function useOption(key, title, defaultValue) {
  86. if (typeof GM_getValue === 'undefined') {
  87. return {
  88. value: defaultValue,
  89. }
  90. }
  91.  
  92. let value = GM_getValue(key, defaultValue)
  93. const ref = {
  94. get value() {
  95. return value
  96. },
  97. set value(v) {
  98. value = v
  99. GM_setValue(key, v)
  100. location.reload()
  101. },
  102. }
  103.  
  104. GM_registerMenuCommand(title, () => {
  105. const newValue = prompt(title, value)
  106. if (newValue != null) ref.value = newValue
  107. })
  108.  
  109. return ref
  110. }
  111.  
  112. /**
  113. * @param {Function} fn
  114. * @param {number} wait
  115. * @returns {Function}
  116. */
  117. function debounce(fn, wait) {
  118. let timeout
  119.  
  120. return function (...args) {
  121. const later = () => {
  122. clearTimeout(timeout)
  123. fn.apply(this, args)
  124. }
  125.  
  126. clearTimeout(timeout)
  127. timeout = setTimeout(later, wait)
  128. }
  129. }
  130. })()