Pull to refresh

Шишки об матрешку

Reading time 5 min
Views 13K
Недавно вышла новая версия Matreshka.js.

image

В документации на первой же странице написано, что разобраться сможет даже новичок, фреймворк очень простой.

Так гласит документация, но на деле подводные камни присутствуют, особенно учитывая «для новичков» и примеры в документации, которые сбивают с толку.

В данном эксперименте решил отказаться полностью от любой другой библиотеки (в частности JQuery), чтобы по привычке не написать все на ней.

Задача


  • Состряпать фильтр списка словосочетаний
  • Пощупать матрешку


Легенда


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

Процесс пошел


Что должно получиться:

Картинка
image

Итак, первым делом набросаем html:

<div id="m">
	<div class="button" id="delPlus">Удалить плюсы</div>
	<div class="button" id="minus-words-open">Минус-слова</div>
	<div id="mWordsContainer">
		<div class="button" id="myMinus">Свое <input type="text"></div>
		<div class="button" id="selfhands">Своими руками</div>
		<div class="button" id="bu">Б/у</div>
		<div class="button" id="forfree">Бесплатно</div>
		<div class="button" id="otz">Отзывы</div>
		<div class="button" id="video">Видео</div>
		<div class="button" id="foto">Фото</div>
	</div>
</div>
<div id="c">
	<div class="button" id="loadWords">Загрузить слова списком</div>
	<div id="loadList">
		<textarea></textarea>
		<div class="button" id="startLoad">Загрузить</div>
	</div>
	<ul id="wordList"></ul>
</div>

Не стоит на нем заострять внимание, в этом посте мы смотрим на матрешку.

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

Несколько раз прочитав этот раздел документации, я, как оказалось, не понял смысл bindNode(), поэтому приведу визуальный пример:

image

В качестве первого аргумента указываем имя нашей будущей переменной (скорее это даже указатель, но не будем усложнять терминологию).

Каждый раз, когда происходит действие, указанное в on (в нашем случае on: 'click'), возвращаемое значение будет передаваться в нашу «переменную», то есть class (по сути это не совсем переменная, но об этом ниже).

И наоборот, каждый раз, когда «переменная» меняется сторонними методами, например:

this.class = 'value';
app.class = 'value2';

Вызывается метод setValue(arg), в который в качестве аргумента передается новое значение «переменной».

Указатель


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

		this.bindNode('variable','#loadList textarea');       // Текстовое поле
		this.bindNode('variable','#loadList');                    // Обертка текстового поля
		this.bindNode('variable','#myMinus input');        // Свои мину-слова

Что это означает?
Да то, что при изменении значения variable любым способом мы вызовем метод setValue() у каждого привязанного объекта.

Если какой-то объект сам изменил значение variable посредством метода getValue() (по событию on: 'click'), то setValue() вызывается у всех прочих привязанных объектов.

:sandbox


В документации хорошо описан массив Matreshka.Array, останавливаться на нем не буду.
Разве что подробнее о том, что такое sandbox.

Sandbox — это песочница (как явствует из документации), но что нам это дает?

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

		this.on('render',function(){
			this.bindNode('close',':sandbox i');
			this.on('click::close',function(){
				this.sandbox.className = 'disabled';
			});

		});


:Sandbox здесь выступает как указатель на текущий DOM элемент. То есть это и есть песочница, все происходит в рамках нее.

Ближе к делу


С имеющимися у нас знаниями можно накидать добавление словосочетаний списком:

		this.bindNode('preList','#loadList textarea'); // Текстовое поле
		$b('#startLoad').on('click',function(){
			wordList.recreate();
			var preArr = app.preList.split("\n");
			for(key in preArr){
				wordList.push({
					value:preArr[key]
				});
			}	
		});

Полный код задания массива
var listModel = Matreshka.Class({ // Модель списка
	'extends': Matreshka.Object,
	constructor: function(data){
		this.jset(data);
		this.on('render',function(){
			this.bindNode('value',':sandbox .value',Matreshka.binders.innerHTML());
			this.bindNode('class',':sandbox',{ // Свойство class объекта 
				on: 'click',
				getValue: function(){
					return this.className;
				},
				setValue: function(v){ // Когда устанавливаешь: this.class = value
					this.className = v;
				},
				initialize: function(){
					$b(this).on('click',function(){
						$b(this).toggleClass('active');
					});
				}
			});
			this.bindNode('close',':sandbox i');
			this.on('click::close',function(){
				this.sandbox.className = 'disabled';
			});

		});
	}
});

var listArray = Matreshka.Class({ // Класс списка
	'extends': Matreshka.Array,
	Model: listModel,
	itemRenderer: '<li><span class="value"></span><i></li>',
	constructor: function(){
		this.bindNode('sandbox','#wordList'); // Засовываем в песочницу
	},
	minus: function(search){
		if (search.length < 1) return;
		this.each(function(item, index){
			if ((typeof search) == 'object'){
				for(key in search){
					if (item.value.toUpperCase().indexOf(search[key].toUpperCase()) + 1){
						item.class = 'disabled';
					};
				}
			}else{
				if (item.value.toUpperCase().indexOf(search.toUpperCase()) + 1){
					item.class = 'disabled';
				};
			}
		});
	}
});
var wordList = new listArray; // Экземпляр класса списка



Фильтрация


Что нужно? Нужно удалять ненужные.
Тут-то и кроется первое разочарование: так и не смог понять, как удалить конкретный элемент массива.
Есть splice, но чтобы им воспользоваться, надо знать индекс элемента массива.
Хорошо, для этого есть index() при работе с DOM (учитывая, что у нас связаны ul li и наш массив).
НО! Он есть в JQuery, но не в балалайке. Поковырявшись так и сяк, опробовал различные варианты пришел к выводу, что придется не удалять элементы из массива, а скрывать их отображение (display:none).

			this.bindNode('close',':sandbox i');
			this.on('click::close',function(){
				this.sandbox.className = 'disabled';
			});

Хорошо, ручками на крестик удалять замечательно, но пора сделать хоть что-то автоматические, ведь это и было целью.

Минус-слова


Минус слова — это такие слова, присутствие которых не нужно.
В нашем случае, мы будем удалять словосочетания, в которых присутствуют эти минус-слова.
Как их найти? На ум сразу приходит селектор :contains() и его расширение :Contains() (поиск без учета регистра, надо писать самому).

Но тут второе разочарование — такой селектор не поддерживается балалайкой. А потому придется-таки делать перебор и сравнение:

	minus: function(search){
		if (search.length < 1) return;
		this.each(function(item, index){
			if ((typeof search) == 'object'){
				for(key in search){
					if (item.value.toUpperCase().indexOf(search[key].toUpperCase()) + 1){
						item.class = 'disabled';
					};
				}
			}else{
				if (item.value.toUpperCase().indexOf(search.toUpperCase()) + 1){
					item.class = 'disabled';
				};
			}
		});
	}

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

Заключение


На чем хотел заострить внимание, заострил, полный код, если интересно, на гитхабе. Результат.

Резюмирую


Расстроила только балалайка, к матрешке претензий нет.
Хотя схожесть названий наталкивают на мысль об общих разработчиках. Расстроили, такие нужности не включили в балалайку.

Кода получилось меньше, чем на JQuery (хотя на нем делал давно и тухло), сама библиотека весит более, чем в 2 раза меньше.

Вывод: понравилось, буду пользоваться.
С балалайкой пока не решил вопрос.
Tags:
Hubs:
+14
Comments 11
Comments Comments 11

Articles