Can it be determined if window.resizeTo will work? - javascript

Inside the Javascript console, if I execute:
m = window.open(location.origin);
m.resizeTo(400, 400);
The window will resize, but if I just execute:
window.resizeTo(400, 400);
then nothing happens. I understand the reason for this behavior. How can I detect situations where window.resizeTo will do nothing?

Approach 1:
You can use the window.opener property. If it's null, then you did not open that window and thus cannot resize it.
window.parent is intended more for iframes and the like.
Such as:
if (m.opener) {
m.resizeTo(400, 400);
} else {
// You did not create the window, and will not be able to resize it.
}
Approach 2:
ajp15243 brings up a good point, so one thing you could do is listen to the resize event and see if your resizeTo worked:
var resizeFired = false;
...
var triggeredResize = function() {
resizeFired = true;
m.removeEventListener('resize', triggeredResize);
}
m.addEventListener('resize', triggeredResize, true);
m.resizeTo(400, 400);
if (resizeFired) {
// Your resize worked.
}
I haven't been able to fully test this, but it's one potential approach nonetheless. For IE8 and below you may need to use attachEvent instead. Also as #Wesabi noted, the resize may fire for other events (and may fire if the user is resizing the window as the listener as attached), so it's best to execute this is the shortest time span possible.
Approach 3:
Another approach would be to call m.resizeTo(400, 400) and then check the window size to see if the current size is equal to what you set it to:
m.resizeTo(400, 400);
if (w.outerWidth != 400 && w.outerHeight != 400) {
// Your resize didn't work
}

The easiest thing to do would be checking if the window has a parent. if !window.parent, it means it's the main window which cannot be resized with JS, else you have your resize case.
Edit: Igor posted it before I found it: you want m.opener() not window.parent

MDN is a great JavaScript resource: https://developer.mozilla.org/en-US/docs/Web/API/Window.resizeTo
Since Firefox 7, it's no longer possible for a web site to change the default size of a window in a browser, according to the following rules:
You can't resize a window or tab that wasn’t created by window.open.
You can't resize a window or tab when it’s in a window with more than one tab.
SO, you need to detect if you are a child window:
https://developer.mozilla.org/en-US/docs/Web/API/Window.opener
if (window.opener) {
console.log('I can be resized');
} else {
console.log('I cannot be resized');
}

Related

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>

Safe way to interact with page's DOM from Overlay JS

I have a Firefox extension that detects whenever a page loads in the browser and returns its window and document. I want to attach some events (that launch functions in my addon's overlay) to elements in the page, but I don't know how to do this in a way that's safe.
Here's a code sample:
var myExt = {
onInit: function(){
var appcontent = document.getElementById("appcontent");
if(appcontent){
appcontent.addEventListener("DOMContentLoaded", this.onPageLoad, true);
}
},
onPageLoad: function(e){
var doc = e.originalTarget;
var win = doc.defaultView;
doc.getElementById("search").focus = function(){
/* ... 'Some privelliged code here' - unsafe? ... */
};
}
};
So can anyone tell me what's the safe way to add these events/interact with the page's DOM?
Thanks in advance!
I think that you want to listen to the focus event, not replace the focus() function:
doc.getElementById("search").addEventListener("focus", function(event)
{
if (!event.isTrusted)
return;
...
}, false);
Usually, there is fairly little that can go wrong here because you are not accessing the page directly - there is already a security layer (which is also why replacing the focus() method will have no effect). You can also make sure that you only act on "real" events and not events that have been generated by the webpage, you check event.isTrusted for that like in the example code. But as long as you don't unwrap objects or run code that you got from the website, you should be safe.

Why does IE8 hangs on jquery window.resize event?

I discovered a problem that seems to reproduce always when opening a piece of html and javascript in IE8.
<html>
<body>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.0/jquery.min.js"></script>
<script>
$(document).ready(function(){
$(window).resize(function() {
console.log('Handler for .resize() called');
});
});
</script>
<div id="log">
</div>
</body>
</html>
Loading this file in IE8 and opening Developer Tools will show that the log message is printed continuously after one resize of the browser window.
Does anyone has an idea why? This is not happening in IE7 or IE9, nor in other browsers (or at least their latest versions).
UPDATE
One solution to prevent the continuos trigger of resize() is to add handler on document.body.onresize if the browser is IE8.
var ieVersion = getInternetExplorerVersion();
if (ieVersion == 8) {
document.body.onresize = function () {
};
}
else {
$(window).resize(function () {
});
}
But this does not answer my question: is the continuous firing of resize() a bug in IE8?
If "show window contents while dragging" is switched on, you will be inundated with resize events. I guess you're testing IE8 on a separate Windows machine which has this effect enabled (Display Properties -> Appearance -> Effects...).
To counteract this, you can wrap & trap the resize events to tame them: http://paulirish.com/demo/resize
This article says Chrome, Safari & Opera suffer from this too.
I only see the issue you are describing if an element on the page is resized (as described in this question). Your example doesn't work for me, but I assume for you it is appending the console message in the log div that you have there, which means that it is resizing the div and triggering the window resize event.
The answer that Lee gave is correct, but the method in the link didn't work for me. Here's what I did:
var handleResize = function(){
$(window).one("resize", function() {
console.log('Handler for .resize() called');
setTimeout("handleResize()",100);
});
}
handleResize();
This way, the handler is unbound as soon as it fires, and is only re-bound after you've finished all your actions that might re-trigger a page resize. I threw in a setTimeout to provide additional throttling. Increase the value in case your scripts need more time.

Why is the resize event constantly firing when I assign it a handler with a timeout?

I assigned a timeout to my window.resize handler so that I wouldn't call my sizable amount resize code every time the resize event fires. My code looks like this:
<script>
function init() {
var hasTimedOut = false;
var resizeHandler = function() {
// do stuff
return false;
};
window.onresize = function() {
if (hasTimedOut !== false) {
clearTimeout(hasTimedOut);
}
hasTimedOut = setTimeout(resizeHandler, 100); // 100 milliseconds
};
}
</script>
<body onload="init();">
...
etc...
In IE7 (and possibly other versions) it appears that when you do this the resize event will constantly fire. More accurately, it will fire after every timeout duration -- 100 milliseconds in this case.
Any ideas why or how to stop this behavior? I'd really rather not call my resize code for every resize event that fires in a single resizing, but this is worse.
In your //do stuff code, do you manipulate any of the top,left,width,height,border,margin or padding properties?
You may unintentionally be triggering recursion which unintentionally triggers recursion which unintentionally triggers recursion...
How to fix the resize event in IE
also, see the answer for "scunliffe" "In your ... properties?
IE does indeed constantly fire its resize event while resizing is taking place (which you must know, as you are already implementing a timeout for a fix).
I am able to replicate the results you are seeing, using your code, on my test page.
However, the problem goes away if I increase the timeout to 1000 instead of 100. You may want to try with different wait values to see what works for you.
Here is the test page I used: it has a nicely dynamic wait period already set up for you to play with.
I stumbled on the same problem, but solved it differenly, and I think it's more elegant than making a timeout....
The context: I have an iframed page, loaded inside the parent page, and the iframe must notify the parent when its size changes, so the parent can resize the iframe accordingly - achieving dynamic resizing of an iframe.
So, in the iframed HTML document, I tried to register a callback on the body tag. First, on the onchange - it didn't work. Then on resize - it did work, but kept firing constantly. (Later on I found the cause - it was apparently a bug in Firefox, which tried to widen my page to infinity). I tried the ResizeObserver - for no avail, the same thing happened.
The solution I implemented was this:
<body onload="docResizePipe()">
<script>
var v = 0;
const docResizeObserver = new ResizeObserver(() => {
docResizePipe();
});
docResizeObserver.observe(document.querySelector("body"));
function docResizePipe() {
v += 1;
if (v > 5) {
return;
}
var w = document.body.scrollWidth;
var h = document.body.scrollHeight;
window.parent.postMessage([w,h], "*");
}
setInterval(function() {
v -= 1;
if (v < 0) {
v = 0;
}
}, 300);
</script>
So how it works: each time the callback fires, we increment a variable v; once in every 300 ms, we decrement it; if it's too big, the the firing is blocked.
The big advantage of this over the timeout-based solution, is that it introduces to lag for a user experience, and also clear in how exactly it does block the recursion. (Well, actually not )))

Self-closing popups in IE -- how to get proper onBlur behavior?

I want a transient window to close itself when the user clicks away from it. This works for Firefox:
var w = window.open(...);
dojo.connect(w, "onblur", w, "close");
but it doesn't seem to work in Internet Explorer. Some other sites made reference to an IE-specific "onfocusout" event, but I couldn't find a coherent working example of what I need.
What does Stack Overflow say about the best way to get IE browser windows to close when they lose focus?
I'm using Dojo so if there's some shortcut in that library, information would be welcome. Otherwise standard IE calls will be the best answer.
I figured out the alternative in IE.
This:
that.previewWindowAction = function () {
var pw =
window.open(this.link, "preview",
"height=600,width=1024,resizable=yes,"
+ "scrollbars=yes,dependent=yes");
dojo.connect(pw, "onblur", pw, "close");
};
should be written like this to work in IE:
that.previewWindowAction = function () {
var pw =
window.open(this.link, "preview",
"height=600,width=1024,resizable=yes,"
+ "scrollbars=yes,dependent=yes");
if (dojo.isIE) {
dojo.connect
(pw.document,
"onfocusin",
null,
function () {
var active = pw.document.activeElement;
dojo.connect
(pw.document,
"onfocusout",
null,
function () {
if (active != pw.document.activeElement) {
active = pw.document.activeElement;
} else {
window.open("", "preview").close();
}
});
});
}
else {
dojo.connect(pw, "onblur", pw, "close");
}
};
The reasons?
In IE, window objects do not respond to blur events. Therefore we must use the proprietary onfocusout event.
In IE, onfocusout is sent by most HTML elements, so we must add some logic to determine which onfocusout is the one caused by the window losing focus. In onfocusout, the activeElement attribute of the document is always different from the previous value -- except when the window itself loses focus. This is the cue to close the window.
In IE, documents in a new window send an onfocusout when the window is first created. Therefore, we must only add the onfocusout handler after it has been brought into focus.
In IE, window.open does not appear to reliably return a window handle when new windows are created. Therefore we must look up the window by name in order to close it.
Try:
document.onfocusout = window.close();
You might try this as part of an IE-specific code block:
w.onblur = function() { w.close();};

Categories

Resources