GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.

Code Duplication    Length = 541-541 lines in 2 locations

third-party/angularjs-modules-plugins/UI-Bootstrap/ui-bootstrap-tpls-1.3.2.js 1 location

@@ 4486-5026 (lines=541) @@
4483
 * The $tooltip service creates tooltip- and popover-like directives as well as
4484
 * houses global options for them.
4485
 */
4486
.provider('$uibTooltip', function() {
4487
  // The default options tooltip and popover.
4488
  var defaultOptions = {
4489
    placement: 'top',
4490
    placementClassPrefix: '',
4491
    animation: true,
4492
    popupDelay: 0,
4493
    popupCloseDelay: 0,
4494
    useContentExp: false
4495
  };
4496
4497
  // Default hide triggers for each show trigger
4498
  var triggerMap = {
4499
    'mouseenter': 'mouseleave',
4500
    'click': 'click',
4501
    'outsideClick': 'outsideClick',
4502
    'focus': 'blur',
4503
    'none': ''
4504
  };
4505
4506
  // The options specified to the provider globally.
4507
  var globalOptions = {};
4508
4509
  /**
4510
   * `options({})` allows global configuration of all tooltips in the
4511
   * application.
4512
   *
4513
   *   var app = angular.module( 'App', ['ui.bootstrap.tooltip'], function( $tooltipProvider ) {
4514
   *     // place tooltips left instead of top by default
4515
   *     $tooltipProvider.options( { placement: 'left' } );
4516
   *   });
4517
   */
4518
	this.options = function(value) {
4519
		angular.extend(globalOptions, value);
4520
	};
4521
4522
  /**
4523
   * This allows you to extend the set of trigger mappings available. E.g.:
4524
   *
4525
   *   $tooltipProvider.setTriggers( { 'openTrigger': 'closeTrigger' } );
4526
   */
4527
  this.setTriggers = function setTriggers(triggers) {
4528
    angular.extend(triggerMap, triggers);
4529
  };
4530
4531
  /**
4532
   * This is a helper function for translating camel-case to snake_case.
4533
   */
4534
  function snake_case(name) {
4535
    var regexp = /[A-Z]/g;
4536
    var separator = '-';
4537
    return name.replace(regexp, function(letter, pos) {
4538
      return (pos ? separator : '') + letter.toLowerCase();
4539
    });
4540
  }
4541
4542
  /**
4543
   * Returns the actual instance of the $tooltip service.
4544
   * TODO support multiple triggers
4545
   */
4546
  this.$get = ['$window', '$compile', '$timeout', '$document', '$uibPosition', '$interpolate', '$rootScope', '$parse', '$$stackedMap', function($window, $compile, $timeout, $document, $position, $interpolate, $rootScope, $parse, $$stackedMap) {
4547
    var openedTooltips = $$stackedMap.createNew();
4548
    $document.on('keypress', keypressListener);
4549
4550
    $rootScope.$on('$destroy', function() {
4551
      $document.off('keypress', keypressListener);
4552
    });
4553
4554
    function keypressListener(e) {
4555
      if (e.which === 27) {
4556
        var last = openedTooltips.top();
4557
        if (last) {
4558
          last.value.close();
4559
          openedTooltips.removeTop();
4560
          last = null;
4561
        }
4562
      }
4563
    }
4564
4565
    return function $tooltip(ttType, prefix, defaultTriggerShow, options) {
4566
      options = angular.extend({}, defaultOptions, globalOptions, options);
4567
4568
      /**
4569
       * Returns an object of show and hide triggers.
4570
       *
4571
       * If a trigger is supplied,
4572
       * it is used to show the tooltip; otherwise, it will use the `trigger`
4573
       * option passed to the `$tooltipProvider.options` method; else it will
4574
       * default to the trigger supplied to this directive factory.
4575
       *
4576
       * The hide trigger is based on the show trigger. If the `trigger` option
4577
       * was passed to the `$tooltipProvider.options` method, it will use the
4578
       * mapped trigger from `triggerMap` or the passed trigger if the map is
4579
       * undefined; otherwise, it uses the `triggerMap` value of the show
4580
       * trigger; else it will just use the show trigger.
4581
       */
4582
      function getTriggers(trigger) {
4583
        var show = (trigger || options.trigger || defaultTriggerShow).split(' ');
4584
        var hide = show.map(function(trigger) {
4585
          return triggerMap[trigger] || trigger;
4586
        });
4587
        return {
4588
          show: show,
4589
          hide: hide
4590
        };
4591
      }
4592
4593
      var directiveName = snake_case(ttType);
4594
4595
      var startSym = $interpolate.startSymbol();
4596
      var endSym = $interpolate.endSymbol();
4597
      var template =
4598
        '<div '+ directiveName + '-popup ' +
4599
          'uib-title="' + startSym + 'title' + endSym + '" ' +
4600
          (options.useContentExp ?
4601
            'content-exp="contentExp()" ' :
4602
            'content="' + startSym + 'content' + endSym + '" ') +
4603
          'placement="' + startSym + 'placement' + endSym + '" ' +
4604
          'popup-class="' + startSym + 'popupClass' + endSym + '" ' +
4605
          'animation="animation" ' +
4606
          'is-open="isOpen" ' +
4607
          'origin-scope="origScope" ' +
4608
          'class="uib-position-measure"' +
4609
          '>' +
4610
        '</div>';
4611
4612
      return {
4613
        compile: function(tElem, tAttrs) {
4614
          var tooltipLinker = $compile(template);
4615
4616
          return function link(scope, element, attrs, tooltipCtrl) {
4617
            var tooltip;
4618
            var tooltipLinkedScope;
4619
            var transitionTimeout;
4620
            var showTimeout;
4621
            var hideTimeout;
4622
            var positionTimeout;
4623
            var appendToBody = angular.isDefined(options.appendToBody) ? options.appendToBody : false;
4624
            var triggers = getTriggers(undefined);
4625
            var hasEnableExp = angular.isDefined(attrs[prefix + 'Enable']);
4626
            var ttScope = scope.$new(true);
4627
            var repositionScheduled = false;
4628
            var isOpenParse = angular.isDefined(attrs[prefix + 'IsOpen']) ? $parse(attrs[prefix + 'IsOpen']) : false;
4629
            var contentParse = options.useContentExp ? $parse(attrs[ttType]) : false;
4630
            var observers = [];
4631
            var lastPlacement;
4632
4633
            var positionTooltip = function() {
4634
              // check if tooltip exists and is not empty
4635
              if (!tooltip || !tooltip.html()) { return; }
4636
4637
              if (!positionTimeout) {
4638
                positionTimeout = $timeout(function() {
4639
                  var ttPosition = $position.positionElements(element, tooltip, ttScope.placement, appendToBody);
4640
                  tooltip.css({ top: ttPosition.top + 'px', left: ttPosition.left + 'px' });
4641
4642
                  if (!tooltip.hasClass(ttPosition.placement.split('-')[0])) {
4643
                    tooltip.removeClass(lastPlacement.split('-')[0]);
4644
                    tooltip.addClass(ttPosition.placement.split('-')[0]);
4645
                  }
4646
4647
                  if (!tooltip.hasClass(options.placementClassPrefix + ttPosition.placement)) {
4648
                    tooltip.removeClass(options.placementClassPrefix + lastPlacement);
4649
                    tooltip.addClass(options.placementClassPrefix + ttPosition.placement);
4650
                  }
4651
4652
                  // first time through tt element will have the
4653
                  // uib-position-measure class or if the placement
4654
                  // has changed we need to position the arrow.
4655
                  if (tooltip.hasClass('uib-position-measure')) {
4656
                    $position.positionArrow(tooltip, ttPosition.placement);
4657
                    tooltip.removeClass('uib-position-measure');
4658
                  } else if (lastPlacement !== ttPosition.placement) {
4659
                    $position.positionArrow(tooltip, ttPosition.placement);
4660
                  }
4661
                  lastPlacement = ttPosition.placement;
4662
4663
                  positionTimeout = null;
4664
                }, 0, false);
4665
              }
4666
            };
4667
4668
            // Set up the correct scope to allow transclusion later
4669
            ttScope.origScope = scope;
4670
4671
            // By default, the tooltip is not open.
4672
            // TODO add ability to start tooltip opened
4673
            ttScope.isOpen = false;
4674
            openedTooltips.add(ttScope, {
4675
              close: hide
4676
            });
4677
4678
            function toggleTooltipBind() {
4679
              if (!ttScope.isOpen) {
4680
                showTooltipBind();
4681
              } else {
4682
                hideTooltipBind();
4683
              }
4684
            }
4685
4686
            // Show the tooltip with delay if specified, otherwise show it immediately
4687
            function showTooltipBind() {
4688
              if (hasEnableExp && !scope.$eval(attrs[prefix + 'Enable'])) {
4689
                return;
4690
              }
4691
4692
              cancelHide();
4693
              prepareTooltip();
4694
4695
              if (ttScope.popupDelay) {
4696
                // Do nothing if the tooltip was already scheduled to pop-up.
4697
                // This happens if show is triggered multiple times before any hide is triggered.
4698
                if (!showTimeout) {
4699
                  showTimeout = $timeout(show, ttScope.popupDelay, false);
4700
                }
4701
              } else {
4702
                show();
4703
              }
4704
            }
4705
4706
            function hideTooltipBind() {
4707
              cancelShow();
4708
4709
              if (ttScope.popupCloseDelay) {
4710
                if (!hideTimeout) {
4711
                  hideTimeout = $timeout(hide, ttScope.popupCloseDelay, false);
4712
                }
4713
              } else {
4714
                hide();
4715
              }
4716
            }
4717
4718
            // Show the tooltip popup element.
4719
            function show() {
4720
              cancelShow();
4721
              cancelHide();
4722
4723
              // Don't show empty tooltips.
4724
              if (!ttScope.content) {
4725
                return angular.noop;
4726
              }
4727
4728
              createTooltip();
4729
4730
              // And show the tooltip.
4731
              ttScope.$evalAsync(function() {
4732
                ttScope.isOpen = true;
4733
                assignIsOpen(true);
4734
                positionTooltip();
4735
              });
4736
            }
4737
4738
            function cancelShow() {
4739
              if (showTimeout) {
4740
                $timeout.cancel(showTimeout);
4741
                showTimeout = null;
4742
              }
4743
4744
              if (positionTimeout) {
4745
                $timeout.cancel(positionTimeout);
4746
                positionTimeout = null;
4747
              }
4748
            }
4749
4750
            // Hide the tooltip popup element.
4751
            function hide() {
4752
              if (!ttScope) {
4753
                return;
4754
              }
4755
4756
              // First things first: we don't show it anymore.
4757
              ttScope.$evalAsync(function() {
4758
                if (ttScope) {
4759
                  ttScope.isOpen = false;
4760
                  assignIsOpen(false);
4761
                  // And now we remove it from the DOM. However, if we have animation, we
4762
                  // need to wait for it to expire beforehand.
4763
                  // FIXME: this is a placeholder for a port of the transitions library.
4764
                  // The fade transition in TWBS is 150ms.
4765
                  if (ttScope.animation) {
4766
                    if (!transitionTimeout) {
4767
                      transitionTimeout = $timeout(removeTooltip, 150, false);
4768
                    }
4769
                  } else {
4770
                    removeTooltip();
4771
                  }
4772
                }
4773
              });
4774
            }
4775
4776
            function cancelHide() {
4777
              if (hideTimeout) {
4778
                $timeout.cancel(hideTimeout);
4779
                hideTimeout = null;
4780
              }
4781
4782
              if (transitionTimeout) {
4783
                $timeout.cancel(transitionTimeout);
4784
                transitionTimeout = null;
4785
              }
4786
            }
4787
4788
            function createTooltip() {
4789
              // There can only be one tooltip element per directive shown at once.
4790
              if (tooltip) {
4791
                return;
4792
              }
4793
4794
              tooltipLinkedScope = ttScope.$new();
4795
              tooltip = tooltipLinker(tooltipLinkedScope, function(tooltip) {
4796
                if (appendToBody) {
4797
                  $document.find('body').append(tooltip);
4798
                } else {
4799
                  element.after(tooltip);
4800
                }
4801
              });
4802
4803
              prepObservers();
4804
            }
4805
4806
            function removeTooltip() {
4807
              cancelShow();
4808
              cancelHide();
4809
              unregisterObservers();
4810
4811
              if (tooltip) {
4812
                tooltip.remove();
4813
                tooltip = null;
4814
              }
4815
              if (tooltipLinkedScope) {
4816
                tooltipLinkedScope.$destroy();
4817
                tooltipLinkedScope = null;
4818
              }
4819
            }
4820
4821
            /**
4822
             * Set the initial scope values. Once
4823
             * the tooltip is created, the observers
4824
             * will be added to keep things in sync.
4825
             */
4826
            function prepareTooltip() {
4827
              ttScope.title = attrs[prefix + 'Title'];
4828
              if (contentParse) {
4829
                ttScope.content = contentParse(scope);
4830
              } else {
4831
                ttScope.content = attrs[ttType];
4832
              }
4833
4834
              ttScope.popupClass = attrs[prefix + 'Class'];
4835
              ttScope.placement = angular.isDefined(attrs[prefix + 'Placement']) ? attrs[prefix + 'Placement'] : options.placement;
4836
              var placement = $position.parsePlacement(ttScope.placement);
4837
              lastPlacement = placement[1] ? placement[0] + '-' + placement[1] : placement[0];
4838
4839
              var delay = parseInt(attrs[prefix + 'PopupDelay'], 10);
4840
              var closeDelay = parseInt(attrs[prefix + 'PopupCloseDelay'], 10);
4841
              ttScope.popupDelay = !isNaN(delay) ? delay : options.popupDelay;
4842
              ttScope.popupCloseDelay = !isNaN(closeDelay) ? closeDelay : options.popupCloseDelay;
4843
            }
4844
4845
            function assignIsOpen(isOpen) {
4846
              if (isOpenParse && angular.isFunction(isOpenParse.assign)) {
4847
                isOpenParse.assign(scope, isOpen);
4848
              }
4849
            }
4850
4851
            ttScope.contentExp = function() {
4852
              return ttScope.content;
4853
            };
4854
4855
            /**
4856
             * Observe the relevant attributes.
4857
             */
4858
            attrs.$observe('disabled', function(val) {
4859
              if (val) {
4860
                cancelShow();
4861
              }
4862
4863
              if (val && ttScope.isOpen) {
4864
                hide();
4865
              }
4866
            });
4867
4868
            if (isOpenParse) {
4869
              scope.$watch(isOpenParse, function(val) {
4870
                if (ttScope && !val === ttScope.isOpen) {
4871
                  toggleTooltipBind();
4872
                }
4873
              });
4874
            }
4875
4876
            function prepObservers() {
4877
              observers.length = 0;
4878
4879
              if (contentParse) {
4880
                observers.push(
4881
                  scope.$watch(contentParse, function(val) {
4882
                    ttScope.content = val;
4883
                    if (!val && ttScope.isOpen) {
4884
                      hide();
4885
                    }
4886
                  })
4887
                );
4888
4889
                observers.push(
4890
                  tooltipLinkedScope.$watch(function() {
4891
                    if (!repositionScheduled) {
4892
                      repositionScheduled = true;
4893
                      tooltipLinkedScope.$$postDigest(function() {
4894
                        repositionScheduled = false;
4895
                        if (ttScope && ttScope.isOpen) {
4896
                          positionTooltip();
4897
                        }
4898
                      });
4899
                    }
4900
                  })
4901
                );
4902
              } else {
4903
                observers.push(
4904
                  attrs.$observe(ttType, function(val) {
4905
                    ttScope.content = val;
4906
                    if (!val && ttScope.isOpen) {
4907
                      hide();
4908
                    } else {
4909
                      positionTooltip();
4910
                    }
4911
                  })
4912
                );
4913
              }
4914
4915
              observers.push(
4916
                attrs.$observe(prefix + 'Title', function(val) {
4917
                  ttScope.title = val;
4918
                  if (ttScope.isOpen) {
4919
                    positionTooltip();
4920
                  }
4921
                })
4922
              );
4923
4924
              observers.push(
4925
                attrs.$observe(prefix + 'Placement', function(val) {
4926
                  ttScope.placement = val ? val : options.placement;
4927
                  if (ttScope.isOpen) {
4928
                    positionTooltip();
4929
                  }
4930
                })
4931
              );
4932
            }
4933
4934
            function unregisterObservers() {
4935
              if (observers.length) {
4936
                angular.forEach(observers, function(observer) {
4937
                  observer();
4938
                });
4939
                observers.length = 0;
4940
              }
4941
            }
4942
4943
            // hide tooltips/popovers for outsideClick trigger
4944
            function bodyHideTooltipBind(e) {
4945
              if (!ttScope || !ttScope.isOpen || !tooltip) {
4946
                return;
4947
              }
4948
              // make sure the tooltip/popover link or tool tooltip/popover itself were not clicked
4949
              if (!element[0].contains(e.target) && !tooltip[0].contains(e.target)) {
4950
                hideTooltipBind();
4951
              }
4952
            }
4953
4954
            var unregisterTriggers = function() {
4955
              triggers.show.forEach(function(trigger) {
4956
                if (trigger === 'outsideClick') {
4957
                  element.off('click', toggleTooltipBind);
4958
                } else {
4959
                  element.off(trigger, showTooltipBind);
4960
                  element.off(trigger, toggleTooltipBind);
4961
                }
4962
              });
4963
              triggers.hide.forEach(function(trigger) {
4964
                if (trigger === 'outsideClick') {
4965
                  $document.off('click', bodyHideTooltipBind);
4966
                } else {
4967
                  element.off(trigger, hideTooltipBind);
4968
                }
4969
              });
4970
            };
4971
4972
            function prepTriggers() {
4973
              var val = attrs[prefix + 'Trigger'];
4974
              unregisterTriggers();
4975
4976
              triggers = getTriggers(val);
4977
4978
              if (triggers.show !== 'none') {
4979
                triggers.show.forEach(function(trigger, idx) {
4980
                  if (trigger === 'outsideClick') {
4981
                    element.on('click', toggleTooltipBind);
4982
                    $document.on('click', bodyHideTooltipBind);
4983
                  } else if (trigger === triggers.hide[idx]) {
4984
                    element.on(trigger, toggleTooltipBind);
4985
                  } else if (trigger) {
4986
                    element.on(trigger, showTooltipBind);
4987
                    element.on(triggers.hide[idx], hideTooltipBind);
4988
                  }
4989
4990
                  element.on('keypress', function(e) {
4991
                    if (e.which === 27) {
4992
                      hideTooltipBind();
4993
                    }
4994
                  });
4995
                });
4996
              }
4997
            }
4998
4999
            prepTriggers();
5000
5001
            var animation = scope.$eval(attrs[prefix + 'Animation']);
5002
            ttScope.animation = angular.isDefined(animation) ? !!animation : options.animation;
5003
5004
            var appendToBodyVal;
5005
            var appendKey = prefix + 'AppendToBody';
5006
            if (appendKey in attrs && attrs[appendKey] === undefined) {
5007
              appendToBodyVal = true;
5008
            } else {
5009
              appendToBodyVal = scope.$eval(attrs[appendKey]);
5010
            }
5011
5012
            appendToBody = angular.isDefined(appendToBodyVal) ? appendToBodyVal : appendToBody;
5013
5014
            // Make sure tooltip is destroyed and removed.
5015
            scope.$on('$destroy', function onDestroyTooltip() {
5016
              unregisterTriggers();
5017
              removeTooltip();
5018
              openedTooltips.remove(ttScope);
5019
              ttScope = null;
5020
            });
5021
          };
5022
        }
5023
      };
5024
    };
5025
  }];
5026
})
5027
5028
// This is mostly ngInclude code but with a custom scope
5029
.directive('uibTooltipTemplateTransclude', [

third-party/angularjs-modules-plugins/UI-Bootstrap/ui-bootstrap-1.3.2.js 1 location

@@ 4485-5025 (lines=541) @@
4482
 * The $tooltip service creates tooltip- and popover-like directives as well as
4483
 * houses global options for them.
4484
 */
4485
.provider('$uibTooltip', function() {
4486
  // The default options tooltip and popover.
4487
  var defaultOptions = {
4488
    placement: 'top',
4489
    placementClassPrefix: '',
4490
    animation: true,
4491
    popupDelay: 0,
4492
    popupCloseDelay: 0,
4493
    useContentExp: false
4494
  };
4495
4496
  // Default hide triggers for each show trigger
4497
  var triggerMap = {
4498
    'mouseenter': 'mouseleave',
4499
    'click': 'click',
4500
    'outsideClick': 'outsideClick',
4501
    'focus': 'blur',
4502
    'none': ''
4503
  };
4504
4505
  // The options specified to the provider globally.
4506
  var globalOptions = {};
4507
4508
  /**
4509
   * `options({})` allows global configuration of all tooltips in the
4510
   * application.
4511
   *
4512
   *   var app = angular.module( 'App', ['ui.bootstrap.tooltip'], function( $tooltipProvider ) {
4513
   *     // place tooltips left instead of top by default
4514
   *     $tooltipProvider.options( { placement: 'left' } );
4515
   *   });
4516
   */
4517
	this.options = function(value) {
4518
		angular.extend(globalOptions, value);
4519
	};
4520
4521
  /**
4522
   * This allows you to extend the set of trigger mappings available. E.g.:
4523
   *
4524
   *   $tooltipProvider.setTriggers( { 'openTrigger': 'closeTrigger' } );
4525
   */
4526
  this.setTriggers = function setTriggers(triggers) {
4527
    angular.extend(triggerMap, triggers);
4528
  };
4529
4530
  /**
4531
   * This is a helper function for translating camel-case to snake_case.
4532
   */
4533
  function snake_case(name) {
4534
    var regexp = /[A-Z]/g;
4535
    var separator = '-';
4536
    return name.replace(regexp, function(letter, pos) {
4537
      return (pos ? separator : '') + letter.toLowerCase();
4538
    });
4539
  }
4540
4541
  /**
4542
   * Returns the actual instance of the $tooltip service.
4543
   * TODO support multiple triggers
4544
   */
4545
  this.$get = ['$window', '$compile', '$timeout', '$document', '$uibPosition', '$interpolate', '$rootScope', '$parse', '$$stackedMap', function($window, $compile, $timeout, $document, $position, $interpolate, $rootScope, $parse, $$stackedMap) {
4546
    var openedTooltips = $$stackedMap.createNew();
4547
    $document.on('keypress', keypressListener);
4548
4549
    $rootScope.$on('$destroy', function() {
4550
      $document.off('keypress', keypressListener);
4551
    });
4552
4553
    function keypressListener(e) {
4554
      if (e.which === 27) {
4555
        var last = openedTooltips.top();
4556
        if (last) {
4557
          last.value.close();
4558
          openedTooltips.removeTop();
4559
          last = null;
4560
        }
4561
      }
4562
    }
4563
4564
    return function $tooltip(ttType, prefix, defaultTriggerShow, options) {
4565
      options = angular.extend({}, defaultOptions, globalOptions, options);
4566
4567
      /**
4568
       * Returns an object of show and hide triggers.
4569
       *
4570
       * If a trigger is supplied,
4571
       * it is used to show the tooltip; otherwise, it will use the `trigger`
4572
       * option passed to the `$tooltipProvider.options` method; else it will
4573
       * default to the trigger supplied to this directive factory.
4574
       *
4575
       * The hide trigger is based on the show trigger. If the `trigger` option
4576
       * was passed to the `$tooltipProvider.options` method, it will use the
4577
       * mapped trigger from `triggerMap` or the passed trigger if the map is
4578
       * undefined; otherwise, it uses the `triggerMap` value of the show
4579
       * trigger; else it will just use the show trigger.
4580
       */
4581
      function getTriggers(trigger) {
4582
        var show = (trigger || options.trigger || defaultTriggerShow).split(' ');
4583
        var hide = show.map(function(trigger) {
4584
          return triggerMap[trigger] || trigger;
4585
        });
4586
        return {
4587
          show: show,
4588
          hide: hide
4589
        };
4590
      }
4591
4592
      var directiveName = snake_case(ttType);
4593
4594
      var startSym = $interpolate.startSymbol();
4595
      var endSym = $interpolate.endSymbol();
4596
      var template =
4597
        '<div '+ directiveName + '-popup ' +
4598
          'uib-title="' + startSym + 'title' + endSym + '" ' +
4599
          (options.useContentExp ?
4600
            'content-exp="contentExp()" ' :
4601
            'content="' + startSym + 'content' + endSym + '" ') +
4602
          'placement="' + startSym + 'placement' + endSym + '" ' +
4603
          'popup-class="' + startSym + 'popupClass' + endSym + '" ' +
4604
          'animation="animation" ' +
4605
          'is-open="isOpen" ' +
4606
          'origin-scope="origScope" ' +
4607
          'class="uib-position-measure"' +
4608
          '>' +
4609
        '</div>';
4610
4611
      return {
4612
        compile: function(tElem, tAttrs) {
4613
          var tooltipLinker = $compile(template);
4614
4615
          return function link(scope, element, attrs, tooltipCtrl) {
4616
            var tooltip;
4617
            var tooltipLinkedScope;
4618
            var transitionTimeout;
4619
            var showTimeout;
4620
            var hideTimeout;
4621
            var positionTimeout;
4622
            var appendToBody = angular.isDefined(options.appendToBody) ? options.appendToBody : false;
4623
            var triggers = getTriggers(undefined);
4624
            var hasEnableExp = angular.isDefined(attrs[prefix + 'Enable']);
4625
            var ttScope = scope.$new(true);
4626
            var repositionScheduled = false;
4627
            var isOpenParse = angular.isDefined(attrs[prefix + 'IsOpen']) ? $parse(attrs[prefix + 'IsOpen']) : false;
4628
            var contentParse = options.useContentExp ? $parse(attrs[ttType]) : false;
4629
            var observers = [];
4630
            var lastPlacement;
4631
4632
            var positionTooltip = function() {
4633
              // check if tooltip exists and is not empty
4634
              if (!tooltip || !tooltip.html()) { return; }
4635
4636
              if (!positionTimeout) {
4637
                positionTimeout = $timeout(function() {
4638
                  var ttPosition = $position.positionElements(element, tooltip, ttScope.placement, appendToBody);
4639
                  tooltip.css({ top: ttPosition.top + 'px', left: ttPosition.left + 'px' });
4640
4641
                  if (!tooltip.hasClass(ttPosition.placement.split('-')[0])) {
4642
                    tooltip.removeClass(lastPlacement.split('-')[0]);
4643
                    tooltip.addClass(ttPosition.placement.split('-')[0]);
4644
                  }
4645
4646
                  if (!tooltip.hasClass(options.placementClassPrefix + ttPosition.placement)) {
4647
                    tooltip.removeClass(options.placementClassPrefix + lastPlacement);
4648
                    tooltip.addClass(options.placementClassPrefix + ttPosition.placement);
4649
                  }
4650
4651
                  // first time through tt element will have the
4652
                  // uib-position-measure class or if the placement
4653
                  // has changed we need to position the arrow.
4654
                  if (tooltip.hasClass('uib-position-measure')) {
4655
                    $position.positionArrow(tooltip, ttPosition.placement);
4656
                    tooltip.removeClass('uib-position-measure');
4657
                  } else if (lastPlacement !== ttPosition.placement) {
4658
                    $position.positionArrow(tooltip, ttPosition.placement);
4659
                  }
4660
                  lastPlacement = ttPosition.placement;
4661
4662
                  positionTimeout = null;
4663
                }, 0, false);
4664
              }
4665
            };
4666
4667
            // Set up the correct scope to allow transclusion later
4668
            ttScope.origScope = scope;
4669
4670
            // By default, the tooltip is not open.
4671
            // TODO add ability to start tooltip opened
4672
            ttScope.isOpen = false;
4673
            openedTooltips.add(ttScope, {
4674
              close: hide
4675
            });
4676
4677
            function toggleTooltipBind() {
4678
              if (!ttScope.isOpen) {
4679
                showTooltipBind();
4680
              } else {
4681
                hideTooltipBind();
4682
              }
4683
            }
4684
4685
            // Show the tooltip with delay if specified, otherwise show it immediately
4686
            function showTooltipBind() {
4687
              if (hasEnableExp && !scope.$eval(attrs[prefix + 'Enable'])) {
4688
                return;
4689
              }
4690
4691
              cancelHide();
4692
              prepareTooltip();
4693
4694
              if (ttScope.popupDelay) {
4695
                // Do nothing if the tooltip was already scheduled to pop-up.
4696
                // This happens if show is triggered multiple times before any hide is triggered.
4697
                if (!showTimeout) {
4698
                  showTimeout = $timeout(show, ttScope.popupDelay, false);
4699
                }
4700
              } else {
4701
                show();
4702
              }
4703
            }
4704
4705
            function hideTooltipBind() {
4706
              cancelShow();
4707
4708
              if (ttScope.popupCloseDelay) {
4709
                if (!hideTimeout) {
4710
                  hideTimeout = $timeout(hide, ttScope.popupCloseDelay, false);
4711
                }
4712
              } else {
4713
                hide();
4714
              }
4715
            }
4716
4717
            // Show the tooltip popup element.
4718
            function show() {
4719
              cancelShow();
4720
              cancelHide();
4721
4722
              // Don't show empty tooltips.
4723
              if (!ttScope.content) {
4724
                return angular.noop;
4725
              }
4726
4727
              createTooltip();
4728
4729
              // And show the tooltip.
4730
              ttScope.$evalAsync(function() {
4731
                ttScope.isOpen = true;
4732
                assignIsOpen(true);
4733
                positionTooltip();
4734
              });
4735
            }
4736
4737
            function cancelShow() {
4738
              if (showTimeout) {
4739
                $timeout.cancel(showTimeout);
4740
                showTimeout = null;
4741
              }
4742
4743
              if (positionTimeout) {
4744
                $timeout.cancel(positionTimeout);
4745
                positionTimeout = null;
4746
              }
4747
            }
4748
4749
            // Hide the tooltip popup element.
4750
            function hide() {
4751
              if (!ttScope) {
4752
                return;
4753
              }
4754
4755
              // First things first: we don't show it anymore.
4756
              ttScope.$evalAsync(function() {
4757
                if (ttScope) {
4758
                  ttScope.isOpen = false;
4759
                  assignIsOpen(false);
4760
                  // And now we remove it from the DOM. However, if we have animation, we
4761
                  // need to wait for it to expire beforehand.
4762
                  // FIXME: this is a placeholder for a port of the transitions library.
4763
                  // The fade transition in TWBS is 150ms.
4764
                  if (ttScope.animation) {
4765
                    if (!transitionTimeout) {
4766
                      transitionTimeout = $timeout(removeTooltip, 150, false);
4767
                    }
4768
                  } else {
4769
                    removeTooltip();
4770
                  }
4771
                }
4772
              });
4773
            }
4774
4775
            function cancelHide() {
4776
              if (hideTimeout) {
4777
                $timeout.cancel(hideTimeout);
4778
                hideTimeout = null;
4779
              }
4780
4781
              if (transitionTimeout) {
4782
                $timeout.cancel(transitionTimeout);
4783
                transitionTimeout = null;
4784
              }
4785
            }
4786
4787
            function createTooltip() {
4788
              // There can only be one tooltip element per directive shown at once.
4789
              if (tooltip) {
4790
                return;
4791
              }
4792
4793
              tooltipLinkedScope = ttScope.$new();
4794
              tooltip = tooltipLinker(tooltipLinkedScope, function(tooltip) {
4795
                if (appendToBody) {
4796
                  $document.find('body').append(tooltip);
4797
                } else {
4798
                  element.after(tooltip);
4799
                }
4800
              });
4801
4802
              prepObservers();
4803
            }
4804
4805
            function removeTooltip() {
4806
              cancelShow();
4807
              cancelHide();
4808
              unregisterObservers();
4809
4810
              if (tooltip) {
4811
                tooltip.remove();
4812
                tooltip = null;
4813
              }
4814
              if (tooltipLinkedScope) {
4815
                tooltipLinkedScope.$destroy();
4816
                tooltipLinkedScope = null;
4817
              }
4818
            }
4819
4820
            /**
4821
             * Set the initial scope values. Once
4822
             * the tooltip is created, the observers
4823
             * will be added to keep things in sync.
4824
             */
4825
            function prepareTooltip() {
4826
              ttScope.title = attrs[prefix + 'Title'];
4827
              if (contentParse) {
4828
                ttScope.content = contentParse(scope);
4829
              } else {
4830
                ttScope.content = attrs[ttType];
4831
              }
4832
4833
              ttScope.popupClass = attrs[prefix + 'Class'];
4834
              ttScope.placement = angular.isDefined(attrs[prefix + 'Placement']) ? attrs[prefix + 'Placement'] : options.placement;
4835
              var placement = $position.parsePlacement(ttScope.placement);
4836
              lastPlacement = placement[1] ? placement[0] + '-' + placement[1] : placement[0];
4837
4838
              var delay = parseInt(attrs[prefix + 'PopupDelay'], 10);
4839
              var closeDelay = parseInt(attrs[prefix + 'PopupCloseDelay'], 10);
4840
              ttScope.popupDelay = !isNaN(delay) ? delay : options.popupDelay;
4841
              ttScope.popupCloseDelay = !isNaN(closeDelay) ? closeDelay : options.popupCloseDelay;
4842
            }
4843
4844
            function assignIsOpen(isOpen) {
4845
              if (isOpenParse && angular.isFunction(isOpenParse.assign)) {
4846
                isOpenParse.assign(scope, isOpen);
4847
              }
4848
            }
4849
4850
            ttScope.contentExp = function() {
4851
              return ttScope.content;
4852
            };
4853
4854
            /**
4855
             * Observe the relevant attributes.
4856
             */
4857
            attrs.$observe('disabled', function(val) {
4858
              if (val) {
4859
                cancelShow();
4860
              }
4861
4862
              if (val && ttScope.isOpen) {
4863
                hide();
4864
              }
4865
            });
4866
4867
            if (isOpenParse) {
4868
              scope.$watch(isOpenParse, function(val) {
4869
                if (ttScope && !val === ttScope.isOpen) {
4870
                  toggleTooltipBind();
4871
                }
4872
              });
4873
            }
4874
4875
            function prepObservers() {
4876
              observers.length = 0;
4877
4878
              if (contentParse) {
4879
                observers.push(
4880
                  scope.$watch(contentParse, function(val) {
4881
                    ttScope.content = val;
4882
                    if (!val && ttScope.isOpen) {
4883
                      hide();
4884
                    }
4885
                  })
4886
                );
4887
4888
                observers.push(
4889
                  tooltipLinkedScope.$watch(function() {
4890
                    if (!repositionScheduled) {
4891
                      repositionScheduled = true;
4892
                      tooltipLinkedScope.$$postDigest(function() {
4893
                        repositionScheduled = false;
4894
                        if (ttScope && ttScope.isOpen) {
4895
                          positionTooltip();
4896
                        }
4897
                      });
4898
                    }
4899
                  })
4900
                );
4901
              } else {
4902
                observers.push(
4903
                  attrs.$observe(ttType, function(val) {
4904
                    ttScope.content = val;
4905
                    if (!val && ttScope.isOpen) {
4906
                      hide();
4907
                    } else {
4908
                      positionTooltip();
4909
                    }
4910
                  })
4911
                );
4912
              }
4913
4914
              observers.push(
4915
                attrs.$observe(prefix + 'Title', function(val) {
4916
                  ttScope.title = val;
4917
                  if (ttScope.isOpen) {
4918
                    positionTooltip();
4919
                  }
4920
                })
4921
              );
4922
4923
              observers.push(
4924
                attrs.$observe(prefix + 'Placement', function(val) {
4925
                  ttScope.placement = val ? val : options.placement;
4926
                  if (ttScope.isOpen) {
4927
                    positionTooltip();
4928
                  }
4929
                })
4930
              );
4931
            }
4932
4933
            function unregisterObservers() {
4934
              if (observers.length) {
4935
                angular.forEach(observers, function(observer) {
4936
                  observer();
4937
                });
4938
                observers.length = 0;
4939
              }
4940
            }
4941
4942
            // hide tooltips/popovers for outsideClick trigger
4943
            function bodyHideTooltipBind(e) {
4944
              if (!ttScope || !ttScope.isOpen || !tooltip) {
4945
                return;
4946
              }
4947
              // make sure the tooltip/popover link or tool tooltip/popover itself were not clicked
4948
              if (!element[0].contains(e.target) && !tooltip[0].contains(e.target)) {
4949
                hideTooltipBind();
4950
              }
4951
            }
4952
4953
            var unregisterTriggers = function() {
4954
              triggers.show.forEach(function(trigger) {
4955
                if (trigger === 'outsideClick') {
4956
                  element.off('click', toggleTooltipBind);
4957
                } else {
4958
                  element.off(trigger, showTooltipBind);
4959
                  element.off(trigger, toggleTooltipBind);
4960
                }
4961
              });
4962
              triggers.hide.forEach(function(trigger) {
4963
                if (trigger === 'outsideClick') {
4964
                  $document.off('click', bodyHideTooltipBind);
4965
                } else {
4966
                  element.off(trigger, hideTooltipBind);
4967
                }
4968
              });
4969
            };
4970
4971
            function prepTriggers() {
4972
              var val = attrs[prefix + 'Trigger'];
4973
              unregisterTriggers();
4974
4975
              triggers = getTriggers(val);
4976
4977
              if (triggers.show !== 'none') {
4978
                triggers.show.forEach(function(trigger, idx) {
4979
                  if (trigger === 'outsideClick') {
4980
                    element.on('click', toggleTooltipBind);
4981
                    $document.on('click', bodyHideTooltipBind);
4982
                  } else if (trigger === triggers.hide[idx]) {
4983
                    element.on(trigger, toggleTooltipBind);
4984
                  } else if (trigger) {
4985
                    element.on(trigger, showTooltipBind);
4986
                    element.on(triggers.hide[idx], hideTooltipBind);
4987
                  }
4988
4989
                  element.on('keypress', function(e) {
4990
                    if (e.which === 27) {
4991
                      hideTooltipBind();
4992
                    }
4993
                  });
4994
                });
4995
              }
4996
            }
4997
4998
            prepTriggers();
4999
5000
            var animation = scope.$eval(attrs[prefix + 'Animation']);
5001
            ttScope.animation = angular.isDefined(animation) ? !!animation : options.animation;
5002
5003
            var appendToBodyVal;
5004
            var appendKey = prefix + 'AppendToBody';
5005
            if (appendKey in attrs && attrs[appendKey] === undefined) {
5006
              appendToBodyVal = true;
5007
            } else {
5008
              appendToBodyVal = scope.$eval(attrs[appendKey]);
5009
            }
5010
5011
            appendToBody = angular.isDefined(appendToBodyVal) ? appendToBodyVal : appendToBody;
5012
5013
            // Make sure tooltip is destroyed and removed.
5014
            scope.$on('$destroy', function onDestroyTooltip() {
5015
              unregisterTriggers();
5016
              removeTooltip();
5017
              openedTooltips.remove(ttScope);
5018
              ttScope = null;
5019
            });
5020
          };
5021
        }
5022
      };
5023
    };
5024
  }];
5025
})
5026
5027
// This is mostly ngInclude code but with a custom scope
5028
.directive('uibTooltipTemplateTransclude', [