2010-03-17 01:07:00 -07:00
|
|
|
(function(){
|
|
|
|
|
|
|
|
var numCmp = function(a,b){ return a-b; }
|
|
|
|
|
|
|
|
function min(list){ return list.slice().sort(numCmp)[0]; }
|
|
|
|
function max(list){ return list.slice().sort(numCmp).reverse()[0]; }
|
|
|
|
|
2010-03-18 21:49:24 -07:00
|
|
|
function isEventOverElement(event, el){
|
|
|
|
var hit = {nodeName: null};
|
|
|
|
var isOver = false;
|
|
|
|
|
|
|
|
var hiddenEls = [];
|
|
|
|
while(hit.nodeName != "BODY" && hit.nodeName != "HTML"){
|
|
|
|
hit = document.elementFromPoint(event.clientX, event.clientY);
|
|
|
|
if( hit == el ){
|
|
|
|
isOver = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
$(hit).hide();
|
|
|
|
hiddenEls.push(hit);
|
|
|
|
}
|
|
|
|
|
|
|
|
var hidden;
|
|
|
|
[$(hidden).show() for([,hidden] in Iterator(hiddenEls))];
|
|
|
|
return isOver;
|
|
|
|
}
|
|
|
|
|
2010-03-25 17:22:45 -07:00
|
|
|
// ##########
|
2010-03-29 11:55:13 -07:00
|
|
|
window.Group = function(listOfEls, options) {
|
2010-03-29 17:23:35 -07:00
|
|
|
if(typeof(options) == 'undefined')
|
|
|
|
options = {};
|
|
|
|
|
|
|
|
this._children = []; // an array of Items
|
2010-03-29 16:08:48 -07:00
|
|
|
this._padding = 30;
|
2010-03-31 17:24:16 -07:00
|
|
|
this.defaultSize = new Point(TabItems.tabWidth * 1.5, TabItems.tabHeight * 1.5);
|
2010-03-29 16:08:48 -07:00
|
|
|
|
2010-03-29 11:55:13 -07:00
|
|
|
var self = this;
|
|
|
|
|
2010-03-29 16:08:48 -07:00
|
|
|
var boundingBox = this._getBoundingBox(listOfEls);
|
2010-03-29 11:55:13 -07:00
|
|
|
var padding = 30;
|
2010-04-02 15:10:35 -07:00
|
|
|
var rectToBe = new Rect(
|
2010-04-01 17:19:21 -07:00
|
|
|
boundingBox.left-padding,
|
|
|
|
boundingBox.top-padding,
|
|
|
|
boundingBox.width+padding*2,
|
|
|
|
boundingBox.height+padding*2
|
2010-04-02 15:10:35 -07:00
|
|
|
);
|
2010-04-01 17:59:17 -07:00
|
|
|
|
2010-04-02 15:10:35 -07:00
|
|
|
var $container = options.container;
|
|
|
|
if(!$container) {
|
|
|
|
$container = $('<div class="group" />')
|
|
|
|
.css({position: 'absolute'})
|
|
|
|
.css(rectToBe);
|
|
|
|
}
|
|
|
|
|
|
|
|
$container
|
|
|
|
.css({zIndex: -100})
|
2010-03-29 11:55:13 -07:00
|
|
|
.appendTo("body")
|
2010-04-01 17:19:21 -07:00
|
|
|
.dequeue();
|
|
|
|
|
2010-04-02 15:10:35 -07:00
|
|
|
// ___ Resizer
|
2010-04-02 17:33:06 -07:00
|
|
|
this.$resizer = $("<div class='resizer'/>")
|
2010-03-29 11:55:13 -07:00
|
|
|
.css({
|
|
|
|
position: "absolute",
|
|
|
|
width: 16, height: 16,
|
|
|
|
bottom: 0, right: 0,
|
2010-04-02 17:33:06 -07:00
|
|
|
})
|
|
|
|
.appendTo($container)
|
|
|
|
.hide();
|
2010-03-29 11:55:13 -07:00
|
|
|
|
2010-04-02 17:33:06 -07:00
|
|
|
// ___ Titlebar
|
2010-04-09 10:03:51 -07:00
|
|
|
this.$titlebar = $("<div class='titlebar'><input class='name' value=''/><div class='close'>x</div></div>")
|
2010-04-02 15:10:35 -07:00
|
|
|
.appendTo($container)
|
2010-03-29 11:55:13 -07:00
|
|
|
|
2010-04-09 10:03:51 -07:00
|
|
|
this.$titlebar.css({
|
|
|
|
position: "absolute",
|
2010-03-29 11:55:13 -07:00
|
|
|
});
|
|
|
|
|
2010-04-09 10:03:51 -07:00
|
|
|
$('.close', this.$titlebar).click(function() {
|
2010-03-29 16:08:48 -07:00
|
|
|
self.close();
|
2010-03-29 11:55:13 -07:00
|
|
|
});
|
|
|
|
|
|
|
|
// On delay, show the title bar.
|
|
|
|
var shouldShow = false;
|
2010-04-02 15:10:35 -07:00
|
|
|
$container.mouseover(function(){
|
2010-03-29 11:55:13 -07:00
|
|
|
shouldShow = true;
|
|
|
|
setTimeout(function(){
|
|
|
|
if( shouldShow == false ) return;
|
2010-04-02 15:10:35 -07:00
|
|
|
$container.find("input").focus();
|
2010-04-09 10:03:51 -07:00
|
|
|
self.$titlebar
|
2010-04-02 15:10:35 -07:00
|
|
|
.css({width: $container.width()})
|
2010-03-29 11:55:13 -07:00
|
|
|
.animate({ opacity: 1}).dequeue();
|
|
|
|
}, 500);
|
|
|
|
}).mouseout(function(e){
|
|
|
|
shouldShow = false;
|
2010-04-02 15:10:35 -07:00
|
|
|
if( isEventOverElement(e, $container.get(0) )) return;
|
2010-04-09 10:03:51 -07:00
|
|
|
self.$titlebar.animate({opacity:0}).dequeue();
|
2010-04-02 15:10:35 -07:00
|
|
|
})
|
2010-03-29 11:55:13 -07:00
|
|
|
|
2010-04-09 10:03:51 -07:00
|
|
|
// ___ Content
|
|
|
|
this.$content = $('<div class="group-content"/>')
|
|
|
|
.css({
|
|
|
|
left: 0,
|
|
|
|
top: this.$titlebar.height(),
|
|
|
|
position: 'absolute'
|
|
|
|
})
|
|
|
|
.appendTo($container);
|
|
|
|
|
|
|
|
// ___ Superclass initialization
|
|
|
|
this._init($container.get(0));
|
|
|
|
|
|
|
|
if(this.$debug)
|
|
|
|
this.$debug.css({zIndex: -1000});
|
|
|
|
|
2010-04-02 15:10:35 -07:00
|
|
|
// ___ Children
|
2010-03-29 16:08:48 -07:00
|
|
|
$.each(listOfEls, function(index, el) {
|
2010-03-29 17:23:35 -07:00
|
|
|
self.add(el, null, options);
|
2010-03-29 16:08:48 -07:00
|
|
|
});
|
|
|
|
|
2010-04-02 15:10:35 -07:00
|
|
|
// ___ Finish Up
|
|
|
|
this._addHandlers($container);
|
2010-04-02 17:33:06 -07:00
|
|
|
this.setResizable(true);
|
2010-03-29 16:08:48 -07:00
|
|
|
|
|
|
|
Groups.register(this);
|
2010-03-29 11:55:13 -07:00
|
|
|
|
2010-04-02 15:10:35 -07:00
|
|
|
this.setBounds(rectToBe);
|
|
|
|
|
2010-03-29 11:55:13 -07:00
|
|
|
// ___ Push other objects away
|
2010-03-29 17:23:35 -07:00
|
|
|
if(!options.dontPush)
|
2010-03-29 11:55:13 -07:00
|
|
|
this.pushAway();
|
|
|
|
};
|
|
|
|
|
|
|
|
// ----------
|
2010-03-31 17:24:16 -07:00
|
|
|
window.Group.prototype = $.extend(new Item(), new Subscribable(), {
|
2010-03-25 17:22:45 -07:00
|
|
|
// ----------
|
2010-03-29 16:08:48 -07:00
|
|
|
_getBoundingBox: function(els) {
|
2010-03-17 01:07:00 -07:00
|
|
|
var el;
|
|
|
|
var boundingBox = {
|
|
|
|
top: min( [$(el).position().top for([,el] in Iterator(els))] ),
|
|
|
|
left: min( [$(el).position().left for([,el] in Iterator(els))] ),
|
|
|
|
bottom: max( [$(el).position().top for([,el] in Iterator(els))] ) + $(els[0]).height(),
|
|
|
|
right: max( [$(el).position().left for([,el] in Iterator(els))] ) + $(els[0]).width(),
|
|
|
|
};
|
|
|
|
boundingBox.height = boundingBox.bottom - boundingBox.top;
|
|
|
|
boundingBox.width = boundingBox.right - boundingBox.left;
|
|
|
|
return boundingBox;
|
|
|
|
},
|
|
|
|
|
2010-03-25 17:22:45 -07:00
|
|
|
// ----------
|
2010-04-01 17:20:59 -07:00
|
|
|
getContentBounds: function() {
|
|
|
|
var box = this.getBounds();
|
2010-04-09 10:03:51 -07:00
|
|
|
var titleHeight = this.$titlebar.height();
|
2010-04-01 17:20:59 -07:00
|
|
|
box.top += titleHeight;
|
|
|
|
box.height -= titleHeight;
|
|
|
|
return box;
|
2010-03-17 01:07:00 -07:00
|
|
|
},
|
|
|
|
|
2010-03-25 17:22:45 -07:00
|
|
|
// ----------
|
2010-04-01 17:20:59 -07:00
|
|
|
reloadBounds: function() {
|
|
|
|
var bb = Utils.getBounds(this.container);
|
|
|
|
|
2010-04-09 10:03:51 -07:00
|
|
|
if(!this.bounds)
|
|
|
|
this.bounds = new Rect(0, 0, 0, 0);
|
|
|
|
|
|
|
|
this.setBounds(bb, true);
|
2010-03-17 01:07:00 -07:00
|
|
|
},
|
|
|
|
|
2010-03-25 17:22:45 -07:00
|
|
|
// ----------
|
2010-03-29 17:23:35 -07:00
|
|
|
setBounds: function(rect, immediately) {
|
2010-04-09 10:03:51 -07:00
|
|
|
var titleHeight = this.$titlebar.height();
|
|
|
|
|
|
|
|
// ___ Determine what has changed
|
2010-04-01 17:20:59 -07:00
|
|
|
var css = {};
|
2010-04-09 10:03:51 -07:00
|
|
|
var titlebarCSS = {};
|
|
|
|
var contentCSS = {};
|
2010-03-29 16:08:48 -07:00
|
|
|
|
2010-04-01 17:20:59 -07:00
|
|
|
if(rect.left != this.bounds.left)
|
|
|
|
css.left = rect.left;
|
|
|
|
|
|
|
|
if(rect.top != this.bounds.top)
|
2010-04-09 10:03:51 -07:00
|
|
|
css.top = rect.top;
|
2010-04-01 17:20:59 -07:00
|
|
|
|
2010-04-09 10:03:51 -07:00
|
|
|
if(rect.width != this.bounds.width) {
|
2010-04-01 17:20:59 -07:00
|
|
|
css.width = rect.width;
|
2010-04-09 10:03:51 -07:00
|
|
|
titlebarCSS.width = rect.width;
|
|
|
|
contentCSS.width = rect.width;
|
|
|
|
}
|
2010-04-01 17:20:59 -07:00
|
|
|
|
2010-04-09 10:03:51 -07:00
|
|
|
if(rect.height != this.bounds.height) {
|
|
|
|
css.height = rect.height;
|
|
|
|
contentCSS.height = rect.height - titleHeight;
|
|
|
|
}
|
2010-04-01 17:20:59 -07:00
|
|
|
|
|
|
|
if($.isEmptyObject(css))
|
|
|
|
return;
|
|
|
|
|
|
|
|
var offset = new Point(rect.left - this.bounds.left, rect.top - this.bounds.top);
|
|
|
|
this.bounds = new Rect(rect);
|
|
|
|
|
2010-04-09 10:03:51 -07:00
|
|
|
// ___ Deal with children
|
|
|
|
if(this._children.length) {
|
|
|
|
if(css.width || css.height) {
|
|
|
|
this.arrange({animate: !immediately});
|
|
|
|
} else if(css.left || css.top) {
|
|
|
|
$.each(this._children, function(index, child) {
|
|
|
|
var box = child.getBounds();
|
|
|
|
child.setPosition(box.left + offset.x, box.top + offset.y, immediately);
|
|
|
|
});
|
|
|
|
}
|
2010-04-01 17:20:59 -07:00
|
|
|
}
|
2010-04-09 10:03:51 -07:00
|
|
|
|
|
|
|
// ___ Update our representation
|
2010-03-29 17:23:35 -07:00
|
|
|
if(immediately) {
|
2010-04-01 17:20:59 -07:00
|
|
|
$(this.container).css(css);
|
2010-04-09 10:03:51 -07:00
|
|
|
this.$titlebar.css(titlebarCSS);
|
|
|
|
this.$content.css(contentCSS);
|
2010-03-29 17:23:35 -07:00
|
|
|
} else {
|
2010-04-01 17:20:59 -07:00
|
|
|
TabMirror.pausePainting();
|
|
|
|
$(this.container).animate(css, {complete: function() {
|
|
|
|
TabMirror.resumePainting();
|
|
|
|
}}).dequeue();
|
|
|
|
|
2010-04-09 10:03:51 -07:00
|
|
|
this.$titlebar.animate(titlebarCSS).dequeue();
|
|
|
|
this.$content.animate(contentCSS).dequeue();
|
2010-03-29 17:23:35 -07:00
|
|
|
}
|
2010-03-25 17:22:45 -07:00
|
|
|
|
2010-04-01 17:20:59 -07:00
|
|
|
this._updateDebugBounds();
|
|
|
|
},
|
|
|
|
|
2010-04-02 17:33:06 -07:00
|
|
|
// ----------
|
|
|
|
setZ: function(value) {
|
|
|
|
$(this.container).css({zIndex: value});
|
|
|
|
$.each(this._children, function(index, child) {
|
|
|
|
child.setZ(value + 1);
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
2010-03-29 16:08:48 -07:00
|
|
|
// ----------
|
|
|
|
close: function() {
|
2010-03-30 11:05:53 -07:00
|
|
|
var toClose = $.merge([], this._children);
|
|
|
|
$.each(toClose, function(index, child) {
|
2010-03-29 16:08:48 -07:00
|
|
|
child.close();
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
2010-03-25 17:22:45 -07:00
|
|
|
// ----------
|
2010-03-29 17:23:35 -07:00
|
|
|
add: function($el, dropPos, options) {
|
2010-03-24 14:38:23 -07:00
|
|
|
Utils.assert('add expects jQuery objects', Utils.isJQuery($el));
|
2010-03-17 01:07:00 -07:00
|
|
|
|
2010-03-29 17:23:35 -07:00
|
|
|
if(!dropPos)
|
2010-03-29 16:08:48 -07:00
|
|
|
dropPos = {top:window.innerWidth, left:window.innerHeight};
|
|
|
|
|
2010-03-29 17:23:35 -07:00
|
|
|
if(typeof(options) == 'undefined')
|
|
|
|
options = {};
|
|
|
|
|
2010-03-24 14:38:23 -07:00
|
|
|
var self = this;
|
2010-03-24 16:27:56 -07:00
|
|
|
|
2010-03-26 11:34:09 -07:00
|
|
|
// TODO: You should be allowed to drop in the white space at the bottom and have it go to the end
|
|
|
|
// (right now it can match the thumbnail above it and go there)
|
2010-03-24 16:27:56 -07:00
|
|
|
function findInsertionPoint(dropPos){
|
2010-03-29 16:08:48 -07:00
|
|
|
var best = {dist: Infinity, item: null};
|
2010-03-24 16:27:56 -07:00
|
|
|
var index = 0;
|
2010-03-29 16:08:48 -07:00
|
|
|
var box;
|
2010-03-24 16:27:56 -07:00
|
|
|
for each(var child in self._children){
|
2010-03-29 16:08:48 -07:00
|
|
|
box = child.getBounds();
|
|
|
|
var dist = Math.sqrt( Math.pow((box.top+box.height/2)-dropPos.top,2) + Math.pow((box.left+box.width/2)-dropPos.left,2) );
|
2010-03-26 11:34:09 -07:00
|
|
|
/* Utils.log( index, dist ); */
|
2010-03-24 16:27:56 -07:00
|
|
|
if( dist <= best.dist ){
|
2010-03-29 16:08:48 -07:00
|
|
|
best.item = child;
|
2010-03-24 16:27:56 -07:00
|
|
|
best.dist = dist;
|
|
|
|
best.index = index;
|
|
|
|
}
|
|
|
|
index += 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( self._children.length > 0 ){
|
2010-03-29 16:08:48 -07:00
|
|
|
box = best.item.getBounds();
|
|
|
|
var insertLeft = dropPos.left <= box.left + box.width/2;
|
|
|
|
if( !insertLeft )
|
|
|
|
return best.index+1;
|
|
|
|
else
|
|
|
|
return best.index;
|
2010-03-24 16:27:56 -07:00
|
|
|
}
|
|
|
|
|
2010-03-29 16:08:48 -07:00
|
|
|
return 0;
|
2010-03-24 16:27:56 -07:00
|
|
|
}
|
|
|
|
|
2010-03-29 16:08:48 -07:00
|
|
|
var item = Items.item($el);
|
|
|
|
var oldIndex = $.inArray(item, this._children);
|
2010-03-26 11:34:09 -07:00
|
|
|
if(oldIndex != -1)
|
|
|
|
this._children.splice(oldIndex, 1);
|
|
|
|
|
2010-03-24 16:27:56 -07:00
|
|
|
var index = findInsertionPoint(dropPos);
|
2010-03-29 16:08:48 -07:00
|
|
|
this._children.splice( index, 0, item );
|
2010-03-24 16:27:56 -07:00
|
|
|
|
2010-03-29 16:08:48 -07:00
|
|
|
$el.droppable("disable");
|
2010-04-02 17:33:06 -07:00
|
|
|
item.setZ(this.getZ() + 1);
|
2010-03-24 16:27:56 -07:00
|
|
|
|
2010-03-29 16:08:48 -07:00
|
|
|
item.addOnClose(this, function() {
|
|
|
|
self.remove($el);
|
|
|
|
});
|
2010-03-24 14:38:23 -07:00
|
|
|
|
2010-03-29 16:08:48 -07:00
|
|
|
$el.data("group", this);
|
2010-03-29 17:23:35 -07:00
|
|
|
|
2010-04-02 17:33:06 -07:00
|
|
|
if(typeof(item.setResizable) == 'function')
|
|
|
|
item.setResizable(false);
|
|
|
|
|
2010-03-29 17:23:35 -07:00
|
|
|
if(!options.dontArrange)
|
|
|
|
this.arrange();
|
2010-03-17 01:07:00 -07:00
|
|
|
},
|
|
|
|
|
2010-03-25 17:22:45 -07:00
|
|
|
// ----------
|
2010-03-29 16:08:48 -07:00
|
|
|
// The argument a can be an Item, a DOM element, or a jQuery object
|
|
|
|
remove: function(a, options) {
|
|
|
|
var $el;
|
|
|
|
var item;
|
|
|
|
|
|
|
|
if(a.isAnItem) {
|
|
|
|
item = a;
|
2010-04-01 17:20:59 -07:00
|
|
|
$el = $(item.container);
|
2010-03-29 16:08:48 -07:00
|
|
|
} else {
|
|
|
|
$el = $(a);
|
|
|
|
item = Items.item($el);
|
|
|
|
}
|
2010-03-24 14:38:23 -07:00
|
|
|
|
2010-03-29 16:08:48 -07:00
|
|
|
if(typeof(options) == 'undefined')
|
|
|
|
options = {};
|
2010-03-17 01:07:00 -07:00
|
|
|
|
2010-03-29 16:08:48 -07:00
|
|
|
var index = $.inArray(item, this._children);
|
|
|
|
if(index != -1)
|
|
|
|
this._children.splice(index, 1);
|
|
|
|
|
|
|
|
$el.data("group", null);
|
2010-03-31 17:24:16 -07:00
|
|
|
item.setSize(item.defaultSize.x, item.defaultSize.y);
|
2010-03-29 16:08:48 -07:00
|
|
|
$el.droppable("enable");
|
|
|
|
item.removeOnClose(this);
|
|
|
|
|
2010-04-02 17:33:06 -07:00
|
|
|
if(typeof(item.setResizable) == 'function')
|
|
|
|
item.setResizable(true);
|
|
|
|
|
|
|
|
if(this._children.length == 0 ){
|
|
|
|
this._sendOnClose();
|
2010-03-29 16:08:48 -07:00
|
|
|
Groups.unregister(this);
|
2010-04-01 17:20:59 -07:00
|
|
|
$(this.container).fadeOut(function() {
|
2010-03-29 16:08:48 -07:00
|
|
|
$(this).remove();
|
|
|
|
});
|
|
|
|
} else if(!options.dontArrange) {
|
2010-03-17 01:07:00 -07:00
|
|
|
this.arrange();
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2010-03-26 11:34:09 -07:00
|
|
|
// ----------
|
|
|
|
removeAll: function() {
|
2010-03-30 11:05:53 -07:00
|
|
|
var self = this;
|
|
|
|
var toRemove = $.merge([], this._children);
|
|
|
|
$.each(toRemove, function(index, child) {
|
|
|
|
self.remove(child, {dontArrange: true});
|
|
|
|
});
|
2010-03-26 11:34:09 -07:00
|
|
|
},
|
2010-03-29 16:08:48 -07:00
|
|
|
|
2010-03-25 17:22:45 -07:00
|
|
|
// ----------
|
2010-03-31 17:24:16 -07:00
|
|
|
arrange: function(options) {
|
|
|
|
if( options && options.animate == false )
|
|
|
|
animate = false;
|
|
|
|
else
|
|
|
|
animate = true;
|
|
|
|
|
|
|
|
if(typeof(options) == 'undefined')
|
|
|
|
options = {};
|
2010-03-24 16:27:56 -07:00
|
|
|
|
2010-04-02 15:10:35 -07:00
|
|
|
var bb = this.getContentBounds();
|
2010-03-17 01:07:00 -07:00
|
|
|
|
2010-03-24 14:17:05 -07:00
|
|
|
var count = this._children.length;
|
|
|
|
var bbAspect = bb.width/bb.height;
|
|
|
|
var tabAspect = 4/3;
|
|
|
|
|
|
|
|
function howManyColumns( numRows, count ){ return Math.ceil(count/numRows) }
|
|
|
|
|
|
|
|
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;
|
2010-03-17 01:07:00 -07:00
|
|
|
|
2010-03-24 14:17:05 -07:00
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
var padAmount = .1;
|
|
|
|
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; var y=pad; var numInCol = 0;
|
2010-03-29 16:08:48 -07:00
|
|
|
for each(var item in this._children){
|
2010-03-31 17:24:16 -07:00
|
|
|
item.setBounds(new Rect(x + bb.left, y + bb.top, tabW, tabH), !animate);
|
2010-03-24 16:27:56 -07:00
|
|
|
|
2010-03-24 14:17:05 -07:00
|
|
|
x += tabW + pad;
|
|
|
|
numInCol += 1;
|
2010-03-31 17:24:16 -07:00
|
|
|
if( numInCol >= best.numCols )
|
|
|
|
[x, numInCol, y] = [pad, 0, y+tabH+pad];
|
2010-03-17 01:07:00 -07:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2010-03-25 17:22:45 -07:00
|
|
|
// ----------
|
2010-03-17 01:07:00 -07:00
|
|
|
_addHandlers: function(container){
|
|
|
|
var self = this;
|
|
|
|
|
|
|
|
$(container).draggable({
|
|
|
|
start: function(){
|
2010-04-01 17:20:59 -07:00
|
|
|
drag.info = new DragInfo(this);
|
2010-03-17 01:07:00 -07:00
|
|
|
},
|
|
|
|
drag: function(e, ui){
|
2010-04-01 17:20:59 -07:00
|
|
|
drag.info.drag(e, ui);
|
2010-03-29 16:08:48 -07:00
|
|
|
},
|
|
|
|
stop: function() {
|
2010-04-01 17:20:59 -07:00
|
|
|
drag.info.stop();
|
|
|
|
drag.info = null;
|
2010-04-02 17:33:06 -07:00
|
|
|
}
|
2010-03-17 01:07:00 -07:00
|
|
|
});
|
|
|
|
|
|
|
|
$(container).droppable({
|
|
|
|
over: function(){
|
2010-04-01 17:20:59 -07:00
|
|
|
drag.info.$el.addClass("willGroup");
|
2010-03-17 01:07:00 -07:00
|
|
|
},
|
|
|
|
out: function(){
|
2010-04-01 17:20:59 -07:00
|
|
|
var $group = drag.info.$el.data("group");
|
2010-03-24 16:54:48 -07:00
|
|
|
if($group)
|
2010-04-01 17:20:59 -07:00
|
|
|
$group.remove(drag.info.$el);
|
|
|
|
drag.info.$el.removeClass("willGroup");
|
2010-03-17 01:07:00 -07:00
|
|
|
},
|
2010-03-24 16:27:56 -07:00
|
|
|
drop: function(event){
|
2010-04-01 17:20:59 -07:00
|
|
|
drag.info.$el.removeClass("willGroup");
|
2010-04-01 17:59:17 -07:00
|
|
|
self.add( drag.info.$el, {left:event.pageX, top:event.pageY} );
|
2010-03-17 01:07:00 -07:00
|
|
|
},
|
2010-03-31 17:24:16 -07:00
|
|
|
accept: ".tab, .group",
|
2010-03-17 01:07:00 -07:00
|
|
|
});
|
2010-04-02 17:33:06 -07:00
|
|
|
},
|
|
|
|
|
|
|
|
// ----------
|
|
|
|
setResizable: function(value){
|
|
|
|
var self = this;
|
|
|
|
|
|
|
|
if(value) {
|
|
|
|
this.$resizer.fadeIn();
|
|
|
|
$(this.container).resizable({
|
|
|
|
handles: "se",
|
|
|
|
aspectRatio: false,
|
|
|
|
resize: function(){
|
|
|
|
self.reloadBounds();
|
|
|
|
},
|
|
|
|
stop: function(){
|
|
|
|
self.reloadBounds();
|
|
|
|
self.pushAway();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
this.$resizer.fadeOut();
|
|
|
|
$(this.container).resizable('disable');
|
|
|
|
}
|
2010-03-29 16:08:48 -07:00
|
|
|
}
|
|
|
|
});
|
2010-03-17 01:07:00 -07:00
|
|
|
|
2010-03-25 17:22:45 -07:00
|
|
|
// ##########
|
2010-04-01 17:20:59 -07:00
|
|
|
var DragInfo = function(element) {
|
|
|
|
this.el = element;
|
|
|
|
this.$el = $(this.el);
|
|
|
|
this.item = Items.item(this.el);
|
|
|
|
|
|
|
|
this.$el.data('isDragging', true);
|
2010-04-02 17:33:06 -07:00
|
|
|
this.item.setZ(9999);
|
2010-04-01 17:20:59 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
DragInfo.prototype = {
|
|
|
|
// ----------
|
|
|
|
drag: function(e, ui) {
|
|
|
|
this.item.reloadBounds();
|
|
|
|
},
|
|
|
|
|
|
|
|
// ----------
|
|
|
|
stop: function() {
|
2010-04-02 17:33:06 -07:00
|
|
|
this.$el.data('isDragging', false);
|
|
|
|
if(this.item && !this.$el.hasClass('willGroup') && !this.$el.data('group')) {
|
|
|
|
this.item.setZ(drag.zIndex);
|
|
|
|
drag.zIndex++;
|
|
|
|
|
2010-04-01 17:20:59 -07:00
|
|
|
this.item.reloadBounds();
|
|
|
|
this.item.pushAway();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
var drag = {
|
|
|
|
info: null,
|
|
|
|
zIndex: 100
|
|
|
|
};
|
2010-03-17 01:07:00 -07:00
|
|
|
|
2010-04-01 17:20:59 -07:00
|
|
|
// ##########
|
2010-03-17 01:07:00 -07:00
|
|
|
window.Groups = {
|
2010-03-29 16:08:48 -07:00
|
|
|
groups: [],
|
|
|
|
|
2010-03-25 17:22:45 -07:00
|
|
|
// ----------
|
2010-03-17 01:07:00 -07:00
|
|
|
dragOptions: {
|
2010-04-01 17:20:59 -07:00
|
|
|
start: function() {
|
|
|
|
drag.info = new DragInfo(this);
|
2010-03-17 01:07:00 -07:00
|
|
|
},
|
2010-04-01 17:20:59 -07:00
|
|
|
drag: function(e, ui) {
|
|
|
|
drag.info.drag(e, ui);
|
2010-03-17 01:07:00 -07:00
|
|
|
},
|
2010-04-01 17:20:59 -07:00
|
|
|
stop: function() {
|
|
|
|
drag.info.stop();
|
|
|
|
drag.info = null;
|
2010-04-02 17:33:06 -07:00
|
|
|
}
|
2010-03-17 01:07:00 -07:00
|
|
|
},
|
|
|
|
|
2010-03-25 17:22:45 -07:00
|
|
|
// ----------
|
2010-03-17 01:07:00 -07:00
|
|
|
dropOptions: {
|
|
|
|
accept: ".tab",
|
|
|
|
tolerance: "pointer",
|
|
|
|
greedy: true,
|
|
|
|
drop: function(e){
|
2010-04-01 17:19:21 -07:00
|
|
|
$target = $(e.target);
|
2010-04-01 17:59:17 -07:00
|
|
|
drag.info.$el.removeClass("willGroup")
|
2010-04-01 17:19:21 -07:00
|
|
|
var phantom = $target.data("phantomGroup")
|
|
|
|
|
|
|
|
var group = $target.data("group");
|
|
|
|
if( group == null ){
|
|
|
|
phantom.removeClass("phantom");
|
2010-04-09 10:03:51 -07:00
|
|
|
phantom.removeClass("group-content");
|
2010-04-01 17:59:17 -07:00
|
|
|
var group = new Group([$target, drag.info.$el], {container:phantom});
|
2010-04-02 15:10:35 -07:00
|
|
|
} else
|
|
|
|
group.add( drag.info.$el );
|
2010-03-17 01:07:00 -07:00
|
|
|
},
|
|
|
|
over: function(e){
|
2010-04-01 17:19:21 -07:00
|
|
|
var $target = $(e.target);
|
2010-04-01 17:59:17 -07:00
|
|
|
|
2010-04-01 17:19:21 -07:00
|
|
|
function elToRect($el){
|
|
|
|
return new Rect( $el.position().left, $el.position().top, $el.width(), $el.height() );
|
|
|
|
}
|
2010-04-01 17:59:17 -07:00
|
|
|
|
|
|
|
var height = elToRect($target).height * 1.5 + 20;
|
|
|
|
var width = elToRect($target).width * 1.5 + 20;
|
|
|
|
var unionRect = elToRect($target).union( elToRect(drag.info.$el) );
|
|
|
|
|
2010-04-01 17:19:21 -07:00
|
|
|
var newLeft = unionRect.left + unionRect.width/2 - width/2;
|
|
|
|
var newTop = unionRect.top + unionRect.height/2 - height/2;
|
2010-04-01 17:59:17 -07:00
|
|
|
|
2010-04-01 17:19:21 -07:00
|
|
|
$(".phantom").remove();
|
2010-04-09 10:03:51 -07:00
|
|
|
var phantom = $("<div class='group phantom group-content'/>").css({
|
2010-04-01 17:19:21 -07:00
|
|
|
width: width,
|
|
|
|
height: height,
|
|
|
|
position:"absolute",
|
|
|
|
top: newTop,
|
|
|
|
left: newLeft,
|
|
|
|
zIndex: -99
|
|
|
|
}).appendTo("body").hide().fadeIn();
|
2010-04-01 17:59:17 -07:00
|
|
|
$target.data("phantomGroup", phantom);
|
2010-03-17 01:07:00 -07:00
|
|
|
},
|
2010-04-01 17:19:21 -07:00
|
|
|
out: function(e){
|
|
|
|
$(e.target).data("phantomGroup").fadeOut(function(){
|
|
|
|
$(this).remove();
|
|
|
|
});
|
2010-03-17 01:07:00 -07:00
|
|
|
}
|
2010-03-17 17:32:49 -07:00
|
|
|
},
|
|
|
|
|
2010-03-29 16:08:48 -07:00
|
|
|
// ----------
|
|
|
|
register: function(group) {
|
|
|
|
Utils.assert('only register once per group', $.inArray(group, this.groups) == -1);
|
|
|
|
this.groups.push(group);
|
|
|
|
},
|
|
|
|
|
|
|
|
// ----------
|
|
|
|
unregister: function(group) {
|
|
|
|
var index = $.inArray(group, this.groups);
|
|
|
|
if(index != -1)
|
|
|
|
this.groups.splice(index, 1);
|
|
|
|
},
|
|
|
|
|
2010-03-25 17:22:45 -07:00
|
|
|
// ----------
|
2010-03-17 17:32:49 -07:00
|
|
|
arrange: function() {
|
2010-03-29 17:23:35 -07:00
|
|
|
var count = this.groups.length;
|
2010-03-17 17:32:49 -07:00
|
|
|
var columns = Math.ceil(Math.sqrt(count));
|
|
|
|
var rows = ((columns * columns) - count >= columns ? columns - 1 : columns);
|
|
|
|
var padding = 12;
|
|
|
|
var startX = padding;
|
2010-03-29 17:23:35 -07:00
|
|
|
var startY = Page.startY;
|
2010-03-17 17:32:49 -07:00
|
|
|
var totalWidth = window.innerWidth - startX;
|
|
|
|
var totalHeight = window.innerHeight - startY;
|
2010-03-29 16:08:48 -07:00
|
|
|
var box = new Rect(startX, startY,
|
|
|
|
(totalWidth / columns) - padding,
|
|
|
|
(totalHeight / rows) - padding);
|
2010-03-17 17:32:49 -07:00
|
|
|
|
2010-03-29 16:08:48 -07:00
|
|
|
$.each(this.groups, function(index, group) {
|
2010-03-29 17:23:35 -07:00
|
|
|
group.setBounds(box, true);
|
2010-03-17 17:32:49 -07:00
|
|
|
|
2010-03-29 16:08:48 -07:00
|
|
|
box.left += box.width + padding;
|
|
|
|
if(index % columns == columns - 1) {
|
|
|
|
box.left = startX;
|
|
|
|
box.top += box.height + padding;
|
2010-03-17 17:32:49 -07:00
|
|
|
}
|
|
|
|
});
|
2010-03-26 11:34:09 -07:00
|
|
|
},
|
2010-03-25 17:22:45 -07:00
|
|
|
|
2010-03-26 11:34:09 -07:00
|
|
|
// ----------
|
|
|
|
removeAll: function() {
|
2010-03-30 11:05:53 -07:00
|
|
|
var toRemove = $.merge([], this.groups);
|
|
|
|
$.each(toRemove, function(index, group) {
|
|
|
|
group.removeAll();
|
|
|
|
});
|
2010-03-26 11:34:09 -07:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2010-03-25 17:22:45 -07:00
|
|
|
// ##########
|
2010-03-17 01:07:00 -07:00
|
|
|
$(".tab").data('isDragging', false)
|
|
|
|
.draggable(window.Groups.dragOptions)
|
|
|
|
.droppable(window.Groups.dropOptions);
|
|
|
|
|
|
|
|
})();
|