Показ дописів із міткою howto. Показати всі дописи
Показ дописів із міткою howto. Показати всі дописи

середу, квітня 29, 2009

Искусство JavaScript ошибок: JavaScript error handling anti-pattern

Есть одна область в javascript программировании, где я ощущаю недостаток дискуссии - это отслеживание ошибок. В то время как многие девелоперы занимаются дебагом ошибок в серверных языках, в JS это делают не многие. Я постараюсь поднять интерес разработчиков к обработке javascript ошибок.

Одно из решений, это введение дебаг мода для приложения на JS. Идея такая, что если дебаг мод установлен в false, ошибки происходят сами собой, если же дебаг мод true - ошибки могут логироваться на сервере или алертом показывать свое присутствие с указанием строки и причины ошибки. Очень полезно для IE.


Пример:
function doSomething(value){
try {
process(value);
} catch (ex){
if (debugMode){
throw ex;
} else {
log(1, "doSomething(): " + ex.message);
}
}
}
Идея примера такова, что если возникла ошибка, то в зависимости от установленного дебаг мода ошибка или логируется или просто показывается. Сейчас, я постараюсь объяснить всю уязвимость данной идеи.

Если ошибка возникнет в функции process(), она будет перехвачена в функции doSomething() и в зависимости от дебаг мода сгенерируется или залогируется, тем самым разрушит call stack. Ошибка будет слишком далека от актуального события, которое нам и нужно отдебажить. Вся полезная информация, которая могла бы быть решением будет утеряна, так как мы выйдем из функции process(). Используя этот код, ваш дебагер будет обрывать выполнение программы в строке содержащей throw ex, в то время как вы хотите оборвать выполнение в самой функции process().

Мое решение - это код, который будет скорее предотвращать полезный дебаг, чем разрешать его.
Есть два способа решения этой проблемы:

1 (Галимый):
function doSomething(value){
if (!debugMode){
process(value);
} else {
try {
process(value);
} catch (ex){
log(1, "doSomething(): " + ex.message);
}
}
}
2 (Нормальный):
var doSomething = debugMode ?
function(value){
process(value);
} :
function(value){
try {
process(value);
} catch (ex){
log(1, "doSomething(): " + ex.message);
}
};
Второй метод более предпочтительнее, так как он предотвращает проверку дебаг мода каждый раз, когда функция исполняется. Еще его легче автоматизировать. Предполагается, что у вас есть один или несколько обьектов и вы хотите, что бы все их методы имели враппер для отлова ошибок на продакшине. Вот вам пример такого кода:

Пример:
//by Nicholas C. Zakas (MIT Licensed)
function productionize(object){

var name,
method;

for (name in object){
method = object[name];
if (typeof method == "function"){
object[name] = function(name, method){
return function(){
try {
return method.apply(this, arguments);
} catch (ex) {
log(1, name + "(): " + ex.message);
}
};

}(name, method);
}
}
}
Этот код пробегает по всем методам объекта и заменяет его функции на другие, которые уже содержат в себе механизм отлова ошибок. Вот пример использования:
var system = {
fail: function(){
throw new Error("Oops!");
}
};

function log(severity, message){
alert(severity + ":" + message);
}

if (!debugMode){
productionize(system);
}

system.fail(); //error is trapped!
Всегда убеждайтесь в том, что ошибка сгенерировалась именно там где нужно - это первая проблема дебага JS ошибок. Удачи!

По материалам: Nicholas C. Zakas

четвер, квітня 23, 2009

YUI карусель за 10 минут.

yui карусельБыстрое howto или как запустить javascript карусель у себя на сайте за 10 минут.

Компонент карусель был добавлен в YUI билиотеку для быстрого скролла контента на сайте в привлекательном и удобном интерфейсе. Последние тенденции показывают, что карусели все чаще становятся необходимым атрибутом каждого сайта. Конкретно В данном туториале мы расмотрим стандартную имплементацию yui библиотеки для реализации поставленной задачи.

Посмотрим?
В вашем текстовом редакторе создайте следующую html-страничку:





<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">

<html>

<head>

<link rel="stylesheet" type="text/css"
href="http://yui.yahooapis.com/2.6.0/build/carousel/assets/skins/sam/carousel.css">

<meta http-equiv="Content-Type" content="text/html; charset=utf-8">

<title>YUI Carousel Example 1</title>

</head>

<body class="yui-skin-sam">

<div id="scientists">

<ol>

<li><img src="img/scientists/bohr_thumb.jpg" alt="Niels Bohr"></li>

<li><img src="img/scientists/darwin_thumb.jpg" alt="Charles Darwin"></li>

<li><img src="img/scientists/einstein_thumb.jpg" alt="Albert Einstein"></li>

<li><img src="img/scientists/galileo_thumb.jpg" alt="Galileo Galilei"></li>

<li><img src="img/scientists/newton_thumb.jpg" alt="Isaac Newton"></li>

<li><img src="img/scientists/maxwell_thumb.jpg" alt="James Clerk Maxwell"></li>

</ol>

</div>

<script type="text/javascript"
src="http://yui.yahooapis.com/2.6.0/build/yahoo-dom-event/yahoo-dom-event.js"></script>

<script type="text/javascript"
src="http://yui.yahooapis.com/2.6.0/build/element/element-beta-min.js"></script>

<script type="text/javascript"
src="http://yui.yahooapis.com/2.6.0/build/carousel/carousel-beta-min.js"></script>

<script type="text/javascript">


//create carousel control

var carousel = new YAHOO.widget.Carousel("scientists");


//render to page

carousel.render();


//display

carousel.show();


</script>

</body>

</html>
Все! Сохраните ее, только картинки сами добавьте. Карусель готова. Результат можно наблюдать на изображении.

середу, квітня 22, 2009

Регулярные выражения php

regexpЯ надеюсь все знают, что такое регулярные выражения, публикую полезную таблицу и полезные примеры для web-разработчиков:


Ниже приведена таблица паттернов и их соответствий:

/pattern/Соответствие
x?ноль или один символ 'x'
x*ноль или больше символов 'x'
x+один или больше символов 'x'
.*ноль или больше любых символов
.+один или больше любых символов
{m}M символов
[]символы, заключенные в []
[^]символы, кроме заключенных в []
[0-9]любая цифра от '0' до '9'
[a-z]любая буква от 'a' до 'z'
[^0-9]любой символ, не находящийся между '0' и '9'
[^a-z]любой символ, не находящийся между 'a' и 'z'
/^.../первый символ в строке
/...$/последний символ в строке
\dодна цифра, то же, что и [0-9]
\d+одна или больше цифр, то же, что и [0-9]+
\Dодна не-цифра, то же, что и [0-9]
\D+одна или больше не-цифр, то же, что и [0-9]+
\wодин alphanumeric символ (латинская буква или цифра), то же, что и [a-zA-Z0-9]
\w+один или больше alphanumeric-символов, то же, что и [a-zA-Z0-9]+
\Wодин не-alphanumeric символ, то же что и [^a-zA-Z0-9]
\W+один или больше не-alphanumeric символ, то же что и [^a-zA-Z0-9]+
\sодин space символ (пробел, табуляция, новая строка), то же что и [\n\t\r\f]
\s+один или больше space символов, то же что и [\n\t\r\f]
\Sодин не-space символ, то же что и [^\n\t\r\f]
\S+один или больше не-space символов, то же что и [^\n\t\r\f]+
a|b|c'a' или 'b' или 'c'
abcподстрока "abc"
(pattern)() запоминает группу символов, присваивая их переменным $1, $2 и т.д. См. примеры.
/pattern/iигнорировать регистр букв

Это, конечно, не понять с первого раза, поэтому вот примеры:

ПримерОписание
$str=~/perl/;проверяет, есть ли в строке $str подстрока "perl"
$str=~/^perl/;проверяет, начинается ли строка с подстроки "perl"
$str=~/perl$/;проверяет, заканчивается ли строка на подстроку "perl"
$str=~/c|g|i/;проверяет, содержит ли строка символ 'c' или 'g' или 'i'
$str=~/cg{2,4}i/;проверяет, содержит ли строка символ 'c', следующие сразу за ним 2-4 символа 'g', за которыми следует символ 'i'
$str=~/cg*i/;проверяет, содержит ли строка символ 'c', слудующие за ним 0 или больше символа 'g', за которыми следует символ 'i'
$str=~/c..i/;проверяет, содержит ли строка символ 'c', и символ 'i', разделенные двумя любыми буквами
$str=~/[cgi]/;проверяет, содержит ли строка один из символов 'c', 'g' или 'i'
$str=~/\d/;проверяет, содержит ли строка цифру
$str=~/\W/;проверяет, содержит ли строка символы, не являющиеся буквами латинского алфавита и цифрами

Использование регулярных выражений:

1) Иногда требуется узнать расширение файла по его имени. Элементарное регулярное выражение выбирает все символы после последней точки;
# Пример в  PHP

$filename = '/index.php';

$out = array();

preg_match('/\S+\.(\S+)$/', $filename, $out);

# $out[1] будет содержать расширение файла - 'php'

2) Заменяет английские закрывающие кавычки-«лапки» на русские «елочки»;
# Пример в  PHP

$text = preg_replace('/(\S)"([ .,?!])/', '$1»$2', $text);

3) Простая проверка правильности введенного адреса электронной почты;
# Пример в  PHP

$is_ok = preg_match('/^(.+@.+\..+|)$/', $text);
4) Находит в тексте и автоматически преобразует адреса, начинающиеся с ftp://, http://, https:// в активные ссылки;
# Пример в  PHP

$text = preg_replace("#(https?|ftp)://\S+[^\s.,>)\];'\&
quot;!?]#", '\\0', $text);

вівторок, квітня 21, 2009

суботу, квітня 18, 2009

Использование memcached php

memcachedДля начала использования memcached, вы должны запустить memcached-сервис на одном или более серверов. Запуск сервиса: сетапит сервер, выделяет память, и собственно прослушивает соединения от клиентов, использующих сервис.
Пометка: Вы можете запустить memcached не из под рута, но в этом случае вы будете слушать только один TCP/IP порт (от 1024). Однако, вы не должны использовать пользователя, для запуска сервиса, у которого есть ограничения памяти, например setrlimit.
Для запуска сервера, не из под рута:
shell>memcached
По дефолту, memcached использует следующие настройки:
  • Выделение памяти: 64 мб;
  • Прослушивает порт для соединений: 11211;
  • Максимум 1024 одновременных подключений;
Обычно люди используют полную комбинацию опций, при старте сервиса, а также скрипт, который сам запускает memcached при старте компьютера. Для примера, следующая строка запускает сервис с максимум 1024 MB RAM для кэша, прослушивает 11121 порт на айпи-адресе 192.168.0.110, запущен как бекграунд-демон.
shell> memcached -d -m 1024 -p 11121 -l 192.168.0.110
Для того, что бы убедиться, что memcached запущен, вы можете его проверить. На OpenSolaris мемкеш контролируется SMF. Активируйте его, запустив:
root-shell> svcadm enable memcached
memcached поддерживает следующие опции:
  • -u user
Если вы запускаете memcached как root, используйте опцию -u, для обозначения пользователя, который запустит memcached
shell> memcached -u memcache
  • -m memory
Установите количество выделяющейся памяти, по дефолту 64 Mb. Для увеличения используемой RAM памяти (в мегабайтах) используйте опцию -m. Чем больше памяти вы выделите, тем больше данных вы сможете сохранить.
Внимание: Не выделяйте памяти больше, чем у вас есть в RAM. Если вы выделите больше памяти, то то место, которое не влезло засвапится, это приведет к замедлению сохранения и возвращения данных. Вы можете проинспектировать свою память командой vmstat.
shell> vmstat
kthr memory page disk faults cpu
r b w swap free re mf pi po fr de sr s1 s2 -- -- in sy cs us sy id
0 0 0 5170504 3450392 2 7 2 0 0 0 4 0 0 0 0 296 54 199 0 0 100

Для примера выделим 3GB памяти:
shell> memcached -m 3072
На 32-битных х86 системах, где используется РАЕ для доступа к памяти, стоит 4 GB лимит и вы не сможете выделить памяти больше этого лимита. Но вы можете обойти это ограничение, запустив несколько сущностей memcached, каждую на разный порт:
shell> memcached -m 1024 -p11211
shell> memcached -m 1024 -p11212
shell> memcached -m 1024 -p11213
  • -l interface
Определяет сетевой интерфейс/адрес для прослушивания соединений. По дефолту стоит на прослушку всех свободных адресов (INADDR_ANY).
shell> memcached -l 192.168.0.110
Поддержка IPv6 была добавлена в версии memcached 1.2.5
  • -p port
Определяет TCP порт, используемый для соединений. По дефолту: 18080.
shell> memcached -p 18080
  • -U port
Определяет UDP порт, используемый для соединений. По дефолту: 0 (выключен);
shell> memcached -U 18080
  • -s socket
Определяет Unix socket используемый для прослушки.
Если вы запустили memcached на одном сервере, вы можете отключить сетевой интерфейс и использовать локальный Unix socket, для этого надо воспользоваться -s опцией.
shell> memcached -s /tmp/memcached
Использование сокета автоматически отключает сетевой интерфейс и сохраняет открытыми порты;
  • -a mask
Определяет маску доступа для Unix socket в восьмеричной системе. По дефолту 0700;
  • -c connections
Определяет максимальное число одновременных подключений, по дефолту 1024;
shell> memcached -c 2048
Вы должны использовать данную опцию, также для уменьшения количества одновременных подключений к memcached, для улучшения работы сервера;
  • -t threads
Определяет количество потоков, для обработки входящих запросов. По умолчанию, memcached сконфигурирован с использованием 4 конкурентных потоков. Потоки улучшают процесс сохранения и отдачи даты в кеш и из кеша. Используйте замыкающую систему, для предотвращения перезаписи различных потоков или апдейта одинаковых данных. Вы можете увеличить или уменьшить количество потоков используя опцию -t;
shell> memcached -t 8
  • -d
Запускает memcached как демон бэкграунд процесс;
shell> memcached -d
  • -r
Увеличить размер файла ядра. В случае краша системы, эта опция позволит задампить всю выделенную память на диск, несмотря на установку setrlimit;
  • -M
Возвращает ошибку клиенту, в случае когда память закончилась. Эта опция обходит нормальную работу memcached, когда старые элементы замещаются новыми;
  • -k
Ограничение памяти;
Пользовательское ограничение по количеству выделяемой памяти. Попытка выделить больше памяти, чем разрешено приведет к ошибке. Вы можете установить лимит тому пользователю, при помощи которого стартуете демон (для -u user) вместе с шелом ulimit -S -l NUM_KB
  • -v
Отладочный режим (verbose mode). Печатает ошибки и замечания, пока запускается главный цикл;
  • -vv
Вдвойне отладочный режим. В дополнение к режиму -v печатает каждую клиентскую команду и ответ на нее;
  • -h
Печатает справку и выходит;
  • -i
Печатает memcached и libevent соглашения;
  • -b
Запускает контроллируемую сущность;
  • -p pidfile
Сохраняет ID процесса memcached в файл;
  • -f
Устанавливает размер блока выделяемой памяти. Когда будут выделяться новые блоки памяти, размер новых блоков будет определен делением на дефолтовый размер блока памяти;
  • -n bytes
Минимальный размер выделяемой памяти = 48 килобайт;
  • -L
В системах, которые поддерживают большое фрагментирование памяти, разрешает эту фрагментацию. использование фрагментации позволяет memcached выделить память в один большой блок памяти, что позволяет уменьшить количество обращений к памяти и увеличить производительность.

  • Перевод статьи оригинала: Dev.MySQL

вівторок, квітня 07, 2009

Как установить __utmv

В продолжении серии постов о Google Analytics, я расскажу как установить __utmv для решения проблемы с директ-траффиком.

Как Google Analytics отслеживает рефералы?

Ниже приведен кусок кода, который следует установить на страницу, и по ключевому слову Direct сформировать пользовательский отчет в Google Analytics.

<!-- Urchin begin -->
<script src="http://www.google-analytics.com/urchin.js" type="text/javascript"></script>
<!-- place to paste the hack -->
<script type="text/javascript">
try {
_uacct = "UA-XXXXXXX-X";
urchinTracker();
} catch(err) {}</script>
<!-- Urchin end -->


<!-- hack begin -->
<script type="text/javascript">
function _uGC(l,n,s)
{
if (!l || l=="" || !n || n=="" || !s || s=="") return "-";
var i,i2,i3,c="-";
i=l.indexOf(n);
i3=n.indexOf("=") 1;

if (i > -1)
{
i2=l.indexOf(s,i); if (i2 < 0) { i2=l.length; }
c=l.substring((i i3),i2);
}

return c;
}

var z = _uGC(document.cookie, '__utmz=', ';');
var source = _uGC(z, 'utmcsr=', '|');
if (source != '' && document.referrer == '')
{
__utmSetVar('Direct');
}
//Код для Urchin, для ga.js надо писать pageTracker._setVar('Direct');

</script>
<!-- hack end -->

Данный код, позволяет решить именно ту проблему с рефералами и директ траффиком, которую я описал выше. Методом анализа куки __utmz, вычленения из нее utmcsr и на основании этого установить __utmv.

Для тех кто интересуется детально данной проблемой, я привожу ссылку на презентацию, где рассказывается о куках более подробно.

вівторок, березня 24, 2009

Как Google Analytics отслеживает рефералы?

пщщпду фтфднешсы
Когда пользователь заходит на сайт, его данные сохраняются на компьютере при помощи кук. В куке содержится реферал пользовательской сессии:
  1. organic google реферал (поиск гугла);
  2. протаженные ссылки google analytics;
  3. обычные ссылки;
  4. direct траффик (пользователь вбил адрес в браузер).
Каждый раз, когда посетитель посещает ваш сайт, Google Analytics отслеживает реферал и апдейтит куку. Когда кука проапдейтилась GA отменяет предыдущую информацию о реферале и как результат отслеживает только текущую сессию.

Таким образом есть два правила, по которым GA апдейтит куку:
  • Директ траффик всегда переписывается другими рефералами;
  • Новые рефералы (не директ траффик) всегда переписывают существующую куку.
В этом - то и проблема, например:
  1. Человек пришел из Адвордса, google записала его как source=cpc
  2. Он посерфал по сайту, ушел. Через неделю вернулся, но вбил адрес в браузер. Google его все равно покажет как source=cpc, поскольку директ траффик не переписывается поверх других источников.
Из-за этого теряются данные о директ траффике в отчетах. Когда вы работаете с клиентом и клиент хочет знать КАЖДЫЙ шаг пользователя на сайте, то перед вами стоит задача разработать некий хинт, который покажет этот потерянный кусок траффика.

Для того, что бы решить эту проблему, надо написать JavaScript код, вставить его в код отслеживания GA и сгенерировать пользовательский отчет. Такой ход хоть и не есть решением всех проблем, но зато даст полную картину траффика в отчетах.

Javascript код должен:
Читать куку __utmz GA, смотреть, есть ли там информация о реферале, если есть и в данный момент реферал является директ траффиком, сегментировать пользователя устанавливая переменную посредством utmSetVar('var segment'). На этот сегмент и надо создавать пользовательский отчет в Google Analytics, где можно будет проследить неучтенный директ траффик.

Дополнительную информацию, и сам код я выложу позже, а пока оставьте свое мнение о том, была ли данная информация полезна... Источником статьи и размышлений на эту тему послужил блог Analytics Talk.

Как и говорил, выкладываю сам хак!

понеділок, березня 23, 2009

Как установить php memcache

memcachedНебольшое howto, как установить memcached.
Вы можете собрать и установить memcached из исходных кодов, из пакетов или при помощи инсталлятора.

Установка memcached при помощи инсталлятора:
  • На RedHat, Fedora или CentOS используйте yum:
root-shell> yum install memcached
  • Для установки на Debian или Ubuntu используйте apt-get:
root-shell> apt-get install memcached
  • На Gentoo используйте emerge:
root-shell> emerge install memcached
  • Для установки на OpenSolaris используйте pkg для установки SUNWmemcached пакета
root-shell> pkg install SUNWmemcached
Сборка memcached из исходников:
На других Unix-подобных платформах, включая Solaris, AIX, HP-UX и Mac OS X и дистрибутивы Linux не перечисленные выше, вы должны собирать memcached из исходников. Для Linux есть некоторые требования:
  1. Релиз ядра версии 2.6;
  2. Библиотека libevent версии 1.1 или выше;
Скачать memcached вы можете отсюда!
Сама сборка:
shell> gunzip -c memcached-1.2.5.tar.gz | tar xf - 
shell> cd memcached-1.2.5
shell> ./configure
Опции для конфигурации:
  • --prefix
Если хотите сменить директорию установки;
shell> ./configure --prefix=/opt
По умолчанию установка производится в /usr/local;
  • --with-libevent
Если у вас установлен libevent и configure не может его найти используйте --with-libevent для нахождения библиотеки;
  • --enable-64bit
Для сборки 64-битовой версии memcached используйте --enable-64bit;
  • --enable-threads
Для поддержки мультипоточности в memcached, используйте --enable-threads.Улучшает время реакции сервера;

Запустите make для сборки memcached;
shell> make
Запустите make install для установки memcached;
shell> make install

пʼятницю, березня 13, 2009

Как вставить программный код на Blogger?

Хотел оптимизировать блог в google, но вставить JS код в шаблон Blogger не так то просто, решил погуглить данный вопрос и наткнулся на оригинальное решение, немного изменив его я получил следующий результат.

Нужно добавить теги в css шаблона, для того, что бы код красиво смотрелся на странице:
pre {
background:#efefef;
border:1px solid #A6B0BF;
font-size:120%;
line-height:100%;
overflow:auto;
padding:10px;
color:#000000 }
pre:hover {
border:1px solid #efefef;
}
И всего лишь пропустить весь вставляемый JS/HTML... через волшебную формочку postable:
После чего можно получившийся код вставлять себе в статью, обрамив его тегами <pre>

четвер, березня 12, 2009

Элементы страниц в Blogger

Как изменить или добавить новый элемент в layout Bloggera?

Все совсем просто!
Итак начнем.

Элемент body в макете шаблона Bloggera состоит главным образом из секций и виджетов.

Секции обрамляют области вашей страницы, такие как боковая панель, колонтитул, футер и т.д.

Виджеты же, в свою очередь, являются индивидуальными элементами страницы, например картинка в верхнем правом углу или еще что-то.

Каждая секция имеет свой открывающий и закрывающий тег, что-то вроде этого:
<b:section id='header' class='header' maxwidgets="1" showaddelement="no">
</b:section>
Тег секции может иметь следующие атрибуты:
  • ID - (обязателен) уникальный идентификатор;
  • class - (опционален) navbar, header, main, sidebar, footer, ajax, polova... Если вы смените шаблон, имя класса поможет Blogger определить, что делать с секцией;
  • maxwidgets - (опционально) максимальное количество виджетов в данном разделе;
  • showaddelement - (опционально) может быть "да" или "нет" по умолчанию "да". Этот параметр определяет будет ли на вкладке "Элементы страницы" показана ссылка "Add a Page Element" для данной секции;
  • growth - (опционально) аттрибут может иметь значение "горизонтально" или "вертикально" по умолчанию "вертикально". Он определяет разположение виджетов в секции;

Секция может содержать только виджеты, но не другие разделы. Если необходимо вставить кусок кода между виджетами, то тогда надо поделить секцию на несколько секций и добавить в каждую секцию по виджету.

Некоторые примеры виджетов (по одному для заголовка страницы и один для списка):

<b:widget id="header" type='HeaderView' locked="yes"/>
<b:widget id="myList" type='ListView' locked="no" title="My Favorite Things"/>

Виджет может иметь следующие атрибуты:
  • ID - (обязателен) уникальный идентификатор. Идентификатор виджета не может быть изменен без удаления самого виджета;
  • type - (обязателен) тип виджета;
  • locked - (опционально) "да" или "нет" по умолчанию "нет". Заблокированый виджет, не может быть перемещен или удален на вкладке "Элементы страницы";
  • title - (опционально) отображает название виджета;
  • pageType - (опционально) может быть 'all,' 'archive,' 'main,' или 'item,' по умолчанию "all". Данный виджет будет отображаться только на страницах согласно типу. Все виджеты отображаются на вкладке "Элементы страницы", независимо от их pageType;
Типы виджетов:
  • BlogArchive
  • Blog
  • Feed
  • Header
  • HTML
  • SingleImage
  • LinkList
  • List
  • Logo
  • BlogProfile
  • Navbar
  • VideoBar
  • NewsBar
Примечание: В блоге, все <b:section></b:section> и <b:widget></b:widget> метки будут заменены на <div> теги, которые будут иметь указанный ID. Таким образом, вы можете обратиться к ним, например, div#header или div#myList в CSS, если хотите.

Как видите все довольно просто, главное немного поднапрячься.

неділю, березня 01, 2009

JS Mouse wheel Tutorial, или как заставить колесо крутиться!

Доброго времени суток всем!
Начну с предистории. Когда мне надо решить какую либо задачу, я начинаю ее гуглить. Иногда быстро, иногда медленно я нахожу решение. И когда я его нашел, я думаю о том, сколько я времени потратил на данную задачу. Так вот, в данном туториале, я хочу сократить время, потраченное девелоперами...
Также возвращаясь к предыдущему моему посту о каруселях, данный туториал будет как-никогда актуален.

Речь пойдет о колесике мышки. Заставим его крутиться. Самый яркий пример использования колесика это Гугл Мапс, там оно используется для масштабирования. Также очень хорошо колесо используется для гугл-ридера.

Итак...

Кручение колеса - это ивент, его надо приатачить к какому либо обьекту, в нашем случае это div. Вся проблема в том, что название этих ивентов в разных браузерах разные. В IE это событие называется onmousewheel, а в FireFox называется DOMMouseScroll.Opera в свою очередь использует название IE только без приставки on, тоесть mousewheel. Но Opera атачит ивенты как FireFox, а не как IE.

Есть две отличные функции, которые атачат и деатачат ивенты к html-элементам, но предварительно эти элементы надо снабдить id.


function hookEvent(element, eventName, callback)
{
if(typeof(element) == "string")
element = document.getElementById(element);
if(element == null)
return;
if(element.addEventListener)
{
if(eventName == 'mousewheel')
{
element.addEventListener('DOMMouseScroll',
callback, false);
}
element.addEventListener(eventName, callback, false);
}
else if(element.attachEvent)
element.attachEvent("on" + eventName, callback);
}

function unhookEvent(element, eventName, callback)
{
if(typeof(element) == "string")
element = document.getElementById(element);
if(element == null)
return;
if(element.removeEventListener)
{
if(eventName == 'mousewheel')
{
element.removeEventListener('DOMMouseScroll',
callback, false);
}
element.removeEventListener(eventName, callback, false);
}
else if(element.detachEvent)
element.detachEvent("on" + eventName, callback);
}

Посредством этих функций, можно приатачить любое событие к любому элементу. Может возникнуть вопрос, что при использовании Firefox/Opera/Safari мы атачим два события сразу (и DOMMouseScroll и mousewheel). Это не беда, так как это никак не повлияет на работу...

Но приатачить событие колесика мыши это всего лишь пол беды, главное впереди.

После атача, нам необходимо забрать значение вращения колеса. Тоесть вперед или назад (например zoom в гугл мапс).
Есть два пути, как сделать это: detail (для Firefox и Opera), а также wheelData (для Internet Explorer, Safari, и Opera). Opera по некоторым причинам включает в себя и тот и другой путь.
Функция которая будет возвращать нам значения, должна выглядеть примерно так:


function MouseWheel(e)
{
e = e ? e : window.event;
var wheelData = e.detail ? e.detail : e.wheelData;

//js код

}

Вроде бы все, но тут есть несколько подводных камней.
Например значение 3 для FireFox и Opera в detail равняется значению 120 в WheelData для Internet Explorer или Safari. Также скролл вниз это положительное число для detail, но отрицательное число для WheelData. Это может быть легко пофикшено немного модифицируя нашу функцию.


function MouseWheel(e)
{
e = e ? e : window.event;
var wheelData = e.detail ? e.detail * -1 : e.wheelDelta / 40;

//js код

}

Следующий шаг будет остановка скроллинга страницы при скроллинге html-элемента.


function cancelEvent(e)
{
e = e ? e : window.event;
if(e.stopPropagation)
e.stopPropagation();
if(e.preventDefault)
e.preventDefault();
e.cancelBubble = true;
e.cancel = true;
e.returnValue = false;
return false;
}

Если мы остановили скролл, значит страница скроллится не будет.
Для этого можно модифицировать нашу функцию следующим образом.


function MouseWheel(e)
{
e = e ? e : window.event;
var wheelData = e.detail ? e.detail * -1 : e.wheelDelta / 40;

//js код

return cancelEvent(e);
}

Теперь мы имеем все функции, необходимые нам для организации скролла над каким-то элементом. Все предельно просто и ясно.
Организуем некоторый div.

Ниже опишем наглядную функцию для деммонстрации всего выше перечисленного


function printInfo(e)
{
e = e ? e : window.event;
var raw = e.detail ? e.detail : e.wheelDelta;
var normal = e.detail ? e.detail * -1 : e.wheelDelta / 40;
document.getElementById('scrollContent').innerHTML =
" Raw Value: " + raw +
" Normalized Value: " + normal;
cancelEvent(e);
}

hookEvent('scrollContent', 'mousewheel', printInfo);

Вот впринципе и все. Теперь можно данный скролл прикрутить к карусели, к гугл мапсу, к ридеру, к счетчику или к чему-либо.

Люблю хорошие и простые туториалы.
Данный туториал написан не мною (а жаль), это всего лишь перевод. Но я считаю, что опубликовав его здесь, я добьюсь поставленной цели укоротить время, потраченное девелоперами на поиск решения по данному вопросу.

Данный туториал был найден благодаря:
1) http://forum.dklab.ru/
2) http://adomas.org/javascript-mouse-wheel/
3) http://blog.paranoidferret.com/index.php/2007/10/31/javascript-tutorial-...

На последней ссылке можно посмотреть данное решение в действии, перевод был взят оттуда же.
Всем спасибо!

Що таке база данних?

База данних — це спеціальна система зберігання, організації та пошуку інформації. Вона містить дані у вигляді таблиць, записів та інших стру...