mirror of
https://github.com/the-djmaze/snappymail.git
synced 2026-07-13 03:27:39 +03:00
Dropdown menu keyboard navigation (step 1 / USTABLE)
This commit is contained in:
parent
cd6974ecd2
commit
2ad305e40e
15 changed files with 305 additions and 228 deletions
|
|
@ -37,6 +37,7 @@ Enums.KeyState = {
|
||||||
'MessageList': 'message-list',
|
'MessageList': 'message-list',
|
||||||
'MessageView': 'message-view',
|
'MessageView': 'message-view',
|
||||||
'Compose': 'compose',
|
'Compose': 'compose',
|
||||||
|
'Menu': 'menu',
|
||||||
'PopupComposeOpenPGP': 'compose-open-pgp',
|
'PopupComposeOpenPGP': 'compose-open-pgp',
|
||||||
'PopupAsk': 'popup-ask'
|
'PopupAsk': 'popup-ask'
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -126,6 +126,15 @@ ko.bindingHandlers.onEsc = {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
ko.bindingHandlers.clickOnTrue = {
|
||||||
|
'update': function (oElement, fValueAccessor) {
|
||||||
|
if (ko.utils.unwrapObservable(fValueAccessor()))
|
||||||
|
{
|
||||||
|
$(oElement).click();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
ko.bindingHandlers.modal = {
|
ko.bindingHandlers.modal = {
|
||||||
'init': function (oElement, fValueAccessor) {
|
'init': function (oElement, fValueAccessor) {
|
||||||
$(oElement).toggleClass('fade', !Globals.bMobileDevice) .modal({
|
$(oElement).toggleClass('fade', !Globals.bMobileDevice) .modal({
|
||||||
|
|
|
||||||
|
|
@ -320,6 +320,7 @@ Selector.prototype.init = function (oContentVisible, oContentScrollable, sKeySco
|
||||||
})
|
})
|
||||||
;
|
;
|
||||||
|
|
||||||
|
// TODO
|
||||||
key('enter', sKeyScope, function () {
|
key('enter', sKeyScope, function () {
|
||||||
if (self.focusedItem())
|
if (self.focusedItem())
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,17 @@ function WebMailDataStorage()
|
||||||
this.projectHash = ko.observable('');
|
this.projectHash = ko.observable('');
|
||||||
this.threading = ko.observable(false);
|
this.threading = ko.observable(false);
|
||||||
|
|
||||||
|
this.accountMenuFocus = ko.observable(false);
|
||||||
|
this.accountMenuFocus.sKeyState = Enums.KeyState.All;
|
||||||
|
|
||||||
|
this.accountMenuFocus.subscribe(function (bValue) {
|
||||||
|
if (bValue)
|
||||||
|
{
|
||||||
|
this.accountMenuFocus.sKeyState = RL.data().keyScope();
|
||||||
|
}
|
||||||
|
RL.data().keyScope(bValue ? Enums.KeyState.Menu : this.accountMenuFocus.sKeyState);
|
||||||
|
}, this);
|
||||||
|
|
||||||
this.lastFoldersHash = '';
|
this.lastFoldersHash = '';
|
||||||
this.remoteSuggestions = false;
|
this.remoteSuggestions = false;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -60,10 +60,10 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.e-item.selected > .e-link {
|
.e-item.selected > .e-link {
|
||||||
background-color: #eee;
|
background-color: #eee !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.e-item > .e-link:hover {
|
.e-item > .e-link:focus, .e-item > .e-link:hover {
|
||||||
background-color: #555;
|
background-color: #555;
|
||||||
background-image: none;
|
background-image: none;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,8 @@ function AbstractSystemDropDownViewModel()
|
||||||
this.accounts = oData.accounts;
|
this.accounts = oData.accounts;
|
||||||
this.accountEmail = oData.accountEmail;
|
this.accountEmail = oData.accountEmail;
|
||||||
this.accountsLoading = oData.accountsLoading;
|
this.accountsLoading = oData.accountsLoading;
|
||||||
|
this.accountMenuFocus = oData.accountMenuFocus;
|
||||||
|
|
||||||
this.allowAddAccount = RL.settingsGet('AllowAdditionalAccounts');
|
this.allowAddAccount = RL.settingsGet('AllowAdditionalAccounts');
|
||||||
|
|
||||||
this.loading = ko.computed(function () {
|
this.loading = ko.computed(function () {
|
||||||
|
|
@ -20,6 +22,14 @@ function AbstractSystemDropDownViewModel()
|
||||||
}, this);
|
}, this);
|
||||||
|
|
||||||
this.accountClick = _.bind(this.accountClick, this);
|
this.accountClick = _.bind(this.accountClick, this);
|
||||||
|
|
||||||
|
key('`', function () {
|
||||||
|
if (oData.useKeyboardShortcuts() && !RL.popupVisibility() &&
|
||||||
|
!oData.accountMenuFocus())
|
||||||
|
{
|
||||||
|
oData.accountMenuFocus(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
_.extend(AbstractSystemDropDownViewModel.prototype, KnoinAbstractViewModel.prototype);
|
_.extend(AbstractSystemDropDownViewModel.prototype, KnoinAbstractViewModel.prototype);
|
||||||
|
|
|
||||||
|
|
@ -89,7 +89,7 @@
|
||||||
background-color: @dropdown-menu-selected-background-color !important;
|
background-color: @dropdown-menu-selected-background-color !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.g-ui-menu .e-item > .e-link:hover {
|
.g-ui-menu .e-item > .e-link:hover, .g-ui-menu .e-item > .e-link:focus {
|
||||||
color: @dropdown-menu-hover-color !important;
|
color: @dropdown-menu-hover-color !important;
|
||||||
background-color: @dropdown-menu-hover-background-color !important;
|
background-color: @dropdown-menu-hover-background-color !important;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,17 +10,19 @@
|
||||||
|
|
||||||
</div>-->
|
</div>-->
|
||||||
<div class="btn-group pull-right">
|
<div class="btn-group pull-right">
|
||||||
<a class="btn btn-ellipsis btn-block dropdown-toggle system-dropdown" data-placement="left" data-toggle="dropdown"
|
<a id="top-system-dropdown-id" href="#" tabindex="-1" class="btn btn-ellipsis btn-block dropdown-toggle system-dropdown"
|
||||||
data-tooltip-class="tooltip-big" data-bind="tooltip2: emailTitle">
|
data-placement="left" data-toggle="dropdown"
|
||||||
|
data-tooltip-class="tooltip-big" data-bind="tooltip2: emailTitle, hasfocus: accountMenuFocus">
|
||||||
|
|
||||||
<i data-bind="css: {'icon-user': !loading(), 'icon-spinner animated': loading()}"></i>
|
<i data-bind="css: {'icon-user': !loading(), 'icon-spinner animated': loading()}"></i>
|
||||||
|
|
||||||
<span class="caret"></span>
|
<span class="caret"></span>
|
||||||
</a>
|
</a>
|
||||||
<ul class="dropdown-menu g-ui-menu" role="menu">
|
<ul class="dropdown-menu g-ui-menu" tabindex="-1" role="menu" aria-labelledby="top-system-dropdown-id">
|
||||||
<!-- ko if: accounts().length -->
|
<!-- ko if: accounts().length -->
|
||||||
<!-- ko foreach: accounts -->
|
<!-- ko foreach: accounts -->
|
||||||
<li class="e-item">
|
<li class="e-item" role="presentation">
|
||||||
<a class="e-link" data-bind="click: $root.accountClick, attr: {'href': changeAccountLink() }">
|
<a class="e-link menuitem" href="#" data-bind="click: $root.accountClick, attr: {'href': changeAccountLink() }">
|
||||||
<i class="icon-ok" data-bind="visible: $root.accountEmail() === email"></i>
|
<i class="icon-ok" data-bind="visible: $root.accountEmail() === email"></i>
|
||||||
<i class="icon-user" data-bind="visible: $root.accountEmail() !== email"></i>
|
<i class="icon-user" data-bind="visible: $root.accountEmail() !== email"></i>
|
||||||
|
|
||||||
|
|
@ -28,28 +30,28 @@
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<!-- /ko -->
|
<!-- /ko -->
|
||||||
<li class="divider"></li>
|
<li class="divider" role="presentation"></li>
|
||||||
<!-- /ko -->
|
<!-- /ko -->
|
||||||
<!-- ko if: allowAddAccount -->
|
<!-- ko if: allowAddAccount -->
|
||||||
<li class="e-item">
|
<li class="e-item" role="presentation">
|
||||||
<a class="e-link" data-bind="click: addAccountClick">
|
<a class="e-link menuitem" href="#" tabindex="-1" data-bind="click: addAccountClick">
|
||||||
<i class="icon-user-add"></i>
|
<i class="icon-user-add"></i>
|
||||||
|
|
||||||
<span class="i18n" data-i18n-text="TOP_TOOLBAR/BUTTON_ADD_ACCOUNT"></span>
|
<span class="i18n" data-i18n-text="TOP_TOOLBAR/BUTTON_ADD_ACCOUNT"></span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<!-- /ko -->
|
<!-- /ko -->
|
||||||
<li class="e-item">
|
<li class="e-item" role="presentation">
|
||||||
<a class="e-link" data-bind="click: settingsClick">
|
<a class="e-link menuitem" href="#" tabindex="-1" data-bind="click: settingsClick">
|
||||||
<i class="icon-cog"></i>
|
<i class="icon-cog"></i>
|
||||||
|
|
||||||
<span class="i18n" data-i18n-text="TOP_TOOLBAR/BUTTON_SETTINGS"></span>
|
<span class="i18n" data-i18n-text="TOP_TOOLBAR/BUTTON_SETTINGS"></span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li class="divider"></li>
|
<li class="divider" role="presentation"></li>
|
||||||
<li class="e-item">
|
<li class="e-item" role="presentation">
|
||||||
<a class="e-link" data-bind="click: logoutClick">
|
<a class="e-link menuitem" href="#" tabindex="-1" data-bind="click: logoutClick">
|
||||||
<i class="icon-power"></i>
|
<i class="icon-power"></i>
|
||||||
|
|
||||||
<span class="i18n" data-i18n-text="TOP_TOOLBAR/BUTTON_LOGOUT"></span>
|
<span class="i18n" data-i18n-text="TOP_TOOLBAR/BUTTON_LOGOUT"></span>
|
||||||
|
|
|
||||||
|
|
@ -5861,8 +5861,9 @@ html.no-rgba .modal {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
.g-ui-menu .e-item.selected > .e-link {
|
.g-ui-menu .e-item.selected > .e-link {
|
||||||
background-color: #eee;
|
background-color: #eee !important;
|
||||||
}
|
}
|
||||||
|
.g-ui-menu .e-item > .e-link:focus,
|
||||||
.g-ui-menu .e-item > .e-link:hover {
|
.g-ui-menu .e-item > .e-link:hover {
|
||||||
background-color: #555;
|
background-color: #555;
|
||||||
background-image: none;
|
background-image: none;
|
||||||
|
|
|
||||||
2
rainloop/v/0.0.0/static/css/app.min.css
vendored
2
rainloop/v/0.0.0/static/css/app.min.css
vendored
File diff suppressed because one or more lines are too long
|
|
@ -377,6 +377,7 @@ Enums.KeyState = {
|
||||||
'MessageList': 'message-list',
|
'MessageList': 'message-list',
|
||||||
'MessageView': 'message-view',
|
'MessageView': 'message-view',
|
||||||
'Compose': 'compose',
|
'Compose': 'compose',
|
||||||
|
'Menu': 'menu',
|
||||||
'PopupComposeOpenPGP': 'compose-open-pgp',
|
'PopupComposeOpenPGP': 'compose-open-pgp',
|
||||||
'PopupAsk': 'popup-ask'
|
'PopupAsk': 'popup-ask'
|
||||||
};
|
};
|
||||||
|
|
@ -2764,6 +2765,15 @@ ko.bindingHandlers.onEsc = {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
ko.bindingHandlers.clickOnTrue = {
|
||||||
|
'update': function (oElement, fValueAccessor) {
|
||||||
|
if (ko.utils.unwrapObservable(fValueAccessor()))
|
||||||
|
{
|
||||||
|
$(oElement).click();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
ko.bindingHandlers.modal = {
|
ko.bindingHandlers.modal = {
|
||||||
'init': function (oElement, fValueAccessor) {
|
'init': function (oElement, fValueAccessor) {
|
||||||
$(oElement).toggleClass('fade', !Globals.bMobileDevice) .modal({
|
$(oElement).toggleClass('fade', !Globals.bMobileDevice) .modal({
|
||||||
|
|
|
||||||
8
rainloop/v/0.0.0/static/js/admin.min.js
vendored
8
rainloop/v/0.0.0/static/js/admin.min.js
vendored
File diff suppressed because one or more lines are too long
|
|
@ -381,6 +381,7 @@ Enums.KeyState = {
|
||||||
'MessageList': 'message-list',
|
'MessageList': 'message-list',
|
||||||
'MessageView': 'message-view',
|
'MessageView': 'message-view',
|
||||||
'Compose': 'compose',
|
'Compose': 'compose',
|
||||||
|
'Menu': 'menu',
|
||||||
'PopupComposeOpenPGP': 'compose-open-pgp',
|
'PopupComposeOpenPGP': 'compose-open-pgp',
|
||||||
'PopupAsk': 'popup-ask'
|
'PopupAsk': 'popup-ask'
|
||||||
};
|
};
|
||||||
|
|
@ -2768,6 +2769,15 @@ ko.bindingHandlers.onEsc = {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
ko.bindingHandlers.clickOnTrue = {
|
||||||
|
'update': function (oElement, fValueAccessor) {
|
||||||
|
if (ko.utils.unwrapObservable(fValueAccessor()))
|
||||||
|
{
|
||||||
|
$(oElement).click();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
ko.bindingHandlers.modal = {
|
ko.bindingHandlers.modal = {
|
||||||
'init': function (oElement, fValueAccessor) {
|
'init': function (oElement, fValueAccessor) {
|
||||||
$(oElement).toggleClass('fade', !Globals.bMobileDevice) .modal({
|
$(oElement).toggleClass('fade', !Globals.bMobileDevice) .modal({
|
||||||
|
|
@ -4223,6 +4233,7 @@ Selector.prototype.init = function (oContentVisible, oContentScrollable, sKeySco
|
||||||
})
|
})
|
||||||
;
|
;
|
||||||
|
|
||||||
|
// TODO
|
||||||
key('enter', sKeyScope, function () {
|
key('enter', sKeyScope, function () {
|
||||||
if (self.focusedItem())
|
if (self.focusedItem())
|
||||||
{
|
{
|
||||||
|
|
@ -11650,6 +11661,8 @@ function AbstractSystemDropDownViewModel()
|
||||||
this.accounts = oData.accounts;
|
this.accounts = oData.accounts;
|
||||||
this.accountEmail = oData.accountEmail;
|
this.accountEmail = oData.accountEmail;
|
||||||
this.accountsLoading = oData.accountsLoading;
|
this.accountsLoading = oData.accountsLoading;
|
||||||
|
this.accountMenuFocus = oData.accountMenuFocus;
|
||||||
|
|
||||||
this.allowAddAccount = RL.settingsGet('AllowAdditionalAccounts');
|
this.allowAddAccount = RL.settingsGet('AllowAdditionalAccounts');
|
||||||
|
|
||||||
this.loading = ko.computed(function () {
|
this.loading = ko.computed(function () {
|
||||||
|
|
@ -11657,6 +11670,14 @@ function AbstractSystemDropDownViewModel()
|
||||||
}, this);
|
}, this);
|
||||||
|
|
||||||
this.accountClick = _.bind(this.accountClick, this);
|
this.accountClick = _.bind(this.accountClick, this);
|
||||||
|
|
||||||
|
key('`', function () {
|
||||||
|
if (oData.useKeyboardShortcuts() && !RL.popupVisibility() &&
|
||||||
|
!oData.accountMenuFocus())
|
||||||
|
{
|
||||||
|
oData.accountMenuFocus(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
_.extend(AbstractSystemDropDownViewModel.prototype, KnoinAbstractViewModel.prototype);
|
_.extend(AbstractSystemDropDownViewModel.prototype, KnoinAbstractViewModel.prototype);
|
||||||
|
|
@ -14851,6 +14872,17 @@ function WebMailDataStorage()
|
||||||
this.projectHash = ko.observable('');
|
this.projectHash = ko.observable('');
|
||||||
this.threading = ko.observable(false);
|
this.threading = ko.observable(false);
|
||||||
|
|
||||||
|
this.accountMenuFocus = ko.observable(false);
|
||||||
|
this.accountMenuFocus.sKeyState = Enums.KeyState.All;
|
||||||
|
|
||||||
|
this.accountMenuFocus.subscribe(function (bValue) {
|
||||||
|
if (bValue)
|
||||||
|
{
|
||||||
|
this.accountMenuFocus.sKeyState = RL.data().keyScope();
|
||||||
|
}
|
||||||
|
RL.data().keyScope(bValue ? Enums.KeyState.Menu : this.accountMenuFocus.sKeyState);
|
||||||
|
}, this);
|
||||||
|
|
||||||
this.lastFoldersHash = '';
|
this.lastFoldersHash = '';
|
||||||
this.remoteSuggestions = false;
|
this.remoteSuggestions = false;
|
||||||
|
|
||||||
|
|
|
||||||
18
rainloop/v/0.0.0/static/js/app.min.js
vendored
18
rainloop/v/0.0.0/static/js/app.min.js
vendored
File diff suppressed because one or more lines are too long
Loading…
Add table
Add a link
Reference in a new issue