+ Added the concept of the "focused" tab.

+ The last tab you were viewing is now highlighted as the focused tab.
+ You can get back to the tab you were looking at now by hitting the escape key.
+ You can navigate to the focused tab by hitting the return key.
+ You can select other tabs via the keyboard with the arrow keys.
This commit is contained in:
Aza Raskin 2010-05-12 19:56:35 -07:00
parent ad1dfd1097
commit cc60577ba9
4 changed files with 180 additions and 64 deletions

View File

@ -971,6 +971,15 @@ var DragInfo = function(element, event) {
};
DragInfo.prototype = {
// ----------
snap: function(event, ui){
window.console.log( event, ui);
// Step 1: Find the closest group by edge
// Step 2: Match to the to
},
// ----------
drag: function(event, ui) {
if(this.item.isAGroup) {
@ -1035,6 +1044,7 @@ window.Groups = {
},
drag: function(e, ui) {
drag.info.drag(e, ui);
},
stop: function() {
drag.info.stop();

View File

@ -199,6 +199,23 @@ window.TabItem.prototype = $.extend(new Item(), {
$resizer.fadeOut();
$(this.container).resizable('destroy');
}
},
// ----------
makeActive: function(){
$(this.container).find("canvas").addClass("focus")
},
// ----------
makeDeactive: function(){
$(this.container).find("canvas").removeClass("focus")
},
// ----------
// Function: zoom
// Zooms into this tab thereby allowing you to interact with it.
zoom: function(){
TabItems.zoomTo(this.container);
}
});
@ -235,66 +252,7 @@ window.TabItems = {
$(this).find("canvas").data("link").tab.close(); }
else {
if(!$(this).data('isDragging')) {
var item = $(this).data('tabItem');
var childHitResult = { shouldZoom: true };
if(item.parent)
childHitResult = item.parent.childHit(item);
if(childHitResult.shouldZoom) {
// Zoom in!
var orig = {
width: $(this).width(),
height: $(this).height(),
pos: $(this).position()
}
var scale = window.innerWidth/orig.width;
var tab = Tabs.tab(this);
var mirror = tab.mirror;
var overflow = $("body").css("overflow");
$("body").css("overflow", "hidden");
function onZoomDone(){
UI.tabBar.show(false);
TabMirror.resumePainting();
$(this).find("canvas").data("link").tab.focus();
$(this).css({
top: orig.pos.top,
left: orig.pos.left,
width: orig.width,
height:orig.height,
})
.removeClass("front");
Navbar.show();
// If the tab is in a group set then set the active
// group to the tab's parent.
if( self.getItemByTab(this).parent ){
var gID = self.getItemByTab(this).parent.id;
var group = Groups.group(gID);
Groups.setActiveGroup( group );
}
else
Groups.setActiveGroup( null );
$("body").css("overflow", overflow);
if(childHitResult.callback)
childHitResult.callback();
}
TabMirror.pausePainting();
$(this)
.addClass("front")
.animate({
top: -10,
left: 0,
width: orig.width*scale,
height: orig.height*scale
}, 200, "easeInQuad", onZoomDone);
}
self.zoomTo(this);
} else {
$(this).find("canvas").data("link").tab.raw.pos = $(this).position();
}
@ -352,6 +310,76 @@ window.TabItems = {
window.TabMirror.customize(mod);
},
// ----------
// Function: zoomTo(container)
// Given the containing element of a tab, allows you to
// select that tab and zoom in on it, thereby bringing you
// to the tab in Firefox to interact with.
//
zoomTo: function(tabEl){
var self = this;
var item = $(tabEl).data('tabItem');
var childHitResult = { shouldZoom: true };
if(item.parent)
childHitResult = item.parent.childHit(item);
if(childHitResult.shouldZoom) {
// Zoom in!
var orig = {
width: $(tabEl).width(),
height: $(tabEl).height(),
pos: $(tabEl).position()
}
var scale = window.innerWidth/orig.width;
var tab = Tabs.tab(tabEl);
var mirror = tab.mirror;
var overflow = $("body").css("overflow");
$("body").css("overflow", "hidden");
function onZoomDone(){
UI.tabBar.show(false);
TabMirror.resumePainting();
$(tabEl).find("canvas").data("link").tab.focus();
$(tabEl).css({
top: orig.pos.top,
left: orig.pos.left,
width: orig.width,
height:orig.height,
})
.removeClass("front");
Navbar.show();
// If the tab is in a group set then set the active
// group to the tab's parent.
if( self.getItemByTab(tabEl).parent ){
var gID = self.getItemByTab(tabEl).parent.id;
var group = Groups.group(gID);
Groups.setActiveGroup( group );
}
else
Groups.setActiveGroup( null );
$("body").css("overflow", overflow);
if(childHitResult.callback)
childHitResult.callback();
}
TabMirror.pausePainting();
$(tabEl)
.addClass("front")
.animate({
top: -10,
left: 0,
width: orig.width*scale,
height: orig.height*scale
}, 200, "easeInQuad", onZoomDone);
}
},
// ----------
getItems: function() {

View File

@ -149,9 +149,57 @@ window.Page = {
Utils.homeTab.focus();
UI.tabBar.hide(false);
},
setupKeyHandlers: function(){
var self = this;
$(window).keydown(function(e){
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]);
});
return matches[0][1];
}
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;
}
if( norm != null ){
var nextTab = getClosestTabBy(norm);
self.setActiveTab(nextTab);
e.preventDefault();
}
});
$(window).keyup(function(e){
// If you hit escape or return, zoom into the active tab.
if(e.which == 27 || e.which == 13)
if( self.getActiveTab() ) self.getActiveTab().zoom();
});
},
// ----------
init: function() {
init: function() {
var self = this;
Utils.homeTab.raw.maxWidth = 60;
Utils.homeTab.raw.minWidth = 60;
@ -162,6 +210,7 @@ window.Page = {
Page.createGroupOnDrag(e)
})
this.setupKeyHandlers();
Tabs.onClose(function(){
// Only go back to the TabCandy tab when there you close the last
@ -179,7 +228,7 @@ window.Page = {
return false;
});
var lastTab = null;
Tabs.onFocus(function(){
// If we switched to TabCandy window...
@ -192,6 +241,7 @@ window.Page = {
// its mirror for the zoom out.
// Zoom out!
var $tab = $(lastTab.mirror.el);
self.setActiveTab($(lastTab.mirror.el).data().tabItem);
var rotation = $tab.css("-moz-transform");
var [w,h, pos, z] = [$tab.width(), $tab.height(), $tab.position(), $tab.css("zIndex")];
@ -286,6 +336,30 @@ window.Page = {
$("html").mousemove(updateSize)
$("html").one('mouseup',finalize);
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.
// Hiting 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( this._activeTab ) this._activeTab.makeDeactive();
this._activeTab = tab;
tab.makeActive();
},
// ----------
// Function: getActiveTab
// Returns the currently active tab as a <TabItem>
//
getActiveTab: function(){
return this._activeTab;
}
}

View File

@ -6,8 +6,8 @@ html {
body {
font-family: Tahoma, sans-serif !important;
padding: 0px;
background-color: rgba(240,240,240,1);
color: rgba(0,0,0,0.4);;
background-color: rgba(233,233,233,1);
color: rgba(0,0,0,0.4);
font-size:12px;
line-height: 16px;
margin: 0 auto;
@ -132,6 +132,10 @@ body {
}
.stack-trayed .thumb{ -moz-box-shadow: none !important;}
.focus{
-moz-box-shadow: rgba(54,79,225,1) 0px 0px 5px !important;
}
/* Tab Group
----------------------------------*/