diff --git a/src/animationFactory.js b/src/animationFactory.js new file mode 100644 index 00000000..0fc5fc10 --- /dev/null +++ b/src/animationFactory.js @@ -0,0 +1,13 @@ +/****************** + * This class is responsible for a lot of the heavy lifting around creating an animation at a certain state in time. + * The tricky thing is that when a new commit has to be "born," say in the middle of a rebase or something, it must animate + * out from the parent position to it's birth position. + + * These two positions though may not be where the commit finally ends up. So we actually need to take a snapshot of the tree, + * store all those positions, take a snapshot of the tree after a layout refresh afterwards, and then animate between those two spots. + * and then essentially animate the entire tree too. + + * not sure if this is necessary yet, so ill hold off for now. lets do some refs + + */ + diff --git a/src/async.js b/src/async.js index b528991c..f4e36cfa 100644 --- a/src/async.js +++ b/src/async.js @@ -71,3 +71,4 @@ var AnimationQueue = Backbone.Model.extend({ }, this), duration); }, }); + diff --git a/src/commandModel.js b/src/commandModel.js index 1d450c74..cb33ed61 100644 --- a/src/commandModel.js +++ b/src/commandModel.js @@ -1,24 +1,52 @@ var Command = Backbone.Model.extend({ defaults: { status: 'inqueue', + rawStr: null, result: '', + error: null, - generalArgs: [], - supportedMap: {}, + warnings: null, + + generalArgs: null, + supportedMap: null, options: null, method: null, - createTime: null, - rawStr: null + + createTime: null }, validateAtInit: function() { + // weird things happen with defaults if you dont + // make new objects + this.set('generalArgs', []); + this.set('supportedMap', {}); + this.set('warnings', []); + if (this.get('rawStr') === null) { throw new Error('Give me a string!'); } if (!this.get('createTime')) { this.set('createTime', new Date().toString()); } + + this.on('change:error', this.errorChanged, this); + // catch errors on init + if (this.get('error')) { + this.errorChanged(); + } + }, + + addWarning: function(msg) { + this.set('warnings', this.get('warnings').push(msg)); + }, + + getFormattedWarnings: function() { + if (!this.get('warnings').length) { + return ''; + } + + return '
' + this.get('warnings').join('
') + '
'; }, initialize: function() { @@ -32,8 +60,9 @@ var Command = Backbone.Model.extend({ } catch (err) { if (err instanceof CommandProcessError || err instanceof GitError || - err instanceof CommandResult) { - // erroChanged() will handle status and all of that + err instanceof CommandResult || + err instanceof Warning) { + // errorChanged() will handle status and all of that this.set('error', err); } else { throw err; @@ -41,12 +70,15 @@ var Command = Backbone.Model.extend({ } }, - errorChanged: function(model, err) { + errorChanged: function() { + var err = this.get('error'); if (err instanceof CommandProcessError || err instanceof GitError) { this.set('status', 'error'); } else if (err instanceof CommandResult) { this.set('status', 'finished'); + } else if (err instanceof Warning) { + this.set('status', 'warning'); } this.formatError(); }, @@ -76,6 +108,7 @@ var Command = Backbone.Model.extend({ reset: /^reset($|\s)/, branch: /^branch($|\s)/, revert: /^revert($|\s)/, + log: /^log($|\s)/, merge: /^merge($|\s)/ }; }, @@ -204,6 +237,7 @@ OptionParser.prototype.getMasterOptionMap = function() { '-a': false, // warning '-am': false }, + log: {}, add: {}, branch: { '-d': false, diff --git a/src/commandViews.js b/src/commandViews.js index 117eb258..8f8b2f8e 100644 --- a/src/commandViews.js +++ b/src/commandViews.js @@ -139,11 +139,11 @@ var CommandView = Backbone.View.extend({ var json = _.extend( { resultType: '', - result: '' + result: '', + warnings: '' }, this.model.toJSON() ); - console.log('rendering', this.model.toJSON()); this.$el.html(this.template(json)); return this; @@ -164,6 +164,22 @@ var CommandLineHistoryView = Backbone.View.extend({ this.collection.on('all', this.render, this); this.collection.on('change', this.scrollDown, this); + + events.on('issueWarning', this.addWarning, this); + }, + + addWarning: function(msg) { + console.log('here', arguments); + var err = new Warning({ + msg: msg + }); + + var command = new Command({ + error: err, + rawStr: 'Warning:' + }); + + this.collection.add(command); }, scrollDown: function() { diff --git a/src/errors.js b/src/errors.js index 0e3b3be6..83e5e299 100644 --- a/src/errors.js +++ b/src/errors.js @@ -12,7 +12,7 @@ var MyError = Backbone.Model.extend({ }, toResult: function() { - return this.get('msg').replace('\n', ''); + return '' + this.get('msg').replace(/\n/g, '
') + '
'; } }); @@ -28,6 +28,12 @@ var CommandResult = MyError.extend({ } }); +var Warning = MyError.extend({ + defaults: { + type: 'Warning' + } +}); + var GitError = MyError.extend({ defaults: { type: 'Git Error' diff --git a/src/git.js b/src/git.js index b2152614..45c61514 100644 --- a/src/git.js +++ b/src/git.js @@ -40,12 +40,6 @@ GitEngine.prototype.init = function() { // commit once to get things going this.commit(); - - // update tree - // TODO make async, not async - setTimeout(function() { - events.trigger('treeRefresh'); - }, 100); }; GitEngine.prototype.getDetachedHead = function() { @@ -193,7 +187,7 @@ GitEngine.prototype.resetStarter = function() { }); } if (this.commandOptions['--hard']) { - events.trigger('commandProcessWarn', + this.command.addWarning( 'Nice! You are using --hard. The default behavior is a hard reset in ' + "this demo, so don't worry about specifying the option explicity" ); @@ -220,10 +214,10 @@ GitEngine.prototype.reset = function(target) { GitEngine.prototype.commitStarter = function() { this.acceptNoGeneralArgs(); if (this.commandOptions['-a']) { - events.trigger('commandProcessWarn', 'No need to add files in this demo'); + this.command.addWarning('No need to add files in this demo'); } if (this.commandOptions['-am']) { - events.trigger('commandProcessWarn', "Don't worry about adding files or commit messages in this demo"); + this.command.addWarning("Don't worry about adding files or commit messages in this demo"); } this.commit(); }; @@ -237,7 +231,7 @@ GitEngine.prototype.commit = function() { var newCommit = this.makeCommit([targetCommit]); if (this.getDetachedHead()) { - events.trigger('commandProcessWarn', 'Warning!! Detached HEAD state'); + this.command.addWarning('Warning!! Detached HEAD state'); this.HEAD.set('target', newCommit); } else { var targetBranch = this.HEAD.get('target'); @@ -611,7 +605,7 @@ GitEngine.prototype.branchStarter = function() { // handle deletion first if (this.commandOptions['-d'] || this.commandOptions['-D']) { var names = this.commandOptions['-d']; - names.concat(this.commandOptions['-D']); + names = names.concat(this.commandOptions['-D']); if (!names.length) { throw new GitError({ msg: 'I expect branch names when deleting' @@ -726,9 +720,52 @@ GitEngine.prototype.dispatch = function(command, callback) { this.animationQueue.add(new Animation({closure: function() { console.log(Math.random()); }})); } + // animation queue will call the callback when its done this.animationQueue.start(); }; +GitEngine.prototype.logStarter = function() { + if (this.generalArgs.length > 1) { + throw new GitError({ + msg: "git log with more than 1 argument doesn't make sense" + }); + } + if (this.generalArgs.length == 0) { + this.generalArgs.push('HEAD'); + } + this.log(this.generalArgs[0]); +}; + +GitEngine.prototype.log = function(ref) { + // first get the commit we referenced + var commit = this.getCommitFromRef(ref); + + // then get as many far back as we can from here, order by commit date + var toDump = []; + var pQueue = [commit]; + + while (pQueue.length) { + var popped = pQueue.shift(0); + toDump.push(popped); + + if (popped.get('parents') && popped.get('parents').length) { + pQueue = pQueue.concat(popped.get('parents')); + } + pQueue.sort(this.idSortFunc); + } + + toDump.reverse(); + // now go through and collect logs + var bigLogStr = ''; + _.each(toDump, function(c) { + bigLogStr += c.getLogEntry(); + }, this); + + throw new CommandResult({ + msg: bigLogStr + }); +}; + GitEngine.prototype.addStarter = function() { throw new CommandResult({ msg: "This demo is meant to demonstrate git branching, so don't worry about " + @@ -750,7 +787,7 @@ GitEngine.prototype.getCommonAncestor = function(ancestor, cousin) { if (upstreamSet[here.get('id')]) { return here; } - queue.concat(here.get('parents')); + queue = queue.concat(here.get('parents')); } throw new Error('something has gone very wrong... two nodes arent connected!'); }; @@ -814,12 +851,32 @@ var Commit = Backbone.Model.extend({ type: 'commit', children: null, parents: null, + author: 'Peter Cottle', + createTime: null, + commitMessage: null + }, + + getLogEntry: function() { + // for now we are just joining all these things with newlines... + return [ + 'Author: ' + this.get('author'), + 'Date: ' + this.get('createTime'), + this.get('commitMessage'), + 'Commit: ' + this.get('id') + ].join('\n' ) + '\n'; }, validateAtInit: function() { if (!this.get('id')) { this.set('id', uniqueId('C')); } + if (!this.get('createTime')) { + this.set('createTime', new Date().toString()); + } + if (!this.get('commitMessage')) { + this.set('commitMessage', 'Quick Commit. Go Bears!'); + } + this.set('children', []); // root commits have no parents diff --git a/src/index.html b/src/index.html index 87f09e1a..8b0c2b61 100644 --- a/src/index.html +++ b/src/index.html @@ -74,7 +74,15 @@- <%= result %> +
+