mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-01 14:45:29 +00:00
+ Removed unnecessary margin and padding from tabs and groups (was messing up layout)
+ Now compensating for padding in tabs when laying them out + Tab titles are now a single line, cut at the width of the tab (but no ellipsis yet) + Groups now have the move cursor + Tab resizing now works, and is disabled when a tab is in a group + We now have a "new tabs" group that new tabs go into (created as needed) + New layout algorithm for tabs inside a group. It's not as space efficient as the last one, but the unused space is at the bottom rather than the right side, and in general I think it behaves more like people expect. + Groups now have a minimum width when resizing + If you drag the second to last tab out of a group and don't return it to that group, the group now dissolves. + When a tab gets below a certain size, its thumbnail and close box are hidden + When a tab's title gets below a certain size, it is hidden.
This commit is contained in:
parent
3a944f5cd5
commit
6951057a1c
@ -33,6 +33,7 @@ window.Group = function(listOfEls, options) {
|
||||
this._children = []; // an array of Items
|
||||
this._padding = 30;
|
||||
this.defaultSize = new Point(TabItems.tabWidth * 1.5, TabItems.tabHeight * 1.5);
|
||||
this.title = '';
|
||||
|
||||
var self = this;
|
||||
|
||||
@ -199,7 +200,7 @@ window.Group.prototype = $.extend(new Item(), new Subscribable(), {
|
||||
// ___ Deal with children
|
||||
if(this._children.length) {
|
||||
if(css.width || css.height) {
|
||||
this.arrange({animate: !immediately});
|
||||
this.arrange({animate: !immediately}); //(immediately ? 'sometimes' : true)});
|
||||
} else if(css.left || css.top) {
|
||||
$.each(this._children, function(index, child) {
|
||||
var box = child.getBounds();
|
||||
@ -229,6 +230,10 @@ window.Group.prototype = $.extend(new Item(), new Subscribable(), {
|
||||
// ----------
|
||||
setZ: function(value) {
|
||||
$(this.container).css({zIndex: value});
|
||||
|
||||
if(this.$debug)
|
||||
this.$debug.css({zIndex: value + 1});
|
||||
|
||||
$.each(this._children, function(index, child) {
|
||||
child.setZ(value + 1);
|
||||
});
|
||||
@ -294,6 +299,7 @@ window.Group.prototype = $.extend(new Item(), new Subscribable(), {
|
||||
|
||||
$el.droppable("disable");
|
||||
item.setZ(this.getZ() + 1);
|
||||
item.groupData = {};
|
||||
|
||||
item.addOnClose(this, function() {
|
||||
self.remove($el);
|
||||
@ -360,59 +366,71 @@ window.Group.prototype = $.extend(new Item(), new Subscribable(), {
|
||||
|
||||
// ----------
|
||||
arrange: function(options) {
|
||||
if( options && options.animate == false )
|
||||
animate = false;
|
||||
else
|
||||
var animate;
|
||||
if(!options || typeof(options.animate) == 'undefined')
|
||||
animate = true;
|
||||
else
|
||||
animate = options.animate;
|
||||
|
||||
if(typeof(options) == 'undefined')
|
||||
options = {};
|
||||
|
||||
var bb = this.getContentBounds();
|
||||
bb.inset(6, 6);
|
||||
|
||||
var tabAspect = TabItems.tabHeight / TabItems.tabWidth;
|
||||
var count = this._children.length;
|
||||
if(!count)
|
||||
return;
|
||||
|
||||
var columns = 1;
|
||||
var padding = 0;
|
||||
var rows;
|
||||
var tabWidth;
|
||||
var tabHeight;
|
||||
|
||||
var count = this._children.length;
|
||||
var bbAspect = bb.width/bb.height;
|
||||
var tabAspect = 4/3;
|
||||
function figure() {
|
||||
rows = Math.ceil(count / columns);
|
||||
tabWidth = (bb.width / columns) - padding;
|
||||
tabHeight = tabWidth * tabAspect;
|
||||
}
|
||||
|
||||
function howManyColumns( numRows, count ){ return Math.ceil(count/numRows) }
|
||||
figure();
|
||||
|
||||
var count = this._children.length;
|
||||
var best = {cols: 0, rows:0, area:0};
|
||||
for(var numRows=1; numRows<=count; numRows++){
|
||||
numCols = howManyColumns( numRows, count);
|
||||
var w = numCols*tabAspect;
|
||||
var h = numRows;
|
||||
while(rows > 1 && tabHeight * rows > bb.height) {
|
||||
columns++;
|
||||
figure();
|
||||
}
|
||||
|
||||
if(rows == 1) {
|
||||
tabWidth = Math.min(bb.width / count, bb.height / tabAspect);
|
||||
tabHeight = tabWidth * tabAspect;
|
||||
}
|
||||
|
||||
var box = new Rect(bb.left, bb.top, tabWidth, tabHeight);
|
||||
var row = 0;
|
||||
var column = 0;
|
||||
var immediately;
|
||||
|
||||
$.each(this._children, function(index, child) {
|
||||
if(animate == 'sometimes')
|
||||
immediately = (typeof(child.groupData.row) == 'undefined' || child.groupData.row == row);
|
||||
else
|
||||
immediately = !animate;
|
||||
|
||||
child.setBounds(box, immediately);
|
||||
child.groupData.column = column;
|
||||
child.groupData.row = row;
|
||||
|
||||
// We are width constrained
|
||||
if( w/bb.width >= h/bb.height ) var scale = bb.width/w;
|
||||
// We are height constrained
|
||||
else var scale = bb.height/h;
|
||||
var w = w*scale;
|
||||
var h = h*scale;
|
||||
|
||||
if( w*h >= best.area ){
|
||||
best.numRows = numRows;
|
||||
best.numCols = numCols;
|
||||
best.area = w*h;
|
||||
best.w = w;
|
||||
best.h = h;
|
||||
box.left += box.width + padding;
|
||||
column++;
|
||||
if(column == columns) {
|
||||
box.left = bb.left;
|
||||
box.top += box.height + padding;
|
||||
column = 0;
|
||||
row++;
|
||||
}
|
||||
}
|
||||
|
||||
var padAmount = .15;
|
||||
var pad = padAmount * (best.w/best.numCols);
|
||||
var tabW = (best.w-pad)/best.numCols - pad;
|
||||
var tabH = (best.h-pad)/best.numRows - pad;
|
||||
|
||||
var x = pad*2; var y=pad; var numInCol = 0;
|
||||
for each(var item in this._children){
|
||||
item.setBounds(new Rect(x + bb.left, y + bb.top, tabW, tabH), !animate);
|
||||
|
||||
x += tabW + pad;
|
||||
numInCol += 1;
|
||||
if( numInCol >= best.numCols )
|
||||
[x, numInCol, y] = [pad*2, 0, y+tabH+pad];
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// ----------
|
||||
@ -459,6 +477,8 @@ window.Group.prototype = $.extend(new Item(), new Subscribable(), {
|
||||
$(this.container).resizable({
|
||||
handles: "se",
|
||||
aspectRatio: false,
|
||||
minWidth: 60,
|
||||
minHeight: 90,
|
||||
resize: function(){
|
||||
self.reloadBounds();
|
||||
},
|
||||
@ -479,6 +499,7 @@ var DragInfo = function(element) {
|
||||
this.el = element;
|
||||
this.$el = $(this.el);
|
||||
this.item = Items.item(this.el);
|
||||
this.parent = this.$el.data('group');
|
||||
|
||||
this.$el.data('isDragging', true);
|
||||
this.item.setZ(9999);
|
||||
@ -493,6 +514,10 @@ DragInfo.prototype = {
|
||||
// ----------
|
||||
stop: function() {
|
||||
this.$el.data('isDragging', false);
|
||||
|
||||
if(this.parent && this.parent != this.$el.data('group') && this.parent._children.length <= 1)
|
||||
this.parent.remove(this.parent._children[0]);
|
||||
|
||||
if(this.item && !this.$el.hasClass('willGroup') && !this.$el.data('group')) {
|
||||
this.item.setZ(drag.zIndex);
|
||||
drag.zIndex++;
|
||||
@ -620,6 +645,24 @@ window.Groups = {
|
||||
$.each(toRemove, function(index, group) {
|
||||
group.removeAll();
|
||||
});
|
||||
},
|
||||
|
||||
// ----------
|
||||
newTab: function(tabItem) {
|
||||
var groupTitle = 'New Tabs';
|
||||
var array = jQuery.grep(this.groups, function(group) {
|
||||
return group.title == groupTitle;
|
||||
});
|
||||
|
||||
var $el = $(tabItem.container);
|
||||
if(array.length)
|
||||
array[0].add($el);
|
||||
else {
|
||||
var p = Page.findOpenSpaceFor($el); // TODO shouldn't know about Page
|
||||
tabItem.setPosition(p.x, p.y, true);
|
||||
var group = new Group([$el]);
|
||||
group.title = groupTitle;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -3,6 +3,7 @@ window.TabItem = function(container, tab) {
|
||||
this._init(container);
|
||||
this.tab = tab;
|
||||
this.defaultSize = new Point(TabItems.tabWidth, TabItems.tabHeight);
|
||||
this.setResizable(true);
|
||||
};
|
||||
|
||||
window.TabItem.prototype = $.extend(new Item(), {
|
||||
@ -14,6 +15,10 @@ window.TabItem.prototype = $.extend(new Item(), {
|
||||
|
||||
// ----------
|
||||
setBounds: function(rect, immediately) {
|
||||
var $container = $(this.container);
|
||||
var $title = $('.tab-title', $container);
|
||||
var $thumb = $('.thumb', $container);
|
||||
var $close = $('.close', $container);
|
||||
var css = {};
|
||||
|
||||
if(rect.left != this.bounds.left)
|
||||
@ -23,13 +28,20 @@ window.TabItem.prototype = $.extend(new Item(), {
|
||||
css.top = rect.top;
|
||||
|
||||
if(rect.width != this.bounds.width) {
|
||||
css.width = rect.width;
|
||||
var scale = rect.width / TabItems.tabWidth;
|
||||
var widthExtra = parseInt($container.css('padding-left'))
|
||||
+ parseInt($container.css('padding-right'));
|
||||
|
||||
css.width = rect.width - widthExtra;
|
||||
var scale = css.width / TabItems.tabWidth;
|
||||
css.fontSize = TabItems.fontSize * scale;
|
||||
}
|
||||
|
||||
if(rect.height != this.bounds.height)
|
||||
css.height = rect.height;
|
||||
if(rect.height != this.bounds.height) {
|
||||
var heightExtra = parseInt($container.css('padding-top'))
|
||||
+ parseInt($container.css('padding-bottom'));
|
||||
|
||||
css.height = rect.height - heightExtra;
|
||||
}
|
||||
|
||||
if($.isEmptyObject(css))
|
||||
return;
|
||||
@ -37,14 +49,40 @@ window.TabItem.prototype = $.extend(new Item(), {
|
||||
this.bounds.copy(rect);
|
||||
|
||||
if(immediately) {
|
||||
$(this.container).css(css);
|
||||
$container.css(css);
|
||||
|
||||
/*
|
||||
if(css.fontSize) {
|
||||
if(css.fontSize < 8)
|
||||
$title.hide();
|
||||
else
|
||||
$title.show();
|
||||
}
|
||||
*/
|
||||
} else {
|
||||
TabMirror.pausePainting();
|
||||
$(this.container).animate(css, {complete: function() {
|
||||
$container.animate(css, {complete: function() {
|
||||
TabMirror.resumePainting();
|
||||
}}).dequeue();
|
||||
}
|
||||
|
||||
if(css.fontSize) {
|
||||
if(css.fontSize < 8)
|
||||
$title.fadeOut();
|
||||
else
|
||||
$title.fadeIn();
|
||||
}
|
||||
|
||||
if(css.width) {
|
||||
if(css.width < 30) {
|
||||
$thumb.fadeOut();
|
||||
$close.fadeOut();
|
||||
} else {
|
||||
$thumb.fadeIn();
|
||||
$close.fadeIn();
|
||||
}
|
||||
}
|
||||
|
||||
this._updateDebugBounds();
|
||||
},
|
||||
|
||||
@ -66,11 +104,38 @@ window.TabItem.prototype = $.extend(new Item(), {
|
||||
// ----------
|
||||
removeOnClose: function(referenceObject) {
|
||||
this.tab.mirror.removeOnClose(referenceObject);
|
||||
},
|
||||
|
||||
// ----------
|
||||
setResizable: function(value){
|
||||
var self = this;
|
||||
|
||||
var $resizer = $('.expander', this.container);
|
||||
if(value) {
|
||||
$resizer.fadeIn();
|
||||
$(this.container).resizable({
|
||||
handles: "se",
|
||||
aspectRatio: true,
|
||||
minWidth: TabItems.minTabWidth,
|
||||
minHeight: TabItems.minTabWidth * (TabItems.tabHeight / TabItems.tabWidth),
|
||||
resize: function(){
|
||||
self.reloadBounds();
|
||||
},
|
||||
stop: function(){
|
||||
self.reloadBounds();
|
||||
self.pushAway();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
$resizer.fadeOut();
|
||||
$(this.container).resizable('destroy');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// ##########
|
||||
window.TabItems = {
|
||||
minTabWidth: 40,
|
||||
tabWidth: 160,
|
||||
tabHeight: 120,
|
||||
fontSize: 9,
|
||||
@ -149,19 +214,14 @@ window.TabItems = {
|
||||
$("<div class='close'></div>").appendTo($div);
|
||||
$("<div class='expander'></div>").appendTo($div);
|
||||
|
||||
function onNewTab(){
|
||||
var p = Page.findOpenSpaceFor($div); // TODO shouldn't know about Page
|
||||
$div.css({left: p.x, top: p.y, width:TabItems.tabWidth, height:TabItems.tabHeight});
|
||||
}
|
||||
|
||||
// This code deals with adding a new tab.
|
||||
if($div.length == 1) onNewTab();
|
||||
|
||||
$div.each(function() {
|
||||
var tab = Tabs.tab(this);
|
||||
$(this).data('tabItem', new TabItem(this, tab));
|
||||
});
|
||||
|
||||
if($div.length == 1)
|
||||
Groups.newTab($div.data('tabItem'));
|
||||
|
||||
// TODO: Figure out this really weird bug?
|
||||
// Why is that:
|
||||
// $div.find("canvas").data("link").tab.url
|
||||
|
@ -52,6 +52,8 @@ TabCanvas.prototype = {
|
||||
|
||||
var w = $canvas.attr('width');
|
||||
var h = $canvas.attr('height');
|
||||
if(!w || !h)
|
||||
return;
|
||||
|
||||
var fromWin = this.tab.contentWindow;
|
||||
if(fromWin == null) {
|
||||
@ -123,8 +125,6 @@ function Mirror(tab, manager) {
|
||||
if( this.tab.url.match("chrome:") )
|
||||
div.hide();
|
||||
|
||||
this.manager._customize(div);
|
||||
|
||||
this.needsPaint = 0;
|
||||
this.canvasSizeForced = false;
|
||||
this.el = div.get(0);
|
||||
@ -138,6 +138,9 @@ function Mirror(tab, manager) {
|
||||
this.tabCanvas.attach();
|
||||
this.triggerPaint();
|
||||
}
|
||||
|
||||
this.tab.mirror = this;
|
||||
this.manager._customize(div);
|
||||
}
|
||||
|
||||
Mirror.prototype = $.extend(new Subscribable(), {
|
||||
@ -259,7 +262,7 @@ TabMirror.prototype = {
|
||||
},
|
||||
|
||||
_createEl: function(tab){
|
||||
tab.mirror = new Mirror(tab, this);
|
||||
new Mirror(tab, this); // sets tab.mirror to itself
|
||||
},
|
||||
|
||||
update: function(tab){
|
||||
|
@ -147,8 +147,8 @@ window.Subscribable.prototype = {
|
||||
return element.referenceElement == referenceElement;
|
||||
});
|
||||
|
||||
if(existing.size) {
|
||||
Utils.assert('should only ever be one', existing.size == 1);
|
||||
if(existing.length) {
|
||||
Utils.assert('should only ever be one', existing.length == 1);
|
||||
existing[0].callback = callback;
|
||||
} else {
|
||||
this.onCloseSubscribers.push({
|
||||
|
@ -1,9 +1,4 @@
|
||||
html {
|
||||
padding-bottom: 20px;
|
||||
padding-top: 20px;
|
||||
padding-left: 20px;
|
||||
padding-right: 20px;
|
||||
|
||||
}
|
||||
|
||||
body {
|
||||
@ -22,7 +17,6 @@ body {
|
||||
|
||||
.tab {
|
||||
position: absolute;
|
||||
margin: 10px;
|
||||
padding: 4px 6px 6px 4px;
|
||||
border: 1px solid rgba(230,230,230,1);
|
||||
background-color: rgba(245,245,245,1);
|
||||
@ -110,6 +104,8 @@ body {
|
||||
text-align: center;
|
||||
text-shadow: rgba(255,255,255,1) 0 1px;
|
||||
width: 94.5%;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
|
||||
@ -129,8 +125,7 @@ body {
|
||||
.group {
|
||||
position: relative;
|
||||
float: left;
|
||||
margin: 20px;
|
||||
padding: 10px 10px 30px 10px;
|
||||
cursor: move;
|
||||
border: 1px solid rgba(230,230,230,1);
|
||||
background-color: rgba(245,245,245,1);
|
||||
-moz-border-radius: 0.4em;
|
||||
@ -144,20 +139,6 @@ body {
|
||||
.group .expander {
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
.group {
|
||||
cursor: move;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.group-content {
|
||||
border: 1px inset rgba(0,0,0,.3);
|
||||
background-color: white;
|
||||
-moz-box-shadow: inset 2px 2px 12px rgba(0,0,0,.15);
|
||||
}
|
||||
*/
|
||||
|
||||
// -----------------------------------------------------
|
||||
// Other
|
||||
// -----------------------------------------------------
|
||||
@ -198,7 +179,7 @@ input.name{
|
||||
opacity: .2;
|
||||
}
|
||||
|
||||
.ui-resizable { position: relative;}
|
||||
.ui-resizable { }
|
||||
.ui-resizable-handle { position: absolute;font-size: 0.1px;z-index: 99999; display: block;}
|
||||
.ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; }
|
||||
.ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; }
|
||||
|
Loading…
Reference in New Issue
Block a user