<?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>Очередной блог фрилансера &#187; общая</title>
	<atom:link href="http://dreamhelg.ru/category/uncategorized/feed/" rel="self" type="application/rss+xml" />
	<link>http://dreamhelg.ru</link>
	<description>о моей работе в сети и не только</description>
	<lastBuildDate>Fri, 23 Dec 2011 07:10:04 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3</generator>
		<item>
		<title>Эффект неонового текста с помощью CSS и JQuery</title>
		<link>http://dreamhelg.ru/2010/06/neon-text-effect-with-css-and-jquery/</link>
		<comments>http://dreamhelg.ru/2010/06/neon-text-effect-with-css-and-jquery/#comments</comments>
		<pubDate>Wed, 09 Jun 2010 05:00:07 +0000</pubDate>
		<dc:creator>dreamhelg</dc:creator>
				<category><![CDATA[общая]]></category>
		<category><![CDATA[переводы]]></category>
		<category><![CDATA[css]]></category>
		<category><![CDATA[jquery]]></category>

		<guid isPermaLink="false">http://dreamhelg.ru/?p=2043</guid>
		<description><![CDATA[<p><img width="200" height="200" src="http://dreamhelg.ru/wp-content/uploads/2010/06/home.png" class="attachment-200x200 wp-post-image" alt="home" title="home" /></p>В сегодняшней статье, вы узнаете как создать красивый эффект неонового свечения текста, средствами JQuery и CSS, и совсем немного фотошопа. Результат, как обычно можно посмотреть <a href="http://demo.tutorialzine.com/2010/06/neon-text-effect-jquery/demo.html" target="_blank">заранее</a>.<span id="more-2043"></span>
<br/>
<h3>Шаг 1 – Дизайн</h3>
Первым делом, для достижения такого эффекта, нам нужно создать фоновое изображение, содержащее две, слегка отличающиеся версии текста. jQuery будет плавно переключаться между этими изображениями, создавая красивый эффект свечения.

Итак, открываем фотошоп  и создаем новый документ, 650х300 пикселей, в качестве фонового цвета указываем #141414. Для заголовка используйте свой любимый шрифт, в приведенном примере – это Century Gothic, размер 60px.

После этого, Ctrl + клик по иконке текстового слоя в палитре слоев, для выделения всего текста.

<a href="http://dreamhelg.ru/wp-content/uploads/2010/06/i1.png"><img class="aligncenter size-full wp-image-2045" title="i1" src="http://dreamhelg.ru/wp-content/uploads/2010/06/i1.png" alt="" width="620" height="260" /></a>

Используйте инструмент прямоугольного выделения, зажав Shift + Alt, для того, чтобы ограничить выделение текста одним словом.

<a href="http://dreamhelg.ru/wp-content/uploads/2010/06/i2.png"><img class="aligncenter size-full wp-image-2046" title="i2" src="http://dreamhelg.ru/wp-content/uploads/2010/06/i2.png" alt="" width="620" height="260" /></a>

Далее, сохраняя выделение, создайте новый слой под названием “gradients”, и кликните по нему, для активации.

<a href="http://dreamhelg.ru/wp-content/uploads/2010/06/i3.png"><img class="aligncenter size-full wp-image-2047" title="i3" src="http://dreamhelg.ru/wp-content/uploads/2010/06/i3.png" alt="" width="620" height="260" /></a>

Теперь, возьмите инструмент градиента и раскрасьте каждое слово, поочередно переключая выделение между отдельными словами. Выделение отдельных слов требуется для ограничения области действия градиента, к тому же мы предварительно активировали слой “gradients”, с тем, чтобы все изменения были сохранены на нем.

<a href="http://dreamhelg.ru/wp-content/uploads/2010/06/i4.png"><img class="aligncenter size-full wp-image-2048" title="i4" src="http://dreamhelg.ru/wp-content/uploads/2010/06/i4.png" alt="" width="620" height="260" /></a>

После того, как вы раскрасите весь заголовок, дублируйте слой, расположив его ниже основного, и примените другой набор градиентов. В результате, у нас получилась картинка, с двумя разноцветными заголовками, так что мы легко сможем переключаться между ними, путем простого изменения свойства background-position в CSS.

<a href="http://dreamhelg.ru/wp-content/uploads/2010/06/i5.png"><img class="aligncenter size-full wp-image-2049" title="i5" src="http://dreamhelg.ru/wp-content/uploads/2010/06/i5.png" alt="" width="620" height="260" /></a>

Вы найдете psd-файл данного изображения, в архиве с приведенным примером.
<h3>Шаг 2 – XHTML</h3>
XHTML-разметка очень простая, вам понадобится только контейнер (#neonText H1), который будет содержать две версии фона.

[html]
&lt;h1 id=&quot;neonText&quot;&gt;
	Neon Text Effect With jQuery &amp; CSS.
	&lt;span class=&quot;textVersion&quot; id=&quot;layer1&quot;&gt;&lt;/span&gt;
	&lt;span class=&quot;textVersion&quot; id=&quot;layer2&quot;&gt;&lt;/span&gt;
&lt;/h1&gt;
[/html]

Слой layer1, постепенно уменьшая свою прозрачность, создает плавный эффект неонового свечения, за счет того, что он расположен поверх слоя layer2.

Исходя из соображений поисковой оптимизации, мы также создадим текст, соответствующий надписи на картинке, который будет скрыт с помощью отрицательного значения свойства text-indent.
<h3>Шаг 3 – CSS</h3>
Стили, используемые для этого эффекта – также очень простые. Два элемента span, которым назначено одинаковое фоновое изображение, с разницей в позиционировании. Один элемент показывает только верхнюю часть картинки, а второй, только нижнюю.

[css]
/* The two text layers */
#neonText span{
	width:700px;
	height:150px;
	position:absolute;
	left:0;
	top:0;

	background:url('img/text.jpg') no-repeat left top;
}

span#layer1{
	z-index:100;
}

span#layer2{
	background-position:left bottom;
	z-index:99;
}

/* The h1 tag that holds the layers */
#neonText{
	height:150px;
	margin:180px auto 0;
	position:relative;
	width:650px;
	text-indent:-9999px;
}
[/css]

Контейнер #neonText позиционирован относительно, с тем, чтобы внутренние элементы span, располагались точно один над другим. Кроме того, обратите вниманием на свойство text-indent, которое скрывает текстовое содержимое нашего контейнера.

<h3>Шаг 4 – jQuery</h3>
Последнее, что нам осталось сделать – создать анимацию переключения блоков. Поскольку мы используем jQuery (предварительно подключив его на страницу тэгом script), в нашем распоряжении есть два удобных метода fadeIn и fadeOut, которые мы используем в следующем коде.

[javascript]
$(document).ready(function(){

	setInterval(function(){

		// Selecting only the visible layers:
		var versions = $('.textVersion:visible');

		if(versions.length&lt;2){
			// If only one layer is visible, show the other
			$('.textVersion').fadeIn(800);
		}
		else{
			// Hide the upper layer
			versions.eq(0).fadeOut(800);
		}
	},1000);

});
[/javascript]

Функция, расположенная внутри выражения setinterval, выполняется каждую секунду, отображая/скрывая слой с первым контейнером span.

<a href="http://demo.tutorialzine.com/2010/06/neon-text-effect-jquery/demo.zip">Скачать архив с примером</a>.

Перевод статьи “<a href="http://tutorialzine.com/2010/06/neon-text-effect-jquery/">Neon Text Effect With jQuery &amp; CSS</a>”, автор <strong>Martin</strong>]]></description>
		<wfw:commentRss>http://dreamhelg.ru/2010/06/neon-text-effect-with-css-and-jquery/feed/</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
		<item>
		<title>Инструменты для тестирования и отладки в IE</title>
		<link>http://dreamhelg.ru/2010/03/debugging-and-testing-tools-in-ie/</link>
		<comments>http://dreamhelg.ru/2010/03/debugging-and-testing-tools-in-ie/#comments</comments>
		<pubDate>Fri, 26 Mar 2010 05:00:02 +0000</pubDate>
		<dc:creator>dreamhelg</dc:creator>
				<category><![CDATA[общая]]></category>
		<category><![CDATA[переводы]]></category>
		<category><![CDATA[IE]]></category>
		<category><![CDATA[инструменты]]></category>

		<guid isPermaLink="false">http://dreamhelg.ru/?p=1920</guid>
		<description><![CDATA[<p><img width="200" height="200" src="http://dreamhelg.ru/wp-content/uploads/2010/03/home1.png" class="attachment-200x200 wp-post-image" alt="home" title="home" /></p>Очень часто, при разработке проекта, его тестирование в Internet Explorer откладывают до последнего. И это вполне нормально, если ваши проблемы в основном связаны с версткой страницы.

Однако, во время разработки веб-приложения с большим количеством различных функций, вполне возможно появление другого рода проблем: постоянная отладка, производительность на клиентской стороне, проприетарные проблемы и многое другое. В любом случае, производить отладку в IE не всегда так же комфортно, как в других браузерах.<span id="more-1920"></span>

В сегодняшней статье, мы рассмотрим различные наборы инструментов, которые помогут вам сделать процесс отладки и тестирования в IE, более приятным.
<h3>Сборки браузеров</h3>
<p style="text-align: center;"><a href="http://dreamhelg.ru/wp-content/uploads/2010/03/browserpackages.jpg"><img class="size-full wp-image-1947 aligncenter" title="browserpackages" src="http://dreamhelg.ru/wp-content/uploads/2010/03/browserpackages.jpg" alt="" width="550" height="225" /></a></p>
В первую очередь конечно же нужно установить все популярные версии Internet Explorer (IE6, IE7, IE8). Для этого существует множество различных решений, я расскажу о четырех из них.
<h3>Internet Explorer Collection</h3>
Лично я рекомендую использовать – <a href="http://utilu.com/IECollection/">Internet Explorer Collection</a>. Не пугайтесь, это очень надежный инструмент (несмотря на внешний вид их сайта). Internet Explorer Collection содержит множество версий IE, совершенно независимых друг от друга, так что их можно использовать одновременно.

Я рекомендую эту сборку главным образом потому, что их браузеры весьма стабильны. Кроме того, Internet Explorer Collection содержит Internet Explorer Developer Toolbar.
<h3>BrowserSeal.BrowserPack</h3>
Если вам требуются более старые версии других браузеров, я рекомендую установить <a href="http://www.browserseal.com/?option=com_content&amp;view=article&amp;id=35">BrowserSeal.BrowserPack</a>. Он использует, упомянутый выше Internet Explorer Collection, и кроме того, позволяет установить браузеры типа Safari3 и Opera 9.

Браузеры, входящие в состав BrowserSeal.BrowserPack стабильны и не имеют никаких выявленных проблем.
<h3>IETester</h3>
<a href="http://www.my-debugbar.com/wiki/IETester/HomePage">IETester</a> имеет некоторые преимущества в сравнении с другими сборками, например такие как открытие разных версий IE в табах.

IETester разрабатывается командой DebugBar, которая так же предоставляет замечательные инструменты отладки DebugBar и Companion.js (оба рассмотрены в сегодняшней статье).

К сожалению, IETester (версии 0.4.2) остается весьма ненадежным приложением, к тому же во время отладки находятся некоторые несоответствия. Будем надеяться, что рано или поздно эти проблемы будут исправлены, и мы сможем взять IETester на вооружение.
<h3>Microsoft Expression Web SuperPreview</h3>
<a href="http://www.microsoft.com/downloads/details.aspx?FamilyID=8e6ac106-525d-45d0-84db-dccff3fae677&amp;displaylang=en">Microsoft Expression Web SuperPreview</a> – это полноценное приложение и часть продукта <a href="http://www.microsoft.com/expression/products/Web_Overview.aspx">Microsoft Expression Web 3</a>. Главное его назначение – это возможность сравнить одну и ту же страницу одновременно в IE6, IE7 и IE8.

На мой взгляд, это приложение не предназначено для отладки и тестирования.
<h3>Основные инструменты отладки</h3>
<a href="http://dreamhelg.ru/wp-content/uploads/2010/03/generaldebugging.jpg"><img class="aligncenter size-full wp-image-1948" title="generaldebugging" src="http://dreamhelg.ru/wp-content/uploads/2010/03/generaldebugging.jpg" alt="" width="550" height="225" /></a>

Скорее всего, для отладки в Firefox, вы используете Firebug. И возможно, вы также слышали о Firebug Lite и даже использовали его. Далее, вы узнаете какие еще способы можно использовать для отладки кода под Internet Explorer.
<h3>Firebug Lite</h3>
Конечно же, вы уже знакомы с Firebug Lite. Если нет, читайте далее. <a href="http://getfirebug.com/firebuglite">Firebug Lite</a> – это javascript-файл, который можно подключить к странице, чтобы получить возможность использовать некоторые функции Firebug, в других браузерах.

Скажу сразу, я не являюсь большим фанатом Firebug Lite. Во-первых потому, что большинство возможностей консоли недоступны в других браузерах. Во-вторых, он не всегда хорошо работает. Мне не раз приходилось сталкиваться с рядом проблем в IE, поэтому не стоит концентрироваться только на этом инструменте.
<h3>IE Developer Toolbar</h3>
Возможно, вы знакомы с инструментами разработчика под IE8. <a href="http://www.microsoft.com/downloads/details.aspx?familyid=e59c3964-672d-4511-bb3e-2d5e1db91038&amp;displaylang=en">IE Developer Toolbar</a> – практически тот же самый инструмент для IE6 и IE7. И кроме того, он поставляется вместе со сборкой IE Collection, по умолчанию.

IE Developer Toolbar прост в использовании и предоставляет широкий набор средств для отладки. По функциональности, его можно сравнить с Web Developer – дополнением для Firefox.
<h3>DebugBar</h3>
Все, чего вам не хватило в Developer Toolbar, вы найдете в <a href="http://www.debugbar.com/">DebugBar</a>. В большинстве случаев, когда вам требуется найти что-либо за пределами документа, вам поможет DebugBar. Он очень быстрый и надежный.

Если бы требовалось описать DebugBar в двух словах, то достаточно сказать “он работает!”.
<h3>CompanionJS</h3>
<a href="http://www.my-debugbar.com/wiki/CompanionJS/HomePage">Companion.js</a> интегрируется с IE, и вполне может быть назван простейшей версией Firebug. В отличие от Firebug Lite, Companion.js, имеет более удобную консоль и отчеты об ошибках.

К сожалению, в Companion.js есть два серьезных недостатка: 1) он пока не поддерживает методы типа console.dir(); и 2) иногда вываливается в ошибку, при совместном использовании с другими инструментами разработчика для IE.
<h3>Инструменты тестирования производительности</h3>
<a href="http://dreamhelg.ru/wp-content/uploads/2010/03/performancetesting.jpg"><img class="aligncenter size-full wp-image-1949" title="performancetesting" src="http://dreamhelg.ru/wp-content/uploads/2010/03/performancetesting.jpg" alt="" width="550" height="225" /></a>

Клиентское тестирование производительности и оптимизация – это практика, которая долгое время “не существовала” в веб-разработке. Я имею в виду, что ей долгое время не уделяли должного внимания.

Как вам наверное известно, Internet Explorer (особенно IE6), не настолько хорош, особенно в сравнении с другими браузерами. Но, когда вы начнете тестировать производительность в IE6, вы удивитесь, насколько незначительные вещи могут влиять на скорость работы сайта.

Далее рассмотрены некоторые инструменты тестирования производительности, которые можно использовать в любом браузере, не столько в Internet Exploer.
<h3>dynaTrace AJAX</h3>
Если вы используете Speed Tracer в Google Chrome, тогда вы полюбите <a href="http://ajax.dynatrace.com/pages/">dyna Trace AJAX</a>. Название говорит само за себя – он используется для диагностики и отслеживания AJAX, а также проблем с производительностью клиентских скриптов. Кроме того, в дополнение, он предоставляет инструменты для отслеживания проблем рендера (отрисовки) и сетевой загрузки.

dynaTrace AJAX не самый простой в использовании инструмент. Однако в их <a href="http://blog.dynatrace.com/">одноименном</a> блоге, вы найдете множество полезной информации, об применении этого мощного приложения. Установите dynaTrace AJAX, и разрешите все проблемы производительности, замедляющие работу сайта в Internet Explorer.
<h3>MySpace’s Perfomance Tracker</h3>
<a href="http://msfast.myspace.com/">MySpace’s Perfomance Tracker</a> или “<a href="http://code.google.com/p/msfast/">msfast</a>” – это плагин для браузера, который помогает разработчикам улучшить производительность кода, путем сбора и измерения возможных “узких мест”, на веб-странице.

У меня возникли небольшие проблемы, при установке бета-версии. Но после того, как была установлена альфа-версия и произведено обновление до бета-версии, все заработало.
<h3>JSLitmus</h3>
<a href="http://www.broofa.com/Tools/JSLitmus/">JSLitmus</a> – это простой инструмент для создания специализированных JavaScript-тестов. Я особенно рекомендую использовать JSLitmus для тестирования производительности всего вашего JavaScript-кода.

JSLitmus предоставляет дополнительные преимущества в Internet Explorer. Как известно, в IE, существуют  проблемы с JavaScript, способные нанести серьезный удар по производительности. Но если вы заранее создадите несколько простых тестов, то времени на поиск и решение этих проблем уйдет гораздо меньше.
<h3>Fiddler2</h3>
<a href="http://www.fiddler2.com/fiddler2/">Fiddler</a> – это отладочный прокси-сервер, ведущий логи всего HTTP(S) трафика. Fiddler позволяет вам проверить весь HTTP(S) трафик, установить точки прерывания и “играть” с исходящими и входящими данными. Fiddler включает мощную скриптовую подсистему, и может быть расширен с помощью любого .NET языка.

Если честно, я практически не использую Fiddler. В основном потому, что проблемы производительности связанные с трафиком сайта, всегда решаются с помощью другого инструмента (в другом браузере). Но Fiddler на самом деле дает отличное понимание того, что действительно происходит между браузером и сервером, и кроме того предоставляет большое количество настроек.
<h3>Другие ресурсы</h3>
Во время написания статьи, мне попался инструмент под названием <a href="http://www.ieinspector.com/">IEInspector</a>. Инструмент платный, но есть бесплатная демо-версия. У меня не было времени рассмотреть его подробнее, возможно вы захотите попробовать его.

Кроме того, на сайте Microsoft Windows, есть <a href="http://www.microsoft.com/windows/internet-explorer/readiness/testing-tools.aspx">список</a>, в котором перечислены полезные инструменты для тестирования и разработки приложений под Internet Explorer 8.

Существует еще множество других интересных приложений и сервисов, которые не рассмотрены в этой статье. Если вы знаете хорошие инструменты тестирования и отладки кода под Internet Explorer, оставляйте ссылки в комментариях.

Перевод статьи "<a href="http://samuli.hakoniemi.net/debugging-and-testing-in-internet-explorer-made-easy/">Debugging and Testing in Internet Explorer Made Easy</a>", автор <strong>Samuli Hakoniemi</strong>]]></description>
		<wfw:commentRss>http://dreamhelg.ru/2010/03/debugging-and-testing-tools-in-ie/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>Создаем счетчик загрузок файла с помощью PHP и MySQL</title>
		<link>http://dreamhelg.ru/2010/03/create-download-counter-with-php-and-mysql/</link>
		<comments>http://dreamhelg.ru/2010/03/create-download-counter-with-php-and-mysql/#comments</comments>
		<pubDate>Thu, 18 Mar 2010 13:38:43 +0000</pubDate>
		<dc:creator>dreamhelg</dc:creator>
				<category><![CDATA[общая]]></category>
		<category><![CDATA[переводы]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[php]]></category>

		<guid isPermaLink="false">http://dreamhelg.ru/?p=1921</guid>
		<description><![CDATA[<p><img width="200" height="200" src="http://dreamhelg.ru/wp-content/uploads/2010/03/home.png" class="attachment-200x200 wp-post-image" alt="home" title="home" /></p>В сегодняшней статье, мы создадим простую, но надежную систему учета загрузок файлов. Каждый файл будет иметь соответствующую строку в базе данных, где будет хранится общее число загрузок этого файла. PHP будет обновлять базу данных MySQL, и перенаправлять пользователей на соответствующие файлы.<span id="more-1921"></span>

Чтобы отслеживать количество загрузок, вам понадобится только загрузить файлы в нужную папку, и использовать определенный URL для доступа к ним.

<h3>Шаг 1 – XHTML</h3>
Для начала нам понадобится XHTML-разметка. Она очень простая – это общий блок <strong>file-manager</strong>, содержащий маркированный список, в котором ссылка на каждый файл будет находится внутри элемента <strong>li</strong>.

Файлы, по которым будет учитываться количество скачиваний, нужно загрузить в папку <strong>files</strong>, расположенную в корневой директории скрипта (вы можете посмотреть как организована структура файлов, в архиве с приведенным примером). PHP будет проходить циклом по всем файлам в папке, и добавлять каждый файл в виде отдельного элемента li, в маркированный список.

<strong>demo.php</strong>

[html]
&lt;div id=&quot;file-manager&quot;&gt;

	&lt;ul class=&quot;manager&quot;&gt;

		&lt;!-- The LI items are generated by php --&gt;
		&lt;li&gt;&lt;a href=&quot;download.php?file=photoShoot-1.0.zip&quot;&gt;photoShoot-1.0.zip
			&lt;span class=&quot;download-count&quot; title=&quot;Times Downloaded&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;download-label&quot;&gt;download&lt;/span&gt;&lt;/a&gt;
		&lt;/li&gt;
	&lt;/ul&gt;

&lt;/div&gt;
[/html]

Обратите внимание, что атрибут <strong>href</strong> у ссылки передает имя загружаемого файла в качестве параметра для файла <strong>download.php</strong>. Именно здесь будет происходить подсчет загрузок, как вы увидите в дальнейшем.

Вам не обязательно пользоваться именно этим интерфейсом для организации подсчета загрузок. Вы можете просто разместить ссылки на <strong>download.php</strong> на страницах блога или сайта, и все загрузки будут подсчитаны правильно.

<a href="http://dreamhelg.ru/wp-content/uploads/2010/03/i11.png"><img class="aligncenter size-full wp-image-1922" title="i11" src="http://dreamhelg.ru/wp-content/uploads/2010/03/i11.png" alt="" width="620" height="460" /></a>

<h3>Шаг 2 – CSS</h3>
После того как наша XHTML-разметка готова, мы можем сконцентрироваться на внешнем виде нашего скрипта. CSS-стили, представленные ниже, назначают внешний вид блоку file-manager, через его ID, поскольку он у нас один на странице. Остальные элементы стилизуются через имена классов.

<strong>style.css</strong>

[css]
#file-manager{
	background-color:#EEE;
	border:1px solid #DDD;
	margin:50px auto;
	padding:10px;
	width:400px;
}

ul.manager li{
	background:url(&quot;img/bg_gradient.gif&quot;) repeat-x center bottom #F5F5F5;
	border:1px solid #DDD;
	border-top-color:#FFF;

	list-style:none;
	position:relative;
}

ul.manager li a{
	display:block;
	padding:8px;
}

ul.manager li a:hover .download-label{
	/* When a list is hovered over, show the download green text inside it: */
	display:block;
}

span.download-label{
	background-color:#64B126;
	border:1px solid #4E9416;
	color:white;
	display:none;
	font-size:10px;
	padding:2px 4px;
	position:absolute;
	right:8px;
	text-decoration:none;
	text-shadow:0 0 1px #315D0D;
	top:6px;

	/* CSS3 Rounded Corners */

	-moz-border-radius:3px;
	-webkit-border-radius:3px;
	border-radius:3px;
}

span.download-count{
	color:#999;
	font-size:10px;
	padding:3px 5px;
	position:absolute;
	text-decoration:none;
}
[/css]

Обратите внимание, что здесь подпись “download” скрыта по умолчанию, с помощью свойства <strong>display: none</strong>. Она отображается через <strong>display:block</strong>, только при наведении мыши на ссылку, без использования JavaScript. Немного CSS3 используется для закругления уголков у подписи.

<a href="http://dreamhelg.ru/wp-content/uploads/2010/03/i21.png"><img class="aligncenter size-full wp-image-1923" title="i21" src="http://dreamhelg.ru/wp-content/uploads/2010/03/i21.png" alt="" width="620" height="260" /></a>

<h3>Шаг 3 – PHP</h3>
Как мы уже говорили выше, PHP проходит циклом по всей папке <strong>files</strong>, и выводит каждый файл в виде элемента li маркированного списка. Давайте рассмотрим подробнее, как это происходит.

<strong>demo.php  - Верхняя часть</strong>

[php]
// Error reporting:
error_reporting(E_ALL^E_NOTICE);

// Including the DB connection file:
require 'connect.php';

$extension='';
$files_array = array();

/* Opening the thumbnail directory and looping through all the thumbs: */

$dir_handle = @opendir($directory) or die(&quot;There is an error with your file directory!&quot;);

while ($file = readdir($dir_handle))
{
	/* Skipping the system files: */
	if($file{0}=='.') continue;

	/* end() returns the last element of the array generated by the explode() function: */
	$extension = strtolower(end(explode('.',$file)));

	/* Skipping the php files: */
	if($extension == 'php') continue;

	$files_array[]=$file;
}

/* Sorting the files alphabetically */
sort($files_array,SORT_STRING);

$file_downloads=array();

$result = mysql_query(&quot;SELECT * FROM download_manager&quot;);

if(mysql_num_rows($result))
while($row=mysql_fetch_assoc($result))
{
	/* 	The key of the $file_downloads array will be the name of the file,
		and will contain the number of downloads: */

	$file_downloads[$row['filename']]=$row['downloads'];
}
[/php]

Обратите внимание, как мы выбираем все записи из таблицы download_manager с помощью <strong>mysql_query()</strong> и затем добавляем их в массив <strong>$file_downloads</strong>, с ключом массива filename, и значением downloads. Таким образом, далее в коде, мы сможем записать <strong>$file_downloads[‘archive.zip’]</strong>, и вывести количество загрузок этого файла.

Ниже представлен код, который используется для генерации элементов li маркированного списка.

<strong>demo.php – Центральная часть</strong>

[php]
foreach($files_array as $key=&gt;$val)
{
	echo '&lt;li&gt;&lt;a href=&quot;download.php?file='.urlencode($val).'&quot;&gt;'.$val.'
		&lt;span class=&quot;download-count&quot; title=&quot;Times Downloaded&quot;&gt;'.(int)$file_downloads[$val].'&lt;/span&gt; &lt;span class=&quot;download-label&quot;&gt;download&lt;/span&gt;&lt;/a&gt;
	&lt;/li&gt;';
}
[/php]

Все очень просто – проходим циклом <strong>foreach</strong> по массиву <strong>$files_array</strong>, и выводим на страницу нужные данные в соответствующей разметке.

Теперь давайте более подробно рассмотрим как происходит учет загрузок.

<strong>download.php</strong>

[php]
// Error reporting:
error_reporting(E_ALL^E_NOTICE);

// Including the connection file:
require('connect.php');

if(!$_GET['file']) error('Missing parameter!');
if($_GET['file']{0}=='.') error('Wrong file!');

if(file_exists($directory.'/'.$_GET['file']))
{
	/* If the visitor is not a search engine, count the downoad: */
	if(!is_bot())
	mysql_query(&quot;	INSERT INTO download_manager SET filename='&quot;.mysql_real_escape_string($_GET['file']).&quot;'
					ON DUPLICATE KEY UPDATE downloads=downloads+1&quot;);

	header(&quot;Location: &quot;.$directory.&quot;/&quot;.$_GET['file']);
	exit;
}
else error(&quot;This file does not exist!&quot;);

/* Helper functions: */

function error($str)
{
	die($str);
}

function is_bot()
{
	/* This function will check whether the visitor is a search engine robot */

	$botlist = array(&quot;Teoma&quot;, &quot;alexa&quot;, &quot;froogle&quot;, &quot;Gigabot&quot;, &quot;inktomi&quot;,
	&quot;looksmart&quot;, &quot;URL_Spider_SQL&quot;, &quot;Firefly&quot;, &quot;NationalDirectory&quot;,
	&quot;Ask Jeeves&quot;, &quot;TECNOSEEK&quot;, &quot;InfoSeek&quot;, &quot;WebFindBot&quot;, &quot;girafabot&quot;,
	&quot;crawler&quot;, &quot;www.galaxy.com&quot;, &quot;Googlebot&quot;, &quot;Scooter&quot;, &quot;Slurp&quot;,
	&quot;msnbot&quot;, &quot;appie&quot;, &quot;FAST&quot;, &quot;WebBug&quot;, &quot;Spade&quot;, &quot;ZyBorg&quot;, &quot;rabaz&quot;,
	&quot;Baiduspider&quot;, &quot;Feedfetcher-Google&quot;, &quot;TechnoratiSnoop&quot;, &quot;Rankivabot&quot;,
	&quot;Mediapartners-Google&quot;, &quot;Sogou web spider&quot;, &quot;WebAlta Crawler&quot;,&quot;TweetmemeBot&quot;,
	&quot;Butterfly&quot;,&quot;Twitturls&quot;,&quot;Me.dium&quot;,&quot;Twiceler&quot;);

	foreach($botlist as $bot)
	{
		if(strpos($_SERVER['HTTP_USER_AGENT'],$bot)!==false)
		return true;	// Is a bot
	}

	return false;	// Not a bot
}
[/php]

Здесь обязательно нужно проверить, не является ли посетитель роботом поисковой системы, сканирующим ваши ссылки. Роботы – это хорошие посетители, поскольку они помогают включить ваш сайт в поисковые сервисы, однако в нашем случае, они могут исказить статистику загрузок. Вот почему база данных обновляется только после того, как посетитель пройдет проверку <strong>is_bot().</strong>

<h3>Шаг 4 – MySQL</h3>
Как мы упоминали в предыдущем шаге, количество загрузок записывается в виде строки, в таблицу download_manager, базы данных MySQL. Сначала, позвольте объяснить как работает эта часть запроса:

<strong>download.php</strong>

[sql]
INSERT INTO download_manager SET filename='filename.doc'
ON DUPLICATE KEY UPDATE downloads=downloads+1
[/sql]

Первая часть запроса говорит MySQL вставить новую строчку в таблицу <strong>download_manager</strong>, и установить значение поля <strong>filename</strong> равным имени запрашиваемого для загрузки файла. Кроме этого, поле <strong>filename</strong> определено как уникальный индекс таблицы. Это значит, что строка с конкретным именем файла, может быть вставлена только один раз, иначе произойдет ошибка дублирования ключевых полей.

Именно в этом случае, вступает в силу вторая часть запроса - <strong>ON DUPLICATE KEY UPDATE</strong>, которая увеличивает значение поля <strong>downloads</strong> на единицу, если этот файл уже записан в базе данных.

Таким образом, новые файлы будут автоматически вставляться в базу данных в первый раз, после того как загружены.

<a href="http://dreamhelg.ru/wp-content/uploads/2010/03/i31.png"><img class="aligncenter size-full wp-image-1924" title="i31" src="http://dreamhelg.ru/wp-content/uploads/2010/03/i31.png" alt="" width="620" height="260" /></a>

<h3>Шаг 5 – jQuery</h3>
Для того, чтобы сделать наш счетчик загрузок более наглядным, было бы неплохо добавить возможность обновлять счетчик, находящийся рядом с именем файла, сразу после того, как пользователь начнет загрузку. Пока что, для того чтобы увидеть новые значения счетчиков, пользователю нужно перезагрузить страницу.

Это можно исправить небольшим фрагментом кода:

<strong>script.js</strong>

[javascript]
$(document).ready(function(){
	/* This code is executed after the DOM has been completely loaded */

	$('ul.manager a').click(function(){

		var countSpan = $('.download-count',this);
		countSpan.text( parseInt(countSpan.text())+1);
	});
});
[/javascript]

Мы просто назначили обработчик события на клик по ссылке. Каждый раз, после того, как пользователь кликнет по ссылке, мы увеличиваем текущее значение загрузок на единицу.

<h3>Шаг 6 – htaccess</h3>
Нам осталось сделать еще одну вещь, прежде чем можно будет назвать работу законченной. Возможно, вы уже заметили, что некоторые типы файлов, браузер по умолчанию пытается сразу же открывать. Вместо этого, нам нужно запускать загрузку файла. Это довольно легко сделать, добавив несколько строчек внутри файла <strong>.htaccess</strong>, расположенного в папке <strong>files</strong>:

[php]
&lt;Files *.*&gt;
ForceType application/octet-stream
&lt;/Files&gt;
[/php]

Вот и все, наш счетчик загрузок готов.
<h3>Заключение</h3>
Чтобы запустить этот пример на своем собственном сервере, вам понадобится создать таблицу download_manager в базе данных MySQL, к которой у вас разумеется есть доступ. В архиве с примером, есть файл <strong>table.sql</strong>, который содержит необходимый SQL-код, который создаст нужную таблицу.

После этого, просто укажите свои данные подключения к базе, в файле <strong>configuration.php</strong>.

<a href="http://demo.tutorialzine.com/2010/02/php-mysql-download-counter/demo.php">Смотреть демо.</a>

<a href="http://dreamhelg.ru/wp-content/uploads/2010/03/counter.zip">Архив с приведенным примером</a>.


Перевод статьи “<a href="http://tutorialzine.com/2010/02/php-mysql-download-counter/">PHP &amp; MySQL File Download Counter</a>”, автор <strong>Martin Angelov</strong>]]></description>
		<wfw:commentRss>http://dreamhelg.ru/2010/03/create-download-counter-with-php-and-mysql/feed/</wfw:commentRss>
		<slash:comments>14</slash:comments>
		</item>
		<item>
		<title>15 регулярных выражений PHP в помощь веб-разработчику</title>
		<link>http://dreamhelg.ru/2010/02/15-regular-expression-for-web-developers/</link>
		<comments>http://dreamhelg.ru/2010/02/15-regular-expression-for-web-developers/#comments</comments>
		<pubDate>Fri, 12 Feb 2010 11:49:52 +0000</pubDate>
		<dc:creator>dreamhelg</dc:creator>
				<category><![CDATA[общая]]></category>
		<category><![CDATA[переводы]]></category>
		<category><![CDATA[php]]></category>

		<guid isPermaLink="false">http://dreamhelg.ru/?p=1881</guid>
		<description><![CDATA[<p><img width="200" height="200" src="http://dreamhelg.ru/wp-content/uploads/2010/02/home.png" class="attachment-200x200 wp-post-image" alt="home" title="home" /></p>Регулярные выражения – это очень полезный инструмент для разработчиков. С их помощью можно находить, определять или заменять текст, слова или любые другие символы. В сегодняшней статье собраны 15 наиболее полезных регулярных выражений, которые пригодятся любому веб-разработчику.<span id="more-1881"></span>
<h3>Введение в регулярные выражения</h3>
Многим начинающим разработчикам кажется, что регулярные выражения очень сложны для понимания и использования. На самом деле, все не так уж сложно, как может показаться. Прежде чем мы непосредственно перейдем к регулярным выражениям, с их полезным и универсальным кодом, давайте взглянем на основы:

<strong>Синтаксис регулярных выражений</strong>
<table border="1" cellspacing="0" cellpadding="2" width="550">
<tbody>
<tr>
<td width="249" valign="top"><strong>Регулярное выражение</strong></td>
<td width="347" valign="top"><strong>Означает</strong></td>
</tr>
<tr>
<td width="249" valign="top">foo</td>
<td width="347" valign="top">Строка “foo”</td>
</tr>
<tr>
<td width="249" valign="top">^foo</td>
<td width="347" valign="top">Строка начинается с “foo”</td>
</tr>
<tr>
<td width="249" valign="top">foo$</td>
<td width="347" valign="top">Строка заканчивается на “foo”</td>
</tr>
<tr>
<td width="249" valign="top">^foo$</td>
<td width="347" valign="top">"foo" встречается в строке только один раз</td>
</tr>
<tr>
<td width="249" valign="top">[abc]</td>
<td width="347" valign="top">a, b, или c</td>
</tr>
<tr>
<td width="249" valign="top">[a-z]</td>
<td width="347" valign="top">любой символ в нижнем регистре</td>
</tr>
<tr>
<td width="249" valign="top">[^A-Z]</td>
<td width="347" valign="top">любой символ, не находящийся в верхнем регистре</td>
</tr>
<tr>
<td width="249" valign="top">(gif|jpg)</td>
<td width="347" valign="top">Означает как "gif” так и “jpeg”</td>
</tr>
<tr>
<td width="249" valign="top">[a-z]+</td>
<td width="347" valign="top">Один или более символов нижнего регистра</td>
</tr>
<tr>
<td width="249" valign="top">[0-9.-]</td>
<td width="347" valign="top">Любая цифра, точка или знак минус</td>
</tr>
<tr>
<td width="249" valign="top">^[a-zA-Z0-9_]{1,}$</td>
<td width="347" valign="top">Любое слово, хотя бы одна буква, число или _</td>
</tr>
<tr>
<td width="249" valign="top">([wx])([yz])</td>
<td width="347" valign="top">wy, wz, xy, или xz</td>
</tr>
<tr>
<td width="249" valign="top">(^A-Za-z0-9)</td>
<td width="347" valign="top">Любой символ (не число и не буква)</td>
</tr>
<tr>
<td width="249" valign="top">([A-Z]{3}|[0-9]{4})</td>
<td width="347" valign="top">Означает три буквы или 4 цифры</td>
</tr>
</tbody>
</table>
<br/><strong>PHP-функции для регулярных выражений</strong>

<table border="1" cellspacing="0" cellpadding="2" width="550">
<tbody>
<tr>
<td width="130" valign="top"><strong>Функция</strong></td>
<td width="468" valign="top"><strong>Описание</strong></td>
</tr>
<tr>
<td width="130" valign="top">preg_match()</td>
<td width="468" valign="top">Функция preg_match() ищет строку по заданному шаблону, возвращает true, если строка находится и false, в остальных случаях</td>
</tr>
<tr>
<td width="130" valign="top">preg_match_all()</td>
<td width="468" valign="top">Функция preg_match_all() находит все вхождения строки, заданной по шаблону</td>
</tr>
<tr>
<td width="130" valign="top">preg_replace()</td>
<td width="468" valign="top">Функция preg_replace(), действует по тому же принципу, что и ereg_replace(), за исключением того, что регулярные выражения можно использовать как для задания шаблона поиска, так и для строки, на которую следует заменить, найденное значение.</td>
</tr>
<tr>
<td width="130" valign="top">preg_split()</td>
<td width="468" valign="top">Функция preg_split(), действует так же как split(), за исключением того, что регулярное выражение можно использовать в качестве параметра для шаблона поиска.</td>
</tr>
<tr>
<td width="130" valign="top">preg_grep()</td>
<td width="468" valign="top">Функция preg_grep() ищет все элементы входного массива, возвращая все элементы, соответствующие шаблону регулярного выражения.</td>
</tr>
<tr>
<td width="130" valign="top">preg_quote()</td>
<td width="468" valign="top">Экранирует символы регулярного выражения</td>
</tr>
</tbody>
</table>
<h3>Проверка доменного имени</h3>
Проверяем, является ли строка правильным доменным именем

[php]
$url = &quot;http://komunitasweb.com/&quot;;
if (preg_match('/^(http|https|ftp)://([A-Z0-9][A-Z0-9_-]*(?:.[A-Z0-9][A-Z0-9_-]*)+):?(d+)?/?/i', $url)) {
    echo &quot;Your url is ok.&quot;;
} else {
    echo &quot;Wrong url.&quot;;
}
[/php]
<h3>Подсветка слова в тексте</h3>
Это очень полезное регулярное выражение, с его помощью вы можете найти нужное слово и подсветить его. Особенно полезно для отображения результатов поиска.

[php]
$text = &quot;Sample sentence from KomunitasWeb, regex has become popular in web programming. Now we learn regex. According to wikipedia, Regular expressions (abbreviated as regex or regexp, with plural forms regexes, regexps, or regexen) are written in a formal language that can be interpreted by a regular expression processor&quot;;
$text = preg_replace(&quot;/b(regex)b/i&quot;, '&lt;span style=&quot;background:#5fc9f6&quot;&gt;1&lt;/span&gt;', $text);
echo $text;
[/php]
<h3>Подсветка результатов поиска в WordPress блоге</h3>
Как уже говорилось в предыдущем примере, этот пример кода, удобно использовать в выдаче поисковых результатов и есть отличный способ внедрить эту функцию в wordpress-блог.

Откройте ваш файл search.php, и найдите функцию the_title(). Замените ее следующим кодом:

[php]
echo $title;
[/php]

Теперь, выше этой строки, добавьте этот код:

[php]
&lt;?php
	$title 	= get_the_title();
	$keys= explode(&quot; &quot;,$s);
	$title 	= preg_replace('/('.implode('|', $keys) .')/iu',
		'&lt;strong class=&quot;search-excerpt&quot;&gt;&#92;&#48;&lt;/strong&gt;',
		$title);
?&gt;
[/php]

Сохраните файл search.php, и откройте style.css. Добавьте следующую строку:

[css]
strong.search-excerpt { background: yellow; }
[/css]
<h3>Получение всех картинок из HTML-документа</h3>
Если вам когда-нибудь требовалось получить все картинки с веб-страницы, этот код должен быть Вы легко сможете создать загрузчик изображений с помощью возможностей <a href="http://www.catswhocode.com/blog/10-awesome-things-to-do-with-curl">cURL</a>

[php]
$images = array();
preg_match_all('/(img|src)=(&quot;|')[^&quot;'&gt;]+/i', $data, $media);
unset($data);
$data=preg_replace('/(img|src)(&quot;|'|=&quot;|=')(.*)/i',&quot;$3&quot;,$media[0]);
foreach($data as $url)
{
	$info = pathinfo($url);
	if (isset($info['extension']))
	{
		if (($info['extension'] == 'jpg') ||
		($info['extension'] == 'jpeg') ||
		($info['extension'] == 'gif') ||
		($info['extension'] == 'png'))
		array_push($images, $url);
	}
}
[/php]
<h3>Удаление повторяющихся слов (не чувствителен к регистру)</h3>
Во время печатания, часто повторяются слова? Поможет это регулярное выражение.

[php]
$text = preg_replace(&quot;/s(w+s)1/i&quot;, &quot;$1&quot;, $text);
[/php]
<h3>Удаление повторяющейся пунктуации</h3>
То же самое, только для пунктуации. Попрощайтесь с двойными запятыми.

[php]
$text = preg_replace(&quot;/.+/i&quot;, &quot;.&quot;, $text);
[/php]
<h3>Поиск XML/HTML тэгов</h3>
Эта простая функция, принимает два аргумента. Первый – это тэг, который вам нужно найти, и второй – это переменная, содержащая XML или HTML. Повторюсь, эту функцию очень удобно использовать вместе с cURL.

[php]
function get_tag( $tag, $xml ) {
  $tag = preg_quote($tag);
  preg_match_all('{&lt;'.$tag.'[^&gt;]*&gt;(.*?)&lt;/'.$tag.'&gt;.'}',
                   $xml,
                   $matches,
                   PREG_PATTERN_ORDER);

  return $matches[1];
}
[/php]
<h3>Поиск XHTML/XML тэгов с определенным значением атрибута</h3>
Эта функция очень похожа на предыдущую, за исключением того, что вы можете задать тегу нужный атрибут. Например, вы легко сможете найти &lt;div id=”header”&gt;.

[php]
function get_tag( $attr, $value, $xml, $tag=null ) {
  if( is_null($tag) )
    $tag = '\w+';
  else
    $tag = preg_quote($tag);

  $attr = preg_quote($attr);
  $value = preg_quote($value);

  $tag_regex = &quot;/&lt;(&quot;.$tag.&quot;)[^&gt;]*$attr\s*=\s*&quot;.
                &quot;(['\&quot;])$value\\2[^&gt;]*&gt;(.*?)&lt;\/\\1&gt;/&quot;

  preg_match_all($tag_regex,
                 $xml,
                 $matches,
                 PREG_PATTERN_ORDER);

  return $matches[3];
}
[/php]
<h3>Поиск шестнадцатеричных значений цветов</h3>
Еще один полезный инструмент для веб-разработчика! Он позволяет вам находить/проверять шестнадцатеричные значение цвета.

[php]
$string = &quot;#555555&quot;;
if (preg_match('/^#(?:(?:[a-fd]{3}){1,2})$/i', $string)) {
echo &quot;example 6 successful.&quot;;
}
[/php]
<h3>Поиск заголовка статьи</h3>
Этот фрагмент кода найдет и выведет на экран текст, находящийся внутри тэгов &lt;title&gt;&lt;/title&gt;, на html-странице.

[php]
$fp = fopen(&quot;http://www.catswhocode.com/blog&quot;,&quot;r&quot;);
while (!feof($fp) ){
    $page .= fgets($fp, 4096);
}

$titre = eregi(&quot;&lt;title&gt;(.*)&lt;/title&gt;&quot;,$page,$regs);
echo $regs[1];
fclose($fp);
[/php]
<h3>Парсинг логов Apache</h3>
Большинство сайтов запущено на всем известном веб-сервере Apache. Если ваш сайт находится в их числе, почему бы не использовать PHP и регулярные выражения для разбора логов апача?

[php]
//Logs: Apache web server
//Successful hits to HTML files only.  Useful for counting the number of page views.
'^((?#client IP or domain name)S+)s+((?#basic authentication)S+s+S+)s+[((?#date and time)[^]]+)]s+&quot;(?:GET|POST|HEAD) ((?#file)/[^ ?&quot;]+?.html?)??((?#parameters)[^ ?&quot;]+)? HTTP/[0-9.]+&quot;s+(?#status code)200s+((?#bytes transferred)[-0-9]+)s+&quot;((?#referrer)[^&quot;]*)&quot;s+&quot;((?#user agent)[^&quot;]*)&quot;$'

//Logs: Apache web server
//404 errors only
'^((?#client IP or domain name)S+)s+((?#basic authentication)S+s+S+)s+[((?#date and time)[^]]+)]s+&quot;(?:GET|POST|HEAD) ((?#file)[^ ?&quot;]+)??((?#parameters)[^ ?&quot;]+)? HTTP/[0-9.]+&quot;s+(?#status code)404s+((?#bytes transferred)[-0-9]+)s+&quot;((?#referrer)[^&quot;]*)&quot;s+&quot;((?#user agent)[^&quot;]*)&quot;$'
[/php]
<h3>Замена двойных кавычек “умными” кавычками</h3>
Если вы любитель типографики, вам понравится это регулярное выражение, заменяющее обычные двойные кавычки, на “умные кавычки”. Похожее регулярное выражение используется в wordpress в контенте страницы.

[php]
preg_replace('B&quot;b([^&quot;x84x93x94rn]+)b&quot;B', '?1?', $text);
[/php]
<h3>Комплексная проверка пароля</h3>
Это регулярное выражение будет следить за тем, чтобы в текстовое поле было введено не менее шести символов, цифры, дефисы и подчеркивания.

Текстовое поле должно содержать как минимум один символ верхнего регистра, один нижнего регистра и одну цифру.

[php]
'A(?=[-_a-zA-Z0-9]*?[A-Z])(?=[-_a-zA-Z0-9]*?[a-z])(?=[-_a-zA-Z0-9]*?[0-9])[-_a-zA-Z0-9]{6,}z'
[/php]
<h3>WordPress: Использование регулярного выражения для получения картинок из записи</h3>
Поскольку многие из вас являются пользователями WordPress, вам возможно пригодится код, который позволяет получить все картинки, из текста статьи, и вывести их.

Для того, чтобы использовать этот код, просто вставьте его в любой файл вашей темы.

[php]
&lt;?php if (have_posts()) : ?&gt;
&lt;?php while (have_posts()) : the_post(); ?&gt;

&lt;?php
$szPostContent = $post-&gt;post_content;
$szSearchPattern = '~&lt;img [^&gt;]* /&gt;~';

// Run preg_match_all to grab all the images and save the results in $aPics
preg_match_all( $szSearchPattern, $szPostContent, $aPics );

// Check to see if we have at least 1 image
$iNumberOfPics = count($aPics[0]);

if ( $iNumberOfPics &gt; 0 ) {
     // Now here you would do whatever you need to do with the images
     // For this example the images are just displayed
     for ( $i=0; $i &lt; $iNumberOfPics ; $i++ ) {
          echo $aPics[0][$i];
     };
};

endwhile;
endif;
?&gt;
[/php]
<h3>Генерация автоматических смайлов</h3>
Другая функция, используемая в wordpress – позволяет автоматически заменять символы смайлов на картинку смайла.

[php]
$texte='A text with a smiley :-)';
echo str_replace(':-)','&lt;img src=&quot;smileys/souriant.png&quot;&gt;',$texte);
[/php]

Перевод статьи “<a href="http://www.catswhocode.com/blog/15-php-regular-expressions-for-web-developers">15 PHP regular expressions for web developers</a>”, автор <strong>Jean-Baptiste Jung</strong>]]></description>
		<wfw:commentRss>http://dreamhelg.ru/2010/02/15-regular-expression-for-web-developers/feed/</wfw:commentRss>
		<slash:comments>16</slash:comments>
		</item>
		<item>
		<title>Меркуриал. Разрешение конфликтов</title>
		<link>http://dreamhelg.ru/2009/12/mercurial-resolve-conflicts/</link>
		<comments>http://dreamhelg.ru/2009/12/mercurial-resolve-conflicts/#comments</comments>
		<pubDate>Thu, 17 Dec 2009 08:12:19 +0000</pubDate>
		<dc:creator>dreamhelg</dc:creator>
				<category><![CDATA[общая]]></category>
		<category><![CDATA[mercurial]]></category>
		<category><![CDATA[tortoiseHG]]></category>
		<category><![CDATA[инструменты]]></category>
		<category><![CDATA[контроль версий]]></category>

		<guid isPermaLink="false">http://dreamhelg.ru/?p=1766</guid>
		<description><![CDATA[<p><img width="192" height="200" src="http://dreamhelg.ru/wp-content/uploads/2009/12/konflict_08.jpg" class="attachment-200x200 wp-post-image" alt="konflict_08" title="konflict_08" /></p>В <a href="http://dreamhelg.ru/2009/09/mercurial-merge-work/">предыдущей статье</a>, мы рассматривали совместную работу над одним проектом, изучив базовые приемы объединения двух различных репозиториев в один. В сегодняшней статье, мы рассмотрим более сложную ситуацию – разрешение конфликтующих изменений.<span id="more-1766"></span>Итак, как вы уже заметили ранее, большинство объединений выполняется очень просто, но из всякого правила бывают исключения. Иногда, вы можете столкнуться с тем, что каждая сторона изменений затрагивает одну и ту же часть, одного и того же файла. И если обе модификации не идентичны, то слияние приведет к образованию конфликта, в котором вам придется решить, каким образом «помирить» различные изменения, чтобы получить правильный результат.

<strong>Рисунок 3.4. Конфликтующие изменения документа</strong>

<img class="aligncenter size-full wp-image-1778" title="schema" src="http://dreamhelg.ru/wp-content/uploads/2009/12/schema.png" alt="schema" width="475" height="500" />

Рисунок 3.4.  иллюстрирует пример двух конфликтующих изменений одного и того же документа. Мы начнем с создания первоначальной версии файла, затем произведем в нем небольшие изменения, в то время как кто-нибудь другой, изменит ту же часть текста. Наша задача в разрешении конфликтующих изменений – решить, как именно должен выглядеть наш файл после объединения.

Меркуриал не имеет встроенной возможности разрешения конфликтов. Вместо этого, он использует внешнюю программу, имеющую графический интерфейс.
<h3>Рабочий пример</h3>
В разрешении конфликтующих изменений нет ничего сложного, и сейчас мы на примере разберем эту задачу.

Первое, что нам понадобится – это исходный репозиторий с файлом, который мы впоследствии будем изменять. Создаем папку <em>first</em>, внутри которой, создаем простой текстовый файл, с именем <em>letter.txt</em>, с одним единственным, знакомым многим, предожением:

<img class="aligncenter size-full wp-image-1768" title="letter" src="http://dreamhelg.ru/wp-content/uploads/2009/12/letter.jpg" alt="letter" width="467" height="187" />

Далее запускаем внутри папки командную строку, и поочередно выполняем следующие команды:

<code>$ hg init

$ hg add letter.txt

$ hg commit –m “исходная версия текстового файла”
</code>

Здесь, мы сначала создаем репозиторий, затем добавляем в него наш файл <em>letter.txt</em>, и сохраняем его начальную версию. То же самое можно сделать с помощью графического интерфейса, через контекстное меню, доступное по правому клику мыши.

Далее, клонируем репозиторий <em>first</em>, в репозиторий под названием <em>first-one</em>. Снова используем командную строку:

<code>$ cd ..

$hg clone first first-one</code>

Если вы все сделали правильно, у вас должна появится новая папка с именем <em>first-one</em>, заходим в нее и смело изменяем копию файла <em>letter.txt</em>:

<img class="aligncenter size-full wp-image-1770" title="letter-two" src="http://dreamhelg.ru/wp-content/uploads/2009/12/letter-two.jpg" alt="letter-two" width="486" height="188" />

Сохраняем изменения, и создаем новый коммит:

<code>$ cd first-one

$ hg commit –m “название булок изменено на норвежские”</code>

Отлично, наш первый репозиторий с изменениями готов. Теперь снова вернемся к изначальному репозиторию <em>first</em>, и клонируем его еще раз. В этот раз, имя клонированного репозитория будет <em>first-second</em>:

<code>$ cd ..

$ hg clone first first-second</code>

Заходим внутрь только что клонированного репозитория <em>first-second</em>, и снова изменяем копию файла <em>letter.txt</em>:

<img class="aligncenter size-full wp-image-1769" title="letter-three" src="http://dreamhelg.ru/wp-content/uploads/2009/12/letter-three.jpg" alt="letter-three" width="461" height="185" />

И снова повторяем действия второго этапа, записываем наши изменения:

<code>$ cd first-second

$ hg commit –m “название булок изменено на австрийские”</code>

Отлично, теперь у нас есть две копии одного репозитория, с разными изменениями одной и той же части предложения. Переходим к главной части нашего примера – к объединению. Для того, чтобы не было путаницы, создадим из репозитория <em>first-one</em> клон, и назовем его <em>first-merge</em>. Он как раз и будет содержать объединенные версии двух репозиториев.

<code>$ cd ..

$ hg clone first-one first-merge

$ cd first-merge

$ hg pull –u ../first-second</code>

В вышеприведенном коде, кроме того что мы клонировали новый репозиторий <em>first-merge</em>, мы еще затянули в него изменения из репозитория <em>first-second</em>, так что сейчас он содержит два набора взаимоисключающих изменений. Теперь самое интересное, нам нужно их объединить, так что смело запускаем команду:

<code>$ hg merge</code>

И перед вами должна предстать графическая утилита <strong>Kdiff3</strong>, предназначенная специально для разрешения конфликтов:

<img class="aligncenter size-full wp-image-1772" title="kDiff3" src="http://dreamhelg.ru/wp-content/uploads/2009/12/kDiff3.jpg" alt="kDiff3" width="615" height="438" />

Как раз, на представленном выше скриншоте, она сообщает нам, что у нас есть один конфликт, который не возможно разрешить автоматически. А нам и не нужно автоматически, поэтому жмем кнопку ОК, и внимательно смотрим на окошко:

<img class="aligncenter size-full wp-image-1773" title="kDiff3-2" src="http://dreamhelg.ru/wp-content/uploads/2009/12/kDiff3-2.jpg" alt="kDiff3-2" width="620" height="455" />

Здесь по порядку слева направо отображается:
<ul>
	<li><strong>A</strong> -  набор изменений после которого началась развилка</li>
	<li><strong>B</strong> -  набор изменений, содержащийся в репозитории <em>first-one</em></li>
	<li><strong>C</strong> - набор изменений, затянутый из репозитория first-<em>second</em>.</li>
</ul>
Итак, для того чтобы разрешить конфликтную ситуацию, нам нужно решить, какое же изменение стоит использовать в конечном итоге. Предположим, что свежие австрийские булки будут гораздо лучше на вкус, чем черствые норвежские, поэтому, мы решаем использовать набор изменений <strong>C</strong>, который был получен из репозитория <em>first-second</em>.

Для того чтобы использовать ревизию <strong>C</strong>, можно воспользоваться соответствующей кнопкой на панели инструментов, или пунктом меню «<em>Merge – Select Line(s) from C</em>»

<img class="aligncenter size-full wp-image-1774" title="kDiff3-merge" src="http://dreamhelg.ru/wp-content/uploads/2009/12/kDiff3-merge.jpg" alt="kDiff3-merge" width="620" height="455" />

После этого нажимаем кнопку сохранить, и все окошко можно закрыть. И последний этап – создание коммита полученного объединения, как обычно воспользуемся привычной командой:

<code>$ hg commit –m “объединение двух версий”</code>

Теперь если воспользоваться командой контекстного меню «<em>TortoiseHG – View Changelog</em>», мы сможем увидеть как были объединены наши конфликтующие ветки:

<img class="aligncenter size-full wp-image-1771" title="changelog" src="http://dreamhelg.ru/wp-content/uploads/2009/12/changelog.jpg" alt="changelog" width="672" height="307" />

В данном примере мы рассмотрели простейший конфликт, однако, в процессе совместной работы над проектом, таких конфликтов может быть огромное количество. С помощью утилиты kDiff3,  вы можете либо обрабатывать конфликты построчно, как мы только что сделали и для каждой строки назначать определенную ревизию, либо указать нужную ревизию для всех возникших конфликтов. В этом случае, указанная вами ревизия заменит своим содержанием все конфликтующие изменения, поэтому используйте ее аккуратно.

В статье использовались материалы книги "<a href="http://hgbook.red-bean.com/read/">Mercurial: The Definitive Guide</a>", автор <strong>Bryan O'Sullivan </strong>]]></description>
		<wfw:commentRss>http://dreamhelg.ru/2009/12/mercurial-resolve-conflicts/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Микроформаты: Что, Почему и Как</title>
		<link>http://dreamhelg.ru/2009/12/microformats-why-what-and-how/</link>
		<comments>http://dreamhelg.ru/2009/12/microformats-why-what-and-how/#comments</comments>
		<pubDate>Wed, 09 Dec 2009 13:34:03 +0000</pubDate>
		<dc:creator>dreamhelg</dc:creator>
				<category><![CDATA[общая]]></category>
		<category><![CDATA[переводы]]></category>
		<category><![CDATA[html]]></category>
		<category><![CDATA[microformats]]></category>

		<guid isPermaLink="false">http://dreamhelg.ru/?p=1745</guid>
		<description><![CDATA[<p><img width="200" height="200" src="http://dreamhelg.ru/wp-content/uploads/2009/12/200.jpg" class="attachment-200x200 wp-post-image" alt="200" title="200" /></p>В интернете существует большое количество всевозможных данных. Но я убежден, что большинство полезных данных –  например таких как контактная информация о людях или события, на которых необходимо присутствовать – должны храниться в HTML, там, где вы легко сможете получить к ним доступ. С этой задачей, нам помогут справиться Микроформаты.<span id="more-1745"></span>
<h3>Что это такое?</h3>
Итак, что же такое микроформаты? На домашней странице сайта <a href="http://microformats.org/">microformats.org</a> есть такое описание:

<blockquote>Разработанные в первую очередь для людей, а затем для машин, микроформаты – это набор простых, открытых форматов данных, построенные на основе существующих и широко распространенных стандартов.</blockquote>

Неплохое начало, но нам потребуется небольшое разъяснение.  Вы можете найти на сайте <a href="http://microformats.org/wiki/what-are-microformats">список определений</a>, но суть заключается в следующем: <strong>микроформаты – это набор стандартов для внедрения легко извлекаемых данных на ваши страницы, с использованием современных технологий</strong>.

Отличная новость в том, что если у вас, предположим, есть контент на сайте, мы можете прямо сейчас пометить его микроформатами. Другая хорошая новость в том, что после прочтения этой статьи, весь процесс займет у вас пару минут.

<h3>Для чего?</h3>

Зачем же нужны микроформаты? Ну, если вы убеждены в том, что HTML должен быть семантичным, то микроформаты отлично вам  подойдут. Или же, я могу привести другие аргументы: как мы уже заметили, идея микроформатов состоит в стандартизации того, как данные будут отмечены на странице, с тем, чтобы в дальнейшем, их легко можно было извлечь. На сегодняшний день существует не так уж и много инструментов, использующих возможности микроформатов, но я думаю ситуация изменится.

Использование микроформатов в своей работе, подготовит ваши сайты для будущего, когда микроформаты будут более широко распространены. Опять же, на сайте, вы можете найти <a href="http://microformats.org/wiki/what-can-you-do-with-microformats">список</a> того, что вы можете делать с микроформатами. Также для извлечения микроформатов, существует отличный аддон для Firefox, он называется <a href="https://addons.mozilla.org/en-US/firefox/addon/4106">Operator</a>.

<img class="aligncenter size-full wp-image-1748" title="operator" src="http://dreamhelg.ru/wp-content/uploads/2009/12/operator.jpg" alt="operator" width="600" height="332" />

Кроме этого, <a href="http://www.danwebb.net/">Дэн Веб</a> создал простую <a href="http://www.github.com/danwrong/sumo">JavaScript библиотеку под названием “Sumo”</a>, которая <a href="http://www.danwebb.net/2007/2/9/sumo-a-generic-microformats-parser-for-javascript">извлекает микроформаты, используя JavaScript</a>. Вы также можете попробовать <a href="http://leftlogic.com/lounge/articles/microformats_bookmarklet/">microformats bookmarklet</a>.

<h3>Как их использовать?</h3>
Что ж, если вы зашли так далеко, видимо вы и микроформаты просто созданы друг для друга. Так что, давайте сразу рассмотрим первый. Но прежде чем мы начнем, вот общая структура микроформатов, которую мы будем использовать:  если они связаны более чем с одним элементом в нашем коде, то используются классы. Если они связаны только с одним элементом, обычно используется атрибут <code>rel</code>.

<strong>hCalendar</strong>

hCalendar  - это простой способ отмечать события. Начнем с элемента, который объявляет наше событие:

[html]
&lt;div class=&quot;vevent&quot;&gt;   
  
&lt;/div&gt; 
[/html]

Если у вас предполагается несколько событий, вам нужно обернуть их в <code>div.vcalendar</code>, однако это не обязательно. Есть два обязательных свойства для события:  дата начала (<code>dtstart</code>) и описание (<code>summary</code>). Давайте добавим их:

[html]
&lt;div class=&quot;vevent&quot;&gt;   
    &lt;p&gt;This year, our &lt;span class=&quot;summary&quot;&gt;company holiday dinner&lt;/span&gt;    
    will begin at &lt;span class=&quot;dtstart&quot;&gt;2009-12-18T17:30&lt;/span&gt;.&lt;/p&gt;   
&lt;/div&gt;   
[/html]

Волне читаемо, не так ли? Но не дата! Вы правы, хотя микроформаты написаны в первую очередь для людей, даты – это единственная область, где в первую очередь важно, чтобы компьютер смог ее прочесть. Поэтому, было принято соглашение, записывать дату с помощью тэга <code>abbr</code>, в котором атрибут <code>title</code> будет выступать в роли значения свойства:

[html]
&lt;abbr class=&quot;dtstart&quot; title=&quot;2009-12-18T17:30&quot;&gt;5:30pm on Friday, December 18.&lt;/abbr&gt; 
[/html]

Есть и другие, необязательные свойства, которые вы можете добавить, при желании. Например, время окончания события или расположение:

[html]
&lt;p&gt;We'll meet in the &lt;span class=&quot;location&quot;&gt; conference room of the Tower Hotel&lt;/span&gt;,   
which we have reserved until &lt;abbr class=&quot;dtend&quot; title=&quot;2009-12-18T20:30&quot;&gt;9:30pm&lt;/abbr&gt;.&lt;/p&gt;   
[/html]

С помощью панели аддона Operator в Firefox, мы можем видеть это событие на нашей странице. Мы можем использовать его несколькими способами:

<img src="http://dreamhelg.ru/wp-content/uploads/2009/12/hcalendar1.jpg" alt="hcalendar" title="hcalendar" width="600" height="290" class="aligncenter size-full wp-image-1750" />

Если я выберу экспорт в Google Calendar, он отлично перенесет в календарь данные, которые мы указали.

<img src="http://dreamhelg.ru/wp-content/uploads/2009/12/gcal.jpg" alt="gcal" title="gcal" width="600" height="276" class="aligncenter size-full wp-image-1761" />

Если хотите узнать больше о hCalendar, обратитесь к <a href="http://microformats.org/wiki/hcalendar">документации</a>.

<strong>hCard</strong>

Давайте перейдем к hCard. hCard гораздо сложнее, чем hCalendar, но мы не будет рассматривать все детали. Если в дальнейшем, вы захотите узнать больше, читайте <a href="http://microformats.org/wiki/hcard">документацию</a>.

Снова мы начинаем с основы:

[html]
&lt;div class=&quot;vcard&quot;&gt;   
&lt;/div&gt;  
[/html]

Для hCard существует только два обязательных свойства: имя (<code>n</code>) и форматированное имя (<code>fn</code>). Обычно это один и тот же элемент.

[html]
&lt;div class=&quot;vcard&quot;&gt;   
    &lt;p class=&quot;fn n&quot;&gt;John Doe&lt;/p&gt;   
&lt;/div&gt;   
[/html]

Не забираясь слишком глубоко, замечу, что этот формат подразумевает что «John» - это имя, а “Doe” – фамилия. Если вы хотите это указать, вы можете использовать классы <code>given-name</code> и <code>family-name</code>:

[html]
&lt;span class=&quot;given-name&quot;&gt;John&lt;/span&gt;   
&lt;span class=&quot;family-name&quot;&gt;Doe&lt;/span&gt;   
[/html]

Конечно, обычно требуется указать немного больше, чем просто имя. Вы можете добавить псевдоним, фото, адрес электронной почты, день рожденья, url, номер телефона, и почтовый адрес.

[html]
&lt;p class=&quot;nickname&quot;&gt;JayDee&lt;/p&gt;   
&lt;img src=&quot;http://www.johndoe.com/avatar.jpg&quot; class=&quot;photo&quot; /&gt;   
&lt;ul&gt;   
    &lt;li class=&quot;email&quot;&gt;&lt;span class=&quot;type&quot;&gt;Personal:&lt;/span&gt; &lt;span class=&quot;value&quot;&gt;johndoe@gmail.com&lt;/span&gt;&lt;/li&gt;   
    &lt;li class=&quot;email&quot;&gt;&lt;span class=&quot;type&quot;&gt;Work:&lt;/span&gt; jdoe@example.com&lt;/li&gt;   
&lt;/ul&gt;   
&lt;ul&gt;   
    &lt;li class=&quot;tel&quot;&gt;&lt;span class=&quot;type&quot;&gt;Home&lt;/span&gt;: &lt;span class=&quot;value&quot;&gt;(416) 123-4567&lt;/span&gt;&lt;/li&gt;   
    &lt;li class=&quot;tel&quot;&gt;&lt;span class=&quot;type&quot;&gt;Work&lt;/span&gt; 416-987-6543&lt;/li&gt;   
&lt;/ul&gt;   
&lt;p class=&quot;bday&quot;&gt;January 1, 1980&lt;/p&gt;   
&lt;a href=&quot;http://www.johndoe.com&quot; class=&quot;url&quot;&gt;My Website&lt;/a&gt;   
&lt;address class=&quot;adr&quot;&gt;   
    &lt;p class=&quot;street-address&quot;&gt;123 Main Street&lt;/p&gt;   
    &lt;p&gt;&lt;span class=&quot;locality&quot;&gt;Toronto&lt;/span&gt;, &lt;span class=&quot;region&quot;&gt;Ontario&lt;/span&gt; &lt;span class=&quot;postal-code&quot;&gt;M2W 4R5&lt;/span&gt;&lt;/p&gt;   
    &lt;p class=&quot;country&quot;&gt;Canada&lt;/p&gt;   
&lt;/address&gt;   
[/html]

Есть несколько вещей, на которые стоит обратить внимание:
<ul>
	<li>Все имена классов, который я использовал здесь, являются свойствами hCard.</li>
	<li>Некоторые свойства, такие как url или photo, получают свои значения из атрибутов href и src, а не из текста элемента.</li>
	<li>Такие свойства как tel и email могут иметь два дочерних свойства: type и value. Если указан только type, value все равно будет подразумеваться (как вы могли заметить во втором адресе электронной почты и номере телефона).</li>
</ul>

С помощью Оператора, я могу экспортировать эти данные…

<img class="aligncenter size-full wp-image-1751" title="hcard" src="http://dreamhelg.ru/wp-content/uploads/2009/12/hcard.jpg" alt="hcard" width="342" height="300" />

… и открыть их в Outlook.

<img class="aligncenter size-full wp-image-1752" title="outlook" src="http://dreamhelg.ru/wp-content/uploads/2009/12/outlook.jpg" alt="outlook" width="600" height="418" />

Видите? Все что мы указывали, здесь!

<strong>xFolk</strong>

xFolk – это разрабатываемый микроформат для социальных закладок. Из <a href="http://microformats.org/wiki/xfolk">документации</a>:

<blockquote>Недостаток открытых, совместимых стандартов данных является главной проблемой в использовании сервисов социальных закладок. Открытый стандарт позволит легко собирать данные социальных закладок и на их основе изобретать новые сервисы… Кроме того, открытый стандарт сделает возможным написания кода JavaScript, который будет работать на любых сервисах, как сейчас сделано на del.icio.us.</blockquote>

Чтобы использовать xFolk, оберните каждую закладку контейнером с классом «<code>xfolkentry</code>»:

[html]
&lt;li class=&quot;xfolkentry&quot;&gt;   
&lt;/li&gt;   
[/html]

Затем, вставьте ссылку и описание, используя классы «<code>taggedLink</code>» и «<code>description</code>», соответственно.

[html]
&lt;a class=&quot;taggedlink&quot; href=&quot;http://net.tutsplus.com&quot; title=&quot;Nettuts+&quot;&gt;Nettuts&lt;/a&gt;,    
&lt;span class=&quot;description&quot;&gt;the best web development blog on the planet&lt;/span&gt;.
[/html]

Просто, не правда ли? Думаю, это будет весьма полезно для блог ролла или сводки последних новостей.

<strong>XFN (XHTML Friends Network)</strong>

XFN  - это простой способ отметить человеческие взаимоотношения. С помощью атрибута <code>rel</code> (который является аббревиатурой отношений) в ваших ссылках, вы описываете свои взаимоотношения с владельцем страницы, на которую вы ссылаетесь. У вас могут быть взаимоотношения двух видов: с другими людьми или с самим собой (ссылки на другие ваши страницы). Очень легко описать другие страницы, владельцем которых тоже являетесь вы:

[html]
&lt;a rel=&quot;me&quot; href=&quot;http://JohnDoe.posterous.com&quot;&gt;My Posterous&lt;/a&gt;   
&lt;a rel=&quot;me&quot; href=&quot;http://www.flickr.com/JohnDoe&quot;&gt;My Photos&lt;/a&gt;   
&lt;a rel=&quot;me&quot; href=&quot;http://twitter.com/JohnDoe&quot;&gt;My Tweets&lt;/a&gt; 
[/html]

Очень просто, да? Достаточно указать <code>rel=”me”</code> и все готово.

Отношения с другими людьми чуть более детальные, но совсем не трудные. Существует шесть категорий, которые вы можете использовать:  дружеские, физические, профессиональные, географические, семейные, романтические. Я не буду перечислять их все (узнать больше можно по этой <a href="http://gmpg.org×fn/creator">ссылке</a>), вот несколько примеров:

[html]
&lt;ul&gt;   
    &lt;li&gt;&lt;a href=&quot;#&quot; rel=&quot;met friend&quot;&gt;Good friend&lt;/a&gt;&lt;/li&gt;   
    &lt;li&gt;&lt;a href=&quot;#&quot; rel=&quot;met muse spouse sweetheart&quot;&gt;Darling wife&lt;/a&gt;&lt;/li&gt;   
    &lt;li&gt;&lt;a href=&quot;#&quot; rel=&quot;met acquaintance neighbour&quot;&gt;Guy next door&lt;/a&gt;&lt;/li&gt;   
    &lt;li&gt;&lt;a href=&quot;#&quot; rel=&quot;friend co-worker&quot;&gt;Co-worker at Envato&lt;/a&gt;&lt;/li&gt;   
&lt;/ul&gt;   
[/html]

В первой ссылке, вы можете сообщить, с помощью атрибута <code>rel</code>, что-то вроде «Я встречал владельца страницы, ставлю ссылку на его страницу, и я его друг».  Следующее, это моя (гипотетическая) жена, которой посчастливилось быть моей супругой и возлюбленной. Я также встречал парня по соседству, но он просто знакомый и сосед. И наконец, хотя мой (снова гипотетический) коллега является другом, обратите внимание, что я никогда не встречался с ним, это можно определить как виртуальные взаимоотношения.

Я хотел бы заметить, что вы не должны использовать XFN, когда просто ставите ссылки на статью в блоге и прочее. Используйте XFN, когда вы хотите указать непосредственно на человека, когда текстом ссылки является его имя, а ссылка ведет на домашнюю страницу.

<strong>VoteLinks</strong>

VoteLinks – это интересная идея: когда вы ставите ссылку на статью, продукт, на все что угодно, добавляйте атрибут rev. Rev? Rev – это противник <code>rel</code>; в то время как <code>rel</code> описывает как страница на которую ведет ссылка связана с текущей страницей, <code>rev</code> определяет отношение текущей страницы к той, на которую идет ссылка. С помощью VoteLinks, вы можете сделать свою страницу как голосующую за материал, который доступен по ссылке. Голосовать можно за, против, или воздержатся. Например:

[html]
&lt;p&gt;Check our &lt;a href=&quot;#&quot; rev=&quot;vote-for&quot;&gt;this great blog post by Collis&lt;/a&gt; on the netsetter&lt;/p&gt;   
  
&lt;p&gt;I got terrible service at &lt;a href=&quot;#&quot; rev=&quot;vote-against&quot;&gt;the Five Seasons Grill&lt;/a&gt; last night&lt;/p&gt;   
  
&lt;p&gt;What do I think of &lt;a href=&quot;#&quot; rev=&quot;vote-abstain&quot;&gt;his site redesign&lt;/a&gt;? &lt;/p&gt;
[/html]

Насколько это полезно? Ну, представьте если Google (или любой другой поисковик) будет учитывать VoteLinks при выдаче результатов поиска. Сейчас, их система (правда, в общих чертах)  выдает то количество ссылок, которое видит поисковик. Но что если за большинство этих ссылок являются голосами пользователей против продукта или страницы? Или как насчет сайта, который будет сканировать веб, в поисках VoteLinks, и выдавать вам список наиболее популярных страниц?  Конечно это обширное поле для спекуляции, но возможно это будет интересно. Проблема в том, что для того чтобы получить какой-то эффект, использовать VoteLinks  придется очень многим людям.

<strong>Geo</strong>

Geo очень простой, у него есть только два свойства: <code>latitude</code> и <code>longitude</code>.

[html]
&lt;p class=&quot;geo&quot;&gt;&lt;strong&gt;Apple :&lt;/strong&gt;   
    (&lt;span class=&quot;latitude&quot;&gt;37.33171397409807&lt;/span&gt;   
    &lt;span class=&quot;longitude&quot;&gt;-122.03051626682281&lt;/span&gt;)   
&lt;/p&gt;   
&lt;p class=&quot;geo&quot;&gt;&lt;strong&gt;Envato :&lt;/strong&gt;   
    &lt;abbr class=&quot;latitude&quot; title=&quot;-37.812528&quot;&gt;-37&amp;deg; 48' 45.1008&quot;&lt;/abbr&gt;   
    &lt;abbr class=&quot;longitude&quot; title=&quot;144.969076&quot;&gt;144&amp;deg; 58' 8.6736&quot;&lt;/abbr&gt;.   
&lt;/p&gt;   
[/html]

Как мы уже говорили ранее, вы можете использовать элемент abbr для маскировки настоящих значений. И конечно же, Оператор распознает их.

<img class="aligncenter size-full wp-image-1753" title="geo" src="http://dreamhelg.ru/wp-content/uploads/2009/12/geo.jpg" alt="geo" width="600" height="283" />

<strong>rel-license</strong>

Если вы разрабатываете что-то для публичного использования, вы, скорее всего, знаете, что в проект необходимо включить лицензию. Вы можете назначить атрибут <code>rel</code> со значением «<code>license</code>» для ссылки на лицензионную документацию.

[html]
&lt;a href=&quot;http://creativecommons.org/licenses/by/2.0/&quot; rel=&quot;license&quot;&gt;cc by 2.0&lt;/a&gt;
[/html]

В чем смысл? В том, что Yahoo Creative Commons Search и Google Usage Right's Search, оба уже используют атрибут rel=”license” в своих алгоритмах.

<strong>rel-tag</strong>

Это очень интересный микроформат, потому что каждый блоггер назначает тэги своим статьям. Для того, чтобы использовать этот микроформат, просто добавьте <code>rel=”tag”</code> к вашей тэговой ссылке, и все готово. Теперь, с помощью нашей панели Оператора, мы можем видеть контент других сайтов, с такими же тэгами. Важно понимать, что имя тэга берется из атрибута <code>href</code>, а не из текста ссылки. Так что в следующем примере…

[html]
&lt;a href=&quot;http://www.example.com/tag/javascript&quot; rel=”tag” &gt;Client-Side Scripting&lt;/a&gt;   
[/html]

… тэгом будет «JavaScript» а не «client-side scripting».

Nettuts использует этот микроформат, но вы конечно об этом знаете, если используете Оператор.

<img class="aligncenter size-full wp-image-1754" title="reltag" src="http://dreamhelg.ru/wp-content/uploads/2009/12/reltag.jpg" alt="reltag" width="600" height="308" />

<strong>rel-nofollow</strong>

Другой простой, но эффективный тэг – это атрибут <code>rel=”nofollow”</code> к ссылке. Он используется для того, чтобы выбранная ссылка не участвовала в ранжировании страниц  в поисковых системах. И конечно такие поисковые системы как Google, Yahoo и Bing, активно используют этот микроформат. Он идеален для ссылок в комментариях к блогу, поскольку с этим атрибутом сторонние ссылки не будут оказывать влияния на ваш сайт, а также раздавать рейтинг своим владельцам.

<h3>Итак, что вы собираетесь делать?</h3>
Сегодня, мы вкратце рассмотрели некоторые полезные микроформаты, но вопрос в том, стоят ли они вашего времени? Не стоят, пока вы не начнете их использовать! Микроформаты разработаны для более удобного получения данных со страницы, но пока они не будут широко использоваться, инструментов для их использования, тоже будет мало. Несмотря на то, что многие из них могут показаться бессмысленными сейчас, надеюсь, через несколько лет они будут использоваться повсеместно.

Будете ли вы использовать микроформаты в своих сайтах?

Перевод статьи "<a href="http://net.tutsplus.com/tutorials/other/microformats-what-why-and-how/">Microformats: What, Why, and How</a>", автор <strong>Andrew Burgess</strong>]]></description>
		<wfw:commentRss>http://dreamhelg.ru/2009/12/microformats-why-what-and-how/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Простой, перетаскиваемый элемент на jQuery</title>
		<link>http://dreamhelg.ru/2009/11/simple-draggable-element-with-jquery/</link>
		<comments>http://dreamhelg.ru/2009/11/simple-draggable-element-with-jquery/#comments</comments>
		<pubDate>Mon, 23 Nov 2009 07:54:16 +0000</pubDate>
		<dc:creator>dreamhelg</dc:creator>
				<category><![CDATA[общая]]></category>
		<category><![CDATA[переводы]]></category>
		<category><![CDATA[ajax]]></category>
		<category><![CDATA[jquery]]></category>
		<category><![CDATA[php]]></category>

		<guid isPermaLink="false">http://dreamhelg.ru/?p=1713</guid>
		<description><![CDATA[<p><img width="200" height="200" src="http://dreamhelg.ru/wp-content/uploads/2009/11/200x200.jpg" class="attachment-200x200 wp-post-image" alt="200x200" title="200x200" /></p>Бывают случаи, когда вам может понадобиться создать перетаскиваемый элемент внутри вашего веб-приложения. Это отличная функциональность, однако, возможно вы хотите, чтобы элемент оставался на новом месте, после перетаскивания.  В сегодняшней статье вы узнаете, как можно легко перетаскивать и закреплять в новом месте нужный элемент даже после перезагрузки страницы, с помощью захвата и хранения его X и Y координат.<span id="more-1713"></span>

<h3>Сценарий</h3>
Итак, у вас есть элемент на странице. Вы можете перетаскивать его туда-сюда. Но, когда страница перезагружается, элемент возвращается на исходную позицию.  И хотя нам нужно, чтобы элемент был перетаскиваемый, при этом нужно, чтобы наш элемент достаточно было перетащить один раз. Давайте рассмотрим простое решение, реализующее данную функциональность.

<h3>Начало</h3>
Для этого примера нам понадобится библиотека <a href="http://jquery.com/">jQuery</a>, <a href="http://jqueryui.com/">jQuery UI </a>и плагин JQuery-<a href="http://code.google.com/p/jquery-json/">JSON</a>. Кроме этого, мы также будем использовать PHP и базу данных MySQL для разбора и хранения наших данных. Если вы новичок в jQuery, не беспокойтесь. JQuery - это расширяемая, быстрая и легковесная JavaScript-библиотека, которую легко и весело использовать. Библиотека имеет хорошо структурированную документацию и огромное сообщество.

<a href="http://dreamhelg.ru/wp-content/uploads/2009/11/jquery.jpg"><img class="aligncenter size-full wp-image-1716" title="jquery" src="http://dreamhelg.ru/wp-content/uploads/2009/11/jquery.jpg" alt="jquery" width="500" height="200" /></a>

<h3>HTML и CSS</h3>
Начнем с HTML-разметки и стилей для нашего примера. Сначала CSS:

[css]
html, body {   
    background:#151515;   
    margin:0 0 0 0;   
    padding:0 0 0 0;   
}   
  
#glassbox {   
    background:#333;   
    border:1px solid #000;   
    height:400px;   
    margin:30px auto auto auto;   
    position:relative;   
    width:960px;   
    -moz-border-radius: 10px;   
    -webkit-border-radius: 10px;       
}   
  
#element {   
    background:#666;   
    border:1px #000 solid;   
    cursor:move;   
    height:143px;   
    padding:10px 10px 10px 10px;   
    width:202px;   
    -moz-border-radius: 10px;   
    -webkit-border-radius: 10px;   
}   
  
#respond{   
    color:#fff;   
    margin:0 auto 0 auto;   
    width:960px;       
}  
[/css]

CSS – очень простой. Мы назначаем html и body нулевые свойства, для чистки внешних и внутренних отступов, далее устанавливаем значения высоты, ширины и другие свойства для наших элементов. -<code>moz-border-radius</code> и <code>-webkit-border-radius</code> – это два свойства, позволяющие нам создать закругленные углы (работает пока только в Mozilla Firefox и Safari 3) для наших элементов. Теперь, давайте взглянем на HTML:

[html]
&lt;!DOCTYPE html&gt;   
&lt;html&gt;   
&lt;head&gt;   
&lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=utf-8&quot; /&gt;   
&lt;title&gt;Simple Draggable Element Persistence with jQuery&lt;/title&gt;   
  
&lt;link rel=&quot;stylesheet&quot; href=&quot;style.css&quot; type=&quot;text/css&quot; /&gt;   
&lt;script type=&quot;text/javascript&quot; src=&quot;js/jquery-1.3.2.min.js&quot;&gt;&lt;/script&gt;   
&lt;script type=&quot;text/javascript&quot; src=&quot;js/jquery-ui-1.7.2.custom.min.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;/head&gt;   
  
&lt;body&gt;   
  
    &lt;div id=&quot;glassbox&quot;&gt;   
        &lt;div id=&quot;element&quot;&gt;&lt;img src=&quot;nettuts.jpg&quot; alt=&quot;Nettuts+&quot; /&gt;Move the Box&lt;p&gt;&lt;/p&gt;&lt;/div&gt;   
    &lt;/div&gt;   
  
    &lt;div id=&quot;respond&quot;&gt;&lt;/div&gt;   
[/html]

Как видите, мы создали очень простую страницу, в которую подключили наш CSS, библиотеку JavaScript и плагины, кроме того, страница содержит элементы, к которым мы будем применять некоторые эффекты и события. Обратите внимание, что файл jquery-ui представляет собой специальную сборку, включающую в себя только ядро и функции перетаскивания элементов.

<a href="http://dreamhelg.ru/wp-content/uploads/2009/11/general.jpg"><img class="aligncenter size-full wp-image-1717" title="general" src="http://dreamhelg.ru/wp-content/uploads/2009/11/general.jpg" alt="general" width="584" height="452" /></a>

<h3>JavaScript</h3>
Теперь самое интересное! Сначала давайте рассмотрим базовые функции, которые мы будем использовать для применения некоторых эффектов к нашим элементам. Разберем все до основания.

[javascript]
&lt;script type=&quot;text/javascript&quot;&gt;   
    $(document).ready(function() {   
        $(&quot;#element&quot;).draggable({    
                containment: '#glassbox',    
                scroll: false   
         })   
[/javascript]

Сначала мы говорим браузеру: «Эй, это код, который мы хотим запустить; это не HTML, это JavaScript». Затем, мы ждем пока документ полностью загрузится, после того как это случилось, вызываем функцию для получения нашего блока <code>#element</code>, и добавляем к нему обработчик перетаскивания с базовыми настройками. Опция <code>containment</code> содержит наш элемент внутри родительского блока, и мы устанавливаем значение <code>scroll</code> в <code>false</code>, потому что, нам не нужен скролл.

Двигаемся дальше:

[javascript]
.mousemove(function(){   
    var coord = $(this).position();   
    $(&quot;p:last&quot;).text( &quot;left: &quot; + coord.left + &quot;, top: &quot; + coord.top );   
})   
[/javascript]

Внутри этого фрагмента, мы вызываем, обработчик события mousemove и говорим ему: «Когда мышь передвигается, установить переменную <code>coord</code> равной значению текущей позиции нашего блока #element» Затем мы получаем последний параграф в блоке <code>#(“p: last”) </code>и печатаем текст, выводящий значения свойств <code>left(x) </code>и <code>top(y)</code> нашего элемента, относительно родительского объекта (которым является блок <code>#glassbox</code>).

[javascript]
.mouseup(function(){    
            var coords=[];   
            var coord = $(this).position();   
            var item={ coordTop:  coord.left, coordLeft: coord.top  };   
            coords.push(item);   
            var order = { coords: coords };   
            $.post('updatecoords.php', 'data='+$.toJSON(order), function(response){   
                    if(response==&quot;success&quot;)   
                        $(&quot;#respond&quot;).html('&lt;div class=&quot;success&quot;&gt;X and Y Coordinates Saved!&lt;/div&gt;').hide().fadeIn(1000);   
                        setTimeout(function(){ $('#respond').fadeOut(1000); }, 2000);   
                    });    
            });   
                       
});   
lt;/script&gt;   
[/javascript]

Ну да, здесь уже сложнее. В этом фрагменте мы собираемся сделать кучу вещей. Сначала, мы устанавливаем пустой массив, а затем получаем некоторые значения для его наполнения. С помощью вызова обработчика событий <code>.mouseup()</code> мы велим браузеру отслеживать событие, когда вы отпускаете кнопку мыши. Мы указываем, что переменная <code>coords</code> – это пустой массив и снова устанавливаем ее значение равной позиции нашего блока <code>#element</code>.

Затем, нам нужно создать список из двух строчек, которыми будут <code>coordTop:</code> и <code>coordLeft:</code>, соответствующие позициям <code>left</code> и <code>top</code>, нашего блока. С помощью строки <code>coords.push(item)</code>, мы заполним наш список массивом из координат. Затем задаем переменную <code>order</code> как новый список, в котором ключ <code>coords</code> будет соответствовать нашему массиву <code>coords</code>. Теперь немного аякса.

<a href="http://dreamhelg.ru/wp-content/uploads/2009/11/dragged.jpg"><img class="aligncenter size-full wp-image-1718" title="dragged" src="http://dreamhelg.ru/wp-content/uploads/2009/11/dragged.jpg" alt="dragged" width="528" height="458" /></a>

<code>$.post</code> – это обработчик запроса AJAX, который загружает удаленную страницу, с помощью метода <code>HTTP POST</code>. Эта функция принимает следующие параметры: url, дата, ответ и тип данных для возврата. В этом примере, мы укажем файле updatecoords.php в качестве нашего URL, потому что, именно этому файлы мы хотим отправить наши данные. Затем, мы опишем тип данных, с помощью включения функции <code>$.toJSON</code>, определенной в плагине JSON и назначим переменную <code>order</code>, в качестве данных, которые должен вернуть <code>.toJSON</code>.

Далее, мы создаем ответ, который проверяет возвращение успешного ответа от нашего PHP-файла. В случае получения успешного ответа, мы отображаем сообщение об успешном сохранении координат, используя метод <code>.fadeIn()</code> и скорость 1000 миллисекунд, затем задаем таймер на 2000 миллисекунд, и снова медленно прячем это сообщение, с помощью метода <code>.fadeOut()</code>. Вот так будет выглядеть наш JavaScript в целом виде:

[javascript]
&lt;script type=&quot;text/javascript&quot;&gt;   
    $(document).ready(function() {   
        $(&quot;#element&quot;).draggable({    
                containment: '#glassbox',    
                scroll: false   
         }).mousemove(function(){   
                var coord = $(this).position();   
                $(&quot;p:last&quot;).text( &quot;left: &quot; + coord.left + &quot;, top: &quot; + coord.top );   
         }).mouseup(function(){    
                var coords=[];   
                var coord = $(this).position();   
                var item={ coordTop:  coord.left, coordLeft: coord.top  };   
                coords.push(item);   
                var order = { coords: coords };   
                $.post('updatecoords.php', 'data='+$.toJSON(order), function(response){   
                        if(response==&quot;success&quot;)   
                            $(&quot;#respond&quot;).html('&lt;div class=&quot;success&quot;&gt;X and Y Coordinates Saved!&lt;/div&gt;').hide().fadeIn(1000);   
                            setTimeout(function(){ $('#respond').fadeOut(1000); }, 2000);   
                        });    
                });   
                           
        });   
&lt;/script&gt;   
[/javascript]

Поместите этот код ниже HTML, сразу после закрывающего тега body.
<h3>PHP</h3>
Хорошо, давайте сделаем что-нибудь с данными, которые приходят от нашего JQuery. Сначала нужно создать простую базу данных, для хранения наших координат, которые мы впоследствии будем использовать для определения позиции нашего элемента. Затем, нам понадобится файл config.php, в котором будут записаны параметры подключения к базе данных, а затем мы перейдем к updatecords.php.

<strong>SQL</strong>

[sql]
Database: 'xycoords'   
  
CREATE TABLE IF NOT EXISTS `coords` (   
  `id` int(11) NOT NULL AUTO_INCREMENT,   
  `x_pos` int(4) NOT NULL,   
  `y_pos` int(4) NOT NULL,   
  PRIMARY KEY (`id`)   
) ENGINE=MyISAM  DEFAULT CHARSET=latin1; 
[/sql]

<strong>Config.php</strong>

[php]
&lt;?php   
/*Database Settings*/   
  
$db_host =&quot;localhost&quot;; //this will likely stay the same   
$db_name = &quot;xycoords&quot;; //name of the database we will be using   
$db_usr = &quot;database_username&quot;; //db username   
$db_pass = &quot;database_password&quot;; //db password   
  
//Connect to the database   
$link = mysqli_connect($db_host, $db_usr, $db_pass) or die(&quot;MySQL Error: &quot; . mysqli_error());   
//Select our database   
mysqli_select_db($link, $db_name) or die(&quot;MySQL Error: &quot; . mysqli_error());   
?&gt;   
[/php]

<strong>updatecoords.php</strong>

[php]
&lt;?php   
if(!$_POST[&quot;data&quot;]){   
    echo &quot;Nothing Sent&quot;;   
    exit;   
}   
  
include ('config.php');   
  
//decode JSON data received from AJAX POST request   
$data = json_decode($_POST[&quot;data&quot;]);   
  
foreach($data-&gt;coords as $item) {   
    //Extract X number for panel   
    $coord_X = preg_replace('/[^\d\s]/', '', $item-&gt;coordTop);   
    //Extract Y number for panel   
    $coord_Y = preg_replace('/[^\d\s]/', '', $item-&gt;coordLeft);   
    //escape our values - as good practice   
    $x_coord = mysqli_real_escape_string($link, $coord_X);   
    $y_coord = mysqli_real_escape_string($link, $coord_Y);   
       
    //Setup our Query   
    $sql = &quot;UPDATE coords SET x_pos = '$x_coord', y_pos = '$y_coord'&quot;;   
       
    //Execute our Query   
    mysqli_query($link, $sql) or die(&quot;Error updating Coords :&quot;.mysqli_error());    
}   
  
//Return Success   
echo &quot;success&quot;;   
  
?&gt;
[/php]

Здесь все довольно просто. Первое, что мы делаем – это проверяем, были ли переданы данные в файл. Если это произошло, мы включаем наш файл с настройками config.php и назначаем переменной <code>$data</code> значение <code>json_decode(passed post variable);</code> <a href="http://us.php.net/manual/en/function.json-decode.php">json_decode</a> – это PHP-функция, представленная в PHP 5.2.0, которая позволяет декодировать строку JSON.

Поскольку наша переменная <code>$data</code> содержит массив данных, нам нужно разобрать его на части, чтобы получить нужные значения. Для этого мы пройдемся по массиву <code>$data-&gt;coords () </code>(который был получен из переменной <code>order</code> в JavaScript) и обработаем каждый элемент. В результате, из каждой пары ключ – значение будет создан объект списка, который мы в дальнейшем укажем и создадим переменную для его вывода. При этом мы будем использовать функцию <code>preg_replace</code>, для исключения ненужных символов. Кроме того, мы подготовим наши значения для вставки в базу данных, путем экранирования кавычек, и апострофов, с помощью функции <code>mysqli_real_escape_string</code>. Если все прошло хорошо, нам нужно будет вернуть успешный результат JavaScript.

<a href="http://dreamhelg.ru/wp-content/uploads/2009/11/response.jpg"><img class="aligncenter size-full wp-image-1719" title="response" src="http://dreamhelg.ru/wp-content/uploads/2009/11/response.jpg" alt="response" width="558" height="466" /></a>
<h3>В заключение</h3>
Теперь, когда у нас уже все готово, для того чтобы получить координаты элемента и передать их в PHP для записи, нам понадобится изменить нашу HTML-разметку для отображения позиции элемента. Для этого, мы удалим простую HTML-разметку и создадим ее с помощью PHP:

[php]
&lt;div id=&quot;glassbox&quot;&gt;   
&lt;?php   
        //Create a query to fetch our values from the database     
        $get_coords = mysqli_query($link, &quot;SELECT * FROM coords&quot;);   
        //We then set variables from the * array that is fetched from the database   
        while($row = mysqli_fetch_array($get_coords)) {   
            $x = $row['x_pos'];   
            $y = $row['y_pos'];   
            //then echo our div element with CSS properties to set the left(x) and top(y) values of the element   
            echo '&lt;div id=&quot;element&quot; style=&quot;left:'.$x.'px; top:'.$y.'px;&quot;&gt;&lt;img src=&quot;nettuts.jpg&quot; alt=&quot;Nettuts+&quot; /&gt;Move the Box&lt;p&gt;&lt;/p&gt;&lt;/div&gt;';   
        }              
?&gt;   
&lt;/div&gt;   
&lt;div id=&quot;respond&quot;&gt;&lt;/div&gt;   
[/php]

Здесь мы исполняем простой запрос к базе данных для выбора всех строк из таблицы coords. Затем мы вызываем цикл while, который определяет каждую выбранную нами строчку как <code>$row</code>. Теперь, мы можем назначить переменные равными каждой, индивидуальной строке, полученной из базы данных, и выводим их в соответствующем месте.

<a href="http://nettuts.s3.amazonaws.com/477_drag/source.zip">Скачать архив с примером</a>.

Перевод статьи «<a href="http://net.tutsplus.com/tutorials/javascript-ajax/simple-draggable-element-persistence-with-jquery/">Simple Draggable Element Persistence with jQuery</a>», автор <strong>Dustin Blake</strong>]]></description>
		<wfw:commentRss>http://dreamhelg.ru/2009/11/simple-draggable-element-with-jquery/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Красивая форма обратной связи на основе AJAX</title>
		<link>http://dreamhelg.ru/2009/11/fancy-ajax-contact-form/</link>
		<comments>http://dreamhelg.ru/2009/11/fancy-ajax-contact-form/#comments</comments>
		<pubDate>Fri, 13 Nov 2009 08:56:14 +0000</pubDate>
		<dc:creator>dreamhelg</dc:creator>
				<category><![CDATA[общая]]></category>
		<category><![CDATA[переводы]]></category>
		<category><![CDATA[ajax]]></category>
		<category><![CDATA[jquery]]></category>
		<category><![CDATA[php]]></category>

		<guid isPermaLink="false">http://dreamhelg.ru/?p=1690</guid>
		<description><![CDATA[<p><img width="200" height="150" src="http://dreamhelg.ru/wp-content/uploads/2009/11/home.jpg" class="attachment-200x200 wp-post-image" alt="home" title="home" /></p>Предоставление посетителям сайта простого и надежного средства обратной связи –  это важнейшая часть любого веб-проекта. Наиболее простым и часто используемым каналом обратной связи - являются контактные формы. Посмотреть результат можно <a href="http://dreamhelg.ru/demo/contactform/demo.php">здесь</a>.<span id="more-1690"></span>

В сегодняшней статье, мы создадим <strong>форму обратной связи  на аяксе</strong>, с использованием современных техник веб-разработки.  Для этого мы будем использовать PHP, CSS и jQuery в виде нескольких плагинов. Плагин <a href="http://www.position-absolute.com/articles/jquery-form-validator-because-form-validation-is-a-mess/">formValidator</a> будем использовать для проверки введенных значений, а с помощью плагина <a href="http://www.dfc-e.com/metiers/multimedia/opensource/jqtransform/">jQTransform</a>, будем стилизовать текстовые поля и кнопки нашей формы. В дополнение, мы будем использовать класс <a href="http://sourceforge.net/projects/phpmailer/">PHPMailer</a> для отправки на почту введенных данных.

Кроме того, наша форма будет прекрасно работать даже с выключенным JS.

<em>*Для нормальной работы примера, вам понадобится <strong>PHP5</strong></em>
<h3>Шаг 1 – XHTML</h3>
Сначала нам понадобится XHTML-разметка для формы.

<strong>demo.php</strong>

[html]
&lt;div id=&quot;main-container&quot;&gt;	&lt;!-- The main container element --&gt;

&lt;div id=&quot;form-container&quot;&gt;	&lt;!-- The form container --&gt;

&lt;h1&gt;Fancy Contact Form&lt;/h1&gt;	&lt;!-- Headings --&gt;
&lt;h2&gt;Drop us a line and we will get back to you&lt;/h2&gt;

&lt;form id=&quot;contact-form&quot; name=&quot;contact-form&quot; method=&quot;post&quot; action=&quot;submit.php&quot;&gt;	&lt;!-- The form, sent to submit.php --&gt;

&lt;table width=&quot;100%&quot; border=&quot;0&quot; cellspacing=&quot;0&quot; cellpadding=&quot;5&quot;&gt;

&lt;tr&gt;
&lt;td width=&quot;18%&quot;&gt;&lt;label for=&quot;name&quot;&gt;Name&lt;/label&gt;&lt;/td&gt;	&lt;!-- Text label for the input field --&gt;
&lt;td width=&quot;45%&quot;&gt;&lt;input type=&quot;text&quot; class=&quot;validate[required,custom[onlyLetter]]&quot; name=&quot;name&quot; id=&quot;name&quot; value=&quot;&lt;?=$_SESSION['post']['name']?&gt;&quot; /&gt;&lt;/td&gt;
&lt;!-- We are using session to prevent losing data between page redirects --&gt;

&lt;td width=&quot;37%&quot; id=&quot;errOffset&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;&lt;label for=&quot;email&quot;&gt;Email&lt;/label&gt;&lt;/td&gt;
&lt;td&gt;&lt;input type=&quot;text&quot; class=&quot;validate[required,custom[email]]&quot; name=&quot;email&quot; id=&quot;email&quot; value=&quot;&lt;?=$_SESSION['post']['email']?&gt;&quot; /&gt;&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;&lt;label for=&quot;subject&quot;&gt;Subject&lt;/label&gt;&lt;/td&gt;

&lt;!-- This select is being replaced entirely by the jqtransorm plugin --&gt;

&lt;td&gt;&lt;select name=&quot;subject&quot; id=&quot;subject&quot;&gt;
&lt;option value=&quot;&quot; selected=&quot;selected&quot;&gt; - Choose -&lt;/option&gt;
&lt;option value=&quot;Question&quot;&gt;Question&lt;/option&gt;
&lt;option value=&quot;Business proposal&quot;&gt;Business proposal&lt;/option&gt;
&lt;option value=&quot;Advertisement&quot;&gt;Advertising&lt;/option&gt;
&lt;option value=&quot;Complaint&quot;&gt;Complaint&lt;/option&gt;
&lt;/select&gt;          &lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td valign=&quot;top&quot;&gt;&lt;label for=&quot;message&quot;&gt;Message&lt;/label&gt;&lt;/td&gt;
&lt;td&gt;&lt;textarea name=&quot;message&quot; id=&quot;message&quot; class=&quot;validate[required]&quot; cols=&quot;35&quot; rows=&quot;5&quot;&gt;&lt;?=$_SESSION['post']['message']?&gt;&lt;/textarea&gt;&lt;/td&gt;
&lt;td valign=&quot;top&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;&lt;label for=&quot;captcha&quot;&gt;&lt;?=$_SESSION['n1']?&gt; + &lt;?=$_SESSION['n2']?&gt; =&lt;/label&gt;&lt;/td&gt;

&lt;!-- A simple captcha math problem --&gt;

&lt;td&gt;&lt;input type=&quot;text&quot; class=&quot;validate[required,custom[onlyNumber]]&quot; name=&quot;captcha&quot; id=&quot;captcha&quot; /&gt;&lt;/td&gt;
&lt;td valign=&quot;top&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td valign=&quot;top&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;!-- These input buttons are being replaced with button elements --&gt;
&lt;td colspan=&quot;2&quot;&gt;&lt;input type=&quot;submit&quot; name=&quot;button&quot; id=&quot;button&quot; value=&quot;Submit&quot; /&gt;
&lt;input type=&quot;reset&quot; name=&quot;button2&quot; id=&quot;button2&quot; value=&quot;Reset&quot; /&gt;
&lt;?=$str?&gt;

&lt;!-- $str contains the error string if the form is used with JS disabled --&gt;

&lt;img id=&quot;loading&quot; src=&quot;img/ajax-load.gif&quot; width=&quot;16&quot; height=&quot;16&quot; alt=&quot;loading&quot; /&gt;
&lt;!-- the rotating gif animation, hidden by default --&gt;
&lt;/td&gt;&lt;/tr&gt;

&lt;/table&gt;
&lt;/form&gt;

&lt;?=$success?&gt;
&lt;!-- The $success variable contains the message that is shown if JS is disabled and the form is submitted successfully --&gt;

&lt;/div&gt;
&lt;/div&gt;	&lt;!-- closing the containers --&gt;
[/html]

Как вы могли заметить в строке 8, обрабатывать нашу форму будет файл <strong>submit.php</strong>. Мы будем использовать этот файл в обоих случаях – как для обычной отправки формы (для посетителей с выключенным JS), так и для аяксовой отправки формы. Это позволит легко обновлять код, без необходимости объединять изменения между файлами.

Далее, мы можете видеть, что мы используем массив <strong>$_SESSION</strong> для заполнения текстовых полей значениями. Это делается для того, чтобы данные не потерялись во время перенаправления страницы, которое происходит во время отправки формы в <strong>submit.php</strong>.

Другой важный аспект – это классы, назначенный текстовым полям – <strong>classs=”validate[required,custom[onlyLetter]]”</strong>. Эти классы используются плагином валидации для определения правил проверки введенных значений для каждого текстового поля. В нашем примере, мы указываем, что поле обязательное, и разрешено вводить только буквы.

Существует множество доступных правил валидации, вы можете узнать о них на домашней странице плагина.

Теперь взгляните, как будет выглядеть наша форма, с применением плагина <strong>JQtransform</strong>.

<a href="http://dreamhelg.ru/wp-content/uploads/2009/11/1.jpg"><img class="aligncenter size-full wp-image-1694" title="1" src="http://dreamhelg.ru/wp-content/uploads/2009/11/1.jpg" alt="1" width="433" height="468" /></a>
<h3>Шаг 2 – jQuery</h3>
МЫ используем два плагина jQuery – <strong>jQtransform</strong> для стилизации элементов формы, и <strong>formValidator</strong> для проверки введенных значений на клиентской стороне.

Очень важно помнить, что кроме клиентской стороны, введенные данные всегда нужно проверять на серверной стороне.

Итак, для начала нам нужно подключить все необходимые библиотеки.

<strong>demo.php</strong>

[php]
&lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;jqtransformplugin/jqtransform.css&quot; /&gt;
&lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;formValidator/validationEngine.jquery.css&quot; /&gt;
&lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;demo.css&quot; /&gt;

&lt;?=$css?&gt; &lt;!-- Special CSS rules, created by PHP --&gt;

&lt;script type=&quot;text/javascript&quot; src=&quot;http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;jqtransformplugin/jquery.jqtransform.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;formValidator/jquery.validationEngine.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;script.js&quot;&gt;&lt;/script&gt;
[/php]

Указанный выше код расположен в секции <em>head</em>, файла <strong>demo.php</strong>. Сначала мы подключаем CSS-файлы, используемые обоими плагинами, а затем уже библиотеку JQuery и плагины. Возможно, вас заинтересовала строка 5 – это специальный набор CSS-правил, который мы создадим с помощью PHP, для отображения подтверждающего сообщения, как вы увидите в дальнейшем.

Теперь, давайте посмотрим на наш файл <strong>script.js</strong>.

<strong>script.js</strong>

[javascript]
$(document).ready(function(){
	/* after the page has finished loading */

	$('#contact-form').jqTransform();
	/* transform the form using the jqtransform plugin */

	$(&quot;button&quot;).click(function(){

		$(&quot;.formError&quot;).hide();
		/* hide all the error tooltips */
	});

	var use_ajax=true;
	$.validationEngine.settings={};
	/* initialize the settings object for the formValidation plugin */

	$(&quot;#contact-form&quot;).validationEngine({	/* create the form validation */
		inlineValidation: false,
		promptPosition: &quot;centerRight&quot;,
		success :  function(){use_ajax=true},	/* if everything is OK enable AJAX */
		failure : function(){use_ajax=false}	/* in case of validation failure disable AJAX */
	 })

	$(&quot;#contact-form&quot;).submit(function(e){

			if(!$('#subject').val().length)
			{
				$.validationEngine.buildPrompt(&quot;.jqTransformSelectWrapper&quot;,&quot;* This field is required&quot;,&quot;error&quot;)
				/* a custom validation tooltip, using the buildPrompt method */

				return false;
			}

			if(use_ajax)
			{
				$('#loading').css('visibility','visible');
				/* show the rotating gif */

				$.post('submit.php',$(this).serialize()+'&amp;ajax=1',
				/* using jQuery's post method to send data */

				function(data){
					if(parseInt(data)==-1)
						$.validationEngine.buildPrompt(&quot;#captcha&quot;,&quot;* Wrong verification number!&quot;,&quot;error&quot;);
						/* if there is an error, build a custom error tooltip for the captcha */
					else
					{
						$(&quot;#contact-form&quot;).hide('slow').after('&lt;h1&gt;Thank you!&lt;/h1&gt;');
						/* show the confirmation message */
					}

					$('#loading').css('visibility','hidden');
					/* hide the rotating gif */
				});
			}

e.preventDefault();	/* stop the default form submit */
})

});
[/javascript]

Весь блок скрипта выполняется внутри метода <strong>$(document).ready</strong>, который гарантирует нам, свое исполнение, только после окончания загрузки страницы.

Далее, мы используем метод <strong>jqTransform()</strong>, который определен в плагине <strong>jqtransform</strong>. Он переделывает и стилизует все элементы формы (тестовые поля, кнопки и др.)

Элемент <em>select</em> заменяется набором дивов и ссылок. Это выглядит здорово, однако влечет за собой некоторые проблемы с плагином валидации, в связи с чем, тултип для селекта нам придется сделать вручную.

После этого, в строке 7, вешаем обработчик событий на нажатие кнопки в нижней части формы, с одной строкой кода, которая прячет отображаемые тултипы с сообщениями об ошибках. Это для того, чтобы страница правильно обновлялась, и подсказки не оставались на странице, если пользователь ввел правильные данные.

Далее, мы инициализируем  плагин <strong>formValidation</strong>, с помощью метода <strong>validationEngine() </strong>и в строке 24 описываем событие формы <strong>onsubmit</strong>. Пара моментов, на которые стоит обратить внимание здесь – отдельный тултип в строке 28, и дополнительный параметр <strong>ajax=1</strong>, в строке 39. Этот параметр использует файл <strong>submit.php</strong>, для того чтобы определить, передан ли запрос с помощью аякса или получен непосредственно через отправку формы.

Также, обратите внимание, что мы используем специальную переменную <strong>use_ajax</strong>, для предотвращения работы аякса, если форма не прошла проверку.

<a href="http://dreamhelg.ru/wp-content/uploads/2009/11/2.png"><img class="aligncenter size-full wp-image-1695" title="2" src="http://dreamhelg.ru/wp-content/uploads/2009/11/2.png" alt="2" width="600" height="460" /></a>
<h3>Шаг 3 – CSS</h3>
Все наши CSS-правила описаны в файле <strong>demo.css</strong>

<strong>demo.css</strong>

[css]
body,h1,h2,h3,p,quote,small,form,input,ul,li,ol,label{
	/* reset some of the page elements */
	margin:0px;
	padding:0px;
}

body{
	color:#555555;
	font-size:13px;
	background: url(img/dark_wood_texture.jpg) #282828;
	font-family:Arial, Helvetica, sans-serif;
}

.clear{
	clear:both;
}

#main-container{
	width:400px;
	margin:30px auto;
}

#form-container{
	background-color:#f5f5f5;
	padding:15px;

	/* rounded corners */
	-moz-border-radius:12px;
	-khtml-border-radius: 12px;
	-webkit-border-radius: 12px;
	border-radius:12px;
}

td{
	/* prevent multiline text */
	white-space:nowrap;
}

a, a:visited {
	color:#00BBFF;
	text-decoration:none;
	outline:none;
}

a:hover{
	text-decoration:underline;
}

h1{
	color:#777777;
	font-size:22px;
	font-weight:normal;
	text-transform:uppercase;
	margin-bottom:5px;
}

h2{
	font-weight:normal;
	font-size:10px;

	text-transform:uppercase;

	color:#aaaaaa;
	margin-bottom:15px;

	border-bottom:1px solid #eeeeee;
	margin-bottom:15px;
	padding-bottom:10px;
}

label{
	text-transform:uppercase;
	font-size:10px;
	font-family:Tahoma,Arial,Sans-serif;
}

textarea{
	color:#404040;
	font-family:Arial,Helvetica,sans-serif;
	font-size:12px;
}

td &gt; button{
	/* A special CSS selector that targets non-IE6 browsers */
	text-indent:8px;
}

.error{
	/* this class is used if JS is disabled */
	background-color:#AB0000;
	color:white;
	font-size:10px;
	font-weight:bold;
	margin-top:10px;
	padding:10px;
	text-transform:uppercase;
	width:300px;
}

#loading{
	/* the loading gif is hidden on page load */
	position:relative;
	bottom:9px;
	visibility:hidden;
}

.tutorial-info{
	color:white;
	text-align:center;
	padding:10px;
	margin-top:10px;
}
[/css]

Обратите внимание на строку 85. Это правило делает кнопки шире, но, к сожалению это плохо выглядит в IE6. Поэтому мы используем специальный CSS-селектор, который игнорируется IE6, но отлично понимают остальные браузеры.

Теперь, все что нам осталось – это PHP.

<a href="http://dreamhelg.ru/wp-content/uploads/2009/11/3.jpg"><img class="aligncenter size-full wp-image-1696" title="3" src="http://dreamhelg.ru/wp-content/uploads/2009/11/3.jpg" alt="3" width="555" height="319" /></a>
<h3>Шаг 4 – PHP</h3>
Сначала давайте рассмотрим код в начале файла <strong>demo.php</strong>

<strong>demo.php</strong>

[php]
session_name(&quot;fancyform&quot;);
session_start();

$_SESSION['n1'] = rand(1,20);	/* generate the first number */
$_SESSION['n2'] = rand(1,20);	/* then the second */
$_SESSION['expect'] = $_SESSION['n1']+$_SESSION['n2'];	/* the expected result */

/* the code below is used if JS has been disabled by the user */
$str='';
if($_SESSION['errStr'])	/* if submit.php returns an error string in the session array */
{
	$str='&lt;div class=&quot;error&quot;&gt;'.$_SESSION['errStr'].'&lt;/div&gt;';
	unset($_SESSION['errStr']);	/* will be shown only once */
}

$success='';
if($_SESSION['sent'])
{
	$success='&lt;h1&gt;Thank you!&lt;/h1&gt;';	/* the success message */

	$css='&lt;style type=&quot;text/css&quot;&gt;#contact-form{display:none;}&lt;/style&gt;';
	/* a special CSS rule that hides our form */

	unset($_SESSION['sent']);
}
[/php]

Как видите, мы используем массив <strong>$_SESSION</strong> для хранения двух случайных чисел и ожидаемого результата. Это будет использоваться в дальнейшем, файлом <strong>submit.php</strong>, для подтверждения того, что капча решена.

Другой интересный момент находится в строке 21, где мы описываем простой CSS-класс. Фактически здесь, мы скрываем форму, и отображаем сообщение об успешной отправке, если у пользователя отключен JS.

<strong>submit.php</strong>

[php]
require &quot;phpmailer/class.phpmailer.php&quot;;

session_name(&quot;fancyform&quot;);	/* starting the session */
session_start();

foreach($_POST as $k=&gt;$v)
{
	/* if magic_quotes is enabled, strip the post array */
	if(ini_get('magic_quotes_gpc'))
	$_POST[$k]=stripslashes($_POST[$k]);

	$_POST[$k]=htmlspecialchars(strip_tags($_POST[$k]));
	/* escape the special chars */
}

$err = array();

/* some error checks */
if(!checkLen('name'))
	$err[]='The name field is too short or empty!';

if(!checkLen('email'))
	$err[]='The email field is too short or empty!';
else if(!checkEmail($_POST['email']))
	$err[]='Your email is not valid!';

if(!checkLen('subject'))
	$err[]='You have not selected a subject!';

if(!checkLen('message'))
	$err[]='The message field is too short or empty!';

/* compare the received captcha code to the one in the session array */
if((int)$_POST['captcha'] != $_SESSION['expect'])
	$err[]='The captcha code is wrong!';

/* if there are errors */
if(count($err))
{
	/* if the form was submitted via AJAX */
	if($_POST['ajax'])
	{
		echo '-1';
	}

	/* else fill the SESSION array and redirect back to the form */
	else if($_SERVER['HTTP_REFERER'])
	{
		$_SESSION['errStr'] = implode('&lt;br /&gt;',$err);
		$_SESSION['post']=$_POST;

		header('Location: '.$_SERVER['HTTP_REFERER']);
	}

	exit;
}

/* the email body */
$msg=
'Name:	'.$_POST['name'].'&lt;br /&gt;
Email:	'.$_POST['email'].'&lt;br /&gt;
IP:	'.$_SERVER['REMOTE_ADDR'].'&lt;br /&gt;&lt;br /&gt;

Message:&lt;br /&gt;&lt;br /&gt;

'.nl2br($_POST['message']).'

';

$mail = new PHPMailer();	/* using PHPMailer */
$mail-&gt;IsMail();

$mail-&gt;AddReplyTo($_POST['email'], $_POST['name']);
$mail-&gt;AddAddress($emailAddress);
$mail-&gt;SetFrom($_POST['email'], $_POST['name']);
$mail-&gt;Subject = &quot;A new &quot;.mb_strtolower($_POST['subject']).&quot; from &quot;.$_POST['name'].&quot; | contact form feedback&quot;;

$mail-&gt;MsgHTML($msg);

$mail-&gt;Send();

unset($_SESSION['post']);	/* unsetting */

/* the form was successfully sent */
if($_POST['ajax'])
{
	echo '1';
}
else
{
	$_SESSION['sent']=1;

	if($_SERVER['HTTP_REFERER'])
		header('Location: '.$_SERVER['HTTP_REFERER']);

	exit;
}

/* some helpful functions */
function checkLen($str,$len=2)
{
	return isset($_POST[$str]) &amp;&amp; mb_strlen(strip_tags($_POST[$str]),&quot;utf-8&quot;) &gt; $len;
}

function checkEmail($str)
{
	return preg_match(&quot;/^[\.A-z0-9_\-\+]+[@][A-z0-9_\-]+([.][A-z0-9_\-]+)+[A-z]{1,4}$/&quot;, $str);
}
[/php]

Обратите внимание как мы проверяем переменную <strong>$_POST[‘ajax’]</strong> на предмет установки и правильной работы. Как вы наверное помните, мы устанавливаем ее ранее, в файле <strong>script.js</strong>, для определения используется ли аякс для извлечения данных.

Две переменные массива <strong>$_SESSION</strong> <strong>errStr</strong> и <strong>post</strong> используются для совместного использования данных между формой и файлом <strong>submit.php</strong>, в случае выключенного JS. Здесь переменная <strong>post</strong> содержит отправленный нами массив <strong>$_POST</strong> и используется для заполнения полей формы, после того как пользователь перенаправляется обратно.

На этом работа над нашей формой обратной связи подошла к концу.

Пример рабочий, за исключением одного маленького недоразумения. Плагин formValidation, создан с целью проводить валидацию только английских символов, так что если вы попытаетесь написать имя по-русски, он выдаст ошибку о том, что нужно вводить только буквы. К счастью это решается путем замены регулярного выражения в файле <strong>jquery.validationEngine.js</strong>. Найдите строчки:

[javascript]
&quot;onlyLetter&quot;:{
	&quot;regex&quot;:&quot;/^[a-zA-Z\ \']+$/&quot;,
}	
[/javascript]

и замените на следующую:

[javascript]
&quot;onlyLetter&quot;:{
	&quot;regex&quot;:&quot;/^[a-zA-Zа-яА-Я' ]+$/&quot;,
}	
[/javascript]

После этого, скрипт перестанет игнорировать русские символы.

<a href="http://dreamhelg.ru/wp-content/uploads/2009/11/contactform.zip">Скачать архив с примером</a>.

<strong>В связи с бесконечными вопросами, специально, отдельно сообщаю: настройка адреса email на который производится отправка писем, находится в файле submit.php, в самом начале файла, выглядит вот так:
</strong>
[php]
/* config start */

$emailAddress = '';

/* config end */
[/php]

Перевод статьи "<a href="http://tutorialzine.com/2009/09/fancy-contact-form/">A Fancy AJAX Contact Form</a>", автор <strong>Martin</strong>]]></description>
		<wfw:commentRss>http://dreamhelg.ru/2009/11/fancy-ajax-contact-form/feed/</wfw:commentRss>
		<slash:comments>92</slash:comments>
		</item>
		<item>
		<title>Решение для очень длинных выпадающих меню</title>
		<link>http://dreamhelg.ru/2009/10/long-dropdowns-solutions/</link>
		<comments>http://dreamhelg.ru/2009/10/long-dropdowns-solutions/#comments</comments>
		<pubDate>Thu, 29 Oct 2009 05:05:30 +0000</pubDate>
		<dc:creator>dreamhelg</dc:creator>
				<category><![CDATA[верстка]]></category>
		<category><![CDATA[общая]]></category>
		<category><![CDATA[jquery]]></category>
		<category><![CDATA[меню]]></category>
		<category><![CDATA[навигация]]></category>

		<guid isPermaLink="false">http://dreamhelg.ru/?p=1670</guid>
		<description><![CDATA[<p><img width="200" height="169" src="http://dreamhelg.ru/wp-content/uploads/2009/10/home1.jpg" class="attachment-200x200 wp-post-image" alt="home" title="home" /></p>Мне нравится давать статьям точные заголовки, но в данном случае, правильно было бы сказать *<strong>возможное</strong>* решение для очень длинного, выпадающего меню. Проблема с такими меню состоит в том, что выпадающий список может выйти за пределы самой веб-страницы, то есть ниже видимой области окна браузера. Так, что для доступа к нижним пунктам меню, вам понадобится прокручивать страницу до нужного пункта.<span id="more-1670"></span>

Для пользователей, имеющих специальное колесо прокрутки у мыши, это не большая проблема. Для тех же, у кого нет такой полезной функциональности, длинное выпадающее меню станет совершенно неработоспособным, потому что для прокрутки окна, им придется использовать полосу прокрутки браузера, для чего придется отвести мышь от меню, в связи с чем, меню, конечно же, закроется.

Но есть очень простое решение для этого. Прежде чем мы начнем, взгляните на <a href="http://css-tricks.com/examples/LongDropdowns/">результат</a>.

Впервые, я увидел эту идею на странице аккаунта, на сайте Media Temple. У них есть выпадающее меню для «Доменов», в котором перечислены все ваши домены, находящиеся у них на хостинге. Это может быть очень длинный список. Но, Media Temple применили специальную технику – при прокручивании окна, меню также прокручивается в ускоренном режиме.

<img class="aligncenter size-full wp-image-1671" title="mt-below-fold" src="http://dreamhelg.ru/wp-content/uploads/2009/10/mt-below-fold.jpg" alt="mt-below-fold" width="570" height="322" />

И конечно, поскольку я делал скриншот, то обратил внимание, что замечательное решение, которое они так расхваливали, оказалось не таким уж хорошим. Это заставило меня задуматься, какие именно проблемы у них возникают с этим меню, так что давайте смотреть вместе. Далее представлена визуализация идеи:

<img class="aligncenter size-full wp-image-1672" title="visual-long-dropdowns" src="http://dreamhelg.ru/wp-content/uploads/2009/10/visual-long-dropdowns.jpg" alt="visual-long-dropdowns" width="570" height="355" />
<h3>JQuery делает это мгновенно</h3>
Я выложу весь код здесь, просто для справки. Код сопровождают комментарии, так что понять его будет легко. Он насчитывает 60 строк, но не пугайтесь, что это слишком много, весь код очень простой.
<ol>
	<li>Устанавливаем максимальную высоту выпадающего меню</li>
	<li>При наведении открываем дочернее меню</li>
	<li>Рассчитываем коэффициент скорости, основанный на высоте дочернего меню</li>
	<li>Отслеживаем движение мыши в меню</li>
	<li>Прокручиваем меню вместе с движением мыши, основываясь на коэффициенте</li>
	<li>При покидании мыши, закрываем меню</li>
</ol>

[javascript]
var maxHeight = 400;

$(function(){

    $(&quot;.dropdown &gt; li&quot;).hover(function() {

         var $container = $(this),
             $list = $container.find(&quot;ul&quot;),
             $anchor = $container.find(&quot;a&quot;),
             height = $list.height() * 1.1,     // проверяем, достаточно ли свободного места внизу
             multiplier = height / maxHeight; // необходим для более быстрого движения, если список длиннее

        // сохраняем высоту здесь, так что она восстанавливается при покидании мыши       
$container.data(&quot;origHeight&quot;, $container.height());

        // сохраняем цвет наведения, пока открыто выпадающее меню
        $anchor.addClass(&quot;hover&quot;);

        // проверяем, появился ли список непорседственно под родительским списком
        $list
            .show()
            .css({
                paddingTop: $container.data(&quot;origHeight&quot;)
            });

        // Не применяем анимацию, если список короче максимального
        if (multiplier &gt; 1) {
            $container
                .css({
                    height: maxHeight,
                    overflow: &quot;hidden&quot;
                })
                .mousemove(function(e) {
                    var offset = $container.offset();
                    var relativeY = ((e.pageY - offset.top) * multiplier) - ($container.data(&quot;origHeight&quot;) * multiplier);
                    if (relativeY &gt; $container.data(&quot;origHeight&quot;)) {
                        $list.css(&quot;top&quot;, -relativeY + $container.data(&quot;origHeight&quot;));
                    };
                });
        }

    }, function() {

        var $el = $(this);

        // возвращаем все как было
        $el
            .height($(this).data(&quot;origHeight&quot;))
            .find(&quot;ul&quot;)
            .css({ top: 0 })
            .hide()
            .end()
            .find(&quot;a&quot;)
            .removeClass(&quot;hover&quot;);

    });

    // Добавляем нижнюю стрелку только для тех пунктов, у которых есть дочернее меню
    $(&quot;.dropdown &gt; li:has('ul')&quot;).each(function() {
        $(this).find(&quot;a:first&quot;).append(&quot;&lt;img src='images/down-arrow.png' /&gt;&quot;);
    });

});
[/javascript]

<h3>HTML и CSS</h3>
Я не стал выкладывать здесь HTML и CSS, поскольку они очень простые и не интересные. Вы, в любом случае, можете скачать архив с примером, и посмотреть. Это самый обыкновенный, вложенный, маркированный список, и немного очень простых стилей.
<h3>Тестирование</h3>
Пример тестировался во всех браузерах, вплоть до IE6, меню отлично выглядит и работает везде.

<a href="http://css-tricks.com/examples/LongDropdowns.zip">Скачать архив с примером</a>.

Перевод статьи "<a href="http://css-tricks.com/long-dropdowns-solution/">Solution For Very Long Dropdown Menus</a>", автор <strong>Chris Coyier</strong>]]></description>
		<wfw:commentRss>http://dreamhelg.ru/2009/10/long-dropdowns-solutions/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Интерактивная корзина на основе AJAX, PHP и JQuery</title>
		<link>http://dreamhelg.ru/2009/09/ajax-based-shopping-cart-with-jquery-and-php/</link>
		<comments>http://dreamhelg.ru/2009/09/ajax-based-shopping-cart-with-jquery-and-php/#comments</comments>
		<pubDate>Thu, 24 Sep 2009 06:26:06 +0000</pubDate>
		<dc:creator>dreamhelg</dc:creator>
				<category><![CDATA[общая]]></category>
		<category><![CDATA[переводы]]></category>
		<category><![CDATA[ajax]]></category>
		<category><![CDATA[css]]></category>
		<category><![CDATA[jquery]]></category>
		<category><![CDATA[php]]></category>

		<guid isPermaLink="false">http://dreamhelg.ru/?p=1419</guid>
		<description><![CDATA[<p><img width="171" height="167" src="http://dreamhelg.ru/wp-content/uploads/2009/09/home1.jpg" class="attachment-200x200 wp-post-image" alt="home" title="home" /></p>"Какая корзина? И почему вдруг корзина?" - возможно удивитесь вы, прочитав заголовок. Так вот, корзина самая обычная - та, которую все мы используем, покупая что-нибудь в интернет-магазине. А опубликовать статью о ее создании, я решила по одной, единственной причине - не смогла устоять перед замечательным и красивым решением.

Не верите? можете посмотреть <a href="http://demo.tutorialzine.com/2009/09/shopping-cart-php-jquery/demo.php">результат</a>. А если вам интересно как это делается, читайте далее.<span id="more-1419"></span>

<h3>Вступление</h3>
В этой статье, мы собираемся создать корзину, работающую на основе технологии Ajax. Все товары будут записываться в базу данных MySQL, данные будут обрабатываться с помощью PHP.

JQuery, будет запускать <strong>Ajax</strong> на странице, кроме этого, плагин <strong><a href="http://craigsworks.com/projects/simpletip/">simpletip</a></strong>, добавит всему процессу интерактивности.

Итак, давайте начнем, скачайте демо-файлы, и начинайте чтение.

<h3>Шаг 1 – База данных MySQL</h3>
Если вы хотите получить рабочую демо-версию, вам понадобится выполнить следующий SQL-запрос в панели управления базой данных (то есть в phpMyAdmin). Этот запрос создаст таблицу, и внесет несколько продуктов. Этот код запроса, также доступен в файле table.sql, в демо-файлах.

<strong>table.sql</strong>

[sql]
CREATE TABLE IF NOT EXISTS `internet_shop` (
  `id` int(6) NOT NULL auto_increment,
  `img` varchar(32) collate utf8_unicode_ci NOT NULL default '',
  `name` varchar(64) collate utf8_unicode_ci NOT NULL default '',
  `description` text collate utf8_unicode_ci NOT NULL,
  `price` double NOT NULL default '0',
  PRIMARY KEY  (`id`),
  UNIQUE KEY `img` (`img`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=7 ;

INSERT INTO `internet_shop` VALUES(1, 'iPod.png', 'iPod', 'The original and popular iPod.', 200);
INSERT INTO `internet_shop` VALUES(2, 'iMac.png', 'iMac', 'The iMac computer.', 1200);
INSERT INTO `internet_shop` VALUES(3, 'iPhone.png', 'iPhone', 'This is the new iPhone.', 400);
INSERT INTO `internet_shop` VALUES(4, 'iPod-Shuffle.png', 'iPod Shuffle', 'The new iPod shuffle.', 49);
INSERT INTO `internet_shop` VALUES(5, 'iPod-Nano.png', 'iPod Nano', 'The new iPod Nano.', 99);
INSERT INTO `internet_shop` VALUES(6, 'Apple-TV.png', 'Apple TV', 'The new Apple TV. Buy it now!', 300);
[/sql]

После этого, вам нужно заполнить данные вашей учетной записи MySQL, в файле <strong>connect.php</strong>.

<h3>Шаг 2 – XHTML</h3>
Сначала мы создадим основную разметку.

<strong>demo.php</strong>

[html]
&lt;div id=&quot;main-container&quot;&gt; &lt;!-- основной контент --&gt;	
&lt;div class=&quot;tutorialzine&quot;&gt;	&lt;!-- заголовок --&gt;

&lt;h1&gt;Корзина&lt;/h1&gt;
&lt;h3&gt;Лучшие товары, по лучшим ценам&lt;/h3&gt;
&lt;/div&gt;

&lt;div class=&quot;container&quot;&gt;  &lt;!-- первая секция - товары --&gt;

&lt;span class=&quot;top-label&quot;&gt;
    &lt;span class=&quot;label-txt&quot;&gt;Товары&lt;/span&gt;  &lt;!-- название секции --&gt;
&lt;/span&gt;

&lt;div class=&quot;content-area&quot;&gt;

&lt;div class=&quot;content drag-desired&quot;&gt;

// php-код, который генерирует товары

&lt;div class=&quot;clear&quot;&gt;&lt;/div&gt;   &lt;!-- чистка потока --&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;div class=&quot;bottom-container-border&quot;&gt;	&lt;!-- нижняя часть секции --&gt;
&lt;/div&gt;

&lt;/div&gt;	&lt;!-- окончание секции товаров --&gt;

&lt;div class=&quot;container&quot;&gt;	&lt;!-- вторая секция- корзина--&gt;

&lt;span class=&quot;top-label&quot;&gt;
   &lt;span class=&quot;label-txt&quot;&gt;Корзина&lt;/span&gt;	&lt;!-- название секции --&gt;
&lt;/span&gt;

&lt;div class=&quot;content-area&quot;&gt;
  &lt;div class=&quot;content drop-here&quot;&gt;
         &lt;div id=&quot;cart-icon&quot;&gt;
               &lt;img src=&quot;img/Shoppingcart_128x128.png&quot; alt=&quot;shopping cart&quot; class=&quot;pngfix&quot; width=&quot;128&quot; height=&quot;128&quot; /&gt;	&lt;!-- использование класса pngfix--&gt;

                &lt;img src=&quot;img/ajax_load_2.gif&quot; alt=&quot;loading..&quot; id=&quot;ajax-loader&quot; width=&quot;16&quot; height=&quot;16&quot; /&gt;	&lt;!-- прелоадер - спрятан по умолчанию, и отображается когда работает AJAX --&gt;
    &lt;/div&gt;

&lt;form name=&quot;checkoutForm&quot; method=&quot;post&quot; action=&quot;order.php&quot;&gt;	&lt;!-- форма --&gt;
    &lt;div id=&quot;item-list&quot;&gt;	&lt;!-- в этот блок мы вставим все товары корзины --&gt;

     &lt;/div&gt;
&lt;/form&gt;	&lt;!-- конец формы --&gt;

&lt;div class=&quot;clear&quot;&gt;&lt;/div&gt;	&lt;!-- чистка потока --&gt;

&lt;div id=&quot;total&quot;&gt;&lt;/div&gt;	&lt;!-- здесь расположена общая сумма --&gt;

&lt;div class=&quot;clear&quot;&gt;&lt;/div&gt;	&lt;!-- чистка потока --&gt;

&lt;a href=&quot;&quot; onclick=&quot;document.forms.checkoutForm.submit(); return false;&quot; class=&quot;button&quot;&gt;
	Оформить
&lt;/a&gt;	&lt;!-- кнопка отправки заказа, спрятана по умолчанию. обратите внимание на атрибут onclick --&gt;

&lt;/div&gt;
&lt;/div&gt;

&lt;div class=&quot;bottom-container-border&quot;&gt;	&lt;!-- нижняя часть секции --&gt;
&lt;/div&gt;

&lt;/div&gt;&lt;!-- конец основного контейнера --&gt;
[/html]

Как вы могли заметить, из вышеприведенного кода, мы расположили наш контент в двух основных секциях, полностью идентичных с точки зрения XHTML-разметки. В первой колонке мы отображаем все наши продукты, вторая колонка выступает в качестве корзины.

Ниже, вы можете увидеть детальное представление структуры нашей секции товаров.

<img class="aligncenter size-full wp-image-1433" title="scheme" src="http://dreamhelg.ru/wp-content/uploads/2009/09/scheme.jpg" alt="scheme" width="600" height="460" />

Товары, генерируются с помощью нашего PHP-кода, как можно увидеть в строке 18. Мы разберем это подробнее, через несколько минут. Теперь, давайте взглянем, как мы обработаем XHTML-разметку, для получения финального дизайна.
<h3>Шаг 3 – CSS</h3>
В этот раз, CSS-код получился очень длинный, поэтому я разделил его на две части.

<strong>demo.css</strong>

[css]
body,h1,h2,h3,p,td,quote,small,form,input,ul,li,ol,label{
/* сброс первоначальных стилей, для совместимости браузеров */
	margin:0px;
	padding:0px;
	font-family:Arial, Helvetica, sans-serif;
}

body{
	color:#555555;
	font-size:13px;
	background-color:#282828;
}

.clear{	/*  clear-fix хак для чистки потока от флоатов */
	clear:both;
}

#main-container{	/* это основной контейнер, содержащий две секции */
	width:700px;
	margin:20px auto;
}

.container{	/* основной контейнер для секций контента - товаров и корзины */
	margin-bottom:40px;
}

.top-label{	/* внешний span, включающий в себя название секции*/
	background: url(img/label_bg.png) no-repeat;	/* отображение левой части label_bg.png - широкого изображения с закругленными краями */
	display:inline-block;
	margin-left:20px;
	position:relative;
	margin-bottom:-15px;	/* название секции прилегает к верхнему краю секции товаров*/
}

.label-txt{	/* внутренний span - обведен красной рамкой, на рисунке выше*/
	background: url(img/label_bg.png) no-repeat top right;	/* отображение правой части изображения label_bg.png */
	display:inline-block;
	font-size:10px;
	height:36px;
	margin-left:10px;	/* слева оставлено пустое пространство, чтобы отображить фон внешнего span'а */
	padding:12px 15px 0 5px;
	text-transform:uppercase;
}

.content-area{	/* Верхняя часть изображения с закругленными краями, смотрите на рисунке выше */
	background:url(img/container_top.png) no-repeat #fcfcfc;
	padding:15px 20px 0 20px;
}

.content{	/* общий отступ для обеих секций */
	padding:10px;
}

.drag-desired{	/* индивидуально назначенные свойства */
	background:url(img/drag_desired_label.png) no-repeat top right;
	padding:20px;
}

.drop-here{	/* не предназначено для других секций */
	background:url(img/drop_here_label.png) no-repeat top right;
}

.bottom-container-border{	/* нижняя часть закругленной картинки, которая завершает секцию */
	background:url(img/container_bottom.png) no-repeat;
	height:14px;
}

.product{	/* стили для товаров */
	border:2px solid #F5F5F5;
	float:left;
	margin:15px;
	padding:10px;
}

.product img{
	cursor:move;
}

p.descr{
	padding:5px 0;
}

small{
	display:block;
	margin-top:4px;
}

.tooltip{	/* тултипы, которые создаются с помощью плагина simpletip */
	position: absolute;
	top: 0;
	left: 0;
	z-index: 3;
	display: none;

	background-color:#666666;
	border:1px solid #666666;
	color:#fcfcfc;

	padding:10px;

	-moz-border-radius:12px;	/* закругленные углы */
	-khtml-border-radius: 12px;
	-webkit-border-radius: 12px;
	border-radius:12px;
}
[/css]

Обратите внимание на класс tooltip. Он создается автоматически, <strong>плагином simpletip</strong>, но не имеет никаких стилей, по умолчанию. Вот почему, мы назначаем ему стиль здесь. Я использовал свойство <strong>border-radius</strong>, которое еще не поддерживается всеми браузерами, но не принесет сильного ущерба, тем, кто его не поддерживает.

Теперь, давайте взглянем на CSS-стили, для секции корзины.

[css]
#cart-icon{	/* div, который содержит иконку корзины */
	width:128px;
	float:left;
	position:relative;	/* устанавливаем относительное позиционирование, так, чтобы ajax-загрузчик позиционировался по отношению к div*/
}

#ajax-loader{
	position:absolute;	/* абсолютное позиционирование располагает элемент на странице, относительно его родительского элемента, которому назначено относительное позиционирование */
	top:0px;
	left:0px;
	visibility:hidden;
}

#item-list{	/* содержимое корзины будет расположено в этом блоке */
	float:left;
	width:490px;
	margin-left:20px;
	padding-top:15px;
}

a.remove,a.remove:visited{	/* Удаление ссылки */
	color:red;
	font-size:10px;
	text-transform:uppercase;
}

#total{	/* блок, с общей суммой */
	clear:both;
	float:right;
	font-size:10px;
	font-weight:bold;
	padding:10px 12px;
	text-transform:uppercase;
}

#item-list table{	/* каждый товар в корзине, позиционируется внутри блока item-list*/
	background-color:#F7F7F7;
	border:1px solid #EFEFEF;
	margin-top:5px;
	padding:4px;
}

a.button,a.button:visited{	/* Кнопка оформления заказа */
	display:none;

	height:29px;
	width:136px;

	padding-top:15px;
	margin:0 auto;
	overflow:hidden;

	color:white;
	font-size:12px;
	font-weight:bold;
	text-align:center;
	text-transform:uppercase;

	background:url(img/button.png) no-repeat center top;	/* отображаем только верхнюю часть фонового изображения */
}

a.button:hover{
	background-position:bottom;	/* при наведении, мы показываем нижнюю часть фоногового изображения */
	text-decoration:none;
}

/* Несколько менее интересных стилей */

a, a:visited {
	color:#00BBFF;
	text-decoration:none;
	outline:none;
}

a:hover{
	text-decoration:underline;
}

h1{
	font-size:28px;
	font-weight:bold;
	font-family:&quot;Trebuchet MS&quot;,Arial, Helvetica, sans-serif;
}

h2{
	font-weight:normal;
	font-size:20px;

	color:#666666;
	text-indent:30px;
	margin:20px 0;
}

.tutorialzine h1{
	color:white;
	margin-bottom:10px;
	font-size:48px;
}

.tutorialzine h3{
	color:#F5F5F5;
	font-size:10px;
	font-weight:bold;
	margin-bottom:30px;
	text-transform:uppercase;
}

.tutorial-info{
	color:white;
	text-align:center;
	padding:10px;
	margin-top:-20px;
}
[/css]

Любой разработчик скажет нам, что здесь мы кое-что упустили. Как вы, наверное, догадались – специальные процедуры лечения для IE6.

Лично я, планирую в скором времени прекратить поддержку IE6 во всех своих проектах – если бы не IE6, вышеприведенный код, был бы на четверть короче, и мне не пришлось бы тратить столько времени на его отладку.

Но, в любом случае, вот, что нам нужно, чтобы IE6 понимал, то, что мы от него хотим:

<strong>demo.php</strong>

[html]
&lt;!--[if lt IE 7]&gt;
&lt;style type=&quot;text/css&quot;&gt;
	.pngfix { behavior: url(pngfix/iepngfix.htc);}	/* this is a special htc file that fixes the IE6 transparency issues */
	.tooltip{width:200px;};	/* provide a default width for the tooltips */
&lt;/style&gt;
&lt;![endif]--&gt;
[/html]

Отлично. Теперь, давайте взглянем на окончательный вариант PHP.

<img class="aligncenter size-full wp-image-1434" title="cart" src="http://dreamhelg.ru/wp-content/uploads/2009/09/cart.jpg" alt="cart" width="588" height="262" />

<h3>Шаг 4 – PHP</h3>
Мы используем PHP несколькими способами и в разных местах. Для начала, давайте посмотрим, как формируется список товаров на главной странице.

<strong>demo.php</strong>

[php]
&lt;?php
	$result = mysql_query(&quot;SELECT * FROM internet_shop&quot;);	// выбираем все товары
		while($row=mysql_fetch_assoc($result))
		{
			echo '&lt;div class=&quot;product&quot;&gt;&lt;img src=&quot;img/products/'.$row['img'].'&quot; alt=&quot;'.htmlspecialchars($row['name']).'&quot; width=&quot;128&quot; height=&quot;128&quot; class=&quot;pngfix&quot; /&gt;&lt;/div&gt;';

?&gt;
[/php]

Далее, в файле tips.php, мы снова используем PHP, для того чтобы передать в качестве параметра имя файла картинки, проверяя какой товар ассоциируется с этим изображением, и выводим подсказку в виде HTML. Это позднее, будет использоваться плагином simpletip.

<strong>ajax/tips.php</strong>

[php]
&lt;?php
define('INCLUDE_CHECK',1);
require &quot;../connect.php&quot;;

if(!$_POST['img']) die(&quot;Нет таких товаров!&quot;);

$img=mysql_real_escape_string(end(explode('/',$_POST['img'])));

$row=mysql_fetch_assoc(mysql_query(&quot;SELECT * FROM internet_shop WHERE img='&quot;.$img.&quot;'&quot;));

if(!$row) die(&quot;Нет таких товаров!&quot;);

echo '&lt;strong&gt;'.$row['name'].'&lt;/strong&gt;
&lt;p class=&quot;descr&quot;&gt;'.$row['description'].'&lt;/p&gt;
&lt;strong&gt;price: $'.$row['price'].'&lt;/strong&gt;
&lt;small&gt;Для того, чтобы купить, просто перетащите его в коризну&lt;/small&gt;';

 ;?&gt;
[/php]

Кроме этого, мы используем PHP для получения данных, необходимых для добавления товаров в корзину. Разница в том, что в этот раз мы получаем данные в качестве JSON (javascript-объекта).

<strong>ajax/addtocart.php</strong>

[php]
&lt;?php
define('INCLUDE_CHECK',1);
require &quot;../connect.php&quot;;

if(!$_POST['img']) die(&quot;Нет таких товаров!&quot;);

$img=mysql_real_escape_string(end(explode('/',$_POST['img'])));
$row=mysql_fetch_assoc(mysql_query(&quot;SELECT * FROM internet_shop WHERE img='&quot;.$img.&quot;'&quot;));

echo '{status:1,id:'.$row['id'].',price:'.$row['price'].',txt:\'\
\
&lt;table width=&quot;100%&quot; id=&quot;table_'.$row['id'].'&quot;&gt;\
&lt;tr&gt;\
&lt;td width=&quot;60%&quot;&gt;'.$row['name'].'&lt;/td&gt;\
&lt;td width=&quot;10%&quot;&gt;$'.$row['price'].'&lt;/td&gt;\
&lt;td width=&quot;15%&quot;&gt;&lt;select name=&quot;'.$row['id'].'_cnt&quot; id=&quot;'.$row['id'].'_cnt&quot; onchange=&quot;change('.$row['id'].');&quot;&gt;\
&lt;option value=&quot;1&quot;&gt;1&lt;/option&gt;\
&lt;option value=&quot;2&quot;&gt;2&lt;/option&gt;\
&lt;option value=&quot;3&quot;&gt;3&lt;/option&gt;&lt;/slect&gt;\
\
&lt;/td&gt;\
&lt;td width=&quot;15%&quot;&gt;&lt;a href=&quot;#&quot; onclick=&quot;remove('.$row['id'].');return false;&quot; class=&quot;remove&quot;&gt;удалить&lt;/a&gt;&lt;/td&gt;\
&lt;/tr&gt;\
&lt;/table&gt;\'}';

?&gt;
[/php]

Полученный объект имеет свойства status, id, price и txt. Все они используются AJAX-функциями, как вы скоро убедитесь.

Обратите внимание на то, что я заканчиваю каждую строку обратным слешем. Это сделано потому, что JavaScript не поддерживает множественные строчки.

И последний файл, в котором мы используем PHP – это order.php, который используется для обработки заказа. Сейчас, он просто выводит ваш заказ. Мы можете изменить его, включив форму обратной связи, функции платежных систем, или что-нибудь еще, что позволит превратить этот пример в функциональный онлайн-магазин.

<strong>order.php</strong>

[php]
&lt;?php

define('INCLUDE_CHECK',1);
require &quot;connect.php&quot;;

if(!$_POST)	// если данные не были отправлены в форму
{
	if($_SERVER['HTTP_REFERER'])	// редирект
	header('Location : '.$_SERVER['HTTP_REFERER']);
	exit;	// и выход
}

?&gt;

&lt;!-- XHTML код.. --&gt;

&lt;?php		
$cnt = array();
$products = array();
$total = 0;
foreach($_POST as $key=&gt;$value)
{
	$key=(int)str_replace('_cnt','',$key);
	$products[]=$key;	// запись ID товара в массив
	$cnt[$key]=$value;	// создание пары ключ-значение, где для каждого ID товара есть соответствующее значение количества товаров
 }

$result = mysql_query(&quot;SELECT * FROM internet_shop WHERE id IN(&quot;.join($products,',').&quot;)&quot;);	// выбор всех товаров с помощью функции IN()

if(!mysql_num_rows($result))	// товары не найдены
{
	echo '&lt;h1&gt;При оформлении заказа возникла ошибка!&lt;/h1&gt;';
}
else
{
	echo '&lt;h1&gt;Ваш заказ:&lt;/h1&gt;';
	while($row=mysql_fetch_assoc($result))
	{
		echo '&lt;h2&gt;'.$cnt[$row['id']].' x '.$row['name'].'&lt;/h2&gt;';
		$total+=$cnt[$row['id']]*$row['price'];
	}

	echo '&lt;h1&gt;Всего: $'.$total.'&lt;/h1&gt;';
}

?&gt;

[/php]

На этом, часть PHP закончена. Все, что нам осталось сделать, это добавить немного магии jQuery.

<img class="aligncenter size-full wp-image-1435" title="checkout" src="http://dreamhelg.ru/wp-content/uploads/2009/09/checkout.jpg" alt="checkout" width="585" height="268" />
<h3>Шаг 5 – JQuery</h3>
Поскольку мы будем использовать jQuery в полном объеме, нам понадобится подключить библиотеку jQuery UI, так же, как и основную.

[html]
&lt;script type=&quot;text/javascript&quot; src=&quot;http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.2/jquery-ui.min.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;simpletip/jquery.simpletip-1.3.1.pack.js&quot;&gt;&lt;/script&gt; &lt;!-- плагин к jQuery simpletip --&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;script.js&quot;&gt;&lt;/script&gt; &lt;!-- наш script.js --&gt;
[/html]

Теперь, мы можем продолжить с нашим скриптом.

<strong>script.js</strong>

[javascript]
var purchased=new Array();	//массив, содержащий все товары, которые мы приобрели
var totalprice=0;	//цена

$(document).ready(function(){

$('.product').simpletip({	//используем плагин simpletip

	offset:[40,0],
	content:'&lt;img style=&quot;margin:10px;&quot; src=&quot;img/ajax_load.gif&quot; alt=&quot;loading&quot; /&gt;',	// контент по умолчанию
	onShow: function(){

		var param = this.getParent().find('img').attr('src');
		// fix для IE6
		if($.browser.msie &amp;&amp; $.browser.version=='6.0')
		{
			param = this.getParent().find('img').attr('style').match(/src=\&quot;([^\&quot;]+)\&quot;/);
			param = param[1];
		}

		// после того как отображена подсказка, загружаем файл tips.php и передаем название изображения в качестве параметра
		this.load('ajax/tips.php',{img:param});
	} 

});

$(&quot;.product img&quot;).draggable({	// разрешаем перетаскивание картинок товаров

containment: 'document',
opacity: 0.6,
revert: 'invalid',
helper: 'clone',
zIndex: 100

});

$(&quot;div.content.drop-here&quot;).droppable({	// разрешаем выгружать товары в корзину

		drop:
			function(e, ui)
			{
				var param = $(ui.draggable).attr('src');
				// IE6 fix
				if($.browser.msie &amp;&amp; $.browser.version=='6.0')
				{
					param = $(ui.draggable).attr('style').match(/src=\&quot;([^\&quot;]+)\&quot;/);
					param = param[1];
				}

				addlist(param);	// специальная функция addlist - смотрите ниже
			}

});


});
[/javascript]

Основная идея в том, что мы используем атрибут изображения <strong>src</strong>, в качестве уникального ключа, который передается PHP. Каждый товар в базе данных имеет поле c именем файла, что позволяет нам найти нужный товар по его картинке.

Этот блок кода выполняется после того как страница полностью загрузилась, так, что мы уверены, что все элементы на странице инициализированы.

Ниже представлена вторая часть кода script.js.

[javascript]
function addlist(param)
{
	// функция addlist добавляет товар в корзину

	$.ajax({	// посылаем ajax-request в addtocart.php
	type: &quot;POST&quot;,
	url: &quot;ajax/addtocart.php&quot;,
	data: 'img='+encodeURIComponent(param),	// картинка товара в качестве параметра
	dataType: 'json',	// ждем json
	beforeSend: function(x){$('#ajax-loader').css('visibility','visible');},	// отображаем прелоадер
	success: function(msg){

		$('#ajax-loader').css('visibility','hidden');	// прячем прелоадер
		if(parseInt(msg.status)!=1)
		{
			return false;	// если обнаружена ошибка, возвращаем false
		}
		else
		{
			var check=false;
			var cnt = false;

			for(var i=0; i&lt;purchased.length;i++)
			{
				if(purchased[i].id==msg.id)	// ищем, не покупали ли мы этот товар ранее
				{
					check=true;
					cnt=purchased[i].cnt;

					break;
				}
			}

			if(!cnt)	// если еще не покупали, или удалили из покупок, то вставляем в корзину
				$('#item-list').append(msg.txt);

			if(!check)	// если еще не купили, вставляем в массив покупок
			{
				purchased.push({id:msg.id,cnt:1,price:msg.price});
			}

			else	// иначе, если купили
			{
				if(cnt&gt;=3) return false;	// больше 3 товаров

				purchased[i].cnt++;
				$('#'+msg.id+'_cnt').val(purchased[i].cnt);	// обновляем select box
			}

			totalprice+=msg.price;	// пересчитываем стоимость recalculate the price
			update_total();	// обновляем блок общей стоимости
		}

		$('.tooltip').hide();	// прячем подсказку (иногда она остается после перетаскивания)

	}
	});
}

function findpos(id)	// полезная функция, помогающая найти поизицию товара в массиве, возвращаяя ее
{
	for(var i=0; i&lt;purchased.length;i++)
	{
		if(purchased[i].id==id)
			return i;
	}

	return false;
}

function remove(id)	// удаляем товары из корзины
{
	var i=findpos(id);	// находим их позицию в массиве

	totalprice-=purchased[i].price*purchased[i].cnt;	// пересчитываем стоимость
	purchased[i].cnt = 0;	// сбрасываем счетчик

	$('#table_'+id).remove();	// удаляем их из таблицы
	update_total();	// обновляем счетчик общей стоимости на странице
}

function change(id)	// вызывается когда мы изменям количество товаров в селекте
{
	var i=findpos(id);

	totalprice+=(parseInt($('#'+id+'_cnt').val())-purchased[i].cnt)*purchased[i].price;

	purchased[i].cnt=parseInt($('#'+id+'_cnt').val());
	update_total();
}

function update_total()	// функция, которая обновляет блок с общей стоимостью на странице
{
	if(totalprice)
	{
		$('#total').html('всего: $'+totalprice); // Если мы купили что-нибудь, отобразить блок с общей стоимостью и кнопку оформления
		$('a.button').css('display','block');
	}
	else	// прячем их
	{
		$('#total').html('');
		$('a.button').hide();
	}
}
[/javascript]

В нескольких местах этого кода, мы используем <strong>id</strong> для указания товара. ID – это уникальный идентификатор, который создается базой данных MySQL один раз, когда мы вносим новую позицию.

Он передается AJAX-запросом, и нам необходимо перевести его в index-позицию нашего массива товаров для дальнейшего использования, все это осуществляет функция <strong>findpos()</strong>.

Теперь, наша интерактивная корзина готова.

<a href="http://dreamhelg.ru/wp-content/uploads/2009/09/cart.zip">Скачать архив с примером.</a>

Перевод статьи "<a href="http://tutorialzine.com/2009/09/shopping-cart-php-jquery/">An AJAX Based Shopping Cart with PHP, CSS &amp; jQuery</a>", автор <strong>Martin</strong>]]></description>
		<wfw:commentRss>http://dreamhelg.ru/2009/09/ajax-based-shopping-cart-with-jquery-and-php/feed/</wfw:commentRss>
		<slash:comments>18</slash:comments>
		</item>
	</channel>
</rss>

