Support dragging the goal window

This commit is contained in:
Sergey Krilov 2014-03-09 20:46:30 -04:00
parent 549e67b1c7
commit f29252e6ad
5 changed files with 182 additions and 36 deletions

View file

@ -50,6 +50,9 @@ var Level = Sandbox.extend({
this.initGoalData(options);
this.initName(options);
this.on('toggleGoal', this.toggleGoal);
this.on('minimizeCanvas', this.minimizeGoal);
this.on('resizeCanvas', this.resizeGoal);
Level.__super__.initialize.apply(this, [options]);
this.startOffCommand();
@ -128,7 +131,8 @@ var Level = Sandbox.extend({
var name = intl.getName(this.level);
this.levelToolbar = new LevelToolbar({
name: name
name: name,
parent: this
});
},
@ -170,7 +174,8 @@ var Level = Sandbox.extend({
var onlyMaster = TreeCompare.onlyMasterCompared(this.level);
// first we make the goal visualization holder
this.goalCanvasHolder = new CanvasTerminalHolder({
text: (onlyMaster) ? intl.str('goal-only-master') : undefined
text: (onlyMaster) ? intl.str('goal-only-master') : undefined,
parent: this
});
// then we make a visualization. the "el" here is the element to
@ -185,9 +190,38 @@ var Level = Sandbox.extend({
levelBlob: this.level,
noClick: true
});
// If the goal visualization gets dragged to the right side of the screen, then squeeze the main
// repo visualization a bit to make room. This way, you could have the goal window hang out on
// the right side of the screen and still see the repo visualization.
this.goalVis.customEvents.on('drag', _.bind(function(event, ui) {
if (ui.position.left > 0.5*$(window).width()) {
if (!$('#goalPlaceholder').is(':visible')) {
$('#goalPlaceholder').show();
this.mainVis.myResize();
}
} else {
if ($('#goalPlaceholder').is(':visible')) {
$('#goalPlaceholder').hide();
this.mainVis.myResize();
}
}
}, this));
return this.goalCanvasHolder;
},
minimizeGoal: function (position, size) {
this.goalVis.hide();
this.goalWindowPos = position;
this.goalWindowSize = size;
this.levelToolbar.$goalButton.text('Show Goal');
},
resizeGoal: function () {
this.goalVis.myResize();
},
showSolution: function(command, deferred) {
var toIssue = this.level.solutionCommand;
var issueFunc = _.bind(function() {
@ -230,8 +264,17 @@ var Level = Sandbox.extend({
});
},
toggleGoal: function () {
if (this.goalCanvasHolder && this.goalCanvasHolder.inDom) {
this.hideGoal();
} else {
this.showGoal();
}
},
showGoal: function(command, defer) {
this.showSideVis(command, defer, this.goalCanvasHolder, this.initGoalVisualization);
this.levelToolbar.$goalButton.text('Hide Goal');
},
showSideVis: function(command, defer, canvasHolder, initMethod) {
@ -242,12 +285,13 @@ var Level = Sandbox.extend({
canvasHolder = initMethod.apply(this);
}
canvasHolder.slideIn();
canvasHolder.restore(this.goalWindowPos, this.goalWindowSize);
setTimeout(safeFinish, canvasHolder.getAnimationTime());
},
hideGoal: function(command, defer) {
this.hideSideVis(command, defer, this.goalCanvasHolder);
this.levelToolbar.$goalButton.text('Show Goal');
},
hideSideVis: function(command, defer, canvasHolder, vis) {

View file

@ -558,6 +558,7 @@ var LevelToolbar = BaseView.extend({
initialize: function(options) {
options = options || {};
this.parent = options.parent;
this.JSON = {
name: options.name || 'Some level! (unknown name)'
};
@ -565,6 +566,13 @@ var LevelToolbar = BaseView.extend({
this.beforeDestination = $($('#commandLineHistory div.toolbar')[0]);
this.render();
this.$goalButton = this.$el.find('#show-goal');
var parent = this.parent;
this.$goalButton.on('click', function () {
parent.trigger('toggleGoal');
});
if (!options.wait) {
process.nextTick(_.bind(this.show, this));
}
@ -840,6 +848,8 @@ var CanvasTerminalHolder = BaseView.extend({
initialize: function(options) {
options = options || {};
this.parent = options.parent;
this.minHeight = options.minHeight || 200;
this.destination = $('body');
this.JSON = {
title: options.title || intl.str('goal-to-reach'),
@ -849,6 +859,19 @@ var CanvasTerminalHolder = BaseView.extend({
this.render();
this.inDom = true;
this.$terminal = this.$el.find('.terminal-window-holder').first();
this.$terminal.height(0.8 * $(window).height());
this.$terminal.draggable({
cursor: 'move',
handle: '.toolbar',
containment: '#interfaceWrapper',
scroll: false
});
// If the entire window gets resized such that the terminal is outside the view, then
// move it back into the view, and expand/shrink it vertically as necessary.
$(window).on('resize', _.debounce(_.bind(this.recalcLayout, this), 300));
if (options.additionalClass) {
this.$el.addClass(options.additionalClass);
}
@ -861,7 +884,7 @@ var CanvasTerminalHolder = BaseView.extend({
},
die: function() {
this.slideOut();
this.minimize();
this.inDom = false;
setTimeout(_.bind(function() {
@ -869,16 +892,79 @@ var CanvasTerminalHolder = BaseView.extend({
}, this), this.getAnimationTime());
},
slideOut: function() {
this.slideToggle(true);
minimize: function() {
this.parent.trigger('minimizeCanvas', {
left: this.$terminal.css('left'),
top: this.$terminal.css('top')
}, {
width: this.$terminal.css('width'),
height: this.$terminal.css('height')
});
this.$terminal.animate({
height: '0px',
opacity: 0
}, this.getAnimationTime());
},
slideIn: function() {
this.slideToggle(false);
restore: function (pos, size) {
var self = this;
pos = pos || { top: this.$terminal.css('top'), left: this.$terminal.css('left') };
size = size || { width: this.$terminal.css('width'), height: this.$terminal.css('height') };
this.$terminal.css({
top: pos.top,
left: pos.left,
width: size.width,
height: '0px',
opacity: '0'
});
this.$terminal.animate({
height: size.height,
opacity: 1
}, this.getAnimationTime(), function () {
self.recalcLayout();
});
},
slideToggle: function(value) {
this.$('div.terminal-window-holder').toggleClass('slideOut', value);
recalcLayout: function () {
// Resize/reposition self based on the size of the browser window.
var parent = this.parent,
leftOffset = 0,
topOffset = 0,
heightOffset = 0,
width = this.$terminal.outerWidth(),
height = this.$terminal.outerHeight(),
left = this.$terminal.offset().left,
top = this.$terminal.offset().top,
right = ($(window).width() - (left + width)),
bottom = ($(window).height() - (top + height)),
minHeight = 0.75 * $(window).height(),
maxHeight = 0.95 * $(window).height();
// Calculate offsets
if (top < 0) { topOffset = -top; }
if (left < 0) { leftOffset = -left; }
if (right < 0) { leftOffset = right; }
if (bottom < 0) { topOffset = bottom; }
if (height < minHeight) { heightOffset = minHeight - height; }
if (height > maxHeight) { heightOffset = maxHeight - height; }
// Establish limits
left = Math.max(left + leftOffset, 0);
top = Math.max(top + topOffset, 0);
height = Math.max(height + heightOffset, minHeight);
// Set the new position/size
this.$terminal.animate({
left: left + 'px',
top: top + 'px',
height: height + 'px'
}, this.getAnimationTime(), function () {
parent.trigger('resizeCanvas');
});
},
getCanvasLocation: function() {

View file

@ -74,6 +74,13 @@ var Visualization = Backbone.View.extend({
this.myResize();
}, this));
// If the visualization is within a draggable container, we need to update the
// position whenever the container is moved.
this.$el.parents('.ui-draggable').on('drag', _.bind(function(event, ui) {
this.customEvents.trigger('drag', event, ui);
this.myResize();
}, this));
this.gitVisuals.drawTreeFirstTime();
if (this.treeString) {
this.gitEngine.loadTreeFromString(this.treeString);
@ -182,12 +189,14 @@ var Visualization = Backbone.View.extend({
$(this.paper.canvas).css('visibility', 'visible');
setTimeout(_.bind(this.fadeTreeIn, this), 10);
this.originToo('show', arguments);
this.myResize();
},
showHarsh: function() {
$(this.paper.canvas).css('visibility', 'visible');
this.setTreeOpacity(1);
this.originToo('showHarsh', arguments);
this.myResize();
},
resetFromThisTreeNow: function(treeString) {
@ -257,8 +266,8 @@ var Visualization = Backbone.View.extend({
// if we don't have a container, we need to set our
// position absolutely to whatever we are tracking
if (!this.containerElement) {
var left = el.offsetLeft;
var top = el.offsetTop;
var left = this.$el.offset().left;
var top = this.$el.offset().top;
$(this.paper.canvas).css({
position: 'absolute',