diff --git a/build/bundle.js b/build/bundle.js index 7ffc77c5..cd3a7679 100644 --- a/build/bundle.js +++ b/build/bundle.js @@ -4641,6 +4641,22 @@ var Sandbox = Backbone.View.extend({ }); }, + buildLevel: function(command, deferred) { + this.hide(); + this.clear(); + + var whenBuilderOpen = Q.defer(); + + var LevelBuilder = require('../level/builder').LevelBuilder; + var levelBuilder = new LevelBuilder({ + deferred: whenBuilderOpen + }); + + whenBuilderOpen.promise.then(function() { + command.finishWith(deferred); + }); + }, + exitLevel: function(command, deferred) { command.addWarning( "You aren't in a level! You are in a sandbox, start a level with `level [id]`" @@ -4667,7 +4683,8 @@ var Sandbox = Backbone.View.extend({ 'level': this.startLevel, 'sandbox': this.exitLevel, 'levels': this.showLevels, - 'iosAlert': this.iosAlert + 'iosAlert': this.iosAlert, + 'build level': this.buildLevel }; var method = commandMap[command.get('method')]; @@ -6609,10 +6626,10 @@ var Level = Sandbox.extend({ treeString: options.level.startTree }); - this.initGoalVisualization(options); + this.initGoalVisualization(); }, - initGoalVisualization: function(options) { + initGoalVisualization: function() { // first we make the goal visualization holder this.goalCanvasHolder = new CanvasTerminalHolder(); @@ -6663,6 +6680,8 @@ var Level = Sandbox.extend({ showGoal: function(command, defer) { this.goalCanvasHolder.slideIn(); + + if (!command || !defer) { return; } setTimeout(function() { command.finishWith(defer); }, this.goalCanvasHolder.getAnimationTime()); @@ -10130,6 +10149,10 @@ var CanvasTerminalHolder = BaseView.extend({ }; this.render(); + + if (options.additionalClass) { + this.$el.addClass(options.additionalClass); + } }, getAnimationTime: function() { return 700; }, @@ -12911,7 +12934,7 @@ var instantCommands = [ msg: 'Commands combined!' }); }], - [/^echo "([a-zA-Z0-9 ]+)"$|^echo ([a-zA-Z0-9 ]+)$/, function(bits) { + [/^echo "(.*?)"$|^echo (.*?)$/, function(bits) { var msg = bits[1] || bits[2]; console.log(bits, msg); throw new CommandResult({ @@ -12929,7 +12952,8 @@ var regexMap = { 'sandbox': /^sandbox($|\s)/, 'level': /^level\s?([a-zA-Z0-9]*)/, 'levels': /^levels($|\s)/, - 'iosAlert': /^iOS alert($|\s)/ + 'iosAlert': /^iOS alert($|\s)/, + 'build level': /^build level($|\s)/ }; exports.instantCommands = instantCommands; @@ -13777,6 +13801,10 @@ GitVisuals.prototype.visBranchesFront = function() { vBranch.nonTextToFront(); vBranch.textToFront(); }); + + this.visBranchCollection.each(function(visBranch) { + vBranch.textToFrontIfInStack(); + }); }; GitVisuals.prototype.drawTreeFromReload = function() { @@ -14611,6 +14639,12 @@ var VisBranch = VisBase.extend({ this.get('text').toFront(); }, + textToFrontIfInStack: function() { + if (this.getBranchStackIndex() !== 0) { + this.get('text').toFront(); + } + }, + getFill: function() { // in the easy case, just return your own fill if you are: // - the HEAD ref @@ -16450,6 +16484,229 @@ exports.setupZoomPoll = setupZoomPoll; exports.detectZoom = detectZoom; +}); + +require.define("/src/js/level/builder.js",function(require,module,exports,__dirname,__filename,process,global){var _ = require('underscore'); +var Backbone = require('backbone'); +var Q = require('q'); + +var util = require('../util'); +var Main = require('../app'); + +var Visualization = require('../visuals/visualization').Visualization; +var ParseWaterfall = require('../level/parseWaterfall').ParseWaterfall; +var Level = require('../level').Level; + +var Command = require('../models/commandModel').Command; +var GitShim = require('../git/gitShim').GitShim; + +var MultiView = require('../views/multiView').MultiView; +var CanvasTerminalHolder = require('../views').CanvasTerminalHolder; +var ConfirmCancelTerminal = require('../views').ConfirmCancelTerminal; +var NextLevelConfirm = require('../views').NextLevelConfirm; +var LevelToolbar = require('../views').LevelToolbar; + +var regexMap = { + 'define goal': /^define goal$/, + 'define start': /^define start$/, + 'show start': /^show start$/, + 'hide start': /^hide start$/ +}; + +var parse = util.genParseCommand(regexMap, 'processLevelBuilderCommand'); + +var LevelBuilder = Level.extend({ + initialize: function(options) { + options = options || {}; + + this.options = options; + this.level = {}; + + this.level.startDialog = { + childViews: [{ + type: 'ModalAlert', + options: { + markdowns: [ + '## Welcome to the level builder!', + '', + 'Here are the main steps:', + '', + ' * Define the starting tree', + ' * Enter the series of git commands that compose of the (optimal) solution', + ' * Define the goal tree, which also defines the solution', + ' * Enter the command ```finish building``` to specify start dialogs and such' + ] + } + }] + }; + + LevelBuilder.__super__.initialize.apply(this, [options]); + + this.initStartVisualization(); + + // we wont be using this stuff, and its to delete to ensure we overwrite all functions that + // include that functionality + delete this.treeCompare; + delete this.solved; + }, + + initName: function() { + this.levelToolbar = new LevelToolbar({ + name: 'Level Builder' + }); + }, + + initGoalData: function() { + // add some default behavior in the beginning + this.level.goalTreeString = '{"branches":{"master":{"target":"C1","id":"master"},"makeLevel":{"target":"C2","id":"makeLevel"}},"commits":{"C0":{"parents":[],"id":"C0","rootCommit":true},"C1":{"parents":["C0"],"id":"C1"},"C2":{"parents":["C1"],"id":"C2"}},"HEAD":{"target":"makeLevel","id":"HEAD"}}'; + this.level.solutionCommand = 'git checkout -b makeLevel; git commit'; + LevelBuilder.__super__.initGoalData.apply(this, arguments); + }, + + initStartVisualization: function() { + this.startCanvasHolder = new CanvasTerminalHolder({ + additionalClass: 'startTree' + }); + + this.startVis = new Visualization({ + el: this.startCanvasHolder.getCanvasLocation(), + containerElement: this.startCanvasHolder.getCanvasLocation(), + treeString: this.level.startTree, + noKeyboardInput: true, + noClick: true + }); + }, + + startDie: function() { + this.startCanvasHolder.die(); + this.startVis.die(); + }, + + startOffCommand: function() { + Main.getEventBaton().trigger( + 'commandSubmitted', + 'echo "Get Building!!"' + ); + }, + + initParseWaterfall: function(options) { + LevelBuilder.__super__.initParseWaterfall.apply(this, [options]); + + this.parseWaterfall.addFirst( + 'parseWaterfall', + parse + ); + this.parseWaterfall.addFirst( + 'instantWaterfall', + this.getInstantCommands() + ); + }, + + buildLevel: function(command, deferred) { + this.exitLevel(); + + setTimeout(function() { + Main.getSandbox().buildLevel(command, deferred); + }, this.getAnimationTime() * 1.5); + }, + + getInstantCommands: function() { + return []; + }, + + takeControl: function() { + Main.getEventBaton().stealBaton('processLevelBuilderCommand', this.processLevelBuilderCommand, this); + + LevelBuilder.__super__.takeControl.apply(this); + }, + + releaseControl: function() { + Main.getEventBaton().releaseBaton('processLevelBuilderCommand', this.processLevelBuilderCommand, this); + + LevelBuilder.__super__.releaseControl.apply(this); + }, + + showGoal: function() { + this.startCanvasHolder.slideOut(); + LevelBuilder.__super__.showGoal.apply(this, arguments); + }, + + showStart: function(command, deferred) { + this.goalCanvasHolder.slideOut(); + this.startCanvasHolder.slideIn(); + + setTimeout(function() { + command.finishWith(deferred); + }, this.startCanvasHolder.getAnimationTime()); + }, + + hideStart: function(command, deferred) { + this.startCanvasHolder.slideOut(); + + setTimeout(function() { + command.finishWith(deferred); + }, this.startCanvasHolder.getAnimationTime()); + }, + + defineStart: function(command, deferred) { + this.startDie(); + + command.addWarning( + 'Defining start point... solution and goal will be overwritten if they were defined earlier' + ); + this.reset(); + this.solutionCommand = undefined; + + this.level.startTree = this.mainVis.gitEngine.printTree(); + this.initStartVisualization(); + + this.showStart(command, deferred); + }, + + defineGoal: function(command, deferred) { + this.goalDie(); + + if (!this.gitCommandsIssued.length) { + command.addWarning( + 'Your solution is empty!! something is amiss' + ); + } + + this.solutionCommand = this.gitCommandsIssued.join(';'); + this.goalTreeString = this.mainVis.gitEngine.printTree(); + this.initGoalVisualization(); + + this.showGoal(command, deferred); + }, + + processLevelBuilderCommand: function(command, deferred) { + var methodMap = { + 'define goal': this.defineGoal, + 'define start': this.defineStart, + 'show start': this.showStart, + 'hide start': this.hideStart + }; + + methodMap[command.get('method')].apply(this, arguments); + }, + + afterCommandDefer: function(defer, command) { + // we dont need to compare against the goal anymore + defer.resolve(); + }, + + die: function() { + this.startDie(); + + LevelBuilder.__super__.die.apply(this, arguments); + + delete this.startVis; + delete this.startCanvasHolder; + } +}); + +exports.LevelBuilder = LevelBuilder; + }); require.define("/src/js/dialogs/sandbox.js",function(require,module,exports,__dirname,__filename,process,global){exports.helpDialog = [{ @@ -19093,7 +19350,8 @@ var LevelToolbar = require('../views').LevelToolbar; var regexMap = { 'define goal': /^define goal$/, 'define start': /^define start$/, - 'show start': /^show start$/ + 'show start': /^show start$/, + 'hide start': /^hide start$/ }; var parse = util.genParseCommand(regexMap, 'processLevelBuilderCommand'); @@ -19147,7 +19405,9 @@ var LevelBuilder = Level.extend({ }, initStartVisualization: function() { - this.startCanvasHolder = new CanvasTerminalHolder(); + this.startCanvasHolder = new CanvasTerminalHolder({ + additionalClass: 'startTree' + }); this.startVis = new Visualization({ el: this.startCanvasHolder.getCanvasLocation(), @@ -19183,12 +19443,20 @@ var LevelBuilder = Level.extend({ ); }, + buildLevel: function(command, deferred) { + this.exitLevel(); + + setTimeout(function() { + Main.getSandbox().buildLevel(command, deferred); + }, this.getAnimationTime() * 1.5); + }, + getInstantCommands: function() { return []; }, takeControl: function() { - Main.getEventBaton().stealBaton('processLevelBuilderCommand', this.processLevelCommand, this); + Main.getEventBaton().stealBaton('processLevelBuilderCommand', this.processLevelBuilderCommand, this); LevelBuilder.__super__.takeControl.apply(this); }, @@ -19199,6 +19467,70 @@ var LevelBuilder = Level.extend({ LevelBuilder.__super__.releaseControl.apply(this); }, + showGoal: function() { + this.startCanvasHolder.slideOut(); + LevelBuilder.__super__.showGoal.apply(this, arguments); + }, + + showStart: function(command, deferred) { + this.goalCanvasHolder.slideOut(); + this.startCanvasHolder.slideIn(); + + setTimeout(function() { + command.finishWith(deferred); + }, this.startCanvasHolder.getAnimationTime()); + }, + + hideStart: function(command, deferred) { + this.startCanvasHolder.slideOut(); + + setTimeout(function() { + command.finishWith(deferred); + }, this.startCanvasHolder.getAnimationTime()); + }, + + defineStart: function(command, deferred) { + this.startDie(); + + command.addWarning( + 'Defining start point... solution and goal will be overwritten if they were defined earlier' + ); + this.reset(); + this.solutionCommand = undefined; + + this.level.startTree = this.mainVis.gitEngine.printTree(); + this.initStartVisualization(); + + this.showStart(command, deferred); + }, + + defineGoal: function(command, deferred) { + this.goalDie(); + + if (!this.gitCommandsIssued.length) { + command.addWarning( + 'Your solution is empty!! something is amiss' + ); + } + + this.solutionCommand = this.gitCommandsIssued.join(';'); + this.goalTreeString = this.mainVis.gitEngine.printTree(); + this.initGoalVisualization(); + + this.showGoal(command, deferred); + }, + + processLevelBuilderCommand: function(command, deferred) { + var methodMap = { + 'define goal': this.defineGoal, + 'define start': this.defineStart, + 'show start': this.showStart, + 'hide start': this.hideStart + }; + + methodMap[command.get('method')].apply(this, arguments); + }, + afterCommandDefer: function(defer, command) { // we dont need to compare against the goal anymore defer.resolve(); @@ -19382,10 +19714,10 @@ var Level = Sandbox.extend({ treeString: options.level.startTree }); - this.initGoalVisualization(options); + this.initGoalVisualization(); }, - initGoalVisualization: function(options) { + initGoalVisualization: function() { // first we make the goal visualization holder this.goalCanvasHolder = new CanvasTerminalHolder(); @@ -19436,6 +19768,8 @@ var Level = Sandbox.extend({ showGoal: function(command, defer) { this.goalCanvasHolder.slideIn(); + + if (!command || !defer) { return; } setTimeout(function() { command.finishWith(defer); }, this.goalCanvasHolder.getAnimationTime()); @@ -19917,6 +20251,22 @@ var Sandbox = Backbone.View.extend({ }); }, + buildLevel: function(command, deferred) { + this.hide(); + this.clear(); + + var whenBuilderOpen = Q.defer(); + + var LevelBuilder = require('../level/builder').LevelBuilder; + var levelBuilder = new LevelBuilder({ + deferred: whenBuilderOpen + }); + + whenBuilderOpen.promise.then(function() { + command.finishWith(deferred); + }); + }, + exitLevel: function(command, deferred) { command.addWarning( "You aren't in a level! You are in a sandbox, start a level with `level [id]`" @@ -19943,7 +20293,8 @@ var Sandbox = Backbone.View.extend({ 'level': this.startLevel, 'sandbox': this.exitLevel, 'levels': this.showLevels, - 'iosAlert': this.iosAlert + 'iosAlert': this.iosAlert, + 'build level': this.buildLevel }; var method = commandMap[command.get('method')]; @@ -20046,7 +20397,7 @@ var instantCommands = [ msg: 'Commands combined!' }); }], - [/^echo "([a-zA-Z0-9 ]+)"$|^echo ([a-zA-Z0-9 ]+)$/, function(bits) { + [/^echo "(.*?)"$|^echo (.*?)$/, function(bits) { var msg = bits[1] || bits[2]; console.log(bits, msg); throw new CommandResult({ @@ -20064,7 +20415,8 @@ var regexMap = { 'sandbox': /^sandbox($|\s)/, 'level': /^level\s?([a-zA-Z0-9]*)/, 'levels': /^levels($|\s)/, - 'iosAlert': /^iOS alert($|\s)/ + 'iosAlert': /^iOS alert($|\s)/, + 'build level': /^build level($|\s)/ }; exports.instantCommands = instantCommands; @@ -21956,6 +22308,10 @@ var CanvasTerminalHolder = BaseView.extend({ }; this.render(); + + if (options.additionalClass) { + this.$el.addClass(options.additionalClass); + } }, getAnimationTime: function() { return 700; }, @@ -23741,6 +24097,10 @@ GitVisuals.prototype.visBranchesFront = function() { vBranch.nonTextToFront(); vBranch.textToFront(); }); + + this.visBranchCollection.each(function(visBranch) { + vBranch.textToFrontIfInStack(); + }); }; GitVisuals.prototype.drawTreeFromReload = function() { @@ -24139,6 +24499,12 @@ var VisBranch = VisBase.extend({ this.get('text').toFront(); }, + textToFrontIfInStack: function() { + if (this.getBranchStackIndex() !== 0) { + this.get('text').toFront(); + } + }, + getFill: function() { // in the easy case, just return your own fill if you are: // - the HEAD ref diff --git a/src/js/level/builder.js b/src/js/level/builder.js index 17e60076..c2b821e1 100644 --- a/src/js/level/builder.js +++ b/src/js/level/builder.js @@ -21,7 +21,8 @@ var LevelToolbar = require('../views').LevelToolbar; var regexMap = { 'define goal': /^define goal$/, 'define start': /^define start$/, - 'show start': /^show start$/ + 'show start': /^show start$/, + 'hide start': /^hide start$/ }; var parse = util.genParseCommand(regexMap, 'processLevelBuilderCommand'); @@ -75,7 +76,9 @@ var LevelBuilder = Level.extend({ }, initStartVisualization: function() { - this.startCanvasHolder = new CanvasTerminalHolder(); + this.startCanvasHolder = new CanvasTerminalHolder({ + additionalClass: 'startTree' + }); this.startVis = new Visualization({ el: this.startCanvasHolder.getCanvasLocation(), @@ -111,12 +114,20 @@ var LevelBuilder = Level.extend({ ); }, + buildLevel: function(command, deferred) { + this.exitLevel(); + + setTimeout(function() { + Main.getSandbox().buildLevel(command, deferred); + }, this.getAnimationTime() * 1.5); + }, + getInstantCommands: function() { return []; }, takeControl: function() { - Main.getEventBaton().stealBaton('processLevelBuilderCommand', this.processLevelCommand, this); + Main.getEventBaton().stealBaton('processLevelBuilderCommand', this.processLevelBuilderCommand, this); LevelBuilder.__super__.takeControl.apply(this); }, @@ -127,6 +138,70 @@ var LevelBuilder = Level.extend({ LevelBuilder.__super__.releaseControl.apply(this); }, + showGoal: function() { + this.startCanvasHolder.slideOut(); + LevelBuilder.__super__.showGoal.apply(this, arguments); + }, + + showStart: function(command, deferred) { + this.goalCanvasHolder.slideOut(); + this.startCanvasHolder.slideIn(); + + setTimeout(function() { + command.finishWith(deferred); + }, this.startCanvasHolder.getAnimationTime()); + }, + + hideStart: function(command, deferred) { + this.startCanvasHolder.slideOut(); + + setTimeout(function() { + command.finishWith(deferred); + }, this.startCanvasHolder.getAnimationTime()); + }, + + defineStart: function(command, deferred) { + this.startDie(); + + command.addWarning( + 'Defining start point... solution and goal will be overwritten if they were defined earlier' + ); + this.reset(); + this.solutionCommand = undefined; + + this.level.startTree = this.mainVis.gitEngine.printTree(); + this.initStartVisualization(); + + this.showStart(command, deferred); + }, + + defineGoal: function(command, deferred) { + this.goalDie(); + + if (!this.gitCommandsIssued.length) { + command.addWarning( + 'Your solution is empty!! something is amiss' + ); + } + + this.solutionCommand = this.gitCommandsIssued.join(';'); + this.goalTreeString = this.mainVis.gitEngine.printTree(); + this.initGoalVisualization(); + + this.showGoal(command, deferred); + }, + + processLevelBuilderCommand: function(command, deferred) { + var methodMap = { + 'define goal': this.defineGoal, + 'define start': this.defineStart, + 'show start': this.showStart, + 'hide start': this.hideStart + }; + + methodMap[command.get('method')].apply(this, arguments); + }, + afterCommandDefer: function(defer, command) { // we dont need to compare against the goal anymore defer.resolve(); diff --git a/src/js/level/index.js b/src/js/level/index.js index 12091fa2..a3475bf8 100644 --- a/src/js/level/index.js +++ b/src/js/level/index.js @@ -118,10 +118,10 @@ var Level = Sandbox.extend({ treeString: options.level.startTree }); - this.initGoalVisualization(options); + this.initGoalVisualization(); }, - initGoalVisualization: function(options) { + initGoalVisualization: function() { // first we make the goal visualization holder this.goalCanvasHolder = new CanvasTerminalHolder(); @@ -172,6 +172,8 @@ var Level = Sandbox.extend({ showGoal: function(command, defer) { this.goalCanvasHolder.slideIn(); + + if (!command || !defer) { return; } setTimeout(function() { command.finishWith(defer); }, this.goalCanvasHolder.getAnimationTime()); diff --git a/src/js/level/sandbox.js b/src/js/level/sandbox.js index 799bcfcb..127048ef 100644 --- a/src/js/level/sandbox.js +++ b/src/js/level/sandbox.js @@ -148,6 +148,22 @@ var Sandbox = Backbone.View.extend({ }); }, + buildLevel: function(command, deferred) { + this.hide(); + this.clear(); + + var whenBuilderOpen = Q.defer(); + + var LevelBuilder = require('../level/builder').LevelBuilder; + var levelBuilder = new LevelBuilder({ + deferred: whenBuilderOpen + }); + + whenBuilderOpen.promise.then(function() { + command.finishWith(deferred); + }); + }, + exitLevel: function(command, deferred) { command.addWarning( "You aren't in a level! You are in a sandbox, start a level with `level [id]`" @@ -174,7 +190,8 @@ var Sandbox = Backbone.View.extend({ 'level': this.startLevel, 'sandbox': this.exitLevel, 'levels': this.showLevels, - 'iosAlert': this.iosAlert + 'iosAlert': this.iosAlert, + 'build level': this.buildLevel }; var method = commandMap[command.get('method')]; diff --git a/src/js/level/sandboxCommands.js b/src/js/level/sandboxCommands.js index dca45068..6576ee74 100644 --- a/src/js/level/sandboxCommands.js +++ b/src/js/level/sandboxCommands.js @@ -35,7 +35,7 @@ var instantCommands = [ msg: 'Commands combined!' }); }], - [/^echo "([a-zA-Z0-9 ]+)"$|^echo ([a-zA-Z0-9 ]+)$/, function(bits) { + [/^echo "(.*?)"$|^echo (.*?)$/, function(bits) { var msg = bits[1] || bits[2]; console.log(bits, msg); throw new CommandResult({ @@ -53,7 +53,8 @@ var regexMap = { 'sandbox': /^sandbox($|\s)/, 'level': /^level\s?([a-zA-Z0-9]*)/, 'levels': /^levels($|\s)/, - 'iosAlert': /^iOS alert($|\s)/ + 'iosAlert': /^iOS alert($|\s)/, + 'build level': /^build level($|\s)/ }; exports.instantCommands = instantCommands; diff --git a/src/js/views/index.js b/src/js/views/index.js index c39b8c64..26fb0e4f 100644 --- a/src/js/views/index.js +++ b/src/js/views/index.js @@ -526,6 +526,10 @@ var CanvasTerminalHolder = BaseView.extend({ }; this.render(); + + if (options.additionalClass) { + this.$el.addClass(options.additionalClass); + } }, getAnimationTime: function() { return 700; }, diff --git a/src/js/visuals/index.js b/src/js/visuals/index.js index df774d40..a634df33 100644 --- a/src/js/visuals/index.js +++ b/src/js/visuals/index.js @@ -724,6 +724,10 @@ GitVisuals.prototype.visBranchesFront = function() { vBranch.nonTextToFront(); vBranch.textToFront(); }); + + this.visBranchCollection.each(function(visBranch) { + vBranch.textToFrontIfInStack(); + }); }; GitVisuals.prototype.drawTreeFromReload = function() { diff --git a/src/js/visuals/visBranch.js b/src/js/visuals/visBranch.js index 0bd582f3..10f2bb69 100644 --- a/src/js/visuals/visBranch.js +++ b/src/js/visuals/visBranch.js @@ -273,6 +273,12 @@ var VisBranch = VisBase.extend({ this.get('text').toFront(); }, + textToFrontIfInStack: function() { + if (this.getBranchStackIndex() !== 0) { + this.get('text').toFront(); + } + }, + getFill: function() { // in the easy case, just return your own fill if you are: // - the HEAD ref diff --git a/src/style/main.css b/src/style/main.css index 1d693f01..754b7912 100644 --- a/src/style/main.css +++ b/src/style/main.css @@ -225,6 +225,11 @@ div.canvasTerminalHolder > div.terminal-window-holder div.inside { background: #ff4c7e; } +div.canvasTerminalHolder.startTree > div.terminal-window-holder div.terminal-text, +div.canvasTerminalHolder.startTree > div.terminal-window-holder div.inside { + background: #4CA2FF; +} + div.canvasTerminalHolder > div.terminal-window-holder div.inside { min-height: 200px; border-radius: 0 0 5px 5px;