Get actual target dom element on edit

Hi,

I have the editor configured with following dom elements

  • Header

  • Content

Now I have this event handler handleKeyDown attached to the editorview and I would like to listen to the TAB key and ignore it on Header, however, when the same TAB key is used in Content i need to use it default functionality.

So basically my question is how do I identify whether the edit operation is happening on Header or Content from handleKeyDown(view, event){ ....} event handler?

What I have tried so far: I tried to check the view.dom, but it shows the entire dom of the editor(header and content) and the same is the case with event.target.

any quick help would be really appreciated with this approach or if you think it can be achieved in a different way then I’m all ears :slight_smile:

You’ll want to use view.state.selection I guess—that’ll tell you where the cursor or selection is in the document.

when I access this object inside the handleKeyDown event handler, I get this below object structure and I can’t figure out which property in it clearly identifies the place where is the cursor is currently placed on the editor.

I guess, the pos property just points at the relative position where is key was pressed, so I have no idea how to figure out whether this is from header or content

I did spend quite a lot of time writing documentation for this project. It might help you if you’d spend some more time reading it.

2 Likes

thanks, i was able to figure it out from the path property :smiley: just sharing it here, so that it might help others with similar issues

const head: any = view.state.selection.$head; const isSectionHeader = head.path[3].type.name === 'sectionHeader';

That’s private and not guaranteed to work in future versions, though! Poking at JavaScript objects really is no substitute for reading documentation.

@marijn, I totally get it what you are saying, but the documentation isn’t easy to go through. I spent a couple of hours going through it and found no direct answer to my problem, which I why posted my question here to get your expert advice.

Believe me, this is my personal opinion that the documentation is not so easy, especially with no code examples, it makes it harder to understand.

anyway, I really appreciate your support and help that you’re providing here even though its not a paid one :slight_smile:

if you think it can be achieved in a different way then I’m all ears :slight_smile:

Here is a pattern I have to come to like when dealing with this kind of problem.

The following code wraps a node in a blockQuote when it is not already inside a blockQuote:


import { keymap } from 'prosemirror-keymap';
import { findParentNodeOfType } from 'prosemirror-utils';
import { wrapIn } from 'prosemirror-commands';

const type = MY_BLOCKQUOTE_TYPE

const plugin = keymap({
  Tab: filter(
    // Do a check
    (state) => !isInBlockquote(state),
    (state, dispatch, view) => {
      // If check passes this will be called 
      // dispatch whatever you want in this block
      return wrapIn(type)(state, dispatch, view);
    },
  ),
});

const isInBlockquote = (state) =>
  Boolean(findParentNodeOfType(type)(state.selection));


function filter(predicates, cmd) {
  return function (state, dispatch, view) {
    if (!Array.isArray(predicates)) {
      predicates = [predicates];
    }
    if (predicates.some((pred) => !pred(state, view))) {
      return false;
    }
    return cmd(state, dispatch, view) || false;
  };
}

Believe me, this is my personal opinion that the documentation is not so easy, especially with no code examples, it makes it harder to understand.

Imho, the documentation is dense because the subject in hand is not straightforward. In my experience initially it might be intimidating, but I think after reading the docs multiple times, looking at the examples and reading the code, things finally start to make sense.

2 Likes