From 05f3730c34c86c2cb973db1ddba151f9efd0027e Mon Sep 17 00:00:00 2001 From: SanderElias Date: Wed, 25 Nov 2015 10:48:40 +0100 Subject: [PATCH] fix(tooltip): tooltip sometimes not hidden after element is disabled. use an mutationobserver to make sure the tooltip is hidden after an element becomes disabled. fixes: #2602 --- src/components/tooltip/tooltip.js | 18 ++++++++ src/components/tooltip/tooltip.spec.js | 57 ++++++++++++++++++++++++++ 2 files changed, 75 insertions(+) diff --git a/src/components/tooltip/tooltip.js b/src/components/tooltip/tooltip.js index 2068ec64ab2..1fb48c55e02 100644 --- a/src/components/tooltip/tooltip.js +++ b/src/components/tooltip/tooltip.js @@ -122,6 +122,23 @@ function MdTooltipDirective($timeout, $window, $$rAF, $document, $mdUtil, $mdThe var ngWindow = angular.element($window); + // add an mutationObserver when there is support for it + // and the need for it in the form of viable host(parent[0]) + if (parent[0] && 'MutationObserver' in $window) { + // use an mutationObserver to tackle #2602 + var attributeObserver = new MutationObserver(function(mutations) { + mutations + .forEach(function (mutation) { + if (mutation.attributeName === 'disabled' && parent[0].disabled) { + setVisible(false); + scope.$digest(); // make sure the elements gets updated + } + }); + }); + + attributeObserver.observe(parent[0], { attributes: true}); + }; + // Store whether the element was focused when the window loses focus. var windowBlurHandler = function() { elementFocusedOnWindowBlur = document.activeElement === parent[0]; @@ -133,6 +150,7 @@ function MdTooltipDirective($timeout, $window, $$rAF, $document, $mdUtil, $mdThe scope.$on('$destroy', function() { ngWindow.off('blur', windowBlurHandler); ngWindow.off('resize', debouncedOnResize); + attributeObserver && attributeObserver.disconnect(); }); var enterHandler = function(e) { diff --git a/src/components/tooltip/tooltip.spec.js b/src/components/tooltip/tooltip.spec.js index 34267ee3d83..0b3ff49e572 100644 --- a/src/components/tooltip/tooltip.spec.js +++ b/src/components/tooltip/tooltip.spec.js @@ -224,6 +224,63 @@ describe(' directive', function() { triggerEvent('focus'); expect($rootScope.testModel.isVisible).toBe(false); })); + + ddescribe(' attributeObserver', function() { + if (window.MutationObserver === undefined) { + // PhantomJS doesn't support mo + it(' does not work without support for mutationObservers', function () { + expect(true).toBe(true); + }) + return ; + } + var obs + beforeEach(function (mutationDone){ + obs = new MutationObserver(function(mutations) { + mutations + .forEach(function (mutation) { + if (mutation.attributeName === 'disabled' && mutation.target.disabled) { + // allow a little time for the observer on the tooltip to finish + setTimeout(function() { + $timeout.flush(); + $material.flushOutstandingAnimations(); + mutationDone(); + },50); + } + }) + }); + + var el = buildTooltip( + '' + + 'Hello' + + '' + + 'Tooltip' + + '' + + '' + ); + + showTooltip(true); + // check if the testsetup is ok + expect($rootScope.testModel.isVisible).toBe(true) + expect(findTooltip().length).toBe(1); + // attach the observer + obs.observe(el[0], { attributes: true}); + // trigger the mutationObserver(s). + el.attr('disabled',true) + }) + + afterEach(function () { + // remove observer from dom. + obs.disconnect(); + obs = null; + }) + + it('should be hidden after element gets disabled', function() { + expect($rootScope.testModel.isVisible).toBe(false) + expect(findTooltip().length).toBe(0); + }) + }); + + }); // ******************************************************