Skip to content

Commit 06985b6

Browse files
committed
Work on issue #10, remember space bounds when resize, move, close happens.
1 parent 384f9e0 commit 06985b6

File tree

8 files changed

+652
-7
lines changed

8 files changed

+652
-7
lines changed

CHANGELOG.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ All notable changes to this project will be documented in this file.
66

77
### Changes
88

9+
- Work on [issue #10](https://github.com/codedread/spaces/issues/10): Remember named space window bounds in the internal database.
910
- Fixed [issue #20](https://github.com/codedread/spaces/issues/20): Close browser windows from the Spaces window.
10-
- Increased unit test coverage from 10.75% to 11.41%.
11-
11+
- Increased unit test coverage from 10.75% to 14.75%.
1212

1313
## [1.1.6] - 2025-09-17
1414

js/background/background.js

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { dbService } from './dbService.js';
1111
import { spacesService } from './spacesService.js';
1212
import * as common from '../common.js';
1313
/** @typedef {common.Space} Space */
14+
/** @typedef {import('./dbService.js').WindowBounds} WindowBounds */
1415

1516
// eslint-disable-next-line no-unused-vars, no-var
1617
let spacesPopupWindowId = false;
@@ -169,6 +170,19 @@ export function initializeServiceWorker() {
169170
spacesService.handleWindowFocussed(windowId);
170171
});
171172

173+
// Listen for window bounds changes (resize/move) with debouncing
174+
chrome.windows.onBoundsChanged.addListener(async (window) => {
175+
if (checkInternalSpacesWindows(window.id, false)) return;
176+
177+
// Capture bounds - await ensures proper event ordering and timer management
178+
await spacesService.captureWindowBounds(window.id, {
179+
left: window.left,
180+
top: window.top,
181+
width: window.width,
182+
height: window.height
183+
});
184+
});
185+
172186
// add listeners for message requests from other extension pages (spaces.html & tab.html)
173187

174188
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
@@ -335,7 +349,14 @@ async function processMessage(request, sender) {
335349
}
336350

337351
try {
338-
await chrome.windows.get(windowId);
352+
const window = await chrome.windows.get(windowId);
353+
// Capture bounds before programmatically closing the window
354+
await spacesService.captureWindowBounds(windowId, {
355+
left: window.left,
356+
top: window.top,
357+
width: window.width,
358+
height: window.height
359+
});
339360
await chrome.windows.remove(windowId);
340361
return true;
341362
} catch (error) {
@@ -909,7 +930,13 @@ async function handleSaveNewSession(windowId, sessionName, deleteOld) {
909930
const result = await spacesService.saveNewSession(
910931
sessionName,
911932
curWindow.tabs,
912-
curWindow.id
933+
curWindow.id,
934+
{
935+
left: curWindow.left,
936+
top: curWindow.top,
937+
width: curWindow.width,
938+
height: curWindow.height
939+
},
913940
);
914941
return result ?? false;
915942
}

js/background/dbService.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,14 @@
22

33
import { db, Server } from './db.js';
44

5+
/**
6+
* @typedef WindowBounds
7+
* @property {number} left The x-coordinate of the window's left edge
8+
* @property {number} top The y-coordinate of the window's top edge
9+
* @property {number} width The width of the window
10+
* @property {number} height The height of the window
11+
*/
12+
513
/**
614
* @typedef Session
715
* @property {number} id Auto-generated indexedDb object id
@@ -10,6 +18,7 @@ import { db, Server } from './db.js';
1018
* @property {Array} tabs An array of chrome tab objects (often taken from the chrome window obj)
1119
* @property {Array} history An array of chrome tab objects that have been removed from the session
1220
* @property {Date} lastAccess Timestamp that gets updated with every window focus
21+
* @property {WindowBounds?} windowBounds Optional saved window position and size
1322
*/
1423

1524
/**

js/background/spacesService.js

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ class SpacesService {
2525
constructor() {
2626
this.tabHistoryUrlMap = {};
2727
this.closedWindowIds = {};
28+
this.boundsUpdateTimers = {};
2829
this.sessionUpdateTimers = {};
2930
this.historyQueue = [];
3031
this.eventQueueCount = 0;
@@ -405,6 +406,50 @@ class SpacesService {
405406
return null;
406407
}
407408

409+
/**
410+
* Captures and stores window bounds for a window with debouncing.
411+
* This is called when window bounds change to ensure we have current bounds
412+
* without excessive database writes during rapid resize/move operations.
413+
*
414+
* @param {number} windowId - The ID of the window to capture bounds for
415+
* @param {Object} bounds - The window bounds object with left, top, width, height
416+
* @returns {Promise<void>}
417+
*/
418+
async captureWindowBounds(windowId, bounds) {
419+
await this.ensureInitialized();
420+
421+
const session = await this.getSessionByWindowId(windowId);
422+
if (session && session.id) {
423+
// Update bounds in memory immediately for responsiveness
424+
session.windowBounds = {
425+
left: bounds.left,
426+
top: bounds.top,
427+
width: bounds.width,
428+
height: bounds.height
429+
};
430+
431+
if (debug) {
432+
// eslint-disable-next-line no-console
433+
console.log(`Captured window bounds for session ${session.id}:`, session.windowBounds);
434+
}
435+
436+
// Debounce database writes to avoid excessive I/O during rapid resize/move
437+
clearTimeout(this.boundsUpdateTimers[windowId]);
438+
this.boundsUpdateTimers[windowId] = setTimeout(async () => {
439+
try {
440+
// Save bounds to database after debounce period
441+
await this._updateSessionSync(session);
442+
if (debug) {
443+
// eslint-disable-next-line no-console
444+
console.log(`Saved window bounds to database for session ${session.id}`);
445+
}
446+
} catch (error) {
447+
console.error(`Error saving bounds for session ${session.id}:`, error);
448+
}
449+
}, 1000); // 1 second debounce - adjust as needed
450+
}
451+
}
452+
408453
// event listener functions for window and tab events
409454
// (events are received and screened first in background.js)
410455
// -----------------------------------------------------------------------------------------
@@ -530,6 +575,7 @@ class SpacesService {
530575
}
531576

532577
this.closedWindowIds[windowId] = true;
578+
clearTimeout(this.boundsUpdateTimers[windowId]);
533579
clearTimeout(this.sessionUpdateTimers[windowId]);
534580
}
535581

@@ -538,7 +584,7 @@ class SpacesService {
538584
// if this is a saved session then just remove the windowId reference
539585
if (session.id) {
540586
session.windowId = false;
541-
// Persist the cleared windowId to database with sync
587+
// Persist the window to database with sync
542588
await this._updateSessionSync(session);
543589

544590
// else if it is temporary session then remove the session from the cache
@@ -856,11 +902,12 @@ class SpacesService {
856902
* @param {string} sessionName - The name for the new session
857903
* @param {Array<Object>} tabs - Array of tab objects containing URL and other tab properties
858904
* @param {number|false} windowId - The window ID to associate with this session, or false for no association
905+
* @param {WindowBounds} [windowBounds] - Optional window bounds to save with the session
859906
* @returns {Promise<Session|null>} Promise that resolves to:
860907
* - Session object with id property if successfully created
861908
* - null if session creation failed, no tabs were provided, or attempted on already saved session
862909
*/
863-
async saveNewSession(sessionName, tabs, windowId) {
910+
async saveNewSession(sessionName, tabs, windowId, windowBounds) {
864911
await this.ensureInitialized();
865912

866913
if (!tabs) {
@@ -909,6 +956,11 @@ class SpacesService {
909956
session.sessionHash = sessionHash;
910957
session.tabs = tabs;
911958
session.lastAccess = new Date();
959+
960+
// Add window bounds if provided
961+
if (windowBounds) {
962+
session.windowBounds = windowBounds;
963+
}
912964

913965
// save session to db - this should only be called on temporary sessions (id: false)
914966
try {

manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "Spaces",
33
"description": "Intuitive tab management",
4-
"version": "1.1.7.0",
4+
"version": "1.1.7.1",
55
"permissions": [
66
"contextMenus",
77
"favicon",

0 commit comments

Comments
 (0)