2010-06-16 17:19:11 -07:00
|
|
|
/* ***** BEGIN LICENSE BLOCK *****
|
|
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
|
|
*
|
|
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
|
|
* the License. You may obtain a copy of the License at
|
|
|
|
* http://www.mozilla.org/MPL/
|
|
|
|
*
|
|
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
|
|
* for the specific language governing rights and limitations under the
|
|
|
|
* License.
|
|
|
|
*
|
|
|
|
* The Original Code is ui.js.
|
|
|
|
*
|
|
|
|
* The Initial Developer of the Original Code is
|
|
|
|
* Ian Gilman <ian@iangilman.com>.
|
|
|
|
* Portions created by the Initial Developer are Copyright (C) 2010
|
|
|
|
* the Initial Developer. All Rights Reserved.
|
|
|
|
*
|
|
|
|
* Contributor(s):
|
|
|
|
* Aza Raskin <aza@mozilla.com>
|
|
|
|
* Michael Yoshitaka Erlewine <mitcho@mitcho.com>
|
|
|
|
* Ehsan Akhgari <ehsan@mozilla.com>
|
2010-06-21 17:27:12 -07:00
|
|
|
* Raymond Lee <raymond@appcoast.com>
|
2010-06-16 17:19:11 -07:00
|
|
|
*
|
|
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
|
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
|
|
|
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
|
|
* use your version of this file under the terms of the MPL, indicate your
|
|
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
|
|
* the provisions above, a recipient may use your version of this file under
|
|
|
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
|
|
|
*
|
|
|
|
* ***** END LICENSE BLOCK ***** */
|
|
|
|
|
|
|
|
// **********
|
|
|
|
// Title: ui.js
|
2010-05-11 17:22:06 -07:00
|
|
|
|
2010-02-24 01:47:55 -08:00
|
|
|
(function(){
|
|
|
|
|
2010-05-23 23:42:18 -07:00
|
|
|
window.Keys = {meta: false};
|
|
|
|
|
2010-03-25 17:22:45 -07:00
|
|
|
// ##########
|
2010-02-24 01:47:55 -08:00
|
|
|
Navbar = {
|
2010-04-22 17:19:42 -07:00
|
|
|
// ----------
|
2010-02-24 01:47:55 -08:00
|
|
|
get el(){
|
2010-05-24 14:49:03 -07:00
|
|
|
var win = Utils.getCurrentWindow();
|
2010-04-22 17:19:42 -07:00
|
|
|
if(win) {
|
|
|
|
var navbar = win.gBrowser.ownerDocument.getElementById("navigator-toolbox");
|
|
|
|
return navbar;
|
|
|
|
}
|
|
|
|
|
|
|
|
return null;
|
|
|
|
},
|
2010-05-03 15:24:22 -07:00
|
|
|
|
|
|
|
get urlBar(){
|
2010-05-24 14:49:03 -07:00
|
|
|
var win = Utils.getCurrentWindow();
|
2010-05-03 15:24:22 -07:00
|
|
|
if(win) {
|
|
|
|
var navbar = win.gBrowser.ownerDocument.getElementById("urlbar");
|
|
|
|
return navbar;
|
|
|
|
}
|
|
|
|
|
|
|
|
return null;
|
2010-06-23 02:25:34 -07:00
|
|
|
}
|
2010-06-25 16:00:51 -07:00
|
|
|
};
|
2010-02-24 01:47:55 -08:00
|
|
|
|
2010-03-25 17:22:45 -07:00
|
|
|
// ##########
|
2010-05-14 15:58:55 -07:00
|
|
|
// Class: Tabbar
|
|
|
|
// Singleton for managing the tabbar of the browser.
|
2010-02-24 01:47:55 -08:00
|
|
|
var Tabbar = {
|
2010-05-13 15:14:08 -07:00
|
|
|
// ----------
|
2010-05-19 16:35:54 -07:00
|
|
|
get el() {
|
|
|
|
return window.Tabs[0].raw.parentNode;
|
|
|
|
},
|
2010-05-13 15:14:08 -07:00
|
|
|
|
|
|
|
// ----------
|
2010-05-19 16:35:54 -07:00
|
|
|
get height() {
|
|
|
|
return window.Tabs[0].raw.parentNode.getBoundingClientRect().height;
|
|
|
|
},
|
2010-04-27 15:31:20 -07:00
|
|
|
|
2010-05-08 21:11:57 -07:00
|
|
|
// ----------
|
|
|
|
// Function: getVisibleTabs
|
|
|
|
// Returns an array of the tabs which are currently visibible in the
|
|
|
|
// tab bar.
|
|
|
|
getVisibleTabs: function(){
|
|
|
|
var visibleTabs = [];
|
2010-05-14 15:58:55 -07:00
|
|
|
// this.el.children is not a real array and does contain
|
2010-05-08 21:11:57 -07:00
|
|
|
// useful functions like filter or forEach. Convert it into a real array.
|
2010-05-14 15:58:55 -07:00
|
|
|
for( var i=0; i<this.el.children.length; i++ ){
|
|
|
|
var tab = this.el.children[i];
|
2010-05-10 09:43:34 -07:00
|
|
|
if( tab.collapsed == false )
|
2010-05-08 21:11:57 -07:00
|
|
|
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.
|
2010-06-17 14:52:25 -07:00
|
|
|
showOnlyTheseTabs: function(tabs, options){
|
|
|
|
try {
|
|
|
|
if(!options)
|
|
|
|
options = {};
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
if(!options.dontReorg)
|
|
|
|
Utils.getCurrentWindow().gBrowser.moveTabTo(tab, self.el.children.length-1);
|
|
|
|
});
|
|
|
|
} catch(e) {
|
|
|
|
Utils.log(e);
|
2010-04-27 15:31:20 -07:00
|
|
|
}
|
2010-04-20 10:53:07 -07:00
|
|
|
},
|
2010-05-13 15:14:08 -07:00
|
|
|
|
|
|
|
// ----------
|
|
|
|
// Function: showAllTabs
|
|
|
|
// Shows all of the tabs in the tab bar.
|
|
|
|
showAllTabs: function(){
|
2010-05-14 15:58:55 -07:00
|
|
|
for( var i=0; i<this.el.children.length; i++ ){
|
|
|
|
var tab = this.el.children[i];
|
2010-05-13 15:14:08 -07:00
|
|
|
tab.collapsed = false;
|
|
|
|
}
|
2010-06-23 02:25:34 -07:00
|
|
|
}
|
2010-02-24 01:47:55 -08:00
|
|
|
}
|
|
|
|
|
2010-03-25 17:22:45 -07:00
|
|
|
// ##########
|
2010-05-14 15:58:55 -07:00
|
|
|
// Class: Page
|
|
|
|
// Singleton top-level UI manager. TODO: Integrate with <UIClass>.
|
2010-03-29 17:23:35 -07:00
|
|
|
window.Page = {
|
|
|
|
startX: 30,
|
2010-03-31 17:24:16 -07:00
|
|
|
startY: 70,
|
2010-04-30 23:50:43 -07:00
|
|
|
|
2010-07-03 09:08:34 -07:00
|
|
|
isTabCandyVisible: function(){
|
2010-07-02 02:28:53 -07:00
|
|
|
return (Utils.getCurrentWindow().document.getElementById("tab-candy-deck").
|
|
|
|
selectedIndex == 1);
|
2010-05-21 19:51:34 -07:00
|
|
|
},
|
|
|
|
|
|
|
|
hideChrome: function(){
|
2010-06-23 02:25:34 -07:00
|
|
|
let currentWin = Utils.getCurrentWindow();
|
2010-07-03 09:08:34 -07:00
|
|
|
currentWin.document.getElementById("tab-candy-deck").selectedIndex = 1;
|
|
|
|
|
2010-05-21 19:51:34 -07:00
|
|
|
// Mac Only
|
2010-06-23 02:25:34 -07:00
|
|
|
Utils.getCurrentWindow().document.getElementById("main-window").
|
|
|
|
setAttribute("activetitlebarcolor", "#C4C4C4");
|
2010-05-21 19:51:34 -07:00
|
|
|
},
|
|
|
|
|
|
|
|
showChrome: function(){
|
2010-06-23 02:25:34 -07:00
|
|
|
let currentWin = Utils.getCurrentWindow();
|
|
|
|
currentWin.document.getElementById("tab-candy-deck").selectedIndex = 0;
|
2010-06-21 15:17:23 -07:00
|
|
|
|
2010-05-21 19:51:34 -07:00
|
|
|
// Mac Only
|
2010-06-23 02:25:34 -07:00
|
|
|
Utils.getCurrentWindow().document.getElementById("main-window").
|
|
|
|
removeAttribute("activetitlebarcolor");
|
2010-04-30 23:50:43 -07:00
|
|
|
},
|
2010-06-23 02:25:34 -07:00
|
|
|
|
|
|
|
showTabCandy : function() {
|
|
|
|
let self = this;
|
|
|
|
|
|
|
|
let currentTab = UI.currentTab;
|
|
|
|
let 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);
|
|
|
|
|
|
|
|
let activeGroup = Groups.getActiveGroup();
|
|
|
|
if( activeGroup )
|
|
|
|
activeGroup.setTopChild(item);
|
2010-05-12 19:56:35 -07:00
|
|
|
|
2010-06-23 02:25:34 -07:00
|
|
|
window.Groups.setActiveGroup(null);
|
|
|
|
UI.resize(true);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
},
|
2010-06-21 15:17:23 -07:00
|
|
|
|
2010-05-12 19:56:35 -07:00
|
|
|
setupKeyHandlers: function(){
|
|
|
|
var self = this;
|
2010-05-28 15:56:00 -07:00
|
|
|
iQ(window).keyup(function(e){
|
2010-05-23 23:42:18 -07:00
|
|
|
if( e.metaKey == false ) window.Keys.meta = false;
|
|
|
|
});
|
|
|
|
|
2010-05-28 15:56:00 -07:00
|
|
|
iQ(window).keydown(function(e){
|
2010-05-23 23:42:18 -07:00
|
|
|
if( e.metaKey == true ) window.Keys.meta = true;
|
|
|
|
|
2010-05-12 19:56:35 -07:00
|
|
|
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]);
|
|
|
|
});
|
2010-05-12 20:31:51 -07:00
|
|
|
if( matches.length > 0 ) return matches[0][1];
|
|
|
|
else return null;
|
2010-05-12 19:56:35 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
2010-05-24 00:37:31 -07:00
|
|
|
case 69: // Command-E
|
2010-06-14 15:43:02 -07:00
|
|
|
if( Keys.meta ) if( self.getActiveTab() ) self.getActiveTab().zoomIn();
|
2010-05-24 00:37:31 -07:00
|
|
|
break;
|
2010-05-12 19:56:35 -07:00
|
|
|
}
|
|
|
|
|
2010-05-28 15:56:00 -07:00
|
|
|
if( norm != null && iQ(":focus").length == 0 ){
|
2010-05-12 19:56:35 -07:00
|
|
|
var nextTab = getClosestTabBy(norm);
|
2010-05-12 20:31:51 -07:00
|
|
|
if( nextTab ){
|
|
|
|
if( nextTab.inStack() && !nextTab.parent.expanded){
|
|
|
|
nextTab = nextTab.parent.getChild(0);
|
|
|
|
}
|
|
|
|
self.setActiveTab(nextTab);
|
|
|
|
}
|
2010-05-12 19:56:35 -07:00
|
|
|
e.preventDefault();
|
2010-05-14 17:23:21 -07:00
|
|
|
}
|
|
|
|
|
2010-05-28 15:56:00 -07:00
|
|
|
if((e.which == 27 || e.which == 13) && iQ(":focus").length == 0 )
|
2010-06-14 15:43:02 -07:00
|
|
|
if( self.getActiveTab() ) self.getActiveTab().zoomIn();
|
2010-05-12 19:56:35 -07:00
|
|
|
});
|
2010-05-14 17:23:21 -07:00
|
|
|
|
2010-05-12 19:56:35 -07:00
|
|
|
},
|
2010-03-31 17:24:16 -07:00
|
|
|
|
2010-04-14 17:12:06 -07:00
|
|
|
// ----------
|
2010-05-12 19:56:35 -07:00
|
|
|
init: function() {
|
|
|
|
var self = this;
|
2010-05-21 01:05:55 -07:00
|
|
|
|
2010-05-06 16:28:10 -07:00
|
|
|
// When you click on the background/empty part of TabCandy
|
|
|
|
// we create a new group.
|
2010-06-23 02:25:34 -07:00
|
|
|
let tabCandyContentDoc =
|
|
|
|
Utils.getCurrentWindow().document.getElementById("tab-candy").
|
|
|
|
contentDocument;
|
|
|
|
iQ(tabCandyContentDoc).mousedown(function(e){
|
2010-05-21 18:08:35 -07:00
|
|
|
if( e.originalTarget.id == "bg" )
|
2010-05-06 16:28:10 -07:00
|
|
|
Page.createGroupOnDrag(e)
|
2010-06-23 02:25:34 -07:00
|
|
|
});
|
2010-05-06 16:28:10 -07:00
|
|
|
|
2010-05-12 19:56:35 -07:00
|
|
|
this.setupKeyHandlers();
|
2010-05-04 13:52:25 -07:00
|
|
|
|
2010-02-24 01:47:55 -08:00
|
|
|
Tabs.onClose(function(){
|
2010-07-06 18:50:15 -07:00
|
|
|
if (!self.isTabCandyVisible()) {
|
2010-07-06 19:32:42 -07:00
|
|
|
iQ.timeout(function() { // Marshal event from chrome thread to DOM thread
|
2010-07-06 18:50:15 -07:00
|
|
|
// 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 ) {
|
|
|
|
self.hideChrome();
|
|
|
|
self.showTabCandy();
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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){
|
|
|
|
self.hideChrome();
|
|
|
|
self.showTabCandy();
|
|
|
|
}
|
|
|
|
}, 1);
|
|
|
|
}
|
2010-02-24 01:47:55 -08:00
|
|
|
return false;
|
2010-03-19 15:21:12 -07:00
|
|
|
});
|
2010-05-12 19:56:35 -07:00
|
|
|
|
2010-06-17 16:38:07 -07:00
|
|
|
Tabs.onMove(function() {
|
|
|
|
iQ.timeout(function() { // Marshal event from chrome thread to DOM thread
|
|
|
|
var activeGroup = Groups.getActiveGroup();
|
|
|
|
if( activeGroup )
|
|
|
|
activeGroup.reorderBasedOnTabOrder();
|
|
|
|
}, 1);
|
|
|
|
});
|
|
|
|
|
2010-05-14 17:11:42 -07:00
|
|
|
Tabs.onFocus(function() {
|
2010-07-02 02:28:53 -07:00
|
|
|
self.tabOnFocus(this);
|
|
|
|
});
|
|
|
|
},
|
2010-06-14 15:43:02 -07:00
|
|
|
|
2010-07-02 02:28:53 -07:00
|
|
|
// ----------
|
|
|
|
tabOnFocus: function(tab) {
|
|
|
|
var focusTab = tab;
|
|
|
|
var currentTab = UI.currentTab;
|
|
|
|
|
|
|
|
UI.currentTab = focusTab;
|
2010-07-03 09:08:34 -07:00
|
|
|
if (this.isTabCandyVisible()) {
|
2010-07-02 02:28:53 -07:00
|
|
|
this.showChrome();
|
|
|
|
}
|
2010-06-14 16:56:27 -07:00
|
|
|
|
2010-07-02 02:28:53 -07:00
|
|
|
iQ.timeout(function() { // Marshal event from chrome thread to DOM thread
|
|
|
|
if(focusTab != UI.currentTab) {
|
|
|
|
// things have changed while we were in timeout
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
let newItem = null;
|
|
|
|
if(focusTab && focusTab.mirror)
|
|
|
|
newItem = TabItems.getItemByTabElement(focusTab.mirror.el);
|
2010-06-23 02:25:34 -07:00
|
|
|
|
2010-07-02 02:28:53 -07:00
|
|
|
if(newItem)
|
|
|
|
Groups.setActiveGroup(newItem.parent);
|
2010-06-23 02:25:34 -07:00
|
|
|
|
2010-07-02 02:28:53 -07:00
|
|
|
// ___ prepare for when we return to TabCandy
|
|
|
|
let oldItem = null;
|
|
|
|
if(currentTab && currentTab.mirror)
|
|
|
|
oldItem = TabItems.getItemByTabElement(currentTab.mirror.el);
|
2010-06-23 02:25:34 -07:00
|
|
|
|
2010-07-02 02:28:53 -07:00
|
|
|
if(newItem != oldItem) {
|
|
|
|
if(oldItem)
|
|
|
|
oldItem.setZoomPrep(false);
|
2010-06-23 02:25:34 -07:00
|
|
|
|
2010-07-02 02:28:53 -07:00
|
|
|
if(newItem)
|
|
|
|
newItem.setZoomPrep(true);
|
|
|
|
} else {
|
|
|
|
// the tab is already focused so the new and old items are the
|
|
|
|
// same.
|
|
|
|
if (oldItem) {
|
|
|
|
oldItem.setZoomPrep(true);
|
2010-06-23 02:25:34 -07:00
|
|
|
}
|
2010-07-02 02:28:53 -07:00
|
|
|
}
|
|
|
|
}, 1);
|
2010-03-24 10:34:25 -07:00
|
|
|
},
|
2010-06-23 02:25:34 -07:00
|
|
|
|
2010-05-06 16:28:10 -07:00
|
|
|
// ----------
|
|
|
|
createGroupOnDrag: function(e){
|
2010-05-10 17:17:48 -07:00
|
|
|
/* e.preventDefault(); */
|
2010-05-06 16:28:10 -07:00
|
|
|
const minSize = 60;
|
2010-06-18 14:42:06 -07:00
|
|
|
const minMinSize = 15;
|
2010-05-06 16:28:10 -07:00
|
|
|
|
|
|
|
var startPos = {x:e.clientX, y:e.clientY}
|
2010-06-03 15:31:18 -07:00
|
|
|
var phantom = iQ("<div>")
|
2010-05-28 15:56:00 -07:00
|
|
|
.addClass('group phantom')
|
|
|
|
.css({
|
|
|
|
position: "absolute",
|
|
|
|
opacity: .7,
|
|
|
|
zIndex: -1,
|
|
|
|
cursor: "default"
|
|
|
|
})
|
|
|
|
.appendTo("body");
|
2010-07-03 12:44:35 -07:00
|
|
|
|
|
|
|
var item = { // a faux-Item
|
|
|
|
container: phantom,
|
2010-07-03 13:55:54 -07:00
|
|
|
isAFauxItem: true,
|
2010-07-03 12:44:35 -07:00
|
|
|
bounds: {},
|
|
|
|
getBounds: function FauxItem_getBounds() {
|
|
|
|
return this.container.bounds();
|
|
|
|
},
|
|
|
|
setBounds: function FauxItem_setBounds( bounds ) {
|
|
|
|
this.container.css( bounds );
|
|
|
|
},
|
|
|
|
setZ: function FauxItem_setZ( z ) {
|
|
|
|
this.container.css( 'z-index', z );
|
|
|
|
},
|
|
|
|
setOpacity: function FauxItem_setOpacity( opacity ) {
|
|
|
|
this.container.css( 'opacity', opacity );
|
|
|
|
},
|
|
|
|
// we don't need to pushAway the phantom item at the end, because
|
|
|
|
// when we create a new Group, it'll do the actual pushAway.
|
|
|
|
pushAway: function () {},
|
|
|
|
};
|
|
|
|
item.setBounds( new Rect( startPos.y, startPos.x, 0, 0 ) );
|
|
|
|
|
|
|
|
var dragOutInfo = new Drag(item, e, true); // true = isResizing
|
2010-05-06 16:28:10 -07:00
|
|
|
|
|
|
|
function updateSize(e){
|
2010-06-18 14:42:06 -07:00
|
|
|
var box = new Rect();
|
|
|
|
box.left = Math.min(startPos.x, e.clientX);
|
|
|
|
box.right = Math.max(startPos.x, e.clientX);
|
|
|
|
box.top = Math.min(startPos.y, e.clientY);
|
|
|
|
box.bottom = Math.max(startPos.y, e.clientY);
|
2010-07-03 12:44:35 -07:00
|
|
|
item.setBounds(box);
|
|
|
|
|
2010-07-03 13:55:54 -07:00
|
|
|
// compute the stationaryCorner
|
|
|
|
var stationaryCorner = '';
|
|
|
|
|
|
|
|
if (startPos.y == box.top)
|
|
|
|
stationaryCorner += 'top';
|
|
|
|
else
|
|
|
|
stationaryCorner += 'bottom';
|
|
|
|
|
|
|
|
if (startPos.x == box.left)
|
|
|
|
stationaryCorner += 'left';
|
|
|
|
else
|
|
|
|
stationaryCorner += 'right';
|
|
|
|
|
|
|
|
dragOutInfo.snap(stationaryCorner, false, false); // null for ui, which we don't use anyway.
|
2010-06-18 14:42:06 -07:00
|
|
|
|
2010-07-03 12:44:35 -07:00
|
|
|
box = item.getBounds();
|
|
|
|
if (box.width > minMinSize && box.height > minMinSize
|
|
|
|
&& (box.width > minSize || box.height > minSize))
|
|
|
|
item.setOpacity(1);
|
2010-06-18 14:42:06 -07:00
|
|
|
else
|
2010-07-03 12:44:35 -07:00
|
|
|
item.setOpacity(0.7);
|
2010-05-06 16:28:10 -07:00
|
|
|
|
|
|
|
e.preventDefault();
|
|
|
|
}
|
|
|
|
|
|
|
|
function collapse(){
|
|
|
|
phantom.animate({
|
|
|
|
width: 0,
|
|
|
|
height: 0,
|
|
|
|
top: phantom.position().top + phantom.height()/2,
|
|
|
|
left: phantom.position().left + phantom.width()/2
|
2010-06-07 16:16:55 -07:00
|
|
|
}, {
|
|
|
|
duration: 300,
|
|
|
|
complete: function() {
|
|
|
|
phantom.remove();
|
|
|
|
}
|
2010-05-28 15:56:00 -07:00
|
|
|
});
|
2010-05-06 16:28:10 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
function finalize(e){
|
2010-06-18 14:42:06 -07:00
|
|
|
iQ(window).unbind("mousemove", updateSize);
|
2010-07-03 12:44:35 -07:00
|
|
|
dragOutInfo.stop();
|
|
|
|
if ( phantom.css("opacity") != 1 )
|
2010-06-18 14:42:06 -07:00
|
|
|
collapse();
|
2010-07-03 12:44:35 -07:00
|
|
|
else {
|
|
|
|
var bounds = item.getBounds();
|
2010-05-06 16:28:10 -07:00
|
|
|
|
|
|
|
// 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 ){
|
2010-07-03 12:44:35 -07:00
|
|
|
if ( bounds.contains( tab.bounds ) ){
|
2010-05-06 16:28:10 -07:00
|
|
|
insideTabs.push(tab);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
var group = new Group(insideTabs,{bounds:bounds});
|
|
|
|
phantom.remove();
|
2010-07-03 12:44:35 -07:00
|
|
|
dragOutInfo = null;
|
2010-05-06 16:28:10 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-06-18 14:42:06 -07:00
|
|
|
iQ(window).mousemove(updateSize)
|
2010-06-03 15:31:18 -07:00
|
|
|
iQ(window).one('mouseup', finalize);
|
2010-05-21 18:08:35 -07:00
|
|
|
e.preventDefault();
|
2010-05-06 16:28:10 -07:00
|
|
|
return false;
|
2010-05-12 19:56:35 -07:00
|
|
|
},
|
|
|
|
|
|
|
|
// ----------
|
|
|
|
// 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.
|
2010-06-14 15:43:02 -07:00
|
|
|
// Hitting return/esc brings you to the focused tab, and using the
|
2010-05-12 19:56:35 -07:00
|
|
|
// arrow keys lets you navigate between open tabs.
|
|
|
|
//
|
2010-05-13 17:24:37 -07:00
|
|
|
// Parameters:
|
2010-05-12 19:56:35 -07:00
|
|
|
// - Takes a <TabItem>
|
|
|
|
//
|
|
|
|
setActiveTab: function(tab){
|
2010-05-13 11:21:14 -07:00
|
|
|
if(tab == this._activeTab)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if(this._activeTab) {
|
|
|
|
this._activeTab.makeDeactive();
|
|
|
|
this._activeTab.removeOnClose(this);
|
|
|
|
}
|
|
|
|
|
2010-05-12 19:56:35 -07:00
|
|
|
this._activeTab = tab;
|
2010-05-13 11:21:14 -07:00
|
|
|
|
|
|
|
if(this._activeTab) {
|
|
|
|
var self = this;
|
|
|
|
this._activeTab.addOnClose(this, function() {
|
|
|
|
self._activeTab = null;
|
|
|
|
});
|
|
|
|
|
|
|
|
this._activeTab.makeActive();
|
|
|
|
}
|
2010-05-12 19:56:35 -07:00
|
|
|
},
|
|
|
|
|
|
|
|
// ----------
|
|
|
|
// Function: getActiveTab
|
|
|
|
// Returns the currently active tab as a <TabItem>
|
|
|
|
//
|
|
|
|
getActiveTab: function(){
|
|
|
|
return this._activeTab;
|
2010-02-24 01:47:55 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-04-14 17:12:06 -07:00
|
|
|
// ##########
|
2010-05-14 15:58:55 -07:00
|
|
|
// Class: UIClass
|
|
|
|
// Singleton top-level UI manager. TODO: Integrate with <Page>.
|
2010-04-14 17:12:06 -07:00
|
|
|
function UIClass(){
|
2010-06-23 02:25:34 -07:00
|
|
|
if(window.Tabs)
|
2010-05-19 16:35:54 -07:00
|
|
|
this.init();
|
2010-06-23 02:25:34 -07:00
|
|
|
else {
|
2010-05-19 16:35:54 -07:00
|
|
|
var self = this;
|
|
|
|
TabsManager.addSubscriber(this, 'load', function() {
|
|
|
|
self.init();
|
|
|
|
});
|
2010-05-13 15:14:08 -07:00
|
|
|
}
|
2010-05-19 16:35:54 -07:00
|
|
|
};
|
2010-03-24 10:34:25 -07:00
|
|
|
|
2010-05-19 16:35:54 -07:00
|
|
|
// ----------
|
|
|
|
UIClass.prototype = {
|
|
|
|
// ----------
|
|
|
|
init: function() {
|
2010-05-21 15:44:15 -07:00
|
|
|
try {
|
2010-07-01 17:05:46 -07:00
|
|
|
Utils.log('TabCandy init --------------------');
|
2010-07-01 22:27:49 -07:00
|
|
|
|
2010-05-21 15:44:15 -07:00
|
|
|
// 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;
|
|
|
|
|
|
|
|
var self = this;
|
|
|
|
|
2010-06-28 13:47:25 -07:00
|
|
|
this.setBrowserKeyHandler();
|
|
|
|
|
2010-05-24 17:14:10 -07:00
|
|
|
// ___ Dev Menu
|
|
|
|
this.addDevMenu();
|
|
|
|
|
2010-06-03 15:31:18 -07:00
|
|
|
iQ("#reset").click(function(){
|
2010-05-27 17:25:14 -07:00
|
|
|
self.reset();
|
|
|
|
});
|
2010-06-23 02:25:34 -07:00
|
|
|
|
2010-06-29 14:39:37 -07:00
|
|
|
iQ("#feedback").click(function(){
|
|
|
|
self.newTab('http://feedback.mozillalabs.com/forums/56804-tabcandy');
|
|
|
|
});
|
|
|
|
|
2010-06-03 15:31:18 -07:00
|
|
|
iQ(window).bind('beforeunload', function() {
|
2010-06-07 17:20:15 -07:00
|
|
|
// 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();
|
2010-05-24 14:49:03 -07:00
|
|
|
});
|
|
|
|
|
2010-05-21 15:44:15 -07:00
|
|
|
// ___ Page
|
2010-06-23 02:25:34 -07:00
|
|
|
let currentWindow = Utils.getCurrentWindow();
|
2010-05-21 15:44:15 -07:00
|
|
|
Page.init();
|
2010-06-29 14:39:37 -07:00
|
|
|
|
2010-06-23 02:25:34 -07:00
|
|
|
currentWindow.addEventListener(
|
|
|
|
"tabcandyshow", function() {
|
|
|
|
Page.hideChrome();
|
|
|
|
Page.showTabCandy();
|
2010-06-29 14:39:37 -07:00
|
|
|
}, false);
|
|
|
|
|
2010-06-23 02:25:34 -07:00
|
|
|
currentWindow.addEventListener(
|
2010-06-29 14:39:37 -07:00
|
|
|
"tabcandyhide", function() { Page.showChrome(); }, false);
|
2010-07-06 19:32:42 -07:00
|
|
|
|
2010-07-02 16:33:33 -07:00
|
|
|
// ___ delay init
|
|
|
|
Storage.onReady(function() {
|
|
|
|
self.delayInit();
|
|
|
|
});
|
2010-05-21 15:44:15 -07:00
|
|
|
}catch(e) {
|
|
|
|
Utils.log("Error in UIClass(): " + e);
|
|
|
|
Utils.log(e.fileName);
|
|
|
|
Utils.log(e.lineNumber);
|
|
|
|
Utils.log(e.stack);
|
2010-05-19 16:35:54 -07:00
|
|
|
}
|
2010-07-01 22:27:49 -07:00
|
|
|
},
|
|
|
|
|
|
|
|
// ----------
|
|
|
|
delayInit : function() {
|
2010-07-06 16:22:57 -07:00
|
|
|
try {
|
|
|
|
// ___ Storage
|
|
|
|
let currentWindow = Utils.getCurrentWindow();
|
|
|
|
let data = Storage.readUIData(currentWindow);
|
|
|
|
this.storageSanity(data);
|
|
|
|
|
|
|
|
let groupsData = Storage.readGroupsData(currentWindow);
|
|
|
|
let firstTime = !groupsData || iQ.isEmptyObject(groupsData);
|
|
|
|
let groupData = Storage.readGroupData(currentWindow);
|
|
|
|
Groups.reconstitute(groupsData, groupData);
|
|
|
|
|
|
|
|
TabItems.init();
|
|
|
|
|
|
|
|
if(firstTime) {
|
|
|
|
let items = TabItems.getItems();
|
|
|
|
iQ.each(items, function(index, item) {
|
|
|
|
if(item.parent)
|
|
|
|
item.parent.remove(item);
|
|
|
|
});
|
|
|
|
|
|
|
|
let box = Items.getPageBounds();
|
|
|
|
box.inset(10, 10);
|
|
|
|
let options = {padding: 10};
|
|
|
|
Items.arrange(items, box, options);
|
|
|
|
}
|
|
|
|
|
|
|
|
// ___ resizing
|
|
|
|
if(data.pageBounds) {
|
|
|
|
this.pageBounds = data.pageBounds;
|
|
|
|
this.resize(true);
|
|
|
|
} else
|
|
|
|
this.pageBounds = Items.getPageBounds();
|
|
|
|
|
|
|
|
var self = this;
|
|
|
|
iQ(window).resize(function() {
|
|
|
|
self.resize();
|
2010-07-01 22:27:49 -07:00
|
|
|
});
|
2010-07-06 16:22:57 -07:00
|
|
|
|
|
|
|
// ___ Done
|
|
|
|
this.initialized = true;
|
|
|
|
this.save(); // for this.pageBounds
|
|
|
|
} catch(e) {
|
|
|
|
Utils.log(e);
|
|
|
|
}
|
2010-07-01 22:27:49 -07:00
|
|
|
},
|
2010-04-30 17:24:03 -07:00
|
|
|
|
2010-06-28 13:47:25 -07:00
|
|
|
// ----------
|
|
|
|
setBrowserKeyHandler : function() {
|
|
|
|
var self = this;
|
|
|
|
var browser = Utils.getCurrentWindow().gBrowser;
|
|
|
|
var tabbox = browser.mTabBox;
|
|
|
|
|
|
|
|
browser.addEventListener("keypress", function(event) {
|
|
|
|
var handled = false;
|
|
|
|
// based on http://mxr.mozilla.org/mozilla1.9.2/source/toolkit/content/widgets/tabbox.xml#145
|
|
|
|
switch (event.keyCode) {
|
|
|
|
case event.DOM_VK_TAB:
|
|
|
|
if (event.ctrlKey && !event.altKey && !event.metaKey)
|
|
|
|
if (tabbox.tabs && tabbox.handleCtrlTab) {
|
|
|
|
self.advanceSelectedTab(event.shiftKey);
|
|
|
|
event.stopPropagation();
|
|
|
|
event.preventDefault();
|
|
|
|
handled = true;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case event.DOM_VK_PAGE_UP:
|
|
|
|
if (event.ctrlKey && !event.shiftKey && !event.altKey &&
|
|
|
|
!event.metaKey)
|
|
|
|
if (tabbox.tabs && tabbox.handleCtrlPageUpDown) {
|
|
|
|
self.advanceSelectedTab(true);
|
|
|
|
event.stopPropagation();
|
|
|
|
event.preventDefault();
|
|
|
|
handled = true;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case event.DOM_VK_PAGE_DOWN:
|
|
|
|
if (event.ctrlKey && !event.shiftKey && !event.altKey &&
|
|
|
|
!event.metaKey)
|
|
|
|
if (tabbox.tabs && tabbox.handleCtrlPageUpDown) {
|
|
|
|
self.advanceSelectedTab(false);
|
|
|
|
event.stopPropagation();
|
|
|
|
event.preventDefault();
|
|
|
|
handled = true;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case event.DOM_VK_LEFT:
|
|
|
|
if (event.metaKey && event.altKey && !event.shiftKey &&
|
|
|
|
!event.ctrlKey)
|
|
|
|
if (tabbox.tabs && tabbox._handleMetaAltArrows) {
|
|
|
|
var reverse =
|
|
|
|
window.getComputedStyle(tabbox, "").direction == "ltr" ? -1 : 1;
|
|
|
|
self.advanceSelectedTab(reverse);
|
|
|
|
event.stopPropagation();
|
|
|
|
event.preventDefault();
|
|
|
|
handled = true;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case event.DOM_VK_RIGHT:
|
|
|
|
if (event.metaKey && event.altKey && !event.shiftKey &&
|
|
|
|
!event.ctrlKey)
|
|
|
|
if (tabbox.tabs && tabbox._handleMetaAltArrows) {
|
|
|
|
var forward =
|
|
|
|
window.getComputedStyle(tabbox, "").direction == "ltr" ? 1 : -1;
|
|
|
|
self.advanceSelectedTab(!forward);
|
|
|
|
event.stopPropagation();
|
|
|
|
event.preventDefault();
|
|
|
|
handled = true;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!handled) {
|
|
|
|
// ToDo: the "tabs" binding implements the nsIDOMXULSelectControlElement,
|
|
|
|
// we might need to rewrite the tabs without using the
|
|
|
|
// nsIDOMXULSelectControlElement.
|
|
|
|
// http://mxr.mozilla.org/mozilla1.9.2/source/toolkit/content/widgets/tabbox.xml#246
|
|
|
|
// The below handles the ctrl/meta + number key and prevent the default
|
|
|
|
// actions.
|
|
|
|
var isMac = (navigator.platform.search(/mac/i) > -1);
|
|
|
|
|
|
|
|
if ((isMac && event.metaKey) || (!isMac && event.ctrlKey)) {
|
|
|
|
var charCode = event.charCode;
|
|
|
|
// 1 to 9
|
|
|
|
if (48 < charCode && charCode < 58) {
|
|
|
|
self.advanceSelectedTab(false, (charCode - 48));
|
|
|
|
event.stopPropagation();
|
|
|
|
event.preventDefault();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}, false);
|
|
|
|
},
|
|
|
|
|
|
|
|
// ----------
|
|
|
|
advanceSelectedTab : function(reverse, index) {
|
|
|
|
var tabbox = Utils.getCurrentWindow().gBrowser.mTabBox;
|
|
|
|
var tabs = tabbox.tabs;
|
|
|
|
var visibleTabs = [];
|
|
|
|
var selectedIndex;
|
|
|
|
|
|
|
|
for (var i = 0; i < tabs.childNodes.length ; i++) {
|
|
|
|
var tab = tabs.childNodes[i];
|
|
|
|
if (!tab.collapsed) {
|
|
|
|
visibleTabs.push(tab);
|
|
|
|
if (tabs.selectedItem == tab) {
|
|
|
|
selectedIndex = (visibleTabs.length - 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// reverse should be false when index exists.
|
|
|
|
if (index && index > 0) {
|
|
|
|
if (visibleTabs.length > 1) {
|
|
|
|
if (visibleTabs.length >= index && index < 9) {
|
|
|
|
tabs.selectedItem = visibleTabs[index - 1];
|
|
|
|
} else {
|
|
|
|
tabs.selectedItem = visibleTabs[visibleTabs.length - 1];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (visibleTabs.length > 1) {
|
|
|
|
if (reverse) {
|
|
|
|
tabs.selectedItem =
|
|
|
|
(selectedIndex == 0) ? visibleTabs[visibleTabs.length - 1] :
|
|
|
|
visibleTabs[selectedIndex - 1]
|
|
|
|
} else {
|
|
|
|
tabs.selectedItem =
|
|
|
|
(selectedIndex == (visibleTabs.length - 1)) ? visibleTabs[0] :
|
|
|
|
visibleTabs[selectedIndex + 1];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2010-04-26 16:48:46 -07:00
|
|
|
// ----------
|
2010-05-21 19:51:34 -07:00
|
|
|
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.
|
2010-06-03 15:31:18 -07:00
|
|
|
var isAnimating = iQ.isAnimating();
|
2010-05-21 19:51:34 -07:00
|
|
|
if( force == false){
|
2010-07-03 09:08:34 -07:00
|
|
|
if( isAnimating || !Page.isTabCandyVisible() ) {
|
2010-06-28 14:56:20 -07:00
|
|
|
// TODO: should try again once the animation is done
|
|
|
|
// Actually, looks like iQ.isAnimating is non-functional;
|
|
|
|
// perhaps we should clean it out, or maybe we should fix it.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2010-07-03 18:41:31 -07:00
|
|
|
|
|
|
|
var oldPageBounds = new Rect(this.pageBounds);
|
|
|
|
var newPageBounds = Items.getPageBounds();
|
|
|
|
if (newPageBounds.equals(oldPageBounds))
|
|
|
|
return;
|
2010-05-21 01:05:55 -07:00
|
|
|
|
2010-04-26 16:48:46 -07:00
|
|
|
var items = Items.getTopLevelItems();
|
2010-07-03 18:41:31 -07:00
|
|
|
|
|
|
|
// compute itemBounds: the union of all the top-level items' bounds.
|
2010-07-06 16:22:57 -07:00
|
|
|
var itemBounds = new Rect(this.pageBounds); // We start with pageBounds so that we respect
|
|
|
|
// the empty space the user has left on the page.
|
2010-04-26 16:48:46 -07:00
|
|
|
itemBounds.width = 1;
|
|
|
|
itemBounds.height = 1;
|
2010-06-03 15:31:18 -07:00
|
|
|
iQ.each(items, function(index, item) {
|
2010-05-07 15:49:54 -07:00
|
|
|
if(item.locked.bounds)
|
2010-04-26 16:48:46 -07:00
|
|
|
return;
|
|
|
|
|
|
|
|
var bounds = item.getBounds();
|
|
|
|
itemBounds = (itemBounds ? itemBounds.union(bounds) : new Rect(bounds));
|
|
|
|
});
|
2010-05-21 15:44:15 -07:00
|
|
|
|
2010-05-24 17:14:10 -07:00
|
|
|
Groups.repositionNewTabGroup(); // TODO:
|
|
|
|
|
2010-07-03 18:41:31 -07:00
|
|
|
if (newPageBounds.width < this.pageBounds.width && newPageBounds.width > itemBounds.width)
|
2010-04-26 16:48:46 -07:00
|
|
|
newPageBounds.width = this.pageBounds.width;
|
|
|
|
|
2010-07-03 18:41:31 -07:00
|
|
|
if (newPageBounds.height < this.pageBounds.height && newPageBounds.height > itemBounds.height)
|
2010-04-26 16:48:46 -07:00
|
|
|
newPageBounds.height = this.pageBounds.height;
|
|
|
|
|
|
|
|
var wScale;
|
|
|
|
var hScale;
|
2010-07-03 18:41:31 -07:00
|
|
|
if ( Math.abs(newPageBounds.width - this.pageBounds.width)
|
|
|
|
> Math.abs(newPageBounds.height - this.pageBounds.height) ) {
|
2010-04-26 16:48:46 -07:00
|
|
|
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;
|
2010-05-07 15:49:54 -07:00
|
|
|
var pairs = [];
|
2010-06-03 15:31:18 -07:00
|
|
|
iQ.each(items, function(index, item) {
|
2010-05-07 15:49:54 -07:00
|
|
|
if(item.locked.bounds)
|
2010-04-26 16:48:46 -07:00
|
|
|
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;
|
|
|
|
|
2010-05-07 15:49:54 -07:00
|
|
|
pairs.push({
|
|
|
|
item: item,
|
|
|
|
bounds: bounds
|
|
|
|
});
|
2010-04-26 16:48:46 -07:00
|
|
|
});
|
|
|
|
|
2010-05-07 15:49:54 -07:00
|
|
|
Items.unsquish(pairs);
|
|
|
|
|
2010-06-03 15:31:18 -07:00
|
|
|
iQ.each(pairs, function(index, pair) {
|
2010-05-07 15:49:54 -07:00
|
|
|
pair.item.setBounds(pair.bounds, true);
|
2010-07-03 18:41:31 -07:00
|
|
|
pair.item.snap();
|
2010-05-07 15:49:54 -07:00
|
|
|
});
|
|
|
|
|
2010-04-26 16:48:46 -07:00
|
|
|
this.pageBounds = Items.getPageBounds();
|
2010-05-24 14:49:03 -07:00
|
|
|
this.save();
|
2010-04-26 16:48:46 -07:00
|
|
|
},
|
|
|
|
|
2010-04-30 17:24:03 -07:00
|
|
|
// ----------
|
|
|
|
addDevMenu: function() {
|
2010-07-06 14:53:40 -07:00
|
|
|
try {
|
|
|
|
var self = this;
|
2010-04-30 17:24:03 -07:00
|
|
|
|
2010-07-06 14:53:40 -07:00
|
|
|
var $select = iQ('<select>')
|
|
|
|
.css({
|
|
|
|
position: 'absolute',
|
2010-07-06 16:22:57 -07:00
|
|
|
top: 5,
|
2010-07-06 14:53:40 -07:00
|
|
|
right: 5,
|
|
|
|
opacity: .2
|
|
|
|
})
|
|
|
|
.appendTo('body')
|
|
|
|
.change(function () {
|
|
|
|
var index = iQ(this).val();
|
|
|
|
try {
|
|
|
|
commands[index].code.apply(commands[index].element);
|
|
|
|
} catch(e) {
|
|
|
|
Utils.log('dev menu error', e);
|
|
|
|
}
|
|
|
|
iQ(this).val(0);
|
|
|
|
});
|
|
|
|
|
|
|
|
var commands = [{
|
|
|
|
name: 'dev menu',
|
|
|
|
code: function() {
|
|
|
|
}
|
|
|
|
}, {
|
|
|
|
name: 'show trenches',
|
|
|
|
code: function() {
|
|
|
|
Trenches.toggleShown();
|
|
|
|
iQ(this).html((Trenches.showDebug ? 'hide' : 'show') + ' trenches');
|
|
|
|
}
|
|
|
|
}, {
|
|
|
|
name: 'refresh',
|
|
|
|
code: function() {
|
|
|
|
location.href = 'tabcandy.html';
|
|
|
|
}
|
|
|
|
}, {
|
|
|
|
name: 'code docs',
|
|
|
|
code: function() {
|
|
|
|
self.newTab('http://hg.mozilla.org/labs/tabcandy/raw-file/tip/content/doc/index.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++) {
|
|
|
|
commands[a].element = iQ('<option>')
|
|
|
|
.val(a)
|
|
|
|
.html(commands[a].name)
|
|
|
|
.appendTo($select)
|
|
|
|
.get(0);
|
2010-05-26 11:29:31 -07:00
|
|
|
}
|
2010-07-06 14:53:40 -07:00
|
|
|
} catch(e) {
|
|
|
|
Utils.log(e);
|
2010-04-30 17:24:03 -07:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2010-05-27 17:25:14 -07:00
|
|
|
// -----------
|
|
|
|
reset: function() {
|
|
|
|
Storage.wipe();
|
|
|
|
location.href = '';
|
|
|
|
},
|
|
|
|
|
2010-05-24 14:49:03 -07:00
|
|
|
// ----------
|
|
|
|
saveAll: function() {
|
|
|
|
this.save();
|
|
|
|
Groups.saveAll();
|
|
|
|
TabItems.saveAll();
|
|
|
|
},
|
|
|
|
|
2010-05-11 12:03:31 -07:00
|
|
|
// ----------
|
|
|
|
save: function() {
|
2010-05-24 14:49:03 -07:00
|
|
|
if(!this.initialized)
|
|
|
|
return;
|
|
|
|
|
2010-05-11 12:03:31 -07:00
|
|
|
var data = {
|
2010-05-24 14:49:03 -07:00
|
|
|
pageBounds: this.pageBounds
|
2010-05-11 12:03:31 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
if(this.storageSanity(data))
|
2010-05-24 14:49:03 -07:00
|
|
|
Storage.saveUIData(Utils.getCurrentWindow(), data);
|
2010-05-11 12:03:31 -07:00
|
|
|
},
|
|
|
|
|
2010-05-03 15:32:11 -07:00
|
|
|
// ----------
|
|
|
|
storageSanity: function(data) {
|
2010-06-03 15:31:18 -07:00
|
|
|
if(iQ.isEmptyObject(data))
|
2010-05-11 17:22:06 -07:00
|
|
|
return true;
|
|
|
|
|
2010-05-24 14:49:03 -07:00
|
|
|
if(!isRect(data.pageBounds)) {
|
|
|
|
Utils.log('UI.storageSanity: bad pageBounds', data.pageBounds);
|
|
|
|
data.pageBounds = null;
|
|
|
|
return false;
|
|
|
|
}
|
2010-05-11 12:03:31 -07:00
|
|
|
|
2010-05-24 14:49:03 -07:00
|
|
|
return true;
|
2010-05-03 15:32:11 -07:00
|
|
|
},
|
|
|
|
|
2010-04-22 17:19:42 -07:00
|
|
|
// ----------
|
2010-05-26 11:29:31 -07:00
|
|
|
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();
|
2010-04-14 17:12:06 -07:00
|
|
|
|
2010-05-26 11:29:31 -07:00
|
|
|
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 {
|
2010-04-14 17:12:06 -07:00
|
|
|
var domainParts = domain.split('.');
|
|
|
|
var mainDomain = domainParts[domainParts.length - 2];
|
|
|
|
if(groups[mainDomain])
|
2010-05-26 11:29:31 -07:00
|
|
|
groups[mainDomain].push(item.container);
|
2010-04-14 17:12:06 -07:00
|
|
|
else
|
2010-05-26 11:29:31 -07:00
|
|
|
groups[mainDomain] = [item.container];
|
2010-04-14 17:12:06 -07:00
|
|
|
}
|
|
|
|
});
|
2010-05-26 11:29:31 -07:00
|
|
|
|
|
|
|
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();
|
2010-06-29 14:39:37 -07:00
|
|
|
},
|
2010-04-16 15:09:23 -07:00
|
|
|
|
|
|
|
// ----------
|
2010-06-29 14:39:37 -07:00
|
|
|
newTab: function(url) {
|
|
|
|
try {
|
|
|
|
var group = Groups.getNewTabGroup();
|
|
|
|
if(group)
|
|
|
|
group.newTab(url);
|
|
|
|
else
|
|
|
|
Tabs.open(url);
|
|
|
|
} catch(e) {
|
|
|
|
Utils.log(e);
|
|
|
|
}
|
2010-02-24 01:47:55 -08:00
|
|
|
}
|
2010-04-14 17:12:06 -07:00
|
|
|
};
|
2010-02-24 01:47:55 -08:00
|
|
|
|
2010-04-14 17:12:06 -07:00
|
|
|
// ----------
|
|
|
|
window.UI = new UIClass();
|
2010-02-24 01:47:55 -08:00
|
|
|
|
|
|
|
})();
|