|
|
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()); |
|
|
|
|
|
|
|
|
const autoCompleteSuggestionOrder = [ |
|
|
'levels', |
|
|
'help', |
|
|
'show solution', |
|
|
'reset', |
|
|
'import level', |
|
|
]; |
|
|
|
|
|
const allCommandsSorted = autoCompleteSuggestionOrder.concat( |
|
|
|
|
|
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); |
|
|
|
|
|
|
|
|
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 || {}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var text = $('#commandTextField').val(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var selectionStart = el.selectionStart; |
|
|
var selectionEnd = el.selectionEnd; |
|
|
if (!text.length) { |
|
|
text = ' '; |
|
|
selectionStart = 0; |
|
|
selectionEnd = 1; |
|
|
} else if (selectionStart === selectionEnd) { |
|
|
|
|
|
|
|
|
text += ' '; |
|
|
selectionEnd += 1; |
|
|
} else if (selectionStart === undefined || selectionEnd === undefined) { |
|
|
|
|
|
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); |
|
|
|
|
|
|
|
|
var finalHTML = '<span>' + this.badHtmlEncode(before) + '</span>' + |
|
|
'<span class="commandCursor">' + this.badHtmlEncode(middle) + '</span>' + |
|
|
'<span>' + this.badHtmlEncode(end) + '</span>'; |
|
|
this.commandParagraph.innerHTML = finalHTML; |
|
|
|
|
|
Main.getEvents().trigger('commandScrollDown'); |
|
|
}, |
|
|
|
|
|
commandSelectChange: function(delta) { |
|
|
this.index += delta; |
|
|
|
|
|
|
|
|
|
|
|
if (this.index >= CommandLineStore.getCommandHistoryLength() || this.index < 0) { |
|
|
this.clear(); |
|
|
this.index = -1; |
|
|
return; |
|
|
} |
|
|
|
|
|
|
|
|
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) { |
|
|
|
|
|
|
|
|
|
|
|
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; |
|
|
|