Skip navigation.

My comments on ...

... everything bothering me

Posts tagged with "IE"

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.

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
}

November 2009
M T W T F S S
October 2009December 2009
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