import { Document } from "../../Document" ; import { Helper , RTFJSError } from "../../Helper" ; import { GlobalState } from "../Containers" ; import { DestinationBase , DestinationFormattedTextBase , DestinationTextBase , findParentDestination , } from "./DestinationBase" ; import { PictDestination } from "./PictDestinations" ; import { RtfDestination } from "./RtfDestination" ; export interface IField { renderFieldBegin ( field , rtf , records ) : boolean ; renderFieldEnd ( field , rtf , records ) : void ; } export class FieldDestination extends DestinationBase { private _haveInst : boolean ; private _parsedInst : IField ; private _result : FldrsltDestination ; constructor ( ) { super ( "field" ) ; this . _haveInst = false ; this . _parsedInst = null ; this . _result = null ; } public apply ( ) { if ( ! this . _haveInst ) { throw new RTFJSError ( "IField has no fldinst destination" ) ; } } public setInst ( inst ) { this . _haveInst = true ; if ( this . _parsedInst != null ) { throw new RTFJSError ( "IField cannot have multiple fldinst destinations" ) ; } if ( inst instanceof Promise ) { inst . then ( ( parsedInst ) => { this . _parsedInst = parsedInst ; } ) . catch ( ( error ) => { this . _parsedInst = null ; throw new RTFJSError ( error . message ) ; } ) ; } else { this . _parsedInst = inst ; } } public getInst ( ) { return this . _parsedInst ; } public setResult ( inst ) { if ( this . _result != null ) { throw new RTFJSError ( "IField cannot have multiple fldrslt destinations" ) ; } this . _result = inst ; } } class FieldBase { private _fldinst : FldinstDestination ; constructor ( fldinst ) { this . _fldinst = fldinst ; } public renderFieldEnd ( field , rtf , records ) { if ( records > 0 ) { rtf . addIns ( ( renderer ) => { renderer . popContainer ( ) ; } ) ; } } } class FieldHyperlink extends FieldBase { private _url : string ; constructor ( fldinst , data ) { super ( fldinst ) ; this . _url = data ; } public url ( ) { return this . _url ; } public renderFieldBegin ( field , rtf , records ) { const self = this ; if ( records > 0 ) { rtf . addIns ( ( renderer ) => { const inst = renderer . _doc ; const create = ( ) => { return renderer . buildHyperlinkElement ( self . _url ) ; } ; let container ; if ( inst . _settings . onHyperlink != null ) { container = inst . _settings . onHyperlink ( create , { url ( ) { return self . url ( ) ; } , } ) ; } else { const elem = create ( ) ; container = { element : elem , content : elem , } ; } renderer . pushContainer ( container ) ; } ) ; return true ; } return false ; } } export class FldinstDestination extends DestinationTextBase { private parser : GlobalState ; private inst : Document ; constructor ( parser , inst ) { super ( "fldinst" ) ; this . parser = parser ; this . inst = inst ; } public apply ( ) { const field = findParentDestination ( this . parser , "field" ) as FieldDestination ; if ( field == null ) { throw new RTFJSError ( "fldinst destination must be child of field destination" ) ; } field . setInst ( this . parseType ( ) ) ; } private parseType ( ) { this . text = this . text . trim ( ) ; const sep = this . text . indexOf ( " " ) ; if ( sep > 0 ) { let data = this . text . substr ( sep + 1 ) ; if ( data . length >= 2 && data [ 0 ] === "\"" ) { const end = data . indexOf ( "\"" , 1 ) ; if ( end >= 1 ) { data = data . substring ( 1 , end ) ; } } const fieldType = this . text . substr ( 0 , sep ) . toUpperCase ( ) ; switch ( fieldType ) { case "HYPERLINK" : return new FieldHyperlink ( this , data ) ; case "IMPORT" : if ( typeof this . inst . _settings . onImport === "function" ) { let pict ; this . inst . addIns ( ( renderer ) => { const inst = renderer . _doc ; const hook = inst . _settings . onPicture ; inst . _settings . onPicture = null ; let { isLegacy , element } = pict . apply ( true ) ; inst . _settings . onPicture = hook ; if ( typeof hook === "function" ) { element = hook ( isLegacy , ( ) => element ) ; } if ( element != null ) { renderer . appendElement ( element ) ; } } ) ; const promise = new Promise ( ( resolve , reject ) => { try { const cb = ( { error , keyword , blob , width , height } ) => { if ( ! error && typeof keyword === "string" && keyword && blob ) { const dims = { w : Helper . _pxToTwips ( width || window . document . body . clientWidth || window . innerWidth ) , h : Helper . _pxToTwips ( height || 300 ) , } ; pict = new PictDestination ( this . parser , this . inst ) ; pict . handleBlob ( blob ) ; pict . handleKeyword ( keyword , 8 ) ; pict . _displaysize . width = dims . w ; pict . _displaysize . height = dims . h ; pict . _size . width = dims . w ; pict . _size . height = dims . h ; const _parsedInst = { renderFieldBegin : ( ) => true , renderFieldEnd : ( ) => null , } ; resolve ( _parsedInst ) ; } else { Helper . log ( "[fldinst]: failed to IMPORT image file: " + data ) ; if ( error ) { error = ( error instanceof Error ) ? error : new Error ( error ) ; reject ( error ) ; } else { resolve ( null ) ; } } } ; this . inst . _settings . onImport ( data , cb ) ; } catch ( error ) { reject ( error ) ; } } ) ; this . parser . _asyncTasks . push ( promise ) ; return promise ; } break ; default : Helper . log ( "[fldinst]: unknown field type: " + fieldType ) ; break ; } } } } export class FldrsltDestination extends DestinationFormattedTextBase { constructor ( parser , inst ) { super ( parser , "fldrslt" ) ; } public apply ( ) { const field = findParentDestination ( this . parser , "field" ) as FieldDestination ; if ( field != null ) { field . setResult ( this ) ; } super . apply ( ) ; } public renderBegin ( rtf , records ) { const field = findParentDestination ( this . parser , "field" ) as FieldDestination ; if ( field != null ) { const inst = field . getInst ( ) ; if ( inst != null ) { return inst . renderFieldBegin ( field , rtf , records ) ; } } return false ; } public renderEnd ( rtf , records ) { const field = findParentDestination ( this . parser , "field" ) as FieldDestination ; if ( field != null ) { const inst = field . getInst ( ) ; if ( inst != null ) { inst . renderFieldEnd ( field , rtf , records ) ; } } } }