Rich UI on Dojo Toolkit and Zend Framework
-
Upload
georgy-turevich -
Category
Technology
-
view
3.780 -
download
3
description
Transcript of Rich UI on Dojo Toolkit and Zend Framework
Создание динамических интерфейсови AJAX-приложений
промышленного класса с помощьюDojo Toolkit и Zend Framework
Георгий Туревич, Wizartech
Немного о себе
• Ведущий веб-программист компании Wizartech• Более 7-и лет использования PHP и JavaScript• Более 2-х лет использования Zend Framework• Около 1-го года активного использования Dojo Toolkit
(с момента заключения партнерства с Zend Framework)и создания индивидуальных компонентов
• Принимаю активное участие в развитии сообщества ZendFramework.ru (с момента создания)
• Модератор русскоязычной группы рассылки«RU DojoToolkit JS Framework» на Google Groups
Промышленный?
• Богатый функционал• Гибкая архитектура• Проверенный код
– Код библиотек покрыт тестами– Собственный инструментарий для тестирования
• Постоянное развитие и ясное будущее– Поддержка от Zend Technologies и Sitepen
• Мощное сообщество– Zend Framework: Adobe, Google, Sitepen, Microsoft, Nirvanix, Strikiron– Dojo Toolkit: Sun, IBM, Google, AOL, Uxebu, Sitepen
• Лицензирование– Zend Framework: New BSD License– Dojo Toolkit: Modified BSD license \ The Academic Free License 2.1
Dojo Toolkit
Где взять Dojo?
• Скачайте напрямую• Subversion / Git / Bazaar• CDN (Google, AOL, …)
Архитектура Dojo Toolkit
Вкратце о Core и Base
• Полезные утилиты• Обработка событий• Ajax (Restful XHR, script, iframe) • Манипулирование узлами• Интернационализация• Перетаскивание• Анимация• Абстракция данных• Имитация классов и наследования
Dojo ToolkitCore и Base
Инициализация
<html> <head> <title>Dojo</title> <script type="text/javascript" src="http://o.aolcdn.com/dojo/1.3/dojo.xd.js"> </script> </head><body>HELLO PHPCONF 2009 !!!</body></html>
Также можно использовать:• Другие CDN (помимо AOL и Google можно использовать собственные
XD-сборки)• Локальные копии Dojo Toolkit
Конфигурирование
<script type="text/javascript" src="/dojotoolkit/dojo/dojo.js" djConfig="isDebug:true,parseOnLoad:true"></script>
Конфигурировать возможно прямо в тэге <script>:
Или программным способом (для соответствия стандартам):
<script>
var djConfig = {isDebug: true, parseOnLoad: true}
</script>
<script type="text/javascript"
src="/dojotoolkit/dojo/dojo.js">
</script>
Система управленияпакетами и зависимостями
<script> dojo.require("dojo.fx"); dojo.require("dojo.io.script");
dojo.registerModulePath("wlib", "/js/wlib/"); dojo.require("wlib.Example"); // /js/wlib/Example.js
var exampleObj = new wlib.Example();</script>
Система управленияпакетами и зависимостями
dojo.provide("wlib.Example");
dojo.declare("wlib.Example", null, { constructor: function() { console.log("HELLO! It is example!"); }});
/js/wlib/Example.js
Вывод в консоли Firebug Lite (упрощенный аналог плагина для FF):
dojo.addOnLoad()
dojo.addOnUnload()
<script>
var onLoadFunc = function() {
console.log('Да! Страница загружена!');
}
dojo.addOnLoad(onLoadFunc);
</script>
<script>
var onUnloadFunc = function() {
alert('Закрываем страницу');
}
dojo.addOnUnload(onUnloadFunc);
</script>
Интересное в Base и CoreСобытия
Интересное в Base и CoreСобытия
dojo.connect()
<a href="http://phpconf.ru" id="link">Все на конференцию</a>
<script>
dojo.connect(dojo.byId('link'),'onclick', function(evt) {
dojo.stopEvent(evt);
console.log('Вы щелкнули на ссылку!');
});
</script>
Интересное в Base и CoreСобытия
dojo.connect() / dojo.disconnect()
<script>
function foo() { console.log('Вызвана функция foo') }
function bar() { console.log('Вызвана фукция bar') }
var conn = dojo.connect('foo', bar);
foo();
console.log('--- Удаляем соединение --- ');
dojo.disconnect(conn);
foo();
</script>
Интересное в Base и CoreСобытия
dojo.connect() / dojo.disconnect()
Интересное в Base и CoreСобытия
dojo.subscribe(), dojo.unsubscribe(), dojo.publish()
<script>
function handlerFirst(data) {
console.log("Функция handlerFirst, Данные:", data);
}
function handlerSecond(data) {
console.log("Функция handlerSecond, Данные:", data);
}
var subscrFirst
= dojo.subscribe('mySubscribe', null, handlerFirst);
var subscrSecond
= dojo.subscribe('mySubscribe', null, handlerSecond);
</script>
Интересное в Base и CoreСобытия
dojo.subscribe(), dojo.unsubscribe(), dojo.publish()
<script>
dojo.publish("mySubscribe", ["Привет всем!"]);
dojo.publish("mySubscribe", ["Пока всем!"]);
console.log(" --- Очищаем subscrFirst --- ");
dojo.unsubscribe(subscrFirst);
dojo.publish("mySubscribe", ["Привет всем!"]);
dojo.publish("mySubscribe", ["Пока всем!"]);
</script>
Интересное в Base и CoreСобытия
dojo.subscribe(), dojo.unsubscribe(), dojo.publish()
Интересное в Base и CoreAjax
Полный Restful набор функций:• dojo.xhrGet()• dojo.xhrPost()
<script>
dojo.xhrPost({
url: "./test.php",
handleAs: "text",
content: {a: "1111", b: "2222"},
load: function(response, ioArgs) {
console.log(response);
return response;
}
});
</script>
• dojo.xhrPut()• dojo.xhrDelete()
Интересное в Base и CoreAjax
test.php
<?php
print_r($_POST);
Интересное в Base и CoreAjax
dojo.Deffered (позволяет создавать цепочки функций обратного вызова)
<script>
function firstCallback(response, ioArgs) {
console.log("Вызван firstCallback:", response);
return response;
}
function secondCallback(response, ioArgs) {
console.log("Вызван secondCallback:", response);
return response;
}
</script>
Интересное в Base и CoreAjax
<script>
var deffered = dojo.xhrPost({
url: "./test_deffered.php",
handleAs: "json",
content: {a: "1111", b: "2222"},
load: function(response, ioArgs) {}
});
deffered.addCallback(firstCallback);
deffered.addCallback(secondCallback);
</script>
dojo.Deffered
Также есть возможность добавлять:• Исключительно обработчики ошибок (addErrback метод)• Универсальные обработчики (addBoth метод)
Интересное в Base и CoreAjax
test_deffered.php
<?php
echo json_encode($_POST);
Имитация классови наследования
dojo.declare()
<script>
dojo.declare("wlib.ExampleParentFirst", null, {
constructor: function() {
console.log("Вызов конструктора");
}
});
dojo.declare("wlib.ExampleParentSecond", null, {
say: function(message) {
console.log(message)
}
});
</script>
Имитация классови наследования
<script>
dojo.declare(
"wlib.ExampleParentChild",
[wlib.ExampleParentFirst, wlib.ExampleParentSecond],
{
sayBy: function() {
this.say("Всем пока!")
}
}
);
var child = new wlib.ExampleParentChild();
child.sayBy();
</script>
dojo.declare()
Имитация классови наследования
dojo.declare()
Имитация классови наследования
dojo.extend()
<script>
dojo.extend(wlib.ExampleParentChild, { sayHello: function() {
this.say("Всем привет!");
}
});
var child = new wlib.ExampleParentChild();
child.sayHello();
child.sayBy();
</script>
Имитация классови наследования
dojo.mixin()
<script>
var obj = { firstName: "Иван", lastName: "Петров" };
var emp = dojo.mixin(obj, {
sayName: function() {
console.log(
"Меня зовут " + this.firstName + " "
+ this.lastName
);
}
});
emp.sayName();
</script>
Имитация классови наследования
dojo.hitch()
<script>
function sayName() {
console.log(
"Меня зовут " + this.firstName + " "
+ this.lastName
);
}
var obj = { firstName: "Иван", lastName: "Петров" };
var callback = dojo.hitch(obj, sayName);
callback();
</script>
Dojo ToolkitDijit
Что такое Dijit?
• Система виджетов Dojo• Богатый набор готовых виджетов
– Элементы форм (текстовые поля, кнопки, выпадающие элементы,слайдеры и т.д.)
Элементы форм
Что такое Dijit?
• Система виджетов Dojo• Богатый набор готовых виджетов
– Элементы форм (текстовые поля, кнопки, выпадающие элементы,слайдеры и т.д.)
– Виджеты компоновки (Content pane, Accordion / Tab / Stack /Border-контейнеры)
Виджеты компоновки
Что такое Dijit?
• Система виджетов Dojo• Богатый набор готовых виджетов
– Элементы форм (текстовые поля, кнопки, выпадающие элементы,слайдеры и т.д.)
– Виджеты компоновки (Content pane, Accordion / Tab / Stack /Border-контейнеры)
– Виджеты приложения (деревья, прогресс-бар, диалоги, меню,WYSIWYG и т.д.)
Виджеты приложения
Что такое Dijit?
• Система виджетов Dojo• Богатый набор готовых виджетов
– Элементы форм (текстовые поля, кнопки, выпадающие элементы,слайдеры и т.д.)
– Виджеты компоновки (Content pane, Accordion / Tab / Stack /Border-контейнеры)
– Виджеты приложения (деревья, прогресс-бар, диалоги, меню,WYSIWYG и т.д.)
• Доступность (Accessibility (a11y))• Шаблонность (встроенный шаблонизатор)• Готовые темы оформления (tundra, soria, nihilo, noir)
Инициализация виджетов
<script src="/dojotoolkit/dojo/dojo.js"
djConfig="isDebug: true, parseOnLoad: true"
></script>
<script>
dojo.require("dijit.form.Button");
</script>
<link id="themeStyles" rel="stylesheet" href="/dojotoolkit/dijit/themes/tundra/tundra.css">
В секции <head>:• Устанавливаем parseOnLoad в true• Подключаем нужные виджеты• Подключаем тему оформления
Инициализация виджетов
<div class="tundra">
<button id="buttonHello"></button>
<button dojoType="dijit.form.Button">
Щелкни по мне!
</button>
</div>
<script>
var button = new dijit.form.Button({
label: "Привет!",
name: "programmatic"
}, "buttonHello");
</script>
В секции <body>:
Инициализация виджетов
• Одна кнопка инициализирована программным способом• Вторая кнопка инициализирована декларативным способом
Возможности расширения
• Переопределение методов жизненного цикла– constructor() (конструктор)– postMixInProperties() (вызывается после формирования структуры виджета)– buildRendering() (генерирует визуальное отображение виджета)– postCreate() (вызывается сразу после создания визуального отображения)– startup() (вызывается после создания всех дочерних виджетов и самого
виджета)
• Шаблон– Можно встраивать в код класса– Можно выносить в отдельный файл
• Языковые файлы– Можно встраивать в код класса– Можно выносить в отдельный файл
Dojo ToolkitDojox
Dojox
Dojox — собрание расширенных, дополнительных и экспериментальных компонентов (Extensions, Extras, Experiments)
Состав:• Расширения Dijit (dojox.widget, dojox.layout, dojox.form)• Дополнительная анимация: dojox.fx (Morph, Text, Extras, ...)• Виджеты изображений (FlickrBadge, Lightbox (Nano), SlideShow, ...)• Расширенный IO (RPC, REST, SMD, ScriptFrame, ...)• И многое другое …
Dojox
Кроссбраузерная векторная графика:• GFX API• Charting• GFX 2D / 3D• GFX-анимации
Dojox
dojox.grid.Grid
Dojo ToolkitДанные
Абстракция работы с данными
Все типы хранилищ реализуют один или несколько интерфейсов:• dojo.data.api.Read (чтение, поиск, сортировка и фильтрация элементов
данных)• dojo.data.api.Write (создание, удаление, обновление элементов данных)• dojo.data.api.Identity (доступ к элементам по средствам уникальных
идентификаторов)• dojo.data.api.Notification (уведомление о таких событиях, как создание,
удаление или обновление элементов данных)
Абстракция работы с данными
Dojo• dojo.data.ItemFileReadStore• dojo.data.ItemFileWriteStore
Dojox• AtomReadStore• CouchDBRestStore• CssRuleStore• CsvStore• FileStore• FlickrRestStore/FlickrStore• GoogleFeedStore• GoogleSearchStore
• HtmlStore• jsonRestStore• QueryReadStore• ServiceStore• S3Store• WikipediaStore• XmlStore• И другие …
Dojo ToolkitUtil
Подготовка к выпускув эксплуатацию
В пакете Dojo Toolkit поставляется утилита ShrinkSafe (Java),которая реализует следующие функции:
• Уменьшение количества HTTP-запросов– Объедение файлов с классами, шаблонами, языковыми данными
• Уменьшение размера JavaScript-файлов– Удаление комментариев и пробелов– Сокращение наименований переменных
• CSS-оптимизация– Объединение @import-файлов в один– Удаление комментариев
• Опции StripConsole• X-Domain-сборки (свой CDN)
D.O.HСистема модульного тестирования
Поддерживает assert*, buildUp, tearDown–методы, тестирование синхронныхи асинхронных запросов, включает в себя подсистему тестирования визуальных компонентов doh.robot.
Интеграция Dojo Toolkitи Zend Framework
• Программная настройка Dojo-окружения• Автоматизация работы с виджетами• Генерация спец. форматов данных• Упрощение выпуска в эксплуатацию
Zend Framework
Программная настройка Dojo-окружения
<style type="text/css">
@import "/js/dojo-toolkit/dijit/themes/tundra/tundra.css";
</style>
<script type="text/javascript">
var djConfig = {"isDebug":true,"parseOnLoad":true};
</script>
<script type="text/javascript"
src="/js/dojo-toolkit/dojo/dojo.js"></script>
<script type="text/javascript">
dojo.require("dojo.io.script");
dojo.require("dojo.fx");
dojo.require("dijit.form.Button");
</script>
Типичный код в <head> секции для настройки Dojo:
Программная настройка Dojo-окружения
<?=$this->dojo()
->enable()
->setDjConfig(
array('isDebug' => true,
'parseOnLoad' => true)
)
->setLocalPath('/js/dojo-toolkit/dojo/dojo.js')
->addStyleSheetModule('dijit.themes.tundra')
->requireModule(
array('dojo.io.script',
'dojo.fx',
'dijit.form.Button')
)?>
Конфигурация с помощью dojo() view-хелпера:
Программная настройка Dojo-окружения
<?=$this->dojo()?>
Шаг в будущее В активной разработке плагин бустрапаZend_Application_Resource_Dojo, с помощью которого:
И в application.ini:
resources.dojo.djConfig.isDebug = 1
resources.dojo.djConfig.parseOnLoad = 1
resources.dojo.localPath = "/js/dojo-toolkit/dojo/dojo.js"
resources.dojo.requireModule[] = "dojo.io.script"
resources.dojo.requireModule[] = "dojo.fx"
resources.dojo.requireModule[] = "dijit.form.Button"
В макете указываем:
Работа с виджетамиView-хелперы
<h1>Форма</h1>
<div class="tundra">
<form>
<?=$this->editor('editor')?>
<?=$this->button(
'send', 'Отправить')?>
</form>
</div>
В шаблоне:
Работа с виджетамиЭлементы форм
$form = new Zend_Dojo_Form();
$form->addElement('editor', 'editor');
$form->addElement(
'button',
'send',
array('label' => 'Отправить')
);
$this->view->form = $form;
В контроллере:
<h1>Форма</h1>
<div class="tundra">
<?=$this->form?>
</div>
В шаблоне:
Работа с виджетамиСостав компонентов
• В состав элементов для Zend_Dojo_Form входят классы для большинства виджетов формы
• Так же реализованы view-хелперы и декораторы для форм, которые упрощают работу с виджетами компоновки:– AccordionContainer– AccordionPane– BorderContainer– SplitContainer– StackContainer– TabContainer– ContentPane
AjaxZend_Dojo_Data
public function dojoDataExampleAction()
{
$form = new Zend_Dojo_Form();
$form->addElement(
'FilteringSelect', 'city',
array(
'label' => 'City',
'storeId' => 'cityStore',
'storeType' => 'dojo.data.ItemFileReadStore',
'storeParams' => array(
'url' => '/json/simple-city-store/',
),
'dijitParams' => array(
'searchAttr' => 'name',
)
)
);
$this->view->form = $form;
}
Формируем форму:
AjaxZend_Dojo_Data
public function simpleCityStoreAction()
{
$data = array(
array('id' => 1, 'name' => 'Волгоград'),
array('id' => 2, 'name' => 'Москва'),
array('id' => 3, 'name' => 'Минск'),
array('id' => 4, 'name' => 'Мурманск')
);
$dojoData = new Zend_Dojo_Data('id', $data);
echo $dojoData;
}
Отдаем данные в формате dojo.data:
AjaxZend_Dojo_Data
Отдаем данные в формате dojo.data:
{
"identifier":"id",
"items":[
{"id":1,"name":"Волгоград"},
{"id":2,"name":"Москва"},
{"id":3,"name":"Минск"},
{"id":4,"name":"Мурманск"}
]
}
AjaxZend_Dojo_Data
В шаблоне:
<div class="tundra"><?=$this->form?></div>
Вуаля!
AjaxJSON-RPC
Клиентская часть (в шаблоне):
<? $this->dojo()->requireModule("dojo.rpc.JsonService"); ?>
<? $this->dojo()->onLoadCaptureStart(); ?>
function() {
var o = {
"serviceType": "JSON-RPC",
"serviceUrl": "/json/rpc-server",
"methods": [{
"name": "sum",
"parameters": [
{name: "numbers"}
]
}]
}
...
}
<? $this->dojo()->onLoadCaptureEnd(); ?>
AjaxJSON-RPC
Клиентская часть (в шаблоне):
...
var rpcObject = new dojo.rpc.JsonService(o)
var sum = rpcObject.sum([4,8,15,16,23,42]);
sum.addCallback(function(response) {
console.log("Сумма чисел: ", response)
});
Запрос:
{"params":[[4,8,15,16,23,42]],"method":"sum","id":1}
AjaxJSON-RPC
Серверная часть (модель):
class Default_Model_RpcTest
{
function sum($numbers)
{
return array_sum($numbers);
}
}
AjaxJSON-RPC
Серверная часть (контроллер):
public function rpcServerAction()
{
$server = new Zend_Json_Server();
$server->setClass('Default_Model_RpcTest');
$server->handle();
}
Результат:
AjaxRest
• Dojo Toolkit• Хранилища
• dojox.data.jsonRestStore• dojox.data.jsonQueryRestStore• dojox.data.FlickrRestStore• dojox.data.AtomReadStore• …
• Интерфейсы• Большая часть виджетов форм• dojox.Grid• …
AjaxRest
• Zend Framework• Zend_Rest_Route
• GET /product/ratings/ - indexAction()• GET /product/ratings/:id - getAction()• POST /product/ratings - postAction()• PUT /product/ratings/:id - putAction()• DELETE /product/ratings/:id - deleteAction()• POST /product/ratings/:id?_method="PUT" - putAction()• POST /product/ratings/:id?_method="DELETE" - deleteAction()
• Zend_Rest_Controller
Выпуск в эксплуатациюСлой сборки
dojo.provide("custom.main");
(function(){
dojo.require("dojo.io.script");
dojo.require("dojo.fx");
dojo.require("dijit.form.Button");
})();
custom.main.js
Выпуск в эксплуатациюПрофиль сборки
dependencies = {
action:"release", optimize:"shrinksafe",
layerOptimize:"shrinksafe", copyTests:false,
loader:"default", cssOptimize:"comments",
releaseName:"custom",
layers:[{
name:"custom.main.js",
layerDependencies:[],
dependencies:["custom.main"]
}],
prefixes:[
["custom","../custom"],
["dojo","../dojo"],
["dijit","../dijit"]
]
};
Выпуск в эксплуатациюГенерация профиля и слоя
public function buildAction()
{
$build = new Zend_Dojo_BuildLayer(array(
'view' => $this->view,
'layerScriptPath' => 'custom.main.js',
'layerName' => 'custom.main',
));
$profile = $build->generateBuildProfile();
$layerScript = $build->generateLayerScript();
}
Zend_Dojo_BuildLayer автоматически генерирует содержание профиляи содержание слоя на основе данных из view-хелпера dojo().
Подробнее?
• Dojo Toolkit• Документация
• http://api.dojotoolkit.org• http://docs.dojocampus.org
• Блоги• http://dojotoolkit.org/rss.xml• http://dojocampus.org/content/feed
• IRC• #dojo на irc.freenode.net
• Список рассылки dojo-interest• http://dojotoolkit.org/mailman/listinfo/dojo-interest
Подробнее?
• Zend Framework• Документация
• http://framework.zend.com/manual• Wiki
• http://framework.zend.com/wiki• Блоги
• http://devzone.zend.com• http://framework.zend.com
• IRC• #zftalk on irc.freenode.net
• Списки рассылок• http://framework.zend.com/archives
• Развитое русскоязычное сообщество• http://zendframework.ru (основатель: Александр Махомет)
Вопросы?E-mail: [email protected]
Георгий Туревич, Wizartech