Search code examples
javascriptjquerylightboxnivo-slider

How to chain .call() functions - adding transitions to Nivo Lightbox


I'm trying to impliment CSS animation transitions for items displayed in a Nivo Lightbox. I've got the new function inserted and running, but the 2 following functions run before it is complete.

$('.nivo-lightbox-prev').off('click').on('click', function(e){
    e.preventDefault();                
    var index = galleryItems.index(currentLink);
    currentLink = galleryItems.eq(index - 1);
    if(!$(currentLink).length) currentLink = galleryItems.last();
    $this.options.beforePrev.call(this, [ currentLink ]);  # <---- new function I added
    $this.processContent(content, currentLink);            # <---- existing function 1
    $this.options.onPrev.call(this, [ currentLink ]);      # <---- existing function 2
});

The only way I know would be to put them in a callback, but .call() doesn't accept a callback.

I tried this:

function beforePrev(callback){
    $this.options.beforePrev.call(this, [ currentLink ]);
    callback();
}
function onPrev(){
    $this.processContent(content, currentLink);
    $this.options.onPrev.call(this, [ currentLink ]);
}
beforePrev(onPrev);

but it behaved the same.

In case it's relevant the code for beforePrev is:

beforePrev: function() {
    el = $('.nivo-lightbox-content');
    el.addClass('animated fadeOutLeft');
    el.one('webkitAnimationEnd oanimationend msAnimationEnd animationend', function (e) {
        el.removeClass('fadeOutLeft');
    });
},

Can anyone point me in the right direction?


Update / edit for extra clarity: This is the full original Nivo code: link

From my reading of it, $this is just a standard variable referring to the init function, not a DOM object. I think this is one of the reasons this seems hard to do.


Solution

  • Turns out deferind / promise is the key here, using jQuery's .when(): http://api.jquery.com/jquery.when/

    This answer: How to use "queue" or "deferred" in what condition? What are their designing purpose? helped - .queue() is primarily for animations and acts on a DOM object, whereas .deferred() is for async operations.

    So in this example:

    $('.nivo-lightbox-prev').off('click').on('click', function(e){
        e.preventDefault();
        var index = galleryItems.index(currentLink);
        currentLink = galleryItems.eq(index - 1);
        if(!$(currentLink).length) currentLink = galleryItems.last();
        $.when($this.options.beforePrev.call(this, [ currentLink ])).done(function(){
            $this.processContent(content, currentLink);
            $this.options.onPrev.call(this, [ currentLink ]);
        });
    });
    

    Then in the beforePrev function, start by setting up a .deferred() object, then .resolve() when it is complete, and finally pass the .promise() back:

    beforePrev: function() {
        var deferred = $.Deferred();
        el = $('.nivo-lightbox-content');
        el.addClass('fastAnimated fadeOutRight');
        el.one('webkitAnimationEnd oanimationend msAnimationEnd animationend', function (e) {
            el.removeClass('fadeOutRight');
            deferred.resolve();
        });
        return deferred.promise();
    },