Решил провести полный рефакторинг своей CMS (да-да, каждый веб-разработчик просто обязан написать свою систему управления контентом), и заодно сделать панель управления удобнее.
Задача такая: есть дерево меню сайта в админке. Рядом с каждым пунктом меню — кнопка, нажав её, переходим на страницу редактирования свойств пункта меню: ссылки, активности, картинки. Задача следующая — не переходить на другую страницу, как в «суровые девяностые», а используя AJAX открыть тут же, в псевдо всплывающем окне, типа лайтбокса, который заполонил весь инет.
Начнём, как говорят «37 signals», с проектирования интерфейса. Использовать плагины и чужие скрипты не хочется, люблю, чтобы страницы загружались быстро. Поэтому обойдёмся без лайтбокса и jquery tools. Всплывающее окно будет у нас слоем с абсолютным позиционированием и следующими свойствами:
- #divedit
- {
- position: absolute;
- z-index:0;
- background: silver;
- display: none;
- top:50%;
- left:50%;
- width: 400px;
- height: 274px;
- margin-left: -200px;
- margin-top: -137px;
- border: gray solid;
- }
- <div id=»divedit»>
- <div class=»box content»>
- <form id=»editform» name=»editform» method=»post» action=»{base}cms/menu/edit»>
- <input type=»hidden» value=»1″ name=»old_parent»/>
- <input type=»hidden» value=»2″ name=»lft»/>
- <label>Название: </label>
- <input type=»text» style=»width: 50%;» name=»title» id=»title»/>
- <br/>
- <br/>
- <label>Ссылка: </label>
- <input type=»text» style=»width: 50%;» value=»» name=»alias»/>
- <br/>
- <br/>
- <label>Родитель: </label>
- <div id=»parent»></div>
- <br/>
- <br/>
- <label>Включён: </label>
- <div id=»visible»></div>
- <br/>
- <br/>
- <label>Картинка: </label>
- <br/>
- <div id=»picture» align=»center»></div>
- <br/>
- <div align=»center»>
- <input class=»subm i-accept» type=»submit» value=»Сохранить» name=»submit_edit»/>
- <input class=»subm i-cancel» type=»button» value=»Отмена» id=»cancel_ed» name=»cancel_ed»/>
- </div>
- </form>
- </div>
- </div>
Напишем функцию контроллера, которая должна будет передавать данные о пункте меню:
- function ajaxitemdata()
- {
- if ($this->input->post(‘id’))
- {
- $id = $this->input->post(‘id’);
- $this->MPTtree->set_table(‘menu_tree’);
- $node = $this->MPTtree->get_ORM($id);
- $parent = $node->parent();
- $arr = array(
- ‘title’ => $node->get(‘title’),
- ‘alias’ => $node->get(‘alias’),
- ‘parent’ => $this->MPTtree->display_as_select(1,$parent->get(‘lft’),‘parent’),
- ‘visible’ => form_checkbox(‘visible’, ‘visible’,$node->get(‘visible’)),
- ‘picture’ => img($this->Menu_model->get_pic_by_id($node->get(‘id’)))
- );
- echo json_encode($arr);
- }
- else
- {
- $arr = array(‘title’ => ‘Error’);
- echo json_encode($arr);
- }
- }
В CodeIgniter для хранения деревьев я использую модель MPTtree, реализующую алгоритм Nested Sets. Надеюсь, вы в своих проектах не используете рекурсивное построение дерева сотней запросов в цикле? display_as_select — метод, выводящий сразу HTML код выпадающего списка со всеми пунктами меню, чтобы не парсить на стороне клиента каждую опцию. Результат выводится в формате JSON, легко читаемом и гораздо быстрее обрабатываемым, чем XML.
Следующий пример показывает JSON-представление объекта, описывающего человека. В объекте есть строковые поля имени и фамилии, объект, описывающий адрес, и массив, содержащий список телефонов.
{ "firstName": "Иван", "lastName": "Иванов", "address": { "streetAddress": "Московское ш., 101, кв.101", "city": "Ленинград", "postalCode": 101101 }, "phoneNumbers": [ "812 123-1234", "916 123-4567" ] }На языке XML подобная структура выглядела бы примерно так:
<person> <firstName>Иван</firstName> <lastName>Иванов</lastName> <address> <streetAddress>Московское ш., 101, кв.101</streetAddress> <city>Ленинград</city> <postalCode>101101</postalCode> </address> <phoneNumbers> <phoneNumber>812 123-1234</phoneNumber> <phoneNumber>916 123-4567</phoneNumber> </phoneNumbers> </person>
Теперь нужно вызвать эту функцию со стороны клиента:
- $(«button[name*=’edit’]»).click(function() {
- $.post(«{base}cms/menu/ajaxitemdata/», {id: this.value}, getitem, «json»);
- });
При нажатии на кнопку, имя которой начинается с ‘edit’, отправляем POST запрос к серверу со значением id, равному value кнопки. Так же передаём имя callback функции (она выполнится после запроса и будет обрабатывать ответ) и указываем формат ответа — json.
Код callback функции:
- function getitem(data)
- {
- document.editform.title.value = data.title;
- document.editform.alias.value = data.alias;
- $(«#parent»).html(data.parent);
- $(«#visible»).html(data.visible);
- $(«#picture»).html(data.picture);
- $(«#divedit»).show(«slow»);
- }
Значения полей ввода подставляем прямо в атрибут value элемента формы, для выпадающего списка, флажка и картинки — в пустые слои формы с соответствующими id подставляем html код. После этого открываем слой со спецэффектом.
Далее форма либо сабмитится, либо слой закрывается при нажатии на кнопку отмены. Для этого вешаем на неё обработчик:
- $(«#cancel_ed»).click(function() {
- $(«#divedit»).hide(«slow»);
- });
Всё просто.