Фильтрация элементов в cuSel

в 8:55, , рубрики: front-end, html, jquery, Веб-разработка, метки:

image

На одном из сайтов, который я имею честь обслуживать, для кастомизации селекта используется замечательный jQuery-плагин cuSel. Он удобен тем, что достаточно прост в настройке и позволяет кастомизировать даже полосу прокрутки.
Но иногда случается так, что список элементов может быть очень большим. И быстро найти нужный пункт не так просто.

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

Сегодня я постараюсь повторить все это вместе с вами. Для этого возьмем демонстрационный пример со странички плагина. В архиве содержаться все необходимые библиотеки и стили. На странице index.html автор подготовил несколько примеров подключения и использования плагина. Давайте добавим фильтрацию для первого селекта, в котором содержится список стран.

Для ввода текста мы будем использовать прозрачное текстовое поле, которое по клику будет налаживаться верхним слоем на селект. Добавим для этого поля соответствующий css-класс в файл css/cusel.css и установим такие же размеры для блока, в котором отображается текст выбранного элемента списка.

.cusel .search-field {
	position: absolute;
	outline:0;
	border: 0;
	background: transparent;
	display:none;
}
.cusel .search-field, .cuselText {
	width: 144px;
	height: 20px;
	line-height:20px;
	padding: 3px 30px 3px 6px;
}

Для того чтобы была возможность добавлять фильтрацию только нужным селектам, будем помечать их дополнительным классом filtering.

		<select class="sel80 filtering" id="country" name="country" tabindex="2">

Откроем файл js/cusel.js и добавим следующий код в функцию cuselEvents.

jQuery(".cusel").each(function () {
		var itv;
		var elm = $(this);
		if (elm.hasClass("filtering") && elm.find(".search-field").length == 0) {
			var f = $("<input type='text' />")
			f.addClass("search-field");
			f.keydown(function () {
				clearInterval(itv);
				var list = elm.find(".cusel-scroll-pane > span");
				itv = setInterval(function () {
					list.each(function () {
						var item = $(this);
						item.show();
						if (item.text().toLowerCase().indexOf(f.val().toLowerCase()) != 0)
							item.hide();
					});
					var d = elm.find(".cusel-scroll-pane").eq(0).attr("id");
					jQuery("#" + d)[0].scrollTo(0);
					clearInterval(itv);
				}, 100);
			});
			f.click(function () {
				$(this).val('').hide();
				elm.focus();
			});
			elm.append(f);
		}
	});

Что делает данный код? Находит на странице все элементы с классом «cusel» т.к. именно этот класс используется в стилизированных селектах. Далее, если для селекта указан класс «filtering» и он не имеет дочерний элемент с классом «search-field» (наше поле для ввода текста), то такое поле создается и на него вешается обработчик события. Обработчик, по каждому нажатию клавиш в поле, находит пункты в списке, текст которых не соответствует тексту в поле и просто скрывает их.

Теперь нам нужно сделать так, чтобы по клику на селекте над ним появлялось наше прозрачное поле. Для этого в той же функцие cuselEvents найдем обработчик события «click». В нем необходимо отыскать часть кода помеченную комментарием автора «если кликнули по самому селекту (текст)» и изменить следующим образом.

/* если кликнули по самому селекту (текст) */
		if((clickedClass.indexOf("cuselText")!=-1 || clickedClass.indexOf("cuselFrameRight")!=-1) && clicked.parent().prop("class").indexOf("classDisCusel")==-1)
		{
			var cuselWrap = clicked.parent().find(".cusel-scroll-wrap").eq(0);

			var parent = clicked.parents(".cusel");
			if (parent.hasClass("filtering")) {
				var txt = parent.children(".cuselText");
				var sf = parent.children(".search-field");
				if(sf.is(":hidden")) {
					txt.text("");
					sf.show().focus();
				}
				else {
					txt.text(parent.find(".cuselActive").eq(0).text());
					sf.val("").hide();
				}
			}

			/* если выпадающее меню скрыто - показываем */
			cuselShowList(cuselWrap);
		}

Поскольку поле для ввода текста прозрачное, чтобы не перекрывать фон, мы очищаем текст выбранного элемента в селекте. Повторный клик будет возвращать исходное состояние элемента.

Теперь сделаем, чтобы при выборе элемента в списке, поле наоборот скрывалось. Ниже найдите блок помеченный комментарием автора «если выбрали позицию в списке» и добавьте туда следующий код

			else if(clicked.is(".cusel-scroll-wrap span") && clickedClass.indexOf("cuselActive")==-1) {

		         var parent = clicked.parents(".cusel");
		         if (parent.hasClass("filtering")) {
		            parent.children(".search-field").val('').hide();
		            parent.find(".cusel-scroll-pane > span").show();
		         }

                         //оригинальный код
			}

Как видно при этом мы делаем видимыми скрытые при фильтрации элементы списка.

Логично бы было, если пользователь кликнет все списка, закрыть список и спрятать поле фильтра. Поэтому находим ниже блок, помеченный комментарием автора «скрываем раскрытые списки, если кликнули вне списка» и изменяем его следующим образом.

/*
		скрываем раскрытые списки, если кликнули вне списка
		*/
		else {
			var wrap = jQuery(".cusel-scroll-wrap");
			var parent = wrap.parents(".cusel");

			parent.each(function () {
				var elm = $(this);
				if (elm.hasClass("filtering")) {
					elm.find(".cuselText").text(elm.find(".cuselActive").eq(0).text());
					elm.find(".search-field").val('').hide();
					elm.find(".cusel-scroll-pane > span").show();
				}
			});

			wrap.hide();
			parent.removeClass("cuselOpen")
		}

И теперь последний штрих. В самом конце функции cuselEvents вы найдете кусок кода помеченный следующим комментарием

        /*
	функция отбора по нажатым символам (от Alexey Choporov)
	отбор идет пока пауза между нажатиями сиволов не будет больше 0.5 сек
	keypress нужен для отлова символа нажатой клавиш
       */

Функция Алексея подбирает подходящее значение по первой букве. Мы же реализовываем возможность отбора по нескольким буквам. Поэтому во избежание конфликтов код Алексея необходимо закомментировать.

Исходники

Автор: aleksey_bober

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js