From b4d9d015537224602501213638f12435aaca8b35 Mon Sep 17 00:00:00 2001 From: Dan Spagnoli Date: Wed, 7 Feb 2018 12:53:03 -0500 Subject: [PATCH 1/8] testing on android --- jquery.console.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/jquery.console.js b/jquery.console.js index 794fc23..a8dd5c2 100644 --- a/jquery.console.js +++ b/jquery.console.js @@ -299,7 +299,7 @@ typer.keydown(function(e){ cancelKeyPress = 0; - var keyCode = e.keyCode; + var keyCode = e.which || e.code; // C-c: cancel the execution if(e.ctrlKey && keyCode == 67) { cancelKeyPress = keyCode; @@ -325,12 +325,6 @@ return false; } } - }); - - //////////////////////////////////////////////////////////////////////// - // Handle key press - typer.keypress(function(e){ - var keyCode = e.keyCode || e.which; if (isIgnorableKey(e)) { return false; } @@ -342,14 +336,20 @@ if (cancelKeyPress) return false; if ( typeof config.charInsertTrigger == 'undefined' || ( - typeof config.charInsertTrigger == 'function' && + typeof config.charInsertTrigger == 'faunction' && config.charInsertTrigger(keyCode,promptText) ) ){ - typer.consoleInsert(keyCode); + let currentKey = e.key; + if (!currentKey) { + currentKey = String.fromCharCode(keyCode); + } + + typer.consoleInsert(currentKey); } } if (isWebkit) return false; + }); function isIgnorableKey(e) { From d37396e6ab83dca808ca62d7ea7956e907e8f681 Mon Sep 17 00:00:00 2001 From: Dan Spagnoli Date: Wed, 7 Feb 2018 12:57:22 -0500 Subject: [PATCH 2/8] testing on android --- jquery.console.js | 1 + 1 file changed, 1 insertion(+) diff --git a/jquery.console.js b/jquery.console.js index a8dd5c2..815e9c7 100644 --- a/jquery.console.js +++ b/jquery.console.js @@ -298,6 +298,7 @@ // For picking up control characters like up/left/down/right typer.keydown(function(e){ + console.log(e); cancelKeyPress = 0; var keyCode = e.which || e.code; // C-c: cancel the execution From eff018e34431b7decf94dfec77c946411028f922 Mon Sep 17 00:00:00 2001 From: Dan Spagnoli Date: Wed, 7 Feb 2018 13:37:31 -0500 Subject: [PATCH 3/8] fixed for android, maybe --- demo.html | 2 +- jquery.console.js | 1495 +++++++++++++++++++++++---------------------- 2 files changed, 754 insertions(+), 743 deletions(-) diff --git a/demo.html b/demo.html index 2a3c0ed..daa4daa 100644 --- a/demo.html +++ b/demo.html @@ -55,7 +55,7 @@ controller2.promptText('5 * 4'); /* Third console */ var console3CancelFlag = false; - var console3 = $('
'); + var console3 = $('
'); $('body').append(console3); var controller3 = console3.console({ promptLabel: 'Echo> ', diff --git a/jquery.console.js b/jquery.console.js index 815e9c7..da9080e 100644 --- a/jquery.console.js +++ b/jquery.console.js @@ -37,800 +37,811 @@ // Safari 4.0.5 (6531.22.7) (Mac) // Google Chrome 5.0.375.55 (Mac) -(function($){ - var isWebkit = !!~navigator.userAgent.indexOf(' AppleWebKit/'); - - $.fn.console = function(config){ - //////////////////////////////////////////////////////////////////////// - // Constants - // Some are enums, data types, others just for optimisation - var keyCodes = { - // left - 37: moveBackward, - // right - 39: moveForward, - // up - 38: previousHistory, - // down - 40: nextHistory, - // backspace - 8: backDelete, - // delete - 46: forwardDelete, - // end - 35: moveToEnd, - // start - 36: moveToStart, - // return - 13: commandTrigger, - // tab - 18: doNothing, - // tab - 9: doComplete - }; - var ctrlCodes = { - // C-a - 65: moveToStart, - // C-e - 69: moveToEnd, - // C-d - 68: forwardDelete, - // C-n - 78: nextHistory, - // C-p - 80: previousHistory, - // C-b - 66: moveBackward, - // C-f - 70: moveForward, - // C-k - 75: deleteUntilEnd, - // C-l - 76: clearScreen, - // C-u - 85: clearCurrentPrompt - }; - if(config.ctrlCodes) { - $.extend(ctrlCodes, config.ctrlCodes); - } - var altCodes = { - // M-f - 70: moveToNextWord, - // M-b - 66: moveToPreviousWord, - // M-d - 68: deleteNextWord - }; - var shiftCodes = { - // return - 13: newLine, - }; - var cursor = ' '; - - //////////////////////////////////////////////////////////////////////// - // Globals - var container = $(this); - var inner = $('
'); - // erjiang: changed this from a text input to a textarea so we - // can get pasted newlines - var typer = $(''); - // Prompt - var promptBox; - var prompt; - var continuedPromptLabel = config && config.continuedPromptLabel? - config.continuedPromptLabel : "> "; - var column = 0; - var promptText = ''; - var restoreText = ''; - var continuedText = ''; - var fadeOnReset = config.fadeOnReset !== undefined ? config.fadeOnReset : true; - // Prompt history stack - var history = []; - var ringn = 0; - // For reasons unknown to The Sword of Michael himself, Opera - // triggers and sends a key character when you hit various - // keys like PgUp, End, etc. So there is no way of knowing - // when a user has typed '#' or End. My solution is in the - // typer.keydown and typer.keypress functions; I use the - // variable below to ignore the keypress event if the keydown - // event succeeds. - var cancelKeyPress = 0; - // When this value is false, the prompt will not respond to input - var acceptInput = true; - // When this value is true, the command has been canceled - var cancelCommand = false; - - // External exports object - var extern = {}; - - //////////////////////////////////////////////////////////////////////// - // Main entry point - (function(){ - extern.promptLabel = config && config.promptLabel? config.promptLabel : "> "; - container.append(inner); - inner.append(typer); - typer.css({position:'absolute',top:0,left:'-9999px'}); - if (config.welcomeMessage) - message(config.welcomeMessage,'jquery-console-welcome'); - newPromptBox(); - if (config.autofocus) { - inner.addClass('jquery-console-focus'); - typer.focus(); - setTimeout(function(){ - inner.addClass('jquery-console-focus'); - typer.focus(); - },100); - } - extern.inner = inner; - extern.typer = typer; - extern.scrollToBottom = scrollToBottom; - extern.report = report; - extern.showCompletion = showCompletion; - extern.clearScreen = clearScreen; - })(); - - //////////////////////////////////////////////////////////////////////// - // Reset terminal - extern.reset = function(){ - var welcome = (typeof config.welcomeMessage != 'undefined'); - - var removeElements = function() { - inner.find('div').each(function(){ - if (!welcome) { - $(this).remove(); - } else { - welcome = false; - } - }); - }; - - if (fadeOnReset) { - inner.parent().fadeOut(function() { - removeElements(); - newPromptBox(); - inner.parent().fadeIn(focusConsole); - }); - } - else { - removeElements(); - newPromptBox(); - focusConsole(); - } - }; - - var focusConsole = function() { - inner.addClass('jquery-console-focus'); - typer.focus(); - }; - - extern.focus = function(){ - focusConsole(); - } - - //////////////////////////////////////////////////////////////////////// - // Reset terminal - extern.notice = function(msg,style){ - var n = $('
').append($('
').text(msg)) - .css({visibility:'hidden'}); - container.append(n); - var focused = true; - if (style=='fadeout') - setTimeout(function(){ - n.fadeOut(function(){ - n.remove(); - }); - },4000); - else if (style=='prompt') { - var a = $('
'); - n.append(a); - focused = false; - a.click(function(){ n.fadeOut(function(){ n.remove();inner.css({opacity:1}) }); }); - } - var h = n.height(); - n.css({height:'0px',visibility:'visible'}) - .animate({height:h+'px'},function(){ - if (!focused) inner.css({opacity:0.5}); - }); - n.css('cursor','default'); - return n; - }; - - //////////////////////////////////////////////////////////////////////// - // Make a new prompt box - function newPromptBox() { - column = 0; - promptText = ''; - ringn = 0; // Reset the position of the history ring - enableInput(); - promptBox = $('
'); - var label = $(''); - var labelText = extern.continuedPrompt? continuedPromptLabel : extern.promptLabel; - promptBox.append(label.text(labelText).show()); - label.html(label.html().replace(' ',' ')); - prompt = $(''); - promptBox.append(prompt); - inner.append(promptBox); - updatePromptDisplay(); - }; - - //////////////////////////////////////////////////////////////////////// - // Handle setting focus - container.click(function(){ - // Don't mess with the focus if there is an active selection - if (window.getSelection().toString()) { - return false; - } - - inner.addClass('jquery-console-focus'); - inner.removeClass('jquery-console-nofocus'); - if (isWebkit) { - typer.focusWithoutScrolling(); - } else { - typer.css('position', 'fixed').focus(); - } - scrollToBottom(); - return false; - }); - - //////////////////////////////////////////////////////////////////////// - // Handle losing focus - typer.blur(function(){ - inner.removeClass('jquery-console-focus'); - inner.addClass('jquery-console-nofocus'); - }); - - //////////////////////////////////////////////////////////////////////// - // Bind to the paste event of the input box so we know when we - // get pasted data - typer.bind('paste', function(e) { - // wipe typer input clean just in case - typer.val(""); - // this timeout is required because the onpaste event is - // fired *before* the text is actually pasted - setTimeout(function() { - typer.consoleInsert(typer.val()); - typer.val(""); - }, 0); - }); - - //////////////////////////////////////////////////////////////////////// - // Handle key hit before translation - // For picking up control characters like up/left/down/right - - typer.keydown(function(e){ - console.log(e); - cancelKeyPress = 0; - var keyCode = e.which || e.code; - // C-c: cancel the execution - if(e.ctrlKey && keyCode == 67) { - cancelKeyPress = keyCode; - cancelExecution(); - return false; - } - if (acceptInput) { - if (e.shiftKey && keyCode in shiftCodes) { - cancelKeyPress = keyCode; - (shiftCodes[keyCode])(); - return false; - } else if (e.altKey && keyCode in altCodes) { - cancelKeyPress = keyCode; - (altCodes[keyCode])(); - return false; - } else if (e.ctrlKey && keyCode in ctrlCodes) { - cancelKeyPress = keyCode; - (ctrlCodes[keyCode])(); - return false; - } else if (keyCode in keyCodes) { - cancelKeyPress = keyCode; - (keyCodes[keyCode])(); - return false; +(function($) { + var isWebkit = !!~navigator.userAgent.indexOf(' AppleWebKit/'); + + $.fn.console = function(config) { + //////////////////////////////////////////////////////////////////////// + // Constants + // Some are enums, data types, others just for optimisation + var keyCodes = { + // left + 37: moveBackward, + // right + 39: moveForward, + // up + 38: previousHistory, + // down + 40: nextHistory, + // backspace + 8: backDelete, + // delete + 46: forwardDelete, + // end + 35: moveToEnd, + // start + 36: moveToStart, + // return + 13: commandTrigger, + // tab + 18: doNothing, + // tab + 9: doComplete + }; + var ctrlCodes = { + // C-a + 65: moveToStart, + // C-e + 69: moveToEnd, + // C-d + 68: forwardDelete, + // C-n + 78: nextHistory, + // C-p + 80: previousHistory, + // C-b + 66: moveBackward, + // C-f + 70: moveForward, + // C-k + 75: deleteUntilEnd, + // C-l + 76: clearScreen, + // C-u + 85: clearCurrentPrompt + }; + if (config.ctrlCodes) { + $.extend(ctrlCodes, config.ctrlCodes); } - } - if (isIgnorableKey(e)) { - return false; - } - // C-v: don't insert on paste event - if ((e.ctrlKey || e.metaKey) && String.fromCharCode(keyCode).toLowerCase() == 'v') { - return true; - } - if (acceptInput && cancelKeyPress != keyCode && keyCode >= 32){ - if (cancelKeyPress) return false; - if ( - typeof config.charInsertTrigger == 'undefined' || ( - typeof config.charInsertTrigger == 'faunction' && - config.charInsertTrigger(keyCode,promptText) - ) - ){ - let currentKey = e.key; - if (!currentKey) { - currentKey = String.fromCharCode(keyCode); - } - - typer.consoleInsert(currentKey); - } - } - if (isWebkit) return false; - - }); + var altCodes = { + // M-f + 70: moveToNextWord, + // M-b + 66: moveToPreviousWord, + // M-d + 68: deleteNextWord + }; + var shiftCodes = { + // return + 13: newLine, + }; + var cursor = ' '; + + //////////////////////////////////////////////////////////////////////// + // Globals + var container = $(this); + var inner = $('
'); + // erjiang: changed this from a text input to a textarea so we + // can get pasted newlines + var typer = $(''); + // Prompt + var promptBox; + var prompt; + var continuedPromptLabel = config && config.continuedPromptLabel ? + config.continuedPromptLabel : "> "; + var column = 0; + var promptText = ''; + var restoreText = ''; + var continuedText = ''; + var fadeOnReset = config.fadeOnReset !== undefined ? config.fadeOnReset : true; + // Prompt history stack + var history = []; + var ringn = 0; + // For reasons unknown to The Sword of Michael himself, Opera + // triggers and sends a key character when you hit various + // keys like PgUp, End, etc. So there is no way of knowing + // when a user has typed '#' or End. My solution is in the + // typer.keydown and typer.keypress functions; I use the + // variable below to ignore the keypress event if the keydown + // event succeeds. + var cancelKeyPress = 0; + // When this value is false, the prompt will not respond to input + var acceptInput = true; + // When this value is true, the command has been canceled + var cancelCommand = false; + + // External exports object + var extern = {}; + + //////////////////////////////////////////////////////////////////////// + // Main entry point + (function() { + extern.promptLabel = config && config.promptLabel ? config.promptLabel : "> "; + container.append(inner); + inner.append(typer); + typer.css({ position: 'absolute', top: 0, left: '-9999px' }); + if (config.welcomeMessage) + message(config.welcomeMessage, 'jquery-console-welcome'); + newPromptBox(); + if (config.autofocus) { + inner.addClass('jquery-console-focus'); + typer.focus(); + setTimeout(function() { + inner.addClass('jquery-console-focus'); + typer.focus(); + }, 100); + } + extern.inner = inner; + extern.typer = typer; + extern.scrollToBottom = scrollToBottom; + extern.report = report; + extern.showCompletion = showCompletion; + extern.clearScreen = clearScreen; + })(); + + //////////////////////////////////////////////////////////////////////// + // Reset terminal + extern.reset = function() { + var welcome = (typeof config.welcomeMessage != 'undefined'); + + var removeElements = function() { + inner.find('div').each(function() { + if (!welcome) { + $(this).remove(); + } else { + welcome = false; + } + }); + }; + + if (fadeOnReset) { + inner.parent().fadeOut(function() { + removeElements(); + newPromptBox(); + inner.parent().fadeIn(focusConsole); + }); + } else { + removeElements(); + newPromptBox(); + focusConsole(); + } + }; - function isIgnorableKey(e) { - // for now just filter alt+tab that we receive on some platforms when - // user switches windows (goes away from the browser) - return ((e.keyCode == keyCodes.tab || e.keyCode == 192) && e.altKey); - }; + var focusConsole = function() { + inner.addClass('jquery-console-focus'); + typer.focus(); + }; - //////////////////////////////////////////////////////////////////////// - // Rotate through the command history - function rotateHistory(n){ - if (history.length == 0) return; - ringn += n; - if (ringn < 0) ringn = history.length; - else if (ringn > history.length) ringn = 0; - var prevText = promptText; - if (ringn == 0) { - promptText = restoreText; - } else { - promptText = history[ringn - 1]; - } - if (config.historyPreserveColumn) { - if (promptText.length < column + 1) { - column = promptText.length; - } else if (column == 0) { - column = promptText.length; + extern.focus = function() { + focusConsole(); } - } else { - column = promptText.length; - } - updatePromptDisplay(); - }; - - function previousHistory() { - rotateHistory(-1); - }; - - function nextHistory() { - rotateHistory(1); - }; - - // Add something to the history ring - function addToHistory(line){ - history.push(line); - restoreText = ''; - }; - - // Delete the character at the current position - function deleteCharAtPos(){ - if (column < promptText.length){ - promptText = - promptText.substring(0,column) + - promptText.substring(column+1); - restoreText = promptText; - return true; - } else return false; - }; - function backDelete() { - if (moveColumn(-1)){ - deleteCharAtPos(); - updatePromptDisplay(); - } - }; + //////////////////////////////////////////////////////////////////////// + // Reset terminal + extern.notice = function(msg, style) { + var n = $('
').append($('
').text(msg)) + .css({ visibility: 'hidden' }); + container.append(n); + var focused = true; + if (style == 'fadeout') + setTimeout(function() { + n.fadeOut(function() { + n.remove(); + }); + }, 4000); + else if (style == 'prompt') { + var a = $('
'); + n.append(a); + focused = false; + a.click(function() { n.fadeOut(function() { n.remove(); + inner.css({ opacity: 1 }) }); }); + } + var h = n.height(); + n.css({ height: '0px', visibility: 'visible' }) + .animate({ height: h + 'px' }, function() { + if (!focused) inner.css({ opacity: 0.5 }); + }); + n.css('cursor', 'default'); + return n; + }; + + //////////////////////////////////////////////////////////////////////// + // Make a new prompt box + function newPromptBox() { + column = 0; + promptText = ''; + ringn = 0; // Reset the position of the history ring + enableInput(); + promptBox = $('
'); + var label = $(''); + var labelText = extern.continuedPrompt ? continuedPromptLabel : extern.promptLabel; + promptBox.append(label.text(labelText).show()); + label.html(label.html().replace(' ', ' ')); + prompt = $(''); + promptBox.append(prompt); + inner.append(promptBox); + updatePromptDisplay(); + }; + + //////////////////////////////////////////////////////////////////////// + // Handle setting focus + container.click(function() { + // Don't mess with the focus if there is an active selection + if (window.getSelection().toString()) { + return false; + } - function forwardDelete() { - if (deleteCharAtPos()){ - updatePromptDisplay(); - } - }; + inner.addClass('jquery-console-focus'); + inner.removeClass('jquery-console-nofocus'); + if (isWebkit) { + typer.focusWithoutScrolling(); + } else { + typer.css('position', 'fixed').focus(); + } + scrollToBottom(); + return false; + }); - function deleteUntilEnd() { - while(deleteCharAtPos()) { - updatePromptDisplay(); - } - }; + //////////////////////////////////////////////////////////////////////// + // Handle losing focus + typer.blur(function() { + inner.removeClass('jquery-console-focus'); + inner.addClass('jquery-console-nofocus'); + }); - function clearCurrentPrompt() { - extern.promptText(""); - }; + //////////////////////////////////////////////////////////////////////// + // Bind to the paste event of the input box so we know when we + // get pasted data + typer.bind('paste', function(e) { + // wipe typer input clean just in case + typer.val(""); + // this timeout is required because the onpaste event is + // fired *before* the text is actually pasted + setTimeout(function() { + typer.consoleInsert(typer.val()); + typer.val(""); + }, 0); + }); - function clearScreen() { - inner.children(".jquery-console-prompt-box, .jquery-console-message").slice(0, -1).remove(); - extern.report(" "); - extern.focus(); - }; + //////////////////////////////////////////////////////////////////////// + // Handle key hit before translation + // For picking up control characters like up/left/down/right - function deleteNextWord() { - // A word is defined within this context as a series of alphanumeric - // characters. - // Delete up to the next alphanumeric character - while( - column < promptText.length && - !isCharAlphanumeric(promptText[column]) - ) { - deleteCharAtPos(); - updatePromptDisplay(); - } - // Then, delete until the next non-alphanumeric character - while( - column < promptText.length && - isCharAlphanumeric(promptText[column]) - ) { - deleteCharAtPos(); - updatePromptDisplay(); - } - }; - function newLine() { - var lines = promptText.split("\n"); - var last_line = lines.slice(-1)[0]; - var spaces = last_line.match(/^(\s*)/g)[0]; - var new_line = "\n" + spaces; - promptText += new_line; - moveColumn(new_line.length); - updatePromptDisplay(); - }; - //////////////////////////////////////////////////////////////////////// - // Validate command and trigger it if valid, or show a validation error - function commandTrigger() { - var line = promptText; - if (typeof config.commandValidate == 'function') { - var ret = config.commandValidate(line); - if (ret == true || ret == false) { - if (ret) { - handleCommand(); - } - } else { - commandResult(ret,"jquery-console-message-error"); - } - } else { - handleCommand(); - } - }; + typer.keydown(function(e) { - // Scroll to the bottom of the view - function scrollToBottom() { - var version = jQuery.fn.jquery.split('.'); - var major = parseInt(version[0]); - var minor = parseInt(version[1]); - - // check if we're using jquery > 1.6 - if ((major == 1 && minor > 6) || major > 1) { - inner.prop({ scrollTop: inner.prop("scrollHeight") }); - } - else { - inner.attr({ scrollTop: inner.attr("scrollHeight") }); - } - }; + oldValue = typer.val(); + console.log(typer.val()); + console.log(e); + cancelKeyPress = 0; + var keyCode = e.which || e.code; + // C-c: cancel the execution + if (e.ctrlKey && keyCode == 67) { + cancelKeyPress = keyCode; + cancelExecution(); + return false; + } + if (acceptInput) { + if (e.shiftKey && keyCode in shiftCodes) { + cancelKeyPress = keyCode; + (shiftCodes[keyCode])(); + return false; + } else if (e.altKey && keyCode in altCodes) { + cancelKeyPress = keyCode; + (altCodes[keyCode])(); + return false; + } else if (e.ctrlKey && keyCode in ctrlCodes) { + cancelKeyPress = keyCode; + (ctrlCodes[keyCode])(); + return false; + } else if (keyCode in keyCodes) { + cancelKeyPress = keyCode; + (keyCodes[keyCode])(); + return false; + } + } + if (isIgnorableKey(e)) { + return false; + } + // C-v: don't insert on paste event + if ((e.ctrlKey || e.metaKey) && String.fromCharCode(keyCode).toLowerCase() == 'v') { + return true; + } + if (acceptInput && cancelKeyPress != keyCode && keyCode >= 32) { + if (cancelKeyPress) return false; + } - function cancelExecution() { - if(typeof config.cancelHandle == 'function') { - config.cancelHandle(); - } - } - - //////////////////////////////////////////////////////////////////////// - // Handle a command - function handleCommand() { - if (typeof config.commandHandle == 'function') { - disableInput(); - addToHistory(promptText); - var text = promptText; - if (extern.continuedPrompt) { - if (continuedText) - continuedText += '\n' + promptText; - else continuedText = promptText; - } else continuedText = undefined; - if (continuedText) text = continuedText; - var ret = config.commandHandle(text,function(msgs){ - commandResult(msgs); }); - if (extern.continuedPrompt && !continuedText) - continuedText = promptText; - if (typeof ret == 'boolean') { - if (ret) { - // Command succeeded without a result. - commandResult(); - } else { - commandResult( - 'Command failed.', - "jquery-console-message-error" - ); - } - } else if (typeof ret == "string") { - commandResult(ret,"jquery-console-message-success"); - } else if (typeof ret == 'object' && ret.length) { - commandResult(ret); - } else if (extern.continuedPrompt) { - commandResult(); - } - } - }; - //////////////////////////////////////////////////////////////////////// - // Disable input - function disableInput() { - acceptInput = false; - }; + var oldValue; + var newValue; - // Enable input - function enableInput() { - acceptInput = true; - } - - //////////////////////////////////////////////////////////////////////// - // Reset the prompt in invalid command - function commandResult(msg,className) { - column = -1; - updatePromptDisplay(); - if (typeof msg == 'string') { - message(msg,className); - } else if ($.isArray(msg)) { - for (var x in msg) { - var ret = msg[x]; - message(ret.msg,ret.className); - } - } else { // Assume it's a DOM node or jQuery object. - inner.append(msg); - } - newPromptBox(); - }; - //////////////////////////////////////////////////////////////////////// - // Report some message into the console - function report(msg,className) { - var text = promptText; - promptBox.remove(); - commandResult(msg,className); - extern.promptText(text); - }; + difference = function(value1, value2) { + var output = []; + for (i = 0; i < value2.length; i++) { + if (value1[i] !== value2[i]) { + output.push(value2[i]); + } + } + return output.join(""); + } - //////////////////////////////////////////////////////////////////////// - // Display a message - function message(msg,className) { - var mesg = $('
'); - if (className) mesg.addClass(className); - mesg.filledText(msg).hide(); - inner.append(mesg); - mesg.show(); - }; + typer.on("input", function(e) { + newValue = typer.val(); + typer.consoleInsert(difference(oldValue, newValue)); + }) + - //////////////////////////////////////////////////////////////////////// - // Handle normal character insertion - // data can either be a number, which will be interpreted as the - // numeric value of a single character, or a string - typer.consoleInsert = function(data){ - // TODO: remove redundant indirection - var text = (typeof data == 'number') ? String.fromCharCode(data) : data; - var before = promptText.substring(0,column); - var after = promptText.substring(column); - promptText = before + text + after; - moveColumn(text.length); - restoreText = promptText; - updatePromptDisplay(); - }; + function isIgnorableKey(e) { + // for now just filter alt+tab that we receive on some platforms when + // user switches windows (goes away from the browser) + return ((e.keyCode == keyCodes.tab || e.keyCode == 192) && e.altKey); + }; + + //////////////////////////////////////////////////////////////////////// + // Rotate through the command history + function rotateHistory(n) { + if (history.length == 0) return; + ringn += n; + if (ringn < 0) ringn = history.length; + else if (ringn > history.length) ringn = 0; + var prevText = promptText; + if (ringn == 0) { + promptText = restoreText; + } else { + promptText = history[ringn - 1]; + } + if (config.historyPreserveColumn) { + if (promptText.length < column + 1) { + column = promptText.length; + } else if (column == 0) { + column = promptText.length; + } + } else { + column = promptText.length; + } + updatePromptDisplay(); + }; + + function previousHistory() { + rotateHistory(-1); + }; + + function nextHistory() { + rotateHistory(1); + }; + + // Add something to the history ring + function addToHistory(line) { + history.push(line); + restoreText = ''; + }; + + // Delete the character at the current position + function deleteCharAtPos() { + if (column < promptText.length) { + promptText = + promptText.substring(0, column) + + promptText.substring(column + 1); + restoreText = promptText; + return true; + } else return false; + }; + + function backDelete() { + if (moveColumn(-1)) { + deleteCharAtPos(); + updatePromptDisplay(); + } + }; - //////////////////////////////////////////////////////////////////////// - // Move to another column relative to this one - // Negative means go back, positive means go forward. - function moveColumn(n){ - if (column + n >= 0 && column + n <= promptText.length){ - column += n; - return true; - } else return false; - }; + function forwardDelete() { + if (deleteCharAtPos()) { + updatePromptDisplay(); + } + }; - function moveForward() { - if(moveColumn(1)) { - updatePromptDisplay(); - return true; - } - return false; - }; + function deleteUntilEnd() { + while (deleteCharAtPos()) { + updatePromptDisplay(); + } + }; + + function clearCurrentPrompt() { + extern.promptText(""); + }; + + function clearScreen() { + inner.children(".jquery-console-prompt-box, .jquery-console-message").slice(0, -1).remove(); + extern.report(" "); + extern.focus(); + }; + + function deleteNextWord() { + // A word is defined within this context as a series of alphanumeric + // characters. + // Delete up to the next alphanumeric character + while ( + column < promptText.length && + !isCharAlphanumeric(promptText[column]) + ) { + deleteCharAtPos(); + updatePromptDisplay(); + } + // Then, delete until the next non-alphanumeric character + while ( + column < promptText.length && + isCharAlphanumeric(promptText[column]) + ) { + deleteCharAtPos(); + updatePromptDisplay(); + } + }; + + function newLine() { + var lines = promptText.split("\n"); + var last_line = lines.slice(-1)[0]; + var spaces = last_line.match(/^(\s*)/g)[0]; + var new_line = "\n" + spaces; + promptText += new_line; + moveColumn(new_line.length); + updatePromptDisplay(); + }; + + //////////////////////////////////////////////////////////////////////// + // Validate command and trigger it if valid, or show a validation error + function commandTrigger() { + var line = promptText; + if (typeof config.commandValidate == 'function') { + var ret = config.commandValidate(line); + if (ret == true || ret == false) { + if (ret) { + handleCommand(); + } + } else { + commandResult(ret, "jquery-console-message-error"); + } + } else { + handleCommand(); + } + }; - function moveBackward() { - if(moveColumn(-1)) { - updatePromptDisplay(); - return true; - } - return false; - }; + // Scroll to the bottom of the view + function scrollToBottom() { + var version = jQuery.fn.jquery.split('.'); + var major = parseInt(version[0]); + var minor = parseInt(version[1]); - function moveToStart() { - if (moveColumn(-column)) - updatePromptDisplay(); - }; + // check if we're using jquery > 1.6 + if ((major == 1 && minor > 6) || major > 1) { + inner.prop({ scrollTop: inner.prop("scrollHeight") }); + } else { + inner.attr({ scrollTop: inner.attr("scrollHeight") }); + } + }; - function moveToEnd() { - if (moveColumn(promptText.length-column)) - updatePromptDisplay(); - }; + function cancelExecution() { + if (typeof config.cancelHandle == 'function') { + config.cancelHandle(); + } + } - function moveToNextWord() { - while( - column < promptText.length && - !isCharAlphanumeric(promptText[column]) && - moveForward() - ) {} - while( - column < promptText.length && - isCharAlphanumeric(promptText[column]) && - moveForward() - ) {} - }; + //////////////////////////////////////////////////////////////////////// + // Handle a command + function handleCommand() { + if (typeof config.commandHandle == 'function') { + disableInput(); + addToHistory(promptText); + var text = promptText; + if (extern.continuedPrompt) { + if (continuedText) + continuedText += '\n' + promptText; + else continuedText = promptText; + } else continuedText = undefined; + if (continuedText) text = continuedText; + var ret = config.commandHandle(text, function(msgs) { + commandResult(msgs); + }); + if (extern.continuedPrompt && !continuedText) + continuedText = promptText; + if (typeof ret == 'boolean') { + if (ret) { + // Command succeeded without a result. + commandResult(); + } else { + commandResult( + 'Command failed.', + "jquery-console-message-error" + ); + } + } else if (typeof ret == "string") { + commandResult(ret, "jquery-console-message-success"); + } else if (typeof ret == 'object' && ret.length) { + commandResult(ret); + } else if (extern.continuedPrompt) { + commandResult(); + } + } + }; - function moveToPreviousWord() { - // Move backward until we find the first alphanumeric - while( - column -1 >= 0 && - !isCharAlphanumeric(promptText[column-1]) && - moveBackward() - ) {} - // Move until we find the first non-alphanumeric - while( - column -1 >= 0 && - isCharAlphanumeric(promptText[column-1]) && - moveBackward() - ) {} - }; + //////////////////////////////////////////////////////////////////////// + // Disable input + function disableInput() { + acceptInput = false; + }; - function isCharAlphanumeric(charToTest) { - if(typeof charToTest == 'string') { - var code = charToTest.charCodeAt(); - return (code >= 'A'.charCodeAt() && code <= 'Z'.charCodeAt()) || - (code >= 'a'.charCodeAt() && code <= 'z'.charCodeAt()) || - (code >= '0'.charCodeAt() && code <= '9'.charCodeAt()); - } - return false; - }; + // Enable input + function enableInput() { + acceptInput = true; + } - function doComplete() { - if(typeof config.completeHandle == 'function') { - doCompleteDirectly(); - } else { - issueComplete(); + //////////////////////////////////////////////////////////////////////// + // Reset the prompt in invalid command + function commandResult(msg, className) { + column = -1; + updatePromptDisplay(); + if (typeof msg == 'string') { + message(msg, className); + } else if ($.isArray(msg)) { + for (var x in msg) { + var ret = msg[x]; + message(ret.msg, ret.className); + } + } else { // Assume it's a DOM node or jQuery object. + inner.append(msg); } - }; - - function doCompleteDirectly() { - if(typeof config.completeHandle == 'function') { - var completions = config.completeHandle(promptText); - var len = completions.length; - if (len === 1) { - extern.promptText(promptText + completions[0]); - } else if (len > 1 && config.cols) { - var prompt = promptText; - // Compute the number of rows that will fit in the width - var max = 0; - for (var i = 0;i < len;i++) { - max = Math.max(max, completions[i].length); - } - max += 2; - var n = Math.floor(config.cols / max); - var buffer = ""; - var col = 0; - for (i = 0;i < len;i++) { - var completion = completions[i]; - buffer += completions[i]; - for (var j = completion.length;j < max;j++) { - buffer += " "; - } - if (++col >= n) { - buffer += "\n"; - col = 0; - } - } - commandResult(buffer,"jquery-console-message-value"); - extern.promptText(prompt); - } - } - }; + newPromptBox(); + }; + + //////////////////////////////////////////////////////////////////////// + // Report some message into the console + function report(msg, className) { + var text = promptText; + promptBox.remove(); + commandResult(msg, className); + extern.promptText(text); + }; + + //////////////////////////////////////////////////////////////////////// + // Display a message + function message(msg, className) { + var mesg = $('
'); + if (className) mesg.addClass(className); + mesg.filledText(msg).hide(); + inner.append(mesg); + mesg.show(); + }; + + //////////////////////////////////////////////////////////////////////// + // Handle normal character insertion + // data can either be a number, which will be interpreted as the + // numeric value of a single character, or a string + typer.consoleInsert = function(data) { + // TODO: remove redundant indirection + var text = (typeof data == 'number') ? String.fromCharCode(data) : data; + var before = promptText.substring(0, column); + var after = promptText.substring(column); + promptText = before + text + after; + moveColumn(text.length); + restoreText = promptText; + updatePromptDisplay(); + }; + + //////////////////////////////////////////////////////////////////////// + // Move to another column relative to this one + // Negative means go back, positive means go forward. + function moveColumn(n) { + if (column + n >= 0 && column + n <= promptText.length) { + column += n; + return true; + } else return false; + }; + + function moveForward() { + if (moveColumn(1)) { + updatePromptDisplay(); + return true; + } + return false; + }; - function issueComplete() { - if (typeof config.completeIssuer == 'function') { - config.completeIssuer(promptText); + function moveBackward() { + if (moveColumn(-1)) { + updatePromptDisplay(); + return true; } - }; + return false; + }; + + function moveToStart() { + if (moveColumn(-column)) + updatePromptDisplay(); + }; + + function moveToEnd() { + if (moveColumn(promptText.length - column)) + updatePromptDisplay(); + }; + + function moveToNextWord() { + while ( + column < promptText.length && + !isCharAlphanumeric(promptText[column]) && + moveForward() + ) {} + while ( + column < promptText.length && + isCharAlphanumeric(promptText[column]) && + moveForward() + ) {} + }; + + function moveToPreviousWord() { + // Move backward until we find the first alphanumeric + while ( + column - 1 >= 0 && + !isCharAlphanumeric(promptText[column - 1]) && + moveBackward() + ) {} + // Move until we find the first non-alphanumeric + while ( + column - 1 >= 0 && + isCharAlphanumeric(promptText[column - 1]) && + moveBackward() + ) {} + }; + + function isCharAlphanumeric(charToTest) { + if (typeof charToTest == 'string') { + var code = charToTest.charCodeAt(); + return (code >= 'A'.charCodeAt() && code <= 'Z'.charCodeAt()) || + (code >= 'a'.charCodeAt() && code <= 'z'.charCodeAt()) || + (code >= '0'.charCodeAt() && code <= '9'.charCodeAt()); + } + return false; + }; - function showCompletion(promptText, completions) { + function doComplete() { + if (typeof config.completeHandle == 'function') { + doCompleteDirectly(); + } else { + issueComplete(); + } + }; - var len = completions.length; - if (len === 1) { + function doCompleteDirectly() { + if (typeof config.completeHandle == 'function') { + var completions = config.completeHandle(promptText); + var len = completions.length; + if (len === 1) { extern.promptText(promptText + completions[0]); - } else if (len > 1 && config.cols) { + } else if (len > 1 && config.cols) { var prompt = promptText; // Compute the number of rows that will fit in the width var max = 0; for (var i = 0; i < len; i++) { - max = Math.max(max, completions[i].length); + max = Math.max(max, completions[i].length); } max += 2; var n = Math.floor(config.cols / max); var buffer = ""; var col = 0; for (i = 0; i < len; i++) { - var completion = completions[i]; - buffer += completions[i]; - for (var j = completion.length; j < max; j++) { - buffer += " "; - } - if (++col >= n) { - buffer += "\n"; - col = 0; - } + var completion = completions[i]; + buffer += completions[i]; + for (var j = completion.length; j < max; j++) { + buffer += " "; + } + if (++col >= n) { + buffer += "\n"; + col = 0; + } } commandResult(buffer, "jquery-console-message-value"); extern.promptText(prompt); + } } - }; + }; - function doNothing() {}; + function issueComplete() { + if (typeof config.completeIssuer == 'function') { + config.completeIssuer(promptText); + } + }; - extern.promptText = function(text){ - if (typeof text === 'string') { - promptText = text; - column = promptText.length; - updatePromptDisplay(); - } - return promptText; - }; + function showCompletion(promptText, completions) { - //////////////////////////////////////////////////////////////////////// - // Update the prompt display - function updatePromptDisplay(){ - var line = promptText; - var html = ''; - if (column > 0 && line == ''){ - // When we have an empty line just display a cursor. - html = cursor; - } else if (column == promptText.length){ - // We're at the end of the line, so we need to display - // the text *and* cursor. - html = htmlEncode(line) + cursor; - } else { - // Grab the current character, if there is one, and - // make it the current cursor. - var before = line.substring(0, column); - var current = line.substring(column,column+1); - if (current){ - current = - '' + - htmlEncode(current) + - ''; - } - var after = line.substring(column+1); - html = htmlEncode(before) + current + htmlEncode(after); - } - prompt.html(html); - scrollToBottom(); - }; + var len = completions.length; + if (len === 1) { + extern.promptText(promptText + completions[0]); + } else if (len > 1 && config.cols) { + var prompt = promptText; + // Compute the number of rows that will fit in the width + var max = 0; + for (var i = 0; i < len; i++) { + max = Math.max(max, completions[i].length); + } + max += 2; + var n = Math.floor(config.cols / max); + var buffer = ""; + var col = 0; + for (i = 0; i < len; i++) { + var completion = completions[i]; + buffer += completions[i]; + for (var j = completion.length; j < max; j++) { + buffer += " "; + } + if (++col >= n) { + buffer += "\n"; + col = 0; + } + } + commandResult(buffer, "jquery-console-message-value"); + extern.promptText(prompt); + } + }; - // Simple HTML encoding - // Simply replace '<', '>' and '&' - // TODO: Use jQuery's .html() trick, or grab a proper, fast - // HTML encoder. - function htmlEncode(text){ - return ( - text.replace(/&/g,'&') - .replace(/') - ); + function doNothing() {}; + + extern.promptText = function(text) { + if (typeof text === 'string') { + promptText = text; + column = promptText.length; + updatePromptDisplay(); + } + return promptText; + }; + + //////////////////////////////////////////////////////////////////////// + // Update the prompt display + function updatePromptDisplay() { + var line = promptText; + var html = ''; + if (column > 0 && line == '') { + // When we have an empty line just display a cursor. + html = cursor; + } else if (column == promptText.length) { + // We're at the end of the line, so we need to display + // the text *and* cursor. + html = htmlEncode(line) + cursor; + } else { + // Grab the current character, if there is one, and + // make it the current cursor. + var before = line.substring(0, column); + var current = line.substring(column, column + 1); + if (current) { + current = + '' + + htmlEncode(current) + + ''; + } + var after = line.substring(column + 1); + html = htmlEncode(before) + current + htmlEncode(after); + } + prompt.html(html); + scrollToBottom(); + }; + + // Simple HTML encoding + // Simply replace '<', '>' and '&' + // TODO: Use jQuery's .html() trick, or grab a proper, fast + // HTML encoder. + function htmlEncode(text) { + return ( + text.replace(/&/g, '&') + .replace(/') + ); + }; + + return extern; + }; + // Simple utility for printing messages + $.fn.filledText = function(txt) { + $(this).text(txt); + $(this).html($(this).html().replace(/\t/g, '  ').replace(/\n/g, '
')); + return this; }; - return extern; - }; - // Simple utility for printing messages - $.fn.filledText = function(txt){ - $(this).text(txt); - $(this).html($(this).html().replace(/\t/g, '  ').replace(/\n/g,'
')); - return this; - }; - - // Alternative method for focus without scrolling - $.fn.focusWithoutScrolling = function(){ - var x = window.scrollX, y = window.scrollY; - $(this).focus(); - window.scrollTo(x, y); - }; -})(jQuery); + // Alternative method for focus without scrolling + $.fn.focusWithoutScrolling = function() { + var x = window.scrollX, + y = window.scrollY; + $(this).focus(); + window.scrollTo(x, y); + }; +})(jQuery); \ No newline at end of file From feb76581bced20137bc470c8c7d9abf72a8357c9 Mon Sep 17 00:00:00 2001 From: Dan Spagnoli Date: Wed, 7 Feb 2018 13:43:37 -0500 Subject: [PATCH 4/8] Removed depreciated "onkeypress" event that doesn't work on android devices, now will listen for onkeydown event, get current input value, then on "input" event get the new input value, figure out what character was added, and then add that new character to the console display, tested and works. thanks to this article : https://www.outsystems.com/blog/javascript-events-unmasked-how-to-create-input-mask-for-mobile.html --- jquery.console.js | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/jquery.console.js b/jquery.console.js index da9080e..caabaf8 100644 --- a/jquery.console.js +++ b/jquery.console.js @@ -223,8 +223,12 @@ var a = $('
'); n.append(a); focused = false; - a.click(function() { n.fadeOut(function() { n.remove(); - inner.css({ opacity: 1 }) }); }); + a.click(function() { + n.fadeOut(function() { + n.remove(); + inner.css({ opacity: 1 }) + }); + }); } var h = n.height(); n.css({ height: '0px', visibility: 'visible' }) @@ -297,13 +301,13 @@ // Handle key hit before translation // For picking up control characters like up/left/down/right + //Old and new input value globals + var oldValue; + var newValue; typer.keydown(function(e) { - oldValue = typer.val(); - console.log(typer.val()); - console.log(e); cancelKeyPress = 0; var keyCode = e.which || e.code; // C-c: cancel the execution @@ -344,10 +348,7 @@ }); - var oldValue; - var newValue; - - + //helper function to figure out new character added to input difference = function(value1, value2) { var output = []; for (i = 0; i < value2.length; i++) { @@ -358,11 +359,12 @@ return output.join(""); } + //after input event get new string, figure out the difference and add the character to the typer. typer.on("input", function(e) { newValue = typer.val(); typer.consoleInsert(difference(oldValue, newValue)); }) - + function isIgnorableKey(e) { // for now just filter alt+tab that we receive on some platforms when From 51e21eeade27fb492ebfd317fa0247773240891a Mon Sep 17 00:00:00 2001 From: Dan Spagnoli Date: Wed, 7 Feb 2018 13:47:49 -0500 Subject: [PATCH 5/8] code cleanup --- demo.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demo.html b/demo.html index daa4daa..2a3c0ed 100644 --- a/demo.html +++ b/demo.html @@ -55,7 +55,7 @@ controller2.promptText('5 * 4'); /* Third console */ var console3CancelFlag = false; - var console3 = $('
'); + var console3 = $('
'); $('body').append(console3); var controller3 = console3.console({ promptLabel: 'Echo> ', From 4f0f53a955392e7128be323385968d1ed17722c9 Mon Sep 17 00:00:00 2001 From: Dan Spagnoli Date: Wed, 7 Feb 2018 13:57:18 -0500 Subject: [PATCH 6/8] got rid of globals --- jquery.console.js | 32 +++++++++++++------------------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/jquery.console.js b/jquery.console.js index caabaf8..8e42721 100644 --- a/jquery.console.js +++ b/jquery.console.js @@ -296,17 +296,21 @@ typer.val(""); }, 0); }); - + //helper function to figure out new character added to input + difference = function(value1, value2) { + var output = []; + for (i = 0; i < value2.length; i++) { + if (value1[i] !== value2[i]) { + output.push(value2[i]); + } + } + return output.join(""); + } //////////////////////////////////////////////////////////////////////// // Handle key hit before translation // For picking up control characters like up/left/down/right - - //Old and new input value globals - var oldValue; - var newValue; - - typer.keydown(function(e) { + typer.oldValue = typer.val(); oldValue = typer.val(); cancelKeyPress = 0; var keyCode = e.which || e.code; @@ -348,21 +352,11 @@ }); - //helper function to figure out new character added to input - difference = function(value1, value2) { - var output = []; - for (i = 0; i < value2.length; i++) { - if (value1[i] !== value2[i]) { - output.push(value2[i]); - } - } - return output.join(""); - } //after input event get new string, figure out the difference and add the character to the typer. typer.on("input", function(e) { - newValue = typer.val(); - typer.consoleInsert(difference(oldValue, newValue)); + var newValue = typer.val(); + typer.consoleInsert(difference(typer.oldValue, newValue)); }) From a5a4e574125c0f9a78789b5906cf490df6984605 Mon Sep 17 00:00:00 2001 From: Dan Spagnoli Date: Wed, 7 Feb 2018 14:16:35 -0500 Subject: [PATCH 7/8] fix backspace on android --- jquery.console.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/jquery.console.js b/jquery.console.js index 8e42721..64f057c 100644 --- a/jquery.console.js +++ b/jquery.console.js @@ -350,6 +350,7 @@ if (cancelKeyPress) return false; } + }); @@ -357,6 +358,7 @@ typer.on("input", function(e) { var newValue = typer.val(); typer.consoleInsert(difference(typer.oldValue, newValue)); + typer.val(difference(typer.oldValue, newValue)); }) From 85fab01f3fcbf77158993037d93068e0e9d88e86 Mon Sep 17 00:00:00 2001 From: Dan Spagnoli Date: Wed, 7 Feb 2018 14:24:42 -0500 Subject: [PATCH 8/8] clear typer value for autocomplete to not engage --- jquery.console.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jquery.console.js b/jquery.console.js index 64f057c..e8f0be8 100644 --- a/jquery.console.js +++ b/jquery.console.js @@ -358,7 +358,7 @@ typer.on("input", function(e) { var newValue = typer.val(); typer.consoleInsert(difference(typer.oldValue, newValue)); - typer.val(difference(typer.oldValue, newValue)); + typer.val(""); })