Search code examples
javascriptjquerykeyup

jQuery can't catch keyup target element in designmode


I'm trying to write my own WYSIWYG Editor with jQuery!

I need to catch events which fired on the editor's frame. The "click" event is working fine and has the right current element, but "keyup" returns only <body> as current tag in any place! What did I do wrong?

<iframe id="editor"></iframe>
<script>

  // Define editor
  var editor = $('#editor').contents().find('body');

  // Switch to design mode
  $('#editor').contents().prop('designMode', 'on');

  editor.on("click", function(event) {
    console.log("clicked:" + event.target.nodeName + $(this).prop("tagName") + $(event.target).prop("tagName"));
  });

  editor.on("keyup", function(event) {
    console.log("key:" + event.target.nodeName + $(this).prop("tagName") + $(event.target).prop("tagName"));
  });

</script>

There is example: jsfiddle.net/p38L10zp/1


Solution

  • There are two options for retrieving the element, which is currently being edited.

    1. Use Selection API to determine targeted HTML Element.
    2. Use MutationObserver to track DOM mutations inside the <iframe>

    Selection

    Please consider a working example of the first approach in this JSFiddle.

    The example is heavily inspired by another SO question Get parent element of caret in iframe design mode.

    MutationObserver

    The use of this API might be somewhat tricky, here's a working example for a very specific use-case.

    And the code:

    var editor = $('#editor').contents().find('body');
    
    var observer = new MutationObserver(function(mutations) {
      mutations.forEach(function(mutation) {
        console.log(mutation);
    
        if (mutation.type === 'characterData') {
            console.log('Tag name is: ' + mutation.target.parentNode.tagName);
        }
      });
    });
    
    // Configuration of the observer.
    var config = {
      attributes: true,
      childList: true,
      characterData: true,
      subtree: true
    };
    
    observer.observe(editor[0], config);
    
    $('#editor').contents().prop('designMode', 'on');
    
    editor.append("<p>Test <b>bold</b> text</p>");