pcottle.learnGitBranching/src/js/views/multiView.js
2013-01-13 11:09:21 -08:00

199 lines
5 KiB
JavaScript

var _ = require('underscore');
var Q = require('q');
// horrible hack to get localStorage Backbone plugin
var Backbone = (!require('../util').isBrowser()) ? require('backbone') : window.Backbone;
var ModalTerminal = require('../views').ModalTerminal;
var ContainedBase = require('../views').ContainedBase;
var ConfirmCancelView = require('../views').ConfirmCancelView;
var LeftRightView = require('../views').LeftRightView;
var ModalAlert = require('../views').ModalAlert;
var GitDemonstrationView = require('../views/gitDemonstrationView').GitDemonstrationView;
var BuilderViews = require('../views/builderViews');
var MarkdownPresenter = BuilderViews.MarkdownPresenter;
var KeyboardListener = require('../util/keyboard').KeyboardListener;
var GitError = require('../util/errors').GitError;
var MultiView = Backbone.View.extend({
tagName: 'div',
className: 'multiView',
// ms to debounce the nav functions
navEventDebounce: 550,
deathTime: 700,
// a simple mapping of what childViews we support
typeToConstructor: {
ModalAlert: ModalAlert,
GitDemonstrationView: GitDemonstrationView,
MarkdownPresenter: MarkdownPresenter
},
initialize: function(options) {
options = options || {};
this.childViewJSONs = options.childViews || [{
type: 'ModalAlert',
options: {
markdown: 'Woah wtf!!'
}
}, {
type: 'GitDemonstrationView',
options: {
command: 'git checkout -b side; git commit; git commit'
}
}, {
type: 'ModalAlert',
options: {
markdown: 'Im second'
}
}];
this.deferred = options.deferred || Q.defer();
this.childViews = [];
this.currentIndex = 0;
this.navEvents = _.clone(Backbone.Events);
this.navEvents.on('negative', this.getNegFunc(), this);
this.navEvents.on('positive', this.getPosFunc(), this);
this.navEvents.on('quit', this.finish, this);
this.keyboardListener = new KeyboardListener({
events: this.navEvents,
aliasMap: {
left: 'negative',
right: 'positive',
enter: 'positive',
esc: 'quit'
}
});
this.render();
if (!options.wait) {
this.start();
}
},
onWindowFocus: function() {
// nothing here for now...
// TODO -- add a cool glow effect?
},
getAnimationTime: function() {
return 700;
},
getPromise: function() {
return this.deferred.promise;
},
getPosFunc: function() {
return _.debounce(_.bind(function() {
this.navForward();
}, this), this.navEventDebounce, true);
},
getNegFunc: function() {
return _.debounce(_.bind(function() {
this.navBackward();
}, this), this.navEventDebounce, true);
},
lock: function() {
this.locked = true;
},
unlock: function() {
this.locked = false;
},
navForward: function() {
// we need to prevent nav changes when a git demonstration view hasnt finished
if (this.locked) { return; }
if (this.currentIndex === this.childViews.length - 1) {
this.hideViewIndex(this.currentIndex);
this.finish();
return;
}
this.navIndexChange(1);
},
navBackward: function() {
if (this.currentIndex === 0) {
return;
}
this.navIndexChange(-1);
},
navIndexChange: function(delta) {
this.hideViewIndex(this.currentIndex);
this.currentIndex += delta;
this.showViewIndex(this.currentIndex);
},
hideViewIndex: function(index) {
this.childViews[index].hide();
},
showViewIndex: function(index) {
this.childViews[index].show();
},
finish: function() {
// first we stop listening to keyboard and give that back to UI, which
// other views will take if they need to
this.keyboardListener.mute();
_.each(this.childViews, function(childView) {
childView.die();
});
this.deferred.resolve();
},
start: function() {
// steal the window focus baton
this.showViewIndex(this.currentIndex);
},
createChildView: function(viewJSON) {
var type = viewJSON.type;
if (!this.typeToConstructor[type]) {
throw new Error('no constructor for type "' + type + '"');
}
var view = new this.typeToConstructor[type](_.extend(
{},
viewJSON.options,
{ wait: true }
));
return view;
},
addNavToView: function(view, index) {
var leftRight = new LeftRightView({
events: this.navEvents,
// we want the arrows to be on the same level as the content (not
// beneath), so we go one level up with getDestination()
destination: view.getDestination(),
showLeft: (index !== 0),
lastNav: (index === this.childViewJSONs.length - 1)
});
if (view.receiveMetaNav) {
view.receiveMetaNav(leftRight, this);
}
},
render: function() {
// go through each and render... show the first
_.each(this.childViewJSONs, function(childViewJSON, index) {
var childView = this.createChildView(childViewJSON);
this.childViews.push(childView);
this.addNavToView(childView, index);
}, this);
}
});
exports.MultiView = MultiView;