1

How can I execute a function after a plugin's animation finishes?

I'm using the Tocify plugin and customizing its functionality for a project I'm working on.

After I click on an entry in the automatically generated Table of Contents, it scrolls to that entry using $('html, body').animate({'scrollTop', ... . I need to do something after that finishes.

Right now, my workaround is to attach a handler to the click event on the ToC items to set a variable identifying the target in a global variable then attach another handler to the scroll event on the window that checks the variable's value, takes the appropriate action, then sets the variable to be undefined.

Here's the code for my work-around:

$('.tocify-item').click(function() {
    var unique = $(this).data('unique');
    $target = $('div[data-unique=' + unique + ']').eq(0).next();
});

$(window).scroll(function() {
    $.doTimeout('scroll', 100, function() {
        if ($target !== undefined) {
        $('h1,h2,h3').removeClass('target');
        $target.addClass('target');
        $target = undefined;
    }
});

This seems sloppy. Is there a better way to do this?

I've tried to use $('html,body').promise().done() in a handler for the click.tocify event that Tocify uses, but that fires right away so I'm guessing it happens before the animation starts.

I have a page at CodePen that has all of the code including my workaround: http://codepen.io/Ghodmode/pen/dGdWqV

Update:

The following seems like a slightly better workaround. It doesn't need that extra variable and it doesn't fire every time the user scrolls.

It works in my testing environment, but that 100 milliseconds is completely arbitrary. I don't know how much time passes between when the click.tocify event initially fires and the animation starts. I'm concerned that it might not work on some browsers.

$('.tocify-item').on('click.tocify', function() {
    var itemid = $(this).data('unique');
    var $target = $('div[data-unique=' + itemid + ']').next();

    var clicktimeout;
    var after_scroll = function() {
        $('html,body').promise().done(function() {
            $('h1,h2,h3').removeClass('target');
            $target.addClass('target');
        });
    };
    clicktimeout = setTimeout(after_scroll, 100);
});
Community
  • 1
  • 1
Vince
  • 3,962
  • 3
  • 33
  • 58
  • Can you post the code please – Michael Bellamy Feb 09 '16 at 08:30
  • 1
    That plugin doesn't expose any event handlers, so if you want this behaviour you may need to amend the source, or find a better plugin. – Rory McCrossan Feb 09 '16 at 08:40
  • @MichaelBellamy It's already there in the CodePen page I linked to. I didn't want to put the code directly in my question because the HTML has a lot of *lorem ipsum* type content that would make my post unnecessarily long. It has to be long in order for to see the scrolling effect. That's why I put a link to all the code over at CodePen. Tocify has [a page with all of the plugin's code nicely annotated](http://gregfranko.com/jquery.tocify.js/docs/jquery.tocify.html). – Vince Feb 09 '16 at 08:40
  • @Vince apologies, I'm half asleep, I'll have a look. :) – Michael Bellamy Feb 09 '16 at 08:45
  • @RoryMcCrossan A better plugin is probably the answer, but this plugin was requested by my client. I'm nearly done with this project and I don't want to start over with a new plugin. While working on this I've been taking notes on things I wish Tocify did differently and I considered modifying the plugin in the future... ["pull requests are always welcome =)"](https://github.com/gfranko/jquery.tocify.js/issues/57#issuecomment-42499254) – Vince Feb 09 '16 at 09:18

1 Answers1

1

You can't do this with the existing plugin..

I was created a commit of this plugin:

I was added event after the scroll was ended that called tocify.scrollEnd.

So you can "listen" to the event like that:

$('div').on('tocify.scrollEnd', function() {
   // .. Your code
});

Just follow the demo and if you have a question, let me know:

var $target;
$(function() {
  $('body').children().filter(':first').before('<div id="toc"></div>');
  $('#toc').tocify({
    'theme': 'jqueryui'
  });

  $('div').on('tocify.scrollEnd', function(){
    alert('scroll done');
  });
  
  $('#toc').append('<div id="hamburger"></div>');
  $('.tocify-item').click(function() {
    var unique = $(this).data('unique');
    $target = $('div[data-unique=' + unique + ']').eq(0).next();
  });

  $(window).scroll(function() {
    $.doTimeout('scroll', 100, function() {
      if ($target !== undefined) {
        $('h1,h2,h3').removeClass('target');
        $target.addClass('target');
        $target = undefined;
      }
    });
  });
});
#toc {
  z-index: 1;
  width: auto;
  min-width: 1.5em;
  min-height: 1.4em;
  margin: 0;
  top: 1em;
  right: 1em;
}

#toc .tocify-item {
  padding-right: 10px;
}

#hamburger {
  display: none;
  position: absolute;
  top: 0;
  left: 0;
}

#hamburger::before {
  content: '';
  position: absolute;
  left: 0.25em;
  top: 0.4em;
  width: 1em;
  height: 0.15em;
  background: gray;
  box-shadow: 0 0.25em 0 0 gray, 0 0.5em 0 0 gray;
}

@media (max-width: 40em) {
  #hamburger {
    display: block;
  }
  #toc ul {
    display: none;
  }
}

.target {
  animation: highlight 1.5s ease;
}

@keyframes highlight {
  from { background: yellow; }
  to { background: white; }
}
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script>
<link rel="stylesheet" href="//ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/themes/smoothness/jquery-ui.css">
<script src="//ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery-dotimeout/1.0/jquery.ba-dotimeout.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jquery.tocify/1.9.0/stylesheets/jquery.tocify.min.css">

<script src="https://rawgit.com/moshfeu/jquery.tocify.js/45d6d52a832b9bf49935d04f9685f9e7d447658e/src/javascripts/jquery.tocify.js"></script>

<h1>Playing with <a href="http://gregfranko.com/jquery.tocify.js/">Tocify</a></h1>
<p>
  Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi sit amet blandit leo. Aliquam libero ex, bibendum eu nulla at, semper vehicula orci. Nunc sodales quam et est interdum, ac consectetur mi pharetra. Morbi finibus varius lectus at tempor. Mauris non justo nec risus posuere vehicula a eget diam. Suspendisse auctor bibendum rhoncus. Maecenas sed bibendum odio. Nullam iaculis placerat turpis non finibus. Aliquam sodales volutpat justo eget tempus. Nunc sodales enim non nulla ornare rhoncus. Curabitur eget arcu quis nisi tincidunt molestie eget et lorem.
</p>
<h1>Heading 1</h1>
<p>
  Suspendisse tincidunt, enim quis tristique feugiat, urna mauris ornare odio, a elementum purus arcu quis turpis. Curabitur viverra dictum gravida. Vestibulum tortor erat, ultrices at blandit sed, pellentesque at dui. Nunc pulvinar accumsan lacus ut euismod. Aliquam porta aliquam massa, nec gravida elit eleifend quis. Suspendisse quam purus, porttitor nec ex in, rhoncus ultrices lacus. Fusce pulvinar, quam eget dapibus faucibus, elit erat facilisis ligula, sed volutpat risus justo feugiat risus. Etiam non felis fermentum, ultricies nisi a, euismod metus. Sed hendrerit cursus blandit.
</p>
<h2>Subheadng 1</h2>
<p>
  Vestibulum malesuada diam sit amet ligula posuere faucibus. Aenean lobortis orci eu augue rutrum lacinia. Morbi imperdiet sapien odio, in commodo metus molestie at. Ut fermentum lectus vel mauris rhoncus, eget pellentesque augue commodo. Aenean commodo id odio eget cursus. Pellentesque id consectetur odio. Interdum et malesuada fames ac ante ipsum primis in faucibus.
</p>
<p>
  Vivamus vel libero nec lectus consectetur auctor in tempor metus. Quisque varius malesuada velit ac ultrices. Nunc ullamcorper est diam, sed vestibulum sapien finibus vel. Suspendisse mollis vel libero eget sagittis. Nam id odio libero. Donec mi ipsum, maximus a egestas id, dapibus sed arcu. In efficitur risus vel est pharetra, vitae sollicitudin dolor finibus. Vivamus sem magna, condimentum nec porta eu, imperdiet at erat. Nulla aliquet auctor consequat. Aliquam pulvinar sodales mattis. Donec congue, nisl at bibendum pulvinar, nibh justo malesuada nisl, non vulputate odio velit nec felis. Proin aliquam lobortis metus quis fringilla. Sed interdum maximus augue in auctor. Proin faucibus commodo turpis, eleifend tempor neque elementum quis.
</p>
<h2>Subheading 2</h2>
<p>
  Vivamus eu ante est. Maecenas at arcu eu magna maximus sollicitudin a eu nunc. Curabitur non euismod nibh. Etiam tristique lacus sem, at ornare leo laoreet eget. Morbi suscipit augue semper felis placerat laoreet in at elit. Phasellus et congue orci. Quisque ac aliquam nulla. Quisque sed sem cursus, bibendum est at, varius eros. Donec quis molestie turpis. Ut tincidunt pellentesque sem quis tincidunt. Fusce in nibh eu mi ullamcorper porttitor at eu nisl.
</p>
<p>
  Vivamus vel libero nec lectus consectetur auctor in tempor metus. Quisque varius malesuada velit ac ultrices. Nunc ullamcorper est diam, sed vestibulum sapien finibus vel. Suspendisse mollis vel libero eget sagittis. Nam id odio libero. Donec mi ipsum, maximus a egestas id, dapibus sed arcu. In efficitur risus vel est pharetra, vitae sollicitudin dolor finibus. Vivamus sem magna, condimentum nec porta eu, imperdiet at erat. Nulla aliquet auctor consequat. Aliquam pulvinar sodales mattis. Donec congue, nisl at bibendum pulvinar, nibh justo malesuada nisl, non vulputate odio velit nec felis. Proin aliquam lobortis metus quis fringilla. Sed interdum maximus augue in auctor. Proin faucibus commodo turpis, eleifend tempor neque elementum quis.
</p>
<h1>Heading 2</h1>
<p>
  Vivamus vel libero nec lectus consectetur auctor in tempor metus. Quisque varius malesuada velit ac ultrices. Nunc ullamcorper est diam, sed vestibulum sapien finibus vel. Suspendisse mollis vel libero eget sagittis. Nam id odio libero. Donec mi ipsum, maximus a egestas id, dapibus sed arcu. In efficitur risus vel est pharetra, vitae sollicitudin dolor finibus. Vivamus sem magna, condimentum nec porta eu, imperdiet at erat. Nulla aliquet auctor consequat. Aliquam pulvinar sodales mattis. Donec congue, nisl at bibendum pulvinar, nibh justo malesuada nisl, non vulputate odio velit nec felis. Proin aliquam lobortis metus quis fringilla. Sed interdum maximus augue in auctor. Proin faucibus commodo turpis, eleifend tempor neque elementum quis.
</p>
<h2>Subheading 1</h2>
<p>
  Vivamus vel libero nec lectus consectetur auctor in tempor metus. Quisque varius malesuada velit ac ultrices. Nunc ullamcorper est diam, sed vestibulum sapien finibus vel. Suspendisse mollis vel libero eget sagittis. Nam id odio libero. Donec mi ipsum, maximus a egestas id, dapibus sed arcu. In efficitur risus vel est pharetra, vitae sollicitudin dolor finibus. Vivamus sem magna, condimentum nec porta eu, imperdiet at erat. Nulla aliquet auctor consequat. Aliquam pulvinar sodales mattis. Donec congue, nisl at bibendum pulvinar, nibh justo malesuada nisl, non vulputate odio velit nec felis. Proin aliquam lobortis metus quis fringilla. Sed interdum maximus augue in auctor. Proin faucibus commodo turpis, eleifend tempor neque elementum quis.
</p>
<p>
  Vivamus vel libero nec lectus consectetur auctor in tempor metus. Quisque varius malesuada velit ac ultrices. Nunc ullamcorper est diam, sed vestibulum sapien finibus vel. Suspendisse mollis vel libero eget sagittis. Nam id odio libero. Donec mi ipsum, maximus a egestas id, dapibus sed arcu. In efficitur risus vel est pharetra, vitae sollicitudin dolor finibus. Vivamus sem magna, condimentum nec porta eu, imperdiet at erat. Nulla aliquet auctor consequat. Aliquam pulvinar sodales mattis. Donec congue, nisl at bibendum pulvinar, nibh justo malesuada nisl, non vulputate odio velit nec felis. Proin aliquam lobortis metus quis fringilla. Sed interdum maximus augue in auctor. Proin faucibus commodo turpis, eleifend tempor neque elementum quis.
</p>
<h2>Subheading 2</h2>
<p>
  Vivamus vel libero nec lectus consectetur auctor in tempor metus. Quisque varius malesuada velit ac ultrices. Nunc ullamcorper est diam, sed vestibulum sapien finibus vel. Suspendisse mollis vel libero eget sagittis. Nam id odio libero. Donec mi ipsum, maximus a egestas id, dapibus sed arcu. In efficitur risus vel est pharetra, vitae sollicitudin dolor finibus. Vivamus sem magna, condimentum nec porta eu, imperdiet at erat. Nulla aliquet auctor consequat. Aliquam pulvinar sodales mattis. Donec congue, nisl at bibendum pulvinar, nibh justo malesuada nisl, non vulputate odio velit nec felis. Proin aliquam lobortis metus quis fringilla. Sed interdum maximus augue in auctor. Proin faucibus commodo turpis, eleifend tempor neque elementum quis.
</p>
<p>
  Vivamus vel libero nec lectus consectetur auctor in tempor metus. Quisque varius malesuada velit ac ultrices. Nunc ullamcorper est diam, sed vestibulum sapien finibus vel. Suspendisse mollis vel libero eget sagittis. Nam id odio libero. Donec mi ipsum, maximus a egestas id, dapibus sed arcu. In efficitur risus vel est pharetra, vitae sollicitudin dolor finibus. Vivamus sem magna, condimentum nec porta eu, imperdiet at erat. Nulla aliquet auctor consequat. Aliquam pulvinar sodales mattis. Donec congue, nisl at bibendum pulvinar, nibh justo malesuada nisl, non vulputate odio velit nec felis. Proin aliquam lobortis metus quis fringilla. Sed interdum maximus augue in auctor. Proin faucibus commodo turpis, eleifend tempor neque elementum quis.
</p>

http://jsbin.com/nuwini/edit?html,css,js

Mosh Feu
  • 28,354
  • 16
  • 88
  • 135
  • Excellent! Although I think the answer to my question is "I can't", I think your answer is as close as I'm going to get. I looked at [the modification](https://github.com/gfranko/jquery.tocify.js/pull/92) and I should've realized it would be that simple. I can't use this in my current project because this client can't host additional files and I [can't rely on RawGit's CDN](http://rawgit.com/faq#no-uptime-guarantee) for a production project, but I'll definitely use it in the future. – Vince Feb 09 '16 at 10:53
  • My pleasure ;) Good luck with that.. How do you reference to this plugin now? – Mosh Feu Feb 09 '16 at 10:59
  • I'm using [cdnjs](https://cdnjs.com/). Although their site doesn't say anything about guaranteed uptime, they have a team of maintainers and they're targeted at production sites. – Vince Feb 09 '16 at 11:20
  • I see.. Maybe if the author of the plugin will accept the commit and will update the files in cdnjs you could work with it.Good luck anyway.. – Mosh Feu Feb 09 '16 at 12:21