Bug Tracker: ответы на комментарии (часть десятая)

Владимир | | CodeIgniter, HTML, JavaScript, MySQL, PHP, Web разработка.

В предыдущих частях (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.
Можете не задумываясь вставлять или удалять любые данные, все равно у меня есть бекап базы 😉

Скачать

Также можно скачать архив с исходниками.

И, конечно, вы можете поделиться своими впечатлениями в комментариях 😉