UNPKG

23.8 kBJavaScriptView Raw
1import $ from './jquery';
2import './tooltip';
3import './navigation';
4import { I18n } from './i18n';
5import clone from './clone';
6import * as deprecate from './internal/deprecation';
7import globalize from './internal/globalize';
8import hasTouch from './internal/has-touch';
9import isInput from './internal/is-input';
10import keyCode from './key-code';
11import mediaQuery from './internal/mediaQuery';
12import skate from './internal/skate';
13import uid from './unique-id';
14import widget from './internal/widget';
15import deduplicateIDs from './internal/deduplicateIDs';
16
17
18function sidebarOffset(sidebar) {
19 return sidebar.offset().top;
20}
21
22function Sidebar(selector) {
23 this.$el = $(selector);
24 if (!this.$el.length) {
25 return;
26 }
27 this.$body = $('body');
28 this.$wrapper = this.$el.children('.aui-sidebar-wrapper');
29
30 // Sidebar users should add class="aui-page-sidebar" to the
31 // <body> in the rendered markup (to prevent any potential flicker),
32 // so we add it just in case they forgot.
33 this.$body.addClass('aui-page-sidebar');
34
35 this._previousScrollTop = null;
36 this._previousViewportHeight = null;
37 this._previousViewportWidth = null;
38 this._previousOffsetTop = null;
39
40 this.submenus = new SubmenuManager();
41
42 initializeHandlers(this);
43 constructAllSubmenus(this);
44}
45
46var FORCE_COLLAPSE_WIDTH = 1240;
47var EVENT_PREFIX = '_aui-internal-sidebar-';
48
49function namespaceEvents (events) {
50 return $.map(events.split(' '), function (event) {
51 return EVENT_PREFIX + event;
52 }).join(' ');
53}
54
55Sidebar.prototype.on = function () {
56 var events = arguments[0];
57 var args = Array.prototype.slice.call(arguments, 1);
58 var namespacedEvents = namespaceEvents(events);
59 this.$el.on.apply(this.$el, [namespacedEvents].concat(args));
60 return this;
61};
62
63Sidebar.prototype.off = function () {
64 var events = arguments[0];
65 var args = Array.prototype.slice.call(arguments, 1);
66 var namespacedEvents = namespaceEvents(events);
67 this.$el.off.apply(this.$el, [namespacedEvents].concat(args));
68 return this;
69};
70
71Sidebar.prototype.setHeight = function (scrollTop, viewportHeight, headerHeight) {
72 var visibleHeaderHeight = Math.max(0, headerHeight - scrollTop);
73 this.$wrapper.height(viewportHeight - visibleHeaderHeight);
74 return this;
75};
76
77Sidebar.prototype.setTopPosition = function (scrollTop = window.pageYOffset) {
78 this.$wrapper.toggleClass('aui-is-docked', scrollTop > sidebarOffset(this.$el));
79 return this;
80};
81
82Sidebar.prototype.setPosition = deprecate.fn(Sidebar.prototype.setTopPosition, 'Sidebar.setPosition', {
83 removeInVersion: '10.0.0',
84 sinceVersion: '7.6.1',
85 alternativeName: 'Sidebar.setTopPosition',
86});
87
88Sidebar.prototype.setLeftPosition = function (scrollLeft = window.pageXOffset) {
89 if (this.$wrapper.hasClass('aui-is-docked')) {
90 this.$wrapper.css({ left: -scrollLeft });
91 }
92 return this;
93};
94
95Sidebar.prototype.setCollapsedState = function (viewportWidth) {
96 // Reflow behaviour is implemented as a state machine (hence all
97 // state transitions are enumerated). The rest of the state machine,
98 // e.g., entering the expanded narrow (fly-out) state, is implemented
99 // by the toggle() method.
100 var transition = {collapsed: {}, expanded: {}};
101 transition.collapsed.narrow = {
102 narrow: $.noop,
103 wide: function (s) {
104 s._expand(viewportWidth, true);
105 }
106 };
107 transition.collapsed.wide = {
108 narrow: $.noop, // Becomes collapsed narrow (no visual change).
109 wide: $.noop
110 };
111 transition.expanded.narrow = {
112 narrow: $.noop,
113 wide: function (s) {
114 s.$body.removeClass('aui-sidebar-collapsed');
115 s.$el.removeClass('aui-sidebar-fly-out');
116 }
117 };
118 transition.expanded.wide = {
119 narrow: function (s) {
120 s._collapse(true);
121 },
122 wide: $.noop
123 };
124
125 var collapseState = this.isCollapsed() ? 'collapsed' : 'expanded';
126 var oldSize = this.isViewportNarrow(this._previousViewportWidth) ? 'narrow' : 'wide';
127 var newSize = this.isViewportNarrow(viewportWidth) ? 'narrow' : 'wide';
128 transition[collapseState][oldSize][newSize](this);
129 return this;
130};
131
132Sidebar.prototype._collapse = function (isResponsive) {
133 if (this.isCollapsed()) {
134 return this;
135 }
136
137 var startEvent = $.Event(EVENT_PREFIX + 'collapse-start', {isResponsive: isResponsive});
138 this.$el.trigger(startEvent);
139 if (startEvent.isDefaultPrevented()) {
140 return this;
141 }
142
143 this.$body.addClass('aui-sidebar-collapsed');
144 this.$el.attr('aria-expanded', 'false');
145 this.$el.removeClass('aui-sidebar-fly-out');
146 this.$el.find(this.submenuTriggersSelector).attr('tabindex', 0);
147 $(this.inlineDialogSelector).attr('responds-to', 'hover');
148
149 if (!this.isAnimated()) {
150 this.$el.trigger($.Event(EVENT_PREFIX + 'collapse-end', {isResponsive: isResponsive}));
151 }
152 return this;
153};
154
155Sidebar.prototype.collapse = function () {
156 return this._collapse(false);
157};
158
159Sidebar.prototype._expand = function (viewportWidth, isResponsive) {
160 var startEvent = $.Event(EVENT_PREFIX + 'expand-start', {isResponsive: isResponsive});
161 this.$el.trigger(startEvent);
162 if (startEvent.isDefaultPrevented()) {
163 return this;
164 }
165
166 var isViewportNarrow = this.isViewportNarrow(viewportWidth);
167 this.$el.attr('aria-expanded', 'true');
168 this.$body.toggleClass('aui-sidebar-collapsed', isViewportNarrow);
169 this.$el.toggleClass('aui-sidebar-fly-out', isViewportNarrow);
170 this.$el.find(this.submenuTriggersSelector).removeAttr('tabindex');
171 $(this.inlineDialogSelector).removeAttr('responds-to');
172
173 if (!this.isAnimated()) {
174 this.$el.trigger($.Event(EVENT_PREFIX + 'expand-end', {isResponsive: isResponsive}));
175 }
176 return this;
177};
178
179Sidebar.prototype.expand = function () {
180 if (this.isCollapsed()) {
181 this._expand(this._previousViewportWidth, false);
182 }
183 return this;
184};
185
186Sidebar.prototype.isAnimated = function () {
187 return this.$el.hasClass('aui-is-animated');
188};
189
190Sidebar.prototype.isCollapsed = function () {
191 return this.$el.attr('aria-expanded') === 'false';
192};
193
194Sidebar.prototype.isViewportNarrow = function (viewportWidth) {
195 viewportWidth = viewportWidth === undefined ? this._previousViewportWidth : viewportWidth;
196 return viewportWidth < FORCE_COLLAPSE_WIDTH;
197};
198
199Sidebar.prototype.responsiveReflow = function responsiveReflow(isInitialPageLoad, viewportWidth) {
200 if (isInitialPageLoad) {
201 if (!this.isCollapsed() && this.isViewportNarrow(viewportWidth)) {
202 var isAnimated = this.isAnimated();
203 if (isAnimated) {
204 this.$el.removeClass('aui-is-animated');
205 }
206 // This will trigger the "collapse" event before non-sidebar
207 // JS code has a chance to bind listeners; they'll need to
208 // check isCollapsed() if they care about the value at that
209 // time.
210 this.collapse();
211 if (isAnimated) {
212 // We must trigger a CSS reflow (by accessing
213 // offsetHeight) otherwise the transition still runs.
214 // eslint-disable-next-line
215 this.$el[0].offsetHeight;
216 this.$el.addClass('aui-is-animated');
217 }
218 }
219 } else if (viewportWidth !== this._previousViewportWidth) {
220 this.setCollapsedState(viewportWidth);
221 }
222};
223
224Sidebar.prototype.reflow = function reflow(
225 scrollTop = window.pageYOffset,
226 viewportHeight = document.documentElement.clientHeight,
227 viewportWidth = window.innerWidth,
228 scrollHeight = document.documentElement.scrollHeight,
229 scrollLeft = window.pageXOffset) {
230
231 // Header height needs to be checked because in Stash it changes when the CSS "transform: translate3d" is changed.
232 // If you called reflow() after this change then nothing happened because the scrollTop and viewportHeight hadn't changed.
233 var offsetTop = sidebarOffset(this.$el);
234 var isInitialPageLoad = this._previousViewportWidth === null;
235
236 if (!(scrollTop === this._previousScrollTop && viewportHeight === this._previousViewportHeight && offsetTop === this._previousOffsetTop)) {
237 var isTouch = this.$body.hasClass('aui-page-sidebar-touch');
238 var isTrackpadBounce = scrollTop !== this._previousScrollTop && (scrollTop < 0 || scrollTop + viewportHeight > scrollHeight);
239 if (!isTouch && (isInitialPageLoad || !isTrackpadBounce)) {
240 this.setHeight(scrollTop, viewportHeight, offsetTop);
241 this.setTopPosition(scrollTop);
242 }
243 }
244
245 if (scrollLeft !== this._previousScrollLeft) {
246 this.setLeftPosition(scrollLeft);
247 }
248
249 var isResponsive = this.$el.attr('data-aui-responsive') !== 'false';
250 if (isResponsive) {
251 this.responsiveReflow(isInitialPageLoad, viewportWidth);
252 } else {
253 var isFlyOut = !this.isCollapsed() && this.isViewportNarrow(viewportWidth);
254 this.$el.toggleClass('aui-sidebar-fly-out', isFlyOut);
255 }
256
257 this._previousScrollTop = scrollTop;
258 this._previousViewportHeight = viewportHeight;
259 this._previousViewportWidth = viewportWidth;
260 this._previousOffsetTop = offsetTop;
261 this._previousScrollLeft = scrollLeft;
262 return this;
263};
264
265Sidebar.prototype.toggle = function () {
266 if (this.isCollapsed()) {
267 this.expand();
268 this.$el
269 .find('.aui-sidebar-toggle')
270 .attr('aria-label', I18n.getText('aui.sidebar.collapse.tooltip'));
271 } else {
272 this.collapse();
273 this.$el
274 .find('.aui-sidebar-toggle')
275 .attr('aria-label', I18n.getText('aui.sidebar.expand.tooltip'));
276 }
277 return this;
278};
279
280/**
281 * Returns a jQuery selector string for the trigger elements when the
282 * sidebar is in a collapsed state, useful for delegated event binding.
283 *
284 * When using this selector in event handlers, the element ("this") will
285 * either be an <a> (when the trigger was a tier-one menu item) or an
286 * element with class "aui-sidebar-group" (for non-tier-one items).
287 *
288 * For delegated event binding you should bind to $el and check the value
289 * of isCollapsed(), e.g.,
290 *
291 * sidebar.$el.on('click', sidebar.collapsedTriggersSelector, function (e) {
292 * if (!sidebar.isCollapsed()) {
293 * return;
294 * }
295 * });
296 *
297 * @returns string
298 */
299Sidebar.prototype.submenuTriggersSelector = '.aui-sidebar-group:not(.aui-sidebar-group-tier-one)';
300
301Sidebar.prototype.collapsedTriggersSelector = [
302 Sidebar.prototype.submenuTriggersSelector,
303 '.aui-sidebar-group.aui-sidebar-group-tier-one > .aui-nav > li > a',
304 '.aui-sidebar-footer > .aui-sidebar-settings-button'
305].join(', ');
306
307Sidebar.prototype.toggleSelector = '.aui-sidebar-footer > .aui-sidebar-toggle';
308
309Sidebar.prototype.tooltipClassName = 'aui-sidebar-section-tooltip';
310
311Sidebar.prototype.inlineDialogClass = 'aui-sidebar-submenu-dialog';
312Sidebar.prototype.inlineDialogSelector = '.' + Sidebar.prototype.inlineDialogClass;
313
314function getAllSubmenuDialogs() {
315 return document.querySelectorAll(Sidebar.prototype.inlineDialogSelector);
316}
317
318function SubmenuManager () {
319 this.inlineDialog = null;
320}
321
322SubmenuManager.prototype.submenu = function ($trigger) {
323 sidebarSubmenuDeprecationLogger();
324 return getSubmenu($trigger);
325};
326
327SubmenuManager.prototype.hasSubmenu = function ($trigger) {
328 sidebarSubmenuDeprecationLogger();
329 return hasSubmenu($trigger);
330};
331
332SubmenuManager.prototype.submenuHeadingHeight = function () {
333 sidebarSubmenuDeprecationLogger();
334 return 34;
335};
336
337SubmenuManager.prototype.isShowing = function () {
338 sidebarSubmenuDeprecationLogger();
339 return Sidebar.prototype.isSubmenuVisible();
340};
341
342SubmenuManager.prototype.show = function (e, trigger) {
343 sidebarSubmenuDeprecationLogger();
344 showSubmenu(trigger);
345};
346
347SubmenuManager.prototype.hide = function () {
348 sidebarSubmenuDeprecationLogger();
349 hideAllSubmenus();
350};
351
352SubmenuManager.prototype.inlineDialogShowHandler = function () {
353 sidebarSubmenuDeprecationLogger();
354};
355SubmenuManager.prototype.inlineDialogHideHandler = function () {
356 sidebarSubmenuDeprecationLogger();
357};
358SubmenuManager.prototype.moveSubmenuToInlineDialog = function () {
359 sidebarSubmenuDeprecationLogger();
360};
361SubmenuManager.prototype.restoreSubmenu = function () {
362 sidebarSubmenuDeprecationLogger();
363};
364
365Sidebar.prototype.getVisibleSubmenus = function () {
366 return Array.prototype.filter.call(getAllSubmenuDialogs(), function (inlineDialog2) {
367 return inlineDialog2.open;
368 });
369};
370
371Sidebar.prototype.isSubmenuVisible = function () {
372 return this.getVisibleSubmenus().length > 0;
373};
374
375function getSubmenu($trigger) {
376 return $trigger.is('a') ? $trigger.next('.aui-nav') : $trigger.children('.aui-nav, hr');
377}
378
379function getSubmenuInlineDialog(trigger) {
380 var inlineDialogId = trigger.getAttribute('aria-controls');
381 return document.getElementById(inlineDialogId);
382}
383
384function hasSubmenu($trigger) {
385 return getSubmenu($trigger).length !== 0;
386}
387
388function hideAllSubmenus() {
389 var allSubmenuDialogs = getAllSubmenuDialogs();
390 Array.prototype.forEach.call(allSubmenuDialogs, function (inlineDialog2) {
391 inlineDialog2.open = false;
392 });
393}
394
395function showSubmenu(trigger) {
396 getSubmenuInlineDialog(trigger).open = true;
397}
398
399function constructSubmenu(sidebar, $trigger) {
400 if ($trigger.data('_aui-sidebar-submenu-constructed')) {
401 return;
402 } else {
403 $trigger.data('_aui-sidebar-submenu-constructed', true)
404 }
405
406 if (!hasSubmenu($trigger)) {
407 return;
408 }
409
410 var submenuInlineDialog = document.createElement('aui-inline-dialog');
411
412 var uniqueId = uid('sidebar-submenu');
413
414 $trigger.attr('aria-controls', uniqueId);
415 $trigger.attr('data-aui-trigger', '');
416 skate.init($trigger); //Trigger doesn't listen to attribute modification
417
418 submenuInlineDialog.setAttribute('id', uniqueId);
419 submenuInlineDialog.setAttribute('alignment', 'right top');
420 submenuInlineDialog.setAttribute('hidden', '');
421 submenuInlineDialog.setAttribute('contained-by', 'viewport');
422 if (sidebar.isCollapsed()) {
423 submenuInlineDialog.setAttribute('responds-to', 'hover');
424 }
425
426 $(submenuInlineDialog).addClass(Sidebar.prototype.inlineDialogClass);
427
428 document.body.appendChild(submenuInlineDialog);
429 skate.init(submenuInlineDialog); //Needed so that sidebar.submenus.isShowing() will work on page load
430
431 addHandlersToSubmenuInlineDialog(sidebar, $trigger, submenuInlineDialog);
432
433 return submenuInlineDialog;
434}
435
436function didOtherLayerOpened(e) {
437 return e.target.tagName !== 'AUI-INLINE-DIALOG';
438}
439
440function didNestedInlineDialogOpened(e) {
441 return !e.target.classList.contains('aui-sidebar-submenu-dialog');
442}
443
444function addHandlersToSubmenuInlineDialog(sidebar, $trigger, submenuInlineDialog) {
445 submenuInlineDialog.addEventListener('aui-layer-show', function (e) {
446 if (!sidebar.isCollapsed()) {
447 e.preventDefault();
448 return;
449 }
450
451 // we only care if sidebars inline dialog is opening
452 if (didOtherLayerOpened(e) || didNestedInlineDialogOpened(e)) {
453 return;
454 }
455
456 /**
457 * trigger an event on inline dialog trigger and pass a reference to the inline dialog.
458 * this let's one perform actions and modify content before it is displayed, for example lazy load submenu content
459 */
460 var customEvent = $.Event('aui-sidebar-submenu-before-show');
461 $trigger.trigger(customEvent, submenuInlineDialog);
462 if (customEvent.isDefaultPrevented()) {
463 e.preventDefault();
464 return;
465 }
466 inlineDialogShowHandler($trigger, submenuInlineDialog);
467 });
468
469 submenuInlineDialog.addEventListener('aui-layer-hide', function () {
470 inlineDialogHideHandler($trigger);
471 });
472}
473
474function inlineDialogShowHandler($trigger, submenuInlineDialog) {
475 $trigger.addClass('active');
476 submenuInlineDialog.innerHTML = SUBMENU_INLINE_DIALOG_CONTENTS_HTML;
477 var title = $trigger.is('a') ? $trigger.text() : $trigger.children('.aui-nav-heading').text();
478
479 var $container = $(submenuInlineDialog).find('.aui-navgroup-inner');
480 $container.children('.aui-nav-heading')
481 .attr('title', title)
482 .children('strong')
483 .text(title);
484
485 var $submenu = getSubmenu($trigger);
486 cloneExpander($submenu).appendTo($container);
487
488 /**
489 * Workaround to show all contents in the expander.
490 * This function should come from the expander component.
491 */
492 function cloneExpander(element) {
493 const $clone = clone(element);
494 deduplicateIDs($clone, uid);
495
496 if ($clone.hasClass('aui-expander-content')) {
497 $clone.find('.aui-expander-cutoff').remove();
498 $clone.removeClass('aui-expander-content');
499 }
500 return $clone;
501 }
502}
503
504const SUBMENU_INLINE_DIALOG_CONTENTS_HTML =
505 '<div class="aui-inline-dialog-contents">' +
506 '<div class="aui-sidebar-submenu" >' +
507 '<div class="aui-navgroup aui-navgroup-vertical">' +
508 '<div class="aui-navgroup-inner">' +
509 '<div class="aui-nav-heading"><strong></strong></div>' +
510 '</div>' +
511 '</div>' +
512 '</div>' +
513 '</div>';
514
515function inlineDialogHideHandler($trigger) {
516 $trigger.removeClass('active');
517}
518
519function constructAllSubmenus(sidebar) {
520 $(sidebar.collapsedTriggersSelector).each(function () {
521 var $trigger = $(this);
522 constructSubmenu(sidebar, $trigger);
523 });
524}
525
526var tooltipOptions = {
527 gravity: 'w',
528 title: function () {
529 var $item = $(this);
530 if ($item.is('a') || $item.is('button')) {
531 return $item.attr('title') || $item.find('.aui-nav-item-label').text() || $item.data('tooltip');
532 } else {
533 return $item.children('.aui-nav').attr('title') || $item.children('.aui-nav-heading').text();
534 }
535 }
536};
537
538function lazilyInitializeSubmenus (sidebar) {
539 sidebar.$el.on('mouseenter mouseleave click focus', sidebar.collapsedTriggersSelector, function (e) {
540 const $trigger = $(e.target);
541 constructSubmenu(sidebar, $trigger);
542 });
543}
544
545function initializeHandlers(sidebar) {
546 var $sidebar = $('.aui-sidebar');
547 if (!$sidebar.length) {
548 return;
549 }
550
551 lazilyInitializeSubmenus(sidebar);
552
553 // AUI-2542: only enter touch mode on small screen touchable devices
554 if (hasTouch && mediaQuery('only screen and (max-device-width:1024px)')) {
555 $('body').addClass('aui-page-sidebar-touch');
556 }
557
558 var pendingReflow = null;
559 var onScrollResizeReflow = function () {
560 if (pendingReflow === null) {
561 pendingReflow = requestAnimationFrame(function () {
562 sidebar.reflow();
563 pendingReflow = null;
564 });
565 }
566 };
567
568 $(window).on('scroll resize', onScrollResizeReflow);
569 onScrollResizeReflow();
570
571 if (sidebar.isAnimated()) {
572 sidebar.$el.on('transitionend webkitTransitionEnd', function () {
573 sidebar.$el.trigger($.Event(EVENT_PREFIX + (sidebar.isCollapsed() ? 'collapse-end' : 'expand-end')));
574 });
575 }
576
577 sidebar.$el.on('click', '.aui-sidebar-toggle', function (e) {
578 e.preventDefault();
579 sidebar.toggle();
580 });
581
582 $('.aui-page-panel').on('click', function () {
583 if (!sidebar.isCollapsed() && sidebar.isViewportNarrow()) {
584 sidebar.collapse();
585 }
586 });
587
588 var toggleShortcutHandler = function (e) {
589 if (isNormalSquareBracket(e)) {
590 sidebar.toggle();
591 }
592 };
593
594 //We use keypress because it captures the actual character that was typed and not the physical key that was pressed.
595 //This accounts for other keyboard layouts
596
597 $(document).on('keypress', toggleShortcutHandler);
598
599 sidebar._remove = function () {
600 $(this.inlineDialogSelector).remove();
601 this.$el.off();
602 this.$el.remove();
603 $(document).off('keypress', toggleShortcutHandler);
604 $(window).off('scroll resize', onScrollResizeReflow);
605 };
606
607 sidebar.$el.on('touchend', function (e) {
608 if (sidebar.isCollapsed()) {
609 sidebar.expand();
610 e.preventDefault();
611 }
612 });
613
614 sidebar.$el.tooltip({
615 ...tooltipOptions,
616 live: sidebar.collapsedTriggersSelector,
617 suppress: function () {
618 const $trigger = $(this);
619 const sidebarIsExpanded = sidebar.isCollapsed() === false;
620 const triggerHasSubmenu = hasSubmenu($trigger) === true;
621 return triggerHasSubmenu || sidebarIsExpanded;
622 }
623 })
624
625 sidebar.$el.tooltip({
626 ...tooltipOptions,
627 aria: false,
628 live: sidebar.toggleSelector,
629 title: function () {
630 return sidebar.isCollapsed() ?
631 I18n.getText('aui.sidebar.expand.tooltip') :
632 I18n.getText('aui.sidebar.collapse.tooltip')
633 }
634 })
635
636 function isNormalTab(e) {
637 return e.keyCode === keyCode.TAB && !e.shiftKey && !e.altKey;
638 }
639
640 function isNormalSquareBracket(e) {
641 return e.which === keyCode.LEFT_SQUARE_BRACKET && !e.shiftKey && !e.ctrlKey && !e.metaKey && !isInput(e.target);
642 }
643
644 function isShiftTab(e) {
645 return e.keyCode === keyCode.TAB && e.shiftKey;
646 }
647
648 function isFirstSubmenuItem(item, $submenuDialog) {
649 return item === $submenuDialog.find(':aui-tabbable')[0];
650 }
651
652 function isLastSubmenuItem(item, $submenuDialog) {
653 return item === $submenuDialog.find(':aui-tabbable').last()[0];
654 }
655
656 /**
657 * Force to focus on the first tabbable item in inline dialog.
658 * Reason: inline dialog will be hidden as soon as the trigger is out of focus (onBlur event)
659 * This function should come directly from inline dialog component.
660 */
661 function focusFirstItemOfInlineDialog($inlineDialog) {
662 $inlineDialog.attr('persistent', '');
663 // don't use :aui-tabbable:first as it will select the first tabbable item in EACH nav group
664 $inlineDialog.find(':aui-tabbable').first().focus();
665 // workaround on IE:
666 // delay the persistence of inline dialog to make sure onBlur event was triggered first
667 setTimeout(function () {
668 $inlineDialog.removeAttr('persistent');
669 }, 100);
670 }
671
672 sidebar.$el.on('keydown', sidebar.collapsedTriggersSelector, function (e) {
673 if (sidebar.isCollapsed()) {
674 var triggerEl = e.target;
675 var submenuInlineDialog = getSubmenuInlineDialog(triggerEl);
676 if (!submenuInlineDialog) {
677 return;
678 }
679
680 var $submenuInlineDialog = $(submenuInlineDialog);
681
682 if (isNormalTab(e) && submenuInlineDialog.open) {
683 e.preventDefault();
684 focusFirstItemOfInlineDialog($submenuInlineDialog);
685
686 $submenuInlineDialog.on('keydown', function (e) {
687 if (isShiftTab(e) && isFirstSubmenuItem(e.target, $submenuInlineDialog) || isNormalTab(e) && isLastSubmenuItem(e.target, $submenuInlineDialog)) {
688 triggerEl.focus();
689 // unbind event and close submenu as the focus is out of the submenu
690 $(this).off('keydown');
691 hideAllSubmenus();
692 }
693 });
694 }
695 }
696 });
697}
698
699var sidebar = widget('sidebar', Sidebar);
700
701$(function () {
702 sidebar('.aui-sidebar');
703});
704
705var sidebarSubmenuDeprecationLogger = deprecate.getMessageLogger('Sidebar.submenus', {
706 removeInVersion: '10.0.0',
707 sinceVersion: '5.8.0'
708});
709
710globalize('sidebar', sidebar);
711
712export default sidebar;