Files
rainmelt/html/UserInterface.js
2012-08-06 19:32:11 +09:00

351 lines
9.2 KiB
JavaScript

var UserInterface = function(terminal) {
this.terminal = terminal;
this.view = document.createElement('div');
this.view.style.whiteSpace = 'pre-wrap';
this.view.style.wordWrap = 'break-word';
this.view.style.wordBreak = 'break-all';
this.code = document.createElement('code');
this.completion = document.createElement('span');
this.completion.style.color = '#d09050';
this.prompt = document.createElement('span');
this.input = document.createElement('input');
this.input.type = 'text';
this.DEFAULT_INPUT_SIZE = this.input.size;
this.view.appendChild(this.code);
this.code.appendChild(this.completion);
this.code.appendChild(this.prompt);
this.code.appendChild(this.input);
this.parser = new Parser();
this.inputHistory = [];
this.inputHistoryIndex = this.inputHistory.length;
var self = this;
this.splitPath = function(path) {
var slash = path.lastIndexOf('/');
if (slash == -1) {
return [ '', path ];
} else if (path.length > 1 && slash == path.length - 1) {
return [ path, '' ];
} else if (slash == 0) {
return [ '/', path.substr(1) ];
} else {
return [ path.substr(0, slash), path.substr(slash + 1) ];
}
};
this.headCompletionCallback = function(packet, args) {
if (packet.opcode == 'StringList') {
self.parser.setLine(self.input.value);
self.parser.parse();
var elements = self.parser.tokens;
var originalElements = self.parser.originalTokens;
var length = 0;
var index;
if (originalElements.length < 1) {
index = -1;
} else {
for (index = 0; index < originalElements.length; index++) {
if (length + originalElements[index].length >= self.input.selectionStart) {
break;
}
length += originalElements[index].length;
}
}
var word = '';
if (index >= 0 && index < elements.length) {
word = elements[index];
}
var list = args.concat(self.createCompletionList(packet.list, word));
if (list.length < 2) {
if (index >= 0) {
if (index < 1) {
originalElements[index] = list[0];
} else {
originalElements[index] = ' ' + list[0];
}
self.input.value = originalElements.join('') + ' ';
self.completion.textContent = '';
}
} else {
self.completion.textContent = list.join(' ') + '\n';
self.scrollToBottom();
}
} else {
self.println(packet.opcode);
}
};
this.completionCallback = function(packet, args) {
var list = [];
var i;
if (packet.opcode == 'FileException') {
if (packet.type == 'IS_FILE') {
list.push({ name: args[1], type: 'FILE' });
return;
} else {
self.completion.textContent = packet.type;
return;
}
} else if (packet.opcode == 'FileList') {
for (i = 0; i < packet.list.length; i++) {
if (packet.list[i].name.indexOf(args[1]) == 0) {
list.push(packet.list[i]);
}
}
}
if (list.length < 1) {
self.completion.textContent = '';
} else if (list.length < 2) {
self.parser.setLine(self.input.value);
self.parser.parse();
var elements = self.parser.tokens;
var originalElements = self.parser.originalTokens;
var length = 0;
var index;
if (originalElements.length < 1) {
index = -1;
} else {
for (index = 0; index < originalElements.length; index++) {
if (length + originalElements[index].length >= self.input.selectionStart) {
break;
}
length += originalElements[index].length;
}
}
if (index >= 0) {
var filename;
if (args[0].length < 1) {
filename = list[0].name;
} else {
if (args[0] == '/') {
filename = '/' + list[0].name;
} else {
if (args[0].charAt(args[0].length - 1) == '/') {
filename = args[0] + list[0].name;
} else {
filename = args[0] + '/' + list[0].name;
}
}
}
if (filename.indexOf(' ') >= 0) {
filename = '"' + filename + '"';
}
originalElements[index] = ' ' + filename;
if (list[0].type == 'DIRECTORY') {
self.input.value = originalElements.join('') + '/';
} else {
self.input.value = originalElements.join('') + ' ';
}
self.completion.textContent = '';
if (self.input.value.length < self.DEFAULT_INPUT_SIZE) {
self.input.size = self.DEFAULT_INPUT_SIZE;
} else {
self.input.size = self.input.value.length;
}
}
} else {
var names = [];
for (i = 0; i < list.length; i++) {
names.push(list[i].name);
}
self.completion.textContent = names.join(' ') + '\n';
self.scrollToBottom();
}
};
this.handleInput = function(e) {
if (e.keyCode == 13) { // ENTER
var value = self.input.value;
self.input.value = '';
self.addHistory(value);
self.inputHistoryIndex = self.inputHistory.length;
self.completion.textContent = '';
} else if (e.keyCode == 9) { // TAB
e.preventDefault();
self.parser.setLine(self.input.value);
self.parser.parse();
var elements = self.parser.tokens;
var originalElements = self.parser.originalTokens;
var length = 0;
var index;
if (originalElements.length < 1) {
index = -1;
} else {
for (index = 0; index < originalElements.length; index++) {
if (length + originalElements[index].length >= self.input.selectionStart) {
break;
}
length += originalElements[index].length;
}
}
var word = '';
if (index >= 0 && index < elements.length) {
word = elements[index];
}
if (index < 1) {
var list = self.createCompletionList(self.completionListHead, word);
self.terminal.api.commandList(self.headCompletionCallback, list);
} else {
var sp = self.splitPath(word);
var absolutePath = self.terminal.session.toAbsolutePath(sp[0]);
self.terminal.fileAPI.list(self.completionCallback, sp, absolutePath);
}
} else if (e.keyCode == 38) { // UP
if (self.inputHistoryIndex < 0) {
self.input.value = '';
} else {
self.inputHistoryIndex--;
if (self.inputHistoryIndex < 0) {
self.input.value = '';
} else {
self.input.value = self.inputHistory[self.inputHistoryIndex];
}
}
} else if (e.keyCode == 40) { // DOWN
if (self.inputHistoryIndex >= self.inputHistory.length) {
self.input.value = '';
} else {
self.inputHistoryIndex++;
if (self.inputHistoryIndex >= self.inputHistory.length) {
self.input.value = '';
} else {
self.input.value = self.inputHistory[self.inputHistoryIndex];
}
}
}
if (self.input.value.length < self.DEFAULT_INPUT_SIZE) {
self.input.size = self.DEFAULT_INPUT_SIZE;
} else {
self.input.size = self.input.value.length;
}
if (e.keyCode == 13) { // ENTER
self.input.onkeydown = null;
self.inputCallback(value);
}
};
this.handleTemporalInput = function(e) {
if (e.keyCode == 13) { // ENTER
var value = self.input.value;
self.input.value = '';
}
if (self.input.value.length < self.DEFAULT_INPUT_SIZE) {
self.input.size = self.DEFAULT_INPUT_SIZE;
} else {
self.input.size = self.input.value.length;
}
if (e.keyCode == 13) { // ENTER
self.input.onkeydown = null;
self.temporalInputCallback(value);
}
};
this.login2 = function(line) {
self.account = line;
self.print(self.prompt.textContent);
self.println(line);
self.temporalInputCallback = self.login3;
self.prompt.textContent = 'Password: ';
self.input.type = 'password';
self.input.onkeydown = self.handleTemporalInput;
};
this.login3 = function(line) {
self.println(self.prompt.textContent);
self.prompt.textContent = self.terminal.promptString;
self.temporalInputCallback = null;
self.input.type = 'text';
var account = self.account;
self.account = null;
self.inputCallback(account, line);
};
};
UserInterface.prototype.addHistory = function(s) {
if (s.length < 1) {
return;
}
for (var i = this.inputHistory.length - 1; i >= 0; i--) {
if (this.inputHistory[i] == s) {
this.inputHistory.splice(i, 1);
break;
}
}
this.inputHistory.push(s);
};
UserInterface.prototype.createCompletionList = function(list, word) {
var result = [];
for (var i = 0; i < list.length; i++) {
if (list[i].indexOf(word) == 0) {
result.push(list[i]);
}
}
return result;
};
UserInterface.prototype.scrollToBottom = function() {
window.scrollTo(0, document.body.scrollHeight);
};
UserInterface.prototype.clear = function() {
while (this.code.firstChild != this.completion) {
this.code.removeChild(this.code.firstChild);
}
};
UserInterface.prototype.print = function(s, color, background) {
var output = document.createElement('span');
output.textContent = s;
output.style.color = color;
output.style.background = background;
this.code.insertBefore(output, this.completion);
this.scrollToBottom();
};
UserInterface.prototype.println = function(s, color, background) {
this.print(s + '\n', color, background);
};
UserInterface.prototype.append = function(node) {
this.code.insertBefore(node, this.prompt);
this.scrollToBottom();
};
UserInterface.prototype.readLine = function(callback, headList) {
this.inputCallback = callback;
this.completionListHead = headList;
this.input.onkeydown = this.handleInput;
this.input.focus();
};
UserInterface.prototype.login = function(callback) {
this.terminal.command.inputCallback = null;
this.inputCallback = callback;
this.temporalInputCallback = this.login2;
this.prompt.textContent = 'Account: ';
this.input.onkeydown = this.handleTemporalInput;
this.input.focus();
};