|
18 | 18 | * |
19 | 19 | * @param {string} brandSrc src for brand image |
20 | 20 | * @param {string} brandAlt Text for product name when brand image is not available |
21 | | - * @param {boolean} hasSubMenus Flag if there are secondary and/or tertiary navigation items, default: true |
| 21 | + * @param {boolean} showBadges Flag if badges are used on navigation items, default: false |
22 | 22 | * @param {boolean} persistentSecondary Flag to use persistent secondary menus, default: false |
23 | 23 | * @param {boolean} hiddenIcons Flag to not show icons on the primary menu, default: false |
24 | 24 | * @param {array} items List of navigation items |
|
27 | 27 | * <li>.iconClass - (string) Classes for icon to be shown on the menu (ex. "fa fa-dashboard") |
28 | 28 | * <li>.href - (string) href link to navigate to on click |
29 | 29 | * <li>.children - (array) Submenu items (same structure as top level items) |
| 30 | + * <li>.badges - (array) Badges to display for the item, badges with a zero count are not displayed. |
| 31 | + * <ul style='list-style-type: none'> |
| 32 | + * <li>.count - (number) Count to display in the badge |
| 33 | + * <li>.iconClass - (string) Class to use for showing an icon before the count |
| 34 | + * <li>.tooltip - (string) Tooltip to display for the badge |
| 35 | + * <li>.badgeClass: - (string) Additional class(es) to add to the badge container |
| 36 | + * </ul> |
30 | 37 | * </ul> |
31 | 38 | * @param {function} navigateCallback function(item) Callback method invoked on a navigation item click (one with no submenus) |
32 | 39 | * @param {function} itemClickCallback function(item) Callback method invoked on an item click |
|
43 | 50 | </div> |
44 | 51 | <div id="verticalNavLayout" class="layout-pf layout-pf-fixed faux-layout hidden" ng-controller="vertNavController"> |
45 | 52 | <div pf-vertical-navigation items="navigationItems" brand-alt="ANGULAR PATTERNFLY" |
46 | | - has-sub-menus="true" pinnable-menus="true" update-active-items-on-click="true" |
| 53 | + show-badges="true" pinnable-menus="true" update-active-items-on-click="true" |
47 | 54 | navigate-callback="handleNavigateClick"> |
48 | 55 | <div> |
49 | 56 | <ul class="nav navbar-nav"> |
|
75 | 82 | </ul> |
76 | 83 | </div> |
77 | 84 | </div> |
78 | | - <div id="contentContainer" class="container-fluid container-cards-pf container-pf-nav-pf-vertical container-pf-nav-pf-vertical-with-sub-menus example-page-container"> |
| 85 | + <div id="contentContainer" class="container-fluid container-cards-pf container-pf-nav-pf-vertical example-page-container"> |
79 | 86 | <div id="includedContent"></div> |
80 | 87 | </div> |
81 | 88 | </div> |
|
92 | 99 | { |
93 | 100 | title: "Dolor", |
94 | 101 | iconClass : "fa fa-shield", |
95 | | - href: "#/dolor" |
| 102 | + href: "#/dolor", |
| 103 | + badges: [ |
| 104 | + { |
| 105 | + count: 1283, |
| 106 | + tooltip: "Total number of items" |
| 107 | + } |
| 108 | + ] |
96 | 109 | }, |
97 | 110 | { |
98 | 111 | title: "Ipsum", |
|
103 | 116 | children: [ |
104 | 117 | { |
105 | 118 | title: "Recteque", |
106 | | - href: "#/ipsum/intellegam/recteque" |
| 119 | + href: "#/ipsum/intellegam/recteque", |
| 120 | + badges: [ |
| 121 | + { |
| 122 | + count: 6, |
| 123 | + tooltip: "Total number of error items", |
| 124 | + badgeClass: 'example-error-background' |
| 125 | + } |
| 126 | + ] |
107 | 127 | }, |
108 | 128 | { |
109 | 129 | title: "Suavitate", |
110 | | - href: "#/ipsum/intellegam/suavitate" |
| 130 | + href: "#/ipsum/intellegam/suavitate", |
| 131 | + badges: [ |
| 132 | + { |
| 133 | + count: 2, |
| 134 | + tooltip: "Total number of items" |
| 135 | + } |
| 136 | + ] |
111 | 137 | }, |
112 | 138 | { |
113 | 139 | title: "Vituperatoribus", |
114 | | - href: "#/ipsum/intellegam/vituperatoribus" |
| 140 | + href: "#/ipsum/intellegam/vituperatoribus", |
| 141 | + badges: [ |
| 142 | + { |
| 143 | + count: 18, |
| 144 | + tooltip: "Total number of warning items", |
| 145 | + badgeClass: 'example-warning-background' |
| 146 | + } |
| 147 | + ] |
115 | 148 | } |
116 | 149 | ] |
117 | 150 | }, |
|
120 | 153 | children: [ |
121 | 154 | { |
122 | 155 | title: "Exerci", |
123 | | - href: "#/ipsum/copiosae/exerci" |
| 156 | + href: "#/ipsum/copiosae/exerci", |
| 157 | + badges: [ |
| 158 | + { |
| 159 | + count: 2, |
| 160 | + tooltip: "Total number of error items", |
| 161 | + iconClass: 'pficon pficon-error-circle-o' |
| 162 | + }, |
| 163 | + { |
| 164 | + count: 6, |
| 165 | + tooltip: "Total number warning error items", |
| 166 | + iconClass: 'pficon pficon-warning-triangle-o' |
| 167 | + } |
| 168 | + ] |
124 | 169 | }, |
125 | 170 | { |
126 | 171 | title: "Quaeque", |
127 | | - href: "#/ipsum/copiosae/quaeque" |
| 172 | + href: "#/ipsum/copiosae/quaeque", |
| 173 | + badges: [ |
| 174 | + { |
| 175 | + count: 0, |
| 176 | + tooltip: "Total number of error items", |
| 177 | + iconClass: 'pficon pficon-error-circle-o' |
| 178 | + }, |
| 179 | + { |
| 180 | + count: 4, |
| 181 | + tooltip: "Total number warning error items", |
| 182 | + iconClass: 'pficon pficon-warning-triangle-o' |
| 183 | + } |
| 184 | + ] |
128 | 185 | }, |
129 | 186 | { |
130 | 187 | title: "Utroque", |
131 | | - href: "#/ipsum/copiosae/utroque" |
| 188 | + href: "#/ipsum/copiosae/utroque", |
| 189 | + badges: [ |
| 190 | + { |
| 191 | + count: 1, |
| 192 | + tooltip: "Total number of error items", |
| 193 | + iconClass: 'pficon pficon-error-circle-o' |
| 194 | + }, |
| 195 | + { |
| 196 | + count: 2, |
| 197 | + tooltip: "Total number warning error items", |
| 198 | + iconClass: 'pficon pficon-warning-triangle-o' |
| 199 | + } |
| 200 | + ] |
132 | 201 | } |
133 | 202 | ] |
134 | 203 | }, |
|
151 | 220 | }, |
152 | 221 | { |
153 | 222 | title: "Accumsan", |
154 | | - href: "#/ipsum/Accumsan" |
| 223 | + href: "#/ipsum/Accumsan", |
| 224 | + badges: [ |
| 225 | + { |
| 226 | + count: 2, |
| 227 | + tooltip: "Total number of error items", |
| 228 | + iconClass: 'pficon pficon-error-circle-o' |
| 229 | + }, |
| 230 | + { |
| 231 | + count: 6, |
| 232 | + tooltip: "Total number warning error items", |
| 233 | + iconClass: 'pficon pficon-warning-triangle-o' |
| 234 | + } |
| 235 | + ] |
155 | 236 | } |
156 | 237 | ] |
157 | 238 | }, |
|
492 | 573 | scope: { |
493 | 574 | brandSrc: '@', |
494 | 575 | brandAlt: '@', |
495 | | - hasSubMenus: '@', |
| 576 | + showBadges: '@', |
496 | 577 | persistentSecondary: '@', |
497 | 578 | pinnableMenus: '@', |
498 | 579 | hiddenIcons: '@', |
|
508 | 589 | controller: function ($scope) { |
509 | 590 | var routeChangeListener; |
510 | 591 |
|
511 | | - $scope.hasSubMenus = $scope.hasSubMenus !== 'false'; |
| 592 | + $scope.showBadges = $scope.showBadges === 'true'; |
512 | 593 | $scope.persistentSecondary = $scope.persistentSecondary === 'true'; |
513 | 594 | $scope.pinnableMenus = $scope.pinnableMenus === 'true'; |
514 | 595 | $scope.hiddenIcons = $scope.hiddenIcons === 'true'; |
515 | 596 | $scope.updateActiveItemsOnClick = $scope.updateActiveItemsOnClick === 'true'; |
516 | 597 | $scope.ignoreMobile = $scope.ignoreMobile === 'true'; |
| 598 | + $scope.activeSecondary = false; |
517 | 599 |
|
518 | 600 | $scope.clearActiveItems = function () { |
519 | 601 | $scope.items.forEach(function (item) { |
|
573 | 655 | 'desktop': 1200 |
574 | 656 | }; |
575 | 657 |
|
576 | | - var bodyContentElement = angular.element(document.querySelector('.container-pf-nav-pf-vertical')); |
| 658 | + var getBodyContentElement = function () { |
| 659 | + return angular.element(document.querySelector('.container-pf-nav-pf-vertical')); |
| 660 | + }; |
| 661 | + |
577 | 662 | var explicitCollapse = false; |
578 | 663 | var hoverDelay = 500; |
579 | 664 | var hideDelay = hoverDelay + 200; |
580 | 665 |
|
| 666 | + var initBodyElement = function () { |
| 667 | + var bodyContentElement = getBodyContentElement(); |
| 668 | + if ($scope.showBadges) { |
| 669 | + bodyContentElement.addClass('nav-pf-vertical-with-badges'); |
| 670 | + } |
| 671 | + if ($scope.persistentSecondary) { |
| 672 | + bodyContentElement.addClass('nav-pf-persistent-secondary'); |
| 673 | + } |
| 674 | + if ($scope.hiddenIcons) { |
| 675 | + bodyContentElement.addClass('hidden-icons-pf'); |
| 676 | + } |
| 677 | + }; |
| 678 | + |
581 | 679 | var updateMobileMenu = function (selected, secondaryItem) { |
582 | 680 | $scope.items.forEach(function (item) { |
583 | 681 | item.isMobileItem = false; |
|
606 | 704 |
|
607 | 705 | var checkNavState = function () { |
608 | 706 | var width = $window.innerWidth; |
| 707 | + var bodyContentElement = getBodyContentElement(); |
609 | 708 |
|
610 | 709 | // Check to see if we need to enter/exit the mobile state |
611 | 710 | if (!$scope.ignoreMobile && width < breakpoints.tablet) { |
|
640 | 739 | }; |
641 | 740 |
|
642 | 741 | var collapseMenu = function () { |
| 742 | + var bodyContentElement = getBodyContentElement(); |
643 | 743 | $scope.navCollapsed = true; |
644 | 744 |
|
645 | 745 | //Set the body class to the correct state |
|
649 | 749 | }; |
650 | 750 |
|
651 | 751 | var expandMenu = function () { |
| 752 | + var bodyContentElement = getBodyContentElement(); |
652 | 753 | $scope.navCollapsed = false; |
653 | 754 |
|
654 | 755 | //Set the body class to the correct state |
|
668 | 769 | }, 500); |
669 | 770 | }; |
670 | 771 |
|
671 | | - var setFirstChildActive = function (item) { |
672 | | - if (item && item.children && item.children.length > 0) { |
673 | | - if ($scope.updateActiveItemsOnClick ) { |
674 | | - item.children[0].isActive = true; |
675 | | - } |
676 | | - setFirstChildActive(item.children[0]); |
677 | | - } else if (item && $scope.navigateCallback) { |
678 | | - $scope.navigateCallback(item); |
679 | | - } |
680 | | - }; |
681 | | - |
682 | 772 | var setParentActive = function (item) { |
683 | 773 | $scope.items.forEach(function (topLevel) { |
684 | 774 | if (topLevel.children) { |
|
699 | 789 | }); |
700 | 790 | }; |
701 | 791 |
|
702 | | - var navigateToItem = function (item) { |
703 | | - var navTo = item.href; |
| 792 | + var getFirstNavigateChild = function (item) { |
| 793 | + var firstChild; |
704 | 794 | if (!item.children || item.children.length < 1) { |
| 795 | + firstChild = item; |
| 796 | + } else { |
| 797 | + firstChild = getFirstNavigateChild(item.children[0]); |
| 798 | + } |
| 799 | + return firstChild; |
| 800 | + }; |
| 801 | + |
| 802 | + var setSecondaryItemVisible = function () { |
| 803 | + var bodyContentElement = getBodyContentElement(); |
| 804 | + $scope.activeSecondary = false; |
| 805 | + |
| 806 | + if ($scope.persistentSecondary && !$scope.inMobileState) { |
| 807 | + $scope.items.forEach(function (topLevel) { |
| 808 | + if (topLevel.children) { |
| 809 | + topLevel.children.forEach(function (secondLevel) { |
| 810 | + if (secondLevel.isActive) { |
| 811 | + $scope.activeSecondary = true; |
| 812 | + } |
| 813 | + }); |
| 814 | + } |
| 815 | + }); |
| 816 | + if ($scope.activeSecondary) { |
| 817 | + bodyContentElement.addClass('secondary-visible-pf'); |
| 818 | + } else { |
| 819 | + bodyContentElement.removeClass('secondary-visible-pf'); |
| 820 | + } |
| 821 | + } |
| 822 | + }; |
| 823 | + |
| 824 | + var navigateToItem = function (item) { |
| 825 | + var navItem = getFirstNavigateChild(item); |
| 826 | + var navTo; |
| 827 | + if (navItem) { |
705 | 828 | $scope.showMobileNav = false; |
| 829 | + navTo = navItem.href; |
706 | 830 | if (navTo) { |
707 | 831 | if (navTo.startsWith('#/')) { |
708 | 832 | navTo = navTo.substring(2); |
709 | 833 | } |
710 | 834 | location.path(navTo); |
711 | 835 | } |
712 | 836 | if ($scope.navigateCallback) { |
713 | | - $scope.navigateCallback(item); |
| 837 | + $scope.navigateCallback(navItem); |
714 | 838 | } |
715 | 839 | } |
716 | 840 |
|
|
720 | 844 |
|
721 | 845 | if ($scope.updateActiveItemsOnClick ) { |
722 | 846 | $scope.clearActiveItems(); |
723 | | - item.isActive = true; |
724 | | - setParentActive(item); |
| 847 | + navItem.isActive = true; |
| 848 | + setParentActive(navItem); |
| 849 | + setSecondaryItemVisible(); |
725 | 850 | } |
726 | | - |
727 | | - setFirstChildActive(item); |
| 851 | + setSecondaryItemVisible(); |
728 | 852 | }; |
729 | 853 |
|
730 | 854 | var primaryHover = function () { |
|
752 | 876 | }; |
753 | 877 |
|
754 | 878 | var updateSecondaryCollapsedState = function (setCollapsed, collapsedItem) { |
| 879 | + var bodyContentElement = getBodyContentElement(); |
755 | 880 | if (collapsedItem) { |
756 | 881 | collapsedItem.secondaryCollapsed = setCollapsed; |
757 | 882 | } |
|
773 | 898 | }; |
774 | 899 |
|
775 | 900 | var updateTertiaryCollapsedState = function (setCollapsed, collapsedItem) { |
| 901 | + var bodyContentElement = getBodyContentElement(); |
776 | 902 | if (collapsedItem) { |
777 | 903 | collapsedItem.tertiaryCollapsed = setCollapsed; |
778 | 904 | } |
|
808 | 934 | $scope.navCollapsed = false; |
809 | 935 | $scope.forceHidden = false; |
810 | 936 |
|
811 | | - if ($scope.hasSubMenus) { |
812 | | - bodyContentElement.addClass('container-pf-nav-pf-vertical-with-sub-menus'); |
813 | | - } |
814 | | - if ($scope.persistentSecondary) { |
815 | | - bodyContentElement.addClass('nav-pf-persistent-secondary'); |
816 | | - } |
817 | | - if ($scope.hiddenIcons) { |
818 | | - bodyContentElement.addClass('hidden-icons-pf'); |
819 | | - } |
820 | | - |
821 | 937 | $scope.handleNavBarToggleClick = function () { |
822 | 938 |
|
823 | 939 | if ($scope.inMobileState) { |
|
981 | 1097 | event.stopImmediatePropagation(); |
982 | 1098 | }; |
983 | 1099 |
|
| 1100 | + initBodyElement(); |
984 | 1101 | checkNavState(); |
985 | 1102 |
|
986 | 1103 | angular.element($window).bind('resize', function () { |
|
0 commit comments