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