<?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>web-dev.info &#187; ExtJS</title>
	<atom:link href="http://web-dev.info/category/extjs/feed/" rel="self" type="application/rss+xml" />
	<link>http://web-dev.info</link>
	<description>Информация о web-разработке для web-разработчиков.</description>
	<lastBuildDate>Tue, 02 Sep 2008 19:55:08 +0000</lastBuildDate>
	
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Использование пространств имен для организации JavaScript-кода</title>
		<link>http://web-dev.info/2008/06/javascript-namespaces/</link>
		<comments>http://web-dev.info/2008/06/javascript-namespaces/#comments</comments>
		<pubDate>Tue, 03 Jun 2008 14:59:37 +0000</pubDate>
		<dc:creator>wd</dc:creator>
				<category><![CDATA[ExtJS]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Перевод]]></category>
		<category><![CDATA[namespace]]></category>

		<guid isPermaLink="false">http://web-dev.info/2008/06/javascript-namespaces/</guid>
		<description><![CDATA[На текущий момент большинство web-приложений состоят из большого числа библиотек, виджетов и сниппетов из многих и многих источников. Следует помнить, что код других разработчиков может взаимодействовать с вашим кодом в случае, если происходит подключение обоих их на одной странице. А если вы оперируете глобальными переменными, то это и вовсе небезопасно.
Почему необходимо использовать пространства имен?
Возьмем, в [...]]]></description>
			<content:encoded><![CDATA[<p>На текущий момент большинство web-приложений состоят из большого числа библиотек, виджетов и сниппетов из многих и многих источников. Следует помнить, что код других разработчиков может взаимодействовать с вашим кодом в случае, если происходит подключение обоих их на одной странице. А если вы оперируете глобальными переменными, то это и вовсе небезопасно.</p>
<h3 class="floatBar">Почему необходимо использовать пространства имен?</h3>
<p>Возьмем, в качестве примера, форум Ext JS, который использует три совершенно различных набора скриптов, созданных разными производителями: Ext JS используется нами для расширения функционала, Google Analytics для отслеживания использования сайта плюс обычные скрипты форума vBulletin. На рисунке представлено каким образом весь этот код из различных источников включается в тело страницы. Вообразите себе количество возможных противоречий с еще большим ростом подключаемых файлов.</p>
<p class="image"><img src="http://web-dev.info/wp-content/uploads/2008/06/diffsources.png" alt="Включаемые файлы" /></p>
<p>Если взглянуть на закладку DOM отладчика Firebug, можно увидеть сотни переменных контекста window, созданных подключенными скриптами. В тоже самое время Ext JS объединяет все свои классы в едином пространстве имен Ext и далее организует их в виде отдельных пакетов.</p>
<p class="image"><img src="http://web-dev.info/wp-content/uploads/2008/06/domwindow.png" alt="Обзор DOM" /></p>
<p>Когда вы пишете собственный срипт, вам следует помещать все свои классы и синглтоны (singletone) в некие пространства имен чтобы предотвратить противоречия с кодом других разработчиков. Термин «пространство имен» определяется в Википедии (<a href="http://en.wikipedia.org/wiki/Namespace">EN</a>, <a href="http://ru.wikipedia.org/wiki/Namespace">RU</a>) следующим образом: «… абстрактный контейнер предоставляющий контекст для содержащихся в нем элементов (имена, термины или слова) и позволяющий предотвратить возникновение неоднозначностей в случае существования элементов с одинаковыми именами…».</p>
<p>Пространства имен это важный инструмент разработчика, гарантирующий невозможность перезаписи одного кода другим. Ведь если иной разработчик определит переменную с таким же, как у вас именем, то существовавшее до этого определение будет перезаписано. Последний подключенный, в таком случае, фрагмент кода будет всегда одерживать верх.</p>
<p>Так как JavaScript является языком с функциональными областями видимости<sup>*</sup>, то создание функции или/и переменной не «обернутых» в функцию приводит к появлению их в глобальной области видимости (в контексте window). Чтобы предотвратить это разработчики помещают свои классы в объекты.</p>
<h6><sup>*</sup> примечание переводчика:</h6>
<p class="notice">вероятно, автор имеет ввиду создание различных областей видимости, что достижимо в этом языке лишь с помощью функций (прим. пер.)</p>
<h3 class="floatBar">Пространства имен без Ext JS</h3>
<p>Без Ext JS вы можете создать пространство имен следующим образом:</p>
<pre name="code" class="js">
if (!App) App = {};
if (!App.form) App.form = {};
if (!App.data) App.data = {};</pre>
<h3 class="floatBar">Ext.namespace</h3>
<p>Объект Ext предоставляет метод <a href="http://extjs.com/deploy/dev/docs/?class=Ext&amp;member=namespace">Ext.namespace</a> (или его шоткат Ext.ns), который проверяет создаваемое пространство имен на существование и создает его, если такового еще нет. Сначала следует определить первоначальный уровень пространства, а затем можно создавать различные подуровни-пакеты. Например, создадим пространство имен <em>App</em> и входящие в него пакеты <em>form</em> и <em>data</em>:</p>
<pre name="code" class="js">
/* Ext.namespace создаст объекты с переданными именами, если они еще не существуют */
Ext.namespace('App', 'App.form', 'App.data');

/* Теперь можно определять новый класс, например SampleForm, внутри пакета App.form */
App.form.SampleForm = Ext.extend(Ext.form.FormPanel, {
    initComponent: function() {
        /* код настройки компонента */
       App.form.SampleForm.superclass.call(this);
   }
});
/* Определение MySingleton внутри пакета App.data */
App.data.MySingleton = function() {
    return {
        sampleStaticMethod: Ext.emptyFn
    };
}();</pre>
<h3 class="floatBar">В завершение</h3>
<p>Используемый в web-приложениях на стороне клиента код JavaScript становится все более сложным и сложным. Поэтому важность правильной организация совместной работы вашего кода и кода третьих сторон также вырастает. Использование пространств имен гарантирует защиту вашему коду от перезаписи другим, находящимся в глобальной области видимости, кодом.</p>
<h3>От переводчика</h3>
<p>Автор оригинала: Aaron Conran</p>
<p>Оригинал статьи: <a href="http://extjs.com/blog/2008/05/28/use-namespaces/">Use Namespaces to organize your JavaScript code</a></p>
]]></content:encoded>
			<wfw:commentRss>http://web-dev.info/2008/06/javascript-namespaces/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>ExtJS: компонент выбора местонахождения</title>
		<link>http://web-dev.info/2008/03/location-select/</link>
		<comments>http://web-dev.info/2008/03/location-select/#comments</comments>
		<pubDate>Fri, 14 Mar 2008 01:43:05 +0000</pubDate>
		<dc:creator>wd</dc:creator>
				<category><![CDATA[ExtJS]]></category>
		<category><![CDATA[ajax]]></category>
		<category><![CDATA[extension]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[location]]></category>
		<category><![CDATA[Zend Framework]]></category>

		<guid isPermaLink="false">http://web-dev.info/2008/03/location-select/</guid>
		<description><![CDATA[Многие проекты на данный момент используют информацию о местонахождении своих клиентов. К таким относятся интернет-магазины, сайты знакомств, банковские операционные ресурсы и прочее. Именно об элементе указания такого рода информации и будет данная статья: Ext.ux.locationSelect реализованный в поле фреймворка ExtJS 2.
Маленькая демка поможет ответить на вопрос о необходимости вчитываться в дальнейшее.
Synopsis
Так сложилось исторически, что управляющим элементом [...]]]></description>
			<content:encoded><![CDATA[<p>Многие проекты на данный момент используют информацию о местонахождении своих клиентов. К таким относятся интернет-магазины, сайты знакомств, банковские операционные ресурсы и прочее. Именно об элементе указания такого рода информации и будет данная статья: <span class="extComponent">Ext.ux.locationSelect</span> реализованный в поле фреймворка ExtJS 2.</p>
<p>Маленькая <a href="/wp-content/themes/special/demos/locationSelect/">демка</a> поможет ответить на вопрос о необходимости вчитываться в дальнейшее.</p>
<h3 class="floatBar">Synopsis</h3>
<p>Так сложилось исторически, что управляющим элементом по выбору локации (будем пользоваться этим словом для определения месторасположения, местонахождения и иного) является некоторое количество взаимосвязанных списков <span class="code">&lt;select&gt;</span>, позволяющих последовательно уточнять локацию часть за частью. Выглядеть это может примерно <cite class="pppImage" width="855" height="474" src="/wp-content/uploads/2008/03/lmr.gif">следующим образом</cite>. Контрол в сумме удобен, малопротиворечив, но несколько устарел. Вот первые, бросающиеся в глаза, минусы решения:</p>
<ul>
<li>popup окно для донесения до посетителя всего контрола;</li>
<li>отсутствие кеширования данных селектов;</li>
<li>слабая расширяемость и гибкость — любой функционал необходимо реализовывать самостоятельно.</li>
</ul>
<h3 class="floatBar">Что необходимо получить</h3>
<p>В одном из проектов мне понадобилось обойти всё вышеперечисленное и ко всему прочему соблюсти следующее:</p>
<ul>
<li>window based дизайн — ресурс интенсивно редактируется и интерфейс решено было сделать оконным;</li>
<li>т. к. страница могла не перезагружаться при работе на ней часами, то вопрос кеширования данных стоит очень остро;</li>
<li>необходимо не только позволять выбирать локации, но и верно отображать их, в такой, например, ситуации как редактирование, когда все селекты уже означены, а соответствующие списки в них уже загружены.</li>
</ul>
<h3 class="floatBar">Инструментарий</h3>
<p>Нам потребуется:</p>
<ul>
<li>Zend Framework;</li>
<li>ExtJS JavaScript Library;</li>
<li>Класс <span class="phpClass">Application_Db_Table_Nestedset</span>, описанный в <a href="/2008/03/zf-nestedset/">предыдущей статье</a>.</li>
</ul>
<p>Использование ExtJS обусловлено требованием №1 — интерфейс window based. Только этот фреймворк способен был справиться со всеми требованиями, которые были предъявлены к процессу работы с данными.</p>
<p><acronym title="Zend Framework">ZF</acronym> и базирующийся на его составляющих <span class="phpClass">Application_Db_Table_Nestedset</span> это ответ на вопрос стандартизации кода, ответ в ряде мест противоречивый, но  все же ответ.</p>
<h6>кстати:</h6>
<p class="notice">данные <acronym title="Zend Framework">ZF</acronym>-элементы дизайна контрола можно исключить и заменить на что-либо более привычное буквально в течении получаса.</p>
<h3 class="floatBar">Контрол в действии</h3>
<p>Использование, благодаря мастерству и прозорливости разработчиков ExtJS, практически ничем не отличается от использования стандартных компонент этого пакета — создать и применить <span class="jsComponent">Ext.ux.locationSelect</span> также легко как и создать обычную панель.</p>
<h3 class="floatBar indent">Подключение</h3>
<p>Подключение реализуется в обычном порядке. Если ExtJS уже используется, то необходимо подключить только само расширение:</p>
<pre name="code" class="html">&lt;head&gt;
    &lt;script type="text/javascript" src="/lib/ext/adapter/ext/ext-base.js"&gt;&lt;/script&gt;
    &lt;script type="text/javascript" src="/lib/ext/ext-all.js"&gt;&lt;/script&gt;
    &lt;script type="text/javascript" src="/lib/ext/ux/locationSelect.js"&gt;&lt;/script&gt;
    &lt;link href="/lib/ext/resources/css/ext-all.css" rel="stylesheet" type="text/css" /&gt;
&lt;/head&gt;</pre>
<h6>для галочки:</h6>
<p class="notice">используйте правильный DOCTYPE документа, часто многие нетривиальности можно решить раз и навсегда только начав работать в правильном режиме.</p>
<h3 class="floatBar indent">Конфигурирование и создание</h3>
<p>Ввиду того, что контрол расширяет <span class="extComponent">Ext.form.FieldSet</span>, то видеть себя он предполагает в поле <span class="extComponent">Ext.FormPanel</span>, однако это необязательное требование.</p>
<h6>важно:</h6>
<p class="notice">подробнейшее описание <acronym title="Application Programming Interface">API</acronym>, конфигураций и немного примеров по каждому из контролов можно обнаружить в <a href="http://extjs.com/deploy/dev/docs/">ExtJS API Documentation</a> в соответствующей части дерева компонент, пакетов и классов.</p>
<p>Таким образом включить контрол в форму можно простым добавлением его конфигурационного объекта в items формы:</p>
<pre name="code" class="js">var myForm = new Ext.form.FormPanel({
    items: [{
        xtype: 'locationselect',
        url: '/someURL',
        prefix: 'some_location_',
        title: 'someFieldSetTitle',
        valueNotFoundText: 'Не важно',
        validator: function(){/*some js-code*/}
        autoHeight: true
    }]
});</pre>
<p>Нестандартными конфигурационными полями являются:</p>
<ul>
<li><span class="code">url</span> — адрес куда хранилища контрола будут обращаться за списками частей локаций (страны, регионы и города), по этому же адресу будет отправляться запрос на полную единовременную загрузку локации целиком. Например, Россия | Рязанская обл. | Рязань;</li>
<li><span class="code">prefix</span> — префикс имен переменных в которых будут сохранены ID частей локации. Для случая выше при сабмите контрол «сгенерирует» и отправит на сервер переменные <span class="jsVar">_some_location_country</span>, <span class="jsVar">_some_location_region</span>, <span class="jsVar">_some_location_city</span>;</li>
<li><span class="code">valueNotFoundText</span> — значение этого поля будет присвоено одноименному конфигурационному полю всех <span class="extComponent">Ext.form.ComboBox</span> контрола;</li>
<li><span class="code">validator</span> — функция будет вызываться при событии выбора любой части локации и позволит обязать, например, к указанию локации полностью.</li>
</ul>
<h6>о незаметном:</h6>
<p class="notice">обратите внимание на символ подчеркивания в именах генерируемых по префиксу переменных. Дело в том, что комбобокс в ExtJS реализации состоит из двух полей ввода — одно из которых и отправляет значение при сабмите формы т.е. приходится генерировать два похожих имени для каждого комбобокса.</p>
<p>Все остальные поля — наследие конфигурации суперкласса.</p>
<h3 class="floatBar indent">Загрузка локации целиком</h3>
<p>Существуют задачи когда необходимо позволить выбирать локацию и при этом начать выбор с той, что уже установлена — редактирование анкетных данных, оформление переезда и прочее.</p>
<p>Для этой цели контрол имеет метод <span class="jsMethod">loadLocation ()</span>, который принимает конфигурационный объект формата <span class="code">{country: integer, region: integer, city: integer}</span>. При его вызове будет произведено обращение по url, указанном при создании, с передачей параметров локации. Если вернувшиеся данные соответствуют допустимому формату, то в соответствующие комбобоксы будут загружены списки с данными, а те части локации, которые были заданы в конфигурационном объекте будут выбраны.</p>
<h3 class="floatBar indent">Серверная часть</h3>
<p>Так как контрол подкачивает данные с помощью <acronym title="Asynchronous JavaScript and XML">AJAX</acronym>, необходимо «договориться» о протоколе общения его с сервером. Здесь имеется развилка:</p>
<ol>
<li>При выборе какой-либо одной части локации посредством комбобокса контрол «расчитывает» на один массив со значениями для следующего комбобокса в json-формате <span class="code">{rows: [{id: numeric, name: string}, ...]}</span>;</li>
<li>При полной загрузке локации контролу необходимы массивы для двух последних комбобоксов единовременно в json-формате <span class="code">{rows: {region: [{id: numeric, name: string}, ...], city: [{id: numeric, name: string}, ...]}}</span>.</li>
</ol>
<p>Мне было удобнее реализовать обе подгрузки в одном действии <span class="phpMethod">locationSelectGetSublocations ()</span> контроллера <span class="phpClass">AjaxController</span>.</p>
<pre name="code" class="php">public function locationSelectGetSublocationsAction() {
        $this->_helper->viewRenderer->setNoRender();
        $filter = new Zend_Filter_Digits();
        $location = new Location();
        if ($this->getRequest()->getParam('country', 0) &#038;& $this->getRequest()->getParam('region', 0)){
            $countryId = $filter->filter($this->getRequest()->getParam('country', 0));
            $regionId = $filter->filter($this->getRequest()->getParam('region', 0));
            $result = array(
                'region' => $location->getSublocations($countryId),
                'city' => $location->getSublocations($regionId)
            );
            //добавляем опции по умолчанию
            array_unshift($result['region'], array('id' => 0, 'name' => 'Не имеет значения'));
            array_unshift($result['city'], array('id' => 0, 'name' => 'Не имеет значения'));
            echo json_encode(array('rows' => $result));
        } else {
            $id = $filter->filter($this->getRequest()->getParam('parentId', 1));
            $result = $location->getSublocations($id);
            //добавляем опцию по умолчанию
            array_unshift($result, array('id' => 0, 'name' => 'Не имеет значения'));
            echo json_encode(array('rows' => $result));
        }
    }
</pre>
<h6>на заметку:</h6>
<p class="notice">вы можете не использовать <acronym title="Zend Framework">ZF</acronym>, хранить данные локаций в любом удобном для вас виде и делать, что заблагорассудится, главное — возвращать данные как это указано выше.</p>
<p>Белым пятном действия является класс <span class="phpClass">Location</span> — модель таблицы <span class="dbTable">location</span>. Это ничто иное как наследник класса <span class="phpClass">Application_Db_Table_Nestedset</span> о котором велась речь в предыдущей <a href="/2008/03/zf-nestedset/">статье</a>. Код модели имеет вид:</p>
<pre name="code" class="php">class Location extends Application_Db_Table_Nestedset{

    protected $_name = 'location';
    protected $_primary = 'id';
    /**
     *  Return child locations of location
     *
     * @param integer parent location id
     * @return array location items
     */
    public function getSublocations($id){
        $result = array();
        foreach ($this->getChildren($id) as $row)
            $result[] = array('id' => $row['id'], 'name' => $row['name']);
        return $result;
    }
}</pre>
<h3 class="floatBar">Таблица данных локаций</h3>
<p>Таблицу локаций было решено вынести в отдельный пункт из-за самой её сути. В свое время пришлось попотеть, чтобы найти в Сети довольно полные данные по странам, регионам и городам. Теперь, когда эта задача решена можно <a class="tar" href="/websvn/dl.php?&#038;path=%2FlocationSelect%2Ftrunk%2Fdb%2F&#038;rev=0&#038;isdir=1">скачать</a> порядка 20к объектов одним кликом.</p>
<p>Локации упорядочены и собраны в одной таблице по схеме <cite class="footNote" post="zf-nestedset" place="1">Вложенных Множеств</cite>. Лично мне кажется, что эта схема является очень удачной для такого рода задач:</p>
<ul>
<li>данные очень редко изменяются, но часто выбираются;</li>
<li>нет многих таблиц данных и таблиц связей между ними.</li>
</ul>
<h3 class="floatBar">Ресурсы</h3>
<ul>
<li><a class="tar" href="/websvn/listing.php?path=%2FlocationSelect%2Ftrunk%2Fux%2F#_locationSelect_trunk_ux_">Ext.ux.locationSelect.js (trunk/ux)</a
<li><a class="svn" href="http://svn.web-dev.info/repos/locationSelect/trunk/ux/locationSelect.js">Ext.ux.locationSelect.js (trunk) UTF-8</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://web-dev.info/2008/03/location-select/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
	</channel>
</rss>
