PDA

View Full Version : Cursor position in designMode IFrame



Jas
08-02-2008, 03:35 AM
I am making an RTE with JavaScript, and I was wondering how you go about capturing the curser position in an IFrame that's in design mode. I venture to guess that it's not as easy to get as it is in a textarea, but I have no idea.

The reason I need the cursor position is that 1) I plan to use javascript to insert things into the IFrame, and 2) I need to be able to place the cursor in different places in the IFrame.

Let me know if you need more information.

Jesdisciple
08-02-2008, 09:28 PM
What's an RTE?

You're talking about a WYSIWYG, right? The only thing I know to suggest is that you look through an existing solution, e.g. OpenWYSIWYG (http://www.dynamicdrive.com/dynamicindex16/openwysiwyg/index.htm). Oddly enough, that uses both a textarea and an iframe.

Jas
08-03-2008, 01:40 AM
RTE = Rich Text Editor. Basically a WYSIWYG editor.

Most use both, because you can't submit the information without a form field.

I'll look into it :)

mburt
08-03-2008, 03:55 AM
document.onmousemove = function(e) {
var ev = e || event;
document["title"] = ev["clientX"]+","+ev["clientY"];
};

Jas
08-03-2008, 10:24 PM
Thanks, but I was really talking about the insert point in the iframe, aka the caret. I need to be able to inset text at the insertion point. I still haven't had time to look into the WYSIWYG editor, but I will soon, I hope.

jscheuer1
08-04-2008, 03:15 PM
There is no insert point in an iframe. You need a textarea or a text input on the page in the iframe. Now, I assume you are familiar with accessing elements in the iframe from the parent page (if that's part of the process). This function (I forget were I saw it, it's not mine but it works):


function setCursorPosition(oInput,oStart,oEnd) {
if( oInput.setSelectionRange ) {
oInput.setSelectionRange(oStart,oEnd);
}
else if( oInput.createTextRange ) {
var range = oInput.createTextRange();
range.collapse(true);
range.moveEnd('character',oEnd);
range.moveStart('character',oStart);
range.select();
}
}

will allow you to set the cursor position within an element that can receive text input. It is designed to select a range, but if start and end are the same, it will simply move the cursor to that point. An alternative to getting the element in the iframe from the parent would be to put the above on the page in the iframe and hard code the element into it, then just call the function from the parent with the desired coordinates.

Jas
08-04-2008, 03:59 PM
Thanks, John, but I am really lost. Here is the code that I have so far:



function start_JEMpad(){
//JEMPAD is the id of a textarea
document.getElementById("JEMPAD").style.display = "none";

var pad = document.createElement("IFRAME");
pad.name = pad.id = "JEMp";

if(pad.addEventListener){
pad.addEventListener("load",function(e){this.contentWindow.document.designMode = "on";}, false);
}else if(pad.attachEvent){
pad.attachEvent("load", function(e){this.contentWindow.document.designMode = "on";});
}

document.body.insertBefore(pad, document.getElementById("JEMPAD"));

JEMp.document.designMode = "on";
JEMp.document.open();
JEMp.document.write('<html>\n\t<head>\n\t\t<style type="text/css">\n\t\t\tbody{ font-family:arial; font-size:13px; }\n\t\t</style>');
JEMp.document.write('\n\t</head>\n\t<body>\n\t</body>\n</html>');
//I tried adding JS functions in here too, but they don't seem to work since the IFrame in in design mode
JEMp.document.close();
JEMp.focus();

JEMp.document.body.innerHTML = formattext(document.getElementById("JEMPAD").innerHTML);

try{
JEMp.document.body.attachEvent("onkeyup", update_pad, false); //triggers error in FF unless I use try/catch
}catch(e){
JEMp.addEventListener("keyup", update_pad, false);
}
}

function setCursorPosition(oInput,oStart,oEnd) {
if( oInput.setSelectionRange ) {
oInput.setSelectionRange(oStart,oEnd);
}
else if( oInput.createTextRange ) {
var range = oInput.createTextRange();
range.collapse(true);
range.moveEnd('character',oEnd);
range.moveStart('character',oStart);
range.select();
}
}

function update_pad(){
JEMp.document.body.innerHTML = formattext(JEMp.document.body.innerHTML); //PUSHES CURSOR TO END OF IFRAME

//How do I capture the cursor's previous position and put it back? (obviously the capture would need to be before the previous line)
setCursorPosition(document.getElementById("JEMp"),1,1); // I obviously need to use this, but it's not working
}

function formattext(string){
return string;
}

function decompiletext(string){
return string;
}

function addtag(tag1, tag2){
//How do I do this?
}


Two questions on the above: 1) how do I capture the caret position and put it back after I format the IFrame, 2) how do I insert text at the insertion point? (i.e. the user highlights "Hello" and clicks bold, so the text becomes "Hello". This would then be processed by the formattext() function and become XHTML-- I already have that part done.)

Any help/suggestions would be amazing. I know it's asking a lot.

jscheuer1
08-05-2008, 09:13 AM
I don't think this will work:


pad.attachEvent("load", function(e){this.contentWindow.document.designMode = "on";});

because this refers to the top window in an attachEvent function. The use of (e) for that function is meaningless, as it isn't used in the function and because when a browser (usually only IE) uses attachEvent, it doesn't pass events that way, it uses the window.event model. With addEventListener the (e) will represent the event, but you still aren't using it in that function, so don't need it. The good news is that this will refer to the pad element in that case (FF, most others except IE). Unfortunately, document.designMode does not (as far as I can tell) work in anything other than IE, so I'm surprised that any of the rest of the code works at all in any browsers. See:

http://www.mozilla.org/editor/ie2midas.html

I will glance over the rest of the code, but as I've just pointed out, any of it that depends upon designMode in the iframe will probably fail with that initialization setup. However, later where you do:


JEMp.document.designMode = "on";

That should do the trick in IE (only). But since I see nowhere in your code that the function start_JEMpad() is ever run, once again, I don't see anything happening. Perhaps it is run, you just haven't shown that part, or something other than document.designMode is at work here, either could explain why you may have some positive results in one or more browsers.

If you do have this working at all, give me a link to the live page.

In any case, it would be best to get rid of any parts of the code that aren't really doing anything, it makes it so much easier to debug the parts that are.

Jas
08-05-2008, 06:16 PM
I am very sorry! I should have added the HTML page:


<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
<meta http-equiv="Content-Style-Type" content="text/css" />
<title>JEMpad Version 1.0 TEST</title>

<!-- This is the javascript shown in my last post //-->
<script type="text/javascript" src="./jempad.js"></script>

</head>
<body onload="start_JEMpad()">

<button onclick="addtag('b','b')">B</button>
<textarea id="JEMPAD">Some initial text that's going to be bold</textarea>

</body>
</html>

I see your points, John, and I will try to clean that up; but, the script actually does work in both IE and FF so far. I haven't tried any other browsers yet, because my client will really only need those two for now. There is no live page, but you should be able to get it working from the code in this and the last post, unless I made some typos.

Thank you so much for sticking with this thread. I know this isn't the easiest question in the world, so I really do appreciate the help.

jscheuer1
08-06-2008, 04:52 AM
The setCursorPosition doesn't appear to work with the iframe in FF. It does work in IE with the iframe. As I mentioned before though, it is intended for textarea or text input.

Jas
08-06-2008, 03:38 PM
So, are there any alternatives, then? Or is it impossible to do?

jscheuer1
08-06-2008, 04:09 PM
I already mentioned:

http://www.mozilla.org/editor/ie2midas.html

And, if I recall correctly, someone else in this thread already suggested the use of a textarea on the iframe page.

I did play around a bit with your code, I noticed that it outputted:


Some initial text that's going to be bold

to the iframe. And that in IE nothing was required to get the insertion point to automatically move to the end of the text inserted onload, but that in FF nothing (of the code used in your example) seemed able to do so.

Anyways, if all you are trying to output is text, a textarea would be ideal.

Just exactly what are you trying to do? DD's rich text editor is very good for what it does.

Jas
08-06-2008, 07:47 PM
Ah, I see where the confusion is, now. It's a little complicated, but I will do my best to explain.

The IFrame takes in custom PHPBB tags and formats them in real time to XHTML. While it does this, it also simultaniously captures the PHPBB portion of the code to a textarea (I will do this part on my own later, as I already know what to do for it-- or so I think). The PHPBB system that I am using is highly customized-- I created it myself specifically for my client-- so a normal editor won't work the way I want it to.

The reason the [b] tags show up is because I took out the formattext() function and simply returned the string. The functions is very long and not really relevant to the problem I am facing. Suffice it to say that it changes the tags into valid XHTML.

The trouble is that, when the IFrame's body's innerHTML is chaged, the curser moves to the end (in IE) or the beginning (in FF) rather than staying put. I understand why that is, but I don't know how to fix it. I also need to know how to insert PHPBB style tags into the editor when a user clicks a button.

I am starting to doubt the possibility of creating such a JavaScript. The IFrame in designMode seems like it lacks some of the necessary features that I would need.

Thanks, and let me know if that makes sense.

marlonbtx
08-07-2008, 07:18 PM
hi, i already finish my Rich Text Editor, but now i'm adding smilers, but also need to store the cursor position... i'll keep searching all about range objects etc

jscheuer1
08-07-2008, 07:52 PM
I recently responded to another post that is somewhat related:

http://www.dynamicdrive.com/forums/showthread.php?t=35220

There I show a way, at least with textarea, to store the cursor position (actually a position in the textarea's value's length that you want to reference later). If it isn't completely clear from that code, what you need to do is find the spot where the cursor is. This generally can be calculated if you know where it is in relation to the text already in the textarea, armed with that information, you can calculate the length of the value of the textarea up to that point.

Jas
08-12-2008, 01:53 AM
So I take it that what I am looking to accomplish is impossible with JavaScript?

Chippo
09-23-2008, 08:19 PM
it can be done as most WYSIWYG's can do it, FCKEditor, tinyMCE and openwysiwyg but trying to look through there codes for answers is a pain in the rear end, I am also looking for the answer for to this question, when/if I figure it out I will post it here

Chippo
09-24-2008, 07:01 PM
I found the answer, all along it was sat in a book on my shelf, o well use something like

insertSmilie: function(editorid,code){
this.getEditor(editorid).contentWindow.focus();
var emot = this.getEmot(code);
var selection = null, range = null;
var iframeWindow = document.getElementById('wysiwyg_'+editorid).contentWindow;
var iframeDocument = iframeWindow.document;
if(typeof iframeWindow.getSelection != 'undefined'){
selection = iframeWindow.getSelection();
if(typeof selection.getRangeAt != 'undefined')
range = selection.getRangeAt(0);
else if(typeof selection.baseNode != 'undefined'){
range = iframeDocument.createRange();
range.setStart(selection.baseNode,selection.baseOffset);
range.setEnd(selection.extentNode,selection.extentOffset);
if(range.collapsed){
range.setStart(selection.extentNode,selection.extentOffset);
range.setEnd(selection.baseNode,selection.baseOffset);
}
}
var rangecopy = range.cloneRange();
var newimg = iframeDocument.createElement('img');
newimg.alt = emot[1];
newimg.src = emot[2];

rangecopy.collapse(true);
range.deleteContents();
rangecopy.insertNode(newimg);
//selection.collapse(newimg,newimg.length);
} else if(typeof iframeDocument.selection != 'undefined'){
selection = iframeDocument.selection;
range = selection.createRange();
range.pasteHTML('<img src="'+emot[2]+'" alt="'+emot[1]+'" />');
} else {
return false;
}
iframeWindow.focus();
return true;
},
but unfortunately in my IE7 it seems to add the emot to the main window rather than the iframe, any ideas on how to fix that?

samindaw
05-08-2009, 08:37 PM
you may find the solution for this in http://samindaw.wordpress.com/2009/05/08/how-to-get-the-caret-position-cursor-position-of-a-iframe-which-has-designmode-on-firefox/