]> git.wh0rd.org - chrome-ext/tabs-backup.git/blob - background.js
add extended window/tab details to restore page
[chrome-ext/tabs-backup.git] / background.js
1
2 // Set default values if needed
3 if (!localStorage.prefsMaxBackupItems) {
4 localStorage.prefsMaxBackupItems = "10";
5 }
6
7 if (!localStorage.prefsBackupTimer) {
8 localStorage.prefsBackupTimer = "30";
9 }
10
11 if (!localStorage.lastBackupTime) {
12 localStorage.lastBackupTime = -1;
13
14 // Create a backup now
15 var d = new Date();
16 var formattedDate = date_format (d);
17
18 backupNow(true, formattedDate, function(success, backupName, backupObj) {
19 // backup completed
20 });
21 }
22
23 function initAlarm () {
24 //console.log("initAlarm");
25
26 var BACKUP_ALARM_NAME = "backup_alarm";
27
28 // Clear any previous alarm
29 chrome.alarms.clearAll();
30
31 var timerMinutes = parseInt(localStorage.prefsBackupTimer);
32 chrome.alarms.create(BACKUP_ALARM_NAME, {periodInMinutes: timerMinutes});
33 }
34
35 initAlarm();
36
37 function onAlarm (alarm) {
38 var d = new Date();
39 var formattedDate = date_format (d);
40
41 console.log("Alarm {" + alarm + "} fired up: " + formattedDate);
42
43 // if last backup time != lastTabsEdit
44 // perform automatic backup
45 backupNow(true, formattedDate, function(success, backupName, backupObj) {
46 // automatic backup completed
47 var popupViews = chrome.extension.getViews({type: "popup"});
48 if (popupViews.length > 0) {
49 for (var i = 0; i < popupViews.length; i++) {
50 var popupView = popupViews[i];
51 if (!popupView.insertBackupItem) {
52 continue;
53 }
54
55 popupView.insertBackupItem(backupName, backupObj, true /*insertAtBeginning*/, true /*doAnimation*/);
56 popupView.updateStorageInfo();
57 }
58 }
59 });
60 }
61
62 chrome.alarms.onAlarm.addListener(onAlarm);
63
64 function date_prependZero (val) {
65 return val < 10 ? "0" + val : "" + val;
66 }
67
68 // yyyy-m-d h:i:s
69 function date_format (d) {
70 var monthOneOffset = d.getMonth() + 1; // convert from 0-11 to 1-12
71
72 var formattedDate = d.getFullYear() + "-" + date_prependZero(monthOneOffset) + "-" + date_prependZero(d.getDate())
73 + " " + date_prependZero(d.getHours()) + ":" + date_prependZero(d.getMinutes()) + ":" + date_prependZero(d.getSeconds());
74
75 return formattedDate;
76 }
77
78
79 function backupNowManual (callbackDone) {
80 var d = new Date();
81 var formattedDate = date_format (d);
82
83 backupNow(false, formattedDate, callbackDone);
84
85
86 }
87
88 function deleteOldestBackup () {
89 chrome.storage.local.get("backups_list", function(items) {
90 if(!items.backups_list) {
91 return;
92 }
93
94 var backupsList = items.backups_list;
95 var numItemsToDelete = backupsList.length - parseInt(localStorage.prefsMaxBackupItems);
96 if (numItemsToDelete > 0) {
97 var i = 0;
98 var loopFunc = function () {
99 //
100 if (i > 0) {
101 var deletedBackupName = backupsList[i-1];
102 var popupViews = chrome.extension.getViews({type: "popup"});
103 if (popupViews.length > 0) {
104 for (var j = 0; j < popupViews.length; j++) {
105 var popupView = popupViews[j];
106 if (!popupView.removeBackupItemDiv) {
107 continue;
108 }
109
110 popupView.removeBackupItemDiv(deletedBackupName);
111 popupView.updateStorageInfo();
112 }
113 }
114 }
115 //
116
117 if (i >= numItemsToDelete) {
118 return;
119 }
120
121 deleteBackup (backupsList[i], loopFunc);
122 i++;
123 };
124
125 loopFunc ();
126 }
127
128 //for (var i = 0; i < numItemsToDelete; i++) {
129 // TODO WARNING: I'm calling deleteBackup rapidly, while deleting is async...(I should wait for each delete to complete before deleting the next)
130 //deleteBackup (backupsList[i], function() {
131
132 //});
133 //}
134
135 });
136 }
137
138 //var isCreatingBackup = false;
139
140 function backupNow(isAutomatic, backupName, callbackDone) {
141 console.log("backupNow - isAutomatic: " + isAutomatic + " name: " + backupName);
142 /*if (isCreatingBackup === true) {
143 console.log("backupNow - already running..skipping..");
144 return;
145 }*/
146
147 //isCreatingBackup = true;
148
149 /*if (!confirm("Perform a full backup? All windows and their tabs will be saved!")) {
150 return;
151 }*/
152
153 var fullBackup = {
154 windows: [],
155 isAutomatic: isAutomatic,
156 totNumTabs: 0
157 };
158
159 chrome.windows.getAll({populate : true}, function (window_list) {
160 var totNumTabs = 0;
161
162 for(var i=0;i<window_list.length;i++) {
163 var window = window_list[i];
164
165 //console.log ("Window " + i);
166
167 var bkpWindow = {
168 state: window.state,
169 top: window.top,
170 left: window.left,
171 width: window.width,
172 height: window.height,
173 tabs: []
174 };
175
176 var windowTabs = window.tabs;
177
178 // If it's a single window sittig at the new tab page, don't bother
179 // saving it. This is a nice shortcut when things crash as it will
180 // only show a single window.
181 if (windowTabs.length == 1) {
182 const tab = windowTabs[0];
183 if (tab.title == 'New Tab' && tab.url == 'chrome://newtab/')
184 continue;
185 }
186
187 for (var j = 0; j < windowTabs.length; j++) {
188 var tab = windowTabs[j];
189
190 //console.log("==> Tab " + j + " (" + tab.index + "): " + tabUrl);
191
192 var bkpTab = {
193 url: tab.url,
194 title: tab.title,
195 highlighted: tab.highlighted,
196 pinned: tab.pinned,
197 };
198
199 // Add tab to tabs arrays
200 bkpWindow.tabs.push(bkpTab);
201 }
202
203 totNumTabs += windowTabs.length;
204
205 fullBackup.windows.push(bkpWindow);
206 }
207
208 if (totNumTabs == 0)
209 return;
210
211 fullBackup.totNumTabs = totNumTabs;
212
213 var storageSetValues = {};
214 storageSetValues[backupName] = fullBackup;
215
216 // Store backup
217 chrome.storage.local.set(storageSetValues, function () {
218 if (chrome.runtime.lastError) {
219 //isCreatingBackup = false;
220 // TODO change icon to error..
221 //alert ("Error: " + chrome.runtime.lastError.message);
222 updateBrowserActionIcon (1);
223
224 callbackDone(false);
225 } else {
226 console.log("backup saved");
227 //alert("Backup saved successfully!");
228
229 chrome.storage.local.get("backups_list", function(items) {
230 var backupsList = [];
231 if(items.backups_list) {
232 backupsList = items.backups_list;
233 }
234
235 console.log("Updating 'backups_list' - cur. size: " + backupsList.length);
236
237 backupsList.push(backupName);
238
239 chrome.storage.local.set({"backups_list": backupsList}, function () {
240 //isCreatingBackup = false;
241
242 if (chrome.runtime.lastError) {
243 console.log ("Error saving backups_list: " + chrome.runtime.lastError.message);
244 updateBrowserActionIcon (1);
245 callbackDone(false);
246 } else {
247 console.log("Backups list saved successfully");
248
249 updateBrowserActionIcon (0);
250 callbackDone(true, backupName, fullBackup);
251
252 if (backupsList.length > parseInt(localStorage.prefsMaxBackupItems)) {
253 deleteOldestBackup();
254 }
255 }
256 });
257 });
258 }
259 });
260 });
261 }
262
263 /**
264 * 0 ==> OK
265 * 1 ==> ERROR
266 */
267 function updateBrowserActionIcon (status) {
268 var icon;
269 switch(status) {
270 case 0:
271 icon = "icon_ok.png";
272 break;
273 default:
274 icon = "icon_error.png";
275 break;
276 }
277
278 chrome.browserAction.setIcon({path: icon});
279 }
280
281 function deleteBackup (backupName, callback) {
282 console.log("Deleting backup " + backupName);
283
284 chrome.storage.local.remove(backupName, function() {
285 //console.log ("=> Deleted backup " + backupName);
286
287 chrome.storage.local.get("backups_list", function(items) {
288 //console.log ("==> got backups_list " + backupName);
289
290 if(!items.backups_list) {
291 callback();
292 return;
293 }
294
295 var backupsList = items.backups_list;
296
297 var index = backupsList.indexOf(backupName);
298 if (index >= 0) {
299 backupsList.splice(index, 1);
300 }
301
302 //console.log ("===> Updating backups_list (removing " + backupName + ")");
303
304 chrome.storage.local.set({"backups_list": backupsList}, function() {
305 //console.log ("===> Updated backups_list (removed " + backupName + ")");
306
307 callback();
308 });
309
310 //console.log ("==> EXIT got backups_list " + backupName);
311 });
312
313 //console.log ("=> EXIT Deleted backup " + backupName);
314 });
315
316 //console.log("EXIT Deleting backup " + backupName);
317
318
319 }
320
321 function restoreNow(backupName) {
322 console.log("restoreNow");
323
324 chrome.storage.local.get(backupName, function(items) {
325 if(!items[backupName]) {
326 alert("No Backup found");
327 return;
328 }
329
330 /*if (!confirm("Restore full backup?")) {
331 return;
332 }*/
333 /*
334 if (confirm("Would you like to close all existing windows first?")) {
335 chrome.windows.getAll({populate : false}, function (window_list) {
336 for(var i=0;i<window_list.length;i++) {
337 var window = window_list[i];
338 chrome.windows.remove(window.id);
339 }
340 });
341 }*/
342
343
344 var fullBackup = items[backupName];
345
346 for(var i=0;i<fullBackup.windows.length;i++) {
347 const window = fullBackup.windows[i];
348
349 //console.log ("Window " + i);
350
351 urlsToOpen = [];
352
353 const windowTabs = window.tabs;
354 for (let j = 0; j < windowTabs.length; j++) {
355 const tab = windowTabs[j];
356 const tabUrl = tab.url;
357 urlsToOpen.push(tabUrl);
358 }
359
360 const windowProperties = {
361 state: 'normal',
362 url: urlsToOpen,
363 top: window.top,
364 left: window.left,
365 width: window.width,
366 height: window.height,
367 };
368
369 // Create a new Window
370 chrome.windows.create(windowProperties, function(createdWindow) {
371 // Chrome errors if the dimensions are set on non-normal windows.
372 // So we create the window first with the right settings, then
373 // update the window state.
374 if (window.state != 'normal') {
375 chrome.windows.update(createdWindow.id, {state: window.state});
376 }
377
378 chrome.windows.get(createdWindow.id, {populate: true}, ({tabs}) => {
379 for (let tabi = 0; tabi < windowTabs.length; ++tabi) {
380 const oldtab = windowTabs[tabi];
381 const newtab = tabs[tabi];
382 chrome.tabs.update(newtab.id, {
383 highlighted: oldtab.highlighted,
384 pinned: oldtab.pinned,
385 }, () => {
386 if (!oldtab.highlighted) {
387 // If we discard a tab too fast, Chrome will completely
388 // throw it away. Wait until it's in a stable enough
389 // state for us to discard it.
390 let retryCount = 60;
391 const checktab = (id) => {
392 if (retryCount-- < 0)
393 return;
394 chrome.tabs.get(id, (tab) => {
395 if (tab.pendingUrl)
396 setTimeout(() => checktab(id), 500);
397 else
398 chrome.tabs.discard(id);
399 });
400 };
401 checktab(newtab.id);
402 }
403 });
404 }
405 });
406 });
407 }
408 });
409 }