mirror of
https://github.com/the-djmaze/snappymail.git
synced 2026-07-13 03:27:39 +03:00
Solve menu arrow navigation
https://github.com/the-djmaze/snappymail/issues/22
This commit is contained in:
parent
250caab957
commit
f25d210f3e
8 changed files with 28 additions and 37 deletions
4
dev/External/ko.js
vendored
4
dev/External/ko.js
vendored
|
|
@ -48,9 +48,9 @@ ko.bindingHandlers.tooltipErrorTip = {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
ko.bindingHandlers.registrateBootstrapDropdown = {
|
ko.bindingHandlers.registerBootstrapDropdown = {
|
||||||
init: element => {
|
init: element => {
|
||||||
rl.Dropdowns.registrate(element);
|
rl.Dropdowns.register(element);
|
||||||
element.ddBtn = new BSN.Dropdown(element.querySelector('[data-toggle="dropdown"]'));
|
element.ddBtn = new BSN.Dropdown(element.querySelector('[data-toggle="dropdown"]'));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
7
dev/bootstrap.js
vendored
7
dev/bootstrap.js
vendored
|
|
@ -45,12 +45,9 @@ export default (App) => {
|
||||||
rl.Enums = Enums;
|
rl.Enums = Enums;
|
||||||
|
|
||||||
rl.Dropdowns = [];
|
rl.Dropdowns = [];
|
||||||
rl.Dropdowns.registrate = function(element) {
|
rl.Dropdowns.register = function(element) { this.push(element); };
|
||||||
this.push(element);
|
|
||||||
element.addEventListener('click', () => rl.Dropdowns.detectVisibility());
|
|
||||||
};
|
|
||||||
rl.Dropdowns.detectVisibility = (() =>
|
rl.Dropdowns.detectVisibility = (() =>
|
||||||
dropdownVisibility(!!rl.Dropdowns.find(item => item.classList.contains('open')))
|
dropdownVisibility(!!rl.Dropdowns.find(item => item.classList.contains('show')))
|
||||||
).debounce(50);
|
).debounce(50);
|
||||||
|
|
||||||
rl.route = {
|
rl.route = {
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="btn-group" data-bind="visible: allowReload && mobileCheckedStateHide()"> </div>
|
<div class="btn-group" data-bind="visible: allowReload && mobileCheckedStateHide()"> </div>
|
||||||
<!-- ko if: !newMoveToFolder -->
|
<!-- ko if: !newMoveToFolder -->
|
||||||
<div class="btn-group dropdown colored-toggle hide-on-mobile" data-bind="visible: allowMessageListActions, registrateBootstrapDropdown: true, openDropdownTrigger: moveDropdownTrigger">
|
<div class="btn-group dropdown colored-toggle hide-on-mobile" data-bind="visible: allowMessageListActions, registerBootstrapDropdown: true, openDropdownTrigger: moveDropdownTrigger">
|
||||||
<a id="move-dropdown-id" href="#" tabindex="-1" class="btn single btn-dark-disabled-border dropdown-toggle buttonMove" data-toggle="dropdown" data-bind="command: moveCommand, tooltip: 'MESSAGE_LIST/BUTTON_MOVE_TO'">
|
<a id="move-dropdown-id" href="#" tabindex="-1" class="btn single btn-dark-disabled-border dropdown-toggle buttonMove" data-toggle="dropdown" data-bind="command: moveCommand, tooltip: 'MESSAGE_LIST/BUTTON_MOVE_TO'">
|
||||||
<i class="icon-copy visible-on-ctrl-btn"></i>
|
<i class="icon-copy visible-on-ctrl-btn"></i>
|
||||||
<i class="icon-folder hidden-on-ctrl-btn"></i>
|
<i class="icon-folder hidden-on-ctrl-btn"></i>
|
||||||
|
|
@ -73,7 +73,7 @@
|
||||||
<!--<span data-bind="text: printableMessageCountForDeletion()"></span>-->
|
<!--<span data-bind="text: printableMessageCountForDeletion()"></span>-->
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="btn-group dropdown colored-toggle" data-bind="visible: allowComposer || allowMessageListActions || allowDangerousActions, registrateBootstrapDropdown: true, openDropdownTrigger: moreDropdownTrigger">
|
<div class="btn-group dropdown colored-toggle" data-bind="visible: allowComposer || allowMessageListActions || allowDangerousActions, registerBootstrapDropdown: true, openDropdownTrigger: moreDropdownTrigger">
|
||||||
<a id="more-list-dropdown-id" class="btn single btn-dark-disabled-border dropdown-toggle buttonMore" href="#" tabindex="-1" data-toggle="dropdown" data-bind="tooltip: 'MESSAGE_LIST/BUTTON_MORE'">
|
<a id="more-list-dropdown-id" class="btn single btn-dark-disabled-border dropdown-toggle buttonMore" href="#" tabindex="-1" data-toggle="dropdown" data-bind="tooltip: 'MESSAGE_LIST/BUTTON_MORE'">
|
||||||
<i class="icon-list animate-this-icon-on-open"></i>
|
<i class="icon-list animate-this-icon-on-open"></i>
|
||||||
</a>
|
</a>
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,7 @@
|
||||||
|
|
||||||
<div class="message-fixed-button-toolbar clearfix" data-bind="visible: message">
|
<div class="message-fixed-button-toolbar clearfix" data-bind="visible: message">
|
||||||
<div class="btn-group pull-right" style="margin-right: -11px;">
|
<div class="btn-group pull-right" style="margin-right: -11px;">
|
||||||
<div class="btn-group pull-right" data-bind="registrateBootstrapDropdown: true, visible: allowComposer || allowMessageListActions || allowMessageActions">
|
<div class="btn-group pull-right" data-bind="registerBootstrapDropdown: true, visible: allowComposer || allowMessageListActions || allowMessageActions">
|
||||||
<a class="btn btn-thin-2 btn-transparent last btn-dark-disabled-border dropdown-toggle buttonMore" id="more-view-dropdown-id" href="#" tabindex="-1" data-toggle="dropdown" style="margin-left: -4px; margin-right: 2px" data-bind="command: messageVisibilityCommand, css: {'first': !allowComposer}">
|
<a class="btn btn-thin-2 btn-transparent last btn-dark-disabled-border dropdown-toggle buttonMore" id="more-view-dropdown-id" href="#" tabindex="-1" data-toggle="dropdown" style="margin-left: -4px; margin-right: 2px" data-bind="command: messageVisibilityCommand, css: {'first': !allowComposer}">
|
||||||
<span data-bind="visible: !allowComposer" class="icon-ellipsis-alt"></span>
|
<span data-bind="visible: !allowComposer" class="icon-ellipsis-alt"></span>
|
||||||
<span data-bind="visible: allowComposer" class="caret"></span>
|
<span data-bind="visible: allowComposer" class="caret"></span>
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="e-cell e-value">
|
<div class="e-cell e-value">
|
||||||
<div class="dropdown pull-left" data-bind="registrateBootstrapDropdown: true, openDropdownTrigger: identitiesDropdownTrigger">
|
<div class="dropdown pull-left" data-bind="registerBootstrapDropdown: true, openDropdownTrigger: identitiesDropdownTrigger">
|
||||||
<a class="dropdown-toggle e-identity" href="#" tabindex="-1"
|
<a class="dropdown-toggle e-identity" href="#" tabindex="-1"
|
||||||
id="identity-label-id" role="button" data-toggle="dropdown"
|
id="identity-label-id" role="button" data-toggle="dropdown"
|
||||||
data-bind="text: currentIdentityView, dropdownCloser: true, css: {'multiply': 1 < identitiesOptions().length }">
|
data-bind="text: currentIdentityView, dropdownCloser: true, css: {'multiply': 1 < identitiesOptions().length }">
|
||||||
|
|
@ -45,7 +45,7 @@
|
||||||
<!-- /ko -->
|
<!-- /ko -->
|
||||||
</div>
|
</div>
|
||||||
<div class="pull-right">
|
<div class="pull-right">
|
||||||
<div class="btn-group dropdown colored-toggle pull-right" style="margin-right: 4px;" data-bind="registrateBootstrapDropdown: true">
|
<div class="btn-group dropdown colored-toggle pull-right" style="margin-right: 4px;" data-bind="registerBootstrapDropdown: true">
|
||||||
<a class="btn single dropdown-toggle buttonMore" data-toggle="dropdown">
|
<a class="btn single dropdown-toggle buttonMore" data-toggle="dropdown">
|
||||||
<i class="icon-list"></i>
|
<i class="icon-list"></i>
|
||||||
</a>
|
</a>
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="btn-group dropdown colored-toggle" data-bind="registrateBootstrapDropdown: true">
|
<div class="btn-group dropdown colored-toggle" data-bind="registerBootstrapDropdown: true">
|
||||||
<a id="contacts-more-dropdown-id" class="btn single dropdown-toggle buttonMore" href="#" tabindex="-1" data-toggle="dropdown">
|
<a id="contacts-more-dropdown-id" class="btn single dropdown-toggle buttonMore" href="#" tabindex="-1" data-toggle="dropdown">
|
||||||
<i data-bind="css: {'icon-list': !contacts.importing() && !contacts.syncing(),
|
<i data-bind="css: {'icon-list': !contacts.importing() && !contacts.syncing(),
|
||||||
'icon-spinner animated': contacts.importing() || contacts.syncing()}"></i>
|
'icon-spinner animated': contacts.importing() || contacts.syncing()}"></i>
|
||||||
|
|
@ -108,7 +108,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="b-view-content-toolbar btn-toolbar" data-bind="css: {'read-only': viewReadOnly}">
|
<div class="b-view-content-toolbar btn-toolbar" data-bind="css: {'read-only': viewReadOnly}">
|
||||||
<div class="btn-group pull-right dropdown colored-toggle button-add-prop" data-bind="visible: !emptySelection(), registrateBootstrapDropdown: true">
|
<div class="btn-group pull-right dropdown colored-toggle button-add-prop" data-bind="visible: !emptySelection(), registerBootstrapDropdown: true">
|
||||||
<a id="button-add-prop-dropdown-id" href="#" tabindex="-1" class="btn single dropdown-toggle" data-toggle="dropdown">
|
<a id="button-add-prop-dropdown-id" href="#" tabindex="-1" class="btn single dropdown-toggle" data-toggle="dropdown">
|
||||||
<span class="i18n" data-i18n="CONTACTS/ADD_MENU_LABEL"></span>
|
<span class="i18n" data-i18n="CONTACTS/ADD_MENU_LABEL"></span>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
<div class="b-system-drop-down g-ui-user-select-none">
|
<div class="b-system-drop-down g-ui-user-select-none">
|
||||||
<div class="b-toolbar">
|
<div class="b-toolbar">
|
||||||
<div class="btn-toolbar">
|
<div class="btn-toolbar">
|
||||||
<div class="btn-group btn-group-last pull-right dropdown colored-toggle" data-bind="registrateBootstrapDropdown: true, openDropdownTrigger: accountMenuDropdownTrigger">
|
<div class="btn-group btn-group-last pull-right dropdown colored-toggle" data-bind="registerBootstrapDropdown: true, openDropdownTrigger: accountMenuDropdownTrigger">
|
||||||
<a id="top-system-dropdown-id" href="#" tabindex="-1" class="btn single btn-ellipsis btn-block dropdown-toggle system-dropdown" data-toggle="dropdown">
|
<a id="top-system-dropdown-id" href="#" tabindex="-1" class="btn single btn-ellipsis btn-block dropdown-toggle system-dropdown" data-toggle="dropdown">
|
||||||
<i data-bind="css: {'icon-user': !accounts.loading(), 'icon-spinner animated': accounts.loading()}"></i>
|
<i data-bind="css: {'icon-user': !accounts.loading(), 'icon-spinner animated': accounts.loading()}"></i>
|
||||||
<!--
|
<!--
|
||||||
|
|
|
||||||
38
vendors/bootstrap/js/bootstrap.native.js
vendored
38
vendors/bootstrap/js/bootstrap.native.js
vendored
|
|
@ -42,32 +42,26 @@
|
||||||
},
|
},
|
||||||
preventScroll = e => (e.key === 'ArrowUp' || e.key === 'ArrowDown') && e.preventDefault(),
|
preventScroll = e => (e.key === 'ArrowUp' || e.key === 'ArrowDown') && e.preventDefault(),
|
||||||
keyHandler = e => {
|
keyHandler = e => {
|
||||||
let activeItem = doc.activeElement,
|
if (e.key === 'Escape') {
|
||||||
isSameElement = activeItem === element,
|
|
||||||
isInsideMenu = menu.contains(activeItem),
|
|
||||||
isMenuItem = activeItem.parentNode === menu || activeItem.parentNode.parentNode === menu,
|
|
||||||
idx = menuItems.indexOf(activeItem);
|
|
||||||
if ( isMenuItem ) {
|
|
||||||
idx = isSameElement ? 0
|
|
||||||
: e.key === 'ArrowUp' ? (idx>1?idx-1:0)
|
|
||||||
: e.key === 'ArrowDown' ? (idx<menuItems.length-1?idx+1:idx) : idx;
|
|
||||||
menuItems[idx] && setFocus(menuItems[idx]);
|
|
||||||
}
|
|
||||||
if ( (menuItems.length && isMenuItem
|
|
||||||
|| !menuItems.length && (isInsideMenu || isSameElement)
|
|
||||||
|| !isInsideMenu )
|
|
||||||
&& element.open && e.key === 'Escape'
|
|
||||||
) {
|
|
||||||
self.toggle();
|
self.toggle();
|
||||||
|
} else if (e.key === 'ArrowUp' || e.key === 'ArrowDown') {
|
||||||
|
let activeItem = doc.activeElement,
|
||||||
|
isMenuButton = activeItem === element,
|
||||||
|
idx = isMenuButton ? 0 : menuItems.indexOf(activeItem);
|
||||||
|
if (parent.contains(activeItem)) {
|
||||||
|
if (!isMenuButton) {
|
||||||
|
idx = e.key === 'ArrowUp' ? (idx > 1 ? idx-1 : 0)
|
||||||
|
: e.key === 'ArrowDown' ? (idx < menuItems.length-1 ? idx+1 : idx) : idx;
|
||||||
|
}
|
||||||
|
menuItems[idx] && setFocus(menuItems[idx]);
|
||||||
|
} else {
|
||||||
|
console.log('activeElement not in menu');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
self.show = () => {
|
self.show = () => {
|
||||||
menu = parent.querySelector('.dropdown-menu');
|
menu = parent.querySelector('.dropdown-menu');
|
||||||
menuItems = [];
|
menuItems = [...menu.querySelectorAll('A')].filter(item => 'none' != item.parentNode.style.display);
|
||||||
[...menu.children].forEach(child => {
|
|
||||||
child.children.length && (child.children[0].tagName === 'A' && menuItems.push(child.children[0]));
|
|
||||||
child.tagName === 'A' && menuItems.push(child);
|
|
||||||
});
|
|
||||||
!('tabindex' in menu) && menu.setAttribute('tabindex', '0');
|
!('tabindex' in menu) && menu.setAttribute('tabindex', '0');
|
||||||
menu.classList.add('show');
|
menu.classList.add('show');
|
||||||
parent.classList.add('show');
|
parent.classList.add('show');
|
||||||
|
|
@ -88,7 +82,7 @@
|
||||||
setFocus(element);
|
setFocus(element);
|
||||||
setTimeout(() => element.Dropdown && element.addEventListener('click',clickHandler), 1);
|
setTimeout(() => element.Dropdown && element.addEventListener('click',clickHandler), 1);
|
||||||
};
|
};
|
||||||
self.toggle = () => (parent.classList.contains('show') && element.open) ? self.hide() : self.show();
|
self.toggle = () => element.open ? self.hide() : self.show();
|
||||||
element.addEventListener('click',clickHandler);
|
element.addEventListener('click',clickHandler);
|
||||||
element.open = false;
|
element.open = false;
|
||||||
element.Dropdown = self;
|
element.Dropdown = self;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue