Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Port Image Edit Operations #2670

Merged
merged 62 commits into from
Jun 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
52f30e4
WIP
juliaroldi Apr 5, 2024
5bb6b15
fix conflicts
juliaroldi Apr 5, 2024
36f592c
conflict
juliaroldi Apr 5, 2024
ec80d60
WIP
juliaroldi Apr 5, 2024
4aa4828
Merge branch 'master' of https://github.com/microsoft/roosterjs into …
juliaroldi Apr 5, 2024
ec97315
WIP
juliaroldi Apr 5, 2024
531985b
WIP
juliaroldi Apr 8, 2024
b91e403
croppers
juliaroldi Apr 10, 2024
7a06999
porting
juliaroldi Apr 11, 2024
091f2db
WIPP
juliaroldi Apr 12, 2024
c11771f
fix conflicts
juliaroldi Apr 17, 2024
13dcca1
WIP
juliaroldi Apr 18, 2024
816b769
Merge branch 'master' of https://github.com/microsoft/roosterjs into …
juliaroldi Apr 22, 2024
cc260bc
WIP
juliaroldi Apr 23, 2024
b7a0ca8
conflicts
juliaroldi Apr 23, 2024
a1586a5
fixes
juliaroldi Apr 23, 2024
89d51b1
WIP
juliaroldi Apr 24, 2024
63125da
Merge branch 'master' of https://github.com/microsoft/roosterjs into …
juliaroldi Apr 24, 2024
21599f9
fix build
juliaroldi Apr 25, 2024
cca526e
remove function
juliaroldi Apr 25, 2024
7b5cd18
wip: clean/refactor
juliaroldi Apr 26, 2024
75bea9e
wip: clean
juliaroldi Apr 26, 2024
554e3da
clean
juliaroldi Apr 26, 2024
207657d
wip
juliaroldi Apr 26, 2024
3806813
Merge branch 'u/juliaroldi/image-span' of https://github.com/microsof…
juliaroldi Apr 29, 2024
3221722
WIP
juliaroldi Apr 29, 2024
8a50224
Merge branch 'u/juliaroldi/image-span' of https://github.com/microsof…
juliaroldi Apr 30, 2024
abe2b18
wip
juliaroldi Apr 30, 2024
5c15d3e
Merge branch 'u/juliaroldi/image-span' of https://github.com/microsof…
juliaroldi Apr 30, 2024
f91b48b
port image
juliaroldi Apr 30, 2024
f45bf71
wip
juliaroldi May 2, 2024
69b4204
conflicts
juliaroldi May 2, 2024
ee28ea4
test
juliaroldi May 20, 2024
d5e6775
conflict
juliaroldi May 20, 2024
4766498
WIP
juliaroldi May 21, 2024
3642b10
unit test
juliaroldi May 23, 2024
7ea11d5
test
juliaroldi May 24, 2024
da849be
Merge branch 'master' of https://github.com/microsoft/roosterjs into …
juliaroldi May 24, 2024
98d3520
test
juliaroldi May 24, 2024
cb87afd
test
juliaroldi May 28, 2024
814b54f
remove console.log
juliaroldi May 28, 2024
dd732bb
Merge branch 'master' into u/juliaroldi/port-image
juliaroldi May 28, 2024
d95360c
tests
juliaroldi May 29, 2024
71f830b
Merge branch 'u/juliaroldi/port-image' of https://github.com/microsof…
juliaroldi May 29, 2024
6251d8d
tests
juliaroldi May 29, 2024
ac8790f
changed to protected
juliaroldi May 29, 2024
6d86454
image operations
juliaroldi May 29, 2024
2ec3974
fix test
juliaroldi May 29, 2024
5e1be98
remove code
juliaroldi May 29, 2024
85198f2
Merge branch 'master' into u/juliaroldi/image-edit-operations
juliaroldi May 30, 2024
8b5961c
remove editor
juliaroldi Jun 3, 2024
357c7c7
Merge branch 'u/juliaroldi/image-edit-operations' of https://github.c…
juliaroldi Jun 3, 2024
53b044b
fix test
juliaroldi Jun 3, 2024
4c5963a
WIP
juliaroldi Jun 3, 2024
f86541c
fixes
juliaroldi Jun 4, 2024
3c465c6
fix test
juliaroldi Jun 4, 2024
27792a0
status
juliaroldi Jun 4, 2024
9a9abae
test
juliaroldi Jun 4, 2024
baff339
fix conflicts
juliaroldi Jun 4, 2024
4c8d7eb
add mutate block
juliaroldi Jun 4, 2024
26d6e90
fixes texts
juliaroldi Jun 5, 2024
9dd412a
Merge branch 'master' into u/juliaroldi/image-edit-operations
juliaroldi Jun 5, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 81 additions & 0 deletions demo/scripts/controlsV2/demoButtons/createImageEditButtons.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { ImageEditor } from 'roosterjs-content-model-types';
import type { RibbonButton } from '../roosterjsReact/ribbon';

/**
* @internal
* "Image Crop" button on the format ribbon
*/
function createImageCropButton(handler: ImageEditor): RibbonButton<'buttonNameCropImage'> {
return {
key: 'buttonNameCropImage',
unlocalizedText: 'Crop Image',
iconName: 'Crop',
isDisabled: formatState =>
!formatState.canAddImageAltText || !handler.isOperationAllowed('crop'),
onClick: () => {
handler.cropImage();
},
};
}

const directions: Record<string, string> = {
left: 'Left',
right: 'Right',
};

/**
* @internal
* "Image Rotate" button on the format ribbon
*/
function createImageRotateButton(handler: ImageEditor): RibbonButton<'buttonNameRotateImage'> {
return {
key: 'buttonNameRotateImage',
unlocalizedText: 'Rotate Image',
iconName: 'Rotate',
dropDownMenu: {
items: directions,
},
isDisabled: formatState => !formatState.canAddImageAltText,
onClick: (_editor, direction) => {
const rotateDirection = direction as 'left' | 'right';
const rad = degreeToRad(rotateDirection == 'left' ? 270 : 90);
handler.rotateImage(rad);
},
};
}

const flipDirections: Record<string, string> = {
horizontal: 'horizontal',
vertical: 'vertical',
};

/**
* @internal
* "Image Flip" button on the format ribbon
*/
function createImageFlipButton(handler: ImageEditor): RibbonButton<'buttonNameFlipImage'> {
return {
key: 'buttonNameFlipImage',
unlocalizedText: 'Flip Image',
iconName: 'ImagePixel',
dropDownMenu: {
items: flipDirections,
},
isDisabled: formatState => !formatState.canAddImageAltText,
onClick: (_editor, flipDirection) => {
handler.flipImage(flipDirection as 'horizontal' | 'vertical');
},
};
}

export const createImageEditButtons = (handler: ImageEditor) => {
return [
createImageCropButton(handler),
createImageRotateButton(handler),
createImageFlipButton(handler),
];
};

const degreeToRad = (degree: number) => {
return degree * (Math.PI / 180);
};
25 changes: 13 additions & 12 deletions demo/scripts/controlsV2/mainPane/MainPane.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,11 @@ import { ApiPlaygroundPlugin } from '../sidePane/apiPlayground/ApiPlaygroundPlug
import { ContentModelPanePlugin } from '../sidePane/contentModel/ContentModelPanePlugin';
import { createEmojiPlugin } from '../roosterjsReact/emoji';
import { createImageEditMenuProvider } from '../roosterjsReact/contextMenu/menus/createImageEditMenuProvider';
import { createLegacyPlugins } from '../plugins/createLegacyPlugins';
import { createListEditMenuProvider } from '../roosterjsReact/contextMenu/menus/createListEditMenuProvider';
import { createPasteOptionPlugin } from '../roosterjsReact/pasteOptions';
import { createRibbonPlugin, Ribbon, RibbonButton, RibbonPlugin } from '../roosterjsReact/ribbon';
import { darkModeButton } from '../demoButtons/darkModeButton';
import { Editor } from 'roosterjs-content-model-core';
import { EditorAdapter } from 'roosterjs-editor-adapter';
import { EditorOptionsPlugin } from '../sidePane/editorOptions/EditorOptionsPlugin';
import { EventViewPlugin } from '../sidePane/eventViewer/EventViewPlugin';
import { exportContentButton } from '../demoButtons/exportContentButton';
Expand Down Expand Up @@ -54,6 +52,7 @@ import {
CustomReplacePlugin,
EditPlugin,
HyperlinkPlugin,
ImageEditPlugin,
MarkdownPlugin,
PastePlugin,
ShortcutPlugin,
Expand Down Expand Up @@ -100,6 +99,7 @@ export class MainPane extends React.Component<{}, MainPaneState> {
private formatPainterPlugin: FormatPainterPlugin;
private samplePickerPlugin: SamplePickerPlugin;
private snapshots: Snapshots;
private imageEditPlugin: ImageEditPlugin;

protected sidePane = React.createRef<SidePane>();
protected updateContentPlugin: UpdateContentPlugin;
Expand Down Expand Up @@ -137,6 +137,7 @@ export class MainPane extends React.Component<{}, MainPaneState> {
this.ribbonPlugin = createRibbonPlugin();
this.formatPainterPlugin = new FormatPainterPlugin();
this.samplePickerPlugin = new SamplePickerPlugin();
this.imageEditPlugin = new ImageEditPlugin();

this.state = {
showSidePane: window.location.hash != '',
Expand Down Expand Up @@ -288,7 +289,11 @@ export class MainPane extends React.Component<{}, MainPaneState> {
private renderRibbon() {
return (
<Ribbon
buttons={getButtons(this.state.activeTab, this.formatPainterPlugin)}
buttons={getButtons(
this.state.activeTab,
this.formatPainterPlugin,
this.imageEditPlugin
)}
plugin={this.ribbonPlugin}
dir={this.state.isRtl ? 'rtl' : 'ltr'}
/>
Expand All @@ -310,14 +315,7 @@ export class MainPane extends React.Component<{}, MainPaneState> {
private resetEditor() {
this.setState({
editorCreator: (div: HTMLDivElement, options: EditorOptions) => {
const legacyPluginList = createLegacyPlugins(this.state.initState);

return legacyPluginList.length > 0
? new EditorAdapter(div, {
...options,
legacyPlugins: legacyPluginList,
})
: new Editor(div, options);
return new Editor(div, options);
},
});
}
Expand Down Expand Up @@ -505,13 +503,16 @@ export class MainPane extends React.Component<{}, MainPaneState> {
pluginList.tableEdit && new TableEditPlugin(),
pluginList.watermark && new WatermarkPlugin(watermarkText),
pluginList.markdown && new MarkdownPlugin(markdownOptions),
pluginList.imageEditPlugin && this.imageEditPlugin,
pluginList.emoji && createEmojiPlugin(),
pluginList.pasteOption && createPasteOptionPlugin(),
pluginList.sampleEntity && new SampleEntityPlugin(),
pluginList.contextMenu && createContextMenuPlugin(),
pluginList.contextMenu && listMenu && createListEditMenuProvider(),
pluginList.contextMenu && tableMenu && createTableEditMenuProvider(),
pluginList.contextMenu && imageMenu && createImageEditMenuProvider(),
pluginList.contextMenu &&
imageMenu &&
createImageEditMenuProvider(this.imageEditPlugin),
pluginList.hyperlink &&
new HyperlinkPlugin(
linkTitle?.indexOf(UrlPlaceholder) >= 0
Expand Down
18 changes: 0 additions & 18 deletions demo/scripts/controlsV2/plugins/createLegacyPlugins.ts

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ const ImageRotateMenuItem: ContextMenuItem<ImageEditMenuItemStringKey, ImageEdit
imageEditor.canRegenerateImage(node as HTMLImageElement)
);
},
onClick: (key, editor, node, strings, uiUtilities, imageEdit) => {
onClick: (key, _editor, _node, _strings, _uiUtilities, imageEdit) => {
switch (key) {
case 'menuNameImageRotateLeft':
imageEdit?.rotateImage(-Math.PI / 2);
Expand All @@ -116,7 +116,7 @@ const ImageFlipMenuItem: ContextMenuItem<ImageEditMenuItemStringKey, ImageEditor
imageEditor.canRegenerateImage(node as HTMLImageElement)
);
},
onClick: (key, editor, node, strings, uiUtilities, imageEdit) => {
onClick: (key, _editor, _node, _strings, _uiUtilities, imageEdit) => {
switch (key) {
case 'menuNameImageRotateFlipHorizontally':
imageEdit?.flipImage('horizontal');
Expand All @@ -137,7 +137,7 @@ const ImageCropMenuItem: ContextMenuItem<ImageEditMenuItemStringKey, ImageEditor
imageEditor.canRegenerateImage(node as HTMLImageElement)
);
},
onClick: (_, editor, node, strings, uiUtilities, imageEdit) => {
onClick: (_, _editor, _node, _strings, _uiUtilities, imageEdit) => {
imageEdit?.cropImage();
},
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,9 @@ const initialState: OptionState = {
pasteOption: true,
sampleEntity: true,
markdown: true,
imageEditPlugin: true,
hyperlink: true,
customReplace: true,

// Legacy plugins
imageEdit: false,
},
defaultFormat: {
fontFamily: 'Calibri',
Expand All @@ -32,7 +30,6 @@ const initialState: OptionState = {
linkTitle: 'Ctrl+Click to follow the link:' + UrlPlaceholder,
watermarkText: 'Type content here ...',
forcePreserveRatio: false,
applyChangesOnMouseUp: false,
isRtl: false,
disableCache: false,
tableFeaturesContainerSelector: '#' + 'EditorContainer',
Expand Down
8 changes: 2 additions & 6 deletions demo/scripts/controlsV2/sidePane/editorOptions/OptionState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,6 @@ import { AutoFormatOptions, CustomReplace, MarkdownOptions } from 'roosterjs-con
import type { SidePaneElementProps } from '../SidePaneElement';
import type { ContentModelSegmentFormat, ExperimentalFeature } from 'roosterjs-content-model-types';

export interface LegacyPluginList {
imageEdit: boolean;
}

export interface NewPluginList {
autoFormat: boolean;
edit: boolean;
Expand All @@ -19,10 +15,11 @@ export interface NewPluginList {
sampleEntity: boolean;
markdown: boolean;
hyperlink: boolean;
imageEditPlugin: boolean;
customReplace: boolean;
}

export interface BuildInPluginList extends LegacyPluginList, NewPluginList {}
export interface BuildInPluginList extends NewPluginList {}

export interface OptionState {
pluginList: BuildInPluginList;
Expand All @@ -46,7 +43,6 @@ export interface OptionState {
// Editor options
isRtl: boolean;
disableCache: boolean;
applyChangesOnMouseUp: boolean;
experimentalFeatures: Set<ExperimentalFeature>;
}

Expand Down
22 changes: 6 additions & 16 deletions demo/scripts/controlsV2/sidePane/editorOptions/OptionsPane.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ import { Code } from './Code';
import { DefaultFormatPane } from './DefaultFormatPane';
import { EditorCode } from './codes/EditorCode';
import { ExperimentalFeatures } from './ExperimentalFeatures';
import { LegacyPlugins, Plugins } from './Plugins';
import { MainPane } from '../../mainPane/MainPane';
import { OptionPaneProps, OptionState } from './OptionState';
import { Plugins } from './Plugins';

const htmlStart =
'<html>\n' +
Expand All @@ -23,8 +23,6 @@ const htmlButtons =
'<button id=buttonDark>Dark mode</button>\n';
'<button id=buttonDark>Dark Mode</button>\n';
const jsCode = '<script src="https://microsoft.github.io/roosterjs/rooster-min.js"></script>\n';
const legacyJsCode =
'<script src="https://microsoft.github.io/roosterjs/rooster-legacy-min.js"></script>\n<script src="https://microsoft.github.io/roosterjs/rooster-adapter-min.js"></script>\n';
const htmlEnd = '</body>\n' + '</html>';

export class OptionsPane extends React.Component<OptionPaneProps, OptionState> {
Expand All @@ -39,7 +37,7 @@ export class OptionsPane extends React.Component<OptionPaneProps, OptionState> {
}
render() {
const editorCode = new EditorCode(this.state);
const html = this.getHtml(editorCode.requireLegacyCode());
const html = this.getHtml();

return (
<div>
Expand All @@ -58,12 +56,6 @@ export class OptionsPane extends React.Component<OptionPaneProps, OptionState> {
</summary>
<Plugins state={this.state} resetState={this.resetState} />
</details>
<details>
<summary>
<b>Legacy Plugins</b>
</summary>
<LegacyPlugins state={this.state} resetState={this.resetState} />
</details>
<details>
<summary>
<b>Experimental features</b>
Expand Down Expand Up @@ -136,7 +128,7 @@ export class OptionsPane extends React.Component<OptionPaneProps, OptionState> {
pluginList: { ...this.state.pluginList },
defaultFormat: { ...this.state.defaultFormat },
forcePreserveRatio: this.state.forcePreserveRatio,
applyChangesOnMouseUp: this.state.applyChangesOnMouseUp,

isRtl: this.state.isRtl,
disableCache: this.state.disableCache,
tableFeaturesContainerSelector: this.state.tableFeaturesContainerSelector,
Expand Down Expand Up @@ -165,7 +157,7 @@ export class OptionsPane extends React.Component<OptionPaneProps, OptionState> {
let code = editor.getCode();
let json = {
title: 'RoosterJs',
html: this.getHtml(editor.requireLegacyCode()),
html: this.getHtml(),
head: '',
js: code,
js_pre_processor: 'typescript',
Expand All @@ -188,9 +180,7 @@ export class OptionsPane extends React.Component<OptionPaneProps, OptionState> {
}, true);
};

private getHtml(requireLegacyCode: boolean) {
return `${htmlStart}${htmlButtons}${jsCode}${
requireLegacyCode ? legacyJsCode : ''
}${htmlEnd}`;
private getHtml() {
return `${htmlStart}${htmlButtons}${jsCode}${htmlEnd}`;
}
}
31 changes: 2 additions & 29 deletions demo/scripts/controlsV2/sidePane/editorOptions/Plugins.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
import * as React from 'react';
import { UrlPlaceholder } from './OptionState';
import type {
BuildInPluginList,
LegacyPluginList,
NewPluginList,
OptionState,
} from './OptionState';
import type { BuildInPluginList, NewPluginList, OptionState } from './OptionState';

const styles = require('./OptionsPane.scss');

Expand Down Expand Up @@ -101,29 +96,6 @@ abstract class PluginsBase<PluginKey extends keyof BuildInPluginList> extends Re
};
}

export class LegacyPlugins extends PluginsBase<keyof LegacyPluginList> {
private forcePreserveRatio = React.createRef<HTMLInputElement>();

render() {
return (
<table>
<tbody>
{this.renderPluginItem(
'imageEdit',
'Image Edit Plugin',
this.renderCheckBox(
'Force preserve ratio',
this.forcePreserveRatio,
this.props.state.forcePreserveRatio,
(state, value) => (state.forcePreserveRatio = value)
)
)}
</tbody>
</table>
);
}
}

export class Plugins extends PluginsBase<keyof NewPluginList> {
private allowExcelNoBorderTable = React.createRef<HTMLInputElement>();
private listMenu = React.createRef<HTMLInputElement>();
Expand Down Expand Up @@ -292,6 +264,7 @@ export class Plugins extends PluginsBase<keyof NewPluginList> {
)
)}
{this.renderPluginItem('customReplace', 'Custom Replace')}
{this.renderPluginItem('imageEditPlugin', 'ImageEditPlugin')}
</tbody>
</table>
);
Expand Down
Loading
Loading