Finar.ru
web.finar.ru
video.finar.ru
Темы для BootstrapNew!

Как работать с формами и добавить функционал комментариев к PmWiki?

Автор: Филипп Казаков, дата: 2011-05-08, просмотров 8499
Тэги

темы: PmWiki

Комментарии - это html-формы и их обработка, а в PmWiki есть два принципиальных подхода к работе с формами:

  1. в которых результат обработки сохраняется в отдельной сущности;
  2. в которых результат обработки просто записывается в контент существующей страницы.

Исходя из принципа наименьшего сопротивления, рассмотрим второй - более простой случай.

Есть два рецепта для решения этой задачи: Cookbook:CommentBoxPlus  и его производные и Cookbook:PmForm . Первый рецепт более популярен, второй находится в стадии бетатестирования, однако написан самим разработчиком PmWiki в соответствии с концепцией ядра системы и от того ближе к его философии и более конфигурабелен. Я выбрал второй вариант.

Процессинг форм с записью в контент страницы: PmForm

Установка PmForm и капчи

Установка формы стандартна. Интерес вызывает только последняя строчка, где описывается процессинг формы с именем savedata: результат обработки формы записывается в страницу ее вызова, форма генерируется по шаблону dataform, а результат форматируется по шаблону datapost (шаблоны описаны в Site.LocalTemplates):

# добавляем комментарии:
include_once("$FarmD/cookbook/pmform.php");
$PmForm['savedata'] = 'saveto={$FullName} form=#dataform fmt=#datapost';

Сразу после установки рецепта Cookbook:Captcha , капча начинает по-умолчанию применяться ко всем формам, которые только найдет на сайте. Поэтому отредактировать страницу, например, станет невозможно - нужно будет вводить код. Нам не нужна защита от самих себя, а только от посетителей сайта, заполняющих форму комментариев. Забегая вперед, вот как это реализуется (другие предложения со страницы рецепта , почему-то не зарабаботали):

# добавляем капчу:
if ($action == 'browse' || $action == '' || $action == 'pmform')
   $EnablePostCaptchaRequired = true; #требовать ввода для всех форм страницы только при перечисленных действиях
include_once("$FarmD/cookbook/captcha.php");

Вызов на странице

Чтобы вызвать форму на странице, воспользуемся синтаксисом (:pmform savedata:), где 'savedata' описана в config.php выше. Это надо будет поместить в GroupFooter, например, обрамив условием (:if exists {$FullName}:) (чтобы форма не выводилась на несуществующей странице). Синтаксис (:messages:) отвечает за обратную связь с пользователем - сюда будут выводиться ошибки, если они возникнут при заполнении формы (неверная капча, не заполнено обязательное поле), ее стоит поместить в GroupHeader.

Важное замечание: если по-умолчанию ваш сайт имеет пароль на редактирование, то перемещение (:pmform savedata:) в GroupFooter или GroupHeader автоматически приведет к тому, что анонимусы потеряют возможность добавлять комментарии. Логика здесь PmForms такая: скрипт дает возможность изменять страницы пользователям с правами "read", но только на тех страницах, где собственно установлена форма. Иначе, путем подмены POST-запроса, теоретически, можно будет через форму осуществить запись в любую страницу сайта без прав на то. ОК, но только как же быть, если вызов формы находится в GroupFooter? Не знаю, что придумает PM, а пока он не придумал ничего, а я - ничего лучше, как не параноидальничать и вырезать эту проверку из исходника pmform.php вот так:

# 4 lines below Finar commented
#  if (!@$mark) {
#    $page = RetrieveAuthPage($saveto, 'edit', true);
#    if (!$page) return '$[Edit permission required]';
#  }

Выход не очень хороший, зато действенный.

Шаблон формы

Самое хитрое: создаем, собственно, саму форму на системной странице шаблонов Site.LocalTemplates. Вот как это выглядело на момент написания статьи:

  1. [@
  2. [[#dataform]]
  3. (:div class="comment_post_block":)
  4. ''[++(:toggle show="Оставить комментарий " hide="Оставить комментарий:" commentpost:)++]''
  5. (:div2 id="commentpost" class="comment_post_form":)
  6. (:input pmform target=savedata :)
  7. (:input default request=1 :)
  8. (:input hidden author "{*$LastModifiedBy}" size=25 :)
  9. (:input hidden title "{*$Title}" size=25 :)
  10. (:input hidden ctime "{*$Created}" size=25 :)
  11. (:input hidden csum "новый комментарий" size=25 :)
  12. (:input hidden description "{*$Description}" size=25 :)
  13. (:input textarea text rows=5 cols=50:) \\
  14. Ваше имя: (:input text name:) \\
  15. {$Captcha} -> (:input captcha:)
  16. (:input submit name=post value="$[Отправить]" :)
  17. (:input end:)
  18. (:div2end:)
  19. (:divend:)
  20. [[#dataformend]]
  21. @]

Первые пять, а также 19 и 20 строчки относятся к внешнему представлению в виде кнопки и двух слоев, один из которых вложен в другой. Это оформление, к делу не имеет отношения. Следующие две строчки - инициализация формы, детали можно узнать на странице рецепта.

Особый интерес представляют строчки с 8 по 12, включительно. Дело в том, что почему-то и PmForm, и CommentBox при добавлении поста на страницу не просто дописывают новый блок информации в контент, но переписывают всю страницу, удаляя при этом все переменные страницы (PV), которые на ней присутствовали до того! Это кажется очень странным и не логичным, и, наверное, будет как-то пофиксено и учтено при дальнешей разработке PmForm, по крайней мере запрос я отправил.

Чтобы обойти данную особенность, в 8-12 строчках все переменные страниц, введенные на сайте, считываются с текущей страницы и записываются в форму, в скрытом виде. Также туда записывается значение для csum, которое на моем сайте особо не используется, но удобно для отслеживания событий на сайте на странице Site.AllRecentChanges, например.

Строчки 13-17, по-моему, очевидны: это собственно и есть простое и прозрачное, практически визуальное программирование формы. Именно ради этой простоты мы и прошли все предыдущие козни.

Шаблон поста

  1. [@
  2. [[#datapost]]
  3. (:template defaults where=bottom :)
  4. (:template require name errmsg="$[Незакомментилось: представьтесь, пожалуйста]":)
  5. (:template require text errmsg="$[Незакомментилось: напишите что-нибудь]":)
  6. (:nl:)>>messagehead<<
  7. !!!!!{$$name} &mdash; [-{$$CurrentTime}-]
  8. >>messageitem<<
  9. {$$text}
  10. >><<
  11. [[#datapostend]]
  12. @]

Здесь 3 строчка описывает координаты для помещения комментария, важно указать значение "bottom" или "top", если вы собираетесь размещать вызов формы в GroupFooter, ведь для возможных значений "above" или "below" (над или под собственно формой) у скрипта не будет привязки, так как вызова формы в этом случае на самой странице не будет. 4 и 5 строчки перечисляют поля, обязательные для заполнения и текст, который выведется в (:messages:), если они не будут заполнены. 6-10 строчки - это формат результирующего поста, который, собственно, и будет записан на страницу.

Комментарии готовы.

ToDo-лист

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

  1. факт всякого постинга с любым результатом должен приводить к редиректу на якорь #commentform этой же страницы, стоящий прямо перед вызовом формы, где и должен отображаться результат операции. Это более юзабильно, чем размещение (:messages:) в GroupHeader.
  2. в формы надо научиться внедрять javascript, чтобы они заполнялись тектом по умолчанию (например, "ваше имя"), исчезающим при наведении фокуса
  3. ну и, самое главное, хотелось бы переделать комментарии так, чтобы они умели просто добавлять новый блок информации на страницу, не трогая существующие переменные страницы вообще. Существующее решение хоть и работоспособно, но архитектурно криво и сомнительно с точки зрения безопасности.
  4. выход из положения с правами при вызове из GroupFooter

Оставить комментарий 


Ваше имя:
->