cross-browser element onresize (HTML / JS) - javascript

I know that IE supports the onresize event for any element while FireFox supports it for the window object only.
Since I need that functionality for any modern browser I am currently using a (fairly fast) interval timer that continuously checks the clientWidth/clientHeight of an element to emulate the onresize. Of course this is very inefficient and I'd like to know if there is a cross-browser way that does this. Or, alternatively, different methods that work in Firefox/WebKit/IE so that the timer-method can be used as a fallback for remaining browsers.
Targeting at plain JavaScript, instead of jQuery / Prototype etc.

If you don't want to use jQuery then you must check what browser sends to your's script, so:
if(!element.onresize != null) element.onresize += event;
if(!element.onresizeAnotherHandler != null) element.onresizeAnotherHandler += event;
I don't know is it that easy, but it is a general concept.
EDIT: It looks like there is not event handler for Firefox. But there is an trick:
If you are changing width in your's JS just create an function update
function update(var nx, var ny){
// do something with nx and ny
}
If you added an resize handle using CSS do it using JavaScript
If you are using something like 80% in your's CSS then handle window.onresize:
function resize(){
alert(document.getElementById("test").style.width);
}
window.onresize = resize;
It looks that there is no other way.

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>

onload function init not found

I'm encountering a strange issue. I am developing a books application and using javascript onload. I read somewhere that its best to include your javascript at the end of the html. This works for most of the html loaded. However some complain that onload init() not found. This gets solved if i include the javascript in the html head. But than other htmls start behaving strangely. onload gets called before the page is fully loaded. i dont get the correct scroll width. Please suggest what could be worng. Whats the best way of including javascripts. Thanks
html is as follows
columizer id use css column-width which i've defined like this.
css style below
#columnizer
{
width:290px;
height:450px;
column-width:290px;
column-gap:10px;
word-wrap:break-word;
}
Javascript onload is defined like this.
function init()
{
docScrollWidth = document.getElementById('columnizer').scrollWidth;
document.getElementsByTagName('body')[0].style.width = docScrollWidth + "px";
window.external.notify(str);
}
Since the actual answer was in my comment, I'll add that to my answer:
My guess is that you're doing something like window.onload = init(); instead of window.onload = init; and the init function will have to be declared before you do that assignment. You assign function references without the parens. Using the parens causes it to get executed immediately.
You say you're using this code:
docScrollWidth = document.getElementsByTagName('body')[0].style.width
The main problem with this is that style.width ONLY reads a style attribute set directly on the body object. It doesn't get the width of the object as calculated by layout or CSS rules.
So, what you should use instead really depends upon what you're trying to do. The body width will nearly always be the same or more than the window width unless your content is entirely fixed width. So, that makes me wonder what you're trying to accomplish here? What you should use instead depends upon what you're really trying to do.
FYI, document.body is a direct reference to the body object so you don't need document.getElementsByTagName('body')[0].
First, let me define the problem. The window.onload event is used by programmers to kick-start their web applications. This could be something trivial like animating a menu or something complex like initialising a mail application. The problem is that the onload event fires after all page content has loaded (including images and other binary content). If your page includes lots of images then you may see a noticeable lag before the page becomes active. What we want is a way to determine when the DOM has fully loaded without waiting for all those pesky images to load also.
Mozilla provides an (undocumented) event tailor-made for this: DOMContentLoaded. The following code will do exactly what we want on Mozilla platforms:
// for Mozilla browsers
if (document.addEventListener) {
document.addEventListener("DOMContentLoaded", init, false);
}
So what about Internet Explorer?
IE supports a very handy (but non-standard) attribute for the tag: defer. The presence of this attribute will instruct IE to defer the loading of a script until after the DOM has loaded. This only works for external scripts however. Another important thing to note is that this attribute cannot be set using script. That means you cannot create a script using DOM methods and set the defer attribute – it will be ignored.
Using the handy defer attribute we can create a mini-script that calls our onload handler:
<script defer src="ie_onload.js" type="text/javascript"></script>
The contents of this external script would be a single line of code to call our onload event handler:
init();
There is a small problem with this approach. Other browsers will ignore the defer attribute and load the script immediately. There are several ways round this. My preferred method is to use conditional comments to hide the deferred script from other browsers:
<!--[if IE]><script defer src="ie_onload.js"></script><![endif]-->
IE also supports conditional compilation. The following code is the JavaScript equivalent of the above HTML:
// for Internet Explorer
/*#cc_on #*/
/*#if (#_win32)
document.write("<script defer src=ie_onload.js><\/script>");
/*#end #*/
So far so good? We now need to support the remaining browsers. We have only one choice – the standard window.onload event:
// for other browsers
window.onload = init;
There is one remaining problem (who said this would be easy?). Because we are trapping the onload event for the remaining browsers we will be calling the init function twice for IE and Mozilla. To get around this we should flag the function so that it is executed only once. So our init method will look something like this:
function init() {
// quit if this function has already been called
if (arguments.callee.done) return;
// flag this function so we don't do the same thing twice
arguments.callee.done = true;
// do stuff
};
I’ve provided a sample page that demonstrates this technique.

Use Javascript to CTRL+ and CTRL- in Firefox & Chrome

I would like to give users the ability to increase/decrease the rendering size of the content inside of a web app.
The CTRL+ and CTRL- features (or CTRL1 through CTRL9) of Chrome & Firefox are handy - but is there a way from JavaScript to execute those features?
Clarification:
I want the user to be able to achieve this via mouse-clicks, not keypresses, so something like this:
function resize_rendering() {
// code that executes ctrl+ or crtl-
}
The browser zoom level is a user setting, which is there for accessiblity purposes; it's not intended for the site developer to ever know or care what the zoom level is, so I would expect that you'll have trouble doing exactly what you want. Certainly, it'll be hard to get it right in a way that works cross-browser.
The normal approach to this is to have a sizing gadget that changes the base font size.
If all the font sizes in your site are in em units, then you can change the sizes of all the text on the site with a single CSS change.
So you would have a set of buttons on the site which use Javascript to set the font-size of the <body> element to (for example) 12, 14, 16 or 18 pixels, depending on the element clicked.
There's a write-up of the technique here: http://labnol.blogspot.com/2006/12/allow-site-visitors-to-change-font.html
You are not allowed to by design. You can't change a user's browser setting via Javascript.
You can do other things, like modify all of the CSS on your page to scale everything down to simulate a CTRL-, but that's all.
In some browsers you can capture CTRL+/- before the browser does, allowing you to stop those events from occuring. But you cannot do the oppisite - you cannot cause those events to occur from your own script.
This library here by John Resig is a jQuery plugin that should do the job. There's some samples. Its quite easy to hookup combinations of keys as well.
You could intercept the keystroke in a general key event handler (such as on the window object), check to see if it's the one you're looking for, and if so, call stopPropagation() on the event parameter (and return false) to prevent the browser from then handling it on its own.
You'd then have to perform the sizing operation yourself, such as by modifying a stylesheet using JavaScript.
window.addEventListener( 'keydown', function( e ) {
if ( /* check e.keyCode etc. */ ) {
// modify global style to increase/decrease font size
e.stopPropagation();
return false;
} );
Look towards CSS property "zoom"
/* ctrl++ */
body {
zoom: 1.1;
}
For JS, it's like:
function resize_rendering(zoom) {
let currentZoom = parseFloat(document.body.style.zoom) || 1
document.body.style.zoom = currentZoom * zoom
}
resize_rendering(1.1) // ctrl++
resize_rendering(0.9) // ctrl+-

My html/javascript/css site works in IE but not in FF

www.warhawkcomputers.com/Birenbaum
This site has various projects for my Computer class that I am in. A check is coming up and all programs will need to work in FF and IE.
My Bouncing Ball, Race Track, and Tanks projects under Third quarter as well as pong under Fourth Quarter work in IE when the objects need to be moved by a continuously adding variable performed in a javascript script, and it works perfectly fine in IE, but when viewed with Firefox 3, the moving objects no longer move and I have tested to find out it gets the variables but seems to only add it once and that the document.getElementById("objectname").style.left = "continuously adding variable" seems to not be executed despite being in a timer running every 10 milliseconds.
Also, none of my keypress code works in Firefox, but I believe that is because I use an outdated method of moving objects via keypress. This is largely due to my teacher's outdated methods.
Thanks for all of your guys's help.
You need to add a 'units' to your positions:
document.getElementById("ball").style.left = x + 'px';
document.getElementById("ball").style.top = y + 'px';
That will work in FF as well now.
Firefox does not use a global event object. They pass an event object into the handler. As a result, you need to modify your Move function:
function Move(e) {
/* snip */
var whichkey = window.event ? window.event.keyCode : e.keyCode;
/* ... */
Gerrat is absolutely correct about the other problem you asked about.
EDIT: this won't work with how you hooked your event handler in the body tag. You need to remove the onkeydown="Move()" attribute from the body tag and add the following code at the top of JavaScript.js:
document.body.onkeydown=Move;
If allowed to do so by your teacher, you would be MUCH better off using jQuery or some other framework.

img onload doesn't work well in IE7

I have an img tag in my webapp that uses the onload handler to resize the image:
<img onLoad="SizeImage(this);" src="foo" >
This works fine in Firefox 3, but fails in IE7 because the image object being passed to the SizeImage() function has a width and height of 0 for some reason -- maybe IE calls the function before it finishes loading?. In researching this, I have discovered that other people have had this same problem with IE. I have also discovered that this isn't valid HTML 4. This is our doctype, so I don't know if it's valid or not:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
Is there a reasonable solution for resizing an image as it is loaded, preferably one that is standards-compliant? The image is being used for the user to upload a photo of themselves, which can be nearly any size, and we want to display it at a maximum of 150x150. If your solution is to resize the image server-side on upload, I know that is the correct solution, but I am forbidden from implementing it :( It must be done client side, and it must be done on display.
Thanks.
Edit: Due to the structure of our app, it is impractical (bordering on impossible) to run this script in the document's onload. I can only reasonably edit the image tag and the code near it (for instance I could add a <script> right below it). Also, we already have Prototype and EXT JS libraries... management would prefer to not have to add another (some answers have suggested jQuery). If this can be solved using those frameworks, that would be great.
Edit 2: Unfortunately, we must support Firefox 3, IE 6 and IE 7. It is desirable to support all Webkit-based browsers as well, but as our site doesn't currently support them, we can tolerate solutions that only work in the Big 3.
If you don't have to support IE 6, you can just use this CSS.
yourImageSelector {
max-width: 150px;
max-height: 150px;
}
IE7 is trying to resize the image before the DOM tree is fully rendered. You need to run it on document.onload... you'll just need to make sure your function can handle being passed a reference to the element that isn't "this."
Alternatively... and I hope this isn't a flameable offense... jQuery makes stuff like this really, really easy.
EDIT in response to EDIT 1:
You can put document.onload(runFunction); in any script tag, anywhere in the body. it will still wait until the document is loaded to run the function.
I've noticed that Firefox and Safari both fire "load" events on new images no matter what, but IE 6&7 only fire "load" if they actually have to get the image from the server -- they don't if the image is already in local cache. I played with two solutions:
1) Give the image a unique http argument every time, that the web server ignores, like
<img src="mypicture.jpg?keepfresh=12345" />
This has the downside that it actually defeats caching, so you're wasting bandwidth. But it might solve the problem without having to screw with your JavaScript.
2) In my app, the images that need load handlers are being inserted dynamically by JavaScript. Instead of just appending the image, then building a handler, I use this code, which is tested good in Safari, FF, and IE6 & 7.
document.body.appendChild(newPicture);
if(newPicture.complete){
doStuff.apply(newPicture);
}else{
YAHOO.util.Event.addListener(newPicture, "load", doStuff);
}
I'm using YUI (obviously) but you can attache the handler using whatever works in your framework. The function doStuff expects to run with this attached to the affected IMG element, that's why I call it in the .apply style, your mileage may vary.
Code for jQuery. But it's easy to make dial with other frameworks. Really helpful.
var onload = function(){ /** your awesome onload method **/ };
var img = new Image();
img.src = 'test.png';
// IE 7 workarond
if($.browser.version.substr(0,1) == 7){
function testImg(){
if(img.complete != null && img.complete == true){
onload();
return;
}
setTimeout(testImg, 1000);
}
setTimeout(testImg, 1000);
}else{
img.onload = onload
}
The way I would do it is to use jQuery to do something like:
$(document).load(function(){
// applies to all images, could be replaced
//by img.resize to resize all images with class="resize"
$('img').each(function(){
// sizing code here
});
});
But I'm no javascript expert ;)
setTimeout() may be a workaround if you are really stuck. Just set it for 2 or 3 seconds - or after the page is expected to load.
EDIT: You may want to have a look at this article - all the way at the bottom about IE mem leaks...
Edit: Due to the structure of our app,
it is impractical (bordering on
impossible) to run this script in the
document's onload.
It is always possible to add handlers to window.onload (or any event really), even if other frameworks, library or code attaches handlers to that event.
<script type="text/javascript">
function addOnloadHandler(func) {
if (window.onload) {
var windowOnload = window.onload;
window.onload = function(evt) {
windowOnload(evt);
func(evt);
}
} else {
window.onload = function(evt) {
func(evt);
}
}
}
// attach a handler to window.onload as you normally might
window.onload = function() { alert('Watch'); };
// demonstrate that you can now attach as many other handlers
// to the onload event as you want
addOnloadHandler(function() { alert('as'); });
addOnloadHandler(function() { alert('window.onload'); });
addOnloadHandler(function() { alert('runs'); });
addOnloadHandler(function() { alert('as'); });
addOnloadHandler(function() { alert('many'); });
addOnloadHandler(function() { alert('handlers'); });
addOnloadHandler(function() { alert('as'); });
addOnloadHandler(function() { alert('you'); });
addOnloadHandler(function() { alert('want.'); });
</script>
This answer has a slightly different version of my addOnloadHandler() code using attachEvent. But I discovered in testing that attachEvent doesn't seem to guarantee the handlers fire in the order you added them, which may be important. The function as presented guarantees handlers are fired in the order added.
Note that I pass evt into the added event handlers. This is not strictly necessary and the code should work without it, but I work with a library that expects the event to be passed to the onload handler and that code fails unless I include it in my function.
You can do something like :
var img = new Image();
img.src = '/output/preview_image.jpg' + '?' + Math.random();
img.onload = function() {
alert('pass')
}

Categories

Resources