Dynamically created editable iframe not working in Firefox - javascript

I have an iframe that is generated in JavaScript with createElement() when a function is fired, which becomes a text editor. It works just fine in Chrome, Safari and Edge, but in Firefox, the innerHTML text, "Text Layer", will briefly flash within the iframe and then it disappears and the iframe doesn't seem to be editable. Upon inspection, the iframe's body tag is empty. If I set contentEditable to true on the iframe's body tag in the inspector it seems to work properly, but when I try to set this in my JS function, nothing happens in Firefox.
I'm guessing this has something to do with the iframe being created in JavaScript, since setting the designMode of an iframe already in the DOM to 'On' with JS seems to work properly. Wondering if there's a way to get this to work in Firefox, maybe another method of creating the iframe? I have seen some similar problems that were solved by putting some javascript in the iframe's src, as in the comments here, but that apparently causes problems in other browsers. Creating the iframe in JS is preferable to appending it from somewhere.
function text() {
var rtf = document.createElement("iframe");
rtf.name = "richTextField";
rtf.id = "richTextField";
rtf.className = "texteditor";
var dwrap = document.createElement("div");
dwrap.appendChild(rtf);
var tframe = document.getElementById("richTextField");
tframe.contentWindow.document.designMode = 'On';
tframe.contentWindow.document.body.innerHTML = "Text Layer";
tframe.contentWindow.document.getElementsByTagName('body')[0].focus();
tframe.onload = autosize();
};

Found this 15 year old bug report and was able to get it work by setting the contentWindow properties inside of a setTimeout function.
function text() {
var rtf = document.createElement("iframe");
rtf.name = "richTextField";
rtf.id = "richTextField";
rtf.className = "texteditor";
var dwrap = document.createElement("div");
dwrap.appendChild(rtf);
var tframe = document.getElementById("richTextField");
setTimeout(function(){
tframe.contentWindow.document.designMode = 'On';
tframe.contentWindow.document.body.innerHTML = "Text Layer";
tframe.contentWindow.document.getElementsByTagName('body')[0].focus();
}, 0);
tframe.onload = autosize();
};

Related

Place cursor at the end of text in an iframe body element with JavaScript

I'll start by apologising as this may seem like or actually be a duplicate, but I've tried every solution I've encountered and none seem to be working for me.
In my HTML I have an iframe referencing another HTML document. With JavaScript, at the press of a list of buttons I insert text into the body of that iframe. I also use JavaScript to maintain focus on the iframe body. The problem is that nothing appears to work for me to get the cursor to move to the end of the text each time I press those buttons, it always moves to the beginning.
One of the solutions I've tried was to add this code to the function that handles my button presses:
iFrameBody.focus();
var content = iFrameBody.innerHTML;
iFrameBody.innerHTML = content;
so the function looks like this:
function typeIn(buttonId) {
var iFrameBody = document.getElementById("iFrame").contentWindow.document.body;
iFrameBody.innerHTML += buttonId;
iFrameBody.focus();
var content = iFrameBody.innerHTML;
iFrameBody.innerHTML = content;
}
Something else I tried was, in the HTML file referenced by my iframe I did:
<body onfocus="this.innerHTML = this.innerHTML;"></body>
I tried several other more complicated solutions that frankly I didn't even quite understand to be honest, all to no avail. Any help would be much appreciated.
I figured it out. The issue was that I was using a body element, writing to it's innerHTML and trying to set focus on the body. By simply using a textarea inside my iFrame instead it became very simple and it only required the simplest code.
This to set focus when the page loads:
window.onload = function () {
var iFrameTextArea = document.getElementById("iFrame").contentWindow.document.getElementById("iFrameTextArea");
iFrameTextArea.focus();
}
And then this to set the button to write to the textarea while maintaining focus:
function typeIn(buttonId) {
var iFrameTextArea = document.getElementById("iFrame").contentWindow.document.getElementById("iFrameInput");
iFrameTextArea.focus();
iFrameTextArea.value += buttonId;
}
Super easy!!
Instead of again using textarea in iframe, u can also solve this by using the following code.
var iframeElement = document.getElementById("iFrame").contentWindow.document.body;
iframeElement.focus();
var len = iframeElement.length ;
iframeElement.setSelectionRange(len, len);

iFrame Text Not showing up on Firefox but works on Chrome (document.body.innerHTML)

Fellow coders, I am running into this issue, I've a iframe with ID="graph", I am trying to output this html while page loads, but for some reason it's not working on firefox but works great on chrome.
<script language="javascript">
var text = "We are creating your Memory Performance Graph, Please hold.";
document.getElementById('graph').document.body.innerHTML = text;
</script>
Any recommendations on where it went wrong?
The DOM interface for an HTMLIFrameElement object specifies 'contentDocument' as the name of the IFrame document, not "document" by itself.
I was able to get a version of your message to appear in an iframe using
var text = "We are creating your Memory Performance Graph, Please hold.";
var iFrameObj = document.getElementById('graph');
var docObj = iFrameObj.contentDocument || iFrameObj.document;
docObj.body.innerHTML = text;
The only reason to include " || iFrameObj.document" was in case Chrome does not support the standard attribute name (untestested).
In testing I placed the code in a window onload event handler to avoid potential timing issues with accessing the iframe element before finalisation.

Javascript Print iframe contents only

This is my code
<script>
var body = "dddddd"
var script = "<script>window.print();</scr'+'ipt>";
var newWin = $("#printf")[0].contentWindow.document;
newWin.open();
newWin.close();
$("body",newWin).append(body+script);
</script>
<iframe id="printf"></iframe>
This works but it prints the parent page, how do I get it to print just the iframe?
I would not expect that to work
try instead
window.frames["printf"].focus();
window.frames["printf"].print();
and use
<iframe id="printf" name="printf"></iframe>
Alternatively try good old
var newWin = window.frames["printf"];
newWin.document.write('<body onload="window.print()">dddd</body>');
newWin.document.close();
if jQuery cannot hack it
Live Demo
document.getElementById("printf").contentWindow.print();
Same origin policy applies.
Easy way (tested on ie7+, firefox, Chrome,safari ) would be this
//id is the id of the iframe
function printFrame(id) {
var frm = document.getElementById(id).contentWindow;
frm.focus();// focus on contentWindow is needed on some ie versions
frm.print();
return false;
}
an alternate option, which may or may not be suitable, but cleaner if it is:
If you always want to just print the iframe from the page, you can have a separate "#media print{}" stylesheet that hides everything besides the iframe. Then you can just print the page normally.
You can use this command:
document.getElementById('iframeid').contentWindow.print();
This command basically is the same as window.print(), but as the window we would like to print is in the iframe, we first need to obtain an instance of that window as a javascript object.
So, in reference to that iframe, we first obtain the iframe by using it's id, and then it's contentWindow returns a window(DOM) object. So, we are able to directly use the window.print() function on this object.
I had issues with all of the above solutions in IE8, have found a decent workaround that is tested in IE 8+9, Chrome, Safari and Firefox. For my situation i needed to print a report that was generated dynamically:
// create content of iframe
var content = '<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">'+
'<head><link href="/css/print.css" media="all" rel="stylesheet" type="text/css"></head>'+
'<body>(rest of body content)'+
'<script type="text/javascript">function printPage() { window.focus(); window.print();return; }</script>'+
'</body></html>';
Note the printPage() javascript method before the body close tag.
Next create the iframe and append it to the parent body so its contentWindow is available:
var newIframe = document.createElement('iframe');
newIframe.width = '0';
newIframe.height = '0';
newIframe.src = 'about:blank';
document.body.appendChild(newIframe);
Next set the content:
newIframe.contentWindow.contents = content;
newIframe.src = 'javascript:window["contents"]';
Here we are setting the dynamic content variable to the iframe's window object then invoking it via the javascript: scheme.
Finally to print; focus the iframe and call the javascript printPage() function within the iframe content:
newIframe.focus();
setTimeout(function() {
newIframe.contentWindow.printPage();
}, 200);
return;
The setTimeout is not necessarily needed, however if you're loading large amounts of content i found Chrome occasionally failed to print without it so this step is recommended. The alternative is to wrap 'newIframe.contentWindow.printPage();' in a try catch and place the setTimeout wrapped version in the catch block.
Hope this helps someone as i spent a lot of time finding a solution that worked well across multiple browsers. Thanks to SpareCycles.
EDIT:
Instead of using setTimeout to call the printPage function use the following:
newIframe.onload = function() {
newIframe.contentWindow.printPage();
}
At this time, there is no need for the script tag inside the iframe. This works for me (tested in Chrome, Firefox, IE11 and node-webkit 0.12):
<script>
window.onload = function() {
var body = 'dddddd';
var newWin = document.getElementById('printf').contentWindow;
newWin.document.write(body);
newWin.document.close(); //important!
newWin.focus(); //IE fix
newWin.print();
}
</script>
<iframe id="printf"></iframe>
Thanks to all answers, save my day.
If you are setting the contents of IFrame using javascript document.write() then you must close the document by newWin.document.close(); otherwise the following code will not work and print will print the contents of whole page instead of only the IFrame contents.
var frm = document.getElementById(id).contentWindow;
frm.focus();// focus on contentWindow is needed on some ie versions
frm.print();
I was stuck trying to implement this in typescript, all of the above would not work. I had to first cast the element in order for typescript to have access to the contentWindow.
let iframe = document.getElementById('frameId') as HTMLIFrameElement;
iframe.contentWindow.print();
Use this code for IE9 and above:
window.frames["printf"].focus();
window.frames["printf"].print();
For IE8:
window.frames[0].focus();
window.frames[0].print();
I am wondering what's your purpose of doing the iframe print.
I met a similar problem a moment ago: use chrome's print preview to generate a PDF file of a iframe.
Finally I solved my problem with a trick:
$('#print').click(function() {
$('#noniframe').hide(); // hide other elements
window.print(); // now, only the iframe left
$('#noniframe').show(); // show other elements again.
});

Set focus on iframe in Chrome

I have an iframe (id: 'chat') with designMode='on' in Chrome.
On Enter keypress event I call the function send(), which takes the iframe contents and writes it to a socket. My problem is that when clearing the iframe, I lose focus.
How to do I set the focus so I can continue to type text in the iframe?
function send(){
var $iframe = $('#chat');
var text = $iframe.contents().text() + "\n";
socket.send(text);
// When this is done, the focus is lost
// If commented, the focus will not be lost
$iframe.contents().find('body').empty();
// My different failed attempts to regain the focus
//$iframe.focus();
//$iframe.contents().focus();
//$iframe.contents().find('body').focus();
//$iframe.contents().find('body').parent().focus();
//$iframe[0].contentWindow.focus();
// I've also tried all the above with timers
//setTimeout( function(){ $('#chat').contents().focus(); }, 100);
}
I've tried many of the solutions on other questions, but none seems to work.
The trick is to first set focus on the body and then create a Range.
var win = iframe.contentWindow;
var range = win.document.createRange();
range.setStart(win.document.body, 0);
range.setEnd(win.document.body, 0);
win.document.body.focus();
win.getSelection().addRange(range);
This question has been answered here
Basically, if you are not refreshing the iframe you could use:
$iframe[0].contentWindow.focus();
Note that I'm grabbing the underlying iframe DOM object.
I have tried below solution it works in all browser (IE/Chrome/Firefox)
Context: I want to focus the iframe all the time.
function IFocus() {
var iframe = $("#iframeId")[0];
iframe.contentWindow.focus();
};
window.setInterval(IFocus, 300);
Hope it helps, if any one in need...
I tested this solution with Chrome. I originally posted it in Setting focus to iframe contents.
Here is code to create an iframe using jQuery, append it to the document, poll it until it is loaded, then focus it. This is better than setting an arbitrary timeout which may or may not work depending on how long the iframe takes to load.
var jqueryIframe = $('<iframe>', {
src: "http://example.com"
}),
focusWhenReady = function(){
var iframe = jqueryIframe[0],
doc = iframe.contentDocument || iframe.contentWindow.document;
if (doc.readyState == "complete") {
iframe.contentWindow.focus();
} else {
setTimeout(focusWhenReady, 100)
}
}
$(document).append(jqueryIframe);
setTimeout(focusWhenReady, 10);
The code for detecting when the iframe is loaded was adapted from Biranchi's answer to How to check if iframe is loaded or it has a content?

IE 8 iframe border

There is a border showing on an iframe and I can't get rid of it.
IE 6 and 7 work as intended with a little JavaScript:
function test(){
var iframe = document.getElementById('frame2');
iframe.contentWindow.document.body.style.backgroundColor = "#a31d1d";
iframe.contentWindow.document.body.style.border = "#a31d1d";
iframe.contentWindow.document.body.style.outlineColor = "#a31d1d";
}
But the border remains visible in IE 8.
Add following attributes to iframe tag:
marginheight="0" marginwidth="0" frameborder="0"
I had the same problem with iframes created dynamically, and it turned out that setting border properties AFTER adding the iframe to the document has NO effect:
The following code shows a 3d border:
var iframe = document.createElement("IFRAME");
iframe.src = "http:www.stackoverflow.com";
//Iframe added BEFORE setting border properties.
document.body.appendChild(iframe);
iframe.frameBorder = "no";
But this actually removes it:
var iframe = document.createElement("IFRAME");
iframe.src = "http:www.stackoverflow.com";
iframe.frameBorder = "no";
//Iframe added AFTER setting border properties.
document.body.appendChild(iframe);
Hope that this would help solve your problem.
I tried loads of variations on this idea and ended up using something along these lines. Thought I'd share it.
<script type="text/javascript">
url = 'http://www.dollypower.com';
title = 'Dolly Power';
width = '660';
height = '430';
document.write('<iframe src='+url+' title='+title+' width='+width+' height='+height+' frameborder=0></iframe>');
</script>
Then I used noscript tags to enter an alternative for non-JS users, i.e:
<noscript><p>Please click here for Dolly Power</p></noscript>
I tested it in IE8 and it's all cool for me and it also validates.
Hope this might help someone out there!
Success!
Try this. It will find any iframe elements and remove their borders in IE and other browsers (though you can just set a style of "border : none;" in non-IE browsers instead of using JavaScript). AND it will work even if used AFTER the iframe is generated and in place in the document (e.g. iframes that are added in plain HTML and not JavaScript)!
This appears to work because IE creates the border, not on the iframe element as you'd expect, but on the CONTENT of the iframe--after the iframe is created in the BOM. ($#&*##!!! IE!!!)
Note: The IE part will only work (of course) if the parent window and iframe are from the SAME origin (same domain, port, protocol etc.). Otherwise the script will get "access denied" errors in the IE error console. If that happens, your only option is to set it before it is generated, as others have noted, or use the non-standard frameBorder="0" attribute. (or just let IE look fugly--my current favorite option ;) )
Took me MANY hours of working to the point of despair to figure this out...
Enjoy. :)
// =========================================================================
// Remove borders on iFrames
if (window.document.getElementsByTagName("iframe"))
{
var iFrameElements = window.document.getElementsByTagName("iframe");
for (var i = 0; i < iFrameElements.length; i++)
{
iFrameElements[i].frameBorder="0"; // For other browsers.
iFrameElements[i].setAttribute("frameBorder", "0"); // For other browsers (just a backup for the above).
iFrameElements[i].contentWindow.document.body.style.border="none"; // For IE.
}
}
Sample HTML to go with the sample JS would be helpful =)
Try using IE8's Developer Tools (press F12 on the page you have problems with) to isolate what styles are being applied to the iframe. You can also play with the styles there, to cut down your iteration time.
Keep in mind that this may be IE not respecting border settings in the css, whereas the traditional setting of the attribute BORDER=0 on the iframe element may work. Worth a test, at least.
Edit: It looks like what does fix the problem is setting frameborder='0' on the iframe element. That worked for me, at least.
If you want your code to validate you could do this with javascript. I found the perfect answer when I had this problem a few months ago here
var iframe = document.createElement("iframe");
iframe.src = "banner_728x90.gif";
iframe.width = "728";
iframe.height = "90";
iframe.frameBorder = "0";
iframe.scrolling = "no";
document.body.appendChild(iframe);
f you want to load another page seamless in the iframe you can do this if you copy and paste this code into the head of your page. I found it on a site with free scripts. The performance is good in most cases
function getDocHeight(doc) {
doc = doc || document;
var body = doc.body, html = doc.documentElement;
var height = Math.max( body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight );
return height;
}
function setIframeHeight(id) {
var ifrm = document.getElementById(id);
var doc = ifrm.contentDocument? ifrm.contentDocument: ifrm.contentWindow.document;
ifrm.style.visibility = 'hidden';
ifrm.style.height = "10px"; // reset to minimal height in case going from longer to shorter doc
ifrm.style.height = getDocHeight( doc ) + 10 + "px";
ifrm.style.visibility = 'visible';
}
You then give your iframe an id and call the script on load. This is how.
var iframe = document.createElement("iframe");
iframe.setAttribute('id', "ifrm1");
iframe.setAttribute('src', 'http://www.hekcmviw.com/'); // change the URL
iframe.setAttribute('width', '100%');
iframe.setAttribute('height', '10');
iframe.setAttribute('frameBorder', '0');
iframe.setAttribute('scrolling', 'no');
iframe.setAttribute('onload' ,"setIframeHeight(this.id)");
document.body.appendChild(iframe);

Categories

Resources