Skip to content

Commit 3b3a84f

Browse files
committed
Improve markdown rendering with a table of content.
1 parent 200be62 commit 3b3a84f

File tree

2 files changed

+180
-61
lines changed

2 files changed

+180
-61
lines changed

markdown/index.html

Lines changed: 163 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,59 @@
3737
white-space: nowrap;
3838
}
3939

40+
#table-of-contents {
41+
padding: 0;
42+
margin: 0;
43+
margin-left: 0.5em;
44+
45+
}
46+
47+
.tl1 {
48+
margin-left: 0em;
49+
font-size: 90%;
50+
}
51+
52+
.tl2 {
53+
margin-left: 0.5em;
54+
font-size: 85%;
55+
}
56+
57+
.tl3 {
58+
margin-left: 1.0em;
59+
font-size: 80%;
60+
}
61+
62+
.tl4 {
63+
margin-left: 1.5em;
64+
font-size: 75%;
65+
}
66+
67+
.tl5 {
68+
margin-left: 2.0em;
69+
font-size: 75%;
70+
}
71+
72+
.tl6 {
73+
margin-left: 2.5em;
74+
font-size: 75%;
75+
}
76+
77+
#toc {
78+
float: right;
79+
position: sticky;
80+
top: 0;
81+
margin-top: 1.5em;
82+
}
83+
84+
toc .sideitem {
85+
padding: 0.5em 0.5em;
86+
}
87+
88+
#toc h2 {
89+
margin-bottom: 0.5em;
90+
padding-bottom: 0.0em;
91+
}
92+
4093
/*]]>*/
4194
</style>
4295
</head>
@@ -56,19 +109,46 @@
56109
<script>
57110
//<![CDATA[
58111

59-
generate();
60-
61-
const targetElement = document.getElementById('markdown-target');
62-
const file = new URLSearchParams(window.location.search).get('file');
63-
const parts = /(?<org>[^/]+)\/(?<repo>[^/]+)\/(?<branch>[^/]+)\/(?<path>.*)/.exec(file);
64112
const repoNames = {
65113
"eclipse-platform/eclipse.platform": "Platform",
66114
"eclipse-platform/eclipse.platform.ui": "Platform UI",
115+
"eclipse-platform/www.eclipse.org-eclipse": "Eclipse Website",
67116
"eclipse-pde/eclipse.pde": "PDE",
68117
"eclipse-equinox/p2": "Equinox p2",
69118
"eclipse-ide/.github": "Eclipse IDE",
70119
};
71120

121+
const file = new URLSearchParams(window.location.search).get('file');
122+
const parts = /(?<org>[^/]+)\/(?<repo>[^/]+)\/(?<branch>[^/]+)\/(?<path>.*)/.exec(file);
123+
const org = parts == null ? '' : parts.groups.org;
124+
const repo = parts == null ? '' : parts.groups.repo;
125+
const branch = parts == null ? '' : parts.groups.branch;
126+
const path = parts == null ? '' : parts.groups.path;
127+
128+
const selfHosted = repo == 'www.eclipse.org-eclipse';
129+
const repoName = parts == null ? '' : repoNames[`${org}/${repo}`];
130+
131+
defaultAside = toElements(`${markdownAside}`);
132+
133+
if (parts != null && parts.groups.path.endsWith('.md')) {
134+
tableOfContentsAside = `
135+
<div id="toc" class="col-md-6">
136+
<aside
137+
<ul class="ul-left-nav">
138+
<div class="sideitem">
139+
<h2>Table of Contents</h2>
140+
<div id="toc-target">
141+
</div>
142+
</div>
143+
</ul>
144+
</aside>
145+
</div>`;
146+
}
147+
148+
generate();
149+
150+
const targetElement = document.getElementById('markdown-target');
151+
72152
function niceName(name) {
73153
return name.replaceAll(/[_-]/g, ' ').replaceAll(/([a-z])([A-Z])/g, '$1 $2').replace(/^([a-z])/, letter => letter.toLocaleUpperCase())
74154
}
@@ -101,20 +181,82 @@
101181
targetElement.innerHTML = heading + fileElements.join('');
102182
}
103183

184+
function generateMarkdown(logicalBaseURL, response) {
185+
if (response instanceof Array) {
186+
generateFileList(response)
187+
} else {
188+
const text = response;
189+
const editLink = `<a id="edit-markdown-link" href=""><span class="orange">\u270E Improve this page</span></a>\n`;
190+
marked.use(markedGfmHeadingId.gfmHeadingId());
191+
marked.use({
192+
hooks: {
193+
postprocess(html) {
194+
return `${html}`;
195+
}
196+
}
197+
});
198+
targetElement.innerHTML = editLink + marked.parse(text);
199+
200+
201+
const headings = markedGfmHeadingId.getHeadingList();
202+
const headingText = `
203+
<ul id="table-of-contents">
204+
${headings.map(({id, raw, level}) => `<li class="tl${level}"><a href="#${id}">${raw}</a></li>`).join(' ')}
205+
</ul>
206+
`;
207+
document.getElementById('toc-target').replaceChildren(...toElements(headingText));
208+
209+
const imgs = targetElement.querySelectorAll("img[src]");
210+
for (const img of imgs) {
211+
const src = img.getAttribute('src');
212+
if (!src.startsWith('http')) {
213+
img.src = `https://raw.githubusercontent.com/${org}/${repo}/${branch}/${src}`;
214+
}
215+
}
216+
217+
const as = targetElement.querySelectorAll("a[href]");
218+
for (const a of as) {
219+
const href = a.getAttribute('href');
220+
if (href == null) {
221+
continue;
222+
}
223+
224+
if (href.startsWith('#')) {
225+
a.setAttribute('href', fixHash(href));
226+
continue;
227+
}
228+
229+
const logicalHref = new URL(href, logicalBaseURL);
230+
const url = new URL(window.location);
231+
url.hash = fixHash(logicalHref.hash);
232+
if (logicalHref.hostname == 'api.github.com') {
233+
const parts = /\/repos\/(?<org>[^/]+)\/(?<repo>[^/]+)\/contents\/(?<path>.*)/.exec(logicalHref.pathname);
234+
if (parts != null) {
235+
url.search = `?file=${parts.groups.org}/${parts.groups.repo}/${branch}/${parts.groups.path}`;
236+
a.href = url;
237+
}
238+
} else if (logicalHref.hostname == 'github.com') {
239+
const parts = /(?<org>[^/]+)\/(?<repo>[^/]+)\/blob\/(?<branch>[^/]+)\/(?<path>.*)/.exec(logicalHref.pathname);
240+
if (parts != null) {
241+
url.search = `?file=${parts.groups.org}/${parts.groups.repo}/${parts.groups.branch}/${parts.groups.path}`;
242+
a.href = url;
243+
}
244+
}
245+
}
246+
247+
document.getElementById('edit-markdown-link').href = `https://github.com/${org}/${repo}/blob/${branch}/${path}`;
248+
}
249+
}
250+
251+
104252
if (parts == null || parts.length == 0) {
105253
targetElement.innerHTML = 'No well-formed query parameter of the form <code>?file=org/repo/branch/path</code> has been specified.';
106254
} else {
107-
const org = parts.groups.org;
108-
const repo = parts.groups.repo;
109-
const repoName = repoNames[`${org}/${repo}`];
110255
if (repoName == null) {
111256
targetElement.innerHTML = `The repository ${org}/${repo} is not on the allowed list.`;
112257
} else {
113258
document.title = `${repoName} Documentation | Eclipse Project`;
114259

115-
const branch = parts.groups.branch;
116-
const path = parts.groups.path;
117-
118260
const breadcrumb = document.querySelector(".breadcrumb");
119261
const normalizedPath = path.replace(/\/$/, '');
120262
const segments = normalizedPath == '' ? [''] : ['', ...normalizedPath.split('/')];
@@ -125,56 +267,17 @@
125267
}
126268

127269
const logicalBaseURL = new URL(`https://api.github.com/repos/${org}/${repo}/contents/${path}`);
128-
const mdLocation = `${logicalBaseURL}?ref=${branch}`;
129-
130-
sendRequest(mdLocation, request => {
131-
const response = JSON.parse(request.responseText);
132-
if (response instanceof Array) {
133-
generateFileList(response)
270+
fetch(selfHosted ? `${scriptBase}${path}` : `${logicalBaseURL}?ref=${branch}`).then(response => {
271+
console.log(response);
272+
return response.text();
273+
}).then(text => {
274+
if (text.startsWith('<')) {
275+
console.log('Unsupported');
276+
} else if (text.startsWith('{') || text.startsWith('[')) {
277+
const json = JSON.parse(text);
278+
generateMarkdown(logicalBaseURL, json instanceof Array ? json : blobToText(json.content));
134279
} else {
135-
const text = blobToText(response.content);
136-
const editLink = `<a id="edit-markdown-link" href=""><span class="orange">\u270E Improve this page</span></a>\n`;
137-
targetElement.innerHTML = editLink + marked.use(markedGfmHeadingId.gfmHeadingId()).parse(text);
138-
139-
const imgs = targetElement.querySelectorAll("img[src]");
140-
for (const img of imgs) {
141-
const src = img.getAttribute('src');
142-
if (!src.startsWith('http')) {
143-
img.src = `https://raw.githubusercontent.com/${org}/${repo}/${branch}/${src}`;
144-
}
145-
}
146-
147-
const as = targetElement.querySelectorAll("a[href]");
148-
for (const a of as) {
149-
const href = a.getAttribute('href');
150-
if (href == null) {
151-
continue;
152-
}
153-
154-
if (href.startsWith('#')) {
155-
a.setAttribute('href', fixHash(href));
156-
continue;
157-
}
158-
159-
const logicalHref = new URL(href, logicalBaseURL);
160-
const url = new URL(window.location);
161-
url.hash = fixHash(logicalHref.hash);
162-
if (logicalHref.hostname == 'api.github.com') {
163-
const parts = /\/repos\/(?<org>[^/]+)\/(?<repo>[^/]+)\/contents\/(?<path>.*)/.exec(logicalHref.pathname);
164-
if (parts != null) {
165-
url.search = `?file=${parts.groups.org}/${parts.groups.repo}/${branch}/${parts.groups.path}`;
166-
a.href = url;
167-
}
168-
} else if (logicalHref.hostname == 'github.com') {
169-
const parts = /(?<org>[^/]+)\/(?<repo>[^/]+)\/blob\/(?<branch>[^/]+)\/(?<path>.*)/.exec(logicalHref.pathname);
170-
if (parts != null) {
171-
url.search = `?file=${parts.groups.org}/${parts.groups.repo}/${parts.groups.branch}/${parts.groups.path}`;
172-
a.href = url;
173-
}
174-
}
175-
}
176-
177-
document.getElementById('edit-markdown-link').href = `https://github.com/${org}/${repo}/blob/${branch}/${path}`;
280+
generateMarkdown(logicalBaseURL, text);
178281
}
179282
});
180283
}

project.js

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,26 +49,41 @@ let defaultNav = toElements(`
4949
</a>
5050
`);
5151

52-
let defaultAside = toElements(`
52+
53+
let projectAside = `
5354
<a class="separator" href="https://projects.eclipse.org/projects/eclipse"><i class='fa fa-cube'></i> Eclipse Project</a>
5455
<a href="https://projects.eclipse.org/projects/eclipse.equinox">Equinox</a>
5556
<a href="https://projects.eclipse.org/projects/eclipse.platform">Platform</a>
5657
<a href="${scriptBase}swt/index.html">&nbsp;&nbsp;&bullet;&nbsp;SWT</a>
5758
<a href="https://projects.eclipse.org/projects/eclipse.jdt">Java Development Tools</a>
5859
<a href="https://projects.eclipse.org/projects/eclipse.pde">Plug-in Development Environment</a>
60+
`;
61+
62+
let githubAside = `
5963
<span class="separator"><i class='fa fa-github'></i> GitHub</span>
6064
<a href="https://github.com/eclipse-equinox/">Equinox</a>
6165
<a href="https://github.com/eclipse-platform/">Platform</a>
6266
<a href="https://github.com/eclipse-jdt/">Java Development Tools</a>
6367
<a href="https://github.com/eclipse-pde/">Plug-in Development Environment</a>
68+
`;
69+
70+
let markdownAside = `
6471
<span class="separator"><i class='fa fa-edit'></i> Markdown</span>
6572
<a href="${scriptBase}markdown/index.html?file=eclipse-platform/eclipse.platform/master/docs">Platform</a>
6673
<a href="${scriptBase}markdown/index.html?file=eclipse-platform/eclipse.platform.ui/master/docs">Platform UI</a>
6774
<a href="${scriptBase}markdown/index.html?file=eclipse-pde/eclipse.pde/master/docs">PDE</a>
6875
<a href="${scriptBase}markdown/index.html?file=eclipse-equinox/p2/master/docs">Equinox p2</a>
6976
<a href="${scriptBase}markdown/index.html?file=eclipse-ide/.github/main/">Eclipse IDE</a>
77+
`;
78+
79+
let defaultAside = toElements(`
80+
${projectAside}
81+
${githubAside}
82+
${markdownAside}
7083
`);
7184

85+
let tableOfContentsAside = '';
86+
7287
let selfContent = document.documentElement.outerHTML;
7388

7489
function generate() {
@@ -139,6 +154,7 @@ function generateBody() {
139154
</div>
140155
</div>
141156
${generateAside()}
157+
${tableOfContentsAside}
142158
</div>
143159
</div>
144160
</main>

0 commit comments

Comments
 (0)