<!doctype html>
<html>
<head>
<title>Textarea versus Div (contenteditable="true") - RJM Programming - January, 2018</title>
<style>
.fill { object-fit: fill; }
.contain { object-fit: contain; }
.cover { object-fit: cover; }
.scale-down { object-fit: scale-down; }
.none { object-fit: none; }

table {
width:100%;
height: calc(100vh - 70px);
}
th, tr, td, tbody {
width:100%;
}
div {
height: calc(100vh - 35px);
background-color: #f0f0f0;
}
textarea {
background-color: #e0f0f0;
}
#myh1 {
height: 50px;
}
#myh3 {
height: 20px;
}
</style>
<script type='text/javascript'>
function porkplaceatcursor() {
placeatcursor('');
setTimeout(porkplaceatcursor,4000);
}

function analyze(stritself, tokpos, proposed) {
//alert(1);
var lasteqs=[], lasteqr=[];
var lastcos=[], lastcor=[];
var lastscos=[], lastscor=[];
var lastets=[], lastetr=[];
var toleft="";
//alert(11);
if (tokpos > 0) toleft=stritself.substring(0,tokpos);
//alert(111);
var toright="";
if (tokpos < stritself.length) toright=stritself.substring(tokpos);
//alert(1111);
var atleft="", atright="";
//alert(11111);
var akpos=tokpos;
//alert(111111);
while (akpos > 0) {
atleft=stritself.substring(eval(-1 + akpos), akpos) + atleft;
if (stritself.substring(eval(-1 + akpos), akpos) == "<") akpos=0;
//alert('L ' + akpos + ' ' + atleft);
akpos--;
}
akpos=tokpos;
while (akpos < stritself.length) {
atright=atright + stritself.substring(akpos, eval(1 + akpos));
if (stritself.substring(akpos, eval(1 + akpos)) == ">") akpos=stritself.length;
//alert('R ' + akpos + ' ' + atright);
akpos++;
}
lasteqs=atleft.split('=');
lasteqr=atright.split('=');
lastcos=atleft.split(':');
lastcor=atright.split(':');
lastscos=atleft.split(';');
lastscor=atright.split(';');
lastets=atleft.split('</');
lastetr=atright.split('</');
if (atleft.indexOf('>') == -1 && atleft.indexOf('<') != -1 && atright.indexOf('<') == -1 && atright.indexOf('>') != -1) {
if (atright.indexOf(' ') != -1) {
//alert('*' + lasteqs[eval(-1 + lasteqs.length)].replace("'","").replace('"','') + '*');
if (atleft.indexOf('<') == 0 && ('~@' + atright).indexOf('~@ ') != -1) {
document.getElementById('description').innerHTML="HTML ... ready for space then new element attribute name=value";
} else if (lasteqs[eval(-1 + lasteqs.length)].replace("'","").replace('"','') == '') {
document.getElementById('description').innerHTML="HTML ... at start of attribute value";
} else if (atleft.indexOf(' ') == -1) {
document.getElementById('description').innerHTML="HTML ... within element start tag " + (atleft + atright.split(' ')[0] + ' ... >').replace(/\</g,'<').replace(/\>/g,'>');
} else {
document.getElementById('description').innerHTML="HTML ... within element attributes";
}
} else {
if (atleft.indexOf('</') == 0) {
document.getElementById('description').innerHTML="HTML ... within end tag definition " + (atleft + atright).replace(/\</g,'<').replace(/\>/g,'>');
} else if (atleft == '<' && atright.substring(0,1) == '/') {
document.getElementById('description').innerHTML="HTML ... at start of end tag definition";
} else if (atleft == '<' && atright.substring(0,1) != '/') {
document.getElementById('description').innerHTML="HTML ... at start of tag definition";
} else {

if (atleft.indexOf('<') == 0 && (atleft + '~@').indexOf(' ~@') != -1) {
document.getElementById('description').innerHTML="HTML ... ready for new element attribute name=value";
} else if (atleft.indexOf('<') == 0 && ('~@' + atright).indexOf('~@ ') != -1) {
document.getElementById('description').innerHTML="HTML ... ready for space then new element attribute name=value";
} else if (atleft.indexOf('<') == 0 && lasteqs[eval(-1 + lasteqs.length)].replace("'","").replace('"','') == '') {
document.getElementById('description').innerHTML="HTML ... at start of attribute value";
} else if (atleft.indexOf('<') == 0 && lasteqr[0] == '') {
document.getElementById('description').innerHTML="HTML ... at end of attribute name";
} else if (atleft.indexOf('<') == 0 && lasteqr.length > 1 && lasteqr[0].length > 0 && lasteqr[0].indexOf(' ') == -1) {
document.getElementById('description').innerHTML="HTML ... within attribute name";
} else if (atleft.indexOf(' ') == -1) {
document.getElementById('description').innerHTML="HTML ... within element tag " + (atleft + atright).replace(/\</g,'<').replace(/\>/g,'>');
} else {
document.getElementById('description').innerHTML="HTML ... within element tag attribute value"; // + (atleft + atright).replace(/\</g,'<').replace(/\>/g,'>');
}


}
}
} else if (atleft.substring(0,6).toLowerCase() == '<style') {

if (atleft.indexOf('<') == 0 && lastcos[eval(-1 + lastcos.length)].replace("'","").replace('"','') == '') {
document.getElementById('description').innerHTML="HTML ... at start of CSS ruleset declaration property";
} else if (atleft.indexOf('<') == 0 && lastcor[0] == '') {
document.getElementById('description').innerHTML="HTML ... at end of CSS ruleset declaration property";
} else if (atleft.indexOf('<') == 0 && lastcor.length > 1 && lastcor[0].length > 0 && lastcor[0].indexOf(' ') == -1) {
document.getElementById('description').innerHTML="HTML ... within CSS ruleset declaration property";
} else if (atleft.indexOf('<') == 0 && lastscos.length > 1 && lastscos[eval(-1 + lastscos.length)].trim() == '') {
document.getElementById('description').innerHTML="HTML ... ready for new CSS ruleset declaration property and value";
} else if (atleft.indexOf('<') == 0 && lastscos.length > 1 && lastscos[eval(-1 + lastscos.length)].replace('}','').trim() == '') {
document.getElementById('description').innerHTML="HTML ... ready for new CSS ruleset";
} else if (atright.indexOf('{') < atright.indexOf('}') && atright.indexOf('{') != -1) {
document.getElementById('description').innerHTML="HTML ... within CSS ruleset selector";
} else {
document.getElementById('description').innerHTML="HTML ... within CSS ruleset declaration value";
}



} else {

if (lastetr.length > 1) {
if (lastetr[1].toLowerCase().substring(0,6) == 'script') {
document.getElementById('description').innerHTML="HTML ... script content";
} else {
if ((' ' + atleft).slice(-1) == '>' && (atright + ' ').substring(0,1) == '<') {
document.getElementById('description').innerHTML="HTML ... whitespace text content";
} else if ((atright + ' ').substring(0,1) == '<') {
document.getElementById('description').innerHTML="HTML ... end of some text content";
} else if (('>' + atleft).slice(-1) == '>') {
document.getElementById('description').innerHTML="HTML ... start of some text content";
} else {
document.getElementById('description').innerHTML="HTML ... text content";
}
}
} else if ((' ' + atleft).slice(-1) == '>' && (atright + ' ').substring(0,1) == '<') {
document.getElementById('description').innerHTML="HTML ... whitespace text content";
} else if ((atright + ' ').substring(0,1) == '<') {
document.getElementById('description').innerHTML="HTML ... end of some text content";
} else if (('>' + atleft).slice(-1) == '>') {
document.getElementById('description').innerHTML="HTML ... start of some text content";
} else {
document.getElementById('description').innerHTML="HTML ... text content";
}

}
//document.getElementById('top').innerHTML=atleft.replace(/\</g,'<').replace(/\>/g,'>') + " ... " + atright.replace(/\</g,'<').replace(/\>/g,'>');
}

function placeatcursor(what) {
var kpos, lwhat;
if (what != '' || 1 == 1) {
lwhat=what.length;
if (what.indexOf('</') != -1) {
lwhat=what.indexOf('</');
}
kpos=wherearewe(document.getElementById('htmlcontent'));
analyze(document.getElementById('htmlcontent').value, kpos, what);
document.getElementById('htmlcontent').value = document.getElementById('htmlcontent').value.replace(document.getElementById('htmlcontent').value.substring(0,kpos),document.getElementById('htmlcontent').value.substring(0,kpos) + what);
setwherearewe(document.getElementById('htmlcontent'), eval(lwhat + kpos));
}
}

function wherearewe(ota) { // thanks to //stackoverflow.com/questions/2897155/get-cursor-position-in-characters-within-a-text-input-field

// Initialize

var ipos = 0;

if (document.selection) { // IE Support

// Set focus on the element

ota.focus();

// To get cursor position, get empty selection range

var oselis = document.selection.createRange();

// Move selection start to 0 position

oselis.moveStart('character', -ota.value.length);

// The caret position is selection length

ipos = oselis.text.length;

} else if (ota.selectionStart || ota.selectionStart == '0') { // Firefox support

ipos = ota.selectionStart;

}

// Return results

//alert(ipos);

return ipos;

}


function setwherearewe(ota, wota) { // thanks to //stackoverflow.com/questions/2897155/get-cursor-position-in-characters-within-a-text-input-field

if (ota.setSelectionRange) {

ota.setSelectionRange(wota, wota);

} else if (ota.createTextRange) {

var range = ota.createTextRange();

range.collapse(true);

range.moveEnd('character', wota);

range.moveStart('character', wota);

range.select();

}

// Return cursor position

ota.focus();

//document.title=ota.value.length + ' vs ' + wota;

return wota;

}

function fixi(owhat) {
if (owhat.id == 'irows') {
document.getElementById('htmlcontent').rows=owhat.value;
} else if (owhat.id == 'icols') {
document.getElementById('htmlcontent').cols=owhat.value;
}
}
</script>
</head>
<body style='background-color:yellow;' onload="setTimeout(porkplaceatcursor,5000);">
<span id=top></span>
<h1 id=myh1>Textarea versus Div (contenteditable="true")</h1>
<h3 id=myh3>RJM Programming - January, 2018</h3>
<table border=20>
<tbody>
<tr style='background-color:cyan;'>
<th>div contenteditable="true"</th>
<th>textarea cols=<input style='width:50px;' onblur=fixi(this); onchange=fixi(this); id=icols value=80 type=number min=1 step=1></input> rows=<input style='width:50px;' onblur=fixi(this); onchange=fixi(this); id=irows value=58 type=number min=1 step=1></input></th>
<tr>
<tr style='background-color:pink;'>
<th>Display</th>
<th id=description>HTML</th>
<tr>
<td style="vertical-align:top;"><div class=cover id=dce contenteditable="true" onchange="document.getElementById('htmlcontent').value=this.innerHTML;" onblur="document.getElementById('htmlcontent').value=this.innerHTML;" style="border:1px solid black;">The Rain in Spain falls mainly on the plain.<br><h2>The Rain in Spain falls mainly on the plain.</h2><br><h3>The <font color=blue>Rain</font> in <font color=orange>Spain</font> falls mainly on the <font color=brown>plain</font>.</h3></div></td>
<td><textarea class=cover id=htmlcontent onchange="document.getElementById('dce').innerHTML=this.value; " onblur="document.getElementById('dce').innerHTML=this.value; " cols=80 rows=58>The Rain in Spain falls mainly on the plain.<br><h2>The Rain in Spain falls mainly on the plain.</h2><br><h3>The <font color=blue>Rain</font> in <font color=orange>Spain</font> falls mainly on the <font color=brown>plain</font>.</h3></textarea>
<input type=text style="position:absolute;top:-30px;left:0px;width:0px;" value=""></input>
</td>
</tr>
</tbody>
</table>
</body>
</html>