Сегодня неизвестный, но бдительный пользователь вновь напомнил мне о разнице между Drupal.behaviors и $(document).ready(). Причем так напомнил, что я уже обновил по горячим следам jSlider Form API. Для закрепления, напишу об этой разнице несколько слов.
Дело в том, что некоторые (и я был в их числе) принимают Drupal.behaviors за полную замену $(document).ready(), дескать, в Друпале надо вот так — и все. Виной тому, с одной стороны, невнимательность, с другой — тот факт, что в 2009-м году описание Drupal JavaScript API было не таким подробным, как теперь. Так или иначе, основная разница между ними заключается в том, что, тогда как $(document).ready() вызывается однократно, после готовности DOM, Drupal.behaviors может вызываться несколько раз: если скрипты подгружают по AJAX на страницу новые элементы и вызывают для них функцию Drupal.attachBehaviors().
При отладке с этим сталкиваешься не всегда, поэтому о разнице нетрудно забыть. Но в боевом режиме вляпаться легко. Достаточно поставить какой-нибудь Vote Up/Down — и вот уже кнопки, генерируемые нашими скриптами, при каждом голосовании генерируются вторично, а формы начинают сохраняться по несколько раз подряд.
Чтобы избежать таких глюков, необходимо в Drupal.behaviors, во-первых, использовать переменную context, и во-вторых — присваивать обработанным однажды элементам соответствующий класс и проверять его наличие при обработке. Как в данном примере, добавленном к упомянутому описанию JS в Друпале:
Drupal.behaviors.myModuleBehavior = function(context) {
$('.module-class-object:not(.module-class-processed)', context).each(function () {
$(this).addClass('module-class-processed');
// Do things
});
};
Кроме того, для глобальных задач (например, однократно добавить на страницу кнопку) можно по-прежнему пользоваться $(document).ready().