<?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>jQuery и другое...</title>
	<atom:link href="http://www.linkexchanger.su/feed" rel="self" type="application/rss+xml" />
	<link>http://www.linkexchanger.su</link>
	<description>css, html, php, javascript, jQuery, ajax ... - решения, примеры, рецепты</description>
	<lastBuildDate>Sun, 29 Aug 2010 10:51:12 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>jqGrid Часть III: Расширенные возможности</title>
		<link>http://www.linkexchanger.su/2010/523.html</link>
		<comments>http://www.linkexchanger.su/2010/523.html#comments</comments>
		<pubDate>Sun, 23 May 2010 15:26:04 +0000</pubDate>
		<dc:creator>TRAHOMOTO</dc:creator>
				<category><![CDATA[jQuery]]></category>
		<category><![CDATA[jQuery UI]]></category>

		<guid isPermaLink="false">http://www.linkexchanger.su/?p=523</guid>
		<description><![CDATA[Введение
Я рад приветствовать вас, дорогие читатели в третьей статье цикла, посвященного плагину jqGrid. Прошу прощения за столь долгое отсутствие, сейчас все свободное время отдаю изучению и освоению другого монстра &#8211; ExtJS.
Напомню, что в предыдущей статье (jqGrid Часть II: Базовые возможности) мы перешли от basic к advanced уровню использования этого замечательного плагина. Но прежде чем мы [...]]]></description>
			<content:encoded><![CDATA[<p><strong>Введение</strong><br />
Я рад приветствовать вас, дорогие читатели в третьей статье цикла, посвященного плагину jqGrid. Прошу прощения за столь долгое отсутствие, сейчас все свободное время отдаю изучению и освоению другого монстра &#8211; ExtJS.<br />
Напомню, что в предыдущей статье (<a href="http://www.linkexchanger.su/2010/486.html">jqGrid Часть II: Базовые возможности</a>) мы перешли от basic к advanced уровню использования этого замечательного плагина. Но прежде чем мы начнем я хотел бы сообщить, что jqGrid обновилась до версии 3.6.5 и соответственно и мы будем использовать новую версию.</p>
<p>Итак план работ на эту статью:</p>
<ul>
<li><strong><a href="http://www.linkexchanger.su/2010/523.html#p1">jqGrid и &laquo;деревья&raquo;</a></strong>
<ul>
<li><a href="http://www.linkexchanger.su/2010/523.html#p1.1">Общие сведения о деревьях</a></li>
<li><a href="http://www.linkexchanger.su/2010/523.html#p1.2">jqGrid и SQL деревья</a></li>
<li><a href="http://www.linkexchanger.su/2010/523.html#p1.3">jqGrid и статические деревья</a></li>
</ul>
</li>
<li><strong><a href="http://www.linkexchanger.su/2010/523.html#p2">Связывание данных в jqGrid</a></strong>
<ul>
<li><a href="http://www.linkexchanger.su/2010/523.html#p2.1">Простая подтаблица (subgrid)</a></li>
<li><a href="http://www.linkexchanger.su/2010/523.html#p2.2">jqGrid как subgrid</a></li>
<li><a href="http://www.linkexchanger.su/2010/523.html#p2.3">Ведущая и ведомая jqGrid</a></li>
</ul>
</li>
</ul>
<p><span id="more-523"></span><br />
<a title="p1" name="p1"></a><strong>I.jqGrid и &laquo;деревья&raquo;</strong></p>
<p><a title="p1.1" name="p1.1"></a><strong>1) Краткие сведения о деревьях</strong><br />
Конечно здесь речь пойдет не о садово-огородных работах, а об представлении древовидных структур данных. В очередной раз обратимся за определением к Википедии:</p>
<p><strong>Древовидная структура</strong> является одним из способов представления иерархической структуры в графическом виде. <strong>Древовидной структурой</strong> называется благодаря тому, что граф выглядит как перевернутое дерево. По этой же причине говорят, что корневой узел (корень) находится на самом верху, а листья — внизу.</p>
<p>В принципе более или менее сносное определение, несмотря на то, что оно навивает академическую скуку я все же настоятельно рекомендую ознакомиться с материалом по древовидным структурам. Поверьте моему не большому опыту, абсолютно каждый программист рано или поздно станет перед необходимостью использовать дерево, и тут одним из помошников может стать jqGrid. Плагин может работать с двумя самыми распространенными в вычислительной технике типами деревьев: на основе &laquo;вложенных множеств&raquo; (Nested Sets) и &laquo;матрицы смежностей&raquo; (adjacency matrix). Вообще говоря тема деревьев очень серьезна, это один из разделов теории графов на изучение которых отводится не одна лекция в ВУЗах, но от себя посоветую те материалы которые мне в свое время очень помогли. Столкнувшись впервые с проблемой хранения деревьев я наткнулся на материал по подходу вложенных множеств (<a href="http://phpclub.ru/detail/article/db_tree">Хранение древовидных структур в Базах данных</a>) и сразу же остановился на нем, наверное потому что для работы с таким деревом существует готовый PHP класс. Но в процессе написания статьи я все же прочел статью <a href="http://phpclub.ru/detail/article/2002-06-03">Работа с &laquo;MySQL. Деревья&raquo;</a> в которой рассматривается подход матрицы смежностей.</p>
<p>Думаю здесь общие сведения следует закончить и перейти к практическому рассмотрению. </p>
<p><a title="p1.2" name="p1.2"></a><strong>2) jqGrid и SQL деревья</strong><br />
Для того, чтобы jqGrid могла работать с древовидными структурами, она должна быть загружена с модулем <strong>Tree Grid</strong>. Плагин может работать с обоими типами деревьев, упомянутых в предыдущем пункте. При этом jqGrid может работать с деревьями подгрузив все дерево за один раз или же подгружая ветви и листья по мере необходимости. Собственно загрузку дерева за один раз я рассматривать не буду, не интересно, а вот автоподгрузку мы разберем детально. И на этой ноте давайте перейдем к просмотру <a href="http://trahomoto.dlinkddns.com/works/linkexchanger/articles/jqgrid/p3e1.html">ДЕМО3.1</a>, <a href="http://trahomoto.dlinkddns.com/works/linkexchanger/articles/jqgrid/files/demo3.1.zip">ссылка для скачивания</a> </p>
<pre class="brush: jscript;">
$(function(){
     $('#table_nested').jqGrid({
                     treeGrid: true,
                     treeGridModel: 'nested',
                     ExpandColumn: 'title',
                     ExpandColClick: true,
                     url: 'p3e1_n.php',
                     datatype: &quot;json&quot;,
                     mtype: &quot;POST&quot;,
                     colNames:[&quot;id&quot;,&quot;Раздел&quot;],
                     colModel:[
                                   {name:'cid',index:'cid', width:1, hidden:true, key:true},
                                   {name:'title',index:'title', width:180}
                                  ],
                     treeIcons: {plus:'ui-icon-folder-collapsed',minus:'ui-icon-folder-open',leaf:'ui-icon-document'},
                     height: 'auto',
                     caption: 'вложенныe множества',
                     hidegrid: false
     });

     $('#table_adjacency').jqGrid({
                     treeGrid: true,
                     treeGridModel: 'adjacency',
                     ExpandColumn: 'title',
                     ExpandColClick: true,
                     url: 'p3e1_a.php',
                     datatype: &quot;json&quot;,
                     mtype: &quot;POST&quot;,
                     colNames:[&quot;cid&quot;,&quot;Раздел&quot;],
                     colModel:[
                                   {name:'cid',index:'cid', width:1, hidden:true, key:true},
                                   {name:'title',index:'title', width:180}
                                   ],
                     treeIcons: {plus:'ui-icon-circle-plus',minus:'ui-icon-circle-minus',leaf:'ui-icon-person'},
                     height: 'auto',
                     caption:'матрица смежностей',
                     hidegrid: false
    });
});
</pre>
<p>Настройки обоих таблиц идентичны, но имеется ряд свойств, отличающих эти экземпляры от рассмотренных в предыдущих статьях.</p>
<ul>
<li><strong>treeGrid: true</strong> &#8211; самый главный параметр, указывает что jqGrig будет работать с древовидной структурой, а не с простыми табличными данными</li>
<li><strong>treeGridModel: &#8216;adjacency&#8217; / &#8216;nested&#8217;</strong> &#8211; это свойство определяет какой алгоритм дерева использовать</li>
<li><strong>ExpandColumn: &#8216;title&#8217;</strong> &#8211; определяет при клике по какому столбцу происходит открытие и(или) загрузка ветви</li>
<li><strong>ExpandColClick: true</strong> &#8211; необходимо, чтобы открытие ветви происходило при клике на колонку, а не на иконку</li>
<li><strong>colModel:[... key:true},...]</strong> &#8211; свойство <strong>key</strong> в массиве colModel позволяет указать данные какого столбца следует использовать как уникальный идентификатор записи при запросе данных с сервера. Т.е. благодаря этому свойству, можно переопределить идентификатор. Но только в одном столбце может быть указан <strong>key</strong>. Плагин будет использовать первый, найденный столбец как ключевой.</li>
<li><strong>treeIcons:</strong> &#8211; позволяет переопределить стандартные (<em>{plus:&#8217;ui-icon-triangle-1-e&#8217;,minus:&#8217;ui-icon-triangle-1-s&#8217;,leaf:&#8217;ui-icon-radio-off&#8217;}</em>) иконки листьев и ветвей.</li>
</ul>
<p>С не описанными свойства мы знакомы из предыдущих статей, а другие свойства и методы, характерные только для работы с jqGrid в качестве дерева можно посмотреть на странице <a href="http://www.trirand.com/jqgridwiki/doku.php?id=wiki:treegrid">TreeGrid</a>. </p>
<p>Прежде чем перейдем к рассмотрению серверных скриптов давайте немного разберемся как работает плагин. Сразу после инициализации, таблица отправляет запрос к серверу, при этом передает следующие данные и ждет ответа сервера:</p>
<blockquote><p><strong>В режиме &#8216;nested&#8217; (на примере метода POST)</strong></p>
<ul>
<li><strong>POST['nodeid']</strong> &#8211; идентификатор узла (ветви)</li>
<li><strong>POST['n_left']</strong> &#8211; позиция узла &laquo;слева&raquo;</li>
<li><strong>POST['n_right']</strong> &#8211; позиция узла &laquo;справа&raquo;</li>
<li><strong>POST['n_level']</strong> &#8211; уровень вложенности узла</li>
</ul>
</blockquote>
<p></p>
<blockquote><p><strong>В режиме &#8216;adjacency&#8217; (на примере метода POST)</strong></p>
<ul>
<li><strong>POST['nodeid']</strong> &#8211; идентификатор узла (ветви)</li>
<li><strong>POST['parentid']</strong> &#8211; идентификатор родительского узла</li>
<li><strong>POST['n_level']</strong> &#8211; уровень вложенности узла</li>
</ul>
</blockquote>
<p></p>
<blockquote><p><strong>кроме этого, на сервер также передаются стандартные для jqGrid параметры (на примере метода POST)</strong></p>
<li><strong>POST['page']</strong> &#8211; номер страницы, для &laquo;листалки&raquo;</li>
<li><strong>POST['rows']</strong> &#8211; количество записей, для ограничения при выборке данных</li>
<li><strong>POST['sidx']</strong> &#8211; значение <strong>index:</strong> в<strong> colModel</strong>, имя столбца по которому необходимо отсортировать результат</li>
<li><strong>POST['sord']</strong> &#8211; направление сортировки</li>
</blockquote>
<p>
После получения данных, серверный скрипт выполняет запрос данных из БД и сроит и  выводит результат в следующих форматах. </p>
<blockquote><p><strong>В режиме &#8216;nested&#8217; (на примере XML ответа)</strong></p>
<ul>
<li><strong>пользовательские столбцы</strong></li>
<li><strong>level</strong> &#8211; уровень узла в иерархии</li>
<li><strong>lft</strong> &#8211; позиция узла &laquo;слева&raquo;</li>
<li><strong>rgt</strong> &#8211; позиция узла &laquo;справа&raquo;</li>
<li><strong>isLeaf</strong> &#8211; логический признак (true/false), определяет этот узел является &laquo;веткой&raquo;(есть подузлы) или &laquo;листом&raquo;(нет подузлов)</li>
<li><strong>expanded</strong> &#8211; логический признак (true/false), нужно ли показывать подузлы если этот узел является веткой, т.е. загрузить &laquo;открытым&raquo; или &laquo;закрытым&raquo;</li>
</ul>
</blockquote>
<p></p>
<blockquote><p><strong>В режиме &#8216;adjacency&#8217; (на примере XML ответа)</strong></p>
<ul>
<li><strong>пользовательские столбцы</strong></li>
<li><strong>level</strong> &#8211; уровень узла в иерархии</li>
<li><strong>parent</strong> &#8211; идентификатор родительского узла</li>
<li><strong>isLeaf</strong> &#8211; логический признак (true/false), определяет этот узел является &laquo;веткой&raquo;(есть подузлы) или &laquo;листом&raquo;(нет подузлов)</li>
<li><strong>expanded</strong> &#8211; логический признак (true/false), нужно ли показывать подузлы если этот узел является веткой, т.е. загрузить &laquo;открытым&raquo; или &laquo;закрытым&raquo;</li>
</ul>
</blockquote>
<p>
Ядро (<a href="http://www.trirand.com/jqgridwiki/doku.php?id=wiki:retrieving_data">ридеры</a>) jqGrid разбирают ответ и вставляют данные в таблицу. Вот теперь серверные скрипты будут более-менее понятны. </p>
<p><strong>Вложенные множества (<em>p3e1_n.php</em>)</strong>(опущены подключение к БД и вывод результата)</p>
<pre class="brush: php;">
// Получаем параметры от таблицы
    # ВНИМАНИЕ!!!
    # Данный код не имеет проверок запрашиваемых данных
    # что может стать причиной взлома! Обязательно проверяйте все данные
    # поступающие от клиента

    $node  = intval($_POST['nodeid']);
    $left  = intval($_POST['n_left']);
    $right = intval($_POST['n_right']);
    $level = intval($_POST['n_level']);

// Настраиваем условие для выбора ветки
    $WHERE = '';
    if($node &gt; 0) {
       $level = $level + 1;  // нужно выбрать следующий уровень
       $WHERE = &quot; AND cleft &gt; &quot;.$left.&quot; AND cright &lt; &quot;.$right.&quot; AND clevel = &quot;.$level;
    }else{
       $level = 0;
    }

// Выбираем подразделы
    $query = &quot;SELECT cid, title, clevel, cleft, cright FROM tree_nested_sets WHERE cleft BETWEEN cleft AND cright &quot;.$WHERE.&quot; GROUP BY title ORDER BY cleft;&quot;;
    $result = mysql_query($query);

// Формируем результат
    $response-&gt;page = 1;
    $response-&gt;total = 1;
    $response-&gt;records = 1;

    $i = 0;
    while($row = mysql_fetch_assoc($result)) {
        //-------------------------------------
        // Определяем является ли выбранный узел &quot;листом&quot;
        if($row['cright'] == $row['cleft']+1)
            $leaf = 'true';
        else
            $leaf='false';
        //-------------------------------------

        if($level == $row['clevel']){
            $response-&gt;rows[$i]['cell'] = array($row['cid'], $row['title'], $row['clevel'], $row['cleft'], $row['cright'], $leaf, 'false');
        }
        $i++;
    }
</pre>
<p><strong>Матрица смежностей(<em>p3e1_a.php</em>)</strong>(опущены подключение к БД и вывод результата)</p>
<pre class="brush: php;">
// Выбираем все разделы без подразделов (листья)
    $query_feafs = &quot;SELECT t1.cid FROM tree_adjacency_matrix AS t1 LEFT JOIN tree_adjacency_matrix AS t2 ON t1.cid = t2.id_parent WHERE t2.cid IS NULL&quot;;
    $sql_leafs = mysql_query($query_feafs);

    while($row = mysql_fetch_assoc($sql_leafs)) {
       $leafs[] = $row['cid']; // Массив для хранения &quot;листьев&quot;
    }
    unset($row);

// Получаем параметры от таблицы
    # ВНИМАНИЕ!!!
    # Данный код не имеет проверок запрашиваемых данных
    # что может стать причиной взлома! Обязательно проверяйте все данные
    # поступающие от клиента

    $level  = intval($_POST['n_level']);
    $node   = intval($_POST['nodeid']);

// Настраиваем условие для выбора ветки
    if($node &gt; 0) {
       $level = $level + 1;            // нужно выбрать следующий уровень
       $WHERE = 'id_parent ='.$node;
    } else {
       $WHERE = 'id_parent IS NULL';   // выбрать корень(ни)
    } 

// Выбираем подразделы
    $query  = &quot;SELECT cid, title, id_parent FROM tree_adjacency_matrix WHERE &quot;.$WHERE;
    $result = mysql_query($query);

// Формируем результат
    $response-&gt;page      = 1;
    $response-&gt;total     = 1;
    $response-&gt;records   = 1;

    $i = 0;
    while($row = mysql_fetch_assoc($result)) {
       //-------------------------------------
       // Определяем ID родителя этого узла
       if(!$row['id_parent'])
           $parent = 'NULL';
       else
          $parent = $row['id_parent'];
       //-------------------------------------
       // Определяем является ли выбранный узел &quot;листом&quot;
       if(in_array($row['cid'], $leafs))
           $is_leaf = 'true';
       else
           $is_leaf = 'false';
       //--------------------------------------

       $response-&gt;rows[$i]['cell'] = array($row['cid'], $row['title'], $level, $parent, $is_leaf, FALSE);

       $i++;
    }</pre>
<p>Я считаю комментировать в этих листингах особо нечего, кроме того что данные поступающие с сервера не ограничиваются по кол-ву записей и не сортируются. А практически все остальное является повторением примеров из предыдущих статей или специфическими вещами при работе с деревьями, описанными в статьях приложенных выше. Также обращу ваше внимание на то, что пример работы с <a href="http://www.trirand.com/jqgridwiki/doku.php?id=wiki:nested_set_model">Nested Set Model</a> описанный в документации разработчиком не хотел работать, пришлось его доводить, за что мне большое спасибо <img src='http://www.linkexchanger.su/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> .</p>
<p><a title="p1.3" name="p1.3"></a><strong>3)jqGrid и статические деревья</strong><br />
Название <em>статические деревья</em> оносительно, того что мы делали немного ранее. Безусловно данные &laquo;загруженные&raquo; таким способом могут быть построены и скриптом динамически, но все же бывают такие задачи, когда дерево уже есть необходимо лишь вывести его в дружественной для пользователя форме как в <a href="http://trahomoto.dlinkddns.com/works/linkexchanger/articles/jqgrid/p3e2.html">ДЕМО3.2</a> . Не правда ли что-то напоминает? Да! это меню из демо jqGrid от разработчика. </p>
<p>Листинг клиентской части:</p>
<pre class="brush: jscript;">
  $('#table').jqGrid({
            url: &quot;tree.xml&quot;,
            datatype: &quot;xml&quot;,
            height: &quot;auto&quot;,
            pager: false,
            loadui: &quot;disable&quot;,
            colNames: [&quot;id&quot;,&quot;Items&quot;,&quot;url&quot;],
            colModel: [
                {name: &quot;id&quot;,width:1,hidden:true, key:true},
                {name: &quot;menu&quot;, width:150, resizable: false, sortable:false},
                {name: &quot;url&quot;,width:1,hidden:true}
            ],
            treeGrid: true,
                    caption: &quot;jqGrid Demos&quot;,
            ExpandColumn: &quot;menu&quot;,
            width: 200,
            rowNum: 200,
            ExpandColClick: true,
            treeIcons: {leaf:'ui-icon-document-b'}
 });
</pre>
<p>Полностью идентичные параметры плагина, за исключением того, что я отключил обработчик события <strong>onSelectRow</strong>.<br />
Из листига должно стать понятно, что таблица запрашивает статичный(оносительно) файл <em>tree.xml</em>, который выглядит так</p>
<pre class="brush: xml;">&lt;?xml version='1.0' encoding=&quot;utf-8&quot;?&gt;
&lt;rows&gt;
    &lt;page&gt;1&lt;/page&gt;
    &lt;total&gt;1&lt;/total&gt;
    &lt;records&gt;1&lt;/records&gt;
    &lt;row&gt;&lt;cell&gt;1&lt;/cell&gt;&lt;cell&gt;Loading Data&lt;/cell&gt;&lt;cell&gt;&lt;/cell&gt;&lt;cell&gt;0&lt;/cell&gt;&lt;cell&gt;1&lt;/cell&gt;&lt;cell&gt;10&lt;/cell&gt;&lt;cell&gt;false&lt;/cell&gt;&lt;cell&gt;false&lt;/cell&gt;&lt;/row&gt;
    &lt;row&gt;&lt;cell&gt;2&lt;/cell&gt;&lt;cell&gt;XML Data&lt;/cell&gt;&lt;cell&gt;xmlex.html&lt;/cell&gt;&lt;cell&gt;1&lt;/cell&gt;&lt;cell&gt;2&lt;/cell&gt;&lt;cell&gt;3&lt;/cell&gt;&lt;cell&gt;true&lt;/cell&gt;&lt;cell&gt;true&lt;/cell&gt;&lt;/row&gt;
    &lt;row&gt;&lt;cell&gt;3&lt;/cell&gt;&lt;cell&gt;JSON Data&lt;/cell&gt;&lt;cell&gt;jsonex.html&lt;/cell&gt;&lt;cell&gt;1&lt;/cell&gt;&lt;cell&gt;4&lt;/cell&gt;&lt;cell&gt;5&lt;/cell&gt;&lt;cell&gt;true&lt;/cell&gt;&lt;cell&gt;true&lt;/cell&gt;&lt;/row&gt;

...

&lt;/rows&gt;
</pre>
<p>Т.е. jqGrid просто разбирает данные из этого файла и строит TreeGrid.</p>
<p><a title="p2" name="p2"></a><strong>II. Связывание данных в jqGrid</strong></p>
<p>Иногда при построении какого либо приложения необходимо как то сгруппировать данные для экономии визуального пространства на странице и при этом иметь возможность как можно быстрее и комфортнее получить доступ к более детальной информации или связанной с текущей. Немного сумбурно получилось <img src='http://www.linkexchanger.su/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> , но надеюсь вы меня поняли, а если не поняли то примеры разложат все по полочкам.</p>
<p><a title="p2.1" name="p2.1"></a><strong>1)Простая подтаблица (subgrid)</strong></p>
<p>Это весьма полезная опция у этого плагина. На <a href="http://trahomoto.dlinkddns.com/works/linkexchanger/articles/jqgrid/p3e3.html">ДЕМО3.3</a> обратите внимание на крестик в крайнем правом столбце таблицы. При клике на нем под выбранной строкой распахивается &laquo;карман&raquo; в котором находится небольшая табличка с названиями городов и прочей &laquo;рыбой&raquo;.  Вот пример группировки. Теперь давайте перейдем к листингам.</p>
<pre class="brush: jscript;">
$('#table').jqGrid({
       url:'p3e3.php',
       datatype: 'json',
       mtype: 'POST',
       colNames:['Код страны','Cтрана',''],
       colModel :[
          {name:'country_code', index:'country_code', width:80, hidden: true},
          {name:'country_name', index:'country_name', width:60},
          {name:'description', width:200, sortable: false}
          ],
       pager: $('#tablePager'),
       rowNum: 100,
       scroll: true,
       viewrecords: true,
       sortname: 'country_name',
       sortorder: 'asc',
       width: 700,
       height: 400,
       subGrid: true,
         subGridUrl: 'p3e3.php?get=subgrid',
         subGridModel:[{
                     name :  ['&amp;nbsp;','Город', 'Широта', 'Долгота'],
                     width:  [40, 200, 150, 150],
                     align:  ['center','left','right','right'],
                     params: ['country_code','country_name']
                 }]
});
</pre>
<p>Как видите, абсолютно обыкновенный jqGrid, но в &laquo;настройках&raquo; есть несколько интересных моментов:</p>
<ul>
<li><strong>subGrid:</strong> &#8211; в строке 19. Эта опция позволяет использовать подтаблицу.</li>
<li><strong>subGridUrl:</strong> &#8211; указывает путь к скрипту, который должен вернуть данные для построения подтаблицы. В данном случае происходит запрос к тому же скрипту, который &laquo;обслуживает&raquo; и таблицу-родителя при этом передав ему параметр <em>get</em> со значением <em>subgrid</em></li>
<li><strong>subGridModel:</strong> &#8211; свойство которое задает параметры подтаблицы. Аналогично <strong>colModel</strong> таблицы-родителя</li>
</ul>
<p><strong>subGridModel:</strong> &#8211; представляет из себя массив с объектом, у которого есть свои параметры. <strong>name</strong>, <strong>width</strong> и <strong>align</strong> уверен их имена говорят сами за себя, это тексты заголовков столбцов, ширины соответствующих столбцов и выравнивание в них соответственно. Более интересным будет свойство <strong>params</strong>. Оно позволяет передать значения из каких то ячеек родительской таблицы на сервер при запросе подтаблицы. Иными словами, когда вы нажмете на крестик , открывающий подтаблицу, происходит запрос к серверу которому передается  клоч (id) записи (в нашем случае это <em>country_code</em>) и плос к этим данным можно передать дополнительные (в нашем случае серверу будет передан еще и <strong>country_name</strong>). А вот на сервере получив значения нужных параметров (в этом примере серверный скрипт просто игнорирует значение параметра <strong>country_name</strong>) вы выполняем запрос к БД и выводим JSON объект с данными.</p>
<pre class="brush: php;">
...
$get = $_REQUEST['get'];  // Параметр указывающий на то
                                    //  что мы запросили информацию для подтаблицы
...
switch ($get){
    case 'subgrid':
        // Выбрать города запрошенной страны
        $id =$_REQUEST['id'];

        // Запрос данных
        $query = &quot;SELECT id, country_code, region_code, city, latitude, longitude, nbip FROM cities  WHERE country_code LIKE '&quot;.$id.&quot;'&quot;;

        $result = mysql_query($query);
        if(mysql_num_rows($result) &gt;= 1){
            // Строки данных для таблицы
            $i = 0;
            while($row = mysql_fetch_assoc($result)) {
                $data-&gt;rows[$i]['cell'] = array($i+1,'&lt;strong&gt;&lt;em&gt;'.$row['city'].'&lt;/em&gt;&lt;/strong&gt;',$row['latitude'],$row['longitude']);
                $i++;
            }
        }
        break;

    default:
        // Выбрать названия стран и сосчетать города
        ...

}
// Вывести результат
...
</pre>
<p>Серверный скрипт особо ничем не отличается от рассмотренных в предыдущих примерах. При этом он разбит на две части оператором <strong>switch</strong>. Который по умолчанию выполняет &laquo;стандартную&raquo; обработку и вывод данных для главной таблицы. А вот если этот скрипт запустить передав ему  параметр <em>get</em> (я выбрал такое имя только ради наглядности) тогда будет выполнена выборка данных для подтаблицы. Ну и если у вас чешутся руки поковырять пример, вы можете <a href="http://trahomoto.dlinkddns.com/works/linkexchanger/articles/jqgrid/files/demo3.3.zip">скачать его</a>.</p>
<p>Подтаблицы это замечательный инструмент, который позволяет очень элегантно организавать данные, но при этом имеет один существенный недостаток &#8211; подтаблица &laquo;не живая&raquo;. Т.е. данные в подтаблице не могут сортироваться, нет возморжности реализовать поиск и т.д. А это очень критично если в подтаблице будет выводиться много записей. Однако это ограничение отпадает само собой при использовании jqGrid как подтаблицы.</p>
<p><a title="p2.2" name="p2.2"></a><strong>2)jqGrid как subgrid</strong><br />
Итак начнем с промотра <a href="http://trahomoto.dlinkddns.com/works/linkexchanger/articles/jqgrid/p3e4.html">ДЕМО3.4</a>. Как видите все тот же &laquo;родной&raquo; jqGrid с названиями стран, и кол-вом городов в этой стране, но при этом подтаблица теперь представляет из себя самую настоящую jqGrid со всеми свойствами и методами. Согласитесь, что так работать намного приятнее и удобнее. </p>
<p>А вот здесь самое интересное &#8211; клиентский код (в листинге опущены все настройки родительской таблицы, кроме одного свойства):</p>
<pre class="brush: jscript;">
...
subGrid: true,
subGridRowExpanded: function(subgrid_id, row_id) {
    var subgrid_table_id;
    subgrid_table_id = subgrid_id+'_t';

    $('#'+subgrid_id).html('&lt;table id=&quot;'+subgrid_table_id+'&quot;&gt;&lt;/table&gt;&lt;div id=&quot;'+subgrid_table_id+'_pager&quot;&gt;&lt;/div&gt;');
    $('#'+subgrid_table_id).jqGrid({
        url: 'p3e4.php',
        datatype: 'json',
        mtype: 'POST',
        postData: {'get':'subgrid', 'id':row_id},
        colNames: ['Город', 'Широта', 'Долгота'],
        colModel: [
            {name: 'city', index: 'city', width:130},
            {name: 'latitude', index: 'latitude', width:80, align: 'right'},
            {name: 'longitude', index: 'longitude', width:80, align: 'right'}
            ],
        height: 'auto',
        autowidth: true,
        rownumbers: true,
        rownumWidth: 40,
        rowNum: 10,
        sortname: 'city',
        sortorder: 'asc',
        pager: $('#'+subgrid_table_id+'_pager'),
        rowNum:10,
        rowList:[10,20,50,100]
    });
}
...
</pre>
<p>Настройки таблицы-родителя идентичные предыдущему примеру, но при этом появилось новое свойство <strong>subGridRowExpanded</strong>. Думаю самые догадливые поняли, а самые любопытные прочли в документации в секции <a href="http://www.trirand.com/jqgridwiki/doku.php?id=wiki:subgrid">Subgrid</a>, что <strong>subGridRowExpanded</strong> не просто свойство, а событие. </p>
<blockquote><p>
<strong>subGridRowExpanded</strong> &#8211; это событие возникает когда пользователь кликает на крестик раскрытия подтаблицы и выполняет определенную функцию при распахивании &laquo;кармана&raquo; для подтаблицы. При этом в функцию обработчик будут переданы 2 параметра:</p>
<ul>
<li><strong>pID</strong> &#8211; уникальный идентификатор &laquo;кармана&raquo; (контейнера, если хотите) который открывается под выбранной строкой</li>
<li><strong>id</strong> &#8211; идентификатор записи под которой открылся &laquo;карман&raquo;</li>
</ul>
</blockquote>
<p>Безусловно существуют еще события, о которых вы можете узнать из документации. А мы пока пробежимся по листингу. Итак когда пользователь &laquo;тыцнул&raquo; на крестик, открывается контейнер и выполняется функция. Которая получает 2 параметра <em>subgrid_id</em> и <em>row_id</em>. Далее в строке 5 создаем строковое значение для атрибута id и в 6й строке используем метод jQuery, который вставляет в &laquo;карман&raquo; (кстати сказать что это обыкновенный DIV) html разметку таблицы и DIV&#8217;a. А далее идет бональная инициализация jqGrid для только что созданной разметки. Т.е. фактически мы просто напросто динамически создали разметку и создали jqGrid! В этот момент я воскликнул &laquo;Тааак!&raquo; и потер руки. Почему? Да потому, что зная id объекта (&lt;div id=&quot;someid&quot;&gt;&#8230;&lt;/div&gt;) с помощью jQuery можно сотворить с ним все что угодно. Но прежде чем мы перейдем к следующему примеру я приведу <a href="http://trahomoto.dlinkddns.com/works/linkexchanger/articles/jqgrid/files/demo3.4.zip">ссылку на раздаточный материал</a> по теме &#8211; это пример который только что расмотрели.<br />
А теперь зная id контейнера давайте, еще добавим наглядности нашему примеру со странами и городами, например как на <a href="http://trahomoto.dlinkddns.com/works/linkexchanger/articles/jqgrid/p3e5.html">ДЕМО3.5</a>. Как видите все эта же, скучная таблица со странами, но теперь при клике на крестик открывается подробная информация и флаг выбранной строки. Под которой свернутая jqGrid таблица с перечнем городов. Этот пример вы можете скачать перейдя по <a href="http://trahomoto.dlinkddns.com/works/linkexchanger/articles/jqgrid/files/demo3.5.zip">этой ссылке</a>. Внутри архива все скрипты, но наибольший интерес представляет клиентский код. Я условно разделю его на 2 части, первая (нижняя) часть:</p>
<pre class="brush: jscript;">
$('#table').jqGrid({
          ...
          subGrid: true,
          subGridRowExpanded: function(subgrid_id, row_id) {
                       getCountryDetails(subgrid_id, row_id);
                   }

});
</pre>
<p>Это таблица из предыдущего примера, но теперь при возникновении события <strong>subGridRowExpanded</strong> будет выполнена пользовательская функция <strong>getCountryDetails()</strong>, которая и является 2 половиной клиентского скрипта:</p>
<pre class="brush: jscript;">
function getCountryDetails(container, countryCode){
    $.ajax({
            type: 'post',
            url: 'p3e5.php',
            data: ({'id': countryCode, 'get': 'details'}),
            dataType: 'json',
            success: function(server){
                $('#'+container).html('&lt;div class=&quot;c_detail&quot;&gt;&lt;img src=&quot;files/images/'+server.flag+'&quot;&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Столица:&lt;/strong&gt; '+server.capital+'&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Дата независимости:&lt;/strong&gt; '+server.independence_date+'&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Официальные языки:&lt;/strong&gt; '+server.off_lng+'&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Форма правления:&lt;/strong&gt; '+server.government+'&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Глава правительства:&lt;/strong&gt; '+server.president+'&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Валюта:&lt;/strong&gt; '+server.currency+'&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Интернет-домены:&lt;/strong&gt; '+server.domains+'&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Телефонный код:&lt;/strong&gt; '+server.dialing_code+'&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Часовой пояс:&lt;/strong&gt; '+server.time_zone+'&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;');

                var subgrid_table_id = container+'_t';

                $('#'+container).append('&lt;table id=&quot;'+subgrid_table_id+'&quot;&gt;&lt;/table&gt;&lt;div id=&quot;'+subgrid_table_id+'_pager&quot;&gt;&lt;/div&gt;');
                $('#'+subgrid_table_id).jqGrid({
                          caption: 'Города',
                          hiddengrid: true,
                          url: 'p3e4.php',
                          datatype: 'json',
                          mtype: 'POST',
                          postData: {'get':'subgrid', 'id':countryCode},
                          colNames: ['Город', 'Широта', 'Долгота'],
                          colModel: [
                            {name: 'city', index: 'city', width:130},
                            {name: 'latitude', index: 'latitude', width:80, align: 'right'},
                            {name: 'longitude', index: 'longitude', width:80, align: 'right'}
                          ],
                          height: 'auto',
                          autowidth: true,
                          rownumbers: true,
                          rownumWidth: 40,
                          rowNum: 10,
                          sortname: 'city',
                          sortorder: 'asc',
                          pager: $('#'+subgrid_table_id+'_pager'),
                          rowNum:10,
                          rowList:[10,20,50,100]
                });
            }
    });
}
</pre>
<p>В теле этой функции выполняется AJAX запрос, передающий серверному скрипту 2 параметра методом POST:</p>
<ul>
<li><strong>id</strong> &#8211; идентификатор записи, в нашем случае это сокращенный код страны</li>
<li><strong>get</strong> &#8211; этот параметр указывает, что мы хотим получить с сервера детальную информацию по выбранной стране</li>
</ul>
<p>После того как запрос будет успешно выполнен (см. строку 8), в открывшийся под выбранной строкой контейнер будет помещена какая-то HTML разметка с полученными с сервера данными. В данном примере такая разметка представлена не нумированным списком в картинкой &#8211; флагом страны. После этого в этот же контейнер помещается разметка для дочерней таблицы и производится инициализация дочерней таблицы.</p>
<p>В принципе логика работы достаточно проста, главное не забывать что работать с полученными от сервера данными можно только после окончания AJAX запроса или производя синхронные запросы. </p>
<p>Как вы понимаете в контейнер для подтаблицы можно помещать не только какую-то примитивную разметку, но и формы, флеш, другие &laquo;вкусные&raquo; и полезные вещи.</p>
<p><a title="p2.3" name="p2.3"></a><strong>3)Ведущая и ведомая jqGrid</strong></p>
<p>Однако не всегда можно сгруппировать данные и засунуть их в подтаблицу. Иногда данные могут быть полностью самостоятельными и при этом иметь некую связь. Например однажды передо мной стала задача вывести пользователю перечень счетов и платежей по этим счетам, и при этом обеспечить возможность просмотра счетов, платежей и платежей по выбранному счету. И тут то мне очень помогла методика &laquo;ведущий-ведомый&raquo;. Работа которой проиллюстрирована в <a href="http://trahomoto.dlinkddns.com/works/linkexchanger/articles/jqgrid/p3e6.html">ДЕМО5.6</a>.</p>
<p>Имеется две jqGrid, отображающие страны и города, которые можно менять местами благодаря плагину <em>sortable</em>. Также в верхней части документа есть checkbox который включает функцию фильтрации содержимого ведомой (нижней) таблицы, на основе выбранной записи в ведущей (верхней) таблице. При этом вся фильтровка осуществляется на стороне сервера, с этого и начнем разбор примера. Для удобства две таблицы запрашивают данные у двух отдельных серверных скриптов, один для городов, другой для стран.<br />
<strong>Скрипт для таблицы &laquo;Города&raquo;</strong> (т.к. основная структура скрипта &laquo;стандартна&raquo; я привожу лишь основные моменты):</p>
<pre class="brush: php;">
// Получение параметров page, rows и т.д.
...
if($_REQUEST['filterBy'] != 'null')  // Фильтр
    $WHERE = &quot; WHERE country_code = '&quot;.$_REQUEST['filterBy'].&quot;' &quot;;
else
    $WHERE = '';
...
// Запрос подсчета суммарного кол-ва записей
$result = mysql_query(&quot;SELECT COUNT(*)AS count FROM cities&quot;.$WHERE);
...
// Запрос выборки данных
$result = mysql_query(&quot;SELECT city, latitude, longitude FROM cities &quot;.$WHERE.&quot; ORDER BY &quot;.$sidx.&quot; &quot;.$sord.&quot; LIMIT &quot;.$start.&quot;, &quot;.$limit);
</pre>
<p>В данном случае клиентский код при запросе данных с сервера помимо &laquo;стандартных&raquo; параметров, отправляет еще и дополнительный параметр <strong>filterBy</strong>, который по сути и определяет критерий по которому нужно выбрать записи из БД и вернуть клиенту. Что и проиллюстрировано в последующих запросах.</p>
<p><strong>Скрипт для таблицы &laquo;Страны&raquo;:</strong></p>
<pre class="brush: php;">
// Получение параметров page, rows и т.д.
...
if($_REQUEST['filterBy'] != 'null'){
     $country = @mysql_fetch_array(mysql_query(&quot;SELECT country_code FROM cities WHERE id = &quot;.$_REQUEST['filterBy']));
     $WHERE = &quot; WHERE country_code = '&quot;.$country['country_code'].&quot;' &quot;;
}else{
     $WHERE = '';
}
...
// Запрос подсчета суммарного кол-ва записей
$result = mysql_query(&quot;SELECT COUNT(*)AS count FROM countries &quot;.$WHERE);
...
// Запрос выборки данных
$result = mysql_query(&quot;SELECT * FROM countries &quot;.$WHERE.&quot; ORDER BY &quot;.$sidx.&quot; &quot;.$sord.&quot; LIMIT &quot;.$start.&quot;, &quot;.$limit);
</pre>
<p>Как видите полная аналогия предыдущего листинга, но теперь если передано определенное значение фильтра, происходит дополнительный запрос для уточнения кода страны.<br />
На этом все премудрости серверной стороны заканчиваются и начинается клиентский код, но прежде чем перейти к его рассмотрению <strong>пара слов о разметке страницы</strong>:</p>
<pre class="brush: xml;">
&lt;input type=&quot;checkbox&quot; id=&quot;link&quot;&gt;
&lt;label for=&quot;link&quot;&gt;Связать таблицы&lt;/label&gt;

&lt;div id=&quot;interfaceBody&quot; style=&quot;margin: 10px 10px 10px 10px; padding: 0px 10px 10px 10px; border: 2px solid gray&quot;&gt;
&lt;div class=&quot;grid&quot; id=&quot;countries&quot; style=&quot;padding: 10px 10px 10px 10px; margin-top: 10px; border: 2px solid red&quot;&gt;
    &lt;table id=&quot;table_countries&quot;&gt;&lt;/table&gt;
    &lt;div id=&quot;table_countriesPager&quot;&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;grid&quot; id=&quot;cities&quot; style=&quot;padding: 10px 10px 10px 10px; margin-top: 10px; border: 2px solid green&quot;&gt;
    &lt;table id=&quot;table_cities&quot;&gt;&lt;/table&gt;
    &lt;div id=&quot;table_citiesPager&quot;&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
</pre>
<p>Если не обращать внимание на ужасно длинные inline-стили, то разметка достаточно проста. Сначала идет код checkbox&#8217;a с меткой, а следом контейнер всего интерфейса, внутри которого два дочерних контейнера, по одному для каждой таблицы. </p>
<p>И наконец <strong>клиентский скрипт:</strong></p>
<pre class="brush: jscript;">
//-------------------------------------------------------------------
// Функция-обработчик
function stickTogether(){
    if($('#link').is(':checked')){
        // Флаг &quot;Связать таблицы&quot; утановлен
        var masterId        = $('#interfaceBody &gt; DIV:first').attr('id');                //Определяем ID контейнера &quot;ведущей таблицы&quot;
        var masterPostData  = $('#table_'+masterId).jqGrid('getGridParam','postData');   //Получаем весь объект postData &quot;ведущей таблицы&quot;
        var selId    = $('#table_'+masterId).jqGrid('getGridParam','selrow');            //Получаем id записи в выделенной строке
                                                                                         //не путайте с rowIndex
        // Проверяем какое текущее значение фильтра ведущей таблицы, он должен быть сброшен (например null)
        if(masterPostData.filterBy){
            $('#table_'+masterId).jqGrid('setGridParam',{'postData':{'filterBy':null}}); //Сбрасываем значение фильтра
            $('#table_'+masterId).trigger('reloadGrid');                                 //Перезагружаем данные в таблицу
        }

        var slaveId  = $('#interfaceBody &gt; DIV:last').attr('id');                        //Определяем ID контейнера &quot;ведомой таблицы&quot;
        $('#table_'+slaveId).jqGrid('setGridParam',{'postData':{'filterBy':selId}});     //Применяем в качестве фильтра ведомой таблицы
                                                                                         //id выбранной записи в ведущей таблице
        $('#table_'+slaveId).trigger('reloadGrid');                                      //Перезагружаем данные в таблицу
    }else{
        // Флаг &quot;Связать таблицы&quot; не утановлен
        var coutriesT       = $('#table_countries');
        var countriesPost   = coutriesT.jqGrid('getGridParam','postData');

        if(countriesPost.filterBy){ //Сбрасываем фильтр т.к. ничего не нужно фильтровать
            coutriesT.jqGrid('setGridParam',{'postData':{'filterBy':null}})
            coutriesT.trigger('reloadGrid');
        }
        //-----------------------
        var citiesT       = $('#table_cities');
        var citiesPost    = citiesT.jqGrid('getGridParam','postData');

        if(citiesPost.filterBy){ //Сбрасываем фильтр т.к. ничего не нужно фильтровать
            citiesT.jqGrid('setGridParam',{'postData':{'filterBy':null}})
            citiesT.trigger('reloadGrid');
        }
    }
}
//-------------------------------------------------------------------
// Настройка плагинов
var tcountries = $('#table_countries').jqGrid({
                          caption: 'Страны',
                          hidegrid: false,
                          url:'p3e6_countries.php',
                          postData: {'filterBy':null},
                          datatype: 'json',
                          mtype: 'POST',
                          colNames:['Код страны','Cтрана','Столица','Домены'],
                          colModel :[
                                    {name:'country_code', index:'country_code', width:80, hidden: true},
                                    {name:'country_name', index:'country_name', width:60},
                                    {name:'capital', index:'capital', width:60},
                                    {name:'domains', index:'domains', width:60}
                                    ],
                          pager: $('#table_countriesPager'),
                          rowNum: 100,
                          scroll: true,
                          viewrecords: true,
                          sortname: 'country_name',
                          sortorder: 'asc',
                          height: 200,
                          autowidth: true,
                          onSelectRow: stickTogether
                });

var tcities = $('#table_cities').jqGrid({
                          caption: 'Города',
                          hidegrid: false,
                          url: 'p3e6_cities.php',
                          postData: {'filterBy':null},
                          datatype: 'json',
                          mtype: 'POST',
                          colNames: ['Город', 'Широта', 'Долгота'],
                          colModel: [
                            {name: 'city', index: 'city', width:130},
                            {name: 'latitude', index: 'latitude', width:80, align: 'right'},
                            {name: 'longitude', index: 'longitude', width:80, align: 'right'}
                          ],
                          height: 200,
                          autowidth: true,
                          rownumbers: true,
                          rownumWidth: 40,
                          rowNum: 100,
                          sortname: 'city',
                          sortorder: 'asc',
                          pager: $('#table_citiesPager'),
                          scroll: true,
                          viewrecords: true,
                          onSelectRow: stickTogether
                });

$(&quot;#interfaceBody&quot;).sortable({
        connectWith: '.grid',
        placeholder: 'ui-state-error',
        opacity: 0.7,
        stop: stickTogether
});

//-------------------------------------------------------------------
// Назначаем обработчик на событие
$('#link').change(stickTogether);
</pre>
<p>При всем своем объеме код достаточно груб и прост. Начнем пожалуй с назначения обработчика на изменение checkbox&#8217;a, самая последняя строка в листинге. Как видите при изменении checkbox&#8217;a будет вызвана функция <strong>stickTogether</strong>. В теле которой происходит проверка состояния флажка и если он не установлен, то произойдет сброс всех &laquo;фильтров&raquo; таблиц и перезагрузка данных в таблице.<br />
Но самое интересное это код в &laquo;положительной&raquo; ветке if&#8217;а, когда флажок установлен. Мы знаем, что ведущая таблица расположена вверху, значит для начала узнаем какая же таблица в данный момент находится там. Для этого получаем значение атрибута <em>id</em> первого контейнера (строка 6).  Теперь зная какая таблица ведущая &#8211; получаем объект <strong>postData</strong>, который, напомню, содержит все параметры и их значения для отправки серверу. В 7й строке получим Id записи в выделенной строке ведущей таблицы. Далее проверив значение фильтра ведущей таблицы, при необходимости сбросим его. Это необходимо если пользователь поменял таблицы местами.<br />
В строке 16 узнаем id контейнера ведомой таблицы. И применяем фильтр, записав id выделенной строки в ведущей таблице, и перезагружаем данные.<br />
У данного скрипта есть один недостаток &#8211; расплата за универсальность. Из-за того что на событие <strong>onSelectRow:</strong> в обоих таблицах определен один и тот же обработчик <strong>stickTogether</strong>, при выделении строки в ведомой таблице, происходит постоянное обновление ее записей. Но уверен что те кому потребуется такой функционал jqGrid без труда смогут это исправить. </p>
<p><strong>Заключение</strong><br />
Подведя итоги проделанной работы можно сказать, что в данной статье мы рассмотрели практически все варианты расширенного использования плагина. Научились работать с древовидными данными и подтаблицами, а также попробовали управлять содержимым ведомой таблицы посредством данных из ведущей. В следующей части я рассмотрю еще одну экзотическую интересную опцию jqGrid &#8211; &laquo;drag&#8217;n'drop записей между jqGrid&#8217;ами&raquo;.<br />
Ну и как всегда если у вас возникли вопросы задавайте их на <a href="http://www.linkexchanger.su/forum/">форуме</a> ну а комментарии используйте для предложений и пожеланий.</p>
<p>Итак приблизительный план работ на следующий выпуск:</p>
<ul>
<li><strong>Расширенные возможности jqGrid</strong>
<ul>
<li>drag&#8217;n'drop записей между jqGrid&#8217;ами</li>
</ul>
</li>
<li><strong>Поиск данных в jqGrid</strong>
<ul>
<li>&laquo;inline&raquo; поиск</li>
<li>поиск с использованием встроенной формы</li>
<li>расширенный поиск с использованием встроенной формы</li>
<li>поиск с использованием внешней формы</li>
</ul>
</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.linkexchanger.su/2010/523.html/feed</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>Yii framework. Часть 1 : Введение</title>
		<link>http://www.linkexchanger.su/2010/418.html</link>
		<comments>http://www.linkexchanger.su/2010/418.html#comments</comments>
		<pubDate>Sat, 06 Mar 2010 04:44:29 +0000</pubDate>
		<dc:creator>M4V23</dc:creator>
				<category><![CDATA[php]]></category>
		<category><![CDATA[mvc]]></category>
		<category><![CDATA[yii]]></category>

		<guid isPermaLink="false">http://www.linkexchanger.su/?p=418</guid>
		<description><![CDATA[Предисловие
В этом цикле статей я хочу рассказать о таком замечательном фреймворке, как yii. Предполагается, что у читателя есть некоторый навык работы с php5, особенно с его объектно-ориентированной частью. Я буду стараться охватить как можно больше разных аспектов создания веб-приложений на базе yii, добавляя от себя разные тонкости и хитрости; но не ждите от меня копипаста [...]]]></description>
			<content:encoded><![CDATA[<h2><strong>Предисловие</strong></h2>
<p>В этом цикле статей я хочу рассказать о таком замечательном фреймворке, как yii. Предполагается, что у читателя есть некоторый навык работы с <a href="http://php.net">php5</a>, особенно с его объектно-ориентированной частью. Я буду стараться охватить как можно больше разных аспектов создания веб-приложений на базе yii, добавляя от себя разные тонкости и хитрости; но не ждите от меня копипаста документации или api. И то и другое Вы можете найти на официальном сайте.</p>
<h2><strong>Введение</strong></h2>
<p>Что такое Yii?</p>
<p>Yii это свободный(распространяется под <a href="http://yiiframework.com/license/">new BSD licence</a>) высокопроизводительный объектно-ориентированный расширяемый php-фрэймворк для разработки веб-приложений.<br />
<span id="more-418"></span><br />
Зачем он нужен?</p>
<p>Для удобной разработки веб-приложений и чтобы не изобретать сто раз изобретенный велосипед.</p>
<h3>Основные особенности :</h3>
<ul>
<li>MVC-архитектура</li>
<li>Работа с базами данных</li>
<li>Поддержка кэширования на разных уровнях</li>
<li>Большое количество встроенных компонентов</li>
<li>Возможность простого подключения сторонних библиотек</li>
<li>Интеграция с jQuery</li>
</ul>
<h2><strong>Подготовка:</strong></h2>
<p>Системные требования:</p>
<ul>
<li>Веб-сервер(рекомендуется Apache)</li>
<li>PHP версии не ниже 5.1.0</li>
<li>PDO-совместимая СУБД (MySql, PostgreSQL, SqLite, Microsoft SQL, Oracle8) и соответствующее php-расширение для её поддержки.</li>
</ul>
<p>Рекомендуемые расширения для php:</p>
<ul>
<li>gd – для работы с графикой.</li>
<li>mcrypt – для функций кодирования.</li>
<li>MemCache  или APC – для кэширования, ускорения работы.</li>
</ul>
<p>Такой нехитрый набор в наше время можно найти почти на любом хостинге.</p>
<p>Для домашнего тестирования на linux можно установить пакеты из стандартных репозитариев.Если же Вы предпочитаете на windows, могу порекомендовать в качестве готового решения <a href="http://denwer.ru">denwer</a>.</p>
<p>Для пользователей денвера:</p>
<p>(В данном случае, Z: это диск, монтируемый денвером)<br />
1. Для начала прописываем в переменные окружения путь  Z:\usr\local\php5\<br />
2. Открываем /usr/local/php5/php.ini, ищем строчку extension_dir = &laquo;/usr/local/php5/ext&raquo;, заменяем на extension_dir = &laquo;Z:\usr\local\php5\ext&raquo;<br />
3. session.save_path = &laquo;/tmp&raquo; на session.save_path = &laquo;Z:\tmp&raquo;</p>
<h2><strong>Установка:</strong></h2>
<p>На момент написания статьи, последняя стабильная версия была 1.1.0. Скачать её можно в виде архива по адресу  <a title="http://yiiframework.com/download" href="http://yiiframework.com/download" target="_blank">http://yiiframework.com/download</a><br />
Вся установка сводится к распаковке содержимого архива.Для начала рекомендую распаковать всё в директорию доступную из веб и открыть папку requirments в браузере, чтобы убедиться в наличии всех необходимых компонентов.</p>
<p>Для создания приложения необходимо использовать коммандную строку(ssh при удалённом доступе). Нужно запустить файл yiic.bat(для windows) или yiic(для linux и других unix-based систем) с параметрами webapp /full/path/to/new/wbebapp/.<br />
Например :</p>
<blockquote><p><em>$ /var/www/framework/yiic webapp /var/www/testing</em></p></blockquote>
<p>Убедитесь, что у вас есть права записи в  директорию, где Вы хотите создать веб-приложение и она доступна из web. Можно зайти в нее через браузер и увидеть возможности, предоставлямые yii «из коробки».</p>
<p>Практикой мы займемся в следующей статье, а теперь немного теории.</p>
<p><strong>Модель – Представление – Контроллер(MVC)</strong> – это модульная архитектура, применяющийся в веб-программировании(в частности и в yii). Она направлена на разделение логики(контроллер), управления данными(модель) и пользовательского интерфейса(представление) с целью возможности изменять одни части не внося изменения в другие.</p>
<h3>Основные части, из которых состоит yii:</h3>
<blockquote><p><span style="color: #000000;">В yii имена всех системных классов начинается с перфикса C , с целью недопущения коллизии имён. По этому, пожалуйста, воздержитесь от использования этого префикса в своих классах.</span></p></blockquote>
<p><strong>Входной файл</strong><br />
Входной файл(обычно index.php) это единственный скрипт, с которым контактирует пользователю. Вобщем-то, всё что он делает, это читает конфигурацию и создаёт экземпляр класса CWebApplication.<br />
<strong>Приложение(application)</strong><br />
Приложение(экземпляр класса CWebApplication) обрабатывает запрос пользователя, выполняет роутинг и передаёт его на исполнение соответствующему контроллеру.<br />
<strong>Контроллер(controller)</strong><br />
Контроллер(экзэмпляр класса CController или производного от него) определяет основную логику приложения, взаимодействует с моделями и отображениями. Контроллеры обычно находятся в папке /protected/controllers. По соглашению, класс контроллера и имя файла с ним : NameController.php<br />
<strong>Действие(action)</strong><br />
Действие это тип действия, выполняемого пользователем, например просмотр статьи в блоге или отправка комментария. Обычно является методом контроллера(вида actionName), но может быть вынесенно в отдельный класс.<br />
<strong>Модель (model)</strong><br />
Модель представляет собой сущность данных. Например таблица в базе данных(CActiveRecord) или форма на веб-странице(CForm). Она занимается непосредственной обработкой данных: созданием, получением, изменением. Также представляет интерфейс доступа к валидаторам(validator), проверяющим корректность введённых пользователем данных. Модели находятся в папке /protected/models. Модель обычно имеет имя, соответствующее таблице в бд, которую она представляет.<br />
<strong>Представление(view)</strong><br />
Представление генерирует готовые части страницы, отдаваемой пользователю.Оно не использует логики, кроме как условий и циклов. Представления для каждого контроллера обычно раздельны и хранятся в /protected/views/controllername/.<br />
<strong>Макет (layout)</strong><br />
Макет это специальное представление для вставки других представлений. Обычно он содержит части пользовательского интерфейса, используемого другими представлениями. Например, основной макет может содержать в себе шапку и подвал страницы, места для подключения других представлений и виджетов. Макеты храняться в /protected/views/layouts. По умолчанию используется макет main.php.<br />
<strong>Виджет(widget)</strong><br />
Виджет это компонент для генерации самодостаточного элемента пользовательского интерфейса(например, верхнее меню в тестовом приложении). В zii (библиотеке расширений, поставляемых вместе с yii) имеется большое количество готовых виджетов.<br />
<strong>Компонент(component)</strong><br />
Представляет сущность какого-либо аспекта веб-приложения. Например, авторизация пользователей. В yii много готовых компонентов, которые могут использоваться как в готовом виде, так и расширяться веб-разработчиками.<br />
<strong>Модуль(module)</strong><br />
Модуль, это самодостаточная единица, состоящая из контроллеров, моделей, отображений, и.т.д. Модули используются для разделения сайта на логические части, например форум и блог.</p>
<h2><strong>Заключение</strong></h2>
<p>В первой статье мы узнали, что такое yii, познакомились с базовыми понятиями и подготовили полигон для дальнейшего изучения.</p>
<p>И на последок хочу дать несколько полезных ссылок:</p>
<p><a href="http://yiiframework.com" target="_blank">Оффициальный сайт (en)</a></p>
<p><a href="http://yiiframework.ru" target="_blank">Русскоязычное сообщество (ru)</a></p>
<p><a href="http://dbhelp.ru/" target="_blank">Блог, посвящённый yii (ru) </a></p>
<h2><strong>В следующей статье:</strong></h2>
<p>В следующей статье мы познокомимся со внутренним устройством фреймворка, научимся делать собственные контроллеры, модели и отображения, изучим основы ActiveRecord.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.linkexchanger.su/2010/418.html/feed</wfw:commentRss>
		<slash:comments>19</slash:comments>
		</item>
		<item>
		<title>jqGrid Часть II: Базовые возможности</title>
		<link>http://www.linkexchanger.su/2010/486.html</link>
		<comments>http://www.linkexchanger.su/2010/486.html#comments</comments>
		<pubDate>Sat, 27 Feb 2010 07:37:35 +0000</pubDate>
		<dc:creator>TRAHOMOTO</dc:creator>
				<category><![CDATA[jQuery]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[jqGrig]]></category>

		<guid isPermaLink="false">http://www.linkexchanger.su/?p=486</guid>
		<description><![CDATA[Итак в предыдущей статье (jqGrid Часть I:Знакомство) мы с вами подготовили платформу для опытов и выполнили &#171;пробный запуск&#187; плагина, с самыми &#171;базовейшими&#187; параметрами. Согласно которым таблица запрашивает данные с сервера в XML разметке, при этом у нас есть возможность сортировать данные в столбцах.
В данной статье мы продолжим эксперименты и прощупаем еще ряд замечательных возможностей jqGrid, [...]]]></description>
			<content:encoded><![CDATA[<p>Итак в предыдущей статье (<a href="http://www.linkexchanger.su/2010/118.html">jqGrid Часть I:Знакомство</a>) мы с вами подготовили платформу для опытов и выполнили &laquo;пробный запуск&raquo; плагина, с самыми &laquo;базовейшими&raquo; параметрами. Согласно которым таблица запрашивает данные с сервера в XML разметке, при этом у нас есть возможность сортировать данные в столбцах.</p>
<p>В данной статье мы продолжим эксперименты и прощупаем еще ряд замечательных возможностей jqGrid, вот план действий:</p>
<ul>
<li><strong><a href="http://www.linkexchanger.su/2010/486.html#p1">Другие способы загрузки данных</a></strong>
<ul>
<li><a href="http://www.linkexchanger.su/2010/486.html#p1.1">В виде JSON объекта</a></li>
<li><a href="http://www.linkexchanger.su/2010/486.html#p1.2">В виде массива</a></li>
<li><a href="http://www.linkexchanger.su/2010/486.html#p1.3">Конвертирование простой таблицы в jqGrid</a></li>
</ul>
</li>
<li><strong><a href="http://www.linkexchanger.su/2010/486.html#p2">Форматирование данных</a></strong>
<ul>
<li><a href="http://www.linkexchanger.su/2010/486.html#p2.1">Форматирование ячеек</a></li>
<li><a href="http://www.linkexchanger.su/2010/486.html#p2.2">Изменение представления данных</a></li>
</ul>
</li>
<li><strong><a href="http://www.linkexchanger.su/2010/486.html#p3">Панели инструментов и дополнительные панели</a></strong>
<ul>
<li><a href="http://www.linkexchanger.su/2010/486.html#p3.1">Панель-листалка</a></li>
<li><a href="http://www.linkexchanger.su/2010/486.html#p3.2">Панель инструментов</a></li>
<li><a href="http://www.linkexchanger.su/2010/486.html#p3.3">Пользовательские панели</a></li>
</ul>
</li>
<li><strong><a href="http://www.linkexchanger.su/2010/486.html#p4">Управление столбцами данных</a></strong>
<ul>
<li><a href="http://www.linkexchanger.su/2010/486.html#p4.1">Изменение размера и положения столбцов</a></li>
<li><a href="http://www.linkexchanger.su/2010/486.html#p4.2">Скрываем не нужные или отображаем нужные столбцы данных</a></li>
</ul>
</li>
</ul>
<p><span id="more-486"></span></p>
<p><a title="p1" name="p1"></a><strong>I. Другие способы загрузки данных</strong><br />
<a title="p1.1" name="p1.1"></a><strong>1) Загрузка данных в виде JSON объекта</strong></p>
<p>JSON &#8211; как и XML является текстовым форматом обмена данными, при этом намного моложе последнего. Является более прогрессивным методом, благодаря большей гибкости своей архитектуры по сравнению с XML. На тему сравнения XML и JSON есть очень хорошая статья (<a href="http://habrahabr.ru/blogs/webdev/31225/">JSON и XML. Что лучше?</a>). Но при генерировании ответа в JSON методами PHP, есть ряд особенностей при работе с кириллицей. Повествование о которых выходит за рамки данной статьи, поэтому я ограничиваюсь лишь упоминанием.</p>
<p>Итак на практике загрузка таких данных требует следующей конфигурации плагина:</p>
<pre class="brush: jscript;">$(function(){
                $('#table').jqGrid({
                              url:'p2e1.php',
                  datatype: 'json',
                             mtype: 'GET',
                             colNames:['Код страны','Код региона', 'Город','Долгота','Широта','nbip'],
                             colModel :[
                                    {name:'country_code', index:'country_code', width:80},
                                    {name:'region_code', index:'region_code', width:80},
                                    {name:'city', index:'city', width:90},
                                    {name:'latitude', index:'latitude', width:60},
                                    {name:'longitude', index:'longitude', width:60},
                                    {name:'nbip', index:'nbip', width:30}],
                            pager: $('#tablePager'),
                            rowNum:10,
                            rowList:[10,20,30,100],
                            sortname: 'city',
                            sortorder: 'asc',
                  caption: 'Загрузка JSON данных',
                  rownumbers: true,
                            rownumWidth: 40
                });
    });
</pre>
<p>Все изменения я выделил отступами (строки 4, 19-21). Как вы можете видеть в листинге параметру <strong>datatype:</strong> присвоено значение <em><strong>&#8216;json&#8217;</strong></em>, что говорит плагину о том что от сервера ожидается ответ в виде JSON объекта. Далее я ввел в конфиг таблицы еще три свойства <strong>caption</strong>, <strong>rownumbers</strong>, <strong>rownumWidth</strong>. Что они определяют?</p>
<ul>
<li><strong>caption</strong> &#8211; если это свойство не пустое, то у таблицы появляется заголовок с текстом, присвоенным этому свойству.</li>
<li><strong>rownumbers</strong> &#8211; если это свойство &laquo;истина&raquo;, то первым столбцом таблицы будет столбец с номерами записей по порядку.
<ul>
<li><strong>rownumWidth</strong> &#8211; это свойство зависимо от rownumbers. И определяет ширину столбца с нумерацией.</li>
</ul>
</li>
</ul>
<p>С данного момента, я ввожу еще одно правило в этот цикл статей. Все свойства-параметры инициализации jqGrid вы будете самостоятельно изучать на <a href="http://www.trirand.com/jqgridwiki/doku.php?id=wiki:jqgriddocs">странице документации</a> плагина в разделе <a href="http://www.trirand.com/jqgridwiki/doku.php?id=wiki:options">Options</a> и <a href="http://www.trirand.com/jqgridwiki/doku.php?id=wiki:colmodel_options">colModel Options</a>. Но при этом я буду комментировать, то на что следует обратить внимание.</p>
<p>C параметрами клиентской части разобрались, теперь перейдем к серверной. Здесь я привожу листинг только последних строк кода, собственно это момент формирования и вывод ответа сервера.</p>
<p>Пример 1 &#8211; используя массив</p>
<pre class="brush: php;">
...
// Начало формирование массива
// для последующего преобразоования
// в JSON объект
$data['page']       = $page;
$data['total']      = $total_pages;
$data['records']    = $count;
// Строки данных для таблицы
$i = 0;
while($row = mysql_fetch_assoc($result)) {
    $data['rows'][$i]['id'] = $row['id'];
    $data['rows'][$i]['cell'][] = $row['country_code'];
    $data['rows'][$i]['cell'][] = $row['region_code'];
    $data['rows'][$i]['cell'][] = $row['city'];
    $data['rows'][$i]['cell'][] = $row['latitude'];
    $data['rows'][$i]['cell'][] = $row['longitude'];
    $data['rows'][$i]['cell'][] = $row['nbip'];
    $i++;
}
// Перед выводом не забывайте выставить header
// с типом контента и кодировкой
header(&quot;Content-type: application/json;charset=utf-8&quot;);
echo json_encode($data);
</pre>
<p>Пример 2 &#8211; используя объект</p>
<pre class="brush: php;">
...
// Начало формирование объекта
// для последующего преобразоования
// в JSON объект
$data-&gt;page       = $page;
$data-&gt;total       = $total_pages;
$data-&gt;records   = $count;
// Строки данных для таблицы
$i = 0;
while($row = mysql_fetch_assoc($result)) {
    $data-&gt;rows[$i]['id'] = $row[id];
    $data-&gt;rows[$i]['cell'] = array($row[country_code],$row[region_code],$row[city],$row[latitude],$row[longitude],$row[nbip]);
    $i++;
}
// Перед выводом не забывайте выставить header
// с типом контента и кодировкой
header(&quot;Content-type: text/script;charset=utf-8&quot;);
echo json_encode($data);
</pre>
<p>Оба подхода выполняют одни и те же действия, но при этом выбор подхода зависит от ваших предпочтений и уровня мастерства.</p>
<p>Вот ссылка на <a href="http://trahomoto.dlinkddns.com/works/linkexchanger/articles/jqgrid/p2e1.html">ДЕМО2.1</a> и <a href="http://trahomoto.dlinkddns.com/works/linkexchanger/articles/jqgrid/files/demo2.1.zip">ссылка на архив</a> с примером.<br />
Подытожив, скажу, что как видите в данном способе загрузки данных нет ничего сложного и принцип работы идентичен с загрузкой данных в виде XML, но при этом немного облегчается код серверного скрипта. Также повторюсь, что при кодировании данных в JSON методом PHP следует учитывать особенности работы с кириллицей!</p>
<p><a title="p1.2" name="p1.2"></a><strong>2) Загрузка данных в виде массива</strong></p>
<p>Теперь рассмотрим пример, как можно создать jqGrid используя в качестве источника данных массив. Как вы понимаете для данного примера не понадобится серверный скрипт, а клиентский скрипт будет выглядеть приблизительно так.</p>
<pre class="brush: jscript;">
$(function(){
$('#table').jqGrid({
  datatype: 'local',
          colNames:['ID','Код страны','Код региона', 'Город','Долгота','Широта','nbip'],
          colModel :[
                        {name:'id', index:'id', width:20},
                        {name:'country_code', index:'country_code', width:80},
                        {name:'region_code', index:'region_code', width:80},
                        {name:'city', index:'city', width:90},
                        {name:'latitude', index:'latitude', width:60},
                        {name:'longitude', index:'longitude', width:60},
                        {name:'nbip', index:'nbip', width:30}
                     ],
          caption: 'Загрузка массива данных'
});
var data = [
            {id: '1', country_code:'AD',  region_code:'02', city:'Canillo', latitude:'42.5667', longitude: '1.6', nbip:'0'},
            {id: '2', country_code:'AD',  region_code:'02', city:'El Tarter', latitude:'42.5833', longitude: '1.65', nbip:'0'},
            {id: '3', country_code:'AD',  region_code:'03', city:'Encamp', latitude:'42.5333', longitude: '1.5833', nbip:'0'},
            {id: '4', country_code:'AD',  region_code:'04', city:'Arinsal', latitude:'42.5667', longitude: '1.4833', nbip:'1'},
            {id: '5', country_code:'AD',  region_code:'04', city:'La Massana', latitude:'42.55', longitude: '1.5167', nbip:'0'},
            {id: '6', country_code:'AD',  region_code:'04', city:'Llorts', latitude:'42.6', longitude: '1.5333', nbip:'0'},
            {id: '7', country_code:'AD',  region_code:'05', city:'Ordino', latitude:'42.55', longitude: '1.5333', nbip:'2'},
            {id: '8', country_code:'AD',  region_code:'06', city:'Sant JuliГ  De LГІria', latitude:'42.4667', longitude: '1.5', nbip:'0'},
            {id: '9', country_code:'AD',  region_code:'07', city:'Andorra La Vella', latitude:'42.5', longitude: '1.5167', nbip:'56'},
            {id: '10', country_code:'AD',  region_code:'08', city:'Engordany', latitude:'42.5167', longitude: '1.55', nbip:'1'},
            {id: '11', country_code:'AD',  region_code:'08', city:'Les Escaldes', latitude:'42.5', longitude: '1.5333', nbip:'0'},
            {id: '12', country_code:'AE',  region_code:'01', city:'Abu Dhabi', latitude:'24.4667', longitude: '54.3667', nbip:'824'},
            {id: '13', country_code:'AE',  region_code:'01', city:'Al Ain', latitude:'24.1917', longitude: '55.7606', nbip:'19'},
            {id: '14', country_code:'AE',  region_code:'03', city:'Deira', latitude:'25.2722', longitude: '55.3111', nbip:'0'},
            {id: '15', country_code:'AE',  region_code:'03', city:'Dubai', latitude:'25.2521', longitude: '55.28', nbip:'7082'},
            {id: '16', country_code:'AE',  region_code:'03', city:'Jumairah', latitude:'25.2097', longitude: '55.2478', nbip:'0'},
            {id: '17', country_code:'AE',  region_code:'04', city:'Fujairah', latitude:'25.1231', longitude: '56.3375', nbip:'1'},
            {id: '18', country_code:'AE',  region_code:'05', city:'Ras Al Khaima', latitude:'25.7911', longitude: '55.9428', nbip:'0'},
            {id: '19', country_code:'AE',  region_code:'05', city:'Ras Al Khaimah', latitude:'25.7911', longitude: '55.9428', nbip:'2'},
            {id: '20', country_code:'AE',  region_code:'06', city:'Dibba', latitude:'25.6167', longitude: '56.2667', nbip:'1'},
            {id: '21', country_code:'AE',  region_code:'06', city:'Sharjah', latitude:'25.3622', longitude: '55.3911', nbip:'297'},
            {id: '22', country_code:'AF',  region_code:'11', city:'Herat', latitude:'34.3469', longitude: '62.1983', nbip:'0'},
            {id: '23', country_code:'AF',  region_code:'13', city:'Kabul', latitude:'34.5167', longitude: '69.1833', nbip:'161'},
            {id: '24', country_code:'AF',  region_code:'23', city:'Iran', latitude:'31.8314', longitude: '65.0689', nbip:'0'},
            {id: '25', country_code:'AF',  region_code:'23', city:'Kandahar', latitude:'31.6125', longitude: '65.7094', nbip:'0'}
           ]
for(var i = 0;i &lt;= data.length; i++){
    $('#table').jqGrid('addRowData',i+1,data[i]);
}
});
</pre>
<p>Как видите и в этом примере нет ничего &laquo;военного&raquo;, все предельно просто.  В качестве <strong>datatype:</strong> указываем <em><strong>&#8216;local&#8217;</strong></em>. Далее каким-либо образом(в данном примере простым присвоением) создаем массив объектов (каждая строка данных является объектом) и производим добавление данных методом <strong>addRowData</strong> в цикле (<em>for(var i = 0;i &lt;= data.length; i++)</em>).<br />
На данном этапе мне следует дать небольшой комментарий. Почему я написал &laquo;&#8230; добавление данных методом &#8230;&raquo; а при этом вся конструкция выглядит как передача параметра. Т.е. фактически происходит передача названия метода addRowData методу jqGrid() в качестве параметра. Дело все в том, что с версии 3.6 разработчики реализовали новый API для работы с jqGrid, согласно которому запись вида <strong>$(&#8216;#table&#8217;).jqGrid(&#8216;addRowData&#8217;,i+1,data[i]);</strong> равноценна <strong>$(&#8216;#table&#8217;).addRowData(i+1,data[i]);</strong> Но будьте внимательны, не все методы могут быть использованы в аннотации нового API, перед использованием методов обязательно ознакомьтесь с документацией по данному методу на странице <a href="http://www.trirand.com/jqgridwiki/doku.php?id=wiki:methods">Methods</a>.</p>
<ul>
<li><strong>addRowData</strong> &#8211; добавляет в таблицу новую строку данных. При этом строка данных должна выглядеть следующим образом {имя1: значение1, имя2: значение2&#8230;}. В качестве первого параметра методу, addRowData передается id вставляемой строки, а вторым объект данных (<strong>addRowData(row_id, row_data)</strong>).</li>
</ul>
<p>Также в свойствах инициализации jqGrid вы не найдете параметров панели-листалки, потому что данные уже загружены и нет необходимости запрашивать их порциями.<br />
Если присмотреться, то можно заметить что данный способ загрузки данных напоминает работу с JSON, но только на стороне клиента. Такой способ может пригодиться если вы по каким-либо причинам не можете сформировать XML или JSON ответ с данными от сервера.<br />
<a title="p1.3" name="p1.3"></a><strong>3) Конвертирование простой таблицы в jqGrid</strong><br />
Данный способ создания jqGrid будет полезен во время &laquo;страховки&raquo; на странице. Т.е. у нас есть страница, на которой есть таблица jqGrid в &laquo;нормальном браузере&raquo;, но как же пользователи у которых браузер не поддерживает JavaScript (Простите но тут обязан быть смайл <img src='http://www.linkexchanger.su/wp-includes/images/smilies/icon_biggrin.gif' alt=':-D' class='wp-smiley' /> )? Они не увидят таблицу? И вот тут то и пригодится данное свойство плагина.<br />
План действий таков:</p>
<ul>
<li>На сервере выполняется скрипт, который выводит в браузер страницу с таблицей и данными.</li>
<li>После загрузки всех элементов страницы выполняется функция преобразования статической таблицы в jqGrid</li>
<li>Ну, а если браузер посетителя-бедолаги не поддерживает JS, то он просто увидит таблицу. Которую кстати можно оформить используя стили jQueryUI CSS Framework.</li>
</ul>
<p>Вот и листинг</p>
<pre class="brush: xml;">
&lt;!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Strict//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd'&gt;
&lt;html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en' lang='en'&gt;
&lt;head&gt;
&lt;meta http-equiv='Content-Type' content='text/html; charset=utf-8' /&gt;
&lt;title&gt;Осваиваем jqGrid с Linkexchanger&lt;/title&gt;&lt;/p&gt;
&lt;link rel='stylesheet' type='text/css' media='screen' href='css/flick/jquery-ui-1.7.2.custom.css' /&gt;
&lt;link rel='stylesheet' type='text/css' media='screen' href='css/ui.jqgrid.css' /&gt;
&lt;p&gt;&lt;style&gt;
html, body {
margin: 0;
padding: 0;
font-size: 80%;
}
&lt;/style&gt;
&lt;script type='text/javascript' src='js/jquery-1.4.min.js'&gt;&lt;/script&gt;
&lt;script src='js/i18n/grid.locale-ru.js' type='text/javascript'&gt;&lt;/script&gt;
&lt;script src='js/jquery.jqgrid.min.js' type='text/javascript'&gt;&lt;/script&gt;
&lt;script type='text/javascript'&gt;
$(function(){
    $('#table').click(function(){
        tableToGrid('#table');
    });
});
&lt;/script&gt;&lt;/head&gt;
&lt;body&gt;
&lt;?php
// Подключение и выбор БД
//$db = mysql_connect('database_host', 'database_user', 'database_password');
//mysql_select_db('database_name');
// Подключение и выбор БД
$db = mysql_connect('database_host', 'database_user', 'database_password');
mysql_select_db('database_name');&lt;/p&gt;
// Запрос выборки данных
$query = 'SELECT id, country_code, region_code, city, latitude, longitude, nbip FROM cities LIMIT 30';
$result = mysql_query($query);
// Строим таблицу с данными
echo &quot;&lt;table id='table' border='1'&gt;&quot;;
echo &quot;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;ID&lt;/th&gt;&lt;th&gt;Код страны&lt;/th&gt;&lt;th&gt;Код региона&lt;/th&gt;&lt;th&gt;Город&lt;/th&gt;&lt;th&gt;Долгота&lt;/th&gt;&lt;th&gt;Широта&lt;/th&gt;&lt;th&gt;nbip&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&quot;;
while($row = mysql_fetch_assoc($result)) {
    echo &quot;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;'.$row['id'].'&lt;/td&gt;&lt;td&gt;'.$row['country_code'].'&lt;/td&gt;&lt;td&gt;'.$row['region_code'].'&lt;/td&gt;&lt;td&gt;'.$row['city'].'&lt;/td&gt;td&gt;'.$row['latitude'].'&lt;/td&gt;&lt;td&gt;'.$row['longitude'].'&lt;/td&gt;&lt;td&gt;'.$row['nbip'].'&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&quot;;
}
echo &quot;&lt;/table&gt;&quot;;
?&gt;
&lt;/body&gt;
&lt;/html&gt;
</pre>
<p>И ссылка на <a href="http://trahomoto.dlinkddns.com/works/linkexchanger/articles/jqgrid/p2e2.php">ДЕМО2.2</a> (просто кликните на таблицу)<br />
Как видите простейший код, при клике на объект <em><strong>#table</strong></em> собственно таблицу, выполняется функция <strong>tableToGrid()</strong> которой в качестве параметра передается селектор таблицы которую следует преобразовать в jqGrid.</p>
<p><strong>Использование свойств при конвертировании таблицы в jqGrid</strong><br />
И раз уж мы начали разговор про этот метод инициализации jqGrid, то давайте рассмотрим на примере <a href="http://trahomoto.dlinkddns.com/works/linkexchanger/articles/jqgrid/p2e2_1.php">ДЕМО2.2_1</a> его работу. А следом и код</p>
<pre class="brush: jscript;">
var options = {
                    caption: 'Конвертирование таблицы',
                    width: 800,
                    height: 600,
                    colModel :[
                                {name:'ID', width:20},
                                {name:'Код страны', width:80},
                                {name:'Страна', width:100, formatter:'select', editoptions:{value:&quot;AD:Andorra; AE:United Arab Emirates; AF:Afghanistan; AG:Antigua and Barbuda; AI:Anguilla; AL:Albania; AM:Armenia; AN:Netherland Antilles; AO:Angola; AR:Argentina&quot;}},
                                {name:'Код региона', width:80},
                                {name:'Город', width:90},
                                {name:'Долгота', width:60},
                                {name:'Широта', width:60},
                                {name:'nbip', index:'nbip', width:30}
                   ]};
                   tableToGrid(&quot;#table&quot;,options);
</pre>
<p>Как видите при использовании этой функции, в качестве второго параметра можно передать объект с параметрами таблицы. Но при этом следует обратить внимание на то, что заголовки столбцов должны иметь такое же имя как и текст в заголовке конвертируемой таблицы. Я думаю вы обратили внимание на дополнительные параметры в строке 8, мы рассмотрим их далее в этой статье.<br />
<a title="p2" name="p2"></a><strong>II. Форматирование данных</strong><br />
<a title="p2.1" name="p2.1"></a><strong>1) Форматирование ячеек</strong><br />
Википедия определяет Форматирование как &laquo;приведение чего-либо к какому-либо формату&raquo;. Соответственно в нашем случае это будет преобразование полученных от сервера данных, к другому виду. jqGrid позволяет производить как  простое так и сложное форматирование. &laquo;Простым форматированием&raquo; я условно назвал &laquo;Выравнивание&raquo; и &laquo;Изменением цвета&raquo; данных при этом мы &laquo;форматируем ячейку&raquo;.<br />
Давайте посмотрим как это делается на примере <a href="http://trahomoto.dlinkddns.com/works/linkexchanger/articles/jqgrid/p2e3.html">ДЕМО2.3</a></p>
<pre class="brush: jscript;">
$(function(){
    $('#table').jqGrid({
              datatype: 'local',
              colNames:['ID','Код страны','Код региона', 'Город','Долгота','Широта','nbip'],
              colModel :[
                            {name:'id', index:'id', width:20, align: 'center'},
                            {name:'country_code', index:'country_code', width:80, align: 'right'},
                            {name:'region_code', index:'region_code', width:80, align: 'left'},
                            {name:'city', index:'city', width:90},
                            {name:'latitude', index:'latitude', width:60},
                            {name:'longitude', index:'longitude', width:60},
                            {name:'nbip', index:'nbip', width:30}
                         ],
              caption: 'Простое форматирование',
              width: 600,
              afterInsertRow: function(row_id, row_data){
                                if (row_data.country_code == 'AD') {
                                    $('#table').jqGrid('setCell',row_id,'city','',{'color':'#FF00FF'});
                                }else if(row_data.country_code == 'AE'){
                                    $('#table').jqGrid('setCell',row_id,'city','',{'color':'red'});
                                }else{
                                    $('#table').jqGrid('setCell',row_id,'city','',{'background-color': '#999999'});
                              if(row_data.country_code == 'CZ'){
                                        $('#table').jqGrid('setCell',row_id,'city','',{'color':'#FF00FF', 'font-weight':'bold'},{'title': 'Чехия Ура!'});
                                    }
                                }
                            }
    });
var data = [
            {id: '1', country_code:'AD',  region_code:'02', city:'Canillo', latitude:'42.5667', longitude: '1.6', nbip:'0'},
            {id: '2', country_code:'AD',  region_code:'02', city:'El Tarter', latitude:'42.5833', longitude: '1.65', nbip:'0'},
            {id: '3', country_code:'AD',  region_code:'03', city:'Encamp', latitude:'42.5333', longitude: '1.5833', nbip:'0'},
            {id: '4', country_code:'AD',  region_code:'04', city:'Arinsal', latitude:'42.5667', longitude: '1.4833', nbip:'1'},
            {id: '5', country_code:'AD',  region_code:'04', city:'La Massana', latitude:'42.55', longitude: '1.5167', nbip:'0'},
            {id: '6', country_code:'AD',  region_code:'04', city:'Llorts', latitude:'42.6', longitude: '1.5333', nbip:'0'},
            {id: '7', country_code:'AD',  region_code:'05', city:'Ordino', latitude:'42.55', longitude: '1.5333', nbip:'2'},
            {id: '8', country_code:'AD',  region_code:'06', city:'Sant JuliГ  De LГІria', latitude:'42.4667', longitude: '1.5', nbip:'0'},
            {id: '9', country_code:'AD',  region_code:'07', city:'Andorra La Vella', latitude:'42.5', longitude: '1.5167', nbip:'56'},
            {id: '10', country_code:'AD',  region_code:'08', city:'Engordany', latitude:'42.5167', longitude: '1.55', nbip:'1'},
            {id: '11', country_code:'AD',  region_code:'08', city:'Les Escaldes', latitude:'42.5', longitude: '1.5333', nbip:'0'},
            {id: '12', country_code:'AE',  region_code:'01', city:'Abu Dhabi', latitude:'24.4667', longitude: '54.3667', nbip:'824'},
            {id: '13', country_code:'AE',  region_code:'01', city:'Al Ain', latitude:'24.1917', longitude: '55.7606', nbip:'19'},
            {id: '14', country_code:'AE',  region_code:'03', city:'Deira', latitude:'25.2722', longitude: '55.3111', nbip:'0'},
            {id: '15', country_code:'AE',  region_code:'03', city:'Dubai', latitude:'25.2521', longitude: '55.28', nbip:'7082'},
            {id: '16', country_code:'AE',  region_code:'03', city:'Jumairah', latitude:'25.2097', longitude: '55.2478', nbip:'0'},
            {id: '17', country_code:'AE',  region_code:'04', city:'Fujairah', latitude:'25.1231', longitude: '56.3375', nbip:'1'},
            {id: '18', country_code:'AE',  region_code:'05', city:'Ras Al Khaima', latitude:'25.7911', longitude: '55.9428', nbip:'0'},
            {id: '19', country_code:'AE',  region_code:'05', city:'Ras Al Khaimah', latitude:'25.7911', longitude: '55.9428', nbip:'2'},
            {id: '20', country_code:'AE',  region_code:'06', city:'Dibba', latitude:'25.6167', longitude: '56.2667', nbip:'1'},
            {id: '21', country_code:'AE',  region_code:'06', city:'Sharjah', latitude:'25.3622', longitude: '55.3911', nbip:'297'},
            {id: '22', country_code:'AF',  region_code:'11', city:'Herat', latitude:'34.3469', longitude: '62.1983', nbip:'0'},
            {id: '23', country_code:'AF',  region_code:'13', city:'Kabul', latitude:'34.5167', longitude: '69.1833', nbip:'161'},
            {id: '24', country_code:'AF',  region_code:'23', city:'Iran', latitude:'31.8314', longitude: '65.0689', nbip:'0'},
            {id: '25', country_code:'AF',  region_code:'23', city:'Kandahar', latitude:'31.6125', longitude: '65.7094', nbip:'0'},
            {id: '26', country_code:'CZ',  region_code:'23', city:'Stav', latitude:'50.4667', longitude: '15.4667', nbip:'0'}
           ]
for(var i = 0;i &lt;= data.length; i++){
     $('#table').jqGrid('addRowData',i+1,data[i]);
}
});
</pre>
<p>Для этого примера я взял код &laquo;Загрузки данных из массива&raquo;. Давайте разберем, то что изменилось. Во-первых для удобства это таблица имеет ширину 600px (width: 600), во-вторых появился обработчик на событие <strong><em>afterInsertRow</em></strong> и в-третьих &#8211; в набор данных добавилась строка id 26.<br />
Итак выравнивание текста в ячейке осуществляется простым определением свойства align в модели столбца (<em>colModel</em>).<br />
А вот чтобы раскрасить, а также изменить другие стилевые свойства ячейки, нужно писать пользовательскую функцию, например как та что написал я. Давайте разберемся что же происходит.<br />
Сразу после добавления строки в таблицу возникает событие  <strong>afterInsertRow</strong> (все события вы можете изучить на странице <a href="http://www.trirand.com/jqgridwiki/doku.php?id=wiki:events">Events</a>), при котором выполняется функция. Функции принимает в качестве параметров (см. описание события) Id строки (row_id) и объект с данными (row_data) текущей строки, вставка которой вызвала событие. Далее смотрим чему равен <strong>country_code</strong> текущей строки.</p>
<ul>
<li>Если <strong>AD</strong> то установить ячейке (setCell) в строке <strong>row_id</strong> с именем  <strong>city</strong> данные <strong>&raquo;</strong> (пусто &#8211; не менять текущие данные) и стиль <strong>color:#FF00FF</strong>. Последнее действие аналогично записи для &laquo;обыкновенной&raquo;  таблицы.</li>
<li>Если <strong>AE</strong> &#8211; аналогично, но цвет текста в ячейке сделать <strong>red</strong>.</li>
<li>Иначе всем остальным ячейкам сделать фон <strong>#999999</strong> и если попадутся строки с <strong>CZ</strong> то выделить такие ячейки жирным шрифтом и присвоить атрибуту <strong>title</strong> текст <strong>&#8216;Чехия Ура!&#8217;</strong>. Атрибуты ячейки можно выставить передав в качестве 5го параметра функции <strong>setCell</strong> объект с именами и значениями этих атрибутов.</li>
</ul>
<p>Как вы понимаете благодаря такому подходу, можно раскрасить таблицу как угодно.<br />
<a title="p2.2" name="p2.2"></a><strong>2) Изменение представления данных</strong><br />
Другим мощным инструментом форматирования данных в jqGrid является набор &laquo;предопределенных форматтеров&raquo; (<a href="http://www.trirand.com/jqgridwiki/doku.php?id=wiki:predefined_formatter">Predefined Formatter</a>). Это функции, которые выполняются над данными в столбце.<br />
Существует 9 стандартных форматтеров</p>
<ul>
<li><strong>integer</strong> &#8211; форматирование целых чисел</li>
<li><strong>number</strong> &#8211; форматирование любых чисел</li>
<li><strong>currency</strong> &#8211; форматирование денежных величин</li>
<li><strong>date</strong> &#8211; форматирование даты/времени</li>
<li><strong>email</strong> &#8211; форматирование адресов эл. почты</li>
<li><strong>link</strong> &#8211; форматирование ссылок</li>
<li><strong>showlink</strong> &#8211; генератор ссылок</li>
<li><strong>checkbox</strong> &#8211; форматирование данных имеющих два состояния</li>
<li><strong>select </strong>- форматирование данных имеющих множество состояний</li>
</ul>
<pre class="brush: jscript;">
$(function(){
    $('#table').jqGrid({
      url:'p2e4.php',
      datatype: 'json',
      mtype: 'GET',
      colNames:['id', 'integer', 'number', 'currency','date','email','link','showlink','checkbox','select','ip'],
      colModel :[
        {name:'id', index:'id', width:15},
        {name:'integer', index:'integer', width:50},
        {name:'number', index:'number', width:50},
        {name:'currency', index:'currency', width:60},
        {name:'date', index:'date', width:65},
        {name:'email', index:'email', width:70},
        {name:'link', index:'link', width:300},
        {name:'showlink', index:'showlink', width:130},
        {name:'checkbox', index:'checkbox', width:35},
        {name:'select', index:'select', width:30},
        {name:'ip', index:'ip', width:50}],
      caption: 'Данные в чистом виде',
      autowidth: true
    });
$('#tableFormated').jqGrid({
      url:'p2e4.php',
      datatype: 'json',
      mtype: 'GET',
      colNames:['id', 'integer', 'number', 'currency','date','email','link','showlink','checkbox','select','ip'],
      colModel :[
        {name:'id', index:'id', width:15},
        {name:'integer', index:'integer', width:50, formatter:'integer', formatoptions:{defaultValue: 'n.a.'}},
        {name:'number', index:'number', width:50, formatter:'number',formatoptions:{decimalPlaces: 3}},
        {name:'currency', index:'currency', width:60, formatter:'currency',formatoptions:{prefix: '$', suffix:'p.'}},
        {name:'date', index:'date', width:65, formatter: 'date',formatoptions:{srcformat:'Y-m-d H:i:s',newformat:'F d'}},
        {name:'email', index:'email', width:70, formatter: 'email'},
        {name:'link', index:'link', width:300, formatter:'link',formatoptions:{target: '_blank'}},
        {name:'title', index:'title', width:130, formatter:'showlink',formatoptions:{baseLinkUrl: 'http://www.linkexchanger.su/forum/',showAction: 'viewtopic.php', addParam: '&amp;amp;f=4', idName:'t',target: '_blank'}},
        {name:'checkbox', index:'checkbox', width:35, formatter:'checkbox',formatoptions:{disabled: true}},
        {name:'select', index:'select', width:30, formatter:'select', editoptions:{value:&amp;quot;:Все; black:Черный; white:Белый; yellow:Желтый; red:Красный&amp;quot;}},
        {name:'ip', index:'ip', width:50, formatter:long2ip}],
      caption: 'Встроенное форматирование',
      autowidth: true
    });
function long2ip (proper_address) {
        var output = false;
if ( !isNaN( proper_address ) &amp;&amp; ( proper_address &gt;= 0 || proper_address &lt;= 4294967295 ) ) {
            output = Math.floor(proper_address / Math.pow( 256, 3 ) ) + '.' +
                Math.floor( ( proper_address % Math.pow( 256, 3 ) ) / Math.pow( 256, 2 ) ) + '.' +
                Math.floor( ( ( proper_address % Math.pow( 256, 3 ) )  % Math.pow( 256, 2 ) ) / Math.pow( 256, 1 ) ) + '.' +
                Math.floor( ( ( ( proper_address % Math.pow( 256, 3 ) ) % Math.pow( 256, 2 ) ) % Math.pow( 256, 1 ) ) / Math.pow( 256, 0 ) );
        }
return output;
    }
});
</pre>
<p>Работающий код данного примера можно увидеть на <a href="http://trahomoto.dlinkddns.com/works/linkexchanger/articles/jqgrid/p2e4.html">ДЕМО2.4</a>. Или если вы хотите скачать его, то вот <a href="http://trahomoto.dlinkddns.com/works/linkexchanger/articles/jqgrid/files/demo2.4.zip">ссылка на архив</a>, внутри клиентский и серверный скрипты, а также дамп БД.<br />
Давайте разберемся как все это работает. Сам пример выглядит как две таблицы и как написано в заголовках, верхняя &#8211; отображает данные с сервера как они есть, а нижняя &#8211; применяет собственные методы форматирования. Как вы уже наверное догадались, в этом примере важен только клиентский код, поэтому серверный скрипт я упростил до минимума, поэтому таблица не сортирует данные в столбцах. Все столбцы кроме последнего названы в соответствии с используемым &laquo;форматтером&raquo;. Все &laquo;форматтеры&raquo; используются одинаково, указывая имя и параметры в colModel таблицы, описания всех параметров доступны на странице <a href="http://www.trirand.com/jqgridwiki/doku.php?id=wiki:predefined_formatter">Predefined Formatter</a> документации плагина.<br />
Теперь подробнее по применению в данном примере.</p>
<ul>
<li><strong>formatter:&#8217;integer&#8217;, formatoptions:{defaultValue: &#8216;n.a.&#8217;}</strong> &#8211; я переназначил значение по-умолчанию, которое будет отображаться в таблице если сервер не вернул никакого значения (пусто).</li>
<li><strong>formatter:&#8217;number&#8217;,formatoptions:{decimalPlaces: 3}</strong> &#8211; для данного типа данных я хочу чтобы после запятой было 3 знака.</li>
<li><strong>formatter:&#8217;currency&#8217;,formatoptions:{prefix: &#8216;$&#8217;, suffix:&#8217;p.&#8217;}</strong> &#8211; для валют нужно ставить вначале $, а в конце р.</li>
<li><strong>formatoptions:{srcformat:&#8217;Y-m-d H:i:s&#8217;,newformat:&#8217;F d&#8217;}</strong> &#8211; для  использования этого &laquo;форматтера&raquo; сначала нужно указать параметру srcformat: маску формата даты в <a href="http://www.php.su/functions/?date">принятом в PHP виде</a>, а затем новый формат newformat:</li>
<li><strong>formatter: &#8216;email&#8217;</strong> &#8211; этот &laquo;форматтер&raquo; не имеет параметров, он всего лишь добавляет mailto: к адресам эл.почты</li>
<li><strong>formatter:&#8217;link&#8217;,formatoptions:{target: &#8216;_blank&#8217;}</strong> &#8211; с помощью &#8216;link&#8217; можно указать target открытия ссылки</li>
<li><strong>formatter:&#8217;showlink&#8217;,formatoptions:{baseLinkUrl: &#8216;http://www.linkexchanger.su/forum/&#8217;, showAction: &#8216;viewtopic.php&#8217;, addParam: &#8216;&amp;f=4&#8242;, idName:&#8217;t', target: &#8216;_blank&#8217;} </strong>- а вот с помощью этого &laquo;форматтера&raquo; можно генерировать ссылки. В нашем примере сервер возвращает название раздела форума linkexchanger в поле <em>showlink</em> в верхней таблице, при этом в нижней таблице вы видите уже готовую ссылку на тему. Это делается указанием следующих параметров:
<ul>
<li><strong>baseLinkUrl:</strong> &#8211; базовая (не изменяющаяся) часть адреса.</li>
<li><strong>showAction:</strong> &#8211; имя скрипта или метода сервера, в нашем примере это скрипт, который показывает тему.</li>
<li><strong>addParam:</strong> &#8211; дополнительные параметры адреса, в нашем случае это идентификатор ветки форума.</li>
<li><strong>idName:</strong> &#8211; какой параметр использовать в качестве имени идентификатора записи, в нашем случае темы форума. А вот сам идентификатор записи (темы на форуме) равен id строки в таблице.</li>
</ul>
</li>
<li><strong>formatter:&#8217;checkbox&#8217;,formatoptions:{disabled: true}</strong> &#8211; удобно использовать при отображении булевых данных (данных которые имеют только два значения), намного нагляднее видеть &laquo;флажок&raquo; вместо 0 или 1 например. При этом &laquo;флажок&raquo; можно сделать активным (formatoptions:{disabled: false}) и использовать при быстром редактировании (об этом в последующих статьях).</li>
<li><strong>formatter:&#8217;select&#8217;, editoptions:{value:&raquo;:Все; black:Черный; white:Белый; yellow:Желтый; red:Красный&raquo;}</strong> &#8211; этот &laquo;форматтер&raquo; очень пригодится при отображении данных, имеющих много значений, но при этом все значения известны. В нашем примере замена названий цветов.</li>
</ul>
<p>На этом Стандартные &laquo;форматтеры&raquo; закончились, а в последнем столбце используется пользовательский. Он представляет из себя функцию <strong>function long2ip (proper_address)</strong> полный <a href="http://www.php.su/functions/?long2ip">аналог PHP&#8217;шной функции</a>, но написанной <a href="http://phpjs.org/functions/index">на и для JS</a>, которая переводит IP из <em>unsignet int</em> в &laquo;человеко-понятный&raquo; вид октетов с точками.<br />
Если возникла необходимость создать сложный пользовательский &laquo;форматтер&raquo; со множеством параметров, то на странице <a href="http://www.trirand.com/jqgridwiki/doku.php?id=wiki:predefined_formatter">Predefined Formatter</a> можно посмотреть пример расширения jqGrid своим &laquo;форматтером&raquo;.<br />
<a title="p3" name="p3"></a><strong>III. Панели инструментов и дополнительные панели</strong><br />
<a title="p3.1" name="p3.1"></a><strong>1) Панель-листалка (Pager)</strong><br />
C этой панелью мы уже знакомы, именно ее мы инициализировали устанавливая свойства <strong>pager:</strong>, <strong>rowNum:</strong>, <strong>rowList:</strong> в предыдущих примерах. В принципе об этой панели рассказывать более нечего, я лишь приведу ссылку на прочие свойства панели <a href="http://www.trirand.com/jqgridwiki/doku.php?id=wiki:pager">Pager</a>, которые возможно понадобятся вам для решения какой-то специфической задачи.<br />
<a title="p3.2" name="p3.2"></a><strong>2) Панель инструментов (Navigator) </strong><br />
Данная панель совсем не является панелью это функция, которая позволяет добавлять элементы управления (кнопки) на панель-листалку. Т.е. если вы хотите использовать pager, то вы обязательно должны его объявить  при инициализации jqGrid хотя бы со стандартными параметрами, без использования <strong>rowNum:</strong>, <strong>rowList:</strong>. После этого уже можно добавлять кнопки, давайте взглянем на <a href="http://trahomoto.dlinkddns.com/works/linkexchanger/articles/jqgrid/p2e5.html">ДЕМО2.5</a>. Добавление кнопок стандартных функций.</p>
<pre class="brush: jscript;">
$(function(){
        var pager = $('#tablePager');
$('#table').jqGrid({
                  url:'p2e1.php',
                  datatype: 'json',
                  mtype: 'GET',
                  colNames:['Код страны','Код региона', 'Город','Долгота','Широта','nbip'],
                  colModel :[
                    {name:'country_code', index:'country_code', width:80},
                    {name:'region_code', index:'region_code', width:80},
                    {name:'city', index:'city', width:90},
                    {name:'latitude', index:'latitude', width:60},
                    {name:'longitude', index:'longitude', width:60},
                    {name:'nbip', index:'nbip', width:30}],
                  pager: pager,
                  sortname: 'city',
                  sortorder: 'asc',
                  caption: 'Pager в качестве панели инструментов',
                  autowidth: true
         }).jqGrid('navGrid', pager);
});
</pre>
<p>Итак друзья мы с вами переступили порог начального уровня использования плагина, с этого момента я буду рассказывать о продвинутых функциях jqGrid.<br />
Как вы уже заметили на листалке появились 6 кнопок, при этом 4 &laquo;практически не работают&raquo;, 1 &#8211; &laquo;практически работает&raquo; и 1 работает, давайте разберемся. Листинг выглядит вполне &laquo;стандартно&raquo;, разве что строка <strong>var pager = $(&#8216;#tablePager&#8217;);</strong> может вызвать легкое недоумение у новичков, но это обычная практика программирования JS, а именно кэширование, об этом написан <a href="http://vl.vg/07.02.2010/cache/">цикл хороших статей</a>, возьмите эту методику на вооружение! Далее вы можете видеть что после инициализации jqGrid я инициализирую панель Navigator используя метод <strong>navGrid</strong>.  Данному методу в качестве первого параметра передается селектор панели листалки, вторым параметром (не указан в листинге) &#8211; объект в котором указывается функции (<em>редактировать, добавить и т.п.</em>) которые необходимо задействовать на панели (например <strong>{view:true, del:false}</strong>), а далее идут объекты с параметрами по каждой из функций в определенном порядке. Давайте я приведу иллюстрацию в виде списка:</p>
<ul>
<li><strong>pagerSelector</strong></li>
<li><strong>{refresh: true(false), add: true(false), del: true(false), edit: true(false), search: true(false), view: true(false)}</strong></li>
<li><strong>{&#8230; параметры редактирования &#8230;}</strong></li>
<li><strong>{&#8230; параметры добавления &#8230;}</strong></li>
<li><strong>{&#8230; параметры удаления &#8230;}</strong></li>
<li><strong>{&#8230; параметры поиска &#8230;}</strong></li>
<li><strong>{&#8230; параметры просмотра &#8230;}</strong></li>
</ul>
<p>Я уверен, что теперь вам стало ясно почему не работают или не совсем работают задействованные функции, потому что они просто не настроены. Т.к. использование этих функций будет рассмотрена в последующих статьях, я не буду продолжать рассмотрение настроек, а перейду к следующему подпункту <em><strong>Добавление пользовательских кнопок</strong></em>.<br />
jqGrid позволяет добавлять на панель pager пользовательские кнопки и назначать на них функции, ниже приведен листинг <a href="http://trahomoto.dlinkddns.com/works/linkexchanger/articles/jqgrid/p2e6.html">ДЕМО2.6</a></p>
<pre class="brush: jscript;">
$(function(){
var pager = $('#tablePager');
$('#table').jqGrid({
              url:'p2e1.php',
              datatype: 'json',
              mtype: 'GET',
              colNames:['Код страны','Код региона', 'Город','Долгота','Широта','nbip'],
              colModel :[
                {name:'country_code', index:'country_code', width:80},
                {name:'region_code', index:'region_code', width:80},
                {name:'city', index:'city', width:90},
                {name:'latitude', index:'latitude', width:60},
                {name:'longitude', index:'longitude', width:60},
                {name:'nbip', index:'nbip', width:30}],
              pager: pager,
              sortname: 'city',
              sortorder: 'asc',
              caption: 'Pager в качестве панели инструментов',
              autowidth: true
     }).jqGrid('navGrid', pager,{add: false, del: false, edit: false, search: false});
$('#table').jqGrid('navSeparatorAdd','#tablePager');
     $('#table').jqGrid('navButtonAdd','#tablePager',{
                                              caption: 'Закрутить ',
                                              title: 'Ключ рожковый, обыкновенный',
                                              buttonicon: 'ui-icon-wrench',
                                              onClickButton: function(){
                                                                 alert('Скрип, скрип, скрип!..');
                                                             },
                                              position:'last'
               }).jqGrid('navButtonAdd','#tablePager',{
                                              caption: 'Замкнуть ',
                                              title: 'Открытый замок',
                                              buttonicon: 'ui-icon-unlocked',
                                              onClickButton: lock,
                                              position:'last'
});
function lock(){
                  alert('Взяли и замкнули что-то...');
              }
});
</pre>
<p>В данном примере после стандартных кнопок, из которых я оставил только &laquo;Обновить&raquo;, вставлен разделитель (separator) и две кнопки &laquo;Закрутить&raquo; и &laquo;Замкнуть&raquo;, простите но оригинальнее я не смог ничего придумать. По нажанию на эту кнопку вызываются функции, которые показывают стандартный alert.<br />
Разделитель добавляется методом <strong>navSeparatorAdd</strong>, первым параметром которого является строка-селектор панели-листалки (pager), а в качестве второго (не указан в листинге) объект с параметрами разделителя.</p>
<blockquote><p>Вот тут следует немного отвлечся и обратить ваше внимание на небольшой ньюанс, возможно разработчики что-то не доделали или не захотели доделать, но при использовании методов <strong>navSeparatorAdd</strong> и <strong>navButtonAdd</strong> в качестве первого параметра должна быть передана именно строка-селектор, но никак не переменная содержащая последний.</p></blockquote>
<p>Параметры разделителя по-умолчанию:<br />
<strong>{sepclass: &#8216;ui-separator&#8217;, sepcontent: &raquo;}</strong><br />
Где</p>
<ul>
<li><strong>sepclass:</strong> &#8211; класс в CSS ui.jqgrid.css, который определяет стиль разделителя. Можно использовать если захотите изменить внешний вид разделителя.</li>
<li><strong>sepcontent:</strong> &#8211; контент, который может быть помещен в разделитель.</li>
</ul>
<p>Кнопка вставляется с помощью метода <strong>navButtonAdd</strong><br />
<strong>{ caption:&#8217;NewButton&#8217;, buttonicon:&#8217;ui-icon-newwin&#8217;, onClickButton:null, position: &#8216;last&#8217;, title:&#8217; &#8216;, cursor: &#8216;pointer&#8217;} </strong><br />
Где</p>
<ul>
<li><strong>caption:</strong> &#8211; надпись на кнопке</li>
<li><strong>title:</strong> &#8211; атрибут кнопки, используется как подсказка</li>
<li><strong>buttonicon:</strong> &#8211; название класса иконки из <a href="http://jqueryui.com/themeroller/">jQuery UI CSS Framework</a></li>
<li><strong>onClickButton:</strong> &#8211; функция, которая будет выполнена при клике на кнопке</li>
<li><strong>position:</strong> (<strong>&#8216;first&#8217;</strong> или <strong>&#8216;last&#8217;</strong>) &#8211; добавить кнопку до или после стандартных кнопок</li>
<li><strong>cursor:</strong> &#8211; CSS свойство, определяющее вид курсора при наведении на элемент</li>
<li><strong>id:</strong> &#8211; с помощью этого свойства можно задать значение атрибуту id контейнеру(TD &#8211; обыкновенная ячейка таблицы) в котором находится кнопка.</li>
</ul>
<p>Однако при всем своем удобстве, у данного подхода к созданию панели инструментов есть ряд недостатков, таких как то что панель находится в нижней части таблицы, мало места для каких-то дополнительных элементов, большого размера и т.п. Для этих целей разработчики добавили еще и возможность создания пользовательских панелей.<br />
<a title="p3.3" name="p3.3"></a><strong>3) Пользовательские панели</strong><br />
Вот <a href="http://trahomoto.dlinkddns.com/works/linkexchanger/articles/jqgrid/p2e7.html">ДЕМО2.7</a> листинги которого приведены ниже.<br />
Клиентская часть</p>
<pre class="brush: jscript;">
$(function(){
       $('#table').jqGrid({
           sortable: true,
                  url:'p2e1.php?userdata=true',
                  datatype: 'json',
                  mtype: 'GET',
                  colNames:['Код страны','Код региона', 'Город','Долгота','Широта','nbip'],
                  colModel :[
                    {name:'country_code', index:'country_code', width:80},
                    {name:'region_code', index:'region_code', width:80},
                    {name:'city', index:'city', width:90},
                    {name:'latitude', index:'latitude', width:60},
                    {name:'longitude', index:'longitude', width:60, resizable: false},
                    {name:'nbip', index:'nbip', width:30}],
                  pager: $('#tablePager'),
          toolbar: [true,'both'],
                  sortname: 'city',
                  sortorder: 'asc',
                  caption: 'Пользовательские панели инструментов',
                  autowidth: true,
                  loadComplete: function() {
                                    var udata = $('#table').jqGrid('getUserData');
                                    $('#tb_table').css('text-align','right').html(udata.msg+' '+udata.sum_regions_numbers+' '+udata.button);
                                }
    });
$(&quot;#t_table&quot;).height(60); //Set height of toolbar
    $(&quot;#t_table&quot;).append('&lt;input id=&quot;say_hello&quot; type=&quot;button&quot; value=&quot;Привет&quot; style=&quot;height:60px; width:80px&quot;&gt;');
    $(&quot;#say_hello&quot;).click(function(){
            alert(&quot;Привет! Спасибо что читаете linkexchanger.su!&quot;);
    });
    $('#show_sum').live('click',function(){
        var val = $(this).val();
        alert('Обратите внимание, с сервера мы получили кнопку с сууммой '+val+', а обработчик назначили уже на странице');
    });
   });
</pre>
<p>И серверная, практически полностью повторяющая пример 2.1</p>
<pre class="brush: php;">
// Начало формирование массива
// для последующего преобразоования
// в JSON объект
$data['page']       = $page;
$data['total']      = $total_pages;
$data['records']    = $count;
// Дополнительная информация с сервера
if($_GET['userdata']){
  $data['userdata']['msg'] = '&lt;span style=&quot;font-weight: normal; color: red;&quot;&gt;Сумма всех чисел в столбце &lt;em&gt;&quot;region_code&quot;&lt;em&gt; равна&lt;/span&gt; ';
  $data['userdata']['sum_regions_numbers'] = '&lt;em&gt;'. $row['sum'].'&lt;em&gt;';
  $data['userdata']['button'] = '&lt;input id=&quot;show_sum&quot; type=&quot;button&quot; value=&quot;'.$row['sum'].'&quot;&gt;';
}
// Строки данных для таблицы
$i = 0;
while($row = mysql_fetch_assoc($result)) {
    $data['rows'][$i]['id'] = $row['id'];
    $data['rows'][$i]['cell'][] = $row['country_code'];
    $data['rows'][$i]['cell'][] = $row['region_code'];
    $data['rows'][$i]['cell'][] = $row['city'];
    $data['rows'][$i]['cell'][] = $row['latitude'];
    $data['rows'][$i]['cell'][] = $row['longitude'];
    $data['rows'][$i]['cell'][] = $row['nbip'];
    $i++;
}
// Перед выводом не забывайте выставить header
// с типом контента и кодировкой
header(&quot;Content-type: text/script;charset=utf-8&quot;);
echo json_encode($data);
</pre>
<p>Ну а теперь по традиции давайте разберем пример подробнее<br />
jqGrig позволяет создавать две независимые панели инструментов. Для этого стоит свойству <strong>toolbar:</strong> присвоить массив <strong>[true,'both']</strong>, элементы которго в данном случае означают, что нужно создать обе(верхнюю и нижнюю) панели инструментов. Вместо <strong>&#8216;both&#8217;</strong> также можно указать <strong>&#8216;top&#8217;</strong> или <strong>&#8216;bottom&#8217;</strong> для верхней и нижней панелей соответственно.<br />
Теперь давайте рассмотрим первый вариант манипуляции с элементами на панелях, начнем с верхней панели. При инициализации плагина с определенным свойством <strong>toolbar:</strong> jqGrid автоматически выставит атрибут  <strong>id</strong> верхней панели как <strong>id=&raquo;t_&raquo;</strong>(<em><strong>&laquo;t_table&raquo;</strong></em> в нашем случае), а нижнюю  <strong>id=&raquo;tb_&raquo;</strong> (<em><strong>&laquo;tb_table&raquo;</strong></em> в нашем случае). С помощью этих идентификаторов можно отыскать &laquo;тулбары&raquo; в DOM и выполнить например такие манипуляции</p>
<pre class="brush: jscript;">
$(&quot;#t_table&quot;).height(60);
$(&quot;#t_table&quot;).append('&lt;input id=&quot;say_hello&quot; type=&quot;button&quot; value=&quot;Привет&quot; style=&quot;height:60px; width:80px&quot;&gt;');
...
$(&quot;#say_hello&quot;).click(function(){
            alert(&quot;Привет! Спасибо что читаете linkexchanger.su!&quot;);
});
</pre>
<p>Первая строка сделает высоту верхней панели равной 60px, а вторая поместит на нее кнопку, код которой вы видите. После этого определяется функция-обработчик которая выполнится при щелчке по добавленной кнопке. Думаю такая методика использования не вызовет затруднений.<br />
А вот второй, альтернативный вариант манипуляций с элементами на панелях, иллюстрируется на примере  нижней панели. Это следующие строки кода</p>
<pre class="brush: jscript;">
...
loadComplete: function() {
                                    var udata = $('#table').jqGrid('getUserData');
                                    $('#tb_table').css('text-align','right').html(udata.msg+' '+udata.sum_regions_numbers+' '+udata.button);
                                }
...
 $('#show_sum').live('click',function(){
        var val = $(this).val();
        alert('Обратите внимание, с сервера мы получили кнопку с суммой '+val+', а обработчик назначили уже на странице');
    });
...
</pre>
<p>Работает это следующим образом. После окончания загрузки данных возникает событие <strong><em>loadComplete:</em></strong> и вызывается функция. Эта функция  (<strong>var udata = $(&#8216;#table&#8217;).jqGrid(&#8216;getUserData&#8217;); </strong>) получает пользовательские данные из ответа сервера, об этом немного ниже, в виде JSON объекта в данном случае и выводит эти данные на нижнюю панель (<strong>$(&#8216;#tb_table&#8217;)</strong>) в виде HTML выравнивая по правому краю (<strong>css(&#8216;text-align&#8217;,'right&#8217;)</strong>). После чего выполняется объявление обработчика используя метод <strong>live</strong>.<br />
Ну откуда же берутся эти пользовательские данные? С сервера как и все остальные! Вот например как сделал я</p>
<pre class="brush: php;">
$userdata = $_GET['userdata'];
// Выполним запрос, который вернет суммарное кол-во записей в таблице
$result = mysql_query(&quot;SELECT COUNT(*)AS count, SUM(region_code) AS sum FROM cities&quot;);
if($userdata){
            $data['userdata']['msg'] = '&lt;span style=&quot;font-weight: normal; color: red;&quot;&gt;Сумма всех чисел в столбце &lt;em&gt;&quot;region_code&quot;&lt;em&gt; равна&lt;/span&gt; ';
            $data['userdata']['sum_regions_numbers'] = '&lt;em&gt;'. $row['sum'].'&lt;em&gt;';
            $data['userdata']['button'] = '&lt;input id=&quot;show_sum&quot; type=&quot;button&quot; value=&quot;'.$row['sum'].'&quot;&gt;';
        }
// Строки данных для таблицы
        $i = 0;
        while($row = mysql_fetch_assoc($result)) {
            $data['rows'][$i]['id'] = $row[id];
            $data['rows'][$i]['cell'][] = $row[country_code];
            }
            echo json_encode($data);
</pre>
<p>Итак я запрашиваю серверный скрипт (<strong>url:&#8217;p2e1.php?userdata=true&#8217;</strong>), который выполняет запрос. После выполнения запроса, вместе с суммарным кол-вом записей получаем сумму всех значений полей  <em><strong>region_code</strong></em>. Далее полученные данные помещаем в массив  <strong>$data</strong> и кодируем в формат JSON.<br />
<a title="p4" name="p4"></a><strong>IV. Управление столбцами данных</strong><br />
<a title="p4.1" name="p4.1"></a><strong>1) Изменение размера и положения столбцов</strong><br />
На самом деле никаких манипуляций для реализации этих возможностей таблицы делать не придется. Возможно вы заметили что в листинге предыдущего примера есть не рассмотренное свойство <strong>sortable: true</strong> и если схватить за заголовок любого из столбцов, то можно drag&#8217;n'drop&#8217;ом переместить его на место другого столбца.  Определение этого свойства как <strong>true</strong> как раз и включает возможность перетаскивать столбцы. Но перед использованием этой опции плагина убедитесь:</p>
<ul>
<li>Что вы послушали мой совет в первой части и при скачивании архива с прагином в <a href="http://www.trirand.com/blog/?page_id=6">Download Builder</a> вы выставили все галки в том числе <strong>jQuiery UI addons</strong>.</li>
<li>Что вы подключили к странице <a href="http://jqueryui.com/demos/">jQueryUI</a>,а именно виджет <a href="http://jqueryui.com/demos/sortable/">sortable</a>.</li>
</ul>
<p>При этом можно изменять ширину любых столбцов, в <em><strong>colModel</strong></em>-опциях которых не определено свойство <strong>resizable: false</strong> как столбец &laquo;Широта&raquo; в <a href="http://trahomoto.dlinkddns.com/works/linkexchanger/articles/jqgrid/p2e7.html">ДЕМО2.7</a>, при условии что вы скачали jqGrid с опцией <strong>jQuiery UI addons</strong>.<br />
<a title="p4.2" name="p4.2"></a><strong>2) Скрываем не нужные или отображаем нужные столбцы данных</strong><br />
Начнем обсуждение с <a href="http://trahomoto.dlinkddns.com/works/linkexchanger/articles/jqgrid/p2e8.html">ДЕМО2.8</a>.</p>
<pre class="brush: jscript;">
&lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; media=&quot;screen&quot; href=&quot;../../../_library/css/ui.multiselect.css&quot; /&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;../../../_library/js/ui.multiselect.js&quot;&gt;&lt;/script&gt;
    &lt;script type=&quot;text/javascript&quot;&gt;
$(function(){
      var table = $('#table');
      table.jqGrid({
                  url:'p2e1.php',
                  datatype: 'json',
                  mtype: 'GET',
                  colNames:['Код страны','Код региона', 'Город','Долгота','Широта','nbip'],
                  colModel :[
                    {name:'country_code', index:'country_code', width:80, hidden: true},
                    {name:'region_code', index:'region_code', width:80, hidden: true},
                    {name:'city', index:'city', width:90},
                    {name:'latitude', index:'latitude', width:60},
                    {name:'longitude', index:'longitude', width:60},
                    {name:'nbip', index:'nbip', width:30, hidden: true}],
                  pager: $('#tablePager'),
                  toolbar: [true,&quot;top&quot;],
                  sortname: 'city',
                  sortorder: 'asc',
                  caption: 'Управление видимостью столбцов',
                  width: 400
        });

    var tBar = $(&quot;#t_table&quot;);
    tBar.append('&lt;input id=&quot;c_chooser1&quot; type=&quot;button&quot; value=&quot;Базовый мастер&quot;&gt;');
    tBar.append('&lt;input id=&quot;c_chooser2&quot; type=&quot;button&quot; value=&quot;Сторонний мастер&quot;&gt;');

    $(&quot;#c_chooser1&quot;).click(function(){
        table.jqGrid('setColumns',{
                                   colnameview:false,
                                   updateAfterCheck: true
                                  });
    });

    $(&quot;#c_chooser2&quot;).click(function(){
        table.jqGrid('columnChooser');
    });

});
&lt;/script&gt;
</pre>
<p>Первое что бросается в глаза так это то, что не все столбцы показаны, хотя все объявлены. Эта опция будет полезна если у вас имеется очень много колонок, при этом обычно не все они нужны, но могут понадобится при более детальном рассмотрении каких-то строк. Сделать столбец не видимым при инициализации таблицы можно указав в <strong>colModel</strong> колонки свойство  <strong>hidden: true</strong>. Но спрятанные колонки нужно как-то показывать при необходимости. Для таких целей можно воспользоваться 2 способами.</p>
<ul>
<li>Использовать метод  <a href="http://www.trirand.com/jqgridwiki/doku.php?id=wiki:show_hide_columns">setColumns</a>, я предпочитаю этот метод ввиду его простоты, не часто нужно управлять столбцами, но если нужно то этот метод самое оно.</li>
<li>Использовать метод-плагин <a href="http://www.trirand.com/jqgridwiki/doku.php?id=wiki:jquery_ui_methods">columnChooser</a> &#8211; этот подходя для истинных гурманов эстетов, очень эффектен если подключить соответствующие файлы. Для начала скачиваем плагин <a href="http://michael.github.com/multiselect/index.html">UI.MultiSelect</a> и подключаем файлы <strong>ui.multiselect.css</strong> и <strong>ui.multiselect.js</strong> как в демо. И снова напомню что для этого метода jqGrid должна быть с модулями  <strong>jQuiery UI addons</strong>.</li>
</ul>
<p><strong>Послесловие</strong><br />
В данной статье мы рассмотрели очень много вспомогательных возможностей плагина-таблицы jqGrid, при этом мы пересекли черту &laquo;начального использования&raquo; таблицы, от всей души поздравляю! Мы хорошо потрудились и дальше нас ждет еще больше интересного, а именно:</p>
<ul>
<li><strong>jqGrid и &laquo;деревья&raquo;</strong>
<ul>
<li>jqGrid и MySQL деревья</li>
<li>jqGrid и статические деревья</li>
</ul>
</li>
<li><strong>Связывание данных в jqGrid</strong>
<ul>
<li>Простая подтаблица (subgrid)</li>
<li>jqGrid как subgrid</li>
<li>Ведущая и ведомая jqGrid</li>
<li>Перемещение строк данных между таблицами</li>
</ul>
</li>
<li><strong>&#8230;</strong></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.linkexchanger.su/2010/486.html/feed</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
		<item>
		<title>jqGrid Часть I: Знакомство</title>
		<link>http://www.linkexchanger.su/2010/118.html</link>
		<comments>http://www.linkexchanger.su/2010/118.html#comments</comments>
		<pubDate>Mon, 25 Jan 2010 18:54:10 +0000</pubDate>
		<dc:creator>TRAHOMOTO</dc:creator>
				<category><![CDATA[jQuery]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[jqGrid]]></category>

		<guid isPermaLink="false">http://www.linkexchanger.su/2010/118.html</guid>
		<description><![CDATA[- Не робейте -, сказала Черная Королева, &#8211; это всего-навсего баранья нога, ни больше ни меньше.
Она вам понравится, уверяю вас.
Познакомьтесь. Алиса, это Баранья Нога.
Баранья Нога, это Алиса.
Предисловие
Весь цикл статей направлен в первую очередь на начинающих разработчиков, которые постигают все прелести jQuery. Которые имеют базовые знания и понимания работы с этой библиотекой. Для разработчиков, которые впервые [...]]]></description>
			<content:encoded><![CDATA[<p><span style="font-family: Georgia,'Times New Roman',Times,serif">- Не робейте -, сказала Черная Королева, &#8211; это всего-навсего баранья нога, ни больше ни меньше.<br />
Она вам понравится, уверяю вас.<br />
Познакомьтесь. Алиса, это Баранья Нога.<br />
Баранья Нога, это Алиса.</span></p>
<p><strong>Предисловие</strong></p>
<p>Весь цикл статей направлен в первую очередь на начинающих разработчиков, которые постигают все прелести jQuery. Которые имеют базовые знания и понимания работы с этой библиотекой. Для разработчиков, которые впервые слышат слово jQuery я бы посоветовал цикл видео уроков Евгений Попова (<a href="http://www.evgeniypopov.com/magazine.php?mag=45">Уроки 1-4</a> и <a href="http://www.evgeniypopov.com/magazine.php?mag=46">Уроки 5-6</a>) или книгу Геннадия Самкова<a href="http://www.linkexchanger.su/2010/115.html"> jQuery. Сборник рецептов</a>.</p>
<p>Во всех статьях, я постараюсь максимально подробно охватить материал, чтобы исключить появление примитивных вопросов.<span id="more-118"></span> Также хочется сразу предупредить, я не буду учить вас программированию на PHP, этот материал как и весь ресурс посвящен в первую очередь jQuery и технологиям AJAX. Поэтому пожалйста не задавайте вопросы &laquo;как мне защититься от хакеров?&raquo;, &laquo;как мне сделать авторизацию?&raquo; и т.п., на эту тему вы всегда сможете найти массу материала на дружественных сайтах.</p>
<p><strong>Введение</strong></p>
<p>Любой набор данных можно представить в виде двумерного массива &#8211; таблицы. Я считаю таблицу одним из фундаментальных элементов представления информации. Благодаря такой структуре организации человек может увидеть, оценить и легко манипулировать данными в такой форме.</p>
<p>В данном цикле статей я постараюсь познакомить вас и вместе с вами сам постигнуть все прелести замечательнейшего плагина для jQuery &#8211; jqGrid. Чтобы дать вам почувствовать этого &laquo;монстра&raquo;, да-да именно &laquo;монстра&raquo;, я приведу ссылку на <a href="http://trirand.com/blog/jqgrid/jqgrid.html">демо-галерею</a> сайта разработчика. Рекомендую посмотреть все примеры работы с таблицей.</p>
<p>Лично я, когда увидел &laquo;это&raquo; был шокирован и решил разобрать этот плагин. Но сразу же был разочарован, он не заработал! А перепроверив все еще раз я понял, что проблема не в плагине, а во мне. Вот еще одна причина, по которой я сел за этот цикл. Далее меня настигло еще одно разочарование, скрипт вызывал ошибку в IE и отказывался работать. Это было связанно с багом в коде плагина, которую устранили к версии 3.6.1 (На момент написания статьи, последняя версия была 3.6.2). Таким образом я &laquo;вляпался&raquo; в этот плагин. Уверен вы устали от моей пустой болтовни и следует перейти к делу.</p>
<p><strong>I. Подготовка к установке</strong></p>
<p>Перед началом любых работ нам необходимо заготовить &laquo;инструменты&raquo; и &laquo;материалы&raquo;.<br />
<strong>Инструменты (которые использую я)</strong></p>
<ul>
<li>Apache/2.2.9</li>
<li>PHP/5.2.6</li>
<li>MySQL-server/5.0.51a-24</li>
</ul>
<p>Вобщем все стандартные пакеты в репозитории Debian. Если вы предпочитаете Windows, то я могу посоветовать вам <a href="http://www.denwer.ru/">Denwer</a><br />
<strong>Материалы</strong></p>
<ul>
<li>jQuery &#8211; скачать с <a href="http://jquery.com/">официального сайта</a> или подключить по ссылке Google http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js</li>
<li>jQueryUI CSS Framework (проще говоря тема для jQueryUI) &#8211; выбирайте и скачивате на <a href="http://jqueryui.com/themeroller/">официальном сайте</a></li>
<li>jqGrid Plugin &#8211; скачивайте с <a href="http://www.trirand.com/blog/?page_id=6">официального сайта</a>. <strong><em>ВАЖНО!</em></strong> Выберите все модули, т.к. мы пока разбираемся и будем тестировать все возможности jqGrid! В дальнейшей работе, вы можете выбирать только те модули которые вам необходимы.</li>
</ul>
<p><strong>II. Документ, в котором будет использоваться jqGrid</strong><br />
<em>Аннотация:</em></p>
<ul>
<li>Весь материал, который начинается с этого момента я буду осваивать заново, поэтому все ответы на вопросы я буду искать вмести с вами.</li>
<li>Мы будем работать с кириллицей в кодировке UTF-8. Но я дам некоторые рекомендации при использовании плагина с кодировкой Windows-1251(CP1251) .</li>
</ul>
<p><strong>1) Html &#8211; разметка</strong><br />
Итак создадим документ с разметкой следующего вида:</p>
<pre class="brush: xml;">&lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD XHTML 1.0 Strict//EN&quot;&quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd&quot;&gt;
&lt;html xmlns=&quot;http://www.w3.org/1999/xhtml&quot; xml:lang=&quot;en&quot; lang=&quot;en&quot;&gt;
&lt;head&gt;
&lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=utf-8&quot; /&gt;
&lt;title&gt;Осваиваем jqGrid с Linkexchanger&lt;/title&gt;&lt;/head&gt;
&lt;body&gt;
&lt;table id=&quot;le_table&quot;&gt;&lt;/table&gt;
&lt;div id=&quot;le_tablePager&quot;&gt;&lt;/div&gt;
&lt;/body&gt;
&lt;/html&gt;</pre>
<p>Как видите самый незаурядный код чистой страницы, где <em>&lt;table id=&raquo;le_table&raquo;&gt;&lt;/table&gt;</em> это и есть таблица которую вы видели на демо, а <em>&lt;div id=&raquo;le_tablePager&raquo;&gt;&lt;/div&gt;</em> &#8211; это элемент таблицы, &laquo;статус бар&raquo; (status bar), о нем поговорим позже. Здесь следует сказать, что в качестве селектора таблицы лучше использовать именно атрибут ID, почему? Ответ на этот вопрос будет дан по мере изучения плагина.</p>
<p><strong>2) Html + CSS + JS</strong><br />
Далее переходим к подключаем необходимые стили и скрипты. Для начала создадим на сервере, в рабочем каталоге следующую структуру.</p>
<ul>
<li><strong>css/</strong> &#8211; в этом каталоге будут все *.css файлы и прочие файлы относящиеся к визуальному оформлению страницы.</li>
<li><strong>js/</strong> &#8211; в этом каталоге будут все *.js файлы</li>
</ul>
<p>Теперь по каждому каталогу подробнее:</p>
<ul>
<li> <strong>css</strong> &#8211; в него следует положить
<ol> <em><strong> &laquo;jqueryUI Theme&raquo;</strong></em> &#8211; каталог с темой оформления jQueryUI (например flick)</ol>
<ol> <strong><em> ui.jqgrid.css</em></strong> &#8211; дополнительные стили jqGrid (находятся в скачанном в п.I архиве css/ui.jqgrid.css)</ol>
</li>
<li> <strong>js</strong> &#8211; в него следует положить
<ol><strong><em>jQuery</em> </strong>- библиотеку</ol>
<ol><strong><em>Каталог i18n</em></strong> &#8211; это каталог с локализациями плагина, проще говоря с &laquo;языками&raquo; (находятся в скачанном в п.I архиве js/i18n) . На этом этапе я остановлюсь подробнее, потому что тут дам обещанный совет по использованию плагина с кирилице кодировки CP1251. Если вы планируете использовать плагин в таких условиях, то вам необходимо в каталоге i18n найти и переконвертировать кодировку файла grid.locale-ru.js из UTF-8 в CP1251. Рассказ о том как это сделать выходит за рамки данной статьи. Также вы можете не загружать все языки, а выбрать только тот, который вам необходим.</ol>
<ol><em><strong>jquery.jqGrid.min.js</strong></em> &#8211; собственно сам плагин.</ol>
</li>
</ul>
<p>Теперь следует перепроверить всю структуру каталога еще раз. Именно на этом этапе я допустил первую ошибку, упоминавшуюся во введении.</p>
<ul>
<li><strong>/css/</strong>
<ul>
<li>flick/
<ul>
<li>images/</li>
<li>&#8230;</li>
<li>jquery-ui-1.7.2.custom.css</li>
</ul>
</li>
<li>ui.jqgrid.css</li>
</ul>
</li>
<li><strong>/js/</strong>
<ul>
<li>i18n/
<ul>
<li>grid.locale-ru.js</li>
<li>&#8230;</li>
</ul>
</li>
<li>jquery-1.4.min.js</li>
<li>jquery.jqGrid.min.js</li>
</ul>
</li>
</ul>
<p>Далее необходимо подключить всю эту кухню</p>
<pre class="brush: xml;">&lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD XHTML 1.0 Strict//EN&quot;
&quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd&quot;&gt;
&lt;html xmlns=&quot;http://www.w3.org/1999/xhtml&quot; xml:lang=&quot;en&quot; lang=&quot;en&quot;&gt;&lt;head&gt;
&lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html;
charset=utf-8&quot; /&gt;
&lt;title&gt;Осваиваем jqGrid с Linkexchanger&lt;/title&gt;
&lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; media=&quot;screen&quot; href=&quot;css/flick/jquery-ui-1.7.2.custom.css&quot; /&gt;
&lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; media=&quot;screen&quot; href=&quot;css/ui.jqgrid.css&quot; mce_href=&quot;css/ui.jqgrid.css&quot; /&gt;
&lt;style&gt;html, body {
    margin: 0;
    padding: 0;
    font-size: 80%;
}
&lt;/style&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;js/jquery-1.4.min.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;js/i18n/grid.locale-ru.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;js/jquery.jqgrid.min.js&quot;&gt;&lt;/script&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;table id=&quot;le_table&quot;&gt;&lt;/table&gt;
&lt;div id=&quot;le_tablePager&quot;&gt;&lt;/div&gt;
&lt;/body&gt;
&lt;/html&gt;</pre>
<p>Как видите в разметке есть еще дополнительный стиль. Этот стиль задает базовые параметры для отступов и самое главное размер шрифта! Если этого не сделать, то при использовании jQueryUI CSS Framework размер шрифта будет &laquo;не маленьким&raquo; и при этом различным в различных браузерах.</p>
<p><strong>3) MySQL</strong><br />
Как бы мы не хотели, но в данной статье мы никак не сможем обойтись без базы данных. Поэтому я подготовил для вас дамп. Вы можете скачать его по <a title="Дамп MySQL (jqGrid)" href="http://www.linkexchanger.su/wp-content/uploads/2010/01/mysqldump.zip">этой ссылке</a> или <a href="http://trahomoto.dlinkddns.com/works/linkexchanger/articles/jqgrid/files/mysqldump.zip">с моего домашнего сервера</a> и экспортировать в любую БД (MySQL) например используя phpMyAdmin, у данного дампа есть один ньюанс. Аименно у некоторых названий городов &laquo;искаверкана&raquo; кодировка, т.е. проблема в дампе, но никак не в плагине!<br />
В дампе сохранены 10тыс городов с кодами страны, региона, названием на англ., долготой, широтой, и nbit. Фактически это кусок одной таблицы БД распределения IP адресов в интернете. В принципе нам абсолютно не важно, что это будет за БД и для опытов подойдет и такая.</p>
<p><strong>4) PHP</strong><br />
На данном этапе следует создать PHP скрипт, который будет возвращать таблице, запрашиваемую ею информацию. Вот пример такого скрипта для наших нужд</p>
<pre class="brush: php;">&lt;?php
// Подключение и выбор БД
$db = mysql_connect('database_host', 'database_user',
'database_password');
mysql_select_db('database_name');
# ВНИМАНИЕ!!!
# Данный код не имеет проверок запрашиваемых данных
# что может стать причиной взлома!
# Обязательно проверяйте все данные
# поступающие от клиента

// Номер запришиваемой страницы
$page = $_GET['page'];

// Количество запрашиваемых записей
$limit = $_GET['rows'];

// Номер элемента массива по которому
// следует производить сортировку
// Проще говоря поле, по которому
// следует производить сортировку 
$sidx = $_GET['sidx'];                 

// Направление сортировки
$sord = $_GET['sord'];                         

// Если не указано поле сортировки,
// то производить сортировку по первому полю
if(!$sidx) $sidx =1;                 

// Выполним запрос, который
// вернет суммарное кол-во записей в таблице
$result = mysql_query(&quot;SELECT COUNT(*) AS count FROM cities&quot;);
$row = mysql_fetch_array($result,MYSQL_ASSOC);
 // Теперь эта переменная хранит кол-во записей в таблице
$count = $row['count'];                   

// Рассчитаем сколько всего страниц займут данные в БД
if( $count &gt; 0 &amp;&amp; $limit &gt; 0) {
    $total_pages = ceil($count/$limit);
} else {
    $total_pages = 0;
}                   

// Если по каким-то причинам клиент запросил
if ($page &gt; $total_pages) $page=$total_pages;                   

// Рассчитываем стартовое значение для LIMIT запроса
$start = $limit*$page - $limit;                   

// Зашита от отрицательного значения
if($start &lt; 0) $start = 0;                   

// Запрос выборки данных
$query = &quot;SELECT id, country_code, region_code, city, latitude,
longitude, nbip FROM cities
ORDER BY &quot;.$sidx.&quot; &quot;.$sord.&quot; LIMIT &quot;.$start.&quot;, &quot;.$limit;
$result = mysql_query($query);                   

// Начало xml разметки
$s = &quot;&lt;?xml version='1.0' encoding='utf-8'?&gt;&quot;;
$s .=  &quot;&lt;rows&gt;&quot;;
$s .= &quot;&lt;page&gt;&quot;.$page.&quot;&lt;/page&gt;&quot;;
$s .= &quot;&lt;total&gt;&quot;.$total_pages.&quot;&lt;/total&gt;&quot;;
$s .= &quot;&lt;records&gt;&quot;.$count.&quot;&lt;/records&gt;&quot;;                   

// Строки данных для таблицы
// Не забудьте обернуть
//текстовые данные в &lt;![CDATA[]]&gt;                   

while($row = mysql_fetch_assoc($result)) {
  $s .= &quot;&lt;row id='&quot;. $row[id].&quot;'&gt;&quot;;
  $s .= &quot;&lt;cell&gt;&lt;![CDATA[&quot;. $row[country_code].&quot;]]&gt;&lt;/cell&gt;&quot;;
  $s .= &quot;&lt;cell&gt;&quot;. $row[region_code].&quot;&lt;/cell&gt;&quot;;
  $s .= &quot;&lt;cell&gt;&lt;![CDATA[&quot;. $row[city].&quot;]]&gt;&lt;/cell&gt;&quot;;
  $s .= &quot;&lt;cell&gt;&quot;. $row[latitude].&quot;&lt;/cell&gt;&quot;;
  $s .= &quot;&lt;cell&gt;&quot;. $row[longitude].&quot;&lt;/cell&gt;&quot;;
  $s .= &quot;&lt;cell&gt;&quot;. $row[nbip].&quot;&lt;/cell&gt;&quot;;
  $s .= &quot;&lt;/row&gt;&quot;;
}
$s .= &quot;&lt;/rows&gt;&quot;;                   

// Перед выводом не забывайте выставить header
// с типом контента и кодировкой
header(&quot;Content-type: text/xml;charset=utf-8&quot;);                 

echo $s;
?&gt;</pre>
<p><strong>5) Инициализация плагина</strong><br />
Последний этап подготовительных работ. Здесь мы должны инициализировать плагин JqGrid. Делается это вызовом метода jqGrid(), который в качестве параметра, принимает объект со свойствами таблицы.<br />
Теперь давайте посмотрим на примере разметки, приведенной выше.</p>
<pre class="brush: xml;">&lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD XHTML 1.0 Strict//EN&quot; &quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd&quot;&gt;
&lt;html xmlns=&quot;http://www.w3.org/1999/xhtml&quot; xml:lang=&quot;en&quot; lang=&quot;en&quot;&gt;&lt;head&gt;
&lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=utf-8&quot; /&gt;
&lt;title&gt;Осваиваем jqGrid с Linkexchanger&lt;/title&gt;
&lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; media=&quot;screen&quot; href=&quot;css/flick/jquery-ui-1.7.2.custom.css&quot; /&gt;
&lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; media=&quot;screen&quot; href=&quot;css/ui.jqgrid.css&quot; mce_href=&quot;css/ui.jqgrid.css&quot; /&gt;
&lt;style&gt;html, body {
    margin: 0;
    padding: 0;
    font-size: 80%;
}
&lt;/style&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;js/jquery-1.4.min.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;js/i18n/grid.locale-ru.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;js/jquery.jqgrid.min.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
$(function(){           

$('#le_table').jqGrid({
   url:'p1e1.php',
   datatype: 'xml',
   mtype: 'GET',
   colNames:['Код страны','Код региона', 'Город','Долгота','Широта','nbip'],
   colModel :[
     {name:'country_code', index:'country_code', width:80},
     {name:'region_code', index:'region_code', width:80},
     {name:'city', index:'city', width:90},
     {name:'latitude', index:'latitude', width:60},
     {name:'longitude', index:'longitude', width:60},
     {name:'nbip', index:'nbip', width:30}],
  pager: $('#le_tablePager'),
  rowNum:10,
  rowList:[10,20,30,100],
  sortname: 'city',
  sortorder: 'asc'
});           

});
&lt;/script&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;table id=&quot;le_table&gt;&lt;/table&gt;
&lt;div id=&quot;le_tablePager&quot;&gt;&lt;/div&gt;
&lt;/body&gt;
&lt;/html&gt;</pre>
<p>Cейчас можно взглянуть результаты наших трудов. Вот ссылка на просмотр <a href="http://trahomoto.dlinkddns.com/works/linkexchanger/articles/jqgrid/p1e1.html">ДЕМО1</a> и на архив с <a title="ДЕМО1 jqGrid" href="http://www.linkexchanger.su/wp-content/uploads/2010/01/demo1.zip">ДЕМО1</a> (<a href="http://trahomoto.dlinkddns.com/works/linkexchanger/articles/jqgrid/files/demo1.zip">тот же архив на зеркале</a>)</p>
<p><strong>III. Разбор параметров</strong><br />
Остался последний пункт сегодняшней статьи в котором я дам пояснения по каждому из используемых в данном примере свойств плагина.</p>
<ul>
<li><strong>url</strong> &#8211; этот параметр указывает URL на скрипт</li>
<li><strong>datatype</strong> &#8211; тип возвращаемых сервером данных. В данном примере, плагин ожидает данные с сервера в виде XML. Забегая наперед скажу что в следующей статье мы рассмотрим ответ сервера в виде JSON и Offline варианты использования плагина.</li>
<li><strong>mtype</strong> &#8211; определяет каким методом будут переданы данные серверу</li>
<li><strong>colNames</strong> &#8211; массив с заголовками столбцов таблицы</li>
<li><strong>colModel</strong> &#8211; параметр-массив, каждый элемент которого является объектом свойств столбца с данными
<ul>
<li><strong>name</strong> &#8211; &laquo;имя колонки&raquo;, используется внутренними механизмами jqGrid</li>
<li><strong>index</strong> &#8211; &laquo;имя колонки&raquo;, передается серверу при запросах данных</li>
<li><strong>width</strong> &#8211; ширина столбца в пикселах</li>
</ul>
</li>
<li><strong>pager</strong> &#8211; определяет элемент, который будет преобразован в &laquo;панель-листалку&raquo;. Может быть как строкой (<em>&#8216;#le_tablePager&#8217;</em>) так и объектом jQuery (<em>$(&#8216;#le_tablePager&#8217;)</em>). При этом сами разработчики рекомендуют присваивать этому параметру как раз объект jQuery.</li>
<li><strong>rowNum</strong> &#8211; определяет количество записей запрашиваемых у сервера и отображаемых за &laquo;один раз&raquo; (я написал именно так, потому что jqGrid может динамически подгружать строки с данными, что будет рассмотрено в последующих статьях) по умолчанию.</li>
<li><strong>rowList </strong>- параметр-массив. На основе этого параметра строится выпадающий список, позволяющий изменять кол-во записей выводимых за &laquo;один раз&raquo;</li>
<li><strong>sortname</strong> &#8211; определяет index(столбец) по которому будут отсортированы записи</li>
<li><strong>sortorder</strong> &#8211; определяет направление сортировки. asc &#8211; по возрастанию, desc &#8211; по убыванию.</li>
</ul>
<p>Говоря о параметрах (options) следует сказать, что это лишь крохотная их часть. Эти параметры обеспечивают только базовую функциональность таблице. Множество других параметров мы с вами рассмотрим в последующих статьях, а пока поэкспериментируйте с теми что использованы в этом примере.</p>
<p><strong>IV. Содержание следующей статьи</strong></p>
<ul>
<li>Другие способы загрузки данных
<ul>
<li>В виде JSON объекта</li>
<li>В виде массива</li>
<li>Конвертирование простой таблицы в jqGrid</li>
</ul>
</li>
<li>Форматирование данных
<ul>
<li>Встроенные функции форматирования</li>
<li>Пользовательские функции форматирования</li>
</ul>
</li>
<li>Дополнительные панели и панели инструментов
<ul>
<li>Панель-листалка</li>
<li>Панели инструментов</li>
<li>Пользовательская панель</li>
<li>Управление столбцами данных</li>
</ul>
</li>
</ul>
<p><strong>Выводы</strong><br />
В данной статье мы познакомились с плагином jqGrid, запустили его в базовой функциональности и создали полигон для будущих примеров.</p>
<p>В ходе работы мы поняли принцип работы плагина. Фактически сам плагин это интерфейс пользователя, который отправляет AJAX запросы серверу и получает от него ответ. Таблица отправляет все необходимые параметры, для выборки данных на стороне сервера,  в виде GET запроса, а сервер возвращает в виде набора строк в XML-разметке.</p>
<p>Пожалуйста оставляйте только конструктивные комментария и пожелания, а все вопросы задавайте на форуме!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.linkexchanger.su/2010/118.html/feed</wfw:commentRss>
		<slash:comments>32</slash:comments>
		</item>
		<item>
		<title>JavaScript мастер-классы</title>
		<link>http://www.linkexchanger.su/2010/117.html</link>
		<comments>http://www.linkexchanger.su/2010/117.html#comments</comments>
		<pubDate>Mon, 25 Jan 2010 06:34:55 +0000</pubDate>
		<dc:creator>Gennady</dc:creator>
				<category><![CDATA[jQuery]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[ajax]]></category>
		<category><![CDATA[comet]]></category>

		<guid isPermaLink="false">http://www.linkexchanger.su/2010/117.html</guid>
		<description><![CDATA[Недавно узнал, что 20-21 февраля в Москве и 27-28 февраля в Санкт-Петербурге пройдут мастер-классы по Javascript, которые будет вести Илья Кантор &#8211; создатель  сайтов algolist.manual.ru и javascript.ru.
Это  мой уважаемый коллега, человек с большим опытом разработки сложных  приложений, в прошлом один из разработчиков javascript-фреймворка Dojo Toolkit.
» Профессиональное javascript-программирование
»  Сложный AJAX и COMET: [...]]]></description>
			<content:encoded><![CDATA[<p>Недавно узнал, что 20-21 февраля в Москве и 27-28 февраля в Санкт-Петербурге пройдут мастер-классы по Javascript, которые будет вести Илья Кантор &#8211; создатель  сайтов <a href="http://algolist.manual.ru">algolist.manual.ru</a> и <a href="http://javascript.ru">javascript.ru</a>.</p>
<p>Это  мой уважаемый коллега, человек с большим опытом разработки сложных  приложений, в прошлом один из разработчиков javascript-фреймворка <a href="http://dojotoolkit.org/">Dojo Toolkit</a>.</p>
<p>» Профессиональное javascript-программирование<br />
»  Сложный AJAX и COMET: тонкости Web 2.0<br />
» Мастер-класс по клиентской оптимизации<br />
» Секреты jQuery</p>
<p>Такие мастер-классы помогут узнать много нового, понять уровень своих знаний, получить новые идеи.</p>
<p>И еще, очень интересно! Принять участие в мастер-классе &laquo;<strong>Секреты jQuery</strong>&raquo; можно будет в режиме on-line.</p>
<p><strong><a href="http://javascript.ru/mk">Исходное объявление на javascript.ru »</a></strong><br />
<span id="more-117"></span></p>
<p>Для понимания материала необходимо знать javascript на минимальном уровне, писать простые скрипты. Содержание мастер-классов построено так, чтобы максимально глубоко раскрыть темы за короткий срок.</p>
<p>Теперь подробнее о содержании мастер-классов.</p>
<h3>&laquo;Профессиональное javascript-программирование&raquo;</h3>
<blockquote><p>- Javascript, browser tips &amp; tricks.<br />
- Фишки DOM, функции/замыкания, ООП &#8211; понятно и в деталях.<br />
- Малоизвестные возможности javascript и браузеров.<br />
- Javascript-фреймворки. Сравнение современных возможностей. jQuery в деталях.<br />
- Полезный инструментарий, который сделает вашу разработку быстрее и качественнее. Гораздо больше, чем Firebug.<br />
- Обмен информацией между окнами с разных доменов<br />
- HTML5: что уже есть, а что нас ждет уже скоро.</p></blockquote>
<p>Этот мастер класс &#8211; отнюдь не об основах javascript, здесь присутствует много информации для профессионалов.<br />
Москва: суббота, 20 февраля, 11.00<br />
Санкт-Петербург: суббота, 27 февраля, 11.00<br />
<em>Продолжительность &#8211; 4 часа.</em></p>
<h3>&laquo;Клиентская оптимизация&raquo;</h3>
<blockquote><p>- Способы и принципы сжатия javascript, что делать, чтобы код сжимался эффективнее.<br />
- Идеальное кеширование. Скрипты и серверная часть.<br />
- Эффективная оптимизация javascript. Подходы, цифры, рецепты.<br />
- Основные приемы оптимизации jQuery.<br />
- Ускорение загрузки страницы через HTTP pipelining.<br />
- Оптимизация с Google Gears и HTML5.<br />
- Google Closure Compiler в деталях<br />
- Удобные инструменты для оптимизации и профайлинга.</p></blockquote>
<p>Про то, как ускорить страницу, почти ничего не делая, и как серьезно ускорить страницу и сайт, если что-то сделать.<br />
Москва: воскресенье, 21 февраля, 11.00<br />
Санкт-Петербург: воскресенье, 28 февраля, 11.00<br />
<em>Продолжительность &#8211; 4 часа.</em></p>
<h3>&laquo;Сложный AJAX и COMET: тонкости Web 2.0&#8243;</h3>
<blockquote><p>- Асинхронная подгрузка событий с сервера (COMET) &#8211; различные варианты, сравнение и примеры реализации.<br />
- Кнопки back-forward, закладки и история с AJAX.<br />
- Cпособы написания чата/оповещающего демона, аспекты производительности и решения.<br />
- Кросс-доменные ограничения, способы их преодоления.<br />
- Асинхронный try..catch. Удобная работа с асинхронностью.<br />
- Инструменты для разработки и отладки сложных AJAX-приложений.<br />
- Специализированный COMET-сервер, установка, расширение, интеграция. Поднимем COMET прямо на мастер-классе.</p></blockquote>
<p>Мастер-класс сделает современные подходы простыми и понятными для вас, позволит улучшить те приложения, которые есть сейчас, и перейти к качественно новой разработке в будущем.<br />
Москва: суббота, 20 февраля, 16.00<br />
Санкт-Петербург: суббота, 27 февраля, 16.00<br />
<em>Продолжительность &#8211; 4 часа.</em></p>
<h3>&laquo;Секреты jQuery&raquo;</h3>
<blockquote><p>1. Как работает поисковой движок jQuery $(&#8216;&#8230;&#8217;).<br />
- Внутреннее устройство. Алгоритм поиска. No magic.<br />
- Почему некоторые очевидные запросы тормозят, и как их ускорять.<br />
- Расширение поискового движка, добавление своих фильтров.<br />
2. Система событий в jQuery.<br />
- Внутреннее устройство.<br />
- Слабо- и недокументированные фичи, отсутствующие в обычных javascript-событиях.<br />
- Влияние системы событий на быстродействие и DOM-манипуляции. Что тормозит и почему.<br />
- Обход утечек памяти.<br />
3. Фишки AJAX.<br />
- Особенные фичи AJAX в jQuery, которых нет в других библиотеках и полезные приемы работы с ними.<br />
4. $.изнутри.<br />
- Внутреннее устройство функции $. Что она делает быстро, а что &#8211; нет.<br />
- Создание плагинов. Внутренний механизм работы $.fn.plugin.<br />
5. jQuery UI.<br />
- Обзор и устройство jQuery UI.<br />
- Написание собственных виджетов. Объявление, вызов методов и т.п. Примеры.<br />
- Приемы для более удобной работы с виджетами.<br />
6. Профайлинг jQuery-приложения<br />
- Как из каши $(вызовов) получить читаемый профиль.<br />
7. Дополнительно.<br />
- Общий обзор библиотеки jQuery, ее сильных и слабых мест. Сравнение с другими фреймворками. Новое в jQuery 1.4.</p></blockquote>
<p>Мастер-класс посвящен слабо документированным особенностям и устройству фреймворка jQuery. Это не вводный курс. Знакомство и опыт работы с фреймворком jQuery &#8211; обязательны.<br />
Москва: воскресенье, 21 февраля, 16.00<br />
Санкт-Петербург: воскресенье, 28 февраля, 16.00<br />
<em>Продолжительность &#8211; 3 часа.</em><br />
<strong>On-line</strong>: суббота, 27 февраля, 20.00-21.50 и воскресенье, 28 февраля, 20.00-21.50</p>
<p><strong><a href="http://javascript.ru/mk">Дополнительная информация, запись на мастер-классы »</a></strong></p>
]]></content:encoded>
			<wfw:commentRss>http://www.linkexchanger.su/2010/117.html/feed</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>jQuery. Сборник рецептов</title>
		<link>http://www.linkexchanger.su/2010/115.html</link>
		<comments>http://www.linkexchanger.su/2010/115.html#comments</comments>
		<pubDate>Fri, 22 Jan 2010 09:51:08 +0000</pubDate>
		<dc:creator>Gennady</dc:creator>
				<category><![CDATA[jQuery]]></category>
		<category><![CDATA[jQuery документация]]></category>
		<category><![CDATA[документация jQuery]]></category>

		<guid isPermaLink="false">http://www.linkexchanger.su/2010/115.html</guid>
		<description><![CDATA[Несколько дней назад в интернет-магазинах появилась в продаже книга &#171;jQuery. Сборник рецептов&#187;. Книга вышла в издательстве &#171;БХВ-Петербург&#187;. Написана она мной &#8211; автором этого блога.

Геннадий Самков
jQuery. Сборник рецептов (+ CD-ROM)
Издательство: БХВ-Петербург, 2010 г.
Мягкая обложка, 410 стр.
ISBN 978-5-9775-0495-9
Тираж: 1500 экз.
Формат: 70&#215;100/16


Аннотация:
Книга является сборником решений наиболее часто встречающихся задач при веб-программировании пользовательских интерфейсов с использованием библиотеки jQuery. Рассмотрены [...]]]></description>
			<content:encoded><![CDATA[<p>Несколько дней назад в интернет-магазинах появилась в продаже книга <strong>&laquo;jQuery. Сборник рецептов&raquo;</strong>. Книга вышла в издательстве &laquo;БХВ-Петербург&raquo;. Написана она мной &#8211; автором этого блога.</p>
<ul style="float: right; width: 200px">
<li>Геннадий Самков</li>
<li>jQuery. Сборник рецептов (+ CD-ROM)</li>
<li>Издательство: БХВ-Петербург, 2010 г.</li>
<li>Мягкая обложка, 410 стр.</li>
<li>ISBN 978-5-9775-0495-9</li>
<li>Тираж: 1500 экз.</li>
<li>Формат: 70&#215;100/16</li>
</ul>
<p><a href="http://www.ozon.ru/context/detail/id/4934639/" title="jQuery. Сборник рецептов" target="_blank"><img style="border:1px solid #333;" src="http://www.linkexchanger.su/wp-content/uploads/2010/01/book2.jpg" alt="jQuery. Сборник рецептов" /></a><span id="more-115"></span></p>
<p><strong>Аннотация:</strong><br />
Книга является сборником решений наиболее часто встречающихся задач при веб-программировании пользовательских интерфейсов с использованием библиотеки jQuery. Рассмотрены практически все методы и вспомогательные функции jQuery, в том числе обеспечивающие взаимодействие jQuery и AJAX. Подробно рассказано о надстройке UI jQuery и приведены описания всех настроек для виджетов, входящих в ее состав, что позволяет использовать книгу в качестве справочника. Приведено большое количество примеров использования наиболее популярных плагинов для jQuery &#8211; создание графиков и диаграмм, фотогалерей, навигационных меню, всплывающих подсказок, работа с веб-формами, таймерами и cookies, обработка табличных данных. Компакт-диск содержит примеры, разобранные в книге, файлы библиотеки jQuery версий 1.2.6 и 1.3.2, файлы надстройки UI jQuery, а также файлы рассмотренных в книге расширений сторонних разработчиков.</p>
<p>От себя могу добавить, что книга написана в таком же духе, как и предыдущая: &laquo;<a href="http://www.linkexchanger.su/2009/87.html">AJAX. Программирование для Интернета</a>&laquo;, т.е. примеры, примеры и еще раз примеры плюс подробные разъяснения&#8230;.</p>
<p><strong>Полное содержание:</strong></p>
<table border="0" width="100%">
<tr>
<td>Введение</td>
<td>1</td>
</tr>
<tr>
<td>Структура книги</td>
<td>1</td>
</tr>
<tr>
<td>Как работать с книгой</td>
<td>2</td>
</tr>
<tr>
<td>Источники информации</td>
<td>3</td>
</tr>
<tr>
<td>Благодарности</td>
<td>4</td>
</tr>
<tr>
<td>
<h3>ЧАСТЬ I. МЕТОДЫ БИБЛИОТЕКИ JQUERY</h3>
</td>
<td>5</td>
</tr>
<tr>
<td>
<h3>Глава 1. Выбор элементов</h3>
</td>
<td>7</td>
</tr>
<tr>
<td>1.1. Базовые правила</td>
<td>7</td>
</tr>
<tr>
<td>1.2. Выбор элементов с учетом иерархии</td>
<td>14</td>
</tr>
<tr>
<td>1.3. Основные фильтры</td>
<td>18</td>
</tr>
<tr>
<td>1.4. Фильтрация по содержимому</td>
<td>24</td>
</tr>
<tr>
<td>1.5. Фильтры видимых и невидимых элементов</td>
<td>28</td>
</tr>
<tr>
<td>1.6. Фильтры атрибутов</td>
<td>29</td>
</tr>
<tr>
<td>1.7. Фильтры элементов форм</td>
<td>35</td>
</tr>
<tr>
<td>1.8. Фильтры состояния элементов форм</td>
<td>37</td>
</tr>
<tr>
<td>1.9. Фильтры элементов-потомков</td>
<td>42</td>
</tr>
<tr>
<td>
<h3>Глава 2. Атрибуты элементов</h3>
</td>
<td>48</td>
</tr>
<tr>
<td>2.1. Управление атрибутами элементов</td>
<td>48</td>
</tr>
<tr>
<td>2.2. Работа с атрибутом class</td>
<td>53</td>
</tr>
<tr>
<td>2.3. Работа с HTML и текстом</td>
<td>54</td>
</tr>
<tr>
<td>2.4. Работа с атрибутом value</td>
<td>57</td>
</tr>
<tr>
<td>
<h3>Глава 3. Визуальные эффекты</h3>
</td>
<td>64</td>
</tr>
<tr>
<td>3.1. Как показывать и скрывать элементы</td>
<td>64</td>
</tr>
<tr>
<td>3.2. Эффекты &laquo;скольжения&raquo; и &laquo;затухания&raquo;</td>
<td>67</td>
</tr>
<tr>
<td>3.3. Создание анимации</td>
<td>71</td>
</tr>
<tr>
<td>3.4. Эффекты UI jQuery</td>
<td>76</td>
</tr>
<tr>
<td>
<h3>Глава 4. Работа с CSS-свойствами</h3>
</td>
<td>81</td>
</tr>
<tr>
<td>4.1. Как получать и устанавливать значения CSS-свойств элементов</td>
<td>81</td>
</tr>
<tr>
<td>4.2. Ширина и высота элементов</td>
<td>85</td>
</tr>
<tr>
<td>4.3. Позиционирование элементов</td>
<td>88</td>
</tr>
<tr>
<td>
<h3>Глава 5. Некоторые методы ядра библиотеки jQuery</h3>
</td>
<td>92</td>
</tr>
<tr>
<td>5.1. Примеры работы с объектом jQuery</td>
<td>92</td>
</tr>
<tr>
<td>5.2. Сохранение и извлечение данных</td>
<td>97</td>
</tr>
<tr>
<td>
<h3>Глава 6. Манипуляции над элементами</h3>
</td>
<td>101</td>
</tr>
<tr>
<td>6.1. Изменение содержимого элементов</td>
<td>101</td>
</tr>
<tr>
<td>6.2. Как вставлять элементы в DOM</td>
<td>103</td>
</tr>
<tr>
<td>6.3. Замена, удаление и копирование элементов</td>
<td>113</td>
</tr>
<tr>
<td>
<h3>Глава 7. Перемещение по элементам</h3>
</td>
<td>120</td>
</tr>
<tr>
<td>7.1. Поиск нужных элементов в DOM</td>
<td>120</td>
</tr>
<tr>
<td>7.2. Фильтрация элементов набора</td>
<td>131</td>
</tr>
<tr>
<td>7.3. Перемещение по цепочке вызовов</td>
<td>138</td>
</tr>
<tr>
<td>
<h3>Глава 8. События и их обработка</h3>
</td>
<td>142</td>
</tr>
<tr>
<td>8.1. Готовность документа</td>
<td>142</td>
</tr>
<tr>
<td>8.2. Назначение, удаление и вызов событий</td>
<td>144</td>
</tr>
<tr>
<td>8.3. Взаимодействие с элементами</td>
<td>152</td>
</tr>
<tr>
<td>8.4. События</td>
<td>155</td>
</tr>
<tr>
<td>
<h3>Глава 9. Взаимодействие jQuery и AJAX</h3>
</td>
<td>161</td>
</tr>
<tr>
<td>9.1. Самое простое</td>
<td>161</td>
</tr>
<tr>
<td>9.2. GET- и POST-запросы</td>
<td>166</td>
</tr>
<tr>
<td>9.3. Вспомогательная функция $.ajax(options)</td>
<td>174</td>
</tr>
<tr>
<td>9.4. Для чего нужна функция $.ajaxSetup(options)</td>
<td>180</td>
</tr>
<tr>
<td>9.5. События AJAX</td>
<td>183</td>
</tr>
<tr>
<td>
<h3>Глава 10. Утилиты jQuery</h3>
</td>
<td>190</td>
</tr>
<tr>
<td>10.1. Некоторые операции с массивами и объектами в jQuery</td>
<td>190</td>
</tr>
<tr>
<td>
<h3>ЧАСТЬ II. РАСШИРЕНИЯ ДЛЯ БИБЛИОТЕКИ JQUERY</h3>
</td>
<td>201</td>
</tr>
<tr>
<td>
<h3>Глава 11. Меню для веб-сайта</h3>
</td>
<td>203</td>
</tr>
<tr>
<td>11.1. Плагин jQuery Multi Level Menu</td>
<td>203</td>
</tr>
<tr>
<td>11.2. Плагин jQuery Drop Line Menu</td>
<td>207</td>
</tr>
<tr>
<td>11.3. Плагин jQuery TreeView</td>
<td>210</td>
</tr>
<tr>
<td>11.4. Делаем меню похожее на Accordion</td>
<td>216</td>
</tr>
<tr>
<td>
<h3>Глава 12. Работа с таблицами</h3>
</td>
<td>219</td>
</tr>
<tr>
<td>12.1. Плагин jQuery DataTables</td>
<td>219</td>
</tr>
<tr>
<td>
<h3>Глава 13. Графики и диаграммы</h3>
</td>
<td>229</td>
</tr>
<tr>
<td>13.1. Плагин jqPlot</td>
<td>229</td>
</tr>
<tr>
<td>
<h3>Глава 14. AJAX-формы</h3>
</td>
<td>242</td>
</tr>
<tr>
<td>14.1. Плагин jQuery Autocomplete</td>
<td>242</td>
</tr>
<tr>
<td>14.2. Плагин jQuery Form</td>
<td>252</td>
</tr>
<tr>
<td>14.3. Плагин jQuery Validate</td>
<td>257</td>
</tr>
<tr>
<td>14.4. Плагин jQuery Uploadify</td>
<td>264</td>
</tr>
<tr>
<td>
<h3>Глава 15. Фотогалереи для сайта</h3>
</td>
<td>274</td>
</tr>
<tr>
<td>15.1. Фотогалерея FancyBox</td>
<td>274</td>
</tr>
<tr>
<td>15.2. Простая фотогалерея</td>
<td>282</td>
</tr>
<tr>
<td>
<h3>Глава 16. Несколько полезных плагинов</h3>
</td>
<td>286</td>
</tr>
<tr>
<td>16.1. jQuery Cookie</td>
<td>286</td>
</tr>
<tr>
<td>16.2. jQuery Corner</td>
<td>288</td>
</tr>
<tr>
<td>16.3. jQuery Timers</td>
<td>293</td>
</tr>
<tr>
<td>16.4. jQuery Cluetip</td>
<td>297</td>
</tr>
<tr>
<td>
<h3>Глава 17. UI jQuery — виджеты</h3>
</td>
<td>303</td>
</tr>
<tr>
<td>17.1. Виджет Accordion</td>
<td>303</td>
</tr>
<tr>
<td>17.2. Виджет Datepicker</td>
<td>314</td>
</tr>
<tr>
<td>17.3. Виджет Dialog</td>
<td>326</td>
</tr>
<tr>
<td>17.4. Виджет Progressbar</td>
<td>334</td>
</tr>
<tr>
<td>17.5. Виджет Slider</td>
<td>337</td>
</tr>
<tr>
<td>17.6. Виджет Tabs</td>
<td>343</td>
</tr>
<tr>
<td>
<h3>Глава 18. UI jQuery — взаимодействие с элементами страницы</h3>
</td>
<td>354</td>
</tr>
<tr>
<td>18.1. Draggable — перемещение элементов</td>
<td>354</td>
</tr>
<tr>
<td>18.2. Droppable — &laquo;сброс&raquo; элементов</td>
<td>364</td>
</tr>
<tr>
<td>18.3. Resizable — изменение размеров элементов</td>
<td>371</td>
</tr>
<tr>
<td>18.4. Selectable — выбор элементов</td>
<td>377</td>
</tr>
<tr>
<td>18.5. Sortable — сортировка элементов</td>
<td>385</td>
</tr>
<tr>
<td>Литература</td>
<td>397</td>
</tr>
<tr>
<td>Приложение. Описание компакт-диска</td>
<td>398</td>
</tr>
<tr>
<td>Предметный указатель</td>
<td>400</td>
</tr>
<tr>
<td>Оглавление</td>
</tr>
</table>
]]></content:encoded>
			<wfw:commentRss>http://www.linkexchanger.su/2010/115.html/feed</wfw:commentRss>
		<slash:comments>59</slash:comments>
		</item>
		<item>
		<title>jQuery 1.4</title>
		<link>http://www.linkexchanger.su/2010/114.html</link>
		<comments>http://www.linkexchanger.su/2010/114.html#comments</comments>
		<pubDate>Thu, 14 Jan 2010 20:46:02 +0000</pubDate>
		<dc:creator>Gennady</dc:creator>
				<category><![CDATA[jQuery]]></category>

		<guid isPermaLink="false">http://www.linkexchanger.su/2010/114.html</guid>
		<description><![CDATA[Сегодня (по Москве почти в полночь) официально объявлено о выпуске jQuery версии 1.4. Выход новой версии, как и в прошлом году, приурочен к дню рождения библиотеки, которой исполнилось уже 4 года. Собственно, интересующиеся этой тематикой уже могли ознакомиться с релизами jQuery 1.4 Alpha 1 от 4 декабря 2009 года и jQuery 1.4 Alpha 2 от [...]]]></description>
			<content:encoded><![CDATA[<p>Сегодня (по Москве почти в полночь) официально объявлено о выпуске jQuery версии 1.4. Выход новой версии, как и в прошлом году, приурочен к дню рождения библиотеки, которой исполнилось уже 4 года. Собственно, интересующиеся этой тематикой уже могли ознакомиться с релизами jQuery 1.4 Alpha 1 от 4 декабря 2009 года и jQuery 1.4 Alpha 2 от 18 декабря 2009 года. А 12 января появился релиз-кандидат jQuery 1.4rc1. Подробное знакомство с новшествами еще впереди, но я не мог не дать краткий обзор изменений и новых возможностей, которые появились в очередной версии. Начнем знакомство?<span id="more-114"></span></p>
<p>Метод <em>.addClass(className)</em> теперь может принимать в качестве аргумента не только имя класса (или классов), но и функцию <em>.addClass(function)</em>, которая должна возвратить один или более имен классов, которые должны быть добавлены элементу. Если имен классов более одного, они должны быть разделены пробелами. На примере:</p>
<pre class="brush: jscript;">$('ul li:last').addClass(function() {
    return 'item-' + $(this).index();
});</pre>
<p>Аналогичные изменения претерпели методы <em>.removeClass(className)</em> и <em>.toggleClass(className)</em>, которые также теперь могут принимать функцию в качестве аргумента.</p>
<p>Похожие изменения внесены в методы <em>.after(content)</em>, <em>.before(content)</em>, <em>.append(content)</em> и <em>.prepend(content)</em>. Все эти методы начиная с версии 1.4 могут принимать в качестве аргумента функцию, которая должна возвращать строку html-кода.</p>
<p>Аналогичным образом дополнены методы <em>.html(htmlString)</em> и <em>.text(textString)</em>. Если до версии 1.4 эти методы принимали аргументом соответственно строку html-кода и обычный текст, то теперь аргументом может быть также функция &#8211; <em>.html(function)</em> и <em>.text(function)</em>. Функции должны возвращать соответственно html-код и текст.</p>
<p>Дополнен метод <em>.val()</em>. Теперь при установке нужного значения можно использовать не только собственно значение, но и функцию, которая должна возвращать требуемое значение.</p>
<p>Дополнен метод <em>.css()</em>. Если раньше для того, чтобы установить значение какого-либо css-свойства мы использовали <em>.css(propertyName, value)</em> или <em>.css(map)</em> для того, чтобы установить значения сразу нескольких css-свойств элемента, то теперь получили возможность использовать во втором аргументе функцию, возвращающую то значение, которое должно быть установлено этому css-свойству <em>.css(propertyName, function)</em>.</p>
<p>Чтобы сохранить произвольные данные, связав их с выбранным элементом мы должны были передать методу <em>.data(key, value)</em> соответствующие пары ключ/значение. Теперь аргументом этого метода может быть и непосредственно объект <em>.data(obj)</em>. Чтобы получить доступ к сохраненным данным требуется указать <em>.data(key)</em> имя под которым были сохранены эти данные. В дополнение к этому с версии 1.4 можно вызвать метод <em>.data()</em> без аргументов, и в этом случае данные будут возвращены в виде объекта.<br />
Точно также теперь можно поступить  и в том случае, если данные, связанные с элементом были сохранены в свойстве data объекта jQuery.</p>
<p>Начиная с версии 1.4 добавлены вспомогательные функции <em>jQuery.isEmptyObject(object)</em> &#8211; проверяет, является ли объект пустым (не содержащим свойств)</p>
<pre class="brush: jscript;">jQuery.isEmptyObject({}) // вернет true
jQuery.isEmptyObject({ foo: &quot;bar&quot; }) // вернет false</pre>
<p>и <em>jQuery.isObjectLiteral(object)</em> &#8211; проверяет является ли он простым объектом (создан с помощью {} или new Object)</p>
<pre class="brush: jscript;">jQuery.isPlainObject({}) // true
jQuery.isObjectLiteral(&quot;test&quot;) // false</pre>
<p>Добавлены методы <em>.prevUntil([selector])</em>, <em>.nextUntil([selector])</em> и <em>.parentsUntil([selector])</em>. Первые два новых метода помогут выбрать все элементы соответственно перед и после, но при этом <strong>ДО</strong> элемента <em>[selector]</em> указанного в качестве аргумента метода. А метод <em>.parentsUntil([selector])</em> поможет выбрать всех родителей, но также <strong>ДО</strong> элемента <em>[selector]</em> указанного в качестве аргумента.</p>
<p>Дополнены методы <em>.wrap(wrappingElement)</em>, <em>.wrapAll(wrappingElement)</em> и <em>.wrapInner(wrappingElement)</em>. Теперь в качестве аргумента этих методов можно использовать функцию, которая должна возвращать структуру в которую будет обернут каждый выбранный элемент (для <em>wrap</em>), все выбранные элементы (для <em>wrapAll</em>) или внутреннее содержимое выбранного элемента (для <em>wrapInner</em>). Также добавлен новый метод <em>.unwrap()</em>, название которого говорит само за себя &#8211; удаляет непосредственных родителей выбранных элементов, оставляя сами элементы без изменений.</p>
<p>Добавлен весьма полезный метод <em>.delay(duration, [queueName])</em>, которые позволяет установить таймер задержки выполнения следующего пункта очереди. На примере:</p>
<pre class="brush: jscript;">$('#foo').slideUp(300).delay(800).fadeIn(400);</pre>
<p>Здесь метод <em>fadeIn</em> начнет выполняться только через 800 миллисекунд после того, как отработает метод <em>slideUp</em>.</p>
<p>Добавлен метод <em>.detach([selector])</em>, который похож на метод <em>.remove()</em> тем, что также удаляет выбранные элементы из DOM, но, в отличие от <em>.remove()</em> новый метод сохраняет данные, связанные с удаленными элементами, что можно использовать при возврате  удаленных элементы обратно в DOM.</p>
<p>Добавлен метод <em>.toArray()</em>, который возвращает в виде массива все DOM-элементы, включенные в набор jQuery. Выполнив</p>
<pre class="brush: jscript;">alert($('li').toArray());</pre>
<p>увидим что-то вроде</p>
<pre class="brush: xml;">[&lt;li id=&quot;foo&quot;&gt;, &lt;li id=&quot;bar&quot;&gt;]</pre>
<p>Дополнен метод <em>.replaceWith(newContent)</em> и теперь в качестве аргумента может использоваться функция, которая должна возвращать строку html-кода, которым должен быть заменен выбранный элемент.</p>
<p>Дополнен метод <em>.add()</em>, с помощью которого можно добавлять в существующий набор дополнительные элементы. Если до версии 1.4 в качестве аргумента можно было указать jQuery-селектор, элемент(или элементы) и фрагмент html-кода, то теперь появилась возможность после селектора указать второй аргумент &#8211; контекст, в котором будет производится поиск нужного элемента(ов).</p>
<p>Добавлены новые методы <em>.focusin(handler(eventObject))</em> и <em>.focusout(handler(eventObject))</em>. Методы вызывают обработчики соответственно при получении и потере фокуса выбранным элементом. В качестве аргумента обработчик принимает объект события.</p>
<p>Добавлен метод <em>.has(selector)</em>, с помощью которого можно проверить наличие элемента внутри другого элемента. Для разметки</p>
<pre class="brush: jscript;">&lt;ul&gt;&lt;li&gt;Does the UL contain an LI?&lt;/li&gt;&lt;/ul&gt;</pre>
<p>выполним код</p>
<pre class="brush: jscript;">$(&quot;ul&quot;).append('&lt;li&gt;' +
($(&quot;ul&quot;).has(&quot;li&quot;).length ? &quot;Yes&quot; : &quot;No&quot;) +
'&lt;/li&gt;');</pre>
<p>Такой код добавит в список элемент li с текстом Yes.</p>
<p>Дополнен метод <em>.index(element)</em> с помощью которого можно было узнать индекс DOM-элемента в наборе. Теперь может принимать в качестве аргумента селектор jQuery, а также может быть вызван без передачи аргумента. Довольно интересно, чтобы смотреть на примерах.</p>
<pre class="brush: xml;">&lt;ul&gt;
  &lt;li id=&quot;foo&quot;&gt;foo&lt;/li&gt;
  &lt;li id=&quot;bar&quot;&gt;bar&lt;/li&gt;
  &lt;li id=&quot;baz&quot;&gt;baz&lt;/li&gt;
&lt;/ul&gt;</pre>
<p>В качестве аргумента DOM-элемент:</p>
<pre class="brush: jscript;">var listItem = document.getElementById('bar');
alert('Index: ' + $('li').index(listItem));  // 1</pre>
<p>В качестве аргумента объект jQuery:</p>
<pre class="brush: jscript;">var listItem = $('#bar');
alert('Index: ' + $('li').index(listItem)); // 1</pre>
<p>И без передачи аргумента:</p>
<pre class="brush: jscript;">alert('Index: ' + $('#bar').index(); // 1</pre>
<p>т.е. возвращается индекс (считаем от 0) элемента в наборе, в котором присутствуют все сестринские элементы этого уровня.</p>
<p>Дополнен метод <em>.closest(selector)</em>, теперь вторым параметром можно передать контекст.</p>
<p>Добавлен новый метод <em>.clearQueue([queueName])</em>, который удаляет из очереди все функции, которые еще не были выполнены. Похож на <em>.stop(true)</em>, однако есть отличия.</p>
<p>Дополнен метод <em>.offset()</em>, который позволяет получить координаты выбранного элемента относительно документа. Теперь координаты можно будет <strong>устанавливать</strong> с помощью передачи этому методу аргумента &#8211; <em>.offset(coordinates)</em>. Здесь <em>coordinates</em> &#8211; объект, содержащий свойства <em>top</em> и <em>left</em>, значениями которых являются числовые значения новых координат. Также в качестве аргумента может выступать функция <em>.offset(coordinates(index,coords))</em>, которая в свою очередь принимает в качестве первого аргумента индекс элемента в наборе, а качестве второго &#8211; его новые координаты.</p>
<p>Изменения коснулись и функция <em>jQuery()</em>. Теперь при ее вызове без аргументов будет возвращен пустой набор.</p>
<p>Изменения во вспомогательной функции <em>jQuery.param(obj)</em>, которая упорядочивает предоставленный объект или массив, представляя его в форме, пригодной для передачи в URL или Ajax-запросе. Начиная с версии 1.4 можно передавать второй параметр <em>jQuery.param(obj, traditional)</em>, где <em>traditional</em> &#8211; логическое значение, которое устанавливается в <em>true</em>, если необходимо эмулировать поведение этой функции как в версиях ниже 1.4.</p>
<p>Новая вспомогательная функция <em>jQuery.contains(container, contained)</em>, позволяющая проверить существование элемента DOM внутри другого элемента DOM. Здесь <em>container</em> &#8211; элемент DOM, который может содержать другой элемент DOM, а <em>contained</em> &#8211; элемент DOM, который может находится внутри. На примере:</p>
<pre class="brush: jscript;">// true
jQuery.contains(document.documentElement, document.body);
// false
jQuery.contains(document.body, document.documentElement);</pre>
<p>Добавлена <em>jQuery.noop()</em> &#8211; функция, которая ничего не делает.</p>
<p>Новый метод <em>jQuery.proxy()</em>. Принимает пару аргументов, например так <em>jQuery.proxy(function, scope)</em>, где <em>function</em> &#8211; функция, область видимости которой будет изменена, а <em>scope</em> &#8211; объект в который должна быть установлена область видимости функции. <strong>Грандиозно!</strong> Еще вариант &#8211; <em>jQuery.proxy(scope, name)</em>, где <em>scope</em> &#8211; то же, а <em>name</em> &#8211; имя функции, область видимости которой будет изменена (должно быть свойством объекта &#8217;scope&#8217;). На примере:</p>
<pre class="brush: jscript;">var obj = {
  name: &quot;John&quot;,
  test: function() {
    alert( this.name );
    $(&quot;#test&quot;).unbind(&quot;click&quot;, obj.test);
  }
};
// 2-й вариант
$(&quot;#test&quot;).click( jQuery.proxy( obj, &quot;test&quot; ) );
// И так тоже работает:
// 1-й вариант
// $(&quot;#test&quot;).click( jQuery.proxy( obj.test, obj ) );</pre>
<p>Обзор конечно получился краткий, несколько поспешный и насколько я уже понимаю с некоторыми неточностями (не по моей вине <img src='http://www.linkexchanger.su/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  ), но для тех, кто хочет сам покопаться и разобраться повнимательнее &#8211; <a href="http://api.jquery.com/">новый сайт API jQuery</a>.</p>
<p>P.S. Поздравляю всех с наконец-то окончательно наступившим Новым Годом, jQuery &#8211; с четвертым Днем Рождения и выходом очередной версии, а себя &#8211; с Днем Рождения своего блога, которому исполнилось два года.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.linkexchanger.su/2010/114.html/feed</wfw:commentRss>
		<slash:comments>31</slash:comments>
		</item>
		<item>
		<title>Форуму быть?</title>
		<link>http://www.linkexchanger.su/2010/113.html</link>
		<comments>http://www.linkexchanger.su/2010/113.html#comments</comments>
		<pubDate>Mon, 11 Jan 2010 18:20:06 +0000</pubDate>
		<dc:creator>Gennady</dc:creator>
				<category><![CDATA[jQuery]]></category>

		<guid isPermaLink="false">http://www.linkexchanger.su/2010/113.html</guid>
		<description><![CDATA[К началу третьего года существования блога стало окончательно понятно, что его &#171;мощностей&#187; не хватает для удовлетворения растущих потребностей сообщества поклонников jQuery. А посему вопрос встал ребром &#8211; быть или не быть форуму?
Вопрос решено вынести на суд сообщества, приведя при этом некоторые аргументы &#171;pro&#187; и &#171;contra&#187; и предоставив возможность решить этот вопрос голосованием.
Итак, аргументы &#171;pro&#187;:
- формат [...]]]></description>
			<content:encoded><![CDATA[<p>К началу третьего года существования блога стало окончательно понятно, что его &laquo;мощностей&raquo; не хватает для удовлетворения растущих потребностей сообщества поклонников jQuery. А посему вопрос встал ребром &#8211; быть или не быть форуму?<br />
Вопрос решено вынести на суд сообщества, приведя при этом некоторые аргументы &laquo;pro&raquo; и &laquo;contra&raquo; и предоставив возможность решить этот вопрос голосованием.<span id="more-113"></span><br />
<strong>Итак, аргументы &laquo;pro&raquo;:</strong><br />
- формат блога неудобен для подробного описания решения проблем, количество комментариев растет с устрашающей скоростью.<br />
- довольно много писем с просьбой сделать наконец-то уже форум.<br />
<strong>Однако не менее серьезны аргументы &laquo;contra&raquo;:</strong><br />
- существование форумов с подобной тематикой. Пример: javascript.ru<br />
- банальная нехватка времени, поскольку кроме собственной работы (семью-то надо кормить) и ведения блога, иногда приходиться еще и спать…</p>
<p>Скажу, что сам склоняюсь к идее создания форума, посвященного исключительно jQuery, но очень хотел бы, чтобы среди читателей блога нашлись люди (знаю, что они есть и их немало), которые были бы не против поучаствовать в администрировании форума (если конечно будет решено его создавать).</p>
<p>Исходя из всего того, что я здесь нагородил <img src='http://www.linkexchanger.su/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  призываю не просто голосовать, а (если голосовали &laquo;за&raquo;) еще и активно оставлять в комментариях свои предложения по структуре форума. Да и вообще любые мысли на этот счет весьма приветствуются&#8230;.</p>
<h3>Голосование завершено</h3>
Note: There is a poll embedded within this post, please visit the site to participate in this post's poll.
]]></content:encoded>
			<wfw:commentRss>http://www.linkexchanger.su/2010/113.html/feed</wfw:commentRss>
		<slash:comments>54</slash:comments>
		</item>
		<item>
		<title>Галерея LightBox и ее клоны</title>
		<link>http://www.linkexchanger.su/2009/112.html</link>
		<comments>http://www.linkexchanger.su/2009/112.html#comments</comments>
		<pubDate>Fri, 27 Nov 2009 06:37:29 +0000</pubDate>
		<dc:creator>Gennady</dc:creator>
				<category><![CDATA[jQuery]]></category>
		<category><![CDATA[lightbox]]></category>
		<category><![CDATA[фотогалерея]]></category>

		<guid isPermaLink="false">http://www.linkexchanger.su/2009/112.html</guid>
		<description><![CDATA[Почему решил написать этот обзор? Во-первых, предыдущая статья про LightBox безнадежно устарела. Во-вторых, мне LightBox нравится. Правда было время, когда разработчики плагина убирали оттуда поддержку ie6, но потом, видимо одумавшись, вернули ее. В общем, всем хорош плагин LightBox, но вот заточен он только под фото. А если приперло вывести видео с YouTube или вообще какой-нибудь [...]]]></description>
			<content:encoded><![CDATA[<p>Почему решил написать этот обзор? Во-первых, предыдущая <a href="http://www.linkexchanger.su/2008/65.html">статья про LightBox</a> безнадежно устарела. Во-вторых, мне LightBox нравится. Правда было время, когда разработчики плагина убирали оттуда поддержку ie6, но потом, видимо одумавшись, вернули ее. В общем, всем хорош плагин LightBox, но вот заточен он только под фото. А если приперло вывести видео с YouTube или вообще какой-нибудь контент в iframe? Да, да, знаю, есть <a href="http://www.linkexchanger.su/2008/66.html">галерея FancyBox</a>, сам пользуюсь, но LightBox все равно больше нравится. Поэтому и было решено покопаться среди многочисленных клонов галереи LightBox.<span id="more-112"></span></p>
<h3>Галерея LightBox</h3>
<p>Начинаем, так сказать, с первоисточника и сразу же смотрим <a href="http://www.linkexchanger.su/examples_2009/galleries/lightBox/demo.html" target="_blank">демо</a>, замечая при этом нюансы, чтобы потом сравнить с другими галереями.</p>
<p>Ясно, что для использования плагина нужно подключить к веб-странице файл библиотеки jquery-1.3.2.js, файл плагина jquery.lightbox.js и файл стилевого оформления плагина jquery.lightbox.css. Не забудьте, что в папке images полученного архива, хранятся изображения элементов управления, необходимые для работы плагина.</p>
<pre class="brush: xml;">&lt;link type=&quot;text/css&quot; href=&quot;js/jquery.lightbox.css&quot; rel=&quot;stylesheet&quot; /&gt;
&lt;script src=&quot;js/jquery-1.3.2.js&quot; type=&quot;text/javascript&quot;&gt;&lt;/script&gt;
&lt;script src=&quot;js/jquery.lightbox.js&quot; type=&quot;text/javascript&quot;&gt;&lt;/script&gt;</pre>
<p>Теперь о том, как собственно организовать галерею. Естественно понадобятся изображения из которых будет состоять галерея &#8211; миниатюры и соответствующие им полноразмерные изображения. Общая конструкция такая:</p>
<pre class="brush: xml;">&lt;a rel=&quot;lightbox&quot; href=&quot;images/large.jpg&quot; title=&quot;Какой-то текст&quot;&gt;
&lt;img src=&quot;images/small.jpg&quot; /&gt;
&lt;/a&gt;</pre>
<p>Картинка-миниатюра заключена в тэг а, атрибут href которого указывает на соответствующее полноразмерное изображение. В атрибуте rel содержится ключевое слово &#8211; lightbox. Такого кода достаточно, чтобы при клике по миниатюре в отдельном слое открылось большое (именно большое, потому что по умолчанию оно масштабируется, если не помещается в области просмотра) изображение. Текст, содержащийся в атрибуте title тэга a станет комментарием к открывшемуся изображению.</p>
<p>В рассмотренном примере функциональность плагина применена к отдельному изображению, а нам нужно сделать тоже самое для группы. Смотрим следующую разметку:</p>
<pre class="brush: xml;">&lt;a rel=&quot;lightbox-tour&quot; href=&quot;images/large.jpg&quot; title=&quot;Какой-то текст&quot;&gt;
&lt;img src=&quot;images/small.jpg&quot; /&gt;
&lt;/a&gt;</pre>
<p>К ключевому слову lightbox просто добавили произвольный суффикс, в данном случае -tour. Добавляйте какое-то количество таких конструкций в свой код, назначайте им одинаковый суффикс и плагин автоматически объединит изображения в группы. Естественно, в этом случае, кроме комментариев, которые также будут создаваться из содержимого атрибута title, появятся элементы управления для перемещения по галерее.</p>
<p>Если по каким-то причинам Вам нежелательно использовать атрибут rel, можно обойтись и без него. Создать галерею можно используя простой jQuery-код.</p>
<pre class="brush: jscript;">$(function(){
  $('a.gallery').lightbox();
});</pre>
<p>Если этот код использовать с приведенной ниже разметкой, то все элементы а, имеющие класс gallery, получат функциональность плагина, и атрибут rel тут не потребуется.</p>
<pre class="brush: xml;">&lt;a class=&quot;gallery&quot; href=&quot;images/large.jpg&quot; title=&quot;Какой-то текст&quot;&gt;
&lt;img src=&quot;images/small.jpg&quot; /&gt;
&lt;/a&gt;</pre>
<p>Плагин LightBox имеет некоторое количество пользовательских настроек, с помощью которых можно переопределить поведение по умолчанию. Обычно jQuery-плагины принимают такие настройки в виде объекта, передаваемого методу в качестве аргумента. Здесь дело обстоит несколько иначе &#8211; для настройки вызывается отдельный метод. Ниже приведен пример кода, который создаст галерею из изображений, заключенных в тэг а с классом gallery и передаст плагину некоторые настройки.</p>
<pre class="brush: jscript;">$(function(){
  $(&quot;a.gallery&quot;).lightbox();
  $.Lightbox.construct({
    text: {
      image: &quot;Фото&quot;,
      of: &quot;из&quot;
    },
    download_link: false,
    opacity: 0.5,
    show_linkback: false
  });
});</pre>
<p>Кстати, помимо использования $.Lightbox.construct(); есть другая возможность передать настройки &#8211; в строке запроса. Примерно так:</p>
<pre class="brush: xml;">&lt;script src=&quot;js/jquery.lightbox.js?show_linkback=false&amp;amp;text.image=Фото&amp;amp;text.of=из&quot; type=&quot;text/javascript&quot;&gt;&lt;/script&gt;</pre>
<blockquote><p><strong>ПРИМЕЧАНИЕ:</strong> В плагине подразумевается поддержка IE6 и она включена по умолчанию. Для IE6 передача параметров возможна только в строке запроса (остальные браузеры тоже понимают такой способ). Если попытаться использовать $.Lightbox.construct(); то в IE плагин перестает работать. По крайней мере у меня не получилось.</p></blockquote>
<p>Ну а теперь немного о возможных опциях, которые можно использовать для настройки LightBox.</p>
<p><strong>show_linkback</strong> &#8211; по умолчанию true, показывает ссылку на страницу плагина на сайте plugins.jquery.com в правом верхнем углу. Передаем false, чтобы скрыть ссылку.<br />
<strong>show_helper_text</strong> &#8211; по умолчанию true, показывает текст (Click to close) в правом верхнем углу и всплывающую подсказку (Hover to interact) при наведении указателя мыши на этот текст. Используем false, чтобы убрать текст (и подсказку естественно тоже).<br />
<strong>show_info</strong> &#8211; по умолчанию &#8216;auto&#8217;, показывает информацию (текст, содержащийся в атрибуте title) под открывшимся изображением только в том случае, если указатель мыши находится над изображением. Чтобы показывать эту информацию независимо от положения указателя мыши используем значение true.<br />
<strong>show_extended_info</strong> &#8211; по умолчанию &#8216;auto&#8217;, показывает дополнительную информацию (Image 1 of nn) при указатель мыши прошел над область, где показывается основная информация (текст, содержащийся в атрибуте title). Чтобы показывать эту информацию независимо от положения указателя мыши используем значение true.<br />
<strong>download_link</strong> &#8211; по умолчанию true, предоставляет возможность открыть полноразмерное изображение в новом окне (вкладке) браузера, воспользовавшись ссылкой, которой является текст комментария к изображению (текст, содержащийся в атрибуте title). Чтобы запретить использование этой возможности, надо передать false.<br />
<strong>auto_resize</strong> &#8211; по умолчанию true, автоматически изменяет размеры картинки, если она слишком большая и не вписывается в область просмотра. Необходимо передать false, чтобы отменить это поведение.<br />
<strong>ie6_support</strong> &#8211; по умолчанию true, включена поддержка IE6. Чтобы отключить ее, надо передать false.<br />
<strong>ie6_upgrade</strong> &#8211; по умолчанию true, показывает сообщение, призывающее пользователей IE6 проапгрейдить свое ПО (у меня почему-то не сработало).<br />
<strong>speed</strong> &#8211; число, определяющее количество миллисекунд, которые отводятся на переход между двумя изображениями. По умолчанию установлено 400.<br />
<strong>baseurl</strong> &#8211; по умолчанию null, но можно указать url для автоматического подключения файлов, которые использует скрипт (стили, картинки).<br />
<strong>files</strong> &#8211; объект, в свойствах которого можно передать местоположение требуемых файлов (используется, если названия файлов менялись). Можно использовать следующие свойства: js.lightbox, js.colorBlend, css.lightbox, images.prev, images.next, images.blank, images.loading.<br />
<strong>text</strong> &#8211; объект, в свойствах которого можно передать текст частей интерфейса. Используется для перевода на нужный язык. Можно использовать следующие свойства: image, of, close, closeInfo, download, help.close, help.interact, about.text, about.title, about.link.<br />
<strong>keys</strong> &#8211; объект, в свойствах которого можно определить &laquo;горячие клавиши&raquo; для перемещения по галерее вперед и назад, а также для закрытия галереи. Используются свойства close, prev, next.<br />
<strong>opacity</strong> &#8211; прозрачность слоя, который появляется при просмотре галереи между большими изображениями и основным содержимым страницы. Значение может изменяться от 0 до 1. По умолчанию используется значение 0.9.<br />
<strong>padding</strong> &#8211; по умолчанию null, но можно указать число, которое будет определять отступы вокруг просматриваемого изображения.<br />
<strong>rel</strong> &#8211; по умолчанию &#8216;lightbox&#8217;, определяет значение в атрибуте rel тега а (см. пример html-разметки), исходя из которого плагин автоматически формирует галереи. Можно передать строку, в которой определить любое удобное значение.<br />
<strong>auto_relify</strong> &#8211; по умолчанию true, плагин должен автоматически искать и формировать галереи. Чтобы отменить такое поведение следует передать значение false.</p>
<blockquote><p><strong>Выводы:</strong> Плюсы &#8211; неплохое оформление, большинство опций действительно полезны. Минусы &#8211; сложности с настройкой плагина с учетом поддержки IE6, не все опции удается использовать так, как заявлено разработчиком, не работает ни с каким другим контентом, кроме фото. Имхо, минусов больше, причем перечислены еще не все.</p></blockquote>
<h3>Галерея NFLightBox</h3>
<p>По сравнению с обычным LightBox не имеет таких заморочек с настройкой под все основные браузеры, но точно также работает только с фото. Однако имеет возможность автоматической смены изображений &#8211; слайдшоу.</p>
<p>Смотрим <a href="http://www.linkexchanger.su/examples_2009/galleries/NFLightBox/demo.html" target="_blank">демо</a>, замечаем отличия от LightBox&#8230;</p>
<p>Подключается просто:</p>
<pre class="brush: xml;">&lt;link type=&quot;text/css&quot; href=&quot;css/nf.lightbox.css&quot; rel=&quot;stylesheet&quot; /&gt;
&lt;script src=&quot;js/jquery-1.3.2.min.js&quot; type=&quot;text/javascript&quot;&gt;&lt;/script&gt;
&lt;script src=&quot;js/NFLightBox.js&quot; type=&quot;text/javascript&quot;&gt;&lt;/script&gt;</pre>
<p>В разделе HEAD надо указать пути к файлу стилевого оформления, файлу библиотеки jQuery и файлу плагина. Требования к разметке точно такие же, как и у LightBox.</p>
<pre class="brush: xml;">&lt;a href=&quot;images/large.jpg&quot; title=&quot;Какой-то текст&quot;&gt;
&lt;img src=&quot;images/small.jpg&quot; /&gt;
&lt;/a&gt;</pre>
<p>Создается галерея с помощью следующего jQuery-кода:</p>
<pre class="brush: jscript;">$('a').lightBox({
  overlayBgColor: '#363',
  txtImage: 'Фото',
  txtOf: 'из',
  txtPrev: ' Назад',
  txtNext: ' Вперед',
  keyToClose: 'q',
  keyToPrev: 'z',
  keyToNext: 'c'
});</pre>
<p>Этот плагин тоже имеет приличное количество настроек. Использование некоторых показано в приведенном выше коде. Довольно полезная опция overlayBgColor &#8211; позволяет менять цвет промежуточного слоя между просматриваемым изображением и содержимым веб-страницы. В LightBox для этого пришлось бы править css-файл.</p>
<p>Чуть подробнее про опции, которые можно использовать для настройки.</p>
<p><strong>overlayBgColor</strong> &#8211; по умолчанию #000 (черный), используется для задания цвета промежуточного слоя.<br />
<strong>overlayOpacity</strong> &#8211; по умолчанию 0.8, задает прозрачность промежуточного слоя. Можно использовать значения от 0 до 1.<br />
<strong>imageLoading, imageBtnPrev, imageBtnNext, imageBtnClose, imageBlank, imageBtnBottomPrev, imageBtnBottomNext, imageBtnPlay, imageBtnStop</strong> &#8211; во всех этих опциях можно передать строку, содержащую путь к файлу изображения соответствующего элемента управления.<br />
<strong>containerBorderSize</strong> &#8211; по умолчанию 10, определяет ширину рамки вокруг просматриваемого изображения.<br />
<strong>containerResizeSpeed</strong> &#8211; по умолчанию 500, время в миллисекундах, за которое будет изменяться размеры области просмотра изображения при переходе от одного изображения к другому.<br />
<strong>txtImage, txtOf, txtPrev, txtNext</strong> &#8211; вполне понятные опции. Например задав значения txtImage: &#8216;Фото&#8217; и txtOf:&#8217;из&#8217; Вы уже будете видеть не Image 1 of 8, а Фото 1 из 8.<br />
<strong>keyToClose, keyToPrev, keyToNext</strong> &#8211; с помощью этих опций можно задать &laquo;горячие&raquo; клавиши. Например keyToClose:&#8217;q&#8217; &#8211; при нажатии клавиши &#8216;q&#8217; просмотр будет прекращен.<br />
<strong>slideShowTimer</strong> &#8211; по умолчанию 5000, т.е.если Вы запустите слайдшоу, то изображения будут меняться каждые 5 секунд.</p>
<blockquote><p><strong>Выводы:</strong> Плюсы &#8211; неплохое оформление, большинство опций действительно полезны, есть автоматическая смена фото при просмотре, нет сложностей с настройкой. Минусы &#8211; png-файлы для элементов управления не очень здорово выглядят в IE6 (и к сожалению jquery.pngfix.js тут не поможет), не работает ни с каким другим контентом, кроме фото. Имхо, лучше, чем стандартный LightBox, но все же не то, что хочется.</p></blockquote>
<h3>Галерея PrettyPhoto</h3>
<p>Так и хочется написать &#8211; PrettyPhoto мой выбор! Во-первых, этот плагин позволяет работать не только с фото. В области просмотра можно выводить видео с YouTube, ролики в формате .mov (Apple QuickTime), содержимое во flash-формате и наконец вообще любой контент через iframe. Во-вторых, этот плагин имеет свой API, чего нет в рассмотренных ранее плагинах.<br />
Смотрим <a href="http://www.linkexchanger.su/examples_2009/galleries/prettyPhoto/demo.html" target="_blank">демо</a>, отмечаем отличия от других галерей и начинаем разговор про PrettyPhoto.</p>
<p>Сначала необходимо подключить к веб-страницы файл библиотеки jquery-1.3.2.js, файл плагина jquery.prettyPhoto.js и файл стилевого оформления плагина prettyPhoto.css.</p>
<pre class="brush: xml;">&lt;link type=&quot;text/css&quot; href=&quot;css/prettyPhoto.css&quot; rel=&quot;stylesheet&quot; /&gt;
&lt;script src=&quot;js/jquery-1.3.2.min.js&quot; type=&quot;text/javascript&quot;&gt;&lt;/script&gt;
&lt;script src=&quot;js/jquery.prettyPhoto.js&quot; type=&quot;text/javascript&quot;&gt;&lt;/script&gt;</pre>
<p>Организация галереи (или галерей) почти не отличается от того, как это делается в LightBox.</p>
<pre class="brush: xml;">&lt;a rel=&quot;prettyPhoto[gallery_1]&quot; href=&quot;max/1.jpg&quot; title=&quot;Фото номер 1&quot;&gt;
&lt;img src=&quot;min/1.jpg&quot; alt=&quot;Фото номер 1&quot; /&gt;
&lt;/a&gt;</pre>
<p>Картинка-миниатюра заключена в тэг а, атрибут href которого указывает на соответствующее полноразмерное изображение. В атрибуте rel содержится ключевое слово &#8211; prettyPhoto. Чтобы создать несколько различных галерей на обной веб-странице, в атрибуте rel следует указать например &#8211; prettyPhoto[gallery_easy] для условной первой галереи, prettyPhoto[other_gallery] &#8211; для другой и так далее&#8230;</p>
<p>С помощью jQuery-кода создаем галерею. Используем настройки, установленные по умолчанию.</p>
<pre class="brush: jscript;">$(function(){
  $(&quot;a[rel^='prettyPhoto']&quot;).prettyPhoto();
});</pre>
<p>Опции, которые можно использовать для настройки prettyPhoto:<br />
<strong>animationSpeed</strong> &#8211; по умолчанию &#8216;normal&#8217;. Другие возможные значения &#8211; &#8216;fast&#8217; и &#8217;slow&#8217;. Скорость анимации изменения размеров окна просмотра при переходе от одного изображения к другому.<br />
<strong>padding</strong> &#8211; по умолчанию 40. Число, опредяляющее отступы вокруг изображения.<br />
<strong>opacity</strong> &#8211; по умолчанию 0.80, прозрачность промежуточного слоя. Изменяется от 0 до 1.<br />
<strong>showTitle</strong> &#8211; по умолчанию true. Заголовок (содержимое атрибута title тэга а), который отображается в левом верхнем углу над областью просмотра. Чтобы отключить надо использовать значение false.<br />
<strong>allowresize</strong> &#8211; по умолчанию true. По умолчанию полноразмерное изображение масштабируется, если ему не хватает места для отображения в полном размере. Можно отменить это поведение, передав false.<br />
<strong>counter_separator_label</strong> &#8211; по умолчанию &#8216;/&#8217;. Разделитель в счетчика изображений галереи.<br />
<strong>theme</strong> &#8211; по умолчанию &#8216;light_rounded&#8217;. Да! Плагин поддерживает несколько тем оформления. Кроме light_rounded возможны также dark_rounded, light_square, dark_square. Вот только для IE6 принудительно используется тема light_square (светлый фон и нескругленные углы).<br />
<strong>hideflash</strong> &#8211; по умолчанию false. Скрывает все flash-объекты на странице при просмотре галереи, чтобы они не отображались поверх. Если этого не требуется, можно установить значение true.<br />
<strong>modal</strong> &#8211; по умолчанию false. Если установить true, будет использоваться модальный режим, т.е. завершить просмотр галереи можно будет только нажатием на картинку &#8216;close&#8217;.</p>
<p>Еще две полезные опции, в которых можно определить callback-функции, вызываемые при наступлении определенного события.<br />
<strong>changepicturecallback</strong> &#8211; функция, определенная в этой опции, будет вызываться каждый раз при смене изображения галереи.<br />
<strong>callback</strong> &#8211; функция, определенная в этой опции, будет вызываться при завершении просмотра.</p>
<p>Плюс ко всем этим полезным опциям, плагин предоставляет четыре метода.</p>
<p><em>$.prettyPhoto.open(&#8216;path/to/image&#8217;,'Title&#8217;,'Description&#8217;)</em> &#8211; метод позволяет открыть нужную галерею. Пример будет чуть позже.<br />
<em>$.prettyPhoto.changePage(&#8216;next&#8217;)</em> &#8211; с помощью этого метода можно осуществить переход к следующему изображению галереи.<br />
<em>$.prettyPhoto.changePage(&#8216;previous&#8217;)</em> &#8211; с помощью этого метода можно осуществить переход к предыдущему изображению галереи.<br />
<em>$.prettyPhoto.close()</em> &#8211; с помощью этого метода можно закрыть галерею.</p>
<p>Самый большой интерес наверняка вызовет метод, с помощью которого можно открыть галерею практически как угодно и откуда угодно. Поэтому смотрим <a href="http://www.linkexchanger.su/examples_2009/galleries/prettyPhoto/demo2.html" target="_blank">демо</a>. Код там настолько несложный и понятный даже интуитивно, что не стоит его и комментировать.</p>
<p>В общем эта галерея может удовлетворить наверное все потребности веб-мастеров. Кроме одной &#8211; слайд-шоу. Чтобы не было обидно, давайте попробуем немного доработать предыдущий пример. Мы дополнительно подключим плагин jquery.timers.js и воспользуемся тем фактом, что в опциях changepicturecallback и callback можно определить функции. В html-разметке добавим select, откуда можно будет выбирать значения задержки при смене изображений. Что из этого получилось, смотрите <a href="http://www.linkexchanger.su/examples_2009/galleries/prettyPhoto/demo3.html" target="_blank">демо</a>, там же можно посмотреть и исходный код.</p>
<p>В опции changepicturecallback, пользуясь возможностями плагина jQuery Timers, при смене изображений каждый раз запускаем одноразовый таймер со значением, полученным из выбранной опции в селекте. По срабатыванию таймера вызываем метод $.prettyPhoto.changePage(&#8216;next&#8217;) заставляя плагин показывать следующее изображение. В опции callback определяем функцию, которая останавливает таймер, если галерея была закрыта и заодно, с помощью alert благодарим за просмотр.</p>
<p>На самом деле такое решение небезгрешно, но зато сделано &laquo;на колене в 5 секунд&raquo;, поэтому кто имеет желание, может в комментариях предлагать свои идеи по этому поводу.</p>
<blockquote><p>Все примеры, использованные в этой статье, лежат в этом <a href="http://www.linkexchanger.su/examples_2009/galleries/demo.zip">архиве</a>.</p></blockquote>
<p>Для тех, кто хочет самостоятельно изучить первоисточники, пожалуйста, ссылки: <a href="http://www.balupton.com/sandbox/jquery_lightbox_bal/demo/">LightBox</a>, <a href="http://www.notesfor.net/post/NotesForLightBox.aspx">NFLightBox</a>, <a href="http://www.no-margin-for-errors.com/projects/prettyPhoto-jquery-lightbox-clone/">PrettyPhoto</a>.</p>
<blockquote><p><strong>Выводы:</strong> для себя выбрал именно PrettyPhoto&#8230;. по крайней мере пока не появилось что-нибудь еще лучше.</p></blockquote>
]]></content:encoded>
			<wfw:commentRss>http://www.linkexchanger.su/2009/112.html/feed</wfw:commentRss>
		<slash:comments>70</slash:comments>
		</item>
		<item>
		<title>jQuery UI &#8211; плагин Sortable</title>
		<link>http://www.linkexchanger.su/2009/111.html</link>
		<comments>http://www.linkexchanger.su/2009/111.html#comments</comments>
		<pubDate>Fri, 09 Oct 2009 05:07:24 +0000</pubDate>
		<dc:creator>Gennady</dc:creator>
				<category><![CDATA[jQuery UI]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[Sortable]]></category>
		<category><![CDATA[UI]]></category>

		<guid isPermaLink="false">http://www.linkexchanger.su/2009/111.html</guid>
		<description><![CDATA[Плагин Sortable &#8211; один из нескольких плагинов, входящих в состав jQuery UI, с помощью которых можно организовать взаимодействие с элементами веб-станиц. Плагин Sortable предоставляет возможность организовать сортировку элементов, перемещая их с помощью указателя мыши.

Читаем, и пробуем проделать все это самостоятельно.
Для начала посетим страницу настраиваемой закачки на сайте jQuery UI, чтобы получить необходимые нам файлы. Щелкаем [...]]]></description>
			<content:encoded><![CDATA[<p>Плагин <strong>Sortable</strong> &#8211; один из нескольких плагинов, входящих в состав <strong>jQuery UI</strong>, с помощью которых можно организовать взаимодействие с элементами веб-станиц. Плагин Sortable предоставляет возможность организовать сортировку элементов, перемещая их с помощью указателя мыши.<br />
<iframe src="http://www.linkexchanger.su/examples_2009/ui_sortable/example-one.html" style="border: 1px solid #6699cc; overflow: hidden" height="320" width="418"></iframe><br />
Читаем, и пробуем проделать все это самостоятельно.<span id="more-111"></span></p>
<p>Для начала посетим страницу <a href="http://jqueryui.com/download">настраиваемой закачки</a> на сайте jQuery UI, чтобы получить необходимые нам файлы. Щелкаем на ссылке <strong>Deselect all component</strong>, чтобы не закачивать лишнее, а затем выбираем только то, что нам потребуется &#8211; отмечаем <strong>чекбокс Sortable</strong> и видим, что вместе с ним отметились <strong>чекбоксы UI Core и Draggable</strong>. Работа плагина Sortable зависит от них, поэтому они необходимы.<br />
Кроме этого, справа есть выпадающий список, где можно выбрать понравившуюся тему оформления. Если все готово, кликаем кнопку <strong>Download</strong> и получаем архив.</p>
<p>Сначала в разделе HEAD подключаем несколько файлов, которые есть в архиве:</p>
<pre class="brush: xml;">&lt;link type=&quot;text/css&quot; href=&quot;css/sunny/jquery-ui-1.7.2.custom.css&quot; rel=&quot;stylesheet&quot; /&gt;
&lt;script src=&quot;js/jquery-1.3.2.min.js&quot; type=&quot;text/javascript&quot;&gt;&lt;/script&gt;
&lt;script src=&quot;js/jquery-ui-1.7.2.custom.min.js&quot; type=&quot;text/javascript&quot;&gt;&lt;/script&gt;</pre>
<p>Здесь мы подключили файл стилей css/sunny/jquery-ui-1.7.2.custom.css одной из многочисленных тем оформления. Хотите использовать Ваше собственное оформление &#8211; пожалуйста, но в примере мы используем готовое. Кроме этого мы подключили файл библиотеки – js/jquery-1.3.2.min.js и файл js/jquery-ui-1.7.2.custom.min.js, в котором объединена функциональность ядра UI и плагинов Sortable и Draggable.</p>
<p>Смотрим HTML-разметку. Пусть у нас она будет выглядеть так:</p>
<pre class="brush: xml;">&lt;ul id=&quot;sortable&quot;&gt;
  &lt;li class=&quot;ui-state-default&quot;&gt;Item 1&lt;/li&gt;
  &lt;li class=&quot;ui-state-default&quot;&gt;Item 2&lt;/li&gt;
  &lt;li class=&quot;ui-state-default&quot;&gt;Item 3&lt;/li&gt;
  &lt;li class=&quot;ui-state-default&quot;&gt;Item 4&lt;/li&gt;
  &lt;li class=&quot;ui-state-default&quot;&gt;Item 5&lt;/li&gt;
  &lt;li class=&quot;ui-state-default&quot;&gt;Item 6&lt;/li&gt;
  &lt;li class=&quot;ui-state-default&quot;&gt;Item 7&lt;/li&gt;
&lt;/ul&gt;</pre>
<p>и следующий javascript-код, который применит к выбранному элементу функциональность плагина Sortable.</p>
<pre class="brush: jscript;">$(function(){
  $(&quot;#sortable&quot;).sortable();
});</pre>
<blockquote><p><a href="http://www.linkexchanger.su/examples_2009/ui_sortable/example-one.html" target="_blank">Открыть пример в новом окне</a></p></blockquote>
<p>В этом примере мы использовали плагин с настройками по умолчанию, но поскольку его можно очень гибко настраивать с помощью большого количества различных опций, то обязательно надо познакомиться с тем, как это делается. В следующем примере мы передадим плагину пару опций.</p>
<pre class="brush: jscript;">$(function(){
  $(&quot;#sortable&quot;).sortable({
  	placeholder: &quot;ui-state-highlight&quot;,
  	opacity: 0.6
  });
});</pre>
<blockquote><p><a href="http://www.linkexchanger.su/examples_2009/ui_sortable/example-two.html" target="_blank">Открыть пример в новом окне</a></p></blockquote>
<p>Опция placeholder передает плагину имя css-класса, который будет применен к той позиции, откуда элемент начал перемещение (или куда он может быть помещен), а опция opacity устанавливает прозрачность элемента во время перемещения. Значения остальных опций передаются плагину подобным образом.</p>
<p><strong>appendTo</strong> &#8211; по умолчанию эта опция имеет значение &#8216;parent&#8217;. В ней можно передать селектор jQuery или элемент, который будет использован в качестве контейнера для объекта, представляющего сортируемый элемент во время его перемещения.<br />
<strong>axis</strong> &#8211; в качестве значения используется строка. Доступные значения &#8216;x&#8217; или &#8216;y&#8217;. По умолчанию установлено false. Если определить эту опцию, сортируемые элементы смогут перемещаться только по вертикали или горизонтали.<br />
<strong>cancel</strong> &#8211; в качестве значения используется селектор jQuery. Предотвращает сортировку, если она начинается на элементе, указанном в это опции. По умолчанию используется значение &#8216;:input,button&#8217;.<br />
<strong>connectWith</strong> &#8211; в качестве значения принимает селектор jQuery, где можно указать другой сортируемый список, в который можно будет перемещать сортируемые элементы, таким образом, что они станут частью другого сортируемого списка.<br />
<strong>containment</strong> &#8211; ограничивает перемещение внутри определенного элемента или области. В качестве значения может принимать селектор jQuery, элемент или строку. Примеры возможных значений: &#8216;parent&#8217;, &#8216;document&#8217;, &#8216;window&#8217;. По умолчанию – false.<br />
<strong>cursor</strong> &#8211; строка, определяющая вид курсора в процессе перемещения элемента. По умолчанию установлено значение &#8216;auto&#8217;.<br />
<strong>cursorAt</strong> &#8211; объект, который определяет положение указателя мыши во время перемещения элемента. Для задания координат используется комбинация одного или двух свойств из четырех возможных &#8211; &#8216;top&#8217;, &#8216;right&#8217;, &#8216;bottom&#8217; и &#8216;left&#8217;. Например: {top: 10, left: 20} или {bottom: 5}. По умолчанию – false.<br />
<strong>delay</strong> &#8211; число, указанное в этой опции, определяет отсрочку начала перемещения элемента. Указывается в миллисекундах. Опция помогает предотвратить нежелательное перемещение элемента во время случайного щелчка мышью. По умолчанию используется значение 0.<br />
<strong>distance</strong> &#8211; число в пикселах, определяющее расстояние, которое должен пройти указатель мыши (с одновременно нажатой левой клавишей), чтобы начался процесс перемещения элемента. Опция помогает предотвратить нежелательное перемещение элемента во время случайного щелчка мышью. По умолчанию используется значение 1.<br />
<strong>dropOnEmpty</strong> &#8211; по умолчанию используется значение true. В этом случае, если один из связанных списков пустой, в него можно перемещать элементы из другого списка. Если установить значение false, эта возможность будет запрещена.<br />
<strong>grid</strong> &#8211; по умолчанию – false. Значением может быть массив из двух чисел, определяющий шаг сетки, по которой будет перемещаться сортируемый элемент. Например: grid: [20,20]<br />
<strong>handle</strong> &#8211; по умолчанию установлено значение false. В качестве значения можно указать селектор jQuery или элемент. В этом случае процесс сортировки можно будет начать только в том случае, если левая клавиша мыши нажата в момент нахождения указателя мыши над элементом, определенным в этой опции.<br />
<strong>helper</strong> &#8211; по умолчанию используется значение &#8216;original&#8217;. В этом случае, при сортировке, перемещаемый элемент представлен самим элементом. Другое возможное значение &#8216;clone&#8217;. В этом случае элемент при перемещении представлен своей копией.<br />
<strong>items</strong> &#8211; в качестве значения используется селектор jQuery. По умолчанию установлено значение &#8216;&gt; *&#8217;. Опция определяет, какие элементы, являющиеся элементами-потомками того элемента, с которым связана функциональность плагина, могут быть сортируемыми.<br />
<strong>opacity</strong> &#8211; значение опции может изменяться от 0.01 до 1 и определяет прозрачность перемещаемого элемента. По умолчанию – false.<br />
<strong>placeholder</strong> &#8211; имя css-класса, который будет применен к той позиции, откуда элемент начал перемещение. Если значение опции не определено «пустая» позиция никак не оформляется.<br />
<strong>revert</strong> &#8211; по умолчанию используется значение false. Если использовать значение true, то при перемещении элемента, после того, как будет отпущена клавиша мыши, элемент переместится на свою новую позицию с использованием плавного анимационного эффекта.<br />
<strong>scroll</strong> &#8211; по умолчанию установлено значение true – при перемещении элемента к краю области просмотра, она автоматически прокручивается бесконечно. Если установить значение false, эта возможность будет запрещена.<br />
<strong>scrollSensitivity</strong> &#8211; число, определяющее расстояние в пикселах от края области просмотра, после которого она начинает прокручиваться. Расстояние определяется относительно указателя мыши, а не перемещаемого элемента. По умолчанию установлено значение 20.<br />
<strong>scrollSpeed</strong> &#8211; число, определяющее скорость, с которой прокручивается область просмотра при приближении указателя мыши к ее краю на расстояние определенное в опции scrollSensitivity. По умолчанию установлено значение 20.<br />
<strong>tolerance</strong> &#8211; по умолчанию эта опция имеет значение &#8216;intersect&#8217;. При этом элемент, перемещаемый во время сортировки должен перекрыть любой другой сортируемый элемент как минимум на 50%, чтобы тот «освободил» занимаемое место. Другое возможное значение &#8211; &#8216;pointer&#8217;. При этом над сортируемым элементом должен оказаться только указатель мыши.<br />
<strong>zIndex</strong> &#8211; число, которое определяет значение css-свойства z-index для элемента в момент его сортировки.</p>
<p>Настало время познакомиться с событиями, на которые умеет реагировать плагин Sortable. Пример использования одного из возможных событий плагина приведен в следующем примере:</p>
<pre class="brush: jscript;">$(function(){
  $(&quot;#sortable&quot;).sortable({
  	placeholder: &quot;ui-state-highlight&quot;,
  	opacity: 0.6,
  	stop: function(event, ui) {
  	  alert(event.type);
  	}
  });
});</pre>
<blockquote><p><a href="http://www.linkexchanger.su/examples_2009/ui_sortable/example-three.html" target="_blank">Открыть пример в новом окне</a></p></blockquote>
<p>Здесь мы использовали только опцию stop, в которой определили функцию, которая будет вызвана в момент окончания сортировки. Функция может принимать два аргумента. Первый аргумент – объект события, второй – специальный объект ui, в свойствах которого можно обнаружить разнообразную полезную информацию. Но в приведенном примере мы используем только свойство type объекта события, чтобы вывести в окне предупреждения название события, вызвавшего нашу функцию.</p>
<p>А вот пример того, как можно использовать специальный объект ui:</p>
<pre class="brush: jscript;">$(function(){
  $(&quot;#sortable&quot;).sortable({
    placeholder: &quot;ui-state-highlight&quot;,
    opacity: 0.6,
    helper: &quot;clone&quot;,
    change: function(event, ui) {
      ui.helper.css(&quot;color&quot;,&quot;#f00&quot;);
    }
  });
});</pre>
<blockquote><p><a href="http://www.linkexchanger.su/examples_2009/ui_sortable/example-four.html" target="_blank">Открыть пример в новом окне</a></p></blockquote>
<p>Мы использовали опцию change, чтобы вызвать функцию в момент изменения положения сортируемого элемента. Внутри функции мы обращаемся к одному из свойств объекта ui – к свойству helper. Это свойство является объектом, который представляет перемещаемый элемент во время сортировки. Используя метод css(name,value) мы устанавливаем красный цвет шрифта на перемещаемом элементе. Но, как только этот элемент займет свое новое место в списке, цвет шрифта вернется к исходному значению. Догадались почему? Если нет, то обратите внимание на опцию helper. Установив значение clone в этой опции, мы использовали во время перемещения не сам исходный объект, а его копию.<br />
Кстати, helper – это не единственное полезное свойство объекта ui, есть и другие:</p>
<p><strong>ui.helper</strong> – объект, характеризующий элемент, находящийся в процессе перемещения;<br />
<strong>ui.position</strong> – объект, в свойствах top и left которого содержится информация о положении перемещаемого элемента относительно родительского элемента;<br />
<strong>ui.offset</strong> – объект, в свойствах top и left которого содержится информация об абсолютном положении перемещаемого элемента;<br />
<strong>ui.item</strong> – объект, представляющий сортируемый элемент;<br />
<strong>ui.placeholder</strong> – объект, представляющий место, откуда был перемещен сортируемый элемент (или куда он будет перемещен);<br />
<strong>ui.sender</strong> – объект, который представляет элемент-контейнер для сортируемых элементов, откуда сортируемый элемент был перемещен (при использовании связанных списков);</p>
<p>Ниже перечислены опции, связанные с событиями плагина Sortable, их довольно много:<br />
Опция <strong>start</strong> &#8211; событие <em>sortstart</em> наступает в момент начала сортировки.<br />
Опция <strong>sort</strong> &#8211; событие <em>sort</em> наступает постоянно в течение сортировки.<br />
Опция <strong>change</strong> &#8211; событие <em>sortchange</em> наступает во время сортировки, но только в том случае, если изменилось положение сортируемого элемента в объектной модели документа.<br />
Опция <strong>beforeStop</strong> &#8211; событие <em>sortbeforeStop</em> наступает в момент сортировки, перед ее окончанием (когда отпущена левая клавиша мыши).<br />
Опция <strong>stop</strong> &#8211; событие <em>sortstop</em> наступает в момент окончания сортировки.<br />
Опция <strong>update</strong> &#8211; событие <em>sortupdate</em> наступает в момент окончания сортировки, но только в том случае, если порядок сортируемых элементов был изменен.<br />
Опция <strong>receive</strong> &#8211; событие <em>sortreceive</em> наступает, когда связанный сортируемый список принимает элемент из другого списка.<br />
Опция <strong>remove</strong> &#8211; событие <em>sortremove</em> наступает, когда элемент покидает один связанный список, и перемещается в другой.<br />
Опция <strong>over</strong> &#8211; событие <em>sortover</em> наступает, когда сортируемый элемент перемещен в связанный список.<br />
Опция <strong>out</strong> &#8211; событие <em>sortout</em> наступает, когда сортируемый элемент перемещен из связанного списка.<br />
Опция <strong>activate</strong> &#8211; событие <em>sortactivate</em> наступает при использовании связанных списков, для каждого связанного списка при начале процесса сортировки.<br />
Опция <strong>deactivate</strong> &#8211; событие <em>sortdeactivate</em> наступает при использовании связанных списков, для каждого связанного списка при окончании процесса сортировки.</p>
<p>А теперь &#8211; методы плагина. С помощью методов можно управлять плагином после инициализации. Сначала добавим кнопочку в HTML-разметку:</p>
<pre class="brush: xml;">&lt;button id=&quot;cancelSort&quot;&gt;Cancel Sort&lt;/button&gt;</pre>
<p>и небольшой пример:</p>
<pre class="brush: jscript;">$(function(){
  $(&quot;#sortable&quot;).sortable({
  	placeholder: &quot;ui-state-highlight&quot;,
  	opacity: 0.6
  });
  $(&quot;#cancelSort&quot;).click(function(){
  	$(&quot;#sortable&quot;).sortable(&quot;cancel&quot;);
  });
});</pre>
<blockquote><p><a href="http://www.linkexchanger.su/examples_2009/ui_sortable/example-five.html" target="_blank">Открыть пример в новом окне</a></p></blockquote>
<p>Метод .sortable(&laquo;cancel&raquo;) использованный в примере, один из самых полезных методов плагина. Он позволяет отменить результат последней операции сортировки и вернуть элементы к предшествующему состоянию.<br />
Обратите внимание на элемент button с идентификатором #cancelSort. С кнопкой связан обработчик события click, по которому и вызывается метод соответствующий метод.<br />
Если Вы попробуете переместить один из элементов с писка на новое место, а затем нажать на кнопку cancelSort, список вернется в предыдущее состояние.</p>
<p>Но конечно, этот метод не единственный. Вот другие:<br />
<strong>destroy</strong> &#8211; .sortable(&#8216;destroy&#8217;) полностью удаляет всю функциональность плагина Sortable. Возвращает элементы в состояние, предшествующее инициализации.<br />
<strong>disable</strong> &#8211; .sortable(&#8216;disable&#8217;) временно запрещает использование всей функциональности плагина. Вновь разрешить ее использование можно с помощью метода enable.<br />
<strong>enable</strong> &#8211; .sortable(&#8216;enable&#8217;) разрешает использование всей функциональности плагина, если ранее она была запрещена с использованием метода disable.<br />
<strong>option</strong> &#8211; .sortable(&#8216;option&#8217;, optionName, [value]) с помощью этого метода можно получить или установить значение любой опции плагина после инициализации.<br />
<strong>serialize</strong> &#8211; .sortable(&#8217;serialize&#8217;, [option]) упорядочивает значение атрибутов id элементов сортируемого списка в строку, которую можно передать на сервер с помощью ajax-запроса. Предъявляет требования к формату записи значения атрибута id. Допустимые форматы: id=&#8217;name_number&#8217; или id=&#8217;name-number&#8217;. В этом случае вид строки получается &#8216;name[]=number&amp; name[]=number&#8217;. Вторым, необязательным параметром, можно передать объект. Возможные значения: &#8216;key&#8217; – заменит часть &#8216;name[]&#8216; на необходимую Вам, &#8216;attribute&#8217; – попробует получить значения из атрибута, отличного от id, &#8216;expression&#8217; – можно использовать свое регулярное выражение.<br />
<strong>toArray</strong> &#8211; .sortable(&#8216;toArray&#8217;) упорядочивает значение атрибутов id элементов сортируемого списка в массив.<br />
<strong>cancel</strong> &#8211; .sortable(&#8216;cancel&#8217;) отменяет результат последней операции сортировки и возвращает элемент в состояние, предшествующее этой операции. Метод полезен при использовании в callback-функциях, связанных с событиями stop или receive.</p>
<p>Ну, и &laquo;на сладкое&raquo; &#8211; конечно обязательно надо дать пример использования связанных списков.</p>
<pre class="brush: jscript;">$(function(){
  $(&quot;#sortable1, #sortable2&quot;).sortable({
  	connectWith: &quot;.connectedSortable&quot;,
  	tolerance: &quot;pointer&quot;
  });
});</pre>
<blockquote><p><a href="http://www.linkexchanger.su/examples_2009/ui_sortable/example-six.html" target="_blank">Открыть пример в новом окне</a></p></blockquote>
<p>Я привел пример только javascript-кода, поскольку в HTML-коде страницы ничего особенного нет – просто два ненумерованных списка #sortable1 и #sortable2. С помощью javascript-кода мы сделаем их сортируемыми, указав их идентификаторы в селекторе jQuery и связав с ними функциональность Sortable. Самое главное заключается в использовании опции connectWith. Здесь мы указываем имя класса для того списка, который хотим сделать связанным с другим списком.<br />
Обратите внимание, что атрибут class со значением connectedSortable мы присвоили обоим спискам и добились того, что элементы могут перемещаться не только из первого списка во второй, но и наоборот. Если бы мы захотели организовать только «одностороннее движение», скажем из первого списка во второй, мы бы присвоили класс connectedSortable только второму списку.</p>
<p>Теперь сортируемые элементы можно переносить из одного списка в другой и элемент, перемещенный из одного списка в другой, становится частью другого списка.</p>
<blockquote><p>Все примеры, использованные в статье, можно совершенно запросто получить в этом <a href="http://www.linkexchanger.su/examples_2009/ui_sortable/ui_sortable.zip">архиве</a>.</p></blockquote>
]]></content:encoded>
			<wfw:commentRss>http://www.linkexchanger.su/2009/111.html/feed</wfw:commentRss>
		<slash:comments>74</slash:comments>
		</item>
	</channel>
</rss>
