Zange-chan Zange-chan - 3 months ago 9
HTML Question

Contenteditable height animation: animate only after a line is deleted

This is a continuation from my previous question.

I managed to fixed the "animation pauses every continuous keystrokes" by adding a condition

e.which === 13
, which detects and animate when the Enter key is pressed.




This is how the previous one works:

enter image description here

As you can see, after entering a newline then a continues of keystrokes, the animation lags, which means the animation executes on every keystrokes.




These is the modified one, that will only animate after the Enter is pressed:

enter image description here

It works smoothly (it lags a bit though during the recording).




These is how it works when deleting every character (not long press):

enter image description here

As you can see, it didn't animate well, because as you delete every character continuously, the animation pauses, just like the first attempt.




So what I'm trying to achieve now is the reverse one, animate smoothly after deleting a newline.

Here's a live code:



var kAnimationSpeed = 250;
var kPadding = 10;

$('div[contenteditable]').on('blur keyup paste input', function(e) {
var styleElement = $(this).prev();

var editorHeight = $(this).height();
var styleElementHeight = styleElement.height();

if (editorHeight !== styleElementHeight - kPadding * 2 && e.which === 13 || e.which === 8) {
styleElement.stop().animate({ height: editorHeight + kPadding * 2 }, kAnimationSpeed);
}
});

.autogrowWrapper {
position: relative;
}

.autogrow {
border: 1px solid rgb(0, 0, 0);
height: 40px; /* line-height + 2 * padding */
}

div[contenteditable] {
outline: none;
line-height : 20px;
position: absolute;
top: 10px; /* padding */
left: 10px; /* padding */
right: 10px; /* padding */
}

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<div class="autogrowWrapper">
<div class="autogrow"></div>
<div contenteditable="true"></div>
</div>





How can I achieve a smooth animation on deleting a newline, or how to animate only when a newline is deleted?

Answer

So I managed to solve the problem based on Alex' answer.

In his answer, it only works when pressing the Enter key. But my goal is use Shift + Enter. Pressing Enter will insert new <div> inside the contenteditable div, while the Shift + Enter inserts a new <br> instead of <div>. So I modify the code which will count <br>, stores the value to the data, and compares whether the current number of lines is less than the new number of lines, and also listens the Backspace key. I then replace the e.which === 8 with newLineDeleted variable to tell when a new line is deleted. And remove the input function so it will return the exact boolean value (because it seems not to work with the input function in it. I add cut and paste listener as well.

var kAnimationSpeed = 250;
var kPadding = 10;

$('div[contenteditable]').on('blur keyup paste', function(e) {
  var styleElement = $(this).prev();
  var editorHeight = $(this).height();
  var styleElementHeight = styleElement.height();
  
  var lineCount = parseInt($(this).data('linecount') || 0);
  var newLineCount = $(this).children('br').length;
  $(this).data('linecount', newLineCount);
  var newLineDeleted = (lineCount - 1 === newLineCount && e.which === 8);
  
  var cutPasteListener = (e.ctrlKey && e.which === 86 || e.which === 88);

  if (editorHeight !== styleElementHeight - kPadding * 2 && e.which === 13 || newLineDeleted || cutPasteListener) {
    styleElement.stop().animate({ height: editorHeight + kPadding * 2 }, kAnimationSpeed);
  }
});
.autogrowWrapper {
  position: relative;
}

.autogrow {
  border: 1px solid rgb(0, 0, 0);
  height: 40px; /* line-height + 2 * padding */
}

div[contenteditable] {
  outline: none;
  line-height : 20px;
  position: absolute;
  top: 10px; /* padding */
  left: 10px; /* padding */
  right: 10px; /* padding */
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<div class="autogrowWrapper">
  <div class="autogrow"></div>
  <div contenteditable="true"></div>
</div>

Thanks.