Diffstat (limited to 'frontend/gamma/js/MochiKit/Signal.js') (more/less context) (ignore whitespace changes)
-rw-r--r-- | frontend/gamma/js/MochiKit/Signal.js | 47 |
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,107 +1,107 @@ /*** MochiKit.Signal 1.5 See <http://mochikit.com/> for documentation, downloads, license, etc. (c) 2006 Jonathan Gardner, Beau Hartshorne, Bob Ippolito. All rights Reserved. ***/ -MochiKit.Base._module('Signal', '1.5', ['Base', 'DOM', 'Style']); +MochiKit.Base.module(MochiKit, 'Signal', '1.5', ['Base', 'DOM']); MochiKit.Signal._observers = []; /** @id MochiKit.Signal.Event */ MochiKit.Signal.Event = function (src, e) { this._event = e || window.event; this._src = src; }; MochiKit.Signal.Event.__export__ = false; MochiKit.Base.update(MochiKit.Signal.Event.prototype, { __repr__: function () { var repr = MochiKit.Base.repr; var str = '{event(): ' + repr(this.event()) + ', src(): ' + repr(this.src()) + ', type(): ' + repr(this.type()) + ', target(): ' + repr(this.target()); if (this.type() && this.type().indexOf('key') === 0 || this.type().indexOf('mouse') === 0 || this.type().indexOf('click') != -1 || this.type() == 'contextmenu') { str += ', modifier(): ' + '{alt: ' + repr(this.modifier().alt) + ', ctrl: ' + repr(this.modifier().ctrl) + ', meta: ' + repr(this.modifier().meta) + ', shift: ' + repr(this.modifier().shift) + ', any: ' + repr(this.modifier().any) + '}'; } if (this.type() && this.type().indexOf('key') === 0) { str += ', key(): {code: ' + repr(this.key().code) + ', string: ' + repr(this.key().string) + '}'; } if (this.type() && ( this.type().indexOf('mouse') === 0 || this.type().indexOf('click') != -1 || this.type() == 'contextmenu')) { str += ', mouse(): {page: ' + repr(this.mouse().page) + ', client: ' + repr(this.mouse().client); if (this.type() != 'mousemove' && this.type() != 'mousewheel') { str += ', button: {left: ' + repr(this.mouse().button.left) + ', middle: ' + repr(this.mouse().button.middle) + ', right: ' + repr(this.mouse().button.right) + '}'; } if (this.type() == 'mousewheel') { str += ', wheel: ' + repr(this.mouse().wheel); } str += '}'; } if (this.type() == 'mouseover' || this.type() == 'mouseout' || this.type() == 'mouseenter' || this.type() == 'mouseleave') { str += ', relatedTarget(): ' + repr(this.relatedTarget()); } str += '}'; return str; }, /** @id MochiKit.Signal.Event.prototype.toString */ toString: function () { return this.__repr__(); }, /** @id MochiKit.Signal.Event.prototype.src */ src: function () { return this._src; }, /** @id MochiKit.Signal.Event.prototype.event */ event: function () { return this._event; }, /** @id MochiKit.Signal.Event.prototype.type */ type: function () { if (this._event.type === "DOMMouseScroll") { return "mousewheel"; } else { return this._event.type || undefined; } }, /** @id MochiKit.Signal.Event.prototype.target */ target: function () { return this._event.target || this._event.srcElement; }, _relatedTarget: null, /** @id MochiKit.Signal.Event.prototype.relatedTarget */ relatedTarget: function () { if (this._relatedTarget !== null) { return this._relatedTarget; @@ -173,264 +173,265 @@ MochiKit.Base.update(MochiKit.Signal.Event.prototype, { shift+a ku,kd 0 65 shift+a kp 65 0 1 ku,kd 0 49 1 kp 49 0 shift+1 ku,kd 0 0 shift+1 kp 33 0 IE key event behavior: (IE doesn't fire keypress events for special keys.) key event keyCode DOWN ku,kd 40 DOWN kp undefined ESC ku,kd 27 ESC kp 27 a ku,kd 65 a kp 97 shift+a ku,kd 65 shift+a kp 65 1 ku,kd 49 1 kp 49 shift+1 ku,kd 49 shift+1 kp 33 Safari key event behavior: (Safari sets charCode and keyCode to something crazy for special keys.) key event charCode keyCode DOWN ku,kd 63233 40 DOWN kp 63233 63233 ESC ku,kd 27 27 ESC kp 27 27 a ku,kd 97 65 a kp 97 97 shift+a ku,kd 65 65 shift+a kp 65 65 1 ku,kd 49 49 1 kp 49 49 shift+1 ku,kd 33 49 shift+1 kp 33 33 */ /* look for special keys here */ if (this.type() == 'keydown' || this.type() == 'keyup') { k.code = this._event.keyCode; k.string = (MochiKit.Signal._specialKeys[k.code] || 'KEY_UNKNOWN'); this._key = k; return k; /* look for characters here */ } else if (this.type() == 'keypress') { /* Special key behavior: IE: does not fire keypress events for special keys FF: sets charCode to 0, and sets the correct keyCode Safari: sets keyCode and charCode to something stupid */ k.code = 0; k.string = ''; if (typeof(this._event.charCode) != 'undefined' && this._event.charCode !== 0 && !MochiKit.Signal._specialMacKeys[this._event.charCode]) { k.code = this._event.charCode; k.string = String.fromCharCode(k.code); } else if (this._event.keyCode && typeof(this._event.charCode) == 'undefined') { // IE k.code = this._event.keyCode; k.string = String.fromCharCode(k.code); } this._key = k; return k; } } return undefined; }, _mouse: null, /** @id MochiKit.Signal.Event.prototype.mouse */ mouse: function () { if (this._mouse !== null) { return this._mouse; } var m = {}; var e = this._event; if (this.type() && ( this.type().indexOf('mouse') === 0 || + this.type().indexOf('drag') === 0 || this.type().indexOf('click') != -1 || this.type() == 'contextmenu')) { - m.client = new MochiKit.Style.Coordinates(0, 0); + m.client = { x: 0, y: 0 }; if (e.clientX || e.clientY) { m.client.x = (!e.clientX || e.clientX < 0) ? 0 : e.clientX; m.client.y = (!e.clientY || e.clientY < 0) ? 0 : e.clientY; } - m.page = new MochiKit.Style.Coordinates(0, 0); + m.page = { x: 0, y: 0 }; if (e.pageX || e.pageY) { m.page.x = (!e.pageX || e.pageX < 0) ? 0 : e.pageX; m.page.y = (!e.pageY || e.pageY < 0) ? 0 : e.pageY; } else { /* The IE shortcut can be off by two. We fix it. See: http://msdn.microsoft.com/workshop/author/dhtml/reference/methods/getboundingclientrect.asp This is similar to the method used in MochiKit.Style.getElementPosition(). */ var de = MochiKit.DOM._document.documentElement; var b = MochiKit.DOM._document.body; m.page.x = e.clientX + (de.scrollLeft || b.scrollLeft) - (de.clientLeft || 0); m.page.y = e.clientY + (de.scrollTop || b.scrollTop) - (de.clientTop || 0); } if (this.type() != 'mousemove' && this.type() != 'mousewheel') { m.button = {}; m.button.left = false; m.button.right = false; m.button.middle = false; /* we could check e.button, but which is more consistent */ if (e.which) { m.button.left = (e.which == 1); m.button.middle = (e.which == 2); m.button.right = (e.which == 3); /* Mac browsers and right click: - Safari doesn't fire any click events on a right click: http://bugs.webkit.org/show_bug.cgi?id=6595 - Firefox fires the event, and sets ctrlKey = true - Opera fires the event, and sets metaKey = true oncontextmenu is fired on right clicks between browsers and across platforms. */ } else { m.button.left = !!(e.button & 1); m.button.right = !!(e.button & 2); m.button.middle = !!(e.button & 4); } } if (this.type() == 'mousewheel') { - m.wheel = new MochiKit.Style.Coordinates(0, 0); + m.wheel = { x: 0, y: 0 }; if (e.wheelDeltaX || e.wheelDeltaY) { m.wheel.x = e.wheelDeltaX / -40 || 0; m.wheel.y = e.wheelDeltaY / -40 || 0; } else if (e.wheelDelta) { m.wheel.y = e.wheelDelta / -40; } else { m.wheel.y = e.detail || 0; } } this._mouse = m; return m; } return undefined; }, /** @id MochiKit.Signal.Event.prototype.stop */ stop: function () { this.stopPropagation(); this.preventDefault(); }, /** @id MochiKit.Signal.Event.prototype.stopPropagation */ stopPropagation: function () { if (this._event.stopPropagation) { this._event.stopPropagation(); } else { this._event.cancelBubble = true; } }, /** @id MochiKit.Signal.Event.prototype.preventDefault */ preventDefault: function () { if (this._event.preventDefault) { this._event.preventDefault(); } else if (this._confirmUnload === null) { this._event.returnValue = false; } }, _confirmUnload: null, /** @id MochiKit.Signal.Event.prototype.confirmUnload */ confirmUnload: function (msg) { if (this.type() == 'beforeunload') { this._confirmUnload = msg; this._event.returnValue = msg; } } }); /* Safari sets keyCode to these special values onkeypress. */ MochiKit.Signal._specialMacKeys = { 3: 'KEY_ENTER', 63289: 'KEY_NUM_PAD_CLEAR', 63276: 'KEY_PAGE_UP', 63277: 'KEY_PAGE_DOWN', 63275: 'KEY_END', 63273: 'KEY_HOME', 63234: 'KEY_ARROW_LEFT', 63232: 'KEY_ARROW_UP', 63235: 'KEY_ARROW_RIGHT', 63233: 'KEY_ARROW_DOWN', 63302: 'KEY_INSERT', 63272: 'KEY_DELETE' }; /* for KEY_F1 - KEY_F12 */ (function () { var _specialMacKeys = MochiKit.Signal._specialMacKeys; for (var i = 63236; i <= 63242; i++) { // no F0 _specialMacKeys[i] = 'KEY_F' + (i - 63236 + 1); } })(); /* Standard keyboard key codes. */ MochiKit.Signal._specialKeys = { 8: 'KEY_BACKSPACE', 9: 'KEY_TAB', 12: 'KEY_NUM_PAD_CLEAR', // weird, for Safari and Mac FF only 13: 'KEY_ENTER', 16: 'KEY_SHIFT', 17: 'KEY_CTRL', 18: 'KEY_ALT', 19: 'KEY_PAUSE', 20: 'KEY_CAPS_LOCK', 27: 'KEY_ESCAPE', 32: 'KEY_SPACEBAR', 33: 'KEY_PAGE_UP', 34: 'KEY_PAGE_DOWN', 35: 'KEY_END', 36: 'KEY_HOME', 37: 'KEY_ARROW_LEFT', 38: 'KEY_ARROW_UP', 39: 'KEY_ARROW_RIGHT', 40: 'KEY_ARROW_DOWN', @@ -579,310 +580,322 @@ MochiKit.Base.update(MochiKit.Signal, { return; } e.stop(); if (MochiKit.DOM.isChildNode(e.relatedTarget(), src)) { /* We've moved between our node and a child. Ignore. */ return; } e.type = function () { return sig; }; if (typeof(func) == "string") { return obj[func].apply(obj, [e]); } else { return func.apply(obj, [e]); } }; }, _getDestPair: function (objOrFunc, funcOrStr) { var obj = null; var func = null; if (typeof(funcOrStr) != 'undefined') { obj = objOrFunc; func = funcOrStr; if (typeof(funcOrStr) == 'string') { if (typeof(objOrFunc[funcOrStr]) != "function") { throw new Error("'funcOrStr' must be a function on 'objOrFunc'"); } } else if (typeof(funcOrStr) != 'function') { throw new Error("'funcOrStr' must be a function or string"); } } else if (typeof(objOrFunc) != "function") { throw new Error("'objOrFunc' must be a function if 'funcOrStr' is not given"); } else { func = objOrFunc; } return [obj, func]; }, /** @id MochiKit.Signal.connect */ connect: function (src, sig, objOrFunc/* optional */, funcOrStr) { if (typeof(src) == "string") { src = MochiKit.DOM.getElement(src); } var self = MochiKit.Signal; if (typeof(sig) != 'string') { throw new Error("'sig' must be a string"); } var destPair = self._getDestPair(objOrFunc, funcOrStr); var obj = destPair[0]; var func = destPair[1]; if (typeof(obj) == 'undefined' || obj === null) { obj = src; } var isDOM = !!(src.addEventListener || src.attachEvent); if (isDOM && (sig === "onmouseenter" || sig === "onmouseleave") && !self._browserAlreadyHasMouseEnterAndLeave()) { var listener = self._mouseEnterListener(src, sig.substr(2), func, obj); if (sig === "onmouseenter") { sig = "onmouseover"; } else { sig = "onmouseout"; } } else if (isDOM && sig == "onmousewheel" && self._browserLacksMouseWheelEvent()) { var listener = self._listener(src, sig, func, obj, isDOM); sig = "onDOMMouseScroll"; } else { var listener = self._listener(src, sig, func, obj, isDOM); } if (src.addEventListener) { src.addEventListener(sig.substr(2), listener, false); } else if (src.attachEvent) { src.attachEvent(sig, listener); // useCapture unsupported } var ident = new MochiKit.Signal.Ident({ source: src, signal: sig, listener: listener, isDOM: isDOM, objOrFunc: objOrFunc, funcOrStr: funcOrStr, connected: true }); self._observers.push(ident); if (!isDOM && typeof(src.__connect__) == 'function') { var args = MochiKit.Base.extend([ident], arguments, 1); src.__connect__.apply(src, args); } return ident; }, + /** @id MochiKit.Signal.connectOnce */ + connectOnce: function (src, sig, objOrFunc/* optional */, funcOrStr) { + var self = MochiKit.Signal; + var ident1 = self.connect(src, sig, objOrFunc, funcOrStr); + var ident2; + ident2 = self.connect(src, sig, function() { + self.disconnect(ident1); + self.disconnect(ident2); + }); + return ident1; + }, + _disconnect: function (ident) { // already disconnected if (!ident.connected) { return; } ident.connected = false; var src = ident.source; var sig = ident.signal; var listener = ident.listener; // check isDOM if (!ident.isDOM) { if (typeof(src.__disconnect__) == 'function') { src.__disconnect__(ident, sig, ident.objOrFunc, ident.funcOrStr); } return; } if (src.removeEventListener) { src.removeEventListener(sig.substr(2), listener, false); } else if (src.detachEvent) { src.detachEvent(sig, listener); // useCapture unsupported } else { throw new Error("'src' must be a DOM element"); } }, /** @id MochiKit.Signal.disconnect */ disconnect: function (ident) { var self = MochiKit.Signal; var observers = self._observers; var m = MochiKit.Base; if (arguments.length > 1) { // compatibility API var src = arguments[0]; if (typeof(src) == "string") { src = MochiKit.DOM.getElement(src); } var sig = arguments[1]; var obj = arguments[2]; var func = arguments[3]; for (var i = observers.length - 1; i >= 0; i--) { var o = observers[i]; if (o.source === src && o.signal === sig && o.objOrFunc === obj && o.funcOrStr === func) { self._disconnect(o); - if (!self._lock) { + if (self._lock === 0) { observers.splice(i, 1); } else { self._dirty = true; } return true; } } } else { var idx = m.findIdentical(observers, ident); if (idx >= 0) { self._disconnect(ident); - if (!self._lock) { + if (self._lock === 0) { observers.splice(idx, 1); } else { self._dirty = true; } return true; } } return false; }, /** @id MochiKit.Signal.disconnectAllTo */ disconnectAllTo: function (objOrFunc, /* optional */funcOrStr) { var self = MochiKit.Signal; var observers = self._observers; var disconnect = self._disconnect; - var locked = self._lock; + var lock = self._lock; var dirty = self._dirty; if (typeof(funcOrStr) === 'undefined') { funcOrStr = null; } for (var i = observers.length - 1; i >= 0; i--) { var ident = observers[i]; if (ident.objOrFunc === objOrFunc && (funcOrStr === null || ident.funcOrStr === funcOrStr)) { disconnect(ident); - if (locked) { - dirty = true; - } else { + if (lock === 0) { observers.splice(i, 1); + } else { + dirty = true; } } } self._dirty = dirty; }, /** @id MochiKit.Signal.disconnectAll */ disconnectAll: function (src/* optional */, sig) { if (typeof(src) == "string") { src = MochiKit.DOM.getElement(src); } var m = MochiKit.Base; var signals = m.flattenArguments(m.extend(null, arguments, 1)); var self = MochiKit.Signal; var disconnect = self._disconnect; var observers = self._observers; var i, ident; - var locked = self._lock; + var lock = self._lock; var dirty = self._dirty; if (signals.length === 0) { // disconnect all for (i = observers.length - 1; i >= 0; i--) { ident = observers[i]; if (ident.source === src) { disconnect(ident); - if (!locked) { + if (lock === 0) { observers.splice(i, 1); } else { dirty = true; } } } } else { var sigs = {}; for (i = 0; i < signals.length; i++) { sigs[signals[i]] = true; } for (i = observers.length - 1; i >= 0; i--) { ident = observers[i]; if (ident.source === src && ident.signal in sigs) { disconnect(ident); - if (!locked) { + if (lock === 0) { observers.splice(i, 1); } else { dirty = true; } } } } self._dirty = dirty; }, /** @id MochiKit.Signal.signal */ signal: function (src, sig) { var self = MochiKit.Signal; var observers = self._observers; if (typeof(src) == "string") { src = MochiKit.DOM.getElement(src); } var args = MochiKit.Base.extend(null, arguments, 2); var errors = []; - self._lock = true; + self._lock++; for (var i = 0; i < observers.length; i++) { var ident = observers[i]; if (ident.source === src && ident.signal === sig && ident.connected) { try { if (ident.isDOM && ident.funcOrStr != null) { var obj = ident.objOrFunc; obj[ident.funcOrStr].apply(obj, args); } else if (ident.isDOM) { ident.objOrFunc.apply(src, args); } else { ident.listener.apply(src, args); } } catch (e) { errors.push(e); } } } - self._lock = false; - if (self._dirty) { + self._lock--; + if (self._lock === 0 && self._dirty) { self._dirty = false; for (var i = observers.length - 1; i >= 0; i--) { if (!observers[i].connected) { observers.splice(i, 1); } } } if (errors.length == 1) { throw errors[0]; } else if (errors.length > 1) { var e = new Error("Multiple errors thrown in handling 'sig', see errors property"); e.errors = errors; throw e; } } }); MochiKit.Signal.__new__ = function (win) { var m = MochiKit.Base; this._document = document; this._window = win; - this._lock = false; + this._lock = 0; this._dirty = false; try { this.connect(window, 'onunload', this._unloadCache); } catch (e) { // pass: might not be a browser } m.nameFunctions(this); }; MochiKit.Signal.__new__(this); // // XXX: Internet Explorer blows // if (MochiKit.__export__) { connect = MochiKit.Signal.connect; disconnect = MochiKit.Signal.disconnect; disconnectAll = MochiKit.Signal.disconnectAll; signal = MochiKit.Signal.signal; } MochiKit.Base._exportSymbols(this, MochiKit.Signal); |