UNPKG

3.75 kBJavaScriptView Raw
1import { I18n } from './i18n';
2import $ from './jquery';
3import skate from './internal/skate';
4import globalize from './internal/globalize';
5import widget from './internal/widget';
6
7/**
8 * Navigation (".aui-nav" elements).
9 *
10 * @param {(string|HtmlElement|jQuery)} selector - An expression
11 * representing a single .aui-nav element; you may also pass an expression
12 * for a descendent element, in which case the closest containing
13 * .aui-nav element is used.
14 * @constructor
15 */
16function Navigation (selector) {
17 this.$el = $(selector).closest('.aui-nav');
18
19 // If there are multiple objects, initialise them separately
20 if (this.$el.length > 1) {
21 return this.$el.map(function (idx, elm) {
22 return new Navigation(elm);
23 })[0];
24 }
25
26 // If already initialised, return existing object
27 if (this.$el.data('aui-navigation')) {
28 return this.$el.data('aui-navigation');
29 }
30
31 this.$el.data('aui-navigation', this);
32
33 this.$treeParent = this.$el.parent('li[aria-expanded]');
34 this.$subtreeToggleIcon = this.$treeParent
35 .children('.aui-nav-subtree-toggle')
36 .children('span.aui-icon');
37
38 // Add child-selected class to relevant attributes
39 this.$el.children('li:has(.aui-nav-selected)').addClass('aui-nav-child-selected');
40
41 // Auto-expand if child is selected
42 var $selected = this.$el.children('.aui-nav-selected');
43 $selected
44 .parents('.aui-nav > [aria-expanded=false]')
45 .add($selected.filter('[aria-expanded=false]'))
46 .each(function () {
47 var nav = navigationWidget($(this).children('.aui-nav'));
48 nav.expand();
49 });
50
51 // Toggle expand on click
52 var $togglers = this.$el.find('> li[aria-expanded] > .aui-nav-subtree-toggle');
53 $togglers.on('click', function () {
54 var nav = navigationWidget($(this).siblings('.aui-nav'));
55 nav.toggle();
56 });
57
58 // Make sure subtree togglers have proper a11y label
59 $togglers.each(function () {
60 var $parent = $(this).parent('li[aria-expanded]');
61 var $icon = $(this).find('.aui-icon');
62 var isListItemExpanded = $parent.attr('aria-expanded') === 'true';
63
64 $icon.text(
65 isListItemExpanded ?
66 I18n.getText('aui.words.collapse') :
67 I18n.getText('aui.words.expand')
68 );
69 })
70
71 return this;
72}
73
74Navigation.prototype.isNested = function () {
75 return this.$treeParent.length === 1;
76};
77
78Navigation.prototype.isCollapsed = function () {
79 return this.$treeParent.attr('aria-expanded') === 'false';
80};
81
82Navigation.prototype.expand = function () {
83 this.$treeParent.attr('aria-expanded', 'true');
84 this.$subtreeToggleIcon
85 .removeClass('aui-iconfont-collapsed')
86 .addClass('aui-iconfont-expanded')
87 .text(I18n.getText('aui.words.collapse'));
88 return this;
89};
90
91Navigation.prototype.collapse = function () {
92 this.$treeParent.attr('aria-expanded', 'false');
93 this.$subtreeToggleIcon
94 .removeClass('aui-iconfont-expanded')
95 .addClass('aui-iconfont-collapsed')
96 .text(I18n.getText('aui.words.expand'));
97 return this;
98};
99
100Navigation.prototype.toggle = function () {
101 if (this.isCollapsed()) {
102 this.expand();
103 } else {
104 this.collapse();
105 }
106 return this;
107};
108
109const navigationWidget = widget('navigation', Navigation);
110
111// Initialise nav elements
112const NavigationEl = skate('aui-nav', {
113 type: skate.type.CLASSNAME,
114 attached: function (element) {
115 new Navigation(element);
116 },
117 detached: function (element) {
118 $(element).removeData();
119 }
120});
121
122globalize('navigation', navigationWidget);
123
124export default navigationWidget;
125export {
126 NavigationEl
127};