From a6571bf9b8cedcbee34c99299485f88a2fcde97c Mon Sep 17 00:00:00 2001 From: Dannon Baker Date: Mon, 8 Nov 2021 11:34:30 -0500 Subject: [PATCH 01/26] Toplevel nav elements should not have aria role menuitem (they aren't in a parent 'menu' container) --- client/src/components/Masthead/MastheadItem.vue | 1 - 1 file changed, 1 deletion(-) diff --git a/client/src/components/Masthead/MastheadItem.vue b/client/src/components/Masthead/MastheadItem.vue index 6f28eebd84c..c50bc581002 100644 --- a/client/src/components/Masthead/MastheadItem.vue +++ b/client/src/components/Masthead/MastheadItem.vue @@ -8,7 +8,6 @@ :style="styles" :href="formatUrl(tab.url)" :target="tab.target || '_parent'" - role="menuitem" :link-classes="linkClasses" :title="tab.tooltip" @click="open(tab, $event)"> From 371cefc5b3f5b5a3e12e05adbc6ebeab5862cf93 Mon Sep 17 00:00:00 2001 From: Dannon Baker Date: Mon, 8 Nov 2021 11:53:45 -0500 Subject: [PATCH 02/26] Set default lang on html -- we do supply some translations and can scope those elements to other values, but the default (and supported value) for most of the app is english. --- templates/js-app.mako | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/js-app.mako b/templates/js-app.mako index 7c35eeba08e..3a434881061 100644 --- a/templates/js-app.mako +++ b/templates/js-app.mako @@ -1,6 +1,6 @@ <%namespace name="galaxy_client" file="/galaxy_client_app.mako" /> - + From e8293e3c2b7d99bc2d33e188cc68f760a1a4b299 Mon Sep 17 00:00:00 2001 From: Dannon Baker Date: Mon, 8 Nov 2021 15:19:38 -0500 Subject: [PATCH 03/26] Drop a11y-breaking scale max enforcement from templates. --- lib/tool_shed/webapp/templates/base.mako | 2 -- lib/tool_shed/webapp/templates/base/base_panels.mako | 2 -- templates/base.mako | 2 -- templates/base/base_panels.mako | 2 -- templates/js-app.mako | 2 -- templates/webapps/galaxy/galaxy.panels.mako | 2 -- 6 files changed, 12 deletions(-) diff --git a/lib/tool_shed/webapp/templates/base.mako b/lib/tool_shed/webapp/templates/base.mako index c908acbceae..5b982cefb1d 100644 --- a/lib/tool_shed/webapp/templates/base.mako +++ b/lib/tool_shed/webapp/templates/base.mako @@ -8,8 +8,6 @@ ${self.init()} - ## For mobile browsers, don't scale up - ## Force IE to standards mode, and prefer Google Chrome Frame if the user has already installed it diff --git a/lib/tool_shed/webapp/templates/base/base_panels.mako b/lib/tool_shed/webapp/templates/base/base_panels.mako index b3a947cfa84..9c54487d392 100644 --- a/lib/tool_shed/webapp/templates/base/base_panels.mako +++ b/lib/tool_shed/webapp/templates/base/base_panels.mako @@ -123,8 +123,6 @@ ${self.init()} - ## For mobile browsers, don't scale up - ## Force IE to standards mode, and prefer Google Chrome Frame if the user has already installed it diff --git a/templates/base.mako b/templates/base.mako index 2990b345b65..0647d98b79b 100644 --- a/templates/base.mako +++ b/templates/base.mako @@ -8,8 +8,6 @@ ${self.init()} - ## For mobile browsers, don't scale up - ## Force IE to standards mode, and prefer Google Chrome Frame if the user has already installed it diff --git a/templates/base/base_panels.mako b/templates/base/base_panels.mako index 72f27b3728d..b3b986361f2 100644 --- a/templates/base/base_panels.mako +++ b/templates/base/base_panels.mako @@ -120,8 +120,6 @@ ${self.init()} - ## For mobile browsers, don't scale up - ## Force IE to standards mode, and prefer Google Chrome Frame if the user has already installed it diff --git a/templates/js-app.mako b/templates/js-app.mako index 3a434881061..da20e6a125b 100644 --- a/templates/js-app.mako +++ b/templates/js-app.mako @@ -4,8 +4,6 @@ - ## For mobile browsers, don't scale up - ## Force IE to standards mode, and prefer Google Chrome Frame if the user has already installed it diff --git a/templates/webapps/galaxy/galaxy.panels.mako b/templates/webapps/galaxy/galaxy.panels.mako index f944dadfcd2..bcdedf91377 100644 --- a/templates/webapps/galaxy/galaxy.panels.mako +++ b/templates/webapps/galaxy/galaxy.panels.mako @@ -28,8 +28,6 @@ - ## for mobile browsers, don't scale up - ## force IE to standards mode, and prefer Google Chrome Frame if the user has already installed it From 0f4c96c63871fa8d0684981362f54e1316381c88 Mon Sep 17 00:00:00 2001 From: Dannon Baker Date: Mon, 8 Nov 2021 15:21:35 -0500 Subject: [PATCH 04/26] X-UA-Compatible is no longer needed; we don't support the older browsers that this applies to anyway (and it does nothing in IE11) --- lib/tool_shed/webapp/templates/base.mako | 2 -- lib/tool_shed/webapp/templates/base/base_panels.mako | 2 -- templates/base.mako | 2 -- templates/base/base_panels.mako | 2 -- templates/js-app.mako | 2 -- templates/webapps/galaxy/galaxy.panels.mako | 2 -- 6 files changed, 12 deletions(-) diff --git a/lib/tool_shed/webapp/templates/base.mako b/lib/tool_shed/webapp/templates/base.mako index 5b982cefb1d..1e9f116c91e 100644 --- a/lib/tool_shed/webapp/templates/base.mako +++ b/lib/tool_shed/webapp/templates/base.mako @@ -8,8 +8,6 @@ ${self.init()} - ## Force IE to standards mode, and prefer Google Chrome Frame if the user has already installed it - Galaxy diff --git a/lib/tool_shed/webapp/templates/base/base_panels.mako b/lib/tool_shed/webapp/templates/base/base_panels.mako index 9c54487d392..0ee0cbeabad 100644 --- a/lib/tool_shed/webapp/templates/base/base_panels.mako +++ b/lib/tool_shed/webapp/templates/base/base_panels.mako @@ -123,8 +123,6 @@ ${self.init()} <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> - ## Force IE to standards mode, and prefer Google Chrome Frame if the user has already installed it - <meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1"> <title> Galaxy diff --git a/templates/base.mako b/templates/base.mako index 0647d98b79b..2fe2a3c247f 100644 --- a/templates/base.mako +++ b/templates/base.mako @@ -8,8 +8,6 @@ ${self.init()} <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> - ## Force IE to standards mode, and prefer Google Chrome Frame if the user has already installed it - <meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1"> <title> Galaxy diff --git a/templates/base/base_panels.mako b/templates/base/base_panels.mako index b3b986361f2..026973584ba 100644 --- a/templates/base/base_panels.mako +++ b/templates/base/base_panels.mako @@ -120,8 +120,6 @@ ${self.init()} <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> - ## Force IE to standards mode, and prefer Google Chrome Frame if the user has already installed it - <meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1"> <title> Galaxy diff --git a/templates/js-app.mako b/templates/js-app.mako index da20e6a125b..c52916ce42c 100644 --- a/templates/js-app.mako +++ b/templates/js-app.mako @@ -4,8 +4,6 @@ <!--js-app.mako--> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> - ## Force IE to standards mode, and prefer Google Chrome Frame if the user has already installed it - <meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1"> <title> Galaxy diff --git a/templates/webapps/galaxy/galaxy.panels.mako b/templates/webapps/galaxy/galaxy.panels.mako index bcdedf91377..5822b938fbf 100644 --- a/templates/webapps/galaxy/galaxy.panels.mako +++ b/templates/webapps/galaxy/galaxy.panels.mako @@ -28,8 +28,6 @@ <html> <head> <meta charset="UTF-8"> - ## force IE to standards mode, and prefer Google Chrome Frame if the user has already installed it - <meta http-equiv="x-ua-compatible" content="ie=edge,chrome=1"> <title> Galaxy From 245a804d9e09a77512f2d1580aa799ba26d30b76 Mon Sep 17 00:00:00 2001 From: Dannon Baker <dannon.baker@gmail.com> Date: Thu, 18 Aug 2022 14:39:24 -0400 Subject: [PATCH 05/26] Fix aria role for container 'list' in history contents. xref: https://dequeuniversity.com/rules/axe/4.4/aria-required-parent --- client/src/components/History/Layout/ListingLayout.vue | 1 + 1 file changed, 1 insertion(+) diff --git a/client/src/components/History/Layout/ListingLayout.vue b/client/src/components/History/Layout/ListingLayout.vue index b4bec4e56ed..b66be94135f 100644 --- a/client/src/components/History/Layout/ListingLayout.vue +++ b/client/src/components/History/Layout/ListingLayout.vue @@ -3,6 +3,7 @@ <virtual-list ref="listing" class="listing" + role="list" data-key="id" :offset="offset" :data-sources="items" From 5bc4864b36b06ea4f726513359cb477c7ff9d3db Mon Sep 17 00:00:00 2001 From: Dannon Baker <dannon.baker@gmail.com> Date: Thu, 18 Aug 2022 14:59:49 -0400 Subject: [PATCH 06/26] The default role here 'menu' is fine, since it's a dropdown menu. --- client/src/components/Panels/Buttons/PanelViewButton.vue | 1 - 1 file changed, 1 deletion(-) diff --git a/client/src/components/Panels/Buttons/PanelViewButton.vue b/client/src/components/Panels/Buttons/PanelViewButton.vue index 37689b98305..17e07ae6cf9 100644 --- a/client/src/components/Panels/Buttons/PanelViewButton.vue +++ b/client/src/components/Panels/Buttons/PanelViewButton.vue @@ -2,7 +2,6 @@ <b-dropdown v-b-tooltip.hover right - role="button" title="Show panel options" variant="link" aria-label="View all tool panel configurations" From 0120730df4616860411d2acb8b3b53d7cb98f2c6 Mon Sep 17 00:00:00 2001 From: Dannon Baker <dannon.baker@gmail.com> Date: Thu, 18 Aug 2022 16:18:05 -0400 Subject: [PATCH 07/26] Add sr-only text to b-dropdown button in toolbox --- client/src/components/Panels/Buttons/PanelViewButton.vue | 3 +++ 1 file changed, 3 insertions(+) diff --git a/client/src/components/Panels/Buttons/PanelViewButton.vue b/client/src/components/Panels/Buttons/PanelViewButton.vue index 17e07ae6cf9..4716bc2b2e4 100644 --- a/client/src/components/Panels/Buttons/PanelViewButton.vue +++ b/client/src/components/Panels/Buttons/PanelViewButton.vue @@ -7,6 +7,9 @@ aria-label="View all tool panel configurations" class="tool-panel-dropdown" size="sm"> + <template v-slot:button-content> + <span class="sr-only">View all tool panel configurations</span> + </template> <PanelViewMenuItem :current-panel-view="currentPanelView" :panel-view="defaultPanelView" From 126258831a34689959c508764a823592b76b6ed6 Mon Sep 17 00:00:00 2001 From: Dannon Baker <dannon.baker@gmail.com> Date: Thu, 18 Aug 2022 16:19:49 -0400 Subject: [PATCH 08/26] Add sr-only text to history options dropdown --- .../components/History/CurrentHistory/HistoryNavigation.vue | 3 +++ 1 file changed, 3 insertions(+) diff --git a/client/src/components/History/CurrentHistory/HistoryNavigation.vue b/client/src/components/History/CurrentHistory/HistoryNavigation.vue index 94213a5bb8c..6fafc23e966 100644 --- a/client/src/components/History/CurrentHistory/HistoryNavigation.vue +++ b/client/src/components/History/CurrentHistory/HistoryNavigation.vue @@ -33,6 +33,9 @@ toggle-class="text-decoration-none" menu-class="history-options-button-menu" data-description="history options"> + <template v-slot:button-content> + <span class="sr-only">History Options</span> + </template> <b-dropdown-text> <div v-if="historiesLoading"> <b-spinner v-if="historiesLoading" small /> From 794329eb8f082223aceeeb6c10372533967cdf41 Mon Sep 17 00:00:00 2001 From: Dannon Baker <dannon.baker@gmail.com> Date: Thu, 18 Aug 2022 16:20:06 -0400 Subject: [PATCH 09/26] Add proper tooltip to history options dropdown --- .../src/components/History/CurrentHistory/HistoryNavigation.vue | 1 + 1 file changed, 1 insertion(+) diff --git a/client/src/components/History/CurrentHistory/HistoryNavigation.vue b/client/src/components/History/CurrentHistory/HistoryNavigation.vue index 6fafc23e966..ecf0ce7dd24 100644 --- a/client/src/components/History/CurrentHistory/HistoryNavigation.vue +++ b/client/src/components/History/CurrentHistory/HistoryNavigation.vue @@ -32,6 +32,7 @@ variant="link" toggle-class="text-decoration-none" menu-class="history-options-button-menu" + title="History options" data-description="history options"> <template v-slot:button-content> <span class="sr-only">History Options</span> From 45f9e608c445a8aadcfc103bc37c72012c166379 Mon Sep 17 00:00:00 2001 From: Dannon Baker <dannon.baker@gmail.com> Date: Thu, 18 Aug 2022 16:28:03 -0400 Subject: [PATCH 10/26] Fix aria labels in history filter box buttons --- .../CurrentHistory/HistoryFilters/HistoryFilters.vue | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/client/src/components/History/CurrentHistory/HistoryFilters/HistoryFilters.vue b/client/src/components/History/CurrentHistory/HistoryFilters/HistoryFilters.vue index 29573bd3f72..d6362e73699 100644 --- a/client/src/components/History/CurrentHistory/HistoryFilters/HistoryFilters.vue +++ b/client/src/components/History/CurrentHistory/HistoryFilters/HistoryFilters.vue @@ -17,11 +17,16 @@ :pressed="showAdvanced" :variant="showAdvanced ? 'info' : 'secondary'" data-description="show advanced filter toggle" + aria-label="Show advanced filter" @click="onToggle"> <icon v-if="showAdvanced" icon="angle-double-up" /> <icon v-else icon="angle-double-down" /> </b-button> - <b-button size="sm" data-description="show deleted filter toggle" @click="updateFilter('')"> + <b-button + size="sm" + aria-label="Clear filters" + data-description="clear filters" + @click="updateFilter('')"> <icon icon="times" /> </b-button> </b-input-group-append> From 981c8b2cab08950f2ec31a77cd2304bc58dd50ba Mon Sep 17 00:00:00 2001 From: Dannon Baker <dannon.baker@gmail.com> Date: Thu, 18 Aug 2022 16:36:05 -0400 Subject: [PATCH 11/26] Add sr-only text to history actions cog --- .../History/CurrentHistory/HistoryOperations/Operations.vue | 1 + 1 file changed, 1 insertion(+) diff --git a/client/src/components/History/CurrentHistory/HistoryOperations/Operations.vue b/client/src/components/History/CurrentHistory/HistoryOperations/Operations.vue index e5d4ee957ae..2b797a5cc09 100644 --- a/client/src/components/History/CurrentHistory/HistoryOperations/Operations.vue +++ b/client/src/components/History/CurrentHistory/HistoryOperations/Operations.vue @@ -8,6 +8,7 @@ toggle-class="text-decoration-none rounded-0" data-description="history action menu"> <template v-slot:button-content> + <span class="sr-only">History actions</span> <Icon icon="cog" /> </template> <b-dropdown-text id="history-op-all-content"> From d7c123c5ce80316ad757879424b80e9d17110439 Mon Sep 17 00:00:00 2001 From: Dannon Baker <dannon.baker@gmail.com> Date: Thu, 18 Aug 2022 16:38:05 -0400 Subject: [PATCH 12/26] aria-label attribute is not well supported on a div with no valid role attribute // specify menu here --- client/src/components/Panels/Buttons/PanelViewButton.vue | 1 + 1 file changed, 1 insertion(+) diff --git a/client/src/components/Panels/Buttons/PanelViewButton.vue b/client/src/components/Panels/Buttons/PanelViewButton.vue index 4716bc2b2e4..71809a56496 100644 --- a/client/src/components/Panels/Buttons/PanelViewButton.vue +++ b/client/src/components/Panels/Buttons/PanelViewButton.vue @@ -4,6 +4,7 @@ right title="Show panel options" variant="link" + role="menu" aria-label="View all tool panel configurations" class="tool-panel-dropdown" size="sm"> From b61e7280a13ec5190b9774500a9e9e1d85975380 Mon Sep 17 00:00:00 2001 From: Dannon Baker <dannon.baker@gmail.com> Date: Thu, 18 Aug 2022 17:18:56 -0400 Subject: [PATCH 13/26] Fix quotameter a11y label; have to work around bootstrap-vue shortcoming here. xref: https://dequeuniversity.com/rules/axe/4.4/aria-progressbar-name --- client/src/components/Masthead/QuotaMeter.vue | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/client/src/components/Masthead/QuotaMeter.vue b/client/src/components/Masthead/QuotaMeter.vue index 5dff5200fa4..206a1fdb110 100644 --- a/client/src/components/Masthead/QuotaMeter.vue +++ b/client/src/components/Masthead/QuotaMeter.vue @@ -5,7 +5,9 @@ {{ usingString + " " + totalUsageString }} </b-link> <b-link v-else v-b-tooltip.hover.left class="quota-progress" to="/storage" :title="title"> - <b-progress :value="usage" :max="100" :variant="variant" /> + <b-progress :max="100"> + <b-progress-bar aria-label="Quota usage" :value="usage" :variant="variant" /> + </b-progress> <span>{{ usingString + " " + usage.toFixed(0) }}%</span> </b-link> </div> From 28627fe3528c23a41781deb2d4a8bb001540c8d0 Mon Sep 17 00:00:00 2001 From: Dannon Baker <dannon.baker@gmail.com> Date: Thu, 18 Aug 2022 17:29:31 -0400 Subject: [PATCH 14/26] Masthead a11y; for icon-only tabs display the tooltip as a sr-only text placeholder. --- client/src/components/Masthead/MastheadItem.vue | 2 ++ 1 file changed, 2 insertions(+) diff --git a/client/src/components/Masthead/MastheadItem.vue b/client/src/components/Masthead/MastheadItem.vue index c50bc581002..124bc4d6c09 100644 --- a/client/src/components/Masthead/MastheadItem.vue +++ b/client/src/components/Masthead/MastheadItem.vue @@ -12,6 +12,8 @@ :title="tab.tooltip" @click="open(tab, $event)"> <template v-if="tab.icon"> + <!-- If this is an icon-based tab, inject tooltip directly for screen readers --> + <span class="sr-only">{{ tab.tooltip || tab.id }}</span> <span :class="iconClasses" /> <span v-if="toggle" class="nav-note fa fa-check" /> </template> From e1a6089cb295a7b88ee8f567aed3c77b2c2524d3 Mon Sep 17 00:00:00 2001 From: Dannon Baker <dannon.baker@gmail.com> Date: Thu, 18 Aug 2022 20:51:26 -0400 Subject: [PATCH 15/26] Wrap app in 'main' landmark. --- templates/js-app.mako | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/templates/js-app.mako b/templates/js-app.mako index c52916ce42c..57bb1744af9 100644 --- a/templates/js-app.mako +++ b/templates/js-app.mako @@ -27,7 +27,9 @@ <body scroll="no" class="full-content"> <!-- Provide mount point for application --> - <div id="app"></div> + <main> + <div id="app"></div> + </main> ${ js_disabled_warning() } ${ javascripts() } From 3aad3708bf352236d5f6e33e18f1e996156517c6 Mon Sep 17 00:00:00 2001 From: Dannon Baker <dannon.baker@gmail.com> Date: Fri, 19 Aug 2022 08:20:35 -0400 Subject: [PATCH 16/26] Update masthead test to check for scratchbook existence with a more specific selector. --- client/src/components/Masthead/Masthead.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/components/Masthead/Masthead.test.js b/client/src/components/Masthead/Masthead.test.js index 3ef70f80abb..1024cdede18 100644 --- a/client/src/components/Masthead/Masthead.test.js +++ b/client/src/components/Masthead/Masthead.test.js @@ -140,7 +140,7 @@ describe("Masthead.vue", () => { }); it("should display window manager button", async () => { - expect(wrapper.find("#enable-window-manager a span").classes("fa-th")).toBe(true); + expect(wrapper.find("#enable-window-manager a span.fa-th").exists()).toBe(true); expect(windowManager.active).toBe(false); await wrapper.find("#enable-window-manager a").trigger("click"); expect(windowManager.active).toBe(true); From 4b08481ed1f165835f638198119c0d3cfcf31a3c Mon Sep 17 00:00:00 2001 From: Dannon Baker <dannon.baker@gmail.com> Date: Fri, 19 Aug 2022 08:21:07 -0400 Subject: [PATCH 17/26] Fix historyfilters test to look for updated data description. --- .../CurrentHistory/HistoryFilters/HistoryFilters.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/components/History/CurrentHistory/HistoryFilters/HistoryFilters.test.js b/client/src/components/History/CurrentHistory/HistoryFilters/HistoryFilters.test.js index cf8262f6c1f..0b4769571d9 100644 --- a/client/src/components/History/CurrentHistory/HistoryFilters/HistoryFilters.test.js +++ b/client/src/components/History/CurrentHistory/HistoryFilters/HistoryFilters.test.js @@ -53,7 +53,7 @@ describe("HistoryFilters", () => { await expectCorrectEmits(wrapper, false, "name:name-filter"); // Test: clearing the filterText - const clearButton = wrapper.find("[data-description='show deleted filter toggle']"); + const clearButton = wrapper.find("[data-description='clear filters']"); await clearButton.trigger("click"); await expectCorrectEmits(wrapper, false, ""); From d84379fb778aa4fc15623f6f21bf580a182c0235 Mon Sep 17 00:00:00 2001 From: Dannon Baker <dannon.baker@gmail.com> Date: Mon, 22 Aug 2022 09:51:43 -0400 Subject: [PATCH 18/26] Attribute order tweaks --- client/src/components/Workflow/Invocations.vue | 4 ++-- client/src/entry/analysis/modules/Base.vue | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/client/src/components/Workflow/Invocations.vue b/client/src/components/Workflow/Invocations.vue index 580677a7093..44b517ab491 100644 --- a/client/src/components/Workflow/Invocations.vue +++ b/client/src/components/Workflow/Invocations.vue @@ -66,9 +66,9 @@ </template> <template v-slot:cell(execute)="data"> <WorkflowRunButton + v-if="getStoredWorkflowIdByInstanceId(data.item.workflow_id)" :id="getStoredWorkflowIdByInstanceId(data.item.workflow_id)" - :root="root" - v-if="getStoredWorkflowIdByInstanceId(data.item.workflow_id)" /> + :root="root" /> </template> </b-table> <b-pagination diff --git a/client/src/entry/analysis/modules/Base.vue b/client/src/entry/analysis/modules/Base.vue index 8f3e0876441..0d9d8c82212 100644 --- a/client/src/entry/analysis/modules/Base.vue +++ b/client/src/entry/analysis/modules/Base.vue @@ -1,3 +1,3 @@ <template> - <router-view class="m-2" :key="$route.fullPath" /> + <router-view :key="$route.fullPath" class="m-2" /> </template> From 23c94f407ba71d804190eeb5706443ac891b20e6 Mon Sep 17 00:00:00 2001 From: Dannon Baker <dannon.baker@gmail.com> Date: Mon, 22 Aug 2022 09:51:56 -0400 Subject: [PATCH 19/26] Add eslint plugin for vuejs accessibility testing --- client/.eslintrc.json | 4 ++-- client/package.json | 1 + client/yarn.lock | 14 ++++++++++++++ 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/client/.eslintrc.json b/client/.eslintrc.json index 5f85ab1cfa8..b7031822e77 100644 --- a/client/.eslintrc.json +++ b/client/.eslintrc.json @@ -3,8 +3,8 @@ "extends": [ "eslint:recommended", "plugin:vue/recommended", - "plugin:compat/recommended" - //"airbnb-base", eventually (?) + "plugin:compat/recommended", + "plugin:vuejs-accessibility/recommended" ], "env": { "browser": true, diff --git a/client/package.json b/client/package.json index 0352d66a6b7..df59e80642a 100644 --- a/client/package.json +++ b/client/package.json @@ -148,6 +148,7 @@ "eslint": "^8.20.0", "eslint-plugin-compat": "^4.0.2", "eslint-plugin-vue": "^9.3.0", + "eslint-plugin-vuejs-accessibility": "^1.2.0", "expose-loader": "^4.0.0", "gulp": "^4.0.2", "ignore-loader": "^0.1.2", diff --git a/client/yarn.lock b/client/yarn.lock index d415e87e632..79d7e97e0cb 100644 --- a/client/yarn.lock +++ b/client/yarn.lock @@ -3926,6 +3926,11 @@ emittery@^0.8.1: resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.8.1.tgz#bb23cc86d03b30aa75a7f734819dee2e1ba70860" integrity sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg== +emoji-regex@^10.0.0: + version "10.1.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-10.1.0.tgz#d50e383743c0f7a5945c47087295afc112e3cf66" + integrity sha512-xAEnNCT3w2Tg6MA7ly6QqYJvEoY1tm9iIjJ3yMKK9JPlWuRHAMoe5iETwQnx3M9TVbFMfsrBgWKR+IsmswwNjg== + emoji-regex@^8.0.0: version "8.0.0" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" @@ -4159,6 +4164,15 @@ eslint-plugin-vue@^9.3.0: vue-eslint-parser "^9.0.1" xml-name-validator "^4.0.0" +eslint-plugin-vuejs-accessibility@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-vuejs-accessibility/-/eslint-plugin-vuejs-accessibility-1.2.0.tgz#b7304bc8dfe4fad930c5d95cd51a2e0979225bda" + integrity sha512-wF7kT22lS2VOmIpDeI65bnFFKFgESEEpI+CWKr43mdfDRywA4sCk7cKhtZsvfbPOtKO0GDlnpFxZbOIGsFn7IQ== + dependencies: + aria-query "^5.0.0" + emoji-regex "^10.0.0" + vue-eslint-parser "^9.0.1" + eslint-scope@5.1.1, eslint-scope@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" From 2819ba5557c267f9c7b6d0ae8e59091c993d9440 Mon Sep 17 00:00:00 2001 From: Dannon Baker <dannon.baker@gmail.com> Date: Mon, 22 Aug 2022 09:56:56 -0400 Subject: [PATCH 20/26] Set refined error/warn granularity for first pass implementing vuejs-accessibility --- client/.eslintrc.json | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/client/.eslintrc.json b/client/.eslintrc.json index b7031822e77..5df4f328d4a 100644 --- a/client/.eslintrc.json +++ b/client/.eslintrc.json @@ -41,7 +41,19 @@ "vue/singleline-html-element-content-newline": "off", "vue/multiline-html-element-content-newline": "off", "vue/html-closing-bracket-newline": "off", - "vue/html-closing-bracket-spacing": "off" + "vue/html-closing-bracket-spacing": "off", + + // Accessibility rules + "vuejs-accessibility/alt-text": "error", + "vuejs-accessibility/anchor-has-content": "warn", + "vuejs-accessibility/click-events-have-key-events": "warn", + "vuejs-accessibility/form-control-has-label": "warn", + "vuejs-accessibility/heading-has-content": "error", + "vuejs-accessibility/iframe-has-title": "error", + "vuejs-accessibility/label-has-for": "warn", + "vuejs-accessibility/mouse-events-have-key-events": "warn", + "vuejs-accessibility/no-autofocus": "error", + "vuejs-accessibility/tabindex-no-positive": "error" }, "ignorePatterns": ["src/qunit", "src/mocha", "src/libs", "src/nls", "src/legacy"] } From f241d19ae5883e2b062925d453fe344dfa8441da Mon Sep 17 00:00:00 2001 From: Dannon Baker <dannon.baker@gmail.com> Date: Mon, 22 Aug 2022 09:57:31 -0400 Subject: [PATCH 21/26] Drop usage of autofocus prop in clicktoedit https://github.com/vue-a11y/eslint-plugin-vuejs-accessibility/blob/main/docs/no-autofocus.md --- client/src/components/ClickToEdit.vue | 1 - 1 file changed, 1 deletion(-) diff --git a/client/src/components/ClickToEdit.vue b/client/src/components/ClickToEdit.vue index 04f1ea3cfb6..44a3cdf67cc 100644 --- a/client/src/components/ClickToEdit.vue +++ b/client/src/components/ClickToEdit.vue @@ -17,7 +17,6 @@ <b-form-input ref="clickToEditInput" :value="debouncedValue" - :autofocus="true" :placeholder="placeholder" :state="stateValidator(debouncedValue, localValue)" @input="input" From da8a4ae5a7f3e00f3d08e4fd0b147ac8e8e70eef Mon Sep 17 00:00:00 2001 From: Dannon Baker <dannon.baker@gmail.com> Date: Mon, 22 Aug 2022 10:02:16 -0400 Subject: [PATCH 22/26] Add title to galaxy viz iframe // vuejs-a11y --- client/src/components/Markdown/Elements/Visualization.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/components/Markdown/Elements/Visualization.vue b/client/src/components/Markdown/Elements/Visualization.vue index 0f500b9efa2..13476efc5cf 100644 --- a/client/src/components/Markdown/Elements/Visualization.vue +++ b/client/src/components/Markdown/Elements/Visualization.vue @@ -2,7 +2,7 @@ <b-card body-class="embed-responsive embed-responsive-4by3"> <LoadingSpan v-if="loading" class="m-2" message="Loading Visualization" /> <div v-else-if="error" class="m-2">{{ error }}</div> - <iframe v-else class="embed-responsive-item" :src="visualizationUrl" /> + <iframe v-else title="Galaxy Visualization Frame" class="embed-responsive-item" :src="visualizationUrl" /> </b-card> </template> From 30107d5be021856a15472cb8047dc1430b8ca917 Mon Sep 17 00:00:00 2001 From: Dannon Baker <dannon.baker@gmail.com> Date: Mon, 22 Aug 2022 10:05:46 -0400 Subject: [PATCH 23/26] Use tabindex 0 in sharing, flowing naturally in the page order instead of forcing first index. https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/tabindex#accessibility_concerns --- client/src/components/Sharing/Sharing.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/components/Sharing/Sharing.vue b/client/src/components/Sharing/Sharing.vue index 11bb957c75f..bbb87cc7afa 100644 --- a/client/src/components/Sharing/Sharing.vue +++ b/client/src/components/Sharing/Sharing.vue @@ -123,7 +123,7 @@ <span>{{ option.email }}</span> <i aria-hidden="true" - tabindex="1" + tabindex="0" class="multiselect__tag-icon" @click="remove(option)"></i> </span> From deafe95eaff7251f22a4b67201a6a6a6c5cb59c4 Mon Sep 17 00:00:00 2001 From: Dannon Baker <dannon.baker@gmail.com> Date: Mon, 22 Aug 2022 10:16:49 -0400 Subject: [PATCH 24/26] Add image alt tag to tool logo -- vue-a11y --- client/src/components/Panels/Common/Tool.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/components/Panels/Common/Tool.vue b/client/src/components/Panels/Common/Tool.vue index 76ce79d6d22..43e2bd53b9e 100644 --- a/client/src/components/Panels/Common/Tool.vue +++ b/client/src/components/Panels/Common/Tool.vue @@ -5,7 +5,7 @@ <span class="description">{{ tool.description }}</span> </a> <a v-else :class="targetClass" :href="tool.link" :target="tool.target" @click="onClick"> - <img v-if="tool.logo" class="logo" :src="tool.logo" /> + <img v-if="tool.logo" class="logo" :src="tool.logo" :alt="tool.name"/> <span class="labels"> <span v-for="(label, index) in tool.labels" From a4c077150fb8d2538b3955a3cae3f8b052bdfbd7 Mon Sep 17 00:00:00 2001 From: Dannon Baker <dannon.baker@gmail.com> Date: Mon, 22 Aug 2022 10:33:40 -0400 Subject: [PATCH 25/26] Flag two empty headers as compliant -- v-short will always insert contents here Format. --- .../components/History/CurrentCollection/CollectionDetails.vue | 1 + client/src/components/History/CurrentHistory/HistoryDetails.vue | 1 + client/src/components/Panels/Common/Tool.vue | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/client/src/components/History/CurrentCollection/CollectionDetails.vue b/client/src/components/History/CurrentCollection/CollectionDetails.vue index 0a743c7d0d7..7cae6c7cae3 100644 --- a/client/src/components/History/CurrentCollection/CollectionDetails.vue +++ b/client/src/components/History/CurrentCollection/CollectionDetails.vue @@ -6,6 +6,7 @@ :show-annotation="false" @save="$emit('update:dsc', $event)"> <template v-slot:name> + <!-- eslint-disable-next-line vuejs-accessibility/heading-has-content --> <h3 v-short="dsc.name || 'Collection'" data-description="collection name display" /> <CollectionDescription :job-state-summary="jobState" diff --git a/client/src/components/History/CurrentHistory/HistoryDetails.vue b/client/src/components/History/CurrentHistory/HistoryDetails.vue index 6f43400f768..831fb28d00e 100644 --- a/client/src/components/History/CurrentHistory/HistoryDetails.vue +++ b/client/src/components/History/CurrentHistory/HistoryDetails.vue @@ -6,6 +6,7 @@ :writeable="writeable" @save="onSave"> <template v-slot:name> + <!-- eslint-disable-next-line vuejs-accessibility/heading-has-content --> <h3 v-short="history.name || 'History'" data-description="name display" class="my-2" /> </template> </DetailsLayout> diff --git a/client/src/components/Panels/Common/Tool.vue b/client/src/components/Panels/Common/Tool.vue index 43e2bd53b9e..be926ec04ed 100644 --- a/client/src/components/Panels/Common/Tool.vue +++ b/client/src/components/Panels/Common/Tool.vue @@ -5,7 +5,7 @@ <span class="description">{{ tool.description }}</span> </a> <a v-else :class="targetClass" :href="tool.link" :target="tool.target" @click="onClick"> - <img v-if="tool.logo" class="logo" :src="tool.logo" :alt="tool.name"/> + <img v-if="tool.logo" class="logo" :src="tool.logo" :alt="tool.name" /> <span class="labels"> <span v-for="(label, index) in tool.labels" From 2c9fc7751ff1895dce7389dc0336f7acbc0f05e2 Mon Sep 17 00:00:00 2001 From: Dannon Baker <dannon.baker@gmail.com> Date: Mon, 22 Aug 2022 11:05:34 -0400 Subject: [PATCH 26/26] Rename CenterPanel as CenterFrame for clarity -- this is always an iframe and is too layered --- client/src/components/Tour/TourRunner.vue | 6 +++--- client/src/entry/analysis/modules/Analysis.vue | 6 +++--- .../analysis/modules/{CenterPanel.vue => CenterFrame.vue} | 2 +- client/src/entry/analysis/modules/Home.vue | 6 +++--- 4 files changed, 10 insertions(+), 10 deletions(-) rename client/src/entry/analysis/modules/{CenterPanel.vue => CenterFrame.vue} (94%) diff --git a/client/src/components/Tour/TourRunner.vue b/client/src/components/Tour/TourRunner.vue index a4fdb2c3c27..02fd9f2087f 100644 --- a/client/src/components/Tour/TourRunner.vue +++ b/client/src/components/Tour/TourRunner.vue @@ -1,14 +1,14 @@ <template> - <CenterPanel src="welcome" /> + <CenterFrame src="welcome" /> </template> <script> -import CenterPanel from "entry/analysis/modules/CenterPanel"; +import CenterFrame from "entry/analysis/modules/CenterFrame"; import { runTour } from "./runTour"; export default { components: { - CenterPanel, + CenterFrame, }, props: { tourId: { diff --git a/client/src/entry/analysis/modules/Analysis.vue b/client/src/entry/analysis/modules/Analysis.vue index 446029b2bd2..17379d9a667 100644 --- a/client/src/entry/analysis/modules/Analysis.vue +++ b/client/src/entry/analysis/modules/Analysis.vue @@ -7,7 +7,7 @@ :current-panel-properties="toolBoxProperties" /> <div id="center"> <div class="center-container"> - <CenterPanel v-show="showCenter" id="galaxy_main" @load="onLoad" /> + <CenterFrame v-show="showCenter" id="galaxy_main" @load="onLoad" /> <div v-show="!showCenter" class="center-panel" style="display: block"> <router-view :key="$route.fullPath" /> </div> @@ -21,11 +21,11 @@ import { getGalaxyInstance } from "app"; import HistoryIndex from "components/History/Index"; import ToolBox from "components/Panels/ProviderAwareToolBox"; import SidePanel from "components/Panels/SidePanel"; -import CenterPanel from "./CenterPanel"; +import CenterFrame from "./CenterFrame"; export default { components: { - CenterPanel, + CenterFrame, SidePanel, }, data() { diff --git a/client/src/entry/analysis/modules/CenterPanel.vue b/client/src/entry/analysis/modules/CenterFrame.vue similarity index 94% rename from client/src/entry/analysis/modules/CenterPanel.vue rename to client/src/entry/analysis/modules/CenterFrame.vue index 3bae2638c0a..24b8f1486cc 100644 --- a/client/src/entry/analysis/modules/CenterPanel.vue +++ b/client/src/entry/analysis/modules/CenterFrame.vue @@ -38,7 +38,7 @@ export default { this.$emit("load"); } } catch (err) { - console.warn("CenterPanel - onLoad location access forbidden.", ev, location); + console.warn("CenterFrame - onLoad location access forbidden.", ev, location); } }, }, diff --git a/client/src/entry/analysis/modules/Home.vue b/client/src/entry/analysis/modules/Home.vue index 146052331d5..7b5fe0c2158 100644 --- a/client/src/entry/analysis/modules/Home.vue +++ b/client/src/entry/analysis/modules/Home.vue @@ -3,19 +3,19 @@ <ToolForm v-if="isTool && !isUpload" v-bind="toolParams" /> <WorkflowRun v-else-if="isWorkflow" v-bind="workflowParams" /> <div v-else-if="isController" :src="controllerParams" /> - <CenterPanel v-else src="welcome" /> + <CenterFrame v-else src="welcome" /> </div> </template> <script> import decodeUriComponent from "decode-uri-component"; -import CenterPanel from "entry/analysis/modules/CenterPanel"; +import CenterFrame from "entry/analysis/modules/CenterFrame"; import ToolForm from "components/Tool/ToolForm"; import WorkflowRun from "components/Workflow/Run/WorkflowRun"; export default { components: { - CenterPanel, + CenterFrame, ToolForm, WorkflowRun, },