mirror of
https://github.com/pcottle/learnGitBranching.git
synced 2025-08-01 00:25:15 +02:00
240 lines
7 KiB
JavaScript
240 lines
7 KiB
JavaScript
var Backbone = require('backbone');
|
|
const {getAllCommands} = require('../sandbox/commands');
|
|
|
|
var Main = require('../app');
|
|
var CommandLineStore = require('../stores/CommandLineStore');
|
|
var CommandLineActions = require('../actions/CommandLineActions');
|
|
|
|
var log = require('../log');
|
|
var keyboard = require('../util/keyboard');
|
|
|
|
const allCommands = Object.keys(getAllCommands());
|
|
// Lets push a few commands up in the suggestion order,
|
|
// which overrides the order from the exportj
|
|
const autoCompleteSuggestionOrder = [
|
|
'levels', // above "level"
|
|
'help', // above help level since you might not be in a level
|
|
'show solution', // above show goal since you start with a goal view
|
|
'reset', // over reset solved
|
|
'import level', // over import tree
|
|
];
|
|
|
|
const allCommandsSorted = autoCompleteSuggestionOrder.concat(
|
|
// add the rest that arent in the list above
|
|
allCommands.map(command => autoCompleteSuggestionOrder.indexOf(command) > 0 ? null : command)
|
|
.filter(command => !!command)
|
|
);
|
|
|
|
var CommandPromptView = Backbone.View.extend({
|
|
initialize: function() {
|
|
Main.getEvents().on('commandSubmittedPassive', this.addToCommandHistory, this);
|
|
|
|
this.index = -1;
|
|
this.commandParagraph = this.$('#prompt p.command')[0];
|
|
this.focus();
|
|
|
|
Main.getEvents().on('rollupCommands', this.rollupCommands, this);
|
|
|
|
Main.getEventBaton().stealBaton('keydown', this.onKeyDown, this);
|
|
Main.getEventBaton().stealBaton('keyup', this.onKeyUp, this);
|
|
this.updatePrompt(" ");
|
|
},
|
|
|
|
events: {
|
|
'blur #commandTextField': 'hideCursor',
|
|
'focus #commandTextField': 'showCursor'
|
|
},
|
|
|
|
blur: function() {
|
|
this.hideCursor();
|
|
},
|
|
|
|
focus: function() {
|
|
this.$('#commandTextField').focus();
|
|
this.showCursor();
|
|
},
|
|
|
|
hideCursor: function() {
|
|
this.toggleCursor(false);
|
|
},
|
|
|
|
showCursor: function() {
|
|
this.toggleCursor(true);
|
|
},
|
|
|
|
toggleCursor: function(state) {
|
|
$(this.commandParagraph).toggleClass('showCursor', state);
|
|
},
|
|
|
|
onKeyDown: function(e) {
|
|
var el = e.target;
|
|
|
|
const shadowEl = document.querySelector('#shadow');
|
|
|
|
const currentValue = el.value;
|
|
const allCommand = currentValue.split(';');
|
|
const lastCommand = allCommand[allCommand.length - 1]
|
|
.replace(/\s\s+/g, ' ').replace(/^\s/, '');
|
|
|
|
shadowEl.innerHTML = '';
|
|
if (lastCommand.length) {
|
|
for (const c of allCommandsSorted) {
|
|
if (c.startsWith(lastCommand)) {
|
|
shadowEl.innerHTML = (currentValue + c.replace(lastCommand, '')).replace(/ /g, ' ');
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (e.keyCode === 9) {
|
|
e.preventDefault();
|
|
if (shadowEl.innerHTML) {
|
|
el.value = shadowEl.innerHTML.replace(/ /g, ' ');
|
|
}
|
|
}
|
|
|
|
this.updatePrompt(el);
|
|
},
|
|
|
|
onKeyUp: function(e) {
|
|
this.onKeyDown(e);
|
|
|
|
// we need to capture some of these events.
|
|
var keyToFuncMap = {
|
|
enter: function() {
|
|
this.submit();
|
|
}.bind(this),
|
|
up: function() {
|
|
this.commandSelectChange(1);
|
|
}.bind(this),
|
|
down: function() {
|
|
this.commandSelectChange(-1);
|
|
}.bind(this)
|
|
};
|
|
|
|
var key = keyboard.mapKeycodeToKey(e.which || e.keyCode);
|
|
if (keyToFuncMap[key] !== undefined) {
|
|
e.preventDefault();
|
|
keyToFuncMap[key]();
|
|
this.onKeyDown(e);
|
|
}
|
|
},
|
|
|
|
badHtmlEncode: function(text) {
|
|
return text.replace(/&/g,'&')
|
|
.replace(/</g,'<')
|
|
.replace(/</g,'<')
|
|
.replace(/ /g,' ')
|
|
.replace(/\n/g,'');
|
|
},
|
|
|
|
updatePrompt: function(el) {
|
|
el = el || {}; // firefox
|
|
// i WEEEPPPPPPpppppppppppp that this reflow takes so long. it adds this
|
|
// super annoying delay to every keystroke... I have tried everything
|
|
// to make this more performant. getting the srcElement from the event,
|
|
// getting the value directly from the dom, etc etc. yet still,
|
|
// there's a very annoying and sightly noticeable command delay.
|
|
// try.github.com also has this, so I'm assuming those engineers gave up as
|
|
// well...
|
|
var text = $('#commandTextField').val();
|
|
|
|
// Alright so we have our initial value for what we want the
|
|
// command line to contain. We need to next split into the
|
|
// parse with the cursor and without
|
|
var selectionStart = el.selectionStart;
|
|
var selectionEnd = el.selectionEnd;
|
|
if (!text.length) {
|
|
text = ' ';
|
|
selectionStart = 0;
|
|
selectionEnd = 1;
|
|
} else if (selectionStart === selectionEnd) {
|
|
// Lets pretend they have selected the end character to make the cursor
|
|
// shown
|
|
text += ' ';
|
|
selectionEnd += 1;
|
|
} else if (selectionStart === undefined || selectionEnd === undefined) {
|
|
// I donno what this is for
|
|
selectionStart = Math.max(text.length - 1, 0);
|
|
selectionEnd = text.length;
|
|
}
|
|
|
|
var before = text.substring(0, selectionStart);
|
|
var middle = text.substring(selectionStart, selectionEnd);
|
|
var end = text.substring(selectionEnd, text.length);
|
|
|
|
// Then just make three spans and slap it in.
|
|
var finalHTML = '<span>' + this.badHtmlEncode(before) + '</span>' +
|
|
'<span class="commandCursor">' + this.badHtmlEncode(middle) + '</span>' +
|
|
'<span>' + this.badHtmlEncode(end) + '</span>';
|
|
this.commandParagraph.innerHTML = finalHTML;
|
|
// and scroll down due to some weird bug
|
|
Main.getEvents().trigger('commandScrollDown');
|
|
},
|
|
|
|
commandSelectChange: function(delta) {
|
|
this.index += delta;
|
|
|
|
// if we are over / under, display blank line. yes this eliminates your
|
|
// partially edited command, but i doubt that is much in this demo
|
|
if (this.index >= CommandLineStore.getCommandHistoryLength() || this.index < 0) {
|
|
this.clear();
|
|
this.index = -1;
|
|
return;
|
|
}
|
|
|
|
// yay! we actually can display something
|
|
var commandEntry = CommandLineStore.getCommandHistory()[this.index];
|
|
this.setTextField(commandEntry);
|
|
},
|
|
|
|
setTextField: function(value) {
|
|
this.$('#commandTextField').val(value);
|
|
},
|
|
|
|
clear: function() {
|
|
this.setTextField('');
|
|
},
|
|
|
|
submit: function() {
|
|
var value = this.$('#commandTextField').val().replace('\n', '');
|
|
this.clear();
|
|
|
|
this.submitCommand(value);
|
|
this.index = -1;
|
|
},
|
|
|
|
rollupCommands: function(numBack) {
|
|
var which = CommandLineStore.getCommandHistory().slice(1, Number(numBack) + 1);
|
|
which.reverse();
|
|
|
|
var str = '';
|
|
which.forEach(function(text) {
|
|
str += text + ';';
|
|
}, this);
|
|
|
|
CommandLineActions.submitCommand(str);
|
|
},
|
|
|
|
addToCommandHistory: function(value) {
|
|
// we should add the command to our local storage history
|
|
// if it's not a blank line and this is a new command...
|
|
// or if we edited the command in place in history
|
|
var shouldAdd = (value.length && this.index === -1) ||
|
|
((value.length && this.index !== -1 &&
|
|
CommandLineStore.getCommandHistory()[this.index] !== value));
|
|
|
|
if (!shouldAdd) {
|
|
return;
|
|
}
|
|
|
|
CommandLineActions.submitCommand(value);
|
|
log.commandEntered(value);
|
|
},
|
|
|
|
submitCommand: function(value) {
|
|
Main.getEventBaton().trigger('commandSubmitted', value);
|
|
}
|
|
});
|
|
|
|
exports.CommandPromptView = CommandPromptView;
|