Skip to content

Commit

Permalink
Merge pull request #2921 from microsoft/u/juliaroldi/bump-rooster-js
Browse files Browse the repository at this point in the history
Bump RoosterJS Version 9.17.0
  • Loading branch information
juliaroldi authored Jan 10, 2025
2 parents 9f1ba11 + efa2131 commit c4bd4b4
Show file tree
Hide file tree
Showing 32 changed files with 718 additions and 305 deletions.
2 changes: 1 addition & 1 deletion demo/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
<div id="mainPane"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.14.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.14.0/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fluentui-react/8.60.1/fluentui-react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fluentui-react/8.122.3/fluentui-react.min.js"></script>
<script src="rooster-min.js"></script>
<script src="rooster-react-min.js"></script>
<script src="demo.js"></script>
Expand Down
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
2 changes: 1 addition & 1 deletion demo/scripts/utils/cssMonitor.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Stylesheet } from '@fluentui/merge-styles/lib/Stylesheet';
import { Stylesheet } from '@fluentui/merge-styles';

let isCssMonitorStarted: boolean = false;
const activeWindows: Window[] = [];
Expand Down
2 changes: 1 addition & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
<div id="mainPane"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.14.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.14.0/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fluentui-react/8.60.1/fluentui-react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fluentui-react/8.122.3/fluentui-react.min.js"></script>
<script src="scripts/demo.js"></script>
</body>
</html>
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
"publish": "node tools/build.js clean normalize buildcommonjs buildamd buildmjs dts pack packprod builddemo builddoc publish"
},
"devDependencies": {
"@fluentui/react": "^8.0.0",
"@fluentui/react": "8.122.3",
"@microsoft/loader-load-themed-styles": "1.8.11",
"@types/color": "3.0.0",
"@types/dompurify": "2.2.3",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,17 @@ const MAX_FONT_SIZE = 1000;
* @param change Whether increase or decrease font size
* @param fontSizes A sorted font size array, in pt. Default value is FONT_SIZES
*/
export function changeFontSize(editor: IEditor, change: 'increase' | 'decrease') {
export function changeFontSize(
editor: IEditor,
change: 'increase' | 'decrease',
fontSizes: number[] = FONT_SIZES
) {
editor.focus();

formatSegmentWithContentModel(
editor,
'changeFontSize',
(format, _, __, paragraph) => changeFontSizeInternal(change, format, paragraph),
(format, _, __, paragraph) => changeFontSizeInternal(change, format, paragraph, fontSizes),
undefined /* segmentHasStyleCallback*/,
true /*includingFormatHandler*/
);
Expand All @@ -36,13 +40,14 @@ export function changeFontSize(editor: IEditor, change: 'increase' | 'decrease')
function changeFontSizeInternal(
change: 'increase' | 'decrease',
format: ContentModelSegmentFormat,
paragraph: ShallowMutableContentModelParagraph | null
paragraph: ShallowMutableContentModelParagraph | null,
fontSizes: number[]
) {
if (format.fontSize) {
const sizeInPt = parseValueWithUnit(format.fontSize, undefined /*element*/, 'pt');

if (sizeInPt > 0) {
const newSize = getNewFontSize(sizeInPt, change == 'increase' ? 1 : -1, FONT_SIZES);
const newSize = getNewFontSize(sizeInPt, change == 'increase' ? 1 : -1, fontSizes);

setFontSizeInternal(newSize + 'pt', format, paragraph);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,5 @@ export function generatePasteOptionFromPlugins(
containsBlockElements: !!htmlFromClipboard.containsBlockElements,
};

return pasteType == 'asPlainText'
? event
: editor.triggerEvent('beforePaste', event, true /* broadcast */);
return editor.triggerEvent('beforePaste', event, true /* broadcast */);
}
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,8 @@ describe('generatePasteOptionFromPlugins', () => {
it('PasteType=asPlainText', () => {
triggerPluginEventSpy.and.callFake((core, event) => {
Object.assign(event, mockedResult);

return event;
});
const result = generatePasteOptionFromPlugins(
editor,
Expand All @@ -236,24 +238,16 @@ describe('generatePasteOptionFromPlugins', () => {
);

expect(result).toEqual({
fragment: mockedFragment,
domToModelOption: {
additionalAllowedTags: [],
additionalDisallowedTags: [],
additionalFormatParsers: {},
formatParserOverride: {},
processorOverride: {},
styleSanitizers: {},
attributeSanitizers: {},
},
pasteType: 'asPlainText',
eventType: 'beforePaste',
clipboardData: mockedClipboardData,
htmlBefore,
htmlAfter,
htmlAttributes: mockedMetadata,
clipboardData: 'CLIPBOARDDATA' as any,
fragment: 'FragmentResult' as any,
htmlBefore: 'HTMLBEFORE',
htmlAfter: 'HTMLAFTER',
htmlAttributes: 'METADATA' as any,
pasteType: 'TypeResult' as any,
domToModelOption: 'OptionResult' as any,
containsBlockElements: false,
});
expect(triggerPluginEventSpy).toHaveBeenCalledTimes(0);
expect(triggerPluginEventSpy).toHaveBeenCalledTimes(1);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -223,9 +223,9 @@ describe('paste with content model & paste plugin', () => {

paste(editor!, clipboardData, 'asPlainText');

expect(setProcessorF.setProcessor).toHaveBeenCalledTimes(0);
expect(addParserF.addParser).toHaveBeenCalledTimes(0);
expect(WordDesktopFile.processPastedContentFromWordDesktop).toHaveBeenCalledTimes(0);
expect(setProcessorF.setProcessor).toHaveBeenCalledTimes(1);
expect(addParserF.addParser).toHaveBeenCalledTimes(9);
expect(WordDesktopFile.processPastedContentFromWordDesktop).toHaveBeenCalledTimes(1);
});

it('Word Online | Plain Text', () => {
Expand All @@ -234,9 +234,9 @@ describe('paste with content model & paste plugin', () => {

paste(editor!, clipboardData, 'asPlainText');

expect(setProcessorF.setProcessor).toHaveBeenCalledTimes(0);
expect(addParserF.addParser).toHaveBeenCalledTimes(0);
expect(WacComponents.processPastedContentWacComponents).toHaveBeenCalledTimes(0);
expect(setProcessorF.setProcessor).toHaveBeenCalledTimes(2);
expect(addParserF.addParser).toHaveBeenCalledTimes(11);
expect(WacComponents.processPastedContentWacComponents).toHaveBeenCalledTimes(1);
});

it('Excel Online | Plain Text', () => {
Expand All @@ -246,7 +246,7 @@ describe('paste with content model & paste plugin', () => {
paste(editor!, clipboardData, 'asPlainText');

expect(setProcessorF.setProcessor).toHaveBeenCalledTimes(0);
expect(addParserF.addParser).toHaveBeenCalledTimes(0);
expect(addParserF.addParser).toHaveBeenCalledTimes(4);
expect(ExcelF.processPastedContentFromExcel).toHaveBeenCalledTimes(0);
});

Expand All @@ -257,7 +257,7 @@ describe('paste with content model & paste plugin', () => {
paste(editor!, clipboardData, 'asPlainText');

expect(setProcessorF.setProcessor).toHaveBeenCalledTimes(0);
expect(addParserF.addParser).toHaveBeenCalledTimes(0);
expect(addParserF.addParser).toHaveBeenCalledTimes(4);
expect(ExcelF.processPastedContentFromExcel).toHaveBeenCalledTimes(0);
});

Expand All @@ -268,8 +268,8 @@ describe('paste with content model & paste plugin', () => {
paste(editor!, clipboardData, 'asPlainText');

expect(setProcessorF.setProcessor).toHaveBeenCalledTimes(0);
expect(addParserF.addParser).toHaveBeenCalledTimes(0);
expect(PPT.processPastedContentFromPowerPoint).toHaveBeenCalledTimes(0);
expect(addParserF.addParser).toHaveBeenCalledTimes(4);
expect(PPT.processPastedContentFromPowerPoint).toHaveBeenCalledTimes(1);
});

it('Verify the event data is not lost', () => {
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>');
});
});
Loading

0 comments on commit c4bd4b4

Please sign in to comment.