/* * angular-ui-bootstrap * http://angular-ui.github.io/bootstrap/ * Version: 0.10.0 - 2014-02-10 * License: MIT */ angular.module("ui.bootstrap", ["ui.bootstrap.tpls", "ui.bootstrap.transition","ui.bootstrap.collapse","ui.bootstrap.dropdownToggle","ui.bootstrap.modal","ui.bootstrap.position","ui.bootstrap.bindHtml","ui.bootstrap.tooltip"]); angular.module("ui.bootstrap.tpls", ["template/modal/backdrop.html","template/modal/window.html","template/tooltip/tooltip-html-unsafe-popup.html","template/tooltip/tooltip-popup.html"]); angular.module('ui.bootstrap.transition', []) /** * $transition service provides a consistent interface to trigger CSS 3 transitions and to be informed when they complete. * @param {DOMElement} element The DOMElement that will be animated. * @param {string|object|function} trigger The thing that will cause the transition to start: * - As a string, it represents the css class to be added to the element. * - As an object, it represents a hash of style attributes to be applied to the element. * - As a function, it represents a function to be called that will cause the transition to occur. * @return {Promise} A promise that is resolved when the transition finishes. */ .factory('$transition', ['$q', '$timeout', '$rootScope', function($q, $timeout, $rootScope) { var $transition = function(element, trigger, options) { options = options || {}; var deferred = $q.defer(); var endEventName = $transition[options.animation ? "animationEndEventName" : "transitionEndEventName"]; var transitionEndHandler = function(event) { $rootScope.$apply(function() { element.unbind(endEventName, transitionEndHandler); deferred.resolve(element); }); }; if (endEventName) { element.bind(endEventName, transitionEndHandler); } // Wrap in a timeout to allow the browser time to update the DOM before the transition is to occur $timeout(function() { if ( angular.isString(trigger) ) { element.addClass(trigger); } else if ( angular.isFunction(trigger) ) { trigger(element); } else if ( angular.isObject(trigger) ) { element.css(trigger); } //If browser does not support transitions, instantly resolve if ( !endEventName ) { deferred.resolve(element); } }); // Add our custom cancel function to the promise that is returned // We can call this if we are about to run a new transition, which we know will prevent this transition from ending, // i.e. it will therefore never raise a transitionEnd event for that transition deferred.promise.cancel = function() { if ( endEventName ) { element.unbind(endEventName, transitionEndHandler); } deferred.reject('Transition cancelled'); }; return deferred.promise; }; // Work out the name of the transitionEnd event var transElement = document.createElement('trans'); var transitionEndEventNames = { 'WebkitTransition': 'webkitTransitionEnd', 'MozTransition': 'transitionend', 'OTransition': 'oTransitionEnd', 'transition': 'transitionend' }; var animationEndEventNames = { 'WebkitTransition': 'webkitAnimationEnd', 'MozTransition': 'animationend', 'OTransition': 'oAnimationEnd', 'transition': 'animationend' }; function findEndEventName(endEventNames) { for (var name in endEventNames){ if (transElement.style[name] !== undefined) { return endEventNames[name]; } } } $transition.transitionEndEventName = findEndEventName(transitionEndEventNames); $transition.animationEndEventName = findEndEventName(animationEndEventNames); return $transition; }]); angular.module('ui.bootstrap.collapse', ['ui.bootstrap.transition']) .directive('collapse', ['$transition', function ($transition, $timeout) { return { link: function (scope, element, attrs) { var initialAnimSkip = true; var currentTransition; function doTransition(change) { var newTransition = $transition(element, change); if (currentTransition) { currentTransition.cancel(); } currentTransition = newTransition; newTransition.then(newTransitionDone, newTransitionDone); return newTransition; function newTransitionDone() { // Make sure it's this transition, otherwise, leave it alone. if (currentTransition === newTransition) { currentTransition = undefined; } } } function expand() { if (initialAnimSkip) { initialAnimSkip = false; expandDone(); } else { element.removeClass('collapse').addClass('collapsing'); doTransition({ height: element[0].scrollHeight + 'px' }).then(expandDone); } } function expandDone() { element.removeClass('collapsing'); element.addClass('collapse in'); element.css({height: 'auto'}); } function collapse() { if (initialAnimSkip) { initialAnimSkip = false; collapseDone(); element.css({height: 0}); } else { // CSS transitions don't work with height: auto, so we have to manually change the height to a specific value element.css({ height: element[0].scrollHeight + 'px' }); //trigger reflow so a browser realizes that height was updated from auto to a specific value var x = element[0].offsetWidth; element.removeClass('collapse in').addClass('collapsing'); doTransition({ height: 0 }).then(collapseDone); } } function collapseDone() { element.removeClass('collapsing'); element.addClass('collapse'); } scope.$watch(attrs.collapse, function (shouldCollapse) { if (shouldCollapse) { collapse(); } else { expand(); } }); } }; }]); /* * dropdownToggle - Provides dropdown menu functionality in place of bootstrap js * @restrict class or attribute * @example: */ angular.module('ui.bootstrap.dropdownToggle', []).directive('dropdownToggle', ['$document', '$location', function ($document, $location) { var openElement = null, closeMenu = angular.noop; return { restrict: 'CA', link: function(scope, element, attrs) { scope.$watch('$location.path', function() { closeMenu(); }); element.parent().bind('click', function() { closeMenu(); }); element.bind('click', function (event) { var elementWasOpen = (element === openElement); event.preventDefault(); event.stopPropagation(); if (!!openElement) { closeMenu(); } if (!elementWasOpen && !element.hasClass('disabled') && !element.prop('disabled')) { element.parent().addClass('open'); openElement = element; closeMenu = function (event) { if (event) { event.preventDefault(); event.stopPropagation(); } $document.unbind('click', closeMenu); element.parent().removeClass('open'); closeMenu = angular.noop; openElement = null; }; $document.bind('click', closeMenu); } }); } }; }]); angular.module('ui.bootstrap.modal', ['ui.bootstrap.transition']) /** * A helper, internal data structure that acts as a map but also allows getting / removing * elements in the LIFO order */ .factory('$$stackedMap', function () { return { createNew: function () { var stack = []; return { add: function (key, value) { stack.push({ key: key, value: value }); }, get: function (key) { for (var i = 0; i < stack.length; i++) { if (key == stack[i].key) { return stack[i]; } } }, keys: function() { var keys = []; for (var i = 0; i < stack.length; i++) { keys.push(stack[i].key); } return keys; }, top: function () { return stack[stack.length - 1]; }, remove: function (key) { var idx = -1; for (var i = 0; i < stack.length; i++) { if (key == stack[i].key) { idx = i; break; } } return stack.splice(idx, 1)[0]; }, removeTop: function () { return stack.splice(stack.length - 1, 1)[0]; }, length: function () { return stack.length; } }; } }; }) /** * A helper directive for the $modal service. It creates a backdrop element. */ .directive('modalBackdrop', ['$timeout', function ($timeout) { return { restrict: 'EA', replace: true, templateUrl: 'template/modal/backdrop.html', link: function (scope) { scope.animate = false; //trigger CSS transitions $timeout(function () { scope.animate = true; }); } }; }]) .directive('modalWindow', ['$modalStack', '$timeout', function ($modalStack, $timeout) { return { restrict: 'EA', scope: { index: '@', animate: '=' }, replace: true, transclude: true, templateUrl: 'template/modal/window.html', link: function (scope, element, attrs) { scope.windowClass = attrs.windowClass || ''; $timeout(function () { // trigger CSS transitions scope.animate = true; // focus a freshly-opened modal element[0].focus(); }); scope.close = function (evt) { var modal = $modalStack.getTop(); if (modal && modal.value.backdrop && modal.value.backdrop != 'static' && (evt.target === evt.currentTarget)) { evt.preventDefault(); evt.stopPropagation(); $modalStack.dismiss(modal.key, 'backdrop click'); } }; } }; }]) .factory('$modalStack', ['$transition', '$timeout', '$document', '$compile', '$rootScope', '$$stackedMap', function ($transition, $timeout, $document, $compile, $rootScope, $$stackedMap) { var OPENED_MODAL_CLASS = 'modal-open'; var backdropDomEl, backdropScope; var openedWindows = $$stackedMap.createNew(); var $modalStack = {}; function backdropIndex() { var topBackdropIndex = -1; var opened = openedWindows.keys(); for (var i = 0; i < opened.length; i++) { if (openedWindows.get(opened[i]).value.backdrop) { topBackdropIndex = i; } } return topBackdropIndex; } $rootScope.$watch(backdropIndex, function(newBackdropIndex){ if (backdropScope) { backdropScope.index = newBackdropIndex; } }); function removeModalWindow(modalInstance) { var body = $document.find('body').eq(0); var modalWindow = openedWindows.get(modalInstance).value; //clean up the stack openedWindows.remove(modalInstance); //remove window DOM element removeAfterAnimate(modalWindow.modalDomEl, modalWindow.modalScope, 300, checkRemoveBackdrop); body.toggleClass(OPENED_MODAL_CLASS, openedWindows.length() > 0); } function checkRemoveBackdrop() { //remove backdrop if no longer needed if (backdropDomEl && backdropIndex() == -1) { var backdropScopeRef = backdropScope; removeAfterAnimate(backdropDomEl, backdropScope, 150, function () { backdropScopeRef.$destroy(); backdropScopeRef = null; }); backdropDomEl = undefined; backdropScope = undefined; } } function removeAfterAnimate(domEl, scope, emulateTime, done) { // Closing animation scope.animate = false; var transitionEndEventName = $transition.transitionEndEventName; if (transitionEndEventName) { // transition out var timeout = $timeout(afterAnimating, emulateTime); domEl.bind(transitionEndEventName, function () { $timeout.cancel(timeout); afterAnimating(); scope.$apply(); }); } else { // Ensure this call is async $timeout(afterAnimating, 0); } function afterAnimating() { if (afterAnimating.done) { return; } afterAnimating.done = true; domEl.remove(); if (done) { done(); } } } $document.bind('keydown', function (evt) { var modal; if (evt.which === 27) { modal = openedWindows.top(); if (modal && modal.value.keyboard) { $rootScope.$apply(function () { $modalStack.dismiss(modal.key); }); } } }); $modalStack.open = function (modalInstance, modal) { openedWindows.add(modalInstance, { deferred: modal.deferred, modalScope: modal.scope, backdrop: modal.backdrop, keyboard: modal.keyboard }); var body = $document.find('body').eq(0), currBackdropIndex = backdropIndex(); if (currBackdropIndex >= 0 && !backdropDomEl) { backdropScope = $rootScope.$new(true); backdropScope.index = currBackdropIndex; backdropDomEl = $compile('
')(backdropScope); body.append(backdropDomEl); } var angularDomEl = angular.element('
'); angularDomEl.attr('window-class', modal.windowClass); angularDomEl.attr('index', openedWindows.length() - 1); angularDomEl.attr('animate', 'animate'); angularDomEl.html(modal.content); var modalDomEl = $compile(angularDomEl)(modal.scope); openedWindows.top().value.modalDomEl = modalDomEl; body.append(modalDomEl); body.addClass(OPENED_MODAL_CLASS); }; $modalStack.close = function (modalInstance, result) { var modalWindow = openedWindows.get(modalInstance).value; if (modalWindow) { modalWindow.deferred.resolve(result); removeModalWindow(modalInstance); } }; $modalStack.dismiss = function (modalInstance, reason) { var modalWindow = openedWindows.get(modalInstance).value; if (modalWindow) { modalWindow.deferred.reject(reason); removeModalWindow(modalInstance); } }; $modalStack.dismissAll = function (reason) { var topModal = this.getTop(); while (topModal) { this.dismiss(topModal.key, reason); topModal = this.getTop(); } }; $modalStack.getTop = function () { return openedWindows.top(); }; return $modalStack; }]) .provider('$modal', function () { var $modalProvider = { options: { backdrop: true, //can be also false or 'static' keyboard: true }, $get: ['$injector', '$rootScope', '$q', '$http', '$templateCache', '$controller', '$modalStack', function ($injector, $rootScope, $q, $http, $templateCache, $controller, $modalStack) { var $modal = {}; function getTemplatePromise(options) { return options.template ? $q.when(options.template) : $http.get(options.templateUrl, {cache: $templateCache}).then(function (result) { return result.data; }); } function getResolvePromises(resolves) { var promisesArr = []; angular.forEach(resolves, function (value, key) { if (angular.isFunction(value) || angular.isArray(value)) { promisesArr.push($q.when($injector.invoke(value))); } }); return promisesArr; } $modal.open = function (modalOptions) { var modalResultDeferred = $q.defer(); var modalOpenedDeferred = $q.defer(); //prepare an instance of a modal to be injected into controllers and returned to a caller var modalInstance = { result: modalResultDeferred.promise, opened: modalOpenedDeferred.promise, close: function (result) { $modalStack.close(modalInstance, result); }, dismiss: function (reason) { $modalStack.dismiss(modalInstance, reason); } }; //merge and clean up options modalOptions = angular.extend({}, $modalProvider.options, modalOptions); modalOptions.resolve = modalOptions.resolve || {}; //verify options if (!modalOptions.template && !modalOptions.templateUrl) { throw new Error('One of template or templateUrl options is required.'); } var templateAndResolvePromise = $q.all([getTemplatePromise(modalOptions)].concat(getResolvePromises(modalOptions.resolve))); templateAndResolvePromise.then(function resolveSuccess(tplAndVars) { var modalScope = (modalOptions.scope || $rootScope).$new(); modalScope.$close = modalInstance.close; modalScope.$dismiss = modalInstance.dismiss; var ctrlInstance, ctrlLocals = {}; var resolveIter = 1; //controllers if (modalOptions.controller) { ctrlLocals.$scope = modalScope; ctrlLocals.$modalInstance = modalInstance; angular.forEach(modalOptions.resolve, function (value, key) { ctrlLocals[key] = tplAndVars[resolveIter++]; }); ctrlInstance = $controller(modalOptions.controller, ctrlLocals); } $modalStack.open(modalInstance, { scope: modalScope, deferred: modalResultDeferred, content: tplAndVars[0], backdrop: modalOptions.backdrop, keyboard: modalOptions.keyboard, windowClass: modalOptions.windowClass }); }, function resolveError(reason) { modalResultDeferred.reject(reason); }); templateAndResolvePromise.then(function () { modalOpenedDeferred.resolve(true); }, function () { modalOpenedDeferred.reject(false); }); return modalInstance; }; return $modal; }] }; return $modalProvider; }); angular.module('ui.bootstrap.position', []) /** * A set of utility methods that can be use to retrieve position of DOM elements. * It is meant to be used where we need to absolute-position DOM elements in * relation to other, existing elements (this is the case for tooltips, popovers, * typeahead suggestions etc.). */ .factory('$position', ['$document', '$window', function ($document, $window) { function getStyle(el, cssprop) { if (el.currentStyle) { //IE return el.currentStyle[cssprop]; } else if ($window.getComputedStyle) { return $window.getComputedStyle(el)[cssprop]; } // finally try and get inline style return el.style[cssprop]; } /** * Checks if a given element is statically positioned * @param element - raw DOM element */ function isStaticPositioned(element) { return (getStyle(element, "position") || 'static' ) === 'static'; } /** * returns the closest, non-statically positioned parentOffset of a given element * @param element */ var parentOffsetEl = function (element) { var docDomEl = $document[0]; var offsetParent = element.offsetParent || docDomEl; while (offsetParent && offsetParent !== docDomEl && isStaticPositioned(offsetParent) ) { offsetParent = offsetParent.offsetParent; } return offsetParent || docDomEl; }; return { /** * Provides read-only equivalent of jQuery's position function: * http://api.jquery.com/position/ */ position: function (element) { var elBCR = this.offset(element); var offsetParentBCR = { top: 0, left: 0 }; var offsetParentEl = parentOffsetEl(element[0]); if (offsetParentEl != $document[0]) { offsetParentBCR = this.offset(angular.element(offsetParentEl)); offsetParentBCR.top += offsetParentEl.clientTop - offsetParentEl.scrollTop; offsetParentBCR.left += offsetParentEl.clientLeft - offsetParentEl.scrollLeft; } var boundingClientRect = element[0].getBoundingClientRect(); return { width: boundingClientRect.width || element.prop('offsetWidth'), height: boundingClientRect.height || element.prop('offsetHeight'), top: elBCR.top - offsetParentBCR.top, left: elBCR.left - offsetParentBCR.left }; }, /** * Provides read-only equivalent of jQuery's offset function: * http://api.jquery.com/offset/ */ offset: function (element) { var boundingClientRect = element[0].getBoundingClientRect(); return { width: boundingClientRect.width || element.prop('offsetWidth'), height: boundingClientRect.height || element.prop('offsetHeight'), top: boundingClientRect.top + ($window.pageYOffset || $document[0].body.scrollTop || $document[0].documentElement.scrollTop), left: boundingClientRect.left + ($window.pageXOffset || $document[0].body.scrollLeft || $document[0].documentElement.scrollLeft) }; } }; }]); angular.module('ui.bootstrap.bindHtml', []) .directive('bindHtmlUnsafe', function () { return function (scope, element, attr) { element.addClass('ng-binding').data('$binding', attr.bindHtmlUnsafe); scope.$watch(attr.bindHtmlUnsafe, function bindHtmlUnsafeWatchAction(value) { element.html(value || ''); }); }; }); /** * The following features are still outstanding: animation as a * function, placement as a function, inside, support for more triggers than * just mouse enter/leave, html tooltips, and selector delegation. */ angular.module( 'ui.bootstrap.tooltip', [ 'ui.bootstrap.position', 'ui.bootstrap.bindHtml' ] ) /** * The $tooltip service creates tooltip- and popover-like directives as well as * houses global options for them. */ .provider( '$tooltip', function () { // The default options tooltip and popover. var defaultOptions = { placement: 'top', animation: true, popupDelay: 0 }; // Default hide triggers for each show trigger var triggerMap = { 'mouseenter': 'mouseleave', 'click': 'click', 'focus': 'blur' }; // The options specified to the provider globally. var globalOptions = {}; /** * `options({})` allows global configuration of all tooltips in the * application. * * var app = angular.module( 'App', ['ui.bootstrap.tooltip'], function( $tooltipProvider ) { * // place tooltips left instead of top by default * $tooltipProvider.options( { placement: 'left' } ); * }); */ this.options = function( value ) { angular.extend( globalOptions, value ); }; /** * This allows you to extend the set of trigger mappings available. E.g.: * * $tooltipProvider.setTriggers( 'openTrigger': 'closeTrigger' ); */ this.setTriggers = function setTriggers ( triggers ) { angular.extend( triggerMap, triggers ); }; /** * This is a helper function for translating camel-case to snake-case. */ function snake_case(name){ var regexp = /[A-Z]/g; var separator = '-'; return name.replace(regexp, function(letter, pos) { return (pos ? separator : '') + letter.toLowerCase(); }); } /** * Returns the actual instance of the $tooltip service. * TODO support multiple triggers */ this.$get = [ '$window', '$compile', '$timeout', '$parse', '$document', '$position', '$interpolate', function ( $window, $compile, $timeout, $parse, $document, $position, $interpolate ) { return function $tooltip ( type, prefix, defaultTriggerShow ) { var options = angular.extend( {}, defaultOptions, globalOptions ); /** * Returns an object of show and hide triggers. * * If a trigger is supplied, * it is used to show the tooltip; otherwise, it will use the `trigger` * option passed to the `$tooltipProvider.options` method; else it will * default to the trigger supplied to this directive factory. * * The hide trigger is based on the show trigger. If the `trigger` option * was passed to the `$tooltipProvider.options` method, it will use the * mapped trigger from `triggerMap` or the passed trigger if the map is * undefined; otherwise, it uses the `triggerMap` value of the show * trigger; else it will just use the show trigger. */ function getTriggers ( trigger ) { var show = trigger || options.trigger || defaultTriggerShow; var hide = triggerMap[show] || show; return { show: show, hide: hide }; } var directiveName = snake_case( type ); var startSym = $interpolate.startSymbol(); var endSym = $interpolate.endSymbol(); var template = '
'+ '
'; return { restrict: 'EA', scope: true, compile: function (tElem, tAttrs) { var tooltipLinker = $compile( template ); return function link ( scope, element, attrs ) { var tooltip; var transitionTimeout; var popupTimeout; var appendToBody = angular.isDefined( options.appendToBody ) ? options.appendToBody : false; var triggers = getTriggers( undefined ); var hasRegisteredTriggers = false; var hasEnableExp = angular.isDefined(attrs[prefix+'Enable']); var positionTooltip = function (){ var position, ttWidth, ttHeight, ttPosition; // Get the position of the directive element. position = appendToBody ? $position.offset( element ) : $position.position( element ); // Get the height and width of the tooltip so we can center it. ttWidth = tooltip.prop( 'offsetWidth' ); ttHeight = tooltip.prop( 'offsetHeight' ); // Calculate the tooltip's top and left coordinates to center it with // this directive. switch ( scope.tt_placement ) { case 'right': ttPosition = { top: position.top + position.height / 2 - ttHeight / 2, left: position.left + position.width }; break; case 'bottom': ttPosition = { top: position.top + position.height, left: position.left + position.width / 2 - ttWidth / 2 }; break; case 'left': ttPosition = { top: position.top + position.height / 2 - ttHeight / 2, left: position.left - ttWidth }; break; default: ttPosition = { top: position.top - ttHeight, left: position.left + position.width / 2 - ttWidth / 2 }; break; } ttPosition.top += 'px'; ttPosition.left += 'px'; // Now set the calculated positioning. tooltip.css( ttPosition ); }; // By default, the tooltip is not open. // TODO add ability to start tooltip opened scope.tt_isOpen = false; function toggleTooltipBind () { if ( ! scope.tt_isOpen ) { showTooltipBind(); } else { hideTooltipBind(); } } // Show the tooltip with delay if specified, otherwise show it immediately function showTooltipBind() { if(hasEnableExp && !scope.$eval(attrs[prefix+'Enable'])) { return; } if ( scope.tt_popupDelay ) { popupTimeout = $timeout( show, scope.tt_popupDelay, false ); popupTimeout.then(function(reposition){reposition();}); } else { show()(); } } function hideTooltipBind () { scope.$apply(function () { hide(); }); } // Show the tooltip popup element. function show() { // Don't show empty tooltips. if ( ! scope.tt_content ) { return angular.noop; } createTooltip(); // If there is a pending remove transition, we must cancel it, lest the // tooltip be mysteriously removed. if ( transitionTimeout ) { $timeout.cancel( transitionTimeout ); } // Set the initial positioning. tooltip.css({ top: 0, left: 0, display: 'block' }); // Now we add it to the DOM because need some info about it. But it's not // visible yet anyway. if ( appendToBody ) { $document.find( 'body' ).append( tooltip ); } else { element.after( tooltip ); } positionTooltip(); // And show the tooltip. scope.tt_isOpen = true; scope.$digest(); // digest required as $apply is not called // Return positioning function as promise callback for correct // positioning after draw. return positionTooltip; } // Hide the tooltip popup element. function hide() { // First things first: we don't show it anymore. scope.tt_isOpen = false; //if tooltip is going to be shown after delay, we must cancel this $timeout.cancel( popupTimeout ); // And now we remove it from the DOM. However, if we have animation, we // need to wait for it to expire beforehand. // FIXME: this is a placeholder for a port of the transitions library. if ( scope.tt_animation ) { transitionTimeout = $timeout(removeTooltip, 500); } else { removeTooltip(); } } function createTooltip() { // There can only be one tooltip element per directive shown at once. if (tooltip) { removeTooltip(); } tooltip = tooltipLinker(scope, function () {}); // Get contents rendered into the tooltip scope.$digest(); } function removeTooltip() { if (tooltip) { tooltip.remove(); tooltip = null; } } /** * Observe the relevant attributes. */ attrs.$observe( type, function ( val ) { scope.tt_content = val; if (!val && scope.tt_isOpen ) { hide(); } }); attrs.$observe( prefix+'Title', function ( val ) { scope.tt_title = val; }); attrs.$observe( prefix+'Placement', function ( val ) { scope.tt_placement = angular.isDefined( val ) ? val : options.placement; }); attrs.$observe( prefix+'PopupDelay', function ( val ) { var delay = parseInt( val, 10 ); scope.tt_popupDelay = ! isNaN(delay) ? delay : options.popupDelay; }); var unregisterTriggers = function() { if (hasRegisteredTriggers) { element.unbind( triggers.show, showTooltipBind ); element.unbind( triggers.hide, hideTooltipBind ); } }; attrs.$observe( prefix+'Trigger', function ( val ) { unregisterTriggers(); triggers = getTriggers( val ); if ( triggers.show === triggers.hide ) { element.bind( triggers.show, toggleTooltipBind ); } else { element.bind( triggers.show, showTooltipBind ); element.bind( triggers.hide, hideTooltipBind ); } hasRegisteredTriggers = true; }); var animation = scope.$eval(attrs[prefix + 'Animation']); scope.tt_animation = angular.isDefined(animation) ? !!animation : options.animation; attrs.$observe( prefix+'AppendToBody', function ( val ) { appendToBody = angular.isDefined( val ) ? $parse( val )( scope ) : appendToBody; }); // if a tooltip is attached to we need to remove it on // location change as its parent scope will probably not be destroyed // by the change. if ( appendToBody ) { scope.$on('$locationChangeSuccess', function closeTooltipOnLocationChangeSuccess () { if ( scope.tt_isOpen ) { hide(); } }); } // Make sure tooltip is destroyed and removed. scope.$on('$destroy', function onDestroyTooltip() { $timeout.cancel( transitionTimeout ); $timeout.cancel( popupTimeout ); unregisterTriggers(); removeTooltip(); }); }; } }; }; }]; }) .directive( 'tooltipPopup', function () { return { restrict: 'EA', replace: true, scope: { content: '@', placement: '@', animation: '&', isOpen: '&' }, templateUrl: 'template/tooltip/tooltip-popup.html' }; }) .directive( 'tooltip', [ '$tooltip', function ( $tooltip ) { return $tooltip( 'tooltip', 'tooltip', 'mouseenter' ); }]) .directive( 'tooltipHtmlUnsafePopup', function () { return { restrict: 'EA', replace: true, scope: { content: '@', placement: '@', animation: '&', isOpen: '&' }, templateUrl: 'template/tooltip/tooltip-html-unsafe-popup.html' }; }) .directive( 'tooltipHtmlUnsafe', [ '$tooltip', function ( $tooltip ) { return $tooltip( 'tooltipHtmlUnsafe', 'tooltip', 'mouseenter' ); }]); angular.module("template/modal/backdrop.html", []).run(["$templateCache", function($templateCache) { $templateCache.put("template/modal/backdrop.html", "
"); }]); angular.module("template/modal/window.html", []).run(["$templateCache", function($templateCache) { $templateCache.put("template/modal/window.html", "
\n" + "
\n" + "
\n" + "
\n" + "
\n" + "
"); }]); angular.module("template/tooltip/tooltip-html-unsafe-popup.html", []).run(["$templateCache", function($templateCache) { $templateCache.put("template/tooltip/tooltip-html-unsafe-popup.html", "
\n" + "
\n" + "
\n" + "
\n" + ""); }]); angular.module("template/tooltip/tooltip-popup.html", []).run(["$templateCache", function($templateCache) { $templateCache.put("template/tooltip/tooltip-popup.html", "
\n" + "
\n" + "
\n" + "
\n" + ""); }]);