mirror of
https://github.com/pcottle/learnGitBranching.git
synced 2025-06-26 16:08:34 +02:00
Support dragging the goal window
This commit is contained in:
parent
549e67b1c7
commit
f29252e6ad
5 changed files with 182 additions and 36 deletions
|
@ -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) {
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -34,7 +34,7 @@ p {
|
|||
}
|
||||
|
||||
.githubLink {
|
||||
z-index: 99;
|
||||
z-index: 2;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
|
@ -224,10 +224,11 @@ body.hgMode #mainVisSpace .modeText.hgMode {
|
|||
/* Some interface things */
|
||||
|
||||
div.canvasTerminalHolder {
|
||||
height: 100%;
|
||||
height: 0;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 3;
|
||||
}
|
||||
|
||||
#canvasHolder {
|
||||
|
@ -254,28 +255,8 @@ body.hgMode .visBackgroundColor {
|
|||
min-height: 600px;
|
||||
}
|
||||
|
||||
div.canvasTerminalHolder > div.terminal-window-holder {
|
||||
margin: 100px 0;
|
||||
height: 100%;
|
||||
-webkit-transform: translate3d(0,0,0);
|
||||
-moz-transform: translate3d(0,0,0);
|
||||
-o-transform: translate3d(0,0,0);
|
||||
-ms-transform: translate3d(0,0,0);
|
||||
transform: translate3d(0,0,0);
|
||||
}
|
||||
|
||||
div.canvasTerminalHolder > div.terminal-window-holder.slideOut {
|
||||
-webkit-transform: translate3d(-150%,0,0);
|
||||
-moz-transform: translate3d(-150%,0,0);
|
||||
-o-transform: translate3d(-150%,0,0);
|
||||
-ms-transform: translate3d(-150%,0,0);
|
||||
transform: translate3d(-150%,0,0);
|
||||
}
|
||||
|
||||
|
||||
div.canvasTerminalHolder > div.terminal-window-holder > div.wrapper {
|
||||
margin: 0 20px 0px 20px;
|
||||
height: 80%;
|
||||
height: 100%;
|
||||
box-shadow: 0 0 30px rgb(0,0,0);
|
||||
cursor: pointer;
|
||||
border-radius: 0 0 5px 5px;
|
||||
|
@ -346,6 +327,21 @@ div.toolbar.level-toolbar {
|
|||
background-image: linear-gradient(top, #B2FF2E, #8AD247);
|
||||
border-radius: 0;
|
||||
height: 50px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
div.toolbar.level-toolbar button {
|
||||
font-size: 12px;
|
||||
border: 1px solid #888;
|
||||
border-radius: 4px;
|
||||
padding: 4px 8px;
|
||||
background-image: -webkit-linear-gradient(top, #EFEDEE, #C1C1C1);
|
||||
}
|
||||
|
||||
#show-goal {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
left: 4px;
|
||||
}
|
||||
|
||||
span.levelToolbarSpan {
|
||||
|
@ -739,6 +735,10 @@ div.modalView.box.inFront.show {
|
|||
z-index: 100;
|
||||
}
|
||||
|
||||
.terminal-window-holder {
|
||||
z-index: 3;
|
||||
}
|
||||
|
||||
.terminal-window .inside {
|
||||
padding: 10px;
|
||||
box-shadow: 0 0 10px rgba(0, 0, 0, 0.7);
|
||||
|
|
|
@ -67,7 +67,7 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div id="mainVisSpace" class="box flex1 horizontal transitionAll visBackgroundColor">
|
||||
<div id="mainVisSpace" class="box flex2 horizontal transitionAll visBackgroundColor">
|
||||
<span class="modeText transitionOpacity gitMode">
|
||||
Git
|
||||
</span>
|
||||
|
@ -75,6 +75,12 @@
|
|||
Hg
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- If you drag the goal window to the right side of the screen, this gets shown and causes
|
||||
the main visualization to squeeze a bit. This way, you could have the goal window hang out
|
||||
on the right side of the screen and still see the repo visualization. -->
|
||||
<div id="goalPlaceholder" class="box flex1 visBackgroundColor" style="display: none;"></div>
|
||||
|
||||
</div>
|
||||
|
||||
<div id="canvasHolder">
|
||||
|
@ -138,6 +144,7 @@
|
|||
<script type="text/html" id="level-toolbar-template">
|
||||
<div class="toolbar level-toolbar box vertical center transitionAll hidden">
|
||||
<div>
|
||||
<button id="show-goal" type="button">Show Goal</button>
|
||||
<i class="icon-bolt"></i>
|
||||
Level
|
||||
<span class="levelToolbarSpan">
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue