v1.9.1
Самый простой фреймворк во Вселенной
<output class="out"></output>
<input class="in" type="text">

<script src="matreshka.min.js"></script>
<script>
var app = new Matreshka();
app.bindNode('x', '.in, .out');
app.x = 'Самый простой фреймворк во Вселенной';
</script>

Скачать Github

Кто помогает проекту?

Главный спонсор
Matreshka
% медленнее
React
% медленнее
Knockout
% медленнее
Angular

На основе этого бенчмарка

А еще взгляните на DMBON test

Отдельное спасибо...

Александру Колодько за крутой логотип.

Крису Оплеру за пожертвование в размере 600 долларов.

Введение

Матрешка - фреймворк для больших и бесконечно расширяемых приложений (в рамках Вселенной, конечно же), написанных на языке JavaScript. Он позволяет построить архитектуру программы так, чтоб ни вы, ни ваша команда не запутались в многочисленных сущностях, в дебаггинге логики, описанной в HTML файле, многочисленных ограничениях других фреймворков и непонятных абстракциях.

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

Порядок не важен, вы можете объявить привязки после полной реализации логики, отвечающей за данные.

Коллекции в Матрешке представлены классом Matreshka.Array, экземпляры которого сами рендерят HTML при добавлении, удалении или изменении элементов. Вы можете сказать, что фреймворк X тоже отрисовывает элементы массива при изменении данных, но в Матрешке эта задача решается невероятно просто и элегантно.

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

С чего начать

Все популярные фреймворки включают в себя множество удобных и интересных функций. Проблема в том, что новичку порой сложно понять, с чего начинать своё обучение. Изобилие функциональных возможностей того или иного фреймворка наводит на резонный вопрос: "Эй, я должен всё это выучить?".

В этой документации этот недочет решен. Документация разбита на три уровня "продвинутости".

Первый уровень - самое важное

Изучив самые важные свойства и методы, вы можете смело приступать к работе. С классами, методами и свойствами, помеченными значком необходимо разобраться в первую очередь.

Второй уровень - рекомендуется изучить

После того, как вы освоили необходимые для быстрого старта возможности, можете ознакомиться с другими свойствами и методами Матрешки.

Третий уровень - остальные методы и свойства

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

Внимание, если вы перейдете по ссылке к методу или свойству третьего уровня важности, то режим документации автоматически переключится в "продвинутый режим".

Потрясающие возможности HTML5 не обошли стороной и эту страницу. Она доступна оффлайн для любого устройства, от вашего компьютера до мобильного телефона.

Chrome для Android: зайдите в меню и нажмите "Добавить на главный экран" или "Add to home screen"

Safari для iOS: нажмите на иконку "Action" и выберите "Add to Home Screen"

Любые другие устройства: просто добавьте страницу в закладки

Теперь документацию к Матрешке можно читать без подключения к интернету. Если страница тормозит (замечено на Android 4.2), переключитесь в режим "По одному".

Hello World!

Написать первое приложение с помощью фреймворка Матрешка очень просто. Для этого:

1. Создайте HTML файл со следующим содержимым

<!DOCTYPE html>
<html>
    <head>
        <title>Моё первое приложение на базе Матрешки</title>
    </head>
    <body>
        <input type="text" class="my-input">
        <div class="my-output"></div>
        <script src="http://cdn.jsdelivr.net/matreshka/latest/matreshka.min.js"></script>
        <script src="js/app.js"></script>
    </body>
</html>

2. Напишите свой первый класс, наследующий Матрешку, создав файл js/app.js

var Application = Class({
    'extends': Matreshka,
    constructor: function() {

        // связываем свойство x и текстовое поле
        this.bindNode('x', '.my-input');

        // связываем свойство x и блок с классом my-output
        this.bindNode('x', '.my-output', {
            setValue: function(v) {
                this.innerHTML = v;
            }
        });

        // если свойство "х" изменилось, сообщаем об этом в консоли
        this.on('change:x', function() {
            console.log('x изменен на ' + this.x);
        });
    }
});

var app = new Application();

3. Это всё!

Теперь можете открыть консоль разработчика (клавиша F12) и написать:

app.x = 'Привет Мир!';

Круто, не правда ли? Теперь можно работать напрямую со свойствами без болезненных инкапсуляций.

Матрешка использует объектно-ориентированный подход основанный на классах, которые зарекомендовали себя с самой лучшей стороны в большинстве языков программирования: Python, C#, Java и многих других. Такое решение позволяет легко перейти на новые возможности синтаксиса JavaScript, описанные в стандарте ECMAScript 2015 и поддерживаемые Матрешкой. Проекты типа Babel уже сегодня позволяют использовать крутой синтаксис JS нового поколения.

class Application extends Matreshka {
    constructor() {
        this.bindNode('x', '.my-input');
        this.bindNode('x', '.my-output', {
            setValue(v) {
                this.innerHTML = v;
            }
        });
        this.on('change:x', () =>
            console.log('x изменен на ' + this.x));
    }
}

Живой пример (нажмите кнопку "Run with JS", чтобы пример запустился)

Ссылки

Как подключить?

Матрешка - самостоятельный фреймворк, не требующий никаких зависимостей. Но вы, при желании, можете использовать jQuery или Zepto в качестве библиотеки, которая будет использоваться Матрешкой для работы с DOM. Если jQuery или Zepto на странице нет, используется внутренняя компактная библиотека bQuery.

<!-- никакой магии -->
<script src="js/matreshka.min.js"></script>

Кроме этого, Матрешка поддерживает AMD, например, require.js или almond

require(['path/to/matreshka'], function(Matreshka) {
    //...
});

Импорт в стиле ECMAScript 2015

import Matreshka from 'path/to/matreshka';

Класс Matreshka

Класс Matreshka - ядро фреймворка Matreshka.js, от которого наследуются Matreshka.Array, Matreshka.Object и каждый класс создаваемого приложения. Он содержит основной функционал фреймворка, среди которого есть несколько полезнейших функций: медиаторы, зависимости, привязки к DOM, движок событий и пр. Наследование этого класса, как и наследование любого другого класса, осуществляется при помощи функции Class.

Как правило, этот класс, (как и Matreshka.Array и Matreshka.Object), не используются напрямую. Вместо этого, от него наследуются классы, создаваемые вами. Поэтому, примеры к свойствам и методам в этой документации, как правило, будут приведены с использованием ключевого слова this.

Ссылки

Примеры

Создание экземпляра

var mk = new Matreshka;

Краткая запись: MK вместо Matreshka

var mk = new MK;

Наследование

var MyClass = Class({
	'extends': Matreshka,
	constructor: function() {
		this.sayHello();
	},
	sayHello: function() {
		alert("Hello World!");
	}
});

Матрешка использует прототипы для реализации наследования. Функция Class лишь вносит синтаксический сахар. Поэтому вы можете воспользоваться любым другим полюбившимся способом наследования, например, используя классы из ECMAScript 2015

class MyClass extends Matreshka {
	constructor() {
		this.sayHello();
	}
	sayHello() {
		alert("Hello World!");
	}
}
Задать вопрос

Matreshka#bindNode(key, node, binder, eventOptions) matreshka

Связывает свойство объекта с HTML элементом

Matreshka#bindNode - это единственный метод класса Matreshka, отвечающий за изменения DOM. Он создаёт мост между значением свойства и состоянием HTML элемента на странице: от простого инпута до сложного виджета (сложность элементов не ограничена). bindNode, по праву, можно назвать главным методом фреймворка. После связывания свойства экземпляра и HTML элемента не нужно больше следить за синхронизацией данных и представления.

Для двустороннего связывания элемента и значения свойства, в метод передаются три аргумента: имя свойства (ключ), HTML элемент (или селектор) и правило привязки (синонимы: байндер, биндер, binder, привязчик). Байндер, в свою очередь, является обычным объектом и может иметь следующие свойства: on, getValue, setValue, initialize (подробнее см. binder). Все четыре свойства - опциональны. Это позволяет также объявить и односторонние привязки.

Метод bindNode поддерживает привязки "многие ко многим". С одним свойством можно связать несколько элементов, а с одним элементом можно связать несколько свойств, в том числе и от разных экземпляров разных классов.

this.bindNode('myKey', '.my-element', {
    on: 'click',
    getValue: function() { ... },
    setValue: function() { ... }
});

Например, вы хотите связать свойство объекта с элементом input[type="checkbox"]:

this.bindNode('myKey', '.my-checkbox', {
    // когда менятся состояние элемента?
    // - по событию 'click'
    on: 'click',
    // как извлечь состояние элемента?
    // - вернуть значение 'checked'
    getValue: function() {
        return this.checked;
    },
    // как установить состояние элемента?
    // - установить значение 'checked'
    setValue: function(v) {
        this.checked = !!v;
    }
});

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

// устанавливает checked = true
this.myKey = true;

Если значение свойства экземпляра класса не задано, Матрешка, после привязки, попробует извлечь это значение из HTML узла, используя getValue. Отменить это поведение можно передав свойство assignDefaultValue: false в объект события.

this.bindNode('myKey', '.my-element', binder, {
    assignDefaultValue: false
});

Более сложный пример: связывание свойства объекта с виджетом jQuery UI

<div class="my-slider"></div>
this.bindNode('myKey', '.my-slider', {
    // когда менятся состояние элемента?
    // - по событию 'slide'
    on: 'slide',
    // как извлечь состояние элемента?
    // - вернуть значение виджета 'value'
    getValue: function() {
        return $(this).slider('option', 'value');
    },
    // как установить состояние элемента?
    // - установить значение 'value'
    setValue: function(v) {
        $(this).slider('option', 'value', v);
    },
    // как инициализировать виджет?
    // инициализировать слайдер можно любым способом,
    // но initialize предоставляет немного синтаксического сахара
    initialize: function() {
        $(this).slider({min: 0, max: 100});
    }
});
// установит знaчeние слайдера 42
this.myKey = 42;

Выглядит просто, но вы, скорее всего, задаётесь вопросом: "Как сделать так, чтоб мне не пришлось каждый раз прописывать эти правила?". Вопрос очень правильный. Действительно, на странице может быть очень много однотипных элементов: текстовых полей, выпадающих меню, новых полей из спецификации HTML5, могут быть и сторонние виджеты (о чем говорит пример выше).

Как видно из документации к аргументам метода Matreshka#bindNode (см. ниже), третий аргумент не обязателен. Этот вопрос решает массив Matreshka.defaultBinders, который содержит функции, проверяющие HTML элемент на соответствие заданным правилам. Вы получаете возможность многократно сократить код, вынося правила привязки в отдельную часть вашего кода, а для привязки использовать синтаксис без третьего аргумента:

this.bindNode('myKey', '.my-element');

Как это сделать? Нужно добавить функцию, проверяющую ваш элемент на соответствие некоторым правилам в начало массива Matreshka.defaultBinders. Пример ниже можно использовать в качестве шаблона для создания своего стандартного байндера.

// добавляем байндер в коллекцию байндеров
// это нужно для того, чтоб сохранить возможность переопределения
Matreshka.binders.checkbox = function() {
    return {
        on: 'click',
        getValue: function() {
            return this.checked;
        },
        setValue: function(v) {
            this.checked = !!v;
        }
    }
};

// метод unshift добавляет функцию в начало массива Matreshka.defaultBinders
Matreshka.defaultBinders.unshift(function(node) {
    // проверяем, является ли элемент чекбоксом
    if(node.tagName == 'INPUT' && node.type == 'checkbox') {
        // если проверка пройдена, возвращаем новый байндер
        return Matreshka.binders.checkbox();
    }
});
this.bindNode('myKey', '.my-checkbox');
this.myKey = true;

Что делать, если вам нужно передать аргументы для инициализации какого-нибудь плагина или виджета? Всё очень просто: можно ограничиться добавлением байндера в коллекцию Matreshka.binders, не создавая функцию для Matreshka.defaultBinders.

Matreshka.binders.uiSlider = function(min, max) {
    return {
        on: 'slide',
        getValue: function() {
            return $(this).slider('option', 'value');
        },
        setValue: function(v) {
            $(this).slider('option', 'value', v);
        },
        initialize: function() {
            $(this).slider({min: min, max: max});
        }
    }
};
this.bindNode('myKey1', '.my-slider1', Matreshka.binders.uiSlider(0, 100));
this.bindNode('myKey2', '.my-slider2', Matreshka.binders.uiSlider(1, 1000));
this.myKey1 = 42;
this.myKey2 = 999;

Изменения DOM происходят синхронно, сразу после изменения свойства. Для того, чтоб DOM менялся после небольшой задержки только один раз, несмотря на то, как часто меняется свойство, передайте в аргумент eventOptions свойство debounce: true. См. Matreshka.debounce.

Matreshka.defaultBinders из коробки, начиная с версии 0.3, содержит поддержку всех без исключения HTML элементов форм: select (включая multiple), textarea, output,input (в том числе и все типы из спецификации HTML5: text, checkbox, radio, range, number, date, search, time, datetime, datetime-local, color и остальных). Это значит, что для стандартных элементов указывать байндер вовсе не обязательно.

<input type="color" class="my-color-input">
this.bindNode('myColor', '.my-color-input');
this.myColor = '#66bb6a';

Кроме всего, после привязки, вам доступен новый нестандартный CSS селектор :bound(KEY).

this.bindNode('myKey', '.my-element');

// найдет элемент '.my-inner-element' внутри '.my-element'
this.bindNode('myAnotherKey', ':bound(myKey) .my-inner-element');

И расширяется синтаксис возможных имен событий:

this.bindNode('myKey', '.my-element');

// отловит клик на элементе .my-element
this.on('click::myKey', function() { ... });

// отловит клик на элементе .my-element .my-inner-element
this.on('click::myKey(.my-inner-element)', function() { ... });

Создание песочницы

Matreshka#bindNode умеет ассоциировать экземпляр класса с "главным" HTML элементом на странице, создавая так называемую песочницу. Это нужно для того, чтоб ограничить влияние экземпляра на HTML элементы, содержащиеся в другой песочнице (т. е. в другом HTML элементе). Для привязки песочницы используется специальное свойство 'sandbox'.

<div class="my-sandbox">
    <!-- your HTML code -->
</div>
this.bindNode('sandbox', '.my-sandbox');

Определение песочницы добавляет множество удобств программисту. Например:

Для объявления песочницы можно воспользоваться методом Matreshka#bindSandbox, который требует только один аргумент.

// объявляем песочницу
this.bindNode('sandbox', '.my-sandbox');

// .my-element ищется в песочнице
this.bindNode('myKey', ':sandbox .my-element');

// для делегированных событий внутри песочницы не требуется указывать ключ
this.on('click::(.my-button)', function() { ... });

// выведет в консоль элемент песочницы
console.log(this.$bound());

// выведет в консоль элемент .inner-node, который находится внутри песочницы
console.log(this.$('.inner-node'));

Глубокое связывание

Начиная с версии 1.1, метод bindNode поддерживает так называемое "глубокое связывание". Метод научился связывать DOM узел со свойством внутри дерева вложенных объектов. Например, у вас есть вложенный объект:

this.a = {b: {c: {d: 42}}};

И вы хотите связать некий узел со свойством d из этого объекта. Достаточно только указать путь к свойству, а Матрешка будет слушать изменения во всём дереве объектов, то разрывая связь, то создавая её вновь:

this.bindNode('a.b.c.d', '.my-node');

Когда произойдут какие-нибудь изменения в дереве, bindNode отловит эти изменения и пересоздаст связь между свойством и нодой.

this.a.b = {c: {d: 41}};

Это поведение можно отменить, передав свойство deep: false в объект события (eventOptions), тогда точка в имени свойства будет проигнорирована.

Возвращает matreshka - self

Генерирует события bind bind:KEY

Аргументы

Имя Тип Описание
key string matreshka

Ключ (имя свойства)

node string node $nodes

HTML элемент, который должен быть связан со свойством экземпляра

binder optional binder

Байндер (привязчик), содержащий следующие свойства: on - какое событие должно произойти на HTML элементе, говорящее о том, что пользователь что-то изменил (например, keyup или click), getValue - как извлечь значение из HTML элемента, setValue - как установить новое значение элементу и initialize - функция, выполняющаяся однажды, при инициализации привязки. Более подробно о привязчиках можно найти в документации к ним: см. binder.

eventOptions optional eventOptions

Объект события, в который можно передать ключ "silent" (не генерировать события "bind" и "bind:KEY"), "assignDefaultValue" (извлечь ли текущее значение элемента при привязке), debounce (оптимизировать ли изменения DOM), deep (использовать ли "глубокое связывание" или игнорировать точку в имени свойства) или другие данные

Ссылки

Примеры

Кастомный чекбокс. Этот пример демонстрирует создание кастомного элемента, по клику на который у него меняется класс "checked"

this.bindNode('myKey', '.custom-checkbox', {
	on: 'click',
	getValue: function() {
		return $(this).hasClass('checked');
	},
	setValue: function(v) {
		$(this).toggleClass('checked', !!v);
	},
	// инициализируем поведение элемента
	// по клику на элемент меняется наличие класса 'checked'
	initialize: function() {
		$(this).on('click', function() {
			$(this).toggleClass('checked');
		});
	}
});

Кастомный чекбокс 2. Этот пример повторяет предыдущий, но использует Matreshka#defaultBinders, и проверяет элемент на наличие класса custom-checkbox. Если проверка пройдена, возвращает байндер

// добавляем байндер в коллекцию байндеров
Matreshka.binders.customCheckbox = function() {
	return {
		on: 'click',
		getValue: function() {
			return $(this).hasClass('checked');
		},
		setValue: function(v) {
			$(this).toggleClass('checked', !!v);
		},
		initialize: function() {
			$(this).on('click', function() {
				$(this).toggleClass('checked');
			});
		}
	}
};

MK.defaultBinders.unshift(function(element) {
	// проверяем, есть ли у элемента класс "custom-checkbox"
	if($(element).hasClass('custom-checkbox') ) {
		// если проверка пройдена, возвращаем новый байндер
		return Matreshka.binders.customCheckbox();
	}
});

this.bindNode('myKey', '.my-custom-checkbox');

Событие "bind", которое генерируется после связывания любого свойства и HTML узла

this.on('bind', function() { alert('ok!'); });
this.bindNode('myKey', '.my-element'); // alerts "ok!"

Событие "bind:KEY", которое генерируется при связывании конкретного свойства и HTML узла

this.on('bind:myKey', function() { alert('ok!'); });
this.bindNode('myKey', '.my-element'); // alerts "ok!"

Подмена DOM события для стандартного байндера. Например, мы хотим связать input[type="text"] со свойством. По умолчанию, стандартный байндер для этого элемента содержит свойство "on" со значением "keydown paste". Это значит, что значение свойства экземпляра и состояние элемента будут синхронизированы, когда пользователь отпускает клавишу клавиатуры или вставляет содержимое из буфера обмена. В случае, если вы хотите, чтоб синхронизация происходила по DOM событию "blur", вам потребуется передать третьим аргументом объект, содержащий единственное свойство "on". Этот объект объединится со стандартным байндером, сохранив при этом значения getValue и setValue

this.bindNode('myKey', '.my-input', {on: "blur"});

Если элемент не найден, бросается исключение "Bound element is missing". Для того, чтоб избежать ошибки используйте метод Matreshka#bindOptionalNode

var $el = $();
this.bindNode('x', $el); // Ошибка, так как $el пуст

Синхронизация значения свойства и HTML содержимого элемента

this.bindNode('myKey', '.my-element', {
	setValue: function(v) {
		this.innerHTML = v;
	}
});

// можно сделать проще
this.bindNode('myKey', '.my-element', MK.binders.html());
Задать вопрос

Matreshka#bindNode(keyElementPairs, binder, eventOptions)

Альтернативный синтаксис: пары "ключ-элемент"

В метод Matreshka#bindNode можно передать объект с парами ключ-элемент, чтобы избежать многократного вызова метода и сократить код

Аргументы

Имя Тип Описание
keyElementPairs object

(см. пример)

binder optional binder

(см. выше)

eventOptions optional eventOptions

(см. выше)

Примеры

this.bindNode({
	myKey1: '.custom-checkbox',
	myKey2: 'textarea'
});

Начиная с версии 1.1 синтаксис метода немного расширился: вместо элемента, можно передать массив, состоящий из элемента и байндера

this.bindNode({
	myKey1: ['.custom-checkbox', MK.binders.customCheckbox()],
	myKey2: 'textarea',
	myKey3: ['.my-node', {
		setValue: function(v) {
			// do something
		}
	}]
});
Задать вопрос

Matreshka#bindNode(setOfArguments, eventOptions)

Альтернативный синтаксис "куча аргументов"

Еще один синтаксис для метода Matreshka#bindNode. Этот способ может показаться непривлекательным, но, иногда, есть нужда привязать много элементов с различными байндерами за один присест. С таким синтаксисом вы можете присвоить определенные байндеры какой-нибудь переменной, затем легко удалить все и сразу, используя Matreshka#unbindNode.

Аргументы

Имя Тип Описание
setOfArguments array

Массив массивов аргументов (см. пример)

eventOptions optional eventOptions

(см. выше)

Примеры

this.bindNode([
	[{
		myKey1: '.my-element1',
		myKey2: '.my-element2'
	}],
	[{
		myKey3: '.my-element3',
		myKey4: '.my-element4'
	}, {
		on: 'click',
		getValue: function() { ... },
		setValue: function() { ... }
	}],
	[{
		myKey5: '.my-element5',
		myKey6: '.my-element6'
	}, {
		on: 'somethingelse',
		getValue: function() { ... },
		setValue: function() { ... }
	}]
]);
Задать вопрос

Matreshka#bindSandbox(node, eventOptions)

Добавлено в версии 1.5.

Привязывает песочницу

Оптимизированный метод для быстрого связывания свойства "sandbox" и элемента на странице.

Генерирует события bind bind:sandbox

Аргументы

Имя Тип Описание
node string node $node

Элемент, который должен стать песочницей

eventOptions optional eventOptions

Объект события, в который можно передать какие-нибудь данные для обработчика или ключ "silent", который отключает генерацию событий "bind" и "bind:sandbox"

Ссылки

Примеры

this.bindSandbox('.my-element');
Задать вопрос

Matreshka#bound(key) node null

Возвращает первый привязанный элемент или null

Возвращает node null - Привязанный элемент

Аргументы

Имя Тип Описание
key optional string

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

Примеры

this.bindNode('myKey', '.my-element');
this.bound('mykey'); // вернет $('.my-element')[0]

Возврат песочницы (вместо этого, можно использовать свойство Matreshka#sandbox)

this.bindNode('sandbox', '.app');
this.bound(); // вернет $('.app')[0]
Задать вопрос

Matreshka#boundAll(key) $nodes

Возвращает коллекцию привязанных элементов

После привязки свойств и HTML элементов, можно получить коллекцию этих элементов с помощью метода boundAll.

Возвращает $nodes - Привязанные элементы

Аргументы

Имя Тип Описание
key optional string

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

Примеры

this.bindNode('myKey', '.my-element');
this.boundAll('myKey'); // вернет $('.my-element')

Возврат песочницы (вместо этого, можно использовать свойство Matreshka#$sandbox)

this.bindNode('sandbox', '.app');
this.boundAll(); // вернет $('.app')
Задать вопрос

Matreshka#define(key, descriptor) matreshka

Полностью переписывает дескриптор свойства, используя Object.defineProperty

Используйте метод только тогда, когда знаете, что делаете.

Возвращает matreshka - self

Аргументы

Имя Тип Описание
key string

Ключ

descriptor function

Дескриптор

Примеры

Простой пример

this.define('myKey', {
	get: function() { ... }
	set: function() { ... }
});
Задать вопрос

Matreshka#define(keyObjectPairs) matreshka

Альтернативный синтаксис для метода Matreshka#define "ключ-дескриптор"

Работа метода очень похожа на Object.defineProperties

Возвращает matreshka - self

Аргументы

Имя Тип Описание
keyObjectPairs object

Объект, содержащий пары ключ-дескриптор

Примеры

this.define({
	myKey1: {
		get: function() { ... }
		set: function() { ... }
	},
	myKey2: {
		get: function() { ... }
		set: function() { ... }
	}
});
Задать вопрос

Matreshka#defineGetter(key, getter)

Устанавливает кастомный геттер для свойства

Этот метод позволяет установить геттер (getter), используя нативный метод Object.defineProperty. Возвращаемое значение свойства вычисляется при каждом обращении к свойству, поэтому более предпочтительным методом, с точки зрения производительности, является Matreshka#linkProps.

Аргументы

Имя Тип Описание
key string

Ключ свойства, для которого устанавливается геттер

getter function

Функция-геттер

Примеры

this.defineGetter('myKey', function() {
	return 42; // функция может возвращать любое вычисляемое значение
});
Задать вопрос

Matreshka#defineGetter(keyGetterPairs)

Альтернативный синтаксис метода Matreshka#defineGetter для установки геттера "ключ-геттер"

Аргументы

Имя Тип Описание
keyGetterPairs object

Объект со свойствами ключ-геттер

Примеры

this.defineGetter({
	myKey1: function() { return 1; }
	myKey2: function() { return 2; }
});
Задать вопрос

Matreshka#defineSetter(key, setter)

Устанавливает кастомный сеттер для свойства

Этот метод позволяет установить сеттер (setter), используя нативный метод Object.defineProperty. При использовании этого метода следует иметь в виду, что он переписывает встроенный Матрешкой сеттер и, таким образом убирает возможность отлова событий, типа change:КЛЮЧ. Используйте этот метод только если точно знаете, что делаете. Методы Matreshka#on и Matreshka#mediate безопасны с точки зрения стабильности создаваемого приложения, лучше используйте их.

Аргументы

Имя Тип Описание
key string

Ключ, для которого требуется установить сеттер

setter function

Функция-сеттер

Примеры

this.defineSetter('mykey', function(v) {
	alert(v);
});
Задать вопрос

Matreshka#defineSetter(keySetterPairs)

Альтернативный синтаксис метода Matreshka#defineSetter для установки сеттера "ключ-сеттер"

Аргументы

Имя Тип Описание
keySetterPairs object

Объект со свойствами ключ-сеттер

Примеры

this.defineSetter({
	myKey1: function(v) { alert(v); }
	myKey2: function(v) { alert(v); }
});
Задать вопрос

Matreshka#delay(f, delay, thisArg) matreshka

Добавлено в версии 0.3.

Выполняет функцию после заданной задержки

Работа метода очень похожа на setTimеout. В качестве контекста принимается текущий экземпляр или переданный объект.

Возвращает matreshka - self

Аргументы

0
Имя Тип Описание
f function

Функция, которая должна быть выполнена после истечения таймера

delay optional number

Задержка в миллисекундах

thisArg optional object

Контекст

Ссылки

Примеры

this.on('change:x', function() {
	alert(this.x); // 1 ... 2
});

this.delay(function() {
	this.x = 2;
}, 100);

this.x = 1;
Задать вопрос

Matreshka#get(key)

Возвращает значение свойства

Аргументы

Имя Тип
key string

Примеры

// то же самое, что и this['myKey'] или this.myKey
this.get('myKey');
Задать вопрос

Matreshka#linkProps(targetKeys, sourceKeys, handler=function(v){return v}, eventOptions)

Добавлено в версии 0.1.

Создает зависимость значения одного свойства от значений других

Метод linkProps создает зависимость значения свойства (первый аргумент) от значений других свойств (второй аргумент). Метод защищен от цикличных ссылок (например a зависит от b, b зависит от c, а c зависит от a) и при ошибке вычислений не блокирует страницу и не бросает исключение о переполнении стека.

В версии 1.5 аргумент setOnInit заменен на объект eventOptions (четвертый аргумент), включающий несколько дополнительных возможностей метода.

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

Вы можете передать какие-нибудь данные в обработчик события изменения искомого свойства, используя аргумент eventOptions.

this.on('change:a', function(evt) {
    alert(evt.foo); // 'bar'
});

this.linkProps('a', 'b c', function(b, c) {
    return b + c;
}, {
    foo: 'bar'
});

Кроме этого в eventOptions, можно передать и специальные флаги, например silent: true.

this.on('change:a', function(evt) {
    alert('foo');
});

this.linkProps('a', 'b c', function(b, c) {
    return b + c;
}, {
    silent: true
});

this.b = 1;

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

Если изменить искомое свойство другим способом, например, присваиванием (this.a = 42), то, очевидно, обработчик будет вызван.

Полный список поддерживаемых флагов можно найти в документации к методу Matreshka#set.

Вычисление свойства при вызове linkProps

По умолчанию, свойство будет вычислено сразу, при вызове linkProps.

var handler = function(b, c) {
    return b + c;
};

this.b = 1;
this.c = 2;
this.linkProps('a', 'b c', handler);
alert(this.a); // 3

Для отмены этого поведения передайте в объект eventOptions свойство setOnInit: false. Оно необходимо в тех случаях, когда свойства, от которых зависит искомое свойство еще не заданы, и вы не хотите, чтоб значением свойства стала какая-нибудь ерунда. В примере ниже linkProps вычислит сумму b и c как undefined + undefined и значением свойства a станет NaN.

var handler = function(b, c) {
    return b + c;
};

this.linkProps('a', 'b c', handler);
alert(this.a); // NaN
this.linkProps('a', 'b c', handler, {
    setOnInit: false // теперь всё хорошо
});

Мгновенное вычисление свойства

Реакция на изменения свойств мгновенна и синхронна. Это значит, что при изменении свойста от которого зависит искомое свойство, вычисление второго произойдет моментально. Взгляните на пример:

var handler = function(b, c) {return b + c;};

this.linkProps('a', 'b c', handler);
this.b = 1;
this.c = 2;

Функция handler будет вызвана трижды. Первый раз - при вызове linkProps (если setOnInit не задан), второй раз - при изменении свойства b, третий - при изменении свойства c. Такое поведение обусловлено идеей о том, что все реакции на изменения должны происходить последовательно и предсказуемо. Для оптимизации этого поведения, передайте в объект eventOptions свойство debounce: true. См. Matreshka.debounce.

var handler = function(b, c) {
    return b + c;
};

this.linkProps('a', 'b c', handler, {
    debounce: true
});
this.b = 1;
this.c = 2;

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

Аргументы

Имя По умолчанию Тип Описание
targetKeys string array

Свойство (свойства) которое зависит от других свойств

sourceKeys string array

От каких свойств зависит искомое свойство (свойства)

handler optional function(v){return v} function

Функция, возвращающая новое значение

eventOptions optional object

Объект, в который можно передать какие-нибудь данные для обработчика события, слушающего изменения targetKeys или специальные флаги (см. описание метода); кроме этого, к linkProps можно применить паттерн Matreshka.debounce для того, чтоб многократные изменения sourceKeys меняли targetKeys однократно.

Примеры

this.linkProps('greeting', 'name', function() {
	return 'Hello, ' + this.name + '!';
});

this.name = 'Joe';

alert(this.greeting); // 'Hello, Joe!'

Сложный пример: вычисление периметра прямоугольника по двум сторонам (и сторон по периметру). Как видите, linkProps можно использовать и для решения математических задач, где каждый член уравнения можно использовать, как неизвестное

this.a = 3;

this.b = 4;

this.linkProps('p', 'a b', function(a, b) {
	return (a + b) * 2;
});

this.linkProps('a', 'p b', function(p, b) {
	return p/2 - b;
});

this.linkProps('b', 'p a', function(p, a) {
	return p/2 - a;
});

alert(this.p); // 14

this.on('change:p', function() {
	alert('периметр изменен и равен ' + this.p);
});

this.a = 5; // alerts "периметр изменен и равен 18"

Начиная с версии 1.1, можно использовать путь к ключу во втором аргументе, вместо ключа

this.a = {b: {c: 21}};

this.linkProps('x', 'a.b.c', function(c) {
	return c * 2;
});

alert(this.x); //42
Задать вопрос

Matreshka#linkProps(targetKeys, instancesAndKeys, handler=function(v){return v}, eventOptions)

Добавлено в версии 0.2.

Дополнительная возможность метода Matreshka#linkProps: зависимость от значений свойств других объектов

Аргументы

Имя По умолчанию Тип Описание
targetKeys string array

Свойство (свойства) которое зависит от других свойств

instancesAndKeys array

Массив, который содержит объекты (четные элементы) их ключи (нечетные элементы), от которых зависит искомое свойство (свойства). Такой, возможно, странный синтаксис является следствием ограничений синтаксиса JavaScript.

handler optional function(v){return v} function

Функция, возвращающая новое значение

eventOptions optional object

См. выше

Примеры

Свойство sum является суммой свойств a и b других объектов и вычисляется каждый раз при их изменении

anotherInstance1.a = 2;

anotherInstance2.b = 3;

this.linkProps('sum', [
	anotherInstance1, 'a',
	anotherInstance2, 'b'
], function(a, b) {
	return a + b;
});

alert(this.sum); // 5

this.on('change:sum', function() {
	alert('this.sum равен ' + this.sum);
});

anotherInstance1.a = 5; // "this.sum равен 8"
Задать вопрос

Matreshka#mediate(key, mediator)

Добавлено в версии 0.1.

Трансформирует значение свойства при его изменении

Этот метод используется для преобразования значения свойства при его изменении. Например, вам нужно, чтоб значение свойства всегда было либо определенного типа, либо целым числом, либо быть не менее нуля и не более ста и т. д.

Аргументы

Имя Тип Описание
key string array

Ключ или массив ключей или список ключей, разделенных пробелами

mediator function

Функция-посредник (медиатор, mediator), возвращающая новое значение

Примеры

this.mediate('x', function(value) {
	return String(value);
});
this.x = 1;
alert(typeof this.x); // "string"

Список ключей, разделенных пробелами

this.mediate('x y', function(value) {
	return String(value);
});

Массив ключей

this.mediate(['x', 'y'], function(value) {
	return String(value);
});
Задать вопрос

Matreshka#mediate(keyMediatorPairs)

Добавлено в версии 0.1.

Альтернативный синтаксис метода Matreshka#mediate, принимающий в качестве аргумента объект "ключ-медиатор"

Аргументы

Имя Тип Описание
keyMediatorPairs object

Объект со свойствами ключ-медиатор

Примеры

this.mediate({
	x: String,
	y: Number,
	z: Boolean
});
this.x = 1;
this.y = 2;
this.z = 3;
alert(typeof this.x); // "string"
alert(typeof this.y); // "number"
alert(typeof this.z); // "boolean"

Список ключей, разделенных пробелами

this.mediate({
	'u v': String,
	'w x': Number,
	'y z': Boolean
});
Задать вопрос

Matreshka#off(names, callback, context) matreshka

Удаляет обработчик события

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

Возвращает matreshka - self

Генерирует события removeevent removeevent:NAME

Аргументы

Имя Тип Описание
names optional eventNames

Разделенный пробелами список имен событий (например, "change:x ajaxcomplete change:y")

callback optional eventHandler

Функция-обработчик

context optional object

Контекст

Ссылки

Примеры

this.off('change:x bind');

Удаление всех событий

this.off();

Удаление события с определенным обработчиком

var handler = function() {
	//...
}
this.on('change:x', handler);
this.off('change:x', handler);

Удаление события с определенным контекстом

var object = {};
this.on('change:x', handler, object);
this.off('change:x', handler, object);
Задать вопрос

Matreshka#on(names, callback, triggerOnInit, context) matreshka

Добавляет обработчик события

Метод Matreshka#on добавляет обработчик события для экземпляра класса Matreshka. Полный список возможных событий с описанием см. здесь: eventNames.

Возвращает matreshka - self

Генерирует события addevent addevent:NAME

Аргументы

false
Имя Тип Описание
names eventNames

Имя события или несколько имен, разделенных пробелом (например, "change:x ajaxcomplete change:y")

callback eventHandler

Функция, которая вызывается по событию

triggerOnInit optional boolean

Если аргумент triggerOnInit равен true, то обработчик будет вызван немедленно после инициализации.

context optional object

Контекст обработчика. Другими словами, this при вызове callback

Ссылки

Примеры

this.on('foo', function() {
	alert('Custom Event is fired');
});

this.trigger('foo');

Передача контекста

this.on('foo', function() {
	alert(this.a); // 5
}, {a: 5});

this.trigger('foo', 'Hello world');

Вызов обработчика сразу после инициализации

//Выводит на экран "bar" сиюсекундно и ждет генерации события "foo"
this.on('foo', function() {
	alert('bar');
}, true);
Задать вопрос

Matreshka#on(evtnameHandlerObject, triggerOnInit, context) matreshka

Добавлено в версии 1.1.

Альтернативный синтаксис: пары "событие-обработчик"

В метод Matreshka#on можно передать объект с парами событие-обработчик, чтобы избежать многократного вызова метода и сократить код.

Возвращает matreshka - self

Аргументы

false
Имя Тип Описание
evtnameHandlerObject object

Объект с событиями

triggerOnInit optional boolean

Если аргумент triggerOnInit равен true, то обработчики будут вызван немедленно после инициализации

context optional object

Контекст обработчика

Примеры

this.on({
	'custom': function(evt) { ... },
	'click::x': function(evt) { ... },
	'change:y': function(evt) { ... }
});

Особенно круто этот способ вызова метода on выглядит с использованием синтаксиса ECMAScript 2015

this.on({
	'custom': evt => ...,
	'click::x': evt => ...,
	'change:y': evt => ...,
});
Задать вопрос

Matreshka#onDebounce(names, callback, debounceDelay, triggerOnInit, context) matreshka

Добавляет обработчик события, вызываемый лишь однажды за определенный промежуток времени

Метод позволяет добавить обработчик события на экземпляр класса Matreshka, устраняя "дребезжание" обработчика. Функция может быть вызвана лишь один раз за определенный промежуток времени. В остальном, метод работает так же, как и Matreshka#on.

Возвращает matreshka - self

Генерирует события addevent addevent:NAME

Аргументы

0 false
Имя Тип Описание
names eventNames

Имя события или несколько имен, разделенных пробелом (например, "change:x ajaxcomplete change:y").

callback eventHandler

Функция, которая вызывается по событию

debounceDelay optional number

Задержка

triggerOnInit optional boolean

Если аргумент triggerOnInit равен true, то обработчик будет вызван немедленно после инициализации

context optional object

Контекст обработчика. Другими словами, this при вызове callback

Ссылки

Примеры

this.onDebounce('change:x', function() {
	alert('x = ' + this.x); // x = 100
}, 300);

this.x = 1;

for(var i = 0; i < 100; i++) {
	this.x++;
}
Задать вопрос

Matreshka#onDebounce(evtnameHandlerObject, debounceDelay, triggerOnInit, context) matreshka

Добавлено в версии 1.1.

Альтернативный синтаксис: пары "событие-обработчик"

В метод Matreshka#onDebounce можно передать объект с парами событие-обработчик, чтобы избежать многократного вызова метода и сократить код.

Возвращает matreshka - self

Аргументы

0 false
Имя Тип Описание
evtnameHandlerObject object

Объект с событиями

debounceDelay optional number

Задержка

triggerOnInit optional boolean

Если аргумент triggerOnInit равен true, то обработчики будут вызван немедленно после инициализации

context optional object

Контекст обработчиков

Ссылки

Примеры

this.onDebounce({
	'custom': function(evt) { ... },
	'click::x': function(evt) { ... },
	'change:y': function(evt) { ... }
});
Задать вопрос

Matreshka#once(names, callback, context) matreshka

Добавляет обработчик событий, который может быть вызван однажды

Метод работает так же, как и Matreshka#on но передаваемый обработчик может быть вызван только один раз. Обратите внимание, что у метода отсутствует аргумент triggerOnInit.

Возвращает matreshka - self

Генерирует события addevent addevent:NAME

Аргументы

Имя Тип Описание
names eventNames

Имя события или несколько имен, разделенных пробелом (например, "change:x ajaxcomplete change:y")

callback eventHandler

Функция, которая вызывается по событию

context optional object

Контекст обработчика

Ссылки

Примеры

this.x = 1;

this.once('change:x', function() {
	alert('x is changed');
});

this.x = 2; // выводит 'x is changed'

this.x = 3; // ничего не делает
Задать вопрос

Matreshka#once(evtnameHandlerObject, context) matreshka

Добавлено в версии 1.1.

Альтернативный синтаксис: пары "событие-обработчик"

В метод Matreshka#once можно передать объект с парами событие-обработчик, чтобы избежать многократного вызова метода и сократить код.

Возвращает matreshka - self

Аргументы

Имя Тип Описание
evtnameHandlerObject object

Объект с событиями

context optional object

Контекст обработчиков

Ссылки

Примеры

this.once({
	'custom': function(evt) { ... },
	'click::x': function(evt) { ... },
	'change:y': function(evt) { ... }
});
Задать вопрос

Matreshka#parseBindings(node) $nodes

Добавлено в версии 1.1.

Парсит DOM дерево, объявляя привязки свойств, заключенных в двойные фигурные скобки.

Начиная с версии 1.1, Матрешка включает в себя простой DOM парсер, обрабатывающий синтаксические конструкции, заключенные в двойные фигурные скобки. Метод parseBindings принимает один опциональный аргумент: HTML строку, DOM узел или селектор, соответствующий DOM узлу. Если аргумент не задан, парсер обрабатывает песочницу (см. Matreshka#bindNode).

Так как метод является DOM шаблонизатором (а не строковым HTML шаблонизатором), все дочерние DOM узлы переданного элемента остаются в своём прежнем состоянии (например, DOM события не затираются).

Поддерживаемый синтаксис.

  1. HTML привязка

    <!--
    Создаст DOM узел на месте
    и свяжет свойство name из объекта user с этим узлом
    JS: this.user = {name: 'Joe'}
    -->
    <span>Hello, {{user.name}}</span>
  2. Привязка элементов форм.

    <!--
    Свяжет свойство "x" экземпляра с текстовым
    полем (двусторонняя привязка)
    JS: this.x = 'some value';
    -->
    <input type="text" value="{{x}}">
<!--
Для привязки textarea и select нужно использовать атрибут value
-->
<textarea value="{{x}}"></textarea>
<select value="{{x}}">...</select>
<!--
Свяжет свойство "x" экземпляра с чекбоксом
(двусторонняя привязка)
JS: this.x = true;
-->
<input type="checkbox" checked="{{x}}">
  1. Привязка атрибутов.
    <!--
    Значение атрибута href будет зависеть
    от значений свойств "category" и "someObject.page"
    (односторонняя привязка)
    JS:
     this.category = 'matreshka';
     this.someObject = {page: 42}
    -->
    <a href="http://example.com/{{category}}/{{someObject.page}}">A link</a>
    <!--
    Результат:
    <a href="http://example.com/matreshka/42">A link</a>
    -->

Зачем нужен такой метод?

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

Не противоречит ли это идеологии Матрешки ("вся логика должна быть заключена в JavaScript файле")?

Нет, в парсере не предусмотрено циклов, условных операторов и любой другой логики. Объявление простых привязок это всё, что доступно разработчику, использующему parseBindings.

Производительность

Метод работает несколько медленнее, чем объявление привязок вручную методом Matreshka#bindNode. Это нужно иметь в виду при создании приложения с очень серьезными требованиями к производительности. Скорость немного падает только во время процесса связывания. В остальном, привязки работают так же быстро, как и с Matreshka#bindNode.

Возвращает $nodes - Коллекция DOM узлов (как правило, состоящая из одного элемента), переданная в функцию в качестве аргумента или, если аргументов нет, песочница

Аргументы

Имя Тип Описание
node optional string node $nodes

HTML строка, селектор, DOM узел или коллекция DOM узлов

Примеры

Парсинг заданного узла

this.parseBindings(node);

> Если фигурные скобки не устраивают, поменяйте их на что-то другое, используя Matreshka.parserBrackets

Парсинг узла по селектору

this.parseBindings('.my-node');

Парсинг HTML строки

var $node = this.parseBindings('<h3>Hello, {{name}}</h3>');
this.name = 'Arthur Philip Dent';

Парсинг песочницы

this.bindNode('sandbox', '.my-node');
this.parseBindings();
Задать вопрос

Matreshka#remove(key, eventOptions) matreshka

Удаляет свойство

Возвращает matreshka - self

Генерирует события delete delete:KEY

Аргументы

Имя Тип Описание
key string

Ключ или ключи, разделенные пробелом

eventOptions optional eventOptions

Объект события

Примеры

this.remove('myKey');
this.remove('myKey1 myKey2');

Использование eventOptions

this.remove('myKey', {
	silent: true
});
Задать вопрос

Matreshka#select(selector) node null

Возвращает элемент из песочницы, соответствующий селектору

Метод очень похож на Matreshka#selectAll, но возвращает лишь один элемент или null

Возвращает node null

Аргументы

Имя Тип Описание
selector string

Селектор

Примеры

this.bindNode('sandbox', '.app');
this.select('.my-element');
// то же самое, что и
this.bound().querySelector('.my-element');
// и то же самое, что и
$('.app').find('.my-element')[0];
Задать вопрос

Matreshka#selectAll(selector) $nodes

Возвращает элементы из песочницы, соответствующие селектору

После создания песочницы методом Matreshka#bindNode, можно получать и использовать элементы, находящиеся в ней. Кроме этого, метод поддерживает селектор :bound(KEY)

Возвращает $nodes

Аргументы

Имя Тип Описание
selector string

Cелектор

Примеры

this.bindNode('sandbox', '.app');
this.selectAll('.my-element');
// то же самое, что и
this.$bound().find('.my-element');
// и то же самое, что и
$('.app').find('.my-element');

Селектор :bound(KEY)

this.bindNode('myKey', '.my-element');
this.selectAll(':bound(myKey) .my-another-element');
// то же самое, что и
this.$bound('myKey').find('.my-another-element');
// и то же самое, что и
$('.my-element').find('.my-another-element');
Задать вопрос

Matreshka#set(key, value, eventOptions)

Устанавливает значение свойства, позволяя передать объект события в качестве третьего аргумента

Список поддерживаемых флагов:

  • silent - не вызывать события change и change:KEY
  • silentHTML - не менять состояние привязанных элементов
  • force - вызвать события change и change:KEY даже если значение свойства не изменилось
  • forceHTML - изменить состояние привязанного элемента, даже если значение свойства не изменилось. Эта опция нужна, если привязанный элемент был отрисован после привязки (например, в select были добавлены теги option)
  • skipMediator - предотвращает трансформацию свойства медиатором (см. Matreshka#mediate)
  • skipLinks - предотвращает работу зависимостей, созданных с помощью Matreshka#linkProps

Генерирует события change change:KEY beforechange beforechange:KEY

Аргументы

Имя Тип Описание
key string

Ключ

value *

Значение

eventOptions optional eventOptions

Объект события

Примеры

this.on('change:myKey', function(eventOptions) {
	alert(eventOptions.value);
});

// то же самое, что и this['myKey'] = 3
// или this.myKey = 3
// выводит на экран 3
this.set('myKey', 3);

Используя eventOptions

this.on('change:myKey', function(eventOptions) {
	alert(eventOptions.value);
});

// alert не срабатывает
this.set('myKey', 4, {
	silent: true
});

Передача произвольных данных в обработчик

this.on('change:myKey', function(eventOptions) {
	alert(eventOptions.myCustomFlag);
});

// выводит на экран 42
this.set('myKey', 4, {
	myCustomFlag: 42
});
Задать вопрос

Matreshka#set(keyValuePairs, eventOptions)

Альтернативный синтаксис метода Matreshka#set "ключ-значение"

Аргументы

Имя Тип Описание
keyValuePairs object

Объект, содержащий пары ключ-значение

eventOptions optional eventOptions

Объект события

Примеры

this.set({
	myKey1: 1,
	myKey2: 2
});

Передача eventOptions в качестве второго аргумента

this.set({
	myKey: 3
}, {
	myFlag: 'Jigurda'
});
Задать вопрос

Matreshka#setClassFor(key, class, updateCallback)

Добавлено в версии 1.1.

Устанавливает класс для свойства

Метод позволяет строго указать на то, экземпляром какого класса будет заданное свойство. Разработчику не нужно беспокоиться о том, что значение свойства случайно перезапишется "голыми" данными.

Метод является надстройкой над Matreshka#mediate и переопределяет медиатор, исключая конфликт двух медиаторов.

Экземпляр класса создается во время запуска метода Matreshka#setClassFor. Первым аргументом конструктора класса становится текущее значение свойства. В конструкторе класса необходимо предусмотреть то, что в него попадет либо undefined (если свойство не содержало до этого никаких данных), либо объект, с которым нужно что-то сделать (например, расширить экземпляр класса свойствами объекта).

На деле это выглядит просто: вы создаете обычный класс, который почти всегда принимает какие-нибудь данные, которые нужно обработать (например, использовать их в методе Matreshka.Object#jset).

При попытке присвоить свойству другое значение (объект или массив), внутренний механизм метода setClassFor, вместо присваивания, делает следующее:

  • Если указана функция updateCallback, метод запускает его с двумя аргументами: текущим значением свойства и данными, которые код пытается присвоить.
  • Если заданный класс унаследован от Matreshka.Object, экземпляр обновляется новыми данными, используя метод Matreshka.Object#jset.
  • Если заданный класс унаследован от Matreshka.Array, экземпляр обновляется новыми данными, используя метод Matreshka.Object#recreate.
  • Если не указана функция updateCallback и если класс не унаследован от Matreshka.Object или Matreshka.Array, экземпляр расширяется свойствами объекта, который код пытается присвоить.

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

Аргументы

Имя Тип Описание
key string array

Ключ или массив ключей, или список ключей, разделенных пробелами

class function

Класс, который вы хотите установить свойству

updateCallback optional function

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

Примеры

var SubClass = Class({
	// ...
});

// ...

this.setClassFor('x', SubClass);

// пытаемся присвоить свойству другое значение
this.x = {a: 42};

// this.x по-прежнему экземпляр класса SubClass
alert(this.x instanceof SubClass); // true
alert(this.x.a); // 42

Использование updateCallback.

this.setClassFor('x', SubClass, function(instance, data) {
	updateSomeHow(instance, data);
});

Получение родителя и ключа. Кроме данных (первый аргумент), в конструктор создаваемого класса, передается ссылка на объект, вызвавший setClassFor и ключ свойства

var MySubClass = Class({
	'extends': Matreshka,
	constructor: function(data, parent, key) {
		// parent - это экземпляр MyClass
		// key - ключ ("х")
	}
});

var MyClass = Class({
	'extends': Matreshka,
	constructor: function() {
		this.setClassFor('x', MySubClass);
	}
});

Нестандартный способ использования updateCallback для игнорирования любых изменений свойства.

// MK.noop - пустая функция
this.setClassFor('x', SubClass, MK.noop);

В случае, если ваш класс не подерживает использование оператора new, вместо setClassFor воспользуйтесь методом Matreshka#mediate.

this.mediate('x', function(data, currentValue) {
	return currentValue instanceof SomeClass
		? Object.assign(currentValue, data)
		: SomeLib.initInstance(SomeClass, data);
});

Абстрактный пример с данными большой вложенности (для краткости используется синтаксис ECMAScript 7)

// app.js
class App extends MK {
	constructor(appData) {
		this.appData = appData;
		this.setClassFor('appData', AppData);
	}
}

// app-data.js
class AppData extends MK.Object {
	constructor(data) {
		super(data)
			.setClassFor({
				friends: Friends,
				settins: Settings
			});
	}
}

// friend.js
class Friend extends MK.Object {
	constructor(data) {
		super(data);
	}
}

// friends.js
class Friends extends MK.Array {
	Model = Friend;
	trackBy = 'id';
	constructor(data) {
		super(...data);
	}
}

// settings.js
class Settings extends MK.Object {
	constructor(data) {
		super(data)
			.setClassFor('credentials', Credentials);
	}
}

// credentials.js
class Credentials extends MK.Object {
	constructor(data) {
		super(data);
	}
}

// app-init.js
var app = new App({
	settings: {
		name: 'Vasiliy Vasiliev',
		credentials: {
			email: 'vasia.vasia@gmail.com'
		}
	},
	friends: [{
		name: 'Yulia Zuyeva',
		id: 1
	}, {
		name: 'Konstantin Konstantinopolsky',
		id: 2
	}, {
		name: 'nagibator3000',
		id: 3
	}]
});

// данные можно сериализировать и передать на сервер
JSON.stringify(app.appData);


// потом просто присвоить новые данные свойству appData
// при этом, структура классов не изменится
app.appData = {
	settings: {
		name: 'Petr Petrov',
		credentials: {
			email: 'petr.petrov@gmail.com'
		}
	},
	friends: [{
		name: 'Yulechka Zuyeva',
		id: 1
	}, {
		name: 'Konstantin Konstantinopolsky',
		id: 2
	}]
};
Задать вопрос

Matreshka#setClassFor(keyClassPairs, updateCallback)

Добавлено в версии 1.1.

Альтернативный синтаксис метода Matreshka#setClassFor, принимающий в качестве аргумента объект "ключ-класс"

Аргументы

Имя Тип Описание
keyClassPairs object

Объект со свойствами ключ-класс

updateCallback optional function

Функция, вызывающаяся при каждой попытке присвоить новые данные свойству.

Примеры

this.setClassFor({
	x: Class1,
	y: Class2,
	z: Class3
}, function(data) {
	instance.jset(data);
});
Задать вопрос

Matreshka#trigger(names, arg) matreshka

Генерирует событие

После добавление обработчиков событий с помощью метода Matreshka#on, Matreshka#onDebounce или Matreshka#once, событие можно генерировать вручную с помощью этого метода.

Возвращает matreshka - self

Аргументы

Имя Тип Описание
names optional eventNames

Имя события или несколько имен, разделенных пробелом

arg optional *

Аргументы, которые будут переданы обработчикам

Ссылки

Примеры

this.on('foo bar', function(a, b, c) {
	alert(a + b + c);
});
this.trigger('bar', 1, 2, 3); // alerts 6
Задать вопрос

Matreshka#unbindNode(key, node, eventOptions) matreshka

Разрывает связь между свойством и HTML элементом

Используя этот метод, можно удалить недавно добавленную, но уже не нужную связь между свойством и элементом.

Возвращает matreshka - self

Генерирует события unbind unbind:KEY

Аргументы

Имя Тип Описание
key string null

Ключ или список ключей, разделенных пробелами. Если вместо ключа передать null, удалятся все привязки для данного экземпляра

node optional string node $nodes

HTML элемент, с которым свойство больше не хочет иметь дела

eventOptions optional eventOptions

Объект события, в который можно передать какие-нибудь данные для обработчика или ключ "silent", который отключает генерацию событий "unbind" и "unbind:KEY"

Примеры

this.bindNode('myKey', '.my-element');

// меняет значение свойства и состояние HTML элемента
this.myKey = true;

this.unbindNode('myKey', '.my-element');

// теперь меняется только значение свойства
this.myKey = false;
Задать вопрос

Matreshka#unbindNode(keyElementPairs, eventOptions) matreshka

Альтернативный синтаксис Matreshka#unbindNode "ключ-элемент" для Matreshka#unbindNode

Возвращает matreshka - self

Аргументы

Имя Тип Описание
keyElementPairs object

(см. пример)

eventOptions optional eventOptions

(см. выше)

Ссылки

Примеры

this.unbindNode({
	myKey1: '.my-element1'
	myKey1: '.my-element2'
});
Задать вопрос

Matreshka#unbindNode(setOfArguments, eventOptions) matreshka

Альтернативный синтаксис Matreshka#unbindNode "большая куча аргументов"

Возвращает matreshka - self

Аргументы

Имя Тип Описание
setOfArguments array

Массив массивов аргументов (см. пример)

eventOptions optional eventOptions

(см. выше)

Ссылки

Примеры

var temporaryBindings = [
	[{
		myKey1: '.my-element1'
		myKey2: '.my-element2'
	}],
	[{
		myKey3: '.my-element3'
		myKey4: '.my-element4'
	}, {
		on: 'click',
		getValue: function() { ... },
		setValue: function() { ... }
	}],
	[{
		myKey5: '.my-element5'
		myKey6: '.my-element6'
	}, {
		on: 'somethingelse',
		getValue: function() { ... },
		setValue: function() { ... }
	}]
];

this.bindNode(temporaryBindings);

// больше не нужны эти привязки
this.unbindNode(temporaryBindings);
Задать вопрос

Matreshka#$nodes: $nodes

Добавлено в версии 1.1.

Объект содержит коллекции (jQuery, Zepto, bQuery) привязанных элементов для быстрого доступа.

Ссылки

Примеры

this.bindNode('myKey', '.my-node');
this.$nodes.myKey; // то же самое, что и $('.my-node')
Задать вопрос

Matreshka#$sandbox: $nodes

Добавлено в версии 0.4.

Свойство содержит HTML песочницу в виде коллекции (jQuery, Zepto, bQuery)

Ссылки

Примеры

this.bindNode('sandbox', '.app');
this.$sandbox; // то же самое, что и $('.app')
Задать вопрос

Matreshka#isMK: boolean

isMK всегда равен true. Это свойство используется для того, чтоб определить, является ли объект экземпляром класса Matreshka

Примеры

alert(object.isMK);
Задать вопрос

Matreshka#nodes: node

Добавлено в версии 1.1.

Объект содержит привязанные элементы для быстрого доступа, в виде отдельных DOM узлов.

Обратите внимание, каждое свойство объекта содержит первый узел из связанных с соотвутствующим свойством. Для получения всех узлов, связанных с определенным свойством, используйте Matreshka#$nodes.

Ссылки

Примеры

this.bindNode('myKey', '.my-node');
this.nodes.myKey; // то же самое, что и $('.my-node')[0]
Задать вопрос

Matreshka.$bound() $nodes

Добавлено в версии 1.1.

Возвращает коллекцию привязанных элементов

Этот статичный метод работает так же, как и Matreshka#$bound и все его вариации, но принимает в качестве первого аргумента любой JavaScript объект.

Возвращает $nodes - Привязанные элементы

Ссылки

Примеры

var object = {},
	bound;
MK.bindNode(object, 'x', '.my-node');
bound = MK.$bound(object, 'x');
Задать вопрос

Matreshka.Class()

Добавлено в версии 0.2.

Содержит ссылку на глобальную функцию Class

Такой способ применения функции Class употребляется тогда, когда разрабатываемое приложение использует AMD

Примеры

MK.Class({
	method: function() {}
});

// то же самое, что и
Class({
	method: function() {}
});
Задать вопрос

Matreshka.bindNode() object

Добавлено в версии 1.1.

Связывает свойство объекта с HTML элементом

Этот статичный метод работает так же, как и Matreshka#bindNode и все его вариации, но принимает в качестве первого аргумента любой JavaScript объект.

Возвращает object - Первый аргумент

Ссылки

Примеры

var object = {};
MK.bindNode(object, 'x', '.my-node');
Задать вопрос

Matreshka.bindOptionalNode() object

Добавлено в версии 1.1.

Работает в точности так же, как и Matreshka#bindNode но не бросает исключение, если аргумент node - пустой массив, undefined или не существует

Этот статичный метод работает так же, как и Matreshka#bindOptionalNode и все его вариации, но принимает в качестве первого аргумента любой JavaScript объект.

Возвращает object - Первый аргумент

Ссылки

Примеры

var object = {};
MK.bindOptionalNode(object, 'x', '.my-node');
Задать вопрос

Matreshka.bound() node null

Добавлено в версии 1.1.

Возвращает первый привязанный элемент или null

Этот статичный метод работает так же, как и Matreshka#bound и все его вариации, но принимает в качестве первого аргумента любой JavaScript объект.

Возвращает node null - Привязаннй элемент

Ссылки

Примеры

var object = {},
	bound;
MK.bindNode(object, 'x', '.my-node');
bound = MK.bound(object, 'x');
Задать вопрос

Matreshka.boundAll() $nodes

Добавлено в версии 1.1.

Возвращает коллекцию привязанных элементов

Этот статичный метод работает так же, как и Matreshka#boundAll и все его вариации, но принимает в качестве первого аргумента любой JavaScript объект.

Возвращает $nodes - Привязанные элементы

Ссылки

Примеры

var object = {},
	bound;
MK.bindNode(object, 'x', '.my-node');
bound = MK.boundAll(object, 'x');
Задать вопрос

Matreshka.debounce(f, duration, thisArg)

Добавлено в версии 0.3.

Запускает функцию лишь однажды после истечения таймера. С каждой попыткой запуска таймер обновляется

Этот метод - реализация микропаттерна debounce, который решает проблему многократного вызова обработчика событий за определенный промежуток времени. См. пример и статью на Хабре.

Аргументы

0
Имя Тип Описание
f function

Оригинальная функция,

duration optional number

Задержка

thisArg optional *

Контекст, в котором функция должна быть запущена

Примеры

var debounced = MK.debounce(function(x) {
	console.log(x);
}, 10);

for(var i = 0; i < 100; i++) {
	debounced(i);
}

// >>> 99
Задать вопрос

Matreshka.deepFind(object, path) *

Добавлено в версии 1.5.

Возвращает свойство во вложенном объекте

Функция позволяет обратиться к свойству вложенного объекта, не бросая исключение, если один из объектов в пути не определен.

Возвращает * - Значение свойства

Аргументы

Имя Тип Описание
object object

Объект

path string

Путь к свойству

Примеры

var obj = {
		a: {
			b: {
				c: {
					d: 42
				}
			}
		}
	},
	d = MK.deepFind(obj, 'a.b.c.d');

alert(d); // 42

Прямое обращение бросает исключение

var obj = {},
	d = obj.a.b.c.d; // ошибка

deepFind возвращает undefined, если путь "сломан" и не бросает исключение

var obj = {},
	d = MK.deepFind(obj, 'a.b.c.d');

alert(d); // undefined
Задать вопрос

Matreshka.define() object

Добавлено в версии 1.1.

Полностью переписывает дескриптор свойства, используя Object.defineProperty

Этот статичный метод работает так же, как и Matreshka#define и все его вариации, но принимает в качестве первого аргумента любой JavaScript объект.

Возвращает object - Первый аргумент

Ссылки

Примеры

var object = {};
MK.define(object, 'myKey', {
	get: function() { ... }
	set: function() { ... }
});
Задать вопрос

Matreshka.defineGetter() object

Добавлено в версии 1.1.

Устанавливает кастомный геттер для свойства

Этот статичный метод работает так же, как и Matreshka#defineGetter и все его вариации, но принимает в качестве первого аргумента любой JavaScript объект.

Возвращает object - Первый аргумент

Ссылки

Примеры

var object = {};
MK.defineGetter(object, 'myKey', function() {
	return 42;
});
Задать вопрос

Matreshka.defineSetter() object

Добавлено в версии 1.1.

Устанавливает кастомный сеттер для свойства

Этот статичный метод работает так же, как и Matreshka#defineSetter и все его вариации, но принимает в качестве первого аргумента любой JavaScript объект.

Возвращает object - Первый аргумент

Ссылки

Примеры

var object = {};
MK.defineSetter(object, 'myKey', function() {
	alert('setter is running');
});
Задать вопрос

Matreshka.each(o, callback, thisArg)

Итерирует любой объект, прогоняя каждое его свойство через функцию callback

Этот статичный метод схож с работой Array.prototype.forEach.

Аргументы

Имя Тип Описание
o object

Объект

callback function

Функция, запускаемая на каждой итерации

thisArg optional *

Объект, который используется в качестве this при вызове callback

Примеры

var myObject = {
	a: 1,
	b: 2
};
MK.each(myObject, function(value, key) {
	// ...
});
Задать вопрос

Matreshka.extend(o1, o2) object

Небольшая вспомогательная функция, которая расширяет один объект свойствами другого объекта

Возвращает object - o1

Аргументы

Имя Тип
o1 object
o2 object

Примеры

var o1 = {a: 3},
	o2 = {b: 4};

MK.extend(o1, o2);
Задать вопрос

Matreshka.get() *

Добавлено в версии 1.1.

Возвращает значение свойства

Этот статичный метод работает так же, как и Matreshka#get и все его вариации, но принимает в качестве первого аргумента любой JavaScript объект.

Возвращает * - Значение свойства

Ссылки

Примеры

var object = {},
	val = MK.get(object, 'x');
Задать вопрос

Matreshka.linkProps() object

Добавлено в версии 1.1.

Создает зависимость значения одного свойства от значений других

Этот статичный метод работает так же, как и Matreshka#linkProps и все его вариации, но принимает в качестве первого аргумента любой JavaScript объект.

Возвращает object - Первый аргумент

Ссылки

Примеры

var object = {};
MK.linkProps(object, 'sum', 'a b', function(a, b) {
	return a + b;
});
object.a = 40;
object.b = 2;
alert(object.sum); // 42
Задать вопрос

Matreshka.lookForBinder(node) object

Возвращает байндер, соответствующий элементу. Если таковой не найден, возвращает undefined. Функция использует Matreshka.defaultBinders.

Возвращает object - properties

Аргументы

Имя Тип
node node

Ссылки

Примеры

console.log(Matreshka.lookForBinder($('input[type="text"]')[0]));

// вернет объект
{
	on: 'keyup paste',
	getValue: function() { return this.value; },
	setValue: function(v) {
		if( this.value != v ) {
			this.value = v;
		}
	}
}
Задать вопрос

Matreshka.mediate() object

Добавлено в версии 1.1.

Трансформирует значение свойства при его изменении

Этот статичный метод работает так же, как и Matreshka#mediate и все его вариации, но принимает в качестве первого аргумента любой JavaScript объект.

Возвращает object - Первый аргумент

Ссылки

Примеры

var object = {};
MK.mediate(object, 'x', String);
object.x = 42;
alert(typeof object.x); // string
Задать вопрос

Matreshka.off() object

Добавлено в версии 1.1.

Удаляет обработчик события

Этот статичный метод работает так же, как и Matreshka#off и все его вариации, но принимает в качестве первого аргумента любой JavaScript объект.

Возвращает object - Первый аргумент

Ссылки

Примеры

var object = {};
MK.on(object, 'foo', function(evt) {
	//...
});

MK.off(object, 'foo');
Задать вопрос

Matreshka.on() object

Добавлено в версии 1.1.

Добавляет обработчик события

Этот статичный метод работает так же, как и Matreshka#on и все его вариации, но принимает в качестве первого аргумента любой JavaScript объект.

Возвращает object - Первый аргумент

Ссылки

Примеры

var object = {};
MK.on(object, 'foo', function(evt) {
	alert(evt.hello);
});

MK.trigger(object, 'foo', {hello: 'World'});
Задать вопрос

Matreshka.onDebounce() object

Добавлено в версии 1.1.

Добавляет обработчик события, вызываемый лишь однажды за определенный промежуток времени

Этот статичный метод работает так же, как и Matreshka#onDebounce и все его вариации, но принимает в качестве первого аргумента любой JavaScript объект.

Возвращает object - Первый аргумент

Ссылки

Примеры

var object = {};
MK.onDebounce(object, 'foo', function(evt) {
	//...
});
Задать вопрос

Matreshka.once() object

Добавлено в версии 1.1.

Добавляет обработчик событий, который может быть вызван однажды

Этот статичный метод работает так же, как и Matreshka#once и все его вариации, но принимает в качестве первого аргумента любой JavaScript объект.

Возвращает object - Первый аргумент

Ссылки

Примеры

var object = {};
MK.once(object, 'foo', function(evt) {
	//...
});
Задать вопрос

Matreshka.orderBy(collection, keys, orders=asc) array

Добавлено в версии 1.6.

Сортирует переданный массив по значениям свойств объектов, которые в него входят

Этот статичный метод работает точно так же, как и метод orderBy из lodash. Он принимает коллекцию (array-like объект) первым аргументом, ключ или массив ключей - вторым, порядок (asc/desc) или массив порядков - третьим.

Возвращает array - Новый отсортированный массив

Аргументы

Имя По умолчанию Тип Описание
collection object

Коллекция (array-like объект)

keys string Array.

Ключ свойства или массив нескольких ключей, по которым коллекция будет отсортирована

orders optional asc string Array.

Порядок или массив порядков, соответствующих массиву ключей

Примеры

Пример из документации к lodash

var users = [
  { 'user': 'fred',   'age': 48 },
  { 'user': 'barney', 'age': 34 },
  { 'user': 'fred',   'age': 42 },
  { 'user': 'barney', 'age': 36 }
];

// сортирует по значениям свойств `user` по возрастанию и значениям свойств `age` по убыванию
MK.orderBy(users, ['user', 'age'], ['asc', 'desc']);
// → [{"user":"barney","age":36},{"user":"barney","age":34},{"user":"fred","age":48},{"user":"fred","age":42}]
Задать вопрос

Matreshka.parseBindings() $nodes

Добавлено в версии 1.1.

Парсит DOM дерево, объявляя привязки свойств, заключенных в двойные фигурные скобки.

Этот статичный метод работает так же, как и Matreshka#parseBindings и все его вариации, но принимает в качестве первого аргумента любой JavaScript объект.

Возвращает $nodes - Коллекция DOM узлов (как правило, состоящая из одного элемента), переданная в функцию в качестве аргумента или, если аргументов нет, песочница

Ссылки

Примеры

var object = {};
var $node = MK.parseBindings(object, '<h3>Hello, {{name}}</h3>');
object.name = 'Arthur Philip Dent';
Задать вопрос

Matreshka.randomString() string

Функция, которая возвращает уникальную псевдо-случайную строку

Для генерации строки используются функции new Date().getTime и Math.random(), так что возвращаемая строка уникальна.

Возвращает string - случайная строка

Примеры

var id = MK.randomString();
Задать вопрос

Matreshka.remove() object

Добавлено в версии 1.1.

Удаляет свойство

Этот статичный метод работает так же, как и Matreshka#remove и все его вариации, но принимает в качестве первого аргумента любой JavaScript объект.

Возвращает object - Первый аргумент

Ссылки

Примеры

MK.remove(object, 'x');
Задать вопрос

Matreshka.select() node null

Добавлено в версии 1.1.

Возвращает элемент из песочницы, соответствующий селектору

Этот статичный метод работает так же, как и Matreshka#select и все его вариации, но принимает в качестве первого аргумента любой JavaScript объект.

Возвращает node null

Ссылки

Примеры

var object = {};
MK.bindNode(object, 'sandbox', '.app');
MK.select(object, '.my-element');
Задать вопрос

Matreshka.selectAll() $nodes

Добавлено в версии 1.1.

Возвращает элементы из песочницы, соответствующие селектору

Этот статичный метод работает так же, как и Matreshka#selectAll и все его вариации, но принимает в качестве первого аргумента любой JavaScript объект.

Возвращает $nodes

Ссылки

Примеры

var object = {};
MK.bindNode(object, 'sandbox', '.app');
MK.selectAll(object, '.my-element');
Задать вопрос

Matreshka.set() object

Добавлено в версии 1.1.

Устанавливает значение свойства, позволяя передать объект события в качестве третьего аргумента

Этот статичный метод работает так же, как и Matreshka#set и все его вариации, но принимает в качестве первого аргумента любой JavaScript объект.

Возвращает object - Первый аргумент

Ссылки

Примеры

var object = {};
MK.set(object, 'x', 42, {
	someOption: true
});
Задать вопрос

Matreshka.setClassFor() object

Добавлено в версии 1.1.

Устанавливает класс для свойства

Этот статичный метод работает так же, как и Matreshka#setClassFor и все его вариации, но принимает в качестве первого аргумента любой JavaScript объект.

Возвращает object - Первый аргумент

Ссылки

Примеры

var object = {};
MK.setClassFor(object, 'x', SomeClass);
object.x = {a: 42};
alert(this.x instanceof SubClass); // true
alert(this.x.a); // 42
Задать вопрос

Matreshka.setProto(proto)

Добавлено в версии 1.7.

Позволяет установить прототип классу Matreshka

Позволяет сделать так, чтоб класс Matreshka и все её потомки были наследниками другого класса (если точнее, наследниками указанного прототипа). Использование метода требует понимания прототипного наследования в JavaScript. Метод работает везде, кроме IE9 и IE10, так как в этих браузерах не предусмотрено свойство __proto__ или метод Object.setPrototypeOf.

Аргументы

Имя Тип Описание
proto object

Прототип

Примеры

function F() {}

F.prototype.someMethod = function() {
	alert('yep');
};

Matreshka.setProto(F.prototype);
// то же самое, что и
// Object.setPrototypeOf(Matreshka.prototype, F.prototype);
// или
// Matreshka.prototype.__proto__ = F.prototype;

var instance = new Matreshka;

alert(instance instanceof F); // true

instance.someMethod(); // 'yep'

Можно унаследовать класс Matreshka от чего угодно

// перенимает все возможности React.Component
Matreshka.setProto(React.Component.prototype);
Задать вопрос

Matreshka.to() matreshka

Добавлено в версии 1.1.

Функция, конвертирующая произвольную структуру объектов и массивов в экземпляры Matreshka.Object и Matreshka.Array

Возвращает matreshka - новосозданный экземпляр Матрешки

Примеры

var mk = MK.to({
	a: 1,
	b: {
		c: 2
	},
	d: [{e: 1}, {e: 2}, {e: 3}]
});
Задать вопрос

Matreshka.toArray(arr) array

Добавлено в версии 1.1.

Конвертирует любой array-like объект в обычный массив.

Функция работает в два раза быстрее, чем Array.prototype.slice.

Возвращает array - Новый массив

Аргументы

Имя Тип Описание
arr object array

Любой array-like объект

Примеры

var object = {
	0: 'a',
	1: 'b',
	2: 'c',
	length: 3
};

console.log(MK.toArray(object)); // ['a', 'b', 'c']

Клонирование масива

var arr = ['a', 'b', 'c'],
	cloneArr = MK.toArray(arr);
Задать вопрос

Matreshka.trigger() object

Добавлено в версии 1.1.

Генерирует событие

Этот статичный метод работает так же, как и Matreshka#trigger и все его вариации, но принимает в качестве первого аргумента любой JavaScript объект.

Возвращает object - Первый аргумент

Ссылки

Примеры

var object = {};
MK.on(object, 'foo', function(evt) {
	alert(evt.hello);
});

MK.trigger(object, 'foo', {hello: 'World'});
Задать вопрос

Matreshka.trim(string) string

Добавлено в версии 1.1.

Удаляет пробелы из начала и конца строки

Метод может быть полезен в том случае, если браузер не поддерживает String.prototype.trim.

Возвращает string - Результат

Аргументы

Имя Тип Описание
string string

Строка

Примеры

console.log(MK.trim('   hello world  ')); // "hello world"
Задать вопрос

Matreshka.unbindNode() object

Добавлено в версии 1.1.

Разрывает связь между свойством и HTML элементом

Этот статичный метод работает так же, как и Matreshka#unbindNode и все его вариации, но принимает в качестве первого аргумента любой JavaScript объект.

Возвращает object - Первый аргумент

Ссылки

Примеры

var object = {};
MK.unbindNode(object, 'x', '.my-node');
Задать вопрос

Matreshka.useAs$($)

Добавлено в версии 0.2.

Заставляет использовать определенную библиотеку для работы с DOM

По умолчанию, Матрешка использует в качестве библиотеки ту, которая находится по ссылке window.$. Если такой переменной нет в глобальном пространстве имен, либо же она не включает в себя необходимый набор методов, то используется встроенная микро библиотека bQuery.

Метод Matreshka.useAs$ заставляет Матрешку использовать ту библиотеку, которую вы захотите использовать, не смотря на отсутствие таковой в глобальном пространстве имен или по другой причине (например, если используется две разных версии jQuery на странице). Желательно, чтобы метод был запущен перед объявлением какого-либо класса, так как никакой конвертации в объект новой библиотеки не происходит.

Аргументы

Имя Тип Описание
$ function

Любая библиотека (jQuery, Zepto, bQuery или др.)

Примеры

Matreshka.useAs$(jQuery.noConflict());
Задать вопрос

Matreshka.defaultBinders: array

Массив функций, возвращающих соответствующий байндер

Matreshka.defaultBinders - массив функций, которые по очереди проверяют элемент на соответствие заданным в этих функциях правилам и возвращающих байндер (см. binder). Этот массив используется тогда, когда в метод Matreshka#bindNode не был передан третий аргумент. Подробную информацию о привязках смотрите в документации к Matreshka#bindNode.

Ссылки

Примеры

Кастомный чекбокс

// добавляем байндер в коллекцию байндеров
MK.binders.customCheckbox = function() {
	return {
		on: 'click',
		getValue: function() {
			return $(this).hasClass('checked');
		},
		setValue: function( v ) {
			$(this).toggleClass('checked', !!v);
		},
		initialize: function() {
			$(this).toggleClass('checked');
		}
	}
};

// метод unshift добавляет функцию в начало массива Matreshka.defaultBinders
MK.defaultBinders.unshift( function( element ) {
	// проверяем, есть ли у элемента класс "custom-checkbox"
	if($(element).hasClass('custom-checkbox')) {
		// если проверка пройдена, возвращаем новый байндер
		return MK.binders.customCheckbox();
	}
});

// ...

this.bindNode('myKey', '.custom-checkbox');
Задать вопрос

Matreshka.parserBrackets: object

Добавлено в версии 1.5.

Содержит скобки для парсера

Объект parserBrackets позволяет изменить стандартный синтаксис парсера привязок. Он содержит два свойства: left (левая скобка, по умолчанию "{{") и right (правая скобка, по умолчанию "}}")

Примеры

Заменяет поведение парсера, используя синтаксис [[=property]] вместо {{property}}

MK.parserBrackets.left = '[[=';
MK.parserBrackets.right = ']]';
Задать вопрос

Matreshka.binders object

Пространство имен для байндеров. Этот объект можно расширять собственными свойствами, чтоб не засорять глобальное пространство имен.

Примите во внимание небольшое соглашение: каждое свойство из коллекции Matreshka.binders должно быть оформлено в виде функции, возвращающей байндер.

Ссылки

Примеры

MK.binders.myCoolBinder = function(var1, var2) {
	return {
		on: 'click',
		getValue: function() { ... },
		setValue: function() { ... },
		initialize: function() { ... }
	};
};

this.bindNode('myKey', '.my-element',
	MK.binders.myCoolBinder('Hello', 'World'));
Задать вопрос

Matreshka.binders.html() binder

Добавлено в версии 0.1.

Возвращает привязчик, меняющий innerHTML DOM элемента в зависимости от значения свойства экземпляра класса

Возвращает binder

Примеры

this.bindNode('myKey', '.my-element', MK.binders.html());
Задать вопрос

Matreshka.binders.display(value=true) binder

Добавлено в версии 0.1.

Возвращает односторонний привязчик, меняющий видимость DOM элемент (используя style.display), в зависимости от значения свойства экземпляра класса

Возвращает binder

Аргументы

Имя По умолчанию Тип Описание
value optional true boolean

Если аргумент равен true, то элемент прячется при ложном значении свойства, если равен false, прячется при правдивом значении

Примеры

this.bindNode('myKey', '.my-element', MK.binders.display(true));
this.bindNode('myKey', '.my-element', MK.binders.display(false));
Задать вопрос

Matreshka.binders.className(className) binder

Добавлено в версии 0.1.

Возвращает привязчик, который переключает имя класса DOM элемента в зависимости от значения свойства экземпляра класса. Если значение свойства нестрого равно true, имя класса добавляется, в противном случае - убирается. Логику можно изменить, добавив восклицательный знак перед именем класса, и, таким образом, имя класса будет добавляться, когда значение свойства нестрого равно false и наоборот.

Возвращает binder

Аргументы

Имя Тип
className string

Примеры

this.bindNode('myKey', '.my-element', MK.binders.className('blah'));

this.myKey = true; // добавляет класс 'blah'

this.myKey = false; // убирает класс 'blah'

Использование восклицательного знака перед именем класса

this.bindNode('myKey', '.my-element', MK.binders.className('!blah'));

this.myKey = false; // добавляет класс 'blah'

this.myKey = true; // убирает класс 'blah'
Задать вопрос

Matreshka.binders.prop(property) binder

Добавлено в версии 0.3.

Возвращает привязчик, меняющий свойство DOM элемента на значение свойства экземпляра класса

Возвращает binder

Аргументы

Имя Тип
property string

Примеры

this.bindNode('disabled', '.my-button', MK.binders.prop('disabled'));

// устанавливает свойство disabled = true для элемента
this.disabled = true;

// устанавливает свойство disabled = false для элемента
this.disabled = false;
Задать вопрос

Matreshka.binders.attr(attribute) binder

Добавлено в версии 0.3.

Возвращает привязчик, меняющий атрибут DOM элемента на значение свойства экземпляра класса

Возвращает binder

Аргументы

Имя Тип
attribute string

Примеры

this.bindNode('image', 'img.my-image', MK.binders.attr('src'));

this.image = 'http://example.com/cats.jpg';
Задать вопрос

Matreshka.binders.input(type) binder

Добавлено в версии 0.3.

Возвращает привязчик, связывающий свойство экземпляра класса с элементом input. Напрямую привязчик использовать не обязательно, так как он входит в список Matreshka.defaultBinders.

Возвращает binder

Аргументы

Имя Тип Описание
type optional string

Тип инпута

Примеры

this.bindNode('myKey', '.my-input', MK.binders.input('range'));
Задать вопрос

Matreshka.binders.output() binder

Добавлено в версии 1.4.

Возвращает привязчик, связывающий свойство экземпляра класса с элементом output. Напрямую привязчик использовать не обязательно, так как он входит в список Matreshka.defaultBinders.

Возвращает binder

Примеры

this.bindNode('myKey', '.my-output', MK.binders.output()));
Задать вопрос

Matreshka.binders.textarea() binder

Добавлено в версии 0.3.

Возвращает привязчик, связывающий свойство экземпляра с элементом textarea. Напрямую привязчик использовать не обязательно, так как он входит в список Matreshka.defaultBinders.

Возвращает binder

Примеры

this.bindNode('myKey', '.my-textarea', MK.binders.textarea());
Задать вопрос

Matreshka.binders.select(multiple) binder

Добавлено в версии 0.3.

Возвращает привязчик, связывающий свойство экземпляра с элементом select. Напрямую привязчик использовать не обязательно, так как он входит в список Matreshka.defaultBinders.

Возвращает binder

Аргументы

false
Имя Тип Описание
multiple optional boolean

Является ли селект multiple

Примеры

this.bindNode('myKey', '.my-select', MK.binders.select(true));
Задать вопрос

Matreshka.binders.progress() binder

Добавлено в версии 1.1.

Возвращает привязчик, связывающий свойство с экземпляра с элементом progress. Напрямую привязчик использовать не обязательно, так как он входит в список Matreshka.defaultBinders.

Возвращает binder

Примеры

this.bindNode('myKey', '.my-progress', MK.binders.progress());
Задать вопрос

Matreshka.binders.text() binder

Добавлено в версии 1.1.

Возвращает привязчик, меняющий textContent (текстовое содержимое) DOM элемента в зависимости от значения свойства экземпляра класса.

Matreshka.binders.text позволяет вывести содержимое свойства как есть и немного улучшает производительность из-за отсутствия необходимости браузеру парсить HTML.

Возвращает binder

Примеры

this.bindNode('myKey', '.my-node', MK.binders.text());
Задать вопрос

Matreshka.binders.style(property) binder

Добавлено в версии 1.1.

Возвращает привязчик, меняющий заданное свойство стиля DOM элемента в зависимости от значения свойства экземпляра класса.

Возвращает binder

Аргументы

Имя Тип Описание
property string

Свойство style (camel-cased)

Примеры

this.bindNode('myKey', '.my-node', MK.binders.style('backgroundColor'));
this.myKey = 'red'; // цвет фона ``.my-node`` стал красным
Задать вопрос

Matreshka.binders.dataset(property) binder

Добавлено в версии 1.1.

Возвращает привязчик, меняющий заданное свойство объекта dataset DOM элемента в зависимости от значения свойства экземпляра класса.

Возвращает binder

Аргументы

Имя Тип Описание
property string

Свойство dataset

Примеры

this.bindNode('myKey', '.my-node', MK.binders.dataset('myProp'));
this.myKey = 'cool value';
Задать вопрос

Matreshka.binders.file(readAs) binder

Добавлено в версии 1.1.

Возвращает привязчик для input[type="file"].

Байндер позволяет не только получить основные данные о файле, но и считать его, не вызывая FileReader вручную.

Если аргумент readAs не задан, то в привязанное свойство попадает значение инпута после его изменения (по событию change). Если readAs задан, то байндер считает файл и преобразует в необходимый формат (data URI, Blob...) и только после прочтения файла свойство изменится.

Результирующим значением свойства становится файл (нативный File) или массив файлов при наличии атрибута multiple. При этом, результат чтения попадет в объект каждого файла в виде свойства readerResult.

Возвращает binder

Аргументы

Имя Тип Описание
readAs optional string

Значением аргумента readAs могут быть "arrayBufer", "binaryString", "dataURL", "text". Значение зависит от наличия соответствующих методов в интерфейсе FileReader

Ссылки

Примеры

this.bindNode('myKey', '.my-file', MK.binders.file('dataURL'));
// ... пользователь меняет содержимое инпута,
// выбирая my-image.png из файловой системы ...
this.on('change:myKey', function() {
	console.log(this.myKey);
	// -->
	// File
	//	lastModified: 1383404384000
	//	lastModifiedDate: ...
	//	name: "my-image.png"
	//	readerResult: "data:image/png;base64,iVBO..."
	//	- результат считывания файла
	//	size: 9378
	//	type: "image/png"
});
Задать вопрос

Matreshka.binders.dropFiles(readAs) binder

Добавлено в версии 1.8.

Возвращает байндер, позволяющий перетаскивать файлы в заданный блок из файлового менеджера (drag'n'drop).

При связывании свойства и HTML блока при помощи dropFiles, на блок навешиваются необходимые обработчики DOM событий (dragover и drop). При перетаскивании файлов из файлового менеджера в блок, свойство получает массив с этими файлами в качестве значения. Как и в случае с Matreshka.binders.file, привязчику можно передать аргумент readAs, указывающий на то, каким образом следует читать дропнутые файлы с помощью FileReader: data URI, Blob... (результат чтения находится в свойстве readerResult каждого файла). Если readAs не задан, свойство получает список файлов без их предварительного прочтения.

Возвращает binder

Аргументы

Имя Тип Описание
readAs optional string

Значением аргумента readAs могут быть "arrayBufer", "binaryString", "dataURL", "text". Значение зависит от наличия соответствующих методов в интерфейсе FileReader

Ссылки

Примеры

this.bindNode('myKey', '.drop-area', MK.binders.dropFiles('dataURL'));
// ... пользователь дропает файл my-image.png в блок .drop-area
this.on('change:myKey', function() {
	console.log(this.myKey[0]);
	// -->
	// File
	//	lastModified: 1383404384000
	//	lastModifiedDate: ...
	//	name: "my-image.png"
	//	readerResult: "data:image/png;base64,iVBO..."
	//	- результат считывания файла
	//	size: 9378
	//	type: "image/png"
});
Задать вопрос

Matreshka.binders.dragOver() binder

Добавлено в версии 1.9.

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

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

Возвращает binder

Примеры

this.bindNode('myKey', '.my-node', MK.binders.dragOver());
this.on('change:myKey', function() {
	if(this.myKey) {
		console.log('something is dragging over .my-node');
	} else {
		console.log('nothing is dragged over the node');
	}
});

Добавление класса dragovered при перетаскивании файла (или другого draggable объекта) над элементом

this.bindNode('myKey', '.my-node', MK.binders.dragOver());
this.bindNode('myKey', '.my-node', MK.binders.className('dragovered'));
Задать вопрос

Класс Matreshka.Object

Matreshka.Object - класс, который отвечает за данные вида пар ключ-значение. Его задачей является отделение служебных свойств от данных, которые можно передать на сервер или сохранить в локальном хранилище. Класс наследуется от класса Matreshka и включает все его свойства и методы.

Представьте себе, что вы создаёте класс, включающий свойства "a", "b" и "c". Допустим "a" и "b" - свойства которые должны быть отправлены на сервер, а свойство "c" лишь отвечает за некоторое состояние приложения (например, содержит сумму "a" и "b"). Свойство "c" не нужно серверу. Поэтому нам нужно отделить свойства отвечающие за данные от свойств, которые таковыми не являются.

Для того, чтоб объявить такие свойства от остальных, можно воспользоваться методом Matreshka.Object#addDataKeys.

this.addDataKeys('a b');

this.a = 1;
this.b = 2;
this.c = 3;

Если вы заранее не знаете, какие свойства являются данными, можно всегда использовать метод Matreshka.Object#jset, который не только объявляет свойства, отвечающие за данные, но и сразу устанавливает значения.

this.jset({
    a: 1,
    b: 2
});

this.c = 3;

После того, как приложение "узнало" о том, что является данными, экземпляр Matreshka.Object можно сконвертировать в обычный объект методом Matreshka.Object#toJSON и передать на сервер или сохранить в локальной БД (например, в localStorage).

// вернет объект {a: 1, b: 2}
this.toJSON();

При изменении свойств, отвечающих за данные генерируется событие modify

this.on('modify', function() {
    alert('Object is modified');
});

Аргументы

Имя Тип Описание
data optional object Данные, входящие в новый экземпляр
collection optional matreshkaArray Массив, в который был добавлен объект в качестве модели

Примеры

Создание экземпляра

new MK.Object;

Создание экземпляра с двумя заданными свойствами

// то же самое, что и new MK.Object().jset({a: 1, b: 2});
new MK.Object({a: 1, b: 2});

Наследование

var MyClass = Class({
	'extends': MK.Object,
	constructor: function() {
		this.sayHello();
	},
	sayHello: function() {
		alert("Hello World!");
	}
});

Наследование, используя синтаксис ECMAScript 2015

class MyClass extends MK.Object {
	constructor() {
		this.sayHello();
	}
	sayHello() {
		alert("Hello World!");
	}
}

Перебор данных, используя цикл for..of из ECMAScript 2015

var mkObject = new MK.Object({a: 1, b: 2});
for(let item of mkObject) {
	console.log(item); // 1 .. 2
}
Задать вопрос

Matreshka.Object#addDataKeys(keys) matreshkaObject

Добавляет ключи в список ключей, отвечающих за данные

Этот метод применяется тогда, когда нужно объявить ключи, отвечающие за данные, но значения соответствующих свойств еще не известны.

Возвращает matreshkaObject - self

Аргументы

Имя Тип Описание
keys string array

Ключ, или ключи разделенные пробелами, или массив ключей

Примеры

this.addDataKeys('a b');
this.addDataKeys(['a', 'b']);
this.addDataKeys('a', 'b');

Пример с Matreshka.Object#each

this.addDataKeys('a b');

this.each(function(value, key) {
	console.log(key, value);
});
// выводит 'a' undefined and 'b' undefined
Задать вопрос

Matreshka.Object#each(callback, thisArg) matreshkaObject

Перебирает свойства, отвечающие за данные

Метод очень похож на Array.prototype.forEach

Возвращает matreshkaObject - self

Аргументы

Имя Тип Описание
callback function

Функция, которая вызывается на каждой итерации

thisArg optional *

Контекст функции

Примеры

this.each( function(value, key) {
	...
}, this);
this
	.jset({a: 1, b: 2})
	.addDataKeys('c')
	.each(function(value, key) {
		console.log(key, value);
	}, this);
;
// >>> a 1, b 2, c undefined
Задать вопрос

Matreshka.Object#hasOwnProperty(key) matreshkaObject

Проверяет есть ли в экземпляре свойство, отвечающее за данные, с заданным ключом

Возвращает matreshkaObject - self

Аргументы

Имя Тип
key string

Примеры

var mkObject = new MK.Object({
	a: 1,
	b: 2
});

mkObject.hasOwnProperty('a'); // true

mkObject.hasOwnProperty('b'); // true

mkObject.hasOwnProperty('c'); // false
Задать вопрос

Matreshka.Object#jset(key, value, evtOpts) matreshkaObject

Устанавливает свойство и добавляет ключ в список ключей, отвечающих за данные

Этот метод делает две вещи:

1. Устанавливает заданное значение заданному свойству.

2. Добавляет ключ свойства в список данных, что делает свойство доступным для использования в методах Matreshka.Object#each, Matreshka.Object#keys, Matreshka.Object#toObject и Matreshka.Object#toJSON).

В остальном, метод работает так же, как и Matreshka#set.

Возвращает matreshkaObject - self

Генерирует события change change:KEY modify

Аргументы

Имя Тип Описание
key string

Ключ

value *

Значение

evtOpts optional eventOptions

Объект события

Ссылки

Примеры

this.jset('a', 1).jset('b', 2);
this.jset('a', 1).jset('b', 2);

// присваиваем свойству 'c' тройку,
// но не добавляем ключ в список ключей, отвечающих за данные
this.set('c', 3);

this.each(function(value, key) {
	console.log(key, value);
});

// выводит 'a' 1 и 'b' 2

console.log(this.keys()); // выводит ['a', 'b']

console.log(this.toJSON()); // выводит {a: 1, b: 2}

После использования метода Matreshka.Object#jset со свойством можно работать, как с обычным свойством

this.jset('a', 1).jset('b', 2);
this.set('a', 3);
this.b = 4;
Задать вопрос

Matreshka.Object#jset(keyValuePairs, evtOpts) matreshkaObject

Альтернативный синтаксис метода Matreshka.Object#jset, который использует объект ключ-значение для установки нескольких свойств сразу

Возвращает matreshkaObject - self

Аргументы

Имя Тип Описание
keyValuePairs object

Объект ключ-значение

evtOpts eventOptions

Объект события

Примеры

this.jset({
	a: 1,
	b: 2
});

Использование объекта события

this.jset({
	a: 1,
	b: 2
}, {silent: true});
Задать вопрос

Matreshka.Object#keyOf(value) string null

Ищет заданное значение свойства среди свойств, отвечающих за данные, и возвращает ключ, если такое значение найдено (аналог Array.prototype.indexOf)

Возвращает string null

Аргументы

Имя Тип Описание
value *

значение любого типа, которое следует найти среди данных

Примеры

var mkObject = new MK.Object({
	a: 1,
	b: 2
});

mkObject.keyOf(1); // 'a'

mkObject.keyOf(2); // 'b'

mkObject.keyOf(3); // null
Задать вопрос

Matreshka.Object#remove(key, evtOptions) matreshkaObject

Удаляет свойство из экземпляра класса Matreshka.Object и из списка ключей, отвечающих за данные

Возвращает matreshkaObject - self

Генерирует события delete delete:KEY modify

Аргументы

Имя Тип Описание
key string

Ключ (или список ключей, разделенных пробелами)

evtOptions optional eventOptions

Объект события

Ссылки

Примеры

this.remove('myKey');
this.remove('myKey1 myKey2');

Использование объекта события

this.remove('myKey', {silent: true});
Задать вопрос

Matreshka.Object#removeDataKeys(keys) matreshkaObject

Удаляет ключи из списка ключей, отвечающих за данные (но не удаляет свойство)

Возвращает matreshkaObject - self

Аргументы

Имя Тип Описание
keys string array

Ключ или ключи разделенные пробелами или массив ключей

Примеры

this.removeDataKeys('a b');
this.removeDataKeys(['a', 'b']);
this.removeDataKeys('a', 'b');
Задать вопрос

Matreshka.Object#toJSON() object

Конвертирует экземпляр и внутренние свойства Matreshka.Object в обычный объект

Возвращает object

Примеры

var mkObject = new MK.Object({
	a: 1,
	b: 2,
	c: new MK.Object({
		d: 3,
		e: 4
	})
});

// возвращает {a: 1, b: 2, c: {d: 3, e: 4}}
mkObject.toJSON();
Задать вопрос

Matreshka.Object#toObject() object

Конвертирует экземпляр Matreshka.Object в обычный объект, но не конвертирует входящие в него свойства

Возвращает object

Примеры

Basic usage

var mkObject = new MK.Object({
	a: 1,
	b: 2
});

mkObject.toObject(); // возвращает {a: 1, b: 2}
Задать вопрос

Класс Matreshka.Array

Класс Matreshka.Array служит коллекцией во фреймворке Матрешка. Он наследуется от класса Matreshka, получая все без исключения возможности родителя. Кроме этого, Matreshka.Array имеет все методы, которые есть у обычного массива.

Все методы, позаимствованные у встроенного Array работают аналогично их оригиналам

Программист, знакомый с методами нативного Array сразу может понять, каким методом можно добавить элемент (push, unshift, splice), каким удалить (pop, shift, splice), каким отсортировать (sort, reverse) и т. д. Исключением из этого правила является метод forEach, который в оригинальном виде всегда возвращает undefined, а, в случае с Matreshka.Array возвращает "себя" для возможности цепочечного вызова. По причине того, что методы работают точно так же, как и оригинальные, они не приведены в этой документации по отдельности, а выведены в раздел Matreshka.Array#METHOD.

this.push(1, 2, 3);
this.pop();

Все методы, позаимствованные у встроенного Array, которые модифицируют массив могут быть вызваны с передачей объекта события

Для этого используется синтаксис метод_, где нижнее подчеркивание в конце имени метода означает, что последним аргументом является объект события. Такие методы не приведены в этой документации, так как требуется запомнить только их синтаксис. См. Matreshka.Array#METHOD_.

this.push_(1, 2, 3, {
    silent: true
});
this.pop_({
    silent: true
});

Разработчик имеет возможность отлавливать любые модификации данных

При использовании методов, позаимствованных у встроенного Array генерируются события с соответствующим именем. Вызывая метод push, генерируется событие push, вызывая метод pull генерируется событие pull, вызывая метод sort, генерируется событие sort и так далее... Список аргументов можно получить, обратясь к свойству args.

this.on('push', function(evt) {
    console.log(evt.args); // [1,2,3]
});

this.push(1, 2, 3);

При добавлении элементов генерируются события add и addone. Первое генерируется один раз на добавление (например, вы добавили несколько элементов с помощью push, событие вызвалось только один раз), второе генерируется один раз на каждый добавленный элемент. При срабатывании события add, в объект события (свойство added) передается массив добавленных элементов, а при срабатывании addone, в него же передаётся каждый отдельный добавленный элемент.

this.on('add', function(evt) {
    console.log(evt.added); // [1,2,3]
});

this.push(1, 2, 3);
// обработчик запустится трижды,
// так как в массив добавили три новых элемента
this.on('addone', function(evt) {
    console.log(evt.added); // 1 ... 2 ... 3
});

this.push(1, 2, 3);

При удалении элементов действует та же логика: remove срабатывает один раз, даже если удалено несколько элементов, а событие removeone срабатывает для каждого удаленного элемента индивидуально. Удаленные элементы содержатся в свойстве removed объекта события.

this.push(1, 2, 3, 4, 5);

this.on('remove', function(evt) {
    console.log(evt.removed); // [2,3,4]
});

this.splice(1, 3);
this.push(1, 2, 3, 4, 5);

// обработчик запустится трижды,
// так как в массив добавили три новых элемента
this.on('removeone', function( evt ) {
    console.log(evt.removed); // 2 ... 3 ... 4
});

this.splice(1, 3);

При каждой модификации массива генерируется событие modify, позволяя отловить все без исключения изменения в массиве (добавление, удаление, пересортировку).

this.on('modify', function(evt) {
    ...
});

length - это обычное свойство которое можно связывать с HTML элементом или отлавливать изменения с помощью события change:length.

Например, при добавлении трех элементов с помощью метода push с тремя аргументами, генерируются следующие события: push, add, addone (трижды), modify, change:length.

Model

Свойство Matreshka.Array#Model определяет класс элементов, которые будет содержать коллекция. Его поведение очень напоминает поведение свойства model из Backbone.Collection. Рекомендуется наследовать Model от класса Matreshka.Object или Matreshka.Array (на случай, если требуется получить коллекцию коллекций), чтоб получить возможность конвертации массива в обычный массив методом Matreshka.Array#toJSON.

// определяем Модель
var MyModel = Class({
    // она наследуется от MK.Object
    'extends': MK.Object,
    constructor: function(data) {
        // устанавливаем переданные свойства методом jset
        this.jset(data);
    }
});

// определяем класс для коллекции
var MyArray = Class({
    'extends': MK.Array,
    Model: MyModel
});

// создаем экземпляр класса
var myArray = new MyArray;

// добавляем два элемента
myArray.push({
    a: 1,
    b: 2
}, {
    a: 3,
    b: 4
})

// вернет [{a: 1, b: 2}, {a: 3, b: 4}]
myArray.toJSON();

Автоматический рендеринг

Matreshka.Array умеет автоматически отрисовывать элементы на странице при любых модификациях массива. Для этого применяется свойство Matreshka.Array#itemRenderer. Программисту больше не нужно заботиться о перестройке HTML дерева, Matreshka.Array делает это за него. Ниже пример использования автоматического рендеринга списка.

<ul class="my-list"></ul>
var MyModel = MK.Class({
    'extends': MK.Object,
    constructor: function(data) {
        this.jset(data);

        // ждем события 'render'
        this.on('render', function() {
            // и привязываем свойство 'value'
            // к новосозданному HTML элементу <li>
            this.bindNode('value', ':sandbox', MK.binders.html());
        });
    }
});

var MyArray = MK.Class({
    'extends': MK.Array,
    Model: MyModel,
    // определяем рендерер для каждого элемента коллекции
    itemRenderer: '<li>',
    constructor: function() {
        // создаём песочницу
        this.bindNode('sandbox', '.my-list');
    }
});

var myArray = new MyArray();
myArray.push({
    value: 'Hello'
}, {
    value: 'World'
});

За подробностями обратитесь к документации Matreshka.Array#itemRenderer.

Ссылки

Примеры

Создание экземпляра

new MK.Array();

Создание экземпляра с указанием длины

new MK.Array(42);

Передача элементов при создании

new MK.Array('Hi', {a: 'b'});

Наследование

var MyClass = Class({
	'extends': MK.Array,
	constructor: function() {
		this.sayHello();
	},
	sayHello: function() {
		alert("Hello World!");
	}
});

Наследование, используя синтаксис ECMAScript 2015

class MyClass extends MK.Array {
	constructor() {
		this.sayHello();
	}
	sayHello() {
		alert("Hello World!");
	}
}

Перебор данных, используя цикл for..of из ECMAScript 2015

var mkArray = new MK.Array(1, 2, 3);
for(let item of mkArray) {
	console.log(item); // 1 .. 2 .. 3
}

Прослушивание событий

this.on('modify', function(evt) {
	alert('1) Вызван метод ' + evt.method);
});

this.on('shift', function(evt) {
	alert('2) Вызван метод ' + evt.method);
});

this.push(1); // 1) Вызван метод push

this.shift(); // 1) Вызван метод shift, 2) Вызван метод shift

Передача объекта события во встроенный метод Array

this.on('modify', function(evt) {
	alert(evt.customData);
});

this.push_(1, {
	silent: true // событие не генерируется
});

this.shift_({
	customData: 42 // 42
});
Задать вопрос

Matreshka.Array#METHOD()

Любой метод из Array.prototype

Matreshka.Array включает в себя все методы, входящие в нативный JavaScript массив:

При этом, они работают точно так же, как и методы Array.prototype. Есть лишь несколько оговорок:

  • Метод forEach возвращает себя вместо undefined
  • Методы, которые в оригинальном виде возвращают новый массив (splice, slice, filter, map...), в Матрешке возвращают новый экземпляр Matreshka.Array.

Кроме всего, методы генерируют события связанные с любой модификацией массива. Подробнее см. Matreshka.Array.

Ссылки

Примеры

this.push(1, 2, 3);
var mapped = this
	.forEach(function(value, index) {
		//...
	})
	.map( function(value, index) {
		//...
	})
;
alert(mapped.isMKArray);
this.reverse();
Задать вопрос

Matreshka.Array#METHOD_()

Любой метод из Array.prototype с возможностью передать объект события

Ознакомившись с Matreshka.Array#METHOD становится понятно, что методы не поддерживают передачу объекта события, так как в точности повторяют синтаксис и количество аргументов встроенного Array. Синтаксис МЕТОД_ позволяет передать в обработчик события какие-нибудь данные либо установить служебные флаги, отвечающие за поведение массива после вызова метода.

Список доступных флагов:

  • silent: true - отключает генерацию событий
  • dontRender: true - отключает рендеринг
  • skipMediator: true - отключает медиаторы

Ссылки

Примеры

this.push_(1, 2, 3, {
    silent: true
});

this.pop_({
    silent: true
});
this.on('modify', function(evt) {
	alert(evt.flag); // 42
});

this.push_(1, 2, 3, {
	flag: 42
});
Задать вопрос

<virtual>Matreshka.Array#Model(data, mkArray, index)

Добавлено в версии 0.2.

Свойство определяет класс элементов, которые будет содержать коллекция

При каждом добавлении элементов в массив, встроенный обработчик проверяет, является ли добавленный элемент экземпляром Model и конвертирует его в таковой, если проверка не пройдена. Это поведение очень напоминает поведение свойства model из Backbone.Collection. Рекомендуется наследовать Model от класса Matreshka.Object или Matreshka.Array (на случай, если требуется получить коллекцию коллекций), чтоб получить возможность конвертации массива в обычный массив методом Matreshka.Array#toJSON.

Для более гибкого контроля класса элементов (например, если для одних элементов нужно использовать одну Модель, а для других - другую), используйте Matreshka.Array#mediateItem.

Аргументы

Имя Тип Описание
data object

Данные, переданные в конструктор

mkArray matreshkaArray

Массив, в который добавили элемент

index number

Текущий индекс объекта в родительском массиве

Ссылки

Примеры

// определяем Модель
var MyModel = Class({
	// она наследуется от MK.Object
	'extends': MK.Object,
	constructor: function(data, parentArray, index) {
		// устанавливаем переданные свойства методом jset
		this.jset(data);
		this.doSomething();
	},
	doSomething: function() { ... }
});

// определяем класс для коллекции
var MyArray = Class({
    'extends': MK.Array,
    Model: MyModel
});

// создаем экземпляр класса
var myArray = new MyArray();

// добавляем два элемента
myArray.push({
    a: 1,
    b: 2
}, {
    a: 3,
    b: 4
})

// вернет [{ a: 1, b: 2 }, { a: 3, b: 4 }]
myArray.toJSON();

Model и ECMAScript 2015

class MyArray extends MK.Array {
	get Model() {
		return MyModel;
	}
	constructor() { ... }
}

Model и ECMAScript 7

class MyArray extends MK.Array {
	Model = MyModel;
	constructor() { ... }
}
Задать вопрос

Matreshka.Array#each(callback, thisArg) matreshkaArray

Работает точно так же, как и метод forEach, который перебирает элементы массива

Возвращает matreshkaArray - self

Аргументы

Имя Тип Описание
callback function

Функция, запускаемая на каждой итерации

thisArg optional *

Объект, который используется в качестве this при вызове callback

Примеры

this.each(function(item, index) {
	console.log(index, item);
});
Задать вопрос

Matreshka.Array#hasOwnProperty() boolean

Существует ли свойство в экземпляре (индекс или свойство length)

Возвращает boolean

Примеры

var mkArray = new MK.Array(42); // создает массив длиной 42

mkArray.hasOwnProperty(5); // true

mkArray.hasOwnProperty(100500); // false

mkArray.hasOwnProperty('length'); // true

mkArray.hasOwnProperty('blah'); // false
Задать вопрос

Matreshka.Array#mediateItem()

Добавлено в версии 0.1.

Трансформирует значение элемента при вставке

Этот метод служит для того, чтоб установить типизацию для вставляемых элементов. Обратите внимание, метод переопределяет свойство Matreshka.Array#Model.

Ссылки

Примеры

// все элементы массива - числа
this.mediateItem(Number);
this.push(1, 2, 3, 4, 5);

// все элементы массива - строки
this.mediateItem(function(value) {
	return String(value);
});

this.push(6, 7);

this.unshift(true, {});

// ["true", "[object Object]", "1", "2", "3", "4", "5", "6", "7"]
console.log(mkArray.toJSON());

Условная Модель

this.mediateItem(function(item) {
	if(item.something) {
		return new FirstModel(item);
	} else {
		return new SecondModel(item);
	}
});
Задать вопрос

<virtual>Matreshka.Array#onItemRender(item, renderEvt)

Добавлено в версии 1.1.

Функция, которая запускается перед событием render.

Для улучшения читаемости кода и небольшого выигрыша в скорости, в версии 1.1 появился виртуальный метод onItemRender, который можно использовать в качестве замены события render.

При этом, у отрисованного элемента вызывается метод onRender с единственным аргументом - объектом события.

Аргументы

Имя Тип Описание
item matreshka

отрисованный элемент коллекции

renderEvt matreshka

объект события render

Примеры

var MyModel = Class({
	'extends': MK.Object,
	constructor: function(data) {
		this.jset(data);
	},
	onRender: function(renderEvt) {
		this.bindNode('isChecked', ':sandbox .my-checkbox');
		this.bindNode('text', ':sandbox .text', MK.binders.html());
	}
});

var MyArray = Class({
	'extends': MK.Array,
	Model: MyModel,
	itemRenderer: '<li>',
	constructor: function() {
		this.bindNode('sandbox', '.my-form');
	},
	onItemRender: function(item, renderEvt) {
		// тоже что-то сделать
	}
});

var app = new MyArray();
Задать вопрос

Matreshka.Array#orderBy(keys, orders=asc) matreshkaArray

Добавлено в версии 1.6.

Сортирует массив по значениям свойств объектов, которые в него входят

Метод использует Matreshka.sortBy для упорядочивания, и сортирует this вместо создания нового объекта.

Возвращает matreshkaArray - self

Аргументы

Имя По умолчанию Тип Описание
keys string Array.

Ключ свойства или массив нескольких ключей, по которым коллекция будет отсортирована

orders optional asc string Array.

Порядок или массив порядков, соответствующих массиву ключей

Примеры

this.recreate([
  { 'user': 'fred',   'age': 48 },
  { 'user': 'barney', 'age': 34 },
  { 'user': 'fred',   'age': 42 },
  { 'user': 'barney', 'age': 36 }
]);

// сортирует по значениям свойств `user` по возрастанию и значениям свойств `age` по убыванию
this.orderBy(['user', 'age'], ['asc', 'desc']);
// → [{"user":"barney","age":36},{"user":"barney","age":34},{"user":"fred","age":48},{"user":"fred","age":42}]
Задать вопрос

Matreshka.Array#pull(index, evtOptions) * null

Добавлено в версии 0.1.

Удаляет элемент с заданным индексом из массива и возвращает этот элемент. Начиная с версии 0.3, метод поддерживает удаляемый элемент в качестве аргумента.

Возвращает * null - Удаленный элемент или ``null``

Генерирует события pull remove removeone modify

Аргументы

Имя Тип Описание
index string number *

Индекс элемента, который нужно удалить (число или строка) либо сам удаляемый элемент (не являющийся ни числом ни строкой)

evtOptions optional eventOptions

Объект события на случай, если нужно передать в обработчик события какие-нибудь данные или установить флаг silent, предотвращающий срабатывание события

Примеры

Передача индекса массива

var removed;

this.recreate(['a', 'b', 'c']);

removed = this.pull(1);

alert(removed); // 'b'

alert(this.toString()); // 'a,c'

Передача удаляемого элемента

var object1 = {},
	object2 = {},
	object3 = {},
	removed;

this.push(object1, object2, object3);

removed = this.pull(object2);

alert(removed === object2); // true

alert(this.length); // 2
Задать вопрос

Matreshka.Array#recreate(array, eventOptions) matreshkaArray

Пересоздает экземпляр Matreshka.Array

Метод позволяет конвертировать любой массив (или объект, подобный массиву) в экземпляр Matreshka.Array. Если ничего не передано в качестве первого аргумента, экземпляр очищается.

Возвращает matreshkaArray - self

Генерирует события recreate modify add addone remove removeone

Аргументы

Имя Тип Описание
array optional array

Массив

eventOptions optional eventOptions

Объект события

Ссылки

Примеры

// очищаем массив и добавляем 5 новых элементов
this.recreate([1, 2, 3, 4, 5]);

// очищаем массив
this.recreate();
Задать вопрос

Matreshka.Array#rerender(options) matreshkaArray

Добавлено в версии 0.3.

Перерисовывает DOM узлы элементов, входящих в массив

Этот метод заново рендерит элементы массива в контейнере массива. Если узел, который ассоциирован с элеменом масива уже создан, метод, вместо перерисовки с нуля, "перевставляет" его в контейнер или песочницу массива.

Метод может быть полезным на случай, когда элементы добавлены в массив перед объявлением песочницы или контейнера.

Начиная с версии 1.1, для того, чтоб заставить массив перерисоваться, независимо от наличия отрендеренных узлов (например, вы используете handlebars в itemRenderer), передайте в метод объект со свойством forceRerender равным true.

Возвращает matreshkaArray - self

Аргументы

Имя Тип Описание
options optional object

Объект с флагами (на сегодняшний день, единственный флаг - forceRerender)

Примеры

this.rerender({
	forceRerender: true
});
Задать вопрос

Matreshka.Array#restore(selector, eventOptions) matreshkaArray

Добавлено в версии 1.3.

Воссоздаёт Matreshka.Array из HTML узлов на странице.

В случае, если коллекция заранее отрисована на странице (например, с помощью сервера), метод может воссоздать коллекцию из отрендеренных HTML узлов.

<!-- One, Two, Three заранее отрисованы -->
<ul class="collection-node">
    <li>One</li>
    <li>Two</li>
    <li>Three</li>
    <script type="text/html" class="renderer">
        <li></li>
    </script>
</ul>
var MyModel = Class({
    'extends': MK.Object,
    constructor: function(data) {
        this.addDataKeys('value');
        this.set(data);
    },
    onRender: function() {
        this.bindNode('value', ':sandbox', MK.binders.html())
    }
});

var MyCollection = Class({
    'extends': MK.Array,
    itemRenderer: ':sandbox .renderer',
    constructor: function() {
        this
            .bindNode('sandbox', '.collection-node')
            .restore(':sandbox li');
    }
});

var myCollection = new MyCollection();
myCollection.push({
    value: 'Four'
});

console.log(myCollection.toJSON());
// [{value: 'One'}, {value: 'Two'}, {value: 'Three'}, {value: 'Four'}]

Если аргумент selector не задан, то коллекция будет воссоздана из элементов, входящих в контейнер ("container" или "sandbox").

При воссоздании, на каждом элементе массива генерируется событие render и вызываются методы onRender и onItemRender (см документацию), как и при обычном рендеринге.

Возвращает matreshkaArray - self

Генерирует события recreate modify add addone

Аргументы

Имя Тип Описание
selector optional selector

Селектор

eventOptions optional eventOptions

Объект события

Примеры

this.restore();
Задать вопрос

Matreshka.Array#toJSON() object

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

Возвращает object

Примеры

var data = this.toJSON();
Задать вопрос

<virtual>Matreshka.Array#itemRenderer: string function

Добавлено в версии 0.1.

HTML строка, селектор или функция, отвечающая за отрисовку элементов массива на странице

Свойство itemRenderer - это переопределяемое (виртуальное) свойство, которое позволяет рендерить элементы массива без участия программиста. При вставке нового элемента в массив, автоматически создается HTML узел. Этот узел становится песочницей (см. Matreshka#bindNode) для вставленного элемента и встраивается в HTML контейнер, определенный в массиве.

Куда вставляется созданный элемент?

Для того, чтобы определить HTML контейнер, в который будут вставляться отрисованные HTML узлы, нужно определить контейнер. Для этого следует объявить HTML песочницу для массива либо связать специальный ключ container с HTML контейнером. Подробнее о привязках и песочнице см. Matreshka#bindNode. Пример использования песочницы в качестве контейнера:

<ul class="my-list"></ul>
var MyArray = Class({
    'extends': MK.Array,
    itemRenderer: '<li>',
    Model: MyModel,
    constructor: function() {
        // определяем песочницу
        this.bindNode('sandbox', '.my-list');
    }
});

Теперь все новосозданные узлы <li> попадут в узел .my-list

Если вы не хотите вставлять HTML узлы непосредственно в песочницу, можете связать ключ container с необходимым элементом. Такая логика нужна в том случае, если песочница не ограничена одними лишь элементами коллекции и включает в себя другие HTML узлы.

<div class="my-widget">
    <h1>This is my awesome list</h1>
    <ul class="my-list"></ul>
</div>
var MyArray = Class({
    'extends': MK.Array,
    itemRenderer: '<li>',
    Model: MyModel,
    constructor: function() {
        // определяем песочницу
        this.bindNode('sandbox', '.my-widget');
        // определяем контейнер для HTML элементов
        this.bindNode('container', '.my-list');
    }
});

В примере выше HTML узлы будут вставляться в .my-list вместо .my-widget.

Свойство itemRenderer поддерживает несколько вариантов определения, но все они должны содержать или возвращать единственный HTML узел.

HTML строка в качестве значения свойства

Как видно из примера выше, itemRenderer может быть определен, как HTML строка.

var MyArray = Class({
    'extends': MK.Array,
    Model: MyModel,
    itemRenderer: '<div class="my-div">Be cool</div>',
    constructor: function() { ... }
});

Селектор в качестве значения свойства

На случай, если вы выносите шаблоны для элементов на HTML страницу, itemRenderer поддерживает селектор в качестве значения. В этом случае, Matreshka.Array будет искать HTML элемент в DOM дереве и извлечет innerHTML найденого элемента. В случае, если элемент не найден, бросается исключение. HTML текст от селектора отличается наличием символа < в строке.

<script type="text/html" id="be-cool-template">
    <div class="my-div">Be cool</div>
</script>
var MyArray = Class({
    'extends': MK.Array,
    Model: MyModel
    itemRenderer: '#be-cool-template',
    constructor: function() { ... }
});

Функция в качестве значения свойства

Использование функции в качестве значения свойства itemRenderer даёт дополнительную гибкость кода, если есть нужда динамически генерировать элемент для рендеринга. Функция может возвращать:

HTML строку

var MyArray = Class({
    'extends': MK.Array,
    Model: MyModel,
    itemRenderer: function() {
        return '<div class="my-div">Be cool</div>';
    },
    constructor: function() { ... }
});

Селектор

var MyArray = Class({
    'extends': MK.Array,
    Model: MyModel,
    itemRenderer: function() {
        return '#be-cool-template';
    },
    constructor: function() { ... }
});

DOM узел

var MyArray = Class({
    'extends': MK.Array,
    itemRenderer: function() {
        return document.createElement('div');
    }
});

Handlebars.js в качестве шаблонизатора

var MyArray = Class({
    'extends': MK.Array,
    // model - модель (экземпляр Matreshka.Object), который будет рендериться
    itemRenderer: function(model) {
        // получение и компилирование шаблона
        var template = Handlebars
            .compile($('#handlebarsTemplateSelector').html());
        // подстановка значений модели в шаблон и его возвращение
        return template(model);
    }
});

Переопределение родительского рендерера свойством render

Иногда удобно объявлять рендерер внутри класса Matreshka.Array#Model, как это делает Backbone. Свойство renderer переопределяет значение itemRenderer, если оно задано для дочернего элемента коллекции.

var MyModel = Class({
    'extends': MK.Object,
    renderer: '<div class="my-div">Be cool</div>',
    constructor: function(data) { ... }
});

var MyArray = Class({
    'extends': MK.Array,
    Model: MyModel,
    itemRenderer: '<frameset>Not cool</frameset>',
    constructor: function() { ... }
});

В этом случае, можно вовсе не указывать itemRenderer, так как render дочернего элемента перенимает все его возможности. Синтаксис остаётся такими же: можно использовать HTML, селектор или функцию.

Событие render

После того, как элемент вставлен в массив, а его HTML узел уже создан, но еще не вставлен в контейнер, генерируется событие render на вставленном элементе. После его генерации можно объявить привязки свойств к HTML узлам, содержащимся внутри вставленного.

<form class="my-form"></form>
var MyModel = Class({
    'extends': MK.Object,
    constructor: function(data) {
        this.jset(data);

        // ждем генерации события
        this.on('render', function() {
            this.bindNode('isChecked', ':sandbox .my-checkbox');
            this.bindNode('text', ':sandbox .text',
                MK.binders.html());
        });
    }
});

var MyArray = Class({
    'extends': MK.Array,
    Model: MyModel,
    itemRenderer: '<label>\
        <input type="checkbox" class="my-checkbox">\
        <span class="text"></span>\
    </label>',
    constructor: function() {
        this.bindNode('sandbox', '.my-form');
        this.push({
            isChecked: true,
            text: 'Be cool'
        }, {
            isChecked: false,
            text: 'Produce shitcode'
        });
    }
});

var app = new MyArray();

Код выше создаст такое HTML дерево:

<form class="my-form">
    <label>
        <input type="checkbox" class="my-checkbox">
        <span class="text">Be cool</span>
    </label>
    <label>
        <input type="checkbox" class="my-checkbox">
        <span class="text">Produce shitcode</span>
    </label>
</form>

И свяжет чекбоксы с соответствующими свойствaми isChecked и text. Живой пример

Не забывайте, что в Матрешке реализована возможность отлова всплывающих событий. Т. е. сам массив может отловить событие рендеринга элемента, используя имя события *@render (см. документацию к eventNames).

this.on('*@render', function(evt) {
    alert('Child element is rendered');
});

Отрисованный HTML узел становится песочницей для вставленного элемента, позволяя использовать селектор :sandbox и другие возможности после рендеринга. Если элемент входит сразу в несколько коллекций, установите ему свойство bindRenderedAsSandbox: false, чтобы отменить это поведение.

var MyModel = Class({
    'extends': MK.Object,
    bindRenderedAsSandbox: false,
    // ...
});

Событие afterrender

После срабатывания события render запускается нулевой таймер (setTimeout(f, 0)), вызывающий событие afterrender. Таким образом можно получить актуальные данные о позиции элемента на странице и другую информацию, которая доступна только тогда, когда DOM узел вставлен на страницу.

var MyModel = Class({
    'extends': MK.Object,
    constructor: function(data) {
        //...
        this.on('afterrender', function() {
            console.log('Computed style', getComputedStyle(this.sandbox));
        });
        //...
    }
});
// ...

onItemRender и onRender

Для улучшения читаемости кода и небольшого выигрыша в скорости, в версии 1.1 появился виртуальный метод Matreshka.Array#onItemRender, который можно использовать вместо события render. В качестве альтернативы, у "моделей" вызывается метод onRender, так же позволяющий сделать код более "плоским" и избавиться от вложенных функций.

var MyModel = Class({
    'extends': MK.Object,
    constructor: function(data) {
        this.jset(data);
    },
    onRender: function(evt) {
        this.bindNode('isChecked', ':sandbox .my-checkbox');
        this.bindNode('text', ':sandbox .text',
                MK.binders.html());
    }
});

var MyArray = Class({
    'extends': MK.Array,
    Model: MyModel,
    itemRenderer: '...`,
    constructor: function() {
        //...
    },
    onItemRender: function(item, evt) {
        //...
    }
});

var app = new MyArray();

Шаблонизатор

Взглянув на примеры использования Matreshka.Array и Matreshka.Array#itemRenderer можно обратить внимание на то, что вся логика, отвечающая за двустороннюю и одностороннюю привязку данных заключена в JavaScript коде. Это одно из главных преимуществ Матрешки. Но когда разрабатываешь очень простую коллекцию, не включающую в себя сложную логику, массу привязок и пр. хотелось бы иметь более краткий вариант объявления привязок. Для этого, в itemRenderer может быть передан шаблон, включающий привязки. Начиная с версии 1.1, шаблонизатор включен по умолчанию.

var MyArray = Class({
    'extends': MK.Array,
    Model: MK.Object,
    itemRenderer: '<label>\
        <input type="checkbox" checked="{{isChecked}}">{{text}}\
    </label>',
    constructor: function() {
        this.bindNode('sandbox', '.my-form');
        this.push({
            isChecked: true,
            text: 'Be cool'
        }, {
            isChecked: false,
            text: 'Produce shitcode'
        });
    }
});

var app = new MyArray();

Пример выше полностью повторяет предыдущий, но не требует создания отдельного класса для Модели, так как нам не требуется отлавливать событие render и объявлять привязки вручную. Живой пример

Обратите внимание: Скорость кода с шаблонизатором несколько ниже, чем без него. Это происходит из-за того, что анализ строки, перебор ключей в цикле (при использовании нескольких ключей в одном атрибуте), замена подстрок регулярным выражением и пр. требуют больше ресурсов. Шаблонизатор можно отключить двумя способами: установить свойство Matreshka.Array#useBindingsParser, как false, или не использовать синтаксис {{KEY}} вовсе (шаблонизатор срабатывает только тогда, когда у узла или HTML строки есть двойные фигурные скобки).

Шаблонизация реализована с помощью метода Matreshka#parseBindings.

Отмена рендеринга

Как видно выше, если у дочернего элемента задано свойство render, Matreshka.Array попробует его отрисовать. Для того, чтоб полностью отменить рендеринг для массива, присвойте свойству renderIfPossible: false.

var MyArray = Class({
    'extends': MK.Array,
    renderIfPossible: false,
    // ...
});

Перемещение объекта из одного массива в другой

По умолчанию, при вставке объекта в массив Матрешка попытается его отрисовать, используя itemRenderer (если он еще не был отрисован). Это даёт огромное преимущество в случаях, когда у вас на странице есть два или более списка, включающих в себя один и тот же объект. При изменении этого объекта, все списки моментально реагируют на изменение, обновляя DOM.

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

this.push_( item, {
    moveSandbox: true
});

Переопределение itemRenderer

Начиная с версии 1.1, при переустановке свойства itemRenderer, коллекция автоматически перерисовывается.

this.itemRenderer = '<div>';

Эта возможность полезна в том случае, когда разработчик желает загрузить шаблон с сервера.

// пример jQuery.get
jQuery.get('templates/template.html', function(data) {
    this.itemRenderer = data;
}.bind(this));

// пример Fetch API
fetch('templates/template.html')
    .then(function(resp) {
        return resp.text();
    })
    .then(function(data) {
        this.itemRenderer = data;
    }.bind(this));

// пример Fetch API + ECMAScript 2015
fetch('templates/template.html')
    .then(resp => resp.text())
    .then(data => this.itemRenderer = data);

Для отрисовки только тех объектов, которые еще не были отрисованы, воспользуйтесь методом Matreshka#set с флагом forceRerender: false

this.set('itemRenderer', renderer, {forceRerender: false});

Такая необходимость может возникнуть тогда, когда вы используете серверный пререндеринг (см. Matreshka.Array#restore), а шаблон подгружается динамически.

var MyArray = Class({
    'extends': MK.Array,
    constructor:  function() {
        this
            .bindNode('sandbox', '.some-node')
            .restore();

        jQuery.get('templates/template.html', function(data) {
            this.set('itemRenderer', data, {forceRerender: false})
        }.bind(this));
    }
});

Рендеринг коллекции, состоящей из обычных объектов

В версии 1.1 самым большим нововведением фреймворка стала поддержка нативных объектов в методах Matreshka.bindNode, Matreshka.linkProps, Matreshka.mediate и пр. Эта замечательная возможность не обошла стороной и рендеринг. Теперь не обязательно заботиться о том, чтобы элементы, входящие в коллекцию наследовались от класса Matreshka.

var MyArray = Class({
    'extends': MK.Array,
    // Model не определена
    itemRenderer: ...
    onItemRender: function(item) {
        MK.bindNode(item, 'x', ':sandbox .some-node');
    }
})

Для того, чтоб удостовериться, что элементы, попадающие в массив - объекты (а не null, number и пр), можно присвоить свойству Matreshka.Array#Model значение Object, который является встроенным в JavaScript конструктором объектов.

var MyArray = Class({
    'extends': MK.Array,
    Model: Object,
    itemRenderer: ...
    constructor: function() {...}
})

Еще небольшой пример: рендеринг простого списка:

var MyArray = Class({
    'extends': MK.Array,
    itemRenderer: '<li></li>',
    constructor: function() {
        this.bindNode('sandbox', '.my-list');
    }
});

var arr = new MyArray();
arr.push({value: 'Item 1'}, {value: 'Item 2'});

Ссылки

Примеры

ECMAScript 2015

class MyArray extends MK.Array {
	get itemRenderer() {
		return '<div>';
	},
	constructor() { ... }
}

ECMAScript 7

class MyArray extends MK.Array {
	itemRenderer = '<div>';
	constructor() { ... }
}
Задать вопрос

<virtual>Matreshka.Array#trackBy: string

Добавлено в версии 1.2.

Свойство trackBy указывает на ключ идентификатора объектов, входящих в массив

В случае, если клиент и сервер активно обмениваются данными (например, списком пользователей), а объекты, входящие в массив имеют уникальный ID (например, идентификатор пользователя), то перерисовка всей коллекции с нуля не имеет смысла. После того, как сервер вернул новую коллекцию, намного рациональнее проверить, есть ли в коллекции объект с таким же ID и, если объект найден, обновить его. Таким образом, не создаётся новый объект (экземпляр Matreshka.Array#Model) и не рисуется новый DOM узел.

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

trackBy работает только при использовании метода Matreshka.Array#recreate, так как это единственный метод "пересоздающий" коллекцию заново.

В примере ниже используется _id в качестве значения (значение может быть любым).

var MyArray = Class({
    'extends': MK.Array,
    trackBy: '_id'
    constructor: function() {
        //,,,
    }
});

var arr = new MyArray();

// добавит три объекта в массив
arr.recreate([
    {_id: 0, name: 'Foo'},
    {_id: 1, name: 'Bar'},
    {_id: 2, name: 'Baz'}
]);

// удалит объект с идентификатором 0
// добавит объект с идентификатором 3
// обновит объект с идентификатором 1, обновив name: Bar -> BarNew
// обновит объект с идентификатором 2, обновив name: Baz -> BazNew
// пересортирует коллекцию в соответствие с переданным данным
arr.recreate([
    {_id: 1, name: 'BarNew'},
    {_id: 3, name: 'Qux'},
    {_id: 2, name: 'BazNew'}
]);

Свойство может содержать специальное значение "$index", которое позволяет обновлять объект по индексу в коллекции.

var MyArray = Class({
    'extends': MK.Array,
    trackBy: '$index'
    constructor: function() {
        //,,,
    }
});

var arr = new MyArray();

// добавит три объекта в массив
arr.recreate([
    {name: 'Foo'},
    {name: 'Bar'},
    {name: 'Baz'}
]);

// обновит все три объекта новыми данными
// и добавит новый объект с именем Qux
arr.recreate([
    {name: 'NewFoo'},
    {name: 'NewBar'},
    {name: 'NewBaz'},
    {name: 'Qux'}
]);

Ссылки

Задать вопрос

Matreshka.Array.from(arrayLike, mapFn, thisArg) matreshkaArray

Добавлено в версии 1.1.

Метод создаёт новый экземпляр Matreshka.Array из массивоподобного объекта.

Возвращает matreshkaArray

Аргументы

Имя Тип Описание
arrayLike object

Массивоподобный объект.

mapFn optional function

Отображающая функция, вызываемая для каждого элемента массива.

thisArg optional *

Объект, который используется в качестве this при вызове mapFn

Ссылки

Примеры

var mkArray = MK.Array.from([1, 2, 3, 4]);
var mkArray = MK.Array.from([1, 2, 3, 4], function(item) {
	return item*2;
}, this);
Задать вопрос

Matreshka.Array.of() matreshkaArray

Добавлено в версии 1.1.

Метод Array.of() создаёт новый экземпляр Matreshka.Array из произвольного числа агрументов, вне зависимости от числа или типа аргумента.

Возвращает matreshkaArray

Ссылки

Примеры

var mkArray = MK.Array.of(1, 2, 3, 4);
Задать вопрос

Class(prototype, statics) class

Реализация классов, основанная на прототипном наследовании

Функция Class позволяет использовать классическое ООП, основанное на классаx.

Возвращает class - class (точнее, конструктор класса)

Аргументы

Имя Тип Описание
prototype object Методы и свойства
statics optional object Статичные методы и свойства

Примеры

var A = Class({
	method1: function() { ... }
});

var B = Class({
	// B наследуется от A
	'extends': A,
	method2: function() { ... }
});

var C = Class({
	// С наследуется от B
	'extends': B,
	method2: function() {
		// вызов родительского метода
		B.prototype.method2.apply(this, arguments);
	},
	method3: function(a, b) { ... }
});

var D = Class({
	// D наследуется от C
	'extends': C,
	method3: function(a, b) {
		// вызов родительского метода
		C.prototype.method2.call(this, arguments);
	}
});

Передача объекта со статичными методами и свойствами

var MyClass = Class({
	method: function() { ... }
}, {
	staticProp: 'foo',
	staticMethod: function() {
		return 'bar';
	}
});

alert(MyClass.staticProp); // foo
alert(MyClass.staticMethod()); // bar

Использование AMD (именованные модули)

require.config({
	paths: {
		'xclass': 'path/to/matreshka.min',
		'matreshka': 'path/to/matreshka.min',
		'bquery': 'path/to/matreshka.min'
	}
});
require(['xclass', 'matreshka', 'bquery'], function(Class, MK, $) {
	var MyClass = Class({
		'extends': MK,
		constructor: function() {
			// ...
		}
	});
});

Использование AMD (безымянный модуль)

// Матрешка содержит функции Class и $b, как статичные свойства
require(['path/to/matreshka.min'], function(MK) {
	var MyClass = MK.Class({
		'extends': MK,
		constructor: function() {
			// ...
		}
	});
});

Матрешка поддерживает любой вид прототипного наследования, в том числе и классы из ECMAScript 2015

class A extends B {
	constructor() {
		super();
		this.sayHello();
	}

	sayHello() {
		alert("Hello World!");
	}
}
Задать вопрос

$b()

Добавлено в версии 0.1.

Микро-библиотека bQuery

bQuery (старое название - "балалайка") - это компактная jQuery-подобная библиотека для работы с DOM. Она наследуется от Array.prototype и включает в себя все методы, которые есть у массива:

Кроме этого, она включает несколько собственных методов: on, off, is, extend, возможности парсинга HTML, отлов события DOM-ready и пр. bQuery используется внутренними механизмами Матрешки тогда, когда на странице не подключена jQuery или другая jQuery-подобная библиотека.

Примеры

Создание обработчика события

$('.my-selector').on('click.namespace', function() {
    alert('hi');
});

Удаление обработчика

$('.my-selector').off('click.namespace');

Метод is

$('.my-selector').on('click', function(evt) {
    if($(evt.target).is('.another-selector')) {
        alert('hi');
    }
});

Метод extend (расширение одного объекта другим)

var myObject = {a:1};
$.extend(myObject,{
    b: 2
});

DOM-ready

$(function() {
    // Do something with DOM
});

Парсинг

var elements = $('<div><span class="yeah"></span></div>');

Поиск одного элемента в другом

var myElement = $('.my-selector', node);

Установка стиля

$('.my-selector').forEach(function(el) {
    $.extend( el.style, {
        width: '30px',
        backgroundColor: 'red'
    });
});

Делегирование события

$('.my-selector').on('click', function(evt) {
    var node = evt.target;
    while(node !== this) {
        if($(node).is('.delegated-selector')) {
            // Handle it!
            break;
        }
        node = node.parentNode;
    }
});

Простой плагин

$.fn.addClass = function( className ) {
    this.forEach( function(item) {
        var classList = item.classList;
        classList.add.apply(classList, className.split(/\s/+));
    });
    return this;
};

Функция create - дополнительная утилита для создания элементов, входящая в комплект Матрешки. Первый аргумент - имя тега, второй - свойства, расширяющие DOM объект

var div = $.create('div', {
	className: 'my-div',
	innerHTML: 'My DIV',
	dataset: {
		a: 1,
		b: 2
	}
});

Начиная с версии 1.1, функция create имеет альтернативный синтаксис. Имя тега можно передать в объект в виде свойства tagName, а дочерние элементы в виде свойства children

var div = $.create({
	tagName: 'div',
	className: 'my-div',
	innerHTML: 'My DIV',
	children: [{
		tagName: 'span',
		className: 'div-child',
		innerHTML: 'first child'
	}, {
		tagName: 'span',
		className: 'div-child',
		innerHTML: 'second child'
	}]
});
Задать вопрос

eventHandler: function

Функция-обработчик события. Принимает любые аргументы, переданные в Matreshka#trigger

Аргументы

Имя Тип Описание
options * любые аргументы, переданные в вызов Matreshka#trigger после имени собыия

Примеры

var eventHandler = function() {
	console.log(arguments);
}
this.on('fyeah', eventHandler);
this.trigger('fyeah', 'foo', 'bar', 'baz'); // logs 'foo', 'bar', 'baz'

matreshka: object

Экземпляр класса Matreshka

bQuery: array

Коллекция bQuery

eventNames: string

Имя события или несколько имен, разделенных пробелами.

Здесь представлен краткий список событий с небольшими примерами. Для получения полной информации, прочтите эту статью на Хабре.

Произвольные события
this.on('myevent', function() {...});
this.trigger('myevent');
change:KEY, вызывающееся, когда свойство меняется
this.on('change:x', function(evt) {...});
this.x = 42;
beforechange:KEY, вызывающееся перед изменением свойства
this.on('beforechange:x', function(evt) {...});
this.x = 42;
bind:KEY и bind, вызывающееся после связывания данных
//для всех свойств
this.on('bind', function(evt) {...});
//для свойства "x"
this.on('bind:x', function(evt) {...});
this.bindNode('x', '.my-node');
delete:KEY и delete, вызывающееся при удалении свойства
//для всех свойств
this.on('delete', function(evt) {...});
//для свойства "x"
this.on('delete:x', function(evt) {...});
this.remove('x');
addevent:NAME и addevent, вызывающееся при инициализации события
//для всех событий
this.on('addevent', function(evt) {...});
//для события "someevent"
this.on('addevent:someevent', function(evt) {...});
//генерирует события "addevent" и "addevent:someevent"
this.on('someevent', function(evt) {...});
DOM_EVENT::KEY, где DOM_EVENT - имя DOM события, KEY - ключ. Генерируется тогда, когда событие DOM_EVENT срабатывает на элементе, связанным с KEY.
this.bindNode('x', '.my-div');
this.on('click::x', function(evt) {
    alert('clicked ".my-div"');
});
DOM_EVENT::KEY(SELECTOR), где DOM_EVENT - имя DOM события, KEY - ключ, SELECTOR - селектор. Генерируется тогда, когда событие DOM_EVENT срабатывает на элементе, который соответствует селектору SELECTOR, и находится в элементе, который связан со свойством KEY.
<div class="my-div">
    <button class="my-button"></button>
</div>
this.bindNode('x', '.my-div');
this.on('click::x(.my-button)', function(evt) {
    alert('clicked ".my-button"');
});
DOM_EVENT::(SELECTOR), где DOM_EVENT - имя DOM события, SELECTOR - селектор. Генерируется тогда, когда событие DOM_EVENT срабатывает на элементе, который соответствует селектору SELECTOR, и находится в песочнице текущего объекта.
this.bindNode('sandbox', '.my-div');
this.on('click::(.my-button)', function(evt) {
    alert('clicked ".my-button"');
});

То же самое, что и:

this.bindNode('sandbox', '.my-div');
this.on('click::sandbox(.my-button)', function(evt) {
    alert('clicked ".my-button"');
});
Делегированные события PATH@EVENT, где PATH - путь к объекту, события которого мы желаем прослушивать, EVENT - имя события.
this.on('a@someevent', function() {...});
this.on('a.b.c@change:d', function() {...});

При возникновении необходимости слушать изменения во всех элементах Matreshka.Array или во всех ключах, отвечающих за данные Matreshka.Object, вместо имени свойства можно указать звездочку "*".

this.on('*@someevent', function() {...});
this.on('*.b.*.d@change:e', function() {...});

Всевозможные комбинации

Все приведенные выше варианты синтаксиса можно комбинировать произвольным способом.

this.on('x.y.z@click::(.my-selector)', function() {...});

binder: object

binder (байндер, привязчик) содержит всю информацию о том, как синхронизировать значение свойства с привязанным к нему DOM элементом. Для всех методов байндера контекст (this) - соответствующий DOM узел.

Свойства

Имя Тип Описание
on optional string function DOM событие (или список событий, разделенных пробелами), после срабатывания которого извлекается состояние DOM элемента и устанавливается свойство. Кроме этого, значением свойства может быть функция, которая устанавливает обработчик произвольным образом.
getValue optional function Функция, которая отвечает за то, как извлечь значение (или "состояние") DOM элемента
setValue optional function Функция, которая отвечает за то, как установить значение свойства DOM элементу
initialize optional function Функция, которая запускается при инициализации привязки. Например, может быть использована для инициализации jQuery плагина.

Примеры

var binder = {
	on: 'click',
	getValue: function(options) {
		return this.value;
	}
	setValue: function(v, options) {
		this.value = v;
	},
	initialize: function(options) {
		alert('Binder is initialized. Initial input value=' + this.value);
	}
};

this.bindNode('a', '.my-checkbox', binder);
var binder = {
	on: function(callback) {
		this.onclick = callback;
	},
	getValue: function(options) {
		return this.value;
	}
	setValue: function(v, options) {
		this.value = v;
	},
	initialize: function(options) {
		alert('Binder is initialized. Initial input value=' + this.value);
	}
};

this.bindNode('a', '.my-checkbox', binder);

eventOptions: object

Это обычный объект, которй может содержать служебные флаги или произвольные данные, которые попадут в обработчик события

Примеры

var eventOptions = {silent: true};

this.a = 1;

this.on('change:a', function() {
	alert('a is changed');
});

this.set('a', 2, eventOptions); // no alert
var eventOptions = {f: 'yeah'};

this.a = 1;

this.on('change:a', function(eventOptions) {
	alert(eventOptions.f);
});

this.set('a', 2, eventOptions); // alerts "yeah"

class: function

Класс (точнее, конструктор класса) возвращаемый функцией Class

Примеры

var MyClass = Class({
	method: function() { ... }
});

node

DOM узел

$nodes

Коллекция DOM узлов. Например, jQuery-элемент(ы)

string

Строка

boolean

Логический тип

number

Число

object

Объект

array

Массив

function

Функция

null

null

*

Любой тип

MatreshkaMagic

Некоторые разработчики не нуждаются в богатом функционале Матрешки, но хотят пользоваться потрясающими утилитами, имеющимися во фреймворке. Поэтому, было решено создать новую, компактную библиотеку, которая называется MatreshkaMagic. Библиотека не включает в себя классы (Matreshka, Matreshka.Object, Matreshka.Array и функцию Class), но содержит все статичные методы и свойства класса Matreshka:

Библиотека находится в папке /magic/ репозитория на github. Подключив скрипт с помощью тега script, программисту доступна глобальная переменная MatreshkaMagic и её краткий вариант magic. Переменная - это обычный объект с методами.

<script src="magic/matreshka-magic.min.js"></script>
var object = {};
magic.bindNode(object, 'x', '.my-node');
magic.linkProps(object, 'y', 'x z', function(x, z) {
    return x + z;
});
magic.mediate(object, 'z', Number);
// и т. д.

При использовании AMD или CJS, глобальные переменные не создаются:

require(['magic/matreshka-magic.min'], function(magic) {
    //...
});
var magic = require('magic/matreshka-magic.min');

На момент написания этой документации, файл matreshka-magic.min.js занимает чуть меньше 30КБ в несжатом виде против 46КБ matreshka.min.js. Если на каком-то этапе потребуется подключить весь фреймворк в проект, нужно лишь изменить пути к файлу скрипта и поменять имена переменных с magic или MatreshkaMagic на MK или Matreshka (второе обязательно только в том случае, если вы не используете AMD или CJS в проекте).

Что нового?

Не забывайте голосовать за новые возможности в trello.

Матрешка 1.9.1

  • Значение setValue для встроенных байндеров всегда либо функция либо null. Это исправляет некоторые проблемы при совместной работе байндеров file и dropFiles.

Матрешка 1.9.0

  • Новый байндер Matreshka.binders.dragOver.
  • Немного изменен алгоритм избегания зацикливания linkProps.
  • Исправлены баги:
    • addDataKeys некорректно работал со случаем, когда передается много аргументов-строк.
    • Аргумент getValue в байндерах всегда получал свойство node равное undefined.
    • bindNode: нельзя было использовать одну и ту же пару элемент-ключ дважды.

Матрешка 1.8.1

  • Исправлены некоторые проблемы в работе parseBindings.
  • Исправлена проблема странного поведения MK.Array#restore в случае, когда renderer находится в песочнице.

Матрешка 1.8.0

  • Новый байндер Matreshka.binders.dropFiles, позволяющий перетаскивать файлы из файловой системы в блок.
  • Исправлена ошибка: делегированные события для селекторов, в которых есть запятая, работали некорректно (click::key(.a, .b, .c)).
  • Исправлен баг: опция assignDefaultProperty со значением true для Matreshka#bindNode не форсило извлечение значения свойства из элемента.
  • Класс Matreshka наследуется от Object.prototype вместо null (как в версиях < 1.6). Это исправляет проблему при которой __proto__ был не виден, а автодополнение не работало в консоли инструментов разработчика.

Матрешка 1.7.1

  • Исправлена ошибка bindNode: метод генерировал ошибку при передаче объекта ключ-нода.

Матрешка 1.7.0

  • Добавлен метод Matreshka.setProto, позволяющий унаследовать прототип класса Matreshka от другого объекта.
  • Исправлен баг, при котором узел, генерируемый itemRenderer обрамлялся тегом span, при использовании jQuery.
  • Исправлен баг: если в метод Matreshka#select передать аргумент нестрокового типа, возвращалась пустая коллекция, вместо null.
  • Больше тестов.

Матрешка 1.6.0

  • Новый метод для сортировки Matreshka.Array: Matreshka.Array#orderBy.
  • Новый статичный метод для сортировки произвольных массивов: Matreshka.orderBy.
  • Убрана поддержка Internet Explorer 8.
  • Метод one для библиотеки bQuery, возвращающий первый элемент из коллекции элементов.
  • Вместо Symbol(matreshka) используется WeakMap для ассоциации объектов со служебными данными (событиями и пр.)
  • itemRenderer теперь кешируется (не парсит HTML каждый раз при рендеринге).
  • Почти полностью переписана библиотека bQuery.
  • Полностью переписана функция Class. Теперь она умеет наследовать свойства, использующие Symbol вместо ключей, а классы наследуются от null вместо Object.
  • Убраны некоторые недокументированные возможности.
  • Убраны полифилы addEventListener и classList.
  • Если использовать встроенные классы без оператора new, генерируется исключение.
  • Больше тестов (покрыто 92% кода)
  • Исправлены баги:
    • Некорректная работа при использовании Zepto в качестве библиотеки.
    • Селектор дочернего элемента в методах select и selectAll не работал.
    • Некорректная работа binders.file при обработке нескольких файлов input[type="file"][multiple].
    • При использовании Matreshka.Array#splice новые элементы массива не конвертировались в Model.
    • Другие мелкие исправления.

Матрешка 1.5.2

  • parseBindings некорректно обрабатывал байндинги к радиокнопкам.
  • Обновлены зависимости. Теперь в тестах используется Babel 6.

Матрешка 1.5.1

  • Исправлен баг: в MK.Object отсутствует Symbol.iterator.

Матрешка 1.5.0

  • Аргумент setOnInit заменен на объект eventOptions в методе Matreshka#linkProps (старый вариант по-прежнему будет работать). Смотрите обновленную документацию к методу.
    • Добавлена поддержка возможности передачи специальных флагов или данных для обработчика изменения свойства, контроллируемого Matreshka#linkProps.
    • Добавлен флаг debounce, оптимизирующий многократные изменения свойств, от которых зависит целевое свойство
    • Добавлен флаг setOnInit
  • Расширен список флагов для Matreshka.bindNode.
    • Добавлен флаг debounce, оптимизирующий обращения к DOM
    • Исправлена проблема #26 за счет флага deep: false, который включает игнорирование точек в имени свойства.
  • Добавлен метод Matreshka.deepFind.
  • Добавлен метод Matreshka#bindSandbox
  • Теперь можно менять скобки парсера, используя объект Matreshka.parserBrackets.
  • При удалении ключей, отвеающих за данные в Matreshka.Object генерируются события remove и modify.
  • Balalaika переименована в bQuery по причине того, что 90% библиотеки переписано с нуля под нужды Матрешки.
  • Многократное увеличение производительности метода splice при рендеринге.
  • Если в качестве Matreshka.Array#Model передать что-то отличное от function или null, генерируется исключение.
  • Исправлен баг: конструктор класса, переданный в Matreshka.Array#Model в некоторых случаях получал неверный индекс.

Матрешка 1.4.1

  • В функцию Class вторым аргументом можно передать объект со статичными свойствами и методами
  • Matreshka.Array#Model получает индекс в качестве третьего аргумента
  • Классы, использующиеся в Matreshka#setClassFor получают ключ в качестве третьего аргумента
  • Matreshka#bound И Matreshka#$bound поддерживают путь к ключу (например, a.b.c.d)
  • Matreshka.binders.file генерирует понятную ошибку, если FileReader не поддерживается браузером
  • Улучшена производительность Балалайки
  • Исправлен баг: Matreshka.Array не мог принудительно перерисовывать кастомные объекты
  • Исправлен баг: Matreshka.Array не позволял перемещать песочницу между коллекциями
  • Теперь можно удалять делегированные DOM события методом Matreshka#off
  • Не использовать кастомную логику делегированных событий, если подключена jQuery
  • Вся логика, отвечающая за делегированные DOM события перемещена в Балалайку
  • Исправлены баги небраузерного окружения (некоторые фичи Матрешки можно использовать в nodejs)

Матрешка 1.4.0

  • Стандартный байндер для тега output Matreshka.binders.output
  • Байндер visibility переименован в Matreshka.binders.display во избежания путаницы с CSS свойством visibility (старое название будет по-прежнему работать )
  • При установке Matreshka.Array#itemRenderer доступен флаг forceRerender: false
  • Событие afterrender, которое срабатывает после небольшой задержки, следующей за вставкой элемента в контейнер (см. Matreshka.Array#itemRenderer)
  • Matreshka#trigger теперь умеет генерировать нативные DOM события ("click::x(.selector)"), которые можно отловить addEventListener
  • Поддержка Opera 11.6+ (было 12+) и Firefox 8+ (было 15+)
  • Ускорен метод Matreshka.Array#pull
  • Исправлена проблема удаления DOM событий, используя метод Matreshka#off
  • Исправлена небольшая проблема в методе Matreshka#mediate
  • Исправлена проблема работы Matreshka.binders.dataset в Internet Explorer
  • Все байндеры покрыты тестами
  • Другие небольшие исправления

Матрешка 1.3.3

  • Исправлен баг рендеринга коллекций и вызова события modify при использовании методов reverse и sort

Матрешка 1.3.2

  • Устранена проблема "Cannot find module 'matreshka'" при использовании Browserify.

Матрешка 1.3.1

  • Исправлена проблема импорта AMD модуля при использовании SystemJS Builder.

Матрешка 1.3.0

  • Новый метод Matreshka.Array#restore
  • Некоторые байндеры из Matreshka.binders переименованы (старые названия будут по-прежнему работать)
  • Байндеры html и text поддерживают двустороннее связывание при использовании атрибута "contenteditable".
  • Новые события "removeevent" и "removeevent:NAME", вызывающиеся при удалении события.
  • Matreshka.Array#itemRenderer не обязательно должен быть валидным HTML элементом. Теперь, если HTML строка содержит несколько узлов (HTML или текстовых), она оборачивается в span.
  • Балалайка поддерживает любые объекты, а не только DOM узлы.
  • Изменения в способе подключения исходника Матрешки при помощи AMD.

Матрешка 1.2.0

  • Добавлено виртуальное свойство Matreshka.Array#trackBy
  • Исправлена ошибка в Matreshka.to
  • Кастомные селекторы при глубоком связывании работали некорректно

Матрешка 1.1.2

  • Улучшена производительность кастомных селекторов (:bound(KEY) и :sandbox)
  • Восстановлен Matreshka#parseBindings

Матрешка 1.1.1

  • Поддержка Матрешкой Opera Mini за счет включения oMatchesSelector для Балалайки

Матрешка 1.1.0

  • Упрощенная проверка версии Internet Explorer: используется documentMode вместо useragent.
  • Улучшена производительность Matreshka#parseBindings и исправлена ошибка для старых WebKit.
  • "Глубокие ссылки" для метода Matreshka#linkProps.

Матрешка 1.1.0 RC3

  • Исправлена ошибка в setClassFor, возникающая в Internet Explorer 8.
  • Небольшая оптимизация метода off.
  • Восстановлен байндер innerText.

Матрешка 1.1.0 RC2

  • Исправлены некоторые ошибки, возникающие в Internet Explorer 8.
  • Небольшая оптимизация метода on.
  • Убраны неиспользующиеся псевдо-приватные методы.

Матрешка 1.1.0 RC

Новые методы и свойства

Расширение функционала Матрешки

  • "Глубокое связывание", позволяющее связать элемент со свойством, находящемся где-то в глубине дерева объектов.
    this.bindNode('a.b.c.d', '.my-node');
  • Изменение синтаксиса делегированных событий и реализация совместимости со старыми приложениями.
    this.on('a.b.*.*.e@someevent', f);
  • Дополнительный синтаксис Matreshka#bindNode
    this.bindNode({
      x: '.my-x-node',
      y: ['.my-y-node', MK.binders.className()],
      z: ['.my-z-node', {
          setValue: function(v) {...}
      }]
    })
  • Новые вариации методов Matreshka#on, Matreshka#once, Matreshka#onDebounce, позволяющие передать объект событие-обработчик.
  • Улучшенный багрепорт в случае, если нода не найдена при использовании Matreshka#bindNode. В тексте ошибки теперь видно селектор, а не только ключ.
  • getValue для старых байндеров (для получения значения ноды в момент привязки).
  • Флаг forceRerender для Matreshka.Array#rerender.
  • Рендеринг любых объектов в Matreshka.Array.
  • Включение шаблонизатора для Matreshka.Array#renderer по умолчанию.
  • Возможность создавать DOM дерево произвольной вложенности с помощью функции $b.create.
  • Возврат this из всех конструкторов для красивого цепочечного вызова после super в ECMAScript 2015.
    class X extends Matreshka.Array {
      constructor(data) {
          super(...data).bindNode(/*...*/);
      }
    }

События

  • Новые события: beforechange и beforechange:KEY, вызывающиеся перед изменением свойства.
  • Новые события: addevent и addevent:NAME для отслеживания добавления новых событий.

Исправления

  • Matreshka.Object#jset не генерирует исключение, если передан null.
  • Исправлена ошибка зацикливания Matreshka#linkProps в некоторых специфичных случаях.
  • Исправлен кейс, когда флаг forceHTML не срабатывал в методе Matreshka.#set
  • Исправлен баг в методе Matreshka.Array#concat.
  • Исправление небольшого бага для старых WebKit браузеров при использовании шаблонизатора.
  • Исправлен баг в MacOS, появляющися при использовании Matreshka#mediate.
  • Рендерить массивы, даже если в модифицирующий метод передан silent: true.
  • Мелкие исправления.

Другие новости

  • Объекты, использующиеся Матрешкой получают свойство Symbol(matreshka) вместо __events, __special и __id.
  • Добавлены автоматические тесты (на текущий момент, 145 штук).
  • Исходный код разбит на мелкие кусочки.
  • Многократное увеличение производительности фреймворка. В некоторых местах производительность улучшена в 40 (!) раз.
  • Библиотека MatreshkaMagic.

Матрешка 1.0.7

  • Устранена ошибка в MacOS, возникающая при использовании Matreshka#mediate

Матрешка 1.0.6

  • Устранена проблема работы AMD в минифицированной версии

Матрешка 1.0.5

  • Исправлен баг: не работает байндинг при автозаполнении, когда текст вводится руками, а браузер выдаёт подсказки
  • Теперь ловится событие input вместо paste + change в байндерах input и textarea (кроме IE8)
  • setValue теперь вызывается при нестрогом неравенстве (вместо строгого). Этим исправлением убрана проблема перепрыгивания курсора в конец строки при использовании Matreshka#mediate.
  • Matreshka.version обновляется автоматически при сборке
  • Исправлен баг: отвязанные элементы можно было получить из $bound/bound, select/$
  • Небольшой рефакторинг

Матрешка 1.0.4

  • Исправлена ошибка рендеринга, связанная с удалением элементов Matreshka.Array.

Матрешка 1.0.3

  • Исправлена ошибка Matreshka.binders.select, возникающая при использовании аргумента multiple
  • Серьезная оптимизация скорости большинства методов Matreshka.Array
  • Исправлены неочевидные ошибки рендеринга Matreshka.Array

Матрешка 1.0.2

  • Исправлены ошибки Matreshka.Array для Internet Explorer 8
  • Небольшая оптимизация методов Matreshka.Array

Матрешка 1.0.1

  • Серьезная оптимизация скорости всех методов Matreshka.Array

Матрешка 1.0

  • Убраны предупреждения об использовании устаревших методов и событий, очищен код
  • Несколько небольших исправлений

Матрешка 0.4.1

  • Устранена проблема со сборкой

Матрешка 0.4

  • Исправлена небольшая ошибка при работе с Babel
  • Все файлы проекта теперь используют строгий режим
  • Новое свойство Matreshka#sandbox
  • Новое свойство Matreshka#$sandbox
  • Ключ value объекта события
  • Ключ element объекта события переименован в node
  • Ключ elements объекта события переименован в $nodes
  • Ключ fromElement объекта события переименован в fromNode
  • Ключ originaEvent для объекта события, содержащее оригинальное DOM событие в случае использования jQuery
  • Опция moveSandbox для MK.Array
  • Другие небольшие исправления

Матрешка 0.3

Новые возможности

  • Метод Matreshka.randomString
  • Метод Matreshka#onDebounce
  • Метод Matreshka#bindOptionalNode
  • Метод Matreshka#delay
  • Методы Matreshka.Array, позволяющие передать объект события (push_, sort_, splice_...). См. Matreshka.Array#METHOD_
  • Свойство Matreshka.version
  • Новый односторонний байндер Matreshka.binders.visibility
  • Свойство on у привязчика может быть функцией
  • Добавлен флаг skipMediator для методов Matreshka.Array
  • Переопределение Matreshka.Array#itemRenderer свойством renderer дочернего элемента
  • Свойство Matreshka.Array#renderIfPossible
  • Функция Matreshka.lookForBinder теперь статичный метод класса Matreshka
  • Для привязки песочницы теперь используется ключ sandbox вместо __this__
  • События addone и removeone для Matreshka.Array
  • Matreshka.Array#push и Matreshka.Array#unshift теперь возвращают длину массива вместо себя (как и в нативном массиве)
  • Реализованы привязчики для всех HTML5 элементов формы
  • Новые служебные флаги для метода Matreshka#set: silentHTML, skipLinks
  • Matreshka.Array#itemRenderer теперь поддерживает строку, как значение
  • Добавлен ключ self для всех событий Matreshka.Array
  • Можно менять Matreshka.Array#Model динамически
  • Вызывать событие change, если при привязке Матрешка меняет значение свойства на состояние элемента (если свойство не определено и не передан флаг assignDefaultValue: false)
  • Новые селекторы: :sandbox и :bound(KEY)
  • Поддержка свойства attributes для функции Balalaika.create
  • Экспериментальный шаблонизатор для Matreshka.Array#itemRenderer если Matreshka.Array#useBindingsParser установлен, как true
  • Перенесены все привязчики в объект Matreshka.binders
  • Matreshka.Array#pull теперь поддерживает объект в качестве аргумента
  • Короткая запись для делегированных событий DOM внутри песочницы (click::(.selector) вместо click::sandbox(.selector))
  • Поддержка цикла for..of для Matreshka.Array и Matreshka.Object
  • Свойство domEvent содержащее объект события для событий DOM
  • Делегированные DOM события (this.on( 'click::something(.x > .y)' ))

Устаревшие методы и события

  • Все методы, имя которых начинается с silent (silentPush, silentSplice, silentSort ...) удалены. Для этих целей теперь используются методы с нижним подчеркиванием в конце имени и флагом silent (например, this.push_(1,2,3, {silent: true}))
  • Метод Matreshka#initMK удален, теперь используется ленивая инициализация
  • Метод Matreshka#defineNotEnum удален по причине отсутствия в нем потребности
  • Matreshka.Array#initializeSmartArray -> Matreshka.Array#rerender
  • Matreshka#setMediator -> Matreshka#mediate
  • Matreshka#bindElement -> Matreshka#bindNode
  • Matreshka#unbindElement -> Matreshka#unbindNode
  • Matreshka#addDependency -> Matreshka#linkProps
  • Matreshka.Array#setItemMediator -> Matreshka.Array#mediateItem
  • Matreshka.Object#addJSONKeys -> Matreshka.Object#addDataKeys
  • Matreshka.Object#removeJSONKeys -> Matreshka.Object#removeDataKeys
  • Matreshka.procrastinate -> Matreshka.debounce
  • Удалено событие itemrender из Matreshka.Array. Можно использовать @render вместо него

Исправленные баги

  • Фиксы в Балалайке для старых браузеров WebKit, например, iOS 5 Safari
  • Обработчик DOM события вызывался несколько раз
  • Matreshka#off теперь возвращает себя
  • Исправлен баг в Matreshka#defineGetter
  • Исправлен баг в Matreshka.Array#concat
  • Исправлен баг в Matreshka#once
  • Исправлен баг в Matreshka.Array#itemMediator
  • Исправлен баг в механизме рендеринга Matreshka.Array
  • Небольшие исправления в Matreshka#bindNode
  • Небольшие исправления для стандартных байндеров
  • Делегированные события не работали для Matreshka.Object
  • Всегда возвращать null из Matreshka#bound если элемент не найден
  • Исправлен неочевидный баг в Matreshka#set, возникающий при использовании Matreshka.Array#mediateItem и Matreshka.Array#linkProps вместе
  • Использовать событие delete вместо remove
  • binder.setValue вызывался даже если значение свойства не было изменено
  • Привязанные HTML элементы не обновлялись после вызова Matreshka#mediate
  • Фиксы для Internet Explorer 8
  • Matreshka.lookForBinder теперь возвращает undefined если байндер не найден
  • Генерировать события модификации Matreshka.Array только когда коллекция изменилась

Изменения в коде

  • Оптимизирована генерация событий
  • Созданы методы _on и _off для внутреннего использования и улучшения производительности
  • Создан приватный метод Matreshka#_initMK
  • Оптимизирован код Matreshka.Object
  • Убран полифил Number.isNaN

FAQ

Имеется ли в Матрешке обертка над XMLHttpRequest (AJAX)?

Нет. Во-первых есть много прекрасных библиотек, реализующих коммуникации с сервером: некогда популярный jQuery.ajax, потрясающая библиотека qwest, основанная на "промисах" и многие другие.

Во-вторых, в качестве альтернативы XMLHttpRequest, все браузеры, возможно, очень скоро получат нативную поддержку Fetch API. fetch имеет более простое и чистое API, основанное на "промисах", позволяющее избежать катастрофического количества callback'ов и необходимости помнить API XMLHttpRequest. Пока fetch поддерживается не всем браузерами, можно воспользоваться популярным полифилом.

"Промисы" и асинхронные функции из спецификации ECMAScript 7 дают возможность писать великолепной красоты JavaScript код:

async function getData() {
    let resp = await fetch(someUrl);
    let data = await resp.text();

    console.log(data);
}

getData();

Есть ли в Матрешке роутинг?

И да и нет. Как и в случае с AJAX, в интернете есть полно замечательных библитек, реализующих роутинг, например director. Но для простых задач и задач средней сложности (99% всех проектов) можно воспользоваться плагином, реализующим двусторонее связывание части URL со свойствами объекта. Плагин прекрасно вписывается в концепцию Матрешки, добавляя в приложение самый простой способ управления адресом во всей Вселенной. Плагин находится по этой ссылке. Подробное описание на русском можно прочесть в статье на Хабре.

Как работает Матрешка?

Матрешка использует акцессоры (accessors), в частности, сеттеры (setters) для реализации двустороннего связывания данных и отлова событий изменения свойств. Эта технология существует достаточно давно. Одной из главных особенностей сеттеров, является молниеносная скорость, сравнимая со скоростью работы с обычными свойствами. В производительности акцессоры выигрывают у других решений: Object.observe и, особенно, dirty-checking.

В качестве примера того, как работает двустороннее связывание (в частности, функция bindNode), взгляните на этот код:

window.bindNode = function bindNode(object, key, node, binder) {
    var value = object[key];
    Object.defineProperty(object, key, {
        get: function() {
            return value;
        },
        set: function(v) {
            binder.setValue.call(node, v);
        }
    });

    node.addEventListener(binder.on, function() {
        value = binder.getValue.call(node);
    });
};

Как видите, ничего сложного (для упрощения, функция не поддерживает связь многие-ко-многим).

Пример работы функции можно посмотреть на jsbin.

Поддерживает ли Матрешка серверный рендеринг?

К сожалению, (возможно, пока) нет. Матрешка использует DOM шаблонизацию, которая требует наличия на сервере библиотеки, реализующей DOM API. Хорошим примером такой библиотеки является jsdom. Проблема в том, что к серверу присоединяется много клиентов, каждый из которых может запросить соверщенно разные страницы, генерирующиеся динамически. DOM шаблонизация работает заметно медленнее, чем HTML шаблонизация, где шаблоном выступает обычный текст, а не многочисленные DOM объеты.

В качестве примера, можно привести серверный рендеринг React компонентов, которые тоже требуют DOM шаблонизатор. Как правило, эта задача решается хитрыми трюками и рекомендациями использовать кеширование шаблонов (что не всегда возможно, а если возможно, может вызвать утечки памяти). Даже используя лучшие практики и хитроумные решения, обычный текстовый HTML шаблонизатор (скажем, mustache.js) решит проблему многократно быстрее, а скорость на сервере, как известно, намного важне, чем на клиенте.

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

Поддержка браузерами

Firefox Chrome Opera Internet Explorer Safari iOS Safari Opera Mini Android Browser Yandex Browser
<8 <14 <11.6 <9 * <5 <4 <11 <2.2 <14
8+ 14+ 11.6+ 9+ 5+ 4+ 11+ 2.2+ 14+
  • Тесты прошли успешно.
  • Нет данных. Матрешка в этих браузерах не проверялась.
  • Некоторые тесты не пройдены.

Обратите внимание:

  • Поддержка чтения файлов Matreshka.binders.file не включена в таблицу. Она зависит от наличия в браузере FileReader API. Узнать, поддерживает ли тот или иной браузер FileReader можно на Caniuse.
  • Поддержка установки прототипа класса Matreshka с помощью Matreshka.setProto не включена в таблицу. Она зависит от наличия статичного метода Object.setPrototypeOf или свойства __proto__.

Не нашли свой браузер? Откройте в нем страницу с тестами.

Нашли опечатку или ошибку?
Выберите текст и нажмите
+
Ошибка на сайте