React Image Slider From Photo Gallery - Taxonomy Filter (#800)

* First Time Commit

* updating changes

* commit changes

* Update README.md
This commit is contained in:
sudhir007rawat 2019-03-09 05:57:03 -05:00 committed by Vesa Juvonen
parent b6bea9922e
commit 16e7afd05f
24 changed files with 658 additions and 0 deletions

View File

@ -0,0 +1,25 @@
# EditorConfig helps developers define and maintain consistent
# coding styles between different editors and IDEs
# editorconfig.org
root = true
[*]
# change these settings to your own preference
indent_style = space
indent_size = 2
# we recommend you to keep these unchanged
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
trim_trailing_whitespace = false
[{package,bower}.json]
indent_style = space
indent_size = 2

View File

@ -0,0 +1,32 @@
# Logs
logs
*.log
npm-debug.log*
# Dependency directories
node_modules
# Build generated files
dist
lib
solution
temp
*.sppkg
# Coverage directory used by tools like istanbul
coverage
# OSX
.DS_Store
# Visual Studio files
.ntvs_analysis.dat
.vs
bin
obj
# Resx Generated Code
*.resx.ts
# Styles Generated Code
*.scss.ts

View File

@ -0,0 +1,10 @@
{
"@microsoft/generator-sharepoint": {
"version": "1.6.0",
"libraryName": "spfx-photos-sol-react",
"libraryId": "a4282f62-8f32-4d1f-bf80-d25bc778c069",
"environment": "spo",
"packageManager": "npm",
"isCreatingSolution": true
}
}

View File

@ -0,0 +1,62 @@
# Image Slider from Photo Gallery using Taxonomy Filter
## Summary
This webpart display the image in slider based on the filter of Taxonomy from Property panel. Images are stored in PhotoGallery and tagged with Taxonomy. This web part showcase 3 important implementation.
- How to add the Terms in the propertypage and pass the values to react component
- How to filter the list based on Taxonomy and extract the Image URL
- Implementation of Slick Slider
<img src=https://github.com/sudhir007rawat/sp-dev-fx-webparts/blob/sample-Contribution/samples/react-ImageSlider-List-TaxonomyFilter/assets/ImageSlider.gif />
## Used SharePoint Framework Version
![drop](https://img.shields.io/badge/version-GA-green.svg)
## Applies to
* [SharePoint Framework](https:/dev.office.com/sharepoint)
* [Office 365 tenant](https://dev.office.com/sharepoint/docs/spfx/set-up-your-development-environment)
> Update accordingly as needed.
## Prerequisites
> PhotoGalley list names "Photos" and Managed Metadata field attached to Site collection Terms
> Upload few photos in the "Photos" library and tag it.
## Solution
Solution|Author(s)
--------|---------
react-ImageSlider-List-TaxonomyFilter | Sudhir Rawat
## Version history
Version|Date|Comments
-------|----|--------
1.0|March 1, 2019 |Initial release
## Disclaimer
**THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.**
---
## Minimal Path to Awesome
- Clone this repository
- in the command line run:
- `npm install`
- `gulp serve`
> Include any additional steps as needed.
## Features
This web part show the images carousel which is picking from the list based on terms filter.
This Web Part illustrates the following concepts on top of the SharePoint Framework:
- How to add the Terms in the propertypage and pass the values to react component
- How to filter the list based on Taxonomy and extract the Image URL
- Implementation of Slick Slider
<img src="https://telemetry.sharepointpnp.com/sp-dev-fx-webparts/samples/readme-template" />

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 MiB

View File

@ -0,0 +1,21 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/config.2.0.schema.json",
"version": "2.0",
"bundles": {
"photo-gallery-web-part": {
"components": [
{
"entrypoint": "./lib/webparts/photoGallery/PhotoGalleryWebPart.js",
"manifest": "./src/webparts/photoGallery/PhotoGalleryWebPart.manifest.json"
}
]
}
},
"externals": {
"jquery": "https://code.jquery.com/jquery-3.1.0.min.js"
},
"localizedResources": {
"PhotoGalleryWebPartStrings": "lib/webparts/photoGallery/loc/{locale}.js",
"PropertyControlStrings": "node_modules/@pnp/spfx-property-controls/lib/loc/{locale}.js"
}
}

View File

@ -0,0 +1,4 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/copy-assets.schema.json",
"deployCdnPath": "temp/deploy"
}

View File

@ -0,0 +1,7 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/deploy-azure-storage.schema.json",
"workingDir": "./temp/deploy/",
"account": "<!-- STORAGE ACCOUNT NAME -->",
"container": "spfx-photos-sol-react",
"accessKey": "<!-- ACCESS KEY -->"
}

View File

@ -0,0 +1,12 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/package-solution.schema.json",
"solution": {
"name": "spfx-photos-sol-react-client-side-solution",
"id": "a4282f62-8f32-4d1f-bf80-d25bc778c069",
"version": "1.0.0.0",
"includeClientSideAssets": true
},
"paths": {
"zippedPackage": "solution/spfx-photos-sol-react.sppkg"
}
}

View File

@ -0,0 +1,10 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/core-build/serve.schema.json",
"port": 4321,
"https": true,
"initialPage": "https://localhost:5432/workbench",
"api": {
"port": 5432,
"entryPath": "node_modules/@microsoft/sp-webpart-workbench/lib/api/"
}
}

View File

@ -0,0 +1,4 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/write-manifests.schema.json",
"cdnBasePath": "<!-- PATH TO CDN -->"
}

View File

@ -0,0 +1,7 @@
'use strict';
const gulp = require('gulp');
const build = require('@microsoft/sp-build-web');
build.addSuppression(`Warning - [sass] The local CSS class 'ms-Grid' is not camelCase and will not be type-safe.`);
build.initialize(gulp);

View File

@ -0,0 +1,38 @@
{
"name": "spfx-photos-sol-react",
"version": "0.0.1",
"private": true,
"engines": {
"node": ">=0.10.0"
},
"scripts": {
"build": "gulp bundle",
"clean": "gulp clean",
"test": "gulp test"
},
"dependencies": {
"@microsoft/sp-core-library": "1.6.0",
"@microsoft/sp-lodash-subset": "1.6.0",
"@microsoft/sp-office-ui-fabric-core": "1.6.0",
"@microsoft/sp-webpart-base": "1.6.0",
"@pnp/spfx-property-controls": "1.14.1",
"@types/es6-promise": "0.0.33",
"@types/react": "15.6.6",
"@types/react-dom": "15.5.6",
"@types/react-slick": "^0.23.3",
"@types/webpack-env": "1.13.1",
"react": "15.6.2",
"react-dom": "15.6.2",
"react-slick": "^0.23.2"
},
"devDependencies": {
"@microsoft/sp-build-web": "1.6.0",
"@microsoft/sp-module-interfaces": "1.6.0",
"@microsoft/sp-webpart-workbench": "1.6.0",
"tslint-microsoft-contrib": "~5.0.0",
"gulp": "~3.9.1",
"@types/chai": "3.4.34",
"@types/mocha": "2.2.38",
"ajv": "~5.2.2"
}
}

View File

@ -0,0 +1 @@
// A file is required to be in the root of the /src directory by the TypeScript compiler

View File

@ -0,0 +1,26 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/spfx/client-side-web-part-manifest.schema.json",
"id": "940d8dc5-0ce9-4725-9197-3a5edbdea27f",
"alias": "PhotoGalleryWebPart",
"componentType": "WebPart",
// The "*" signifies that the version should be taken from the package.json
"version": "*",
"manifestVersion": 2,
// If true, the component can only be installed on sites where Custom Script is allowed.
// Components that allow authors to embed arbitrary script code should set this to true.
// https://support.office.com/en-us/article/Turn-scripting-capabilities-on-or-off-1f2c515f-5d7e-448a-9fd7-835da935584f
"requiresCustomScript": false,
"preconfiguredEntries": [{
"groupId": "5c03119e-3074-46fd-976b-c60198311f70", // Other
"group": { "default": "Other" },
"title": { "default": "PhotoGallery" },
"description": { "default": "PhotoGallery description" },
"officeFabricIconFontName": "Page",
"properties": {
"description": "PhotoGallery"
}
}]
}

View File

@ -0,0 +1,85 @@
import * as React from 'react';
import * as ReactDom from 'react-dom';
import { PropertyFieldTermPicker } from '@pnp/spfx-property-controls/lib/PropertyFieldTermPicker';
import { IPickerTerms } from '@pnp/spfx-property-controls/lib/PropertyFieldTermPicker';
import { Version } from '@microsoft/sp-core-library';
import {
BaseClientSideWebPart,
IPropertyPaneConfiguration,
PropertyPaneTextField
} from '@microsoft/sp-webpart-base';
import * as strings from 'PhotoGalleryWebPartStrings';
import PhotoGallery from './components/PhotoGallery';
import { IPhotoGalleryProps } from './components/IPhotoGalleryProps';
export interface IPhotoGalleryWebPartProps {
description: string;
terms : IPickerTerms;
}
export default class PhotoGalleryWebPart extends BaseClientSideWebPart<IPhotoGalleryWebPartProps> {
protected get disableReactivePropertyChanges(): boolean {
return true;
}
public render(): void {
const element: React.ReactElement<IPhotoGalleryProps > = React.createElement(
PhotoGallery,
{
description: this.properties.description,
tagkeywords : this.properties.terms,
siteurl:this.context.pageContext.web.absoluteUrl,
spHttpClient:this.context.spHttpClient
}
);
ReactDom.render(element, this.domElement);
}
protected onDispose(): void {
ReactDom.unmountComponentAtNode(this.domElement);
}
protected get dataVersion(): Version {
return Version.parse('1.0');
}
protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
return {
pages: [
{
header: {
description: strings.PropertyPaneDescription
},
groups: [
{
groupName: strings.BasicGroupName,
groupFields: [
PropertyPaneTextField('description', {
label: strings.DescriptionFieldLabel
}),
PropertyFieldTermPicker('terms', {
label: 'Select Keywords',
panelTitle: 'Select Keywords',
initialValues: this.properties.terms,
allowMultipleSelections: true,
excludeSystemGroup: false,
onPropertyChange: this.onPropertyPaneFieldChanged,
properties: this.properties,
context: this.context,
onGetErrorMessage: null,
deferredValidationTime: 0,
limitByGroupNameOrID: 'Site Collection - sudhirrawatdev.sharepoint.com-sites-TeamTestSite',
limitByTermsetNameOrID: 'Keyword',
key: 'termSetsPickerFieldId'
})
]
}
]
}
]
};
}
}

View File

@ -0,0 +1,10 @@
import { IPickerTerms } from '@pnp/spfx-property-controls/lib/PropertyFieldTermPicker';
import { SPHttpClient } from '@microsoft/sp-http';
import {IPhotoGallery} from '../model/IPhotoGallery'
export interface IPhotoGalleryProps {
description: string;
tagkeywords: IPickerTerms;
siteurl:string;
spHttpClient:SPHttpClient;
}

View File

@ -0,0 +1,74 @@
@import '~@microsoft/sp-office-ui-fabric-core/dist/sass/SPFabricCore.scss';
.photoGallery {
.container {
max-width: 700px;
margin: 0px auto;
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2), 0 25px 50px 0 rgba(0, 0, 0, 0.1);
}
.row {
@include ms-Grid-row;
@include ms-fontColor-white;
background-color: $ms-color-themeDark;
padding: 20px;
}
.column {
@include ms-Grid-col;
@include ms-lg10;
@include ms-xl8;
@include ms-xlPush2;
@include ms-lgPush1;
}
.title {
@include ms-font-xl;
@include ms-fontColor-white;
}
.subTitle {
@include ms-font-l;
@include ms-fontColor-white;
}
.description {
@include ms-font-l;
@include ms-fontColor-white;
}
.button {
// Our button
text-decoration: none;
height: 32px;
// Primary Button
min-width: 80px;
background-color: $ms-color-themePrimary;
border-color: $ms-color-themePrimary;
color: $ms-color-white;
// Basic Button
outline: transparent;
position: relative;
font-family: "Segoe UI WestEuropean","Segoe UI",-apple-system,BlinkMacSystemFont,Roboto,"Helvetica Neue",sans-serif;
-webkit-font-smoothing: antialiased;
font-size: $ms-font-size-m;
font-weight: $ms-font-weight-regular;
border-width: 0;
text-align: center;
cursor: pointer;
display: inline-block;
padding: 0 16px;
.label {
font-weight: $ms-font-weight-semibold;
font-size: $ms-font-size-m;
height: 32px;
line-height: 32px;
margin: 0 4px;
vertical-align: top;
display: inline-block;
}
}
}

View File

@ -0,0 +1,142 @@
import * as React from 'react';
import styles from './PhotoGallery.module.scss';
import { IPhotoGalleryProps } from './IPhotoGalleryProps';
import { escape } from '@microsoft/sp-lodash-subset';
import {SPHttpClient,SPHttpClientResponse} from '@microsoft/sp-http';
import Slider from 'react-slick';
import {IPhotoGallery} from '../model/IPhotoGallery';
import 'slick-carousel/slick/slick-theme.css';
import 'slick-carousel/slick/slick.css';
export default class PhotoGallery extends React.Component<IPhotoGalleryProps,any> {
constructor (props) {
super(props);
this.state = {
currentboxvalue:String,
photoGallery: [ {
photoURL:"",
photoID:""
}
],
};
this.getPhotos=this.getPhotos.bind(this);
this.loadPhotos=this.loadPhotos.bind(this);
this.getPhotosURL=this.getPhotosURL.bind(this);
}
componentDidUpdate(prevProps) {
if (prevProps.tagkeywords === this.props.tagkeywords)
{
// this.loadPhotos()
}
else
{
this.loadPhotos();
}
}
componentDidMount(){
this.loadPhotos();
}
getPhotos(termSet) {
this.props.spHttpClient.get(this.props.siteurl + `/_api/web/lists/GetByTitle('Photos')/Items?$filter=TaxCatchAll/IdForTerm eq '` + termSet +`'`,
SPHttpClient.configurations.v1)
.then((response: SPHttpClientResponse) => {
if (response.ok) {
response.json().then((responseJSON) => {
if (responseJSON!=null && responseJSON.value!=null){
for (var i=0; i < responseJSON.value.length; i++) {
this.getPhotosURL(responseJSON.value[i].ID)
//so on
}
}
});
}
});
}
loadPhotos()
{
if (this.props.tagkeywords != undefined)
{
if (this.props.tagkeywords.length >=1)
{
this.state.photoGallery.length=0;
this.props.tagkeywords.map((tg) => this.getPhotos(tg.key));
}
}
//this.getPhotosURL(2);
//this.getPhotosURL(3);
}
getPhotosURL(itemid) {
this.props.spHttpClient.get(this.props.siteurl + `/_api/web/lists/GetByTitle('Photos')/Items(`+itemid+`)?$select=FileRef/FileRef`,
SPHttpClient.configurations.v1)
.then((response: SPHttpClientResponse) => {
if (response.ok) {
response.json().then((responseJSON) => {
if (responseJSON!=null){
let items:any[] = responseJSON;
this.setState(prevState => ({
photoGallery: [...prevState.photoGallery, { "photoURL" : items["FileRef"], "photoID" : itemid }]
}))
}
});
}
});
}
public render(): React.ReactElement<IPhotoGalleryProps> {
debugger;
const settings = {
dots: true,
infinite: true,
slidesToShow: 1,
slidesToScroll: 1,
autoplay: true,
speed: 3000,
autoplaySpeed: 3000,
cssEase: "linear"
};
return (
<div>
{ this.state.photoGallery != undefined &&
<Slider {...settings}>
{
this.state.photoGallery.map((pg)=> <this.PhotoComponent imgurl={pg.photoURL} />)
}
</Slider>
}
{ this.state.photoGallery.length == 1 && this.state.photoGallery[0].photoID == "" && <h1>Please configure the web part</h1>
}
</div>
);
}
PhotoComponent=props =>
(
<div>
<img src={props.imgurl} />
</div>
);
}

View File

@ -0,0 +1,7 @@
define([], function() {
return {
"PropertyPaneDescription": "Description",
"BasicGroupName": "Group Name",
"DescriptionFieldLabel": "Description Field"
}
});

View File

@ -0,0 +1,10 @@
declare interface IPhotoGalleryWebPartStrings {
PropertyPaneDescription: string;
BasicGroupName: string;
DescriptionFieldLabel: string;
}
declare module 'PhotoGalleryWebPartStrings' {
const strings: IPhotoGalleryWebPartStrings;
export = strings;
}

View File

@ -0,0 +1,5 @@
export interface IPhotoGallery
{
photoURL:string;
photoID:number;
}

View File

@ -0,0 +1,34 @@
{
"compilerOptions": {
"target": "es5",
"forceConsistentCasingInFileNames": true,
"module": "esnext",
"moduleResolution": "node",
"jsx": "react",
"declaration": true,
"sourceMap": true,
"experimentalDecorators": true,
"skipLibCheck": true,
"outDir": "lib",
"typeRoots": [
"./node_modules/@types",
"./node_modules/@microsoft"
],
"types": [
"es6-promise",
"webpack-env"
],
"lib": [
"es5",
"dom",
"es2015.collection"
]
},
"include": [
"src/**/*.ts"
],
"exclude": [
"node_modules",
"lib"
]
}

View File

@ -0,0 +1,32 @@
{
"rulesDirectory": [
"tslint-microsoft-contrib"
],
"rules": {
"class-name": false,
"export-name": false,
"forin": false,
"label-position": false,
"member-access": true,
"no-arg": false,
"no-console": false,
"no-construct": false,
"no-duplicate-variable": true,
"no-eval": false,
"no-function-expression": true,
"no-internal-module": true,
"no-shadowed-variable": true,
"no-switch-case-fall-through": true,
"no-unnecessary-semicolons": true,
"no-unused-expression": true,
"no-use-before-declare": true,
"no-with-statement": true,
"semicolon": true,
"trailing-comma": false,
"typedef": false,
"typedef-whitespace": false,
"use-named-parameter": true,
"variable-name": false,
"whitespace": false
}
}