UNPKG

@mikezimm/fps-library-v2

Version:

Library of reusable typescript/javascript functions, interfaces and constants

257 lines (255 loc) 15.2 kB
/** * CodeAnalizerComment: Updated 2 imports on 2024-09-22 14:49:52 * Update:: import { complexStringSearch } to '@mikezimm/fps-core-v7/lib/logic/Strings/filtering;' * Update:: import { IAnySourceItemAny } to '@mikezimm/fps-core-v7/lib/components/molecules/AnyContent/IAnyContent;' */ /** * CodeAnalizerComment: Updated 3 imports on 2024-09-21 23:07:24 * Update:: import { IUrlPairs } to '@mikezimm/fps-core-v7/lib/components/molecules/AnyContent/IFPSItemRelated;' * Update:: import { makeid } to '@mikezimm/fps-core-v7/lib/logic/Strings/guids;' * Update:: import { IAnySourceItemAny } to '@mikezimm/fps-core-v7/lib/components/molecules/AnyContent/IAnyContent;' */ /** * RelatedItems originally copied from * https://github.com/pnp/sp-dev-fx-webparts/tree/main/samples/react-page-navigator */ import * as React from 'react'; import { Icon, } from '@fluentui/react/lib/Icon'; import { getRelatedItems } from './GetItems'; import { complexStringSearch } from '@mikezimm/fps-core-v7/lib/logic/Strings/filtering'; import { makeid } from '@mikezimm/fps-core-v7/lib/logic/Strings/guids'; // import { fetchFileEmbedUrlD } from '@mikezimm/fps-pnp2/lib/services/sp/fetch/items/fetchFileEmbedUrl'; import { getFileEmbedUrl } from '@mikezimm/fps-core-v7/lib/restAPIs/lists/files/getFileEmbedUrl'; // import { complexStringSearch } from '../Services/Strings_/filtering'; require('@mikezimm/fps-styles/dist/RelatedItems.css'); /** * 2024-12-15: Updated to do all fetching from fps-core-v7 */ export default class RelatedItems extends React.Component { constructor(props) { super(props); this.regExpOrigin = new RegExp(`${window.location.origin}`, 'gim'); this.regExpWeb = new RegExp(`${this.props.fetchInfo.web}`, 'gim'); let fetched = false; let items = []; if (this.props.items && this.props.items.length > 0) { items = this.props.items; fetched = true; } this.state = { relatedItems: { minSourceFetchProps: null, items: [], index: [], loaded: false, refreshId: makeid(5), status: 'Unknown', e: null, fpsContentType: ['item'], ok: null, unifiedPerformanceOps: null, fetchAPI: '', method: null }, textFilter: this.props.fetchInfo.textFilter ? this.props.fetchInfo.textFilter : '', linkFilter: this.props.linkFilter ? this.props.linkFilter : '', filteredItems: items, canvasImagesExpanded: false, canvasLinksExpanded: false, }; // this.onLinkClick = this.onLinkClick.bind(this); } componentDidMount() { this._getRelatedItems(this.props.fetchInfo.textFilter, this.props.linkFilter); } componentDidUpdate(prevProps) { // if (JSON.stringify(prevProps.items) !== JSON.stringify(this.props.items)) { // this.setState({ items: this.props.items, selectedKey: this.props.items[0] ? this.props.items[0].key : '' }); // } else if (prevProps.showItems !== this.props.showItems) { //Force component update in case it was not previously rendered if (prevProps.showItems !== this.props.showItems) { //Force component update in case it was not previously rendered this._getRelatedItems(this.props.fetchInfo.textFilter, this.props.linkFilter); } else if (prevProps.isExpanded !== this.props.isExpanded) { //Force component update in case it was not previously rendered this._getRelatedItems(this.props.fetchInfo.textFilter, this.props.linkFilter); } else if (prevProps.linkFilter !== this.props.linkFilter) { //Force component update in case it was not previously rendered this._getRelatedItems(this.props.fetchInfo.textFilter, this.props.linkFilter); } } /** * WHY IS textFilter a param that is passed into state but then the filtering uses the state version? * @param textFilter * @param linkFilter */ async _getRelatedItems(textFilter, linkFilter) { // this.setState({ items: this.props.items, selectedKey: this.props.items[0] ? this.props.items[0].key : '' }); let canvasImagesExpanded = linkFilter ? true : this.state.canvasImagesExpanded; let canvasLinksExpanded = linkFilter ? true : this.state.canvasLinksExpanded; if (this.props.showItems === true && this.props.isExpanded === true && this.state.relatedItems.loaded !== true) { /** * 2024-12-15: Updated to use fps-core-v7 */ let results = await getRelatedItems(this.props.fetchInfo); let fetched = results.loaded; let filteredItems = results.items; if (this.state.textFilter && results.items && results.items.length > 0) { filteredItems = []; results.items.map((item) => { let pushItem = true; if (this.props && this.props.fetchInfo && this.props.fetchInfo.textFilterProps && this.props.fetchInfo.textFilterProps.length > 0) { //Search all props ( must be string values or it will error ) this.props.fetchInfo.textFilterProps.map((key) => { //If key does not exist or the key.lowerCase !== textFilter.lowerCase, do not push item. const itemKey = typeof item[key] === 'string' ? item[key] : ''; //Added to resolve typing error if (item[key] === null || item[key] === undefined || itemKey.toLowerCase().indexOf(this.state.textFilter.toLowerCase()) < 0) { pushItem = false; } }); } if (pushItem === true) { filteredItems.push(item); } }); } this.setState({ relatedItems: results, filteredItems: filteredItems, textFilter: textFilter ? textFilter : '', linkFilter: linkFilter ? linkFilter : '', canvasImagesExpanded: canvasImagesExpanded, canvasLinksExpanded: canvasLinksExpanded, }); } else if (this.props.showItems === true && this.props.isExpanded === true) { //Already fetched, just update filters this.setState({ linkFilter: linkFilter ? linkFilter : '', canvasImagesExpanded: canvasImagesExpanded, canvasLinksExpanded: canvasLinksExpanded, }); } } // private onLinkClick(ev: React.MouseEvent<HTMLElement>, item?: INavLink) { // this.setState({ selectedKey: item.key }); // } filterUrlPairs(items, linkFilter, expanded, UrlType) { const showPropsStyles = expanded === true ? 'showProperties' : 'hideProperties'; let returnItems = []; items.map(item => { // https://github.com/mikezimm/PageInfo/issues/114 const descLong = decodeURI(item.url.replace(this.regExpOrigin, '').replace(this.regExpWeb, '/ThisSite')); let desc = this.props.linkTrimmed === false ? descLong : descLong.replace(/(?<=\/ThisSite\/).*(?=\/)/gi, '...'); let showItem = complexStringSearch(linkFilter, desc, ';', '<>', true); // if ( linkFilter && desc.toLowerCase().indexOf( linkFilter.toLowerCase() ) < 0) { showItem = false; } if (showItem === true) { let label = React.createElement("span", { className: 'trimText' }, desc); if (item.url) { let liTitle = `Go to ${item.url}`; // return <li className = { 'isLink' } style={ this.props.itemsStyle } title={liTitle} onClick={ () => { this.onLinkClick.bind( this, item.url, item.embed ); }}>{ label } returnItems.push(React.createElement("li", { className: 'isLink', style: this.props.itemsStyle, title: liTitle, onClick: this.onLinkClick.bind(this, item.url, item.embed) }, label, React.createElement(Icon, { title: `Go to ${item.url}`, iconName: 'OpenInNewTab' }))); } else { returnItems.push(React.createElement("li", { style: this.props.itemsStyle }, label)); } } }); let headingCount = linkFilter && linkFilter.length > 0 ? `${returnItems.length} of ${items.length}` : `${returnItems.length}`; let heading = `Embedded ${UrlType} ( ${headingCount} )`; return React.createElement("div", null, React.createElement("div", { className: 'relatedSubTitle', onClick: () => { this.toggleRelated(`canvas${UrlType}Expanded`); }, title: `Click to toggle ${UrlType}` }, " ", heading, " "), React.createElement("div", { className: showPropsStyles }, returnItems)); } filterRelatedItems(items, textFilter) { let returnItems = []; items.map(item => { let searchLinkText = typeof item.FPSItem.Related.linkText === 'string' ? item.FPSItem.Related.linkText : ''; let searchLinkUrl = typeof item.FPSItem.Related.linkUrl === 'string' ? item.FPSItem.Related.linkUrl : ''; let searchString = [searchLinkText, searchLinkUrl].join(' || '); let showItem = true; if (textFilter && searchString.toLowerCase().indexOf(textFilter.toLowerCase()) < 0) { showItem = false; } if (showItem === true) { let label = React.createElement("span", { className: 'trimText' }, item.FPSItem.Related.linkText); if (item.FPSItem.Related.linkUrl) { let liTitle = `Go to ${item.FPSItem.Related.linkText}`; // return <li className = { 'isLink' } style={ this.props.itemsStyle } title={liTitle} onClick={ () => { this.onLinkClick.bind( this, item.FPSItem.Related.linkUrl, item.FPSItem.Related.linkAlt ); }}>{ label } returnItems.push(React.createElement("li", { className: 'isLink', style: this.props.itemsStyle, title: liTitle, onClick: this.onLinkClick.bind(this, item.FPSItem.Related.linkUrl, item.FPSItem.Related.linkAlt) }, label, React.createElement(Icon, { title: `Go to ${item.FPSItem.Related.linkUrl}`, iconName: 'OpenInNewTab' }))); } else { returnItems.push(React.createElement("li", { style: this.props.itemsStyle }, label)); } } }); return returnItems; } render() { // const { semanticColors }: IReadonlyTheme = this.props.themeVariant; if (this.props.showItems === false) { return (null); } else { //If there is a null value, it will just show it const { relatedItems, textFilter, linkFilter, canvasImagesExpanded, canvasLinksExpanded } = this.state; const { errorInfo, items, } = relatedItems; // const itemsRelated: IAnyContentRelated[] = items; let linksElement = null; if (this.props.parentKey !== 'pageLinks') { // @1.0.188 - 2023-May-15: added errorInfo check after issue testing PageInfo let noItemsMessage = errorInfo && errorInfo.returnMess ? React.createElement("div", { style: { color: 'red', fontWeight: 600 } }, errorInfo.returnMess) : 'There are no related items ;('; linksElement = items.length === 0 ? React.createElement("div", { style: { paddingLeft: '20px', paddingBottom: '10px', fontSize: 'larger' } }, noItemsMessage) : React.createElement("div", null, this.filterRelatedItems(items, textFilter)); } let imgList = null; if (this.props.fetchInfo.canvasImgs === true && items.length > 0 && items[0].FPSItem.Related.images.length > 0) { imgList = this.filterUrlPairs(items[0].FPSItem.Related.images, linkFilter, canvasImagesExpanded, 'Images'); } let linksList = null; if (this.props.fetchInfo.canvasLinks === true && items.length > 0 && items[0].FPSItem.Related.links.length > 0) { let paddingTop = imgList ? '10px' : undefined; linksList = this.filterUrlPairs(items[0].FPSItem.Related.links, linkFilter, canvasLinksExpanded, 'Links'); } return (React.createElement("div", { className: 'relatedItems' }, linksElement, imgList, linksList)); } } toggleRelated(propToToggle) { let newExpanded = this.state[propToToggle] === true ? false : true; if (propToToggle === 'canvasImagesExpanded') { this.setState({ canvasImagesExpanded: newExpanded }); } else if (propToToggle === 'canvasLinksExpanded') { this.setState({ canvasLinksExpanded: newExpanded }); } else { alert(`Whhhooaaa, was not expecting this propToToggle: ${propToToggle} ~ RelatedItems 171`); } } // private async onLinkClick( gotoLink: string, altLink: string, ev: MouseEvent ) { async onLinkClick(gotoLink, altLink, ev) { // alert('Going to ' + gotoLink ); console.log('onLinkClick ev:', ev); if (ev.altKey === true && altLink) { if (altLink !== 'gotoLink') { window.open(altLink, '_blank'); } else { /** * 2024-12-15: NOTE - Made a calculated risk here that digest value would already be on the window given it was needed to fetch the list itself. */ getFileEmbedUrl({ fpsSpService: this.props.fpsSpService, webUrl: this.props.fetchInfo.web, FileByServerRelativePath: gotoLink, ThenGo: true, digestValue: '' }); // MIGRATED TO FPS-PNP2 // let decodedLink = decodeURI(gotoLink); // try { // let web = Web( `${window.location.origin}${this.props.fetchInfo.web}` ); // const item: any = await web.getFileByServerRelativePath( decodedLink ).select('*,ServerRedirectedEmbedUrl').getItem(); // console.log('onLinkClick alt-click item: ', decodedLink, item); // if ( item.ServerRedirectedEmbedUrl ) { // window.open( item.ServerRedirectedEmbedUrl, '_blank' ) ; // } else { // window.open( decodedLink, '_blank' ) ; // } // } catch (e) { // console.log('onLinkClick alt-click error: ', decodedLink, e ); // window.open( decodedLink, '_blank' ) ; // } } } else { window.open(gotoLink, '_blank'); } } } //# sourceMappingURL=RelatedItems.js.map