Moving skip and loop line calculation into Repeat nodes

This code seems more at home in Repeat instead of MatchFragment since
Repeat knows about the dimensions of the lines for the contentPosition
value.
This commit is contained in:
Jeff Avallone 2015-04-23 20:03:25 -04:00
parent ff9e84f20e
commit 06a7ffc110
4 changed files with 120 additions and 125 deletions

View File

@ -77,11 +77,11 @@ describe('parser/javascript/match_fragment.js', function() {
this.node.content.render.and.returnValue(this.renderDeferred.promise); this.node.content.render.and.returnValue(this.renderDeferred.promise);
this.node.repeat = { this.node.repeat = {
contentPosition: 'example position' contentPosition: 'example position',
skipPath: jasmine.createSpy('skipPath').and.returnValue('skip path'),
loopPath: jasmine.createSpy('loopPath').and.returnValue('loop path')
}; };
spyOn(this.node, 'skipPath').and.returnValue('skip path');
spyOn(this.node, 'loopPath').and.returnValue('loop path');
spyOn(this.node, 'loopLabel'); spyOn(this.node, 'loopLabel');
}); });
@ -107,8 +107,8 @@ describe('parser/javascript/match_fragment.js', function() {
it('renders a skip path and loop path', function(done) { it('renders a skip path and loop path', function(done) {
this.node._render() this.node._render()
.then(() => { .then(() => {
expect(this.node.skipPath).toHaveBeenCalledWith('content bbox'); expect(this.node.repeat.skipPath).toHaveBeenCalledWith('content bbox');
expect(this.node.loopPath).toHaveBeenCalledWith('content bbox'); expect(this.node.repeat.loopPath).toHaveBeenCalledWith('content bbox');
expect(this.node.container.path).toHaveBeenCalledWith('skip pathloop path'); expect(this.node.container.path).toHaveBeenCalledWith('skip pathloop path');
done(); done();
}); });
@ -126,85 +126,6 @@ describe('parser/javascript/match_fragment.js', function() {
}); });
describe('#skipPath', function() {
beforeEach(function() {
this.node = new javascript.Parser('a').__consume__match_fragment();
this.node.repeat = {};
this.box = {
y: 11,
ay: 22,
width: 33
};
});
it('returns nothing when there is no skip', function() {
this.node.repeat.hasSkip = false;
expect(this.node.skipPath(this.box)).toEqual([]);
});
it('returns a path when there is a skip', function() {
this.node.repeat.hasSkip = true;
this.node.repeat.greedy = true;
expect(this.node.skipPath(this.box)).toEqual([
'M0,22q10,0 10,-10v-1q0,-10 10,-10h23q10,0 10,10v1q0,10 10,10'
]);
});
it('returns a path with arrow when there is a non-greedy skip', function() {
this.node.repeat.hasSkip = true;
this.node.repeat.greedy = false;
expect(this.node.skipPath(this.box)).toEqual([
'M0,22q10,0 10,-10v-1q0,-10 10,-10h23q10,0 10,10v1q0,10 10,10',
'M10,7l5,5m-5,-5l-5,5'
]);
});
});
describe('#loopPath', function() {
beforeEach(function() {
this.node = new javascript.Parser('a').__consume__match_fragment();
this.node.repeat = {};
this.box = {
x: 11,
x2: 22,
ay: 33,
y2: 44,
width: 55
};
});
it('returns nothing when there is no loop', function() {
this.node.repeat.hasLoop = false;
expect(this.node.loopPath(this.box)).toEqual([]);
});
it('returns a path when there is a loop', function() {
this.node.repeat.hasLoop = true;
this.node.repeat.greedy = false;
expect(this.node.loopPath(this.box)).toEqual([
'M11,33q-10,0 -10,10v1q0,10 10,10h55q10,0 10,-10v-1q0,-10 -10,-10'
]);
});
it('returns a path with arrow when there is a greedy loop', function() {
this.node.repeat.hasLoop = true;
this.node.repeat.greedy = true;
expect(this.node.loopPath(this.box)).toEqual([
'M11,33q-10,0 -10,10v1q0,10 10,10h55q10,0 10,-10v-1q0,-10 -10,-10',
'M32,48l5,-5m-5,5l-5,-5'
]);
});
});
describe('#loopLabel', function() { describe('#loopLabel', function() {
beforeEach(function() { beforeEach(function() {

View File

@ -253,4 +253,78 @@ describe('parser/javascript/repeat.js', function() {
}); });
describe('#skipPath', function() {
beforeEach(function() {
this.node = new javascript.Parser('*').__consume__repeat();
this.box = {
y: 11,
ay: 22,
width: 33
};
});
it('returns nothing when there is no skip', function() {
this.node.hasSkip = false;
expect(this.node.skipPath(this.box)).toEqual([]);
});
it('returns a path when there is a skip', function() {
this.node.hasSkip = true;
this.node.greedy = true;
expect(this.node.skipPath(this.box)).toEqual([
'M0,22q10,0 10,-10v-1q0,-10 10,-10h23q10,0 10,10v1q0,10 10,10'
]);
});
it('returns a path with arrow when there is a non-greedy skip', function() {
this.node.hasSkip = true;
this.node.greedy = false;
expect(this.node.skipPath(this.box)).toEqual([
'M0,22q10,0 10,-10v-1q0,-10 10,-10h23q10,0 10,10v1q0,10 10,10',
'M10,7l5,5m-5,-5l-5,5'
]);
});
});
describe('#loopPath', function() {
beforeEach(function() {
this.node = new javascript.Parser('*').__consume__repeat();
this.box = {
x: 11,
x2: 22,
ay: 33,
y2: 44,
width: 55
};
});
it('returns nothing when there is no loop', function() {
this.node.hasLoop = false;
expect(this.node.loopPath(this.box)).toEqual([]);
});
it('returns a path when there is a loop', function() {
this.node.hasLoop = true;
this.node.greedy = false;
expect(this.node.loopPath(this.box)).toEqual([
'M11,33q-10,0 -10,10v1q0,10 10,10h55q10,0 10,-10v-1q0,-10 -10,-10'
]);
});
it('returns a path with arrow when there is a greedy loop', function() {
this.node.hasLoop = true;
this.node.greedy = true;
expect(this.node.loopPath(this.box)).toEqual([
'M11,33q-10,0 -10,10v1q0,10 10,10h55q10,0 10,-10v-1q0,-10 -10,-10',
'M32,48l5,-5m-5,5l-5,-5'
]);
});
});
}); });

View File

@ -38,8 +38,8 @@ export default {
// Add skip or repeat paths to the container. // Add skip or repeat paths to the container.
paths = _.flatten([ paths = _.flatten([
this.skipPath(box), this.repeat.skipPath(box),
this.loopPath(box) this.repeat.loopPath(box)
]); ]);
this.container.prepend( this.container.prepend(
@ -49,45 +49,6 @@ export default {
}); });
}, },
// Returns the path spec to render the line that skips over the content for
// fragments that are optionally matched.
skipPath(box) {
var paths = [];
if (this.repeat.hasSkip) {
let vert = Math.max(0, box.ay - box.y - 10),
horiz = box.width - 10;
paths.push(`M0,${box.ay}q10,0 10,-10v${-vert}q0,-10 10,-10h${horiz}q10,0 10,10v${vert}q0,10 10,10`);
// When the repeat is not greedy, the skip path gets a preference arrow.
if (!this.repeat.greedy) {
paths.push(`M10,${box.ay - 15}l5,5m-5,-5l-5,5`);
}
}
return paths;
},
// Returns the path spec to render the line that repeats the content for
// fragments that are matched more than once.
loopPath(box) {
var paths = [];
if (this.repeat.hasLoop) {
let vert = box.y2 - box.ay - 10;
paths.push(`M${box.x},${box.ay}q-10,0 -10,10v${vert}q0,10 10,10h${box.width}q10,0 10,-10v${-vert}q0,-10 -10,-10`);
// When the repeat is greedy, the loop path gets the preference arrow.
if (this.repeat.greedy) {
paths.push(`M${box.x2 + 10},${box.ay + 15}l5,-5m-5,5l-5,-5`);
}
}
return paths;
},
// Renders label for the loop path indicating how many times the content may // Renders label for the loop path indicating how many times the content may
// be matched. // be matched.
loopLabel() { loopLabel() {

View File

@ -47,6 +47,45 @@ export default {
} }
}, },
// Returns the path spec to render the line that skips over the content for
// fragments that are optionally matched.
skipPath(box) {
var paths = [];
if (this.hasSkip) {
let vert = Math.max(0, box.ay - box.y - 10),
horiz = box.width - 10;
paths.push(`M0,${box.ay}q10,0 10,-10v${-vert}q0,-10 10,-10h${horiz}q10,0 10,10v${vert}q0,10 10,10`);
// When the repeat is not greedy, the skip path gets a preference arrow.
if (!this.greedy) {
paths.push(`M10,${box.ay - 15}l5,5m-5,-5l-5,5`);
}
}
return paths;
},
// Returns the path spec to render the line that repeats the content for
// fragments that are matched more than once.
loopPath(box) {
var paths = [];
if (this.hasLoop) {
let vert = box.y2 - box.ay - 10;
paths.push(`M${box.x},${box.ay}q-10,0 -10,10v${vert}q0,10 10,10h${box.width}q10,0 10,-10v${-vert}q0,-10 -10,-10`);
// When the repeat is greedy, the loop path gets the preference arrow.
if (this.greedy) {
paths.push(`M${box.x2 + 10},${box.ay + 15}l5,-5m-5,5l-5,-5`);
}
}
return paths;
},
setup() { setup() {
this.minimum = this.properties.spec.minimum; this.minimum = this.properties.spec.minimum;
this.maximum = this.properties.spec.maximum; this.maximum = this.properties.spec.maximum;