From 74f932fd0d71bfc5365edf47e5aa9dae271da4c0 Mon Sep 17 00:00:00 2001 From: Dante Soares Date: Tue, 2 Jul 2024 17:04:41 -0500 Subject: [PATCH 01/11] Set Rex heading levels for Assignable --- src/app/content/components/Assigned.tsx | 2 +- .../content/components/Page/PageComponent.tsx | 2 +- src/app/content/components/Page/connector.ts | 1 + .../Page/contentDOMTransformations.ts | 27 ++++++++++++++++--- 4 files changed, 27 insertions(+), 5 deletions(-) diff --git a/src/app/content/components/Assigned.tsx b/src/app/content/components/Assigned.tsx index 708e57e4d0..a803be3425 100644 --- a/src/app/content/components/Assigned.tsx +++ b/src/app/content/components/Assigned.tsx @@ -109,7 +109,7 @@ export default () => { - + {prevNext ? { contentLinks.reduceReferences(parsedContent, this.props.contentLinks); lazyResources.makeResourcesLazy(parsedContent); - transformContent(parsedContent, parsedContent.body, this.props.intl, services); + transformContent(parsedContent, parsedContent.body, this.props, services); if (this.props.lockNavigation) { linksToOtherPagesOpenInNewTab(parsedContent.body, this.props.currentPath); diff --git a/src/app/content/components/Page/connector.ts b/src/app/content/components/Page/connector.ts index 54165bb51b..30d39f86bf 100644 --- a/src/app/content/components/Page/connector.ts +++ b/src/app/content/components/Page/connector.ts @@ -34,6 +34,7 @@ export interface PagePropTypes { textSize: TextResizerValue; lockNavigation: boolean; ToastOverride: StyledComponent<'div', any, {}, never>; + topHeadingLevel?: number; } export default connect( diff --git a/src/app/content/components/Page/contentDOMTransformations.ts b/src/app/content/components/Page/contentDOMTransformations.ts index 8f1bf70ee4..e7cc949e95 100644 --- a/src/app/content/components/Page/contentDOMTransformations.ts +++ b/src/app/content/components/Page/contentDOMTransformations.ts @@ -21,15 +21,19 @@ export function linksToOtherPagesOpenInNewTab(rootEl: HTMLElement, currentPath: // .../src/scripts/modules/media/body/body.coffee#L123 // We are passing Document because it is required to prerender. export const transformContent = ( - document: Document, rootEl: HTMLElement, intl: IntlShape, services: AppServices & MiddlewareAPI + document: Document, + rootEl: HTMLElement, + props: { intl: IntlShape, topHeadingLevel?: number }, + services: AppServices & MiddlewareAPI ) => { removeDocumentTitle(rootEl); + if (props.topHeadingLevel) { changeHeadingLevels(rootEl, props.topHeadingLevel); } wrapElements(document, rootEl); tweakFigures(rootEl); fixLists(rootEl); - wrapSolutions(document, rootEl, intl); + wrapSolutions(document, rootEl, props.intl); expandSolutionForFragment(document); - moveFootnotes(document, rootEl, intl); + moveFootnotes(document, rootEl, props.intl); optimizeImages(rootEl, services); }; @@ -42,6 +46,23 @@ function removeDocumentTitle(rootEl: HTMLElement) { ].join(',')).forEach((el) => el.remove()); } +// Set the top heading's level to topHeadingLevel and make them all consecutive, based on contents +function changeHeadingLevels(rootEl: HTMLElement, topHeadingLevel: number) { + let currentLevel = topHeadingLevel; + + [ 1, 2, 3, 4, 5, 6 ].forEach((level) => { + const origTagName = `h${level}`; + const tags = rootEl.querySelectorAll(origTagName); + + if (tags.length > 0) { + const newTagName = `h${currentLevel}`; + tags.forEach((el) => el.outerHTML = el.outerHTML.replace(RegExp(`<${origTagName}`, 'g'), `<${newTagName}`) + .replace(RegExp(``, 'g'), ``)); + if (currentLevel < 6) { currentLevel += 1; } + } + }); +} + // Wrap title and content elements in header and section elements, respectively function wrapElements(document: Document, rootEl: HTMLElement) { rootEl.querySelectorAll(`.example, .exercise, .note, .abstract, From 9c79ef48cdb834502cbcf36f13d3122861da525b Mon Sep 17 00:00:00 2001 From: Beth Shook Date: Thu, 3 Oct 2024 21:01:47 -0500 Subject: [PATCH 02/11] replace old heading tags with new --- .../Page/contentDOMTransformations.ts | 37 ++++++++++++++----- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/src/app/content/components/Page/contentDOMTransformations.ts b/src/app/content/components/Page/contentDOMTransformations.ts index 7ea4c52b90..731ac82251 100644 --- a/src/app/content/components/Page/contentDOMTransformations.ts +++ b/src/app/content/components/Page/contentDOMTransformations.ts @@ -27,7 +27,7 @@ export const transformContent = ( services: AppServices & MiddlewareAPI ) => { removeDocumentTitle(rootEl); - if (props.topHeadingLevel) { changeHeadingLevels(rootEl, props.topHeadingLevel); } + if (props.topHeadingLevel) { changeHeadingLevels(document, rootEl, props.topHeadingLevel); } wrapElements(document, rootEl); tweakFigures(rootEl); fixLists(rootEl); @@ -47,20 +47,39 @@ function removeDocumentTitle(rootEl: HTMLElement) { } // Set the top heading's level to topHeadingLevel and make them all consecutive, based on contents -function changeHeadingLevels(rootEl: HTMLElement, topHeadingLevel: number) { - let currentLevel = topHeadingLevel; +function changeHeadingLevels(document: Document, rootEl: HTMLElement, topHeadingLevel: number) { + const headingLevels = [ 1, 2, 3, 4, 5, 6 ]; + const currentTopHeading = headingLevels.find((level) => rootEl.querySelectorAll(`h${level}`)?.length); - [ 1, 2, 3, 4, 5, 6 ].forEach((level) => { + if (!currentTopHeading || topHeadingLevel >= currentTopHeading) { + return; + } + + const differenceInLevels = topHeadingLevel - currentTopHeading; + + headingLevels.forEach((level) => { const origTagName = `h${level}`; const tags = rootEl.querySelectorAll(origTagName); if (tags.length > 0) { - const newTagName = `h${currentLevel}`; - tags.forEach((el) => el.outerHTML = el.outerHTML.replace(RegExp(`<${origTagName}`, 'g'), `<${newTagName}`) - .replace(RegExp(``, 'g'), ``)); - if (currentLevel < 6) { currentLevel += 1; } + const newTagName = `h${level + differenceInLevels}`; + + tags.forEach((tag) => { + const contents = tag.innerHTML; + const newTagEl = document.createElement(newTagName); + + Array.from(tag.attributes).forEach((attr) => { + newTagEl.setAttribute(attr.name, attr.value); + }); + + newTagEl.innerHTML = contents; + + tag.replaceWith(newTagEl); + }); } - }); + }) + + } // Wrap title and content elements in header and section elements, respectively From 0f79e7fce5b584eee6c4dec1f40eb310e6ce9202 Mon Sep 17 00:00:00 2001 From: Beth Shook Date: Thu, 3 Oct 2024 21:04:08 -0500 Subject: [PATCH 03/11] lint fix --- src/app/content/components/Page/contentDOMTransformations.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/app/content/components/Page/contentDOMTransformations.ts b/src/app/content/components/Page/contentDOMTransformations.ts index 731ac82251..fc60b40b99 100644 --- a/src/app/content/components/Page/contentDOMTransformations.ts +++ b/src/app/content/components/Page/contentDOMTransformations.ts @@ -77,9 +77,7 @@ function changeHeadingLevels(document: Document, rootEl: HTMLElement, topHeading tag.replaceWith(newTagEl); }); } - }) - - + }); } // Wrap title and content elements in header and section elements, respectively From 56e14738b96be5c0c75e547fda8c1962f39d2e1e Mon Sep 17 00:00:00 2001 From: Beth Shook Date: Fri, 4 Oct 2024 12:15:23 -0500 Subject: [PATCH 04/11] update comment --- src/app/content/components/Page/contentDOMTransformations.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/content/components/Page/contentDOMTransformations.ts b/src/app/content/components/Page/contentDOMTransformations.ts index fc60b40b99..a13a0251ec 100644 --- a/src/app/content/components/Page/contentDOMTransformations.ts +++ b/src/app/content/components/Page/contentDOMTransformations.ts @@ -46,7 +46,7 @@ function removeDocumentTitle(rootEl: HTMLElement) { ].join(',')).forEach((el) => el.remove()); } -// Set the top heading's level to topHeadingLevel and make them all consecutive, based on contents +// set the top heading's level to topHeadingLevel and adjust other headings accordingly function changeHeadingLevels(document: Document, rootEl: HTMLElement, topHeadingLevel: number) { const headingLevels = [ 1, 2, 3, 4, 5, 6 ]; const currentTopHeading = headingLevels.find((level) => rootEl.querySelectorAll(`h${level}`)?.length); From 49aa25ec2497b1af7144faa25e9711fcbf3e8d72 Mon Sep 17 00:00:00 2001 From: Beth Shook Date: Fri, 4 Oct 2024 13:35:01 -0500 Subject: [PATCH 05/11] allow heading levels to decrease --- src/app/content/components/Page/contentDOMTransformations.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/content/components/Page/contentDOMTransformations.ts b/src/app/content/components/Page/contentDOMTransformations.ts index a13a0251ec..bd2a8143be 100644 --- a/src/app/content/components/Page/contentDOMTransformations.ts +++ b/src/app/content/components/Page/contentDOMTransformations.ts @@ -51,7 +51,7 @@ function changeHeadingLevels(document: Document, rootEl: HTMLElement, topHeading const headingLevels = [ 1, 2, 3, 4, 5, 6 ]; const currentTopHeading = headingLevels.find((level) => rootEl.querySelectorAll(`h${level}`)?.length); - if (!currentTopHeading || topHeadingLevel >= currentTopHeading) { + if (!currentTopHeading || topHeadingLevel === currentTopHeading) { return; } From 08f8da3c029921b386d2d343d4f415624e2b4ae8 Mon Sep 17 00:00:00 2001 From: Beth Shook Date: Fri, 4 Oct 2024 13:39:09 -0500 Subject: [PATCH 06/11] undo change --- src/app/content/components/Page/contentDOMTransformations.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/content/components/Page/contentDOMTransformations.ts b/src/app/content/components/Page/contentDOMTransformations.ts index bd2a8143be..a13a0251ec 100644 --- a/src/app/content/components/Page/contentDOMTransformations.ts +++ b/src/app/content/components/Page/contentDOMTransformations.ts @@ -51,7 +51,7 @@ function changeHeadingLevels(document: Document, rootEl: HTMLElement, topHeading const headingLevels = [ 1, 2, 3, 4, 5, 6 ]; const currentTopHeading = headingLevels.find((level) => rootEl.querySelectorAll(`h${level}`)?.length); - if (!currentTopHeading || topHeadingLevel === currentTopHeading) { + if (!currentTopHeading || topHeadingLevel >= currentTopHeading) { return; } From bc77d79aa4ffbfd5265d7ea29114a1d3d9cd6b4f Mon Sep 17 00:00:00 2001 From: Beth Shook Date: Fri, 4 Oct 2024 14:02:13 -0500 Subject: [PATCH 07/11] being confused by numbers --- src/app/content/components/Page/contentDOMTransformations.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/content/components/Page/contentDOMTransformations.ts b/src/app/content/components/Page/contentDOMTransformations.ts index a13a0251ec..32e7ac171c 100644 --- a/src/app/content/components/Page/contentDOMTransformations.ts +++ b/src/app/content/components/Page/contentDOMTransformations.ts @@ -51,7 +51,7 @@ function changeHeadingLevels(document: Document, rootEl: HTMLElement, topHeading const headingLevels = [ 1, 2, 3, 4, 5, 6 ]; const currentTopHeading = headingLevels.find((level) => rootEl.querySelectorAll(`h${level}`)?.length); - if (!currentTopHeading || topHeadingLevel >= currentTopHeading) { + if (!currentTopHeading || topHeadingLevel <= currentTopHeading) { return; } From 45952ed7fa7d7c20ad71479fb71765da6404a1aa Mon Sep 17 00:00:00 2001 From: Beth Shook Date: Fri, 4 Oct 2024 14:26:24 -0500 Subject: [PATCH 08/11] lint fix --- src/app/content/components/Page/contentDOMTransformations.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/content/components/Page/contentDOMTransformations.ts b/src/app/content/components/Page/contentDOMTransformations.ts index 32e7ac171c..272acd373d 100644 --- a/src/app/content/components/Page/contentDOMTransformations.ts +++ b/src/app/content/components/Page/contentDOMTransformations.ts @@ -73,7 +73,7 @@ function changeHeadingLevels(document: Document, rootEl: HTMLElement, topHeading }); newTagEl.innerHTML = contents; - + tag.replaceWith(newTagEl); }); } From eae77ed4b21809e28769ccffda64f0e4731f64af Mon Sep 17 00:00:00 2001 From: Beth Shook Date: Mon, 7 Oct 2024 17:01:36 -0500 Subject: [PATCH 09/11] fix condition and add spec --- src/app/content/components/Page.spec.tsx | 43 ++++++++++++++++++- .../Page/contentDOMTransformations.ts | 2 +- 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/src/app/content/components/Page.spec.tsx b/src/app/content/components/Page.spec.tsx index 213a507521..edb657b10d 100644 --- a/src/app/content/components/Page.spec.tsx +++ b/src/app/content/components/Page.spec.tsx @@ -17,6 +17,7 @@ import { renderToDom } from '../../../test/reactutils'; import { makeSearchResultHit, makeSearchResults } from '../../../test/searchResults'; import AccessibilityButtonsWrapper from '../../components/AccessibilityButtonsWrapper'; import * as Services from '../../context/Services'; +import * as selectNavigation from '../../navigation/selectors'; import { scrollTo } from '../../domUtils'; import { locationChange, push } from '../../navigation/actions'; import { addToast } from '../../notifications/actions'; @@ -37,6 +38,7 @@ import { formatBookData } from '../utils'; import ConnectedPage, { PageComponent } from './Page'; import PageNotFound from './Page/PageNotFound'; import allImagesLoaded from './utils/allImagesLoaded'; +import Assigned from './Assigned'; jest.mock('./utils/allImagesLoaded', () => jest.fn()); jest.mock('../highlights/components/utils/showConfirmation', () => () => new Promise((resolve) => resolve(false))); @@ -157,6 +159,45 @@ describe('Page', () => { ); }; + describe('Content tweaks for assignable', () => { + let pageElement: HTMLElement; + + const htmlHelper = async(html: string) => { + archiveLoader.mock.cachedPage.mockImplementation(() => ({ + ...page, + content: html, + })); + + const {root} = renderToDom( + + + + + + ); + const query = root.querySelector('#main-content'); + + if (!query) { + return expect(query).toBeTruthy(); + } + pageElement = query; + + // page lifecycle hooks + await Promise.resolve(); + + return pageElement.innerHTML; + }; + + it('changes heading levels when specified', async() => { + jest.spyOn(selectNavigation, 'query').mockReturnValue({ + section: [page.id, shortPage.id], + }); + + expect(await htmlHelper('

1.1 A Section, Probably

')) + .toEqual('

1.1 A Section, Probably

') + }); + }); + describe('Content tweaks for generic styles', () => { let pageElement: HTMLElement; @@ -478,7 +519,7 @@ describe('Page', () => { '' + ''; expect(input).toEqual(expectedOutput); - }); + }); }); it('updates content link with new hrefs', async() => { diff --git a/src/app/content/components/Page/contentDOMTransformations.ts b/src/app/content/components/Page/contentDOMTransformations.ts index 272acd373d..7848f5e002 100644 --- a/src/app/content/components/Page/contentDOMTransformations.ts +++ b/src/app/content/components/Page/contentDOMTransformations.ts @@ -51,7 +51,7 @@ function changeHeadingLevels(document: Document, rootEl: HTMLElement, topHeading const headingLevels = [ 1, 2, 3, 4, 5, 6 ]; const currentTopHeading = headingLevels.find((level) => rootEl.querySelectorAll(`h${level}`)?.length); - if (!currentTopHeading || topHeadingLevel <= currentTopHeading) { + if (!currentTopHeading || topHeadingLevel === currentTopHeading) { return; } From 2e4cb67e81d00b1ff57673e83511f1cf4eb8a8cb Mon Sep 17 00:00:00 2001 From: Beth Shook Date: Tue, 8 Oct 2024 22:33:30 -0500 Subject: [PATCH 10/11] update spec --- src/app/content/components/Page.spec.tsx | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/app/content/components/Page.spec.tsx b/src/app/content/components/Page.spec.tsx index edb657b10d..d71fd709ca 100644 --- a/src/app/content/components/Page.spec.tsx +++ b/src/app/content/components/Page.spec.tsx @@ -38,7 +38,6 @@ import { formatBookData } from '../utils'; import ConnectedPage, { PageComponent } from './Page'; import PageNotFound from './Page/PageNotFound'; import allImagesLoaded from './utils/allImagesLoaded'; -import Assigned from './Assigned'; jest.mock('./utils/allImagesLoaded', () => jest.fn()); jest.mock('../highlights/components/utils/showConfirmation', () => () => new Promise((resolve) => resolve(false))); @@ -171,7 +170,11 @@ describe('Page', () => { const {root} = renderToDom( - + + + + + ); @@ -192,9 +195,11 @@ describe('Page', () => { jest.spyOn(selectNavigation, 'query').mockReturnValue({ section: [page.id, shortPage.id], }); + jest.spyOn(select, 'book') + .mockReturnValue(formatBookData(book, mockCmsBook)); - expect(await htmlHelper('

1.1 A Section, Probably

')) - .toEqual('

1.1 A Section, Probably

') + expect(await htmlHelper('

Largest heading

Second largest heading

')) + .toEqual('

Largest heading

Second largest heading

') }); }); From 382095a002d32074fe3b6031db31fbd9ce5cf44b Mon Sep 17 00:00:00 2001 From: Beth Shook Date: Tue, 8 Oct 2024 22:36:33 -0500 Subject: [PATCH 11/11] lint fix --- src/app/content/components/Page.spec.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/app/content/components/Page.spec.tsx b/src/app/content/components/Page.spec.tsx index 7db0a3fcec..4c8a407877 100644 --- a/src/app/content/components/Page.spec.tsx +++ b/src/app/content/components/Page.spec.tsx @@ -197,9 +197,9 @@ describe('Page', () => { }); jest.spyOn(select, 'book') .mockReturnValue(formatBookData(book, mockCmsBook)); - + expect(await htmlHelper('

Largest heading

Second largest heading

')) - .toEqual('

Largest heading

Second largest heading

') + .toEqual('

Largest heading

Second largest heading

'); }); }); @@ -571,7 +571,7 @@ describe('Page', () => { '' + ''; expect(input).toEqual(expectedOutput); - }); + }); }); it('updates content link with new hrefs', async() => {