БетаЛаборатория - внеочередной IT-блог

Записки обычного программиста

 

Записи с тэгом jQuery

jQuery, :hidden и тэг option

В jQuery имеет место одна проблема с псевдоцсс селектором :hidden - в браузерах отличных от FireFox конструкция вида
 
<script>
$(document).ready(function() {
	$("*:hidden").remove();
});
</script>
 
удалит не только действительно невидимые объекты, но и все options.
Проблема кроется в текущей реализации алгоритма определения видимости:
Sizzle.selectors.filters.hidden = function(elem){
	return elem.offsetWidth === 0 || elem.offsetHeight === 0;
};
 
Фаерфокс этот момент обрабатывает вполне корректно - в качестве габаритов option он всегда возвращает размеры отрисованного select. А вот остальные браузеры (возможно не все конечно, но основные) сплоховали - всегда возвращают 0, что и приводит jQuery в замешательство.
 
В принципе есть два варианта решения данной проблемы. Первый сгодится если проблемы возникают только с вашим кодом - тут можно просто изменить конструкцию селектора:
 
<script>
$(document).ready(function() {
	$("*:hidden:not(option)").remove();
});
</script>
 
Хуже если эта проблема мешает работе каких-либо плагинов. Решить ее можно "подменив" селектор ":hidden", что, между прочим, совсем не сложно.
 
<script>
// Удалять настоящий селектор не за чем.
// Просто переименуем его в :realhidden.
jQuery.expr[':'].realhidden = jQuery.expr[':'].hidden;
// А на его место поместим наш собственный, с дополнительной проверкой
jQuery.expr[':'].hidden = function(elem) {
	// Если обрабатываемый элемент это option возвращаем false
  	if (elem.nodeName == "OPTION") {
		return false;
  	} else { // Если нет - передаем управление оригинальному селектору :hidden 
 		return jQuery(elem).is(":realhidden");
	}
};
$(document).ready(function() {
	// Сработает функция jQuery.forceHidden и все опции останутся на месте
	$("#test :hidden").remove(); 	
});

</script>
 
Главное, чтобы замена селектора произошла до выполнения кода скрипта, который будет ее использовать. Скорее всего достаточно того, что он выполняется до события $(document).ready, но в некоторых случаях могут быть варианты - просто будте внимательный.
jQuery abeInline plugin

Я наконец оформил одну из функцию, которую написал в процессе разработки этого блога, в виде плагина к jQuery. Получился плагин abeInline - средство для inline редактирования контента. Конечно, пока она еще не полная, так сказать beta-версия, но в принципе работоспособная. Сейчас она умеет конвертировать блоки в text input и в textarea, отправлять результат по AJAX и обрабатывать несколько разных блоков как единую форму.
 
Документация - тоже пока не полная =(
Скачать - пока выложил только на jQuery, но планирую сделать проект на code.google.com с ропозиторием и багтреком.
Лицензия - библиотека распространяется по Лицензии BSD.
 
Если честно, это первая библиотека открываемая мной публично. У меня есть одна черта, которая мне очень мешает в вопросе выкладывания своих наработок - мне все время кажется что работа настолько незакончена, что выкладывать ее неприлично. Помимо всего прочего, это распространяется и на запуск личных проектов - многие я не запустил именно потому, что они казались мне не готовыми. Сейчас я усердно борюсь с этими своими ощущениями - в конце концов, полевые испытания всегда самые эффективные. А если что-то в библиотеке не работает - никто же не отменял багтрекинг, патчи и новые версии. Вобщем, теперь я буду стараться выкладывать больше своих наработок - возможно кому-то что-то из них поможет.
Подсветка синтаксиса, часть четветрая, заключительная

Ну вот , кажется, и походит к концу моя эпопея с подсветкой синтаксиса. В процессе беседы, несколько для меня неожиданной, с Иваном Салагаевым, получил от него несколько разъяснений по его библиотеке и сам покопался в ней поглубже. В итоге, убрал из функции инициализации автоматический поиск блоков для подсветки и открыл функцию highlight для внешнего доступа. Кое-какие недочеты конечно остались, но я думаю разберусь со временем. Ивану огромное спасибо за библиотеку и за помощь.
 
Еще добавил вывод номеров строк, но он работает независимо от основной библиотеки.
Подстветка синтаксиса, часть третья

Задумался о том, что в текущей реализации подсветки кода я могу столкнуться с чрезмерным увеличением количества AJAX-запросов. Учитывая что на одной странице выводится до 20 записей, в каждой из которой может оказаться по несколько блоков кода, это чревато десятками запросов.
 
В сети я нашел несколько скриптов для подсветки синтаксиса на JavaScript, однако, после нескольких экспериментов, я убедился что они не дают никаких реальных преимуществ. Самым качественным решением, из тех которые я нашел, является библиотека Ивана Салагаева (http://softwaremaniacs.org/soft/highlight/). Но, во-первых, упакованная библиотека со всеми языками весит 78 Килобайт, а во-вторых, имеет несколько странную реализацию - подсветка осуществляется ТОЛЬКО автоматически, основываясь на анализе кода, то есть нельзя вручную указать какой блок подсвечивать. Скорость его работы я не анализировал, поскольку для меня достаточным для отказа фактором стал именно вес библиотеки.
 
Поэтому я несколько оптимизировал свою систему. В новой версии все блоки на странице обрабатываются одним AJAX запросом. Для этого сначала генерируется форма, в которую агрегируются все блоки с кодом. Форма создается по правилам Django Formset, для удобства ее обработки на сервере.
Полученный от сервера ответ разбит на блоки, которые очень легко разбираются и размещаются где положено.
 
$(document).ready(function() {
	var form = $("<form>"); // Создаем форму.
	var i = 0;
	$(".highlight").each(function() { //Перебираем все блоки требующие подсветки
		var hObject = $(this);
		hObject.attr("id", "highlight-"+i); // Присваиваем блоку уникальный id, чтобы потом найти его.
		// Создаем поле language для формы. Содержит название языка.
		language = $("<input>").attr({
			"name" : "form-"+i+"-language",
			"value" :  hObject.attr("lang")? hObject.attr("lang") : "text", // Если аттрибудет lang не задан, код будет возвращен без подсветки.
			"type" : "text"
		});
		// Создаем поле id для формы. Используется для идентификации блока с результатом.
		id = $("<input>").attr({
			"name" : "form-"+i+"-id",
			"value" :  i,
			"type" : "text"
		});
		// Создаем поле code для формы. Содержит код для подсветки.
		code = $("<textarea>").attr({
			"name" : "form-"+i+"-code",
		}).text(hObject.html());
		// Добавляем поля к форме.
		form.append(language);
		form.append(code);
		form.append(id);
		i++;
	});
	// Если есть хотя бы один блок
	if (i) {
		// Создаем поле form-TOTAL_FORMS. Нужен для Django Formset для обработки формы. 
		total = $("<input>").attr({
			"name" : "form-TOTAL_FORMS",
			"type" : "text",
			"value" : i
		});
		// Создаем поле form-INITIAL_FORMS. Нужен для Django Formset для обработки формы. В нашем случае всегда 0.
		initial  = $("<input>").attr({
			"name" : "form-INITIAL_FORMS",
			"type" : "text",
			"value" : "0"
		});
		// Добавляем поля к форме.
		form.append(total); 
		form.append(initial);
		// Отправляем запрос 
		$.post("/tools/highlight/", form.serialize(), function(response_data) {
			// Перебираем блоки ответа.
			$(response_data).find(".highlighted").each(function(){
				// Заменяем исходный блок, на подсвеченный, ореинтируясь на id.
				$("#highlight-"+$(this).attr("id")).replaceWith($(this).html());
			});
		});
	}
});
Подсветка синтаксиса, часть вторая

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

Как я и думал, встраивание подсвеченного кода в пост в чистом виде оказалось решением скверным. Причем, помимо неудобств при редактиваронии, такой подход вызывает дополнительные проблесмы при экспотре RSS - лишние теги + лишние стили... ничего хорогошего вобщем. =)
 
В итоге я заменил способ подстветки - теперь это работает так:
 
В WYSIWYG вставляется контейнер с небработанным кодом, которому присваивается класс highlight и в аттрибуте lang указывается язык для подсветки. По окончании загрузаки страницы, из всех контейнеров класса highlight извлекается их содержимое и AJAX-запросом отправляется на сервер, а полученный результат замещает собой первоначальный контейнер.
 
Выполнено это пока не очень изящно, однако работает.
 
$(document).ready(function() {
	$(".highlight").each(function() {
		var hObject = $(this);
		$.post("/tools/highlight/", {
			"language" : hObject.attr("lang")? hObject.attr("lang") : "text",
			"code" : hObject.html()
		},
		function(response_data) {
			hObject.replaceWith($("<div>").append(response_data));
		});
	})
});

Авторизация

Логин:

Пароль:


Регистрация | Забыли пароль?


Последние записи


Promo

Follow pyhoster on Twitter Subscribe

Реклама

A Django project.