Fix Order of GitHub Dashboard

Keeps entries on the GitHub dashboard page ordered from the newest one to the oldest one, but the More button may not always appear.

  1. // ==UserScript==
  2. // @name Fix Order of GitHub Dashboard
  3. // @namespace http://prantlf.me/
  4. // @version 2.2
  5. // @description Keeps entries on the GitHub dashboard page ordered from the newest one to the oldest one, but the More button may not always appear.
  6. // @author prantlf@gmail.com
  7. // @license MIT
  8. // @match https://github.com/
  9. // @icon https://www.google.com/s2/favicons?sz=64&domain=github.com
  10. // @grant none
  11. // ==/UserScript==
  12.  
  13. (function() {
  14. 'use strict';
  15.  
  16. const dashboard = document.getElementById('dashboard')
  17. let observe = true
  18. const observer = new MutationObserver(mutations => {
  19. if (observe && mutations.some(mutatedArticle)) {
  20. console.debug('[fix-order]', 'new articles detected')
  21. debounce(reorder)
  22. }
  23. })
  24. observer.observe(dashboard, { childList: true, subtree: true })
  25.  
  26. function mutatedArticle({ target, addedNodes }) {
  27. return isOrHasArticle(target) || Array.from(addedNodes).some(isOrHasArticle)
  28. }
  29.  
  30. function isOrHasArticle(el) {
  31. return el.tagName === 'ARTICLE' || el.nodeType === 1 && el.getElementsByTagName('ARTICLE').length > 0
  32. }
  33.  
  34. let debouncing
  35. function debounce(fn) {
  36. if (debouncing) {
  37. clearTimeout(debouncing)
  38. debouncing = undefined
  39. }
  40. debouncing = setTimeout(fn, 100)
  41. }
  42.  
  43. function reorder() {
  44. observe = false
  45. const feeds = Array.from(dashboard.getElementsByTagName('TURBO-FRAME'))
  46. const articles = feeds
  47. .map(frame => Array.from(frame.children).filter(el => el.tagName === 'ARTICLE'))
  48. .flat()
  49. const position = document.documentElement.scrollTop
  50. const now = new Date
  51. for (const article of articles) {
  52. const { nextElementSibling: div } = article
  53. article.div = div
  54. const time = article.querySelector('relative-time')
  55. article.time = time && new Date(time.getAttribute('datetime')) || now
  56. article.remove()
  57. div.remove()
  58. }
  59. articles.sort((l, r) => l.time < r.time ? 1 : l.time > r.time ? -1 : 0)
  60. const feed = feeds[feeds.length - 1]
  61. let { firstElementChild: anchor } = feed
  62. for (const article of articles) {
  63. const { div } = article
  64. anchor.insertAdjacentElement('afterend', article)
  65. article.insertAdjacentElement('afterend', div)
  66. delete article.div
  67. delete article.time
  68. anchor = div
  69. }
  70. console.debug('[fix-order]', articles.length, 'articles reordered')
  71. setTimeout(() => {
  72. document.documentElement.scrollTop = position
  73. observe = true
  74. })
  75. }
  76. })();