Unfuck Farnell's Website in Opera

Farnell, as is well known, are a very useful supplier of electronic components, and their website has pretty good facilities for sorting through their enormous stock list. However, in Opera at least, on certain pages there lurks a dog's cunt.

What happens is that the page begins to load, and then the entire sodding browser locks up and stays that way for over a minute. When it finally unfreezes the page is fucked: the list of select-options boxes is not there and sometimes the listings aren't there either. Sometimes reloading the page gets them to show up (after another minute-plus swearing break) but more often it does not, and even if it does the extreme slowness is a pain in the fucking arse.

This only happens on the pages for types of components of which there are several thousand varieties - for example the page for discrete MOSFETs has, at the time of writing, 6744 entries, and it does not fucking work at all.

The reason for this is that on those pages, the select-options boxes bit accounts for some 2MB of HTML, which is all tags and each tag has its own individual attributes. When you feed it such a sodding massive chunk of complex HTML, Opera chokes. And to make matters worse, the stupid way they load this section both makes the problem twice as bad to start with, and makes it not show up at all after all the wait.

What they do is, instead of loading the select-options boxes bit along with all the rest of the page, they load it in a hidden iframe. Fuck knows why. Comments in the code claim that it is to "improve the load sequence", but what it actually does is fuck the load sequence up. When the iframe has loaded, it extracts its innerHTML, as a string, and sticks it into the innerHTML of the div which is waiting to receive the select-options boxes.

So what happens is that the sodding massive chunk of HTML gets parsed twice - once in the iframe, and a second time when it is injected as a string into the parent document. Fucksake. And then there is a fucking timeout on the loading; if the timeout is exceeded the stuff will not be displayed, even if it does become available after the timeout. So it can clearly be seen that this idiotic loading method both doubles the already grossly excessive time taken to do it, and then decides that it took too long so it's not going to show the results anyway even though it fucking could now, and the whole operation was a waste.

Well, I got really fucked off with this shit and wrote a UserJS to fix it. Opera is perfectly capable of parsing all that HTML in a reasonable time as long as it gets it in separate chunks instead of one huge sodding massive lump. So that is what this script does: it loads the content one select-options-box at a time, instead of all at once, and fuck me does it speed it up.

Knocking out iframes from a UserJS is a pain in the arse because there is no event that fires before the buggers start to load to enable you to intercept it and delete them instead. So this script uses Pigeon's Patent Opera Iframe Frig: it kills them off from the inside, by doing a document.write() as soon as the iframe loads the UserJS. This has the effect of halting the loading, and you end up with an empty iframe. The parent document then retrieves the relevant URL using XMLHttpRequest, which just treats the data as a blob and does not try to parse it.

Once it has done this it goes through the unparsed HTML, copies the content of the select-options divs and associated dropdowns into separate strings, and deletes them from the blob. The vastly-simplified blob is then injected into the relevant div in the page. After this the strings are injected back into their original elements, one at a time. By this means the HTML is parsed in several separate reasonably-small bits instead of a sodding huge chunk. And, of course, it does not do the fucking stupid parse-it-twice thing.

It also incorporates another little tweak: the original code loads this content into a full-width div down at the bottom of the page, then reduces the div's width so it pops up to the top. Apart from being completely fucking pointless this introduces another annoying delay while the page reflows itself. So this script reduces the div's width before it loads its content; that way the reflowing happens on a very much simpler page and is accordingly a lot quicker.

Download the script: farnell.js

// ==UserScript== // @include http://*.farnell.com/* // ==/UserScript== function fuckSoddingMassiveIframe() { var getContentEvent = new CustomEvent('getContent', { detail: { name: 'Get content' }, bubbles: false, cancelable: false }); function gcw(i) { var e = (i == 'body' ? document.body : document.getElementById(i)); return(parseInt(getComputedStyle(e).getPropertyValue('width'))); } function removeCruft() { var a, i, d; d = document.getElementById('paramFiltersBasePlaceholder').getElementsByClassName('filterType'); a = new Array(); for (i = d.length - 1; i >= 0; --i) a.push(d[i]); while (i = a.pop()) { i.removeEventListener('getContent', fetchContent); i.contentStuff = null; } } function fetchContent(ev) { var e = ev.currentTarget; var s = e.getElementsByTagName('select'); e.getElementsByTagName('div')[0].innerHTML = e.contentStuff.divContent; s[0].innerHTML = e.contentStuff.firstSelectContent; s[1].innerHTML = e.contentStuff.secondSelectContent; if (e.contentStuff.nextDiv) { setTimeout(function() { e.contentStuff.nextDiv.dispatchEvent(getContentEvent); }, 10); } else { globalIFrameLoaded = true; setTimeout(removeCruft, 10); } } function handleResponse(t) { var d = document.getElementById('paramFiltersBasePlaceholder'); var h = ''; var i = 0, o = 0; var g = new Array(); var e = gcw('body') - gcw('filterCol'); d.parentNode.style.width = (e - 75) + 'px'; while ((i = t.indexOf('<div class="scrollHolder">', o)) >= 0 ) { e = new Object(); i += 26; h += t.substring(o, i); o = t.indexOf('</div>', i); e.divContent = t.substring(i, o); i = t.indexOf('<select', o); i = t.indexOf('>', i) + 1; h += t.substring(o, i); o = t.indexOf('</select>', i); e.firstSelectContent = t.substring(i, o); i = t.indexOf('<select', o); i = t.indexOf('>', i) + 1; h += t.substring(o, i); o = t.indexOf('</select>', i); e.secondSelectContent = t.substring(i, o); g.push(e); } h += t.substr(o); d.innerHTML = h; document.getElementById('para').style.width = (e - 116) + 'px'; e = d.getElementsByClassName('filterType'); for (i = 0; i < e.length; i++) { e[i].contentStuff = g.shift(); e[i].contentStuff.nextDiv = (i > 0 ? e[i - 1] : null); e[i].addEventListener('getContent', fetchContent, false); } setTimeout(function() { e[e.length - 1].dispatchEvent(getContentEvent); }, 10); } function fuckIframes() { var x, i, f = document.getElementsByTagName('iframe'); for (i = 0; i < f.length; i++) if (f[i].src.indexOf('GetParametricFilters' >= 0)) { x = new AnonXMLHttpRequest(); x.onreadystatechange = function() { if (this.readyState != 4) return; if (this.status == 200) { handleResponse(this.responseText); } else { alert('XHR Error: ' + this.status + ' ' + this.statusText); } }; x.open('GET', f[i].src, true); x.send(); f[i].parentNode.removeChild(f[i]); break; } } if (location.href.indexOf('GetParametricFilters') >= 0) { document.write('stop'); // Causes page loading to be aborted } else { window.opera.addEventListener('BeforeEvent.DOMContentLoaded', fuckIframes, true); } } fuckSoddingMassiveIframe();

Back to Pigeon's Nest

Be kind to pigeons

Valid HTML 4.01!