summaryrefslogtreecommitdiff
path: root/lib/dojo/_base/connect.js
diff options
context:
space:
mode:
Diffstat (limited to 'lib/dojo/_base/connect.js')
-rw-r--r--lib/dojo/_base/connect.js359
1 files changed, 292 insertions, 67 deletions
diff --git a/lib/dojo/_base/connect.js b/lib/dojo/_base/connect.js
index 3905d92e7..f37af65b2 100644
--- a/lib/dojo/_base/connect.js
+++ b/lib/dojo/_base/connect.js
@@ -5,81 +5,306 @@
*/
-if(!dojo._hasResource["dojo._base.connect"]){
-dojo._hasResource["dojo._base.connect"]=true;
+if(!dojo._hasResource["dojo._base.connect"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojo._base.connect"] = true;
dojo.provide("dojo._base.connect");
dojo.require("dojo._base.lang");
-dojo._listener={getDispatcher:function(){
-return function(){
-var ap=Array.prototype,c=arguments.callee,ls=c._listeners,t=c.target;
-var r=t&&t.apply(this,arguments);
-var i,_1;
-_1=[].concat(ls);
-for(i in _1){
-if(!(i in ap)){
-_1[i].apply(this,arguments);
-}
-}
-return r;
+
+// this file courtesy of the TurboAjax Group, licensed under a Dojo CLA
+
+// low-level delegation machinery
+dojo._listener = {
+ // create a dispatcher function
+ getDispatcher: function(){
+ // following comments pulled out-of-line to prevent cloning them
+ // in the returned function.
+ // - indices (i) that are really in the array of listeners (ls) will
+ // not be in Array.prototype. This is the 'sparse array' trick
+ // that keeps us safe from libs that take liberties with built-in
+ // objects
+ // - listener is invoked with current scope (this)
+ return function(){
+ var ap=Array.prototype, c=arguments.callee, ls=c._listeners, t=c.target;
+ // return value comes from original target function
+ var r = t && t.apply(this, arguments);
+ // make local copy of listener array so it is immutable during processing
+ var i, lls;
+ lls = [].concat(ls);
+
+ // invoke listeners after target function
+ for(i in lls){
+ if(!(i in ap)){
+ lls[i].apply(this, arguments);
+ }
+ }
+ // return value comes from original target function
+ return r;
+ };
+ },
+ // add a listener to an object
+ add: function(/*Object*/ source, /*String*/ method, /*Function*/ listener){
+ // Whenever 'method' is invoked, 'listener' will have the same scope.
+ // Trying to supporting a context object for the listener led to
+ // complexity.
+ // Non trivial to provide 'once' functionality here
+ // because listener could be the result of a dojo.hitch call,
+ // in which case two references to the same hitch target would not
+ // be equivalent.
+ source = source || dojo.global;
+ // The source method is either null, a dispatcher, or some other function
+ var f = source[method];
+ // Ensure a dispatcher
+ if(!f || !f._listeners){
+ var d = dojo._listener.getDispatcher();
+ // original target function is special
+ d.target = f;
+ // dispatcher holds a list of listeners
+ d._listeners = [];
+ // redirect source to dispatcher
+ f = source[method] = d;
+ }
+ // The contract is that a handle is returned that can
+ // identify this listener for disconnect.
+ //
+ // The type of the handle is private. Here is it implemented as Integer.
+ // DOM event code has this same contract but handle is Function
+ // in non-IE browsers.
+ //
+ // We could have separate lists of before and after listeners.
+ return f._listeners.push(listener); /*Handle*/
+ },
+ // remove a listener from an object
+ remove: function(/*Object*/ source, /*String*/ method, /*Handle*/ handle){
+ var f = (source || dojo.global)[method];
+ // remember that handle is the index+1 (0 is not a valid handle)
+ if(f && f._listeners && handle--){
+ delete f._listeners[handle];
+ }
+ }
};
-},add:function(_2,_3,_4){
-_2=_2||dojo.global;
-var f=_2[_3];
-if(!f||!f._listeners){
-var d=dojo._listener.getDispatcher();
-d.target=f;
-d._listeners=[];
-f=_2[_3]=d;
+
+// Multiple delegation for arbitrary methods.
+
+// This unit knows nothing about DOM, but we include DOM aware documentation
+// and dontFix argument here to help the autodocs. Actual DOM aware code is in
+// event.js.
+
+dojo.connect = function(/*Object|null*/ obj,
+ /*String*/ event,
+ /*Object|null*/ context,
+ /*String|Function*/ method,
+ /*Boolean?*/ dontFix){
+ // summary:
+ // `dojo.connect` is the core event handling and delegation method in
+ // Dojo. It allows one function to "listen in" on the execution of
+ // any other, triggering the second whenever the first is called. Many
+ // listeners may be attached to a function, and source functions may
+ // be either regular function calls or DOM events.
+ //
+ // description:
+ // Connects listeners to actions, so that after event fires, a
+ // listener is called with the same arguments passed to the original
+ // function.
+ //
+ // Since `dojo.connect` allows the source of events to be either a
+ // "regular" JavaScript function or a DOM event, it provides a uniform
+ // interface for listening to all the types of events that an
+ // application is likely to deal with though a single, unified
+ // interface. DOM programmers may want to think of it as
+ // "addEventListener for everything and anything".
+ //
+ // When setting up a connection, the `event` parameter must be a
+ // string that is the name of the method/event to be listened for. If
+ // `obj` is null, `dojo.global` is assumed, meaning that connections
+ // to global methods are supported but also that you may inadvertently
+ // connect to a global by passing an incorrect object name or invalid
+ // reference.
+ //
+ // `dojo.connect` generally is forgiving. If you pass the name of a
+ // function or method that does not yet exist on `obj`, connect will
+ // not fail, but will instead set up a stub method. Similarly, null
+ // arguments may simply be omitted such that fewer than 4 arguments
+ // may be required to set up a connection See the examples for details.
+ //
+ // The return value is a handle that is needed to
+ // remove this connection with `dojo.disconnect`.
+ //
+ // obj:
+ // The source object for the event function.
+ // Defaults to `dojo.global` if null.
+ // If obj is a DOM node, the connection is delegated
+ // to the DOM event manager (unless dontFix is true).
+ //
+ // event:
+ // String name of the event function in obj.
+ // I.e. identifies a property `obj[event]`.
+ //
+ // context:
+ // The object that method will receive as "this".
+ //
+ // If context is null and method is a function, then method
+ // inherits the context of event.
+ //
+ // If method is a string then context must be the source
+ // object object for method (context[method]). If context is null,
+ // dojo.global is used.
+ //
+ // method:
+ // A function reference, or name of a function in context.
+ // The function identified by method fires after event does.
+ // method receives the same arguments as the event.
+ // See context argument comments for information on method's scope.
+ //
+ // dontFix:
+ // If obj is a DOM node, set dontFix to true to prevent delegation
+ // of this connection to the DOM event manager.
+ //
+ // example:
+ // When obj.onchange(), do ui.update():
+ // | dojo.connect(obj, "onchange", ui, "update");
+ // | dojo.connect(obj, "onchange", ui, ui.update); // same
+ //
+ // example:
+ // Using return value for disconnect:
+ // | var link = dojo.connect(obj, "onchange", ui, "update");
+ // | ...
+ // | dojo.disconnect(link);
+ //
+ // example:
+ // When onglobalevent executes, watcher.handler is invoked:
+ // | dojo.connect(null, "onglobalevent", watcher, "handler");
+ //
+ // example:
+ // When ob.onCustomEvent executes, customEventHandler is invoked:
+ // | dojo.connect(ob, "onCustomEvent", null, "customEventHandler");
+ // | dojo.connect(ob, "onCustomEvent", "customEventHandler"); // same
+ //
+ // example:
+ // When ob.onCustomEvent executes, customEventHandler is invoked
+ // with the same scope (this):
+ // | dojo.connect(ob, "onCustomEvent", null, customEventHandler);
+ // | dojo.connect(ob, "onCustomEvent", customEventHandler); // same
+ //
+ // example:
+ // When globalEvent executes, globalHandler is invoked
+ // with the same scope (this):
+ // | dojo.connect(null, "globalEvent", null, globalHandler);
+ // | dojo.connect("globalEvent", globalHandler); // same
+
+ // normalize arguments
+ var a=arguments, args=[], i=0;
+ // if a[0] is a String, obj was omitted
+ args.push(dojo.isString(a[0]) ? null : a[i++], a[i++]);
+ // if the arg-after-next is a String or Function, context was NOT omitted
+ var a1 = a[i+1];
+ args.push(dojo.isString(a1)||dojo.isFunction(a1) ? a[i++] : null, a[i++]);
+ // absorb any additional arguments
+ for(var l=a.length; i<l; i++){ args.push(a[i]); }
+ // do the actual work
+ return dojo._connect.apply(this, args); /*Handle*/
}
-return f._listeners.push(_4);
-},remove:function(_5,_6,_7){
-var f=(_5||dojo.global)[_6];
-if(f&&f._listeners&&_7--){
-delete f._listeners[_7];
+
+// used by non-browser hostenvs. always overriden by event.js
+dojo._connect = function(obj, event, context, method){
+ var l=dojo._listener, h=l.add(obj, event, dojo.hitch(context, method));
+ return [obj, event, h, l]; // Handle
}
-}};
-dojo.connect=function(_8,_9,_a,_b,_c){
-var a=arguments,_d=[],i=0;
-_d.push(dojo.isString(a[0])?null:a[i++],a[i++]);
-var a1=a[i+1];
-_d.push(dojo.isString(a1)||dojo.isFunction(a1)?a[i++]:null,a[i++]);
-for(var l=a.length;i<l;i++){
-_d.push(a[i]);
+
+dojo.disconnect = function(/*Handle*/ handle){
+ // summary:
+ // Remove a link created by dojo.connect.
+ // description:
+ // Removes the connection between event and the method referenced by handle.
+ // handle:
+ // the return value of the dojo.connect call that created the connection.
+ if(handle && handle[0] !== undefined){
+ dojo._disconnect.apply(this, handle);
+ // let's not keep this reference
+ delete handle[0];
+ }
}
-return dojo._connect.apply(this,_d);
-};
-dojo._connect=function(_e,_f,_10,_11){
-var l=dojo._listener,h=l.add(_e,_f,dojo.hitch(_10,_11));
-return [_e,_f,h,l];
-};
-dojo.disconnect=function(_12){
-if(_12&&_12[0]!==undefined){
-dojo._disconnect.apply(this,_12);
-delete _12[0];
+
+dojo._disconnect = function(obj, event, handle, listener){
+ listener.remove(obj, event, handle);
}
-};
-dojo._disconnect=function(obj,_13,_14,_15){
-_15.remove(obj,_13,_14);
-};
-dojo._topics={};
-dojo.subscribe=function(_16,_17,_18){
-return [_16,dojo._listener.add(dojo._topics,_16,dojo.hitch(_17,_18))];
-};
-dojo.unsubscribe=function(_19){
-if(_19){
-dojo._listener.remove(dojo._topics,_19[0],_19[1]);
+
+// topic publish/subscribe
+
+dojo._topics = {};
+
+dojo.subscribe = function(/*String*/ topic, /*Object|null*/ context, /*String|Function*/ method){
+ // summary:
+ // Attach a listener to a named topic. The listener function is invoked whenever the
+ // named topic is published (see: dojo.publish).
+ // Returns a handle which is needed to unsubscribe this listener.
+ // context:
+ // Scope in which method will be invoked, or null for default scope.
+ // method:
+ // The name of a function in context, or a function reference. This is the function that
+ // is invoked when topic is published.
+ // example:
+ // | dojo.subscribe("alerts", null, function(caption, message){ alert(caption + "\n" + message); });
+ // | dojo.publish("alerts", [ "read this", "hello world" ]);
+
+ // support for 2 argument invocation (omitting context) depends on hitch
+ return [topic, dojo._listener.add(dojo._topics, topic, dojo.hitch(context, method))]; /*Handle*/
}
-};
-dojo.publish=function(_1a,_1b){
-var f=dojo._topics[_1a];
-if(f){
-f.apply(this,_1b||[]);
+
+dojo.unsubscribe = function(/*Handle*/ handle){
+ // summary:
+ // Remove a topic listener.
+ // handle:
+ // The handle returned from a call to subscribe.
+ // example:
+ // | var alerter = dojo.subscribe("alerts", null, function(caption, message){ alert(caption + "\n" + message); };
+ // | ...
+ // | dojo.unsubscribe(alerter);
+ if(handle){
+ dojo._listener.remove(dojo._topics, handle[0], handle[1]);
+ }
}
+
+dojo.publish = function(/*String*/ topic, /*Array*/ args){
+ // summary:
+ // Invoke all listener method subscribed to topic.
+ // topic:
+ // The name of the topic to publish.
+ // args:
+ // An array of arguments. The arguments will be applied
+ // to each topic subscriber (as first class parameters, via apply).
+ // example:
+ // | dojo.subscribe("alerts", null, function(caption, message){ alert(caption + "\n" + message); };
+ // | dojo.publish("alerts", [ "read this", "hello world" ]);
+
+ // Note that args is an array, which is more efficient vs variable length
+ // argument list. Ideally, var args would be implemented via Array
+ // throughout the APIs.
+ var f = dojo._topics[topic];
+ if(f){
+ f.apply(this, args||[]);
+ }
+}
+
+dojo.connectPublisher = function( /*String*/ topic,
+ /*Object|null*/ obj,
+ /*String*/ event){
+ // summary:
+ // Ensure that every time obj.event() is called, a message is published
+ // on the topic. Returns a handle which can be passed to
+ // dojo.disconnect() to disable subsequent automatic publication on
+ // the topic.
+ // topic:
+ // The name of the topic to publish.
+ // obj:
+ // The source object for the event function. Defaults to dojo.global
+ // if null.
+ // event:
+ // The name of the event function in obj.
+ // I.e. identifies a property obj[event].
+ // example:
+ // | dojo.connectPublisher("/ajax/start", dojo, "xhrGet");
+ var pf = function(){ dojo.publish(topic, arguments); }
+ return event ? dojo.connect(obj, event, pf) : dojo.connect(obj, pf); //Handle
};
-dojo.connectPublisher=function(_1c,obj,_1d){
-var pf=function(){
-dojo.publish(_1c,arguments);
-};
-return _1d?dojo.connect(obj,_1d,pf):dojo.connect(obj,pf);
-};
+
}