Canvas Tab Expander

Automatically expands all tabs in Canvas assignments and combines content

当前为 2024-10-25 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Canvas Tab Expander
  3. // @namespace http://tampermonkey.net/
  4. // @version 0.2
  5. // @description Automatically expands all tabs in Canvas assignments and combines content
  6. // @author You
  7. // @match https://*.instructure.com/courses/*/assignments/*
  8. // @match https://elearn.ucr.edu/*
  9. // @grant none
  10. // @license MIT
  11. // ==/UserScript==
  12.  
  13. (function() {
  14. 'use strict';
  15.  
  16. function expandAllTabs() {
  17. // Get all tab content divs
  18. const tabContents = document.querySelectorAll('.tab-pane.dp-panel-content');
  19.  
  20. // Remove classes and attributes that hide content
  21. tabContents.forEach(content => {
  22. // Remove Bootstrap's tab hiding classes
  23. content.classList.remove('fade');
  24. content.classList.add('show', 'active');
  25.  
  26. // Remove any inline display:none styling
  27. content.style.removeProperty('display');
  28.  
  29. // Remove hidden attribute
  30. content.removeAttribute('hidden');
  31.  
  32. // Force display block
  33. content.style.display = 'block';
  34.  
  35. // Remove aria-hidden attribute
  36. content.removeAttribute('aria-hidden');
  37. });
  38.  
  39. // Modify the tab navigation to show all tabs as active
  40. const tabNavs = document.querySelectorAll('.nav-link.dp-panel-heading');
  41. tabNavs.forEach(tab => {
  42. tab.classList.add('active');
  43. tab.setAttribute('aria-selected', 'true');
  44. });
  45.  
  46. // Also expand any nested accordion panels
  47. const accordionPanels = document.querySelectorAll('.dp-panel-content[style*="display: none"]');
  48. accordionPanels.forEach(panel => {
  49. panel.style.display = 'block';
  50. const toggler = panel.previousElementSibling?.querySelector('.dp-panel-toggler');
  51. if (toggler) {
  52. toggler.setAttribute('aria-expanded', 'true');
  53. }
  54. });
  55.  
  56. // Remove the tab-content active class restriction
  57. const tabContentContainer = document.querySelector('.tab-content');
  58. if (tabContentContainer) {
  59. tabContentContainer.classList.remove('active');
  60. // Add custom CSS to override Bootstrap's tab display logic
  61. const style = document.createElement('style');
  62. style.textContent = `
  63. .tab-content > .tab-pane {
  64. display: block !important;
  65. opacity: 1 !important;
  66. }
  67. .dp-panel-content {
  68. display: block !important;
  69. }
  70. `;
  71. document.head.appendChild(style);
  72. }
  73. }
  74.  
  75. // Function to create and add the expand button
  76. function addExpandButton() {
  77. const existingButton = document.getElementById('expandAllTabsButton');
  78. if (!existingButton) {
  79. const expandButton = document.createElement('button');
  80. expandButton.id = 'expandAllTabsButton';
  81. expandButton.textContent = 'Expand All Tabs';
  82. expandButton.className = 'Button Button--primary';
  83. expandButton.style.margin = '10px 0';
  84. expandButton.addEventListener('click', expandAllTabs);
  85.  
  86. const contentArea = document.querySelector('.description.user_content');
  87. if (contentArea) {
  88. contentArea.insertBefore(expandButton, contentArea.firstChild);
  89. }
  90. }
  91. }
  92.  
  93. // Wait for the page to load
  94. function init() {
  95. addExpandButton();
  96. expandAllTabs();
  97.  
  98. // Add a mutation observer to handle dynamically loaded content
  99. const observer = new MutationObserver((mutations) => {
  100. mutations.forEach((mutation) => {
  101. if (mutation.addedNodes.length) {
  102. expandAllTabs();
  103. }
  104. });
  105. });
  106.  
  107. const config = { childList: true, subtree: true };
  108. observer.observe(document.body, config);
  109. }
  110.  
  111. // Run on page load
  112. if (document.readyState === 'loading') {
  113. document.addEventListener('DOMContentLoaded', init);
  114. } else {
  115. init();
  116. }
  117.  
  118. // Also run after a short delay to catch any dynamic content
  119. setTimeout(init, 1000);
  120. })();