New Sample Added, Modern Calendar (#140)
* Initial Commit * Update README.md * Updated README
This commit is contained in:
parent
b6fd85de83
commit
6020d00821
|
@ -0,0 +1,21 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2017 jcoleman-pcprofessional
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
|
@ -0,0 +1,56 @@
|
||||||
|
# Modern Calendar
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
This is a modern webpart built on the GA version of the [SharePoint Framework](https://dev.office.com/sharepoint/docs/spfx/sharepoint-framework-overview). The ready to deploy SharePoint Add-in package is available under the sharepoint/solution folder.
|
||||||
|
|
||||||
|
![SS1](https://cloud.githubusercontent.com/assets/13068139/23584809/14c4333e-0121-11e7-9bf1-3117651222d3.png)
|
||||||
|
![SS2](https://cloud.githubusercontent.com/assets/13068139/23584808/14c3ec26-0121-11e7-8be8-65fbcca32b62.png)
|
||||||
|
![SS3](https://cloud.githubusercontent.com/assets/13068139/23584807/14b88f34-0121-11e7-8c91-56ecff9343e1.png)
|
||||||
|
|
||||||
|
## Used SharePoint Framework Version
|
||||||
|
![drop](https://img.shields.io/badge/version-GA-green.svg)
|
||||||
|
|
||||||
|
## Applies to
|
||||||
|
|
||||||
|
* [SharePoint Framework](https://blogs.office.com/2017/02/23/sharepoint-framework-reaches-general-availability-build-and-deploy-engaging-web-parts-today/)
|
||||||
|
* [Office 365 tenant](https://dev.office.com/sharepoint/docs/spfx/set-up-your-development-environment)
|
||||||
|
|
||||||
|
> Update accordingly as needed.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
> Any special pre-requisites?
|
||||||
|
|
||||||
|
## Solution
|
||||||
|
|
||||||
|
Solution|Author(s)
|
||||||
|
--------|---------
|
||||||
|
folder name | Author details
|
||||||
|
|
||||||
|
## Version history
|
||||||
|
|
||||||
|
Version|Date|Comments
|
||||||
|
-------|----|--------
|
||||||
|
1.1|September 2, 2025|Update comment
|
||||||
|
1.0|August 29, 2025|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
|
||||||
|
Renders a calendar from any list available on the selected site. Site, List, Start, End, Event Title,Event Details and Calendar Theme are user-definable in the web part properties.
|
||||||
|
|
||||||
|
![](https://telemetry.sharepointpnp.com/sp-dev-fx-webparts/samples/js-modern-calendar)
|
||||||
|
|
||||||
|
<img src="https://telemetry.sharepointpnp.com/sp-dev-fx-webparts/samples/js-modern-calendar“ />
|
|
@ -0,0 +1,14 @@
|
||||||
|
{
|
||||||
|
"entries": [
|
||||||
|
{
|
||||||
|
"entry": "./lib/webparts/modernCalendar/ModernCalendarWebPart.js",
|
||||||
|
"manifest": "./src/webparts/modernCalendar/ModernCalendarWebPart.manifest.json",
|
||||||
|
"outputPath": "./dist/modern-calendar.bundle.js"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"externals": {
|
||||||
|
},
|
||||||
|
"localizedResources": {
|
||||||
|
"modernCalendarStrings": "webparts/modernCalendar/loc/{locale}.js"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"deployCdnPath": "temp/deploy"
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"workingDir": "./temp/deploy/",
|
||||||
|
"account": "<!-- STORAGE ACCOUNT NAME -->",
|
||||||
|
"container": "document-card-web-part",
|
||||||
|
"accessKey": "<!-- ACCESS KEY -->"
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
{
|
||||||
|
"solution": {
|
||||||
|
"name": "spFX Modern Calendar",
|
||||||
|
"id": "3d593a2f-73f1-486f-9dae-555c6f6b584d",
|
||||||
|
"version": "1.0.0.1"
|
||||||
|
},
|
||||||
|
"paths": {
|
||||||
|
"zippedPackage": "solution/modern-calendar.sppkg"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
{
|
||||||
|
"port": 4321,
|
||||||
|
"initialPage": "https://localhost:5432/workbench",
|
||||||
|
"https": true,
|
||||||
|
"api": {
|
||||||
|
"port": 5432,
|
||||||
|
"entryPath": "node_modules/@microsoft/sp-webpart-workbench/lib/api/"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
{
|
||||||
|
// Display errors as warnings
|
||||||
|
"displayAsWarning": true,
|
||||||
|
// The TSLint task may have been configured with several custom lint rules
|
||||||
|
// before this config file is read (for example lint rules from the tslint-microsoft-contrib
|
||||||
|
// project). If true, this flag will deactivate any of these rules.
|
||||||
|
"removeExistingRules": true,
|
||||||
|
// When true, the TSLint task is configured with some default TSLint "rules.":
|
||||||
|
"useDefaultConfigAsBase": false,
|
||||||
|
// Since removeExistingRules=true and useDefaultConfigAsBase=false, there will be no lint rules
|
||||||
|
// which are active, other than the list of rules below.
|
||||||
|
"lintConfig": {
|
||||||
|
// Opt-in to Lint rules which help to eliminate bugs in JavaScript
|
||||||
|
"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-case": true,
|
||||||
|
"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-unused-imports": true,
|
||||||
|
"no-use-before-declare": true,
|
||||||
|
"no-with-statement": true,
|
||||||
|
"semicolon": true,
|
||||||
|
"trailing-comma": false,
|
||||||
|
"typedef": false,
|
||||||
|
"typedef-whitespace": false,
|
||||||
|
"use-named-parameter": true,
|
||||||
|
"valid-typeof": true,
|
||||||
|
"variable-name": false,
|
||||||
|
"whitespace": false,
|
||||||
|
"prefer-const": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"cdnBasePath": "https://publiccdn.sharepointonline.com/pcpro365.sharepoint.com/163800463de5f9285ad4f6f9cc0a97985b96b057e062d4733849cc0fc90eeffbd6d72bb8/calendar/"
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const gulp = require('gulp');
|
||||||
|
const build = require('@microsoft/sp-build-web');
|
||||||
|
|
||||||
|
build.initialize(gulp);
|
|
@ -0,0 +1,31 @@
|
||||||
|
{
|
||||||
|
"name": "modern-calendar",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"private": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@microsoft/sp-client-base": "~1.0.0",
|
||||||
|
"@microsoft/sp-core-library": "~1.0.0",
|
||||||
|
"@microsoft/sp-webpart-base": "~1.0.0",
|
||||||
|
"@types/fullcalendar": "^2.7.38",
|
||||||
|
"@types/moment": "^2.13.0",
|
||||||
|
"@types/webpack-env": ">=1.12.1 <1.14.0",
|
||||||
|
"fullcalendar": "^3.2.0",
|
||||||
|
"sweetalert2": "^6.4.2"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@microsoft/sp-build-web": "~1.0.0",
|
||||||
|
"@microsoft/sp-module-interfaces": "~1.0.0",
|
||||||
|
"@microsoft/sp-webpart-workbench": "~1.0.0",
|
||||||
|
"gulp": "~3.9.1",
|
||||||
|
"@types/chai": ">=3.4.34 <3.6.0",
|
||||||
|
"@types/mocha": ">=2.2.33 <2.6.0"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"build": "gulp bundle",
|
||||||
|
"clean": "gulp clean",
|
||||||
|
"test": "gulp test"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,52 @@
|
||||||
|
.EmptyCalendar {
|
||||||
|
.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 {
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.listItem {
|
||||||
|
max-width: 715px;
|
||||||
|
margin: 5px auto 5px auto;
|
||||||
|
box-shadow: 0 0 4px 0 rgba(0, 0, 0, 0.2), 0 25px 50px 0 rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.button {
|
||||||
|
// Our button
|
||||||
|
text-decoration: none;
|
||||||
|
height: 32px;
|
||||||
|
|
||||||
|
// Primary Button
|
||||||
|
min-width: 80px;
|
||||||
|
background-color: #0078d7;
|
||||||
|
border-color: #0078d7;
|
||||||
|
color: #ffffff;
|
||||||
|
|
||||||
|
// 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: 14px;
|
||||||
|
font-weight: 400;
|
||||||
|
border-width: 0;
|
||||||
|
text-align: center;
|
||||||
|
cursor: pointer;
|
||||||
|
display: inline-block;
|
||||||
|
padding: 0 16px;
|
||||||
|
|
||||||
|
.label {
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 14px;
|
||||||
|
height: 32px;
|
||||||
|
line-height: 32px;
|
||||||
|
margin: 0 4px;
|
||||||
|
vertical-align: top;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,82 @@
|
||||||
|
import {
|
||||||
|
IPropertyPaneDropdownOption
|
||||||
|
} from '@microsoft/sp-webpart-base';
|
||||||
|
import styles from './CalendarTemplate.module.scss';
|
||||||
|
import { escape } from '@microsoft/sp-lodash-subset';
|
||||||
|
|
||||||
|
export interface ISPLists {
|
||||||
|
value: ISPList[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ISPList {
|
||||||
|
Title: string;
|
||||||
|
Id: string;
|
||||||
|
}
|
||||||
|
export default class CalendarTemplate {
|
||||||
|
public static templateHtml: string = `
|
||||||
|
<div class='spfxcalendar'></div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
public static emptyHtml(title: string): string {
|
||||||
|
return `<div class="${styles.EmptyCalendar}">
|
||||||
|
<div class="${styles.container}">
|
||||||
|
<div class="ms-Grid-row ms-bgColor-themeDark ms-fontColor-white ${styles.row}">
|
||||||
|
<div class="ms-Grid-col ms-u-lg10 ms-u-xl8 ms-u-xlPush2 ms-u-lgPush1">
|
||||||
|
<span class="ms-font-xl ms-fontColor-white">${title}</span>
|
||||||
|
<p class="ms-font-l ms-fontColor-white">Edit this web part to continue</p>
|
||||||
|
<a href="https://aka.ms/spfx" class="${styles.button}">
|
||||||
|
<span class="${styles.label}">View More Modern Web Parts</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static themeBase: string = `https://publiccdn.sharepointonline.com/pcpro365.sharepoint.com/163800463de5f9285ad4f6f9cc0a97985b96b057e062d4733849cc0fc90eeffbd6d72bb8/calendar/themes/`;
|
||||||
|
|
||||||
|
public static themeNames: Array<string> = [
|
||||||
|
'default',
|
||||||
|
'black-tie',
|
||||||
|
'blitzer',
|
||||||
|
'cupertino',
|
||||||
|
'dark-hive',
|
||||||
|
'dot-luv',
|
||||||
|
'eggplant',
|
||||||
|
'excite-bike',
|
||||||
|
'flick',
|
||||||
|
'hot-sneaks',
|
||||||
|
'humanity',
|
||||||
|
'le-frog',
|
||||||
|
'mint-choc',
|
||||||
|
'overcast',
|
||||||
|
'pcpro',
|
||||||
|
'pepper-grinder',
|
||||||
|
'redmond',
|
||||||
|
'smoothness',
|
||||||
|
'south-street',
|
||||||
|
'start',
|
||||||
|
'sunny',
|
||||||
|
'swanky-purse',
|
||||||
|
'trontastic',
|
||||||
|
'ui-darkness',
|
||||||
|
'ui-lightness',
|
||||||
|
'vader'
|
||||||
|
]
|
||||||
|
|
||||||
|
public static theme(): IPropertyPaneDropdownOption[] {
|
||||||
|
var themes: IPropertyPaneDropdownOption[] = [];
|
||||||
|
CalendarTemplate.themeNames.forEach(function(name,index) {
|
||||||
|
themes.push({key: CalendarTemplate.themeBase + name + '/jquery-ui.min.css', text: name.toLocaleUpperCase()})
|
||||||
|
});
|
||||||
|
return themes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static themes: IPropertyPaneDropdownOption[] = [
|
||||||
|
{ key: CalendarTemplate.themeBase + 'jquery-ui.theme.min.css', text: 'Default' },
|
||||||
|
{ key: CalendarTemplate.themeBase + 'ui-lightness/jquery-ui.min.css', text: 'Light' },
|
||||||
|
{ key: '//cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/themes/redmond/jquery-ui.min.css', text: 'Redmond' },
|
||||||
|
{ key: '//cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/themes/overcast/jquery-ui.min.css', text: 'Overcast' }
|
||||||
|
];
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
export interface IModernCalendarWebPartProps {
|
||||||
|
description: string;
|
||||||
|
site: string;
|
||||||
|
siteOther: string;
|
||||||
|
other: boolean;
|
||||||
|
listTitle: string;
|
||||||
|
theme: string;
|
||||||
|
start: string;
|
||||||
|
end: string;
|
||||||
|
title: string;
|
||||||
|
detail: string;
|
||||||
|
}
|
|
@ -0,0 +1,60 @@
|
||||||
|
.helloWorld {
|
||||||
|
.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 {
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.listItem {
|
||||||
|
max-width: 715px;
|
||||||
|
margin: 5px auto 5px auto;
|
||||||
|
box-shadow: 0 0 4px 0 rgba(0, 0, 0, 0.2), 0 25px 50px 0 rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.button {
|
||||||
|
// Our button
|
||||||
|
text-decoration: none;
|
||||||
|
height: 32px;
|
||||||
|
|
||||||
|
// Primary Button
|
||||||
|
min-width: 80px;
|
||||||
|
background-color: #0078d7;
|
||||||
|
border-color: #0078d7;
|
||||||
|
color: #ffffff;
|
||||||
|
|
||||||
|
// 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: 14px;
|
||||||
|
font-weight: 400;
|
||||||
|
border-width: 0;
|
||||||
|
text-align: center;
|
||||||
|
cursor: pointer;
|
||||||
|
display: inline-block;
|
||||||
|
padding: 0 16px;
|
||||||
|
|
||||||
|
.label {
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 14px;
|
||||||
|
height: 32px;
|
||||||
|
line-height: 32px;
|
||||||
|
margin: 0 4px;
|
||||||
|
vertical-align: top;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
input[aria-label='hide-col'] {
|
||||||
|
display:none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#spPropertyPaneContainer input[aria-label='hide-col'] {
|
||||||
|
display:none;
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
{
|
||||||
|
"$schema": "../../../node_modules/@microsoft/sp-module-interfaces/lib/manifestSchemas/jsonSchemas/clientSideComponentManifestSchema.json",
|
||||||
|
|
||||||
|
"id": "c2a397d3-8c8f-47ab-b731-897178313c15",
|
||||||
|
"alias": "ModernCalendarWebPart",
|
||||||
|
"componentType": "WebPart",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"manifestVersion": 2,
|
||||||
|
|
||||||
|
"preconfiguredEntries": [{
|
||||||
|
"groupId": "c2a397d3-8c8f-47ab-b731-897178313c15",
|
||||||
|
"group": { "default": "Modern Web Parts" },
|
||||||
|
"title": { "default": "ModernCalendar" },
|
||||||
|
"description": { "default": "SFPx Modern Calendar" },
|
||||||
|
"officeFabricIconFontName": "Calendar",
|
||||||
|
"properties": {
|
||||||
|
"description": "SPFx Modern Calendar",
|
||||||
|
"other": false
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
}
|
|
@ -0,0 +1,376 @@
|
||||||
|
import { Version } from '@microsoft/sp-core-library';
|
||||||
|
import {
|
||||||
|
BaseClientSideWebPart,
|
||||||
|
IPropertyPaneConfiguration,
|
||||||
|
IPropertyPaneDropdownOption,
|
||||||
|
IPropertyPaneTextFieldProps,
|
||||||
|
IWebPartContext,
|
||||||
|
PropertyPaneTextField,
|
||||||
|
PropertyPaneDropdown,
|
||||||
|
IPropertyPaneDropdownProps
|
||||||
|
} from '@microsoft/sp-webpart-base';
|
||||||
|
import { escape } from '@microsoft/sp-lodash-subset';
|
||||||
|
import styles from './ModernCalendar.module.scss';
|
||||||
|
import * as strings from 'modernCalendarStrings';
|
||||||
|
import { IModernCalendarWebPartProps } from './IModernCalendarWebPartProps';
|
||||||
|
import CalendarTemplate from './CalendarTemplate';
|
||||||
|
import * as jQuery from 'jquery';
|
||||||
|
import 'fullcalendar';
|
||||||
|
import * as moment from 'moment';
|
||||||
|
import * as swal2 from 'sweetalert2';
|
||||||
|
import { SPComponentLoader } from '@microsoft/sp-loader';
|
||||||
|
import {
|
||||||
|
SPHttpClient
|
||||||
|
} from '@microsoft/sp-http';
|
||||||
|
import {
|
||||||
|
Environment,
|
||||||
|
EnvironmentType
|
||||||
|
} from '@microsoft/sp-core-library';
|
||||||
|
|
||||||
|
export interface ISPLists {
|
||||||
|
value: ISPList[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ISPList {
|
||||||
|
Title: string;
|
||||||
|
Id: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface EventObjects {
|
||||||
|
value: FC.EventObject[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class ModernCalendarWebPart extends BaseClientSideWebPart<IModernCalendarWebPartProps> {
|
||||||
|
|
||||||
|
public constructor() {
|
||||||
|
super();
|
||||||
|
//Modify with your a CDN or local path
|
||||||
|
SPComponentLoader.loadCss('//publiccdn.sharepointonline.com/pcpro365.sharepoint.com/163800463de5f9285ad4f6f9cc0a97985b96b057e062d4733849cc0fc90eeffbd6d72bb8/calendar/sweetalert2.min.css');
|
||||||
|
SPComponentLoader.loadCss('//publiccdn.sharepointonline.com/pcpro365.sharepoint.com/163800463de5f9285ad4f6f9cc0a97985b96b057e062d4733849cc0fc90eeffbd6d72bb8/calendar/fullcalendar.min.css');
|
||||||
|
}
|
||||||
|
|
||||||
|
public render(): void {
|
||||||
|
|
||||||
|
if (this.properties.theme != null){
|
||||||
|
SPComponentLoader.loadCss(this.properties.theme);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.properties.other){
|
||||||
|
jQuery('input[aria-label=hide-col]').parent().hide();
|
||||||
|
}
|
||||||
|
//Check required properties before rendering list
|
||||||
|
if (this.properties.listTitle == null || this.properties.start == null || this.properties.end == null || this.properties.title == null || this.properties.detail == null) {
|
||||||
|
this.domElement.innerHTML = CalendarTemplate.emptyHtml(this.properties.description);
|
||||||
|
} else {
|
||||||
|
this.domElement.innerHTML = CalendarTemplate.templateHtml;
|
||||||
|
this._renderListAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected get dataVersion(): Version {
|
||||||
|
return Version.parse('1.0');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected onPropertyPaneConfigurationStart(): void {
|
||||||
|
//Set a default theme
|
||||||
|
|
||||||
|
if (this.properties.theme == null){
|
||||||
|
this.properties.theme = CalendarTemplate.theme()[0].key.toString();
|
||||||
|
}
|
||||||
|
if (this.properties.site){
|
||||||
|
this.listDisabled = false;
|
||||||
|
}
|
||||||
|
if (this.properties.listTitle && (!this.properties.start || !this.properties.end || !this.properties.title || !this.properties.detail)){
|
||||||
|
//this._getColumnsAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.properties.other){
|
||||||
|
jQuery('input[aria-label=hide-col]').parent().hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.properties.site && this.properties.listTitle && this.properties.start && this.properties.start && this.properties.end && this.properties.title && this.properties.detail){
|
||||||
|
this.context.statusRenderer.displayLoadingIndicator(this.domElement, 'Configuration');
|
||||||
|
this._getSiteRootWeb()
|
||||||
|
.then((response0) => {
|
||||||
|
this._getSites(response0['Url'])
|
||||||
|
.then((response) => {
|
||||||
|
var sites: IPropertyPaneDropdownOption[] = [];
|
||||||
|
sites.push({key:this.context.pageContext.web.absoluteUrl, text:'This Site'});
|
||||||
|
sites.push({key:'other', text:'Other Site (Specify Url)'});
|
||||||
|
for (var _key in response.value) {
|
||||||
|
if (this.context.pageContext.web.absoluteUrl != response.value[_key]['Url']){
|
||||||
|
sites.push({key: response.value[_key]['Url'], text: response.value[_key]['Title']});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this._siteOptions = sites;
|
||||||
|
if (this.properties.site){
|
||||||
|
this._getListTitles(this.properties.site)
|
||||||
|
.then((response2) => {
|
||||||
|
this._dropdownOptions = response2.value.map((list: ISPList) => {
|
||||||
|
return {
|
||||||
|
key: list.Title,
|
||||||
|
text: list.Title
|
||||||
|
};
|
||||||
|
});
|
||||||
|
this._getListColumns(this.properties.listTitle,this.properties.site)
|
||||||
|
.then((response3) => {
|
||||||
|
var col: IPropertyPaneDropdownOption[] = [];
|
||||||
|
for (var _key in response3.value) {
|
||||||
|
col.push({key: response3.value[_key]['InternalName'], text: response3.value[_key]['Title']});
|
||||||
|
}
|
||||||
|
this._columnOptions = col;
|
||||||
|
this.colsDisabled = false;
|
||||||
|
this.listDisabled = false;
|
||||||
|
this.context.propertyPane.refresh();
|
||||||
|
this.context.statusRenderer.clearLoadingIndicator(this.domElement);
|
||||||
|
this.render();
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
this._getSitesAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected onPropertyPaneFieldChanged(propertyPath: string, oldValue: any, newValue: any): void {
|
||||||
|
if (newValue == 'other' ){
|
||||||
|
this.properties.other = true;
|
||||||
|
this.properties.listTitle = null;
|
||||||
|
jQuery('input[aria-label=hide-col]').parent().show();
|
||||||
|
} else if (oldValue === 'other' && newValue != 'other') {
|
||||||
|
this.properties.other = false;
|
||||||
|
this.properties.siteOther = null;
|
||||||
|
this.properties.listTitle = null;
|
||||||
|
jQuery('input[aria-label=hide-col]').parent().hide();
|
||||||
|
}
|
||||||
|
this.context.statusRenderer.displayLoadingIndicator(this.domElement, 'Configuration');
|
||||||
|
if ((propertyPath === 'site' || propertyPath === 'siteOther') && newValue) {
|
||||||
|
this.colsDisabled = true;
|
||||||
|
this.listDisabled = true;
|
||||||
|
var siteUrl = newValue;
|
||||||
|
if (this.properties.other) { siteUrl = this.properties.siteOther; } else { jQuery('input[aria-label=hide-col]').parent().hide(); }
|
||||||
|
if ((this.properties.other && this.properties.siteOther.length > 25) || !this.properties.other){
|
||||||
|
this._getListTitles(siteUrl)
|
||||||
|
.then((response) => {
|
||||||
|
this._dropdownOptions = response.value.map((list: ISPList) => {
|
||||||
|
return {
|
||||||
|
key: list.Title,
|
||||||
|
text: list.Title
|
||||||
|
};
|
||||||
|
});
|
||||||
|
this.listDisabled = false;
|
||||||
|
this.context.propertyPane.refresh();
|
||||||
|
this.context.statusRenderer.clearLoadingIndicator(this.domElement);
|
||||||
|
this.render();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else if (propertyPath === 'listTitle' && newValue) {
|
||||||
|
var siteUrl = newValue;
|
||||||
|
if (this.properties.other) { siteUrl = this.properties.siteOther; }
|
||||||
|
this._getListColumns(newValue,siteUrl)
|
||||||
|
.then((response) => {
|
||||||
|
var col: IPropertyPaneDropdownOption[] = [];
|
||||||
|
for (var _key in response.value) {
|
||||||
|
col.push({key: response.value[_key]['InternalName'], text: response.value[_key]['Title']});
|
||||||
|
}
|
||||||
|
this._columnOptions = col;
|
||||||
|
this.colsDisabled = false;
|
||||||
|
this.context.propertyPane.refresh();
|
||||||
|
this.context.statusRenderer.clearLoadingIndicator(this.domElement);
|
||||||
|
this.render();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
//Handle other fields here
|
||||||
|
this.render();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private colsDisabled: boolean = true;
|
||||||
|
private listDisabled: boolean = true;
|
||||||
|
|
||||||
|
protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
|
||||||
|
var otherSiteAria = 'hide-col';
|
||||||
|
if (this.properties.other) { otherSiteAria = ''; }
|
||||||
|
return {
|
||||||
|
pages: [
|
||||||
|
{
|
||||||
|
header: {
|
||||||
|
description: strings.PropertyPaneDescription
|
||||||
|
},
|
||||||
|
groups: [
|
||||||
|
{
|
||||||
|
groupName: strings.BasicGroupName,
|
||||||
|
groupFields: [
|
||||||
|
PropertyPaneTextField('description', {
|
||||||
|
label: strings.DescriptionFieldLabel
|
||||||
|
}),
|
||||||
|
PropertyPaneDropdown('theme', {
|
||||||
|
label: 'Theme',
|
||||||
|
options: CalendarTemplate.theme()
|
||||||
|
}),
|
||||||
|
PropertyPaneDropdown('site', {
|
||||||
|
label: 'Site',
|
||||||
|
options: this._siteOptions
|
||||||
|
}),
|
||||||
|
PropertyPaneTextField('siteOther', {
|
||||||
|
label: 'Other Site Url (i.e. https://contoso.sharepoint.com/path)',
|
||||||
|
ariaLabel: otherSiteAria
|
||||||
|
}),
|
||||||
|
PropertyPaneDropdown('listTitle', {
|
||||||
|
label: 'List Title',
|
||||||
|
options: this._dropdownOptions,
|
||||||
|
disabled: this.listDisabled
|
||||||
|
}),
|
||||||
|
PropertyPaneDropdown('start', {
|
||||||
|
label: 'Start Date Field',
|
||||||
|
options: this._columnOptions,
|
||||||
|
disabled: this.colsDisabled
|
||||||
|
}),
|
||||||
|
PropertyPaneDropdown('end', {
|
||||||
|
label: 'End Date Field',
|
||||||
|
options: this._columnOptions,
|
||||||
|
disabled: this.colsDisabled
|
||||||
|
}),
|
||||||
|
PropertyPaneDropdown('title', {
|
||||||
|
label: 'Event Title Field',
|
||||||
|
options: this._columnOptions,
|
||||||
|
disabled: this.colsDisabled
|
||||||
|
}),
|
||||||
|
PropertyPaneDropdown('detail', {
|
||||||
|
label: 'Event Details',
|
||||||
|
options: this._columnOptions,
|
||||||
|
disabled: this.colsDisabled
|
||||||
|
})
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private _siteOptions: IPropertyPaneDropdownOption[] = [];
|
||||||
|
private _dropdownOptions: IPropertyPaneDropdownOption[] = [];
|
||||||
|
private _columnOptions: IPropertyPaneDropdownOption[] = [];
|
||||||
|
|
||||||
|
public onInit<T>(): Promise<T> {
|
||||||
|
//this._siteOptions.push({key:this.context.pageContext.web.absoluteUrl, text:'This Site'});
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
|
||||||
|
private _getSiteRootWeb(): Promise<ISPLists> {
|
||||||
|
return this.context.spHttpClient.get(this.context.pageContext.web.absoluteUrl + `/_api/Site/RootWeb?$select=Title,Url`, SPHttpClient.configurations.v1)
|
||||||
|
.then((response: Response) => {
|
||||||
|
return response.json();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private _getSites(rootWebUrl: string): Promise<ISPLists> {
|
||||||
|
return this.context.spHttpClient.get(rootWebUrl + `/_api/web/webs?$select=Title,Url`, SPHttpClient.configurations.v1)
|
||||||
|
.then((response: Response) => {
|
||||||
|
return response.json();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private _getListTitles(site: string): Promise<ISPLists> {
|
||||||
|
return this.context.spHttpClient.get(site + `/_api/web/lists?$filter=Hidden eq false and BaseType eq 0`, SPHttpClient.configurations.v1)
|
||||||
|
.then((response: Response) => {
|
||||||
|
return response.json();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private _getListColumns(listNameColumns: string,listsite: string): Promise<any> {
|
||||||
|
return this.context.spHttpClient.get(listsite + `/_api/web/lists/GetByTitle('${listNameColumns}')/Fields?$filter=Hidden eq false and ReadOnlyField eq false`, SPHttpClient.configurations.v1)
|
||||||
|
.then((response: Response) => {
|
||||||
|
return response.json();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private _getListData(listName: string, site: string): Promise<any> {
|
||||||
|
return this.context.spHttpClient.get(site + `/_api/web/lists/GetByTitle('${listName}')/items?$select=${encodeURIComponent(this.properties.title)},${encodeURIComponent(this.properties.start)},${encodeURIComponent(this.properties.end)},${encodeURIComponent(this.properties.detail)},Created,Author/ID,Author/Title&$expand=Author/ID,Author/Title&$orderby=Id desc&$limit=500`,SPHttpClient.configurations.v1)
|
||||||
|
.then((response: Response) => {
|
||||||
|
return response.json();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private _renderList(items: any[]): void {
|
||||||
|
var calItems: FC.EventObject[] = items.map((list: any) => {
|
||||||
|
return {
|
||||||
|
title: list[this.properties.title],
|
||||||
|
start: list[this.properties.start],
|
||||||
|
end: list[this.properties.end],
|
||||||
|
id: list['Id'],
|
||||||
|
detail: list[this.properties.detail]
|
||||||
|
};
|
||||||
|
});
|
||||||
|
this.context.statusRenderer.clearLoadingIndicator(this.domElement);
|
||||||
|
const calendarOptions:FC.Options = {
|
||||||
|
theme: true,
|
||||||
|
events: calItems,
|
||||||
|
eventClick: function(_event) {
|
||||||
|
var eventDetail = moment(_event['start']).format('MM/DD/YYYY hh:mm') + ' - ' + moment(_event['end']).format('MM/DD/YYYY hh:mm') + '<br>' + _event['detail'];
|
||||||
|
swal2.default(_event.title,eventDetail,'info');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
jQuery('.spfxcalendar', this.domElement).fullCalendar(calendarOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
private _getSitesAsync(): void {
|
||||||
|
this._getSiteRootWeb()
|
||||||
|
.then((response) => {
|
||||||
|
this._getSites(response['Url'])
|
||||||
|
.then((response1) => {
|
||||||
|
var sites: IPropertyPaneDropdownOption[] = [];
|
||||||
|
sites.push({key:this.context.pageContext.web.absoluteUrl, text:'This Site'});
|
||||||
|
sites.push({key:'other', text:'Other Site (Specify Url)'});
|
||||||
|
for (var _key in response1.value) {
|
||||||
|
sites.push({key: response1.value[_key]['Url'], text: response1.value[_key]['Title']});
|
||||||
|
}
|
||||||
|
this._siteOptions = sites;
|
||||||
|
this.context.propertyPane.refresh();
|
||||||
|
var siteUrl = this.properties.site;
|
||||||
|
if (this.properties.other) { siteUrl = this.properties.siteOther; }
|
||||||
|
this._getListTitles(siteUrl)
|
||||||
|
.then((response2) => {
|
||||||
|
this._dropdownOptions = response2.value.map((list: ISPList) => {
|
||||||
|
return {
|
||||||
|
key: list.Title,
|
||||||
|
text: list.Title
|
||||||
|
};
|
||||||
|
});
|
||||||
|
this.context.propertyPane.refresh();
|
||||||
|
if (this.properties.listTitle) {
|
||||||
|
this._getListColumns(this.properties.listTitle,this.properties.site)
|
||||||
|
.then((response3) => {
|
||||||
|
var col: IPropertyPaneDropdownOption[] = [];
|
||||||
|
for (var _key in response3.value) {
|
||||||
|
col.push({key: response3.value[_key]['InternalName'], text: response3.value[_key]['Title']});
|
||||||
|
}
|
||||||
|
this._columnOptions = col;
|
||||||
|
this.colsDisabled = false;
|
||||||
|
this.listDisabled = false;
|
||||||
|
this.context.propertyPane.refresh();
|
||||||
|
this.context.statusRenderer.clearLoadingIndicator(this.domElement);
|
||||||
|
this.render();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private _renderListAsync(): void {
|
||||||
|
var siteUrl = this.properties.site;
|
||||||
|
if (this.properties.other) { siteUrl = this.properties.siteOther; }
|
||||||
|
this._getListData(this.properties.listTitle, siteUrl).then((response) => {
|
||||||
|
this._renderList(response.value);
|
||||||
|
}).catch((err) => {
|
||||||
|
this.context.statusRenderer.clearLoadingIndicator(this.domElement);
|
||||||
|
this.context.statusRenderer.renderError(this.domElement,"There was an error loading your list, please verify the selected list has Calendar Events or choose a new list.");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
define([], function() {
|
||||||
|
return {
|
||||||
|
"PropertyPaneDescription": "Description",
|
||||||
|
"BasicGroupName": "Group Name",
|
||||||
|
"DescriptionFieldLabel": "Description Field"
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,10 @@
|
||||||
|
declare interface IModernCalendarStrings {
|
||||||
|
PropertyPaneDescription: string;
|
||||||
|
BasicGroupName: string;
|
||||||
|
DescriptionFieldLabel: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module 'modernCalendarStrings' {
|
||||||
|
const strings: IModernCalendarStrings;
|
||||||
|
export = strings;
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
/// <reference types="mocha" />
|
||||||
|
|
||||||
|
import { assert } from 'chai';
|
||||||
|
|
||||||
|
describe('ModernCalendarWebPart', () => {
|
||||||
|
it('should do something', () => {
|
||||||
|
assert.ok(true);
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,15 @@
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "es5",
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"module": "commonjs",
|
||||||
|
"jsx": "react",
|
||||||
|
"declaration": true,
|
||||||
|
"sourceMap": true,
|
||||||
|
"types": [
|
||||||
|
"es6-promise",
|
||||||
|
"es6-collections",
|
||||||
|
"webpack-env"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
// Type definitions for Microsoft ODSP projects
|
||||||
|
// Project: ODSP
|
||||||
|
|
||||||
|
/* Global definition for UNIT_TEST builds
|
||||||
|
Code that is wrapped inside an if(UNIT_TEST) {...}
|
||||||
|
block will not be included in the final bundle when the
|
||||||
|
--ship flag is specified */
|
||||||
|
declare const UNIT_TEST: boolean;
|
|
@ -0,0 +1 @@
|
||||||
|
/// <reference path="@ms/odsp.d.ts" />
|
Loading…
Reference in New Issue