author | Giulio Cesare Solaroli <giulio.cesare@clipperz.com> | 2011-10-02 23:56:18 (UTC) |
---|---|---|
committer | Giulio Cesare Solaroli <giulio.cesare@clipperz.com> | 2011-10-02 23:56:18 (UTC) |
commit | ef68436ac04da078ffdcacd7e1f785473a303d45 (patch) (unidiff) | |
tree | c403752d66a2c4775f00affd4fa8431b29c5b68c /frontend/gamma/js/MochiKit/Signal.js | |
parent | 597ecfbc0249d83e1b856cbd558340c01237a360 (diff) | |
download | clipperz-ef68436ac04da078ffdcacd7e1f785473a303d45.zip clipperz-ef68436ac04da078ffdcacd7e1f785473a303d45.tar.gz clipperz-ef68436ac04da078ffdcacd7e1f785473a303d45.tar.bz2 |
First version of the newly restructured repository
Diffstat (limited to 'frontend/gamma/js/MochiKit/Signal.js') (more/less context) (show whitespace changes)
-rw-r--r-- | frontend/gamma/js/MochiKit/Signal.js | 888 |
1 files changed, 888 insertions, 0 deletions
diff --git a/frontend/gamma/js/MochiKit/Signal.js b/frontend/gamma/js/MochiKit/Signal.js new file mode 100644 index 0000000..7df5619 --- a/dev/null +++ b/frontend/gamma/js/MochiKit/Signal.js | |||
@@ -0,0 +1,888 @@ | |||
1 | /*** | ||
2 | |||
3 | MochiKit.Signal 1.5 | ||
4 | |||
5 | See <http://mochikit.com/> for documentation, downloads, license, etc. | ||
6 | |||
7 | (c) 2006 Jonathan Gardner, Beau Hartshorne, Bob Ippolito. All rights Reserved. | ||
8 | |||
9 | ***/ | ||
10 | |||
11 | MochiKit.Base._module('Signal', '1.5', ['Base', 'DOM', 'Style']); | ||
12 | |||
13 | MochiKit.Signal._observers = []; | ||
14 | |||
15 | /** @id MochiKit.Signal.Event */ | ||
16 | MochiKit.Signal.Event = function (src, e) { | ||
17 | this._event = e || window.event; | ||
18 | this._src = src; | ||
19 | }; | ||
20 | MochiKit.Signal.Event.__export__ = false; | ||
21 | |||
22 | MochiKit.Base.update(MochiKit.Signal.Event.prototype, { | ||
23 | |||
24 | __repr__: function () { | ||
25 | var repr = MochiKit.Base.repr; | ||
26 | var str = '{event(): ' + repr(this.event()) + | ||
27 | ', src(): ' + repr(this.src()) + | ||
28 | ', type(): ' + repr(this.type()) + | ||
29 | ', target(): ' + repr(this.target()); | ||
30 | |||
31 | if (this.type() && | ||
32 | this.type().indexOf('key') === 0 || | ||
33 | this.type().indexOf('mouse') === 0 || | ||
34 | this.type().indexOf('click') != -1 || | ||
35 | this.type() == 'contextmenu') { | ||
36 | str += ', modifier(): ' + '{alt: ' + repr(this.modifier().alt) + | ||
37 | ', ctrl: ' + repr(this.modifier().ctrl) + | ||
38 | ', meta: ' + repr(this.modifier().meta) + | ||
39 | ', shift: ' + repr(this.modifier().shift) + | ||
40 | ', any: ' + repr(this.modifier().any) + '}'; | ||
41 | } | ||
42 | |||
43 | if (this.type() && this.type().indexOf('key') === 0) { | ||
44 | str += ', key(): {code: ' + repr(this.key().code) + | ||
45 | ', string: ' + repr(this.key().string) + '}'; | ||
46 | } | ||
47 | |||
48 | if (this.type() && ( | ||
49 | this.type().indexOf('mouse') === 0 || | ||
50 | this.type().indexOf('click') != -1 || | ||
51 | this.type() == 'contextmenu')) { | ||
52 | |||
53 | str += ', mouse(): {page: ' + repr(this.mouse().page) + | ||
54 | ', client: ' + repr(this.mouse().client); | ||
55 | |||
56 | if (this.type() != 'mousemove' && this.type() != 'mousewheel') { | ||
57 | str += ', button: {left: ' + repr(this.mouse().button.left) + | ||
58 | ', middle: ' + repr(this.mouse().button.middle) + | ||
59 | ', right: ' + repr(this.mouse().button.right) + '}'; | ||
60 | } | ||
61 | if (this.type() == 'mousewheel') { | ||
62 | str += ', wheel: ' + repr(this.mouse().wheel); | ||
63 | } | ||
64 | str += '}'; | ||
65 | } | ||
66 | if (this.type() == 'mouseover' || this.type() == 'mouseout' || | ||
67 | this.type() == 'mouseenter' || this.type() == 'mouseleave') { | ||
68 | str += ', relatedTarget(): ' + repr(this.relatedTarget()); | ||
69 | } | ||
70 | str += '}'; | ||
71 | return str; | ||
72 | }, | ||
73 | |||
74 | /** @id MochiKit.Signal.Event.prototype.toString */ | ||
75 | toString: function () { | ||
76 | return this.__repr__(); | ||
77 | }, | ||
78 | |||
79 | /** @id MochiKit.Signal.Event.prototype.src */ | ||
80 | src: function () { | ||
81 | return this._src; | ||
82 | }, | ||
83 | |||
84 | /** @id MochiKit.Signal.Event.prototype.event */ | ||
85 | event: function () { | ||
86 | return this._event; | ||
87 | }, | ||
88 | |||
89 | /** @id MochiKit.Signal.Event.prototype.type */ | ||
90 | type: function () { | ||
91 | if (this._event.type === "DOMMouseScroll") { | ||
92 | return "mousewheel"; | ||
93 | } else { | ||
94 | return this._event.type || undefined; | ||
95 | } | ||
96 | }, | ||
97 | |||
98 | /** @id MochiKit.Signal.Event.prototype.target */ | ||
99 | target: function () { | ||
100 | return this._event.target || this._event.srcElement; | ||
101 | }, | ||
102 | |||
103 | _relatedTarget: null, | ||
104 | /** @id MochiKit.Signal.Event.prototype.relatedTarget */ | ||
105 | relatedTarget: function () { | ||
106 | if (this._relatedTarget !== null) { | ||
107 | return this._relatedTarget; | ||
108 | } | ||
109 | |||
110 | var elem = null; | ||
111 | if (this.type() == 'mouseover' || this.type() == 'mouseenter') { | ||
112 | elem = (this._event.relatedTarget || | ||
113 | this._event.fromElement); | ||
114 | } else if (this.type() == 'mouseout' || this.type() == 'mouseleave') { | ||
115 | elem = (this._event.relatedTarget || | ||
116 | this._event.toElement); | ||
117 | } | ||
118 | try { | ||
119 | if (elem !== null && elem.nodeType !== null) { | ||
120 | this._relatedTarget = elem; | ||
121 | return elem; | ||
122 | } | ||
123 | } catch (ignore) { | ||
124 | // Firefox 3 throws a permission denied error when accessing | ||
125 | // any property on XUL elements (e.g. scrollbars)... | ||
126 | } | ||
127 | |||
128 | return undefined; | ||
129 | }, | ||
130 | |||
131 | _modifier: null, | ||
132 | /** @id MochiKit.Signal.Event.prototype.modifier */ | ||
133 | modifier: function () { | ||
134 | if (this._modifier !== null) { | ||
135 | return this._modifier; | ||
136 | } | ||
137 | var m = {}; | ||
138 | m.alt = this._event.altKey; | ||
139 | m.ctrl = this._event.ctrlKey; | ||
140 | m.meta = this._event.metaKey || false; // IE and Opera punt here | ||
141 | m.shift = this._event.shiftKey; | ||
142 | m.any = m.alt || m.ctrl || m.shift || m.meta; | ||
143 | this._modifier = m; | ||
144 | return m; | ||
145 | }, | ||
146 | |||
147 | _key: null, | ||
148 | /** @id MochiKit.Signal.Event.prototype.key */ | ||
149 | key: function () { | ||
150 | if (this._key !== null) { | ||
151 | return this._key; | ||
152 | } | ||
153 | var k = {}; | ||
154 | if (this.type() && this.type().indexOf('key') === 0) { | ||
155 | |||
156 | /* | ||
157 | |||
158 | If you're looking for a special key, look for it in keydown or | ||
159 | keyup, but never keypress. If you're looking for a Unicode | ||
160 | chracter, look for it with keypress, but never keyup or | ||
161 | keydown. | ||
162 | |||
163 | Notes: | ||
164 | |||
165 | FF key event behavior: | ||
166 | key event charCode keyCode | ||
167 | DOWN ku,kd 0 40 | ||
168 | DOWN kp 0 40 | ||
169 | ESC ku,kd 0 27 | ||
170 | ESC kp 0 27 | ||
171 | a ku,kd 0 65 | ||
172 | a kp 97 0 | ||
173 | shift+a ku,kd 0 65 | ||
174 | shift+a kp 65 0 | ||
175 | 1 ku,kd 0 49 | ||
176 | 1 kp 49 0 | ||
177 | shift+1 ku,kd 0 0 | ||
178 | shift+1 kp 33 0 | ||
179 | |||
180 | IE key event behavior: | ||
181 | (IE doesn't fire keypress events for special keys.) | ||
182 | key event keyCode | ||
183 | DOWN ku,kd 40 | ||
184 | DOWN kp undefined | ||
185 | ESC ku,kd 27 | ||
186 | ESC kp 27 | ||
187 | a ku,kd 65 | ||
188 | a kp 97 | ||
189 | shift+a ku,kd 65 | ||
190 | shift+a kp 65 | ||
191 | 1 ku,kd 49 | ||
192 | 1 kp 49 | ||
193 | shift+1 ku,kd 49 | ||
194 | shift+1 kp 33 | ||
195 | |||
196 | Safari key event behavior: | ||
197 | (Safari sets charCode and keyCode to something crazy for | ||
198 | special keys.) | ||
199 | key event charCode keyCode | ||
200 | DOWN ku,kd 63233 40 | ||
201 | DOWN kp 63233 63233 | ||
202 | ESC ku,kd 27 27 | ||
203 | ESC kp 27 27 | ||
204 | a ku,kd 97 65 | ||
205 | a kp 97 97 | ||
206 | shift+a ku,kd 65 65 | ||
207 | shift+a kp 65 65 | ||
208 | 1 ku,kd 49 49 | ||
209 | 1 kp 49 49 | ||
210 | shift+1 ku,kd 33 49 | ||
211 | shift+1 kp 33 33 | ||
212 | |||
213 | */ | ||
214 | |||
215 | /* look for special keys here */ | ||
216 | if (this.type() == 'keydown' || this.type() == 'keyup') { | ||
217 | k.code = this._event.keyCode; | ||
218 | k.string = (MochiKit.Signal._specialKeys[k.code] || | ||
219 | 'KEY_UNKNOWN'); | ||
220 | this._key = k; | ||
221 | return k; | ||
222 | |||
223 | /* look for characters here */ | ||
224 | } else if (this.type() == 'keypress') { | ||
225 | |||
226 | /* | ||
227 | |||
228 | Special key behavior: | ||
229 | |||
230 | IE: does not fire keypress events for special keys | ||
231 | FF: sets charCode to 0, and sets the correct keyCode | ||
232 | Safari: sets keyCode and charCode to something stupid | ||
233 | |||
234 | */ | ||
235 | |||
236 | k.code = 0; | ||
237 | k.string = ''; | ||
238 | |||
239 | if (typeof(this._event.charCode) != 'undefined' && | ||
240 | this._event.charCode !== 0 && | ||
241 | !MochiKit.Signal._specialMacKeys[this._event.charCode]) { | ||
242 | k.code = this._event.charCode; | ||
243 | k.string = String.fromCharCode(k.code); | ||
244 | } else if (this._event.keyCode && | ||
245 | typeof(this._event.charCode) == 'undefined') { // IE | ||
246 | k.code = this._event.keyCode; | ||
247 | k.string = String.fromCharCode(k.code); | ||
248 | } | ||
249 | |||
250 | this._key = k; | ||
251 | return k; | ||
252 | } | ||
253 | } | ||
254 | return undefined; | ||
255 | }, | ||
256 | |||
257 | _mouse: null, | ||
258 | /** @id MochiKit.Signal.Event.prototype.mouse */ | ||
259 | mouse: function () { | ||
260 | if (this._mouse !== null) { | ||
261 | return this._mouse; | ||
262 | } | ||
263 | |||
264 | var m = {}; | ||
265 | var e = this._event; | ||
266 | |||
267 | if (this.type() && ( | ||
268 | this.type().indexOf('mouse') === 0 || | ||
269 | this.type().indexOf('click') != -1 || | ||
270 | this.type() == 'contextmenu')) { | ||
271 | |||
272 | m.client = new MochiKit.Style.Coordinates(0, 0); | ||
273 | if (e.clientX || e.clientY) { | ||
274 | m.client.x = (!e.clientX || e.clientX < 0) ? 0 : e.clientX; | ||
275 | m.client.y = (!e.clientY || e.clientY < 0) ? 0 : e.clientY; | ||
276 | } | ||
277 | |||
278 | m.page = new MochiKit.Style.Coordinates(0, 0); | ||
279 | if (e.pageX || e.pageY) { | ||
280 | m.page.x = (!e.pageX || e.pageX < 0) ? 0 : e.pageX; | ||
281 | m.page.y = (!e.pageY || e.pageY < 0) ? 0 : e.pageY; | ||
282 | } else { | ||
283 | /* | ||
284 | |||
285 | The IE shortcut can be off by two. We fix it. See: | ||
286 | http://msdn.microsoft.com/workshop/author/dhtml/reference/methods/getboundingclientrect.asp | ||
287 | |||
288 | This is similar to the method used in | ||
289 | MochiKit.Style.getElementPosition(). | ||
290 | |||
291 | */ | ||
292 | var de = MochiKit.DOM._document.documentElement; | ||
293 | var b = MochiKit.DOM._document.body; | ||
294 | |||
295 | m.page.x = e.clientX + | ||
296 | (de.scrollLeft || b.scrollLeft) - | ||
297 | (de.clientLeft || 0); | ||
298 | |||
299 | m.page.y = e.clientY + | ||
300 | (de.scrollTop || b.scrollTop) - | ||
301 | (de.clientTop || 0); | ||
302 | |||
303 | } | ||
304 | if (this.type() != 'mousemove' && this.type() != 'mousewheel') { | ||
305 | m.button = {}; | ||
306 | m.button.left = false; | ||
307 | m.button.right = false; | ||
308 | m.button.middle = false; | ||
309 | |||
310 | /* we could check e.button, but which is more consistent */ | ||
311 | if (e.which) { | ||
312 | m.button.left = (e.which == 1); | ||
313 | m.button.middle = (e.which == 2); | ||
314 | m.button.right = (e.which == 3); | ||
315 | |||
316 | /* | ||
317 | |||
318 | Mac browsers and right click: | ||
319 | |||
320 | - Safari doesn't fire any click events on a right | ||
321 | click: | ||
322 | http://bugs.webkit.org/show_bug.cgi?id=6595 | ||
323 | |||
324 | - Firefox fires the event, and sets ctrlKey = true | ||
325 | |||
326 | - Opera fires the event, and sets metaKey = true | ||
327 | |||
328 | oncontextmenu is fired on right clicks between | ||
329 | browsers and across platforms. | ||
330 | |||
331 | */ | ||
332 | |||
333 | } else { | ||
334 | m.button.left = !!(e.button & 1); | ||
335 | m.button.right = !!(e.button & 2); | ||
336 | m.button.middle = !!(e.button & 4); | ||
337 | } | ||
338 | } | ||
339 | if (this.type() == 'mousewheel') { | ||
340 | m.wheel = new MochiKit.Style.Coordinates(0, 0); | ||
341 | if (e.wheelDeltaX || e.wheelDeltaY) { | ||
342 | m.wheel.x = e.wheelDeltaX / -40 || 0; | ||
343 | m.wheel.y = e.wheelDeltaY / -40 || 0; | ||
344 | } else if (e.wheelDelta) { | ||
345 | m.wheel.y = e.wheelDelta / -40; | ||
346 | } else { | ||
347 | m.wheel.y = e.detail || 0; | ||
348 | } | ||
349 | } | ||
350 | this._mouse = m; | ||
351 | return m; | ||
352 | } | ||
353 | return undefined; | ||
354 | }, | ||
355 | |||
356 | /** @id MochiKit.Signal.Event.prototype.stop */ | ||
357 | stop: function () { | ||
358 | this.stopPropagation(); | ||
359 | this.preventDefault(); | ||
360 | }, | ||
361 | |||
362 | /** @id MochiKit.Signal.Event.prototype.stopPropagation */ | ||
363 | stopPropagation: function () { | ||
364 | if (this._event.stopPropagation) { | ||
365 | this._event.stopPropagation(); | ||
366 | } else { | ||
367 | this._event.cancelBubble = true; | ||
368 | } | ||
369 | }, | ||
370 | |||
371 | /** @id MochiKit.Signal.Event.prototype.preventDefault */ | ||
372 | preventDefault: function () { | ||
373 | if (this._event.preventDefault) { | ||
374 | this._event.preventDefault(); | ||
375 | } else if (this._confirmUnload === null) { | ||
376 | this._event.returnValue = false; | ||
377 | } | ||
378 | }, | ||
379 | |||
380 | _confirmUnload: null, | ||
381 | |||
382 | /** @id MochiKit.Signal.Event.prototype.confirmUnload */ | ||
383 | confirmUnload: function (msg) { | ||
384 | if (this.type() == 'beforeunload') { | ||
385 | this._confirmUnload = msg; | ||
386 | this._event.returnValue = msg; | ||
387 | } | ||
388 | } | ||
389 | }); | ||
390 | |||
391 | /* Safari sets keyCode to these special values onkeypress. */ | ||
392 | MochiKit.Signal._specialMacKeys = { | ||
393 | 3: 'KEY_ENTER', | ||
394 | 63289: 'KEY_NUM_PAD_CLEAR', | ||
395 | 63276: 'KEY_PAGE_UP', | ||
396 | 63277: 'KEY_PAGE_DOWN', | ||
397 | 63275: 'KEY_END', | ||
398 | 63273: 'KEY_HOME', | ||
399 | 63234: 'KEY_ARROW_LEFT', | ||
400 | 63232: 'KEY_ARROW_UP', | ||
401 | 63235: 'KEY_ARROW_RIGHT', | ||
402 | 63233: 'KEY_ARROW_DOWN', | ||
403 | 63302: 'KEY_INSERT', | ||
404 | 63272: 'KEY_DELETE' | ||
405 | }; | ||
406 | |||
407 | /* for KEY_F1 - KEY_F12 */ | ||
408 | (function () { | ||
409 | var _specialMacKeys = MochiKit.Signal._specialMacKeys; | ||
410 | for (var i = 63236; i <= 63242; i++) { | ||
411 | // no F0 | ||
412 | _specialMacKeys[i] = 'KEY_F' + (i - 63236 + 1); | ||
413 | } | ||
414 | })(); | ||
415 | |||
416 | /* Standard keyboard key codes. */ | ||
417 | MochiKit.Signal._specialKeys = { | ||
418 | 8: 'KEY_BACKSPACE', | ||
419 | 9: 'KEY_TAB', | ||
420 | 12: 'KEY_NUM_PAD_CLEAR', // weird, for Safari and Mac FF only | ||
421 | 13: 'KEY_ENTER', | ||
422 | 16: 'KEY_SHIFT', | ||
423 | 17: 'KEY_CTRL', | ||
424 | 18: 'KEY_ALT', | ||
425 | 19: 'KEY_PAUSE', | ||
426 | 20: 'KEY_CAPS_LOCK', | ||
427 | 27: 'KEY_ESCAPE', | ||
428 | 32: 'KEY_SPACEBAR', | ||
429 | 33: 'KEY_PAGE_UP', | ||
430 | 34: 'KEY_PAGE_DOWN', | ||
431 | 35: 'KEY_END', | ||
432 | 36: 'KEY_HOME', | ||
433 | 37: 'KEY_ARROW_LEFT', | ||
434 | 38: 'KEY_ARROW_UP', | ||
435 | 39: 'KEY_ARROW_RIGHT', | ||
436 | 40: 'KEY_ARROW_DOWN', | ||
437 | 44: 'KEY_PRINT_SCREEN', | ||
438 | 45: 'KEY_INSERT', | ||
439 | 46: 'KEY_DELETE', | ||
440 | 59: 'KEY_SEMICOLON', // weird, for Safari and IE only | ||
441 | 91: 'KEY_WINDOWS_LEFT', | ||
442 | 92: 'KEY_WINDOWS_RIGHT', | ||
443 | 93: 'KEY_SELECT', | ||
444 | 106: 'KEY_NUM_PAD_ASTERISK', | ||
445 | 107: 'KEY_NUM_PAD_PLUS_SIGN', | ||
446 | 109: 'KEY_NUM_PAD_HYPHEN-MINUS', | ||
447 | 110: 'KEY_NUM_PAD_FULL_STOP', | ||
448 | 111: 'KEY_NUM_PAD_SOLIDUS', | ||
449 | 144: 'KEY_NUM_LOCK', | ||
450 | 145: 'KEY_SCROLL_LOCK', | ||
451 | 186: 'KEY_SEMICOLON', | ||
452 | 187: 'KEY_EQUALS_SIGN', | ||
453 | 188: 'KEY_COMMA', | ||
454 | 189: 'KEY_HYPHEN-MINUS', | ||
455 | 190: 'KEY_FULL_STOP', | ||
456 | 191: 'KEY_SOLIDUS', | ||
457 | 192: 'KEY_GRAVE_ACCENT', | ||
458 | 219: 'KEY_LEFT_SQUARE_BRACKET', | ||
459 | 220: 'KEY_REVERSE_SOLIDUS', | ||
460 | 221: 'KEY_RIGHT_SQUARE_BRACKET', | ||
461 | 222: 'KEY_APOSTROPHE' | ||
462 | // undefined: 'KEY_UNKNOWN' | ||
463 | }; | ||
464 | |||
465 | (function () { | ||
466 | /* for KEY_0 - KEY_9 */ | ||
467 | var _specialKeys = MochiKit.Signal._specialKeys; | ||
468 | for (var i = 48; i <= 57; i++) { | ||
469 | _specialKeys[i] = 'KEY_' + (i - 48); | ||
470 | } | ||
471 | |||
472 | /* for KEY_A - KEY_Z */ | ||
473 | for (i = 65; i <= 90; i++) { | ||
474 | _specialKeys[i] = 'KEY_' + String.fromCharCode(i); | ||
475 | } | ||
476 | |||
477 | /* for KEY_NUM_PAD_0 - KEY_NUM_PAD_9 */ | ||
478 | for (i = 96; i <= 105; i++) { | ||
479 | _specialKeys[i] = 'KEY_NUM_PAD_' + (i - 96); | ||
480 | } | ||
481 | |||
482 | /* for KEY_F1 - KEY_F12 */ | ||
483 | for (i = 112; i <= 123; i++) { | ||
484 | // no F0 | ||
485 | _specialKeys[i] = 'KEY_F' + (i - 112 + 1); | ||
486 | } | ||
487 | })(); | ||
488 | |||
489 | /* Internal object to keep track of created signals. */ | ||
490 | MochiKit.Signal.Ident = function (ident) { | ||
491 | this.source = ident.source; | ||
492 | this.signal = ident.signal; | ||
493 | this.listener = ident.listener; | ||
494 | this.isDOM = ident.isDOM; | ||
495 | this.objOrFunc = ident.objOrFunc; | ||
496 | this.funcOrStr = ident.funcOrStr; | ||
497 | this.connected = ident.connected; | ||
498 | }; | ||
499 | MochiKit.Signal.Ident.__export__ = false; | ||
500 | MochiKit.Signal.Ident.prototype = {}; | ||
501 | |||
502 | MochiKit.Base.update(MochiKit.Signal, { | ||
503 | |||
504 | _unloadCache: function () { | ||
505 | var self = MochiKit.Signal; | ||
506 | var observers = self._observers; | ||
507 | |||
508 | for (var i = 0; i < observers.length; i++) { | ||
509 | if (observers[i].signal !== 'onload' && observers[i].signal !== 'onunload') { | ||
510 | self._disconnect(observers[i]); | ||
511 | } | ||
512 | } | ||
513 | }, | ||
514 | |||
515 | _listener: function (src, sig, func, obj, isDOM) { | ||
516 | var self = MochiKit.Signal; | ||
517 | var E = self.Event; | ||
518 | if (!isDOM) { | ||
519 | /* We don't want to re-bind already bound methods */ | ||
520 | if (typeof(func.im_self) == 'undefined') { | ||
521 | return MochiKit.Base.bindLate(func, obj); | ||
522 | } else { | ||
523 | return func; | ||
524 | } | ||
525 | } | ||
526 | obj = obj || src; | ||
527 | if (typeof(func) == "string") { | ||
528 | if (sig === 'onload' || sig === 'onunload') { | ||
529 | return function (nativeEvent) { | ||
530 | obj[func].apply(obj, [new E(src, nativeEvent)]); | ||
531 | |||
532 | var ident = new MochiKit.Signal.Ident({ | ||
533 | source: src, signal: sig, objOrFunc: obj, funcOrStr: func}); | ||
534 | |||
535 | MochiKit.Signal._disconnect(ident); | ||
536 | }; | ||
537 | } else { | ||
538 | return function (nativeEvent) { | ||
539 | obj[func].apply(obj, [new E(src, nativeEvent)]); | ||
540 | }; | ||
541 | } | ||
542 | } else { | ||
543 | if (sig === 'onload' || sig === 'onunload') { | ||
544 | return function (nativeEvent) { | ||
545 | func.apply(obj, [new E(src, nativeEvent)]); | ||
546 | |||
547 | var ident = new MochiKit.Signal.Ident({ | ||
548 | source: src, signal: sig, objOrFunc: func}); | ||
549 | |||
550 | MochiKit.Signal._disconnect(ident); | ||
551 | }; | ||
552 | } else { | ||
553 | return function (nativeEvent) { | ||
554 | func.apply(obj, [new E(src, nativeEvent)]); | ||
555 | }; | ||
556 | } | ||
557 | } | ||
558 | }, | ||
559 | |||
560 | _browserAlreadyHasMouseEnterAndLeave: function () { | ||
561 | return /MSIE/.test(navigator.userAgent); | ||
562 | }, | ||
563 | |||
564 | _browserLacksMouseWheelEvent: function () { | ||
565 | return /Gecko\//.test(navigator.userAgent); | ||
566 | }, | ||
567 | |||
568 | _mouseEnterListener: function (src, sig, func, obj) { | ||
569 | var E = MochiKit.Signal.Event; | ||
570 | return function (nativeEvent) { | ||
571 | var e = new E(src, nativeEvent); | ||
572 | try { | ||
573 | e.relatedTarget().nodeName; | ||
574 | } catch (err) { | ||
575 | /* probably hit a permission denied error; possibly one of | ||
576 | * firefox's screwy anonymous DIVs inside an input element. | ||
577 | * Allow this event to propogate up. | ||
578 | */ | ||
579 | return; | ||
580 | } | ||
581 | e.stop(); | ||
582 | if (MochiKit.DOM.isChildNode(e.relatedTarget(), src)) { | ||
583 | /* We've moved between our node and a child. Ignore. */ | ||
584 | return; | ||
585 | } | ||
586 | e.type = function () { return sig; }; | ||
587 | if (typeof(func) == "string") { | ||
588 | return obj[func].apply(obj, [e]); | ||
589 | } else { | ||
590 | return func.apply(obj, [e]); | ||
591 | } | ||
592 | }; | ||
593 | }, | ||
594 | |||
595 | _getDestPair: function (objOrFunc, funcOrStr) { | ||
596 | var obj = null; | ||
597 | var func = null; | ||
598 | if (typeof(funcOrStr) != 'undefined') { | ||
599 | obj = objOrFunc; | ||
600 | func = funcOrStr; | ||
601 | if (typeof(funcOrStr) == 'string') { | ||
602 | if (typeof(objOrFunc[funcOrStr]) != "function") { | ||
603 | throw new Error("'funcOrStr' must be a function on 'objOrFunc'"); | ||
604 | } | ||
605 | } else if (typeof(funcOrStr) != 'function') { | ||
606 | throw new Error("'funcOrStr' must be a function or string"); | ||
607 | } | ||
608 | } else if (typeof(objOrFunc) != "function") { | ||
609 | throw new Error("'objOrFunc' must be a function if 'funcOrStr' is not given"); | ||
610 | } else { | ||
611 | func = objOrFunc; | ||
612 | } | ||
613 | return [obj, func]; | ||
614 | }, | ||
615 | |||
616 | /** @id MochiKit.Signal.connect */ | ||
617 | connect: function (src, sig, objOrFunc/* optional */, funcOrStr) { | ||
618 | if (typeof(src) == "string") { | ||
619 | src = MochiKit.DOM.getElement(src); | ||
620 | } | ||
621 | var self = MochiKit.Signal; | ||
622 | |||
623 | if (typeof(sig) != 'string') { | ||
624 | throw new Error("'sig' must be a string"); | ||
625 | } | ||
626 | |||
627 | var destPair = self._getDestPair(objOrFunc, funcOrStr); | ||
628 | var obj = destPair[0]; | ||
629 | var func = destPair[1]; | ||
630 | if (typeof(obj) == 'undefined' || obj === null) { | ||
631 | obj = src; | ||
632 | } | ||
633 | |||
634 | var isDOM = !!(src.addEventListener || src.attachEvent); | ||
635 | if (isDOM && (sig === "onmouseenter" || sig === "onmouseleave") | ||
636 | && !self._browserAlreadyHasMouseEnterAndLeave()) { | ||
637 | var listener = self._mouseEnterListener(src, sig.substr(2), func, obj); | ||
638 | if (sig === "onmouseenter") { | ||
639 | sig = "onmouseover"; | ||
640 | } else { | ||
641 | sig = "onmouseout"; | ||
642 | } | ||
643 | } else if (isDOM && sig == "onmousewheel" && self._browserLacksMouseWheelEvent()) { | ||
644 | var listener = self._listener(src, sig, func, obj, isDOM); | ||
645 | sig = "onDOMMouseScroll"; | ||
646 | } else { | ||
647 | var listener = self._listener(src, sig, func, obj, isDOM); | ||
648 | } | ||
649 | |||
650 | if (src.addEventListener) { | ||
651 | src.addEventListener(sig.substr(2), listener, false); | ||
652 | } else if (src.attachEvent) { | ||
653 | src.attachEvent(sig, listener); // useCapture unsupported | ||
654 | } | ||
655 | |||
656 | var ident = new MochiKit.Signal.Ident({ | ||
657 | source: src, | ||
658 | signal: sig, | ||
659 | listener: listener, | ||
660 | isDOM: isDOM, | ||
661 | objOrFunc: objOrFunc, | ||
662 | funcOrStr: funcOrStr, | ||
663 | connected: true | ||
664 | }); | ||
665 | self._observers.push(ident); | ||
666 | |||
667 | if (!isDOM && typeof(src.__connect__) == 'function') { | ||
668 | var args = MochiKit.Base.extend([ident], arguments, 1); | ||
669 | src.__connect__.apply(src, args); | ||
670 | } | ||
671 | |||
672 | return ident; | ||
673 | }, | ||
674 | |||
675 | _disconnect: function (ident) { | ||
676 | // already disconnected | ||
677 | if (!ident.connected) { | ||
678 | return; | ||
679 | } | ||
680 | ident.connected = false; | ||
681 | var src = ident.source; | ||
682 | var sig = ident.signal; | ||
683 | var listener = ident.listener; | ||
684 | // check isDOM | ||
685 | if (!ident.isDOM) { | ||
686 | if (typeof(src.__disconnect__) == 'function') { | ||
687 | src.__disconnect__(ident, sig, ident.objOrFunc, ident.funcOrStr); | ||
688 | } | ||
689 | return; | ||
690 | } | ||
691 | if (src.removeEventListener) { | ||
692 | src.removeEventListener(sig.substr(2), listener, false); | ||
693 | } else if (src.detachEvent) { | ||
694 | src.detachEvent(sig, listener); // useCapture unsupported | ||
695 | } else { | ||
696 | throw new Error("'src' must be a DOM element"); | ||
697 | } | ||
698 | }, | ||
699 | |||
700 | /** @id MochiKit.Signal.disconnect */ | ||
701 | disconnect: function (ident) { | ||
702 | var self = MochiKit.Signal; | ||
703 | var observers = self._observers; | ||
704 | var m = MochiKit.Base; | ||
705 | if (arguments.length > 1) { | ||
706 | // compatibility API | ||
707 | var src = arguments[0]; | ||
708 | if (typeof(src) == "string") { | ||
709 | src = MochiKit.DOM.getElement(src); | ||
710 | } | ||
711 | var sig = arguments[1]; | ||
712 | var obj = arguments[2]; | ||
713 | var func = arguments[3]; | ||
714 | for (var i = observers.length - 1; i >= 0; i--) { | ||
715 | var o = observers[i]; | ||
716 | if (o.source === src && o.signal === sig && o.objOrFunc === obj && o.funcOrStr === func) { | ||
717 | self._disconnect(o); | ||
718 | if (!self._lock) { | ||
719 | observers.splice(i, 1); | ||
720 | } else { | ||
721 | self._dirty = true; | ||
722 | } | ||
723 | return true; | ||
724 | } | ||
725 | } | ||
726 | } else { | ||
727 | var idx = m.findIdentical(observers, ident); | ||
728 | if (idx >= 0) { | ||
729 | self._disconnect(ident); | ||
730 | if (!self._lock) { | ||
731 | observers.splice(idx, 1); | ||
732 | } else { | ||
733 | self._dirty = true; | ||
734 | } | ||
735 | return true; | ||
736 | } | ||
737 | } | ||
738 | return false; | ||
739 | }, | ||
740 | |||
741 | /** @id MochiKit.Signal.disconnectAllTo */ | ||
742 | disconnectAllTo: function (objOrFunc, /* optional */funcOrStr) { | ||
743 | var self = MochiKit.Signal; | ||
744 | var observers = self._observers; | ||
745 | var disconnect = self._disconnect; | ||
746 | var locked = self._lock; | ||
747 | var dirty = self._dirty; | ||
748 | if (typeof(funcOrStr) === 'undefined') { | ||
749 | funcOrStr = null; | ||
750 | } | ||
751 | for (var i = observers.length - 1; i >= 0; i--) { | ||
752 | var ident = observers[i]; | ||
753 | if (ident.objOrFunc === objOrFunc && | ||
754 | (funcOrStr === null || ident.funcOrStr === funcOrStr)) { | ||
755 | disconnect(ident); | ||
756 | if (locked) { | ||
757 | dirty = true; | ||
758 | } else { | ||
759 | observers.splice(i, 1); | ||
760 | } | ||
761 | } | ||
762 | } | ||
763 | self._dirty = dirty; | ||
764 | }, | ||
765 | |||
766 | /** @id MochiKit.Signal.disconnectAll */ | ||
767 | disconnectAll: function (src/* optional */, sig) { | ||
768 | if (typeof(src) == "string") { | ||
769 | src = MochiKit.DOM.getElement(src); | ||
770 | } | ||
771 | var m = MochiKit.Base; | ||
772 | var signals = m.flattenArguments(m.extend(null, arguments, 1)); | ||
773 | var self = MochiKit.Signal; | ||
774 | var disconnect = self._disconnect; | ||
775 | var observers = self._observers; | ||
776 | var i, ident; | ||
777 | var locked = self._lock; | ||
778 | var dirty = self._dirty; | ||
779 | if (signals.length === 0) { | ||
780 | // disconnect all | ||
781 | for (i = observers.length - 1; i >= 0; i--) { | ||
782 | ident = observers[i]; | ||
783 | if (ident.source === src) { | ||
784 | disconnect(ident); | ||
785 | if (!locked) { | ||
786 | observers.splice(i, 1); | ||
787 | } else { | ||
788 | dirty = true; | ||
789 | } | ||
790 | } | ||
791 | } | ||
792 | } else { | ||
793 | var sigs = {}; | ||
794 | for (i = 0; i < signals.length; i++) { | ||
795 | sigs[signals[i]] = true; | ||
796 | } | ||
797 | for (i = observers.length - 1; i >= 0; i--) { | ||
798 | ident = observers[i]; | ||
799 | if (ident.source === src && ident.signal in sigs) { | ||
800 | disconnect(ident); | ||
801 | if (!locked) { | ||
802 | observers.splice(i, 1); | ||
803 | } else { | ||
804 | dirty = true; | ||
805 | } | ||
806 | } | ||
807 | } | ||
808 | } | ||
809 | self._dirty = dirty; | ||
810 | }, | ||
811 | |||
812 | /** @id MochiKit.Signal.signal */ | ||
813 | signal: function (src, sig) { | ||
814 | var self = MochiKit.Signal; | ||
815 | var observers = self._observers; | ||
816 | if (typeof(src) == "string") { | ||
817 | src = MochiKit.DOM.getElement(src); | ||
818 | } | ||
819 | var args = MochiKit.Base.extend(null, arguments, 2); | ||
820 | var errors = []; | ||
821 | self._lock = true; | ||
822 | for (var i = 0; i < observers.length; i++) { | ||
823 | var ident = observers[i]; | ||
824 | if (ident.source === src && ident.signal === sig && | ||
825 | ident.connected) { | ||
826 | try { | ||
827 | if (ident.isDOM && ident.funcOrStr != null) { | ||
828 | var obj = ident.objOrFunc; | ||
829 | obj[ident.funcOrStr].apply(obj, args); | ||
830 | } else if (ident.isDOM) { | ||
831 | ident.objOrFunc.apply(src, args); | ||
832 | } else { | ||
833 | ident.listener.apply(src, args); | ||
834 | } | ||
835 | } catch (e) { | ||
836 | errors.push(e); | ||
837 | } | ||
838 | } | ||
839 | } | ||
840 | self._lock = false; | ||
841 | if (self._dirty) { | ||
842 | self._dirty = false; | ||
843 | for (var i = observers.length - 1; i >= 0; i--) { | ||
844 | if (!observers[i].connected) { | ||
845 | observers.splice(i, 1); | ||
846 | } | ||
847 | } | ||
848 | } | ||
849 | if (errors.length == 1) { | ||
850 | throw errors[0]; | ||
851 | } else if (errors.length > 1) { | ||
852 | var e = new Error("Multiple errors thrown in handling 'sig', see errors property"); | ||
853 | e.errors = errors; | ||
854 | throw e; | ||
855 | } | ||
856 | } | ||
857 | |||
858 | }); | ||
859 | |||
860 | MochiKit.Signal.__new__ = function (win) { | ||
861 | var m = MochiKit.Base; | ||
862 | this._document = document; | ||
863 | this._window = win; | ||
864 | this._lock = false; | ||
865 | this._dirty = false; | ||
866 | |||
867 | try { | ||
868 | this.connect(window, 'onunload', this._unloadCache); | ||
869 | } catch (e) { | ||
870 | // pass: might not be a browser | ||
871 | } | ||
872 | |||
873 | m.nameFunctions(this); | ||
874 | }; | ||
875 | |||
876 | MochiKit.Signal.__new__(this); | ||
877 | |||
878 | // | ||
879 | // XXX: Internet Explorer blows | ||
880 | // | ||
881 | if (MochiKit.__export__) { | ||
882 | connect = MochiKit.Signal.connect; | ||
883 | disconnect = MochiKit.Signal.disconnect; | ||
884 | disconnectAll = MochiKit.Signal.disconnectAll; | ||
885 | signal = MochiKit.Signal.signal; | ||
886 | } | ||
887 | |||
888 | MochiKit.Base._exportSymbols(this, MochiKit.Signal); | ||