Replace words with span in contenteditable

6

I want to replace all the words with span, my code is as follows:

let written = '';
document.getElementById('test').addEventListener('keyup', function(e) {
  var palabra = written;
  written += String.fromCharCode(e.which);
  if (e.which === 32) {
    let text = document.getElementById('test').innerHTML;
    console.log(text);
    var wordsWithSpan = text.split(' ').map(function(c) {
      return '<span class="word">' + c + '</span>';
    }).join('');

    document.getElementById('test').innerHTML = wordsWithSpan;
  }

});
.word {
  color: red;
  padding-right: 2px;
}

div {
  margin: 50px;
}
<div contenteditable="true" id="test">hola mundo tierra</div>

At the moment it only works with the first attempt ( press space bar ), since the second attempt I get the text but with span tags in flat text.

What I need is to get in nodes not in text.

    
asked by x-rw 09.07.2018 в 18:38
source

2 answers

3

The problem is that every time you insert a character, you have to check for the presence of spans and remove them, to simply manipulate the text. Here is an example:

let written = '';
document.getElementById('test').addEventListener('keyup', function(e) {
  var palabra = written;
  written += String.fromCharCode(e.which);
  if (e.which === 32) {
    let text = document.getElementById('test');
    let spans = text.getElementsByTagName('span');
    if (spans.length > 0) {
      text = '';
      for (var i = 0; i< spans.length; i++) {
        text += spans[i].innerHTML + ' ';
      }
      text = text.substring(0, text.length - 1);
    } else {
      text = text.innerHTML;
    }
    console.log(text);
    var wordsWithSpan = text.split(' ').map(function(c) {
      return '<span class="word">' + c + '</span>';
    }).join('');

    document.getElementById('test').innerHTML = wordsWithSpan;
  }

});
.word {
  color: red;
  padding-right: 2px;
}

div {
  margin: 50px;
}
<div contenteditable="true" id="test">hola mundo tierra</div>
    
answered by 09.07.2018 / 19:16
source
1

To get the text we use textContent ... What I do is capture the text that is shown inside the div , and then separate it by spaces with a regular expression /[\b\s\n]+/gi , then I reassign the content of div , but this time converted to words with span .

The problem with assigning the content again is that the position of the cursor is lost ... For this you can make a function that changes the cursor.

  

Note: In my example, the cursor does not work completely well, it seems to be teleporting ... At the end of the day, it's just a demonstration.

To add spaces at the end of the word I do <a> </a> . Although I could have added only one space by innerHTML , I recommend using appendChild ... For the same reason, the cursor returns to the beginning, because I am using innerHTML , and also, determine the position when there are several <span> mixed in the HTML structure is a complicated task.

  

To make it notice that it is grouped in span , I put a background of another color in each word.

function asignar_posición(div,posición)
{
	var range = document.createRange()
	var sel = window.getSelection()
	range.setStart(div, posición)
	range.collapse(true)
	sel.removeAllRanges()
	sel.addRange(range)
}
function obtener_posición_final_selección() {
	return document
		.defaultView.getSelection()
		.getRangeAt(0).startOffset
}
document.getElementById('test').addEventListener('keyup', function(e) {
	var test = document.querySelector("#test")
	var texto = document.querySelector("#test").textContent
	var posición = obtener_posición_final_selección()
	test.innerHTML = ""
	texto.split(/[\b\s\n]+/gi).map(
		function(x){
			var span = document.createElement("span")
			var a = document.createElement("a")
			span.className = "word"
			span.style["background-color"] = "#abcd"
			span.innerHTML = x
			a.innerHTML = " \n"
			test.appendChild(span)
			test.appendChild(a)
		}
	)
	try{
		asignar_posición(test,posición)
	}catch(e){}
});
#test{
	background-color:#0123;
	font-size:33px
}
<div contenteditable="true" id="test">hola mundo tierra</div>
    
answered by 09.07.2018 в 22:10