понедельник, 25 декабря 2006 г.

10 подсказок для создания хороших форм

Формы - одна из самых скучных вещей, с которой приходится работать любому веб-программисту. Но несмотря на то, любим мы заниматься формами или нет, часто именно работа с формами определяет, будет ли пользователь пробовать то что вы ему предлагаете или просто покинет сайт. Несмотря на многообразие обстоятельств, здесь вы найдете 10 подсказок, которые помогут превратить форму из "обычной ванилы" в "двойную шоколадную порцию с зефиром". Приступим!

О примерах


Примеры, указанные ниже, не будут работать "как есть". Все они зависят от внешней библиотеки Prototypes.js,с включенной функцией addEvent. В дополнение, функции указанные ниже должны быть присоединены к событиям, таким как onclick или onmouseover. Обратите внимание на полные тексты примеров, доступные для скачивания.


1. Помните о ваших возможностях


Многие люди забывают использовать все возможности по работе с формами. Мы акцентируем ваше внимание на нескольких HTML элементах, которые созданы специально для форм. Просто освежим наши знания:

Метка (Label)

Конструкция Label используется для прикрепления информациик к элементу. Если вы наведете фокус на метку, фокус будет переведен на элемент, с которым она ассоциирована. Это полезно, когда пользователи кликает на названии элемента и получает фокус на самом элементе.

<label for="email">Email: </label>
<input type="text" id="email">

или

<label>Email: <input type="text" id="email"></label>

Fieldset

«Fieldset - элеменит, который позволяет тематически сгруппировать элементы управления или метки. Группировка элементов позволяет пользователю легче понять их назначение. Фактически группировка позволяет определить tab-порядок для визуальных приложений, и голосовую навигацию для звуко-ориентированных приложений. Основное назначение элемента сделать документ более удобным.»

Рекомендации W3C

Legend

«Элемент Legend позволяет автору назначить название элементу FIELDSET. Legend увеличивает удобство когда FIELDSET не отображается визуально.»

Рекомендации W3C

Tabindex

«Этот аттрибут определяет порядок элемента для tab-порядка текущего документа. Это значение должно быть между 0 и 32767. Пользовательские приложения будут игнорировать ведущие нули. Tab-порядок определяет порядок, в котором элементы будут получать фокус когда навигация пользователем осуществляется через клавиатуру. Tab-порядок может включать элементы, которые наследуются другими элементами.»

Рекомендации W3C


Accesskey

«Этот аттрибут назначает клавишу доступа для элемента. Клавиша доступа - это одиночный символ из кодировки документа. Обратите внимание, что автор должен иметь ввиду метод ввода в документе, определяя клавишу доступа.»

Рекомендации W3C


2. CSS


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

Style Those Buttons - Вы узнаете как сделать "те самые" кнопки для форм более привлекательными

Niceforms - Работа, призванная помочь формам не быть настолько невыносимыми, иногда используя CSS действия

Hide optional Fields
- в этом примере CSS и JavaScript используются для того чтобы сделать ваши формы красивее и удобнее

CSS Forms - Джеф Хоуденс показывает как сделать классную форму без помощи таблиц


3. AutoTab


Когда происходит перемещение по форме, пользователь традиционно нажимает Tab клавишу для того чтобы перескочить к следующему элементу. Функция AutoTab, описанная ниже, автоматически переводит фокус на следующий элемент, когда элемент полностью введен (ориентируясь на максимальный размер элемента - maxlength). Это позволяет пользователю больше не переходить на следующие элементы самостоятельно, когда весь элемент введен. Эта функция особенно удобна в тех случаях, когда пользователю предлагают ввести ограниченно количество символов, например, для номера телефона. Когда пользователь закончит вводить код для региона, он автоматически перейдет для ввода остальной части номера без прерывания в воде.

Для того чтобы указать, что фокус элемента ввода будет переведен на следующий автоматически, мы должны включить в него три вещи: tabindex, class="autoTab" и указать maxlength:

<input type="text" name="areacode" class="autoTab" tabindex="1" maxlength="3"  />

После загрузки страницы будут подключены события для поля ввода для автоперевода фокуса. Если у элемента будет указано свойтво maxlength и элемент будет полностью заполнен, фокус автоматически будет переведен на следующий элемент, с большим значением tabindex. Давайте взглянем на нашу функцию, autoTab():

function autoTab(e) {
if(this.value.length == this.getAttribute("maxlength") &&
e.KeyCode != 8 && e.keyCode != 16 && e.keyCode != 9) {
new Field.activate(findNextElement(this.getAttribute("tabindex")));
}
}

function findNextElement(index) {
elements = new Form.getElements('shippingInfo');
for(i = 0; i < elements.length; i++) {
element = elements[i];
if(parseInt(element.getAttribute("tabindex")) == (parseInt(index) + 1)) {
return element;
}
}
return elements[0];
}

Две вещи, которые хотелось бы отметить:

Вы также можете использовать input.form[(getIndex(input)+1)].focus(), но в этом случае получите сообщение об ошибке в Firefox. Пример можете посмотреть на The Javascript Source.

Когда пользователь нажмет shift-tab фокус перейдет на предыдущий элемент, и autotab автоматически выключится


4. Информация о полях для ввода


Это хорошая практика, когда вы информируете пользователя о требованиях и ограничениях к полям. Ну как еще по-другому пользователь должен узнать, скажем, что длинна пароля должна быть не меньше трех символов? Вдохновленные формами, использованными на Tangent, мы возвращаемся к нашей задаче с новыми идеями:

Храните всю нужную информацию о поле в тэге label. Вы можете указать название класса, клавишу доступа и описание в элементе title.

Мы используем onfocus впротивовес onmouseover, когда информация отображается пользователю.

Проще, когда id метки похож на id поля к которому он относятся. Для примера, поле с названием fname обращается к метке lfname. Это делает задачу по работе с информацией о полях в JavaScript более простой. К примеру:

p = document.createElement("p"); p.innerHTML = $("l" + this.id).title; span.appendChild(p);


5. Отображение ошибок


Когда пользователь сделает ошибку, ваша задача показать ему это быстро и эффективно. Вот несколько идей для того чтобы сделать отображение информации об ошибках в форме немного лучше:

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

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

Вы должны помнить о трех вещах: 1) Вы можете выдавать нужную информацию пользователю через JavaScript. Пользователь получит дополнительное удобство, но вы должны будете сдублировать ваши функции проверки как на стороне клиента, так и на стороне сервера. 2) Вы можете использовать Ajax проверку, которая избавляет, скажем, от ввода одинаковой информации, но это увеличвает нагрузку на сервер. 3) Вы можете проверять информацию только после отправки формы, что снизит нагрузку на сервер, но уменьшит удобство для пользователя.

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


6. Повторное заполнение данных


Нет ничего хуже, чем, в случае ошибки вводить всю информацию в форму заново. Сохраняйте в полях верно введенную информацию. Это также касается многостраничных форм - удобно вернуться на несколько шагов назад и произвести минимально-необходимые исправления, если нужно. К примеру:

<input type="text" name="fname" value="<? echo htmlspecialchars($_POST["fname"]) ?>" />


7. onFocus


Визуальные сигналы, такие как изменение цвета рамки поля, помогают понять пользователю какой элемент формы сейчас активен. CSS предоставляет простое решение для добавления, скажем, рамок, при помощи border селектора, но эта возможность поддерживается не во всех версиях IE, и эта схема не работает на всех элементах формы. Наше решение - выделение элемента за счет добавления span для каждого элемента формы, используя простой JavaScript.

Не беспокойтесь, вам не придется писать руками код для каждого span-элемента. Наша скромная JavaScript функция автоматически добавит нужную информацию о внешнем виде активного элемента и скроет ее в случае необходимости. Примечательно, что наш span блок может также иметь фоновую картинку или любую другую нужную комбинацию эффектов, которая будет работать и для элементов text, textarea, select. Вот как примерно все это выглядит:

<span class="focus">
<input type="text" id="fname" name="fname" />
</span>

function showFocus() {
this.parentNode.className = "focusHover";

function hideFocus() {
this.parentNode.className = "focus";
}

Нам необходимо хранить состояние элемента span для того чтобы на странице не было подергивания. К примеру, если наш span имеет 3 пикселя отступа для события onfocus, нам нужно 3 пикселя для невидимого отступа когда нет фокуса на элементе, т.о. мы не будем наблюдать "прагающий" элемент когда пользователь перемещается с одного на другой.


8. Нажатие на элементе Label


Когда элемент Label получает фокус, через onclick или acceskeys, связанный с меткой элемент также получит фокус.

Когда элемент LABEL получает фокус, он передает фокус на ассоциированный с ним элемент

Рекомендации W3C

К сожалению, это не работает во всех браузерах. Чтобы решить проблему, воспользуемся небольшой JavaScript функцией:

function initLabels() {
labels = document.getElementsByTagName("label");
for(i = 0; i < labels.length; i++) {
addEvent(labels[i], "click", labelFocus);
}
}

function labelFocus() {
new Field.focus(this.getAttribute('for'));
}


9. Двойной Submit


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

Если javaScript активен, используйте его чтобы заблокировать кнопку для нажатия.

Если JavaScript не доступен, сообщите пользователю о том, чтобы он не нажимал кнопку дважды

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


10. Послесловие


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

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

Combo Box - Элемент, упущенный в HTML, наполовину SELECT, наполовину TEXT. Этот элемент позволяет пользователю выбрать значение из списка, или ввести новое если таковое отсутствует. Взгляните на статью "Обновите ваш элемент Select до Combo Box" чтобы узнать как решить данную проблему.

Визуальные карты - как и всплывающий календарь, всплывающие карты могут быть также эффективны. Взгляните на Orbitz, и перейдите по ссылке выбора аэропорта. Это перебросит вас к списку всех аэропортов. Проблема выбора аэропорта может быть решена по-другому, используя карту для выбора из списка и сокрытия всех значений после выбора нужного аэропорта.

Здесь мы перечислили некоторые идеи для того чтообы вы смогли начать эффективно работать с формами. Если у вас есть какие-либо новые идеи, пожалуйста, дайте нам знать!

Источник: http://particletree.com/features/10-tips-to-a-better-form/


пятница, 22 декабря 2006 г.

Linux Format выложен в свободный доступ

C учетом того, что Линукс набирает все большую популярность как в фирмах, так и в гос. учереждениях, знание этой ОС медленно, но верно превращается в де-факто для любых IT-специалистов. И наверняка многие пользователи Линукса знают и читают единственное издание в России, посвященное Linux - Linux Format. Рад сообщить всем тем, кто еще не знаком с этим изданием, что редакция любезно выложила в свободный доступ для скачивания первые четыре выпуска этого журнала. Номера доступны в pdf формате.


четверг, 21 декабря 2006 г.

Обзор Drag&Drop библиотек для JavaScript

В данной статье приведен обзор наиболее известных Drag&Drop библиотек.
Dragable RSS boxes (сайт, пример)

Этот скрипт использует Ajax для того чтобы читать данные из внешних RSS источников и показывать их содержимое в перетаскиваемых блоках. Также вы можете создать новый блок динамически прямо на странице. Т.к. библиотека выпущена недавно, ждите появление новго функционала в ближайшее время.



DOM Drag (сайт, пример)

DOM Drag - это легкое и простое в использование API для всех современных DHTML браузеров. На данный момент проект находится в стадии более экспереметнального, поэтому не рекомендую его использовать в профессиональных приложениях. С другой стороны, эта библиотека может быть полезна для использования в простых проектах, где нужны минимальные возможности Drag&Drop.



Walterzorn Drag&Drop (сайт, пример)

Кросс-браузерная JavaScript библиотека, которая добавляет функциональность Drag&Drop для любых слоев или к изображениям. Вы можете ограничить наличие элементов, которые можно передвигать, изменить курсор или указать сразу несколько картинок доступных для перемещения. Скрипт работает практически во всех браузерах, не считая нескольких наиболее редко используемых.



X Library (сайт, пример)

Ничем не примечательная Drag&Drop библиотека



Drag-and-Drop extension for Prototype (сайт, пример)

Эта библиотека позволит не только использовать технику Drag&Drop, но еще позволит сортировать перемещаемые элементы. Укажите какие элементы можно использовать в качестве перемещаемых, а также элементы которые можно вставлять в требуемые блоки. Используйте сортировку (элементы, дети которых могут быть отсортированы внутри своего родителя).



Toolman DHTML (сайт, пример)

Используйте эту простую библиотеку если захотите создать простую по функциональности свою собственную



Rico (сайт, пример)

Одна из самых богатых по возможностям библиотека для расширенной функциональности ваших приложений. Rico предоставляет полную поддержку Ajax, полное управление перемещаемыми объектами и поддержку кинематических эффектов.



DragLib (сайт, пример)

Полезен, если хотите быстро создать какой-либо элемент на странице перемещаемым.



Yahoo User Interface Library (сайт, пример)

Позволяет все внимание сконцентрировать на логике ваших приложений, т.к. для использования API вам часто понадобится всего лишь пар строк кода. Поддерживает широкий набор стандартных элементов для перетаскивания.


Оригинал: http://www.ajaxpath.com/drag-and-drop



Смотрите также:
Anatomy of a Drag and Drop




среда, 20 декабря 2006 г.

Редактирование на месте при помощи Ajax и Prototypes

В этой статье я покажу вам как использовать популярный файл Prototype.js чтобы использовать Ajax-технику, называемую "редактирование на месте", но для начала, давайте подробно рассмотрем саму технику. Редактирование на месте, как и множество других Ajax функций, использует XmlHttpRequest объект для того чтобы вызвать внешнюю страницу, отправить и получить от нее информацию. Первым делом я познакомлю вас с архитектурой этого приложения. Т.к. мы используем базу данных и PHP для создания слоя обмена данными, начнем так:

Самый первый слой - MysqlDB класс, который содержите необходимые методя для работы с базой данных. В то время как наша статья ставит основной целью объяснение техники редактирования на месте, и, в частности, использование Ajax, мы сконцентрируем наше внимание на brains.php, который содержит Ajax_Interface PHP класс (который, как вы могли уже заметить, наследет MysqlDB класс). На верхнем уровне происходит вызов index.php, который включает в себя brains.php, а так же functions.js и prototype.js. Когда brains.php включается в файле index.php, происходит инициализация методов, которые теперь могут быть использованы в index.php.

Давайте продолжим, обращая наше внимание на следующие PHP файлы: Ajax_Interface.php и brains.php. Вообще в этом приложении я решил не пользоваться классами. Для начана взглянем на функцию print_records() - она устанавливает значения для страницы после загрузки, показывая что сейчас хранится в базе данных.

function print_records() {

$this->get_records();
$products = $this->rs;
$id = $products['product_id'];
$name = $products['name'];

do {
$id = $products['product_id'];
$name = $products['name'];
$field = 'field_'.$id;

echo '<input type="text" name"?" id="'.$id.'" value="'.$name.'"
onClick="changeClass(\''.$id.'\', \'show\')"
onBlur="changeClass(\''.$id.'\', 'hide\')"
onKeyPress="checkLength(this)" class="text" maxlength="60" readonly />';
echo "\n";
} while ($products = $this->fetch_array($this->result));
}


Здесь мы использовали цикл чтобы выывести каждую строку из базы данных.Обратите внимение, что события onBlur и onClick - это основа нашей техники. Когда происходит событие onClick функция изменяет текст на поле для ввода (changeClass). Событие onBlur заканчивает процесс обновления текста, используя ту же самую функцию. Давайте взглянем на changeClass:

function changeClass(id, action) {
if (action=="hide") {
$(id).className = "text";
save(id);
} else {
$('status').innerHTML ='';
$(id).className = "input";
$(id).readOnly = false;
}
}


Нажимая на тексте, мы изменяем CSS класс и получаем поле для ввода. Когда мы теряем фокус (событие onBlur), мы переключаем наше поле обратно в не-редактируемому виду. Обратите внимание на функцию save(), которая вызывается после того как произошло событие onBlur:

function save(id){
var new_content = $F(id);
var success = function(t){
$('ddiv').innerHTML = t.responseText + 'supposed to be here';
}
var failure = function(t){ alert('update failed'); }
var url = 'http://localhost/ajax/prototype/include/brains.php';
var pars = 'edit=go&content='+new_content+'&product_id='+id;

var myAjax = new Ajax.Request(
url,
{
method: 'get',
parameters: pars,
onComplete: update_page
} );
}


Обратите внимание на функции S() и $F(). Эти функции служат для более короткого и удобного обращения к элементам DOM. Если вы не еще не знакомы с этими функциями и хотите больше узнать о возможностях Prototype.js, рекомендую прочитать основы работы с Prototypes на русском или ознакомиться с документацией по этой библиотеке.

Теперь давайте взглянем на переменные url и parts. Url - адрес, который будет вызван, parts - параметры, переданные по этому адресу. После создания Ajax-запроса (функция из Prototypes), мы устанавливаем для события onComplete функцию, которая вызовет обновление страницы. Давайте глянем как будет обработан наш запрос со стороны PHP:

if ($_GET['edit'] == 'go')  {
$result = $ai->save();
header('Content-Type: text/xml');
// создаем XML заголовок
echo '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>';
echo "<response>";
echo $result;
echo "</response>";
}


Когда мы получаем уведомление о необходимости изменить данные через $_GET переменную, мы вызываем метод $ai->save(). Этот метод просто получает текущий элемент для редактирования и обновляет базу данных на основе данных, полученных из вызова объекта XmlHttpRequest. Затем мы возвращаем данные полученные из базы данных в виде xml:

function save() {
$query = 'update product SET name="'.$_GET['content'].'"
where product_id = '.$_GET['product_id'].' LIMIT 1';

$this->query($query);
$output = '<pID>'.$_GET['product_id'].'</pID>.
<value>'.$_GET['content'].'</value>';

return $output;
}


Последнее, что я хотел бы вам показать - как происходит обновление div-а, который будет содержать обновленную информацию из базы данных:

function update_page(originalRequest) {
var rXML = originalRequest.responseXML;
var pIDs = rXML.getElementsByTagName('pID').item(0);
var pID = pIDs.firstChild.data;

//предупреждаем('i have ' + pID + ' to update');
var values = rXML.getElementsByTagName('value').item(0);
var value = values.firstChild.data;
//предупреждаем('i have ' + value + 'as a return value');

$(pID).innerHTML = value;
$('status').innerHTML = 'update complete';
}


Первым делом я разделил xml информацию по названиям нод. Я так же обновил div, который при первой загрузке страницы был пустым (div select), для того, чтобы вы могли увидеть текст "обновление завершено" после завершения обновления. Но самое главное - я обновил содержание измененного элемента.

Скачать полный исходный код примера.

Оригинал: phpbuilder.com


вторник, 19 декабря 2006 г.

Введение в Prototype

JavaScript продолжает завоевывать популярность во всем интернете, и на сегодняшний день мы можем быть уверены в скорости, надежности и удобстве его использования. Разумным решением было бы использовать некую основу, которая пригодилась бы нам в наших проектах. Именно за это мы благодарны Сэму Стефенсону - человеку, создавшего Prototype.js - потрясающую библиотеку функций, которая упростит нашу работу в JavaScript.

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

Приступим!

После того как вы скачали нужные файлы и положили их в нужную директорию, все что вам нужно, чтобы включить Prototype в ваш html-код, например так:

<script src="/scripts/prototype.js" type="text/javascript"></script>


Обратите внимание, только что программирование на javascript стало в 10 раз легче! Давайте же поскорее узнаем что за возможности появилось в наших руках!

Функция $()

Наиболее используемая функция, предоставляет простой путь для получения дескриптора DOM элемента. Обычно, если вы хотите получить доступ к DOM элементу, вы делаете что-то вроде:

node = document.getElementById("elementID");


Использование $() поможет делать это проще:

node = $("elementID");


Другая замечательная сторона этой функции - то что она более мощная нежели document.getElementById(), т.к. в функцию встроена возможность получать доступ к нескольким элементам сразу:

allNodes = $("firstDiv", "secondDiv");
for(i = 0; i < allNodes.length; i++) {
alert(allNodes[i].innerHTML);
}


В этом примере мы использовали функцию $() для получения массива элементов, который затем может быть обработан, скажем, в цикле.

Работа с формами

Работа с формами - полное д_рьмо не только со стороны HTML/CSS, но и в JavaScript. Prototype.js предоставляет удобные методы работы с формами, которые сделают вашу жизнь более веселой.

Функция $F() возвращает значение элемента формы по его ID. К примеру возьмем простую форму:

<input type="text" id="textfield" name="textfield" />
<textarea rows="5" cols="5" id="areafield" name="areafield"></textarea>
<select id="selectfield" name="selectfield">
<option value="1" selected>One</option>
<option value="2">Two</option>
</select>
<input type="checkbox" id="checkfield" name="checkfield" value="1" checked />


Для того, чтобы получить значения элементов, воспользуемся $F():

$F("textfield");      // возвращает значение text input
$F("areafield"); // возвращает значение textarea
$F("selectfield"); // возвращает выбранное значение select
$F("checkfield"); // возвращает null если не установлена, иначе значение


В большинстве случаев получать значение элемента формы через эту удобнее, чем напрямую. Но есть пара "заморочек" которые я обнаружил:
- как и прежде, нет простого способа получить значени radio group элемента (только конкретное значение каждого radio элемента)
- нельзя передать сразу несколько ID, как вы это делали в $()

Другая функция, Form.getElements() вернет в массиве значение каждого элемента формы, не обращая внимания на тип элемента:

allNodes = Form.getElements("myform");
for(i = 0; i < allNodes.length; i++) {
//делаем что-то для каждого элемента формы
}


В этом примере мы получили все значения формы c id="myform". Если вы хотите обработать событие onclick для каждого элемента или показать вспывающее окно, вы можете это сделать как указано выше.

Следующий метод, который мы рассмотрим - Form.serialize(). Когда вы строите Ajax запрос, часто вам приходится приводить к нужному формату вашу POST строку, чтобы передать данные. Когда вы жмете submit строка уже построена. serialize() сделал этот процесс удивительно простым:

allNodes = Form.serialize("myform");

// возвращает field1=value1&field2=value2&field3=value3 и т.д...


Построение строки для нас - бесспорно удобно, но что делает эту функцию поистине замечательной, то что она работает со всеми типами элементов. Выше мы видели, что $F() имеет некоторые проблемы с использованием radio groups, но serialize() делает работу с элементами, независимо от типа, полностью корректной.

getElementsByClassName()

Не могу понять, почему до сих пор в JavaScript не реализована эта функция. Но Prototype.js добавляет getElementByClassName(), расширяя объект document. Функция работает практически так же, как document.getElementsByTagName(). Различие в том, что нашей функции как параметр надо передать название класса:

allNodes = document.getElementsByClassName("red");
for(i = 0; i < allNodes.length; i++) {
alert(allNodes[i].innerHTML);
}


В массиве возвращаются все элементы, которые соответствуют указанному классу. Функция работает даже в том случае, если для элемента определено несколько классов. getElementByClassName() используется во многих проектах, в основном для того чтобы задействовать нужное DOM событие. Я верю, что вы найдете ее полезной!

Работа с элементами

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

Получение высоты элемента без дополнительных функций:

$("first").offsetHeight


А теперь воспользуемся ими:

Element.getHeight("first")


В этом примере новая функция не предоставила никаких преимуществ. Но что если мы хотим, скажем, убрать className из элемента? Это обычный путь (взято из Prototype.js):

element = $(element);
if (!element)
return;
var newClassName = '';
var a = element.className.split(' ');
for (var i = 0; i < a.length; i++) {
if (a[i] != className) {
if (i > 0)
newClassName += ' ';
newClassName += a[i];
}
}
element.className = newClassName;


А теперь с помощью вспомогательной функции:

Element.removeClassName("elementID", "red");


Круто, не правда ли? Не беря во внимание первый пример, вспомогательные функции позволяют экономить море времени, делая общие задачи проще. Для простоты и удобства я рекомендую использовать эти функции на протяжении написания всего проекта. Посмотреть полный список функций, и информацию об их использовании вы можете на странице документации Prototype от Sergio (англ. версия).

Функция Try.This()

Try.This() - замечательная функция, которая помогает разработчикам создавать код, работающий независимо от реализации JavaScript в различных браузерах. Чтобы вам не пришлось самостоятельно определять тип объекта или браузера, эта функция будет пробовать выполнять часть кода пока не произойдет ошибка, а затем переходить дальше:

return Try.these(
function() {
alert("первый");
jkgjhgjhg //преднамеренная ошибка
alert("первая ошибка");
return 1;
},
function() {
alert("второй");
return 2;
}
);


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

Поддержка Ajax

Сейчас я покажу вам как мы можем создавать Ajax-приложения при помощи Prototypes.js. В соответствии с документацией обычный Ajax-запрос может быть реализован так:

var myAjax = new Ajax.Request(
url,
{method: 'post', parameters: data, onComplete: ajax_response}
);


Где используемый метод post или get, а параметры - пары имя/значение объединенные в строку и onComplete() - функция, которая будет вызвана когда вызов закончится. Один раз разобравшись с работой этого метода легко сделать повторяющиеся Ajax-вызовы путем создания ваших собственных функций. Для начала просто пример, который создает Ajax-запрос:

function ajax_request(url, data) {
var myAjax = new Ajax.Request(
url,
{method: 'post', parameters: data, onComplete: ajax_response}
);
}


И после того как запрос закончится, отправим его ответ в ajax_response().

function ajax_response(originalRequest) {
if(!bHasRedirect) {
//process originalRequest.responseText;
}
else {
bHasRedirect = false;
ajax_request(originalRequest.responseText, "");
}
}


После того как вы создали Ajax-запрос, ответ всегда будет получен в ajax_response(). В дальнейшем будет выполнен другой Ajax-запрос, если bHasRedirect установлен (true), или будет запущен код на основе глобального массива функций и метода originalRequest.responseText() (возвращаемое значение).

PeriodicalExecuter

Этот объект после инициализации повторно вызывает требуемую функцию с заданным интервалом времени. Удобно, когда вы хотите автоматически обновить часть сайта.

function periodicalUpdate() {
new PeriodicalExecuter(refreshNews, 10);
}

function refreshNews() {
//Ajax код для слива новостей и обновления DOM
}


Конструктор PeriodicalExecuter получает название функции для выполнения как первый параметр и интервал выполнения в качестве второго. Обратите внимание, наша функция получает промежуток времени в секундах (стандартная функция setInterval() использует миллисекунды в качестве параметра). Хочу заметить, что этот пример может использоваться для любых целей - не только в связке с Ajax. Для использования вместе с Ajax удобнее пользоваться классом Ajax.PeriodicalUpdater.

В данном руководстве вы найдете все методы или функции, которые предоставляет Prototype.js, но есть некоторые функции, которые тоже хотелось бы упомянуть (Все они могут быть найдены в документации):

observe - функции этого метода подобны addEvent(), но используются для того чтобы аккуратно присоединять события к DOM

User Iteraction - вы можете обнаружить встроенные глобальные значения, такие как KEY_TAB, для того чтобы понять какую клавишу нажал пользователь. Так же вы можете получить координаты мыши и информацию о нажатых на ней кнопках.

Class Creation - зачем останавливаться на функциональности Prototype.js? Используя похожий синтаксис и функции мы можем построить свой собственный класс, чтобы держать все по полочкам. Добавление конструктора и дополнительных методов еще никогда не было столь простым. Смотрите Class.Create() в документации.

Обобщая вышесказанное

Разве допустимо использование публичного кода/библиотек, если вы не знаете автора и досконально не разбираетесь в том, что творится "за кулисами"? Мой ответ - да, до тех пор пока вы более или менее тестируете код и доверяете человеку/сообществу, которые стоят за разработкой всего этого. В случае Prototype.js такая уверенность складывается из двух частей. Во-первых Ruby on Rails интегрировали поддержку Prototype.js. С тех пор как Ruby on Rails имеет надежную команду разработчиков, было найдено и исправлено огромное количество багов, за счет чего Prototype.js стала еще более стабильной. Во-вторых - разработчик работающий на 37signals. Я доверяю не только практике разработки программ какой-либо фирмы, но я верю что в дальнейшем Prototype.js будет и дальше тестироваться и становиться лучше. Вдобавок ко всему, я сам продолжаю тестировать эту библиотеку и теперь уже использую практически во всех своих проектах.

Prototypes.js это намного большее, чем описано в этой статье, и его действительно стоит попробовать! Если вас возмущает размер файла (30 кб, примерно как этот текст), помните, что вы всегда можете убрать классы, которые вы не используете или сжать JavaScript при помощи PHP перед отдачей пользователю. Prototypes.js совсем не сложен при изучении. И не забудьте - это всего лишь вводная статья, если вы хотите узнать побольше информации, посетите неоффициальную документацию Prototype и script.aculo.us wiki-документацию.

Оригинал статьи: http://particletree.com/features/quick-guide-to-prototype


понедельник, 18 декабря 2006 г.

Кросс-браузерный перехват событий Javascript и утечка памяти

В "старой школе" вы обычно регистрировали событие путем установки соответствия свойству onevent DOM элемента.

elem.onclick = function() {
alert("You clicked me");
}

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

function addEventListener(instance, eventName, listener) {
var listenerFn = listener;
if (instance.addEventListener) {
instance.addEventListener(eventName, listenerFn, false);
} else if (instance.attachEvent) {
listenerFn = function() {
listener(window.event);
}
instance.attachEvent("on" + eventName, listenerFn);
} else {
throw new Error("Event registration not supported");
}
return {
instance: instance,
name: eventName,
listener: listenerFn
};
}

function removeEventListener(event) {
var instance = event.instance;
if (instance.removeEventListener) {
instance.removeEventListener(event.name, event.listener, false);
} else if (instance.detachEvent) {
instance.detachEvent("on" + event.name, event.listener);
}
}

Пример использования вышеуказанных функций:

var elem = document.getElementById("elem");
var listener = addEventListener(elem, "click", function() {
alert("You clicked me!");
});
removeEventListener(listener);


Несмотря на то, что этот рецепт работает во всех браузерах, Internet Explorer имеет в своем арсенале огромное количество багов, связанных с утечкой памяти и наше использование регистратора событий только обостряет ситуацию. Сама по себе проблема эта комплексная (тонкие взаимодействия между закрытиями функции и COM), но мы можем дополнить вышеуказанный рецепт при помощи глобальной функции де-регистрации, которая устранит проблему утечки памяти в большинстве случаев:

var __eventListeners = [];

function addEventListener(instance, eventName, listener) {
var listenerFn = listener;
if (instance.addEventListener) {
instance.addEventListener(eventName, listenerFn, false);
} else if (instance.attachEvent) {
listenerFn = function() {
listener(window.event);
}
instance.attachEvent("on" + eventName, listenerFn);
} else {
throw new Error("Event registration not supported");
}
var event = {
instance: instance,
name: eventName,
listener: listenerFn
};
__eventListeners.push(event);
return event;
}

function removeEventListener(event) {
var instance = event.instance;
if (instance.removeEventListener) {
instance.removeEventListener(event.name, event.listener, false);
} else if (instance.detachEvent) {
instance.detachEvent("on" + event.name, event.listener);
}
for (var i = 0; i < __eventListeners.length; i++) {
if (__eventListeners[i] == event) {
__eventListeners.splice(i, 1);
break;
}
}

}

function unregisterAllEvents() {
while (__eventListeners.length > 0) {
removeEventListener(__eventListeners[0]);
}
}


Функция unregisterAllEvents удаляет события глобально, удаляя связи между DOM объектом и слушающей функцией и тем самым решает проблему в большинстве случаев. Чтобы воспользоваться дополнительным преимуществом этой функции, вызывайте ее при возникновении события onunload:

<body onunload="unregisterAllEvents()">

Пример перехвата событий

Источник: http://ajaxcookbook.org/


воскресенье, 17 декабря 2006 г.

CMS для разработчика (продолжение темы на livejournal.com)

На одном из блогов лайвжорнала меня привлекла идея автора создания системы управления сайтами для программистов. Что это такое (по мнению автора) - эта система, которая позволит каждому программеру быстро создавать проекты опираясь на какое-то ядро, общую систему, и т.д. По сути развитие PHP как ранее сам PHP был вырожден из набора библиотек для Perl.

Саму идею создания такой универсальной среды я отвергаю. Если говорить о продолжении эволюции развития языков программирования, то тенденцию и сами различия уже весьма заметны. Именно PHP ставит своей задачу создание веб-приложений. Но есть ряд пунктов, которые в состоянии помочь решать поставленные задачи перед программистами:

  • часто чтобы решить поставленную задачу достаточно взять напильник и доработать уже готовую CMS. Проблема одна - не много людей готовы потратить день своей жизни для изучения открытых систем. Лучше за месяц написать "свое"
  • если нужные архитектурные решения слишком отличаются (болишие уникальные проекты или проекты под нагрузкой) - основа делается разработчиком (можно ее оставить еще для нескольких проектов)

Универсальной системы ни здесь ни там никогда не получится. Но система управления для разработчика есть! Это просто!

  • документируйте
  • учитесь писать понятные алгоритмы
  • сужайте круг поставленных задач, не пишите бесполезные части, "делай меньше, но качественно"

И будет вам счастье!



Воскресенье на работе

Сегодня моя super-girl весь собирается на весь день занять комп, так что пришлось ехать на работу чтобы продолжить заниматься программингом. Уже подходя к офису увидел художника, который закутавшись в курску (сегодня в Питере ноль градусов - холодно) писал пейзаж улицы. Никогда ничего интересного на этой улице не находил. Немного удивлен.

А тем временем вышла Opera 9.10. Среди изменений (слито с linux.org.ru):

  • плавная прокрутка теперь работает;
  • появление защиты от фишинга (по умолчанию отключено);
  • исправление проблем с горизонтальной прокруткой на некоторых сайтах (adobe.com);
  • повышение стабильности;
Хоть пытался себя переучить на Оперу с Firefox, ничего не получается. Закоренелая привычка.

Для разработчиков на javascript будет интересно узнать о недавно открывшемся блоге Брета Тейлора. Кроссбраузерность, события и т.п. Для досуга ;-)


Сейчас пол-второго ночи. И, кажется, появился еще один блог

Вначале хотел написать размышления на тему "почему каждый человек" хочет создать свой блог, сразу плюнул на эту идею.. неинтересно... Но начал все с того, что искал место, где моему блогу будет лучше жить. Все-же на блоггере приятней. Вообще вибирал одно из 2х: либо на лайвжорнале (livejournal.com) или здесь. На лайве каким-то чудом остался какой-то старый, зарегистрированный ранее аккаунт. Решил зайти и посмотреть что они мне предлагают (все же как данность профессии предъявлять большую требовательность к сервисам по сравнению со "смертными" - это уже обыденность. Хотя.. Быть может это скорее к вопросу о пристрастиях.) Море рекламы (да-да, я помню что от нее можно отказаться в момент регистрации - в убыток своему развязанному поведению на сайте), херовенькие дефолтные темплейты. Админка... Бее.. Нет уж! Единственный плюс который заметил - большинство товарищей на лайвжорнале, ну да и Бог с ними! Может получится их сюда перетащить (товарищи, моя совесть чиста! Поверьте! ;-)

По своей природе приходится программировать на PHP каждый день, это и хобби, и работа. Но в будущем я не хочу быть просто прочитанным дневником, общение с со-товарищами - это круто!