Скорочтение
HTML
<!-- Inspired by http://www.spritzinc.com/ -->
<!-- Strugatskie's text is used for demo -->
<div id="help">
Скопируйте текст в поле ввода и нажмите "ПОЕХАЛИ".
<br/> Во время чтения доступны горячие клавиши: k — быстрее, j — медленнее, s — stop/start.
</div>
<div id="pnl-input">
<textarea>
Ложа Анкиного арбалета была выточена из черной пластмассы, а тетива была из хромистой стали и натягивалась одним движением бесшумно скользящего рычага. Антон новшеств не признавал: у него было доброе боевое устройство в стиле маршала Тоца, короля Пица
Первого, окованное черной медью, с колесиком, на которое наматывался шнур из воловьих жил. Что касается Пашки, то он взял пневматический карабин. Арбалеты он считал детством человечества, так как был ленив и неспособен к столярному ремеслу. Они причалили
к северному берегу, где из желтого песчаного обрыва торчали корявые корни мачтовых сосен. Анка бросила рулевое весло и оглянулась. Солнце уже поднялось над лесом, и все было голубое, зеленое и желтое — голубой туман над озером, темно-зеленые сосны
и желтый берег на той стороне. И небо над всем этим было ясное, белесовато-синее. — Ничего там нет,— сказал Пашка. s Ребята сидели, перегнувшись через борт, и глядели в воду. — Громадная щука,— уверенно сказал Антон. — С вот такими плавниками? — спросил
Пашка. Антон промолчал. Анка тоже посмотрела в воду, но увидела только собственное отражение. — Искупаться бы,— сказал Пашка, запуская руку по локоть в воду.— Холодная,— сообщил он. Антон перебрался на нос и спрыгнул на берег. Лодка закачалась. Антон
взялся за борт и выжидательно посмотрел на Пашку. Тогда Пашка поднялся, заложил весло за шею, как коромысло, и, извиваясь нижней частью туловища, пропел: Старый шкипер Вицлипуцли! Ты, приятель, не заснул? Берегись, к тебе несутся Стаи жареных акул!
Антон молча рванул лодку. — Эй-эй! — закричал Пашка, хватаясь за борта. — Почему жареных? — спросила Анка. — Не знаю,— ответил Пашка. Они выбрались из лодки.— А...
CSS
#pnl-read {
width: 500px;
height: 200px;
margin: 50px auto;
position: relative;
}
#frame {
width: 150px;
height: 20px;
border: 2px solid red;
border-left: none;
border-right: none;
position: absolute;
left: 225px;
top: 90px;
}
#content {
width: 500px;
overflow: hidden;
position: absolute;
}
#content P {
margin-top: 3pt;
text-indent: 10pt;
color: #CCC;
}
#content .cur {
color: #000;
}
#content .cur A {
color: #A00;
}
JavaScript
var anchors, interval = 120,
delta = 20,
contentElem, frameElem, timeoutId = null,
nextIdx = 0,
curWordSpan = null,
usePunctuation = false;
function arr(o) {
return Array.prototype.slice.apply(o)
}
function $(q) {
return document.querySelector(q)
}
function $$(q) {
return arr(document.querySelectorAll(q))
}
onload();
function onload() {
// global
frameElem = $('#frame');
contentElem = $('#content');
// local
var pnlInput = $('#pnl-input'),
pnlRead = $('#pnl-read'),
btnStart = $('#pnl-input INPUT[type=button]');
pnlInput.style.display = "block";
pnlRead.style.display = "none";
btnStart.addEventListener('click', function() {
pnlInput.style.display = "none";
pnlRead.style.display = "block";
beginRead();
});
btnStart.focus();
}
function beginRead() {
var text = $('#pnl-input TEXTAREA').value;
text = escapeHtml(text);
text = spreadAnchors(text);
text = '<p>' + text.replace(/\n/g, '</p><p>') + '</p>';
contentElem.innerHTML = text;
anchors = $$('#content A');
document.addEventListener('keypress', function(e) {
switch (e.keyCode || e.which) {
case 's'.charCodeAt(0):
startStop();
break;
case 'j'.charCodeAt(0):
slower();
break;
case 'k'.charCodeAt(0):
faster();
break;
}
});
usePunctuation = $('#chk-punktuation').checked;
tick();
}
function escapeHtml(text) {
return text.replace(/[<>&"]/g, function(c) {
switch (c) {
case '<':
return "<";
case '>':
return ">";
case '&':
return "&";
case '"':
return """;
}
});
}
function spreadAnchors(text) {
return text.replace(/([^\s-——,.;:!?«»"„“]+)([\s-——,.;:!?«»"„“]{0,3})/g, function(_, w, p) {
var c = bestChar(w.length);
return '<span>' + w.substring(0, c) +
'<a data-l="' + w.length + '" data-p="' + punctuationCoeff(p) + '">' + w[c] + '</a>' +
w.substring(c + 1) + '</span>'...