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