feat(aio): add GH-style anchor links to headings (#16161)
Closes #16126 PR Close #16161
This commit is contained in:
parent
1bfa7c6f14
commit
1e848d696b
|
@ -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",
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
|
@ -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';
|
|
@ -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) => {
|
||||||
|
|
|
@ -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', () => {
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -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"
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue