From 53b0fe814480e008df8aa2318f3648a8d8e26654 Mon Sep 17 00:00:00 2001 From: Pete Bacon Darwin Date: Sat, 3 Mar 2018 13:12:08 +0000 Subject: [PATCH] feat(aio): allow template to position embedded ToC (#22570) Previously the doc-viewer would insert an embedded `` element into the DOM directly after the H1 element. Now it will not do this if there is already a such element in the doc contents. This allows the content-author/template-developer to position the ToC for specific cases. PR Close #22570 --- .../doc-viewer/doc-viewer.component.spec.ts | 52 +++++++++++++------ .../layout/doc-viewer/doc-viewer.component.ts | 11 ++-- 2 files changed, 45 insertions(+), 18 deletions(-) diff --git a/aio/src/app/layout/doc-viewer/doc-viewer.component.spec.ts b/aio/src/app/layout/doc-viewer/doc-viewer.component.spec.ts index aa8d6eade0..182a8c5058 100644 --- a/aio/src/app/layout/doc-viewer/doc-viewer.component.spec.ts +++ b/aio/src/app/layout/doc-viewer/doc-viewer.component.spec.ts @@ -175,6 +175,9 @@ describe('DocViewerComponent', () => { const DOC_WITHOUT_H1 = 'Some content'; const DOC_WITH_H1 = '

Features

Some content'; const DOC_WITH_NO_TOC_H1 = '

Features

Some content'; + const DOC_WITH_EMBEDDED_TOC = '

Features

Some content'; + const DOC_WITH_EMBEDDED_TOC_WITHOUT_H1 = 'Some content'; + const DOC_WITH_EMBEDDED_TOC_WITH_NO_TOC_H1 = 'Some content'; const DOC_WITH_HIDDEN_H1_CONTENT = '

linkFeatures

Some content'; let titleService: MockTitle; let tocService: MockTocService; @@ -271,26 +274,45 @@ describe('DocViewerComponent', () => { }); describe('(ToC)', () => { - it('should add an embedded ToC element if there is an `

` heading', () => { - doPrepareTitleAndToc(DOC_WITH_H1); - const tocEl = getTocEl()!; + describe('needed', () => { + it('should add an embedded ToC element if there is an `

` heading', () => { + doPrepareTitleAndToc(DOC_WITH_H1); + const tocEl = getTocEl()!; - expect(tocEl).toBeTruthy(); - expect(tocEl.classList.contains('embedded')).toBe(true); + expect(tocEl).toBeTruthy(); + expect(tocEl.classList.contains('embedded')).toBe(true); + }); + + it('should not add a second ToC element if there a hard coded one in place', () => { + doPrepareTitleAndToc(DOC_WITH_EMBEDDED_TOC); + expect(targetEl.querySelectorAll('aio-toc').length).toEqual(1); + }); }); - it('should not add a ToC element if there is a `.no-toc` `

` heading', () => { - doPrepareTitleAndToc(DOC_WITH_NO_TOC_H1); - expect(getTocEl()).toBeFalsy(); + + describe('not needed', () => { + it('should not add a ToC element if there is a `.no-toc` `

` heading', () => { + doPrepareTitleAndToc(DOC_WITH_NO_TOC_H1); + expect(getTocEl()).toBeFalsy(); + }); + + it('should not add a ToC element if there is no `

` heading', () => { + doPrepareTitleAndToc(DOC_WITHOUT_H1); + expect(getTocEl()).toBeFalsy(); + + doPrepareTitleAndToc(EMPTY_DOC); + expect(getTocEl()).toBeFalsy(); + }); + + it('should remove ToC a hard coded one', () => { + doPrepareTitleAndToc(DOC_WITH_EMBEDDED_TOC_WITHOUT_H1); + expect(getTocEl()).toBeFalsy(); + + doPrepareTitleAndToc(DOC_WITH_EMBEDDED_TOC_WITH_NO_TOC_H1); + expect(getTocEl()).toBeFalsy(); + }); }); - it('should not add a ToC element if there is no `

` heading', () => { - doPrepareTitleAndToc(DOC_WITHOUT_H1); - expect(getTocEl()).toBeFalsy(); - - doPrepareTitleAndToc(EMPTY_DOC); - expect(getTocEl()).toBeFalsy(); - }); it('should generate ToC entries if there is an `

` heading', () => { doAddTitleAndToc(DOC_WITH_H1, 'foo'); diff --git a/aio/src/app/layout/doc-viewer/doc-viewer.component.ts b/aio/src/app/layout/doc-viewer/doc-viewer.component.ts index 7ead74d128..dce991eae3 100644 --- a/aio/src/app/layout/doc-viewer/doc-viewer.component.ts +++ b/aio/src/app/layout/doc-viewer/doc-viewer.component.ts @@ -112,10 +112,15 @@ export class DocViewerComponent implements DoCheck, OnDestroy { */ protected prepareTitleAndToc(targetElem: HTMLElement, docId: string): () => void { const titleEl = targetElem.querySelector('h1'); - const hasToc = !!titleEl && !/no-?toc/i.test(titleEl.className); + const needsToc = !!titleEl && !/no-?toc/i.test(titleEl.className); + const embeddedToc = targetElem.querySelector('aio-toc.embedded'); - if (hasToc) { + if (needsToc && !embeddedToc) { + // Add an embedded ToC if it's needed and there isn't one in the content already. titleEl!.insertAdjacentHTML('afterend', ''); + } else if (!needsToc && embeddedToc) { + // Remove the embedded Toc if it's there and not needed. + embeddedToc.remove(); } return () => { @@ -127,7 +132,7 @@ export class DocViewerComponent implements DoCheck, OnDestroy { if (titleEl) { title = (typeof titleEl.innerText === 'string') ? titleEl.innerText : titleEl.textContent; - if (hasToc) { + if (needsToc) { this.tocService.genToc(targetElem, docId); } }