Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 217
Zange-chan Avatar asked Aug 09 '16 01:08

Zange-chan


2 Answers

I dont know if this works crossbrowser but Chrome adds <div>s for lines, so you can actually count them:

working fiddle

var kAnimationSpeed = 250;
var kPadding = 10;
var keyCodeDelete = 8;
var keyCodeReturn = 13;

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

  var divCount = parseInt(el.data('divcount') || 0 );
  var newDivCount = el.children('div').not(':contains("br")').length;
  var newLineDeleted = (divCount - 1 == newDivCount && e.which == keyCodeDelete);

  var heightCheck = (editorHeight !== styleElementHeight - kPadding * 2);
  var keyCodeCheck = (e.which === keyCodeReturn || e.which === keyCodeDelete);


  if (heightCheck && keyCodeCheck) {
    if (newLineDeleted) {
      $('body').append('<p>nl removed!</p>');
    }
    styleElement.stop().animate({ height: editorHeight + kPadding * 2 }, kAnimationSpeed);
  }

  el.data('divcount', newDivCount);
});

So you just have to adjust your animation :)

like image 77
Alex Avatar answered Oct 05 '22 08:10

Alex


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.

like image 22
Zange-chan Avatar answered Oct 05 '22 09:10

Zange-chan