Представьте, что пользователи сайта могут сами создавать фотогалереи и публиковать их на сайте с помощью визуального редактора без знаний html. Такую задачу решал на сайте rusland.xyz
Идея сайта в том, что любой путешественник может написать историю своего похода. Такие истории содержат сочетания множества фотографий и небольшого количества текста. В стандартных wysiwyg редакторах есть опция добавить одну картинку (как на habr), но когда фотографий 50+ начинаешь искать другой выход. Что получилось в итоге? Смотрите
Примеры публикаций созданных в этом редакторе:
Далее о том, как это работает и какие инструменты использовались
Как это работает?
В редакторе нажимаем на иконку «вставить фотогалерею», загружаем фотографии на сервер и копируем все ссылки в текстовое поле:
Если все ок, увидим миникартинки и добавляем комментарии:
В визуальном редакторе фотогалерея отобразится отдельным цветовым блоком, вот так:
При нажатии на «Просмотр» получим полноценную фотогалерею:
Что использовалось?
1. Визуальный редактор ckeditor, базовая комплектация
Удобно, бесплатно, хорошее описание с примерами, все на английском. Самое главное — предоставляет разработчику возможность создания собственных плагинов, очень гибко и просто. Хватает двух первых примеров, чтобы понять, как работает и можно делать свой. Один пример даже был на хабре, про встраивание яндекс карт.
2. Фотогалерея fotorama
Красиво, просто настраивается и бесплатно. Оптимально. HTML код фотогалереи выглядит просто:
<div class="fotorama" data-nav="thumbs" data-fit="cover" data-width="100%" data-ratio="700/467" data-max-width="100%">
<img src="img/altay/f7.jpg" data-caption="Чулышман в месте впадение в Телецкое озеро">
<img src="img/altay/h2.jpg" data-caption="Телецкое озеро. Переправляемся в Артыбаш на катере">
<img src="img/altay/h3.jpg" data-caption="Телецкое озеро на закате">
<img src="img/altay/h4.jpg" data-caption="Кафе в Артыбаше, получилось забавно">
<img src="img/altay/h5.jpg" data-caption="Поселок Артыбаш">
</div>
3. Хостинг фотографий на postimage.com
Лучший из тех, что видел. Не требует регистрации, быстрая загрузка, загрузка множества фотографий, хранятся «вечно» и бесплатно. Предоставляют API, загрузку можно встроить на свой сайт, но это за малую плату. Обойдемся пока без этого.
Детали
В ckeditor создаем свой плагин (пример1, пример2). Каждый плагин имеет три составляющих:
- иконка //кнопка в меню редактора
- plugin.js //инициализация плагина
- dialogs/gallery.js //описывает работу плагина
В моем случае plugin.js:
CKEDITOR.plugins.add( 'gallery', {
icons: 'gallery',
init: function( editor ) {
editor.addCommand( 'gallery', new CKEDITOR.dialogCommand( 'galleryDialog' ) );
editor.ui.addButton( 'gallery', {
label: 'Добавить фотогалерею',
icons: 'gallery',
command: 'gallery'
});
CKEDITOR.dialog.add( 'galleryDialog', this.path + 'dialogs/gallery.js' );
}
});
В результате в редакторе появится новая кнопка, при клике на него запускается gallery.js, который отвечает за отрисовку диалогового окна и обработку введенных данных. Основной кусок gallery.js:
CKEDITOR.dialog.add("galleryDialog", function(editor) {
return {
allowedContent: "img[src,alt]",
title: "Галерея",
minWidth: 550,
minHeight: 150,
contents:[{
id: "gallery",
label: "Details",
elements:[
{
type: 'html',
html: '<div id="step1"></div>'
},
{
type: 'html',
html: '<div id="new_data"></div>'
}
]
}],
onOk: function(){
var dialog = this;
getCOM();
var output= '<div id="fororama" class="w3-row foto_cont ckeditor">Фотогалерея сформирована:<ul>';
for(var i=0;i<IMG.length;i++){
output += '<li>'+IMG[i]+' - '+COM[i]+'</li>';
}
output += '</ul></div>'
editor.insertHtml(output);
},
onShow: function() {
init();
}
};
});
Блок elements декларирует, какие элементы должны быть в диалоговом окне. При открытии диалогового окна выполняется блок onShow, где инициализируются переменные, дорисовывается DOM.
При нажатии «Ок» выполняется блок onOk, который обрабатывает введенные пользователем данные и вставляет html код в редактор. В моем примере формирую массив из url картинок, который вставил пользователь в текстовое поле, затем добавляю комментарии. Далее, генерирую блок html и добавляю в редактор. В данном случае это простой список из url и комментариев.
При нажатии на «Просмотр» средствами jQuery обрабатываю специальные блоки div#fotorama… и формирую окончательный html код фотогалереи. Вот и все.
Небольшая хитрость
Пришлось пойти на это, так как мое диалоговое окно получилось сложным и прямым путем реализовать не удалось. У диалогового окна подразумевается фиксированный набор элементов, определенное количество input, select, textarea и тд. Но в моем случае контент зависел от того, сколько картинок добавил пользователь. Поэтому в elements задекларировал два пустых контейнера, куда вставлял нужные элементы средствами jQuery. При нажатии на кнопку, удалял все содержимое и рисовал другой контент.
В завершении
Ckeditor гибкий и удобный редактор, позволяющий разработчикам создавать собственные плагины любой сложности. Таким образом, простые пользователи сайта сами смогут создавать сложные объекты в публикациях без знаний html.
Кто ходил в походы, пишите истории:)
P.S. Не можете комментировать?! Почта указана на сайте. Спасибо
Комментарии (42)
mmjurov
21.07.2016 09:24+1Добавил кнопку в CKEditor в пять строк и рассказал об этом на всю страну. Это, конечно, интереснее, чем про покемонов, но…
nikitasius
21.07.2016 10:46+3Критика:
Грузим все фотки сразу?!fivelife
21.07.2016 11:04+1Да, это самая ценная рекомендация). Спасибо за lazyload
nikitasius
21.07.2016 11:27+1Незачто :-)
В моем случае это
- jquery.2.1.3.min.js
- jquery.lazyload.1.8.4.js
- jquery.masonry.2.1.08.min.js
- classie.js
- AnimOnScroll.js
Каждый div с фоткой находится в своем .
<style type="text/css"> #container.fluid .item { /*width: 33.3%;*/ height: 300px; width: 300px; margin: 3px 0.2% 3px 0.2%; } #container.fluid .item img { display: block; width: auto !important; height: auto !important; opacity: 1; border: 2px solid #333; } </style>
Изначально был вариант только на masonry, но большие галереи (в силу подгрузки всех превьюшек) были неудобны. В итоге был впилен lazyload.
Из-за lazyload на портретных фотках встречается вот такая ерунда
фотки очень близкоfivelife
21.07.2016 11:34Богатый у вас опыт, а можно где-то посмотреть ваши работы?
nikitasius
21.07.2016 12:10+1Богатый у вас опыт, а можно где-то посмотреть ваши работы?
Работы… На lazyload у меня закрытая галерея (семейные фото и видео). Публичная галерея с lazyload (и проект в целом) в процессе написания (музыкальный сайт403 пока что), который засветился вот тут. Так же это опыт в плане галерей и совместимости (чтобы html5 видео играло на айпаде к примеру, конфиги для mencoder).
В плане CSS я использую готовые решения и допиливаю их как позволяет практика и гугл. Из тех, что не стыдно показать (в технич плане и в визуальном) вот. Еще есть другой закрытый сайт, который я публиковать не стану, дабы хабр не закрыли в роскоме :-) Хостится он не у меня, но с технической точки зрения я получил оргазм, пока писал его, галерей там нету.illuzii
21.07.2016 16:13+1напишите подробнее как сделать, чтобы html5 видео играло автоматом на ipad, iphone — некоторое время назад искал — ничего путного не нашел. Спасибо.
nikitasius
21.07.2016 22:06+1напишите подробнее как сделать, чтобы html5 видео играло автоматом на ipad, iphone
кодируем:
если частота звука менее чем 44.1 kHz
for file in *.mov; do /usr/local/bin/mencoder $file -o ${file}.mp4 -vf pullup,softskip,harddup -of lavf -oac faac -af resample=44100 -srate 44100 -faacopts mpeg=4:object=2:raw:br=192 -aid 0 -ovc x264 -sws 9 -x264encopts nocabac:bframes=0:nofast_pskip:psnr:ssim:b_adapt=2:bitrate=2048:8x8dct:deblock:weight_b:threads=4:global_header:me_range=32:nodct_decimate:subq=9:frameref=9:partitions=all:aq_strength=1.0:aq_mode=1:mixed_refs:trellis=2:chroma_me:me=umh;done
Если звук 44.1kHz
for file in *.mov; do /usr/local/bin/mencoder $file -o ${file}.mp4 -vf pullup,softskip,harddup -of lavf -oac faac -faacopts mpeg=4:object=2:raw:br=192 -aid 0 -ovc x264 -sws 9 -x264encopts nocabac:bframes=0:nofast_pskip:psnr:ssim:b_adapt=2:bitrate=2048:8x8dct:deblock:weight_b:global_header:me_range=32:nodct_decimate:threads=4:subq=9:frameref=9:partitions=all:aq_strength=1.0:aq_mode=1:mixed_refs:trellis=2:chroma_me:me=umh;done
А вот как перегнать slowmotion видео с айфона (240 кадров в секунду) в «нормальное» slowmotion:for file in *.mov; do /usr/local/bin/mencoder -fps 30 $file -o ${file}.mp4 -vf pullup,softskip,harddup -of lavf -nosound -ovc x264 -sws 9 -x264encopts nocabac:bframes=0:nofast_pskip:psnr:ssim:b_adapt=2:bitrate=2048:8x8dct:deblock:weight_b:global_header:me_range=32:nodct_decimate:threads=4:subq=9:frameref=9:partitions=all:aq_strength=1.0:aq_mode=1:mixed_refs:trellis=2:chroma_me:me=umh;done
2 Мбит оптимальный битрейт, хотя яблоки едят и 4Мбит.
Вместо mov можно указать другие расширения файлов. Сие работает с айфонами и айпадами, камерой панасоник (mov) и видео с андроида (mp4).
mencoder из пакетов, ffmpeg собранный:
ffmpeg version 2.8.2-1 Copyright (c) 2000-2015 the FFmpeg developers built with gcc 5.2.1 (Debian 5.2.1-23) 20151028 configuration: --prefix=/usr --extra-version=1 --build-suffix=-ffmpeg --toolchain=hardened --libdir=/usr/lib/x86_64-linux-gnu --incdir=/usr/include/x86_64-linux-gnu --enable-gpl --enable-shared --disable-stripping --disable-decoder=libopenjpeg --disable-decoder=libschroedinger --enable-avresample --enable-avisynth --enable-gnutls --enable-ladspa --enable-libass --enable-libbluray --enable-libbs2b --enable-libcaca --enable-libcdio --enable-libflite --enable-libfontconfig --enable-libfreetype --enable-libfribidi --enable-libgme --enable-libgsm --enable-libmodplug --enable-libmp3lame --enable-libopenjpeg --enable-openal --enable-libopus --enable-libpulse --enable-librtmp --enable-libschroedinger --enable-libshine --enable-libsnappy --enable-libspeex --enable-libssh --enable-libtheora --enable-libtwolame --enable-libvorbis --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx265 --enable-libxvid --enable-libzvbi --enable-opengl --enable-x11grab --enable-libdc1394 --enable-libiec61883 --enable-libzmq --enable-frei0r --enable-libx264 --enable-libopencv
illuzii
21.07.2016 22:18+1я понял, это не совсем то, что я хотел. Я думал, что у вас получилось решить проблему, чтобы если пользователь открыл сайт со встроенным видео — видео играло на автомате сразу на iPad, iPhone.
nikitasius
21.07.2016 12:27+1Кстати из той статья про число 60: http://jsfiddle.net/nathando/s3KPn/4/ — рабочий пример с lazyload.
Только у меня div в <li> находятся, так структура «ощущается» :-)
alexey-m-ukolov
21.07.2016 11:15+1У нас на аналогичном проекте эта задача решена вот так:
Скрин, 2 Мбalexey-m-ukolov
21.07.2016 11:22+1Не ради пиара, а для удобства, оформлю ссылку правильно. Ожидал, что парсер комментариев автоматически это сделает.
http://tripteam.org/reports/20-pohod-na-manpupuner-i-per-dyatlova-severnyi-uralfivelife
21.07.2016 11:25+1Так лучше)
alexey-m-ukolov
21.07.2016 11:28+1Я думаю, что мы пойдём по схожему пути с редактором.
У нас только немного сложнее функционал, как видите: есть и видео, а в фотогалерее можно выбирать главную фотографию и менять их порядок, поэтому и встроиться в какой-то готовый редактор будет сложнее.fivelife
21.07.2016 11:32Интересный у вас сайт, буду знать) Спасибо
Без проблем можно отмечать главные фотографии галереи. Это и реализую после lazyload)
nikitasius
21.07.2016 11:34+1Скрин, 2 Мб
У вас не только скрин на 2 Мб.
Ваша галерея при старте съела 33.5 метра траффика, подгрузив полные фотки.
Кстати, зачем сырбор с /abc/efg/photo1.jpg? Чем вам добавление sha1 хеша не угодило?
Папка = галерея, удобнее в файлах рыться (если приспичит)
/orig/IMG_0860.JPG_20160617195039.c195f3a9f40850b186c1d6407b4046bb0c23ac53.jpg
— не такой уж и страшный путь.
*exif
*sha1alexey-m-ukolov
21.07.2016 11:46+1> Ваша галерея при старте съела 33.5 метра траффика, подгрузив полные фотки.
Да, это одна из проблем. Слайдер глючил с ленивой загрузкой, а разбираться времени нет, поэтому отключили её и реализовали вместо этого последовательную загрузку, чтобы страница при открытии хотя бы не тормозила.
А по поводу полных фоток — превью там никаких нет, поэтому «неполных» фотографий быть в принципе не может.
> Кстати, зачем сырбор с /abc/efg/photo1.jpg? Чем вам добавление sha1 хеша не угодило?
Вот это чистой воды bike-shedding. Работает и работает, какой сырбор, зачем менять? Это вообще сжатые и обработанные файлы, не оригиналы.
> не такой уж и страшный путь
Путей бояться — в DevTools не ходить.nikitasius
21.07.2016 12:15+1Вот это чистой воды bike-shedding. Работает и работает, какой сырбор, зачем менять? Это вообще сжатые и обработанные файлы, не оригиналы.
Согласен, у каждого свои фломастеры. Хз, мне было проще добавить хеш и все складировать в одну папку, для защиты от подбора и скачивания каким-нить менеджером.alexey-m-ukolov
21.07.2016 12:25+2Вообще, это стандартная техника для относительно равномерного распределения файлов по директориям, поскольку при очень большом количестве файлов в одной директории операции с ней могут занимать очень долго.
От перебора эта система защищена не хуже — индекс директории посмотреть нельзя, а угадывать два уровня вложенности с неизвестным названием файла внутри можно очень-очень долго.
Но вообще, я уже и сам не помню почему сделано именно так.nikitasius
21.07.2016 12:36Вообще, это стандартная техника для относительно равномерного распределения файлов по директориям, поскольку при очень большом количестве файлов в одной директории операции с ней могут занимать очень долго.
Надо очень много файлов в директории иметь, много, много больше, чем человек нафоткает на месяц.
В любом случае, я только за критику подгрузки всего и разом, с технической стороны ничего не имею против :-)
Nadoedalo
21.07.2016 13:14+1Просто? Вы вот ЭТО называете просто?
Где считывание метаданных? Время, координаты, ближайшее название объекта(типа «гора Эверест, высота 500 метров») для дефолтного коммента? Почему нельзя по фоткам посмотреть маршрут? Вообщем мильйон вариантов чего можно было бы ещё сделать так что бы было ВАААУ.
Ну вообщем очередной слайдер на jquery. Тысячи их, и многие попроще.fivelife
21.07.2016 13:19Примеры?
Nadoedalo
21.07.2016 14:26Примеры попроще? Или примеры того как можно сделать лучше?
Кто из нас собирается сделать сервис который удобен клиенту?
Метаданным сто лет в обед и удивительно что Вы хотя бы в планы на будущее не вписали их парсинг и отображение.
http://www.panoramio.com/ вот например, первое что нагуглил по фотоаппараты с GPS
Вообщем с моей колокольни статья — смотрите, я написал jquery-слайдер и хочу с него сделать сервис. Извини конечно, но не взлетит.fivelife
21.07.2016 14:51Колокольня вещь хорошая. Интересные идеи фиксирую, будут еще — буду рад. Спасибо)
almkhaj
21.07.2016 14:19+2Я так понимаю — это больше реклама сайта. Сами истории мне понравились, только жалко, что их «кот наплакал»…
fivelife
21.07.2016 14:46Все по делу говорите ребята) Сайт запустился на этой неделе, минимальный функционал, который хотели сделать — реализовали. Вот теперь начнем публиковать истории и прикручивать удобства.
Мы не реализовывали (писали) слайдер, а взяли готовое решение. Мы сделали интерфейс, который позволяет любому пользователю формировать свою галерею и публиковать на сайте.
Toshi
21.07.2016 15:10«Представьте, что пользователи сайта могут сами создавать фотогалереи и публиковать их на сайте с помощью визуального редактора без знаний html.»
Это бы неплохо звучало, лет так 10-15 тому назад… Но это еще полбеды. Про безопасность веб-проектов почитайте обязательно, а я пока письмо Вам на почту с описанием проблемы скину.
snnwolf
21.07.2016 15:34Хорошая идея, хоть и требует доработки. Вставлю свои пять копеек.
var output= '<div id="fororama" class="w3-row foto_cont ckeditor">Фотогалерея сформирована:<ul>';
А если я заходу вставить не одну галерею? Понимаю, что jquery схавает и не подавиться, но w3c, если мне не изменяет память, рекомендует использовать уникальные id для элементов.
fivelife
21.07.2016 15:49-1Да, все правильно. Поэтому использую такое сочетание:
var rand = Math.floor(1000000*Math.random()); var output='<div id="fororama'+rand+'" class="w3-row foto_cont ckeditor">Фотогалерея сформирована:<ul>';
Этот момент опустил, чтоб не усложнять. Спасибо, что заметили)
cema93
Так ждал в конце статьи ссылку на github…