Skip to content

Commit 1878d7a

Browse files
JiuqingSonghaven2worldDurssBryanValverdeUjuliaroldi
authored
Bump version to 9.35.0 (#3133)
* Fix toggling format issue at composition stage for CJK (#3064) * draft * temp * update ff * update * test * update * Avoid "undefined" in HTML to Markdown generated content (#3069) * fix: avoid "undefined" before paragraphs content * fix: set "image" as the default alt value instead of "undefined" --------- Co-authored-by: Francois Dursus <[email protected]> * Add focus handling in formatTableWithContentModel and its tests (#3072) * format applier (#3073) * Keep implicit paragraph when pressing Enter at the start of it. (#3075) * Enhance splitParagraph function to allow preservation of implicit paragraphs after split * Fix preserveImplicitParagraph flag in handleEnterOnParagraph to false * Update packages/roosterjs-content-model-plugins/lib/edit/utils/splitParagraph.ts Co-authored-by: Copilot <[email protected]> --------- Co-authored-by: Copilot <[email protected]> * Add beforeLogicalRootChanged event handling and related tests (#3077) * Add beforeLogicalRootChanged event handling and related tests * Rename event type from 'beforeLogicalRootChanged' to 'beforeLogicalRootChange' across relevant files * Update packages/roosterjs-content-model-types/lib/event/LogicalRootChangedEvent.ts Co-authored-by: Copilot <[email protected]> --------- Co-authored-by: Copilot <[email protected]> * Disable isComposing check in DOM event propagation for Android (#3076) * dsiable isComposing check for Android * add test --------- Co-authored-by: Bryan Valverde U <[email protected]> * Allow plugins to store state in snapshot (#3079) * Allow plugins to store custom state in undo snapshots * Type fixes * Move to using object instead array * Fix #3080 (#3084) * Add auto direction to setDirection (#3082) * Initial commit * Pending changes exported from your codespace * fix code and tests * Address comments --------- Co-authored-by: wisaulni <[email protected]> Co-authored-by: Bryan Valverde U <[email protected]> * Ensure image is loaded before creating image wrapper (#3090) * Enhance image loading handling in ImageEditPlugin to support resizing and editing of images not fully loaded * Apply suggestions from code review Co-authored-by: Copilot <[email protected]> --------- Co-authored-by: Copilot <[email protected]> * test (#3092) * Fix #3085 (#3095) Co-authored-by: Julia Roldi <[email protected]> * Adjust the image wrapper to stay inline (#3093) Use text-bottom instead of bottom for vertical-align to prevent the image to rotate below the text line. Also add some 5px in margin bottom to compensate for the height of the bottom handles. * Fix 309357 (#3097) * Fix 309357 * improve * improve * improve * Update packages/roosterjs-content-model-types/lib/context/ModelToDomOption.ts Co-authored-by: Copilot <[email protected]> * Update packages/roosterjs-content-model-types/lib/context/ModelToDomSettings.ts Co-authored-by: Copilot <[email protected]> * fix build --------- Co-authored-by: Copilot <[email protected]> Co-authored-by: Bryan Valverde U <[email protected]> * Fix #3063 (#3096) * Fix #3087 Delete paragraph styles when there is nothing else to be deleted (#3094) * Fix #3087 * Update packages/roosterjs-content-model-plugins/lib/edit/deleteSteps/deleteParagraphStyle.ts Co-authored-by: Copilot <[email protected]> * Update packages/roosterjs-content-model-plugins/lib/edit/deleteSteps/deleteParagraphStyle.ts Co-authored-by: Copilot <[email protected]> * Update packages/roosterjs-content-model-plugins/lib/edit/deleteSteps/deleteParagraphStyle.ts Co-authored-by: Copilot <[email protected]> --------- Co-authored-by: Copilot <[email protected]> * Remove karma changes (#3102) * karma * change * Adjust Block Indentation (#3099) When inserting a list or table in an indented segment, add the indentation to the block. * Process non-visible elements (#3089) New parameter processNonVisibleElements has been added to the DomToModelSettings and DomToModelOptions, allowing optional processing of non-visible elements. * Fix runtime color for dark mode (#3101) * Fix runtime color for dark mode * add test * fix build * table rtl (#3103) The style direction: RTL does move the table to the right, so use justifySelf:flex-end. * image-handles (#3104) When rotating an image, the resize handles direction must be updated according to the rotation angle. * Fix superscript rule (#3106) * Fix 380860 (#3107) * Support 'HTMLFast' mode when get HTML (#3109) * Support 'HTMLFast' mode when get HTML * fix build and comment * Bump tmp from 0.2.1 to 0.2.4 (#3114) Bumps [tmp](https://github.com/raszi/node-tmp) from 0.2.1 to 0.2.4. - [Changelog](https://github.com/raszi/node-tmp/blob/master/CHANGELOG.md) - [Commits](raszi/node-tmp@v0.2.1...v0.2.4) --- updated-dependencies: - dependency-name: tmp dependency-version: 0.2.4 dependency-type: indirect ... Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Jiuqing Song <[email protected]> * Fix #3110 (#3113) * Add logical root plugin and related presets; enhance event handling with capture option * Update packages/roosterjs-content-model-plugins/lib/imageEdit/ImageEditPlugin.ts Co-authored-by: Copilot <[email protected]> * Update demo/scripts/controlsV2/sidePane/presets/PresetPane.tsx Co-authored-by: Copilot <[email protected]> --------- Co-authored-by: Copilot <[email protected]> * Add markdown support for strikethrough * Fix test * Try fix unstable test (#3118) * add support for nested style markdowns * move let to const * update * Support DL,DT,DD in content model (#3120) * Support DL,DT,DD in content model * improve * fix build * fix test * Add an experimental feature for 'HTMLFast' when export html (#3121) * Add an experimental feature for 'HTMLFast' when export html * fix build * Fix 276282 (#3125) * Fix #3112 Delete empty block group when need (#3124) * Fix #3112 * improve * fix comments * update * remove console log * fix regression * update * Do not add undo snapshot from ImageEdit plugin if image is not changed (#3127) * Fix 377316: Skip undo snapshot when start to edit image * improve * fix comment * Support different options for empty line mode in mark down (#3128) * Support different options for empty line mode in mark down * Fix build * fix test * fix test * Fix auto link (#3129) When the text segment already has link, do not create the link again. * Graduate option "disableCache" (#3132) * Graduate option "disableCache" * Improve * Improve handleParagraph function (#3130) * 9.35.0 * Remove console.log added accidentally in test code (#3134) * Toggle blockquote in Format Container (#3126) FormatContainer can be used to other elements other than blockquotes. When toggling blockquote in format containers that are not blockquotes, search for the selected elements inside the container and only apply blockquote to theses selected elements. --------- Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: Haowen Chen <[email protected]> Co-authored-by: François Dursus <[email protected]> Co-authored-by: Francois Dursus <[email protected]> Co-authored-by: Bryan Valverde U <[email protected]> Co-authored-by: Julia Roldi <[email protected]> Co-authored-by: Copilot <[email protected]> Co-authored-by: Rain-Zheng <[email protected]> Co-authored-by: florian-msft <[email protected]> Co-authored-by: wisaulni <[email protected]> Co-authored-by: wisaulni <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Francis Meng <[email protected]> Co-authored-by: Francis Meng <[email protected]>
1 parent a2b0b6e commit 1878d7a

File tree

52 files changed

+2467
-313
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+2467
-313
lines changed

demo/scripts/controlsV2/mainPane/MainPane.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -394,7 +394,6 @@ export class MainPane extends React.Component<{}, MainPaneState> {
394394
editorCreator={this.state.editorCreator}
395395
dir={this.state.isRtl ? 'rtl' : 'ltr'}
396396
knownColors={this.knownColors}
397-
disableCache={this.state.initState.disableCache}
398397
announcerStringGetter={getAnnouncingString}
399398
experimentalFeatures={Array.from(
400399
this.state.initState.experimentalFeatures

demo/scripts/controlsV2/sidePane/MarkdownPane/MarkdownPane.tsx

Lines changed: 66 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,40 @@
11
import * as React from 'react';
2+
import { createBr, createParagraph, createSelectionMarker } from 'roosterjs-content-model-dom';
23
import { MarkdownPaneProps } from './MarkdownPanePlugin';
34
import {
45
convertMarkdownToContentModel,
56
convertContentModelToMarkdown,
67
} from 'roosterjs-content-model-markdown';
7-
import {
8-
createBr,
9-
createParagraph,
10-
createSelectionMarker,
11-
mergeModel,
12-
} from 'roosterjs-content-model-dom';
138

149
const styles = require('./MarkdownPane.scss');
1510

16-
export default class MarkdownPane extends React.Component<MarkdownPaneProps> {
11+
export default class MarkdownPane extends React.Component<
12+
MarkdownPaneProps,
13+
{ emptyLine: 'preserve' | 'remove' | 'merge' }
14+
> {
1715
private html = React.createRef<HTMLTextAreaElement>();
16+
private emptyLinePreserve = React.createRef<HTMLInputElement>();
17+
private emptyLineRemove = React.createRef<HTMLInputElement>();
18+
private emptyLineMerge = React.createRef<HTMLInputElement>();
1819

1920
constructor(props: MarkdownPaneProps) {
2021
super(props);
22+
23+
this.state = { emptyLine: 'merge' };
2124
}
2225

2326
private convert = () => {
2427
const editor = this.props.getEditor();
2528
editor.formatContentModel((model, context) => {
26-
const markdownModel = convertMarkdownToContentModel(this.html.current.value);
27-
mergeModel(model, markdownModel, context);
29+
const markdownModel = convertMarkdownToContentModel(this.html.current.value, {
30+
emptyLine: this.emptyLinePreserve.current.checked
31+
? 'preserve'
32+
: this.emptyLineRemove.current.checked
33+
? 'remove'
34+
: 'merge',
35+
});
36+
37+
model.blocks = markdownModel.blocks;
2838
return true;
2939
});
3040
};
@@ -55,10 +65,57 @@ export default class MarkdownPane extends React.Component<MarkdownPaneProps> {
5565
}
5666
};
5767

68+
private onEmptyLineChange = (e: React.MouseEvent<HTMLInputElement>) => {
69+
switch (e.currentTarget.value) {
70+
case 'preserve':
71+
this.setState({ emptyLine: 'preserve' });
72+
break;
73+
case 'remove':
74+
this.setState({ emptyLine: 'remove' });
75+
break;
76+
case 'merge':
77+
this.setState({ emptyLine: 'merge' });
78+
break;
79+
}
80+
};
81+
5882
render() {
5983
return (
6084
<div className={styles.container}>
6185
<p>Convert Markdown to content model</p>
86+
<div>
87+
Empty line:
88+
<input
89+
type="radio"
90+
name="emptyLine"
91+
id="emptyLinePreserve"
92+
value="preserve"
93+
checked={this.state.emptyLine == 'preserve'}
94+
ref={this.emptyLinePreserve}
95+
onClick={this.onEmptyLineChange}
96+
/>{' '}
97+
<label htmlFor="emptyLinePreserve">Preserve</label>
98+
<input
99+
type="radio"
100+
name="emptyLine"
101+
id="emptyLineRemove"
102+
value="remove"
103+
checked={this.state.emptyLine == 'remove'}
104+
ref={this.emptyLineRemove}
105+
onClick={this.onEmptyLineChange}
106+
/>{' '}
107+
<label htmlFor="emptyLineRemove">Remove</label>
108+
<input
109+
type="radio"
110+
name="emptyLine"
111+
id="emptyLineMerge"
112+
value="merge"
113+
checked={this.state.emptyLine == 'merge'}
114+
ref={this.emptyLineMerge}
115+
onClick={this.onEmptyLineChange}
116+
/>{' '}
117+
<label htmlFor="emptyLineMerge">Merge</label>
118+
</div>
62119
<textarea
63120
className={styles.textArea}
64121
title="Plain Text Editor"

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ const initialState: OptionState = {
3232
watermarkText: 'Type content here ...',
3333
forcePreserveRatio: false,
3434
isRtl: false,
35-
disableCache: false,
3635
tableFeaturesContainerSelector: '#' + 'EditorContainer',
3736
allowExcelNoBorderTable: false,
3837
imageMenu: true,

demo/scripts/controlsV2/sidePane/editorOptions/OptionState.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@ export interface OptionState {
4848

4949
// Editor options
5050
isRtl: boolean;
51-
disableCache: boolean;
5251
experimentalFeatures: Set<ExperimentalFeature>;
5352
}
5453

demo/scripts/controlsV2/sidePane/editorOptions/OptionsPane.tsx

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ export class OptionsPane extends React.Component<OptionPaneProps, OptionState> {
2929
private exportForm = React.createRef<HTMLFormElement>();
3030
private exportData = React.createRef<HTMLInputElement>();
3131
private rtl = React.createRef<HTMLInputElement>();
32-
private disableCache = React.createRef<HTMLInputElement>();
3332

3433
constructor(props: OptionPaneProps) {
3534
super(props);
@@ -75,16 +74,6 @@ export class OptionsPane extends React.Component<OptionPaneProps, OptionState> {
7574
/>
7675
<label htmlFor="pageRtl">Show controls from right to left</label>
7776
</div>
78-
<div>
79-
<input
80-
id="disableCache"
81-
type="checkbox"
82-
checked={this.state.disableCache}
83-
onChange={this.onToggleCacheModel}
84-
ref={this.disableCache}
85-
/>
86-
<label htmlFor="disableCache">Disable Content Model Cache</label>
87-
</div>
8877
<hr />
8978
<div>
9079
<button onClick={this.onExportRoosterContentModel}>
@@ -130,7 +119,6 @@ export class OptionsPane extends React.Component<OptionPaneProps, OptionState> {
130119
forcePreserveRatio: this.state.forcePreserveRatio,
131120

132121
isRtl: this.state.isRtl,
133-
disableCache: this.state.disableCache,
134122
tableFeaturesContainerSelector: this.state.tableFeaturesContainerSelector,
135123
allowExcelNoBorderTable: this.state.allowExcelNoBorderTable,
136124
listMenu: this.state.listMenu,
@@ -176,12 +164,6 @@ export class OptionsPane extends React.Component<OptionPaneProps, OptionState> {
176164
MainPane.getInstance().setPageDirection(isRtl);
177165
};
178166

179-
private onToggleCacheModel = () => {
180-
this.resetState(state => {
181-
state.disableCache = this.disableCache.current.checked;
182-
}, true);
183-
};
184-
185167
private getHtml() {
186168
return `${htmlStart}${htmlButtons}${jsCode}${htmlEnd}`;
187169
}

packages/roosterjs-content-model-api/lib/modelApi/block/toggleModelBlockQuote.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,9 @@ export function toggleModelBlockQuote(
3333

3434
const paragraphOfQuote = getOperationalBlocks<
3535
ContentModelFormatContainer | ContentModelListItem
36-
>(model, ['FormatContainer', 'ListItem'], ['TableCell'], true /*deepFirst*/);
36+
>(model, ['FormatContainer', 'ListItem'], ['TableCell'], true /*deepFirst*/, block => {
37+
return block.blockGroupType == 'FormatContainer' ? block.tagName == 'blockquote' : true;
38+
});
3739

3840
if (areAllBlockQuotes(paragraphOfQuote)) {
3941
// All selections are already in quote, we need to unquote them

packages/roosterjs-content-model-api/lib/modelApi/link/promoteLink.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ export function promoteLink(
2222
paragraph: ShallowMutableContentModelParagraph,
2323
autoLinkOptions: AutoLinkOptions
2424
): ContentModelText | null {
25+
if (segment.link) {
26+
return null;
27+
}
2528
const link = segment.text.split(' ').pop();
2629
const url = link?.trim();
2730
let linkUrl: string | undefined = undefined;

packages/roosterjs-content-model-api/test/modelApi/block/toggleModelBlockQuoteTest.ts

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -797,4 +797,180 @@ describe('toggleModelBlockQuote', () => {
797797
expect(splitSelectedParagraphByBrSpy).toHaveBeenCalledTimes(1);
798798
expect(splitSelectedParagraphByBrSpy).toHaveBeenCalledWith(doc);
799799
});
800+
801+
it('Quote only selected segments in a FormatContainer', () => {
802+
const doc = createContentModelDocument();
803+
const para1 = createParagraph();
804+
const text1 = createText('test1');
805+
const para2 = createParagraph();
806+
const text2 = createText('test2');
807+
const container = createFormatContainer('div', {
808+
id: 'TestId',
809+
});
810+
811+
para1.segments.push(text1);
812+
para2.segments.push(text2);
813+
container.blocks.push(para1);
814+
container.blocks.push(para2);
815+
doc.blocks.push(container);
816+
817+
text2.isSelected = true;
818+
819+
toggleModelBlockQuote(doc, {}, {});
820+
821+
expect(doc).toEqual({
822+
blockGroupType: 'Document',
823+
blocks: [
824+
{
825+
tagName: 'div',
826+
blockType: 'BlockGroup',
827+
format: {
828+
id: 'TestId',
829+
},
830+
blockGroupType: 'FormatContainer',
831+
blocks: [
832+
{
833+
segments: [
834+
{
835+
text: 'test1',
836+
segmentType: 'Text',
837+
format: {},
838+
},
839+
],
840+
blockType: 'Paragraph',
841+
format: {},
842+
},
843+
{
844+
tagName: 'blockquote',
845+
blockType: 'BlockGroup',
846+
format: {},
847+
blockGroupType: 'FormatContainer',
848+
blocks: [
849+
{
850+
segments: [
851+
{
852+
text: 'test2',
853+
segmentType: 'Text',
854+
format: {},
855+
isSelected: true,
856+
},
857+
],
858+
859+
blockType: 'Paragraph',
860+
format: {},
861+
},
862+
],
863+
},
864+
],
865+
},
866+
],
867+
});
868+
expect(splitSelectedParagraphByBrSpy).toHaveBeenCalledTimes(1);
869+
expect(splitSelectedParagraphByBrSpy).toHaveBeenCalledWith(doc);
870+
});
871+
872+
it('Quote only selected segments in a FormatContainer - multi selected segments', () => {
873+
const doc = createContentModelDocument();
874+
const para1 = createParagraph();
875+
const text1 = createText('test1');
876+
const para2 = createParagraph();
877+
const text2 = createText('test2');
878+
const para3 = createParagraph();
879+
const text3 = createText('test3');
880+
const para4 = createParagraph();
881+
const text4 = createText('test4');
882+
883+
const container = createFormatContainer('div', {
884+
id: 'TestId',
885+
});
886+
887+
para1.segments.push(text1);
888+
para2.segments.push(text2);
889+
para3.segments.push(text3);
890+
para4.segments.push(text4);
891+
container.blocks.push(para1);
892+
container.blocks.push(para2);
893+
container.blocks.push(para3);
894+
container.blocks.push(para4);
895+
doc.blocks.push(container);
896+
897+
text2.isSelected = true;
898+
text3.isSelected = true;
899+
text4.isSelected = true;
900+
901+
toggleModelBlockQuote(doc, {}, {});
902+
903+
expect(doc).toEqual({
904+
blockGroupType: 'Document',
905+
blocks: [
906+
{
907+
tagName: 'div',
908+
blockType: 'BlockGroup',
909+
format: {
910+
id: 'TestId',
911+
},
912+
blockGroupType: 'FormatContainer',
913+
blocks: [
914+
{
915+
segments: [
916+
{
917+
text: 'test1',
918+
segmentType: 'Text',
919+
format: {},
920+
},
921+
],
922+
blockType: 'Paragraph',
923+
format: {},
924+
},
925+
{
926+
tagName: 'blockquote',
927+
blockType: 'BlockGroup',
928+
format: {},
929+
blockGroupType: 'FormatContainer',
930+
blocks: [
931+
{
932+
segments: [
933+
{
934+
text: 'test2',
935+
segmentType: 'Text',
936+
format: {},
937+
isSelected: true,
938+
},
939+
],
940+
blockType: 'Paragraph',
941+
format: {},
942+
},
943+
{
944+
segments: [
945+
{
946+
text: 'test3',
947+
segmentType: 'Text',
948+
format: {},
949+
isSelected: true,
950+
},
951+
],
952+
blockType: 'Paragraph',
953+
format: {},
954+
},
955+
{
956+
segments: [
957+
{
958+
text: 'test4',
959+
segmentType: 'Text',
960+
format: {},
961+
isSelected: true,
962+
},
963+
],
964+
blockType: 'Paragraph',
965+
format: {},
966+
},
967+
],
968+
},
969+
],
970+
},
971+
],
972+
});
973+
expect(splitSelectedParagraphByBrSpy).toHaveBeenCalledTimes(1);
974+
expect(splitSelectedParagraphByBrSpy).toHaveBeenCalledWith(doc);
975+
});
800976
});

0 commit comments

Comments
 (0)