mirror of
https://github.com/pcottle/learnGitBranching.git
synced 2025-06-27 16:38:50 +02:00
BIG move towards backbone models and collections for everything
This commit is contained in:
parent
95277013e5
commit
5ac6b035f5
9 changed files with 290 additions and 234 deletions
|
@ -3,3 +3,75 @@ var CommitCollection = Backbone.Collection.extend({
|
|||
});
|
||||
|
||||
var commitCollection = new CommitCollection();
|
||||
|
||||
var CommandCollection = Backbone.Collection.extend({
|
||||
model: Command
|
||||
});
|
||||
|
||||
var CommandBuffer = Backbone.Model.extend({
|
||||
initialize: function() {
|
||||
events.on('gitCommandReady', _.bind(
|
||||
this.addCommand, this
|
||||
));
|
||||
|
||||
this.collection = new CommandCollection();
|
||||
this.buffer = [];
|
||||
this.timeout = null;
|
||||
this.delay = 300;
|
||||
},
|
||||
|
||||
addCommand: function(command) {
|
||||
this.collection.add(command);
|
||||
this.buffer.push(command);
|
||||
this.touchBuffer();
|
||||
},
|
||||
|
||||
touchBuffer: function() {
|
||||
// touch buffer just essentially means we just check if our buffer is being
|
||||
// processed. if it's not, we immediately process the first item
|
||||
// and then set the timeout.
|
||||
if (this.timeout) {
|
||||
// timeout existence implies its being processed
|
||||
return;
|
||||
}
|
||||
|
||||
// process first element now
|
||||
this.popAndProcess();
|
||||
// always set the timeout, regardless of buffer size
|
||||
this.setTimeout();
|
||||
},
|
||||
|
||||
|
||||
setTimeout: function() {
|
||||
this.timeout = setTimeout(_.bind(function() {
|
||||
this.sipFromBuffer();
|
||||
}, this), 300);
|
||||
},
|
||||
|
||||
popAndProcess: function() {
|
||||
var popped = this.buffer.pop();
|
||||
events.trigger('processCommand', popped);
|
||||
},
|
||||
|
||||
clear: function() {
|
||||
clearTimeout(this.timeout);
|
||||
this.timeout = null;
|
||||
},
|
||||
|
||||
sipFromBuffer: function() {
|
||||
if (!this.buffer.length) {
|
||||
this.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
this.popAndProcess();
|
||||
if (this.buffer.length) {
|
||||
this.setTimeout();
|
||||
} else {
|
||||
this.clear();
|
||||
}
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
var commandBuffer = new CommandBuffer();
|
||||
|
|
|
@ -1,16 +1,25 @@
|
|||
/**
|
||||
* class Command
|
||||
* @desc A parser for commands given
|
||||
*/
|
||||
function Command(str) {
|
||||
this.fullCommand = null;
|
||||
this.options = null;
|
||||
this.method = null;
|
||||
var Command = Backbone.Model.extend({
|
||||
defaults: {
|
||||
status: 'inqueue',
|
||||
generalArgs: [],
|
||||
supportedMap: {},
|
||||
options: null,
|
||||
method: null,
|
||||
rawStr: null
|
||||
},
|
||||
|
||||
this.parse(str);
|
||||
validateAtInit: function() {
|
||||
if (!this.get('rawStr')) {
|
||||
throw new Error('Give me a string!');
|
||||
}
|
||||
},
|
||||
|
||||
Command.prototype.getShortcutMap = function() {
|
||||
initialize: function() {
|
||||
this.validateAtInit();
|
||||
this.parse();
|
||||
},
|
||||
|
||||
getShortcutMap: function() {
|
||||
return {
|
||||
'git commit': /^gc($|\s)/,
|
||||
'git add': /^ga($|\s)/,
|
||||
|
@ -18,9 +27,9 @@ Command.prototype.getShortcutMap = function() {
|
|||
'git rebase': /^gr($|\s)/,
|
||||
'git branch': /^gb($|\s)/
|
||||
};
|
||||
};
|
||||
},
|
||||
|
||||
Command.prototype.getRegexMap = function() {
|
||||
getRegexMap: function() {
|
||||
return {
|
||||
// ($|\s) means that we either have to end the string
|
||||
// after the command or there needs to be a space for options
|
||||
|
@ -33,9 +42,9 @@ Command.prototype.getRegexMap = function() {
|
|||
revert: /^revert($|\s)/,
|
||||
merge: /^merge($|\s)/
|
||||
};
|
||||
};
|
||||
},
|
||||
|
||||
Command.prototype.getSandboxCommands = function() {
|
||||
getSandboxCommands: function() {
|
||||
return [
|
||||
[/^ls/, function() {
|
||||
throw new CommandResult({
|
||||
|
@ -59,9 +68,10 @@ Command.prototype.getSandboxCommands = function() {
|
|||
});
|
||||
}]
|
||||
];
|
||||
};
|
||||
},
|
||||
|
||||
Command.prototype.parse = function(str) {
|
||||
parse: function() {
|
||||
var str = this.get('rawStr');
|
||||
// first if the string is empty, they just want a blank line
|
||||
if (!str.length) {
|
||||
throw new CommandResult({msg: ""});
|
||||
|
@ -93,32 +103,38 @@ Command.prototype.parse = function(str) {
|
|||
|
||||
// ok, we have a (probably) valid command. actually parse it
|
||||
this.gitParse(str);
|
||||
};
|
||||
},
|
||||
|
||||
Command.prototype.gitParse = function(str) {
|
||||
gitParse: function(str) {
|
||||
// now slice off command part
|
||||
this.fullCommand = str.slice('git '.length);
|
||||
var fullCommand = str.slice('git '.length);
|
||||
|
||||
// see if we support this particular command
|
||||
var matched = false;
|
||||
_.each(this.getRegexMap(), function(regex, method) {
|
||||
if (regex.exec(this.fullCommand)) {
|
||||
this.options = this.fullCommand.slice(method.length + 1);
|
||||
this.method = method;
|
||||
if (regex.exec(fullCommand)) {
|
||||
this.set('options', fullCommand.slice(method.length + 1));
|
||||
this.set('method', method);
|
||||
// we should stop iterating, but the regex will only match
|
||||
// one command in practice
|
||||
matched = true;
|
||||
// one command in practice. we could stop iterating if we used
|
||||
// jqeurys for each but im using underscore (for no real reason other
|
||||
// than style)
|
||||
}
|
||||
}, this);
|
||||
|
||||
if (!matched) {
|
||||
if (!this.get('method')) {
|
||||
throw new CommandProcessError({
|
||||
msg: "Sorry, this demo does not support that git command: " + this.fullCommand
|
||||
msg: "Sorry, this demo does not support that git command: " + fullCommand
|
||||
});
|
||||
}
|
||||
|
||||
this.optionParser = new OptionParser(this.method, this.options);
|
||||
};
|
||||
// parse off the options and assemble the map / general args
|
||||
var optionParser = new OptionParser(this.get('method'), this.get('options'));
|
||||
|
||||
// steal these away so we can be completely JSON
|
||||
this.set('generalArgs', optionParser.generalArgs);
|
||||
this.set('supportedMap', optionParser.supportedMap);
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* OptionParser
|
||||
|
@ -203,4 +219,3 @@ OptionParser.prototype.explodeAndSet = function() {
|
|||
// done!
|
||||
};
|
||||
|
||||
|
||||
|
|
13
src/git.js
13
src/git.js
|
@ -20,7 +20,7 @@ function GitEngine() {
|
|||
this.commandOptions = {};
|
||||
this.generalArgs = [];
|
||||
|
||||
events.on('gitCommandReady', _.bind(this.dispatch, this));
|
||||
events.on('processCommand', _.bind(this.dispatch, this));
|
||||
|
||||
this.init();
|
||||
}
|
||||
|
@ -675,11 +675,14 @@ GitEngine.prototype.deleteBranch = function(name) {
|
|||
this.branches.splice(toDelete, 1);
|
||||
};
|
||||
|
||||
GitEngine.prototype.dispatch = function(commandObj) {
|
||||
this.commandOptions = commandObj.optionParser.supportedMap;
|
||||
this.generalArgs = commandObj.optionParser.generalArgs;
|
||||
GitEngine.prototype.dispatch = function(command) {
|
||||
// current command, options, and args are stored in the gitEngine
|
||||
// for easy reference during processing.
|
||||
this.command = command;
|
||||
this.commandOptions = command.get('supportedMap');
|
||||
this.generalArgs = command.get('generalArgs');
|
||||
|
||||
this[commandObj.method + 'Starter']();
|
||||
this[command.get('method') + 'Starter']();
|
||||
};
|
||||
|
||||
GitEngine.prototype.addStarter = function() {
|
||||
|
|
|
@ -42,6 +42,18 @@
|
|||
<script src="../lib/underscore-min.js"></script>
|
||||
<script src="../lib/backbone-min.js"></script>
|
||||
|
||||
<!-- Templates -->
|
||||
<script type="text/html" id="command-template">
|
||||
<p class="commandLine <%= status %>">
|
||||
<span class="arrows">> > ></span>
|
||||
<%= rawStr %>
|
||||
</p>
|
||||
|
||||
<p class="commandLine <%= resultType %>">
|
||||
<%= result %>
|
||||
</p>
|
||||
</script>
|
||||
|
||||
<!-- My files! -->
|
||||
<script src="async.js"></script>
|
||||
<script src="mine.js"></script>
|
||||
|
|
95
src/mine.js
95
src/mine.js
|
@ -11,7 +11,7 @@ $(document).ready(function(){
|
|||
sys = arbor.ParticleSystem(4000, 200, 0.5, false, 55, 0.005, 'verlet');
|
||||
sys.renderer = Renderer('#viewport');
|
||||
|
||||
new CommandLineView({
|
||||
new CommandPromptView({
|
||||
el: $('#commandLineBar')
|
||||
});
|
||||
new CommandLineHistoryView({
|
||||
|
@ -20,14 +20,6 @@ $(document).ready(function(){
|
|||
|
||||
gitEngine = new GitEngine();
|
||||
gitVisuals = new GitVisuals();
|
||||
|
||||
var repulsionBreathe = function(r) {
|
||||
sys.parameters({repulsion: r});
|
||||
};
|
||||
// TODO: decide on breather
|
||||
// var b = new Breather(repulsionBreathe, 6050, 4000);
|
||||
|
||||
graphicsEffects.edgeStrokeEffect = new GraphicsEffect('edgeStroke', {wait: 1000});
|
||||
});
|
||||
|
||||
|
||||
|
@ -73,88 +65,3 @@ Edge.prototype.drawLine = function(ctx, pt1, pt2, opacityPercent) {
|
|||
ctx.stroke();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* class GraphicsEffect
|
||||
*/
|
||||
function GraphicsEffect(gKey, options) {
|
||||
this.baseColor = graphics[gKey];
|
||||
|
||||
this.closure = (function(base_color) {
|
||||
var oSetter = function(o) {
|
||||
var color = new Color(base_color);
|
||||
color.a *= o;
|
||||
graphics[gKey] = color.toRGBA();
|
||||
};
|
||||
return oSetter;
|
||||
})(this.baseColor);
|
||||
|
||||
this.breather = new Breather(
|
||||
this.closure,
|
||||
options.midpoint || 0.9,
|
||||
options.amp || 0.85,
|
||||
options.period || 0.1,
|
||||
options.wait || 0
|
||||
);
|
||||
}
|
||||
|
||||
GraphicsEffect.prototype.pause = function() {
|
||||
this.breather.stop();
|
||||
};
|
||||
|
||||
GraphicsEffect.prototype.resume = function() {
|
||||
this.breather.next();
|
||||
};
|
||||
|
||||
/**
|
||||
* class Breather
|
||||
*/
|
||||
function Breather(closure, baseline, delta, period, wait) {
|
||||
this.delta = delta;
|
||||
this.baseline = baseline;
|
||||
this.closure = closure;
|
||||
|
||||
this.t = 0;
|
||||
this.interval = 1/40 * 1000; // 40fps
|
||||
|
||||
var period_in_seconds = period || time.breathePeriod;
|
||||
this.period = 2 * Math.PI * 1000 * period_in_seconds;
|
||||
|
||||
this.interpolationFunction = TWEEN.Easing.Cubic.EaseInOut;
|
||||
|
||||
if (wait) {
|
||||
var _this = this;
|
||||
setTimeout(function() {
|
||||
_this.start();
|
||||
}, wait);
|
||||
} else {
|
||||
this.start();
|
||||
}
|
||||
}
|
||||
|
||||
Breather.prototype.start = function() {
|
||||
this.t = 0;
|
||||
this.next();
|
||||
};
|
||||
|
||||
Breather.prototype.next = function() {
|
||||
this.timeout = setTimeout(
|
||||
$.proxy(function() {
|
||||
this.breathe();
|
||||
}, this),
|
||||
this.interval);
|
||||
};
|
||||
|
||||
Breather.prototype.stop = function() {
|
||||
clearTimeout(this.timeout);
|
||||
};
|
||||
|
||||
Breather.prototype.breathe = function() {
|
||||
this.t += this.interval;
|
||||
|
||||
var value = Math.sin(this.t / this.period) * this.delta + this.baseline;
|
||||
this.closure(value);
|
||||
|
||||
this.next();
|
||||
};
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ p.commandError, p.errorResult {
|
|||
color: red;
|
||||
}
|
||||
|
||||
span.arrows {
|
||||
p.commandLine span.arrows {
|
||||
color: greenyellow;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
<p class="<%= class %>">
|
||||
<span class="arrows"> > > > </span>
|
||||
<%= command %>
|
||||
</p>
|
78
src/views.js
78
src/views.js
|
@ -1,15 +1,19 @@
|
|||
var CommandLineView = Backbone.View.extend({
|
||||
var CommandPromptView = Backbone.View.extend({
|
||||
initialize: function(options) {
|
||||
this.commands = [];
|
||||
this.index = -1;
|
||||
|
||||
this.$('#commandTextField').keyup(
|
||||
$.proxy(this.keyUp, this)
|
||||
);
|
||||
|
||||
events.on('commandReadyForProcess', _.bind(
|
||||
events.on('commandSubmitted', _.bind(
|
||||
this.parseOrCatch, this
|
||||
));
|
||||
|
||||
events.on('processErrorGeneral', _.bind(
|
||||
this.processError, this
|
||||
));
|
||||
},
|
||||
|
||||
events: {
|
||||
'keyup #commandTextField': 'keyUp'
|
||||
},
|
||||
|
||||
keyUp: function(e) {
|
||||
|
@ -39,7 +43,8 @@ var CommandLineView = Backbone.View.extend({
|
|||
commandSelectChange: function(delta) {
|
||||
this.index += delta;
|
||||
|
||||
// if we are over / under, display blank line
|
||||
// if we are over / under, display blank line. yes this eliminates your
|
||||
// partially written command, but i doubt that is much in this demo
|
||||
if (this.index >= this.commands.length || this.index < 0) {
|
||||
this.clear();
|
||||
this.index = -1;
|
||||
|
@ -51,6 +56,8 @@ var CommandLineView = Backbone.View.extend({
|
|||
},
|
||||
|
||||
processError: function(err) {
|
||||
// TODO move this somewhere else!!! it's awkward here
|
||||
|
||||
// in this demo, every command that's not a git command will
|
||||
// throw an exception. Some of these errors might be just to
|
||||
// short-circuit the normal programatic flow and print stuff,
|
||||
|
@ -59,6 +66,8 @@ var CommandLineView = Backbone.View.extend({
|
|||
events.trigger('commandProcessError', err);
|
||||
} else if (err instanceof CommandResult) {
|
||||
events.trigger('commandResultPrint', err);
|
||||
} else if (err instanceof GitError) {
|
||||
events.trigger('commandGitError', err);
|
||||
} else {
|
||||
throw err;
|
||||
}
|
||||
|
@ -82,26 +91,70 @@ var CommandLineView = Backbone.View.extend({
|
|||
}
|
||||
this.index = -1;
|
||||
|
||||
// split commands on semicolon
|
||||
_.each(value.split(';'), function(command) {
|
||||
command = command.replace(/^(\s+)/, '');
|
||||
command = command.replace(/(\s+)$/, '');
|
||||
if (command.length) {
|
||||
events.trigger('commandSubmitted', command);
|
||||
events.trigger('commandReadyForProcess', command);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
parseOrCatch: function(value) {
|
||||
// TODO: move this also
|
||||
try {
|
||||
var command = new Command(value);
|
||||
// parse validation
|
||||
var command = new Command({
|
||||
rawStr: value
|
||||
});
|
||||
// gitCommandReady actually gives it to the gitEngine for dispatch
|
||||
events.trigger('gitCommandReady', command);
|
||||
} catch (err) {
|
||||
this.processError(err);
|
||||
events.trigger('processErrorGeneral', err);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// This is the view for all commands -- it will represent
|
||||
// their status (inqueue, processing, finished, error),
|
||||
// their value ("git commit --amend"),
|
||||
// and the result (either errors or warnings or whatever)
|
||||
var CommandView = Backbone.View.extend({
|
||||
tagName: 'div',
|
||||
model: Command,
|
||||
template: _.template($('#command-template').html()),
|
||||
|
||||
events: {
|
||||
'click': 'alert'
|
||||
},
|
||||
|
||||
alert: function() { alert('clicked!' + this.get('status')); },
|
||||
|
||||
initialize: function() {
|
||||
this.model.bind('change', this.render, this);
|
||||
this.model.bind('destroy', this.remove, this);
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var json = _.extend(
|
||||
{
|
||||
resultType: '',
|
||||
result: ''
|
||||
},
|
||||
this.model.toJSON()
|
||||
);
|
||||
this.$el.html(this.template(json));
|
||||
return this;
|
||||
},
|
||||
|
||||
remove: function() {
|
||||
$(this.el).hide();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
var CommandLineHistoryView = Backbone.View.extend({
|
||||
initialize: function(options) {
|
||||
events.on('commandSubmitted', _.bind(
|
||||
|
@ -112,6 +165,11 @@ var CommandLineHistoryView = Backbone.View.extend({
|
|||
this.commandError, this
|
||||
));
|
||||
|
||||
// TODO special errors for git?
|
||||
events.on('commandGitError', _.bind(
|
||||
this.commandError, this
|
||||
));
|
||||
|
||||
events.on('commandProcessWarn', _.bind(
|
||||
this.commandWarn, this
|
||||
));
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
function GitVisuals() {
|
||||
this.collection = commitCollection;
|
||||
|
||||
this.collection.on('change', _.bind(this.collectionChanged, this));
|
||||
events.on('drawGitVisuals', _.bind(this.drawVisuals, this));
|
||||
events.on('fixNodePositions', _.bind(this.fixNodes, this));
|
||||
}
|
||||
|
@ -74,10 +71,6 @@ GitVisuals.prototype.drawArrow = function(ctx, start, end, headWidth, offset) {
|
|||
ctx.stroke();
|
||||
};
|
||||
|
||||
GitVisuals.prototype.collectionChanged = function() {
|
||||
// redo the algorithms
|
||||
};
|
||||
|
||||
GitVisuals.prototype.fixRootCommit = function(sys) {
|
||||
// get the viewports bottom center
|
||||
var bottomPosScreen = {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue