import * as React from 'react' ; import findIndex from 'lodash/findIndex' ; import { ISiteFilePickerTabProps } from './ISiteFilePickerTabProps' ; import { ISiteFilePickerTabState } from './ISiteFilePickerTabState' ; import { DocumentLibraryBrowser } from '../controls/DocumentLibraryBrowser/DocumentLibraryBrowser' ; import { FileBrowser } from '../controls/FileBrowser/FileBrowser' ; import { PrimaryButton , DefaultButton } from 'office-ui-fabric-react/lib/components/Button' ; import { Breadcrumb , IBreadcrumbItem } from 'office-ui-fabric-react/lib/Breadcrumb' ; import { IFile , IFolder , ILibrary } from '../../../services/FileBrowserService.types' ; import { Link } from 'office-ui-fabric-react/lib/Link' ; import { IFilePickerResult , FilePickerBreadcrumbItem } from '../FilePicker.types' ; import { SPWeb } from "@microsoft/sp-page-context" ; import styles from './SiteFilePickerTab.module.scss' ; import * as strings from 'ControlStrings' ; import { urlCombine } from '../../../common/utilities' ; import { cloneDeep } from '@microsoft/sp-lodash-subset' ; export default class SiteFilePickerTab extends React . Component < ISiteFilePickerTabProps , ISiteFilePickerTabState > { private _defaultLibraryNamePromise : Promise < void | string > = Promise . resolve ( ) ; constructor ( props ) { super ( props ) ; const breadcrumbSiteNode = this . props . breadcrumbFirstNode ? this . props . breadcrumbFirstNode : { isCurrentItem : false , text : props . context . pageContext . web . title , key : props . context . pageContext . web . id . toString ( ) , } ; breadcrumbSiteNode . onClick = ( ev , itm ) => { this . onBreadcrumpItemClick ( itm ) ; } ; let breadcrumbItems = [ breadcrumbSiteNode ] ; let { folderAbsPath = undefined , libraryServRelUrl = undefined , folderServRelPath = undefined , folderBreadcrumbs = [ ] } = props . defaultFolderAbsolutePath ? this . _parseInitialLocationState ( props . defaultFolderAbsolutePath , props . context . pageContext . web ) : { } ; breadcrumbItems . push ( ... folderBreadcrumbs ) ; breadcrumbItems [ breadcrumbItems . length - 1 ] . isCurrentItem = true ; this . state = { filePickerResult : null , libraryAbsolutePath : folderAbsPath || undefined , libraryUrl : libraryServRelUrl || urlCombine ( props . context . pageContext . web . serverRelativeUrl , '/Shared%20Documents' ) , libraryPath : folderServRelPath , folderName : strings . DocumentLibraries , breadcrumbItems } ; } private _parseInitialLocationState ( folderAbsPath , { serverRelativeUrl : webServRelUrl , absoluteUrl : webAbsUrl } ) { let folderServRelPath = folderAbsPath && folderAbsPath . substr ( folderAbsPath . indexOf ( webServRelUrl ) ) ; if ( webServRelUrl === "/" ) { folderServRelPath = folderAbsPath && folderAbsPath . split ( webAbsUrl ) [ 1 ] ; } let folderWebRelPath = folderServRelPath && folderServRelPath . substr ( webServRelUrl . length ) ; let libInternalName = folderWebRelPath && folderWebRelPath . substring ( 1 , Math . max ( folderWebRelPath . indexOf ( "/" , 2 ) , 0 ) || undefined ) ; if ( webServRelUrl === "/" ) { libInternalName = folderWebRelPath && folderWebRelPath . substring ( 0 , Math . max ( folderWebRelPath . indexOf ( "/" , 2 ) , 0 ) || undefined ) ; } let libraryServRelUrl = urlCombine ( webServRelUrl , libInternalName ) ; let tenantUrl = folderAbsPath . substring ( 0 , folderAbsPath . indexOf ( webServRelUrl ) ) ; if ( webAbsUrl === "/" ) { tenantUrl = webAbsUrl ; } let folderBreadcrumbs = this . parseBreadcrumbsFromPaths ( libraryServRelUrl , folderServRelPath , folderWebRelPath , webAbsUrl , tenantUrl , libInternalName , webServRelUrl ) ; return { libraryServRelUrl , folderServRelPath , folderAbsPath , folderBreadcrumbs } ; } private parseBreadcrumbsFromPaths ( libraryServRelUrl , folderServRelPath , folderWebRelPath , webAbsUrl , tenantUrl , libInternalName , webServRelUrl ) { this . _defaultLibraryNamePromise = this . props . fileBrowserService . getLibraryNameByInternalName ( libInternalName ) ; let folderBreadcrumbs = [ ] ; folderBreadcrumbs . push ( { isCurrentItem : false , text : libInternalName , key : libraryServRelUrl , libraryData : { serverRelativeUrl : libraryServRelUrl , absoluteUrl : urlCombine ( webAbsUrl , libInternalName ) , title : libInternalName } , onClick : ( ev , itm ) => { this . onBreadcrumpItemClick ( itm ) ; } } ) ; if ( folderServRelPath != libraryServRelUrl ) { let folderLibRelPath = folderWebRelPath . substring ( libInternalName . length + 2 ) ; if ( webServRelUrl === "/" ) { folderLibRelPath = folderWebRelPath . substring ( libInternalName . length + 1 ) ; } let breadcrumbFolderServRelPath = libraryServRelUrl ; let crumbs = folderLibRelPath . split ( "/" ) . map ( ( currFolderName => { breadcrumbFolderServRelPath += `/${ currFolderName }` ; return { isCurrentItem : false , text : currFolderName , key : urlCombine ( tenantUrl , breadcrumbFolderServRelPath ) , folderData : { name : currFolderName , absoluteUrl : urlCombine ( tenantUrl , breadcrumbFolderServRelPath ) , serverRelativeUrl : breadcrumbFolderServRelPath , } , onClick : ( ev , itm ) => { this . onBreadcrumpItemClick ( itm ) ; } } ; } ) ) ; folderBreadcrumbs . push ( ... crumbs ) ; } return folderBreadcrumbs ; } public componentDidMount ( ) { this . _defaultLibraryNamePromise . then ( docLibName => { if ( docLibName ) { let updatedBCItems = cloneDeep ( this . state . breadcrumbItems ) ; updatedBCItems . forEach ( crumb => { if ( crumb . libraryData ) { crumb . text = docLibName ; crumb . libraryData . title = docLibName ; } } ) ; this . setState ( { breadcrumbItems : updatedBCItems } ) ; } } ) . catch ( ( err ) => { console . log ( "[SiteFilePicker] Failed To Fetch defaultLibraryName, defaulting to internal name" ) ; } ) ; } public render ( ) { return ( < div className = { styles . tabContainer } > < div className = { styles . tabHeaderContainer } > < Breadcrumb items = { this . state . breadcrumbItems } className = { styles . breadcrumbNav } / > < /div> < div className = { styles . tabFiles } > { this . state . libraryAbsolutePath === undefined && < DocumentLibraryBrowser fileBrowserService = { this . props . fileBrowserService } includePageLibraries = { this . props . includePageLibraries } onOpenLibrary = { ( selectedLibrary ) => this . _handleOpenLibrary ( selectedLibrary , true ) } />} { this . state . libraryAbsolutePath !== undefined && < FileBrowser onChange = { ( filePickerResult ) => this . _handleSelectionChange ( filePickerResult ) } onOpenFolder = { ( folder ) => this . _handleOpenFolder ( folder , true ) } fileBrowserService = { this . props . fileBrowserService } libraryUrl = { this . state . libraryUrl } folderPath = { this . state . libraryPath } accepts = { this . props . accepts } / > } < /div> < div className = { styles . actionButtonsContainer } > < div className = { styles . actionButtons } > < PrimaryButton disabled = { ! this . state . filePickerResult } onClick = { ( ) => this . _handleSave ( ) } className = { styles . actionButton } > { strings . OpenButtonLabel } < /PrimaryButton> < DefaultButton onClick = { ( ) => this . _handleClose ( ) } className = { styles . actionButton } > { strings . CancelButtonLabel } < /DefaultButton> < /div> < /div> < /div>); } private renderBreadcrumbItem = ( item ) : JSX . Element => { return ( < Link href = { item . href } onClick = { item . onClick } key = { item . key } className = { `ms-Link ms-Breadcrumb-itemLink ${ styles . breadcrumbNavItem }` } > { item . text } < /Link>); } ; private onBreadcrumpItemClick = ( node ) => { let { breadcrumbItems } = this . state ; let breadcrumbClickedItemIndx = 0 ; if ( node . libraryData == null && node . folderData == null ) { this . setState ( { libraryAbsolutePath : undefined , libraryPath : undefined , folderName : undefined } ) ; } else if ( node . folderData != null ) { this . _handleOpenFolder ( node . folderData , false ) ; breadcrumbClickedItemIndx = findIndex ( breadcrumbItems , item => item . folderData && item . folderData . absoluteUrl === node . key ) ; } else if ( node . libraryData != null ) { this . _handleOpenLibrary ( node . libraryData , false ) ; breadcrumbClickedItemIndx = findIndex ( breadcrumbItems , item => item . libraryData && item . libraryData . serverRelativeUrl === node . key ) ; } breadcrumbItems = breadcrumbItems . slice ( 0 , breadcrumbClickedItemIndx + 1 ) ; breadcrumbItems [ breadcrumbItems . length - 1 ] . isCurrentItem = true ; this . setState ( { breadcrumbItems , filePickerResult : undefined } ) ; } ; private _handleSelectionChange = ( filePickerResult ) => { if ( filePickerResult ) { filePickerResult . downloadFileContent = ( ) => { return this . props . fileBrowserService . downloadSPFileContent ( filePickerResult . fileAbsoluteUrl , filePickerResult . fileName ) ; } ; } this . setState ( { filePickerResult } ) ; } ; private _handleSave = ( ) => { this . props . onSave ( [ this . state . filePickerResult ] ) ; } ; private _handleClose = ( ) => { this . props . onClose ( ) ; } ; private _handleOpenFolder = ( folder , addBreadcrumbNode ) => { const { breadcrumbItems } = this . state ; if ( addBreadcrumbNode ) { breadcrumbItems . map ( item => item . isCurrentItem = false ) ; const breadcrumbNode = { folderData : folder , isCurrentItem : true , text : folder . name , key : folder . absoluteUrl , onClick : ( ev , itm ) => { this . onBreadcrumpItemClick ( itm ) ; } } ; breadcrumbItems . push ( breadcrumbNode ) ; } this . setState ( { filePickerResult : null , libraryPath : folder . serverRelativeUrl , folderName : folder . name , libraryAbsolutePath : folder . absoluteUrl , breadcrumbItems } ) ; } ; private _handleOpenLibrary = ( library , addBreadcrumbNode ) => { const { breadcrumbItems } = this . state ; if ( addBreadcrumbNode ) { breadcrumbItems . map ( item => item . isCurrentItem = false ) ; const breadcrumbNode = { libraryData : library , isCurrentItem : true , text : library . title , key : library . serverRelativeUrl , onClick : ( ev , itm ) => { this . onBreadcrumpItemClick ( itm ) ; } } ; breadcrumbItems . push ( breadcrumbNode ) ; } this . setState ( { libraryAbsolutePath : library . absoluteUrl , libraryUrl : library . serverRelativeUrl , libraryPath : library . serverRelativeUrl , breadcrumbItems } ) ; } ; }