Создаём виджет для хранения заметок. Часть 2.

Владимир | | Ajax, CSS, HTML, JavaScript, Web разработка.

notes widget

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

Интересно почитать:

Закат Веба?

  • Serator

    В продолжении темы удобства к виджету (по сути любому), неплохо бы прикрутить кнопку для сворачивания вплоть до размеров копеечной монетки. А в остальном все выглядит законченным 🙂

    • Согласен. Нужно будет доделать. Может кроме сворачивания добавить перемещение свернутого виджета к краю экрана?

      • Serator

        Не думаю, что это будет удобно, ибо пользователь изначально расположит виджет так, как ему удобно. Возможно будет лучше, если, наравне с содержимым, виджет будет запоминать свое местоположение + position:fixed (опционально) для сохранения позиции при прокрутке.

        • Спасибо за советы! Я поэкспериментирую.

  • Serator

    В продолжении темы удобства к виджету (по сути любому), неплохо бы прикрутить кнопку для сворачивания вплоть до размеров копеечной монетки. А в остальном все выглядит законченным 🙂

    • Согласен. Нужно будет доделать. Может кроме сворачивания добавить перемещение свернутого виджета к краю экрана?

      • Serator

        Не думаю, что это будет удобно, ибо пользователь изначально расположит виджет так, как ему удобно. Возможно будет лучше, если, наравне с содержимым, виджет будет запоминать свое местоположение + position:fixed (опционально) для сохранения позиции при прокрутке.

        • Спасибо за советы! Я поэкспериментирую.

  • Спасибо автору за статью, очень классный виджет

  • Спасибо автору за статью, очень классный виджет

  • Ivolga

    наткнулась на эту статью, 
    спасибо, полезная.
    есть вопрос: у меня записи на русск. яз. вставляются как ????
    проверила — везде стоит UT8
    не подскажете, может какие-то настройки еще нужно изменить?

    • На моей демо-страничке русские буквы отображаются нормально, только что проверил. Я правильно понимаю, что проблема на вашем сервере?
      Уточните, пожалуйста, UTF-8 исползуется в скриптах, заголовке страницы, установлена как кодировка таблиц в БД, указана при установке соединения с базой? Правильно?

      • Ivolga

        да, проблема на моем сервере. возилась долго, оказалось, что если изначально создавать БД, указав кодировку utf8, то и проблем нет, а я создала таблицу в существующей базе и там стоит сравнение latin1_swedish_ci. в общем, если в файле savenote.php заменить строчку 
        $dbh->exec('SET CHARACTER SET utf8');на$dbh->exec(«set names utf8»);
        то все работает и с русск. буквами
        спасибо за отклик

        • Не за что. Кстати, проверить все кодировки базы можно запросами
          SHOW VARIABLES LIKE 'character%'

          SHOW VARIABLES LIKE 'collation%'

  • Parls22

    А как сделать перенос длинных сообщений ?

    • Parls22

      Спасибо розобрался, а как убрать нижний скрол ? 

      • Обе операции выполняются с помощью CSS.
        #notes {
        overflow-y: scroll;
        word-wrap: break-word;
        }

  • Parls22

    Спасибо, за помощ ))) , отличная статья