Fix focus issues with hotkeys
Since making use of keypress in addition to keydown, hotkeys did not work in certain scenarios, including clicking on the feed tree expanders or empty spaces of the toolbar. This issue is caused by dijit.Tree and dijit.Toolbar implementing the _KeyNavMixin, which explicitly stops propagation of keypress events. This change contains two main fixes plus a smaller hotfix: 1. It overrides _onContainerKeydown and _onContainerKeypress for fox.FeedTree (which inherits from dijit.Tree). 2. It adds fox.Toolbar, which overrides _onContainerKeydown, _onContainerKeypress and focus. This fixes hotkeys being swallowed and the first focusable child receiving focus when clicking on an empty space of the toolbar. 3. It adds the same handling of keydown and keypress to the prefs hotkey handler as is done in the main hotkey handler.
This commit is contained in:
parent
7e55340295
commit
4a2a90c980
|
@ -1208,7 +1208,7 @@ class Pref_Feeds extends Handler_Protected {
|
||||||
|
|
||||||
print '<div dojoType="dijit.layout.BorderContainer" gutters="false">';
|
print '<div dojoType="dijit.layout.BorderContainer" gutters="false">';
|
||||||
|
|
||||||
print "<div region='top' dojoType=\"dijit.Toolbar\">"; #toolbar
|
print "<div region='top' dojoType=\"fox.Toolbar\">"; #toolbar
|
||||||
|
|
||||||
print "<div style='float : right; padding-right : 4px;'>
|
print "<div style='float : right; padding-right : 4px;'>
|
||||||
<input dojoType=\"dijit.form.TextBox\" id=\"feed_search\" size=\"20\" type=\"search\"
|
<input dojoType=\"dijit.form.TextBox\" id=\"feed_search\" size=\"20\" type=\"search\"
|
||||||
|
@ -1449,7 +1449,7 @@ class Pref_Feeds extends Handler_Protected {
|
||||||
ORDER BY last_article");
|
ORDER BY last_article");
|
||||||
$sth->execute([$_SESSION['uid']]);
|
$sth->execute([$_SESSION['uid']]);
|
||||||
|
|
||||||
print "<div dojoType='dijit.Toolbar'>";
|
print "<div dojoType='fox.Toolbar'>";
|
||||||
print "<div dojoType='dijit.form.DropDownButton'>".
|
print "<div dojoType='dijit.form.DropDownButton'>".
|
||||||
"<span>" . __('Select')."</span>";
|
"<span>" . __('Select')."</span>";
|
||||||
print "<div dojoType='dijit.Menu' style='display: none'>";
|
print "<div dojoType='dijit.Menu' style='display: none'>";
|
||||||
|
@ -1506,7 +1506,7 @@ class Pref_Feeds extends Handler_Protected {
|
||||||
FROM ttrss_feeds WHERE last_error != '' AND owner_uid = ?");
|
FROM ttrss_feeds WHERE last_error != '' AND owner_uid = ?");
|
||||||
$sth->execute([$_SESSION['uid']]);
|
$sth->execute([$_SESSION['uid']]);
|
||||||
|
|
||||||
print "<div dojoType=\"dijit.Toolbar\">";
|
print "<div dojoType=\"fox.Toolbar\">";
|
||||||
print "<div dojoType=\"dijit.form.DropDownButton\">".
|
print "<div dojoType=\"dijit.form.DropDownButton\">".
|
||||||
"<span>" . __('Select')."</span>";
|
"<span>" . __('Select')."</span>";
|
||||||
print "<div dojoType=\"dijit.Menu\" style=\"display: none;\">";
|
print "<div dojoType=\"dijit.Menu\" style=\"display: none;\">";
|
||||||
|
|
|
@ -354,7 +354,7 @@ class Pref_Filters extends Handler_Protected {
|
||||||
print "<header class='horizontal'>".__("Match")."</header>";
|
print "<header class='horizontal'>".__("Match")."</header>";
|
||||||
print "<section>";
|
print "<section>";
|
||||||
|
|
||||||
print "<div dojoType=\"dijit.Toolbar\">";
|
print "<div dojoType=\"fox.Toolbar\">";
|
||||||
|
|
||||||
print "<div dojoType=\"dijit.form.DropDownButton\">".
|
print "<div dojoType=\"dijit.form.DropDownButton\">".
|
||||||
"<span>" . __('Select')."</span>";
|
"<span>" . __('Select')."</span>";
|
||||||
|
@ -414,7 +414,7 @@ class Pref_Filters extends Handler_Protected {
|
||||||
|
|
||||||
print "<section>";
|
print "<section>";
|
||||||
|
|
||||||
print "<div dojoType=\"dijit.Toolbar\">";
|
print "<div dojoType=\"fox.Toolbar\">";
|
||||||
|
|
||||||
print "<div dojoType=\"dijit.form.DropDownButton\">".
|
print "<div dojoType=\"dijit.form.DropDownButton\">".
|
||||||
"<span>" . __('Select')."</span>";
|
"<span>" . __('Select')."</span>";
|
||||||
|
@ -757,7 +757,7 @@ class Pref_Filters extends Handler_Protected {
|
||||||
|
|
||||||
print "<div dojoType='dijit.layout.BorderContainer' gutters='false'>";
|
print "<div dojoType='dijit.layout.BorderContainer' gutters='false'>";
|
||||||
print "<div style='padding : 0px' dojoType='dijit.layout.ContentPane' region='top'>";
|
print "<div style='padding : 0px' dojoType='dijit.layout.ContentPane' region='top'>";
|
||||||
print "<div dojoType='dijit.Toolbar'>";
|
print "<div dojoType='fox.Toolbar'>";
|
||||||
|
|
||||||
if (array_key_exists("search", $_REQUEST)) {
|
if (array_key_exists("search", $_REQUEST)) {
|
||||||
$_SESSION["prefs_filter_search"] = $filter_search;
|
$_SESSION["prefs_filter_search"] = $filter_search;
|
||||||
|
@ -856,7 +856,7 @@ class Pref_Filters extends Handler_Protected {
|
||||||
print "<header class='horizontal'>".__("Match")."</header >";
|
print "<header class='horizontal'>".__("Match")."</header >";
|
||||||
print "<section>";
|
print "<section>";
|
||||||
|
|
||||||
print "<div dojoType='dijit.Toolbar'>";
|
print "<div dojoType='fox.Toolbar'>";
|
||||||
|
|
||||||
print "<div dojoType='dijit.form.DropDownButton'>".
|
print "<div dojoType='dijit.form.DropDownButton'>".
|
||||||
"<span>" . __('Select')."</span>";
|
"<span>" . __('Select')."</span>";
|
||||||
|
@ -885,7 +885,7 @@ class Pref_Filters extends Handler_Protected {
|
||||||
|
|
||||||
print "<section>";
|
print "<section>";
|
||||||
|
|
||||||
print "<div dojoType='dijit.Toolbar'>";
|
print "<div dojoType='fox.Toolbar'>";
|
||||||
|
|
||||||
print "<div dojoType='dijit.form.DropDownButton'>".
|
print "<div dojoType='dijit.form.DropDownButton'>".
|
||||||
"<span>" . __('Select')."</span>";
|
"<span>" . __('Select')."</span>";
|
||||||
|
|
|
@ -251,7 +251,7 @@ class Pref_Labels extends Handler_Protected {
|
||||||
|
|
||||||
print "<div dojoType='dijit.layout.BorderContainer' gutters='false'>";
|
print "<div dojoType='dijit.layout.BorderContainer' gutters='false'>";
|
||||||
print "<div style='padding : 0px' dojoType='dijit.layout.ContentPane' region='top'>";
|
print "<div style='padding : 0px' dojoType='dijit.layout.ContentPane' region='top'>";
|
||||||
print "<div dojoType='dijit.Toolbar'>";
|
print "<div dojoType='fox.Toolbar'>";
|
||||||
|
|
||||||
print "<div dojoType='dijit.form.DropDownButton'>".
|
print "<div dojoType='dijit.form.DropDownButton'>".
|
||||||
"<span>" . __('Select')."</span>";
|
"<span>" . __('Select')."</span>";
|
||||||
|
|
|
@ -1021,7 +1021,7 @@ class Pref_Prefs extends Handler_Protected {
|
||||||
}
|
}
|
||||||
|
|
||||||
function editPrefProfiles() {
|
function editPrefProfiles() {
|
||||||
print "<div dojoType='dijit.Toolbar'>";
|
print "<div dojoType='fox.Toolbar'>";
|
||||||
|
|
||||||
print "<div dojoType='dijit.form.DropDownButton'>".
|
print "<div dojoType='dijit.form.DropDownButton'>".
|
||||||
"<span>" . __('Select')."</span>";
|
"<span>" . __('Select')."</span>";
|
||||||
|
|
|
@ -313,7 +313,7 @@ class Pref_Users extends Handler_Protected {
|
||||||
|
|
||||||
print "<div dojoType='dijit.layout.BorderContainer' gutters='false'>";
|
print "<div dojoType='dijit.layout.BorderContainer' gutters='false'>";
|
||||||
print "<div style='padding : 0px' dojoType='dijit.layout.ContentPane' region='top'>";
|
print "<div style='padding : 0px' dojoType='dijit.layout.ContentPane' region='top'>";
|
||||||
print "<div dojoType='dijit.Toolbar'>";
|
print "<div dojoType='fox.Toolbar'>";
|
||||||
|
|
||||||
$user_search = trim(clean($_REQUEST["search"]));
|
$user_search = trim(clean($_REQUEST["search"]));
|
||||||
|
|
||||||
|
|
|
@ -145,7 +145,7 @@
|
||||||
|
|
||||||
<div dojoType="dijit.layout.BorderContainer" region="center" id="content-wrap">
|
<div dojoType="dijit.layout.BorderContainer" region="center" id="content-wrap">
|
||||||
<div id="toolbar-frame" dojoType="dijit.layout.ContentPane" region="top">
|
<div id="toolbar-frame" dojoType="dijit.layout.ContentPane" region="top">
|
||||||
<div id="toolbar" dojoType="dijit.Toolbar">
|
<div id="toolbar" dojoType="fox.Toolbar">
|
||||||
|
|
||||||
<i class="material-icons net-alert" style="display : none"
|
<i class="material-icons net-alert" style="display : none"
|
||||||
title="<?php echo __("Communication problem with server.") ?>">error_outline</i>
|
title="<?php echo __("Communication problem with server.") ?>">error_outline</i>
|
||||||
|
|
|
@ -2,7 +2,10 @@
|
||||||
define(["dojo/_base/declare", "dojo/dom-construct", "dijit/Tree", "dijit/Menu"], function (declare, domConstruct) {
|
define(["dojo/_base/declare", "dojo/dom-construct", "dijit/Tree", "dijit/Menu"], function (declare, domConstruct) {
|
||||||
|
|
||||||
return declare("fox.FeedTree", dijit.Tree, {
|
return declare("fox.FeedTree", dijit.Tree, {
|
||||||
_onKeyPress: function(/* Event */ e) {
|
_onContainerKeydown: function(/* Event */ e) {
|
||||||
|
return; // Stop dijit.Tree from interpreting keystrokes
|
||||||
|
},
|
||||||
|
_onContainerKeypress: function(/* Event */ e) {
|
||||||
return; // Stop dijit.Tree from interpreting keystrokes
|
return; // Stop dijit.Tree from interpreting keystrokes
|
||||||
},
|
},
|
||||||
_createTreeNode: function(args) {
|
_createTreeNode: function(args) {
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
/* global dijit */
|
||||||
|
define(["dojo/_base/declare", "dijit/Toolbar"], function (declare) {
|
||||||
|
return declare("fox.Toolbar", dijit.Toolbar, {
|
||||||
|
_onContainerKeydown: function(/* Event */ e) {
|
||||||
|
return; // Stop dijit.Toolbar from interpreting keystrokes
|
||||||
|
},
|
||||||
|
_onContainerKeypress: function(/* Event */ e) {
|
||||||
|
return; // Stop dijit.Toolbar from interpreting keystrokes
|
||||||
|
},
|
||||||
|
focus: function() {
|
||||||
|
return; // Stop dijit.Toolbar from focusing the first child on click
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
|
@ -53,7 +53,8 @@ require(["dojo/_base/kernel",
|
||||||
"fox/PrefFilterStore",
|
"fox/PrefFilterStore",
|
||||||
"fox/PrefFeedTree",
|
"fox/PrefFeedTree",
|
||||||
"fox/PrefFilterTree",
|
"fox/PrefFilterTree",
|
||||||
"fox/PrefLabelTree"], function (dojo, declare, ready, parser, AppBase) {
|
"fox/PrefLabelTree",
|
||||||
|
"fox/Toolbar"], function (dojo, declare, ready, parser, AppBase) {
|
||||||
|
|
||||||
ready(function () {
|
ready(function () {
|
||||||
try {
|
try {
|
||||||
|
@ -118,6 +119,10 @@ require(["dojo/_base/kernel",
|
||||||
hotkeyHandler: function (event) {
|
hotkeyHandler: function (event) {
|
||||||
if (event.target.nodeName == "INPUT" || event.target.nodeName == "TEXTAREA") return;
|
if (event.target.nodeName == "INPUT" || event.target.nodeName == "TEXTAREA") return;
|
||||||
|
|
||||||
|
// Arrow buttons and escape are not reported via keypress, handle them via keydown.
|
||||||
|
// escape = 27, left = 37, up = 38, right = 39, down = 40
|
||||||
|
if (event.type == "keydown" && event.which != 27 && (event.which < 37 || event.which > 40)) return;
|
||||||
|
|
||||||
const action_name = App.keyeventToAction(event);
|
const action_name = App.keyeventToAction(event);
|
||||||
|
|
||||||
if (action_name) {
|
if (action_name) {
|
||||||
|
|
|
@ -54,7 +54,8 @@ require(["dojo/_base/kernel",
|
||||||
"fox/Headlines",
|
"fox/Headlines",
|
||||||
"fox/Article",
|
"fox/Article",
|
||||||
"fox/FeedStoreModel",
|
"fox/FeedStoreModel",
|
||||||
"fox/FeedTree"], function (dojo, declare, ready, parser, AppBase) {
|
"fox/FeedTree",
|
||||||
|
"fox/Toolbar"], function (dojo, declare, ready, parser, AppBase) {
|
||||||
|
|
||||||
ready(function () {
|
ready(function () {
|
||||||
try {
|
try {
|
||||||
|
@ -203,7 +204,7 @@ require(["dojo/_base/kernel",
|
||||||
isCombinedMode: function() {
|
isCombinedMode: function() {
|
||||||
return App.getInitParam("combined_display_mode");
|
return App.getInitParam("combined_display_mode");
|
||||||
},
|
},
|
||||||
hotkeyHandler(event) {
|
hotkeyHandler: function(event) {
|
||||||
if (event.target.nodeName == "INPUT" || event.target.nodeName == "TEXTAREA") return;
|
if (event.target.nodeName == "INPUT" || event.target.nodeName == "TEXTAREA") return;
|
||||||
|
|
||||||
// Arrow buttons and escape are not reported via keypress, handle them via keydown.
|
// Arrow buttons and escape are not reported via keypress, handle them via keydown.
|
||||||
|
|
Loading…
Reference in New Issue