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