Skip to content

Commit

Permalink
Bump Rooster to 8.49, content-model to 0.8.0 (#1859)
Browse files Browse the repository at this point in the history
* Add Size Format Handler to tables (#1838)

* add width format handler

* Revert "add width format handler"

This reverts commit b36f17d.

* add size handle to table

* add default style override when pasting table

* fix test

* revert

* Remove Table temp elements from Word Online (#1842)

* init

* fix test

* Remove the support of ShadowDOM entity (#1841)

* Undo with entity (#1791)

* Prototype: Undo with entity

* check entity type

* Content Model: Only optimize paragraph

* do not optimize entity

* fix build

* Improve

* improve

* improve

* fix test

* improve

* improve sample entity

* fix build

* improve

* Fix test

* Add  test

* fix test

* improve

* Content Model: Improve link and heading behavior (#1812)

* Improve link and heading behavior

* fix build

* improve format state, fix test

* Make roosterjs work with nodejs 17+ (#1849)

* Make roosterjs work with nodejs 17+

* update node version in workflow

* Content Model: Fix #1847 (#1848)

* Content Model: Fix #1847

* improve

* Fix config for test:coverage (#1851)

* Try fix #1816 (#1846)

* Add new param (#1853)

* Content Model: Maintain selection on empty line (#1814)

* Content Model: Maintain selection on empty line

* fix build

* improve

* Content Model: Fix #1802 Default format is not applied when type in a not-empty line (#1805)

* Try fix #1802

* fix build

* Improve

* fix test

* add more test

* Remove zeroFontSize from paragraph

* fix build

* fix bug

* fix test

* Improve

* fix test

* Fix list bug when pasting from Word Online (#1855)

Right now when copying from Word Online, if text is between 2 lists, the text between would be transformed to list too.
So we need to clear the list context to prevent this from happening. We will do this when:

Element is not wrapped in a ListContainerDiv
Element is not contained inside of a List item

* Make paste with content model a public api instead of a Editor Class member (#1852)

* init

* Remove unused function

* remove unused type

* Content Model: Fix #1839:  Fix toggleBold on heading text (#1845)

* Content Model: Fix #1839

* add test

---------

Co-authored-by: Bryan Valverde U <[email protected]>

* Fix #1322: Copying some table structure transform the table to single line text (#1843)

* add width format handler

* Revert "add width format handler"

This reverts commit b36f17d.

* add size handle to table

* add default style override when pasting table

* fix test

* revert

* fix

* address comment

* handle only on copy and cut

* Revert "address comment"

This reverts commit e268795.

* handle only on cut and paste

* fix tests & build

* use onNodeCreated instead

* Improve test running (#1854)

* Use default format for empty line below entity (#1858)

* Use default format for empty line below entity

* fix build

* Fix bug when pasting from Outlook Win 32 to Rooster (#1857)

* init

* fix

* fix test in ff

* add a constants

* address comments

---------

Co-authored-by: Jiuqing Song <[email protected]>

* bump

---------

Co-authored-by: Bryan Valverde U <[email protected]>
Co-authored-by: Jiuqing Song <[email protected]>
  • Loading branch information
3 people authored Jun 2, 2023
1 parent 0e88e6b commit 6b6210e
Show file tree
Hide file tree
Showing 137 changed files with 4,406 additions and 2,754 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build-and-deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
- name: Set Node Version
uses: actions/setup-node@v2
with:
node-version: 'v14.18.2'
node-version: 'v18.16.0'

- name: Install dependencies
run: yarn
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/build-and-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
- name: Set Node Version
uses: actions/setup-node@v2
with:
node-version: 'v14.18.2'
node-version: 'v18.16.0'

- name: Install dependencies
run: yarn
Expand All @@ -31,7 +31,7 @@ jobs:
- name: Set Node Version
uses: actions/setup-node@v2
with:
node-version: 'v14.18.2'
node-version: 'v18.16.0'

- name: Install dependencies
run: yarn
Expand All @@ -54,7 +54,7 @@ jobs:
- name: Set Node Version
uses: actions/setup-node@v2
with:
node-version: 'v14.18.2'
node-version: 'v18.16.0'

- name: Install dependencies
run: yarn
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
- name: Set Node Version
uses: actions/setup-node@v2
with:
node-version: 'v14.18.2'
node-version: 'v18.16.0'

- name: Install dependencies
run: yarn
Expand Down
4 changes: 4 additions & 0 deletions demo/scripts/controls/MainPane.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import FormatPainterPlugin from './contentModel/plugins/FormatPainterPlugin';
import FormatStatePlugin from './sidePane/formatState/FormatStatePlugin';
import getToggleablePlugins from './getToggleablePlugins';
import MainPaneBase from './MainPaneBase';
import SampleEntityPlugin from './sampleEntity/SampleEntityPlugin';
import SidePane from './sidePane/SidePane';
import SnapshotPlugin from './sidePane/snapshot/SnapshotPlugin';
import TitleBar from './titleBar/TitleBar';
Expand Down Expand Up @@ -128,6 +129,7 @@ class MainPane extends MainPaneBase {
private updateContentPlugin: UpdateContentPlugin;
private toggleablePlugins: EditorPlugin[] | null = null;
private formatPainterPlugin: FormatPainterPlugin;
private sampleEntityPlugin: SampleEntityPlugin;
private mainWindowButtons: RibbonButton<RibbonStringKeys>[];
private popoutWindowButtons: RibbonButton<RibbonStringKeys>[];

Expand All @@ -150,6 +152,7 @@ class MainPane extends MainPaneBase {
this.emojiPlugin = createEmojiPlugin();
this.updateContentPlugin = createUpdateContentPlugin(UpdateMode.OnDispose, this.onUpdate);
this.formatPainterPlugin = new FormatPainterPlugin();
this.sampleEntityPlugin = new SampleEntityPlugin();
this.mainWindowButtons = getButtons([
...AllButtonKeys,
darkMode,
Expand Down Expand Up @@ -439,6 +442,7 @@ class MainPane extends MainPaneBase {
this.pasteOptionPlugin,
this.emojiPlugin,
this.formatPainterPlugin,
this.sampleEntityPlugin,
];

if (this.state.showSidePane || this.state.popoutWindow) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,22 +15,14 @@ const styles = require('./ContentModelParagraphView.scss');
export function ContentModelParagraphView(props: { paragraph: ContentModelParagraph }) {
const { paragraph } = props;
const implicitCheckbox = React.useRef<HTMLInputElement>(null);
const zeroFontCheckbox = React.useRef<HTMLInputElement>(null);
const [isImplicit, setIsImplicit] = useProperty(!!paragraph.isImplicit);
const [isZeroFont, setZeroFont] = useProperty(!!paragraph.zeroFontSize);

const onIsImplicitChange = React.useCallback(() => {
const newValue = implicitCheckbox.current.checked;
paragraph.isImplicit = newValue;
setIsImplicit(newValue);
}, [paragraph, setIsImplicit]);

const onChangeZeroFontSize = React.useCallback(() => {
const newValue = zeroFontCheckbox.current.checked;
paragraph.zeroFontSize = newValue;
setZeroFont(newValue);
}, [paragraph, setIsImplicit]);

const getContent = React.useCallback(() => {
return (
<>
Expand All @@ -43,15 +35,6 @@ export function ContentModelParagraphView(props: { paragraph: ContentModelParagr
/>
Implicit
</div>
<div>
<input
type="checkbox"
checked={isZeroFont}
ref={zeroFontCheckbox}
onChange={onChangeZeroFontSize}
/>
Zero font size
</div>
{paragraph.decorator && (
<ContentModelParagraphDecoratorView decorator={paragraph.decorator} />
)}
Expand All @@ -60,14 +43,15 @@ export function ContentModelParagraphView(props: { paragraph: ContentModelParagr
))}
</>
);
}, [
paragraph,
isImplicit,
// headerLevel
]);
}, [paragraph, isImplicit]);

const getFormat = React.useCallback(() => {
return <BlockFormatView format={paragraph.format} />;
return (
<>
<BlockFormatView format={paragraph.format} />
{paragraph.segmentFormat && <SegmentFormatView format={paragraph.segmentFormat} />}
</>
);
}, [paragraph.format]);

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export const imageBoxShadowButton: RibbonButton<'buttonNameImageBoxSHadow'> = {
},
onClick: (editor, size) => {
if (isContentModelEditor(editor)) {
setImageBoxShadow(editor, STYLES[size]);
setImageBoxShadow(editor, STYLES[size], STYLES[size].length ? '4px' : null);
}
return true;
},
Expand Down
178 changes: 178 additions & 0 deletions demo/scripts/controls/sampleEntity/SampleEntityPlugin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
import { insertEntity } from 'roosterjs-editor-api';
import {
createNumberDefinition,
createObjectDefinition,
findClosestElementAncestor,
getEntityFromElement,
getEntitySelector,
getMetadata,
setMetadata,
} from 'roosterjs-editor-dom';
import {
EditorPlugin,
Entity,
EntityOperation,
EntityState,
IEditor,
PluginEvent,
PluginEventType,
} from 'roosterjs-editor-types';

const EntityType = 'SampleEntity';

interface EntityMetadata {
count: number;
}

const EntityMetadataDefinition = createObjectDefinition<EntityMetadata>({
count: createNumberDefinition(),
});

export default class SampleEntityPlugin implements EditorPlugin {
private editor: IEditor;

getName() {
return 'SampleEntity';
}

initialize(editor: IEditor) {
this.editor = editor;
}

dispose() {
this.editor = null;
}

onPluginEvent(event: PluginEvent) {
if (
event.eventType == PluginEventType.KeyDown &&
event.rawEvent.key == 'm' &&
event.rawEvent.ctrlKey
) {
const entityNode = this.createEntity();
let entity: Entity | undefined;

this.editor.addUndoSnapshot(
() => {
entity = insertEntity(this.editor, EntityType, entityNode, true, true);
},
undefined /*changeSource*/,
false /*canUndoByBackspace*/,
{
getEntityState: () => this.getEntityStates(entity),
}
);

event.rawEvent.preventDefault();
} else if (
event.eventType == PluginEventType.EntityOperation &&
event.entity.type == EntityType
) {
switch (event.operation) {
case EntityOperation.NewEntity:
this.dehydrate(event.entity);
this.hydrate(event.entity);

event.shouldPersist = true;

break;

case EntityOperation.RemoveFromEnd:
case EntityOperation.RemoveFromStart:
case EntityOperation.Overwrite:
case EntityOperation.ReplaceTemporaryContent:
this.dehydrate(event.entity);

break;

case EntityOperation.UpdateEntityState:
if (event.state) {
setMetadata(
event.entity.wrapper,
JSON.parse(event.state),
EntityMetadataDefinition
);
this.updateEntity(event.entity);
}

break;
}
}
}

private hydrate(entity: Entity) {
const containerDiv = entity.wrapper.querySelector('div');

const span = document.createElement('span');
const button = document.createElement('button');

containerDiv.appendChild(span);
containerDiv.appendChild(button);

button.textContent = 'Test entity';
button.addEventListener('click', this.onClickEntity);

this.updateEntity(entity);
}

private dehydrate(entity: Entity) {
const containerDiv = entity.wrapper.querySelector('div');
const button = containerDiv.querySelector('button');

if (button) {
button.removeEventListener('click', this.onClickEntity);
containerDiv.removeChild(button);
}
}

private updateEntity(entity: Entity, increase: number = 0) {
const metadata = getMetadata<EntityMetadata>(entity.wrapper);
const count = (metadata?.count || 0) + increase;

setMetadata(entity.wrapper, {
count,
});

entity.wrapper.querySelector('span').textContent = 'Count: ' + count;
}

private createEntity() {
const div = document.createElement('div');

return div;
}

private onClickEntity = (e: MouseEvent) => {
const wrapper = findClosestElementAncestor(
e.target as Node,
undefined,
getEntitySelector(EntityType)
);
const entity = getEntityFromElement(wrapper);

if (entity) {
this.editor.addUndoSnapshot(
() => {
this.updateEntity(entity, 1);
},
undefined /*changeSource*/,
false /*canUndoByBackspace*/,
{
getEntityState: () => this.getEntityStates(entity),
}
);
}
};

private getEntityStates(entity: Entity | undefined): EntityState[] {
return entity
? [
{
id: entity.id,
type: entity.type,
state: entity.wrapper.dataset.editingInfo,
},
]
: undefined;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ interface InsertEntityPaneState {
export default class InsertEntityPane extends React.Component<ApiPaneProps, InsertEntityPaneState> {
private entityType = React.createRef<HTMLInputElement>();
private html = React.createRef<HTMLTextAreaElement>();
private hydratedHtml = React.createRef<HTMLTextAreaElement>();
private styleInline = React.createRef<HTMLInputElement>();
private styleBlock = React.createRef<HTMLInputElement>();
private isReadonly = React.createRef<HTMLInputElement>();
Expand All @@ -37,10 +36,6 @@ export default class InsertEntityPane extends React.Component<ApiPaneProps, Inse
<div>
HTML: <textarea className={styles.textarea} ref={this.html}></textarea>
</div>
<div>
Hydrated HTML:
<textarea className={styles.textarea} ref={this.hydratedHtml}></textarea>
</div>
<div>
Style:
<input
Expand Down Expand Up @@ -85,7 +80,6 @@ export default class InsertEntityPane extends React.Component<ApiPaneProps, Inse
const entityType = this.entityType.current.value;
const node = document.createElement('span');
node.innerHTML = trustedHTMLHandler(this.html.current.value);
node.dataset.hydratedHtml = this.hydratedHtml.current.value.trim();
const isBlock = this.styleBlock.current.checked;
const isReadonly = this.isReadonly.current.checked;
const insertAtRoot = this.insertAtRoot.current.checked;
Expand Down Expand Up @@ -139,9 +133,6 @@ function EntityButton({ entity }: { entity: Entity }) {
<br />
Readonly: {entity.isReadonly ? 'True' : 'False'}
<br />
IsShadowEntity: {!!entity.wrapper.shadowRoot}
<br />
<br />
</div>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ const EntityOperationMap: { [key in EntityOperation]: string } = {
[EntityOperation.RemoveFromEnd]: 'RemoveFromEnd',
[EntityOperation.RemoveFromStart]: 'RemoveFromStart',
[EntityOperation.ReplaceTemporaryContent]: 'ReplaceTemporaryContent',
[EntityOperation.UpdateEntityState]: 'UpdateEntityState',
};

export default class EventViewPane extends React.Component<
Expand Down
3 changes: 2 additions & 1 deletion demo/scripts/controls/sidePane/snapshot/SnapshotPlugin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import * as React from 'react';
import SidePanePlugin from '../../SidePanePlugin';
import SnapshotPane from './SnapshotPane';
import UndoSnapshots from './UndoSnapshots';
import { ChangeSource, IEditor, PluginEvent, PluginEventType } from 'roosterjs-editor-types';
import { createSnapshots } from 'roosterjs-editor-dom';
import { IEditor, PluginEvent, PluginEventType } from 'roosterjs-editor-types';
import { Snapshot } from 'roosterjs-editor-types';

export default class SnapshotPlugin implements SidePanePlugin {
Expand Down Expand Up @@ -87,6 +87,7 @@ export default class SnapshotPlugin implements SidePanePlugin {
this.component.snapshotToString(snapshot),
false /*triggerContentChangedEvent*/
);
this.editorInstance.triggerContentChangedEvent(ChangeSource.SetContent);
};

private updateSnapshots = () => {
Expand Down
Loading

0 comments on commit 6b6210e

Please sign in to comment.