From d54682ea3a68694dec580c8dee682dd02320169d Mon Sep 17 00:00:00 2001 From: Ian Gilman Date: Wed, 14 Apr 2010 17:12:06 -0700 Subject: [PATCH] + added the title and close box back to groups, with some basic styling + the "new tab" group now always lives at the bottom of the page + the candy switcher and the "grid" and "sites" features are now hidden by default. add ?dev=1 to the url to show them + the Firefox nav bar is now hidden when you're in the tab candy page + the starting grid now scales depending on how many tabs you have. (it is in fact sharing the arrange code that groups use for their children) --- browser/base/content/tabcandy/app/groups.js | 149 ++++++---------- browser/base/content/tabcandy/app/items.js | 81 +++++++++ browser/base/content/tabcandy/app/tabitems.js | 13 +- browser/base/content/tabcandy/app/ui.js | 168 ++++++++++-------- .../pinstripe/browser/tabcandy/tabcandy.css | 10 +- content/candies/revision-a/index.html | 6 +- 6 files changed, 243 insertions(+), 184 deletions(-) diff --git a/browser/base/content/tabcandy/app/groups.js b/browser/base/content/tabcandy/app/groups.js index c3bb4906dbb..c55beaf1070 100644 --- a/browser/base/content/tabcandy/app/groups.js +++ b/browser/base/content/tabcandy/app/groups.js @@ -31,20 +31,21 @@ window.Group = function(listOfEls, options) { 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; - var boundingBox = this._getBoundingBox(listOfEls); - var padding = 30; - var rectToBe = new Rect( - boundingBox.left-padding, - boundingBox.top-padding, - boundingBox.width+padding*2, - boundingBox.height+padding*2 - ); + var rectToBe = options.bounds; + if(!rectToBe) { + var boundingBox = this._getBoundingBox(listOfEls); + var padding = 30; + rectToBe = new Rect( + boundingBox.left-padding, + boundingBox.top-padding, + boundingBox.width+padding*2, + boundingBox.height+padding*2 + ); + } var $container = options.container; if(!$container) { @@ -69,9 +70,13 @@ window.Group = function(listOfEls, options) { .hide(); // ___ Titlebar - this.$titlebar = $("
x
") - .appendTo($container) - + var html = "
"; + + this.$titlebar = $(html) + .appendTo($container); + this.$titlebar.css({ position: "absolute", }); @@ -79,23 +84,8 @@ window.Group = function(listOfEls, options) { $('.close', this.$titlebar).click(function() { self.close(); }); - - // On delay, show the title bar. - var shouldShow = false; - $container.mouseover(function(){ - shouldShow = true; - setTimeout(function(){ - if( shouldShow == false ) return; - $container.find("input").focus(); - self.$titlebar - .css({width: $container.width()}) - .animate({ opacity: 1}).dequeue(); - }, 500); - }).mouseout(function(e){ - shouldShow = false; - if( isEventOverElement(e, $container.get(0) )) return; - self.$titlebar.animate({opacity:0}).dequeue(); - }) + + this.$title = $('.name', this.$titlebar); // ___ Content this.$content = $('
') @@ -132,6 +122,16 @@ window.Group = function(listOfEls, options) { // ---------- window.Group.prototype = $.extend(new Item(), new Subscribable(), { + // ---------- + getTitle: function() { + return (this.$title ? this.$title.val() : ''); + }, + + // ---------- + setValue: function(value) { + this.$title.val(value); + }, + // ---------- _getBoundingBox: function(els) { var el; @@ -366,71 +366,10 @@ window.Group.prototype = $.extend(new Item(), new Subscribable(), { // ---------- arrange: function(options) { - 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; - function figure() { - rows = Math.ceil(count / columns); - tabWidth = (bb.width / columns) - padding; - tabHeight = tabWidth * tabAspect; - } - - figure(); - - 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; - - box.left += box.width + padding; - column++; - if(column == columns) { - box.left = bb.left; - box.top += box.height + padding; - column = 0; - row++; - } - }); + Items.arrange(this._children, bb, options); }, // ---------- @@ -601,6 +540,21 @@ window.Groups = { } }, + // ---------- + init: function() { + var self = this; + setTimeout(function() { + // we do this in a timeout, as window.innerHeight hasn't adjusted for Firebug initially + var pad = 5; + var sw = window.innerWidth; + var sh = window.innerHeight; + var w = sw - (pad * 2); + var h = TabItems.tabHeight; + var box = new Rect(pad, sh - (h + pad), w, h); + self.newTabGroup = new Group([], {bounds: box, title: 'New Tabs'}); + }, 1000); + }, + // ---------- register: function(group) { Utils.assert('only register once per group', $.inArray(group, this.groups) == -1); @@ -651,21 +605,18 @@ window.Groups = { newTab: function(tabItem) { var groupTitle = 'New Tabs'; var array = jQuery.grep(this.groups, function(group) { - return group.title == groupTitle; + return group.getTitle() == 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; - } } }; +// ---------- +Groups.init(); + // ########## $(".tab").data('isDragging', false) .draggable(window.Groups.dragOptions) diff --git a/browser/base/content/tabcandy/app/items.js b/browser/base/content/tabcandy/app/items.js index 4d5f26289a0..4113ecaf370 100644 --- a/browser/base/content/tabcandy/app/items.js +++ b/browser/base/content/tabcandy/app/items.js @@ -219,6 +219,87 @@ window.Items = { }); return items; + }, + + // ---------- + // Function: arrange + // Arranges the given items in a grid within the given bounds, + // maximizing item size but maintaining standard tab aspect ratio for each + // + // Parameters: + // items - an array of s + // bounds - a defining the space to arrange within + // options - an object with options. If options.animate is false, doesn't animate, otherwise it does. + arrange: function(items, bounds, options) { + var animate; + if(!options || typeof(options.animate) == 'undefined') + animate = true; + else + animate = options.animate; + + if(typeof(options) == 'undefined') + options = {}; + + var tabAspect = TabItems.tabHeight / TabItems.tabWidth; + var count = items.length; + if(!count) + return; + + var columns = 1; + var padding = options.padding || 0; + var yScale = 1.1; // to allow for titles + var rows; + var tabWidth; + var tabHeight; + var totalHeight; + + function figure() { + rows = Math.ceil(count / columns); + tabWidth = (bounds.width - (padding * (columns - 1))) / columns; + tabHeight = tabWidth * tabAspect; + totalHeight = (tabHeight * yScale * rows) + (padding * (rows - 1)); + } + + figure(); + + while(rows > 1 && totalHeight > bounds.height) { + columns++; + figure(); + } + + if(rows == 1) { + tabWidth = Math.min(bounds.width / count, bounds.height / tabAspect); + tabHeight = tabWidth * tabAspect; + } + + var box = new Rect(bounds.left, bounds.top, tabWidth, tabHeight); + var row = 0; + var column = 0; + var immediately; + + $.each(items, function(index, item) { +/* + if(animate == 'sometimes') + immediately = (typeof(item.groupData.row) == 'undefined' || item.groupData.row == row); + else +*/ + immediately = !animate; + + item.setBounds(box, immediately); +/* + item.groupData.column = column; + item.groupData.row = row; +*/ + + box.left += box.width + padding; + column++; + if(column == columns) { + box.left = bounds.left; + box.top += (box.height * yScale) + padding; + column = 0; + row++; + } + }); } }; diff --git a/browser/base/content/tabcandy/app/tabitems.js b/browser/base/content/tabcandy/app/tabitems.js index 5b4926242a5..cbb476f5842 100644 --- a/browser/base/content/tabcandy/app/tabitems.js +++ b/browser/base/content/tabcandy/app/tabitems.js @@ -214,13 +214,24 @@ window.TabItems = { $("
").appendTo($div); $("
").appendTo($div); + var items = []; $div.each(function() { var tab = Tabs.tab(this); - $(this).data('tabItem', new TabItem(this, tab)); + var item = new TabItem(this, tab); + $(this).data('tabItem', item); + items.push(item); }); if($div.length == 1) Groups.newTab($div.data('tabItem')); + else { + var top = 20; + var bottom = TabItems.tabHeight + 10; // MAGIC NUMBER: giving room for the "new tabs" group + var box = new Rect(0, top, window.innerWidth, window.innerHeight - (top + bottom)); + box.inset(20, 20); + + Items.arrange(items, box, {padding: 10}); + } // TODO: Figure out this really weird bug? // Why is that: diff --git a/browser/base/content/tabcandy/app/ui.js b/browser/base/content/tabcandy/app/ui.js index 8d3556e9996..dcd3f80d9c3 100644 --- a/browser/base/content/tabcandy/app/ui.js +++ b/browser/base/content/tabcandy/app/ui.js @@ -23,6 +23,7 @@ window.Page = { startX: 30, startY: 70, + // ---------- init: function() { Utils.homeTab.raw.maxWidth = 60; Utils.homeTab.raw.minWidth = 60; @@ -77,6 +78,7 @@ window.Page = { ); }, + // ---------- findOpenSpaceFor: function($div) { var w = window.innerWidth; var h = 0; @@ -162,8 +164,7 @@ window.Page = { } } - -//---------------------------------------------------------- +// ########## function ArrangeClass(name, func){ this.init(name, func); }; ArrangeClass.prototype = { init: function(name, func){ @@ -177,90 +178,107 @@ ArrangeClass.prototype = { } } - -//---------------------------------------------------------- -var grid = new ArrangeClass("Grid", function(value) { - if(typeof(Groups) != 'undefined') - Groups.removeAll(); - - var immediately = false; - if(typeof(value) == 'boolean') - immediately = value; - - var box = new Rect(Page.startX, Page.startY, TabItems.tabWidth, TabItems.tabHeight); - $(".tab:visible").each(function(i){ - var item = Items.item(this); - item.setBounds(box, immediately); - - box.left += box.width + 30; - if( box.left > window.innerWidth - (box.width + Page.startX)){ // includes allowance for the box shadow - box.left = Page.startX; - box.top += box.height + 30; - } - }); -}); - -//---------------------------------------------------------- -var site = new ArrangeClass("Site", function() { - Groups.removeAll(); +// ########## +function UIClass(){ + this.navBar = Navbar; + this.tabBar = Tabbar; + this.devMode = false; - var groups = []; - $(".tab:visible").each(function(i) { - $el = $(this); - var tab = Tabs.tab(this); - - var url = tab.url; - var domain = url.split('/')[2]; - var domainParts = domain.split('.'); - var mainDomain = domainParts[domainParts.length - 2]; - if(groups[mainDomain]) - groups[mainDomain].push($(this)); - else - groups[mainDomain] = [$(this)]; + var self = this; + + // ___ URL Params + var params = document.location.search.replace('?', '').split('&'); + $.each(params, function(index, param) { + var parts = param.split('='); + if(parts[0] == 'dev' && parts[1] == '1') + self.devMode = true; }); - var createOptions = {dontPush: true, dontArrange: true}; - - var leftovers = []; - for(key in groups) { - var set = groups[key]; - if(set.length > 1) { - group = new Group(set, createOptions); - } else - leftovers.push(set[0]); + // ___ Dev Mode + if(this.devMode) { + Switch.insert('#nav', ''); + this._addArrangements(); } -/* if(leftovers.length > 1) { */ - group = new Group(leftovers, createOptions); -/* } */ + // ___ Navbar + this.navBar.hide(); + + Utils.homeTab.onFocus(function(){ + self.navBar.hide(); + }); - Groups.arrange(); -}); + $(window).blur(function(){ + self.navBar.show(); + }); -//---------------------------------------------------------- -var Arrange = { - initialized: false, + // ___ Finish up + Page.init(); +}; - init: function(){ - this.initialized = true; - grid.arrange(true); - } -} - -//---------------------------------------------------------- -function UIClass(){ this.init(); }; +// ---------- UIClass.prototype = { - navbar: Navbar, - tabbar: Tabbar, - init: function(){ - Page.init(); - Arrange.init(); + _addArrangements: function() { + this.grid = new ArrangeClass("Grid", function(value) { + if(typeof(Groups) != 'undefined') + Groups.removeAll(); + + var immediately = false; + if(typeof(value) == 'boolean') + immediately = value; + + var box = new Rect(Page.startX, Page.startY, TabItems.tabWidth, TabItems.tabHeight); + $(".tab:visible").each(function(i){ + var item = Items.item(this); + item.setBounds(box, immediately); + + box.left += box.width + 30; + if( box.left > window.innerWidth - (box.width + Page.startX)){ // includes allowance for the box shadow + box.left = Page.startX; + box.top += box.height + 30; + } + }); + }); + + this.site = new ArrangeClass("Site", function() { + Groups.removeAll(); + + var groups = []; + $(".tab:visible").each(function(i) { + $el = $(this); + var tab = Tabs.tab(this); + + var url = tab.url; + var domain = url.split('/')[2]; + var domainParts = domain.split('.'); + var mainDomain = domainParts[domainParts.length - 2]; + if(groups[mainDomain]) + groups[mainDomain].push($(this)); + else + groups[mainDomain] = [$(this)]; + }); + + var createOptions = {dontPush: true, dontArrange: true}; + + var leftovers = []; + for(key in groups) { + var set = groups[key]; + if(set.length > 1) { + group = new Group(set, createOptions); + } else + leftovers.push(set[0]); + } + + /* if(leftovers.length > 1) { */ + group = new Group(leftovers, createOptions); + /* } */ + + Groups.arrange(); + }); } -} +}; -//---------------------------------------------------------- -var UI = new UIClass(); -window.UI = UI; +// ---------- +window.UI = new UIClass(); })(); diff --git a/browser/themes/pinstripe/browser/tabcandy/tabcandy.css b/browser/themes/pinstripe/browser/tabcandy/tabcandy.css index 05b8f73d472..6aed924da13 100644 --- a/browser/themes/pinstripe/browser/tabcandy/tabcandy.css +++ b/browser/themes/pinstripe/browser/tabcandy/tabcandy.css @@ -77,6 +77,7 @@ body { height: 16px; background: url(../img/closetab.png) no-repeat; opacity: 0.2; + cursor: pointer; } .close:hover{ opacity: 1.0;} @@ -155,18 +156,17 @@ body { } .titlebar{ - border: 1px solid #ccc; font-size: 12px; line-height: 18px; height: 18px; - background: -moz-linear-gradient(90deg, #ccc,#eee); - display: none; - visibility: hidden; } input.name{ background: transparent; - border: none; + border: 1px solid #ddd; + color: #999; + margin: 3px 0px 0px 3px; + padding: 1px; } /* Resizable diff --git a/content/candies/revision-a/index.html b/content/candies/revision-a/index.html index 298bfbb1e01..c82c554c2aa 100644 --- a/content/candies/revision-a/index.html +++ b/content/candies/revision-a/index.html @@ -49,15 +49,13 @@ - - + +