UNPKG

kibana-with-account

Version:

kibana-with-account is develop based kibana project

116 lines (97 loc) 3.47 kB
define(function (require) { var $ = require('jquery'); var _ = require('lodash'); var SCROLLER_HEIGHT = 20; require('ui/modules') .get('kibana') .directive('fixedScroll', function ($timeout) { return { restrict: 'A', link: function ($scope, $el) { var $window = $(window); var $scroller = $('<div class="fixed-scroll-scroller">').height(SCROLLER_HEIGHT); /** * Remove the listeners bound in listen() * @type {function} */ var unlisten = _.noop; /** * Listen for scroll events on the $scroller and the $el, sets unlisten() * * unlisten must be called before calling or listen() will throw an Error * * Since the browser emits "scroll" events after setting scrollLeft * the listeners also prevent tug-of-war * * @throws {Error} If unlisten was not called first * @return {undefined} */ function listen() { if (unlisten !== _.noop) { throw new Error('fixedScroll listeners were not cleaned up properly before re-listening!'); } var blockTo; function bind($from, $to) { function handler() { if (blockTo === $to) return (blockTo = null); $to.scrollLeft((blockTo = $from).scrollLeft()); } $from.on('scroll', handler); return function () { $from.off('scroll', handler); }; } unlisten = _.flow( bind($el, $scroller), bind($scroller, $el), function () { unlisten = _.noop; } ); } /** * Revert DOM changes and event listeners * @return {undefined} */ function cleanUp() { unlisten(); $scroller.detach(); $el.css('padding-bottom', 0); } /** * Modify the DOM and attach event listeners based on need. * Is called many times to re-setup, must be idempotent * @return {undefined} */ function setup() { cleanUp(); var containerWidth = $el.width(); var contentWidth = $el.prop('scrollWidth'); var containerHorizOverflow = contentWidth - containerWidth; var elTop = $el.offset().top - $window.scrollTop(); var elBottom = elTop + $el.height(); var windowVertOverflow = elBottom - $window.height(); var requireScroller = containerHorizOverflow > 0 && windowVertOverflow > 0; if (!requireScroller) return; // push the content away from the scroller $el.css('padding-bottom', SCROLLER_HEIGHT); // fill the scroller with a dummy element that mimics the content $scroller .width(containerWidth) .html($('<div>').css({ width: contentWidth, height: SCROLLER_HEIGHT })) .insertAfter($el); // listen for scroll events listen(); } // reset when the width or scrollWidth of the $el changes $scope.$watchMulti([ function () { return $el.prop('scrollWidth'); }, function () { return $el.width(); } ], setup); // cleanup when the scope is destroyed $scope.$on('$destroy', function () { cleanUp(); $scroller = $window = null; }); } }; }); });