Skip to content

Commit e8c8e7f

Browse files
feat: improve keyboard navigation on chart creation screen (#1293)
1 parent 1b131a0 commit e8c8e7f

3 files changed

Lines changed: 115 additions & 10 deletions

File tree

classes/Visualizer/Render/Layout.php

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -762,7 +762,7 @@ public static function _renderTabBasic( $args ) {
762762
<ul class="viz-group-wrapper">
763763
<!-- manual -->
764764
<li class="viz-group visualizer_source_manual">
765-
<h2 class="viz-group-title viz-sub-group visualizer-editor-tab" data-current="chart"><?php _e( 'Manual Data', 'visualizer' ); ?></h2>
765+
<h2 class="viz-group-title viz-sub-group visualizer-editor-tab" data-current="chart" role="button" tabindex="0"><?php _e( 'Manual Data', 'visualizer' ); ?></h2>
766766
<div class="viz-group-content edit-data-content">
767767
<form id="editor-form" action="<?php echo $upload_link; ?>" method="post" target="thehole">
768768
<input type="hidden" id="chart-data" name="chart_data">
@@ -807,7 +807,7 @@ public static function _renderTabBasic( $args ) {
807807

808808
<!-- import from file -->
809809
<li class="viz-group visualizer_source_csv <?php echo apply_filters( 'visualizer_pro_upsell_class', 'only-pro-feature', 'import-file' ); ?> ">
810-
<h2 class="viz-group-title viz-sub-group visualizer-src-tab"><?php _e( 'Import data from file', 'visualizer' ); ?><span class="dashicons dashicons-lock"></span></h2>
810+
<h2 class="viz-group-title viz-sub-group visualizer-src-tab" role="button" tabindex="0"><?php _e( 'Import data from file', 'visualizer' ); ?><span class="dashicons dashicons-lock"></span></h2>
811811
<div class="viz-group-content">
812812
<div>
813813
<p class="viz-group-description"><?php esc_html_e( 'Select and upload your data file here. Supported formats: CSV, XLSX. The first row should contain the column headings. The second row should contain the series type (string, number, boolean, date, datetime, timeofday).', 'visualizer' ); ?></p>
@@ -837,11 +837,11 @@ public static function _renderTabBasic( $args ) {
837837
</li>
838838
<!-- import from url -->
839839
<li class="viz-group visualizer-import-url visualizer_source_csv_remote visualizer_source_json <?php echo apply_filters( 'visualizer_pro_upsell_class', 'only-pro-feature', 'import-url' ); ?> ">
840-
<h2 class="viz-group-title viz-sub-group visualizer-src-tab"><?php _e( 'Import data from URL', 'visualizer' ); ?><span class="dashicons dashicons-lock"></span></h2>
840+
<h2 class="viz-group-title viz-sub-group visualizer-src-tab" role="button" tabindex="0"><?php _e( 'Import data from URL', 'visualizer' ); ?><span class="dashicons dashicons-lock"></span></h2>
841841
<ul class="viz-group-content">
842842
<!-- import from csv url -->
843843
<li class="viz-subsection">
844-
<span class="viz-section-title"><?php _e( 'Import from CSV / XLSX', 'visualizer' ); ?></span>
844+
<span class="viz-section-title" role="button" tabindex="0"><?php _e( 'Import from CSV / XLSX', 'visualizer' ); ?></span>
845845
<div class="only-pro-anchor">
846846
<div class="viz-section-items section-items">
847847
<p class="viz-group-description">
@@ -909,7 +909,7 @@ public static function _renderTabBasic( $args ) {
909909
</li>
910910
<!-- import from json url -->
911911
<li class="viz-subsection">
912-
<span class="viz-section-title visualizer_source_json"><?php _e( 'Import from JSON', 'visualizer' ); ?></span>
912+
<span class="viz-section-title visualizer_source_json" role="button" tabindex="0"><?php _e( 'Import from JSON', 'visualizer' ); ?></span>
913913
<div class="only-pro-anchor">
914914
<div class="viz-section-items section-items">
915915
<p class="viz-group-description"><?php _e( 'You can choose here to import/synchronize your chart data with a remote JSON source. For more info check <a href="https://docs.themeisle.com/article/1052-how-to-generate-charts-from-json-data-rest-endpoints" target="_blank" >this</a> tutorial', 'visualizer' ); ?></p>
@@ -967,7 +967,7 @@ public static function _renderTabBasic( $args ) {
967967
<!-- import from chart -->
968968
<li class="viz-group viz-import-from-other <?php echo apply_filters( 'visualizer_pro_upsell_class', 'only-pro-feature' ); ?>">
969969
<h2 class="viz-group-title viz-sub-group"
970-
data-current="chart"><?php _e( 'Import from other chart', 'visualizer' ); ?><span
970+
data-current="chart" role="button" tabindex="0"><?php _e( 'Import from other chart', 'visualizer' ); ?><span
971971
class="dashicons dashicons-lock"></span></h2>
972972
<div class="viz-group-content edit-data-content">
973973
<div>
@@ -1040,7 +1040,7 @@ class="dashicons dashicons-lock"></span></h2>
10401040
?>
10411041
<!-- import from WordPress -->
10421042
<li class="viz-group visualizer_source_query_wp <?php echo esc_attr( apply_filters( 'visualizer_pro_upsell_class', 'only-pro-feature', 'import-wp' ) ); ?> ">
1043-
<h2 class="viz-group-title viz-sub-group"><?php _e( 'Import from WordPress', 'visualizer' ); ?><span
1043+
<h2 class="viz-group-title viz-sub-group" role="button" tabindex="0"><?php _e( 'Import from WordPress', 'visualizer' ); ?><span
10441044
class="dashicons dashicons-lock"></span></h2>
10451045
<div class="viz-group-content edit-data-content">
10461046
<div>
@@ -1128,7 +1128,7 @@ class="dashicons dashicons-lock"></span></h2>
11281128
);
11291129
?>
11301130
<li class="viz-group visualizer_woocommerce_source<?php echo 'visualizer_source_json_wc' === $source_of_chart ? ' open' : ''; ?> <?php echo apply_filters( 'visualizer_pro_upsell_class', 'only-pro-feature', 'import-wc-report' ); ?> ">
1131-
<h2 class="viz-group-title viz-sub-group"><?php _e( 'Import from WooCommerce Reports', 'visualizer' ); ?><span class="dashicons dashicons-lock"></span></h2>
1131+
<h2 class="viz-group-title viz-sub-group" role="button" tabindex="0"><?php _e( 'Import from WooCommerce Reports', 'visualizer' ); ?><span class="dashicons dashicons-lock"></span></h2>
11321132
<div class="viz-group-content edit-data-content">
11331133
<div>
11341134
<p class="viz-group-description"><?php _e( 'You can choose here to import/synchronize your chart data with a WooCommerce report API. For more info check <a href="https://woocommerce.github.io/woocommerce-rest-api-docs/?shell#reports" target="_blank" >this</a> tutorial', 'visualizer' ); ?></p>
@@ -1199,7 +1199,7 @@ class="dashicons dashicons-lock"></span></h2>
11991199
?>
12001200
<!-- import from db -->
12011201
<li class="viz-group visualizer_source_query <?php echo esc_attr( apply_filters( 'visualizer_pro_upsell_class', 'only-pro-feature', 'db-query' ) ); ?>">
1202-
<h2 class="viz-group-title viz-sub-group"><?php _e( 'Import from database', 'visualizer' ); ?><span
1202+
<h2 class="viz-group-title viz-sub-group" role="button" tabindex="0"><?php _e( 'Import from database', 'visualizer' ); ?><span
12031203
class="dashicons dashicons-lock"></span></h2>
12041204
<div class="viz-group-content edit-data-content">
12051205
<div>

css/frame.css

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -570,6 +570,13 @@ div.viz-group-content .viz-group-description {
570570
filter: grayscale(0);
571571
}
572572

573+
.type-label:focus,
574+
.viz-group-title:focus,
575+
.viz-section-title:focus {
576+
outline: 2px solid #2271b1;
577+
outline-offset: 2px;
578+
}
579+
573580
.type-box-area .type-label {
574581
background-position: -8px -225px;
575582
}
@@ -1780,4 +1787,4 @@ canvas.chartjs-render-monitor {
17801787
.pro-upsell .pro-upsell-overlay .pro-upsell-action .button{
17811788
width: 100%;
17821789
text-align: center;
1783-
}
1790+
}

js/frame.js

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
}
3737

3838
function onReady() {
39+
initAccessibility();
3940
initTabs();
4041

4142
// open the correct source tab/sub-tab.
@@ -73,6 +74,7 @@
7374
$('.type-radio').change(function () {
7475
$('.type-label-selected').removeClass('type-label-selected');
7576
$(this).parent().addClass('type-label-selected');
77+
updateTypeAriaChecked();
7678
});
7779

7880
// collapse other open sections of this group
@@ -95,6 +97,7 @@
9597
* let's close the LHS window and show the chart that is hidden
9698
*/
9799
$('body').trigger('visualizer:change:action');
100+
updateGroupAriaState($(this));
98101
});
99102

100103
// collapse other open subsections of this section
@@ -103,6 +106,7 @@
103106
grandparent.find('.viz-section-title.open').not(this).each(function () {
104107
$(this).removeClass('open').siblings('.viz-section-items').hide();
105108
});
109+
updateSectionAriaState($(this));
106110
});
107111

108112
$('#view-remote-file').click(function () {
@@ -156,6 +160,100 @@
156160

157161
}
158162

163+
function initAccessibility(){
164+
// Chart type picker: treat tiles as radios with keyboard support.
165+
var $typePicker = $('#type-picker');
166+
if($typePicker.length){
167+
$typePicker.attr('role', 'radiogroup');
168+
$('.type-label').each(function(){
169+
var $label = $(this);
170+
var $input = $label.find('input[type="radio"]');
171+
$label.attr('tabindex', '0').attr('role', 'radio');
172+
if($input.length){
173+
$label.attr('aria-checked', $input.is(':checked') ? 'true' : 'false');
174+
}else{
175+
$label.attr('aria-disabled', 'true');
176+
}
177+
});
178+
$(document).on('keydown', '.type-label', function(e){
179+
if(e.key === 'Enter' || e.key === ' '){
180+
e.preventDefault();
181+
var $label = $(this);
182+
var $input = $label.find('input[type="radio"]');
183+
if($input.length){
184+
$input.prop('checked', true).trigger('change');
185+
}
186+
}
187+
});
188+
}
189+
190+
// Collapsible groups: add button roles + keyboard activation.
191+
$('.viz-group-title').each(function(index){
192+
var $title = $(this);
193+
$title.attr('role', 'button').attr('tabindex', '0');
194+
var $content = $title.siblings('.viz-group-content');
195+
if($content.length){
196+
if(!$content.attr('id')){
197+
$content.attr('id', 'viz-group-content-' + index);
198+
}
199+
$title.attr('aria-controls', $content.attr('id'));
200+
updateGroupAriaState($title);
201+
}
202+
});
203+
$(document).on('keydown', '.viz-group-title', function(e){
204+
if(e.key === 'Enter' || e.key === ' '){
205+
e.preventDefault();
206+
$(this).trigger('click');
207+
}
208+
});
209+
210+
// Subsections in source panel.
211+
$('.viz-section-title').each(function(index){
212+
var $title = $(this);
213+
$title.attr('role', 'button').attr('tabindex', '0');
214+
var $items = $title.siblings('.viz-section-items');
215+
if($items.length){
216+
if(!$items.attr('id')){
217+
$items.attr('id', 'viz-section-items-' + index);
218+
}
219+
$title.attr('aria-controls', $items.attr('id'));
220+
updateSectionAriaState($title);
221+
}
222+
});
223+
$(document).on('keydown', '.viz-section-title', function(e){
224+
if(e.key === 'Enter' || e.key === ' '){
225+
e.preventDefault();
226+
$(this).trigger('click');
227+
}
228+
});
229+
}
230+
231+
function updateTypeAriaChecked(){
232+
$('.type-label').each(function(){
233+
var $label = $(this);
234+
var $input = $label.find('input[type="radio"]');
235+
if($input.length){
236+
$label.attr('aria-checked', $input.is(':checked') ? 'true' : 'false');
237+
}
238+
});
239+
}
240+
241+
function updateGroupAriaState($title){
242+
if(!$title || $title.length === 0){
243+
return;
244+
}
245+
var isOpen = $title.parent().hasClass('open');
246+
$title.attr('aria-expanded', isOpen ? 'true' : 'false');
247+
}
248+
249+
function updateSectionAriaState($title){
250+
if(!$title || $title.length === 0){
251+
return;
252+
}
253+
var isOpen = $title.hasClass('open');
254+
$title.attr('aria-expanded', isOpen ? 'true' : 'false');
255+
}
256+
159257
/**
160258
* Initialize/Update the available chart list based on their supported renderer libraries.
161259
*

0 commit comments

Comments
 (0)