Torn Chat Popout

Adds a popout button for Torn chat

  1. // ==UserScript==
  2. // @name Torn Chat Popout
  3. // @namespace http://tampermonkey.net/
  4. // @version 1.0
  5. // @description Adds a popout button for Torn chat
  6. // @author Weav3r
  7. // @match https://www.torn.com/*
  8. // ==/UserScript==
  9.  
  10. (function() {
  11. 'use strict';
  12.  
  13. let popoutWindow = null;
  14. const POPOUT_KEY = 'torn_chat_popout_active';
  15. const POPOUT_CSS = `
  16. body { margin: 0; padding: 0; background: #1c1c1c; height: 100vh; overflow: hidden; }
  17. body > *:not(#chatRoot):not(script):not(link):not(style) { display: none !important; }
  18. #chatRoot { position: fixed; top: 0; left: 0; width: 100%; height: 100%; z-index: 9999; display: block !important; }
  19. #chat-popout-btn { display: none !important; }
  20. `;
  21.  
  22. function toggleMainChat(show) {
  23. const chatRoot = document.querySelector('#chatRoot');
  24. if (chatRoot) chatRoot.style.display = show ? '' : 'none';
  25. localStorage.setItem(POPOUT_KEY, !show);
  26. }
  27.  
  28. function createPopoutButton() {
  29. const button = document.createElement('button');
  30. button.id = 'chat-popout-btn';
  31. button.type = 'button';
  32. button.className = 'chat-list-button___d1Olw';
  33.  
  34. const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
  35. svg.setAttribute('xmlns', 'http://www.w3.org/2000/svg');
  36. svg.setAttribute('viewBox', '0 0 22 24');
  37. svg.setAttribute('class', 'chat-app__footer-chat-list-icon___o_mD2');
  38.  
  39. svg.innerHTML = `
  40. <defs>
  41. <linearGradient id="popout-default-blue" x1="0.5" x2="0.5" y2="1" gradientUnits="objectBoundingBox">
  42. <stop offset="0" stop-color="#8faeb4"/>
  43. <stop offset="1" stop-color="#638c94"/>
  44. </linearGradient>
  45. <linearGradient id="popout-hover-blue" x1="0.5" x2="0.5" y2="1" gradientUnits="objectBoundingBox">
  46. <stop offset="0" stop-color="#eaf0f1"/>
  47. <stop offset="1" stop-color="#7b9fa6"/>
  48. </linearGradient>
  49. </defs>
  50. <path d="M19 3h-7v2h4.6l-8.3 8.3 1.4 1.4L18 6.4V11h2V3z M5 5h7V3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2v-7h-2v7H5V5z" fill="url(#popout-default-blue)"/>
  51. `;
  52.  
  53. button.appendChild(svg);
  54. button.addEventListener('click', createPopout);
  55.  
  56. const path = svg.querySelector('path');
  57. button.addEventListener('mouseenter', () => path.setAttribute('fill', 'url(#popout-hover-blue)'));
  58. button.addEventListener('mouseleave', () => path.setAttribute('fill', 'url(#popout-default-blue)'));
  59.  
  60. const chatListButton = document.querySelector('.chat-list-button___d1Olw');
  61. chatListButton?.parentNode?.insertBefore(button, chatListButton.nextSibling);
  62. }
  63.  
  64. function createPopout() {
  65. if (popoutWindow?.closed === false) {
  66. popoutWindow.focus();
  67. return;
  68. }
  69.  
  70. popoutWindow = window.open('https://www.torn.com', 'TornChat', 'width=400,height=600,resizable=yes');
  71.  
  72. const waitForChat = setInterval(() => {
  73. if (popoutWindow.document.querySelector('#chatRoot')) {
  74. clearInterval(waitForChat);
  75. toggleMainChat(false);
  76. const style = document.createElement('style');
  77. style.textContent = POPOUT_CSS;
  78. popoutWindow.document.head.appendChild(style);
  79. }
  80. }, 100);
  81.  
  82. const checkClosure = setInterval(() => {
  83. if (popoutWindow.closed) {
  84. toggleMainChat(true);
  85. clearInterval(checkClosure);
  86. popoutWindow = null;
  87. }
  88. }, 1000);
  89. }
  90.  
  91. function init() {
  92. if (document.querySelector('#chatRoot') && !document.querySelector('#chat-popout-btn')) {
  93. createPopoutButton();
  94. if (localStorage.getItem(POPOUT_KEY) === 'true') toggleMainChat(false);
  95. }
  96. }
  97.  
  98. document.readyState === 'loading'
  99. ? document.addEventListener('DOMContentLoaded', init)
  100. : init();
  101.  
  102. new MutationObserver(init).observe(document.body, { childList: true, subtree: true });
  103.  
  104. window.addEventListener('storage', e => {
  105. if (e.key === POPOUT_KEY) toggleMainChat(e.newValue === 'false');
  106. });
  107. })();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址