diff --git a/framework/core/js/forum/src/components/stream-content.js b/framework/core/js/forum/src/components/stream-content.js index 16c6a60d3..767e8a657 100644 --- a/framework/core/js/forum/src/components/stream-content.js +++ b/framework/core/js/forum/src/components/stream-content.js @@ -179,16 +179,33 @@ export default class StreamContent extends mixin(Component, evented) { scrollToItem($item, noAnimation) { var $container = $('html, body').stop(true); if ($item.length) { - var scrollTop = $item.is(':first-child') ? 0 : $item.offset().top - this.getMarginTop(); - if (noAnimation) { - $container.scrollTop(scrollTop); - } else if (scrollTop !== $(document).scrollTop()) { - $container.animate({scrollTop: scrollTop}, 'fast'); + var itemTop = $item.offset().top - this.getMarginTop(); + var itemBottom = itemTop + $item.height(); + var scrollTop = $(document).scrollTop(); + var scrollBottom = scrollTop + $(window).height(); + + // If the item is already in the viewport, just flash it, we don't need to + // scroll anywhere. + if (itemTop > scrollTop && itemBottom < scrollBottom) { + this.flashItem($item); + } else { + var scrollTop = $item.is(':first-child') ? 0 : itemTop; + if (noAnimation) { + $container.scrollTop(scrollTop); + } else if (scrollTop !== $(document).scrollTop()) { + $container.animate({scrollTop: scrollTop}, 'fast', this.flashItem.bind(this, $item)); + } else { + this.flashItem($item); + } } } return $container.promise(); } + flashItem($item) { + $item.addClass('flash').one('animationend webkitAnimationEnd', () => $item.removeClass('flash')); + } + /** Find the DOM element of the item that is nearest to a post with a certain number. This will either be another post (if the requested post doesn't diff --git a/framework/core/less/forum/discussion.less b/framework/core/less/forum/discussion.less index 464f5e838..aed151e57 100644 --- a/framework/core/less/forum/discussion.less +++ b/framework/core/less/forum/discussion.less @@ -166,6 +166,18 @@ background: @fl-primary-color; } } +@-webkit-keyframes pulsate { + 0% {transform: scale(1)} + 50% {transform: scale(1.02)} + 100% {transform: scale(1)} +} +.item.pulsate { + -webkit-animation: pulsate 1s ease-in-out; + -webkit-animation-iteration-count: infinite; +} +.item.flash { + -webkit-animation: pulsate 0.2s ease-in-out; + -webkit-animation-iteration-count: 1; } .post-header { margin-bottom: 10px;