Blame view

resources/js/common/directives/frClickOut.js 2.54 KB
e77200db5   nologostudio.ru   Initial commit
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();
                  }
              }
          },
      };
  }]);