通过油猴脚本实现$替换为$

在很多论坛系统中,美元符号不能直接使用,尤其是开启了 latex语法的论坛。

那么最简单的就是通过油猴脚本,在发帖时,把 美元符号换成 全角美元符号。代码如下:

// ==UserScript==
// @name         Replace Dollar Signs in Flarum
// @namespace    https://beiduofen.top/
// @version      0.2
// @description  Replaces all $ with $ in textareas on beiduofen.top, fixing Flarum's editor issues
// @author       Steper Lin
// @match        *://*/*
// ==/UserScript==

(function() {
    'use strict';

    // Function to replace regular dollar signs with full-width dollar signs
    function replaceDollarSigns(element) {
        // Save cursor position
        const isTextarea = element.tagName === 'TEXTAREA';
        const cursorPosition = isTextarea ? element.selectionStart : null;

        // Replace content
        const text = isTextarea ? element.value : element.textContent;
        const newText = text.replace(/$/g, '$');

        // Only update if changes were made
        if (text !== newText) {
            if (isTextarea) {
                element.value = newText;
                // Dispatch input event to trigger Flarum's update mechanism
                element.dispatchEvent(new Event('input', { bubbles: true }));
                // Also dispatch change event for good measure
                element.dispatchEvent(new Event('change', { bubbles: true }));

                // Restore cursor position if needed
                if (cursorPosition !== null) {
                    element.selectionStart = cursorPosition;
                    element.selectionEnd = cursorPosition;
                }
            } else {
                element.textContent = newText;
            }
        }
    }

    // Handle key presses in the document to catch paste operations
    document.addEventListener('keydown', function(e) {
        // Check for paste operation (Ctrl+V or Command+V. if ((e.ctrlKey || e.metaKey) && e.key === 'v') {
            // Give time for the paste to complete
            setTimeout(function() {
                processAllElements();
            }, 100);
        }
    });

    // Intercept paste event on textareas
    function setupPasteListener(element) {
        element.addEventListener('paste', function() {
            // Process after paste completes
            setTimeout(() => {
                replaceDollarSigns(element);
                // Also look for preview areas that might have been updated
                processPreviewAreas();
            }, 100);
        });
    }

    // Setup input listener for textareas
    function setupInputListener(element) {
        element.addEventListener('input', function() {
            replaceDollarSigns(this);
            // Also check for preview areas on input
            setTimeout(processPreviewAreas, 100);
        });

        // Also handle blur event (when user clicks away)
        element.addEventListener('blur', function() {
            replaceDollarSigns(this);
            // Final check of preview areas
            setTimeout(processPreviewAreas, 100);
        });

        // Set up paste listener
        setupPasteListener(element);
    }

    // Process preview areas - these are likely where formatted content appears
    function processPreviewAreas() {
        // Target common preview area selectors in Flarum
        const previewSelectors = [
            '.Post-body', '.PostPreview', '.FormattedContent',
            '.Post-preview', '.ComposerBody-preview', '.item-preview',
            '[data-preview]', '.Preview', '.PostPreview-content',
            // Add code block related selectors
            'pre', 'code', '.hljs', '.CodeMirror', '.CodeMirror-code',
            // Try to catch any element with "preview" in its class or id
            '[class*="preview"]', '[id*="preview"]'
        ];

        previewSelectors.forEach(selector => {
            try {
                const previewElements = document.querySelectorAll(selector);
                previewElements.forEach(element => {
                    // For code blocks, we need to be more thorough
                    if (element.tagName === 'PRE' || element.tagName === 'CODE') {
                        replaceDollarSigns(element);
                    } else {
                        // For other preview elements, look for code blocks inside them
                        const codeBlocks = element.querySelectorAll('pre, code');
                        codeBlocks.forEach(codeBlock => {
                            replaceDollarSigns(codeBlock);
                        });

                        // Also check the text nodes directly
                        replaceDollarSigns(element);
                    }
                });
            } catch (e) {
                // Ignore errors from invalid selectors
            }
        });
    }

    // Process all elements that might contain dollar signs
    function processAllElements() {
        // Handle textareas
        const textareas = document.querySelectorAll('textarea');
        textareas.forEach(textarea => {
            replaceDollarSigns(textarea);
            // Make sure the listener is set up
            if (!textarea.hasProcessedDollarSigns) {
                setupInputListener(textarea);
                textarea.hasProcessedDollarSigns = true;
            }
        });

        // Process preview areas
        processPreviewAreas();
    }

    // Run initial processing
    processAllElements();

    // Also look for submit buttons and process everything before submission
    document.addEventListener('click', function(e) {
        if (e.target && (
            e.target.type === 'submit' ||
            e.target.classList.contains('Button--primary') ||
            e.target.classList.contains('PostStream-reply')
        )) {
            // Process all elements one last time before form submission
            processAllElements();

            // Give it a moment to process before actual submission
            setTimeout(() => {}, 100);
        }
    });

    // Observe DOM for new elements
    const observer = new MutationObserver(mutations => {
        let shouldProcess = false;

        mutations.forEach(mutation => {
            if (mutation.addedNodes && mutation.addedNodes.length > 0) {
                shouldProcess = true;

                // Specifically look for added textareas
                mutation.addedNodes.forEach(node => {
                    if (node.nodeName === 'TEXTAREA' && !node.hasProcessedDollarSigns) {
                        setupInputListener(node);
                        node.hasProcessedDollarSigns = true;
                        replaceDollarSigns(node);
                    }

                    // Check for textareas within added nodes
                    if (node.querySelectorAll) {
                        const textareas = node.querySelectorAll('textarea');
                        textareas.forEach(textarea => {
                            if (!textarea.hasProcessedDollarSigns) {
                                setupInputListener(textarea);
                                textarea.hasProcessedDollarSigns = true;
                                replaceDollarSigns(textarea);
                            }
                        });
                    }
                });
            }
        });

        if (shouldProcess) {
            // Process everything after DOM changes
            setTimeout(processAllElements, 200);
        }
    });

    // Start observing the document
    observer.observe(document.body, { childList: true, subtree: true });

    // Also set a periodic check for complex editors
    setInterval(processAllElements, 2000);
})();

评论

发表回复

人生梦想 - 关注前沿的计算机技术 acejoy.com 🐾 步子哥の博客 🐾 背多分论坛 🐾 知差(chai)网