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