]> git.wh0rd.org - tt-rss.git/blame - lib/dojo/_base/connect.js.uncompressed.js
make precache_headlines_idle() start slower
[tt-rss.git] / lib / dojo / _base / connect.js.uncompressed.js
CommitLineData
1354d172
AD
1define("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.
12has.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
21function 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
51var _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};
67var evtCopyKey = has("mac") ? "metaKey" : "ctrlKey";
68
69
70var _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};
80function setKeyChar(evt){
81 evt.keyChar = evt.charCode ? String.fromCharCode(evt.charCode) : '';
82 evt.charOrCode = evt.keyChar || evt.keyCode;
83}
84var keypress;
85if(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
166var 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};
205connect.unsubscribe = connect.disconnect;
206
2071 && lang.mixin(kernel, connect);
208return connect;
209
210/*=====
211dojo.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/*=====
312dojo.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/*=====
323dojo.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/*=====
342dojo.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/*=====
355dojo.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/*=====
370dojo.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/*=====
390dojo.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