pcottle.learnGitBranching/src/js/views/builderViews.js
2020-05-13 13:18:31 +07:00

420 lines
10 KiB
JavaScript

var _ = require('underscore');
var Q = require('q');
var marked = require('marked');
var Views = require('../views');
var throttle = require('../util/throttle');
var ModalTerminal = Views.ModalTerminal;
var ContainedBase = Views.ContainedBase;
var TextGrabber = ContainedBase.extend({
tagName: 'div',
className: 'textGrabber box vertical',
template: _.template($('#text-grabber').html()),
initialize: function(options) {
options = options || {};
this.JSON = {
helperText: options.helperText || 'Enter some text'
};
this.container = options.container || new ModalTerminal({
title: 'Enter some text'
});
this.render();
if (options.initialText) {
this.setText(options.initialText);
}
if (!options.wait) {
this.show();
}
},
getText: function() {
return this.$('textarea').val();
},
setText: function(str) {
this.$('textarea').val(str);
}
});
var MarkdownGrabber = ContainedBase.extend({
tagName: 'div',
className: 'markdownGrabber box horizontal',
template: _.template($('#markdown-grabber-view').html()),
events: {
'keyup textarea': 'keyup'
},
initialize: function(options) {
options = options || {};
this.deferred = options.deferred || Q.defer();
if (options.fromObj) {
options.fillerText = options.fromObj.options.markdowns.join('\n');
}
this.JSON = {
previewText: options.previewText || 'Preview',
fillerText: options.fillerText || '## Enter some markdown!\n\n\n'
};
this.container = options.container || new ModalTerminal({
title: options.title || 'Enter some markdown'
});
this.render();
if (!options.withoutButton) {
// do button stuff
var buttonDefer = Q.defer();
buttonDefer.promise
.then(this.confirmed.bind(this))
.fail(this.cancelled.bind(this))
.done();
var confirmCancel = new Views.ConfirmCancelView({
deferred: buttonDefer,
destination: this.getDestination()
});
}
this.updatePreview();
if (!options.wait) {
this.show();
}
},
confirmed: function() {
this.die();
this.deferred.resolve(this.getRawText());
},
cancelled: function() {
this.die();
this.deferred.resolve();
},
keyup: function() {
if (!this.throttledPreview) {
this.throttledPreview = throttle(
this.updatePreview.bind(this),
500
);
}
this.throttledPreview();
},
getRawText: function() {
return this.$('textarea').val();
},
exportToArray: function() {
return this.getRawText().split('\n');
},
getExportObj: function() {
return {
markdowns: this.exportToArray()
};
},
updatePreview: function() {
var raw = this.getRawText();
var HTML = marked(raw);
this.$('div.insidePreview').html(HTML);
}
});
var MarkdownPresenter = ContainedBase.extend({
tagName: 'div',
className: 'markdownPresenter box vertical',
template: _.template($('#markdown-presenter').html()),
initialize: function(options) {
options = options || {};
this.deferred = options.deferred || Q.defer();
this.JSON = {
previewText: options.previewText || 'Here is something for you',
fillerText: options.fillerText || '# Yay'
};
this.container = new ModalTerminal({
title: 'Check this out...'
});
this.render();
if (!options.noConfirmCancel) {
var confirmCancel = new Views.ConfirmCancelView({
destination: this.getDestination()
});
confirmCancel.deferred.promise
.then(function() {
this.deferred.resolve(this.grabText());
}.bind(this))
.fail(function() {
this.deferred.reject();
}.bind(this))
.done(this.die.bind(this));
}
this.show();
},
grabText: function() {
return this.$('textarea').val();
}
});
var DemonstrationBuilder = ContainedBase.extend({
tagName: 'div',
className: 'demonstrationBuilder box vertical',
template: _.template($('#demonstration-builder').html()),
events: {
'click div.testButton': 'testView'
},
initialize: function(options) {
options = options || {};
this.deferred = options.deferred || Q.defer();
if (options.fromObj) {
var toEdit = options.fromObj.options;
options = Object.assign(
{},
options,
toEdit,
{
beforeMarkdown: toEdit.beforeMarkdowns.join('\n'),
afterMarkdown: toEdit.afterMarkdowns.join('\n')
}
);
}
this.JSON = {};
this.container = new ModalTerminal({
title: 'Demonstration Builder'
});
this.render();
// build the two markdown grabbers
this.beforeMarkdownView = new MarkdownGrabber({
container: this,
withoutButton: true,
fillerText: options.beforeMarkdown,
previewText: 'Before demonstration Markdown'
});
this.beforeCommandView = new TextGrabber({
container: this,
helperText: 'The git command(s) to set up the demonstration view (before it is displayed)',
initialText: options.beforeCommand || 'git checkout -b bugFix'
});
this.commandView = new TextGrabber({
container: this,
helperText: 'The git command(s) to demonstrate to the reader',
initialText: options.command || 'git commit'
});
this.afterMarkdownView = new MarkdownGrabber({
container: this,
withoutButton: true,
fillerText: options.afterMarkdown,
previewText: 'After demonstration Markdown'
});
// build confirm button
var buttonDeferred = Q.defer();
var confirmCancel = new Views.ConfirmCancelView({
deferred: buttonDeferred,
destination: this.getDestination()
});
buttonDeferred.promise
.then(this.confirmed.bind(this))
.fail(this.cancelled.bind(this))
.done();
},
testView: function() {
var MultiView = require('../views/multiView').MultiView;
new MultiView({
childViews: [{
type: 'GitDemonstrationView',
options: this.getExportObj()
}]
});
},
getExportObj: function() {
return {
beforeMarkdowns: this.beforeMarkdownView.exportToArray(),
afterMarkdowns: this.afterMarkdownView.exportToArray(),
command: this.commandView.getText(),
beforeCommand: this.beforeCommandView.getText()
};
},
confirmed: function() {
this.die();
this.deferred.resolve(this.getExportObj());
},
cancelled: function() {
this.die();
this.deferred.resolve();
},
getInsideElement: function() {
return this.$('.insideBuilder')[0];
}
});
var MultiViewBuilder = ContainedBase.extend({
tagName: 'div',
className: 'multiViewBuilder box vertical',
template: _.template($('#multi-view-builder').html()),
typeToConstructor: {
ModalAlert: MarkdownGrabber,
GitDemonstrationView: DemonstrationBuilder
},
events: {
'click div.deleteButton': 'deleteOneView',
'click div.testButton': 'testOneView',
'click div.editButton': 'editOneView',
'click div.testEntireView': 'testEntireView',
'click div.addView': 'addView',
'click div.saveView': 'saveView',
'click div.cancelView': 'cancel'
},
initialize: function(options) {
options = options || {};
this.deferred = options.deferred || Q.defer();
this.multiViewJSON = options.multiViewJSON || {};
this.JSON = {
views: this.getChildViews(),
supportedViews: Object.keys(this.typeToConstructor)
};
this.container = new ModalTerminal({
title: 'Build a MultiView!'
});
this.render();
this.show();
},
saveView: function() {
this.hide();
this.deferred.resolve(this.multiViewJSON);
},
cancel: function() {
this.hide();
this.deferred.resolve();
},
addView: function(ev) {
var el = ev.target;
var type = $(el).attr('data-type');
var whenDone = Q.defer();
var Constructor = this.typeToConstructor[type];
var builder = new Constructor({
deferred: whenDone
});
whenDone.promise
.then(function() {
var newView = {
type: type,
options: builder.getExportObj()
};
this.addChildViewObj(newView);
}.bind(this))
.fail(function() {
// they don't want to add the view apparently, so just return
})
.done();
},
testOneView: function(ev) {
var el = ev.target;
var index = $(el).attr('data-index');
var toTest = this.getChildViews()[index];
var MultiView = require('../views/multiView').MultiView;
new MultiView({
childViews: [toTest]
});
},
testEntireView: function() {
var MultiView = require('../views/multiView').MultiView;
new MultiView({
childViews: this.getChildViews()
});
},
editOneView: function(ev) {
var el = ev.target;
var index = $(el).attr('data-index');
var type = $(el).attr('data-type');
var whenDone = Q.defer();
var builder = new this.typeToConstructor[type]({
deferred: whenDone,
fromObj: this.getChildViews()[index]
});
whenDone.promise
.then(function() {
var newView = {
type: type,
options: builder.getExportObj()
};
var views = this.getChildViews();
views[index] = newView;
this.setChildViews(views);
}.bind(this))
.fail(function() { })
.done();
},
deleteOneView: function(ev) {
var el = ev.target;
var index = $(el).attr('data-index');
var toSlice = this.getChildViews();
var updated = toSlice.slice(0,index).concat(toSlice.slice(index + 1));
this.setChildViews(updated);
this.update();
},
addChildViewObj: function(newObj, index) {
var childViews = this.getChildViews();
childViews.push(newObj);
this.setChildViews(childViews);
this.update();
},
setChildViews: function(newArray) {
this.multiViewJSON.childViews = newArray;
},
getChildViews: function() {
return this.multiViewJSON.childViews || [];
},
update: function() {
this.JSON.views = this.getChildViews();
this.renderAgain();
}
});
exports.MarkdownGrabber = MarkdownGrabber;
exports.DemonstrationBuilder = DemonstrationBuilder;
exports.TextGrabber = TextGrabber;
exports.MultiViewBuilder = MultiViewBuilder;
exports.MarkdownPresenter = MarkdownPresenter;