ui/lib/shared/addon/mixins/hover-dropdowns.js

269 lines
6.5 KiB
JavaScript

import { later, cancel } from '@ember/runloop';
import $ from 'jquery';
import Mixin from '@ember/object/mixin';
import C from 'ui/utils/constants';
import { positionDropdown } from 'ui/utils/position-dropdown';
const DROPDOWNCLOSETIMER = 250;
const PARENT = 'HEADER NAV';
const SELECTOR = 'NAV .dropdown';
const WINDOW_SM = 694;
let timerObj = null;
let dropdown = null;
export default Mixin.create({
willRender(){
if ($('BODY').hasClass('touch')) {
later(() => {
this.clearHeaderMenus();
}, DROPDOWNCLOSETIMER);
}
},
didInsertElement: function() {
let $body = $('BODY');
if ($body.hasClass('touch') && $(window).width() <= WINDOW_SM) {
// below iphone 6plus vertical width no need for dropdown logic
this.$().on('click', () => {
if (dropdown) {
later(() => {
this.clearHeaderMenus();
}, DROPDOWNCLOSETIMER);
}
});
this.$('[data-toggle="header-user-menu"]').on('touchstart', (e) => {
e.preventDefault();
e.stopPropagation();
this.touchHandler(e);
});
this.$('ul[data-dropdown-id="enviroment"] > li > a').on('touchend', () => {
if (dropdown) {
later(() => {
this.clearHeaderMenus();
}, DROPDOWNCLOSETIMER);
}
});
} else {
// ipad/tablet width
$body.on('touchend', (e) => {
let $el = $(e.target);
if ($el.closest('.navbar').length < 1) {
later(() => {
this.clearHeaderMenus();
});
}
});
this.$().on('touchstart', SELECTOR, (e) => {
let $el = $(e.currentTarget).find('a.dropdown-toggle');
if ($el.attr('aria-expanded') === 'false') {
e.preventDefault();
e.stopPropagation();
this.enterHandler(e);
}
});
// desktop width
this.$().on('click', SELECTOR, (e) => {
this.onClickHandler(e, false);
});
this.$().on('mouseenter', SELECTOR, (e) => {
this.enterHandler(e, false);
});
this.$().on('mouseleave', SELECTOR, () => {
this.leaveHandler();
});
this.$().on('keydown', `${SELECTOR} a`, (e) => {
this.keydownHandler(e);
});
}
},
touchHandler(e) {
let anchor = $(e.currentTarget);
cancel(timerObj);
timerObj = null;
if (dropdown) { // dropdown open alread
if (dropdown.data('dropdown-id') !== $(e.currentTarget).find('ul').data('dropdown-id')) { // not the same dropdown
this.clearHeaderMenus();
dropdown = $(e.currentTarget).siblings('ul');
if (dropdown) {
this.showMenu(anchor, dropdown);
}
}
} else { // no dropdown open
dropdown = $(e.currentTarget).siblings('ul');
if (dropdown) {
this.showMenu(anchor, dropdown);
}
}
},
enterHandler(e) {
let anchor = $(e.currentTarget).find('.dropdown-toggle');
let dataTarget = anchor.data('toggle') ? anchor.data('toggle') : null;
let findTarget = dataTarget ? `ul[data-dropdown-id ="${dataTarget}"]` : 'ul';
let offset = null;
if (anchor.data('offset-x') || anchor.data('offset-y')) {
offset = {};
if (anchor.data('offset-x')) {
offset.x = anchor.data('offset-x');
}
if (anchor.data('offset-y')) {
offset.y = anchor.data('offset-y');
}
}
cancel(timerObj);
timerObj = null;
if (dropdown) { // dropdown open alread
if (dropdown.data('dropdown-id') !== $(e.currentTarget).find('ul').data('dropdown-id')) { // not the same dropdown
this.clearHeaderMenus();
dropdown = $(e.currentTarget).find('ul');
if (dropdown) {
this.showMenu(anchor, dropdown, offset);
}
}
} else { // no dropdown open
dropdown = $(e.currentTarget).find(findTarget);
if (dropdown) {
this.showMenu(anchor, dropdown, offset);
}
}
},
leaveHandler() {
timerObj = later(() => {
if (dropdown) {
this.clearHeaderMenus();
timerObj = null;
}
}, DROPDOWNCLOSETIMER);
},
onClickHandler(e) {
let anchor = $(e.target).closest('A');
if ( anchor.hasClass('dropdown-toggle') && anchor[0].href.match(/#$/) ) {
e.preventDefault();
e.stopPropagation();
return false;
}
timerObj = null;
let collapsedNav = $('#navbar');
if (collapsedNav.hasClass('in')) {
collapsedNav.collapse('toggle');
}
this.clearHeaderMenus();
},
keydownHandler(e) {
let items = this.get('items');
let currentIndex = 0;
let element = $(e.currentTarget);
let dropdownMenu = element.siblings('ul').length ? element.siblings('ul') : element.parent().parent('ul'); // if we're not in the top link we're in the ul links
if (dropdownMenu) {
items = dropdownMenu.find('li > a');
currentIndex = items.index(e.currentTarget);
if (currentIndex < 0) {
currentIndex = 0;
}
}
switch (e.which) {
case C.KEY.ESCAPE:
this.clearHeaderMenus();
element.focus();
break;
case C.KEY.SPACE:
this.clearHeaderMenus();
this.showMenu(element, dropdownMenu);
break;
case C.KEY.UP:
if (currentIndex > 0) {
currentIndex--;
}
items.eq(currentIndex).focus();
break;
case C.KEY.DOWN:
var $currentTarget = $(e.currentTarget);
if (dropdownMenu && !$currentTarget.parent().parent('ul.dropdown-menu').length) {
this.clearHeaderMenus();
this.showMenu(element, dropdownMenu);
dropdownMenu.addClass('block');
if (element.attr('aria-expanded') === false) {
element.attr('aria-expanded', true);
}
} else {
if (currentIndex < items.length -1) {
currentIndex++;
}
}
items.eq(currentIndex).focus();
break;
default:
break;
}
},
showMenu: function(el, drpd, offset) {
drpd.addClass('invisible');
drpd.addClass('block');
positionDropdown(drpd, el, drpd.hasClass('dropdown-menu-right'), offset);
drpd.removeClass('invisible');
if (el.attr('aria-expanded')) {
el.attr('aria-expanded', true);
}
},
clearHeaderMenus: function() {
const navbar = $(PARENT);
dropdown = null;
navbar.find('.dropdown-menu.block').removeClass('block');
navbar.find('a.dropdown-toggle[aria-expanded=true]').attr('aria-expanded', false);
}
});