@@ -100,6 +100,7 @@ export class RichText extends React.Component<IRichTextProps, IRichTextState> {
100
100
showAlign : true ,
101
101
showList : true ,
102
102
showLink : true ,
103
+ showImage : true ,
103
104
showMore : true
104
105
}
105
106
} ;
@@ -115,9 +116,11 @@ export class RichText extends React.Component<IRichTextProps, IRichTextState> {
115
116
editing : false ,
116
117
morePaneVisible : false ,
117
118
hideDialog : true ,
119
+ hideImageDialog : true ,
118
120
formats : { } ,
119
121
insertUrl : undefined ,
120
122
insertUrlText : undefined ,
123
+ insertImageUrl : undefined ,
121
124
selectedText : undefined ,
122
125
selectedUrl : undefined ,
123
126
wrapperTop : 0
@@ -392,6 +395,40 @@ export class RichText extends React.Component<IRichTextProps, IRichTextState> {
392
395
) ;
393
396
}
394
397
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
+
395
432
/**
396
433
* Renders the Rich Text Editor
397
434
*/
@@ -409,7 +446,7 @@ export class RichText extends React.Component<IRichTextProps, IRichTextState> {
409
446
}
410
447
411
448
// 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 ;
413
450
414
451
// Get a unique id for the toolbar
415
452
const modules = {
@@ -551,6 +588,20 @@ id="DropDownStyles"
551
588
} } />
552
589
</ TooltipHost >
553
590
)
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
+ )
554
605
}
555
606
{
556
607
showMore && (
@@ -583,6 +634,10 @@ id="DropDownStyles"
583
634
{
584
635
this . renderLinkDialog ( )
585
636
}
637
+ {
638
+ this . renderImageDialog ( )
639
+ }
640
+
586
641
</ div >
587
642
) ;
588
643
}
@@ -659,6 +714,29 @@ id="DropDownStyles"
659
714
this . setState ( { hideDialog : true } ) ;
660
715
}
661
716
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
+
662
740
/**
663
741
* When user enters the richtext editor, displays the border
664
742
*/
@@ -703,6 +781,28 @@ id="DropDownStyles"
703
781
} ) ;
704
782
}
705
783
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
+
706
806
/**
707
807
* Disable Save-button if hyperlink is undefined or empty
708
808
* This prevents the user of adding an empty hyperlink
@@ -714,6 +814,17 @@ id="DropDownStyles"
714
814
return true ;
715
815
}
716
816
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
+
717
828
/**
718
829
* Applies a format to the selection
719
830
* @param name format name
0 commit comments