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({