10/20/2006

Event Handlers on Disabled Inputs by Ryan Campbell [russian translation]

Original article

Обработчики событий на disabled полях формы


Мы попали в интересную ситуацию на прошлой неделе. У нас есть input поля, которые никогда не получают фокус, но которые должны отвечать на события, такие как onclick, onmousedown, и onmouseup. Чтобы они не получали фокус - мы добавили к ним аттрибут disabled

<input type="text" disabled="disabled" />

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

Решение оказалось простым: ипсользовать readonly вместо disabled

<input type="text" readonly="readonly" />

Из комментариев к статье


Подобная техника работает только с textarea и input type="text"

10/19/2006

Introduction to Events by Peter-Paul Koch [russian translation]

Original article

События- это основа приложений на яваскрипте. В этой статье мы рассмотрим что такое обработка событий, какие проблемы с этим связаны и как писать событийные кроссбраузерные скрипты.

Без событий нет скриптов. Взгляните на любую веб-страницу с яваскриптом на ней: в большинстве случаев вы увидите событие, которое запускает скрипт. Причина очень проста. Яваскрипт предназначен для того, чтобы добавлять интерактивность на ваши страницы: пользователь что-то делает и скрипт реагирует на это.

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

Яваскрипт может ловить некоторые из этих событий. Начиная с Netscape 2 стало возможным вешать обработчики событий на некоторые HTML элементы - по больше части на ссылки и поля форм. Обработчик события ждет возникновения определенного события, например клик на ссылку. А когда это происходит - запускается некий явасрипт, который вы определили в качестве обработчика события.

Когда пользователь выполняет какое-либо действие на странице - он вызывает событие. Когда ваш скрипт реагирует на это событие - возникает интерактивность.

История обработки событий


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

Модель Netscape


Netscape 2 поддерживал только некоторые события. Mouseover and mouseout быстро стали знаменитыми из-за легендарного mouseover effect, который менял изображения. Так же стало возможным отслеживать сабмит или ресет формы, таким образом возникла клиентская валидация форм. Браузер также мог отслеживать получение или потерю фокуса элементами форм, а также начало и конец загрузки страницы. И хотя сейчас - это стандартное поведение браузеров, в то время это было революционным расширением возможностей веб-страниц.

В своей самой древней форме обработчик событий выглядел примерно так: когда пользователь сликал на ссылку, обработчик события выполнялся и показывал alert попап:
<a href="somewhere.html" onclick="alert('I\'ve been clicked!')"></a>

Очень важно понять, что этот древний способ обработки событий стал де-факто стандартизирован Нетскейпом. Все остальные браузеры, включая Internet Explorer, должны были соответствовать способу, придуманному Netscape, и трем обработчикам событий, если они хотели, чтобы пользовательские скрипты в них работали. Поэтому эти древние события и их обработчики работают во всех браузерах с поддержкой яваскрипта.

Современная модель событий


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

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

С тех пор, как эта функциональность была добавлена в разгаре Войны Браузеров, Нетскейп и Майкрософт достигли точки полной несовместимости событийных моделей. Позднее появилась третья модель, когда W3C опубликовала свою DOM Event specification Несмотря на один серьезный недостаток, модель W3C, которая основана преимущественно на старой модели Netscape, была универсальнее и разностороннее, с добавлением новых интересных функциональных возможностей и решившая множество проблем старых моделей.

Естественно, что существование трех моделей привело к тому, что обработка событий не работает одинаково во всех браузерах.

Проблемы браузерной совместимости


Начнем сначала. Как с DHTML, W3C DOM , так и с любой другой скриптовой техникой, мы должны заботиться о том, чтобы наш код работал только в тех браухерах, которые его понимают. Вызов stopPropagation() в IE или srcElement в Netscape породит ужасные ошибки. Таким образом, мы в первую очередь должны проверить - поддерживает ли конкретный браузер методы или свойства, которые мы хотим использовать. По типу:

if (Netscape) {
use Netscape model
}
else if (Explorer) {
use Microsoft model
}

Но это только поверхностное решение, которое оставляет за бортом другие браузеры. Другие браузеры каждый сам для себя решали нелегкую задачу - какую из событийной модели поддерживать. Konqueror/Safari, как всегда, ратовал за стандарты и поддержал W3C модель. Opera и iCab были более осторожны и поддержали большую часть обоих моделей - и старую модель Netscape и модель Microsoft . Я еще не изучал другие малоизвестные браузеры.

Не используйте определения браузера


Первое - НИКОГДА не используйте определение браузера. Это самый быстрый путь в ад :) Любой скрипт, использующий navigator.userAgent для определения событийной модели плох тем, что малоюзабелен, и должен быть как можно скорее переписан.
Второе - не путайте DHTML object detection и event object detection. Когда мы пишем DHTML, мы обычно проверяем поддержку DOM таким способом if (document.all) . Если true, скрипт использует all массив от Microsoft .

Но DHTML и обработка событий имеют разные паттерны совместимости браузеров. Например, Opera 6 поддерживает часть W3C DOM, но поддерживает и W3C Event модель. Следовательно, проверка DHTML объектов приведет к неправильному использованию событий в Opera. Так что использование в скриптах if (document.layers) и подобных для детекта событийной модели - некорректно!

Правильные вопросы



Так что же нам делать? Имена свойств событий порождают массу проблем. If we use a lot of specific object detections in this area, we solve 99% of the browser incompatibilities. Only finding the mouse position, is very hard, accessing other bits of information is simpler.

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

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

Сколько существует событий?

Много. Конечно, некотороые из них не работают в некоторых браузерах.

Как зарегистрировать обработчик события для HTML элемента?

Есть четыре способа для этого: inline, traditional, W3C and Microsoft. первый способ работает во всех браузерах. Никаких проблем с ним.


Как запретить событие по умолчанию у элемента?

Если вы сделаете return false из вашего обработчика события, то действие по умолчанию (редирект по ссылке, сабмит формы) прекратится. Этот способ был стандартизирован Netscape 2 и работает до сих пор.


Как мне получить доступ к событию, если я хочу получить больше инфрмации?[How do I access the event when I want to obtain more information?]

Ест два пути сделать это: W3C/Netscape и Microsoft. Чтобы решить проблему совместимости, вам нужна одна строчка кода


Когда у меня есть доступ к событию, как мне прочитать его свойства?

Здесь есть проблема совместимости. Все правильно, объяснение на этой странице. Вам нужна таблица совместимости свойств событий и some strict object detection.


Если элемент и один из его предков имеют обрабтчики для одного и того же события, какой запустится первым?

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


Is Netscape 4’s event handling model up to supporting interesting scripts?

Not really, though you can execute simple scripts in this browser. See the special Netscape 4 page for the gory details.



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

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

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

Продолжение


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

Написание обработчика событий


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

Регистрация обработчика


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

Есть четыре способа для регистрации обработчика события: inline, traditional, W3C and Microsoft.

Самый лучший - traditional, поскольку он полностью кроссбраузерный и универсальный. Для регистрации сделайте следующее:

element.onclick = doSomething;
if (element.captureEvents) element.captureEvents(Event.CLICK);

Сейчас функция doSomething зарегистрирована как обработчик события click для html-элемента element. Это подразумевает, что как только пользователь кликнет левой клавишей мыши на элементе - выполнится функция doSomething.

Доступ к событию


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

function doSomething(e) {
if (!e) var e = window.event
// e refers to the event
}

Сейчас e ссылается на событие во всех браузерах.

Доступ к html элементу


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

function doSomething(e) {
if (!e) var e = window.event
// e refers to the event
// this refers to the HTML element which currently handles the event
// target/srcElement refer to the HTML element the event originally took place on
}


Свойства target/srcElement содержат ссылку на html элемент, непосредственно над которым произошло событие. Эти свойства очень удобны, но когда событие просачивается или перехватывается, эти свойства не меняются: это по-прежнему ссылка на элемент, непосредственно над которым произошло событие. (Посмотрите Event properties для target/srcElement и эту страницу для ключевого слова this)

Чтение свойств


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

function doSomething(e) {
if (!e) var e = window.event
if (e.keyCode) code = e.keyCode;
else if (e.which) code = e.which;
}

Теперь code содержит код нажатой клавиши во всех браузерах.

Порядок событий


Наконец вы долджны принять решение - разрешать просачиваться событию или нет. Если вы не хотите, прекратите распространение события:

function doSomething(e) {
if (!e) var e = window.event
// handle event
e.cancelBubble = true;
if (e.stopPropagation) e.stopPropagation();
}


Написание скрипта


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

9/26/2006

Objectifying JavaScript by Jonathan Snook [russian translation]

Original article.

Когда я только начинал программировать на Javascript я создавал мои переменные и инкапсулировал функциональность, которая мне нужна, в функцию. Так как мои задачи становились более сложными и я начал изучать OOP в других языках, я увидел преимущества использования OOP в Javascript.

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

В настоящем объектно-ориентированном смысле, объект представляет "a thing". Это может быть изображение, пользователь, документ - все, что угодно, что представлено именем существительным. Объект содержит свойства, которые его описывают и методы, которые описывают действия этого объекта (или что можно сделать с объектом). Например, array в javascript - это объект. У него есть свойства, такие как length, которые хранят информацию об объекте, и методы, такие как push, которые что-то делают с объектом.

Главная идея здесь простая - objects encapsulate related functionality.

В Javascript-е мы часто выполняем серии задач на существующих объектах. Например, валидация формы: "Когда эта форма сабмитится, проверить что пользователь вввел валидный e-mail, телефон и т.д." Вместо создания функции для проверки каждой формы на странице, почему не собрать связанные задачи в объект FormValidator(tm) , для того чтобы можно было легко использовать его на других страницах и других сайтах? Даже задачи, по типу установки onclick события на коллекцию ссылок лучше вынести в объект.

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

  • using the object literal
  • using the new keyword with a function

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

Using the Object Literal


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

Пример:
{
property: value,
property: value
}

Создание объектов:


Для демонстранстрации, давайте создадим новый объект, с тремя свойствами, два хранят числовые значения,третье - это анонимная функция( функция без имени )

var AnimationManager =
{
framesPerSecond: 30,
totalLength: 15,
startAnimation: function(){ /* code goes here */ }
}

Важно понять, что объектный литерал - это просто shortcut для создания объекта, используя встроенный Object-type. Мы изучим этот код более детально позже, а сейчас просто запомним, что мы также можем создать AnimationManager объект следующим образом:

var AnimationManager = new Object();
AnimationManager.framesPerSecond = 30;
AnimationManager.totalLength = 15;
AnimationManager.startAnimation = function () { /* code goes here */ };

Доступ к свойствам объекта


Мы назначили объектный литерал переменной AnimationManager и теперь можем получить доступ к свойствам объекта используя точечную нотацию или скобки. Следующие строки идентичны:

alert(AnimationManager.framesPerSecond); // object.property
alert(AnimationManager['framesPerSecond']); // object['property']

В основном мы будем использовать точечную нотацию, но возможность обращаться к объекту, как к hash-массиву - очень удобная возможность. Например, мы можем написать функцию, которая будет устанавливать значения для полей framesPerSecond or totalLength:

function changeValue(property, value)
{
if (property == "framesPerSecond")
AnimationManager.framesPerSecond = value;
else
AnimationManager.totalLength = value;
}

Или можно использовать возможность доступа к свойствам через скобки:

function changeValue(property, value)
{
AnimationManager[property] = value;
}

Таким образом мы можем упростить код - одна строка вместо серии if-else

Добавление свойств или методов


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

AnimationManager.stopAnimation = function(){ }
AnimationManager.defaultTween = "sinoidal";

You’ll recall that is exactly what we did earlier when we discussed the alternate new Object() syntax for the object literal.

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


В javascript функция - это объект. Создавая функцию - вы создаете объект. Объекты функций более полезны, чем объектные литералы, потому что они могут быть использованы как шаблоны для новых объектов.
Для тех, кто незнаком с OOP, этот объектный шаблон более известен, как класс. В отличие от объектов, которые каждый раз строятся заново, объект, созданный на основе класса - уже заполнен методами и свойствами. Определяя new function object, мы в результате определяем шаблон (blueprint) для новых объектов, которые мы можем использовать снова и снова.
Например, мы создали AnimationManager в передыдущем разделе, используя объектный литерал. Нам действительно нужен только один менеджер, таким образом у нас нет необходимости предоставлять второй механизм. Объектный литерал - отличный выбор для этого объекта. Давайте немного расширим пример и представим, что AnimationManager контролирует множеством объектов Animation. Если мы объявим Animation, используя объектный литерал, нам придется писать этот код еще и еще для каждого анимированного объекта. Создание таких объектов на базе шаблона предоставляет нам решение этой проблемы.

Использование шаблона


Чтобы использовать наш шаблон для создания объекта, мы используем ключевое слово new и вызов шаблона функции, передавая в нее аргументы:

function Animation(element)
{
this.animationLength = 30;
this.element = element;
}
var obj = document.getElementById('login');
var animateLogin = new Animation(obj);

Во время выполнения new Animation(obj) создается пустой объект и вызывается Animation, связывая новый объект с его this ключевым словом. Мы можем связать свойства объекта с егоthis keyword и как результат выполнения функции вернется новый объект со всеми его свойствами. Таким образом новый объект будет имеет два свойства animationLength и element и связан с переменной animateLogin для дальнейшего использования.
Мы также можем создать методы в нашем шаблоне, просто добавляя функции:

function Animation(element)
{
this.animationLength = 30;
this.element = element;
this.onStart = function ()
{
alert("The animation is starting!");
};
this.onEnd = function ()
{
alert("The animation is ending!");
};
}
var obj = document.getElementById('login');
var animateLogin = new Animation(obj);

Важно понять, что мы можем в Animation функцию добавлять свойства как объектные литералы:

function Animate() { }
Animate.animationLength = 30;
Animate.element = element;

Разница здесь в том, что эти дополнительные свойства не являются частью шаблона
Если мы выполним new Animation() из кода выше, мы получим назад пустой объект - не объект с двумя свойствами. Например:

var animateLogin = new Animation(loginform);
Animation.animationLength = 30;
alert(animateLogin.element); // the 'loginform' element
alert(animateLogin.animationLength); // undefined!

Prototype


Метод описанный выше работает замечательно, но он немного непроизводительный. В частности, создание тысячи объектов Animation создаст тысячу копий каждого метода и свойства, занимая ценную память, которую мы могли бы использовать для других вещей ( и создавая возможную утечку памяти). К счастью для нас, есть путь создания шаблонного объекта, который генерит объекты, как ссылки на те же самые методы и свойства: Мы назначаем свойства шаблону через prototype. Поступая таким образом, все объекты, инициализированные из оргинального шаблона могут использовать методы и свойства из прототипа шаблона вместо создания их собственных копий. Короче говоря, вызов свойства объекта в первую очередь проверяет объект на наличие этого свойства, если оно не существует, проверяется прототип шаблона. Таким образом существует только одна версия свойства, сохраненная в памяти, невзирая на то, сколько объектов мы создали.
Синтаксис выглядит почти так же, как добавление свойства для объекта Animation. Вместо Animation.onStart мы добавляем свойство в функцию через свойство объекта prototype: Animation.prototype.onStart. Давайте перепишем Animation объект, чтобы быть увереными, что метода ссылаются, а не копируются:

function Animation(element)
{
this.animationLength = 30;
this.element = element;
}
Animation.prototype.onStart = function()
{
alert("The animation is beginning!");
};
Animation.prototype.onEnd = function()
{
alert("The animation is ending!");
};
var animateLogin = new Animate(loginform);
animateLogin.onStart();

Мы можем добавить в прототип шаблона в любое время и новые свойства будут автоматически доступны, даже если объект был уже создан. Давайте перестроим последний пример для демонстрации:

function Animation(element)
{
this.animationLength = 30;
this.element = element;
}
var animateLogin = new Animate(loginform);
Animation.prototype.onStart = function()
{
alert("The animation is beginning!");
};
Animation.prototype.onEnd = function()
{
alert("The animation is ending!");
};
animateLogin.onStart();

Даже если мы создали новый Animation объект перед тем, как объявили onStart и onEnd методы, мы можем использовать их! Это огромное преимущество способа, сонованного на прототипе.

Объект, как результат выполнения конструктора


Как вы знаете, функции могут возвращать значения. Что интересно, если вы возвращаете объект, как результат выполнения конструктора (функция вызванная сключевым словом new), этот объект будет использован как новый объект вместо пустого только что созданного объекта и назначенного слову this. Любые свойства, которые вы определите В или ВНЕ функции будут недоступны. Пример объяснит это лучше:

function Animation(element)
{
this.animationLength = 30;
return {hello: "Hello, world!"}; // empty object.
}
Animation.prototype.onStart = function() { };
Animation.prototype.onEnd = function() { };

var animateLogin = new Animation(loginform);

animateLogin.onStart(); // undefined!
animateLogin.animationLength; // undefined!
alert(animateLogin.hello); // "Hello, world!"

"В чем фишка", спросите вы? Это позволяет нам создавать приватные переменные, которые доступны внутри нашего объекта, но не доступны снаружи, как только что созданные. Давайте посмотрим на пример с использованием ключевого слова new в функции:

function Animation(element)
{
var looped = 0;
var e = element;

function construct()
{
this.loopCount = function()
{
return looped;
}
this.loop = function()
{
looped++;
}
}
return new construct();
}

var animateLogin = new Animation();

animateLogin.loop();

alert(animateLogin.loopCount()); // it's 1
alert(animateLogin.looped); // undefined!

We created a new function called construct within our Animation function. Anytime we create a newAnimation object, we end up returning a new construct object instead. Это означает, что методы loopCount и loop будут единственными, к кому мы будем иметь доступ. Тем не менее, благодаря замыканиям переменная looped все еще доступна внутри тех функций.

Singletons with functions


Сушествуют ситуации, когда у нас есть центральный объект и нам не нужно предоставлять механизм для создания его новых версий. The singleton design pattern решает эту проблему. В примере, который мы используем, AnimationManager - центральный объект, который должен контролировать когда анимация начинается и заканчивается. We only need one of these, as opposed to the individual animations that require separate Animation objects with unique values. Мы создали AnimationManager с помощью объектного литерала, но вы будете часто встречать singletons implemented with functions. Давайте посмотрим, как это делается:

var AnimationManager = new function()
{
this.framesPerSecond = 30;
this.startAnimation = function(){ /* code goes here*/ }
}

Мы просто вызываем new на анонимной функции и используем this для установки свойств и методов. Создание нового объекта этим путем позволяет избежать потенциального использования объекта, как шаблона. Вуаля, это функция-одиночка! Если мы хотим быть очень осторожными в доступе к свойствам объекта, мы можем даже создать приватные переменные для нашего синглтона, используя ту же технику, что и в предыдущем разделе:

var AnimationManager = new function()
{
var framesPerSecond = 30;
function construct()
{
this.startAnimation = function() {}
this.getFPS = function() { return framesPerSecond; }
this.setFPS = function(fps) { framesPerSecond = fps; }
}
return new construct();
}

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

The Object Factory


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

function objectMaker()
{
return {value:5}
}
var object1 = objectMaker();
var object2 = objectMaker();

Это удобно потому что мы можем выборочно перекрывать значения, распределяя значения одного литерала в другой [by mapping the values of one literal onto another.]
The Prototype JavaScript Framework (не путайте со свойством prototype) поступает именно таким образом со своим Object.extend методом.

9/18/2006

Mozilla feature. Or bug? Hmm..

Сегодня столкнулся со странным поведением Firefox.

Если на странице объявлена форма, у которой есть id, но нет name - браузер Firefox при парсинге страницы сам добавляет к элементу формы name, значение которого берет из его id.

Продолбался около 2 часов, пока нашел эту ошибку у себя в коде - я искал форму по его name. И все это время матерился на IE, который почему-то генерил ошибку. Теперь-то я знаю, что в этом отношении IE - честный браузер, не добавляет аттрибут вместо девелопера.

Блин, медвежья услуга от Mozilla. :(

9/17/2006

Prototype documentation

Где, блин, брать качественную документацию?
Конечно, можно смотреть код Сэма Стефенсона и пытаться понять суть методов.
Но, признаюсь, первый раз открыв его - я мало что понял. Меня поразило то, насколько неудобно отструктурирован код - на каждой строчке спотыкались глаза, плюс использовались странные конструкции, которых я никогда не видел в js (несколько позже я узнал, что код написан в руби-стиле, и спустя некоторое время я признался сам себе, что руби-стиль не менее читаем, чем привычный С-подобный структированный код).

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

Рекомендую обратить внимание на ресурс Sergio Pereira. На сегодняшний день - это самая полная документация библиотеки версии 1.4.0.
Там же есть возможность просмотреть этот документ на других языках.

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

Но кроме Сержио за развитием прототипа следит не один разработчик. Некоторые из них рассказывают на страницах своих блогов о тонкостях использования библиотеки.
На мой взгляд, сюда стоит заглядывать:
http://encytemedia.com/blog/
http://ajaxian.com/by/topic/prototype/
http://particletree.com/
http://www.snook.ca/jonathan/

Кроме этих ссылок, стоит заглядывать на страничку Ronnie Roller, на которой он собирает ресурсы, посвященные прототипу.

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

9/11/2006

Prototype home and repository

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

На сайте библиотеки последней версией называется 1.4.0. Вероятно, она считается супер-стабильной. Но пользоваться ей я бы не рекомендовал, потому что, во-первых, в ней не исправлена проблема утечки памяти в ИЕ, а во-вторых, в ней только 50% тех вкусняшек, которые делают javascript-разработку простой и вкусной.

Если внимательно прочитать все 22 строки текста на сайте, то можно заметить маааленьким шрифтом путь к репозиторию библиотеки:
Checkout with
svn co http://dev.rubyonrails.org/svn/rails/spinoffs/prototype

Там лежат самые свежие исходники библиотеки.

По тому пути меня интересует только один файлик - CHANGELOG - в нем описаны все изменения в текущей версии.
Для того, чтобы получить самую свежую версию библиотеки (а на сегодняшний день это 1.5.0_rc1), я хожу сюда, дальше кликаю в ссылку prototype.js, перехожу на страницу, где показан весь код библиотеки в нумерованном списке и внизу этой страницы нахожу ссылки:
Download in other formats: Plain Text, Original Format

Именно здесь всегда свежий код :)

9/10/2006

Prototype's meeting

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

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

Одна из задач от заказчика - показывать юзеру увеличенные изображения по клику на маленькие иконки этих изображений. Тривиально! Но заказчик захотел показывать это... плавно. Красоты захотел :)

Света мне дала линку на scriptaculous - она когда-то видела, что там можно делать какие-то эффекты. Действительно - добавить плавное увеличение любого блочного элемента оказалось элементарно с помощью этой библиотечки. Спасибо Томасу Фучу :)

Потом уже, копаясь в коде библиотек скриптакулоса, я обнаружил, что они базируются на какой-то странной библиотеке prototype.js. Полез копаться уже в ней и ... прозрел!

Prototype - это относительно легкая, почти безглючная и аафигенно удобная в использовании библиотека, которую я использую под девизом:"Зачем изобретать велосипед? Он уже создан и тысячи людей УЖЕ ездят на нем!"

Читайте дальше. Будет интересно :)

И как говорит Justin Palmer: "Happy prototyping!"