Table of Content with Book-like Page Numbers
by denvdmj
HTML
<h1>Жемчужины программирования</h1>
<author>Джон Бентли</author>
<h2>Содержание</h2>
<ul class="toc">
<li page="15">Предисловие
<ul>
<li page="15">О книге</li>
<li page="16">Программы</li>
<li page="17">Читателям первого издания</li>
<li page="17">Благодарности к первому изданию</li>
<li page="18">Благодарности ко второму изданию</li>
<li page="18">От издательства</li>
</ul>
</li>
<li page="19">Часть 1. Предварительные сведения
<ul>
<li page="21">Глава 1. Как расколоть орешек
<ul>
<li page="21">1.1. Дружеский разговор</li>
<li page="22">1.2. Точная постановка задачи</li>
<li page="23">1.3. Разработка программы</li>
<li page="24">1.4. Набросок решения</li>
<li page="25">1.5. Основные принципы</li>
<li page="26">1.6. Задачи</li>
<li page="28">1.7. Дополнительная литература</li>
</ul>
</li>
<li page="29">Глава 2. Ага! Алгоритмы
<ul>
<li page="29">2.1. Три задачи</li>
<li page="30">2.2. Вездесущий двоичный поиск</li>
<li page="32">2.3. Мощь элементарного</li>
<li page="34">2.4. Соберем все вместе: сортировка</li>
<li page="35">2.5. Принципы
<ul>
<li page="35">Сортировка</li>
<li page="35">Двоичный поиск</li>
<li page="35">Сигнатуры</li>
<li page="84">Постановка задачи</li>
<li page="36">Перспективы для программиста</li>
</ul>
</li>
<li page="36">2.6. Задачи</li>
<li page="38">2.7. Дополнительная литература</li>
<li page="38">2.8. Реализация поиска анаграмм</li>
</ul>
</li>
<li page="41">Глава 3. Программы и структуры данных
<ul>
<li page="41">3.1. Программа обработки результатов опроса</li>
<li page="43">3.2. Обработка шаблонных писем</li>
<li page="45">3.3....
CSS
@import url('https://fonts.googleapis.com/css?family=Play|Roboto+Condensed');
:root {
font: 300 16px/1.3 "Roboto", sans-serif;
font-stretch: ultra-condensed;
text-align: left;
cursor: default;
}
body {
margin: auto;
padding: 1em 2em 4em 2em;
min-width: 18em;
max-width: 42em;
background: #fff;
}
h1, h2 {
font-family: Play, sans-serif;
font-weight: 400;
padding: 0;
margin: 2em 0 .5em -1px;
line-height: 1.3;
word-spacing: .1em;
letter-spacing: .15em;
color: #222;
clear: both;
}
body h1:first-child {
font-size: 190%;
margin: 1em 0 .5em -1px;
}
h1 {
border-bottom: 1px solid #ddd;
clear: both;
color: #000;
font-size: 230%;
letter-spacing: .1em;
margin: 0 0 .3em 0;
padding: 0 0 .3em 0;
}
h2 {
font-size: 170%;
}
ul li { list-style-type: square; }
ul li li { list-style-type: disc; }
ul.toc {
border-left: 1em solid #EEE;
}
ul.toc ul {
margin: 0;
padding: .5em 0 1em 3em;
}
ul.toc li { color: #A00; text-shadow: #000 0 0 0; }
ul.toc li li { color: #0A0; }
ul.toc li li li { color: #77C; text-shadow: #fff 0 0 0; }
ul.toc li li li li { color: #AA5; }
ul.toc a {
text-decoration: none;
color: #444;
}
ul.toc a:hover {
color: blue;
color: #A00;
text-decoration: underline;
}
/* page numbers */
li {
position: relative;
}
li > a {
background: #fff;
display: inline-block;
padding-right: .5em;
}
li:before {
text-align: right;
content: ' ';
float: right;
width: 100%;
height: calc(1em - 1px);
margin-bottom: -1em;
right: 0;
border-bottom: 1px dashed #000;
}
li:after {
content: attr(page);
position: absolute;
right: 0;
top: 0;
padding-left: .3em;
background: #fff;
}
JavaScript
const formatAsID = (node, format = '%s') =>
format.replace(/%s/,
node.textContent.trim().replace(/[^\wА-Яа-я.]+/g, '-')
)
;
const replaceWithLink = (node, url) => {
let a = document.createElement('a');
node.replaceWith(a);
a.href = url;
a.append(node);
};
for (let chapLI of document.querySelectorAll('ul.toc > li')) {
let textNode = chapLI.firstChild;
let chapURL = formatAsID(textNode, '%s.html');
replaceWithLink(textNode, chapURL);
for (let subChapLI of chapLI.querySelectorAll('ul.toc > li li')) {
let textNode = subChapLI.firstChild;
replaceWithLink(textNode, formatAsID(textNode, chapURL + '#%s'));
}
}
for (let header of document.querySelectorAll('h1,h2,h3,h4,h5,h6')) {
let textNode = header.firstChild;
header.id = formatAsID(textNode);
}