From 9679ba3772d0a5e1b0cd96d78919aaef3a9d4e59 Mon Sep 17 00:00:00 2001 From: Jasey Waegebaert Date: Tue, 19 Jul 2022 20:44:34 +0200 Subject: [PATCH 1/3] Solve collapsible heading issues --- .../src/Service/SPService.ts | 104 ++++++++---------- 1 file changed, 48 insertions(+), 56 deletions(-) diff --git a/samples/react-page-navigator/src/Service/SPService.ts b/samples/react-page-navigator/src/Service/SPService.ts index c443bca8c..fc883f409 100644 --- a/samples/react-page-navigator/src/Service/SPService.ts +++ b/samples/react-page-navigator/src/Service/SPService.ts @@ -38,13 +38,38 @@ export class SPService { return anchorUrl; } + /** + * Nests a new nav link within the nav links tree + * @param currentLinks current nav links + * @param newLink the new nav link to be added to the structure + * @param order place order of the new link + * @param depth sequence depth + * @returns navLinks + */ + public static navLinkBuilder(currentLinks: INavLink[], newLink: INavLink, order: number, depth: number = 0): INavLink[] { + const lastIndex = currentLinks.length - 1; + + if (currentLinks[lastIndex].links.length === 0 || order === depth) { + if (depth === 0) { + currentLinks.push(newLink); + } else { + currentLinks[lastIndex].links.push(newLink); + } + } else { + depth++; + currentLinks[lastIndex].links.concat(this.navLinkBuilder(currentLinks[lastIndex].links, newLink, order, depth)); + } + + return currentLinks; + } + /** * Returns the Anchor Links for Nav element * @param context Web part context * @returns anchorLinks */ public static async GetAnchorLinks(context: WebPartContext) { - const anchorLinks: INavLink[] = []; + let anchorLinks: INavLink[] = []; try { /* Page ID on which the web part is added */ @@ -56,82 +81,49 @@ export class SPService { 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; - let subHeadingIndex = -1; - let prevHeadingOrder = 0; - this.allUrls = []; /* Traverse through all the Text web parts in the page */ canvasContent1JSON.map((webPart) => { - if (webPart.zoneGroupMetadata) { - const headingValue = webPart.zoneGroupMetadata.displayName; - const anchorUrl = this.GetAnchorUrl(headingValue); + if (webPart.zoneGroupMetadata && webPart.zoneGroupMetadata.type === 1) { + const headingValue: string = webPart.zoneGroupMetadata.displayName; + const anchorUrl: string = this.GetAnchorUrl(headingValue); this.allUrls.push(anchorUrl); - /* Add link to Nav element */ - anchorLinks.push({ name: headingValue, key: anchorUrl, url: anchorUrl, links: [], isExpanded: webPart.zoneGroupMetadata.isExpanded }); + // Limitation! This will break with headings containing the same name + if (anchorLinks.filter(x => x.name === headingValue).length === 0) { + // Add link to nav element + anchorLinks.push({ name: headingValue, key: anchorUrl, url: anchorUrl, links: [], isExpanded: webPart.zoneGroupMetadata.isExpanded }); + } } if (webPart.innerHTML) { const HTMLString: string = webPart.innerHTML; + const hasCollapsableHeader: boolean = webPart.zoneGroupMetadata && + webPart.zoneGroupMetadata.type === 1 && + anchorLinks.filter(x => x.name === webPart.zoneGroupMetadata.displayName).length === 1; - const htmlObject = document.createElement('div'); + const htmlObject: HTMLDivElement = document.createElement('div'); htmlObject.innerHTML = HTMLString; - const headers = htmlObject.querySelectorAll('h1, h2, h3, h4'); + const headers: NodeListOf = htmlObject.querySelectorAll('h1, h2, h3, h4'); headers.forEach(header => { - const headingValue = header.textContent; - let headingOrder = parseInt(header.tagName.substring(1)); + const headingValue: string = header.textContent; + let headingOrder: number = parseInt(header.tagName.substring(1)); + // -2 because the text webpart heading 1 uses a h2 element + headingOrder -= 2; - if (webPart.zoneGroupMetadata) { + if (hasCollapsableHeader) { headingOrder++; } - const anchorUrl = this.GetAnchorUrl(headingValue); + const anchorUrl: string = this.GetAnchorUrl(headingValue); this.allUrls.push(anchorUrl); - /* Add links to Nav element */ - if (anchorLinks.length === 0) { - anchorLinks.push({ name: headingValue, key: anchorUrl, url: anchorUrl, links: [], isExpanded: true }); - } else { - if (headingOrder <= prevHeadingOrder) { - /* Adding or Promoting links */ - 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 = 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 = anchorLinks[headingIndex].links.length - 1; - } else { - 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; + // Add link to nav element + const newNavLink: INavLink = { name: headingValue, key: anchorUrl, url: anchorUrl, links: [], isExpanded: true }; + anchorLinks = this.navLinkBuilder(anchorLinks, newNavLink, headingOrder, hasCollapsableHeader ? 1 : 0); }); } }); From f0cf95dc3ece3f897ca5e83cb92414f1b6f31710 Mon Sep 17 00:00:00 2001 From: Jasey Waegebaert Date: Tue, 19 Jul 2022 20:57:02 +0200 Subject: [PATCH 2/3] Solve collapsible sections without a name --- samples/react-page-navigator/src/Service/SPService.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/samples/react-page-navigator/src/Service/SPService.ts b/samples/react-page-navigator/src/Service/SPService.ts index fc883f409..a1d6847f6 100644 --- a/samples/react-page-navigator/src/Service/SPService.ts +++ b/samples/react-page-navigator/src/Service/SPService.ts @@ -86,14 +86,15 @@ export class SPService { /* Traverse through all the Text web parts in the page */ canvasContent1JSON.map((webPart) => { if (webPart.zoneGroupMetadata && webPart.zoneGroupMetadata.type === 1) { - const headingValue: string = webPart.zoneGroupMetadata.displayName; + const headingIsEmpty: boolean = webPart.zoneGroupMetadata.displayName === ''; + const headingValue: string = headingIsEmpty ? 'Empty Heading' : webPart.zoneGroupMetadata.displayName ; const anchorUrl: string = this.GetAnchorUrl(headingValue); this.allUrls.push(anchorUrl); // Limitation! This will break with headings containing the same name if (anchorLinks.filter(x => x.name === headingValue).length === 0) { // Add link to nav element - anchorLinks.push({ name: headingValue, key: anchorUrl, url: anchorUrl, links: [], isExpanded: webPart.zoneGroupMetadata.isExpanded }); + anchorLinks.push({ name: headingValue, key: anchorUrl, url: !headingIsEmpty && anchorUrl, links: [], isExpanded: webPart.zoneGroupMetadata.isExpanded }); } } @@ -101,7 +102,8 @@ export class SPService { const HTMLString: string = webPart.innerHTML; const hasCollapsableHeader: boolean = webPart.zoneGroupMetadata && webPart.zoneGroupMetadata.type === 1 && - anchorLinks.filter(x => x.name === webPart.zoneGroupMetadata.displayName).length === 1; + ( anchorLinks.filter(x => x.name === webPart.zoneGroupMetadata.displayName).length === 1 || + webPart.zoneGroupMetadata.displayName === '' ); const htmlObject: HTMLDivElement = document.createElement('div'); htmlObject.innerHTML = HTMLString; From 8825a57c68ac4d5edfaa2029b7db3866fe30847a Mon Sep 17 00:00:00 2001 From: Hugo Bernier Date: Wed, 27 Jul 2022 23:47:24 -0400 Subject: [PATCH 3/3] Added readme and sample.json --- samples/react-page-navigator/README.md | 2 ++ samples/react-page-navigator/assets/sample.json | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/samples/react-page-navigator/README.md b/samples/react-page-navigator/README.md index a7db2ed9a..1886e65d3 100644 --- a/samples/react-page-navigator/README.md +++ b/samples/react-page-navigator/README.md @@ -28,6 +28,8 @@ Version|Date|Comments 1.2|May, 2022|SPFx Upgraded to 1.14.0 1.3|June 9, 2022|Updated React package from `^16.14.0` to `16.13.1` 1.4|June 29, 2022|Adds the capability to find collapsible section headers and insert them into the navigation +1.5|July 19, 2022|Bug fixes + ## Minimal Path to Awesome diff --git a/samples/react-page-navigator/assets/sample.json b/samples/react-page-navigator/assets/sample.json index d9efdbb88..9cf42a4a5 100644 --- a/samples/react-page-navigator/assets/sample.json +++ b/samples/react-page-navigator/assets/sample.json @@ -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": "2022-06-29", + "updateDateTime": "2022-07-19", "products": [ "SharePoint" ],