-
Notifications
You must be signed in to change notification settings - Fork 426
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
ariaAttr support #206
Comments
Seems related to issue #87 |
Indeed. |
Yes, ARIA attributes are the most reliable way to tell the screen reader about an HTML element. All the screen readers rely on ARIA attributes and "role" to determine the element type and how to process them. Currently, If I tab through Slickgrid cells, screen readers don't read anything. With the changes in the another branch things appear to work fine (even narrator read properly). |
I worked around this by creating custom editor for cells and having aria properties over there. |
Great, could you possibly post a sample of the editor? |
For my scenario, I was just interested in aria-label (Screen reader will read this) and role attributes. Moving on to cell brings up the editor with element in focus, which screen reader recognizes and then reads it properly. The only issue that I had was, if editor is visible, onClick of slick grid was not working. So, handled this scenario separately from the editor itself. Here is the trimmed down version of my code. Slickgrid column definition: public columns = [
// tslint:disable-next-line:typedef no-any only-arrow-functions object-literal-shorthand
{
id: 'message', name: stringResources.Monitoring_ErrorLabel, field: 'message',
width: this.columnWidths[7], minWidth: 45, editable: true, editor: CustomEditor.bind(this, this.eventHandlers),
formatter: (_row: number, _column: number, value: string) => {
const messageIcon = (value) ? '<div id="runMessage" class="svg-i-16x16-comment"></div>' : '';
return '<div class="gridIcons">' + messageIcon + '</div>';
}
},
{
id: 'runId', name: stringResources.Monitoring_RunIDLabel, field: 'runId', width: this.columnWidths[8] + this.columnPadding,
minWidth: 45, editable: true, editor: CustomEditor.bind(this, this.eventHandlers),
formatter: (_row: number, _column: number, value: string) => {
return CustomEditor.getFormattedRunId(value);
}
}
] My custom editor: export class CustomEditor {
// tslint:disable-next-line:no-any
public args: any;
public focussableElements: NodeListOf<Element>;
public focussedElementIndex: number = -1;
public eventHandlers: { [eventKey: string]: (item: object, event: MouseEvent|KeyboardEvent) => void };
public static getFormattedMessage(message: string): string {
const messageIcon = (message) ? '<div id="runMessage" class="svg-i-16x16-comment" role="button" tabindex="0" title="'+ stringResources.Error +'"></div>' : '';
return '<div class="gridIcons">' + messageIcon + '</div>';
}
public static getFormattedRunId(id: string): string {
return '<div aria-label="' + stringResources.Monitoring_RunIDLabel + ' ' + id +'" tabindex="0">' + id + '</div>';
}
// tslint:disable-next-line:no-any
public constructor(handlers: any, args: any) {
// initialize the cell editor UI
if (!args || !args.container || !args.item || !args.column) {
return;
}
let divElement: HTMLElement;
this.args = args;
this.eventHandlers = handlers;
switch (args.column.id) {
case 'message':
divElement = this.createCellEditorContainer()
// tslint:disable-next-line:no-inner-html
divElement.innerHTML = CustomEditor.getFormattedMessage(args.item.message);
break;
case 'runId':
divElement = this.createCellEditorContainer('gridCellEditorContent')
// tslint:disable-next-line:no-inner-html
divElement.innerHTML = CustomEditor.getFormattedRunId(args.item.runId);
break;
default:
return;
}
this.args.container.appendChild(divElement);
this.focussableElements = this.args.container.querySelectorAll('[tabindex="0"]');
this.setNextFocus();
}
public createCellEditorContainer(cssClass?: string): HTMLElement {
let divElement = document.createElement('DIV');
if (cssClass) {
divElement.className = cssClass;
}
divElement.onkeydown = this.handleKeyDown.bind(this);
divElement.onclick = this.handleClick.bind(this);
return divElement;
}
public setNextFocus(): void {
if (this.focussableElements && this.focussableElements.length) {
this.focussedElementIndex = (this.focussedElementIndex + this.focussableElements.length + 1) % this.focussableElements.length;
const nextElement = this.focussableElements[this.focussedElementIndex] as HTMLElement;
if (nextElement) {
nextElement.focus();
}
}
}
public handleKeyDown(event: KeyboardEvent): void {
if (KeyboardUtils.IsKeyboardTabEvent(event)) {
this.setNextFocus();
event.preventDefault();
event.stopPropagation();
}
}
public handleClick(e: MouseEvent): void {
const handler = this.eventHandlers[(event.target as HTMLElement).id];
if (handler && this.args && this.args.item) {
handler(this.args.item as {}, event as MouseEvent);
}
}
/*********** REQUIRED METHODS ***********/
public destroy(): void {
// remove all data, events & dom elements created in the constructor
while (this.args && this.args.container && this.args.container.firstChild) {
this.args.container.removeChild(this.args.container.firstChild);
}
}
public focus(): void {
// set the focus on the main input control (if any)
}
public isValueChanged(): boolean {
// return true if the value(s) being edited by the user has/have been changed
return false;
}
public serializeValue(): string {
// return the value(s) being edited by the user in a serialized form
// can be an arbitrary object
// the only restriction is that it must be a simple object that can be passed around even
// when the editor itself has been destroyed
return '';
}
// tslint:disable-next-line:no-any
public loadValue(item: any): void {
// load the value(s) from the data item and update the UI
// this method will be called immediately after the editor is initialized
// it may also be called by the grid if if the row/cell being edited is updated via grid.updateRow/updateCell
}
// tslint:disable-next-line:no-any
public applyValue(item: any, state: any): void {
// deserialize the value(s) saved to "state" and apply them to the data item
// this method may get called after the editor itself has been destroyed
// treat it as an equivalent of a Java/C# "static" method - no instance variables should be accessed
}
// tslint:disable-next-line:no-any
public validate(): any {
// validate user input and return the result along with the validation message, if any
// if the input is valid, return {valid:true,msg:null}
}
} |
Hi,
I am trying to make slickgrid cells, screen-reader accessible.
ariaAttr support was added for this in another branch.
I dont think that change has merged over here, Is there a plan to get those changes?
Thanks,
The text was updated successfully, but these errors were encountered: