<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>CTAPbIu_MABP&#039;s BLOG &#187; ExtJS</title>
	<atom:link href="http://mabp.kiev.ua/tag/extjs/feed/" rel="self" type="application/rss+xml" />
	<link>http://mabp.kiev.ua</link>
	<description>энтузиазм = 1/опыт © Старый Мавр</description>
	<lastBuildDate>Thu, 26 Jan 2012 10:34:13 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2</generator>
		<item>
		<title>Cascading comboboxes on GWT, ExtGWT, ExtJS и MySQL</title>
		<link>http://mabp.kiev.ua/2009/06/12/cascading-comboboxes-on-gwt-extgwt-extjs-and-mysql/</link>
		<comments>http://mabp.kiev.ua/2009/06/12/cascading-comboboxes-on-gwt-extgwt-extjs-and-mysql/#comments</comments>
		<pubDate>Fri, 12 Jun 2009 12:27:44 +0000</pubDate>
		<dc:creator>CTAPbIu_MABP</dc:creator>
				<category><![CDATA[JAVA]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[Программирование]]></category>
		<category><![CDATA[combobox]]></category>
		<category><![CDATA[ExtJS]]></category>
		<category><![CDATA[GWT]]></category>

		<guid isPermaLink="false">http://mabp.kiev.ua/?p=1078</guid>
		<description><![CDATA[Я уже давно грозился выложить свежую версию каскадных выпадающих списков на GWT 1.5.3, ExtGWT 1.2, ExtJS 2.2.1 и MySQL 5.1. Код был написан еще в конце апреля, но меня все ломало написать к нему текстовку. А сейчас когда на подходе выход ExtGWT 2.0 и ExtJS 3.0 я решил пошевелиться и накрапать небольшое описалово. Действительно небольшое [...]]]></description>
			<content:encoded><![CDATA[<p>Я уже давно грозился выложить свежую версию каскадных выпадающих списков на GWT 1.5.3, ExtGWT 1.2, ExtJS 2.2.1 и MySQL 5.1. Код был написан еще в конце апреля, но меня все ломало написать к нему текстовку. А сейчас когда на подходе выход ExtGWT 2.0 и ExtJS 3.0 я решил пошевелиться и накрапать небольшое описалово. Действительно небольшое потому что все настройки я уже описал в <a href="http://mabp.kiev.ua/2009/04/12/gwt-extjs-connecting-to-mysql/">предыдущей статье</a>, так что тут будут описаны только изменения.</p>
<span id="more-1078"></span>
<p>Для начала опишу изменения в БД, я ее полностью поменял. Теперь у нас вместо машинок будут города и страны, но смысл тот же.</p>
<pre><code class="sql">
DROP TABLE IF EXISTS `city`;
CREATE TABLE IF NOT EXISTS `city` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL,
  `parent` int(10) unsigned NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=50 ;

INSERT INTO `city` (`id`, `name`, `parent`) VALUES
(1, 'Kiev', 1),
(2, 'Lviv', 1),
(3, 'Odesa', 1),
(4, 'Kharkov', 1),
(5, 'Lugansk', 1),
(6, 'Zaporizhzhia', 1),
(7, 'Mariupol', 1),
(8, 'Moskow', 2),
(9, 'Volgograd', 2),
(10, 'Samara', 2),
(11, 'Kazan', 2),
(12, 'Perm', 2),
(13, 'Eburg', 2),
(14, 'Chelyabinsk', 2),
(15, 'Minsk', 3),
(16, 'Homel', 3),
(17, 'Grodno', 3),
(18, 'Vitebsk', 3),
(19, 'Le Havre', 4),
(20, 'Rennes', 4),
(21, 'Nantes', 4),
(22, 'Berdeaux', 4),
(23, 'Toulouse', 4),
(24, 'Montpellier', 4),
(25, 'Marseille', 4),
(26, 'Lyon', 4),
(27, 'Paris', 4),
(28, 'Reims am Main', 5),
(29, 'Berlin', 5),
(30, 'Bremen', 5),
(31, 'Hannover', 5),
(32, 'Hamburg', 5),
(33, 'Frankfurt', 5),
(34, 'Munchen', 5),
(35, 'Strasbourg', 5),
(36, 'Milano', 6),
(37, 'Bologna', 6),
(38, 'Genova', 6),
(39, 'Roma', 6),
(40, 'Napoli', 6),
(41, 'Palermo', 6),
(42, 'London', 7),
(43, 'Bristol', 7),
(44, 'Birmingham', 7),
(45, 'Liverpool', 7),
(46, 'Manchester', 7),
(47, 'Edinburg', 7),
(48, 'Glasgow', 7),
(49, 'Belfast', 7);

DROP TABLE IF EXISTS `country`;
CREATE TABLE IF NOT EXISTS `country` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=8 ;

INSERT INTO `country` (`id`, `name`) VALUES
(1, 'Ukrain'),
(2, 'Russia'),
(3, 'Belarus'),
(4, 'France'),
(5, 'German'),
(6, 'Italia'),
(7, 'Uniited Kingdom');
</code></pre>

<p>И EntryPoint у нас на этот раз будет по проще. В нем не будет кучи виджетов, а только один.</p>

<pre><code class="java">
package ua.kiev.mabp.client;

import com.extjs.gxt.ui.client.Events;
import com.extjs.gxt.ui.client.Style.Scroll;
import com.extjs.gxt.ui.client.event.BaseEvent;
import com.extjs.gxt.ui.client.event.Listener;
import com.extjs.gxt.ui.client.widget.ContentPanel;
import com.extjs.gxt.ui.client.widget.Viewport;
import com.extjs.gxt.ui.client.widget.form.FormPanel;
import com.extjs.gxt.ui.client.widget.layout.FitLayout;
import com.extjs.gxt.ui.client.widget.layout.FlowLayout;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.user.client.ui.RootPanel;
import ua.kiev.mabp.client.utility.CityToCountryUtility;
import ua.kiev.mabp.client.widget.CitySuggestBox;
import ua.kiev.mabp.client.widget.CountrySuggestBox;

public class HelloWorld implements EntryPoint {

    public void onModuleLoad() {

        // создаем рабочую область
        ContentPanel contentPanel = new ContentPanel();
        contentPanel.setLayout(new FitLayout());
        contentPanel.setHeading("Cascading combobox");

        // и новый комбобокс для стран
        CountrySuggestBox countrySuggestBox = new CountrySuggestBox();
        countrySuggestBox.setDisplayField("name");
        countrySuggestBox.setFieldLabel("Country");

        // вот тут вся магия
        CityToCountryUtility.getInstance().setCountryComboBox(countrySuggestBox);

        // ну и листенер конечно
        countrySuggestBox.addListener(Events.SelectionChange, new Listener&lt;BaseEvent&gt;(){
            public void handleEvent(BaseEvent be) {
                CityToCountryUtility.getInstance().eraseCity();
            }
        });

        // новый комбобокс для городов
        CitySuggestBox citySuggestBox = new CitySuggestBox();
        citySuggestBox.setDisplayField("name");
        citySuggestBox.setFieldLabel("City");
        citySuggestBox.setForceSelection(false);

        // еще немного магии
        CityToCountryUtility.getInstance().setCityComboBox(citySuggestBox);

        // дальше манипуляции с отображением 
        FormPanel formPanel = new FormPanel();
        formPanel.setHeaderVisible(false);
        formPanel.add(countrySuggestBox);
        formPanel.add(citySuggestBox);

        contentPanel.add(formPanel);

        Viewport viewport = new Viewport();
        viewport.setLayout(new FlowLayout());
        viewport.setScrollMode(Scroll.AUTO);
        viewport.add(contentPanel);
        RootPanel.get().add(viewport);
    }
}
</code></pre>

<p>Тут интересны два, точнее три объекта, CountrySuggestBox, CitySuggestBox и CityToCountryUtility, но два практически одинаковые, поэтому я буду рассказывать только про больший.</p>
<pre><code class="java">
package ua.kiev.mabp.client.widget;

import com.extjs.gxt.ui.client.data.BasePagingLoadConfig;
import com.extjs.gxt.ui.client.data.BasePagingLoadResult;
import com.extjs.gxt.ui.client.data.ModelData;
import com.extjs.gxt.ui.client.data.RpcProxy;
import ua.kiev.mabp.client.proxy.CitySuggestBoxRpcProxy;

/**
 * Created by IntelliJ IDEA.
 * User: CTAPbIu_MABP
 * Date: 16.04.2009
 * Time: 22:46:56
 */
public class CitySuggestBox&lt;D extends ModelData&gt; extends AbstractSuggestBox&lt;D&gt; {

    @Override
    protected RpcProxy&lt;BasePagingLoadConfig, BasePagingLoadResult&lt;D&gt;&gt; getRpcProxy() {
        return new CitySuggestBoxRpcProxy&lt;BasePagingLoadConfig, BasePagingLoadResult&lt;D&gt;&gt;();
    }
}
</code></pre>
<p>CitySuggestBox и CountrySuggestBox всеголишь обертки, поэтому показываю AbstractSuggestBox.</p>

<pre><code class="java">
package ua.kiev.mabp.client.widget;

import com.extjs.gxt.ui.client.data.*;
import com.extjs.gxt.ui.client.store.ListStore;
import com.extjs.gxt.ui.client.widget.form.ComboBox;
import com.google.gwt.user.client.Element;

/**
 * Created by IntelliJ IDEA.
 * User: CTAPbIu_MABP
 * Date: 16.04.2009
 * Time: 22:46:09
 */

public abstract class AbstractSuggestBox&lt;D extends ModelData&gt; extends ComboBox&lt;D&gt; {

    public AbstractSuggestBox() {
        RpcProxy&lt;BasePagingLoadConfig, BasePagingLoadResult&lt;D&gt;&gt; proxy = getRpcProxy();
        PagingLoader&lt;BasePagingLoadConfig&gt; bpl = new BasePagingLoader&lt;BasePagingLoadConfig, BasePagingLoadResult&lt;D&gt;&gt;(proxy);
        ListStore&lt;D&gt; store = new ListStore&lt;D&gt;(bpl);
        setStore(store);
        setTypeAhead(true);
        setForceSelection(true);
        setPageSize(5);
        setWidth("500px");
    }

    protected abstract RpcProxy&lt;BasePagingLoadConfig, BasePagingLoadResult&lt;D&gt;&gt; getRpcProxy();

    @Override
    protected void onRender(Element parent, int index) {
        setEditable(true);
        setTriggerAction(TriggerAction.QUERY);
        super.onRender(parent, index);
    }
}
</code></pre>

<p>Тут тоже практически ничего интересного - главное получить правильно параметризированый RpcProxy. Дальше дело техники. Прокси на самом деле тоже только обертка.</p>

<pre><code class="java">
package ua.kiev.mabp.client.proxy;

import com.extjs.gxt.ui.client.data.BasePagingLoadConfig;
import com.extjs.gxt.ui.client.data.RpcProxy;
import com.extjs.gxt.ui.client.widget.Info;
import com.google.gwt.user.client.rpc.AsyncCallback;
import ua.kiev.mabp.client.HelloWorldService;
import ua.kiev.mabp.client.HelloWorldServiceAsync;
import ua.kiev.mabp.client.utility.CityToCountryUtility;

/**
 * Created by IntelliJ IDEA.
 * User: CTAPbIu_MABP
 * Date: 16.04.2009
 * Time: 22:51:48
 */
public class CitySuggestBoxRpcProxy&lt;C extends BasePagingLoadConfig, D&gt; extends RpcProxy&lt;C, D&gt; {

    final HelloWorldServiceAsync service = HelloWorldService.App.getInstance();

    @Override
    protected final void load(C loadConfig, final AsyncCallback&lt;D&gt; asyncCallback) {
        String parernt = CityToCountryUtility.getInstance().getParentForCity();
        loadConfig.getParams().put("parent", parernt);
        service.getCity(loadConfig, new AsyncCallback&lt;D&gt;() {
            public void onSuccess(D result) {
                Info.display("Success", "success");
                asyncCallback.onSuccess(result);
            }

            public void onFailure(Throwable caught) {
                Info.display("Failure", "fail");
                asyncCallback.onFailure(caught);
            }

        });
    }
}
</code></pre>

<p>Но только эта обертка для городов имеет две лишних строки (по сравнению с оберткой для стран) в которых происходит получение выбранной страны и подставления этого значения в параметры запроса. Для этого я использую класс CityToCountryUtility, который реализует паттерн Registry.</p>

<pre><code class="java">
package ua.kiev.mabp.client.utility;

import com.extjs.gxt.ui.client.data.ModelData;
import ua.kiev.mabp.client.widget.CitySuggestBox;
import ua.kiev.mabp.client.widget.CountrySuggestBox;

/**
 * Created by IntelliJ IDEA.
 * User: CTAPbIu_MABP
 * Date: 28.04.2009
 * Time: 15:20:29
 */
public class CityToCountryUtility {

    private static CityToCountryUtility manager;
    private CountrySuggestBox country;
    private CitySuggestBox city;

    private CityToCountryUtility() {

    }

    public static CityToCountryUtility getInstance() {
        if (manager == null) {
            manager = new CityToCountryUtility();
        }
        return manager;
    }

    public void setCountryComboBox(CountrySuggestBox country) {
        this.country = country;
    }

    public void eraseCity() {
        //city.clearSelections();
        city.getStore().removeAll();
    }

    public void setCityComboBox(CitySuggestBox city) {
        this.city = city;
    }

    public String getParentForCity() {
        ModelData value = country.getValue();
        return value != null ? (String) value.get("abbr") : "";
    }
}
</code></pre>

<p>Пожалуй это все что надо для того, чтобы сделать каскадные комбобоксы. Повторюсь что как настроить мавен, какие либы подключать и как замапить комбобокс к базе данных описано в <a href="http://mabp.kiev.ua/2009/04/12/gwt-extjs-connecting-to-mysql/">предыдущей статье</a>. Осталось только прикрепить <a href="http://mabp.kiev.ua/content/source/cascading_combobox.rar">проект</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://mabp.kiev.ua/2009/06/12/cascading-comboboxes-on-gwt-extgwt-extjs-and-mysql/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>GWT+EXTJS подключаем MySQL</title>
		<link>http://mabp.kiev.ua/2009/04/12/gwt-extjs-connecting-to-mysql/</link>
		<comments>http://mabp.kiev.ua/2009/04/12/gwt-extjs-connecting-to-mysql/#comments</comments>
		<pubDate>Sun, 12 Apr 2009 14:22:40 +0000</pubDate>
		<dc:creator>CTAPbIu_MABP</dc:creator>
				<category><![CDATA[JAVA]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[Программирование]]></category>
		<category><![CDATA[combobox]]></category>
		<category><![CDATA[ExtJS]]></category>
		<category><![CDATA[GWT]]></category>

		<guid isPermaLink="false">http://mabp.kiev.ua/?p=1051</guid>
		<description><![CDATA[Очень долго, чуть больше недели готовил эту статью, начал с того что написал по статье об установке каждого используемого компонента, а теперь не знаю с чего начать :) Начну с описания того, что буду делать. Я попробую создать тонкий клиент используя GWT и GWT-Ext. Кто уже на этом месте начал кричать "GWT-Ext устарела надо использовать [...]]]></description>
			<content:encoded><![CDATA[<p>Очень долго, чуть больше недели готовил эту статью, начал с того что написал по статье об установке каждого используемого компонента, а теперь не знаю с чего начать :)</p>
<span id="more-1051"></span>
<p>Начну с описания того, что буду делать. Я попробую создать тонкий клиент используя GWT и GWT-Ext. Кто уже на этом месте начал кричать "GWT-Ext устарела надо использовать GXT" может смело закрывать вкладку браузера [x]. Остальные если не знают что такое и как установить <a href="http://mabp.kiev.ua/2009/04/09/install-intellij-idea/">IntelliJ IDEA</a> и <a href="http://mabp.kiev.ua/2009/04/09/install-maven-2/">Maven</a> отвлекаются от статьи на 20 минут на прочтение инструкций и установку софта. Инструкция об установке <a href="http://mabp.kiev.ua/2009/04/10/install-google-web-toolkit/">Google Web Toolkit</a> тоже имеется, а вот по установке MySQL мне было лень писать.</p>
<p>Теперь собственно о тонком клиенте, он будет немного не доделан. Дело в том что в одну статью все не впихнуть и в этой будут продемонстрированы только некоторые части интерфейса, потому что основной темой будет взаимодействие с базой данных MySQL. Все известные мне мануалы рассказываю как передавать данные в GWT используя XML или JSON сгенерированные PHP, а я хочу чтобы GWT получал данные напрямую из базы и передавал на клиент в сериализированом виде.</p>

<p>Если вы хотите попробовать запустить пример вот ссылка для скачивания <a href="http://mabp.kiev.ua/content/source/HelloWorld.zip" rel="nofollow">проекта</a> и исходников <a href="http://yogurtearl.com/ext-2.0.2.zip" rel="nofollow external">ext-js 2.0.2</a></p>

<p>Теперь об используемых компанентах: помимо всего прочего я буду использовать Spring Framefork, Hibernate, Log4j, JUnit и базу данных MySQL. Для того чтобы не разруливать немыслимое количество зависимостей в этих компонентах я и предложил вам поставить Maven, а еще он удобен для сборки билда. Я написал конфигурационный файл в который включил все необходимые зависимости и плагины для сборки. Я, если честно, не очень силен в конфигурации Maven'а, поэтому большая часть настроек была скопирована из мануала по GWT. Конфиг очень большой и его нет смысла выкладывать здесь, поэтому чтоб его посмотреть придется скачать проект.</p>

<p>Когда загрузите проект откроете закладку Maven'а и нажмете на кнопку закачать все артефакты</p>

<div style="text-align:center"><img src="/content/img/gwt_extjs_mysql/maven.jpg" alt="Control Panel" width="260" height="600"/></div>

<p>Если у вас медленное соединение или еще какие-то проблемы Maven может закачать не все и отказаться скачивать повторно. В общем я советую сразу через командную строку зайти в папку с проектом и выполнить команду:</p>

<pre><code class="bat">
mvn eclipse:eclipse -Declipse.downloadSources=true -DdownloadJavadocs=true
</code></pre>

<p>Эта команда скачает плагин для Eclipse, который умеет качать исходники и доки, правда он попутно закачивает еще какие-то свои файлы, а после работы создает файлы проекта Eclipse которые можно смело удалять по завершению загрузки. В общей сложности Maven скачает примерно 120 метров кода и документации.</p>

<p>В начале статьи была ссылка на EXT-JS, нужно скачать именно версию 2.0.2 (или 2.0.5 но тогда вы нарушите лицензию) c более поздними GWT-EXT работать не хочет. EXT-JS нужно распаковать в D:ideaHelloWorldsrcmainjavauakievmabppublicjsext , позже я объясню почему именно сюда.</p>

<p>Теперь когда у вас есть все исходники, нужно настроить базу данных, откройте файл D:ideaHelloWorldsrcmainresourcesdb.properties и начинайте править настройки подключения.</p>

<pre><code class="ini">
jdbc.driverClassName=com.mysql.jdbc.Driver			<- не менять
jdbc.url=jdbc:mysql://localhost:3306/helloworld		<- helloworld это имя базы
jdbc.username=root						<- пользователь
jdbc.password=qwerty					<- пароль
hibernate.dialect=org.hibernate.dialect.MySQL5Dialect	<- диалект
hibernate.default_schema=helloworld			<- схема, можно не трогать
</code></pre>

Первую строку строгать не надо, во второй, после последнего слеша надо написать название БД, в третей - имя пользователя, в четвертой - пароль, разрабатывал на MySQL 5.1 если у вас 4 то в пятой надо убрать цифру 5, шестую можно не трогать. Структура таблицы и дамп данных наже:</p>

<pre><code class="sql">
SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO";

CREATE TABLE IF NOT EXISTS `car` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `model` varchar(255) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=43 ;

INSERT INTO `car` (`id`, `model`) VALUES
(1, 'Audi'),
(2, 'BMW'),
(3, 'Lexus'),
(4, 'Ford'),
(5, 'Honda'),
(6, 'Chevrolet'),
(7, 'KIA'),
(8, 'Mercedes'),
(9, 'Mitsubishi'),
(10, 'Nissan'),
(11, 'Opel'),
(12, 'Rover'),
(13, 'Subaru'),
(14, 'Toyota'),
(15, 'Volkswagen'),
(16, 'Volvo'),
(17, 'Mazda'),
(18, 'Skoda'),
(19, 'Lincoln'),
(20, 'Infiniti'),
(21, 'Cadillac'),
(22, 'Renault'),
(23, 'Daevoo'),
(24, 'Jeep'),
(25, 'Pontiac'),
(26, 'Hummer'),
(27, 'Bentley'),
(28, 'Isuzu'),
(29, 'Seat'),
(30, 'Fiat'),
(31, 'GMC'),
(32, 'Land Rover'),
(33, 'Porsche'),
(34, 'Jaguar'),
(35, 'Hyundai'),
(36, 'Peugeot'),
(37, 'Aston Martin'),
(38, 'Alfa Romeo'),
(39, 'Dodge'),
(40, 'Ferrari'),
(41, 'Saab'),
(42, 'Chrysler');
</code></pre>

<p>Все с базой почти закончили. Теперь надо зайти в Tools->Data Source (в восьмой идеи это панелька сбоку а в седьмой новое окно) и добавить новый источник данных как показано на скриншоте:</p>
<div style="text-align:center"><img src="/content/img/gwt_extjs_mysql/datasouce.jpg" alt="Control Panel" width="554" height="694"/></div>
<p>И наконец надо закачать данные о структуре при помощи кнопки Refresh Tables. Вот теперь с базой все.</p>

<p>Предполагается что вы все делали как я описывал в статьях по установке и все находиться на диске D:Program Files , если нет заходите в Project Structure и настраивайте </p>

<p>В закладке GWT указываете путь к GWT, после этого нажимать на кнопку FIX не нужно, потому что у вас dll'ки лежат в одной директории (D:Program Filesgwt-windows-1.5.3), а jar'ники в другой (D:Program Filesapache-maven-2.1.0repocomgooglegwtgwt-user1.5.3).</p>
<div style="text-align:center"><img src="/content/img/gwt_extjs_mysql/structure-gwt.jpg" alt="Control Panel" width="500" height="300"/></div>
<p>В закладке Spring скорее всего ничего править не придется потому что все три конфига подтянутся сами, но проверьте на всякий случай.</p>
<div style="text-align:center"><img src="/content/img/gwt_extjs_mysql/structure-spring.jpg" alt="Control Panel" width="500" height="300"/></div>
<p>В закладке JPA подключите только что созданный источник данных.</p>
<div style="text-align:center"><img src="/content/img/gwt_extjs_mysql/structure-jpa.jpg" alt="Control Panel" width="500" height="300"/></div>
<p>В закладке WEB тоже ничего делать не надо там все само подхватывается.</p>
<div style="text-align:center"><img src="/content/img/gwt_extjs_mysql/structure-web.jpg" alt="Control Panel" width="500" height="300"/></div>
<p>Возвращайтесь в корень настроек проекта, там три закладки, на первой (Sources) отметьте папки с исходниками (main/java), тестами (test/java)</p>
<div style="text-align:center"><img src="/content/img/gwt_extjs_mysql/structure-sources.jpg" alt="Control Panel" width="500" height="300"/></div>
<p>На второй (Paths) кажется ничего делать не надо</p>
<div style="text-align:center"><img src="/content/img/gwt_extjs_mysql/structure-paths.jpg" alt="Control Panel" width="500" height="300"/></div>
<p>А на закладке (Dependencies) проверьте чтоб не было пакета gwt-user (это значит вы все-таки нажали на кнопку FIX на закладке GWT) и был файл javaee.jar</p>
<div style="text-align:center"><img src="/content/img/gwt_extjs_mysql/structure-dependencies.jpg" alt="Control Panel" width="500" height="300"/></div>

<p>Так все настройки закончили переходим к запуску программы.</p>

<p>Maven и GWT навязываю нам свою структуру проекта. От Maven нам достается разделение кода на исходники (main) и тесты (test), а от GWT три пакета: client - то что в последствии станет javascript кодом, public - статические ресурсы, сюда кладется ext-js, и server - классы которые работают на сервере, например для работы с БД.</p>

<p>Для минимального запуска нужно всего несколько файлов. Клаcc ua.kiev.mabp.client.HelloWorld расширяет точку входа в приложение, там задаются основные layuot'ы. HelloWorld.css и HelloWorld.html нужны для каркаса с которым будут работать все js функции. В HelloWorld.gwt.xml указываеться какие модули наследует сценарий. И наконец web.xml определяет точку входа (servlet) в приложение.</p>

<p>В примере есть несколько layaut'ов. Первый это выбор страны и города, демонстрирует функционал связанных выпадающих списков. Второй выбор даты, календари тоже должны были не пересекаться но к сожалению в ext-js 2.0.2 этого функционала еще не было (я опишу его в следующей статье где использую ext-js 2.2.1) поэтому использована валидация полей. Выбор марки автомобиля собственно тат самый виджет ради которого вся статья. И последний это выбор цвета, там совсем все просто.</p>

<pre><code class="java">
package ua.kiev.mabp.client;

import com.google.gwt.core.client.EntryPoint;
import com.gwtext.client.widgets.Panel;
import com.gwtext.client.widgets.Viewport;
import com.gwtext.client.widgets.form.FieldSet;
import com.gwtext.client.widgets.layout.AnchorLayout;
import com.gwtext.client.widgets.layout.AnchorLayoutData;
import com.gwtext.client.widgets.layout.ColumnLayout;
import com.gwtext.client.widgets.layout.ColumnLayoutData;
import ua.kiev.mabp.client.widgets.CarPanel;
import ua.kiev.mabp.client.widgets.ColorPanel;
import ua.kiev.mabp.client.widgets.DatePanel;
import ua.kiev.mabp.client.widgets.LocationPanel;

/**
 * Created by IntelliJ IDEA.
 * User: CTAPbIu_MABP
 * Date: 10.04.2009
 * Time: 22:58:15
 */

public class HelloWorld implements EntryPoint {

	public void onModuleLoad() {
		Panel panel = new Panel();
		panel.setBorder(false);
		panel.setPaddings(15);
		panel.setLayout(new AnchorLayout());

		panel.add(new FieldSet(), new AnchorLayoutData("100%"));

		Panel wrapperPanel = new Panel();
		wrapperPanel.setBorder(false);

		Panel columnOnePanel = new Panel();
		columnOnePanel.setBorder(false);
		columnOnePanel.setLayout(new AnchorLayout());
		columnOnePanel.add(new LocationPanel(), new AnchorLayoutData("100%"));
		columnOnePanel.add(new DatePanel(), new AnchorLayoutData("100%"));
		columnOnePanel.add(new CarPanel(), new AnchorLayoutData("100%"));

		Panel columnTwoPanel = new Panel();
		columnTwoPanel.setBorder(false);
		columnTwoPanel.setLayout(new AnchorLayout());
		columnTwoPanel.add(new ColorPanel(), new AnchorLayoutData("100%"));

		wrapperPanel.setLayout(new ColumnLayout());
		wrapperPanel.add(columnOnePanel, new ColumnLayoutData(.5));
		wrapperPanel.add(columnTwoPanel, new ColumnLayoutData(.5));

		panel.add(wrapperPanel, new AnchorLayoutData("100%"));
		panel.add(new FieldSet(), new AnchorLayoutData("100%"));

		new Viewport(panel);
	}
}
</code></pre>

<p>Немного поигравшись с layaut'ами можно начать прикручивать БД, данные из которой получает выпадающий список.</p>

<pre><code class="java">
package ua.kiev.mabp.client.widgets;

import com.gwtext.client.core.Template;
import com.gwtext.client.core.UrlParam;
import com.gwtext.client.data.*;
import com.gwtext.client.widgets.Panel;
import com.gwtext.client.widgets.form.ComboBox;
import com.gwtext.client.widgets.form.FieldSet;
import com.gwtext.client.widgets.form.event.ComboBoxListenerAdapter;
import ua.kiev.mabp.client.proxies.MyProxy;

/**
 * Created by IntelliJ IDEA.
 * User: CTAPbIu_MABP
 * Date: 10.04.2009
 * Time: 22:58:15
 */

public class CarPanel extends FieldSet {
	public CarPanel(){
	super("Select your car");

		// определяе вид записи
		FieldDef[] fieldDefs = new FieldDef[]{new StringFieldDef("id"), new StringFieldDef("model")};
		RecordDef recordDef = new RecordDef(fieldDefs);

		// создаем хранилище
		final Store store = new Store(new MyProxy(), new ArrayReader(recordDef), true);
		store.setBaseParams(new UrlParam[]{new UrlParam("paramName", "paramValue")});

		// создаем новую панель
		// сюда будет дублироваться выбраный результат
		final Panel instructionPanel = new Panel();
		instructionPanel.setBorder(false);
		instructionPanel.setHeight(24);
		instructionPanel.setHtml("Car model doesn't selected yet");

		// создаем новый шаблон
		final Template template = new Template("&lt;div class="x-combo-list-item"&gt;" +
				"&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;" +
				"&lt;td style="width:50px;border-right:2px dotted #A3BAE9;"&gt;{id}&lt;/td&gt;" +
				"&lt;td style="width:200px;border-right:2px dotted #A3BAE9;"&gt;{model}&lt;/td&gt;" +
				"&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;" +
				"&lt;div class="x-clear"&gt;&lt;/div&gt;&lt;/div&gt;");

		// создаем новый выпадающий список 
		// и присваеваем ему хранилище и шаблон
		final ComboBox carComboBox = new ComboBox();
		carComboBox.setMinChars(1);
		carComboBox.setFieldLabel("Label");
		carComboBox.setStore(store);
		carComboBox.setDisplayField("model");
		carComboBox.setMode(ComboBox.LOCAL);
		carComboBox.setTriggerAction(ComboBox.ALL);
		carComboBox.setForceSelection(true);
		carComboBox.setEmptyText("Choose car model");
		carComboBox.setTypeAhead(true);
		carComboBox.setSelectOnFocus(true);
		carComboBox.setResizable(true);
		carComboBox.setTpl(template);
		carComboBox.setHideLabel(true);

		// устанавливаем листенер
		carComboBox.addListener(new ComboBoxListenerAdapter() {
			public void onSelect(ComboBox comboBox, Record record, int index) {
				instructionPanel.setHtml(record.getAsString("id") + " " + record.getAsString("model"));
			}
		});

		// добавляем все в текущий layout
		add(carComboBox);
		add(instructionPanel);

		// загружаем в список 5 первых элементов
		store.load(0, 5);
	}
}

</code></pre>

<p>Итак кроме того что виджет CarPanel создает ComboBox с листенером он использует для получения данных прокси MyProxy.</p>


<p>Итак кроме того что виджет CarPanel создает ComboBox с листенером он использует для получения данных прокси MyProxy.</p>

<pre><code class="java">
package ua.kiev.mabp.client.proxies;

import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.gwtext.client.core.UrlParam;
import ua.kiev.mabp.client.HelloWorldService;
import ua.kiev.mabp.client.beans.ArrayBean;

/**
 * Created by IntelliJ IDEA.
 * User: CTAPbIu_MABP
 * Date: 10.04.2009
 * Time: 22:58:15
 */

public class MyProxy extends GWTProxy {

	/**
	 * Загружает данные в объект
	 *
	 * @param start позиция первого элемента
	 * @param limit количество элемента
	 * @param sort сортировка
	 * @param dir направление сортировки
	 * @param javaScriptObject объект
	 */
	public void load(int start, int limit, String sort, String dir, JavaScriptObject javaScriptObject) {
		load(start, limit, sort, dir, javaScriptObject, null);
	}
	
	/**
	 * Загружает данные в объект
	 *
	 * @param start позиция первого элемента
	 * @param limit количество элемента
	 * @param sort сортировка
	 * @param dir направление сортировки
	 * @param o объект
	 * @param baseParams параметры запроса
	 */
	public void load(int start, int limit, String sort, String dir, final JavaScriptObject o, UrlParam[] baseParams) {
		String[][] params = new String[0][];
		HelloWorldService.App.getInstance().getCars(start, limit, sort, dir, params, new AsyncCallback() {
			public void onFailure(Throwable caught) {
				loadResponse(o, false, 0, (JavaScriptObject) null);
			}
			
			public void onSuccess(Object result) {
				ArrayBean response = (ArrayBean) result;
				loadResponse(o, true, response.totalPages, response.data);
			}
		});
	}
}

</code></pre>

<p>Класс MyProxy наследует класс GWTProxy который был выдран мной из проекта gwt-ext-ux (com.gwtextux.client.data.GWTProxy), который я счел не нужным подключать из-за одного класса. Самый большой интерес в классе MyProxy представляет вызов метода HelloWorldService.App.getInstance().getCars() .</p>

<pre><code class="java">
package ua.kiev.mabp.client;

import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.rpc.RemoteService;
import com.google.gwt.user.client.rpc.ServiceDefTarget;
import ua.kiev.mabp.client.beans.ArrayBean;

/**
 * Created by IntelliJ IDEA.
 * User: CTAPbIu_MABP
 * Date: 10.04.2009
 * Time: 22:58:15
 */

public interface HelloWorldService extends RemoteService {

	public static class App {
		private static HelloWorldServiceAsync ourInstance = null;

		public static synchronized HelloWorldServiceAsync getInstance() {
			if (ourInstance == null) {
				ourInstance = (HelloWorldServiceAsync) GWT.create(HelloWorldService.class);
				((ServiceDefTarget) ourInstance).setServiceEntryPoint(GWT.getModuleBaseURL() + "ua.kiev.mabp.HelloWorld/HelloWorldService");
			}
			return ourInstance;
		}
	}

	public ArrayBean getCars(int start, int limit, String sort, String dir, String params[][]);
}
</code></pre>
<p>HelloWorldService это интерфейс описанный в пакете client и имеющий реализацию в пакете server. Внутренний класс App знает о бэкенде у которого можно получить данные. Этот бекэнд описывается в конфигах в HelloWorld.gwt.xml и web.xml .</p>

<pre><code class="java">
package ua.kiev.mabp.server;

import com.google.gwt.user.server.rpc.RemoteServiceServlet;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import ua.kiev.mabp.server.beans.DaoManager;
import ua.kiev.mabp.server.beans.ArrayHelper;
import ua.kiev.mabp.server.beans.entity.Car;
import ua.kiev.mabp.client.HelloWorldService;
import ua.kiev.mabp.client.beans.ArrayBean;
import java.util.Collection;

/**
 * Created by IntelliJ IDEA.
 * User: CTAPbIu_MABP
 * Date: 10.04.2009
 * Time: 22:58:15
 */

public class HelloWorldServiceImpl extends RemoteServiceServlet implements HelloWorldService {
	DaoManager daoManager = DaoManager.getInstance();
	
	public ArrayBean getCars(int start, int limit, String sort, String dir, String params[][]) {
		ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath*:ApplicationConfig.xml");
		Collection&lt;Car&gt; col = daoManager.getCarDao().getCarByCriteria(start, limit, "ASC".equals(dir), sort);
		return new ArrayBean(ArrayHelper.collectionToArrayString(col), 30);
	}
}
</code></pre>


<p>Реализующий интерфейс HelloWorldService класс HelloWorldServiceImpl, знает о конфигах Spring. Этот конфиг знает о файле db.properties в котором описано как подключиться к базе. Я не буду опубликовывать тут весь конфиг, только самую интересную его часть. </p>

<pre><code class="xml">
&lt;bean id="car" class="ua.kiev.mabp.server.beans.dao.CarDAO"&gt;
	&lt;property name="sessionFactory" ref="sessionFactory"/&gt;
&lt;/bean&gt;
&lt;bean id="daoManager" class="ua.kiev.mabp.server.beans.DaoManager" factory-method="getInstance"&gt;
	&lt;property name="carDao" ref="car"/&gt;
&lt;/bean&gt;
</code></pre>

<p>Тут описывается что singleton класс DaoManager для своего создания использует метод getInstance и что ему нужно наполнить свойство carDao классом CarDAO</p>

<pre><code class="java">
package ua.kiev.mabp.server.beans.dao;

import ua.kiev.mabp.server.beans.entity.Car;

import java.util.List;

/**
 * Created by IntelliJ IDEA.
 * User: CTAPbIu_MABP
 * Date: 10.04.2009
 * Time: 22:58:15
 */

public class CarDAO extends DAOBean  {
	
	/**
	 * Сохраняет элемент
	 *
	 * @param bean элемент
	 */
	public void save(Car bean) {
		getHibernateTemplate().save(Car.class.getName(), bean);
	}
	
	/**
	 * Удаляет элемент
	 *
	 * @param bean элемент
	 */
	public void delete(Car bean) {
		getHibernateTemplate().delete(bean);
	}
	
	/**
	 * Получает список объектов
	 *
	 * @param start позиция первого элемента
	 * @param limit количество элемента
	 * @param sort сортировка
	 * @param fieldName название поля
	 * @return список
	 */
	public List&lt;Car&gt; getCarByCriteria(int start, int limit, boolean sort, String fieldName) {
		return getObjectsByCriteria(start, limit, sort, fieldName, Car.class);
	}
	
	/**
	 * Получает весь список операций
	 *
	 * @return коллекция операций
	 */
	public List&lt;Car&gt; getAllCar() {
		return getHibernateTemplate().loadAll(Car.class);
	}
	
	/**
	 * Получает список операция по производству машины
	 *
	 * @param s где произведена
	 * @return коллекция операция
	 */
	public List&lt;Car&gt; getCarByModel(String s) {
		return getHibernateTemplate().findByNamedQueryAndNamedParam("findByModelFromCar", "model", s);
	}
	
	/**
	 * Получает операции по id
	 *
	 * @param id номер операции
	 * @return коллекция операций
	 */
	public Car getCarById(Integer id) {
		return (Car) getHibernateTemplate().get(Car.class, id);
	}
}

</code></pre>

<p>Класс CarDAO содержит метод getCarByCriteria который вызывается в классе HelloWorldServiceImpl. Метод возвращает список бинов Car. Немного отвлекусь и расскажу о дополнительных возможностях. Вместо вызова getCarByCriteria можно вызывать getCarByModel передавая модель машины, это будет полезно в каскадных списках, при этом findByModelFromCar описано в классе Car в виде аннотаций.</p>

<pre><code class="java">
package ua.kiev.mabp.server.beans.entity;

import javax.persistence.*;
import java.io.Serializable;

/**
 * Created by IntelliJ IDEA.
 * User: CTAPbIu_MABP
 * Date: 10.04.2009
 * Time: 22:58:15
 */

@Entity
@Table(name = "car")
@NamedQueries({
	@NamedQuery(name = "findByModelFromCar", query = "select t from Car t where t.model=:model order by t.model"),
	@NamedQuery(name = "findByIdFromCar", query = "select t from Car t where t.id=:id")
})
public class Car implements Serializable {
	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	@Column(name = "id", unique = true, nullable = false, length = 11)
	private Integer id;
	@Column(name = "model")
	private String model;
	private static final long serialVersionUID = 5664909385244426031L;

	/**
	 * Getter for property 'id'.
	 *
	 * @return Value for property 'id'.
	 */
	public Integer getId() {
		return id;
	}
	
	/**
	 * Setter for property 'id'.
	 *
	 * @param id Value to set for property 'id'.
	 */
	public void setId(Integer id) {
		this.id = id;
	}
	
	/**
	 * Getter for property 'model'.
	 *
	 * @return Value for property 'model'.
	 */
	public String getModel() {
		return model;
	}
	
	/**
	 * Setter for property 'model'.
	 *
	 * @param model Value to set for property 'model'.
	 */
	public void setModel(String model) {
		this.model = model;
	}
}
</code></pre>

<p>После того как класс HelloWorldServiceImpl получит коллекцию бинов Car он должен превратить ее в двухмерный массив строк, который после сериализации можно передать клиенту. Все стек распутан, а рассказ подошел к концу. И стоит показать как выглядит то ради чего вы все это читали. </p>
<div style="text-align:center"><img src="/content/img/gwt_extjs_mysql/result.jpg" alt="Control Panel" width="600" height="570"/></div>

<p>Все кто дочитал до конца молодец, а я готовлю следующую статью, до скорых встреч.</p>
]]></content:encoded>
			<wfw:commentRss>http://mabp.kiev.ua/2009/04/12/gwt-extjs-connecting-to-mysql/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Возвращаяюсь к началу...</title>
		<link>http://mabp.kiev.ua/2008/03/23/back_to_the_beginning/</link>
		<comments>http://mabp.kiev.ua/2008/03/23/back_to_the_beginning/#comments</comments>
		<pubDate>Sun, 23 Mar 2008 13:32:55 +0000</pubDate>
		<dc:creator>CTAPbIu_MABP</dc:creator>
				<category><![CDATA[Голоса в голове]]></category>
		<category><![CDATA[Разное]]></category>
		<category><![CDATA[ExtJS]]></category>
		<category><![CDATA[YUI]]></category>

		<guid isPermaLink="false">http://mabp.localhost/?p=92</guid>
		<description><![CDATA[Это все про старый движок. Я вот что подумал: я отвлекся от темы. На самом деле блог задумывался как описание того «как написать движок сайта на php», собственно на примере самого блога. Так вот движок был написан где-то в январе-феврале 2007 года, за две с небольшим недели. Больше я к движку не прикасался. Связано это [...]]]></description>
			<content:encoded><![CDATA[<table style="background-color:#EDEFF0;width:100%;"><tbody><tr><th><img src="/wp-content/themes/inove/img/warning_red.png"/></th>
<th style="text-align: center;">Это все про старый движок.</th></tr></tbody></table>

<p>Я вот что подумал: я отвлекся от темы. На самом деле блог задумывался как описание того «как написать движок сайта на php», собственно на примере самого блога.</p>
<span id="more-92"></span>
<p>Так вот движок был написан где-то в январе-феврале 2007 года, за две с небольшим недели. Больше я к движку не прикасался. Связано это было не с тем что я закончил его писать и/или остался доволен результатами свое работы, а с тем что у меня закончился отпуск. В то время я работал в <a href="http://www.ssi.com.ua/" rel="nofollow external">Servus Sistems Integration</a> разработчиком пользовательских интерфейсов на <a href="http://mabp.kiev.ua/category/programming/javascript/">JavaScript</a> и к <a href="http://mabp.kiev.ua/category/programming/php/">PHP</a> вернулся только благодаря небольшому проекту от Alfa банка которому нужен был онлайновый калькулятор ипотеки. Этот калькулятор и реализовали на php+oracle. После его написания меня накрыло давнее (с времен работы на <a href="http://www.promsat.com/" rel="nofollow external">promsat</a>) желание написать собственное движло.</p>

<p>Писать было нелегко. С одной стороны опыт программирования и желание работать с другой разработка архитектуры движка, базы данных и создание UI и все сразу. Не знаешь с чего начать, чтоб получить хоть какой-то результат. Наброски классов и интерфейсов наследование и отношения которых все время меняются, заготовки кода подсмотрены в других системах, просто отдельные классы, все это перемешивается в голове создавая иллюзию готового движка, которая в 5 утра, с первыми лучами солнца разбивается о недостаток времени и сообщения дебагера. </p>

<p>Архитектура движка была выбрана фреймворковая то есть основой должно быть генерация страниц (страниц и списков) и раздача прав пользователям. Так например комментарии к страницам выполнены в виде модуля "цепляющегося" к самой странице. </p>

<p>С базой тоже все было не гладко надо было выбирать что использовать nested sets или adjustment lists и я выбрал nested sets. Для этого у человека по имени <a href="http://kuzma.russofile.ru/" rel="nofollow external">Кузьма Феськов</a> была выклянчена свежая (v3.0) версия (которую я так до сих пор нигде не видел) библиотеки <a href="http://php.russofile.ru/ru/authors/sql/nestedsets01/" rel="nofollow external">DbTree</a>, хотя к сожалению не смотря на это она так и не вошла в движок. </p>

<p>Интерфейс сайта я сначала собирался сделать с помощью <a href="http://mabp.kiev.ua/tag/yui/">YUI</a>, как раз примерно в это время появилась библиотека <a href="http://mabp.kiev.ua/tag/extjs/">ExtJS</a> тогда еще yui-ext и я с радостью начал в ней ковыряться, удачно сперев коментарии с блога <a href="http://jackslocum.com/blog/" rel="nofollow external">Jack Slocum'a</a>. Потом уже я отказался от этой идеи из-за убогости моего исполненя и того что автор перекраивал свое творение изо дня в день, а мне не хватало элементарно познания <a href="http://mabp.kiev.ua/category/programming/javascript/">JavaScript</a>, чтобы за ним хоть как-то угнаться. Так вот дизайн я решил взять портированый под <a href="http://neocrome.ru/" rel="nofollow external">Seditio</a> c движка <a href="http://www.joomla.org/" rel="nofollow">Joomla</a>, а точнее спертый с сайта  <a href="http://demo.rockettheme.com/jan06/" rel="nofollow">Rocket Theme</a> моим другом Asmo.</p>

<p>Так вот я решил реанимировать движок и дописать спустя почти год. По памяти поставив apache+php+mysql всего за 40 минут (неутешительный результат), я запустил сайт локально (странно заработал с первого раза, подозреваю грандиозный подвох) и открыв код удивился как это все вообще работает. Сейчас я собираюсь как следует подрихтовать это чудовище на предмет навигации, а также дописать авторизацию и сделать нормальные коментарии.</p>]]></content:encoded>
			<wfw:commentRss>http://mabp.kiev.ua/2008/03/23/back_to_the_beginning/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>YUI: extention</title>
		<link>http://mabp.kiev.ua/2006/12/11/yui-extention/</link>
		<comments>http://mabp.kiev.ua/2006/12/11/yui-extention/#comments</comments>
		<pubDate>Mon, 11 Dec 2006 13:16:40 +0000</pubDate>
		<dc:creator>CTAPbIu_MABP</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Программирование]]></category>
		<category><![CDATA[ExtJS]]></category>
		<category><![CDATA[layout]]></category>
		<category><![CDATA[YUI]]></category>

		<guid isPermaLink="false">http://mabp.kiev.ua/?p=1201</guid>
		<description><![CDATA[Автор Jack Locum предлагает верстать с помощью этой либы сайты. на самом деле это очень красиво но совершенно не удобно! сейчас я это докажу Предположим что у нас есть localhost и у него по адресу /yui/ лежит YUI а по адресу /yui-ext/ собственно сама библиотека Тогда создаем простой html код &#60;html&#62; &#60;head&#62; ... &#60;/head&#62; &#60;body&#62; [...]]]></description>
			<content:encoded><![CDATA[<p>Автор <a href="http://www.jackslocum.com/blog/index.php" rel="nofollow external">Jack Locum</a> предлагает верстать с помощью этой либы сайты. на самом деле это очень красиво но совершенно не удобно! сейчас я это докажу</p>
<span id="more-1201"></span>
<p>Предположим что у нас есть localhost и у него по адресу /yui/ лежит YUI а по адресу /yui-ext/ собственно сама библиотека</p>

<p>Тогда создаем простой html код</p>

<pre><code class="html">
&lt;html&gt;
&lt;head&gt;
...
&lt;/head&gt;
&lt;body&gt;
...
&lt;/body&gt;
&lt;/html&gt;
</code></pre>


<p>В хедере мы разместим наш скрипт</p>

<pre><code class="html">
&lt;link rel="stylesheet" type="text/css" href="lib/yui-ext/resources/css/yui-ext.css" /&gt;&lt;!-- подключаем стили --&gt;

&lt;script type="text/javascript" src="lib/yui/utilities/utilities.js"&gt;&lt;/script&gt;&lt;!-- yui --&gt;
&lt;script type="text/javascript" src="lib/yui-ext/yui-ext.js"&gt;&lt;/script&gt;&lt;!-- yui-ext --&gt;

&lt;!-- добавляем собстенные стили --&gt;

&lt;style type="text/css"&gt;
	body {font:normal 9pt verdana; margin:0;padding:0;border:0px none;overflow:hidden;}
	.ylayout-panel-north {
	    border:0px none;
	    background-color:#c3daf9;
	}
	#nav {
	}
	#autoTabs, #center1, #center2, #west {
	    padding:10px;
	}
	#north, #south{
	    font:normal 8pt arial, helvetica;
	    padding:4px;
	}
	.ylayout-panel-center p {
	    margin:5px;
	}
	#props-panel .ygrid-col-0{
	}
	#props-panel .ygrid-col-1{
	}
&lt;/style&gt;
</code></pre>

<p>Теперь представим, что мы хотим создать класическую трехполосную ленту, с шапкой и футером. в левой полосе прсто коллонка, по центру две закладки, две, а справа коллонка поделена на три части горизонтально; подвал  по умолчанию отключен</p>

<p>для всего этого мы в body положим основной контейнер</p> 

<pre><code class="html">
&lt;div id ="container"&gt;...&lt;/div&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;а в него по очереди все блоки которые нам понадобятся&lt;/p&gt;
&lt;pre&gt;&lt;code class="html"&gt;
&lt;div id="west" class="ylayout-inactive-content"&gt;west&lt;/div&gt;
&lt;div id="north" class="ylayout-inactive-content"&gt;north&lt;/div&gt;
&lt;div id="autoTabs" class="ylayout-inactive-content"&gt;autoTabs&lt;/div&gt;
&lt;div id="center2" class="ylayout-inactive-content"&gt;center2&lt;/div&gt;
&lt;div id="center1" class="ylayout-inactive-content"&gt;center1&lt;/div&gt;
  
&lt;div id="content1" class="ylayout-inactive-content"&gt;content1&lt;/div&gt;
&lt;div id="content2" class="ylayout-inactive-content"&gt;content2&lt;/div&gt;
&lt;div id="content3" class="ylayout-inactive-content"&gt;content3&lt;/div&gt;
  
&lt;div id="inner1" class="ylayout-inactive-content"&gt;inner1&lt;/div&gt;
&lt;div id="inner2" class="ylayout-inactive-content"&gt;inner2&lt;/div&gt;
&lt;div id="inner3" class="ylayout-inactive-content"&gt;inner3&lt;/div&gt;
&lt;div id="sqldebug" class="ylayout-inactive-content"&gt;sqldebug&lt;/div&gt;
&lt;div id="gpcdebug" class="ylayout-inactive-content"&gt;gpcdebug&lt;/div&gt;
</code></pre>

<p>Теперь приспупаем писать инициализатор</p>

<pre><code class="javascript">
        // определяем функцию которая будет стартовать наш скрипт
	Example = function(){
	        // в теле пусто 
	        return {
	            // зато она возвращает объект с одним свойством init
	            init : function(){
	               // определяем новый layout.
	               // кажждый объект BorderLayout имеет 5 свойств north west east south center
	               var layout = new YAHOO.ext.BorderLayout(document.body, {
	                    hideOnLayout: true,
	                    // говорим что north
	                    north: {
	                        // не resizable
	                        split:false,
	                        // с шириной 100
	                        initialSize: 100,
	                        // без титлбара
	                        titlebar: false
	                    },
	                    // west 
	                    west: {
	                        // resizable
	                        split:true,
	                        // появляется с размером 200
	                        initialSize: 200,
	                        // минимум при растягивании 175 
	                        minSize: 175,
	                        // максимум 400
	                        maxSize: 400,
	                        // с титл баром
	                        titlebar: true,
	                        // с кнопкой закрыть
	                        collapsible: true,
	                        // анимированный 
                            animate: true
	                    },
	                    east: {
	                        split:false,
	                        initialSize: 200,
	                        minSize: 175,
	                        maxSize: 400,
	                        titlebar: true,
	                        collapsible: true,
                            animate: true
	                    },
	                    south: {
	                        split:true,
	                        initialSize: 100,
	                        minSize: 100,
	                        maxSize: 200,
	                        titlebar: true,
	                        collapsible: true,
                            animate: true,
	                    // с скролбаром если надо
                            autoScroll:true
	                    },
	                    center: {
	                        // закладки сверху
	                        tabPosition: 'top',
	                        autoScroll:true
	                    }
	                });
	                // начинаем создавать елементы слоя
	                layout.beginUpdate();
	                // северный (хедер)
	                layout.add('north', new YAHOO.ext.ContentPanel('north', 'North'));
	                // западный с надписью в титлбаре Navigation Panel
			layout.add('west', new YAHOO.ext.ContentPanel('west', {title: 'Navigation Panel'}));
	                // перввая закладка центра
	                layout.add('center', new YAHOO.ext.ContentPanel('center1', {title: 'Main block', closable: false}));
	                // вторая закладка центра
	                layout.add('center', new YAHOO.ext.ContentPanel('center2', {title: 'Center Panel', closable: false}));
	                // по умолчанию открыта первая закладка
	                layout.getRegion('center').showPanel('center1');
	                
	                /*
	                Теперь рилическое отступление по поводу того чем неудобна эта либа
	                нельзя создать 5 блоков друг под другом можно только 3
	                но можно в каждом из трех еще по три и в каждом следующем еще по три
	                */

	                // создаем внутренний слой правого столбца
	                var innerLayout = new YAHOO.ext.BorderLayout('content1', {
	                    // нижняя часть
	                    south: {
	                        //split:true,
	                        initialSize: 100,
	                        collapsible:true,
	                        titlebar: true
	                    },
	                    // центр пуст
	                    center: { }
	                });
	                // создаем нутренний елемент внутреннего елемента 'юг'
	                var southInnerLayout  = new YAHOO.ext.BorderLayout('content2', {
	                    // только центр
	                    center: { }
	                });
	                
	                // добавляем во нутренний елемент внутреннего елемента 'юг' центральный блок
	                /*
	                вот тут былобы неплохо осознавать обектную модель 	                
	                происходящего потому что словами это обьяснять очень сложно
	                */

	                southInnerLayout.add('center', new YAHOO.ext.ContentPanel('inner1', {title:'More Information', closable:true}));

	                // создаем нутренний елемент внутреннего елемента 'центер'
	                var centerInnerLayout  = new YAHOO.ext.BorderLayout('content3', {
	                    south: {
	                        //split:true,
	                        initialSize: 100,
	                        collapsible:true,
	                        titlebar: true
	                    },
	                    center: { }
	                });
	                
	                // добавляем во нутренний елемент внутреннего елемента 'центер' центральный блок
	                centerInnerLayout.add('center', new YAHOO.ext.ContentPanel('inner2', {title:'More Information', closable:true}));
	                // добавляем во нутренний елемент внутреннего елемента 'центер' нижний блок
	                centerInnerLayout.add('south', new YAHOO.ext.ContentPanel('inner3', {title:'More Information', closable:true}));
	                // закрепляем к внутреннему елементу его 'детей' к блоку 'юг'
	                innerLayout.add('south', new YAHOO.ext.NestedLayoutPanel(southInnerLayout, {title:'More Information', closable:true}));
	                // закрепляем к внутреннему елементу его 'детей' к блоку 'центер'
	                innerLayout.add('center', new YAHOO.ext.NestedLayoutPanel(centerInnerLayout, {title:'More Information', closable:true}));

	                // закрепляем за елементов east (оноже левая коллонка) все то что мы токачто насоздавали, заголовок More Information, и кнопка закрыть
	                layout.add('east', new YAHOO.ext.NestedLayoutPanel(innerLayout, {title:'More Information', closable:true}));
	                // вот тут по вашему желанию подвал
	                if (false)
	                {
	                        // первая закладка
	                	layout.add('south', new YAHOO.ext.ContentPanel('sqldebug', {title: 'SQL-Debug', closable: true}));
	                        // и вторая
	                	layout.add('south', new YAHOO.ext.ContentPanel('gpcdebug', {title: 'GPC-Debug', closable: true}));
	                        // показываем вторую
	                	layout.getRegion('south').showPanel('gpcdebug');
	                }
	                // закрепляем елементы слоя
	                layout.endUpdate();
	           }
	     }
	       
	}();// конец функции  Example
       // стартуем Example при полной загрузке страницы 
	YAHOO.ext.EventManager.onDocumentReady(Example.init, Example, true); 
</code></pre>

<p>Теперь еще одна поправка: смотрите (кто сделал конечно) вся левая коллонка отезжает на лево, вся правая - на право.</p>
<p>А в правой коллонке начинаются чудеса. Вехний блок никуда не девается а вот нижнии два, каждый по очереди, отезжает вниз и могут быть закрыты, а вот кульминация, если закрыть средний блок то нижний оставшись без родителя (учим ООП) не сможет быть закрыт не имея ссылки на то откуда его надо удалить!</p>

<p>а и вот еще при скрытии/закрытии блока используется комманда </p>
<pre><code class="javascript">
Example.layout.getRegion('center').hidePanel('center1'); 
</code></pre>
<p>где center и center1 координаты (id) радителей блока, также его можно и показать прилепив функцию на ссылку или кнопку</p>
<pre><code class="javascript">
Example.layout.getRegion('center').showPanel('center1'); 
</code></pre>

<p>PS ну вот и все ребята, пример рабочий можете пробовать, писем, пожеланий, комментов и апллодисментов конечноже не надо!!! </p>
<p>PSS спасибо всем кто читал!!!</p>]]></content:encoded>
			<wfw:commentRss>http://mabp.kiev.ua/2006/12/11/yui-extention/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

