summaryrefslogtreecommitdiff
path: root/frontend/gamma/js/MochiKit/Signal.js
Unidiff
Diffstat (limited to 'frontend/gamma/js/MochiKit/Signal.js') (more/less context) (ignore whitespace changes)
-rw-r--r--frontend/gamma/js/MochiKit/Signal.js47
1 files changed, 30 insertions, 17 deletions
diff --git a/frontend/gamma/js/MochiKit/Signal.js b/frontend/gamma/js/MochiKit/Signal.js
index 7df5619..11590c1 100644
--- a/frontend/gamma/js/MochiKit/Signal.js
+++ b/frontend/gamma/js/MochiKit/Signal.js
@@ -1,59 +1,59 @@
1/*** 1/***
2 2
3MochiKit.Signal 1.5 3MochiKit.Signal 1.5
4 4
5See <http://mochikit.com/> for documentation, downloads, license, etc. 5See <http://mochikit.com/> for documentation, downloads, license, etc.
6 6
7(c) 2006 Jonathan Gardner, Beau Hartshorne, Bob Ippolito. All rights Reserved. 7(c) 2006 Jonathan Gardner, Beau Hartshorne, Bob Ippolito. All rights Reserved.
8 8
9***/ 9***/
10 10
11MochiKit.Base._module('Signal', '1.5', ['Base', 'DOM', 'Style']); 11MochiKit.Base.module(MochiKit, 'Signal', '1.5', ['Base', 'DOM']);
12 12
13MochiKit.Signal._observers = []; 13MochiKit.Signal._observers = [];
14 14
15/** @id MochiKit.Signal.Event */ 15/** @id MochiKit.Signal.Event */
16MochiKit.Signal.Event = function (src, e) { 16MochiKit.Signal.Event = function (src, e) {
17 this._event = e || window.event; 17 this._event = e || window.event;
18 this._src = src; 18 this._src = src;
19}; 19};
20MochiKit.Signal.Event.__export__ = false; 20MochiKit.Signal.Event.__export__ = false;
21 21
22MochiKit.Base.update(MochiKit.Signal.Event.prototype, { 22MochiKit.Base.update(MochiKit.Signal.Event.prototype, {
23 23
24 __repr__: function () { 24 __repr__: function () {
25 var repr = MochiKit.Base.repr; 25 var repr = MochiKit.Base.repr;
26 var str = '{event(): ' + repr(this.event()) + 26 var str = '{event(): ' + repr(this.event()) +
27 ', src(): ' + repr(this.src()) + 27 ', src(): ' + repr(this.src()) +
28 ', type(): ' + repr(this.type()) + 28 ', type(): ' + repr(this.type()) +
29 ', target(): ' + repr(this.target()); 29 ', target(): ' + repr(this.target());
30 30
31 if (this.type() && 31 if (this.type() &&
32 this.type().indexOf('key') === 0 || 32 this.type().indexOf('key') === 0 ||
33 this.type().indexOf('mouse') === 0 || 33 this.type().indexOf('mouse') === 0 ||
34 this.type().indexOf('click') != -1 || 34 this.type().indexOf('click') != -1 ||
35 this.type() == 'contextmenu') { 35 this.type() == 'contextmenu') {
36 str += ', modifier(): ' + '{alt: ' + repr(this.modifier().alt) + 36 str += ', modifier(): ' + '{alt: ' + repr(this.modifier().alt) +
37 ', ctrl: ' + repr(this.modifier().ctrl) + 37 ', ctrl: ' + repr(this.modifier().ctrl) +
38 ', meta: ' + repr(this.modifier().meta) + 38 ', meta: ' + repr(this.modifier().meta) +
39 ', shift: ' + repr(this.modifier().shift) + 39 ', shift: ' + repr(this.modifier().shift) +
40 ', any: ' + repr(this.modifier().any) + '}'; 40 ', any: ' + repr(this.modifier().any) + '}';
41 } 41 }
42 42
43 if (this.type() && this.type().indexOf('key') === 0) { 43 if (this.type() && this.type().indexOf('key') === 0) {
44 str += ', key(): {code: ' + repr(this.key().code) + 44 str += ', key(): {code: ' + repr(this.key().code) +
45 ', string: ' + repr(this.key().string) + '}'; 45 ', string: ' + repr(this.key().string) + '}';
46 } 46 }
47 47
48 if (this.type() && ( 48 if (this.type() && (
49 this.type().indexOf('mouse') === 0 || 49 this.type().indexOf('mouse') === 0 ||
50 this.type().indexOf('click') != -1 || 50 this.type().indexOf('click') != -1 ||
51 this.type() == 'contextmenu')) { 51 this.type() == 'contextmenu')) {
52 52
53 str += ', mouse(): {page: ' + repr(this.mouse().page) + 53 str += ', mouse(): {page: ' + repr(this.mouse().page) +
54 ', client: ' + repr(this.mouse().client); 54 ', client: ' + repr(this.mouse().client);
55 55
56 if (this.type() != 'mousemove' && this.type() != 'mousewheel') { 56 if (this.type() != 'mousemove' && this.type() != 'mousewheel') {
57 str += ', button: {left: ' + repr(this.mouse().button.left) + 57 str += ', button: {left: ' + repr(this.mouse().button.left) +
58 ', middle: ' + repr(this.mouse().button.middle) + 58 ', middle: ' + repr(this.mouse().button.middle) +
59 ', right: ' + repr(this.mouse().button.right) + '}'; 59 ', right: ' + repr(this.mouse().button.right) + '}';
@@ -221,168 +221,169 @@ MochiKit.Base.update(MochiKit.Signal.Event.prototype, {
221 return k; 221 return k;
222 222
223 /* look for characters here */ 223 /* look for characters here */
224 } else if (this.type() == 'keypress') { 224 } else if (this.type() == 'keypress') {
225 225
226 /* 226 /*
227 227
228 Special key behavior: 228 Special key behavior:
229 229
230 IE: does not fire keypress events for special keys 230 IE: does not fire keypress events for special keys
231 FF: sets charCode to 0, and sets the correct keyCode 231 FF: sets charCode to 0, and sets the correct keyCode
232 Safari: sets keyCode and charCode to something stupid 232 Safari: sets keyCode and charCode to something stupid
233 233
234 */ 234 */
235 235
236 k.code = 0; 236 k.code = 0;
237 k.string = ''; 237 k.string = '';
238 238
239 if (typeof(this._event.charCode) != 'undefined' && 239 if (typeof(this._event.charCode) != 'undefined' &&
240 this._event.charCode !== 0 && 240 this._event.charCode !== 0 &&
241 !MochiKit.Signal._specialMacKeys[this._event.charCode]) { 241 !MochiKit.Signal._specialMacKeys[this._event.charCode]) {
242 k.code = this._event.charCode; 242 k.code = this._event.charCode;
243 k.string = String.fromCharCode(k.code); 243 k.string = String.fromCharCode(k.code);
244 } else if (this._event.keyCode && 244 } else if (this._event.keyCode &&
245 typeof(this._event.charCode) == 'undefined') { // IE 245 typeof(this._event.charCode) == 'undefined') { // IE
246 k.code = this._event.keyCode; 246 k.code = this._event.keyCode;
247 k.string = String.fromCharCode(k.code); 247 k.string = String.fromCharCode(k.code);
248 } 248 }
249 249
250 this._key = k; 250 this._key = k;
251 return k; 251 return k;
252 } 252 }
253 } 253 }
254 return undefined; 254 return undefined;
255 }, 255 },
256 256
257 _mouse: null, 257 _mouse: null,
258 /** @id MochiKit.Signal.Event.prototype.mouse */ 258 /** @id MochiKit.Signal.Event.prototype.mouse */
259 mouse: function () { 259 mouse: function () {
260 if (this._mouse !== null) { 260 if (this._mouse !== null) {
261 return this._mouse; 261 return this._mouse;
262 } 262 }
263 263
264 var m = {}; 264 var m = {};
265 var e = this._event; 265 var e = this._event;
266 266
267 if (this.type() && ( 267 if (this.type() && (
268 this.type().indexOf('mouse') === 0 || 268 this.type().indexOf('mouse') === 0 ||
269 this.type().indexOf('drag') === 0 ||
269 this.type().indexOf('click') != -1 || 270 this.type().indexOf('click') != -1 ||
270 this.type() == 'contextmenu')) { 271 this.type() == 'contextmenu')) {
271 272
272 m.client = new MochiKit.Style.Coordinates(0, 0); 273 m.client = { x: 0, y: 0 };
273 if (e.clientX || e.clientY) { 274 if (e.clientX || e.clientY) {
274 m.client.x = (!e.clientX || e.clientX < 0) ? 0 : e.clientX; 275 m.client.x = (!e.clientX || e.clientX < 0) ? 0 : e.clientX;
275 m.client.y = (!e.clientY || e.clientY < 0) ? 0 : e.clientY; 276 m.client.y = (!e.clientY || e.clientY < 0) ? 0 : e.clientY;
276 } 277 }
277 278
278 m.page = new MochiKit.Style.Coordinates(0, 0); 279 m.page = { x: 0, y: 0 };
279 if (e.pageX || e.pageY) { 280 if (e.pageX || e.pageY) {
280 m.page.x = (!e.pageX || e.pageX < 0) ? 0 : e.pageX; 281 m.page.x = (!e.pageX || e.pageX < 0) ? 0 : e.pageX;
281 m.page.y = (!e.pageY || e.pageY < 0) ? 0 : e.pageY; 282 m.page.y = (!e.pageY || e.pageY < 0) ? 0 : e.pageY;
282 } else { 283 } else {
283 /* 284 /*
284 285
285 The IE shortcut can be off by two. We fix it. See: 286 The IE shortcut can be off by two. We fix it. See:
286 http://msdn.microsoft.com/workshop/author/dhtml/reference/methods/getboundingclientrect.asp 287 http://msdn.microsoft.com/workshop/author/dhtml/reference/methods/getboundingclientrect.asp
287 288
288 This is similar to the method used in 289 This is similar to the method used in
289 MochiKit.Style.getElementPosition(). 290 MochiKit.Style.getElementPosition().
290 291
291 */ 292 */
292 var de = MochiKit.DOM._document.documentElement; 293 var de = MochiKit.DOM._document.documentElement;
293 var b = MochiKit.DOM._document.body; 294 var b = MochiKit.DOM._document.body;
294 295
295 m.page.x = e.clientX + 296 m.page.x = e.clientX +
296 (de.scrollLeft || b.scrollLeft) - 297 (de.scrollLeft || b.scrollLeft) -
297 (de.clientLeft || 0); 298 (de.clientLeft || 0);
298 299
299 m.page.y = e.clientY + 300 m.page.y = e.clientY +
300 (de.scrollTop || b.scrollTop) - 301 (de.scrollTop || b.scrollTop) -
301 (de.clientTop || 0); 302 (de.clientTop || 0);
302 303
303 } 304 }
304 if (this.type() != 'mousemove' && this.type() != 'mousewheel') { 305 if (this.type() != 'mousemove' && this.type() != 'mousewheel') {
305 m.button = {}; 306 m.button = {};
306 m.button.left = false; 307 m.button.left = false;
307 m.button.right = false; 308 m.button.right = false;
308 m.button.middle = false; 309 m.button.middle = false;
309 310
310 /* we could check e.button, but which is more consistent */ 311 /* we could check e.button, but which is more consistent */
311 if (e.which) { 312 if (e.which) {
312 m.button.left = (e.which == 1); 313 m.button.left = (e.which == 1);
313 m.button.middle = (e.which == 2); 314 m.button.middle = (e.which == 2);
314 m.button.right = (e.which == 3); 315 m.button.right = (e.which == 3);
315 316
316 /* 317 /*
317 318
318 Mac browsers and right click: 319 Mac browsers and right click:
319 320
320 - Safari doesn't fire any click events on a right 321 - Safari doesn't fire any click events on a right
321 click: 322 click:
322 http://bugs.webkit.org/show_bug.cgi?id=6595 323 http://bugs.webkit.org/show_bug.cgi?id=6595
323 324
324 - Firefox fires the event, and sets ctrlKey = true 325 - Firefox fires the event, and sets ctrlKey = true
325 326
326 - Opera fires the event, and sets metaKey = true 327 - Opera fires the event, and sets metaKey = true
327 328
328 oncontextmenu is fired on right clicks between 329 oncontextmenu is fired on right clicks between
329 browsers and across platforms. 330 browsers and across platforms.
330 331
331 */ 332 */
332 333
333 } else { 334 } else {
334 m.button.left = !!(e.button & 1); 335 m.button.left = !!(e.button & 1);
335 m.button.right = !!(e.button & 2); 336 m.button.right = !!(e.button & 2);
336 m.button.middle = !!(e.button & 4); 337 m.button.middle = !!(e.button & 4);
337 } 338 }
338 } 339 }
339 if (this.type() == 'mousewheel') { 340 if (this.type() == 'mousewheel') {
340 m.wheel = new MochiKit.Style.Coordinates(0, 0); 341 m.wheel = { x: 0, y: 0 };
341 if (e.wheelDeltaX || e.wheelDeltaY) { 342 if (e.wheelDeltaX || e.wheelDeltaY) {
342 m.wheel.x = e.wheelDeltaX / -40 || 0; 343 m.wheel.x = e.wheelDeltaX / -40 || 0;
343 m.wheel.y = e.wheelDeltaY / -40 || 0; 344 m.wheel.y = e.wheelDeltaY / -40 || 0;
344 } else if (e.wheelDelta) { 345 } else if (e.wheelDelta) {
345 m.wheel.y = e.wheelDelta / -40; 346 m.wheel.y = e.wheelDelta / -40;
346 } else { 347 } else {
347 m.wheel.y = e.detail || 0; 348 m.wheel.y = e.detail || 0;
348 } 349 }
349 } 350 }
350 this._mouse = m; 351 this._mouse = m;
351 return m; 352 return m;
352 } 353 }
353 return undefined; 354 return undefined;
354 }, 355 },
355 356
356 /** @id MochiKit.Signal.Event.prototype.stop */ 357 /** @id MochiKit.Signal.Event.prototype.stop */
357 stop: function () { 358 stop: function () {
358 this.stopPropagation(); 359 this.stopPropagation();
359 this.preventDefault(); 360 this.preventDefault();
360 }, 361 },
361 362
362 /** @id MochiKit.Signal.Event.prototype.stopPropagation */ 363 /** @id MochiKit.Signal.Event.prototype.stopPropagation */
363 stopPropagation: function () { 364 stopPropagation: function () {
364 if (this._event.stopPropagation) { 365 if (this._event.stopPropagation) {
365 this._event.stopPropagation(); 366 this._event.stopPropagation();
366 } else { 367 } else {
367 this._event.cancelBubble = true; 368 this._event.cancelBubble = true;
368 } 369 }
369 }, 370 },
370 371
371 /** @id MochiKit.Signal.Event.prototype.preventDefault */ 372 /** @id MochiKit.Signal.Event.prototype.preventDefault */
372 preventDefault: function () { 373 preventDefault: function () {
373 if (this._event.preventDefault) { 374 if (this._event.preventDefault) {
374 this._event.preventDefault(); 375 this._event.preventDefault();
375 } else if (this._confirmUnload === null) { 376 } else if (this._confirmUnload === null) {
376 this._event.returnValue = false; 377 this._event.returnValue = false;
377 } 378 }
378 }, 379 },
379 380
380 _confirmUnload: null, 381 _confirmUnload: null,
381 382
382 /** @id MochiKit.Signal.Event.prototype.confirmUnload */ 383 /** @id MochiKit.Signal.Event.prototype.confirmUnload */
383 confirmUnload: function (msg) { 384 confirmUnload: function (msg) {
384 if (this.type() == 'beforeunload') { 385 if (this.type() == 'beforeunload') {
385 this._confirmUnload = msg; 386 this._confirmUnload = msg;
386 this._event.returnValue = msg; 387 this._event.returnValue = msg;
387 } 388 }
388 } 389 }
@@ -627,262 +628,274 @@ MochiKit.Base.update(MochiKit.Signal, {
627 var destPair = self._getDestPair(objOrFunc, funcOrStr); 628 var destPair = self._getDestPair(objOrFunc, funcOrStr);
628 var obj = destPair[0]; 629 var obj = destPair[0];
629 var func = destPair[1]; 630 var func = destPair[1];
630 if (typeof(obj) == 'undefined' || obj === null) { 631 if (typeof(obj) == 'undefined' || obj === null) {
631 obj = src; 632 obj = src;
632 } 633 }
633 634
634 var isDOM = !!(src.addEventListener || src.attachEvent); 635 var isDOM = !!(src.addEventListener || src.attachEvent);
635 if (isDOM && (sig === "onmouseenter" || sig === "onmouseleave") 636 if (isDOM && (sig === "onmouseenter" || sig === "onmouseleave")
636 && !self._browserAlreadyHasMouseEnterAndLeave()) { 637 && !self._browserAlreadyHasMouseEnterAndLeave()) {
637 var listener = self._mouseEnterListener(src, sig.substr(2), func, obj); 638 var listener = self._mouseEnterListener(src, sig.substr(2), func, obj);
638 if (sig === "onmouseenter") { 639 if (sig === "onmouseenter") {
639 sig = "onmouseover"; 640 sig = "onmouseover";
640 } else { 641 } else {
641 sig = "onmouseout"; 642 sig = "onmouseout";
642 } 643 }
643 } else if (isDOM && sig == "onmousewheel" && self._browserLacksMouseWheelEvent()) { 644 } else if (isDOM && sig == "onmousewheel" && self._browserLacksMouseWheelEvent()) {
644 var listener = self._listener(src, sig, func, obj, isDOM); 645 var listener = self._listener(src, sig, func, obj, isDOM);
645 sig = "onDOMMouseScroll"; 646 sig = "onDOMMouseScroll";
646 } else { 647 } else {
647 var listener = self._listener(src, sig, func, obj, isDOM); 648 var listener = self._listener(src, sig, func, obj, isDOM);
648 } 649 }
649 650
650 if (src.addEventListener) { 651 if (src.addEventListener) {
651 src.addEventListener(sig.substr(2), listener, false); 652 src.addEventListener(sig.substr(2), listener, false);
652 } else if (src.attachEvent) { 653 } else if (src.attachEvent) {
653 src.attachEvent(sig, listener); // useCapture unsupported 654 src.attachEvent(sig, listener); // useCapture unsupported
654 } 655 }
655 656
656 var ident = new MochiKit.Signal.Ident({ 657 var ident = new MochiKit.Signal.Ident({
657 source: src, 658 source: src,
658 signal: sig, 659 signal: sig,
659 listener: listener, 660 listener: listener,
660 isDOM: isDOM, 661 isDOM: isDOM,
661 objOrFunc: objOrFunc, 662 objOrFunc: objOrFunc,
662 funcOrStr: funcOrStr, 663 funcOrStr: funcOrStr,
663 connected: true 664 connected: true
664 }); 665 });
665 self._observers.push(ident); 666 self._observers.push(ident);
666 667
667 if (!isDOM && typeof(src.__connect__) == 'function') { 668 if (!isDOM && typeof(src.__connect__) == 'function') {
668 var args = MochiKit.Base.extend([ident], arguments, 1); 669 var args = MochiKit.Base.extend([ident], arguments, 1);
669 src.__connect__.apply(src, args); 670 src.__connect__.apply(src, args);
670 } 671 }
671 672
672 return ident; 673 return ident;
673 }, 674 },
674 675
676 /** @id MochiKit.Signal.connectOnce */
677 connectOnce: function (src, sig, objOrFunc/* optional */, funcOrStr) {
678 var self = MochiKit.Signal;
679 var ident1 = self.connect(src, sig, objOrFunc, funcOrStr);
680 var ident2;
681 ident2 = self.connect(src, sig, function() {
682 self.disconnect(ident1);
683 self.disconnect(ident2);
684 });
685 return ident1;
686 },
687
675 _disconnect: function (ident) { 688 _disconnect: function (ident) {
676 // already disconnected 689 // already disconnected
677 if (!ident.connected) { 690 if (!ident.connected) {
678 return; 691 return;
679 } 692 }
680 ident.connected = false; 693 ident.connected = false;
681 var src = ident.source; 694 var src = ident.source;
682 var sig = ident.signal; 695 var sig = ident.signal;
683 var listener = ident.listener; 696 var listener = ident.listener;
684 // check isDOM 697 // check isDOM
685 if (!ident.isDOM) { 698 if (!ident.isDOM) {
686 if (typeof(src.__disconnect__) == 'function') { 699 if (typeof(src.__disconnect__) == 'function') {
687 src.__disconnect__(ident, sig, ident.objOrFunc, ident.funcOrStr); 700 src.__disconnect__(ident, sig, ident.objOrFunc, ident.funcOrStr);
688 } 701 }
689 return; 702 return;
690 } 703 }
691 if (src.removeEventListener) { 704 if (src.removeEventListener) {
692 src.removeEventListener(sig.substr(2), listener, false); 705 src.removeEventListener(sig.substr(2), listener, false);
693 } else if (src.detachEvent) { 706 } else if (src.detachEvent) {
694 src.detachEvent(sig, listener); // useCapture unsupported 707 src.detachEvent(sig, listener); // useCapture unsupported
695 } else { 708 } else {
696 throw new Error("'src' must be a DOM element"); 709 throw new Error("'src' must be a DOM element");
697 } 710 }
698 }, 711 },
699 712
700 /** @id MochiKit.Signal.disconnect */ 713 /** @id MochiKit.Signal.disconnect */
701 disconnect: function (ident) { 714 disconnect: function (ident) {
702 var self = MochiKit.Signal; 715 var self = MochiKit.Signal;
703 var observers = self._observers; 716 var observers = self._observers;
704 var m = MochiKit.Base; 717 var m = MochiKit.Base;
705 if (arguments.length > 1) { 718 if (arguments.length > 1) {
706 // compatibility API 719 // compatibility API
707 var src = arguments[0]; 720 var src = arguments[0];
708 if (typeof(src) == "string") { 721 if (typeof(src) == "string") {
709 src = MochiKit.DOM.getElement(src); 722 src = MochiKit.DOM.getElement(src);
710 } 723 }
711 var sig = arguments[1]; 724 var sig = arguments[1];
712 var obj = arguments[2]; 725 var obj = arguments[2];
713 var func = arguments[3]; 726 var func = arguments[3];
714 for (var i = observers.length - 1; i >= 0; i--) { 727 for (var i = observers.length - 1; i >= 0; i--) {
715 var o = observers[i]; 728 var o = observers[i];
716 if (o.source === src && o.signal === sig && o.objOrFunc === obj && o.funcOrStr === func) { 729 if (o.source === src && o.signal === sig && o.objOrFunc === obj && o.funcOrStr === func) {
717 self._disconnect(o); 730 self._disconnect(o);
718 if (!self._lock) { 731 if (self._lock === 0) {
719 observers.splice(i, 1); 732 observers.splice(i, 1);
720 } else { 733 } else {
721 self._dirty = true; 734 self._dirty = true;
722 } 735 }
723 return true; 736 return true;
724 } 737 }
725 } 738 }
726 } else { 739 } else {
727 var idx = m.findIdentical(observers, ident); 740 var idx = m.findIdentical(observers, ident);
728 if (idx >= 0) { 741 if (idx >= 0) {
729 self._disconnect(ident); 742 self._disconnect(ident);
730 if (!self._lock) { 743 if (self._lock === 0) {
731 observers.splice(idx, 1); 744 observers.splice(idx, 1);
732 } else { 745 } else {
733 self._dirty = true; 746 self._dirty = true;
734 } 747 }
735 return true; 748 return true;
736 } 749 }
737 } 750 }
738 return false; 751 return false;
739 }, 752 },
740 753
741 /** @id MochiKit.Signal.disconnectAllTo */ 754 /** @id MochiKit.Signal.disconnectAllTo */
742 disconnectAllTo: function (objOrFunc, /* optional */funcOrStr) { 755 disconnectAllTo: function (objOrFunc, /* optional */funcOrStr) {
743 var self = MochiKit.Signal; 756 var self = MochiKit.Signal;
744 var observers = self._observers; 757 var observers = self._observers;
745 var disconnect = self._disconnect; 758 var disconnect = self._disconnect;
746 var locked = self._lock; 759 var lock = self._lock;
747 var dirty = self._dirty; 760 var dirty = self._dirty;
748 if (typeof(funcOrStr) === 'undefined') { 761 if (typeof(funcOrStr) === 'undefined') {
749 funcOrStr = null; 762 funcOrStr = null;
750 } 763 }
751 for (var i = observers.length - 1; i >= 0; i--) { 764 for (var i = observers.length - 1; i >= 0; i--) {
752 var ident = observers[i]; 765 var ident = observers[i];
753 if (ident.objOrFunc === objOrFunc && 766 if (ident.objOrFunc === objOrFunc &&
754 (funcOrStr === null || ident.funcOrStr === funcOrStr)) { 767 (funcOrStr === null || ident.funcOrStr === funcOrStr)) {
755 disconnect(ident); 768 disconnect(ident);
756 if (locked) { 769 if (lock === 0) {
757 dirty = true;
758 } else {
759 observers.splice(i, 1); 770 observers.splice(i, 1);
771 } else {
772 dirty = true;
760 } 773 }
761 } 774 }
762 } 775 }
763 self._dirty = dirty; 776 self._dirty = dirty;
764 }, 777 },
765 778
766 /** @id MochiKit.Signal.disconnectAll */ 779 /** @id MochiKit.Signal.disconnectAll */
767 disconnectAll: function (src/* optional */, sig) { 780 disconnectAll: function (src/* optional */, sig) {
768 if (typeof(src) == "string") { 781 if (typeof(src) == "string") {
769 src = MochiKit.DOM.getElement(src); 782 src = MochiKit.DOM.getElement(src);
770 } 783 }
771 var m = MochiKit.Base; 784 var m = MochiKit.Base;
772 var signals = m.flattenArguments(m.extend(null, arguments, 1)); 785 var signals = m.flattenArguments(m.extend(null, arguments, 1));
773 var self = MochiKit.Signal; 786 var self = MochiKit.Signal;
774 var disconnect = self._disconnect; 787 var disconnect = self._disconnect;
775 var observers = self._observers; 788 var observers = self._observers;
776 var i, ident; 789 var i, ident;
777 var locked = self._lock; 790 var lock = self._lock;
778 var dirty = self._dirty; 791 var dirty = self._dirty;
779 if (signals.length === 0) { 792 if (signals.length === 0) {
780 // disconnect all 793 // disconnect all
781 for (i = observers.length - 1; i >= 0; i--) { 794 for (i = observers.length - 1; i >= 0; i--) {
782 ident = observers[i]; 795 ident = observers[i];
783 if (ident.source === src) { 796 if (ident.source === src) {
784 disconnect(ident); 797 disconnect(ident);
785 if (!locked) { 798 if (lock === 0) {
786 observers.splice(i, 1); 799 observers.splice(i, 1);
787 } else { 800 } else {
788 dirty = true; 801 dirty = true;
789 } 802 }
790 } 803 }
791 } 804 }
792 } else { 805 } else {
793 var sigs = {}; 806 var sigs = {};
794 for (i = 0; i < signals.length; i++) { 807 for (i = 0; i < signals.length; i++) {
795 sigs[signals[i]] = true; 808 sigs[signals[i]] = true;
796 } 809 }
797 for (i = observers.length - 1; i >= 0; i--) { 810 for (i = observers.length - 1; i >= 0; i--) {
798 ident = observers[i]; 811 ident = observers[i];
799 if (ident.source === src && ident.signal in sigs) { 812 if (ident.source === src && ident.signal in sigs) {
800 disconnect(ident); 813 disconnect(ident);
801 if (!locked) { 814 if (lock === 0) {
802 observers.splice(i, 1); 815 observers.splice(i, 1);
803 } else { 816 } else {
804 dirty = true; 817 dirty = true;
805 } 818 }
806 } 819 }
807 } 820 }
808 } 821 }
809 self._dirty = dirty; 822 self._dirty = dirty;
810 }, 823 },
811 824
812 /** @id MochiKit.Signal.signal */ 825 /** @id MochiKit.Signal.signal */
813 signal: function (src, sig) { 826 signal: function (src, sig) {
814 var self = MochiKit.Signal; 827 var self = MochiKit.Signal;
815 var observers = self._observers; 828 var observers = self._observers;
816 if (typeof(src) == "string") { 829 if (typeof(src) == "string") {
817 src = MochiKit.DOM.getElement(src); 830 src = MochiKit.DOM.getElement(src);
818 } 831 }
819 var args = MochiKit.Base.extend(null, arguments, 2); 832 var args = MochiKit.Base.extend(null, arguments, 2);
820 var errors = []; 833 var errors = [];
821 self._lock = true; 834 self._lock++;
822 for (var i = 0; i < observers.length; i++) { 835 for (var i = 0; i < observers.length; i++) {
823 var ident = observers[i]; 836 var ident = observers[i];
824 if (ident.source === src && ident.signal === sig && 837 if (ident.source === src && ident.signal === sig &&
825 ident.connected) { 838 ident.connected) {
826 try { 839 try {
827 if (ident.isDOM && ident.funcOrStr != null) { 840 if (ident.isDOM && ident.funcOrStr != null) {
828 var obj = ident.objOrFunc; 841 var obj = ident.objOrFunc;
829 obj[ident.funcOrStr].apply(obj, args); 842 obj[ident.funcOrStr].apply(obj, args);
830 } else if (ident.isDOM) { 843 } else if (ident.isDOM) {
831 ident.objOrFunc.apply(src, args); 844 ident.objOrFunc.apply(src, args);
832 } else { 845 } else {
833 ident.listener.apply(src, args); 846 ident.listener.apply(src, args);
834 } 847 }
835 } catch (e) { 848 } catch (e) {
836 errors.push(e); 849 errors.push(e);
837 } 850 }
838 } 851 }
839 } 852 }
840 self._lock = false; 853 self._lock--;
841 if (self._dirty) { 854 if (self._lock === 0 && self._dirty) {
842 self._dirty = false; 855 self._dirty = false;
843 for (var i = observers.length - 1; i >= 0; i--) { 856 for (var i = observers.length - 1; i >= 0; i--) {
844 if (!observers[i].connected) { 857 if (!observers[i].connected) {
845 observers.splice(i, 1); 858 observers.splice(i, 1);
846 } 859 }
847 } 860 }
848 } 861 }
849 if (errors.length == 1) { 862 if (errors.length == 1) {
850 throw errors[0]; 863 throw errors[0];
851 } else if (errors.length > 1) { 864 } else if (errors.length > 1) {
852 var e = new Error("Multiple errors thrown in handling 'sig', see errors property"); 865 var e = new Error("Multiple errors thrown in handling 'sig', see errors property");
853 e.errors = errors; 866 e.errors = errors;
854 throw e; 867 throw e;
855 } 868 }
856 } 869 }
857 870
858}); 871});
859 872
860MochiKit.Signal.__new__ = function (win) { 873MochiKit.Signal.__new__ = function (win) {
861 var m = MochiKit.Base; 874 var m = MochiKit.Base;
862 this._document = document; 875 this._document = document;
863 this._window = win; 876 this._window = win;
864 this._lock = false; 877 this._lock = 0;
865 this._dirty = false; 878 this._dirty = false;
866 879
867 try { 880 try {
868 this.connect(window, 'onunload', this._unloadCache); 881 this.connect(window, 'onunload', this._unloadCache);
869 } catch (e) { 882 } catch (e) {
870 // pass: might not be a browser 883 // pass: might not be a browser
871 } 884 }
872 885
873 m.nameFunctions(this); 886 m.nameFunctions(this);
874}; 887};
875 888
876MochiKit.Signal.__new__(this); 889MochiKit.Signal.__new__(this);
877 890
878// 891//
879// XXX: Internet Explorer blows 892// XXX: Internet Explorer blows
880// 893//
881if (MochiKit.__export__) { 894if (MochiKit.__export__) {
882 connect = MochiKit.Signal.connect; 895 connect = MochiKit.Signal.connect;
883 disconnect = MochiKit.Signal.disconnect; 896 disconnect = MochiKit.Signal.disconnect;
884 disconnectAll = MochiKit.Signal.disconnectAll; 897 disconnectAll = MochiKit.Signal.disconnectAll;
885 signal = MochiKit.Signal.signal; 898 signal = MochiKit.Signal.signal;
886} 899}
887 900
888MochiKit.Base._exportSymbols(this, MochiKit.Signal); 901MochiKit.Base._exportSymbols(this, MochiKit.Signal);