Merge pull request #2083 from aakashbhardwaj619/reactPageNavigatorUpgrade

react-page-navigator SPFx upgrade and code refactoring
This commit is contained in:
Hugo Bernier 2021-10-31 15:14:57 -04:00 committed by GitHub
commit cf9b0fefee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 16657 additions and 8172 deletions

View File

@ -1,25 +0,0 @@
# 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

@ -12,6 +12,7 @@ lib
solution
temp
*.sppkg
release
# Coverage directory used by tools like istanbul
coverage

View File

@ -18,7 +18,7 @@
"environment": "spo",
"framework": "react",
"isCreatingSolution": true,
"version": "1.9.1",
"version": "1.12.1",
"libraryName": "navigator",
"libraryId": "065ee566-e00d-4058-bbfd-356c8d9a8005",
"packageManager": "npm",

View File

@ -8,22 +8,29 @@ When added to a Vertical Section it can be used as a Contents table for the page
![Page Navigator](./assets/PageNavigator.gif)
## Used SharePoint Framework Version
## Compatibility
![version](https://img.shields.io/badge/version-1.9.1-green.svg)
![SPFx 1.12.1](https://img.shields.io/badge/SPFx-1.12.1-green.svg)
![Node.js LTS v14 | LTS v12 | LTS v10](https://img.shields.io/badge/Node.js-LTS%20v14%20%7C%20LTS%20v12%20%7C%20LTS%20v10-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")
![Local Workbench Incompatible](https://img.shields.io/badge/Local%20Workbench-Incompatible-red.svg "The solution requires access to the page structure")
![Hosted Workbench Partially](https://img.shields.io/badge/Hosted%20Workbench-Partially-yellow.svg "The solution needs to run on a hosted page to work as intended")
## Version history
Version|Date|Comments
-------|----|--------
1.0|September 5, 2019|Initial release
1.1|October 20, 2021|SPFx Upgraded to 1.12.1 and code refactored
## Minimal Path to Awesome
- git clone the repo
- npm i
- gulp bundle --ship
- gulp package-solution --ship
- `git clone` the repo
- `npm i`
- `gulp bundle --ship`
- `gulp package-solution --ship`
- Add the app package to Site Collection App Catalog and Install the App
- Add the web part to a page in the Site Collection
@ -31,10 +38,20 @@ Version|Date|Comments
Solution|Author(s)
--------|---------
react-page-navigator|Aakash Bhardwaj
react-page-navigator|[Aakash Bhardwaj](https://github.com/aakashbhardwaj619)
## 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.**
## 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 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&template=bug-report.yml&sample=react-page-navigator&authors=@aakashbhardwaj619&title=react-page-navigator%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%3Abug-suspected&template=question.yml&sample=react-page-navigator&authors=@aakashbhardwaj619&title=react-page-navigator%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%3Abug-suspected&template=suggestion.yml&sample=react-page-navigator&authors=@aakashbhardwaj619&title=react-page-navigator%20-%20).
<img src="https://telemetry.sharepointpnp.com/sp-dev-fx-webparts/samples/react-page-navigator" />

View File

@ -9,7 +9,7 @@
"This web part fetches all the automatically added Header anchor tags in a SharePoint page and displays them in a Navigation component."
],
"creationDateTime": "2019-09-05",
"updateDateTime": "2019-09-05",
"updateDateTime": "2021-10-20",
"products": [
"SharePoint",
"Office"
@ -21,7 +21,7 @@
},
{
"key": "SPFX-VERSION",
"value": "1.9.1"
"value": "1.12.1"
}
],
"thumbnails": [

View File

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

View File

@ -1,6 +1,6 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/deploy-azure-storage.schema.json",
"workingDir": "./temp/deploy/",
"workingDir": "./release/assets/",
"account": "<!-- STORAGE ACCOUNT NAME -->",
"container": "navigator",
"accessKey": "<!-- ACCESS KEY -->"

View File

@ -1,9 +1,16 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/package-solution.schema.json",
"solution": {
"developer": {
"name": "",
"privacyUrl": "",
"termsOfUseUrl": "",
"websiteUrl": "",
"mpnId": ""
},
"name": "react-page-navigator",
"id": "065ee566-e00d-4058-bbfd-356c8d9a8005",
"version": "1.0.0.0",
"version": "1.1.0.0",
"includeClientSideAssets": true,
"isDomainIsolated": false
},

View File

@ -25,5 +25,12 @@ gulp.task('dev', gulpSequence('clean', 'bundle', 'package-solution'));
* Custom Framework Specific gulp tasks
*/
var getTasks = build.rig.getTasks;
build.rig.getTasks = function () {
var result = getTasks.call(build.rig);
result.set('serve', result.get('serve-deprecated'));
return result;
};
build.initialize(gulp);

File diff suppressed because it is too large Load Diff

View File

@ -3,9 +3,6 @@
"version": "0.0.1",
"private": true,
"main": "lib/index.js",
"engines": {
"node": ">=0.10.0"
},
"scripts": {
"build": "gulp bundle",
"clean": "gulp clean",
@ -15,36 +12,35 @@
"test:watch": "./node_modules/.bin/jest --config ./config/jest.config.json --watchAll"
},
"dependencies": {
"@microsoft/sp-core-library": "1.9.1",
"@microsoft/sp-lodash-subset": "1.9.1",
"@microsoft/sp-office-ui-fabric-core": "1.9.1",
"@microsoft/sp-webpart-base": "1.9.1",
"@microsoft/sp-core-library": "1.12.1",
"@microsoft/sp-lodash-subset": "1.12.1",
"@microsoft/sp-office-ui-fabric-core": "1.12.1",
"@microsoft/sp-property-pane": "1.12.1",
"@microsoft/sp-webpart-base": "1.12.1",
"@pnp/pnpjs": "^1.3.5",
"@pnp/spfx-controls-react": "1.14.0",
"@pnp/spfx-property-controls": "1.16.0",
"@types/es6-promise": "0.0.33",
"@types/react": "16.8.8",
"@types/react-dom": "16.8.3",
"@types/webpack-env": "1.13.1",
"office-ui-fabric-react": "^6.182.0",
"react": "16.8.5",
"react-dom": "16.8.5"
"office-ui-fabric-react": "7.156.0",
"react": "16.9.0",
"react-dom": "16.9.0"
},
"resolutions": {
"@types/react": "16.8.8"
},
"devDependencies": {
"@microsoft/rush-stack-compiler-3.3": "0.1.7",
"@microsoft/sp-build-web": "1.9.1",
"@microsoft/sp-module-interfaces": "1.9.1",
"@microsoft/sp-tslint-rules": "1.9.1",
"@microsoft/sp-webpart-workbench": "1.9.1",
"@types/chai": "3.4.34",
"@types/mocha": "2.2.38",
"@types/react": "^16.7.22",
"@microsoft/rush-stack-compiler-3.7": "0.2.3",
"@microsoft/sp-build-web": "1.12.1",
"@microsoft/sp-module-interfaces": "1.12.1",
"@microsoft/sp-tslint-rules": "1.12.1",
"@microsoft/sp-webpart-workbench": "1.12.1",
"@types/es6-promise": "0.0.33",
"@types/react": "16.9.36",
"@types/react-dom": "16.9.8",
"@types/webpack-env": "1.13.1",
"@voitanos/jest-preset-spfx-react16": "^1.1.0",
"ajv": "~5.2.2",
"gulp": "~3.9.1",
"gulp": "4.0.2",
"gulp-sequence": "1.0.0",
"jest": "^23.6.0"
}

View File

@ -3,18 +3,49 @@ import { WebPartContext } from '@microsoft/sp-webpart-base';
import { SPHttpClient } from '@microsoft/sp-http';
export class SPService {
/* Array to store all unique anchor URLs */
private static allUrls: string[] = [];
/**
* Returns the unique Anchor URL for a heading
* @param headingValue The text value of the heading
* @returns anchorUrl
*/
private static GetAnchorUrl(headingValue: string): string {
let urlExists = true;
// .replace(/'|?|\|/| |&/g, "-") replaces any blanks and special characters (list is for sure not complete) with "-"
// .replace(/--+/g, "-") replaces any additional - with only one -; e.g. --- get replaced with -, -- get replaced with - etc.
let anchorUrl = `#${headingValue
.replace(/\'|\?|\\|\/| |\&/g, "-")
.replace(/--+/g, "-")}`.toLowerCase();
let urlSuffix = 1;
while (urlExists === true) {
urlExists = (this.allUrls.indexOf(anchorUrl) === -1) ? false : true;
if (urlExists) {
anchorUrl = anchorUrl + `-${urlSuffix}`;
urlSuffix++;
}
}
return anchorUrl;
}
/**
* Returns the Anchor Links for Nav element
* @param context Web part context
* @returns anchorLinks
*/
public static async GetAnchorLinks(context: WebPartContext) {
let anchorLinks: INavLink[] = [];
const anchorLinks: INavLink[] = [];
try {
/* Page ID on which the web part is added */
let pageId = context.pageContext.listItem.id;
const pageId = context.pageContext.listItem.id;
/* Get the canvasContent1 data for the page which consists of all the HTML */
let data = await context.spHttpClient.get(`${context.pageContext.web.absoluteUrl}/_api/sitepages/pages(${pageId})`, SPHttpClient.configurations.v1);
let jsonData = await data.json();
let canvasContent1 = jsonData.CanvasContent1;
let canvasContent1JSON: any[] = JSON.parse(canvasContent1);
const data = await context.spHttpClient.get(`${context.pageContext.web.absoluteUrl}/_api/sitepages/pages(${pageId})`, SPHttpClient.configurations.v1);
const jsonData = await data.json();
const canvasContent1 = jsonData.CanvasContent1;
const canvasContent1JSON: any[] = JSON.parse(canvasContent1);
/* Initialize variables to be used for sorting and adding the Navigation links */
let headingIndex = 0;
@ -22,9 +53,6 @@ export class SPService {
let headingOrder = 0;
let prevHeadingOrder = 0;
/* Array to store all unique anchor URLs */
let allUrls: string[] = [];
/* Traverse through all the Text web parts in the page */
canvasContent1JSON.map((webPart) => {
if (webPart.innerHTML) {
@ -34,28 +62,14 @@ export class SPService {
/* The Header Text value */
// .replace(/<.+?>/gi, "") replaces in the headingValue any html tags like <strong> </strong>
// .replace(/&.+;/gi, "") replaces in the headingValue any &****; tags like &nbsp;
let headingValue = HTMLString.substring(HTMLString.search(/<h[1-4]>/g) + 4, HTMLString.search(/<\/h[1-4]>/g))
const headingValue = HTMLString.substring(HTMLString.search(/<h[1-4]>/g) + 4, HTMLString.search(/<\/h[1-4]>/g))
.replace(/<.+?>/gi, "")
.replace(/\&.+\;/gi, "");
headingOrder = parseInt(HTMLString.charAt(HTMLString.search(/<h[1-4]>/g) + 2));
/* Check if same anchorUrl already exists */
let urlExists = true;
// .replace(/'|?|\|/| |&/g, "-") replaces any blanks and special characters (list is for sure not complete) with "-"
// .replace(/--+/g, "-") replaces any additional - with only one -; e.g. --- get replaced with -, -- get replaced with - etc.
let anchorUrl = `#${headingValue
.replace(/\'|\?|\\|\/| |\&/g, "-")
.replace(/--+/g, "-")}`.toLowerCase();
let urlSuffix = 1;
while (urlExists === true) {
urlExists = (allUrls.indexOf(anchorUrl) === -1) ? false : true;
if (urlExists) {
anchorUrl = anchorUrl + `-${urlSuffix}`;
urlSuffix++;
}
}
allUrls.push(anchorUrl);
const anchorUrl = this.GetAnchorUrl(headingValue);
this.allUrls.push(anchorUrl);
/* Add links to Nav element */
if (anchorLinks.length === 0) {
@ -63,33 +77,42 @@ export class SPService {
} else {
if (headingOrder <= prevHeadingOrder) {
/* Adding or Promoting links */
if (headingOrder === 2) {
anchorLinks.push({ name: headingValue, key: anchorUrl, url: anchorUrl, links: [], isExpanded: true });
headingIndex++;
subHeadingIndex = -1;
} else {
if (headingOrder === 4) {
anchorLinks[headingIndex].links[subHeadingIndex].links.push({ name: headingValue, key: anchorUrl, url: anchorUrl, links: [], isExpanded: true });
} else if (headingOrder === 3) {
switch (headingOrder) {
case 2:
anchorLinks.push({ name: headingValue, key: anchorUrl, url: anchorUrl, links: [], isExpanded: true });
headingIndex++;
subHeadingIndex = -1;
break;
case 4:
if (subHeadingIndex > -1) {
anchorLinks[headingIndex].links[subHeadingIndex].links.push({ name: headingValue, key: anchorUrl, url: anchorUrl, links: [], isExpanded: true });
} else {
anchorLinks[headingIndex].links.push({ name: headingValue, key: anchorUrl, url: anchorUrl, links: [], isExpanded: true });
}
break;
default:
anchorLinks[headingIndex].links.push({ name: headingValue, key: anchorUrl, url: anchorUrl, links: [], isExpanded: true });
subHeadingIndex++;
}
subHeadingIndex = anchorLinks[headingIndex].links.length - 1;
break;
}
} else {
/* Making sub links */
if (headingOrder === 3) {
anchorLinks[headingIndex].links.push({ name: headingValue, key: anchorUrl, url: anchorUrl, links: [], isExpanded: true });
subHeadingIndex++;
subHeadingIndex = anchorLinks[headingIndex].links.length - 1;
} else {
anchorLinks[headingIndex].links[subHeadingIndex].links.push({ name: headingValue, key: anchorUrl, url: anchorUrl, links: [], isExpanded: true });
if (subHeadingIndex > -1) {
anchorLinks[headingIndex].links[subHeadingIndex].links.push({ name: headingValue, key: anchorUrl, url: anchorUrl, links: [], isExpanded: true });
} else {
anchorLinks[headingIndex].links.push({ name: headingValue, key: anchorUrl, url: anchorUrl, links: [], isExpanded: true });
}
}
}
}
prevHeadingOrder = headingOrder;
/* Replace the added header links from the string so they don't get processed again */
HTMLString = HTMLString.replace(`<h${headingOrder}>`, '');
HTMLString = HTMLString.replace(`</h${headingOrder}>`, '');
HTMLString = HTMLString.replace(`<h${headingOrder}>`, '').replace(`</h${headingOrder}>`, '');
}
}
});
@ -97,7 +120,7 @@ export class SPService {
console.log(error);
}
console.log(anchorLinks);
console.log('anchorLinks', anchorLinks);
return anchorLinks;
}
}

View File

@ -1,12 +1,8 @@
import * as React from 'react';
import * as ReactDom from 'react-dom';
import { Version } from '@microsoft/sp-core-library';
import {
BaseClientSideWebPart,
IPropertyPaneConfiguration,
PropertyPaneTextField
} from '@microsoft/sp-webpart-base';
import { BaseClientSideWebPart } from "@microsoft/sp-webpart-base";
import { IPropertyPaneConfiguration, PropertyPaneTextField } from "@microsoft/sp-property-pane";
import * as strings from 'PageNavigatorWebPartStrings';
import PageNavigator from './components/PageNavigator';
import { IPageNavigatorProps } from './components/IPageNavigatorProps';

View File

@ -1,5 +1,5 @@
{
"extends": "./node_modules/@microsoft/rush-stack-compiler-3.3/includes/tsconfig-web.json",
"extends": "./node_modules/@microsoft/rush-stack-compiler-3.7/includes/tsconfig-web.json",
"compilerOptions": {
"target": "es5",
"forceConsistentCasingInFileNames": true,
@ -19,20 +19,18 @@
"./node_modules/@microsoft"
],
"types": [
"es6-promise",
"webpack-env"
],
"lib": [
"es5",
"dom",
"es2015.collection"
"es2015.collection",
"es2015.promise"
]
},
"include": [
"src/**/*.ts"
"src/**/*.ts",
"src/**/*.tsx"
],
"exclude": [
"node_modules",
"lib"
]
"exclude": []
}

View File

@ -1,5 +1,5 @@
{
"extends": "@microsoft/sp-tslint-rules/base-tslint.json",
"extends": "./node_modules/@microsoft/sp-tslint-rules/base-tslint.json",
"rules": {
"class-name": false,
"export-name": false,