Итак, требовалось: опубликовать книгу с иллюстрациями онлайн так, чтобы ее можно было дописывать и переписывать, и извещать об этом читателей. Быстрое и изящное решение под катом.
Изначально планировалось написать полноценную админку с WYSIWYG-редактором, у которого обязательно должна быть хорошая проверка орфографии, удобный интерфейс и возможность прицепить к записи анимацию. В планах было анимировать рисование карандашных набросков на полях. Забегая чуть вперед, скажу, что делали саму отрисовку с помощью vivus.
В общем, купили домен, но разработка серверной части никак не шла: получались какие-то громоздкие уродцы, у которых лишнего было больше, чем полезного. Может так бы все и осталось, если бы мне на глаза не попалось описание одного продукта (jekyll), где в преимуществах при прочих было отмечено отсутствие базы данных. Тут-то меня и осенило, что книге база данных как корове седло не нужна.
И завертелось: решено было хостить книгу на github, а страницы размечать markdown, благо для любимого автором word’а быстро нашелся плагин для сохранения в этом формате (Writage). Ну а для преобразования его в html подвернулась библиотека ShowDown
Достаточно быстро задуманное было реализовано. Книга состоит из файлов-страничек в формате .md и файла .json, в котором перечислено что за чем идет, какую анимацию грузить и надо ли вообще.
Вот так выглядит конфигурационный файл:
[{
"file": "имяфайла.md",
"hash": "хештег",
"animation": {
"svg": "анимация.svg",
"duration": 2000,//Продолжительность анимации в милисекундах
"style": "width:400px;height:300px;opacity:0.5;float:right;margin-right:20px;"//Стиль для блока анимации, чтобы было понятно где его размещать
},
{
"file": "имяфайла2.md",
"hash": "хештег2"
}]
Собственно, сами страницы загружаются асинхронно при прокрутке и по хештегу, чтобы пользователь мог продолжить читать с того же месте, где остановился. При загрузке страницы по хештегу подгружается еще и предыдущая запись, если она есть, чтобы не казалось, что это начало книги.
Синхронный Ajax браузер мне использовать не дал, но может оно и к лучшему. Делала так: сначала создаются блоки с id=хештег, потом отправляются запросы к непосредственным страницам. Таким образом, все запрошенные страницы встают на свое место, независимо от того, какой из запросов быстрее выполнится.
Вот функция загрузки страницы, которая принимает объект страницы из конфигурационного файла и опционально параметры: нужно ли изменять хеш страницы, добавить ли эту страницу после текущей или перед и нужно ли скроллить к новой странице после загрузки. Параметры дают возможность фоновой загрузки страниц.
function loadPage(page, options = {}) {
$("#loader").show();
if (options.changeHash === undefined) {
options.changeHash = true;
}
if (options.next === undefined) {
options.next = true;
}
if (options.scroll === undefined) {
options.scroll = true;
}
if (options.changeHash) {
document.location.hash = "#" + page.hash;
}
if ($("#" + page.hash).size() == 0) {
if (options.next) {
$("#content").append('<div id="' + page.hash + '"></div>');
} else {
$("#content").prepend('<div id="' + page.hash + '"></div>');
}
jQuery.ajax({
url: "/book/" + page.file,
success: function(result) {
//Преобразуем markdown в html
var converter = new showdown.Converter();
var html = converter.makeHtml(result);
$("#" + page.hash).html(html);
if(page.animation!==undefined){
//Рисуем иллюстрацию, если она есть
$("#" + page.hash).prepend('<div id="animation-'+page.hash+'" style="'+page.animation.style+'"></div>');
var vivus=new Vivus('animation-'+page.hash, {duration: page.animation.duration, file: '/svg/'+page.animation.svg, type:'oneByOne'}, finishedDrawing);
}
$("#loader").fadeOut();
if (options.scroll) {
//Ползем к загруженной странице, если нужно
$('html,body').animate({
scrollTop: $("#" + page.hash).offset().top
}, 300, 'swing');
}
}
});
}
}
Собственно, вот и вся магия. Автор спокойно пишет себе книгу и в пару кликов публикует (с редактурой json файла он тоже справился сам).
Готовую книгу (она на английском) можно почитать тут, а рассмотреть внутренности подробнее в коде на github.
Спасибо за уделенное время, надеюсь, что вы не сочли его потраченным впустую!
Автор: ValeriaVG