Skip to content

Improved keyboard accessibility of the find-replace popup #1700

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Dec 11, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 11 additions & 9 deletions client/styles/components/_editor.scss
Original file line number Diff line number Diff line change
Expand Up @@ -121,14 +121,6 @@ pre.CodeMirror-line {
height: 100%;
}

.CodeMirror-find-div {
padding: 0;
display: flex;
justify-content: flex-start;
align-items: center;
flex-wrap: nowrap;
}

.CodeMirror-search-modifiers {
margin-left: #{10 / $base-font-size}rem;
}
Expand All @@ -142,12 +134,22 @@ pre.CodeMirror-line {
.CodeMirror-find-controls {
display: flex;
}

.CodeMirror-search-inputs {
width: 30%;
margin-left: 10px;
}
.CodeMirror-replace-div {
display: flex;
justify-content: flex-start;
align-items: center;
}
.CodeMirror-search-controls {
width: 60%;
display: flex;
flex-wrap: wrap-reverse;
justify-content: flex-start;
align-items: flex-end;
}
.CodeMirror-replace-controls {
display: flex;
margin-left: #{10 / $base-font-size}rem;
Expand Down
201 changes: 102 additions & 99 deletions client/utils/codemirror-search.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ function persistentDialog(cm, text, deflt, onEnter, replaceOpened, onKeyDown) {
var state = getSearchState(cm);

CodeMirror.on(searchField, "keyup", function (e) {
state.replaceStarted = false;
if (e.keyCode !== 13 && searchField.value.length > 1) { // not enter and more than 1 character to search
startSearch(cm, getSearchState(cm), searchField.value);
} else if (searchField.value.length < 1) {
Expand Down Expand Up @@ -154,30 +155,30 @@ function persistentDialog(cm, text, deflt, onEnter, replaceOpened, onKeyDown) {
}

function toggleReplace(open) {
var replaceDivHeightOpened = "45px", replaceDivHeightClosed = "0px";
var toggleButtonHeightOpened = "80px", toggleButtonHeightClosed = "40px";

if (open) {
replaceDiv.style.height = replaceDivHeightOpened;
replaceFieldDiv.style.display = replaceControlsDiv.style.display = '';
toggleReplaceBtnDiv.style.height = toggleButtonHeightOpened;
showReplaceButton.style.height = toggleButtonHeightOpened;
showReplaceButton.innerHTML = triangleArrowDown;
toggleReplaceBtn.style.height = toggleButtonHeightOpened;
toggleReplaceBtn.innerHTML = triangleArrowDown;
} else {
replaceDiv.style.height = replaceDivHeightClosed;
replaceFieldDiv.style.display = replaceControlsDiv.style.display = 'none';
toggleReplaceBtnDiv.style.height = toggleButtonHeightClosed;
showReplaceButton.style.height = toggleButtonHeightClosed;
showReplaceButton.innerHTML = triangleArrowRight;
toggleReplaceBtn.style.height = toggleButtonHeightClosed;
toggleReplaceBtn.innerHTML = triangleArrowRight;
}
}

var showReplaceButton = dialog.getElementsByClassName("CodeMirror-replace-toggle-button")[0];
var toggleReplaceBtnDiv = dialog.getElementsByClassName("Toggle-replace-btn-div")[0];
var replaceDiv = dialog.getElementsByClassName("CodeMirror-replace-div")[0];
var toggleReplaceBtnDiv = document.getElementById('Btn-Toggle-replace-div');
var toggleReplaceBtn = document.getElementById('Btn-Toggle-replace')
var replaceFieldDiv = document.getElementById('Replace-input-div');
var replaceControlsDiv = document.getElementById('Replace-controls-div');
if (replaceOpened) {
toggleReplace(true);
}
CodeMirror.on(showReplaceButton, "click", function () {
if (replaceDiv.style.height === "0px") {
CodeMirror.on(toggleReplaceBtn, "click", function () {
if (replaceFieldDiv.style.display === "none") {
toggleReplace(true);
} else {
toggleReplace(false);
Expand All @@ -186,10 +187,6 @@ function persistentDialog(cm, text, deflt, onEnter, replaceOpened, onKeyDown) {

var replaceField = document.getElementById('Replace-input-field');
CodeMirror.on(replaceField, "keyup", function (e) {
if (!searchField.value) {
searchField.focus();
return;
}
var state = getSearchState(cm);
var query = parseQuery(searchField.value, state);
var withText = parseString(replaceField.value);
Expand Down Expand Up @@ -232,13 +229,15 @@ function persistentDialog(cm, text, deflt, onEnter, replaceOpened, onKeyDown) {
if (match) {
cm.setSelection(cursor.from(), cursor.to());
doReplace(match, cursor, query, withText);
doReplaceButton.focus();
}
} else {
startSearch(cm, state, searchField.value);
state.replaceStarted = true;
cm.focus();
CodeMirror.commands.findNext(cm);
searchField.blur();
doReplaceButton.focus();
}
})

Expand All @@ -251,6 +250,9 @@ function persistentDialog(cm, text, deflt, onEnter, replaceOpened, onKeyDown) {
var state = getSearchState(cm);
var query = parseQuery(searchField.value, state);
var withText = parseString(replaceField.value);
if (searchField.value.length > 1) {
state.replaceStarted = true;
}
if (state.replaceStarted) {
replaceAll(cm, query, withText);
state.replaceStarted = false;
Expand Down Expand Up @@ -491,104 +493,105 @@ function replaceAll(cm, query, text) {
var getQueryDialog = function() {
return (`
<div class="CodeMirror-find-popup-container">
<div class="Toggle-replace-btn-div">
<div id="Btn-Toggle-replace-div" class="Toggle-replace-btn-div">
<button
title="${i18n.t('CodemirrorFindAndReplace.Replace')}"
aria-label="${i18n.t('CodemirrorFindAndReplace.Replace')}"
role="button"
title="${i18n.t('CodemirrorFindAndReplace.ToggleReplace')}"
aria-label="${i18n.t('CodemirrorFindAndReplace.ToggleReplace')}"
role="button" id="Btn-Toggle-replace"
class="CodeMirror-search-modifier-button CodeMirror-replace-toggle-button"
>
<span aria-hidden="true" class="button">
${triangleArrowRight}
</span>
</button>
</div>
<div class="CodeMirror-find-input-fields">
<div class="CodeMirror-find-div">
<div class="CodeMirror-find-input">
<input id="Find-input-field" type="text" class="search-input CodeMirror-search-field" placeholder="${i18n.t('CodemirrorFindAndReplace.FindPlaceholder')}" />
</div>
<div class="CodeMirror-find-controls">
<div class="CodeMirror-search-modifiers button-wrap">
<button
title="${i18n.t('CodemirrorFindAndReplace.Regex')}"
aria-label="${i18n.t('CodemirrorFindAndReplace.Regex')}"
role="checkbox"
class="CodeMirror-search-modifier-button CodeMirror-regexp-button"
>
<span aria-hidden="true" class="button">.*</span>
</button>
<button
title="${i18n.t('CodemirrorFindAndReplace.CaseSensitive')}"
aria-label="${i18n.t('CodemirrorFindAndReplace.CaseSensitive')}"
role="checkbox"
class="CodeMirror-search-modifier-button CodeMirror-case-button"
>
<span aria-hidden="true" class="button">Aa</span>
</button>
<button
title="${i18n.t('CodemirrorFindAndReplace.WholeWords')}"
aria-label="${i18n.t('CodemirrorFindAndReplace.WholeWords')}"
role="checkbox"
class="CodeMirror-search-modifier-button CodeMirror-word-button"
>
<span aria-hidden="true" class="button">" "</span>
</button>
</div>
<div class="CodeMirror-search-nav">
<p class="CodeMirror-search-results">${i18n.t('CodemirrorFindAndReplace.NoResults')}</p>
<button
title="${i18n.t('CodemirrorFindAndReplace.Previous')}"
aria-label="${i18n.t('CodemirrorFindAndReplace.Previous')}"
class="CodeMirror-search-button icon up-arrow prev"
>
<span aria-hidden="true">
${upArrow}
</span>
</button>
<button
title="${i18n.t('CodemirrorFindAndReplace.Next')}"
aria-label="${i18n.t('CodemirrorFindAndReplace.Next')}"
class="CodeMirror-search-button icon down-arrow next"
>
<span aria-hidden="true">
${downArrow}
</span>
</button>
</div>
<div class="CodeMirror-close-button-container">
<button
title="${i18n.t('CodemirrorFindAndReplace.Close')}"
aria-label="${i18n.t('CodemirrorFindAndReplace.Close')}"
class="CodeMirror-close-button close icon"
>
<span aria-hidden="true">
${exitIcon}
</span>
</button>
</div>
</div>
<div class="CodeMirror-search-inputs">
<div class="CodeMirror-find-input">
<input id="Find-input-field" type="text" class="search-input CodeMirror-search-field" placeholder="${i18n.t('CodemirrorFindAndReplace.FindPlaceholder')}" />
</div>
<div style="height: 0px; overflow: hidden;" class="CodeMirror-replace-div">
<div style="display: none;" id="Replace-input-div"
class="CodeMirror-replace-input">
<input id="Replace-input-field" type="text" placeholder="${i18n.t('CodemirrorFindAndReplace.ReplacePlaceholder')}" class="search-input CodeMirror-search-field"/>
<div class="CodeMirror-replace-controls">
</div>
</div>
<div class="CodeMirror-search-controls">
<div style="display: none;" id="Replace-controls-div" class="CodeMirror-replace-controls">
<button
title="${i18n.t('CodemirrorFindAndReplace.Replace')}"
aria-label="${i18n.t('CodemirrorFindAndReplace.Replace')}"
role="button"
id="Btn-replace"
class="CodeMirror-search-modifier-button CodeMirror-replace-button"
>
${i18n.t('CodemirrorFindAndReplace.Replace')}
</button>
<button
title="${i18n.t('CodemirrorFindAndReplace.ReplaceAll')}"
aria-label="${i18n.t('CodemirrorFindAndReplace.ReplaceAll')}"
role="button"
id="Btn-replace-all"
class="CodeMirror-search-modifier-button CodeMirror-replace-button"
>
${i18n.t('CodemirrorFindAndReplace.ReplaceAll')}
</button>
</div>
<div class="CodeMirror-find-controls">
<div class="CodeMirror-search-modifiers button-wrap">
<button
title="${i18n.t('CodemirrorFindAndReplace.Replace')}"
aria-label="${i18n.t('CodemirrorFindAndReplace.Replace')}"
role="button"
id="Btn-replace"
class="CodeMirror-search-modifier-button CodeMirror-replace-button"
title="${i18n.t('CodemirrorFindAndReplace.Regex')}"
aria-label="${i18n.t('CodemirrorFindAndReplace.Regex')}"
role="checkbox"
class="CodeMirror-search-modifier-button CodeMirror-regexp-button"
>
${i18n.t('CodemirrorFindAndReplace.Replace')}
<span aria-hidden="true" class="button">.*</span>
</button>
<button
title="${i18n.t('CodemirrorFindAndReplace.ReplaceAll')}"
aria-label="${i18n.t('CodemirrorFindAndReplace.ReplaceAll')}"
role="button"
id="Btn-replace-all"
class="CodeMirror-search-modifier-button CodeMirror-replace-button"
title="${i18n.t('CodemirrorFindAndReplace.CaseSensitive')}"
aria-label="${i18n.t('CodemirrorFindAndReplace.CaseSensitive')}"
role="checkbox"
class="CodeMirror-search-modifier-button CodeMirror-case-button"
>
<span aria-hidden="true" class="button">Aa</span>
</button>
<button
title="${i18n.t('CodemirrorFindAndReplace.WholeWords')}"
aria-label="${i18n.t('CodemirrorFindAndReplace.WholeWords')}"
role="checkbox"
class="CodeMirror-search-modifier-button CodeMirror-word-button"
>
<span aria-hidden="true" class="button">" "</span>
</button>
</div>
<div class="CodeMirror-search-nav">
<p class="CodeMirror-search-results">${i18n.t('CodemirrorFindAndReplace.NoResults')}</p>
<button
title="${i18n.t('CodemirrorFindAndReplace.Previous')}"
aria-label="${i18n.t('CodemirrorFindAndReplace.Previous')}"
class="CodeMirror-search-button icon up-arrow prev"
>
<span aria-hidden="true">
${upArrow}
</span>
</button>
<button
title="${i18n.t('CodemirrorFindAndReplace.Next')}"
aria-label="${i18n.t('CodemirrorFindAndReplace.Next')}"
class="CodeMirror-search-button icon down-arrow next"
>
<span aria-hidden="true">
${downArrow}
</span>
</button>
</div>
<div class="CodeMirror-close-button-container">
<button
title="${i18n.t('CodemirrorFindAndReplace.Close')}"
aria-label="${i18n.t('CodemirrorFindAndReplace.Close')}"
class="CodeMirror-close-button close icon"
>
${i18n.t('CodemirrorFindAndReplace.ReplaceAll')}
<span aria-hidden="true">
${exitIcon}
</span>
</button>
</div>
</div>
Expand Down
1 change: 1 addition & 0 deletions translations/locales/en-US/translations.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
}
},
"CodemirrorFindAndReplace": {
"ToggleReplace": "Toggle Replace",
"Find": "Find",
"FindPlaceholder": "Find in files",
"Replace": "Replace",
Expand Down
1 change: 1 addition & 0 deletions translations/locales/es-419/translations.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
}
},
"CodemirrorFindAndReplace": {
"ToggleReplace": "Alternar reemplazar",
"Find": "Buscar",
"FindPlaceholder": "Buscar en archivos",
"Replace": "Reemplazar",
Expand Down
1 change: 1 addition & 0 deletions translations/locales/ja/translations.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
}
},
"CodemirrorFindAndReplace": {
"ToggleReplace": "置換の切り替え",
"Find": "検索",
"FindPlaceholder": "ファイル内検索",
"Replace": "置換",
Expand Down