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. // @name:zh-CN GitHub 时间格式化
  4. // @namespace https://greatest.deepsurf.us/zh-CN/scripts/480032-github-relative-time-format
  5. // @version 0.1.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 datetimeStr = e.getAttribute("datetime")
  31. const dateObj = dayjs(datetimeStr)
  32. e.title = dateObj.format(TOOLTIP_FORMAT.value)
  33. e.shadowRoot.innerHTML = dateObj.format(DISPLAY_FORMAT.value)
  34. }
  35. }
  36.  
  37. replaceRelativeTimeText()
  38.  
  39. /**
  40. * @type {MutationObserver}
  41. */
  42. let observer
  43.  
  44. const setupObserve = () => {
  45. observer?.observe(
  46. document.querySelector('body'),
  47. {
  48. childList: true,
  49. subtree: true,
  50. attributes: true,
  51. },
  52. )
  53. }
  54. const debounceReplaceRelativeTimeText = debounce(
  55. () => {
  56. observer?.disconnect()
  57. replaceRelativeTimeText()
  58. setupObserve()
  59. },
  60. 50
  61. )
  62. observer = new MutationObserver(debounceReplaceRelativeTimeText)
  63. setupObserve()
  64.  
  65.  
  66. /**
  67. * Create UI for the options
  68. * 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
  69. * The copyright of the original code belongs to John Doe and is released under the MIT license
  70. * Any modifications follow the terms of the MIT license
  71. * @template T
  72. * @param {string} key
  73. * @param {string} title
  74. * @param {T} defaultValue
  75. * @returns {{ value: T }}
  76. */
  77. function useOption(key, title, defaultValue) {
  78. if (typeof GM_getValue === 'undefined') {
  79. return {
  80. value: defaultValue,
  81. }
  82. }
  83.  
  84. let value = GM_getValue(key, defaultValue)
  85. const ref = {
  86. get value() {
  87. return value
  88. },
  89. set value(v) {
  90. value = v
  91. GM_setValue(key, v)
  92. location.reload()
  93. },
  94. }
  95.  
  96. GM_registerMenuCommand(title, () => {
  97. const newValue = prompt(title, value)
  98. if (newValue != null) ref.value = newValue
  99. })
  100.  
  101. return ref
  102. }
  103.  
  104. /**
  105. * @param {Function} fn
  106. * @param {number} wait
  107. * @returns {Function}
  108. */
  109. function debounce(fn, wait) {
  110. let timeout
  111.  
  112. return function (...args) {
  113. const later = () => {
  114. clearTimeout(timeout)
  115. fn.apply(this, args)
  116. }
  117.  
  118. clearTimeout(timeout)
  119. timeout = setTimeout(later, wait)
  120. }
  121. }
  122. })()