Skip to content

Commit

Permalink
Merge pull request #1837 from microsoft/u/juliaroldi/bump-roosterjs-v…
Browse files Browse the repository at this point in the history
…ersion

Bump RoosterJS to v8.48.0 and Content-Model package to 0.7.0
  • Loading branch information
juliaroldi authored May 26, 2023
2 parents 3862e3b + 563b42a commit 0e88e6b
Show file tree
Hide file tree
Showing 123 changed files with 4,861 additions and 2,323 deletions.
Binary file added assets/design-charts/BackwardDeleteWord.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/design-charts/ForwardDeleteWord.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as React from 'react';
import ApiPaneProps from '../ApiPaneProps';
import { ExperimentalFeatures, IEditor, PositionType, Region } from 'roosterjs-editor-types';
import { IEditor, PositionType, Region } from 'roosterjs-editor-types';
import {
createRange,
getSelectedBlockElementsInRegion,
Expand Down Expand Up @@ -55,11 +55,7 @@ export default class GetSelectedRegionsPane extends React.Component<

function Region({ region, editor, index }: { region: Region; editor: IEditor; index: number }) {
const selectRegion = React.useCallback(() => {
const blocks = getSelectedBlockElementsInRegion(
region,
undefined /* createBlockIfEmpty */,
editor.isFeatureEnabled(ExperimentalFeatures.DefaultFormatInSpan)
);
const blocks = getSelectedBlockElementsInRegion(region);
if (blocks.length > 0) {
const range = createRange(
blocks[0].getStartNode(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,10 @@ const initialState: BuildInPluginState = {
watermarkText: 'Type content here ...',
forcePreserveRatio: false,
experimentalFeatures: [
ExperimentalFeatures.DefaultFormatInSpan,
ExperimentalFeatures.AutoFormatList,
ExperimentalFeatures.ReusableContentModel,
ExperimentalFeatures.EditWithContentModel,
ExperimentalFeatures.InlineEntityReadOnlyDelimiters,
ExperimentalFeatures.DefaultFormatOnContainer,
],
isRtl: false,
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,13 @@ const FeatureNames: Partial<Record<ExperimentalFeatures, string>> = {
'Trigger formatting by a especial characters. Ex: (A), 1. i).',
[ExperimentalFeatures.ReuseAllAncestorListElements]:
"Reuse ancestor list elements even if they don't match the types from the list item.",
[ExperimentalFeatures.DefaultFormatInSpan]:
'When apply default format when initialize or user type, apply the format on a SPAN element.',
[ExperimentalFeatures.ReusableContentModel]:
'Reuse existing DOM structure if possible when convert Content Model back to DOM tree',
[ExperimentalFeatures.EditWithContentModel]: 'Handle keyboard edit event with Content Model',
[ExperimentalFeatures.DeleteTableWithBackspace]:
'Delete a table selected with the table selector pressing Backspace key',
[ExperimentalFeatures.InlineEntityReadOnlyDelimiters]:
'Add read entities around read only entities to handle browser edge cases.',
[ExperimentalFeatures.DefaultFormatOnContainer]: 'Apply default format on editor container',
[ExperimentalFeatures.ContentModelPaste]: 'Paste with content model',
};

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "roosterjs",
"version": "8.47.0",
"version": "8.48.0",
"description": "Framework-independent javascript editor",
"repository": {
"type": "git",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import ContextMenuItem from '../types/ContextMenuItem';
import createContextMenuProvider from '../utils/createContextMenuProvider';
import showInputDialog from '../../inputDialog/utils/showInputDialog';
import { EditorPlugin, IEditor, ImageEditOperation } from 'roosterjs-editor-types';
import { DocumentCommand, EditorPlugin, IEditor, ImageEditOperation } from 'roosterjs-editor-types';
import { ImageEditMenuItemStringKey } from '../types/ContextMenuItemStringKeys';
import { LocalizedStrings } from '../../common/type/LocalizedStrings';
import { safeInstanceOf } from 'roosterjs-editor-dom';
Expand Down Expand Up @@ -163,6 +163,30 @@ const ImageRemoveMenuItem: ContextMenuItem<ImageEditMenuItemStringKey, ImageEdit
},
};

const ImageCopyMenuItem: ContextMenuItem<ImageEditMenuItemStringKey, ImageEdit> = {
key: 'menuNameImageCopy',
unlocalizedText: 'Copy image',
onClick: (_, editor, node, strings, uiUtilities, imageEdit) => {
if (editor.contains(node)) {
editor.addUndoSnapshot(() => {
editor.getDocument()?.execCommand(DocumentCommand.Copy);
}, 'CopyImage');
}
},
};

const ImageCutMenuItem: ContextMenuItem<ImageEditMenuItemStringKey, ImageEdit> = {
key: 'menuNameImageCut',
unlocalizedText: 'Cut image',
onClick: (_, editor, node, strings, uiUtilities, imageEdit) => {
if (editor.contains(node)) {
editor.addUndoSnapshot(() => {
editor.getDocument()?.execCommand(DocumentCommand.Cut);
}, 'CutImage');
}
},
};

function shouldShowImageEditItems(editor: IEditor, node: Node) {
return safeInstanceOf(node, 'HTMLImageElement') && node.isContentEditable;
}
Expand All @@ -184,6 +208,8 @@ export default function createImageEditMenuProvider(
ImageRemoveMenuItem,
ImageRotateMenuItem,
ImageFlipMenuItem,
ImageCopyMenuItem,
ImageCutMenuItem,
],
strings,
shouldShowImageEditItems,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ export type ImageEditMenuItemStringKey =
| 'menuNameImageRotateRight'
| 'menuNameImageRotateFlipHorizontally'
| 'menuNameImageRotateFlipVertically'
| 'menuNameImageCopy'
| 'menuNameImageCut'
| OkButtonStringKey
| CancelButtonStringKey;

Expand Down
3 changes: 2 additions & 1 deletion packages-ui/roosterjs-react/lib/ribbon/component/Ribbon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ export default function Ribbon<T extends string>(props: RibbonProps<T>) {
result.subMenuProps = {
shouldFocusOnMount: true,
focusZoneProps: { direction: FocusZoneDirection.bidirectional },
onDismiss: onDismiss,
onMenuDismissed: onDismiss,
onItemClick: onClick,
onRenderContextualMenuItem: dropDownMenu.allowLivePreview
? contextMenuItemRenderer
Expand Down Expand Up @@ -153,6 +153,7 @@ export default function Ribbon<T extends string>(props: RibbonProps<T>) {
moreCommandsBtn.key,
moreCommandsBtn.unlocalizedText
),
...props?.overflowButtonProps,
}}
/>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { computedSegmentFormatHandler } from '../formatHandlers/segment/computedSegmentFormatHandler';
import { ContentModelDocument } from '../publicTypes/group/ContentModelDocument';
import { createContentModelDocument } from '../modelApi/creators/createContentModelDocument';
import { createDomToModelContext } from './context/createDomToModelContext';
Expand Down Expand Up @@ -28,11 +27,6 @@ export default function domToContentModel(
if (safeInstanceOf(root, 'DocumentFragment')) {
context.elementProcessors.child(model, root, context);
} else {
if (!context.defaultFormatOnContainer) {
// For root element, use computed style as initial value of segment formats
parseFormat(root, [computedSegmentFormatHandler.parse], context.segmentFormat, context);
}

// Need to calculate direction (ltr or rtl), use it as initial value
parseFormat(root, [rootDirectionFormatHandler.parse], context.blockFormat, context);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,22 @@ export const entityProcessor: ElementProcessor<HTMLElement> = (group, element, c
context,
{ segment: isBlockEntity ? 'empty' : undefined, paragraph: 'empty' },
() => {
const entityModel = createEntity(element, isReadonly, context.segmentFormat, id, type);
const wrapperToUse = context.allowCacheElement
? element
: (element.cloneNode(true /* deep */) as HTMLElement);

if (!context.allowCacheElement) {
wrapperToUse.style.backgroundColor = element.style.backgroundColor || 'inherit';
wrapperToUse.style.color = element.style.color || 'inherit';
}

const entityModel = createEntity(
wrapperToUse,
isReadonly,
context.segmentFormat,
id,
type
);

// TODO: Need to handle selection for editable entity
if (context.isInSelection) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { createText } from '../../modelApi/creators/createText';
import { DomToModelContext } from '../../publicTypes/context/DomToModelContext';
import { ElementProcessor } from '../../publicTypes/context/ElementProcessor';
import { getRegularSelectionOffsets } from '../utils/getRegularSelectionOffsets';
import { hasSpacesOnly } from '../../domUtils/hasSpacesOnly';
import { hasSpacesOnly } from '../../domUtils/stringUtil';

/**
* @internal
Expand Down
10 changes: 0 additions & 10 deletions packages/roosterjs-content-model/lib/domUtils/hasSpacesOnly.ts

This file was deleted.

35 changes: 35 additions & 0 deletions packages/roosterjs-content-model/lib/domUtils/stringUtil.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// A regex to match text that only has space and CR
// We use real space char " " (\u0020) here but not "\s" since "\s" will also match "&nbsp;" (\u00A0) which is something we need to keep
const SPACE_TEXT_REGEX = /^[\r\n\t ]*$/;

const SPACES_REGEX = /[\u2000\u2009\u200a\u200b\u202f\u205f\u3000\s\t\r\n]/gm;
const PUNCTUATIONS = '.,?!:"()[]\\/';

/**
* @internal
*/
export function isPunctuation(char: string) {
return PUNCTUATIONS.indexOf(char) >= 0;
}

/**
* @internal
*/
export function isSpace(char: string) {
const code = char?.charCodeAt(0) ?? 0;
return code == 160 || code == 32 || SPACES_REGEX.test(char);
}

/**
* @internal
*/
export function hasSpacesOnly(txt: string): boolean {
return SPACE_TEXT_REGEX.test(txt);
}

/**
* @internal
*/
export function normalizeText(txt: string, isForward: boolean): string {
return txt.replace(isForward ? /^\u0020+/ : /\u0020+$/, '\u00A0');
}
14 changes: 2 additions & 12 deletions packages/roosterjs-content-model/lib/editor/ContentModelEditor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { ContentModelSegmentFormat } from '../publicTypes/format/ContentModelSeg
import { createContentModelEditorCore } from './createContentModelEditorCore';
import { EditorBase } from 'roosterjs-editor-core';
import { formatWithContentModel } from '../publicApi/utils/formatWithContentModel';
import { getOnDeleteEntityCallback } from './utils/handleKeyboardEventCommon';
import { mergeModel } from '../modelApi/common/mergeModel';
import { Position } from 'roosterjs-editor-dom';
import {
Expand Down Expand Up @@ -35,17 +36,6 @@ export default class ContentModelEditor
super(contentDiv, options, createContentModelEditorCore);
}

dispose() {
const { contentDiv, originalContainerFormat, defaultFormatOnContainer } = this.getCore();

if (defaultFormatOnContainer) {
contentDiv.style.setProperty('font-family', originalContainerFormat.fontFamily || null);
contentDiv.style.setProperty('font-size', originalContainerFormat.fontSize || null);
}

super.dispose();
}

/**
* Create Content Model from DOM tree in this editor
* @param option The option to customize the behavior of DOM to Content Model conversion
Expand Down Expand Up @@ -138,7 +128,7 @@ export default class ContentModelEditor
this,
'Paste',
model => {
mergeModel(model, pasteModel);
mergeModel(model, pasteModel, getOnDeleteEntityCallback(this));
return true;
},
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,5 @@ export const createEditorContext: CreateEditorContext = core => {
defaultFormat: core.defaultFormat,
darkColorHandler: core.darkColorHandler,
addDelimiterForEntity: core.addDelimiterForEntity,
defaultFormatOnContainer: core.defaultFormatOnContainer,
};
};
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import ContentModelBeforePasteEvent from '../../publicTypes/event/ContentModelBeforePasteEvent';
import domToContentModel from '../../domToModel/domToContentModel';
import { ContentModelEditorCore, CreatePasteModel } from '../../publicTypes/ContentModelEditorCore';
import {
ClipboardData,
EditorCore,
NodePosition,
PasteType,
PluginEventType,
} from 'roosterjs-editor-types';
import { ContentModelEditorCore, CreatePasteModel } from '../../publicTypes/ContentModelEditorCore';
import {
createDefaultHtmlSanitizerOptions,
createFragmentFromClipboardData,
Expand Down Expand Up @@ -44,7 +44,10 @@ export const createPasteModel: CreatePasteModel = (
event
);

return domToContentModel(fragment, core.api.createEditorContext(core), event.domToModelOption);
return domToContentModel(fragment, core.api.createEditorContext(core), {
...event.domToModelOption,
disableCacheElement: true,
});
};

/**
Expand Down
Loading

0 comments on commit 0e88e6b

Please sign in to comment.