diff --git a/.gitignore b/.gitignore
index 28fdb01..d4db9aa 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
.idea/workspace.xml
.idea/tasks.xml
-.DS_Store
\ No newline at end of file
+.DS_Store
+bower_components
diff --git a/.idea/misc.xml b/.idea/misc.xml
index 223f438..1162f43 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -1,8 +1,5 @@
-
- $APPLICATION_HOME_DIR$/lib/webide.jar!/resources/html5-schema/html5.rnc
-
diff --git a/README.md b/README.md
index 91ead01..c2379c2 100644
--- a/README.md
+++ b/README.md
@@ -1,9 +1,9 @@
-josh.js 0.3
+josh.js 0.2
===========
-http://sdether.github.com/josh.js/
+http://sdether.github.io/josh.js/
-***Javascript Online SHell*** provides a toolkit for building bash-like command line consoles for web pages. It consists of the following components:
+***Javascript Online SHell*** provides a toolkit for building bash-like command line consoles for web pages. JOSH enables the visitor who prefers the bash-like command to maneuver through web content using a console rather than clicking with a mouse. This toolkit is most useful for people who like to use command line because it is faster and more effective than using a mouse. It is easier and convienent to access hierarchical information using JOSH command history, change or display current directory. It consists of the following components:
* `readline.js` - full readline support for ctrl sequences, tab, history, etc.
* `shell.js` - visual presentation of the shell and command handling
@@ -11,6 +11,19 @@ http://sdether.github.com/josh.js/
* `history.js` - localStorage backed command history
* `killring.js` - killring for kill & yank handling in readline
+## What to use Josh for and when to use it
+
+Josh allows developers to build their own command line interface to any sites. It supports full CLI Readline in the browser like TAB completion, emacs-style line editing, killring and history with reverse search. When you are tired of clicking your way through a hierachy tree, Josh will come in handy. It will helps you browse or navigate text files quickly and minimal the using of mouse click.
+
+## Tutorials
+* Hello world - put a console on a web page and add a new custom command with completion
+* Quake Console - Create a quake-style console with ls,
+ cd, pwd and bash filename tab-completion
+* GitHub Console - Extend the Quake Console to talk to GitHub's REST API to navigate repositories, their branches and file system
+
+## Articles
+* CLI all the things: Introducing Josh.js Article about the origins of Josh.js with an example console for wordpress sites.
+
## License
josh.js is licensed under the Apache 2.0 License
@@ -121,22 +134,36 @@ By implementing the functions `getNode` and `getChildNodes`, this library adds p
`history.js` implements a localStorage back command history storage that persists over page changes and reloads. It is used by the `shell.js` history command to list all executed commands, and by `readline.js` for up/down arrow and reverse search capabilities.
### killring.js
-`killing.js` implements the kill and yank behavior as well as state tracking, i.e. multiple consecutive kills are combined as a single kill and killring rotation tracks the previous yank, so that the `readline.js` can remove the previous yank and replace it with the rotated text.
+`killring.js` implements the kill and yank behavior as well as state tracking, i.e. multiple consecutive kills are combined as a single kill and killring rotation tracks the previous yank, so that the `readline.js` can remove the previous yank and replace it with the rotated text.
## Changelog
-**0.3** -- 2013/02/13
-* Removed all html used for Shell UI generation from config to `Shell.templates`, so that they can easily be customized (see: [Issue 11](https://github.com/sdether/josh.js/issues/11 )
+**0.2.10** -- 2014/04/03
+* Added bower support (pr#19 - @bricef)
+* Code clean-up for closure compiler issues (pr#20 - @aaronmars)
+
+**0.2.9** -- 2013/08/31
+* Added ability to bind ReadLine/Shell to an element.
+* Added ability to bind/unbind keys (could be used to replace emacs bindings of readline, but primarily added to unbind some keys for using readline on input elements.
+* Created input.js for easy binding of readline to either an input element or a span behaving like an input.
+
+**0.2.8** -- 2013/03/13
+* Added handling of . and .. in Josh.PathHandler.pathcompletionhandler, so that a trailing .. completes to ../ and . to ./
+* Removed the hardcoded **strong** in the input template, making it a span instead so it can be styled via css instead.
+* The prompt value itself is now assumed to be html instead of plain text, allowing for richer formatting without changing the input template.
+
+**0.2.7** -- 2013/02/13
+* Removed all html used for Shell UI generation from config to `Shell.templates`, so that they can easily be customized (see: [Issue 11](https://github.com/sdether/josh.js/issues/11))
* Removed `PathHandler.templates`. PathHandler now attches its templates to `Shell.templates` as well
**0.2.6** -- 2013/01/21
-* Removed Activation/Deactivation keybindings from Readline, making it an outside concern (see: [Issue 2](https://github.com/sdether/josh.js/issues/2 )
+* Removed Activation/Deactivation keybindings from Readline, making it an outside concern (see: [Issue 2](https://github.com/sdether/josh.js/issues/2))
* Fixed Backspace regression introduced by 0.2.5
* Fixed `M-d` not deleting last character of line
* Example shell can now be resized (via jquery-ui.resizable)
**0.2.5** -- 2013/01/14
-* Implemented missing Readline behavior (see: [Issue 1](https://github.com/sdether/josh.js/issues/1 )
+* Implemented missing Readline behavior (see: [Issue 1](https://github.com/sdether/josh.js/issues/1))
* Added scrollbar to sample implemenation (also adds scrollwheel support)
**0.2.4** -- 2013/01/14
diff --git a/bower.json b/bower.json
new file mode 100644
index 0000000..9971f61
--- /dev/null
+++ b/bower.json
@@ -0,0 +1,33 @@
+{
+ "name": "josh.js",
+ "version": "0.2.10",
+ "homepage": "http://sdether.github.io/josh.js/",
+ "authors": [
+ "Arne Claassen "
+ ],
+ "description": "Javascript Online SHell provides a toolkit for building bash-like command line consoles for web pages.",
+ "main": [
+ "js/readline.js",
+ "js/history.js",
+ "js/killring.js",
+ "js/input.js",
+ "js/pathhandler.js",
+ "js/shell.js"
+ ],
+ "keywords": [
+ "shell",
+ "josh"
+ ],
+ "license": "Apache 2.0",
+ "ignore": [
+ "**/.*",
+ "node_modules",
+ "bower_components",
+ "test",
+ "tests"
+ ],
+ "dependencies": {
+ "jquery": "~3.1.0",
+ "lodash": "~4.14.2"
+ }
+}
diff --git a/index.html b/index.html
index 1813906..06d1ce2 100755
--- a/index.html
+++ b/index.html
@@ -1,49 +1,75 @@
-
-
- Shell testbed
+
+
+ Shell testbed
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
Press ~ to activate console.
+
Press ~ to activate console.
+
+ Cmd1:
+
+
+
+ Cmd2:
+
+
\ No newline at end of file
diff --git a/js/example.js b/js/example.js
index 0f00691..f8d2cc8 100644
--- a/js/example.js
+++ b/js/example.js
@@ -1,5 +1,5 @@
/*------------------------------------------------------------------------*
- * Copyright 2013 Arne F. Claassen
+ * Copyright 2013-2014 Arne F. Claassen
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -45,7 +45,7 @@
// -------------------------
// Setup the `Underscore` template for displaying items in the `KillRing`.
- var killringItemTemplate = _.template("
<% _.each(items, function(item, i) { %>
<%- i %> <%- item %>
<% }); %>
")
+ var killringItemTemplate = _.template("
<% _.each(items, function(item, i) { %>
<%- i %> <%- item %>
<% }); %>
");
// Create a the command `killring` which will display all text currently in the `KillRing`, by attaching
// a handler to the `Shell`.
@@ -125,7 +125,7 @@
// references like `.` and `..`. In implementations that let you explore an hierarchy on a server, this function
// would live on the server side and be called remotely via `getNode`.
function findNode(current, parts, callback) {
- if(!parts || parts.length == 0) {
+ if(!parts || parts.length === 0) {
return callback(current);
}
if(parts[0] == ".") {
@@ -147,12 +147,12 @@
// -----------------------
// Activation and display behavior happens at document ready time.
- $(document).ready(function() {
+ $(root).ready(function() {
// The default name for the div the shell uses as its container is `shell-panel`, although that can be changed via
- // the shell config parameter `shell-view-id`. The `Shell` display model relies on a div to contain a 'view'. The
- // acts as the view-port, i.e. the visible portion of the shell content, while the view is appended to and
- // scrolled up as new content is added.
+ // the shell config parameter `shell-panel-id`. The `Shell` display model relies on a 'panel' to contain a 'view'.
+ // The 'panel' acts as the view-port, i.e. the visible portion of the shell content, while the 'view' is appended
+ // to and scrolled up as new content is added.
var $consolePanel = $('#shell-panel');
// We use **jquery-ui**'s `resizable` to let us drag the bottom edge of the console up and down.
@@ -167,8 +167,8 @@
}
// Mimicking *Quake*-style dropdown consoles, we activate and show on `~`.
- _console.log("activating shell");
if(event.keyCode == 126) {
+ _console.log("activating shell");
event.preventDefault();
shell.activate();
$consolePanel.slideDown();
@@ -208,7 +208,7 @@
boot: {},
dev: {},
etc: {
- default: {},
+ 'default': {},
'rc.d': {},
sysconfig: {},
x11: {}
@@ -254,7 +254,7 @@
},
src: {}
},
- var: {
+ 'var': {
lib: {},
lock: {},
run: {},
diff --git a/js/history.js b/js/history.js
index 49fb27a..7e4e38c 100644
--- a/js/history.js
+++ b/js/history.js
@@ -1,5 +1,5 @@
/* ------------------------------------------------------------------------*
- * Copyright 2013 Arne F. Claassen
+ * Copyright 2013-2014 Arne F. Claassen
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -28,7 +28,11 @@ var Josh = Josh || {};
var _key = config.key || 'josh.history';
if (_storage) {
- var data = _storage.getItem(_key);
+ try {
+ var data = _storage.getItem(_key);
+ } catch(e) {
+ _console.log("Error accessing storage");
+ }
if (data) {
_history = JSON.parse(data);
_searchCursor = _cursor = _history.length - 1;
@@ -38,7 +42,11 @@ var Josh = Josh || {};
}
function save() {
if (_storage) {
- _storage.setItem(_key, JSON.stringify(_history));
+ try {
+ _storage.setItem(_key, JSON.stringify(_history));
+ } catch(e) {
+ _console.log("Error accessing storage");
+ }
}
}
diff --git a/js/input.js b/js/input.js
new file mode 100644
index 0000000..3085db2
--- /dev/null
+++ b/js/input.js
@@ -0,0 +1,172 @@
+/* ------------------------------------------------------------------------*
+ * Copyright 2013-2014 Arne F. Claassen
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *-------------------------------------------------------------------------*/
+
+var Josh = Josh || {};
+(function (root, $, _) {
+ $.fn.josh_caretTo = function (index) {
+ return this.queue(function (next) {
+ if (this.createTextRange) {
+ var range = this.createTextRange();
+ range.move("character", index);
+ range.select();
+ } else if (this.selectionStart !== null) {
+ this.setSelectionRange(index, index);
+ }
+ next();
+ });
+ };
+ $.fn.josh_caretPosition = function () {
+ var el = this.get(0);
+ if (el.createTextRange) {
+ var range = el.createTextRange();
+ range.moveStart('character', -el.value.length);
+ return range.text.length;
+ } else if (el.selectionStart !== null) {
+ return el.selectionStart;
+ }
+ return 0;
+ };
+
+ var history = Josh.History();
+ var killring = new Josh.KillRing();
+
+ Josh.Input = function (config) {
+ config = config || {};
+
+ // instance fields
+ var _console = config.console || (Josh.Debug && root.console ? root.console : {
+ log: function () {
+ }
+ });
+
+ var _id = "#" + config.id;
+ var _blinktime = config.blinktime || 500;
+ var _active = false;
+ var _cursor_visible = false;
+ var _isInput = false;
+ var _history = config.history || history;
+ var _killring = config.killring || killring;
+ var _text;
+ var self = {
+ templates: {
+ span: _.template('')
+ },
+ history: _history,
+ killring: _killring
+ };
+
+ $(document).ready(function () {
+ var $input = $(_id);
+ var el = $input.get(0);
+ var readline = new Josh.ReadLine({
+ history: _history,
+ killring: _killring,
+ console: _console
+ });
+ self.readline = readline;
+ readline.attach(el);
+ var activate = null;
+ _isInput = $input.is('input');
+ if (_isInput) {
+
+ _console.log(_id + ' is an input');
+
+ function renderInput(line) {
+ var text = line ? line.text : '';
+ _text = text;
+ $input.val(text);
+ $input.josh_caretTo(line.cursor);
+ }
+ readline.onChange(renderInput);
+ $input.click(function() {
+ var line = readline.getLine();
+ line.cursor = $input.josh_caretPosition();
+ readline.setLine(line);
+ });
+
+ activate = function() {
+ // Note: have to re-render with a setTimeout, because on focus, but after the onfocus event is processed,
+ // the input will select all, invalidating our render
+ setTimeout(function() {
+ renderInput(readline.getLine());
+ }, 0);
+ };
+ } else {
+ _console.log(_id + ' is a non-input element');
+ $input.html(self.templates.span());
+ if(typeof $input.attr('tabindex') === 'undefined') {
+ $input.attr('tabindex',0);
+ }
+ var $left = $input.find('.left');
+ var $right = $input.find('.right');
+ var $cursor = $input.find('.cursor');
+
+ function renderSpan(line) {
+ var text = line.text || '';
+ _text = text;
+ var cursorIdx = line.cursor || 0;
+ var left = _.escape(text.substr(0, cursorIdx)).replace(/ /g, ' ');
+ var cursor = text.substr(cursorIdx, 1);
+ var right = _.escape(text.substr(cursorIdx + 1)).replace(/ /g, ' ');
+ $left.html(left);
+ if (!cursor) {
+ $cursor.html(' ').css('textDecoration', 'underline');
+ } else {
+ $cursor.text(cursor).css('textDecoration', 'underline');
+ }
+ $right.html(right);
+ }
+
+ function blinkCursor() {
+ if (!_active) {
+ return;
+ }
+ root.setTimeout(function () {
+ if (!_active) {
+ return;
+ }
+ _cursor_visible = !_cursor_visible;
+ if (_cursor_visible) {
+ $cursor.css('textDecoration', 'underline');
+ } else {
+ $cursor.css('textDecoration', '');
+ }
+ blinkCursor();
+ }, _blinktime);
+ }
+
+ activate = function () {
+ blinkCursor();
+ }
+ readline.onChange(renderSpan);
+ }
+ readline.unbind({keyCode: Josh.Keys.Special.Tab});
+ readline.unbind({'char': 'R', ctrlKey: true});
+ readline.onActivate(function () {
+ _active = true;
+ activate();
+ });
+ readline.onDeactivate(function () {
+ _active = false;
+ if (_text) {
+ _history.accept(_text);
+ }
+ });
+
+ });
+ return self;
+ }
+})(this, $, _);
diff --git a/js/killring.js b/js/killring.js
index dc22874..822af2b 100644
--- a/js/killring.js
+++ b/js/killring.js
@@ -1,5 +1,5 @@
/* ------------------------------------------------------------------------*
- * Copyright 2013 Arne F. Claassen
+ * Copyright 2013-2014 Arne F. Claassen
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/js/pathhandler.js b/js/pathhandler.js
index 62964aa..bf1148f 100644
--- a/js/pathhandler.js
+++ b/js/pathhandler.js
@@ -1,5 +1,5 @@
/* ------------------------------------------------------------------------*
- * Copyright 2013 Arne F. Claassen
+ * Copyright 2013-2014 Arne F. Claassen
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -94,6 +94,12 @@ var Josh = Josh || {};
var lastPathSeparator = arg.lastIndexOf("/");
var parent = arg.substr(0, lastPathSeparator + 1);
partial = arg.substr(lastPathSeparator + 1);
+ if(partial === '..' || partial === '.') {
+ return callback({
+ completion: '/',
+ suggestions: []
+ });
+ }
_console.log("completing children via parent '" + parent+"' w/ partial '"+partial+"'");
return self.getNode(parent, function(node) {
if(!node) {
diff --git a/js/readline.js b/js/readline.js
index 2534ce6..a710f23 100644
--- a/js/readline.js
+++ b/js/readline.js
@@ -1,5 +1,5 @@
/* ------------------------------------------------------------------------*
- * Copyright 2013 Arne F. Claassen
+ * Copyright 2013-2014 Arne F. Claassen
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,26 +15,28 @@
*-------------------------------------------------------------------------*/
var Josh = Josh || {};
-Josh.Version = "0.2.6";
+Josh.Version = "0.2.10";
(function(root) {
- var SPECIAL = {
- 8: 'BACKSPACE',
- 9: 'TAB',
- 13: 'ENTER',
- 19: 'PAUSE',
- 20: 'CAPS_LOCK',
- 27: 'ESCAPE',
- 32: 'SPACE',
- 33: 'PAGE_UP',
- 34: 'PAGE_DOWN',
- 35: 'END',
- 36: 'HOME',
- 37: 'LEFT',
- 38: 'UP',
- 39: 'RIGHT',
- 40: 'DOWN',
- 45: 'INSERT',
- 46: 'DELETE'
+ Josh.Keys = {
+ Special: {
+ Backspace: 8,
+ Tab: 9,
+ Enter: 13,
+ Pause: 19,
+ CapsLock: 20,
+ Escape: 27,
+ Space: 32,
+ PageUp: 33,
+ PageDown: 34,
+ End: 35,
+ Home: 36,
+ Left: 37,
+ Up: 38,
+ Right: 39,
+ Down: 40,
+ Insert: 45,
+ Delete: 46
+ }
};
Josh.ReadLine = function(config) {
@@ -46,8 +48,9 @@ Josh.Version = "0.2.6";
}
});
var _history = config.history || new Josh.History();
- var _deactivationKey = config.deactivationKey || { keyCode: 27 }; // Esc
var _killring = config.killring || new Josh.KillRing();
+ var _boundToElement = config.element ? true : false;
+ var _element = config.element || root;
var _active = false;
var _onActivate;
var _onDeactivate;
@@ -69,6 +72,72 @@ Josh.Version = "0.2.6";
var _completionActive;
var _cmdQueue = [];
var _suspended = false;
+ var _cmdMap = {
+ complete: cmdComplete,
+ done: cmdDone,
+ noop: cmdNoOp,
+ history_top: cmdHistoryTop,
+ history_end: cmdHistoryEnd,
+ history_next: cmdHistoryNext,
+ history_previous: cmdHistoryPrev,
+ end: cmdEnd,
+ home: cmdHome,
+ left: cmdLeft,
+ right: cmdRight,
+ cancel: cmdCancel,
+ 'delete': cmdDeleteChar,
+ backspace: cmdBackspace,
+ kill_eof: cmdKillToEOF,
+ kill_wordback: cmdKillWordBackward,
+ kill_wordforward: cmdKillWordForward,
+ yank: cmdYank,
+ clear: cmdClear,
+ search: cmdReverseSearch,
+ wordback: cmdBackwardWord,
+ wordforward: cmdForwardWord,
+ yank_rotate: cmdRotate
+ };
+ var _keyMap = {
+ 'default': {
+ 8: cmdBackspace, // Backspace
+ 9: cmdComplete, // Tab
+ 13: cmdDone, // Enter
+ 27: cmdEsc, // Esc
+ 33: cmdHistoryTop, // Page Up
+ 34: cmdHistoryEnd, // Page Down
+ 35: cmdEnd, // End
+ 36: cmdHome, // Home
+ 37: cmdLeft, // Left
+ 38: cmdHistoryPrev, // Up
+ 39: cmdRight, // Right
+ 40: cmdHistoryNext, // Down
+ 46: cmdDeleteChar, // Delete
+ 10: cmdNoOp, // Pause
+ 19: cmdNoOp, // Caps Lock
+ 45: cmdNoOp // Insert
+ },
+ control: {
+ 65: cmdHome, // A
+ 66: cmdLeft, // B
+ 67: cmdCancel, // C
+ 68: cmdDeleteChar, // D
+ 69: cmdEnd, // E
+ 70: cmdRight, // F
+ 80: cmdHistoryPrev, // P
+ 78: cmdHistoryNext, // N
+ 75: cmdKillToEOF, // K
+ 89: cmdYank, // Y
+ 76: cmdClear, // L
+ 82: cmdReverseSearch // R
+ },
+ meta: {
+ 8: cmdKillWordBackward, // Backspace
+ 66: cmdBackwardWord, // B
+ 68: cmdKillWordForward, // D
+ 70: cmdForwardWord, // F
+ 89: cmdRotate // Y
+ }
+ };
// public methods
var self = {
@@ -87,6 +156,36 @@ Josh.Version = "0.2.6";
_onDeactivate();
}
},
+ bind: function(key, action) {
+ var k = getKey(key);
+ var cmd = _cmdMap[action];
+ if(!cmd) {
+ return;
+ }
+ _keyMap[k.modifier][k.code];
+ },
+ unbind: function(key) {
+ var k = getKey(key);
+ delete _keyMap[k.modifier][k.code];
+ },
+ attach: function(el) {
+ if(_element) {
+ self.detach();
+ }
+ _console.log("attaching");
+ _console.log(el);
+ _element = el;
+ _boundToElement = true;
+ addEvent(_element, "focus", self.activate);
+ addEvent(_element, "blur", self.deactivate);
+ subscribeToKeys();
+ },
+ detach: function() {
+ removeEvent(_element, "focus", self.activate);
+ removeEvent(_element, "blur", self.deactivate);
+ _element = null;
+ _boundToElement = false;
+ },
onActivate: function(completionHandler) {
_onActivate = completionHandler;
},
@@ -125,10 +224,31 @@ Josh.Version = "0.2.6";
text: _text,
cursor: _cursor
};
+ },
+ setLine: function(line) {
+ _text = line.text;
+ _cursor = line.cursor;
+ refresh();
}
};
// private methods
+ function addEvent(element, name, callback) {
+ if(element.addEventListener) {
+ element.addEventListener(name, callback, false);
+ } else if(element.attachEvent) {
+ element.attachEvent('on' + name, callback);
+ }
+ }
+
+ function removeEvent(element, name, callback) {
+ if(element.removeEventListener) {
+ element.removeEventListener(name, callback, false);
+ } else if(element.detachEvent) {
+ element.detachEvent('on' + name, callback);
+ }
+ }
+
function getKeyInfo(e) {
var code = e.keyCode || e.charCode;
var c = String.fromCharCode(code);
@@ -142,6 +262,22 @@ Josh.Version = "0.2.6";
};
}
+ function getKey(key) {
+ var k = {
+ modifier: 'default',
+ code: key.keyCode
+ };
+ if(key.metaKey || key.altKey) {
+ k.modifier = 'meta';
+ } else if(key.ctrlKey) {
+ k.modifier = 'control';
+ }
+ if(key['char']) {
+ k.code = key['char'].charCodeAt(0);
+ }
+ return k;
+ }
+
function queue(cmd) {
if(_suspended) {
_cmdQueue.push(cmd);
@@ -525,164 +661,69 @@ Josh.Version = "0.2.6";
return left + ins + right;
}
+ function subscribeToKeys() {
- // set up key capture
- root.onkeydown = function(e) {
- e = e || window.event;
-
- // return as unhandled if we're not active or the key is just a modifier key
- if(!_active || e.keyCode == 16 || e.keyCode == 17 || e.keyCode == 18 || e.keyCode == 91) {
- return true;
- }
-
- var cmd = null;
-
- // check for some special first keys, regardless of modifiers
- switch(e.keyCode) {
- case 8: // Backspace
- cmd = cmdBackspace;
- break;
- case 9: // Tab
- cmd = cmdComplete;
- break;
- case 13: // Enter
- cmd = cmdDone;
- break;
- case 27: // Esc
- cmd = cmdEsc;
- break;
- case 33: // Page Up
- cmd = cmdHistoryTop;
- break;
- case 34: // Page Down
- cmd = cmdHistoryEnd;
- break;
- case 35: // End
- cmd = cmdEnd;
- break;
- case 36: // Home
- cmd = cmdHome;
- break;
- case 37: // Left
- cmd = cmdLeft;
- break;
- case 38: // Up
- cmd = cmdHistoryPrev;
- break;
- case 39: // Right
- cmd = cmdRight;
- break;
- case 40: // Down
- cmd = cmdHistoryNext;
- break;
- case 46: // Delete
- cmd = cmdDeleteChar;
- break;
-
- // these we catch and have no commands for
- case 10: // Pause
- case 19: // Caps Lock
- case 45: // Insert
- cmd = cmdNoOp;
- break;
-
- // all others we don't handle at this level
- default:
- break;
- }
-
- // intercept ctrl- and meta- sequences (may override the non-modifier cmd captured above
- if(e.ctrlKey && !e.shiftKey && !e.altKey && !e.metaKey) {
- switch(e.keyCode) {
- case 65: // A
- cmd = cmdHome;
- break;
- case 66: // B
- cmd = cmdLeft;
- break;
- case 67: // C
- cmd = cmdCancel;
- break;
- case 68: // D
- cmd = cmdDeleteChar;
- break;
- case 69: // E
- cmd = cmdEnd;
- break;
- case 70: // F
- cmd = cmdRight;
- break;
- case 80: // P
- cmd = cmdHistoryPrev;
- break;
- case 78: // N
- cmd = cmdHistoryNext;
- break;
- case 75: // K
- cmd = cmdKillToEOF;
- break;
- case 89: // Y
- cmd = cmdYank;
- break;
- case 76: // L
- cmd = cmdClear;
- break;
- case 82: // R
- cmd = cmdReverseSearch;
- break;
- }
- } else if((e.altKey || e.metaKey) && !e.ctrlKey && !e.shiftKey) {
- switch(e.keyCode) {
- case 8: // Backspace
- cmd = cmdKillWordBackward;
- break;
- case 66: // B
- cmd = cmdBackwardWord;
- break;
- case 68: // D
- cmd = cmdKillWordForward;
- break;
- case 70: // F
- cmd = cmdForwardWord;
- break;
- case 89: // Y
- cmd = cmdRotate;
- break;
+ // set up key capture
+ _element.onkeydown = function(e) {
+ e = e || window.event;
+
+ // return as unhandled if we're not active or the key is just a modifier key
+ if(!_active || e.keyCode == 16 || e.keyCode == 17 || e.keyCode == 18 || e.keyCode == 91) {
+ return true;
}
- }
- if(!cmd) {
- return true;
- }
- queue(cmd);
- e.preventDefault();
- e.stopPropagation();
- e.cancelBubble = true;
- return false;
- };
- root.onkeypress = function(e) {
- if(!_active) {
- return true;
- }
- var key = getKeyInfo(e);
- if(key.code == 0 || e.defaultPrevented) {
- return false;
- }
- queue(function cmdKeyPress() {
- if(_inSearch) {
- addSearchText(key.character);
- } else {
- addText(key.character);
+ // check for some special first keys, regardless of modifiers
+ _console.log("key: " + e.keyCode);
+ var cmd = _keyMap['default'][e.keyCode];
+ // intercept ctrl- and meta- sequences (may override the non-modifier cmd captured above
+ var mod;
+ if(e.ctrlKey && !e.shiftKey && !e.altKey && !e.metaKey) {
+ mod = _keyMap.control[e.keyCode];
+ if(mod) {
+ cmd = mod;
+ }
+ } else if((e.altKey || e.metaKey) && !e.ctrlKey && !e.shiftKey) {
+ mod = _keyMap.meta[e.keyCode];
+ if(mod) {
+ cmd = mod;
+ }
}
- });
- e.preventDefault();
- e.stopPropagation();
- e.cancelBubble = true;
- return false;
- };
+ if(!cmd) {
+ return true;
+ }
+ queue(cmd);
+ e.preventDefault();
+ e.stopPropagation();
+ e.cancelBubble = true;
+ return false;
+ };
+ _element.onkeypress = function(e) {
+ if(!_active) {
+ return true;
+ }
+ var key = getKeyInfo(e);
+ if(key.code == 0 || e.defaultPrevented || e.metaKey || e.altKey || e.ctrlKey) {
+ return false;
+ }
+ queue(function cmdKeyPress() {
+ if(_inSearch) {
+ addSearchText(key.character);
+ } else {
+ addText(key.character);
+ }
+ });
+ e.preventDefault();
+ e.stopPropagation();
+ e.cancelBubble = true;
+ return false;
+ };
+ }
+ if(_boundToElement) {
+ self.attach(_element);
+ } else {
+ subscribeToKeys();
+ }
return self;
};
})(this);
-
-
diff --git a/js/shell.js b/js/shell.js
index 6b36c29..ba27216 100644
--- a/js/shell.js
+++ b/js/shell.js
@@ -1,5 +1,5 @@
/* ------------------------------------------------------------------------*
- * Copyright 2013 Arne F. Claassen
+ * Copyright 2013-2014 Arne F. Claassen
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -86,7 +86,7 @@ var Josh = Josh || {};
history: _.template("
<% _.each(items, function(cmd, i) { %>
<%- i %> <%- cmd %>
<% }); %>
"),
help: _.template("
Commands:
<% _.each(commands, function(cmd) { %>
<%- cmd %>
<% }); %>
"),
bad_command: _.template('
Unrecognized command: <%=cmd%>
'),
- input_cmd: _.template('
'),
+ input_cmd: _.template('
'),
input_search: _.template('
(reverse-i-search)`\':
'),
suggest: _.template("
<% _.each(suggestions, function(suggestion) { %>
<%- suggestion %>
<% }); %>
")
},
@@ -147,7 +147,7 @@ var Josh = Josh || {};
var left = _.escape(text.substr(0, cursorIdx)).replace(/ /g, ' ');
var cursor = text.substr(cursorIdx, 1);
var right = _.escape(text.substr(cursorIdx + 1)).replace(/ /g, ' ');
- $(id(_input_id) + ' .prompt').text(_prompt);
+ $(id(_input_id) + ' .prompt').html(_prompt);
$(id(_input_id) + ' .input .left').html(left);
if(!cursor) {
$(id(_input_id) + ' .input .cursor').html(' ').css('textDecoration', 'underline');