/* Copyright (c) 2004-2006, The Dojo Foundation All Rights Reserved. Licensed under the Academic Free License version 2.1 or above OR the modified BSD license. For more information on Dojo licensing, see: http://dojotoolkit.org/community/licensing.shtml */ dojo.provide("dojo.event"); dojo.require("dojo.lang.array"); dojo.require("dojo.lang.extras"); dojo.require("dojo.lang.func"); dojo.event = new function(){ this.canTimeout = dojo.lang.isFunction(dj_global["setTimeout"])||dojo.lang.isAlien(dj_global["setTimeout"]); // FIXME: where should we put this method (not here!)? function interpolateArgs(args, searchForNames){ var dl = dojo.lang; var ao = { srcObj: dj_global, srcFunc: null, adviceObj: dj_global, adviceFunc: null, aroundObj: null, aroundFunc: null, adviceType: (args.length>2) ? args[0] : "after", precedence: "last", once: false, delay: null, rate: 0, adviceMsg: false }; switch(args.length){ case 0: return; case 1: return; case 2: ao.srcFunc = args[0]; ao.adviceFunc = args[1]; break; case 3: if((dl.isObject(args[0]))&&(dl.isString(args[1]))&&(dl.isString(args[2]))){ ao.adviceType = "after"; ao.srcObj = args[0]; ao.srcFunc = args[1]; ao.adviceFunc = args[2]; }else if((dl.isString(args[1]))&&(dl.isString(args[2]))){ ao.srcFunc = args[1]; ao.adviceFunc = args[2]; }else if((dl.isObject(args[0]))&&(dl.isString(args[1]))&&(dl.isFunction(args[2]))){ ao.adviceType = "after"; ao.srcObj = args[0]; ao.srcFunc = args[1]; var tmpName = dl.nameAnonFunc(args[2], ao.adviceObj, searchForNames); ao.adviceFunc = tmpName; }else if((dl.isFunction(args[0]))&&(dl.isObject(args[1]))&&(dl.isString(args[2]))){ ao.adviceType = "after"; ao.srcObj = dj_global; var tmpName = dl.nameAnonFunc(args[0], ao.srcObj, searchForNames); ao.srcFunc = tmpName; ao.adviceObj = args[1]; ao.adviceFunc = args[2]; } break; case 4: if((dl.isObject(args[0]))&&(dl.isObject(args[2]))){ // we can assume that we've got an old-style "connect" from // the sigslot school of event attachment. We therefore // assume after-advice. ao.adviceType = "after"; ao.srcObj = args[0]; ao.srcFunc = args[1]; ao.adviceObj = args[2]; ao.adviceFunc = args[3]; }else if((dl.isString(args[0]))&&(dl.isString(args[1]))&&(dl.isObject(args[2]))){ ao.adviceType = args[0]; ao.srcObj = dj_global; ao.srcFunc = args[1]; ao.adviceObj = args[2]; ao.adviceFunc = args[3]; }else if((dl.isString(args[0]))&&(dl.isFunction(args[1]))&&(dl.isObject(args[2]))){ ao.adviceType = args[0]; ao.srcObj = dj_global; var tmpName = dl.nameAnonFunc(args[1], dj_global, searchForNames); ao.srcFunc = tmpName; ao.adviceObj = args[2]; ao.adviceFunc = args[3]; }else if((dl.isString(args[0]))&&(dl.isObject(args[1]))&&(dl.isString(args[2]))&&(dl.isFunction(args[3]))){ ao.srcObj = args[1]; ao.srcFunc = args[2]; var tmpName = dl.nameAnonFunc(args[3], dj_global, searchForNames); ao.adviceObj = dj_global; ao.adviceFunc = tmpName; }else if(dl.isObject(args[1])){ ao.srcObj = args[1]; ao.srcFunc = args[2]; ao.adviceObj = dj_global; ao.adviceFunc = args[3]; }else if(dl.isObject(args[2])){ ao.srcObj = dj_global; ao.srcFunc = args[1]; ao.adviceObj = args[2]; ao.adviceFunc = args[3]; }else{ ao.srcObj = ao.adviceObj = ao.aroundObj = dj_global; ao.srcFunc = args[1]; ao.adviceFunc = args[2]; ao.aroundFunc = args[3]; } break; case 6: ao.srcObj = args[1]; ao.srcFunc = args[2]; ao.adviceObj = args[3] ao.adviceFunc = args[4]; ao.aroundFunc = args[5]; ao.aroundObj = dj_global; break; default: ao.srcObj = args[1]; ao.srcFunc = args[2]; ao.adviceObj = args[3] ao.adviceFunc = args[4]; ao.aroundObj = args[5]; ao.aroundFunc = args[6]; ao.once = args[7]; ao.delay = args[8]; ao.rate = args[9]; ao.adviceMsg = args[10]; break; } if(dl.isFunction(ao.aroundFunc)){ var tmpName = dl.nameAnonFunc(ao.aroundFunc, ao.aroundObj, searchForNames); ao.aroundFunc = tmpName; } if(dl.isFunction(ao.srcFunc)){ ao.srcFunc = dl.getNameInObj(ao.srcObj, ao.srcFunc); } if(dl.isFunction(ao.adviceFunc)){ ao.adviceFunc = dl.getNameInObj(ao.adviceObj, ao.adviceFunc); } if((ao.aroundObj)&&(dl.isFunction(ao.aroundFunc))){ ao.aroundFunc = dl.getNameInObj(ao.aroundObj, ao.aroundFunc); } if(!ao.srcObj){ dojo.raise("bad srcObj for srcFunc: "+ao.srcFunc); } if(!ao.adviceObj){ dojo.raise("bad adviceObj for adviceFunc: "+ao.adviceFunc); } return ao; } this.connect = function(){ if(arguments.length == 1){ var ao = arguments[0]; }else{ var ao = interpolateArgs(arguments, true); } if(dojo.lang.isArray(ao.srcObj) && ao.srcObj!=""){ var tmpAO = {}; for(var x in ao){ tmpAO[x] = ao[x]; } var mjps = []; dojo.lang.forEach(ao.srcObj, function(src){ if((dojo.render.html.capable)&&(dojo.lang.isString(src))){ src = dojo.byId(src); // dojo.debug(src); } tmpAO.srcObj = src; // dojo.debug(tmpAO.srcObj, tmpAO.srcFunc); // dojo.debug(tmpAO.adviceObj, tmpAO.adviceFunc); mjps.push(dojo.event.connect.call(dojo.event, tmpAO)); }); return mjps; } // FIXME: just doing a "getForMethod()" seems to be enough to put this into infinite recursion!! var mjp = dojo.event.MethodJoinPoint.getForMethod(ao.srcObj, ao.srcFunc); if(ao.adviceFunc){ var mjp2 = dojo.event.MethodJoinPoint.getForMethod(ao.adviceObj, ao.adviceFunc); } mjp.kwAddAdvice(ao); return mjp; // advanced users might want to fsck w/ the join point // manually } this.log = function(a1, a2){ var kwArgs; if((arguments.length == 1)&&(typeof a1 == "object")){ kwArgs = a1; }else{ kwArgs = { srcObj: a1, srcFunc: a2 }; } kwArgs.adviceFunc = function(){ var argsStr = []; for(var x=0; x= this.jp_.around.length){ return this.jp_.object[this.jp_.methodname].apply(this.jp_.object, this.args); // return this.jp_.run_before_after(this.object, this.args); }else{ var ti = this.jp_.around[this.around_index]; var mobj = ti[0]||dj_global; var meth = ti[1]; return mobj[meth].call(mobj, this); } } dojo.event.MethodJoinPoint = function(obj, methname){ this.object = obj||dj_global; this.methodname = methname; this.methodfunc = this.object[methname]; this.before = []; this.after = []; this.around = []; } dojo.event.MethodJoinPoint.getForMethod = function(obj, methname) { // if(!(methname in obj)){ if(!obj){ obj = dj_global; } if(!obj[methname]){ // supply a do-nothing method implementation obj[methname] = function(){}; if(!obj[methname]){ // e.g. cannot add to inbuilt objects in IE6 dojo.raise("Cannot set do-nothing method on that object "+methname); } }else if((!dojo.lang.isFunction(obj[methname]))&&(!dojo.lang.isAlien(obj[methname]))){ return null; // FIXME: should we throw an exception here instead? } // we hide our joinpoint instance in obj[methname + '$joinpoint'] var jpname = methname + "$joinpoint"; var jpfuncname = methname + "$joinpoint$method"; var joinpoint = obj[jpname]; if(!joinpoint){ var isNode = false; if(dojo.event["browser"]){ if( (obj["attachEvent"])|| (obj["nodeType"])|| (obj["addEventListener"]) ){ isNode = true; dojo.event.browser.addClobberNodeAttrs(obj, [jpname, jpfuncname, methname]); } } var origArity = obj[methname].length; obj[jpfuncname] = obj[methname]; // joinpoint = obj[jpname] = new dojo.event.MethodJoinPoint(obj, methname); joinpoint = obj[jpname] = new dojo.event.MethodJoinPoint(obj, jpfuncname); obj[methname] = function(){ var args = []; if((isNode)&&(!arguments.length)){ var evt = null; try{ if(obj.ownerDocument){ evt = obj.ownerDocument.parentWindow.event; }else if(obj.documentElement){ evt = obj.documentElement.ownerDocument.parentWindow.event; }else{ evt = window.event; } }catch(e){ evt = window.event; } if(evt){ args.push(dojo.event.browser.fixEvent(evt, this)); } }else{ for(var x=0; x0){ dojo.lang.forEach(this.before, unrollAdvice); } var result; if(this.around.length>0){ var mi = new dojo.event.MethodInvocation(this, obj, args); result = mi.proceed(); }else if(this.methodfunc){ result = this.object[this.methodname].apply(this.object, args); } if(this.after.length>0){ dojo.lang.forEach(this.after, unrollAdvice); } return (this.methodfunc) ? result : null; }, getArr: function(kind){ var arr = this.after; // FIXME: we should be able to do this through props or Array.in() if((typeof kind == "string")&&(kind.indexOf("before")!=-1)){ arr = this.before; }else if(kind=="around"){ arr = this.around; } return arr; }, kwAddAdvice: function(args){ this.addAdvice( args["adviceObj"], args["adviceFunc"], args["aroundObj"], args["aroundFunc"], args["adviceType"], args["precedence"], args["once"], args["delay"], args["rate"], args["adviceMsg"]); }, addAdvice: function( thisAdviceObj, thisAdvice, thisAroundObj, thisAround, advice_kind, precedence, once, delay, rate, asMessage){ var arr = this.getArr(advice_kind); if(!arr){ dojo.raise("bad this: " + this); } var ao = [thisAdviceObj, thisAdvice, thisAroundObj, thisAround, delay, rate, asMessage]; if(once){ if(this.hasAdvice(thisAdviceObj, thisAdvice, advice_kind, arr) >= 0){ return; } } if(precedence == "first"){ arr.unshift(ao); }else{ arr.push(ao); } }, hasAdvice: function(thisAdviceObj, thisAdvice, advice_kind, arr){ if(!arr){ arr = this.getArr(advice_kind); } var ind = -1; for(var x=0; x