Files
yoga/spec/LayoutSpec.js
Christopher Chedeau 6859575797 flex recursively
2014-04-06 09:43:16 -07:00

254 lines
6.6 KiB
JavaScript
Executable File

function setupIframe(callback) {
var iframe = document.createElement('iframe');
document.body.appendChild(iframe);
var doc = iframe.contentDocument;
var link = document.createElement('link');
link.setAttribute('rel', 'stylesheet');
link.setAttribute('type', 'text/css');
link.setAttribute('href', 'style.css');
doc.head.appendChild(link);
requestAnimationFrame(function wait() {
if (doc.styleSheets.length) {
callback(iframe);
} else {
requestAnimationFrame(wait);
}
})
}
var iframe = null;
function computeDOMLayout(node) {
var body = iframe.contentDocument.body;
function transfer(div, node, name, ext) {
if (name in node.style) {
div.style[name] = node.style[name] + (ext || '');
}
}
function renderNode(parent, node) {
var div = document.createElement('div');
transfer(div, node, 'width', 'px');
transfer(div, node, 'height', 'px');
transfer(div, node, 'margin', 'px');
transfer(div, node, 'flexDirection');
transfer(div, node, 'flex');
parent.appendChild(div);
(node.children || []).forEach(function(child) {
renderNode(div, child);
});
return div;
}
var div = renderNode(body, node);
function buildLayout(parentRect, div) {
var rect = div.getBoundingClientRect();
var result = {
width: rect.width,
height: rect.height,
top: rect.top - parentRect.top,
left: rect.left - parentRect.left
};
var children = [];
for (var child = div.firstChild; child; child = child.nextSibling) {
children.push(buildLayout(result, child));
}
if (children.length) {
result.children = children;
}
return result;
}
var layout = buildLayout({left: 0, top: 0}, div);
body.removeChild(div);
return layout;
}
function nameLayout(name, layout) {
var namedLayout = {name: name};
for (var key in layout) {
namedLayout[key] = layout[key];
}
return namedLayout;
}
function testNamedLayout(name, layoutA, layoutB) {
expect(nameLayout(name, layoutA))
.toEqual(nameLayout(name, layoutB));
}
function testLayout(node, expectedLayout) {
var layout = computeLayout(node);
var domLayout = computeDOMLayout(node);
testNamedLayout('expected-dom', expectedLayout, domLayout);
testNamedLayout('layout-dom', layout, domLayout);
}
describe('Layout', function() {
beforeEach(function(done) {
if (iframe) {
done();
} else {
setupIframe(function(ifrm) { iframe = ifrm; done(); });
}
});
it('should layout a single node with width and height', function() {
testLayout({
style: {width: 100, height: 200}
}, {
width: 100, height: 200, top: 0, left: 0
});
});
it('should layout node with children', function() {
testLayout({
style: {width: 1000, height: 1000},
children: [
{style: {width: 500, height: 500}},
{style: {width: 250, height: 250}},
{style: {width: 125, height: 125}}
]
}, {
width: 1000, height: 1000, top: 0, left: 0,
children: [
{width: 500, height: 500, top: 0, left: 0},
{width: 250, height: 250, top: 500, left: 0},
{width: 125, height: 125, top: 750, left: 0}
]
});
});
it('should layout node with nested children', function() {
testLayout({
style: {width: 1000, height: 1000},
children: [{
style: {width: 500, height: 500}
}, {
style: {width: 500, height: 500},
children: [
{style: {width: 250, height: 250}},
{style: {width: 250, height: 250}}
]
}]
}, {
width: 1000, height: 1000, top: 0, left: 0,
children: [{
width: 500, height: 500, top: 0, left: 0
}, {
width: 500, height: 500, top: 500, left: 0,
children: [
{width: 250, height: 250, top: 0, left: 0},
{width: 250, height: 250, top: 250, left: 0},
]
}]
});
});
it('should layout node with margin', function() {
testLayout({
style: {width: 100, height: 200, margin: 10}
}, {
width: 100, height: 200, top: 10, left: 10
});
});
it('should layout node with several children', function() {
testLayout({
style: {width: 1000, height: 1000, margin: 10},
children: [
{style: {width: 100, height: 100, margin: 50}},
{style: {width: 100, height: 100, margin: 25}},
{style: {width: 100, height: 100, margin: 10}}
]
}, {
width: 1000, height: 1000, top: 10, left: 10,
children: [
{width: 100, height: 100, top: 50, left: 50},
{width: 100, height: 100, top: 225, left: 25},
{width: 100, height: 100, top: 360, left: 10}
]
});
});
it('should layout node with row flex direction', function() {
testLayout({
style: {width: 1000, height: 1000, flexDirection: 'row'},
children: [
{style: {width: 100, height: 200}},
{style: {width: 300, height: 150}}
]
}, {
width: 1000, height: 1000, top: 0, left: 0,
children: [
{width: 100, height: 200, top: 0, left: 0},
{width: 300, height: 150, top: 0, left: 100}
]
});
});
it('should layout node based on children main dimensions', function() {
testLayout({
style: {width: 300},
children: [
{style: {width: 100, height: 200}},
{style: {width: 300, height: 150}}
]
}, {
width: 300, height: 350, top: 0, left: 0,
children: [
{width: 100, height: 200, top: 0, left: 0},
{width: 300, height: 150, top: 200, left: 0}
]
});
});
it('should layout node with flex', function() {
testLayout({
style: {width: 1000, height: 1000},
children: [
{style: {width: 100, height: 200}},
{style: {width: 100, flex: 1}}
]
}, {
width: 1000, height: 1000, top: 0, left: 0,
children: [
{width: 100, height: 200, top: 0, left: 0},
{width: 100, height: 800, top: 200, left: 0}
]
});
});
it('should layout node with flex recursively', function() {
testLayout({
style: {width: 1000, height: 1000},
children: [{
style: {width: 1000, flex: 1},
children: [{
style: {width: 1000, flex: 1},
children: [{
style: {width: 1000, flex: 1}
}]
}]
}]
}, {
width: 1000, height: 1000, top: 0, left: 0,
children: [{
width: 1000, height: 1000, top: 0, left: 0,
children: [{
width: 1000, height: 1000, top: 0, left: 0,
children: [{
width: 1000, height: 1000, top: 0, left: 0
}]
}]
}]
});
});
});