Old JavaScript Function Crashes Browser - javascript

I'm integrating a mootools script onto a page which has very old JavaScript functions which run a navigation vertical menu. This old script will be hard to change now.
The line breaking is:
function stgobj(id) {
with(document) return nIE && nVER < 5 ? all[id] : nNN4 ? layers[id] : getElementById(id);
}
Not sure exactly what's it's purpose, but it looks like it's rendering some elements. If commented the menu will disappear.
FF, Chrome, IE(doesn't crash, but menu does not render)
Any quick patch to resolve the browsers crashing?

Looks like its purpose is to return the element corresponding to the given ID. The code simply uses some different methods based on the browser - document.all for IE5 and earlier, and document.layers for Netscape 4. Unless you need to support those ancient browsers, you could alter the function to return just document.getElementById(id). Or better yet, ditch this function altogether and call document.getElementById directly.
However, if it's crashing modern browsers like Firefox and Chrome, then you should also look at the browser detection logic (the code that populates the nIE, nVER and nNN4 variables), otherwise it might just end up crashing elsewhere.

It's a "compatibility" function for document.getElementById. I think you should be able to equal it:
stgobj = document.getElementById.bind(document);

Related

How to make this code compatible with IE7?

This code works in all browsers except for older IE versions. It'll be accessed by users, some of whom are still using IE7. I'm not a coder and the author isn't available until next week so I'm at loss how to refactor it so that all browsers show only the options defined in chk.
for (var x=1;x<5;x++){
var st='select[name="Score_'+x+'e"] option';
$(st).each(function(){
var chk=',0,1,2,3,4,5,,,,,,--,';
var sn=','+$.trim(this.innerHTML)+',';
if (chk.indexOf(sn)==-1){$(this).hide();}
});
st='#tableScoringInfoBox'+x+' strong';
$(st).html('1-10 Ratings explained');
}
A quick fix would be to simply replace .hide() with .remove(), though there's no way of knowing without seeing more code if that will impact something else.

Disabling JIT in Safari 6 to workaround severe Javascript JIT bugs

We found a severe problem with the interpretation of our Javascript code that only occurs on iOS 5/Safari 6 (then current iPad release) that we think is due to critical bug in the Just in Time JS compiler in Safari. (See updates below for more affected versions and versions that seem to now contain a fix).
We originally found the issue in our online demos of our library: the demos crash more or less randomly but this happens only the second time (or even later) that the same code is executed. I.e. if you run the part of the code once, everything works OK, however subsequent runs crash the application.
Interestingly executing the same code in Chrome for iOS the problem does not show, which we believe is due to the missing JIT capabilities of the Webview that is used in Chrome for iOS.
After a lot of fiddling we finally think we found at least one problematic piece of code:
var a = 0; // counter for index
for (var b = this.getStart(); b !== null; b = b.getNext()) // iterate over all cells
b.$f = a++; // assign index to cell and then increment
In essence this is a simple for loop that assigns each cell in a linked list data structure its index. The problem here is the post-increment operation in the loop body. The current count is assigned to the field and updated after the expression is evaluated, basically the same as first assigning a and then incrementing it by one.
This works OK in all browsers we tested and in Safari for the first couple of times, and then suddenly it seems as if the counter variable a is incremented first and then the result is assigned, like a pre-increment operation.
I have created a fiddle that shows the problem here: http://jsfiddle.net/yGuy/L6t5G/
Running the example on an iPad 2 with iOS 6 and all updates the result is OK for the first 2 runs in my case and in the third identic run suddenly the last element in the list has a value assigned that is off by one (the output when you click the "click me" button changes from "from 0 to 500" to "from 0 to 501")
Interestingly if you switch tabs, or wait a little it can happen that suddenly the results are correct for two or so more runs! It seems as if Safari sometimes resets is JIT caches.
So since I think it may take a very long for the Safari team to fix this bug (which I have not yet reported) and there may be other similar bugs like this lurking in the JIT that are equally hard to find, I would like to know whether there is a way to disable the JIT functionality in Safari. Of course this would slow down our code (which is very CPU intensive already), but better slow than crashing.
Update:
Unsurprisingly it's not just the post increment operator that is affected, but also the post decrement operator. Less surprisingly and more worryingly is that it makes no difference if the value is assigned, so looking for an assignment in existing code is not enough. E.g. the following the code b.$f = (a++ % 2 == 0) ? 1 : 2; where the variables value is not assigned but just used for the ternary operator condition also "fails" in the sense that sometimes the wrong branch is chosen. Currently it looks as if the problem can only be avoided if the post operators are not used at all.
Update:
The same issue does not only exist in iOS devices, but also on Mac OSX in Safari 6 and the latest Safari 5:
These have been tested and found to be affected by the bug:
Mac OS 10.7.4, Safari 5.1.7
Mac OS X 10.8.2, WebKit Nightly r132968: Safari 6.0.1 (8536.26.14, 537+). Interestingly these do not seem to be affected: iPad 2 (Mobile) Safari 5.1.7, and iPad 1 Mobile Safari 5.1. I have reported these problems to Apple but have not received any response, yet.
Update:
The bug has been reported as Webkit bug 109036. Apple still has not responded to my bug report, all current (February 2013) Safari versions on iOS and MacOS are still affected by the problem.
Update 27th of February 2013:
It seems the bug has been fixed by the Webkit team here! It was indeed a problem with the JIT and the post-operators! The comments indicate that more code might have been affected by the bug, so it could be that more mysterious Heisenbugs have been fixed, now!
Update October 2013:
The fix finally made it into production code: iOS 7.0.2 at least on iPad2 does not seem to suffer from this bug anymore. I did not check all of the intermediate versions, though, since we worked around the problem a long time ago.
Try-catch blocks seem to disable the JIT compiler on Safari 6 on Lion for the part directly inside the try block (this code worked for me on Safari 6.0.1 7536.26.14 and OS X Lion).
// test function
utility.test = function(){
try {
var a = 0; // counter for index
for (var b = this.getStart(); b !== null; b = b.getNext()) // iterate over all cells
b.$f = a++; // assign index to cell and then increment
}
catch (e) { throw e }
this.$f5 = !1; // random code
};
This is at least a documented behavior of the current version of Google's V8 (see the Google I/O presentation on V8), but I don't know for Safari.
If you want to disable it for the whole script, one solution would be to compile your JS to wrap every function's content inside a try-catch with a tool such as burrito.
Good job on making this reproducible!
IMO, the correct solution is to report the bug to Apple, then workaround it in your code (surely using a separate a = a + 1; statement will work, unless the JIT is even worse than you thought!). It does indeed suck, though. Here's a list of common things you can also try throwing in to the function to make it de-optimise and not use JIT:
Exceptions
'with' statement
using arguments object, e.g. arguments.callee
eval()
The problem with those is if the Javascript engine is optimised to JIT them before they fix that bug, in which case you're back to crashing. So, report and workaround!
Actually, the FOR loop bug is still present in Safari on iOS 7.0.4 in iPhone 4 and iPad 2. The loop failing can be significantly simpler than the illustration above, and it rakes several passes through the code to hit. Changing to a WHILE loop allows proper execution.
Failing code:
function zf(num,digs)
{
var out = "";
var n = Math.abs(num);
for (digs; digs>0||n>0; digs--)
{
out = n%10 + out;
n = Math.floor(n/10);
}
return num<0?"-"+out:out;
}
Successful code:
function zf(num,digs)
{
var out = "";
var n = Math.abs(num);
do
{
out = n%10 + out;
n = Math.floor(n/10);
}
while (--digs>0||n>0)
return num<0?"-"+out:out;
}

IE Object doesn't support this property or method

This is probably the beginning of many questions to come.
I have finished building my site and I was using Firefox to view and test the site. I am now IE fixing and am stuck at the first JavaScript error which only IE seems to be throwing a hissy about.
I run the IE 8 JavaScript debugger and get this:
Object doesn't support this property or method app.js, line 1 character 1
Source of app.js (first 5 lines):
var menu = {};
menu.current = "";
menu.first = true;
menu.titleBase = "";
menu.init = function(){...
I have tested the site in a Webkit browser and it works fine in that.
What can I do to fix this? The site is pretty jQuery intensive so i have given up any hope for getting it to work in IE6 but I would appreciate it working in all the others.
UPDATE: I have upload the latest version of my site to http://www.frankychanyau.com
In IE8, your code is causing jQuery to fail on this line
$("title").text(title);
in the menu.updateTitle() function. Doing a bit of research (i.e. searching with Google), it seems that you might have to use document.title with IE.
Your issue is (probably) here:
menu.updateTitle = function(hash){
var title = menu.titleBase + ": " + $(hash).data("title");
$("title").text(title); // IE fails on setting title property
};
I can't be bothered to track down why jQuery's text() method fails here, but it does. In any case, it's much simpler to not use it. There is a title property of the document object that is the content of the document's title element. It isn't marked readonly, so to set its value you can simply assign a new one:
document.title = title;
and IE is happy with that.
It is a good idea to directly access DOM properties wherever possible and not use jQuery's equivalent methods. Property access is less troublesome and (very much) faster, usually with less code.
Well, your line 1 certainly looks straight forward enough. Assuming the error line and number is not erroneous, it makes me think there is a hidden character in the first spot of your js file that is throwing IE for a fit. Try opening the file in another text editor that may support display of normally hidden characters. Sometimes copying/pasting the source into a super-basic text-editor, like Notepad, can sometimes strip out non-displayable characters and then save it back into place directly from Notepad.

IE won't split string with Javascript

I have the following code:
$('#smallcart .plusone').live('click',function(){
var id = $(this).attr('id');
articlenr = id.split('_')[1];
});
this works fine in FF, safari, Chrome, however in IE (7 and 8) it throws an error on the split-function (this property or method is not supported by this object).
if I alert the 'id'-variable I get something like plus_5751. (so I want to get the '5751' part)
if I do alert(typeof(id)) I get String as an answer...
Maybe somebody can point me to the right answer?
Thx
The split works pretty well in IE. The problem is the part left of the equal-sign. It's an object with all input-fields having the name articlenr and therefor IE quits with 'this property or method is not supported by this object' when you're trying to assign a string to it.
Your code works just fine for me in Internet Explorer - as it should be expected to. The problem must lie elsewhere, perhaps something is overriding String.prototype.split?. You can see a working example of your code at http://jsfiddle.net/AndyE/6K77Y/. The first thing to check for is any Internet Explorer specific code in your scripts.
I would make one small improvement for efficiency. $(this).attr('id'); is pretty much the long winded way of writing this.id. It's slower, because a new jQuery object has to be created and then the attr function has to run. Without it, your code can be compressed more, whilst still remaining very readable, if you like:
$('#smallcart .plusone').live('click',function(){
articlenr = this.id.split('_')[1];
});
Try renaming your variable 'id' to something else. IE doesn't like it when you name things in your scripts the same as items in the DOM.
Never mind, that seems to have not been the issue in this case. I have, however, had issues in the past with IE specific bugs caused by variable names.

LightWindow & IE7, "Line 444 - object does not support this property or method"

I have just received and bypassed a problem with LightWindow and IE7 where, on page load, it throws a JavaScript error on line 444 of lightwindow.js, claiming that the object does not support this property or method. Despite finding various postings on various forums, no Google result I could find had a solution, so I am posting this here in the hopes that it will help someone / myself later.
Many suggested a specific order of the script files but I was already using this order (prototype, scriptaculous, lightwindow).
These are the steps I took that seemed to finally work, I write them here only as a record as I do not know nor have time to test which ones specifically "fixed" the issue:
Moved the call to lightwindow.js to the bottom of the page.
Changed line 444 to: if (this._getGalleryInfo(link.rel)) {
Changed line 1157 to: if (this._getGalleryInfo(this.element.rel)) {
Finally, I enclosed (and this is dirty, my apologies) lines 1417 to 1474 with a try/catch block, swallowing the exception.
EDIT:
I realised that this broke Firefox. Adding the following as line 445 now makes it work - try { gallery = this._getGalleryInfo(link.rel); } catch (e) { }
It's not a very nice fix, but my page (which contains a lightwindow link with no "rel" tag, several lightwindow links which do have "rel" tags, and one "inline" link) works just fine in IE7 now. Please comment if you have anything to add about this issue or problems with / improvements to my given solution.
Instead of the try..catch maybe you could try using
if( this && this._getGalleryInfo )
{
//use the function
}
you could also check in the same way this.element.rel ( if(this && this.element && this.element.rel) ... ) before using it.
It looks like there's a case that the _getGalleryInfo or this.element.rel has not yet been initialized so it wouldn't exist yet. Check if it exists then if I does use it.
of course i could be completely wrong, the only way to know is by testing it out.
I fixed this by changing line 444 to:
var gallery = this._getGalleryInfo(link.rel)
Then changing the subsequent comparison statement to:
if(gallery.length > 0)
{
// Rest of code here...
...which seems to have sorted it in IE6+ and kept it working in Firefox etc.
I didn't change line 1157 at all, but I haven't read the code to see what I actually does so I can't comment on its relevance?
I suspect the ? used in the example rel attribute (Evoution?[man]) may be causing the problem with IE but without spending some time testing a few things, I can't be sure?
HTH.
I had the same problem with Lightwindow 2.0, IE6, IE7, IE8 (beta); I resolved in the following way for IE6, IE7, IE8 (beta).
Instead of:
if(gallery = this._getGalleryInfo(link.rel))
I put on lines 443 and 1157:
gallery = this._getGalleryInfo(link.rel)
if(gallery)
Hope this will help!

Categories

Resources