В предыдущих частях (1, 2, 3, 4, 5, 6, 7, 8, 9) мы создали практически работоспособную систему отслеживания ошибок.
«Практически» в данном случае означает, что на данный момент у пользователя отсутствует возможность отвечать на комментарии. Т.е. можно оставить только комментарий 1-ого уровня (комментарий к багу).
Сегодня мы исправим этот недостаток.
Напомню, что на стороне сервера поддержка вложенных комментариев уже реализована. В базе данных (таблица comments
) есть поле parent_id
в котором хранится id
родительского комментария.
Кроме того, метод addComment
(модели mcomments
) принимает массив с данными комментария, одним из полей которого является parent_id
.
И, наконец, метод addcomment
контроллера читает этот параметр из массива $_POST
и передает его модели.
Таким образом, нам остается обеспечить возможность посетителю указывать на какой комментарий он хочет ответить.
В принципе, реализовать эту возможность можно без JavaScript. Но при этом пользоваться ей будет очень не удобно. Нам придется сформировать выпадающий список с перечнем id
всех комментариев к данному багу, а посетитель вручную будет выбирать на какой он хочет ответить. Не думаю, что кому-то понравиться работать с такой формой.
Ситуация совершенно меняется если использовать JavaScript. Под каждым комментарием мы создадим ссылку «Ответить». При клике по ней форма будет перемещаться под выбранный комментарий. Id
этого комментария мы сохраним в скрытом поле формы.
Таким образом, детали механизма работы со вложенными комментариями будут совершенно незаметны пользователю. Кстати, комментарии в этом блоге работают именно таким образом.
Переходим к реализации.
Прежде всего, рассмотрим разметку формы.
<form id="fAddComment" method="post" action="http://www.bugtracker.l/bugtracker/addcomment"> ... <div> <input type="hidden" value="" id="parent_id" name="parent_id"/> </div> <p> <input type="submit" value="Отправить" class="addcomment" id="addcomment" name="addcomment"/> </p> </form>
Чтобы сделать её немного понятнее я опустил поля, которые не имеют отношения ко вложенным комментариями. В данном случае интерес представляет только одно поле — parent_id
. В нём хранится id
комментария, на который отвечает посетитель. Пустое значение в этом поле соответствует комментарию к багу (первый уровень).
Теперь подключим два JavaScript файла. Первый – библиотека jQuery
, второй – файл с нашими функциями.
<script type="text/javascript" src="<?php echo base_url(); ?>js/jquery-1.3.2.min.js"></script> <script type="text/javascript" src="<?php echo base_url(); ?>js/main.js"></script>
Примечание. Я разместил этот код в конце страницы (в представлении footer.php
).
Добавляем ссылку «Ответить» внизу каждого комментария. Для этого открываем шаблон комментариев (\application\views\comment_tpl.php
)
<div class="comment depth-{depth}" id="comment-{id}"> <p class="commentInfo"> <span class="commentAuthor">Автор: {uname}.</span> <span class="commentDate">Дата: {comment_date}.</span> </p> <p class="commentDescription">{description}</p> <p class="replyComment"><a href="#">Ответить</a></p> <?php if ($this->redux_auth->logged_in()) { echo '<p class="deleteComment">'.anchor('bugtracker/deletecomment/{id}', 'Удалить').'</p>'; } ?> </div>
Ссылка создается в строке 7. Тут может возникнуть вопрос: «Почему в параметрах ссылки мы не указываем id
комментария?». Дело в том, что с помощью jQuery мы можем легко получить родительский div
(строка 1) и прочесть его атрибут id
, в котором записан id
комментария.
Теперь рассмотрим функцию, которая перемещает форму (файл main.js
).
$(function() { //перемещаем форму $(".replyComment a").click(function() { var comment = $(this).parent().parent(); var commentId = comment.attr("id"); var id = Array(); //в id[1] будет сохранен id комментария на который нужно ответить id = commentId.split('-'); //перемещаем форму $("#fAddComment").appendTo(comment); //устанавливаем значение в поле parent_id $("#parent_id").val(id[1]); //добавляем ссылку "Отменить комментарий", клик по ней возвращает форму вниз страницы cancelComment = $("<p class=\"cancelComment\"><a href=\"#\">Отменить комментарий</a></p>"); cancelComment.prependTo($("#fAddComment")); var cancelLink = cancelComment.children("a").get(0); $(cancelLink).click(function() { $("#parent_id").val(""); $(this).parent().remove(); $("#fAddComment").insertBefore("#footer"); return false; }); //предотвращает "скачки" страницы return false; }); //подтверждение удаления бага $(".deleteBug a").click(function() { return confirm("Точно удалить?"); }); //подтверждение удаления комментария $(".deleteComment a").click(function() { return confirm("Будет удалена ветка комментариев начиная с данного. Удалить?"); }); });
Рассмотрим как она работает.
Прежде всего, мы находим все ссылки, которые находятся внутри элементов с классом «replyComment
» (т.е. наши ссылки «Ответить»), и назначаем им обработчик события onclick
(строка 3).
При клике по ссылке начинает выполняться функция (строки 3-30). Алгоритм тут следующий.
1) Получаем родительский div
и читаем его атрибут id
(строки 4, 5).
2) Вырезаем из него номер комментария (с помощью функции split
, строка 8).
3) Перемещаем форму. Для этого мы используем функцию appendTo
из библиотеки jQuery. Элемент, к которому нужно добавить форму мы получили на 1-ом шаге.
4) Записываем значение в поле parent_id
(строка 14).
5) Создаём ссылку «Отменить комментарий» и размещаем её в начале формы. Клик по ней вернет форму в исходное положение.
Без этой ссылки вернуть форму в исходное положение можно будет, только обновив страницу, а сделать это догадаются не все 😉 .
6) Находим ссыку «Отменить комментарий» и назначем ей обработчик события onclick (строки 19-26).
7) В этом обработчике мы сбрасываем значение скрытого поля parent_id, удаляем ссылку «Отменить комментарий» и возвращаем форму в исходное положение.
Как видите, принцип работы достаточно простой. А благодаря jQuery вся функция занимает меньше 20 строк (если убрать комментарии и пустые строки).
В завершение мы выполняем ещё два действия.
Назначаем обработчик события onclick
для всех ссылок «Удалить» (строки 33-40). Теперь при попытке удаления бага или комментария (в администраторском режиме) будет появляться диалог с просьбой подтвердить действие.
На этом я закончу эту часть.
Демо версия баг трекера.
Если у вас есть желание поэкспериментировать я выложил демо версию баг трекера. Логин: vvv@ddd.sss
, пароль: 111
.
Можете не задумываясь вставлять или удалять любые данные, все равно у меня есть бекап базы 😉
Скачать
Также можно скачать архив с исходниками.
И, конечно, вы можете поделиться своими впечатлениями в комментариях 😉