11// buttons-clicking-claude.js
22// This file is a dependency for buttons.js. It provides functions to handle the send button clicking process for Claude.
33
4+ 'use strict' ;
45
56/**
67 * Handles text insertion and sending for Claude site
@@ -28,18 +29,14 @@ function processClaudeCustomSendButtonClick(event, customText, autoSend) {
2829
2930/**
3031 * Handles the send button clicking process for Claude
32+ * Uses a promise-based approach to wait for the send button, reducing duplicate code.
3133 */
3234function handleClaudeSend ( ) {
33- // Add timeout and attempt counter for finding send button
34- let attempts = 0 ;
35- const MAX_ATTEMPTS = 50 ;
36- const TIMEOUT_DURATION = 5000 ;
37- let timeoutId ;
38-
39- function findClaudeSendButton ( ) {
40- // Common selectors for Claude send buttons
41- const sendButtonSelectors = window . InjectionTargetsOnWebsite . selectors . sendButtons ;
35+ const TIMEOUT_DURATION = 5000 ; // 5 seconds
4236
37+ // Helper to find a send button using the selectors provided
38+ const findClaudeSendButton = ( ) => {
39+ const sendButtonSelectors = window . InjectionTargetsOnWebsite . selectors . sendButtons ;
4340 for ( const selector of sendButtonSelectors ) {
4441 const button = document . querySelector ( selector ) ;
4542 if ( button ) {
@@ -48,55 +45,55 @@ function handleClaudeSend() {
4845 }
4946 }
5047 return null ;
51- }
48+ } ;
5249
53- // First immediate attempt
54- const sendButton = findClaudeSendButton ( ) ;
55- if ( sendButton ) {
56- logConCgp ( '[Claude] Send button found immediately, delaying click by 200ms' ) ;
57- setTimeout ( ( ) => {
58- MaxExtensionUtils . simulateClick ( sendButton ) ;
59- logConCgp ( '[Claude] Send button clicked after 200ms delay' ) ;
60- } , 200 ) ;
61- return ;
62- }
50+ // Promise-based helper to wait for a send button
51+ const waitForClaudeSendButton = ( timeout = TIMEOUT_DURATION ) => {
52+ return new Promise ( ( resolve , reject ) => {
53+ // Try immediately
54+ const button = findClaudeSendButton ( ) ;
55+ if ( button ) {
56+ return resolve ( button ) ;
57+ }
6358
64- // If not found, set up observer
65- logConCgp ( '[Claude] Send button not found immediately, setting up observer' ) ;
59+ let attempts = 0 ;
60+ const observer = new MutationObserver ( ( ) => {
61+ attempts ++ ;
62+ const btn = findClaudeSendButton ( ) ;
63+ if ( btn ) {
64+ observer . disconnect ( ) ;
65+ logConCgp ( `[Claude] Send button found after ${ attempts } mutation callbacks` ) ;
66+ resolve ( btn ) ;
67+ } else {
68+ logConCgp ( `[Claude] Attempt ${ attempts } : Send button not found yet` ) ;
69+ }
70+ } ) ;
6671
67- const observer = new MutationObserver ( ( mutations , obs ) => {
68- attempts ++ ;
69- const sendButton = findClaudeSendButton ( ) ;
72+ observer . observe ( document . body , { childList : true , subtree : true } ) ;
7073
71- if ( sendButton ) {
72- clearTimeout ( timeoutId ) ;
73- obs . disconnect ( ) ;
74- logConCgp ( '[Claude] Send button found after observation, delaying click by 200ms' ) ;
74+ // Timeout to reject the promise if the button is not found
75+ setTimeout ( ( ) => {
76+ observer . disconnect ( ) ;
77+ reject ( new Error ( 'Timeout reached without finding send button' ) ) ;
78+ } , timeout ) ;
79+ } ) ;
80+ } ;
81+
82+ // Use an async IIFE to wait for the send button and then click it
83+ ( async ( ) => {
84+ try {
85+ const sendButton = await waitForClaudeSendButton ( ) ;
86+ logConCgp ( '[Claude] Send button found, delaying click by 200ms' ) ;
7587 setTimeout ( ( ) => {
7688 MaxExtensionUtils . simulateClick ( sendButton ) ;
7789 logConCgp ( '[Claude] Send button clicked after 200ms delay' ) ;
7890 } , 200 ) ;
79- } else if ( attempts >= MAX_ATTEMPTS ) {
80- clearTimeout ( timeoutId ) ;
81- obs . disconnect ( ) ;
82- logConCgp ( '[Claude] Maximum attempts reached without finding send button' ) ;
83- } else {
84- logConCgp ( `[Claude] Attempt ${ attempts } /${ MAX_ATTEMPTS } : Send button not found yet` ) ;
91+ } catch ( error ) {
92+ logConCgp ( '[Claude] ' + error . message ) ;
8593 }
86- } ) ;
87-
88- observer . observe ( document . body , {
89- childList : true ,
90- subtree : true
91- } ) ;
92-
93- timeoutId = setTimeout ( ( ) => {
94- observer . disconnect ( ) ;
95- logConCgp ( '[Claude] Timeout reached without finding send button' ) ;
96- } , TIMEOUT_DURATION ) ;
94+ } ) ( ) ;
9795}
9896
99-
10097/**
10198 * Utility functions for handling text insertion in Claude's editor
10299 * Handles different editor states and element structures
@@ -241,7 +238,7 @@ const ClaudeEditorUtils = {
241238 // Focus the editor
242239 editorElement . focus ( ) ;
243240
244- // If editor has placeholder, clear it
241+ // If editor has placeholder or is empty, initialize content
245242 if ( editorState . hasPlaceholder || editorState . isEmpty ) {
246243 logConCgp ( '[ClaudeEditor] Editor is empty or has placeholder, initializing content' ) ;
247244 editorElement . innerHTML = '<p><br></p>' ;
@@ -288,6 +285,7 @@ const ClaudeEditorUtils = {
288285
289286 /**
290287 * Inserts text into the editor, handling both empty and non-empty cases
288+ * Uses modern Range and Selection APIs.
291289 * @param {Element } editorElement - The editor element
292290 * @param {string } textToInsert - The text to insert
293291 * @returns {boolean } - Whether the insertion was successful
@@ -298,6 +296,9 @@ const ClaudeEditorUtils = {
298296 editorElement . focus ( ) ;
299297
300298 const selection = window . getSelection ( ) ;
299+ if ( ! selection ) {
300+ throw new Error ( 'Selection API not available' ) ;
301+ }
301302 selection . removeAllRanges ( ) ;
302303 const range = document . createRange ( ) ;
303304
@@ -308,9 +309,7 @@ const ClaudeEditorUtils = {
308309 editorElement . appendChild ( newParagraph ) ;
309310 range . setStart ( newParagraph , 0 ) ;
310311 } else {
311- // Editor has content, append text to last paragraph
312-
313- // Find the last paragraph element
312+ // Editor has content, append text to the last paragraph
314313 const paragraphs = editorElement . querySelectorAll ( 'p' ) ;
315314 let lastParagraph ;
316315 if ( paragraphs . length > 0 ) {
@@ -320,8 +319,6 @@ const ClaudeEditorUtils = {
320319 lastParagraph = document . createElement ( 'p' ) ;
321320 editorElement . appendChild ( lastParagraph ) ;
322321 }
323-
324- // Set the selection to the end of the last paragraph
325322 range . selectNodeContents ( lastParagraph ) ;
326323 range . collapse ( false ) ;
327324 }
0 commit comments