Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // ==UserScript==
- // @name Highlighted Text Popup
- // @namespace http://www.greasespot.net/
- // @version 1.5 // Incrementing version number for these updates
- // @description Adds a custom right-click menu to display highlighted text in a popup with font size and font family controls.
- // @author Gemini
- // @match *://*/*
- // @grant none
- // ==/UserScript==
- (function() {
- 'use strict';
- console.log("GM_Script: Highlighted Text Popup script started.");
- // --- CSS for Custom Elements (now injected directly via JavaScript) ---
- const css = `
- #gm-custom-context-menu
- {
- position: fixed; /* Ensures it stays in position on scroll */
- background-color: #f9f9f9;
- border: 1px solid #ccc;
- box-shadow: 2px 2px 8px rgba(0,0,0,0.2);
- padding: 5px 0;
- min-width: 180px;
- z-index: 99999; /* Ensure it's on top of most page content */
- display: none; /* Hidden by default */
- font-family: sans-serif;
- font-size: 14px;
- user-select: none; /* Prevent text selection within the menu itself */
- /* NEW POSITIONING: Bottom-right with padding */
- bottom: 20px; /* Padding from the bottom of the viewport */
- right: 20px; /* Padding from the right of the viewport */
- left: auto; /* Ensure 'right' takes precedence over 'left' */
- top: auto; /* Ensure 'bottom' takes precedence over 'top' */
- }
- .gm-context-menu-item
- {
- padding: 8px 15px;
- cursor: pointer;
- color: #333;
- white-space: nowrap;
- }
- .gm-context-menu-item:hover
- {
- background-color: #e0e0e0;
- }
- #gm-text-display-popup
- {
- position: fixed;
- background-color: #ffffff;
- border: 1px solid #a0a0a0;
- box-shadow: 0 4px 12px rgba(0,0,0,0.3);
- padding: 10px; /* Reduced padding to make space for menu bar */
- z-index: 100000; /* Higher than the context menu */
- top: 50%;
- left: 50%;
- transform: translate(-50%, -50%); /* Center the popup */
- max-width: 650px; /* Comfortable reading width */
- width: 90%; /* Responsive width */
- /* UPDATED: More vertical space, 5% buffer top/bottom */
- top: 5%;
- transform: translateX(-50%); /* Only translate horizontally for centering */
- max-height: 90vh; /* 100vh - 5% (top) - 5% (bottom) = 90vh */
- overflow-y: auto; /* Enable vertical scrolling if content exceeds max-height */
- display: none; /* Hidden by default; will be 'flex' when shown */
- font-family: serif; /* Classic reading font fallback */
- line-height: 1.6;
- color: #222;
- box-sizing: border-box; /* Include padding in width/height */
- flex-direction: column; /* Stack children vertically - applied when display:flex */
- }
- #gm-popup-close-button
- {
- position: absolute; /* Position relative to #gm-text-display-popup */
- top: 10px;
- right: 15px;
- background: none;
- border: none;
- font-size: 20px;
- cursor: pointer;
- color: #555;
- padding: 0;
- line-height: 1;
- }
- #gm-popup-close-button:hover
- {
- color: #000;
- }
- #gm-popup-menu-bar
- {
- display: flex;
- align-items: center;
- justify-content: flex-start; /* Align items to the left */
- padding: 5px 10px;
- border-bottom: 1px solid #eee;
- margin-bottom: 10px; /* Space between menu bar and content */
- }
- .gm-font-size-button
- {
- background-color: #e0e0e0;
- border: 1px solid #ccc;
- border-radius: 4px;
- padding: 4px 8px;
- margin: 0 5px; /* Default margin for buttons */
- cursor: pointer;
- font-weight: bold;
- font-size: 14px;
- line-height: 1;
- user-select: none;
- }
- .gm-font-size-button:hover
- {
- background-color: #d0d0d0;
- }
- /* Adjust margin for the first font size button to create left padding */
- .gm-font-size-button:first-of-type {
- margin-left: 15px; /* Moves the '-' button from the left edge */
- }
- .gm-font-size-label
- {
- font-size: 13px;
- color: #666;
- margin: 0 5px;
- }
- .gm-font-family-select {
- margin-left: 15px; /* Space from the font size controls */
- padding: 5px 8px;
- border: 1px solid #ccc;
- border-radius: 4px;
- background-color: #f9f9f9;
- font-size: 13px;
- color: #333;
- cursor: pointer;
- min-width: 150px; /* Ensure enough width for longer names */
- }
- .gm-font-family-select:hover {
- background-color: #efefef;
- }
- #gm-popup-content
- {
- flex-grow: 1; /* Allows content to take up remaining space */
- padding: 10px; /* Add internal padding for content */
- white-space: pre-wrap; /* Preserves whitespace and wraps text */
- word-wrap: break-word; /* Breaks long words */
- overflow-y: auto; /* Ensure content itself scrolls if needed */
- margin-top: 0; /* Remove previous margin-top as menu bar handles spacing */
- }
- `;
- // Create a style element and append the CSS to it
- const styleElement = document.createElement('style');
- styleElement.textContent = css;
- document.head.appendChild(styleElement);
- console.log("GM_Script: CSS injected directly via <style> element.");
- // --- Global Variables and Constants ---
- let highlightedText = '';
- let customMenu;
- let textPopup;
- let popupContent;
- const MIN_FONT_SIZE_PT = 8; // Minimum font size in points
- const MAX_FONT_SIZE_PT = 40; // Maximum font size in points
- const DEFAULT_FONT_SIZE_PT = 17; // UPDATED: Default font size in points
- const FONT_FAMILIES = [
- { name: "Arial", value: "Arial, sans-serif" },
- { name: "Georgia", value: "Georgia, serif" },
- { name: "Times New Roman", value: "Times New Roman, serif" },
- { name: "Verdana", value: "Verdana, sans-serif" },
- { name: "Adobe Garamond Pro", value: '"Adobe Garamond Pro", serif' } // Default font
- ];
- const DEFAULT_FONT_FAMILY_VALUE = '"Adobe Garamond Pro", serif'; // Value for the default font
- // --- Create Custom Context Menu ---
- function createCustomContextMenu()
- {
- console.log("GM_Script: Entering createCustomContextMenu function.");
- customMenu = document.createElement('div');
- customMenu.id = 'gm-custom-context-menu';
- document.body.appendChild(customMenu);
- console.log("GM_Script: Custom menu DIV created and appended to body:", customMenu);
- const menuItem = document.createElement('div');
- menuItem.classList.add('gm-context-menu-item');
- menuItem.textContent = 'Show Highlighted Text in Popup';
- customMenu.appendChild(menuItem);
- console.log("GM_Script: Menu item added to custom menu:", menuItem);
- menuItem.addEventListener('click', function()
- {
- console.log("GM_Script: Custom menu item clicked.");
- highlightedText = window.getSelection().toString().trim();
- console.log("GM_Script: Captured highlighted text (raw):", window.getSelection().toString());
- console.log("GM_Script: Captured highlighted text (trimmed):", highlightedText);
- if (highlightedText)
- {
- popupContent.textContent = highlightedText;
- // Set default font size and family when new text is loaded
- popupContent.style.fontSize = DEFAULT_FONT_SIZE_PT + 'pt';
- popupContent.style.fontFamily = DEFAULT_FONT_FAMILY_VALUE;
- // Reset font family select dropdown to default value in case it was changed
- if (window.gmFontFamilySelect)
- {
- window.gmFontFamilySelect.value = DEFAULT_FONT_FAMILY_VALUE;
- console.log("GM_Script: Font family select dropdown reset to default.");
- }
- textPopup.style.display = 'flex'; // Set display to 'flex' to show the popup and enable flexbox layout
- console.log("GM_Script: Popup content updated and popup displayed.");
- }
- else
- {
- alert('No text highlighted. Please highlight some text first.');
- console.log("GM_Script: No text highlighted, alert shown.");
- }
- customMenu.style.display = 'none'; // Hide menu after selection
- console.log("GM_Script: Custom menu hidden after item click.");
- });
- }
- // --- Create Text Display Popup ---
- function createTextDisplayPopup()
- {
- console.log("GM_Script: Entering createTextDisplayPopup function.");
- textPopup = document.createElement('div');
- textPopup.id = 'gm-text-display-popup';
- document.body.appendChild(textPopup);
- console.log("GM_Script: Popup DIV created and appended to body:", textPopup);
- // Close Button (direct child of textPopup for absolute positioning)
- const closeButton = document.createElement('button');
- closeButton.id = 'gm-popup-close-button';
- closeButton.textContent = '✖'; // Unicode multiplication sign for 'X'
- textPopup.appendChild(closeButton);
- console.log("GM_Script: Close button added to popup.");
- // Menu Bar (contains font controls, direct child of textPopup)
- const menuBar = document.createElement('div');
- menuBar.id = 'gm-popup-menu-bar';
- textPopup.appendChild(menuBar); // Append to textPopup before popupContent
- console.log("GM_Script: Popup menu bar created.");
- // Font Size Controls (inside menuBar)
- const decreaseFontButton = document.createElement('button');
- decreaseFontButton.classList.add('gm-font-size-button');
- decreaseFontButton.textContent = '-';
- menuBar.appendChild(decreaseFontButton);
- console.log("GM_Script: Decrease font button added.");
- const fontSizeLabel = document.createElement('span');
- fontSizeLabel.classList.add('gm-font-size-label');
- fontSizeLabel.textContent = 'font size';
- menuBar.appendChild(fontSizeLabel);
- console.log("GM_Script: Font size label added.");
- const increaseFontButton = document.createElement('button');
- increaseFontButton.classList.add('gm-font-size-button');
- increaseFontButton.textContent = '+';
- menuBar.appendChild(increaseFontButton);
- console.log("GM_Script: Increase font button added.");
- // Font Family Control (inside menuBar)
- const fontFamilySelect = document.createElement('select');
- fontFamilySelect.classList.add('gm-font-family-select');
- menuBar.appendChild(fontFamilySelect);
- console.log("GM_Script: Font family select dropdown created.");
- FONT_FAMILIES.forEach(font => {
- const option = document.createElement('option');
- option.value = font.value;
- option.textContent = font.name;
- fontFamilySelect.appendChild(option);
- });
- // Make the select element accessible globally (or more carefully scoped if preferred for complex scripts)
- window.gmFontFamilySelect = fontFamilySelect; // This allows access from customMenu's click listener
- console.log("GM_Script: Font family options populated and default set.");
- // Content Area (remains same)
- popupContent = document.createElement('div');
- popupContent.id = 'gm-popup-content';
- textPopup.appendChild(popupContent); // Append to textPopup, after menuBar
- console.log("GM_Script: Popup content area added to popup.");
- // Event Listeners for Font Size
- decreaseFontButton.addEventListener('click', function()
- {
- console.log("GM_Script: Decrease font size button clicked.");
- let currentSizePx = parseFloat(window.getComputedStyle(popupContent).fontSize);
- // Convert px to pt for comparison with pt-based limits (1pt = 1/72 inch, 1px = 1/96 inch, so 1px = 0.75pt)
- let currentSizePt = currentSizePx * (72 / 96);
- if (currentSizePt > MIN_FONT_SIZE_PT)
- {
- // Decrement by 1pt and round to nearest whole number
- popupContent.style.fontSize = Math.round(currentSizePt - 1) + 'pt';
- console.log("GM_Script: Font size decreased to:", popupContent.style.fontSize);
- }
- else
- {
- console.log("GM_Script: Minimum font size reached (", MIN_FONT_SIZE_PT, "pt).");
- }
- });
- increaseFontButton.addEventListener('click', function()
- {
- console.log("GM_Script: Increase font size button clicked.");
- let currentSizePx = parseFloat(window.getComputedStyle(popupContent).fontSize);
- let currentSizePt = currentSizePx * (72 / 96);
- if (currentSizePt < MAX_FONT_SIZE_PT)
- {
- // Increment by 1pt and round to nearest whole number
- popupContent.style.fontSize = Math.round(currentSizePt + 1) + 'pt';
- console.log("GM_Script: Font size increased to:", popupContent.style.fontSize);
- }
- else
- {
- console.log("GM_Script: Maximum font size reached (", MAX_FONT_SIZE_PT, "pt).");
- }
- });
- // Event Listener for Font Family
- fontFamilySelect.addEventListener('change', function()
- {
- const selectedFont = this.value;
- popupContent.style.fontFamily = selectedFont;
- console.log("GM_Script: Font family changed to:", selectedFont);
- });
- closeButton.addEventListener('click', function()
- {
- console.log("GM_Script: Popup close button clicked.");
- textPopup.style.display = 'none';
- console.log("GM_Script: Popup hidden.");
- });
- // Make the popup draggable
- let isDragging = false;
- let offsetX, offsetY;
- textPopup.addEventListener('mousedown', function(e)
- {
- // Only allow dragging if not clicking on a button, select, or the main content area.
- // Drag should initiate from the menu bar background or other non-interactive parts.
- if (e.target.closest('.gm-font-size-button') || e.target.closest('.gm-font-family-select') || e.target.id === 'gm-popup-close-button' || e.target.id === 'gm-popup-content')
- {
- console.log("GM_Script: Mousedown on interactive element inside popup, preventing drag.");
- return;
- }
- isDragging = true;
- offsetX = e.clientX - textPopup.getBoundingClientRect().left;
- offsetY = e.clientY - textPopup.getBoundingClientRect().top;
- textPopup.style.cursor = 'grabbing';
- textPopup.style.transition = 'none'; // Disable transition during drag
- console.log("GM_Script: Popup dragging started. Offset X:", offsetX, "Y:", offsetY);
- });
- document.addEventListener('mousemove', function(e)
- {
- if (!isDragging) return;
- textPopup.style.left = (e.clientX - offsetX) + 'px';
- textPopup.style.top = (e.clientY - offsetY) + 'px';
- textPopup.style.transform = 'none'; // Remove transform to allow direct left/top positioning
- });
- document.addEventListener('mouseup', function()
- {
- if (isDragging)
- {
- console.log("GM_Script: Popup dragging ended.");
- }
- isDragging = false;
- textPopup.style.cursor = 'grab';
- textPopup.style.transition = ''; // Re-enable transition
- });
- }
- // --- Event Listeners for Page ---
- document.addEventListener('DOMContentLoaded', function()
- {
- console.log("GM_Script: DOMContentLoaded event fired.");
- createCustomContextMenu();
- createTextDisplayPopup();
- console.log("GM_Script: Custom menu and popup created.");
- });
- document.addEventListener('contextmenu', function(event)
- {
- console.log("GM_Script: 'contextmenu' event detected.");
- // Prevent default browser context menu
- event.preventDefault();
- console.log("GM_Script: Default context menu prevented.");
- // We no longer dynamically position the menu; its position is fixed via CSS (bottom/right)
- customMenu.style.display = 'block';
- console.log("GM_Script: Custom menu displayed at fixed bottom-right position.");
- });
- // Hide custom menu when clicking anywhere else on the page
- document.addEventListener('click', function(event)
- {
- if (customMenu && event.target !== customMenu && !customMenu.contains(event.target))
- {
- if (customMenu.style.display === 'block') {
- console.log("GM_Script: Click outside custom menu detected. Hiding custom menu.");
- }
- customMenu.style.display = 'none';
- }
- });
- // Hide custom menu if scrolling occurs (helps prevent it being off-screen)
- document.addEventListener('scroll', function()
- {
- if (customMenu && customMenu.style.display === 'block')
- {
- console.log("GM_Script: Scroll detected. Hiding custom menu.");
- customMenu.style.display = 'none';
- }
- }, true); // Use capture phase for better reliability
- })();
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement