@mikezimm/fps-library-v2
Version:
Library of reusable typescript/javascript functions, interfaces and constants
257 lines (255 loc) • 15.2 kB
JavaScript
/**
* 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