diff --git a/js/id/renderer/map.js b/js/id/renderer/map.js index 2b98c491a..11b6e2e8a 100644 --- a/js/id/renderer/map.js +++ b/js/id/renderer/map.js @@ -15,9 +15,6 @@ iD.Map = function() { notice, background = iD.Background() .projection(projection), - class_stroke = iD.Style.styleClasses('way line stroke'), - class_casing = iD.Style.styleClasses('way line casing'), - class_area = iD.Style.styleClasses('way area'), transformProp = iD.util.prefixCSSProperty('Transform'), supersurface, surface, defs, tilegroup, r, g, alength; @@ -193,25 +190,30 @@ iD.Map = function() { notice.message(''); } - function drawLines(data, filter, group, class_gen) { + function drawLines(data, filter, group, fixedClasses) { var lines = group.selectAll('path') .filter(filter) .data(data, key); + lines.exit().remove(); - lines.enter().append('path'); + + lines.enter().append('path') + .attr('class', fixedClasses); + lines .order() .attr('d', getline) - .attr('class', class_gen); + .call(iD.Style.styleClasses()); + return lines; } function drawFills(areas, filter) { - drawLines(areas, filter, g.fill, class_area); + drawLines(areas, filter, g.fill, 'way area'); } function drawCasings(ways, filter) { - drawLines(ways, filter, g.casing, class_casing); + drawLines(ways, filter, g.casing, 'way line casing'); } function drawPoints(points, filter) { @@ -242,7 +244,7 @@ iD.Map = function() { } function drawStrokes(ways, filter) { - var strokes = drawLines(ways, filter, g.stroke, class_stroke); + var strokes = drawLines(ways, filter, g.stroke, 'way line stroke'); // Determine the lengths of oneway paths var lengths = {}, diff --git a/js/id/renderer/style.js b/js/id/renderer/style.js index 4c35c5650..99b346329 100644 --- a/js/id/renderer/style.js +++ b/js/id/renderer/style.js @@ -53,15 +53,26 @@ iD.Style.TAG_CLASSES = iD.util.trueObj([ 'landuse', 'building', 'oneway', 'bridge' ]); -iD.Style.styleClasses = function(pre) { - return function(d) { - var tags = d.tags; - var c = pre ? [pre] : []; - for (var k in tags) { - if (!iD.Style.TAG_CLASSES[k]) continue; - c.push('tag-' + k); - c.push('tag-' + k + '-' + tags[k]); - } - return c.join(' '); +iD.Style.styleClasses = function() { + var tagClassRe = /^tag-/; + return function(selection) { + selection.each(function(d) { + var classes, value = this.className; + + if (value.baseVal != null) value = value.baseVal; + + classes = value.trim().split(/\s+/).filter(function(name) { + return name.length && !tagClassRe.test(name); + }); + + var tags = d.tags; + for (var k in tags) { + if (!iD.Style.TAG_CLASSES[k]) continue; + classes.push('tag-' + k); + classes.push('tag-' + k + '-' + tags[k]); + } + + return selection.attr('class', classes.join(' ')); + }); }; }; diff --git a/test/spec/renderer/style.js b/test/spec/renderer/style.js index b48554c84..1fccc9658 100644 --- a/test/spec/renderer/style.js +++ b/test/spec/renderer/style.js @@ -16,22 +16,48 @@ describe('iD.Style', function() { }); describe('#styleClasses', function() { - it('returns an empty string when no classes are present', function() { - var classes = iD.Style.styleClasses(''), - entity = iD.Entity(); - expect(classes(entity)).to.equal(''); + var selection; + + beforeEach(function () { + selection = d3.select(document.createElement('div')); }); - it('returns a string containing predefined classes', function() { - var classes = iD.Style.styleClasses('selected'), - entity = iD.Entity(); - expect(classes(entity)).to.equal('selected'); + it('adds no classes to elements whose datum has no tags', function() { + selection + .datum(iD.Entity()) + .call(iD.Style.styleClasses()); + expect(selection.attr('class')).to.equal(''); }); - it('returns a string containing classes for highway tags', function() { - var classes = iD.Style.styleClasses(''), - entity = iD.Entity({tags: {highway: 'primary'}}); - expect(classes(entity)).to.equal('tag-highway tag-highway-primary'); + it('adds classes for highway tags', function() { + selection + .datum(iD.Entity({tags: {highway: 'primary'}})) + .call(iD.Style.styleClasses()); + expect(selection.attr('class')).to.equal('tag-highway tag-highway-primary'); + }); + + it('removes classes for tags that are no longer present', function() { + selection + .attr('class', 'tag-highway tag-highway-primary') + .datum(iD.Entity()) + .call(iD.Style.styleClasses()); + expect(selection.attr('class')).to.equal(''); + }); + + it('preserves existing non-"tag-"-prefixed classes', function() { + selection + .attr('class', 'selected') + .datum(iD.Entity()) + .call(iD.Style.styleClasses()); + expect(selection.attr('class')).to.equal('selected'); + }); + + it('works on SVG elements', function() { + selection = d3.select(document.createElementNS('http://www.w3.org/2000/svg', 'g')); + selection + .datum(iD.Entity()) + .call(iD.Style.styleClasses()); + expect(selection.attr('class')).to.equal(''); }); }); });