image

Итак, требовалось: опубликовать книгу с иллюстрациями онлайн так, чтобы ее можно было дописывать и переписывать, и извещать об этом читателей. Быстрое и изящное решение под катом.

Изначально планировалось написать полноценную админку с 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 = {}) {

    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>');
        }
        $("#loader").show();
        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.

Спасибо за уделенное время, надеюсь, что вы не сочли его потраченным впустую!
Поделиться с друзьями
-->

Комментарии (33)


  1. kahi4
    30.09.2016 18:30
    +2

    Итак, требовалось: опубликовать книгу с иллюстрациями онлайн так, чтобы ее можно было дописывать и переписывать, и извещать об этом читателей.

    И как же извещаете об этом читателей?


    А так — это даже на тестовое задание junior'у тянет с трудом, если честно и по секрету.


    1. ValeriaVG
      30.09.2016 19:53
      +4

      Что и где изменилось в книге есть в логе github, непосредственно средство время и формат оповещения читателей целиком на попечении автора.

      Вам не стоит рассматривать предоставленный код как вызов самому себе и обществу, код там прост и ничего принципиально нового не использует. В статье я хотела показать, что решая простую задачу лучше использовать простые решения, а не то, что привыкли/положено/модно.

      И нет, мой маленький кодик куда лучше показывает уровень знаний нежели чем крестики-нолики по пять в ряд


      1. geakstr
        01.10.2016 19:05

        > мой маленький кодик куда лучше показывает уровень знаний нежели чем крестики-нолики по пять в ряд

        Если уж сравнивать с заданием про крестики-нолики, то нет, не показывает


        1. ValeriaVG
          01.10.2016 23:27
          +4

          А что вы считаете уровнем? Просто/сложно? Я склонна ко мнению, что это оценка субъективна. Задача про крестики-нолики скорее на логику нежели чем на знание JavaScript, к примеру. Джуниору, возможно, только она и нужна, опыта он же в конце концов и идет набираться. А вышеописанную задачу, которая по сути сводится к проектированию архитектуры приложения, нежели к самому коду, он будет решать на

          таблица в бд + ckeditor. И править проще, и не надо это вот аяксовые loadPage.
          (см. ниже в комментариях)

          Ну и так, чтобы закрыть тему: я не ищу работу ни джуниором, ни кем ли бы то ни было и не претендую ни на ваши места, ни на ваши заслуги. Можете откинуться на спинку стула и отметить еще одну победу. Считайте, что ваш оппонент позорно бежал. Продолжать сей спор показывает — не показывает без указаний на конкретные огрехи кода считаю бессмысленным.


          1. geakstr
            02.10.2016 17:23

            Проникся уважением к вашему ответу. Но я только имел ввиду, что задание про крестики-нолики со всеми «плюсами» из списка — годное, комплексное и хорошо покажет кандидата как со стороны «на подумать», так и в плане, собственно, написания кода.


  1. aTwice
    30.09.2016 22:19
    +1

    Чем gitbook не подошёл?


    1. ValeriaVG
      01.10.2016 09:34
      +1

      Да в общем-то всем: оглавление было не нужно, нужна была автозагрузка страниц по скроллу и проигрывание анимации при этом. Вроде как читаешь ты себе книгу, а на полях рисуется тематическая иллюстрация.


  1. J_K
    01.10.2016 07:03

    А где книга-то? По ссылке одна-единственная страница.


    1. ValeriaVG
      01.10.2016 09:41

      Автор хочет преподнести ее в формате дневника — в данный момент там действительно одна страница с описанием предпосылок к этому. Идея автора, насколько мне объяснили, в том, чтобы читатель мог находиться в одной плоскости с книгой, почуствовать себя частью того мира, который она (книга) описывает и получать новую информацию в режиме реального времени с вымышленным миром.

      Вкратце: это книга — блог или, скорее, сериал.


      1. Punk_UnDeaD
        01.10.2016 19:39
        +4

        Книги нет, расходимся.


  1. zartarn
    01.10.2016 09:41
    +2

    Свой GitBook с блэкджеком и куртизанками?


    1. ValeriaVG
      01.10.2016 09:50
      +1

      Нет, это не gitbook. Описанное мною решение для совершенно другой задачи.

      Gitbook замечательно подходит для технической литературы за счет создания четкой структуры страниц.

      Я же описывала подход для создания «живой» художественной книги. В моем проекте страницы открываются и рисуется иллюстрация, но никто не мешает добавить любые другие эффекты — будь то музыка, видео, игра на canvas или еще что-то по аналогии.


  1. nikitastaf1996
    01.10.2016 16:01

    >чтобы ее можно было дописывать и переписывать
    В таком случае нужна версионность.


    1. ValeriaVG
      01.10.2016 23:10

      Поэтому github


  1. ecl
    01.10.2016 17:11

    Ничего не понял. Читатель должен после прочтения статьи стать чуточку (или не чуточку) умнее, осведомленее или веселее. Разве нет?
    Здесь я почувствовал себя обманутым и растерянным. Что мне хотели донести?


    1. ValeriaVG
      01.10.2016 23:11
      +1

      А что вы рассчитывали прочитать в статье «Онлайн книга своими руками на JavaScript»? Все инструменты расписала, основные куски кода показала, ссылку на код целиком дала. Может что-то подробнее рассказать? Что было непонятно?


  1. DenimTornado
    01.10.2016 18:48
    +2

    Подождите, автоматизации уведомлений об изменениях в книге нет, правильно? Тогда зачем эта морока с .md файлами? Тут по идее просто нужно добавление и изменение контента. То есть одна таблица в бд + ckeditor. И править проще, и не надо это вот аяксовые loadPage.


    1. ValeriaVG
      01.10.2016 23:09

      А почему вы считаете, что база данных тут подошла бы больше?

      Поиска / сортировки / массового обновления в этом проекте нет и точно не будет. Автор один, все тексты в файлах, а к базе пришлось бы еще и отдельное кеширование прикручивать. А загрузка по ajax — это не вынужденная мера, это изначальное требование. Во-первых: нужно отследить загрузку страницы, чтобы проиграть анимацию, а во-вторых это сейчас там две с половиной страницы, а когда их 400 будет? Одним махом все грузить из базы/кеша для каждого пользователя?


      1. DenimTornado
        02.10.2016 00:42
        +2

        Возможно я не прав и выбранная вами архитектура верная, но ответьте, пожалуйста на несколько вопросов.

        1. Каким образом автор добавляет новую страницу? Правильно ли я понимаю, что от него требуется, экспортировать из Ворда .md файл, затем по фтп закинуть в определённую папку на сервер, затем поправить конфиг (тут отдельный вопрос по блоку animation).
        2. Если я открою сразу 200-ую страницу, то загрузятся сразу три? Текущая + предыдущая + следующая?
        3. Почему вы не держите статику на своём сервере? Сейчас среднее время загрузки первой страницы 2-4 секунды как из-за статики снаружи.
        4. Что, если человек забудет сохранить в закладке на нужной странице? Ему ведь придётся пролистывать все 200-300 страниц?
        5. Вы в курсе, что сайт не работает в ИЕ11 и в любом другом браузере, который не поддерживает ES6?


        1. ValeriaVG
          02.10.2016 01:12
          -2

          1. Плагин, описанный в статье позволяет сразу сохранять в этом формате из Word, а Github клиент в два клика изменения публикует. Касательно редактуры конфига — в данном случае автор сам справился, но никто не мешает написать UI, если такая необходимость возникнет

          2. Загрузятся две. Предыдущая и запрошенная.

          3. На своем сервере потребовалось бы поднять свой git, к нему делать отрисовку логов, давать возможность watch. По поводу скорости: сайт с большой картинкой на первом экране и svg на странице (суммарно 500кб) + шрифт, пару скриптов в т.ч. с шарилками. Сервер тут вообще не причем — он быстро все отдает.

          4. А если вы в книгу человек закладку вложить забудет? Пока сложно сказать, есть ли нужда в карте. Технически — реализуемо и быстро (все есть в конфиге — нужно только вывести по порядку).

          5. Да. В данном случае нет задачи поддержать пользователей IE, Edge и старых версий — целевая аудитория продукта не та, да и я лично против поддержки кривого по.

          А на мой вопрос вы так и не ответили…


          1. bromium
            02.10.2016 11:10
            +3

            Еще не старый айпад, новая айось. Ваша «книга» не работает — тоже нецелевая аудитория? Тоже кривое ПО? А какое тогда прямое!?

            «Фтопку» такую «книгу», которую можно читать только на десктопе или ноуте


            1. ValeriaVG
              02.10.2016 12:38
              +1

              Спасибо, согласна с вами, не знала про такую проблему ios, внесла соответсвующие правки.


  1. Source
    02.10.2016 00:02
    +2

    А мне понравилась статья. На мой взгляд она не столько про конкретный код, сколько про то, что не нужно увлекаться оверинженерингом. Задача то на самом деле была нетиповая и получившееся решение выглядит весьма элегантно. Код, конечно, можно ещё подшлифовать, но куда ж без этого.
    Плюс я узнал про существование Vivus и Writage. Кстати, интересно, насколько хорошо Writage справляется со своей задачей в плане истории изменений? Т.е. насколько сильно результат отличается от ручного редактирования Markdown, если отличается?


    1. ValeriaVG
      02.10.2016 00:14

      Writage справляется неплохо, если у того, кто им пользуется есть представление о markdown. В моем случае пришлось объяснять, что специальные символы (например "-" с последующим пробелом в начале строки) лучше не использовать. В остальном — результат не отличается.

      Согласна с вами насчет кода, куда ж без правок.


  1. rumkin
    02.10.2016 05:42

    По-моему, вполне оправданное применение KISS. Но в плане типографики есть недочет, строки растягиваются на всю длину окна, отступы по краям небольшие, для комфортного чтения придется подстраивать ширину окна. Текст из-за этого становится "тягучим", обратите внимание на типографику сайта medium.com, особенно на размер шрифта, высоту строки и отступы.


    1. ValeriaVG
      02.10.2016 11:26

      Большое спасибо, обязательно посмотрю.


    1. xtala
      02.10.2016 13:40

      text-align: justify??? Лебедев негодует и требует смертной кары! :D


      1. ValeriaVG
        02.10.2016 13:41

        Ни на medium.com, ни на the-downpour.com этого нет. Откуда вы это вытащили?


  1. Gibrrr
    02.10.2016 11:24
    +3

    Статья понравилась, как обзор возможных решений для конкретной небольшой задачи.
    Одно «но» — в самой готовой книге наблюдается глюк со скроллом (Chrome): если пролистать книгу до самого конца, а потом пытаться отскроллить вверх, то в определенный момент происходит сброс обратно в конец книги.


    1. ValeriaVG
      02.10.2016 11:25

      Спасибо, а можно подробнее? Мне не удалось повторить проблему


    1. ValeriaVG
      02.10.2016 11:30

      А, нет, удалось, спасибо. Поправлю.


  1. antirek
    03.10.2016 06:36

    Зачем Showdown?
    wintersmith — готовый генератор сайта на основе markdown текстов и jade-шаблонов.


    1. ValeriaVG
      03.10.2016 10:34
      +1

      Статья про Keep It Simple (Silly,Sweetheart,etc), как верно подметили rumkin и Source в комментариях, и вы не первый уже предлагаете использовать что-то, от чего понадобится минимум функций просто потому что оно уже есть / знакомо вам.

      Единственное, что мне нужно было — это преобразовать markdown разметку в html. Showdown это и делает, это и ничего больше.