Trouble with markjs.io and TinyMCE Bookmark when caret is active on text

412 views Asked by At

Okay. I'm using TinyMCE and MarkJS to highlight long words in the text. If words are longer than 6 letters they are marked.

I've put together a demo here: http://codepen.io/MarkBuskbjerg/pen/RomqKO

The problem:

At first glance everything is mighty fine. The long words are highligthed perfectly.

But...

If you place the caret inside the word. The highlight disappears on keydown.

Example: Place the caret at the end of the text and arrow key your way throught the text the highlight is gone when the caret is on a highlighted word.

I suspect that the problem is due to TinyMCE triggering some sort of event when the caret is on a word.

Possible solution I've tried to see if the caret is somehow splitting the word and thereby making it seem shorter. Which doesn't seem to be the case (see the console.log(words) on line 24.

** EDIT 30-12-2016:** Seems like it ought to be TinyMCE triggering the error when the caret is inside of a word. Maybe because it execute some other event?

My question I somehow need to find a way to keep the word highlighted while the caret is active on the highlighted span.

Any ideas on how to achieve this is very much appreciated :)

The HTML markup is:

<div class="container">
    <div id="myTextArea" contenteditable="true">
        Lorem ipsum dolores sit amet.
    </div>
</div>

The JavaScript goes like this:

tinymce.init({
  selector: '#myTextArea',
  height: 200,
  setup: function(ed) {
    ed.on('keyup', myCustomInitInstance);
    ed.on('paste', myCustomInitInstance);
    ed.on('cut', myCustomInitInstance);
  },
  init_instance_callback: "myCustomInitInstance",
});

function myCustomInitInstance(inst) {
  var rawText = tinyMCE.get('myTextArea').getContent({
    format: 'text'
  });
  rawText = rawText.replace(/<([^>]+)>|[\.\+\?,\(\)"'\-\!\;\:]/ig, "");

  var words = rawText.split(" ");

  var matchWarning = [];
  var longWord = 6;
  var wordCounter;
  var output;
  for (var i = 0, len = words.length; i < len; i++) {
    if (words[i].length > longWord) {
      matchWarning.push(words[i]);
    }
  }

  var editor = tinyMCE.activeEditor;
   // Store the selection
  var bookmark = editor.selection.getBookmark();
  console.log(bookmark);
   // Remove previous marks and add new ones
   var $ctx = $(editor.getBody());
   $ctx.unmark({
     done: function() {
      $ctx.mark(matchWarning, {
        acrossElements: true,
        //debug: true,
        separateWordSearch: false
      });
    }
  });
  console.log(bookmark);
  // Restore the selection
  editor.selection.moveToBookmark(bookmark);

}
1

There are 1 answers

4
dude On BEST ANSWER

Your problem is that you're listening to the keyup event, which is also fired if you're navigating with the arrow keys. And in the callback function of this event listener you've removing the highlighted terms using .unmark(), which is why the highlighting disappears.

To solve this, you need to ignore events from arrow keys. I've done this for you. Also I've refactored your example to simplify the situation, removed unnecessary variables and used TinyMCE v4 methods (which you're using).

Example

tinymce.init({
  selector: "#myTextArea",
  height: 200,
  setup: function(editor) {
    editor.on("init keyup", function(e) {
      var code = (e.keyCode || e.which || 0);
      // do nothing if it's an arrow key
      if (code == 37 || code == 38 || code == 39 || code == 40) {
        return;
      }
      myCustomInitInstance();
    });
  }
});

function myCustomInitInstance() {
  var editor = tinymce.get("myTextArea"),
    rawText = editor.getContent({
      format: "text"
    }).replace(/<([^>]+)>|[\.\+\?,\(\)"'\-\!\;\:]/ig, ""),
    words = rawText.split(" "),
    matchWarning = [],
    longWord = 6;

  for (var i = 0, len = words.length; i < len; i++) {
    if (words[i].length > longWord) {
      matchWarning.push(words[i]);
    }
  }

  console.log(matchWarning);
  var bookmark = editor.selection.getBookmark();
  var $ctx = $(editor.getBody());
  $ctx.unmark({
    done: function() {
      $ctx.mark(matchWarning, {
        acrossElements: true,
        separateWordSearch: false,
        done: function() {
          editor.selection.moveToBookmark(bookmark);
        }
      });
    }
  });

}