source: trip-planner-front/node_modules/angular-material/modules/js/navBar/navBar.js@ 6a3a178

Last change on this file since 6a3a178 was 6a3a178, checked in by Ema <ema_spirova@…>, 3 years ago

initial commit

  • Property mode set to 100644
File size: 23.4 KB
Line 
1/*!
2 * AngularJS Material Design
3 * https://github.com/angular/material
4 * @license MIT
5 * v1.2.3
6 */
7(function( window, angular, undefined ){
8"use strict";
9
10/**
11 * @ngdoc module
12 * @name material.components.navBar
13 */
14MdNavBar['$inject'] = ["$mdAria", "$mdTheming", "$window", "$mdUtil"];
15MdNavBarController['$inject'] = ["$element", "$scope", "$timeout", "$mdConstant"];
16MdNavItem['$inject'] = ["$mdAria", "$$rAF", "$mdUtil", "$window"];
17MdNavItemController['$inject'] = ["$element"];
18angular.module('material.components.navBar', ['material.core'])
19 .controller('MdNavBarController', MdNavBarController)
20 .directive('mdNavBar', MdNavBar)
21 .controller('MdNavItemController', MdNavItemController)
22 .directive('mdNavItem', MdNavItem);
23
24/**
25 * @ngdoc directive
26 * @name mdNavBar
27 * @module material.components.navBar
28 *
29 * @restrict E
30 *
31 * @description
32 * The `<md-nav-bar>` directive renders a list of material tabs that can be used
33 * for top-level page navigation. Unlike `<md-tabs>`, it has no concept of a tab
34 * body and no bar pagination.
35 *
36 * Because it deals with page navigation, certain routing concepts are built-in.
37 * Route changes via `ng-href`, `ui-sref`, or `ng-click` events are supported.
38 * Alternatively, the user could simply watch the value of `md-selected-nav-item`
39 * (`currentNavItem` in the below example) for changes.
40 *
41 * Accessibility functionality is implemented as a
42 * <a href="https://www.w3.org/TR/wai-aria-1.0/complete#tablist">
43 * tablist</a> with
44 * <a href="https://www.w3.org/TR/wai-aria-1.0/complete#tab">tabs</a>.
45 * We've kept the `role="navigation"` on the `<nav>`, for backwards compatibility, even though
46 * it is not required in the
47 * <a href="https://www.w3.org/TR/wai-aria-practices/#aria_lh_navigation">
48 * latest Working Group Note from December 2017</a>.
49 *
50 * <h3>Keyboard Navigation</h3>
51 * - `Tab`/`Shift+Tab` moves the focus to the next/previous interactive element on the page
52 * - `Enter`/`Space` selects the focused nav item and navigates to display the item's contents
53 * - `Right`/`Down` moves focus to the next nav item, wrapping at the end
54 * - `Left`/`Up` moves focus to the previous nav item, wrapping at the end
55 * - `Home`/`End` moves the focus to the first/last nav item
56 *
57 * @param {string=} md-selected-nav-item The name of the current tab; this must
58 * match the `name` attribute of `<md-nav-item>`.
59 * @param {boolean=} md-no-ink-bar If set to true, the ink bar will be hidden.
60 * @param {string=} nav-bar-aria-label An `aria-label` applied to the `md-nav-bar`'s tablist
61 * for accessibility.
62 *
63 * @usage
64 * <hljs lang="html">
65 * <md-nav-bar md-selected-nav-item="currentNavItem">
66 * <md-nav-item md-nav-click="goto('page1')" name="page1">
67 * Page One
68 * </md-nav-item>
69 * <md-nav-item md-nav-href="#page2" name="page3">Page Two</md-nav-item>
70 * <md-nav-item md-nav-sref="page3" name="page2">Page Three</md-nav-item>
71 * <md-nav-item
72 * md-nav-sref="app.page4"
73 * sref-opts="{reload: true, notify: true}"
74 * name="page4">
75 * Page Four
76 * </md-nav-item>
77 * </md-nav-bar>
78 *</hljs>
79 * <hljs lang="js">
80 * (function() {
81 * 'use strict';
82 *
83 * $rootScope.$on('$routeChangeSuccess', function(event, current) {
84 * $scope.currentLink = getCurrentLinkFromRoute(current);
85 * });
86 * });
87 * </hljs>
88 */
89/**
90 * @param $mdAria
91 * @param $mdTheming
92 * @param $window
93 * @param $mdUtil
94 * @constructor
95 * ngInject
96 */
97function MdNavBar($mdAria, $mdTheming, $window, $mdUtil) {
98 return {
99 restrict: 'E',
100 transclude: true,
101 controller: MdNavBarController,
102 controllerAs: 'ctrl',
103 bindToController: true,
104 scope: {
105 'mdSelectedNavItem': '=?',
106 'mdNoInkBar': '=?',
107 'navBarAriaLabel': '@?',
108 },
109 template:
110 '<div class="md-nav-bar">' +
111 '<nav role="navigation">' +
112 '<ul class="_md-nav-bar-list" ng-transclude role="tablist" ' +
113 'ng-focus="ctrl.onFocus()" ' + // Deprecated but kept for now in order to not break tests
114 'aria-label="{{ctrl.navBarAriaLabel}}">' +
115 '</ul>' +
116 '</nav>' +
117 '<md-nav-ink-bar ng-hide="ctrl.mdNoInkBar"></md-nav-ink-bar>' +
118 '</div>',
119 link: function(scope, element, attrs, ctrl) {
120
121 ctrl.width = $window.innerWidth;
122
123 function onResize() {
124 if (ctrl.width !== $window.innerWidth) {
125 ctrl.updateSelectedTabInkBar();
126 ctrl.width = $window.innerWidth;
127 scope.$digest();
128 }
129 }
130
131 function cleanUp() {
132 angular.element($window).off('resize', onResize);
133 }
134
135 angular.element($window).on('resize', $mdUtil.debounce(onResize, 300));
136 scope.$on('$destroy', cleanUp);
137
138 $mdTheming(element);
139 if (!ctrl.navBarAriaLabel) {
140 $mdAria.expectAsync(element, 'aria-label', angular.noop);
141 }
142 },
143 };
144}
145
146/**
147 * Controller for the nav-bar component.
148 * Accessibility functionality is implemented as a tablist
149 * (https://www.w3.org/TR/wai-aria-1.0/complete#tablist) and
150 * tabs (https://www.w3.org/TR/wai-aria-1.0/complete#tab).
151 *
152 * @param {!JQLite} $element
153 * @param {!IScope} $scope
154 * @param {!ITimeoutService} $timeout
155 * @param {!Object} $mdConstant
156 * @constructor
157 * @final
158 * ngInject
159 */
160function MdNavBarController($element, $scope, $timeout, $mdConstant) {
161 // Injected variables
162 /**
163 * @private @const
164 * @type {!ITimeoutService}
165 */
166 this._$timeout = $timeout;
167
168 /**
169 * @private @const
170 * @type {!IScope}
171 */
172 this._$scope = $scope;
173
174 /**
175 * @private @const
176 * @type {!Object}
177 */
178 this._$mdConstant = $mdConstant;
179
180 // Data-bound variables.
181 /** @type {?string} */
182 this.mdSelectedNavItem;
183
184 /** @type {?string} */
185 this.navBarAriaLabel;
186
187 // State variables.
188 /** @type {?HTMLElement} */
189 this._navBarEl = $element[0];
190
191 /** @type {?JQLite} */
192 this._inkbar;
193
194 var self = this;
195 // need to wait for transcluded content to be available
196 var deregisterTabWatch = this._$scope.$watch(function() {
197 return self._navBarEl.querySelectorAll('._md-nav-button').length;
198 },
199 function(newLength) {
200 if (newLength > 0) {
201 self._initTabs();
202 deregisterTabWatch();
203 }
204 });
205}
206
207/**
208 * Initializes the tab components once they exist.
209 * @private
210 */
211MdNavBarController.prototype._initTabs = function() {
212 this._inkbar = angular.element(this._navBarEl.querySelector('md-nav-ink-bar'));
213
214 var self = this;
215 this._$timeout(function() {
216 self._updateTabs(self.mdSelectedNavItem, null);
217 });
218
219 this._$scope.$watch('ctrl.mdSelectedNavItem', function(newValue, oldValue) {
220 // Wait a digest before update tabs for products doing
221 // anything dynamic in the template.
222 self._$timeout(function() {
223 self._updateTabs(newValue, oldValue);
224 });
225 });
226};
227
228/**
229 * Set the current tab to be selected.
230 * @param {string|undefined} newValue New current tab name.
231 * @param {string|undefined|null} oldValue Previous tab name.
232 * @private
233 */
234MdNavBarController.prototype._updateTabs = function(newValue, oldValue) {
235 var self = this;
236 var tabs = this._getTabs();
237 var sameTab = newValue === oldValue;
238
239 // this._getTabs can return null if nav-bar has not yet been initialized
240 if (!tabs) return;
241
242 var newIndex = -1;
243 var newTab = this._getTabByName(newValue);
244 var oldTab = this._getTabByName(oldValue);
245
246 if (oldTab) {
247 oldTab.setSelected(false);
248 }
249
250 if (newTab) {
251 newTab.setSelected(true);
252 newIndex = tabs.indexOf(newTab);
253 }
254
255 this._$timeout(function() {
256 self._updateInkBarStyles(newTab, newIndex);
257 // Don't change focus when there is no newTab, the new and old tabs are the same, or when
258 // called from MdNavBarController._initTabs() which would have no oldTab defined.
259 if (newTab && oldTab && !sameTab) {
260 self._moveFocus(oldTab, newTab);
261 }
262 });
263};
264
265/**
266 * Repositions the ink bar to the selected tab.
267 * @param {MdNavItemController} tab the nav item that should have ink bar styles applied
268 * @param {number=} newIndex the index of the newly selected nav item
269 * @private
270 */
271MdNavBarController.prototype._updateInkBarStyles = function(tab, newIndex) {
272 this._inkbar.css({display: newIndex < 0 ? 'none' : ''});
273
274 if (tab) {
275 var tabEl = tab.getButtonEl();
276 var left = tabEl.offsetLeft;
277 var tabWidth = tabEl.offsetWidth;
278 var navBarWidth = this._navBarEl.getBoundingClientRect().width;
279 var scale = tabWidth / navBarWidth;
280 var translate = left / navBarWidth * 100;
281
282 this._inkbar.css({ transform: 'translateX(' + translate + '%) scaleX(' + scale + ')' });
283 }
284};
285
286/**
287 * Updates ink bar to match current tab.
288 */
289MdNavBarController.prototype.updateSelectedTabInkBar = function() {
290 this._updateInkBarStyles(this._getSelectedTab());
291};
292
293/**
294 * Returns an array of the current tabs.
295 * @return {Array<!MdNavItemController>}
296 * @private
297 */
298MdNavBarController.prototype._getTabs = function() {
299 var controllers = Array.prototype.slice.call(
300 this._navBarEl.querySelectorAll('.md-nav-item'))
301 .map(function(el) {
302 return angular.element(el).controller('mdNavItem');
303 });
304 return controllers.indexOf(undefined) ? controllers : [];
305};
306
307/**
308 * Returns the tab with the specified name.
309 * @param {string} name The name of the tab, found in its name attribute.
310 * @return {MdNavItemController}
311 * @private
312 */
313MdNavBarController.prototype._getTabByName = function(name) {
314 return this._findTab(function(tab) {
315 return tab.getName() === name;
316 });
317};
318
319/**
320 * Returns the selected tab.
321 * @return {MdNavItemController}
322 * @private
323 */
324MdNavBarController.prototype._getSelectedTab = function() {
325 return this._findTab(function(tab) {
326 return tab.isSelected();
327 });
328};
329
330/**
331 * Returns the focused tab.
332 * @return {MdNavItemController}
333 */
334MdNavBarController.prototype.getFocusedTab = function() {
335 return this._findTab(function(tab) {
336 return tab.hasFocus();
337 });
338};
339
340/**
341 * Find a tab that matches the specified function, starting from the first tab.
342 * @param {Function} fn
343 * @param {number=} startIndex index to start at. Defaults to 0.
344 * @returns {MdNavItemController|null}
345 * @private
346 */
347MdNavBarController.prototype._findTab = function(fn, startIndex) {
348 var tabs = this._getTabs(), i;
349 if (startIndex == null) {
350 startIndex = 0;
351 }
352 for (i = startIndex; i < tabs.length; i++) {
353 if (fn(tabs[i])) {
354 return tabs[i];
355 }
356 }
357 return null;
358};
359
360/**
361 * Find a tab that matches the specified function, going backwards from the end of the list.
362 * @param {Function} fn
363 * @param {number=} startIndex index to start at. Defaults to tabs.length - 1.
364 * @returns {MdNavItemController}
365 * @private
366 */
367MdNavBarController.prototype._findTabReverse = function(fn, startIndex) {
368 var tabs = this._getTabs();
369 if (startIndex === undefined || startIndex === null) {
370 startIndex = tabs.length - 1;
371 }
372 for (var i = startIndex; i >= 0 ; i--) {
373 if (fn(tabs[i])) {
374 return tabs[i];
375 }
376 }
377 return null;
378};
379
380/**
381 * Direct focus to the selected tab when focus enters the nav bar.
382 */
383MdNavBarController.prototype.onFocus = function() {
384 var tab = this._getSelectedTab();
385 if (tab && !tab.isFocused) {
386 tab.setFocused(true);
387 }
388};
389
390/**
391 * Move focus from oldTab to newTab.
392 * @param {!MdNavItemController} oldTab
393 * @param {!MdNavItemController} newTab
394 * @private
395 */
396MdNavBarController.prototype._moveFocus = function(oldTab, newTab) {
397 oldTab.setFocused(false);
398 newTab.setFocused(true);
399};
400
401/**
402 * Focus the first tab.
403 * @private
404 */
405MdNavBarController.prototype._focusFirstTab = function() {
406 var tabs = this._getTabs();
407 if (!tabs) return;
408 var tabToFocus = this._findTab(function(tab) {
409 return tab._isEnabled();
410 });
411 if (tabToFocus) {
412 this._moveFocus(this.getFocusedTab(), tabToFocus);
413 }
414};
415
416/**
417 * Focus the last tab.
418 * @private
419 */
420MdNavBarController.prototype._focusLastTab = function() {
421 var tabs = this._getTabs();
422 if (!tabs) return;
423 var tabToFocus = this._findTabReverse(function(tab) {
424 return tab._isEnabled();
425 });
426 if (tabToFocus) {
427 this._moveFocus(this.getFocusedTab(), tabToFocus);
428 }
429};
430
431/**
432 * Focus the next non-disabled tab.
433 * @param {number} focusedTabIndex the index of the currently focused tab
434 * @private
435 */
436MdNavBarController.prototype._focusNextTab = function(focusedTabIndex) {
437 var tabs = this._getTabs();
438 if (!tabs) return;
439 var tabToFocus = this._findTab(function(tab) {
440 return tab._isEnabled();
441 }, focusedTabIndex + 1);
442 if (tabToFocus) {
443 this._moveFocus(this.getFocusedTab(), tabToFocus);
444 } else {
445 this._focusFirstTab();
446 }
447};
448
449/**
450 * Focus the previous non-disabled tab.
451 * @param {number} focusedTabIndex the index of the currently focused tab
452 * @private
453 */
454MdNavBarController.prototype._focusPreviousTab = function(focusedTabIndex) {
455 var tabs = this._getTabs();
456 if (!tabs) return;
457 var tabToFocus = this._findTabReverse(function(tab) {
458 return tab._isEnabled();
459 }, focusedTabIndex - 1);
460 if (tabToFocus) {
461 this._moveFocus(this.getFocusedTab(), tabToFocus);
462 } else {
463 this._focusLastTab();
464 }
465};
466
467/**
468 * Responds to keydown events.
469 * Calls to preventDefault() stop the page from scrolling when changing focus in the nav-bar.
470 * @param {!KeyboardEvent} e
471 */
472MdNavBarController.prototype.onKeydown = function(e) {
473 var keyCodes = this._$mdConstant.KEY_CODE;
474 var tabs = this._getTabs();
475 var focusedTab = this.getFocusedTab();
476 if (!focusedTab || !tabs) return;
477
478 var focusedTabIndex = tabs.indexOf(focusedTab);
479
480 // use arrow keys to navigate between tabs
481 switch (e.keyCode) {
482 case keyCodes.UP_ARROW:
483 case keyCodes.LEFT_ARROW:
484 e.preventDefault();
485 this._focusPreviousTab(focusedTabIndex);
486 break;
487 case keyCodes.DOWN_ARROW:
488 case keyCodes.RIGHT_ARROW:
489 e.preventDefault();
490 this._focusNextTab(focusedTabIndex);
491 break;
492 case keyCodes.SPACE:
493 case keyCodes.ENTER:
494 // timeout to avoid a "digest already in progress" console error
495 this._$timeout(function() {
496 focusedTab.getButtonEl().click();
497 });
498 break;
499 case keyCodes.HOME:
500 e.preventDefault();
501 this._focusFirstTab();
502 break;
503 case keyCodes.END:
504 e.preventDefault();
505 this._focusLastTab();
506 break;
507 }
508};
509
510/**
511 * @ngdoc directive
512 * @name mdNavItem
513 * @module material.components.navBar
514 *
515 * @restrict E
516 *
517 * @description
518 * `<md-nav-item>` describes a page navigation link within the `<md-nav-bar>` component.
519 * It renders an `<md-button>` as the actual link.
520 *
521 * Exactly one of the `md-nav-click`, `md-nav-href`, or `md-nav-sref` attributes are required
522 * to be specified.
523 *
524 * @param {string=} nav-item-aria-label Allows setting or overriding the label that is announced by
525 * a screen reader for the nav item's button. If this is not set, the nav item's transcluded
526 * content will be announced. Make sure to set this if the nav item's transcluded content does
527 * not include descriptive text, for example only an icon.
528 * @param {expression=} md-nav-click Expression which will be evaluated when the
529 * link is clicked to change the page. Renders as an `ng-click`.
530 * @param {string=} md-nav-href url to transition to when this link is clicked.
531 * Renders as an `ng-href`.
532 * @param {string=} md-nav-sref UI-Router state to transition to when this link is
533 * clicked. Renders as a `ui-sref`.
534 * @param {string} name The name of this link. Used by the nav bar to know
535 * which link is currently selected.
536 * @param {!object=} sref-opts UI-Router options that are passed to the `$state.go()` function. See
537 * the <a ng-href="https://ui-router.github.io/docs/latest/interfaces/transition.transitionoptions.html"
538 * target="_blank">UI-Router documentation for details</a>.
539 *
540 * @usage
541 * See <a ng-href="api/directive/mdNavBar">md-nav-bar</a> for usage.
542 */
543/**
544 * @param $mdAria
545 * @param $$rAF
546 * @param $mdUtil
547 * @param $window
548 * @constructor
549 * ngInject
550 */
551function MdNavItem($mdAria, $$rAF, $mdUtil, $window) {
552 return {
553 restrict: 'E',
554 require: ['mdNavItem', '^mdNavBar'],
555 controller: MdNavItemController,
556 bindToController: true,
557 controllerAs: 'ctrl',
558 replace: true,
559 transclude: true,
560 template: function(tElement, tAttrs) {
561 var hasNavClick = tAttrs.mdNavClick;
562 var hasNavHref = tAttrs.mdNavHref;
563 var hasNavSref = tAttrs.mdNavSref;
564 var hasSrefOpts = tAttrs.srefOpts;
565 var navigationAttribute;
566 var navigationOptions;
567 var buttonTemplate;
568
569 // Cannot specify more than one nav attribute
570 if ((hasNavClick ? 1 : 0) + (hasNavHref ? 1 : 0) + (hasNavSref ? 1 : 0) > 1) {
571 throw Error(
572 'Please do not specify more than one of the md-nav-click, md-nav-href, ' +
573 'or md-nav-sref attributes per nav-item directive.'
574 );
575 }
576
577 if (hasNavClick !== undefined && hasNavClick !== null) {
578 navigationAttribute = 'ng-click="ctrl.mdNavClick()"';
579 } else if (hasNavHref !== undefined && hasNavHref !== null) {
580 navigationAttribute = 'ng-href="{{ctrl.mdNavHref}}"';
581 } else if (hasNavSref !== undefined && hasNavSref !== null) {
582 navigationAttribute = 'ui-sref="{{ctrl.mdNavSref}}"';
583 } else {
584 throw Error(
585 'Please specify at least one of the md-nav-click, md-nav-href, or md-nav-sref ' +
586 'attributes per nav-item directive.');
587 }
588
589 navigationOptions = hasSrefOpts ? 'ui-sref-opts="{{ctrl.srefOpts}}" ' : '';
590
591 if (navigationAttribute) {
592 buttonTemplate = '' +
593 '<md-button class="_md-nav-button md-accent" ' +
594 'ng-class="ctrl.getNgClassMap()" ' +
595 'ng-blur="ctrl.setFocused(false)" ' +
596 'ng-disabled="ctrl.disabled" ' +
597 'tabindex="-1" ' +
598 'role="tab" ' +
599 'ng-attr-aria-label="{{ctrl.navItemAriaLabel ? ctrl.navItemAriaLabel : undefined}}" ' +
600 'aria-selected="{{ctrl.isSelected()}}" ' +
601 navigationOptions +
602 navigationAttribute + '>' +
603 '<span ng-transclude class="_md-nav-button-text"></span>' +
604 '</md-button>';
605 }
606
607 return '' +
608 '<li class="md-nav-item" ' +
609 'role="presentation">' +
610 (buttonTemplate || '') +
611 '</li>';
612 },
613 scope: {
614 'mdNavClick': '&?',
615 'mdNavHref': '@?',
616 'mdNavSref': '@?',
617 'srefOpts': '=?',
618 'name': '@',
619 'navItemAriaLabel': '@?',
620 },
621 link: function(scope, element, attrs, controllers) {
622 var disconnect;
623 var mdNavItem;
624 var mdNavBar;
625 var navButton;
626
627 // When accessing the element's contents synchronously, they
628 // may not be defined yet because of transclusion. There is a higher
629 // chance that it will be accessible if we wait one frame.
630 $$rAF(function() {
631 mdNavItem = controllers[0];
632 mdNavBar = controllers[1];
633 navButton = angular.element(element[0].querySelector('._md-nav-button'));
634
635 if (!mdNavItem.name) {
636 mdNavItem.name = angular.element(element[0]
637 .querySelector('._md-nav-button-text')).text().trim();
638 }
639
640 navButton.on('keydown', function($event) {
641 mdNavBar.onKeydown($event);
642 });
643
644 navButton.on('focus', function() {
645 mdNavItem._focused = true;
646 });
647
648 navButton.on('click', function() {
649 // This triggers a watcher on mdNavBar.mdSelectedNavItem which calls
650 // MdNavBarController._updateTabs() after a $timeout. That function calls
651 // MdNavItemController.setSelected() for the old tab with false and the new tab with true.
652 mdNavBar.mdSelectedNavItem = mdNavItem.name;
653 scope.$apply();
654 });
655
656 // Get the disabled attribute value first, then setup observing of value changes
657 mdNavItem.disabled = $mdUtil.parseAttributeBoolean(attrs['disabled'], false);
658 if ('MutationObserver' in $window) {
659 var config = {attributes: true, attributeFilter: ['disabled']};
660 var targetNode = element[0];
661 var mutationCallback = function(mutationList) {
662 $mdUtil.nextTick(function() {
663 mdNavItem.disabled = $mdUtil.parseAttributeBoolean(attrs[mutationList[0].attributeName], false);
664 });
665 };
666 var observer = new MutationObserver(mutationCallback);
667 observer.observe(targetNode, config);
668 disconnect = observer.disconnect.bind(observer);
669 } else {
670 attrs.$observe('disabled', function (value) {
671 mdNavItem.disabled = $mdUtil.parseAttributeBoolean(value, false);
672 });
673 }
674
675 if (!mdNavItem.navItemAriaLabel) {
676 $mdAria.expectWithText(navButton, 'aria-label');
677 }
678 });
679
680 scope.$on('destroy', function() {
681 navButton.off('keydown');
682 navButton.off('focus');
683 navButton.off('click');
684 disconnect();
685 });
686 }
687 };
688}
689
690/**
691 * Controller for the nav-item component.
692 * @param {!JQLite} $element
693 * @constructor
694 * @final
695 * ngInject
696 */
697function MdNavItemController($element) {
698
699 /**
700 * @private @const
701 * @type {!JQLite}
702 */
703 this._$element = $element;
704
705 // Data-bound variables
706
707 /**
708 * @const
709 * @type {?Function}
710 */
711 this.mdNavClick;
712
713 /**
714 * @const
715 * @type {?string}
716 */
717 this.mdNavHref;
718
719 /**
720 * @const
721 * @type {?string}
722 */
723 this.mdNavSref;
724 /**
725 * @const
726 * @type {?Object}
727 */
728 this.srefOpts;
729 /**
730 * @const
731 * @type {?string}
732 */
733 this.name;
734
735 /**
736 * @const
737 * @type {string}
738 */
739 this.navItemAriaLabel;
740
741 // State variables
742 /**
743 * @private
744 * @type {boolean}
745 */
746 this._selected = false;
747
748 /**
749 * @type {boolean}
750 */
751 this.isFocused = false;
752}
753
754/**
755 * Returns a map of class names and values for use by ng-class.
756 * @return {!Object<string,boolean>}
757 */
758MdNavItemController.prototype.getNgClassMap = function() {
759 return {
760 'md-active': this._selected,
761 'md-primary': this._selected,
762 'md-unselected': !this._selected,
763 'md-focused': this.isFocused,
764 };
765};
766
767/**
768 * Get the name attribute of the tab.
769 * @return {string}
770 */
771MdNavItemController.prototype.getName = function() {
772 return this.name;
773};
774
775/**
776 * Get the button element associated with the tab.
777 * @return {!Element}
778 */
779MdNavItemController.prototype.getButtonEl = function() {
780 return this._$element[0].querySelector('._md-nav-button');
781};
782
783/**
784 * Set the selected state of the tab and updates the tabindex.
785 * This function is called for the oldTab and newTab when selection changes.
786 * @param {boolean} isSelected true to select the tab, false to deselect the tab
787 */
788MdNavItemController.prototype.setSelected = function(isSelected) {
789 this._selected = isSelected;
790 if (isSelected) {
791 // https://www.w3.org/TR/wai-aria-practices/examples/tabs/tabs-2/tabs.html suggests that we call
792 // removeAttribute('tabindex') here, but that causes our unit tests to fail due to
793 // document.activeElement staying set to the body instead of the focused nav button.
794 this.getButtonEl().setAttribute('tabindex', '0');
795 } else {
796 this.getButtonEl().setAttribute('tabindex', '-1');
797 }
798};
799
800/**
801 * @return {boolean}
802 */
803MdNavItemController.prototype.isSelected = function() {
804 return this._selected;
805};
806
807/**
808 * Set the focused state of the tab.
809 * @param {boolean} isFocused
810 */
811MdNavItemController.prototype.setFocused = function(isFocused) {
812 this.isFocused = isFocused;
813
814 if (isFocused) {
815 this.getButtonEl().focus();
816 }
817};
818
819/**
820 * @return {boolean} true if the tab has focus, false if not.
821 */
822MdNavItemController.prototype.hasFocus = function() {
823 return this.isFocused;
824};
825
826/**
827 * @return {boolean} true if the tab is enabled, false if disabled.
828 * @private
829 */
830MdNavItemController.prototype._isEnabled = function() {
831 return !this._$element.attr('disabled');
832};
833
834})(window, window.angular);
Note: See TracBrowser for help on using the repository browser.