From 3b1b923a18578c2c1f1ff1359591b437f1c231e5 Mon Sep 17 00:00:00 2001 From: Lloydi Date: Sun, 19 Jul 2020 22:24:12 +0100 Subject: [PATCH 01/18] Removed tabindex="-1" from all buttons This was making the whole UI inaccessible for keyboard-only users --- src/ui.js | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/src/ui.js b/src/ui.js index 80d85db..3092946 100755 --- a/src/ui.js +++ b/src/ui.js @@ -1672,8 +1672,6 @@ var btn_panner_left = d.createElement ('button'); var btn_panner_right = d.createElement ('button'); - btn_panner_left.setAttribute ('tabIndex', -1); - btn_panner_right.setAttribute ('tabIndex', -1); btn_panner_left.className = 'pk_pan_btn'; btn_panner_right.className = 'pk_pan_btn'; @@ -1728,7 +1726,6 @@ var btn_zoom_in_h = d.createElement ('button'); btn_zoom_in_h.className = 'pk_btn pk_zoom_in_h'; btn_zoom_in_h.innerHTML = '+Zoom In Horiz (+)'; - btn_zoom_in_h.setAttribute ('tabIndex', -1); btn_zoom_in_h.onclick = function () { app.fireEvent ('RequestZoomUI', 'h', -1); this.blur(); @@ -1737,7 +1734,6 @@ var btn_zoom_out_h = d.createElement ('button'); btn_zoom_out_h.className = 'pk_btn pk_zoom_out_h pk_inact'; btn_zoom_out_h.innerHTML = '–Zoom Out Horiz (-)'; - btn_zoom_out_h.setAttribute ('tabIndex', -1); btn_zoom_out_h.onclick = function () { app.fireEvent ('RequestZoomUI', 'h', 1); this.blur(); @@ -1746,7 +1742,6 @@ var btn_zoom_reset = d.createElement ('button'); btn_zoom_reset.className = 'pk_btn pk_zoom_reset pk_inact'; btn_zoom_reset.innerHTML = '[R] Reset Zoom (0)'; - btn_zoom_reset.setAttribute ('tabIndex', -1); btn_zoom_reset.onclick = function () { app.fireEvent ('RequestZoomUI', 0); this.blur(); @@ -1768,7 +1763,6 @@ var btn_zoom_in_v = d.createElement ('button'); btn_zoom_in_v.className = 'pk_btn pk_zoom_in_v'; btn_zoom_in_v.innerHTML = '↕ +Zoom In Vertically'; - btn_zoom_in_v.setAttribute ('tabIndex', -1); btn_zoom_in_v.onclick = function () { app.fireEvent ('RequestZoomUI', 'v', -1); this.blur(); @@ -1777,7 +1771,6 @@ var btn_zoom_out_v = d.createElement ('button'); btn_zoom_out_v.className = 'pk_btn pk_zoom_out_v'; btn_zoom_out_v.innerHTML = '↕ –Zoom Out Vertically'; - btn_zoom_out_v.setAttribute ('tabIndex', -1); btn_zoom_out_v.onclick = function () { app.fireEvent ('RequestZoomUI', 'v', 1); this.blur(); @@ -2067,7 +2060,6 @@ // play button var btn_stop = d.createElement ('button'); - btn_stop.setAttribute ('tabIndex', -1); btn_stop.innerHTML = 'Stop Playback (Space)'; btn_stop.className = 'pk_btn pk_stop icon-stop2'; btn_stop.onclick = function() { @@ -2076,7 +2068,6 @@ transport.appendChild ( btn_stop ); var btn_play = d.createElement ('button'); - btn_play.setAttribute ('tabIndex', -1); btn_play.className = 'pk_btn pk_play icon-play3'; btn_play.innerHTML = 'Play (Space)'; transport.appendChild ( btn_play ); @@ -2092,7 +2083,6 @@ }); var btn_pause = d.createElement ('button'); - btn_pause.setAttribute('tabIndex', -1); btn_pause.className = 'pk_btn pk_pause icon-pause2'; btn_pause.innerHTML = 'Pause (Shift+Space)'; transport.appendChild ( btn_pause ); @@ -2102,7 +2092,6 @@ }; var btn_loop = d.createElement ('button'); - btn_loop.setAttribute('tabIndex', -1); btn_loop.className = 'pk_btn pk_loop icon-loop'; btn_loop.innerHTML = 'Toggle Loop (L)'; transport.appendChild ( btn_loop ); @@ -2116,7 +2105,6 @@ }); var btn_back_jump = d.createElement ('button'); - btn_back_jump.setAttribute('tabIndex', -1); btn_back_jump.className = 'pk_btn pk_back_jump icon-backward2'; btn_back_jump.innerHTML = 'Seek (left arrow)'; transport.appendChild ( btn_back_jump ); @@ -2196,7 +2184,6 @@ //////////////////////// var btn_front_jump = d.createElement ('button'); - btn_front_jump.setAttribute('tabIndex', -1); btn_front_jump.className = 'pk_btn pk_front_jump icon-forward3'; btn_front_jump.innerHTML = 'Seek (right arrow)'; transport.appendChild ( btn_front_jump ); @@ -2388,7 +2375,6 @@ }, [27]); var btn_back_total = d.createElement ('button'); - btn_back_total.setAttribute('tabIndex', -1); btn_back_total.className = 'pk_btn icon-previous2'; btn_back_total.innerHTML = 'Seek Start (Shift + left arrow)'; transport.appendChild ( btn_back_total ); @@ -2399,7 +2385,6 @@ }; var btn_front_total = d.createElement ('button'); - btn_front_total.setAttribute('tabIndex', -1); btn_front_total.className = 'pk_btn icon-next2'; btn_front_total.innerHTML = 'Seek End (Shift + right arrow)'; btn_front_total.onclick = function() { @@ -2411,7 +2396,6 @@ var btn_rec = d.createElement ('button'); - btn_rec.setAttribute('tabIndex', -1); btn_rec.className = 'pk_btn icon-rec'; btn_rec.innerHTML = 'Record (R)'; btn_rec.onclick = function() { @@ -2684,7 +2668,6 @@ actions.className = 'pk_ctns'; var copy_btn = d.createElement ('button'); - copy_btn.setAttribute('tabIndex', -1); copy_btn.className = 'pk_btn icon-files-empty pk_inact'; copy_btn.innerHTML = 'Copy Selection (Shift + C)'; actions.appendChild ( copy_btn ); @@ -2713,7 +2696,6 @@ }; var cut_btn = d.createElement ('button'); - cut_btn.setAttribute('tabIndex', -1); cut_btn.className = 'pk_btn icon-scissors pk_inact'; cut_btn.innerHTML = 'Cut Selection (Shift + X)'; actions.appendChild ( cut_btn ); @@ -2724,7 +2706,6 @@ }; var silence_btn = d.createElement ('button'); - silence_btn.setAttribute('tabIndex', -1); silence_btn.className = 'pk_btn icon-silence'; silence_btn.innerHTML = 'Insert Silence (Shift + N)'; actions.appendChild ( silence_btn ); @@ -2752,7 +2733,6 @@ ''; var btn_clear_selection = d.createElement ('button'); - btn_clear_selection.setAttribute('tabIndex', -1); btn_clear_selection.className = 'pk_btn icon-clearsel pk_inact'; btn_clear_selection.innerHTML = 'Clear Selection (~ tilda)'; From 5a7c4361ea2327ca1dfbdda2ce71b7432d65a756 Mon Sep 17 00:00:00 2001 From: Lloydi Date: Sun, 19 Jul 2020 22:32:07 +0100 Subject: [PATCH 02/18] Provided button labels with aria-labelledby All buttons were missing an accessible name (the inner content was being stripped by the tooltip effect. Fixed by adding id to the inner and referencing it with aria-labelledby --- src/ui.js | 42 ++++++++++++++++++++++++++++-------------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/src/ui.js b/src/ui.js index 3092946..012aab3 100755 --- a/src/ui.js +++ b/src/ui.js @@ -2060,7 +2060,8 @@ // play button var btn_stop = d.createElement ('button'); - btn_stop.innerHTML = 'Stop Playback (Space)'; + btn_stop.innerHTML = 'Stop Playback (Space)'; + btn_stop.setAttribute('aria-labelledby','btn_stop_label'); btn_stop.className = 'pk_btn pk_stop icon-stop2'; btn_stop.onclick = function() { UI.fireEvent('RequestStop'); @@ -2069,7 +2070,8 @@ var btn_play = d.createElement ('button'); btn_play.className = 'pk_btn pk_play icon-play3'; - btn_play.innerHTML = 'Play (Space)'; + btn_play.innerHTML = 'Play (Space)'; + btn_play.setAttribute('aria-labelledby','btn_play_label'); transport.appendChild ( btn_play ); btn_play.onclick = function() { UI.fireEvent('RequestPlay'); @@ -2084,7 +2086,8 @@ var btn_pause = d.createElement ('button'); btn_pause.className = 'pk_btn pk_pause icon-pause2'; - btn_pause.innerHTML = 'Pause (Shift+Space)'; + btn_pause.innerHTML = 'Pause (Shift+Space)'; + btn_pause.setAttribute('aria-labelledby','btn_pause_label'); transport.appendChild ( btn_pause ); btn_pause.onclick = function() { UI.fireEvent('RequestPause'); @@ -2093,7 +2096,8 @@ var btn_loop = d.createElement ('button'); btn_loop.className = 'pk_btn pk_loop icon-loop'; - btn_loop.innerHTML = 'Toggle Loop (L)'; + btn_loop.innerHTML = 'Toggle Loop (L)'; + btn_loop.setAttribute('aria-labelledby','btn_loop_label'); transport.appendChild ( btn_loop ); btn_loop.onclick = function() { UI.fireEvent('RequestSetLoop'); @@ -2106,7 +2110,8 @@ var btn_back_jump = d.createElement ('button'); btn_back_jump.className = 'pk_btn pk_back_jump icon-backward2'; - btn_back_jump.innerHTML = 'Seek (left arrow)'; + btn_back_jump.innerHTML = 'Seek (left arrow)'; + btn_back_jump.setAttribute('aria-labelledby','btn_back_jump_label'); transport.appendChild ( btn_back_jump ); /////////////////////////////////////////////////////////// @@ -2185,7 +2190,8 @@ var btn_front_jump = d.createElement ('button'); btn_front_jump.className = 'pk_btn pk_front_jump icon-forward3'; - btn_front_jump.innerHTML = 'Seek (right arrow)'; + btn_front_jump.innerHTML = 'Seek (right arrow)'; + btn_front_jump.setAttribute('aria-labelledby','btn_front_jump_label'); transport.appendChild ( btn_front_jump ); var btn_frnt_focus = false; @@ -2376,7 +2382,8 @@ var btn_back_total = d.createElement ('button'); btn_back_total.className = 'pk_btn icon-previous2'; - btn_back_total.innerHTML = 'Seek Start (Shift + left arrow)'; + btn_back_total.innerHTML = 'Seek Start (Shift + left arrow)'; + btn_back_total.setAttribute('aria-labelledby','btn_back_total_label'); transport.appendChild ( btn_back_total ); btn_back_total.onclick = function() { UI.fireEvent( 'RequestRegionClear'); @@ -2386,7 +2393,8 @@ var btn_front_total = d.createElement ('button'); btn_front_total.className = 'pk_btn icon-next2'; - btn_front_total.innerHTML = 'Seek End (Shift + right arrow)'; + btn_front_total.innerHTML = 'Seek End (Shift + right arrow)'; + btn_front_total.setAttribute('aria-labelledby','btn_front_total_label'); btn_front_total.onclick = function() { UI.fireEvent( 'RequestRegionClear'); UI.fireEvent( 'RequestSeekTo', 0.996); @@ -2397,7 +2405,8 @@ var btn_rec = d.createElement ('button'); btn_rec.className = 'pk_btn icon-rec'; - btn_rec.innerHTML = 'Record (R)'; + btn_rec.innerHTML = 'Record (R)'; + btn_rec.setAttribute('aria-labelledby','btn_rec_label'); btn_rec.onclick = function() { if (this.getAttribute('disabled') === 'disabled') { this.blur (); return ; @@ -2669,7 +2678,8 @@ var copy_btn = d.createElement ('button'); copy_btn.className = 'pk_btn icon-files-empty pk_inact'; - copy_btn.innerHTML = 'Copy Selection (Shift + C)'; + copy_btn.innerHTML = 'Copy Selection (Shift + C)'; + copy_btn.setAttribute('aria-labelledby','copy_btn_label'); actions.appendChild ( copy_btn ); copy_btn.onclick = function() { @@ -2687,7 +2697,8 @@ var paste_btn = d.createElement ('button'); paste_btn.setAttribute('focusable', 'false'); paste_btn.className = 'pk_btn icon-file-text2 pk_inact'; - paste_btn.innerHTML = 'Paste Selection (Shift + V)'; + paste_btn.innerHTML = 'Paste Selection (Shift + V)'; + paste_btn.setAttribute('aria-labelledby','paste_btn_label'); actions.appendChild ( paste_btn ); paste_btn.onclick = function() { @@ -2697,7 +2708,8 @@ var cut_btn = d.createElement ('button'); cut_btn.className = 'pk_btn icon-scissors pk_inact'; - cut_btn.innerHTML = 'Cut Selection (Shift + X)'; + cut_btn.innerHTML = 'Cut Selection (Shift + X)'; + cut_btn.setAttribute('aria-labelledby','cut_btn_label'); actions.appendChild ( cut_btn ); cut_btn.onclick = function() { @@ -2707,7 +2719,8 @@ var silence_btn = d.createElement ('button'); silence_btn.className = 'pk_btn icon-silence'; - silence_btn.innerHTML = 'Insert Silence (Shift + N)'; + silence_btn.innerHTML = 'Insert Silence (Shift + N)'; + silence_btn.setAttribute('aria-labelledby','silence_btn_label'); actions.appendChild ( silence_btn ); UI.KeyHandler.addCallback ('KeyShiftN', function( k ) { @@ -2734,7 +2747,8 @@ var btn_clear_selection = d.createElement ('button'); btn_clear_selection.className = 'pk_btn icon-clearsel pk_inact'; - btn_clear_selection.innerHTML = 'Clear Selection (~ tilda)'; + btn_clear_selection.innerHTML = 'Clear Selection (~ tilda)'; + btn_clear_selection.setAttribute('aria-labelledby','btn_clear_selection_label'); var sel_spans = selection.getElementsByClassName('pk_dat'); UI.listenFor ('DidCreateRegion', function ( region ) { From 812116d96d1085fa058db837247fe8ee6ff61a60 Mon Sep 17 00:00:00 2001 From: Lloydi Date: Sun, 19 Jul 2020 22:56:28 +0100 Subject: [PATCH 03/18] Added region and group roles Allows for screen reader users to jump from region to region more easily --- src/ui.js | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/ui.js b/src/ui.js index 012aab3..9d4be18 100755 --- a/src/ui.js +++ b/src/ui.js @@ -1291,6 +1291,8 @@ function _makeUITopHeader ( menu_tree, UI ) { var header = d.createElement ( 'div' ); header.className = 'pk_hdr pk_noselect'; + header.setAttribute('role','region'); + header.setAttribute('aria-label','Application menu'); var _name = 'TopHeader', _default_class = 'pk_btn pk_noselect'; @@ -1648,6 +1650,8 @@ var audio_container = d.createElement ('div'); audio_container.className = 'pk_av_cont'; + audio_container.setAttribute('role','region'); + audio_container.setAttribute('aria-label','Audio waveform'); UI.el.appendChild( audio_container ); @@ -1659,6 +1663,8 @@ var footer = d.createElement ( 'div' ); footer.className = 'pk_ftr pk_noselect'; + footer.setAttribute('role','region'); + footer.setAttribute('aria-label','Volume information'); UI.el.appendChild( footer ); // make panner buttons @@ -2048,6 +2054,8 @@ function _makeUIToolbar (UI) { var container = d.createElement ( 'div' ); container.className = 'pk_tbc'; + container.setAttribute('role','toolbar'); + container.setAttribute('aria-label','Main tools'); var toolbar = d.createElement ( 'div' ); toolbar.className = 'pk_tb pk_noselect'; @@ -2057,6 +2065,8 @@ var transport = d.createElement( 'div' ); transport.className = 'pk_transport'; + transport.setAttribute('role','group'); + transport.setAttribute('aria-label','Transport controls'); // play button var btn_stop = d.createElement ('button'); @@ -2442,6 +2452,8 @@ var timing = d.createElement( 'div' ); timing.className = 'pk_timecontainer'; + timing.setAttribute('role','group'); + timing.setAttribute('aria-label','Time information') var timingspan = d.createElement( 'span' ); timingspan.innerText = '00:00:000'; @@ -2675,6 +2687,8 @@ var actions = d.createElement( 'div' ); actions.className = 'pk_ctns'; + action.setAttribute('role','group'); + action.setAttribute('aria-label','Copy/Paste controls'); var copy_btn = d.createElement ('button'); copy_btn.className = 'pk_btn icon-files-empty pk_inact'; @@ -2738,6 +2752,8 @@ var selection = d.createElement( 'div' ); selection.className = 'pk_selection'; + selection.setAttribute('role','group'); + selection.setAttribute('aria-label','Selected audio time properties'); selection.innerHTML = '
' + 'Selection:' + '
Start:-
' + From c605c640988eca50069c500509dc100094b242e5 Mon Sep 17 00:00:00 2001 From: Lloydi Date: Sun, 19 Jul 2020 23:05:33 +0100 Subject: [PATCH 04/18] Typo on action. => actions. --- src/ui.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ui.js b/src/ui.js index 9d4be18..ae5c3f1 100755 --- a/src/ui.js +++ b/src/ui.js @@ -2687,8 +2687,8 @@ var actions = d.createElement( 'div' ); actions.className = 'pk_ctns'; - action.setAttribute('role','group'); - action.setAttribute('aria-label','Copy/Paste controls'); + actions.setAttribute('role','group'); + actions.setAttribute('aria-label','Copy/Paste controls'); var copy_btn = d.createElement ('button'); copy_btn.className = 'pk_btn icon-files-empty pk_inact'; From dec66334633ba76fe95946ed5b718b9e6eca84d3 Mon Sep 17 00:00:00 2001 From: Lloydi Date: Sun, 19 Jul 2020 23:07:22 +0100 Subject: [PATCH 05/18] Removed maximum-scale restriction to allow users to zoom --- src/index-cache.html | 2 +- src/index.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/index-cache.html b/src/index-cache.html index b69183b..bc0e60a 100755 --- a/src/index-cache.html +++ b/src/index-cache.html @@ -5,7 +5,7 @@ - + diff --git a/src/index.html b/src/index.html index a1edbce..b8dd7e7 100755 --- a/src/index.html +++ b/src/index.html @@ -5,7 +5,7 @@ - + From b8d49772bfeb26e30bf7c99493273ea4633b5829 Mon Sep 17 00:00:00 2001 From: Lloydi Date: Sun, 19 Jul 2020 23:13:38 +0100 Subject: [PATCH 06/18] Made 'load sample' link accessible Changed wording (should avoid 'click here phrases', and link phrase now makes sense out of context ("load a sample audio file") --- src/ui.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ui.js b/src/ui.js index ae5c3f1..b0a8156 100755 --- a/src/ui.js +++ b/src/ui.js @@ -2022,9 +2022,9 @@ // change temp message, it's pretty ugly #### TODO var ttmp = d.createElement('div'); ttmp.className = 'pk_tmpMsg'; - ttmp.innerHTML = 'Drag n drop an Audio File in this window, or click ' + - 'here to use a sample'; + ttmp.innerHTML = 'Drag n drop an Audio File in this window, or ' + + 'load a sample audio file'; main_audio_view.appendChild( ttmp ); var ttmp2 = d.createElement('div'); From 5a2d30cc9dca04f385f631275d61ed62cf113a60 Mon Sep 17 00:00:00 2001 From: Lloydi Date: Sun, 19 Jul 2020 23:20:57 +0100 Subject: [PATCH 07/18] Dialog naming fixes --- src/modal.js | 3 +++ src/welcome.js | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/modal.js b/src/modal.js index 856616c..701d52a 100755 --- a/src/modal.js +++ b/src/modal.js @@ -24,6 +24,9 @@ // var centerer var el_cont = d.createElement ('div'); el_cont.className = 'pk_modal_cnt'; + el_cont.setAttribute('role','dialog'); + el_cont.setAttribute('aria-labelledby','dialogHeading'); + el_cont.setAttribute('aria-describedby','dialogContent'); this.el_cont = el_cont; // title diff --git a/src/welcome.js b/src/welcome.js index e9a5206..c037a37 100755 --- a/src/welcome.js +++ b/src/welcome.js @@ -20,12 +20,12 @@ setTimeout(function () { // Welcome to AudioMass, var md = new PKSimpleModal({ - title: 'Welcome to AudioMass', + title: 'Welcome to AudioMass', ondestroy: function( q ) { PKAE.ui.InteractionHandler.on = false; PKAE.ui.KeyHandler.removeCallback ('modalTemp'); }, - body:'
'+ + body:'
'+ 'AudioMass is a free, open source, web-based Audio and Waveform Editor.
It runs entirely in the browser with no backend and no plugins required!'+ '


'+ body_str+ From dcc4d1b49df2e635e7092a923e48892773fe1aa7 Mon Sep 17 00:00:00 2001 From: Lloydi Date: Mon, 20 Jul 2020 00:29:56 +0100 Subject: [PATCH 08/18] Added focus styles for all main controls Doubled up on all hover styles with :focus equivalent Added new styles for all .pk_btn buttons --- src/main.css | 46 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 35 insertions(+), 11 deletions(-) diff --git a/src/main.css b/src/main.css index f7bd7d8..7197b60 100755 --- a/src/main.css +++ b/src/main.css @@ -73,7 +73,8 @@ body,html{height:100%;background:#111; white-space:nowrap } -.pk_hdr .pk_btn:hover{ +.pk_hdr .pk_btn:hover, +.pk_hdr .pk_btn:focus-within{ background:#eee; color:#111 } @@ -630,7 +631,7 @@ a{cursor:pointer;color:#99c2c6;-webkit-tap-highlight-color:rgba(0,0,0,0)} box-shadow: 0 2px 12px rgba(138, 58, 138, 0.5); background-clip: padding-box; } -.pk_contextMenu a, .pk_contextMenu a:hover{ +.pk_contextMenu a, .pk_contextMenu a:hover, .pk_contextMenu a:focus{ clear: both; color: #eee; display: block; @@ -645,7 +646,8 @@ a{cursor:pointer;color:#99c2c6;-webkit-tap-highlight-color:rgba(0,0,0,0)} font-weight:normal; transition: all 110ms; } -.pk_contextMenu a:hover{ +.pk_contextMenu a:hover, +.pk_contextMenu a:focus{ color:#99c2c6; line-height: 18px; text-decoration: none; @@ -936,7 +938,8 @@ a{cursor:pointer;color:#99c2c6;-webkit-tap-highlight-color:rgba(0,0,0,0)} -webkit-user-select:none; user-select:none; } -.pk_modal_a_bottom:hover{ +.pk_modal_a_bottom:hover, +.pk_modal_a_bottom:focus{ /*background: #eee; color: #111; border-color: #eee;*/ @@ -958,7 +961,8 @@ a{cursor:pointer;color:#99c2c6;-webkit-tap-highlight-color:rgba(0,0,0,0)} transition: background 120ms; } -.pk_modal_cancel:hover{ +.pk_modal_cancel:hover, +.pk_modal_cancel:focus{ box-shadow: 0 0 6px rgba(158, 39, 39, 0.6); border-color: unset; background: #280a0ac7; @@ -970,7 +974,8 @@ a{cursor:pointer;color:#99c2c6;-webkit-tap-highlight-color:rgba(0,0,0,0)} transition: border-color 120ms, color 120ms; } -.pk_modal_a_accpt:hover{ +.pk_modal_a_accpt:hover, +.pk_modal_a_accpt:focus{ color: #99c2c6; } @@ -1153,7 +1158,8 @@ a{cursor:pointer;color:#99c2c6;-webkit-tap-highlight-color:rgba(0,0,0,0)} letter-spacing: normal; } -.pk_sel_edt:hover > span{ +.pk_sel_edt:hover > span, +.pk_sel_edt:focus > span{ visibility:visible; opacity: 1; } @@ -1666,7 +1672,8 @@ input.pk_horiz.pk_w180{ transition:background 120ms; } -.pk_pgeq_els:hover{ +.pk_pgeq_els:hover, +.pk_pgeq_els:focus{ background:#3b413f; } @@ -1821,7 +1828,8 @@ body.pk_stndln{ background:#303030; } -.pk_tbsa:hover{ +.pk_tbsa:hover, +.pk_tbsa:focus{ box-shadow: inset 0 -2px 6px #181818; } @@ -1894,7 +1902,8 @@ body.pk_stndln{ transition: background 70ms; } -#pk_tmp_tap3:hover{ +#pk_tmp_tap3:hover, +#pk_tmp_tap3:focus{ background:#363636; } @@ -1930,7 +1939,8 @@ body.pk_stndln{ padding-right:5px; } -.pk_lcldrf:hover{ +.pk_lcldrf:hover, +.pk_lcldrf:focus{ background:#292929; } @@ -1987,3 +1997,17 @@ body.pk_stndln{ .pk_aut{ box-shadow: 0px 0px 20px #eee, inset 0px 0px 4px gold; } + +/* a11y fixes */ +* .pk_btn, +.pk_pan_btn:focus { + border:3px solid #333; + transition-duration: 0.2s; +} +* .pk_btn:focus, +.pk_pan_btn:focus { + border:3px solid black; + color:black; + background: white; + box-shadow: 0 0 0 2px #fff; +} \ No newline at end of file From 8ca8cb0f608d1822d1a55aa33d7d1bc4c8a902fa Mon Sep 17 00:00:00 2001 From: Lloydi Date: Mon, 20 Jul 2020 00:44:34 +0100 Subject: [PATCH 09/18] Used aria-label instead of aria-labelledby --- src/ui.js | 60 +++++++++++++++++++++++++++---------------------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/src/ui.js b/src/ui.js index b0a8156..a0f2606 100755 --- a/src/ui.js +++ b/src/ui.js @@ -2054,8 +2054,8 @@ function _makeUIToolbar (UI) { var container = d.createElement ( 'div' ); container.className = 'pk_tbc'; - container.setAttribute('role','toolbar'); - container.setAttribute('aria-label','Main tools'); + container.setAttribute('role','region'); + container.setAttribute('aria-label','Main toolbar'); var toolbar = d.createElement ( 'div' ); toolbar.className = 'pk_tb pk_noselect'; @@ -2070,8 +2070,8 @@ // play button var btn_stop = d.createElement ('button'); - btn_stop.innerHTML = 'Stop Playback (Space)'; - btn_stop.setAttribute('aria-labelledby','btn_stop_label'); + btn_stop.innerHTML = 'Stop Playback (Space)'; + btn_stop.setAttribute('aria-label','Stop Playback (Space)'); btn_stop.className = 'pk_btn pk_stop icon-stop2'; btn_stop.onclick = function() { UI.fireEvent('RequestStop'); @@ -2080,8 +2080,8 @@ var btn_play = d.createElement ('button'); btn_play.className = 'pk_btn pk_play icon-play3'; - btn_play.innerHTML = 'Play (Space)'; - btn_play.setAttribute('aria-labelledby','btn_play_label'); + btn_play.innerHTML = 'Play (Space)'; + btn_play.setAttribute('aria-label','Play (Space)'); transport.appendChild ( btn_play ); btn_play.onclick = function() { UI.fireEvent('RequestPlay'); @@ -2096,8 +2096,8 @@ var btn_pause = d.createElement ('button'); btn_pause.className = 'pk_btn pk_pause icon-pause2'; - btn_pause.innerHTML = 'Pause (Shift+Space)'; - btn_pause.setAttribute('aria-labelledby','btn_pause_label'); + btn_pause.innerHTML = 'Pause (Shift+Space)'; + btn_pause.setAttribute('aria-label','Pause (Shift+Space)'); transport.appendChild ( btn_pause ); btn_pause.onclick = function() { UI.fireEvent('RequestPause'); @@ -2106,8 +2106,8 @@ var btn_loop = d.createElement ('button'); btn_loop.className = 'pk_btn pk_loop icon-loop'; - btn_loop.innerHTML = 'Toggle Loop (L)'; - btn_loop.setAttribute('aria-labelledby','btn_loop_label'); + btn_loop.innerHTML = 'Toggle Loop (L)'; + btn_loop.setAttribute('aria-label','Toggle Loop (L)'); transport.appendChild ( btn_loop ); btn_loop.onclick = function() { UI.fireEvent('RequestSetLoop'); @@ -2120,8 +2120,8 @@ var btn_back_jump = d.createElement ('button'); btn_back_jump.className = 'pk_btn pk_back_jump icon-backward2'; - btn_back_jump.innerHTML = 'Seek (left arrow)'; - btn_back_jump.setAttribute('aria-labelledby','btn_back_jump_label'); + btn_back_jump.innerHTML = 'Seek (left arrow)'; + btn_back_jump.setAttribute('aria-label','Seek (left arrow)'); transport.appendChild ( btn_back_jump ); /////////////////////////////////////////////////////////// @@ -2200,8 +2200,8 @@ var btn_front_jump = d.createElement ('button'); btn_front_jump.className = 'pk_btn pk_front_jump icon-forward3'; - btn_front_jump.innerHTML = 'Seek (right arrow)'; - btn_front_jump.setAttribute('aria-labelledby','btn_front_jump_label'); + btn_front_jump.innerHTML = 'Seek (right arrow)'; + btn_front_jump.setAttribute('aria-label','Seek (right arrow)'); transport.appendChild ( btn_front_jump ); var btn_frnt_focus = false; @@ -2392,8 +2392,8 @@ var btn_back_total = d.createElement ('button'); btn_back_total.className = 'pk_btn icon-previous2'; - btn_back_total.innerHTML = 'Seek Start (Shift + left arrow)'; - btn_back_total.setAttribute('aria-labelledby','btn_back_total_label'); + btn_back_total.innerHTML = 'Seek Start (Shift + left arrow)'; + btn_back_total.setAttribute('aria-label','Seek Start (Shift + left arrow)'); transport.appendChild ( btn_back_total ); btn_back_total.onclick = function() { UI.fireEvent( 'RequestRegionClear'); @@ -2403,8 +2403,8 @@ var btn_front_total = d.createElement ('button'); btn_front_total.className = 'pk_btn icon-next2'; - btn_front_total.innerHTML = 'Seek End (Shift + right arrow)'; - btn_front_total.setAttribute('aria-labelledby','btn_front_total_label'); + btn_front_total.innerHTML = 'Seek End (Shift + right arrow)'; + btn_front_total.setAttribute('aria-label','Seek End (Shift + right arrow)'); btn_front_total.onclick = function() { UI.fireEvent( 'RequestRegionClear'); UI.fireEvent( 'RequestSeekTo', 0.996); @@ -2415,8 +2415,8 @@ var btn_rec = d.createElement ('button'); btn_rec.className = 'pk_btn icon-rec'; - btn_rec.innerHTML = 'Record (R)'; - btn_rec.setAttribute('aria-labelledby','btn_rec_label'); + btn_rec.innerHTML = 'Record (R)'; + btn_rec.setAttribute('aria-label','Record (R)'); btn_rec.onclick = function() { if (this.getAttribute('disabled') === 'disabled') { this.blur (); return ; @@ -2692,8 +2692,8 @@ var copy_btn = d.createElement ('button'); copy_btn.className = 'pk_btn icon-files-empty pk_inact'; - copy_btn.innerHTML = 'Copy Selection (Shift + C)'; - copy_btn.setAttribute('aria-labelledby','copy_btn_label'); + copy_btn.innerHTML = 'Copy Selection (Shift + C)'; + copy_btn.setAttribute('aria-label','Copy Selection (Shift + C)'); actions.appendChild ( copy_btn ); copy_btn.onclick = function() { @@ -2711,8 +2711,8 @@ var paste_btn = d.createElement ('button'); paste_btn.setAttribute('focusable', 'false'); paste_btn.className = 'pk_btn icon-file-text2 pk_inact'; - paste_btn.innerHTML = 'Paste Selection (Shift + V)'; - paste_btn.setAttribute('aria-labelledby','paste_btn_label'); + paste_btn.innerHTML = 'Paste Selection (Shift + V)'; + paste_btn.setAttribute('aria-label','Paste Selection (Shift + V)'); actions.appendChild ( paste_btn ); paste_btn.onclick = function() { @@ -2722,8 +2722,8 @@ var cut_btn = d.createElement ('button'); cut_btn.className = 'pk_btn icon-scissors pk_inact'; - cut_btn.innerHTML = 'Cut Selection (Shift + X)'; - cut_btn.setAttribute('aria-labelledby','cut_btn_label'); + cut_btn.innerHTML = 'Cut Selection (Shift + X)'; + cut_btn.setAttribute('aria-label','Cut Selection (Shift + X)'); actions.appendChild ( cut_btn ); cut_btn.onclick = function() { @@ -2733,8 +2733,8 @@ var silence_btn = d.createElement ('button'); silence_btn.className = 'pk_btn icon-silence'; - silence_btn.innerHTML = 'Insert Silence (Shift + N)'; - silence_btn.setAttribute('aria-labelledby','silence_btn_label'); + silence_btn.innerHTML = 'Insert Silence (Shift + N)'; + silence_btn.setAttribute('aria-label','Insert Silence (Shift + N)'); actions.appendChild ( silence_btn ); UI.KeyHandler.addCallback ('KeyShiftN', function( k ) { @@ -2763,8 +2763,8 @@ var btn_clear_selection = d.createElement ('button'); btn_clear_selection.className = 'pk_btn icon-clearsel pk_inact'; - btn_clear_selection.innerHTML = 'Clear Selection (~ tilda)'; - btn_clear_selection.setAttribute('aria-labelledby','btn_clear_selection_label'); + btn_clear_selection.innerHTML = 'Clear Selection (~ tilda)'; + btn_clear_selection.setAttribute('aria-label','Clear Selection (~ tilda)'); var sel_spans = selection.getElementsByClassName('pk_dat'); UI.listenFor ('DidCreateRegion', function ( region ) { From 50886c3b5eed9072327d2854f2fd50097fa3fccb Mon Sep 17 00:00:00 2001 From: Lloydi Date: Mon, 20 Jul 2020 00:44:56 +0100 Subject: [PATCH 10/18] Slight fix for global focus style --- src/main.css | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/main.css b/src/main.css index 7197b60..c2ed7a2 100755 --- a/src/main.css +++ b/src/main.css @@ -1999,9 +1999,7 @@ body.pk_stndln{ } /* a11y fixes */ -* .pk_btn, -.pk_pan_btn:focus { - border:3px solid #333; +* .pk_btn{ transition-duration: 0.2s; } * .pk_btn:focus, From ef0092132ddbe2ce54f07ed6f980bafab9bf557a Mon Sep 17 00:00:00 2001 From: Lloydi Date: Mon, 20 Jul 2020 09:40:30 +0100 Subject: [PATCH 11/18] Added a skip link to main toolbar that appears on keyboard focus --- src/index-cache.html | 3 +++ src/index.html | 3 +++ src/main.css | 34 +++++++++++++++++++++++++++++++++- src/ui.js | 2 ++ 4 files changed, 41 insertions(+), 1 deletion(-) diff --git a/src/index-cache.html b/src/index-cache.html index bc0e60a..a14cf1c 100755 --- a/src/index-cache.html +++ b/src/index-cache.html @@ -29,6 +29,9 @@ + + +
diff --git a/src/index.html b/src/index.html index b8dd7e7..5146ac4 100755 --- a/src/index.html +++ b/src/index.html @@ -30,6 +30,9 @@ + + +
diff --git a/src/main.css b/src/main.css index c2ed7a2..8cede87 100755 --- a/src/main.css +++ b/src/main.css @@ -1999,7 +1999,39 @@ body.pk_stndln{ } /* a11y fixes */ -* .pk_btn{ + +/*for skip links*/ +.skip { + height: 1px; + overflow: hidden; + position: absolute; + white-space: nowrap; + width: 1px; + left:-10px; +} +a.skip:focus { + clip: none; + height: auto; + overflow: none; + width: auto; + background: black; + color:white; + font-weight: bold; + font-size: 22px; + padding: 10px; + z-index: 1000; + top: 30px; + left: 15px; + border: 2px solid white; + border-radius: 3px; + outline: none; +} +#skipToolbar:focus { + outline: 2px solid white; +} + +* .pk_btn, .pk_pan_btn { + cursor: pointer; transition-duration: 0.2s; } * .pk_btn:focus, diff --git a/src/ui.js b/src/ui.js index a0f2606..05c0021 100755 --- a/src/ui.js +++ b/src/ui.js @@ -2059,6 +2059,8 @@ var toolbar = d.createElement ( 'div' ); toolbar.className = 'pk_tb pk_noselect'; + toolbar.setAttribute('tabindex','0'); + toolbar.setAttribute('id','skipToolbar'); var btn_groups = d.createElement( 'div' ); btn_groups.className = 'pk_btngroup'; From c42cb40bfb2b07ae9a61f4641f372f37d1455235 Mon Sep 17 00:00:00 2001 From: Lloydi Date: Mon, 20 Jul 2020 09:41:54 +0100 Subject: [PATCH 12/18] Update tabindex to toolbar to -1 --- src/ui.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ui.js b/src/ui.js index 05c0021..80f3585 100755 --- a/src/ui.js +++ b/src/ui.js @@ -2059,7 +2059,7 @@ var toolbar = d.createElement ( 'div' ); toolbar.className = 'pk_tb pk_noselect'; - toolbar.setAttribute('tabindex','0'); + toolbar.setAttribute('tabindex','-1'); toolbar.setAttribute('id','skipToolbar'); var btn_groups = d.createElement( 'div' ); From 2587ebe95850479dfdb227865fc2e171b18ee82b Mon Sep 17 00:00:00 2001 From: Lloydi Date: Mon, 20 Jul 2020 09:48:18 +0100 Subject: [PATCH 13/18] More tweaks to dialog Set focus on OK button on load Changed link phrase for Githib so link makes sanes out of context --- src/modal.js | 1 + src/welcome.js | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/modal.js b/src/modal.js index 701d52a..dae73c1 100755 --- a/src/modal.js +++ b/src/modal.js @@ -25,6 +25,7 @@ var el_cont = d.createElement ('div'); el_cont.className = 'pk_modal_cnt'; el_cont.setAttribute('role','dialog'); + el_cont.setAttribute('aria-modal','true'); el_cont.setAttribute('aria-labelledby','dialogHeading'); el_cont.setAttribute('aria-describedby','dialogContent'); this.el_cont = el_cont; diff --git a/src/welcome.js b/src/welcome.js index c037a37..4e2c229 100755 --- a/src/welcome.js +++ b/src/welcome.js @@ -15,7 +15,7 @@ setTimeout(function () { } else { body_str = 'Tips:
Please keep in mind that most key shortcuts rely on the Shift + key combo. (eg Shift+Z for undo, Shift+C copy, Shift+X cut... etc )

'; - body_str2 = 'Check out the codebase on Github

'; // checkout the code on github + body_str2 = 'Check out the codebase on Github

'; // checkout the code on github } // Welcome to AudioMass, @@ -52,7 +52,9 @@ setTimeout(function () { } }); md.Show (); + document.getElementsByClassName('pk_modal_cancel')[0].innerHTML = '      OK      '; + document.getElementsByClassName('pk_modal_cancel')[0].focus(); }; var change = 96; From 4c900cf1ed6c984b4ed1314c39db22274def0e5b Mon Sep 17 00:00:00 2001 From: Lloydi Date: Mon, 20 Jul 2020 10:10:12 +0100 Subject: [PATCH 14/18] Alt attribute for phone switch --- src/welcome.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/welcome.js b/src/welcome.js index 4e2c229..cc32262 100755 --- a/src/welcome.js +++ b/src/welcome.js @@ -10,7 +10,7 @@ setTimeout(function () { if (PKAE.isMobile) { change -= 15; body_str = 'Tips:
Please make sure your device is not in silent mode. You might need to physically flip the silent switch. '+ - ''+ + 'Phone silent mode switch'+ '

'; } else { From 6f8eea30348012318fc0c9d609cc8bcbe59f1d29 Mon Sep 17 00:00:00 2001 From: Lloydi Date: Mon, 20 Jul 2020 10:24:07 +0100 Subject: [PATCH 15/18] Added alt attributes for images in About page --- src/about.html | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/about.html b/src/about.html index 357438b..0f6a086 100755 --- a/src/about.html +++ b/src/about.html @@ -104,13 +104,13 @@

Introducing AudioMass (https://audiomass.co) an open-source web based audio and waveform editing tool.

- +Screenshot of AudioMass with parametric EQ options visible

AudioMass lets you record, or use your existing audio tracks, and modify them by trimming, cutting, pasting or applying a plethora of effects, from compression and paragraphic equalizers to reverb, delay and distortion fx. AudioMass also supports more than 20 hotkeys combinations and a dynamic responsive interface to ensure ease of use and that your producivity remains high. it is written solely in plain old-school javascript, weights approximately 65kb and has no backend or framework dependencies.

- +AudioMass shown running on multiple devices

It also has very good browser and device support.

@@ -146,21 +146,21 @@

Getting Started

To get started, drag and drop an audio file, or try the included sample.
Once the file is loaded and you can view the waveform, zoom in, pan around, or select a region.

- +Screenshot of selected audio

Recording Audio

To record audio, simply press the Recording button, or the [R] key.

- +Screenshot of recording in progress

Exporting to mp3

In order to export back to mp3, click on 'File', then 'Export to mp3', and follow the modal's instructions.

- +Export MP3 screenshot
@@ -177,11 +177,11 @@

The story behind AudioMass. And a short rant on web interfaces.

In general I am a big fan of the interfaces of DAWs (Digital Audio Workstations), they are extremely, complex, intricate, versatile, and they manage to remain visually pleasant even through their infinite options and knobs. Many times I feel the web has taken a very wrong turn, as amazing interfaces such as...

Sonar

- +Sonar screenshot

Fruity loops

- +Fruity loops screenshot
From 2cf2e55a2c5ad630fb8f1cd7110a11e0d9de5630 Mon Sep 17 00:00:00 2001 From: Lloydi Date: Mon, 20 Jul 2020 11:37:41 +0100 Subject: [PATCH 16/18] Set role to application --- src/index-cache.html | 2 +- src/index.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/index-cache.html b/src/index-cache.html index a14cf1c..d5ac293 100755 --- a/src/index-cache.html +++ b/src/index-cache.html @@ -32,7 +32,7 @@ -
+
diff --git a/src/index.html b/src/index.html index 5146ac4..3af18b1 100755 --- a/src/index.html +++ b/src/index.html @@ -33,7 +33,7 @@ -
+
From ac409e8b7fe88bc0ec73f76b2dd4b4f4a30328ec Mon Sep 17 00:00:00 2001 From: Lloydi Date: Mon, 20 Jul 2020 11:39:33 +0100 Subject: [PATCH 17/18] Making a start on creating a global button state function --- src/ui.js | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/ui.js b/src/ui.js index 80f3585..49bc656 100755 --- a/src/ui.js +++ b/src/ui.js @@ -2723,7 +2723,8 @@ }; var cut_btn = d.createElement ('button'); - cut_btn.className = 'pk_btn icon-scissors pk_inact'; + cut_btn.className = 'pk_btn icon-scissors'; + _setButtonActiveState(cut_btn,'inactive'); cut_btn.innerHTML = 'Cut Selection (Shift + X)'; cut_btn.setAttribute('aria-label','Cut Selection (Shift + X)'); actions.appendChild ( cut_btn ); @@ -2842,6 +2843,18 @@ // - }; + function _setButtonActiveState(button,state) { + if (state==="active") { + button.removeAttribute('tabindex'); + button.classList.remove('pk_inact'); + } else { + button.setAttribute('tabindex','-1'); + button.classList.add('pk_inact'); + } + } + + + function _makeMobileScroll (UI) { var getFactor = function () { From 2921d766e79deea88757f77c82d58c48682f4b20 Mon Sep 17 00:00:00 2001 From: Lloydi Date: Mon, 20 Jul 2020 11:40:13 +0100 Subject: [PATCH 18/18] Making a start on creating a global button state function --- src/fx-pg-eq.js | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/src/fx-pg-eq.js b/src/fx-pg-eq.js index 8c5cea6..6e906bd 100755 --- a/src/fx-pg-eq.js +++ b/src/fx-pg-eq.js @@ -1615,8 +1615,10 @@ }; if (!PKAudioEditor.engine.wavesurfer.isReady) { - play_btn.className += ' pk_inact'; - both_btn.className += ' pk_inact'; + // play_btn.className += ' pk_inact'; + _setButtonState(play_btn,'inactive'); + // both_btn.className += ' pk_inact'; + _setButtonState(both_btn,'inactive'); } if (PKAudioEditor.engine.wavesurfer.isPlaying()) { @@ -1865,8 +1867,10 @@ if (!PKAudioEditor.engine.wavesurfer.isReady) { - play_btn.className += ' pk_inact'; - loop_btn.className += ' pk_inact'; + // play_btn.className += ' pk_inact'; + _setButtonState(play_btn,'inactive'); + // loop_btn.className += ' pk_inact'; + _setButtonState(loop_btn,'inactive'); } if (PKAudioEditor.engine.wavesurfer.isPlaying()) { play_btn.className += ' pk_act'; @@ -2877,14 +2881,16 @@ } is_ready = true; - btn_start.classList.remove ('pk_inact'); + // btn_start.classList.remove ('pk_inact'); + _setButtonState(btn_start,'active'); }); } else { devices_sel.parentNode.style.display = 'none'; has_devices = false; is_ready = true; - btn_start.classList.remove ('pk_inact'); + // btn_start.classList.remove ('pk_inact'); + _setButtonState(btn_start,'active'); } }; @@ -2934,7 +2940,8 @@ if (is_active) { stop (); - btn_pause.classList.add ('pk_inact'); + // btn_pause.classList.add ('pk_inact'); + _setButtonState(btn_pause,'inactive'); btn_start.innerText = 'START RECORDING'; return ; @@ -2969,7 +2976,8 @@ script_processor.connect ( audio_context.destination ); is_active = true; - btn_pause.classList.remove ('pk_inact'); + // btn_pause.classList.remove ('pk_inact'); + _setButtonState(btn_pause,'active'); btn_start.innerText = 'FINISH RECORDING'; script_processor.onaudioprocess = fetchBufferFunction;