наверное, именно для этой задачи чаще всего используется javascript. Нужно заблокировать кнопку, чтобы пользователь не кликнул её по ошибке, и сделать блокировку заметной, чтобы он даже не пытался. Иногда вместо кнопки блокируется поле ввода.
в идеальном мире задача решается очень просто: element.disabled = true
. Это сделает поле неактивным, а также применит к нему css-правила из селектора [disabled]
. В реальности всенародный браузер не понимает таких селекторов, поэтому на элемент приходится навешивать дополнительный класс, например, disabled
. Впрочем, это имя не всегда устраивает верстальщиков, поэтому хорошо бы иметь возможность задать другой класс.
в посте «стандарты для расширения Element.Methods» был описан шаблон функции для расширения:
function (element) {
element = $(element);
// …
return element;
}
в этот шаблон мы добавляем параметр (опциональное имя класса) и пару строк, выполняющих нужные нам действия:
Element.Methods.disable = function(element, className) {
element = $(element);
element.disabled = true;
element.addClassName(className || 'disabled');
return element;
}
решение почти готово, осталась только одна деталь: в пару к функции блокирования неплохо бы иметь и ее зеркальную противоположность. Она будет отличаться только значением для свойства disabled, и работающим с именем класса методом. А для того, чтобы избежать копипаста, мы применим технику карринга (currying):
function toggle(state, method, element, className) {
element = $(element);
element.disabled = state;
element[method](className || 'disabled');
return element;
};
Element.Methods.disable = toggle.curry(true, 'addClassName');
Element.Methods.enable = toggle.curry(false, 'removeClassName');
здесь используется шаблонная функция четырех параметров, первые два из которых мы фиксируем разными значениями для того, чтобы получить два зеркальных метода. Того же эффекта можно было добиться конструкцией типа disable = function(a, b){ toggle(1, 2, a, b) }
, но метод .curry() на мой взгляд элегантнее и проще читается
extend.js, javascript, prototype.js
мои поиски русских блогов о javascript были сравнительно небезуспешными. Сейчас, просматривая один из обнаруженных блогов, нашел в нем заметку «Три варианта удаления childNodes». Она напомнила мне об одной забавной особенности яваскрипта
наверное, многие программисты на ЯВУ привыкли к тому, что у программного массива есть метаданные, которые можно напрямую прочитать. Но далеко не всем приходит в голову, что эти же данные можно и записать ; )
>>> a = [1, 2, 3]
[1, 2, 3]
>>> a.length
3
>>> a.length = 0
0
>>> a
[]
к сожалению, childNodes — это не массив, а NodeList, поэтому напрямую задать ему длину не удастся:
>>> $1.childNodes.length = 0
setting a property that has only a getter
javascript
Изначально задачей разработчиков prototype было улучшить сам язык. Добавить в него синтаксического сахара, используя существующие возможности javascript, в конечном итоге приближая к ruby. Естественно, при этом решались и проблемы кроссбраузерности, но не они были основными.
Недавно в их листе рассылки увидел своеобразное подтверждение того, насколько хорошо им это удалось: Non-browser version of Prototype.js. В этой теме один программист рассказывает, как их компания использует prototype в своём серверном javascript, а другой — о подключении библиотеки к скриптам для Windows Scripting Host.
javascript, prototype.js, server-side
Prototype.js объявляет множество удобных методов для DOM-объектов, но разработчикам всегда хочется большего. Добавить объекту новый метод очень просто, но при этом рекомендуется соблюдать несколько правил.
- ссылка на элемент или его id должна быть первым параметром метода, обычно его называют element
- первой строкой метода становится
element = $(element);
, чтобы быть уверенным, что дальше идет работа именно с объектом
- последней строкой метода становится
return element;
, благодаря этому можно использовать method chaining типа element.update().hide();
- после добавления всех желаемых методов в
Element.Methods
нужно вызвать Element.addMethods();
Почему нужно выполнять первый пункт? Без этого вы не сможете вызывать эту функцию как метод объекта. Дело в том, что prototype создает у всех DOM-объектов методы, имена которых совпадают с аналогами из Element.Methods
, но при этом первым параметром в них передается сам DOM-объект. Поэтому, если ваша функция ожидает первым параметром что-то другое, её нельзя будет вызывать с использованием синтаксиса element.method()
.
extend.js, javascript, prototype.js