Duolingo Table Header Tooltips

Adds tooltips for table header columns on Duolingo tables and make them sticky.

  1. // ==UserScript==
  2. // @name Duolingo Table Header Tooltips
  3. // @namespace http://tampermonkey.net/
  4. // @version 0.1
  5. // @description Adds tooltips for table header columns on Duolingo tables and make them sticky.
  6. // @author BErnd14
  7. // @match https://duolingodata.com/*
  8. // @grant GM_addStyle
  9. // @license MIT
  10. // ==/UserScript==
  11.  
  12. (function () {
  13. 'use strict';
  14.  
  15. const tooltips = {
  16. 'Learning': 'Link to course structure (CEFR levels in red)',
  17. 'from': "'from' links to a technical JSON file",
  18. 'U': 'Units - Links to an image of the Path structure',
  19. 'Lr': 'Learners - Number of learners (in millions), links to DuoRadios when green',
  20. 'Ls': 'Lessons - Purple = Adventures, links to these',
  21. 'S': 'Stories - Links to official or unofficial stories',
  22. 'W': 'Words - Word list (if available)',
  23. 'R': 'Release Date - Format: Year.Month, links to course versions',
  24. 'D': 'Different Lessons - Ranking, links to alternative versions'
  25. };
  26.  
  27. function addTooltips() {
  28. const headers = document.querySelectorAll('#DuolingoData thead th');
  29. if (!headers.length) return;
  30.  
  31. headers.forEach(th => {
  32. const key = th.textContent.trim();
  33. if (tooltips[key]) {
  34. if (th.title !== tooltips[key]) {
  35. th.title = tooltips[key];
  36. }
  37. }
  38. });
  39. }
  40.  
  41. const observer = new MutationObserver(mutations => {
  42. for (const mutation of mutations) {
  43. if (mutation.type === 'childList' || mutation.type === 'subtree' || mutation.type === 'characterData') {
  44. addTooltips();
  45. break;
  46. }
  47. }
  48. });
  49.  
  50. observer.observe(document.body, {
  51. childList: true,
  52. subtree: true,
  53. characterData: true
  54. });
  55.  
  56. setTimeout(addTooltips, 1000);
  57.  
  58. GM_addStyle(`
  59. #DuolingoData thead th {
  60. position: sticky !important;
  61. top: 0;
  62. background: white;
  63. z-index: 1000;
  64. }
  65. `);
  66. })();