I'm trying to do a rich text editor for a web application, and I need to be able to mark some elements in the text as uneditable by the user. The reason for this is they're placeholders for dynamic content (like created date) that I want to have a live preview for.
Take the following Code as an example - there's no toolbar or anything in this one, for light weightness, but the textarea and html are synchronized.
<!-- DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" -->
<html>
<head>
<title>Hi</title>
<script type="text/javascript" src="http://code.jquery.com/jquery-1.4.2.min.js"></script>
<script>
$(function() {
g = {};
g.iFrame = document.createElement("IFRAME");
$("#frameContainer").append(g.iFrame);
g.iDoc = g.iFrame.contentWindow.document;
g.iDoc.designMode = "on";
g.jTextArea = $("#textContainer textarea");
setTimeout(function() {
g.iDoc.body.innerHTML = "<b class=\"notype\">Cannot type here</b>";
$(g.iDoc).trigger("keyup");
$(g.iDoc.body).focus();
}, 0);
$(g.iDoc).keyup(function() {
g.jTextArea.text(g.iDoc.body.innerHTML);
});
g.jTextArea.keyup(function() {
g.iDoc.body.innerHTML = this.innerText;
});
var getSelection = function() {
if (typeof g.iDoc.selection !== "undefined" && g.iDoc.selection.type !== "Text" && g.iDoc.selection.type !== "None") {
g.iDoc.selection.clear();
}
return g.iDoc.selection.createRange();
};
$(g.iDoc).keypress(function(event) {
// If we're in a marked field, disable the operation.
var sel = getSelection();
if ($(sel.parentElement()).hasClass('notype')) {
sel.moveToElementText(sel.parentElement());
sel.collapse();
sel.move("character", -1);
sel.select();
$("#log").append("<div>outside of thing</div>");
}
});
$(testLink).click(function() {
// Try and insert stuff at the front
$(g.iDoc.body).focus();
var sel = getSelection();
sel.moveToElementText(sel.parentElement());
sel.collapse();
sel.move("character", -100);
sel.pasteHTML("Before html?");
$(g.iDoc).trigger("keyup");
$(g.iDoc.body).focus();
});
});
</script>
</head>
<body id="#body">
<div id="container">
<div id="frameContainer">
<h1>
Frame</h1>
</div>
<div id="textContainer">
<h1>
Text</h1>
<textarea rows="10" cols="80"></textarea>
</div>
<a href="#" id="testLink">Test</a>
<div id="log">
</div>
</div>
</body>
</html>
In the keyup binding, I can successfuly detect if I'm inside another element, and move the cursor to the front of the text before inserting it no problem. However, since there is no text before the element marked as 'notype', it gets inserted inside the same element.
This is double bad when the user presses "enter", as a new tag is genrated, and the "notype" tag is duplicated, obviously not required.
I want the behaviour as follows:
* If the user types while the cursor is in the 'notype' tag, the cursor is moved to front and the text goes there
* If the cursor is at the last position inside the 'notype' tag, then the text appears after the tag
* If the user types anywhere else, it's inserted as always.
The link at the bottom tries to manually put the cursor at the front and insert the html. Obviously fails. I know this one can work by doing something like $(g.iDoc.body).prepend("before!"), but this obviously won't work in a real scenario (using keyup).