* DeepShare DOCX Button Injector * Injects a DOCX conversion button into the DeepSeek interface
()
| 4 | */ |
| 5 | |
| 6 | function injectDocxButton() { |
| 7 | console.debug('Initializing DOCX button injection'); |
| 8 | let floatingContainer = null; |
| 9 | |
| 10 | // Function to observe and inject the button |
| 11 | function observeAndInjectButton() { |
| 12 | // Create a mutation observer to watch for the copy button |
| 13 | const observer = new MutationObserver((mutations) => { |
| 14 | for (const mutation of mutations) { |
| 15 | if (mutation.type === 'childList') { |
| 16 | // More robust selector targeting button containers and groups |
| 17 | const buttonContainers = document.querySelectorAll('.ds-flex[style*="align-items"][style*="gap"], div[class*="ds-flex"][style*="align-items: center"]'); |
| 18 | |
| 19 | buttonContainers.forEach(container => { |
| 20 | // Find button groups more flexibly - look for containers with gap and align-items |
| 21 | const buttonGroup = container.querySelector('.ds-flex[style*="align-items"][style*="gap"], div[class*="ds-flex"][style*="align-items"]') || container; |
| 22 | |
| 23 | // Look for copy buttons using multiple strategies |
| 24 | let copyButtons = buttonGroup.querySelectorAll('[role="button"][tabindex]'); |
| 25 | |
| 26 | // Fallback: look for clickable divs that might be buttons |
| 27 | if (copyButtons.length === 0) { |
| 28 | copyButtons = buttonGroup.querySelectorAll('div[tabindex][role], div[style*="cursor"][role]'); |
| 29 | } |
| 30 | |
| 31 | // Further fallback: look for elements with button-like characteristics |
| 32 | if (copyButtons.length === 0) { |
| 33 | copyButtons = buttonGroup.querySelectorAll('div[class*="button"], div[class*="btn"], div[style*="cursor: pointer"]'); |
| 34 | } |
| 35 | |
| 36 | copyButtons.forEach(copyBtn => { |
| 37 | // More flexible check for copy button with prioritized strategies |
| 38 | // Strategy 1: .ds-icon-button class with role attribute and SVG path starting with M6.149 |
| 39 | const isStrategy1 = copyBtn.classList.contains('ds-icon-button') && |
| 40 | copyBtn.hasAttribute('role') && |
| 41 | copyBtn.querySelector('svg path[d^="M6.149"]'); |
| 42 | |
| 43 | // Strategy 2 (most stable): First button with role="button" |
| 44 | const isStrategy2 = copyBtn === buttonGroup.querySelector('[role="button"]') || |
| 45 | copyBtn === Array.from(buttonGroup.children).find(child => |
| 46 | child.hasAttribute('role') && child.getAttribute('role') === 'button'); |
| 47 | |
| 48 | const isCopyButton = isStrategy1 || isStrategy2; |
| 49 | |
| 50 | if (!isCopyButton) return; |
| 51 | |
| 52 | // Check if this is an AI response (not a user message) |
| 53 | // Strategy: Look for distinctive patterns between user messages and AI responses |
| 54 | |
| 55 | // 1. User messages have the "d29f3d7d" class in their ds-message container |
| 56 | const isUserMessage = copyBtn.closest('.d29f3d7d, [class*="d29f3d7d"]'); |
| 57 | |
| 58 | // 2. AI responses are in containers with "_4f9bf79" class |
| 59 | const isAIContainer = copyBtn.closest('._4f9bf79, [class*="_4f9bf79"]'); |
| 60 | |
| 61 | // 3. AI responses typically have markdown content nearby |
| 62 | const nearbyMarkdown = copyBtn.closest('div').querySelector('.ds-markdown') || |
| 63 | copyBtn.parentElement?.parentElement?.querySelector('.ds-markdown'); |
no test coverage detected