Главная » Фантастика » Второй шанс попаданки. Теперь элита » Книга полностью
Читать онлайн полностью

Второй шанс попаданки. Теперь элита

Автор: Дана Данберг

Жанр: Фантастика

Описание книги
Оцените книгу
0%
Страница 1 из 129 Настройки чтения
  • Тема
  • Шрифт
  • Размер
  • Поля
  • Межстрочный интервал
  • Показывать прогресс

Второй шанс попаданки. Теперь элита читать книгу онлайн

Автор: Дана Данберг

обложка книги Второй шанс попаданки. Теперь элита <div class="title"> <p>Дана Данберг. Второй шанс попаданки. Теперь элита</p> </div> <p/> <div class="title"> <p>Глава 1</p> </div> <p> <p> <p>На самом деле, обучение в Подгорной действительно отличалось в лучшую сторону в плане профессионализма и учебной программы, но были и свои особенности.</p> <p>Когда я только приехала и разместилась, мне было странно наблюдать вот это все хождение всей группой в столовую, на лекции и даже на утренние пробежки, хотя они не были обязательными. Но потом я поняла, что это просто насущная необходимость. Солнце в долине рано заходило за ближайшие горы и наступала серая полутьма, а вот появлялось оно наоборот поздно. Так что утром мы шли на занятия практически в темноте.</p> <p>А ведь я уже встречалась с монстрами из Подгорной рощи, так что недооценивать их не собиралась. Повторять встречу тоже.</p> <p>И хоть по периметру были сигнальные артефакты, они только и исключительно сообщали о приближении тварей, но никак от них не защищали. Так что ходить в одиночку было просто опасно даже в самой долине.</p> <p>Про горы я и не говорю, с ними отдельная история. Понятно, что не все из них находятся в самой Роще. Глупо ставить Академию прямо с ней на границе, так что ближайшие пики были свободны от мглы. Правда, мутанты там все равно водились и немало.</p> <p>Это все мне рассказал староста нашей группы Тлил Ниис, а также взятая им для моральной поддержки Тена. Моя одногруппница уже успела здесь освоиться и не то чтобы вписаться, но правила местного сообщества уже уяснила.</p> <p>– Я так рада тебя здесь видеть, ты даже не представляешь! – улыбнулась мне она, когда староста ушел, выполнив свой долг. – Мы с Эси уже беспокоились, что ты не приедешь.</p> <p>– Куда бы я делась? – фыркнула я. – Просто оставались дела в столице.</p> <p>– А эти дела как-то связаны с магистром Зеером? – хитро улыбнулась та. А у меня остался один единственный вопрос: откуда она знает? – Ты на каком этаже живешь?</p> <p>Мы обосновались для общения в холле общежития. Да, тут были такие открытые помещения на каждом этаже, правда, мы засели на первом. Но сейчас мы с Теной решили двигаться в направлении своих комнат. Дело в том, что уже через полчаса начинался ужин и надо было забросить учебники и привести себя в порядок, а то последним занятием у нас была физкультура. Почему наш староста решил, что это как раз подходящее время, чтобы рассказать о правилах – для меня загадка, ведь я приехала уже три дня назад, два из которых училась.</p> <p>– Отчасти, – я пожала плечами.</p> <p>Алек, конечно, только частично виноват в том, что я задержалась. В основном, виновата местная бюрократия и мои глупые метания по магазинам. Кто ж знал, что тут всю необходимую для жизни одежду выдают? Правда, есть одно немаловажное уточнение: носить форму можно только на территории Академии. Ездить в город разрешено только в гражданской одежде. Не знаю уж, к чему такая конспирация.</p> <p>– Мне сюда, – я указала на свой этаж.</p> <p>– Это же четвертый, – нахмурилась Тена.</p> <p>– Ну да, – непонимающе посмотрела я на девушку, и только через несколько секунд до меня дошло. – Тена, я просто не успела сказать…</p> <p>– О чем? – она посмотрела на меня заинтересованно, предчувствуя, видимо, занимательную историю.</p> <p>– В общем, тут такое дело… – я глубоко вздохнула, успокаивая пульс. – Я получила дворянство…</p> <p>– Ты что, вышла замуж за Зеера?! – перебив меня, тут же закричала Тена.</p> <p>– Что? Нет, конечно, нет. Мне присвоили титул.</p> <p>– За что это? – теперь уже она смотрела подозрительно.</p> <p>– Ну, я немного помогла в поимке тех, кто натравил монстров на Академию.</p> <p>– А… Постой-ка! – девушка нахмурилась. – И твой вклад был настолько велик, что тебе дали дворянство?</p> <p>А вот это был очень тонкий момент, учитывая то, что я сама не понимала, почему мои действия оценили настолько высоко. Я не считала, что заслужила, так как же это объяснить другим людям?</p> <p>– Мне дали Орден Дэса, – призналась я. – Ты сама понимаешь, что это значит.</p> <p>– Ого! – только и смогла вымолвить она, а потом в мгновение изменилась, ее глаза загорелись живейшим любопытством. Мне аж стало не по себе. Впрочем, хорошо, что она на новость не отреагировала отрицательно, чего я, честно говоря, опасалась. – Так, ты должна мне все рассказать! А Эси, она знает?</p> <p>– Я ей пока не говорила, но мы виделись только мельком в столовой.</p> <p>– Мы должны ей рассказать! И я выпытаю у тебя все подробности!</p> <p>– Не надо меня пытать, – усмехнулась я. – Я что могу и так расскажу.</p> </div> </div> <div class="navigation"> <div class="pages"><span>1</span><a href="/fb2reader/24597/2/">2</a><a href="/fb2reader/24597/3/">3</a><a href="/fb2reader/24597/4/">4</a><a href="/fb2reader/24597/5/">5</a><a href="/fb2reader/24597/6/">6</a><span class="nav_ext">...</span><a href="/fb2reader/24597/129/">129</a></div> </div> <br><div class="adfinity_block_18173"></div><div class="adfinity_block_18175"></div> <div id="reader-final-recs-slot"></div> <section class="reader-recs reader-recs--author"><h2>Другие книги автора</h2><div class="reader-rec-grid"><div class="reader-rec-card"><a class="reader-rec-card__cover" href="https://knigi.fun/26336-vtoroy-shans-popadanki-pochti-elita.html"><img src="https://knigi.fun/uploads/posts/2025-10/vtoroi_shans_popadanki_pochti_elita_danberg.763818.jpg" loading="lazy" decoding="async" alt="Второй шанс попаданки. Почти элита"></a><a class="reader-rec-card__title" href="https://knigi.fun/26336-vtoroy-shans-popadanki-pochti-elita.html">Второй шанс попаданки. Почти элита</a><a class="reader-rec-card__meta" href="https://knigi.fun/genre/popadancy/">Попаданцы</a></div><div class="reader-rec-card"><a class="reader-rec-card__cover" href="https://knigi.fun/19563-temnaya-knyaghna-imperii-2.html"><img src="https://knigi.fun/uploads/posts/2025-08/temnaia_kniazhna_imperii_2_danberg.832272.jpg" loading="lazy" decoding="async" alt="Темная княжна Империи 2"></a><a class="reader-rec-card__title" href="https://knigi.fun/19563-temnaya-knyaghna-imperii-2.html">Темная княжна Империи 2</a><a class="reader-rec-card__meta" href="https://knigi.fun/genre/fantastika/">Фантастика</a></div><div class="reader-rec-card"><a class="reader-rec-card__cover" href="https://knigi.fun/21650-temnaya-knyaghna-imperii.html"><img src="https://knigi.fun/uploads/posts/2025-09/temnaia_kniazhna_imperii_danberg.832271.jpg" loading="lazy" decoding="async" alt="Темная княжна Империи"></a><a class="reader-rec-card__title" href="https://knigi.fun/21650-temnaya-knyaghna-imperii.html">Темная княжна Империи</a><a class="reader-rec-card__meta" href="https://knigi.fun/genre/fantastika/">Фантастика</a></div><div class="reader-rec-card"><a class="reader-rec-card__cover" href="https://knigi.fun/20709-vtoroy-shans-popadanki-voyti-v-elitu.html"><img src="https://knigi.fun/uploads/posts/2025-08/vtoroi_shans_popadanki_voiti_v_elitu_danberg.807587.jpg" loading="lazy" decoding="async" alt="Второй шанс попаданки. Войти в элиту"></a><a class="reader-rec-card__title" href="https://knigi.fun/20709-vtoroy-shans-popadanki-voyti-v-elitu.html">Второй шанс попаданки. Войти в элиту</a><a class="reader-rec-card__meta" href="https://knigi.fun/genre/popadancy/">Попаданцы</a></div><div class="reader-rec-card"><a class="reader-rec-card__cover" href="https://knigi.fun/21403-gospogha-travnica_-ili-lyubovnoe-zelye-zakazyvali.html"><img src="https://knigi.fun/uploads/posts/2025-09/gospozha_travnitsa_ili_liubovnoe_zele_zakazyvali_danberg.803995.jpg" loading="lazy" decoding="async" alt="Госпожа травница, или Любовное зелье заказывали?"></a><a class="reader-rec-card__title" href="https://knigi.fun/21403-gospogha-travnica_-ili-lyubovnoe-zelye-zakazyvali.html">Госпожа травница, или Любовное зелье заказывали?</a><a class="reader-rec-card__meta" href="https://knigi.fun/genre/ljubovnoe-fjentezi/">Любовное фэнтези</a></div></div></section> <section class="reader-recs reader-recs--similar"><h2>Похожие книги</h2><div class="reader-rec-grid"><div class="reader-rec-card"><a class="reader-rec-card__cover" href="https://knigi.fun/18093-sedymoy-rubegh-i.html"><img src="https://knigi.fun/uploads/posts/2025-06/bor_5000-let-temnoty_1_sedmoy-rubezh-i.9lvatw.788616.jpg" loading="lazy" decoding="async" alt="Седьмой Рубеж I"></a><a class="reader-rec-card__title" href="https://knigi.fun/18093-sedymoy-rubegh-i.html">Седьмой Рубеж I</a><a class="reader-rec-card__meta" href="https://knigi.fun/genre/fantastika/">Фантастика</a></div><div class="reader-rec-card"><a class="reader-rec-card__cover" href="https://knigi.fun/25461-«intime»-chasty-tretyya.html"><img src="https://knigi.fun/uploads/posts/2025-10/03_intime_chast_tretya.jpg" loading="lazy" decoding="async" alt="«InTime». Часть третья"></a><a class="reader-rec-card__title" href="https://knigi.fun/25461-«intime»-chasty-tretyya.html">«InTime». Часть третья</a><a class="reader-rec-card__meta" href="https://knigi.fun/genre/fantastika/">Фантастика</a></div><div class="reader-rec-card"><a class="reader-rec-card__cover" href="https://knigi.fun/22568-alchuschie.html"><img src="https://knigi.fun/uploads/posts/2025-09/05_alchuschie.jpg" loading="lazy" decoding="async" alt="Алчущие"></a><a class="reader-rec-card__title" href="https://knigi.fun/22568-alchuschie.html">Алчущие</a><a class="reader-rec-card__meta" href="https://knigi.fun/genre/fantastika/">Фантастика</a></div><div class="reader-rec-card"><a class="reader-rec-card__cover" href="https://knigi.fun/22272-palach-ghelaniy.html"><img src="https://knigi.fun/uploads/posts/2025-09/02_palach_zhelanij.jpg" loading="lazy" decoding="async" alt="Палач желаний"></a><a class="reader-rec-card__title" href="https://knigi.fun/22272-palach-ghelaniy.html">Палач желаний</a><a class="reader-rec-card__meta" href="https://knigi.fun/genre/fantastika/">Фантастика</a></div><div class="reader-rec-card"><a class="reader-rec-card__cover" href="https://knigi.fun/22653-krapiva_-kotoraya-lyubila-chitaty.html"><img src="https://knigi.fun/uploads/posts/2025-09/krapiva_kotoraia_liubila_chitat_carbon.749356.jpg" loading="lazy" decoding="async" alt="Крапива, которая любила читать"></a><a class="reader-rec-card__title" href="https://knigi.fun/22653-krapiva_-kotoraya-lyubila-chitaty.html">Крапива, которая любила читать</a><a class="reader-rec-card__meta" href="https://knigi.fun/genre/fantastika/">Фантастика</a></div><div class="reader-rec-card"><a class="reader-rec-card__cover" href="https://knigi.fun/17463-dochy-vraga-rossiyskoy-imperii-kursantka.html"><img src="https://knigi.fun/uploads/posts/2025-06/02_doch_vraga_rossijskoj_imperii_kursantka.jpg" loading="lazy" decoding="async" alt="Дочь врага Российской империи. Курсантка"></a><a class="reader-rec-card__title" href="https://knigi.fun/17463-dochy-vraga-rossiyskoy-imperii-kursantka.html">Дочь врага Российской империи. Курсантка</a><a class="reader-rec-card__meta" href="https://knigi.fun/genre/fantastika/">Фантастика</a></div></div></section> </div> <script> (function () { var toggleBtn = document.getElementById('fb2-autoscroll-toggle'); var speedInput = document.getElementById('fb2-autoscroll-speed'); var contentWrap = document.getElementById('fb2-reader-content'); var scrollingElement = document.scrollingElement || document.documentElement; var activeScroller = scrollingElement; if (!toggleBtn || !speedInput) return; var isRunning = false; var rafId = null; var lastTime = null; var scrollRemain = 0; // накапливаем дробные пиксели var prevHtmlScrollBehavior = ''; var prevBodyScrollBehavior = ''; var cachedMaxScroll = 0; var lastMetricsUpdate = 0; var iosInnerScrollerEnabled = false; window.__fb2AutoscrollState = window.__fb2AutoscrollState || { running: false }; // простая проверка iOS var isIOS = /iP(ad|hone|od)/.test(navigator.userAgent); // читаем реальные границы слайдера var sliderMin = parseInt(speedInput.min || '1', 10); var sliderMax = parseInt(speedInput.max || '100', 10); if (isNaN(sliderMin)) sliderMin = 1; if (isNaN(sliderMax)) sliderMax = 100; // Скорость в пикселях в секунду (логика общая, но диапазон для iOS мягче) function getSpeedPxPerSec() { var raw = parseInt(speedInput.value || '40', 10); if (isNaN(raw)) raw = 40; // учитываем твой реальный слайдер 1..80 var sliderMin = parseInt(speedInput.min || '1', 10); var sliderMax = parseInt(speedInput.max || '80', 10); if (isNaN(sliderMin)) sliderMin = 1; if (isNaN(sliderMax)) sliderMax = 80; raw = Math.min(Math.max(raw, sliderMin), sliderMax); // нормируем в 0..1 var k = (raw - sliderMin) / (sliderMax - sliderMin || 1); // Для iOS оставляем более плавный старт, но делаем хвост заметно быстрее, // чтобы верхние значения ползунка реально ощущались. if (isIOS) { k = Math.pow(k, 1.25); } var minSpeed = isIOS ? 20 : 15; var maxSpeed = isIOS ? 150 : 200; return minSpeed + (maxSpeed - minSpeed) * k; } function setNativeScrollBehavior(enabled) { var html = document.documentElement; var body = document.body; if (enabled) { prevHtmlScrollBehavior = html.style.scrollBehavior; prevBodyScrollBehavior = body.style.scrollBehavior; html.style.scrollBehavior = 'auto'; body.style.scrollBehavior = 'auto'; } else { html.style.scrollBehavior = prevHtmlScrollBehavior || ''; body.style.scrollBehavior = prevBodyScrollBehavior || ''; } } function refreshScrollMetrics(force) { var now = Date.now(); if (!force && (now - lastMetricsUpdate) < 800) { return; } lastMetricsUpdate = now; if (iosInnerScrollerEnabled) { cachedMaxScroll = activeScroller.scrollHeight - activeScroller.clientHeight; } else { cachedMaxScroll = Math.max( scrollingElement.scrollHeight, document.documentElement.scrollHeight, document.body.scrollHeight ) - window.innerHeight - 2; } if (cachedMaxScroll < 0) cachedMaxScroll = 0; } function enableIOSInnerScroller() { if (!isIOS || !contentWrap || iosInnerScrollerEnabled) return; var rect = contentWrap.getBoundingClientRect(); var absoluteTop = rect.top + window.pageYOffset; var carryScroll = Math.max(0, window.pageYOffset - absoluteTop); var availableHeight = Math.floor(window.innerHeight - Math.max(rect.top, 0) - 16); if (availableHeight < 260) { availableHeight = Math.max(220, window.innerHeight - 40); } contentWrap.style.maxHeight = availableHeight + 'px'; contentWrap.style.overflowY = 'auto'; contentWrap.style.overflowX = 'hidden'; contentWrap.style.webkitOverflowScrolling = 'auto'; contentWrap.style.overscrollBehavior = 'contain'; contentWrap.style.contain = 'layout paint style'; window.scrollTo(0, absoluteTop); contentWrap.scrollTop = carryScroll; activeScroller = contentWrap; iosInnerScrollerEnabled = true; refreshScrollMetrics(true); } function disableIOSInnerScroller() { if (!iosInnerScrollerEnabled || !contentWrap) return; var absoluteTop = contentWrap.getBoundingClientRect().top + window.pageYOffset; var carryScroll = contentWrap.scrollTop; contentWrap.style.maxHeight = ''; contentWrap.style.overflowY = ''; contentWrap.style.overflowX = ''; contentWrap.style.webkitOverflowScrolling = ''; contentWrap.style.overscrollBehavior = ''; contentWrap.style.contain = ''; activeScroller = scrollingElement; iosInnerScrollerEnabled = false; window.scrollTo(0, absoluteTop + carryScroll); refreshScrollMetrics(true); } function step(timestamp) { if (!isRunning) return; if (lastTime === null) { lastTime = timestamp; } var dt = timestamp - lastTime; // мс с прошлого кадра lastTime = timestamp; var speed = getSpeedPxPerSec(); // px/сек refreshScrollMetrics(false); var current = activeScroller.scrollTop; var maxScroll = cachedMaxScroll; if (current >= maxScroll) { stopAutoscroll(); return; } // На iOS тоже считаем по реальному времени, иначе при просадках FPS // визуальная скорость получается заметно ниже выбранной. if (dt > (isIOS ? 34 : 50)) { dt = isIOS ? 34 : 50; } var distance = speed * (dt / 1000); // Накапливаем дробные пиксели, чтобы даже при маленькой скорости всё равно ползло scrollRemain += distance; var move = Math.floor(scrollRemain); if (move >= 1) { scrollRemain -= move; activeScroller.scrollTop = Math.min(current + move, maxScroll); } rafId = requestAnimationFrame(step); } function startAutoscroll() { if (isRunning) return; isRunning = true; window.__fb2AutoscrollState.running = true; lastTime = null; scrollRemain = 0; enableIOSInnerScroller(); refreshScrollMetrics(true); setNativeScrollBehavior(true); toggleBtn.classList.add('is-running'); toggleBtn.textContent = 'Остановить'; // лёгкий "пинок" странице — особенно помогает iOS try { window.scrollBy(0, 1); window.scrollBy(0, -1); } catch (e) {} rafId = requestAnimationFrame(step); } function stopAutoscroll() { if (!isRunning) return; isRunning = false; window.__fb2AutoscrollState.running = false; toggleBtn.classList.remove('is-running'); toggleBtn.textContent = 'Автопрокрутка'; if (rafId !== null) { cancelAnimationFrame(rafId); rafId = null; } setNativeScrollBehavior(false); disableIOSInnerScroller(); lastTime = null; scrollRemain = 0; } // Кнопка старт/стоп toggleBtn.addEventListener('click', function (e) { e.preventDefault(); if (isRunning) { stopAutoscroll(); } else { startAutoscroll(); } }); // iOS: touchstart -> click toggleBtn.addEventListener('touchstart', function (e) { e.preventDefault(); toggleBtn.click(); }, { passive: false }); // Любое "осознанное" действие пользователя — стоп function userStopHandler(e) { if (!isRunning) return; // Не гасим, если это внутри панели автопрокрутки if (e.target && e.target.closest && e.target.closest('.reader-autoscroll')) { return; } stopAutoscroll(); } ['wheel', 'keydown', 'mousedown'].forEach(function (ev) { document.addEventListener(ev, userStopHandler, { passive: true }); }); ['touchmove'].forEach(function (ev) { document.addEventListener(ev, userStopHandler, { passive: true }); }); window.addEventListener('resize', function () { refreshScrollMetrics(true); }, { passive: true }); })(); </script> <script> (function () { var $fb2Area = $('.fb2-area'); var ajaxMode = $fb2Area.data('ajax') == 1 || $fb2Area.data('ajax') === '1'; var $content = $('#fb2-reader-content'); var $pages = $('.navigation .pages'); var $pageInfo = $('.fb2-page-info'); var $introSlot = $('#reader-intro-slot'); var initialIntroHtml = $introSlot.html() || ''; var $finalRecsSlot = $('#reader-final-recs-slot'); var initialFinalRecsHtml = $finalRecsSlot.html() || ''; var $message = $('<div class="fb2-ajax-message" role="status"></div>'); var $loader = $('<div class="fb2-ajax-loader" role="status">Загружаем страницу...</div>'); var loading = false; var cache = {}; var prefetching = {}; var prefetchXhrs = {}; var bookId = $fb2Area.data('book-id'); if (!ajaxMode || !$fb2Area.length || !$content.length || !$pages.length || !$pageInfo.length) { return; } $pages.before($message); $content.before($loader); function normalizePage(page) { page = parseInt(page || '1', 10); return page > 0 ? page : 1; } function pageFromUrl(url) { var page = 1; var match = String(url).match(/\/fb2reader\/([0-9]+)(?:\/([0-9]+))?\//); if (match) page = normalizePage(match[2] || '1'); return page; } function ajaxUrl(page) { page = normalizePage(page); return '/index.php?do=fb2reader&news_id=' + encodeURIComponent(bookId) + '&cstart=' + page + '&fb2ajax=1'; } function pageUrl(page) { page = normalizePage(page); return page > 1 ? '/fb2reader/' + bookId + '/' + page + '/' : '/fb2reader/' + bookId + '/'; } function updateBrowserUrl(page) { var url = pageUrl(page); if (!window.history || !window.history.replaceState || !bookId) return url; window.history.replaceState(null, document.title, url); return url; } function sendMetrikaHit(page, refererUrl) { if (typeof window.ym !== 'function') return; var url = pageUrl(page); var absoluteUrl = window.location.origin + url; var title = document.title + ' — страница ' + normalizePage(page); window.ym(100046838, 'hit', absoluteUrl, { title: title, referer: refererUrl || document.referrer || '' }); } function updateIntroVisibility(page) { page = normalizePage(page); if (!$introSlot.length) return; if (page === 1 && initialIntroHtml) { $introSlot.html(initialIntroHtml).show(); } else { $introSlot.hide(); } } function updateFinalRecs(page, total, html) { page = normalizePage(page); total = normalizePage(total); if (!$finalRecsSlot.length) return; if (page >= total) { $finalRecsSlot.html(html || initialFinalRecsHtml).show(); } else { $finalRecsSlot.hide().html(''); } } function abortPrefetches(exceptPage) { $.each(prefetchXhrs, function (page, xhr) { if (parseInt(page, 10) === exceptPage) return; if (xhr && xhr.readyState !== 4) xhr.abort(); delete prefetchXhrs[page]; delete prefetching[page]; }); } function applyResponse(response, href) { updateIntroVisibility(response.page); updateFinalRecs(response.page, response.count, response.final_recs || ''); $content.html(response.content); $pages.html(response.pages || ''); $pageInfo .attr('data-page', response.page) .attr('data-count', response.count) .data('page', response.page) .data('count', response.count) .text('Страница ' + response.page + ' из ' + response.count); window.scrollTo({ top: 0, behavior: 'smooth' }); window.dispatchEvent(new CustomEvent('fb2:page-loaded', { detail: { page: parseInt(response.page || 1, 10), total: parseInt(response.count || 1, 10) } })); var refererUrl = window.location.href; updateBrowserUrl(response.page); sendMetrikaHit(response.page, refererUrl); prefetchAround(response.page, response.count); } function prefetchPage(page, total) { page = normalizePage(page); total = normalizePage(total); if (page < 1 || page > total || cache[page] || prefetching[page]) return; if (Object.keys(prefetching).length >= 1) return; prefetching[page] = true; prefetchXhrs[page] = $.ajax({ url: ajaxUrl(page), type: 'GET', dataType: 'json', cache: false, timeout: 8000 }).done(function (response) { if (response && typeof response.content !== 'undefined') { cache[page] = response; } }).always(function () { delete prefetching[page]; delete prefetchXhrs[page]; }); } function prefetchAround(page, total) { page = normalizePage(page); total = normalizePage(total); window.setTimeout(function () { if (loading) return; prefetchPage(page + 1, total); if (!prefetching[page + 1]) prefetchPage(page + 2, total); }, 250); } $(document).on('mouseenter touchstart', '.navigation .pages a', function () { var href = $(this).attr('href'); if (!href || href.indexOf('/fb2reader/') === -1) return; prefetchPage(pageFromUrl(href), normalizePage($pageInfo.data('count'))); }); $(document).on('click', '.navigation .pages a', function (e) { var href = $(this).attr('href'); if (!href || href.indexOf('/fb2reader/') === -1) return; e.preventDefault(); e.stopPropagation(); if (loading) return false; var targetPage = pageFromUrl(href); abortPrefetches(targetPage); if (cache[targetPage]) { $message.removeClass('is-visible').text(''); applyResponse(cache[targetPage], href); return false; } loading = true; $fb2Area.addClass('fb2-ajax-loading'); $message.removeClass('is-visible').text(''); $.ajax({ url: ajaxUrl(targetPage), type: 'GET', dataType: 'json', cache: false, timeout: 12000 }).done(function (response) { if (!response || typeof response.content === 'undefined') { $message .text('Не удалось быстро загрузить страницу. Попробуйте нажать ещё раз.') .addClass('is-visible'); return; } cache[targetPage] = response; applyResponse(response, href); }).fail(function () { $message .text('Страница не загрузилась за отведённое время. Попробуйте ещё раз или обновите страницу.') .addClass('is-visible'); }).always(function () { loading = false; $fb2Area.removeClass('fb2-ajax-loading'); }); return false; }); cache[normalizePage($pageInfo.data('page'))] = { content: $content.html(), pages: $pages.html(), page: normalizePage($pageInfo.data('page')), count: normalizePage($pageInfo.data('count')) }; prefetchAround($pageInfo.data('page'), $pageInfo.data('count')); })(); </script> <script> (function () { var $win = $(window); var $bar = $('#reader-progress-bar'); var $label = $('#reader-progress-label'); var $pageInfo = $('.fb2-page-info'); var $fb2Area = $('.fb2-area'); var progressEndpoint = null; if (!$bar.length || !$label.length || !$pageInfo.length || !$fb2Area.length) return; var page = parseInt($pageInfo.data('page') || '1', 10); // текущая страница var total = parseInt($pageInfo.data('count') || '1', 10); // всего страниц var pathMatch = window.location.pathname.match(/\/fb2reader\/(\d+)/); var bookId = pathMatch ? parseInt(pathMatch[1], 10) : ($fb2Area.data('book-id') || null); // news-id if (page < 1) page = 1; if (total < 1) total = 1; if (page > total) page = total; var lastSavedPercent = null; var lastSavedTime = 0; var progressTickQueued = false; function saveProgress(percent) { if (!bookId) return; var now = Date.now(); var isAutoscrolling = !!(window.__fb2AutoscrollState && window.__fb2AutoscrollState.running); var minSaveInterval = isAutoscrolling ? 4000 : 1000; // Во время автопрокрутки сохраняем реже, чтобы iPhone не дёргался // из-за частых cookie/localStorage/ajax-операций. if (lastSavedPercent !== null && lastSavedPercent === percent && (now - lastSavedTime) < minSaveInterval) { return; } if ((now - lastSavedTime) < minSaveInterval) { return; } lastSavedPercent = percent; lastSavedTime = now; try { localStorage.setItem( 'fb2_book_' + bookId, JSON.stringify({ page: page, total: total, percent: percent, // уже округлённый процент updated: now }) ); } catch (e) { // молча игнорируем } try { document.cookie = 'fb2_' + bookId + '=' + page + '-' + total + '; path=/; max-age=' + (60 * 60 * 24 * 365); document.cookie = 'fb2_shelf_' + bookId + '=' + ((page >= total || percent >= 100) ? 'finished' : 'reading') + '; path=/; max-age=' + (60 * 60 * 24 * 365); } catch (e) { // молча игнорируем } if (progressEndpoint) { $.post(progressEndpoint, { news_id: bookId, page: page, total: total, percent: percent }); } } function updateProgress(forceSave) { progressTickQueued = false; var winTop = $win.scrollTop(); var winH = $win.height(); var docH = $(document).height(); var maxScroll = docH - winH; var intra = 0; // прогресс внутри текущей страницы: 0..1 if (maxScroll > 0) { intra = winTop / maxScroll; if (intra < 0) intra = 0; if (intra > 1) intra = 1; } // общий прогресс по книге: // (пройденные полные страницы + доля текущей) / всего var overall = ((page - 1) + intra) / total * 100; if (overall < 0) overall = 0; if (overall > 100) overall = 100; // 🔹 одно и то же округление используем и для отображения, и для сохранения var rounded = Math.round(overall); $bar.css('width', rounded + '%'); $label.text(rounded + '%'); if (forceSave) { lastSavedPercent = null; lastSavedTime = 0; } saveProgress(rounded); } function queueProgressUpdate() { if (window.__fb2AutoscrollState && window.__fb2AutoscrollState.running) { return; } if (progressTickQueued) return; progressTickQueued = true; window.requestAnimationFrame(updateProgress); } $win.on('scroll resize', queueProgressUpdate); updateProgress(); window.addEventListener('fb2:page-loaded', function (event) { var detail = event.detail || {}; page = parseInt(detail.page || $pageInfo.data('page') || '1', 10); total = parseInt(detail.total || $pageInfo.data('count') || '1', 10); if (page < 1) page = 1; if (total < 1) total = 1; if (page > total) page = total; lastSavedPercent = null; lastSavedTime = 0; updateProgress(true); }); setInterval(function () { if (window.__fb2AutoscrollState && window.__fb2AutoscrollState.running) { updateProgress(false); } }, 1200); // 🔹 при уходе со страницы ещё раз гарантированно сохраняем window.addEventListener('beforeunload', function () { var txt = $label.text().replace('%', '').trim(); var p = parseInt(txt, 10); if (!isNaN(p)) { updateProgress(true); saveProgress(p); } }); })(); </script> <!-- Yandex.Metrika counter --> <script type="text/javascript" > (function(m,e,t,r,i,k,a){m[i]=m[i]||function(){(m[i].a=m[i].a||[]).push(arguments)}; m[i].l=1*new Date(); for (var j = 0; j < document.scripts.length; j++) {if (document.scripts[j].src === r) { return; }} k=e.createElement(t),a=e.getElementsByTagName(t)[0],k.async=1,k.src=r,a.parentNode.insertBefore(k,a)}) (window, document, "script", "https://mc.yandex.ru/metrika/tag.js", "ym"); ym(100046838, "init", { clickmap:true, trackLinks:true, accurateTrackBounce:true }); </script> <noscript><div><img src="https://mc.yandex.ru/watch/100046838" style="position:absolute; left:-9999px;" alt="" /></div></noscript> <!-- /Yandex.Metrika counter --> <!--LiveInternet counter--><a href="https://www.liveinternet.ru/click" target="_blank"><img id="licnt125D" width="0" height="1" style="border:0" title="LiveInternet" src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAEALAAAAAABAAEAAAIBTAA7" alt=""/></a><script>(function(d,s){d.getElementById("licnt125D").src= "https://counter.yadro.ru/hit?t41.6;r"+escape(d.referrer)+ ((typeof(s)=="undefined")?"":";s"+s.width+"*"+s.height+"*"+ (s.colorDepth?s.colorDepth:s.pixelDepth))+";u"+escape(d.URL)+ ";h"+escape(d.title.substring(0,150))+";"+Math.random()}) (document,screen)</script><!--/LiveInternet--> <script> (function(){ var readerRecs = document.querySelectorAll('.reader-recs'); for (var i = 0; i < readerRecs.length; i++) { var grid = readerRecs[i].querySelector('.reader-rec-grid'); if (grid && !grid.textContent.replace(/\s+/g, ' ').trim()) readerRecs[i].style.display = 'none'; } })(); </script> <script>document.addEventListener("DOMContentLoaded",function readerRatingVote(){var box=document.querySelector(".reader-rating[data-news-id]");if(!box)return;var msg=box.querySelector(".reader-rating__msg");box.addEventListener("click",function(event){var btn=event.target.closest(".reader-rating__btn");if(!btn)return;event.preventDefault();var params=new URLSearchParams();params.set("news_id",box.getAttribute("data-news-id"));params.set("go_rate",btn.getAttribute("data-rate"));params.set("user_hash",box.getAttribute("data-hash"));fetch("/engine/ajax/controller.php?mod=rating",{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded; charset=UTF-8"},body:params.toString(),credentials:"same-origin"}).then(function(res){return res.json()}).then(function(data){if(data&&data.success){var like=box.querySelector("[data-rate=plus] .reader-rating__count");var dislike=box.querySelector("[data-rate=minus] .reader-rating__count");if(like)like.textContent=data.likes||0;if(dislike)dislike.textContent=data.dislikes||0;box.querySelector("[data-rate=plus]").classList.remove("is-liked");box.querySelector("[data-rate=minus]").classList.remove("is-disliked");btn.classList.add(btn.getAttribute("data-rate")==="plus"?"is-liked":"is-disliked");if(msg)msg.textContent="Спасибо, оценка учтена"}else if(msg){msg.textContent=data&&data.errorinfo?data.errorinfo:"Не удалось сохранить оценку"}}).catch(function(){if(msg)msg.textContent="Не удалось сохранить оценку"})})});</script> </body> </html>