tribute icon indicating copy to clipboard operation
tribute copied to clipboard

CodeMirror integration not working

Open doshkim opened this issue 4 years ago • 5 comments

  • I'm getting the data remotely to fetch the list of suggestions for @mention.
  • What worked: I've implemented a KeyMap handler for CodeMirror to have down/up/enter keys be ignored when Tribute's @mention's suggestion list is open, so that I can use the arrow keys & enter to select the right person/content, instead of cursor moving around within the CodeMirror editor.
  • What's not working: The problem is with left/right arrow keys & backspace. Because element that gets passed to Tribute when these keys are pressed is a textarea (empty) and not the editor (FYI. the CodeMirror editor does not have .value.. it has getValue() to retrieve the textarea's value), it stops calling the servers and the suggestion list no longer updates.

Has anyone successfully implemented @mention feature within CodeMirror?

doshkim avatar Jul 02 '20 07:07 doshkim

Because in CodeMirror, the CodeMirror's TextArea gets reset when backspace/left arrow/right arrow is pressed, Tribute.js is using an empty value to look things up, causing no changes to the suggestion/result list.

Need a way to prevent TextArea reset in CodeMirror for those keys during Tribute.js menu is open, or Tribute.js to look at the original TextArea that CodeMirror is attached to, while editing in the CodeMirror's TextArea.

So far, not sure how to do that..

doshkim avatar Jul 04 '20 09:07 doshkim

A poor hack used for handling backspace:

  1. addKeyMap to CodeMirror to handle Backspace
  2. When Tribute menu is on, handle the Backspace key to throw an error which confuses CodeMirror (stopping operations from happening)
  3. Then backspace will work correctly for updating Tribute menu's content

on the console, it will show the error, but hey.. the feature now works. 🤦

doshkim avatar Jul 05 '20 08:07 doshkim

@doshkim do you happen to have the code for this implementation?

artknight avatar Oct 20 '21 20:10 artknight

We have come up with a different trick. Instead of throwing an exception for Backspace, we preventDefault and implement our own backspace function.

    /**
     * If Tribute is open we ignore keys used by tribute in our editor
     *
     * The tribute active state is attached to the textarea that codemirror creates. (see below)
     */
    editor.codemirror.on('keydown', function(codemirror, e) {
        if (['ArrowDown', 'ArrowUp', 'Enter'].includes(e.code)
            && $(codemirror.getInputField()).data('tribute-active')
        ) {
            e.preventDefault();
        }

        if (e.code === 'Backspace') {
            let $input = $(codemirror.getInputField());
            if ($input.data('tribute-active')
                && $input.val().length
            ) {
                e.preventDefault();
                // remove the last character
                $input.val($input.val().slice(0, -1));
            }
        }
    });

    /**
     * Attach open state to the codemirror textarea (this is not the original textarea). This way we can make sure
     * some keydown events only apply to the tributemenu.
     */
    $(editor.codemirror.getInputField())
        .on('tribute-active-true', e => $(e.currentTarget).data('tribute-active', true))
        .on('tribute-active-false', e => $(e.currentTarget).data('tribute-active', false));

This lets backspace work with tribute without throwing exceptions.

bjhijmans avatar Mar 10 '22 16:03 bjhijmans

@bjhijmans my implementation ended up being this

editor.codemirror.addKeyMap({
	'Enter': codemirror => {
		return tribute.isActive ? false : 'CodeMirror.Pass';
	},
	'Up': codemirror => {
		return tribute.isActive ? false : 'CodeMirror.Pass';
	},
	'Down': codemirror => {
		return tribute.isActive ? false : 'CodeMirror.Pass';
	}
});

artknight avatar Mar 13 '22 18:03 artknight