Skip to content

Commit 504f27d

Browse files
fix(blog): make changelog urls clickable (#254)
1 parent 3fa36bb commit 504f27d

File tree

2 files changed

+102
-13
lines changed

2 files changed

+102
-13
lines changed

_config_theme.yml

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -100,31 +100,43 @@ paginate: 5
100100
kramdown:
101101
input: GFM
102102

103+
# Common defaults using YAML anchors
104+
ALL_PAGES: &ALL_PAGES
105+
after-content:
106+
- donate.html
107+
footer-extra:
108+
- footer-extra.html
109+
ALL_POSTS: &ALL_POSTS
110+
comments: true # add comments to all blog posts
111+
social-share: true # add social media sharing buttons to all blog posts
112+
css:
113+
- "/assets/css/show-search.css"
114+
103115
# Default YAML values (more information on Jekyll's site)
104116
defaults:
105117
- scope:
106118
path: ""
107119
type: "posts"
108120
values:
109121
layout: "post"
110-
after-content:
111-
- donate.html
112-
footer-extra:
113-
- footer-extra.html
114-
comments: true # add comments to all blog posts
115-
social-share: true # add social media sharing buttons to all blog posts
116-
css:
117-
- "/assets/css/show-search.css"
122+
<<: *ALL_PAGES
123+
<<: *ALL_POSTS
124+
- scope:
125+
path: "_posts/releases"
126+
type: "posts"
127+
values:
128+
layout: "post"
129+
<<: *ALL_PAGES
130+
<<: *ALL_POSTS
131+
js:
132+
- "/assets/js/changelog-links.js"
118133
- scope:
119134
path: "" # any file that's not a post will be a "page" layout by default
120135
values:
121136
layout: "page"
122-
after-content:
123-
- donate.html
124-
footer-extra:
125-
- footer-extra.html
137+
<<: *ALL_PAGES
126138

127-
# Exclude these files from production site
139+
# Exclude these files from the production site
128140
exclude:
129141
- Dockerfile
130142
- Gemfile

assets/js/changelog-links.js

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/**
2+
* Convert Full Changelog URLs to clickable links in GitHub release notes
3+
*/
4+
(function() {
5+
'use strict';
6+
7+
function makeChangelogLinksClickable() {
8+
// Find all paragraphs that contain "Full Changelog" text and a GitHub compare URL
9+
const paragraphs = document.querySelectorAll('p');
10+
11+
// Loop through paragraphs in reverse order and break after the first match
12+
for (let i = paragraphs.length - 1; i >= 0; i--) {
13+
const paragraph = paragraphs[i];
14+
const text = paragraph.textContent || paragraph.innerText;
15+
16+
// Check if this paragraph contains "Full Changelog" and a GitHub compare URL
17+
if (
18+
text.includes('Full Changelog') &&
19+
text.includes('/compare/') &&
20+
text.includes('…')
21+
) {
22+
// Extract the URL from the text
23+
const urlMatch = text.match(/(https:\/\/github\.com\/\S+)/);
24+
25+
if (!urlMatch) {
26+
continue;
27+
}
28+
29+
const url = urlMatch[1];
30+
let parsedUrl;
31+
try {
32+
parsedUrl = new URL(url);
33+
} catch (e) {
34+
continue;
35+
}
36+
// Only allow https://github.com links with the expected pathname format
37+
// Pattern: /LizardByte/<repo-name>/compare/<version-a>…<version-b>
38+
const encodedEllipsis = encodeURI('…')
39+
const githubOrg = 'LizardByte'
40+
const pathPattern = new RegExp(`^\\/${githubOrg}\\/\\S+\\/compare\\/\\S+${encodedEllipsis}\\S+$`);
41+
if (
42+
parsedUrl.protocol !== 'https:' ||
43+
parsedUrl.hostname !== 'github.com' ||
44+
!pathPattern.test(parsedUrl.pathname)
45+
) {
46+
continue;
47+
}
48+
49+
// Safely replace the URL text in the paragraph with a clickable link
50+
const urlIndex = text.indexOf(url);
51+
// Clear the paragraph contents
52+
paragraph.textContent = '';
53+
// Add text before the URL as a text node
54+
paragraph.appendChild(document.createTextNode(text.slice(0, urlIndex)));
55+
// Create the anchor element for the URL
56+
const link = document.createElement('a');
57+
link.href = parsedUrl.href;
58+
link.textContent = decodeURI(parsedUrl.href);
59+
link.target = '_blank';
60+
link.rel = 'noopener noreferrer';
61+
paragraph.appendChild(link);
62+
// Add text after the URL as a text node
63+
paragraph.appendChild(document.createTextNode(text.slice(urlIndex + url.length)));
64+
65+
// Break after first match
66+
break;
67+
}
68+
}
69+
}
70+
71+
// Run when DOM is ready
72+
if (document.readyState === 'loading') {
73+
document.addEventListener('DOMContentLoaded', makeChangelogLinksClickable);
74+
} else {
75+
makeChangelogLinksClickable();
76+
}
77+
})();

0 commit comments

Comments
 (0)