Skip to content

Commit

Permalink
Merge pull request #1487 from microsoft/u/juliaroldi/version-8.40.0
Browse files Browse the repository at this point in the history
U/juliaroldi/version 8.40.0
  • Loading branch information
juliaroldi authored Jan 9, 2023
2 parents 20e3a02 + 07332f4 commit a279b70
Show file tree
Hide file tree
Showing 129 changed files with 9,081 additions and 2,459 deletions.
Original file line number Diff line number Diff line change
@@ -1,23 +1,76 @@
import * as React from 'react';
import { BackgroundColorFormatRenderer } from '../format/formatPart/BackgroundColorFormatRenderer';
import { BlockGroupContentView } from './BlockGroupContentView';
import { ContentModelQuote, hasSelectionInBlock } from 'roosterjs-content-model';
import { BorderFormatRenderers } from '../format/formatPart/BorderFormatRenderers';
import { ContentModelView } from '../ContentModelView';
import { DirectionFormatRenderers } from '../format/formatPart/DirectionFormatRenderers';
import { FontFamilyFormatRenderer } from '../format/formatPart/FontFamilyFormatRenderer';
import { FontSizeFormatRenderer } from '../format/formatPart/FontSizeFormatRenderer';
import { FormatRenderer } from '../format/utils/FormatRenderer';
import { FormatView } from '../format/FormatView';
import { LineHeightFormatRenderer } from '../format/formatPart/LineHeightFormatRenderer';
import { MarginFormatRenderer } from '../format/formatPart/MarginFormatRenderer';
import { PaddingFormatRenderer } from '../format/formatPart/PaddingFormatRenderer';
import { TextColorFormatRenderer } from '../format/formatPart/TextColorFormatRenderer';
import { WhiteSpaceFormatRenderer } from '../format/formatPart/WhiteSpaceFormatRenderer';
import {
ContentModelQuote,
ContentModelQuoteFormat,
ContentModelSegmentFormat,
hasSelectionInBlock,
} from 'roosterjs-content-model';
import {
BoldFormatRenderer,
ItalicFormatRenderer,
UnderlineFormatRenderer,
} from '../format/formatPart/BasicFormatRenderers';

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

const QuoteBlockFormatRenders: FormatRenderer<ContentModelQuoteFormat>[] = [
BackgroundColorFormatRenderer,
...DirectionFormatRenderers,
MarginFormatRenderer,
PaddingFormatRenderer,
LineHeightFormatRenderer,
WhiteSpaceFormatRenderer,
...BorderFormatRenderers,
];
const QuoteSegmentFormatRenders: FormatRenderer<ContentModelSegmentFormat>[] = [
TextColorFormatRenderer,
FontSizeFormatRenderer,
FontFamilyFormatRenderer,
BoldFormatRenderer,
ItalicFormatRenderer,
UnderlineFormatRenderer,
];

export function ContentModelQuoteView(props: { quote: ContentModelQuote }) {
const { quote } = props;
const getContent = React.useCallback(() => {
return <BlockGroupContentView group={quote} />;
}, [quote]);

const getFormat = React.useCallback(() => {
return (
<>
<FormatView format={quote.format} renderers={QuoteBlockFormatRenders} />
<FormatView
format={quote.quoteSegmentFormat}
renderers={QuoteSegmentFormatRenders}
/>
</>
);
}, [quote]);

return (
<ContentModelView
title="Quote"
className={styles.modelQuote}
hasSelection={hasSelectionInBlock(quote)}
jsonSource={quote}
getContent={getContent}
getFormat={getFormat}
/>
);
}
20 changes: 9 additions & 11 deletions demo/scripts/controls/editor/ExperimentalContentModelEditor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,18 +76,16 @@ export default class ExperimentalContentModelEditor extends Editor
);
const mergingCallback = option?.mergingCallback || restoreContentWithEntityPlaceholder;

if (range) {
if (range.type == SelectionRangeTypes.Normal) {
// Need to get start and end from range position before merge because range can be changed during merging
const start = Position.getStart(range.ranges[0]);
const end = Position.getEnd(range.ranges[0]);
if (range?.type == SelectionRangeTypes.Normal) {
// Need to get start and end from range position before merge because range can be changed during merging
const start = Position.getStart(range.ranges[0]);
const end = Position.getEnd(range.ranges[0]);

mergingCallback(fragment, this.contentDiv, entityPairs);
this.select(start, end);
} else {
mergingCallback(fragment, this.contentDiv, entityPairs);
this.select(range);
}
mergingCallback(fragment, this.contentDiv, entityPairs);
this.select(start, end);
} else {
mergingCallback(fragment, this.contentDiv, entityPairs);
this.select(range);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { alignCenterButton } from './alignCenterButton';
import { alignLeftButton } from './alignLeftButton';
import { alignRightButton } from './alignRightButton';
import { backgroundColorButton } from './backgroundColorButton';
import { blockQuoteButton } from './blockQuoteButton';
import { boldButton } from './boldButton';
import { bulletedListButton } from './bulletedListButton';
import { decreaseFontSizeButton } from './decreaseFontSizeButton';
Expand All @@ -12,6 +13,7 @@ import { fontSizeButton } from './fontSizeButton';
import { formatTableButton } from './formatTableButton';
import { increaseFontSizeButton } from './increaseFontSizeButton';
import { increaseIndentButton } from './increaseIndentButton';
import { insertImageButton } from './insertImageButton';
import { insertTableButton } from './insertTableButton';
import { italicButton } from './italicButton';
import { listStartNumberButton } from './listStartNumberButton';
Expand Down Expand Up @@ -52,19 +54,21 @@ const buttons = [
numberedListButton,
decreaseIndentButton,
increaseIndentButton,
strikethroughButton,
superscriptButton,
subscriptButton,
blockQuoteButton,
alignLeftButton,
alignCenterButton,
alignRightButton,
insertTableButton,
insertImageButton,
superscriptButton,
subscriptButton,
strikethroughButton,
setHeaderLevelButton,
ltrButton,
rtlButton,
setHeaderLevelButton,
setBulletedListStyleButton,
setNumberedListStyleButton,
listStartNumberButton,
insertTableButton,
formatTableButton,
setTableCellShadeButton,
setTableHeaderButton,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import isContentModelEditor from '../../editor/isContentModelEditor';
import { QuoteButtonStringKey, RibbonButton } from 'roosterjs-react';
import { toggleBlockQuote } from 'roosterjs-content-model';

/**
* @internal
* "Block quote" button on the format ribbon
*/
export const blockQuoteButton: RibbonButton<QuoteButtonStringKey> = {
key: 'buttonNameQuote',
unlocalizedText: 'Quote',
iconName: 'RightDoubleQuote',
isChecked: formatState => !!formatState.isBlockQuote,
onClick: editor => {
if (isContentModelEditor(editor)) {
toggleBlockQuote(editor);
}
return true;
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import isContentModelEditor from '../../editor/isContentModelEditor';
import { createElement } from 'roosterjs-editor-dom';
import { CreateElementData } from 'roosterjs-editor-types';
import { insertImage } from 'roosterjs-content-model';
import { InsertImageButtonStringKey, RibbonButton } from 'roosterjs-react';

const FileInput: CreateElementData = {
tag: 'input',
attributes: {
type: 'file',
accept: 'image/*',
display: 'none',
},
};

/**
* @internal
* "Insert image" button on the format ribbon
*/
export const insertImageButton: RibbonButton<InsertImageButtonStringKey> = {
key: 'buttonNameInsertImage',
unlocalizedText: 'Insert image',
iconName: 'Photo2',
onClick: editor => {
if (isContentModelEditor(editor)) {
const document = editor.getDocument();
const fileInput = createElement(FileInput, document) as HTMLInputElement;
document.body.appendChild(fileInput);

fileInput.addEventListener('change', () => {
if (fileInput.files) {
for (let i = 0; i < fileInput.files.length; i++) {
insertImage(editor, fileInput.files[i]);
}
}
});

try {
fileInput.click();
} finally {
document.body.removeChild(fileInput);
}
}
},
};
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as React from 'react';
import ApiPaneProps from '../ApiPaneProps';
import { IEditor, PositionType, Region } from 'roosterjs-editor-types';
import { ExperimentalFeatures, IEditor, PositionType, Region } from 'roosterjs-editor-types';
import {
createRange,
getSelectedBlockElementsInRegion,
Expand Down Expand Up @@ -55,7 +55,11 @@ 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);
const blocks = getSelectedBlockElementsInRegion(
region,
undefined /* createBlockIfEmpty */,
editor.isFeatureEnabled(ExperimentalFeatures.DefaultFormatInSpan)
);
if (blocks.length > 0) {
const range = createRange(
blocks[0].getStartNode(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,7 @@ const initialState: BuildInPluginState = {
watermarkText: 'Type content here ...',
forcePreserveRatio: false,
experimentalFeatures: [
ExperimentalFeatures.ConvertSingleImageBody,
ExperimentalFeatures.ListItemAlignment,
ExperimentalFeatures.PendingStyleBasedFormat,
ExperimentalFeatures.DefaultFormatInSpan,
ExperimentalFeatures.AutoFormatList,
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,11 @@ export interface ExperimentalFeaturesProps {
}

const FeatureNames: Partial<Record<ExperimentalFeatures, string>> = {
[ExperimentalFeatures.ConvertSingleImageBody]:
'Paste Html instead of image when Html have one Img Children (Animated Image Paste)',
[ExperimentalFeatures.TabKeyTextFeatures]: 'Additional functionality to Tab Key',
[ExperimentalFeatures.ListItemAlignment]:
'Align list elements elements to left, center and right using setAlignment API',
[ExperimentalFeatures.AutoFormatList]:
'Trigger formatting by a especial characters. Ex: (A), 1. i).',
[ExperimentalFeatures.PendingStyleBasedFormat]:
'Use pending style format to do formatting when selection is collapsed',
[ExperimentalFeatures.NormalizeList]:
'Normalize list to make sure it can be displayed correctly in other client',
[ExperimentalFeatures.ReuseAllAncestorListElements]:
"Reuse ancestor list elements even if they don't match the types from the list item.",
[ExperimentalFeatures.DefaultFormatInSpan]:
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "roosterjs",
"version": "8.39.1",
"version": "8.40.0",
"description": "Framework-independent javascript editor",
"repository": {
"type": "git",
Expand All @@ -18,7 +18,7 @@
"builddemo": "node tools/build.js builddemo",
"builddoc": "node tools/build.js builddoc",
"build": "node tools/build.js clean checkdep normalize tslint buildcommonjs dts packprod builddemo",
"build:ci": "node tools/build.js --noProgressBar clean checkdep normalize tslint buildcommonjs buildamd buildmjs dts pack packprod builddemo builddoc",
"build:ci": "node --max-old-space-size=8192 tools/build.js --noProgressBar clean checkdep normalize tslint buildcommonjs buildamd buildmjs dts pack packprod builddemo builddoc",
"start": "node tools/start.js",
"test": "node tools/build.js normalize & karma start --chrome",
"test:chrome": "node tools/build.js normalize & karma start --chrome",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,10 @@ export const knownElementProcessor: ElementProcessor<HTMLElement> = (group, elem
);

if (topDivider) {
if (context.isInSelection) {
topDivider.isSelected = true;
}

addBlock(group, topDivider);
}

Expand All @@ -82,6 +86,10 @@ export const knownElementProcessor: ElementProcessor<HTMLElement> = (group, elem
context.elementProcessors.child(group, element, context);

if (bottomDivider) {
if (context.isInSelection) {
bottomDivider.isSelected = true;
}

addBlock(group, bottomDivider);
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,28 +1,46 @@
import { addBlock } from '../../modelApi/common/addBlock';
import { ContentModelQuoteFormat } from '../../publicTypes/format/ContentModelQuoteFormat';
import { ContentModelSegmentFormat } from '../../publicTypes/format/ContentModelSegmentFormat';
import { createQuote } from '../../modelApi/creators/createQuote';
import { ElementProcessor } from '../../publicTypes/context/ElementProcessor';
import { getObjectKeys, getStyles } from 'roosterjs-editor-dom';

const KnownQuoteStyleNames = ['margin-top', 'margin-bottom'];
import { getObjectKeys } from 'roosterjs-editor-dom';
import { knownElementProcessor } from './knownElementProcessor';
import { parseFormat } from '../utils/parseFormat';
import { stackFormat } from '../utils/stackFormat';

/**
* @internal
*/
export const quoteProcessor: ElementProcessor<HTMLQuoteElement> = (group, element, context) => {
const styles = getStyles(element);
if (element.style.borderLeft || element.style.borderRight) {
stackFormat(
context,
{
paragraph: 'empty',
segment: 'shallowCloneForBlock',
},
() => {
const quoteFormat: ContentModelQuoteFormat = {};
const segmentFormat: ContentModelSegmentFormat = {};

parseFormat(element, context.formatParsers.quote, quoteFormat, context);
parseFormat(element, context.formatParsers.segmentOnBlock, segmentFormat, context);

const quote = createQuote(quoteFormat, segmentFormat);

addBlock(group, quote);

if (
parseInt(element.style.marginTop) === 0 &&
parseInt(element.style.marginBottom) === 0 &&
getObjectKeys(styles).every(key => KnownQuoteStyleNames.indexOf(key) >= 0)
) {
// Temporary solution: Use Quote to provide indentation
// TODO: We should use CSS to do indentation, and only use Quote for quoted text
const quote = createQuote();
// These inline formats are overridden by quote, and will be applied onto BLOCKQUOTE element
// So no need to pass them down into segments.
// And when toggle blockquote (unwrap the quote model), no need to modify the inline format of segments
getObjectKeys(segmentFormat).forEach(key => {
delete context.segmentFormat[key];
});

addBlock(group, quote);
context.elementProcessors.child(quote, element, context);
context.elementProcessors.child(quote, element, context);
}
);
} else {
context.elementProcessors['*'](group, element, context);
knownElementProcessor(group, element, context);
}
};
Loading

0 comments on commit a279b70

Please sign in to comment.