]> git.wh0rd.org Git - tt-rss.git/blob - lib/dojo/_base/connect.js.uncompressed.js
update dojo to 1.7.3
[tt-rss.git] / lib / dojo / _base / connect.js.uncompressed.js
1 define("dojo/_base/connect", ["./kernel", "../on", "../topic", "../aspect", "./event", "../mouse", "./sniff", "./lang", "../keys"], function(kernel, on, hub, aspect, eventModule, mouse, has, lang){
2 //  module:
3 //    dojo/_base/connect
4 //  summary:
5 //    This module defines the dojo.connect API.
6 //              This modules also provides keyboard event handling helpers.
7 //              This module exports an extension event for emulating Firefox's keypress handling.
8 //              However, this extension event exists primarily for backwards compatibility and
9 //              is not recommended. WebKit and IE uses an alternate keypress handling (only
10 //              firing for printable characters, to distinguish from keydown events), and most
11 //              consider the WebKit/IE behavior more desirable.
12 has.add("events-keypress-typed", function(){ // keypresses should only occur a printable character is hit
13         var testKeyEvent = {charCode: 0};
14         try{
15                 testKeyEvent = document.createEvent("KeyboardEvent");
16                 (testKeyEvent.initKeyboardEvent || testKeyEvent.initKeyEvent).call(testKeyEvent, "keypress", true, true, null, false, false, false, false, 9, 3);
17         }catch(e){}
18         return testKeyEvent.charCode == 0 && !has("opera");
19 });
20
21 function connect_(obj, event, context, method, dontFix){
22         method = lang.hitch(context, method);
23         if(!obj || !(obj.addEventListener || obj.attachEvent)){
24                 // it is a not a DOM node and we are using the dojo.connect style of treating a
25                 // method like an event, must go right to aspect
26                 return aspect.after(obj || kernel.global, event, method, true);
27         }
28         if(typeof event == "string" && event.substring(0, 2) == "on"){
29                 event = event.substring(2);
30         }
31         if(!obj){
32                 obj = kernel.global;
33         }
34         if(!dontFix){
35                 switch(event){
36                         // dojo.connect has special handling for these event types
37                         case "keypress":
38                                 event = keypress;
39                                 break;
40                         case "mouseenter":
41                                 event = mouse.enter;
42                                 break;
43                         case "mouseleave":
44                                 event = mouse.leave;
45                                 break;
46                 }
47         }
48         return on(obj, event, method, dontFix);
49 }
50
51 var _punctMap = {
52         106:42,
53         111:47,
54         186:59,
55         187:43,
56         188:44,
57         189:45,
58         190:46,
59         191:47,
60         192:96,
61         219:91,
62         220:92,
63         221:93,
64         222:39,
65         229:113
66 };
67 var evtCopyKey = has("mac") ? "metaKey" : "ctrlKey";
68
69
70 var _synthesizeEvent = function(evt, props){
71         var faux = lang.mixin({}, evt, props);
72         setKeyChar(faux);
73         // FIXME: would prefer to use lang.hitch: lang.hitch(evt, evt.preventDefault);
74         // but it throws an error when preventDefault is invoked on Safari
75         // does Event.preventDefault not support "apply" on Safari?
76         faux.preventDefault = function(){ evt.preventDefault(); };
77         faux.stopPropagation = function(){ evt.stopPropagation(); };
78         return faux;
79 };
80 function setKeyChar(evt){
81         evt.keyChar = evt.charCode ? String.fromCharCode(evt.charCode) : '';
82         evt.charOrCode = evt.keyChar || evt.keyCode;
83 }
84 var keypress;
85 if(has("events-keypress-typed")){
86         // this emulates Firefox's keypress behavior where every keydown can correspond to a keypress
87         var _trySetKeyCode = function(e, code){
88                 try{
89                         // squelch errors when keyCode is read-only
90                         // (e.g. if keyCode is ctrl or shift)
91                         return (e.keyCode = code);
92                 }catch(e){
93                         return 0;
94                 }
95         };
96         keypress = function(object, listener){
97                 var keydownSignal = on(object, "keydown", function(evt){
98                         // munge key/charCode
99                         var k=evt.keyCode;
100                         // These are Windows Virtual Key Codes
101                         // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/WinUI/WindowsUserInterface/UserInput/VirtualKeyCodes.asp
102                         var unprintable = (k!=13 || (has("ie") >= 9 && !has("quirks"))) && k!=32 && (k!=27||!has("ie")) && (k<48||k>90) && (k<96||k>111) && (k<186||k>192) && (k<219||k>222) && k!=229;
103                         // synthesize keypress for most unprintables and CTRL-keys
104                         if(unprintable||evt.ctrlKey){
105                                 var c = unprintable ? 0 : k;
106                                 if(evt.ctrlKey){
107                                         if(k==3 || k==13){
108                                                 return listener.call(evt.currentTarget, evt); // IE will post CTRL-BREAK, CTRL-ENTER as keypress natively
109                                         }else if(c>95 && c<106){
110                                                 c -= 48; // map CTRL-[numpad 0-9] to ASCII
111                                         }else if((!evt.shiftKey)&&(c>=65&&c<=90)){
112                                                 c += 32; // map CTRL-[A-Z] to lowercase
113                                         }else{
114                                                 c = _punctMap[c] || c; // map other problematic CTRL combinations to ASCII
115                                         }
116                                 }
117                                 // simulate a keypress event
118                                 var faux = _synthesizeEvent(evt, {type: 'keypress', faux: true, charCode: c});
119                                 listener.call(evt.currentTarget, faux);
120                                 if(has("ie")){
121                                         _trySetKeyCode(evt, faux.keyCode);
122                                 }
123                         }
124                 });
125                 var keypressSignal = on(object, "keypress", function(evt){
126                         var c = evt.charCode;
127                         c = c>=32 ? c : 0;
128                         evt = _synthesizeEvent(evt, {charCode: c, faux: true});
129                         return listener.call(this, evt);
130                 });
131                 return {
132                         remove: function(){
133                                 keydownSignal.remove();
134                                 keypressSignal.remove();
135                         }
136                 };
137         };
138 }else{
139         if(has("opera")){
140                 keypress = function(object, listener){
141                         return on(object, "keypress", function(evt){
142                                 var c = evt.which;
143                                 if(c==3){
144                                         c=99; // Mozilla maps CTRL-BREAK to CTRL-c
145                                 }
146                                 // can't trap some keys at all, like INSERT and DELETE
147                                 // there is no differentiating info between DELETE and ".", or INSERT and "-"
148                                 c = c<32 && !evt.shiftKey ? 0 : c;
149                                 if(evt.ctrlKey && !evt.shiftKey && c>=65 && c<=90){
150                                         // lowercase CTRL-[A-Z] keys
151                                         c += 32;
152                                 }
153                                 return listener.call(this, _synthesizeEvent(evt, { charCode: c }));
154                         });
155                 };
156         }else{
157                 keypress = function(object, listener){
158                         return on(object, "keypress", function(evt){
159                                 setKeyChar(evt);
160                                 return listener.call(this, evt);
161                         });
162                 };
163         }
164 }
165
166 var connect = {
167         _keypress:keypress,
168
169         connect:function(obj, event, context, method, dontFix){
170                 // normalize arguments
171                 var a=arguments, args=[], i=0;
172                 // if a[0] is a String, obj was omitted
173                 args.push(typeof a[0] == "string" ? null : a[i++], a[i++]);
174                 // if the arg-after-next is a String or Function, context was NOT omitted
175                 var a1 = a[i+1];
176                 args.push(typeof a1 == "string" || typeof a1 == "function" ? a[i++] : null, a[i++]);
177                 // absorb any additional arguments
178                 for(var l=a.length; i<l; i++){  args.push(a[i]); }
179                 return connect_.apply(this, args);
180         },
181
182         disconnect:function(handle){
183                 if(handle){
184                         handle.remove();
185                 }
186         },
187
188         subscribe:function(topic, context, method){
189                 return hub.subscribe(topic, lang.hitch(context, method));
190         },
191
192         publish:function(topic, args){
193                 return hub.publish.apply(hub, [topic].concat(args));
194         },
195
196         connectPublisher:function(topic, obj, event){
197                 var pf = function(){ connect.publish(topic, arguments); };
198                 return event ? connect.connect(obj, event, pf) : connect.connect(obj, pf); //Handle
199         },
200
201         isCopyKey: function(e){
202                 return e[evtCopyKey];   // Boolean
203         }
204 };
205 connect.unsubscribe = connect.disconnect;
206
207 1 && lang.mixin(kernel, connect);
208 return connect;
209
210 /*=====
211 dojo.connect = function(obj, event, context, method, dontFix){
212         // summary:
213         //              `dojo.connect` is the core event handling and delegation method in
214         //              Dojo. It allows one function to "listen in" on the execution of
215         //              any other, triggering the second whenever the first is called. Many
216         //              listeners may be attached to a function, and source functions may
217         //              be either regular function calls or DOM events.
218         //
219         // description:
220         //              Connects listeners to actions, so that after event fires, a
221         //              listener is called with the same arguments passed to the original
222         //              function.
223         //
224         //              Since `dojo.connect` allows the source of events to be either a
225         //              "regular" JavaScript function or a DOM event, it provides a uniform
226         //              interface for listening to all the types of events that an
227         //              application is likely to deal with though a single, unified
228         //              interface. DOM programmers may want to think of it as
229         //              "addEventListener for everything and anything".
230         //
231         //              When setting up a connection, the `event` parameter must be a
232         //              string that is the name of the method/event to be listened for. If
233         //              `obj` is null, `kernel.global` is assumed, meaning that connections
234         //              to global methods are supported but also that you may inadvertently
235         //              connect to a global by passing an incorrect object name or invalid
236         //              reference.
237         //
238         //              `dojo.connect` generally is forgiving. If you pass the name of a
239         //              function or method that does not yet exist on `obj`, connect will
240         //              not fail, but will instead set up a stub method. Similarly, null
241         //              arguments may simply be omitted such that fewer than 4 arguments
242         //              may be required to set up a connection See the examples for details.
243         //
244         //              The return value is a handle that is needed to
245         //              remove this connection with `dojo.disconnect`.
246         //
247         // obj: Object|null:
248         //              The source object for the event function.
249         //              Defaults to `kernel.global` if null.
250         //              If obj is a DOM node, the connection is delegated
251         //              to the DOM event manager (unless dontFix is true).
252         //
253         // event: String:
254         //              String name of the event function in obj.
255         //              I.e. identifies a property `obj[event]`.
256         //
257         // context: Object|null
258         //              The object that method will receive as "this".
259         //
260         //              If context is null and method is a function, then method
261         //              inherits the context of event.
262         //
263         //              If method is a string then context must be the source
264         //              object object for method (context[method]). If context is null,
265         //              kernel.global is used.
266         //
267         // method: String|Function:
268         //              A function reference, or name of a function in context.
269         //              The function identified by method fires after event does.
270         //              method receives the same arguments as the event.
271         //              See context argument comments for information on method's scope.
272         //
273         // dontFix: Boolean?
274         //              If obj is a DOM node, set dontFix to true to prevent delegation
275         //              of this connection to the DOM event manager.
276         //
277         // example:
278         //              When obj.onchange(), do ui.update():
279         //      |       dojo.connect(obj, "onchange", ui, "update");
280         //      |       dojo.connect(obj, "onchange", ui, ui.update); // same
281         //
282         // example:
283         //              Using return value for disconnect:
284         //      |       var link = dojo.connect(obj, "onchange", ui, "update");
285         //      |       ...
286         //      |       dojo.disconnect(link);
287         //
288         // example:
289         //              When onglobalevent executes, watcher.handler is invoked:
290         //      |       dojo.connect(null, "onglobalevent", watcher, "handler");
291         //
292         // example:
293         //              When ob.onCustomEvent executes, customEventHandler is invoked:
294         //      |       dojo.connect(ob, "onCustomEvent", null, "customEventHandler");
295         //      |       dojo.connect(ob, "onCustomEvent", "customEventHandler"); // same
296         //
297         // example:
298         //              When ob.onCustomEvent executes, customEventHandler is invoked
299         //              with the same scope (this):
300         //      |       dojo.connect(ob, "onCustomEvent", null, customEventHandler);
301         //      |       dojo.connect(ob, "onCustomEvent", customEventHandler); // same
302         //
303         // example:
304         //              When globalEvent executes, globalHandler is invoked
305         //              with the same scope (this):
306         //      |       dojo.connect(null, "globalEvent", null, globalHandler);
307         //      |       dojo.connect("globalEvent", globalHandler); // same
308 }
309 =====*/
310
311 /*=====
312 dojo.disconnect = function(handle){
313         // summary:
314         //              Remove a link created by dojo.connect.
315         // description:
316         //              Removes the connection between event and the method referenced by handle.
317         // handle: Handle:
318         //              the return value of the dojo.connect call that created the connection.
319 }
320 =====*/
321
322 /*=====
323 dojo.subscribe = function(topic, context, method){
324         //      summary:
325         //              Attach a listener to a named topic. The listener function is invoked whenever the
326         //              named topic is published (see: dojo.publish).
327         //              Returns a handle which is needed to unsubscribe this listener.
328         //      topic: String:
329         //              The topic to which to subscribe.
330         //      context: Object|null:
331         //              Scope in which method will be invoked, or null for default scope.
332         //      method: String|Function:
333         //              The name of a function in context, or a function reference. This is the function that
334         //              is invoked when topic is published.
335         //      example:
336         //      |       dojo.subscribe("alerts", null, function(caption, message){ alert(caption + "\n" + message); });
337         //      |       dojo.publish("alerts", [ "read this", "hello world" ]);
338 }
339 =====*/
340
341 /*=====
342 dojo.unsubscribe = function(handle){
343         //      summary:
344         //              Remove a topic listener.
345         //      handle: Handle
346         //              The handle returned from a call to subscribe.
347         //      example:
348         //      |       var alerter = dojo.subscribe("alerts", null, function(caption, message){ alert(caption + "\n" + message); };
349         //      |       ...
350         //      |       dojo.unsubscribe(alerter);
351 }
352 =====*/
353
354 /*=====
355 dojo.publish = function(topic, args){
356         //      summary:
357         //              Invoke all listener method subscribed to topic.
358         //      topic: String:
359         //              The name of the topic to publish.
360         //      args: Array?
361         //              An array of arguments. The arguments will be applied
362         //              to each topic subscriber (as first class parameters, via apply).
363         //      example:
364         //      |       dojo.subscribe("alerts", null, function(caption, message){ alert(caption + "\n" + message); };
365         //      |       dojo.publish("alerts", [ "read this", "hello world" ]);
366 }
367 =====*/
368
369 /*=====
370 dojo.connectPublisher = function(topic, obj, event){
371         //      summary:
372         //              Ensure that every time obj.event() is called, a message is published
373         //              on the topic. Returns a handle which can be passed to
374         //              dojo.disconnect() to disable subsequent automatic publication on
375         //              the topic.
376         //      topic: String:
377         //              The name of the topic to publish.
378         //      obj: Object|null:
379         //              The source object for the event function. Defaults to kernel.global
380         //              if null.
381         //      event: String:
382         //              The name of the event function in obj.
383         //              I.e. identifies a property obj[event].
384         //      example:
385         //      |       dojo.connectPublisher("/ajax/start", dojo, "xhrGet");
386 }
387 =====*/
388
389 /*=====
390 dojo.isCopyKey = function(e){
391         // summary:
392         //              Checks an event for the copy key (meta on Mac, and ctrl anywhere else)
393         // e: Event
394         //              Event object to examine
395 }
396 =====*/
397
398 });
399
400