Dropdown menu keyboard navigation (step 1 / USTABLE)

This commit is contained in:
RainLoop Team 2014-04-11 20:09:51 +04:00
parent cd6974ecd2
commit 2ad305e40e
15 changed files with 305 additions and 228 deletions

View file

@ -37,6 +37,7 @@ Enums.KeyState = {
'MessageList': 'message-list',
'MessageView': 'message-view',
'Compose': 'compose',
'Menu': 'menu',
'PopupComposeOpenPGP': 'compose-open-pgp',
'PopupAsk': 'popup-ask'
};

View file

@ -126,6 +126,15 @@ ko.bindingHandlers.onEsc = {
}
};
ko.bindingHandlers.clickOnTrue = {
'update': function (oElement, fValueAccessor) {
if (ko.utils.unwrapObservable(fValueAccessor()))
{
$(oElement).click();
}
}
};
ko.bindingHandlers.modal = {
'init': function (oElement, fValueAccessor) {
$(oElement).toggleClass('fade', !Globals.bMobileDevice) .modal({

View file

@ -320,6 +320,7 @@ Selector.prototype.init = function (oContentVisible, oContentScrollable, sKeySco
})
;
// TODO
key('enter', sKeyScope, function () {
if (self.focusedItem())
{

View file

@ -39,6 +39,17 @@ function WebMailDataStorage()
this.projectHash = ko.observable('');
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.remoteSuggestions = false;

View file

@ -60,10 +60,10 @@
}
.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-image: none;
color: #fff;

View file

@ -13,6 +13,8 @@ function AbstractSystemDropDownViewModel()
this.accounts = oData.accounts;
this.accountEmail = oData.accountEmail;
this.accountsLoading = oData.accountsLoading;
this.accountMenuFocus = oData.accountMenuFocus;
this.allowAddAccount = RL.settingsGet('AllowAdditionalAccounts');
this.loading = ko.computed(function () {
@ -20,6 +22,14 @@ function AbstractSystemDropDownViewModel()
}, this);
this.accountClick = _.bind(this.accountClick, this);
key('`', function () {
if (oData.useKeyboardShortcuts() && !RL.popupVisibility() &&
!oData.accountMenuFocus())
{
oData.accountMenuFocus(true);
}
});
}
_.extend(AbstractSystemDropDownViewModel.prototype, KnoinAbstractViewModel.prototype);

View file

@ -89,7 +89,7 @@
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;
background-color: @dropdown-menu-hover-background-color !important;

View file

@ -10,17 +10,19 @@
   
</div>-->
<div class="btn-group pull-right">
<a class="btn btn-ellipsis btn-block dropdown-toggle system-dropdown" data-placement="left" data-toggle="dropdown"
data-tooltip-class="tooltip-big" data-bind="tooltip2: emailTitle">
<a id="top-system-dropdown-id" href="#" tabindex="-1" class="btn btn-ellipsis btn-block dropdown-toggle system-dropdown"
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>
&nbsp;&nbsp;
<span class="caret"></span>
</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 foreach: accounts -->
<li class="e-item">
<a class="e-link" data-bind="click: $root.accountClick, attr: {'href': changeAccountLink() }">
<li class="e-item" role="presentation">
<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-user" data-bind="visible: $root.accountEmail() !== email"></i>
&nbsp;&nbsp;
@ -28,28 +30,28 @@
</a>
</li>
<!-- /ko -->
<li class="divider"></li>
<li class="divider" role="presentation"></li>
<!-- /ko -->
<!-- ko if: allowAddAccount -->
<li class="e-item">
<a class="e-link" data-bind="click: addAccountClick">
<li class="e-item" role="presentation">
<a class="e-link menuitem" href="#" tabindex="-1" data-bind="click: addAccountClick">
<i class="icon-user-add"></i>
&nbsp;&nbsp;
<span class="i18n" data-i18n-text="TOP_TOOLBAR/BUTTON_ADD_ACCOUNT"></span>
</a>
</li>
<!-- /ko -->
<li class="e-item">
<a class="e-link" data-bind="click: settingsClick">
<li class="e-item" role="presentation">
<a class="e-link menuitem" href="#" tabindex="-1" data-bind="click: settingsClick">
<i class="icon-cog"></i>
&nbsp;&nbsp;
<span class="i18n" data-i18n-text="TOP_TOOLBAR/BUTTON_SETTINGS"></span>
</a>
</li>
<li class="divider"></li>
<li class="e-item">
<a class="e-link" data-bind="click: logoutClick">
<li class="divider" role="presentation"></li>
<li class="e-item" role="presentation">
<a class="e-link menuitem" href="#" tabindex="-1" data-bind="click: logoutClick">
<i class="icon-power"></i>
&nbsp;&nbsp;
<span class="i18n" data-i18n-text="TOP_TOOLBAR/BUTTON_LOGOUT"></span>

View file

@ -5861,8 +5861,9 @@ html.no-rgba .modal {
cursor: pointer;
}
.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 {
background-color: #555;
background-image: none;

File diff suppressed because one or more lines are too long

View file

@ -377,6 +377,7 @@ Enums.KeyState = {
'MessageList': 'message-list',
'MessageView': 'message-view',
'Compose': 'compose',
'Menu': 'menu',
'PopupComposeOpenPGP': 'compose-open-pgp',
'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 = {
'init': function (oElement, fValueAccessor) {
$(oElement).toggleClass('fade', !Globals.bMobileDevice) .modal({

File diff suppressed because one or more lines are too long

View file

@ -381,6 +381,7 @@ Enums.KeyState = {
'MessageList': 'message-list',
'MessageView': 'message-view',
'Compose': 'compose',
'Menu': 'menu',
'PopupComposeOpenPGP': 'compose-open-pgp',
'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 = {
'init': function (oElement, fValueAccessor) {
$(oElement).toggleClass('fade', !Globals.bMobileDevice) .modal({
@ -4223,6 +4233,7 @@ Selector.prototype.init = function (oContentVisible, oContentScrollable, sKeySco
})
;
// TODO
key('enter', sKeyScope, function () {
if (self.focusedItem())
{
@ -11650,6 +11661,8 @@ function AbstractSystemDropDownViewModel()
this.accounts = oData.accounts;
this.accountEmail = oData.accountEmail;
this.accountsLoading = oData.accountsLoading;
this.accountMenuFocus = oData.accountMenuFocus;
this.allowAddAccount = RL.settingsGet('AllowAdditionalAccounts');
this.loading = ko.computed(function () {
@ -11657,6 +11670,14 @@ function AbstractSystemDropDownViewModel()
}, this);
this.accountClick = _.bind(this.accountClick, this);
key('`', function () {
if (oData.useKeyboardShortcuts() && !RL.popupVisibility() &&
!oData.accountMenuFocus())
{
oData.accountMenuFocus(true);
}
});
}
_.extend(AbstractSystemDropDownViewModel.prototype, KnoinAbstractViewModel.prototype);
@ -14851,6 +14872,17 @@ function WebMailDataStorage()
this.projectHash = ko.observable('');
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.remoteSuggestions = false;

File diff suppressed because one or more lines are too long