Skip to content

Commit

Permalink
feat: The new existence binder
Browse files Browse the repository at this point in the history
  • Loading branch information
finom committed Apr 2, 2017
1 parent 4f5aadf commit 35b403f
Show file tree
Hide file tree
Showing 7 changed files with 192 additions and 5 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"node-test": "babel-node test/node-test/jasmine.js",
"node-cover": "babel-node node_modules/.bin/babel-istanbul cover test/node-test/jasmine.js && cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js",
"check-coverage": "babel-istanbul check-coverage --lines 95",
"develop": "karma start test/karma.conf.js",
"develop": "CHROME_BIN=chromium-browser karma start test/karma-test/karma.conf.js",
"karma-test": "CHROME_BIN=chromium-browser karma start test/karma-test/karma.conf.js --single-run --no-auto-watch",
"karma-libraries-test": "npm run karma-test && npm run karma-test -- --dom-library=jquery-1 && npm run karma-test -- --dom-library=jquery-2 && npm run karma-test -- --dom-library=jquery-3 && npm run karma-test -- --dom-library=zepto",
"watch": "webpack --config ./webpack.config.js --watch",
Expand Down
3 changes: 2 additions & 1 deletion src/array/_processrendering/getalreadyrendered.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ export default function getAlreadyRendered({

// if item's node is already rendered for an array then return it
if (renderedInArrays && renderedInArrays[selfId]) {
return renderedInArrays[selfId];
const node = renderedInArrays[selfId];
return node.__matreshkaReplacedByNode || node;
}
}

Expand Down
3 changes: 2 additions & 1 deletion src/array/_processrendering/renderitemnode.js
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,8 @@ export default function renderItemNode({
throw matreshkaError('array:rendered_number_nodes', { length: parsed.length });
}

const node = renderedInArrays[selfId] = parsed[0];
let node = renderedInArrays[selfId] = parsed[0];
node = node.__matreshkaReplacedByNode || node;

if (bindRenderedAsSandbox) {
if (forceRerender) {
Expand Down
43 changes: 43 additions & 0 deletions src/binders/existence.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
export default function existence(switcher = true) {
let comment;

return {
setValue(value) {
const node = this;
const { tagName, id, classList, className } = node;

if (!comment) {
let commentText = tagName;


if (id) {
commentText += `#${id}`;
}

if (className) {
commentText += `.${[].slice.apply(classList).join('.')}`;
}

comment = window.document.createComment(commentText);
}

value = !switcher ? !value : value; // eslint-disable-line no-param-reassign

if (value) {
delete node.__matreshkaReplacedByNode;
if (comment.parentNode) {
comment.parentNode.insertBefore(node, comment);
comment.parentNode.removeChild(comment);
}
}

if (!value) {
node.__matreshkaReplacedByNode = comment;
if (node.parentNode) {
node.parentNode.insertBefore(comment, node);
node.parentNode.removeChild(node);
}
}
}
};
}
4 changes: 3 additions & 1 deletion src/binders/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import progress from './progress';
import text from './text';
import style from './style';
import dataset from './dataset';
import existence from './existence';

export {
html,
Expand All @@ -25,5 +26,6 @@ export {
progress,
text,
style,
dataset
dataset,
existence
};
2 changes: 1 addition & 1 deletion src/select.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export default function select(object, selector) {
if (bindings) {
// iterate over all bound nodes trying to find a descendant matched given selector
for (let i = 0; i < bindings.length; i++) {
const { node } = bindings[i];
const node = bindings[i].node;
const selected = node.querySelector(selector);

if (selected) {
Expand Down
140 changes: 140 additions & 0 deletions test/spec/bindings/existence_binder_spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
/* eslint-disable import/no-extraneous-dependencies, import/extensions */
import bindNode from 'src/bindnode';
import select from 'src/select';
import MatreshkaArray from 'src/array';
import { existence } from 'src/binders';

describe('Existence binder', () => {
const noDebounceFlag = {
debounceSetValue: false,
debounceGetValue: false
};

let obj;
let node;
let parent;

beforeEach(() => {
obj = {};
node = window.document.createElement('div');
node.innerHTML = '<div><i class="foo" id="foo"></i></div>';
parent = window.document.createElement('div');
parent.appendChild(node);
});

it('should allow to use exitence binder', () => {
node.id = 'foo';
node.className = 'bar baz';

obj.x = false;
bindNode(obj, 'x', node, existence(), noDebounceFlag);

expect(parent.childNodes.length).toEqual(1);
expect(parent.childNodes[0].nodeName).toEqual('#comment');
expect(parent.childNodes[0].nodeValue).toEqual('DIV#foo.bar.baz');

obj.x = true;

expect(parent.childNodes.length).toEqual(1);
expect(parent.childNodes[0].tagName).toEqual('DIV');

obj.x = false; // try again

expect(parent.childNodes.length).toEqual(1);
expect(parent.childNodes[0].nodeName).toEqual('#comment');
expect(parent.childNodes[0].nodeValue).toEqual('DIV#foo.bar.baz');

obj.x = true; // try again

expect(parent.childNodes.length).toEqual(1);
expect(parent.childNodes[0].tagName).toEqual('DIV');
});

it('should allow to use exitence binder with reverse behavior', () => {
node.id = 'foo';
node.className = 'bar baz';

obj.x = false;
bindNode(obj, 'x', node, existence(false), noDebounceFlag);

expect(parent.childNodes.length).toEqual(1);
expect(parent.childNodes[0].nodeName).toEqual('DIV');

obj.x = true;

expect(parent.childNodes.length).toEqual(1);
expect(parent.childNodes[0].nodeName).toEqual('#comment');
expect(parent.childNodes[0].nodeValue).toEqual('DIV#foo.bar.baz');

obj.x = false; // try again

expect(parent.childNodes.length).toEqual(1);
expect(parent.childNodes[0].nodeName).toEqual('DIV');

obj.x = true; // try again

expect(parent.childNodes.length).toEqual(1);
expect(parent.childNodes[0].nodeName).toEqual('#comment');
expect(parent.childNodes[0].nodeValue).toEqual('DIV#foo.bar.baz');
});

it('should allow to select nodes inside original element', () => {
obj.x = false;
bindNode(obj, 'x', node, existence(), noDebounceFlag);

expect(select(obj, ':bound(x)')).toEqual(node);
expect(select(obj, ':bound(x) .foo').id).toEqual('foo');

obj.x = true;
expect(select(obj, ':bound(x)')).toEqual(node);
expect(select(obj, ':bound(x) .foo').id).toEqual('foo');

obj.x = false;
expect(select(obj, ':bound(x)')).toEqual(node);
expect(select(obj, ':bound(x) .foo').id).toEqual('foo');
});

it('should be possible to bind array item and manipulate with an array', () => {
const arr = new MatreshkaArray();
arr.itemRenderer = '<div class="child"></div>';

bindNode(arr, 'sandbox', '<div class="parent"></div>');

arr.push(
{ x: 3, exists: true },
{ x: 1, exists: false },
{ x: 5, exists: true },
{ x: 2, exists: false },
{ x: 4, exists: true }
);

for (const item of arr) {
bindNode(item, 'exists', ':sandbox', existence(), noDebounceFlag);
console.log(select(item, ':sandbox').__matreshkaReplacedByNode);
}

expect(
Array.from(arr.nodes.sandbox.childNodes).map(({ nodeName }) => nodeName)
).toEqual(['DIV', '#comment', 'DIV', '#comment', 'DIV']);

arr.sort((a, b) => (a.x > b.x ? 1 : -1));

expect(
Array.from(arr.nodes.sandbox.childNodes).map(({ nodeName }) => nodeName)
).toEqual(['#comment', '#comment', 'DIV', 'DIV', 'DIV']);

arr.reverse();

expect(
Array.from(arr.nodes.sandbox.childNodes).map(({ nodeName }) => nodeName)
).toEqual(['DIV', 'DIV', 'DIV', '#comment', '#comment']);

arr[0].exists = false;

arr[4].exists = true;

expect(
Array.from(arr.nodes.sandbox.childNodes).map(({ nodeName }) => nodeName)
).toEqual(['#comment', 'DIV', 'DIV', '#comment', 'DIV']);
});
});

0 comments on commit 35b403f

Please sign in to comment.