The Official Power User Tips, Tricks & Productivity Thread

bnew

Veteran
Joined
Nov 1, 2015
Messages
55,699
Reputation
8,224
Daps
157,237
while trying to firegure out how to embed bluesky posts i cam across a post by the author of the xenforo media plugin and he said he doesn't explicity support adult conetnt sites so i decided to create embed support for redgifs urls.

created with llama 3.1 sonar large 128k chat

Bookmarklets and Userscripts Overview​


  1. Purpose:
    • These scripts are designed to replace links to RedGIFs videos on a webpage with embedded iframes, allowing you to watch the videos directly on the page.
  2. Functionality:
    • Without Blur:
      • When you click the bookmarklet or enable the userscript, it finds all links to RedGIFs videos on the page and replaces them with iframes. This lets you watch the videos without leaving the page.
    • With Blur:
      • In addition to embedding the videos, this version also blurs the iframes initially. You can click on the blurred area to unblur it and watch the video as normal.

Detailed Explanation​


  • Finding Links:
    • The scripts look for links that point to RedGIFs videos.
    • They check both regular links (<a> tags) and image links (<img> tags) with a data-url attribute.
  • Replacing Links with Iframes:
    • When a RedGIFs link is found, it is replaced with an iframe that shows the video.
    • The iframe source URL is constructed by changing "watch" to "ifr" in the original link.
  • Blur Functionality:
    • For the blurred version, an overlay is added over the iframe.
    • When you click on this overlay, it removes the blur effect, allowing you to watch the video.
  • Userscripts vs Bookmarklets:
    • Bookmarklets: These are small pieces of JavaScript code that you can save as bookmarks in your browser. When clicked, they run on the current webpage.
    • Userscripts: These are scripts that run automatically on specific websites when you have a userscript manager like Tampermonkey or Greasemonkey installed.

In Simple Terms​


  • Without Blur:
    • Clicking the bookmarklet or enabling the userscript will turn RedGIFs links into playable videos right on the page.
  • With Blur:
    • The same as above, but the videos will be blurred until you click on them to unblur and watch.
This way, you can easily watch RedGIFs videos directly on any webpage without having to navigate away from it.

Bookmarklet Without Blur Functionality​




Bookmarklet With Blur Functionality​


Original Code to Final Code Changes
1. Lazy Loading of Iframes

Original: Iframes were loaded immediately upon replacing the links and images.
Final: Iframes are now loaded lazily using IntersectionObserver to load them only when they come into view.

2. Placeholder Elements

Original: Directly replaced elements with iframes.
Final: Replaced elements with placeholder divs, which are then replaced with iframes when they come into view.

3. Data Attribute for iframeSrc

Original: iframeSrc was constructed and used immediately.
Final: iframeSrc is stored in a data attribute of the wrapper div for later use when loading the iframe.

4. Preload Attribute

Original: No preload attribute was used.
Final: Added preload="metadata" to iframes to reduce initial load times by only loading metadata initially.

5. Pause/Play on Visibility

Original: No management of video playback based on visibility.
Final: Implemented an IntersectionObserver to pause/play videos based on their visibility to save CPU and memory resources.

6. Event Handling Refinement

Original: Click event listener was added to unblur iframes.
Final: Click event listener now also loads the iframe if it hasn't been loaded yet, ensuring that iframes are loaded either on click or when they come into view.

7. Error Handling and Null Checks

Original: No explicit checks for null values.
Final: Added checks to ensure that url, href, and data-url attributes are not null before using them.

Layman's Terms Summary

Lazy Loading: Instead of loading all videos at once, the new code loads them only when you scroll to where they are on the page. This saves a lot of memory and CPU power.
Placeholder Elements: Before loading a video, a placeholder is shown. This helps in managing resources better.
Efficient Data Storage: The video URL is stored in a hidden attribute of the placeholder until it's needed, making the code more efficient.
Preloading Metadata: When loading videos, only the metadata (like video length) is loaded first, reducing initial load times.
Pause/Play Videos: Videos are paused when you scroll away from them and resume playing when you scroll back. This saves resources by not playing videos that are not visible.
Improved Event Handling: Clicking on a blurred video now loads it if it hasn't been loaded yet, ensuring that videos are loaded either when you click on them or when they come into view.
Error Prevention: The new code checks for potential errors like missing URLs before trying to load videos, making it more robust.

These changes make the bookmarklet more efficient, reducing memory and CPU usage while still providing a smooth user experience.


Userscripts​


Userscript Without Blur Functionality​




Userscript With Blur Functionality​




Explanation​


  • Bookmarklets:
    • The first bookmarklet replaces RedGIFs links with iframes without any blur functionality.
    • The second bookmarklet includes blur functionality and an overlay to capture clicks.
  • Userscripts:
    • The first userscript replaces RedGIFs links with iframes without any blur functionality.
    • The second userscript includes blur functionality and an overlay to capture clicks, similar to the bookmarklet.
These scripts should help you achieve your desired functionality for both bookmarklets and userscripts.

edit:
just noticed the bookmarklets have a // comments in them so they won't work when you add it as a bookmark, :snoop:
you'll have to manually remove those lines like // Construct iframe source URL by replacing 'watch' with 'ifr' before adding it to bookmarks but it'll run just fine in browser console.
 
Last edited:

bnew

Veteran
Joined
Nov 1, 2015
Messages
55,699
Reputation
8,224
Daps
157,237
I was annoyed by having to constantly disable javascript for some one-off sites I come across that manage to still show nagging screens asking for a email or to join, they usually disable the scroll bar even after i delete nag screen element and disabling javascript would restore it again. It's either that or waste time inspecting the network log to see wch script i have to disable. so I had an Iead to get a LLM to write me a bookmarklet to restore the scrollbar, only took two attempts too.

created with llama-3.1-sonar-large-128k-chat:
JavaScript:
javascript:(function(){function restoreScrollbar(){document.body.style.overflow='auto';document.documentElement.style.overflow='auto';var elements=document.querySelectorAll('*');elements.forEach(function(element){element.style.overflow='';});setInterval(function(){document.body.style.overflow='auto';document.documentElement.style.overflow='auto';elements.forEach(function(element){element.style.overflow='';});},100);}restoreScrollbar();})();

The code creates a small tool (called a bookmarklet) that you can click to restore the scrollbar on a webpage if it has been hidden by another script. Here's what it does:
  1. Fixes the Scrollbar: When you click the bookmarklet, it sets the webpage's settings back to normal so that the scrollbar appears.
  2. Keeps Checking: To make sure the scrollbar stays visible, the code checks every 0.1 seconds (100 milliseconds) and re-applies the fix if necessary.
This way, even if another script tries to hide the scrollbar again, this tool will keep restoring it, ensuring you can always see and use your scrollbar.


only tested it on this site and it worked.


edit:

converted to a userscript :manny:

 
Last edited:

bnew

Veteran
Joined
Nov 1, 2015
Messages
55,699
Reputation
8,224
Daps
157,237
I reached my gpt-4o message limit so I used llama-3-sonar-large-32k-chat to make additional modifications to the code I now know works,

Code:
# Import necessary assemblies for the GUI
Add-Type -AssemblyName PresentationFramework

function Create-MainWindow {
    [xml]$xaml = @"
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="ChatGPT Text Splitter" Height="500" Width="800" ResizeMode="CanResizeWithGrip">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>

        <!-- Header -->
        <TextBlock Grid.Row="0" Text="ChatGPT Text Splitter" FontSize="20" FontWeight="Bold" Margin="10" HorizontalAlignment="Center"/>

        <!-- Content Area -->
        <DockPanel Grid.Row="1" Margin="10">
            <StackPanel DockPanel.Dock="Top" Orientation="Vertical">
                <TextBox Name="InputTextBox" AcceptsReturn="True" VerticalScrollBarVisibility="Auto" Height="200" Margin="0,0,0,10"/>
                <TextBlock Name="CharCountText" Text="Characters: 0" Margin="0,0,0,5"/>
                <TextBlock Name="WordCountText" Text="Words: 0" Margin="0,0,0,5"/>
                <TextBlock Name="ParagraphCountText" Text="Paragraphs: 0" Margin="0,0,0,10"/>
                <StackPanel Orientation="Horizontal" Margin="0">
                    <TextBlock Text="Max Characters Per Part:" VerticalAlignment="Center" Margin="0,0,5,0"/>
                    <TextBox Name="MaxCharCountTextBox" Width="100" Text="2048" Margin="0,0,5,0"/>
                    <Button Name="SplitButton" Content="Split" Width="100" Margin="0,0,5,0" HorizontalAlignment="Right"/>
                </StackPanel>
            </StackPanel>
            <ScrollViewer DockPanel.Dock="Bottom" Height="200" VerticalScrollBarVisibility="Auto">
                <StackPanel Name="OutputStackPanel" Orientation="Vertical"/>
            </ScrollViewer>
            <ProgressBar Name="ProgressBar" Visibility="Collapsed" Height="20" Margin="10" />
        </DockPanel>

        <!-- Footer -->
        <TextBlock Grid.Row="2" Text="© 2024 Your Company" HorizontalAlignment="Center" Margin="10"/>
    </Grid>
</Window>
"@

    $reader = (New-Object System.Xml.XmlNodeReader $xaml)
    $window = [Windows.Markup.XamlReader]::Load($reader)

    # Find elements
    $inputTextBox = $window.FindName("InputTextBox")
    $charCountText = $window.FindName("CharCountText")
    $wordCountText = $window.FindName("WordCountText")
    $paragraphCountText = $window.FindName("ParagraphCountText")
    $splitButton = $window.FindName("SplitButton")
    $outputStackPanel = $window.FindName("OutputStackPanel")
    $maxCharCountTextBox = $window.FindName("MaxCharCountTextBox")
    $progressBar = $window.FindName("ProgressBar")

    # Event Handlers
    $inputTextBox.Add_TextChanged({
        $charCountText.Text = "Characters: " + $inputTextBox.Text.Length
        $wordCountText.Text = "Words: " + ($inputTextBox.Text -split '\s+').Count
        $paragraphCountText.Text = "Paragraphs: " + ($inputTextBox.Text -split '\r\n|\r|\n').Count
    })

    $splitButton.Add_Click({
        $progressBar.Visibility = "Visible"
        $outputStackPanel.Children.Clear()
        $text = $inputTextBox.Text
        [int]$maxCharCount = [int]$maxCharCountTextBox.Text
        $parts = [math]::Ceiling($text.Length / $maxCharCount)
        $quickCopyButtonStackPanel = New-Object System.Windows.Controls.WrapPanel
        $quickCopyButtonStackPanel.Orientation = "Horizontal"
        for ($i = 0; $i -lt $parts; $i++) {
            $start = $i * $maxCharCount
            $length = [math]::Min($maxCharCount, $text.Length - $start)
            $partText = $text.Substring($start, $length)
            $partLabel = "Part " + ($i + 1) + " of " + $parts
            $outputText = "Do not answer yet. This is just another part of the text I want to send you. Just receive and acknowledge as `$partLabel` and wait for the next part.`n[START $partLabel]`n$partText"
            $textBox = New-Object System.Windows.Controls.TextBox
            $textBox.Text = $outputText
            $textBox.Margin = "0,0,0,10"
            $textBox.AcceptsReturn = $true
            $textBox.VerticalScrollBarVisibility = "Auto"
            $textBox.IsReadOnly = $true
            $textBox.MaxLines = 8
            $textBox.VerticalScrollBarVisibility = "Auto"
            $textBox.HorizontalScrollBarVisibility = "Auto"
            $textBox.ResizeMode = "CanResizeWithGrip"
            $copyButton = New-Object System.Windows.Controls.Button
            $copyButton.Content = "Copy"
            $copyButton.Tag = $outputText
            $copyButton.Add_Click({
                $currentButton = $_.Source
                [System.Windows.Clipboard]::SetText($currentButton.Tag)
            })
            $quickCopyButton = New-Object System.Windows.Controls.Button
            $quickCopyButton.Content = "Copy " + ($i + 1) + "/" + $parts
            $quickCopyButton.Tag = $outputText
            $quickCopyButton.Add_Click({
                if ($quickCopyButton.Background -eq "LightBlue") {
                    $quickCopyButton.Background = "Transparent"
                } else {
                    $quickCopyButton.Background = "LightBlue"
                }
                $currentButton = $_.Source
                [System.Windows.Clipboard]::SetText($currentButton.Tag)
            })
            $quickCopyButtonStackPanel.Children.Add($quickCopyButton)
            $stackPanel = New-Object System.Windows.Controls.StackPanel
            $stackPanel.Orientation = "Vertical"
            $stackPanel.Children.Add($textBox)
            $stackPanel.Children.Add($copyButton)
            $separator = New-Object System.Windows.Controls.Separator
            $separator.Margin = "0,5,0,5"
            $outputStackPanel.Children.Add($quickCopyButtonStackPanel)
            $outputStackPanel.Children.Add($stackPanel)
            $outputStackPanel.Children.Add($separator)
        }
        $progressBar.Visibility = "Collapsed"
    })

    # Show the window
    $window.ShowDialog() | Out-Null
}

Create-MainWindow
qDCnqrd.png


A.I Generated changelog:

1. **Reorganized layout**: The layout of the content area has been reorganized to improve usability. The max character count text box, split button, and progress bar are now aligned horizontally.
2. **Added progress bar**: A progress bar has been added to the GUI to indicate when the text is being split.
3. **Improved text box functionality**: The text boxes now have a maximum number of lines set to 8, and they can be resized with a grip.
4. **Added quick copy buttons**: Quick copy buttons have been added to allow users to quickly copy each part of the text without having to open each text box.
5. **Improved copy button functionality**: The copy buttons now toggle their background color when clicked to indicate that the text has been copied.
6. **Added separators**: Separators have been added between each part of the text to improve readability.
7. **Improved performance**: The progress bar is now shown while the text is being split, and hidden when the operation is complete, to improve the user experience.

* The XAML code has been reformatted for better readability.

couldn't get the script to run on my laptop even though it worked on my desktop so i went looking for another offline solution and found this:

tip: edit script.js line 6 const WORDS_LIMIT = 450 to 2500 since more llms these days have larger token inputs.


Text Splitter: A Simple Tool for Working with Long Texts and Generative AI​

This project provides a user-friendly interface for splitting large text files into smaller, more manageable sections suitable for use with generative AI models like Gemini and ChatGPT, which often have character limitations.

Features:

Simple and Intuitive: Drag and drop or upload your text file and specify the desired maximum characters per section.
Customizable Splitting: Choose the ideal character limit for your specific AI model and task.
Preserves Formatting: Optionally, maintain basic formatting (paragraphs, line breaks) during the splitting process.
Static and Offline: Works entirely in your browser, requiring no installation or external servers.
Benefits:

Study Aid: Quickly generate summaries of long texts (e.g., books) using generative AI models.
Content Management: Break down lengthy content into digestible chunks for easier online consumption.
AI Experimentation: Explore the capabilities of generative AI models with different text lengths.
Offline Processing: Utilize the tool even without an internet connection.
Technologies:

HTML: Structures the user interface and content flow.
CSS: Styles the visual elements for a clean and user-friendly experience.
JavaScript: Implements the text splitting logic and user interaction.
Getting Started:

Live Demo
Clone this repository or download the project files.
Open index.html in your web browser.
Type or copy and paste your text into the designated area.
Click "Split Text."
The split sections will be displayed below, ready for copying and pasting into your chosen AI model.
 

bnew

Veteran
Joined
Nov 1, 2015
Messages
55,699
Reputation
8,224
Daps
157,237
I got tired of constantly opening inspector tools to copy element code so I created this bookmarklet code using llama-3.1-sonar-large-128k-chat to easily use a picker and highlight the element and copy to clipboard.

What the Code Does:

  1. Highlight Elements: When you click on any part of a webpage, it highlights that part in red.
  2. Copy HTML: It copies the HTML code of what you've highlighted to your clipboard.
  3. Show Messages: It shows messages at the bottom left corner of your screen when you copy something or exit.
  4. Exit Functionality: You can press "Q" or "ESC" keys to stop highlighting and return your webpage to its normal state without any lingering notifications.
In Simple Terms:

  • This code helps you select parts of a webpage by clicking on them.
  • It copies the underlying HTML code of what you've selected.
  • It shows you messages about what's happening (like "HTML copied").
  • You can stop using it by pressing "Q" or "ESC", which returns everything back to normal without leaving any notifications behind.
This makes it easy for users to inspect and copy HTML elements from webpages with just a few clicks and key presses.


I use it in combination with


JavaScript:
javascript:(function(){
    let currentElement = null;
    let notifications = [];
    const maxNotifications = 3;

    function handleClick(event) {
        if (currentElement) {
            currentElement.classList.remove('highlight');
        }
        
        currentElement = event.target;
        currentElement.classList.add('highlight');

        navigator.clipboard.writeText(currentElement.outerHTML)
            .then(() => {
                console.log("HTML copied to clipboard");
                showNotification("HTML copied to clipboard. Press Q or ESC to exit.");
            })
            .catch(err => console.error("Could not copy text: ", err));
    }

    function handleKeyPress(event) {
        if (event.key === 'q' || event.key === 'Escape') {
            document.body.removeEventListener('click', handleClick);
            document.body.removeEventListener('keydown', handleKeyPress);

            const highlightedElements = document.querySelectorAll('.highlight');
            highlightedElements.forEach(element => element.classList.remove('highlight'));

            const notificationStyle = document.querySelector('style.notification-style');
            if (notificationStyle) {
                notificationStyle.remove();
            }

            const notificationsList = document.querySelectorAll('.notification');
            notificationsList.forEach(notification => notification.remove());

            notifications.length = 0;

            showNotification("Bookmarklet exited. Press Q or ESC to exit next time.");
            setTimeout(() => {
                const exitNotification = document.querySelector('.notification');
                if (exitNotification) {
                    exitNotification.remove();
                }
            }, 2000);
        }
    }

    function showNotification(message) {
        const notification = document.createElement('div');
        notification.textContent = message;
        notification.className = 'notification';

        notifications.push(notification);
        if (notifications.length > maxNotifications) {
            const oldestNotification = notifications.shift();
            oldestNotification.remove();
        }

        document.body.appendChild(notification);

        const notificationHeight = notification.offsetHeight;
        const bottomOffset = (notifications.length - 1) * notificationHeight;
        notification.style.bottom = `${bottomOffset}px`;
        
        const existingStyle = document.querySelector('style.notification-style');
        if (!existingStyle) {
            const style = document.createElement('style');
            style.className = 'notification-style';
            style.textContent = `
                .highlight {
                    border: 2px solid red;
                    box-shadow: 0 0 10px rgba(255, 0, 0, 0.5);
                }
                .notification {
                    position: fixed;
                    left: 10px;
                    bottom: 10px;
                    background-color: #fff;
                    border: 1px solid #ddd;
                    padding: 5px;
                    width: 200px;
                    z-index: 1000;
                    box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
                }
            `;
            document.head.appendChild(style);
        }
    }

    document.body.addEventListener('click', handleClick);
    document.body.addEventListener('keydown', handleKeyPress);

    showNotification("Click an element to copy its HTML. Press Q or ESC to exit.");
})();
 

bnew

Veteran
Joined
Nov 1, 2015
Messages
55,699
Reputation
8,224
Daps
157,237
needed a way to quickly change the Title of a webpage instead of using the save as dialog to do so.

What This Code Does:
  • Creates a Pop-Up Window: When you click on this bookmarklet, it opens a small window in the middle of your screen.
  • Shows Original Title: This window shows you what the current title of the webpage is.
  • Allows Title Change: You can type a new title into an input box in this window.
  • Buttons to Control:
    • Original Button: Clicking this button puts the original title back into the input box.
    • OK Button: Clicking this button changes the webpage's title to what you typed and closes the window.
    • Cancel Button: Clicking this button closes the window without changing anything.
  • Hotkeys: You can also use keyboard shortcuts (Enter to save changes, Esc to cancel) instead of clicking buttons.
  • Adjusts Input Box Size: The input box automatically adjusts its size so you can see all of your typed text without needing to scroll.
In simple terms, this code helps you easily change a webpage's title without reloading the page, with convenient buttons and keyboard shortcuts.

screenshot:

dgtApQ0.png


JavaScript:
javascript:(function(){
    var originalTitle = document.title;

    var dialog = document.createElement('div');
    dialog.style.position = 'fixed';
    dialog.style.top = '50%';
    dialog.style.left = '50%';
    dialog.style.transform = 'translate(-50%, -50%)';
    dialog.style.padding = '20px';
    dialog.style.borderRadius = '10px';
    dialog.style.boxShadow = '0 0 10px rgba(0,0,0,0.5)';
    dialog.style.backgroundColor = '#fff';
    dialog.style.zIndex = '1000';
    dialog.style.width = 'auto';
    dialog.style.maxWidth = '90%';

    var html = `
        <h2>Change Title</h2>
        <p>Original Title: <span id="original-title">${originalTitle}</span></p>
        <button id="restore-original" style="background-color: #4CAF50; color: white; padding: 10px 20px; border: none; border-radius: 5px; cursor: pointer;">Original</button>
        <input type="text" id="new-title" value="${originalTitle}" />
        <button id="ok" style="background-color: #4CAF50; color: white; padding: 10px 20px; border: none; border-radius: 5px; cursor: pointer;">OK</button>
        <button id="cancel" style="background-color: #4CAF50; color: white; padding: 10px 20px; border: none; border-radius: 5px; cursor: pointer;">Cancel</button>
    `;

    dialog.innerHTML = html;

    document.body.appendChild(dialog);

    document.getElementById('restore-original').addEventListener('click', function() {
        document.getElementById('new-title').value = originalTitle;
    });

    document.getElementById('ok').addEventListener('click', function() {
        var newTitle = document.getElementById('new-title').value;
        document.title = newTitle;
        dialog.remove();
    });

    document.getElementById('cancel').addEventListener('click', function() {
        dialog.remove();
    });

   
    document.addEventListener('keydown', function(event) {
        if (event.key === 'Enter') {
            var newTitle = document.getElementById('new-title').value;
            document.title = newTitle;
            dialog.remove();
        } else if (event.key === 'Escape') {
            dialog.remove();
        }
    });

   
    var inputField = document.getElementById('new-title');
    inputField.style.width = (inputField.value.length * 8) + 'px';

    inputField.addEventListener('input', function() {
        inputField.style.width = (inputField.value.length * 8) + 'px';
    });
})();



edit:

added

Predefined Rules: You can select from predefined rules like appending "()" or prepending "[bookmarklet]" to your title from a dropdown menu.


screenshot:
1swLCJg.png




This on has a sanitize option to make the title compatible with windows filenames.

m2GaoVW.png


 
Last edited:

bnew

Veteran
Joined
Nov 1, 2015
Messages
55,699
Reputation
8,224
Daps
157,237
found a usersript here and decided to fork it for use on thecoli using llama-3.1-sonar-large-128k-chat and claude sonnet 3.5


or



default:
1lyBEDq.png


after you click on the button:
MB2ZSFU.gif


after you open the smiley menu, you have to click inside the form field to get the blinking cursor than click on the smiley to insert.


you can add your own preferred urls to the userscript too using the same url format thats easy to follow .. use chatgpt/LLM if you want to add multiple smilie urls and format it the way as seen in the userscript.


A.I generated:

Summary​

  1. Smiley Collection:
    • The script gathers a list of URLs for various smiley images.
  2. Container Creation:
    • It creates a container (a div element) where these smiley images will be displayed.
    • This container is initially hidden and can be toggled on and off using a "Show/hide Smilies" button.
  3. Display Settings:
    • The container is set to display at least three rows of smileys by default.
    • It is also made scrollable if there are more than three rows of smileys.
  4. Lazy Loading:
    • Instead of loading all the smiley images immediately, they are loaded only when the container becomes visible.
      • Initially, placeholder images are used.
      • When you click the "Show/hide Smilies" button to show the container, the actual smiley images are loaded.
  5. Insertion Functionality:
    • When you click on a smiley image, it inserts that image into the editable text area where you are typing.
  6. Toggle Button:
    • The "Show/hide Smilies" button allows you to show or hide the smiley container.
      • When you click this button to show the container, it loads the actual smiley images.
  7. Integration:
    • The script inserts the toggle button and the smiley container above or below the first editable field on the page, ensuring it does not interfere with the content editable area.

Key Points​

  • Lazy Loading: Smiley images are loaded only when needed (when you show the container), improving performance.
  • Rows and Scrollability: The container maintains its initial height and allows scrolling if there are many smileys.
  • Toggle Button: Easily show or hide the smiley container using a button.
  • Insertion: Clicking on a smiley image inserts it into your editable text area.
This setup enhances user experience by providing an easy way to insert various smileys while optimizing performance through lazy loading.

edit:

YIKES! I didn't do a thorough enough bug test. I think it's looks to insert the show/hide button under the first input field it finds. 😬

X4ueeIJ.png

Updated to address some bugs where it inserted images outside the input area.



 

bnew

Veteran
Joined
Nov 1, 2015
Messages
55,699
Reputation
8,224
Daps
157,237
instead of scrolling and highlighting, i just select an element with this bookmarklet which is a twist on a previous bookmarklet and it copies the contents of the selected element.

I used llama-3.1-sonar-large-128k-chat to create it.

What the Code Does:
  • Copy Content: When you click on an element on a webpage, this code copies the content of that element to your clipboard.
  • Preserve Formatting: It ensures that the formatting (like bold, italics, colors) of the content is preserved when you paste it.
  • User Interaction: The code requires you to click on an element to trigger the copy action, which is a security measure to prevent websites from accessing your clipboard without your consent.
  • Notifications: It shows notifications to let you know when the content has been copied and how to exit the bookmarklet.
How It Works:
  • Extract HTML and Text: The code gets both the HTML and plain text versions of the clicked element.
  • Create Clipboard Item: It combines these into a special object that can be written to the clipboard.
  • Write to Clipboard: The code uses the modern navigator.clipboard API to write this object to the clipboard.
  • Handle Events: It listens for keyboard events to exit the bookmarklet when you press 'Q' or 'Escape'.
This approach ensures that the copied content retains its original formatting when pasted, similar to how it would if you manually highlighted and copied the content using your mouse and keyboard.

JavaScript:
javascript:(function(){
    let currentElement = null;
    let notifications = [];
    const maxNotifications = 3;

    function handleClick(event) {
        if (currentElement) {
            currentElement.classList.remove('highlight');
        }
        
        currentElement = event.target;
        currentElement.classList.add('highlight');

        const htmlContent = currentElement.outerHTML;
        const plainTextContent = currentElement.innerText;

        const clipboardItem = new ClipboardItem({
            "text/html": new Blob([htmlContent], { type: "text/html" }),
            "text/plain": new Blob([plainTextContent], { type: "text/plain" }),
        });

        navigator.clipboard.write([clipboardItem])
            .then(() => {
                console.log("Content copied to clipboard");
                showNotification("Content copied to clipboard. Press Q or ESC to exit.");
            })
            .catch(err => console.error("Could not copy text: ", err));
    }

    function handleKeyPress(event) {
        if (event.key === 'q' || event.key === 'Escape') {
            document.body.removeEventListener('click', handleClick);
            document.body.removeEventListener('keydown', handleKeyPress);

            const highlightedElements = document.querySelectorAll('.highlight');
            highlightedElements.forEach(element => element.classList.remove('highlight'));

            const notificationStyle = document.querySelector('style.notification-style');
            if (notificationStyle) {
                notificationStyle.remove();
            }

            const notificationsList = document.querySelectorAll('.notification');
            notificationsList.forEach(notification => notification.remove());

            notifications.length = 0;

            showNotification("Bookmarklet exited. Press Q or ESC to exit next time.");
            setTimeout(() => {
                const exitNotification = document.querySelector('.notification');
                if (exitNotification) {
                    exitNotification.remove();
                }
            }, 2000);
        }
    }

    function showNotification(message) {
        const notification = document.createElement('div');
        notification.textContent = message;
        notification.className = 'notification';

        notifications.push(notification);
        if (notifications.length > maxNotifications) {
            const oldestNotification = notifications.shift();
            oldestNotification.remove();
        }

        document.body.appendChild(notification);

        const notificationHeight = notification.offsetHeight;
        const bottomOffset = (notifications.length - 1) * notificationHeight;
        notification.style.bottom = `${bottomOffset}px`;
        
        const existingStyle = document.querySelector('style.notification-style');
        if (!existingStyle) {
            const style = document.createElement('style');
            style.className = 'notification-style';
            style.textContent = `
                .highlight {
                    border: 2px solid red;
                    box-shadow: 0 0 10px rgba(255, 0, 0, 0.5);
                }
                .notification {
                    position: fixed;
                    left: 10px;
                    bottom: 10px;
                    background-color: #fff;
                    border: 1px solid #ddd;
                    padding: 5px;
                    width: 200px;
                    z-index: 1000;
                    box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
                }
            `;
            document.head.appendChild(style);
        }
    }

    document.body.addEventListener('click', handleClick);
    document.body.addEventListener('keydown', handleKeyPress);

    showNotification("Click an element to copy its content. Press Q or ESC to exit.");
})();

edit
9/15/2024

updated to add an highlight effect when you hover over a element so you don't have to constantly click around to get the right one copied to clipboard

rVFVnUV.png


Code:
javascript:(function(){ 
    let currentElement = null; 
    let notifications = []; 
    const maxNotifications = 3;

    function handleClick(event) {
        if (currentElement) { 
            currentElement.classList.remove('highlight'); 
        }

        currentElement = event.target; 
        currentElement.classList.add('highlight');

        const htmlContent = currentElement.outerHTML; 
        const plainTextContent = currentElement.innerText;

        const clipboardItem = new ClipboardItem({ 
            "text/html": new Blob([htmlContent], { type: "text/html" }), 
            "text/plain": new Blob([plainTextContent], { type: "text/plain" }), 
        });

        navigator.clipboard.write([clipboardItem])
            .then(() => { 
                console.log("Content copied to clipboard"); 
                showNotification("Content copied to clipboard. Press Q or ESC to exit."); 
            })
            .catch(err => console.error("Could not copy text: ", err));
    }

    function handleMouseOver(event) {
        event.target.classList.add('hover');
    }

    function handleMouseOut(event) {
        event.target.classList.remove('hover');
    }

    function handleKeyPress(event) {
        if (event.key === 'q' || event.key === 'Escape') { 
            document.body.removeEventListener('click', handleClick); 
            document.body.removeEventListener('keydown', handleKeyPress);
            document.body.removeEventListener('mouseover', handleMouseOver);
            document.body.removeEventListener('mouseout', handleMouseOut);

            const highlightedElements = document.querySelectorAll('.highlight'); 
            highlightedElements.forEach(element => element.classList.remove('highlight'));

            const hoverElements = document.querySelectorAll('.hover'); 
            hoverElements.forEach(element => element.classList.remove('hover'));

            const notificationStyle = document.querySelector('style.notification-style'); 
            if (notificationStyle) { 
                notificationStyle.remove(); 
            }

            const notificationsList = document.querySelectorAll('.notification'); 
            notificationsList.forEach(notification => notification.remove());

            notifications.length = 0;

            showNotification("Bookmarklet exited. Press Q or ESC to exit next time.");
            setTimeout(() => { 
                const exitNotification = document.querySelector('.notification'); 
                if (exitNotification) { 
                    exitNotification.remove(); 
                } 
            }, 2000);
        }
    }

    function showNotification(message) {
        const notification = document.createElement('div');
        notification.textContent = message;
        notification.className = 'notification';

        notifications.push(notification);
        if (notifications.length > maxNotifications) {
            const oldestNotification = notifications.shift();
            oldestNotification.remove();
        }

        document.body.appendChild(notification);

        const notificationHeight = notification.offsetHeight;
        const bottomOffset = (notifications.length - 1) * notificationHeight;
        notification.style.bottom = `${bottomOffset}px`;

        const existingStyle = document.querySelector('style.notification-style');
        if (!existingStyle) {
            const style = document.createElement('style');
            style.className = 'notification-style';
            style.textContent = `
                .highlight {
                    border: 2px solid red;
                    box-shadow: 0 0 10px rgba(255, 0, 0, 0.5);
                    background-color: rgba(255, 0, 0, 0.2); /* Add semi-transparent background */
                }
                .hover {
                    border: 1px dashed blue; /* Add dashed blue border on hover */
                    box-shadow: 0 0 5px rgba(0, 0, 255, 0.3); /* Add light blue shadow on hover */
                }
                .notification {
                    position: fixed;
                    left: 10px;
                    bottom: 10px;
                    background-color: #fff;
                    border: 1px solid #ddd;
                    padding: 5px;
                    width: 200px;
                    z-index: 1000;
                    box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
                }
            `;
            document.head.appendChild(style);
        }
    }

    document.body.addEventListener('click', handleClick);
    document.body.addEventListener('keydown', handleKeyPress);
    document.body.addEventListener('mouseover', handleMouseOver);
    document.body.addEventListener('mouseout', handleMouseOut);

    showNotification("Hover over an element to see what will be copied. Click an element to copy its content. Press Q or ESC to exit.");
})();

10/2/24
another version



What Changed?

The code is now easier to read because it's broken down into smaller, manageable parts.
The way the script handles copying content to the clipboard is more modern and easier to understand.
Error messages are now shown to users if something goes wrong while copying content.
The styling of highlighted elements and notifications is now more organized and maintained separately from the JavaScript code.
The script should work better across different browsers without needing extra checks.
The notification system has been optimized for better performance.
Accessibility has been improved by using better practices in styling.

Why These Changes Matter?

These changes make the code more maintainable, readable, and efficient.
Users will get better feedback if there are errors during the copying process.
The script will work more smoothly across various browsers.
Performance improvements ensure that the bookmarklet doesn't slow down your browser.

Overall, these changes enhance the usability, performance, and maintainability of your bookmarklet.
 
Last edited:

bnew

Veteran
Joined
Nov 1, 2015
Messages
55,699
Reputation
8,224
Daps
157,237
I had an issue with the CSS of a saved .html file not being correct so I needed to apply the correct one and view it using stylus addon which i rarely ever used. wrote a bookmarklet to quickly copy CSS to clipboard but it wasn't working so this one inserts a temporary button on the webpage when press it'll copy the css to clipboard and disappear.

created with llama-3.1 sonar large 128k chat

Detailed Explanation​

This JavaScript code is designed to extract and copy the CSS styles from a webpage. Here's a step-by-step breakdown of what the code does:
  1. Extract CSS Rules:
    • The extractCssRules function takes a stylesheet as input and extracts its CSS rules.
    • It handles potential errors and logs them to the console.
    • It also prepends the domain of the current site to any relative URLs found in the CSS rules.
  2. Combine CSS Content:
    • The combineCss function iterates through all stylesheets on the page and combines their extracted CSS rules into a single string.
  3. Show CSS in Popup:
    • The showCssInPopup function creates a popup window with a textarea containing the combined CSS content.
    • It includes buttons to copy the content to the clipboard and to close the popup.
  4. Notification Function:
    • The showNotification function displays a brief notification at the lower left corner of the webpage when the content is copied to the clipboard.
  5. Floating Copy Button:
    • The createFloatingCopyButton function creates a floating button that appears at the bottom right corner of the viewport.
    • When clicked, this button copies the combined CSS content to the clipboard, shows a notification, and then removes itself.
  6. Main Logic:
    • A button labeled "Show CSS" is created and appended to the page.
    • When this button is clicked, it opens the popup window with the CSS content.
    • The floating copy button is also created and appended to the page.
What the Code Does:
  1. Extracts Webpage Styles: The code collects all the CSS styles from a webpage.
  2. Combines Styles: It puts all these styles together into one big string.
  3. Shows Styles in Popup: When you click a button, it shows these styles in a popup window.
  4. Copies to Clipboard: You can copy these styles to your clipboard from either the popup or a floating button at the bottom right corner of the page.
  5. Notifies You: After copying, it shows a brief message saying that the styles have been copied.
In Simple Terms:
  • Collects Webpage Styles: Gets all the CSS code from a webpage.
  • Displays in Popup: Shows this code in a popup window when you click a button.
  • Copies Easily: Allows you to copy this code to your clipboard using either the popup or a convenient floating button.
  • Notifies Success: Tells you when the code has been successfully copied.
This makes it easy to get and use the CSS styles from any webpage

it stays on the webpage until you press it.
1bYzcC3.png


 

bnew

Veteran
Joined
Nov 1, 2015
Messages
55,699
Reputation
8,224
Daps
157,237
add invidious mirror links for youtube embeds on thecoli or any xenforo forum so you canwatch videos without worrying about messing up your algorithm.

What the Script Does:
  1. Finds YouTube Videos: The script looks for YouTube videos embedded on a webpage.
  2. Tracks Processed Videos: It keeps track of which videos have already been processed to avoid adding duplicate mirror links.
  3. Adds Mirror Links: It adds alternative links (mirrors) for each YouTube video found, using different domains like yewtu.be, inv.nadeko.net, etc.
  4. Checks Every Second: The script runs every second to check for new YouTube videos and add mirror links if necessary.
Why It's Useful:
  • Redundancy: If one domain is down, you can still watch the video using another domain.
  • Efficiency: It ensures that mirror links are only added once per video, preventing duplicates.
How It Works:
  • Initial Run: The script first processes all existing YouTube videos on the page and adds mirror links.
  • Interval Check: Every second, it checks again for any new YouTube videos and adds mirror links if they are not already present.
  • Tracking: It uses a list (Set) to remember which videos have already been processed to avoid adding duplicate links.
This way, you get multiple ways to access a YouTube video from one place, enhancing your viewing experience and providing redundancy in case one link doesn't work.

xplJkSQ.png


bookmarklet:



userscript:

 

bnew

Veteran
Joined
Nov 1, 2015
Messages
55,699
Reputation
8,224
Daps
157,237
i halfway created a local site to download bluesky/bksy post videos using llama-3.1-sonar-large-128k-chat , i say halfway because i didn't bother developing it further to run the ffmpeg in the background since it requires a proper NodeJS webserver. you can take the code and develop it further.

screenshot of index.html:
fgtBLsE.png

H0QIypa.png

HTML (index.html)​


JavaScript (script.js)​


What does this code do?This code creates a simple web page that helps you download videos from Bluesky posts. Here's how it works:
  1. Enter URL: You paste the URL of a Bluesky post into an input field on the page.
  2. Download Options: The page fetches details about the video and gives you options to download it as an .m3u8 file or convert it to an MP4 file using ffmpeg.
  3. Conversion Instructions: If you choose to convert, it shows you step-by-step instructions on how to do it, including a button to copy the necessary command.
  4. Notifications: When you copy the command or complete other actions, it shows a brief notification that disappears automatically.
Key Features:
  • Centered Input and Button: The input field and download button are centered on the page for better usability.
  • Wider Input Field: The input field is wider to accommodate longer URLs.
  • Queuing Downloads: You can add multiple downloads to a queue, which processes them one by one.
  • Non-Interactive Notifications: Notifications appear briefly without requiring any action from you.
This tool makes it easier for users to download and convert videos from Bluesky posts with minimal effort.
 

bnew

Veteran
Joined
Nov 1, 2015
Messages
55,699
Reputation
8,224
Daps
157,237
took less than 5 mins create and refine using llama 3.1 sonar-large129k

What the Code Does:
  • Floating Window: Creates a floating window on the right side of the page.
  • Buttons: Includes buttons to copy all URLs, close the window, and modify links.
  • Modify Links Pane: Opens a sliding pane where you can enter text to prepend or replace in URLs.
  • Sanitize URLs: Allows you to remove common trailing parameters like "?" and "&" from URLs.
  • Undo/Redo: Lets you undo or redo changes made to the URLs.
  • Remove Duplicates: Removes duplicate lines from the list of URLs.
In Simple Terms:This code helps you manage a list of URLs by:
  • Displaying them in a floating window.
  • Allowing you to copy all URLs at once.
  • Providing an option to modify these URLs by adding or replacing text.
  • Giving you checkboxes to clean up URLs by removing unnecessary parts like "?" and "&".
  • Letting you undo or redo any changes made.
  • Removing any duplicate entries from your list.
This makes it easier for users to work with lists of URLs efficiently.

CD2jZtZ.png




This bookmarklet does the following:
  1. Asks for Input: Prompts you to enter a pattern (like a search term or regex) to find specific URLs on the page.
  2. Finds Matching URLs: Looks through all links, images, and scripts on the page and finds those that match your input pattern.
  3. Displays Results: Creates a small floating window at the top-right corner of your screen showing all matching URLs.
  4. Provides Buttons: Includes buttons to close the window and copy all found URLs to your clipboard.
  5. Handles Esc Key: Allows you to close the window by pressing the Esc key.
  6. Shows Notifications: Displays a brief message when you copy URLs to let you know it was successful or not.
In simple terms, this tool helps you quickly find and collect specific URLs from a webpage based on your search criteria, making it easier to manage and copy them.

4TvAOoc.png


 
Last edited:

bnew

Veteran
Joined
Nov 1, 2015
Messages
55,699
Reputation
8,224
Daps
157,237
i made this so i could use it as a easy web proxy .. it works as long at the search box starts with https


This userscript helps you navigate search results on StartPage.com more efficiently. Here’s what it does in simple terms:
  • Checks Your Search: It looks at what you've searched for and makes sure it's a valid URL.
  • Finds Exact Matches: It checks if any of the search results exactly match what you searched for.
  • Finds Similar Matches: If there's no exact match, it looks for results that are very similar to what you searched for.
  • Redirects You: Once it finds the best match (either exact or similar), it automatically takes you to that result's anonymous view link.
In essence, this script saves you time by automatically finding and redirecting you to the most relevant search result on StartPage.com.

fZWKsax.png



used with redirector , as you can see this captures url from the domain and redirects as a startpage.com query and the userscript does the rest.
RsC7hYp.png


 

bnew

Veteran
Joined
Nov 1, 2015
Messages
55,699
Reputation
8,224
Daps
157,237


Anonymous View by Startpage​


Ready to be invisible? Anonymous View lets anyone access and explore websites without leaving a trace.

Startpage goes beyond private search with our proprietary private browsing feature, Anonymous View. This feature enables you to visit the websites from your search results anonymously, guaranteeing secure HTTPS connection, on both desktop and mobile devices. Anonymous View essentially acts like a VPN, but without an account or the fees.

hero



While browsing with Anonymous View, your identity and data are completely shielded, meaning:​


1618601933-cookies-icon.svg


No website cookies or trackers

1618601939-fingerprinting-icon.svg


No website fingerprinting

1618601944-pricer-trackers-icon.svg


No price tracking or “optimized” prices based on you or your location

1618601948-social-media-trackers-icon.svg


No social media trackers from sites like Facebook and Twitter


How to use​


First, start your search on Startpage. For example, let’s look for information on “internet privacy.”Find and click on the Anonymous View mask icon next to the websites listed in your search results. This will instantly open the website with Startpage privacy. In fact, the website only sees that Startpage is visiting, and you remain completely hidden.The Startpage blue box around your browser window indicates Anonymous View is on and that you are viewing the website in true privacy. You can browse the page you’re visiting as well as click on links within. Have fun, go explore, and rest assured that your identity and personal data are completely masked.


Pro tips and helpful information about browsing with Anonymous View​


1618733724-guy-with-cat-illo.svg



  • Since Startpage uses a secure HTTPS connection, you can even stay private on unsafe networks, like at airports, train stations, or coffee shops.

  • Page loading will take a little longer. That’s because you’re visiting the website through a Startpage proxy, instead of through a direct connection.

  • Cookie and location notifications may appear multiple times because we block the cookies that record and store those private details. We think that’s a small price to pay for privacy.

  • If you use tools that block ads and scripts, you may notice that trackers and cookies are still fully operational in Anonymous View. No worries.

  • With Anonymous View, all they will see is Startpage visiting, not you. None of your data is logged or shared.

  • If you want to visit the website without Anonymous View protection and are comfortable with the website’s privacy policy, click “Visit Original Website” at the bottom right of the blue box. Anonymous View will be disabled.

  • Anonymous View now allows you to use the POST method. This means you will now be able to submit anonymous feedback or log in using alternate accounts and remain private within the Anonymous View session. However, please exercise caution when entering any data in a form, as Anonymous View cannot protect you from websites using or abusing data you have explicitly sent them.

Want to learn more about how our Anonymous View technology works?

We‘re proud to tell you all about it here.

1618734020-anonymous-view-illustration.svg



When it comes to searching and browsing online, Startpage has you covered. Literally!​

 

bnew

Veteran
Joined
Nov 1, 2015
Messages
55,699
Reputation
8,224
Daps
157,237
I was looking for a way to share a code pro in a singlefile with chatgpt and other LLM's which lead me to this:


About​

A Python utility for flattening an entire source tree into a single markdown file


Coderoller​

Coderoller banner


Coderoller is a Python utility that flattens a source code repository into a single markdown file. This tool collects all relevant source and configuration files, including Python, JavaScript, TypeScript, HTML, CSS, JSON, and more, and compiles them into a markdown document. The flattened file provides an organized overview of the repository's contents, making it easy to use in conjunction with LLMs. Simply copy the contents of the flattened file and paste it into your LLM chat context. The flattened form is also great for API-based uses of LLMs in automated workflows.


Features​

  • Flattens source code repositories into a single markdown file.
  • Supports multiple file types including .py, .js, .jsx, .ts, .tsx, .swift, .go, .java, .c, .cpp, .h, .hpp, .cs, .lua, .rb, .php, .pl, .html, .css, .json, .toml, .md, .yaml, .yml, .conf, .ini, and .sh.
  • Automatically includes README files if present, placing it at the start of the flattened file.
  • Excludes hidden files and directories (those starting with a dot), specific directories (build, dist, node_modules, __pycache__), specific files (lockfiles, hidden files, other flattened files, etc.), and any paths specified in .gitignore.
  • Supports flattening directly from Git URLs even if the repository is not cloned locally.\\




To install and use Coderoller on Windows or macOS, follow these step-by-step instructions:

Step 1: Install Python​

  1. Download Python:
  2. Install Python:
    • Windows:
      • Run the downloaded installer.
      • Make sure to check the box that says "Add Python to PATH" before clicking "Install Now."
    • macOS:
      • Open the downloaded .pkg file and follow the installation instructions.
  3. Verify Python Installation:
    • Open a terminal (Command Prompt on Windows or Terminal on macOS).
    • Type python --version or python3 --version and press Enter. You should see the installed version of Python.

Step 2: Install pipx​

  1. Install pipx:
    • Windows:
      • Open Command Prompt and run:
        bash
        Code:
        python -m pip install --user pipx
        python -m pipx ensurepath
    • macOS:
      • Open Terminal and run:
        bash
        Code:
        python3 -m pip install --user pipx
        python3 -m pipx ensurepath
  2. Restart your terminal to ensure that the pipx command is available.

Step 3: Install Coderoller​

  1. Install Coderoller using pipx:
    • In your terminal, run:
      bash
      Code:
      pipx install coderoller

Step 4: Using Coderoller​

  1. Flatten a Local Repository:
    • Navigate to the directory where your repository is located using the terminal. For example:
      bash
      Code:
      cd /path/to/your/repo
    • Run the following command to flatten the repository:
      bash
      Code:
      coderoller-flatten-repo .
    • This will create a markdown file named repo_name.flat.md in the current directory.
  2. Flatten a Repository from a Git URL:
    • You can also flatten a repository directly from a Git URL. Run:
      bash
      Code:
      coderoller-flatten-repo https://github.com/username/reponame.git
    • Replace https://github.com/username/reponame.git with the actual URL of the repository you want to flatten.

Step 5: Access the Flattened Markdown File​

  1. Locate the Markdown File:
    • After running the flatten command, you will find a file named reponame.flat.md in your current working directory.
  2. Open the Markdown File:
    • You can open this file using any text editor or markdown viewer to see the flattened contents of the repository.

Additional Notes​

  • Make sure you have internet access when installing Python and pipx.
  • If you encounter any issues, ensure that Python and pipx are correctly added to your system's PATH.
  • You can refer to the Coderoller documentation for more advanced usage and options.
That's it! You have successfully installed and used Coderoller to flatten a source code repository into a markdown file.
 

bnew

Veteran
Joined
Nov 1, 2015
Messages
55,699
Reputation
8,224
Daps
157,237

Change Log​

Version 1.0 (Initial Release)​

  • Initial Implementation: The bookmarklet was designed to highlight and copy elements on a webpage, including features for drawing rectangles and handling multiple selections.

Version 1.1 (Simplification and Refinement)​

  • Removed Unnecessary Code: Code related to drawing rectangles and associated event handlers were removed to focus solely on highlighting and copying selected elements.
  • Refined Click Event Handler: Ensured that only the clicked element is highlighted and its content is copied to the clipboard.
  • Improved Key Press Event Handler: Added functionality to remove all event listeners, clear highlighted elements, and exit the bookmarklet cleanly when 'Q' or 'ESC' is pressed.

Version 1.2 (Edge Case Testing and Initialization)​

  • Proper Initialization: Ensured all variables are initialized correctly before use.
  • Edge Case Testing: Tested for multiple clicks in quick succession and multiple presses of 'Q' or 'ESC'.
  • Event Listener Addition: Ensured event listeners are added only once.

Version 1.3 (Final Refinements)​

  • Combined All Refinements: Integrated all previous refinements into a single, cohesive version.
  • Final Review and Confirmation: Conducted a thorough review to ensure the bookmarklet meets all requirements without any issues.

Summary​

What Does This Bookmarklet Do?
  • This bookmarklet helps you copy the content of any element on a webpage. Here’s how it works:
    • When you click on an element (like a paragraph or image), it gets highlighted.
    • The content of the highlighted element is automatically copied to your clipboard.
    • You can press 'Q' or 'ESC' to stop the bookmarklet and remove any highlights.
Changes Made:
  • We removed unnecessary features that were not needed.
  • We made sure that only the clicked element gets highlighted and copied.
  • We added a way to exit the bookmarklet cleanly by pressing 'Q' or 'ESC'.
  • We tested it to make sure it works well even if you click multiple times quickly or press 'Q' or 'ESC' multiple times.
How to Use:
  1. Click on the bookmarklet in your browser's bookmarks bar.
  2. Hover over an element to see what will be copied.
  3. Click on an element to copy its content.
  4. Press 'Q' or 'ESC' to exit the bookmarklet.
This version is simpler, more efficient, and easier to use than before

JavaScript:
javascript:(function(){
    let currentElement = null;
    let highlightedElements = [];
    const maxNotifications = 3;
    let notifications = [];

    function handleClick(event) {
        if (currentElement) {
            currentElement.classList.remove('highlight');
        }
        currentElement = event.target;
        currentElement.classList.add('highlight');

        const htmlContent = currentElement.outerHTML;
        const plainTextContent = currentElement.innerText;
        const clipboardItem = new ClipboardItem({
            "text/html": new Blob([htmlContent], { type: "text/html" }),
            "text/plain": new Blob([plainTextContent], { type: "text/plain" }),
        });
        navigator.clipboard.write([clipboardItem])
            .then(() => {
                console.log("Content copied to clipboard");
                showNotification("Content copied to clipboard. Press Q or ESC to exit.");
            })
            .catch(err => console.error("Could not copy text: ", err));
    }

    function handleMouseOver(event) {
        event.target.classList.add('hover');
    }

    function handleMouseOut(event) {
        event.target.classList.remove('hover');
    }

    function handleKeyPress(event) {
        if (event.key === 'q' || event.key === 'Escape') {
            document.body.removeEventListener('click', handleClick);
            document.body.removeEventListener('keydown', handleKeyPress);
            document.body.removeEventListener('mouseover', handleMouseOver);
            document.body.removeEventListener('mouseout', handleMouseOut);

            const highlightedElementsList = document.querySelectorAll('.highlight');
            highlightedElementsList.forEach(element => element.classList.remove('highlight'));

            const notificationStyleElement = document.querySelector('style.notification-style');
            if (notificationStyleElement) {
                notificationStyleElement.remove();
            }
            const notificationsListElements = document.querySelectorAll('.notification');
            notificationsListElements.forEach(notification => notification.remove());
            notifications.length = 0;

            showNotification("Bookmarklet exited. Press Q or ESC to exit next time.");
            setTimeout(() => {
                const exitNotificationElement = document.querySelector('.notification');
                if (exitNotificationElement) {
                    exitNotificationElement.remove();
                }
            }, 2000);
        }
    }

    function showNotification(message) {
        const notification = document.createElement('div');
        notification.textContent = message;
        notification.className = 'notification';

        notifications.push(notification);
        if (notifications.length > maxNotifications) {
            const oldestNotification = notifications.shift();
            oldestNotification.remove();
        }

        document.body.appendChild(notification);

        const notificationHeight = notification.offsetHeight;
        const bottomOffset = (notifications.length - 1) * notificationHeight;
        notification.style.bottom = `${bottomOffset}px`;

        const existingStyle = document.querySelector('style.notification-style');
        if (!existingStyle) {
            const style = document.createElement('style');
            style.className = 'notification-style';
            style.textContent = `
                .highlight { 
                    border: 2px solid red; 
                    box-shadow: 0 0 10px rgba(255, 0, 0, 0.5); 
                    background-color: rgba(255, 0, 0, 0.2); 
                }
                .hover { 
                    border: 1px dashed blue; 
                    box-shadow: 0 0 5px rgba(0, 0, 255, 0.3); 
                }
                .notification { 
                    position: fixed; 
                    left: 10px; 
                    bottom: 10px; 
                    background-color: #fff;
                    border: 1px solid #ddd;
                    padding: 5px;
                    width: 200px;
                    z-index: 1000;
                    box-shadow: 0 0 10px rgba(0,0,0,0.2);
                }
            `;
            document.head.appendChild(style);
        }
    }

    document.body.addEventListener('click', handleClick);
    document.body.addEventListener('keydown', handleKeyPress);
    document.body.addEventListener('mouseover', handleMouseOver);
    document.body.addEventListener('mouseout', handleMouseOut);

    showNotification("Hover over an element to see what will be copied. Click an element to copy its content. Press Q or ESC to exit.");
})();
 
Top