Показаны сообщения с ярлыком jQuery. Показать все сообщения
Показаны сообщения с ярлыком jQuery. Показать все сообщения

понедельник, 9 июля 2012 г.

Задержка события ready и особенности работы jQuery.holdReady()

jQuery.holdReady() появился c версии v.1.6 и позволяет отложить выполнение события ready. Наиболее часто используется для того чтобы задержать событие ready, в случае динамической загрузки скриптов (или плагинов jQuery).

Простейший пример использования:

$.holdReady(true);
$.getScript("myplugin.js", function() {
$.holdReady(false);
});

Вроде как всё лаконично и можно использовать, но не тут-то было. У него есть одна неприятная особенность: jQuery.holdReady() не будет иметь никакого эффекта, если перед этим уже произошло ready event.


Что это означает на практике? – Если мы попытаемся сделать динамическую загрузку дополнительных JavaScript файлов, к примеру ajax-ом после того как страница уже была загружена, и хотели бы придержать использование методов и объектов JS-плагинов, до полной загрузки необходимых файлов, то holdReady() не отработает вообще.

Выходом из ситуации, когда нужно подождать пока не инициализируются все объекты, а использование jQuery.holdReady() уже невозможно после наступления ready event-а может быть:
1. использование callback вызовов после успешной ajax-загрузки и только тогда использовать сами загруженные объекты;
2. Сделать периодический опрос по таймеру (setTimeout), пока объявляемая функция или объект не станут доступными.

вторник, 26 апреля 2011 г.

Disabling arrow keys at Fancybox (отменить перехват курсорных клавиш в Fancybox)

Используя замечательный плагин Fancybox для jQuery, натолкнулся на один очень неприятный момент. При использовании его, например, в совокупности с элементами формы input или textarea невозможно было перемещаться внутри этих элементов влево и вправо, используя курсорные клавиши. Происходило это по причине перехвата событий от клавиш-стрелок (keycodes 37 и 39) функцией навигации в плагине Fancybox. Оказалось, что простой опции отключить навигацию курсорными клавишами в этом плагине нет, пришлось хучить.

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

Для начала я добавил новую переменную в файл, где хранились дефолтные значения оцпий для Fancybox, назвал её disableNavButtons:

$.fn.fancybox.defaults = {
 ...
 disableNavButtons : true,
 ...
};

Затем, пропатчил функцию fancybox_set_navigation, в условных выражениях добавил обработчики на проверку равен ли e.keycode 37 или 39 и при этом currentOpts.disableNavButtons выставлено в false. И если условие выполняется, то переназначить действия для левой и правой курсорных клавиш.

function fancybox_set_navigation() {
  $(document).unbind('keydown.fb').bind('keydown.fb', function(e) {
    if (e.keyCode == 27 && currentOpts.enableEscapeButton) {
      e.preventDefault();
      $.fancybox.close();
    
    } else if (e.keyCode == 37 && !currentOpts.disableNavButtons) {
      e.preventDefault();
      $.fancybox.prev();
    
    } else if (e.keyCode == 39 && !currentOpts.disableNavButtons) {
      e.preventDefault();
      $.fancybox.next();
    }
    ...

четверг, 3 февраля 2011 г.

Подсказки в input: text полях (default search text at input using jQuery)

На сайтах часто попадаются подсказки в input: text полях, например, в полях для поиска, когда написан текст «Поиск по сайту», а при вводе в него значения – он исчезает и пользователь может ввести критерий поиска.

Алгоритм работы данного функционала прост. Задается текст-подсказка (описание поля) по умолчанию, зачастую бледного цвета, а при фокусе на элементе всё очищается. При потере фокуса, если значение поля осталось пустым, то снова возвращается текст подсказка.

Самый простой способ, для «любителей» размещать весь код инлайн, реализуется при помощи JS, навесив два события onfocus и onblur на input элемент формы:

<input type="text" value="Поиск по сайту…" onfocus="if (this.value == 'Поиск по сайту…') {this.value = '';}" onblur="if (this.value == '') {this.value ='Поиск по сайту…';}" />

Есть, конечно, и много уже готовых плагинов для отображения подсказки в input полях, но мне почему-то больше всех приглянулся jquery.hint.js (как пользоваться расписано тут).  Как мне показалось, jquery.hint.js вполне удачное, маленькое и элегантное решение для такой задачи.

В любом случае, плагины уже нашёл после того, как написал собственное решение для этой задачи, да и подгружать отдельный js файл на каждую html страницу - непозволительная роскошь, из-за одного маленького input в блоке поиска. Вот этот кусочек js-кода, который с использованием jQuery навешивает подсказку для input text поля с id-шником search:

$('#search').focus(function(){
    if($(this).val() == $(this).attr('title')){
      $(this).val('').css('color','#333');
    }
  }).blur(function(){
    if($(this).val() != $(this).attr('title') && $.trim($(this).val()).length == 0){
      $(this).val($(this).attr('title')).css('color','#AAA');
    }
}).blur();

Сам элемент input выглядет следующим образом:

<input id="search" type="text" name="search" value="" title=" Поиск по сайту…" />

Скрипт использует значение, которое задано в атрибуте title в качестве текста подсказки и выводит его серым цветов в самом input. Как только пользователь ставит/убирает курсор в поле для ввода, срабатывает событие focus/blur, которое и показывает/скрывает текст подсказки и меняет CSS стиль для элемента.

Для того чтобы submit формы не происходил с нашим фейк-значением подсказки, я навесил дополнительное событие onsubmit="checkFakeSearchValues();" на элемент form. Эта функция выглядит следующим образом:

function checkFakeSearchValues(){
  var search = $('#search');
  if($(search).val() == $(search).attr('title')){
    $(search).val('');
  }
}

и проверяет значение поля для ввода перед submit формы.  Если пользователь ничего не вводил в поле, значение осталось равно значению текста подсказки, то оно будет почищено и оставлено пустым.

пятница, 22 января 2010 г.

Новый jQuery 1.4 + обновлённый jQuery CheatSheet

Не так давно вышла оновлённая библиотека jQuery 1.4, краткий список новшеств приведу ниже.

  • метод live полностью переделали, теперь он поддерживает во всех браузерах такие события, как: submit, change, mouseenter, mouseleave, focus, blur.
  • подкорректировано поведение метода add.
  • сильно увеличена производительность функций для работы с Document object model (в частности append, prepend).
  • стали быстрее работать функции find, empty, remove, addClass, removeClass, hasClass, attr и css.
  • добавлена jQuery.noop() - функция, которая ничего не делает.
  • новая вспомогательная функция jQuery.contains(container, contained), позволяющая проверить существование элемента DOM внутри другого элемента DOM.
  • добавлен весьма полезный метод .delay(duration, [queueName]), которые позволяет установить таймер задержки выполнения следующего пункта очереди.
  • и много других приятных дополнений, о которых можно почитать на официальном сайте jQuery.

Кстати, если нужно, вот ссылка на обновлённую шпаргалку по API jQuery 1.4 (cheetsheet)

понедельник, 17 августа 2009 г.

jQuery toggle() IE8 bug

Недавно в процессе разработки наткнулся на интересный баг в jQuery. В библиотеке jQuery ver.1.3.2 реализована некорректная работа функции toggle() под IE8. В остальных браузерах работает нормально. Заключается ошибка в следующем: последовательно применяя toggle() к элементу таблицы в браузере Internet Explorer 8 элемент будет успешно скрыт, но обратно не будет показан при повторном вызове.

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

Sizzle.selectors.filters.hidden = function(elem){
    return elem.offsetWidth === 0 || elem.offsetHeight === 0;
};

Sizzle.selectors.filters.visible = function(elem){
    return elem.offsetWidth > 0 || elem.offsetHeight > 0;
};


Оба из них проверяют видимость элемента на странице путём проверки его высоты и ширины. Итак, в чём же кроется проблема данного определения, и почему не работает метод toggle() под IE8? Элемент
, хоть и имеет аттрибут display:none, всё равно имеет ширину > 0. Высота скрытого tr равна 0. Логика :visible/:hidden селекторов считает элемент видимым, если элемент имеет какую-то высоту или ширину, что есть неправильно для «любимого» IE.

Эту проблему можно исправить, проверяя атрибут display у искомого элемента. Тогда селекторы должны принять такой вид:

Sizzle.selectors.filters.hidden = function(elem){
    return (elem.style.display.toLowerCase() !== 'none');
};

Sizzle.selectors.filters.visible = function(elem){
    return (elem.style.display.toLowerCase() === 'none');
};

Могу предложить и более сложное решение, которое проверяет, как и раньше, высоту и ширину элемента, но при этом берёт во внимание особенности работы с tr:

Sizzle.selectors.filters.hidden = function(elem){
    var width = elem.offsetWidth, height = elem.offsetHeight,
         force = /^tr$/i.test( elem.tagName );
    return ( width === 0 && height === 0 && !force ) ?
        true :
            ( width !== 0 && height !== 0 && !force ) ?
                false :
                    !!( jQuery.curCSS(elem, "display") === "none" );
};

Sizzle.selectors.filters.visible = function(elem){
    return !Sizzle.selectors.filters.hidden(elem);
};

суббота, 28 марта 2009 г.

jQuery Tabs. Ajax загрузка в один и тот же div контейнер

Эта статья будет полезна тем, кто использует такую мощную штуку как jQuery UI, в частности элемент интерфейса Tabs. jQuery Tabs позволяет в несколько строчек кода создавать удобный и быстрый набор вкладок на HTML странице.

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

Приведу пример использования:

<div id="contacttabs">
  <ul>
    <li><a href="all.html"><span>Все контакты</span></a></li>
    <li><a href="friends.html"><span>Друзья</span></a></li>
    <li><a href="invisible.html"><span>Список невидящих</span></a></li>
    <li><a href="ignore.html"><span>Список игнорируемых</span></a></li>
  </ul>
</div>

<script type="text/javascript">
  $(document).ready(function() {
    $("#contacttabs").tabs({
      spinner: 'загрузка...'
});
  }
</script>

После загрузки страницы создастся четыре вкладки, содержимое, в каждую из них, будет загружено динамически ajax-ом. Все недостающие контейнеры, в которые загружать содержимое вкладок, jQuery создаст сам. Эта часть будет выглядеть приблизительно вот так (содержимое div-ов опущено для упрощения восприятия):

<ul class="ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all">
...
</ul>
<div id="ui-tabs-16" class="ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide"></div>
<div id="ui-tabs-27" class="ui-tabs-panel ui-widget-content ui-corner-bottom"></div>
<div id="ui-tabs-29" class="ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide"></div>
<div id="ui-tabs-31" class="ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide"></div>

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

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

Единственным выходом для меня было – подчищать содержимое контейнеров неактивных вкладок, дабы не возникало дублирование ID-шников. Такой опции в jQuery Tabs, я найти не смог, пришлось написать небольшой hook. Я навесил на событие select, возникающее в Tabs, в момент переключения активной вкладки, очистку всех неактивных контейнеров <div>.

<script type="text/javascript">
  $(document).ready(function() {
    $("#contacttabs").tabs({
      spinner: 'загрузка...',
      select: function(event, ui) {
        /*clear all divs content except active one*/
        fakes = ui.panel.parentNode.getElementsByTagName('div');
        for(i=0;i<fakes.length;i++){
          if(fakes[i] != ui.panel){
            fakes[i].innerHTML = '';
          }
        }
      }
    });
  });
</script>

И тогда всё заработало, как следует..

Рекоммендую

Попробуйте надёжный хостинг от Scala Hosting