Better TankTrouble Chatbox

Redesigned chatbox meant both for power users, and those who maybe just wants something new

目前為 2024-01-09 提交的版本,檢視 最新版本

  1. // ==UserScript==
  2. // @name Better TankTrouble Chatbox
  3. // @author commander
  4. // @description Redesigned chatbox meant both for power users, and those who maybe just wants something new
  5. // @namespace https://github.com/asger-finding/tanktrouble-userscripts
  6. // @version 0.1.2
  7. // @license GPL-3.0
  8. // @match *://*.tanktrouble.com/*
  9. // @exclude *://classic.tanktrouble.com/
  10. // @run-at document-end
  11. // @grant GM_addStyle
  12. // @grant GM_getValue
  13. // @grant GM_setValue
  14. // @require https://update.greasyfork.org/scripts/482092/1309109/TankTrouble%20Development%20Library.js
  15. // @noframes
  16. // ==/UserScript==
  17.  
  18. GM_addStyle(`
  19. #chat {
  20. /*Move it to the bottom left*/
  21. inset: calc(100% - 30px) auto auto 34px !important;
  22. /*Disable drop shadow filter*/
  23. filter: none;
  24. -webkit-filter: none;
  25. }
  26. /*Reverse the chat flow*/
  27. #chat,
  28. #chat .content,
  29. #chat .body {
  30. display: flex;
  31. flex-direction: column-reverse;
  32. }
  33. #chat .status.button {
  34. transform: translate(7px, -18px);
  35. cursor: initial;
  36. z-index: 1;
  37. }
  38. #chat form {
  39. width: 200px;
  40. margin-left: 20px;
  41. background: #ececec;
  42. }
  43. #chat form[style*="repeating-linear-gradient"] {
  44. background: #d0d0d0 !important;
  45. }
  46. #chat:not(.open) form {
  47. display: none;
  48. }
  49. #chat textarea {
  50. left: 5px;
  51. transition: width 0s !important;
  52. }
  53. #chat .body {
  54. padding-right: 10px;
  55. border-radius: 3px;
  56. background: linear-gradient(225deg, #00000005 12px, #00000014 12px, #00000014 100%);
  57. margin-bottom: 7px;
  58. top: 0 !important;
  59. -webkit-mask-image: linear-gradient(225deg, #000000 11px, #00000000 12px, #00000000 100% ),
  60. linear-gradient(to top, #000000 70%, rgba(0, 0, 0, 0.11));
  61. }
  62. #chat .body .chatMessage svg {
  63. padding: 2px 4px 1px 4px;
  64. border-left: 2px dotted rgb(170, 170, 170);
  65. filter: drop-shadow(1px 1px 1px #00000022);
  66. }
  67. #chat .body.dragging {
  68. border: none !important;
  69. margin-left: 20px !important;
  70. }
  71. /*Rotate and align the handle to top-right*/
  72. .handle.ui-resizable-ne[src*="resizeHandleBottomRight.png"] {
  73. width: 12px;
  74. height: 12px !important;
  75. transform: translateX(6px) rotate(-90deg);
  76. z-index: 2147483647;
  77. position: sticky;
  78. left: calc(100% - 7px);
  79. top: 0;
  80. order: 0;
  81. margin-bottom: auto !important;
  82. }
  83. body:has(#chat .body.ui-resizable-resizing) .ui-resizable-handle.handle.ui-resizable-ne {
  84. display: none !important;
  85. }
  86.  
  87. /* Scrollbar */
  88. #chat .body {
  89. scrollbar-gutter: stable;
  90. scrollbar-width: thin;
  91. scrollbar-color: rgb(170, 170, 170) transparent;
  92. align-items: end;
  93. direction: rtl;
  94. pointer-events: auto;
  95. overflow-x: hidden;
  96. overflow-y: hidden;
  97. }
  98. #chat .body:hover {
  99. overflow-y: scroll;
  100. }
  101. #chat .body .chatMessage {
  102. direction: ltr;
  103. margin-left: ${(/Chrome.*Safari/u).test(navigator.userAgent) ? '3px' : '5px'};
  104. }
  105. #chat .body::-webkit-scrollbar {
  106. width: 3px;
  107. }
  108. #chat .body::-webkit-scrollbar-track {
  109. background: transparent;
  110. }
  111. #chat .body::-webkit-scrollbar-thumb {
  112. background: rgb(170, 170, 170);
  113. }
  114. `);
  115.  
  116. /**
  117. * Reconfigure the chat handle to be dragging
  118. * from the south-east direction (down)
  119. * to the north-east direction (up)
  120. */
  121. const changeHandleDirection = () => {
  122. const { resizable } = $.fn;
  123.  
  124. // Use a regular function to keep context
  125. $.fn.resizable = function(...args) {
  126. const [config] = args;
  127.  
  128. // Reassign the chat handle to be north-east facing
  129. if (config.handles) {
  130. const handle = config.handles.se;
  131. if (handle === TankTrouble.ChatBox.chatBodyResizeHandle) {
  132. handle.removeClass('ui-resizable-se')
  133. .addClass('ui-resizable-ne');
  134.  
  135. config.handles.ne = handle;
  136. delete config.handles.se;
  137.  
  138. // Set a taller chat maxHeight
  139. config.maxHeight = 650;
  140. }
  141. }
  142.  
  143. return resizable.call(this, config);
  144. };
  145. };
  146.  
  147. /**
  148. * Hook message render functions to disable jquery .show() animation
  149. * This fixes chat messages not showing up in the reversed chat order
  150. */
  151. const fixChatRendering = () => {
  152. Loader.interceptFunction(TankTrouble.ChatBox, '_renderChatMessage', (original, ...args) => {
  153. // Set animateHeight to false
  154. args[9] = false;
  155. original(...args);
  156. });
  157.  
  158. Loader.interceptFunction(TankTrouble.ChatBox, '_renderSystemMessage', (original, ...args) => {
  159. // Set animateHeight to false
  160. args[3] = false;
  161. original(...args);
  162. });
  163. };
  164.  
  165. /**
  166. * Prevent TankTrouble from clearing the chat when the client disconnects
  167. * Print message to chat when client switches server to separate conversations
  168. */
  169. const preventChatClear = () => {
  170. Loader.interceptFunction(TankTrouble.ChatBox, '_clearChat', (original, ...args) => {
  171. const isUnconnected = ClientManager.getClient().getState() === TTClient.STATES.UNCONNECTED;
  172.  
  173. // Void the call if the client is unconnected
  174. // when the function is invoked
  175. if (isUnconnected) return null;
  176.  
  177. return original(...args);
  178. });
  179.  
  180. Loader.interceptFunction(TankTrouble.ChatBox, '_updateStatusMessageAndAvailability', (original, ...args) => {
  181. const [systemMessageText, guestPlayerIds] = args;
  182.  
  183. // Check for welcome message
  184. // If true, print a system message
  185. if (systemMessageText === 'Welcome to TankTrouble Comms § § ') {
  186. const newServer = ClientManager.getAvailableServers()[ClientManager.multiplayerServerId];
  187. return original(`Connected to ${ newServer.name } ${ guestPlayerIds.length ? '§ ' : '' }`, guestPlayerIds);
  188. }
  189. return original(...args);
  190. });
  191. };
  192.  
  193. /**
  194. * Write the chat savestate to storage and return
  195. * @returns Promise for last savestate
  196. */
  197. const startChatSavestate = () => {
  198. Loader.interceptFunction(TankTrouble.ChatBox, 'open', (original, ...args) => {
  199. GM_setValue('chat-open', true);
  200. original(...args);
  201. });
  202. Loader.interceptFunction(TankTrouble.ChatBox, 'close', (original, ...args) => {
  203. GM_setValue('chat-open', false);
  204. original(...args);
  205. });
  206.  
  207. // Get savestate and default to chat being open
  208. return GM_getValue('chat-open', true);
  209. };
  210.  
  211. changeHandleDirection();
  212. fixChatRendering();
  213. Loader.whenContentInitialized().then(async() => {
  214. preventChatClear();
  215.  
  216. const shouldChatOpen = await startChatSavestate();
  217. if (shouldChatOpen) TankTrouble.ChatBox.open();
  218.  
  219. // Get the plain nodes for better performance
  220. // eslint-disable-next-line prefer-destructuring
  221. const chatBody = TankTrouble.ChatBox.chatBody[0];
  222. // eslint-disable-next-line prefer-destructuring
  223. const chatForm = TankTrouble.ChatBox.chatForm[0];
  224. // eslint-disable-next-line prefer-destructuring
  225. const chatInput = TankTrouble.ChatBox.chatInput[0];
  226.  
  227. // Create a mutation observer that looks for changes in the chatBody's attributes (namely width)
  228. new MutationObserver(() => {
  229. const width = Number(chatBody.offsetWidth || 220);
  230.  
  231. chatForm.style.width = `${width}px`;
  232. chatInput.style.width = `${width - 12}px`;
  233. }).observe(chatBody, {
  234. attributes: true,
  235. characterData: false
  236. });
  237.  
  238. chatForm.style.width = '220px';
  239. chatInput.style.width = `${chatForm.offsetWidth - 12}px`;
  240.  
  241. // Allow more characters in the chat input
  242. chatInput.setAttribute('maxlength', '255');
  243. });