Is this an onload bug in Opera? - javascript

I believe that I've identified a bug in Opera (version 12.01 running on Windows 7), but am looking for assistance with a possible workaround (presuming that others can confirm that this is a bug).
If I have an HTML page containing the following:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Test</title>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js" />
</head>
<body onload="window.alert(0);">
</body>
</html>
The "onload" event is never fired. Oddly, if I close the script tag instead of self closing it, and change:
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js" />
to:
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
(which unfortunately I can't do), the event will fire and my alert will be shown.
Had anyone else run into this problem? If so, have they found a way around it besides changing the script tag from <script /> to <script></script>?
NOTE: Yes, I have opened a bug report with Opera. No response back from them yet.

This "bug" exists in all browsers, not only in Opera (I've tested Chrome, FF and IE).
Self-closing script tags just don't work. See this question on SO: Why don't self-closing script tags work?
EDIT:
I have no idea why you can't close the script tag with </script>, but one possible workaround would be loading the scripts with JavaScript:
var newScript = document.createElement("script");
newScript.type = "text/javascript";
newScript.src = "https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js";
newScript.onload = function(){
// jQuery code...
};
document.getElementsByTagName("head")[0].appendChild(newScript);
(OK, admittedly this actually forces you to use </script> somewhere, but at least the part between <script> and </script> now isn't empty... :P)

What Opera does is correct per HTML5. To understand why the onload doesn't run, you need to remember that the contents of a SCRIPT tag with SRC set should be ignored. Since /> is not a correct way to close the first SCRIPT tag, the subsequent end-of-head and start-of-body tags end up inside the SCRIPT tag. It would be a bit like writing this:
<script src="foo.js">
</head><body><p>This doesn't appear anywhere, does it?</p></body>
</script>
So onload is never set in the first place because the BODY inside the SCRIPT tag will be ignored.

Related

how to isolate js script from the html code?

i'd like to isolate the javascript code from the html code in two diferent files, originally I had this code:
<!DOCTYPE html>
<html>
<head>
<title>Page Title</title>
</head>
<body>
<p id="body">HTML Text</p>
</body>
</html>
<script>
$(document).ready(function () {
$("#body").text("JS Text");
});
</script>
and the output of the <-p-> was the expected "JS Text".
Then I tried to isolate the js script to another file (script.js):
window.onload = function(){
var text = document.getElementById('body');
text.innerHTML ='JS Text';
}
I've also make the reference at the html file:
<script type="text/javascript"src="scripts.js"></script>
but then the output text is no longer the expected (JS Text) but (HTML text)
what else do I need to make the js script work again?
First, it is invalid to place anything after the closing HTML tag, so while your first bit of code worked, it was invalid.
If you remove the JavaScript and place it in its own file, it will continue to work as long as you reference the file properly (use a relative reference and test the file on a web server) and place the script element just prior to the closing body tag so that when the script is processed and attempts to find the right DOM element, the DOM will have been loaded at that time.
FYI:
If you have JQuery in the referenced script file, then your
script that references JQuery will need to occur in the HTML prior
to the script that uses it.
The type attribute in the script tag has not been needed in
several years.
It's not a good idea to name anything body so that you won't cause
confusion with the body element.
Don't use .innerHTML when the string you are working with doesn't
contain any HTML. .innerHTML has security and performance
implications. Use .textContent instead.
<!DOCTYPE html>
<html>
<head>
<title>Page Title</title>
</head>
<body>
<p id="body">HTML Text</p>
<script src="relativePathToFile.js"></script>
</body>
</html>

Chrome - <body onload=""> is not working

I know
"Onload executes when DOM fully loaded.This means it is executed after
end of your page. This is useful when you want to do some task when
document is fully loaed."
but why these code don't work in chrome(spBodyOnLoadWrapper is a function defined in "init.debug.js" , this function was not called ):
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns:o="urn:schemas-microsoft-com:office:office" lang="en-us" dir="ltr">
<head>
<script type="text/javascript">
document.write('<script type="text/javascript" src="/_layouts/1033/init.debug.js?rev=Cn3X2qRiBI8U52EFeStGwg%3D%3D"></' + 'script>');
</script>
</head>
<body scroll="no" onload="if (typeof(_spBodyOnLoadWrapper) != 'undefined') _spBodyOnLoadWrapper();" class="v4master">
</body>
These HTML is generated by a Microsoft product named "SharePoint 2010", ugly, and not "best practices" , but i have to make it work in chrome...
document.write() is JavaScript code, so it must be included within a script element.
I see a few mistakes/bad practices in your HTML:
First of all, you must wrap the document.write statement in script tags,
Second, using document.write is not necessary (and should be considered as a bad practice).
You can simply add the script to your page by placing the script tags in head or body:
<script type="text/javascript" src="/_layouts/1033/init.debug.jsrev=Cn3X2qRiBI8U52EFeStGwg%3D%3D"></script>
If you want to specify the script source dynamically, you can create a script element, set its source and add it to your document:
<script type="text/javascript">
var headElement = document.getElementsByTagName('head')[0],
script = document.createElement('script');
script.setAttribute('src', '/_layouts/1033/init.debug.jsrev=Cn3X2qRiBI8U52EFeStGwg%3D%3D');
script.setAttribute('type', 'text/javascript');
headElement.appendChild(script);
</script>
Instead of using onload attribute, it's better to add an EventListener for load event with JavaScript:
window.addEventListener('load', function () {
if (typeof(_spBodyOnLoadWrapper) != 'undefined') {
_spBodyOnLoadWrapper();
}
});
Just put the script tags in the head without document.write. Secondly, I suggest you put the code which you want to execute in a separate function as well in your head section but anywho, below example might work as well (see also JS Bin):
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns:o="urn:schemas-microsoft-com:office:office" lang="en-us" dir="ltr">
<head>
<script type="text/javascript" src="/_layouts/1033/init.debug.js?rev=Cn3X2qRiBI8U52EFeStGwg%3D%3D"></script>
</head>
<body scroll="no" onload="javascript:if (typeof(_spBodyOnLoadWrapper) != 'undefined'){ _spBodyOnLoadWrapper();}" class="v4master">
</body>
I'll suggest to use the following script:
window.onload = function() {
var head = document.getElementsByTagName('head')[0];
var script = document.createElement('script');
script.type = 'text/javascript';
script.onreadystatechange = function () {
if(this.readyState == 'complete') {
if (typeof(_spBodyOnLoadWrapper) != 'undefined') {
_spBodyOnLoadWrapper();
}
}
}
script.src = '/_layouts/1033/init.debug.js?rev=Cn3X2qRiBI8U52EFeStGwg%3D%3D';
head.appendChild(script);
}
The usage of document.write is not a good idea. The code above dynamically adds a new script tag into the header of the current page. It detects when this script is loaded and executes your function.
I ran into this problem and tried the solutions suggested here but they didn’t work. Some more searching indicates that this is a bug in Chrome that appears to go back at least to 2009:
http://productforums.google.com/forum/#!topic/chrome/7VIpByhmU3U
The issue is that body.onload (and also window.onload) are firing before the web page has completely loaded, apparently in my case because I’m loading large images whose time-to-load varies with net traffic. The work around is to put your JavaScript into the page after any referenced HTML, but before the end tag:
<script type="text/javascript">
if (typeof(_spBodyOnLoadWrapper) != 'undefined') _spBodyOnLoadWrapper();
</script>
This also had the effect for me of producing a substantially more immediate update of the page content in the other browsers (Firefox, Safari) where the bug doesn’t occur.
check if you have 2 onload events.

Script only runs in some browsers when head tags are removed

I'm using a tumblr theme which is structured like this:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<style>
</style>
<body>
</body>
</html>
There are no head tags which I thought was strange but it works fine; because when you run the site it places head tags automatically. However, since I'm using plugins I added the head tags myself to give me better control as some required me to place it in <head>. This worked fine in chrome and safari but it disabled one of my scripts in firefox and IE:
$(document).ready(function () {
var speed = 25,
timer;
$("#hoverscroll").hover(function () {
$(this).css({cursor: 'none'});
$(this).css({opacity: '0'});
var div = $('body');
(function startscrolling(){
timer = setTimeout(function () {
var pos = div.scrollTop();
div.scrollTop(pos + 1);
startscrolling();
}, speed);
})();
},
function () {
$("#hoverscroll").css({opacity: '1'});
clearTimeout(timer);
speed = 25;
})
.click(function(){
speed = 1;
});
});
It's a simple script where it scrolls the page when an element is hovered.
I reproduced the problem in these 2 demo-sites:
http://testmycode.tumblr.com/ This site has head tag, scrolls in chrome, does not scroll in Firefox.
http://testmycode2.tumblr.com/ This site has no head tag, works perfectly and scrolls in all browsers.
you can add code to your head tag using JQuery like below
$("head").append("<script src=\"mypluginscript.js\"></script>");
this will let you add any new code to it without having to write the head tag
an example!
'However, since I'm using plugins I added the head tags myself to give
me better control'
What you mean by that?
Most of the times there is an alternative solution.
A proper html needs a html tag a head tag and a body tag
inside the head tag you put meta,script and style tags
minimal structure is
<html>
<head>
</head>
<body>
</body>
</html>
Else it's not a html file.
Almost TEN years html5 was launched....
and as it is similar to the basic structure it works on all browsers.
<!doctype html> // html5
<html lang="en"> // language set to english
<head>
<meta charset="utf-8"> // can decode almost al charachters éçàò..
<style></style>
<script></script>
<title>Title</title>
</head>
<body>
</body>
</html>
now reguarding your code.
<script>
goes inside head (or at the end of the body [or just after each element])
if you put the code in the head..
to handle elements inside the body
you need to add a window.onload // DOMContentLoaded
else you have no access to the dom elements.
Now looking at your code from Chrome the errors starts on the html tag..
Why the html has a webkit animation?
Then your talking about the doctype tag and not the head tag.
So if you tell us why you need that we can probably find a solution.

Very strange IE crash problem with stylesheet javascript object

Hello I use javascript stylesheet object, with a specfic style and place it on dom ready. When i do exactly my code IE crash.
The problem is the UL with exactly this style set after the page is load. If I place the styleSheet.cssText = css; before the page load, everyting is correct. If i remove the char f in <DIV>f everything work. I need to use my code after the page is load. Any suggestion to pass over this trouble ?
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>test</title>
<script type="text/javascript" src="./jquery-1.4.2.min.js" ></script>
<script type="text/javascript">
var styleSheet = document.createStyleSheet();
var css= "UL{list-style-type:none;display:inline;}LI{padding:0px;}";
$(document).ready(function(){
styleSheet.cssText = css;
});
</script>
</head>
<body>
<DIV>f
<UL>
<LI><a>dfgfdg</a></LI>
<LI><a>fdgdfg</a></LI></UL>?
</DIV>?
</body>
</html>
The problem is IE8 specific. It seems to work on ie7 and ie9.
In order to reproduce the bug it is important to apply the stylesheet after the page is loaded.
We used jquery.ready() for this example but the code also crashes for click and load events.
This bug is very specific. It requires the precise css and html used in the example above. We have tried adding the stylesheet in different ways ( stylesheet.rules[i].lisStyleType='none' for example and adding the stylesheet in a .css file) with no success. We absolutely need to add the style dynamically where this probleme is happening.
createStyleSheet is not a cross-browser friendly solution... Try this code instead:
$(function(){
var styles = "UL{list-style-type:none;display:inline;}LI{padding:0px;}";
var newSS=document.createElement('link');
newSS.rel='stylesheet';
newSS.href='data:text/css,'+escape(styles);
document.getElementsByTagName("head")[0].appendChild(newSS);
});
I can't tell you exactly why IE is crashing, but this code works for me and it shouldn't trigger any unexpected errors.
I tried your code in a jsfiddle and it doesn't bug with IE7 .. what's the problem ?
What version of IE are you using ? Do you have an url of a demo that's crashing for you ? I can't reproduce your problem, please see my jsfiddle ...
Btw why do you use jquery 1.4.2 and not a more recent version ? 1.4.4 or 1.5.2 , in the jsfiddle I choosed 1.4.4
Please Try this. Tested in IE6,7,8,9 FF, Opera, Googlechrome, Safari
<script type="text/javascript">
function createRuntimeStyle(){
//create a style tag
var rStyle=document.createElement("style");
//create the content of the style tag
var cssDef=document.createTextNode(".myclass{display:block;font-family:Verdana;font-weight:bold;}");
//assign the type
rStyle.type="text/css";
if(rStyle.styleSheet){ //check for IE
rStyle.styleSheet.cssText=cssDef.nodeValue;
}else{ //check for Other Browsers
rStyle.appendChild(cssDef);
}
//append to document head
document.getElementsByTagName("head")[0].appendChild(rStyle);
}
//call to the function
createRuntimeStyle();
</script>

How does the location of a script tag in a page affect a JavaScript function that is defined in it?

I read that you should define your JavaScript functions in the <head> tag, but how does the location of the <script> (whether in the <head>, <body>, or any other tag) affect a JavaScript function.
Specifically, how does it affect the scope of the function and where you can call it from?
Telling people to add <SCRIPT> only in the head sounds like a reasonable thing to do, but as others have said there are many reasons why this isn't recommended or even practical - mainly speed and the way that HTML pages are generated dynamically.
This is what the HTML 4 spec says :
The SCRIPT element places a script
within a document. This element may
appear any number of times in the HEAD
or BODY of an HTML document.
And some sample HTML. Doesn't it look pretty all formatted here :)
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<HTML>
<HEAD>
<TITLE>A document with SCRIPT</TITLE>
<META http-equiv="Content-Script-Type" content="text/tcl">
<SCRIPT type="text/vbscript" src="http://someplace.com/progs/vbcalc">
</SCRIPT>
</HEAD>
<BODY>
<SCRIPT type="text/javascript">
...some JavaScript...
</SCRIPT>
</BODY>
</HTML>
And something to look forward to in HTML 5 :
New async attribute in <SCRIPT> :
Note: There are ways [sic] a script can be
executed:
The async attribute is "true": The
script will be executed asynchrously
with the rest of the page, so the
script will be executed while the page
continues the parsing.
The async attribute is "false", but
the defer attribute is "true": The
script will be executed when the page
is finished with the parsing.
The normal rules of play still stand; don't use stuff before it's defined. :)
Also, take note that the 'put everything at the bottom' advice isn't the only rule in the book - in some cases it may not be feasible and in other cases it may make more sense to put the script elsewhere.
The main reason for putting a script at the bottom of a document is for performance, scripts, unlike other HTTP requests, do not load in parallel, meaning they'll slow down the loading of the rest of your page. Another reason for putting scripts at the bottom is so you don't have to use any 'DOM ready' functions. Since the script tag is below all elements the DOM will be ready for manipulation!
EDIT: Read this: http://developer.yahoo.com/performance/rules.html#js_bottom
One of the aspects of placement is performance. See this fine article within the YSlow discussion for why it's sometimes recommended you put them at the bottom of the document.
As for issues of scope, the usual visibility rules for Javascript (vars defined inside or outside of functions, local, global, closures, etc.) are not affected so far as I know.
Position of script tag does matter.
If you bind a Function with document Element then the document element has to be loaded first before we implement function. suppose getTeachers() is function in getTeachers.js file.
This will give you an error:
<html xmlns="http://www.w3.org/1999/xhtml">
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Unit Teachers</title>
<head>
<script type="text/javascript" src="getTeachers.js"></script>
<script type="text/javascript">
document.getElementById("buttonId").onclick=function(){getResults()};
</script>
</head>
<body>
<form>
<input type = "button" id="buttonId" value = "Press for Results" /><br />
</form>
<span id="results" /></span>
</body>
</html>
It gives error before head is loaded first and it cannot find element with id specified.
The below code is correction:
<html xmlns="http://www.w3.org/1999/xhtml">
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Unit Teachers</title>
<head>
<script type="text/javascript" src="getTeachers.js"></script>
</head>
<body>
<form>
<input type = "button" id="buttonId" value = "Press for Results" /><br />
</form>
<script type="text/javascript">
document.getElementById("buttonId").onclick=function(){getResults()};
</script>
<span id="results" /></span>
</body>
</html>
If your script refers to an ID on the page and the page has not been rendered (i.e. script is before HTML, or your script is executed with onload, rather then the DOM is ready) you can also get an error.
It doesn't. Most programming framework scatter scripts all throughout the page. I've only rarely seen problems because of that (and only from older browsers).
If you pull Javascripts in through XMLHttpRequest, like Diodeus said, it probably won't work. In my case, there was no error, the browser just ignores the new script(s).
I ended up using this, not terribly elegant but works for me so far:
http://zeta-puppis.com/2006/03/07/javascript-script-execution-in-innerhtml-the-revenge/
How to use execJS: http://zeta-puppis.com/2006/02/23/javascript-script-execution-in-innerhtml/
Note: Watch out for < in this line: for(var i=0;i<st.length; i++)
If you have an inline script (outside functions) located before functions it may call, you may get an error because they may not be not available yet. Not saying it is always going to happen, just that it may depending on browser type or version.
Javascript's scoping rules are similar to perl - you can call any function at the current or any higher scope level. The only restriction is that the function has to be defined at the time you call it. The position in the source is irrelevant - only the position in time matters.
You should avoid putting scripts in the <head> if possible as it slows down page display (see the link Alan posted).

Categories

Resources