Schaffer
Schaffer

Reputation: 315

How to manipulate list element on Enter key press

I want to allow the editing of an ordered list using contenteditable. When the user changes or adds in a new element in the list I want to be able to manipulate the text (e.g. wrap in span tag, replace text etc).

I've created a listener for the Enter key and can get the last list element value. I've tried to change this and replace with the new value. However this populates the new list element created on the enter press.

<div>
   <ol contenteditable=true class="editor">
    <li><br></li>
   </ol>
</div>
$('.editor' ).on('keydown .editable', function(e){
    if ( e.keyCode === 13 ) {   

    var insertText = "<span>"+e.target.lastElementChild.innerText+"</span>";
    e.target.lastElementChild.innerHTML = insertText;
    return true
  }
 });

What is the best way to implement this functionality for new entries anywhere in the list not just the end? Open to Jquery solutions

example jsfiddle

Upvotes: 4

Views: 1861

Answers (4)

soben360
soben360

Reputation: 31

hello you might wanna check this let me give you a heads up. instead of using the

lastchild.innerHTML

replace it with

nextSibling.innerHTML

like this

$('.editor' ).on('keydown .editable', function(e){
    if ( e.keyCode === 13 ) {
			
						
			var insertText = "<span>"+e.target.lastElementChild.innerText+"</span>";
			e.target.nextSibling.innerHTML = insertText;
			
			
			return true
		}
 });
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div>
<ol contenteditable=true class="editor">
	<li><br></li>
</ol>
</div>

$('.editor' ).on('keydown .editable', function(e){
    if ( e.keyCode === 13 ) {   

    var insertText = "<span>"+e.target.lastElementChild.innerText+"</span>";
      e.target.nextSibling.innerHTML = insertText;
      return true
     }
    });

Upvotes: 0

jo_va
jo_va

Reputation: 13983

You could use a MutationObserver to detect when a child is added to your list, and then update the previousSibling to wrap it in a <span>:

function subscriber(mutations) {
  mutations.forEach(mutation => {
    mutation.addedNodes.forEach(node => {
      const prev = node.previousSibling;
      if (prev) {
        prev.innerHTML = `<span>${prev.innerHTML.replace(/<br>$/, '')}</span>`;
      }
    });
  });
}

const observer = new MutationObserver(subscriber);
observer.observe(document.querySelector('ol[contenteditable]'), { childList: true });
.editor span::after {
  content: '😀';
}
<ol contenteditable class="editor">
  <li>First li</li>
</ol>

Upvotes: 2

daddygames
daddygames

Reputation: 1928

Instead of taking action when an edit happens, you could set an interval that will modify the html of the li elements as desired.

setInterval(function(){
    $('.editor' ).find('li').each(function(){
    if ($(this).html().indexOf('span')==-1){
            $(this).html('<span>' + $(this).html() + '</span>');
    }
  });
}, 200);

Upvotes: 0

Taplar
Taplar

Reputation: 24965

You could bind your logic to the last li, and perform your logic from the events it emits.

$('.editor .last-item')
  .on('click', function(e){
    // clear out the html so the user can just type
    e.target.innerHTML = '';
  })
  .on('keydown', function(e){
    if (e.keyCode === 13) {
      // ignore the enter key so it doesn't insert a new like
      e.preventDefault();
      // create the new li before the last one
      $('<li>'+ e.target.innerHTML.trim() +'</li>').insertBefore(e.target);
      // clear out the html so the user can keep entering items
      e.target.innerHTML = '';
    }
  })
  .on('blur', function(e){
    // if the user leaves the field, change it back to the instructional text
    e.target.innerHTML = 'Click to enter New List Item';
  });
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div>
   <ol class="editor">
    <li class="last-item" contenteditable=true>Click to enter New List Item</li>
   </ol>
</div>

Upvotes: 0

Related Questions