<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0" xml:base="http://www.aether.ru">
<channel>
 <title>AETHER</title>
 <link>http://www.aether.ru</link>
 <description>Aether.ru — это личный сайт веб-разработчика Александра Шабуневича. Здесь я пишу о веб-разработке и других интересных мне темах.</description>
 <language>ru</language>
<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" href="http://feeds.feedburner.com/EyeBeholder" type="application/rss+xml" /><feedburner:emailServiceId xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0">EyeBeholder</feedburner:emailServiceId><feedburner:feedburnerHostname xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0">http://feedburner.google.com</feedburner:feedburnerHostname><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com" /><item>
 <title>Геолокация на веб-сайтах</title>
 <link>http://www.aether.ru/blog/2009/06/23/geolocation</link>
 <description>&lt;!--break--&gt;
&lt;p&gt;Шел я пару дней назад по улице и размышлял о том, как можно улучшить один веб-сервис, предназначенный для поиска ближайших пунктов обслуживания. Обычно такие сервисы показывают карту, на которой при помощи различных фильтров надо установить свое местоположение (например, станцию метро), а сервис вам покажет ближайшие точки. С десктопными клиентами проблем нет — там можно и все разом выложить, а вот с мобильными устройствами желательно обращаться поэкономнее. В идеале была бы такая ситуация: пользователь заходит на сайт и нажимает кнопку «Найти в радиусе 500 метров от меня». А так как во многих современных устройствах (iPhone, HTC Touch и прочие нокии) сейчас встроен GPS-приемник, такая задача должна решаться просто.&lt;/p&gt;

&lt;p&gt;Оказалось, что в этом направлении уже пару лет ведется активная работа, есть даже черновик &lt;a href="http://dev.w3.org/geo/api/spec-source.html" rel="external"&gt;спецификации W3C&lt;/a&gt;, описывающий подобные взаимодействия. Да и программная реализация существует на всех популярных платформах.&lt;/p&gt;


&lt;h2&gt;Порядок определения&lt;/h2&gt;

&lt;p&gt;Есть три основных способа определить местонахождение (координаты) клиента (расположены по степени уменьшения точности определения):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GPS в аппарате (высокая точность — в пределах десятка метров)&lt;/li&gt;
&lt;li&gt;Координаты по Wi-Fi точке доступа (разброс от сотен метров до нескольких километров)&lt;/li&gt;
&lt;li&gt;Город по IP (километры)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Таким образом, при определении координат, необходимо идти по этому списку сверху вниз — если клиент поддерживает GPS — использовать его и т.д.&lt;/p&gt;


&lt;h2&gt;Технологическое воплощение&lt;/h2&gt;

&lt;p&gt;Пока, чуть ли не единственным (ну еще HTC Dream a.k.a. гуглофон) аппаратом, который из коробки поддерживает геолокацию является iPhone с прошивкой 3.0. Если вы уже обновились на новую прошивку, то достаточно сделать простой запрос в виде javascript-кода:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;navigator.geolocation.getCurrentPosition(foundLocation, noLocation);&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;и вы получите доступ (после соответствующего разрешения пользователя, конечно же) к координатам клиента. В этой функции первым параметром является callback, срабатывающий при удачном определении координат, а вторым — срабатывающий при ошибке. Соответственно, в первой функции вы получаете доступ к объекту &lt;code&gt;position&lt;/code&gt;, содержащему свойства &lt;code&gt;position.coords.latitude&lt;/code&gt; и &lt;code&gt;position.coords.longitude&lt;/code&gt;, которые вы сможете использовать в своих скриптах (например, для выборки ближайших объектов).&lt;/p&gt;

&lt;p&gt;Что делать если ваши клиенты не пользуются айфоном? Выход есть, хотя пока что это своего рода экзотика.&lt;/p&gt;

&lt;p class="excerpt"&gt;Но у меня на маке плагин geode глючит, и Firefox вываливается с ошибкой&lt;/p&gt;

&lt;p&gt;Во-первых, следующий релиз Firefox 3.5 &lt;a href="http://ru.www.mozilla.com/ru/firefox/geolocation/" rel="external"&gt;будет содержать&lt;/a&gt; эту же функциональность в ядре. Но уже сейчас можно поставить специальный &lt;a href="https://people.mozilla.com/~dolske/dist/geode/geode-latest.xpi" rel="external"&gt;плагин Geode&lt;/a&gt;, который использует беспроводные сети для попытки определить координаты. Во-вторых, можно установить &lt;a href="http://code.google.com/intl/ru/apis/gears/api_geolocation.html" rel="external"&gt;Google Gears&lt;/a&gt;, который существует для &lt;a href="http://code.google.com/intl/ru/apis/gears/gears_faq.html#supportedSystems" rel="external"&gt;кучи платформ&lt;/a&gt; (например, для Opera mobile на WM6). Этот плагин использует не только Wi-Fi, но и GPS (если он есть в устройстве, конечно же).&lt;/p&gt;

&lt;p&gt;Понятно, что вряд ли кто-то будет специально ставить непонятные плагины, позволяющие что-то там определять (тут еще встает вопрос privacy). Но я уверен, что в самом ближайшем будущем поддержка геолокации по умолчанию появится в большинстве мобильных устройств на платформах WM, symbian (или уже?) и прочих. Особенно это актуально для устройств с GPS, который дает наиболее точные результаты.&lt;/p&gt;

&lt;p&gt;Если нет ни GPS, ни воможности определить координаты по Wi-Fi, то в качестве первого приближения стоит определить хотя бы город посетителя. Сделать это можно средствами специальных баз данных (например, бесплатной &lt;a href="http://www.maxmind.com/app/geolitecity" rel="external"&gt;MaxMind Geo City lite&lt;/a&gt;) или воспользоваться сервисом от вездесущего гугла — &lt;a href="http://code.google.com/intl/ru/apis/ajax/documentation/#ClientLocation" rel="external"&gt;AJAX API&lt;/a&gt;. Последний позволяет определять координаты по IP прямо из javascript-кода, не прибегая к серверным языкам.&lt;/p&gt;


&lt;h2&gt;Рабочий пример&lt;/h2&gt;

&lt;p class="excerpt"&gt;Пример рекомендуется смотреть на айфоне с прошивкой 3.0&lt;/p&gt;

&lt;p&gt;Я написал небольшой тест-драйв-скрипт, который демонстрирует все описанные в статье технологии: сначала пытается использовать встроенные возможности браузера (для iPhone или Firefox с плагином), затем пробует Google Gears, а если и это не проходит, то определяет город по IP. Результатом должна быть карта, центрированная по вашему местоположению.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="/example/geo"&gt;Посмотреть пример&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;


&lt;h2&gt;Ссылки по теме&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://google-code-updates.blogspot.com/2008/08/two-new-ways-to-location-enable-your.html" rel="external"&gt;Two new ways to location-enable your web apps&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.webmonkey.com/tutorial/Track_User_Geolocation_With_JavaScript" rel="external"&gt;Track User Geolocation With JavaScript&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://ajaxian.com/archives/navigatorgeolocation-using-the-w3c-geolocation-api-today" rel="external"&gt;navigator.geolocation: Using the W3C Geolocation API today&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/EyeBeholder?a=HFnWSkfujW8:_LoZaIoTVnA:D7DqB2pKExk"&gt;&lt;img src="http://feeds.feedburner.com/~ff/EyeBeholder?i=HFnWSkfujW8:_LoZaIoTVnA:D7DqB2pKExk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/EyeBeholder?a=HFnWSkfujW8:_LoZaIoTVnA:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/EyeBeholder?i=HFnWSkfujW8:_LoZaIoTVnA:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/EyeBeholder?a=HFnWSkfujW8:_LoZaIoTVnA:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/EyeBeholder?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</description>
 <comments>http://www.aether.ru/blog/2009/06/23/geolocation#comments</comments>
 <category domain="http://www.aether.ru/tags/iphone">iphone</category>
 <category domain="http://www.aether.ru/tags/javascript">Javascript</category>
 <category domain="http://www.aether.ru/tags/browsers">Браузеры</category>
 <category domain="http://www.aether.ru/tags/internet">Интернет</category>
 <wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://www.aether.ru/crss/node/62</wfw:commentRss>
 <pubDate>Tue, 23 Jun 2009 18:55:30 +0000</pubDate>
 <dc:creator>Александр Шабуневич</dc:creator>
 <guid isPermaLink="false">62 at http://www.aether.ru</guid>
</item>
<item>
 <title>Time Machine своими руками</title>
 <link>http://www.aether.ru/blog/2009/06/14/time-machine</link>
 <description>&lt;p&gt;Заметка о настройки бэкапа на Mac OS X без использования Time Machine, а с помощью Unison.&lt;/p&gt;
&lt;!--break--&gt;
&lt;p&gt;В своей первой заметке о работе с Mac OS X я хочу рассказать о собственном опыте настройки автоматического бэкапа данных без использования Time Machine. Почему без нее? Несмотря на то, что это офигенно клевая и удобная программа, она все же заточена под определенные цели, а именно: полное архивирование системы, создание ее загрузочного образа, который быстро позволяет восстановить систему в случае ее поломки. Мне же нужно было сохранять лишь часть своих рабочих документов, а кроме того, эти документы должны быть доступны потом на PC — то есть использование маковской файловой системы отпадает.&lt;/p&gt;

&lt;h2&gt;Что я имею&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Внешний диск на 320 Гб с системой FAT32&lt;/li&gt;
&lt;li&gt;Макбук&lt;/li&gt;
&lt;li&gt;Домашний PC, который должен иметь доступ к данным с этого же диска&lt;/li&gt;
&lt;li&gt;Желание максимально автоматизировать процесс архивации данных таким образом, чтобы при каждом подключении диска к макбуку, бэкап происходил автоматически (самостоятельно нажимать кнопку я буду постоянно забывать, а бэкап по расписанию не подходит, т.к. диск подключен к ноуту не постоянно)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Конечно же архивация должна быть инкрементарной — чтобы не перегонять старые данные снова и снова. Наличие дополнительной архивации (сохранение версий) желательно, но не обязательно.&lt;/p&gt;

&lt;h2&gt;План спасения&lt;/h2&gt;

&lt;p&gt;Time Machine не подходит по нескольким причинам: а) Файловая система внешнего диска должна быть HFS+; б) Мне не нужен полный образ системы — лишь мои отдельные документы; в) Такой способ не подходит для бэкапа на простую флешку, например.&lt;/p&gt;

&lt;p&gt;Я начал искать бесплатное и надежное решение среди сторонних программ, наиболее подходящими мне сначала показались &lt;a href="http://www.lacie.com/silverkeeper/" rel="external"&gt;SilverKeeper&lt;/a&gt; и &lt;a href="http://www.grapefruit.ch/iBackup/" rel="external"&gt;iBackup&lt;/a&gt;. Я попробовал обе, но SK не смог сделать даже первый снимок, а iBackup «сломался» на втором этапе — инкрементарном бэкапе. То есть, сначала он все файлы скопировал, а когда во второй раз надо было скопировать лишь изменения, пошли ошибки. Думаю, что дело оказалось в непривычной для обеих программ файловой системе.&lt;/p&gt;

&lt;p&gt;Я стал копать дальше и наткнулся на простое и клевое решение — программу &lt;a href="http://www.cis.upenn.edu/~bcpierce/unison/"&gt;Unison&lt;/a&gt;. Это кроссплатформенная программа, которой я сначала немного испугался (все-таки она больше заточена под &lt;abbr title="Command Line Interface"&gt;CLI&lt;/abbr&gt;, чем под GUI), но все оказалось довольно просто — мануал доступно все объясняет. Ее я и решил использовать. Тем более, что для моих нужд работа с командной строкой была просто необходима.&lt;/p&gt;

&lt;h2&gt;Настройка Unison&lt;/h2&gt;

&lt;p class="excerpt"&gt;Думаю, что возможности программы удовлетворят и самого взыскательного пользователя.&lt;/p&gt;

&lt;p&gt;Unison — могучая программа. Ее возможности покрывают мои потребности с лихвой: я даже не настраивал дополнительную архивацию, но это вполне можно сделать при желании. Я остановился на том, что задал папку с документами и приказал программе зеркалировать ее в папку на внешнем диске. Вот мой файл конфига, делающий копию моей домашней папки:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;
# Unison preferences file
root = /Users/alex
root = /Volumes/WD320/_backup/macbook/
force = /Users/alex
ignore = Name {.DS_Store}
ignore = Name {unison.log}
ignore = Path {.*}
ignore = Path {Music}
ignore = Path {Movies}
ignore = Path {Library/Caches}
ignore = Path {Library/Mail}
ignore = Path {Library/Mail Downloads}
perms = 0
&lt;/code&gt;&lt;/pre&gt;

&lt;ul&gt;
&lt;li&gt;Первые две строчки означают «&lt;em&gt;Откуда&lt;/em&gt;» и «&lt;em&gt;Куда&lt;/em&gt;».&lt;/li&gt;
&lt;li&gt;Параметр &lt;code&gt;force&lt;/code&gt; указывает производить зеркалирование первого источника, а не двустороннюю синхронизацию&lt;/li&gt;
&lt;li&gt;Правила игнорирования пропускают скрытые папки (начинающиеся с точки) и файлы &lt;em&gt;.DS_Store&lt;/em&gt;, а также папки с музыкой и фильмами. Кроме того, я пропускаю папку с системным кешем и почтовые папки (т.к. все-равно пользуюсь IMAP от gmail, а значит все письма хранятся на сервере).&lt;/li&gt;
&lt;li&gt;Параметр &lt;code&gt;&lt;/code&gt; нужен для того, чтобы не было конфликтов с файловой системой FAT, которая не может сохранить юниксовые разрешения.&lt;/li&gt;
&lt;/ul&gt;

&lt;p class="note"&gt;По большому счету, я мог бы вообще игнорировать папку &lt;em&gt;/Library&lt;/em&gt; — а взять только свои собственные документы, но при игнорировании кеша и почты, эта папка занимает не очень много места (порядка 100 Мб), а полезные настройки и конфиги в ней тоже могут быть (см. ниже).&lt;/p&gt;

&lt;p&gt;Для того, чтобы запустить процесс копирования на диск достаточно ввести в терминале команду:&lt;/p&gt;

&lt;code&gt;unison backup_mac -ui text -silent&lt;/code&gt;

&lt;p&gt;где &lt;em&gt;backup_mac&lt;/em&gt; — это имя файла &lt;em&gt;backup_mac.prf&lt;/em&gt;, который обычно лежит в папке &lt;em&gt;/Users/alex/Library/Application Support/Unison&lt;/em&gt;. Вы можете назвать его как угодно, хоть default.prf — как он и называется по умолчанию.&lt;/p&gt;

&lt;p&gt;Данная команда автоматически и без показа графического интерфейса сделает копию всех изменившихся файлов (удаляя при этом файлы на внешнем диске, которые были удалены с компьютера). Теперь осталось решить проблему с автоматическим запуском Unison при вставке моего диска.&lt;/p&gt;

&lt;h2&gt;Автоматический запуск&lt;/h2&gt;

&lt;a class="img right" href="/files/automator.png" rel="lightbox"&gt;&lt;img src="/files/automator_s.png" /&gt;&lt;/a&gt;

&lt;p&gt;Для этого можно воспользоваться программой Automator, а можно написать свой AppleScript. Забегая вперед, скажу, что использовать пришлось обе техники.&lt;/p&gt;

&lt;p class="excerpt"&gt;Жаль, что в Автоматоре совсем не развито понятие логики условий типа if..else&lt;/p&gt;

&lt;p&gt;Automator — очень клевая и красивая вещь, которая позволяет простым смертным (т.е. «непрограммистам») делать довольно гибкие скрипты-программы для обработки файлов, папок и пр. По большому счету, в ней нет ничего, чего не было бы в AppleScript, но зато сделано все очень красиво и удобно — достаточно перетащить нужные действия и программа будет готова. В моем случае можно было бы обойтись и вовсе без Автоматора (потому что требуется простая команда терминалу). Но если у вас, к примеру, происходит что-то более комплексное, скажем, перед запуском копирования вы хотите заархивировать все PDF-файлы в своей домашней папке, то Автоматор позволит это автоматизировать всего за пару кликов. Пользователи Windows могут только жадно глотать слюни, когда познакомятся с этой программой поближе. =)&lt;/p&gt;

&lt;p&gt;Я настроил очень простой процесс (workflow), который выдает окно с подтверждением, хочу ли я сделать бэкап на диск, и, если я отвечаю положительно, делает свое черное дело в фоновом режиме. Сразу после окончания (если все прошло удачно) вылезает маленькое окошко уведомления &lt;a href="http://growl.info/" rel="external"&gt;Growl&lt;/a&gt; (если он стоит у вас в системе) о том, что все прошло хорошо. Как видите, ничего сложного, но в этот процесс легко можно встроить и дополнительные шаги, например архивацию или удаление файлов, произвести какие-то манипуляции с PDF-файлами и т.д.&lt;/p&gt;

&lt;p&gt;Указанный процесс я сохранил в виде приложения (на самом деле в виде плагина к «действиям папки» — &lt;em&gt;Folder Actions&lt;/em&gt;). Но как же привязать запуск приложения к вставке самого диска? В этом поможет AppleScript, совсем без кода, как видите, не обошлось.&lt;/p&gt;

&lt;p&gt;Опущу подробности того, как я искал решение для моей задачи (т.к. AppleScript я совсем не знаю), приведу лишь код, который для меня работает:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;
on adding folder items to target_folder after receiving added_items
	set volumeName to "WD320" -- This is the display name of your external HDD volume; any of them if you have more than one.
	repeat with added_item in added_items
		if the displayed name of (info for added_item) is equal to volumeName then
			volumeMounted()
			exit repeat
		end if
	end repeat
end adding folder items to

on volumeMounted()
	try
		-- get modification date to determine that last backup was more than 1 day ago
		set logFileInfo to info for POSIX file "/Users/alex/unison.log"
		if modification date of logFileInfo &lt; ((current date) - 24 * 60 * 60) then
			tell application "Macintosh HD:Users:alex:code:automator:wd_backup.app" to activate
		end if
	on error
		tell application "Macintosh HD:Users:alex:code:automator:wd_backup.app" to activate
	end try
	
end volumeMounted
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Этот скрипт сохраняется в папке &lt;em&gt;Folder Action Scripts&lt;/em&gt; (/Users/alex/Library/Scripts/Folder Action scripts) и вешается на папку &lt;em&gt;/Volumes&lt;/em&gt; (для этого надо войти в настройки Действий папки, нажать + для добавления папки, а затем нажать Shift-⌘-G), ввести &lt;em&gt;/Volumes&lt;/em&gt; и нажать Open.&lt;/p&gt;

&lt;p class="excerpt"&gt;Как я говорил, Automator в таком простом случае вообще не нужен — вы можете смело указывать прямую команду для Unison.&lt;/p&gt;

&lt;p&gt;Что этот скрипт делает? Он проверяет, чтобы при добавлении в указанную папку (&lt;em&gt;/Volumes&lt;/em&gt;) новых элементов (дисков, флешек и пр.), при совпадении имени (у меня — «WD320») запускалась бы функция &lt;code&gt;volumeMounted()&lt;/code&gt;. Внутри этой функции я проверяю дату модификации файла &lt;em&gt;unison.log&lt;/em&gt;. Этот файл автоматически создается при каждой синхронизации. И если этот файл менялся больше суток назад (или файла вообще нет), то запускается мой скрипт Автоматора, который и дает команду Unison'у.&lt;/p&gt;

&lt;h2&gt;Другие возможности&lt;/h2&gt;

&lt;p&gt;Естественно, такой способ можно использовать не только для создания бэкапа на внешнем диске, а, например, для синхронизации работы между двумя компьютерами через флешку. Для этого уберите параметр force из конфига Unison (а также можно убрать проверку даты последней синхронизации). И тогда, при каждой вставке флешки, у вас будут синхронизироваться изменения сделанные и на другом компьютере (правда, разрешение конфликтов при одновременном изменении одних и тех же файлов видимо придется взять на себя).&lt;/p&gt;

&lt;p&gt;Вот и все. И еще раз, я вовсе не хочу сказать, что все описанное отменяет Time Machine. Для полного бэкапа своей системы я пользуюсь именно Time Machine, потому что она очень проста и удобна. Данная заметка показывает как связать Unison (позволяющий гораздо более гибко настраивать синхронизацию и архивирование), Automator (облегчающий выполнение автоматических действий над файлами) и AppleScript с Folder Actions — чтобы получить гибкую и простую систему синхронизации/архивации ваших данных. Если у кого есть какие замечания — пишите, с удовольствием выслушаю, так как сам в этих вопросах новичок и мог что-то не досмотреть.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/EyeBeholder?a=dmBV9v77OTk:mq368nTX99k:D7DqB2pKExk"&gt;&lt;img src="http://feeds.feedburner.com/~ff/EyeBeholder?i=dmBV9v77OTk:mq368nTX99k:D7DqB2pKExk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/EyeBeholder?a=dmBV9v77OTk:mq368nTX99k:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/EyeBeholder?i=dmBV9v77OTk:mq368nTX99k:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/EyeBeholder?a=dmBV9v77OTk:mq368nTX99k:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/EyeBeholder?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</description>
 <comments>http://www.aether.ru/blog/2009/06/14/time-machine#comments</comments>
 <category domain="http://www.aether.ru/tags/mac">mac</category>
 <category domain="http://www.aether.ru/tags/soft">Софт</category>
 <wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://www.aether.ru/crss/node/61</wfw:commentRss>
 <pubDate>Sun, 14 Jun 2009 10:04:39 +0000</pubDate>
 <dc:creator>Александр Шабуневич</dc:creator>
 <guid isPermaLink="false">61 at http://www.aether.ru</guid>
</item>
<item>
 <title>Верстка веб-форм</title>
 <link>http://www.aether.ru/blog/2009/05/06/webforms</link>
 <description>&lt;!--break--&gt;
&lt;p&gt;Верстка веб-форм является одной из самых распространенных задач при создании сайта. Формы бывают простыми (типа обратной связи) и сложными (например, анкета на получение кредита). Но все формы объединяет то, что их надо сверстать, и желательно как можно проще и быстрее. Учитывая, что большинство форм состоит из одинаковых элементов, можно использовать для этого шаблон, который я привожу в конце статьи. Серверную часть (генерацию и прочее) я рассматривать не буду, статья касается только клиентской части — разметки.&lt;/p&gt;

&lt;h2&gt;Элементы формы&lt;/h2&gt;

&lt;p&gt;Большая часть веб-форм состоит из двух видов элементов: &lt;em&gt;подписей&lt;/em&gt; и самих &lt;em&gt;элементов управления&lt;/em&gt; (виджетов). Элементами управления могут быть текстовые поля, раскрывающиеся списки, флажки и т.д. В большинстве случаев форма представляет собой пары «подпись—элемент». Бывают и более тяжелые случаи, когда вместо одного элемента используется несколько, вида «подпись—элемент1—элемент2—элемент3». Например, выбор даты, состоящий из трех раскрывающихся списков «число, месяц, год». Часто в связках «подпись—элемент» предусматривается место для подсказки, объясняющей назначение поля.&lt;/p&gt;

&lt;h2&gt;Визуальное представление форм&lt;/h2&gt;

&lt;p class="excerpt"&gt;Подробнее о визуальном представлении форм читайте в книге Люка Роблевски (Luke Wroblewski) «&lt;a href="http://www.lukew.com/resources/web_form_design.asp" rel="external"&gt;Web Form Design: Filling in the blanks&lt;/a&gt;»&lt;/p&gt;

&lt;p&gt;Самыми распространенными способами представления веб-форм являются:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Подписи слева от полей, на одном уровне&lt;/li&gt;
&lt;li&gt;Подписи над полями&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;У обоих способов есть достоинства и недостатки. Лично я предпочитаю размещать подписи на одном уровне с элементами управления (выравнивая текст подписей вправо) — на мой взгляд, это делает форму более понятной, хотя исследования показывают, что времени на заполнение в этом случае требуется чуть больше, чем в случае расположения подписей над элементами.&lt;/p&gt;

&lt;h2&gt;Способы разметки формы&lt;/h2&gt;

&lt;p&gt;Способов разметки веб-форм существует довольно много. Задача, конечно же сверстать форму с наименьшим количеством «лишних» тегов, желательно не нарушая семантики. Из самых распространенных вариантов:&lt;/p&gt;

&lt;h3&gt;Таблицы&lt;/h3&gt;

&lt;pre&gt;&lt;code&gt;
&amp;lt;table&amp;gt;
  &amp;lt;tr&amp;gt;
    &amp;lt;th&amp;gt;&amp;lt;label&amp;gt;Подпись&amp;lt;/label&amp;gt;&amp;lt;/th&amp;gt;
    &amp;lt;td&amp;gt;Элемент&amp;lt;/td&amp;gt;
  &amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Данный способ подходит для расположения подписей на одном уровне с элементами, но затрудняет другие возможности форматирования.&lt;/p&gt;

&lt;h3&gt;Списки (ul или ol)&lt;/h3&gt;

&lt;pre&gt;&lt;code&gt;
&amp;lt;ul&amp;gt;
  &amp;lt;li&amp;gt;
    &amp;lt;label&amp;gt;Подпись&amp;lt;/label&amp;gt;
    Элемент
  &amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;По сути, строки формы являются &lt;em&gt;списком&lt;/em&gt; элементов и подписей к ним, так что употребление списков вполне приемлемо. Мне в этом способе не нравится то, что для выравнивания подписей (&lt;code&gt;label&lt;/code&gt;) на одном уровне с элементами управления необходимо назначать свойство &lt;code&gt;display:block&lt;/code&gt; для инлайнового элемента &lt;code&gt;label&lt;/code&gt;. Да и сам элемент управления иногда состоит из нескольких отдельных элементов (например, несколько флажков), в этом случае их приходится оборачивать в дополнительный &lt;code&gt;div&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;Параграфы или дивы&lt;/h3&gt;

&lt;pre&gt;&lt;code&gt;
&amp;lt;p&amp;gt;
  &amp;lt;label&amp;gt;Подпись&amp;lt;/label&amp;gt;
  Элемент
&amp;lt;/p&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Замечания те же, что и у предыдущего способа.&lt;/p&gt;

&lt;h3&gt;Списки определений (dl)&lt;/h3&gt;

&lt;pre&gt;&lt;code&gt;
&amp;lt;dl&amp;gt;
  &amp;lt;dt&amp;gt;&amp;lt;label&amp;gt;Подпись&amp;lt;/label&amp;gt;&amp;lt;/dt&amp;gt;
  &amp;lt;dd&amp;gt;Элемент&amp;lt;/dd&amp;gt;
&amp;lt;/dl&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Списки определений (definition list) связывают термин (&lt;code&gt;dt&lt;/code&gt;) и определение (&lt;code&gt;dd&lt;/code&gt;), а в нашем случае — подпись и элемент управления. Мне кажется такой способ разметки достаточно правильным с точки зрения семантики, а кроме того, он удобен в представлении — и &lt;code&gt;dt&lt;/code&gt; и &lt;code&gt;dd&lt;/code&gt; являются блочными элементами, что позволяет легко манипулировать ими, выстраивая горизонтально или вертикально без лишних оберток.&lt;/p&gt;

&lt;p&gt;Достаточно прописать к форме стиль:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;
form dt{
  padding: 0;
  margin: 0.7em 1em 0.5em 0;
  width: 25%;
  float: left;
  clear: left;
  text-align: right;
}
form dd{
  margin: 0;
  padding: 0.5em 0;
  width: 70%;
  float: left;
  *float: none; /* hack for IE 6-7 - better to keep in separate file */
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;и наша форма выстроится в мой любимый вариант «подписи слева—элементы справа».&lt;/p&gt;

&lt;p class="note"&gt;В данном случае пришлось использовать небольшой хак для Internet Explorer 6-7, чтобы высота обоих столбцов была синхронной (при длинных подписях). Этого можно избежать, убрав свойство &lt;code&gt;float&lt;/code&gt; у &lt;code&gt;dt&lt;/code&gt;, но возможно есть и другие варианты решения этой проблемы.&lt;/p&gt;

&lt;h2&gt;Шаблон формы&lt;/h2&gt;

&lt;p&gt;Ниже представлен небольшой шаблон, который я в последнее время использую для верстки форм. Он включает в себя подписи к полям, опциональные скрытые поля (наподобие, «откуда вы про нас узнали» &amp;rarr; другое &amp;rarr; появляется доп. текстовое поле) и некоторые другие мелочи.&lt;/p&gt;

&lt;p class="warning"&gt;&lt;a href="/example/forms/"&gt;Шаблон формы&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;Примечания к шаблону&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Работа скрываемых полей требует использования jQuery.&lt;/li&gt;
&lt;li&gt;Скрываемые поля работают так: каждое из них обертывается в &lt;code&gt;&amp;lt;span class="hidden" id="..."&amp;gt;&lt;/code&gt;, каждому элементу, отвечающему за показ скрытого поля (флажок или список) назначается класс &lt;code&gt;hidden-trigger&lt;/code&gt;, а также прописывается аттрибут &lt;code&gt;rel="#ID#"&lt;/code&gt; (где #ID# равен id скрытого элемента).&lt;/li&gt;
&lt;li&gt;Можно нажать кнопку «Отправить», чтобы посмотреть оформление ошибок.&lt;/li&gt;
&lt;li&gt;Ошибки выводятся в специальном блоке с классом &lt;code&gt;error-block&lt;/code&gt;, каждая из них выводится в виде элемента списка с аттрибутом &lt;code&gt;rel="#ERROR_ID#"&lt;/code&gt; (где #ERROR_ID# равен id элемента с ошибкой) — в этом случае, поля с ошибками автоматически подсвечиваются.&lt;/li&gt;
&lt;/ul&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/EyeBeholder?a=UXU7RK51mPM:Mf_w881qb5I:D7DqB2pKExk"&gt;&lt;img src="http://feeds.feedburner.com/~ff/EyeBeholder?i=UXU7RK51mPM:Mf_w881qb5I:D7DqB2pKExk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/EyeBeholder?a=UXU7RK51mPM:Mf_w881qb5I:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/EyeBeholder?i=UXU7RK51mPM:Mf_w881qb5I:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/EyeBeholder?a=UXU7RK51mPM:Mf_w881qb5I:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/EyeBeholder?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</description>
 <comments>http://www.aether.ru/blog/2009/05/06/webforms#comments</comments>
 <category domain="http://www.aether.ru/tags/css">CSS</category>
 <category domain="http://www.aether.ru/tags/xhtml">XHTML</category>
 <category domain="http://www.aether.ru/tags/code">Код</category>
 <category domain="http://www.aether.ru/tags/usability">Юзабилити</category>
 <wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://www.aether.ru/crss/node/59</wfw:commentRss>
 <pubDate>Wed, 06 May 2009 07:30:31 +0000</pubDate>
 <dc:creator>Александр Шабуневич</dc:creator>
 <guid isPermaLink="false">59 at http://www.aether.ru</guid>
</item>
<item>
 <title>Обновился адрес RSS</title>
 <link>http://www.aether.ru/blog/2009/02/27/new-rss-address</link>
 <description>&lt;p&gt;В связи с переходом FeedBurner к Google, все давно поменяли адреса RSS-лент. Старый должен продолжать работать, но на всякий случай лучше обновить.&lt;/p&gt;
&lt;!--break--&gt;
&lt;p&gt;Собственно, новый адрес: &lt;strong&gt;http://feeds2.feedburner.com/EyeBeholder&lt;/strong&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/EyeBeholder?a=5pAq3dExLiQ:vp-2NYFdG3A:D7DqB2pKExk"&gt;&lt;img src="http://feeds.feedburner.com/~ff/EyeBeholder?i=5pAq3dExLiQ:vp-2NYFdG3A:D7DqB2pKExk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/EyeBeholder?a=5pAq3dExLiQ:vp-2NYFdG3A:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/EyeBeholder?i=5pAq3dExLiQ:vp-2NYFdG3A:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/EyeBeholder?a=5pAq3dExLiQ:vp-2NYFdG3A:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/EyeBeholder?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</description>
 <comments>http://www.aether.ru/blog/2009/02/27/new-rss-address#comments</comments>
 <category domain="http://www.aether.ru/tags/blog">Блог</category>
 <wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://www.aether.ru/crss/node/58</wfw:commentRss>
 <pubDate>Fri, 27 Feb 2009 19:10:14 +0000</pubDate>
 <dc:creator>Александр Шабуневич</dc:creator>
 <guid isPermaLink="false">58 at http://www.aether.ru</guid>
</item>
<item>
 <title>Моя тема для phpMyAdmin 3.0</title>
 <link>http://www.aether.ru/blog/2008/12/21/phpmyadmin-theme-3</link>
 <description>&lt;p&gt;&lt;a href="/blog/2006/11/13/phpmyadmin-revamped"&gt;Когда-то&lt;/a&gt; я сделал простую и легкую (для восприятия) версию шаблона для phpMyAdmin. Прошло 2 года, разработчики выпустили новую версию — 3.0. Наконец у меня дошли руки обновить свою тему, теперь она подходит к последней версии phpMyAdmin.&lt;/p&gt;
&lt;!--break--&gt;
&lt;p&gt;Я рад, что люди пользуются мом шаблоном — я сам смотреть не могу на стандартный интерфейс. Ниже приведены ссылки на старую (работающую с 2.x) и новую (для 3.x) версии шаблона. Изменений практически нет, просто подправлены CSS-файлы под новые элементы.&lt;/p&gt;

&lt;p&gt;&lt;a style="border:none" href="/images/54.png" rel="lightbox" title="phpMyAdmin Clear View"&gt;&lt;img src="/images/54t.png" alt="phpMyAdmin Clear View" height="85" width="480" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Как всегда, если заметите какие-то глюки, пожалуйста пишите в комментариях.&lt;/p&gt;

&lt;p class="warning"&gt;
&lt;a href="/files/clearview3.zip"&gt;ClearView 3 (для PMA 3.x)&lt;/a&gt;&lt;br /&gt;
&lt;a href="/files/clear_view-1.31.zip"&gt;ClearView 1.31 (для PMA 2.x)&lt;/a&gt;
&lt;/p&gt;

&lt;p class="note"&gt;Обновлено: теперь картинки в CSS не зависят от пути.&lt;/p&gt;
&lt;p class="note"&gt;А еще мою тему наконец-то добавили в список на &lt;a href="http://www.phpmyadmin.net/home_page/themes.php" rel='external'&gt;официальном сайте&lt;/a&gt;.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/EyeBeholder?a=KHEywR4-SLE:8kGw3GpyLgo:D7DqB2pKExk"&gt;&lt;img src="http://feeds.feedburner.com/~ff/EyeBeholder?i=KHEywR4-SLE:8kGw3GpyLgo:D7DqB2pKExk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/EyeBeholder?a=KHEywR4-SLE:8kGw3GpyLgo:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/EyeBeholder?i=KHEywR4-SLE:8kGw3GpyLgo:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/EyeBeholder?a=KHEywR4-SLE:8kGw3GpyLgo:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/EyeBeholder?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</description>
 <comments>http://www.aether.ru/blog/2008/12/21/phpmyadmin-theme-3#comments</comments>
 <category domain="http://www.aether.ru/tags/php">PHP</category>
 <category domain="http://www.aether.ru/tags/tools">Инструменты</category>
 <category domain="http://www.aether.ru/tags/interface">Интерфейс</category>
 <category domain="http://www.aether.ru/tags/usability">Юзабилити</category>
 <wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://www.aether.ru/crss/node/56</wfw:commentRss>
 <pubDate>Sun, 21 Dec 2008 18:00:12 +0000</pubDate>
 <dc:creator>Александр Шабуневич</dc:creator>
 <guid isPermaLink="false">56 at http://www.aether.ru</guid>
</item>
</channel>
</rss>
