Skip to content

Commit

Permalink
Merge pull request #2126 from microsoft/u/juliaroldi/paste-image
Browse files Browse the repository at this point in the history
Paste/Insert Image according to the visible viewport
  • Loading branch information
juliaroldi authored Oct 6, 2023
2 parents fc2ec5a + b75fc25 commit 9b6b52b
Show file tree
Hide file tree
Showing 34 changed files with 468 additions and 50 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -146,8 +146,14 @@ function mergeParagraph(

newParagraph.segments.splice(segmentIndex + i, 0, segment);

if (context && segment.segmentType == 'Entity') {
context.newEntities.push(segment);
if (context) {
if (segment.segmentType == 'Entity') {
context.newEntities.push(segment);
}

if (segment.segmentType == 'Image') {
context.newImages.push(segment);
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,15 @@ export function formatWithContentModel(
newEntities: [],
deletedEntities: [],
rawEvent,
newImages: [],
};
let selection: DOMSelection | undefined;

if (formatter(model, context)) {
const writeBack = () => {
handleNewEntities(editor, context);
handleDeletedEntities(editor, context);
handleImages(editor, context);

selection =
editor.setContentModel(model, undefined /*options*/, onNodeCreated) || undefined;
Expand Down Expand Up @@ -130,3 +132,19 @@ function handleDeletedEntities(
}
);
}

function handleImages(editor: IContentModelEditor, context: FormatWithContentModelContext) {
if (context.newImages.length > 0) {
const viewport = editor.getVisibleViewport();
if (viewport) {
const { top, bottom, left, right } = viewport;
const minMaxImageSize = 10;
const maxWidth = Math.max(right - left, minMaxImageSize);
const maxHeight = Math.max(bottom - top, minMaxImageSize);
context.newImages.forEach(image => {
image.format.maxHeight = `${maxHeight}px`;
image.format.maxWidth = `${maxWidth}px`;
});
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import type { EntityOperation } from 'roosterjs-editor-types';
import type {
ContentModelDocument,
ContentModelEntity,
ContentModelImage,
DOMSelection,
OnNodeCreated,
} from 'roosterjs-content-model-types';
Expand Down Expand Up @@ -35,6 +36,11 @@ export interface FormatWithContentModelContext {
*/
readonly deletedEntities: DeletedEntity[];

/**
* Images inserted in the editor that needs to have their size adjusted
*/
readonly newImages: ContentModelImage[];

/**
* Raw Event that triggers this format call
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ describe('ContentModelFormatPlugin', () => {
cacheContentModel: () => {},
isDarkMode: () => false,
triggerPluginEvent: jasmine.createSpy('triggerPluginEvent'),
getVisibleViewport: jasmine.createSpy('getVisibleViewport'),
} as any) as IContentModelEditor;
const state = {
defaultFormat: {},
Expand Down Expand Up @@ -215,6 +216,7 @@ describe('ContentModelFormatPlugin', () => {

const setContentModel = jasmine.createSpy('setContentModel');
const triggerPluginEvent = jasmine.createSpy('triggerPluginEvent');
const getVisibleViewport = jasmine.createSpy('getVisibleViewport');
const model = createContentModelDocument();
const text = createText('test a test', { fontFamily: 'Arial' });
const marker = createSelectionMarker();
Expand All @@ -232,6 +234,7 @@ describe('ContentModelFormatPlugin', () => {
cacheContentModel: () => {},
isDarkMode: () => false,
triggerPluginEvent,
getVisibleViewport,
} as any) as IContentModelEditor;
const state = {
defaultFormat: {},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ describe('ContentModelCopyPastePlugin |', () => {
let pasteSpy: jasmine.Spy;
let cloneModelSpy: jasmine.Spy;
let transformToDarkColorSpy: jasmine.Spy;
let getVisibleViewportSpy: jasmine.Spy;

beforeEach(() => {
div = document.createElement('div');
Expand All @@ -64,6 +65,7 @@ describe('ContentModelCopyPastePlugin |', () => {
setContentModelSpy = jasmine.createSpy('setContentModel');
pasteSpy = jasmine.createSpy('paste_');
isDisposed = jasmine.createSpy('isDisposed');
getVisibleViewportSpy = jasmine.createSpy('getVisibleViewport');

cloneModelSpy = spyOn(cloneModelFile, 'cloneModel').and.callFake(
(model: any) => pasteModelValue
Expand Down Expand Up @@ -123,6 +125,7 @@ describe('ContentModelCopyPastePlugin |', () => {
},
transformToDarkColor: transformToDarkColorSpy,
isDisposed,
getVisibleViewport: getVisibleViewportSpy,
});

plugin.initialize(editor);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ describe(ID, () => {
expect(processPastedContentFromExcel.processPastedContentFromExcel).toHaveBeenCalled();
});

it('E2E paste a simage', () => {
it('E2E paste as image', () => {
if (Browser.isFirefox) {
return;
}
Expand All @@ -68,7 +68,10 @@ describe(ID, () => {
{
segmentType: 'Image',
src: 'https://github.com/microsoft/roosterjs',
format: { maxWidth: '100%' },
format: {
maxWidth: '100px',
maxHeight: '100px',
},
dataset: {},
},
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,14 @@ export function initEditor(id: string) {

let options: ContentModelEditorOptions = {
plugins: [new ContentModelPastePlugin()],
getVisibleViewport: () => {
return {
top: 100,
bottom: 200,
left: 100,
right: 200,
};
},
};

let editor = new ContentModelEditor(node as HTMLDivElement, options);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,11 @@ describe('handleKeyboardEventResult', () => {
const mockedModel = 'MODEL' as any;
const which = 'WHICH' as any;
(<any>mockedEvent).which = which;
const context: FormatWithContentModelContext = { newEntities: [], deletedEntities: [] };
const context: FormatWithContentModelContext = {
newEntities: [],
deletedEntities: [],
newImages: [],
};
const result = handleKeyboardEventResult(
mockedEditor,
mockedModel,
Expand All @@ -64,7 +68,11 @@ describe('handleKeyboardEventResult', () => {

it('DeleteResult.NotDeleted', () => {
const mockedModel = 'MODEL' as any;
const context: FormatWithContentModelContext = { newEntities: [], deletedEntities: [] };
const context: FormatWithContentModelContext = {
newEntities: [],
deletedEntities: [],
newImages: [],
};
const result = handleKeyboardEventResult(
mockedEditor,
mockedModel,
Expand All @@ -84,7 +92,11 @@ describe('handleKeyboardEventResult', () => {

it('DeleteResult.Range', () => {
const mockedModel = 'MODEL' as any;
const context: FormatWithContentModelContext = { newEntities: [], deletedEntities: [] };
const context: FormatWithContentModelContext = {
newEntities: [],
deletedEntities: [],
newImages: [],
};
const result = handleKeyboardEventResult(
mockedEditor,
mockedModel,
Expand All @@ -106,7 +118,11 @@ describe('handleKeyboardEventResult', () => {

it('DeleteResult.NothingToDelete', () => {
const mockedModel = 'MODEL' as any;
const context: FormatWithContentModelContext = { newEntities: [], deletedEntities: [] };
const context: FormatWithContentModelContext = {
newEntities: [],
deletedEntities: [],
newImages: [],
};
const result = handleKeyboardEventResult(
mockedEditor,
mockedModel,
Expand Down
Loading

0 comments on commit 9b6b52b

Please sign in to comment.