Skip to content

Commit c93a73d

Browse files
committed
add embedded image
1 parent 4b99c51 commit c93a73d

File tree

5 files changed

+135
-1
lines changed

5 files changed

+135
-1
lines changed

src/controls/richText/RichText.tsx

Lines changed: 112 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ export class RichText extends React.Component<IRichTextProps, IRichTextState> {
100100
showAlign: true,
101101
showList: true,
102102
showLink: true,
103+
showImage: true,
103104
showMore: true
104105
}
105106
};
@@ -115,9 +116,11 @@ export class RichText extends React.Component<IRichTextProps, IRichTextState> {
115116
editing: false,
116117
morePaneVisible: false,
117118
hideDialog: true,
119+
hideImageDialog: true,
118120
formats: {},
119121
insertUrl: undefined,
120122
insertUrlText: undefined,
123+
insertImageUrl: undefined,
121124
selectedText: undefined,
122125
selectedUrl: undefined,
123126
wrapperTop: 0
@@ -392,6 +395,40 @@ export class RichText extends React.Component<IRichTextProps, IRichTextState> {
392395
);
393396
}
394397

398+
/**
399+
* Renders the "Insert Image" dialog
400+
*/
401+
private renderImageDialog = (): JSX.Element => {
402+
return (
403+
<Dialog hidden={this.state.hideImageDialog}
404+
onDismiss={this.closeImageDialog}
405+
dialogContentProps={{
406+
type: DialogType.normal,
407+
title: strings.InsertImageTitle,
408+
}}
409+
modalProps={{
410+
className: styles.insertLinkDialog,
411+
isBlocking: true,
412+
containerClassName: 'ms-dialogMainOverride'
413+
}}>
414+
<TextField label={strings.AddressFieldLabel}
415+
value={this.state.insertImageUrl !== undefined ? this.state.insertImageUrl : ""}
416+
onChanged={(newValue?: string) => {
417+
this.setState({
418+
insertImageUrl: newValue
419+
});
420+
}} />
421+
422+
<DialogFooter className={styles.actions}>
423+
<div className={`ms-Dialog-actionsRight ${styles.actionsRight}`}>
424+
<PrimaryButton className={styles.action} onClick={this.handleInsertImage} text={strings.SaveButtonLabel} disabled={this.checkImageLinkUrl()} />
425+
<DefaultButton className={styles.action} onClick={this.closeImageDialog} text={strings.CancelButtonLabel} />
426+
</div>
427+
</DialogFooter>
428+
</Dialog>
429+
);
430+
}
431+
395432
/**
396433
* Renders the Rich Text Editor
397434
*/
@@ -409,7 +446,7 @@ export class RichText extends React.Component<IRichTextProps, IRichTextState> {
409446
}
410447

411448
// Okay, we're in edit mode.
412-
const { placeholder, styleOptions: { showStyles, showBold, showItalic, showUnderline, showAlign, showList, showLink, showMore } } = this.props;
449+
const { placeholder, styleOptions: { showStyles, showBold, showItalic, showUnderline, showAlign, showList, showLink, showMore, showImage} } = this.props;
413450

414451
// Get a unique id for the toolbar
415452
const modules = {
@@ -551,6 +588,20 @@ id="DropDownStyles"
551588
}} />
552589
</TooltipHost>
553590
)
591+
}
592+
{
593+
showImage && (
594+
<TooltipHost content={strings.ImageTitle}
595+
id="image-richtextbutton"
596+
calloutProps={{ gapSpace: 0 }}>
597+
<IconButton checked={this.state.formats!.link !== undefined}
598+
onClick={this.showInsertImageDialog}
599+
aria-describedby="image-richtextbutton"
600+
iconProps={{
601+
iconName: 'PictureFill'
602+
}} />
603+
</TooltipHost>
604+
)
554605
}
555606
{
556607
showMore && (
@@ -583,6 +634,10 @@ id="DropDownStyles"
583634
{
584635
this.renderLinkDialog()
585636
}
637+
{
638+
this.renderImageDialog()
639+
}
640+
586641
</div>
587642
);
588643
}
@@ -659,6 +714,29 @@ id="DropDownStyles"
659714
this.setState({ hideDialog: true });
660715
}
661716

717+
/**
718+
* Displays the insert link dialog
719+
*/
720+
private showInsertImageDialog = () => {
721+
const quill = this.getEditor();
722+
const range = quill.getSelection();
723+
724+
this.setState({
725+
hideImageDialog: false,
726+
selectedRange: range
727+
});
728+
}
729+
730+
/**
731+
* Hides the insert image dialog
732+
*/
733+
private closeImageDialog = () => {
734+
this.setState({
735+
hideImageDialog: true,
736+
insertImageUrl: undefined,
737+
});
738+
}
739+
662740
/**
663741
* When user enters the richtext editor, displays the border
664742
*/
@@ -703,6 +781,28 @@ id="DropDownStyles"
703781
});
704782
}
705783

784+
/**
785+
* Called when user insert an image
786+
*/
787+
private handleInsertImage = () => {
788+
const { insertImageUrl, selectedRange } = this.state;
789+
try {
790+
const quill = this.getEditor();
791+
const cursorPosition: number = selectedRange!.index;
792+
quill.insertEmbed(cursorPosition, 'image', insertImageUrl, "user");
793+
this.setState({
794+
insertImageUrl: undefined,
795+
hideImageDialog: true,
796+
});
797+
} catch {
798+
//Close the image dialog if something went wrong
799+
this.setState({
800+
insertImageUrl: undefined,
801+
hideImageDialog: true,
802+
});
803+
}
804+
}
805+
706806
/**
707807
* Disable Save-button if hyperlink is undefined or empty
708808
* This prevents the user of adding an empty hyperlink
@@ -714,6 +814,17 @@ id="DropDownStyles"
714814
return true;
715815
}
716816

817+
/**
818+
* Disable Save-button if hyperlink for the imported image is undefined or empty
819+
* This prevents the user of adding an empty image
820+
*/
821+
private checkImageLinkUrl = () => {
822+
if (this.state.insertImageUrl !== undefined && this.state.insertImageUrl != "") {
823+
return false;
824+
}
825+
return true;
826+
}
827+
717828
/**
718829
* Applies a format to the selection
719830
* @param name format name

src/controls/richText/RichText.types.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,12 @@ export interface StyleOptions {
8080
*/
8181
showMore?: boolean;
8282

83+
/**
84+
* Indicates if we should show the Image button.
85+
* @defaultvalue true
86+
*/
87+
showImage?: boolean;
88+
8389
/**
8490
* Indicates if we should show the Styles button (Heading 1, Heading 2, ..., Pull quote)
8591
* @defaultvalue true
@@ -109,6 +115,12 @@ export interface IRichTextState {
109115
*/
110116
hideDialog: boolean;
111117

118+
119+
/**
120+
* Whether to hide the insert image dialog
121+
*/
122+
hideImageDialog: boolean;
123+
112124
/**
113125
* The URL to insert
114126
*/
@@ -119,6 +131,11 @@ export interface IRichTextState {
119131
*/
120132
insertUrlText: string;
121133

134+
/**
135+
* The URL of image to insert
136+
*/
137+
insertImageUrl: string;
138+
122139
/**
123140
* Whether the "More" pane is visible
124141
*/

src/loc/en-us.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,10 +101,12 @@ define([], () => {
101101
AlignTitle: "Align",
102102
ListTitle: "List",
103103
LinkTitle: "Hyperlink",
104+
ImageTitle: "Image",
104105
MoreTitle: "More",
105106
FormattingPaneTitle: "Text formatting",
106107
CloseButton: "Close",
107108
InsertLinkTitle: "Insert link",
109+
InsertImageTitle: "Insert image",
108110
AddressFieldLabel: "Address",
109111
TextToDisplayLabel: "Text to display",
110112
SaveButtonLabel: "Save",

src/loc/mystrings.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,10 +73,12 @@ declare interface IControlStrings {
7373
AlignTitle: string;
7474
ListTitle: string;
7575
LinkTitle: string;
76+
ImageTitle: string;
7677
MoreTitle: string;
7778
FormattingPaneTitle: string;
7879
CloseButton: string;
7980
InsertLinkTitle: string;
81+
InsertImageTitle: string;
8082
AddressFieldLabel: string;
8183
TextToDisplayLabel: string;
8284
SaveButtonLabel: string;

src/loc/nl-nl.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,10 +90,12 @@ define([], () => {
9090
"AlignTitle": "Uitlijnen",
9191
"ListTitle": "Lijst",
9292
"LinkTitle": "Hyperlink",
93+
"ImageTitle": "Afbeelding",
9394
"MoreTitle": "Meer",
9495
"FormattingPaneTitle": "Tekstopmaak",
9596
"CloseButton": "Sluiten",
9697
"InsertLinkTitle": "Koppeling invoegen",
98+
"InsertImageTitle": "Afbeelding invoegen",
9799
"AddressFieldLabel": "Adres",
98100
"TextToDisplayLabel": "Weer te geven tekst",
99101
"SaveButtonLabel": "Opslaan",

0 commit comments

Comments
 (0)