'use strict'; /** * It's like click, but when you don't click on your element. */ app.directive('offClick', ['$document', '$timeout', function ($document, $timeout) { function targetInFilter(target, filter) { if (!target || !filter) return false; var elms = angular.element(document.querySelectorAll(filter)); var elmsLen = elms.length; for (var i = 0; i < elmsLen; ++i) if (elms[i].contains(target)) return true; return false; } return { restrict: 'A', scope: { offClick: '&', offClickIf: '&' }, link: function (scope, elm, attr) { if (attr.offClickIf) { scope.$watch(scope.offClickIf, function (newVal, oldVal) { if (newVal && !oldVal) { $timeout(function () { $document.on('click', handler); }); } else if (!newVal) { $document.off('click', handler); } } ); } else { $document.on('click', handler); } scope.$on('$destroy', function () { $document.off('click', handler); }); function handler(event) { // This filters out artificial click events. Example: If you hit enter on a form to submit it, an // artificial click event gets triggered on the form's submit button. if (event.pageX == 0 && event.pageY == 0) return; var target = event.target || event.srcElement; if (!(elm[0].contains(target) || targetInFilter(target, attr.offClickFilter))) { scope.$apply(scope.offClick()); } } } }; }]);