View Full Version : designMode -- Some Questions

07-14-2005, 04:35 PM
I am going to be using design mode for my Javascript text editor as it seems to be qite well supported these days (safari/mozilla/ie), but tere are a few problems with it that i need help with. The biggest one is the shortcuts that ie adds, (e.g. ctrl+b for bold, ctrl+i for italic) I am going to be highlighting the code with my own functions and so do not really want them to have too much control over the formatting (I know they can if they wanted to but it is their loss in the end) so it would be nice to be able to disable some of the shortcuts (not the ctrl+c/ctrl+v/ctrl+x ones). The enter key is another problem, for each line they type I want to add a new <li> element (it will be in an <ol>, used for line numbers) and do not like the idea of the browser insert a <p>&nbsb</p>, as I will deal with it myself. Does anyone know if it is possible to over-ride these things?

07-15-2005, 09:28 AM
You'd need an event handler on the designMode document to intercept keydown events and filter out ctrl-B, ctrl-I, etc. The event properties of interest are: keyCode, ctrlKey, preventDefault() (for W3C-compliant), returnValue (for IE).

07-16-2005, 11:29 AM
I have managed to do this with a normal document (I attached it to the body). However designMode can only be added to iframes and that is what I am having trouble with. Can anyone tell me how I can generate on the fly an iframe and attach to its body onkeydown(/press) event?
Why cant the darn w3c do something useful with their time apart from removing and depreciating elements, like make a proper way to have formatted outputs in a textarea.

07-16-2005, 03:38 PM
RTE (designMode) is actually a bit buggy in the current Firefox build, though they are some workarounds (and most of the bugginess is fixed in the Firefox 1.1 alpha builds).


var iframe = document.createElement('iframe');
iframe.onload = function() {
editorDoc = iframe.contentDocument || iframe.contentWindow.document;
//Fx workaround: delay modifying editorDoc.body right after iframe onload event
setTimeout(function() {
editorDoc.body.innerHTML = initial_text;
editorDoc.designMode = 'on';
}, 0);

editorDoc.onkeydown = editorDoc_onkeydown; //where editorDoc_onkeydown is the keydown event handler you defined earlier

iframe = null; //IE mem leak fix
div.appendChild(iframe); //where div is the element you want to add the iframe to

07-16-2005, 05:06 PM
I came up with something like that, it works in firefox but not in IE. First, designMode does not switch itself On, I think for ie you need to do something like:
document.getElementByTagName('iframe')[0].contentWindow.document.designMode = 'On'
I also added some content, which works fine in firefox but nothing happens in IE, I think this is because it is an empty iframe, there is no body. Can anyone help me?

07-18-2005, 01:00 PM
This works:

window.onload = function() {
var rteElt = document.createElement('iframe');
rteElt.id = 'rte';
rteElt.onload = initRTE;
rteElt.onloadTimeout = setTimeout(initRTE, 50);

function initRTE() {
var rteElt = document.getElementById('rte');
rteElt.onload = null;
var rte = rteElt.contentWindow.document;
rte.designMode = 'on';
setTimeout(function() {
rte.body.innerHTML = 'abc';
rte.designMode = 'on';
}, 0);

And replace the window.onload thing with something more robust (like using window.addEventListener and window.attachEvent).

07-18-2005, 03:00 PM
Thank you very much, but can you help me add a way to read the contents of the iframe? I tried: document.getElementById('rte').contentWindow.document.body.innerHTML but IE gives me an error, and I have also had problems implementing an onkeydown/press handler for the iframe.

07-18-2005, 03:41 PM
When/where did you try that |document.getElementById('rte').contentWindow.document.body.innerHTML|?

The onkeydown event should be something like this:

function rteOnkeydown(evt) {
evt = evt || window.event;
if (evt.keyCode == <lowercase ascii code for whatever letter you want> && evt.ctrlKey) {
return false;

07-18-2005, 04:39 PM
I am having trouble attaching the onkeydown event to the iframe (I am not sure where to e.g. body/main contentWindow etc).

07-19-2005, 02:09 PM
Here you go:

function RTEonload() {
//dynamically create RTE iframe
var rteElt = document.createElement('iframe');
rteElt.id = 'rte';
//IE6 bug?: setting iframe onload doesn't work, so use attachEvent
if (rteElt.attachEvent)
rteElt.attachEvent('onload', RTEinit);
rteElt.onload = RTEinit;
//Gecko 1.7 bug: see RTEonunload
if (window.addEventListener)
window.addEventListener('unload', RTEonunload, false);
//add iframe to document
document.body.insertBefore(rteElt, document.body.firstChild);

//add RTEonload to window onload event for browsers that support RTE
if (document.designMode) {
if (window.addEventListener)
window.addEventListener('load', RTEonload, false);
else if (window.attachEvent)
window.attachEvent('onload', RTEonload);

function RTEinit() {
//IE6 bug?: even if the onload event handlers are removed, toggling on designMode calls those
// event handlers - none of the following will prevent RTEinit from being called twice:
// rteElt.onload = null;
// rteElt.detachEvent('onload', rteElt);
// rteElt.setAttribute('onload', null);
// rteElt.contentWindow.onload = null;
// rteElt.contentWindow.detachEvent('onload', rteElt);
//so make sure this function never executes more than once
//(this should get rid of some infinite onload loop problems)
if (RTEinit.hasRun)
RTEinit.hasRun = true;
var rteElt = document.getElementById('rte');
var rteWin = rteElt.contentWindow;
var rte = rteWin.document;
//toggling on designMode will cause iframe to reload, so null the onload event handler
//(as previously mentioned, this doesn't work for IE)
//(this should get rid of some infinite onload loop problems)
rteElt.onload = null;
//IE6 bug?: when enabling designMode for the first time, RTE document is reloaded and all
// changes are discarded, so designMode needs to be enabled before modifying document
rte.designMode = 'on';
//IE6 bug?: when enabling designMode for the first time, 0-timeout delay is necessary
// to access rte.body (doesn't apply here since designMode isn't enabled yet)
//Gecko 1.7 bug: 0-timeout delay is necessary since if designMode is enabled during the
// iframe's onload event, the content of the document is deleted and all changes to the
// iframe's document made in the event handler are discarded, regardless of whether
// designMode is enabled before or after making those changes
//note: 0-timeout delay, i.e. setTimeout(x, 0), means that x is executed after the current
// function
setTimeout(function() {
rte.body.innerHTML = 'abc';
//Gecko 1.7 bug: designMode needs to reset (or set if it's off) to 'on' to fix bug 232791
// so enable designMode after setting innerHTML (as opposed to before setting innerHTML)
//Gecko 1.8 bug: if designMode is currently on, it's necessary to toggle it off first,
// before setting it to 'on' again to fix bug 232791, but this causes an infinite onload
// loop in IE6 if the RTE iframe was not dynamically created
//need browser detect here since these bugs can't be directly detected
if (navigator.userAgent.indexOf('Gecko') != -1) {
rte.designMode = 'off';
rte.designMode = 'on';
//Gecko: onevent properties don't work (e.g. rte.onclick doesn't work)
// so DOM2 events must be used
if (rte.addEventListener) {
//Gecko: default action of key accelerators (i.e. hotkeys) occurs onkeypress
rte.addEventListener('keypress', RTEonkeypress, false);
} else if (rte.attachEvent) {
//IE: default action of key accelerators occurs onkeydown
rte.attachEvent('onkeydown', RTEonkeypress);
//set focus to RTE
}, 0);

function RTEonunload() {
//Gecko 1.7 bug: designMode persists even after leaving the page;
// this shouldn't really affect iframes, but I've seen some strange things, so this is
// one of those "just in case" things
var rte = document.getElementById('rte').contentWindow.document;
rte.designMode = 'off';

function RTEonkeypress(evt) {
evt = evt || window.event;
//note: Gecko doesn't support formatting key accelerators, e.g. ctrl-I, ctrl-B (bug 191190)
if (evt.ctrlKey) {
//IE: keyCode
//Gecko: charCode (uses keyCode for keys that aren't characters, e.g. left arrow,
// and for keydown and keyup events)
var keyCode = evt.keyCode || evt.charCode;
switch (keyCode) {
case 67: //ctrl-c
case 86: //ctrl-v
case 88: //ctrl-x
//ctrl-(anything else)
if (evt.preventDefault)
evt.returnValue = false;

That was quite a bug minefield :p

07-19-2005, 03:03 PM
Thank you ever so much! You are right in that it really is a bug minefield. It should be as simple as setting designmode to 'on' and then adding an onkeydown event handler. I am quite suprised that the W3C has not cleaned this whole area up.

I have had some problems removing the iframes border, normally I would do frameborder="0", but when I tried rteElt.setAttribute('frameborder', 0); it did not seem to do any thing. In the page I have a <ol> list for the line numbers, however does anyone know how I can stop the user from editing any content out of the <ol> tag?

07-19-2005, 05:45 PM
That's a CSS thing. You can do it in the script somewhere:

rteElt.style.border = 'none';

Or in some CSS stylesheet:

#rte {
border: none;

The latter way is probably the best - separation of presentation and logic, and all that :)

If you're removing the border, you probably should also remove the padding: |padding: 0;| in the CSS.

BTW, this RTE feature is a Microsoft extension that Mozilla also happened to implement. W3C had no say in it.


Oh yeah, in IE you'll need to set the frameborder and margin* properties to 0:

rteElt.frameBorder = 0;
rteElt.marginHeight = 0;
rteElt.marginWidth = 0;

That code can go in RTEonload.

Then use CSS to tweak the border and padding to your liking.

07-20-2005, 05:38 PM
Thank you very much. I know that the designMode is not a web standard, but I think that the W3C need to create one for dealing with these kinda of things rather than leaving it to the browser compaines to add.