feat(aio): add GH-style anchor links to headings (#16161)

Closes #16126

PR Close #16161
This commit is contained in:
Peter Bacon Darwin 2017-04-19 16:03:15 +01:00 committed by Miško Hevery
parent 1bfa7c6f14
commit 1e848d696b
8 changed files with 94 additions and 7 deletions

View File

@ -81,7 +81,9 @@
"lodash": "^4.17.4", "lodash": "^4.17.4",
"protractor": "~5.1.0", "protractor": "~5.1.0",
"remark": "^7.0.0", "remark": "^7.0.0",
"remark-autolink-headings": "^4.0.0",
"remark-html": "^6.0.0", "remark-html": "^6.0.0",
"remark-slug": "^4.2.2",
"rho": "https://github.com/petebacondarwin/rho#master", "rho": "https://github.com/petebacondarwin/rho#master",
"rimraf": "^2.6.1", "rimraf": "^2.6.1",
"shelljs": "^0.7.7", "shelljs": "^0.7.7",

View File

@ -0,0 +1,42 @@
h1, h2, h3, h4, h5, h6 {
.icon-link {
color: $darkgray;
vertical-align: middle;
visibility: hidden;
margin: 8px;
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;
/* Support for all WebKit browsers. */
-webkit-font-smoothing: antialiased;
/* Support for Safari and Chrome. */
text-rendering: optimizeLegibility;
/* 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: -30px;
display: inline-block;
vertical-align: middle;
}
&:hover .icon-link {
visibility: visible
}
}

View File

@ -23,4 +23,5 @@
@import 'scrollbar'; @import 'scrollbar';
@import 'callout'; @import 'callout';
@import 'resources'; @import 'resources';
@import 'edit-page-cta'; @import 'edit-page-cta';
@import 'heading-anchors';

View File

@ -12,7 +12,7 @@ module.exports = function fixInternalDocumentLinks() {
return { return {
$runAfter: ['inlineTagProcessor'], $runAfter: ['inlineTagProcessor'],
$runBefore: ['writeFilesProcessor'], $runBefore: ['convertToJsonProcessor'],
$process: function(docs) { $process: function(docs) {
docs.forEach(doc => { docs.forEach(doc => {
doc.renderedContent = doc.renderedContent.replace(INTERNAL_LINK, (_, pre, hash) => { doc.renderedContent = doc.renderedContent.replace(INTERNAL_LINK, (_, pre, hash) => {

View File

@ -13,7 +13,7 @@ describe('fixInternalDocumentLinks processor', () => {
it('should run before the correct processor', () => { it('should run before the correct processor', () => {
const processor = processorFactory(); const processor = processorFactory();
expect(processor.$runBefore).toEqual(['writeFilesProcessor']); expect(processor.$runBefore).toEqual(['convertToJsonProcessor']);
}); });
it('should run after the correct processor', () => { it('should run after the correct processor', () => {

View File

@ -1,4 +1,6 @@
const remark = require('remark'); const remark = require('remark');
const slug = require('remark-slug');
const autolinkHeadings = require('remark-autolink-headings');
const html = require('remark-html'); const html = require('remark-html');
/** /**
@ -15,6 +17,8 @@ module.exports = function renderMarkdown() {
// .use(() => tree => { // .use(() => tree => {
// console.log(require('util').inspect(tree, { colors: true, depth: 4 })); // console.log(require('util').inspect(tree, { colors: true, depth: 4 }));
// }) // })
.use(slug)
.use(autolinkHeadings)
.use(html); .use(html);
return function renderMarkdownImpl(content) { return function renderMarkdownImpl(content) {

View File

@ -16,7 +16,7 @@ describe('remark: renderMarkdown service', () => {
const output = renderMarkdown(content); const output = renderMarkdown(content);
expect(output).toEqual( expect(output).toEqual(
'<h1>heading 1</h1>\n' + '<h1 id="heading-1"><a href="#heading-1" aria-hidden="true"><span class="icon icon-link"></span></a>heading 1</h1>\n' +
'<p>A paragraph with <strong>bold</strong> and <em>italic</em>.</p>\n' + '<p>A paragraph with <strong>bold</strong> and <em>italic</em>.</p>\n' +
'<ul>\n' + '<ul>\n' +
'<li>List item 1</li>\n' + '<li>List item 1</li>\n' +
@ -25,9 +25,9 @@ describe('remark: renderMarkdown service', () => {
}); });
it('should not process markdown inside inline tags', () => { it('should not process markdown inside inline tags', () => {
const content = '# heading {@link some_url_path}'; const content = '* list item {@link some_url_path}';
const output = renderMarkdown(content); const output = renderMarkdown(content);
expect(output).toEqual('<h1>heading {@link some_url_path}</h1>\n'); expect(output).toEqual('<ul>\n<li>list item {@link some_url_path}</li>\n</ul>\n');
}); });
it('should not put block level inline tags inside paragraphs', () => { it('should not put block level inline tags inside paragraphs', () => {
@ -67,4 +67,14 @@ describe('remark: renderMarkdown service', () => {
const output = renderMarkdown(content); const output = renderMarkdown(content);
expect(output).toEqual('<p>some text</p>\n<p> indented text</p>\n<p>other text</p>\n'); expect(output).toEqual('<p>some text</p>\n<p> indented text</p>\n<p>other text</p>\n');
}); });
it('should add id slugs and links to headings', () => {
const content = '# heading 1\n\nSome text\n\n## heading 2\n\nMore text';
const output = renderMarkdown(content);
expect(output).toEqual(
'<h1 id="heading-1"><a href="#heading-1" aria-hidden="true"><span class="icon icon-link"></span></a>heading 1</h1>\n' +
'<p>Some text</p>\n' +
'<h2 id="heading-2"><a href="#heading-2" aria-hidden="true"><span class="icon icon-link"></span></a>heading 2</h2>\n' +
'<p>More text</p>\n');
});
}); });

View File

@ -2024,6 +2024,10 @@ ember-cli-string-utils@^1.0.0:
version "1.1.0" version "1.1.0"
resolved "https://registry.yarnpkg.com/ember-cli-string-utils/-/ember-cli-string-utils-1.1.0.tgz#39b677fc2805f55173735376fcef278eaa4452a1" resolved "https://registry.yarnpkg.com/ember-cli-string-utils/-/ember-cli-string-utils-1.1.0.tgz#39b677fc2805f55173735376fcef278eaa4452a1"
emoji-regex@^6.0.0:
version "6.4.2"
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-6.4.2.tgz#a30b6fee353d406d96cfb9fa765bdc82897eff6e"
emojis-list@^2.0.0: emojis-list@^2.0.0:
version "2.1.0" version "2.1.0"
resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389" resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389"
@ -2766,6 +2770,12 @@ getpass@^0.1.1:
dependencies: dependencies:
assert-plus "^1.0.0" assert-plus "^1.0.0"
github-slugger@^1.0.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/github-slugger/-/github-slugger-1.1.1.tgz#5444671f65e5a5a424cfa8ba3255cc1f7baf07ea"
dependencies:
emoji-regex "^6.0.0"
gl-matrix@2.3.2: gl-matrix@2.3.2:
version "2.3.2" version "2.3.2"
resolved "https://registry.yarnpkg.com/gl-matrix/-/gl-matrix-2.3.2.tgz#aac808c74af7d5db05fe04cb60ca1a0fcb174d74" resolved "https://registry.yarnpkg.com/gl-matrix/-/gl-matrix-2.3.2.tgz#aac808c74af7d5db05fe04cb60ca1a0fcb174d74"
@ -4285,6 +4295,10 @@ mdast-util-to-hast@^2.1.1:
unist-util-visit "^1.1.0" unist-util-visit "^1.1.0"
xtend "^4.0.1" xtend "^4.0.1"
mdast-util-to-string@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/mdast-util-to-string/-/mdast-util-to-string-1.0.2.tgz#dc996a24d2b521178d3fac3993680c03a683e1dd"
media-typer@0.3.0: media-typer@0.3.0:
version "0.3.0" version "0.3.0"
resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
@ -5605,6 +5619,12 @@ relateurl@0.2.x:
version "0.2.7" version "0.2.7"
resolved "https://registry.yarnpkg.com/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9" resolved "https://registry.yarnpkg.com/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9"
remark-autolink-headings@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/remark-autolink-headings/-/remark-autolink-headings-4.0.0.tgz#1edabab6636e8cb26a36bf4c06caaec28355d3fc"
dependencies:
unist-util-visit "^1.0.1"
remark-html@^6.0.0: remark-html@^6.0.0:
version "6.0.0" version "6.0.0"
resolved "https://registry.yarnpkg.com/remark-html/-/remark-html-6.0.0.tgz#ade7d94b60e452158f28615218450682601dbfc1" resolved "https://registry.yarnpkg.com/remark-html/-/remark-html-6.0.0.tgz#ade7d94b60e452158f28615218450682601dbfc1"
@ -5635,6 +5655,14 @@ remark-parse@^3.0.0:
vfile-location "^2.0.0" vfile-location "^2.0.0"
xtend "^4.0.1" xtend "^4.0.1"
remark-slug@^4.2.2:
version "4.2.2"
resolved "https://registry.yarnpkg.com/remark-slug/-/remark-slug-4.2.2.tgz#3cfaa02e2e24d98405b296072f2ebbdfad279eb6"
dependencies:
github-slugger "^1.0.0"
mdast-util-to-string "^1.0.0"
unist-util-visit "^1.0.0"
remark-stringify@^3.0.0: remark-stringify@^3.0.0:
version "3.0.0" version "3.0.0"
resolved "https://registry.yarnpkg.com/remark-stringify/-/remark-stringify-3.0.0.tgz#f1720893a3e7c845824d95bb573d628d1346ba2a" resolved "https://registry.yarnpkg.com/remark-stringify/-/remark-stringify-3.0.0.tgz#f1720893a3e7c845824d95bb573d628d1346ba2a"
@ -6915,7 +6943,7 @@ unist-util-stringify-position@^1.0.0:
dependencies: dependencies:
has "^1.0.1" has "^1.0.1"
unist-util-visit@^1.0.0, unist-util-visit@^1.1.0: unist-util-visit@^1.0.0, unist-util-visit@^1.0.1, unist-util-visit@^1.1.0:
version "1.1.1" version "1.1.1"
resolved "https://registry.yarnpkg.com/unist-util-visit/-/unist-util-visit-1.1.1.tgz#e917a3b137658b335cb4420c7da2e74d928e4e94" resolved "https://registry.yarnpkg.com/unist-util-visit/-/unist-util-visit-1.1.1.tgz#e917a3b137658b335cb4420c7da2e74d928e4e94"