From c01ef608d6c5204a7b87e2c9eee2dd66140f9e03 Mon Sep 17 00:00:00 2001 From: Arne Claassen Date: Wed, 13 Feb 2013 21:49:30 -0800 Subject: [PATCH 01/17] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 91ead01..053f3eb 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -josh.js 0.3 +josh.js 0.2 =========== http://sdether.github.com/josh.js/ @@ -125,7 +125,7 @@ By implementing the functions `getNode` and `getChildNodes`, this library adds p ## Changelog -**0.3** -- 2013/02/13 +**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 From 73dffde2661cbedc1a0e5d020a157cf55b273faa Mon Sep 17 00:00:00 2001 From: Arne Claassen Date: Wed, 13 Feb 2013 21:50:08 -0800 Subject: [PATCH 02/17] Update js/readline.js --- js/readline.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/readline.js b/js/readline.js index 2534ce6..739b713 100644 --- a/js/readline.js +++ b/js/readline.js @@ -15,7 +15,7 @@ *-------------------------------------------------------------------------*/ var Josh = Josh || {}; -Josh.Version = "0.2.6"; +Josh.Version = "0.2.7"; (function(root) { var SPECIAL = { 8: 'BACKSPACE', From 275e63df72312cdfbe358aebae42fc384083603b Mon Sep 17 00:00:00 2001 From: Arne Claassen Date: Wed, 13 Mar 2013 23:22:53 -0700 Subject: [PATCH 03/17] 0.2.8, minor tweaks --- .idea/misc.xml | 3 --- README.md | 5 +++++ js/example.js | 8 ++++---- js/pathhandler.js | 6 ++++++ js/shell.js | 4 ++-- 5 files changed, 17 insertions(+), 9 deletions(-) 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 053f3eb..d33e45d 100644 --- a/README.md +++ b/README.md @@ -125,6 +125,11 @@ By implementing the functions `getNode` and `getChildNodes`, this library adds p ## Changelog +**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 diff --git a/js/example.js b/js/example.js index 0f00691..df91fbe 100644 --- a/js/example.js +++ b/js/example.js @@ -150,9 +150,9 @@ $(document).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. @@ -170,7 +170,7 @@ _console.log("activating shell"); if(event.keyCode == 126) { event.preventDefault(); - shell.activate(); + shell.activate(); $consolePanel.slideDown(); $consolePanel.focus(); } diff --git a/js/pathhandler.js b/js/pathhandler.js index 62964aa..d15247a 100644 --- a/js/pathhandler.js +++ b/js/pathhandler.js @@ -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/shell.js b/js/shell.js index 6b36c29..21a54cf 100644 --- a/js/shell.js +++ b/js/shell.js @@ -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'); From bafe7ac3186cf9efa5e9ead66f14b64d83f27386 Mon Sep 17 00:00:00 2001 From: Arne Claassen Date: Mon, 18 Mar 2013 10:24:11 -0700 Subject: [PATCH 04/17] Update README.md --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index d33e45d..beea303 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,15 @@ http://sdether.github.com/josh.js/ * `history.js` - localStorage backed command history * `killring.js` - killring for kill & yank handling in readline +## 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 From 26af7ce3d00d272abf84041e1407e7d7f7ca6500 Mon Sep 17 00:00:00 2001 From: Arne Claassen Date: Tue, 13 Aug 2013 09:17:07 -0700 Subject: [PATCH 05/17] fixing links in readme --- README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index beea303..1a49ff3 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ 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: @@ -12,10 +12,10 @@ http://sdether.github.com/josh.js/ * `killring.js` - killring for kill & yank handling in readline ## 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, +* 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 +* 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. @@ -140,17 +140,17 @@ By implementing the functions `getNode` and `getChildNodes`, this library adds p * 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 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 From 6dad841e240b1cf7d893090b3e7ac7ac6297a6e2 Mon Sep 17 00:00:00 2001 From: Arne Claassen Date: Tue, 13 Aug 2013 08:20:19 -0700 Subject: [PATCH 06/17] - resolves https://github.com/sdether/josh.js/issues/8 - adds Josh.Input for easy binding of Readline to a input fields - adds custom keybinding capabilities for Readline --- README.md | 5 + index.html | 98 ++++++++----- js/example.js | 6 +- js/input.js | 172 ++++++++++++++++++++++ js/readline.js | 385 +++++++++++++++++++++++++++---------------------- 5 files changed, 456 insertions(+), 210 deletions(-) create mode 100644 js/input.js diff --git a/README.md b/README.md index 1a49ff3..6c3a6d7 100644 --- a/README.md +++ b/README.md @@ -134,6 +134,11 @@ By implementing the functions `getNode` and `getChildNodes`, this library adds p ## Changelog +**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. 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 df91fbe..e9f9a08 100644 --- a/js/example.js +++ b/js/example.js @@ -147,7 +147,7 @@ // ----------------------- // 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-panel-id`. The `Shell` display model relies on a 'panel' to contain a 'view'. @@ -167,10 +167,10 @@ } // 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(); + shell.activate(); $consolePanel.slideDown(); $consolePanel.focus(); } diff --git a/js/input.js b/js/input.js new file mode 100644 index 0000000..bac7d45 --- /dev/null +++ b/js/input.js @@ -0,0 +1,172 @@ +/* ------------------------------------------------------------------------* + * Copyright 2013 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/readline.js b/js/readline.js index 739b713..e1b9368 100644 --- a/js/readline.js +++ b/js/readline.js @@ -15,26 +15,28 @@ *-------------------------------------------------------------------------*/ var Josh = Josh || {}; -Josh.Version = "0.2.7"; +Josh.Version = "0.2.9"; (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.7"; } }); 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.7"; 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.7"; _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.7"; 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.7"; }; } + 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,162 +661,69 @@ Josh.Version = "0.2.7"; 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); From 66e66bbc8f2ce2bf26257da01a89b58234b14175 Mon Sep 17 00:00:00 2001 From: Brice Fernandes Date: Thu, 13 Mar 2014 19:45:31 +0000 Subject: [PATCH 07/17] Create example bower file --- bower.json | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 bower.json diff --git a/bower.json b/bower.json new file mode 100644 index 0000000..dff3d34 --- /dev/null +++ b/bower.json @@ -0,0 +1,29 @@ +{ + "name": "josh.js", + "version": "0.2.9", + "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/input.js", + "js/killring.js", + "js/pathhandler.js", + "js/shell.js" + ], + "keywords": [ + "shell", + "josh" + ], + "license": "Apache 2.0", + "ignore": [ + "**/.*", + "node_modules", + "bower_components", + "test", + "tests" + ] +} From 175862df255e133449566309f6c6df069d7c6a63 Mon Sep 17 00:00:00 2001 From: Aaron Mars Date: Wed, 2 Apr 2014 14:11:34 -0700 Subject: [PATCH 08/17] Fixes for closure compiler builds --- js/example.js | 8 ++++---- js/input.js | 6 +++--- js/readline.js | 14 ++++++-------- 3 files changed, 13 insertions(+), 15 deletions(-) diff --git a/js/example.js b/js/example.js index e9f9a08..1291cee 100644 --- a/js/example.js +++ b/js/example.js @@ -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] == ".") { @@ -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/input.js b/js/input.js index bac7d45..4ea40ee 100644 --- a/js/input.js +++ b/js/input.js @@ -22,7 +22,7 @@ var Josh = Josh || {}; var range = this.createTextRange(); range.move("character", index); range.select(); - } else if (this.selectionStart != null) { + } else if (this.selectionStart !== null) { this.setSelectionRange(index, index); } next(); @@ -34,7 +34,7 @@ var Josh = Josh || {}; var range = el.createTextRange(); range.moveStart('character', -el.value.length); return range.text.length; - } else if (el.selectionStart != null) { + } else if (el.selectionStart !== null) { return el.selectionStart; } return 0; @@ -154,7 +154,7 @@ var Josh = Josh || {}; readline.onChange(renderSpan); } readline.unbind({keyCode: Josh.Keys.Special.Tab}); - readline.unbind({char: 'R', ctrlKey: true}); + readline.unbind({'char': 'R', ctrlKey: true}); readline.onActivate(function () { _active = true; activate(); diff --git a/js/readline.js b/js/readline.js index e1b9368..f8961b9 100644 --- a/js/readline.js +++ b/js/readline.js @@ -85,7 +85,7 @@ Josh.Version = "0.2.9"; left: cmdLeft, right: cmdRight, cancel: cmdCancel, - delete: cmdDeleteChar, + 'delete': cmdDeleteChar, backspace: cmdBackspace, kill_eof: cmdKillToEOF, kill_wordback: cmdKillWordBackward, @@ -96,9 +96,9 @@ Josh.Version = "0.2.9"; wordback: cmdBackwardWord, wordforward: cmdForwardWord, yank_rotate: cmdRotate - } + }; var _keyMap = { - default: { + 'default': { 8: cmdBackspace, // Backspace 9: cmdComplete, // Tab 13: cmdDone, // Enter @@ -272,8 +272,8 @@ Josh.Version = "0.2.9"; } else if(key.ctrlKey) { k.modifier = 'control'; } - if(key.char) { - k.code = key.char.charCodeAt(0); + if(key['char']) { + k.code = key['char'].charCodeAt(0); } return k; } @@ -674,7 +674,7 @@ Josh.Version = "0.2.9"; // check for some special first keys, regardless of modifiers _console.log("key: " + e.keyCode); - var cmd = _keyMap.default[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) { @@ -727,5 +727,3 @@ Josh.Version = "0.2.9"; return self; }; })(this); - - From d85d4d75f93078f24b3617e0ccb2ce8d2e2ae926 Mon Sep 17 00:00:00 2001 From: Arne Claassen Date: Thu, 3 Apr 2014 21:08:55 -0700 Subject: [PATCH 09/17] - 0.2.10 readme update - updated copyright for 2014 --- README.md | 4 ++++ bower.json | 2 +- js/example.js | 2 +- js/history.js | 2 +- js/input.js | 2 +- js/killring.js | 2 +- js/pathhandler.js | 2 +- js/readline.js | 4 ++-- js/shell.js | 2 +- 9 files changed, 13 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 6c3a6d7..d9ab5d6 100644 --- a/README.md +++ b/README.md @@ -134,6 +134,10 @@ By implementing the functions `getNode` and `getChildNodes`, this library adds p ## Changelog +**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. diff --git a/bower.json b/bower.json index dff3d34..218274d 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "josh.js", - "version": "0.2.9", + "version": "0.2.10", "homepage": "http://sdether.github.io/josh.js/", "authors": [ "Arne Claassen " diff --git a/js/example.js b/js/example.js index 1291cee..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. diff --git a/js/history.js b/js/history.js index 49fb27a..dff58b3 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. diff --git a/js/input.js b/js/input.js index 4ea40ee..3085db2 100644 --- a/js/input.js +++ b/js/input.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/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 d15247a..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. diff --git a/js/readline.js b/js/readline.js index f8961b9..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,7 +15,7 @@ *-------------------------------------------------------------------------*/ var Josh = Josh || {}; -Josh.Version = "0.2.9"; +Josh.Version = "0.2.10"; (function(root) { Josh.Keys = { Special: { diff --git a/js/shell.js b/js/shell.js index 21a54cf..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. From e5661b0ec7830c1f2281842b09a85e1d5fce20f3 Mon Sep 17 00:00:00 2001 From: jed apostol Date: Wed, 20 Aug 2014 16:38:40 -0700 Subject: [PATCH 10/17] Any call to local storage must be wrapped inside a try catch, due to Safari not allowing localStorage in private browsing mode --- js/history.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/js/history.js b/js/history.js index dff58b3..bd2c594 100644 --- a/js/history.js +++ b/js/history.js @@ -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; @@ -37,8 +41,10 @@ var Josh = Josh || {}; } } function save() { - if (_storage) { + try { _storage.setItem(_key, JSON.stringify(_history)); + } catch(e) { + _console.log("Error accessing storage"); } } From 0041f29eff359b2b6ea03fdcf3d17b0b6e6ab380 Mon Sep 17 00:00:00 2001 From: jed apostol Date: Wed, 20 Aug 2014 16:51:36 -0700 Subject: [PATCH 11/17] replaced condition --- js/history.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/js/history.js b/js/history.js index bd2c594..7e4e38c 100644 --- a/js/history.js +++ b/js/history.js @@ -41,10 +41,12 @@ var Josh = Josh || {}; } } function save() { - try { - _storage.setItem(_key, JSON.stringify(_history)); - } catch(e) { - _console.log("Error accessing storage"); + if (_storage) { + try { + _storage.setItem(_key, JSON.stringify(_history)); + } catch(e) { + _console.log("Error accessing storage"); + } } } From e036b8034177970a8cc61a9c7b47e43ac07706ff Mon Sep 17 00:00:00 2001 From: LewisTehMinerz Date: Fri, 8 Jan 2016 19:38:56 +0000 Subject: [PATCH 12/17] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d9ab5d6..fbb7993 100644 --- a/README.md +++ b/README.md @@ -130,7 +130,7 @@ 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 From 742ddd058d2bb899280cfe8c7595a82ac207c31b Mon Sep 17 00:00:00 2001 From: hiepvo Date: Fri, 5 Feb 2016 11:35:59 -0600 Subject: [PATCH 13/17] add new section 'What to use Josh for and when to use it' --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index fbb7993..042f11d 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,10 @@ http://sdether.github.io/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. + ## 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, From 2166127fa6fa90527d825f867daa94a6d4f1404a Mon Sep 17 00:00:00 2001 From: Irek Romaniuk Date: Fri, 5 Feb 2016 13:30:35 -0500 Subject: [PATCH 14/17] space added --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 042f11d..49d3d36 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ http://sdether.github.io/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 +## 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. From b1a36eb3f86dda7d18139010db3c0e2314bf8982 Mon Sep 17 00:00:00 2001 From: hiep vo Date: Fri, 5 Feb 2016 12:48:11 -0600 Subject: [PATCH 15/17] Update README.md some more sentences when to use josh --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 49d3d36..df4a0d9 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ http://sdether.github.io/josh.js/ ## 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. +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 From 0d7fe0d04f7892449e0e765c6b9ae7bdf42b024b Mon Sep 17 00:00:00 2001 From: Matteo Scandolo Date: Wed, 10 Aug 2016 13:40:47 -0700 Subject: [PATCH 16/17] Added bower deps to jQuery and lodash, changed files order in main section --- .gitignore | 3 ++- bower.json | 8 ++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) 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/bower.json b/bower.json index 218274d..9971f61 100644 --- a/bower.json +++ b/bower.json @@ -9,8 +9,8 @@ "main": [ "js/readline.js", "js/history.js", - "js/input.js", "js/killring.js", + "js/input.js", "js/pathhandler.js", "js/shell.js" ], @@ -25,5 +25,9 @@ "bower_components", "test", "tests" - ] + ], + "dependencies": { + "jquery": "~3.1.0", + "lodash": "~4.14.2" + } } From 1a4ef273b8006f44e1209f4e7e0f5b17b40844cf Mon Sep 17 00:00:00 2001 From: Irek Romaniuk Date: Wed, 10 Aug 2016 16:47:58 -0400 Subject: [PATCH 17/17] Non developer readme contribution (#33) * non developer readme contribution I am assigned project from ModernDeveloper to write a clear and easy-to-understand introduction to JS library I like to. * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index df4a0d9..c2379c2 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ josh.js 0.2 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