diff --git a/packages/oui-action-menu/src/action-menu.component.js b/packages/oui-action-menu/src/action-menu.component.js index 05d7b936..3cb5758f 100644 --- a/packages/oui-action-menu/src/action-menu.component.js +++ b/packages/oui-action-menu/src/action-menu.component.js @@ -8,7 +8,8 @@ export default { text: "@", align: "@?", ariaLabel: "@?", - compact: " { diff --git a/packages/oui-clipboard/src/clipboard.provider.js b/packages/oui-clipboard/src/clipboard.provider.js index 5564aa7a..edd9ee49 100644 --- a/packages/oui-clipboard/src/clipboard.provider.js +++ b/packages/oui-clipboard/src/clipboard.provider.js @@ -1,4 +1,4 @@ -import { merge } from "lodash"; +import merge from "lodash/merge"; export default class { constructor () { this.translations = { diff --git a/packages/oui-clipboard/src/index.js b/packages/oui-clipboard/src/index.js index 7173ae55..54c8785b 100644 --- a/packages/oui-clipboard/src/index.js +++ b/packages/oui-clipboard/src/index.js @@ -1,6 +1,8 @@ -import Clipboard from "./clipboard.component.js"; -import ClipboardProvider from "./clipboard.provider.js"; - -angular - .module("oui.clipboard", []).component("ouiClipboard", Clipboard) - .provider("ouiClipboardConfiguration", ClipboardProvider); +import Clipboard from "./clipboard.component.js"; +import ClipboardProvider from "./clipboard.provider.js"; + +export default angular + .module("oui.clipboard", []) + .component("ouiClipboard", Clipboard) + .provider("ouiClipboardConfiguration", ClipboardProvider) + .name; diff --git a/packages/oui-collapsible/src/index.js b/packages/oui-collapsible/src/index.js index 447637a1..2a2f65a1 100644 --- a/packages/oui-collapsible/src/index.js +++ b/packages/oui-collapsible/src/index.js @@ -1,4 +1,6 @@ import Collapsible from "./collapsible.component.js"; -angular.module("oui.collapsible", []) - .component("ouiCollapsible", Collapsible); +export default angular + .module("oui.collapsible", []) + .component("ouiCollapsible", Collapsible) + .name; diff --git a/packages/oui-criteria-adder/src/criteria-adder.controller.js b/packages/oui-criteria-adder/src/criteria-adder.controller.js index fee4d2e6..df738e89 100644 --- a/packages/oui-criteria-adder/src/criteria-adder.controller.js +++ b/packages/oui-criteria-adder/src/criteria-adder.controller.js @@ -1,5 +1,5 @@ import { addDefaultParameter } from "@oui-angular/common/component-utils"; -import { get } from "lodash"; +import get from "lodash/get"; export default class { constructor ($attrs, $element, $scope, $timeout, ouiCriteriaAdderConfiguration) { diff --git a/packages/oui-criteria-adder/src/index.js b/packages/oui-criteria-adder/src/index.js index 016db6ee..f51b5754 100644 --- a/packages/oui-criteria-adder/src/index.js +++ b/packages/oui-criteria-adder/src/index.js @@ -1,7 +1,8 @@ import CriteriaAdder from "./criteria-adder.component"; import CriteriaAdderProvider from "./criteria-adder.provider"; -angular +export default angular .module("oui.criteria-adder", []) .component("ouiCriteriaAdder", CriteriaAdder) - .provider("ouiCriteriaAdderConfiguration", CriteriaAdderProvider); + .provider("ouiCriteriaAdderConfiguration", CriteriaAdderProvider) + .name; diff --git a/packages/oui-criteria-adder/src/index.spec.js b/packages/oui-criteria-adder/src/index.spec.js index 0b8896fa..6c504fb9 100644 --- a/packages/oui-criteria-adder/src/index.spec.js +++ b/packages/oui-criteria-adder/src/index.spec.js @@ -1,4 +1,4 @@ -import { find } from "lodash"; +import find from "lodash/find"; import mockData from "./index.spec.data.json"; const getValueComponent = $element => $element[0].querySelector("[name=barValue]"); diff --git a/packages/oui-criteria-container/src/criteria-container.controller.js b/packages/oui-criteria-container/src/criteria-container.controller.js index efe2fdf1..37fa3ce6 100644 --- a/packages/oui-criteria-container/src/criteria-container.controller.js +++ b/packages/oui-criteria-container/src/criteria-container.controller.js @@ -1,4 +1,4 @@ -import { findIndex } from "lodash"; +import findIndex from "lodash/findIndex"; export default class CriteriaController { $onInit () { diff --git a/packages/oui-criteria-container/src/index.js b/packages/oui-criteria-container/src/index.js index 295491b9..e6d31978 100644 --- a/packages/oui-criteria-container/src/index.js +++ b/packages/oui-criteria-container/src/index.js @@ -1,4 +1,6 @@ import CriteriaContainer from "./criteria-container.component"; -angular.module("oui.criteria-container", []) - .component("ouiCriteriaContainer", CriteriaContainer); +export default angular + .module("oui.criteria-container", []) + .component("ouiCriteriaContainer", CriteriaContainer) + .name; diff --git a/packages/oui-datagrid/src/datagrid.controller.js b/packages/oui-datagrid/src/datagrid.controller.js index 1037a922..024c1b2d 100644 --- a/packages/oui-datagrid/src/datagrid.controller.js +++ b/packages/oui-datagrid/src/datagrid.controller.js @@ -1,5 +1,5 @@ import { addBooleanParameter } from "@oui-angular/common/component-utils"; -import { find } from "lodash"; +import find from "lodash/find"; import { hasProperty } from "./util"; import template from "./datagrid.html"; diff --git a/packages/oui-datagrid/src/filter/comparator-resolver.js b/packages/oui-datagrid/src/filter/comparator-resolver.js index 9e27ea8d..4d7d7eed 100644 --- a/packages/oui-datagrid/src/filter/comparator-resolver.js +++ b/packages/oui-datagrid/src/filter/comparator-resolver.js @@ -1,6 +1,7 @@ -import { endsWith, negate } from "lodash"; import BasicComparators from "./basic"; import DateComparators from "./date"; +import endsWith from "lodash/endsWith"; +import negate from "lodash/negate"; import NumberComparators from "./number"; import StringComparators from "./string"; diff --git a/packages/oui-datagrid/src/filter/date.js b/packages/oui-datagrid/src/filter/date.js index 439140b6..c7f545ca 100644 --- a/packages/oui-datagrid/src/filter/date.js +++ b/packages/oui-datagrid/src/filter/date.js @@ -1,4 +1,5 @@ -import { isDate, isNaN } from "lodash"; +import isDate from "lodash/isDate"; +import isNaN from "lodash/isNaN"; export default class DateComparators { static is (subject, value) { diff --git a/packages/oui-datagrid/src/filter/filter.js b/packages/oui-datagrid/src/filter/filter.js index 8d6be956..61153578 100644 --- a/packages/oui-datagrid/src/filter/filter.js +++ b/packages/oui-datagrid/src/filter/filter.js @@ -1,5 +1,6 @@ -import { find, get } from "lodash"; import ComparatorResolver from "./comparator-resolver"; +import find from "lodash/find"; +import get from "lodash/get"; import StringComparators from "./string"; export default class Filter { diff --git a/packages/oui-datagrid/src/index.js b/packages/oui-datagrid/src/index.js index 1c54bf56..e21aaf88 100644 --- a/packages/oui-datagrid/src/index.js +++ b/packages/oui-datagrid/src/index.js @@ -7,7 +7,7 @@ import DatagridParameters from "./parameters/datagrid-parameters.component"; import DatagridProvider from "./datagrid.provider"; import DatagridService from "./datagrid.service"; -angular +export default angular .module("oui.datagrid", [ "oui.pagination", "oui.dropdown", @@ -22,4 +22,5 @@ angular .service("ouiDatagridPaging", DatagridPaging) .provider("ouiDatagridConfiguration", DatagridProvider) .service("ouiDatagridService", DatagridService) - .component("ouiDatagridParameters", DatagridParameters); + .component("ouiDatagridParameters", DatagridParameters) + .name; diff --git a/packages/oui-field/README.md b/packages/oui-field/README.md index be2e0e15..d20fcc7f 100644 --- a/packages/oui-field/README.md +++ b/packages/oui-field/README.md @@ -83,6 +83,18 @@ ``` +### Switch + +```html:preview +
+ + + +
+``` ### Radio diff --git a/packages/oui-field/src/field.html b/packages/oui-field/src/field.html index a99dab65..9f8a460d 100644 --- a/packages/oui-field/src/field.html +++ b/packages/oui-field/src/field.html @@ -11,7 +11,7 @@ ng-bind="::$ctrl.label"> - +
diff --git a/packages/oui-field/src/index.js b/packages/oui-field/src/index.js index e7aa4883..cf820e93 100644 --- a/packages/oui-field/src/index.js +++ b/packages/oui-field/src/index.js @@ -1,6 +1,8 @@ import Field from "./field.component.js"; import FieldConfigurationProvider from "./field.provider.js"; -angular.module("oui.field", []) +export default angular + .module("oui.field", []) .component("ouiField", Field) - .provider("ouiFieldConfiguration", FieldConfigurationProvider); + .provider("ouiFieldConfiguration", FieldConfigurationProvider) + .name; diff --git a/packages/oui-field/src/index.spec.js b/packages/oui-field/src/index.spec.js index d2134f91..f7ff759d 100644 --- a/packages/oui-field/src/index.spec.js +++ b/packages/oui-field/src/index.spec.js @@ -1,4 +1,4 @@ -import { noop } from "lodash"; +import noop from "lodash/noop"; describe("ouiField", () => { let $timeout; diff --git a/packages/oui-form-actions/src/index.js b/packages/oui-form-actions/src/index.js index 37c8a5c8..ae1b805a 100644 --- a/packages/oui-form-actions/src/index.js +++ b/packages/oui-form-actions/src/index.js @@ -1,6 +1,8 @@ import FormActions from "./form-actions.component"; import FormActionsProvider from "./form-actions.provider"; -angular.module("oui.form-actions", []) +export default angular + .module("oui.form-actions", []) .component("ouiFormActions", FormActions) - .provider("ouiFormActionsConfiguration", FormActionsProvider); + .provider("ouiFormActionsConfiguration", FormActionsProvider) + .name; diff --git a/packages/oui-guide-menu/src/index.js b/packages/oui-guide-menu/src/index.js index 702e02ff..72e95219 100644 --- a/packages/oui-guide-menu/src/index.js +++ b/packages/oui-guide-menu/src/index.js @@ -3,8 +3,10 @@ import DropdownGroup from "../../oui-dropdown/src/group/dropdown-group.component import DropdownItem from "../../oui-dropdown/src/item/dropdown-item.component"; import GuideMenu from "./guide-menu.component"; -angular.module("oui.guide-menu", []) +export default angular + .module("oui.guide-menu", []) .component("ouiGuideMenu", GuideMenu) .component("ouiGuideMenuDivider", DropdownDivider) .component("ouiGuideMenuGroup", DropdownGroup) - .component("ouiGuideMenuItem", DropdownItem); + .component("ouiGuideMenuItem", DropdownItem) + .name; diff --git a/packages/oui-header-tabs/README.md b/packages/oui-header-tabs/README.md index 8abb0d32..7e2d249c 100644 --- a/packages/oui-header-tabs/README.md +++ b/packages/oui-header-tabs/README.md @@ -92,7 +92,7 @@ | ---- | ---- | ---- | ---- | ---- | ---- | ---- | `text` | string | @ | yes | | | display the menu item with this text | `href` | string | @? | yes | | | href of the menu item -| `state` | boolean | @? | yes | | | state of the menu item +| `state` | string | @? | yes | | | state of the menu item | `stateParams` | object | { diff --git a/packages/oui-modal/src/index.js b/packages/oui-modal/src/index.js index 82cd54fa..646887c1 100644 --- a/packages/oui-modal/src/index.js +++ b/packages/oui-modal/src/index.js @@ -1,3 +1,6 @@ import Modal from "./modal.component.js"; -angular.module("oui.modal", []).component("ouiModal", Modal); +export default angular + .module("oui.modal", []) + .component("ouiModal", Modal) + .name; diff --git a/packages/oui-navbar/README.md b/packages/oui-navbar/README.md index 2670d2d3..eb8f3eba 100644 --- a/packages/oui-navbar/README.md +++ b/packages/oui-navbar/README.md @@ -4,8 +4,9 @@ ## Usage +### Basic + ```html:preview -
-
``` -Note: All children menus have `.oui-navbar-menu_fixed`. The component is intended to be used in `fixed` mode. To avoid being hidden by the documentation navbar, this example is not `fixed`. +### Advanced -## API +```html:preview + + + + + + + + + + + + + + +``` + +## Brand -| Attribute | Type | Binding | One-time Binding | Values | Default | Description | -| ---- | ---- | ---- | ---- | ---- | ---- | ---- | -| brand | object | + +``` ### Properties of attribute `brand` -- `label` _(optional)_: define `aria-label` of the brand link. -- `title`: _(optional)_: define the brand text. +- `label` **(optional)**: define `aria-label` of the brand link. +- `title`: **(optional)**: define the brand text. - `url`: define `href` of the brand link. #### Set a brand icon with a CSS class (for `oui-icon`) @@ -41,8 +101,6 @@ Note: All children menus have `.oui-navbar-menu_fixed`. The component is intende The brand icon will be set as a ``. -###### Example - ```json { "label": String, @@ -54,14 +112,12 @@ The brand icon will be set as a ``. #### Set a brand icon with an image -- `iconAlt` _(optional)_: define `alt` of the brand icon. -- `iconClass` _(optional)_: define `class` of the brand icon. +- `iconAlt` **(optional)**: define `alt` of the brand icon. +- `iconClass` **(optional)**: define `class` of the brand icon. - `iconSrc`: define `src` of the brand icon. The brand icon will be set as a ``. -###### Example - ```json { "label": String, @@ -73,17 +129,30 @@ The brand icon will be set as a ``. } ``` +### With component `oui-navbar-brand` + +```html:preview + + + +``` + +## Links + ### Common properties of attributes `*-links` - `name`: define the navigation name of a menu. -- `class` _(optional)_: define `class` of the menu item (only used for root links). -- `label` _(optional)_: define `aria-label` of the menu item. +- `class` **(optional)**: define `class` of the menu item (only used for root links). +- `label` **(optional)**: define `aria-label` of the menu item. - `title`: define the menu item text. -- `headerTitle` _(optional)_: define the title of the menu header (default text is `title`). -- `headerBreadcrumb` _(optional)_: define the breadcrumb of the menu header. -- `headerTemplate` _(optional)_: define the HTML template of the menu header. -- `isActive` _(optional)_: define if the menu item has active variant `.oui-navbar-menu__item_active`. -- `acknowledged` _(optional)_: define if the menu item is acknowledged. +- `headerTitle` **(optional)**: define the title of the menu header (default text is `title`). +- `headerBreadcrumb` **(optional)**: define the breadcrumb of the menu header. +- `headerTemplate` **(optional)**: define the HTML template of the menu header. +- `isActive` **(optional)**: define if the menu item has active variant `.oui-navbar-menu__item_active`. +- `acknowledged` **(optional)**: define if the menu item is acknowledged. If `headerTemplate` is defined, `headerBreadcrumb` and `headerTitle` are not used. @@ -93,8 +162,6 @@ If `headerTemplate` is defined, `headerBreadcrumb` and `headerTitle` are not use The menu item will be set as a ``. -##### Example - ```json { "name": String, @@ -108,12 +175,10 @@ The menu item will be set as a ``. #### Set a menu item as a link for ui-router - `state`: define `ui-sref` of the menu item. The menu item will be set as a ``, `click` and `url` will be ignored. -- `stateParams` _(optional)_: define parameters for `state`. +- `stateParams` **(optional)**: define parameters for `state`. The menu item will be set as a ``. -##### Example - ```json { "name": String, @@ -131,8 +196,6 @@ The menu item will be set as a ``. The menu item will be set as a ` +
diff --git a/packages/oui-navbar/src/group/navbar-group.controller.js b/packages/oui-navbar/src/group/navbar-group.controller.js index f603a64e..176afce1 100644 --- a/packages/oui-navbar/src/group/navbar-group.controller.js +++ b/packages/oui-navbar/src/group/navbar-group.controller.js @@ -1,11 +1,57 @@ export default class { - constructor ($attrs, $element, ouiNavbarConfiguration, NavbarGroupService) { + constructor ($attrs, $element, ouiNavbarConfiguration, KEYBOARD_KEYS) { "ngInject"; this.$attrs = $attrs; this.$element = $element; this.config = ouiNavbarConfiguration; - this.navbarGroupService = NavbarGroupService; + + this.KEYBOARD_KEYS = KEYBOARD_KEYS; + } + + bindGroup (groupName) { + const keys = {}; + const keysRegex = new RegExp([ + this.KEYBOARD_KEYS.TAB, + this.KEYBOARD_KEYS.SHIFT + ].join("|")); + + const tabbableItems = this.navbarCtrl.getGroup(groupName); + const lastIndex = tabbableItems.length - 1; + const focusElement = (e, groupIndex) => { + let index = groupIndex; + keys[e.which] = true; + + if (keys[this.KEYBOARD_KEYS.TAB] && !keys[this.KEYBOARD_KEYS.SHIFT]) { + // Move Down + index = index >= lastIndex ? 0 : index + 1; + } else if (keys[this.KEYBOARD_KEYS.TAB] && keys[this.KEYBOARD_KEYS.SHIFT]) { + // Move Up + index = index <= 0 ? lastIndex : index - 1; + } + + // Check if element is visible + if (tabbableItems[index].clientHeight) { + tabbableItems[index].focus(); + } else { + focusElement(e, index); + } + }; + + angular.element(tabbableItems) + .on("keydown", (e) => { + if (keysRegex.test(e.which) && this.isOpen(groupName)) { + e.preventDefault(); + focusElement(e, this.navbarCtrl.getGroup(groupName).indexOf(e.target)); + } + }) + .on("keyup", (e) => { + delete keys[e.which]; + }); + } + + isOpen (state) { + return this.navbarCtrl.navigation && this.navbarCtrl.navigation[state]; } $onInit () { @@ -16,11 +62,11 @@ export default class { } $postLink () { - this.navbarGroupService.addItemToGroup(this.$element[0], this.groupName); + this.navbarCtrl.addItemToGroup(this.$element[0], this.groupName); // Bind items when it's the last item if (this.isLast) { - this.navbarGroupService.bindGroup(this.groupName); + this.bindGroup(this.groupName); } } } diff --git a/packages/oui-navbar/src/group/navbar-group.directive.js b/packages/oui-navbar/src/group/navbar-group.directive.js index 54cdbee9..d476a6e2 100644 --- a/packages/oui-navbar/src/group/navbar-group.directive.js +++ b/packages/oui-navbar/src/group/navbar-group.directive.js @@ -2,6 +2,9 @@ import controller from "./navbar-group.controller"; export default () => ({ restrict: "A", + require: { + navbarCtrl: "^ouiNavbar" + }, bindToController: { groupName: "@ouiNavbarGroup", isLast: " { - let index = groupIndex; - keys[e.which] = true; - - if (keys[this.KEYBOARD_KEYS.ALT] && !keys[this.KEYBOARD_KEYS.TAB]) { - // Move Down - index = index >= lastIndex ? 0 : index + 1; - } else if (keys[this.KEYBOARD_KEYS.ALT] && keys[this.KEYBOARD_KEYS.TAB]) { - // Move Up - index = index <= 0 ? lastIndex : index - 1; - } - - // Check if element is visible - if (tabbableItems[index].clientHeight) { - tabbableItems[index].focus(); - } else { - focusElement(e, index); - } - }; - - angular.element(tabbableItems) - .on("keydown", (e) => { - if (keysRegex.test(e.which) && this.navbarService.isOpen(groupName)) { - e.preventDefault(); - focusElement(e, this.keyboardNav[groupName].indexOf(e.target)); - } - }) - .on("keyup", (e) => { - delete keys[e.which]; - }); - } - - // Set focus to an item of a group - setFocusTo (groupName, index) { - // Add a delay to force focus - const delay = 50; - this.$timeout(() => this.keyboardNav[groupName][index] && this.keyboardNav[groupName][index].focus(), delay); - } -} diff --git a/packages/oui-navbar/src/index.js b/packages/oui-navbar/src/index.js index 04aec141..99b858bc 100644 --- a/packages/oui-navbar/src/index.js +++ b/packages/oui-navbar/src/index.js @@ -1,20 +1,30 @@ import KEYBOARD_KEYS from "./keyboard-keys.constant"; + import Navbar from "./navbar.component"; -import NavbarConfigurationProvider from "./navbar.provider.js"; +import NavbarBrand from "./brand/navbar-brand.component"; +import NavbarConfigurationProvider from "./navbar.provider"; +import NavbarDropdown from "./dropdown/navbar-dropdown.component"; +import NavbarDropdownMenu from "./dropdown/menu/navbar-dropdown-menu.component"; import NavbarGroup from "./group/navbar-group.directive"; -import NavbarGroupService from "./group/navbar-group.service"; +import NavbarLink from "./link/navbar-link.component"; import NavbarMenu from "./menu/navbar-menu.component"; -import NavbarService from "./navbar.service"; +import NavbarNotification from "./notification/navbar-notification.component"; +import NavbarToggler from "./toggler/navbar-toggler.component"; -angular +export default angular .module("oui.navbar", [ "ngAria", "ngSanitize" ]) .constant("KEYBOARD_KEYS", KEYBOARD_KEYS) .component("ouiNavbar", Navbar) - .directive("ouiNavbarGroup", NavbarGroup) + .component("ouiNavbarBrand", NavbarBrand) + .component("ouiNavbarDropdown", NavbarDropdown) + .component("ouiNavbarDropdownMenu", NavbarDropdownMenu) + .component("ouiNavbarLink", NavbarLink) .component("ouiNavbarMenu", NavbarMenu) + .component("ouiNavbarNotification", NavbarNotification) + .component("ouiNavbarToggler", NavbarToggler) + .directive("ouiNavbarGroup", NavbarGroup) .provider("ouiNavbarConfiguration", NavbarConfigurationProvider) - .service("NavbarService", NavbarService) - .service("NavbarGroupService", NavbarGroupService); + .name; diff --git a/packages/oui-navbar/src/index.spec.js b/packages/oui-navbar/src/index.spec.js index 8fd210be..c3e67f15 100644 --- a/packages/oui-navbar/src/index.spec.js +++ b/packages/oui-navbar/src/index.spec.js @@ -2,29 +2,255 @@ import mockData from "./index.spec.data.json"; describe("ouiNavbar", () => { let testUtils; + let $document; + let $timeout; + let configuration; beforeEach(angular.mock.module("oui.navbar")); + beforeEach(angular.mock.module("oui.navbar.configuration")); beforeEach(angular.mock.module("oui.test-utils")); - beforeEach(inject((_TestUtils_) => { + beforeEach(inject((_$document_, _$timeout_, _TestUtils_) => { + $document = _$document_; + $timeout = _$timeout_; testUtils = _TestUtils_; })); + describe("Provider", () => { + angular.module("oui.navbar.configuration", [ + "oui.navbar" + ]).config(ouiNavbarConfigurationProvider => { + ouiNavbarConfigurationProvider.setTranslations({ + foo: "bar" + }); + }); + + beforeEach(inject(_ouiNavbarConfiguration_ => { + configuration = _ouiNavbarConfiguration_; + })); + + it("should have custom options", () => { + expect(configuration.translations.foo).toEqual("bar"); + }); + }); + describe("Component", () => { + const navbarClass = "oui-navbar"; + const navbarFixedClass = `${navbarClass}_fixed`; + const navbarDropdownClass = `${navbarClass}-dropdown`; + const navbarMenuClass = `${navbarClass}-menu`; + const navbarMenuFixedClass = `${navbarMenuClass}_fixed`; + const navbarMenuEndClass = `${navbarMenuClass}_end`; + const navbarListItemClass = `${navbarClass}-list__item`; + + it("should display a navbar", () => { + const component = testUtils.compileTemplate(` + + `, { + brand: mockData.brand, + activeLink: mockData.mainLinks[0].name, + mainLinks: mockData.mainLinks, + asideLinks: mockData.asideLinks, + togglerLinks: mockData.togglerLinks + }); + const controller = component.controller("ouiNavbar"); + + $timeout.flush(); + + expect(angular.copy(controller.brand)).toEqual(mockData.brand); + expect(angular.copy(controller.activeLink)).toEqual(mockData.mainLinks[0].name); + expect(angular.copy(controller.mainLinks)).toEqual(mockData.mainLinks); + expect(angular.copy(controller.asideLinks)).toEqual(mockData.asideLinks); + expect(angular.copy(controller.togglerLinks)).toEqual(mockData.togglerLinks); + }); + + describe("Navbar", () => { + const item = "foo"; + const groupName = "bar"; + const menuName = "lorem"; + const internalMenuName = "ipsum"; + + let component; + let controller; + + beforeEach(() => { + component = testUtils.compileTemplate(""); + controller = component.controller("ouiNavbar"); + + $timeout.flush(); + }); + + it("should have default classname", () => { + expect(component.hasClass(navbarClass)).toBeTruthy(); + expect(component.hasClass(navbarFixedClass)).toBeFalsy(); + }); + + it("should have role 'navigation'", () => { + expect(component.attr("role")).toBe("navigation"); + }); + + it("should add item 'foo' to group 'bar'", () => { + controller.addItemToGroup(item, groupName); + + expect(Array.isArray(controller.keyboardNav[groupName])).toBeTruthy(); + expect(controller.keyboardNav[groupName].length).toBe(1); + expect(controller.keyboardNav[groupName][0]).toBe(item); + }); + + it("should return group 'bar'", () => { + controller.addItemToGroup(item, groupName); + const group = controller.getGroup(groupName); + + expect(Array.isArray(group)).toBeTruthy(); + expect(group.length).toBe(1); + expect(group[0]).toBe(item); + }); + + it("should toggle navigation state of Menu 'lorem' ", () => { + expect(controller.navigation).toBeUndefined(); + + controller.toggleMenu(menuName); + expect(controller.navigation[menuName]).toBeTruthy(); + + controller.toggleMenu(menuName); + expect(controller.navigation).toBeNull(); + }); + + it("should toggle navigation state of internal Menu 'lorem'", () => { + controller.toggleMenu(menuName); + controller.toggleMenu(internalMenuName, true); + expect(controller.navigation[internalMenuName]).toBeTruthy(); + + controller.toggleMenu(internalMenuName, true); + expect(controller.navigation[internalMenuName]).toBeFalsy(); + }); + + it("should clear navigation", () => { + controller.toggleMenu(menuName); + controller.toggleMenu(internalMenuName, true); + controller.toggleMenu(); + expect(controller.navigation).toBeNull(); + + // Simulate external click + controller.toggleMenu(menuName); + controller.toggleMenu(internalMenuName, true); + $document.triggerHandler("click"); + + $timeout.flush(); + expect(controller.navigation).toBeNull(); + + // Simulate ESC keydown + controller.toggleMenu(menuName); + controller.toggleMenu(internalMenuName, true); + $document.triggerHandler({ + type: "keydown", + which: controller.KEYBOARD_KEYS.ESC + }); + + $timeout.flush(); + expect(controller.navigation).toBeNull(); + }); + + it("should not clear navigation", () => { + controller.toggleMenu(menuName); + controller.toggleMenu(internalMenuName, true); + + const navigation = controller.navigation; + component.triggerHandler("click"); + + $timeout.flush(); + expect(controller.navigation).toEqual(navigation); + }); + + it("should be fixed", () => { + // Test without value, should be true + component = testUtils.compileTemplate(""); + controller = component.controller("ouiNavbar"); + + $timeout.flush(); + + expect(component.hasClass(navbarFixedClass)).toBeTruthy(); + expect(controller.fixed).toBeTruthy(); + + // Test with value + component = testUtils.compileTemplate(''); + controller = component.controller("ouiNavbar"); + + $timeout.flush(); + + expect(component.hasClass(navbarFixedClass)).toBeTruthy(); + expect(controller.fixed).toBeTruthy(); + }); + + it("should not be fixed", () => { + component = testUtils.compileTemplate(''); + controller = component.controller("ouiNavbar"); + + $timeout.flush(); + + expect(component.hasClass(navbarFixedClass)).toBeFalsy(); + expect(controller.fixed).toBeFalsy(); + }); + + it("should focus element when menu is opened", () => { + const name = mockData.asideLinks[0].name; + component = testUtils.compileTemplate('', { + asideLinks: mockData.asideLinks + }); + controller = component.controller("ouiNavbar"); + + const button = controller.keyboardNav[name][0]; + spyOn(button, "focus"); + controller.toggleMenu(name); + + $timeout.flush(); + expect(button.focus).toHaveBeenCalled(); + }); + + it("should have mainLinks equal togglerLinks", () => { + component = testUtils.compileTemplate('', { + mainLinks: mockData.mainLinks + }); + controller = component.controller("ouiNavbar"); + + expect(controller.mainLinks).toEqual(controller.togglerLinks); + }); + }); describe("Brand", () => { const data = mockData.brand; - let component; let brand; + let component; + let controller; beforeEach(() => { - component = testUtils.compileTemplate('', { + component = testUtils.compileTemplate(` + + + + `, { brand: data }); + controller = component.find("oui-navbar-brand").controller("ouiNavbarBrand"); + + $timeout.flush(); + brand = angular.element(component[0].querySelector(".oui-navbar__brand")); }); + it("should remove aria-label", () => { + expect(controller.$element.attr("aria-label")).toBeUndefined(); + }); + it("should create a link", () => { expect(brand.length).toEqual(1); expect(brand[0].tagName).toBe("A"); @@ -42,6 +268,181 @@ describe("ouiNavbar", () => { }); }); + describe("Dropdown", () => { + let component; + + beforeEach(() => { + component = testUtils.compileTemplate(` + + + + + + + + `, { + name: "foo", + title: "bar", + label: "lorem", + badge: 5, + icon: "oui-icon oui-icon-help_circle", + text: "Lorem ipsum" + }); + + $timeout.flush(); + }); + + it("should have default classname", () => { + const dropdown = component.find("oui-navbar-dropdown"); + const dropdownMenu = component.find("oui-navbar-dropdown-menu"); + + expect(dropdown.hasClass(navbarDropdownClass)).toBeTruthy(); + expect(dropdown.hasClass(navbarListItemClass)).toBeTruthy(); + + expect(dropdownMenu.hasClass(navbarMenuClass)).toBeTruthy(); + expect(dropdownMenu.hasClass(navbarMenuFixedClass)).toBeTruthy(); + }); + + it("should have content transcluded", () => { + const dropdownMenu = component.find("oui-navbar-dropdown-menu"); + + expect(dropdownMenu.text()).toBe("Lorem ipsum"); + }); + + it("should have alignment 'end'", () => { + component = testUtils.compileTemplate(` + + + + + + + + `, { + name: "foo", + title: "bar", + label: "lorem", + badge: 5, + icon: "oui-icon oui-icon-help_circle", + text: "Lorem ipsum" + }); + const dropdownMenu = component.find("oui-navbar-dropdown-menu"); + + $timeout.flush(); + + expect(dropdownMenu.hasClass(navbarMenuEndClass)).toBeTruthy(); + }); + }); + + describe("Menu", () => { + const data = mockData.asideLinks[0]; + + let component; + let menu; + + beforeEach(() => { + component = testUtils.compileTemplate(` + + + + + + + + `, { + name: data.name, + title: data.title, + headerTitle: data.headerTitle, + subLinks: data.subLinks + }); + + $timeout.flush(); + + menu = component.find("oui-navbar-menu"); + }); + + it("should have default classname", () => { + expect(menu.hasClass(navbarMenuClass)).toBeTruthy(); + expect(menu.hasClass(navbarMenuFixedClass)).toBeFalsy(); + expect(menu.hasClass(navbarMenuEndClass)).toBeFalsy(); + }); + + it("should have role 'menu'", () => { + expect(menu.attr("role")).toBe("menu"); + }); + + it("should have alignment", () => { + component = testUtils.compileTemplate(` + + + + + + + + `, { + name: data.name, + title: data.title, + headerTitle: data.headerTitle, + subLinks: data.subLinks + }); + + $timeout.flush(); + + menu = component.find("oui-navbar-menu"); + expect(menu.hasClass(navbarMenuEndClass)).toBeTruthy(); + }); + + it("should be fixed", () => { + component = testUtils.compileTemplate(` + + + + + + + + `, { + name: data.name, + title: data.title, + headerTitle: data.headerTitle, + subLinks: data.subLinks + }); + + $timeout.flush(); + + menu = component.find("oui-navbar-menu"); + expect(menu.hasClass(navbarMenuFixedClass)).toBeTruthy(); + }); + }); + describe("Main links", () => { const data = mockData.mainLinks; const activeIndex = 0; @@ -55,6 +456,8 @@ describe("ouiNavbar", () => { mainLinks: data }); + $timeout.flush(); + menu = angular.element(component[0].querySelector(".oui-navbar-list_main")); links = menu.children("li"); }); @@ -98,6 +501,9 @@ describe("ouiNavbar", () => { component = testUtils.compileTemplate('', { asideLinks: data }); + + $timeout.flush(); + menu = angular.element(component[0].querySelector(".oui-navbar-list_aside")); links = menu.children("li"); }); @@ -154,6 +560,8 @@ describe("ouiNavbar", () => { togglerLinks: data }); + $timeout.flush(); + toggler = angular.element(component[0].querySelector(".oui-navbar-toggler")); responsiveMenu = angular.element(component[0].querySelector(".oui-navbar-menu_toggle")); }); @@ -185,6 +593,8 @@ describe("ouiNavbar", () => { mainLinks: data }); + $timeout.flush(); + backdrop = angular.element(component[0].querySelector(".oui-navbar-backdrop")); toggler = angular.element(component[0].querySelector(".oui-navbar-toggler")); }); diff --git a/packages/oui-navbar/src/keyboard-keys.constant.js b/packages/oui-navbar/src/keyboard-keys.constant.js index 7a757d5e..88461f3f 100644 --- a/packages/oui-navbar/src/keyboard-keys.constant.js +++ b/packages/oui-navbar/src/keyboard-keys.constant.js @@ -1,5 +1,5 @@ export default { - ALT: 9, - TAB: 16, + TAB: 9, + SHIFT: 16, ESC: 27 }; diff --git a/packages/oui-navbar/src/link/navbar-link.component.js b/packages/oui-navbar/src/link/navbar-link.component.js new file mode 100644 index 00000000..65f2e78f --- /dev/null +++ b/packages/oui-navbar/src/link/navbar-link.component.js @@ -0,0 +1,19 @@ +import controller from "./navbar-link.controller"; +import template from "./navbar-link.html"; + +export default { + require: { + navbarCtrl: "^^ouiNavbar" + }, + bindings: { + name: "@", + text: "@", + href: "@?", + state: "@?", + stateParams: " + this.$element + .addClass("oui-navbar-list__item") + ); + } + + // Return value of "ui-sref" + getFullSref () { + return `${this.state}(${JSON.stringify(this.stateParams)})`; + } +} diff --git a/packages/oui-navbar/src/link/navbar-link.html b/packages/oui-navbar/src/link/navbar-link.html new file mode 100644 index 00000000..2c1e4fae --- /dev/null +++ b/packages/oui-navbar/src/link/navbar-link.html @@ -0,0 +1,27 @@ + + + + diff --git a/packages/oui-navbar/src/menu/navbar-menu.component.js b/packages/oui-navbar/src/menu/navbar-menu.component.js index d2e25b66..6cba4db1 100644 --- a/packages/oui-navbar/src/menu/navbar-menu.component.js +++ b/packages/oui-navbar/src/menu/navbar-menu.component.js @@ -2,17 +2,18 @@ import controller from "./navbar-menu.controller"; import template from "./navbar-menu.html"; export default { + require: { + navbarCtrl: "^^ouiNavbar" + }, bindings: { backButton: "

-
    +