Fixed fancybox

31.10.2009 Jman

Из-за того что мне нехватает времени написать свою галерею, пользуюсь в последнее время Fancybox, для тех кто не знаком — плагин jQuery для фотогалереи, очередной клон lightbox. Как у всего в этом мире есть приемущества и есть недостатки.
Основные приемущества — это конечно же настройки. Не надо передавать в скрипт никаких картинок, как в lightbox. Большая часть оформления через css. Приведу основные настройки.

padding
Позволяет задать отступ от картинки, по дефолту стоит 10px, нужно менять если меняете стили отображения рамочки
imageScale (true/false)
машатабировать изображение чтоб поместилось в окно или нет
zoomOpacity (true/false)
Анимировать прозрачность всплвыющего блока при анимации или нет
zoomSpeedIn, zoomSpeedOut, zoomSpeedChange
Скорость анимации в милисикундах (если 0 анимации нет) при открытии, закрытии и переключении картинки
easingIn, easingOut, easingChange
Управление плавностью, и ефектами анимации (нужен плагин jquery.easing)
frameWidth, frameHeight
ширина и высота фрейма (если открываем флеш, iframe, html)
overlayShow (true/false)
отображать подложку (по умолчанию не отображается)
overlayOpacity (от 0 до 1)
Прозрачность подложки
hideOnContentClick (true/false)
Прятать FancyBox, при клике на откртый блок
centerOnScroll (true/false)
Центровать картинку при скроле окна
itemArray ([массив])
Задать свой массив элементов
callbackOnStart, callbackOnShow, callbackOnClose
Вызов произвольной callback-функции по определённому событию — при старте , при отображениии, и при закрытии

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

  1. первое попроще, но и столкнутся проще — неправильно отображается рамка если задан отступ через настройку padding
  2. при завершении работы fancybox, скрипт снимает обработчики событий scroll resize keydown

Кусок кода в котором заключается первая проблема

if (pad > 0) {
	width	+= pad * 2;
	height	+= pad * 2;

	$("#fancy_content").css({
		'top'		: pad + 'px',
		'right'		: pad + 'px',
		'bottom'		: pad + 'px',
		'left'		: pad + 'px',
		'width'		: 'auto',
		'height'		: 'auto'
	});

	if (isIE) {
		$("#fancy_content")[0].style.setExpression('height',	'(this.parentNode.clientHeight - 20)');
		$("#fancy_content")[0].style.setExpression('width',	'(this.parentNode.clientWidth - 20)');
	}

} else {
	$("#fancy_content").css({
		'top'		: 0,
		'right'		: 0,
		'bottom'		: 0,
		'left'		: 0,
		'width'		: '100%',
		'height'		: '100%'
	});
}

Тут долго разбиратся и ненадо, если установлен padding то заполяем css атриуты 'top', 'right', 'bottom', 'left' значением отступа (padding), ширину и высоту ставим auto, такое значение MSIE6 не любит, поэтом для него отдельное правило, в котором и заключена ошибка.
По умолчанию padding = 10, в блоке для ие выставляется высота и ширина равная высоте и ширине родительского блока минус отсуп умноженный на 2, тоесть 20. Блин а если мы задали свой padding то пофиг получается :) . Исравляется легко, заменяем код для MSIE

if (isIE) {
	$("#fancy_content")[0].style.setExpression('height',	'(this.parentNode.clientHeight - ' + pad * 2 + ')');
	$("#fancy_content")[0].style.setExpression('width',	'(this.parentNode.clientWidth - ' + pad * 2 + ')');
}

Вторая проблема возникла из-за способа которым автор устанавливает и удаляет обработчик событий. Просто и ненавящиво

//установил событие
$(window).bind("resize scroll", $.fn.fancybox.scrollBox);
//снял событие
$(window).unbind("resize scroll");

Очень мило со сторны скрипта, разбиндить resize и scroll которые которые назначены на окно. Удаляются все обработчики, и те что назначены фансибоксом и те что назначены другими плагинами или в ручную. Для того чтобы добится совместимости с скриптами правильней было бы сделать вот так

//установил событие
$(window).bind("resize scroll", $.fn.fancybox.scrollBox);
//снял событие
$(window).unbind("resize scroll", $.fn.fancybox.scrollBox);

Благо есть обработчик = хендлер. Но есть ещё одна проблема с обработкой события — обработка нажатия клавиш клавиатуры.

$(document).keydown(function(e) {
	if (e.keyCode == 27) {
		$.fn.fancybox.close();
		$(document).unbind("keydown");

	} else if(e.keyCode == 37 && opts.itemCurrent != 0) {
		opts.itemCurrent--;
		_change_item();
		$(document).unbind("keydown");

	} else if(e.keyCode == 39 && opts.itemCurrent != (opts.itemArray.length - 1)) {
 		opts.itemCurrent++;
		_change_item();
		$(document).unbind("keydown");
	}
});

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

$(document).keydown(keyHandler(event));
function keyHandler(e){
	if (e.keyCode == 27) {
		$.fn.fancybox.close();
		$(document).unbind("keydown", keyHandler);
	} else if(e.keyCode == 37 && opts.itemCurrent != 0) {
		opts.itemCurrent--;
		_change_item();
		$(document).unbind("keydown", keyHandler);

	} else if(e.keyCode == 39 && opts.itemCurrent != (opts.itemArray.length - 1)) {
 		opts.itemCurrent++;
		_change_item();
		$(document).unbind("keydown", keyHandler);
	}
}

И второй способ, который выбрал я (незнаю какой лучше) использует одну фичу в jQuery событиях - неймспейсы, вуаля:

$(document).bind("keydown.fancybox", function(e) {
	if (e.keyCode == 27) {
		$.fn.fancybox.close();
		$(document).unbind("keydown.fancybox");
	} else if(e.keyCode == 37 && opts.itemCurrent != 0) {
		opts.itemCurrent--;
		_change_item();
		$(document).unbind("keydown.fancybox");
	} else if(e.keyCode == 39 && opts.itemCurrent != (opts.itemArray.length - 1)) {
 		opts.itemCurrent++;
		_change_item();
		$(document).unbind("keydown.fancybox");
	}
});

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

Сайт проекта jQuery
Сайт проекта fancybox

Метки: , , , ,

4 Комментария на запись“Fixed fancybox”

  1. Комментирует alexpts

    Из всех аналогичных скриптов понравился тоже fancybox и еще один, сейчас не могу найти название… где-то в закладках есть, там очень красиво перелистывались фотографии.

  2. Комментирует Jman

    2alexpts
    Неплохой скрипт — prettyPhoto. Но у него тоже куча проблем:
    1. плохо скролится
    2. непонятный алгоритм ресайза. (немного углублясь в код я понял что многие цыфры берутся с потолка).

  3. Комментирует alexpts

    prettyPhoto стоит на моем блоге alexpts.ru и my-wordpress.ru. Работает, но fancyBox симпотичнее, переделывать лень просто.

  4. Комментирует Владимир

    Здравствуйте :) У меня проблема такого рода. Всплывающие окно прячется под верхнее меню. Как сделать чтоб окно было поверх меню, а не под ним? Вот пример http://dominat-ua.com//images/pmm.jpg

Оставить комментарий