Enhanced Bing ChatAI

Improves Bing ChatAI user experience by preventing accidental scrolling and increasing input character limit

当前为 2023-05-08 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name        Enhanced Bing ChatAI
// @namespace   EnhancedBingChatAI
// @description Improves Bing ChatAI user experience by preventing accidental scrolling and increasing input character limit
// @version     1.1.0
// @author      CriDos
// @grant       GM_setClipboard
// @match       https://www.bing.com/*
// @license     MIT
// ==/UserScript==

// Prevent scrolling when hovering over cib-serp-main element
window.addEventListener('wheel', (event) => {
    if (event.target.className.includes('cib-serp-main')) {
        event.stopPropagation();
    }
});


(function () {
    'use strict';

    // Increase input character limit to 100,000
    {
        const increaseCharacterLimit = () => {
            const textareaElement = document.querySelector('#b_sydConvCont > cib-serp').shadowRoot.querySelector('#cib-action-bar-main').shadowRoot.querySelector('#searchboxform > label').querySelector('textarea');
            if (textareaElement) textareaElement.setAttribute('maxlength', '100000');
        };

        const waitForElement = (selector, callback) => {
            const element = document.querySelector(selector);

            if (element) {
                callback();
            } else {
                setTimeout(() => {
                    waitForElement(selector, callback);
                }, 2000);
            }
        };

        waitForElement('#b_sydConvCont > cib-serp', increaseCharacterLimit);
    }

    // Copy Code Blocks from Bing Chats
    {
        // A function that returns a copyCode function with a reference to the code block element
        function createCopyCode(codeBlock) {
            // Return a copyCode function that does the following:
            return function (e) {
                // Get the visible text of the code block element passed to the createCopyCode function
                let text = codeBlock.innerText;
                // Copy the text to the clipboard
                GM_setClipboard(text);
                // Show a confirmation message using a temporary span element
                let span = document.createElement("span");
                span.className = "copy-message";
                span.textContent = "Copied!";
                span.style.color = "green";
                span.style.marginLeft = "5px";
                span.style.opacity = "1";
                e.target.parentElement.appendChild(span);
                // Fade away and remove the span element after 3 seconds
                setTimeout(function () {
                    let fade = setInterval(function () {
                        if (span.style.opacity > 0) {
                            span.style.opacity -= 0.1;
                        } else {
                            clearInterval(fade);
                            span.remove();
                        }
                    }, 100);
                }, 1000);
            };
        }

        // A function that traverses the entire DOM tree and checks for shadow roots and code blocks at each node
        function traverseDOM(node) {
            // If the node has a shadowRoot property, call the function recursively on the shadow root node
            if (node.shadowRoot) {
                traverseDOM(node.shadowRoot);
            }
            // If the node has a querySelectorAll method, use it to get all the code blocks under the node and add copy buttons to them if they don't have one already
            if (node.querySelectorAll) {
                let codeBlocks = node.querySelectorAll("pre > code");
                for (let codeBlock of codeBlocks) {
                    let preCodeBlock = codeBlock.parentElement;

                    let copyButton = preCodeBlock.querySelector(".copy-button");
                    if (!copyButton) {
                        copyButton = document.createElement("button");
                        copyButton.className = "copy-button";
                        copyButton.textContent = "Copy";
                        copyButton.addEventListener("click", createCopyCode(codeBlock));
                        try {
                            preCodeBlock.appendChild(copyButton);
                        } catch (error) {
                            console.error(error);
                        }
                    }
                }
            }
            // If the node has child nodes, loop through them and call the function recursively on each child node
            if (node.childNodes) {
                for (let child of node.childNodes) {
                    traverseDOM(child);
                }
            }
        }

        // A function that runs when the DOM changes and calls the traverseDOM function
        function onDOMChange(mutations) {
            // Loop through each mutation record and check if it added or removed any nodes or attributes to the DOM
            for (let mutation of mutations) {
                if (mutation.type === "childList" || mutation.type === "attributes") {
                    // Call the traverseDOM function on the target node of the mutation record and any added or removed nodes
                    traverseDOM(mutation.target);
                    for (let addedNode of mutation.addedNodes) {
                        traverseDOM(addedNode);
                    }
                    for (let removedNode of mutation.removedNodes) {
                        traverseDOM(removedNode);
                    }
                }
            }
        }

        // Create a new mutation observer and pass it the onDOMChange function
        let observer = new MutationObserver(onDOMChange);
        // Start observing the entire document for anytype of changes
        observer.observe(document, { childList: true, attributes: true, subtree: true });

        // A function that checks if the cib-feedback element is present in the DOM
        function isFeedbackReady() {
            // Use the traverseDOM function to get all the cib-feedback elements from any shadow roots
            let feedbackElements = [];
            traverseDOM(document.body, feedbackElements);
            // Return true if there is at least one cib-feedback element in the DOM, false otherwise
            return feedbackElements.length > 0;
        }
        // A function that adds a copy button to each code block in bing chats
        function addCopyButtons() {
            // Get all the code blocks in bing chats using the new selector
            let codeBlocks = document.querySelectorAll("pre > code");
            // Loop through each code block
            for (let codeBlock of codeBlocks) {
                let preCodeBlock = codeBlock.parentElement;

                // Check if the code block already has a copy button
                let copyButton = preCodeBlock.querySelector(".copy-button");
                // If not, create a new copy button
                if (!copyButton) {
                    // Create a new button element
                    copyButton = document.createElement("button");
                    // Set the class name of the button
                    copyButton.className = "copy-button";
                    // Set the text content of the button
                    copyButton.textContent = "Copy";
                    // Add a click event listener to the button
                    copyButton.addEventListener("click", createCopyCode(codeBlock));
                    // Try to insert the button before the code element
                    try {
                        preCodeBlock.appendChild(copyButton);
                    } catch (error) {
                        // Catch and log any errors that occur while inserting the button
                        console.error(error);
                    }
                }
            }
        }

        // A function that runs when the document is ready and calls the addCopyButtons function only if the cib-feedback element is present in the DOM
        function onDocumentReady() {
            // Check if the cib-feedback element is present in the DOM using the isFeedbackReady function
            if (isFeedbackReady()) {
                // Call the addCopyButtons function to add copy buttons to all code blocks in bing chats
                addCopyButtons();
            } else {
                // Wait for 100 milliseconds and try again
                setTimeout(onDocumentReady, 1000);
            }
        }

        // Run the onDocumentReady function when the document is ready
        if (document.readyState === "complete" || document.readyState === "interactive") {
            onDocumentReady();
        } else {
            document.addEventListener("DOMContentLoaded", onDocumentReady);
        }
    }

})();