Skip to content

Commit 962fb77

Browse files
BryanValverdeUjuliaroldiJiuqingSongshaipetel
authored
Bump Rooster to 8.40.2 and ContentModel to 0.0.13 (#1522)
* convert alpha to decimals * fix auto format list * add null and refactor * Content Model Selection API step 4: Refactor existing table API (#1479) * Selection API step 1 * Selection API 2 * New selection API * Refactor table API * add test * Support element with namespace (#1489) * Content Model: Fix a bug when process margin (#1493) * Fix margin issue * Fix test * Fix A tag without href (#1495) * Fix Cut/Copy page scroll issue (#1496) * Fix Cut/Copy page scroll issue * Fix test * fix image plugin z-index calc * Content Model Format State Step 1: Refactor formatSegmentWithContentModel() (#1490) * Selection API step 1 * Selection API 2 * New selection API * Refactor table API * add test * Format state step 1 * Improve * update condition per comments * Content Model Format State Step 2: Allow retrieving metadata directly (#1491) * Selection API step 1 * Selection API 2 * New selection API * Refactor table API * add test * Format state step 1 * FormatState step 2 * Improve * Content Model Format State Step 3: Add getFormatState API and ContentModelPlugin (#1492) * Selection API step 1 * Selection API 2 * New selection API * Refactor table API * add test * Format state step 1 * FormatState step 2 * FormatState step 3: Add getFormatState API and ContentModel plugin * Improve * Improve * Improve * fix test * improve, fix safari issue * fix test * Content Model: Add API clearFormat (#1497) * Selection API step 1 * Selection API 2 * New selection API * Refactor table API * add test * Format state step 1 * FormatState step 2 * FormatState step 3: Add getFormatState API and ContentModel plugin * Improve * Content Model: clearFormat * fix build * Improve * Improve * fix test * improve, fix safari issue * fix test * remove wrapper when content change * fix * Content Model: Move format API: link, image, captalization, ... (#1506) * Selection API step 1 * Selection API 2 * New selection API * Refactor table API * add test * Format state step 1 * FormatState step 2 * FormatState step 3: Add getFormatState API and ContentModel plugin * Improve * Content Model: clearFormat * fix build * Improve * Improve * fix test * improve, fix safari issue * fix test * ContentModel: Support insertLink and removeLink * changeCapitalization and setImageAltText * fix for image selection * refactor * refactor * Fix #1509 (#1511) * ContentModel: Improve Divider (#1513) * ContentModel: Improve Divider * Add BorderFormat to ContentModelBlockFormat * Add test * fix build * Content Model: Support "no color" when set color (#1514) * Content Model: Support "no color" when set color * improve * Content Model: Use Entity handle readonly element (#1515) * Content Model: Support get and apply segment format (#1518) * Do not merge table when insert a table (#1519) * bump versions * Content Model: Fix #1239 (#1521) Co-authored-by: Júlia Roldi <juliaroldi@microsoft.com> Co-authored-by: Jiuqing Song <jisong@microsoft.com> Co-authored-by: Julia Roldi <87443959+juliaroldi@users.noreply.github.com> Co-authored-by: Shai Petel <shai@kwizcom.com> Co-authored-by: Shai Petel <shai@petel.com>
1 parent 878b0d3 commit 962fb77

145 files changed

Lines changed: 8114 additions & 842 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.

demo/scripts/controls/MainPane.tsx

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,21 @@ import * as React from 'react';
22
import * as ReactDOM from 'react-dom';
33
import ApiPlaygroundPlugin from './sidePane/apiPlayground/ApiPlaygroundPlugin';
44
import BuildInPluginState from './BuildInPluginState';
5-
import ContentModelPlugin from './sidePane/contentModel/ContentModelPlugin';
5+
import ContentModelPanePlugin from './sidePane/contentModel/ContentModelPanePlugin';
66
import ContentModelRibbon from './ribbonButtons/contentModel/ContentModelRibbon';
77
import EditorOptionsPlugin from './sidePane/editorOptions/EditorOptionsPlugin';
88
import EventViewPlugin from './sidePane/eventViewer/EventViewPlugin';
99
import ExperimentalContentModelEditor from './editor/ExperimentalContentModelEditor';
10+
import FormatPainterPlugin from './contentModel/plugins/FormatPainterPlugin';
1011
import FormatStatePlugin from './sidePane/formatState/FormatStatePlugin';
1112
import getToggleablePlugins from './getToggleablePlugins';
1213
import MainPaneBase from './MainPaneBase';
1314
import SidePane from './sidePane/SidePane';
1415
import SnapshotPlugin from './sidePane/snapshot/SnapshotPlugin';
1516
import TitleBar from './titleBar/TitleBar';
1617
import { arrayPush } from 'roosterjs-editor-dom';
18+
import { ContentModelPlugin } from 'roosterjs-content-model';
19+
import { ContentModelRibbonPlugin } from './ribbonButtons/contentModel/ContentModelRibbonPlugin';
1720
import { darkMode, DarkModeButtonStringKey } from './ribbonButtons/darkMode';
1821
import { EditorOptions, EditorPlugin } from 'roosterjs-editor-types';
1922
import { ExportButtonStringKey, exportContent } from './ribbonButtons/export';
@@ -118,13 +121,15 @@ class MainPane extends MainPaneBase {
118121
private eventViewPlugin: EventViewPlugin;
119122
private apiPlaygroundPlugin: ApiPlaygroundPlugin;
120123
private snapshotPlugin: SnapshotPlugin;
121-
private contentModelPlugin: ContentModelPlugin;
124+
private ContentModelPanePlugin: ContentModelPanePlugin;
122125
private ribbonPlugin: RibbonPlugin;
123126
private contentModelRibbonPlugin: RibbonPlugin;
124127
private pasteOptionPlugin: EditorPlugin;
125128
private emojiPlugin: EditorPlugin;
126129
private updateContentPlugin: UpdateContentPlugin;
127130
private toggleablePlugins: EditorPlugin[] | null = null;
131+
private contentModelPlugin: ContentModelPlugin;
132+
private formatPainterPlugin: FormatPainterPlugin;
128133
private mainWindowButtons: RibbonButton<RibbonStringKeys>[];
129134
private popoutWindowButtons: RibbonButton<RibbonStringKeys>[];
130135

@@ -140,12 +145,14 @@ class MainPane extends MainPaneBase {
140145
this.eventViewPlugin = new EventViewPlugin();
141146
this.apiPlaygroundPlugin = new ApiPlaygroundPlugin();
142147
this.snapshotPlugin = new SnapshotPlugin();
143-
this.contentModelPlugin = new ContentModelPlugin();
148+
this.ContentModelPanePlugin = new ContentModelPanePlugin();
144149
this.ribbonPlugin = createRibbonPlugin();
145-
this.contentModelRibbonPlugin = createRibbonPlugin();
150+
this.contentModelRibbonPlugin = new ContentModelRibbonPlugin();
146151
this.pasteOptionPlugin = createPasteOptionPlugin();
147152
this.emojiPlugin = createEmojiPlugin();
148153
this.updateContentPlugin = createUpdateContentPlugin(UpdateMode.OnDispose, this.onUpdate);
154+
this.contentModelPlugin = new ContentModelPlugin();
155+
this.formatPainterPlugin = new FormatPainterPlugin();
149156
this.mainWindowButtons = getButtons([
150157
...AllButtonKeys,
151158
darkMode,
@@ -417,7 +424,7 @@ class MainPane extends MainPaneBase {
417424
this.eventViewPlugin,
418425
this.apiPlaygroundPlugin,
419426
this.snapshotPlugin,
420-
this.contentModelPlugin,
427+
this.ContentModelPanePlugin,
421428
];
422429
}
423430

@@ -429,9 +436,11 @@ class MainPane extends MainPaneBase {
429436
...this.toggleablePlugins,
430437
this.ribbonPlugin,
431438
this.contentModelRibbonPlugin,
432-
this.contentModelPlugin.getInnerRibbonPlugin(),
439+
this.ContentModelPanePlugin.getInnerRibbonPlugin(),
433440
this.pasteOptionPlugin,
434441
this.emojiPlugin,
442+
this.contentModelPlugin,
443+
this.formatPainterPlugin,
435444
];
436445

437446
if (this.state.showSidePane || this.state.popoutWindow) {

demo/scripts/controls/contentModel/components/format/BlockFormatView.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import * as React from 'react';
22
import { BackgroundColorFormatRenderer } from './formatPart/BackgroundColorFormatRenderer';
3+
import { BorderFormatRenderers } from './formatPart/BorderFormatRenderers';
34
import { ContentModelBlockFormat, ContentModelSegmentFormat } from 'roosterjs-content-model';
45
import { DirectionFormatRenderers } from './formatPart/DirectionFormatRenderers';
56
import { FormatRenderer } from './utils/FormatRenderer';
@@ -16,6 +17,7 @@ const BlockFormatRenders: FormatRenderer<ContentModelBlockFormat>[] = [
1617
PaddingFormatRenderer,
1718
LineHeightFormatRenderer,
1819
WhiteSpaceFormatRenderer,
20+
...BorderFormatRenderers,
1921
];
2022

2123
export function BlockFormatView(props: { format: ContentModelSegmentFormat }) {
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
.modelDivider {
2-
background-color: #ccf;
2+
background-color: #c0f;
33
}

demo/scripts/controls/contentModel/components/model/ContentModelDividerView.tsx

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,31 @@
11
import * as React from 'react';
2-
import { BlockFormatView } from '../format/BlockFormatView';
3-
import { ContentModelDivider } from 'roosterjs-content-model';
2+
import { BackgroundColorFormatRenderer } from '../format/formatPart/BackgroundColorFormatRenderer';
3+
import { BorderFormatRenderers } from '../format/formatPart/BorderFormatRenderers';
4+
import { ContentModelDivider, ContentModelDividerFormat } from 'roosterjs-content-model';
45
import { ContentModelView } from '../ContentModelView';
6+
import { DirectionFormatRenderers } from '../format/formatPart/DirectionFormatRenderers';
7+
import { DisplayFormatRenderer } from '../format/formatPart/DisplayFormatRenderer';
8+
import { FormatRenderer } from '../format/utils/FormatRenderer';
9+
import { FormatView } from '../format/FormatView';
10+
import { LineHeightFormatRenderer } from '../format/formatPart/LineHeightFormatRenderer';
11+
import { MarginFormatRenderer } from '../format/formatPart/MarginFormatRenderer';
12+
import { PaddingFormatRenderer } from '../format/formatPart/PaddingFormatRenderer';
13+
import { SizeFormatRenderers } from '../format/formatPart/SizeFormatRenderers';
514
import { useProperty } from '../../hooks/useProperty';
15+
import { WhiteSpaceFormatRenderer } from '../format/formatPart/WhiteSpaceFormatRenderer';
616

717
const styles = require('./ContentModelDividerView.scss');
18+
const DividerFormatRenders: FormatRenderer<ContentModelDividerFormat>[] = [
19+
BackgroundColorFormatRenderer,
20+
...DirectionFormatRenderers,
21+
MarginFormatRenderer,
22+
PaddingFormatRenderer,
23+
LineHeightFormatRenderer,
24+
WhiteSpaceFormatRenderer,
25+
...BorderFormatRenderers,
26+
DisplayFormatRenderer,
27+
...SizeFormatRenderers,
28+
];
829

930
export function ContentModelDividerView(props: { divider: ContentModelDivider }) {
1031
const { divider } = props;
@@ -29,7 +50,7 @@ export function ContentModelDividerView(props: { divider: ContentModelDivider })
2950
}, [tagName]);
3051

3152
const getFormat = React.useCallback(() => {
32-
return <BlockFormatView format={divider.format} />;
53+
return <FormatView format={divider.format} renderers={DividerFormatRenders} />;
3354
}, [divider.format]);
3455

3556
return (

demo/scripts/controls/contentModel/components/model/ContentModelQuoteView.tsx

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,14 @@
11
import * as React from 'react';
2-
import { BackgroundColorFormatRenderer } from '../format/formatPart/BackgroundColorFormatRenderer';
2+
import { BlockFormatView } from '../format/BlockFormatView';
33
import { BlockGroupContentView } from './BlockGroupContentView';
4-
import { BorderFormatRenderers } from '../format/formatPart/BorderFormatRenderers';
54
import { ContentModelView } from '../ContentModelView';
6-
import { DirectionFormatRenderers } from '../format/formatPart/DirectionFormatRenderers';
75
import { FontFamilyFormatRenderer } from '../format/formatPart/FontFamilyFormatRenderer';
86
import { FontSizeFormatRenderer } from '../format/formatPart/FontSizeFormatRenderer';
97
import { FormatRenderer } from '../format/utils/FormatRenderer';
108
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';
149
import { TextColorFormatRenderer } from '../format/formatPart/TextColorFormatRenderer';
15-
import { WhiteSpaceFormatRenderer } from '../format/formatPart/WhiteSpaceFormatRenderer';
1610
import {
1711
ContentModelQuote,
18-
ContentModelQuoteFormat,
1912
ContentModelSegmentFormat,
2013
hasSelectionInBlock,
2114
} from 'roosterjs-content-model';
@@ -27,15 +20,6 @@ import {
2720

2821
const styles = require('./ContentModelQuoteView.scss');
2922

30-
const QuoteBlockFormatRenders: FormatRenderer<ContentModelQuoteFormat>[] = [
31-
BackgroundColorFormatRenderer,
32-
...DirectionFormatRenderers,
33-
MarginFormatRenderer,
34-
PaddingFormatRenderer,
35-
LineHeightFormatRenderer,
36-
WhiteSpaceFormatRenderer,
37-
...BorderFormatRenderers,
38-
];
3923
const QuoteSegmentFormatRenders: FormatRenderer<ContentModelSegmentFormat>[] = [
4024
TextColorFormatRenderer,
4125
FontSizeFormatRenderer,
@@ -54,7 +38,7 @@ export function ContentModelQuoteView(props: { quote: ContentModelQuote }) {
5438
const getFormat = React.useCallback(() => {
5539
return (
5640
<>
57-
<FormatView format={quote.format} renderers={QuoteBlockFormatRenders} />
41+
<BlockFormatView format={quote.format} />
5842
<FormatView
5943
format={quote.quoteSegmentFormat}
6044
renderers={QuoteSegmentFormatRenders}

demo/scripts/controls/contentModel/components/model/ContentModelTableCellView.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { FormatView } from '../format/FormatView';
1010
import { MetadataView } from '../format/MetadataView';
1111
import { PaddingFormatRenderer } from '../format/formatPart/PaddingFormatRenderer';
1212
import { TableCellMetadataFormatRender } from '../format/formatPart/TableCellMetadataFormatRender';
13+
import { TextColorFormatRenderer } from '../format/formatPart/TextColorFormatRenderer';
1314
import { updateTableCellMetadata } from 'roosterjs-content-model/lib/modelApi/metadata/updateTableCellMetadata';
1415
import { useProperty } from '../../hooks/useProperty';
1516
import { VerticalAlignFormatRenderer } from '../format/formatPart/VerticalAlignFormatRenderer';
@@ -30,6 +31,7 @@ const TableCellFormatRenderers: FormatRenderer<ContentModelTableCellFormat>[] =
3031
PaddingFormatRenderer,
3132
VerticalAlignFormatRenderer,
3233
WordBreakFormatRenderer,
34+
TextColorFormatRenderer,
3335
];
3436

3537
export function ContentModelTableCellView(props: { cell: ContentModelTableCell }) {
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import { EditorPlugin, IEditor, PluginEvent, PluginEventType } from 'roosterjs-editor-types';
2+
import {
3+
applySegmentFormat,
4+
ContentModelSegmentFormat,
5+
getSegmentFormat,
6+
IExperimentalContentModelEditor,
7+
} from 'roosterjs-content-model';
8+
9+
const FORMATPAINTERCURSOR_SVG = require('./formatpaintercursor.svg');
10+
const FORMATPAINTERCURSOR_STYLE = `;cursor: url("${FORMATPAINTERCURSOR_SVG}") 8.5 16, auto`;
11+
const CURSOR_REGEX = /;?\s*cursor:\s*url\(\".*?\"\)[^;]*/gi;
12+
13+
interface FormatPainterFormatHolder {
14+
format: ContentModelSegmentFormat | null;
15+
}
16+
17+
export default class FormatPainterPlugin implements EditorPlugin {
18+
private editor: IExperimentalContentModelEditor | null = null;
19+
20+
getName() {
21+
return 'FormatPainter';
22+
}
23+
24+
initialize(editor: IEditor) {
25+
this.editor = editor as IExperimentalContentModelEditor;
26+
}
27+
28+
dispose() {
29+
this.editor = null;
30+
}
31+
32+
onPluginEvent(event: PluginEvent) {
33+
if (this.editor && event.eventType == PluginEventType.MouseUp) {
34+
const formatHolder = getFormatHolder(this.editor);
35+
36+
if (formatHolder.format) {
37+
applySegmentFormat(this.editor, formatHolder.format);
38+
formatHolder.format = null;
39+
40+
setFormatPainterCursor(this.editor, false /*isOn*/);
41+
}
42+
}
43+
}
44+
45+
static startFormatPainter(editor: IExperimentalContentModelEditor) {
46+
const formatHolder = getFormatHolder(editor);
47+
const format = getSegmentFormat(editor);
48+
49+
if (format) {
50+
formatHolder.format = { ...format };
51+
setFormatPainterCursor(editor, true /*isOn*/);
52+
}
53+
}
54+
}
55+
56+
function getFormatHolder(editor: IEditor): FormatPainterFormatHolder {
57+
return editor.getCustomData('__FormatPainterFormat', () => {
58+
return {} as FormatPainterFormatHolder;
59+
});
60+
}
61+
62+
function setFormatPainterCursor(editor: IEditor, isOn: boolean) {
63+
let styles = editor.getEditorDomAttribute('style') || '';
64+
styles = styles.replace(CURSOR_REGEX, '');
65+
66+
if (isOn) {
67+
styles += FORMATPAINTERCURSOR_STYLE;
68+
}
69+
70+
editor.setEditorDomAttribute('style', styles);
71+
}
Lines changed: 22 additions & 0 deletions
Loading

demo/scripts/controls/editor/ExperimentalContentModelEditor.ts

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,20 @@
11
import { Editor } from 'roosterjs-editor-core';
22
import { EditorOptions, SelectionRangeTypes } from 'roosterjs-editor-types';
33
import {
4-
getComputedStyles,
5-
Position,
6-
restoreContentWithEntityPlaceholder,
7-
} from 'roosterjs-editor-dom';
8-
import {
9-
EditorContext,
104
ContentModelDocument,
5+
ContentModelSegmentFormat,
116
contentModelToDom,
127
domToContentModel,
138
DomToModelOption,
9+
EditorContext,
1410
IExperimentalContentModelEditor,
1511
ModelToDomOption,
1612
} from 'roosterjs-content-model';
13+
import {
14+
getComputedStyles,
15+
Position,
16+
restoreContentWithEntityPlaceholder,
17+
} from 'roosterjs-editor-dom';
1718

1819
/**
1920
* !!! This is a temporary interface and will be removed in the future !!!
@@ -23,6 +24,7 @@ import {
2324
export default class ExperimentalContentModelEditor extends Editor
2425
implements IExperimentalContentModelEditor {
2526
private getDarkColor: ((lightColor: string) => string) | undefined;
27+
private pendingFormat: ContentModelSegmentFormat | null = null;
2628

2729
/**
2830
* Creates an instance of ExperimentalContentModelEditor
@@ -88,4 +90,20 @@ export default class ExperimentalContentModelEditor extends Editor
8890
this.select(range);
8991
}
9092
}
93+
94+
/**
95+
* Get current pending format if any. A pending format is a format that user set when selection is collapsed,
96+
* it will be applied when next time user input something
97+
*/
98+
getPendingFormat(): ContentModelSegmentFormat | null {
99+
return this.pendingFormat;
100+
}
101+
102+
/**
103+
* Set current pending format if any. A pending format is a format that user set when selection is collapsed,
104+
* it will be applied when next time user input something
105+
*/
106+
setPendingFormat(format: ContentModelSegmentFormat | null) {
107+
this.pendingFormat = format;
108+
}
91109
}

0 commit comments

Comments
 (0)