2

Trying to create a simple html editor.

$('#edit').on('input', function(e){
 console.log($(this).html());
});
.edit{
background:gold;
min-height:140px;
font-size:1.6em;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class='edit' id='edit' contenteditable></div>

type this inside the div edit:

lorem
ipsum

then place the cursor at the end of lorem - and press spacebar and del on keyboard to get this:

lorem ipsum

and you'll see the problem - ipsum has much larger font size then lorem.

That's the first question - how to avoid this?

My second try was using textarea instead of contenteditable div but in that case I cannot use document.execCommand to change some text to be bold etc.

So what is the way to set html tags inside textarea like it's done here on stackoverflow, or on wordpress sites and so on?

My final goal is to provide a simple editor with just a a few commands - bold, italic and align Users should be able to type and style the text, and click on a button should get the html content.

Any help?

qadenza
  • 9,025
  • 18
  • 73
  • 126
  • 2
    https://medium.engineering/why-contenteditable-is-terrible-122d8a40e480 – Mark Mar 08 '19 at 21:30
  • 1
    Don;t use contenteditable. Choose an existing markup like Markdown or Pug and utilize a preexisting library to convert the input to HTML. For ex. https://www.npmjs.com/package/marked – robinsax Mar 08 '19 at 21:32
  • @robinsax, - ` and utilize a preexisting library to convert the input to HTML` - any example, pls – qadenza Mar 08 '19 at 21:34
  • 2
    `contentEditable` is more like a WYSINWYE (What You See Is Not What You Expect). I can't reproduce your issue with Firefox, though. – Teemu Mar 08 '19 at 21:35
  • @Teemu, try on chrome, pls – qadenza Mar 08 '19 at 21:42
  • 1
    Indeed, Chrome and Opera added a `` element, Firefox and Edge didn't, neither did IE11. – Teemu Mar 08 '19 at 21:49
  • 1
    Yes, Chrome adds span tags for some reason, [more info](https://stackoverflow.com/questions/19243432/prevent-contenteditable-mode-from-creating-span-tags) – James Mar 08 '19 at 21:52
  • So, the span within a div, both with relative font sizes set. If you changed your font from 1.6em to 1.6rem, it should not get bigger. – James Mar 08 '19 at 21:55
  • 1
    @qadenza I did include an example... `marked` is a markdown to HTML converter – robinsax Mar 08 '19 at 23:59

2 Answers2

1

As pointed out by many angry developers, contenteditable is indeed terrible - don't expect anything great, but let's try to make do anyway.

By wrapping the editable div inside another div and applying the CSS font to this wrapper, the text shall not get bigger when doing the process described in the question. The HTML is still ugly (useless span tags with 1em of font size), but the text content is acceptable.

const editable = document.querySelector('div[contenteditable]');

editable.onkeyup = () => {
  document.querySelector('#html-log').innerText = editable.innerHTML;
  document.querySelector('#text-log').innerText = JSON.stringify(editable.innerText);
}
#wrapper {
  font-size: 1.2em;
}
div[contenteditable] {
  width: 100%;
  height: 100%;
  border: solid;
  font-size: 1em;
}
<div id="wrapper">
  <div contenteditable></div>
</div>

<h3>HTML content</h3>
<pre id="html-log"></pre>

<h3>Text content</h3>
<pre id="text-log"></pre>
Nino Filiu
  • 16,660
  • 11
  • 54
  • 84
0

.execCommand()

Try loading the first parameter dynamically by assigning the #id of each <button> to match a command.

<button id="bold">B</button>
...
... var ID = this.id;
return document.execCommand(ID, false, null)

Demo

$('#WYSINWYE').on('submit', function() {
  return false;
});
$('#edit').focus();
$('#edit').on('keyup', function() {
  $('#view').html($(this).text());
});
$('#ctrl button').on('click', function() {
  var ID = this.id;
  if (ID === 'HTML') {
    $('#view').slideToggle('750')
    return;
  }
  return document.execCommand(ID, false, null);
});
form {
  width: 100%;
  height: fit-content;
  font: 400 16px/1.25 Arial;
}

#view {
  background: gold;
  min-height: 100px;
  font: inherit;
  border-top-left-radius: 6px;
  border-top-right-radius: 6px;
}

#ctrl {
  height: 20px;
}

#edit {
  font: inherit;
  font-family: Consolas;
  border-bottom-left-radius: 6px;
  border-bottom-right-radius: 6px;
}

button {
  display: inline-block;
  font: inherit;
  width: 36px;
  height: 24px;
  line-height: 24px;
  margin: 0 -2px;
  vertical-align: middle;
  cursor: pointer;
  border-radius: 1px;
}

b:hover,
button:hover {
  color: rgba(205, 121, 0, 0.8);
}

#HTML {
  float: right
}

#ctrl button:first-of-type {
  border-top-left-radius: 4px;
  border-bottom-left-radius: 4px;
}

#ctrl button:nth-of-type(6) {
  border-top-right-radius: 4px;
  border-bottom-right-radius: 4px;
}

#ctrl button:last-of-type {
  border-radius: 4px;
}
<link href="//use.fontawesome.com/releases/v5.7.2/css/all.css" rel="stylesheet" crossorigin="anonymous">

<form id='WYSINWYE'>
  <fieldset id='view' class='text' contenteditable='false' style='display:none'>
  </fieldset>
  <fieldset id='ctrl'>
    <button id='bold' class="fas fa-bold"></button>
    <button id='italic' class="fas fa-italic"></button>
    <button id='underline' class="fas fa-underline"></button>
    <b>|</b>
    <button id='justifyLeft' class="fas fa-align-left"></button>
    <button id='justifyCenter' class="fas fa-align-center"></button>
    <button id='justifyRight' class="fas fa-align-right"></button>
    <button id='HTML' class="fas fa-code"></button>
  </fieldset>
  <fieldset id='edit' class='text' contenteditable='true'>
  </fieldset>
</form>

<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Community
  • 1
  • 1
zer00ne
  • 41,936
  • 6
  • 41
  • 68