Skip to content

Commit 5b62515

Browse files
flyingbee2012juliaroldiJiuqingSongshaipetelAndres-CT98
authored
Version bump up to 8.44.2 (#1666)
* 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 * wip * WIP * wip * 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 * Test image edit with ShadowDOM * improve * 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) * image wrapper using shadow dom * Content Model: Support get and apply segment format (#1518) * Do not merge table when insert a table (#1519) * wip * Content Model: Fix #1239 (#1521) * WIP AND fix for span height * stop dragging * comment * prototype * remove change * prevent drag * remove new max-width * Load fluent ui from cdnjs (#1525) * small changes * Content Model: Improve selection (#1526) * Apply format to word where cursor is located (#1367) * attempt with traversers * attempt using splitTextNode * Return to original implementation * Fix build * implementation with content model * Implement word selection with new content model * removed selectWordFromCollapsedRange.ts * optimization fixes and file changes * standardize function and remove castings * fix paragraph and pending state * fix pending state, name change * Added test cases, disabled end or start of word * fixed dependency * fix pending state * more tests * fixed tests * End of word format fix (#1528) * End of word format fix Fix scenario where format was wrongly applied where the cursor was located at the end of a word * add tests * Variable based dark color (#1531) * Variable based dark color * fix test * improve * Improve * Fix comment * Fix #1532: Support isCode in FormatState (#1533) * Fix #1532 * add comment * fix build * fix comment * Bump ua-parser-js from 0.7.31 to 0.7.33 (#1535) Bumps [ua-parser-js](https://github.com/faisalman/ua-parser-js) from 0.7.31 to 0.7.33. - [Release notes](https://github.com/faisalman/ua-parser-js/releases) - [Changelog](https://github.com/faisalman/ua-parser-js/blob/master/changelog.md) - [Commits](faisalman/ua-parser-js@0.7.31...0.7.33) --- updated-dependencies: - dependency-name: ua-parser-js dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Fix #1529 #1530 and 187095 (#1534) * WIP * test and fixes * unit tests * fix list trigger * Content Model: Adjust selection for link to select a word (#1538) * Content Model: Adjust word selection for link * add test * fix build * Fix table format (#1541) * refactor * move comment * Content Model code simplify 1 (#1544) * Content Model code simplify 2: Clean up EditorContext (#1545) * Content Model code simplify 1 * Content Model: Clean up EditorContext * improve * Content Model code simplify 3: Remove get/setPendingFormat from editor interface (#1546) * Content Model code simplify 1 * Content Model: Clean up EditorContext * improve * Content Model: Remove get/setPendingFormat * Add support for paragraph line spacing for content model (#1543) * Fetch line height from children * Create new content model api * Spacing btn * Fix tests * Remove key from roosterjs-react * testing * Allow segment to hold lineHeight format * Remove lineHeight from segments whenever possible * Fix imports * Remove normalization * Add todo for edge case * Render segment line height * Content Model Editor 1: Rename interface IExperimentalContentModelEditor (#1547) * Content Model code simplify 1 * Content Model: Clean up EditorContext * improve * Content Model: Remove get/setPendingFormat * Content Model: Rename IExperimentalContentModelEditor * fix build * WIP PROTOTYPE * Content Model Editor 2: Publish ContentModelEditor class (#1548) * Content Model code simplify 1 * Content Model: Clean up EditorContext * improve * Content Model: Remove get/setPendingFormat * Content Model: Rename IExperimentalContentModelEditor * Publish ContentModelEditor class * fix build * add test * fix build * fix build * Reorganize Contente Model code (#1555) * blur issue * Fix some block format issues (#1554) * Fix some block format issues * Improve * Content Model: Fix image size for outlook (#1556) * Content Model: Fix image size for outlook * Fix build * fix build * improve * add filter to client rects * Content Model: Support align table to center (#1557) * simply code * Content Model: Fix PRE tag (#1559) * Content Model: Support insert image with src (#1563) * Content Model: Get init segment format from root container (#1567) * Content Model: Get init segment format from root container * Improve * add test * Add missing setSpacing comment (#1564) * do not call updateHandle * check viewport * Content Model: Improve pending format implementation (#1570) * Disable list indentation on mac (#1552) * Disable list indentation on mac * Switch to default disabled * Content Model: Improve hyperlink handling (#1569) * Add support for adding/removing space before/after paragraphs in content model (#1565) * Create api for block margins * Create space before after buttons * Update testing * Fix by using decorator * Replace positive value with none * Treat no margin as space removed * Fix testing * Improve tag name selecting * testing * rename and improve logic * Add support for formatState on onClick call * Update button impl * Revert "Update button impl" This reverts commit edce3ad. * Revert "Add support for formatState on onClick call" This reverts commit 3d6b83d. * use getFormatState() * Update test name * Fix a pending format issue in firefox (#1572) * Content Model: Keep root level entity when format with Content Model (#1573) * Content Model: Preserve segment format when insert table (#1574) * delete table * delete table * fix enum * refactor * Fix #1585 (#1587) * strict mode * remove file * add zeros * enable strict mode * Content Model: Improve clearFormat API (#1579) * Content Model: Improve clearFormat * Improve * Improve * fix build * improve * WIP * Content Model: Improve getFormatState (#1594) * Fix color issue with Font tag (#1595) * refactor * Fix #1586 (#1597) * Add `dir` and `textAlign` in `FormatState` (#1590) Co-authored-by: Echo Li <yalinli@microsoft.com> * uncoment * Step 1: Add HTMLSpanElements around ReadOnly Inline entities to prevent cursor issues, (#1580) * init * add tests and build fixes * Fix failing tests in EntityPlugin * Fix comments * Fix comments * Move functionality to insertEntity * typedoc * refactor * refactor * add tests * Content Model: Improve pending format behavior (#1598) * Improve pending format behavior * fix test * trigger plugin event * fix build * remove code * Add flight check in InsertEntity #1602 * Improve PRE again (#1601) * Step 2: Prevent user from typing inside of readonly entities around the Readonly Inline Entity (#1581) * init * add tests and build fixes * Fix failing tests in EntityPlugin * Prevent user from typing inside of the * Add unit tests * Fix comments * Fix comments * remove typed text from Delimiter * add unit tests * Add selection condition and remove KeyUp * delete image with delete key * preventDefault * Content Model: Support inline CODE style #1536 (#1603) * #1536 * fix build * fix build * add test * Step 3: Add Content Edit Features to prevent cursor to be stuck between ZeroWidthSpace & ReadOnly Entity (#1582) * init * add tests and build fixes * Fix failing tests in EntityPlugin * Prevent user from typing inside of the * Add contentEditable Entities * Add unit tests * add Unit tests * fix test and typeDef * try fix tests * Fix comments * Fix comments * remove typed text from Delimiter * add unit tests * Add contentEditable Entities * add Unit tests * fix test and typeDef * try fix tests * unit tests * re run tests * refactor * Add selection condition and remove KeyUp * More to another file path * remove dup function * Fix * Update comments * refactor * change keydown to keypress * add char * Inline Entity Content Edit Features improvements. (#1606) * inline Entity fixes * Add delimiter to content model * Use isFeatureEnabled instead * Revert "Use isFeatureEnabled instead" This reverts commit a09aa3a. * Revert "Add delimiter to content model" This reverts commit 59be341. * add null check * Improve dark color again (#1609) * Improve dark color again * fix insertContent when source is light and target is dark * Delimiters in Content Model (#1608) * inline Entity fixes * Add delimiter to content model * Use isFeatureEnabled instead * Remove * Add comment * fix comments and add unit tests * fix build * Update comment * Add more comments * Show correct font when jump between table cells (#1612) * simulate rotation * Type assert (#1617) * Content Model: Fix a bug in normalization (#1613) * Fix table selection regression (#1618) * rotate image * uncomment blur * Fix Arrow Keys + Delimiter bug (#1620) * Fix * add Unit test * Add delimiters To InlineReadonly Entities on EditorReady and Paste (#1614) * Add delimiters on EditorReady and Paste * Handle ContentChanged Event * Add a unit test * Fix * Fix build * Reuse Content Model (#1610) * Reuse Content Model * fix test * fix test * add comment * improve * improve * Improve * fix test * improve * image rotation and tests * comment * Handle Enter in a Delimiter (#1622) When pressing Enter on a delimiter, usually when the entity is at the end of the block or is the only element in the block, sometimes the delimiter element is moved away from the Entity or the element after Enter also contains the Delimiter class. This PR adds functionality to prevent this from happening. Before ![DelimiterEnterBefore](https://user-images.githubusercontent.com/8291124/223553792-8b236323-9ca9-4393-8c5e-63c9043fc040.gif) After ![DelimiterEnterAfter](https://user-images.githubusercontent.com/8291124/223554716-0dedd8e7-d035-43fc-9639-ebc7a570007c.gif) * add check and do not sanitize Notes protocol (#1626) * Content Model: Fix fidelity issue of list (#1624) * Content Model: Fix fidelity issue of list * fix demo * Content Model: Fix format change while editing (#1625) * Content Model: Fix format change while editing * add test * Improve Movement Between Delimiters (#1628) The Content Edit was not working when cursor was between Entities, this PR fixes it, To Repro add multiple Readonly inline entities together. Without this change we had to use Arrow Key twice, now we only need to press it once * WIP * Improve deletion of entities (#1630) mprove the Content Edit Feature to delete delimiters. If After the Content Edit was handled: If the Entity still exists, add the delimiter removed. If the entity was removed in the ContentChanged Event, remove the Delimiters. If the event was not default prevented, select the delimiters and entity and let the browser handle the deletion. Also, in EntityPlugin if the known entity removed is a inline entity, normalize delimiters * flip and rotate * Handle Selection Not Collapsed for delimiters (#1629) Handle a scenario where the delimiter is removed when user selects the text + delimiter. Repro Add Entity type Next and Before the Entity Select the text after/before the entity press a key the modified the content Actual: The delimiter is removed in some scenarios Expected: Do not remove the delimiter To fix modify the selection and prevent the user typing inside of the delimiter when selection is not collapsed * comment * Check delimiter classes when adding Delimiters to a new Entity #1632 I was only checking if the element was a delimiter, but also need to check that the classes are correct, Otherwise, if the next sibling of the entity that we are adding the delimiters is a delimiterBefore of another entity, we won't add the delimiter after. * fix flips * fix hyperlink regression * remove max-width from insertSrc * Add a parameter to enable/disable handling keyboard editing from Content Model (#1641) * Add a parameter to enable/disable handling keyboard editing from Content Model * fix test * Fix Tab/ShiftTab indenting for lists on Mac (#1645) * Do not had BR when pasting two LI blocks. (#1646) * init * init * use closest * squash * Enter on Delimiter change and Add classes to sanitizing option (#1644) * Fix Enter and Paste * add classes supported to the BeforePaste Event * Add unit test * Strict Mode for Format Utils (#1647) * Strict Mode for Table Folder in API Package (#1648) * init * Fix error after merge * Content Model: Cache table step 1 (#1649) * Content Model: Cache table step 1 * improvement * refactor * fix test * fix fireforx test * Content Model: Cache table step 2 (#1651) * remove handler * remove change * add image format to get format state * add image format to get format state * add image format to get format state * add content model format state * only one selected image * Support default format in Content Model (#1655) * Fix Movement Between Entity Delimiter issue (#1640) * Init * Use traverser of current block instead of all. * fix multiple inlines in entity issue * change && to || --------- Co-authored-by: Jiuqing Song <jisong@microsoft.com> * fix merge * update version --------- Signed-off-by: dependabot[bot] <support@github.com> 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> Co-authored-by: Andres-CT98 <107568016+Andres-CT98@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Ian Elizondo <ianeli@microsoft.com> Co-authored-by: Echo-az <63284518+Echo-az@users.noreply.github.com> Co-authored-by: Echo Li <yalinli@microsoft.com> Co-authored-by: Bryan Valverde U <bvalverde@microsoft.com> Co-authored-by: charlxu <74210886+charlxu@users.noreply.github.com> Co-authored-by: Bi Wu <biwu@microsoft.com>
1 parent 1f768f3 commit 5b62515

126 files changed

Lines changed: 4643 additions & 853 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.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "roosterjs",
3-
"version": "8.44.1",
3+
"version": "8.44.2",
44
"description": "Framework-independent javascript editor",
55
"repository": {
66
"type": "git",

packages-ui/roosterjs-react/lib/contextMenu/menus/createImageEditMenuProvider.tsx

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,60 @@ const ImageResizeMenuItem: ContextMenuItem<ImageEditMenuItemStringKey, ImageEdit
8282
},
8383
};
8484

85+
const ImageRotateMenuItem: ContextMenuItem<ImageEditMenuItemStringKey, ImageEdit> = {
86+
key: 'menuNameImageRotate',
87+
unlocalizedText: 'Rotate image',
88+
subItems: {
89+
menuNameImageRotateLeft: 'Left',
90+
menuNameImageRotateRight: 'Right',
91+
},
92+
shouldShow: (_, node, imageEdit) => {
93+
return (
94+
!!imageEdit?.isOperationAllowed(ImageEditOperation.Rotate) &&
95+
canRegenerateImage(node as HTMLImageElement)
96+
);
97+
},
98+
onClick: (key, editor, node, strings, uiUtilities, imageEdit) => {
99+
editor.addUndoSnapshot(() => {
100+
switch (key) {
101+
case 'menuNameImageRotateLeft':
102+
imageEdit?.rotateImage(node as HTMLImageElement, -Math.PI / 2);
103+
break;
104+
case 'menuNameImageRotateRight':
105+
imageEdit?.rotateImage(node as HTMLImageElement, Math.PI / 2);
106+
break;
107+
}
108+
});
109+
},
110+
};
111+
112+
const ImageFlipMenuItem: ContextMenuItem<ImageEditMenuItemStringKey, ImageEdit> = {
113+
key: 'menuNameImageFlip',
114+
unlocalizedText: 'Flip image',
115+
subItems: {
116+
menuNameImageRotateFlipHorizontally: 'Flip Horizontally',
117+
menuNameImageRotateFlipVertically: 'Flip Vertically',
118+
},
119+
shouldShow: (_, node, imageEdit) => {
120+
return (
121+
!!imageEdit?.isOperationAllowed(ImageEditOperation.Rotate) &&
122+
canRegenerateImage(node as HTMLImageElement)
123+
);
124+
},
125+
onClick: (key, editor, node, strings, uiUtilities, imageEdit) => {
126+
editor.addUndoSnapshot(() => {
127+
switch (key) {
128+
case 'menuNameImageRotateFlipHorizontally':
129+
imageEdit?.flipImage(node as HTMLImageElement, 'horizontal');
130+
break;
131+
case 'menuNameImageRotateFlipVertically':
132+
imageEdit?.flipImage(node as HTMLImageElement, 'vertical');
133+
break;
134+
}
135+
});
136+
},
137+
};
138+
85139
const ImageCropMenuItem: ContextMenuItem<ImageEditMenuItemStringKey, ImageEdit> = {
86140
key: 'menuNameImageCrop',
87141
unlocalizedText: 'Crop image',
@@ -123,7 +177,14 @@ export default function createImageEditMenuProvider(
123177
): EditorPlugin {
124178
return createContextMenuProvider<ImageEditMenuItemStringKey, ImageEdit>(
125179
'imageEdit',
126-
[ImageAltTextMenuItem, ImageResizeMenuItem, ImageCropMenuItem, ImageRemoveMenuItem],
180+
[
181+
ImageAltTextMenuItem,
182+
ImageResizeMenuItem,
183+
ImageCropMenuItem,
184+
ImageRemoveMenuItem,
185+
ImageRotateMenuItem,
186+
ImageFlipMenuItem,
187+
],
127188
strings,
128189
shouldShowImageEditItems,
129190
imageEditPlugin

packages-ui/roosterjs-react/lib/contextMenu/types/ContextMenuItemStringKeys.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,17 @@ export type ImageEditMenuItemStringKey =
3535
| 'menuNameImageAltText'
3636
| 'menuNameImageResize'
3737
| 'menuNameImageCrop'
38+
| 'menuNameImageRotate'
3839
| 'menuNameImageRemove'
40+
| 'menuNameImageFlip'
3941
| 'menuNameImageSizeBestFit'
4042
| 'menuNameImageSizeSmall'
4143
| 'menuNameImageSizeMedium'
4244
| 'menuNameImageSizeOriginal'
45+
| 'menuNameImageRotateLeft'
46+
| 'menuNameImageRotateRight'
47+
| 'menuNameImageRotateFlipHorizontally'
48+
| 'menuNameImageRotateFlipVertically'
4349
| OkButtonStringKey
4450
| CancelButtonStringKey;
4551

packages/roosterjs-content-model/lib/domToModel/domToContentModel.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ export default function domToContentModel(
2121
editorContext: EditorContext,
2222
option: DomToModelOption
2323
): ContentModelDocument {
24-
const model = createContentModelDocument();
24+
const model = createContentModelDocument(editorContext.defaultFormat);
2525
const context = createDomToModelContext(editorContext, option);
2626

2727
// For root element, use computed style as initial value of segment formats

packages/roosterjs-content-model/lib/domToModel/processors/listItemProcessor.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,13 @@ export const listItemProcessor: ElementProcessor<HTMLLIElement> = (group, elemen
2424
);
2525

2626
const listItem = createListItem(listFormat.levels, context.segmentFormat);
27+
parseFormat(
28+
element,
29+
context.formatParsers.listItemElement,
30+
listItem.format,
31+
context
32+
);
33+
2734
listFormat.listParent!.blocks.push(listItem);
2835

2936
parseFormat(

packages/roosterjs-content-model/lib/domToModel/processors/tableProcessor.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ export const tableProcessor: ElementProcessor<HTMLTableElement> = (
3434
const { table: selectedTable, firstCell, lastCell } = context.tableSelection || {};
3535
const hasTableSelection = selectedTable == tableElement && !!firstCell && !!lastCell;
3636

37+
table.cachedElement = tableElement;
38+
3739
parseFormat(tableElement, context.formatParsers.table, table.format, context);
3840
parseFormat(
3941
tableElement,
@@ -87,6 +89,8 @@ export const tableProcessor: ElementProcessor<HTMLTableElement> = (
8789
table.cells[row + rowSpan - 1][targetCol] = cell;
8890

8991
if (hasTd) {
92+
cell.cachedElement = td;
93+
9094
stackFormat(context, { segment: 'shallowClone' }, () => {
9195
parseFormat(
9296
td,

packages/roosterjs-content-model/lib/editor/ContentModelEditor.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import contentModelToDom from '../modelToDom/contentModelToDom';
22
import domToContentModel from '../domToModel/domToContentModel';
33
import { ContentModelDocument } from '../publicTypes/group/ContentModelDocument';
4+
import { ContentModelSegmentFormat } from '../publicTypes/format/ContentModelSegmentFormat';
45
import { Editor } from 'roosterjs-editor-core';
56
import { EditorContext } from '../publicTypes/context/EditorContext';
67
import { EditorOptions, ExperimentalFeatures } from 'roosterjs-editor-types';
@@ -17,6 +18,7 @@ import {
1718
export default class ContentModelEditor extends Editor implements IContentModelEditor {
1819
private cachedModel: ContentModelDocument | null;
1920
private reuseModel: boolean = false;
21+
private defaultFormat: ContentModelSegmentFormat = {};
2022

2123
/**
2224
* Creates an instance of Editor
@@ -27,6 +29,7 @@ export default class ContentModelEditor extends Editor implements IContentModelE
2729
super(contentDiv, options);
2830
this.cachedModel = null;
2931
this.reuseModel = this.isFeatureEnabled(ExperimentalFeatures.ReusableContentModel);
32+
this.defaultFormat = this.getDefaultSegmentFormat();
3033
}
3134

3235
/**
@@ -90,11 +93,27 @@ export default class ContentModelEditor extends Editor implements IContentModelE
9093

9194
return {
9295
isDarkMode: this.isDarkMode(),
96+
defaultFormat: this.defaultFormat,
9397
getDarkColor: core.lifecycle.getDarkColor,
9498
darkColorHandler: this.getDarkColorHandler(),
9599
addDelimiterForEntity: this.isFeatureEnabled(
96100
ExperimentalFeatures.InlineEntityReadOnlyDelimiters
97101
),
98102
};
99103
}
104+
105+
private getDefaultSegmentFormat(): ContentModelSegmentFormat {
106+
const format = this.getDefaultFormat();
107+
108+
return {
109+
fontWeight: format.bold ? 'bold' : undefined,
110+
italic: format.italic || undefined,
111+
underline: format.underline || undefined,
112+
fontFamily: format.fontFamily || undefined,
113+
fontSize: format.fontSize || undefined,
114+
textColor: format.textColors?.lightModeColor || format.textColor || undefined,
115+
backgroundColor:
116+
format.backgroundColors?.lightModeColor || format.backgroundColor || undefined,
117+
};
118+
}
100119
}

packages/roosterjs-content-model/lib/formatHandlers/block/directionFormatHandler.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,15 @@ export const directionFormatHandler: FormatHandler<DirectionFormat> = {
2323
parse: (format, element, _, defaultStyle) => {
2424
const dir = element.style.direction || element.dir || defaultStyle.direction;
2525
const alignFromAttr = element.getAttribute('align');
26-
const align = element.style.textAlign || alignFromAttr || defaultStyle.textAlign;
26+
const textAlign = element.style.textAlign || alignFromAttr || defaultStyle.textAlign;
27+
const alignSelf = element.style.alignSelf;
28+
const isLI = element.tagName === 'li';
29+
const isFlex =
30+
element.parentElement &&
31+
element.parentElement.style.display === 'flex' &&
32+
element.style.flexDirection === 'column';
33+
const shouldApplyAlignSelf = isLI && isFlex;
34+
const align = shouldApplyAlignSelf ? alignSelf : textAlign;
2735

2836
if (dir) {
2937
format.direction = dir == 'rtl' ? 'rtl' : 'ltr';
@@ -62,9 +70,16 @@ export const directionFormatHandler: FormatHandler<DirectionFormat> = {
6270

6371
if (format.isTextAlignFromAttr) {
6472
element.setAttribute('align', value);
73+
} else if (element.tagName === 'LI') {
74+
element.style.alignSelf = format.textAlign;
6575
} else {
6676
element.style.textAlign = value;
6777
}
6878
}
79+
80+
if (element.tagName == 'OL' || element.tagName == 'UL') {
81+
element.style.flexDirection = 'column';
82+
element.style.display = 'flex';
83+
}
6984
},
7085
};

packages/roosterjs-content-model/lib/formatHandlers/defaultFormatHandlers.ts

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ const defaultFormatKeysPerCategory: {
9595
} = {
9696
block: blockFormatHandlers,
9797
listItem: ['listItemThread', 'listItemMetadata'],
98+
listItemElement: ['direction'],
9899
listLevel: ['listType', 'listLevelThread', 'listLevelMetadata', 'direction', 'margin'],
99100
segment: [
100101
'superOrSubScript',
@@ -112,24 +113,16 @@ const defaultFormatKeysPerCategory: {
112113
segmentOnTableCell: ['fontFamily', 'fontSize', 'underline', 'italic', 'bold'],
113114
tableCell: [
114115
'border',
115-
'borderBox',
116116
'backgroundColor',
117117
'padding',
118118
'direction',
119119
'verticalAlign',
120120
'wordBreak',
121121
'textColor',
122122
],
123-
table: [
124-
'id',
125-
'border',
126-
'borderBox',
127-
'tableSpacing',
128-
'margin',
129-
'backgroundColor',
130-
'display',
131-
'direction',
132-
],
123+
table: ['id', 'border', 'margin', 'backgroundColor', 'display', 'direction'],
124+
tableBorder: ['borderBox', 'tableSpacing'],
125+
tableCellBorder: ['borderBox'],
133126
image: ['id', 'size', 'margin', 'padding', 'borderBox', 'border', 'boxShadow'],
134127
link: ['link', 'textColor', 'underline'],
135128
code: ['fontFamily'],
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import { alignTable } from '../table/alignTable';
2+
import { ContentModelDocument } from '../../publicTypes/group/ContentModelDocument';
3+
import { ContentModelListItem } from '../../publicTypes/group/ContentModelListItem';
4+
import { getOperationalBlocks } from '../selection/collectSelections';
5+
import { TableOperation } from 'roosterjs-editor-types';
6+
7+
const ResultMap: Record<
8+
'left' | 'center' | 'right',
9+
Record<'ltr' | 'rtl', 'start' | 'center' | 'end'>
10+
> = {
11+
left: {
12+
ltr: 'start',
13+
rtl: 'end',
14+
},
15+
center: {
16+
ltr: 'center',
17+
rtl: 'center',
18+
},
19+
right: {
20+
ltr: 'end',
21+
rtl: 'start',
22+
},
23+
};
24+
25+
const TableAlignMap: Record<
26+
'left' | 'center' | 'right',
27+
Record<
28+
'ltr' | 'rtl',
29+
TableOperation.AlignLeft | TableOperation.AlignCenter | TableOperation.AlignRight
30+
>
31+
> = {
32+
left: {
33+
ltr: TableOperation.AlignLeft,
34+
rtl: TableOperation.AlignRight,
35+
},
36+
center: {
37+
ltr: TableOperation.AlignCenter,
38+
rtl: TableOperation.AlignCenter,
39+
},
40+
right: {
41+
ltr: TableOperation.AlignRight,
42+
rtl: TableOperation.AlignLeft,
43+
},
44+
};
45+
46+
/**
47+
* @internal
48+
*/
49+
export function setModelAlignment(
50+
model: ContentModelDocument,
51+
alignment: 'left' | 'center' | 'right'
52+
) {
53+
const paragraphOrListItemOrTable = getOperationalBlocks<ContentModelListItem>(
54+
model,
55+
['ListItem'],
56+
['TableCell']
57+
);
58+
59+
paragraphOrListItemOrTable.forEach(({ block }) => {
60+
const newAligment = ResultMap[alignment][block.format.direction == 'rtl' ? 'rtl' : 'ltr'];
61+
if (block.blockType === 'Table') {
62+
alignTable(
63+
block,
64+
TableAlignMap[alignment][block.format.direction == 'rtl' ? 'rtl' : 'ltr']
65+
);
66+
} else if (block) {
67+
const { format } = block;
68+
format.textAlign = newAligment;
69+
}
70+
});
71+
72+
return paragraphOrListItemOrTable.length > 0;
73+
}

0 commit comments

Comments
 (0)