cmagnuson

Taller Zendesk Macro Menu

Jul 15th, 2025 (edited)
673
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
JavaScript 7.92 KB | Software | 0 0
  1. // ==UserScript==
  2. // @name         Zendesk Taller Macro Menu
  3. // @namespace    http://tampermonkey.net/
  4. // @version      1.4
  5. // @description  Makes the Zendesk macro menu 75% of window height with working scroll and navigation (excludes bulk edit)
  6. // @author       You
  7. // @match        https://*.zendesk.com/agent/*
  8. // @grant        GM_addStyle
  9. // @license      MIT
  10. // ==/UserScript==
  11.  
  12. (function() {
  13.     'use strict';
  14.  
  15.     // Add custom CSS for the macro menu - excluding bulk edit contexts
  16.     GM_addStyle(`
  17.         /* Main macro dropdown - exclude bulk edit modal contexts */
  18.         .macro-suggestions:not([data-bulk-edit] .macro-suggestions):not(.modal .macro-suggestions),
  19.         .macros_dropdown:not([data-bulk-edit] .macros_dropdown):not(.modal .macros_dropdown),
  20.         [data-test-id="macro-suggestions"]:not([data-bulk-edit] [data-test-id="macro-suggestions"]):not(.modal [data-test-id="macro-suggestions"]),
  21.         [data-garden-id="dropdowns.menu"]:not([data-bulk-edit] [data-garden-id="dropdowns.menu"]):not(.modal [data-garden-id="dropdowns.menu"]),
  22.         [aria-label*="macro" i]:not([data-bulk-edit] [aria-label*="macro" i]):not(.modal [aria-label*="macro" i]) {
  23.             max-height: 75vh !important;
  24.             height: auto !important;
  25.             overflow-y: auto !important;
  26.             overflow-x: hidden !important;
  27.         }
  28.  
  29.         /* Exclude bulk edit modal by checking for specific parent classes */
  30.         body:not(.bulk-editing) .macro-suggestions,
  31.         body:not(.bulk-editing) .macros_dropdown,
  32.         body:not(.bulk-editing) [data-test-id="macro-suggestions"],
  33.         :not([role="dialog"]) > :not(.bulk-actions) .macro-suggestions,
  34.         :not([role="dialog"]) > :not(.bulk-actions) [data-test-id="macro-suggestions"] {
  35.             max-height: 75vh !important;
  36.         }
  37.  
  38.         /* Inner scrollable container - exclude bulk edit */
  39.         :not([role="dialog"]) .macro-list:not(.bulk-edit-macro-list),
  40.         :not([role="dialog"]) .macros-list:not(.bulk-edit-macros-list),
  41.         :not([role="dialog"]) [data-test-id="macro-list"],
  42.         :not([role="dialog"]) [data-garden-id="dropdowns.menu"] > ul,
  43.         :not([role="dialog"]) .macros_dropdown > ul,
  44.         :not([role="dialog"]) .macro-suggestions > ul {
  45.             max-height: calc(75vh - 40px) !important;
  46.             overflow-y: auto !important;
  47.             overflow-x: hidden !important;
  48.         }
  49.  
  50.         /* Keep navigation header visible - exclude bulk edit */
  51.         :not([role="dialog"]) .macro-suggestions-header,
  52.         :not([role="dialog"]) .macros_dropdown-header,
  53.         :not([role="dialog"]) .macro-navigation,
  54.         :not([role="dialog"]) .macro-folder-navigation,
  55.         :not([role="dialog"]) [data-test-id="macro-suggestions"] > div:first-child:has(button),
  56.         :not([role="dialog"]) [data-garden-id="dropdowns.menu"] > header {
  57.             position: sticky !important;
  58.             top: 0 !important;
  59.             z-index: 100 !important;
  60.             background: white !important;
  61.             border-bottom: 1px solid #e9ebed !important;
  62.         }
  63.  
  64.         /* Back button and breadcrumbs - exclude bulk edit */
  65.         :not([role="dialog"]) [aria-label="Back"],
  66.         :not([role="dialog"]) [data-test-id="back-button"],
  67.         :not([role="dialog"]) button[aria-label*="folder"],
  68.         :not([role="dialog"]) .macro-folder-back {
  69.             display: flex !important;
  70.             visibility: visible !important;
  71.         }
  72.  
  73.         /* Search box if present - exclude bulk edit */
  74.         :not([role="dialog"]) .macro-search,
  75.         :not([role="dialog"]) input[placeholder*="Search macros"],
  76.         :not([role="dialog"]) input[placeholder*="Filter macros"] {
  77.             position: sticky !important;
  78.             top: 0 !important;
  79.             z-index: 99 !important;
  80.             background: white !important;
  81.         }
  82.  
  83.         /* Ensure proper scrollbar styling - exclude bulk edit */
  84.         :not([role="dialog"]) .macro-suggestions::-webkit-scrollbar,
  85.         :not([role="dialog"]) .macro-list::-webkit-scrollbar,
  86.         :not([role="dialog"]) [data-garden-id="dropdowns.menu"]::-webkit-scrollbar {
  87.             width: 8px !important;
  88.         }
  89.  
  90.         :not([role="dialog"]) .macro-suggestions::-webkit-scrollbar-track,
  91.         :not([role="dialog"]) .macro-list::-webkit-scrollbar-track,
  92.         :not([role="dialog"]) [data-garden-id="dropdowns.menu"]::-webkit-scrollbar-track {
  93.             background: #f1f1f1 !important;
  94.         }
  95.  
  96.         :not([role="dialog"]) .macro-suggestions::-webkit-scrollbar-thumb,
  97.         :not([role="dialog"]) .macro-list::-webkit-scrollbar-thumb,
  98.         :not([role="dialog"]) [data-garden-id="dropdowns.menu"]::-webkit-scrollbar-thumb {
  99.             background: #888 !important;
  100.             border-radius: 4px !important;
  101.         }
  102.  
  103.         /* Individual macro items - exclude bulk edit */
  104.         :not([role="dialog"]) .macro-item,
  105.         :not([role="dialog"]) .macro-suggestion-item {
  106.             padding: 8px 12px !important;
  107.         }
  108.     `);
  109.  
  110.     // Enhanced JavaScript to check context before applying changes
  111.     function expandMacroMenu() {
  112.         const windowHeight = window.innerHeight;
  113.         const menuHeight = Math.floor(windowHeight * 0.75);
  114.  
  115.         // Target all possible macro menu containers
  116.         const selectors = [
  117.             '.macro-suggestions',
  118.             '.macros_dropdown',
  119.             '[data-test-id="macro-suggestions"]',
  120.             '[data-garden-id="dropdowns.menu"]',
  121.             '[aria-label*="macro" i]'
  122.         ];
  123.  
  124.         selectors.forEach(selector => {
  125.             const elements = document.querySelectorAll(selector);
  126.             elements.forEach(element => {
  127.                 // Check if this element is within a bulk edit context
  128.                 const isInModal = element.closest('[role="dialog"]') !== null;
  129.                 const isInBulkEdit = element.closest('.bulk-actions') !== null ||
  130.                                    element.closest('[data-bulk-edit]') !== null ||
  131.                                    element.closest('.modal') !== null ||
  132.                                    element.closest('[aria-label*="bulk" i]') !== null;
  133.  
  134.                 // Only apply changes if NOT in bulk edit context
  135.                 if (element && element.textContent.includes('macro') && !isInModal && !isInBulkEdit) {
  136.                     // Set max height and ensure scrolling works
  137.                     element.style.maxHeight = `${menuHeight}px`;
  138.                     element.style.overflowY = 'auto';
  139.                     element.style.overflowX = 'hidden';
  140.  
  141.                     // Find any inner list containers and ensure they can scroll too
  142.                     const innerLists = element.querySelectorAll('ul, .macro-list, .macros-list');
  143.                     innerLists.forEach(list => {
  144.                         list.style.maxHeight = `${menuHeight - 40}px`;
  145.                         list.style.overflowY = 'auto';
  146.                         list.style.overflowX = 'hidden';
  147.                     });
  148.                 }
  149.             });
  150.         });
  151.     }
  152.  
  153.     // Run after a short delay to ensure DOM is ready
  154.     setTimeout(expandMacroMenu, 500);
  155.  
  156.     // Re-run on window resize
  157.     window.addEventListener('resize', expandMacroMenu);
  158.  
  159.     // Enhanced observer that checks for bulk edit context
  160.     const observer = new MutationObserver((mutations) => {
  161.         // Check if any of the mutations are within a bulk edit context
  162.         let shouldRun = true;
  163.  
  164.         for (const mutation of mutations) {
  165.             if (mutation.target.closest('[role="dialog"]') ||
  166.                 mutation.target.closest('.bulk-actions') ||
  167.                 mutation.target.closest('[data-bulk-edit]')) {
  168.                 shouldRun = false;
  169.                 break;
  170.             }
  171.         }
  172.  
  173.         if (shouldRun) {
  174.             expandMacroMenu();
  175.         }
  176.     });
  177.  
  178.     observer.observe(document.body, {
  179.         childList: true,
  180.         subtree: true
  181.     });
  182. })();
Advertisement