Skip to content

Commit

Permalink
feat: Add option to prevent keyboard focus trapping (#5114)
Browse files Browse the repository at this point in the history
* adds an option `enableKeyboardAccessibility` to `EditorOptions`, after setting this to `true` the editor will not trap focus. Press enter to enter the editor and escape to exit it.
  • Loading branch information
akoreman authored Apr 12, 2023
1 parent 5771031 commit fe5d1bf
Show file tree
Hide file tree
Showing 5 changed files with 95 additions and 0 deletions.
1 change: 1 addition & 0 deletions ace.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,7 @@ export namespace Ace {
value: string;
session: EditSession;
relativeLineNumbers: boolean;
enableKeyboardAccessibility: boolean;
}

export interface SearchOptions {
Expand Down
5 changes: 5 additions & 0 deletions src/css/editor.css.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,11 @@ module.exports = `
font-variant-ligatures: no-common-ligatures;
}
.ace_keyboard-focus:focus {
box-shadow: inset 0 0 0 2px #5E9ED6;
outline: none;
}
.ace_dragging .ace_scroller:before{
position: absolute;
top: 0;
Expand Down
48 changes: 48 additions & 0 deletions src/editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ var TokenIterator = require("./token_iterator").TokenIterator;
var LineWidgets = require("./line_widgets").LineWidgets;

var clipboard = require("./clipboard");
var keys = require('./lib/keys');

/**
* The main entry point into the Ace functionality.
Expand Down Expand Up @@ -2858,6 +2859,53 @@ config.defineOptions(Editor.prototype, "editor", {
this.$updatePlaceholder();
}
},
enableKeyboardAccessibility: {
set: function(value) {
var blurCommand = {
name: "blurTextInput",
description: "Set focus to the editor content div to allow tabbing through the page",
bindKey: "Esc",
exec: function(editor) {
editor.blur();
editor.renderer.content.focus();
},
readOnly: true
};

var focusOnEnterKeyup = function (e) {
if (e.target == this.renderer.content && e.keyCode === keys['enter']){
e.stopPropagation();
e.preventDefault();
this.focus();
}
};

var keyboardFocusClassName = "ace_keyboard-focus";

// Prevent focus to be captured when tabbing through the page. When focus is set to the content div,
// press Enter key to give focus to Ace and press Esc to again allow to tab through the page.
if (value){
this.textInput.getElement().setAttribute("tabindex", -1);
this.renderer.content.setAttribute("tabindex", 0);
this.renderer.content.classList.add(keyboardFocusClassName);
this.renderer.content.setAttribute("aria-label",
"Editor, press Enter key to start editing, press Escape key to exit"
);

this.renderer.content.addEventListener("keyup", focusOnEnterKeyup.bind(this));
this.commands.addCommand(blurCommand);
} else {
this.textInput.getElement().setAttribute("tabindex", 0);
this.renderer.content.setAttribute("tabindex", -1);
this.renderer.content.classList.remove(keyboardFocusClassName);
this.renderer.content.setAttribute("aria-label", "");

this.renderer.content.removeEventListener("keyup", focusOnEnterKeyup.bind(this));
this.commands.removeCommand(blurCommand);
}
},
initialValue: false
},
customScrollbar: "renderer",
hScrollBarAlwaysVisible: "renderer",
vScrollBarAlwaysVisible: "renderer",
Expand Down
38 changes: 38 additions & 0 deletions src/editor_navigation_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ if (typeof process !== "undefined") {
var EditSession = require("./edit_session").EditSession;
var Editor = require("./editor").Editor;
var MockRenderer = require("./test/mockrenderer").MockRenderer;
var VirtualRenderer = require("./virtual_renderer").VirtualRenderer;
var assert = require("./test/assertions");
var keys = require('./lib/keys');

module.exports = {
createEditSession : function(rows, cols) {
Expand Down Expand Up @@ -154,6 +156,42 @@ module.exports = {

editor.navigateDown();
assert.position(editor.getCursorPosition(), 1, 7);
},

"test: should allow to toggle between keyboard trapping modes": function() {
var editor = new Editor(new VirtualRenderer(), new EditSession(["1234", "1234567890"]));

// Should not trap focus
editor.setOption('enableKeyboardAccessibility', true);

// Focus on editor
editor.focus();

// Focus should be on textInput
assert.equal(document.activeElement, editor.textInput.getElement());
assert.notEqual(document.activeElement, editor.renderer.content);

editor.onCommandKey({}, 0, keys["escape"]);

// Focus should be on the content div after pressing Esc
assert.equal(document.activeElement, editor.renderer.content);
assert.notEqual(document.activeElement, editor.textInput.getElement());

// Should trap focus
editor.setOption('enableKeyboardAccessibility', false);

// Focus on editor
editor.focus();

// Focus should be on textInput
assert.equal(document.activeElement, editor.textInput.getElement());
assert.notEqual(document.activeElement, editor.renderer.content);

editor.onCommandKey({}, 0, keys["escape"]);

// Focus should still be on the textInput
assert.equal(document.activeElement, editor.textInput.getElement());
assert.notEqual(document.activeElement, editor.renderer.content);
}
};

Expand Down
3 changes: 3 additions & 0 deletions src/ext/options.js
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,9 @@ var optionGroups = {
},
"Use SVG gutter icons": {
path: "useSvgGutterIcons"
},
"Keyboard Accessibility Mode": {
path: "enableKeyboardAccessibility"
}
}
};
Expand Down

0 comments on commit fe5d1bf

Please sign in to comment.