Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FHL] Import model document #2509

Merged
merged 11 commits into from
Mar 18, 2024
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import * as React from 'react';
import InputDialogItem from './InputDialogItem';
import { DefaultButton, PrimaryButton } from '@fluentui/react/lib/Button';
import { Dialog, DialogFooter, DialogType } from '@fluentui/react/lib/Dialog';
import { getLocalizedString } from '../../common/index';
import { getObjectKeys } from 'roosterjs-content-model-dom';
import { Dialog, DialogFooter, DialogType, IDialogContentProps } from '@fluentui/react/lib/Dialog';
import type { DialogItem } from '../type/DialogItem';
import type {
CancelButtonStringKey,
Expand All @@ -26,6 +26,7 @@ export interface InputDialogProps<Strings extends string, ItemNames extends stri
) => Record<ItemNames, string> | null;
onOk: (values: Record<ItemNames, string>) => void;
onCancel: () => void;
rows?: number;
}

/**
Expand All @@ -34,11 +35,25 @@ export interface InputDialogProps<Strings extends string, ItemNames extends stri
export default function InputDialog<Strings extends string, ItemNames extends string>(
props: InputDialogProps<Strings, ItemNames>
) {
const { items, strings, dialogTitleKey, unlocalizedTitle, onOk, onCancel, onChange } = props;
const dialogContentProps = React.useMemo(
const {
items,
strings,
dialogTitleKey,
unlocalizedTitle,
onOk,
onCancel,
onChange,
rows,
} = props;
const dialogContentProps: IDialogContentProps = React.useMemo(
() => ({
type: DialogType.normal,
title: getLocalizedString(strings, dialogTitleKey, unlocalizedTitle),
styles: {
innerContent: {
height: rows ? '200px' : undefined,
},
},
}),
[strings, dialogTitleKey, unlocalizedTitle]
);
Expand Down Expand Up @@ -80,6 +95,7 @@ export default function InputDialog<Strings extends string, ItemNames extends st
currentValues={currentValues}
onEnterKey={onSubmit}
onChanged={onItemChanged}
rows={rows}
/>
))}
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export interface InputDialogItemProps<Strings extends string, ItemNames extends
currentValues: Record<ItemNames, string>;
onEnterKey: () => void;
onChanged: (itemName: ItemNames, newValue: string) => void;
rows?: number;
}

const classNames = mergeStyleSets({
Expand All @@ -33,7 +34,7 @@ const classNames = mergeStyleSets({
export default function InputDialogItem<Strings extends string, ItemNames extends string>(
props: InputDialogItemProps<Strings, ItemNames>
) {
const { itemName, strings, items, currentValues, onChanged, onEnterKey } = props;
const { itemName, strings, items, currentValues, onChanged, onEnterKey, rows } = props;
const { labelKey, unlocalizedLabel, autoFocus } = items[itemName];
const value = currentValues[itemName];
const onValueChange = React.useCallback(
Expand Down Expand Up @@ -64,6 +65,8 @@ export default function InputDialogItem<Strings extends string, ItemNames extend
onChange={onValueChange}
onKeyPress={onKeyPress}
autoFocus={autoFocus}
rows={rows}
multiline={!!rows}
/>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ export function showInputDialog<Strings extends string, ItemNames extends string
changedItemName: ItemNames,
newValue: string,
currentValues: Record<ItemNames, string>
) => Record<ItemNames, string> | null
) => Record<ItemNames, string> | null,
rows?: number
): Promise<Record<ItemNames, string> | null> {
return new Promise<Record<ItemNames, string> | null>(resolve => {
let disposer: null | (() => void) = null;
Expand All @@ -49,6 +50,7 @@ export function showInputDialog<Strings extends string, ItemNames extends string
onOk={onOk}
onCancel={onCancel}
onChange={onChange}
rows={rows}
/>
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import * as React from 'react';
import { ContentModelDocument } from 'roosterjs-content-model-types';
import { ContentModelDocumentView } from './components/model/ContentModelDocumentView';
import { exportButton } from './buttons/exportButton';
import { importModelButton } from './buttons/importModelButton';
import { refreshButton } from './buttons/refreshButton';
import { Ribbon, RibbonButton, RibbonPlugin } from '../../roosterjsReact/ribbon';
import { SidePaneElementProps } from '../SidePaneElement';
Expand All @@ -25,7 +26,7 @@ export class ContentModelPane extends React.Component<
constructor(props: ContentModelPaneProps) {
super(props);

this.contentModelButtons = [refreshButton, exportButton];
this.contentModelButtons = [refreshButton, exportButton, importModelButton];

this.state = {
model: null,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { isBlockGroupOfType } from 'roosterjs-content-model-core';
import { showInputDialog } from '../../../roosterjsReact/inputDialog/utils/showInputDialog';
import type { RibbonButton } from '../../../roosterjsReact/ribbon/type/RibbonButton';

/**
* @internal
* "Import Model" button on the format ribbon
*/
export const importModelButton: RibbonButton<'buttonNameImportModel'> = {
key: 'buttonNameImportModel',
unlocalizedText: 'Import Model',
iconName: 'Installation',
isChecked: formatState => formatState.isBold,
onClick: (editor, _, strings, uiUtilities) => {
showInputDialog(
uiUtilities,
'buttonNameImportModel',
'Import Model',
{
model: {
autoFocus: true,
labelKey: 'buttonNameImportModel' as const,
unlocalizedLabel: 'Insert model',
initValue: '',
},
},
strings,
undefined /* onChange */,
10 /* rows */
).then(values => {
try {
const importedModel = JSON.parse(values.model);
if (isBlockGroupOfType(importedModel, 'Document')) {
editor.formatContentModel(model => {
model.blocks = importedModel.blocks;
model.format = importedModel.format;
return true;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's also copy format from imported model.

});
}
} catch (e) {
throw new Error('Invalid model');
}
});
},
};
Loading