Repository navigation
fix(aio): improve heading-anchor placement #16336
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
719e07a
81c9784
84dc8e0
e5f23ae
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,42 +1,43 @@ | ||
| h1, h2, h3, h4, h5, h6 { | ||
| .icon-link { | ||
| color: $darkgray; | ||
| vertical-align: middle; | ||
| visibility: hidden; | ||
| margin: 8px; | ||
| .sidenav-content { | ||
| h1, h2, h3, h4, h5, h6 { | ||
|
|
||
| font: normal normal 24px 'Material Icons'; | ||
| display: inline-block; | ||
| line-height: 1; | ||
| text-transform: none; | ||
| letter-spacing: normal; | ||
| word-wrap: normal; | ||
| white-space: nowrap; | ||
| direction: ltr; | ||
| .mat-icon, .material-icons { | ||
| visibility: hidden; | ||
| display: inline-block; | ||
| color: $mediumgray; | ||
| margin: 0 8px; | ||
| } | ||
|
|
||
| /* Support for all WebKit browsers. */ | ||
| -webkit-font-smoothing: antialiased; | ||
| /* Support for Safari and Chrome. */ | ||
| text-rendering: optimizeLegibility; | ||
| &:hover { | ||
| .mat-icon, .material-icons { | ||
| visibility: visible; | ||
| } | ||
| } | ||
|
|
||
| /* Support for Firefox. */ | ||
| -moz-osx-font-smoothing: grayscale; | ||
|
|
||
| /* Support for IE. */ | ||
| font-feature-settings: 'liga'; | ||
|
|
||
| &:before { content: 'link'; } | ||
| a { | ||
| text-decoration: none; | ||
| padding-left: 8px; | ||
| margin-left: -50px; | ||
| display: inline-block; | ||
| vertical-align: middle; | ||
| } | ||
| } | ||
|
|
||
| a { | ||
| text-decoration: none; | ||
| padding-left: 8px; | ||
| margin-left: -50px; | ||
| display: inline-block; | ||
| vertical-align: middle; | ||
| .l-sub-section { | ||
| h1, h2, h3, h4, h5, h6 { | ||
| a { | ||
| padding-right: 24px; | ||
| margin-left: -74px; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| &:hover .icon-link { | ||
| visibility: visible | ||
| .alert { | ||
| h1, h2, h3, h4, h5, h6 { | ||
| a { | ||
| padding-right: 40px; | ||
| margin-left: -90px; | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| const slug = require('rehype-slug'); | ||
| const link = require('rehype-autolink-headings'); | ||
|
|
||
| /** | ||
| * Get remark to inject anchors into headings | ||
| */ | ||
| module.exports = [ | ||
| slug, | ||
| [link, { | ||
| properties: { | ||
| title: 'Link to this heading', | ||
| className: ['header-link'], | ||
| 'aria-hidden': 'true' | ||
| }, | ||
| content: { | ||
| type: 'element', | ||
| tagName: 'i', | ||
| properties: {className: ['material-icons']}, | ||
| children: [{ type: 'text', value: 'link' }] | ||
| } | ||
| }] | ||
| ]; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| const processorFactory = require('../../post-process-package/processors/post-process-html'); | ||
| const plugin = require('./autolink-headings'); | ||
|
|
||
| describe('autolink-headings postprocessor', () => { | ||
| let processor; | ||
|
|
||
| beforeEach(() => { | ||
| processor = processorFactory(); | ||
| processor.docTypes = ['a']; | ||
| processor.plugins = [plugin]; | ||
| }); | ||
|
|
||
| it('should add anchors to headings', () => { | ||
| const docs = [ { | ||
| docType: 'a', | ||
| renderedContent: ` | ||
| <h1>Heading 1</h2> | ||
| <h2>Heading with <strong>bold</strong></h2> | ||
| <h3>Heading with encoded chars &</h3> | ||
| ` | ||
| }]; | ||
| processor.$process(docs); | ||
| expect(docs[0].renderedContent).toEqual(` | ||
| <h1 id="heading-1"><a title="Link to this heading" class="header-link" aria-hidden="true" href="#heading-1"><i class="material-icons">link</i></a>Heading 1</h1> | ||
| <h2 id="heading-with-bold"><a title="Link to this heading" class="header-link" aria-hidden="true" href="#heading-with-bold"><i class="material-icons">link</i></a>Heading with <strong>bold</strong></h2> | ||
| <h3 id="heading-with-encoded-chars-"><a title="Link to this heading" class="header-link" aria-hidden="true" href="#heading-with-encoded-chars-"><i class="material-icons">link</i></a>Heading with encoded chars &</h3> | ||
| `); | ||
| }); | ||
| }); | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| var Package = require('dgeni').Package; | ||
| var base = require('dgeni-packages/base'); | ||
|
|
||
| module.exports = new Package('post-process-package', [base]) | ||
| .processor(require('./processors/post-process-html')); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| const rehype = require('rehype'); | ||
|
|
||
| /** | ||
| * @dgProcessor postProcessHtml | ||
| * | ||
| * @description | ||
| * Use the rehype processing engine to manipulate the | ||
| * `renderedContent` HTML via rehype "plugins" that work with HTML ASTs (HASTs). | ||
| * See https://github.com/wooorm/rehype | ||
| * | ||
| * Each plugin is a factory function that will be called with the "rehype" engine as `this`. | ||
| * The factory should return a function that takes a HAST and returns a `boolean` or `undefined`. | ||
| * The HAST can be mutated by the this function. | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the this --> the or this
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I still think you meant "The HAST can be mutated by this function
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh yeah :-) |
||
| * If `false` is returned then the processing stops with that plugin. | ||
| * | ||
| * @property docTypes {string[]} the `docTypes` of docs that should be post-processed | ||
| * @property plugins {Function[]} the rehype plugins that will modify the HAST. | ||
| * | ||
| */ | ||
| module.exports = function postProcessHtml() { | ||
| return { | ||
| $runAfter: ['docs-rendered'], | ||
| $runBefore: ['writing-files'], | ||
| docTypes: [], | ||
| plugins: [], | ||
| $process(docs) { | ||
| const engine = rehype() | ||
| .data('settings', { fragment: true }); | ||
| this.plugins.forEach(plugin => engine.use(plugin)); | ||
|
|
||
| docs | ||
| .filter(doc => this.docTypes.indexOf(doc.docType) !== -1) | ||
| .forEach(doc => | ||
| doc.renderedContent = engine.processSync(doc.renderedContent).contents); | ||
| } | ||
| }; | ||
| }; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,62 @@ | ||
| const testPackage = require('../../helpers/test-package'); | ||
| const Dgeni = require('dgeni'); | ||
|
|
||
| describe('postProcessHtml', function() { | ||
| let dgeni, injector, processor; | ||
|
|
||
| beforeEach(function() { | ||
| dgeni = new Dgeni([testPackage('post-process-package', true)]); | ||
| injector = dgeni.configureInjector(); | ||
| processor = injector.get('postProcessHtml'); | ||
| processor.docTypes = ['a', 'b']; | ||
| }); | ||
|
|
||
| it('should be available from the injector', () => { | ||
| expect(processor).toBeDefined(); | ||
| }); | ||
|
|
||
| it('should only process docs that match the specified docTypes', () => { | ||
| const elements = []; | ||
| const captureFirstElement = ast => { | ||
| elements.push(ast.children[0].tagName); | ||
| }; | ||
| processor.plugins = [() => captureFirstElement]; | ||
|
|
||
| const docs = [ | ||
| { docType: 'a', renderedContent: '<a></a>' }, | ||
| { docType: 'b', renderedContent: '<b></b>' }, | ||
| { docType: 'c', renderedContent: '<c></c>' }, | ||
| { docType: 'd', renderedContent: '<d></d>' }, | ||
| ]; | ||
| processor.$process(docs); | ||
| expect(elements).toEqual(['a', 'b']); | ||
| }); | ||
|
|
||
| it('should run all the plugins on each doc', () => { | ||
| const capitalizeFirstElement = ast => { | ||
| ast.children[0].tagName = ast.children[0].tagName.toUpperCase(); | ||
| }; | ||
| const addOneToFirstElement = ast => { | ||
| ast.children[0].tagName = ast.children[0].tagName + '1'; | ||
| }; | ||
| const elements = []; | ||
| const captureFirstElement = ast => { | ||
| elements.push(ast.children[0].tagName); | ||
| }; | ||
|
|
||
| const docs = [ | ||
| { docType: 'a', renderedContent: '<a></a>' }, | ||
| { docType: 'b', renderedContent: '<b></b>' }, | ||
| { docType: 'c', renderedContent: '<c></c>' }, | ||
| { docType: 'd', renderedContent: '<d></d>' }, | ||
| ]; | ||
|
|
||
| processor.plugins = [ | ||
| () => capitalizeFirstElement, | ||
| () => addOneToFirstElement, | ||
| () => captureFirstElement | ||
| ]; | ||
| processor.$process(docs); | ||
| expect(elements).toEqual(['A1', 'B1']); | ||
| }); | ||
| }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does @sjtrimble know you did this? 😁