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

javascript - Cursor moves to end of the contenteditable div when character removed from div - Stack Overflow

programmeradmin2浏览0评论

I am working on creating my own chat application in which I used content-editable div as chatbox. I am implementing mention feature where my mention is username wrapped in a span tag followed by a space( ) but my problem is when I remove space my cursor moves to the end of the div.

with space

<html>

<head>
</head>

<body>
  <div contenteditable=true><span contenteditable='false'>UserName</span>&nbsp;</div>
</body>

</html>

I am working on creating my own chat application in which I used content-editable div as chatbox. I am implementing mention feature where my mention is username wrapped in a span tag followed by a space(&nbsp;) but my problem is when I remove space my cursor moves to the end of the div.

with space

<html>

<head>
</head>

<body>
  <div contenteditable=true><span contenteditable='false'>UserName</span>&nbsp;</div>
</body>

</html>

without space

<html>

<head>
</head>

<body>
  <div contenteditable=true><span contenteditable='false'>UserName</span></div>
</body>

</html>

This is how I implemented in code and also this bug happens only in chrome.

Share Improve this question edited Mar 12, 2018 at 7:49 Jithin Raj P R 6,7978 gold badges40 silver badges71 bronze badges asked Mar 8, 2018 at 7:03 Himanshu BansalHimanshu Bansal 4864 silver badges19 bronze badges 0
Add a comment  | 

5 Answers 5

Reset to default 8

This is actually a bug in the browsers, I have a workaround but I don't know how much it will help you but this is the best we can do now in my knowledge.

div>span {
   display:inline-block;
}
<div contenteditable="true"><span contenteditable="true"><span contenteditable="false">UserName</span></span>&nbsp;</div>

Without space

div>span {
  display:inline-block;
}
<div contenteditable="true"><span contenteditable="true"><span contenteditable="false">UserName</span></span></div>

If you want a full proof content to be there then here is a solution with script combining : before pseudo:

Here am taking the width of the : before pseudo-element and hading it over to the div element padding-left. I have used script keeping in mind of your dynamic usernames.

var testBox = document.querySelector('.test'),
  pseudoBeforeWidth = window.getComputedStyle(testBox, ':before').width, //getting the width of the parent elemnts `:before`
  pseudoBeforeContent = window.getComputedStyle(testBox, ':before').content;

testBox.style.paddingLeft = pseudoBeforeWidth; //handing the width to the parent elemnts padding left style
var i = 0
var n = 0;
testBox.addEventListener('keydown', function(event) {
  const key = event.key; // const {key} = event; ES6+
  if ((key === "Backspace" || key === "Delete") && n == 0) {
    i++
    console.log(testBox.textContent, i, n);
    if (testBox.textContent == "" && i >= 2) {
      testBox.className += ' userhide ';
      testBox.style.paddingLeft = 0;
      n = 1;
    }
  }
});
div:before {
  content: attr(data-user);
  display: inline-block;
  position: absolute;
  left: 5px;
}

.test.userhide:before {
  display: none;
}
<div class="test" contenteditable="true" data-user="UserName"></div>

I hope this was helpful for you.

Analysis

Think of a simple text editor(notepad) where you have typed three characters - TRY

Now, its obvious that the cursor can be placed only at 4 places here, which are:

  • before T
  • between T and R
  • between R and Y
  • after Y

The reason for which is simply because, these 3 characters are the only editable ones here and they are 3 individual entities, which can't be edited/separated further. For example, we can't place the cursor in between the letter 'T' and separate the and from it.

Same is the case with your scenario as the cursor is moved to the end of the div once the &nbsp; is cleared because the contenteditable=true is set to the <div> and is set as false to the <span>. Therefore the div is the only editable element here and the span is not. So the cursor can position itself only on an editable place which is either at the beginning of an editable element(div in this case) or at the end of it and not in between.

As the div is a block element, the cursor is moved to the end of the page as the block elements occupy the whole width of its parent. We can see the cursor being moved to the middle of the page if we set width: 50%; to the div.

Solution

Considering your comments on other answers, that you need to keep the width as 100%, the solution is to wrap the div with another one which also have the attribute contenteditable=true and keep the child div as an inline-block element.

<div contenteditable=true>
  <div class="inl-blck" contenteditable=true><span contenteditable='false'>UserName</span>&nbsp;</div>
</div>

CODEPEN

Explanation

Here, both the parent and child divs are editable where the parent occupying the full width (100%) and the child is an inline-block element, which just occupies the space of its contents. Therefore, once the &nbsp; is cleared, the cursor moves to the end of the next editable content which is the child div.

Note that, you need to keep the child div and span along with the &nbsp; in the same line in you code as otherwise it will create extra characters (whitespaces) in the section, which will break the contenteditable further.

Hope this helps.

This Can Help You

<div contenteditable=true style="display: inline-block;background: #000;color:#fff;"><span contenteditable=false>UserName</span>&nbsp;</div>

Believe it or not this bug has to do with whitespace in the actual HTML markup itself.

Here is a working example:

.username {
    margin-left: 10px;
}
<div contenteditable="true">
  <span contenteditable="false" class="username">Username</span>
</div>

By simply moving the closing div to the next line gives we communicate the break to the html parser.

A simple fix is to add <br> inside the contenteditable block.

<body>
  <div contenteditable=true><span contenteditable='false'>UserName</span>&nbsp;<br></div>
</body>
发布评论

评论列表(0)

  1. 暂无评论