Phind.com Chat Box Text Formatter

Format text in chat box while preserving code spacing

当前为 2025-01-31 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Phind.com Chat Box Text Formatter
  3. // @namespace http://tampermonkey.net/
  4. // @version 0.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. // Create format button
  90. if (buttonContainer) {
  91. createFormatButton(buttonContainer, editorContent);
  92. }
  93. }
  94.  
  95. function isCodeBlock(text) {
  96. const codeIndicators = [
  97. '```',
  98. 'function',
  99. 'class',
  100. 'const',
  101. 'let',
  102. 'var',
  103. 'if(',
  104. 'for(',
  105. 'while(',
  106. '{',
  107. '};',
  108. 'return',
  109. 'import',
  110. 'export',
  111. '<div',
  112. '<span',
  113. '</div>',
  114. 'public-',
  115. 'class='
  116. ];
  117. return codeIndicators.some(indicator => text.includes(indicator));
  118. }
  119.  
  120. function formatCodeBlock(text) {
  121. return text.split('\n').map(line => {
  122. const leadingSpaces = line.match(/^\s*/)[0];
  123. return leadingSpaces + line.trim();
  124. }).join('\n');
  125. }
  126.  
  127. function formatCurrentContent(editorContent) {
  128. const blocks = editorContent.querySelectorAll('.public-DraftStyleDefault-block');
  129. blocks.forEach(block => {
  130. const text = block.textContent;
  131. if (isCodeBlock(text)) {
  132. block.style.whiteSpace = 'pre';
  133. block.style.fontFamily = 'monospace';
  134. block.style.backgroundColor = '#f5f5f5';
  135. block.style.padding = '8px';
  136. block.style.borderRadius = '4px';
  137. block.style.margin = '8px 0';
  138. } else {
  139. block.style.whiteSpace = 'pre-wrap';
  140. block.style.fontFamily = 'inherit';
  141. block.style.backgroundColor = 'transparent';
  142. block.style.padding = '0';
  143. }
  144. });
  145. }
  146.  
  147. function createFormatButton(container, editorContent) {
  148. const existingButton = container.querySelector('.format-button');
  149. if (existingButton) return;
  150.  
  151. const button = document.createElement('button');
  152. button.innerHTML = 'Format';
  153. button.className = 'format-button';
  154.  
  155. button.addEventListener('click', () => formatCurrentContent(editorContent));
  156. container.insertBefore(button, container.firstChild);
  157. }
  158.  
  159. // Initialize observers for both editors
  160. function initializeObservers() {
  161. const observer = new MutationObserver((mutations, obs) => {
  162. CONFIG.editorSelectors.forEach((selector, index) => {
  163. const editor = document.querySelector(selector);
  164. const buttonContainer = document.querySelector(CONFIG.buttonContainerSelectors[index]);
  165.  
  166. if (editor && !editor.hasAttribute('data-formatter-initialized')) {
  167. initializeFormatter(editor, buttonContainer);
  168. editor.setAttribute('data-formatter-initialized', 'true');
  169. }
  170. });
  171. });
  172.  
  173. observer.observe(document.body, {
  174. childList: true,
  175. subtree: true
  176. });
  177.  
  178. // Initial check
  179. CONFIG.editorSelectors.forEach((selector, index) => {
  180. const editor = document.querySelector(selector);
  181. const buttonContainer = document.querySelector(CONFIG.buttonContainerSelectors[index]);
  182. if (editor && !editor.hasAttribute('data-formatter-initialized')) {
  183. initializeFormatter(editor, buttonContainer);
  184. editor.setAttribute('data-formatter-initialized', 'true');
  185. }
  186. });
  187. }
  188.  
  189. // Start the initialization process
  190. initializeObservers();
  191. })();

QingJ © 2025

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