My comments on ...

... everything bothering me

Subscribe to RSS feed

Drop in average intelligence on MyOpera

This is a response to the comments on this post.

I hate how people read digg, then instead of posting their irrelevant opinions on digg, where they can be smoten down by the collective opinion of diggers, come here to spam this post with idiotic comments. Seriously, I've never seen this many morons in one place on MyOpera.

  1. You don't get it. Three-letter-company should have tested in their client's browser if they wanted the contract. So either they didn't really want it or they're idiots. Full-stop, no arguing.
  2. Nobody wants to hear your misconceptions about Opera, browsers, and the web in general. Shut up. Seriously, shut up!
  3. Stop using 'fail' as the new symbol of your retarded internet-hype-religion. It's stupid. Talk English.

Wrapping DOM functions — revisited

, ,

A while back I "discovered" a way to wrap DOM functions in IE to make it more alike normal Ecmascript functions. With valuable input from liorean I found this to be the only workable solution (sadly)...

edit: Just to make this clear: You can only use this method to call functions on objects that already possess a method of that name.

This one does use a closure and I bet it does leak memory in IE... I just don't care p

function wrapDOMf (scope,func) {
    /* ensure proper usage (no type checking though) */
    if(!(scope && typeof func == "string" && scope[func]))
       return;

    scope[func] = function(){
        return Function.prototype.apply.call(this[func],this,arguments);
    };
}


The new versions of wrapFunc and wrapFuncBefore were changed in a similar way:

function wrapFunc (scope,func,hijack) {
    if(!(scope && typeof func == "string" && scope[func]))
       return; //ensure proper usage

    if(!(hijack && hijack instanceof Function))
       hijack = function(x){return x}; //if no hijack exists, f(x)=x

    scope[func] = function() {
        var obj = Function.prototype.apply.call(this[func],this,arguments)
        /* 'hijack' is passed the output object and all the arguments */
        return hijack.call(this,obj,arguments);
    };
}


function wrapFuncBefore (scope,func,hijack) {
    if(!(scope && typeof func == "string" && scope[func]))
       return; //ensure proper usage

    if(!(hijack && hijack instanceof Function))
       hijack = function(){return [this,arguments]};

    scope[func] = function() {
        var temp = hijack.apply(this,arguments);
        var that = temp[0];
        var args = temp[1];
        return Function.prototype.apply.call(that[func],that,args);
    };
}


Feel free to correct where I'm wrong.

The "classic example" — revisited

My previous posts on this topic needed attention... so rather than fixing in-place here the new version:

if(!document.getElementById)
{
 (function(){
   var obj = document.all || document.layers || {};
   document.getElementById = function getElementById(id){return obj[id] || null};
  }
 )();
}

Safari and HTMLElement.prototype

, ,

As you all know, Safari does not support HTMLElement, which makes it hard to add stuff to all newly created HTML-Elements, Nodes, whatever you might call it.

Fortunately, it supports the semi-standard __proto__ property. Exploiting another "bug", that all HTMLElement(s) are produced from the same prototype, I came up with a neat solution that even works in Safari 1.3 and you can replace functions such as "getAttribute" (go figure!).

var w = window;
if(!w.HTMLElement&&(typeof document.createElement)=="function" // check basics
   &&(var t=document.createElement('a').__proto__) // '__proto__' supported?
   &&t==document.createElement('p').__proto__){ // all HTMLElements the same?
   w.HTMLElement={}; // prevent people from constructing
   w.HTMLElement.prototype=t;
}

This piece uses perfect object detection, i.e. every browser that works this way will be fixed (i.e. all supporting Safaris, maybe KHTML?), while leaving browsers that work differently untouched.

Remember: You saw it here first!

PS: Best used inside a closure, e.g. (function(){ [your code here] })().

n-Dimensional Arrays

function nD(){
   var A,tempA; //final and temp array
   var dimension=arguments.length, i; //iteration vars
   while(dimension--){
      tempA = Array(arguments[dimension]);
      i = tempA.length;
      while(i--)
         tempA[i]=A.slice(0);
      A = tempA;
   }
   return A;
};

function check(A){
   return (""+A).split(",").length;
};

var test = nD(3,3,3); //create 3x3x3 'cube'
alert(test);
alert(check(test))); //check 'volume'


Or the short version:
l='length';

function nD(){
   var a,b,c=arguments,d=c[l],i;
   while(d--){
      i = (b = Array(c[d]))[l];
      while(i--)
         b[i]=a.slice(0);
      a = b;
   }
   return a;
};

function check(a){
   return (""+a).split(",")[l];
};

alert(nD(3,3,3));
alert(check(nD(3,3,3)));

Wrapping IE's DOM functions

, ,

Many people are irritated by the fact that IE's DOM functions (which are really COM objects) don't support the "call" and "apply" methods. Transfering those methods from a function object to a COM object throws errors. People invented a weird hack involving the Function() constructor to overcome this issue, but I think I know better. I don't know if I'm the first one to come up with it (probably not), but I found a "standard" way to make an arbitrary DOM function into a real Ecmascript function. As a very easy test case, type this javascript url into IE:
javascript:alert(Function.prototype.call.call(document.createElement,document,'p'))
This will produce a new paragraph (

) Element. You can change the string to any valid value. And now the annotated minimised version of the wrapDOMf function:

function wrapDOMf (scope,func)
{
    if(!(scope && typeof func == "string" && scope[func])) return; //ensure proper usage; no type checking

    var storage = arguments.callee; //using wrapDOMf as temporary storage
    storage.orig = scope[func];
    scope[func] = function WRAP()
            {
                return Function.prototype.apply.call(arguments.callee.$original,this,arguments);
            };
    scope[func].$original = storage.orig;
    delete storage.orig; //get rid of any unnecessary references, optional
}
It shouldn't leak memory. If it should turn out to do that, I'll have to sort that out. The minimised version I intend to use is the following (but I don't know about leak-status):
function wrapDOMf (s,f) //scope, function
{
    if(!(s && typeof f == "string" && s[f])) return;

    var m = s[f]; //using local var instead of property
    s[f] = function WRAP()
            {
                return Function.prototype.apply.call(arguments.callee.$original,this,arguments);
            };
    s[f].$original = m;
}
Why I delete the variable at the end [long version only] ? Because that's not where my imagination stopped. I wanted to use a closure to add functionality. We'll want to manipulate the input and output of the function, don't we? I assume we want to change the output most of the cases. Thus, my primary function will do that and only that. The change in the name reflects the new usage: It could be useful for all functions now, not just DOM ones.
function wrapFunc (scope,func,hijack)
{
    if(!(scope && typeof func == "string" && scope[func])) return; //ensure proper usage
    if(!(hijack && hijack instanceof Function)) hijack = function(x){return x}; //if no hijack exists, f(x)=x

    var storage = arguments.callee;
    storage.orig = scope[func];
    scope[func] = function WRAP()
            {
                var obj = Function.prototype.apply.call(arguments.callee.$original,this,arguments)
                return hijack.call(this,obj,arguments); // 'hijack' is passed the output object and all the arguments
            };
    scope[func].$original = storage.orig;
    delete storage.orig; //now mandatory, since we retain closure
}
The one for input manipulation:
function wrapFuncBefore (scope,func,hijack)
{
    if(!(scope && typeof func == "string" && scope[func])) return; //ensure proper usage
    if(!(hijack && hijack instanceof Function)) hijack = function(){return [this,arguments]};

    var storage = arguments.callee;
    storage.orig = scope[func];
    scope[func] = function WRAP()
            {
                var temp = hijack.apply(this,arguments); //I want destructuring assignment
                var that = temp[0];
                var args = temp[1];
                return Function.prototype.apply.call(arguments.callee.$original,that,args);
            };
    scope[func].$original = storage.orig;
    delete storage.orig; //now mandatory, since we retain closure
}

Generated Content

Just a little reminder for me and myself.

Opera has a really... funny way to treat script elements with generated comments. I've already created a proper, minimized test case but I am too tired for a bug report right now which is why this post exists.

One good news though: The behavior does not carry on for newly created script elements (imo it only works with those that have a certain property assigned at "parse time"...), i.e. no big exploit possible.

The "classic example", take 2

, , ,

if(!document.getElementById)void()
else
{
   //continue
}

The "classic example"

, ,

Inspired by hallvors' Capability Detection and a follow-up post from Crisp, I tried to improve on the "classic example"...

if (!document.getElementById)
{
   (function()
    {
     var obj = {};
     if (document.all)
     {
       obj = document.all;
     }
     else if (document.layers)
     {
       obj = document.layers;
     }
     document.getElementById = function(id){return obj[id]};
    }
   )();
}

edit: I also thought about really fixing this, as to change the output from "undefined" to "null" in the case that there is no element with that Id (according to spec), but I figured if someone is stupid enough to check explicitly against null or undefined, instead of normal object detection, then he earned the burn. I really can't imagine a scenario where this "feature" of the function is mandatory.

If there ever occurred such a scenario, however... replace

document.getElementById = function(id){return obj[id]};

by

document.getElementById = function(id){return obj[id] ? obj[id] : null};

or, if there are browsers out there that return "undefined" instead of "null" (natively), you might want to add this instead (update 2007/08/28: Don't use, it's dirty)

if (!document.getElementById(null) && document.getElementById(null) !== null)
{
   (function()
    {
     var obj = document;
     var func = 'getElementById';
     var key = '_';
     while (obj[key+func]) {key+=key};
     obj[key+func] = obj[func];
     obj[func] = function(id){return obj[key+func](id) || null}
    }
   )();
}

The better way of Capability Detection, Part 2

, ,

I haven't found time earlier to write this down, so I've made a note with the code attached and do it now wink

In execution of my occupation, last week (or so) I wrote a post "nagging at the nagger". This is round 2, he has given response (he basically says it's not worth the hassle).

I've removed the "finally" part and shortened the most important part down from two lines to one (thereby obscuring it a bit, *sigh*).

Based on a suggestion from Crisp, I wrapped it around an anonymous function, to prevent the variables from being declared in global scope. I've put the function into the condition (as opposed to the other way round), because the program then can tell right away that this function does not need to be executed, as opposed to executing the function and then evaluating the condition.

if (!window.XMLHttpRequest)
{
    (function()
     {
      var temp;
      var types = [
          'MSXML2.XMLHTTP.6.0',
          'MSXML2.XMLHTTP.3.0'
      ];

      for (var i = 0; i < types.length; i++)
      {
          try
          {
              void((temp = function(){return new ActiveXObject(types[i])})());
          }
          catch {temp = null}
          if(temp) break;
      }
      window.XMLHttpRequest = temp || function(){return undefined};
     }
    )();
}


Now, let's have a look at the most tricky part:

void(temp = function(){return new ActiveXObject(types[i])}());

// reformatted looks like this:

void(                                            /* void the result, to protect browsers
                                                    that return/throw "false" or similar */
     (temp = function()                          /* assign a function to the variable... */
            {
               return new ActiveXObject(types[i])
            })()                                 /* and then call it by inserting parenthe-
                                                  ses after those enclosing the function */
     );


Interestingly, I haven't yet tested it, though. Funny thing, that.
June 2012
M T W T F S S
May 2012July 2012
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30