Skip to content

Commit

Permalink
table aria
Browse files Browse the repository at this point in the history
  • Loading branch information
juliaroldi committed Dec 20, 2024
1 parent 61f4923 commit 9415c68
Show file tree
Hide file tree
Showing 9 changed files with 192 additions and 0 deletions.
56 changes: 56 additions & 0 deletions demo/scripts/controlsV2/demoButtons/tableTitleButton.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { getFirstSelectedTable, mutateBlock } from 'roosterjs-content-model-dom';
import { IEditor } from 'roosterjs-content-model-types';
import { RibbonButton, showInputDialog } from 'roosterjs-react';

/**
* @internal
* "Image Border Style" button on the format ribbon
*/
export const tableTitleButton: RibbonButton<'buttonNameTableTitle'> = {
key: 'buttonNameTableTitle',
unlocalizedText: 'Table Title',
iconName: 'TableComputed',
isDisabled: formatState => !formatState.isInTable,
onClick: (editor, _, strings, uiUtilities) => {
const items = {
title: {
autoFocus: true,
labelKey: 'buttonNameTableTitle' as const,
unlocalizedLabel: 'Title',
initValue: '',
},
};

showInputDialog(
uiUtilities,
'buttonNameTableTitle',
'Insert Table',
items,
strings,
(itemName, newValue, values) => {
if (itemName == 'title') {
values.title = newValue;
return values;
} else {
return null;
}
}
).then(result => {
editor.focus();
if (result && result.title) {
insertTableTitle(editor, result.title);
}
});
},
};

const insertTableTitle = (editor: IEditor, title: string) => {
editor.formatContentModel(model => {
const table = getFirstSelectedTable(model)[0];
if (table) {
mutateBlock(table).format.title = title;
return true;
}
return false;
});
};
3 changes: 3 additions & 0 deletions demo/scripts/controlsV2/tabs/ribbonButtons.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { tableBorderColorButton } from '../demoButtons/tableBorderColorButton';
import { tableBorderStyleButton } from '../demoButtons/tableBorderStyleButton';
import { tableBorderWidthButton } from '../demoButtons/tableBorderWidthButton';
import { tableOptionsButton } from '../demoButtons/tableOptionsButton';
import { tableTitleButton } from '../demoButtons/tableTitleButton';
import { tabNames } from './getTabs';
import {
tableAlignCellButton,
Expand Down Expand Up @@ -83,6 +84,7 @@ const tableButtons: RibbonButton<any>[] = [
insertTableButton,
formatTableButton,
setTableCellShadeButton,
tableTitleButton,
tableOptionsButton,
tableInsertButton,
tableDeleteButton,
Expand Down Expand Up @@ -178,6 +180,7 @@ const allButtons: RibbonButton<any>[] = [
tableDeleteButton,
tableMergeButton,
tableSplitButton,
tableTitleButton,
tableAlignCellButton,
tableAlignTableButton,
tableBorderApplyButton,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import type { AriaFormat } from 'roosterjs-content-model-types';
import type { FormatHandler } from '../FormatHandler';

/**
* @internal
*/
export const ariaFormatHandler: FormatHandler<AriaFormat> = {
parse: (format, element) => {
const ariaDescribedBy = element.getAttribute('aria-describedby');
const title = element.getAttribute('title');
if (ariaDescribedBy) {
format.ariaDescribedBy = ariaDescribedBy;
}
if (title) {
format.title = title;
}
},
apply: (format, element) => {
if (format.ariaDescribedBy) {
element.setAttribute('aria-describedby', format.ariaDescribedBy);
}
if (format.title) {
element.setAttribute('title', format.title);
}
},
};
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { ariaFormatHandler } from './common/ariaFormatHandler';
import { backgroundColorFormatHandler } from './common/backgroundColorFormatHandler';
import { boldFormatHandler } from './segment/boldFormatHandler';
import { borderBoxFormatHandler } from './common/borderBoxFormatHandler';
Expand Down Expand Up @@ -51,6 +52,7 @@ type FormatHandlers = {
};

const defaultFormatHandlerMap: FormatHandlers = {
aria: ariaFormatHandler,
backgroundColor: backgroundColorFormatHandler,
bold: boldFormatHandler,
border: borderFormatHandler,
Expand Down Expand Up @@ -162,6 +164,7 @@ export const defaultFormatKeysPerCategory: {
tableRow: ['backgroundColor'],
tableColumn: ['size'],
table: [
'aria',
'id',
'border',
'backgroundColor',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { AriaFormat, DomToModelContext, ModelToDomContext } from 'roosterjs-content-model-types';
import { ariaFormatHandler } from '../../../lib/formatHandlers/common/ariaFormatHandler';
import { createDomToModelContext } from '../../../lib/domToModel/context/createDomToModelContext';
import { createModelToDomContext } from '../../../lib/modelToDom/context/createModelToDomContext';

describe('ariaFormatHandler.parse', () => {
let div: HTMLElement;
let format: AriaFormat;
let context: DomToModelContext;

beforeEach(() => {
div = document.createElement('div');
format = {};
context = createDomToModelContext();
});

it('No title and describedby', () => {
ariaFormatHandler.parse(format, div, context, {});
expect(format).toEqual({});
});

it('has title and describedby', () => {
div.setAttribute('title', 'test');
div.setAttribute('aria-describedby', 'test');
ariaFormatHandler.parse(format, div, context, {});
expect(format).toEqual({
title: 'test',
ariaDescribedBy: 'test',
});
});

it('has title and no describedby', () => {
div.setAttribute('title', 'test');
ariaFormatHandler.parse(format, div, context, {});
expect(format).toEqual({
title: 'test',
});
});

it('no title and has describedby', () => {
div.setAttribute('aria-describedby', 'test');
ariaFormatHandler.parse(format, div, context, {});
expect(format).toEqual({ ariaDescribedBy: 'test' });
});
});

describe('idFormatHandler.apply', () => {
let div: HTMLElement;
let format: AriaFormat;
let context: ModelToDomContext;

beforeEach(() => {
div = document.createElement('div');
format = {};
context = createModelToDomContext();
});

it('No title and no describedby', () => {
ariaFormatHandler.apply(format, div, context);
expect(div.outerHTML).toBe('<div></div>');
});

it('Has title and has describedby', () => {
format.title = 'test';
format.ariaDescribedBy = 'test';
ariaFormatHandler.apply(format, div, context);
expect(div.outerHTML).toBe('<div aria-describedby="test" title="test"></div>');
});

it('No title and has describedby', () => {
format.ariaDescribedBy = 'test';
ariaFormatHandler.apply(format, div, context);
expect(div.outerHTML).toBe('<div aria-describedby="test"></div>');
});

it('Has title and no describedby', () => {
format.title = 'test';
ariaFormatHandler.apply(format, div, context);
expect(div.outerHTML).toBe('<div title="test"></div>');
});
});
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type { AriaFormat } from './formatParts/AriaFormat';
import type { BorderBoxFormat } from './formatParts/BorderBoxFormat';
import type { BorderFormat } from './formatParts/BorderFormat';
import type { ContentModelBlockFormat } from './ContentModelBlockFormat';
Expand All @@ -13,6 +14,7 @@ import type { SizeFormat } from './formatParts/SizeFormat';
*/
export type ContentModelTableFormat = ContentModelBlockFormat &
IdFormat &
AriaFormat &
BorderFormat &
BorderBoxFormat &
SpacingFormat &
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type { AriaFormat } from './formatParts/AriaFormat';
import type { BackgroundColorFormat } from './formatParts/BackgroundColorFormat';
import type { BoldFormat } from './formatParts/BoldFormat';
import type { BorderBoxFormat } from './formatParts/BorderBoxFormat';
Expand Down Expand Up @@ -37,6 +38,11 @@ import type { WordBreakFormat } from './formatParts/WordBreakFormat';
* Represents a record of all format handlers
*/
export interface FormatHandlerTypeMap {
/**
* Format for AriaFormat
*/
aria: AriaFormat;

/**
* Format for BackgroundColorFormat
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/**
* Format of background color
*/
export type AriaFormat = {
/**
* Aria-describedby attribute
*/
ariaDescribedBy?: string;

/**
* Title attribute
*/
title?: string;
};
1 change: 1 addition & 0 deletions packages/roosterjs-content-model-types/lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export { ContentModelImageFormat } from './contentModel/format/ContentModelImage
export { ContentModelEntityFormat } from './contentModel/format/ContentModelEntityFormat';
export { FormatHandlerTypeMap, FormatKey } from './contentModel/format/FormatHandlerTypeMap';

export { AriaFormat } from './contentModel/format/formatParts/AriaFormat';
export { BackgroundColorFormat } from './contentModel/format/formatParts/BackgroundColorFormat';
export { BoldFormat } from './contentModel/format/formatParts/BoldFormat';
export { FontFamilyFormat } from './contentModel/format/formatParts/FontFamilyFormat';
Expand Down

0 comments on commit 9415c68

Please sign in to comment.