Merge pull request #1586 from DonKirkham/upgrade-react-carousel

This commit is contained in:
Hugo Bernier 2020-11-04 17:31:10 -05:00 committed by GitHub
commit 9012702df9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 3293 additions and 5125 deletions

View File

@ -1,6 +1,6 @@
{ {
"@microsoft/generator-sharepoint": { "@microsoft/generator-sharepoint": {
"version": "1.10.0", "version": "1.11.0",
"libraryName": "react-carousel", "libraryName": "react-carousel",
"libraryId": "263a1d21-f4c7-4a46-a364-e5f995286b9b", "libraryId": "263a1d21-f4c7-4a46-a364-e5f995286b9b",
"environment": "spo", "environment": "spo",

View File

@ -27,7 +27,7 @@ It uses Microsoft Graph API to get image/video url and use PnPjs to load files f
## Used SharePoint Framework Version ## Used SharePoint Framework Version
![1.10](https://img.shields.io/badge/version-1.10.0-green.svg) ![1.11](https://img.shields.io/badge/version-1.11.0-green.svg)
## Applies to ## Applies to
@ -60,6 +60,7 @@ Solution|Author(s)
--------|--------- --------|---------
Carousel Image/Video Web Part|João Mendes Carousel Image/Video Web Part|João Mendes
Carousel Image/Video Web Part|Rahul Suryawanshi ([@rahulsuryawansh](https://twitter.com/rahulsuryawansh)) Carousel Image/Video Web Part|Rahul Suryawanshi ([@rahulsuryawansh](https://twitter.com/rahulsuryawansh))
Carousel Image/Video Web Part|Don Kirkham ([@DonKirkham](https://twitter.com/DonKirkham))
## Version history ## Version history
@ -67,6 +68,7 @@ Version|Date|Comments
-------|----|-------- -------|----|--------
1.0.0|July 11, 2019|Initial release 1.0.0|July 11, 2019|Initial release
2.0.0|June 17, 2020|Upgraded to SPFx v1.10.0 (Rahul Suryawanshi) 2.0.0|June 17, 2020|Upgraded to SPFx v1.10.0 (Rahul Suryawanshi)
3.0.0|October 31, 2020|Upgraded to SPFx v1.11.0 (Don Kirkham)
## Disclaimer ## Disclaimer

View File

@ -1,14 +1,21 @@
{ {
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/package-solution.schema.json", "$schema": "https://developer.microsoft.com/json-schemas/spfx-build/package-solution.schema.json",
"solution": { "solution": {
"name": "react-carousel-client-side-solution", "name": "react-carousel-client-side-solution",
"id": "263a1d21-f4c7-4a46-a364-e5f995286b9b", "id": "263a1d21-f4c7-4a46-a364-e5f995286b9b",
"version": "2.0.0.0", "version": "3.0.0.0",
"includeClientSideAssets": true, "includeClientSideAssets": true,
"skipFeatureDeployment": true, "skipFeatureDeployment": true,
"isDomainIsolated": false "isDomainIsolated": false,
}, "developer": {
"paths": { "name": "Contoso",
"zippedPackage": "solution/react-carousel.sppkg" "privacyUrl": "https://contoso.com/privacy",
} "termsOfUseUrl": "https://contoso.com/terms-of-use",
} "websiteUrl": "https://contoso.com/my-app",
"mpnId": "000000"
}
},
"paths": {
"zippedPackage": "solution/react-carousel.sppkg"
}
}

File diff suppressed because it is too large Load Diff

View File

@ -14,12 +14,12 @@
"test:watch": "./node_modules/.bin/jest --config ./config/jest.config.json --watchAll" "test:watch": "./node_modules/.bin/jest --config ./config/jest.config.json --watchAll"
}, },
"dependencies": { "dependencies": {
"@microsoft/sp-core-library": "1.10.0", "@microsoft/sp-core-library": "1.11.0",
"@microsoft/sp-http": "1.10.0", "@microsoft/sp-http": "1.11.0",
"@microsoft/sp-lodash-subset": "1.10.0", "@microsoft/sp-lodash-subset": "1.11.0",
"@microsoft/sp-office-ui-fabric-core": "1.10.0", "@microsoft/sp-office-ui-fabric-core": "1.11.0",
"@microsoft/sp-property-pane": "1.10.0", "@microsoft/sp-property-pane": "1.11.0",
"@microsoft/sp-webpart-base": "1.10.0", "@microsoft/sp-webpart-base": "1.11.0",
"@microsoft/teams-js": "^1.6.0", "@microsoft/teams-js": "^1.6.0",
"@pnp/common": "^1.3.11", "@pnp/common": "^1.3.11",
"@pnp/graph": "^1.3.11", "@pnp/graph": "^1.3.11",
@ -46,10 +46,10 @@
}, },
"devDependencies": { "devDependencies": {
"@microsoft/rush-stack-compiler-3.3": "0.3.5", "@microsoft/rush-stack-compiler-3.3": "0.3.5",
"@microsoft/sp-build-web": "1.10.0", "@microsoft/sp-build-web": "1.11.0",
"@microsoft/sp-module-interfaces": "1.10.0", "@microsoft/sp-module-interfaces": "1.11.0",
"@microsoft/sp-tslint-rules": "1.10.0", "@microsoft/sp-tslint-rules": "1.11.0",
"@microsoft/sp-webpart-workbench": "1.10.0", "@microsoft/sp-webpart-workbench": "1.11.0",
"@types/chai": "3.4.34", "@types/chai": "3.4.34",
"@types/mocha": "2.2.38", "@types/mocha": "2.2.38",
"@types/react": "16.8.8", "@types/react": "16.8.8",

View File

@ -19,225 +19,229 @@ import * as strings from 'CarouselWebPartStrings';
import { DisplayMode } from '@microsoft/sp-core-library'; import { DisplayMode } from '@microsoft/sp-core-library';
import { CommunicationColors } from '@uifabric/fluent-theme/lib/fluent/FluentColors'; import { CommunicationColors } from '@uifabric/fluent-theme/lib/fluent/FluentColors';
import { import {
Spinner, Spinner,
SpinnerSize, SpinnerSize,
MessageBar, MessageBar,
MessageBarType, MessageBarType,
Label, Label,
Icon, Icon,
ImageFit, ImageFit,
Image, Image,
ImageLoadState, ImageLoadState,
} from 'office-ui-fabric-react'; } from 'office-ui-fabric-react';
export default class Carousel extends React.Component<ICarouselProps, ICarouselState> { export default class Carousel extends React.Component<ICarouselProps, ICarouselState> {
private spService: spservices = null; private spService: spservices = null;
private _teamsContext: microsoftTeams.Context = null; private _teamsContext: microsoftTeams.Context = null;
public constructor(props: ICarouselProps) { public constructor(props: ICarouselProps) {
super(props); super(props);
this.spService = new spservices(this.props.context); this.spService = new spservices(this.props.context);
if (this.props.context.microsoftTeams) { if (this.props.context.microsoftTeams) {
this.props.context.microsoftTeams.getContext(context => { this.props.context.microsoftTeams.getContext(context => {
this._teamsContext = context; this._teamsContext = context;
console.log('ctt', this._teamsContext.theme); console.log('ctt', this._teamsContext.theme);
this.setState({ teamsTheme: this._teamsContext.theme }); this.setState({ teamsTheme: this._teamsContext.theme });
}); });
} }
this.state = { this.state = {
isLoading: false, isLoading: false,
errorMessage: '', errorMessage: '',
hasError: false, hasError: false,
teamsTheme: 'default', teamsTheme: 'default',
photoIndex: 0, photoIndex: 0,
carouselImages: [], carouselImages: [],
loadingImage: true loadingImage: true
}; };
} }
private onConfigure() { private onConfigure() {
// Context of the web part // Context of the web part
this.props.context.propertyPane.open(); this.props.context.propertyPane.open();
} }
private async loadPictures() { private async loadPictures() {
this.setState({ isLoading: true, hasError: false }); this.setState({ isLoading: true, hasError: false });
const tenantUrl = `https://${location.host}`; const tenantUrl = `https://${location.host}`;
let galleryImages: ICarouselImages[] = []; let galleryImages: ICarouselImages[] = [];
let carouselImages: React.ReactElement<HTMLElement>[] = []; let carouselImages: React.ReactElement<HTMLElement>[] = [];
try { try {
const images = await this.spService.getImages(this.props.siteUrl, this.props.list, this.props.numberImages); const images = await this.spService.getImages(this.props.siteUrl, this.props.list, this.props.numberImages);
for (const image of images) { for (const image of images) {
if (image.FileSystemObjectType == 1) continue; // by pass folder item if (image.FileSystemObjectType == 1) continue; // by pass folder item
const pURL = `${tenantUrl}/_api/v2.0/sharePoint:${image.File.ServerRelativeUrl}:/driveItem/thumbnails/0/large/content?preferNoRedirect=true `; const pURL = `${tenantUrl}/_api/v2.0/sharePoint:${image.File.ServerRelativeUrl}:/driveItem/thumbnails/0/large/content?preferNoRedirect=true `;
const thumbnailUrl = `${tenantUrl}/_api/v2.0/sharePoint:${image.File.ServerRelativeUrl}:/driveItem/thumbnails/0/c240x240/content?preferNoRedirect=true `; const thumbnailUrl = `${tenantUrl}/_api/v2.0/sharePoint:${image.File.ServerRelativeUrl}:/driveItem/thumbnails/0/c240x240/content?preferNoRedirect=true `;
let mediaType: string = ''; let mediaType: string = '';
switch (image.File_x0020_Type) { switch (image.File_x0020_Type) {
case ('jpg' || 'jpeg' || 'png' || 'tiff' || 'gif'): case 'jpg':
mediaType = 'image'; case 'jpeg':
break; case 'png':
case ('mp4'): case 'tiff':
mediaType = 'video'; case 'gif':
break; mediaType = 'image';
default: break;
continue; case 'mp4':
break; mediaType = 'video';
} break;
default:
continue;
break;
}
galleryImages.push( galleryImages.push(
{ {
imageUrl: pURL, imageUrl: pURL,
mediaType: mediaType, mediaType: mediaType,
serverRelativeUrl: image.File.ServerRelativeUrl, serverRelativeUrl: image.File.ServerRelativeUrl,
caption: image.Title ? image.Title : image.File.Name, caption: image.Title ? image.Title : image.File.Name,
description: image.Description ? image.Description : '', description: image.Description ? image.Description : '',
linkUrl: '' linkUrl: ''
}, },
); );
// Create Carousel Slides from Images // Create Carousel Slides from Images
carouselImages = galleryImages.map((galleryImage, i) => { carouselImages = galleryImages.map((galleryImage, i) => {
return ( return (
<div className='slideLoading' > <div className='slideLoading' >
{galleryImage.mediaType == 'video' ? {galleryImage.mediaType == 'video' ?
<div > <div >
<Player <Player
poster={galleryImage.imageUrl} poster={galleryImage.imageUrl}
style={{ width: '100%', height: '400px' }}> style={{ width: '100%', height: '400px' }}>
<BigPlayButton position="center" /> <BigPlayButton position="center" />
<source src={galleryImage.serverRelativeUrl} <source src={galleryImage.serverRelativeUrl}
/> />
</Player> </Player>
</div> </div>
: :
<div> <div>
<Image src={galleryImage.imageUrl} <Image src={galleryImage.imageUrl}
onLoadingStateChange={async (loadState: ImageLoadState) => { onLoadingStateChange={async (loadState: ImageLoadState) => {
console.log('imageload Status ' + i, loadState, galleryImage.imageUrl); console.log('imageload Status ' + i, loadState, galleryImage.imageUrl);
if (loadState == ImageLoadState.loaded) { if (loadState == ImageLoadState.loaded) {
this.setState({ loadingImage: false }); this.setState({ loadingImage: false });
} }
}} }}
height={'400px'} height={'400px'}
imageFit={ImageFit.cover} imageFit={ImageFit.cover}
/> />
<div style={{ background: 'rgba(0, 0, 0, 0.3)',overflow:'hidden', fontSize: FontSizes.size16, top:0, transition: '.7s ease', textAlign: 'left', width: '200px', height: '350px', position: 'absolute', color: '#ffffff', padding: '25px' }}> <div style={{ background: 'rgba(0, 0, 0, 0.3)', overflow: 'hidden', fontSize: FontSizes.size16, top: 0, transition: '.7s ease', textAlign: 'left', width: '200px', height: '350px', position: 'absolute', color: '#ffffff', padding: '25px' }}>
<h2 style={{fontSize: FontSizes.size20, textTransform: 'uppercase', color: 'white' }}>{galleryImage.caption}</h2> <h2 style={{ fontSize: FontSizes.size20, textTransform: 'uppercase', color: 'white' }}>{galleryImage.caption}</h2>
<p>{galleryImage.description}</p> <p>{galleryImage.description}</p>
</div> </div>
</div> </div>
} }
</div> </div>
); );
} }
); );
this.setState({ carouselImages: carouselImages, isLoading: false }); this.setState({ carouselImages: carouselImages, isLoading: false });
} }
} catch (error) { } catch (error) {
this.setState({ hasError: true, errorMessage: decodeURIComponent(error.message) }); this.setState({ hasError: true, errorMessage: decodeURIComponent(error.message) });
} }
} }
public async componentDidMount() { public async componentDidMount() {
await this.loadPictures(); await this.loadPictures();
} }
public async componentDidUpdate(prevProps: ICarouselProps) { public async componentDidUpdate(prevProps: ICarouselProps) {
if (!this.props.list || !this.props.siteUrl) return; if (!this.props.list || !this.props.siteUrl) return;
// Get Properties change // Get Properties change
if (prevProps.list !== this.props.list || prevProps.numberImages !== this.props.numberImages) { if (prevProps.list !== this.props.list || prevProps.numberImages !== this.props.numberImages) {
/* /*
this.galleryImages = []; this.galleryImages = [];
this._carouselImages = []; this._carouselImages = [];
this.setState({ images: this.galleryImages, carouselImages: t.his._carouselImages, isLoading: false }); this.setState({ images: this.galleryImages, carouselImages: t.his._carouselImages, isLoading: false });
*/ */
await this.loadPictures(); await this.loadPictures();
} }
} }
public render(): React.ReactElement<ICarouselProps> { public render(): React.ReactElement<ICarouselProps> {
const sliderSettings = { const sliderSettings = {
dots: true, dots: true,
infinite: true, infinite: true,
speed: 500, speed: 500,
slidesToShow: 1, slidesToShow: 1,
slidesToScroll: 1, slidesToScroll: 1,
lazyLoad: 'progressive', lazyLoad: 'progressive',
autoplaySpeed: 3000, autoplaySpeed: 3000,
initialSlide: this.state.photoIndex, initialSlide: this.state.photoIndex,
arrows: true, arrows: true,
draggable: true, draggable: true,
adaptiveHeight: true, adaptiveHeight: true,
useCSS: true, useCSS: true,
useTransform: true, useTransform: true,
}; };
return ( return (
<div className={styles.carousel}> <div className={styles.carousel}>
<div> <div>
</div> </div>
{ {
(!this.props.list) ? (!this.props.list) ?
<Placeholder iconName='Edit' <Placeholder iconName='Edit'
iconText={strings.WebpartConfigIconText} iconText={strings.WebpartConfigIconText}
description={strings.WebpartConfigDescription} description={strings.WebpartConfigDescription}
buttonLabel={strings.WebPartConfigButtonLabel} buttonLabel={strings.WebPartConfigButtonLabel}
hideButton={this.props.displayMode === DisplayMode.Read} hideButton={this.props.displayMode === DisplayMode.Read}
onConfigure={this.onConfigure.bind(this)} /> onConfigure={this.onConfigure.bind(this)} />
: :
this.state.hasError ? this.state.hasError ?
<MessageBar messageBarType={MessageBarType.error}> <MessageBar messageBarType={MessageBarType.error}>
{this.state.errorMessage} {this.state.errorMessage}
</MessageBar> </MessageBar>
: :
this.state.isLoading ? this.state.isLoading ?
<Spinner size={SpinnerSize.large} label='loading images...' /> <Spinner size={SpinnerSize.large} label='loading images...' />
: :
this.state.carouselImages.length == 0 ? this.state.carouselImages.length == 0 ?
<div style={{ width: '300px', margin: 'auto' }}> <div style={{ width: '300px', margin: 'auto' }}>
<Icon iconName="PhotoCollection" <Icon iconName="PhotoCollection"
style={{ fontSize: '250px', color: '#d9d9d9' }} /> style={{ fontSize: '250px', color: '#d9d9d9' }} />
<Label style={{ width: '250px', margin: 'auto', fontSize: FontSizes.size20 }}>No images in the library</Label> <Label style={{ width: '250px', margin: 'auto', fontSize: FontSizes.size20 }}>No images in the library</Label>
</div> </div>
: :
<div style={{ width: '100%', height: '100%'}}> <div style={{ width: '100%', height: '100%' }}>
<div style={{ width: '100%'}}> <div style={{ width: '100%' }}>
<Slider <Slider
{...sliderSettings} {...sliderSettings}
autoplay={true} autoplay={true}
onReInit={() => { onReInit={() => {
if (!this.state.loadingImage) if (!this.state.loadingImage)
$(".slideLoading").removeClass("slideLoading"); $(".slideLoading").removeClass("slideLoading");
}}> }}>
{ {
this.state.carouselImages this.state.carouselImages
} }
</Slider> </Slider>
</div> </div>
{ {
this.state.loadingImage && this.state.loadingImage &&
<Spinner size={SpinnerSize.small} label={'Loading...'} style={{verticalAlign:'middle', right:'30%', top:20, position: 'absolute', fontSize: FontSizes.size18, color: CommunicationColors.primary }}></Spinner> <Spinner size={SpinnerSize.small} label={'Loading...'} style={{ verticalAlign: 'middle', right: '30%', top: 20, position: 'absolute', fontSize: FontSizes.size18, color: CommunicationColors.primary }}></Spinner>
} }
</div> </div>
} }
</div> </div>
); );
} }
} }

View File

@ -29,7 +29,8 @@
] ]
}, },
"include": [ "include": [
"src/**/*.ts" "src/**/*.ts",
"src/**/*.tsx"
], ],
"exclude": [ "exclude": [
"node_modules", "node_modules",