Разработка web приложений. Как сделать редактор списка в стиле Web 2.0 (главная страница)

4 января, 2008

Скриншот WebListEditor
В прошлый раз мы начали создание web приложения, позволяющего редактировать простой список. На данный момент мы разобрали общую структуру приложения и функцию подключения к базе данных (БД).

Примечание. Вы можете посмотреть демонстрационную версию редактора или скачать архив с файлами проекта.

Теперь переходим к созданию главной страницы (index.php). Html разметку постараемся максимально упростить, т.к. нам придется изменять ее в процессе работы web приложения.
Заголовок страницы, в общем-то, обычный

  1. <?php
  2. require_once("scripts/dbdata.php");
  3. ?>
  4. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN">
  5. <html xmlns="http://www.w3.org/1999/xhtml" lang="ru">
  6. <head>
  7. <title>WebListEditor</title>
  8. <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
  9. <link rel="stylesheet" type="text/css" href="css/styles.css" />
  10. <script type="text/javascript" src="scripts/libs/prototype.js"></script>
  11. <script type="text/javascript" src="scripts/libs/scriptaculous.js?load=effects,controls"></script>
  12. <script type="text/javascript" src="scripts/tasks.js"></script>
  13. </head>

Прежде всего, мы подключаем файл dbdata.php с функцией подключения к БД, затем указываем тип страницы, кодировку, размещения файлов с таблицей стилей и JavaScript библиотеками.

Обратите внимание на то, как подключена библиотека Scriptaculous (строка 11). Эта библиотека состоит из семи файлов (версия 1.7.0), большинство из которых мы не используем. Поэтому с помощью параметра load указываем, какие файлы нужно загрузить. В данном случае нам нужна библиотека эффектов (effects) для подсветки вставленных элементов и библиотека элементов управления (controls) для создания встраиваемого редактора.

Теперь рассмотрим основную часть страницы.
Т.к. страница получилась довольно длинной, я разбил ее на три части.

Первая часть выполняет подключение к БД (с помощью функции connect() из файла dbdata.php) и отправляет запрос получения списка.

  1. <?php $con = connect(); ?>
  2. <div id="content">
  3. <?php
  4. $res = mysql_query("SELECT * FROM listitems");
  5. if ($res === FALSE) {
  6.     echo "Ошибка при отправке запроса к БД:".mysql_error();
  7. }
  8. elseif (mysql_num_rows($res) == 0) {
  9.     echo "<div id=\"noItems\">Записей нет</div>";
  10. }
  11. else {
  12. ?>

Если ошибок не было, результаты выполнения запроса будут находиться в переменной $res.

Вторая часть самая интересная. Здесь мы формируем блок со списком.

  1. <p>Список:</p>
  2. <ul id="list">
  3. <?php
  4.     $i = 0;
  5.     while ($item = mysql_fetch_array($res, MYSQL_ASSOC)) {
  6.         $i++;
  7. ?>
  8. <li id="listNum_<?php echo $i - 1; ?>">
  9. <div class='itemNum'><?php echo $i; ?></div>
  10. <div class='itemValue' onclick='closeOtherEditors(<?php echo $i - 1; ?>)'
  11. id="itemId_<?php echo $item['id']; ?>"><?php echo $item['item']; ?></div>
  12. <a href="#" class="deleteLink" onclick="deleteItem(<?php echo $item['id']; ?>)">
  13. <img src="css/images/delete.gif" alt="Удалить" title="Удалить" />
  14. </a>
  15. <script type="text/javascript">
  16. editors.push(addEditor("itemId_<?php echo $item['id'];?>",
  17.     "<?php echo $item['id'];?>"));
  18. </script>
  19. </li>
  20. <?php
  21.     }
  22. ?>
  23. </ul>
  24. <?php
  25. }
  26. ?>
  27. </div>
  28. <?php
  29. mysql_free_result($res);
  30. mysql_close($con);
  31. ?>

Основной цикл, который вставляет элементы списка, находится в строках с 5 по 21. Это обычный while цикл, в котором с помощью функции mysql_fetch_array мы получаем результаты запроса и формируем разметку списка.

Обратите внимание на имена атрибутов тегов списка. Для тега li установлен атрибут вида listNum_номер_записи (это порядковый номер записи в списке, а не id в БД).
Внутри тега li находятся три блока (теги div). В первом блоке находится номер элемента списка. Во втором – текст записи. Атрибут id этого элемента имеет вид itemId_номер_в_БД (здесь используется значение поля id из БД). В третьем блоке находится ссылка «Удалить» с картинкой.

В строках 15-18 мы вставили немного JavaScript кода. Он создает встраиваемый текстовый редактор для текущего элемента и добавляет его в массив (с помощью функции push).

Рассмотрим функцию addEditor подробнее (она находится в файле tasks.js).

  1. var editors = [];
  2.  
  3. function addEditor(item, id) {
  4.     return new Ajax.InPlaceEditor(item,
  5.         "scripts/updateitem.php",
  6.         {
  7.             formId: "listForm",
  8.             okText: "Обновить",
  9.             cancelText: "Отмена",
  10.             highlightcolor: "#ffffff",
  11.             size: "30",
  12.             savingText: "Сохраняю…",
  13.             callback: function(form, value) {
  14.                 return "value=" + value + "&amp;id=" + id;
  15.             }
  16.         });
  17. }

В самом начале скрипта мы объявили глобальный массив (editors), в котором будем хранить встраиваемые редакторы (как вы, наверное, догадались, эти редакторы должны быть созданы отдельно для каждого элемента списка).
Функция addEditor выполняет только одну операцию: создает и настраивает встраиваемый редактор для заданного элемента списка. В первом параметре функции указываем id блока, к которому будет присоединен редактор, второй параметр – id записи в БД.

На скриншоте в начале статьи показан активированный встроенный редактор. Принцип его действия заключается в следующем. При щелчке по блоку, для которого установлен редактор, этот блок заменяется формой, содержащей текстовое поле, кнопку «Обновить» и ссылку «Отмена».

Редактор создается с помощью функции InPlaceEditor() объекта Ajax из библиотеки Scriptaculous. В первом параметре этой функции мы указываем имя php скрипта (updateitem.php), которому будут отправлены данные после нажатия на кнопку «Сохранить». Во втором параметре – массив с настройками редактора. Рассмотрим их по порядку:
formId – значение атрибута id формы редактора (используется для установки стилей);
okText – текст на кнопке;
cancelText – текст ссылки «Отмена»;
highlightcolor – цвет подсветки (при появлении формы к ней автоматически применяется эффект highlight, о котором я писал в статье «Подсветка элементов web страницы»);
size – размер текстового поля формы;
savingText – текст, который отображается пока идет обновление данных;
callback – функция, выполняющая отправку данных серверному скрипту.

На последнем параметре остановимся подробнее. Если его опустить, то при обновлении данных редактор отправит только значение, введенное в текстовое поле. Такое поведение нас не устраивает, т.к. нам нужно знать id записи, которую нужно обновить, а не только ее значение. Поэтому мы объявили свою собственную анонимную функцию, которая добавляет в запрос id выбранного элемента в БД.

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

Если вы внимательно читали разметку html страницы, то заметили, что при щелчке по тексту записи вызывается функция closeOtherEditors(). Этой функции передается номер выбранной записи.

Посмотрим на ее исходный код

  1. function closeOtherEditors(curEditor) {
  2.     editors.each(
  3.         function(editor, index) {
  4.             if (index != curEditor) {
  5.                 editor.leaveEditMode();
  6.             }
  7.         }
  8.     );
  9. }

Как видите, эта функция переводит все встроенные редакторы, кроме указанного, в неактивное состояние (с помощью leaveEditMode()). Дело в том, что созданные нами редакторы не зависят один от другого, и по-умолчанию они закрываются только при нажатии на ссылку «Отмена». Это не очень удобно, поэтому в этой функции мы закрываем все редакторы кроме выбранного.

Третья часть страницы содержит форму для добавления новой записи в список. При нажатии на кнопку «Добавить» будет вызвана функция addItem(), размещенная в файле tasks.js.

  1. <form action="#" id="add_item_form">
  2. <p>
  3. <label for="item_value"></label>
  4. <input type="text" id="item_value" size="30" />
  5. <input type="button" value="Добавить" onclick="addItem()" />
  6. </p>
  7. </form>

Подведем небольшой итог. Формирование страницы включает следующие этапы:
1) создание html разметки;
2) получение данных из БД;
3) создание встроенных редакторов для всех записей списка.

В следующий раз мы рассмотрим добавление новых записей в список.

Понравилась статья? Подпишитесь на продолжение rss link !

]]>

Добавьте эту страницу в google.com bobrdobr.ru del.icio.us technorati.com linkstore.ru news2.ru rumarkz.ru memori.ru moemesto.ru

]]>

Опубликовано в Ajax, JavaScript, PHP

]]>

Комментарии (16)

Вы можете отслеживать обсуждение записи с помощью RSS 2.0 rss link

Вы также можете оставить комментарий, или трекбек с Вашего сайта.

  1. Очень хорошо описано, спасибо за полезную информацию.

  2. Олег 06.02.2008 в 10:42 (Ответить)

    Очень инетерсный редактор. Все разобрал свой запрос вставил. Только непонятно как сделать, чтобы отображался не один столбец, а несколько. Что надо класть в цикл для этого ? Где изменить кодировку по умолчанию с UTF на CP1251 ?

    1. Владимир 06.02.2008 в 16:42 (Ответить)

      Столбцы создаются с помощью таблицы стилей. Т.е. в html разметке все блоки идут друг за другом, а размещение в одну строку обеспечивается правилом
      float: right

      Например, если вы вставляете еще один столбец, между номером (<div class=‘itemNum’>) и текстом (<div class=‘itemValue’>), то для этого блока нужно будет задать float: right. Если ваш блок идет последним, то float: right задаете для предыдущего блока.

      Это, конечно, не единственный способ размещения контента в несколько колонок.

      С кодировкой сложнее. Насколько я знаю, ajax запросы всегда отправляются в UTF8.
      Если ваш эта кодировка не устраивает, то можно использовать функцию
      mb_convert_encoding
      для преобразования кодировок.

  3. Тоха 16.04.2008 в 15:38 (Ответить)

    Подключил как написано, все нормально. Но когда пытаюсь изменить значение в ячейке появляется подобная запись.
    Notice: Use of undefined constant id - assumed 'id' in C:\apache\localhost\www\scripts\updateitem.php on line 14
    В чем может быть проблем?
    P.S. : в исходниках поменял только название базы, имя пользователя и пароль.

    1. Владимир 16.04.2008 в 17:12 (Ответить)

      Прошу прощения, виноват.
      Строку 14 в файле updateitem.php нужно изменить:
      if (($v != null) && ($v != "") && ($id != null) && ($id != "") ) {

      Исправленный вариант я уже выложил.

      Похоже моя версия PHP сама исправляла ошибку или просто игнорировала ее :-)

  4. Тоха 17.04.2008 в 15:08 (Ответить)

    Добрый день. Подскажите пожалуйста как добавить к этому всему 2 столбца(Столбец 1, Столебц 2). Заранее благодарен за совет.

    1. Владимир 17.04.2008 в 21:42 (Ответить)

      Тут может быть несколько вариантов. В html разметке все блоки идут друг за другом, а колонки создаются только за счет таблицы стилей.

      Поэтому просто добавьте

      Столбец 1
      Столбец 2

      перед строкой 12 (листинг 3). А в файле в таблице стилей установите float:left

      Но если планируете использовать много столбцов, возможно, будет удобнее использовать таблицы.

  5. Олег 18.04.2008 в 08:41 (Ответить)

    Конечно редактор классный, но я на него забил и написал свой чисто на пхп потомучто разгребать чужой код не люблю, но всеравно спасибо

    1. Владимир 18.04.2008 в 14:54 (Ответить)

      Правильно сделали :-) Даже если своим не будете пользоваться, все равно польза будет просто от того, что вы его сами написали.
      А этот редактор вобщем-то демонстрационный. Минимальный набор возможностей.
      Но даже в таком варианте описание растянулось на 6 статей :-)

  6. jelena 02.10.2008 в 15:04 (Ответить)

    Zdravstvuite!!
    Spasibo ogromnoe za eto podrobnoe opisanie! Mozet etot vopros zdes' ne sovsem umesten, no nadejus' mozet smozite mne pomo4'!! ja ispol'zuju Ajax.InPlaceCollectionEditor dlja redaktirovanija select box. I mne nado peredavt' 2 zna4enija : value i id pri pomoshi callback. No eto ne rabotaet:::( Mozet vi mozete podskazt' po4emu?

    Jelena

    1. Владимир 02.10.2008 в 15:56 (Ответить)

      А что именно не работает? Можно взглянуть на код?

      1. jelena 02.10.2008 в 20:15 (Ответить)

        polu4aetsja tak 4to callback dlja InPlaceCollectionEditor prosto ignoriruetsja. Segodnja zelii den razbiralas , no tak i ne nashla otveta….

        <span "onclick='closeOtherEditors()' id="exact_">

        editors.push(addEditorSelect("exact_",
        ""));

        i 4ast kotoraja ne rabotaet ( to4nee prosto ignoriruetsja callback)

        function addEditorSelect(item, id) {
        return new Ajax.InPlaceCollectionEditor(item,
        "../form/scripts/updateitem.php",
        { callback: function(form, value) {
        return "value=" + value + "&id=" + id;
        },
        collection: ['Yes','No'],
        value:'Ei',

        okText: "ok",
        cancelText: "cancel",
        highlightcolor: "#ffffff",
        size: "30",
        savingText: "saving",
        ajaxOptions: {method: 'get'},

        });
        }

      2. jelena 02.10.2008 в 20:30 (Ответить)

        nu nikak ne polu4aetsja vilozit kod normalno;( Pozaluista izvinite.
        T.e u menja vse toze samoe 4to i u vas v opisanii, tolko ispolzuju ne InPlaceEditor a InPlaceCollectionEditor s dvumja zna4enijami (da / net). i mne nado 4tobi serveru otpravljalos 2 zne4enija : id zapisi i zna4enie iz select box..

  7. jelena 02.10.2008 в 20:16 (Ответить)

    4to to ja v predidushem poste slu4aino sterla:(

    <span "onclick='closeOtherEditors()'
    id="exact_">

    editors.push(addEditorSelect("exact_",
    ""));

  8. jelena 02.10.2008 в 20:19 (Ответить)


    <span "onclick='closeOtherEditors()'
    id="exact_">

    editors.push(addEditorSelect("exact_",
    ""));

    function addEditorSelect(item, id) {
    return new Ajax.InPlaceCollectionEditor(item,
    "../form/scripts/updateitem.php",
    { callback: function(form, value) {
    return "value=" + value + "&id=" + id;
    },
    collection: ['Yes','No'],
    value:'No',

    okText: "ok",
    cancelText: "cancel",
    highlightcolor: "#ffffff",
    size: "30",
    savingText: "saving",
    ajaxOptions: {method: 'get'},

    });
    }

    1. Владимир 02.10.2008 в 22:03 (Ответить)

      Я поэкспериментирую с callback, но, возможно, вам подойдет другое решение.
      При создании списка указать id:
      collection: [['1','Yes'],['0','No']]

      В этом случае при отправке вместо Yes будет отправлена 1. Т.к. все записи в списке имеют уникальный id (1, 0), то передавать значение (Yes, No), по-моему, смысла нет.

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

Введите ваш комментарий

* - обязательные для заполнения поля

Quicktags:

]]>