nexus site path corrected
[portal.git] / ecomp-portal-FE / client / bower_components / angular-material / modules / js / sidenav / sidenav.js
1 /*!
2  * Angular Material Design
3  * https://github.com/angular/material
4  * @license MIT
5  * v0.9.8
6  */
7 (function( window, angular, undefined ){
8 "use strict";
9
10 /**
11  * @ngdoc module
12  * @name material.components.sidenav
13  *
14  * @description
15  * A Sidenav QP component.
16  */
17 angular.module('material.components.sidenav', [
18     'material.core',
19     'material.components.backdrop'
20   ])
21   .factory('$mdSidenav', SidenavService )
22   .directive('mdSidenav', SidenavDirective)
23   .directive('mdSidenavFocus', SidenavFocusDirective)
24   .controller('$mdSidenavController', SidenavController);
25
26
27 /**
28  * @private
29  * @ngdoc service
30  * @name $mdSidenav
31  * @module material.components.sidenav
32  *
33  * @description
34  * `$mdSidenav` makes it easy to interact with multiple sidenavs
35  * in an app.
36  *
37  * @usage
38  * <hljs lang="js">
39  * // Async lookup for sidenav instance; will resolve when the instance is available
40  * $mdSidenav(componentId).then(function(instance) {
41  *   $log.debug( componentId + "is now ready" );
42  * });
43  * // Async toggle the given sidenav;
44  * // when instance is known ready and lazy lookup is not needed.
45  * $mdSidenav(componentId)
46  *    .toggle()
47  *    .then(function(){
48  *      $log.debug('toggled');
49  *    });
50  * // Async open the given sidenav
51  * $mdSidenav(componentId)
52  *    .open()
53  *    .then(function(){
54  *      $log.debug('opened');
55  *    });
56  * // Async close the given sidenav
57  * $mdSidenav(componentId)
58  *    .close()
59  *    .then(function(){
60  *      $log.debug('closed');
61  *    });
62  * // Sync check to see if the specified sidenav is set to be open
63  * $mdSidenav(componentId).isOpen();
64  * // Sync check to whether given sidenav is locked open
65  * // If this is true, the sidenav will be open regardless of close()
66  * $mdSidenav(componentId).isLockedOpen();
67  * </hljs>
68  */
69 function SidenavService($mdComponentRegistry, $q) {
70   return function(handle) {
71
72     // Lookup the controller instance for the specified sidNav instance
73     var self;
74     var errorMsg = "SideNav '" + handle + "' is not available!";
75     var instance = $mdComponentRegistry.get(handle);
76
77     if(!instance) {
78       $mdComponentRegistry.notFoundError(handle);
79     }
80
81     return self = {
82       // -----------------
83       // Sync methods
84       // -----------------
85       isOpen: function() {
86         return instance && instance.isOpen();
87       },
88       isLockedOpen: function() {
89         return instance && instance.isLockedOpen();
90       },
91       // -----------------
92       // Async methods
93       // -----------------
94       toggle: function() {
95         return instance ? instance.toggle() : $q.reject(errorMsg);
96       },
97       open: function() {
98         return instance ? instance.open() : $q.reject(errorMsg);
99       },
100       close: function() {
101         return instance ? instance.close() : $q.reject(errorMsg);
102       },
103       then : function( callbackFn ) {
104         var promise = instance ? $q.when(instance) : waitForInstance();
105         return promise.then( callbackFn || angular.noop );
106       }
107     };
108
109     /**
110      * Deferred lookup of component instance using $component registry
111      */
112     function waitForInstance() {
113       return $mdComponentRegistry
114                 .when(handle)
115                 .then(function( it ){
116                   instance = it;
117                   return it;
118                 });
119     }
120   };
121 }
122 SidenavService.$inject = ["$mdComponentRegistry", "$q"];
123 /**
124  * @ngdoc directive
125  * @name mdSidenavFocus
126  * @module material.components.sidenav
127  *
128  * @restrict A
129  *
130  * @description
131  * `$mdSidenavFocus` provides a way to specify the focused element when a sidenav opens.
132  * This is completely optional, as the sidenav itself is focused by default.
133  *
134  * @usage
135  * <hljs lang="html">
136  * <md-sidenav>
137  *   <form>
138  *     <md-input-container>
139  *       <label for="testInput">Label</label>
140  *       <input id="testInput" type="text" md-sidenav-focus>
141  *     </md-input-container>
142  *   </form>
143  * </md-sidenav>
144  * </hljs>
145  **/
146 function SidenavFocusDirective() {
147   return {
148     restrict: 'A',
149     require: '^mdSidenav',
150     link: function(scope, element, attr, sidenavCtrl) {
151       sidenavCtrl.focusElement(element);
152     }
153   };
154 }
155 /**
156  * @ngdoc directive
157  * @name mdSidenav
158  * @module material.components.sidenav
159  * @restrict E
160  *
161  * @description
162  *
163  * A Sidenav component that can be opened and closed programatically.
164  *
165  * By default, upon opening it will slide out on top of the main content area.
166  *
167  * For keyboard and screen reader accessibility, focus is sent to the sidenav wrapper by default.
168  * It can be overridden with the `md-sidenav-focus` directive on the child element you want focused.
169  *
170  * @usage
171  * <hljs lang="html">
172  * <div layout="row" ng-controller="MyController">
173  *   <md-sidenav md-component-id="left" class="md-sidenav-left">
174  *     Left Nav!
175  *   </md-sidenav>
176  *
177  *   <md-content>
178  *     Center Content
179  *     <md-button ng-click="openLeftMenu()">
180  *       Open Left Menu
181  *     </md-button>
182  *   </md-content>
183  *
184  *   <md-sidenav md-component-id="right"
185  *     md-is-locked-open="$mdMedia('min-width: 333px')"
186  *     class="md-sidenav-right">
187  *     <form>
188  *       <md-input-container>
189  *         <label for="testInput">Test input</label>
190  *         <input id="testInput" type="text"
191  *                ng-model="data" md-sidenav-focus>
192  *       </md-input-container>
193  *     </form>
194  *   </md-sidenav>
195  * </div>
196  * </hljs>
197  *
198  * <hljs lang="js">
199  * var app = angular.module('myApp', ['ngMaterial']);
200  * app.controller('MyController', function($scope, $mdSidenav) {
201  *   $scope.openLeftMenu = function() {
202  *     $mdSidenav('left').toggle();
203  *   };
204  * });
205  * </hljs>
206  *
207  * @param {expression=} md-is-open A model bound to whether the sidenav is opened.
208  * @param {string=} md-component-id componentId to use with $mdSidenav service.
209  * @param {expression=} md-is-locked-open When this expression evalutes to true,
210  * the sidenav 'locks open': it falls into the content's flow instead
211  * of appearing over it. This overrides the `is-open` attribute.
212  *
213  * The $mdMedia() service is exposed to the is-locked-open attribute, which
214  * can be given a media query or one of the `sm`, `gt-sm`, `md`, `gt-md`, `lg` or `gt-lg` presets.
215  * Examples:
216  *
217  *   - `<md-sidenav md-is-locked-open="shouldLockOpen"></md-sidenav>`
218  *   - `<md-sidenav md-is-locked-open="$mdMedia('min-width: 1000px')"></md-sidenav>`
219  *   - `<md-sidenav md-is-locked-open="$mdMedia('sm')"></md-sidenav>` (locks open on small screens)
220  */
221 function SidenavDirective($timeout, $animate, $parse, $log, $mdMedia, $mdConstant, $compile, $mdTheming, $q, $document) {
222   return {
223     restrict: 'E',
224     scope: {
225       isOpen: '=?mdIsOpen'
226     },
227     controller: '$mdSidenavController',
228     compile: function(element) {
229       element.addClass('md-closed');
230       element.attr('tabIndex', '-1');
231       return postLink;
232     }
233   };
234
235   /**
236    * Directive Post Link function...
237    */
238   function postLink(scope, element, attr, sidenavCtrl) {
239     var lastParentOverFlow;
240     var triggeringElement = null;
241     var promise = $q.when(true);
242
243     var isLockedOpenParsed = $parse(attr.mdIsLockedOpen);
244     var isLocked = function() {
245       return isLockedOpenParsed(scope.$parent, {
246         $media: function(arg) {
247           $log.warn("$media is deprecated for is-locked-open. Use $mdMedia instead.");
248           return $mdMedia(arg);
249         },
250         $mdMedia: $mdMedia
251       });
252     };
253     var backdrop = $compile(
254       '<md-backdrop class="md-sidenav-backdrop md-opaque ng-enter">'
255     )(scope);
256
257     element.on('$destroy', sidenavCtrl.destroy);
258     $mdTheming.inherit(backdrop, element);
259
260     scope.$watch(isLocked, updateIsLocked);
261     scope.$watch('isOpen', updateIsOpen);
262
263
264     // Publish special accessor for the Controller instance
265     sidenavCtrl.$toggleOpen = toggleOpen;
266     sidenavCtrl.focusElement( sidenavCtrl.focusElement() || element );
267
268     /**
269      * Toggle the DOM classes to indicate `locked`
270      * @param isLocked
271      */
272     function updateIsLocked(isLocked, oldValue) {
273       scope.isLockedOpen = isLocked;
274       if (isLocked === oldValue) {
275         element.toggleClass('md-locked-open', !!isLocked);
276       } else {
277         $animate[isLocked ? 'addClass' : 'removeClass'](element, 'md-locked-open');
278       }
279       backdrop.toggleClass('md-locked-open', !!isLocked);
280     }
281
282     /**
283      * Toggle the SideNav view and attach/detach listeners
284      * @param isOpen
285      */
286     function updateIsOpen(isOpen) {
287       var parent = element.parent();
288
289       parent[isOpen ? 'on' : 'off']('keydown', onKeyDown);
290       backdrop[isOpen ? 'on' : 'off']('click', close);
291
292       if ( isOpen ) {
293         // Capture upon opening..
294         triggeringElement = $document[0].activeElement;
295       }
296       var focusEl = sidenavCtrl.focusElement();
297
298       disableParentScroll(isOpen);
299
300       return promise = $q.all([
301                 isOpen ? $animate.enter(backdrop, parent) : $animate.leave(backdrop),
302                 $animate[isOpen ? 'removeClass' : 'addClass'](element, 'md-closed')
303               ])
304               .then(function() {
305                 // Perform focus when animations are ALL done...
306                 if (scope.isOpen) {
307                   focusEl && focusEl.focus();
308                 }
309               });
310     }
311
312     /**
313      * Prevent parent scrolling (when the SideNav is open)
314      */
315     function disableParentScroll(disabled) {
316       var parent = element.parent();
317       if ( disabled ) {
318         lastParentOverFlow = parent.css('overflow');
319         parent.css('overflow', 'hidden');
320       } else if (angular.isDefined(lastParentOverFlow)) {
321         parent.css('overflow', lastParentOverFlow);
322         lastParentOverFlow = undefined;
323       }
324     }
325
326     /**
327      * Toggle the sideNav view and publish a promise to be resolved when
328      * the view animation finishes.
329      *
330      * @param isOpen
331      * @returns {*}
332      */
333     function toggleOpen( isOpen ) {
334       if (scope.isOpen == isOpen ) {
335
336         return $q.when(true);
337
338       } else {
339         var deferred = $q.defer();
340
341         // Toggle value to force an async `updateIsOpen()` to run
342         scope.isOpen = isOpen;
343
344         $timeout(function() {
345
346           // When the current `updateIsOpen()` animation finishes
347           promise.then(function(result) {
348
349             if ( !scope.isOpen ) {
350               // reset focus to originating element (if available) upon close
351               triggeringElement && triggeringElement.focus();
352               triggeringElement = null;
353             }
354
355             deferred.resolve(result);
356           });
357
358         },0,false);
359
360         return deferred.promise;
361       }
362     }
363
364     /**
365      * Auto-close sideNav when the `escape` key is pressed.
366      * @param evt
367      */
368     function onKeyDown(ev) {
369       var isEscape = (ev.keyCode === $mdConstant.KEY_CODE.ESCAPE);
370       return isEscape ? close(ev) : $q.when(true);
371     }
372
373     /**
374      * With backdrop `clicks` or `escape` key-press, immediately
375      * apply the CSS close transition... Then notify the controller
376      * to close() and perform its own actions.
377      */
378     function close(ev) {
379       ev.preventDefault();
380       ev.stopPropagation();
381
382       return sidenavCtrl.close();
383     }
384
385   }
386 }
387 SidenavDirective.$inject = ["$timeout", "$animate", "$parse", "$log", "$mdMedia", "$mdConstant", "$compile", "$mdTheming", "$q", "$document"];
388
389 /*
390  * @private
391  * @ngdoc controller
392  * @name SidenavController
393  * @module material.components.sidenav
394  *
395  */
396 function SidenavController($scope, $element, $attrs, $mdComponentRegistry, $q) {
397
398   var self = this,
399       focusElement;
400
401   // Use Default internal method until overridden by directive postLink
402
403   // Synchronous getters
404   self.isOpen = function() { return !!$scope.isOpen; };
405   self.isLockedOpen = function() { return !!$scope.isLockedOpen; };
406
407   // Async actions
408   self.open   = function() { return self.$toggleOpen( true );  };
409   self.close  = function() { return self.$toggleOpen( false ); };
410   self.toggle = function() { return self.$toggleOpen( !$scope.isOpen );  };
411   self.focusElement = function(el) {
412     if ( angular.isDefined(el) ) {
413       focusElement = el;
414     }
415     return focusElement;
416   };
417
418   self.$toggleOpen = function() { return $q.when($scope.isOpen); };
419
420   self.destroy = $mdComponentRegistry.register(self, $attrs.mdComponentId);
421 }
422 SidenavController.$inject = ["$scope", "$element", "$attrs", "$mdComponentRegistry", "$q"];
423
424 })(window, window.angular);