1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/tests/mochitest/ajax/mochikit/MochiKit/Signal.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,899 @@ 1.4 +/*** 1.5 + 1.6 +MochiKit.Signal 1.4 1.7 + 1.8 +See <http://mochikit.com/> for documentation, downloads, license, etc. 1.9 + 1.10 +(c) 2006 Jonathan Gardner, Beau Hartshorne, Bob Ippolito. All rights Reserved. 1.11 + 1.12 +***/ 1.13 + 1.14 +if (typeof(dojo) != 'undefined') { 1.15 + dojo.provide('MochiKit.Signal'); 1.16 + dojo.require('MochiKit.Base'); 1.17 + dojo.require('MochiKit.DOM'); 1.18 + dojo.require('MochiKit.Style'); 1.19 +} 1.20 +if (typeof(JSAN) != 'undefined') { 1.21 + JSAN.use('MochiKit.Base', []); 1.22 + JSAN.use('MochiKit.DOM', []); 1.23 + JSAN.use('MochiKit.Style', []); 1.24 +} 1.25 + 1.26 +try { 1.27 + if (typeof(MochiKit.Base) == 'undefined') { 1.28 + throw ''; 1.29 + } 1.30 +} catch (e) { 1.31 + throw 'MochiKit.Signal depends on MochiKit.Base!'; 1.32 +} 1.33 + 1.34 +try { 1.35 + if (typeof(MochiKit.DOM) == 'undefined') { 1.36 + throw ''; 1.37 + } 1.38 +} catch (e) { 1.39 + throw 'MochiKit.Signal depends on MochiKit.DOM!'; 1.40 +} 1.41 + 1.42 +try { 1.43 + if (typeof(MochiKit.Style) == 'undefined') { 1.44 + throw ''; 1.45 + } 1.46 +} catch (e) { 1.47 + throw 'MochiKit.Signal depends on MochiKit.Style!'; 1.48 +} 1.49 + 1.50 +if (typeof(MochiKit.Signal) == 'undefined') { 1.51 + MochiKit.Signal = {}; 1.52 +} 1.53 + 1.54 +MochiKit.Signal.NAME = 'MochiKit.Signal'; 1.55 +MochiKit.Signal.VERSION = '1.4'; 1.56 + 1.57 +MochiKit.Signal._observers = []; 1.58 + 1.59 +/** @id MochiKit.Signal.Event */ 1.60 +MochiKit.Signal.Event = function (src, e) { 1.61 + this._event = e || window.event; 1.62 + this._src = src; 1.63 +}; 1.64 + 1.65 +MochiKit.Base.update(MochiKit.Signal.Event.prototype, { 1.66 + 1.67 + __repr__: function () { 1.68 + var repr = MochiKit.Base.repr; 1.69 + var str = '{event(): ' + repr(this.event()) + 1.70 + ', src(): ' + repr(this.src()) + 1.71 + ', type(): ' + repr(this.type()) + 1.72 + ', target(): ' + repr(this.target()); 1.73 + 1.74 + if (this.type() && 1.75 + this.type().indexOf('key') === 0 || 1.76 + this.type().indexOf('mouse') === 0 || 1.77 + this.type().indexOf('click') != -1 || 1.78 + this.type() == 'contextmenu') { 1.79 + str += ', modifier(): ' + '{alt: ' + repr(this.modifier().alt) + 1.80 + ', ctrl: ' + repr(this.modifier().ctrl) + 1.81 + ', meta: ' + repr(this.modifier().meta) + 1.82 + ', shift: ' + repr(this.modifier().shift) + 1.83 + ', any: ' + repr(this.modifier().any) + '}'; 1.84 + } 1.85 + 1.86 + if (this.type() && this.type().indexOf('key') === 0) { 1.87 + str += ', key(): {code: ' + repr(this.key().code) + 1.88 + ', string: ' + repr(this.key().string) + '}'; 1.89 + } 1.90 + 1.91 + if (this.type() && ( 1.92 + this.type().indexOf('mouse') === 0 || 1.93 + this.type().indexOf('click') != -1 || 1.94 + this.type() == 'contextmenu')) { 1.95 + 1.96 + str += ', mouse(): {page: ' + repr(this.mouse().page) + 1.97 + ', client: ' + repr(this.mouse().client); 1.98 + 1.99 + if (this.type() != 'mousemove') { 1.100 + str += ', button: {left: ' + repr(this.mouse().button.left) + 1.101 + ', middle: ' + repr(this.mouse().button.middle) + 1.102 + ', right: ' + repr(this.mouse().button.right) + '}}'; 1.103 + } else { 1.104 + str += '}'; 1.105 + } 1.106 + } 1.107 + if (this.type() == 'mouseover' || this.type() == 'mouseout') { 1.108 + str += ', relatedTarget(): ' + repr(this.relatedTarget()); 1.109 + } 1.110 + str += '}'; 1.111 + return str; 1.112 + }, 1.113 + 1.114 + /** @id MochiKit.Signal.Event.prototype.toString */ 1.115 + toString: function () { 1.116 + return this.__repr__(); 1.117 + }, 1.118 + 1.119 + /** @id MochiKit.Signal.Event.prototype.src */ 1.120 + src: function () { 1.121 + return this._src; 1.122 + }, 1.123 + 1.124 + /** @id MochiKit.Signal.Event.prototype.event */ 1.125 + event: function () { 1.126 + return this._event; 1.127 + }, 1.128 + 1.129 + /** @id MochiKit.Signal.Event.prototype.type */ 1.130 + type: function () { 1.131 + return this._event.type || undefined; 1.132 + }, 1.133 + 1.134 + /** @id MochiKit.Signal.Event.prototype.target */ 1.135 + target: function () { 1.136 + return this._event.target || this._event.srcElement; 1.137 + }, 1.138 + 1.139 + _relatedTarget: null, 1.140 + /** @id MochiKit.Signal.Event.prototype.relatedTarget */ 1.141 + relatedTarget: function () { 1.142 + if (this._relatedTarget !== null) { 1.143 + return this._relatedTarget; 1.144 + } 1.145 + 1.146 + var elem = null; 1.147 + if (this.type() == 'mouseover') { 1.148 + elem = (this._event.relatedTarget || 1.149 + this._event.fromElement); 1.150 + } else if (this.type() == 'mouseout') { 1.151 + elem = (this._event.relatedTarget || 1.152 + this._event.toElement); 1.153 + } 1.154 + if (elem !== null) { 1.155 + this._relatedTarget = elem; 1.156 + return elem; 1.157 + } 1.158 + 1.159 + return undefined; 1.160 + }, 1.161 + 1.162 + _modifier: null, 1.163 + /** @id MochiKit.Signal.Event.prototype.modifier */ 1.164 + modifier: function () { 1.165 + if (this._modifier !== null) { 1.166 + return this._modifier; 1.167 + } 1.168 + var m = {}; 1.169 + m.alt = this._event.altKey; 1.170 + m.ctrl = this._event.ctrlKey; 1.171 + m.meta = this._event.metaKey || false; // IE and Opera punt here 1.172 + m.shift = this._event.shiftKey; 1.173 + m.any = m.alt || m.ctrl || m.shift || m.meta; 1.174 + this._modifier = m; 1.175 + return m; 1.176 + }, 1.177 + 1.178 + _key: null, 1.179 + /** @id MochiKit.Signal.Event.prototype.key */ 1.180 + key: function () { 1.181 + if (this._key !== null) { 1.182 + return this._key; 1.183 + } 1.184 + var k = {}; 1.185 + if (this.type() && this.type().indexOf('key') === 0) { 1.186 + 1.187 + /* 1.188 + 1.189 + If you're looking for a special key, look for it in keydown or 1.190 + keyup, but never keypress. If you're looking for a Unicode 1.191 + chracter, look for it with keypress, but never keyup or 1.192 + keydown. 1.193 + 1.194 + Notes: 1.195 + 1.196 + FF key event behavior: 1.197 + key event charCode keyCode 1.198 + DOWN ku,kd 0 40 1.199 + DOWN kp 0 40 1.200 + ESC ku,kd 0 27 1.201 + ESC kp 0 27 1.202 + a ku,kd 0 65 1.203 + a kp 97 0 1.204 + shift+a ku,kd 0 65 1.205 + shift+a kp 65 0 1.206 + 1 ku,kd 0 49 1.207 + 1 kp 49 0 1.208 + shift+1 ku,kd 0 0 1.209 + shift+1 kp 33 0 1.210 + 1.211 + IE key event behavior: 1.212 + (IE doesn't fire keypress events for special keys.) 1.213 + key event keyCode 1.214 + DOWN ku,kd 40 1.215 + DOWN kp undefined 1.216 + ESC ku,kd 27 1.217 + ESC kp 27 1.218 + a ku,kd 65 1.219 + a kp 97 1.220 + shift+a ku,kd 65 1.221 + shift+a kp 65 1.222 + 1 ku,kd 49 1.223 + 1 kp 49 1.224 + shift+1 ku,kd 49 1.225 + shift+1 kp 33 1.226 + 1.227 + Safari key event behavior: 1.228 + (Safari sets charCode and keyCode to something crazy for 1.229 + special keys.) 1.230 + key event charCode keyCode 1.231 + DOWN ku,kd 63233 40 1.232 + DOWN kp 63233 63233 1.233 + ESC ku,kd 27 27 1.234 + ESC kp 27 27 1.235 + a ku,kd 97 65 1.236 + a kp 97 97 1.237 + shift+a ku,kd 65 65 1.238 + shift+a kp 65 65 1.239 + 1 ku,kd 49 49 1.240 + 1 kp 49 49 1.241 + shift+1 ku,kd 33 49 1.242 + shift+1 kp 33 33 1.243 + 1.244 + */ 1.245 + 1.246 + /* look for special keys here */ 1.247 + if (this.type() == 'keydown' || this.type() == 'keyup') { 1.248 + k.code = this._event.keyCode; 1.249 + k.string = (MochiKit.Signal._specialKeys[k.code] || 1.250 + 'KEY_UNKNOWN'); 1.251 + this._key = k; 1.252 + return k; 1.253 + 1.254 + /* look for characters here */ 1.255 + } else if (this.type() == 'keypress') { 1.256 + 1.257 + /* 1.258 + 1.259 + Special key behavior: 1.260 + 1.261 + IE: does not fire keypress events for special keys 1.262 + FF: sets charCode to 0, and sets the correct keyCode 1.263 + Safari: sets keyCode and charCode to something stupid 1.264 + 1.265 + */ 1.266 + 1.267 + k.code = 0; 1.268 + k.string = ''; 1.269 + 1.270 + if (typeof(this._event.charCode) != 'undefined' && 1.271 + this._event.charCode !== 0 && 1.272 + !MochiKit.Signal._specialMacKeys[this._event.charCode]) { 1.273 + k.code = this._event.charCode; 1.274 + k.string = String.fromCharCode(k.code); 1.275 + } else if (this._event.keyCode && 1.276 + typeof(this._event.charCode) == 'undefined') { // IE 1.277 + k.code = this._event.keyCode; 1.278 + k.string = String.fromCharCode(k.code); 1.279 + } 1.280 + 1.281 + this._key = k; 1.282 + return k; 1.283 + } 1.284 + } 1.285 + return undefined; 1.286 + }, 1.287 + 1.288 + _mouse: null, 1.289 + /** @id MochiKit.Signal.Event.prototype.mouse */ 1.290 + mouse: function () { 1.291 + if (this._mouse !== null) { 1.292 + return this._mouse; 1.293 + } 1.294 + 1.295 + var m = {}; 1.296 + var e = this._event; 1.297 + 1.298 + if (this.type() && ( 1.299 + this.type().indexOf('mouse') === 0 || 1.300 + this.type().indexOf('click') != -1 || 1.301 + this.type() == 'contextmenu')) { 1.302 + 1.303 + m.client = new MochiKit.Style.Coordinates(0, 0); 1.304 + if (e.clientX || e.clientY) { 1.305 + m.client.x = (!e.clientX || e.clientX < 0) ? 0 : e.clientX; 1.306 + m.client.y = (!e.clientY || e.clientY < 0) ? 0 : e.clientY; 1.307 + } 1.308 + 1.309 + m.page = new MochiKit.Style.Coordinates(0, 0); 1.310 + if (e.pageX || e.pageY) { 1.311 + m.page.x = (!e.pageX || e.pageX < 0) ? 0 : e.pageX; 1.312 + m.page.y = (!e.pageY || e.pageY < 0) ? 0 : e.pageY; 1.313 + } else { 1.314 + /* 1.315 + 1.316 + The IE shortcut can be off by two. We fix it. See: 1.317 + http://msdn.microsoft.com/workshop/author/dhtml/reference/methods/getboundingclientrect.asp 1.318 + 1.319 + This is similar to the method used in 1.320 + MochiKit.Style.getElementPosition(). 1.321 + 1.322 + */ 1.323 + var de = MochiKit.DOM._document.documentElement; 1.324 + var b = MochiKit.DOM._document.body; 1.325 + 1.326 + m.page.x = e.clientX + 1.327 + (de.scrollLeft || b.scrollLeft) - 1.328 + (de.clientLeft || 0); 1.329 + 1.330 + m.page.y = e.clientY + 1.331 + (de.scrollTop || b.scrollTop) - 1.332 + (de.clientTop || 0); 1.333 + 1.334 + } 1.335 + if (this.type() != 'mousemove') { 1.336 + m.button = {}; 1.337 + m.button.left = false; 1.338 + m.button.right = false; 1.339 + m.button.middle = false; 1.340 + 1.341 + /* we could check e.button, but which is more consistent */ 1.342 + if (e.which) { 1.343 + m.button.left = (e.which == 1); 1.344 + m.button.middle = (e.which == 2); 1.345 + m.button.right = (e.which == 3); 1.346 + 1.347 + /* 1.348 + 1.349 + Mac browsers and right click: 1.350 + 1.351 + - Safari doesn't fire any click events on a right 1.352 + click: 1.353 + http://bugs.webkit.org/show_bug.cgi?id=6595 1.354 + 1.355 + - Firefox fires the event, and sets ctrlKey = true 1.356 + 1.357 + - Opera fires the event, and sets metaKey = true 1.358 + 1.359 + oncontextmenu is fired on right clicks between 1.360 + browsers and across platforms. 1.361 + 1.362 + */ 1.363 + 1.364 + } else { 1.365 + m.button.left = !!(e.button & 1); 1.366 + m.button.right = !!(e.button & 2); 1.367 + m.button.middle = !!(e.button & 4); 1.368 + } 1.369 + } 1.370 + this._mouse = m; 1.371 + return m; 1.372 + } 1.373 + return undefined; 1.374 + }, 1.375 + 1.376 + /** @id MochiKit.Signal.Event.prototype.stop */ 1.377 + stop: function () { 1.378 + this.stopPropagation(); 1.379 + this.preventDefault(); 1.380 + }, 1.381 + 1.382 + /** @id MochiKit.Signal.Event.prototype.stopPropagation */ 1.383 + stopPropagation: function () { 1.384 + if (this._event.stopPropagation) { 1.385 + this._event.stopPropagation(); 1.386 + } else { 1.387 + this._event.cancelBubble = true; 1.388 + } 1.389 + }, 1.390 + 1.391 + /** @id MochiKit.Signal.Event.prototype.preventDefault */ 1.392 + preventDefault: function () { 1.393 + if (this._event.preventDefault) { 1.394 + this._event.preventDefault(); 1.395 + } else if (this._confirmUnload === null) { 1.396 + this._event.returnValue = false; 1.397 + } 1.398 + }, 1.399 + 1.400 + _confirmUnload: null, 1.401 + 1.402 + /** @id MochiKit.Signal.Event.prototype.confirmUnload */ 1.403 + confirmUnload: function (msg) { 1.404 + if (this.type() == 'beforeunload') { 1.405 + this._confirmUnload = msg; 1.406 + this._event.returnValue = msg; 1.407 + } 1.408 + } 1.409 +}); 1.410 + 1.411 +/* Safari sets keyCode to these special values onkeypress. */ 1.412 +MochiKit.Signal._specialMacKeys = { 1.413 + 3: 'KEY_ENTER', 1.414 + 63289: 'KEY_NUM_PAD_CLEAR', 1.415 + 63276: 'KEY_PAGE_UP', 1.416 + 63277: 'KEY_PAGE_DOWN', 1.417 + 63275: 'KEY_END', 1.418 + 63273: 'KEY_HOME', 1.419 + 63234: 'KEY_ARROW_LEFT', 1.420 + 63232: 'KEY_ARROW_UP', 1.421 + 63235: 'KEY_ARROW_RIGHT', 1.422 + 63233: 'KEY_ARROW_DOWN', 1.423 + 63302: 'KEY_INSERT', 1.424 + 63272: 'KEY_DELETE' 1.425 +}; 1.426 + 1.427 +/* for KEY_F1 - KEY_F12 */ 1.428 +(function () { 1.429 + var _specialMacKeys = MochiKit.Signal._specialMacKeys; 1.430 + for (i = 63236; i <= 63242; i++) { 1.431 + // no F0 1.432 + _specialMacKeys[i] = 'KEY_F' + (i - 63236 + 1); 1.433 + } 1.434 +})(); 1.435 + 1.436 +/* Standard keyboard key codes. */ 1.437 +MochiKit.Signal._specialKeys = { 1.438 + 8: 'KEY_BACKSPACE', 1.439 + 9: 'KEY_TAB', 1.440 + 12: 'KEY_NUM_PAD_CLEAR', // weird, for Safari and Mac FF only 1.441 + 13: 'KEY_ENTER', 1.442 + 16: 'KEY_SHIFT', 1.443 + 17: 'KEY_CTRL', 1.444 + 18: 'KEY_ALT', 1.445 + 19: 'KEY_PAUSE', 1.446 + 20: 'KEY_CAPS_LOCK', 1.447 + 27: 'KEY_ESCAPE', 1.448 + 32: 'KEY_SPACEBAR', 1.449 + 33: 'KEY_PAGE_UP', 1.450 + 34: 'KEY_PAGE_DOWN', 1.451 + 35: 'KEY_END', 1.452 + 36: 'KEY_HOME', 1.453 + 37: 'KEY_ARROW_LEFT', 1.454 + 38: 'KEY_ARROW_UP', 1.455 + 39: 'KEY_ARROW_RIGHT', 1.456 + 40: 'KEY_ARROW_DOWN', 1.457 + 44: 'KEY_PRINT_SCREEN', 1.458 + 45: 'KEY_INSERT', 1.459 + 46: 'KEY_DELETE', 1.460 + 59: 'KEY_SEMICOLON', // weird, for Safari and IE only 1.461 + 91: 'KEY_WINDOWS_LEFT', 1.462 + 92: 'KEY_WINDOWS_RIGHT', 1.463 + 93: 'KEY_SELECT', 1.464 + 106: 'KEY_NUM_PAD_ASTERISK', 1.465 + 107: 'KEY_NUM_PAD_PLUS_SIGN', 1.466 + 109: 'KEY_NUM_PAD_HYPHEN-MINUS', 1.467 + 110: 'KEY_NUM_PAD_FULL_STOP', 1.468 + 111: 'KEY_NUM_PAD_SOLIDUS', 1.469 + 144: 'KEY_NUM_LOCK', 1.470 + 145: 'KEY_SCROLL_LOCK', 1.471 + 186: 'KEY_SEMICOLON', 1.472 + 187: 'KEY_EQUALS_SIGN', 1.473 + 188: 'KEY_COMMA', 1.474 + 189: 'KEY_HYPHEN-MINUS', 1.475 + 190: 'KEY_FULL_STOP', 1.476 + 191: 'KEY_SOLIDUS', 1.477 + 192: 'KEY_GRAVE_ACCENT', 1.478 + 219: 'KEY_LEFT_SQUARE_BRACKET', 1.479 + 220: 'KEY_REVERSE_SOLIDUS', 1.480 + 221: 'KEY_RIGHT_SQUARE_BRACKET', 1.481 + 222: 'KEY_APOSTROPHE' 1.482 + // undefined: 'KEY_UNKNOWN' 1.483 +}; 1.484 + 1.485 +(function () { 1.486 + /* for KEY_0 - KEY_9 */ 1.487 + var _specialKeys = MochiKit.Signal._specialKeys; 1.488 + for (var i = 48; i <= 57; i++) { 1.489 + _specialKeys[i] = 'KEY_' + (i - 48); 1.490 + } 1.491 + 1.492 + /* for KEY_A - KEY_Z */ 1.493 + for (i = 65; i <= 90; i++) { 1.494 + _specialKeys[i] = 'KEY_' + String.fromCharCode(i); 1.495 + } 1.496 + 1.497 + /* for KEY_NUM_PAD_0 - KEY_NUM_PAD_9 */ 1.498 + for (i = 96; i <= 105; i++) { 1.499 + _specialKeys[i] = 'KEY_NUM_PAD_' + (i - 96); 1.500 + } 1.501 + 1.502 + /* for KEY_F1 - KEY_F12 */ 1.503 + for (i = 112; i <= 123; i++) { 1.504 + // no F0 1.505 + _specialKeys[i] = 'KEY_F' + (i - 112 + 1); 1.506 + } 1.507 +})(); 1.508 + 1.509 +/* Internal object to keep track of created signals. */ 1.510 +MochiKit.Signal.Ident = function (ident) { 1.511 + this.source = ident.source; 1.512 + this.signal = ident.signal; 1.513 + this.listener = ident.listener; 1.514 + this.isDOM = ident.isDOM; 1.515 + this.objOrFunc = ident.objOrFunc; 1.516 + this.funcOrStr = ident.funcOrStr; 1.517 + this.connected = ident.connected; 1.518 +}; 1.519 + 1.520 +MochiKit.Signal.Ident.prototype = {}; 1.521 + 1.522 +MochiKit.Base.update(MochiKit.Signal, { 1.523 + 1.524 + __repr__: function () { 1.525 + return '[' + this.NAME + ' ' + this.VERSION + ']'; 1.526 + }, 1.527 + 1.528 + toString: function () { 1.529 + return this.__repr__(); 1.530 + }, 1.531 + 1.532 + _unloadCache: function () { 1.533 + var self = MochiKit.Signal; 1.534 + var observers = self._observers; 1.535 + 1.536 + for (var i = 0; i < observers.length; i++) { 1.537 + if (observers[i].signal !== 'onload' && observers[i].signal !== 'onunload') { 1.538 + self._disconnect(observers[i]); 1.539 + } 1.540 + } 1.541 + }, 1.542 + 1.543 + _listener: function (src, sig, func, obj, isDOM) { 1.544 + var self = MochiKit.Signal; 1.545 + var E = self.Event; 1.546 + if (!isDOM) { 1.547 + return MochiKit.Base.bind(func, obj); 1.548 + } 1.549 + obj = obj || src; 1.550 + if (typeof(func) == "string") { 1.551 + if (sig === 'onload' || sig === 'onunload') { 1.552 + return function (nativeEvent) { 1.553 + obj[func].apply(obj, [new E(src, nativeEvent)]); 1.554 + 1.555 + var ident = new MochiKit.Signal.Ident({ 1.556 + source: src, signal: sig, objOrFunc: obj, funcOrStr: func}); 1.557 + 1.558 + MochiKit.Signal._disconnect(ident); 1.559 + }; 1.560 + } else { 1.561 + return function (nativeEvent) { 1.562 + obj[func].apply(obj, [new E(src, nativeEvent)]); 1.563 + }; 1.564 + } 1.565 + } else { 1.566 + if (sig === 'onload' || sig === 'onunload') { 1.567 + return function (nativeEvent) { 1.568 + func.apply(obj, [new E(src, nativeEvent)]); 1.569 + MochiKit.Signal.disconnect(src, sig, func); 1.570 + 1.571 + var ident = new MochiKit.Signal.Ident({ 1.572 + source: src, signal: sig, objOrFunc: func}); 1.573 + 1.574 + MochiKit.Signal._disconnect(ident); 1.575 + }; 1.576 + } else { 1.577 + return function (nativeEvent) { 1.578 + func.apply(obj, [new E(src, nativeEvent)]); 1.579 + }; 1.580 + } 1.581 + } 1.582 + }, 1.583 + 1.584 + _browserAlreadyHasMouseEnterAndLeave: function () { 1.585 + return /MSIE/.test(navigator.userAgent); 1.586 + }, 1.587 + 1.588 + _mouseEnterListener: function (src, sig, func, obj) { 1.589 + var E = MochiKit.Signal.Event; 1.590 + return function (nativeEvent) { 1.591 + var e = new E(src, nativeEvent); 1.592 + try { 1.593 + e.relatedTarget().nodeName; 1.594 + } catch (err) { 1.595 + /* probably hit a permission denied error; possibly one of 1.596 + * firefox's screwy anonymous DIVs inside an input element. 1.597 + * Allow this event to propogate up. 1.598 + */ 1.599 + return; 1.600 + } 1.601 + e.stop(); 1.602 + if (MochiKit.DOM.isChildNode(e.relatedTarget(), src)) { 1.603 + /* We've moved between our node and a child. Ignore. */ 1.604 + return; 1.605 + } 1.606 + e.type = function () { return sig; }; 1.607 + if (typeof(func) == "string") { 1.608 + return obj[func].apply(obj, [e]); 1.609 + } else { 1.610 + return func.apply(obj, [e]); 1.611 + } 1.612 + }; 1.613 + }, 1.614 + 1.615 + _getDestPair: function (objOrFunc, funcOrStr) { 1.616 + var obj = null; 1.617 + var func = null; 1.618 + if (typeof(funcOrStr) != 'undefined') { 1.619 + obj = objOrFunc; 1.620 + func = funcOrStr; 1.621 + if (typeof(funcOrStr) == 'string') { 1.622 + if (typeof(objOrFunc[funcOrStr]) != "function") { 1.623 + throw new Error("'funcOrStr' must be a function on 'objOrFunc'"); 1.624 + } 1.625 + } else if (typeof(funcOrStr) != 'function') { 1.626 + throw new Error("'funcOrStr' must be a function or string"); 1.627 + } 1.628 + } else if (typeof(objOrFunc) != "function") { 1.629 + throw new Error("'objOrFunc' must be a function if 'funcOrStr' is not given"); 1.630 + } else { 1.631 + func = objOrFunc; 1.632 + } 1.633 + return [obj, func]; 1.634 + }, 1.635 + 1.636 + /** @id MochiKit.Signal.connect */ 1.637 + connect: function (src, sig, objOrFunc/* optional */, funcOrStr) { 1.638 + src = MochiKit.DOM.getElement(src); 1.639 + var self = MochiKit.Signal; 1.640 + 1.641 + if (typeof(sig) != 'string') { 1.642 + throw new Error("'sig' must be a string"); 1.643 + } 1.644 + 1.645 + var destPair = self._getDestPair(objOrFunc, funcOrStr); 1.646 + var obj = destPair[0]; 1.647 + var func = destPair[1]; 1.648 + if (typeof(obj) == 'undefined' || obj === null) { 1.649 + obj = src; 1.650 + } 1.651 + 1.652 + var isDOM = !!(src.addEventListener || src.attachEvent); 1.653 + if (isDOM && (sig === "onmouseenter" || sig === "onmouseleave") 1.654 + && !self._browserAlreadyHasMouseEnterAndLeave()) { 1.655 + var listener = self._mouseEnterListener(src, sig.substr(2), func, obj); 1.656 + if (sig === "onmouseenter") { 1.657 + sig = "onmouseover"; 1.658 + } else { 1.659 + sig = "onmouseout"; 1.660 + } 1.661 + } else { 1.662 + var listener = self._listener(src, sig, func, obj, isDOM); 1.663 + } 1.664 + 1.665 + if (src.addEventListener) { 1.666 + src.addEventListener(sig.substr(2), listener, false); 1.667 + } else if (src.attachEvent) { 1.668 + src.attachEvent(sig, listener); // useCapture unsupported 1.669 + } 1.670 + 1.671 + var ident = new MochiKit.Signal.Ident({ 1.672 + source: src, 1.673 + signal: sig, 1.674 + listener: listener, 1.675 + isDOM: isDOM, 1.676 + objOrFunc: objOrFunc, 1.677 + funcOrStr: funcOrStr, 1.678 + connected: true 1.679 + }); 1.680 + self._observers.push(ident); 1.681 + 1.682 + if (!isDOM && typeof(src.__connect__) == 'function') { 1.683 + var args = MochiKit.Base.extend([ident], arguments, 1); 1.684 + src.__connect__.apply(src, args); 1.685 + } 1.686 + 1.687 + return ident; 1.688 + }, 1.689 + 1.690 + _disconnect: function (ident) { 1.691 + // already disconnected 1.692 + if (!ident.connected) { 1.693 + return; 1.694 + } 1.695 + ident.connected = false; 1.696 + // check isDOM 1.697 + if (!ident.isDOM) { 1.698 + return; 1.699 + } 1.700 + var src = ident.source; 1.701 + var sig = ident.signal; 1.702 + var listener = ident.listener; 1.703 + 1.704 + if (src.removeEventListener) { 1.705 + src.removeEventListener(sig.substr(2), listener, false); 1.706 + } else if (src.detachEvent) { 1.707 + src.detachEvent(sig, listener); // useCapture unsupported 1.708 + } else { 1.709 + throw new Error("'src' must be a DOM element"); 1.710 + } 1.711 + }, 1.712 + 1.713 + /** @id MochiKit.Signal.disconnect */ 1.714 + disconnect: function (ident) { 1.715 + var self = MochiKit.Signal; 1.716 + var observers = self._observers; 1.717 + var m = MochiKit.Base; 1.718 + if (arguments.length > 1) { 1.719 + // compatibility API 1.720 + var src = MochiKit.DOM.getElement(arguments[0]); 1.721 + var sig = arguments[1]; 1.722 + var obj = arguments[2]; 1.723 + var func = arguments[3]; 1.724 + for (var i = observers.length - 1; i >= 0; i--) { 1.725 + var o = observers[i]; 1.726 + if (o.source === src && o.signal === sig && o.objOrFunc === obj && o.funcOrStr === func) { 1.727 + self._disconnect(o); 1.728 + if (!self._lock) { 1.729 + observers.splice(i, 1); 1.730 + } else { 1.731 + self._dirty = true; 1.732 + } 1.733 + return true; 1.734 + } 1.735 + } 1.736 + } else { 1.737 + var idx = m.findIdentical(observers, ident); 1.738 + if (idx >= 0) { 1.739 + self._disconnect(ident); 1.740 + if (!self._lock) { 1.741 + observers.splice(idx, 1); 1.742 + } else { 1.743 + self._dirty = true; 1.744 + } 1.745 + return true; 1.746 + } 1.747 + } 1.748 + return false; 1.749 + }, 1.750 + 1.751 + /** @id MochiKit.Signal.disconnectAllTo */ 1.752 + disconnectAllTo: function (objOrFunc, /* optional */funcOrStr) { 1.753 + var self = MochiKit.Signal; 1.754 + var observers = self._observers; 1.755 + var disconnect = self._disconnect; 1.756 + var locked = self._lock; 1.757 + var dirty = self._dirty; 1.758 + if (typeof(funcOrStr) === 'undefined') { 1.759 + funcOrStr = null; 1.760 + } 1.761 + for (var i = observers.length - 1; i >= 0; i--) { 1.762 + var ident = observers[i]; 1.763 + if (ident.objOrFunc === objOrFunc && 1.764 + (funcOrStr === null || ident.funcOrStr === funcOrStr)) { 1.765 + disconnect(ident); 1.766 + if (locked) { 1.767 + dirty = true; 1.768 + } else { 1.769 + observers.splice(i, 1); 1.770 + } 1.771 + } 1.772 + } 1.773 + self._dirty = dirty; 1.774 + }, 1.775 + 1.776 + /** @id MochiKit.Signal.disconnectAll */ 1.777 + disconnectAll: function (src/* optional */, sig) { 1.778 + src = MochiKit.DOM.getElement(src); 1.779 + var m = MochiKit.Base; 1.780 + var signals = m.flattenArguments(m.extend(null, arguments, 1)); 1.781 + var self = MochiKit.Signal; 1.782 + var disconnect = self._disconnect; 1.783 + var observers = self._observers; 1.784 + var i, ident; 1.785 + var locked = self._lock; 1.786 + var dirty = self._dirty; 1.787 + if (signals.length === 0) { 1.788 + // disconnect all 1.789 + for (i = observers.length - 1; i >= 0; i--) { 1.790 + ident = observers[i]; 1.791 + if (ident.source === src) { 1.792 + disconnect(ident); 1.793 + if (!locked) { 1.794 + observers.splice(i, 1); 1.795 + } else { 1.796 + dirty = true; 1.797 + } 1.798 + } 1.799 + } 1.800 + } else { 1.801 + var sigs = {}; 1.802 + for (i = 0; i < signals.length; i++) { 1.803 + sigs[signals[i]] = true; 1.804 + } 1.805 + for (i = observers.length - 1; i >= 0; i--) { 1.806 + ident = observers[i]; 1.807 + if (ident.source === src && ident.signal in sigs) { 1.808 + disconnect(ident); 1.809 + if (!locked) { 1.810 + observers.splice(i, 1); 1.811 + } else { 1.812 + dirty = true; 1.813 + } 1.814 + } 1.815 + } 1.816 + } 1.817 + self._dirty = dirty; 1.818 + }, 1.819 + 1.820 + /** @id MochiKit.Signal.signal */ 1.821 + signal: function (src, sig) { 1.822 + var self = MochiKit.Signal; 1.823 + var observers = self._observers; 1.824 + src = MochiKit.DOM.getElement(src); 1.825 + var args = MochiKit.Base.extend(null, arguments, 2); 1.826 + var errors = []; 1.827 + self._lock = true; 1.828 + for (var i = 0; i < observers.length; i++) { 1.829 + var ident = observers[i]; 1.830 + if (ident.source === src && ident.signal === sig && 1.831 + ident.connected) { 1.832 + try { 1.833 + ident.listener.apply(src, args); 1.834 + } catch (e) { 1.835 + errors.push(e); 1.836 + } 1.837 + } 1.838 + } 1.839 + self._lock = false; 1.840 + if (self._dirty) { 1.841 + self._dirty = false; 1.842 + for (var i = observers.length - 1; i >= 0; i--) { 1.843 + if (!observers[i].connected) { 1.844 + observers.splice(i, 1); 1.845 + } 1.846 + } 1.847 + } 1.848 + if (errors.length == 1) { 1.849 + throw errors[0]; 1.850 + } else if (errors.length > 1) { 1.851 + var e = new Error("Multiple errors thrown in handling 'sig', see errors property"); 1.852 + e.errors = errors; 1.853 + throw e; 1.854 + } 1.855 + } 1.856 + 1.857 +}); 1.858 + 1.859 +MochiKit.Signal.EXPORT_OK = []; 1.860 + 1.861 +MochiKit.Signal.EXPORT = [ 1.862 + 'connect', 1.863 + 'disconnect', 1.864 + 'signal', 1.865 + 'disconnectAll', 1.866 + 'disconnectAllTo' 1.867 +]; 1.868 + 1.869 +MochiKit.Signal.__new__ = function (win) { 1.870 + var m = MochiKit.Base; 1.871 + this._document = document; 1.872 + this._window = win; 1.873 + this._lock = false; 1.874 + this._dirty = false; 1.875 + 1.876 + try { 1.877 + this.connect(window, 'onunload', this._unloadCache); 1.878 + } catch (e) { 1.879 + // pass: might not be a browser 1.880 + } 1.881 + 1.882 + this.EXPORT_TAGS = { 1.883 + ':common': this.EXPORT, 1.884 + ':all': m.concat(this.EXPORT, this.EXPORT_OK) 1.885 + }; 1.886 + 1.887 + m.nameFunctions(this); 1.888 +}; 1.889 + 1.890 +MochiKit.Signal.__new__(this); 1.891 + 1.892 +// 1.893 +// XXX: Internet Explorer blows 1.894 +// 1.895 +if (MochiKit.__export__) { 1.896 + connect = MochiKit.Signal.connect; 1.897 + disconnect = MochiKit.Signal.disconnect; 1.898 + disconnectAll = MochiKit.Signal.disconnectAll; 1.899 + signal = MochiKit.Signal.signal; 1.900 +} 1.901 + 1.902 +MochiKit.Base._exportSymbols(this, MochiKit.Signal);