After analyzing all the parameters and rules put forth in the initial query, it appears there are a number of potential challenges associated with making this function properly.
The primary concern arises from utilizing the contentEditable attribute as the method for editing HTML. Other solutions and examples suggest using elements like activeElement and selectionStart. While these alternatives seem viable, complications may arise when dealing with mixed content, including HTML that could modify the active element under certain circumstances. Initially considering the use of innerText or innerHTML, it became apparent that they too posed significant issues.
In the provided code snippet, using innerText effectively separates each line but fails to capture any embedded HTML code within the main element. On the other hand, utilizing innerHTML retrieves the HTML code successfully. However, due to the behavior of contentEditable, lines get fragmented by a mere <div> tag, which might also be nested inside the element, leading to conflicts.
Alternative Approach
While I am unsure about any restrictions on what can be implemented with the existing code, my suggestion would be to ditch the contentEditable attribute and instead load the element's contents into a <textarea> for editing. By incorporating the technique from 0stone0, you should be able to achieve the desired outcome.
The example below demonstrates how clicking on an element loads its contents into a <textarea>, thereby replacing the original content. Upon hitting the enter key within the <textarea>, it displays the line number and text from the preceding line. Furthermore, upon clicking outside the <textarea>, the script retrieves the new code and inserts it back into the parent element.
document.querySelector("#sampleeditor").addEventListener("click", function() {
_EditEl(this);
this.removeEventListener('click', arguments.callee);
});
function _EditEl(pEl) {
let curContent = pEl.innerHTML;
// Embed current content into textarea
pEl.innerHTML = `<textarea id="tmpEdit" style="width: 100%; height: 4em;">${curContent}</textarea>`;
document.querySelector("#tmpEdit").focus();//
document.querySelector("#tmpEdit").addEventListener("keyup", function(e) {
if(e.keyCode == 13) {
let start = document.activeElement.selectionStart;
let line = document.activeElement.value.substr(0, document.activeElement.selectionStart).split("\n").length - 2;
console.log(`Pressed enter on line ${line + 1}:`);
console.log(document.activeElement.value.split("\n")[line]);
}
});
document.querySelector("#tmpEdit").addEventListener("blur", function(e) {
let parentEl = this.parentElement;
parentEl.innerHTML = this.value;
parentEl.addEventListener("click", function() {
_EditEl(this);
this.removeEventListener('click', arguments.callee);
});
});
}
<p>Lorem Ipsum is simply dummy text of the printing and typesetting industry.</p>
<div id="sampleeditor">Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of <b><i>classical Latin literature</i></b> from 45 BC, making it over <span>2000 years old</span>.</div>
<p>The standard chunk of Lorem Ipsum used since the 1500s is reproduced below for those interested.</p>
<p>"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."</p>