diff --git a/browser/base/content/tabcandy/app/browserwatcher.js b/browser/base/content/tabcandy/app/browserwatcher.js
new file mode 100644
index 000000000000..d4c48f308edb
--- /dev/null
+++ b/browser/base/content/tabcandy/app/browserwatcher.js
@@ -0,0 +1,117 @@
+// Title: browserwatcher.js
+(function(){
+
+Utils.log('warning! browserwatcher.js has not been tested since the code was taken from tabs.js!');
+
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+const Cu = Components.utils;
+const Cr = Components.results;
+
+// ##########
+// Class: WindowWatcher
+function WindowWatcher() {
+ var self = this;
+
+ var observer = {
+ observe: function(window, event) {
+ if (event == "domwindowopened") {
+ if (self.onWindowOpened)
+ self.onWindowOpened(window);
+ } else
+ if (self.onWindowClosed)
+ self.onWindowClosed(window);
+ }
+ };
+
+ var ww = Cc["@mozilla.org/embedcomp/window-watcher;1"]
+ .getService(Ci.nsIWindowWatcher);
+ ww.registerNotification(observer);
+
+ Extension.addUnloadMethod(
+ this,
+ function() {
+ ww.unregisterNotification(observer);
+ });
+}
+
+// ##########
+// Class: BrowserWatcher
+// When this object is instantiated, the given onLoad() is called for
+// all browser windows, and subsequently for all newly-opened browser
+// windows. When a browser window closes, onUnload() is called.
+// onUnload() is also called once for each browser window when the
+// extension is unloaded.
+function BrowserWatcher(options) {
+ var pendingHandlers = [];
+
+ function makeSafeFunc(func) {
+ function safeFunc(window) {
+ try {
+ func(window);
+ } catch (e) {
+ Utils.log(e);
+ }
+ };
+ return safeFunc;
+ }
+
+ function addUnloader(chromeWindow, func) {
+ function onUnload() {
+ chromeWindow.removeEventListener("unload", onUnload, false);
+ pendingHandlers.splice(pendingHandlers.indexOf(onUnload), 1);
+ func(chromeWindow);
+ }
+ pendingHandlers.push(onUnload);
+ chromeWindow.addEventListener("unload", onUnload, false);
+ }
+
+ function loadAndBind(chromeWindow) {
+ if (options.onLoad)
+ (makeSafeFunc(options.onLoad))(chromeWindow);
+ if (options.onUnload)
+ addUnloader(chromeWindow, makeSafeFunc(options.onUnload));
+ }
+
+ var wm = Cc["@mozilla.org/appshell/window-mediator;1"]
+ .getService(Ci.nsIWindowMediator);
+
+ var enumerator = wm.getEnumerator(XULApp.appWindowType);
+
+ while (enumerator.hasMoreElements()) {
+ var chromeWindow = enumerator.getNext();
+ if (chromeWindow.gIsDoneLoading)
+ loadAndBind(chromeWindow);
+ else
+ onWindowOpened(chromeWindow);
+ }
+
+ function onWindowOpened(chromeWindow) {
+ function removeListener() {
+ chromeWindow.removeEventListener("load", onLoad, false);
+ pendingHandlers.splice(pendingHandlers.indexOf(removeListener), 1);
+ }
+ function onLoad() {
+ removeListener();
+ var type = chromeWindow.document.documentElement
+ .getAttribute("windowtype");
+ if (type == XULApp.appWindowType)
+ loadAndBind(chromeWindow);
+ }
+ chromeWindow.addEventListener("load", onLoad, false);
+ pendingHandlers.push(removeListener);
+ }
+
+ var ww = new WindowWatcher();
+ ww.onWindowOpened = onWindowOpened;
+
+ Extension.addUnloadMethod(
+ this,
+ function() {
+ ww.unload();
+ var handlers = pendingHandlers.slice();
+ handlers.forEach(function(handler) { handler(); });
+ });
+}
+
+})();
\ No newline at end of file
diff --git a/browser/base/content/tabcandy/app/groups.js b/browser/base/content/tabcandy/app/groups.js
index 51852a47ca6a..7f621bdb2d15 100644
--- a/browser/base/content/tabcandy/app/groups.js
+++ b/browser/base/content/tabcandy/app/groups.js
@@ -162,6 +162,8 @@ window.Group = function(listOfEls, options) {
});
} else
self.adjustTitleSize();
+
+ self.save();
}
this.$title
@@ -276,9 +278,10 @@ window.Group.prototype = $.extend(new Item(), new Subscribable(), {
save: function() {
if (!this._inited) // too soon to save now
return;
+
var data = this.getStorageData();
-/* Utils.log("data to save: " + data.toSource()); */
- Storage.saveGroup(Utils.getCurrentWindow(), data);
+ if(Groups.groupStorageSanity(data))
+ Storage.saveGroup(Utils.getCurrentWindow(), data);
},
// ----------
@@ -300,7 +303,6 @@ window.Group.prototype = $.extend(new Item(), new Subscribable(), {
var css = {width: w};
this.$title.css(css);
this.$titleShield.css(css);
- this.save();
},
// ----------
@@ -554,15 +556,13 @@ window.Group.prototype = $.extend(new Item(), new Subscribable(), {
self.remove($el);
});
- item.parent = this;
+ item.setParent(this);
if(typeof(item.setResizable) == 'function')
item.setResizable(false);
if(item.tab == Utils.activeTab)
Groups.setActiveGroup(this);
-
- item.save();
}
if(!options.dontArrange)
@@ -601,7 +601,7 @@ window.Group.prototype = $.extend(new Item(), new Subscribable(), {
if(index != -1)
this._children.splice(index, 1);
- item.parent = null;
+ item.setParent(null);
item.removeClass("tabInGroup");
item.removeClass("stacked");
item.removeClass("stack-trayed");
@@ -627,7 +627,6 @@ window.Group.prototype = $.extend(new Item(), new Subscribable(), {
var toRemove = $.merge([], this._children);
$.each(toRemove, function(index, child) {
self.remove(child, {dontArrange: true});
- child.save();
});
},
@@ -861,8 +860,6 @@ window.Group.prototype = $.extend(new Item(), new Subscribable(), {
this.arrange({z: z + 2});
}
-
- this.save();
},
// ----------
@@ -931,8 +928,6 @@ window.Group.prototype = $.extend(new Item(), new Subscribable(), {
this.$resizer.fadeOut();
$(this.container).resizable('disable');
}
-
- this.save();
},
// ----------
@@ -994,8 +989,6 @@ window.Group.prototype = $.extend(new Item(), new Subscribable(), {
// actions is necessary for a good user experience.
self.onNextNewTab(doNextTab);
-
- this.save();
},
// ----------
@@ -1283,13 +1276,14 @@ window.Groups = {
init: function() {
this.groups = [];
this.nextID = 1;
+ this._inited = false;
},
// ----------
getNextID: function() {
var result = this.nextID;
this.nextID++;
- Storage.saveGroupsData(Utils.getCurrentWindow(), {nextID:this.nextID});
+ this.save();
return result;
},
@@ -1303,73 +1297,77 @@ window.Groups = {
return data;
},
+ // ----------
+ saveAll: function() {
+ this.save();
+ $.each(this.groups, function(index, group) {
+ group.save();
+ });
+ },
+
+ // ----------
+ save: function() {
+ if (!this._inited) // too soon to save now
+ return;
+
+ Storage.saveGroupsData(Utils.getCurrentWindow(), {nextID:this.nextID});
+ },
+
// ----------
reconstitute: function(groupsData, groupData) {
try {
-/* Utils.log("in reconst"); */
- if(groupsData && groupsData.nextID)
- this.nextID = groupsData.nextID;
- else {
- // Decrement and increment. Increment will trigger a save, and that is
- // actually what we want here.
- --this.nextID;
- this.getNextID();
- }
+ if(groupsData && groupsData.nextID)
+ this.nextID = groupsData.nextID;
+
+ if(groupData) {
+ for (var id in groupData) {
+ var group = groupData[id];
+ if(this.groupStorageSanity(group)) {
+ var isNewTabsGroup = (group.title == 'New Tabs');
+ var options = {
+ locked: {
+ close: isNewTabsGroup,
+ title: isNewTabsGroup
+ },
+ dontPush: true
+ };
+
+ new Group([], $.extend({}, group, options));
+ }
+ }
+ }
- if(groupData) {
- for (var id in groupData) {
-/*
- Utils.log("id: " + id);
- Utils.log("groupData[id]: "+ groupData[id].toSource());
-*/
- var group = groupData[id];
-/* Utils.log("src: " +group.toSource()); */
- var isNewTabsGroup = (group.title == 'New Tabs');
+ var group = this.getNewTabGroup();
+ if(!group) {
+ var box = this.getBoundsForNewTabGroup();
var options = {
locked: {
- close: isNewTabsGroup,
- title: isNewTabsGroup
+ close: true,
+ title: true
},
- dontPush: true
+ dontPush: true,
+ bounds: box,
+ title: 'New Tabs'
};
-
- new Group([], $.extend({}, group, options));
- }
- }
-
- var group = this.getNewTabGroup();
- if(!group) {
- var box = this.getBoundsForNewTabGroup();
- var options = {
- locked: {
- close: true,
- title: true
- },
- dontPush: true,
- bounds: box,
- title: 'New Tabs'
- };
-
- new Group([], options);
- }
+
+ new Group([], options);
+ }
+
+ this._inited = true;
+ this.save(); // for nextID
}catch(e){
Utils.log("error in recons: "+e);
}
},
// ----------
- storageSanity: function(data) {
+ groupStorageSanity: function(groupData) {
// TODO: check everything
- if(!data.groups)
- return false;
-
var sane = true;
- $.each(data.groups, function(index, group) {
- if(!isRect(group.bounds)) {
- Utils.log('Groups.storageSanity: bad bounds', group.bounds);
- sane = false;
- }
- });
+ if(!isRect(groupData.bounds)) {
+ Utils.log('Groups.groupStorageSanity: bad bounds', groupData.bounds);
+ sane = false;
+ }
return sane;
},
diff --git a/browser/base/content/tabcandy/app/items.js b/browser/base/content/tabcandy/app/items.js
index e351d61a7a4e..a371abf98209 100644
--- a/browser/base/content/tabcandy/app/items.js
+++ b/browser/base/content/tabcandy/app/items.js
@@ -11,6 +11,7 @@
// close - function()
// addOnClose - function(referenceObject, callback)
// removeOnClose - function(referenceObject)
+// save - function()
//
// ... and this property:
// defaultSize - a Point
@@ -73,6 +74,7 @@ window.Item.prototype = {
Utils.assert('Subclass must provide close', typeof(this.close) == 'function');
Utils.assert('Subclass must provide addOnClose', typeof(this.addOnClose) == 'function');
Utils.assert('Subclass must provide removeOnClose', typeof(this.removeOnClose) == 'function');
+ Utils.assert('Subclass must provide save', typeof(this.save) == 'function');
Utils.assert('Subclass must provide defaultSize', isPoint(this.defaultSize));
Utils.assert('Subclass must provide locked', this.locked);
@@ -136,6 +138,7 @@ window.Item.prototype = {
setUserSize: function() {
Utils.assert('this.bounds', isRect(this.bounds));
this.userSize = new Point(this.bounds.width, this.bounds.height);
+ this.save();
},
// ----------
@@ -153,6 +156,14 @@ window.Item.prototype = {
$(this.container).css({"-moz-transform": value});
},
+ // ----------
+ // Function: setParent
+ //
+ setParent: function(parent) {
+ this.parent = parent;
+ this.save();
+ },
+
// ----------
// Function: pushAway
// Pushes all other items away so none overlap this Item.
diff --git a/browser/base/content/tabcandy/app/storage.js b/browser/base/content/tabcandy/app/storage.js
index 2b0126a30db1..a0df983ecc9a 100644
--- a/browser/base/content/tabcandy/app/storage.js
+++ b/browser/base/content/tabcandy/app/storage.js
@@ -5,6 +5,7 @@ Storage = {
GROUP_DATA_IDENTIFIER: "tabcandy-group",
GROUPS_DATA_IDENTIFIER: "tabcandy-groups",
TAB_DATA_IDENTIFIER: "tabcandy-tab",
+ UI_DATA_IDENTIFIER: "tabcandy-ui",
// ----------
init: function() {
@@ -12,9 +13,31 @@ Storage = {
.getService(Components.interfaces.nsISessionStore);
},
+ // ----------
+ wipe: function() {
+ try {
+ var win = Utils.getCurrentWindow();
+ var self = this;
+
+ // ___ Tabs
+ Tabs.forEach(function(tab) {
+ self.saveTab(tab.raw, null);
+ });
+
+ // ___ Other
+ this.saveGroupsData(win, {});
+ this.saveUIData(win, {});
+
+ this._sessionStore.setWindowValue(win, this.GROUP_DATA_IDENTIFIER,
+ JSON.stringify({}));
+ } catch (e) {
+ Utils.log("Error in wipe: "+e);
+ }
+ },
+
// ----------
saveTab: function(tab, data) {
-/* Utils.log("AAAAAAAAAAAAAAAAAAAAAAAAAAA saving tab data, tab: " + tab.toSource() + ", data: "+data.toSource()); */
+/* Utils.log("AAAAAAAAAAAAAAAAAAAAAAAAAAA saving tab data"); */
this._sessionStore.setTabValue(tab, this.TAB_DATA_IDENTIFIER,
JSON.stringify(data));
},
@@ -32,6 +55,8 @@ Storage = {
// getWindowValue will fail if the property doesn't exist
Utils.log("Error in readTabData: "+e);
}
+
+/* Utils.log('tab', existingData); */
return existingData;
},
@@ -69,71 +94,48 @@ Storage = {
// ----------
saveGroupsData: function(win, data) {
-/* Utils.log("GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG " + data.toSource()); */
- this._sessionStore.setWindowValue(win, this.GROUPS_DATA_IDENTIFIER,
- JSON.stringify(data));
+ this.saveData(win, this.GROUPS_DATA_IDENTIFIER, data);
},
// ----------
readGroupsData: function(win) {
+ return this.readData(win, this.GROUPS_DATA_IDENTIFIER);
+ },
+
+ // ----------
+ saveUIData: function(win, data) {
+ this.saveData(win, this.UI_DATA_IDENTIFIER, data);
+ },
+
+ // ----------
+ readUIData: function(win) {
+ return this.readData(win, this.UI_DATA_IDENTIFIER);
+ },
+
+ // ----------
+ saveData: function(win, id, data) {
+ try {
+ this._sessionStore.setWindowValue(win, id, JSON.stringify(data));
+ } catch (e) {
+ Utils.log("Error in saveData: "+e);
+ }
+
+/* Utils.log('save data', id, data); */
+ },
+
+ // ----------
+ readData: function(win, id) {
var existingData = {};
try {
-/* Utils.log("readGroupsData: "+this._sessionStore.getWindowValue(win, this.GROUPS_DATA_IDENTIFIER)); */
- existingData = JSON.parse(
- this._sessionStore.getWindowValue(win, this.GROUPS_DATA_IDENTIFIER)
- );
+ var data = this._sessionStore.getWindowValue(win, id);
+ if(data)
+ existingData = JSON.parse(data);
} catch (e) {
- // getWindowValue will fail if the property doesn't exist
+ Utils.log("Error in readData: "+e);
}
+
+/* Utils.log('read data', id, existingData); */
return existingData;
- },
-
- // ----------
- read: function() {
- var data = {};
- var file = this.getFile();
- if(file.exists()) {
- var fstream = Components.classes["@mozilla.org/network/file-input-stream;1"].
- createInstance(Components.interfaces.nsIFileInputStream);
- var cstream = Components.classes["@mozilla.org/intl/converter-input-stream;1"].
- createInstance(Components.interfaces.nsIConverterInputStream);
- fstream.init(file, -1, 0, 0);
- cstream.init(fstream, "UTF-8", 0, 0); // you can use another encoding here if you wish
-
- let (str = {}) {
- cstream.readString(-1, str); // read the whole file and put it in str.value
- if(str.value)
- data = JSON.parse(str.value);
- }
- cstream.close(); // this closes fstream
- }
-
- return data;
- },
-
- // ----------
- write: function(data) {
- var file = this.getFile();
- var foStream = Components.classes["@mozilla.org/network/file-output-stream;1"].
- createInstance(Components.interfaces.nsIFileOutputStream);
- foStream.init(file, 0x02 | 0x08 | 0x20, 0666, 0);
- var str = JSON.stringify(data);
- foStream.write(str, str.length);
- foStream.close();
- },
-
- // ----------
- getFile: function() {
- var file = Components.classes["@mozilla.org/file/directory_service;1"].
- getService(Components.interfaces.nsIProperties).
- get("ProfD", Components.interfaces.nsIFile);
-
- file.append('tabcandy');
- if(!file.exists())
- file.create(Components.interfaces.nsIFile.DIRECTORY_TYPE, 0777);
-
- file.append(Switch.name + '.json');
- return file;
}
};
diff --git a/browser/base/content/tabcandy/app/tabitems.js b/browser/base/content/tabcandy/app/tabitems.js
index f5097c6896c1..623b7a72912c 100644
--- a/browser/base/content/tabcandy/app/tabitems.js
+++ b/browser/base/content/tabcandy/app/tabitems.js
@@ -13,6 +13,7 @@ window.TabItem = function(container, tab) {
this._init(container);
+ this.reconnected = false;
this._hasBeenDrawn = false;
this.tab = tab;
this.setResizable(true);
@@ -21,7 +22,14 @@ window.TabItem = function(container, tab) {
var self = this;
this.tab.mirror.addOnClose(this, function(who, info) {
TabItems.unregister(self);
- });
+ });
+
+ this.tab.mirror.addSubscriber(this, 'urlChanged', function(who, info) {
+ if(!self.reconnected && (info.oldURL == 'about:blank' || !info.oldURL))
+ TabItems.reconnect(self);
+
+ self.save();
+ });
};
window.TabItem.prototype = $.extend(new Item(), {
@@ -37,13 +45,13 @@ window.TabItem.prototype = $.extend(new Item(), {
// ----------
save: function() {
-/* Utils.log((this.tab ? this.tab.url : ''), this.reconnected); */
try{
if (!("tab" in this) || !("raw" in this.tab) || !this.reconnected) // too soon to save
return;
+
var data = this.getStorageData();
-/* Utils.log("data to save", data); */
- Storage.saveTab(this.tab.raw, data);
+ if(TabItems.storageSanity(data))
+ Storage.saveTab(this.tab.raw, data);
}catch(e){
Utils.log("Error in saving tab value: "+e);
}
@@ -320,20 +328,19 @@ window.TabItems = {
if(TabItems.reconnect(item))
reconnected = true;
- else if(!tab.url || tab.url == 'about:blank') {
- tab.mirror.addSubscriber(item, 'urlChanged', function(who, info) {
- Utils.assert('changing away from blank', info.oldURL == 'about:blank' || !info.oldURL);
- TabItems.reconnect(item);
- who.removeSubscriber(item);
- });
- }
+ else
+ Groups.newTab(item);
}
});
/* Utils.log("reconnected: "+reconnected); */
+/*
+ Utils.log(reconnected, $div.length, !!Groups);
if(!reconnected && $div.length == 1 && Groups){
+ Utils.log('new tab');
Groups.newTab($div.data('tabItem'));
}
+*/
// TODO: Figure out this really weird bug?
@@ -448,6 +455,14 @@ window.TabItems = {
return $(tab).data("tabItem");
},
+ // ----------
+ saveAll: function() {
+ var items = this.getItems();
+ $.each(items, function(index, item) {
+ item.save();
+ });
+ },
+
// ----------
reconstitute: function() {
var items = this.getItems();
@@ -461,34 +476,26 @@ window.TabItems = {
// ----------
storageSanity: function(data) {
// TODO: check everything
- if(!data.tabs)
- return false;
-
var sane = true;
- $.each(data.tabs, function(index, tab) {
- if(!isRect(tab.bounds)) {
- Utils.log('TabItems.storageSanity: bad bounds', tab.bounds);
- sane = false;
- }
- });
+ if(!isRect(data.bounds)) {
+ Utils.log('TabItems.storageSanity: bad bounds', data.bounds);
+ sane = false;
+ }
return sane;
},
// ----------
reconnect: function(item) {
+ var found = false;
+
try{
-/* Utils.log("trying to reconnect"); */
if(item.reconnected) {
-/* Utils.log("already done"); */
return true;
}
- var found = false;
-
var tab = Storage.getTabData(item.tab.raw);
-/* Utils.log("this is our tab", tab, item.tab.url); */
- if (tab) {
+ if (tab && this.storageSanity(tab)) {
if(item.parent)
item.parent.remove(item);
@@ -499,11 +506,12 @@ window.TabItems = {
if(tab.groupID) {
var group = Groups.group(tab.groupID);
-/* Utils.log("group found: " + group); */
- group.add(item);
+ if(group) {
+ group.add(item);
- if(item.tab == Utils.activeTab)
- Groups.setActiveGroup(item.parent);
+ if(item.tab == Utils.activeTab)
+ Groups.setActiveGroup(item.parent);
+ }
}
Groups.updateTabBarForActiveGroup();
diff --git a/browser/base/content/tabcandy/app/ui.js b/browser/base/content/tabcandy/app/ui.js
index 2bffeb4fb80d..8d5da136e5e9 100644
--- a/browser/base/content/tabcandy/app/ui.js
+++ b/browser/base/content/tabcandy/app/ui.js
@@ -8,7 +8,7 @@ window.Keys = {meta: false};
Navbar = {
// ----------
get el(){
- var win = Utils.activeWindow;
+ var win = Utils.getCurrentWindow();
if(win) {
var navbar = win.gBrowser.ownerDocument.getElementById("navigator-toolbox");
return navbar;
@@ -18,7 +18,7 @@ Navbar = {
},
get urlBar(){
- var win = Utils.activeWindow;
+ var win = Utils.getCurrentWindow();
if(win) {
var navbar = win.gBrowser.ownerDocument.getElementById("urlbar");
return navbar;
@@ -535,7 +535,7 @@ UIClass.prototype = {
var me = this;
setTimeout(function() { // Marshal event from chrome thread to DOM thread
try{
- if(me.contentWindow.location.host == "tabcandy") {
+ if(me.contentWindow == window) {
self.focused = true;
Page.hideChrome();
} else {
@@ -554,47 +554,30 @@ UIClass.prototype = {
}, 1);
});
- // ___ Page
- Page.init();
-
- // ___ Storage
- var data = Storage.read();
- var sane = this.storageSanity(data);
- if(!sane || data.dataVersion < 2) {
- data.groups = null;
- data.tabs = null;
- data.pageBounds = null;
-
- if(!sane)
- alert('storage data is bad; starting fresh');
- }
-
- var groupsData = Storage.readGroupsData(Utils.activeWindow);
- var groupData = Storage.readGroupData(Utils.activeWindow);
-
-/*
- Utils.log("in UI init");
- Utils.log(data.toSource());
- Utils.log(groupsData.toSource());
- Utils.log(groupData.toSource());
-*/
- Groups.reconstitute(groupsData, groupData);
- TabItems.init();
- TabItems.reconstitute();
-
$(window).bind('beforeunload', function() {
- if(self.initialized)
- self.save();
-
self.showChrome();
self.tabBar.showAllTabs();
});
+ // ___ Page
+ Page.init();
+
+ // ___ Storage
+ var currentWindow = Utils.getCurrentWindow();
+ var data = Storage.readUIData(currentWindow);
+ this.storageSanity(data);
+
+ var groupsData = Storage.readGroupsData(currentWindow);
+ var groupData = Storage.readGroupData(currentWindow);
+ Groups.reconstitute(groupsData, groupData);
+
+ TabItems.init();
+ TabItems.reconstitute();
+
// ___ resizing
- data.pageBounds = null;
if(data.pageBounds) {
this.pageBounds = data.pageBounds;
- this.resize();
+ this.resize(true);
} else
this.pageBounds = Items.getPageBounds();
@@ -607,6 +590,7 @@ UIClass.prototype = {
// ___ Done
this.initialized = true;
+ this.save(); // for this.pageBounds
}catch(e) {
Utils.log("Error in UIClass(): " + e);
Utils.log(e.fileName);
@@ -692,6 +676,7 @@ UIClass.prototype = {
});
this.pageBounds = Items.getPageBounds();
+ this.save();
},
// ----------
@@ -716,10 +701,21 @@ UIClass.prototype = {
code: function() {
location.href = '../../index.html';
}
+ }, {
+ name: 'code docs',
+ code: function() {
+ location.href = '../../doc/index.html';
+ }
}, {
name: 'save',
code: function() {
- self.save();
+ self.saveAll();
+ }
+ }, {
+ name: 'reset',
+ code: function() {
+ Storage.wipe();
+ location.href = '';
}
}];
@@ -736,21 +732,24 @@ UIClass.prototype = {
}
},
+ // ----------
+ saveAll: function() {
+ this.save();
+ Groups.saveAll();
+ TabItems.saveAll();
+ },
+
// ----------
save: function() {
- return;
+ if(!this.initialized)
+ return;
+
var data = {
- dataVersion: 2,
- groups: Groups.getStorageData(),
- tabs: TabItems.getStorageData(),
- pageBounds: Items.getPageBounds()
+ pageBounds: this.pageBounds
};
-/* Utils.error(this.pageBounds, data.pageBounds); */
if(this.storageSanity(data))
- Storage.write(data);
- else
- alert('storage data is bad; reverting to previous version');
+ Storage.saveUIData(Utils.getCurrentWindow(), data);
},
// ----------
@@ -758,17 +757,13 @@ UIClass.prototype = {
if($.isEmptyObject(data))
return true;
- var sane = true;
- sane = sane && typeof(data.dataVersion) == 'number';
- sane = sane && isRect(data.pageBounds);
-
- if(data.tabs)
- sane = sane && TabItems.storageSanity(data.tabs);
+ if(!isRect(data.pageBounds)) {
+ Utils.log('UI.storageSanity: bad pageBounds', data.pageBounds);
+ data.pageBounds = null;
+ return false;
+ }
- if(data.groups)
- sane = sane && Groups.storageSanity(data.groups);
-
- return sane;
+ return true;
},
// ----------
diff --git a/browser/base/content/tabcandy/core/tabs.js b/browser/base/content/tabcandy/core/tabs.js
index 7ed194ab38a2..fba76b30ebd8 100644
--- a/browser/base/content/tabcandy/core/tabs.js
+++ b/browser/base/content/tabcandy/core/tabs.js
@@ -1,13 +1,14 @@
// Title: tabs.js
(function(){
-
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
const Cr = Components.results;
-
+// ##########
+// Class: XULApp
+// Singelton
var XULApp = {
appWindowType: "navigator:browser",
tabStripForWindow: function(aWindow) {
@@ -30,7 +31,8 @@ var XULApp = {
}
};
-
+// ##########
+// Class: Dictionary
function Dictionary() {
var keys = [];
var values = [];
@@ -69,6 +71,8 @@ function Dictionary() {
this.__defineGetter__("length", function() { return keys.length; });
}
+// ##########
+// Class: ImmutableArray
function ImmutableArray(baseArray) {
var self = this;
var UNSUPPORTED_MUTATOR_METHODS = ["pop", "push", "reverse", "shift",
@@ -86,117 +90,9 @@ function ImmutableArray(baseArray) {
self.__proto__ = baseArray;
}
-function WindowWatcher() {
- var self = this;
-
- var observer = {
- observe: function(window, event) {
- if (event == "domwindowopened") {
- if (self.onWindowOpened)
- self.onWindowOpened(window);
- } else
- if (self.onWindowClosed)
- self.onWindowClosed(window);
- }
- };
-
- var ww = Cc["@mozilla.org/embedcomp/window-watcher;1"]
- .getService(Ci.nsIWindowWatcher);
- ww.registerNotification(observer);
-
- Extension.addUnloadMethod(
- this,
- function() {
- ww.unregisterNotification(observer);
- });
-}
-
-// When this object is instantiated, the given onLoad() is called for
-// all browser windows, and subsequently for all newly-opened browser
-// windows. When a browser window closes, onUnload() is called.
-// onUnload() is also called once for each browser window when the
-// extension is unloaded.
-
-function BrowserWatcher(options) {
- var pendingHandlers = [];
-
- function makeSafeFunc(func) {
- function safeFunc(window) {
- try {
- func(window);
- } catch (e) {
- Utils.log(e);
- }
- };
- return safeFunc;
- }
-
- function addUnloader(chromeWindow, func) {
- function onUnload() {
- chromeWindow.removeEventListener("unload", onUnload, false);
- pendingHandlers.splice(pendingHandlers.indexOf(onUnload), 1);
- func(chromeWindow);
- }
- pendingHandlers.push(onUnload);
- chromeWindow.addEventListener("unload", onUnload, false);
- }
-
- function loadAndBind(chromeWindow) {
- if (options.onLoad)
- (makeSafeFunc(options.onLoad))(chromeWindow);
- if (options.onUnload)
- addUnloader(chromeWindow, makeSafeFunc(options.onUnload));
- }
-
- var wm = Cc["@mozilla.org/appshell/window-mediator;1"]
- .getService(Ci.nsIWindowMediator);
-
- var enumerator = wm.getEnumerator(XULApp.appWindowType);
-
- while (enumerator.hasMoreElements()) {
- var chromeWindow = enumerator.getNext();
- if (chromeWindow.gIsDoneLoading)
- loadAndBind(chromeWindow);
- else
- onWindowOpened(chromeWindow);
- }
-
- function onWindowOpened(chromeWindow) {
- function removeListener() {
- chromeWindow.removeEventListener("load", onLoad, false);
- pendingHandlers.splice(pendingHandlers.indexOf(removeListener), 1);
- }
- function onLoad() {
- removeListener();
- var type = chromeWindow.document.documentElement
- .getAttribute("windowtype");
- if (type == XULApp.appWindowType)
- loadAndBind(chromeWindow);
- }
- chromeWindow.addEventListener("load", onLoad, false);
- pendingHandlers.push(removeListener);
- }
-
- var ww = new WindowWatcher();
- ww.onWindowOpened = onWindowOpened;
-
- Extension.addUnloadMethod(
- this,
- function() {
- ww.unload();
- var handlers = pendingHandlers.slice();
- handlers.forEach(function(handler) { handler(); });
- });
-}
-
-
-
-
-
-
-
-
-
+// ##########
+// Class: Extension
+// Singleton
var Extension = {
// === {{{Extension.addUnloadMethod()}}} ===
//
@@ -220,14 +116,8 @@ var Extension = {
}
};
-
-
-
-
-
-
-
-
+// ##########
+// Class: EventListenerMixIns
function EventListenerMixIns(mixInto) {
var mixIns = {};
@@ -256,6 +146,8 @@ function EventListenerMixIns(mixInto) {
});
}
+// ##########
+// Class: EventListenerMixIn
function EventListenerMixIn(options) {
var listeners = [];
@@ -577,30 +469,13 @@ window.TabsManager = $.extend(new Subscribable(), {
}
};
}
-
-/*
- var browserWatcher = new BrowserWatcher(
- {onLoad: function(chromeWindow) {
- var trackedWindow = trackedWindows.get(chromeWindow);
- if (!trackedWindow)
- trackedWindows.set(chromeWindow,
- new BrowserWindow(chromeWindow));
- },
- onUnload: function(chromeWindow) {
- var browserWindow = trackedWindows.get(chromeWindow);
- trackedWindows.remove(chromeWindow);
- browserWindow.unload();
- }
- });
-*/
-
+
this.__defineGetter__("tabs", function() { return tabs; });
Extension.addUnloadMethod(
this,
function() {
tabsMixIns.unload();
-/* browserWatcher.unload(); */
});
window.Tabs = tabs;
diff --git a/content/candies/revision-a/index.html b/content/candies/revision-a/index.html
index e728c3fcdd6d..395d56622372 100644
--- a/content/candies/revision-a/index.html
+++ b/content/candies/revision-a/index.html
@@ -23,7 +23,7 @@