// ==UserScript== // @name mac-ROC-flag // @namespace https://github.com/tizee-tampermonkey-scripts/tampermonkey-mac-roc-flag // @homepage https://github.com/tizee-tampermonkey-scripts/tampermonkey-mac-roc-flag // @downloadURL https://raw.githubusercontent.com/tizee-tampermonkey-scripts/tampermonkey-mac-ROC-flag/refs/heads/main/mac-ROC-flag.js // @updateURL https://raw.githubusercontent.com/tizee-tampermonkey-scripts/tampermonkey-mac-ROC-flag/refs/heads/main/mac-ROC-flag.js // @version 1.1 // @description Replace ROC flag unicode to images in Apple devices // @author tizee // @icon https://cdn.jsdelivr.net/gh/twitter/twemoji@latest/assets/72x72/1f1f9-1f1fc.png // @grant GM_addStyle // @match *://*/* // ==/UserScript== (function () { 'use strict'; let _ = document; const ROC_FLAG_SVG=`` function replaceROCFlag(node) { // ROC flag = \uD83C\uDDF9\uD83C\uDDFC // T: \uD83C\uDDF9, U+1F1F9 // W: \uD83C\uDDFC, U+1F1FC let flag = /\u{1F1F9}\u{1F1FC}/gu; const textContent = node.nodeValue; if (!textContent || !flag.test(textContent)) { return false; } // Create a temporary div to handle the HTML replacement const tempDiv = document.createElement('div'); const flagPlaceholder = '___ROC_FLAG_PLACEHOLDER___'; // Replace all flag occurrences with placeholder const textWithPlaceholder = textContent.replace(flag, flagPlaceholder); // Split by placeholder and rebuild with SVG const parts = textWithPlaceholder.split(flagPlaceholder); if (parts.length === 1) { return false; // No replacement occurred } const parent = node.parentNode; // Insert parts and SVG replacements for (let i = 0; i < parts.length; i++) { // Insert text part if (parts[i]) { parent.insertBefore(document.createTextNode(parts[i]), node); } // Insert SVG (except after the last part) if (i < parts.length - 1) { const span = document.createElement('span'); span.className = 'roc-flag-replacement'; span.innerHTML = ROC_FLAG_SVG; // Set proper dimensions for the SVG const svg = span.querySelector('svg'); if (svg) { svg.style.height = '1em'; svg.style.width = '1em'; svg.style.margin = '0 .05em 0 .1em'; svg.style.verticalAlign = '-0.1em'; } parent.insertBefore(span, node); } } // Remove the original node parent.removeChild(node); console.debug('Replace ROC flag:', parts.length - 1, 'occurrences replaced'); return true; } // Watch newly added DOM nodes, and save them for later use function mutationHandler(mutationList) { mutationList.forEach(function (mutationRecord) { mutationRecord.addedNodes.forEach(function (node) { scanTextNodes(node); }); }); } // dfs function scanTextNodes(node) { // The node could have been detached from the DOM tree if (!node.parentNode || !_.body.contains(node)) { return; } // Ignore text boxes and echoes let excludeTags = {ruby: true, script: true, select: true, textarea: true}; switch (node.nodeType) { case Node.ELEMENT_NODE: if (node.tagName.toLowerCase() in excludeTags || node.isContentEditable) { return; } return node.childNodes.forEach(scanTextNodes); case Node.TEXT_NODE: return replaceROCFlag(node); } } // this script does not support mobile devices if (/iPhone|iPad|iPod|Android/i.test(navigator.userAgent)) { return; } const pl = window.navigator.platform.toLowerCase(); const platform = pl.indexOf("mac") >= 0 ? "m" : pl.indexOf("win") >= 0 ? "w" : pl.indexOf("linux") >= 0 ? "l" : pl.indexOf("x11") >= 0 ? "l" : undefined; // only apple devices need this script if (platform != "m") { return; } let observer = new MutationObserver(mutationHandler); observer.observe(_.body, {childList: true, subtree: true}); scanTextNodes(_.body); })();