Недавно вышла новая версия 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 раза меньше.

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

Комментарии (11)


  1. Monnoroch
    29.05.2015 14:48

    Балалайка — это jquery для бедных (жадных?). Просто используйте jquery, если вам мало, смысл, как я понял, в том и был, чтобы выпилить все то, что не нужно самим разработчикам матрешки. Они, если верить документации, взаимозаменяемы для внутренностей матрешки.


    1. seokirill Автор
      29.05.2015 14:55

      Понял, значит придется JQuery использовать. Вообще говоря, то, что я написал, можно было на jquery сделать ни чуть не сложнее, но выглядел бы код похуже. Видимо, матрешка для куда более сложных задач. Но цель как раз была — пощупать.


  1. RubaXa
    29.05.2015 16:17
    +1

    Я просто оставлю это здесь jquerymy.com


    1. seokirill Автор
      29.05.2015 16:25

      Это про «двустороннее связывание данных»? На русском есть?


      1. RubaXa
        29.05.2015 16:26

        Конечно, jquerymy.com/ru


  1. Finom
    29.05.2015 16:33

    так и не смог понять, как удалить конкретный элемент массива.
    Метод pull
    Начиная с версии 0.3, метод поддерживает удаляемый элемент в качестве аргумента.
    Он есть в JQuery, но не в балалайке
    Балалайка наследуется от нативного массива, у которого есть метод indexOf.
    С балалайкой пока не решил вопрос.
    Советую впредь пользоваться jQuery. Балалайка сделана для тех, кто хочет писать ванильный код. Это требует достаточно серьезных знаний DOM и JavaScript.
    Ваша терминология мне немного режет глаза. Там где вы говорите «переменная» правильнее сказать «свойство». Cкорее всего, из-за проблем с терминологией, у вас возникли проблемы с пониманием bindNode.
    Так гласит документация, но на деле подводные камни присутствуют, особенно учитывая «для новичков» и примеры в документации, которые сбивают с толку.
    Примеров действительно многовато, и они вклюают в себя информацию и для опытных разработчиков, в том числе.


  1. xGromMx
    29.05.2015 16:55

    Однако название у вас slovoeb…


    1. seokirill Автор
      29.05.2015 17:13

      Оно заимствовано у оригинальной программы. Хотел сделать веб-версию, да передумал. Сделал немного другое.


  1. Nadoedalo
    29.05.2015 17:51
    +5

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

    не удержался
    1. seokirill Автор
      29.05.2015 18:02

      Просто не понял, это фреймворк, который надо использовать вместо других? Если вместе… то все можно полностью на ином фреймворке написать.

      Картинка улыбнула.


      1. Nadoedalo
        29.05.2015 19:19

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

        Ну и как обычно — как только изобретут что-либо достаточно простое — сразу же найдётся ещё более глупый человек.