Всем привет!
В ходе работы над одним дополнением, которым поделюсь позже, вспомнилась идея: "а не плохо было бы перед публикацией записи посмотреть что получится". Многие ресурсы имеют такой функционал в своем комплекте, а чем инстант хуже?))Сначала двигался по пути реализации дополнительного функционала указанного выше дополнения, затем посмотрел в сторону отдельного компонента и, наконец, остановился на хаке системного компонента content. При удачном стечении обстоятельств, надеюсь опубликовать pull request. Ну а что это за обстоятельства — читаем ниже...
Этот пост скорее представляет собой развернутую тему для обсуждения сообществом "как лучше сделать" некоторые моменты в функционале предпросмотра создаваемых или редактируемых записей.
Ближе к телу:
1. Создаем файл ..\system\controllers\content\actions\item_preview.php и кидаем в него следующий код
<?php class actionContentItemPreview extends cmsAction { public function run($data){ $item['ctype_name'] = $ctype['name']; 'id' => $this->cms_user->id, 'nickname' => $this->cms_user->nickname ); if ($ctype['is_cats'] && $item['category_id'] > 1){ $item['category'] = $this->model->getCategory($ctype['name'], $item['category_id']); } // Получаем поля для данного типа контента $fields = $this->model->getContentFields($ctype['name']); // Парсим значения полей foreach($fields as $name=>$field){ $fields[ $name ]['html'] = $field['handler']->setItem($item)->parse( $item[$name] ); // <- предложение внести флаг is_preview (полезно для нестандартных полей) } // Получаем поля-свойства if ($ctype['is_cats'] && $item['category_id'] > 1){ $props = $this->model->getContentProps($ctype['name'], $item['category_id']); $props_values = $this->model->getPropsValues($ctype['name'], $item['id']); } // Рейтинг if ($ctype['is_rating'] && $this->isControllerEnabled('rating')){ $item['rating_widget'] = cmsCore::getController('rating')->getWidget(1, false, false); } // Формируем теги if ($ctype['is_tags']){ } 'item' => $item, 'ctype' => $ctype, 'fields' => $fields, 'errors' => false, 'html' => $html )); } }
для первого добавляем перед $item = $this->model->addContentItem($ctype, $item, $fields); (205 строка), для второго $item = $this->model->updateContentItem($ctype, $id, $item, $fields); (182 строка)
// Блок предпросмотра if ($this->request->has('is_preview')){ }
// Запрос предпросмотра с ошибками заполнения полей if ($errors && $this->request->has('is_preview')){ 'errors' => $errors, 'message' => LANG_FORM_ERRORS )); }
'action' => '', 'method' => 'post', 'toolbar' => false, 'event' => "content_{$ctype['name']}_form_html", 'do' => $do, 'id' => $do=='edit' ? $item['id'] : null ) ), 'append_html' => html_button('Предпросмотр', 'preview', "icms.content.getPreview();", array('class'=>'button-preview', 'data-description' => 'Предварительный просмотр')), // <- Вот эта строка !!! ), $errors);
data-description — необходим чтобы передать текст в js-скрипт на фронтенде. Есть и другие способы, но я выбрал этот.
Добавляем немного стилей в конец файла ..\templates\default\css\theme-content.css
#preview { border: 5px solid #d6d6d6; padding: 10px; margin: 7px 0 20px; } .preview-title { margin-bottom: 10px; font-size: 12px; color: #aaa; } input.button-preview { float: right; background: #dedede; color: #333; } input.button-preview:hover { background: #e7e7e7; }
this.getPreview = function() { var preview_title = $('.button-preview').data('description'); // объект формы контента var $form = $('.button-preview').closest('form'); var url = $form.attr('action'); // получаем данные из формы var form_data = icms.forms.toJSON($form); // добавляем данные из нестандартных полей // $('[data-preview]', $form).each(function(i, element){ // var key = $(element).closest('.field').attr('id').substr(2); // form_data[key] = $(element).data('preview'); // }); form_data.submit = true; // флаг события submit form_data.is_preview = true; // устанавливаем флаг предпросмотра $.post(url, form_data, function(result) { $('#preview').remove(); // Очищаем старые сообщения об ошибках $('.sess_messages').remove(); $('.error_text', $form).remove(); $('.field_error', $form).removeClass('field_error'); var errors = result.errors || false; // если есть ошибки заполнения полей... if (errors instanceof Object) { // ...выводим их for (var key in errors) { if (key === 'length' || !errors.hasOwnProperty(key)) continue; $('#f_'+key) .addClass('field_error') .prepend('<div class="error_text">'+errors[key]+'</div>'); } // добавляем сообщение о наличии ошибок на форме $('#body').prepend('<div class="sess_messages"><div class="message_error">'+result.message+'</div></div>'); return; } // удаляем скрипты кроме подключаемых по ссылке var html = $(result.html.bold()); html.find('script:not([src])').remove(); // выводим html страницы $form.before('<div id="preview"><div class="preview-title">'+preview_title+'</div>'+html.html()+'</div>'); }, 'json'); }
Вопросы и предложения
Как я написал в начале поста есть ряд моментов которые требуют обсуждения:1. Сторонние разработчики могут делать и делают специфические поля, которые рендеряться по своему внутреннему механизму вывода контента (например в моем компоненте Опросы). Для этих целей предлагаю ввести флаг is_preview в функцию ..\system\core\formfield.php parse($value) -> parse($value, $is_preview=false). Соответственно по этому флагу можно особым образом выводить html-содержимое "нестандартных" полей.
2. Для аналогичных целей с п.1. можно добавить обработчик получения данных поля из атрибута data-preview. В js-скрипте выше этот участок кода закомментирован. Вопрос для разработчиков — нужно ли оно? Или достаточно флага is_preview, или всё же добавить еще возможность формирования данных на фронтэнеде.
3. В представленном решении есть одна большая проблема — подключение стилей CSS! Если поле выводит данные, которые в своем составе содержат стили подключаемые, например, через addCSS(...), то они в текущем виде никак не подгружаются, и соответственно такие данные криво отображаются в области предпросмотра. Тоже самое происходит и с подключаемыми скриптами, функции которых могут запрашиваться при рендере контента, поэтому внутренние скрипты я вычищаю из результатов предпросмотра.
4. Очень проблематично получить ID формы добавления/редактирования контента! Эту проблему я обошел указанием вместо id непосредственно тега form, но механизм получения id был бы не лишним))
5. И в заключении интересует вопрос куда лучше выводить области предпросмотра?
Сейчас, по примеру хабра, я показываю превьюшку вверху формы (позиция 1). Может стоит задействовать позицию 2 или 3? Или выводить в модальном окне, или еще какие варианты?
Демо здесь
demo@demo.ru / 123456
UPD 3 вопрос можно решить заменой подключения стилей с addCSS(...) на addCSSFromContext(...). Также и для js — addJSFromContext($file, $comment='')
Реклама #
Алексей Т 8 лет назад #
Я думаю позиция 2 будет самое то - посмотрел - сохранил.
Jestik 8 лет назад #
Val 8 лет назад #
Поменял вывод предпросмотра на демо во вторую позицию.
Согласен, здесь более логично увидеть превьюшку.
WebMan 8 лет назад #
При размещении и в позиции 1, и в 2, всё равно приходится прокручивать и область предпросмотра, и форму до кнопки "Сохранить". Также нужно учитывать, что обычно предпросмотр используется там, где текст по высоте больше, чем форма. Поэтому на мой взгляд, правильнее оставить предпросмотр в позиции 1. Посмотрел весь текст сверху вниз, что-то решил изменить и форма уже сразу перед глазами - удобно и без лишних движений. Если всё подходит, то кнопка "Сохранить" тут же под формой - прокручивать если и нужно, то невысокую форму и вниз, а не большой текст и в обратном направлении. А если делать в п.2, то для изменения нужно прокручивать весь текст обратно до верха, потом прокрутить форму и там менять в форме - это нелогично, это лишние манипуляции и неудобно.
Да и привычнее видеть кнопку "Сохранить" под формой ввода, а не под текстом. Ведь сохраняем мы не просмотренный текст, а то, что набрано в форме. Если предпросмотр будет в п.2, то при изменении текста в форме и неизменности текста предпросмотра могут быть непонятки: что мы сохраняем, просмотренный текст, раз кнопка "Сохранить" под ним, или набранное в форме? Так что и с этой точки зрения удобнее делать предпросмотр сверху в позиции 1, как Val сразу интуитивно и сделал.
Val 8 лет назад #
WebMan, а как вы смотрите на модальное окно предпросмотра?
Zau4man 8 лет назад #
Какая разница пользователю как будут выглядеть теги, или заголовок. Или прикрепленный к материалу файл. Или карта из поля карты.
Избавьте разработчиков и себя от ненужной возни. Сделайте предпросмотр для поля html.
Val 8 лет назад #
Примеры таких нестандартных полей, как уже упоминал в посте, мои опросы - в форме редактирования пользователь видит менеджер опросов, т.е. список их заголовков, а в записи - уже выводятся полноценные вопросы с вариантами ответов. Или недавно опубликованное поле Loadыря "Список количества", и множество других подобных полей. Это примеры полей которые интересно посмотреть в "препродакшене", т.е. перед публикацией записи.
kirkr 8 лет назад #
Можно сделать предпросмотр и сейчас, не ставя публиковать в статьях (типа черновик). Но если решение будет универсальным, то бует удобно. даже пускай если будет открываться в отдельном окне.
Val 8 лет назад #
Вы за вариант модального окна?
Val 8 лет назад #
Отсюда вопрос: куда девать эту пимпу?
Также есть предложение при включенной опции премодерации, переименовывать кнопку "Сохранить" в "Отправить на модерацию", тогда и надпись о публикации после проверки можно убрать совсем, или выводить ее в виде хинта под кнопкой. Получается более наглядный UX))
GluK 8 лет назад #
Val 8 лет назад #
Вот такой вариант мне кажется неуместным:
А как поместить "Предпросмотр" справа от "Сохранить" (не выравнивание по правому краю, а следом за сохранить) без костылей я пока не знаю.
Val 8 лет назад #
Def 8 лет назад #
Val 8 лет назад #
Зайдите на демо-сайт и потестируйте =)
vikont 8 лет назад #
Есть только пункт 1 описания со Спойлером и все!
Val 8 лет назад #
vikont 8 лет назад #
В отдельный компонент когда завернете?
Хорошее дело. А вот Хаки только головняк добавляют.
vikont 8 лет назад #
Перенес настройки из Дефолтного шаблона в свой кнопка появилась, но не работает!
Возможно неправильно прописал код js/ Куда лучше всего вносить код из 4-го пункта и в какой шаблон?
Val 8 лет назад #
Зайдите на демосайт и посмотрите как там реализовано.
vikont 8 лет назад #
Поэтому будет проще, если как выше напишите что и куда вставить.
Надеюсь когда все получится, сделать патч к Компоненту Мои патчи, чтобы другие могли воспользоваться Хаком без головной боли.
Думаю именно по этой причине не появилось много заинтересованных. Сразу не пошло...
Val 8 лет назад #
Попробуйте еще раз на дефолтном шаблоне чистого движка. Если получится, то нужно искать проблему в стороннем шаблоне (возможно что-то не вписали или не туда вписали и, например, просто не выводится кнопка, а функционал присутствует) ?
Про демосайт, я имел ввиду, посмотреть через devtools что и как, например, в скриптах и html-коде страниц. Но там все ровно так как и описано в тексте поста.
Обращайтесь в личку по возникшим трудностям, победим их вместе
Val 8 лет назад #
vikont 8 лет назад #
vikont 8 лет назад #
Сам предосмотр нужен! Конечно можно без него обойтись, да и без вилок обходятся..., но макароны удобнее вилкой...
Вот этот предосмотр, когда он есть, будет использоваться некоторыми на постоянной основе! Остальные ихредка по ходу жизни!
Так что в коробочку его и никаких хаков! Будет приятное расширение функционала с нуля.
Val 8 лет назад #
p.s. а на счёт "коробки"... в последнее время какая-то тенденция нехорошая любое дополнение тянуть в коробку. Вот мне оно нужно, и вам и еще 5-10 пользователям, но абсолютному большинству нет! Так что до коробки надо еще дорасти =)
Но почва подготовлена, и семена посажены...
Михаил 8 лет назад #
1 Использую редактор markitup, и в предпросмотре нет абзацев http://joxi.ru/p27R9Dgig6pDm7 Как это можно исправить?
2 Возможно ли, чтобыпосле того, как первый раз нажата кнопка Предпросмотр, вместе с формой (и после нее) добавилась еще одна кнопка Сохранить?
Val 8 лет назад #
2. Если я правильно вас понял, можно добавить в конец функции getPreview() следующий код:
Михаил 8 лет назад #
Val 8 лет назад #
Михаил 8 лет назад #
Владимир 8 лет назад #
Bonefacei 8 лет назад #
Саня 6 лет назад #
ParadoX 6 лет назад #
Vlad 2 года назад #
На 2.15 актуально?
Def 1 год назад #
тоже интересно