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