diff --git a/spec/parser/javascript/root_spec.js b/spec/parser/javascript/root_spec.js new file mode 100644 index 0000000..d37f7da --- /dev/null +++ b/spec/parser/javascript/root_spec.js @@ -0,0 +1,172 @@ +import javascript from 'src/js/parser/javascript/parser.js'; +import Snap from 'snapsvg'; +import _ from 'lodash'; +import Q from 'q'; + +describe('parser/javascript/root.js', function() { + + _.forIn({ + 'test': { + flags: [], + regexp: jasmine.objectContaining({ textValue: 'test' }) + }, + '/test/': { + flags: [], + regexp: jasmine.objectContaining({ textValue: 'test' }) + }, + '/test/i': { + flags: ['Ignore Case'], + regexp: jasmine.objectContaining({ textValue: 'test' }) + }, + '/test/g': { + flags: ['Global'], + regexp: jasmine.objectContaining({ textValue: 'test' }) + }, + '/test/m': { + flags: ['Multiline'], + regexp: jasmine.objectContaining({ textValue: 'test' }) + }, + '/test/mgi': { + flags: ['Global', 'Ignore Case', 'Multiline'], + regexp: jasmine.objectContaining({ textValue: 'test' }) + } + }, (content, str) => { + it(`parses "${str}" as a Root`, function() { + var parser = new javascript.Parser(str); + expect(parser.__consume__root()).toEqual(jasmine.objectContaining(content)); + }); + }); + + describe('#_render', function() { + + beforeEach(function() { + this.textElement = jasmine.createSpyObj('text', ['getBBox']); + this.textElement.getBBox.and.returnValue({ + height: 20 + }); + + this.node = new javascript.Parser('test').__consume__root(); + this.node.container = jasmine.createSpyObj('container', [ + 'addClass', + 'text', + 'group', + 'path', + 'circle' + ]); + this.node.container.text.and.returnValue(this.textElement); + this.node.container.group.and.returnValue('group element'); + + this.node.regexp = jasmine.createSpyObj('regexp', [ + 'render', + 'transform', + 'getBBox' + ]); + + this.renderDeferred = Q.defer(); + this.node.regexp.render.and.returnValue(this.renderDeferred.promise); + }); + + it('renders the regexp', function() { + this.node._render(); + expect(this.node.regexp.render).toHaveBeenCalledWith('group element'); + }); + + describe('when there are flags', function() { + + beforeEach(function() { + this.node.flags = ['example', 'flags']; + }); + + it('renders a text element', function() { + this.node._render(); + expect(this.node.container.text).toHaveBeenCalledWith(0, 0, 'Flags: example, flags'); + }); + + }); + + describe('when there are no flags', function() { + + beforeEach(function() { + this.node.flags = []; + }); + + it('does not render a text element', function() { + this.node._render(); + expect(this.node.container.text).not.toHaveBeenCalled(); + }); + + }); + + describe('positioning of elements', function() { + + beforeEach(function() { + this.renderDeferred.resolve(); + + this.node.regexp.getBBox.and.returnValue({ + ax: 1, + ay: 2, + ax2: 3, + x2: 4 + }); + }); + + it('renders a path element to lead in and out of the regexp', function(done) { + this.node._render() + .then(() => { + expect(this.node.container.path).toHaveBeenCalledWith('M1,2H0M3,2H14'); + }) + .finally(done) + .done(); + }); + + it('renders circle elements before and after the regexp', function(done) { + this.node._render() + .then(() => { + expect(this.node.container.circle).toHaveBeenCalledWith(0, 2, 5); + expect(this.node.container.circle).toHaveBeenCalledWith(14, 2, 5); + }) + .finally(done) + .done(); + }); + + describe('when there are flags', function() { + + beforeEach(function() { + this.node.flags = ['example']; + }); + + it('moves the regexp below the flag text', function(done) { + this.node._render() + .then(() => { + expect(this.node.regexp.transform).toHaveBeenCalledWith(Snap.matrix() + .translate(10, 20)); + }) + .finally(done) + .done(); + }); + + }); + + describe('when there are no flags', function() { + + beforeEach(function() { + this.node.flags = []; + }); + + it('positions the regexp', function(done) { + this.node._render() + .then(() => { + expect(this.node.regexp.transform).toHaveBeenCalledWith(Snap.matrix() + .translate(10, 0)); + }) + .finally(done) + .done(); + }); + + }); + + }); + + }); + +}); diff --git a/src/js/parser/javascript/root.js b/src/js/parser/javascript/root.js index 7dfe56e..2d57416 100644 --- a/src/js/parser/javascript/root.js +++ b/src/js/parser/javascript/root.js @@ -3,62 +3,43 @@ import _ from 'lodash'; export default { type: 'root', + flagLabels: { + i: 'Ignore Case', + g: 'Global', + m: 'Multiline' + }, + _render() { - var flagLabels = []; + var flagText; - if (this.flags.global) { - flagLabels.push('Global'); + if (this.flags.length > 0) { + flagText = this.container.text(0, 0, `Flags: ${this.flags.join(', ')}`); } - if (this.flags.ignore_case) { - flagLabels.push('Ignore Case'); - } - if (this.flags.multiline) { - flagLabels.push('Multiline'); - } - - if (flagLabels.length > 0) { - this.flagText = this.container.text(0, 0, `Flags: ${flagLabels.join(', ')}`); - } - - this.start = this.container.circle() - .addClass('pin') - .attr({ r: 5 }); - this.end = this.container.circle() - .addClass('pin') - .attr({ r: 5 }); return this.regexp.render(this.container.group()) .then(() => { - var box, - offset = 0; + var box; - if (this.flagText) { - offset = this.flagText.getBBox().height; + if (flagText) { + this.regexp.transform(Snap.matrix() + .translate(10, flagText.getBBox().height)); + } else { + this.regexp.transform(Snap.matrix() + .translate(10, 0)); } - this.regexp.transform(Snap.matrix() - .translate(10, offset)); - box = this.regexp.getBBox(); - this.start.transform(Snap.matrix() - .translate(0, box.ay)); - this.end.transform(Snap.matrix() - .translate(box.x2 + 10, box.ay)); - - this.container.prepend( - this.container.path(`M${box.ax},${box.ay}H0M${box.ax2},${box.ay}H${box.x2 + 10}`)); + this.container.path(`M${box.ax},${box.ay}H0M${box.ax2},${box.ay}H${box.x2 + 10}`); + this.container.circle(0, box.ay, 5); + this.container.circle(box.x2 + 10, box.ay, 5); }); }, setup() { - var flagsStr = this.properties.flags.textValue; - - this.flags = { - global: /g/.test(flagsStr), - ignore_case: /i/.test(flagsStr), - multiline: /m/.test(flagsStr) - }; + this.flags = _(this.properties.flags.textValue).unique().sort().map(flag => { + return this.flagLabels[flag]; + }).value(); this.regexp = this.properties.regexp } diff --git a/src/sass/svg.scss b/src/sass/svg.scss index 44455bc..1492f8a 100644 --- a/src/sass/svg.scss +++ b/src/sass/svg.scss @@ -14,7 +14,7 @@ path { stroke: $black; } -circle.pin { +circle { fill: $gray; stroke-width: 2px; stroke: $black;