Skip to content

Commit a279b70

Browse files
authored
Merge pull request #1487 from microsoft/u/juliaroldi/version-8.40.0
U/juliaroldi/version 8.40.0
2 parents 20e3a02 + 07332f4 commit a279b70

129 files changed

Lines changed: 9081 additions & 2459 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,76 @@
11
import * as React from 'react';
2+
import { BackgroundColorFormatRenderer } from '../format/formatPart/BackgroundColorFormatRenderer';
23
import { BlockGroupContentView } from './BlockGroupContentView';
3-
import { ContentModelQuote, hasSelectionInBlock } from 'roosterjs-content-model';
4+
import { BorderFormatRenderers } from '../format/formatPart/BorderFormatRenderers';
45
import { ContentModelView } from '../ContentModelView';
6+
import { DirectionFormatRenderers } from '../format/formatPart/DirectionFormatRenderers';
7+
import { FontFamilyFormatRenderer } from '../format/formatPart/FontFamilyFormatRenderer';
8+
import { FontSizeFormatRenderer } from '../format/formatPart/FontSizeFormatRenderer';
9+
import { FormatRenderer } from '../format/utils/FormatRenderer';
10+
import { FormatView } from '../format/FormatView';
11+
import { LineHeightFormatRenderer } from '../format/formatPart/LineHeightFormatRenderer';
12+
import { MarginFormatRenderer } from '../format/formatPart/MarginFormatRenderer';
13+
import { PaddingFormatRenderer } from '../format/formatPart/PaddingFormatRenderer';
14+
import { TextColorFormatRenderer } from '../format/formatPart/TextColorFormatRenderer';
15+
import { WhiteSpaceFormatRenderer } from '../format/formatPart/WhiteSpaceFormatRenderer';
16+
import {
17+
ContentModelQuote,
18+
ContentModelQuoteFormat,
19+
ContentModelSegmentFormat,
20+
hasSelectionInBlock,
21+
} from 'roosterjs-content-model';
22+
import {
23+
BoldFormatRenderer,
24+
ItalicFormatRenderer,
25+
UnderlineFormatRenderer,
26+
} from '../format/formatPart/BasicFormatRenderers';
527

628
const styles = require('./ContentModelQuoteView.scss');
729

30+
const QuoteBlockFormatRenders: FormatRenderer<ContentModelQuoteFormat>[] = [
31+
BackgroundColorFormatRenderer,
32+
...DirectionFormatRenderers,
33+
MarginFormatRenderer,
34+
PaddingFormatRenderer,
35+
LineHeightFormatRenderer,
36+
WhiteSpaceFormatRenderer,
37+
...BorderFormatRenderers,
38+
];
39+
const QuoteSegmentFormatRenders: FormatRenderer<ContentModelSegmentFormat>[] = [
40+
TextColorFormatRenderer,
41+
FontSizeFormatRenderer,
42+
FontFamilyFormatRenderer,
43+
BoldFormatRenderer,
44+
ItalicFormatRenderer,
45+
UnderlineFormatRenderer,
46+
];
47+
848
export function ContentModelQuoteView(props: { quote: ContentModelQuote }) {
949
const { quote } = props;
1050
const getContent = React.useCallback(() => {
1151
return <BlockGroupContentView group={quote} />;
1252
}, [quote]);
1353

54+
const getFormat = React.useCallback(() => {
55+
return (
56+
<>
57+
<FormatView format={quote.format} renderers={QuoteBlockFormatRenders} />
58+
<FormatView
59+
format={quote.quoteSegmentFormat}
60+
renderers={QuoteSegmentFormatRenders}
61+
/>
62+
</>
63+
);
64+
}, [quote]);
65+
1466
return (
1567
<ContentModelView
1668
title="Quote"
1769
className={styles.modelQuote}
1870
hasSelection={hasSelectionInBlock(quote)}
1971
jsonSource={quote}
2072
getContent={getContent}
73+
getFormat={getFormat}
2174
/>
2275
);
2376
}

demo/scripts/controls/editor/ExperimentalContentModelEditor.ts

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -76,18 +76,16 @@ export default class ExperimentalContentModelEditor extends Editor
7676
);
7777
const mergingCallback = option?.mergingCallback || restoreContentWithEntityPlaceholder;
7878

79-
if (range) {
80-
if (range.type == SelectionRangeTypes.Normal) {
81-
// Need to get start and end from range position before merge because range can be changed during merging
82-
const start = Position.getStart(range.ranges[0]);
83-
const end = Position.getEnd(range.ranges[0]);
79+
if (range?.type == SelectionRangeTypes.Normal) {
80+
// Need to get start and end from range position before merge because range can be changed during merging
81+
const start = Position.getStart(range.ranges[0]);
82+
const end = Position.getEnd(range.ranges[0]);
8483

85-
mergingCallback(fragment, this.contentDiv, entityPairs);
86-
this.select(start, end);
87-
} else {
88-
mergingCallback(fragment, this.contentDiv, entityPairs);
89-
this.select(range);
90-
}
84+
mergingCallback(fragment, this.contentDiv, entityPairs);
85+
this.select(start, end);
86+
} else {
87+
mergingCallback(fragment, this.contentDiv, entityPairs);
88+
this.select(range);
9189
}
9290
}
9391
}

demo/scripts/controls/ribbonButtons/contentModel/ContentModelRibbon.tsx

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { alignCenterButton } from './alignCenterButton';
33
import { alignLeftButton } from './alignLeftButton';
44
import { alignRightButton } from './alignRightButton';
55
import { backgroundColorButton } from './backgroundColorButton';
6+
import { blockQuoteButton } from './blockQuoteButton';
67
import { boldButton } from './boldButton';
78
import { bulletedListButton } from './bulletedListButton';
89
import { decreaseFontSizeButton } from './decreaseFontSizeButton';
@@ -12,6 +13,7 @@ import { fontSizeButton } from './fontSizeButton';
1213
import { formatTableButton } from './formatTableButton';
1314
import { increaseFontSizeButton } from './increaseFontSizeButton';
1415
import { increaseIndentButton } from './increaseIndentButton';
16+
import { insertImageButton } from './insertImageButton';
1517
import { insertTableButton } from './insertTableButton';
1618
import { italicButton } from './italicButton';
1719
import { listStartNumberButton } from './listStartNumberButton';
@@ -52,19 +54,21 @@ const buttons = [
5254
numberedListButton,
5355
decreaseIndentButton,
5456
increaseIndentButton,
55-
strikethroughButton,
56-
superscriptButton,
57-
subscriptButton,
57+
blockQuoteButton,
5858
alignLeftButton,
5959
alignCenterButton,
6060
alignRightButton,
61+
insertTableButton,
62+
insertImageButton,
63+
superscriptButton,
64+
subscriptButton,
65+
strikethroughButton,
66+
setHeaderLevelButton,
6167
ltrButton,
6268
rtlButton,
63-
setHeaderLevelButton,
6469
setBulletedListStyleButton,
6570
setNumberedListStyleButton,
6671
listStartNumberButton,
67-
insertTableButton,
6872
formatTableButton,
6973
setTableCellShadeButton,
7074
setTableHeaderButton,
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import isContentModelEditor from '../../editor/isContentModelEditor';
2+
import { QuoteButtonStringKey, RibbonButton } from 'roosterjs-react';
3+
import { toggleBlockQuote } from 'roosterjs-content-model';
4+
5+
/**
6+
* @internal
7+
* "Block quote" button on the format ribbon
8+
*/
9+
export const blockQuoteButton: RibbonButton<QuoteButtonStringKey> = {
10+
key: 'buttonNameQuote',
11+
unlocalizedText: 'Quote',
12+
iconName: 'RightDoubleQuote',
13+
isChecked: formatState => !!formatState.isBlockQuote,
14+
onClick: editor => {
15+
if (isContentModelEditor(editor)) {
16+
toggleBlockQuote(editor);
17+
}
18+
return true;
19+
},
20+
};
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import isContentModelEditor from '../../editor/isContentModelEditor';
2+
import { createElement } from 'roosterjs-editor-dom';
3+
import { CreateElementData } from 'roosterjs-editor-types';
4+
import { insertImage } from 'roosterjs-content-model';
5+
import { InsertImageButtonStringKey, RibbonButton } from 'roosterjs-react';
6+
7+
const FileInput: CreateElementData = {
8+
tag: 'input',
9+
attributes: {
10+
type: 'file',
11+
accept: 'image/*',
12+
display: 'none',
13+
},
14+
};
15+
16+
/**
17+
* @internal
18+
* "Insert image" button on the format ribbon
19+
*/
20+
export const insertImageButton: RibbonButton<InsertImageButtonStringKey> = {
21+
key: 'buttonNameInsertImage',
22+
unlocalizedText: 'Insert image',
23+
iconName: 'Photo2',
24+
onClick: editor => {
25+
if (isContentModelEditor(editor)) {
26+
const document = editor.getDocument();
27+
const fileInput = createElement(FileInput, document) as HTMLInputElement;
28+
document.body.appendChild(fileInput);
29+
30+
fileInput.addEventListener('change', () => {
31+
if (fileInput.files) {
32+
for (let i = 0; i < fileInput.files.length; i++) {
33+
insertImage(editor, fileInput.files[i]);
34+
}
35+
}
36+
});
37+
38+
try {
39+
fileInput.click();
40+
} finally {
41+
document.body.removeChild(fileInput);
42+
}
43+
}
44+
},
45+
};

demo/scripts/controls/sidePane/apiPlayground/region/GetSelectedRegionsPane.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import * as React from 'react';
22
import ApiPaneProps from '../ApiPaneProps';
3-
import { IEditor, PositionType, Region } from 'roosterjs-editor-types';
3+
import { ExperimentalFeatures, IEditor, PositionType, Region } from 'roosterjs-editor-types';
44
import {
55
createRange,
66
getSelectedBlockElementsInRegion,
@@ -55,7 +55,11 @@ export default class GetSelectedRegionsPane extends React.Component<
5555

5656
function Region({ region, editor, index }: { region: Region; editor: IEditor; index: number }) {
5757
const selectRegion = React.useCallback(() => {
58-
const blocks = getSelectedBlockElementsInRegion(region);
58+
const blocks = getSelectedBlockElementsInRegion(
59+
region,
60+
undefined /* createBlockIfEmpty */,
61+
editor.isFeatureEnabled(ExperimentalFeatures.DefaultFormatInSpan)
62+
);
5963
if (blocks.length > 0) {
6064
const range = createRange(
6165
blocks[0].getStartNode(),

demo/scripts/controls/sidePane/editorOptions/EditorOptionsPlugin.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,7 @@ const initialState: BuildInPluginState = {
2828
watermarkText: 'Type content here ...',
2929
forcePreserveRatio: false,
3030
experimentalFeatures: [
31-
ExperimentalFeatures.ConvertSingleImageBody,
3231
ExperimentalFeatures.ListItemAlignment,
33-
ExperimentalFeatures.PendingStyleBasedFormat,
3432
ExperimentalFeatures.DefaultFormatInSpan,
3533
ExperimentalFeatures.AutoFormatList,
3634
],

demo/scripts/controls/sidePane/editorOptions/ExperimentalFeatures.tsx

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,11 @@ export interface ExperimentalFeaturesProps {
99
}
1010

1111
const FeatureNames: Partial<Record<ExperimentalFeatures, string>> = {
12-
[ExperimentalFeatures.ConvertSingleImageBody]:
13-
'Paste Html instead of image when Html have one Img Children (Animated Image Paste)',
1412
[ExperimentalFeatures.TabKeyTextFeatures]: 'Additional functionality to Tab Key',
1513
[ExperimentalFeatures.ListItemAlignment]:
1614
'Align list elements elements to left, center and right using setAlignment API',
1715
[ExperimentalFeatures.AutoFormatList]:
1816
'Trigger formatting by a especial characters. Ex: (A), 1. i).',
19-
[ExperimentalFeatures.PendingStyleBasedFormat]:
20-
'Use pending style format to do formatting when selection is collapsed',
21-
[ExperimentalFeatures.NormalizeList]:
22-
'Normalize list to make sure it can be displayed correctly in other client',
2317
[ExperimentalFeatures.ReuseAllAncestorListElements]:
2418
"Reuse ancestor list elements even if they don't match the types from the list item.",
2519
[ExperimentalFeatures.DefaultFormatInSpan]:

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "roosterjs",
3-
"version": "8.39.1",
3+
"version": "8.40.0",
44
"description": "Framework-independent javascript editor",
55
"repository": {
66
"type": "git",
@@ -18,7 +18,7 @@
1818
"builddemo": "node tools/build.js builddemo",
1919
"builddoc": "node tools/build.js builddoc",
2020
"build": "node tools/build.js clean checkdep normalize tslint buildcommonjs dts packprod builddemo",
21-
"build:ci": "node tools/build.js --noProgressBar clean checkdep normalize tslint buildcommonjs buildamd buildmjs dts pack packprod builddemo builddoc",
21+
"build:ci": "node --max-old-space-size=8192 tools/build.js --noProgressBar clean checkdep normalize tslint buildcommonjs buildamd buildmjs dts pack packprod builddemo builddoc",
2222
"start": "node tools/start.js",
2323
"test": "node tools/build.js normalize & karma start --chrome",
2424
"test:chrome": "node tools/build.js normalize & karma start --chrome",

packages/roosterjs-content-model/lib/domToModel/processors/knownElementProcessor.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,10 @@ export const knownElementProcessor: ElementProcessor<HTMLElement> = (group, elem
7171
);
7272

7373
if (topDivider) {
74+
if (context.isInSelection) {
75+
topDivider.isSelected = true;
76+
}
77+
7478
addBlock(group, topDivider);
7579
}
7680

@@ -82,6 +86,10 @@ export const knownElementProcessor: ElementProcessor<HTMLElement> = (group, elem
8286
context.elementProcessors.child(group, element, context);
8387

8488
if (bottomDivider) {
89+
if (context.isInSelection) {
90+
bottomDivider.isSelected = true;
91+
}
92+
8593
addBlock(group, bottomDivider);
8694
}
8795
}

0 commit comments

Comments
 (0)