import angular from 'angular' import $ from 'jquery' import _ from 'lodash' interface IMflyFirstTimeMotivatorController extends ng.IController { setTargetVisibility: (visibility: boolean) => void } angular.module('app').directive('mflyFtmTargetElement', [ '$window', '$document', function mflyFtmTargetElement( $window, $document, ) { return { link($scope, element, _attrs, mflyFirstTimeMotivatorController: IMflyFirstTimeMotivatorController) { // we need the initial visibility (once the targetElement is loaded) element.ready(() => { // Primary function of this directive is to alert the parent ftm when there is a change to // the target's visibility (and/or position) function targetVisibilityChange() { const currentVisibility = element.is(':visible') mflyFirstTimeMotivatorController.setTargetVisibility(currentVisibility) } // Debounce the above due to the amount of rapid calls const debouncedTargetVisibilityChange = _.debounce(targetVisibilityChange, 200) // TARGET VISIBILITY WATCH #1 - Mutation Observer // run a MutationObserver to catch when DOM changes occur // in this case when targetElement visibility changes const observer = new $window.MutationObserver(() => { // when a mutation occurs we want to alert the parent controller because // a mutation may have been a change in visibility debouncedTargetVisibilityChange() }) // add our observer "listener" to our target observer.observe(element[0], { attributes: true }) // TARGET VISIBILITY WATCH #2 - Window Resize // window resizing can also cause item visibility to change via css media queries // which are not caught by the mutation observer! $($window).resize(() => { debouncedTargetVisibilityChange() }) // TARGET VISIBILITY WATCH #3 - Height Change // If we get a change in the document page height we need to adjust potition $scope.$watch(() => $document.height(), () => { debouncedTargetVisibilityChange() }) // TARGET VISIBILITY WATCH #4 - Visibility Change // lastly we'll run an isVisible watch to catch any changes the missed onLoad $scope.$watch(() => element.is(':visible'), () => { debouncedTargetVisibilityChange() }) // COMPILE FINISHED IN PARENT CONTROLLER $scope.$on('compileComplete', () => { // compiles can finish outside all of the listners..debounce a vis change debouncedTargetVisibilityChange() }) // cleanup function $scope.$on('$destroy', () => { // cleanup observer observer.disconnect() }) }) }, require: '^mflyFirstTimeMotivator', restrict: 'A', scope: {}, } }])