oops, Dynarch.Calendar was used by CXGN.Calendar
[cxgn-jslib.git] / MochiKit / Signal.js
blobeda07ac823bfb32a97ed5fffeec1b387decc39aa
1 /***
3 MochiKit.Signal 1.4
5 See <http://mochikit.com/> for documentation, downloads, license, etc.
7 (c) 2006 Jonathan Gardner, Beau Hartshorne, Bob Ippolito. All rights Reserved.
9 ***/
11 if (typeof(dojo) != 'undefined') {
12 dojo.provide('MochiKit.Signal');
13 dojo.require('MochiKit.Base');
14 dojo.require('MochiKit.DOM');
15 dojo.require('MochiKit.Style');
17 if (typeof(JSAN) != 'undefined') {
18 JSAN.use('MochiKit.Base', []);
19 JSAN.use('MochiKit.DOM', []);
20 JSAN.use('MochiKit.Style', []);
23 try {
24 if (typeof(MochiKit.Base) == 'undefined') {
25 throw '';
27 } catch (e) {
28 throw 'MochiKit.Signal depends on MochiKit.Base!';
31 try {
32 if (typeof(MochiKit.DOM) == 'undefined') {
33 throw '';
35 } catch (e) {
36 throw 'MochiKit.Signal depends on MochiKit.DOM!';
39 try {
40 if (typeof(MochiKit.Style) == 'undefined') {
41 throw '';
43 } catch (e) {
44 throw 'MochiKit.Signal depends on MochiKit.Style!';
47 if (typeof(MochiKit.Signal) == 'undefined') {
48 MochiKit.Signal = {};
51 MochiKit.Signal.NAME = 'MochiKit.Signal';
52 MochiKit.Signal.VERSION = '1.4';
54 MochiKit.Signal._observers = [];
56 /** @id MochiKit.Signal.Event */
57 MochiKit.Signal.Event = function (src, e) {
58 this._event = e || window.event;
59 this._src = src;
62 MochiKit.Base.update(MochiKit.Signal.Event.prototype, {
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());
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) + '}';
83 if (this.type() && this.type().indexOf('key') === 0) {
84 str += ', key(): {code: ' + repr(this.key().code) +
85 ', string: ' + repr(this.key().string) + '}';
88 if (this.type() && (
89 this.type().indexOf('mouse') === 0 ||
90 this.type().indexOf('click') != -1 ||
91 this.type() == 'contextmenu')) {
93 str += ', mouse(): {page: ' + repr(this.mouse().page) +
94 ', client: ' + repr(this.mouse().client);
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 += '}';
104 if (this.type() == 'mouseover' || this.type() == 'mouseout') {
105 str += ', relatedTarget(): ' + repr(this.relatedTarget());
107 str += '}';
108 return str;
111 /** @id MochiKit.Signal.Event.prototype.toString */
112 toString: function () {
113 return this.__repr__();
116 /** @id MochiKit.Signal.Event.prototype.src */
117 src: function () {
118 return this._src;
121 /** @id MochiKit.Signal.Event.prototype.event */
122 event: function () {
123 return this._event;
126 /** @id MochiKit.Signal.Event.prototype.type */
127 type: function () {
128 return this._event.type || undefined;
131 /** @id MochiKit.Signal.Event.prototype.target */
132 target: function () {
133 return this._event.target || this._event.srcElement;
136 _relatedTarget: null,
137 /** @id MochiKit.Signal.Event.prototype.relatedTarget */
138 relatedTarget: function () {
139 if (this._relatedTarget !== null) {
140 return this._relatedTarget;
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);
151 if (elem !== null) {
152 this._relatedTarget = elem;
153 return elem;
156 return undefined;
159 _modifier: null,
160 /** @id MochiKit.Signal.Event.prototype.modifier */
161 modifier: function () {
162 if (this._modifier !== null) {
163 return this._modifier;
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;
175 _key: null,
176 /** @id MochiKit.Signal.Event.prototype.key */
177 key: function () {
178 if (this._key !== null) {
179 return this._key;
181 var k = {};
182 if (this.type() && this.type().indexOf('key') === 0) {
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.
191 Notes:
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
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
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
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;
251 /* look for characters here */
252 } else if (this.type() == 'keypress') {
256 Special key behavior:
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
264 k.code = 0;
265 k.string = '';
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);
278 this._key = k;
279 return k;
282 return undefined;
285 _mouse: null,
286 /** @id MochiKit.Signal.Event.prototype.mouse */
287 mouse: function () {
288 if (this._mouse !== null) {
289 return this._mouse;
292 var m = {};
293 var e = this._event;
295 if (this.type() && (
296 this.type().indexOf('mouse') === 0 ||
297 this.type().indexOf('click') != -1 ||
298 this.type() == 'contextmenu')) {
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;
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 {
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
316 This is similar to the method used in
317 MochiKit.Style.getElementPosition().
320 var de = MochiKit.DOM._document.documentElement;
321 var b = MochiKit.DOM._document.body;
323 m.page.x = e.clientX +
324 (de.scrollLeft || b.scrollLeft) -
325 (de.clientLeft || 0);
327 m.page.y = e.clientY +
328 (de.scrollTop || b.scrollTop) -
329 (de.clientTop || 0);
332 if (this.type() != 'mousemove') {
333 m.button = {};
334 m.button.left = false;
335 m.button.right = false;
336 m.button.middle = false;
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);
346 Mac browsers and right click:
348 - Safari doesn't fire any click events on a right
349 click:
350 http://bugs.webkit.org/show_bug.cgi?id=6595
352 - Firefox fires the event, and sets ctrlKey = true
354 - Opera fires the event, and sets metaKey = true
356 oncontextmenu is fired on right clicks between
357 browsers and across platforms.
361 } else {
362 m.button.left = !!(e.button & 1);
363 m.button.right = !!(e.button & 2);
364 m.button.middle = !!(e.button & 4);
367 this._mouse = m;
368 return m;
370 return undefined;
373 /** @id MochiKit.Signal.Event.prototype.stop */
374 stop: function () {
375 this.stopPropagation();
376 this.preventDefault();
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;
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;
397 _confirmUnload: null,
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;
408 /* Safari sets keyCode to these special values onkeypress. */
409 MochiKit.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'
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);
431 })();
433 /* Standard keyboard key codes. */
434 MochiKit.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'
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);
489 /* for KEY_A - KEY_Z */
490 for (i = 65; i <= 90; i++) {
491 _specialKeys[i] = 'KEY_' + String.fromCharCode(i);
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);
499 /* for KEY_F1 - KEY_F12 */
500 for (i = 112; i <= 123; i++) {
501 // no F0
502 _specialKeys[i] = 'KEY_F' + (i - 112 + 1);
504 })();
506 MochiKit.Base.update(MochiKit.Signal, {
508 __repr__: function () {
509 return '[' + this.NAME + ' ' + this.VERSION + ']';
512 toString: function () {
513 return this.__repr__();
516 _unloadCache: function () {
517 var self = MochiKit.Signal;
518 var observers = self._observers;
520 for (var i = 0; i < observers.length; i++) {
521 if (observers[i][1] !== 'onload' && observers[i][1] !== 'onunload') {
522 self._disconnect(observers[i]);
527 _listener: function (src, sig, func, obj, isDOM) {
528 var self = MochiKit.Signal;
529 var E = self.Event;
530 if (!isDOM) {
531 return MochiKit.Base.bind(func, obj);
533 obj = obj || src;
534 if (typeof(func) == "string") {
535 if (sig === 'onload' || sig === 'onunload') {
536 return function (nativeEvent) {
537 obj[func].apply(obj, [new E(src, nativeEvent)]);
538 MochiKit.Signal.disconnect(src, sig, obj, func);
540 } else {
541 return function (nativeEvent) {
542 obj[func].apply(obj, [new E(src, nativeEvent)]);
545 } else {
546 if (sig === 'onload' || sig === 'onunload') {
547 return function (nativeEvent) {
548 func.apply(obj, [new E(src, nativeEvent)]);
549 MochiKit.Signal.disconnect(src, sig, func);
551 } else {
552 return function (nativeEvent) {
553 func.apply(obj, [new E(src, nativeEvent)]);
559 _browserAlreadyHasMouseEnterAndLeave: function () {
560 return /MSIE/.test(navigator.userAgent);
563 _mouseEnterListener: function (src, sig, func, obj) {
564 var E = MochiKit.Signal.Event;
565 return function (nativeEvent) {
566 var e = new E(src, nativeEvent);
567 try {
568 e.relatedTarget().nodeName;
569 } catch (err) {
570 /* probably hit a permission denied error; possibly one of
571 * firefox's screwy anonymous DIVs inside an input element.
572 * Allow this event to propogate up.
574 return;
576 e.stop();
577 if (MochiKit.DOM.isChildNode(e.relatedTarget(), src)) {
578 /* We've moved between our node and a child. Ignore. */
579 return;
581 e.type = function () { return sig; };
582 if (typeof(func) == "string") {
583 return obj[func].apply(obj, [e]);
584 } else {
585 return func.apply(obj, [e]);
590 _getDestPair: function (objOrFunc, funcOrStr) {
591 var obj = null;
592 var func = null;
593 if (typeof(funcOrStr) != 'undefined') {
594 obj = objOrFunc;
595 func = funcOrStr;
596 if (typeof(funcOrStr) == 'string') {
597 if (typeof(objOrFunc[funcOrStr]) != "function") {
598 throw new Error("'funcOrStr' must be a function on 'objOrFunc'");
600 } else if (typeof(funcOrStr) != 'function') {
601 throw new Error("'funcOrStr' must be a function or string");
603 } else if (typeof(objOrFunc) != "function") {
604 throw new Error("'objOrFunc' must be a function if 'funcOrStr' is not given");
605 } else {
606 func = objOrFunc;
608 return [obj, func];
612 /** @id MochiKit.Signal.connect */
613 connect: function (src, sig, objOrFunc/* optional */, funcOrStr) {
614 src = MochiKit.DOM.getElement(src);
615 var self = MochiKit.Signal;
617 if (typeof(sig) != 'string') {
618 throw new Error("'sig' must be a string");
621 var destPair = self._getDestPair(objOrFunc, funcOrStr);
622 var obj = destPair[0];
623 var func = destPair[1];
624 if (typeof(obj) == 'undefined' || obj === null) {
625 obj = src;
628 var isDOM = !!(src.addEventListener || src.attachEvent);
629 if (isDOM && (sig === "onmouseenter" || sig === "onmouseleave")
630 && !self._browserAlreadyHasMouseEnterAndLeave()) {
631 var listener = self._mouseEnterListener(src, sig.substr(2), func, obj);
632 if (sig === "onmouseenter") {
633 sig = "onmouseover";
634 } else {
635 sig = "onmouseout";
637 } else {
638 var listener = self._listener(src, sig, func, obj, isDOM);
641 if (src.addEventListener) {
642 src.addEventListener(sig.substr(2), listener, false);
643 } else if (src.attachEvent) {
644 src.attachEvent(sig, listener); // useCapture unsupported
647 var ident = [src, sig, listener, isDOM, objOrFunc, funcOrStr, true];
648 self._observers.push(ident);
651 if (!isDOM && typeof(src.__connect__) == 'function') {
652 var args = MochiKit.Base.extend([ident], arguments, 1);
653 src.__connect__.apply(src, args);
657 return ident;
660 _disconnect: function (ident) {
661 // already disconnected
662 if (!ident[6]) { return; }
663 ident[6] = false;
664 // check isDOM
665 if (!ident[3]) { return; }
666 var src = ident[0];
667 var sig = ident[1];
668 var listener = ident[2];
670 if (src.removeEventListener) {
671 src.removeEventListener(sig.substr(2), listener, false);
672 } else if (src.detachEvent) {
673 src.detachEvent(sig, listener); // useCapture unsupported
674 } else {
675 throw new Error("'src' must be a DOM element");
679 /** @id MochiKit.Signal.disconnect */
680 disconnect: function (ident) {
681 var self = MochiKit.Signal;
682 var observers = self._observers;
683 var m = MochiKit.Base;
684 if (arguments.length > 1) {
685 // compatibility API
686 var src = MochiKit.DOM.getElement(arguments[0]);
687 var sig = arguments[1];
688 var obj = arguments[2];
689 var func = arguments[3];
690 for (var i = observers.length - 1; i >= 0; i--) {
691 var o = observers[i];
692 if (o[0] === src && o[1] === sig && o[4] === obj && o[5] === func) {
693 self._disconnect(o);
694 if (!self._lock) {
695 observers.splice(i, 1);
696 } else {
697 self._dirty = true;
699 return true;
702 } else {
703 var idx = m.findIdentical(observers, ident);
704 if (idx >= 0) {
705 self._disconnect(ident);
706 if (!self._lock) {
707 observers.splice(idx, 1);
708 } else {
709 self._dirty = true;
711 return true;
714 return false;
717 /** @id MochiKit.Signal.disconnectAllTo */
718 disconnectAllTo: function (objOrFunc, /* optional */funcOrStr) {
719 var self = MochiKit.Signal;
720 var observers = self._observers;
721 var disconnect = self._disconnect;
722 var locked = self._lock;
723 var dirty = self._dirty;
724 if (typeof(funcOrStr) === 'undefined') {
725 funcOrStr = null;
727 for (var i = observers.length - 1; i >= 0; i--) {
728 var ident = observers[i];
729 if (ident[4] === objOrFunc &&
730 (funcOrStr === null || ident[5] === funcOrStr)) {
731 disconnect(ident);
732 if (locked) {
733 dirty = true;
734 } else {
735 observers.splice(i, 1);
739 self._dirty = dirty;
742 /** @id MochiKit.Signal.disconnectAll */
743 disconnectAll: function (src/* optional */, sig) {
744 src = MochiKit.DOM.getElement(src);
745 var m = MochiKit.Base;
746 var signals = m.flattenArguments(m.extend(null, arguments, 1));
747 var self = MochiKit.Signal;
748 var disconnect = self._disconnect;
749 var observers = self._observers;
750 var i, ident;
751 var locked = self._lock;
752 var dirty = self._dirty;
753 if (signals.length === 0) {
754 // disconnect all
755 for (i = observers.length - 1; i >= 0; i--) {
756 ident = observers[i];
757 if (ident[0] === src) {
758 disconnect(ident);
759 if (!locked) {
760 observers.splice(i, 1);
761 } else {
762 dirty = true;
766 } else {
767 var sigs = {};
768 for (i = 0; i < signals.length; i++) {
769 sigs[signals[i]] = true;
771 for (i = observers.length - 1; i >= 0; i--) {
772 ident = observers[i];
773 if (ident[0] === src && ident[1] in sigs) {
774 disconnect(ident);
775 if (!locked) {
776 observers.splice(i, 1);
777 } else {
778 dirty = true;
783 self._dirty = dirty;
786 /** @id MochiKit.Signal.signal */
787 signal: function (src, sig) {
788 var self = MochiKit.Signal;
789 var observers = self._observers;
790 src = MochiKit.DOM.getElement(src);
791 var args = MochiKit.Base.extend(null, arguments, 2);
792 var errors = [];
793 self._lock = true;
794 for (var i = 0; i < observers.length; i++) {
795 var ident = observers[i];
796 if (ident[0] === src && ident[1] === sig) {
797 try {
798 ident[2].apply(src, args);
799 } catch (e) {
800 errors.push(e);
804 self._lock = false;
805 if (self._dirty) {
806 self._dirty = false;
807 for (var i = observers.length - 1; i >= 0; i--) {
808 if (!observers[i][6]) {
809 observers.splice(i, 1);
813 if (errors.length == 1) {
814 throw errors[0];
815 } else if (errors.length > 1) {
816 var e = new Error("Multiple errors thrown in handling 'sig', see errors property");
817 e.errors = errors;
818 throw e;
824 MochiKit.Signal.EXPORT_OK = [];
826 MochiKit.Signal.EXPORT = [
827 'connect',
828 'disconnect',
829 'signal',
830 'disconnectAll',
831 'disconnectAllTo'
834 MochiKit.Signal.__new__ = function (win) {
835 var m = MochiKit.Base;
836 this._document = document;
837 this._window = win;
838 this._lock = false;
839 this._dirty = false;
841 try {
842 this.connect(window, 'onunload', this._unloadCache);
843 } catch (e) {
844 // pass: might not be a browser
847 this.EXPORT_TAGS = {
848 ':common': this.EXPORT,
849 ':all': m.concat(this.EXPORT, this.EXPORT_OK)
852 m.nameFunctions(this);
855 MochiKit.Signal.__new__(this);
858 // XXX: Internet Explorer blows
860 if (MochiKit.__export__) {
861 connect = MochiKit.Signal.connect;
862 disconnect = MochiKit.Signal.disconnect;
863 disconnectAll = MochiKit.Signal.disconnectAll;
864 signal = MochiKit.Signal.signal;
867 MochiKit.Base._exportSymbols(this, MochiKit.Signal);