Changeset 723
- Timestamp:
- 04/24/06 15:21:35 (2 years ago)
- Files:
-
- mochikit/trunk/MochiKit/DOM.js (modified) (2 diffs)
- mochikit/trunk/MochiKit/Signal.js (modified) (10 diffs)
- mochikit/trunk/examples/draggable/draggable.js (modified) (3 diffs)
- mochikit/trunk/tests/test_Signal.js (modified) (3 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
mochikit/trunk/MochiKit/DOM.js
r699 r723 204 204 205 205 /* 206 elementPosition is adapted from YAHOO.util.Dom.getXY, version 0.9.0. 207 Copyright: Copyright (c) 2006, Yahoo! Inc. All rights reserved. 208 BSD License: http://developer.yahoo.net/yui/license.txt 206 207 elementPosition is adapted from YAHOO.util.Dom.getXY, version 0.9.0. 208 Copyright: Copyright (c) 2006, Yahoo! Inc. All rights reserved. 209 License: BSD, http://developer.yahoo.net/yui/license.txt 210 209 211 */ 210 212 elementPosition: function (elem, /* optional */relativeTo) { … … 239 241 240 242 The IE shortcut is off by two: 241 http://msdn.microsoft.com/workshop/author/dhtml/reference/ 242 methods/getboundingclientrect.asp 243 http://msdn.microsoft.com/workshop/author/dhtml/reference/methods/getboundingclientrect.asp 243 244 244 245 */ mochikit/trunk/MochiKit/Signal.js
r712 r723 49 49 50 50 MochiKit.Base.update(MochiKit.Signal.Event.prototype, { 51 52 _fixPoint: function (point) {53 /*54 55 FIXME: inline this to avoid funciton call overhead? Does JS have56 function call overhead? This code needs test coverage.57 58 */59 if (typeof(point) == 'undefined' || point < 0) {60 return 0;61 }62 return point;63 },64 51 65 52 event: function () { … … 90 77 m.alt = this._event.altKey; 91 78 m.ctrl = this._event.ctrlKey; 92 m.meta = this._event.metaKey || false; // ie and opera punt here79 m.meta = this._event.metaKey || false; // IE and Opera punt here 93 80 m.shift = this._event.shiftKey; 94 81 return m; … … 195 182 } 196 183 } 197 throw new Error(' Signal cannot handle this type ofkey event');184 throw new Error('This is not a key event'); 198 185 }, 199 186 200 187 mouse: function () { 201 188 var m = {}; 189 var e = this._event; 190 202 191 if (this.type() && ( 203 192 this.type().indexOf('mouse') === 0 || 204 193 this.type().indexOf('click') != -1 || 205 194 this.type() == 'contextmenu')) { 206 195 196 197 207 198 m.client = new MochiKit.DOM.Coordinates(0, 0); 208 if ( this._event.clientX || this._event.clientY) {209 m.client.x = this._fixPoint(this._event.clientX);210 m.client.y = this._fixPoint(this._event.clientY);199 if (e.clientX || e.clientY) { 200 m.client.x = (!e.clientX || e.clientX < 0) ? 0 : e.clientX; 201 m.client.y = (!e.clientY || e.clientY < 0) ? 0 : e.clientY; 211 202 } 212 203 213 204 m.page = new MochiKit.DOM.Coordinates(0, 0); 214 if ( this._event.pageX || this._event.pageY) {215 m.page.x = this._fixPoint(this._event.pageX);216 m.page.y = this._fixPoint(this._event.pageY);205 if (e.pageX || e.pageY) { 206 m.page.x = (!e.pageX || e.pageX < 0) ? 0 : e.pageX; 207 m.page.y = (!e.pageY || e.pageY < 0) ? 0 : e.pageY; 217 208 } else { 218 209 /* … … 237 228 var b = MochiKit.DOM._document.body; 238 229 239 m.page.x = this._event.clientX +230 m.page.x = e.clientX + 240 231 (de.scrollLeft || b.scrollLeft) - 241 232 (de.clientLeft || b.clientLeft); 242 233 243 m.page.y = this._event.clientY +234 m.page.y = e.clientY + 244 235 (de.scrollTop || b.scrollTop) - 245 236 (de.clientTop || b.clientTop); … … 252 243 m.button.middle = false; 253 244 254 /* we could check this._event.button, but which is more consistent */255 if ( this._event.which) {256 m.button.left = ( this._event.which == 1);257 m.button.middle = ( this._event.which == 2);258 m.button.right = ( this._event.which == 3);245 /* we could check e.button, but which is more consistent */ 246 if (e.which) { 247 m.button.left = (e.which == 1); 248 m.button.middle = (e.which == 2); 249 m.button.right = (e.which == 3); 259 250 260 251 /* … … 270 261 - Opera fires the event, and sets metaKey = true 271 262 272 oncontextmenu is fired on right clicks between browsers273 and across platforms.263 oncontextmenu is fired on right clicks between 264 browsers and across platforms. 274 265 275 266 */ 276 267 277 268 } else { 278 m.button.left = !!( this._event.button & 1);279 m.button.right = !!( this._event.button & 2);280 m.button.middle = !!( this._event.button & 4);269 m.button.left = !!(e.button & 1); 270 m.button.right = !!(e.button & 2); 271 m.button.middle = !!(e.button & 4); 281 272 } 282 273 } … … 407 398 }, 408 399 409 _getSlot: function (slot, func) {410 if (typeof(func) == 'string' || typeof(func) == 'function') {411 if (typeof(func) == 'string' &&412 typeof(slot[func]) == 'undefined') {413 throw new Error('Invalid function slot');414 }415 slot = [slot, func];416 } else if (!func && typeof(slot) == 'function') {417 slot = [slot];418 } else {419 throw new Error('Invalid slot parameters');420 }421 422 return slot;423 },424 425 400 _unloadCache: function () { 426 for (var i = 0; i < MochiKit.Signal._observers.length; i++) { 427 var src = MochiKit.Signal._observers[i][0]; 428 var sig = MochiKit.Signal._observers[i][1]; 429 var listener = MochiKit.Signal._observers[i][2]; 430 431 try { 432 if (src.removeEventListener) { 433 src.removeEventListener(sig.substr(2), listener, false); 434 } else if (src.detachEvent) { 435 src.detachEvent(sig, listener); 436 } else { 437 delete(src._signals[sig]); 438 } 439 440 delete(src._listeners[sig]); 441 delete(src._listeners); 442 delete(src._signals); 443 444 } catch(e) { 445 // pass 446 } 447 } 448 449 MochiKit.Signal._observers = undefined; 450 401 var self = MochiKit.Signal; 402 var observers = self._observers; 403 404 for (var i = 0; i < observers.length; i++) { 405 self._disconnect(observers[i]); 406 } 407 408 delete self._observers; 409 451 410 try { 452 411 window.onload = undefined; … … 462 421 }, 463 422 464 connect: function (src, sig, slot, /* optional */func) { 465 if (typeof(src) == 'string') { 466 src = MochiKit.DOM.getElement(src); 467 } 468 423 _listener: function (func, obj) { 424 return function (nativeEvent) { 425 func.apply(obj, [new MochiKit.Signal.Event(nativeEvent)]); 426 } 427 }, 428 429 connect: function (src, sig, objOrFunc/* optional */, funcOrStr) { 430 src = MochiKit.DOM.getElement(src); 431 var self = MochiKit.Signal; 432 469 433 if (typeof(sig) != 'string') { 470 434 throw new Error("'sig' must be a string"); 471 435 } 472 473 slot = MochiKit.Signal._getSlot(slot, func); 474 475 /* 476 477 Create the _listeners object. This will help us remember which 478 events we are watching. 479 480 */ 481 if (!src._listeners) { 482 src._listeners = {}; 483 } 484 485 /* Add the signal connector if it hasn't been done already. */ 486 if (!src._listeners[sig]) { 487 var listener = function (nativeEvent) { 488 var eventObject = new MochiKit.Signal.Event(nativeEvent); 489 MochiKit.Signal.signal(src, sig, eventObject); 490 return true; 491 }; 492 MochiKit.Signal._observers.push([src, sig, listener]); 493 494 if (src.addEventListener) { 495 src.addEventListener(sig.substr(2), listener, false); 496 } else if (src.attachEvent) { 497 src.attachEvent(sig, listener); // useCapture unsupported 498 } else { 499 src[sig] = listener; 500 } 501 502 src._listeners[sig] = listener; 503 } 504 505 if (!src._signals) { 506 src._signals = {}; 507 } 508 if (!src._signals[sig]) { 509 src._signals[sig] = []; 510 } 511 512 /* Actually add the slot... if it isn't there already. */ 513 var signals = src._signals[sig]; 514 for (var i = 0; i < signals.length; i++) { 515 var s = signals[i]; 516 if (slot[0] === s[0] && slot[1] === s[1] && slot[2] === s[2]) { 517 return; 518 } 519 } 520 signals.push(slot); 521 }, 522 523 disconnect: function (src, sig, slot, /* optional */func) { 524 if (typeof(src) == 'string') { 525 src = MochiKit.DOM.getElement(src); 526 } 527 528 if (typeof(sig) != 'string') { 529 throw new Error("'signal' must be a string"); 530 } 531 532 slot = MochiKit.Signal._getSlot(slot, func); 533 534 if (src._signals && src._signals[sig]) { 535 var signals = src._signals[sig]; 536 var origlen = signals.length; 436 437 if (typeof(funcOrStr) != 'undefined') { 438 if (typeof(funcOrStr) == 'string' && 439 typeof(objOrFunc[funcOrStr]) == 'undefined') { 440 throw new Error("'funcOrStr' must be a function on 'objOrFunc'"); 441 } else if (typeof(funcOrStr) != 'function') { 442 throw new Error("'funcOrStr' must be a function or string"); 443 } 444 } 445 446 var listener = null; 447 448 var _listener = self._listener; 449 if (typeof(objOrFunc) == 'function') { 450 listener = _listener(objOrFunc, null); 451 } else if (typeof(funcOrStr) == 'function') { 452 listener = _listener(funcOrStr, objOrFunc); 453 } else if (typeof(funcOrStr) == 'string') { 454 listener = _listener(objOrFunc[funcOrStr], objOrFunc); 455 } 456 457 var ident = [src, sig, listener]; 458 self._observers.push(ident); 459 460 if (src.addEventListener) { 461 src.addEventListener(sig.substr(2), listener, false); 462 } else if (src.attachEvent) { 463 src.attachEvent(sig, listener); // useCapture unsupported 464 } else { 465 throw new Error("'src' must be a DOM element"); 466 } 467 468 return ident; 469 }, 470 471 _disconnect: function (ident) { 472 var src = ident[0]; 473 var sig = ident[1]; 474 var listener = ident[2]; 475 if (src.removeEventListener) { 476 src.removeEventListener(sig.substr(2), listener, false); 477 } else if (src.detachEvent) { 478 src.detachEvent(sig, listener); // useCapture unsupported 479 } else { 480 throw new Error("'src' must be a DOM element"); 481 } 482 }, 483 484 disconnect: function (ident) { 485 var self = MochiKit.Signal; 486 var observers = self._observers; 487 var idx = MochiKit.Base.findIdentical(observers, ident); 488 if (idx >= 0) { 489 self._disconnect(observers[idx]); 490 observers.splice(idx, 1); 491 return true; 492 } 493 return false; 494 }, 495 496 disconnectAll: function(src/* optional */, sig) { 497 src = MochiKit.DOM.getElement(src); 498 var m = MochiKit.Base; 499 var signals = m.flattenArguments(m.extend(null, arguments, 1)); 500 var self = MochiKit.Signal; 501 var disconnect = self._disconnect; 502 var observers = self._observers; 503 if (signals.length == 0) { 504 // disconnect all 505 for (var i = observers.length - 1; i >= 0; i--) { 506 var ident = observers[i]; 507 if (ident[0] === src) { 508 disconnect(ident); 509 observers.splice(i, 1); 510 } 511 } 512 } else { 513 var sigs = {}; 537 514 for (var i = 0; i < signals.length; i++) { 538 var s = signals[i]; 539 if (s[0] === slot[0] && 540 s[1] === slot[1] && 541 s[2] === slot[2]) { 542 543 signals.splice(i, 1); 544 break; 545 515 sigs[signals[i]] = true; 516 } 517 for (var i = observers.length - 1; i >= 0; i--) { 518 var ident = observers[i]; 519 if (ident[0] === src && ident[1] in sigs) { 520 disconnect(ident); 521 observers.splice(i, 1); 546 522 } 547 523 } 548 } else { 549 throw new Error('Invalid signal to disconnect'); 550 } 551 552 if (src.addEventListener || src.attachEvent || src._signals[sig]) { 553 /* Stop listening if there are no connected slots. */ 554 if (src._listeners && src._listeners[sig] && 555 src._signals[sig].length === 0) { 556 557 var listener = src._listeners[sig]; 558 559 if (src.removeEventListener) { 560 src.removeEventListener(sig.substr(2), listener, false); 561 } else if (src.detachEvent) { 562 src.detachEvent(sig, listener); 563 } else { 564 src._signals[sig] = undefined; 565 } 566 567 var observers = MochiKit.Signal._observers; 568 for (var i = 0; i < observers.length; i++) { 569 var o = observers[i]; 570 if (o[0] === src && o[1] === sig && o[2] === listener) { 571 observers.splice(i, 1); 572 break; 573 } 574 } 575 src._listeners[sig] = undefined; 576 } 577 } 578 }, 579 580 signal: function (src, sig) { 581 if (typeof(src) == 'string') { 582 src = MochiKit.DOM.getElement(src); 583 } 584 585 if (typeof(sig) != 'string') { 586 throw new Error("'signal' must be a string"); 587 } 588 589 if (!src._signals || !src._signals[sig]) { 590 if (src.addEventListener || src.attachEvent || src[sig]) { 591 // Ignored. 592 return; 593 } else { 594 throw new Error("No such signal '" + sig + "'"); 595 } 596 } 597 var slots = src._signals[sig]; 598 599 var args = MochiKit.Base.extend(null, arguments, 2); 600 601 var slot; 602 var errors = []; 603 for (var i = 0; i < slots.length; i++) { 604 slot = slots[i]; 605 try { 606 if (slot.length == 1) { 607 slot[0].apply(src, args); 608 } else { 609 if (typeof(slot[1]) == 'string') { 610 slot[0][slot[1]].apply(slot[0], args); 611 } else { 612 slot[1].apply(slot[0], args); 613 } 614 } 615 } catch (e) { 616 errors.push(e); 617 } 618 } 619 if (errors.length == 1) { 620 throw errors[0]; 621 } else if (errors.length) { 622 var e = new Error("There were errors in handling signal 'sig'."); 623 e.errors = errors; 624 throw e; 625 } 524 } 525 626 526 }, 627 527 … … 636 536 'connect', 637 537 'disconnect', 638 ' signal'538 'disconnectAll' 639 539 ]; 640 540 … … 663 563 // XXX: Internet Explorer blows 664 564 // 665 signal = MochiKit.Signal.signal;666 565 connect = MochiKit.Signal.connect; 667 566 disconnect = MochiKit.Signal.disconnect; 567 disconnectAll = MochiKit.Signal.disconnectAll; 668 568 669 569 MochiKit.Base._exportSymbols(this, MochiKit.Signal); mochikit/trunk/examples/draggable/draggable.js
r691 r723 5 5 */ 6 6 Drag = { 7 _move: null, 8 _down: null, 9 7 10 start: function(e) { 8 11 e.stop(); … … 20 23 elementPosition(Drag._target)); 21 24 22 connect(document, 'onmousemove', Drag._drag);23 connect(document, 'onmouseup', Drag._stop);25 Drag._move = connect(document, 'onmousemove', Drag._drag); 26 Drag._down = connect(document, 'onmouseup', Drag._stop); 24 27 }, 25 28 … … 39 42 40 43 _stop: function(e) { 41 disconnect( document, 'onmousemove', Drag._drag);42 disconnect( document, 'onmouseup', Drag._stop);44 disconnect(Drag._move); 45 disconnect(Drag._down); 43 46 } 44 47 }; mochikit/trunk/tests/test_Signal.js
r709 r723 5 5 tests.test_Signal = function (t) { 6 6 7 var hasNoSignals = {}; 8 9 var hasSignals = {someVar: 1}; 10 7 var submit = MochiKit.DOM.getElement('submit'); 8 var ident = null; 11 9 var i = 0; 12 13 10 var aFunction = function() { 14 11 i++; … … 22 19 i++; 23 20 }; 24 25 aObject.bMethod = function() {26 i++;27 };28 29 var bObject = {};30 bObject.bMethod = function() {31 i++;32 };33 21 22 ident = connect('submit', 'onclick', aFunction); 23 MochiKit.DOM.getElement('submit').click(); 24 t.is(i, 1, 'HTML onclick event can be connected to a function'); 34 25 35 connect(hasSignals, 'signalOne', aFunction); 36 signal(hasSignals, 'signalOne'); 37 t.is(i, 2, 'Connecting function'); 38 39 disconnect(hasSignals, 'signalOne', aFunction); 40 signal(hasSignals, 'signalOne'); 41 t.is(i, 2, 'Disconnecting function'); 42 43 44 connect(hasSignals, 'signalOne', aObject, aObject.aMethod); 45 signal(hasSignals, 'signalOne'); 46 t.is(i, 3, 'Connecting obj-function'); 47 48 disconnect(hasSignals, 'signalOne', aObject, aObject.aMethod); 49 signal(hasSignals, 'signalOne'); 50 t.is(i, 3, 'Disconnecting obj-function'); 51 52 53 connect(hasSignals, 'signalTwo', aObject, 'aMethod'); 54 signal(hasSignals, 'signalTwo'); 55 t.is(i, 4, 'Connecting obj-string'); 56 57 disconnect(hasSignals, 'signalTwo', aObject, 'aMethod'); 58 signal(hasSignals, 'signalTwo'); 59 t.is(i, 4, 'Disconnecting obj-string'); 60 61 62 var shouldRaise = function() { return undefined.attr; }; 63 64 try { 65 connect(hasSignals, 'signalOne', shouldRaise); 66 signal(hasSignals, 'signalOne'); 67 t.ok(false, 'An exception was not raised'); 68 } catch (e) { 69 t.ok(true, 'An exception was raised'); 70 } 71 disconnect(hasSignals, 'signalOne', shouldRaise); 72 73 74 connect('submit', 'onclick', aFunction); 26 disconnect(ident); 75 27 MochiKit.DOM.getElement('submit').click(); 76 t.is(i, 5, 'HTML onclick event can be connected to a function'); 77 78 disconnect('submit', 'onclick', aFunction); 79 MochiKit.DOM.getElement('submit').click(); 80 t.is(i, 5, 'HTML onclick can be disconnected from a function'); 81 28 t.is(i, 1, 'HTML onclick can be disconnected from a function'); 82 29 83 30 var submit = MochiKit.DOM.getElement('submit'); 84 31 85 connect(submit, 'onclick', aFunction);32 ident = connect(submit, 'onclick', aFunction); 86 33 submit.click(); 87 t.is(i, 6, 'Checking that a DOM element can be connected to a function');34 t.is(i, 2, 'Checking that a DOM element can be connected to a function'); 88 35 89 disconnect( submit, 'onclick', aFunction);36 disconnect(ident); 90 37 submit.click(); 91 t.is(i, 6, '...and then disconnected'); 92 93 94 connect(hasSignals, 'signalOne', aObject, 'aMethod'); 95 connect(hasSignals, 'signalOne', aObject, 'bMethod'); 96 signal(hasSignals, 'signalOne'); 97 t.is(i, 8, 'Connecting one signal to two slots in one object'); 38 t.is(i, 2, '...and then disconnected'); 98 39 99 disconnect(hasSignals, 'signalOne', aObject, 'aMethod');100 disconnect(hasSignals, 'signalOne', aObject, 'bMethod');101 signal(hasSignals, 'signalOne');102 t.is(i, 8, 'Disconnecting one signal from two slots in one object');103 104 105 connect(hasSignals, 'signalOne', aObject, 'aMethod');106 connect(hasSignals, 'signalOne', bObject, 'bMethod');107 signal(hasSignals, 'signalOne');108 t.is(i, 10, 'Connecting one signal to two slots in two objects');109 110 disconnect(hasSignals, 'signalOne', aObject, 'aMethod');111 disconnect(hasSignals, 'signalOne', bObject, 'bMethod');112 signal(hasSignals, 'signalOne');113 t.is(i, 10, 'Disconnecting one signal from two slots in two objects');114 115 116 try {117 connect('submit', 'onclick', null);118 submit.click();119 t.ok(false, 'An exception was not raised when connecting null');120 } catch (e) {121 t.ok(true, 'An exception was raised when connecting null');122 }123 try {124 disconnect('submit', 'onclick', null);125 t.ok(false, 'An exception was not raised when disconnecting null');126 } catch (e) {127 t.ok(true, 'An exception was raised when disconnecting null');128 }129 130 131 try {132 connect(nothing, 'signalOne', aObject, 'aMethod');133 signal(nothing, 'signalOne');134 t.ok(false, 'An exception was not raised when connecting undefined');135 } catch (e) {136 t.ok(true, 'An exception was raised when connecting undefined');137 }138 try {139 disconnect(nothing, 'signalOne', aObject, 'aMethod');140 t.ok(false, 'An exception was not raised when disconnecting undefined');141 } catch (e) {142 t.ok(true, 'An exception was raised when disconnecting undefined');143 }144 145 146 try {147 connect(hasSignals, 'signalOne', nothing);148 signal(hasSignals, 'signalOne');149 t.ok(false, 'An exception was not raised when connecting an undefined function');150 } catch (e) {151 t.ok(true, 'An exception was raised when connecting an undefined function');152 }153 try {154 disconnect(hasSignals, 'signalOne', nothing);155 t.ok(false, 'An exception was not raised when disconnecting an undefined function');156 } catch (e) {157 t.ok(true, 'An exception was raised when disconnecting an undefined function');158 }159 160 161 try {162 connect(hasSignals, 'signalOne', aObject, aObject.nothing);163 signal(hasSignals, 'signalOne');164 t.ok(false, 'An exception was not raised when connecting an undefined method');165 } catch (e) {166 t.ok(true, 'An exception was raised when connecting an undefined method');167 }168 try {169 disconnect(hasSignals, 'signalOne', aObject, aObject.nothing);170 t.ok(false, 'An exception was not raised when disconnecting an undefined method');171 } catch (e) {172 t.ok(true, 'An exception was raised when disconnecting an undefined method');173 }174 175 try {176 connect(hasSignals, 'signalOne', aObject, 'nothing');177 signal(hasSignals, 'signalOne');178 t.ok(false, 'An exception was not raised when connecting an undefined method (as string)');179 } catch (e) {180 t.ok(true, 'An exception was raised when connecting an undefined method (as string)');181 }182 try {183 disconnect(hasSignals, 'signalOne', aObject, 'nothing');184 t.ok(false, 'An exception was not raised when disconnecting an undefined method (as string)');185 } catch (e) {186 t.ok(true, 'An exception was raised when disconnecting an undefined method (as string)');187 }188 189 40 if (MochiKit.DOM.getElement('submit').fireEvent || 190 41 (document.createEvent && … … 247 98 248 99 249 connect('submit', 'onmousedown', eventTest);100 ident = connect('submit', 'onmousedown', eventTest); 250 101 triggerMouseEvent('submit', 'mousedown', false); 251 t.is(i, 11, 'Connecting an event to an HTML object and firing a synthetic event');102 t.is(i, 3, 'Connecting an event to an HTML object and firing a synthetic event'); 252 103 253 disconnect( 'submit', 'onmousedown', eventTest);104 disconnect(ident); 254 105 triggerMouseEvent('submit', 'mousedown', false); 255 t.is(i, 11, 'Disconnecting an event to an HTML object and firing a synthetic event');106 t.is(i, 3, 'Disconnecting an event to an HTML object and firing a synthetic event'); 256 107 257 108 }
