How can I keep the line breaks (formatting) of an element appended to a list via a contenteditable div input?

Viewed 91

I've a bit of a problem. I'm currently programming a list, where users can enter some hints/messages. This works quite well but there is a problem I've found and I don't like it.

To prevent any HTML input, I've implemented some stuff inside a paste function that gives me any plain text in case there is HTML. When I now copy some code that has multiple lines like:

$( "button" ).click( function () {
    let template = $( "#template" ).clone();

  template.removeAttr("id");
    template.html( input.html() );

  input.empty();
    $( "#wrapper" ).append( template );
} ); 

and paste it into my contenteditable div, the line formatting is still there. If I now press my button to append it to the list, the formatting is completely gone and everything is in one single line.

I'm looking now for a way to fix this. Does anyone has an idea how I prevent loosing any of the line breaks and formatting?

jQuery(document).ready(function($) {
  let input = $("#input");

  $("button").click(function() {
    let template = $("#template").clone();

    template.removeAttr("id");
    template.html(input.html());

    input.empty();
    $("#wrapper").append(template);
  });

  input.on("paste", function(e) {
    e.preventDefault();

    let clipboardText = e.originalEvent.clipboardData.getData('text');

    document.execCommand("insertHTML", false, clipboardText.replace(/\t/g, "    "));
  });
});
[contenteditable=true] {
  border: 1px solid #aaaaaa;
  padding: 8px;
  border-radius: 12px;
  margin-bottom: 20px;
  white-space: pre-wrap;
  word-wrap: break-word;
}

[contenteditable=true]:empty:before {
  content: attr(placeholder);
  display: block;
  color: #aaaaaa;
}

#wrapper {
  border: 1px solid;
  height: 350px;
  overflow-y: scroll;
  overflow-x: hidden;
  margin-bottom: 10px;
  padding: 15px;
}

.entry {
  display: flex;
  background-color: gray;
  margin-bottom: 8px;
  padding: 4px;
}

#template {
  display: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="wrapper">
  <span id="template" class="entry"></span>
</div>
<div id="input" placeholder="Write a message..." contenteditable="true" spellcheck="true"></div>
<button>Add to list</button>

Edit

I'm already replacing tabs by whitespaces to move around a possible issue here.

1 Answers

You can just add white-space: pre; to your css .entry class, like so:

jQuery(document).ready(function($) {
  let input = $("#input");

  $("button").click(function() {
    let template = $("#template").clone();

    template.removeAttr("id");
    template.html(input.html());

    input.empty();
    $("#wrapper").append(template);
  });

  input.on("paste", function(e) {
    e.preventDefault();

    let clipboardText = e.originalEvent.clipboardData.getData('text');

    document.execCommand("insertHTML", false, clipboardText.replace(/\t/g, "    "));
  });
});
[contenteditable=true] {
  border: 1px solid #aaaaaa;
  padding: 8px;
  border-radius: 12px;
  margin-bottom: 20px;
  white-space: pre-wrap;
  word-wrap: break-word;
}

[contenteditable=true]:empty:before {
  content: attr(placeholder);
  display: block;
  color: #aaaaaa;
}

#wrapper {
  border: 1px solid;
  height: 350px;
  overflow-y: scroll;
  overflow-x: hidden;
  margin-bottom: 10px;
  padding: 15px;
}

.entry {
  display: flex;
  white-space: pre;
  background-color: gray;
  margin-bottom: 8px;
  padding: 4px;
}

#template {
  display: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="wrapper">
  <span id="template" class="entry"></span>
</div>
<div id="input" placeholder="Write a message..." contenteditable="true" spellcheck="true"></div>
<button>Add to list</button>

Using white-space: pre will tell the browser to preserve white space, and text will only wrap on line breaks. Acts like the <pre> tag in HTML.

Related