ligarb 0.6.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/assets/feedback.css +123 -0
- data/assets/feedback.js +194 -0
- data/assets/serve.js +13 -1
- data/assets/style.css +96 -0
- data/lib/ligarb/builder.rb +104 -11
- data/lib/ligarb/chapter.rb +5 -3
- data/lib/ligarb/claude_runner.rb +2 -1
- data/lib/ligarb/cli.rb +11 -571
- data/lib/ligarb/config.rb +128 -2
- data/lib/ligarb/github_review.rb +245 -0
- data/lib/ligarb/review_store.rb +1 -0
- data/lib/ligarb/template.rb +87 -1
- data/lib/ligarb/version.rb +1 -1
- data/lib/ligarb/writer.rb +2 -2
- data/templates/book.html.erb +520 -10
- data/templates/github_review/.github/ISSUE_TEMPLATE/book-feedback.yml +43 -0
- data/templates/github_review/.github/ISSUE_TEMPLATE/config.yml +5 -0
- data/templates/github_review/.github/workflows/build-check.yml +25 -0
- data/templates/github_review/.github/workflows/claude-feedback.yml +128 -0
- data/templates/github_review/.github/workflows/claude-pr-mention.yml +121 -0
- data/templates/github_review/.github/workflows/deploy-book.yml +45 -0
- data/templates/github_review/SETUP.md +167 -0
- data/templates/github_review/SETUP.sh +49 -0
- metadata +13 -2
data/templates/book.html.erb
CHANGED
|
@@ -16,6 +16,11 @@
|
|
|
16
16
|
<%= custom_css %>
|
|
17
17
|
</style>
|
|
18
18
|
<%- end -%>
|
|
19
|
+
<%- if feedback -%>
|
|
20
|
+
<style>
|
|
21
|
+
<%= feedback[:css] %>
|
|
22
|
+
</style>
|
|
23
|
+
<%- end -%>
|
|
19
24
|
<%- if assets.need?(:highlight) -%>
|
|
20
25
|
<link rel="stylesheet" href="css/highlight.css">
|
|
21
26
|
<%- end -%>
|
|
@@ -28,34 +33,151 @@
|
|
|
28
33
|
<div class="sidebar" id="sidebar">
|
|
29
34
|
<div class="sidebar-header">
|
|
30
35
|
<div class="sidebar-header-top">
|
|
36
|
+
<%- if multilang -%>
|
|
37
|
+
<%- langs.each do |ld| -%>
|
|
38
|
+
<%- ld_cover = ld[:chapters].find(&:cover?) -%>
|
|
39
|
+
<%- if ld_cover -%>
|
|
40
|
+
<h1 class="book-title lang-content" data-lang="<%= ld[:lang] %>"><a href="#<%= ld_cover.slug %>" onclick="showChapter('<%= ld_cover.slug %>'); return false;"><%= h(ld[:title]) %></a></h1>
|
|
41
|
+
<%- else -%>
|
|
42
|
+
<h1 class="book-title lang-content" data-lang="<%= ld[:lang] %>"><%= h(ld[:title]) %></h1>
|
|
43
|
+
<%- end -%>
|
|
44
|
+
<%- end -%>
|
|
45
|
+
<%- else -%>
|
|
31
46
|
<%- cover_chapter = chapters.find(&:cover?) -%>
|
|
32
47
|
<%- if cover_chapter -%>
|
|
33
48
|
<h1 class="book-title"><a href="#<%= cover_chapter.slug %>" onclick="showChapter('<%= cover_chapter.slug %>'); return false;"><%= h(title) %></a></h1>
|
|
34
49
|
<%- else -%>
|
|
35
50
|
<h1 class="book-title"><%= h(title) %></h1>
|
|
36
51
|
<%- end -%>
|
|
52
|
+
<%- end -%>
|
|
37
53
|
<button class="theme-toggle" id="theme-toggle" aria-label="Toggle dark mode" title="Toggle dark mode">☾</button>
|
|
38
54
|
</div>
|
|
55
|
+
<%- if multilang -%>
|
|
56
|
+
<%- langs.each do |ld| -%>
|
|
57
|
+
<%- unless ld[:author].empty? -%>
|
|
58
|
+
<p class="book-author lang-content" data-lang="<%= ld[:lang] %>"><%= h(ld[:author]) %></p>
|
|
59
|
+
<%- end -%>
|
|
60
|
+
<%- end -%>
|
|
61
|
+
<%- else -%>
|
|
39
62
|
<%- unless author.empty? -%>
|
|
40
63
|
<p class="book-author"><%= h(author) %></p>
|
|
41
64
|
<%- end -%>
|
|
65
|
+
<%- end -%>
|
|
66
|
+
<%- if multilang -%>
|
|
67
|
+
<%- if ai_generated -%>
|
|
68
|
+
<%- langs.each do |ld| -%>
|
|
69
|
+
<span class="ai-badge lang-content" data-lang="<%= ld[:lang] %>"><%= ld[:language] == 'ja' ? 'AI 生成' : 'AI Generated' %></span>
|
|
70
|
+
<%- end -%>
|
|
71
|
+
<%- end -%>
|
|
72
|
+
<%- else -%>
|
|
42
73
|
<%- if ai_generated -%>
|
|
43
74
|
<span class="ai-badge"><%= language == 'ja' ? 'AI 生成' : 'AI Generated' %></span>
|
|
44
75
|
<%- end -%>
|
|
76
|
+
<%- end -%>
|
|
77
|
+
<%- if multilang -%>
|
|
78
|
+
<div class="lang-switcher">
|
|
79
|
+
<%- langs.each do |ld| -%>
|
|
80
|
+
<button class="lang-link" data-lang="<%= ld[:lang] %>" onclick="switchLang('<%= ld[:lang] %>')"><%= h(ld[:lang].upcase) %></button>
|
|
81
|
+
<%- end -%>
|
|
82
|
+
</div>
|
|
83
|
+
<%- end -%>
|
|
45
84
|
</div>
|
|
46
85
|
<div class="search-box">
|
|
47
86
|
<input type="text" id="toc-search" placeholder="Search..." autocomplete="off">
|
|
48
87
|
<button class="search-clear" id="search-clear" type="button" aria-label="Clear search">×</button>
|
|
49
88
|
</div>
|
|
50
89
|
<nav class="toc" id="toc">
|
|
90
|
+
<%- if multilang -%>
|
|
91
|
+
<%- langs.each do |ld| -%>
|
|
92
|
+
<ul class="lang-content" data-lang="<%= ld[:lang] %>">
|
|
93
|
+
<li class="toc-chapter" data-chapter="<%= ld[:lang] %>--__toc__">
|
|
94
|
+
<a href="#<%= ld[:lang] %>--__toc__" class="toc-h1" onclick="showChapter('<%= ld[:lang] %>--__toc__')"><%= ld[:language] == 'ja' ? '目次' : 'Contents' %></a>
|
|
95
|
+
</li>
|
|
96
|
+
<%- ld[:structure].each do |node| -%>
|
|
97
|
+
<%- case node.type -%>
|
|
98
|
+
<%- when :cover -%>
|
|
99
|
+
<%- when :chapter -%>
|
|
100
|
+
<li class="toc-chapter" data-chapter="<%= node.chapter.slug %>">
|
|
101
|
+
<a href="#<%= node.chapter.slug %>" class="toc-h1" onclick="showChapter('<%= node.chapter.slug %>')"><%= h(node.chapter.display_title) %></a>
|
|
102
|
+
<%- sub_headings = node.chapter.headings.select { |h| h.level == 2 } -%>
|
|
103
|
+
<%- unless sub_headings.empty? -%>
|
|
104
|
+
<ul>
|
|
105
|
+
<%- sub_headings.each do |heading| -%>
|
|
106
|
+
<li>
|
|
107
|
+
<a href="#<%= node.chapter.slug %>--<%= heading.id %>" class="toc-h<%= heading.level %>" onclick="showChapterAndScroll('<%= node.chapter.slug %>', '<%= node.chapter.slug %>--<%= heading.id %>')"><%= h(heading.display_text) %></a>
|
|
108
|
+
</li>
|
|
109
|
+
<%- end -%>
|
|
110
|
+
</ul>
|
|
111
|
+
<%- end -%>
|
|
112
|
+
</li>
|
|
113
|
+
<%- when :part -%>
|
|
114
|
+
<li class="toc-part">
|
|
115
|
+
<a href="#<%= node.chapter.slug %>" class="toc-part-title" onclick="showChapter('<%= node.chapter.slug %>')"><%= h(node.chapter.title) %></a>
|
|
116
|
+
<ul>
|
|
117
|
+
<%- (node.children || []).each do |child| -%>
|
|
118
|
+
<li class="toc-chapter" data-chapter="<%= child.chapter.slug %>">
|
|
119
|
+
<a href="#<%= child.chapter.slug %>" class="toc-h1" onclick="showChapter('<%= child.chapter.slug %>')"><%= h(child.chapter.display_title) %></a>
|
|
120
|
+
<%- sub_headings = child.chapter.headings.select { |h| h.level == 2 } -%>
|
|
121
|
+
<%- unless sub_headings.empty? -%>
|
|
122
|
+
<ul>
|
|
123
|
+
<%- sub_headings.each do |heading| -%>
|
|
124
|
+
<li>
|
|
125
|
+
<a href="#<%= child.chapter.slug %>--<%= heading.id %>" class="toc-h<%= heading.level %>" onclick="showChapterAndScroll('<%= child.chapter.slug %>', '<%= child.chapter.slug %>--<%= heading.id %>')"><%= h(heading.display_text) %></a>
|
|
126
|
+
</li>
|
|
127
|
+
<%- end -%>
|
|
128
|
+
</ul>
|
|
129
|
+
<%- end -%>
|
|
130
|
+
</li>
|
|
131
|
+
<%- end -%>
|
|
132
|
+
</ul>
|
|
133
|
+
</li>
|
|
134
|
+
<%- when :appendix_group -%>
|
|
135
|
+
<li class="toc-appendix">
|
|
136
|
+
<span class="toc-appendix-title"><%= h(ld[:appendix_label]) %></span>
|
|
137
|
+
<ul>
|
|
138
|
+
<%- (node.children || []).each do |child| -%>
|
|
139
|
+
<li class="toc-chapter" data-chapter="<%= child.chapter.slug %>">
|
|
140
|
+
<a href="#<%= child.chapter.slug %>" class="toc-h1" onclick="showChapter('<%= child.chapter.slug %>')"><%= h(child.chapter.display_title) %></a>
|
|
141
|
+
<%- sub_headings = child.chapter.headings.select { |h| h.level == 2 } -%>
|
|
142
|
+
<%- unless sub_headings.empty? -%>
|
|
143
|
+
<ul>
|
|
144
|
+
<%- sub_headings.each do |heading| -%>
|
|
145
|
+
<li>
|
|
146
|
+
<a href="#<%= child.chapter.slug %>--<%= heading.id %>" class="toc-h<%= heading.level %>" onclick="showChapterAndScroll('<%= child.chapter.slug %>', '<%= child.chapter.slug %>--<%= heading.id %>')"><%= h(heading.display_text) %></a>
|
|
147
|
+
</li>
|
|
148
|
+
<%- end -%>
|
|
149
|
+
</ul>
|
|
150
|
+
<%- end -%>
|
|
151
|
+
</li>
|
|
152
|
+
<%- end -%>
|
|
153
|
+
</ul>
|
|
154
|
+
</li>
|
|
155
|
+
<%- end -%>
|
|
156
|
+
<%- end -%>
|
|
157
|
+
<%- unless ld[:bibliography].empty? -%>
|
|
158
|
+
<li class="toc-chapter" data-chapter="<%= ld[:lang] %>--__bibliography__">
|
|
159
|
+
<a href="#<%= ld[:lang] %>--__bibliography__" class="toc-h1" onclick="showChapter('<%= ld[:lang] %>--__bibliography__')"><%= ld[:language] == 'ja' ? '参考文献' : 'Bibliography' %></a>
|
|
160
|
+
</li>
|
|
161
|
+
<%- end -%>
|
|
162
|
+
<%- unless ld[:index_tree].empty? -%>
|
|
163
|
+
<li class="toc-chapter" data-chapter="<%= ld[:lang] %>--__index__">
|
|
164
|
+
<a href="#<%= ld[:lang] %>--__index__" class="toc-h1" onclick="showChapter('<%= ld[:lang] %>--__index__')"><%= ld[:language] == 'ja' ? '索引' : 'Index' %></a>
|
|
165
|
+
</li>
|
|
166
|
+
<%- end -%>
|
|
167
|
+
</ul>
|
|
168
|
+
<%- end -%>
|
|
169
|
+
<%- else -%>
|
|
51
170
|
<ul>
|
|
171
|
+
<li class="toc-chapter" data-chapter="__toc__">
|
|
172
|
+
<a href="#__toc__" class="toc-h1" onclick="showChapter('__toc__')"><%= language == 'ja' ? '目次' : 'Contents' %></a>
|
|
173
|
+
</li>
|
|
52
174
|
<%- structure.each do |node| -%>
|
|
53
175
|
<%- case node.type -%>
|
|
54
176
|
<%- when :cover -%>
|
|
55
177
|
<%- when :chapter -%>
|
|
56
178
|
<li class="toc-chapter" data-chapter="<%= node.chapter.slug %>">
|
|
57
179
|
<a href="#<%= node.chapter.slug %>" class="toc-h1" onclick="showChapter('<%= node.chapter.slug %>')"><%= h(node.chapter.display_title) %></a>
|
|
58
|
-
<%- sub_headings = node.chapter.headings.select { |h| h.level
|
|
180
|
+
<%- sub_headings = node.chapter.headings.select { |h| h.level == 2 } -%>
|
|
59
181
|
<%- unless sub_headings.empty? -%>
|
|
60
182
|
<ul>
|
|
61
183
|
<%- sub_headings.each do |heading| -%>
|
|
@@ -73,7 +195,7 @@
|
|
|
73
195
|
<%- (node.children || []).each do |child| -%>
|
|
74
196
|
<li class="toc-chapter" data-chapter="<%= child.chapter.slug %>">
|
|
75
197
|
<a href="#<%= child.chapter.slug %>" class="toc-h1" onclick="showChapter('<%= child.chapter.slug %>')"><%= h(child.chapter.display_title) %></a>
|
|
76
|
-
<%- sub_headings = child.chapter.headings.select { |h| h.level
|
|
198
|
+
<%- sub_headings = child.chapter.headings.select { |h| h.level == 2 } -%>
|
|
77
199
|
<%- unless sub_headings.empty? -%>
|
|
78
200
|
<ul>
|
|
79
201
|
<%- sub_headings.each do |heading| -%>
|
|
@@ -94,7 +216,7 @@
|
|
|
94
216
|
<%- (node.children || []).each do |child| -%>
|
|
95
217
|
<li class="toc-chapter" data-chapter="<%= child.chapter.slug %>">
|
|
96
218
|
<a href="#<%= child.chapter.slug %>" class="toc-h1" onclick="showChapter('<%= child.chapter.slug %>')"><%= h(child.chapter.display_title) %></a>
|
|
97
|
-
<%- sub_headings = child.chapter.headings.select { |h| h.level
|
|
219
|
+
<%- sub_headings = child.chapter.headings.select { |h| h.level == 2 } -%>
|
|
98
220
|
<%- unless sub_headings.empty? -%>
|
|
99
221
|
<ul>
|
|
100
222
|
<%- sub_headings.each do |heading| -%>
|
|
@@ -121,14 +243,188 @@
|
|
|
121
243
|
</li>
|
|
122
244
|
<%- end -%>
|
|
123
245
|
</ul>
|
|
246
|
+
<%- end -%>
|
|
124
247
|
</nav>
|
|
125
248
|
</div>
|
|
126
249
|
|
|
127
250
|
<button class="sidebar-toggle" id="sidebar-toggle" aria-label="Toggle sidebar">☰</button>
|
|
128
251
|
|
|
129
252
|
<main class="content" id="content">
|
|
130
|
-
|
|
131
|
-
|
|
253
|
+
<%- if multilang -%>
|
|
254
|
+
<%- langs.each do |ld| -%>
|
|
255
|
+
<%- ld[:chapters].select(&:cover?).each do |chapter| -%>
|
|
256
|
+
<section class="chapter cover-page" id="chapter-<%= chapter.slug %>" data-lang="<%= ld[:lang] %>" style="display: none;">
|
|
257
|
+
<%= chapter.html %>
|
|
258
|
+
</section>
|
|
259
|
+
<%- end -%>
|
|
260
|
+
<section class="chapter toc-page" id="chapter-<%= ld[:lang] %>--__toc__" data-lang="<%= ld[:lang] %>" style="display: none;">
|
|
261
|
+
<h1><%= ld[:language] == 'ja' ? '目次' : 'Contents' %></h1>
|
|
262
|
+
<nav class="toc-full">
|
|
263
|
+
<%- ld[:structure].each do |node| -%>
|
|
264
|
+
<%- case node.type -%>
|
|
265
|
+
<%- when :cover -%>
|
|
266
|
+
<%- when :chapter -%>
|
|
267
|
+
<div class="toc-full-chapter">
|
|
268
|
+
<a href="#<%= node.chapter.slug %>" onclick="showChapter('<%= node.chapter.slug %>'); return false;"><%= h(node.chapter.display_title) %></a>
|
|
269
|
+
<%- sub = node.chapter.headings.select { |h| h.level >= 2 } -%>
|
|
270
|
+
<%- unless sub.empty? -%>
|
|
271
|
+
<ul><%- sub.each do |heading| -%>
|
|
272
|
+
<li class="toc-full-h<%= heading.level %>"><a href="#<%= node.chapter.slug %>--<%= heading.id %>" onclick="showChapterAndScroll('<%= node.chapter.slug %>', '<%= node.chapter.slug %>--<%= heading.id %>'); return false;"><%= h(heading.display_text) %></a></li>
|
|
273
|
+
<%- end -%></ul>
|
|
274
|
+
<%- end -%>
|
|
275
|
+
</div>
|
|
276
|
+
<%- when :part -%>
|
|
277
|
+
<div class="toc-full-part">
|
|
278
|
+
<a href="#<%= node.chapter.slug %>" onclick="showChapter('<%= node.chapter.slug %>'); return false;" class="toc-full-part-title"><%= h(node.chapter.title) %></a>
|
|
279
|
+
<%- (node.children || []).each do |child| -%>
|
|
280
|
+
<div class="toc-full-chapter">
|
|
281
|
+
<a href="#<%= child.chapter.slug %>" onclick="showChapter('<%= child.chapter.slug %>'); return false;"><%= h(child.chapter.display_title) %></a>
|
|
282
|
+
<%- sub = child.chapter.headings.select { |h| h.level >= 2 } -%>
|
|
283
|
+
<%- unless sub.empty? -%>
|
|
284
|
+
<ul><%- sub.each do |heading| -%>
|
|
285
|
+
<li class="toc-full-h<%= heading.level %>"><a href="#<%= child.chapter.slug %>--<%= heading.id %>" onclick="showChapterAndScroll('<%= child.chapter.slug %>', '<%= child.chapter.slug %>--<%= heading.id %>'); return false;"><%= h(heading.display_text) %></a></li>
|
|
286
|
+
<%- end -%></ul>
|
|
287
|
+
<%- end -%>
|
|
288
|
+
</div>
|
|
289
|
+
<%- end -%>
|
|
290
|
+
</div>
|
|
291
|
+
<%- when :appendix_group -%>
|
|
292
|
+
<div class="toc-full-part">
|
|
293
|
+
<span class="toc-full-part-title"><%= h(ld[:appendix_label]) %></span>
|
|
294
|
+
<%- (node.children || []).each do |child| -%>
|
|
295
|
+
<div class="toc-full-chapter">
|
|
296
|
+
<a href="#<%= child.chapter.slug %>" onclick="showChapter('<%= child.chapter.slug %>'); return false;"><%= h(child.chapter.display_title) %></a>
|
|
297
|
+
<%- sub = child.chapter.headings.select { |h| h.level >= 2 } -%>
|
|
298
|
+
<%- unless sub.empty? -%>
|
|
299
|
+
<ul><%- sub.each do |heading| -%>
|
|
300
|
+
<li class="toc-full-h<%= heading.level %>"><a href="#<%= child.chapter.slug %>--<%= heading.id %>" onclick="showChapterAndScroll('<%= child.chapter.slug %>', '<%= child.chapter.slug %>--<%= heading.id %>'); return false;"><%= h(heading.display_text) %></a></li>
|
|
301
|
+
<%- end -%></ul>
|
|
302
|
+
<%- end -%>
|
|
303
|
+
</div>
|
|
304
|
+
<%- end -%>
|
|
305
|
+
</div>
|
|
306
|
+
<%- end -%>
|
|
307
|
+
<%- end -%>
|
|
308
|
+
</nav>
|
|
309
|
+
</section>
|
|
310
|
+
<%- ld[:chapters].reject(&:cover?).each_with_index do |chapter, idx| -%>
|
|
311
|
+
<section class="chapter" id="chapter-<%= chapter.slug %>" data-lang="<%= ld[:lang] %>"<%= src_attrs(chapter, feedback) %> style="display: none;">
|
|
312
|
+
<%= chapter.html %>
|
|
313
|
+
<%- if ld[:repository] && !chapter.part_title? && !chapter.cover? -%>
|
|
314
|
+
<div class="edit-link">
|
|
315
|
+
<a href="<%= h(ld[:repository].chomp('/')) %>/blob/HEAD/<%= h(chapter.relative_path) %>" target="_blank" rel="noopener">View on GitHub</a>
|
|
316
|
+
</div>
|
|
317
|
+
<%- end -%>
|
|
318
|
+
<%- if ld[:footer] && !chapter.part_title? && !chapter.cover? -%>
|
|
319
|
+
<div class="chapter-footer"><%= h(ld[:footer]) %></div>
|
|
320
|
+
<%- end -%>
|
|
321
|
+
<%- unless chapter.cover? -%>
|
|
322
|
+
<nav class="chapter-nav">
|
|
323
|
+
<%- if idx > 0 -%>
|
|
324
|
+
<a href="#" class="nav-prev" onclick="showChapter('<%= ld[:chapters][idx-1].slug %>'); return false;">← <%= h(ld[:chapters][idx-1].display_title) %></a>
|
|
325
|
+
<%- else -%>
|
|
326
|
+
<span></span>
|
|
327
|
+
<%- end -%>
|
|
328
|
+
<%- if idx < ld[:chapters].size - 1 -%>
|
|
329
|
+
<a href="#" class="nav-next" onclick="showChapter('<%= ld[:chapters][idx+1].slug %>'); return false;"><%= h(ld[:chapters][idx+1].display_title) %> →</a>
|
|
330
|
+
<%- end -%>
|
|
331
|
+
</nav>
|
|
332
|
+
<%- end -%>
|
|
333
|
+
</section>
|
|
334
|
+
<%- end -%>
|
|
335
|
+
<%- unless ld[:bibliography].empty? -%>
|
|
336
|
+
<section class="chapter bibliography-chapter" id="chapter-<%= ld[:lang] %>--__bibliography__" data-lang="<%= ld[:lang] %>" style="display: none;">
|
|
337
|
+
<h1><%= ld[:language] == 'ja' ? '参考文献' : 'Bibliography' %></h1>
|
|
338
|
+
<ul class="bibliography-list">
|
|
339
|
+
<%- ld[:bibliography].each do |entry| -%>
|
|
340
|
+
<li id="<%= ld[:lang] %>--bib-<%= h(entry[:key]) %>"><span class="bib-label">[<%= h(entry[:label]) %>]</span> <%= entry[:formatted_html] %></li>
|
|
341
|
+
<%- end -%>
|
|
342
|
+
</ul>
|
|
343
|
+
</section>
|
|
344
|
+
<%- end -%>
|
|
345
|
+
<%- unless ld[:index_tree].empty? -%>
|
|
346
|
+
<section class="chapter index-chapter" id="chapter-<%= ld[:lang] %>--__index__" data-lang="<%= ld[:lang] %>" style="display: none;">
|
|
347
|
+
<h1><%= ld[:language] == 'ja' ? '索引' : 'Index' %></h1>
|
|
348
|
+
<%- ld[:index_tree].keys.sort.each do |letter| -%>
|
|
349
|
+
<div class="index-group">
|
|
350
|
+
<h2 class="index-letter"><%= letter %></h2>
|
|
351
|
+
<dl class="index-entries">
|
|
352
|
+
<%- ld[:index_tree][letter].each do |item| -%>
|
|
353
|
+
<dt><%= h(item[:term]) %></dt>
|
|
354
|
+
<%- item[:refs].each do |ref| -%>
|
|
355
|
+
<dd><a href="#<%= ref[:anchor_id] %>" onclick="showChapterAndScroll('<%= ref[:chapter_slug] %>', '<%= ref[:anchor_id] %>'); return false;"><%= ref[:chapter_title] %></a></dd>
|
|
356
|
+
<%- end -%>
|
|
357
|
+
<%- item[:children].each do |child| -%>
|
|
358
|
+
<dt class="index-sub"><%= h(child[:term]) %></dt>
|
|
359
|
+
<%- child[:refs].each do |ref| -%>
|
|
360
|
+
<dd class="index-sub"><a href="#<%= ref[:anchor_id] %>" onclick="showChapterAndScroll('<%= ref[:chapter_slug] %>', '<%= ref[:anchor_id] %>'); return false;"><%= ref[:chapter_title] %></a></dd>
|
|
361
|
+
<%- end -%>
|
|
362
|
+
<%- end -%>
|
|
363
|
+
<%- end -%>
|
|
364
|
+
</dl>
|
|
365
|
+
</div>
|
|
366
|
+
<%- end -%>
|
|
367
|
+
</section>
|
|
368
|
+
<%- end -%>
|
|
369
|
+
<%- end -%>
|
|
370
|
+
<%- else -%>
|
|
371
|
+
<%- chapters.select(&:cover?).each do |chapter| -%>
|
|
372
|
+
<section class="chapter cover-page" id="chapter-<%= chapter.slug %>" style="display: none;">
|
|
373
|
+
<%= chapter.html %>
|
|
374
|
+
</section>
|
|
375
|
+
<%- end -%>
|
|
376
|
+
<section class="chapter toc-page" id="chapter-__toc__" style="display: none;">
|
|
377
|
+
<h1><%= language == 'ja' ? '目次' : 'Contents' %></h1>
|
|
378
|
+
<nav class="toc-full">
|
|
379
|
+
<%- structure.each do |node| -%>
|
|
380
|
+
<%- case node.type -%>
|
|
381
|
+
<%- when :cover -%>
|
|
382
|
+
<%- when :chapter -%>
|
|
383
|
+
<div class="toc-full-chapter">
|
|
384
|
+
<a href="#<%= node.chapter.slug %>" onclick="showChapter('<%= node.chapter.slug %>'); return false;"><%= h(node.chapter.display_title) %></a>
|
|
385
|
+
<%- sub = node.chapter.headings.select { |h| h.level >= 2 } -%>
|
|
386
|
+
<%- unless sub.empty? -%>
|
|
387
|
+
<ul><%- sub.each do |heading| -%>
|
|
388
|
+
<li class="toc-full-h<%= heading.level %>"><a href="#<%= node.chapter.slug %>--<%= heading.id %>" onclick="showChapterAndScroll('<%= node.chapter.slug %>', '<%= node.chapter.slug %>--<%= heading.id %>'); return false;"><%= h(heading.display_text) %></a></li>
|
|
389
|
+
<%- end -%></ul>
|
|
390
|
+
<%- end -%>
|
|
391
|
+
</div>
|
|
392
|
+
<%- when :part -%>
|
|
393
|
+
<div class="toc-full-part">
|
|
394
|
+
<a href="#<%= node.chapter.slug %>" onclick="showChapter('<%= node.chapter.slug %>'); return false;" class="toc-full-part-title"><%= h(node.chapter.title) %></a>
|
|
395
|
+
<%- (node.children || []).each do |child| -%>
|
|
396
|
+
<div class="toc-full-chapter">
|
|
397
|
+
<a href="#<%= child.chapter.slug %>" onclick="showChapter('<%= child.chapter.slug %>'); return false;"><%= h(child.chapter.display_title) %></a>
|
|
398
|
+
<%- sub = child.chapter.headings.select { |h| h.level >= 2 } -%>
|
|
399
|
+
<%- unless sub.empty? -%>
|
|
400
|
+
<ul><%- sub.each do |heading| -%>
|
|
401
|
+
<li class="toc-full-h<%= heading.level %>"><a href="#<%= child.chapter.slug %>--<%= heading.id %>" onclick="showChapterAndScroll('<%= child.chapter.slug %>', '<%= child.chapter.slug %>--<%= heading.id %>'); return false;"><%= h(heading.display_text) %></a></li>
|
|
402
|
+
<%- end -%></ul>
|
|
403
|
+
<%- end -%>
|
|
404
|
+
</div>
|
|
405
|
+
<%- end -%>
|
|
406
|
+
</div>
|
|
407
|
+
<%- when :appendix_group -%>
|
|
408
|
+
<div class="toc-full-part">
|
|
409
|
+
<span class="toc-full-part-title"><%= h(appendix_label) %></span>
|
|
410
|
+
<%- (node.children || []).each do |child| -%>
|
|
411
|
+
<div class="toc-full-chapter">
|
|
412
|
+
<a href="#<%= child.chapter.slug %>" onclick="showChapter('<%= child.chapter.slug %>'); return false;"><%= h(child.chapter.display_title) %></a>
|
|
413
|
+
<%- sub = child.chapter.headings.select { |h| h.level >= 2 } -%>
|
|
414
|
+
<%- unless sub.empty? -%>
|
|
415
|
+
<ul><%- sub.each do |heading| -%>
|
|
416
|
+
<li class="toc-full-h<%= heading.level %>"><a href="#<%= child.chapter.slug %>--<%= heading.id %>" onclick="showChapterAndScroll('<%= child.chapter.slug %>', '<%= child.chapter.slug %>--<%= heading.id %>'); return false;"><%= h(heading.display_text) %></a></li>
|
|
417
|
+
<%- end -%></ul>
|
|
418
|
+
<%- end -%>
|
|
419
|
+
</div>
|
|
420
|
+
<%- end -%>
|
|
421
|
+
</div>
|
|
422
|
+
<%- end -%>
|
|
423
|
+
<%- end -%>
|
|
424
|
+
</nav>
|
|
425
|
+
</section>
|
|
426
|
+
<%- chapters.reject(&:cover?).each_with_index do |chapter, idx| -%>
|
|
427
|
+
<section class="chapter" id="chapter-<%= chapter.slug %>"<%= src_attrs(chapter, feedback) %> style="display: none;">
|
|
132
428
|
<%= chapter.html %>
|
|
133
429
|
<%- if repository && !chapter.part_title? && !chapter.cover? -%>
|
|
134
430
|
<div class="edit-link">
|
|
@@ -186,38 +482,182 @@
|
|
|
186
482
|
<%- end -%>
|
|
187
483
|
</section>
|
|
188
484
|
<%- end -%>
|
|
485
|
+
<%- end -%>
|
|
189
486
|
</main>
|
|
190
487
|
|
|
191
488
|
<script>
|
|
192
489
|
(function() {
|
|
193
|
-
|
|
490
|
+
<%- if multilang -%>
|
|
491
|
+
var langChapters = {
|
|
492
|
+
<%- langs.each do |ld| -%>
|
|
493
|
+
<%- ld_cover = ld[:chapters].find(&:cover?) -%>
|
|
494
|
+
"<%= ld[:lang] %>": [<%= "\"#{ld_cover.slug}\", " if ld_cover %>"<%= ld[:lang] %>--__toc__", <%= ld[:chapters].reject(&:cover?).map { |c| "\"#{c.slug}\"" }.join(", ") %><%= ", \"#{ld[:lang]}--__bibliography__\"" unless ld[:bibliography].empty? %><%= ", \"#{ld[:lang]}--__index__\"" unless ld[:index_tree].empty? %>],
|
|
495
|
+
<%- end -%>
|
|
496
|
+
};
|
|
497
|
+
var allLangs = [<%= langs.map { |ld| "\"#{ld[:lang]}\"" }.join(", ") %>];
|
|
498
|
+
var currentLang = localStorage.getItem('ligarb-lang') || allLangs[0];
|
|
499
|
+
if (allLangs.indexOf(currentLang) === -1) currentLang = allLangs[0];
|
|
500
|
+
var chapters = langChapters[currentLang];
|
|
501
|
+
<%- else -%>
|
|
502
|
+
<%- cover_ch = chapters.find(&:cover?) -%>
|
|
503
|
+
var chapters = [<%= "\"#{cover_ch.slug}\", " if cover_ch %>"__toc__", <%= chapters.reject(&:cover?).map { |c| "\"#{c.slug}\"" }.join(", ") %><%= ', "__bibliography__"' unless bibliography.empty? %><%= ', "__index__"' unless index_tree.empty? %>];
|
|
504
|
+
<%- end -%>
|
|
194
505
|
var currentChapter = null;
|
|
195
506
|
|
|
196
507
|
var navigating = false; // flag to suppress pushState during popstate/initial load
|
|
197
508
|
|
|
509
|
+
// Track the currently visible heading index and highlight TOC
|
|
510
|
+
var currentHeadingIndex = -1;
|
|
511
|
+
var headingObserver = null;
|
|
512
|
+
|
|
513
|
+
function setupHeadingObserver() {
|
|
514
|
+
if (headingObserver) headingObserver.disconnect();
|
|
515
|
+
if (!currentChapter) return;
|
|
516
|
+
var section = document.getElementById('chapter-' + currentChapter);
|
|
517
|
+
if (!section) return;
|
|
518
|
+
var headings = section.querySelectorAll('h1, h2, h3');
|
|
519
|
+
if (headings.length === 0) return;
|
|
520
|
+
|
|
521
|
+
headingObserver = new IntersectionObserver(function(entries) {
|
|
522
|
+
entries.forEach(function(entry) {
|
|
523
|
+
if (entry.isIntersecting) {
|
|
524
|
+
var idx = Array.prototype.indexOf.call(headings, entry.target);
|
|
525
|
+
if (idx !== -1) {
|
|
526
|
+
currentHeadingIndex = idx;
|
|
527
|
+
highlightTocHeading(entry.target);
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
});
|
|
531
|
+
}, { rootMargin: '0px 0px -70% 0px', threshold: 0 });
|
|
532
|
+
|
|
533
|
+
headings.forEach(function(h) { headingObserver.observe(h); });
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
function highlightTocHeading(heading) {
|
|
537
|
+
// Remove previous active-section highlights
|
|
538
|
+
document.querySelectorAll('.toc a.active-section').forEach(function(a) {
|
|
539
|
+
a.classList.remove('active-section');
|
|
540
|
+
});
|
|
541
|
+
// Find the TOC link matching this heading's ID
|
|
542
|
+
var hid = heading.id;
|
|
543
|
+
if (!hid) return;
|
|
544
|
+
var tocLink = document.querySelector('.toc a[href="#' + CSS.escape(hid) + '"]');
|
|
545
|
+
if (tocLink) tocLink.classList.add('active-section');
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
<%- if multilang -%>
|
|
549
|
+
|
|
550
|
+
function switchLang(lang) {
|
|
551
|
+
// Remember current position: chapter base slug and heading index
|
|
552
|
+
var oldLang = currentLang;
|
|
553
|
+
var targetSlug = null;
|
|
554
|
+
var targetHeadingIdx = currentHeadingIndex;
|
|
555
|
+
|
|
556
|
+
if (currentChapter) {
|
|
557
|
+
// Strip lang prefix to get the base slug (e.g. "ja--03-book-yml" → "03-book-yml")
|
|
558
|
+
var baseSlug = currentChapter.replace(new RegExp('^' + oldLang + '--'), '');
|
|
559
|
+
targetSlug = lang + '--' + baseSlug;
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
currentLang = lang;
|
|
563
|
+
chapters = langChapters[lang];
|
|
564
|
+
localStorage.setItem('ligarb-lang', lang);
|
|
565
|
+
|
|
566
|
+
// Toggle lang-content elements (TOC, header)
|
|
567
|
+
document.querySelectorAll('.lang-content').forEach(function(el) {
|
|
568
|
+
el.style.display = el.dataset.lang === lang ? '' : 'none';
|
|
569
|
+
});
|
|
570
|
+
|
|
571
|
+
// Toggle lang-switcher buttons
|
|
572
|
+
document.querySelectorAll('.lang-link').forEach(function(btn) {
|
|
573
|
+
if (btn.dataset.lang === lang) {
|
|
574
|
+
btn.classList.add('lang-current');
|
|
575
|
+
} else {
|
|
576
|
+
btn.classList.remove('lang-current');
|
|
577
|
+
}
|
|
578
|
+
});
|
|
579
|
+
|
|
580
|
+
// Hide all chapter sections, then show first of current lang
|
|
581
|
+
document.querySelectorAll('main .chapter').forEach(function(el) {
|
|
582
|
+
el.style.display = 'none';
|
|
583
|
+
});
|
|
584
|
+
|
|
585
|
+
// Reset search cache
|
|
586
|
+
chapterTextCache = null;
|
|
587
|
+
|
|
588
|
+
// Navigate to the corresponding chapter in the new language
|
|
589
|
+
if (targetSlug && chapters.indexOf(targetSlug) !== -1) {
|
|
590
|
+
showChapter(targetSlug);
|
|
591
|
+
// Scroll to the corresponding heading by index
|
|
592
|
+
if (targetHeadingIdx >= 0) {
|
|
593
|
+
setTimeout(function() {
|
|
594
|
+
var section = document.getElementById('chapter-' + targetSlug);
|
|
595
|
+
if (!section) return;
|
|
596
|
+
var headings = section.querySelectorAll('h1, h2, h3');
|
|
597
|
+
if (targetHeadingIdx < headings.length) {
|
|
598
|
+
headings[targetHeadingIdx].scrollIntoView({ behavior: 'smooth' });
|
|
599
|
+
}
|
|
600
|
+
}, 50);
|
|
601
|
+
}
|
|
602
|
+
} else {
|
|
603
|
+
showChapter(chapters[0]);
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
// Initialize lang display
|
|
608
|
+
function initLang() {
|
|
609
|
+
document.querySelectorAll('.lang-content').forEach(function(el) {
|
|
610
|
+
el.style.display = el.dataset.lang === currentLang ? '' : 'none';
|
|
611
|
+
});
|
|
612
|
+
document.querySelectorAll('.lang-link').forEach(function(btn) {
|
|
613
|
+
if (btn.dataset.lang === currentLang) btn.classList.add('lang-current');
|
|
614
|
+
});
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
window.switchLang = switchLang;
|
|
618
|
+
<%- end -%>
|
|
619
|
+
|
|
198
620
|
function showChapter(slug, hash) {
|
|
199
621
|
chapters.forEach(function(ch) {
|
|
200
622
|
var el = document.getElementById('chapter-' + ch);
|
|
201
623
|
if (el) el.style.display = (ch === slug) ? 'block' : 'none';
|
|
202
624
|
});
|
|
203
625
|
|
|
204
|
-
// Update active state in TOC
|
|
626
|
+
// Update active state in TOC and scroll sidebar to show active item
|
|
627
|
+
<%- if multilang -%>
|
|
628
|
+
var tocContainer = document.querySelector('.toc .lang-content[data-lang="' + currentLang + '"]');
|
|
629
|
+
var tocItems = tocContainer ? tocContainer.querySelectorAll('.toc-chapter') : [];
|
|
630
|
+
<%- else -%>
|
|
205
631
|
var tocItems = document.querySelectorAll('.toc-chapter');
|
|
632
|
+
<%- end -%>
|
|
633
|
+
var activeItem = null;
|
|
206
634
|
tocItems.forEach(function(item) {
|
|
207
635
|
if (item.dataset.chapter === slug) {
|
|
208
636
|
item.classList.add('active');
|
|
637
|
+
activeItem = item;
|
|
209
638
|
} else {
|
|
210
639
|
item.classList.remove('active');
|
|
211
640
|
}
|
|
212
641
|
});
|
|
642
|
+
if (activeItem) {
|
|
643
|
+
var tocNav = document.getElementById('toc');
|
|
644
|
+
var itemRect = activeItem.getBoundingClientRect();
|
|
645
|
+
var tocRect = tocNav.getBoundingClientRect();
|
|
646
|
+
if (itemRect.top < tocRect.top || itemRect.bottom > tocRect.bottom) {
|
|
647
|
+
activeItem.scrollIntoView({ block: 'center' });
|
|
648
|
+
}
|
|
649
|
+
}
|
|
213
650
|
|
|
214
651
|
currentChapter = slug;
|
|
652
|
+
currentHeadingIndex = -1;
|
|
215
653
|
var newHash = '#' + (hash || slug);
|
|
216
654
|
if (!navigating) {
|
|
217
655
|
history.pushState(null, '', newHash);
|
|
218
656
|
}
|
|
219
657
|
window.scrollTo(0, 0);
|
|
220
658
|
|
|
659
|
+
setupHeadingObserver();
|
|
660
|
+
|
|
221
661
|
// Re-apply highlight if search is active
|
|
222
662
|
if (searchInput && searchInput.value) {
|
|
223
663
|
highlightContent(searchInput.value);
|
|
@@ -232,7 +672,21 @@
|
|
|
232
672
|
if (!section) return;
|
|
233
673
|
if (typeof mermaid !== 'undefined') {
|
|
234
674
|
var unrendered = section.querySelectorAll('.mermaid:not([data-processed])');
|
|
235
|
-
if (unrendered.length > 0)
|
|
675
|
+
if (unrendered.length > 0) {
|
|
676
|
+
// Save original source for error recovery
|
|
677
|
+
var sources = {};
|
|
678
|
+
unrendered.forEach(function(el) { sources[el.id || el.textContent.slice(0, 50)] = el.textContent; });
|
|
679
|
+
mermaid.run({nodes: unrendered, suppressErrors: true}).catch(function() {}).finally(function() {
|
|
680
|
+
unrendered.forEach(function(el) {
|
|
681
|
+
// mermaid sets data-processed; if it's still text-only (no SVG), it failed
|
|
682
|
+
if (!el.querySelector('svg')) {
|
|
683
|
+
var src = sources[el.id || el.textContent.slice(0, 50)] || el.textContent;
|
|
684
|
+
el.innerHTML = '<pre style="color:#c00;border:1px solid #c00;padding:0.5em;white-space:pre-wrap">mermaid error:\n' +
|
|
685
|
+
src.replace(/</g, '<') + '</pre>';
|
|
686
|
+
}
|
|
687
|
+
});
|
|
688
|
+
});
|
|
689
|
+
}
|
|
236
690
|
}
|
|
237
691
|
if (typeof katex !== 'undefined') {
|
|
238
692
|
section.querySelectorAll('.math-block[data-math]').forEach(function(el) {
|
|
@@ -325,6 +779,7 @@
|
|
|
325
779
|
if (target) {
|
|
326
780
|
target.scrollIntoView({ behavior: 'smooth' });
|
|
327
781
|
highlightElement(target);
|
|
782
|
+
highlightTocHeading(target);
|
|
328
783
|
}
|
|
329
784
|
}, 50);
|
|
330
785
|
}
|
|
@@ -345,6 +800,14 @@
|
|
|
345
800
|
return;
|
|
346
801
|
}
|
|
347
802
|
|
|
803
|
+
<%- if multilang -%>
|
|
804
|
+
// In multilang mode, detect language from hash prefix (e.g., "en--cover")
|
|
805
|
+
var langMatch = hash.match(/^([a-z]{2})--/);
|
|
806
|
+
if (langMatch && allLangs.indexOf(langMatch[1]) !== -1 && langMatch[1] !== currentLang) {
|
|
807
|
+
switchLang(langMatch[1]);
|
|
808
|
+
}
|
|
809
|
+
<%- end -%>
|
|
810
|
+
|
|
348
811
|
// Check if hash matches a chapter slug directly
|
|
349
812
|
if (chapters.indexOf(hash) !== -1) {
|
|
350
813
|
showChapter(hash);
|
|
@@ -352,7 +815,20 @@
|
|
|
352
815
|
return;
|
|
353
816
|
}
|
|
354
817
|
|
|
355
|
-
|
|
818
|
+
<%- if multilang -%>
|
|
819
|
+
// Check for bibliography entry (bib-KEY)
|
|
820
|
+
var bibMatch = hash.match(/^(?:([a-z]{2})--)?bib-(.+)/);
|
|
821
|
+
if (bibMatch) {
|
|
822
|
+
var bibLang = bibMatch[1] || currentLang;
|
|
823
|
+
showChapter(bibLang + '--__bibliography__', hash);
|
|
824
|
+
setTimeout(function() {
|
|
825
|
+
var target = document.getElementById(hash);
|
|
826
|
+
if (target) target.scrollIntoView({ behavior: 'smooth' });
|
|
827
|
+
}, 50);
|
|
828
|
+
navigating = false;
|
|
829
|
+
return;
|
|
830
|
+
}
|
|
831
|
+
<%- elsif !bibliography.empty? -%>
|
|
356
832
|
// Check for bibliography entry (bib-KEY)
|
|
357
833
|
var bibMatch = hash.match(/^bib-(.+)/);
|
|
358
834
|
if (bibMatch) {
|
|
@@ -364,7 +840,7 @@
|
|
|
364
840
|
navigating = false;
|
|
365
841
|
return;
|
|
366
842
|
}
|
|
367
|
-
|
|
843
|
+
<%- end -%>
|
|
368
844
|
|
|
369
845
|
// Check for footnote links (fn: or fnref:)
|
|
370
846
|
var fnMatch = hash.match(/^(?:fn|fnref):(.+?)--/);
|
|
@@ -382,12 +858,31 @@
|
|
|
382
858
|
// Check for deep link (chapter--heading)
|
|
383
859
|
var parts = hash.split('--');
|
|
384
860
|
if (parts.length >= 2) {
|
|
861
|
+
<%- if multilang -%>
|
|
862
|
+
// In multilang, slug is "lang--chapter" so join first two parts
|
|
863
|
+
var chSlug = parts[0] + '--' + parts[1];
|
|
864
|
+
if (chapters.indexOf(chSlug) !== -1) {
|
|
865
|
+
showChapterAndScroll(chSlug, hash);
|
|
866
|
+
navigating = false;
|
|
867
|
+
return;
|
|
868
|
+
}
|
|
869
|
+
// Try 3 parts: "lang--chapter--heading" → chapter is "lang--chapter"
|
|
870
|
+
if (parts.length >= 3) {
|
|
871
|
+
chSlug = parts[0] + '--' + parts[1];
|
|
872
|
+
if (chapters.indexOf(chSlug) !== -1) {
|
|
873
|
+
showChapterAndScroll(chSlug, hash);
|
|
874
|
+
navigating = false;
|
|
875
|
+
return;
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
<%- else -%>
|
|
385
879
|
var chSlug = parts[0];
|
|
386
880
|
if (chapters.indexOf(chSlug) !== -1) {
|
|
387
881
|
showChapterAndScroll(chSlug, hash);
|
|
388
882
|
navigating = false;
|
|
389
883
|
return;
|
|
390
884
|
}
|
|
885
|
+
<%- end -%>
|
|
391
886
|
}
|
|
392
887
|
|
|
393
888
|
// Fallback
|
|
@@ -429,8 +924,14 @@
|
|
|
429
924
|
// Remove existing match count badges
|
|
430
925
|
document.querySelectorAll('.search-match-count').forEach(function(el) { el.remove(); });
|
|
431
926
|
|
|
927
|
+
<%- if multilang -%>
|
|
928
|
+
var tocContainer = document.querySelector('.toc .lang-content[data-lang="' + currentLang + '"]');
|
|
929
|
+
var items = tocContainer ? tocContainer.querySelectorAll('.toc-chapter') : [];
|
|
930
|
+
var partItems = tocContainer ? tocContainer.querySelectorAll('.toc-part, .toc-appendix') : [];
|
|
931
|
+
<%- else -%>
|
|
432
932
|
var items = document.querySelectorAll('.toc-chapter');
|
|
433
933
|
var partItems = document.querySelectorAll('.toc-part, .toc-appendix');
|
|
934
|
+
<%- end -%>
|
|
434
935
|
|
|
435
936
|
if (!query || query.length < 2) {
|
|
436
937
|
// Show all items when query is too short
|
|
@@ -597,6 +1098,9 @@
|
|
|
597
1098
|
window.renderSpecialBlocks = function() { if (currentChapter) renderSpecialBlocks(currentChapter); };
|
|
598
1099
|
|
|
599
1100
|
// Initialize (replace initial entry so first back goes to previous page, not same page)
|
|
1101
|
+
<%- if multilang -%>
|
|
1102
|
+
initLang();
|
|
1103
|
+
<%- end -%>
|
|
600
1104
|
navigating = true;
|
|
601
1105
|
handleHash();
|
|
602
1106
|
history.replaceState(null, '', location.hash || '#' + (chapters[0] || ''));
|
|
@@ -624,5 +1128,11 @@ renderSpecialBlocks();
|
|
|
624
1128
|
<script src="js/function-plot.min.js"></script>
|
|
625
1129
|
<script>renderSpecialBlocks();</script>
|
|
626
1130
|
<%- end -%>
|
|
1131
|
+
<%- if feedback -%>
|
|
1132
|
+
<script>window._ligarbReview = <%= feedback[:config_json] %>;</script>
|
|
1133
|
+
<script>
|
|
1134
|
+
<%= feedback[:js] %>
|
|
1135
|
+
</script>
|
|
1136
|
+
<%- end -%>
|
|
627
1137
|
</body>
|
|
628
1138
|
</html>
|