Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // ==UserScript==
- // @name Grok Enhanced
- // @namespace http://tampermonkey.net/
- // @version 0.5
- // @description Customize width & justification (main/secondary panels via slider/input/checkbox). Fixed for May 2024 Grok UI update. Show/hide via menu on grok.com. Handles Shadow DOM. Header added.
- // @author kiranwayne
- // @match https://grok.com/*
- // @grant GM_getValue
- // @grant GM_setValue
- // @grant GM_registerMenuCommand
- // @grant GM_unregisterMenuCommand
- // @run-at document-end
- // ==/UserScript==
- (async () => {
- 'use strict';
- // --- Configuration & Constants ---
- const SCRIPT_NAME = 'Grok Enhanced';
- const SCRIPT_VERSION = '0.5';
- const SCRIPT_AUTHOR = 'kiranwayne';
- // Config Keys
- const CONFIG_PREFIX = 'grokEnhancedControls_v6_'; // Updated prefix to reset settings after update
- // Main Panel
- const MAIN_WIDTH_PX_KEY = CONFIG_PREFIX + 'mainWidthPx';
- const USE_DEFAULT_MAIN_WIDTH_KEY = CONFIG_PREFIX + 'useDefaultMainWidth';
- const MAIN_JUSTIFY_KEY = CONFIG_PREFIX + 'mainJustifyEnabled';
- // Secondary Panel
- const SECONDARY_WIDTH_PX_KEY = CONFIG_PREFIX + 'secondaryWidthPx';
- const USE_DEFAULT_SECONDARY_WIDTH_KEY = CONFIG_PREFIX + 'useDefaultSecondaryWidth';
- const SECONDARY_JUSTIFY_KEY = CONFIG_PREFIX + 'secondaryJustifyEnabled';
- // Shared Settings
- const UI_VISIBLE_KEY = CONFIG_PREFIX + 'uiVisible';
- // Style/Panel IDs
- const STYLE_ID = 'vm-grok-combined-style-v6';
- const SETTINGS_PANEL_ID = 'grok-userscript-settings-panel-v6';
- // Target Selectors
- const MAIN_PANEL_SELECTOR = 'div.breakout[class*="--content-max-width"]'; // [FIX] Updated for May 2024 Grok UI.
- const SECONDARY_PANEL_SELECTOR = '.max-w-4xl'; // NOTE: This selector might also change in the future.
- // Justification targets paragraphs within each panel selector
- const MAIN_JUSTIFY_TARGET_SELECTOR = `${MAIN_PANEL_SELECTOR} p`;
- const SECONDARY_JUSTIFY_TARGET_SELECTOR = `${SECONDARY_PANEL_SELECTOR} p`;
- // Slider/Input Ranges & Defaults
- const DEFAULT_MAIN_WIDTH_PX = 1100; const MIN_MAIN_WIDTH_PX = 500; const MAX_MAIN_WIDTH_PX = 2000;
- const DEFAULT_SECONDARY_WIDTH_PX = 900; const MIN_SECONDARY_WIDTH_PX = 500; const MAX_SECONDARY_WIDTH_PX = 1500;
- const STEP_WIDTH_PX = 1;
- // Layout Constants (Unchanged) - Keep if needed for other features
- const LAYOUT_CONFIG = { /* ... Z-indexes, etc. ... */ };
- // --- State ---
- let config = {
- mainWidthPx: DEFAULT_MAIN_WIDTH_PX,
- useDefaultMainWidth: false,
- mainJustifyEnabled: false,
- secondaryWidthPx: DEFAULT_SECONDARY_WIDTH_PX,
- useDefaultSecondaryWidth: false,
- secondaryJustifyEnabled: false,
- uiVisible: false
- };
- let styleElement = null;
- let settingsPanel = null;
- // Main Panel UI
- let mainWidthSlider=null, mainWidthLabel=null, mainWidthInput=null, useDefaultMainCheckbox=null, mainJustifyCheckbox=null;
- // Secondary Panel UI
- let secondaryWidthSlider=null, secondaryWidthLabel=null, secondaryWidthInput=null, useDefaultSecondaryCheckbox=null, secondaryJustifyCheckbox=null;
- // Shared UI
- let menuCommandId_ToggleUI = null;
- const allStyleRoots = new Set();
- // --- Helper Functions ---
- async function loadSettings() {
- // Load Main Panel Settings
- config.mainWidthPx = await GM_getValue(MAIN_WIDTH_PX_KEY, DEFAULT_MAIN_WIDTH_PX);
- config.mainWidthPx = Math.max(MIN_MAIN_WIDTH_PX, Math.min(MAX_MAIN_WIDTH_PX, config.mainWidthPx));
- config.useDefaultMainWidth = await GM_getValue(USE_DEFAULT_MAIN_WIDTH_KEY, false);
- config.mainJustifyEnabled = await GM_getValue(MAIN_JUSTIFY_KEY, false);
- // Load Secondary Panel Settings
- config.secondaryWidthPx = await GM_getValue(SECONDARY_WIDTH_PX_KEY, DEFAULT_SECONDARY_WIDTH_PX);
- config.secondaryWidthPx = Math.max(MIN_SECONDARY_WIDTH_PX, Math.min(MAX_SECONDARY_WIDTH_PX, config.secondaryWidthPx));
- config.useDefaultSecondaryWidth = await GM_getValue(USE_DEFAULT_SECONDARY_WIDTH_KEY, false);
- config.secondaryJustifyEnabled = await GM_getValue(SECONDARY_JUSTIFY_KEY, false);
- // Load Shared Settings
- config.uiVisible = await GM_getValue(UI_VISIBLE_KEY, false);
- }
- async function saveSetting(key, value) {
- let keyToSave = key;
- let valueToSave = value;
- // Handle Width Keys
- if (key === MAIN_WIDTH_PX_KEY || key === SECONDARY_WIDTH_PX_KEY) {
- const numValue = parseInt(value, 10);
- if (!isNaN(numValue)) {
- let clampedValue = numValue;
- if (key === MAIN_WIDTH_PX_KEY) { clampedValue = Math.max(MIN_MAIN_WIDTH_PX, Math.min(MAX_MAIN_WIDTH_PX, numValue)); config.mainWidthPx = clampedValue; }
- else { clampedValue = Math.max(MIN_SECONDARY_WIDTH_PX, Math.min(MAX_SECONDARY_WIDTH_PX, numValue)); config.secondaryWidthPx = clampedValue; }
- valueToSave = clampedValue;
- } else { return; }
- }
- // Handle Boolean Keys
- else if (key === USE_DEFAULT_MAIN_WIDTH_KEY) config.useDefaultMainWidth = value;
- else if (key === USE_DEFAULT_SECONDARY_WIDTH_KEY) config.useDefaultSecondaryWidth = value;
- else if (key === MAIN_JUSTIFY_KEY) config.mainJustifyEnabled = value;
- else if (key === SECONDARY_JUSTIFY_KEY) config.secondaryJustifyEnabled = value;
- else if (key === UI_VISIBLE_KEY) config.uiVisible = value;
- await GM_setValue(keyToSave, valueToSave);
- }
- // --- Style Generation Functions ---
- function generateCss() {
- // Spinner Fix CSS
- const spinnerCss = `
- #${SETTINGS_PANEL_ID} input[type=number] { -moz-appearance: textfield !important; }
- #${SETTINGS_PANEL_ID} input[type=number]::-webkit-inner-spin-button,
- #${SETTINGS_PANEL_ID} input[type=number]::-webkit-outer-spin-button {
- -webkit-appearance: inner-spin-button !important; opacity: 1 !important; cursor: pointer;
- }
- `;
- // --- Main Panel Width ---
- // [FIX] Changed from setting 'max-width' to overriding the '--content-max-width' CSS variable to work with the new Grok UI.
- let mainWidthRule = !config.useDefaultMainWidth ? `${MAIN_PANEL_SELECTOR} { --content-max-width: ${config.mainWidthPx}px !important; }` : '/* Main width default */';
- // --- Main Panel Justify ---
- let mainJustifyRule = config.mainJustifyEnabled ? `${MAIN_JUSTIFY_TARGET_SELECTOR} { text-align: justify !important; hyphens: auto; }` : '/* Main justify off */';
- // --- Secondary Panel Width ---
- let secondaryWidthRule = !config.useDefaultSecondaryWidth ? `${SECONDARY_PANEL_SELECTOR} { max-width: ${config.secondaryWidthPx}px !important; }` : '/* Secondary width default */';
- // --- Secondary Panel Justify ---
- let secondaryJustifyRule = config.secondaryJustifyEnabled ? `${SECONDARY_JUSTIFY_TARGET_SELECTOR} { text-align: justify !important; hyphens: auto; }` : '/* Secondary justify off */';
- // Combine all rules
- return `
- /* Grok Enhanced Styles v${SCRIPT_VERSION} */
- ${spinnerCss}
- ${mainWidthRule}
- ${mainJustifyRule}
- ${secondaryWidthRule}
- ${secondaryJustifyRule}
- `;
- }
- // --- Style Injection / Update Function ---
- function applyStylesToAllRoots() {
- // Apply the combined CSS to head and all shadow roots
- const css = generateCss();
- allStyleRoots.forEach(root => { if (root) injectOrUpdateStyle(root, STYLE_ID, css); });
- }
- function injectOrUpdateStyle(root, styleId, cssContent) { if (!root) return; let style = root.querySelector(`#${styleId}`); if (cssContent) { if (!style) { style = document.createElement('style'); style.id = styleId; style.textContent = cssContent; if (root === document.head || (root.nodeType === Node.ELEMENT_NODE && root.shadowRoot === null) || root.nodeType === Node.DOCUMENT_FRAGMENT_NODE) root.appendChild(style); else if (root.shadowRoot) root.shadowRoot.appendChild(style); } else if (style.textContent !== cssContent) style.textContent = cssContent; } else { if (style) style.remove(); } }
- // --- UI State Update ---
- function updateUIState() {
- if (!settingsPanel || !document.body.contains(settingsPanel)) return;
- // Update Main Panel Controls
- if(useDefaultMainCheckbox && mainWidthSlider && mainWidthInput && mainWidthLabel && mainJustifyCheckbox) {
- useDefaultMainCheckbox.checked = config.useDefaultMainWidth;
- const isMainCustom = !config.useDefaultMainWidth;
- mainWidthSlider.disabled = !isMainCustom; mainWidthInput.disabled = !isMainCustom;
- mainWidthSlider.value = config.mainWidthPx; mainWidthInput.value = config.mainWidthPx;
- mainWidthLabel.textContent = `${config.mainWidthPx}px`;
- mainWidthLabel.style.opacity = isMainCustom ? 1 : 0.5; mainWidthSlider.style.opacity = isMainCustom ? 1 : 0.5; mainWidthInput.style.opacity = isMainCustom ? 1 : 0.5;
- mainJustifyCheckbox.checked = config.mainJustifyEnabled;
- }
- // Update Secondary Panel Controls
- if(useDefaultSecondaryCheckbox && secondaryWidthSlider && secondaryWidthInput && secondaryWidthLabel && secondaryJustifyCheckbox) {
- useDefaultSecondaryCheckbox.checked = config.useDefaultSecondaryWidth;
- const isSecondaryCustom = !config.useDefaultSecondaryWidth;
- secondaryWidthSlider.disabled = !isSecondaryCustom; secondaryWidthInput.disabled = !isSecondaryCustom;
- secondaryWidthSlider.value = config.secondaryWidthPx; secondaryWidthInput.value = config.secondaryWidthPx;
- secondaryWidthLabel.textContent = `${config.secondaryWidthPx}px`;
- secondaryWidthLabel.style.opacity = isSecondaryCustom ? 1 : 0.5; secondaryWidthSlider.style.opacity = isSecondaryCustom ? 1 : 0.5; secondaryWidthInput.style.opacity = isSecondaryCustom ? 1 : 0.5;
- secondaryJustifyCheckbox.checked = config.secondaryJustifyEnabled;
- }
- }
- // --- Click Outside Handler (Standard) ---
- async function handleClickOutside(event) { if (event.target?.closest?.('iframe[id^="tampermonkey_"]')) return; if (settingsPanel && document.body.contains(settingsPanel) && !settingsPanel.contains(event.target)) { if (config.uiVisible) { await saveSetting(UI_VISIBLE_KEY, false); removeSettingsUI(); updateTampermonkeyMenu(); } } }
- // --- UI Creation/Removal ---
- function removeSettingsUI() {
- document.removeEventListener('click', handleClickOutside, true);
- settingsPanel = document.getElementById(SETTINGS_PANEL_ID);
- if (settingsPanel) {
- settingsPanel.remove(); settingsPanel = null;
- mainWidthSlider=mainWidthLabel=mainWidthInput=useDefaultMainCheckbox=mainJustifyCheckbox=null;
- secondaryWidthSlider=secondaryWidthLabel=secondaryWidthInput=useDefaultSecondaryCheckbox=secondaryJustifyCheckbox=null;
- }
- document.removeEventListener('click', handleClickOutside, true);
- }
- function createSettingsUI() {
- if (document.getElementById(SETTINGS_PANEL_ID) || !config.uiVisible) return;
- const body = document.body || document.getElementsByTagName('body')[0];
- if (!body) { console.error("[Grok Enhanced] Cannot find body."); return; }
- document.removeEventListener('click', handleClickOutside, true);
- settingsPanel = document.createElement('div');
- settingsPanel.id = SETTINGS_PANEL_ID;
- Object.assign(settingsPanel.style, { position: 'fixed', top: '10px', right: '10px', zIndex: '99999', display: 'block', background: '#343541', color: '#ECECF1', border: '1px solid #565869', borderRadius: '6px', padding: '15px', boxShadow: '0 4px 10px rgba(0,0,0,0.3)', minWidth: '300px' });
- // --- Header ---
- const headerDiv = document.createElement('div'); headerDiv.style.marginBottom = '10px'; headerDiv.style.paddingBottom = '10px'; headerDiv.style.borderBottom = '1px solid #565869'; const titleElement = document.createElement('h4'); titleElement.textContent = SCRIPT_NAME; Object.assign(titleElement.style, { margin: '0 0 5px 0', fontSize: '1.1em', fontWeight: 'bold', color: '#FFFFFF'}); const versionElement = document.createElement('p'); versionElement.textContent = `Version: ${SCRIPT_VERSION}`; Object.assign(versionElement.style, { margin: '0 0 2px 0', fontSize: '0.85em', opacity: '0.8'}); const authorElement = document.createElement('p'); authorElement.textContent = `Author: ${SCRIPT_AUTHOR}`; Object.assign(authorElement.style, { margin: '0', fontSize: '0.85em', opacity: '0.8'}); headerDiv.appendChild(titleElement); headerDiv.appendChild(versionElement); headerDiv.appendChild(authorElement); settingsPanel.appendChild(headerDiv);
- // --- Main Panel Width Section ---
- const mainWidthSection = document.createElement('div'); mainWidthSection.style.marginTop = '10px'; mainWidthSection.style.marginBottom = '15px';
- const mainSectionTitle = document.createElement('div'); mainSectionTitle.textContent = 'Main Panel'; mainSectionTitle.style.fontWeight = 'bold'; mainSectionTitle.style.marginBottom = '8px'; mainSectionTitle.style.fontSize = '0.9em';
- const mainDefaultDiv = document.createElement('div'); mainDefaultDiv.style.marginBottom = '8px';
- useDefaultMainCheckbox = document.createElement('input'); useDefaultMainCheckbox.type = 'checkbox'; useDefaultMainCheckbox.id = 'grok-main-default-toggle';
- const mainDefaultLabel = document.createElement('label'); mainDefaultLabel.htmlFor = 'grok-main-default-toggle'; mainDefaultLabel.textContent = ' Use Grok Default Width'; mainDefaultLabel.style.cursor = 'pointer'; mainDefaultLabel.style.fontSize = '0.9em';
- mainDefaultDiv.appendChild(useDefaultMainCheckbox); mainDefaultDiv.appendChild(mainDefaultLabel);
- const mainSliderInputDiv = document.createElement('div'); mainSliderInputDiv.style.display = 'flex'; mainSliderInputDiv.style.alignItems = 'center'; mainSliderInputDiv.style.gap = '10px'; mainSliderInputDiv.style.marginBottom = '8px';
- mainWidthLabel = document.createElement('span'); mainWidthLabel.style.cssText = 'min-width: 50px; font-family: monospace; text-align: right;';
- mainWidthSlider = document.createElement('input'); mainWidthSlider.type = 'range'; mainWidthSlider.min = MIN_MAIN_WIDTH_PX; mainWidthSlider.max = MAX_MAIN_WIDTH_PX; mainWidthSlider.step = STEP_WIDTH_PX; mainWidthSlider.style.cssText = 'flex-grow: 1; vertical-align: middle;';
- mainWidthInput = document.createElement('input'); mainWidthInput.type = 'number'; mainWidthInput.min = MIN_MAIN_WIDTH_PX; mainWidthInput.max = MAX_MAIN_WIDTH_PX; mainWidthInput.step = STEP_WIDTH_PX; mainWidthInput.style.cssText = 'width: 60px; padding: 2px 4px; background: #202123; color: #ECECF1; border: 1px solid #565869; border-radius: 4px; vertical-align: middle;';
- mainSliderInputDiv.appendChild(mainWidthLabel); mainSliderInputDiv.appendChild(mainWidthSlider); mainSliderInputDiv.appendChild(mainWidthInput);
- const mainJustifyDiv = document.createElement('div');
- mainJustifyCheckbox = document.createElement('input'); mainJustifyCheckbox.type = 'checkbox'; mainJustifyCheckbox.id = 'grok-main-justify-toggle';
- const mainJustifyLabel = document.createElement('label'); mainJustifyLabel.htmlFor = 'grok-main-justify-toggle'; mainJustifyLabel.textContent = ' Enable Text Justification'; mainJustifyLabel.style.cursor = 'pointer'; mainJustifyLabel.style.fontSize = '0.9em';
- mainJustifyDiv.appendChild(mainJustifyCheckbox); mainJustifyDiv.appendChild(mainJustifyLabel);
- mainWidthSection.appendChild(mainSectionTitle); mainWidthSection.appendChild(mainDefaultDiv); mainWidthSection.appendChild(mainSliderInputDiv); mainWidthSection.appendChild(mainJustifyDiv);
- settingsPanel.appendChild(mainWidthSection);
- // --- Secondary Panel Width Section ---
- const secondaryWidthSection = document.createElement('div'); secondaryWidthSection.style.borderTop = '1px dashed #565869'; secondaryWidthSection.style.paddingTop = '15px'; secondaryWidthSection.style.marginTop = '15px'; secondaryWidthSection.style.marginBottom = '15px';
- const secondarySectionTitle = document.createElement('div'); secondarySectionTitle.textContent = 'Secondary Panel'; secondarySectionTitle.style.fontWeight = 'bold'; secondarySectionTitle.style.marginBottom = '8px'; secondarySectionTitle.style.fontSize = '0.9em';
- const secondaryDefaultDiv = document.createElement('div'); secondaryDefaultDiv.style.marginBottom = '8px';
- useDefaultSecondaryCheckbox = document.createElement('input'); useDefaultSecondaryCheckbox.type = 'checkbox'; useDefaultSecondaryCheckbox.id = 'grok-secondary-default-toggle';
- const secondaryDefaultLabel = document.createElement('label'); secondaryDefaultLabel.htmlFor = 'grok-secondary-default-toggle'; secondaryDefaultLabel.textContent = ' Use Grok Default Width'; secondaryDefaultLabel.style.cursor = 'pointer'; secondaryDefaultLabel.style.fontSize = '0.9em';
- secondaryDefaultDiv.appendChild(useDefaultSecondaryCheckbox); secondaryDefaultDiv.appendChild(secondaryDefaultLabel);
- const secondarySliderInputDiv = document.createElement('div'); secondarySliderInputDiv.style.display = 'flex'; secondarySliderInputDiv.style.alignItems = 'center'; secondarySliderInputDiv.style.gap = '10px'; secondarySliderInputDiv.style.marginBottom = '8px';
- secondaryWidthLabel = document.createElement('span'); secondaryWidthLabel.style.cssText = 'min-width: 50px; font-family: monospace; text-align: right;';
- secondaryWidthSlider = document.createElement('input'); secondaryWidthSlider.type = 'range'; secondaryWidthSlider.min = MIN_SECONDARY_WIDTH_PX; secondaryWidthSlider.max = MAX_SECONDARY_WIDTH_PX; secondaryWidthSlider.step = STEP_WIDTH_PX; secondaryWidthSlider.style.cssText = 'flex-grow: 1; vertical-align: middle;';
- secondaryWidthInput = document.createElement('input'); secondaryWidthInput.type = 'number'; secondaryWidthInput.min = MIN_SECONDARY_WIDTH_PX; secondaryWidthInput.max = MAX_SECONDARY_WIDTH_PX; secondaryWidthInput.step = STEP_WIDTH_PX; secondaryWidthInput.style.cssText = 'width: 60px; padding: 2px 4px; background: #202123; color: #ECECF1; border: 1px solid #565869; border-radius: 4px; vertical-align: middle;';
- secondarySliderInputDiv.appendChild(secondaryWidthLabel); secondarySliderInputDiv.appendChild(secondaryWidthSlider); secondarySliderInputDiv.appendChild(secondaryWidthInput);
- const secondaryJustifyDiv = document.createElement('div');
- secondaryJustifyCheckbox = document.createElement('input'); secondaryJustifyCheckbox.type = 'checkbox'; secondaryJustifyCheckbox.id = 'grok-secondary-justify-toggle';
- const secondaryJustifyLabel = document.createElement('label'); secondaryJustifyLabel.htmlFor = 'grok-secondary-justify-toggle'; secondaryJustifyLabel.textContent = ' Enable Text Justification'; secondaryJustifyLabel.style.cursor = 'pointer'; secondaryJustifyLabel.style.fontSize = '0.9em';
- secondaryJustifyDiv.appendChild(secondaryJustifyCheckbox); secondaryJustifyDiv.appendChild(secondaryJustifyLabel);
- secondaryWidthSection.appendChild(secondarySectionTitle); secondaryWidthSection.appendChild(secondaryDefaultDiv); secondaryWidthSection.appendChild(secondarySliderInputDiv); secondaryWidthSection.appendChild(secondaryJustifyDiv);
- settingsPanel.appendChild(secondaryWidthSection);
- body.appendChild(settingsPanel);
- // --- Event Listeners ---
- // Main Panel
- useDefaultMainCheckbox.addEventListener('change', async (e) => { await saveSetting(USE_DEFAULT_MAIN_WIDTH_KEY, e.target.checked); applyStylesToAllRoots(); updateUIState(); });
- mainWidthSlider.addEventListener('input', (e) => { if (config.useDefaultMainWidth) return; const nw=parseInt(e.target.value,10); config.mainWidthPx=nw; if(mainWidthLabel) mainWidthLabel.textContent=`${nw}px`; if(mainWidthInput) mainWidthInput.value=nw; applyStylesToAllRoots(); });
- mainWidthSlider.addEventListener('change', async (e) => { if (config.useDefaultMainWidth) return; const fw=parseInt(e.target.value,10); await saveSetting(MAIN_WIDTH_PX_KEY, fw); });
- mainWidthInput.addEventListener('input', (e) => { if (config.useDefaultMainWidth) return; let nw=parseInt(e.target.value,10); if(isNaN(nw)) return; nw=Math.max(MIN_MAIN_WIDTH_PX, Math.min(MAX_MAIN_WIDTH_PX, nw)); config.mainWidthPx=nw; if(mainWidthLabel) mainWidthLabel.textContent=`${nw}px`; if(mainWidthSlider) mainWidthSlider.value=nw; applyStylesToAllRoots(); });
- mainWidthInput.addEventListener('change', async (e) => { if (config.useDefaultMainWidth) return; let fw=parseInt(e.target.value,10); if(isNaN(fw)) fw=config.mainWidthPx; fw=Math.max(MIN_MAIN_WIDTH_PX, Math.min(MAX_MAIN_WIDTH_PX, fw)); e.target.value=fw; if(mainWidthSlider) mainWidthSlider.value=fw; if(mainWidthLabel) mainWidthLabel.textContent=`${fw}px`; await saveSetting(MAIN_WIDTH_PX_KEY, fw); applyStylesToAllRoots(); });
- mainJustifyCheckbox.addEventListener('change', async (e) => { await saveSetting(MAIN_JUSTIFY_KEY, e.target.checked); applyStylesToAllRoots(); });
- // Secondary Panel
- useDefaultSecondaryCheckbox.addEventListener('change', async (e) => { await saveSetting(USE_DEFAULT_SECONDARY_WIDTH_KEY, e.target.checked); applyStylesToAllRoots(); updateUIState(); });
- secondaryWidthSlider.addEventListener('input', (e) => { if (config.useDefaultSecondaryWidth) return; const nw=parseInt(e.target.value,10); config.secondaryWidthPx=nw; if(secondaryWidthLabel) secondaryWidthLabel.textContent=`${nw}px`; if(secondaryWidthInput) secondaryWidthInput.value=nw; applyStylesToAllRoots(); });
- secondaryWidthSlider.addEventListener('change', async (e) => { if (config.useDefaultSecondaryWidth) return; const fw=parseInt(e.target.value,10); await saveSetting(SECONDARY_WIDTH_PX_KEY, fw); });
- secondaryWidthInput.addEventListener('input', (e) => { if (config.useDefaultSecondaryWidth) return; let nw=parseInt(e.target.value,10); if(isNaN(nw)) return; nw=Math.max(MIN_SECONDARY_WIDTH_PX, Math.min(MAX_SECONDARY_WIDTH_PX, nw)); config.secondaryWidthPx=nw; if(secondaryWidthLabel) secondaryWidthLabel.textContent=`${nw}px`; if(secondaryWidthSlider) secondaryWidthSlider.value=nw; applyStylesToAllRoots(); });
- secondaryWidthInput.addEventListener('change', async (e) => { if (config.useDefaultSecondaryWidth) return; let fw=parseInt(e.target.value,10); if(isNaN(fw)) fw=config.secondaryWidthPx; fw=Math.max(MIN_SECONDARY_WIDTH_PX, Math.min(MAX_SECONDARY_WIDTH_PX, fw)); e.target.value=fw; if(secondaryWidthSlider) secondaryWidthSlider.value=fw; if(secondaryWidthLabel) secondaryWidthLabel.textContent=`${fw}px`; await saveSetting(SECONDARY_WIDTH_PX_KEY, fw); applyStylesToAllRoots(); });
- secondaryJustifyCheckbox.addEventListener('change', async (e) => { await saveSetting(SECONDARY_JUSTIFY_KEY, e.target.checked); applyStylesToAllRoots(); });
- // --- Final UI Setup ---
- updateUIState();
- setTimeout(() => { if (document) document.addEventListener('click', handleClickOutside, true); }, 0);
- if (document.head) injectOrUpdateStyle(document.head, STYLE_ID, generateCss());
- }
- // --- Tampermonkey Menu (Standard) ---
- function updateTampermonkeyMenu() { const cmdId = menuCommandId_ToggleUI; menuCommandId_ToggleUI = null; if (cmdId !== null && typeof GM_unregisterMenuCommand === 'function') try { GM_unregisterMenuCommand(cmdId); } catch (e) { console.warn('Failed unregister', e); } const label = config.uiVisible ? 'Hide Settings Panel' : 'Show Settings Panel'; if (typeof GM_registerMenuCommand === 'function') menuCommandId_ToggleUI = GM_registerMenuCommand(label, async () => { await new Promise(res => setTimeout(res, 50)); const newState = !config.uiVisible; await saveSetting(UI_VISIBLE_KEY, newState); if (newState) createSettingsUI(); else removeSettingsUI(); updateTampermonkeyMenu(); }); }
- // --- Shadow DOM Handling (Standard) ---
- function getShadowRoot(element) { try { return element.shadowRoot; } catch (e) { return null; } }
- function processElement(element) { const shadow = getShadowRoot(element); if (shadow && shadow.nodeType === Node.DOCUMENT_FRAGMENT_NODE && !allStyleRoots.has(shadow)) { allStyleRoots.add(shadow); injectOrUpdateStyle(shadow, STYLE_ID, generateCss()); return true; } return false; }
- // --- Initialization (Standard) ---
- console.log('[Grok Enhanced] Script starting (run-at=document-end)...');
- if (document.head) allStyleRoots.add(document.head); else { const rootNode = document.documentElement || document; allStyleRoots.add(rootNode); console.warn("[Grok Enhanced] document.head not found."); }
- await loadSettings();
- applyStylesToAllRoots();
- let initialRootsFound = 0; try { document.querySelectorAll('*').forEach(el => { if (processElement(el)) initialRootsFound++; }); } catch(e) { console.error("[Grok Enhanced] Error during initial scan:", e); } console.log(`[Grok Enhanced] Initial scan complete. Found ${initialRootsFound} roots.`);
- if (config.uiVisible) createSettingsUI();
- updateTampermonkeyMenu();
- const observer = new MutationObserver((mutations) => { let processedNewNode = false; mutations.forEach((mutation) => { mutation.addedNodes.forEach((node) => { if (node.nodeType === Node.ELEMENT_NODE) try { const elementsToCheck = [node, ...node.querySelectorAll('*')]; elementsToCheck.forEach(el => { if (processElement(el)) processedNewNode = true; }); } catch(e) { console.error("[Grok Enhanced] Error querying descendants:", node, e); } }); }); });
- observer.observe(document.documentElement || document.body || document, { childList: true, subtree: true });
- console.log('[Grok Enhanced] Initialization complete.');
- })();
Advertisement
Add Comment
Please, Sign In to add comment