3

I'm trying to turn some dumb quotes into curly quotes on the fly in a contenteditable div (as seen here), using the following:

$("#editor").on("keyup", ".content", function () {
    $(".content").html(function() {
        var start = this.selectionStart, end = this.selectionEnd;
        return $(this).html()
            .replace(/'\b/g, "\u2018")      // opening single
            .replace(/\b'/g, "\u2019")      // closing single
            .replace(/"\b/g, "\u201c")      // opening double
            .replace(/\b"/g, "\u201d")      // closing double
            .replace(/--/g,  "\u2014")      // em-dash
            .replace(/\b\u2018\b/g,  "'");  // handle conjunctions
        this.setSelectionRange(start, end);
    });
// other stuff happens here...
});

The return bit works fine on its own, but moves the caret position back to the start of the dive after every keystroke, which is obviously not desirable. But trying to keep the caret position (using some code seen here) throws Unreachable 'this' after 'return' in JSHint and so doesn't actually do anything in the browser. Can someone point me in the right direction here, please?

Community
  • 1
  • 1
campegg
  • 123
  • 1
  • 1
  • 11
  • 1. define variable called resultHTML. 2. Store your edited html in it. 3. Perform the selectionRange stuff. 4. Return resultHTML. – Doe Johnson Aug 04 '14 at 02:37
  • When I do it this way, I get an error: `TypeError: 'undefined' is not a function (evaluating 'this.setSelectionRange(start,end)')`. Not sure what's going on there. – campegg Aug 04 '14 at 06:10
  • setSelectionRange is a function of HTMLInputElement. In your code `this` is pointing to something else. Try `$(yourInputElement).setSelectionElement(...);` (just a quick and dirty attempt...). – Doe Johnson Aug 04 '14 at 14:45
  • Thanks for your help so far, but I can't find any documentation on that setSelectionElement method - can you point me at a write-up or (even better) a working example somewhere? – campegg Aug 05 '14 at 08:51
  • https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement.setSelectionRange – Doe Johnson Aug 05 '14 at 16:49

1 Answers1

0

I always tend to keep this in a variable to avoid scope problems. I also don't really understand why you try so hard to encapsulate all in anonymous function. Try changing your code as following:

$("#editor").on("keyup", ".content", function () {
    var target = this;
    var selection = window.getSelection();
    var range = selection.getRangeAt(0);
    var startOffset = range.startOffset;
    var endOffset = range.endOffset;
    var html = $(target).html();
    var newHtml = html.replace(/'\b/g, "\u2018") // opening single
    .replace(/\b'/g, "\u2019") // closing single
    .replace(/"\b/g, "\u201c") // opening double
    .replace(/\b"/g, "\u201d") // closing double
    .replace(/--/g, "\u2014") // em-dash
    .replace(/\b\u2018\b/g, "'"); // handle conjunctions
    var delta = html.length - newHtml.length;
    $(target).html(newHtml);

    var newRange = document.createRange();
    newRange.setStart(range.startContainer, startOffset - delta);
    newRange.setEnd(range.startContainer, endOffset - delta);
    selection.removeAllRanges();
    selection.addRange(newRange);

    // other stuff happens here...
});

I corrected the code, making it work with contenteditable under Chrome. The behaviour of resetting caret position to the start does not occur with IE apparently. Required knowledge was found at: https://developer.mozilla.org/en-US/docs/Web/API/Selection

Edit2: I fixed issue with "--" and prepared a fiddle. All works fine in Chrome and IE as I tested. http://jsfiddle.net/mcoo/8oyn41b1/

Maku
  • 1,464
  • 11
  • 20
  • Thanks, but as @Doe Johnson pointed out above, `setSelectionRange` is a function of HTMLInputElement, so won't really work on a `div`. The caret just keeps returning to the start of the div with the above code. I might just put this one in the 'too hard' basket for now. – campegg Aug 06 '14 at 10:58
  • Oh sorry, I missed the contenteditable aspect of your question. Anyway, what browser do you receive that behaviour at? Maybe 'other stuff' has some impact on caret position? – Maku Aug 06 '14 at 12:49
  • Chrome and Safai on Mac and Chrome on Win (so all Webkit browsers - haven't tried on FF yet on any platform). – campegg Aug 07 '14 at 03:53
  • Thanks! It semi works for me... the replacement for quotes is working in one of my `div`s, but the caret jumps back to the start of the div after replacing the em-dash. And in the second `contenteditable div`, it jumps back to the start after every keystroke. – campegg Aug 07 '14 at 11:04
  • If it makes a difference, this is what my HTML looks like: `
    `
    – campegg Aug 07 '14 at 11:06
  • It's because the length of the html is changing it causes chrome to resolve it by resetting range. I couoldn't recreate the issue with second div though. Please take a look at the fiddle from edited answer. – Maku Aug 07 '14 at 11:28