daisydiff.js.dojo.src.event.common.js Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of testcasegenerator Show documentation
Show all versions of testcasegenerator Show documentation
Generates test cases from the crawl session.
The newest version!
/*
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.common");
dojo.require("dojo.lang.array");
dojo.require("dojo.lang.extras");
dojo.require("dojo.lang.func");
// TODO: connection filter functions
// these are functions that accept a method invocation (like around
// advice) and return a boolean based on it. That value determines
// whether or not the connection proceeds. It could "feel" like around
// advice for those who know what it is (calling proceed() or not),
// but I think presenting it as a "filter" and/or calling it with the
// function args and not the MethodInvocation might make it more
// palletable to "normal" users than around-advice currently is
// TODO: execution scope mangling
// YUI's event facility by default executes listeners in the context
// of the source object. This is very odd, but should probably be
// supported as an option (both for the source and for the dest). It
// can be thought of as a connection-specific hitch().
// TODO: more resiliency for 4+ arguments to connect()
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);
}
if(!ao.adviceFunc){
dojo.debug("bad adviceFunc for srcFunc: "+ao.srcFunc);
dojo.debugShallow(ao);
}
return ao;
}
this.connect = function(/*...*/){
// summary:
// dojo.event.connect is the glue that holds most Dojo-based
// applications together. Most combinations of arguments are
// supported, with the connect() method attempting to disambiguate
// the implied types of positional parameters. The following will
// all work:
// dojo.event.connect("globalFunctionName1", "globalFunctionName2");
// dojo.event.connect(functionReference1, functionReference2);
// dojo.event.connect("globalFunctionName1", functionReference2);
// dojo.event.connect(functionReference1, "globalFunctionName2");
// dojo.event.connect(scope1, "functionName1", "globalFunctionName2");
// dojo.event.connect("globalFunctionName1", scope2, "functionName2");
// dojo.event.connect(scope1, "functionName1", scope2, "functionName2");
// dojo.event.connect("after", scope1, "functionName1", scope2, "functionName2");
// dojo.event.connect("before", scope1, "functionName1", scope2, "functionName2");
// dojo.event.connect("around", scope1, "functionName1",
// scope2, "functionName2",
// aroundFunctionReference);
// dojo.event.connect("around", scope1, "functionName1",
// scope2, "functionName2",
// scope3, "aroundFunctionName");
// dojo.event.connect("before-around", scope1, "functionName1",
// scope2, "functionName2",
// aroundFunctionReference);
// dojo.event.connect("after-around", scope1, "functionName1",
// scope2, "functionName2",
// aroundFunctionReference);
// dojo.event.connect("after-around", scope1, "functionName1",
// scope2, "functionName2",
// scope3, "aroundFunctionName");
// dojo.event.connect("around", scope1, "functionName1",
// scope2, "functionName2",
// scope3, "aroundFunctionName", true, 30);
// dojo.event.connect("around", scope1, "functionName1",
// scope2, "functionName2",
// scope3, "aroundFunctionName", null, null, 10);
// adviceType:
// Optional. String. One of "before", "after", "around",
// "before-around", or "after-around". FIXME
// srcObj:
// the scope in which to locate/execute the named srcFunc. Along
// with srcFunc, this creates a way to dereference the function to
// call. So if the function in question is "foo.bar", the
// srcObj/srcFunc pair would be foo and "bar", where "bar" is a
// string and foo is an object reference.
// srcFunc:
// the name of the function to connect to. When it is executed,
// the listener being registered with this call will be called.
// The adviceType defines the call order between the source and
// the target functions.
// adviceObj:
// the scope in which to locate/execute the named adviceFunc.
// adviceFunc:
// the name of the function being conected to srcObj.srcFunc
// aroundObj:
// the scope in which to locate/execute the named aroundFunc.
// aroundFunc:
// the name of, or a reference to, the function that will be used
// to mediate the advice call. Around advice requires a special
// unary function that will be passed a "MethodInvocation" object.
// These objects have several important properties, namely:
// - args
// a mutable array of arguments to be passed into the
// wrapped function
// - proceed
// a function that "continues" the invocation. The result
// of this function is the return of the wrapped function.
// You can then manipulate this return before passing it
// back out (or take further action based on it).
// once:
// boolean that determines whether or not this connect() will
// create a new connection if an identical connect() has already
// been made. Defaults to "false".
// delay:
// an optional delay (in ms), as an integer, for dispatch of a
// listener after the source has been fired.
// rate:
// an optional rate throttling parameter (integer, in ms). When
// specified, this particular connection will not fire more than
// once in the interval specified by the rate
// adviceMsg:
// boolean. Should the listener have all the parameters passed in
// as a single argument?
/*
ao.adviceType = args[0];
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];
*/
if(arguments.length == 1){
var ao = arguments[0];
}else{
var ao = interpolateArgs(arguments, true);
}
if(dojo.lang.isString(ao.srcFunc) && (ao.srcFunc.toLowerCase() == "onkey") ){
if(dojo.render.html.ie){
ao.srcFunc = "onkeydown";
this.connect(ao);
}
ao.srcFunc = "onkeypress";
}
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);
// advanced users might want to fsck w/ the join point manually
return mjp; // a MethodJoinPoint object
}
this.log = function(/*object or funcName*/ a1, /*funcName*/ a2){
// summary:
// a function that will wrap and log all calls to the specified
// a1.a2() function. If only a1 is passed, it'll be used as a
// function or function name on the global context. Logging will
// be sent to dojo.debug
// a1:
// if a2 is passed, this should be an object. If not, it can be a
// function or function name.
// a2:
// a function name
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(/*Object*/obj, /*String*/funcName){
this.object = obj||dj_global;
this.methodname = funcName;
this.methodfunc = this.object[funcName];
this.squelch = false;
// this.before = [];
// this.after = [];
// this.around = [];
}
dojo.event.MethodJoinPoint.getForMethod = function(/*Object*/obj, /*String*/funcName){
// summary:
// "static" class function for returning a MethodJoinPoint from a
// scoped function. If one doesn't exist, one is created.
// obj:
// the scope to search for the function in
// funcName:
// the name of the function to return a MethodJoinPoint for
if(!obj){ obj = dj_global; }
if(!obj[funcName]){
// supply a do-nothing method implementation
obj[funcName] = function(){};
if(!obj[funcName]){
// e.g. cannot add to inbuilt objects in IE6
dojo.raise("Cannot set do-nothing method on that object "+funcName);
}
}else if((!dojo.lang.isFunction(obj[funcName]))&&(!dojo.lang.isAlien(obj[funcName]))){
// FIXME: should we throw an exception here instead?
return null;
}
// we hide our joinpoint instance in obj[funcName + '$joinpoint']
var jpname = funcName + "$joinpoint";
var jpfuncname = funcName + "$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, funcName]);
}
}
var origArity = obj[funcName].length;
obj[jpfuncname] = obj[funcName];
// joinpoint = obj[jpname] = new dojo.event.MethodJoinPoint(obj, funcName);
joinpoint = obj[jpname] = new dojo.event.MethodJoinPoint(obj, jpfuncname);
obj[funcName] = 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 if(obj.event){ //obj is a window
evt = obj.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)){
// pass a cloned array, if this event disconnects this event forEach on this.before wont work
dojo.lang.forEach(this.before.concat(new Array()), unRollSquelch);
}
var result;
try{
if((this["around"])&&(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);
}
}catch(e){
if(!this.squelch){
dojo.debug(e,"when calling",this.methodname,"on",this.object,"with arguments",args);
dojo.raise(e);
}
}
if((this["after"])&&(this.after.length>0)){
// see comment on this.before above
dojo.lang.forEach(this.after.concat(new Array()), unRollSquelch);
}
return (this.methodfunc) ? result : null;
},
getArr: function(/*String*/kind){
// summary: return a list of listeners of the past "kind"
// kind:
// can be one of: "before", "after", "around", "before-around", or
// "after-around"
var type = "after";
// FIXME: we should be able to do this through props or Array.in()
if((typeof kind == "string")&&(kind.indexOf("before")!=-1)){
type = "before";
}else if(kind=="around"){
type = "around";
}
if(!this[type]){ this[type] = []; }
return this[type]; // Array
},
kwAddAdvice: function(/*Object*/args){
// summary:
// adds advice to the joinpoint with arguments in a map
// args:
// An object that can have the following properties:
// - adviceType
// - adviceObj
// - adviceFunc
// - aroundObj
// - aroundFunc
// - once
// - delay
// - rate
// - adviceMsg
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,
adviceType, precedence,
once, delay, rate, asMessage){
// summary:
// add advice to this joinpoint using positional parameters
// thisAdviceObj:
// the scope in which to locate/execute the named adviceFunc.
// thisAdviceFunc:
// the name of the function being conected
// thisAroundObj:
// the scope in which to locate/execute the named aroundFunc.
// thisAroundFunc:
// the name of the function that will be used to mediate the
// advice call.
// adviceType:
// Optional. String. One of "before", "after", "around",
// "before-around", or "after-around". FIXME
// once:
// boolean that determines whether or not this advice will create
// a new connection if an identical advice set has already been
// provided. Defaults to "false".
// delay:
// an optional delay (in ms), as an integer, for dispatch of a
// listener after the source has been fired.
// rate:
// an optional rate throttling parameter (integer, in ms). When
// specified, this particular connection will not fire more than
// once in the interval specified by the rate
// adviceMsg:
// boolean. Should the listener have all the parameters passed in
// as a single argument?
var arr = this.getArr(adviceType);
if(!arr){
dojo.raise("bad this: " + this);
}
var ao = [thisAdviceObj, thisAdvice, thisAroundObj, thisAround, delay, rate, asMessage];
if(once){
if(this.hasAdvice(thisAdviceObj, thisAdvice, adviceType, arr) >= 0){
return;
}
}
if(precedence == "first"){
arr.unshift(ao);
}else{
arr.push(ao);
}
},
hasAdvice: function(thisAdviceObj, thisAdvice, adviceType, arr){
// summary:
// returns the array index of the first existing connection
// betweened the passed advice and this joinpoint. Will be -1 if
// none exists.
// thisAdviceObj:
// the scope in which to locate/execute the named adviceFunc.
// thisAdviceFunc:
// the name of the function being conected
// adviceType:
// Optional. String. One of "before", "after", "around",
// "before-around", or "after-around". FIXME
// arr:
// Optional. The list of advices to search. Will be found via
// adviceType if not passed
if(!arr){ arr = this.getArr(adviceType); }
var ind = -1;
for(var x=0; x