<?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>SimpleCoding.org &#187; Ajax</title>
	<atom:link href="http://www.simplecoding.org/category/aj/feed" rel="self" type="application/rss+xml" />
	<link>http://www.simplecoding.org</link>
	<description>Блог о программировании</description>
	<lastBuildDate>Fri, 27 Jan 2012 18:27:45 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=</generator>
		<item>
		<title>jQuery: обработка параметров URL</title>
		<link>http://www.simplecoding.org/jquery-obrabotka-parametrov-url.html</link>
		<comments>http://www.simplecoding.org/jquery-obrabotka-parametrov-url.html#comments</comments>
		<pubDate>Fri, 19 Aug 2011 07:45:55 +0000</pubDate>
		<dc:creator>Владимир</dc:creator>
				<category><![CDATA[Ajax]]></category>
		<category><![CDATA[HTML]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Web разработка]]></category>

		<guid isPermaLink="false">http://www.simplecoding.org/?p=1225</guid>
		<description><![CDATA[Приветствую всех! Сегодня хочу показать небольшой пример использования библиотеки jQuery для работы с параметрами ссылок. Предположим на нашей странице есть ссылка, клик по которой отправляет запрос на выполнение некоторой операции. Пускай это будет удаление какого-нибудь объекта. HTML разметка такой ссылки может выглядеть следующим образом. &#60;a class="delete" href="http://www.simplecoding.org/script.php?action=delete_object&#38;object_id=1"&#62;Удалить&#60;/a&#62; Как видите, ссылка содержит два параметра (action и [...]]]></description>
			<content:encoded><![CDATA[<div id="attachment_1226" class="wp-caption alignnone" style="width: 299px"><img src="http://www.simplecoding.org/wp-content/uploads/2011/08/jquery_parsequery.png" alt="jquery parsequery" title="jquery parsequery" width="289" height="152" class="size-full wp-image-1226" style="float:left" /><p class="wp-caption-text"> </p></div>
<p><strong>Приветствую всех!</strong></p>
<p>Сегодня хочу показать небольшой пример использования библиотеки <strong>jQuery</strong> для работы с параметрами ссылок.</p>
<p>Предположим на нашей странице есть ссылка, клик по которой отправляет запрос на выполнение некоторой операции. Пускай это будет удаление какого-нибудь объекта.</p>
<p><strong>HTML разметка</strong> такой ссылки может выглядеть следующим образом.</p>
<pre class="brush: html">&lt;a class="delete" href="http://www.simplecoding.org/script.php?action=delete_object&amp;object_id=1"&gt;Удалить&lt;/a&gt;</pre>
<p>Как видите, ссылка содержит два параметра (<code>action</code> и <code>object_id</code>), значения которых PHP скрипт сможет получить из массива <code>$_GET</code>.</p>
<p>Теперь, мы хотим выполнить удаление объекта с помощью <strong>AJAX запроса</strong>. Изменять ради него ссылку нет никакой необходимости. Просто назначаем обработчик для события <code>click</code>.<br />
<span id="more-1225"></span></p>
<pre class="brush: javascript">$('a.delete').click(function() {
  return false;
});</pre>
<p>Этот код блокирует отправку обычного запроса при клике по ссылке. Нам нужно <strong>получить параметры и отправить AJAX запрос</strong>.</p>
<p>В обработчике события <strong>click</strong> получить значение атрибута <strong>href</strong> ссылки можно следующим образом.</p>
<pre class="brush: javascript">$(this).attr('href')</pre>
<p>Затем нужно найти в этой строке параметры. Тут есть <strong>два варианта</strong>.</p>
<p>1) Если вам достаточно параметров, указанных в атрибуте <strong>href</strong> и вы не хотите их изменять, то просто передать методам <code>$.ajax</code> (или <code>$.post</code>, или <code>$.get</code>) строку с параметрами запроса.</p>
<p>Т.е. код будет выглядеть примерно так</p>
<pre class="brush: javascript">var params = $(this).attr('href').split('?');
$.post('ajax_delete.php', params[1], function(response) {
    console.log(response);
} );</pre>
<p>Здесь мы с помощью метода <code>split</code> разбили запрос на две части (по знаку вопроса), и передали методу <code>$.post</code> второй элемент массива <code>params</code>. Для данного примера он выглядит так<br />
<code>action=delete_object&amp;object_id=1</code></p>
<p>2) Если перед отправкой AJAX запроса нужно изменить/удалить/добавить какие-то параметры, то удобнее всего преобразовать строку с параметрами в хеш.</p>
<p>Для этих целей существует специальный плагин – <a href="http://plugins.jquery.com/project/parseQuery">parseQuery</a></p>
<p>Использовать его можно так.</p>
<pre class="brush: javascript">var params = $.parseQuery($( this ).attr( 'href' ).split('?'));</pre>
<p>В результате вы получите хеш</p>
<pre class="brush: javascript">{
	action: delete_object,
	object_id: 1
}</pre>
<p>Код отправки AJAX запроса при этом не изменяется. Точно также передаёте переменную <code>params</code> во втором параметре метода <code>$.post</code>.</p>
<p>В заключение посмотрите код обработчика целиком.</p>
<pre class="brush: javascript">$(document).ready(function() {
	$('a.delete').click( function() {
		var params = $(this).attr('href').split('?');
		$.post('ajax_delete.php', params[1], function(response) {
			console.log(response);
		});
		return false;
	});
});</pre>
<p>Как видите, задача решается с помощью минимального количества кода. И если у посетителя будет отключен JavaScript, то ничего особенного не произойдет. При кликах по ссылкам будут отправляться обычные запросы.</p>
<p>Если есть вопросы или замечания, пишите.</p>
<p><strong>Успехов!</strong></p>
<p><em>Интересно почитать</em></p>
<p>Платежный модуль <a href="http://www.rugento.ru/robokassa-payment-module.html" target="_blank">Robokassa для Magento</a> с поддержкой.</p>
<p>Нужна фотокнига? В наличие <a href="http://printfotobook.ru/primery_fotoknig">фотокниги образцы</a>, множество видов дизайна и верстки</p>
]]></content:encoded>
			<wfw:commentRss>http://www.simplecoding.org/jquery-obrabotka-parametrov-url.html/feed</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>HTML5: загрузка файлов с помощью Drag &amp; Drop</title>
		<link>http://www.simplecoding.org/html5-zagruzka-fajlov-s-pomoshhyu-drag-drop.html</link>
		<comments>http://www.simplecoding.org/html5-zagruzka-fajlov-s-pomoshhyu-drag-drop.html#comments</comments>
		<pubDate>Thu, 21 Jul 2011 13:13:41 +0000</pubDate>
		<dc:creator>Владимир</dc:creator>
				<category><![CDATA[Ajax]]></category>
		<category><![CDATA[HTML]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Web разработка]]></category>

		<guid isPermaLink="false">http://www.simplecoding.org/?p=1222</guid>
		<description><![CDATA[Приветствую всех! В этой статье хочу рассказать о нескольких своих экспериментах с HTML5. Начну издалека. Всем нам периодически приходится работать с различными web интерфейсами и часто возникает ощущение, что эта работа могла бы быть организована более эффективно. Возможно, в каких-то случаях виноваты разработчики сервиса, но часто проблема заключается в ограничениях, которые накладывают браузеры. Рассмотрим загрузку [...]]]></description>
			<content:encoded><![CDATA[<div id="attachment_1223" class="wp-caption alignnone" style="width: 310px"><img src="http://www.simplecoding.org/wp-content/uploads/2011/07/html5_drag_drop_upload.png" alt="html5 drag&amp;drop upload" title="html5 drag&amp;drop upload" width="300" height="186" class="size-full wp-image-1223" style="float:left" /><p class="wp-caption-text"> </p></div>
<p><strong>Приветствую всех!</strong></p>
<p>В этой статье хочу рассказать о нескольких своих экспериментах с HTML5. Начну издалека. Всем нам периодически приходится работать с различными web интерфейсами и часто возникает ощущение, что эта работа могла бы быть организована более эффективно.</p>
<p>Возможно, в каких-то случаях виноваты разработчики сервиса, но часто проблема заключается в ограничениях, которые накладывают браузеры. Рассмотрим загрузку файлов на сервер. В большинстве случаев вам предложат стандартное поле с кнопкой выбора файла с вашего компьютера и/или поле, в котором можно указать URL файла, размещенного где-нибудь в Сети.</p>
<p>Загрузку файлов с локального компьютера трогать пока не будем, я планирую опубликовать отдельный пост на эту тему, разберем загрузку с удалённого сервера.</p>
<p>Проблемы начинаются с первого же шага. Даже если вы четко понимаете, где искать URL и хорошо умеете пользоваться инструментами вроде <strong>firebug</strong>, то всё равно потребуется несколько кликов мышкой чтобы получить нужный адрес. Было бы гораздо удобнее просто перетянуть нужную картинку из одного окна браузера в другое.<br />
<span id="more-1222"></span><br />
Пример реализации такого интерфейса я покажу в этой статье. Если хотите, можете посмотреть, как он работает на демонстрационной страничке или скачать архив с исходниками.</p>
<p><a href="http://demosites.simplecoding.org/images-upload/"><img src="http://www.simplecoding.org/wp-content/themes/three_cols/images/demo_btn_green.png" alt="демонстрационный пример" /></a><a href='http://www.simplecoding.org/wp-content/uploads/2011/07/images-upload.zip'><img src="http://www.simplecoding.org/wp-content/themes/three_cols/images/download_btn_blue.png" alt="архив с исходным кодом" /></a></p>
<p><strong>Обратите внимание!</strong> Данный пример работает только в браузере <strong>Google Chrome</strong>. По-идее, поддержка всех необходимых технологий есть в <strong>Firefox</strong> и <strong>Safari</strong>, но с ними я пока не разбирался.<br />
В качестве объектов для «перетягивания» я брал в основном картинки с википедии. Было замечено несколько проблем связанных с не латинскими символами в URL картинок, но чтобы не перегружать пример проверками и преобразованиями я их оставил как есть.</p>
<h2>Принцип работы</h2>
<p>Стандарт HTML5 предусматривает поддержку «перетягивания» объектов страницы (Drag and Drop). Кстати, пример простейшей реализации D&#038;D я уже показывал – <a href="http://www.simplecoding.org/drag-drop-s-ispolzovaniem-html5.html">Drag &#038; Drop с использованием HTML5</a>. И, кроме того, есть довольно много JavaScript библиотек, реализующих поддержку D&#038;D.</p>
<p>Но тут важно понимать, что если необходимо «перетягивать» картинки со сторонних ресурсов, то использовать библиотеки не получится. Т.к. вы не сможете добавить свой JS код на чужую страницу. А для того, чтобы загрузить картинку, нам нужно получить её URL, т.е. браузер должен вместе с перетягиваемым объектом передавать и его параметры (например, атрибут src картинки или весь тег img).</p>
<p>В этом случае мы можем создать на своей странице «приёмник» картинок. Это будет обычный <code>div</code> которому назначен обработчик события <code>drop</code>. Если пользователь «сбросит» картинку над этим div&#039;ом, то будет вызван обработчик и в первом параметре он получит объект, содержащий информацию о перетягиваемой картинке.</p>
<p>Дальше всё достаточно просто. Если мы получили нужный URL, то можно отправить AJAX-запрос серверному скрипту, который выполнит загрузку файла.</p>
<h2>Реализация</h2>
<p>Начнём со страницы нашего приложения.</p>
<pre class="brush: html">&lt;!DOCTYPE html&gt;
&lt;html&gt;
    &lt;head&gt;
        &lt;meta http-equiv="Content-Type" content="text/html; charset=UTF-8"&gt;
        &lt;title&gt;Images Upload&lt;/title&gt;
		&lt;link rel="stylesheet" type="text/css" href="styles.css" /&gt;
    &lt;/head&gt;
    &lt;body&gt;
		&lt;div id="images"&gt;&lt;/div&gt;
		&lt;div id="img_target"&gt;&lt;/div&gt;
		&lt;script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"&gt;&lt;/script&gt;
		&lt;script src="main.js"&gt;&lt;/script&gt;
    &lt;/body&gt;
&lt;/html&gt;</pre>
<p>На ней размещены два блока: <code>images</code> – здесь будем показывать загруженные изображения и <code>img_target</code> – на этот блок нужно перетягивать картинки.</p>
<p>Внизу страницы подключаем библиотеку jQuery и скрипт main.js, который будет отправлять информацию о перетянутых изображениях на сервер.</p>
<p><strong>Рассмотрим main.js</strong></p>
<pre class="brush: javascript">$(function() {
    $('#img_target')
        .bind('dragenter', function(event) {
            $(this).addClass('drop_here');
            return false;
        })
        .bind('dragleave', function(event) {
            $(this).removeClass('drop_here');
            return false;
        })
        .bind('dragover', function(event) {
            return false;
        })
        .bind('drop', function(event) {
            $(this).removeClass('drop_here');
			var srcRegex = /src=\"([^\s]+)\"/ig;
            var data = event.originalEvent.dataTransfer.getData('text/html');
			var img_data = srcRegex.exec(data);
			$.post('upload.php', {'file_url':img_data[1]}, function(res) {
				var response = eval('(' + res + ')');
				$('#images').append($('&lt;img src="' + response.file_url + '" /&gt;'));
			});
            return true;
        });
});</pre>
<p>Здесь мы назначаем обработчики событиям <code>dragenter</code>, <code>dragleave</code> и <code>dragover</code>. Все они должны просто возвращать false и, чтобы как-то проинформировать пользователя о том, что можно «сбрасывать» картинку, в обработчике <code>dragenter</code> устанавливаем CSS класс <code>drop_here</code> для блока-приёмника.</p>
<p>Основная часть работы выполняется в обработчике события <code>drop</code>. При возникновении этого события мы читаем информацию о «сброшенном» объекте и «вырезаем» значение атрибута <code>src</code>, т.е. URL картинки (строки 16-18). Информация передается в объекте event.originalEvent.dataTransfer (строка 17).</p>
<p>Затем <strong>формируем обычный AJAX запрос</strong> и в качестве параметра передаём ему найденный URL.</p>
<p>Серверный скрипт (upload.php) получит URL изображения на удалённом сервере и загрузит его. А в ответе на AJAX запрос он отправит новый URL загруженной картинки.</p>
<p>В свою очередь, обработчик AJAX-запроса создаст тег <code>img</code> и вставит его в блок <code>images</code>. Таким образом, загруженные картинки будут появляться над полем загрузки.</p>
<p><strong>Рассмотрим upload.php</strong></p>
<pre class="brush: php">&lt;?php

define('BASE_URL', 'http://localhost/tests/images-upload/');

function upload_from_url($file_url) {
	$url_segments = explode('/', $file_url);
	$file_name = urldecode(end($url_segments));
	if (false !== $file_name) {
		$file_name_parts = explode('.', $file_name);
		if (in_array(strtolower(end($file_name_parts)), array('jpeg','jpg','png','gif'))) {
			$destination=fopen("upload/".$file_name,"w");
			$source=fopen($file_url,"r");
			$maxsize=300*1024;
			$length=0;
			while (($a=fread($source,1024))&#038;&#038;($length&lt;$maxsize)) {
				$length=$length+1024;
				fwrite($destination,$a);
			}
			fclose($source);
			fclose($destination);
		}
	}
	$new_file_url = BASE_URL.'upload/'.$file_name;
	return $new_file_url;
}

$res = array('err' =&gt; 'Не указан URL файла');

if (isset($_POST['file_url'])) {
	$new_url = upload_from_url($_POST['file_url']);
	$res = array('file_url' =&gt; $new_url);
}

echo json_encode($res);</pre>
<p>Принцип работы следующий. Читаем URL картинки и пытаемся её загрузить (строки 29-32).</p>
<p>Если картинка загружена, сохраняем её в папку <code>upload</code>. Получение картинки с удалённого сервера осуществляется с помощью функций <code>fread</code>. Файл читаем блоками по 1кБ (строки 15-18). Такой подход позволяет прервать загрузку файла, если его размер превышает заданный предел (в данном случае 300кБ).</p>
<p>После загрузки файла формируем для него URL и отправляем браузеру в формате <strong>JSON</strong>.</p>
<p>Как видите, реализовать такой загрузчик несложно. И пользоваться им достаточно удобно. Естественно, основным недостатком является поддержка HTML5 браузерами, точнее её отсутствие <img src='http://www.simplecoding.org/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p>Тем не менее, если вы создаёте интерфейс для сотрудников какой-нибудь компании, и можете оговорить тип браузера, то HTML5 вполне можно использовать.</p>
<p><strong>Успехов!</strong></p>
<p><em>Интересно почитать.</em></p>
<p>Фотокнига — фантастический <a href="http://imagebook.ru/sjurpriz_ljubimomu_muzhchine">сюрприз для любимого мужчины</a>. Попробуйте сами!</p>
<p>Правильно подготовим <a href="http://online-nalogi.ru/3_ndfl_pokupka_kvartiry">3-ндфл при покупке квартиры за 2011 год</a>, дадим инструкции для получения вычета</p>
<p>Нужно распарсить сайт? Интересный пример как написан <a href="http://www.sergunik.name/?p=140" title="php parser">парсер на php</a>. Можно даже скачать скрипт парсера.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.simplecoding.org/html5-zagruzka-fajlov-s-pomoshhyu-drag-drop.html/feed</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>Создаём валютный информер с помощь PHP и JavaScript</title>
		<link>http://www.simplecoding.org/sozdayom-valyutnyj-informer-s-pomoshh-php-i-javascript.html</link>
		<comments>http://www.simplecoding.org/sozdayom-valyutnyj-informer-s-pomoshh-php-i-javascript.html#comments</comments>
		<pubDate>Sun, 31 Oct 2010 18:05:02 +0000</pubDate>
		<dc:creator>Владимир</dc:creator>
				<category><![CDATA[Ajax]]></category>
		<category><![CDATA[HTML]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Web разработка]]></category>

		<guid isPermaLink="false">http://www.simplecoding.org/?p=1139</guid>
		<description><![CDATA[В этой статье я хочу обсудить подход к добавлению различных информеров на страницы сайта, и показать один из вариантов решения данной задачи. Сразу хочу уточнить, что в этой статье под термином «информер» я имею в виду блок на странице, содержащий информацию, полученную с другого ресурса. Информация может быть какая угодно: курсы валют, погода, данные счетчиков, [...]]]></description>
			<content:encoded><![CDATA[<div id="attachment_1140" class="wp-caption alignnone" style="width: 275px"><img src="http://www.simplecoding.org/wp-content/uploads/2010/10/exchange_rates.png" alt="exchange rates" title="exchange rates" style="float:left" width="265" height="131" class="size-full wp-image-1140" /><p class="wp-caption-text"> </p></div>
<p>В этой статье я хочу обсудить подход к добавлению различных <strong>информеров</strong> на страницы сайта, и показать один из вариантов решения данной задачи.</p>
<p>Сразу хочу уточнить, что в этой статье под термином «информер» я имею в виду <em>блок на странице, содержащий информацию, полученную с другого ресурса</em>. Информация может быть какая угодно: курсы валют, погода, данные счетчиков, последние твиты и т.п.</p>
<p>Результат, который должен получиться, можно посмотреть на демонстрационной страничке или запустив пример из архива.</p>
<p><a href="http://demosites.simplecoding.org/exchange-rates/"><img src="http://www.simplecoding.org/wp-content/themes/three_cols/images/demo_btn_green.png" alt="демонстрационный пример" /></a> <a href='http://www.simplecoding.org/wp-content/uploads/2010/10/exchange-rates.zip'><img src="http://www.simplecoding.org/wp-content/themes/three_cols/images/download_btn_blue.png" alt="архив с исходным кодом" /></a></p>
<h2>Подключение информера</h2>
<p><span id="more-1139"></span><br />
Существует два основных варианта.</p>
<p>1) Ресурс, который является источником информации, предоставляет код для вставки на вашем сайте. Обычно это JS код, который подгружает данные и формирует внешний вид информера. При этом, иногда владельцы запрещают менять оформление и содержимое информера. В этом случае выбор у вас небольшой: либо пользоваться тем, что дают, либо нет.</p>
<p>2) Данные можно получить в XML или JSON формате. Этот вариант гораздо интереснее, т.к. вы полностью контролируете внешний вид информера и можете выводить только те данные, которые вам нужны. Кроме того, появляется выбор между вариантами загрузки данных.</p>
<p>Т.к. по первому варианту обсуждать, в общем-то, нечего, остановимся на втором.</p>
<h2>Получение данных</h2>
<p>Тут тоже два варианта.</p>
<p><strong>1) Отправить запрос из PHP скрипта при формировании страницы.</strong></p>
<p>В этом случае не нужно использовать JavaScript, но могут возникнуть задержки при получении данных, которые увеличат общее время формирования страницы. Частично устранить эту проблему можно с помощью кеширования.</p>
<p><strong>2) Получать данные с помощью AJAX запроса.</strong></p>
<p>При этом поддержка JavaScript на стороне клиента обязательна, а время формирования страницы немного уменьшится. Точнее данные в информер будут загружаться после того как посетитель увидит основное содержимое страницы.</p>
<p>Сразу хочу отметить, что оба подхода имеют много общего.</p>
<p>Дело в том, что запрос к стороннему серверу в любом случае придётся отправлять из PHP скрипта. Причина – Same Origin Policy, которую используют все современные браузеры. Эта политика не позволяет JS коду получить доступ к данным, загруженным с другого домена.</p>
<p>Обойти это ограничение можно с помощью JSONP, но реализовать его поддержку должны разработчики сервиса, от которого вы хотите получить данные. Подробнее на эту тему вы можете почитать <a href="http://www.simplecoding.org/kak-obojti-zapret-na-xss.html">здесь</a>, <a href="http://www.simplecoding.org/xss-i-same-origin-policy.html">здесь</a> и <a href="http://www.simplecoding.org/xss-s-ispolzovaniem-jsonp-i-jquery.html">здесь</a>.</p>
<p>В общем, я покажу пример создания информера с использованием <strong>JavaScript</strong>, но, при желании, его несложно будет переделать под первый вариант.</p>
<h2>Источник данных</h2>
<p>Для этого примера используем данные о курсах валют, которые предоставляет ресурс <code>pfsoft.com.ua</code> в XML формате. Посмотреть их можно <a href="http://pfsoft.com.ua/service/currency/">здесь</a>.</p>
<h2>Разметка информера</h2>
<p>Тут всё просто.</p>
<pre class="brush: html">&lt;ul id="rates"&gt;&lt;li&gt;Загрузка данных...&lt;/li&gt;&lt;/ul&gt;</pre>
<p>Т.к. данные будут загружаться с помощью <strong>AJAX запроса</strong>, то показываем посетителю сообщение о том, что загрузка начата. Когда данные будут загружены, мы вставим их в список.</p>
<h2>Клиентский скрипт</h2>
<p>Принцип работы следующий. После загрузки страницы отправляем AJAX запрос на свой сервер. PHP скрипт получает данные от сервера pfsoft.com.ua и отправляет их браузеру.</p>
<p>JS код получает XML строку с данными, находит в ней нужные элементы и добавляет их в список (исходные данные содержат курсы примерно двух десятков валют, но вряд ли имеет смысл выводить их все).</p>
<pre class="brush: javascript">var curCodes = ['RUB', 'USD', 'EUR'];
$(document).ready(function() {
	$.get('getrates.php', function(data) {
		if (data != 'ERR') {
			var rates = '';
			$(data).find('Valute').each(function(key, value) {
				var curCode = $(value).find('CharCode').html();
				if (-1 != $.inArray(curCode, curCodes)) {
					rates += '&lt;li&gt;' + $(value).find('Nominal').html()
						+ ' ' + curCode
						+ ' = ' + $(value).find('Value').html() + ' грн.' + '&lt;/li&gt;';
				}
				$('#rates').html(rates);
			});
		}
		else {
			$('#rates').html('&lt;li&gt;Данные не доступны&lt;/li&gt;');
		}
	});
});</pre>
<p>Прежде всего, создаём массив с кодами валют, которые нужно показать в информере.</p>
<p>Затем, отправляем AJAX запрос (строка 3). PHP скрипт, который выполняет загрузку данных, называется <code>getrates.php</code>.</p>
<p>Если при получении данных возникли ошибки, выводим соответствующее сообщение (строка 17), в противном случае – начинаем обработку XML строки.</p>
<p>Обратите внимание! Мы можем работать с XML данными точно так же, как и с HTML страницей.</p>
<p>Просто создаём объект <strong>jQuery</strong> (<code>$(data)</code>) и получаем возможность использовать методы <code>find</code>, <code>html</code>, <code>each</code> и т.д.</p>
<p>Здесь мы находим все теги <code>Valute</code>, которые содержат данные об отдельной валюте, а затем из них выбираем код валюты, её курс и формируем элемент списка.</p>
<p>При этом проверяем, указана ли данная валюта в массиве <code>curCodes</code> (строка 8). Кстати, обратите внимание, метод <code>$.inArray</code> возвращает <code>-1</code> если указанный элемент отсутствует в массиве.</p>
<p>После этого вставляем данные в список (строка 13).</p>
<h2>Серверная часть</h2>
<p>Рассмотрим скрипт <code>getrates.php</code>.</p>
<pre class="brush: php">require_once('ratescache.php');

$rCache = new RatesCache();
//$rCache-&gt;expired = 30;

//пробуем получить данные из кеша
if (FALSE === ($data = $rCache-&gt;get())) {
	//если данные в кеше устарели, пытаемся получить их от сервера pfsoft.com.ua
	$data = @file_get_contents('http://pfsoft.com.ua/service/currency/');
	//если сервер недоступен, пробуем получить данные из устаревшего кеша
	if (FALSE === $data) {
		$data = $rCache-&gt;get(TRUE);
	}
	else {
		//обновляем данные в кеше, предварительно изменяем кодировку на UTF-8
		$rCache-&gt;save(iconv('windows-1251','utf-8',$data));
	}
}

if (FALSE !== $data) {
	//отправляем данные
	echo $data;
	exit;
}
//отправляем сообщение об ошибке
echo 'ERR';</pre>
<p>Логика работы довольно простая. Получить данные и отправить их браузеру, но при этом используется немного не стандартный кеш.</p>
<p>Прежде всего, хочу объяснить зачем нужен кеш.</p>
<p>Во-первых, его использование сокращает время загрузки данных.</p>
<p>Во-вторых, если у вас посещаемый сайт, и вы будете запрашивать данные для каждого посетителя, то администраторы источника данных могут вас просто забанить (за нагрузку).</p>
<p>В-третьих, кеш позволит получить данные для информера даже если pfsoft.com.ua не доступен.</p>
<p>Итак, <strong>алгоритм работы</strong> следующий.</p>
<p>1) Создаём экземпляр класса кеша (строка 3) и пробуем получить данные из него (строка 7).</p>
<p>2) Если данные в нём устарели, пробуем получить их от сервера pfsoft.com.ua (строка 9).</p>
<p>3) Если и сервер не отвечает, пытаемся получить данные из устаревшего кеша (строка 12). Кстати, это единственная причина, из-за которой я написал собственную реализацию кеша. Класс <code>RatesCache</code> содержит два метода <code>get</code> и <code>set</code>, причем вызов <code>get(true)</code> вернёт данные, даже если кеш устарел.</p>
<p>4) Если сервер pfsoft.com.ua вернул данные, то обновляем кеш и отправляем их браузеру (строка 16).</p>
<p>5) Если данные получить не удалось (кеш не существует и сервер не отвечает), отправляем сообщение об ошибке (строка 26).</p>
<p>Приводить класс кеша здесь я не буду. Вы всегда можете посмотреть его в <a href="http://www.simplecoding.org/wp-content/uploads/2010/10/exchange-rates.zip">исходниках</a> (там, на мой взгляд, достаточно комментариев). К тому же класс довольно простой и написан в основном для этого примера. Если вы используете какой-нибудь фреймворк, то проще будет использовать встроенную библиотеку кеширования.</p>
<h2>Результаты</h2>
<p>На мой взгляд, показанный здесь вариант создания информера один из самых удобных. С одной стороны он не замедляет формирование страницы (за счет AJAX загрузки), с другой – формируется достаточно быстро (за счет использования кеша).</p>
<p>К тому же, частично устраняется зависимость от источника данных. Посетитель увидит курсы валют, правда устаревшие. Как только источник данных станет доступным кеш будет обновлён.</p>
<p>Как всегда, я буду рад ответить на ваши вопросы и замечания!</p>
<p><strong>Интересно почитать</strong></p>
<p>Необычный <a href="http://nippondom.com/reklama_restorana">пример рекламы ресторана</a> от практичных японцев.</p>
<p>Пять способов <a href="http://blog.copy-write.ru/contact/sposoby-i-metody-privlecheniya-novyx-klientov">привлечения клиентов</a> для фирм на b2b-рынке</p>
]]></content:encoded>
			<wfw:commentRss>http://www.simplecoding.org/sozdayom-valyutnyj-informer-s-pomoshh-php-i-javascript.html/feed</wfw:commentRss>
		<slash:comments>14</slash:comments>
		</item>
		<item>
		<title>CGridView. Часть вторая. AJAX.</title>
		<link>http://www.simplecoding.org/cgridview-chast-vtoraya-ajax.html</link>
		<comments>http://www.simplecoding.org/cgridview-chast-vtoraya-ajax.html#comments</comments>
		<pubDate>Sun, 25 Jul 2010 13:16:41 +0000</pubDate>
		<dc:creator>Владимир</dc:creator>
				<category><![CDATA[Ajax]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Web разработка]]></category>
		<category><![CDATA[Yii]]></category>

		<guid isPermaLink="false">http://www.simplecoding.org/?p=1100</guid>
		<description><![CDATA[В этой части я хочу рассказать о некоторых особенностях реализации AJAX запросов в компоненте CGridView. Предположим, у нас есть таблица, и мы создали для неё модель и скрипты для выполнения CRUD операций (с помощью встроенного генератора Yii). Пусть таблица называется countries, содержит список стран с двумя полями (id, name). В этом случае, страница управления записями [...]]]></description>
			<content:encoded><![CDATA[<div id="attachment_1101" class="wp-caption alignnone" style="width: 310px"><img src="http://www.simplecoding.org/wp-content/uploads/2010/07/yii_grid_view1.png" alt="yii grid view" title="yii grid view" width="300" height="169" style="float:left" class="size-full wp-image-1101" /><p class="wp-caption-text"> </p></div>
<p>В этой части я хочу рассказать о некоторых особенностях реализации AJAX запросов в компоненте <a href="http://www.yiiframework.com/doc/api/CGridView">CGridView</a>.</p>
<p>Предположим, у нас есть таблица, и мы создали для неё модель и скрипты для выполнения CRUD операций (с помощью встроенного генератора <strong>Yii</strong>).</p>
<p>Пусть таблица называется <code>countries</code>, содержит список стран с двумя полями (<code>id</code>, <code>name</code>).</p>
<p>В этом случае, страница управления записями будет доступна адресу<br />
<span id="more-1100"></span><br />
<code>index.php?r=countries/admin</code></p>
<div id="attachment_1107" class="wp-caption alignnone" style="width: 460px"><img src="http://www.simplecoding.org/wp-content/uploads/2010/07/cgridview_ajax_1.png" alt="cgridview ajax" title="cgridview ajax" width="450" height="249" class="size-full wp-image-1107" /><p class="wp-caption-text"> </p></div>
<p>В нижней части страницы находится <strong>пагинатор</strong> (листалка). Клик по ссылке с номером страницы приведет к отправке <strong>ajax запроса</strong>. Но вот тут появляется одна из особенностей. Этот ajax запрос возвращает не только новую страницу с данными, но и всю страницу целиком. Начиная от <code>doctype</code> и заканчивая закрывающим тегом <code>html</code>.</p>
<p>Если на странице ничего, кроме таблицы нет, то это не проблема. Но если мы разместим на ней несколько виджетов, для формирования которых нам потребуется выполнить дополнительные запросы к БД, то смысла в такой ajax пагинации окажется немного.</p>
<p>В общем, <strong>нужно, чтобы при клике на номер страницы сервер отправлял только фрагмент разметки с таблицей</strong>.</p>
<p>Сделать это несложно. Для начала вынесем из представления <code>views/countries/admin.php</code> код, который выполняет формирование таблицы в отдельный файл &#8211; <code>views/countries/admingrid.php</code>.</p>
<p>Речь идет об этом фрагменте</p>
<pre class="brush: php">&lt;?php $this-&gt;widget('zii.widgets.grid.CGridView', array(
	'id'=&gt;'countries-grid',
	'dataProvider'=&gt;$model-&gt;search(),
	'filter'=&gt;$model,
	'columns'=&gt;array(
		'c_id',
		'c_name',
		array(
			'class'=&gt;'CButtonColumn',
		),
	),
)); ?&gt;</pre>
<p>На его место в <code>views/countries/admin.php</code> добавляем следующий код.</p>
<pre class="brush: php">&lt;?php
$this-&gt;renderPartial('admingrid', array('model'=&gt;$model));
?&gt;</pre>
<p>Идея в том, что если мы получим ajax запрос, то возвращать будем только содержимое <code>admingrid.php</code>, если запрос будет обычный – всю страницу.</p>
<p>Теперь переделываем метод <code>actionAdmin</code> контроллера.</p>
<pre class="brush: php">public function actionAdmin()
{
	$model=new Countries('search');
	$model-&gt;unsetAttributes();  // clear any default values
	if(isset($_GET['Countries']))
		$model-&gt;attributes=$_GET['Countries'];

	if (isset($_GET['ajax'])) {
		$this-&gt;renderPartial('admingrid',array(
			'model'=&gt;$model,
		));
	}
	else {
		$this-&gt;render('admin',array(
			'model'=&gt;$model,
		));
	}
}</pre>
<p>Здесь добавлена дополнительная проверка (строка 8). Класс <code>CGridView</code> имеет свойство <code>ajaxVar</code>, которое по-умолчанию равно ajax. Это свойство задает имя GET параметра, который указывает, что данный запрос является ajax запросом.</p>
<p>Если этот параметр установлен, мы используем метод <code>renderPartial</code>, который возвращает браузеру только содержимое представления <code>admingrid</code>. В противном случае, вызываем метод render, который формирует всю страницу целиком.</p>
<p>Внешне в работе страницы ничего не изменилось, но если вы посмотрите с помощью firebug’а ответы сервера на ajax запросы, то разница будет заметной.</p>
<p>Теперь сделаем <strong>просмотр записей с помощью AJAX</strong>.</p>
<p>По-умолчанию, если мы нажмем на кнопку просмотра (в последней колонке таблицы), то мы попадем на страницу соответствующей записи.</p>
<div id="attachment_1106" class="wp-caption alignnone" style="width: 123px"><img src="http://www.simplecoding.org/wp-content/uploads/2010/07/grid_buttons.png" alt="grid buttons" title="grid buttons" width="113" height="102" class="size-full wp-image-1106" /><p class="wp-caption-text"> </p></div>
<p>Мы изменим это поведение. Добавим под таблицей блок, в котором будут отображаться подробные сведения о выбранной записи, т.е. содержимое представления <code>views/countries/admingrid.php</code>.</p>
<p>Чтобы не менять стандартное поведение кнопок в таблице мы добавим к ней ещё один столбец со ссылками «<code>Предпросмотр</code>».</p>
<p>При клике по этой ссылке под таблицей появится подробная информация о данной записи.</p>
<p>Приступим.</p>
<p>Добавляем новую колонку в таблицу. Для этого изменим файл <code>admingrid.php</code> следующим образом.</p>
<pre class="brush: php">&lt;?php
$this-&gt;widget('zii.widgets.grid.CGridView', array(
	'id'=&gt;'countries-grid',
	'dataProvider'=&gt;$model-&gt;search(),
	'filter'=&gt;$model,
	'afterAjaxUpdate'=&gt;'function(id, data) {$.fn.setPreviewLinksHandler(id, data);}',
	'columns'=&gt;array(
		'c_id',
		'c_name',
		array(
			'class'=&gt;'CButtonColumn',
		),
		array(
			'type'=&gt;'raw',
			'value'=&gt;'CHtml::link(&quot;Предпросмотр&quot;, array(&quot;countries/view&quot;, &quot;id&quot;=&gt;$data-&gt;c_id, &quot;ajax&quot;=&gt;&quot;preview&quot;), array(&quot;name&quot;=&gt;&quot;previewLink&quot;))',
		),
	),
)); ?&gt;</pre>
<p>Здесь есть нюансы. Во-первых, при добавлении столбца необходимо указать, что он имеет тип <code>raw</code>, иначе по-умолчанию <strong>Yii</strong> применит фильтры к его содержимому.</p>
<p>Во-вторых, нам нужно назначить каждой ссылке обработчик события <code>onClick</code>. Причем, сделать это необходимо как при первоначальной загрузке страницы, так и при «перелистовании».</p>
<p>Для этого мы используем свойство <code>afterAjaxUpdate</code> (строка 6). Ему присваиваем JavaScript функцию, которая будет вызвана после обновления таблицы с помощью ajax метода.</p>
<p>Теперь напишем функцию <code>setPreviewLinksHandler</code>. Для этого создаём файл <code>js/previewlinks.js</code>.</p>
<pre class="brush: php">$(function() {
	$.fn.setPreviewLinksHandler = function(id, data) {
		$(&quot;a[name=previewLink]&quot;).click(function() {
			var link = $(this);
			$.get(link.attr('href'), function(data) {
				$('#preview').html(data);
			});
			return false;
		});
	};
	$.fn.setPreviewLinksHandler();
});</pre>
<p>Эта функция получает в качестве параметров <code>id</code> блока с таблицей и её содержимое (<code>data</code>). Но, т.к. содержимое таблицы мы менять не будем, то и эти параметры нам не нужны.</p>
<p>Наша функция <code>setPreviewLinksHandler</code> ищет все ссылки, у которых атрибут name равен <code>previewLink</code> и назначает им обработчик события <code>onClick</code>.</p>
<p>Этот обработчик формирует и отправляет ajax запрос, который возвращает подробную информацию о записи.</p>
<p>Тут обратите внимание, что при отправке ajax запроса используется атрибут <code>href</code> ссылки, таким образом, при отключенном JS клик по ссылке будет отправлять пользователя на страницу с подробной информацией о записи.</p>
<p>Рассмотрим метод <code>actionView</code> контроллера.</p>
<pre class="brush: php">public function actionView()
{
	if (isset($_GET['ajax'])) {
		$this-&gt;renderPartial('viewrow',array(
			'model'=&gt;$this-&gt;loadModel(),
		));
	}
	else {
		$this-&gt;render('view',array(
			'model'=&gt;$this-&gt;loadModel(),
		));
	}
}</pre>
<p>Здесь мы проверяем, есть ли в параметрах запроса атрибут <code>ajax</code>, и если он есть, показываем представление <code>viewrow</code>. При этом используется метод <code>renderPartial</code>. В противном случае, просто показываем представление <code>view</code>.</p>
<p><code>viewrow.php</code> создаём по тому же принципу, что и <code>admingrid.php</code>. Перемещаем код создания виджета <code>CDetailView</code> в <code>viewrow.php</code>.</p>
<pre class="brush: php">&lt;?php $this-&gt;widget('zii.widgets.CDetailView', array(
	'data'=&gt;$model,
	'attributes'=&gt;array(
		'c_id',
		'c_name',
	),
)); ?&gt;</pre>
<p>А в <code>view.php</code> добавим</p>
<pre class="brush: php">&lt;?php $this-&gt;renderPartial('viewrow', array('model'=&gt;$model)); ?&gt;</pre>
<p>В результате этих манипуляций подробные сведения о записи будут появляться под таблицей при клике по ссылке «Предпросмотр».</p>
<p>Я надеюсь, что никого не запутал своими объяснениями <img src='http://www.simplecoding.org/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' />  Чтобы вам удобнее было экспериментировать, выкладываю архив с исходниками этого примера и дампом базы (предварительно вам нужно будет создать приложение Yii).</p>
<p><a href='http://www.simplecoding.org/wp-content/uploads/2010/07/yii_grid_countries.zip'><img src="http://www.simplecoding.org/wp-content/themes/three_cols/images/download_btn_blue.png" alt="архив с исходным кодом" /></a></p>
<p>Если есть вопросы или замечания, пишите! Особенно интересуют альтернативные варианты решения таких задач <img src='http://www.simplecoding.org/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p><strong>Интересно почитать</strong></p>
<p>Компания Intelsib предлагает <a href="http://www.intelsib.ru">продвижение сайта в интернете, поисковиках</a>, а также его аудит.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.simplecoding.org/cgridview-chast-vtoraya-ajax.html/feed</wfw:commentRss>
		<slash:comments>27</slash:comments>
		</item>
		<item>
		<title>Ограничения фреймворков (на примере Yii)</title>
		<link>http://www.simplecoding.org/ogranicheniya-frejmvorkov-na-primere-yii.html</link>
		<comments>http://www.simplecoding.org/ogranicheniya-frejmvorkov-na-primere-yii.html#comments</comments>
		<pubDate>Mon, 31 May 2010 13:38:04 +0000</pubDate>
		<dc:creator>Владимир</dc:creator>
				<category><![CDATA[Ajax]]></category>
		<category><![CDATA[HTML]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Web разработка]]></category>
		<category><![CDATA[Yii]]></category>

		<guid isPermaLink="false">http://www.simplecoding.org/?p=1073</guid>
		<description><![CDATA[О том, что фреймворки позволяют сократить время разработки, знают все. Но иногда при этом появляются самые неожиданные ограничения. По-идее, так и должно быть. Каким бы универсальным не пытались сделать фреймворк разработчики, всегда чем-то приходится жертвовать. Точнее искать компромисс между количеством кода, который должен написать пользователь и гибкостью. В этой статье я хочу показать пример такой [...]]]></description>
			<content:encoded><![CDATA[<div id="attachment_1061" class="wp-caption alignnone" style="width: 281px"><img src="http://www.simplecoding.org/wp-content/uploads/2010/05/yii_php_framework_autocomplete.png" alt="yii php framework autocomplete" title="yii php framework autocomplete" width="271" height="166" class="size-full wp-image-1061" style="float:left" /><p class="wp-caption-text"> </p></div>
<p>О том, что фреймворки позволяют сократить время разработки, знают все. Но иногда при этом появляются самые неожиданные ограничения.</p>
<p>По-идее, так и должно быть. Каким бы универсальным не пытались сделать фреймворк разработчики, всегда чем-то приходится жертвовать. Точнее искать компромисс между количеством кода, который должен написать пользователь и гибкостью.</p>
<p>В этой статье я хочу показать пример такой ситуации, и, естественно, её решение.<br />
<span id="more-1073"></span></p>
<p><strong>UPD</strong>: <em>Более удачное решение данной проблемы приведено в комментариях.</em></p>
<p>Не так давно я опубликовал статью <a href="http://www.simplecoding.org/yii-php-frejmvork-sozdaem-pole-s-avtozapolneniem.html">Yii PHP фреймворк: создаем поле с автозаполнением</a>, в которой рассказывал об использовании виджета <a href="http://www.yiiframework.com/doc/api/CAutoComplete">CAutoComplete</a>.</p>
<p><strong>Алгоритм его работы</strong> довольно прост.</p>
<p>1) Создать текстовое поле (тег <code>input</code>).<br />
2) Подключить плагин jQuery <a href="http://plugins.jquery.com/project/autocompletex">Autocomplete</a> и файлы CSS стилей.<br />
3) Подключить плагин к текстовому полю.</p>
<p>При этом, все настройки виджета <code>CAutoComplete</code> задаются при его подключении в <strong>PHP</strong> массиве.</p>
<p>Т.к. основную работу выполняет <strong>Autocomplete</strong>, то логично было бы предположить, что в настройках виджета можно задать все параметры этого плагина. Для большинства параметров, так оно и есть, но с параметром <code>extraParams</code> возникли проблемы.</p>
<p>В документации сказано.</p>
<blockquote><p>Extra parameters for the backend. If you were to specify <code>{bar:4}</code>, the autocompleter would call <code>my_autocomplete_backend.php?q=foo&#038;bar=4</code> (assuming the input box contains &#034;foo&#034;). The param can be a function that is called to calculate the param before each request.</p></blockquote>
<blockquote><p>Дополнительный параметр для бэкенда. Если вы указали <code>{bar:4}</code>, плагин отправит запрос <code>my_autocomplete_backend.php?q=foo&#038;bar=4</code> (предполагается, что текстовое поле содержит текст &#034;foo&#034;). Параметр может быть функцией, которая вызывается чтобы рассчитать значение параметра перед отправкой каждого запроса.</p></blockquote>
<p>Т.е. вы можете задать настройки для <code>CAutoComplete</code> следующим образом.</p>
<pre class="brush: text">$this-&gt;widget('CAutoComplete',
     array(
         'extraParams'=&gt;array('mypar'=&gt;'myval'),
         'url'=&gt;array('countries/autocomplete'),
     )
 );</pre>
<p>И такой вариант будет работать.</p>
<p>Но если вы захотите использовать в качестве значения функцию, например</p>
<pre class="brush: php">'extraParams'=&gt;array('mypar'=&gt;'function() {return $("#myselect").val();}'),</pre>
<p>то этот JS код выполняться не будет.</p>
<p><em>Примечание</em>. Показанная здесь функция возвращает значение из выпадающего списка (<code>myselect</code>).</p>
<p>Дело в том, что функция передается в виде стоки (в кавычках) и JS код при этом, естественно, не выполняется.</p>
<p><strong>Решить проблему</strong> можно так.</p>
<p>1) Создаём js файл с таким кодом.</p>
<pre class="brush: javascript">jQuery("#country").setOptions({
'extraParams':{'mypar':function() {return $("#myselect").val();}}}
);</pre>
<p>2) Подключаем его к нужной странице.</p>
<pre class="brush: php">$cs = Yii::app()->clientScript;
$cs->registerScriptFile(Yii::app()->request->baseUrl.'/js/autocomplete_config.js', CClientScript::POS_END);</pre>
<p>Здесь <code>autocomplete_config.js</code> – название вашего скрипта.</p>
<p>Как видите, решение достаточно простое, но не очень красивое. Часть настроек виджета будет задана в PHP файле, часть в JS.</p>
<p>Если вы знаете более удачные варианты, буду рад выслушать и обсудить <img src='http://www.simplecoding.org/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p>До встречи!</p>
<p><strong>Интересно почитать</strong></p>
<p>Удобный и недорогой <a href="http://www.onyx-inter.ru/stol-i-tumba-kassira-onyx.html ">стол для кассы</a> отечественной разработки</p>
]]></content:encoded>
			<wfw:commentRss>http://www.simplecoding.org/ogranicheniya-frejmvorkov-na-primere-yii.html/feed</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>jQuery + плагины: сортировка и редактирование списка (часть вторая)</title>
		<link>http://www.simplecoding.org/jquery-plaginy-sortirovka-i-redaktirovanie-spiska-chast-vtoraya.html</link>
		<comments>http://www.simplecoding.org/jquery-plaginy-sortirovka-i-redaktirovanie-spiska-chast-vtoraya.html#comments</comments>
		<pubDate>Sun, 25 Apr 2010 08:01:27 +0000</pubDate>
		<dc:creator>Владимир</dc:creator>
				<category><![CDATA[Ajax]]></category>
		<category><![CDATA[HTML]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Web разработка]]></category>

		<guid isPermaLink="false">http://www.simplecoding.org/?p=1049</guid>
		<description><![CDATA[В прошлой статье я начал рассказывать о создании редактируемого html списка с возможностью сортировки записей. Мы рассмотрели структуру БД, создали страницу со списком, подключили JS скрипты и разобрали добавление записей. Осталось немного доделать Демо-версия находится здесь Также вы можете скачать архив с этим примером Удаление существующих записей Рассмотрим серверную часть removenote.php. try { if (!isset($_POST['id'])) [...]]]></description>
			<content:encoded><![CDATA[<div id="attachment_1047" class="wp-caption alignnone" style="width: 310px"><img src="http://www.simplecoding.org/wp-content/uploads/2010/04/jquery_sortable.png" alt="jquery sortable" title="jquery sortable" width="300" height="211" class="size-full wp-image-1047" style="float:left" /><p class="wp-caption-text"> </p></div>
<p>В <a href="http://www.simplecoding.org/jquery-plaginy-sortirovka-i-redaktirovanie-spiska.html">прошлой статье</a> я начал рассказывать о создании <strong>редактируемого html списка</strong> с возможностью сортировки записей. Мы рассмотрели структуру БД, создали страницу со списком, подключили JS скрипты и разобрали добавление записей.</p>
<p>Осталось немного доделать <img src='http://www.simplecoding.org/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p>Демо-версия находится здесь</p>
<p><a href="http://demosites.simplecoding.org/jquery_sortable/"><img src="http://www.simplecoding.org/wp-content/themes/three_cols/images/demo_btn_green.png" alt="демонстрационный пример" /></a></p>
<p>Также вы можете скачать архив с этим примером</p>
<p><a href='http://www.simplecoding.org/wp-content/uploads/2010/04/jquery_sortable.zip'><img src="http://www.simplecoding.org/wp-content/themes/three_cols/images/download_btn_blue.png" alt="архив с исходным кодом" /></a></p>
<p><strong>Удаление существующих записей</strong><br />
<span id="more-1049"></span><br />
Рассмотрим серверную часть <code>removenote.php</code>.</p>
<pre class="brush: php">try {
	if (!isset($_POST['id'])) {
		throw new Exception('Не указан id записи');
	}
	//подключаемся к базе
	require_once('db.php');
	//удаляем запись (id записи приходит в формате note_id, приставку note_ вырезаем)
	$dbh-&gt;exec('DELETE FROM notes WHERE id='.$dbh-&gt;quote(substr($_POST['id'], 5)));
	$result = array();
	$result['id'] = $_POST['id'];
	//отправляет отчет браузеру
	echo json_encode($result);
} catch(Exception $e) {
	echo json_encode(array('err'=&gt;'Ошибка: '.$e-&gt;getMessage()));
}</pre>
<p>Для удаления записи нам нужно знать только её <code>id</code>. После того, как он получен, выполняем запрос на удаление.</p>
<p>Клиентская часть немного сложнее.</p>
<p>Ссылкам «Удалить» назначается обработчик события <code>click</code>.</p>
<pre class="brush: javascript">.click(removeLi)

function removeLi() {
	//определяем id текущей записи
	var noteId = $(this).parent().attr('id');
	//запрашиваем подтверждение
	if (confirm('Точно удалить?')) {
		//отправляем запрос
		$.post('removenote.php', {'id':noteId}, function(data) {
			var response = eval('('+data+')');
			if (response['err'] != null) {
				alert(response['err']);
			} else {
				$('#' + response['id']).detach();
				//проверяем, остались ли записи в списке
				var notes = $('#sortable li');
				if (notes.length == 0) {
					//удаляем сам список и форму сортировки записей
					$('#sortable').detach();
					$('#changeOrder').detach();
					//добавляем сообщение &quot;Записи отсутствуют&quot;
					$('&lt;h2&gt;Записи отстутствуют&lt;/h2&gt;').insertAfter('#addNewNote');
				}
			}
		});
	}
	return false;
}</pre>
<p>Этот обработчик определяет <code>id</code> тега <code>li</code>, в котором расположена ссылка, запрашивает подтверждение удаления и отправляет <strong>ajax</strong> запрос серверу.</p>
<p>После получения ответа от сервера, он удаляет запись из списка с помощью метода <code>.detach()</code> и проверяет, остались ли в списке другие записи. Если не осталось – список вместе с формой сортировки записей также удаляется.</p>
<p><strong>Изменение текста записей</strong></p>
<p>Как и раньше, начинаем с серверной части. Скрипт <strong>update.php</strong>.</p>
<pre class="brush: php">try {
	//проверяем, пришли данные или нет
	if (!isset($_POST['value'])
			|| '' == $_POST['value']
			|| !isset($_POST['id'])
			|| '' == $_POST['id']) {
		throw new Exception('Не указаны данные записи');
	}
	//подключаемся к базе
	require_once('db.php');
	//защита от XSS
	$note = htmlspecialchars($_POST['value']);
	//формируем запрос на изменение записи...
	$stmt = $dbh-&gt;prepare('UPDATE notes SET note=:note WHERE id=:id');
	//... и выполняем его
	$stmt-&gt;execute(array(':note'=&gt;$note, ':id'=&gt;substr($_POST['id'], 2)));
	$dbh = null;
	//тут мы не используем JSON формат, т.к. это требование плагина jeditable
	echo $note;
} catch(Exception $e) {
	echo 'Ошибка: '.$e-&gt;getMessage();
}</pre>
<p>От браузера скрипт получает <code>id</code> записи и новый текст.</p>
<p>После выполнения обычных проверок, мы подключаемся к БД и отправляем запрос на изменение записи. При этом с помощью функции <code>htmlspecialchars</code> мы заменяем теги на их эскейп последовательности (защита от XSS). Защита от <strong>SQL Injection</strong> выполняется с помощью стандартных средств <strong>PDO</strong>.</p>
<p>Обратите внимание, что в этом случае мы отправляем ответ браузеру в виде обычного текста. Это требование плагина <a href="http://www.appelsiini.net/projects/jeditable">jeditable</a>.</p>
<p>Клиентская часть.</p>
<p>Чтобы сделать текст записей редактируемым, мы для каждого тега span (который находится внутри li) выполняем метод editable.</p>
<pre class="brush: javascript">var editableOptions = {
	indicator : 'Сохраняю...',
	tooltip : 'Сделайте двойной клик, чтобы изменить текст',
	event : 'dblclick',
	cancel : 'Отмена',
	submit : 'Сохранить'
};

$('span.note').editable('update.php', editableOptions);</pre>
<p>В параметрах этого метода передаём адрес скрипта, который выполняет обновление записи на сервере, и объект <code>editableOptions</code>, который содержит настройки плагина. В данном случае мы указываем (параметр <code>event</code>), что плагин должен вставить форму редактирования при двойном клике по тексту. Одинарный клик, который используется по-умолчанию, нам не подходит, т.к. в этом случае форма будет появляться при каждой попытке перемещения записи.</p>
<p>Кроме события (<code>dblclick</code>) которое открывает форму редактирования, указанного в параметре event, для настройки плагина мы указали только надписи на кнопках и текст подсказок.</p>
<p>Запрос серверу плагин отправляет сам, после клика по кнопке «Сохранить».</p>
<p><strong>Изменение порядка записей</strong></p>
<p>Самая интересная часть <img src='http://www.simplecoding.org/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>Принцип довольно простой. После того, как пользователь рассортирует записи в нужном порядке, он нажимает кнопку «Сохранить сортировку». При этом запускается обработчик, который формирует массив с записями вида</p>
<pre class="brush: javascript">{
	'id':'id записи',
	'order': порядковый_номер_записи_в_отсортированном_списке
}</pre>
<p>Затем этот массив преобразовывается в форма <strong>JSON</strong> и отправляется серверу.</p>
<p><em>Примечание</em>. Для преобразования в формат JSON используется плагин <a href="http://code.google.com/p/jquery-json/">jquery-json</a>.</p>
<p>Выглядит клиентская часть следующим образом.</p>
<pre class="brush: javascript">function updateOrder() {
	var notes = $('ul#sortable li');
	//проверяем количество записей в списке
	if (notes.length &gt; 0) {
		var order = [];
		//формируем массив
		//просматриваем список в обратном порядке, т.к. записи выводятся в порядке
		//убывания значений в поле note_order (это позволяет при создании записи
		//присваивать ей максимальный порядковый номер и размещать в начале списка).
		$.each(notes.get().reverse(), function(index, value) {
			order.push({'id': $(value).attr('id'), 'order': index});
		});
		//отправка запроса (метод toJSON добавлен плагином json-2.2)
		$.post('changeorder.php', {'neworder':$.toJSON(order)}, function(data) {
			var response = eval('('+data+')');
			if (response.status == 'OK') {
				$('ul#sortable').effect(&quot;highlight&quot;, {}, 3000);
			}
			else {
				alert(response.mes);
			}
		});
	}
	return false;
}</pre>
<p>Обратите внимание, мы обрабатываем массив с элементами списка в обратном порядке (используется метод <code>.reverse()</code>). Это сделано потому, что записи выводятся в порядке убывания значений в поле <code>note_order</code>. Как я объяснял ранее, такой подход позволяет упростить определение номеров сортировки при создании новых записей.</p>
<p>Если данные успешно сохранены, подсвечиваем список, в противном случае – выводим сообщение об ошибке.</p>
<p>Серверный скрипт (changeorder.php).</p>
<pre class="brush: php">try {
	//проверяем полученные данные
	if (!isset($_POST['neworder']) || count($_POST['neworder']) &gt; 5000) {
		throw new Exception('Недопустимые данные');
	}
	//подключаемся к БД
	require_once('db.php');
	//создаём запрос на обновление
	$stmt = $dbh-&gt;prepare('UPDATE notes SET note_order=:note_order WHERE id=:id');
	//преобразовываем строку в JSON формате в массив объектов
	$data = json_decode($_POST['neworder']);
	if (null == $data) {
		throw new Exception('Недопустимый формат');
	}
	//обновляем записи
	foreach ($data as $note) {
		$stmt-&gt;execute(array(':note_order'=&gt;$note-&gt;order, ':id'=&gt;substr($note-&gt;id, 5)));
	}
	$dbh = null;
	//отправляем отчет браузеру
	echo json_encode(array('status'=&gt;'OK'));
} catch(Exception $e) {
	echo json_encode(array('status'=&gt;'ERR', 'mes'=&gt;'Ошибка: '.$e-&gt;getMessage()));
}</pre>
<p>Здесь мы проверяем полученные данные и в цикле обновляем все записи. Используется обычный <code>UPDATE</code> запрос. Преобразование из JSON формата в PHP массив выполняется с помощью функции <code>json_decode</code>.</p>
<p>Как видите, пример получился довольно объёмный, но большая часть кода относится к различным проверкам. Поэтому, надеюсь, общую идею вы поняли <img src='http://www.simplecoding.org/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p>Если у вас будут вопросы или замечания, пишите, буду рад обсудить!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.simplecoding.org/jquery-plaginy-sortirovka-i-redaktirovanie-spiska-chast-vtoraya.html/feed</wfw:commentRss>
		<slash:comments>50</slash:comments>
		</item>
		<item>
		<title>jQuery + плагины: сортировка и редактирование списка</title>
		<link>http://www.simplecoding.org/jquery-plaginy-sortirovka-i-redaktirovanie-spiska.html</link>
		<comments>http://www.simplecoding.org/jquery-plaginy-sortirovka-i-redaktirovanie-spiska.html#comments</comments>
		<pubDate>Fri, 23 Apr 2010 19:11:55 +0000</pubDate>
		<dc:creator>Владимир</dc:creator>
				<category><![CDATA[Ajax]]></category>
		<category><![CDATA[HTML]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Web разработка]]></category>

		<guid isPermaLink="false">http://www.simplecoding.org/?p=1046</guid>
		<description><![CDATA[Довольно давно я написал статью о том, как с помощью библиотек Prototype и Scriptaculous добавить возможность редактирования и удаления записей обычному html списку (вообще-то это был цикл статей 1, 2, 3, 4, 5). С тех пор несколько читателей просили доработать пример и добавить возможность сортировки записей. Переделывать тот пример я не буду, т.к. Prototype сейчас [...]]]></description>
			<content:encoded><![CDATA[<div id="attachment_1047" class="wp-caption alignnone" style="width: 310px"><img src="http://www.simplecoding.org/wp-content/uploads/2010/04/jquery_sortable.png" alt="jquery sortable" title="jquery sortable" width="300" height="211" class="size-full wp-image-1047" style="float:left" /><p class="wp-caption-text"> </p></div>
<p>Довольно давно я написал статью о том, как с помощью библиотек Prototype и Scriptaculous добавить возможность редактирования и удаления записей обычному html списку (вообще-то это был цикл статей <a href="http://www.simplecoding.org/redactor-spiska-structura.html">1</a>, <a href="http://www.simplecoding.org/redaktor-spiska-main.html">2</a>, <a href="http://www.simplecoding.org/redaktor-spiska-add.html">3</a>, <a href="http://www.simplecoding.org/redaktor-spiska-edit.html">4</a>, <a href="http://www.simplecoding.org/redaktor-spiska-delete.html">5</a>).</p>
<p>С тех пор несколько читателей просили доработать пример и добавить <strong>возможность сортировки записей</strong>.</p>
<p>Переделывать тот пример я не буду, т.к. Prototype сейчас практически не использую, лучше покажу, как решить задачу с помощью <a href="http://jquery.com/">jQuery</a>.</p>
<p><strong>Сформулируем требования.</strong></p>
<p>Необходимо создать <strong>html список</strong> с возможностями:</p>
<p>- изменение записей;<br />
- удаление записей;<br />
- изменение порядка записей.</p>
<p>Кроме того, необходимо предусмотреть возможность создания новых записей.<br />
<span id="more-1046"></span><br />
В общем, работать это будет примерно так.</p>
<p><a href="http://demosites.simplecoding.org/jquery_sortable/"><img src="http://www.simplecoding.org/wp-content/themes/three_cols/images/demo_btn_green.png" alt="демонстрационный пример" /></a></p>
<p>Сразу же даю ссылку на архив с исходниками.</p>
<p><a href='http://www.simplecoding.org/wp-content/uploads/2010/04/jquery_sortable.zip'><img src="http://www.simplecoding.org/wp-content/themes/three_cols/images/download_btn_blue.png" alt="архив с исходным кодом" /></a></p>
<p><strong>Теперь разберём принцип работы.</strong></p>
<p>На сегодняшний день сохранить данные html списка можно двумя способами.</p>
<p><strong>1) На стороне сервера в БД.</strong> При этом, после каждого изменения (удаления, создания новой) записи будет отправляться запрос серверу.</p>
<p><strong>2) В браузере</strong>, при условии, что он поддерживает HTML5 или есть доступ к какому-нибудь другому хранилищу. Этот способ работает быстрее и не требует постоянного подключения к интернету, но поддерживается не всеми браузерами. В частности, в IE работать не будет.</p>
<p>Поэтому я остановился на первом варианте.</p>
<p>Итак, наше приложение состоит из двух частей: клиентской и серверной.</p>
<p><strong>Клиентская часть</strong> представляет собой HTML страницу и набор JS скриптов, которые отправляют запросы, позволяют сортировать список и т.п.</p>
<p><strong>Серверная</strong> – это набор PHP скриптов, которые обрабатывают запросы и работают с базой данных. Я не использовал фреймворк в этом примере, поэтому получился набор отдельных скриптов под каждую операцию. При использовании фреймворка эти скрипты станут методами контроллера и, естественно, вы сможете использовать встроенную библиотеку для работы с БД.</p>
<p>Кстати, для этого примера я выбрал базу <strong>sqlite</strong>, но, т.к. доступ к ней осуществляется с помощью <strong>PDO</strong>, то вы легко сможете заменить её, например, на <strong>MySQL</strong> (достаточно будет изменить параметры подключения).</p>
<p><strong>Подключение к БД</strong></p>
<p>Выполняется скриптом <code>db.php</code>, сяостоящим всего из одной строки.</p>
<pre class="brush: php">$dbh = new PDO('sqlite:data/data.sqlite');</pre>
<p>Тут предполагается, что база находится в файле <code>data.sqlite</code>, расположенном в папке <code>data</code>.</p>
<p><strong>Структура БД.</strong></p>
<p>Т.к. задача у нас достаточно простая, мы обойдёмся одной таблицей с тремя полями:</p>
<p><code>id</code> – первичный ключ;<br />
<code>note</code> – текст записи;<br />
<code>note_order</code> – порядковый номер записи в списке (с помощью этого поля осуществляется сортировка).</p>
<p><strong>Создание страницы со списком</strong></p>
<p>Выполняется скриптом <code>index.php</code></p>
<pre class="brush: php">&lt;?php
try {
	//подключаемся к базе
	require_once('db.php');
	//получаем все записи
	$query = $dbh-&gt;query('SELECT * FROM notes ORDER BY note_order DESC');
	$result = $query-&gt;fetchAll();
	$dbh = null;
} catch(Exception $e) {
	$error = 'Ошибка: '.$e-&gt;getMessage();
}
?&gt;
&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;&gt;
&lt;head&gt;
	&lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html;charset=UTF-8&quot; /&gt;
	&lt;title&gt;jQuery Sortable Notes&lt;/title&gt;

	&lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;css/style.css&quot; media=&quot;all&quot; /&gt;

	&lt;script type=&quot;text/javascript&quot; src=&quot;js/jquery-1.4.2.min.js&quot;&gt;&lt;/script&gt;
	&lt;script type=&quot;text/javascript&quot; src=&quot;js/jquery-ui-1.8.custom.min.js&quot;&gt;&lt;/script&gt;
	&lt;script type=&quot;text/javascript&quot; src=&quot;js/jquery.jeditable.mini.js&quot;&gt;&lt;/script&gt;
	&lt;script type=&quot;text/javascript&quot; src=&quot;js/jquery.json-2.2.min.js&quot;&gt;&lt;/script&gt;
	&lt;script type=&quot;text/javascript&quot; src=&quot;js/init.js&quot;&gt;&lt;/script&gt;
&lt;/head&gt;
&lt;body&gt;
	&lt;h1&gt;Заметки&lt;/h1&gt;
	&lt;form action=&quot;addnew.php&quot; method=&quot;post&quot; id=&quot;addNewNote&quot;&gt;
		&lt;p&gt;
		&lt;input type=&quot;text&quot; name=&quot;notetext&quot; id=&quot;notetext&quot; size=&quot;40&quot; /&gt;
		&lt;input type=&quot;submit&quot; value=&quot;Добавить заметку&quot; /&gt;
		&lt;/p&gt;
	&lt;/form&gt;
&lt;?php
	//выводим сообщение об ошибке или формируем список записей
	if (isset($error)) {
		echo '&lt;h2&gt;'.$error.'&lt;/h2&gt;';
	} else {
		if (count($result) &gt; 0) {
			echo '&lt;ul id=&quot;sortable&quot;&gt;';
			foreach ($result as $row) {
				echo '&lt;li id=&quot;note_'.$row['id'].'&quot; class=&quot;editable&quot;&gt;&lt;span class=&quot;note&quot; id=&quot;n_'.$row['id'].'&quot;&gt;'.$row['note'].'&lt;/span&gt;&lt;a href=&quot;#&quot;&gt;&lt;img src=&quot;images/delete.png&quot; alt=&quot;Удалить&quot; /&gt;&lt;/a&gt;&lt;/li&gt;';
			}
			echo '&lt;/ul&gt;';
?&gt;
	&lt;form id=&quot;changeOrder&quot; method=&quot;post&quot; action=&quot;changeorder.php&quot;&gt;
		&lt;p&gt;&lt;input type=&quot;submit&quot; value=&quot;Сохранить сортировку&quot; /&gt;&lt;/p&gt;
	&lt;/form&gt;
&lt;?php
		} else {
			echo '&lt;h2&gt;Записи отстутствуют&lt;/h2&gt;';
		}
	}
?&gt;
&lt;/body&gt;
&lt;/html&gt;</pre>
<p>Прежде всего, мы подключаемся к базе и получаем список записей. Затем, формируем страницу. На странице размещаем:</p>
<p>- форму добавления новой записи;<br />
- список записей (или сообщение о том, что они отсутствуют);<br />
- форму обновления порядка записей.</p>
<p>Обратите внимание на разметку списка.</p>
<pre class="brush: html">&lt;ul id=&quot;sortable&quot;&gt;
	&lt;li id=&quot;note_58&quot; class=&quot;editable&quot;&gt;
		&lt;span class=&quot;note&quot; id=&quot;n_58&quot;&gt;Заметка 1&lt;/span&gt;
		&lt;a href=&quot;#&quot;&gt;&lt;img src=&quot;images/delete.png&quot; alt=&quot;Удалить&quot; /&gt;&lt;/a&gt;
	&lt;/li&gt;
&lt;/ul&gt;</pre>
<p>В атрибутах <code>id</code> хранится значения поля id соответствующих записей в БД. Приставки <code>note_</code> и <code>n_</code> добавлены для совместимости со стандартом (значение атрибута id не может начинаться с цифры).</p>
<p>Каждый тег <code>li</code> содержит текст записи и ссылку «Удалить».</p>
<p><strong>Сортировка списка</strong></p>
<p>Для того, чтобы пользователь смог перемещать записи списка мы подключили библиотеку jQuery и плагин <a href="http://jqueryui.com/">jQuery UI</a>.</p>
<p>Сделать список сортируемым можно одной строчкой кода (в файле <code>init.js</code>)</p>
<pre class="brush: javascript">$('#sortable').sortable();</pre>
<p><strong>Добавление новых записей</strong></p>
<p>Рассмотрим скрипт <code>addnote.php</code></p>
<pre class="brush: php">try {
	//проверяем, пришел текст записи или нет
	if (!isset($_POST['notetext']) || '' == $_POST['notetext']) {
		throw new Exception('Не указан текст записи');
	}
	//подключаемся к БД
	require_once('db.php');
	//находим запись с максимальным значением в поле order
	$query = $dbh-&gt;query('SELECT note_order FROM notes ORDER BY note_order DESC LIMIT 1');
	$result = $query-&gt;fetchAll();
	if (0 == count($result)) {
		$order = 1;
	} else {
		$order = $result[0]['note_order'] + 1;
	}
	//вставляем новую запись, поле note_order новой записи будет на единицу больше,
	//чем у найденной записи
	$notetext = htmlspecialchars($_POST['notetext']);
	$dbh-&gt;exec('INSERT INTO notes (note, note_order) VALUES ('.$dbh-&gt;quote($notetext).', '.$order.')');
	$result = array();
	//получаем id созданной записи
	$result['id'] = $dbh-&gt;lastInsertId();
	$result['note'] = $notetext;
	$result['note_order'] = $order;
	$dbh = null;
	//отправляем результаты браузеру
	echo json_encode($result);
} catch(Exception $e) {
	echo json_encode(array('err'=&gt;'Ошибка: '.$e-&gt;getMessage()));
}</pre>
<p>Прежде чем добавлять в базу запись, нам нужно определиться с её номером сортировки. Форма находится над списком, поэтому будет логично, что запись появится сразу под ней, т.е. в начале списка.</p>
<p>Чтобы не создавать отрицательные номера сортировки, я решил выводить список в порядке убывания этих номеров (значений в поле <code>note_order</code>). Поэтому первая запись списка будет иметь максимальный номер.</p>
<p>Для того, чтобы определить номер новой записи, мы выполняем запрос, который ищет запись с максимальным номером, и добавляем к этому номеру единицу. Если записей в базе нет, то начинаем нумерацию с единицы.</p>
<p>Затем выполняем обычный запрос создания записи, получаем её <code>id</code> и отправляем его браузеру.</p>
<p>Теперь рассмотрим <strong>клиентскую часть</strong>.</p>
<p>Записи у нас будут создаваться с помощью <strong>AJAX</strong> запросов, поэтому назначаем форме обработчик события <code>submit</code>.</p>
<pre class="brush: javascript">$('#addNewNote').submit(function() {
	var note = $('#notetext').val();
	if (note != '') {
		//отправка запроса
		$.post('addnew.php', {'notetext':note}, function(data) {
			var response = eval('('+data+')');
			if (response['err'] != null) {
				alert(response['err']);
			} else {
				var list = $('#sortable');
				//если список отсутствует
				if (list.length == 0) {
					//удаляем текст &quot;Записи отстутствуют&quot;
					$('h2').detach();
					//создаем список
					$('&lt;ul id=&quot;sortable&quot;&gt;&lt;/ul&gt;').sortable().insertAfter($('#addNewNote'));
					//создаем форму &quot;Сохранить сортировку&quot;
					createChangeOrderForm().insertAfter($('ul#sortable'));
				}
				//вставляем новую запись в список
				createLi(response['id'], response['note']).prependTo('#sortable');
			}
		});
	} else {
		alert('Вы забыли ввести текст заметки');
	}
	return false;
});</pre>
<p>В нём мы проверяем, заполнено ли поле с текстом записи, и отправляем AJAX запрос скрипту <code>addnew.php</code>.</p>
<p>После получения ответа сервера мы либо выводим сообщение об ошибке, либо добавляем новую запись. При добавлении записи проверяем, существует ли список вообще и, если нет, создаём его. Обратите внимание, что при создании списка мы делаем его сортируемым (метод <code>sortable()</code>).</p>
<p>Отдельно рассмотрим функцию создания элемента списка (тег <code>li</code>).</p>
<pre class="brush: javascript">function createLi(id, note) {
	var note = $('&lt;span class=&quot;note&quot; id=&quot;n_' + id + '&quot;&gt;' + note + '&lt;/span&gt;').editable('update.php', editableOptions);
	var link = $('&lt;a href=&quot;#&quot;&gt;&lt;img src=&quot;images/delete.png&quot; alt=&quot;Удалить&quot; /&gt;&lt;/a&gt;').click(removeLi);
	return $('&lt;li id=&quot;note_' + id + '&quot; class=&quot;editable&quot;&gt;&lt;/li&gt;').append(note).append(link);
}</pre>
<p>Здесь мы устанавливаем классы и <code>id</code> элементов и назначаем обработчики событий. Всего обработчиков два:</p>
<p>- обработчик двойного клика по тексту записи (он создаётся методом .editable, подробнее о нём чуть позже);</p>
<p>- обработчик клика по ссылке «Удалить» (позже мы его тоже подробно рассмотрим).</p>
<p>На этом я сегодня остановлюсь. Остальные функции мы рассмотрим в следующий раз.</p>
<p>Если есть вопросы или замечания, пишите, постараюсь ответить.</p>
<p><strong>До встречи!</strong></p>
<p><strong>UPD</strong>. Дописал продолжение <a href="http://www.simplecoding.org/jquery-plaginy-sortirovka-i-redaktirovanie-spiska-chast-vtoraya.html">jQuery + плагины: сортировка и редактирование списка (часть вторая)</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.simplecoding.org/jquery-plaginy-sortirovka-i-redaktirovanie-spiska.html/feed</wfw:commentRss>
		<slash:comments>30</slash:comments>
		</item>
		<item>
		<title>jQuery плагин: создаём виджет для сообщений из списков twitter’а</title>
		<link>http://www.simplecoding.org/jquery-plagin-sozdayom-vidzhet-dlya-soobshhenij-iz-spiskov-twitter.html</link>
		<comments>http://www.simplecoding.org/jquery-plagin-sozdayom-vidzhet-dlya-soobshhenij-iz-spiskov-twitter.html#comments</comments>
		<pubDate>Sun, 28 Mar 2010 19:24:39 +0000</pubDate>
		<dc:creator>Владимир</dc:creator>
				<category><![CDATA[Ajax]]></category>
		<category><![CDATA[HTML]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Web разработка]]></category>

		<guid isPermaLink="false">http://www.simplecoding.org/?p=1022</guid>
		<description><![CDATA[Сегодня вряд ли у кого-то вызывает сомнения популярность твиттера, и многие блоггеры размещают в сайдбаре ленту сообщений с этого сервиса. Вообще, это хорошая идея, особенно если тематика сообщений в твиттере совпадает с тематикой блога, но её можно развить. Думаю, вы уже фолловите людей, интересны которых совпадают с вашими, точнее с тематикой вашего блога. Думаю, посетителям [...]]]></description>
			<content:encoded><![CDATA[<div id="attachment_1023" class="wp-caption alignnone" style="width: 239px"><img src="http://www.simplecoding.org/wp-content/uploads/2010/03/jquery_twitter_widget.png" alt="jquery twitter widget" title="jquery twitter widget" width="229" height="184" style="float:left" class="size-full wp-image-1023" /><p class="wp-caption-text"> </p></div>
<p>Сегодня вряд ли у кого-то вызывает сомнения популярность твиттера, и многие блоггеры размещают в сайдбаре ленту сообщений с этого сервиса. Вообще, это хорошая идея, особенно <strong>если тематика сообщений в твиттере совпадает с тематикой блога</strong>, но её можно развить.</p>
<p>Думаю, вы уже фолловите людей, интересны которых совпадают с вашими, точнее с тематикой вашего блога. Думаю, посетителям будет гораздо интереснее читать <strong>тематические твиты</strong>, а не только ваши собственные. Кроме того, в этом случае виджет с твитами будет чаще обновляться.</p>
<p>Сделать это несложно. Добавляем подходящие twitter-ленты <strong>в отдельный список</strong> и публикуем его ленту. В этой статье я покажу, как создать такой виджет с помощью <strong>JavaScript</strong>.</p>
<p>Сразу даю ссылки на пример и архив с исходниками.<br />
<span id="more-1022"></span><br />
<a href="http://demosites.simplecoding.org/twitter/twitter_list.html"><img src="http://www.simplecoding.org/wp-content/themes/three_cols/images/demo_btn_green.png" alt="демонстрационный пример" /></a> <a href='http://www.simplecoding.org/wp-content/uploads/2010/03/twitter_widget.zip'><img src="http://www.simplecoding.org/wp-content/themes/three_cols/images/download_btn_blue.png" alt="архив с исходным кодом" /></a></p>
<p><em>Примечание</em>. Скорее всего, подобные возможности есть в существующих <strong>twitter</strong> плагинах, но собственное решение всегда легче настраивать <img src='http://www.simplecoding.org/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  , к тому же, сделать нужно совсем немного.</p>
<p>Для начала <strong>немного теории</strong>.</p>
<p><strong>Получение списка твитов.</strong></p>
<p>Как вы, наверное, знаете twitter предоставляет разработчикам довольно неплохой API для работы с сервисом. Им мы и воспользуемся. Потребуется всего одна функция <a href="http://apiwiki.twitter.com/Twitter-REST-API-Method%3A-GET-list-statuses">GET list statuses</a>. Она возвращает список твитов выбранного списка.</p>
<p>Принцип её работы следующий. Нужно отправить обычный GET запрос вида.</p>
<pre class="brush: html">http://api.twitter.com/1/user/lists/list_id/statuses.format</pre>
<p>где <code>user</code> – имя пользователя, который создал список;<br />
<code>list_id</code> – название списка;<br />
<code>format</code> – формат возвращаемых данных (доступны три варианта: xml, json и atom).</p>
<p>Например, запрос для получения моего списка <code>webdev</code> будет выглядеть так.</p>
<pre class="brush: html">http://api.twitter.com/1/simplecoding/lists/webdev/statuses.json</pre>
<p>Здесь <code>simplecoding</code> – имя пользователя (т.е. мой аккаунт в твиттере), а <code>webdev</code> – название списка. Т.к. работать мы будем на JS, то удобнее всего использовать <strong>json</strong> формат. Но вручную просматривать полученные данные удобнее в <strong>xml</strong>, т.к. большинство браузеров позволяет сворачивать xml теги. Так или иначе, если вы планируете работать с твиттером, просмотреть эти данные будет интересно.</p>
<p><strong>Переходим к созданию виджета.</strong></p>
<p>Чтобы виджет было удобно использовать на разных сайтах, я решил написать плагин к jQuery, который будет получать список твитов и вставлять их в указанный контейнер (например, тег <code>div</code>). Оформление виджета сделаем с помощью CSS.</p>
<p>Создаём страницу, на которой будет находиться виджет.</p>
<pre class="brush: html">&lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD XHTML 1.1//EN&quot; &quot;http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd&quot;&gt;
&lt;html xmlns=&quot;http://www.w3.org/1999/xhtml&quot; xml:lang=&quot;en&quot;&gt;

&lt;head&gt;
    &lt;title&gt;My Twitter List&lt;/title&gt;
    &lt;link rel=&quot;stylesheet&quot; href=&quot;styles.css&quot; /&gt;
&lt;/head&gt;
&lt;body&gt;
    &lt;h1&gt;My Twitter List&lt;/h1&gt;
    &lt;div id=&quot;mylist&quot;&gt;&lt;/div&gt;
    &lt;script type=&quot;text/javascript&quot; src=&quot;jquery-1.4.2.min.js&quot;&gt;&lt;/script&gt;
    &lt;script type=&quot;text/javascript&quot; src=&quot;twitterlist.jquery.js&quot;&gt;&lt;/script&gt;
    &lt;script type=&quot;text/javascript&quot;&gt;
        $(function() {
            $('#mylist').twitterList();
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;</pre>
<p>Для виджета мы создали тег div (строка 10), затем подключили файлы библиотеки <strong>jQuery</strong> и нашего плагина (<code>twitterlist.jquery.js</code>, строки 11, 12).</p>
<p>Запуск плагина выполняется с помощью метода <code>twitterList()</code>. В параметрах этого метода можно указать имя пользователя и название списка, твиты из которого нужно показать. Например</p>
<pre class="brush: javascript">twitterList({'user':'maxsite', 'list':'bloggers'})</pre>
<p>Рассмотрим сам плагин</p>
<pre class="brush: javascript">(function($) {
    $.fn.twitterList = function(settings) {
        //дефолтные настройки
        var config = {
            'user' : 'simplecoding'
            ,'list' : 'webdev'
        };
        //применяем настройки, указанные пользователем
        if (settings) $.extend(config, settings);
        //сохраняем указатель на блок, в который нужно вставить твиты
        var twitterBlock = this;
        //получаем список твитов

        //шаблон для поиска ссылок в твитах
        var pattern = /(http\S+)/gi;

        $.getJSON('http://api.twitter.com/1/' + config.user + '/lists/' + config.list + '/statuses.json?per_page=10&amp;callback=?'
            , function(twites) {
                //добавляем твиты в блок на странице
                $.each(twites, function(i, tweet) {
                    //добавляем к ссылкам тег a
                    var text = tweet.text.replace(pattern, '&lt;a href=&quot;$1&quot;&gt;$1&lt;/a&gt;');
                    //создаём тег div с текущим твитом...
                    var curTweet = $('&lt;div class=&quot;tweet&quot;&gt;' + text + '&lt;/div&gt;');
                    //...вставляем его в список
                    curTweet.appendTo(twitterBlock);
                });
            }
        );
    };
})(jQuery);</pre>
<p>Если вы никогда не писали плагинов для jQuery и не использовали JSONP, то этот код вызовет вопросы. Поэтому я очень советую прежде чем приниматься за этот пример прочитать две статьи: <a href="http://www.simplecoding.org/sozdaem-plagin-dlya-jquery.html">Создаем плагин для jQuery</a> и <a href="http://www.simplecoding.org/xss-s-ispolzovaniem-jsonp-i-jquery.html">XSS с использованием JSONP и jQuery</a> или любые другие материалы на эти темы.</p>
<p>Здесь мы только кратко рассмотрим, что происходит при <strong>запуске плагина</strong>.</p>
<p>1) Сохраняем параметры, указанные пользователем в хеше <code>config</code>.</p>
<p>2) Сохраняем имя блока, в который нужно вставлять твиты в переменной <code>twitterBlock</code>.</p>
<p>3) Создаём регулярное выражение для поиска ссылок в твитах. Твиты мы получим в виде обычного текста, поэтому вставлять теги <code>&lt;a&gt;</code> нужно будет самостоятельно.</p>
<p>4) Отправляем запрос серверу твиттера. Тут к запросу мы добавили два параметра: <code>per_page=10</code> (количество твитов, которые мы хотим показать) и <code>callback=?</code> (имя функции, которой будут переданы полученные данные). Вместо знака вопроса jQuery подставит сгенерированное имя функции. Саму функцию мы объявляем во втором параметре метода <code>getJSON</code>.</p>
<p>5) Формируем список твитов. Эта операция выполняется в анонимной функции (строки 18-27), которая будет вызвана сразу после получения данных от twitter&#039;а. Мы получим массив объектами, которые содержат данные каждого твита.</p>
<p>В данном случае нам нужно только вывести текст твита (он находится в атрибуте <code>text</code>) и сформировать ссылки. В нашем случае получить текст можно с помощь <code>tweet.text</code>, а создать ссылки – с помощью<br />
<code>replace(pattern, '&lt;a href=&quot;$1&quot;&gt;$1&lt;/a&gt;')</code>,<br />
вместо <code>$1</code> будет подставлена ссылка (совпадение с первой маской в регулярном выражении).</p>
<p>Вставку твита в список выполняем с помощью метода <code>appendTo</code> (строка 26).</p>
<p>Всё! Плагин работает. Естественно, функциональность виджета минимальная, но её несложно расширить. Например, можно добавить фотографии пользователей, ссылки на их ники и т.п. (всю эту информацию мы получаем в массиве с данными твитов).</p>
<p>Кроме того, возможно, вы захотите сделать фильтрацию твитов по каким-нибудь ключевым словам. Ограничений практически нет.</p>
<p>Я планирую продолжить эту тему, поэтому буду рад любым советам, пожеланиям и идеям!</p>
<p>До встречи!</p>
<p><strong>Полезные ссылки.</strong></p>
<p>На нашем портале вы найдёте полезные инструменты, которые помогут выбрать <a href='http://estbase.ru/'>недвижимость</a>, а также интересные статьи и объявления.</p>
<p>Попали в незнакомый город и боитесь заблудиться? В такой ситуации вам пригодятся <a href='http://shopelek.ru/gps_navigatory/'>GPS навигаторы</a> от ведущих мировых производителей.</p>
<p>В вашей квартире старые окна и вы мёрзнете зимой? Решить проблему поможет <a href='http://www.okna-git.ru'>установка пластиковых окон</a>. Они не только сохранят тепло, но и защитят от шума.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.simplecoding.org/jquery-plagin-sozdayom-vidzhet-dlya-soobshhenij-iz-spiskov-twitter.html/feed</wfw:commentRss>
		<slash:comments>13</slash:comments>
		</item>
		<item>
		<title>Использование jqGrid вместе с Yii фреймворком</title>
		<link>http://www.simplecoding.org/ispolzovanie-jqgrid-vmeste-s-yii-frejmvorkom.html</link>
		<comments>http://www.simplecoding.org/ispolzovanie-jqgrid-vmeste-s-yii-frejmvorkom.html#comments</comments>
		<pubDate>Thu, 18 Mar 2010 13:45:17 +0000</pubDate>
		<dc:creator>Владимир</dc:creator>
				<category><![CDATA[Ajax]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Web разработка]]></category>
		<category><![CDATA[Yii]]></category>

		<guid isPermaLink="false">http://www.simplecoding.org/?p=1018</guid>
		<description><![CDATA[Приветствую всех! В этой статье речь пойдёт о том как использовать Yii PHP framework и плагин к jQuery под названием jqGrid. Я не буду повторяться и рассказывать о том, что из себя представляют Yii и jqGrid и зачем они нужны. Вы легко найдёте все мои заметки на эту тему с помощью поиска по блогу (кстати, [...]]]></description>
			<content:encoded><![CDATA[<div id="attachment_1019" class="wp-caption alignnone" style="width: 272px"><img src="http://www.simplecoding.org/wp-content/uploads/2010/03/yii_php_jqgrid.png" alt="yii php jqgrid" title="yii php jqgrid" width="262" height="175" style="float:left" class="size-full wp-image-1019" /><p class="wp-caption-text"> </p></div>
<p><strong>Приветствую всех!</strong></p>
<p>В этой статье речь пойдёт о том как использовать <strong>Yii PHP framework</strong> и плагин к <strong>jQuery </strong>под названием jqGrid. Я не буду повторяться и рассказывать о том, что из себя представляют Yii и jqGrid и зачем они нужны. Вы легко найдёте все мои заметки на эту тему с помощью поиска по блогу <img src='http://www.simplecoding.org/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' />  (кстати, все статьи о Yii вынесены в отдельный <a href="http://www.simplecoding.org/category/yii">раздел</a>).</p>
<p>Когда я проводил этот эксперимент, меня интересовали два момента:</p>
<p><strong>1) подключение jgGrid;</strong></p>
<p><strong>2) преобразование данных</strong>, полученных с помощью CActiveDataProvider в формат понятный для jgGrid.</p>
<p>С первым пунктом всё более-менее понятно. <strong>jqGrid</strong> представляет собой набор JS и CSS файлов, которые нужно подключить к странице.<br />
<span id="more-1018"></span><br />
Для этих целей в Yii предусмотрены специальные методы: <code>registerScriptFile </code>и <code>registerCssFile</code>. Можно, конечно, просто прописать теги <code>script</code> в представлении, но делать этого не рекомендуется, т.к. в этом случае фреймоворк не сможет отслеживать повторные подключения скриптов.</p>
<p>Примечание. Подробнее о работе с JS и CSS файлами можно почитать <a href="http://www.simplecoding.org/yii-php-framework-sozdayom-igrovoj-sajt-chast-7-rabota-s-javascript-i-stranicy-igr.html">здесь</a>.</p>
<p>Т.к. я просто экспериментировал, я сделал тестовое представление (testjqgrid.php)</p>
<pre class="brush: php">//подключение CSS файлов и JS скриптов
$cs = Yii::app()-&gt;clientScript;

$cs-&gt;registerCssFile(Yii::app()-&gt;request-&gt;baseUrl.'/jqgrid/css/ui.jqgrid.css');
$cs-&gt;registerCssFile(Yii::app()-&gt;request-&gt;baseUrl.'/jqgrid/css/ui-lightness/jquery-ui-1.7.2.custom.css');

$cs-&gt;registerScriptFile(Yii::app()-&gt;request-&gt;baseUrl.'/jqgrid/js/jquery-1.3.2.min.js');
$cs-&gt;registerScriptFile(Yii::app()-&gt;request-&gt;baseUrl.'/jqgrid/js/i18n/grid.locale-ru.js');
$cs-&gt;registerScriptFile(Yii::app()-&gt;request-&gt;baseUrl.'/jqgrid/js/jquery.jqGrid.min.js');
?&gt;
&lt;table id=&quot;list&quot;&gt;&lt;/table&gt;
&lt;div id=&quot;pager&quot;&gt;&lt;/div&gt; 

&lt;script type=&quot;text/javascript&quot;&gt;
$(function() {
	jQuery(&quot;#list&quot;).jqGrid( {
		url : '&lt;?php echo $this-&gt;createUrl('blogs/jqgriddata'); ?&gt;',
		datatype : 'json',
		mtype : 'GET',
		colNames : [ '#', 'Name', 'URL', 'API' ],
		colModel : [ {
			name : 'b_id',
			index : 'b_id',
			width : 60
		}, {
			name : 'b_name',
			index : 'b_name',
			width : 120
		}, {
			name : 'b_url',
			index : 'b_url',
			width : 150,
			align : 'right'
		}, {
			name : 'b_api',
			index : 'b_api',
			width : 80,
			align : 'right'
		} ],
		pager : '#pager',
		rowNum : 10,
		rowList : [ 10, 20, 30 ],
		sortname : 'invid',
		sortorder : 'desc',
		viewrecords : true,
		caption : 'Blogs'
	});
});
&lt;/script&gt;</pre>
<p>Как видите, сначала мы регистрируем скрипты и файлы стилей, затем вставляем тег для таблицы (строка 12) и тег для панели навигации.</p>
<p><em>Примечание</em>. В этом примере использован первый попавшийся контроллер (<code>BlogsController</code>). Кроме того, для получения данных используется модель <code>Blogs</code>. Зачем она нужна, в данном случае не принципиально, мы просто будем отображать записи из таблицы с помощью jqGrid.</p>
<p>В конце представления находится код настройки jqGrid. Таблица будет содержать 4 колонки с названиями: «#», «Name», «URL» и «API», а соответствующие поля в таблице имеют названия: «b_id», «b_name», «b_url» и «b_api».</p>
<p>И, конечно, нужно указать адрес скрипта, который будет формировать данные для таблицы (строка 18, параметр url).</p>
<p><strong>Формирование таблицы.</strong></p>
<p>Т.к. jqGrid получает данные с помощью AJAX запросов, то мы добавим два метода в контроллер. Первый – <code>actionJqgrid</code>, будет формировать страницу с таблицей, т.е. просто загружать представление. Второй – <code>actionJqgriddata</code>, предназначен для обработки AJAX запросов.</p>
<pre class="brush: php">public function actionJqgrid() {
	$this-&gt;render('testjqgrid');
}

public function actionJqgriddata() {
	$dataProvider=new CActiveDataProvider('Blogs', array(
		'pagination'=&gt;array(
			'pageSize'=&gt;$_GET['rows'],
			'currentPage'=&gt;$_GET['page']-1,
		),
	));
	$responce-&gt;page = $_GET['page'];
	$responce-&gt;records = $dataProvider-&gt;getTotalItemCount();
	$responce-&gt;total = ceil($responce-&gt;records / $_GET['rows']);
	$rows = $dataProvider-&gt;getData();
	foreach ($rows as $i=&gt;$row) {
		$responce-&gt;rows[$i]['id'] = $row['b_id'];
		$responce-&gt;rows[$i]['cell'] = array($row-&gt;b_id, $row-&gt;b_name, $row-&gt;b_url, $row-&gt;b_api);
	}
	echo json_encode($responce);
}</pre>
<p>Рассмотрим их подробнее. Как я уже говорил, метод <code>actionJqgrid </code>просто загружает представление. Получать данные из базы нам не нужно, т.к. при создании таблицы jqGrid всё равно отправит AJAX запрос на их получение.</p>
<p>С методом <code>actionJqgriddata</code> ситуация немного сложнее. Дело в том, что нам нужно преобразовать данные, которые возвращает <code>CActiveDataProvider</code> в формат, понятный jqGrid.</p>
<p>Для этого мы создаём объект <code>$responce</code> и в нём сохраняем:</p>
<p>1) <code>page</code> – номер текущей страницы;</p>
<p>2) <code>records</code> – общее количество записей;</p>
<p>3) <code>total</code> – общее количество страниц;</p>
<p>4) <code>rows</code> – массив с данными. Каждый элемент этого массива должен содержать id текущей записи и массив cell с данными ячеек. Этот массив мы формируем с помощью цикла (строки 16-19).</p>
<p>После это преобразовываем <code>$responce</code> в JSON формат и возвращаем браузеру.</p>
<p>Как видите, принцип достаточно простой, но код получается объёмный. В принципе, есть расширение <a href="http://www.yiiframework.com/extension/eziiui/">eziiui</a>, которое упрощает работу с jqGrid, но судя по отзывам, оно ограничивает ваши возможности в использовании jqGrid, поэтому я им не пользовался.</p>
<p>Может быть стоит написать расширение, которое будет преобразовывать данные из <code>CActiveDataProvider</code> в JSON формат? Или есть другие идеи?</p>
<p><strong>Полезные ссылки</strong></p>
<p>Блоггер, заходи на новый <a href="http://www.bloggers.su/forum/" target="_blank">форум блоггеров</a>, общайся и зарабатывай.</p>
<p>Не бойтесь холода, подберите себе <a href='http://sharfik.ru/'>шарфы интернет магазин</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.simplecoding.org/ispolzovanie-jqgrid-vmeste-s-yii-frejmvorkom.html/feed</wfw:commentRss>
		<slash:comments>25</slash:comments>
		</item>
		<item>
		<title>Yii фреймворк: создание кнопок с помощью CButtonColumn</title>
		<link>http://www.simplecoding.org/yii-frejmvork-sozdanie-knopok-s-pomoshhyu-cbuttoncolumn.html</link>
		<comments>http://www.simplecoding.org/yii-frejmvork-sozdanie-knopok-s-pomoshhyu-cbuttoncolumn.html#comments</comments>
		<pubDate>Sat, 27 Feb 2010 20:39:14 +0000</pubDate>
		<dc:creator>Владимир</dc:creator>
				<category><![CDATA[Ajax]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Web разработка]]></category>
		<category><![CDATA[Yii]]></category>

		<guid isPermaLink="false">http://www.simplecoding.org/?p=1008</guid>
		<description><![CDATA[Тему этого поста подсказал мне читатель по имени Alex, за что ему большое спасибо. Речь о компонентах zii, которые, начиная с версии 1.1, входят в состав фреймворка, и активно используются утилитой yiic при генерации кода. К сожалению, документация по этим компонентам есть только в виде API (комментарии к исходникам) и её явно недостаточно. Ситуация следующая. [...]]]></description>
			<content:encoded><![CDATA[<div id="attachment_1009" class="wp-caption alignnone" style="width: 282px"><img src="http://www.simplecoding.org/wp-content/uploads/2010/02/yii_php_CButtonColumn.png" alt="yii php CButtonColumn" title="yii php CButtonColumn" width="272" height="103" style="float:left" class="size-full wp-image-1009" /><p class="wp-caption-text"> </p></div>
<p>Тему этого поста подсказал мне читатель по имени <strong>Alex</strong>, за что ему большое спасибо.</p>
<p>Речь о компонентах <strong>zii</strong>, которые, начиная с версии 1.1, входят в состав фреймворка, и активно используются утилитой yiic при генерации кода.</p>
<p>К сожалению, документация по этим компонентам есть только в виде <strong>API</strong> (комментарии к исходникам) и её явно недостаточно.</p>
<p>Ситуация следующая. Если вас полностью устраивает код, который генерирует <strong>yiic</strong> &#8211; никаких проблем. Но вот что-то изменить или добавить какие-нибудь возможности уже сложнее.<br />
<span id="more-1008"></span><br />
Рассмотрим такую ситуацию. Для одной из таблиц в БД вы создали стандартный набор CRUD операций. И вам нужно в таблицу с перечнем записей добавить дополнительную кнопку. На первый взгляд, задача довольно простая, т.к. таблица генерируется с помощью виджета &#039;<code>zii.widgets.grid.CGridView</code>&#039; и среди компонентов <strong>zii</strong> есть <a href="http://www.yiiframework.com/doc/api/CButtonColumn">CButtonColumn</a>, который специально предназначен для создания колонок с кнопками. Т.е. <strong>задача заключается в настройке этого компонента</strong>.</p>
<p>Чтобы было понятнее, рассмотрим небольшой пример.</p>
<p>Создаём новое приложение<br />
<code>yiic webapp .</code><br />
По-умолчанию в нём есть sqlite база с одной таблицей (данными пользователей)</p>
<p>Создаём модель<br />
<code>yiic shell<br />
model User tbl_user</code></p>
<p>и CRUD интерфейс<br />
<code>crud User</code></p>
<p>В результате будет сгенерировано несколько скриптов, которые позволят управлять записями в таблице.</p>
<p>При этом страница управления записями (<code>index.php?r=user/admin</code>) содержит таблицу с перечнем записей и столбцов с кнопками «View», «Update», «Delete». Я сделал скриншот (несколько колонок убрал, чтобы уменьшить ширину таблицы).</p>
<div id="attachment_1010" class="wp-caption alignnone" style="width: 393px"><img src="http://www.simplecoding.org/wp-content/uploads/2010/02/initial_grid.png" alt="initial grid" title="initial grid" width="383" height="294" class="size-full wp-image-1010" /><p class="wp-caption-text"> </p></div>
<p>Взгляните на код, который создаёт стандартную таблицу с тремя кнопками.</p>
<pre class="brush: php">&lt;?php $this-&gt;widget('zii.widgets.grid.CGridView', array(
	'dataProvider'=&gt;$dataProvider,
	'columns'=&gt;array(
		'id',
		'username',
		'password',
		'email',
		array(
			'class'=&gt;'CButtonColumn',
		),
	),
)); ?&gt;</pre>
<p>В массиве <code>columns</code> перечисляем названия столбцов таблицы. Если имя столбца совпадает с полем таблице, то оно будет заполнено соответствующими данными. В последнем элементе указан массив с одним элементом <code>'class'=>'CButtonColumn'</code>. Этого достаточно для создания трёх стандартных кнопок.</p>
<p>Попробуем добавить ещё один столбец с кнопкой «<strong>AJAX запрос</strong>». Для этого добавим ещё один элемент в массив <code>'columns'</code></p>
<pre class="brush: php">array(
	'class'=&gt;'CButtonColumn',
	'buttons'=&gt;array(
		'preview'=&gt;array(
			'label'=&gt;'AJAX запрос',
			'url'=&gt;'…',
			'click'=&gt;'…',
		),
	),
	'template'=&gt;'{preview}',
),</pre>
<p>Принцип следующий. В элементе <code>'buttons'</code> нужно указать массив с новыми кнопками. При этом ключ каждого элемента этого массива является названием кнопки. Его мы должны использовать в элементе <code>'template'</code> для того, чтобы показать кнопку в таблице. Название необходимо заключит в фигурные скобки. При этом можно добавить в одну ячейку сразу несколько кнопок, например, так:<br />
<code>'{view} {update} {delete}'</code>.</p>
<p>Для каждой кнопки необходимо указать <strong>массив с параметрами</strong>.<br />
<code>'label'</code> – содержит текст, который будет отображаться на кнопке.<br />
<code>'url'</code> – PHP выражение, которое сформирует ссылку для данной кнопки.<br />
<code>'click'</code> – JS функция, которая будет назначена в качестве обработчика клика по кнопке.</p>
<p>Кроме того, можно указать картинку и массив с html атрибутами с помощью параметров <code>'imageUrl'</code> и <code>'options'</code>. Но сейчас речь не о них. У меня больше всего вопросов вызвали <code>'url'</code> и <code>'click'</code>.</p>
<p>Расписывать свои ковыряния в исходниках я не буду. Лучше сразу покажу решение.</p>
<p>В параметре <code>'url'</code> нужно записать <strong>PHP</strong> выражение, которое сформирует URL, в виде строки, т.е. в кавычках. Например,</p>
<pre class="brush: php">'url'=>'Yii::app()-&gt;createUrl("user/getuser")'</pre>
<p>При этом будут доступны <strong>две переменные</strong>: <code>$row</code> и <code>$data</code>. Первая содержит номер строки, вторая &#8211; объект с данными текущей записи. Т.е. добавить в запрос GET параметр с email’ом пользователя можно так:</p>
<pre class="brush: php">'url'=>'Yii::app()-&gt;createUrl("user/getuser", array("email"=&gt;$data->email))'</pre>
<p>Для того, чтобы проверить отправку AJAX запросов я добавил в контроллер метод actionGetuser. Он ищет пользователя по его email&#039;у.</p>
<pre class="brush: php">public function actionGetuser() {
	if (isset($_GET['email'])) {
		$user = User::model()-&gt;find('email=:email', array(':email'=&gt;$_GET['email']));
		if (null !== $user) {
			echo $user-&gt;username;
		} else {
			echo 'unknown';
		}
	} else {
		echo 'unknown';
	}
}</pre>
<p>Напишем функцию, которая будет выполнять отправку запроса. Я добавил её прямо в представление.</p>
<pre class="brush: php">&lt;?php
$js_preview =&lt;&lt;&lt; EOD
function() {
	var url = $(this).attr('href');
	$.get(url, function(response) {
		alert(response);
	});
	return false;
}
EOD;
?&gt;

&lt;?php $this-&gt;widget('zii.widgets.grid.CGridView', array(
	'dataProvider'=&gt;$dataProvider,
	'columns'=&gt;array(
		'id',
		'username',
		'password',
		'email',
		array(
			'class'=&gt;'CButtonColumn',
		),
		array(
			'class'=&gt;'CButtonColumn',
			'buttons'=&gt;array(
				'preview'=&gt;array(
					'label'=&gt;'AJAX запрос',
					'url'=&gt;'Yii::app()-&gt;createUrl(&quot;user/getuser&quot;, array(&quot;email&quot;=&gt;$data-&gt;email))',
					'click'=&gt;$js_preview,
				),
			),
			'template'=&gt;'{preview}',
		),
	),
)); ?&gt;</pre>
<p>Как видите, текст JS функции присвоен переменной <code>$js_preview</code>. Эту переменную мы и указываем в параметре <code>'click'</code>.</p>
<p><strong>Принцип работы</strong> следующий.</p>
<p>1) Получаем URL данной кнопки (с помощью <code>$(this).attr('href')</code>). Он уже содержит email в качестве GET параметра.</p>
<p>2) Отправляем AJAX запрос (с помощью <code>$.get</code>).</p>
<p>3) Показываем результат (<code>alert(response)</code>).</p>
<p>Как видите, кода нужно написать минимум, но, повторюсь, очень хотелось бы почитать подробное руководство от разработчиков о компонентах zii <img src='http://www.simplecoding.org/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p>Если есть замечания или вопросы, пишите, обсудим <img src='http://www.simplecoding.org/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p><strong>Интересно почитать</strong></p>
<p><a href="http://bormaley.com/daiting/uchimsya-rabotat-v-deytinge-dating-help.html">Дейтинг</a> &#8211; хорошая возможность заработать на своих интернет-проектах.</p>
<p>Спастись от жары не сложно. Достаточно <a href="http://climatique.ru/catalog/conditions.html">купить сплит-системы</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.simplecoding.org/yii-frejmvork-sozdanie-knopok-s-pomoshhyu-cbuttoncolumn.html/feed</wfw:commentRss>
		<slash:comments>38</slash:comments>
		</item>
	</channel>
</rss>

