simple event-driven slider sketch

a jquery slider that uses custom event dispatching for attaching functionalities

HTML

<div id="container">
    <div class="slide active">1</div>
    <div class="slide">2</div>
    <div class="slide">3</div>
    <div class="slide">4</div>
    <div class="slide">5</div>
    <div class="slide">6</div>
</div>
<div id="controls">
    <a href="#" id="prev">&lt;&lt;</a>
    <span id="controls_go_here"></span>
    <a href="#" id="next">&gt;&gt;</a>
</div>

CSS

#container{
    position : relative;
    overflow : hidden;
    width : 400px;
    height : 300px;
    border : 1px double black; 
}

.slide{
    width : 100%;
    height : 100%;
    line-height : 300px;
    font-size : 100px;
    text-align : center;
    background-image: linear-gradient(top, #000000 37%, #E9F5F5 100%);
    background-image: -o-linear-gradient(top, #000000 37%, #E9F5F5 100%);
    background-image: -moz-linear-gradient(top, #000000 37%, #E9F5F5 100%);
    background-image: -webkit-linear-gradient(top, #000000 37%, #E9F5F5 100%);
    background-image: -ms-linear-gradient(top, #000000 37%, #E9F5F5 100%);
    background-image: -webkit-gradient(
        linear,
        left top,
        left bottom,
        color-stop(0.37, #000000),
        color-stop(1, #E9F5F5)
    );
    color : red;
    text-shadow: 10px 10px 10px #f00;
    position : absolute;
    left : 0;
    top : 0;
    opacity : 0;
}
.slide.active{
    opacity : 1;
}

#controls{
    text-align : center;
    width : 400px;
}
#controls a{
    margin : 0 5px;
    cursor : pointer;
    text-decoration : none;
    color : black;
}
#controls a:hover{
    text-decoration : none;
    color : red;
}

JavaScript

(function($,window,undefined){
    // namespace
    var app = window.app || {};
    
    // our app's dispatcher
    app.dispatcher = null;
    app.sliderContainerSelector = '#container';
    app.slideSelector = '.slide';
    app.controlsContainerSelector = '#controls_go_here';
    app.controlClass = '.control';
    app.currentSlideIndex = null;
    app.sliderContainer = null;
    app.slides = null;
    
    app.transitionInProgress = function(){
        return app.slides.filter(':animated').length > 0;
    };
    
    // our event triggering mechanism
    app.triggerEvent = function(eventName,data){
        app.dispatcher.triggerHandler(eventName,[data]);
    };
    
    // bind all the eventHandlers to our custom events
    app.bindEvents = function(){
        // bind the click events on the controls
        $(app.controlsContainerSelector)
            .on('click',app.controlClass,function(e){
                 if(app.transitionInProgress())
                    return;
                var $this = $(this);
                var data = {
                    from : app.currentSlideIndex,
                    to : $this.index()
                };
                app.triggerEvent('startSlideTransition.slider',data);
                
                e.stopPropagation();
                e.preventDefault();
            });
            $('#prev').on('click',function(e){
                 if(app.transitionInProgress())
                    return;
                var $this = $(this);
                var data = {
                    from : app.currentSlideIndex,
                    to : app.currentSlideIndex== 0 ? app.slides.length-1 : app.currentSlideIndex-1
                };
                app.triggerEvent('startSlideTransition.slider',data);
                
                e.stopPropagation();
                e.preventDefault();
            });
            $('#next').on('click',function(e){
                if(app.transitionInProgress())
                    return;
       ...