import * as Styles from "./LinkDialog.scss.g" ; import { DefaultButton , PrimaryButton } from "office-ui-fabric-react/lib/Button" ; import { Dialog , DialogFooter , DialogType } from "office-ui-fabric-react/lib/Dialog" ; import { ITextField , TextField } from "office-ui-fabric-react/lib/TextField" ; import { css , KeyCodes } from "office-ui-fabric-react/lib/Utilities" ; import * as React from "react" ; import * as ReactDOM from "react-dom" ; import { createLink } from "roosterjs-editor-api" ; import { Editor } from "roosterjs-editor-core" ; import { NullFunction , Strings } from "roosterjs-react-common" ; export const InsertLinkStringKeys = { LinkFieldLabel : "linkFieldLabel" , Title : "linkPromptTitle" , InsertButton : "insertLinkText" , CancelButton : "cancelLinkText" } ; export interface LinkDialogProps { className ? : string ; onDismiss ? : ( ev : React . FocusEvent < HTMLElement > ) => void ; editor : Editor ; strings ? : Strings ; selectionRange ? : Range ; } export interface LinkDialogState { insertButtonDisabled : boolean ; } class LinkDialog extends React . PureComponent < LinkDialogProps , LinkDialogState > { private linkField : ITextField ; private linkInserted : boolean ; constructor ( props ) { super ( props ) ; this . state = { insertButtonDisabled : true } ; } public render ( ) { const { strings = { } , className } = this . props ; return ( < Dialog onDismiss = { this . dismissDialog } dialogContentProps = { { type : DialogType . normal , title : strings [ InsertLinkStringKeys . Title ] } } hidden = { false } modalProps = { { isBlocking : true } } className = { css ( Styles . modal , className ) } > < TextField label = { strings [ InsertLinkStringKeys . LinkFieldLabel ] || "Link" } componentRef = { this . onLinkFieldRef } onKeyDown = { this . onLinkFieldKeyDown } required = { true } onChange = { this . onLinkFieldChanged } / > < DialogFooter > < PrimaryButton onClick = { this . insertLink } text = { strings [ InsertLinkStringKeys . InsertButton ] || "Insert" } disabled = { this . state . insertButtonDisabled } / > < DefaultButton onClick = { this . dismissDialog } text = { strings [ InsertLinkStringKeys . CancelButton ] || "Cancel" } / > < /DialogFooter> < /Dialog>); } public componentDidMount ( ) { this . linkField && this . linkField . focus ( ) ; } private onLinkFieldRef = ( ref ) : void => { this . linkField = ref ; } ; private onLinkFieldChanged = ( _e , newValue ) : void => { this . setState ( { insertButtonDisabled : newValue . trim ( ) . length === 0 } ) ; } ; private onLinkFieldKeyDown = ( ev ) : void => { if ( ev . which === KeyCodes . enter ) { this . insertLink ( ) ; ev . preventDefault ( ) ; ev . stopPropagation ( ) ; } } ; private insertLink = ( ) : void => { const { editor , selectionRange } = this . props ; if ( ! this . linkField || ! editor || editor . isDisposed ( ) ) { return ; } editor && ! editor . isDisposed ( ) && editor . select ( selectionRange ) ; this . linkInserted = true ; createLink ( editor , this . linkField . value ) ; this . dismissDialog ( ) ; } ; private dismissDialog = ( ev ? ) : void => { const { editor , onDismiss = NullFunction , selectionRange } = this . props ; onDismiss ( ev as any ) ; ! this . linkInserted && editor && ! editor . isDisposed ( ) && editor . select ( selectionRange ) ; } ; } export function createLinkDialog ( doc , props , calloutClassName ? ) { const { editor , onDismiss } = props ; let container = doc . createElement ( "div" ) ; doc . body . appendChild ( container ) ; const dispose = ( ) : void => { if ( container ) { ReactDOM . unmountComponentAtNode ( container ) ; container . setAttribute ( "tabindex" , "0" ) ; calloutClassName && container . setAttribute ( "class" , calloutClassName ) ; container . focus ( ) ; editor && ! editor . isDisposed ( ) && editor . focus ( ) ; container . parentElement . removeChild ( container ) ; container = null ; } } ; const selectionRange = editor && ! editor . isDisposed ( ) ? editor . getSelectionRange ( ) : null ; ReactDOM . render ( < LinkDialog { ... props } selectionRange = { selectionRange } onDismiss = { ( ev ) : void => { dispose ( ) ; onDismiss && onDismiss ( ev ) ; } } className = { css ( calloutClassName , props . className ) } / > , container ) ; return dispose ; }