frClickOut.js
2.54 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
/**
* A directive that will execute a function when user clicks out of the current
* element. By specifying filter, one can also extend this functionality to other
* elements, meaning that when user clicks on that element it will not count as
* an out click. By specifying include you can tell which elements will count as
* an out click. Include is useful only when you want to trigger an out click on
* of the children of the element itself.
*
* Example
*
* ```html
* <div fr-click-out="close()" fr-click-out-filter="#openBtn, .header-nav" fr-click-out-include=".close-btn">
* ...
* </div>
* ```
*/
angular.module('fr.clickOut', [])
.directive('frClickOut', ['$document', '$parse', function ($document, $parse) {
// Checks if any of elements defined by selectors in filter contain target.
// In other words checks if one of the filtered elements has been clicked.
function targetInFilter(target, filter) {
var filteredElements = angular.element($document[0].querySelectorAll(filter));
var totalElements = filteredElements.length;
for (var i = 0; i < totalElements; ++i) {
if (filteredElements[i].contains(target)) {
return true;
}
}
return false;
}
// Run the checks to see if we need to run click out handler or not.
function isClickOut(element, event, filter, include) {
// Make sure clicked element is not one of the included elements.
if (include && targetInFilter(event.target, include)) {
return true;
}
// Make sure clicked element is not inside our element.
if (element[0].contains(event.target)) {
return;
}
// Make sure clicked element is not one of filtered elements.
if (filter && targetInFilter(event.target, filter)) {
return;
}
return true;
}
return {
restrict: 'A',
link: function (scope, element, attrs) {
var clickOutHandler = $parse(attrs.frClickOut)(scope);
var filter = attrs.frClickOutFilter;
var include = attrs.frClickOutInclude;
// Listen for clicks on the whole document.
$document.bind('click', handle);
scope.$on('$destroy', function () {
$document.off('click', handle);
});
function handle(event) {
if (isClickOut(element, event, filter, include)) {
clickOutHandler(event);
scope.$apply();
}
}
},
};
}]);