]>
git.wh0rd.org - chrome-ext/tabs-backup.git/blob - background.js
1 // Migrate old localStorage to chrome.storage.local.
2 if (localStorage
.prefsMaxBackupItems
!== undefined) {
3 chrome
.storage
.local
.set({
4 prefs_max_backup_items
: parseInt(localStorage
.prefsMaxBackupItems
),
6 localStorage
.removeItem("prefsMaxBackupItems");
8 if (localStorage
.prefsBackupTimer
!== undefined) {
9 chrome
.storage
.local
.set({
10 prefs_backup_timer
: parseInt(localStorage
.prefsBackupTimer
),
12 localStorage
.removeItem("prefsBackupTimer");
14 if (localStorage
.prefsTheme
!== undefined) {
15 chrome
.storage
.local
.set({
16 prefs_theme
: localStorage
.prefsTheme
,
18 localStorage
.removeItem("prefsTheme");
20 localStorage
.removeItem("lastBackupTime");
22 // Create a backup on first install (or if storage is wiped for some reason.
23 chrome
.storage
.local
.get(function(items
) {
25 if (items
.prefs_max_backup_items
=== undefined) {
26 chrome
.storage
.local
.set({prefs_max_backup_items
: 10});
28 if (items
.prefs_backup_timer
=== undefined) {
29 chrome
.storage
.local
.set({prefs_backup_timer
: 30});
32 // If a backup exists already, nothing to do.
33 if (items
.backups_list
) {
37 // Create a backup now
39 var formattedDate
= date_format (d
);
41 backupNow(true, formattedDate
, function({success
, backupName
, backupObj
}) {
46 function initAlarm () {
47 //console.log("initAlarm");
49 var BACKUP_ALARM_NAME
= "backup_alarm";
51 // Clear any previous alarm
52 chrome
.alarms
.clearAll();
54 chrome
.storage
.local
.get(function(items
) {
55 const timerMinutes
= items
.prefs_backup_timer
;
56 chrome
.alarms
.create(BACKUP_ALARM_NAME
, {periodInMinutes
: timerMinutes
});
62 function onAlarm (alarm
) {
64 var formattedDate
= date_format (d
);
66 console
.log("Alarm {" + alarm
+ "} fired up: " + formattedDate
);
68 // if last backup time != lastTabsEdit
69 // perform automatic backup
70 backupNow(true, formattedDate
, function({success
, backupName
, backupObj
}) {
71 // automatic backup completed
72 var popupViews
= chrome
.extension
.getViews({type
: "popup"});
73 if (popupViews
.length
> 0) {
74 for (var i
= 0; i
< popupViews
.length
; i
++) {
75 var popupView
= popupViews
[i
];
76 if (!popupView
.insertBackupItem
) {
80 popupView
.insertBackupItem(backupName
, backupObj
, true /*insertAtBeginning*/, true /*doAnimation*/);
81 popupView
.updateStorageInfo();
87 chrome
.alarms
.onAlarm
.addListener(onAlarm
);
89 function date_prependZero (val
) {
90 return val
< 10 ? "0" + val
: "" + val
;
94 function date_format (d
) {
95 var monthOneOffset
= d
.getMonth() + 1; // convert from 0-11 to 1-12
97 var formattedDate
= d
.getFullYear() + "-" + date_prependZero(monthOneOffset
) + "-" + date_prependZero(d
.getDate())
98 + " " + date_prependZero(d
.getHours()) + ":" + date_prependZero(d
.getMinutes()) + ":" + date_prependZero(d
.getSeconds());
100 return formattedDate
;
104 function backupNowManual (callbackDone
) {
106 var formattedDate
= date_format (d
);
108 backupNow(false, formattedDate
, callbackDone
);
113 function deleteOldestBackup () {
114 chrome
.storage
.local
.get(function(items
) {
115 if(!items
.backups_list
) {
119 var backupsList
= items
.backups_list
;
120 var numItemsToDelete
= backupsList
.length
- items
.prefs_max_backup_items
;
121 if (numItemsToDelete
> 0) {
123 var loopFunc = function () {
126 var deletedBackupName
= backupsList
[i
-1];
127 var popupViews
= chrome
.extension
.getViews({type
: "popup"});
128 if (popupViews
.length
> 0) {
129 for (var j
= 0; j
< popupViews
.length
; j
++) {
130 var popupView
= popupViews
[j
];
131 if (!popupView
.removeBackupItemDiv
) {
135 popupView
.removeBackupItemDiv(deletedBackupName
);
136 popupView
.updateStorageInfo();
142 if (i
>= numItemsToDelete
) {
146 deleteBackup (backupsList
[i
], loopFunc
);
153 //for (var i = 0; i < numItemsToDelete; i++) {
154 // TODO WARNING: I'm calling deleteBackup rapidly, while deleting is async...(I should wait for each delete to complete before deleting the next)
155 //deleteBackup (backupsList[i], function() {
163 //var isCreatingBackup = false;
165 function backupNow(isAutomatic
, backupName
, callbackDone
) {
166 console
.log("backupNow - isAutomatic: " + isAutomatic
+ " name: " + backupName
);
167 /*if (isCreatingBackup === true) {
168 console.log("backupNow - already running..skipping..");
172 //isCreatingBackup = true;
174 /*if (!confirm("Perform a full backup? All windows and their tabs will be saved!")) {
180 isAutomatic
: isAutomatic
,
184 chrome
.windows
.getAll({populate
: true}, function (window_list
) {
187 for(var i
=0;i
<window_list
.length
;i
++) {
188 var window
= window_list
[i
];
190 //console.log ("Window " + i);
197 height
: window
.height
,
201 var windowTabs
= window
.tabs
;
203 // If it's a single window sittig at the new tab page, don't bother
204 // saving it. This is a nice shortcut when things crash as it will
205 // only show a single window.
206 if (windowTabs
.length
== 1) {
207 const tab
= windowTabs
[0];
208 if (tab
.url
== 'chrome://newtab/')
212 for (var j
= 0; j
< windowTabs
.length
; j
++) {
213 var tab
= windowTabs
[j
];
215 //console.log("==> Tab " + j + " (" + tab.index + "): " + tabUrl);
220 highlighted
: tab
.highlighted
,
224 // Add tab to tabs arrays
225 bkpWindow
.tabs
.push(bkpTab
);
228 totNumTabs
+= windowTabs
.length
;
230 fullBackup
.windows
.push(bkpWindow
);
236 fullBackup
.totNumTabs
= totNumTabs
;
238 var storageSetValues
= {};
239 storageSetValues
[backupName
] = fullBackup
;
242 chrome
.storage
.local
.set(storageSetValues
, function () {
243 if (chrome
.runtime
.lastError
) {
244 //isCreatingBackup = false;
245 // TODO change icon to error..
246 //alert ("Error: " + chrome.runtime.lastError.message);
247 updateBrowserActionIcon (1);
249 callbackDone({success
: false});
251 console
.log("backup saved");
252 //alert("Backup saved successfully!");
254 chrome
.storage
.local
.get(function(items
) {
255 var backupsList
= [];
256 if(items
.backups_list
) {
257 backupsList
= items
.backups_list
;
260 console
.log("Updating 'backups_list' - cur. size: " + backupsList
.length
);
262 backupsList
.push(backupName
);
264 chrome
.storage
.local
.set({"backups_list": backupsList
}, function () {
265 //isCreatingBackup = false;
267 if (chrome
.runtime
.lastError
) {
268 console
.log ("Error saving backups_list: " + chrome
.runtime
.lastError
.message
);
269 updateBrowserActionIcon (1);
270 callbackDone({success
: false});
272 console
.log("Backups list saved successfully");
274 updateBrowserActionIcon (0);
278 backupObj
: fullBackup
,
281 if (backupsList
.length
> items
.prefs_max_backup_items
) {
282 deleteOldestBackup();
296 function updateBrowserActionIcon (status
) {
300 icon
= "icon_ok.png";
303 icon
= "icon_error.png";
307 chrome
.browserAction
.setIcon({path
: icon
});
310 function deleteBackup (backupName
, callback
) {
311 console
.log("Deleting backup " + backupName
);
313 chrome
.storage
.local
.remove(backupName
, function() {
314 //console.log ("=> Deleted backup " + backupName);
316 chrome
.storage
.local
.get("backups_list", function(items
) {
317 //console.log ("==> got backups_list " + backupName);
319 if(!items
.backups_list
) {
324 var backupsList
= items
.backups_list
;
326 var index
= backupsList
.indexOf(backupName
);
328 backupsList
.splice(index
, 1);
331 //console.log ("===> Updating backups_list (removing " + backupName + ")");
333 chrome
.storage
.local
.set({"backups_list": backupsList
}, function() {
334 //console.log ("===> Updated backups_list (removed " + backupName + ")");
339 //console.log ("==> EXIT got backups_list " + backupName);
342 //console.log ("=> EXIT Deleted backup " + backupName);
345 //console.log("EXIT Deleting backup " + backupName);
350 function restoreNow(backupName
) {
351 console
.log("restoreNow");
353 chrome
.storage
.local
.get(backupName
, function(items
) {
354 if(!items
[backupName
]) {
355 alert("No Backup found");
359 /*if (!confirm("Restore full backup?")) {
363 if (confirm("Would you like to close all existing windows first?")) {
364 chrome.windows.getAll({populate : false}, function (window_list) {
365 for(var i=0;i<window_list.length;i++) {
366 var window = window_list[i];
367 chrome.windows.remove(window.id);
373 var fullBackup
= items
[backupName
];
375 for(var i
=0;i
<fullBackup
.windows
.length
;i
++) {
376 const window
= fullBackup
.windows
[i
];
378 //console.log ("Window " + i);
382 const windowTabs
= window
.tabs
;
383 for (let j
= 0; j
< windowTabs
.length
; j
++) {
384 const tab
= windowTabs
[j
];
385 const tabUrl
= tab
.url
;
386 urlsToOpen
.push(tabUrl
);
389 const windowProperties
= {
395 height
: window
.height
,
398 // Create a new Window
399 chrome
.windows
.create(windowProperties
, function(createdWindow
) {
400 // Chrome errors if the dimensions are set on non-normal windows.
401 // So we create the window first with the right settings, then
402 // update the window state.
403 if (window
.state
!= 'normal') {
404 chrome
.windows
.update(createdWindow
.id
, {state
: window
.state
});
407 chrome
.windows
.get(createdWindow
.id
, {populate
: true}, ({tabs
}) => {
408 for (let tabi
= 0; tabi
< windowTabs
.length
; ++tabi
) {
409 const oldtab
= windowTabs
[tabi
];
410 const newtab
= tabs
[tabi
];
411 chrome
.tabs
.update(newtab
.id
, {
412 highlighted
: oldtab
.highlighted
,
413 pinned
: oldtab
.pinned
,
415 if (!oldtab
.highlighted
) {
416 // If we discard a tab too fast, Chrome will completely
417 // throw it away. Wait until it's in a stable enough
418 // state for us to discard it.
420 const checktab
= (id
) => {
421 if (retryCount
-- < 0)
423 chrome
.tabs
.get(id
, (tab
) => {
425 setTimeout(() => checktab(id
), 500);
427 chrome
.tabs
.discard(id
);
441 * Callback from other pages (like the popup).
443 chrome
.runtime
.onMessage
.addListener(function(request
, sender
, sendResponse
) {
444 console
.log(`Got message from ${sender.id}: action=${request.action}`, request
);
446 let asyncResponse
= false;
447 switch (request
?.action
) {
453 restoreNow(...request
.args
);
457 deleteBackup(...request
.args
, sendResponse
);
458 asyncResponse
= true;
461 case 'backupNowManual':
462 backupNowManual(sendResponse
);
463 asyncResponse
= true;
466 return asyncResponse
;