99// Methods included:
1010// - addToQueue(buttonConfig): Adds a prompt to the queue.
1111// - removeFromQueue(index): Removes a prompt from the queue by its index.
12- // - startQueue(): Begins the sequential sending process.
13- // - pauseQueue(): Pauses the sending process.
14- // - resetQueue(): Stops and clears the entire queue.
12+ // - startQueue(): Begins or resumes the sequential sending process.
13+ // - pauseQueue(): Pauses the sending process, remembering the elapsed time.
14+ // - resetQueue(): Stops and clears the entire queue and resets timer state.
15+ // - recalculateRunningTimer(): Adjusts the current timer and progress bar when the delay is changed.
1516// - processNextQueueItem(): The core function that sends one item and sets a timer for the next.
1617// - getSiteSpecificSendFunction(): A helper to determine which site-specific send function to use.
1718//
2829window . MaxExtensionFloatingPanel . addToQueue = function ( buttonConfig ) {
2930 if ( this . promptQueue . length >= this . QUEUE_MAX_SIZE ) {
3031 logConCgp ( '[queue-engine] Queue is full. Cannot add more prompts.' ) ;
31- // Optional: Add visual feedback for the user
3232 if ( this . queueDisplayArea ) {
3333 this . queueDisplayArea . style . borderColor = 'red' ;
3434 setTimeout ( ( ) => {
@@ -58,40 +58,77 @@ window.MaxExtensionFloatingPanel.removeFromQueue = function (index) {
5858} ;
5959
6060/**
61- * Starts the queue processing.
61+ * Starts or resumes the queue processing.
6262 */
6363window . MaxExtensionFloatingPanel . startQueue = function ( ) {
64- if ( this . isQueueRunning || this . promptQueue . length === 0 ) {
64+ // Prevent starting if already running, or if there's nothing to do.
65+ if ( this . isQueueRunning || ( this . promptQueue . length === 0 && this . remainingTimeOnPause <= 0 ) ) {
6566 return ;
6667 }
6768 this . isQueueRunning = true ;
68- logConCgp ( '[queue-engine] Queue started.' ) ;
69+ this . updateQueueControlsState ( ) ;
6970
70- // Show progress bar container when queue starts
7171 if ( this . queueProgressContainer ) {
7272 this . queueProgressContainer . style . display = 'block' ;
7373 }
7474
75- this . updateQueueControlsState ( ) ;
76- this . processNextQueueItem ( ) ;
75+ // If we have remaining time, we are resuming a paused timer.
76+ if ( this . remainingTimeOnPause > 0 ) {
77+ logConCgp ( `[queue-engine] Resuming queue with ${ this . remainingTimeOnPause } ms remaining.` ) ;
78+
79+ const elapsedTimeBeforePause = this . currentTimerDelay - this . remainingTimeOnPause ;
80+ const progressPercentage = ( elapsedTimeBeforePause / this . currentTimerDelay ) * 100 ;
81+
82+ // Restore the conceptual start time for accurate future calculations.
83+ this . timerStartTime = Date . now ( ) - elapsedTimeBeforePause ;
84+
85+ // Resume progress bar animation from its paused state.
86+ if ( this . queueProgressBar ) {
87+ this . queueProgressBar . style . transition = 'none' ;
88+ this . queueProgressBar . style . width = `${ progressPercentage } %` ;
89+ void this . queueProgressBar . offsetWidth ; // Force reflow
90+ this . queueProgressBar . style . transition = `width ${ this . remainingTimeOnPause / 1000 } s linear` ;
91+ this . queueProgressBar . style . width = '100%' ;
92+ }
93+
94+ this . queueTimerId = setTimeout ( ( ) => {
95+ this . remainingTimeOnPause = 0 ; // Clear the remainder state
96+ this . processNextQueueItem ( ) ;
97+ } , this . remainingTimeOnPause ) ;
98+
99+ } else {
100+ // This is a fresh start, so process the first item immediately.
101+ logConCgp ( '[queue-engine] Queue started.' ) ;
102+ this . processNextQueueItem ( ) ;
103+ }
77104} ;
78105
79106/**
80- * Pauses the queue processing.
107+ * Pauses the queue processing and saves the remaining time .
81108 */
82109window . MaxExtensionFloatingPanel . pauseQueue = function ( ) {
83110 this . isQueueRunning = false ;
111+
84112 if ( this . queueTimerId ) {
85113 clearTimeout ( this . queueTimerId ) ;
86114 this . queueTimerId = null ;
115+
116+ const elapsedTime = Date . now ( ) - this . timerStartTime ;
117+ // Ensure remaining time doesn't go negative if the timer fires slightly late.
118+ this . remainingTimeOnPause = ( elapsedTime < this . currentTimerDelay )
119+ ? this . currentTimerDelay - elapsedTime
120+ : 0 ;
121+
122+ logConCgp ( `[queue-engine] Queue paused. Remaining time: ${ this . remainingTimeOnPause } ms` ) ;
123+ } else {
124+ logConCgp ( '[queue-engine] Queue paused.' ) ;
87125 }
88- logConCgp ( '[queue-engine] Queue paused.' ) ;
89126
90- // Freeze the progress bar
127+ // Freeze the progress bar at its current position.
91128 if ( this . queueProgressBar ) {
92129 const computedWidth = window . getComputedStyle ( this . queueProgressBar ) . width ;
93- this . queueProgressBar . style . transition = 'none' ;
94- this . queueProgressBar . style . width = computedWidth ;
130+ this . queueProgressBar . style . transition = 'none' ; // Stop animation
131+ this . queueProgressBar . style . width = computedWidth ; // Freeze at current width
95132 }
96133
97134 this . updateQueueControlsState ( ) ;
@@ -103,19 +140,80 @@ window.MaxExtensionFloatingPanel.pauseQueue = function () {
103140window . MaxExtensionFloatingPanel . resetQueue = function ( ) {
104141 this . pauseQueue ( ) ; // Stop any running timers and set isQueueRunning to false
105142 this . promptQueue = [ ] ;
143+ // Reset all timer-related state.
144+ this . remainingTimeOnPause = 0 ;
145+ this . timerStartTime = 0 ;
146+ this . currentTimerDelay = 0 ;
106147 logConCgp ( '[queue-engine] Queue reset.' ) ;
107148
108- // Hide and reset progress bar
149+ // Hide and reset progress bar to 0%.
109150 if ( this . queueProgressBar ) {
110151 this . queueProgressBar . style . transition = 'none' ;
111- this . queueProgressBar . style . width = '100 %' ;
152+ this . queueProgressBar . style . width = '0 %' ;
112153 }
113154 if ( this . queueProgressContainer ) {
114155 this . queueProgressContainer . style . display = 'none' ;
115156 }
116157
117158 this . renderQueueDisplay ( ) ;
118- this . updateQueueControlsState ( ) ; // This will disable buttons as needed
159+ this . updateQueueControlsState ( ) ;
160+ } ;
161+
162+ /**
163+ * Recalculates the running timer when the delay value is changed.
164+ * This function adjusts the progress bar and timer to reflect the new total delay.
165+ */
166+ window . MaxExtensionFloatingPanel . recalculateRunningTimer = function ( ) {
167+ // Only act if a timer is currently running.
168+ if ( ! this . isQueueRunning || ! this . queueTimerId ) {
169+ return ;
170+ }
171+
172+ logConCgp ( '[queue-engine] Recalculating timer due to delay change.' ) ;
173+
174+ clearTimeout ( this . queueTimerId ) ;
175+
176+ // Calculate how much time has passed on the current timer.
177+ const elapsedTime = Date . now ( ) - this . timerStartTime ;
178+
179+ // Get the new total delay from the configuration.
180+ const unit = globalMaxExtensionConfig . queueDelayUnit || 'min' ;
181+ let newTotalDelayMs ;
182+ if ( unit === 'sec' ) {
183+ newTotalDelayMs = ( globalMaxExtensionConfig . queueDelaySeconds || 300 ) * 1000 ;
184+ } else { // 'min'
185+ newTotalDelayMs = ( globalMaxExtensionConfig . queueDelayMinutes || 5 ) * 60 * 1000 ;
186+ }
187+
188+ // If time is up with the new delay, process next item.
189+ if ( elapsedTime >= newTotalDelayMs ) {
190+ logConCgp ( '[queue-engine] New delay is less than elapsed time. Processing next item.' ) ;
191+ this . remainingTimeOnPause = 0 ;
192+ this . processNextQueueItem ( ) ;
193+ } else {
194+ // Otherwise, set a new timer for the adjusted remaining time.
195+ const newRemainingTime = newTotalDelayMs - elapsedTime ;
196+ logConCgp ( `[queue-engine] New remaining time is ${ newRemainingTime } ms.` ) ;
197+
198+ // Update the total delay for this timer, critical for subsequent actions.
199+ this . currentTimerDelay = newTotalDelayMs ;
200+
201+ this . queueTimerId = setTimeout ( ( ) => this . processNextQueueItem ( ) , newRemainingTime ) ;
202+
203+ // Instantly update the progress bar to reflect the new reality.
204+ if ( this . queueProgressBar ) {
205+ const newProgressPercentage = ( elapsedTime / newTotalDelayMs ) * 100 ;
206+
207+ // Set the new progress instantly.
208+ this . queueProgressBar . style . transition = 'none' ;
209+ this . queueProgressBar . style . width = `${ newProgressPercentage } %` ;
210+ void this . queueProgressBar . offsetWidth ; // Force reflow to apply the new width.
211+
212+ // Animate to 100% over the new remaining time.
213+ this . queueProgressBar . style . transition = `width ${ newRemainingTime / 1000 } s linear` ;
214+ this . queueProgressBar . style . width = '100%' ;
215+ }
216+ }
119217} ;
120218
121219/**
@@ -128,31 +226,28 @@ window.MaxExtensionFloatingPanel.processNextQueueItem = function () {
128226
129227 if ( this . promptQueue . length === 0 ) {
130228 logConCgp ( '[queue-engine] Queue is empty. Stopping.' ) ;
131- this . pauseQueue ( ) ; // Effectively stops and resets the UI
229+ this . pauseQueue ( ) ;
132230 return ;
133231 }
134232
135- const item = this . promptQueue . shift ( ) ; // Get the first item and remove it
136- this . renderQueueDisplay ( ) ; // Update UI to show the item is gone
233+ const item = this . promptQueue . shift ( ) ;
234+ this . renderQueueDisplay ( ) ;
137235 logConCgp ( `[queue-engine] Sending item:` , item . text ) ;
138236
139237 const sendFunction = this . getSiteSpecificSendFunction ( ) ;
140238 if ( sendFunction ) {
141- // A mock event object is sufficient for the send functions
142239 const mockEvent = { preventDefault : ( ) => { } } ;
143- // Always force auto-send for queued items by passing `true`, overriding the button's individual setting.
144240 sendFunction ( mockEvent , item . text , true ) ;
145241 } else {
146242 logConCgp ( '[queue-engine] No send function found for this site. Stopping queue.' ) ;
147243 this . resetQueue ( ) ;
148244 return ;
149245 }
150246
151- // If there are more items, set a timeout for the next one
247+ // If there are more items, set a timeout for the next one.
152248 if ( this . promptQueue . length > 0 ) {
153249 const unit = globalMaxExtensionConfig . queueDelayUnit || 'min' ;
154250 let delayMs ;
155-
156251 if ( unit === 'sec' ) {
157252 const delaySec = globalMaxExtensionConfig . queueDelaySeconds || 300 ;
158253 delayMs = delaySec * 1000 ;
@@ -163,34 +258,39 @@ window.MaxExtensionFloatingPanel.processNextQueueItem = function () {
163258 logConCgp ( `[queue-engine] Waiting for ${ delayMin } minutes before next item.` ) ;
164259 }
165260
166- // Start the progress bar animation
261+ // Start the progress bar animation from 0% to 100%.
167262 if ( this . queueProgressBar ) {
168- // Reset to full width instantly, then start the transition
169263 this . queueProgressBar . style . transition = 'none' ;
170- this . queueProgressBar . style . width = '100 %' ;
264+ this . queueProgressBar . style . width = '0 %' ;
171265
172- // Force reflow to apply the reset before starting transition
173266 setTimeout ( ( ) => {
174267 this . queueProgressBar . style . transition = `width ${ delayMs / 1000 } s linear` ;
175- this . queueProgressBar . style . width = '0 %' ;
268+ this . queueProgressBar . style . width = '100 %' ;
176269 } , 20 ) ;
177270 }
178271
272+ this . timerStartTime = Date . now ( ) ;
273+ this . currentTimerDelay = delayMs ;
274+ this . remainingTimeOnPause = 0 ; // Ensure reset for a new timer.
179275 this . queueTimerId = setTimeout ( ( ) => this . processNextQueueItem ( ) , delayMs ) ;
180276 } else {
181277 logConCgp ( '[queue-engine] All items have been sent.' ) ;
182- this . pauseQueue ( ) ; // Queue finished, so pause/stop
278+ // Visually complete the progress bar.
279+ if ( this . queueProgressBar ) {
280+ this . queueProgressBar . style . transition = 'none' ;
281+ this . queueProgressBar . style . width = '100%' ;
282+ }
283+ this . pauseQueue ( ) ; // Queue finished, so pause/stop.
183284
184- // Hide progress bar after a short delay to let animation finish
285+ // Hide progress bar after a short delay.
185286 setTimeout ( ( ) => {
186287 if ( this . queueProgressContainer && ! this . isQueueRunning ) {
187288 this . queueProgressContainer . style . display = 'none' ;
188289 if ( this . queueProgressBar ) {
189- this . queueProgressBar . style . transition = 'none' ;
190- this . queueProgressBar . style . width = '100%' ;
290+ this . queueProgressBar . style . width = '0%' ; // Reset for next time.
191291 }
192292 }
193- } , 1000 ) ; // Wait 1 second after finish to hide
293+ } , 1000 ) ;
194294 }
195295} ;
196296
0 commit comments