diff --git a/css/60_photos.css b/css/60_photos.css index 8433eb60d..94f86793b 100644 --- a/css/60_photos.css +++ b/css/60_photos.css @@ -24,25 +24,35 @@ overflow: hidden; } +.photo-wrapper .photo-attribution { + width: 100%; + font-size: 10px; + text-align: right; + position: absolute; + bottom: 0; + right: 0; + padding: 4px 2px; + z-index: 10; +} + +.photo-attribution a, +.photo-attribution a:visited, +.photo-attribution span { + padding: 4px 2px; + color: #fff; +} + /* markers and sequences */ .viewfield-group { pointer-events: visible; cursor: pointer; } -.viewfield-group * { - z-index: 50; -} .viewfield-group.selected * { fill: #ffee00 !important; - z-index: 60; } .viewfield-group.hovered * { fill: #eebb00 !important; - z-index: 70; -} -.viewfield-group.highlighted * { - z-index: 60; } .viewfield-group circle { @@ -162,11 +172,18 @@ top: -25px; } #mly .domRenderer .Attribution { - width: 100%; - font-size: 10px; - text-align: right; + /* we will roll our own to avoid async update issues like #4526 */ + display: none; } +.mly-wrapper .photo-attribution a:active, +.mly-wrapper .photo-attribution a:hover { + color: #35af6d; +} + +.mly-wrapper .mapillary-js-dom { + z-index: 9; +} /* OpenStreetCam viewer */ .osc-wrapper { @@ -177,25 +194,8 @@ background-repeat: no-repeat; } -.osc-wrapper .osc-attribution { - width: 100%; - font-size: 10px; - text-align: right; - position: absolute; - bottom: 0; - right: 0; - padding: 4px 2px; - z-index: 10; -} - -.osc-attribution a, -.osc-attribution a:visited, -.osc-attribution span { - padding: 4px 2px; - color: #fff; -} -.osc-attribution a:active, -.osc-attribution a:hover { +.osc-wrapper .photo-attribution a:active, +.osc-wrapper .photo-attribution a:hover { color: #77ddff; } diff --git a/modules/services/mapillary.js b/modules/services/mapillary.js index b67d02365..cb06b4edd 100644 --- a/modules/services/mapillary.js +++ b/modules/services/mapillary.js @@ -172,6 +172,7 @@ function loadNextTilePage(which, currZoom, url, tile) { key: feature.properties.key, ca: feature.properties.ca, captured_at: feature.properties.captured_at, + captured_by: feature.properties.username, pano: feature.properties.pano }; cache.forImageKey[d.key] = d; // cache imageKey -> image @@ -424,15 +425,21 @@ export default { loadViewer: function(context) { - // add mly-wrapper for viewer-js - d3_select('#photoviewer').selectAll('.mly-wrapper') - .data([0]) - .enter() + // add mly-wrapper + var wrap = d3_select('#photoviewer').selectAll('.mly-wrapper') + .data([0]); + + var wrapEnter = wrap.enter() .append('div') .attr('id', 'mly') .attr('class', 'photo-wrapper mly-wrapper') .classed('hide', true); + wrapEnter + .append('div') + .attr('class', 'photo-attribution fillD'); + + // load mapillary-viewercss d3_select('head').selectAll('#mapillary-viewercss') .data([0]) @@ -586,25 +593,44 @@ export default { }); }); - if (!d) return this; + var wrap = d3_select('#photoviewer .mly-wrapper'); + var attribution = wrap.selectAll('.photo-attribution').html(''); - // if viewer is just starting up, attribution might not be available yet - var attribution = d3_select('.mapillary-js-dom .Attribution'); - var timestamp = localeTimestamp(d.captured_at); - var capturedAt = attribution.selectAll('.captured-at'); - if (capturedAt.empty()) { - capturedAt = attribution - .insert('span', ':last-child') - .attr('class', 'captured-at'); + if (d) { + if (d.captured_by) { + attribution + .append('a') + .attr('class', 'captured_by') + .attr('target', '_blank') + .attr('href', 'https://www.mapillary.com/app/user/' + encodeURIComponent(d.captured_by)) + .text('@' + d.captured_by); + + attribution + .append('span') + .text('|'); + } + + if (d.captured_at) { + attribution + .append('span') + .attr('class', 'captured_at') + .text(localeTimestamp(d.captured_at)); + + attribution + .append('span') + .text('|'); + } attribution - .insert('span', ':last-child') - .text('|'); - } - capturedAt - .text(timestamp); + .append('a') + .attr('class', 'image_link') + .attr('target', '_blank') + .attr('href', 'https://www.mapillary.com/app/?pKey=' + encodeURIComponent(d.key) + + '&focus=photo&lat=' + d.loc[1] + '&lng=' + d.loc[0] + '&z=17') + .text('mapillary.com'); - this.updateDetections(d); + this.updateDetections(d); + } return this; }, diff --git a/modules/services/openstreetcam.js b/modules/services/openstreetcam.js index d0f35a020..fd3f81e09 100644 --- a/modules/services/openstreetcam.js +++ b/modules/services/openstreetcam.js @@ -306,7 +306,7 @@ export default { wrapEnter .append('div') - .attr('class', 'osc-attribution fillD'); + .attr('class', 'photo-attribution fillD'); var controlsEnter = wrapEnter .append('div') @@ -427,14 +427,14 @@ export default { .style('transform', 'rotate(' + r + 'deg)') .attr('src', apibase + '/' + d.imagePath); - var attribution = wrap.selectAll('.osc-attribution').html(''); + var attribution = wrap.selectAll('.photo-attribution').html(''); if (d.captured_by) { attribution .append('a') .attr('class', 'captured_by') .attr('target', '_blank') - .attr('href', apibase + '/user/' + d.captured_by) + .attr('href', 'http://openstreetcam.org/user/' + encodeURIComponent(d.captured_by)) .text('@' + d.captured_by); attribution @@ -457,7 +457,7 @@ export default { .append('a') .attr('class', 'image_link') .attr('target', '_blank') - .attr('href', apibase + '/details/' + d.sequence_id + '/' + d.sequence_index) + .attr('href', 'http://openstreetcam.org/details/' + d.sequence_id + '/' + d.sequence_index) .text('openstreetcam.org'); } return this; diff --git a/test/spec/services/mapillary.js b/test/spec/services/mapillary.js index 8fb7aef15..26d674bc6 100644 --- a/test/spec/services/mapillary.js +++ b/test/spec/services/mapillary.js @@ -66,7 +66,7 @@ describe('iD.serviceMapillary', function() { describe('#reset', function() { it('resets cache and image', function() { mapillary.cache().foo = 'bar'; - mapillary.selectImage({key: 'baz'}); + mapillary.selectImage({ key: 'baz', loc: [10,0] }); mapillary.reset(); expect(mapillary.cache()).to.not.have.property('foo'); @@ -432,8 +432,9 @@ describe('iD.serviceMapillary', function() { describe('#selectImage', function() { it('gets and sets the selected image', function() { - mapillary.selectImage('foo'); - expect(mapillary.getSelectedImage()).to.eql('foo'); + var d = { key: 'baz', loc: [10,0] }; + mapillary.selectImage(d); + expect(mapillary.getSelectedImage()).to.eql(d); }); });