Fixing quirk in uihtml + JavaScript implementation of "command line" with command history

5 views (last 30 days)
I have been noodling on creating a simple "command line" prompt with command history, using the App Designer + a uihtml component that relies heavily on JavaScript.
In the attached prompt.zip are two files: prompt.mlapp and prompt.html.
When you run prompt.mlapp, any "command" (here, any text you want) entered in the top box is echoed in the bottom box when you press Enter. Then, you can use the Up and Down arrow keys to scroll through past commands that you entered.
The quirk I am trying to fix: To see for yourself, enter a few commands. Press the Up arrow, and you will see the last command you entered. In a "normal" shell, if you just hit Enter at this point, the command displayed will be "rerun," and here that would mean it would appear again in the bottom text box. However, that doesn't happen. Instead, you have to press some key on the keyboard before the string is treated as new input, regardless of the cursor position, after which you can press Enter and have the new command "rerun."
In terms of the JavaScript in prompt.html: The "command history" is implemented in the function onKeyDown, and the past history is transferred into the current text box with one of the assignments to the variable instring.value. Usually a new command is "run" via a "change" listener, which called the function valueChanged. For reasons I don't understand, this listener isn't triggered until there is some new keyboard input after instring.value is reassigned in onKeyDown.
Any JavaScript experts out there who would have any clue what might be going on here and whether it can be fixed/circumvented somehow?
(This is a pared-down version of a larger routine I've been working on. I plan on contributing the larger routine to File Exchange soon, but I'd like to fix this quirk first, if at all possible!)

Accepted Answer

Alamanda Ponappa Poovaya
Alamanda Ponappa Poovaya on 7 Sep 2021
I have made some modifications to your prompt.html file. It seems to fix your issue. Please have a look
  2 Comments
Antonio Hortal
Antonio Hortal on 8 Sep 2021
This solution listens for the Enter key press on the "keydown" event. As a result, if the user holds down the Enter key the callback would be executed many times and empty strings will be pushed to the cmds array. So you'd have to press the up arrow many times to get to the last real (not empty) command.
I think for what David described, the better apporach would be to listen for the Enter key press on the "keyup" event. Also, I would add some line of code inside the valueChanged function such that if the input is empty, nothing gets pushed into the cmds array

Sign in to comment.

More Answers (1)

Antonio Hortal
Antonio Hortal on 6 Sep 2021
Hi!
I am definitely not a JavaScript expert, but I can try to answer :P
In your HTML script you are listening for the <input> "change" event. That event is meant to trigger when the user makes a change and the component loses focus. The problem is that on your app, when the user presses the arrow keys, you programatically set the value of the <input> element.
You may have also noticed that if you click somewhere else than the input field when typing, the command gets executed. I guess that from what you described this should not be the desired behaviour (you'd only like it to be executed on an "enter", like in the Matlab command window).
One possible solution is listening to the "keyup" event and looking for when the key entered is the Enter. Only then you execute the valueChanged function. In your code, you could replace the change listener by:
instring.addEventListener("keyup", valueChanged);
And fix the valueChanged function. You forgot the curly brackets {}
if (event.key == "Enter") {
... the same code you already have here
}
And emove the valueChanged() and dataChanged() lines from ther setup function. You dont need to call them at the setup, you only need them when listeneing to the events.
One personal recommendation, move most of your code to a <script> that that executes in the body of the html file, and only keep the necessary stuff in the "setup" function. That will help you debug your JS code when you open it on the browser.
It's nice to see more people using the uihtml class. I think it has a ton of potential for creating really nice apps, such as I am sure yours will be. I am looking forward to seeing on the FEX your final app!
  2 Comments
Antonio Hortal
Antonio Hortal on 8 Sep 2021
You are very welcome! I also knew nothing about HTML and JavaScript a few months ago, so I definitely get that feeling of having to google down every line of code :P

Sign in to comment.

Products


Release

R2020a

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!