Skip to content

Commit 4415d7d

Browse files
piti6claude
andcommitted
fix: address Copilot review feedback
- Escape @title in <title> tag to prevent XSS - Fix copyright using consistent @book.config source - Normalize currentPage for trailing slashes and directory URLs - Re-run search query after index finishes loading - Remove redundant bundle install step in CI (bundler-cache handles it) - Fix search index offset mismatch (slice from full html, not body) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 5a3a278 commit 4415d7d

3 files changed

Lines changed: 28 additions & 22 deletions

File tree

.github/workflows/deploy-web.yml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,6 @@ jobs:
3636
- name: Install npm dependencies
3737
run: npm install --ignore-scripts
3838

39-
- name: Install gem dependencies
40-
run: bundle install
41-
4239
- name: Build web pages (JP + EN)
4340
run: npm run web
4441

articles/layouts/layout-web.html.erb

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
<% if @next.present? %><link rel="next" title="<%= h(@next_title)%>" href="<%= h(@next.id.to_s+"."+@book.config['htmlext']) %>" /><% end %>
1818
<% if @prev.present? %><link rel="prev" title="<%= h(@prev_title)%>" href="<%= h(@prev.id.to_s+"."+@book.config['htmlext']) %>" /><% end %>
1919
<meta name="generator" content="Re:VIEW" />
20-
<title><%= @title %> | <%=h @book.config.name_of("booktitle")%></title>
20+
<title><%= h(@title) %> | <%=h @book.config.name_of("booktitle")%></title>
2121
</head>
2222
<body<%= @body_ext %>>
2323
<div class="book">
@@ -63,17 +63,27 @@
6363
</div>
6464
<footer>
6565
<% if @book.config["copyright"].present? %>
66-
<p class="copyright"><%=h @config["copyright"] %></p>
66+
<p class="copyright"><%=h @book.config["copyright"] %></p>
6767
<% end %>
6868
</footer>
6969
<script>
7070
(function() {
71-
var currentPage = location.pathname.split('/').pop().replace(/\.html$/, '');
71+
function normalizePage(value) {
72+
var page = (value || '').split('#')[0].split('?')[0];
73+
page = page.replace(/\.html$/, '');
74+
if (page === '' || page === '.' || page === './' || page.charAt(page.length - 1) === '/') {
75+
return 'index';
76+
}
77+
var last = page.split('/').pop();
78+
return (last === '' || last === '.' || last === 'index') ? 'index' : last;
79+
}
80+
81+
var currentPage = normalizePage(location.pathname);
7282
var tocItems = document.querySelectorAll('.book-toc > li');
7383
var headings = document.querySelectorAll('.book-page h2');
7484

7585
function matchPage(href) {
76-
return href.replace(/\.html$/, '') === currentPage;
86+
return normalizePage(href) === currentPage;
7787
}
7888

7989
// Fix TOP link to use relative directory path instead of index.html
@@ -138,15 +148,7 @@
138148
var resultsDiv = document.getElementById('search-results');
139149
var searchIndex = null;
140150

141-
input.addEventListener('focus', function() {
142-
if (searchIndex) return;
143-
fetch('search-index.json')
144-
.then(function(r) { return r.json(); })
145-
.then(function(data) { searchIndex = data; })
146-
.catch(function() { searchIndex = []; });
147-
});
148-
149-
input.addEventListener('input', function() {
151+
function runSearch() {
150152
var q = input.value.trim().toLowerCase();
151153
if (!q || !searchIndex) {
152154
resultsDiv.innerHTML = '';
@@ -172,8 +174,18 @@
172174
}).join('');
173175
}
174176
resultsDiv.style.display = 'block';
177+
}
178+
179+
input.addEventListener('focus', function() {
180+
if (searchIndex) return;
181+
fetch('search-index.json')
182+
.then(function(r) { return r.json(); })
183+
.then(function(data) { searchIndex = data; runSearch(); })
184+
.catch(function() { searchIndex = []; });
175185
});
176186

187+
input.addEventListener('input', runSearch);
188+
177189
// Close results on outside click
178190
document.addEventListener('click', function(e) {
179191
if (!e.target.closest('.search-box')) {

build-search-index.js

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,11 @@ htmlFiles.forEach(file => {
3636
const text = bodyMatch ? stripTags(bodyMatch[1]).slice(0, 500) : "";
3737
index.push({ file, title: pageTitle, id: "", text });
3838
} else {
39-
// Index each section
40-
const bodyMatch = html.match(/<div class="book-page">([\s\S]*)/);
41-
const body = bodyMatch ? bodyMatch[1] : html;
42-
39+
// Index each section — use positions from full html since headings were matched against it
4340
for (let i = 0; i < headings.length; i++) {
4441
const start = headings[i].pos;
45-
const end = i + 1 < headings.length ? headings[i + 1].pos : body.length;
46-
const sectionHtml = body.slice(start, end);
42+
const end = i + 1 < headings.length ? headings[i + 1].pos : html.length;
43+
const sectionHtml = html.slice(start, end);
4744
const text = stripTags(sectionHtml).slice(0, 500);
4845
sections.push({
4946
file,

0 commit comments

Comments
 (0)