nexus site path corrected
[portal.git] / ecomp-portal-FE / client / bower_components / ng-dialog / js / ngDialog.js
1 /*
2  * ngDialog - easy modals and popup windows
3  * http://github.com/likeastore/ngDialog
4  * (c) 2013-2015 MIT License, https://likeastore.com
5  */
6
7 (function (root, factory) {
8     if (typeof module !== 'undefined' && module.exports) {
9         // CommonJS
10         if (typeof angular === 'undefined') {
11             factory(require('angular'));
12         } else {
13             factory(angular);
14         }
15         module.exports = 'ngDialog';
16     } else if (typeof define === 'function' && define.amd) {
17         // AMD
18         define(['angular'], factory);
19     } else {
20         // Global Variables
21         factory(root.angular);
22     }
23 }(this, function (angular) {
24     'use strict';
25
26     var m = angular.module('ngDialog', []);
27
28     var $el = angular.element;
29     var isDef = angular.isDefined;
30     var style = (document.body || document.documentElement).style;
31     var animationEndSupport = isDef(style.animation) || isDef(style.WebkitAnimation) || isDef(style.MozAnimation) || isDef(style.MsAnimation) || isDef(style.OAnimation);
32     var animationEndEvent = 'animationend webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend';
33     var focusableElementSelector = 'a[href], area[href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), iframe, object, embed, *[tabindex], *[contenteditable]';
34     var disabledAnimationClass = 'ngdialog-disabled-animation';
35     var forceElementsReload = { html: false, body: false };
36     var scopes = {};
37     var openIdStack = [];
38     var keydownIsBound = false;
39     var openOnePerName = false;
40
41
42     m.provider('ngDialog', function () {
43         var defaults = this.defaults = {
44             className: 'ngdialog-theme-default',
45             appendClassName: '',
46             disableAnimation: false,
47             plain: false,
48             showClose: true,
49             closeByDocument: true,
50             closeByEscape: true,
51             closeByNavigation: false,
52             appendTo: false,
53             preCloseCallback: false,
54             overlay: true,
55             cache: true,
56             trapFocus: true,
57             preserveFocus: true,
58             ariaAuto: true,
59             ariaRole: null,
60             ariaLabelledById: null,
61             ariaLabelledBySelector: null,
62             ariaDescribedById: null,
63             ariaDescribedBySelector: null,
64             bodyClassName: 'ngdialog-open',
65             width: null,
66             height: null
67         };
68
69         this.setForceHtmlReload = function (_useIt) {
70             forceElementsReload.html = _useIt || false;
71         };
72
73         this.setForceBodyReload = function (_useIt) {
74             forceElementsReload.body = _useIt || false;
75         };
76
77         this.setDefaults = function (newDefaults) {
78             angular.extend(defaults, newDefaults);
79         };
80
81         this.setOpenOnePerName = function (isOpenOne) {
82             openOnePerName = isOpenOne || false;
83         };
84
85         var globalID = 0, dialogsCount = 0, closeByDocumentHandler, defers = {};
86
87         this.$get = ['$document', '$templateCache', '$compile', '$q', '$http', '$rootScope', '$timeout', '$window', '$controller', '$injector',
88             function ($document, $templateCache, $compile, $q, $http, $rootScope, $timeout, $window, $controller, $injector) {
89                 var $elements = [];
90
91                 var privateMethods = {
92                     onDocumentKeydown: function (event) {
93                         if (event.keyCode === 27) {
94                             publicMethods.close('$escape');
95                         }
96                     },
97
98                     activate: function($dialog) {
99                         var options = $dialog.data('$ngDialogOptions');
100
101                         if (options.trapFocus) {
102                             $dialog.on('keydown', privateMethods.onTrapFocusKeydown);
103
104                             // Catch rogue changes (eg. after unfocusing everything by clicking a non-focusable element)
105                             $elements.body.on('keydown', privateMethods.onTrapFocusKeydown);
106                         }
107                     },
108
109                     deactivate: function ($dialog) {
110                         $dialog.off('keydown', privateMethods.onTrapFocusKeydown);
111                         $elements.body.off('keydown', privateMethods.onTrapFocusKeydown);
112                     },
113
114                     deactivateAll: function (els) {
115                         angular.forEach(els,function(el) {
116                             var $dialog = angular.element(el);
117                             privateMethods.deactivate($dialog);
118                         });
119                     },
120
121                     setBodyPadding: function (width) {
122                         var originalBodyPadding = parseInt(($elements.body.css('padding-right') || 0), 10);
123                         $elements.body.css('padding-right', (originalBodyPadding + width) + 'px');
124                         $elements.body.data('ng-dialog-original-padding', originalBodyPadding);
125                         $rootScope.$broadcast('ngDialog.setPadding', width);
126                     },
127
128                     resetBodyPadding: function () {
129                         var originalBodyPadding = $elements.body.data('ng-dialog-original-padding');
130                         if (originalBodyPadding) {
131                             $elements.body.css('padding-right', originalBodyPadding + 'px');
132                         } else {
133                             $elements.body.css('padding-right', '');
134                         }
135                         $rootScope.$broadcast('ngDialog.setPadding', 0);
136                     },
137
138                     performCloseDialog: function ($dialog, value) {
139                         var options = $dialog.data('$ngDialogOptions');
140                         var id = $dialog.attr('id');
141                         var scope = scopes[id];
142
143                         if (!scope) {
144                             // Already closed
145                             return;
146                         }
147
148                         if (typeof $window.Hammer !== 'undefined') {
149                             var hammerTime = scope.hammerTime;
150                             hammerTime.off('tap', closeByDocumentHandler);
151                             hammerTime.destroy && hammerTime.destroy();
152                             delete scope.hammerTime;
153                         } else {
154                             $dialog.unbind('click');
155                         }
156
157                         if (dialogsCount === 1) {
158                             $elements.body.unbind('keydown', privateMethods.onDocumentKeydown);
159                         }
160
161                         if (!$dialog.hasClass('ngdialog-closing')){
162                             dialogsCount -= 1;
163                         }
164
165                         var previousFocus = $dialog.data('$ngDialogPreviousFocus');
166                         if (previousFocus && previousFocus.focus) {
167                             previousFocus.focus();
168                         }
169
170                         $rootScope.$broadcast('ngDialog.closing', $dialog, value);
171                         dialogsCount = dialogsCount < 0 ? 0 : dialogsCount;
172                         if (animationEndSupport && !options.disableAnimation) {
173                             scope.$destroy();
174                             $dialog.unbind(animationEndEvent).bind(animationEndEvent, function () {
175                                 privateMethods.closeDialogElement($dialog, value);
176                             }).addClass('ngdialog-closing');
177                         } else {
178                             scope.$destroy();
179                             privateMethods.closeDialogElement($dialog, value);
180                         }
181                         if (defers[id]) {
182                             defers[id].resolve({
183                                 id: id,
184                                 value: value,
185                                 $dialog: $dialog,
186                                 remainingDialogs: dialogsCount
187                             });
188                             delete defers[id];
189                         }
190                         if (scopes[id]) {
191                             delete scopes[id];
192                         }
193                         openIdStack.splice(openIdStack.indexOf(id), 1);
194                         if (!openIdStack.length) {
195                             $elements.body.unbind('keydown', privateMethods.onDocumentKeydown);
196                             keydownIsBound = false;
197                         }
198                     },
199
200                     closeDialogElement: function($dialog, value) {
201                         var options = $dialog.data('$ngDialogOptions');
202                         $dialog.remove();
203                         if (dialogsCount === 0) {
204                             $elements.html.removeClass(options.bodyClassName);
205                             $elements.body.removeClass(options.bodyClassName);
206                             privateMethods.resetBodyPadding();
207                         }
208                         $rootScope.$broadcast('ngDialog.closed', $dialog, value);
209                     },
210
211                     closeDialog: function ($dialog, value) {
212                         var preCloseCallback = $dialog.data('$ngDialogPreCloseCallback');
213
214                         if (preCloseCallback && angular.isFunction(preCloseCallback)) {
215
216                             var preCloseCallbackResult = preCloseCallback.call($dialog, value);
217
218                             if (angular.isObject(preCloseCallbackResult)) {
219                                 if (preCloseCallbackResult.closePromise) {
220                                     preCloseCallbackResult.closePromise.then(function () {
221                                         privateMethods.performCloseDialog($dialog, value);
222                                     }, function () {
223                                         return false;
224                                     });
225                                 } else {
226                                     preCloseCallbackResult.then(function () {
227                                         privateMethods.performCloseDialog($dialog, value);
228                                     }, function () {
229                                         return false;
230                                     });
231                                 }
232                             } else if (preCloseCallbackResult !== false) {
233                                 privateMethods.performCloseDialog($dialog, value);
234                             } else {
235                                 return false;
236                             }
237                         } else {
238                             privateMethods.performCloseDialog($dialog, value);
239                         }
240                     },
241
242                     onTrapFocusKeydown: function(ev) {
243                         var el = angular.element(ev.currentTarget);
244                         var $dialog;
245
246                         if (el.hasClass('ngdialog')) {
247                             $dialog = el;
248                         } else {
249                             $dialog = privateMethods.getActiveDialog();
250
251                             if ($dialog === null) {
252                                 return;
253                             }
254                         }
255
256                         var isTab = (ev.keyCode === 9);
257                         var backward = (ev.shiftKey === true);
258
259                         if (isTab) {
260                             privateMethods.handleTab($dialog, ev, backward);
261                         }
262                     },
263
264                     handleTab: function($dialog, ev, backward) {
265                         var focusableElements = privateMethods.getFocusableElements($dialog);
266
267                         if (focusableElements.length === 0) {
268                             if (document.activeElement && document.activeElement.blur) {
269                                 document.activeElement.blur();
270                             }
271                             return;
272                         }
273
274                         var currentFocus = document.activeElement;
275                         var focusIndex = Array.prototype.indexOf.call(focusableElements, currentFocus);
276
277                         var isFocusIndexUnknown = (focusIndex === -1);
278                         var isFirstElementFocused = (focusIndex === 0);
279                         var isLastElementFocused = (focusIndex === focusableElements.length - 1);
280
281                         var cancelEvent = false;
282
283                         if (backward) {
284                             if (isFocusIndexUnknown || isFirstElementFocused) {
285                                 focusableElements[focusableElements.length - 1].focus();
286                                 cancelEvent = true;
287                             }
288                         } else {
289                             if (isFocusIndexUnknown || isLastElementFocused) {
290                                 focusableElements[0].focus();
291                                 cancelEvent = true;
292                             }
293                         }
294
295                         if (cancelEvent) {
296                             ev.preventDefault();
297                             ev.stopPropagation();
298                         }
299                     },
300
301                     autoFocus: function($dialog) {
302                         var dialogEl = $dialog[0];
303
304                         // Browser's (Chrome 40, Forefix 37, IE 11) don't appear to honor autofocus on the dialog, but we should
305                         var autoFocusEl = dialogEl.querySelector('*[autofocus]');
306                         if (autoFocusEl !== null) {
307                             autoFocusEl.focus();
308
309                             if (document.activeElement === autoFocusEl) {
310                                 return;
311                             }
312
313                             // Autofocus element might was display: none, so let's continue
314                         }
315
316                         var focusableElements = privateMethods.getFocusableElements($dialog);
317
318                         if (focusableElements.length > 0) {
319                             focusableElements[0].focus();
320                             return;
321                         }
322
323                         // We need to focus something for the screen readers to notice the dialog
324                         var contentElements = privateMethods.filterVisibleElements(dialogEl.querySelectorAll('h1,h2,h3,h4,h5,h6,p,span'));
325
326                         if (contentElements.length > 0) {
327                             var contentElement = contentElements[0];
328                             $el(contentElement).attr('tabindex', '-1').css('outline', '0');
329                             contentElement.focus();
330                         }
331                     },
332
333                     getFocusableElements: function ($dialog) {
334                         var dialogEl = $dialog[0];
335
336                         var rawElements = dialogEl.querySelectorAll(focusableElementSelector);
337
338                         // Ignore untabbable elements, ie. those with tabindex = -1
339                         var tabbableElements = privateMethods.filterTabbableElements(rawElements);
340
341                         return privateMethods.filterVisibleElements(tabbableElements);
342                     },
343
344                     filterTabbableElements: function (els) {
345                         var tabbableFocusableElements = [];
346
347                         for (var i = 0; i < els.length; i++) {
348                             var el = els[i];
349
350                             if ($el(el).attr('tabindex') !== '-1') {
351                                 tabbableFocusableElements.push(el);
352                             }
353                         }
354
355                         return tabbableFocusableElements;
356                     },
357
358                     filterVisibleElements: function (els) {
359                         var visibleFocusableElements = [];
360
361                         for (var i = 0; i < els.length; i++) {
362                             var el = els[i];
363
364                             if (el.offsetWidth > 0 || el.offsetHeight > 0) {
365                                 visibleFocusableElements.push(el);
366                             }
367                         }
368
369                         return visibleFocusableElements;
370                     },
371
372                     getActiveDialog: function () {
373                         var dialogs = document.querySelectorAll('.ngdialog');
374
375                         if (dialogs.length === 0) {
376                             return null;
377                         }
378
379                         // TODO: This might be incorrect if there are a mix of open dialogs with different 'appendTo' values
380                         return $el(dialogs[dialogs.length - 1]);
381                     },
382
383                     applyAriaAttributes: function ($dialog, options) {
384                         if (options.ariaAuto) {
385                             if (!options.ariaRole) {
386                                 var detectedRole = (privateMethods.getFocusableElements($dialog).length > 0) ?
387                                     'dialog' :
388                                     'alertdialog';
389
390                                 options.ariaRole = detectedRole;
391                             }
392
393                             if (!options.ariaLabelledBySelector) {
394                                 options.ariaLabelledBySelector = 'h1,h2,h3,h4,h5,h6';
395                             }
396
397                             if (!options.ariaDescribedBySelector) {
398                                 options.ariaDescribedBySelector = 'article,section,p';
399                             }
400                         }
401
402                         if (options.ariaRole) {
403                             $dialog.attr('role', options.ariaRole);
404                         }
405
406                         privateMethods.applyAriaAttribute(
407                             $dialog, 'aria-labelledby', options.ariaLabelledById, options.ariaLabelledBySelector);
408
409                         privateMethods.applyAriaAttribute(
410                             $dialog, 'aria-describedby', options.ariaDescribedById, options.ariaDescribedBySelector);
411                     },
412
413                     applyAriaAttribute: function($dialog, attr, id, selector) {
414                         if (id) {
415                             $dialog.attr(attr, id);
416                         }
417
418                         if (selector) {
419                             var dialogId = $dialog.attr('id');
420
421                             var firstMatch = $dialog[0].querySelector(selector);
422
423                             if (!firstMatch) {
424                                 return;
425                             }
426
427                             var generatedId = dialogId + '-' + attr;
428
429                             $el(firstMatch).attr('id', generatedId);
430
431                             $dialog.attr(attr, generatedId);
432
433                             return generatedId;
434                         }
435                     },
436
437                     detectUIRouter: function() {
438                         //Detect if ui-router module is installed if not return false
439                         try {
440                             angular.module('ui.router');
441                             return true;
442                         } catch(err) {
443                             return false;
444                         }
445                     },
446
447                     getRouterLocationEventName: function() {
448                         if(privateMethods.detectUIRouter()) {
449                             return '$stateChangeStart';
450                         }
451                         return '$locationChangeStart';
452                     }
453                 };
454
455                 var publicMethods = {
456                     __PRIVATE__: privateMethods,
457
458                     /*
459                      * @param {Object} options:
460                      * - template {String} - id of ng-template, url for partial, plain string (if enabled)
461                      * - plain {Boolean} - enable plain string templates, default false
462                      * - scope {Object}
463                      * - controller {String}
464                      * - controllerAs {String}
465                      * - className {String} - dialog theme class
466                      * - appendClassName {String} - dialog theme class to be appended to defaults
467                      * - disableAnimation {Boolean} - set to true to disable animation
468                      * - showClose {Boolean} - show close button, default true
469                      * - closeByEscape {Boolean} - default true
470                      * - closeByDocument {Boolean} - default true
471                      * - preCloseCallback {String|Function} - user supplied function name/function called before closing dialog (if set)
472                      * - bodyClassName {String} - class added to body at open dialog
473                      * @return {Object} dialog
474                      */
475                     open: function (opts) {
476                         var dialogID = null;
477                         opts = opts || {};
478                         if (openOnePerName && opts.name) {
479                             dialogID = opts.name.toLowerCase().replace(/\s/g, '-') + '-dialog';
480                             if (this.isOpen(dialogID)) {
481                                 return;
482                             }
483                         }
484                         var options = angular.copy(defaults);
485                         var localID = ++globalID;
486                         dialogID = dialogID || 'ngdialog' + localID;
487                         openIdStack.push(dialogID);
488
489                         // Merge opts.data with predefined via setDefaults
490                         if (typeof options.data !== 'undefined') {
491                             if (typeof opts.data === 'undefined') {
492                                 opts.data = {};
493                             }
494                             opts.data = angular.merge(angular.copy(options.data), opts.data);
495                         }
496
497                         angular.extend(options, opts);
498
499                         var defer;
500                         defers[dialogID] = defer = $q.defer();
501
502                         var scope;
503                         scopes[dialogID] = scope = angular.isObject(options.scope) ? options.scope.$new() : $rootScope.$new();
504
505                         var $dialog, $dialogParent, $dialogContent;
506
507                         var resolve = angular.extend({}, options.resolve);
508
509                         angular.forEach(resolve, function (value, key) {
510                             resolve[key] = angular.isString(value) ? $injector.get(value) : $injector.invoke(value, null, null, key);
511                         });
512
513                         $q.all({
514                             template: loadTemplate(options.template || options.templateUrl),
515                             locals: $q.all(resolve)
516                         }).then(function (setup) {
517                             var template = setup.template,
518                                 locals = setup.locals;
519
520                             if (options.showClose) {
521                                 template += '<div class="ngdialog-close"></div>';
522                             }
523
524                             var hasOverlayClass = options.overlay ? '' : ' ngdialog-no-overlay';
525                             $dialog = $el('<div id="' + dialogID + '" class="ngdialog' + hasOverlayClass + '"></div>');
526                             $dialog.html((options.overlay ?
527                                 '<div class="ngdialog-overlay"></div><div class="ngdialog-content" role="document">' + template + '</div>' :
528                                 '<div class="ngdialog-content" role="document">' + template + '</div>'));
529
530                             $dialog.data('$ngDialogOptions', options);
531
532                             scope.ngDialogId = dialogID;
533
534                             if (options.data && angular.isString(options.data)) {
535                                 var firstLetter = options.data.replace(/^\s*/, '')[0];
536                                 scope.ngDialogData = (firstLetter === '{' || firstLetter === '[') ? angular.fromJson(options.data) : new String(options.data);
537                                 scope.ngDialogData.ngDialogId = dialogID;
538                             } else if (options.data && angular.isObject(options.data)) {
539                                 scope.ngDialogData = options.data;
540                                 scope.ngDialogData.ngDialogId = dialogID;
541                             }
542
543                             if (options.className) {
544                                 $dialog.addClass(options.className);
545                             }
546
547                             if (options.appendClassName) {
548                                 $dialog.addClass(options.appendClassName);
549                             }
550
551                             if (options.width) {
552                                 $dialogContent = $dialog[0].querySelector('.ngdialog-content');
553                                 if (angular.isString(options.width)) {
554                                     $dialogContent.style.width = options.width;
555                                 } else {
556                                     $dialogContent.style.width = options.width + 'px';
557                                 }
558                             }
559
560                             if (options.height) {
561                                 $dialogContent = $dialog[0].querySelector('.ngdialog-content');
562                                 if (angular.isString(options.height)) {
563                                     $dialogContent.style.height = options.height;
564                                 } else {
565                                     $dialogContent.style.height = options.height + 'px';
566                                 }
567                             }
568
569                             if (options.disableAnimation) {
570                                 $dialog.addClass(disabledAnimationClass);
571                             }
572
573                             if (options.appendTo && angular.isString(options.appendTo)) {
574                                 $dialogParent = angular.element(document.querySelector(options.appendTo));
575                             } else {
576                                 $dialogParent = $elements.body;
577                             }
578
579                             privateMethods.applyAriaAttributes($dialog, options);
580
581                             if (options.preCloseCallback) {
582                                 var preCloseCallback;
583
584                                 if (angular.isFunction(options.preCloseCallback)) {
585                                     preCloseCallback = options.preCloseCallback;
586                                 } else if (angular.isString(options.preCloseCallback)) {
587                                     if (scope) {
588                                         if (angular.isFunction(scope[options.preCloseCallback])) {
589                                             preCloseCallback = scope[options.preCloseCallback];
590                                         } else if (scope.$parent && angular.isFunction(scope.$parent[options.preCloseCallback])) {
591                                             preCloseCallback = scope.$parent[options.preCloseCallback];
592                                         } else if ($rootScope && angular.isFunction($rootScope[options.preCloseCallback])) {
593                                             preCloseCallback = $rootScope[options.preCloseCallback];
594                                         }
595                                     }
596                                 }
597
598                                 if (preCloseCallback) {
599                                     $dialog.data('$ngDialogPreCloseCallback', preCloseCallback);
600                                 }
601                             }
602
603                             scope.closeThisDialog = function (value) {
604                                 privateMethods.closeDialog($dialog, value);
605                             };
606
607                             if (options.controller && (angular.isString(options.controller) || angular.isArray(options.controller) || angular.isFunction(options.controller))) {
608
609                                 var label;
610
611                                 if (options.controllerAs && angular.isString(options.controllerAs)) {
612                                     label = options.controllerAs;
613                                 }
614
615                                 var controllerInstance = $controller(options.controller, angular.extend(
616                                     locals,
617                                     {
618                                         $scope: scope,
619                                         $element: $dialog
620                                     }),
621                                     true,
622                                     label
623                                 );
624
625                                 if(options.bindToController) {
626                                     angular.extend(controllerInstance.instance, {ngDialogId: scope.ngDialogId, ngDialogData: scope.ngDialogData, closeThisDialog: scope.closeThisDialog, confirm: scope.confirm});
627                                 }
628
629                                 if(typeof controllerInstance === 'function'){
630                                     $dialog.data('$ngDialogControllerController', controllerInstance());
631                                 } else {
632                                     $dialog.data('$ngDialogControllerController', controllerInstance);
633                                 }
634                             }
635
636                             $timeout(function () {
637                                 var $activeDialogs = document.querySelectorAll('.ngdialog');
638                                 privateMethods.deactivateAll($activeDialogs);
639
640                                 $compile($dialog)(scope);
641                                 var widthDiffs = $window.innerWidth - $elements.body.prop('clientWidth');
642                                 $elements.html.addClass(options.bodyClassName);
643                                 $elements.body.addClass(options.bodyClassName);
644                                 var scrollBarWidth = widthDiffs - ($window.innerWidth - $elements.body.prop('clientWidth'));
645                                 if (scrollBarWidth > 0) {
646                                     privateMethods.setBodyPadding(scrollBarWidth);
647                                 }
648                                 $dialogParent.append($dialog);
649
650                                 privateMethods.activate($dialog);
651
652                                 if (options.trapFocus) {
653                                     privateMethods.autoFocus($dialog);
654                                 }
655
656                                 if (options.name) {
657                                     $rootScope.$broadcast('ngDialog.opened', {dialog: $dialog, name: options.name});
658                                 } else {
659                                     $rootScope.$broadcast('ngDialog.opened', $dialog);
660                                 }
661                             });
662
663                             if (!keydownIsBound) {
664                                 $elements.body.bind('keydown', privateMethods.onDocumentKeydown);
665                                 keydownIsBound = true;
666                             }
667
668                             if (options.closeByNavigation) {
669                                 var eventName = privateMethods.getRouterLocationEventName();
670                                 $rootScope.$on(eventName, function ($event) {
671                                     if (privateMethods.closeDialog($dialog) === false)
672                                         $event.preventDefault();
673                                 });
674                             }
675
676                             if (options.preserveFocus) {
677                                 $dialog.data('$ngDialogPreviousFocus', document.activeElement);
678                             }
679
680                             closeByDocumentHandler = function (event) {
681                                 var isOverlay = options.closeByDocument ? $el(event.target).hasClass('ngdialog-overlay') : false;
682                                 var isCloseBtn = $el(event.target).hasClass('ngdialog-close');
683
684                                 if (isOverlay || isCloseBtn) {
685                                     publicMethods.close($dialog.attr('id'), isCloseBtn ? '$closeButton' : '$document');
686                                 }
687                             };
688
689                             if (typeof $window.Hammer !== 'undefined') {
690                                 var hammerTime = scope.hammerTime = $window.Hammer($dialog[0]);
691                                 hammerTime.on('tap', closeByDocumentHandler);
692                             } else {
693                                 $dialog.bind('click', closeByDocumentHandler);
694                             }
695
696                             dialogsCount += 1;
697
698                             return publicMethods;
699                         });
700
701                         return {
702                             id: dialogID,
703                             closePromise: defer.promise,
704                             close: function (value) {
705                                 privateMethods.closeDialog($dialog, value);
706                             }
707                         };
708
709                         function loadTemplateUrl (tmpl, config) {
710                             var config = config || {};
711                             config.headers = config.headers || {};
712
713                             angular.extend(config.headers, {'Accept': 'text/html'});
714
715                             $rootScope.$broadcast('ngDialog.templateLoading', tmpl);
716                             return $http.get(tmpl, config).then(function(res) {
717                                 $rootScope.$broadcast('ngDialog.templateLoaded', tmpl);
718                                 return res.data || '';
719                             });
720                         }
721
722                         function loadTemplate (tmpl) {
723                             if (!tmpl) {
724                                 return 'Empty template';
725                             }
726
727                             if (angular.isString(tmpl) && options.plain) {
728                                 return tmpl;
729                             }
730
731                             if (typeof options.cache === 'boolean' && !options.cache) {
732                                 return loadTemplateUrl(tmpl, {cache: false});
733                             }
734
735                             return loadTemplateUrl(tmpl, {cache: $templateCache});
736                         }
737                     },
738
739                     /*
740                      * @param {Object} options:
741                      * - template {String} - id of ng-template, url for partial, plain string (if enabled)
742                      * - plain {Boolean} - enable plain string templates, default false
743                      * - name {String}
744                      * - scope {Object}
745                      * - controller {String}
746                      * - controllerAs {String}
747                      * - className {String} - dialog theme class
748                      * - appendClassName {String} - dialog theme class to be appended to defaults
749                      * - showClose {Boolean} - show close button, default true
750                      * - closeByEscape {Boolean} - default false
751                      * - closeByDocument {Boolean} - default false
752                      * - preCloseCallback {String|Function} - user supplied function name/function called before closing dialog (if set); not called on confirm
753                      * - bodyClassName {String} - class added to body at open dialog
754                      *
755                      * @return {Object} dialog
756                      */
757                     openConfirm: function (opts) {
758                         var defer = $q.defer();
759                         var options = angular.copy(defaults);
760
761                         opts = opts || {};
762
763                         // Merge opts.data with predefined via setDefaults
764                         if (typeof options.data !== 'undefined') {
765                             if (typeof opts.data === 'undefined') {
766                                 opts.data = {};
767                             }
768                             opts.data = angular.merge(angular.copy(options.data), opts.data);
769                         }
770
771                         angular.extend(options, opts);
772
773                         options.scope = angular.isObject(options.scope) ? options.scope.$new() : $rootScope.$new();
774                         options.scope.confirm = function (value) {
775                             defer.resolve(value);
776                             var $dialog = $el(document.getElementById(openResult.id));
777                             privateMethods.performCloseDialog($dialog, value);
778                         };
779
780                         var openResult = publicMethods.open(options);
781                         if (openResult) {
782                             openResult.closePromise.then(function (data) {
783                                 if (data) {
784                                     return defer.reject(data.value);
785                                 }
786                                 return defer.reject();
787                             });
788                             return defer.promise;
789                         }
790                     },
791
792                     isOpen: function(id) {
793                         var $dialog = $el(document.getElementById(id));
794                         return $dialog.length > 0;
795                     },
796
797                     /*
798                      * @param {String} id
799                      * @return {Object} dialog
800                      */
801                     close: function (id, value) {
802                         var $dialog = $el(document.getElementById(id));
803
804                         if ($dialog.length) {
805                             privateMethods.closeDialog($dialog, value);
806                         } else {
807                             if (id === '$escape') {
808                                 var topDialogId = openIdStack[openIdStack.length - 1];
809                                 $dialog = $el(document.getElementById(topDialogId));
810                                 if ($dialog.data('$ngDialogOptions').closeByEscape) {
811                                     privateMethods.closeDialog($dialog, '$escape');
812                                 }
813                             } else {
814                                 publicMethods.closeAll(value);
815                             }
816                         }
817
818                         return publicMethods;
819                     },
820
821                     closeAll: function (value) {
822                         var $all = document.querySelectorAll('.ngdialog');
823
824                         // Reverse order to ensure focus restoration works as expected
825                         for (var i = $all.length - 1; i >= 0; i--) {
826                             var dialog = $all[i];
827                             privateMethods.closeDialog($el(dialog), value);
828                         }
829                     },
830
831                     getOpenDialogs: function() {
832                         return openIdStack;
833                     },
834
835                     getDefaults: function () {
836                         return defaults;
837                     }
838                 };
839
840                 angular.forEach(
841                     ['html', 'body'],
842                     function(elementName) {
843                         $elements[elementName] = $document.find(elementName);
844                         if (forceElementsReload[elementName]) {
845                             var eventName = privateMethods.getRouterLocationEventName();
846                             $rootScope.$on(eventName, function () {
847                                 $elements[elementName] = $document.find(elementName);
848                             });
849                         }
850                     }
851                 );
852
853                 return publicMethods;
854             }];
855     });
856
857     m.directive('ngDialog', ['ngDialog', function (ngDialog) {
858         return {
859             restrict: 'A',
860             scope: {
861                 ngDialogScope: '='
862             },
863             link: function (scope, elem, attrs) {
864                 elem.on('click', function (e) {
865                     e.preventDefault();
866
867                     var ngDialogScope = angular.isDefined(scope.ngDialogScope) ? scope.ngDialogScope : 'noScope';
868                     angular.isDefined(attrs.ngDialogClosePrevious) && ngDialog.close(attrs.ngDialogClosePrevious);
869
870                     var defaults = ngDialog.getDefaults();
871
872                     ngDialog.open({
873                         template: attrs.ngDialog,
874                         className: attrs.ngDialogClass || defaults.className,
875                         appendClassName: attrs.ngDialogAppendClass,
876                         controller: attrs.ngDialogController,
877                         controllerAs: attrs.ngDialogControllerAs,
878                         bindToController: attrs.ngDialogBindToController,
879                         disableAnimation: attrs.ngDialogDisableAnimation,
880                         scope: ngDialogScope,
881                         data: attrs.ngDialogData,
882                         showClose: attrs.ngDialogShowClose === 'false' ? false : (attrs.ngDialogShowClose === 'true' ? true : defaults.showClose),
883                         closeByDocument: attrs.ngDialogCloseByDocument === 'false' ? false : (attrs.ngDialogCloseByDocument === 'true' ? true : defaults.closeByDocument),
884                         closeByEscape: attrs.ngDialogCloseByEscape === 'false' ? false : (attrs.ngDialogCloseByEscape === 'true' ? true : defaults.closeByEscape),
885                         overlay: attrs.ngDialogOverlay === 'false' ? false : (attrs.ngDialogOverlay === 'true' ? true : defaults.overlay),
886                         preCloseCallback: attrs.ngDialogPreCloseCallback || defaults.preCloseCallback,
887                         bodyClassName: attrs.ngDialogBodyClass || defaults.bodyClassName
888                     });
889                 });
890             }
891         };
892     }]);
893
894     return m;
895 }));