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

2 次查看(过去 30 天)
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!)

采纳的回答

Drishan Poovaya
Drishan Poovaya 2021-9-7
I have made some modifications to your prompt.html file. It seems to fix your issue. Please have a look
  2 个评论
David Aronstein
David Aronstein 2021-9-7
Your modifications are so helpful, Alamanda! Thank you so much!!! I am delighted that the code now does exactly what I had hoped and imagined it would do!
Antonio Hortal
Antonio Hortal 2021-9-8
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

请先登录,再进行评论。

更多回答(1 个)

Antonio Hortal
Antonio Hortal 2021-9-6
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 个评论
David Aronstein
David Aronstein 2021-9-7
Thank you so much, Antonio!
I have written a longer JavaScript routine than what I posted here (so, for example, you can set the text box's font, background color, etc. from within MATLAB). There was one mistake I made by editing the code down (forgetting the curly brackets) -- thank you for catching that! I also had a separate listener for monitoring for the user pressing the Enter key, to avoid what you understood immediately, that a user changing focus from the text box will trigger the text to be accepted as if the user pressed Enter. Your solution was more elegant than mine, thanks!! Alamanda Ponappa Poovaya's solution, below, includes this as part of the keydown listener, and that seems to also address the main part of my question!
I also appreciate you pointing out things about the structure of the .html file and the unneeded lines of code. I had literally no experience in JavaScript before this project, and so I have been Googling every command and line of code, and so I have no idea about broader issues of program structure and style.
Antonio Hortal
Antonio Hortal 2021-9-8
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

请先登录,再进行评论。

类别

Help CenterFile Exchange 中查找有关 Environment and Settings 的更多信息

产品


版本

R2020a

Community Treasure Hunt

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

Start Hunting!

Translated by