diff --git a/browser/base/content/tabcandy/app/groups.js b/browser/base/content/tabcandy/app/groups.js index c61429da1490..406d6a161f3b 100644 --- a/browser/base/content/tabcandy/app/groups.js +++ b/browser/base/content/tabcandy/app/groups.js @@ -936,10 +936,14 @@ DragInfo.prototype = { stop: function() { this.$el.data('isDragging', false); + // I'm commenting this out for a while as I believe it feels uncomfortable + // that groups go away when there is still a tab in them. I do this at + // the cost of symmetry. -- Aza + /* if(this.parent && !this.parent.locked && this.parent != this.item.parent && this.parent._children.length == 1 && !this.parent.getTitle()) { this.parent.remove(this.parent._children[0]); - } + }*/ if(this.item && !this.$el.hasClass('willGroup') && !this.item.parent) { this.item.setZ(drag.zIndex); diff --git a/browser/base/content/tabcandy/app/ui.js b/browser/base/content/tabcandy/app/ui.js index 6809dadf0a0e..91f594231cb1 100644 --- a/browser/base/content/tabcandy/app/ui.js +++ b/browser/base/content/tabcandy/app/ui.js @@ -129,6 +129,14 @@ window.Page = { init: function() { 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. + $(Utils.homeTab.contentDocument).mousedown(function(e){ + if( e.originalTarget.nodeName == "HTML" ) + Page.createGroupOnDrag(e) + }) + Tabs.onClose(function(){ // Only go back to the TabCandy tab when there you close the last @@ -177,7 +185,70 @@ window.Page = { } lastTab = this; }); - } + }, + + // ---------- + createGroupOnDrag: function(e){ + e.preventDefault(); + const minSize = 60; + + var startPos = {x:e.clientX, y:e.clientY} + var 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 + }, 300, function(){ + phantom.remove(); + }) + } + + function finalize(e){ + $("html").unbind("mousemove"); + 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(); + } + } + + $("html").mousemove(updateSize) + $("html").one('mouseup',finalize); + return false; + } } // ########## diff --git a/browser/base/content/tabcandy/core/utils.js b/browser/base/content/tabcandy/core/utils.js index fe165deb04c5..16572aa123b0 100644 --- a/browser/base/content/tabcandy/core/utils.js +++ b/browser/base/content/tabcandy/core/utils.js @@ -102,6 +102,34 @@ window.Rect.prototype = { && rect.top < this.bottom); }, + // ---------- + // Function: containsPoint + // Returns a boolean denoting if the is inside of + // the bounding rect. + // + // Paramaters + // - A point + containsPoint: function(point){ + return( point.x > this.left + && point.x < this.right + && point.y > this.top + && point.y < this.bottom ) + }, + + // ---------- + // Function: contains + // Returns a boolean denoting if the is contained inside + // of the bounding rect. + // + // Paramaters + // - A rect + contains: function(rect){ + return( rect.left > this.left + && rect.right < this.right + && rect.top > this.top + && rect.bottom < this.bottom ) + }, + // ---------- center: function() { return new Point(this.left + (this.width / 2), this.top + (this.height / 2));