Ik heb een ingewikkeld javascript probleem.
Ik heb een aantal <pre> elementen. In die elementen staan <span> tags, en gewone text nodes.
Het is ongeveer zo:


<pre>Tekst</pre>
<pre><span>In span</span> buiten span <span>in span</span></pre>
<pre>...</pre>


Nu wil ik met javascript een span kunnen invoegen op een plek in de tekst. Je zou misschien zegggen dat je dit met innerHTML heel makkelijk kunt doen. Dat is dus niet zo, want innerHTML geeft de letterlijke html code.
Als voorbeeld neem ik de tweede <pre>
De textContent van de tweede <pre> is: In span buiten span in span
De innerHTML van de tweede <pre> is: <span>In span</span> buiten span <span>in span</span>
Ik wil dus een span invoegen op bijv. de tiende plek in de tekst.
Je kunt het zien als een soort cursor die je ergens in de tekst neerzet. De bestaande span elementen mogen niet worden beïnvloed hierdoor. Hoe doe ik dit? Ik heb echt al van alles geprobeerd.
Kijk eens naar document.createElement()
document.createElement() gaat je niet echt veel helpen...

Met document.createElement() kun je elementen aanmaken en die een bepaalde plek in de DOM tree gegeven, bijv. als child van (element.appendChild()) of voor een element (element.insertBefore()). In jouw geval wil je een element in een tekst plaatsen, tekst wordt in een DOM tree als een enkele TextNode gezien, daar kun je dus niks in plaatsen.

Je zult dus de Text Node moeten opvragen en die dan splitten in een array. Vervolgens op een bepaalde plek in die array een open tag moeten zetten en het element erna een sluit tag en dan de array omzetten tot een string en weer invoegen als innerHTML van het element.

Bijv. http://jsbin.com/bubew/2/edit

[code lang=js]HTMLElement.prototype.addElementAtPosition = function (position, openTag, split) {
split || (split = ' ');

if (this.childElementCount) {
throw('addElementAtPosition can only be used when the element contains only text');
}

var textPositions = this.innerHTML.split(split);

textPositions.splice(position, 0, openTag);
textPositions.splice(position + 2, 0, '</' + openTag.substr(1));

this.innerHTML = textPositions.join(split);
};[/code]
Ik ben ook even bezig geweest :-)

Je moet als eerste niet de innerHTML uitlezen maar een array van childNodes die in je <pre> zitten.

Vervolgens kun je insertBefore() gebruiken om een nieuwe Node voor een bestaande node in te voegen.

http://codepen.io/anon/pen/Cpgrq
Nee dat is zo Wouter. dan zou je de tekstblokken nog moeten splitten op de spaties. Maar je hebt wel text-nodes en span-nodes in een array staan.

Toevoeging op 20/07/2014 14:47:51:

#text =>
SPAN => 'hallo'
#text => 'dit is'
SPAN => 'leuk'
#text =>

zo zou je array er uit kunnen zien.
Heel erg bedankt voor jullie hulp, maar het probleem is nog iets ingewikkelder.
Het gaat niet om het onderscheid tussen stukjes tekst gescheiden door spaties.
Als ik deze tekst heb:

Ze hebben weer regen voorspeld voor morgen

En ik wil op de zesde 'plek' een span invoegen, dan moet je dat zien als:
Ze heb|ben weer regen voorspeld voor morgen

En dus niet:
Ze hebben weer regen voorspeld | voor morgen

Bij dit invoegen van de span, mogen niet de bestaande elementen die eventueel in de tekst staan beschadigd worden.
Ik deed eerst dit:


function insertAt(obj, pos, elemToInsert) {
	
	var nodesBefore = [];
	var nodesAfter = [];
	
	var lengthCounter = 0;
	
	var nodes = obj.childNodes;
	for(var i = 0; i < nodes.length; i++) {
		
		var node = nodes[i];
		
		if(lengthCounter + node.textContent.length <= pos) {
			
			nodesBefore.push(node);
			lengthCounter += node.textContent.length;
		}
		
		if(lengthCounter + node.textContent.length > pos) {
			
			var ntBefore = node.textContent.substring(0, pos - lengthCounter);
			var nBefore = document.createTextNode(ntBefore);
			nodesBefore.push(nBefore);
			
			var ntAfter = node.textContent.substring(pos - lengthCounter, node.textContent.length);
			console.log(ntAfter);
			var nAfter = document.createTextNode(nAfter);
			nodesAfter.push(nAfter);
		}
	}
	
	var nodeSet = [];
	nodeSet.concat(nodesBefore);
	nodeSet.push(elemToInsert);
	nodeSet.concat(nodesAfter);
	
	
	return nodeSet; // Is nu een array van de hele inhoud van het pre element
}


Maar dit werkt niet. Er komen dan steeds stukjes "undefined" in de tekst te staan, maar ik kan niet vinden wat er nou precies undefined is.
Maar hoe weet jouw script waar de span moet komen? is dat een kwestie van karakters tellen? en zijn het alleen span's die in de tekst voorkomen of ook nog andere html elementen?


Toevoeging op 20/07/2014 23:07:03:

Jij wilt dus een span in een span. dat maakt het inderdaad wel veel ingewikkelder omdat dit tot een 'oneindige' diepte kan. Hier zul je dan in ieder geval een recursive function voor moeten maken.
Ja! Wat Wouter heeft is precies wat ik wil. Allemaal bedankt voor jullie voorbeelden en hulp.

Reageren