В этой статье мы продолжаем разработку виджета для работы с короткими заметками. Если вы не читали предыдущую часть, то очень советую бегло её просмотреть. В ней мы подробно описаны постановка задачи и реализована серверная часть виджета, т.е. весь PHP код.
Для того, чтобы виджет заработал нам осталось написать клиентскую часть.
Думаю, очевидно, что для виджета отправка и получение данных должна выполняться с помощью AJAX запросов. Ведь вряд ли кому-то понравиться, если каждая операция с виджетом будет приводить к перезагрузке всей страницы.
Поэтому основную часть клиентской части у нас будет занимать JavaScript код. А чтобы его сократить мы используем библиотеку jQuery с несколькими плагинами.
Кстати, есть демонстрационная страничка с этим виджетом.
DemoИ, как и обещал, выкладываю архив с исходниками.
SourceПрежде всего, рассмотрим разметку страницы (index.html).
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Notes Widget</title>
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
<meta http-equiv="Content-Style-Type" content="text/css" />
<link rel="stylesheet" type="text/css" href="pagestyles.css" />
<link rel="stylesheet" type="text/css" href="widgetstyles.css" />
</head>
<body>
<div id="content">
…. Содержимое страницы…
</div>
<div id="notesWidget">
<div id="notesHeader">Мои заметки</div>
<div id="notes">
</div>
<form id="fAddNote" action="savenote.php" method="post">
<input type="text" id="addNote" name="addNote" value="" />
<input type="submit" name="bAddNote" id="bAddNote" value="" />
</form>
</div>
<script type="text/javascript" src="js/jquery-1.3.2.min.js"></script>
<script type="text/javascript" src="js/jquery-ui-1.7.1.custom.min.js"></script>
<script type="text/javascript" src="js/jquery.jeditable.mini.js"></script>
<script type="text/javascript" src="js/custom.js"></script>
</body>
</html>
В заголовке страницы мы подключаем файлы с CSS стилями (строки 13 и 14). Я вынес все стили, которые относятся к виджету в отдельный файл (widgetstyles.css), чтобы они не путались со стилями основной страницы.
Внутри страницы у нас находится 2 блока: основное содержимое (<div id="content">) и виджет (<div id="notesWidget">).
Первый блок нас не интересует, а вот на втором остановимся подробнее. Он состоит из трёх частей:
— заголовок (<div id="notesHeader">);
— блок заметок (<div id="notes">);
— блок с формой добавления заметки (<form id="fAddNote").
Обратите внимание, что блок заметок не заполнен. Внутрь него мы будем вставлять список заметок, полученный от сервера.
И в конце страницы мы подключаем jQuery, плагины и файл с нашими скриптами.
Сразу же рассмотрим используемые плагины.
1) jQuery UI. Это скорее не плагин, а целая библиотека. На её сайте вы можете выбрать необходимые компоненты и скачать архив с ними. Для нашего виджета нужны Core UI и Draggable. С их помощью мы сможем свободно перемещать виджет по странице.
2) Jeditable. С помощью этого плагина мы будем создавать in-line редакторы. Т.е. сделаем список с нашими заметками редактируемым. При клике по тексту заметки будет появляться поле ввода с помощью которого пользователь сможет изменить текст.
Теперь рассмотрим CSS стили минимально необходимые для работы плагина. Полный файл со стилями вы можете посмотреть в архиве с исходниками. К тому же при использовании виджета его оформление наверняка придется подстраивать под дизайн страницы.
#notesWidget {
position: absolute;
top: 200px;
left: 0;
width: 200px;
height: 300px;
….
}
#notesHeader {
cursor: move;
….
}
#notes {
overflow: scroll;
….
}
Для того, чтобы виджет можно было перемещать по странице, он должен иметь абсолютное позиционирование. При этом необходимо задать его размеры и положение.
Чтобы пользователь без наших подсказок мог догадаться, что это перемещаемый блок, мы изменим вид курсора для заголовка виджета.
И, т.к. заметок может быть много, добавим прокрутку в блок notes.
Теперь переходим к самой интересной части – нашему JavaScript файлу (custom.js).
$(function() {
//делаем виджет перемещаемым
$('#notesWidget').draggable({
handle: '#notesHeader'
, containment: 'parent'
});
//обработчик нажатия на кнопку добавления новой записи
$('#bAddNote').click(function() {
if ($('#addNote').val() != '') {
//сохраняем запись
$.post('savenote.php', {value:$('#addNote').val(), bAddNote:true},
function(noteid) {
//добавляем запись в список
var curDate = new Date();
var noteData = {id:noteid, note_text:$('#addNote').val(),
note_date:curDate.toString()};
var note = $(createListElement(noteData));
$('#notes ul').prepend(note);
$('.edit').editable('savenote.php');
note.children('.remove').click(function() {addRemove(this);});
refreshClasses();
});
}
else {
alert('Вы ничего не написали');
}
return false;
});
//загружаем список записей
$.getJSON('getnotes.php', {}, function(data, status) {
if (data.status == 'OK') {
//формируем список
var notesList = '<ul>';
$.each(data.notes, function(i, note) {
notesList += createListElement(note);
});
notesList += '</ul>';
$('#notes').html(notesList);
//делаем записи редактируемыми
$('.edit').editable('savenote.php');
//добавляем обработчики нажатия на кнопку удаления записи
$('.remove').click(function() {addRemove(this);});
refreshClasses();
}
else {
//вывод сообщения об ошибке
$('#notes').html('<p>Не могу загрузить список записей</p>');
}
});
});
function createListElement(note) {
return '<li>'
+ '<img src="images/removenote.gif" alt="Удалить" class="remove" />'
+ '<div class="edit" id="note_' + note.id + '">'
+ note.note_text + '</div>'
+ '<div class="notedate">' + note.note_date + '</div>'
+ '</li>';
}
function addRemove(element) {
var noteid = $(element).next().attr('id');
//удаляем запись
$.post('removenote.php', {id:noteid}, function() {
//убираем данную запись из списка
$(element).parent().slideUp("slow", function() {
$(this).remove();
refreshClasses();
});
});
}
function refreshClasses() {
var odds = $('#notes ul li:odd');
odds.removeClass('even');
odds.addClass('odd');
var evens = $('#notes ul li:even');
evens.removeClass('odd');
evens.addClass('even');
}
Рассмотрим его подробнее.
Прежде всего, сделаем виджет перемещаемым (строки 3-6). Параметр handle указывает, что блок можно будет перемещать только за заголовок, а containment – запрещает выводить блок за пределы страницы.
Затем, мы создаем обработчик нажатия на кнопку «Добавить» (строки 8-30). В нём мы проверяем, ввел ли пользователь текст новой заметки и отправляем AJAX запрос.
После получения ответа будет вызвана анонимная функция (строки 12-23), которая:
1) создает элемент списка с новой записью (с помощью функции createListElement, её мы рассмотрим чуть ниже);
2) вставляет его в начало общего списка;
3) делает редактируемым (с помощью метода editable);
4) добавляет обработчик нажатия на кнопку «Удалить» (вызывает функцию addRemove);
5) и обновляет цвет фона записей (с помощью функции refreshClasses).
Теперь рассмотрим функцию createListElement (строки 59-66). Её основная задача – создать разметку новой записи.
Запись состоит из текста, кнопки «Удалить» (точнее это обычный рисунок, которому назначается обработчик события click), и даты. Оформление записи выполняется с помощью CSS стилей, но на них я останавливаться не буду, в них ничего примечательного нет, к тому же они в любом случае должны сочетаться с конкретной страницей (если интересно, качайте архив с виджетом).
В разметке записи стоит обратить внимание на два момента.
1) Тексту записи присваивается класс edit (<div class="edit"…). С его помощью мы выбираем элементы для которых создаются in-line редакторы.
2) Этому же элементу мы присваиваем атрибут id в формате (note_№), его значение используется при изменении и удалении заметок.
Следующая функция addRemove (строки 68-79).
Здесь выполняется AJAX запрос на удаление заметки (строка 72) и после этого заметка удаляется из списка. При этом используется эффект slideUp.
Теперь рассмотрим функцию refreshClasses (строки 81-88).
Она работает следующим образом.
1) Находим все нечетные элементы в списке заметок.
2) Устанавливаем для них класс odd и убираем even (если он был установлен).
3) Находим все четные элементы списка и устанавливаем для них класс even.
Стили для классов odd и even указаны в CSS файле (widgetstyles.css). Т.е. с помощью этой функции мы всегда можем обновить расцветку списка после добавления или удаления элементов.
Теперь рассмотрим загрузку полного списка записей (строки 32-56). Она выполняется сразу после загрузки страницы.
Мы отправляем AJAX запрос (с помощью метода getJSON) и после получения ответа формируем HTML список с заметками. Точно также как и при добавлении заметки устанавливаем обработчики нажатия на кнопку «Удалить», делаем записи редактируемыми и обновляем стили.
На этом можно остановиться. Общий принцип работы виджета мы рассмотрели, а если есть вопросы или замечания, пишите в комментариях, постараюсь ответить.
P.S. В архиве с исходниками есть файл notes.sql с помощью которого можно создать таблицу в базе данных.
Интересно почитать:


