feat(aio): allow template to position embedded ToC (#22570)
Previously the doc-viewer would insert an embedded `<aio-toc>` 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
This commit is contained in:
parent
2a1e3d191f
commit
53b0fe8144
|
@ -175,6 +175,9 @@ describe('DocViewerComponent', () => {
|
|||
const DOC_WITHOUT_H1 = 'Some content';
|
||||
const DOC_WITH_H1 = '<h1>Features</h1>Some content';
|
||||
const DOC_WITH_NO_TOC_H1 = '<h1 class="no-toc">Features</h1>Some content';
|
||||
const DOC_WITH_EMBEDDED_TOC = '<h1>Features</h1><aio-toc class="embedded"></aio-toc>Some content';
|
||||
const DOC_WITH_EMBEDDED_TOC_WITHOUT_H1 = '<aio-toc class="embedded"></aio-toc>Some content';
|
||||
const DOC_WITH_EMBEDDED_TOC_WITH_NO_TOC_H1 = '<aio-toc class="embedded"></aio-toc>Some content';
|
||||
const DOC_WITH_HIDDEN_H1_CONTENT = '<h1><i style="visibility: hidden">link</i>Features</h1>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 `<h1>` heading', () => {
|
||||
doPrepareTitleAndToc(DOC_WITH_H1);
|
||||
const tocEl = getTocEl()!;
|
||||
describe('needed', () => {
|
||||
it('should add an embedded ToC element if there is an `<h1>` 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` `<h1>` 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` `<h1>` heading', () => {
|
||||
doPrepareTitleAndToc(DOC_WITH_NO_TOC_H1);
|
||||
expect(getTocEl()).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should not add a ToC element if there is no `<h1>` 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 `<h1>` heading', () => {
|
||||
doPrepareTitleAndToc(DOC_WITHOUT_H1);
|
||||
expect(getTocEl()).toBeFalsy();
|
||||
|
||||
doPrepareTitleAndToc(EMPTY_DOC);
|
||||
expect(getTocEl()).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should generate ToC entries if there is an `<h1>` heading', () => {
|
||||
doAddTitleAndToc(DOC_WITH_H1, 'foo');
|
||||
|
|
|
@ -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', '<aio-toc class="embedded"></aio-toc>');
|
||||
} 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);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue