mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
f4b6400f47
+ Fixed a couple of "null tab" errors when calling storage.js + Fixed a couple of zooming issues related to closing tabs while you're in them
832 lines
21 KiB
JavaScript
832 lines
21 KiB
JavaScript
// Title: ui.js (revision-a)
|
|
|
|
(function(){
|
|
|
|
window.Keys = {meta: false};
|
|
|
|
// ##########
|
|
Navbar = {
|
|
// ----------
|
|
get el(){
|
|
var win = Utils.getCurrentWindow();
|
|
if(win) {
|
|
var navbar = win.gBrowser.ownerDocument.getElementById("navigator-toolbox");
|
|
return navbar;
|
|
}
|
|
|
|
return null;
|
|
},
|
|
|
|
get urlBar(){
|
|
var win = Utils.getCurrentWindow();
|
|
if(win) {
|
|
var navbar = win.gBrowser.ownerDocument.getElementById("urlbar");
|
|
return navbar;
|
|
}
|
|
|
|
return null;
|
|
},
|
|
|
|
// ----------
|
|
show: function() {
|
|
var el = this.el;
|
|
if(el)
|
|
el.collapsed = false;
|
|
else { // needs a little longer to get going
|
|
var self = this;
|
|
iQ.timeout(function() {
|
|
self.show();
|
|
}, 300);
|
|
}
|
|
},
|
|
|
|
// ----------
|
|
hide: function() {
|
|
var el = this.el;
|
|
if(el)
|
|
el.collapsed = true;
|
|
else { // needs a little longer to get going
|
|
var self = this;
|
|
iQ.timeout(function() {
|
|
self.hide();
|
|
}, 300);
|
|
}
|
|
},
|
|
}
|
|
|
|
// ##########
|
|
// Class: Tabbar
|
|
// Singleton for managing the tabbar of the browser.
|
|
var Tabbar = {
|
|
// ----------
|
|
// Variable: _hidden
|
|
// We keep track of whether the tabs are hidden in this (internal) variable
|
|
// so we still have access to that information during the window's unload event,
|
|
// when window.Tabs no longer exists.
|
|
_hidden: false,
|
|
|
|
// ----------
|
|
get el() {
|
|
return window.Tabs[0].raw.parentNode;
|
|
},
|
|
|
|
// ----------
|
|
get height() {
|
|
return window.Tabs[0].raw.parentNode.getBoundingClientRect().height;
|
|
},
|
|
|
|
// ----------
|
|
hide: function() {
|
|
var self = this;
|
|
self.el.collapsed = true;
|
|
},
|
|
|
|
// ----------
|
|
show: function() {
|
|
this.el.collapsed = false;
|
|
},
|
|
|
|
// ----------
|
|
// Function: getVisibleTabs
|
|
// Returns an array of the tabs which are currently visibible in the
|
|
// tab bar.
|
|
getVisibleTabs: function(){
|
|
var visibleTabs = [];
|
|
// this.el.children is not a real array and does contain
|
|
// useful functions like filter or forEach. Convert it into a real array.
|
|
for( var i=0; i<this.el.children.length; i++ ){
|
|
var tab = this.el.children[i];
|
|
if( tab.collapsed == false )
|
|
visibleTabs.push();
|
|
}
|
|
|
|
return visibleTabs;
|
|
},
|
|
|
|
// ----------
|
|
// Function: showOnlyTheseTabs
|
|
// Hides all of the tabs in the tab bar which are not passed into this function.
|
|
//
|
|
// Paramaters
|
|
// - An array of <Tab> objects.
|
|
showOnlyTheseTabs: function(tabs){
|
|
var visibleTabs = [];
|
|
// this.el.children is not a real array and does contain
|
|
// useful functions like filter or forEach. Convert it into a real array.
|
|
var tabBarTabs = [];
|
|
for( var i=0; i<this.el.children.length; i++ ){
|
|
tabBarTabs.push(this.el.children[i]);
|
|
}
|
|
|
|
for each( var tab in tabs ){
|
|
var rawTab = tab.tab.raw;
|
|
var toShow = tabBarTabs.filter(function(testTab){
|
|
return testTab == rawTab;
|
|
});
|
|
visibleTabs = visibleTabs.concat( toShow );
|
|
}
|
|
|
|
tabBarTabs.forEach(function(tab){
|
|
tab.collapsed = true;
|
|
});
|
|
|
|
// Show all of the tabs in the group and move them (in order)
|
|
// that they appear in the group to the end of the tab strip.
|
|
// This way the tab order is matched up to the group's thumbnail
|
|
// order.
|
|
var self = this;
|
|
visibleTabs.forEach(function(tab){
|
|
tab.collapsed = false;
|
|
Utils.getCurrentWindow().gBrowser.moveTabTo(tab, self.el.children.length-1);
|
|
});
|
|
},
|
|
|
|
// ----------
|
|
// Function: showAllTabs
|
|
// Shows all of the tabs in the tab bar.
|
|
showAllTabs: function(){
|
|
for( var i=0; i<this.el.children.length; i++ ){
|
|
var tab = this.el.children[i];
|
|
tab.collapsed = false;
|
|
}
|
|
},
|
|
|
|
// ----------
|
|
get isHidden(){ return this.el.collapsed; }
|
|
}
|
|
|
|
// ##########
|
|
// Class: Page
|
|
// Singleton top-level UI manager. TODO: Integrate with <UIClass>.
|
|
window.Page = {
|
|
startX: 30,
|
|
startY: 70,
|
|
|
|
show: function(){
|
|
Utils.homeTab.focus();
|
|
this.hideChrome();
|
|
},
|
|
|
|
isTabCandyFocused: function(){
|
|
return Utils.homeTab.contentDocument == UI.currentTab.contentDocument;
|
|
},
|
|
|
|
hideChrome: function(){
|
|
Tabbar.hide();
|
|
Navbar.hide();
|
|
window.statusbar.visible = false;
|
|
|
|
// Mac Only
|
|
Utils.getCurrentWindow().document.getElementById("main-window").setAttribute("activetitlebarcolor", "#C4C4C4");
|
|
},
|
|
|
|
showChrome: function(){
|
|
Tabbar.show();
|
|
Navbar.show();
|
|
window.statusbar.visible = true;
|
|
|
|
// Mac Only
|
|
Utils.getCurrentWindow().document.getElementById("main-window").removeAttribute("activetitlebarcolor");
|
|
},
|
|
|
|
setupKeyHandlers: function(){
|
|
var self = this;
|
|
iQ(window).keyup(function(e){
|
|
if( e.metaKey == false ) window.Keys.meta = false;
|
|
});
|
|
|
|
iQ(window).keydown(function(e){
|
|
if( e.metaKey == true ) window.Keys.meta = true;
|
|
|
|
if( !self.getActiveTab() ) return;
|
|
|
|
var centers = [[item.bounds.center(), item] for each(item in TabItems.getItems())];
|
|
myCenter = self.getActiveTab().bounds.center();
|
|
|
|
function getClosestTabBy(norm){
|
|
var matches = centers
|
|
.filter(function(item){return norm(item[0], myCenter)})
|
|
.sort(function(a,b){
|
|
return myCenter.distance(a[0]) - myCenter.distance(b[0]);
|
|
});
|
|
if( matches.length > 0 ) return matches[0][1];
|
|
else return null;
|
|
}
|
|
|
|
var norm = null;
|
|
switch(e.which){
|
|
case 39: // Right
|
|
norm = function(a, me){return a.x > me.x};
|
|
break;
|
|
case 37: // Left
|
|
norm = function(a, me){return a.x < me.x};
|
|
break;
|
|
case 40: // Down
|
|
norm = function(a, me){return a.y > me.y};
|
|
break;
|
|
case 38: // Up
|
|
norm = function(a, me){return a.y < me.y}
|
|
break;
|
|
case 49: // Command-1
|
|
case 69: // Command-E
|
|
if( Keys.meta ) if( self.getActiveTab() ) self.getActiveTab().zoomIn();
|
|
break;
|
|
}
|
|
|
|
if( norm != null && iQ(":focus").length == 0 ){
|
|
var nextTab = getClosestTabBy(norm);
|
|
if( nextTab ){
|
|
if( nextTab.inStack() && !nextTab.parent.expanded){
|
|
nextTab = nextTab.parent.getChild(0);
|
|
}
|
|
self.setActiveTab(nextTab);
|
|
}
|
|
e.preventDefault();
|
|
}
|
|
|
|
if((e.which == 27 || e.which == 13) && iQ(":focus").length == 0 )
|
|
if( self.getActiveTab() ) self.getActiveTab().zoomIn();
|
|
|
|
|
|
|
|
});
|
|
|
|
},
|
|
|
|
// ----------
|
|
init: function() {
|
|
var self = this;
|
|
/* Ian suspects we don't need these lines
|
|
Utils.homeTab.raw.maxWidth = 60;
|
|
Utils.homeTab.raw.minWidth = 60;
|
|
*/
|
|
|
|
// When you click on the background/empty part of TabCandy
|
|
// we create a new group.
|
|
iQ(Utils.homeTab.contentDocument).mousedown(function(e){
|
|
if( e.originalTarget.id == "bg" )
|
|
Page.createGroupOnDrag(e)
|
|
})
|
|
|
|
this.setupKeyHandlers();
|
|
|
|
Tabs.onClose(function(){
|
|
iQ.timeout(function() { // Marshal event from chrome thread to DOM thread
|
|
// Only go back to the TabCandy tab when there you close the last
|
|
// tab of a group.
|
|
var group = Groups.getActiveGroup();
|
|
if( group && group._children.length == 0 )
|
|
Page.show();
|
|
|
|
// Take care of the case where you've closed the last tab in
|
|
// an un-named group, which means that the group is gone (null) and
|
|
// there are no visible tabs.
|
|
if( group == null && Tabbar.getVisibleTabs().length == 0){
|
|
Page.show();
|
|
}
|
|
}, 1);
|
|
|
|
return false;
|
|
});
|
|
|
|
Tabs.onFocus(function() {
|
|
var focusTab = this;
|
|
var currentTab = UI.currentTab;
|
|
|
|
// If we switched to TabCandy window...
|
|
if( focusTab.contentWindow == window ){
|
|
UI.focused = true;
|
|
Page.hideChrome();
|
|
|
|
var item = null;
|
|
if(currentTab && currentTab.mirror)
|
|
item = TabItems.getItemByTabElement(currentTab.mirror.el);
|
|
|
|
if(item) {
|
|
// If there was a previous currentTab we want to animate
|
|
// its mirror for the zoom out.
|
|
// Note that we start the animation on the chrome thread.
|
|
|
|
// Zoom out!
|
|
item.zoomOut(function() {
|
|
if(!currentTab.mirror) // if the tab's been destroyed
|
|
item = null;
|
|
|
|
self.setActiveTab(item);
|
|
var activeGroup = Groups.getActiveGroup();
|
|
if( activeGroup )
|
|
activeGroup.reorderBasedOnTabOrder(item);
|
|
|
|
window.Groups.setActiveGroup(null);
|
|
UI.resize(true);
|
|
});
|
|
}
|
|
} else { // switched to another tab
|
|
UI.focused = false;
|
|
Page.showChrome();
|
|
|
|
iQ.timeout(function() { // Marshal event from chrome thread to DOM thread
|
|
if(focusTab != UI.currentTab) // things have changed while we were in timeout
|
|
return;
|
|
|
|
var newItem = null;
|
|
if(focusTab && focusTab.mirror)
|
|
newItem = TabItems.getItemByTabElement(focusTab.mirror.el);
|
|
|
|
if(newItem)
|
|
Groups.setActiveGroup(newItem.parent);
|
|
|
|
UI.tabBar.show();
|
|
|
|
// ___ prepare for when we return to TabCandy
|
|
var oldItem = null;
|
|
if(currentTab && currentTab.mirror)
|
|
oldItem = TabItems.getItemByTabElement(currentTab.mirror.el);
|
|
|
|
if(newItem != oldItem) {
|
|
if(oldItem)
|
|
oldItem.setZoomPrep(false);
|
|
|
|
if(newItem)
|
|
newItem.setZoomPrep(true);
|
|
}
|
|
}, 1);
|
|
}
|
|
|
|
UI.currentTab = focusTab;
|
|
});
|
|
},
|
|
|
|
// ----------
|
|
createGroupOnDrag: function(e){
|
|
/* e.preventDefault(); */
|
|
const minSize = 60;
|
|
|
|
var startPos = {x:e.clientX, y:e.clientY}
|
|
var phantom = iQ("<div>")
|
|
.addClass('group phantom')
|
|
.css({
|
|
position: "absolute",
|
|
top: startPos.y,
|
|
left: startPos.x,
|
|
width: 0,
|
|
height: 0,
|
|
opacity: .7,
|
|
zIndex: -1,
|
|
cursor: "default"
|
|
})
|
|
.appendTo("body");
|
|
|
|
function updateSize(e){
|
|
var css = {width: e.clientX-startPos.x, height:e.clientY-startPos.y}
|
|
if( css.width > minSize || css.height > minSize ) css.opacity = 1;
|
|
else css.opacity = .7
|
|
|
|
phantom.css(css);
|
|
e.preventDefault();
|
|
}
|
|
|
|
function collapse(){
|
|
phantom.animate({
|
|
width: 0,
|
|
height: 0,
|
|
top: phantom.position().top + phantom.height()/2,
|
|
left: phantom.position().left + phantom.width()/2
|
|
}, {
|
|
duration: 300,
|
|
complete: function() {
|
|
phantom.remove();
|
|
}
|
|
});
|
|
}
|
|
|
|
function finalize(e){
|
|
iQ("#bg, .phantom").unbind("mousemove", updateSize);
|
|
if( phantom.css("opacity") != 1 ) collapse();
|
|
else{
|
|
var bounds = new Rect(startPos.x, startPos.y, phantom.width(), phantom.height())
|
|
|
|
// Add all of the orphaned tabs that are contained inside the new group
|
|
// to that group.
|
|
var tabs = Groups.getOrphanedTabs();
|
|
var insideTabs = [];
|
|
for each( tab in tabs ){
|
|
if( bounds.contains( tab.bounds ) ){
|
|
insideTabs.push(tab);
|
|
}
|
|
}
|
|
|
|
var group = new Group(insideTabs,{bounds:bounds});
|
|
phantom.remove();
|
|
}
|
|
}
|
|
|
|
iQ("#bg, .phantom").mousemove(updateSize)
|
|
iQ(window).one('mouseup', finalize);
|
|
e.preventDefault();
|
|
return false;
|
|
},
|
|
|
|
// ----------
|
|
// Function: setActiveTab
|
|
// Sets the currently active tab. The idea of a focused tab is useful
|
|
// for keyboard navigation and returning to the last zoomed-in tab.
|
|
// Hitting return/esc brings you to the focused tab, and using the
|
|
// arrow keys lets you navigate between open tabs.
|
|
//
|
|
// Parameters:
|
|
// - Takes a <TabItem>
|
|
//
|
|
setActiveTab: function(tab){
|
|
if(tab == this._activeTab)
|
|
return;
|
|
|
|
if(this._activeTab) {
|
|
this._activeTab.makeDeactive();
|
|
this._activeTab.removeOnClose(this);
|
|
}
|
|
|
|
this._activeTab = tab;
|
|
|
|
if(this._activeTab) {
|
|
var self = this;
|
|
this._activeTab.addOnClose(this, function() {
|
|
self._activeTab = null;
|
|
});
|
|
|
|
this._activeTab.makeActive();
|
|
}
|
|
},
|
|
|
|
// ----------
|
|
// Function: getActiveTab
|
|
// Returns the currently active tab as a <TabItem>
|
|
//
|
|
getActiveTab: function(){
|
|
return this._activeTab;
|
|
}
|
|
}
|
|
|
|
// ##########
|
|
// Class: UIClass
|
|
// Singleton top-level UI manager. TODO: Integrate with <Page>.
|
|
function UIClass(){
|
|
if(window.Tabs)
|
|
this.init();
|
|
else {
|
|
var self = this;
|
|
TabsManager.addSubscriber(this, 'load', function() {
|
|
self.init();
|
|
});
|
|
}
|
|
};
|
|
|
|
// ----------
|
|
UIClass.prototype = {
|
|
// ----------
|
|
init: function() {
|
|
try {
|
|
// Variable: navBar
|
|
// A reference to the <Navbar>, for manipulating the browser's nav bar.
|
|
this.navBar = Navbar;
|
|
|
|
// Variable: tabBar
|
|
// A reference to the <Tabbar>, for manipulating the browser's tab bar.
|
|
this.tabBar = Tabbar;
|
|
|
|
// Variable: devMode
|
|
// If true (set by an url parameter), adds extra features to the screen.
|
|
// TODO: Integrate with the dev menu
|
|
this.devMode = false;
|
|
|
|
// Variable: currentTab
|
|
// Keeps track of which <Tabs> tab we are currently on.
|
|
// Used to facilitate zooming down from a previous tab.
|
|
this.currentTab = Utils.activeTab;
|
|
|
|
// Variable: focused
|
|
// Keeps track of whether Tab Candy is focused.
|
|
this.focused = (Utils.activeTab == Utils.homeTab);
|
|
|
|
var self = this;
|
|
|
|
// ___ Dev Menu
|
|
this.addDevMenu();
|
|
|
|
iQ("#reset").click(function(){
|
|
self.reset();
|
|
});
|
|
|
|
// ___ Navbar
|
|
if(this.focused) {
|
|
Page.hideChrome();
|
|
}
|
|
|
|
Tabs.onOpen(function(a, b) {
|
|
iQ.timeout(function() { // Marshal event from chrome thread to DOM thread
|
|
self.navBar.show();
|
|
}, 1);
|
|
});
|
|
|
|
iQ(window).bind('beforeunload', function() {
|
|
// Things may not all be set up by now, so check for everything
|
|
if(self.showChrome)
|
|
self.showChrome();
|
|
|
|
if(self.tabBar && self.tabBar.showAllTabs)
|
|
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 firstTime = !groupsData || iQ.isEmptyObject(groupsData);
|
|
var groupData = Storage.readGroupData(currentWindow);
|
|
Groups.reconstitute(groupsData, groupData);
|
|
|
|
TabItems.init();
|
|
|
|
if(firstTime) {
|
|
var items = TabItems.getItems();
|
|
iQ.each(items, function(index, item) {
|
|
if(item.parent)
|
|
item.parent.remove(item);
|
|
});
|
|
|
|
var box = Items.getPageBounds();
|
|
box.inset(10, 10);
|
|
var options = {padding: 10};
|
|
Items.arrange(items, box, options);
|
|
} else
|
|
TabItems.reconstitute();
|
|
|
|
// ___ resizing
|
|
if(data.pageBounds) {
|
|
this.pageBounds = data.pageBounds;
|
|
this.resize(true);
|
|
} else
|
|
this.pageBounds = Items.getPageBounds();
|
|
|
|
iQ(window).resize(function() {
|
|
self.resize();
|
|
});
|
|
|
|
// ___ Done
|
|
this.initialized = true;
|
|
this.save(); // for this.pageBounds
|
|
}catch(e) {
|
|
Utils.log("Error in UIClass(): " + e);
|
|
Utils.log(e.fileName);
|
|
Utils.log(e.lineNumber);
|
|
Utils.log(e.stack);
|
|
}
|
|
},
|
|
|
|
// ----------
|
|
resize: function(force) {
|
|
if( typeof(force) == "undefined" ) force = false;
|
|
|
|
// If we are currently doing an animation or if TabCandy isn't focused
|
|
// don't perform a resize. This resize really slows things down.
|
|
var isAnimating = iQ.isAnimating();
|
|
if( force == false){
|
|
if( isAnimating || !Page.isTabCandyFocused() ) return; }
|
|
|
|
var items = Items.getTopLevelItems();
|
|
var itemBounds = new Rect(this.pageBounds);
|
|
itemBounds.width = 1;
|
|
itemBounds.height = 1;
|
|
iQ.each(items, function(index, item) {
|
|
if(item.locked.bounds)
|
|
return;
|
|
|
|
var bounds = item.getBounds();
|
|
itemBounds = (itemBounds ? itemBounds.union(bounds) : new Rect(bounds));
|
|
});
|
|
|
|
var oldPageBounds = new Rect(this.pageBounds);
|
|
|
|
var newPageBounds = Items.getPageBounds();
|
|
if(newPageBounds.equals(oldPageBounds))
|
|
return;
|
|
|
|
Groups.repositionNewTabGroup(); // TODO:
|
|
|
|
if(newPageBounds.width < this.pageBounds.width && newPageBounds.width > itemBounds.width)
|
|
newPageBounds.width = this.pageBounds.width;
|
|
|
|
if(newPageBounds.height < this.pageBounds.height && newPageBounds.height > itemBounds.height)
|
|
newPageBounds.height = this.pageBounds.height;
|
|
|
|
var wScale;
|
|
var hScale;
|
|
if(Math.abs(newPageBounds.width - this.pageBounds.width)
|
|
> Math.abs(newPageBounds.height - this.pageBounds.height)) {
|
|
wScale = newPageBounds.width / this.pageBounds.width;
|
|
hScale = newPageBounds.height / itemBounds.height;
|
|
} else {
|
|
wScale = newPageBounds.width / itemBounds.width;
|
|
hScale = newPageBounds.height / this.pageBounds.height;
|
|
}
|
|
|
|
var scale = Math.min(hScale, wScale);
|
|
var self = this;
|
|
var pairs = [];
|
|
iQ.each(items, function(index, item) {
|
|
if(item.locked.bounds)
|
|
return;
|
|
|
|
var bounds = item.getBounds();
|
|
|
|
bounds.left += newPageBounds.left - self.pageBounds.left;
|
|
bounds.left *= scale;
|
|
bounds.width *= scale;
|
|
|
|
bounds.top += newPageBounds.top - self.pageBounds.top;
|
|
bounds.top *= scale;
|
|
bounds.height *= scale;
|
|
|
|
pairs.push({
|
|
item: item,
|
|
bounds: bounds
|
|
});
|
|
});
|
|
|
|
Items.unsquish(pairs);
|
|
|
|
iQ.each(pairs, function(index, pair) {
|
|
pair.item.setBounds(pair.bounds, true);
|
|
});
|
|
|
|
this.pageBounds = Items.getPageBounds();
|
|
this.save();
|
|
},
|
|
|
|
// ----------
|
|
addDevMenu: function() {
|
|
var self = this;
|
|
|
|
var $select = iQ('<select>')
|
|
.css({
|
|
position: 'absolute',
|
|
bottom: 5,
|
|
right: 5,
|
|
opacity: .2
|
|
})
|
|
.appendTo('body')
|
|
.change(function () {
|
|
var index = iQ(this).val();
|
|
try {
|
|
commands[index].code();
|
|
} catch(e) {
|
|
Utils.log('dev menu error', e);
|
|
}
|
|
iQ(this).val(0);
|
|
});
|
|
|
|
var commands = [{
|
|
name: 'dev menu',
|
|
code: function() {
|
|
}
|
|
}, {
|
|
name: 'home',
|
|
code: function() {
|
|
location.href = '../../index.html';
|
|
}
|
|
}, {
|
|
name: 'code docs',
|
|
code: function() {
|
|
location.href = '../../doc/index.html';
|
|
}
|
|
}, {
|
|
name: 'tests',
|
|
code: function() {
|
|
location.href = 'test.html';
|
|
}
|
|
}, {
|
|
name: 'save',
|
|
code: function() {
|
|
self.saveAll();
|
|
}
|
|
}, {
|
|
name: 'group sites',
|
|
code: function() {
|
|
self.arrangeBySite();
|
|
}
|
|
}];
|
|
|
|
var count = commands.length;
|
|
var a;
|
|
for(a = 0; a < count; a++) {
|
|
iQ('<option>')
|
|
.val(a)
|
|
.html(commands[a].name)
|
|
.appendTo($select);
|
|
}
|
|
},
|
|
|
|
// -----------
|
|
reset: function() {
|
|
Storage.wipe();
|
|
location.href = '';
|
|
},
|
|
|
|
// ----------
|
|
saveAll: function() {
|
|
this.save();
|
|
Groups.saveAll();
|
|
TabItems.saveAll();
|
|
},
|
|
|
|
// ----------
|
|
save: function() {
|
|
if(!this.initialized)
|
|
return;
|
|
|
|
var data = {
|
|
pageBounds: this.pageBounds
|
|
};
|
|
|
|
if(this.storageSanity(data))
|
|
Storage.saveUIData(Utils.getCurrentWindow(), data);
|
|
},
|
|
|
|
// ----------
|
|
storageSanity: function(data) {
|
|
if(iQ.isEmptyObject(data))
|
|
return true;
|
|
|
|
if(!isRect(data.pageBounds)) {
|
|
Utils.log('UI.storageSanity: bad pageBounds', data.pageBounds);
|
|
data.pageBounds = null;
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
},
|
|
|
|
// ----------
|
|
arrangeBySite: function() {
|
|
function putInGroup(set, key) {
|
|
var group = Groups.getGroupWithTitle(key);
|
|
if(group) {
|
|
iQ.each(set, function(index, el) {
|
|
group.add(el);
|
|
});
|
|
} else
|
|
new Group(set, {dontPush: true, dontArrange: true, title: key});
|
|
}
|
|
|
|
Groups.removeAll();
|
|
|
|
var newTabsGroup = Groups.getNewTabGroup();
|
|
var groups = [];
|
|
var items = TabItems.getItems();
|
|
iQ.each(items, function(index, item) {
|
|
var url = item.getURL();
|
|
var domain = url.split('/')[2];
|
|
if(!domain)
|
|
newTabsGroup.add(item);
|
|
else {
|
|
var domainParts = domain.split('.');
|
|
var mainDomain = domainParts[domainParts.length - 2];
|
|
if(groups[mainDomain])
|
|
groups[mainDomain].push(item.container);
|
|
else
|
|
groups[mainDomain] = [item.container];
|
|
}
|
|
});
|
|
|
|
var leftovers = [];
|
|
for(key in groups) {
|
|
var set = groups[key];
|
|
if(set.length > 1) {
|
|
putInGroup(set, key);
|
|
} else
|
|
leftovers.push(set[0]);
|
|
}
|
|
|
|
putInGroup(leftovers, 'mixed');
|
|
|
|
Groups.arrange();
|
|
},
|
|
|
|
// ----------
|
|
newTab: function(url, inBackground) {
|
|
Tabs.open(url, inBackground);
|
|
}
|
|
};
|
|
|
|
// ----------
|
|
window.UI = new UIClass();
|
|
|
|
})();
|
|
|