1 /** 2 * @author <a href="http://www.creynders.be">Camille Reynders</a> 3 * @version 0.2.0 4 * @namespace 5 */ 6 var dijon = { 7 /** 8 * framework version number 9 * @constant 10 * @type String 11 */ 12 VERSION : '0.3.2' 13 };//dijon 14 15 //======================================// 16 // dijon.EventDispatcher 17 //======================================// 18 19 /** 20 * @class dijon.EventDispatcher 21 * @author Camille Reynders - www.creynders.be 22 * @constructor 23 */ 24 dijon.EventDispatcher = function(){ 25 26 this.fqn = 'dijon.EventDispatcher'; 27 28 /** @private */ 29 this._listeners = {}; 30 31 /** @private */ 32 this._length = 0; 33 34 };//dijon.EventDispatcher 35 36 dijon.EventDispatcher.prototype = { 37 38 /** 39 * @private 40 * @param {String} eventType 41 * @param {Number} index 42 */ 43 _removeListenerByIndex : function( eventType, index ){ 44 this._listeners[ eventType ].splice( index, 1 ); 45 if( this._listeners[ eventType ].length <= 0 ) 46 delete this._listeners[ eventType ]; 47 this._length--; 48 }, 49 50 /** 51 * adds a handler to be invoked when an event is dispatched 52 * @param {String} eventType The name of the event to be listened to 53 * @param {Function} listener The handler to be called when the event has been dispatched 54 * @param {Boolean} [oneShot=false] Whether the listener must be called only once 55 * @param {Boolean} [passEvent=false] Whether the event object needs to be passed to the listener 56 * @return {dijon.EventDispatcher} The EventDispatcher instance 57 */ 58 addListener : function( eventType, listener, oneShot, passEvent ) { 59 this.addScopedListener( eventType, listener, undefined, oneShot, passEvent ); 60 return this; 61 }, 62 63 /** 64 * adds a handler to be invoked in a specific <code>scope</code> when an event of <code>eventType</code> is dispatched 65 * @param {String} eventType The name of the event to be listened to 66 * @param {Function} listener The handler to be called when the event has been dispatched 67 * @param {Object} scope The scope in which the listener will be called 68 * @param {Boolean} [oneShot=false] Whether the listener must be called only once 69 * @param {Boolean} [passEvent=false] Whether the event object needs to be passed to the listener 70 * @return {dijon.EventDispatcher} The EventDispatcher instance 71 */ 72 addScopedListener : function( eventType, listener, scope, oneShot, passEvent ){ 73 if( oneShot == undefined ) oneShot = false; 74 if( passEvent == undefined ) passEvent = false; 75 if( this._listeners[ eventType ] == undefined ){ 76 this._listeners[ eventType ] = []; 77 } 78 this._listeners[ eventType ].push( { 79 scope : scope, 80 listener : listener, 81 oneShot : oneShot, 82 passEvent : passEvent 83 } ); 84 ++this._length; 85 return this; 86 }, 87 88 /** 89 * Checks whether the dispatcher object has registered <code>listener</code> for <code>eventType</code> 90 * @param {String} eventType The name of the event to be listened to 91 * @param {Function} listener The handler to be called when the event has been dispatched 92 * @return {Boolean} 93 */ 94 hasListener : function( eventType, listener ){ 95 return this.hasScopedListener( eventType, listener, undefined ); 96 }, 97 98 /** 99 * Checks whether the dispatcher object has registered <code>listener</code> in <code>scope</code> for <code>eventType</code> 100 * @param {String} eventType The name of the event to be listened to 101 * @param {Function} listener The handler to be called when the event has been dispatched 102 * @param {Object} scope The scope in which the listener will be called 103 * @return {Boolean} 104 */ 105 hasScopedListener : function( eventType, listener, scope ){ 106 if( this._listeners[ eventType ] ){ 107 var listeners = this._listeners[ eventType ]; 108 for( var i = 0, n = listeners.length ; i < n ; i++ ){ 109 var obj = listeners[ i ]; 110 if( obj.listener === listener && obj.scope === scope ){ 111 return true; 112 } 113 } 114 } 115 116 return false; 117 }, 118 119 /** 120 * Removes a <code>listener</code> registered for <code>eventType</code> 121 * @param {String} eventType The name of the event to be listened to 122 * @param {Function} listener The handler to be called when the event has been dispatched 123 * @return {dijon.EventDispatcher} The EventDispatcher instance 124 */ 125 removeListener : function( eventType, listener ){ 126 this.removeScopedListener( eventType, listener, undefined ); 127 return this; 128 }, 129 130 /** 131 * Removes a <code>listener</code> in <code>scope</code> registered for <code>eventType</code> 132 * @param {String} eventType The name of the event to be listened to 133 * @param {Function} listener The handler to be called when the event has been dispatched 134 * @param {Object} scope The scope in which the listener will be called 135 * @return {dijon.EventDispatcher} The EventDispatcher instance 136 */ 137 removeScopedListener : function( eventType, listener, scope ) { 138 for ( var i = 0 ; this._listeners[ eventType ] && i < this._listeners[ eventType ].length ; ){ 139 var obj = this._listeners[ eventType ][ i ]; 140 if( obj.listener == listener && obj.scope === scope ){ 141 this._removeListenerByIndex( eventType, i ); 142 }else{ 143 i++; 144 } 145 } 146 return this; 147 }, 148 149 /** 150 * dispatches an event with any number of arguments 151 * @param {Object|String} event The event object or event type 152 * @param {String} event.type if <code>event</code> is of type <code>Object</code> it requires a <code>type</code> property set to the name of the event that will be listened to. 153 * @param {...} [...=undefined] Any number of parameters 154 * @return {dijon.EventDispatcher} The EventDispatcher instance 155 */ 156 dispatchEvent : function( event ){ 157 if (typeof event == "string"){ 158 event = { type: event }; 159 } 160 if (!event.target){ 161 event.target = this; 162 } 163 var args = []; 164 for( var i = 1, n = arguments.length; i < n ; i++ ){ 165 args.push( arguments[ i ] ); 166 } 167 168 if( this._listeners[ event.type ] ){ 169 for( var i = 0 ; this._listeners[ event.type ] && i < this._listeners[ event.type ].length ; ){ 170 var obj = this._listeners[ event.type ][ i ]; 171 if( obj.oneShot ){ 172 this._removeListenerByIndex( event.type, i ); 173 }else{ 174 i++; 175 } 176 if( obj.passEvent ){ 177 args.unshift( event ); 178 } 179 obj.listener.apply( obj.scope, args ); 180 } 181 } 182 183 return this; 184 }, 185 186 /** 187 * removes all event listeners 188 * @return {dijon.EventDispatcher} The EventDispatcher instance 189 */ 190 removeAllListeners : function(){ 191 this._listeners = {}; 192 this._length = 0; 193 194 return this; 195 }, 196 197 /** 198 * Returns the number of listeners 199 * @return {Number} The number of listeners 200 */ 201 length : function(){ 202 return this._length; 203 } 204 205 };//dijon.EventDispatcher.prototype 206 207 //======================================// 208 // dijon.Dictionary 209 //======================================// 210 211 /** 212 * The Dictionary class lets you create a dynamic collection of properties, which uses strict equality (===) for key comparison. 213 * @class dijon.Dictionary 214 * @constructor 215 */ 216 dijon.Dictionary = function(){ 217 218 this.fqn = 'dijon.Dictionary'; 219 220 /** 221 * @private 222 */ 223 this._map = []; 224 225 };//dijon.Dictionary 226 227 dijon.Dictionary.prototype = { 228 /** 229 * @private 230 * @param key 231 * @return index 232 */ 233 _getIndexByKey : function( key ){ 234 for( var i = 0, n = this._map.length ; i < n ; i++ ){ 235 if( this._map[ i ].key === key ) 236 return i; 237 } 238 239 return -1; 240 }, 241 242 /** 243 * Maps <code>value</code> to <code>key</code> 244 * @param {Object} key 245 * @param {Object} value 246 * @return {dijon.Dictionary} the Dictionary instance 247 */ 248 add : function( key, value ){ 249 var index = this._getIndexByKey( key ); 250 if( index < 0 ){ 251 this._map.push( { 252 key : key, 253 value : value 254 }); 255 }else{ 256 this._map[ index ] = { 257 key : key, 258 value : value 259 } 260 } 261 return this; 262 }, 263 264 /** 265 * removes the mapping of the value of <code>key</code> 266 * @param {Object} key 267 * @return {dijon.Dictionary} the Dictionary instance 268 */ 269 remove : function( key ){ 270 var index = this._getIndexByKey( key ); 271 if( index >= 0 ) return this._map.splice( index, 1 ).value; 272 273 return this; 274 }, 275 276 /** 277 * retrieves the value mapped to <code>key</code> 278 * @param {Object} key 279 * @return {Object} the value mapped to <code>key</code> 280 */ 281 getValue : function( key ){ 282 var index = this._getIndexByKey( key ); 283 284 if( index >= 0 ) return this._map[ index ].value; 285 286 return null; 287 }, 288 289 /** 290 * checks whether a value has been mapped to <code>key</code> 291 * @param {Object} key 292 * @return {Boolean} 293 */ 294 hasValue : function( key ){ 295 var index = this._getIndexByKey( key ); 296 return ( index >= 0 ); 297 } 298 299 };//dijon.Dictionary.prototype 300 301 //======================================// 302 // dijon.Injector 303 //======================================// 304 305 /** 306 * @class dijon.Injector 307 * @constructor 308 */ 309 dijon.Injector = function(){ 310 this.fqn = 'dijon.Injector'; 311 312 /** @private */ 313 this._mappingsByClassOrObject = new dijon.Dictionary(); 314 315 /** @private */ 316 this._outlets = []; 317 };//dijon.Injector 318 319 dijon.Injector.prototype = { 320 321 /** 322 * @private 323 * @param {Class} clazz 324 */ 325 _createAndSetupInstance : function( clazz ){ 326 var instance = new clazz(); 327 this.injectInto( instance ); 328 if( "setup" in instance ) instance.setup.call( instance ); 329 return instance; 330 }, 331 332 /** 333 * @private 334 * @param {Class} key 335 * @param {Boolean} overrideRules 336 * @return {Object} 337 */ 338 _retrieveFromCacheOrCreate : function( key, overrideRules ){ 339 var config = this._mappingsByClassOrObject.getValue( key ); 340 var output = null; 341 if( overrideRules ){ 342 //key is a class 343 //TODO: check if it IS a class 344 output = this._createAndSetupInstance( key ); 345 }else{ 346 if( config ){ 347 if( config.isSingleton ){ 348 if( config.object == null ){ 349 config.object = this._createAndSetupInstance( config.clazz ); 350 } 351 output = config.object; 352 }else{ 353 output = this._createAndSetupInstance( config.clazz ); 354 } 355 }else{ 356 throw new Error( this.fqn + " is missing a rule for " + key ); 357 } 358 } 359 return output 360 }, 361 362 363 /** 364 * defines <code>propertyName</code> as an injection point for the class mapped to <code>targetKey</code> to be injected with an instance 365 * of the class mapped to <code>sourceKey</code>. 366 * @param {Class} targetKey the class the injection point is applied to. 367 * @param {String} propertyName the <strong>name</strong> of the property used as an injection point.<br/> 368 * [!] MUST BE STRING 369 * @param {Object} sourceKey the key to the value that will be injected 370 * @see dijon.Injector#removeOutlet 371 */ 372 addOutlet : function( targetKey, propertyName, sourceKey ){ 373 this._outlets.push( { 374 target : targetKey, 375 property : propertyName, 376 source : sourceKey 377 } ); 378 }, 379 380 /** 381 * Create (if possible) or retrieve an instance of the class mapped to <code>key</code> 382 * @param {Object} key 383 * @return {Object} 384 */ 385 getInstance : function( key ){ 386 return this._retrieveFromCacheOrCreate( key, false ); 387 }, 388 389 /** 390 * When asked for an instance of the class <code>whenAskedFor<code> or object <code>whenAskedFor</code> inject an instance of <code>whenAskedFor<code>. 391 * @param {Class|Object} whenAskedFor 392 */ 393 mapSingleton : function( whenAskedFor ){ 394 if( this._mappingsByClassOrObject.hasValue( whenAskedFor ) ) throw new Error( this.fqn + ' cannot remap ' + whenAskedFor + ' without unmapping first' ); 395 this.mapSingletonOf( whenAskedFor, whenAskedFor ); 396 }, 397 398 /** 399 * When asked for an instance of the class <code>whenAskedFor</code> or object <code>whenAskedFor</code> inject the instance <code>useValue</code>. 400 * @param {Class|Object} whenAskedFor 401 * @param {Object} useValue 402 */ 403 mapValue : function( whenAskedFor, useValue ){ 404 if( whenAskedFor == null || whenAskedFor == undefined ) throw new Error( this.fqn + ' cannot map to an undefined object' ); 405 if( useValue == null || useValue == undefined ) throw new Error( this.fqn + ' cannot map an undefined object' ); 406 if( this._mappingsByClassOrObject.hasValue( whenAskedFor ) ) throw new Error( this.fqn + ' cannot remap ' + ' without unmapping first' ); 407 this._mappingsByClassOrObject.add( 408 whenAskedFor, 409 { 410 clazz : whenAskedFor, 411 object : useValue, 412 isSingleton : true 413 } 414 ); 415 }, 416 417 setValue : function( whenAskedFor, useValue ){ 418 var config = this._mappingsByClassOrObject.getValue( whenAskedFor ); 419 config.object = useValue; 420 }, 421 422 /** 423 * Does a rule exist to satsify such a request? 424 * @param {Class} whenAskedFor 425 * @return {Boolean} 426 */ 427 hasMapping : function( whenAskedFor ){ 428 return this._mappingsByClassOrObject.hasValue( whenAskedFor ); 429 }, 430 431 /** 432 * When asked for an instance of the class <code>whenAskedFor</code> or for object <code>whenAskedFor</code> inject a <strong>new</strong> instance of <code>instantiateClass</code>. 433 * @param {Class|Object} whenAskedFor 434 * @param {Class} instantiateClass 435 */ 436 mapClass : function( whenAskedFor, instantiateClass ){ 437 if( this.hasMapping( whenAskedFor ) ) throw new Error( this.fqn + ' cannot remap ' + ' without unmapping first' ); 438 this._mappingsByClassOrObject.add( 439 whenAskedFor, 440 { 441 clazz : instantiateClass, 442 object : null, 443 isSingleton : false 444 } 445 ); 446 }, 447 448 /** 449 * When asked for an instance of the class <code>whenAskedFor</code> or object <code>whenAskedFor</code> inject an instance of <code>useSingletonOf</code>. 450 * @param {Class|Object} whenAskedFor 451 * @param {Class} useSingletonOf 452 */ 453 mapSingletonOf : function( whenAskedFor, useSingletonOf ){ 454 if( this._mappingsByClassOrObject.hasValue( whenAskedFor ) ) throw new Error( this.fqn + ' cannot remap ' + ' without unmapping first' ); 455 this._mappingsByClassOrObject.add( 456 whenAskedFor, 457 { 458 clazz : useSingletonOf, 459 object : null, 460 isSingleton : true 461 } 462 ); 463 }, 464 465 /** 466 * create an instance of the class mapped to <code>keyOrClass</code> and fulfill it's mapped dependencies<br/> 467 * <strong>WILL ALWAYS CREATE A NEW INSTANCE</strong>, even if <code>keyOrClass</code> was mapped otherwise or 468 * <strong>even when <code>keyOrClass</code> was not mapped</code>. 469 * @param {Class} keyOrClass 470 * @return {Object} 471 */ 472 instantiate : function( keyOrClass ){ 473 return this._retrieveFromCacheOrCreate( keyOrClass, true ); 474 }, 475 476 /** 477 * Perform an injection into an object, satisfying all it's dependencies 478 * @param {Object} instance 479 */ 480 injectInto : function( instance ){ 481 for( var i = 0, n = this._outlets.length ; i < n ; i++ ){ 482 var mapping = this._outlets[ i ]; 483 if( instance && instance instanceof mapping.target && mapping.property in instance ) 484 instance[ mapping.property ] = this.getInstance( mapping.source ); 485 } 486 }, 487 488 /** 489 * Remove a rule from the injector 490 * @param {Class|Object} whenAskedFor 491 */ 492 unmap : function( whenAskedFor ){ 493 this._mappingsByClassOrObject.remove( whenAskedFor ); 494 }, 495 496 /** 497 * removes an injection point mapping for a given class mapped to <code>key</code> 498 * @param {Object} key 499 * @param {String} propertyName MUST BE STRING 500 * @see dijon.Injector#addOutlet 501 */ 502 removeOutlet : function( key, propertyName ){ 503 for( var i = 0, n = this._outlets.length ; i < n ; i++ ){ 504 var point = this._outlets[ i ]; 505 if( point.target == key && point.property == propertyName ) { 506 this._outlets.splice( i, 1 ); 507 return; 508 } 509 } 510 } 511 512 };//dijon.Injector.prototype 513 514 //======================================// 515 // dijon.EventMap 516 //======================================// 517 518 /** 519 * registers class members as listeners for specific events, before (or after) instantiation.<br/> 520 * Allows for mapping listeners to lazily instantiated objects.<br/> 521 * [!] This class differs substantially from the RobotLegs EventMap both in use and functionality 522 * @class dijon.EventMap 523 * @constructor 524 */ 525 dijon.EventMap = function(){ 526 this.fqn = 'dijon.EventMap'; 527 528 /** 529 * @private 530 * @type Object 531 */ 532 this._mappingsByEventType = {}; 533 534 /** 535 * @private 536 * @type Object 537 */ 538 this._mappingsNumByKey = {}; 539 540 /** 541 * @private 542 * @type dijon.EventDispatcher 543 */ 544 this.eventDispatcher = undefined; //inject 545 546 /** 547 * @private 548 * @type dijon.Injector 549 */ 550 this.injector = undefined; //inject 551 552 };//dijon.EventMap 553 554 dijon.EventMap.prototype = { 555 556 /** 557 * @private 558 * @param eventType 559 * @param key 560 * @param handler 561 */ 562 _getMappingIndex : function( mappingsListForEvent, key, handler ){ 563 if( mappingsListForEvent ){ 564 for( var i = 0, n = mappingsListForEvent.length; i < n ; i++ ){ 565 var mapping = mappingsListForEvent[ i ]; 566 if( mapping.key === key && mapping.handler === handler ){ 567 return i; 568 } 569 } 570 } 571 572 return -1; 573 }, 574 575 /** 576 * @private 577 * @param {Object} event 578 */ 579 _handleRuledMappedEvent : function( event ){ 580 var mappingsListForEvent = this._mappingsByEventType[ event.type ]; 581 var args = []; 582 583 for( var i = 1, n = arguments.length; i < n ; i++ ){ 584 args.push( arguments[ i ] ); 585 } 586 for( var i = 0, n = mappingsListForEvent.length; i < n; i++ ){ 587 var obj = mappingsListForEvent[i]; 588 if( this.injector.hasMapping( obj.key ) ){ 589 var instance = this.injector.getInstance( obj.key ); 590 if( obj.oneShot ) 591 this.removeRuledMapping( event.type, obj.key, obj.handler ); 592 if( obj.passEvent ) 593 args.unshift( event ); 594 if( obj.handler != null ) 595 instance[ obj.handler ].apply( instance, args ); 596 //obj.handler.apply( instance, args ); 597 }else{ 598 //injector mapping has been deleted, but 599 //eventMap mapping not 600 //TODO: remove or throw error? 601 } 602 } 603 }, 604 605 /** 606 * @private 607 * @param {String} eventType 608 * @param {Class} key 609 * @param {Function} handler 610 */ 611 _removeRuledMappingAndUnmapFromInjectorIfNecessary : function( eventType, key, handler ){ 612 this.removeRuledMapping( eventType, key, handler ); 613 var mappingsNum = this._mappingsNumByKey[ key ] || 0; 614 if( mappingsNum <= 0 ) 615 this.injector.unmap( key ); 616 }, 617 618 /** 619 * maps <code>handler</code> as a listener for <code>eventType</code> to be called as an instance member of the class mapped to <code>key</code> 620 * instance. The instance will be created according to the rule defined for <code>key</code> in injector. 621 * <br/>[!] requires <code>key</code> is already ruled by the injector 622 * @see dijon.Injector 623 * @param {String} eventType The name of the event to be listened to 624 * @param {Object} key 625 * @param {Function} handler 626 * @param {Boolean} [oneShot=false] Whether the listener must be called only once 627 * @param {Boolean} [passEvent=false] Whether the event object should be passed as a parameter to <code>handler</code> 628 * upon invocation or not. If <code>true</code> any additional dispatched values will be passed as parameters after 629 * the event object 630 */ 631 addRuledMapping : function( eventType, key, handler, oneShot, passEvent ){ 632 if( ! this.injector.hasMapping( key ) ){ 633 throw new Error( '*** ERROR *** ' + this.fqn + ' addRuledMapping can only be used on a key already mapped by the injector') 634 } 635 if( ! this._mappingsByEventType[ eventType ] ){ 636 this._mappingsByEventType[ eventType ] = []; 637 this.eventDispatcher.addScopedListener( eventType, this._handleRuledMappedEvent, this, false, true ); 638 } 639 640 var mappingsNum = this._mappingsNumByKey[ key ] || 0; 641 this._mappingsNumByKey[ key ] = ++mappingsNum; 642 643 this._mappingsByEventType[ eventType ].push( { key : key, handler : handler, oneShot : oneShot, passEvent: passEvent } ); 644 }, 645 646 /** 647 * Removes the mapping for <code>key</code> 648 * @see dijon.EventMap#addRuledMapping 649 * @param {String} eventType The name of the event to be listened to 650 * @param {Class} key 651 * @param {Function} handler 652 */ 653 removeRuledMapping : function( eventType, key, handler ){ 654 var mappingsListForEvent = this._mappingsByEventType[ eventType ]; 655 var index = this._getMappingIndex( mappingsListForEvent, key, handler ); 656 if( index >= 0 ){ 657 /* DO NOT CLEAN UP MAPPING DEPENDENCIES, mapping maybe still in use */ 658 /* 659 var mapping = mappingsListForEvent[ index ]; 660 delete mapping.key; 661 delete mapping.handler; 662 mapping = null; 663 */ 664 mappingsListForEvent.splice( index, 1 ); 665 if( mappingsListForEvent.length <= 0 ) 666 delete mappingsListForEvent[ eventType ]; 667 var mappingsNum = this._mappingsNumByKey[ key ] || 0; 668 if( mappingsNum <= 0 ){ 669 delete this._mappingsNumByKey[ key ]; 670 }else{ 671 this._mappingsNumByKey[ key ] = --mappingsNum; 672 } 673 return true; 674 675 } 676 return false; 677 }, 678 679 /** 680 * maps <code>handler</code> as a listener for <code>eventType</code> to be called as a member of a <code>clazz</code> 681 * instance. The instance will ALWAYS be a new one, regardless of previous injector mappings for that <code>clazz</code>.<br/> 682 * If <code>handler</code> is <code>undefined</code> or <code>null</code> the instance will be created but no handler will be invoked.<br/> 683 * In that case the dispatched payload will not be passed. (no constructor injection at the moment) 684 * @param {String} eventType 685 * @param {Class} clazz 686 * @param {Function} [handler=null] 687 * @param {Boolean} [oneShot=false] 688 * @param {Boolean} [passEvent=false] 689 */ 690 addClassMapping : function( eventType, clazz, handler, oneShot, passEvent ){ 691 if( ! this.injector.hasMapping( clazz ) ) 692 this.injector.mapClass( clazz, clazz ); 693 if( handler == undefined ) 694 handler = null; 695 this.addRuledMapping( eventType, clazz, handler, oneShot, passEvent ); 696 }, 697 698 /** 699 * Removes the mapping for <code>clazz</code> 700 * @see dijon.EventMap#addClassMapping 701 * @param {String} eventType 702 * @param {Class} clazz 703 * @param {Function} [handler=null] 704 */ 705 removeClassMapping : function( eventType, clazz, handler ){ 706 if( handler == undefined ) 707 handler = null; 708 this._removeRuledMappingAndUnmapFromInjectorIfNecessary( eventType, clazz, handler ); 709 }, 710 711 /** 712 * Checks whether a mapping exists. The combination of <code>eventType, key, handler</code> must be identical 713 * to what was mapped for this to return true. If <code>key</code> was mapped for <code>eventType</code> <strong>with</strong> 714 * a <code>handler</code> then <code>hasMapping</code> will return <code>false</code> if only invoked with parameters 715 * <code>eventType</code> and <code>key</code> 716 * @param {String} eventType 717 * @param {Object} key 718 * @param {Function} [handler=null] 719 * @return {Boolean} 720 */ 721 hasMapping : function( eventType, key, handler ){ 722 if( handler == undefined ) 723 handler = null; 724 return this._getMappingIndex( this._mappingsByEventType[ eventType ], key, handler ) >= 0 ; 725 } 726 727 728 };//dijon.EventMap.prototype 729 730 731 //======================================// 732 // dijon.Actor 733 //======================================// 734 735 /** 736 * Convenience class 737 * @class dijon.Actor 738 * @constructor 739 */ 740 dijon.Actor = function(){ 741 /** 742 * @type dijon.Injector 743 */ 744 this.injector = undefined;//inject 745 746 /** 747 * @type dijon.EventMap 748 */ 749 this.eventMap = undefined;//inject 750 751 /** 752 * @type dijon.EventDispatcher 753 */ 754 this.eventDispatcher = undefined; //inject 755 };//dijon.Actor 756 757 dijon.Actor.prototype = { 758 /** 759 * is automatically invoked after injection has occurred. 760 * <br/> cfr. RobotLegs' <code>[PostConstruct]</code> or <code>Mediator#onRegister</code> 761 */ 762 setup : function(){ 763 } 764 };//dijon.Actor.prototype 765 766 767 //======================================// 768 // dijon.Context 769 //======================================// 770 771 /** 772 * @class dijon.Context 773 * @constructor 774 */ 775 dijon.Context = function(){ 776 this.fqn = 'dijon.Context'; 777 778 };//dijon.Context 779 dijon.Context.prototype = new dijon.Actor(); 780 dijon.Context.prototype.constructor = dijon.Context; 781 782 /** 783 * @private 784 */ 785 dijon.Context.prototype._createInjector = function(){ 786 this.injector = new dijon.Injector(); 787 }; 788 789 /** 790 * @private 791 */ 792 dijon.Context.prototype._setupWirings = function(){ 793 this.parseConfig( dijon.wirings ); 794 this.injector.setValue( dijon.wirings.injector, this.injector ); 795 } 796 /** 797 * @param {Boolean} [autoStartup=true] 798 */ 799 dijon.Context.prototype.init = function( autoStartup ){ 800 this._createInjector(); 801 this._setupWirings(); 802 this.injector.injectInto( this ); 803 if( autoStartup == true || autoStartup==undefined ) this.startup(); 804 }; 805 806 dijon.Context.prototype.parseConfig = function( configList ){ 807 for( var configName in configList ){ 808 var configObj = configList[ configName ]; 809 if( configObj.singleton ){ 810 this.injector.mapSingletonOf( configObj, configObj.impl ); 811 }else{ 812 this.injector.mapClass( configObj, configObj.impl ); 813 } 814 for( var outletName in configObj.outlets ){ 815 var outletWiring = configObj.outlets[ outletName ]; 816 this.injector.addOutlet( configObj.impl, outletName, outletWiring ); 817 } 818 for( var i in configObj.handlers ){ 819 var handlerConfig = configObj.handlers[ i ]; 820 this.eventMap.addRuledMapping( handlerConfig.event, configObj, handlerConfig.handler, handlerConfig.oneShot, handlerConfig.passEvent ) 821 } 822 } 823 }; 824 825 826 827 /** 828 * abstract, should be overridden 829 */ 830 dijon.Context.prototype.startup = function(){ 831 } 832 833 dijon.wirings = {}; 834 dijon.wirings.injector = { 835 impl : dijon.Injector, 836 singleton : true 837 }; 838 dijon.wirings.eventDispatcher = { 839 impl : dijon.EventDispatcher, 840 singleton : true 841 }; 842 dijon.wirings.eventMap = { 843 impl : dijon.EventMap, 844 singleton : true, 845 outlets : { 846 eventDispatcher : dijon.wirings.eventDispatcher, 847 injector : dijon.wirings.injector 848 } 849 }; 850 dijon.wirings.actor = { 851 impl : dijon.Actor, 852 singleton : true, 853 outlets : { 854 eventDispatcher : dijon.wirings.eventDispatcher, 855 injector : dijon.wirings.injector, 856 eventMap : dijon.wirings.eventMap 857 } 858 }; 859