最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - contenteditable selection of text not working - Stack Overflow

programmeradmin0浏览0评论

I am faced with following: when I try to select text in a contenteditable element and the end of the selection is the start of the element content, then no select event is fired and there are no Selection and Range objects.

Could somebody please give me any advice on why this might occur or how I can prevent this?

Code responsible for getting selection range:

$('div[contenteditable="true"]').bind("mouseup keyup touchend", function() {
  lastCaretIndex = getSelectionRange();
});

function getSelectionRange() {
  var sel;
  if (window.getSelection) {
    sel = window.getSelection();

    console.log(sel); // this doesn't print anything event empty string

    if (sel.rangeCount) {
      return sel.getRangeAt(0);
    }
  } else if (document.selection) {
    return document.createRange();
  }

  return null;
}
<div id="main-input" contenteditable="true">Hello world!</div>
<script type="text/javascript" src=".2.4.min.js"></script>

I am faced with following: when I try to select text in a contenteditable element and the end of the selection is the start of the element content, then no select event is fired and there are no Selection and Range objects.

Could somebody please give me any advice on why this might occur or how I can prevent this?

Code responsible for getting selection range:

$('div[contenteditable="true"]').bind("mouseup keyup touchend", function() {
  lastCaretIndex = getSelectionRange();
});

function getSelectionRange() {
  var sel;
  if (window.getSelection) {
    sel = window.getSelection();

    console.log(sel); // this doesn't print anything event empty string

    if (sel.rangeCount) {
      return sel.getRangeAt(0);
    }
  } else if (document.selection) {
    return document.createRange();
  }

  return null;
}
<div id="main-input" contenteditable="true">Hello world!</div>
<script type="text/javascript" src="https://code.jquery./jquery-2.2.4.min.js"></script>

JSFiddle (open your browser console to make sure that selection doesn't get logged).

Share Improve this question edited Apr 5, 2017 at 8:02 Just a student 11.1k2 gold badges44 silver badges71 bronze badges asked Mar 31, 2017 at 10:16 nowikonowiko 2,5677 gold badges40 silver badges87 bronze badges 4
  • This question would be much better with example code. If you post it on jsfiddle or as a stack snippet, we can immediately see what code you are using, and start from there. – phihag Commented Mar 31, 2017 at 10:25
  • @phihag Hello, I have added code responsible for getting user selection range – nowiko Commented Apr 5, 2017 at 7:25
  • Please create a working code sample showing the problem you are facing. I'm sure the unction() above in your code sample want work and I just don't want to dig trough typos ... – caramba Commented Apr 5, 2017 at 7:31
  • @caramba I have added jsfiddle link – nowiko Commented Apr 5, 2017 at 7:55
Add a ment  | 

2 Answers 2

Reset to default 8 +50

The issue is that you only log selection changes when specific events occur on the contenteditable element. More specifically, you have

$('div[contenteditable="true"]').bind("mouseup keyup touchend", // ...

In particular the mouseup event will normally be triggered when the selection changes. Except when it doesn't. When you release the mouse outside of the editable div (which you do in your example!), then the div will never receive a mouseup event and thus never log the selection.

There are two ways around this:

  1. Listen for events on the entire body. Downsides are that you receive more events that do not influence the selection and that it is still possible to get mouseup events outside of the page.
  2. Listen for the selectionchange event.

document.addEventListener('selectionchange', function(event) {
  console.log(event.type);
});
<div contenteditable="true">Hello world!</div>

You can of course still access the selection as you currently do inside this event handler. This event is triggered every time the selection changes, so you may want to throttle it.

Full implementation of that can be found below.

function handler() {
  // do whatever you want here
  // this shows the selection and all ranges it consists of
  var sel = window.getSelection(),
      ranges = Array(sel.rangeCount).fill(0).map((_, i) => sel.getRangeAt(i));
  ranges = ranges.map((r) => `${r.startOffset}-${r.endOffset}`).join(';');
  console.log(`Selection [${ranges}:"${sel.toString()}"]`);
}

function throttle(func) {
  var timeoutId = false,
      called = false,
      wrap = function() {
        if (!called) {
          clearInterval(timeoutId);
          timeoutId = false;
        } else {
          func();
        }
        called = false;
      };
  return function() {
    if (timeoutId === false) {
      func();
      timeoutId = setInterval(wrap, 500);
    } else {
      called = true;
    }
  };
}

document.addEventListener('selectionchange', throttle(handler));
<div contenteditable="true">Hello world!</div>

Your actual code works perfectly and logs a Selection object in the console, even if the end of the selection is the start of the element content.

Indeed you need to log this Selection text instead of logging the whole object which reflects the whole Selection object changes for each event.

I updated your snippet to log the text of the selection using Selection.toString(), you can see it working here:

$('div[contenteditable="true"]').bind("mouseup keyup touchend", function() {
  lastCaretIndex = getSelectionRange();
});

function getSelectionRange() {
  var sel;
  if (window.getSelection) {
    sel = window.getSelection();

    console.log(sel.toString()); // this doesn't print anything event empty string

    if (sel.rangeCount) {
      return sel.getRangeAt(0);
    }
  } else if (document.selection) {
    return document.createRange();
  }

  return null;
}
<div id="main-input" contenteditable="true">Hello world!</div>
<script type="text/javascript" src="https://code.jquery./jquery-2.2.4.min.js"></script>

You can check this answer, it shows and explains the perfect way to get text selection.

发布评论

评论列表(0)

  1. 暂无评论