Hi Akshay,

PFA updated patch.


--
Regards,
Murtuza Zabuawala
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company



On Thu, Jan 23, 2020 at 12:39 PM Akshay Joshi <akshay.jo...@enterprisedb.com>
wrote:

> Hi Ganesh
>
> Following are the review comments:
>
>    - Focus is going on Table headers but it is not visible.
>    - Need to handle keyboard events on table header for sorting.
>    - Add tabindex property for the table rows.
>    - Add keyboard events to select the file from the file dialog.
>
>
> On Tue, Jan 21, 2020 at 6:26 PM Ganesh Jaybhay <
> ganesh.jayb...@enterprisedb.com> wrote:
>
>> Hi Hackers,
>>
>> Please find the attached minor fix for tab navigation on footer and
>> confirmation dialog buttons from file manager dialogue
>> Kindly review.
>>
>> Regards,
>> Ganesh Jaybhay
>>
>
>
> --
> *Thanks & Regards*
> *Akshay Joshi*
>
> *Sr. Software Architect*
> *EnterpriseDB Software India Private Limited*
> *Mobile: +91 976-788-8246*
>
diff --git a/web/pgadmin/misc/file_manager/static/js/create_dialogue.js b/web/pgadmin/misc/file_manager/static/js/create_dialogue.js
index a3c44ec88..268d8d727 100644
--- a/web/pgadmin/misc/file_manager/static/js/create_dialogue.js
+++ b/web/pgadmin/misc/file_manager/static/js/create_dialogue.js
@@ -28,11 +28,7 @@ module.exports =  Alertify.dialog('createModeDlg', function() {
           text: gettext('Create'),
           key: 13,
           className: 'btn btn-primary fa fa-file file_manager_create file_manager_ok pg-alertify-button disabled',
-        },
-        ],
-        focus: {
-          element: 0,
-        },
+        }],
         options: {
           closableByDimmer: false,
           maximizable: false,
@@ -175,6 +171,7 @@ module.exports =  Alertify.dialog('createModeDlg', function() {
 
         if (!_.isUndefined(newFile) && newFile !== '' && this.is_file_exist()) {
           this.replace_file();
+          this.$container.find('.replace_file').find('.btn_yes').trigger('focus');
           closeEvent.cancel = true;
         } else {
           pgAdmin.Browser.Events.trigger('pgadmin-storage:finish_btn:create_file', newFile);
diff --git a/web/pgadmin/misc/file_manager/static/js/select_dialogue.js b/web/pgadmin/misc/file_manager/static/js/select_dialogue.js
index 219e6ba4f..97d1ed770 100644
--- a/web/pgadmin/misc/file_manager/static/js/select_dialogue.js
+++ b/web/pgadmin/misc/file_manager/static/js/select_dialogue.js
@@ -91,9 +91,6 @@ module.exports =  Alertify.dialog('fileSelectionDlg', function() {
           key: 13,
           className: 'btn btn-primary fa fa-file file_manager_ok pg-alertify-button disabled',
         }],
-        focus: {
-          element: 0,
-        },
         options: {
           closableByDimmer: false,
           maximizable: false,
diff --git a/web/pgadmin/misc/file_manager/static/js/utility.js b/web/pgadmin/misc/file_manager/static/js/utility.js
index bd0e51cac..86d239989 100644
--- a/web/pgadmin/misc/file_manager/static/js/utility.js
+++ b/web/pgadmin/misc/file_manager/static/js/utility.js
@@ -474,7 +474,7 @@ define([
 
         /* For the html ele */
         let item_ele =
-          `<li class="${cap_classes}">
+          `<li class="${cap_classes}" tabindex="0">
             <div class="clip">
             <span data-alt="${_.escape(item_data.Path)}" class="${icon_type}"></span>`;
 
@@ -530,7 +530,7 @@ define([
       `<table id="contents" class="table table-bordered table-noouter-border table-bottom-border table-right-border table-hover tablesorter file_listing_table ${no_data?'file_listing_table_no_data':''}">
         <thead>
           <tr>
-            <th>
+            <th tabindex="0">
               <span>${lg.name}</span>
             </th>
             <th class="sorter-metric" data-metric-name-full="byte|Byte|BYTE" data-metric-name-abbr="b|B">
@@ -575,7 +575,7 @@ define([
 
         /* For the html ele */
         let item_ele =
-          `<tr class="${cap_classes}">
+          `<tr class="${cap_classes}" tabindex="0">
             <td title="${_.escape(item_data.Path)}" class="${class_type}">`;
 
         let data_protected = '';
@@ -698,7 +698,7 @@ define([
         $('.storage_dialog #uploader .input-path').prop('disabled', false);
         var result = '',
           data = resp.data.result;
-
+        let isGridView = false;
         // hide activity indicator
         $('.fileinfo').find('span.activity').hide();
         if (data.Code === 0) {
@@ -711,6 +711,7 @@ define([
         // generate HTML for files/folder and render into container
         if ($('.fileinfo').data('view') == 'grid') {
           result += getGridView(data, capabilities);
+          isGridView = true;
         } else {
           result += getListView(data, capabilities);
         }
@@ -737,6 +738,23 @@ define([
           $.tablesorter.resizable.setWidth($listing_table.find('th[data-column="2"]'), wo.resizable_widths[2]);
         });
 
+        /* Role of this function is to click or double click on element when user is doing keyboard navigation*/
+        var clickOnFileFolderManually = function(event) {
+          let self = this;
+          event.preventDefault();
+          event.stopPropagation();
+          // if file/folder is protected do nothing
+          if ($(this).find('.fa-lock').length)
+            return;
+          if ($(this).find('.fa-file-text-o').length)
+            $(this).click();
+          // If folder then first select and then double click to opn folder
+          else if ($(this).find('.fa-folder-open').length) {
+            $(this).click();
+            setTimeout(() => { $(self).trigger('dblclick'); }, 10);
+          }
+        };
+
         $listing_table.on( 'tablesorter-ready', function() {
           let wo = this.config.widgetOptions;
           if($.tablesorter.storage($listing_table[0], 'tablesorter-table-resized-width') === '') {
@@ -744,8 +762,55 @@ define([
           }
           $.tablesorter.resizable.setWidth($listing_table.find('th[data-column="2"]'), wo.resizable_widths[2]);
           $listing_table.trigger('resizableUpdate');
+
+          // Table Sorter writes table elements randomly so we need to handle some corner cases manually
+          $('#show_hidden').off('keydown').on('keydown', function(event) {
+            if (!isGridView && event.keyCode == 9 && event.shiftKey) {
+              event.preventDefault();
+              $listing_table.find('tbody tr:last').trigger('focus');
+            }
+          });
+
+          $listing_table.find('tbody tr').off('keydown').on('keydown', function(event) {
+            // If key is pressed then we need to trigger click so that it can select file
+            if (event.keyCode == 13 || event.keyCode == 32) {
+              clickOnFileFolderManually.call(this, event);
+            } else if (event.keyCode == 9) {
+              if (event.shiftKey) {
+                // When first tr losses focus and shift + tab > we need to set focus on header
+                if ($(this).prev().length == 0) {
+                  event.preventDefault();
+                  $listing_table.find('th.tablesorter-header:last').trigger('focus');
+                }
+              } else {
+                // When last tr losses focus and Tab was pressed > we need to set focus on checkbox
+                if ($(this).next().length == 0) {
+                  event.preventDefault();
+                  $('#show_hidden').trigger('focus');
+                }
+              }
+            }
+          });
+
+          $listing_table.find('th.tablesorter-header').off('keydown').on('keydown', function(event) {
+            // If key is pressed then we need to trigger click so that it can sort
+            if (event.keyCode == 13 || event.keyCode == 32) {
+              event.preventDefault();
+              event.stopPropagation();
+              $(this).trigger('click');
+            }
+          });
         });
 
+        if(isGridView) {
+          $('.file_manager').find('#contents li').off('keydown').on('keydown', function(event) {
+            // If key is pressed then we need to trigger click so that it can sort
+            if (event.keyCode == 13 || event.keyCode == 32) {
+              clickOnFileFolderManually.call(this, event);
+            }
+          });
+        }
+
         // rename file/folder
         $('.file_manager button.rename').off().on('click', function(e) {
 
@@ -1195,11 +1260,11 @@ define([
           select_box = `<div class='change_file_types d-flex align-items-center p-1'>
           <div>
             ${gettext('Show hidden files and folders')}?
-            <input type='checkbox' id='show_hidden' onclick='pgAdmin.FileUtils.handleClick(this)' tabindex='11'>
+            <input type='checkbox' id='show_hidden' onclick='pgAdmin.FileUtils.handleClick(this)' tabindex='0'>
           </div>
           <div class="ml-auto">
             <label class="my-auto">${gettext('Format')}</label>
-            <select name='type' tabindex='12'>${fileFormats}</select>
+            <select name='type' tabindex='0'>${fileFormats}</select>
           <div>`;
         }
 
@@ -1255,6 +1320,8 @@ define([
         enable_disable_btn();
       });
 
+
+
       // Refresh current directory
       $('.file_manager .refresh').on('click', function() {
         enable_disable_btn();
@@ -1476,12 +1543,12 @@ define([
         // we remove simple file upload element
         $('.file-input-container').remove();
         $('.upload').remove();
-        $('.create').before('<button value="Upload" type="button" title="Upload File" name="upload" id="upload" class="btn btn-sm btn-secondary upload" tabindex="6"><span class="fa fa-upload sql-icon-lg"></span></button> ');
+        $('.create').before('<button value="Upload" type="button" title="Upload File" name="upload" id="upload" class="btn btn-sm btn-secondary upload" tabindex="0"><span class="fa fa-upload sql-icon-lg"></span></button> ');
 
         $('#uploader .upload').off().on('click', function() {
           // we create prompt
           var msg = '<div id="dropzone-container" class="d-flex flex-column flex-grow-1">' +
-            '<button class="fa fa-times fa-lg dz_cross_btn ml-auto" tabindex="7"></button>' +
+            '<button class="fa fa-times fa-lg dz_cross_btn ml-auto" tabindex="0"></button>' +
             '<div id="multiple-uploads" class="dropzone flex-grow-1 d-flex p-1">'+
             '<div class="dz-default dz-message d-none"></div>'+
             '</div>' +
@@ -1645,7 +1712,7 @@ define([
 
           // template for creating new folder
           folder_div =
-            '<li class=\'cap_download cap_delete cap_select_file cap_select_folder cap_rename cap_create cap_upload\'>' +
+            '<li tabIndex="0" class=\'cap_download cap_delete cap_select_file cap_select_folder cap_rename cap_create cap_upload\'>' +
             '<div class=\'clip\'><span data-alt=\'\' class=\'fa fa-folder-open fm_folder_grid\' role="img"></span></div>' +
             '<div><input type=\'text\' class=\'fm_file_rename\'><span class="less_text" title=\'\'>New_Folder</span></div>' +
             '<span class=\'meta size\'></span><span class=\'meta created\'></span><span class=\'meta modified\'></span></li>';
diff --git a/web/pgadmin/misc/file_manager/static/scss/_file_manager.scss b/web/pgadmin/misc/file_manager/static/scss/_file_manager.scss
index fc9019036..cf6558350 100644
--- a/web/pgadmin/misc/file_manager/static/scss/_file_manager.scss
+++ b/web/pgadmin/misc/file_manager/static/scss/_file_manager.scss
@@ -333,3 +333,16 @@
   font-size: 8px;
   margin-right: -8px;
 }
+
+table.tablesorter {
+  th:focus,
+  tr:focus {
+    outline: $input-focus-border-color auto 5px !important;
+  }
+}
+
+#contents {
+  li:focus {
+    outline: $input-focus-border-color auto 5px !important;
+  }
+}
diff --git a/web/pgadmin/misc/file_manager/templates/file_manager/index.html b/web/pgadmin/misc/file_manager/templates/file_manager/index.html
index f41860676..99ef0acf9 100644
--- a/web/pgadmin/misc/file_manager/templates/file_manager/index.html
+++ b/web/pgadmin/misc/file_manager/templates/file_manager/index.html
@@ -9,15 +9,15 @@
                 <div class="input-group" role="group">
                     <div class="input-group-prepend">
                         <button name="home" type="button" value="Home" title="{{ _('Home') }}" class="btn btn-secondary home"
-                                tabindex="1">
+                                tabindex="0">
                             <span class="fa fa-home sql-icon-lg"></span>
                         </button>
                         <button name="level-up" type="button" title="{{ _('Back') }}" value="LevelUp" class="btn btn-secondary level-up"
-                                disabled tabindex="2">
+                                disabled tabindex="0">
                             <span class="fa fa-level-up sql-icon-lg"></span>
                         </button>
                     </div>
-                    <input id="file-input-path" class="form-control input-path text-truncate" title="" type="text" tabindex="3" autofocus/>
+                    <input id="file-input-path" class="form-control input-path text-truncate" title="" type="text" tabindex="0" autofocus/>
                 </div>
                 <div class="uploadresponse"></div>
             </div>
@@ -25,7 +25,7 @@
                 <input class="mode" name="mode" type="hidden" value="add"/>
                 <input class="currentpath" name="currentpath" type="hidden"/>
                 <button type="button" title="{{ _('Refresh') }}" class="btn btn-sm btn-secondary refresh"
-                        tabindex="4">
+                        tabindex="0">
                     <span class="fa fa-refresh sql-icon-lg"></span>
                 </button>
                 <button type="button" title="{{ _('Download File') }}" class="btn btn-sm btn-secondary download"
@@ -37,19 +37,19 @@
                     <span class="fa fa-trash sql-icon-lg"></span>
                 </button>
                 <button name="rename" type="button" title="{{ _('Rename File/Folder') }}" class="btn btn-sm btn-secondary rename"
-                        tabindex="5">
+                        tabindex="0">
                     <span class="fa fa-pencil-square-o sql-icon-lg"></span>
                 </button>
                 <button name="newfolder" type="button" title="{{ _('Create new folder') }}" value="New Folder"
-                        class="btn btn-sm btn-secondary create" tabindex="8">
+                        class="btn btn-sm btn-secondary create" tabindex="0">
                     <span class="fa fa-folder-open sql-icon-lg"></span>
                     <span class="fa fa-plus add-folder-icon"></span>
                 </button>
                 <div class="btn-group" role="group">
-                    <button class="ON btn btn-secondary btn-sm grid" type="button" title="{{ _('View as grid') }}" tabindex="9">
+                    <button class="ON btn btn-secondary btn-sm grid" type="button" title="{{ _('View as grid') }}" tabindex="0">
                         <span class="fa fa-th sql-icon-lg"></span>
                     </button>
-                    <button type="button" class="btn btn-secondary btn-sm list" title="{{ _('View as table') }}" tabindex="10">
+                    <button type="button" class="btn btn-secondary btn-sm list" title="{{ _('View as table') }}" tabindex="0">
                         <span class="fa fa-list sql-icon-lg"></span>
                     </button>
                 </div>
@@ -67,15 +67,15 @@
         <div class='delete_item'>
             <span>{{ _('Are you sure you want to delete this item?') }}</span>
             <span class="pull-right">
-                <button type='button' class='btn btn-secondary btn_no' tabindex="14">{{ _('No') }}</button>
-                <button type='button' class='btn btn-primary btn_yes' tabindex="13">{{ _('Yes') }}</button>
+                <button type='button' class='btn btn-secondary btn_no' tabindex="0">{{ _('No') }}</button>
+                <button type='button' class='btn btn-primary btn_yes' tabindex="0">{{ _('Yes') }}</button>
             </span>
         </div>
         <div class='replace_file'>
             <span>{{ _('Are you sure you want to replace this file?') }}</span>
             <span class="pull-right">
-                <button type='button' class='btn btn-secondary btn_no' tabindex="16">{{ _('No') }}</button>
-                <button type='button' class='btn btn-primary btn_yes' tabindex="15">{{ _('Yes') }}</button>
+                <button type='button' class='btn btn-secondary btn_no' tabindex="0">{{ _('No') }}</button>
+                <button type='button' class='btn btn-primary btn_yes' tabindex="0">{{ _('Yes') }}</button>
             </span>
         </div>
     </div>
diff --git a/web/pgadmin/static/js/backgrid.pgadmin.js b/web/pgadmin/static/js/backgrid.pgadmin.js
index 2ea0ec90e..5bf2fec5b 100644
--- a/web/pgadmin/static/js/backgrid.pgadmin.js
+++ b/web/pgadmin/static/js/backgrid.pgadmin.js
@@ -781,6 +781,7 @@ define([
       this.$select.off('blur', this.exitEditMode);
       this.$select.select2('close');
       this.$el.removeClass('editor');
+      this.$el.find('.select2-selection').trigger('focus');
     },
 
     saveOrCancel: function (e) {
@@ -794,7 +795,9 @@ define([
 
         let gotoCell;
         // go to Next Cell & if Shift is also pressed go to Previous Cell
-        gotoCell = e.shiftKey ? self.$el.prev() : self.$el.next();
+        if (e.keyCode == 9 || e.keyCode == 16) {
+          gotoCell = e.shiftKey ? self.$el.prev() : self.$el.next();
+        }
 
         if (gotoCell) {
           let command = new Backgrid.Command({

Reply via email to