GitHub Relative Time Format

replacing GitHub relative timestamps(<relative-time>) with customizable date and time formats

当前为 2023-11-16 提交的版本,查看 最新版本

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