vendor: 30,555 bytes, lines 1-882
1/* 2 * angular-ui-bootstrap 3 * http://angular-ui.github.io/bootstrap/ 4 5 * Version: 1.3.3 - 2016-05-22 6 * License: MIT 7 */angular.module("ui.bootstrap", ["ui.bootstrap.popover","ui.bootstrap.tooltip","ui.bootstrap.position","ui.bootstrap.stackedMap"]); 8/** 9 * The following features are still outstanding: popup delay, animation as a 10 * function, placement as a function, inside, support for more triggers than 11 * just mouse enter/leave, and selector delegatation. 12 */ 13angular.module('ui.bootstrap.popover', ['ui.bootstrap.tooltip']) 14 15.directive('uibPopoverTemplatePopup', function() { 16 return { 17 replace: true, 18 scope: { uibTitle: '@', contentExp: '&', placement: '@', popupClass: '@', animation: '&', isOpen: '&', 19 originScope: '&' }, 20 templateUrl: 'uib/template/popover/popover-template.html' 21 }; 22}) 23 24.directive('uibPopoverTemplate', ['$uibTooltip', function($uibTooltip) { 25 return $uibTooltip('uibPopoverTemplate', 'popover', 'click', { 26 useContentExp: true 27 }); 28}]) 29 30.directive('uibPopoverHtmlPopup', function() { 31 return { 32 replace: true, 33 scope: { contentExp: '&', uibTitle: '@', placement: '@', popupClass: '@', animation: '&', isOpen: '&' }, 34 templateUrl: 'uib/template/popover/popover-html.html' 35 }; 36}) 37 38.directive('uibPopoverHtml', ['$uibTooltip', function($uibTooltip) { 39 return $uibTooltip('uibPopoverHtml', 'popover', 'click', { 40 useContentExp: true 41 }); 42}]) 43 44.directive('uibPopoverPopup', function() { 45 return { 46 replace: true, 47 scope: { uibTitle: '@', content: '@', placement: '@', popupClass: '@', animation: '&', isOpen: '&' }, 48 templateUrl: 'uib/template/popover/popover.html' 49 }; 50}) 51 52.directive('uibPopover', ['$uibTooltip', function($uibTooltip) { 53 return $uibTooltip('uibPopover', 'popover', 'click'); 54}]); 55 56/** 57 * The following features are still outstanding: animation as a 58 * function, placement as a function, inside, support for more triggers than 59 * just mouse enter/leave, html tooltips, and selector delegation. 60 */ 61angular.module('ui.bootstrap.tooltip', ['ui.bootstrap.position', 'ui.bootstrap.stackedMap']) 62 63/** 64 * The $tooltip service creates tooltip- and popover-like directives as well as 65 * houses global options for them. 66 */ 67.provider('$uibTooltip', function() { 68 // The default options tooltip and popover. 69 var defaultOptions = { 70 placement: 'top', 71 placementClassPrefix: '', 72 animation: true, 73 popupDelay: 0, 74 popupCloseDelay: 0, 75 useContentExp: false 76 }; 77 78 // Default hide triggers for each show trigger 79 var triggerMap = { 80 'mouseenter': 'mouseleave', 81 'click': 'click', 82 'outsideClick': 'outsideClick', 83 'focus': 'blur', 84 'none': '' 85 }; 86 87 // The options specified to the provider globally. 88 var globalOptions = {}; 89 90 /** 91 * `options({})` allows global configuration of all tooltips in the 92 * application. 93 * 94 * var app = angular.module( 'App', ['ui.bootstrap.tooltip'], function( $tooltipProvider ) { 95 * // place tooltips left instead of top by default 96 * $tooltipProvider.options( { placement: 'left' } ); 97 * }); 98 */ 99 this.options = function(value) { 100 angular.extend(globalOptions, value); 101 }; 102 103 /** 104 * This allows you to extend the set of trigger mappings available. E.g.: 105 * 106 * $tooltipProvider.setTriggers( { 'openTrigger': 'closeTrigger' } ); 107 */ 108 this.setTriggers = function setTriggers(triggers) { 109 angular.extend(triggerMap, triggers); 110 }; 111 112 /** 113 * This is a helper function for translating camel-case to snake_case. 114 */ 115 function snake_case(name) { 116 var regexp = /[A-Z]/g; 117 var separator = '-'; 118 return name.replace(regexp, function(letter, pos) { 119 return (pos ? separator : '') + letter.toLowerCase(); 120 }); 121 } 122 123 /** 124 * Returns the actual instance of the $tooltip service. 125 * TODO support multiple triggers 126 */ 127 this.$get = ['$window', '$compile', '$timeout', '$document', '$uibPosition', '$interpolate', '$rootScope', '$parse', '$$stackedMap', function($window, $compile, $timeout, $document, $position, $interpolate, $rootScope, $parse, $$stackedMap) { 128 var openedTooltips = $$stackedMap.createNew(); 129 $document.on('keypress', keypressListener); 130 131 $rootScope.$on('$destroy', function() { 132 $document.off('keypress', keypressListener); 133 }); 134 135 function keypressListener(e) { 136 if (e.which === 27) { 137 var last = openedTooltips.top(); 138 if (last) { 139 last.value.close(); 140 openedTooltips.removeTop(); 141 last = null; 142 } 143 } 144 } 145 146 return function $tooltip(ttType, prefix, defaultTriggerShow, options) { 147 options = angular.extend({}, defaultOptions, globalOptions, options); 148 149 /** 150 * Returns an object of show and hide triggers. 151 * 152 * If a trigger is supplied, 153 * it is used to show the tooltip; otherwise, it will use the `trigger` 154 * option passed to the `$tooltipProvider.options` method; else it will 155 * default to the trigger supplied to this directive factory. 156 * 157 * The hide trigger is based on the show trigger. If the `trigger` option 158 * was passed to the `$tooltipProvider.options` method, it will use the 159 * mapped trigger from `triggerMap` or the passed trigger if the map is 160 * undefined; otherwise, it uses the `triggerMap` value of the show 161 * trigger; else it will just use the show trigger. 162 */ 163 function getTriggers(trigger) { 164 var show = (trigger || options.trigger || defaultTriggerShow).split(' '); 165 var hide = show.map(function(trigger) { 166 return triggerMap[trigger] || trigger; 167 }); 168 return { 169 show: show, 170 hide: hide 171 }; 172 } 173 174 var directiveName = snake_case(ttType); 175 176 var startSym = $interpolate.startSymbol(); 177 var endSym = $interpolate.endSymbol(); 178 var template = 179 '<div '+ directiveName + '-popup ' + 180 'uib-title="' + startSym + 'title' + endSym + '" ' + 181 (options.useContentExp ? 182 'content-exp="contentExp()" ' : 183 'content="' + startSym + 'content' + endSym + '" ') + 184 'placement="' + startSym + 'placement' + endSym + '" ' + 185 'popup-class="' + startSym + 'popupClass' + endSym + '" ' + 186 'animation="animation" ' + 187 'is-open="isOpen" ' + 188 'origin-scope="origScope" ' + 189 'class="uib-position-measure"' + 190 '>' + 191 '</div>'; 192 193 return { 194 compile: function(tElem, tAttrs) { 195 var tooltipLinker = $compile(template); 196 197 return function link(scope, element, attrs, tooltipCtrl) { 198 var tooltip; 199 var tooltipLinkedScope; 200 var transitionTimeout; 201 var showTimeout; 202 var hideTimeout; 203 var positionTimeout; 204 var appendToBody = angular.isDefined(options.appendToBody) ? options.appendToBody : false; 205 var triggers = getTriggers(undefined); 206 var hasEnableExp = angular.isDefined(attrs[prefix + 'Enable']); 207 var ttScope = scope.$new(true); 208 var repositionScheduled = false; 209 var isOpenParse = angular.isDefined(attrs[prefix + 'IsOpen']) ? $parse(attrs[prefix + 'IsOpen']) : false; 210 var contentParse = options.useContentExp ? $parse(attrs[ttType]) : false; 211 var observers = []; 212 var lastPlacement; 213 214 var positionTooltip = function() { 215 // check if tooltip exists and is not empty 216 if (!tooltip || !tooltip.html()) { return; } 217 218 if (!positionTimeout) { 219 positionTimeout = $timeout(function() { 220 var ttPosition = $position.positionElements(element, tooltip, ttScope.placement, appendToBody); 221 tooltip.css({ top: ttPosition.top + 'px', left: ttPosition.left + 'px' }); 222 223 if (!tooltip.hasClass(ttPosition.placement.split('-')[0])) { 224 tooltip.removeClass(lastPlacement.split('-')[0]); 225 tooltip.addClass(ttPosition.placement.split('-')[0]); 226 } 227 228 if (!tooltip.hasClass(options.placementClassPrefix + ttPosition.placement)) { 229 tooltip.removeClass(options.placementClassPrefix + lastPlacement); 230 tooltip.addClass(options.placementClassPrefix + ttPosition.placement); 231 } 232 233 // first time through tt element will have the 234 // uib-position-measure class or if the placement 235 // has changed we need to position the arrow. 236 if (tooltip.hasClass('uib-position-measure')) { 237 $position.positionArrow(tooltip, ttPosition.placement); 238 tooltip.removeClass('uib-position-measure'); 239 } else if (lastPlacement !== ttPosition.placement) { 240 $position.positionArrow(tooltip, ttPosition.placement); 241 } 242 lastPlacement = ttPosition.placement; 243 244 positionTimeout = null; 245 }, 0, false); 246 } 247 }; 248 249 // Set up the correct scope to allow transclusion later 250 ttScope.origScope = scope; 251 252 // By default, the tooltip is not open. 253 // TODO add ability to start tooltip opened 254 ttScope.isOpen = false; 255 openedTooltips.add(ttScope, { 256 close: hide 257 }); 258 259 function toggleTooltipBind() { 260 if (!ttScope.isOpen) { 261 showTooltipBind(); 262 } else { 263 hideTooltipBind(); 264 } 265 } 266 267 // Show the tooltip with delay if specified, otherwise show it immediately 268 function showTooltipBind() { 269 if (hasEnableExp && !scope.$eval(attrs[prefix + 'Enable'])) { 270 return; 271 } 272 273 cancelHide(); 274 prepareTooltip(); 275 276 if (ttScope.popupDelay) { 277 // Do nothing if the tooltip was already scheduled to pop-up. 278 // This happens if show is triggered multiple times before any hide is triggered. 279 if (!showTimeout) { 280 showTimeout = $timeout(show, ttScope.popupDelay, false); 281 } 282 } else { 283 show(); 284 } 285 } 286 287 function hideTooltipBind() { 288 cancelShow(); 289 290 if (ttScope.popupCloseDelay) { 291 if (!hideTimeout) { 292 hideTimeout = $timeout(hide, ttScope.popupCloseDelay, false); 293 } 294 } else { 295 hide(); 296 } 297 } 298 299 // Show the tooltip popup element. 300 function show() { 301 cancelShow(); 302 cancelHide(); 303 304 // Don't show empty tooltips. 305 if (!ttScope.content) { 306 return angular.noop; 307 } 308 309 createTooltip(); 310 311 // And show the tooltip. 312 ttScope.$evalAsync(function() { 313 ttScope.isOpen = true; 314 assignIsOpen(true); 315 positionTooltip(); 316 }); 317 } 318 319 function cancelShow() { 320 if (showTimeout) { 321 $timeout.cancel(showTimeout); 322 showTimeout = null; 323 } 324 325 if (positionTimeout) { 326 $timeout.cancel(positionTimeout); 327 positionTimeout = null; 328 } 329 } 330 331 // Hide the tooltip popup element. 332 function hide() { 333 if (!ttScope) { 334 return; 335 } 336 337 // First things first: we don't show it anymore. 338 ttScope.$evalAsync(function() { 339 if (ttScope) { 340 ttScope.isOpen = false; 341 assignIsOpen(false); 342 // And now we remove it from the DOM. However, if we have animation, we 343 // need to wait for it to expire beforehand. 344 // FIXME: this is a placeholder for a port of the transitions library. 345 // The fade transition in TWBS is 150ms. 346 if (ttScope.animation) { 347 if (!transitionTimeout) { 348 transitionTimeout = $timeout(removeTooltip, 150, false); 349 } 350 } else { 351 removeTooltip(); 352 } 353 } 354 }); 355 } 356 357 function cancelHide() { 358 if (hideTimeout) { 359 $timeout.cancel(hideTimeout); 360 hideTimeout = null; 361 } 362 363 if (transitionTimeout) { 364 $timeout.cancel(transitionTimeout); 365 transitionTimeout = null; 366 } 367 } 368 369 function createTooltip() { 370 // There can only be one tooltip element per directive shown at once. 371 if (tooltip) { 372 return; 373 } 374 375 tooltipLinkedScope = ttScope.$new(); 376 tooltip = tooltipLinker(tooltipLinkedScope, function(tooltip) { 377 if (appendToBody) { 378 $document.find('body').append(tooltip); 379 } else { 380 element.after(tooltip); 381 } 382 }); 383 384 prepObservers(); 385 } 386 387 function removeTooltip() { 388 cancelShow(); 389 cancelHide(); 390 unregisterObservers(); 391 392 if (tooltip) { 393 tooltip.remove(); 394 tooltip = null; 395 } 396 if (tooltipLinkedScope) { 397 tooltipLinkedScope.$destroy(); 398 tooltipLinkedScope = null; 399 } 400 } 401 402 /** 403 * Set the initial scope values. Once 404 * the tooltip is created, the observers 405 * will be added to keep things in sync. 406 */ 407 function prepareTooltip() { 408 ttScope.title = attrs[prefix + 'Title']; 409 if (contentParse) { 410 ttScope.content = contentParse(scope); 411 } else { 412 ttScope.content = attrs[ttType]; 413 } 414 415 ttScope.popupClass = attrs[prefix + 'Class']; 416 ttScope.placement = angular.isDefined(attrs[prefix + 'Placement']) ? attrs[prefix + 'Placement'] : options.placement; 417 var placement = $position.parsePlacement(ttScope.placement); 418 lastPlacement = placement[1] ? placement[0] + '-' + placement[1] : placement[0]; 419 420 var delay = parseInt(attrs[prefix + 'PopupDelay'], 10); 421 var closeDelay = parseInt(attrs[prefix + 'PopupCloseDelay'], 10); 422 ttScope.popupDelay = !isNaN(delay) ? delay : options.popupDelay; 423 ttScope.popupCloseDelay = !isNaN(closeDelay) ? closeDelay : options.popupCloseDelay; 424 } 425 426 function assignIsOpen(isOpen) { 427 if (isOpenParse && angular.isFunction(isOpenParse.assign)) { 428 isOpenParse.assign(scope, isOpen); 429 } 430 } 431 432 ttScope.contentExp = function() { 433 return ttScope.content; 434 }; 435 436 /** 437 * Observe the relevant attributes. 438 */ 439 attrs.$observe('disabled', function(val) { 440 if (val) { 441 cancelShow(); 442 } 443 444 if (val && ttScope.isOpen) { 445 hide(); 446 } 447 }); 448 449 if (isOpenParse) { 450 scope.$watch(isOpenParse, function(val) { 451 if (ttScope && !val === ttScope.isOpen) { 452 toggleTooltipBind(); 453 } 454 }); 455 } 456 457 function prepObservers() { 458 observers.length = 0; 459 460 if (contentParse) { 461 observers.push( 462 scope.$watch(contentParse, function(val) { 463 ttScope.content = val; 464 if (!val && ttScope.isOpen) { 465 hide(); 466 } 467 }) 468 ); 469 470 observers.push( 471 tooltipLinkedScope.$watch(function() { 472 if (!repositionScheduled) { 473 repositionScheduled = true; 474 tooltipLinkedScope.$$postDigest(function() { 475 repositionScheduled = false; 476 if (ttScope && ttScope.isOpen) { 477 positionTooltip(); 478 } 479 }); 480 } 481 }) 482 ); 483 } else { 484 observers.push( 485 attrs.$observe(ttType, function(val) { 486 ttScope.content = val; 487 if (!val && ttScope.isOpen) { 488 hide(); 489 } else { 490 positionTooltip(); 491 } 492 }) 493 ); 494 } 495 496 observers.push( 497 attrs.$observe(prefix + 'Title', function(val) { 498 ttScope.title = val; 499 if (ttScope.isOpen) { 500 positionTooltip(); 501 } 502 }) 503 ); 504 505 observers.push( 506 attrs.$observe(prefix + 'Placement', function(val) { 507 ttScope.placement = val ? val : options.placement; 508 if (ttScope.isOpen) { 509 positionTooltip(); 510 } 511 }) 512 ); 513 } 514 515 function unregisterObservers() { 516 if (observers.length) { 517 angular.forEach(observers, function(observer) { 518 observer(); 519 }); 520 observers.length = 0; 521 } 522 } 523 524 // hide tooltips/popovers for outsideClick trigger 525 function bodyHideTooltipBind(e) { 526 if (!ttScope || !ttScope.isOpen || !tooltip) { 527 return; 528 } 529 // make sure the tooltip/popover link or tool tooltip/popover itself were not clicked 530 if (!element[0].contains(e.target) && !tooltip[0].contains(e.target)) { 531 hideTooltipBind(); 532 } 533 } 534 535 var unregisterTriggers = function() { 536 triggers.show.forEach(function(trigger) { 537 if (trigger === 'outsideClick') { 538 element.off('click', toggleTooltipBind); 539 } else { 540 element.off(trigger, showTooltipBind); 541 element.off(trigger, toggleTooltipBind); 542 } 543 }); 544 triggers.hide.forEach(function(trigger) { 545 if (trigger === 'outsideClick') { 546 $document.off('click', bodyHideTooltipBind); 547 } else { 548 element.off(trigger, hideTooltipBind); 549 } 550 }); 551 }; 552 553 function prepTriggers() { 554 var val = attrs[prefix + 'Trigger']; 555 unregisterTriggers(); 556 557 triggers = getTriggers(val); 558 559 if (triggers.show !== 'none') { 560 triggers.show.forEach(function(trigger, idx) { 561 if (trigger === 'outsideClick') { 562 element.on('click', toggleTooltipBind); 563 $document.on('click', bodyHideTooltipBind); 564 } else if (trigger === triggers.hide[idx]) { 565 element.on(trigger, toggleTooltipBind); 566 } else if (trigger) { 567 element.on(trigger, showTooltipBind); 568 element.on(triggers.hide[idx], hideTooltipBind); 569 } 570 571 element.on('keypress', function(e) { 572 if (e.which === 27) { 573 hideTooltipBind(); 574 } 575 }); 576 }); 577 } 578 } 579 580 prepTriggers(); 581 582 var animation = scope.$eval(attrs[prefix + 'Animation']); 583 ttScope.animation = angular.isDefined(animation) ? !!animation : options.animation; 584 585 var appendToBodyVal; 586 var appendKey = prefix + 'AppendToBody'; 587 if (appendKey in attrs && attrs[appendKey] === undefined) { 588 appendToBodyVal = true; 589 } else { 590 appendToBodyVal = scope.$eval(attrs[appendKey]); 591 } 592 593 appendToBody = angular.isDefined(appendToBodyVal) ? appendToBodyVal : appendToBody; 594 595 // Make sure tooltip is destroyed and removed. 596 scope.$on('$destroy', function onDestroyTooltip() { 597 unregisterTriggers(); 598 removeTooltip(); 599 openedTooltips.remove(ttScope); 600 ttScope = null; 601 }); 602 }; 603 } 604 }; 605 }; 606 }]; 607}) 608 609// This is mostly ngInclude code but with a custom scope 610.directive('uibTooltipTemplateTransclude', [ 611 '$animate', '$sce', '$compile', '$templateRequest', 612function ($animate, $sce, $compile, $templateRequest) { 613 return { 614 link: function(scope, elem, attrs) { 615 var origScope = scope.$eval(attrs.tooltipTemplateTranscludeScope); 616 617 var changeCounter = 0, 618 currentScope, 619 previousElement, 620 currentElement; 621 622 var cleanupLastIncludeContent = function() { 623 if (previousElement) { 624 previousElement.remove(); 625 previousElement = null; 626 } 627 628 if (currentScope) { 629 currentScope.$destroy(); 630 currentScope = null; 631 } 632 633 if (currentElement) { 634 $animate.leave(currentElement).then(function() { 635 previousElement = null; 636 }); 637 previousElement = currentElement; 638 currentElement = null; 639 } 640 }; 641 642 scope.$watch($sce.parseAsResourceUrl(attrs.uibTooltipTemplateTransclude), function(src) { 643 var thisChangeId = ++changeCounter; 644 645 if (src) { 646 //set the 2nd param to true to ignore the template request error so that the inner 647 //contents and scope can be cleaned up. 648 $templateRequest(src, true).then(function(response) { 649 if (thisChangeId !== changeCounter) { return; } 650 var newScope = origScope.$new(); 651 var template = response; 652 653 var clone = $compile(template)(newScope, function(clone) { 654 cleanupLastIncludeContent(); 655 $animate.enter(clone, elem); 656 }); 657 658 currentScope = newScope; 659 currentElement = clone; 660 661 currentScope.$emit('$includeContentLoaded', src); 662 }, function() { 663 if (thisChangeId === changeCounter) { 664 cleanupLastIncludeContent(); 665 scope.$emit('$includeContentError', src); 666 } 667 }); 668 scope.$emit('$includeContentRequested', src); 669 } else { 670 cleanupLastIncludeContent(); 671 } 672 }); 673 674 scope.$on('$destroy', cleanupLastIncludeContent); 675 } 676 }; 677}]) 678 679/** 680 * Note that it's intentional that these classes are *not* applied through $animate. 681 * They must not be animated as they're expected to be present on the tooltip on 682 * initialization. 683 */ 684.directive('uibTooltipClasses', ['$uibPosition', function($uibPosition) { 685 return { 686 restrict: 'A', 687 link: function(scope, element, attrs) { 688 // need to set the primary position so the 689 // arrow has space during position measure. 690 // tooltip.positionTooltip() 691 if (scope.placement) { 692 // // There are no top-left etc... classes 693 // // in TWBS, so we need the primary position. 694 var position = $uibPosition.parsePlacement(scope.placement); 695 element.addClass(position[0]); 696 } 697 698 if (scope.popupClass) { 699 element.addClass(scope.popupClass); 700 } 701 702 if (scope.animation()) { 703 element.addClass(attrs.tooltipAnimationClass); 704 } 705 } 706 }; 707}]) 708 709.directive('uibTooltipPopup', function() { 710 return { 711 replace: true, 712 scope: { content: '@', placement: '@', popupClass: '@', animation: '&', isOpen: '&' }, 713 templateUrl: 'uib/template/tooltip/tooltip-popup.html' 714 }; 715}) 716 717.directive('uibTooltip', [ '$uibTooltip', function($uibTooltip) { 718 return $uibTooltip('uibTooltip', 'tooltip', 'mouseenter'); 719}]) 720 721.directive('uibTooltipTemplatePopup', function() { 722 return { 723 replace: true, 724 scope: { contentExp: '&', placement: '@', popupClass: '@', animation: '&', isOpen: '&', 725 originScope: '&' }, 726 templateUrl: 'uib/template/tooltip/tooltip-template-popup.html' 727 }; 728}) 729 730.directive('uibTooltipTemplate', ['$uibTooltip', function($uibTooltip) { 731 return $uibTooltip('uibTooltipTemplate', 'tooltip', 'mouseenter', { 732 useContentExp: true 733 }); 734}]) 735 736.directive('uibTooltipHtmlPopup', function() { 737 return { 738 replace: true, 739 scope: { contentExp: '&', placement: '@', popupClass: '@', animation: '&', isOpen: '&' }, 740 templateUrl: 'uib/template/tooltip/tooltip-html-popup.html' 741 }; 742}) 743 744.directive('uibTooltipHtml', ['$uibTooltip', function($uibTooltip) { 745 return $uibTooltip('uibTooltipHtml', 'tooltip', 'mouseenter', { 746 useContentExp: true 747 }); 748}]); 749 750angular.module('ui.bootstrap.position', []) 751 752/** 753 * A set of utility methods for working with the DOM. 754 * It is meant to be used where we need to absolute-position elements in 755 * relation to another element (this is the case for tooltips, popovers, 756 * typeahead suggestions etc.). 757 */ 758 .factory('$uibPosition', ['$document', '$window', function($document, $window) { 759 /** 760 * Used by scrollbarWidth() function to cache scrollbar's width. 761 * Do not access this variable directly, use scrollbarWidth() instead. 762 */ 763 var SCROLLBAR_WIDTH; 764 /** 765 * scrollbar on body and html element in IE and Edge overlay 766 * content and should be considered 0 width. 767 */ 768 var BODY_SCROLLBAR_WIDTH; 769 var OVERFLOW_REGEX = { 770 normal: /(auto|scroll)/, 771 hidden: /(auto|scroll|hidden)/ 772 }; 773 var PLACEMENT_REGEX = { 774 auto: /\s?auto?\s?/i, 775 primary: /^(top|bottom|left|right)$/, 776 secondary: /^(top|bottom|left|right|center)$/, 777 vertical: /^(top|bottom)$/ 778 }; 779 var BODY_REGEX = /(HTML|BODY)/; 780 781 return { 782 783 /** 784 * Provides a raw DOM element from a jQuery/jQLite element. 785 * 786 * @param {element} elem - The element to convert. 787 * 788 * @returns {element} A HTML element. 789 */ 790 getRawNode: function(elem) { 791 return elem.nodeName ? elem : elem[0] || elem; 792 }, 793 794 /** 795 * Provides a parsed number for a style property. Strips 796 * units and casts invalid numbers to 0. 797 * 798 * @param {string} value - The style value to parse. 799 * 800 * @returns {number} A valid number. 801 */ 802 parseStyle: function(value) { 803 value = parseFloat(value); 804 return isFinite(value) ? value : 0; 805 }, 806 807 /** 808 * Provides the closest positioned ancestor. 809 * 810 * @param {element} element - The element to get the offest parent for. 811 * 812 * @returns {element} The closest positioned ancestor. 813 */ 814 offsetParent: function(elem) { 815 elem = this.getRawNode(elem); 816 817 var offsetParent = elem.offsetParent || $document[0].documentElement; 818 819 function isStaticPositioned(el) { 820 return ($window.getComputedStyle(el).position || 'static') === 'static'; 821 } 822 823 while (offsetParent && offsetParent !== $document[0].documentElement && isStaticPositioned(offsetParent)) { 824 offsetParent = offsetParent.offsetParent; 825 } 826 827 return offsetParent || $document[0].documentElement; 828 }, 829 830 /** 831 * Provides the scrollbar width, concept from TWBS measureScrollbar() 832 * function in https://github.com/twbs/bootstrap/blob/master/js/modal.js 833 * In IE and Edge, scollbar on body and html element overlay and should 834 * return a width of 0. 835 * 836 * @returns {number} The width of the browser scollbar. 837 */ 838 scrollbarWidth: function(isBody) { 839 if (isBody) { 840 if (angular.isUndefined(BODY_SCROLLBAR_WIDTH)) { 841 var bodyElem = $document.find('body'); 842 bodyElem.addClass('uib-position-body-scrollbar-measure'); 843 BODY_SCROLLBAR_WIDTH = $window.innerWidth - bodyElem[0].clientWidth; 844 BODY_SCROLLBAR_WIDTH = isFinite(BODY_SCROLLBAR_WIDTH) ? BODY_SCROLLBAR_WIDTH : 0; 845 bodyElem.removeClass('uib-position-body-scrollbar-measure'); 846 } 847 return BODY_SCROLLBAR_WIDTH; 848 } 849 850 if (angular.isUndefined(SCROLLBAR_WIDTH)) { 851 var scrollElem = angular.element('<div class="uib-position-scrollbar-measure"></div>'); 852 $document.find('body').append(scrollElem); 853 SCROLLBAR_WIDTH = scrollElem[0].offsetWidth - scrollElem[0].clientWidth; 854 SCROLLBAR_WIDTH = isFinite(SCROLLBAR_WIDTH) ? SCROLLBAR_WIDTH : 0; 855 scrollElem.remove(); 856 } 857 858 return SCROLLBAR_WIDTH; 859 }, 860 861 /** 862 * Provides the padding required on an element to replace the scrollbar. 863 * 864 * @returns {object} An object with the following properties: 865 * <ul> 866 * <li>**scrollbarWidth**: the width of the scrollbar</li> 867 * <li>**widthOverflow**: whether the the width is overflowing</li> 868 * <li>**right**: the amount of right padding on the element needed to replace the scrollbar</li> 869 * <li>**rightOriginal**: the amount of right padding currently on the element</li> 870 * <li>**heightOverflow**: whether the the height is overflowing</li> 871 * <li>**bottom**: the amount of bottom padding on the element needed to replace the scrollbar</li> 872 * <li>**bottomOriginal**: the amount of bottom padding currently on the element</li> 873 * </ul> 874 */ 875 scrollbarPadding: function(elem) { 876 elem = this.getRawNode(elem); 877 878 var elemStyle = $window.getComputedStyle(elem); 879 var paddingRight = this.parseStyle(elemStyle.paddingRight); 880 var paddingBottom = this.parseStyle(elemStyle.paddingBottom); 881 var scrollParent = this.scrollParent(elem, false, true); 882 var scrollbarWidth = this.scrollbarWidth(scrollParent,
vendor: 18,751 bytes, lines 882-1281
882BODY_REGEX.test(scrollParent.tagName)); 883 884 return { 885 scrollbarWidth: scrollbarWidth, 886 widthOverflow: scrollParent.scrollWidth > scrollParent.clientWidth, 887 right: paddingRight + scrollbarWidth, 888 originalRight: paddingRight, 889 heightOverflow: scrollParent.scrollHeight > scrollParent.clientHeight, 890 bottom: paddingBottom + scrollbarWidth, 891 originalBottom: paddingBottom 892 }; 893 }, 894 895 /** 896 * Checks to see if the element is scrollable. 897 * 898 * @param {element} elem - The element to check. 899 * @param {boolean=} [includeHidden=false] - Should scroll style of 'hidden' be considered, 900 * default is false. 901 * 902 * @returns {boolean} Whether the element is scrollable. 903 */ 904 isScrollable: function(elem, includeHidden) { 905 elem = this.getRawNode(elem); 906 907 var overflowRegex = includeHidden ? OVERFLOW_REGEX.hidden : OVERFLOW_REGEX.normal; 908 var elemStyle = $window.getComputedStyle(elem); 909 return overflowRegex.test(elemStyle.overflow + elemStyle.overflowY + elemStyle.overflowX); 910 }, 911 912 /** 913 * Provides the closest scrollable ancestor. 914 * A port of the jQuery UI scrollParent method: 915 * https://github.com/jquery/jquery-ui/blob/master/ui/scroll-parent.js 916 * 917 * @param {element} elem - The element to find the scroll parent of. 918 * @param {boolean=} [includeHidden=false] - Should scroll style of 'hidden' be considered, 919 * default is false. 920 * @param {boolean=} [includeSelf=false] - Should the element being passed be 921 * included in the scrollable llokup. 922 * 923 * @returns {element} A HTML element. 924 */ 925 scrollParent: function(elem, includeHidden, includeSelf) { 926 elem = this.getRawNode(elem); 927 928 var overflowRegex = includeHidden ? OVERFLOW_REGEX.hidden : OVERFLOW_REGEX.normal; 929 var documentEl = $document[0].documentElement; 930 var elemStyle = $window.getComputedStyle(elem); 931 if (includeSelf && overflowRegex.test(elemStyle.overflow + elemStyle.overflowY + elemStyle.overflowX)) { 932 return elem; 933 } 934 var excludeStatic = elemStyle.position === 'absolute'; 935 var scrollParent = elem.parentElement || documentEl; 936 937 if (scrollParent === documentEl || elemStyle.position === 'fixed') { 938 return documentEl; 939 } 940 941 while (scrollParent.parentElement && scrollParent !== documentEl) { 942 var spStyle = $window.getComputedStyle(scrollParent); 943 if (excludeStatic && spStyle.position !== 'static') { 944 excludeStatic = false; 945 } 946 947 if (!excludeStatic && overflowRegex.test(spStyle.overflow + spStyle.overflowY + spStyle.overflowX)) { 948 break; 949 } 950 scrollParent = scrollParent.parentElement; 951 } 952 953 return scrollParent; 954 }, 955 956 /** 957 * Provides read-only equivalent of jQuery's position function: 958 * http://api.jquery.com/position/ - distance to closest positioned 959 * ancestor. Does not account for margins by default like jQuery position. 960 * 961 * @param {element} elem - The element to caclulate the position on. 962 * @param {boolean=} [includeMargins=false] - Should margins be accounted 963 * for, default is false. 964 * 965 * @returns {object} An object with the following properties: 966 * <ul> 967 * <li>**width**: the width of the element</li> 968 * <li>**height**: the height of the element</li> 969 * <li>**top**: distance to top edge of offset parent</li> 970 * <li>**left**: distance to left edge of offset parent</li> 971 * </ul> 972 */ 973 position: function(elem, includeMagins) { 974 elem = this.getRawNode(elem); 975 976 var elemOffset = this.offset(elem); 977 if (includeMagins) { 978 var elemStyle = $window.getComputedStyle(elem); 979 elemOffset.top -= this.parseStyle(elemStyle.marginTop); 980 elemOffset.left -= this.parseStyle(elemStyle.marginLeft); 981 } 982 var parent = this.offsetParent(elem); 983 var parentOffset = {top: 0, left: 0}; 984 985 if (parent !== $document[0].documentElement) { 986 parentOffset = this.offset(parent); 987 parentOffset.top += parent.clientTop - parent.scrollTop; 988 parentOffset.left += parent.clientLeft - parent.scrollLeft; 989 } 990 991 return { 992 width: Math.round(angular.isNumber(elemOffset.width) ? elemOffset.width : elem.offsetWidth), 993 height: Math.round(angular.isNumber(elemOffset.height) ? elemOffset.height : elem.offsetHeight), 994 top: Math.round(elemOffset.top - parentOffset.top), 995 left: Math.round(elemOffset.left - parentOffset.left) 996 }; 997 }, 998 999 /** 1000 * Provides read-only equivalent of jQuery's offset function: 1001 * http://api.jquery.com/offset/ - distance to viewport. Does 1002 * not account for borders, margins, or padding on the body 1003 * element. 1004 * 1005 * @param {element} elem - The element to calculate the offset on. 1006 * 1007 * @returns {object} An object with the following properties: 1008 * <ul> 1009 * <li>**width**: the width of the element</li> 1010 * <li>**height**: the height of the element</li> 1011 * <li>**top**: distance to top edge of viewport</li> 1012 * <li>**right**: distance to bottom edge of viewport</li> 1013 * </ul> 1014 */ 1015 offset: function(elem) { 1016 elem = this.getRawNode(elem); 1017 1018 var elemBCR = elem.getBoundingClientRect(); 1019 return { 1020 width: Math.round(angular.isNumber(elemBCR.width) ? elemBCR.width : elem.offsetWidth), 1021 height: Math.round(angular.isNumber(elemBCR.height) ? elemBCR.height : elem.offsetHeight), 1022 top: Math.round(elemBCR.top + ($window.pageYOffset || $document[0].documentElement.scrollTop)), 1023 left: Math.round(elemBCR.left + ($window.pageXOffset || $document[0].documentElement.scrollLeft)) 1024 }; 1025 }, 1026 1027 /** 1028 * Provides offset distance to the closest scrollable ancestor 1029 * or viewport. Accounts for border and scrollbar width. 1030 * 1031 * Right and bottom dimensions represent the distance to the 1032 * respective edge of the viewport element. If the element 1033 * edge extends beyond the viewport, a negative value will be 1034 * reported. 1035 * 1036 * @param {element} elem - The element to get the viewport offset for. 1037 * @param {boolean=} [useDocument=false] - Should the viewport be the document element instead 1038 * of the first scrollable element, default is false. 1039 * @param {boolean=} [includePadding=true] - Should the padding on the offset parent element 1040 * be accounted for, default is true. 1041 * 1042 * @returns {object} An object with the following properties: 1043 * <ul> 1044 * <li>**top**: distance to the top content edge of viewport element</li> 1045 * <li>**bottom**: distance to the bottom content edge of viewport element</li> 1046 * <li>**left**: distance to the left content edge of viewport element</li> 1047 * <li>**right**: distance to the right content edge of viewport element</li> 1048 * </ul> 1049 */ 1050 viewportOffset: function(elem, useDocument, includePadding) { 1051 elem = this.getRawNode(elem); 1052 includePadding = includePadding !== false ? true : false; 1053 1054 var elemBCR = elem.getBoundingClientRect(); 1055 var offsetBCR = {top: 0, left: 0, bottom: 0, right: 0}; 1056 1057 var offsetParent = useDocument ? $document[0].documentElement : this.scrollParent(elem); 1058 var offsetParentBCR = offsetParent.getBoundingClientRect(); 1059 1060 offsetBCR.top = offsetParentBCR.top + offsetParent.clientTop; 1061 offsetBCR.left = offsetParentBCR.left + offsetParent.clientLeft; 1062 if (offsetParent === $document[0].documentElement) { 1063 offsetBCR.top += $window.pageYOffset; 1064 offsetBCR.left += $window.pageXOffset; 1065 } 1066 offsetBCR.bottom = offsetBCR.top + offsetParent.clientHeight; 1067 offsetBCR.right = offsetBCR.left + offsetParent.clientWidth; 1068 1069 if (includePadding) { 1070 var offsetParentStyle = $window.getComputedStyle(offsetParent); 1071 offsetBCR.top += this.parseStyle(offsetParentStyle.paddingTop); 1072 offsetBCR.bottom -= this.parseStyle(offsetParentStyle.paddingBottom); 1073 offsetBCR.left += this.parseStyle(offsetParentStyle.paddingLeft); 1074 offsetBCR.right -= this.parseStyle(offsetParentStyle.paddingRight); 1075 } 1076 1077 return { 1078 top: Math.round(elemBCR.top - offsetBCR.top), 1079 bottom: Math.round(offsetBCR.bottom - elemBCR.bottom), 1080 left: Math.round(elemBCR.left - offsetBCR.left), 1081 right: Math.round(offsetBCR.right - elemBCR.right) 1082 }; 1083 }, 1084 1085 /** 1086 * Provides an array of placement values parsed from a placement string. 1087 * Along with the 'auto' indicator, supported placement strings are: 1088 * <ul> 1089 * <li>top: element on top, horizontally centered on host element.</li> 1090 * <li>top-left: element on top, left edge aligned with host element left edge.</li> 1091 * <li>top-right: element on top, lerightft edge aligned with host element right edge.</li> 1092 * <li>bottom: element on bottom, horizontally centered on host element.</li> 1093 * <li>bottom-left: element on bottom, left edge aligned with host element left edge.</li> 1094 * <li>bottom-right: element on bottom, right edge aligned with host element right edge.</li> 1095 * <li>left: element on left, vertically centered on host element.</li> 1096 * <li>left-top: element on left, top edge aligned with host element top edge.</li> 1097 * <li>left-bottom: element on left, bottom edge aligned with host element bottom edge.</li> 1098 * <li>right: element on right, vertically centered on host element.</li> 1099 * <li>right-top: element on right, top edge aligned with host element top edge.</li> 1100 * <li>right-bottom: element on right, bottom edge aligned with host element bottom edge.</li> 1101 * </ul> 1102 * A placement string with an 'auto' indicator is expected to be 1103 * space separated from the placement, i.e: 'auto bottom-left' If 1104 * the primary and secondary placement values do not match 'top, 1105 * bottom, left, right' then 'top' will be the primary placement and 1106 * 'center' will be the secondary placement. If 'auto' is passed, true 1107 * will be returned as the 3rd value of the array. 1108 * 1109 * @param {string} placement - The placement string to parse. 1110 * 1111 * @returns {array} An array with the following values 1112 * <ul> 1113 * <li>**[0]**: The primary placement.</li> 1114 * <li>**[1]**: The secondary placement.</li> 1115 * <li>**[2]**: If auto is passed: true, else undefined.</li> 1116 * </ul> 1117 */ 1118 parsePlacement: function(placement) { 1119 var autoPlace = PLACEMENT_REGEX.auto.test(placement); 1120 if (autoPlace) { 1121 placement = placement.replace(PLACEMENT_REGEX.auto, ''); 1122 } 1123 1124 placement = placement.split('-'); 1125 1126 placement[0] = placement[0] || 'top'; 1127 if (!PLACEMENT_REGEX.primary.test(placement[0])) { 1128 placement[0] = 'top'; 1129 } 1130 1131 placement[1] = placement[1] || 'center'; 1132 if (!PLACEMENT_REGEX.secondary.test(placement[1])) { 1133 placement[1] = 'center'; 1134 } 1135 1136 if (autoPlace) { 1137 placement[2] = true; 1138 } else { 1139 placement[2] = false; 1140 } 1141 1142 return placement; 1143 }, 1144 1145 /** 1146 * Provides coordinates for an element to be positioned relative to 1147 * another element. Passing 'auto' as part of the placement parameter 1148 * will enable smart placement - where the element fits. i.e: 1149 * 'auto left-top' will check to see if there is enough space to the left 1150 * of the hostElem to fit the targetElem, if not place right (same for secondary 1151 * top placement). Available space is calculated using the viewportOffset 1152 * function. 1153 * 1154 * @param {element} hostElem - The element to position against. 1155 * @param {element} targetElem - The element to position. 1156 * @param {string=} [placement=top] - The placement for the targetElem, 1157 * default is 'top'. 'center' is assumed as secondary placement for 1158 * 'top', 'left', 'right', and 'bottom' placements. Available placements are: 1159 * <ul> 1160 * <li>top</li> 1161 * <li>top-right</li> 1162 * <li>top-left</li> 1163 * <li>bottom</li> 1164 * <li>bottom-left</li> 1165 * <li>bottom-right</li> 1166 * <li>left</li> 1167 * <li>left-top</li> 1168 * <li>left-bottom</li> 1169 * <li>right</li> 1170 * <li>right-top</li> 1171 * <li>right-bottom</li> 1172 * </ul> 1173 * @param {boolean=} [appendToBody=false] - Should the top and left values returned 1174 * be calculated from the body element, default is false. 1175 * 1176 * @returns {object} An object with the following properties: 1177 * <ul> 1178 * <li>**top**: Value for targetElem top.</li> 1179 * <li>**left**: Value for targetElem left.</li> 1180 * <li>**placement**: The resolved placement.</li> 1181 * </ul> 1182 */ 1183 positionElements: function(hostElem, targetElem, placement, appendToBody) { 1184 hostElem = this.getRawNode(hostElem); 1185 targetElem = this.getRawNode(targetElem); 1186 1187 // need to read from prop to support tests. 1188 var targetWidth = angular.isDefined(targetElem.offsetWidth) ? targetElem.offsetWidth : targetElem.prop('offsetWidth'); 1189 var targetHeight = angular.isDefined(targetElem.offsetHeight) ? targetElem.offsetHeight : targetElem.prop('offsetHeight'); 1190 1191 placement = this.parsePlacement(placement); 1192 1193 var hostElemPos = appendToBody ? this.offset(hostElem) : this.position(hostElem); 1194 var targetElemPos = {top: 0, left: 0, placement: ''}; 1195 1196 if (placement[2]) { 1197 var viewportOffset = this.viewportOffset(hostElem, appendToBody); 1198 1199 var targetElemStyle = $window.getComputedStyle(targetElem); 1200 var adjustedSize = { 1201 width: targetWidth + Math.round(Math.abs(this.parseStyle(targetElemStyle.marginLeft) + this.parseStyle(targetElemStyle.marginRight))), 1202 height: targetHeight + Math.round(Math.abs(this.parseStyle(targetElemStyle.marginTop) + this.parseStyle(targetElemStyle.marginBottom))) 1203 }; 1204 1205 placement[0] = placement[0] === 'top' && adjustedSize.height > viewportOffset.top && adjustedSize.height <= viewportOffset.bottom ? 'bottom' : 1206 placement[0] === 'bottom' && adjustedSize.height > viewportOffset.bottom && adjustedSize.height <= viewportOffset.top ? 'top' : 1207 placement[0] === 'left' && adjustedSize.width > viewportOffset.left && adjustedSize.width <= viewportOffset.right ? 'right' : 1208 placement[0] === 'right' && adjustedSize.width > viewportOffset.right && adjustedSize.width <= viewportOffset.left ? 'left' : 1209 placement[0]; 1210 1211 placement[1] = placement[1] === 'top' && adjustedSize.height - hostElemPos.height > viewportOffset.bottom && adjustedSize.height - hostElemPos.height <= viewportOffset.top ? 'bottom' : 1212 placement[1] === 'bottom' && adjustedSize.height - hostElemPos.height > viewportOffset.top && adjustedSize.height - hostElemPos.height <= viewportOffset.bottom ? 'top' : 1213 placement[1] === 'left' && adjustedSize.width - hostElemPos.width > viewportOffset.right && adjustedSize.width - hostElemPos.width <= viewportOffset.left ? 'right' : 1214 placement[1] === 'right' && adjustedSize.width - hostElemPos.width > viewportOffset.left && adjustedSize.width - hostElemPos.width <= viewportOffset.right ? 'left' : 1215 placement[1]; 1216 1217 if (placement[1] === 'center') { 1218 if (PLACEMENT_REGEX.vertical.test(placement[0])) { 1219 var xOverflow = hostElemPos.width / 2 - targetWidth / 2; 1220 if (viewportOffset.left + xOverflow < 0 && adjustedSize.width - hostElemPos.width <= viewportOffset.right) { 1221 placement[1] = 'left'; 1222 } else if (viewportOffset.right + xOverflow < 0 && adjustedSize.width - hostElemPos.width <= viewportOffset.left) { 1223 placement[1] = 'right'; 1224 } 1225 } else { 1226 var yOverflow = hostElemPos.height / 2 - adjustedSize.height / 2; 1227 if (viewportOffset.top + yOverflow < 0 && adjustedSize.height - hostElemPos.height <= viewportOffset.bottom) { 1228 placement[1] = 'top'; 1229 } else if (viewportOffset.bottom + yOverflow < 0 && adjustedSize.height - hostElemPos.height <= viewportOffset.top) { 1230 placement[1] = 'bottom'; 1231 } 1232 } 1233 } 1234 } 1235 1236 switch (placement[0]) { 1237 case 'top': 1238 targetElemPos.top = hostElemPos.top - targetHeight; 1239 break; 1240 case 'bottom': 1241 targetElemPos.top = hostElemPos.top + hostElemPos.height; 1242 break; 1243 case 'left': 1244 targetElemPos.left = hostElemPos.left - targetWidth; 1245 break; 1246 case 'right': 1247 targetElemPos.left = hostElemPos.left + hostElemPos.width; 1248 break; 1249 } 1250 1251 switch (placement[1]) { 1252 case 'top': 1253 targetElemPos.top = hostElemPos.top; 1254 break; 1255 case 'bottom': 1256 targetElemPos.top = hostElemPos.top + hostElemPos.height - targetHeight; 1257 break; 1258 case 'left': 1259 targetElemPos.left = hostElemPos.left; 1260 break; 1261 case 'right': 1262 targetElemPos.left = hostElemPos.left + hostElemPos.width - targetWidth; 1263 break; 1264 case 'center': 1265 if (PLACEMENT_REGEX.vertical.test(placement[0])) { 1266 targetElemPos.left = hostElemPos.left + hostElemPos.width / 2 - targetWidth / 2; 1267 } else { 1268 targetElemPos.top = hostElemPos.top + hostElemPos.height / 2 - targetHeight / 2; 1269 } 1270 break; 1271 } 1272 1273 targetElemPos.top = Math.round(targetElemPos.top); 1274 targetElemPos.left = Math.round(targetElemPos.left); 1275 targetElemPos.placement = placement[1] === 'center' ? placement[0] : placement[0] + '-' + placement[1]; 1276 1277 return targetElemPos; 1278 }, 1279 1280 /** 1281
vendor: 7,414 bytes, lines 1281-1405
1281* Provides a way for positioning tooltip & dropdown 1282 * arrows when using placement options beyond the standard 1283 * left, right, top, or bottom. 1284 * 1285 * @param {element} elem - The tooltip/dropdown element. 1286 * @param {string} placement - The placement for the elem. 1287 */ 1288 positionArrow: function(elem, placement) { 1289 elem = this.getRawNode(elem); 1290 1291 var innerElem = elem.querySelector('.tooltip-inner, .popover-inner'); 1292 if (!innerElem) { 1293 return; 1294 } 1295 1296 var isTooltip = angular.element(innerElem).hasClass('tooltip-inner'); 1297 1298 var arrowElem = isTooltip ? elem.querySelector('.tooltip-arrow') : elem.querySelector('.arrow'); 1299 if (!arrowElem) { 1300 return; 1301 } 1302 1303 var arrowCss = { 1304 top: '', 1305 bottom: '', 1306 left: '', 1307 right: '' 1308 }; 1309 1310 placement = this.parsePlacement(placement); 1311 if (placement[1] === 'center') { 1312 // no adjustment necessary - just reset styles 1313 angular.element(arrowElem).css(arrowCss); 1314 return; 1315 } 1316 1317 var borderProp = 'border-' + placement[0] + '-width'; 1318 var borderWidth = $window.getComputedStyle(arrowElem)[borderProp]; 1319 1320 var borderRadiusProp = 'border-'; 1321 if (PLACEMENT_REGEX.vertical.test(placement[0])) { 1322 borderRadiusProp += placement[0] + '-' + placement[1]; 1323 } else { 1324 borderRadiusProp += placement[1] + '-' + placement[0]; 1325 } 1326 borderRadiusProp += '-radius'; 1327 var borderRadius = $window.getComputedStyle(isTooltip ? innerElem : elem)[borderRadiusProp]; 1328 1329 switch (placement[0]) { 1330 case 'top': 1331 arrowCss.bottom = isTooltip ? '0' : '-' + borderWidth; 1332 break; 1333 case 'bottom': 1334 arrowCss.top = isTooltip ? '0' : '-' + borderWidth; 1335 break; 1336 case 'left': 1337 arrowCss.right = isTooltip ? '0' : '-' + borderWidth; 1338 break; 1339 case 'right': 1340 arrowCss.left = isTooltip ? '0' : '-' + borderWidth; 1341 break; 1342 } 1343 1344 arrowCss[placement[1]] = borderRadius; 1345 1346 angular.element(arrowElem).css(arrowCss); 1347 } 1348 }; 1349 }]); 1350 1351angular.module('ui.bootstrap.stackedMap', []) 1352/** 1353 * A helper, internal data structure that acts as a map but also allows getting / removing 1354 * elements in the LIFO order 1355 */ 1356 .factory('$$stackedMap', function() { 1357 return { 1358 createNew: function() { 1359 var stack = []; 1360 1361 return { 1362 add: function(key, value) { 1363 stack.push({ 1364 key: key, 1365 value: value 1366 }); 1367 }, 1368 get: function(key) { 1369 for (var i = 0; i < stack.length; i++) { 1370 if (key === stack[i].key) { 1371 return stack[i]; 1372 } 1373 } 1374 }, 1375 keys: function() { 1376 var keys = []; 1377 for (var i = 0; i < stack.length; i++) { 1378 keys.push(stack[i].key); 1379 } 1380 return keys; 1381 }, 1382 top: function() { 1383 return stack[stack.length - 1]; 1384 }, 1385 remove: function(key) { 1386 var idx = -1; 1387 for (var i = 0; i < stack.length; i++) { 1388 if (key === stack[i].key) { 1389 idx = i; 1390 break; 1391 } 1392 } 1393 return stack.splice(idx, 1)[0]; 1394 }, 1395 removeTop: function() { 1396 return stack.splice(stack.length - 1, 1)[0]; 1397 }, 1398 length: function() { 1399 return stack.length; 1400 } 1401 }; 1402 } 1403 }; 1404 });angular.module('ui.bootstrap.tooltip').run(function() {!angular.$$csp().noInlineStyle && !angular.$$uibTooltipCss && angular.element(document).find('head').prepend('<style type="text/css">[uib-tooltip-popup].tooltip.top-left > .tooltip-arrow,[uib-tooltip-popup].tooltip.top-right > .tooltip-arrow,[uib-tooltip-popup].tooltip.bottom-left > .tooltip-arrow,[uib-tooltip-popup].tooltip.bottom-right > .tooltip-arrow,[uib-tooltip-popup].tooltip.left-top > .tooltip-arrow,[uib-tooltip-popup].tooltip.left-bottom > .tooltip-arrow,[uib-tooltip-popup].tooltip.right-top > .tooltip-arrow,[uib-tooltip-popup].tooltip.right-bottom > .tooltip-arrow,[uib-tooltip-html-popup].tooltip.top-left > .tooltip-arrow,[uib-tooltip-html-popup].tooltip.top-right > .tooltip-arrow,[uib-tooltip-html-popup].tooltip.bottom-left > .tooltip-arrow,[uib-tooltip-html-popup].tooltip.bottom-right > .tooltip-arrow,[uib-tooltip-html-popup].tooltip.left-top > .tooltip-arrow,[uib-tooltip-html-popup].tooltip.left-bottom > .tooltip-arrow,[uib-tooltip-html-popup].tooltip.right-top > .tooltip-arrow,[uib-tooltip-html-popup].tooltip.right-bottom > .tooltip-arrow,[uib-tooltip-template-popup].tooltip.top-left > .tooltip-arrow,[uib-tooltip-template-popup].tooltip.top-right > .tooltip-arrow,[uib-tooltip-template-popup].tooltip.bottom-left > .tooltip-arrow,[uib-tooltip-template-popup].tooltip.bottom-right > .tooltip-arrow,[uib-tooltip-template-popup].tooltip.left-top > .tooltip-arrow,[uib-tooltip-template-popup].tooltip.left-bottom > .tooltip-arrow,[uib-tooltip-template-popup].tooltip.right-top > .tooltip-arrow,[uib-tooltip-template-popup].tooltip.right-bottom > .tooltip-arrow,[uib-popover-popup].popover.top-left > .arrow,[uib-popover-popup].popover.top-right > .arrow,[uib-popover-popup].popover.bottom-left > .arrow,[uib-popover-popup].popover.bottom-right > .arrow,[uib-popover-popup].popover.left-top > .arrow,[uib-popover-popup].popover.left-bottom > .arrow,[uib-popover-popup].popover.right-top > .arrow,[uib-popover-popup].popover.right-bottom > .arrow,[uib-popover-html-popup].popover.top-left > .arrow,[uib-popover-html-popup].popover.top-right > .arrow,[uib-popover-html-popup].popover.bottom-left > .arrow,[uib-popover-html-popup].popover.bottom-right > .arrow,[uib-popover-html-popup].popover.left-top > .arrow,[uib-popover-html-popup].popover.left-bottom > .arrow,[uib-popover-html-popup].popover.right-top > .arrow,[uib-popover-html-popup].popover.right-bottom > .arrow,[uib-popover-template-popup].popover.top-left > .arrow,[uib-popover-template-popup].popover.top-right > .arrow,[uib-popover-template-popup].popover.bottom-left > .arrow,[uib-popover-template-popup].popover.bottom-right > .arrow,[uib-popover-template-popup].popover.left-top > .arrow,[uib-popover-template-popup].popover.left-bottom > .arrow,[uib-popover-template-popup].popover.right-top > .arrow,[uib-popover-template-popup].popover.right-bottom > .arrow{top:auto;bottom:auto;left:auto;right:auto;margin:0;}[uib-popover-popup].popover,[uib-popover-html-popup].popover,[uib-popover-template-popup].popover{display:block !important;}</style>'); angular.$$uibTooltipCss = true; }); 1405angular.module('ui.bootstrap.position').run(function() {!angular.$$csp().noInlineStyle && !angular.$$uibPositionCss && angular.element(document).find('head').prepend('<style type="text/css">.uib-position-measure{display:block !important;visibility:hidden !important;position:absolute !important;top:-9999px !important;left:-9999px !important;}.uib-position-scrollbar-measure{position:absolute !important;top:-9999px !important;width:50px !important;height:50px !important;overflow:scroll !important;}.uib-position-body-scrollbar-measure{overflow:scroll !important;}</style>'); angular.$$uibPositionCss = true; });
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.