Table of Content

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: 400 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; font-weight: 500 }
ul.toc li li       { color: #0A0; font-weight: 400 }
ul.toc li li li    { color: #77C; }
ul.toc li li li li { color: #AA5; }

ul.toc li:before          { border-bottom: 2px dotted #aaa; }
ul.toc li li:before       { border-bottom: 2px dotted #ddd; }
ul.toc li li li:before    { border-bottom: 1px dashed #eee; }
ul.toc li li li li:before { border-bottom: 1px dashed #eee; }

ul.toc li:hover:before          { border-color: #A00 }
ul.toc li li:hover:before       { border-color: #0A0 }
ul.toc li li li:hover:before    { border-color: #77C }
ul.toc li li li li:hover:before { border-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:...

JavaScript

console.clear();

const formatHash = (text, format = '%s') =>
  format.replace(/%s/,
    text.trim().replace(/[^\wА-Яа-я_-]+/g, '-')
  )
;

const replaceWithLink = (node, url) => {
  let a = document.createElement('a');
  node.replaceWith(a);
  a.href = url;
  a.append(node);
};

const onclick = e => {
  // e.stopPropagation();
  const a = e.target.querySelector(':scope > a:first-child');
  if (a) a.dispatchEvent(new MouseEvent('click'));
  console.log(decodeURIComponent(a.href));  
};

for (let root of document.querySelectorAll('ul.toc')) {
  root.onclick = onclick;
  for (let chapter of root.querySelectorAll(':scope > li')) {
    const textNode = chapter.firstChild;
    const url = formatHash(textNode.data, '%s.html');
    replaceWithLink(textNode, url);
    for (let section of chapter.querySelectorAll(':scope li')) {
      const textNode = section.firstChild;
      replaceWithLink(textNode, formatHash(textNode.data, url + '#%s'));
    }
  }
}

for (let header of document.querySelectorAll('h1,h2,h3,h4,h5,h6')) {
  header.id = formatHash(header.firstChild.data);
}