Setting Focus to an iFrame in IE - javascript

There is a tree menu in my application and on click of the menu items, it loads a url in a iFrame. I like to set the focus in an element of the page loaded in the iFrame.
I'm using this code, and it works perfectly in all the browsers except IE:
var myIFrame = $("#iframeName");
myIFrame.focus();
myIFrame.contents().find('#inputName').focus();
I have tried all different options like using setTimeout, but no chance.
After the page loads, when I hit the tab key, it goes to the second input, which means it's been on the first input, but it doesn't show the cursor!
I am using ExtJS and the ManagedIFrame plugin.
Any help is appreciated.

You need to call the focus() method of the iframe's window object, not the iframe element. I'm no expert in either jQuery or ExtJS, so my example below uses neither.
function focusIframe(iframeEl) {
if (iframeEl.contentWindow) {
iframeEl.contentWindow.focus();
} else if (iframeEl.contentDocument && iframeEl.contentDocument.documentElement) {
// For old versions of Safari
iframeEl.contentDocument.documentElement.focus();
}
}

Is the iFrame visible onload, or shown later? The elements are created in different order which is the basis of the setTimeout approach. Did you try a high value wait time on a set timeout?
Try something like at least a half second to test...IE tends to do things in a different order, so a high timeout may be needed to get it not to fire until render/paint finishes:
$(function(){
setTimeout(function() {
var myIFrame = $("#iframeName");
myIFrame.focus();
myIFrame.contents().find('#inputName').focus();
}, 500);
});

Difficult to troubleshoot without a working example, but you might try hiding and showing the input as well, to force IE to redraw the element.
Something like:
var myIFrame = $("#iframeName");
myIFrame.focus();
myIFrame.contents().find('#inputName').hide();
var x = 1;
myIFrame.contents().find('#inputName').show().focus();
This might jolt IE into displaying the cursor.

I could get IE to focus an input field in an iframe with:
iframe.focus();
var input = iframe...
input.focus();
iframe.contentWindow.document.body.focus();
input.focus();

Related

How can I resize the iframe without page refresh?

I have some swf embedded in iframe but only if the page is refreshed the iframe is resized, then if I select other one then will show as all swf not only the animation the background as well. This is what I am using
if ( 'resizeIframe' === $('#onPlayAction').val() ) {
var ifrEl = $('div.player-container iframe.page-iframe')[0];
$(ifrEl).show();
ifrEl.src = htmlPageBrowserUri;
ifrEl.onload = function() {
ifrEl.width = ifrEl.contentWindow.document.body.scrollWidth;
ifrEl.height = ifrEl.contentWindow.document.body.scrollHeight;
}
}
There are three ways to do this.
You can change the size on every window resize
$(window).on('resize', function (){
ifrEl.width = ... ;
ifrEl.height = ... ;
})
You can use some jQuery plugins like iFrame Resizer
You can use some nifty css tricks. Go search for responsive iframes using css and you will find a ton of good answers.
I hope this all helps you.
I suspect the issue with your code might be thses two lines :
ifrEl.src = htmlPageBrowserUri;
ifrEl.onload = function() {
The problem being that the first line set s the frame address, but second line sets the onload event immediately, probably before the page has loaded ? So when the page does load, the line setting onload event has already run & so doens't get set.
I don't quite understand the text in your question (sorry!) but the code below successfully resizes an iframe - it's run 'onload' in the frame's page:
<body onload="setParent()">
In case it's relevant, the iframe itself has attributes:
<iframe id="neckfinishframe" style="width:100%;overflow-x:hidden" src=".. etc">
In my case I'm only concerned about height. Width is 100%.
In the iFrame page, this code runs from the onload event to amend the iframe height to be whatever the height of the page is, plus a bit. This is intended to avoid showing a set of scroll bars within the iframe.
function setParent() {
// runs onload in iframe page
// in my case I have to run it from the frame page because I need to know the page rendered height in order to set the iframe height
var f;
try {f = parent.getElementById("neckfinishframe")} catch (e) {};
if (f != null) f.style.height=(this.document.body.scrollHeight+30)+"px";
}
Note - I haven't tried this cross- browser but I know it works in IE.

Javascript: Changing "document.body.onresize" does not take hold without "console.log"

I'm writing a website with a canvas in it. The website has a script that runs successfully on every refresh except for a line at the end. When the script ends with:
document.body.onresize = function() {viewport.resizeCanvas()}
"document.body.onresize" is unchanged. (I double-checked in Chrome's javascript console: Entering "document.body.onresize" returns "undefined".)
However, when the script ends with:
document.body.onresize = function() {viewport.resizeCanvas()}
console.log(document.body.onresize)
"document.body.onresize" does change. The function works exactly as it should.
I can't explain why these two functionally identical pieces of code have different results. Can anyone help?
Edit: As far as I can tell, "document.body" is referring to the correct "document.body". When I call console.log(document.body) just before I assign document.body.onresize, the correct HTML is printed.
Edit 2: A solution (sort of)
When I substituted "window" for "document" the viewport's "resizeCanvas" function was called without fail every time I resized the window.
Why does "window" work while "document" only works if you call "console.log" first? Not a clue.
Resize events: no go
Most browsers don't support resize events on anything other than the window object. According to this page, only Opera supported detecting resizing documents. You can use the test page to quickly test it in multiple browsers. Another source that mentions a resize event on the body element specifically also notes that it doesn't work. If we look at these bug reports for Internet Explorer, we find out that having a resize event fire on arbitrary elements was an Internet Explorer-only feature, since removed.
Object.observe: maybe in the future
A more general method of figuring out changes to properties has been proposed and will most likely be implemented cross-browser: Object.observe(). You can observe any property for changes and run a function when that happens. This way, you can observe the element and when any property changes, such as clientWidth or clientHeight, you will get notified. It currently works only in Chrome with the experimental Javascript flag turned on. Plus, it is buggy. I could only get Chrome to notify me about properties that were changed inside Javascript, not properties that were changed by the browser. Experimental stuff; may or may not work in the future.
Current solution
Currently, you will have to do dirty checking: assign the value of the property that you want to watch to a variable and then check whether it has changed every 100 ms. For example, if you have the following HTML on a page:
<span id="editableSpan" contentEditable>Change me!</span>
And this script:
window.onload = function() {
function watch(obj, prop, func) {
var oldVal = null;
setInterval(function() {
var newVal = obj[prop];
if(oldVal != newVal) {
var oldValArg = oldVal;
oldVal = newVal;
func(newVal, oldValArg);
}
}, 100);
}
var span = document.querySelector('#editableSpan');
// add a watch on the offsetWidth property of the span element
watch(span, "offsetWidth", function(newVal, oldVal) {
console.log("width changed", oldVal, newVal);
});
}
This works similarly to Object.observe and for example the watch function in the AngularJS framework. It's not perfect, because with many such checks you will have a lot of code running every 100 ms. Additionally any action will be delayed 100 ms. You could possibly improve on this by using requestAnimationFrame instead of setInterval. That way, an update will be noticed whenever the browser redraws your webpage.
What you can do is that if you know for certain what particular action triggers a resize on your element that doesn't resize the full window you can trigger a resize event so your browser recalculate all of the divs (if by the case the browser is not triggering the event correctly).
With Jquery:
$(window).trigger('resize');
In the other hand, if you have an action that resizes an element you can always hold from that action to handle other following logic.
<script>
function body_OnResize() {
alert('resize');
}
</script>
<body onresize="body_OnResize()"></body>

How to make an iframe auto-resize along with the dynamic changes on its content?

I have this js code I searched on auto-resizing iframe height with its content. It does what the user who posted this says it does. However, I now have this problem with dynamic content within the iframe.
The js code I have works only with the regular content of the page but not when there are dynamic changes going on within. For example, displaying texts through ajax call.
I've tried searching for other solutions to this but others did not work as well as what this code can do.
I'm hoping that there's someone who could help me update the code to meet what I currently need. I'm not very familiar with jquery/javascript to do this on my own. Thank you in advance! :)
This is the JS code:
function setIframeHeight(iframeId) {
var ifDoc, ifRef = document.getElementById(iframeId);
try {
ifDoc = ifRef.contentWindow.document.documentElement;
} catch (e) {
try {
ifDoc = ifRef.contentDocument.documentElement;
} catch (ee) {}
}
if (ifDoc) {
ifRef.height = 1;
ifRef.height = ifDoc.scrollHeight;
/* For width resize, enable below. */
//ifRef.width = 1;
//ifRef.width = ifDoc.scrollWidth;
}
}
I found this other code which enables iframe adapting to its dynamic content but I do not know how to make the code above and this work together. Please help me.
var iframe = document.getElementById("ifr").contentWindow;
iframe.$(".toggle_div").bind("change", function () {
$("#ifr").css({
height: iframe.$("body").outerHeight()
});
});
To summarize, I need a code that autoresizes iframe with its content and will autoresize again if there are changes on the size of the content.
The problem is that your page doesn't have any trigger indicating to resize when the iframe body resizes.
There also (as far as I know) isn't anything built into javascript that lets you watch for changes in an elements height.
You have two options.
If you are the owner of the iframe content, you can put a script in that page which can call to it's parent window telling the parent to run your resize script, or you can run a function which checks for changes say every second or so.
For the first method, you can follow the answer from here Can events fired from an iframe be handled by elements in its parent?
Otherwise just do a
setTimeout(function(){
$("#ifr").css({
height: iframe.$("body").outerHeight()
});
},1000);
function adjustMyFrameHeight()
{
var frame = getElement("myFrame");
var frameDoc = getIFrameDocument("myFrame");
frame.height = frameDoc.body.offsetHeight;
}
call this method on your iframe onload event and replace mtFrame to your iframe Id

Calling a function or focusing a programmatically generated Iframe from an HTML5 canvas

I have an HTML5 canvas controlled and generated by a library of JavaScript files (Craftyjs library mostly).
The canvas generates 2 regular html iframes (same domain) which are stacked on top of each other.
The canvas switches between the two iframes based on calls from the iframes to the parent so I know the code controlling the canvas is easily accessed by their common parent.
I want the parent canvas to either call a function in the iframes to have them focus on a specific element in them or to somehow just have the iframes get focus in general.
I would also prefer to not have to constantly reload/recreate the iframes to get focus.
---- In the Iframe ----
//The head has a function "focusThis()" to focus on an element in the iframe
//body also has onfocus="focusThis();"
//Call the parent to change to the other iframe
parent.changeIframe();
---- In the parent's canvas JS code ----
// I know the function and will hide/show the iframe, but it won't focus
function changeIframe(){
//For now, just switch randomly
MODE = Math.floor(Math.random()*2);
//I am hiding the iframes here, then showing the one that should be seen
Crafty("Game1").each(function () {this.visible = false});
Crafty("Game2").each(function () {this.visible = false});
//Switch the iframes
if(MODE){
//Show this iframe
Crafty("iframe1").each(function () {this.visible = true});
These are things I have tried to get to work
When it doesn't throw an error it doesn't do anything in chrome or FireFox.
(Object [object global] has no method 'focusThis') is a common error
//document.getElementById('iframe1').focus();
//document.getElementById("iframe1").contentWindow.focusThis();
//document.getElementById('iframe1').contentWindow.focusThis();
//var iframe_window = window.frames["iframe1"];
//iframe_window.focus();
//iframe_window.contentDocument.body.focus();
//window.parent.document.getElementById('iframe1').contentWindow.focusThis;
//window.parent.document.getElementById('iframe1').contentWindow.focusThis();
//window.frames["iframe1"].focus();
//window.frames["iframe1"].contentWindow.focus();
//window.frames["iframe1"].contentDocument.focus();
var frame = document.getElementById("iframe1");
if(frame){
alert("yep");
frame.contentWindow.focusThis();
}
}
else{
//....Same thing but for iframe2
}
}
Any help would be greatly appreciated.
I solved my problem after some more fiddling.
This also solved my problem without having to reload the iframe.
I set a timer in the onload function of each iframe that tries to focus itself onto an element in itself based on a parent flag variable (MODE) that tells the iframe if it is supposed to have focus and an internal variable (focused) that tells it to stop trying to focus once it finally has focus again.
Somewhere in the head...
var focused = false;
function focusThis(){
if(parent.MODE && !focused){
document.getElementById("SOME_ELEMENT_I_WANT_FOCUSED").focus();
focused = true;
}
}
Somewhere in onLoad...
var autoFocus =
setInterval(function(){if(parent.MODE && !focused) focusThis()},500);
Somewhere in script below the body...
parent.changeIframe();
changeImage();
if(!parent.MODE){
//This element is just to have a place for focus to go when out of focus
document.getElementById("NA").focus();
focused = false;
}
else
focused = true;

How can you set focus to an HTML input element without having all of the HTML?

First, the background:
I'm working in Tapestry 4, so the HTML for any given page is stitched together from various bits and pieces of HTML scattered throughout the application. For the component I'm working on I don't have the <body> tag so I can't give it an onload attribute.
The component has an input element that needs focus when the page loads. Does anyone know a way to set the focus to a file input (or any other text-type input) on page load without access to the body tag?
I've tried inserting script into the body like
document.body.setAttribute('onload', 'setFocus()')
(where setFocus is a function setting the focus to the file input element), but that didn't work. I can't say I was surprised by that though.
EDIT:
As has been stated, I do indeed need to do this with a page component. I ended up adding file-type inputs to the script we use for giving focus to the first editable and visible input on a page. In researching this problem I haven't found any security issues with doing this.
<script>
window.onload = function() {
document.getElementById('search_query').select();
//document.getElementById('search_query').value = '';
// where 'search_query' will be the id of the input element
};
</script>
must be useful i think !!!
This has worked well for me:
<script>
function getLastFormElem(){
var fID = document.forms.length -1;
var f = document.forms[fID];
var eID = f.elements.length -1;
return f.elements[eID];
}
</script>
<input name="whatever" id="maybesetmaybenot" type="text"/>
<!-- any other code except more form tags -->
<script>getLastFormElem().focus();</script>
you can give the window an onload handler
window.onload = setFocus;
I think you have a fundamental problem with your encapsulation. Although in most cases you could attach an event handler to the onload event - see http://ejohn.org/projects/flexible-javascript-events/ by John Resig for how to do this, setFocus needs to be managed by a page component since you can't have two components on your page requiring that they get the focus when the page loads.
Try play with tabstop attribute
First of all, the input file is no the same as the other inputs, you need to keep this in mind.... thats for security reasons. When the input file get focus it should be read only or the browser should popup a dialog to choose some file.
Now, for the other inputs you could try some onload event on some of your elements...(not only the body have the onload event) or you could use inline javascript in the middle of the html. If you put javascript code without telling that is a function it gets executes while the browser reads it. Something like:
<script type="text/javascript">
function yourFunction()
{
...;
};
alert('hello world!");
yourFunction();
</script>
The function will be executed after the alert just when the browser reads it.
If you can, you should use jQuery to do your javascript. It will make your live soooo much easy.... :)
With jQuery could be done like this:
$(function() {
$("input:file").eq(0).focus()
})
With plain javascript could be done like this:
var oldWindowOnload = window.onload; // be nice with other uses of onload
window.onload = function() {
var form = document.forms[0];
for(i=0; i < form.length; i++) {
if (form[i].type == "file") {
form[i].focus();
}
}
oldWindowOnload();
}
For more elaborate solution with plain javascript see Set Focus to First Input on Web Page on CodeProject.
Scunliffe's solution has a usability advantage.
When page scripts are loading slowly, calling focus() from "onLoad" event makes a very nasty page "jump" if user scrolls away the page. So this is a more user friendly approach:
<input id="..."></input>
... really small piece of HTML ...
<script>getTheDesiredInput().focus();</script>

Categories

Resources