From 7e38f4fd1fcb9abf5a0c20d3fcc8943e8e7445a6 Mon Sep 17 00:00:00 2001 From: George Kalpakas Date: Wed, 15 Nov 2017 03:01:00 +0200 Subject: [PATCH] fix(aio): fix window title on Home page (#20440) Using `display: none` on the `

` causes `innerText` to not work as expected and include the icon ligature (`link`) in the title. This caused the window title on the angular.io Home page to appear as "Angular - link". This commit fixes it by not generating anchors at all for headings with the `no-anchor` class. Fixes #20427 PR Close #20440 --- aio/content/marketing/index.html | 2 +- aio/e2e/app.e2e-spec.ts | 10 +++++ aio/e2e/app.po.ts | 1 + aio/package.json | 1 - .../doc-viewer/doc-viewer.component.spec.ts | 16 +++++++ .../layout/doc-viewer/doc-viewer.component.ts | 6 ++- .../post-processors/autolink-headings.js | 43 +++++++++++++++---- .../post-processors/autolink-headings.spec.js | 43 +++++++++++++------ aio/yarn.lock | 11 +---- 9 files changed, 98 insertions(+), 35 deletions(-) diff --git a/aio/content/marketing/index.html b/aio/content/marketing/index.html index 7516cad924..f735755868 100755 --- a/aio/content/marketing/index.html +++ b/aio/content/marketing/index.html @@ -25,7 +25,7 @@
-

+

diff --git a/aio/e2e/app.e2e-spec.ts b/aio/e2e/app.e2e-spec.ts index bf8d64e00e..f8e219fccd 100644 --- a/aio/e2e/app.e2e-spec.ts +++ b/aio/e2e/app.e2e-spec.ts @@ -15,6 +15,16 @@ describe('site App', function() { expect(page.getDocViewerText()).toMatch(/Progressive web apps/i); }); + it('should set appropriate window titles', () => { + expect(browser.getTitle()).toBe('Angular'); + + page.getTopMenuLink('features').click(); + expect(browser.getTitle()).toBe('Angular - FEATURES & BENEFITS'); + + page.homeLink.click(); + expect(browser.getTitle()).toBe('Angular'); + }); + it('should show the tutorial index page at `/tutorial/` after jitterbugging through features', () => { // check that we can navigate directly to the tutorial page page.navigateTo('tutorial/'); diff --git a/aio/e2e/app.po.ts b/aio/e2e/app.po.ts index ed62a3a568..7beb57d1ea 100644 --- a/aio/e2e/app.po.ts +++ b/aio/e2e/app.po.ts @@ -5,6 +5,7 @@ const githubRegex = /https:\/\/github.com\/angular\/angular\//; export class SitePage { links = element.all(by.css('md-toolbar a')); + homeLink = element(by.css('a.home')); docsMenuLink = element(by.cssContainingText('aio-top-menu a', 'Docs')); docViewer = element(by.css('aio-doc-viewer')); codeExample = element.all(by.css('aio-doc-viewer pre > code')); diff --git a/aio/package.json b/aio/package.json index e7be7549ea..1c09b5b010 100644 --- a/aio/package.json +++ b/aio/package.json @@ -126,7 +126,6 @@ "lunr": "^2.1.0", "protractor": "^5.2.0", "rehype": "^4.0.0", - "rehype-autolink-headings": "^2.0.0", "rehype-slug": "^2.0.0", "remark": "^7.0.0", "remark-html": "^6.0.0", 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 57484e9474..1ab9eb630a 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 @@ -361,6 +361,22 @@ describe('DocViewerComponent', () => { fixture.detectChanges(); expect(titleService.setTitle).toHaveBeenCalledWith('Angular - Text Content'); }); + + it('should still use `innerText` if available but empty', () => { + const querySelector_ = docViewerEl.querySelector; + spyOn(docViewerEl, 'querySelector').and.callFake((selector: string) => { + const elem = querySelector_.call(docViewerEl, selector); + Object.defineProperties(elem, { + innerText: { value: '' }, + textContent: { value: 'Text Content' } + }); + return elem; + }); + + setCurrentDoc('

link

Some content'); + fixture.detectChanges(); + expect(titleService.setTitle).toHaveBeenCalledWith('Angular'); + }); }); describe('TOC', () => { 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 1687f8734c..5808d2a45d 100644 --- a/aio/src/app/layout/doc-viewer/doc-viewer.component.ts +++ b/aio/src/app/layout/doc-viewer/doc-viewer.component.ts @@ -92,17 +92,19 @@ export class DocViewerComponent implements DoCheck, OnDestroy { private addTitleAndToc(docId: string) { this.tocService.reset(); - let title = ''; const titleEl = this.hostElement.querySelector('h1'); + let title = ''; + // Only create TOC for docs with an

title // If you don't want a TOC, add "no-toc" class to

if (titleEl) { - title = (titleEl.innerText || titleEl.textContent).trim(); + title = (typeof titleEl.innerText === 'string') ? titleEl.innerText : titleEl.textContent; if (!/(no-toc|notoc)/i.test(titleEl.className)) { this.tocService.genToc(this.hostElement, docId); titleEl.insertAdjacentHTML('afterend', ''); } } + this.titleService.setTitle(title ? `Angular - ${title}` : 'Angular'); } diff --git a/aio/tools/transforms/angular-base-package/post-processors/autolink-headings.js b/aio/tools/transforms/angular-base-package/post-processors/autolink-headings.js index 5b9c353f78..7daa72623e 100644 --- a/aio/tools/transforms/angular-base-package/post-processors/autolink-headings.js +++ b/aio/tools/transforms/angular-base-package/post-processors/autolink-headings.js @@ -1,9 +1,34 @@ +const has = require('hast-util-has-property'); +const is = require('hast-util-is-element'); const slug = require('rehype-slug'); -const link = require('rehype-autolink-headings'); +const visit = require('unist-util-visit'); /** - * Get remark to inject anchors into headings + * Get remark to add IDs to headings and inject anchors into them. + * This is a stripped-down equivalent of [rehype-autolink-headings](https://github.com/wooorm/rehype-autolink-headings) + * that supports ignoring headings with the `no-anchor` class. */ +const HEADINGS = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6']; +const NO_ANCHOR_CLASS = 'no-anchor'; + +const clone = obj => JSON.parse(JSON.stringify(obj)); +const hasClass = (node, cls) => { + const className = node.properties.className; + return className && className.includes(cls); +}; + +const link = options => + tree => visit(tree, node => { + if (is(node, HEADINGS) && has(node, 'id') && !hasClass(node, NO_ANCHOR_CLASS)) { + node.children.unshift({ + type: 'element', + tagName: 'a', + properties: Object.assign(clone(options.properties), {href: `#${node.properties.id}`}), + children: clone(options.content) + }); + } + }); + module.exports = [ slug, [link, { @@ -12,11 +37,13 @@ module.exports = [ className: ['header-link'], 'aria-hidden': 'true' }, - content: { - type: 'element', - tagName: 'i', - properties: {className: ['material-icons']}, - children: [{ type: 'text', value: 'link' }] - } + content: [ + { + type: 'element', + tagName: 'i', + properties: {className: ['material-icons']}, + children: [{ type: 'text', value: 'link' }] + } + ] }] ]; diff --git a/aio/tools/transforms/angular-base-package/post-processors/autolink-headings.spec.js b/aio/tools/transforms/angular-base-package/post-processors/autolink-headings.spec.js index 618da3a568..05ac0a8dc5 100644 --- a/aio/tools/transforms/angular-base-package/post-processors/autolink-headings.spec.js +++ b/aio/tools/transforms/angular-base-package/post-processors/autolink-headings.spec.js @@ -14,20 +14,37 @@ describe('autolink-headings postprocessor', () => { }); it('should add anchors to headings', () => { - const docs = [ { - docType: 'a', - renderedContent: ` -

Heading 1

-

Heading with bold

-

Heading with encoded chars &

- ` - }]; + const originalContent = ` +

Heading 1

+

Heading with bold

+

Heading with encoded chars &

+ `; + const processedContent = ` +

Heading 1

+

Heading with bold

+

Heading with encoded chars &

+ `; + + const docs = [{docType: 'a', renderedContent: originalContent}]; processor.$process(docs); - expect(docs[0].renderedContent).toEqual(` -

Heading 1

-

Heading with bold

-

Heading with encoded chars &

- `); + expect(docs[0].renderedContent).toBe(processedContent); + }); + + it('should ignore headings with the `no-anchor` class', () => { + const originalContent = ` +

Heading 1

+

Heading with bold

+

Heading with encoded chars &

+ `; + const processedContent = ` +

Heading 1

+

Heading with bold

+

Heading with encoded chars &

+ `; + + const docs = [{docType: 'a', renderedContent: originalContent}]; + processor.$process(docs); + expect(docs[0].renderedContent).toBe(processedContent); }); }); diff --git a/aio/yarn.lock b/aio/yarn.lock index f28c52d8c7..cdeea17743 100644 --- a/aio/yarn.lock +++ b/aio/yarn.lock @@ -2977,7 +2977,7 @@ express@^4.13.3: utils-merge "1.0.1" vary "~1.1.2" -extend@3, extend@^3.0.0, extend@^3.0.1, extend@~3.0.0, extend@~3.0.1: +extend@3, extend@^3.0.0, extend@~3.0.0, extend@~3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444" @@ -6999,15 +6999,6 @@ regjsparser@^0.1.4: dependencies: jsesc "~0.5.0" -rehype-autolink-headings@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/rehype-autolink-headings/-/rehype-autolink-headings-2.0.2.tgz#48c7161b1a1020e942c758eb6b2c55cb1bc504d0" - dependencies: - extend "^3.0.1" - hast-util-has-property "^1.0.0" - hast-util-is-element "^1.0.0" - unist-util-visit "^1.1.0" - rehype-parse@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/rehype-parse/-/rehype-parse-3.1.0.tgz#7f5227a597a3f39fc4b938646161539c444ee728"