Phind.com Chat Box Text Formatter

Format text in chat box while preserving code spacing

  1. // ==UserScript==
  2. // @name Phind.com Chat Box Text Formatter
  3. // @namespace http://tampermonkey.net/
  4. // @version 1.1
  5. // @description Format text in chat box while preserving code spacing
  6. // @author 11
  7. // @license MIT
  8. // @match https://www.phind.com/*
  9. // @grant none
  10. // ==/UserScript==
  11.  
  12. (function() {
  13. 'use strict';
  14.  
  15. const CONFIG = {
  16. editorSelectors: [
  17. '.masthead-chatbox .public-DraftEditor-content',
  18. '.followup-textarea-container .public-DraftEditor-content'
  19. ],
  20. buttonContainerSelectors: [
  21. '.masthead-accessory',
  22. '.followup-textarea-container .flex.items-center'
  23. ]
  24. };
  25.  
  26. function initializeFormatter(editorContent, buttonContainer) {
  27. // Create and inject our custom styles
  28. const styleSheet = document.createElement('style');
  29. styleSheet.textContent = `
  30. .public-DraftEditor-content {
  31. font-family: 'Courier New', monospace !important;
  32. line-height: 1.5 !important;
  33. padding: 10px !important;
  34. }
  35. .public-DraftEditor-content pre {
  36. background-color: #f5f5f5 !important;
  37. padding: 8px !important;
  38. border-radius: 4px !important;
  39. margin: 8px 0 !important;
  40. white-space: pre-wrap !important;
  41. }
  42. .public-DraftStyleDefault-block {
  43. white-space: pre-wrap !important;
  44. }
  45. .format-button {
  46. padding: 4px 8px !important;
  47. margin-left: 8px !important;
  48. border-radius: 4px !important;
  49. background-color: #f0f0f0 !important;
  50. border: 1px solid #ccc !important;
  51. cursor: pointer !important;
  52. font-size: 12px !important;
  53. color: #333 !important;
  54. }
  55. .format-button:hover {
  56. background-color: #e0e0e0 !important;
  57. }
  58. `;
  59. document.head.appendChild(styleSheet);
  60.  
  61. // Handle paste events
  62. editorContent.addEventListener('paste', function(e) {
  63. e.preventDefault();
  64.  
  65. let text = e.clipboardData.getData('text/plain');
  66.  
  67. if (isCodeBlock(text)) {
  68. text = formatCodeBlock(text);
  69. }
  70.  
  71. const selection = window.getSelection();
  72. const range = selection.getRangeAt(0);
  73. range.deleteContents();
  74.  
  75. const textNode = document.createTextNode(text);
  76. range.insertNode(textNode);
  77.  
  78. range.setStartAfter(textNode);
  79. range.setEndAfter(textNode);
  80. selection.removeAllRanges();
  81. selection.addRange(range);
  82. });
  83.  
  84. // Add input event listener
  85. editorContent.addEventListener('input', function(e) {
  86. formatCurrentContent(editorContent);
  87. });
  88. }
  89. function isCodeBlock(text) {
  90. const codeIndicators = [
  91. '```',
  92. 'function',
  93. 'class',
  94. 'const',
  95. 'let',
  96. 'var',
  97. 'if(',
  98. 'for(',
  99. 'while(',
  100. '{',
  101. '};',
  102. 'return',
  103. 'import',
  104. 'export',
  105. '<div',
  106. '<span',
  107. '</div>',
  108. 'public-',
  109. 'class='
  110. ];
  111. return codeIndicators.some(indicator => text.includes(indicator));
  112. }
  113.  
  114. function formatCodeBlock(text) {
  115. return text.split('\n').map(line => {
  116. const leadingSpaces = line.match(/^\s*/)[0];
  117. return leadingSpaces + line.trim();
  118. }).join('\n');
  119. }
  120.  
  121. function formatCurrentContent(editorContent) {
  122. const blocks = editorContent.querySelectorAll('.public-DraftStyleDefault-block');
  123. blocks.forEach(block => {
  124. const text = block.textContent;
  125. if (isCodeBlock(text)) {
  126. block.style.whiteSpace = 'pre';
  127. block.style.fontFamily = 'monospace';
  128. block.style.backgroundColor = '#f5f5f5';
  129. block.style.padding = '8px';
  130. block.style.borderRadius = '4px';
  131. block.style.margin = '8px 0';
  132. } else {
  133. block.style.whiteSpace = 'pre-wrap';
  134. block.style.fontFamily = 'inherit';
  135. block.style.backgroundColor = 'transparent';
  136. block.style.padding = '0';
  137. }
  138. });
  139. }
  140.  
  141. // Initialize observers for both editors
  142. function initializeObservers() {
  143. const observer = new MutationObserver((mutations, obs) => {
  144. CONFIG.editorSelectors.forEach((selector, index) => {
  145. const editor = document.querySelector(selector);
  146. const buttonContainer = document.querySelector(CONFIG.buttonContainerSelectors[index]);
  147.  
  148. if (editor && !editor.hasAttribute('data-formatter-initialized')) {
  149. initializeFormatter(editor, buttonContainer);
  150. editor.setAttribute('data-formatter-initialized', 'true');
  151. }
  152. });
  153. });
  154.  
  155. observer.observe(document.body, {
  156. childList: true,
  157. subtree: true
  158. });
  159.  
  160. // Initial check
  161. CONFIG.editorSelectors.forEach((selector, index) => {
  162. const editor = document.querySelector(selector);
  163. const buttonContainer = document.querySelector(CONFIG.buttonContainerSelectors[index]);
  164. if (editor && !editor.hasAttribute('data-formatter-initialized')) {
  165. initializeFormatter(editor, buttonContainer);
  166. editor.setAttribute('data-formatter-initialized', 'true');
  167. }
  168. });
  169. }
  170.  
  171. // Start the initialization process
  172. initializeObservers();
  173. })();

QingJ © 2025

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