Added advanced iframe webpart
This commit is contained in:
parent
965a2c72a7
commit
b84bae19ec
|
@ -0,0 +1,33 @@
|
|||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
|
||||
# Dependency directories
|
||||
node_modules
|
||||
|
||||
# Build generated files
|
||||
dist
|
||||
lib
|
||||
release
|
||||
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
|
|
@ -0,0 +1,16 @@
|
|||
!dist
|
||||
config
|
||||
|
||||
gulpfile.js
|
||||
|
||||
release
|
||||
src
|
||||
temp
|
||||
|
||||
tsconfig.json
|
||||
tslint.json
|
||||
|
||||
*.log
|
||||
|
||||
.yo-rc.json
|
||||
.vscode
|
|
@ -0,0 +1,25 @@
|
|||
{
|
||||
"@pnp/generator-spfx": {
|
||||
"framework": "none",
|
||||
"pnpFramework": "none.plus",
|
||||
"pnp-libraries": [
|
||||
"rush@3.3"
|
||||
],
|
||||
"pnp-ci": "no-devops",
|
||||
"pnp-vetting": [],
|
||||
"spfxenv": "spo",
|
||||
"pnp-testing": []
|
||||
},
|
||||
"@microsoft/generator-sharepoint": {
|
||||
"environment": "spo",
|
||||
"framework": "none",
|
||||
"plusBeta": false,
|
||||
"isCreatingSolution": true,
|
||||
"version": "1.13.1",
|
||||
"libraryName": "advanced-iframe-webpart",
|
||||
"libraryId": "ea8bc86d-8bd5-42fb-929d-25789fddec26",
|
||||
"packageManager": "npm",
|
||||
"isDomainIsolated": false,
|
||||
"componentType": "webpart"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,301 @@
|
|||
# Advanced IFrame Webpart
|
||||
|
||||
## Summary
|
||||
|
||||
This webpart allows users to add a webpage in an iframe to a modern SharePoint page.
|
||||
|
||||
Main features include:
|
||||
|
||||
- The webpart can be embedded in a "Full-Width" section.
|
||||
- The webpart only allows pages to be embedded that have been added to the "Allow external iframes" in "HTML Field Security"
|
||||
- The webpart resizes the iframe to automatically fit the given space on the page. It keeps the aspect ratio.
|
||||
- The webpart can add additional dynamic parameters to the iframe url. These parameters include
|
||||
- Color codes of the current color scheme
|
||||
- Query string parameters
|
||||
- Information about the logged in user
|
||||
- Information about the current page and site
|
||||
|
||||
![Advanced Iframe Webpart](./images/iframewebpart.png)
|
||||
|
||||
|
||||
## Compatibility
|
||||
|
||||
| :warning: Important |
|
||||
|:---------------------------|
|
||||
| Every SPFx version is only compatible with specific version(s) of Node.js. In order to be able to build this sample, please ensure that the version of Node on your workstation matches one of the versions listed in this section. This sample will not work on a different version of Node.|
|
||||
|Refer to <https://aka.ms/spfx-matrix> for more information on SPFx compatibility. |
|
||||
|
||||
![SPFx 1.13](https://img.shields.io/badge/SPFx-1.13.1-green.svg)
|
||||
![Node.js v14.21.2](https://img.shields.io/badge/Node.js-v14-green.svg)
|
||||
![Compatible with SharePoint Online](https://img.shields.io/badge/SharePoint%20Online-Compatible-green.svg)
|
||||
![Does not work with SharePoint 2019](https://img.shields.io/badge/SharePoint%20Server%202019-Incompatible-red.svg "SharePoint Server 2019 requires SPFx 1.4.1 or lower")
|
||||
![Does not work with SharePoint 2016 (Feature Pack 2)](https://img.shields.io/badge/SharePoint%20Server%202016%20(Feature%20Pack%202)-Incompatible-red.svg "SharePoint Server 2016 Feature Pack 2 requires SPFx 1.1")
|
||||
![Teams Incompatible](https://img.shields.io/badge/Teams-Incompatible-lightgrey.svg)
|
||||
![Local Workbench Compatible](https://img.shields.io/badge/Local%20Workbench-Compatible-green.svg)
|
||||
![Hosted Workbench Compatible](https://img.shields.io/badge/Hosted%20Workbench-Compatible-green.svg)
|
||||
![Compatible with Remote Containers](https://img.shields.io/badge/Remote%20Containers-Compatible-green.svg)
|
||||
|
||||
Tested with: Node.js v14.21.2
|
||||
|
||||
## Applies to
|
||||
|
||||
* [SharePoint Framework](https://learn.microsoft.com/sharepoint/dev/spfx/sharepoint-framework-overview)
|
||||
* [Microsoft 365 tenant](https://learn.microsoft.com/sharepoint/dev/spfx/set-up-your-development-environment)
|
||||
|
||||
## Contributors
|
||||
|
||||
* [Sven Sieverding](https://github.com/365knoten)
|
||||
|
||||
|
||||
## Version history
|
||||
|
||||
Version|Date|Comments
|
||||
-------|----|--------
|
||||
1.0.0 | Aug 27, 2023 | Initial release
|
||||
|
||||
## Minimal Path to Awesome
|
||||
|
||||
- Clone this repository
|
||||
|
||||
### SPFx
|
||||
|
||||
- In the command line, with a compatible version of Node, i.e. v14.21.2, run:
|
||||
- `npm install`
|
||||
- `gulp serve`
|
||||
|
||||
- To bundle and package the installable *.sppkg*, run:
|
||||
- `gulp bundle --ship`
|
||||
- `gulp package-solution --ship`
|
||||
|
||||
### Create a sample PowerApp to test the functions
|
||||
First create a new canvas app, then set "Screen1.Fill" to
|
||||
|
||||
```PowerFX
|
||||
ColorValue("#"&Param("bodyBackground"))
|
||||
```
|
||||
|
||||
This will set the background color of the app to the same color as the section in SharePoint. Add a new label "Label1" and set the font size to 30. Now set it's "Text" Property to
|
||||
|
||||
```PowerFX
|
||||
"Hello "&Param("greeting")
|
||||
```
|
||||
|
||||
and it's "Color" property to
|
||||
|
||||
```PowerFX
|
||||
ColorValue("#"&Param("bodySubtext"))
|
||||
```
|
||||
|
||||
This will set the text color of the label to the text color in the section in SharePoint and the value of the label to "Hello" concatenated with what has been passed with the query string parameter "greeting".
|
||||
Finally publish the app and copy the app url.
|
||||
|
||||
|
||||
Create a new page in SharePoint and add a new Full-Width section. Set the background color of your section to anything else but white.
|
||||
Add the "Advanced Iframe Webpart" here and configure it with the PowerApp url. Append this to the URL
|
||||
|
||||
```Url
|
||||
&bodyBackground={{color.bodyBackground}}&bodySubtext={{color.bodySubtext}}&greeting={{query.greeting}}
|
||||
```
|
||||
|
||||
Publish the Page
|
||||
|
||||
![Advanced Iframe Webpart](./images/advancediframewebpart.gif)
|
||||
|
||||
|
||||
|
||||
## Web Parts Configuration
|
||||
|
||||
### Advanced IFrame Webpart
|
||||
|
||||
![Property Pane](./images/propertypane.png)
|
||||
|
||||
#### Settings
|
||||
|
||||
Remember that only urls are supported that have been allowed by the site collection administrator in "HTML Field Security"
|
||||
|
||||
Setting | Description
|
||||
-------|----
|
||||
Aspect Ratio | The aspect ratio that the iframe should use. Valid values are "16/09" (Default) and "09/16"
|
||||
Iframe Url | Enter the url to the page you want to embed using this webpart. You can use Handlebars syntax to pass additional parameters to the url
|
||||
|
||||
|
||||
#### Query string parameters
|
||||
|
||||
You can append any query string parameter "param" as "{{query.param}}" to the url
|
||||
|
||||
|
||||
#### User parameters
|
||||
|
||||
You can add these parameters to the url to pass information about the current user to the page
|
||||
|
||||
|Key | Example |
|
||||
-------|----
|
||||
{{user.name}} |Sven Sieverding
|
||||
{{user.email}} |Sven@domain.com
|
||||
{{user.loginName}} | sven@domain.com
|
||||
|
||||
|
||||
#### Site parameters
|
||||
|
||||
You can add these parameters to the url to pass information about the current site to the page
|
||||
|
||||
|Key | Example |
|
||||
-------|----
|
||||
{{site.id}} | c0b1166c-19e3-485c-ac0b-e842ffba2a23
|
||||
{{site.serverRelativeUrl}} | /sites/MyAppPage
|
||||
|
||||
#### UI culture parameters
|
||||
|
||||
You can add these parameters to the url to pass information about the current ui culture to the page
|
||||
|
||||
|Key | Example |
|
||||
-------|----
|
||||
{{culture.currentCultureName}} | de-DE
|
||||
|
||||
|
||||
#### Theme parameters
|
||||
|
||||
You can add these parameters to the url to pass information about the current ui theme to the page
|
||||
|
||||
|Key | Example |
|
||||
-------|----
|
||||
{{color.bodyBackground}} | 03787c
|
||||
{{color.bodyFrameBackground}} | 026d70
|
||||
{{color.accentButtonText}} | 03787c
|
||||
{{color.buttonBackground}} | 03787c
|
||||
{{color.primaryButtonText}} | 03787c
|
||||
{{color.primaryButtonTextHovered}} | 025c5f
|
||||
{{color.primaryButtonTextPressed}} | 025c5f
|
||||
{{color.inputBackground}} | FFFFFF
|
||||
{{color.inputForegroundChecked}} | 025c5f
|
||||
{{color.listBackground}} | 03787c
|
||||
{{color.menuBackground}} | 03787c
|
||||
{{color.cardStandoutBackground}} | 03787c
|
||||
{{color.bodyTextChecked}} | FAFAFA
|
||||
{{color.buttonTextCheckedHovered}} | FAFAFA
|
||||
{{color.link}} | FFFFFF
|
||||
{{color.primaryButtonBackground}} | FFFFFF
|
||||
{{color.inputBackgroundChecked}} | FFFFFF
|
||||
{{color.inputIcon}} | FFFFFF
|
||||
{{color.inputFocusBorderAlt}} | 49aeb1
|
||||
{{color.menuIcon}} | FFFFFF
|
||||
{{color.menuHeader}} | FFFFFF
|
||||
{{color.accentButtonBackground}} | FFFFFF
|
||||
{{color.primaryButtonBackgroundPressed}} | 98d6d8
|
||||
{{color.inputBackgroundCheckedHovered}} | 03787c
|
||||
{{color.inputIconHovered}} | FAFAFA
|
||||
{{color.linkHovered}} | FFFFFF
|
||||
{{color.primaryButtonBackgroundHovered}} | c5e9ea
|
||||
{{color.inputPlaceholderBackgroundChecked}} | D1D1D1
|
||||
{{color.bodyBackgroundChecked}} | 98d6d8
|
||||
{{color.bodyFrameDivider}} | 026d70
|
||||
{{color.bodyDivider}} | 49aeb1
|
||||
{{color.variantBorder}} | 026d70
|
||||
{{color.buttonBackgroundCheckedHovered}} | 98d6d8
|
||||
{{color.buttonBackgroundPressed}} | 025c5f
|
||||
{{color.listItemBackgroundChecked}} | 98d6d8
|
||||
{{color.listHeaderBackgroundPressed}} | 98d6d8
|
||||
{{color.menuItemBackgroundPressed}} | 98d6d8
|
||||
{{color.menuItemBackgroundChecked}} | 98d6d8
|
||||
{{color.bodyBackgroundHovered}} | 49aeb1
|
||||
{{color.buttonBackgroundHovered}} | 026d70
|
||||
{{color.buttonBackgroundDisabled}} | c5e9ea
|
||||
{{color.buttonBorderDisabled}} | transparent
|
||||
{{color.primaryButtonBackgroundDisabled}} | 49aeb1
|
||||
{{color.disabledBackground}} | 026d70
|
||||
{{color.listItemBackgroundHovered}} | 49aeb1
|
||||
{{color.listHeaderBackgroundHovered}} | 49aeb1
|
||||
{{color.menuItemBackgroundHovered}} | 49aeb1
|
||||
{{color.primaryButtonTextDisabled}} | f0f9fa
|
||||
{{color.disabledSubtext}} | f0f9fa
|
||||
{{color.listItemBackgroundCheckedHovered}} | c5e9ea
|
||||
{{color.disabledBodyText}} | D1D1D1
|
||||
{{color.variantBorderHovered}} | 014446
|
||||
{{color.buttonTextDisabled}} | 49aeb1
|
||||
{{color.inputIconDisabled}} | D1D1D1
|
||||
{{color.disabledText}} | 49aeb1
|
||||
{{color.bodyText}} | FFFFFF
|
||||
{{color.actionLink}} | FFFFFF
|
||||
{{color.buttonText}} | FFFFFF
|
||||
{{color.inputBorderHovered}} | 014446
|
||||
{{color.inputText}} | 242424
|
||||
{{color.listText}} | FFFFFF
|
||||
{{color.menuItemText}} | 242424
|
||||
{{color.bodyStandoutBackground}} | 026d70
|
||||
{{color.defaultStateBackground}} | FAFAFA
|
||||
{{color.actionLinkHovered}} | FFFFFF
|
||||
{{color.buttonTextHovered}} | FFFFFF
|
||||
{{color.buttonTextChecked}} | F0F0F0
|
||||
{{color.buttonTextPressed}} | FFFFFF
|
||||
{{color.inputTextHovered}} | 141414
|
||||
{{color.menuItemTextHovered}} | F0F0F0
|
||||
{{color.bodySubtext}} | FFFFFF
|
||||
{{color.focusBorder}} | FFFFFF
|
||||
{{color.inputBorder}} | 026d70
|
||||
{{color.smallInputBorder}} | E0E0E0
|
||||
{{color.inputPlaceholderText}} | 616161
|
||||
{{color.buttonBorder}} | FFFFFF
|
||||
{{color.disabledBodySubtext}} | C7C7C7
|
||||
{{color.disabledBorder}} | f0f9fa
|
||||
{{color.buttonBackgroundChecked}} | f0f9fa
|
||||
{{color.menuDivider}} | C7C7C7
|
||||
{{color.cardShadow}} | 0 1.6px 3.6px 0 rgba(0, 0, 0, 0.132), 0 0.3px 0.9px 0 rgba(0, 0, 0, 0.108)
|
||||
{{color.cardShadowHovered}} | 0 0 1px D1D1D1
|
||||
{{color.primaryButtonBorder}} | transparent
|
||||
{{color.errorText}} | a4262c
|
||||
{{color.messageText}} | 323130
|
||||
{{color.messageLink}} | 005A9E
|
||||
{{color.messageLinkHovered}} | 004578
|
||||
{{color.infoIcon}} | 605e5c
|
||||
{{color.errorIcon}} | A80000
|
||||
{{color.blockingIcon}} | FDE7E9
|
||||
{{color.warningIcon}} | 797775
|
||||
{{color.severeWarningIcon}} | D83B01
|
||||
{{color.successIcon}} | 107C10
|
||||
{{color.infoBackground}} | f3f2f1
|
||||
{{color.errorBackground}} | FDE7E9
|
||||
{{color.blockingBackground}} | FDE7E9
|
||||
{{color.warningBackground}} | FFF4CE
|
||||
{{color.severeWarningBackground}} | FED9CC
|
||||
{{color.successBackground}} | DFF6DD
|
||||
{{color.warningHighlight}} | ffb900
|
||||
{{color.successText}} | 107C10
|
||||
{{color.listTextColor}} | 323130
|
||||
{{color.warningText}} | 323130
|
||||
|
||||
|
||||
|
||||
## Features
|
||||
This Web Part illustrates the following concepts on top of the SharePoint Framework:
|
||||
|
||||
- Get the current section theme and react to theme changes.
|
||||
- Get the current webpart width and react to width changes.
|
||||
- Retrieve information about the current user from the page context.
|
||||
- Retrieve information about the current UI culture from the page context.
|
||||
- Retrieve information about the current site from the page context.
|
||||
- Creating and using a service
|
||||
- Fetching the "ScriptSaveDomains", the collection of all domains where iframes are allowed from.
|
||||
|
||||
|
||||
|
||||
## Help
|
||||
|
||||
We do not support samples, but we this community is always willing to help, and we want to improve these samples. We use GitHub to track issues, which makes it easy for community members to volunteer their time and help resolve issues.
|
||||
|
||||
If you're having issues building the solution, please run [spfx doctor](https://pnp.github.io/cli-microsoft365/cmd/spfx/spfx-doctor/) from within the solution folder to diagnose incompatibility issues with your environment.
|
||||
|
||||
You can try looking at [issues related to this sample](https://github.com/pnp/sp-dev-fx-webparts/labels/advanced-iframe-webpart) to see if anybody else is having the same issues.
|
||||
|
||||
You can also try looking at [discussions related to this sample](https://github.com/pnp/sp-dev-fx-webparts/discussions?discussions_q=advanced-iframe-webpart) and see what the community is saying.
|
||||
|
||||
If you encounter any issues while using this sample, [create a new issue](https://github.com/pnp/sp-dev-fx-webparts/issues/new?assignees=&labels=Needs%3A+Triage+%3Amag%3A%2Ctype%3Abug-suspected%2Csample%3A%20advanced-iframe-webpart&template=bug-report.yml&sample=advanced-iframe-webpart&authors=@365knoten&title=advanced-iframe-webpart%20-%20).
|
||||
|
||||
For questions regarding this sample, [create a new question](https://github.com/pnp/sp-dev-fx-webparts/issues/new?assignees=&labels=Needs%3A+Triage+%3Amag%3A%2Ctype%3Aquestion%2Csample%3A%20advanced-iframe-webpart&template=question.yml&sample=advanced-iframe-webpart&authors=@365knoten&title=advanced-iframe-webpart%20-%20).
|
||||
|
||||
Finally, if you have an idea for improvement, [make a suggestion](https://github.com/pnp/sp-dev-fx-webparts/issues/new?assignees=&labels=Needs%3A+Triage+%3Amag%3A%2Ctype%3Aenhancement%2Csample%3A%20advanced-iframe-webpart&template=question.yml&sample=advanced-iframe-webpart&authors=@365knoten&title=advanced-iframe-webpart%20-%20).
|
||||
|
||||
## 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.**
|
||||
|
||||
<img src="https://m365-visitor-stats.azurewebsites.net/sp-dev-fx-webparts/samples/advanced-iframe-webpart" />
|
Binary file not shown.
After Width: | Height: | Size: 378 KiB |
Binary file not shown.
After Width: | Height: | Size: 76 KiB |
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
|
@ -0,0 +1,51 @@
|
|||
[
|
||||
{
|
||||
"name": "pnp-sp-dev-spfx-web-parts-advanced-iframe-webpart",
|
||||
"source": "pnp",
|
||||
"title": "Advanced IFrame Webpart",
|
||||
"shortDescription": "This webpart allows users to add a webpage in an IFrame to a modern SharePoint page.",
|
||||
"url": "https://github.com/pnp/sp-dev-fx-webparts/tree/main/samples/advanced-iframe-webpart",
|
||||
"longDescription": [
|
||||
"This web part demonstrates the following features: Adding a webpart to a 'Full-Width' section, resizing the webpart to fit the given space of the page, fetching dynamic parameters like the current theme or querystring and passing them to the IFrame."
|
||||
],
|
||||
"creationDateTime": "2024-08-27",
|
||||
"updateDateTime": "2024-08-27",
|
||||
"products": [
|
||||
"SharePoint"
|
||||
],
|
||||
"metadata": [
|
||||
{
|
||||
"key": "CLIENT-SIDE-DEV",
|
||||
"value": "Javascript"
|
||||
},
|
||||
{
|
||||
"key": "SPFX-VERSION",
|
||||
"value": "1.12.1"
|
||||
}
|
||||
],
|
||||
"thumbnails": [
|
||||
{
|
||||
"type": "image",
|
||||
"order": 100,
|
||||
"url": "https://github.com/pnp/sp-dev-fx-webparts/raw/main/samples/advanced-iframe-webpart/assets/advancediframewebpart.gif",
|
||||
"alt": "Advanced IFrame Webpart"
|
||||
}
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"gitHubAccount": "365knoten",
|
||||
"company": "Storm Technology Ltd",
|
||||
"pictureUrl": "https://github.com/365knoten.png",
|
||||
"name": "Sven Sieverding",
|
||||
"twitter": "365knoten"
|
||||
}
|
||||
],
|
||||
"references": [
|
||||
{
|
||||
"name": "Build your first SharePoint client-side web part",
|
||||
"description": "Client-side web parts are client-side components that run in the context of a SharePoint page. Client-side web parts can be deployed to SharePoint environments that support the SharePoint Framework. You can also use modern JavaScript web frameworks, tools, and libraries to build them.",
|
||||
"url": "https://learn.microsoft.com/sharepoint/dev/spfx/web-parts/get-started/build-a-hello-world-web-part"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/config.2.0.schema.json",
|
||||
"version": "2.0",
|
||||
"bundles": {
|
||||
"advanced-iframe-webpart": {
|
||||
"components": [
|
||||
{
|
||||
"entrypoint": "./lib/webparts/advancediframewebpart/AdvancedIFrameWebpart.js",
|
||||
"manifest": "./src/webparts/advancediframewebpart/AdvancedIFrameWebpart.manifest.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"localizedResources": {
|
||||
"AdvancedIFrameWebpartStrings": "lib/webparts/advancediframewebpart/loc/{locale}.js",
|
||||
"PropertyControlStrings": "node_modules/@pnp/spfx-property-controls/lib/loc/{locale}.js"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/deploy-azure-storage.schema.json",
|
||||
"workingDir": "./release/assets/",
|
||||
"account": "<!-- STORAGE ACCOUNT NAME -->",
|
||||
"container": "advanced-iframe-webpart",
|
||||
"accessKey": "<!-- ACCESS KEY -->"
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/package-solution.schema.json",
|
||||
"solution": {
|
||||
"name": "advanced-iframe-webpart",
|
||||
"id": "ea8bc86d-8bd5-42fb-929d-25789fddec26",
|
||||
"version": "1.0.0.9",
|
||||
"includeClientSideAssets": true,
|
||||
"isDomainIsolated": false,
|
||||
"developer": {
|
||||
"name": "",
|
||||
"websiteUrl": "",
|
||||
"privacyUrl": "",
|
||||
"termsOfUseUrl": "",
|
||||
"mpnId": "Undefined-1.13.1"
|
||||
}
|
||||
},
|
||||
"paths": {
|
||||
"zippedPackage": "solution/advanced-iframe-webpart.sppkg"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/core-build/serve.schema.json",
|
||||
"port": 4321,
|
||||
"https": true,
|
||||
"initialPage": "https://365knoten.sharepoint.com/sites/MyAppPage/_layouts/workbench.aspx"
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/write-manifests.schema.json",
|
||||
"cdnBasePath": "<!-- PATH TO CDN -->"
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
'use strict';
|
||||
|
||||
// check if gulp dist was called
|
||||
if (process.argv.indexOf('dist') !== -1) {
|
||||
// add ship options to command call
|
||||
process.argv.push('--ship');
|
||||
}
|
||||
|
||||
const path = require('path');
|
||||
const gulp = require('gulp');
|
||||
const build = require('@microsoft/sp-build-web');
|
||||
const gulpSequence = require('gulp-sequence');
|
||||
|
||||
build.addSuppression(`Warning - [sass] The local CSS class 'ms-Grid' is not camelCase and will not be type-safe.`);
|
||||
|
||||
// Create clean distrubution package
|
||||
gulp.task('dist', gulpSequence('clean', 'bundle', 'package-solution'));
|
||||
// Create clean development package
|
||||
gulp.task('dev', gulpSequence('clean', 'bundle', 'package-solution'));
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Custom Framework Specific gulp tasks
|
||||
*/
|
||||
build.tslintCmd.enabled = false
|
||||
|
||||
build.initialize(gulp);
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,37 @@
|
|||
{
|
||||
"name": "advanced-iframe-webpart",
|
||||
"version": "0.0.1",
|
||||
"private": true,
|
||||
"main": "lib/index.js",
|
||||
"scripts": {
|
||||
"tasks": "gulp --tasks",
|
||||
"serve": "gulp serve-deprecated",
|
||||
"dist": "gulp clean && gulp build --ship && gulp bundle --ship && gulp package-solution --ship",
|
||||
"tslint:autofix": "tslint --fix -c ./tslint.json 'src/**/*{.ts,.tsx}'",
|
||||
"build": "gulp bundle",
|
||||
"clean": "gulp clean",
|
||||
"test": "gulp test",
|
||||
"preversion": "node ./tools/pre-version.js",
|
||||
"postversion": "gulp dist"
|
||||
},
|
||||
"dependencies": {
|
||||
"@microsoft/rush-stack-compiler-4.2": "^0.3.1",
|
||||
"@microsoft/sp-core-library": "1.13.1",
|
||||
"@microsoft/sp-lodash-subset": "1.13.1",
|
||||
"@microsoft/sp-office-ui-fabric-core": "1.13.1",
|
||||
"@microsoft/sp-property-pane": "1.13.1",
|
||||
"@microsoft/sp-webpart-base": "1.13.1",
|
||||
"@pnp/sp": "^3.17.0",
|
||||
"@pnp/spfx-property-controls": "3.14.0",
|
||||
"handlebars": "^4.7.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@microsoft/sp-build-web": "1.13.1",
|
||||
"@microsoft/sp-module-interfaces": "1.13.1",
|
||||
"@microsoft/sp-tslint-rules": "1.13.1",
|
||||
"@types/webpack-env": "1.13.1",
|
||||
"ajv": "~5.2.2",
|
||||
"gulp": "~4.0.2",
|
||||
"gulp-sequence": "1.0.0"
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
// A file is required to be in the root of the /src directory by the TypeScript compiler
|
|
@ -0,0 +1,29 @@
|
|||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/spfx/client-side-web-part-manifest.schema.json",
|
||||
"id": "d091a263-4d89-46c0-9a7f-5a55f346e674",
|
||||
"alias": "AdvancedIFrameWebpart",
|
||||
"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,
|
||||
"supportedHosts": ["SharePointWebPart", "TeamsPersonalApp", "TeamsTab", "SharePointFullPage"],
|
||||
"supportsThemeVariants": true,
|
||||
"supportsFullBleed": true,
|
||||
|
||||
"preconfiguredEntries": [{
|
||||
"groupId": "5c03119e-3074-46fd-976b-c60198311f70", // Other
|
||||
"group": { "default": "Other" },
|
||||
"title": { "default": "Advanced IFrame" },
|
||||
"description": { "default": "Add an IFrame to the current page. This supports the full-width section. You can pass context specific parameters down to the webpart." },
|
||||
"officeFabricIconFontName": "Boards",
|
||||
"properties": {
|
||||
"aspectratio":"as0916"
|
||||
}
|
||||
}]
|
||||
}
|
|
@ -0,0 +1,192 @@
|
|||
import { Version } from '@microsoft/sp-core-library';
|
||||
import {
|
||||
IPropertyPaneConfiguration, PropertyPaneChoiceGroup
|
||||
} from '@microsoft/sp-property-pane';
|
||||
import { BaseClientSideWebPart } from '@microsoft/sp-webpart-base';
|
||||
|
||||
|
||||
import * as strings from 'AdvancedIFrameWebpartStrings';
|
||||
import * as Handlebars from 'handlebars';
|
||||
|
||||
import { PropertyFieldCodeEditor, PropertyFieldCodeEditorLanguages } from '@pnp/spfx-property-controls/lib/PropertyFieldCodeEditor';
|
||||
|
||||
import {
|
||||
ThemeProvider,
|
||||
ThemeChangedEventArgs,
|
||||
IReadonlyTheme,
|
||||
ISemanticColors
|
||||
} from '@microsoft/sp-component-base';
|
||||
import { IFrameDataModel } from './models/IFrameDataModel';
|
||||
import { createHTMLDescription } from './helpers/createHTMLDescription';
|
||||
|
||||
import "@pnp/sp/sites";
|
||||
import "@pnp/sp/";
|
||||
import "@pnp/sp/webs";
|
||||
import { IScriptSaveDomainService, ScriptSaveDomainService } from './services/ScriptSaveDomainService';
|
||||
|
||||
export interface AdvancedIFrameWebpartProps {
|
||||
aspectratio: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
|
||||
|
||||
export default class AdvancedIFrameWebpart extends BaseClientSideWebPart<AdvancedIFrameWebpartProps> {
|
||||
|
||||
private _ScriptSaveDomainService: IScriptSaveDomainService;
|
||||
|
||||
private _themeProvider: ThemeProvider;
|
||||
private _themeVariant: IReadonlyTheme | undefined;
|
||||
private _IFramewidth: number = 640;
|
||||
|
||||
/**
|
||||
* The onInit method
|
||||
*/
|
||||
protected async onInit(): Promise<void> {
|
||||
await super.onInit();
|
||||
this._ScriptSaveDomainService = this.context.serviceScope.consume(ScriptSaveDomainService.serviceKey);
|
||||
this._themeProvider = this.context.serviceScope.consume(ThemeProvider.serviceKey);
|
||||
this._themeVariant = this._themeProvider.tryGetTheme();
|
||||
this._themeProvider.themeChangedEvent.add(this, this._handleThemeChangedEvent);
|
||||
}
|
||||
|
||||
/**
|
||||
* The render method
|
||||
*/
|
||||
public render(): void {
|
||||
// get variables that can be used
|
||||
const data = this.getVariables()
|
||||
|
||||
if (this.properties.url == null || this.properties.url.length == 0) {
|
||||
// no url provided in property pane, so render description
|
||||
this.domElement.innerHTML = createHTMLDescription(strings, data);
|
||||
return;
|
||||
}
|
||||
// Compile and render the variables into the url
|
||||
const renderHandlebars = Handlebars.compile(this.properties.url);
|
||||
const renderedUrl = renderHandlebars(data);
|
||||
|
||||
if (!this._ScriptSaveDomainService.isInSaveDomain(renderedUrl)) {
|
||||
// the rendered URL is not a safe url, so show not allowed message
|
||||
this.domElement.innerHTML = strings.UrlNotAllowedMessage;
|
||||
return;
|
||||
}
|
||||
const aspectratio = this.properties.aspectratio == "as0916" ? "9 / 16" : "16 / 9";
|
||||
this.domElement.innerHTML = `<iframe style="aspect-ratio: ${aspectratio};height: 100%;width: 100%;" src="${renderedUrl}" width="${this._IFramewidth}" frameborder="0" allow="autoplay; fullscreen; picture-in-picture"></iframe>`;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This Method is called whenever the theme of the site has been changed
|
||||
* @param args
|
||||
*/
|
||||
private _handleThemeChangedEvent(args: ThemeChangedEventArgs): void {
|
||||
this._themeVariant = args.theme;
|
||||
this.render;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the variables that can be used in the handlebars template
|
||||
* @returns
|
||||
*/
|
||||
private getVariables() {
|
||||
// get all current theme colors
|
||||
const semanticColors: Partial<ISemanticColors> | undefined = this._themeVariant && this._themeVariant.semanticColors;
|
||||
|
||||
// get all current query string parameters and put them into a "query" object
|
||||
const entries = (new URLSearchParams(window.location.search) as any).entries();
|
||||
const query: any = {};
|
||||
let value = null;
|
||||
while (value = entries.next(), !value.done) {
|
||||
query[value.value[0]] = value.value[1];
|
||||
}
|
||||
|
||||
// initialize the data object that will be passed to handlebars renderer
|
||||
const data: IFrameDataModel = {
|
||||
query: query,
|
||||
culture: {
|
||||
currentCultureName: this.context.pageContext.cultureInfo.currentCultureName
|
||||
},
|
||||
site: {
|
||||
id: this.context.pageContext.site.id,
|
||||
serverRelativeUrl: this.context.pageContext.site.serverRelativeUrl
|
||||
},
|
||||
page: {
|
||||
pageUrl: this.context.pageContext.site.serverRequestPath
|
||||
},
|
||||
user: {
|
||||
name: this.context.pageContext.user.displayName,
|
||||
email: this.context.pageContext.user.email,
|
||||
loginName: this.context.pageContext.user.loginName,
|
||||
},
|
||||
// remove the pound sign from every color... It does not work as a query string parameter
|
||||
color: Object.keys(semanticColors).reduce((obj, key) => { obj[key] = semanticColors[key].replace("#", ""); return obj }, {}) || {}
|
||||
};
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is called whenever the webpart resizes and provides the new width
|
||||
* @param newWidth
|
||||
*/
|
||||
protected onAfterResize(newWidth: number) {
|
||||
this._IFramewidth = newWidth;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the dataVersion
|
||||
*/
|
||||
protected get dataVersion(): Version {
|
||||
return Version.parse('1.0');
|
||||
}
|
||||
|
||||
/**
|
||||
* This configures the property pane
|
||||
* @returns
|
||||
*/
|
||||
protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
|
||||
return {
|
||||
pages: [
|
||||
{
|
||||
header: {
|
||||
description: strings.PropertyPaneDescription
|
||||
},
|
||||
groups: [
|
||||
{
|
||||
groupName: strings.BasicGroupName,
|
||||
|
||||
groupFields: [
|
||||
PropertyPaneChoiceGroup('aspectratio', {
|
||||
label: strings.AspectRatioLabel,
|
||||
options: [
|
||||
{ key: 'as1609', text: '16 / 09', checked: true },
|
||||
{ key: 'as0916', text: '09 / 16' }
|
||||
],
|
||||
}),
|
||||
PropertyFieldCodeEditor('url', {
|
||||
label: strings.UrlFieldLabel,
|
||||
panelTitle: strings.EditUrlLabel,
|
||||
initialValue: this.properties.url,
|
||||
onPropertyChange: this.onPropertyPaneFieldChanged,
|
||||
properties: this.properties,
|
||||
disabled: false,
|
||||
key: 'codeEditorFieldId',
|
||||
language: PropertyFieldCodeEditorLanguages.Handlebars,
|
||||
options: {
|
||||
wrap: true,
|
||||
fontSize: 20,
|
||||
mode: "text"
|
||||
// more options
|
||||
}
|
||||
})
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
/**
|
||||
* A Helper Class.
|
||||
* This helps building an easy html-structure in a fluent manner.
|
||||
*/
|
||||
export class HTMLDescriptionBuilder {
|
||||
|
||||
private _html = "";
|
||||
|
||||
/**
|
||||
*
|
||||
* @returns the resulting HTML
|
||||
*/
|
||||
public toString() {
|
||||
|
||||
return this._html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends html to the current document
|
||||
* @param html
|
||||
* @returns
|
||||
*/
|
||||
public add(html: string) {
|
||||
this._html += html;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Appends an HTML tag to the current document
|
||||
* @param tag
|
||||
* @param value
|
||||
* @returns
|
||||
*/
|
||||
public addTag(tag: string, value: string) {
|
||||
return this.add(`<${tag}>${value}</${tag}>`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an h3 tag to the current document
|
||||
* @param value
|
||||
* @returns
|
||||
*/
|
||||
public addHeadline3(value: string) {
|
||||
return this.addTag("h3", value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an h2 tag to the current document
|
||||
* @param value
|
||||
* @returns
|
||||
*/
|
||||
public addHeadline2(value: string) {
|
||||
return this.addTag("h2", value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an p tag to the current document
|
||||
* @param value
|
||||
* @returns
|
||||
*/
|
||||
|
||||
public addParagraph(value: string) {
|
||||
return this.addTag("p", value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterates over all properties of an object and displays them in an HTML table
|
||||
* @returns
|
||||
*/
|
||||
public addPropertyTable(obj: any, keyPrefix = "", keyColumnTitle = "Key", valueColumnTitle = "Value") {
|
||||
return this.add(`<table>
|
||||
<tr><th>${keyColumnTitle}</th><th>${valueColumnTitle}</th></tr>
|
||||
${Object.keys(obj).reduce((propstring: string, prop: string) => {
|
||||
return propstring += `<tr><td>{{${keyPrefix}${prop}}}</td><td>${obj[prop]}</td></tr>\n`;
|
||||
}, "")}
|
||||
</table>`
|
||||
);
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
import { IFrameDataModel } from "../models/IFrameDataModel";
|
||||
import { HTMLDescriptionBuilder } from "./HTMLDescriptionBuilder";
|
||||
|
||||
/**
|
||||
* Creates the Description for this webpart
|
||||
* @param strings
|
||||
* @param data
|
||||
* @returns
|
||||
*/
|
||||
export const createHTMLDescription = (strings: IAdvancedIFrameWebpartStrings, data: IFrameDataModel) => {
|
||||
|
||||
|
||||
return new HTMLDescriptionBuilder()
|
||||
.addHeadline2(strings.WebpartTitle)
|
||||
.addParagraph(strings.DescriptionGeneral1)
|
||||
.addParagraph(strings.DescriptionGeneral2)
|
||||
.addHeadline3(strings.DescriptionHeaderQuery)
|
||||
.addParagraph(strings.DescriptionDetailsQuery)
|
||||
.addPropertyTable(data.query, "query.")
|
||||
.addHeadline3(strings.DescriptionHeaderUser)
|
||||
.addPropertyTable(data.user, "user.")
|
||||
.addHeadline3(strings.DescriptionHeaderSite)
|
||||
.addPropertyTable(data.site, "site.")
|
||||
.addHeadline3(strings.DescriptionHeaderColors)
|
||||
.addPropertyTable(data.color, "color.")
|
||||
.addHeadline3(strings.DescriptionHeaderCulture)
|
||||
.addPropertyTable(data.culture, "culture.")
|
||||
.toString();
|
||||
|
||||
};
|
|
@ -0,0 +1,19 @@
|
|||
define([], function () {
|
||||
return {
|
||||
"WebpartTitle":"Advanced IFrame Webpart",
|
||||
"PropertyPaneDescription": "This webpart displays an IFrame, but keeps the aspect ratio and reacts responsive to width changes.\n You can also add dynamic parameters to the IFrame url.",
|
||||
"BasicGroupName": "Settings",
|
||||
"UrlFieldLabel": "IFrame Url",
|
||||
"AspectRatioLabel": "Aspect Ratio",
|
||||
"EditUrlLabel": "Edit Url",
|
||||
"DescriptionGeneral1": "Open the property pane to enter the url of the page you want to display in the IFrame.",
|
||||
"DescriptionGeneral2": "You can use th following variables in the url:",
|
||||
"DescriptionHeaderQuery": "Query string parameters",
|
||||
"DescriptionDetailsQuery": "You can use each query string parameter \"param\" as \"{{query.param}}\"",
|
||||
"DescriptionHeaderSite": "Site Parameters",
|
||||
"DescriptionHeaderColors": "Colors Parameters",
|
||||
"DescriptionHeaderUser": "User Parameters",
|
||||
"DescriptionHeaderCulture": "UI Culture Parameters",
|
||||
"UrlNotAllowedMessage":"This URL can not be used in an IFrame. Check \"HTML Field Security\"."
|
||||
}
|
||||
});
|
22
samples/advanced-iframe-webpart/src/webparts/advancediframewebpart/loc/mystrings.d.ts
vendored
Normal file
22
samples/advanced-iframe-webpart/src/webparts/advancediframewebpart/loc/mystrings.d.ts
vendored
Normal file
|
@ -0,0 +1,22 @@
|
|||
declare interface IAdvancedIFrameWebpartStrings {
|
||||
WebpartTitle:string;
|
||||
PropertyPaneDescription: string;
|
||||
BasicGroupName: string;
|
||||
UrlFieldLabel: string;
|
||||
AspectRatioLabel:string;
|
||||
EditUrlLabel:string;
|
||||
DescriptionGeneral1:string;
|
||||
DescriptionGeneral2:string;
|
||||
DescriptionHeaderQuery:string;
|
||||
DescriptionDetailsQuery:string;
|
||||
DescriptionHeaderSite:string;
|
||||
DescriptionHeaderColors:string;
|
||||
DescriptionHeaderUser:string;
|
||||
DescriptionHeaderCulture:string;
|
||||
UrlNotAllowedMessage:string;
|
||||
}
|
||||
|
||||
declare module 'AdvancedIFrameWebpartStrings' {
|
||||
const strings: IAdvancedIFrameWebpartStrings;
|
||||
export = strings;
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
export interface IFrameDataModel {
|
||||
query: any;
|
||||
color: any;
|
||||
culture: any;
|
||||
site: any;
|
||||
user: any;
|
||||
page: any;
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
import { Log, ServiceKey, ServiceScope } from "@microsoft/sp-core-library";
|
||||
import { spfi, SPFI, SPFx as spSPFx } from "@pnp/sp";
|
||||
import "@pnp/sp/webs";
|
||||
import { PageContext } from "@microsoft/sp-page-context";
|
||||
|
||||
const LOG_SOURCE: string = "'advanced-iframe-webpart:ScriptSaveDomainService";
|
||||
|
||||
/**
|
||||
* A service that tells us if a given domain is save to display in an IFrame
|
||||
*/
|
||||
export interface IScriptSaveDomainService {
|
||||
/**
|
||||
* Returns true if the given url is a safe url
|
||||
* @param url
|
||||
* @returns
|
||||
*/
|
||||
isInSaveDomain: (url: string) => Promise<boolean>;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A service that tells us if a given domain is save to display in an IFrame
|
||||
*/
|
||||
export class ScriptSaveDomainService implements IScriptSaveDomainService {
|
||||
|
||||
/**
|
||||
* Stores the downloaded script save domains
|
||||
*/
|
||||
private _scriptSaveDomains: string[] = null;
|
||||
/**
|
||||
* The pnpjs spfi object
|
||||
*/
|
||||
private _spfi: SPFI;
|
||||
|
||||
//Create a ServiceKey which will be used to consume the service.
|
||||
public static readonly serviceKey: ServiceKey<IScriptSaveDomainService> =
|
||||
ServiceKey.create<IScriptSaveDomainService>(LOG_SOURCE, ScriptSaveDomainService);
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param serviceScope the servicescipe
|
||||
*/
|
||||
constructor(serviceScope: ServiceScope) {
|
||||
serviceScope.whenFinished(() => {
|
||||
Log.info(LOG_SOURCE, "Begin constructing ScriptSaveDomainService");
|
||||
const pageContext = serviceScope.consume(PageContext.serviceKey);
|
||||
this._spfi = spfi().using(spSPFx({ pageContext }));
|
||||
Log.info(LOG_SOURCE, "Constructed ScriptSaveDomainService");
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches an array of all script save domains
|
||||
* @returns
|
||||
*/
|
||||
private async fetchScriptSaveDomains() {
|
||||
|
||||
// If we don't have already downloaded the domains
|
||||
if (this._scriptSaveDomains == null) {
|
||||
Log.info(LOG_SOURCE, "Downloading Property Bag");
|
||||
// get the Script Save Domains from the site's property bag
|
||||
const props = await this._spfi.web.allProperties();
|
||||
//parse and split them into an array
|
||||
this._scriptSaveDomains = `${props["OData__x005f__x005f_ScriptSafeDomains"]}`
|
||||
.split(";")
|
||||
.filter((d: string) => d != null && d.length > 0)
|
||||
;
|
||||
// Always allow IFrames from the current domain
|
||||
this._scriptSaveDomains.push(window.location.host);
|
||||
Log.info(LOG_SOURCE, "Created script safe domains array");
|
||||
}
|
||||
|
||||
return this._scriptSaveDomains;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the given url is a safe url
|
||||
* @param url
|
||||
* @returns
|
||||
*/
|
||||
public async isInSaveDomain(url: string) {
|
||||
const result = (await this.fetchScriptSaveDomains()).reduce((value, domain) => {
|
||||
if (url.indexOf(domain) != -1) {
|
||||
return true;
|
||||
}
|
||||
return value;
|
||||
}, false)
|
||||
Log.info(LOG_SOURCE, `Domain ${url} is a save domain? ${result}`);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
Binary file not shown.
After Width: | Height: | Size: 10 KiB |
Binary file not shown.
After Width: | Height: | Size: 542 B |
|
@ -0,0 +1,64 @@
|
|||
/**
|
||||
* This script updates the package-solution version analogue to the
|
||||
* the package.json file.
|
||||
*/
|
||||
|
||||
if (process.env.npm_package_version === undefined) {
|
||||
|
||||
throw 'Package version cannot be evaluated';
|
||||
|
||||
}
|
||||
|
||||
// define path to package-solution file
|
||||
const solution = './config/package-solution.json',
|
||||
teams = './teams/manifest.json';
|
||||
|
||||
// require filesystem instance
|
||||
const fs = require('fs');
|
||||
|
||||
// get next automated package version from process variable
|
||||
const nextPkgVersion = process.env.npm_package_version;
|
||||
|
||||
// make sure next build version match
|
||||
const nextVersion = nextPkgVersion.indexOf('-') === -1 ?
|
||||
nextPkgVersion : nextPkgVersion.split('-')[0];
|
||||
|
||||
// Update version in SPFx package-solution if exists
|
||||
if (fs.existsSync(solution)) {
|
||||
|
||||
// read package-solution file
|
||||
const solutionFileContent = fs.readFileSync(solution, 'UTF-8');
|
||||
// parse file as json
|
||||
const solutionContents = JSON.parse(solutionFileContent);
|
||||
|
||||
// set property of version to next version
|
||||
solutionContents.solution.version = nextVersion + '.0';
|
||||
|
||||
// save file
|
||||
fs.writeFileSync(
|
||||
solution,
|
||||
// convert file back to proper json
|
||||
JSON.stringify(solutionContents, null, 2),
|
||||
'UTF-8');
|
||||
|
||||
}
|
||||
|
||||
// Update version in teams manifest if exists
|
||||
if (fs.existsSync(teams)) {
|
||||
|
||||
// read package-solution file
|
||||
const teamsManifestContent = fs.readFileSync(teams, 'UTF-8');
|
||||
// parse file as json
|
||||
const teamsContent = JSON.parse(teamsManifestContent);
|
||||
|
||||
// set property of version to next version
|
||||
teamsContent.version = nextVersion;
|
||||
|
||||
// save file
|
||||
fs.writeFileSync(
|
||||
teams,
|
||||
// convert file back to proper json
|
||||
JSON.stringify(teamsContent, null, 2),
|
||||
'UTF-8');
|
||||
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
{
|
||||
"extends": "./node_modules/@microsoft/rush-stack-compiler-4.2/includes/tsconfig-web.json",
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"jsx": "react",
|
||||
"declaration": true,
|
||||
"sourceMap": true,
|
||||
"experimentalDecorators": true,
|
||||
"skipLibCheck": true,
|
||||
"outDir": "lib",
|
||||
"inlineSources": false,
|
||||
"strictNullChecks": false,
|
||||
"noUnusedLocals": false,
|
||||
"typeRoots": [
|
||||
"./node_modules/@types",
|
||||
"./node_modules/@microsoft"
|
||||
],
|
||||
"types": [
|
||||
"webpack-env"
|
||||
],
|
||||
"lib": [
|
||||
"es5",
|
||||
"dom",
|
||||
"es2015.collection",
|
||||
"es2015.promise"
|
||||
],
|
||||
"esModuleInterop": true
|
||||
},
|
||||
"include": [
|
||||
"src/**/*.ts",
|
||||
"src/**/*.tsx"
|
||||
]
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
{
|
||||
"extends": "./node_modules/@microsoft/sp-tslint-rules/base-tslint.json",
|
||||
"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-with-statement": true,
|
||||
"semicolon": true,
|
||||
"trailing-comma": false,
|
||||
"typedef": false,
|
||||
"typedef-whitespace": false,
|
||||
"use-named-parameter": true,
|
||||
"variable-name": false,
|
||||
"whitespace": false
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue