git log now done, fixed up result rendering

This commit is contained in:
Peter Cottle 2012-09-22 21:16:59 -07:00
parent 543f5986ae
commit 9c7ec69e2f
10 changed files with 189 additions and 35 deletions

13
src/animationFactory.js Normal file
View file

@ -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
*/

View file

@ -71,3 +71,4 @@ var AnimationQueue = Backbone.Model.extend({
}, this), duration);
},
});

View file

@ -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 '<p>' + this.get('warnings').join('</p><p>') + '</p>';
},
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,

View file

@ -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() {

View file

@ -12,7 +12,7 @@ var MyError = Backbone.Model.extend({
},
toResult: function() {
return this.get('msg').replace('\n', '</br>');
return '<p>' + this.get('msg').replace(/\n/g, '</p><p>') + '</p>';
}
});
@ -28,6 +28,12 @@ var CommandResult = MyError.extend({
}
});
var Warning = MyError.extend({
defaults: {
type: 'Warning'
}
});
var GitError = MyError.extend({
defaults: {
type: 'Git Error'

View file

@ -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

View file

@ -74,7 +74,15 @@
</p>
<p class="commandLineResult <%= resultType %>">
<%= result %>
<div class="commandLineResultWrapper">
<%= result %>
</div>
</p>
<p class="commandLineWarnings">
<div class="commandLineWarningsWrapper">
<%= warnings %>
</div>
</p>
</script>
@ -92,11 +100,11 @@
<script src="commandModel.js"></script>
<script src="commandViews.js"></script>
<!-- vis -->
<script src="collections.js"></script>
<script src="visuals.js"></script>
<script src="tree.js"></script>
<script src="animationFactory.js"></script>
</body>
</html>

View file

@ -195,11 +195,17 @@ p.commandLine span.icons i {
p.commandLine.inqueue span.icons i.icon-check-empty,
p.commandLine.error span.icons i.icon-exclamation-sign,
p.commandLine.warning span.icons i.icon-exclamation-sign,
p.commandLine.processing span.icons i.icon-retweet,
p.commandLine.finished span.icons i.icon-check {
opacity: 1;
}
p.commandLine.warning span.icons {
background-color: #E0FF00;
color: black;
}
p.commandLine.inqueue span.icons {
background-color: #EBEB24;
color: black;

View file

@ -1,6 +1,9 @@
var VisBranch = Backbone.Model.extend({
defaults: {
pos: null
pos: null,
text: null,
animationSpeed: GRAPHICS.defaultAnimationTime,
animationEasing: GRAPHICS.defaultEasing
},
validateAtInit: function() {
@ -37,20 +40,14 @@ var VisBranch = Backbone.Model.extend({
this.set('text', text);
},
animateUpdatedPos: function(paper) {
animateUpdatedPos: function(speed, easing) {
var pos = this.getPosition();
var t = this.get('text');
if (!t) {
this.genGraphics(paper);
t = this.get('text');
// TODO HACKY
}
this.get('text').toFront().stop().animate({
x: pos.x,
y: pos.y
},
300,
'easeInOut'
speed || this.get('animationSpeed'),
easing || this.get('animationEasing')
);
}
});

View file

@ -71,7 +71,7 @@ GitVisuals.prototype.toScreenCoords = function(pos) {
**************************************/
GitVisuals.prototype.refreshTree = function() {
if (!this.paperReady) { return; }
if (!this.paperReady) { console.warn('called refresh tree when not ready yet'); return; }
this.calculateTreeCoords();
this.animateNodePositions();
@ -79,6 +79,13 @@ GitVisuals.prototype.refreshTree = function() {
this.animateRefs();
};
GitVisuals.prototype.refreshTreeHarsh = function() {
this.calculateTreeCoords();
this.animateEdges();
this.animateNodePositions();
};
GitVisuals.prototype.calculateTreeCoords = function() {
if (!this.rootCommit) {
throw new Error('grr, no root commit!');
@ -142,6 +149,13 @@ GitVisuals.prototype.assignBoundsRecursive = function(commit, min, max) {
GitVisuals.prototype.calcDepth = function() {
var maxDepth = this.calcDepthRecursive(this.rootCommit, 0);
if (maxDepth > 15) {
// issue warning
events.trigger('issueWarning',
'Max Depth Exceeded! Visuals may degrade here. ' +
'Please start fresh or use reset to reduce the max depth'
);
}
var depthIncrement = this.getDepthIncrement(maxDepth);
_.each(this.visNodeMap, function(visNode) {
@ -279,6 +293,8 @@ GitVisuals.prototype.drawTreeFirstTime = function() {
this.visBranchCollection.each(function(visBranch) {
visBranch.genGraphics(paper);
}, this);
this.refreshTree();
};