mirror of
https://github.com/pcottle/learnGitBranching.git
synced 2025-06-27 16:38:50 +02:00
in th emiddle of transitioning to box flex
This commit is contained in:
parent
f0e45deb1e
commit
fb2a1325c6
7 changed files with 108 additions and 555 deletions
|
@ -1,255 +0,0 @@
|
||||||
var Command = Backbone.Model.extend({
|
|
||||||
defaults: {
|
|
||||||
status: 'inqueue',
|
|
||||||
result: '',
|
|
||||||
error: null,
|
|
||||||
generalArgs: [],
|
|
||||||
supportedMap: {},
|
|
||||||
options: null,
|
|
||||||
method: null,
|
|
||||||
createTime: null,
|
|
||||||
rawStr: null
|
|
||||||
},
|
|
||||||
|
|
||||||
validateAtInit: function() {
|
|
||||||
if (!this.get('rawStr')) {
|
|
||||||
throw new Error('Give me a string!');
|
|
||||||
}
|
|
||||||
if (!this.get('createTime')) {
|
|
||||||
this.set('createTime', new Date().toString());
|
|
||||||
}
|
|
||||||
this.on('change:error', this.errorChanged, this);
|
|
||||||
},
|
|
||||||
|
|
||||||
initialize: function() {
|
|
||||||
this.validateAtInit();
|
|
||||||
this.parseOrCatch();
|
|
||||||
},
|
|
||||||
|
|
||||||
parseOrCatch: function() {
|
|
||||||
try {
|
|
||||||
this.parse();
|
|
||||||
} catch (err) {
|
|
||||||
if (err instanceof CommandProcessError ||
|
|
||||||
err instanceof GitError) {
|
|
||||||
this.set('status', 'error');
|
|
||||||
this.set('error', err);
|
|
||||||
} else if (err instanceof CommandResult) {
|
|
||||||
this.set('status', 'finished');
|
|
||||||
this.set('error', err);
|
|
||||||
} else {
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
errorChanged: function(model, err) {
|
|
||||||
this.set('err', err);
|
|
||||||
this.set('status', 'error');
|
|
||||||
this.formatError();
|
|
||||||
},
|
|
||||||
|
|
||||||
formatError: function() {
|
|
||||||
this.set('result', this.get('err').toResult());
|
|
||||||
},
|
|
||||||
|
|
||||||
getShortcutMap: function() {
|
|
||||||
return {
|
|
||||||
'git commit': /^gc($|\s)/,
|
|
||||||
'git add': /^ga($|\s)/,
|
|
||||||
'git checkout': /^gchk($|\s)/,
|
|
||||||
'git rebase': /^gr($|\s)/,
|
|
||||||
'git branch': /^gb($|\s)/
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
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
|
|
||||||
commit: /^commit($|\s)/,
|
|
||||||
add: /^add($|\s)/,
|
|
||||||
checkout: /^checkout($|\s)/,
|
|
||||||
rebase: /^rebase($|\s)/,
|
|
||||||
reset: /^reset($|\s)/,
|
|
||||||
branch: /^branch($|\s)/,
|
|
||||||
revert: /^revert($|\s)/,
|
|
||||||
merge: /^merge($|\s)/
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
getSandboxCommands: function() {
|
|
||||||
return [
|
|
||||||
[/^ls/, function() {
|
|
||||||
throw new CommandResult({
|
|
||||||
msg: "DontWorryAboutFilesInThisDemo.txt"
|
|
||||||
});
|
|
||||||
}],
|
|
||||||
[/^cd/, function() {
|
|
||||||
throw new CommandResult({
|
|
||||||
msg: "Directory Changed to '/directories/dont/matter/in/this/demo'"
|
|
||||||
});
|
|
||||||
}],
|
|
||||||
[/^git$/, function() {
|
|
||||||
// TODO better git description. also help, hint, etc
|
|
||||||
throw new CommandResult({
|
|
||||||
msg: _.escape("\
|
|
||||||
Git Version \n \
|
|
||||||
PCOTTLE.1.0 \
|
|
||||||
Usage: \n \
|
|
||||||
git <command> [<args>] \
|
|
||||||
")
|
|
||||||
});
|
|
||||||
}]
|
|
||||||
];
|
|
||||||
},
|
|
||||||
|
|
||||||
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: ""});
|
|
||||||
}
|
|
||||||
|
|
||||||
// then check if it's one of our sandbox commands
|
|
||||||
_.each(this.getSandboxCommands(), function(tuple) {
|
|
||||||
var regex = tuple[0];
|
|
||||||
if (regex.exec(str)) {
|
|
||||||
tuple[1]();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// then check if shortcut exists, and replace, but
|
|
||||||
// preserve options if so
|
|
||||||
_.each(this.getShortcutMap(), function(regex, method) {
|
|
||||||
var results = regex.exec(str);
|
|
||||||
if (results) {
|
|
||||||
str = method + ' ' + str.slice(results[0].length);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// see if begins with git
|
|
||||||
if (str.slice(0,3) !== 'git') {
|
|
||||||
throw new CommandProcessError({
|
|
||||||
msg: 'Git commands only, sorry!'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// ok, we have a (probably) valid command. actually parse it
|
|
||||||
this.gitParse(str);
|
|
||||||
},
|
|
||||||
|
|
||||||
gitParse: function(str) {
|
|
||||||
// now slice off command part
|
|
||||||
var fullCommand = str.slice('git '.length);
|
|
||||||
|
|
||||||
// see if we support this particular command
|
|
||||||
_.each(this.getRegexMap(), function(regex, 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. we could stop iterating if we used
|
|
||||||
// jqeurys for each but im using underscore (for no real reason other
|
|
||||||
// than style)
|
|
||||||
}
|
|
||||||
}, this);
|
|
||||||
|
|
||||||
if (!this.get('method')) {
|
|
||||||
throw new CommandProcessError({
|
|
||||||
msg: "Sorry, this demo does not support that git command: " + fullCommand
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
|
||||||
*/
|
|
||||||
function OptionParser(method, options) {
|
|
||||||
this.method = method;
|
|
||||||
this.rawOptions = options;
|
|
||||||
|
|
||||||
this.supportedMap = this.getMasterOptionMap()[method];
|
|
||||||
if (this.supportedMap === undefined) {
|
|
||||||
throw new Error('No option map for ' + method);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.generalArgs = [];
|
|
||||||
this.explodeAndSet();
|
|
||||||
}
|
|
||||||
|
|
||||||
OptionParser.prototype.getMasterOptionMap = function() {
|
|
||||||
// here a value of false means that we support it, even if its just a
|
|
||||||
// pass-through option. If the value is not here (aka will be undefined
|
|
||||||
// when accessed), we do not support it.
|
|
||||||
return {
|
|
||||||
commit: {
|
|
||||||
'--amend': false,
|
|
||||||
'-a': false, // warning
|
|
||||||
'-am': false
|
|
||||||
},
|
|
||||||
add: {},
|
|
||||||
branch: {
|
|
||||||
'-d': false,
|
|
||||||
'-D': false
|
|
||||||
},
|
|
||||||
checkout: {
|
|
||||||
'-b': false
|
|
||||||
},
|
|
||||||
reset: {
|
|
||||||
'--hard': false,
|
|
||||||
'--soft': false, // this will raise an error but we catch it in gitEngine
|
|
||||||
},
|
|
||||||
merge: {},
|
|
||||||
rebase: {},
|
|
||||||
revert: {}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
OptionParser.prototype.explodeAndSet = function() {
|
|
||||||
// split on spaces, except when inside quotes, and strip quotes after.
|
|
||||||
// for some reason the regex includes the quotes even if i move the parantheses
|
|
||||||
// inside
|
|
||||||
var exploded = this.rawOptions.match(/('.*?'|".*?"|\S+)/g) || [];
|
|
||||||
_.each(exploded, function(part, i) {
|
|
||||||
exploded[i] = part.replace(/['"]/g, '');
|
|
||||||
});
|
|
||||||
|
|
||||||
for (var i = 0; i < exploded.length; i++) {
|
|
||||||
var part = exploded[i];
|
|
||||||
if (part.slice(0,1) == '-') {
|
|
||||||
// it's an option, check supportedMap
|
|
||||||
if (this.supportedMap[part] === undefined) {
|
|
||||||
throw new CommandProcessError({
|
|
||||||
msg: 'The option "' + part + '" is not supported'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// go through and include all the next args until we hit another option or the end
|
|
||||||
var optionArgs = [];
|
|
||||||
var next = i + 1;
|
|
||||||
while (next < exploded.length && exploded[next].slice(0,1) != '-') {
|
|
||||||
optionArgs.push(exploded[next]);
|
|
||||||
next += 1;
|
|
||||||
}
|
|
||||||
i = next - 1;
|
|
||||||
|
|
||||||
// **phew** we are done grabbing those. theseArgs is truthy even with an empty array
|
|
||||||
this.supportedMap[part] = optionArgs;
|
|
||||||
} else {
|
|
||||||
// must be a general arg
|
|
||||||
this.generalArgs.push(part);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// done!
|
|
||||||
};
|
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
// backbone or something uses _.uniqueId, so we make our own here
|
// backbone or something uses _.uniqueId, so we make our own here
|
||||||
var uniqueId = (function() {
|
var uniqueId = (function() {
|
||||||
var n = 0;
|
var n = 0;
|
||||||
|
@ -799,7 +798,8 @@ var Branch = Ref.extend({
|
||||||
var Commit = Backbone.Model.extend({
|
var Commit = Backbone.Model.extend({
|
||||||
defaults: {
|
defaults: {
|
||||||
type: 'commit',
|
type: 'commit',
|
||||||
children: []
|
children: [],
|
||||||
|
parents: []
|
||||||
},
|
},
|
||||||
|
|
||||||
validateAtInit: function() {
|
validateAtInit: function() {
|
||||||
|
@ -808,9 +808,7 @@ var Commit = Backbone.Model.extend({
|
||||||
}
|
}
|
||||||
|
|
||||||
// root commits have no parents
|
// root commits have no parents
|
||||||
if (this.get('rootCommit')) {
|
if (!this.get('rootCommit')) {
|
||||||
this.set('parents', []);
|
|
||||||
} else {
|
|
||||||
if (!this.get('parents') || !this.get('parents').length) {
|
if (!this.get('parents') || !this.get('parents').length) {
|
||||||
throw new Error('needs parents');
|
throw new Error('needs parents');
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,23 +10,34 @@
|
||||||
<link rel="stylesheet" href="style/font-awesome.css" type="text/css" charset="utf-8">
|
<link rel="stylesheet" href="style/font-awesome.css" type="text/css" charset="utf-8">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<canvas id="viewport" width="800" height="600"></canvas>
|
|
||||||
|
<div id="interfaceWrapper" class="box horizontal flex1">
|
||||||
|
<div id="controls" class="box vertical flex1">
|
||||||
|
<div id="hintsEtc" class="box vertical flex3">
|
||||||
|
</div>
|
||||||
|
|
||||||
<div id="controls">
|
<div id="commandLineHistory" class="box vertical flex3">
|
||||||
<div id="commandLineHistory">
|
<div id="commandDisplay">
|
||||||
<div id="commandDisplay">
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="commandLineBar" class="box vertical flex0">
|
||||||
|
<textarea id="commandTextField"></textarea>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="commandLineBar">
|
|
||||||
<textarea id="commandTextField"></textarea>
|
<div id="canvasWrapper" class="box flex1">
|
||||||
|
<canvas id="treeCanvas" width="20" height="20"></canvas>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- *******************************************
|
||||||
|
Scripts from here on out
|
||||||
|
****************************************** -->
|
||||||
<script src="../lib/jquery-1.8.0.min.js"></script>
|
<script src="../lib/jquery-1.8.0.min.js"></script>
|
||||||
|
|
||||||
<script src="../lib/Tween.js"></script>
|
|
||||||
<script src="../lib/underscore-min.js"></script>
|
<script src="../lib/underscore-min.js"></script>
|
||||||
<script src="../lib/backbone-min.js"></script>
|
<script src="../lib/backbone-min.js"></script>
|
||||||
|
<script src="../lib/raphael-min.js"></script>
|
||||||
|
|
||||||
<!-- Templates -->
|
<!-- Templates -->
|
||||||
<script type="text/html" id="command-template">
|
<script type="text/html" id="command-template">
|
||||||
|
@ -47,15 +58,24 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<!-- My files! -->
|
<!-- My files! -->
|
||||||
<script src="async.js"></script>
|
|
||||||
<script src="main.js"></script>
|
<script src="main.js"></script>
|
||||||
|
|
||||||
|
<script src="async.js"></script>
|
||||||
<script src="constants.js"></script>
|
<script src="constants.js"></script>
|
||||||
<script src="git.js"></script>
|
|
||||||
<script src="commandline.js"></script>
|
|
||||||
<script src="views.js"></script>
|
|
||||||
<script src="errors.js"></script>
|
<script src="errors.js"></script>
|
||||||
|
|
||||||
|
<!-- the beefy git engine -->
|
||||||
|
<script src="git.js"></script>
|
||||||
|
|
||||||
|
<!-- command line -->
|
||||||
|
<script src="commandModel.js"></script>
|
||||||
|
<script src="commandViews.js"></script>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- vis -->
|
||||||
<script src="collections.js"></script>
|
<script src="collections.js"></script>
|
||||||
<script src="visuals.js"></script>
|
<script src="visuals.js"></script>
|
||||||
<script src="tree.js"></script>
|
<script src="tree.js"></script>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -1,18 +1,62 @@
|
||||||
html, body {
|
html {
|
||||||
overflow:hidden;
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin: 0px;
|
||||||
|
border: 0px;
|
||||||
|
padding: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
html, body {
|
||||||
|
/*
|
||||||
background: -moz-radial-gradient(center, ellipse cover, #0066cc 0%, #000000 90%);
|
background: -moz-radial-gradient(center, ellipse cover, #0066cc 0%, #000000 90%);
|
||||||
background: -webkit-gradient(radial, center center, 0px, center center, 100%, color-stop(0%,#0066cc), color-stop(90%,#000000));
|
background: -webkit-gradient(radial, center center, 0px, center center, 100%, color-stop(0%,#0066cc), color-stop(90%,#000000));
|
||||||
background: -webkit-radial-gradient(center, ellipse cover, #0066cc 0%,#000 90%);
|
background: -webkit-radial-gradient(center, ellipse cover, #0066cc 0%,#000 90%);
|
||||||
background: -o-radial-gradient(center, ellipse cover, #0066cc 0%,#000000 90%);
|
background: -o-radial-gradient(center, ellipse cover, #0066cc 0%,#000000 90%);
|
||||||
background: -ms-radial-gradient(center, ellipse cover, #0066cc 0%,#000000 90%);
|
background: -ms-radial-gradient(center, ellipse cover, #0066cc 0%,#000000 90%);
|
||||||
background: radial-gradient(center, ellipse cover, #0066cc 0%,#000000 90%);
|
background: radial-gradient(center, ellipse cover, #0066cc 0%,#000000 90%); */
|
||||||
-webkit-perspective:600px;
|
|
||||||
|
-webkit-perspective: 600px;
|
||||||
|
|
||||||
font-family: Monaco, Courier, font-monospace;
|
font-family: Monaco, Courier, font-monospace;
|
||||||
color: #eee;
|
color: #eee;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Box Model */
|
||||||
|
html,
|
||||||
|
body,
|
||||||
|
div.box {
|
||||||
|
display: -webkit-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.flex0 {
|
||||||
|
-webkit-box-flex: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
body,
|
||||||
|
div.flex1 {
|
||||||
|
-webkit-box-flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.flex2 {
|
||||||
|
-webkit-box-flex: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.flex3 {
|
||||||
|
-webkit-box-flex: 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
html,
|
||||||
|
body,
|
||||||
|
div.vertical {
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.horizontal {
|
||||||
|
-webkit-box-orient: horizontal;
|
||||||
|
}
|
||||||
|
|
||||||
/* Transition */
|
/* Transition */
|
||||||
.transitionBackground {
|
.transitionBackground {
|
||||||
-webkit-transition: background 700ms cubic-bezier(0.260, 0.860, 0.440, 0.985);
|
-webkit-transition: background 700ms cubic-bezier(0.260, 0.860, 0.440, 0.985);
|
||||||
|
@ -30,17 +74,21 @@ html, body {
|
||||||
transition: opacity 1700ms cubic-bezier(0.260, 0.860, 0.440, 0.985);
|
transition: opacity 1700ms cubic-bezier(0.260, 0.860, 0.440, 0.985);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#treeCanvas {
|
||||||
|
border: 3px solid black;
|
||||||
|
}
|
||||||
|
|
||||||
|
#interfaceWrapper {
|
||||||
|
min-width: 600px;
|
||||||
|
}
|
||||||
|
|
||||||
#controls {
|
#controls {
|
||||||
position: absolute;
|
}
|
||||||
top: 0px;
|
|
||||||
left: 0px;
|
#canvasWrapper {
|
||||||
width: 50%;
|
|
||||||
height: 100%;
|
|
||||||
-webkit-box-orientation: vertical;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#commandTextField {
|
#commandTextField {
|
||||||
width: 90%;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
p.commandLine, p.commandLineResult {
|
p.commandLine, p.commandLineResult {
|
||||||
|
@ -103,8 +151,6 @@ p.commandLine span.arrows {
|
||||||
}
|
}
|
||||||
|
|
||||||
#commandLineHistory {
|
#commandLineHistory {
|
||||||
width: 100%;
|
|
||||||
height: 200px;
|
|
||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
background: #000;
|
background: #000;
|
||||||
opacity: 0.85;
|
opacity: 0.85;
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
var VisNode = Backbone.Model.extend({
|
||||||
|
});
|
||||||
|
|
||||||
|
var VisEdge = Backbone.Model.extend({
|
||||||
|
});
|
187
src/views.js
187
src/views.js
|
@ -1,187 +0,0 @@
|
||||||
var CommandPromptView = Backbone.View.extend({
|
|
||||||
initialize: function(options) {
|
|
||||||
this.collection = options.collection;
|
|
||||||
this.commands = [];
|
|
||||||
this.index = -1;
|
|
||||||
},
|
|
||||||
|
|
||||||
events: {
|
|
||||||
'keyup #commandTextField': 'keyUp'
|
|
||||||
},
|
|
||||||
|
|
||||||
keyUp: function(e) {
|
|
||||||
// we need to capture some of these events.
|
|
||||||
// WARNING: this key map is not internationalized :(
|
|
||||||
var keyMap = {
|
|
||||||
// enter
|
|
||||||
13: _.bind(function() {
|
|
||||||
this.submit();
|
|
||||||
}, this),
|
|
||||||
// up
|
|
||||||
38: _.bind(function() {
|
|
||||||
this.commandSelectChange(1);
|
|
||||||
}, this),
|
|
||||||
// down
|
|
||||||
40: _.bind(function() {
|
|
||||||
this.commandSelectChange(-1);
|
|
||||||
}, this)
|
|
||||||
};
|
|
||||||
|
|
||||||
if (keyMap[e.which] !== undefined) {
|
|
||||||
e.preventDefault();
|
|
||||||
keyMap[e.which]();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
commandSelectChange: function(delta) {
|
|
||||||
this.index += delta;
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// yay! we actually can display something
|
|
||||||
this.setTextField(this.commands[this.index]);
|
|
||||||
},
|
|
||||||
|
|
||||||
setTextField: function(value) {
|
|
||||||
this.$('#commandTextField').val(value);
|
|
||||||
},
|
|
||||||
|
|
||||||
clear: function() {
|
|
||||||
this.setTextField('');
|
|
||||||
},
|
|
||||||
|
|
||||||
submit: function() {
|
|
||||||
var value = this.$('#commandTextField').val().replace('\n', '');
|
|
||||||
this.clear();
|
|
||||||
|
|
||||||
// if we are entering a real command, add it to our history
|
|
||||||
if (value.length) {
|
|
||||||
this.commands.unshift(value);
|
|
||||||
}
|
|
||||||
this.index = -1;
|
|
||||||
|
|
||||||
// split commands on semicolon
|
|
||||||
_.each(value.split(';'), _.bind(function(command) {
|
|
||||||
command = command.replace(/^(\s+)/, '');
|
|
||||||
command = command.replace(/(\s+)$/, '');
|
|
||||||
if (command.length) {
|
|
||||||
this.addToCollection(command);
|
|
||||||
}
|
|
||||||
}, this));
|
|
||||||
},
|
|
||||||
|
|
||||||
addToCollection: function(value) {
|
|
||||||
var command = new Command({
|
|
||||||
rawStr: value
|
|
||||||
});
|
|
||||||
this.collection.add(command);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
// 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': 'clicked'
|
|
||||||
},
|
|
||||||
|
|
||||||
clicked: function(e) {
|
|
||||||
console.log('was clicked');
|
|
||||||
},
|
|
||||||
|
|
||||||
initialize: function() {
|
|
||||||
this.model.bind('change', this.wasChanged, this);
|
|
||||||
this.model.bind('destroy', this.remove, this);
|
|
||||||
},
|
|
||||||
|
|
||||||
wasChanged: function(model, changeEvent) {
|
|
||||||
console.log('command changed', model, changeEvent);
|
|
||||||
// for changes that are just comestic, we actually only want to toggle classes
|
|
||||||
// with jquery rather than brutally delete a html of HTML
|
|
||||||
var changes = changeEvent.changes;
|
|
||||||
var changeKeys = _.keys(changes);
|
|
||||||
if (_.difference(changeKeys, ['status']) == 0) {
|
|
||||||
this.updateStatus();
|
|
||||||
} else if (_.difference(changeKeys, ['error']) == 0) {
|
|
||||||
// the above will
|
|
||||||
this.render();
|
|
||||||
} else {
|
|
||||||
this.render();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
updateStatus: function() {
|
|
||||||
var statuses = ['inqueue', 'processing', 'finished'];
|
|
||||||
var toggleMap = {};
|
|
||||||
_.each(statuses, function(status) {
|
|
||||||
toggleMap[status] = false;
|
|
||||||
});
|
|
||||||
toggleMap[this.model.get('status')] = true;
|
|
||||||
|
|
||||||
var query = this.$('p.commandLine');
|
|
||||||
|
|
||||||
_.each(toggleMap, function(value, key) {
|
|
||||||
query.toggleClass(key, value);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
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) {
|
|
||||||
this.collection = options.collection;
|
|
||||||
|
|
||||||
this.collection.on('add', this.addOne, this);
|
|
||||||
this.collection.on('reset', this.addAll, this);
|
|
||||||
this.collection.on('all', this.render, this);
|
|
||||||
|
|
||||||
this.collection.on('change', this.scrollDown, this);
|
|
||||||
},
|
|
||||||
|
|
||||||
scrollDown: function() {
|
|
||||||
var el = $('#commandLineHistory')[0];
|
|
||||||
el.scrollTop = el.scrollHeight;
|
|
||||||
},
|
|
||||||
|
|
||||||
addOne: function(command) {
|
|
||||||
var view = new CommandView({
|
|
||||||
model: command
|
|
||||||
});
|
|
||||||
this.$('#commandDisplay').append(view.render().el);
|
|
||||||
this.scrollDown();
|
|
||||||
},
|
|
||||||
|
|
||||||
addAll: function() {
|
|
||||||
this.collection.each(this.addOne);
|
|
||||||
}
|
|
||||||
});
|
|
|
@ -3,13 +3,14 @@ function GitVisuals(options) {
|
||||||
this.nodeMap = {};
|
this.nodeMap = {};
|
||||||
|
|
||||||
this.collection.on('change', _.bind(this.collectionChanged, this));
|
this.collection.on('change', _.bind(this.collectionChanged, this));
|
||||||
events.on('drawGitVisuals', _.bind(this.drawVisuals, this));
|
|
||||||
events.on('fixNodePositions', _.bind(this.fixNodes, this));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GitVisuals.prototype.addNode = function(id) {
|
GitVisuals.prototype.addNode = function(id) {
|
||||||
var visNode = sys.addNode(id);
|
var visNode = new VisNode({
|
||||||
|
id: id
|
||||||
|
});
|
||||||
this.nodeMap[id] = visNode;
|
this.nodeMap[id] = visNode;
|
||||||
|
|
||||||
return visNode;
|
return visNode;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -22,88 +23,13 @@ GitVisuals.prototype.addEdge = function(idTail, idHead) {
|
||||||
', ' + idHead + ') does not exist');
|
', ' + idHead + ') does not exist');
|
||||||
}
|
}
|
||||||
|
|
||||||
sys.addEdge(visNodeTail, visNodeHead);
|
var edge = new VisEdge({
|
||||||
};
|
tail: visNodeTail,
|
||||||
|
head: visNodeHead
|
||||||
GitVisuals.prototype.drawVisuals = function(sys, ctx, canvas) {
|
});
|
||||||
this.drawRefs(sys, ctx, canvas);
|
|
||||||
};
|
|
||||||
|
|
||||||
GitVisuals.prototype.fixNodes = function(sys) {
|
|
||||||
this.fixRootCommit(sys);
|
|
||||||
};
|
|
||||||
|
|
||||||
GitVisuals.prototype.drawRefs = function(sys, ctx, canvas) {
|
|
||||||
var sFill = graphics.refSelectedFontFill;
|
|
||||||
// we need to draw refs here
|
|
||||||
var branches = gitEngine.getBranches();
|
|
||||||
var detachedHead = gitEngine.getDetachedHead();
|
|
||||||
var HEAD = gitEngine.getHead();
|
|
||||||
|
|
||||||
_.forEach(branches, _.bind(function(branch) {
|
|
||||||
// get the location of the arbor node and then somehow draw the ref to the side?
|
|
||||||
var node = branch.target.get('visNode');
|
|
||||||
var fillStyle = branch.selected ? sFill : undefined;
|
|
||||||
this.drawLabel(ctx, sys, node, branch.id, fillStyle);
|
|
||||||
}, this));
|
|
||||||
|
|
||||||
if (detachedHead) {
|
|
||||||
var node = HEAD.get('target').get('visNode');
|
|
||||||
this.drawLabel(ctx, sys, node, 'HEAD', sFill);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
GitVisuals.prototype.drawLabel = function(ctx, sys, node, name, fillStyle) {
|
|
||||||
fillStyle = fillStyle || graphics.refFontFill;
|
|
||||||
|
|
||||||
var nodePoint = sys.toScreen(node._p);
|
|
||||||
// text position
|
|
||||||
// TODO: better positioning of text here
|
|
||||||
var screenPoint = _.clone(nodePoint);
|
|
||||||
screenPoint.x += 100;
|
|
||||||
|
|
||||||
ctx.font = graphics.refFont;
|
|
||||||
ctx.fillStyle = fillStyle;
|
|
||||||
ctx.fillText(name, screenPoint.x, screenPoint.y);
|
|
||||||
|
|
||||||
// also draw an arrow
|
|
||||||
var offset = Math.round(graphics.nodeRadius * 2.5);
|
|
||||||
this.drawArrow(ctx, screenPoint, nodePoint, graphics.arrowHeadWidth, offset);
|
|
||||||
};
|
|
||||||
|
|
||||||
GitVisuals.prototype.drawArrow = function(ctx, start, end, headWidth, offset) {
|
|
||||||
// TODO only horizontal arrows for now, fix this later
|
|
||||||
var end = _.clone(end);
|
|
||||||
end.x += offset;
|
|
||||||
|
|
||||||
ctx.lineWidth = graphics.arrowWidth;
|
|
||||||
ctx.fillStyle = graphics.arrowFill;
|
|
||||||
ctx.strokeStyle = graphics.arrowStroke;
|
|
||||||
|
|
||||||
ctx.beginPath();
|
|
||||||
ctx.moveTo(start.x, start.y);
|
|
||||||
ctx.lineTo(end.x, end.y);
|
|
||||||
|
|
||||||
// now do the little arrow head
|
|
||||||
ctx.lineTo(end.x + headWidth, end.y + headWidth);
|
|
||||||
ctx.lineTo(end.x + headWidth, end.y - headWidth);
|
|
||||||
ctx.lineTo(end.x, end.y);
|
|
||||||
|
|
||||||
ctx.stroke();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
GitVisuals.prototype.collectionChanged = function() {
|
GitVisuals.prototype.collectionChanged = function() {
|
||||||
// redo the algorithms
|
// redo stuff
|
||||||
};
|
};
|
||||||
|
|
||||||
GitVisuals.prototype.fixRootCommit = function(sys) {
|
|
||||||
// get the viewports bottom center
|
|
||||||
var bottomPosScreen = {
|
|
||||||
x: Math.round($('#viewport').width() * 0.5),
|
|
||||||
y: $('#viewport').height() - graphics.nodeRadius * 2.5
|
|
||||||
};
|
|
||||||
|
|
||||||
var bottomPos = sys.fromScreen(bottomPosScreen);
|
|
||||||
// fix the root commit to the bottom
|
|
||||||
gitEngine.rootCommit.get('visNode').p = bottomPos;
|
|
||||||
};
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue