Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Retrieve latest input #210

Closed
kaimatachi opened this issue Jul 22, 2024 · 2 comments
Closed

Retrieve latest input #210

kaimatachi opened this issue Jul 22, 2024 · 2 comments

Comments

@kaimatachi
Copy link

kaimatachi commented Jul 22, 2024

Hello,

First thanks for this library !

It handles everything I need except for one use case. I would need to add some mention (@ausername) to specific users from my app. It should work exactly as a mention in a GitHub message.

To implement it I would need to know when the user starts typing an @ and retrieve the data until the next space. With this piece of data, I can then display a list of relevant user.

I'm not entirely sure how to proceed. Should I be looking for an @ after every input in getHtml() ? But it seems quite overkilled. Or maybe you have an other idea to only retrieve the latest input ?

Thanks a lot for your help and have a great day !

@stevengharris
Copy link
Owner

I have tried to avoid keystrokes being tied to getHtml(), altho the demo does this to show the HTML updating as you edit. Clearly it works reasonably well if your HTML size is limited, but it is definitely overkill in the general case. If I were going to implement this, I think I would do something like I did for the "search mode", where there is a flag set/unset on the JavaScript side (like reportInputActive or something) that can be filtered-for in the keydown event listener. This listener falls thru and should be lightweight except for special keys like Enter, Delete, arrows, etc. Here's where I check on the search mode when the ev.key is Enter:

MU.editor.addEventListener('keydown', function(ev) {
    let sib;
    const key = ev.key;
    switch (key) {
        case 'Enter':
            // Seems super easy to get repeat Enter events, which I am declaring to
            // be non-useful to avoid expensive processing in lists, etc.
            if (ev.repeat) {
                ev.preventDefault();
                return;
            }
            const sel = document.getSelection()
            const selNode = (sel) ? sel.anchorNode : null;
            if (!selNode) { return };
            if (searcher.isActive) {
                ev.preventDefault();
                if (_keyModified('Shift', 'Enter')) {
                    searcher.searchBackward();
                } else {
                    searcher.searchForward();
                }
                return;
            };
...

Then you can keep a buffer like inputBuffer of the input while reportInputActive is true. In the cases for ev.key, you could activate and inactivate (just typing here, not compiling ;-))...

case '@':
    reportInputActive = true;
    inputBuffer = '';
    break;
case ' ':
    if (reportInputActive) { reportInputActive = false };
    break;

and in the fall-thru case at the end you can report the inputBuffer back to the Swift side at each keystroke when reportInputActive is true, something like:

if (reportInputActive) {
    inputBuffer += ev.key;
    _callback(JSON.stringify({'messageType' : 'reportedInput', 'buffer' : inputBuffer }));
}

This would require a new case on the Swift side in MarkupCoordinator.receivedMessageData(_:) to handle the reportedInput message type and trigger whatever user interaction you want. You might also want new callbacks to MarkupDelegate to inform you of when the mode has been turned off and on. So, for example, the new cases above for @ and space could do _callback('markupActivateInputReport') and _callback('markupdeactivateInputReport') that would need to be handled in MarkupCoordinator.userContentController(_:didReceive:) and then make the new calls to markupDelegate.

FWIW I recently noticed the fall-thru case I have for keydown to always cancel the search mode:

    // Always cancel search if we fall thru
    searcher.cancel()

is causing a callback on every keystroke that I'd like to avoid, so I may be doing something about that issue fairly soon.

@kaimatachi
Copy link
Author

Thanks a lot for your quick and detailed answer !
It seems to do exactly what I ask. I'll try this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants