3

Is it possible to make a p element both content editable AND JQuery UI Sortable?

In my simple example below, the p elements are sortable but you cannot edit their text. Is there anyway to overcome this?

Note I have tried nesting p's in containers so that the container is sortable and the p is editable but I still cannot edit the inner p.

$(document).ready(function() {
   $( ".elements" ).sortable({
    connectWith: ".elements"
 });
});
p {
 height: 100px;
 background-color: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
<script type="text/javascript" src="../dist/js/visual-designer.min.js"></script>

<div class="elements">
 <p id="foo" contenteditable="true">Foo. Help! I can be sorted but cannot be edited.</p>
 
 <!-- Even if I nest p's in a container they still are not editable -->
 <div class="test-container">
  <p id="bar" contenteditable="true">Bar. Help! I can be sorted but cannot be edited.</p>
 </div>
</div>
Nisarg Shah
  • 14,151
  • 6
  • 34
  • 55
sazr
  • 24,984
  • 66
  • 194
  • 362

3 Answers3

2

Through some random attempts at getting it to work, I found that setting focus on the element, and then moving the cursor to the end of the content editable (as shown here by Nico Burns) is adequate to get the content editable working.

My guess is that the sortable prevents the content editable from getting focus because of some sort of event.preventDefault or cancelBubble.

$(document).ready(function() {
  $(".elements").sortable({
    connectWith: ".elements"
  });

  $(".elements p").on("click", function(e) {
    $(this).focus();
    setEndOfContenteditable(e.target);
  });
});

function setEndOfContenteditable(contentEditableElement) {
  var range, selection;
  if (document.createRange) //Firefox, Chrome, Opera, Safari, IE 9+
  {
    range = document.createRange(); //Create a range (a range is a like the selection but invisible)
    range.selectNodeContents(contentEditableElement); //Select the entire contents of the element with the range
    range.collapse(false); //collapse the range to the end point. false means collapse to end rather than the start
    selection = window.getSelection(); //get the selection object (allows you to change selection)
    selection.removeAllRanges(); //remove any selections already made
    selection.addRange(range); //make the range you have just created the visible selection
  } else if (document.selection) //IE 8 and lower
  {
    range = document.body.createTextRange(); //Create a range (a range is a like the selection but invisible)
    range.moveToElementText(contentEditableElement); //Select the entire contents of the element with the range
    range.collapse(false); //collapse the range to the end point. false means collapse to end rather than the start
    range.select(); //Select the range (make it the visible selection
  }
}
p {
  height: 50px;
  background-color: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
<script type="text/javascript" src="../dist/js/visual-designer.min.js"></script>

<div class="elements">
  <p id="foo" contenteditable="true">Foo. Help! I can be sorted but cannot be edited.</p>

  <div>
    <p id="bar" contenteditable="true">Bar. Help! I can be sorted but cannot be edited.</p>
  </div>
</div>
Nisarg Shah
  • 14,151
  • 6
  • 34
  • 55
0

Probably it's not allowing the edition because Jquery is overwriting some event callback enabled by default in contenteditable=true elements.

You can try overwriting focusin and focusout events in order to allow that edition. Check how they are doing it in the link below:

Focus / blur events on contenteditable elements

I hope it'll help you ;)

0

Here is an example where when the element is clicked, the p tag is converted to an input tag, and when the focus is lost, its converted back to a p tag!

$(document).ready(function() {
 // How to associate a handle that sits outside the element to be dragged?
   $( ".elements" ).sortable({
    connectWith: ".foo"
 });
  
  function focusout(){
    var val = $('input[contenteditable*="true"]').val();
    var replacement2 = $('<p contenteditable="true">'+val+'</p>');
    $('input[contenteditable*="true"]').replaceWith(replacement2);
    replacement2.on("click", clicked);
  }
  
  function clicked(){
    var replacement = $('<input contenteditable="true" value="'+this.innerHTML+'"/>');
    $(this).replaceWith(replacement);
    replacement.on("focusout", focusout);
    $('input[contenteditable*="true"]').focus();
  }
  
  $('p[contenteditable*="true"]').on("click", clicked);
  
});
p {
 height: 100px;
 background-color: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>

<div class="elements">
 <p id="foo" contenteditable="true">Foo. Help! I can be sorted but cannot be edited.</p>
 
 <!-- Even if I nest p's in a container they still are not editable -->
 <div class="test-container">
  <p id="bar" contenteditable="true">Bar. Help! I can be sorted but cannot be edited.</p>
 </div>
</div>
Naren Murali
  • 19,250
  • 3
  • 27
  • 54