In the previous article I discussed dynamically creating an iframe to be used as the input area for a rich text control; the focus of this article is to attach event handlers to the iframe.
There are at least two good reasons for capturing events on the iframe. The first is that if you are authoring a rich text control, then you will need to capture some of the iframe events so that the toolbar is appropriately updated when the user clicks in the editing area. For example, if the user clicks in the middle of a bold word, you will want to depress the corresponding icon on the toolbar. The second reason is that the client application of your rich text control may want to attach event handlers to your object; in order to provide this functionality, your control will have to export this functionality.
A working example can be seen here.
This works in newer versions of most browsers. The two exceptions I know of to date are Safari and Konqueror; support of the designMode property for these browsers is expected.
The HTML for this example is slightly modified from Part I. A <textarea> is created on top of the page; as the iframe events fire the contents of this <textarea> will be updated. There is a Clear button to clear the contents of the <textarea>. The iframe is dynamically created and appended to the document with Javascipt, so it is the last element on the page.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head><!-- HEADER CONTENT --></head>
<body>
<h1>Rich Text Editing - iframe events</h1>
<h4>Textarea</h4>
<p>
<textarea id="ta" rows="10" cols="40"></textarea>
<input type="button" id="clear" value="Clear">
</p>
<h4>iframe</h4>
</body>
</html>
The window.onload event handler is modified to attach an event to the Clear button. We also add a function call at the end of the handler to addEvents(), which is the function we will be creating.
window.onload = function(){
// Code from Part I, unchanged
var clear = document.getElementById("clear"); // Attach an event handler
clear.onclick = function(){ // to the textarea control.
document.getElementById("ta").value = "";
}
addEvents(iframe); // Attach events to the iframe
}
It is beyond the scope of this article to discuss event registration in detail, but there are two event models you should use when adding event handlers. There is the DOM Level 2 model created by the W3C and there is the IE model. There is also the DOM Level 0 model, which I will not bother with for this article.
Adding a click event to the iframe for DOM L2 browsers.
function addEvents(iframe){
iframe.contentDocument.addEventListener("click", function(){
alert("click()");
}, false);
}
Adding a click event to the iframe for IE browsers.
function addEvents(iframe){
iframe.contentWindow.document.attachEvent("onclick", function(){
alert("click()")
});
}
Note that in the simple examples above, the event was attached to the iframe's document. The following events can be attached in that manner: mousedown, mouseup, mouseover, mouseout, mousemove, click, keydown, keyup, keypress.
Also note that accessing the event object from within the handler will be trickier with IE; compliant browsers accept the event object as a parameter to the handler while IE uses a global object. Since we are dealing with an iframe, instead of window.event we have to use iframe.contentWindow.document.parentWindow.event.
function addEvents(iframe){
var events = new Array( "mousedown", "mouseup", "mouseout", "mouseover",
"click", "keydown", "keyup", "keypress" );
for(var i = 0; i < events.length; i++){
if(iframe.contentDocument && iframe.contentDocument.addEventListener){
// DOM L2
iframe.contentDocument.addEventListener(events[i], function(oEvent){
var txt = document.getElementById("ta");
txt.value = oEvent.type + "()\n" + txt.value;
}, false);
}else if(iframe.contentWindow && iframe.contentWindow.document &&
iframe.contentWindow.document.attachEvent){
// IE
iframe.contentWindow.document.attachEvent("on" + events[i], function(){
var txt = document.getElementById("ta");
var event = iframe.contentWindow.document.parentWindow.event;
txt.value = event.type + "()\n" + txt.value;
});
}
}
}
The following events remain to be captured:
At this time, I've discovered how to handle all but the change event.
Compliant browsers provide a document.getSelection method while IE provides a document.selection property for obtaining the currently selected text within a document. I will briefly show how to use this property with the mouseup event. A more complete example would be one that starts with the mousedown event and waits for a mouseup event with no mouseout or blur events in between.
function addEvents(iframe){
// Previous handler code here
if(iframe.contentDocument){ // select
// DOM L2
iframe.contentDocument.addEventListener("mouseup", function(oEvent){
var txt = iframe.contentDocument.getSelection();
if(txt.length > 0){
var ctrl = document.getElementById("ta");
ctrl.value = oEvent.type + "( " + txt + " )\n" + ctrl.value;
}
}, false);
}else if(iframe.contentWindow.document.attachEvent){
// IE
iframe.contentWindow.document.attachEvent("onmouseup", function(){
var range = iframe.contentWindow.document.selection.createRange();
var txt = range.text;
if(txt.length > 0){
var ctrl = document.getElementById("ta");
var event = iframe.contentWindow.document.parentWindow.event;
ctrl.value = event.type + "( " + txt + " )\n" + ctrl.value;
}
});
}
}
In compliant browsers, attach the blur and focus events to the iframe's document as before. In IE, attach the blur and focus events to the iframe itself.
function addEvents(iframe){
// Previous handler code here
if(iframe.contentDocument){ // focus, blur
iframe.contentDocument.addEventListener("blur", function(oEvent){
var txt = document.getElementById("ta");
txt.value = oEvent.type + "()\n" + txt.value;
}, false);
iframe.contentDocument.addEventListener("focus", function(oEvent){
var txt = document.getElementById("ta");
txt.value = oEvent.type + "()\n" + txt.value;
}, false);
}else if(iframe.contentWindow.document.attachEvent){
iframe.attachEvent("onblur", function(){
var txt = document.getElementById("ta");
var event = window.event;
txt.value = event.type + "()\n" + txt.value;
});
iframe.attachEvent("onfocus", function(){
var txt = document.getElementById("ta");
var event = window.event;
txt.value = event.type + "()\n" + txt.value;
});
}
}
The next step is to discover how to mimic the change event, if anyone knows how I'd love to hear it.
Comments
thnx a lot
This is truly a very good explanation of event handling with RTEs.
How can i clear all events
How can i clear all events and pointed functions.
Each time you attach a
Thanks
This is a nice article. a advanced article. thanks for writing this type of article
Thanks for this post. It
Thanks for this post. It helped me fix a serious problem where blur events were not being captured for me in IE.
Have you figured out how to handle the change event yet?
and would you be willing to consider an update to test sf3?
thanks
I actually have not sat down
I actually have not sat down and figured out how to do it. I've been semi-working on a series of articles for form processing in PHP; while I can not predict when I might finish them, I think I will attempt to sort out the onchange behavior then.
By sf3 did you mean Firefox 3?
RE: Problem in calling events other than onload
Hopefully you have this figured out by now, but when you use a function as a parameter you don't include the parentheses. What is happening is you are telling Javascript to call the function myfunc() and then use the return value as the event handler. So unless myfunc() returns a reference to a valid event handler function, the code will not work.
Use this:
fullIframe.contentWindow.document.attachEvent("onkeydown", myfunc);
Notice the lack of parens after myfunc.
Problem in calling events other than onload
Thanks for this very informative article.
I need to call keydown event on iframe but whatever eventlistener i attache to the iframe, its calling the function on load of iframe only. My code is:
fullIframe.contentWindow.document.attachEvent("onkeydown",myfunc());
but myfunc() is getting called when my page is loading. Can you help??
Post new comment