From 10a851e835e96b2c69ef3d245b99a5df319b1dfe Mon Sep 17 00:00:00 2001 From: daria Date: Fri, 10 May 2024 15:24:09 +0300 Subject: [PATCH 01/25] fix modal focus #1205 --- www/common/common-interface.js | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/www/common/common-interface.js b/www/common/common-interface.js index e34037d30..47c09e1ea 100644 --- a/www/common/common-interface.js +++ b/www/common/common-interface.js @@ -564,6 +564,33 @@ define([ setTimeout(function () { Notifier.notify(); }); + + $(frame).on('keydown', function(e) { + if (e.which === 9) { + e.preventDefault(); + + const modalElements = $(frame).find('a, button, input, [tabindex]:not([tabindex="-1"])').filter(':visible'); + const length = modalElements.length; + const firstElement = modalElements[0]; + const lastElement = modalElements[length - 1]; + + if (e.shiftKey) { + if (document.activeElement === firstElement) { + lastElement.focus(); + } else { + const currentIndex = modalElements.index(document.activeElement); + modalElements[currentIndex - 1].focus(); + } + } else { + if (document.activeElement === lastElement) { + firstElement.focus(); + } else { + const currentIndex = modalElements.index(document.activeElement); + modalElements[currentIndex + 1].focus(); + } + } + } + }); return frame; }; From 678aeed39531a9feb8484f16e5d778f34057f44d Mon Sep 17 00:00:00 2001 From: daria Date: Mon, 20 May 2024 18:33:17 +0300 Subject: [PATCH 02/25] modal focus starts on the first available element #1205 --- www/common/common-interface.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/www/common/common-interface.js b/www/common/common-interface.js index 47c09e1ea..d26d7456b 100644 --- a/www/common/common-interface.js +++ b/www/common/common-interface.js @@ -565,11 +565,12 @@ define([ Notifier.notify(); }); + const modalElements = $(frame).find('a, button, input, [tabindex]:not([tabindex="-1"])').filter(':visible'); + modalElements[0].focus(); + $(frame).on('keydown', function(e) { if (e.which === 9) { e.preventDefault(); - - const modalElements = $(frame).find('a, button, input, [tabindex]:not([tabindex="-1"])').filter(':visible'); const length = modalElements.length; const firstElement = modalElements[0]; const lastElement = modalElements[length - 1]; From 8bccd57e4546b0552b34cf7fd885096eebbf019b Mon Sep 17 00:00:00 2001 From: daria Date: Mon, 20 May 2024 18:48:54 +0300 Subject: [PATCH 03/25] fix focus order inside kanban item modal #1205 --- www/common/common-interface.js | 1 - 1 file changed, 1 deletion(-) diff --git a/www/common/common-interface.js b/www/common/common-interface.js index d26d7456b..ae759670b 100644 --- a/www/common/common-interface.js +++ b/www/common/common-interface.js @@ -330,7 +330,6 @@ define([ if (isEdit) { $button.find('span').text(Messages.tag_edit); } else { $button.find('span').text(Messages.add); } $container.append($form); - $input.focus(); isEdit = false; called = false; }); From 30bcacf40d8c37eceecdf4047c1d866606cd8728 Mon Sep 17 00:00:00 2001 From: daria Date: Wed, 29 May 2024 18:15:44 +0300 Subject: [PATCH 04/25] edit item modals (kanban) are keyboard accessible --- www/common/common-interface.js | 72 +++++++++++++++++++++++++++------- www/kanban/inner.js | 2 +- 2 files changed, 58 insertions(+), 16 deletions(-) diff --git a/www/common/common-interface.js b/www/common/common-interface.js index ae759670b..3668ed553 100644 --- a/www/common/common-interface.js +++ b/www/common/common-interface.js @@ -327,6 +327,7 @@ define([ } $form.append($input); $form.append($button); + $button.attr('tabindex', '-1'); if (isEdit) { $button.find('span').text(Messages.tag_edit); } else { $button.find('span').text(Messages.add); } $container.append($form); @@ -567,26 +568,67 @@ define([ const modalElements = $(frame).find('a, button, input, [tabindex]:not([tabindex="-1"])').filter(':visible'); modalElements[0].focus(); + let insideColorButtons = false; $(frame).on('keydown', function(e) { - if (e.which === 9) { - e.preventDefault(); - const length = modalElements.length; - const firstElement = modalElements[0]; - const lastElement = modalElements[length - 1]; + const colors = $('#cp-kanban-edit-colors button:visible'); - if (e.shiftKey) { - if (document.activeElement === firstElement) { - lastElement.focus(); + const currentActiveElement = document.activeElement; + const currentActiveIndex = colors.index(currentActiveElement); + + if (currentActiveIndex !== -1) { + insideColorButtons = true; + + if (e.which === 37) { + e.preventDefault(); + if (currentActiveIndex > 0) { + colors.index(currentActiveIndex - 1).focus(); } else { - const currentIndex = modalElements.index(document.activeElement); - modalElements[currentIndex - 1].focus(); + colors.last().focus(); } - } else { - if (document.activeElement === lastElement) { - firstElement.focus(); + } + + else if (e.which === 39) { + e.preventDefault(); + if (currentActiveIndex < colors.length - 1) { + colors.index(currentActiveIndex + 1).focus(); } else { - const currentIndex = modalElements.index(document.activeElement); - modalElements[currentIndex + 1].focus(); + colors.first().focus(); + } + } + + else if (e.shiftKey && e.which === 9) { + e.preventDefault(); + $(frame).find('input:visible').last().focus(); + insideColorButtons = false; + } + + else if (e.which === 9) { + e.preventDefault(); + $(frame).find('.cp-button-confirm-placeholder:visible').first().focus(); + insideColorButtons = false; + } + } + else{ + if (e.which === 9 && !insideColorButtons) { + e.preventDefault(); + console.log(modalElements); + const firstElement = modalElements.first()[0]; + const lastElement = modalElements.last()[0]; + + if (e.shiftKey) { + if (currentActiveElement === firstElement) { + lastElement.focus(); + } else { + const currentIndex = modalElements.index(currentActiveElement); + modalElements.get(currentIndex - 1).focus(); + } + } else { + if (currentActiveElement === lastElement) { + firstElement.focus(); + } else { + const currentIndex = modalElements.index(currentActiveElement); + modalElements.get(currentIndex + 1).focus(); + } } } } diff --git a/www/kanban/inner.js b/www/kanban/inner.js index e3579e952..9bb5dd515 100644 --- a/www/kanban/inner.js +++ b/www/kanban/inner.js @@ -378,7 +378,7 @@ define([ }); }; palette.forEach(function (color) { - var $color = $(h('span.cp-kanban-palette.fa')); + var $color = $(h('button.cp-kanban-palette.fa')); $color.addClass('cp-kanban-palette-'+(color || 'nocolor')); $color.click(function () { if (offline) { return; } From 6a5439229dd929f928a05f6655eb4c76d0479f03 Mon Sep 17 00:00:00 2001 From: daria Date: Thu, 30 May 2024 15:15:12 +0300 Subject: [PATCH 05/25] fix modal bugs - delete button from kanban modals can be accessed with the keyboard - share/access elements are accessible (WIP) --- www/common/common-interface.js | 53 ++++++++++++++++++-------------- www/common/common-ui-elements.js | 1 + 2 files changed, 31 insertions(+), 23 deletions(-) diff --git a/www/common/common-interface.js b/www/common/common-interface.js index 3668ed553..9afc534f0 100644 --- a/www/common/common-interface.js +++ b/www/common/common-interface.js @@ -240,22 +240,25 @@ define([ if (!(tab.content || tab.disabled) || !tab.title) { return; } var content = h('div.alertify-tabs-content', tab.content); var title = h('span.alertify-tabs-title'+ (tab.disabled ? '.disabled' : ''), h('span.tab-title-text',{id: 'cp-tab-' + tab.title.toLowerCase(), 'aria-hidden':"true"}, tab.title)); + $(title).attr('tabindex', '0'); if (tab.icon) { var icon = h('i', {class: tab.icon, 'aria-labelledby': 'cp-tab-' + tab.title.toLowerCase()}); $(title).prepend(' ').prepend(icon); } - $(title).click(function () { - if (tab.disabled) { return; } - var old = tabs[active]; - if (old.onHide) { old.onHide(); } - titles.forEach(function (t) { $(t).removeClass('alertify-tabs-active'); }); - contents.forEach(function (c) { $(c).removeClass('alertify-tabs-content-active'); }); - if (tab.onShow) { - tab.onShow(); + $(title).on('click keydown', function (event) { + if (event.type === 'click' || (event.type === 'keydown' && event.key === 'Enter')) { + if (tab.disabled) { return; } + var old = tabs[active]; + if (old.onHide) { old.onHide(); } + titles.forEach(function (t) { $(t).removeClass('alertify-tabs-active'); }); + contents.forEach(function (c) { $(c).removeClass('alertify-tabs-content-active'); }); + if (tab.onShow) { + tab.onShow(); + } + $(title).addClass('alertify-tabs-active'); + $(content).addClass('alertify-tabs-content-active'); + active = i; } - $(title).addClass('alertify-tabs-active'); - $(content).addClass('alertify-tabs-content-active'); - active = i; }); titles.push(title); contents.push(content); @@ -486,7 +489,7 @@ define([ var navs = []; buttons.forEach(function (b) { if (!b.name || !b.onClick) { return; } - var button = h('button', { tabindex: '1', 'class': b.className || '' }, [ + var button = h('button', { 'class': b.className || '' }, [ b.iconClass ? h('i' + b.iconClass) : undefined, b.name ]); @@ -565,15 +568,15 @@ define([ Notifier.notify(); }); - const modalElements = $(frame).find('a, button, input, [tabindex]:not([tabindex="-1"])').filter(':visible'); + let modalElements = $(frame).find('a, button, input, [tabindex]:not([tabindex="-1"]), textarea').filter(':visible'); modalElements[0].focus(); let insideColorButtons = false; $(frame).on('keydown', function(e) { const colors = $('#cp-kanban-edit-colors button:visible'); - const currentActiveElement = document.activeElement; const currentActiveIndex = colors.index(currentActiveElement); + modalElements = $(frame).find('a, button, input, [tabindex]:not([tabindex="-1"]), textarea').filter(':visible'); // for modals with dynamic content if (currentActiveIndex !== -1) { insideColorButtons = true; @@ -581,7 +584,7 @@ define([ if (e.which === 37) { e.preventDefault(); if (currentActiveIndex > 0) { - colors.index(currentActiveIndex - 1).focus(); + colors.eq(currentActiveIndex - 1).focus(); } else { colors.last().focus(); } @@ -590,7 +593,7 @@ define([ else if (e.which === 39) { e.preventDefault(); if (currentActiveIndex < colors.length - 1) { - colors.index(currentActiveIndex + 1).focus(); + colors.eq(currentActiveIndex + 1).focus(); } else { colors.first().focus(); } @@ -884,15 +887,19 @@ define([ }; var newCls2 = config.new ? 'new' : ''; - $(originalBtn).addClass('cp-button-confirm-placeholder').addClass(newCls2).click(function (e) { - e.stopPropagation(); - // If we have a validation function, continue only if it's true - if (config.validate && !config.validate()) { return; } - i = 1; - to = setTimeout(todo, INTERVAL); - $(originalBtn).hide().after(content); + $(originalBtn).addClass('cp-button-confirm-placeholder').addClass(newCls2).on('click keydown', function (e) { + if (e.type === 'click' || (e.type === 'keydown' && e.key === 'Enter')) { + e.stopPropagation(); + // If we have a validation function, continue only if it's true + if (config.validate && !config.validate()) { return; } + i = 1; + to = setTimeout(todo, INTERVAL); + $(originalBtn).hide().after(content); + $(button).focus(); + } }); + return { reset: function () { done(false); diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index 537fb89de..e16512069 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -184,6 +184,7 @@ define([ 'data-curve': data.curvePublic || '', 'data-name': name.toLowerCase(), 'data-order': i, + 'tabindex': '0', style: 'order:'+i+';' },[ avatar, From c95dce73583a3c878044d5896013c437cf7c477f Mon Sep 17 00:00:00 2001 From: daria Date: Thu, 6 Jun 2024 19:02:46 +0300 Subject: [PATCH 06/25] change tick on selected color on kanban colors --- www/kanban/app-kanban.less | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/www/kanban/app-kanban.less b/www/kanban/app-kanban.less index 8d50f1e91..782f33d45 100644 --- a/www/kanban/app-kanban.less +++ b/www/kanban/app-kanban.less @@ -152,9 +152,13 @@ line-height: 30px; color: @cp_kanban-fg; border: 1px solid fade(@cp_kanban-fg, 40%); - &.fa-check { // tick on selected color + // tick on selected color + &.cp-kanban-palette-card.fa-check { color: @cryptpad_text_col; } + &.cp-kanban-palette-board.fa-check { + color: @cryptpad_text_col_inv; + } } } #cp-kanban-edit-tags { From f2f30a63a9b3fbe640ebe91d6f86049adee0bb20 Mon Sep 17 00:00:00 2001 From: daria Date: Thu, 6 Jun 2024 19:16:58 +0300 Subject: [PATCH 07/25] `+Add` can be accessed via keyboard in kanban modals --- www/common/common-interface.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/www/common/common-interface.js b/www/common/common-interface.js index 9afc534f0..9b1bf9623 100644 --- a/www/common/common-interface.js +++ b/www/common/common-interface.js @@ -330,7 +330,6 @@ define([ } $form.append($input); $form.append($button); - $button.attr('tabindex', '-1'); if (isEdit) { $button.find('span').text(Messages.tag_edit); } else { $button.find('span').text(Messages.add); } $container.append($form); @@ -601,7 +600,7 @@ define([ else if (e.shiftKey && e.which === 9) { e.preventDefault(); - $(frame).find('input:visible').last().focus(); + $(frame).find('input:visible, .btn-primary:visible').last().focus(); insideColorButtons = false; } From 3fa57d03119ce1844bc3ea30a2b915e671caa8bc Mon Sep 17 00:00:00 2001 From: daria Date: Thu, 6 Jun 2024 19:39:33 +0300 Subject: [PATCH 08/25] add focus style to kanban edit elements #1506 --- www/kanban/app-kanban.less | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/www/kanban/app-kanban.less b/www/kanban/app-kanban.less index 782f33d45..76ef51054 100644 --- a/www/kanban/app-kanban.less +++ b/www/kanban/app-kanban.less @@ -191,6 +191,11 @@ border: 0; background: transparent; align-self: flex-start; + outline-style: none; + border-radius: 5px; + &:focus { + outline: @cryptpad_color_brand solid 2px; + } @media (hover: none) { margin-right: 20px; } From 9f13370ba50cfcd5141885e19623ac08f38863bb Mon Sep 17 00:00:00 2001 From: daria Date: Thu, 6 Jun 2024 20:09:39 +0300 Subject: [PATCH 09/25] change focus style of buttons #1506 --- customize.dist/src/less2/include/forms.less | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/customize.dist/src/less2/include/forms.less b/customize.dist/src/less2/include/forms.less index 2f5777771..3c018e365 100644 --- a/customize.dist/src/less2/include/forms.less +++ b/customize.dist/src/less2/include/forms.less @@ -122,7 +122,6 @@ button.btn { background-color: @cp_buttons-cancel; box-sizing: border-box; - outline: 0; align-items: center; padding: 0 6px; line-height: 36px; @@ -232,11 +231,9 @@ } - + outline: none; &:focus { - //border: 1px dotted @alertify-base; - box-shadow: 0px 0px 5px @cp_buttons-primary !important; - outline: none; + outline: @cryptpad_color_brand solid 2px; } &::-moz-focus-inner { border: 0; From db21bdfc601617ce4acc68a42257bb3f7a0f4acf Mon Sep 17 00:00:00 2001 From: daria Date: Thu, 6 Jun 2024 20:21:12 +0300 Subject: [PATCH 10/25] add focus style for inputs inside modals #1506 --- customize.dist/src/less2/include/alertify.less | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/customize.dist/src/less2/include/alertify.less b/customize.dist/src/less2/include/alertify.less index f01e69a37..0b5e7dfb9 100644 --- a/customize.dist/src/less2/include/alertify.less +++ b/customize.dist/src/less2/include/alertify.less @@ -263,6 +263,10 @@ input { .tools_placeholder-color(); + outline: none; + &:focus-visible { + outline: @cryptpad_color_brand solid 2px; + } } span.cp-password-container { From 2fd586923e1e61bab73fda774854681e450ebc41 Mon Sep 17 00:00:00 2001 From: daria Date: Thu, 6 Jun 2024 20:28:41 +0300 Subject: [PATCH 11/25] add focus style for color picker inside kanban modals #1506 --- www/kanban/app-kanban.less | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/www/kanban/app-kanban.less b/www/kanban/app-kanban.less index 76ef51054..15458e2b4 100644 --- a/www/kanban/app-kanban.less +++ b/www/kanban/app-kanban.less @@ -152,6 +152,7 @@ line-height: 30px; color: @cp_kanban-fg; border: 1px solid fade(@cp_kanban-fg, 40%); + outline: none; // tick on selected color &.cp-kanban-palette-card.fa-check { color: @cryptpad_text_col; @@ -159,6 +160,9 @@ &.cp-kanban-palette-board.fa-check { color: @cryptpad_text_col_inv; } + &:focus{ + outline: @cryptpad_color_brand solid 2px; + } } } #cp-kanban-edit-tags { From 8ab32b7862ea0f325855279275593d911c148534 Mon Sep 17 00:00:00 2001 From: daria Date: Thu, 6 Jun 2024 20:54:08 +0300 Subject: [PATCH 12/25] add focus style for checkmarks + Add/Share modals elements #1506 --- customize.dist/src/less2/include/alertify.less | 10 ++++++++++ customize.dist/src/less2/include/checkmark.less | 8 ++++---- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/customize.dist/src/less2/include/alertify.less b/customize.dist/src/less2/include/alertify.less index 0b5e7dfb9..e41177d81 100644 --- a/customize.dist/src/less2/include/alertify.less +++ b/customize.dist/src/less2/include/alertify.less @@ -198,6 +198,12 @@ text-decoration: none; } } + .cp-usergrid-user, textarea { + outline: none; + &:focus { + outline: @cryptpad_color_brand solid 2px; + } + } } .cp-alertify-type-container { overflow: visible !important; @@ -237,6 +243,10 @@ } } } + outline: none; + &:focus { + outline: @cryptpad_color_brand solid 2px; + } } span.alertify-tabs-active { background-color: @cp_alertify-fg !important; diff --git a/customize.dist/src/less2/include/checkmark.less b/customize.dist/src/less2/include/checkmark.less index 723f4297a..18e2c4ac9 100644 --- a/customize.dist/src/less2/include/checkmark.less +++ b/customize.dist/src/less2/include/checkmark.less @@ -128,9 +128,9 @@ position: absolute; box-sizing: border-box; } + outline: none; &:focus { - box-shadow: 0px 0px 5px @cp_checkmark-back1; - outline: none; + outline: @cryptpad_color_brand solid 2px; } } @@ -216,9 +216,9 @@ height: @checkmark-dim1; height: var(--checkmark-dim1); } + outline: none; &:focus { - box-shadow: 0px 0px 5px @cp_checkmark-back1; - outline: none; + outline: @cryptpad_color_brand solid 2px; } } From bee0d6128ff5e61a11ab00f7c7da3c0ce7d2b451 Mon Sep 17 00:00:00 2001 From: daria Date: Thu, 6 Jun 2024 20:57:51 +0300 Subject: [PATCH 13/25] add focus style for links in modals #1506 --- customize.dist/src/less2/include/alertify.less | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/customize.dist/src/less2/include/alertify.less b/customize.dist/src/less2/include/alertify.less index e41177d81..3a432ddd3 100644 --- a/customize.dist/src/less2/include/alertify.less +++ b/customize.dist/src/less2/include/alertify.less @@ -198,7 +198,7 @@ text-decoration: none; } } - .cp-usergrid-user, textarea { + .cp-usergrid-user, textarea, a { outline: none; &:focus { outline: @cryptpad_color_brand solid 2px; From 408f81864122f716025cb64a768e9d4da7f76d8d Mon Sep 17 00:00:00 2001 From: daria Date: Fri, 7 Jun 2024 13:43:32 +0300 Subject: [PATCH 14/25] Access rights checkmarks can be accessed via keyboard --- www/common/common-interface.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/www/common/common-interface.js b/www/common/common-interface.js index 9b1bf9623..fd876f052 100644 --- a/www/common/common-interface.js +++ b/www/common/common-interface.js @@ -1342,7 +1342,7 @@ define([ $(mark).keydown(function (e) { if ($input.is(':disabled')) { return; } - if (e.which === 32) { + if (e.which === 13 || e.which === 32) { e.stopPropagation(); e.preventDefault(); if ($input.is(':checked')) { return; } From 189a673da78dd591910ad20843255de93e45ed6b Mon Sep 17 00:00:00 2001 From: daria Date: Fri, 7 Jun 2024 13:57:56 +0300 Subject: [PATCH 15/25] Share modal is accessible using the keyboard --- www/common/common-interface.js | 4 +++- www/common/common-ui-elements.js | 7 +++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/www/common/common-interface.js b/www/common/common-interface.js index fd876f052..0fd0b2aad 100644 --- a/www/common/common-interface.js +++ b/www/common/common-interface.js @@ -247,6 +247,8 @@ define([ } $(title).on('click keydown', function (event) { if (event.type === 'click' || (event.type === 'keydown' && event.key === 'Enter')) { + event.preventDefault(); + event.stopPropagation(); if (tab.disabled) { return; } var old = tabs[active]; if (old.onHide) { old.onHide(); } @@ -1291,7 +1293,7 @@ define([ $mark.keydown(function (e) { if ($input.is(':disabled')) { return; } - if (e.which === 32) { + if (e.which === 32 || e.which === 13){ e.stopPropagation(); e.preventDefault(); $input.prop('checked', !$input.is(':checked')); diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index e16512069..f40459ea6 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -232,6 +232,13 @@ define([ } onSelect(); }); + $div.on('keydown', '.cp-usergrid-user', function (e) { + if (e.which === 13) { + e.preventDefault(); + e.stopPropagation(); + $(this).trigger('click'); + } + }); } return { From 0365fdf31d5f9bf4d8b821642ea32caa628220a7 Mon Sep 17 00:00:00 2001 From: daria Date: Mon, 17 Jun 2024 15:45:37 +0300 Subject: [PATCH 16/25] remove focus from Access modal elements (when overlay is applied) --- www/common/inner/access.js | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/www/common/inner/access.js b/www/common/inner/access.js index de171f116..b8cab7a6b 100644 --- a/www/common/inner/access.js +++ b/www/common/inner/access.js @@ -367,6 +367,13 @@ define([ UI.log(Messages.saved); }); }); + $(addBtn).on('keydown', function () { + if (event.keyCode === 13) { + event.preventDefault(); + event.stopPropagation(); + $(addBtn).click(); + } + }); var called = false; redrawAll = function (reload) { @@ -459,6 +466,8 @@ define([ var setLock = function (locked) { $(link).find('.cp-overlay').toggle(locked); + $(link).find('.cp-usergrid-user').attr('tabindex', locked ? -1 : 0); + $(link).find('.cp-access-add').attr('tabindex', locked ? -1 : 0); }; // Remove owner column @@ -714,6 +723,13 @@ define([ UI.log(Messages.saved); }); }); + $(addBtn).on('keydown', function () { + if (event.keyCode === 13) { + event.preventDefault(); + event.stopPropagation(); + $(addBtn).click(); + } + }); var called = false; redrawAll = function (reload) { @@ -1025,6 +1041,13 @@ define([ }); }); }); + $(passwordOk).on('keydown', function (e) { + if (e.keyCode === 13) { + e.preventDefault(); + e.stopPropagation(); + $(passwordOk).click(); + } + }); $d.append(changePass); } if (owned) { From f202a617d090426add39a64b34ce12dc382cc013 Mon Sep 17 00:00:00 2001 From: daria Date: Mon, 17 Jun 2024 16:19:57 +0300 Subject: [PATCH 17/25] remove focus from Access modal input (when overlay is applied) --- www/common/inner/access.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/www/common/inner/access.js b/www/common/inner/access.js index b8cab7a6b..1082b86f5 100644 --- a/www/common/inner/access.js +++ b/www/common/inner/access.js @@ -467,7 +467,8 @@ define([ var setLock = function (locked) { $(link).find('.cp-overlay').toggle(locked); $(link).find('.cp-usergrid-user').attr('tabindex', locked ? -1 : 0); - $(link).find('.cp-access-add').attr('tabindex', locked ? -1 : 0); + $(link).find('.cp-usergrid-filter input').attr('tabindex', locked ? -1 : 0); //tbd + $(link).find('.cp-access-add').attr('tabindex', locked ? -1 : 0); //tbd }; // Remove owner column From f24bbacd0ba8c3dd53dba49b0d742e95ee3f9e2c Mon Sep 17 00:00:00 2001 From: daria Date: Fri, 21 Jun 2024 12:07:40 +0300 Subject: [PATCH 18/25] add focus to remove user button --- customize.dist/src/less2/include/alertify.less | 2 +- customize.dist/src/less2/include/toolbar.less | 2 +- customize.dist/src/less2/include/usergrid.less | 3 ++- www/common/common-interface.js | 1 - www/common/common-ui-elements.js | 7 +++++-- www/kanban/app-kanban.less | 2 +- 6 files changed, 10 insertions(+), 7 deletions(-) diff --git a/customize.dist/src/less2/include/alertify.less b/customize.dist/src/less2/include/alertify.less index 3a432ddd3..9d97d82d4 100644 --- a/customize.dist/src/less2/include/alertify.less +++ b/customize.dist/src/less2/include/alertify.less @@ -198,7 +198,7 @@ text-decoration: none; } } - .cp-usergrid-user, textarea, a { + .cp-usergrid-user, textarea, a, .fa-times { outline: none; &:focus { outline: @cryptpad_color_brand solid 2px; diff --git a/customize.dist/src/less2/include/toolbar.less b/customize.dist/src/less2/include/toolbar.less index 05111c6b0..e47b8757c 100644 --- a/customize.dist/src/less2/include/toolbar.less +++ b/customize.dist/src/less2/include/toolbar.less @@ -774,7 +774,7 @@ padding: 10px; color: @toolbar-bg-color; color: var(--toolbar-bg-color); - border-radius: 5px; + border-radius: @variables_radius; span { font-size: 45px; diff --git a/customize.dist/src/less2/include/usergrid.less b/customize.dist/src/less2/include/usergrid.less index 475f9cde1..bfddc84a3 100644 --- a/customize.dist/src/less2/include/usergrid.less +++ b/customize.dist/src/less2/include/usergrid.less @@ -115,7 +115,8 @@ } } .fa-times { - padding-left: 5px; + border-radius: @variables_radius; + margin-left: 5px; cursor: pointer; height: 100%; line-height: 25px; diff --git a/www/common/common-interface.js b/www/common/common-interface.js index 0fd0b2aad..e26be89aa 100644 --- a/www/common/common-interface.js +++ b/www/common/common-interface.js @@ -615,7 +615,6 @@ define([ else{ if (e.which === 9 && !insideColorButtons) { e.preventDefault(); - console.log(modalElements); const firstElement = modalElements.first()[0]; const lastElement = modalElements.last()[0]; diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index f40459ea6..69cf56543 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -173,8 +173,11 @@ define([ var removeBtn, el; if (config.remove) { removeBtn = h('span.fa.fa-times'); - $(removeBtn).click(function () { - config.remove(el); + $(removeBtn).attr('tabindex', '0'); + $(removeBtn).on('click keydown', function(event) { + if (event.type === 'click' || (event.type === 'keydown' && event.key === 'Enter')) { + config.remove(el); + } }); } diff --git a/www/kanban/app-kanban.less b/www/kanban/app-kanban.less index 15458e2b4..fe33693d3 100644 --- a/www/kanban/app-kanban.less +++ b/www/kanban/app-kanban.less @@ -196,7 +196,7 @@ background: transparent; align-self: flex-start; outline-style: none; - border-radius: 5px; + border-radius: @variables_radius; &:focus { outline: @cryptpad_color_brand solid 2px; } From 79cbd8fc320c84a0565e02fcdfea73fdf495dc9d Mon Sep 17 00:00:00 2001 From: daria Date: Fri, 21 Jun 2024 13:19:53 +0300 Subject: [PATCH 19/25] fix confirmation modal focus #1205 --- www/common/common-interface.js | 32 +++++++++++++++++++++++++++++++- www/common/common-ui-elements.js | 1 + 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/www/common/common-interface.js b/www/common/common-interface.js index e26be89aa..070fc9bd6 100644 --- a/www/common/common-interface.js +++ b/www/common/common-interface.js @@ -814,13 +814,43 @@ define([ var $ok = $(ok).click(function (ev) { close(true, ev); }); var $cancel = $(cancel).click(function (ev) { close(false, ev); }); + document.body.appendChild(frame); + + var modalElements = $(frame).find('a, button, input, [tabindex]:not([tabindex="-1"]), textarea').filter(':visible'); + if (modalElements.length > 0) { + modalElements[0].focus(); + frame.addEventListener('keydown', function(e) { + if (e.keyCode === 9) { + if (e.shiftKey) { + if (document.activeElement === modalElements[0]) { + e.preventDefault(); + modalElements[modalElements.length - 1].focus(); + } + } else { + if (document.activeElement === modalElements[modalElements.length - 1]) { + e.preventDefault(); + modalElements[0].focus(); + } + } + } + else if (e.keyCode === 13) { + if (document.activeElement === $ok[0]) { + $ok.click(); + } else if (document.activeElement === $cancel[0]) { + $cancel.click(); + } + } else if (e.keyCode === 27) { + $cancel.click(); + } + }); + } + listener = listenForKeys(function () { $ok.click(); }, function () { $cancel.click(); }, frame); - document.body.appendChild(frame); setTimeout(function () { Notifier.notify(); $(frame).find('.ok').focus(); diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index 69cf56543..3c2699595 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -176,6 +176,7 @@ define([ $(removeBtn).attr('tabindex', '0'); $(removeBtn).on('click keydown', function(event) { if (event.type === 'click' || (event.type === 'keydown' && event.key === 'Enter')) { + event.preventDefault(); config.remove(el); } }); From bb62932048973f89b9959c9e09c51d347406cc6b Mon Sep 17 00:00:00 2001 From: daria Date: Fri, 21 Jun 2024 13:33:02 +0300 Subject: [PATCH 20/25] leave modal open when choosing a color on kanban modals --- www/kanban/inner.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/www/kanban/inner.js b/www/kanban/inner.js index 9bb5dd515..ed93a4f53 100644 --- a/www/kanban/inner.js +++ b/www/kanban/inner.js @@ -380,6 +380,13 @@ define([ palette.forEach(function (color) { var $color = $(h('button.cp-kanban-palette.fa')); $color.addClass('cp-kanban-palette-'+(color || 'nocolor')); + $color.keydown(function (e) { + if (e.which === 13) { + e.stopPropagation(); + e.preventDefault(); + $color.click(); + } + }); $color.click(function () { if (offline) { return; } if (color === selectedColor) { return; } From 938bda919ad2df7db52e677811bcf3912e45af34 Mon Sep 17 00:00:00 2001 From: daria Date: Fri, 21 Jun 2024 14:49:29 +0300 Subject: [PATCH 21/25] buttons on Contact Request Modal are keyboard accessible --- www/common/common-interface.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/www/common/common-interface.js b/www/common/common-interface.js index 070fc9bd6..2129d75f0 100644 --- a/www/common/common-interface.js +++ b/www/common/common-interface.js @@ -513,6 +513,13 @@ define([ divClasses: 'left' }, todo); } else { + $(button).keydown(function (e) { + if (e.which === 13) { + e.preventDefault(); + e.stopPropagation(); + todo(); + } + }); $(button).click(function () { todo(); }); From 3c4786a8a6abc6be2d3bed58416ad5141e45eaa9 Mon Sep 17 00:00:00 2001 From: yflory Date: Fri, 21 Jun 2024 18:29:54 +0200 Subject: [PATCH 22/25] Fix CodeMirror focus issue --- www/common/sframe-common-codemirror.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/www/common/sframe-common-codemirror.js b/www/common/sframe-common-codemirror.js index 2e84c2d11..aa1bde788 100644 --- a/www/common/sframe-common-codemirror.js +++ b/www/common/sframe-common-codemirror.js @@ -178,8 +178,7 @@ define([ }, //remove focus from editor "Esc": function () { - document.activeElement.blur(); - document.querySelector('.cp-toolbar-link-logo').focus(); + editor.display.input.blur(); }, "Shift-Tab": function () { editor.execCommand("indentLess"); From 9401f617ce6474a2527fe065ce0a4544994efae0 Mon Sep 17 00:00:00 2001 From: yflory Date: Fri, 21 Jun 2024 18:00:59 +0200 Subject: [PATCH 23/25] Fix access modal button not disabled --- www/common/inner/access.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/www/common/inner/access.js b/www/common/inner/access.js index 1082b86f5..9159aac93 100644 --- a/www/common/inner/access.js +++ b/www/common/inner/access.js @@ -467,8 +467,8 @@ define([ var setLock = function (locked) { $(link).find('.cp-overlay').toggle(locked); $(link).find('.cp-usergrid-user').attr('tabindex', locked ? -1 : 0); - $(link).find('.cp-usergrid-filter input').attr('tabindex', locked ? -1 : 0); //tbd - $(link).find('.cp-access-add').attr('tabindex', locked ? -1 : 0); //tbd + $(link).find('.cp-usergrid-filter input').prop('disabled', locked); + $(link).find('.cp-access-add').prop('disabled', locked); }; // Remove owner column From 00b0830f24369d025f543db559d1bad58d8d0247 Mon Sep 17 00:00:00 2001 From: yflory Date: Fri, 21 Jun 2024 18:01:56 +0200 Subject: [PATCH 24/25] Deduplicate some code --- www/common/common-interface.js | 39 ++++++++++++++-------------------- 1 file changed, 16 insertions(+), 23 deletions(-) diff --git a/www/common/common-interface.js b/www/common/common-interface.js index 2129d75f0..58db4396c 100644 --- a/www/common/common-interface.js +++ b/www/common/common-interface.js @@ -245,22 +245,21 @@ define([ var icon = h('i', {class: tab.icon, 'aria-labelledby': 'cp-tab-' + tab.title.toLowerCase()}); $(title).prepend(' ').prepend(icon); } - $(title).on('click keydown', function (event) { - if (event.type === 'click' || (event.type === 'keydown' && event.key === 'Enter')) { - event.preventDefault(); - event.stopPropagation(); - if (tab.disabled) { return; } - var old = tabs[active]; - if (old.onHide) { old.onHide(); } - titles.forEach(function (t) { $(t).removeClass('alertify-tabs-active'); }); - contents.forEach(function (c) { $(c).removeClass('alertify-tabs-content-active'); }); - if (tab.onShow) { - tab.onShow(); - } - $(title).addClass('alertify-tabs-active'); - $(content).addClass('alertify-tabs-content-active'); - active = i; + + Util.onClickEnter($(title), function (event) { + event.preventDefault(); + event.stopPropagation(); + if (tab.disabled) { return; } + var old = tabs[active]; + if (old.onHide) { old.onHide(); } + titles.forEach(function (t) { $(t).removeClass('alertify-tabs-active'); }); + contents.forEach(function (c) { $(c).removeClass('alertify-tabs-content-active'); }); + if (tab.onShow) { + tab.onShow(); } + $(title).addClass('alertify-tabs-active'); + $(content).addClass('alertify-tabs-content-active'); + active = i; }); titles.push(title); contents.push(content); @@ -513,14 +512,8 @@ define([ divClasses: 'left' }, todo); } else { - $(button).keydown(function (e) { - if (e.which === 13) { - e.preventDefault(); - e.stopPropagation(); - todo(); - } - }); - $(button).click(function () { + Util.onClickEnter($(button), function (e) { + e.stopPropagation(); todo(); }); } From 94585f745e25d000063e563cd2abc80f50aeb6f3 Mon Sep 17 00:00:00 2001 From: yflory Date: Fri, 21 Jun 2024 18:28:27 +0200 Subject: [PATCH 25/25] Deduplicate code and remvoe kanban-specific code from common --- www/common/common-interface.js | 132 ++++++++++----------------------- 1 file changed, 40 insertions(+), 92 deletions(-) diff --git a/www/common/common-interface.js b/www/common/common-interface.js index 58db4396c..6a9c66c5b 100644 --- a/www/common/common-interface.js +++ b/www/common/common-interface.js @@ -552,6 +552,34 @@ define([ if (opt.forefront) { $(frame).addClass('forefront'); } return frame; }; + + let addTabListener = frame => { + // find focusable elements + let modalElements = $(frame).find('a, button, input, [tabindex]:not([tabindex="-1"]), textarea').filter(':visible'); + // intialize with focus on first element + modalElements[0].focus(); + + $(frame).on('keydown', function (e) { + modalElements = $(frame).find('a, button, input, [tabindex]:not([tabindex="-1"]), textarea').filter(':visible'); // for modals with dynamic content + + if (e.which === 9) { // Tab + if (e.shiftKey) { + // On the first element, shift+tab goes to last + if (document.activeElement === modalElements[0]) { + e.preventDefault(); + modalElements[modalElements.length - 1].focus(); + } + } else { + // On the last element, tab goes to first + if (document.activeElement === modalElements[modalElements.length - 1]) { + e.preventDefault(); + modalElements[0].focus(); + } + } + } + }); + + }; UI.openCustomModal = function (content, opt) { var frame = dialog.frame([ content @@ -569,73 +597,8 @@ define([ Notifier.notify(); }); - let modalElements = $(frame).find('a, button, input, [tabindex]:not([tabindex="-1"]), textarea').filter(':visible'); - modalElements[0].focus(); + addTabListener(frame); - let insideColorButtons = false; - $(frame).on('keydown', function(e) { - const colors = $('#cp-kanban-edit-colors button:visible'); - const currentActiveElement = document.activeElement; - const currentActiveIndex = colors.index(currentActiveElement); - modalElements = $(frame).find('a, button, input, [tabindex]:not([tabindex="-1"]), textarea').filter(':visible'); // for modals with dynamic content - - if (currentActiveIndex !== -1) { - insideColorButtons = true; - - if (e.which === 37) { - e.preventDefault(); - if (currentActiveIndex > 0) { - colors.eq(currentActiveIndex - 1).focus(); - } else { - colors.last().focus(); - } - } - - else if (e.which === 39) { - e.preventDefault(); - if (currentActiveIndex < colors.length - 1) { - colors.eq(currentActiveIndex + 1).focus(); - } else { - colors.first().focus(); - } - } - - else if (e.shiftKey && e.which === 9) { - e.preventDefault(); - $(frame).find('input:visible, .btn-primary:visible').last().focus(); - insideColorButtons = false; - } - - else if (e.which === 9) { - e.preventDefault(); - $(frame).find('.cp-button-confirm-placeholder:visible').first().focus(); - insideColorButtons = false; - } - } - else{ - if (e.which === 9 && !insideColorButtons) { - e.preventDefault(); - const firstElement = modalElements.first()[0]; - const lastElement = modalElements.last()[0]; - - if (e.shiftKey) { - if (currentActiveElement === firstElement) { - lastElement.focus(); - } else { - const currentIndex = modalElements.index(currentActiveElement); - modalElements.get(currentIndex - 1).focus(); - } - } else { - if (currentActiveElement === lastElement) { - firstElement.focus(); - } else { - const currentIndex = modalElements.index(currentActiveElement); - modalElements.get(currentIndex + 1).focus(); - } - } - } - } - }); return frame; }; @@ -816,34 +779,19 @@ define([ document.body.appendChild(frame); - var modalElements = $(frame).find('a, button, input, [tabindex]:not([tabindex="-1"]), textarea').filter(':visible'); - if (modalElements.length > 0) { - modalElements[0].focus(); - frame.addEventListener('keydown', function(e) { - if (e.keyCode === 9) { - if (e.shiftKey) { - if (document.activeElement === modalElements[0]) { - e.preventDefault(); - modalElements[modalElements.length - 1].focus(); - } - } else { - if (document.activeElement === modalElements[modalElements.length - 1]) { - e.preventDefault(); - modalElements[0].focus(); - } - } - } - else if (e.keyCode === 13) { - if (document.activeElement === $ok[0]) { - $ok.click(); - } else if (document.activeElement === $cancel[0]) { - $cancel.click(); - } - } else if (e.keyCode === 27) { + addTabListener(frame); + + frame.addEventListener('keydown', function(e) { + if (e.keyCode === 13) { + if (document.activeElement === $ok[0]) { + $ok.click(); + } else if (document.activeElement === $cancel[0]) { $cancel.click(); } - }); - } + } else if (e.keyCode === 27) { + $cancel.click(); + } + }); listener = listenForKeys(function () { $ok.click();