From 64bfa54f986e08496deb6d0fce6459344736a874 Mon Sep 17 00:00:00 2001 From: David Phan Date: Fri, 2 Sep 2022 10:48:09 -0700 Subject: [PATCH 01/33] created and formatted popover in audit page with limited info and no clipboard copying (yet) --- Gruntfile.js | 3 +- .../SVLabel/css/svl-info-popover.css | 18 +++ public/javascripts/SVLabel/css/svl.css | 11 +- .../javascripts/SVLabel/src/SVLabel/Main.js | 3 + public/javascripts/common/GSVInfoPopOver.js | 103 ++++++++++++++++++ 5 files changed, 135 insertions(+), 3 deletions(-) create mode 100644 public/javascripts/SVLabel/css/svl-info-popover.css create mode 100644 public/javascripts/common/GSVInfoPopOver.js diff --git a/Gruntfile.js b/Gruntfile.js index 3b39dca940..fe5806f030 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -32,7 +32,8 @@ module.exports = function(grunt) { 'public/javascripts/common/UtilitiesMath.js', 'public/javascripts/common/UtilitiesPanomarker.js', 'public/javascripts/common/UtilitiesShape.js', - 'public/javascripts/common/UtilitiesSidewalk.js' + 'public/javascripts/common/UtilitiesSidewalk.js', + 'public/javascripts/common/GSVInfoPopOver.js' ], dest: 'public/javascripts/SVLabel/build/SVLabel.js' }, diff --git a/public/javascripts/SVLabel/css/svl-info-popover.css b/public/javascripts/SVLabel/css/svl-info-popover.css new file mode 100644 index 0000000000..42f1e98a16 --- /dev/null +++ b/public/javascripts/SVLabel/css/svl-info-popover.css @@ -0,0 +1,18 @@ +#info-button { + margin-left: 5px; + max-height: 100%; +} + +.info-key { + font-weight: bold; +} + +.info-list-item { + display: flex; + justify-content: space-between; +} + +.popover { + width: 350px; + max-width: 350px; +} diff --git a/public/javascripts/SVLabel/css/svl.css b/public/javascripts/SVLabel/css/svl.css index dcace88c06..5d24a80919 100644 --- a/public/javascripts/SVLabel/css/svl.css +++ b/public/javascripts/SVLabel/css/svl.css @@ -133,12 +133,19 @@ input[type="radio"] { } #svl-panorama-date-holder { + display: flex; + justify-content: flex-start; + height: 29px; position: absolute; - bottom: 3px; - left: 75px; + bottom: 0px; + left: 69px; z-index: 1; font-family: sans-serif; font-size: 15px; text-shadow: 0.5px 0.5px 0.5px rgba(0, 0, 0, 0.5); color: white; } + +#svl-panorama-date { + padding: 5px; +} diff --git a/public/javascripts/SVLabel/src/SVLabel/Main.js b/public/javascripts/SVLabel/src/SVLabel/Main.js index de7fc092fe..c57224e09e 100644 --- a/public/javascripts/SVLabel/src/SVLabel/Main.js +++ b/public/javascripts/SVLabel/src/SVLabel/Main.js @@ -156,6 +156,8 @@ function Main (params) { svl.modalSkip = new ModalSkip(svl.form, svl.onboardingModel, svl.ribbon, svl.taskContainer, svl.tracker, svl.ui.leftColumn, svl.ui.modalSkip); svl.modalExample = new ModalExample(svl.modalModel, svl.onboardingModel, svl.ui.modalExample); + var infoPopOver = new GSVInfoPopOver(svl.ui.dateHolder, svl.panorama, svl.map.getPosition, svl.map.getPanoId); + // Survey for select users svl.surveyModalContainer = $("#survey-modal-container").get(0); @@ -424,6 +426,7 @@ function Main (params) { svl.ui.googleMaps = {}; svl.ui.googleMaps.holder = $("#google-maps-holder"); svl.ui.googleMaps.overlay = $("#google-maps-overlay"); + svl.ui.dateHolder = $("#svl-panorama-date-holder") // Status holder svl.ui.status = {}; diff --git a/public/javascripts/common/GSVInfoPopOver.js b/public/javascripts/common/GSVInfoPopOver.js new file mode 100644 index 0000000000..c3c11e5bdf --- /dev/null +++ b/public/javascripts/common/GSVInfoPopOver.js @@ -0,0 +1,103 @@ +/** + * An object for displaying additional locational info on any GSV pane. + * + * @param svl SVL object + * @param {HTMLElement} container Element where the info button will be displayed + * @returns {GSVInfoPopOver} The info button and popover object + * @constructor + */ +function GSVInfoPopOver (container, panorama, coordCallBack, panoIdCallBack, ) { + let self = this; + + function _init() { + let popoverContent = document.createElement('div'); + + let dataList = document.createElement('ul'); + dataList.classList.add('list-group', 'list-group-flush'); + + // Add in container for each info type to the popover + addListElement('Latitude'); + addListElement('Longitude'); + addListElement('PanoID'); + // TODO: add street edge ID and region ID + popoverContent.appendChild(dataList); + + // Create info button and add popover attributes + let infoButton = document.createElement('img'); + infoButton.id = 'info-button'; + infoButton.src = '/assets/javascripts/SVLabel/img/misc/info_button.png'; + infoButton.setAttribute('data-toggle', 'popover'); + infoButton.setAttribute('data-placement', 'top'); + infoButton.setAttribute('title', 'Details'); + infoButton.setAttribute('data-content', popoverContent.innerHTML); + + // Makes the popover a dismissable popover + infoButton.setAttribute('tabindex', 0); + infoButton.setAttribute('data-trigger', 'focus'); + + container.append(infoButton); + + // Enable popover + $(function () { + $('#info-button').popover({ + html: true, + container: $('#view-control-layer'), + trigger: 'focus' + }); + }); + + // Open popover on click + $('#info-button').on('click', updateVals); + } + + /** + * Update the values within the popover + */ + function updateVals() { + const coords = coordCallBack(); + const panoId = panoIdCallBack(); + + function changeVals(key, val) { + let valSpan = document.getElementById(`${key}-value`) + valSpan.textContent = val; + } + + changeVals('Latitude', coords.lat); + changeVals('Longitude', coords.lng); + changeVals('PanoID', panoId); + // TODO: add streetEdgeId, regionId + + // Fixes Bootstrap popover positioning issues, has to be done AFTER popover loads, + // thus cannot be put into css file + $('.popover').css('left', '-10px'); + } + + /** + * Creates a key-value pair display within the popover + * @param key Key name of the key-value pair + */ + function addListElement(key) { + let listElement = document.createElement('li'); + listElement.classList.add('list-group-item', 'info-list-item'); + + let keySpan = document.createElement('span'); + keySpan.classList.add('info-key'); + keySpan.textContent = key; + listElement.appendChild(keySpan); + + let valSpan = document.createElement('span'); + valSpan.classList.add('info-val'); + valSpan.textContent = '-'; + valSpan.id = `${key}-value` + // TODO: create copy to clipboard feature + + listElement.appendChild(valSpan); + dataList.appendChild(listElement); + } + + _init(); + + self.updateVals = updateVals; + + return self; +} From 3eb55afe0bd0268f9a62e9da3ec44e2255211306 Mon Sep 17 00:00:00 2001 From: David Phan Date: Wed, 7 Sep 2022 10:50:08 -0700 Subject: [PATCH 02/33] popover formatted and clipboard + GSV links added --- .../SVLabel/css/svl-info-popover.css | 20 +++++ .../SVLabel/img/misc/clipboard_copy.png | Bin 0 -> 570 bytes .../javascripts/SVLabel/src/SVLabel/Main.js | 2 +- public/javascripts/common/GSVInfoPopOver.js | 82 +++++++++++++----- 4 files changed, 83 insertions(+), 21 deletions(-) create mode 100644 public/javascripts/SVLabel/img/misc/clipboard_copy.png diff --git a/public/javascripts/SVLabel/css/svl-info-popover.css b/public/javascripts/SVLabel/css/svl-info-popover.css index 42f1e98a16..c812eaa64d 100644 --- a/public/javascripts/SVLabel/css/svl-info-popover.css +++ b/public/javascripts/SVLabel/css/svl-info-popover.css @@ -16,3 +16,23 @@ width: 350px; max-width: 350px; } + +.popover-title { + display: flex; + justify-content: space-between; + height: 36px; +} + +.popover-content { + display: flex; + flex-direction: column; + justify-content: center; +} +#gsv-link { + text-align: center; +} + +#clipboard { + max-height: 100%; + cursor: pointer; +} \ No newline at end of file diff --git a/public/javascripts/SVLabel/img/misc/clipboard_copy.png b/public/javascripts/SVLabel/img/misc/clipboard_copy.png new file mode 100644 index 0000000000000000000000000000000000000000..3887dbf6a6df31cc063edf5ec72bde95cfb05561 GIT binary patch literal 570 zcmV-A0>%A_P)~1AXX+e{QXiv66MJTqV>mY1GE1B9n zJ05)7gOBg--Mjbr9Bc7#Im$r`LDt;*g|IDg@w{)makS0AP|F0In|v_tOV; z0YE4?N(C&=+$8x@#OI>ts#kPBZb2DFU%qOShW>|lYrQS|>%h7@*%bThz##*N3>-4B z%?w0I;$$;HK)Q1Wq9k$VQw;%t!erwNZ0b-p(;c}S%Y&UeASi_}&Y5{9t{d+>18?0o zuO6?T{1#Y}QUK_j^&QjAJH4W(P;itAATa@e`U?&_XFX#g7DFij5CumW>^w(6>OD#S z*~^CivG>W827t@4Jg6$Mt}X|$1P{=7l~wDa=%sPlpWre608KL3yp~|PPXGV_07*qo IM6N<$f|2v~mjD0& literal 0 HcmV?d00001 diff --git a/public/javascripts/SVLabel/src/SVLabel/Main.js b/public/javascripts/SVLabel/src/SVLabel/Main.js index c57224e09e..02303030a6 100644 --- a/public/javascripts/SVLabel/src/SVLabel/Main.js +++ b/public/javascripts/SVLabel/src/SVLabel/Main.js @@ -156,7 +156,7 @@ function Main (params) { svl.modalSkip = new ModalSkip(svl.form, svl.onboardingModel, svl.ribbon, svl.taskContainer, svl.tracker, svl.ui.leftColumn, svl.ui.modalSkip); svl.modalExample = new ModalExample(svl.modalModel, svl.onboardingModel, svl.ui.modalExample); - var infoPopOver = new GSVInfoPopOver(svl.ui.dateHolder, svl.panorama, svl.map.getPosition, svl.map.getPanoId); + var infoPopOver = new GSVInfoPopOver(svl.ui.dateHolder, svl.panorama, svl.map); // Survey for select users svl.surveyModalContainer = $("#survey-modal-container").get(0); diff --git a/public/javascripts/common/GSVInfoPopOver.js b/public/javascripts/common/GSVInfoPopOver.js index c3c11e5bdf..ce05d52c47 100644 --- a/public/javascripts/common/GSVInfoPopOver.js +++ b/public/javascripts/common/GSVInfoPopOver.js @@ -6,45 +6,71 @@ * @returns {GSVInfoPopOver} The info button and popover object * @constructor */ -function GSVInfoPopOver (container, panorama, coordCallBack, panoIdCallBack, ) { +function GSVInfoPopOver (container, panorama, map) { let self = this; function _init() { let popoverContent = document.createElement('div'); + // Create popover title bar + let titleBox = document.createElement('div'); + + let title = document.createElement('span'); + title.textContent = 'Details' + titleBox.appendChild(title); + + let clipboard = document.createElement('img'); + clipboard.src = '/assets/javascripts/SVLabel/img/misc/clipboard_copy.png'; + clipboard.id = 'clipboard'; + + clipboard.setAttribute('data-toggle', 'tooltip'); + clipboard.setAttribute('data-placement', 'top'); + clipboard.setAttribute('trigger', 'click'); + clipboard.setAttribute('tabindex', 0); + clipboard.setAttribute('title', 'Copied!'); + + titleBox.appendChild(clipboard); + + + // Create popover content let dataList = document.createElement('ul'); dataList.classList.add('list-group', 'list-group-flush'); // Add in container for each info type to the popover - addListElement('Latitude'); - addListElement('Longitude'); - addListElement('PanoID'); + addListElement('Latitude', dataList); + addListElement('Longitude', dataList); + addListElement('PanoID', dataList); // TODO: add street edge ID and region ID popoverContent.appendChild(dataList); + // Create link to separate GSV + let linkGSV = document.createElement('a'); + linkGSV.id = 'gsv-link' + linkGSV.textContent = 'View in Google Street View'; + popoverContent.appendChild(linkGSV); + // Create info button and add popover attributes let infoButton = document.createElement('img'); infoButton.id = 'info-button'; infoButton.src = '/assets/javascripts/SVLabel/img/misc/info_button.png'; infoButton.setAttribute('data-toggle', 'popover'); infoButton.setAttribute('data-placement', 'top'); - infoButton.setAttribute('title', 'Details'); + infoButton.setAttribute('title', titleBox.innerHTML); infoButton.setAttribute('data-content', popoverContent.innerHTML); // Makes the popover a dismissable popover - infoButton.setAttribute('tabindex', 0); - infoButton.setAttribute('data-trigger', 'focus'); + // infoButton.setAttribute('tabindex', 0); + // infoButton.setAttribute('data-trigger', 'focus'); container.append(infoButton); - // Enable popover - $(function () { - $('#info-button').popover({ - html: true, - container: $('#view-control-layer'), - trigger: 'focus' - }); + // Enable popovers/tooltips and set options + $('#info-button').popover({ + html: true, + container: $('#view-control-layer'), + // trigger: 'focus' }); + $('#clipboard').tooltip(); // Open popover on click $('#info-button').on('click', updateVals); @@ -54,19 +80,36 @@ function GSVInfoPopOver (container, panorama, coordCallBack, panoIdCallBack, ) { * Update the values within the popover */ function updateVals() { - const coords = coordCallBack(); - const panoId = panoIdCallBack(); + const coords = map.getPosition(); + const panoId = map.getPanoId(); + const pov = map.getPov(); function changeVals(key, val) { let valSpan = document.getElementById(`${key}-value`) valSpan.textContent = val; } - changeVals('Latitude', coords.lat); - changeVals('Longitude', coords.lng); + changeVals('Latitude', coords.lat + '°'); + changeVals('Longitude', coords.lng + '°'); changeVals('PanoID', panoId); // TODO: add streetEdgeId, regionId + // Create GSV link + $('#gsv-link').attr('href', `https://www.google.com/maps/@?api=1&map_action=pano&viewpoint=${coords.lat}%2C${coords.lng}&heading=${pov.heading}&pitch=${pov.pitch}`); + $('#gsv-link').attr('target', '_blank'); + + // Copy to clipboard + $('#clipboard').click(() => { + $('#clipboard').tooltip('enable'); + $('#clipboard').tooltip('show'); + navigator.clipboard.writeText( + `Latitude: ${coords.lat}°\nLongitude: ${coords.lng}°\nPanoID: ${panoId}` + ); + }); + $('#clipboard').on('mouseout', () => { + $('#clipboard').tooltip('disable'); + }); + // Fixes Bootstrap popover positioning issues, has to be done AFTER popover loads, // thus cannot be put into css file $('.popover').css('left', '-10px'); @@ -76,7 +119,7 @@ function GSVInfoPopOver (container, panorama, coordCallBack, panoIdCallBack, ) { * Creates a key-value pair display within the popover * @param key Key name of the key-value pair */ - function addListElement(key) { + function addListElement(key, dataList) { let listElement = document.createElement('li'); listElement.classList.add('list-group-item', 'info-list-item'); @@ -89,7 +132,6 @@ function GSVInfoPopOver (container, panorama, coordCallBack, panoIdCallBack, ) { valSpan.classList.add('info-val'); valSpan.textContent = '-'; valSpan.id = `${key}-value` - // TODO: create copy to clipboard feature listElement.appendChild(valSpan); dataList.appendChild(listElement); From b7927d2a613c5feff9994b4d137af010dcf16388 Mon Sep 17 00:00:00 2001 From: David Phan Date: Wed, 7 Sep 2022 15:44:08 -0700 Subject: [PATCH 03/33] popover is dismissable by click, all functionality and styling completed, only on SVL and not all info --- .../SVLabel/css/svl-info-popover.css | 9 ++- public/javascripts/common/GSVInfoPopOver.js | 80 ++++++++++++------- 2 files changed, 60 insertions(+), 29 deletions(-) diff --git a/public/javascripts/SVLabel/css/svl-info-popover.css b/public/javascripts/SVLabel/css/svl-info-popover.css index c812eaa64d..de5d2b04ff 100644 --- a/public/javascripts/SVLabel/css/svl-info-popover.css +++ b/public/javascripts/SVLabel/css/svl-info-popover.css @@ -30,9 +30,16 @@ } #gsv-link { text-align: center; + width: fit-content; + margin-left: auto; + margin-right: auto; } #clipboard { max-height: 100%; cursor: pointer; -} \ No newline at end of file +} + +#clipboard:active { + opacity: 50%; +} diff --git a/public/javascripts/common/GSVInfoPopOver.js b/public/javascripts/common/GSVInfoPopOver.js index ce05d52c47..156acfe766 100644 --- a/public/javascripts/common/GSVInfoPopOver.js +++ b/public/javascripts/common/GSVInfoPopOver.js @@ -1,25 +1,27 @@ /** - * An object for displaying additional locational info on any GSV pane. + * An object for creating a popover which displays additional locational info on any GSV pane. * - * @param svl SVL object * @param {HTMLElement} container Element where the info button will be displayed - * @returns {GSVInfoPopOver} The info button and popover object - * @constructor + * @param {StreetViewPanorama} panorama Panorama object + * @param {svl.map} map Map object + * @returns {GSVInfoPopOver} Popover object, which holds the popover title html, content html, info button html, and + * update values method */ function GSVInfoPopOver (container, panorama, map) { let self = this; function _init() { - let popoverContent = document.createElement('div'); // Create popover title bar - let titleBox = document.createElement('div'); + self.titleBox = document.createElement('div'); let title = document.createElement('span'); + title.classList.add('popover-element'); title.textContent = 'Details' - titleBox.appendChild(title); + self.titleBox.appendChild(title); let clipboard = document.createElement('img'); + clipboard.classList.add('popover-element'); clipboard.src = '/assets/javascripts/SVLabel/img/misc/clipboard_copy.png'; clipboard.id = 'clipboard'; @@ -29,53 +31,74 @@ function GSVInfoPopOver (container, panorama, map) { clipboard.setAttribute('tabindex', 0); clipboard.setAttribute('title', 'Copied!'); - titleBox.appendChild(clipboard); + self.titleBox.appendChild(clipboard); // Create popover content + self.popoverContent = document.createElement('div'); + + // Add in container for each info type to the popover let dataList = document.createElement('ul'); dataList.classList.add('list-group', 'list-group-flush'); - // Add in container for each info type to the popover addListElement('Latitude', dataList); addListElement('Longitude', dataList); addListElement('PanoID', dataList); // TODO: add street edge ID and region ID - popoverContent.appendChild(dataList); + + self.popoverContent.appendChild(dataList); // Create link to separate GSV let linkGSV = document.createElement('a'); + linkGSV.classList.add('popover-element'); linkGSV.id = 'gsv-link' linkGSV.textContent = 'View in Google Street View'; - popoverContent.appendChild(linkGSV); + self.popoverContent.appendChild(linkGSV); + // Create info button and add popover attributes - let infoButton = document.createElement('img'); - infoButton.id = 'info-button'; - infoButton.src = '/assets/javascripts/SVLabel/img/misc/info_button.png'; - infoButton.setAttribute('data-toggle', 'popover'); - infoButton.setAttribute('data-placement', 'top'); - infoButton.setAttribute('title', titleBox.innerHTML); - infoButton.setAttribute('data-content', popoverContent.innerHTML); + self.infoButton = document.createElement('img'); + self.infoButton.classList.add('popover-element'); + self.infoButton.id = 'info-button'; + self.infoButton.src = '/assets/javascripts/SVLabel/img/misc/info_button.png'; + self.infoButton.setAttribute('data-toggle', 'popover'); + self.infoButton.setAttribute('data-placement', 'top'); + self.infoButton.setAttribute('title', self.titleBox.innerHTML); + self.infoButton.setAttribute('data-content', self.popoverContent.innerHTML); - // Makes the popover a dismissable popover - // infoButton.setAttribute('tabindex', 0); - // infoButton.setAttribute('data-trigger', 'focus'); + container.append(self.infoButton); - container.append(infoButton); // Enable popovers/tooltips and set options $('#info-button').popover({ html: true, container: $('#view-control-layer'), - // trigger: 'focus' }); $('#clipboard').tooltip(); - // Open popover on click + // Update popover everytime it opens $('#info-button').on('click', updateVals); + + // Dismiss popover on clicking outside of popover + $('#info-button').on('shown.bs.popover', () => { + console.log('popover shown!'); + $('.popover-title').addClass('popover-element'); + $('.popover-content').addClass('popover-element'); + }); + $('html').on('click', (e) => { + let tar = $(e.target); + console.log(tar[0]); + if (tar[0].className.indexOf('popover-element') === -1) { + $('#info-button').popover('hide'); + } + }); + // Dismiss popover whenver panorama changes + panorama.addListener('pano_changed', () => { + $('#info-button').popover('hide'); + }) } + /** * Update the values within the popover */ @@ -117,19 +140,20 @@ function GSVInfoPopOver (container, panorama, map) { /** * Creates a key-value pair display within the popover - * @param key Key name of the key-value pair + * @param {String} key Key name of the key-value pair + * @param {HTMLElement} dataList List element container to add list item to */ function addListElement(key, dataList) { let listElement = document.createElement('li'); - listElement.classList.add('list-group-item', 'info-list-item'); + listElement.classList.add('list-group-item', 'info-list-item', 'popover-element'); let keySpan = document.createElement('span'); - keySpan.classList.add('info-key'); + keySpan.classList.add('info-key', 'popover-element'); keySpan.textContent = key; listElement.appendChild(keySpan); let valSpan = document.createElement('span'); - valSpan.classList.add('info-val'); + valSpan.classList.add('info-val', 'popover-element'); valSpan.textContent = '-'; valSpan.id = `${key}-value` From 11adf6d0426ccdecb2b8a94689f4747291b17984 Mon Sep 17 00:00:00 2001 From: David Phan Date: Wed, 7 Sep 2022 16:46:14 -0700 Subject: [PATCH 04/33] fixed info button --- .../javascripts/SVLabel/css/svl-info-popover.css | 2 +- .../javascripts/SVLabel/img/misc/gsv_info_btn.png | Bin 0 -> 711 bytes public/javascripts/common/GSVInfoPopOver.js | 8 ++++---- 3 files changed, 5 insertions(+), 5 deletions(-) create mode 100644 public/javascripts/SVLabel/img/misc/gsv_info_btn.png diff --git a/public/javascripts/SVLabel/css/svl-info-popover.css b/public/javascripts/SVLabel/css/svl-info-popover.css index de5d2b04ff..cc3bd8676d 100644 --- a/public/javascripts/SVLabel/css/svl-info-popover.css +++ b/public/javascripts/SVLabel/css/svl-info-popover.css @@ -1,5 +1,5 @@ #info-button { - margin-left: 5px; + margin: 5px; max-height: 100%; } diff --git a/public/javascripts/SVLabel/img/misc/gsv_info_btn.png b/public/javascripts/SVLabel/img/misc/gsv_info_btn.png new file mode 100644 index 0000000000000000000000000000000000000000..f1a61ded415ca87aeb4a2ce19d203aa9731ed4e7 GIT binary patch literal 711 zcmV;&0yzDNP)9!@%0`D3TZ3l6@=gR z&OP~l=bU$P-xKyxM|3ENv8@U>fEpl}JIV+wTh-YLSEpXbyML5o$X>xvbU5G`uh$~? z1l;|K04&G{$I|s?@Y#1?gS)Yz77;rERQZ65wTaN4>hGG#4?6h|;aKva2r1yy0pS2A zf!lTU4QmVYb6<9XyB&mjUp5)lnPSsJ$f}yQ@x;^VU4u|`IABcnD?VfC4&OpmNshnw zGuiO6?!}4ck5>(Vk!+tI96(i3w45%gE1W-Z0O^Ph1=ZMP{(m%u#ek>QsWB?qn@0@? z5O9sLt*(eP`8C~k?Fx-oFCzkrnV%$6zV9F>y>1k0ebZ3L&Av8xu1xrLx=}dmm-X?} zXYMCP4g$^Xd?a)My3IS~DX6 z;n<5&gwDMZ&s0^?(|L!g%F_k$jji7djJ{+2*H$TuSE+%>gYCP>wQ*o`pK8hs?rI%} zKFGVS!?9!|B597`x)#;eu|ySf(a#qd2l$X6&j9B{;IQITeW t^EUU}Vj!ciB&xGnb*JABK3OTn_zM;6$RM0UWxW6Z002ovPDHLkV1govH6;K5 literal 0 HcmV?d00001 diff --git a/public/javascripts/common/GSVInfoPopOver.js b/public/javascripts/common/GSVInfoPopOver.js index 156acfe766..ca9d841059 100644 --- a/public/javascripts/common/GSVInfoPopOver.js +++ b/public/javascripts/common/GSVInfoPopOver.js @@ -29,7 +29,7 @@ function GSVInfoPopOver (container, panorama, map) { clipboard.setAttribute('data-placement', 'top'); clipboard.setAttribute('trigger', 'click'); clipboard.setAttribute('tabindex', 0); - clipboard.setAttribute('title', 'Copied!'); + clipboard.setAttribute('title', 'Details copied to clipboard!'); self.titleBox.appendChild(clipboard); @@ -60,7 +60,7 @@ function GSVInfoPopOver (container, panorama, map) { self.infoButton = document.createElement('img'); self.infoButton.classList.add('popover-element'); self.infoButton.id = 'info-button'; - self.infoButton.src = '/assets/javascripts/SVLabel/img/misc/info_button.png'; + self.infoButton.src = '/assets/javascripts/SVLabel/img/misc/gsv_info_btn.png'; self.infoButton.setAttribute('data-toggle', 'popover'); self.infoButton.setAttribute('data-placement', 'top'); self.infoButton.setAttribute('title', self.titleBox.innerHTML); @@ -85,7 +85,7 @@ function GSVInfoPopOver (container, panorama, map) { $('.popover-title').addClass('popover-element'); $('.popover-content').addClass('popover-element'); }); - $('html').on('click', (e) => { + $('html').on('mousedown', (e) => { let tar = $(e.target); console.log(tar[0]); if (tar[0].className.indexOf('popover-element') === -1) { @@ -135,7 +135,7 @@ function GSVInfoPopOver (container, panorama, map) { // Fixes Bootstrap popover positioning issues, has to be done AFTER popover loads, // thus cannot be put into css file - $('.popover').css('left', '-10px'); + $('.popover').css('left', '-17px'); } /** From 317154072538fd12699751827290f2d5d9a318d6 Mon Sep 17 00:00:00 2001 From: David Phan Date: Wed, 21 Sep 2022 12:42:15 -0700 Subject: [PATCH 05/33] Finalized GSVIinfoPopover js class and completed region id addition for audit page. Audit page is completely done, moving on to next GSV pane --- app/models/audit/AuditTaskTable.scala | 27 +++++--- .../javascripts/SVLabel/src/SVLabel/Main.js | 2 +- .../SVLabel/src/SVLabel/task/Task.js | 6 ++ public/javascripts/common/GSVInfoPopOver.js | 67 ++++++++++++++----- 4 files changed, 76 insertions(+), 26 deletions(-) diff --git a/app/models/audit/AuditTaskTable.scala b/app/models/audit/AuditTaskTable.scala index bd4ad3e48e..2f6aed0261 100644 --- a/app/models/audit/AuditTaskTable.scala +++ b/app/models/audit/AuditTaskTable.scala @@ -11,6 +11,7 @@ import models.daos.slick.DBTableDefinitions.{DBUser, UserTable} import models.label.{LabelTable, LabelTypeTable} import models.street.StreetEdgePriorityTable import models.user.{User, UserRoleTable, UserStatTable} +import models.region.RegionTable import play.api.libs.json._ import play.api.Play.current import play.extras.geojson @@ -18,7 +19,7 @@ import scala.slick.lifted.ForeignKeyQuery import scala.slick.jdbc.{GetResult, StaticQuery => Q} case class AuditTask(auditTaskId: Int, amtAssignmentId: Option[Int], userId: String, streetEdgeId: Int, taskStart: Timestamp, taskEnd: Option[Timestamp], completed: Boolean, currentLat: Float, currentLng: Float, startPointReversed: Boolean) -case class NewTask(edgeId: Int, geom: LineString, +case class NewTask(edgeId: Int, geom: LineString, regionId: Int, currentLng: Float, currentLat: Float, x1: Float, y1: Float, x2: Float, y2: Float, startPointReversed: Boolean, // Did we start at x1,y1 instead of x2,y2? taskStart: Timestamp, @@ -35,6 +36,7 @@ case class NewTask(edgeId: Int, geom: LineString, val linestring: geojson.LineString[geojson.LatLng] = geojson.LineString(latlngs) val properties = Json.obj( "street_edge_id" -> edgeId, + "region_id" -> regionId, "current_lng" -> currentLng, "current_lat" -> currentLat, "x1" -> x1, @@ -106,6 +108,7 @@ object AuditTaskTable { implicit val newTaskConverter = GetResult[NewTask](r => { val edgeId = r.nextInt val geom = r.nextGeometry[LineString] + val regionId = r.nextInt val currentLng = r.nextFloat val currentLat = r.nextFloat val x1 = r.nextFloat @@ -117,7 +120,7 @@ object AuditTaskTable { val completedByAnyUser = r.nextBoolean val priority = r.nextDouble val completed = r.nextBooleanOption.getOrElse(false) - NewTask(edgeId, geom, currentLng, currentLat, x1, y1, x2, y2, startPointReversed, taskStart, completedByAnyUser, priority, completed) + NewTask(edgeId, geom, regionId, currentLng, currentLat, x1, y1, x2, y2, startPointReversed, taskStart, completedByAnyUser, priority, completed) }) val db = play.api.db.slick.DB @@ -126,6 +129,7 @@ object AuditTaskTable { val streetEdges = TableQuery[StreetEdgeTable] val streetEdgePriorities = TableQuery[StreetEdgePriorityTable] val users = TableQuery[UserTable] + val regions = TableQuery[StreetEdgeRegionTable] val completedTasks = auditTasks.filter(_.completed) val streetEdgesWithoutDeleted = streetEdges.filterNot(_.deleted) @@ -364,9 +368,10 @@ object AuditTaskTable { // Join with other queries to get completion count and priority for each of the street edges. val edges = for { se <- streetEdgesWithoutDeleted if se.streetEdgeId === streetEdgeId + re <- regions if se.streetEdgeId === re.streetEdgeId scau <- streetCompletedByAnyUser if se.streetEdgeId === scau._1 sep <- streetEdgePriorities if scau._1 === sep.streetEdgeId - } yield (se.streetEdgeId, se.geom, se.x2, se.y2, se.x1, se.y1, se.x2, se.y2, false, timestamp, scau._2, sep.priority, userCompleted) + } yield (se.streetEdgeId, se.geom, re.regionId, se.x2, se.y2, se.x1, se.y1, se.x2, se.y2, false, timestamp, scau._2, sep.priority, userCompleted) NewTask.tupled(edges.first) } @@ -384,15 +389,16 @@ object AuditTaskTable { val possibleTasks = for { sp <- streetEdgePriorities se <- edgesInRegion if sp.streetEdgeId === se.streetEdgeId + re <- regions if se.streetEdgeId === re.streetEdgeId sc <- streetCompletedByAnyUser if se.streetEdgeId === sc._1 - } yield (se.streetEdgeId, se.geom, se.x2, se.y2, se.x1, se.y1, se.x2, se.y2, false, timestamp, sc._2, sp.priority, false) + } yield (se.streetEdgeId, se.geom, re.regionId, se.x2, se.y2, se.x1, se.y1, se.x2, se.y2, false, timestamp, sc._2, sp.priority, false) // Get the priority of the highest priority task. - val highestPriority: Option[Double] = possibleTasks.map(_._12).max.run + val highestPriority: Option[Double] = possibleTasks.map(_._13).max.run // Get list of tasks that have this priority. val highestPriorityTasks: Option[List[NewTask]] = highestPriority.map { highPriority => - possibleTasks.filter(_._12 === highPriority).list.map(NewTask.tupled) + possibleTasks.filter(_._13 === highPriority).list.map(NewTask.tupled) } // Choose one of the highest priority tasks at random. @@ -408,9 +414,10 @@ object AuditTaskTable { val newTask = for { at <- auditTasks if at.auditTaskId === taskId se <- streetEdges if at.streetEdgeId === se.streetEdgeId + re <- regions if se.streetEdgeId === re.streetEdgeId sp <- streetEdgePriorities if se.streetEdgeId === sp.streetEdgeId sc <- streetCompletedByAnyUser if sp.streetEdgeId === sc._1 - } yield (se.streetEdgeId, se.geom, at.currentLng, at.currentLat, se.x1, se.y1, se.x2, se.y2, at.startPointReversed, timestamp, sc._2, sp.priority, false) + } yield (se.streetEdgeId, se.geom, re.regionId, at.currentLng, at.currentLat, se.x1, se.y1, se.x2, se.y2, at.startPointReversed, timestamp, sc._2, sp.priority, false) newTask.list.map(NewTask.tupled).headOption } @@ -424,9 +431,10 @@ object AuditTaskTable { val tasks = for { ser <- nonDeletedStreetEdgeRegions if ser.regionId === regionId se <- streetEdges if ser.streetEdgeId === se.streetEdgeId + re <- regions if se.streetEdgeId === re.streetEdgeId sep <- streetEdgePriorities if se.streetEdgeId === sep.streetEdgeId scau <- streetCompletedByAnyUser if sep.streetEdgeId === scau._1 - } yield (se.streetEdgeId, se.geom, se.x2, se.y2, se.x1, se.y1, se.x2, se.y2, false, timestamp, scau._2, sep.priority, false) + } yield (se.streetEdgeId, se.geom, re.regionId, se.x2, se.y2, se.x1, se.y1, se.x2, se.y2, false, timestamp, scau._2, sep.priority, false) tasks.list.map(NewTask.tupled(_)) } @@ -444,10 +452,11 @@ object AuditTaskTable { val tasks = for { (ser, ucs) <- edgesInRegion.leftJoin(userCompletedStreets).on(_.streetEdgeId === _._1) se <- streetEdges if ser.streetEdgeId === se.streetEdgeId + re <- regions if se.streetEdgeId === re.streetEdgeId sep <- streetEdgePriorities if se.streetEdgeId === sep.streetEdgeId scau <- streetCompletedByAnyUser if sep.streetEdgeId === scau._1 } yield ( - se.streetEdgeId, se.geom, se.x2, se.y2, se.x1, se.y1, se.x2, se.y2, false, timestamp, scau._2, sep.priority, ucs._2.?.getOrElse(false)) + se.streetEdgeId, se.geom, re.regionId, se.x2, se.y2, se.x1, se.y1, se.x2, se.y2, false, timestamp, scau._2, sep.priority, ucs._2.?.getOrElse(false)) tasks.list.map(NewTask.tupled(_)) } diff --git a/public/javascripts/SVLabel/src/SVLabel/Main.js b/public/javascripts/SVLabel/src/SVLabel/Main.js index 02303030a6..4302eea7dc 100644 --- a/public/javascripts/SVLabel/src/SVLabel/Main.js +++ b/public/javascripts/SVLabel/src/SVLabel/Main.js @@ -156,7 +156,7 @@ function Main (params) { svl.modalSkip = new ModalSkip(svl.form, svl.onboardingModel, svl.ribbon, svl.taskContainer, svl.tracker, svl.ui.leftColumn, svl.ui.modalSkip); svl.modalExample = new ModalExample(svl.modalModel, svl.onboardingModel, svl.ui.modalExample); - var infoPopOver = new GSVInfoPopOver(svl.ui.dateHolder, svl.panorama, svl.map); + var infoPopOver = new GSVInfoPopOver(svl.ui.dateHolder, svl.panorama, svl.map.getPosition, svl.map.getPanoId, svl.taskContainer.getCurrentTask().getStreetEdgeId, svl.taskContainer.getCurrentTask().getRegionId, svl.map.getPov); // Survey for select users svl.surveyModalContainer = $("#survey-modal-container").get(0); diff --git a/public/javascripts/SVLabel/src/SVLabel/task/Task.js b/public/javascripts/SVLabel/src/SVLabel/task/Task.js index f1b8115367..3232baf801 100644 --- a/public/javascripts/SVLabel/src/SVLabel/task/Task.js +++ b/public/javascripts/SVLabel/src/SVLabel/task/Task.js @@ -21,6 +21,7 @@ function Task (geojson, tutorialTask, currentLat, currentLng, startPointReversed var properties = { auditTaskId: null, streetEdgeId: null, + regionId: null, completedByAnyUser: null, priority: null, currentLat: currentLat, @@ -40,6 +41,7 @@ function Task (geojson, tutorialTask, currentLat, currentLng, startPointReversed _geojson = geojson; self.setProperty("streetEdgeId", _geojson.features[0].properties.street_edge_id); + self.setProperty("regionId", _geojson.features[0].properties.region_id); self.setProperty("completedByAnyUser", _geojson.features[0].properties.completed_by_any_user); self.setProperty("priority", _geojson.features[0].properties.priority); @@ -327,6 +329,10 @@ function Task (geojson, tutorialTask, currentLat, currentLng, startPointReversed return _geojson.features[0].properties.street_edge_id; }; + this.getRegionId = function () { + return _geojson.features[0].properties.region_id; + } + this.streetCompletedByAnyUser = function () { return properties.completedByAnyUser; }; diff --git a/public/javascripts/common/GSVInfoPopOver.js b/public/javascripts/common/GSVInfoPopOver.js index ca9d841059..a2d7e28c0d 100644 --- a/public/javascripts/common/GSVInfoPopOver.js +++ b/public/javascripts/common/GSVInfoPopOver.js @@ -1,13 +1,46 @@ + /** - * An object for creating a popover which displays additional locational info on any GSV pane. * * @param {HTMLElement} container Element where the info button will be displayed * @param {StreetViewPanorama} panorama Panorama object - * @param {svl.map} map Map object + * @param {function} coords Function that returns curreent longitude and latitude coordinates + * @param {function} panoId Function that returns current panorama ID + * @param {function} streetEdgeId Function that returns current Street Edge ID + * @param {function} regionId Function that returns current Region ID + * @param {function} pov Function that returns current POV * @returns {GSVInfoPopOver} Popover object, which holds the popover title html, content html, info button html, and * update values method */ -function GSVInfoPopOver (container, panorama, map) { +function GSVInfoPopOver (container, panorama, coords, panoId, streetEdgeId, regionId, pov) { + /* + Back-end API TODO: + + Audit: DONE + Panorama: svl.panorama + Coords: svl.map.getPosition() + PanoId: svl.map.getPanoId() + StreetEdgeId: svl.taskContainer.getCurrentTask().getStreetEdgeId() + RegionId: svl.taskContainer.getCurrentTask().getRegionId() + POV: svl.map.getPov() + Gallery: + Coords: sg.modal().pano.getPosition() + PanoId: sg.modal().pano.panoId + StreetEdgeId: + RegionId: + POV:sg.modal().pano.getPov() + Validate: + Coords: + PanoId: + StreetEdgeId: + RegionId: + POV: + LabelMap: + Coords: + PanoId: + StreetEdgeId: + RegionId: + POV: + */ let self = this; function _init() { @@ -43,8 +76,9 @@ function GSVInfoPopOver (container, panorama, map) { addListElement('Latitude', dataList); addListElement('Longitude', dataList); - addListElement('PanoID', dataList); - // TODO: add street edge ID and region ID + addListElement('Pano ID', dataList); + addListElement('Street Edge ID', dataList); + addListElement('Region ID', dataList) self.popoverContent.appendChild(dataList); @@ -81,13 +115,11 @@ function GSVInfoPopOver (container, panorama, map) { // Dismiss popover on clicking outside of popover $('#info-button').on('shown.bs.popover', () => { - console.log('popover shown!'); $('.popover-title').addClass('popover-element'); $('.popover-content').addClass('popover-element'); }); $('html').on('mousedown', (e) => { let tar = $(e.target); - console.log(tar[0]); if (tar[0].className.indexOf('popover-element') === -1) { $('#info-button').popover('hide'); } @@ -103,22 +135,25 @@ function GSVInfoPopOver (container, panorama, map) { * Update the values within the popover */ function updateVals() { - const coords = map.getPosition(); - const panoId = map.getPanoId(); - const pov = map.getPov(); + const currCoords = coords(); + const currPanoId = panoId(); + const currStreetEdgeId = streetEdgeId(); + const currRegionId = regionId(); + const currPov = pov(); function changeVals(key, val) { let valSpan = document.getElementById(`${key}-value`) valSpan.textContent = val; } - changeVals('Latitude', coords.lat + '°'); - changeVals('Longitude', coords.lng + '°'); - changeVals('PanoID', panoId); - // TODO: add streetEdgeId, regionId + changeVals('Latitude', currCoords.lat + '°'); + changeVals('Longitude', currCoords.lng + '°'); + changeVals('Pano ID', currPanoId); + changeVals('Street Edge ID', currStreetEdgeId); + changeVals('Region ID', currRegionId) // Create GSV link - $('#gsv-link').attr('href', `https://www.google.com/maps/@?api=1&map_action=pano&viewpoint=${coords.lat}%2C${coords.lng}&heading=${pov.heading}&pitch=${pov.pitch}`); + $('#gsv-link').attr('href', `https://www.google.com/maps/@?api=1&map_action=pano&viewpoint=${currCoords.lat}%2C${currCoords.lng}&heading=${currPov.heading}&pitch=${pov.pitch}`); $('#gsv-link').attr('target', '_blank'); // Copy to clipboard @@ -126,7 +161,7 @@ function GSVInfoPopOver (container, panorama, map) { $('#clipboard').tooltip('enable'); $('#clipboard').tooltip('show'); navigator.clipboard.writeText( - `Latitude: ${coords.lat}°\nLongitude: ${coords.lng}°\nPanoID: ${panoId}` + `Latitude: ${currCoords.lat}°\nLongitude: ${currCoords.lng}°\nPano ID: ${currPanoId}\nStreet Edge ID: ${currStreetEdgeId}\nRegion ID: ${currRegionId}` ); }); $('#clipboard').on('mouseout', () => { From 2f5ef33122fabfd0903595025446a7a105221739 Mon Sep 17 00:00:00 2001 From: David Phan Date: Thu, 22 Sep 2022 15:07:47 -0700 Subject: [PATCH 06/33] Audit and Validate front end complete --- Gruntfile.js | 6 +- .../SVLabel/css/svl-info-popover.css | 45 ------------ public/javascripts/SVLabel/css/svl.css | 4 ++ .../SVValidate/css/svv-panorama.css | 15 +++- public/javascripts/SVValidate/src/Main.js | 3 + .../SVValidate/src/panorama/Panorama.js | 2 +- public/javascripts/common/GSVInfoPopOver.js | 72 ++++++++++++++----- 7 files changed, 80 insertions(+), 67 deletions(-) delete mode 100644 public/javascripts/SVLabel/css/svl-info-popover.css diff --git a/Gruntfile.js b/Gruntfile.js index fe5806f030..cf39291afb 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -70,7 +70,8 @@ module.exports = function(grunt) { 'public/javascripts/SVValidate/src/util/*.js', 'public/javascripts/SVValidate/src/zoom/*.js', 'public/javascripts/common/Panomarker.js', - 'public/javascripts/common/UtilitiesSidewalk.js' + 'public/javascripts/common/UtilitiesSidewalk.js', + 'public/javascripts/common/GSVInfoPopOver.js' ], dest: 'public/javascripts/SVValidate/build/SVValidate.js' }, @@ -83,7 +84,8 @@ module.exports = function(grunt) { 'public/javascripts/Gallery/src/displays/*.js', 'public/javascripts/Gallery/src/modal/*.js', 'public/javascripts/Gallery/src/*.js', - 'public/javascripts/common/Panomarker.js' + 'public/javascripts/common/Panomarker.js', + 'public/javascripts/common/GSVInfoPopOver.js' ], dest: 'public/javascripts/Gallery/build/Gallery.js' } diff --git a/public/javascripts/SVLabel/css/svl-info-popover.css b/public/javascripts/SVLabel/css/svl-info-popover.css deleted file mode 100644 index cc3bd8676d..0000000000 --- a/public/javascripts/SVLabel/css/svl-info-popover.css +++ /dev/null @@ -1,45 +0,0 @@ -#info-button { - margin: 5px; - max-height: 100%; -} - -.info-key { - font-weight: bold; -} - -.info-list-item { - display: flex; - justify-content: space-between; -} - -.popover { - width: 350px; - max-width: 350px; -} - -.popover-title { - display: flex; - justify-content: space-between; - height: 36px; -} - -.popover-content { - display: flex; - flex-direction: column; - justify-content: center; -} -#gsv-link { - text-align: center; - width: fit-content; - margin-left: auto; - margin-right: auto; -} - -#clipboard { - max-height: 100%; - cursor: pointer; -} - -#clipboard:active { - opacity: 50%; -} diff --git a/public/javascripts/SVLabel/css/svl.css b/public/javascripts/SVLabel/css/svl.css index 5d24a80919..e7569c1877 100644 --- a/public/javascripts/SVLabel/css/svl.css +++ b/public/javascripts/SVLabel/css/svl.css @@ -149,3 +149,7 @@ input[type="radio"] { #svl-panorama-date { padding: 5px; } + +#clipboard:active { + opacity: 50%; +} diff --git a/public/javascripts/SVValidate/css/svv-panorama.css b/public/javascripts/SVValidate/css/svv-panorama.css index 41841d8ac2..88158d7e9f 100644 --- a/public/javascripts/SVValidate/css/svv-panorama.css +++ b/public/javascripts/SVValidate/css/svv-panorama.css @@ -14,9 +14,12 @@ } #svv-panorama-date-holder { + display: flex; + justify-content: flex-start; + height: 29px; position: absolute; - bottom: 3px; - left: 75px; + bottom: 0px; + left: 69px; z-index: 1; font-family: sans-serif; font-size: 15px; @@ -24,6 +27,14 @@ color: white; } +#svv-panorama-date { + padding: 5px; +} + +#clipboard:active { + opacity: 50%; +} + /* Black outline around GSV panorama. */ #svv-panorama-outline { border: 5px solid black; diff --git a/public/javascripts/SVValidate/src/Main.js b/public/javascripts/SVValidate/src/Main.js index 05a3abc067..451db6d040 100644 --- a/public/javascripts/SVValidate/src/Main.js +++ b/public/javascripts/SVValidate/src/Main.js @@ -129,6 +129,8 @@ function Main (param) { svv.ui.status.examples.popupImage = $("#example-image-popup"); svv.ui.status.examples.popupPointer = $("#example-image-popup-pointer"); svv.ui.status.examples.popupTitle = $("#example-image-popup-title"); + + svv.ui.dateHolder = $("#svv-panorama-date-holder"); } function _init() { @@ -168,6 +170,7 @@ function Main (param) { svv.modalInfo = new ModalInfo(svv.ui.modalInfo, param.modalText); svv.modalLandscape = new ModalLandscape(svv.ui.modalLandscape); svv.modalNoNewMission = new ModalNoNewMission(svv.ui.modalMission); + svv.infoPopover = new GSVInfoPopOver(svv.ui.dateHolder, svv.panorama.getPanorama(), null, svv.panorama.getPanoId, null, null, null); svv.missionContainer = new MissionContainer(); svv.missionContainer.createAMission(param.mission, param.progress); diff --git a/public/javascripts/SVValidate/src/panorama/Panorama.js b/public/javascripts/SVValidate/src/panorama/Panorama.js index 4326ed0160..e6776c53f3 100644 --- a/public/javascripts/SVValidate/src/panorama/Panorama.js +++ b/public/javascripts/SVValidate/src/panorama/Panorama.js @@ -205,7 +205,7 @@ function Panorama (label) { } } else { console.error("Error retrieving Panoramas: " + status); - svl.tracker.push("PanoId_NotFound", {'TargetPanoId': panoramaId}); + svv.tracker.push("PanoId_NotFound", {'TargetPanoId': panoramaId}); } }); } diff --git a/public/javascripts/common/GSVInfoPopOver.js b/public/javascripts/common/GSVInfoPopOver.js index a2d7e28c0d..e28c3f280a 100644 --- a/public/javascripts/common/GSVInfoPopOver.js +++ b/public/javascripts/common/GSVInfoPopOver.js @@ -3,7 +3,7 @@ * * @param {HTMLElement} container Element where the info button will be displayed * @param {StreetViewPanorama} panorama Panorama object - * @param {function} coords Function that returns curreent longitude and latitude coordinates + * @param {function} coords Function that returns current longitude and latitude coordinates * @param {function} panoId Function that returns current panorama ID * @param {function} streetEdgeId Function that returns current Street Edge ID * @param {function} regionId Function that returns current Region ID @@ -23,18 +23,21 @@ function GSVInfoPopOver (container, panorama, coords, panoId, streetEdgeId, regi RegionId: svl.taskContainer.getCurrentTask().getRegionId() POV: svl.map.getPov() Gallery: + Panorama: sg.modal().pano.panorama Coords: sg.modal().pano.getPosition() - PanoId: sg.modal().pano.panoId + PanoId: sg.modal().pano.getPanoId() StreetEdgeId: RegionId: POV:sg.modal().pano.getPov() Validate: + Panorama: Coords: - PanoId: + PanoId: svv.panorama.getPanoId() StreetEdgeId: RegionId: POV: LabelMap: + Panorama: Coords: PanoId: StreetEdgeId: @@ -102,11 +105,16 @@ function GSVInfoPopOver (container, panorama, coords, panoId, streetEdgeId, regi container.append(self.infoButton); + // Info button styling + $(container).css('z-index', 2); + $('#info-button').css('margin', '5px'); + $('#info-button').css('max-height', '100%'); + // Enable popovers/tooltips and set options $('#info-button').popover({ html: true, - container: $('#view-control-layer'), + container: $('body'), }); $('#clipboard').tooltip(); @@ -135,25 +143,59 @@ function GSVInfoPopOver (container, panorama, coords, panoId, streetEdgeId, regi * Update the values within the popover */ function updateVals() { - const currCoords = coords(); - const currPanoId = panoId(); - const currStreetEdgeId = streetEdgeId(); - const currRegionId = regionId(); - const currPov = pov(); + // Position and style popover + let xpos = self.infoButton.getBoundingClientRect().x + (19 / 2) - 175 + $('.popover').css('left', `${xpos}px`); + + $('.info-key').css('font-weight', 'bold'); + + $('.info-list-item').css('display', 'flex'); + $('.info-list-item').css('justify-content', 'space-between'); + + $('.popover').css('width', '350px'); + $('.popover').css('max-width', '350px'); + + $('.popover-title').css('display', 'flex'); + $('.popover-title').css('justify-content', 'space-between'); + $('.popover-title').css('height', '36px'); + + $('.popover-content').css('display', 'flex'); + $('.popover-content').css('flex-direction', 'column'); + $('.popover-content').css('justify-content', 'center'); + + $('#gsv-link').css('text-align', 'center'); + $('#gsv-link').css('width', 'fit-content'); + $('#gsv-link').css('margin-left', 'auto'); + $('#gsv-link').css('margin-right', 'auto'); + + $('#clipboard').css('max-height', '100%'); + $('#clipboard').css('cursor', 'pointer'); + + // Get info values + const currCoords = coords ? coords() : {lat: null, lng: null}; + const currPanoId = panoId ? panoId() : null; + const currStreetEdgeId = streetEdgeId ? streetEdgeId() : null; + const currRegionId = regionId ? regionId() : null; + const currPov = pov ? pov() : {heading: 0, pitch: 0}; function changeVals(key, val) { - let valSpan = document.getElementById(`${key}-value`) + if (!val) { + val = 'No Info'; + } else if (key === "Latitude" || key === 'Longitude') { + val += '°'; + } + let valSpan = document.getElementById(`${key}-value`); valSpan.textContent = val; } - changeVals('Latitude', currCoords.lat + '°'); - changeVals('Longitude', currCoords.lng + '°'); + changeVals('Latitude', currCoords.lat); + changeVals('Longitude', currCoords.lng); changeVals('Pano ID', currPanoId); changeVals('Street Edge ID', currStreetEdgeId); changeVals('Region ID', currRegionId) // Create GSV link - $('#gsv-link').attr('href', `https://www.google.com/maps/@?api=1&map_action=pano&viewpoint=${currCoords.lat}%2C${currCoords.lng}&heading=${currPov.heading}&pitch=${pov.pitch}`); + $('#gsv-link').attr('href', `https://www.google.com/maps/@?api=1&map_action=pano&viewpoint=${currCoords.lat}%2C${currCoords.lng}&heading=${currPov.heading}&pitch=${currPov.pitch}`); $('#gsv-link').attr('target', '_blank'); // Copy to clipboard @@ -167,10 +209,6 @@ function GSVInfoPopOver (container, panorama, coords, panoId, streetEdgeId, regi $('#clipboard').on('mouseout', () => { $('#clipboard').tooltip('disable'); }); - - // Fixes Bootstrap popover positioning issues, has to be done AFTER popover loads, - // thus cannot be put into css file - $('.popover').css('left', '-17px'); } /** From d617ef70af423ba3e9b8dfb859eb89531a029a5c Mon Sep 17 00:00:00 2001 From: David Phan Date: Thu, 22 Sep 2022 16:32:24 -0700 Subject: [PATCH 07/33] front end for Gallery complete --- public/javascripts/Gallery/css/modal.css | 13 ++++++ public/javascripts/Gallery/src/Main.js | 2 + .../Gallery/src/cards/CardContainer.js | 9 +++++ .../Gallery/src/modal/GalleryPanorama.js | 40 +++++++++++++++++++ public/javascripts/Gallery/src/modal/Modal.js | 9 +++-- public/javascripts/SVLabel/css/svl.css | 5 +++ .../javascripts/SVLabel/src/SVLabel/Main.js | 4 +- .../SVValidate/css/svv-panorama.css | 5 +++ public/javascripts/common/GSVInfoPopOver.js | 10 ++--- 9 files changed, 85 insertions(+), 12 deletions(-) diff --git a/public/javascripts/Gallery/css/modal.css b/public/javascripts/Gallery/css/modal.css index 9a78245ad5..20f81925ec 100644 --- a/public/javascripts/Gallery/css/modal.css +++ b/public/javascripts/Gallery/css/modal.css @@ -25,6 +25,19 @@ color: #2d2a3f; } +.label-timestamp { + display: flex; +} + +#info-button { + width: 15px; + margin: 0 3px 3px 7px; +} + +#clipboard:active { + opacity: 50%; +} + .modal-severity-header, .modal-tag-header, .modal-temporary-header, .modal-description-header { font-weight: bold; color: #2d2a3f; diff --git a/public/javascripts/Gallery/src/Main.js b/public/javascripts/Gallery/src/Main.js index bbbb94d538..292b1d0169 100644 --- a/public/javascripts/Gallery/src/Main.js +++ b/public/javascripts/Gallery/src/Main.js @@ -73,6 +73,8 @@ function Main (params) { // sg.cardSortMenu = new CardSortMenu(sg.ui.cardSortMenu); sg.tagContainer = new CardFilter(sg.ui.cardFilter, sg.labelTypeMenu, sg.cityMenu); sg.cardContainer = new CardContainer(sg.ui.cardContainer); + sg.modal = sg.cardContainer.getModal; + sg.infoPopover = new GSVInfoPopOver($('.pano-timestamp'), sg.modal().pano.panorama, sg.modal().pano.getPosition, sg.modal().pano.getPanoId, null, null, sg.modal().pano.getPov); // Initialize data collection. sg.form = new Form(params.dataStoreUrl, params.beaconDataStoreUrl) sg.tracker = new Tracker(); diff --git a/public/javascripts/Gallery/src/cards/CardContainer.js b/public/javascripts/Gallery/src/cards/CardContainer.js index 8e7dbd7a61..923fba8d73 100644 --- a/public/javascripts/Gallery/src/cards/CardContainer.js +++ b/public/javascripts/Gallery/src/cards/CardContainer.js @@ -450,6 +450,14 @@ function CardContainer(uiCardContainer) { return lastPage; } + /** + * Returns the modal object + * @returns {Modal} Gallery modal object + */ + function getModal() { + return modal; + } + self.fetchLabels = fetchLabels; self.getCards = getCards; self.getCurrentCards = getCurrentCards; @@ -465,6 +473,7 @@ function CardContainer(uiCardContainer) { self.getCardByIndex = getCardByIndex; self.getCurrentPage = getCurrentPage; self.getCurrentPageCards = getCurrentPageCards; + self.getModal = getModal; _init(); return this; diff --git a/public/javascripts/Gallery/src/modal/GalleryPanorama.js b/public/javascripts/Gallery/src/modal/GalleryPanorama.js index 64769ad941..ead239a6fa 100644 --- a/public/javascripts/Gallery/src/modal/GalleryPanorama.js +++ b/public/javascripts/Gallery/src/modal/GalleryPanorama.js @@ -273,11 +273,51 @@ 195.93 / Math.pow(1.92, zoom); // parameters determined experimentally. } + /** + * Gets the current coordinates + * @returns {{lng: float, lat: float}} + */ + function getCoords() { + let coords = self.panorama.getPosition(); + // Creates "TypeError: Cannot read properties of undefined (reading 'lat')", but still works fine + return coords ? { 'lat' : coords.lat(), 'lng' : coords.lng() } : undefined; + } + + /** + * Get the current point of view. + * @returns {object} pov + */ + function getPov() { + var pov = self.panorama.getPov(); + + // Pov can be less than 0. So adjust it. + while (pov.heading < 0) { + pov.heading += 360; + } + + // Pov can be more than 360. Adjust it. + while (pov.heading > 360) { + pov.heading -= 360; + } + return pov; + } + + /** + * Get the label's default panorama ID + */ + function getPanoId() { + return self.panoId + } + + _init(); self.setPov = setPov; self.setPano = setPano; self.renderLabel = renderLabel; self.getOriginalPosition = getOriginalPosition; + self.getPosition = getCoords; + self.getPov = getPov; + self.getPanoId = getPanoId; return self; } diff --git a/public/javascripts/Gallery/src/modal/Modal.js b/public/javascripts/Gallery/src/modal/Modal.js index d1ff04a56e..99c9886ffd 100644 --- a/public/javascripts/Gallery/src/modal/Modal.js +++ b/public/javascripts/Gallery/src/modal/Modal.js @@ -128,13 +128,13 @@ function Modal(uiModal) { */ function populateModalDescriptionFields() { // Add timestamp data for when label was placed and when pano was created. - let labelTimestampData = document.createElement('div'); - labelTimestampData.className = 'label-timestamp'; - labelTimestampData.innerHTML = `
${i18next.t('labeled')}: ${moment(new Date(properties.label_timestamp)).format('LL, LT')}
`; + self.labelTimestampData = document.createElement('div'); + self.labelTimestampData.className = 'label-timestamp'; + self.labelTimestampData.innerHTML = `
${i18next.t('labeled')}: ${moment(new Date(properties.label_timestamp)).format('LL, LT')}
`; let panoTimestampData = document.createElement('div'); panoTimestampData.className = 'pano-timestamp'; panoTimestampData.innerHTML = `
${i18next.t('image-date')}: ${moment(properties.image_date).format('MMM YYYY')}
`; - self.timestamps.append(labelTimestampData); + self.timestamps.append(self.labelTimestampData); self.timestamps.append(panoTimestampData); // Add severity and tag display to the modal. @@ -168,6 +168,7 @@ function Modal(uiModal) { function openModal() { resetModal(); populateModalDescriptionFields(); + sg.infoPopover = new GSVInfoPopOver(self.labelTimestampData, sg.modal().pano.panorama, sg.modal().pano.getPosition, sg.modal().pano.getPanoId, null, null, sg.modal().pano.getPov); self.pano.setPano(properties.gsv_panorama_id, properties.heading, properties.pitch, properties.zoom); self.pano.renderLabel(self.label); self.header.text(i18next.t(`gallery.${util.camelToKebab(properties.label_type)}`)); diff --git a/public/javascripts/SVLabel/css/svl.css b/public/javascripts/SVLabel/css/svl.css index e7569c1877..50a405a3ef 100644 --- a/public/javascripts/SVLabel/css/svl.css +++ b/public/javascripts/SVLabel/css/svl.css @@ -153,3 +153,8 @@ input[type="radio"] { #clipboard:active { opacity: 50%; } + +#info-button { + margin: 5px; + max-height: 100%; +} diff --git a/public/javascripts/SVLabel/src/SVLabel/Main.js b/public/javascripts/SVLabel/src/SVLabel/Main.js index 4302eea7dc..eac75ee89b 100644 --- a/public/javascripts/SVLabel/src/SVLabel/Main.js +++ b/public/javascripts/SVLabel/src/SVLabel/Main.js @@ -156,7 +156,7 @@ function Main (params) { svl.modalSkip = new ModalSkip(svl.form, svl.onboardingModel, svl.ribbon, svl.taskContainer, svl.tracker, svl.ui.leftColumn, svl.ui.modalSkip); svl.modalExample = new ModalExample(svl.modalModel, svl.onboardingModel, svl.ui.modalExample); - var infoPopOver = new GSVInfoPopOver(svl.ui.dateHolder, svl.panorama, svl.map.getPosition, svl.map.getPanoId, svl.taskContainer.getCurrentTask().getStreetEdgeId, svl.taskContainer.getCurrentTask().getRegionId, svl.map.getPov); + svl.infoPopover = new GSVInfoPopOver(svl.ui.dateHolder, svl.panorama, svl.map.getPosition, svl.map.getPanoId, svl.taskContainer.getCurrentTask().getStreetEdgeId, svl.taskContainer.getCurrentTask().getRegionId, svl.map.getPov); // Survey for select users svl.surveyModalContainer = $("#survey-modal-container").get(0); @@ -426,7 +426,7 @@ function Main (params) { svl.ui.googleMaps = {}; svl.ui.googleMaps.holder = $("#google-maps-holder"); svl.ui.googleMaps.overlay = $("#google-maps-overlay"); - svl.ui.dateHolder = $("#svl-panorama-date-holder") + svl.ui.dateHolder = $("#svl-panorama-date-holder"); // Status holder svl.ui.status = {}; diff --git a/public/javascripts/SVValidate/css/svv-panorama.css b/public/javascripts/SVValidate/css/svv-panorama.css index 88158d7e9f..35e62d49c0 100644 --- a/public/javascripts/SVValidate/css/svv-panorama.css +++ b/public/javascripts/SVValidate/css/svv-panorama.css @@ -31,6 +31,11 @@ padding: 5px; } +#info-button { + margin: 5px; + max-height: 100%; +} + #clipboard:active { opacity: 50%; } diff --git a/public/javascripts/common/GSVInfoPopOver.js b/public/javascripts/common/GSVInfoPopOver.js index e28c3f280a..381c91cf4e 100644 --- a/public/javascripts/common/GSVInfoPopOver.js +++ b/public/javascripts/common/GSVInfoPopOver.js @@ -1,5 +1,5 @@ - /** + * Displays info about the current GSV pane * * @param {HTMLElement} container Element where the info button will be displayed * @param {StreetViewPanorama} panorama Panorama object @@ -28,7 +28,7 @@ function GSVInfoPopOver (container, panorama, coords, panoId, streetEdgeId, regi PanoId: sg.modal().pano.getPanoId() StreetEdgeId: RegionId: - POV:sg.modal().pano.getPov() + POV: sg.modal().pano.getPov() Validate: Panorama: Coords: @@ -48,6 +48,7 @@ function GSVInfoPopOver (container, panorama, coords, panoId, streetEdgeId, regi function _init() { + console.log('Creating popover!'); // Create popover title bar self.titleBox = document.createElement('div'); @@ -107,9 +108,6 @@ function GSVInfoPopOver (container, panorama, coords, panoId, streetEdgeId, regi // Info button styling $(container).css('z-index', 2); - $('#info-button').css('margin', '5px'); - $('#info-button').css('max-height', '100%'); - // Enable popovers/tooltips and set options $('#info-button').popover({ @@ -144,7 +142,7 @@ function GSVInfoPopOver (container, panorama, coords, panoId, streetEdgeId, regi */ function updateVals() { // Position and style popover - let xpos = self.infoButton.getBoundingClientRect().x + (19 / 2) - 175 + let xpos = self.infoButton.getBoundingClientRect().x + (self.infoButton.getBoundingClientRect().width / 2) - 175 $('.popover').css('left', `${xpos}px`); $('.info-key').css('font-weight', 'bold'); From a32fcf82a121d106884f1a8d1607806326454c97 Mon Sep 17 00:00:00 2001 From: David Phan Date: Sun, 25 Sep 2022 16:55:33 -0700 Subject: [PATCH 08/33] Completed front end except LabelMap bootstrap issues, all remaining tasks noted in public/javascripts/common/GSVInfoPopover.js, css moved from js to main.css --- Gruntfile.js | 3 +- app/views/labelMap.scala.html | 2 +- .../Admin/src/Admin.GSVLabelView.js | 153 +++++++++--------- .../javascripts/Admin/src/Admin.Panorama.js | 41 +++++ public/javascripts/Gallery/css/modal.css | 4 - public/javascripts/SVLabel/css/svl.css | 3 - .../SVValidate/css/svv-panorama.css | 6 +- public/javascripts/SVValidate/src/Main.js | 2 +- public/javascripts/common/GSVInfoPopOver.js | 77 ++++----- public/stylesheets/admin.css | 57 +++++++ public/stylesheets/main.css | 42 +++++ 11 files changed, 249 insertions(+), 141 deletions(-) diff --git a/Gruntfile.js b/Gruntfile.js index cf39291afb..308ad467c8 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -45,7 +45,8 @@ module.exports = function(grunt) { }, dist_admin: { src: [ - 'public/javascripts/Admin/src/*.js' + 'public/javascripts/Admin/src/*.js', + 'public/javascripts/common/GSVInfoPopOver.js' ], dest: 'public/javascripts/Admin/build/Admin.js' }, diff --git a/app/views/labelMap.scala.html b/app/views/labelMap.scala.html index d2b9a51972..f5acf8011d 100644 --- a/app/views/labelMap.scala.html +++ b/app/views/labelMap.scala.html @@ -241,7 +241,7 @@ }); // When audited streets have rendered and submitted labels have loaded, submitted labels can be rendered. $.when(renderAuditedStreets, loadSubmittedLabels).done(function(data1, data2) { - self.mapData = InitializeSubmittedLabels(map, streetParams, AdminGSVLabelView(false), InitializeMapLayerContainer(), data2[0]) + self.mapData = InitializeSubmittedLabels(map, streetParams, AdminGSVLabelView(false), InitializeMapLayerContainer(), data2[0]); }) window.map = self; console.log("To add data from users marked as 'low quality'', use the following commands. You can run them again with 'false' to remove."); diff --git a/public/javascripts/Admin/src/Admin.GSVLabelView.js b/public/javascripts/Admin/src/Admin.GSVLabelView.js index b2cc93e2c8..f89da4dda0 100644 --- a/public/javascripts/Admin/src/Admin.GSVLabelView.js +++ b/public/javascripts/Admin/src/Admin.GSVLabelView.js @@ -24,89 +24,87 @@ function AdminGSVLabelView(admin) { '' + '' + '' + - '' - } else { - modalText += '' + - '' + - '' + - '' + - '' - } + '' + self.modal = $(modalText); self.panorama = AdminPanorama(self.modal.find("#svholder")[0], self.modal.find("#validation-input-holder"), admin); @@ -154,6 +152,9 @@ function AdminGSVLabelView(admin) { self.modalTask = self.modal.find("#task"); self.modalLabelId = self.modal.find("#label-id"); self.modalPanoId = self.modal.find('#pano-id'); + self.modalInfoHolder = self.modal.find('#info-popover-holder'); + + self.infoPopover = new GSVInfoPopOver(self.modalInfoHolder, self.panorama.panorama, self.panorama.getPosition, self.panorama.getPanoId, null, null, self.panorama.getPov); } /** diff --git a/public/javascripts/Admin/src/Admin.Panorama.js b/public/javascripts/Admin/src/Admin.Panorama.js index 023ff034c6..380b368111 100644 --- a/public/javascripts/Admin/src/Admin.Panorama.js +++ b/public/javascripts/Admin/src/Admin.Panorama.js @@ -326,6 +326,43 @@ function AdminPanorama(svHolder, buttonHolder, admin) { } } + /** + * Returns the panorama ID for the current panorama. + * @returns {google.maps.StreetViewPanorama} Google StreetView Panorama Id + */ + function getPanoId () { + return self.panorama.getPano(); + } + + /** + * Returns the lat lng of this panorama. Note that sometimes position is null/undefined + * (probably a bug in GSV), so sometimes this function returns null. + * @returns {{lat, lng}} + */ + function getPos () { + let position = self.panorama.getPosition(); + return (position) ? {'lat': position.lat(), 'lng': position.lng()} : null; + } + + /** + * Returns the pov of the viewer. + * @returns {{heading: float, pitch: float, zoom: float}} + */ + function getPov () { + let pov = self.panorama.getPov(); + + // Pov can be less than 0. So adjust it. + while (pov.heading < 0) { + pov.heading += 360; + } + + // Pov can be more than 360. Adjust it. + while (pov.heading > 360) { + pov.heading -= 360; + } + return pov; + } + //init _init(); @@ -334,5 +371,9 @@ function AdminPanorama(svHolder, buttonHolder, admin) { self.setLabel = setLabel; self.renderLabel = renderLabel; self.getOriginalPosition = getOriginalPosition; + self.getPanoId = getPanoId; + self.getPosition = getPos; + self.getPov = getPov; + return self; } diff --git a/public/javascripts/Gallery/css/modal.css b/public/javascripts/Gallery/css/modal.css index 20f81925ec..a2461c8581 100644 --- a/public/javascripts/Gallery/css/modal.css +++ b/public/javascripts/Gallery/css/modal.css @@ -34,10 +34,6 @@ margin: 0 3px 3px 7px; } -#clipboard:active { - opacity: 50%; -} - .modal-severity-header, .modal-tag-header, .modal-temporary-header, .modal-description-header { font-weight: bold; color: #2d2a3f; diff --git a/public/javascripts/SVLabel/css/svl.css b/public/javascripts/SVLabel/css/svl.css index 50a405a3ef..9c810667ad 100644 --- a/public/javascripts/SVLabel/css/svl.css +++ b/public/javascripts/SVLabel/css/svl.css @@ -150,9 +150,6 @@ input[type="radio"] { padding: 5px; } -#clipboard:active { - opacity: 50%; -} #info-button { margin: 5px; diff --git a/public/javascripts/SVValidate/css/svv-panorama.css b/public/javascripts/SVValidate/css/svv-panorama.css index 35e62d49c0..64c4230ee9 100644 --- a/public/javascripts/SVValidate/css/svv-panorama.css +++ b/public/javascripts/SVValidate/css/svv-panorama.css @@ -20,7 +20,7 @@ position: absolute; bottom: 0px; left: 69px; - z-index: 1; + z-index: 2; font-family: sans-serif; font-size: 15px; text-shadow: 0.5px 0.5px 0.5px rgba(0, 0, 0, 0.5); @@ -36,10 +36,6 @@ max-height: 100%; } -#clipboard:active { - opacity: 50%; -} - /* Black outline around GSV panorama. */ #svv-panorama-outline { border: 5px solid black; diff --git a/public/javascripts/SVValidate/src/Main.js b/public/javascripts/SVValidate/src/Main.js index 451db6d040..ce0ea00570 100644 --- a/public/javascripts/SVValidate/src/Main.js +++ b/public/javascripts/SVValidate/src/Main.js @@ -170,7 +170,7 @@ function Main (param) { svv.modalInfo = new ModalInfo(svv.ui.modalInfo, param.modalText); svv.modalLandscape = new ModalLandscape(svv.ui.modalLandscape); svv.modalNoNewMission = new ModalNoNewMission(svv.ui.modalMission); - svv.infoPopover = new GSVInfoPopOver(svv.ui.dateHolder, svv.panorama.getPanorama(), null, svv.panorama.getPanoId, null, null, null); + svv.infoPopover = new GSVInfoPopOver(svv.ui.dateHolder, svv.panorama.getPanorama(), svv.panorama.getPosition, svv.panorama.getPanoId, null, null, svv.panorama.getPov); svv.missionContainer = new MissionContainer(); svv.missionContainer.createAMission(param.mission, param.progress); diff --git a/public/javascripts/common/GSVInfoPopOver.js b/public/javascripts/common/GSVInfoPopOver.js index 381c91cf4e..e781a01ceb 100644 --- a/public/javascripts/common/GSVInfoPopOver.js +++ b/public/javascripts/common/GSVInfoPopOver.js @@ -13,42 +13,46 @@ */ function GSVInfoPopOver (container, panorama, coords, panoId, streetEdgeId, regionId, pov) { /* + DELETE ONCE FINISHED Back-end API TODO: + Here's the list of all the references to parameters (coords, panoId, etc.) I've found/created on each page. + The blank ones are the ones that need changes to the backend API to grab that info from the database. - Audit: DONE + LabelMap was configured differently so I couldn't figure out how to get the bootstrap popover to function on + that page? + + Audit: (located in public/javascripts/SVLabel/src/Main.js) DONE Panorama: svl.panorama - Coords: svl.map.getPosition() - PanoId: svl.map.getPanoId() - StreetEdgeId: svl.taskContainer.getCurrentTask().getStreetEdgeId() - RegionId: svl.taskContainer.getCurrentTask().getRegionId() - POV: svl.map.getPov() - Gallery: + Coords: svl.map.getPosition + PanoId: svl.map.getPanoId + StreetEdgeId: svl.taskContainer.getCurrentTask().getStreetEdgeId + RegionId: svl.taskContainer.getCurrentTask().getRegionId + POV: svl.map.getPov + Gallery: (located in public/javascripts/Gallery/src/Main.js) Panorama: sg.modal().pano.panorama - Coords: sg.modal().pano.getPosition() - PanoId: sg.modal().pano.getPanoId() + Coords: sg.modal().pano.getPosition + PanoId: sg.modal().pano.getPanoId StreetEdgeId: RegionId: - POV: sg.modal().pano.getPov() - Validate: - Panorama: - Coords: - PanoId: svv.panorama.getPanoId() + POV: sg.modal().pano.getPov + Validate: (located in public/javascripts/SVValidate/src/Main.js) + Panorama: svv.panorama.getPanorama() + Coords: svv.panorama.getPosition + PanoId: svv.panorama.getPanoId StreetEdgeId: RegionId: - POV: - LabelMap: - Panorama: - Coords: - PanoId: + POV: svv.panorama.getPov + LabelMap: (located in public/javascripts/Admin/src/Admin.GSVLabelView.js) + Panorama: self.panorama.panorama + Coords: self.panorama.getPosition + PanoId: self.panorama.getPanoId StreetEdgeId: RegionId: - POV: + POV: self.panorama.getPov */ let self = this; function _init() { - - console.log('Creating popover!'); // Create popover title bar self.titleBox = document.createElement('div'); @@ -106,9 +110,6 @@ function GSVInfoPopOver (container, panorama, coords, panoId, streetEdgeId, regi container.append(self.infoButton); - // Info button styling - $(container).css('z-index', 2); - // Enable popovers/tooltips and set options $('#info-button').popover({ html: true, @@ -141,34 +142,10 @@ function GSVInfoPopOver (container, panorama, coords, panoId, streetEdgeId, regi * Update the values within the popover */ function updateVals() { - // Position and style popover + // Position popover let xpos = self.infoButton.getBoundingClientRect().x + (self.infoButton.getBoundingClientRect().width / 2) - 175 $('.popover').css('left', `${xpos}px`); - $('.info-key').css('font-weight', 'bold'); - - $('.info-list-item').css('display', 'flex'); - $('.info-list-item').css('justify-content', 'space-between'); - - $('.popover').css('width', '350px'); - $('.popover').css('max-width', '350px'); - - $('.popover-title').css('display', 'flex'); - $('.popover-title').css('justify-content', 'space-between'); - $('.popover-title').css('height', '36px'); - - $('.popover-content').css('display', 'flex'); - $('.popover-content').css('flex-direction', 'column'); - $('.popover-content').css('justify-content', 'center'); - - $('#gsv-link').css('text-align', 'center'); - $('#gsv-link').css('width', 'fit-content'); - $('#gsv-link').css('margin-left', 'auto'); - $('#gsv-link').css('margin-right', 'auto'); - - $('#clipboard').css('max-height', '100%'); - $('#clipboard').css('cursor', 'pointer'); - // Get info values const currCoords = coords ? coords() : {lat: null, lng: null}; const currPanoId = panoId ? panoId() : null; diff --git a/public/stylesheets/admin.css b/public/stylesheets/admin.css index 0d1fe2b3d8..303d3a27ea 100644 --- a/public/stylesheets/admin.css +++ b/public/stylesheets/admin.css @@ -93,3 +93,60 @@ left: 405px; bottom: 5px } + +/* GSV Info Popover styling */ +#info-popover-holder { + width: 19px; + height: 19px; + position: absolute; + z-index: 2; + left: 70px; + bottom: 0; + margin: 5px; +} + +#info-button { + width: 19px; + margin-bottom: 4px; +} + +.info-key { + font-weight: bold; +} + +.info-list-item { + display: flex; + justify-content: space-between; +} + +.popover { + width: 350px; + max-width: 350px; +} + +.popover-title { + display: flex; + justify-content: space-between; + height: 36px; +} + +.popover-content { + display: flex; + flex-direction: column; + justify-content: center; +} +#gsv-link { + text-align: center; + width: fit-content; + margin-left: auto; + margin-right: auto; +} + +#clipboard { + max-height: 100%; + cursor: pointer; +} + +#clipboard:active { + opacity: 50%; +} diff --git a/public/stylesheets/main.css b/public/stylesheets/main.css index d885bada21..ded88c541d 100644 --- a/public/stylesheets/main.css +++ b/public/stylesheets/main.css @@ -708,6 +708,48 @@ p#conditional-text { text-decoration:underline; } +/* GSV Info Popover styling */ +.info-key { + font-weight: bold; +} + +.info-list-item { + display: flex; + justify-content: space-between; +} + +.popover { + width: 350px; + max-width: 350px; +} + +.popover-title { + display: flex; + justify-content: space-between; + height: 36px; +} + +.popover-content { + display: flex; + flex-direction: column; + justify-content: center; +} +#gsv-link { + text-align: center; + width: fit-content; + margin-left: auto; + margin-right: auto; +} + +#clipboard { + max-height: 100%; + cursor: pointer; +} + +#clipboard:active { + opacity: 50%; +} + @media only screen and (max-device-width: 500px) { #awardnum { width: 100% !important; From bcd80e2987b82533f6ad23f5a2c135195d9c0e68 Mon Sep 17 00:00:00 2001 From: Mikey Saugstad Date: Tue, 11 Oct 2022 13:37:36 -0700 Subject: [PATCH 09/33] reduces number of digits shown in lat/lng --- public/javascripts/common/GSVInfoPopOver.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/javascripts/common/GSVInfoPopOver.js b/public/javascripts/common/GSVInfoPopOver.js index e781a01ceb..2f6f677d37 100644 --- a/public/javascripts/common/GSVInfoPopOver.js +++ b/public/javascripts/common/GSVInfoPopOver.js @@ -157,7 +157,7 @@ function GSVInfoPopOver (container, panorama, coords, panoId, streetEdgeId, regi if (!val) { val = 'No Info'; } else if (key === "Latitude" || key === 'Longitude') { - val += '°'; + val = val.toFixed(8) + '°'; } let valSpan = document.getElementById(`${key}-value`); valSpan.textContent = val; From d653880b044a4f7378f132a0f20b18eefd7e7195 Mon Sep 17 00:00:00 2001 From: Mikey Saugstad Date: Wed, 12 Oct 2022 11:50:09 -0700 Subject: [PATCH 10/33] removes info popover from LabelMap --- app/views/labelMap.scala.html | 2 +- public/javascripts/Admin/src/Admin.GSVLabelView.js | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/app/views/labelMap.scala.html b/app/views/labelMap.scala.html index 07719dec06..93822d4b44 100644 --- a/app/views/labelMap.scala.html +++ b/app/views/labelMap.scala.html @@ -274,6 +274,6 @@ $('.modal-backdrop').remove(); }, 200) } - }) + }); } diff --git a/public/javascripts/Admin/src/Admin.GSVLabelView.js b/public/javascripts/Admin/src/Admin.GSVLabelView.js index be250c35c2..9f70d0c5c1 100644 --- a/public/javascripts/Admin/src/Admin.GSVLabelView.js +++ b/public/javascripts/Admin/src/Admin.GSVLabelView.js @@ -153,8 +153,6 @@ function AdminGSVLabelView(admin) { self.modalLabelId = self.modal.find("#label-id"); self.modalPanoId = self.modal.find('#pano-id'); self.modalInfoHolder = self.modal.find('#info-popover-holder'); - - self.infoPopover = new GSVInfoPopOver(self.modalInfoHolder, self.panorama.panorama, self.panorama.getPosition, self.panorama.getPanoId, null, null, self.panorama.getPov); } /** From 6ef52c6d1c282770ad814f0318382efd5a7b128e Mon Sep 17 00:00:00 2001 From: Mikey Saugstad Date: Wed, 12 Oct 2022 12:41:05 -0700 Subject: [PATCH 11/33] lat/lng and link to GSV to LabelMap modals --- .../Admin/src/Admin.GSVLabelView.js | 49 ++++++++++++++++--- .../javascripts/Admin/src/Admin.Panorama.js | 4 +- 2 files changed, 45 insertions(+), 8 deletions(-) diff --git a/public/javascripts/Admin/src/Admin.GSVLabelView.js b/public/javascripts/Admin/src/Admin.GSVLabelView.js index 9f70d0c5c1..042dfd205c 100644 --- a/public/javascripts/Admin/src/Admin.GSVLabelView.js +++ b/public/javascripts/Admin/src/Admin.GSVLabelView.js @@ -85,13 +85,33 @@ function AdminGSVLabelView(admin) { '' + 'Pano ID' + '' + - ''; - if (self.admin) { - modalText += + '' + + '' + + 'Google Street View' + + '' + + '' + + '' + + 'Latitude' + + '' + + '' + + '' + + 'Longitude' + + '' + + '' + '' + 'Label ID' + '' + '' + + '' + + 'Street ID' + + '' + + '' + + '' + + 'Region ID' + + '' + + ''; + if (self.admin) { + modalText += '' + 'Task ID' + '' + @@ -150,8 +170,13 @@ function AdminGSVLabelView(admin) { self.modalValidations = self.modal.find("#label-validations"); self.modalImageDate = self.modal.find("#image-date"); self.modalTask = self.modal.find("#task"); - self.modalLabelId = self.modal.find("#label-id"); self.modalPanoId = self.modal.find('#pano-id'); + self.modalGsvLink = self.modal.find('#view-in-gsv'); + self.modalLat = self.modal.find('#lat'); + self.modalLng = self.modal.find('#lng'); + self.modalLabelId = self.modal.find("#label-id"); + self.modalStreetId = self.modal.find('#street-id'); + self.modalRegionId = self.modal.find('#region-id'); self.modalInfoHolder = self.modal.find('#info-popover-holder'); } @@ -304,8 +329,16 @@ function AdminGSVLabelView(admin) { } function _handleData(labelMetadata) { + // Pass a callback function that fills in the pano lat/lng + var panoCallback = function () { + var lat = self.panorama.getPosition().lat; + var lng = self.panorama.getPosition().lng; + self.modalGsvLink.html(`View in Google Street View`); + self.modalLat.html(lat.toFixed(8) + '°'); + self.modalLng.html(lng.toFixed(8) + '°'); + } self.panorama.setPano(labelMetadata['gsv_panorama_id'], labelMetadata['heading'], - labelMetadata['pitch'], labelMetadata['zoom']); + labelMetadata['pitch'], labelMetadata['zoom'], panoCallback); var adminPanoramaLabel = AdminPanoramaLabel(labelMetadata['label_id'], labelMetadata['label_type_key'], labelMetadata['canvas_x'], labelMetadata['canvas_y'], @@ -320,17 +353,19 @@ function AdminGSVLabelView(admin) { var labelDate = moment(new Date(labelMetadata['timestamp'])); var imageDate = moment(new Date(labelMetadata['image_date'])); self.modalTitle.html('Label Type: ' + labelMetadata['label_type_value']); - self.modalTimestamp.html(labelDate.format('LL, LT') + " (" + labelDate.fromNow() + ")"); self.modalLabelTypeValue.html(labelMetadata['label_type_value']); self.modalSeverity.html(labelMetadata['severity'] != null ? labelMetadata['severity'] : "No severity"); self.modalTemporary.html(labelMetadata['temporary'] ? i18next.t('common:yes'): i18next.t('common:no')); self.modalTags.html(labelMetadata['tags'].join(', ')); // Join to format using commas and spaces. self.modalDescription.html(labelMetadata['description'] != null ? labelMetadata['description'] : i18next.t('common:no-description')); self.modalValidations.html(validationsText); + self.modalTimestamp.html(labelDate.format('LL, LT') + " (" + labelDate.fromNow() + ")"); self.modalImageDate.html(imageDate.format('MMMM YYYY')); self.modalPanoId.html(labelMetadata['gsv_panorama_id']); + self.modalLabelId.html(labelMetadata['label_id']); + self.modalStreetId.html(labelMetadata['label_id']); + self.modalRegionId.html(labelMetadata['label_id']); if (self.admin) { - self.modalLabelId.html(labelMetadata['label_id']); self.modalTask.html(""+ labelMetadata['audit_task_id']+" by " + labelMetadata['username'] + ""); diff --git a/public/javascripts/Admin/src/Admin.Panorama.js b/public/javascripts/Admin/src/Admin.Panorama.js index 380b368111..01198b84a3 100644 --- a/public/javascripts/Admin/src/Admin.Panorama.js +++ b/public/javascripts/Admin/src/Admin.Panorama.js @@ -115,8 +115,9 @@ function AdminPanorama(svHolder, buttonHolder, admin) { * @param heading * @param pitch * @param zoom + * @param callbackParam */ - function setPano(panoId, heading, pitch, zoom) { + function setPano(panoId, heading, pitch, zoom, callbackParam) { if (typeof google != "undefined") { self.panorama.registerPanoProvider(function(pano) { if (pano === 'tutorial' || pano === 'afterWalkTutorial') { @@ -169,6 +170,7 @@ function AdminPanorama(svHolder, buttonHolder, admin) { } else { setTimeout(callback, 200, n - 1); } + callbackParam(); } setTimeout(callback, 200, 10); } From 888dce541600c428ced8679a36317e2bf7c26eb9 Mon Sep 17 00:00:00 2001 From: Mikey Saugstad Date: Wed, 12 Oct 2022 12:57:58 -0700 Subject: [PATCH 12/33] adds street_edge_id and region_id to LabelMap modal --- app/formats/json/LabelFormat.scala | 24 +++++++++++-------- app/models/label/LabelTable.scala | 22 ++++++++++------- .../Admin/src/Admin.GSVLabelView.js | 8 +++---- 3 files changed, 31 insertions(+), 23 deletions(-) diff --git a/app/formats/json/LabelFormat.scala b/app/formats/json/LabelFormat.scala index 1018ed311b..84e22e1466 100644 --- a/app/formats/json/LabelFormat.scala +++ b/app/formats/json/LabelFormat.scala @@ -82,14 +82,16 @@ object LabelFormat { "gsv_panorama_id" -> labelMetadata.gsvPanoramaId, "tutorial" -> labelMetadata.tutorial, "image_date" -> labelMetadata.imageDate, - "heading" -> labelMetadata.heading, - "pitch" -> labelMetadata.pitch, - "zoom" -> labelMetadata.zoom, + "heading" -> labelMetadata.headingPitchZoom._1, + "pitch" -> labelMetadata.headingPitchZoom._2, + "zoom" -> labelMetadata.headingPitchZoom._3, "canvas_x" -> labelMetadata.canvasXY._1, "canvas_y" -> labelMetadata.canvasXY._2, - "canvas_width" -> labelMetadata.canvasWidth, - "canvas_height" -> labelMetadata.canvasHeight, + "canvas_width" -> labelMetadata.canvasWidthHeight._1, + "canvas_height" -> labelMetadata.canvasWidthHeight._2, "audit_task_id" -> labelMetadata.auditTaskId, + "street_edge_id" -> labelMetadata.streetEdgeId, + "region_id" -> labelMetadata.regionId, "user_id" -> labelMetadata.userId, "username" -> labelMetadata.username, "timestamp" -> labelMetadata.timestamp, @@ -113,13 +115,15 @@ object LabelFormat { "gsv_panorama_id" -> labelMetadata.gsvPanoramaId, "tutorial" -> labelMetadata.tutorial, "image_date" -> labelMetadata.imageDate, - "heading" -> labelMetadata.heading, - "pitch" -> labelMetadata.pitch, - "zoom" -> labelMetadata.zoom, + "heading" -> labelMetadata.headingPitchZoom._1, + "pitch" -> labelMetadata.headingPitchZoom._2, + "zoom" -> labelMetadata.headingPitchZoom._3, "canvas_x" -> labelMetadata.canvasXY._1, "canvas_y" -> labelMetadata.canvasXY._2, - "canvas_width" -> labelMetadata.canvasWidth, - "canvas_height" -> labelMetadata.canvasHeight, + "canvas_width" -> labelMetadata.canvasWidthHeight._1, + "canvas_height" -> labelMetadata.canvasWidthHeight._2, + "street_edge_id" -> labelMetadata.streetEdgeId, + "region_id" -> labelMetadata.regionId, "timestamp" -> labelMetadata.timestamp, "label_type_key" -> labelMetadata.labelTypeKey, "label_type_value" -> labelMetadata.labelTypeValue, diff --git a/app/models/label/LabelTable.scala b/app/models/label/LabelTable.scala index 8aac535cc4..db0db52fe2 100644 --- a/app/models/label/LabelTable.scala +++ b/app/models/label/LabelTable.scala @@ -142,12 +142,12 @@ object LabelTable { case class LabelCountPerDay(date: String, count: Int) - case class LabelMetadata(labelId: Int, gsvPanoramaId: String, tutorial: Boolean, imageDate: String, heading: Float, - pitch: Float, zoom: Int, canvasXY: (Int, Int), canvasWidth: Int, canvasHeight: Int, - auditTaskId: Int, userId: String, username: String, timestamp: java.sql.Timestamp, - labelTypeKey: String, labelTypeValue: String, severity: Option[Int], temporary: Boolean, - description: Option[String], userValidation: Option[Int], validations: Map[String, Int], - tags: List[String]) + case class LabelMetadata(labelId: Int, gsvPanoramaId: String, tutorial: Boolean, imageDate: String, + headingPitchZoom: (Float, Float, Int), canvasXY: (Int, Int), canvasWidthHeight: (Int, Int), + auditTaskId: Int, streetEdgeId: Int, regionId: Int, userId: String, username: String, + timestamp: java.sql.Timestamp, labelTypeKey: String, labelTypeValue: String, + severity: Option[Int], temporary: Boolean, description: Option[String], + userValidation: Option[Int], validations: Map[String, Int], tags: List[String]) case class LabelMetadataUserDash(labelId: Int, gsvPanoramaId: String, heading: Float, pitch: Float, zoom: Int, canvasX: Int, canvasY: Int, canvasWidth: Int, canvasHeight: Int, labelType: String, @@ -176,9 +176,9 @@ object LabelTable { implicit val labelMetadataWithValidationConverter = GetResult[LabelMetadata](r => LabelMetadata( - r.nextInt, r.nextString, r.nextBoolean, r.nextString, r.nextFloat, r.nextFloat, r.nextInt, (r.nextInt, r.nextInt), - r.nextInt, r.nextInt, r.nextInt, r.nextString, r.nextString, r.nextTimestamp, r.nextString, r.nextString, - r.nextIntOption, r.nextBoolean, r.nextStringOption, r.nextIntOption, + r.nextInt, r.nextString, r.nextBoolean, r.nextString, (r.nextFloat, r.nextFloat, r.nextInt), + (r.nextInt, r.nextInt), (r.nextInt, r.nextInt), r.nextInt, r.nextInt, r.nextInt, r.nextString, r.nextString, + r.nextTimestamp, r.nextString, r.nextString, r.nextIntOption, r.nextBoolean, r.nextStringOption, r.nextIntOption, r.nextString.split(',').map(x => x.split(':')).map { y => (y(0), y(1).toInt) }.toMap, r.nextStringOption.map(tags => tags.split(",").toList).getOrElse(List()) ) @@ -395,6 +395,8 @@ object LabelTable { | lp.canvas_width, | lp.canvas_height, | lb1.audit_task_id, + | lb1.street_edge_id, + | ser.region_id, | u.user_id, | u.username, | lb1.time_created, @@ -409,6 +411,7 @@ object LabelTable { |FROM label AS lb1, | gsv_data, | audit_task AS at, + | street_edge_region AS ser, | sidewalk_user AS u, | label_point AS lp, | ( @@ -443,6 +446,7 @@ object LabelTable { | AND lb1.audit_task_id = at.audit_task_id | AND lb1.label_id = lb_big.label_id | AND at.user_id = u.user_id + | AND lb1.street_edge_id = ser.street_edge_id | AND lb1.label_id = lp.label_id | AND lb1.label_id = val.label_id | $labelFilter diff --git a/public/javascripts/Admin/src/Admin.GSVLabelView.js b/public/javascripts/Admin/src/Admin.GSVLabelView.js index 042dfd205c..d9a74b5e6d 100644 --- a/public/javascripts/Admin/src/Admin.GSVLabelView.js +++ b/public/javascripts/Admin/src/Admin.GSVLabelView.js @@ -329,11 +329,11 @@ function AdminGSVLabelView(admin) { } function _handleData(labelMetadata) { - // Pass a callback function that fills in the pano lat/lng + // Pass a callback function that fills in the pano lat/lng. var panoCallback = function () { var lat = self.panorama.getPosition().lat; var lng = self.panorama.getPosition().lng; - self.modalGsvLink.html(`View in Google Street View`); + self.modalGsvLink.html(`View in Google Street View`); self.modalLat.html(lat.toFixed(8) + '°'); self.modalLng.html(lng.toFixed(8) + '°'); } @@ -363,8 +363,8 @@ function AdminGSVLabelView(admin) { self.modalImageDate.html(imageDate.format('MMMM YYYY')); self.modalPanoId.html(labelMetadata['gsv_panorama_id']); self.modalLabelId.html(labelMetadata['label_id']); - self.modalStreetId.html(labelMetadata['label_id']); - self.modalRegionId.html(labelMetadata['label_id']); + self.modalStreetId.html(labelMetadata['street_edge_id']); + self.modalRegionId.html(labelMetadata['region_id']); if (self.admin) { self.modalTask.html(""+ labelMetadata['audit_task_id']+" by " + From 895dab31c62419d1c784d82ec8f764ec990e25b4 Mon Sep 17 00:00:00 2001 From: Mikey Saugstad Date: Wed, 12 Oct 2022 15:48:31 -0700 Subject: [PATCH 13/33] adds region_id and street_edge_id to Validate and Gallery popovers --- app/formats/json/LabelFormat.scala | 2 + app/models/label/LabelTable.scala | 32 ++++++---- app/views/mobileValidate.scala.html | 2 + app/views/validation.scala.html | 2 + public/javascripts/Gallery/src/Main.js | 2 +- public/javascripts/Gallery/src/cards/Card.js | 2 + public/javascripts/Gallery/src/modal/Modal.js | 6 +- public/javascripts/SVValidate/src/Main.js | 7 ++- .../javascripts/SVValidate/src/label/Label.js | 4 ++ .../src/mission/ValidationContainer.js | 59 ------------------- .../src/panorama/PanoramaContainer.js | 17 ++++++ 11 files changed, 59 insertions(+), 76 deletions(-) delete mode 100644 public/javascripts/SVValidate/src/mission/ValidationContainer.js diff --git a/app/formats/json/LabelFormat.scala b/app/formats/json/LabelFormat.scala index 84e22e1466..5837ad41cf 100644 --- a/app/formats/json/LabelFormat.scala +++ b/app/formats/json/LabelFormat.scala @@ -71,6 +71,8 @@ object LabelFormat { "severity" -> labelMetadata.severity, "temporary" -> labelMetadata.temporary, "description" -> labelMetadata.description, + "street_edge_id" -> labelMetadata.streetEdgeId, + "region_id" -> labelMetadata.regionId, "user_validation" -> labelMetadata.userValidation.map(LabelValidationTable.validationOptions.get), "tags" -> labelMetadata.tags ) diff --git a/app/models/label/LabelTable.scala b/app/models/label/LabelTable.scala index db0db52fe2..f0dc6397c2 100644 --- a/app/models/label/LabelTable.scala +++ b/app/models/label/LabelTable.scala @@ -158,13 +158,14 @@ object LabelTable { timestamp: java.sql.Timestamp, heading: Float, pitch: Float, zoom: Int, canvasX: Int, canvasY: Int, canvasWidth: Int, canvasHeight: Int, severity: Option[Int], temporary: Boolean, description: Option[String], - userValidation: Option[Int], tags: List[String]) extends BasicLabelMetadata + streetEdgeId: Int, regionId: Int, userValidation: Option[Int], tags: List[String]) extends BasicLabelMetadata case class LabelValidationMetadataWithoutTags(labelId: Int, labelType: String, gsvPanoramaId: String, imageDate: String, timestamp: java.sql.Timestamp, heading: Float, pitch: Float, zoom: Int, canvasX: Int, canvasY: Int, canvasWidth: Int, canvasHeight: Int, severity: Option[Int], temporary: Boolean, - description: Option[String], userValidation: Option[Int]) extends BasicLabelMetadata + description: Option[String], streetEdgeId: Int, regionId: Int, + userValidation: Option[Int]) extends BasicLabelMetadata case class ResumeLabelMetadata(labelData: Label, labelType: String, pointData: LabelPoint, svImageWidth: Int, svImageHeight: Int, tagIds: List[Int]) @@ -188,15 +189,15 @@ object LabelTable { LabelValidationMetadataWithoutTags( r.nextInt, r.nextString, r.nextString, r.nextString, r.nextTimestamp, r.nextFloat, r.nextFloat, r.nextInt, r.nextInt, r.nextInt, r.nextInt, r.nextInt, r.nextIntOption, r.nextBoolean, - r.nextStringOption, r.nextIntOption + r.nextStringOption, r.nextInt, r.nextInt, r.nextIntOption ) ) implicit val labelValidationMetadataConverter = GetResult[LabelValidationMetadata](r => LabelValidationMetadata( r.nextInt, r.nextString, r.nextString, r.nextString, r.nextTimestamp, r.nextFloat, r.nextFloat, r.nextInt, - r.nextInt, r.nextInt, r.nextInt, r.nextInt, r.nextIntOption, r.nextBoolean, r.nextStringOption, r.nextIntOption, - r.nextStringOption.map(tags => tags.split(",").toList).getOrElse(List()) + r.nextInt, r.nextInt, r.nextInt, r.nextInt, r.nextIntOption, r.nextBoolean, r.nextStringOption, r.nextInt, + r.nextInt, r.nextIntOption, r.nextStringOption.map(tags => tags.split(",").toList).getOrElse(List()) ) ) @@ -516,7 +517,8 @@ object LabelTable { s"""SELECT label.label_id, label_type.label_type, label.gsv_panorama_id, gsv_data.image_date, | label.time_created, label_point.heading, label_point.pitch, label_point.zoom, label_point.canvas_x, | label_point.canvas_y, label_point.canvas_width, label_point.canvas_height, label.severity, - | label.temporary, label.description, user_validation.validation_result, the_tags.tag_list + | label.temporary, label.description, label.street_edge_id, street_edge_region.region_id, + | user_validation.validation_result, the_tags.tag_list |FROM label |INNER JOIN label_type ON label.label_type_id = label_type.label_type_id |INNER JOIN label_point ON label.label_id = label_point.label_id @@ -524,6 +526,7 @@ object LabelTable { |INNER JOIN mission ON label.mission_id = mission.mission_id |INNER JOIN user_stat ON mission.user_id = user_stat.user_id |INNER JOIN audit_task ON label.audit_task_id = audit_task.audit_task_id + |INNER JOIN street_edge_region ON label.street_edge_id = street_edge_region.street_edge_id |LEFT JOIN ( | -- This subquery counts how many of each users' labels have been validated. If it's less than 50, then we | -- need more validations from them in order to infer worker quality, and they therefore get priority. @@ -619,12 +622,13 @@ object LabelTable { _tags <- tagTable if _labelTags.tagId === _tags.tagId && ((_tags.tag inSet tags) || tags.isEmpty) _a <- auditTasks if _lb.auditTaskId === _a.auditTaskId _us <- UserStatTable.userStats if _a.userId === _us.userId + _ser <- StreetEdgeRegionTable.streetEdgeRegionTable if _lb.streetEdgeId === _ser.streetEdgeId if _lb.labelTypeId === labelTypeId if _gd.expired === false if _us.highQuality || (_lb.correct.isDefined && _lb.correct === true) if _lb.disagreeCount < 3 || _lb.disagreeCount < _lb.agreeCount * 2 if _lb.severity.isEmpty || (_lb.severity inSet severity) - } yield (_lb, _lp, _lt, _gd) + } yield (_lb, _lp, _lt, _gd, _ser) // Join with the validations that the user has given. val userValidations = validationsFromUser(userId) @@ -632,7 +636,7 @@ object LabelTable { (l, v) <- _galleryLabels.leftJoin(userValidations).on(_._1.labelId === _._1) } yield (l._1.labelId, l._3.labelType, l._1.gsvPanoramaId, l._4.imageDate, l._1.timeCreated, l._2.heading, l._2.pitch, l._2.zoom, l._2.canvasX, l._2.canvasY, l._2.canvasWidth, l._2.canvasHeight, l._1.severity, - l._1.temporary, l._1.description, v._2.?) + l._1.temporary, l._1.description, l._1.streetEdgeId, l._5.regionId, v._2.?) // Remove duplicates that we got from joining with the `label_tag` table. val uniqueLabels = addValidations.groupBy(x => x).map(_._1) @@ -662,10 +666,11 @@ object LabelTable { _gd <- gsvData if _lb.gsvPanoramaId === _gd.gsvPanoramaId _a <- auditTasks if _lb.auditTaskId === _a.auditTaskId _us <- UserStatTable.userStats if _a.userId === _us.userId + _ser <- StreetEdgeRegionTable.streetEdgeRegionTable if _lb.streetEdgeId === _ser.streetEdgeId if _gd.expired === false if _us.highQuality || (_lb.correct.isDefined && _lb.correct === true) if _lb.disagreeCount < 3 || _lb.disagreeCount < _lb.agreeCount * 2 - } yield (_lb, _lp, _lt, _gd) + } yield (_lb, _lp, _lt, _gd, _ser) // If severities are specified, filter by whether a label has a valid severity. val _labels = if (severity.isDefined && severity.get.nonEmpty) @@ -679,7 +684,7 @@ object LabelTable { (l, v) <- _labels.leftJoin(userValidations).on(_._1.labelId === _._1) } yield (l._1.labelId, l._3.labelType, l._1.gsvPanoramaId, l._4.imageDate, l._1.timeCreated, l._2.heading, l._2.pitch, l._2.zoom, l._2.canvasX, l._2.canvasY, l._2.canvasWidth, l._2.canvasHeight, l._1.severity, - l._1.temporary, l._1.description, v._2.?) + l._1.temporary, l._1.description, l._1.streetEdgeId, l._5.regionId, v._2.?) // Run query, group by label type, and randomize order. val potentialLabels: Map[String, List[LabelValidationMetadataWithoutTags]] = @@ -712,11 +717,12 @@ object LabelTable { _gd <- gsvData if _lb.gsvPanoramaId === _gd.gsvPanoramaId _a <- auditTasks if _lb.auditTaskId === _a.auditTaskId _us <- UserStatTable.userStats if _a.userId === _us.userId + _ser <- StreetEdgeRegionTable.streetEdgeRegionTable if _lb.streetEdgeId === _ser.streetEdgeId if _lb.labelTypeId === labelTypeId if _gd.expired === false if _us.highQuality || (_lb.correct.isDefined && _lb.correct === true) if _lb.disagreeCount < 3 || _lb.disagreeCount < _lb.agreeCount * 2 - } yield (_lb, _lp, _lt, _gd) + } yield (_lb, _lp, _lt, _gd, _ser) // Join with the validations that the user has given. val userValidations = validationsFromUser(userId) @@ -724,7 +730,7 @@ object LabelTable { (l, v) <- _labels.leftJoin(userValidations).on(_._1.labelId === _._1) } yield (l._1.labelId, l._3.labelType, l._1.gsvPanoramaId, l._4.imageDate, l._1.timeCreated, l._2.heading, l._2.pitch, l._2.zoom, l._2.canvasX, l._2.canvasY, l._2.canvasWidth, l._2.canvasHeight, l._1.severity, - l._1.temporary, l._1.description, v._2.?) + l._1.temporary, l._1.description, l._1.streetEdgeId, l._5.regionId, v._2.?) // Randomize and convert to LabelValidationMetadataWithoutTags. val newRandomLabelsList = addValidations.sortBy(x => rand).list.map(LabelValidationMetadataWithoutTags.tupled) @@ -893,7 +899,7 @@ object LabelTable { LabelValidationMetadata( label.labelId, label.labelType, label.gsvPanoramaId, label.imageDate, label.timestamp, label.heading, label.pitch, label.zoom, label.canvasX, label.canvasY, label.canvasWidth, label.canvasHeight, label.severity, - label.temporary, label.description, label.userValidation, tags + label.temporary, label.description, label.streetEdgeId, label.regionId, label.userValidation, tags ) } diff --git a/app/views/mobileValidate.scala.html b/app/views/mobileValidate.scala.html index 62f7fc5f97..1447011949 100644 --- a/app/views/mobileValidate.scala.html +++ b/app/views/mobileValidate.scala.html @@ -228,6 +228,8 @@

@Messages("validate.mission.complete.category")

severity: param.labelList[key].severity, temporary: param.labelList[key].temporary, description: param.labelList[key].description, + streetEdgeId: param.labelList[key].street_edge_id, + regionId: param.labelList[key].region_id, tags: param.labelList[key].tags }; param.labelList[key] = new Label(labelMetadata); diff --git a/app/views/validation.scala.html b/app/views/validation.scala.html index ac8305c44a..60e4ea4afa 100644 --- a/app/views/validation.scala.html +++ b/app/views/validation.scala.html @@ -283,6 +283,8 @@

severity: param.labelList[key].severity, temporary: param.labelList[key].temporary, description: param.labelList[key].description, + streetEdgeId: param.labelList[key].street_edge_id, + regionId: param.labelList[key].region_id, tags: param.labelList[key].tags }; param.labelList[key] = new Label(labelMetadata); diff --git a/public/javascripts/Gallery/src/Main.js b/public/javascripts/Gallery/src/Main.js index 292b1d0169..d0e58b381f 100644 --- a/public/javascripts/Gallery/src/Main.js +++ b/public/javascripts/Gallery/src/Main.js @@ -74,7 +74,7 @@ function Main (params) { sg.tagContainer = new CardFilter(sg.ui.cardFilter, sg.labelTypeMenu, sg.cityMenu); sg.cardContainer = new CardContainer(sg.ui.cardContainer); sg.modal = sg.cardContainer.getModal; - sg.infoPopover = new GSVInfoPopOver($('.pano-timestamp'), sg.modal().pano.panorama, sg.modal().pano.getPosition, sg.modal().pano.getPanoId, null, null, sg.modal().pano.getPov); + // sg.infoPopover = new GSVInfoPopOver($('.pano-timestamp'), sg.modal().pano.panorama, sg.modal().pano.getPosition, sg.modal().pano.getPanoId, null, null, sg.modal().pano.getPov); // Initialize data collection. sg.form = new Form(params.dataStoreUrl, params.beaconDataStoreUrl) sg.tracker = new Tracker(); diff --git a/public/javascripts/Gallery/src/cards/Card.js b/public/javascripts/Gallery/src/cards/Card.js index e3eb5ae9cb..3fcea247bb 100644 --- a/public/javascripts/Gallery/src/cards/Card.js +++ b/public/javascripts/Gallery/src/cards/Card.js @@ -33,6 +33,8 @@ function Card (params, imageUrl, modal) { severity: undefined, temporary: undefined, description: undefined, + street_edge_id: undefined, + region_id: undefined, user_validation: undefined, tags: [] }; diff --git a/public/javascripts/Gallery/src/modal/Modal.js b/public/javascripts/Gallery/src/modal/Modal.js index 897384a43c..16053ae736 100644 --- a/public/javascripts/Gallery/src/modal/Modal.js +++ b/public/javascripts/Gallery/src/modal/Modal.js @@ -51,6 +51,8 @@ function Modal(uiModal) { severity: undefined, temporary: undefined, description: undefined, + streetEdgeId: undefined, + regionId: undefined, user_validation: undefined, tags: [] }; @@ -168,7 +170,9 @@ function Modal(uiModal) { function openModal() { resetModal(); populateModalDescriptionFields(); - sg.infoPopover = new GSVInfoPopOver(self.labelTimestampData, sg.modal().pano.panorama, sg.modal().pano.getPosition, sg.modal().pano.getPanoId, null, null, sg.modal().pano.getPov); + sg.infoPopover = new GSVInfoPopOver(self.labelTimestampData, sg.modal().pano.panorama, + sg.modal().pano.getPosition, sg.modal().pano.getPanoId, function() { return properties['street_edge_id']; }, + function() { return properties['region_id']; }, sg.modal().pano.getPov); self.pano.setPano(properties.gsv_panorama_id, properties.heading, properties.pitch, properties.zoom); self.pano.renderLabel(self.label); self.header.text(i18next.t(util.camelToKebab(properties.label_type))); diff --git a/public/javascripts/SVValidate/src/Main.js b/public/javascripts/SVValidate/src/Main.js index ce0ea00570..96e3e88936 100644 --- a/public/javascripts/SVValidate/src/Main.js +++ b/public/javascripts/SVValidate/src/Main.js @@ -147,7 +147,8 @@ function Main (param) { svv.statusExample = new StatusExample(svv.ui.status.examples); svv.tracker = new Tracker(); svv.labelDescriptionBox = new LabelDescriptionBox(); - svv.validationContainer = new ValidationContainer(param.labelList); + svv.labelContainer = new LabelContainer(); + svv.panoramaContainer = new PanoramaContainer(param.labelList); // There are certain features that will only make sense on desktop. if (!isMobile()) { @@ -170,7 +171,9 @@ function Main (param) { svv.modalInfo = new ModalInfo(svv.ui.modalInfo, param.modalText); svv.modalLandscape = new ModalLandscape(svv.ui.modalLandscape); svv.modalNoNewMission = new ModalNoNewMission(svv.ui.modalMission); - svv.infoPopover = new GSVInfoPopOver(svv.ui.dateHolder, svv.panorama.getPanorama(), svv.panorama.getPosition, svv.panorama.getPanoId, null, null, svv.panorama.getPov); + svv.infoPopover = new GSVInfoPopOver(svv.ui.dateHolder, svv.panorama.getPanorama(), svv.panorama.getPosition, + svv.panorama.getPanoId, svv.panoramaContainer.getCurrentLabelStreetEdgeId, + svv.panoramaContainer.getCurrentLabelRegionId, svv.panorama.getPov); svv.missionContainer = new MissionContainer(); svv.missionContainer.createAMission(param.mission, param.progress); diff --git a/public/javascripts/SVValidate/src/label/Label.js b/public/javascripts/SVValidate/src/label/Label.js index 0471b05abb..9297a90d70 100644 --- a/public/javascripts/SVValidate/src/label/Label.js +++ b/public/javascripts/SVValidate/src/label/Label.js @@ -23,6 +23,8 @@ function Label(params) { severity: undefined, temporary: undefined, description: undefined, + streetEdgeId: undefined, + regionId: undefined, tags: undefined, isMobile: undefined }; @@ -99,6 +101,8 @@ function Label(params) { if ("severity" in params) setAuditProperty("severity", params.severity); if ("temporary" in params) setAuditProperty("temporary", params.temporary); if ("description" in params) setAuditProperty("description", params.description); + if ("streetEdgeId" in params) setAuditProperty("streetEdgeId", params.streetEdgeId); + if ("regionId" in params) setAuditProperty("regionId", params.regionId); if ("tags" in params) setAuditProperty("tags", params.tags); setAuditProperty("isMobile", isMobile()); } diff --git a/public/javascripts/SVValidate/src/mission/ValidationContainer.js b/public/javascripts/SVValidate/src/mission/ValidationContainer.js deleted file mode 100644 index 3720bbb445..0000000000 --- a/public/javascripts/SVValidate/src/mission/ValidationContainer.js +++ /dev/null @@ -1,59 +0,0 @@ -/** - * Container holding the validation panorama. - * @param labelList Initial list of labels to validate for this mission - * @returns {ValidationContainer} - * @constructor - */ -function ValidationContainer (labelList) { - svv.panoramaContainer = undefined; - svv.labelContainer = undefined; - - let properties = { - agreeButtonList: undefined, - disagreeButtonList: undefined, - labelList: undefined, - notSureButtonList: undefined - }; - - let self = this; - - function _init() { - setProperty("labelList", labelList); - _createContainers(); - } - - /** - * Initializes the panoramaContainer and labelContainer. - * @private - */ - function _createContainers() { - svv.labelContainer = new LabelContainer(); - svv.panoramaContainer = new PanoramaContainer(labelList); - } - - /** - * Gets a specific validation property of this label. - * @param key Name of property. - * @returns Value associated with this key. - */ - function getProperty (key) { - return key in properties ? properties[key] : null; - } - - /** - * Sets the value of a single property in properties. - * @param key Name of property - * @param value Value to set property to. - */ - function setProperty(key, value) { - properties[key] = value; - return this; - } - - _init(); - - self.getProperty = getProperty; - self.setProperty = setProperty; - - return this; -} diff --git a/public/javascripts/SVValidate/src/panorama/PanoramaContainer.js b/public/javascripts/SVValidate/src/panorama/PanoramaContainer.js index 78c3923435..48b496d78f 100644 --- a/public/javascripts/SVValidate/src/panorama/PanoramaContainer.js +++ b/public/javascripts/SVValidate/src/panorama/PanoramaContainer.js @@ -47,6 +47,8 @@ function PanoramaContainer (labelList) { severity: metadata.severity, temporary: metadata.temporary, description: metadata.description, + streetEdgeId: metadata.streetEdgeId, + regionId: metadata.regionId, tags: metadata.tags }; return new Label(labelMetadata); @@ -108,6 +110,18 @@ function PanoramaContainer (labelList) { } } + function getCurrentLabel() { + return labels[getProperty('progress') - 1]; + } + + function getCurrentLabelStreetEdgeId() { + return getCurrentLabel().getAuditProperty('streetEdgeId'); + } + + function getCurrentLabelRegionId() { + return getCurrentLabel().getAuditProperty('regionId'); + } + /** * Resets the validation interface for a new mission. Loads a new set of label onto the panoramas. */ @@ -151,6 +165,9 @@ function PanoramaContainer (labelList) { self.fetchNewLabel = fetchNewLabel; self.getProperty = getProperty; self.loadNewLabelOntoPanorama = loadNewLabelOntoPanorama; + self.getCurrentLabel = getCurrentLabel; + self.getCurrentLabelStreetEdgeId = getCurrentLabelStreetEdgeId; + self.getCurrentLabelRegionId = getCurrentLabelRegionId; self.setProperty = setProperty; self.reset = reset; self.setLabelList = setLabelList; From a6f9b9983c0f56f3b7985e116d636f747280e31f Mon Sep 17 00:00:00 2001 From: Mikey Saugstad Date: Wed, 12 Oct 2022 15:56:42 -0700 Subject: [PATCH 14/33] cleans up info button popover code a bit --- public/javascripts/common/GSVInfoPopOver.js | 105 ++++++-------------- 1 file changed, 33 insertions(+), 72 deletions(-) diff --git a/public/javascripts/common/GSVInfoPopOver.js b/public/javascripts/common/GSVInfoPopOver.js index 2f6f677d37..1c0aba2e98 100644 --- a/public/javascripts/common/GSVInfoPopOver.js +++ b/public/javascripts/common/GSVInfoPopOver.js @@ -12,48 +12,10 @@ * update values method */ function GSVInfoPopOver (container, panorama, coords, panoId, streetEdgeId, regionId, pov) { - /* - DELETE ONCE FINISHED - Back-end API TODO: - Here's the list of all the references to parameters (coords, panoId, etc.) I've found/created on each page. - The blank ones are the ones that need changes to the backend API to grab that info from the database. - - LabelMap was configured differently so I couldn't figure out how to get the bootstrap popover to function on - that page? - - Audit: (located in public/javascripts/SVLabel/src/Main.js) DONE - Panorama: svl.panorama - Coords: svl.map.getPosition - PanoId: svl.map.getPanoId - StreetEdgeId: svl.taskContainer.getCurrentTask().getStreetEdgeId - RegionId: svl.taskContainer.getCurrentTask().getRegionId - POV: svl.map.getPov - Gallery: (located in public/javascripts/Gallery/src/Main.js) - Panorama: sg.modal().pano.panorama - Coords: sg.modal().pano.getPosition - PanoId: sg.modal().pano.getPanoId - StreetEdgeId: - RegionId: - POV: sg.modal().pano.getPov - Validate: (located in public/javascripts/SVValidate/src/Main.js) - Panorama: svv.panorama.getPanorama() - Coords: svv.panorama.getPosition - PanoId: svv.panorama.getPanoId - StreetEdgeId: - RegionId: - POV: svv.panorama.getPov - LabelMap: (located in public/javascripts/Admin/src/Admin.GSVLabelView.js) - Panorama: self.panorama.panorama - Coords: self.panorama.getPosition - PanoId: self.panorama.getPanoId - StreetEdgeId: - RegionId: - POV: self.panorama.getPov - */ let self = this; function _init() { - // Create popover title bar + // Create popover title bar. self.titleBox = document.createElement('div'); let title = document.createElement('span'); @@ -75,10 +37,10 @@ function GSVInfoPopOver (container, panorama, coords, panoId, streetEdgeId, regi self.titleBox.appendChild(clipboard); - // Create popover content + // Create popover content. self.popoverContent = document.createElement('div'); - // Add in container for each info type to the popover + // Add in container for each info type to the popover. let dataList = document.createElement('ul'); dataList.classList.add('list-group', 'list-group-flush'); @@ -90,7 +52,7 @@ function GSVInfoPopOver (container, panorama, coords, panoId, streetEdgeId, regi self.popoverContent.appendChild(dataList); - // Create link to separate GSV + // Create link to separate GSV. let linkGSV = document.createElement('a'); linkGSV.classList.add('popover-element'); linkGSV.id = 'gsv-link' @@ -98,40 +60,37 @@ function GSVInfoPopOver (container, panorama, coords, panoId, streetEdgeId, regi self.popoverContent.appendChild(linkGSV); - // Create info button and add popover attributes + // Create info button and add popover attributes. self.infoButton = document.createElement('img'); self.infoButton.classList.add('popover-element'); self.infoButton.id = 'info-button'; self.infoButton.src = '/assets/javascripts/SVLabel/img/misc/gsv_info_btn.png'; self.infoButton.setAttribute('data-toggle', 'popover'); - self.infoButton.setAttribute('data-placement', 'top'); - self.infoButton.setAttribute('title', self.titleBox.innerHTML); - self.infoButton.setAttribute('data-content', self.popoverContent.innerHTML); container.append(self.infoButton); // Enable popovers/tooltips and set options $('#info-button').popover({ html: true, - container: $('body'), - }); - $('#clipboard').tooltip(); - - // Update popover everytime it opens - $('#info-button').on('click', updateVals); - - // Dismiss popover on clicking outside of popover - $('#info-button').on('shown.bs.popover', () => { + placement: 'top', + container: 'body', + title: self.titleBox.innerHTML, + content: self.popoverContent.innerHTML + }).on('click', updateVals).on('shown.bs.popover', () => { + // Add popover-element classes to more elements, making it easier to dismiss popover on when outside it. $('.popover-title').addClass('popover-element'); $('.popover-content').addClass('popover-element'); }); - $('html').on('mousedown', (e) => { + $('#clipboard').tooltip(); + + // Dismiss popover when clicking outside it. Anything without the 'popover-element' class is considered outside. + $(document).on('click', (e) => { let tar = $(e.target); - if (tar[0].className.indexOf('popover-element') === -1) { + if (!tar[0].classList.contains('popover-element')) { $('#info-button').popover('hide'); } }); - // Dismiss popover whenver panorama changes + // Dismiss popover whenever panorama changes. panorama.addListener('pano_changed', () => { $('#info-button').popover('hide'); }) @@ -139,14 +98,14 @@ function GSVInfoPopOver (container, panorama, coords, panoId, streetEdgeId, regi /** - * Update the values within the popover + * Update the values within the popover. */ function updateVals() { - // Position popover - let xpos = self.infoButton.getBoundingClientRect().x + (self.infoButton.getBoundingClientRect().width / 2) - 175 + // Position popover. + let xpos = self.infoButton.getBoundingClientRect().x + (self.infoButton.getBoundingClientRect().width / 2) - 175; $('.popover').css('left', `${xpos}px`); - // Get info values + // Get info values. const currCoords = coords ? coords() : {lat: null, lng: null}; const currPanoId = panoId ? panoId() : null; const currStreetEdgeId = streetEdgeId ? streetEdgeId() : null; @@ -169,25 +128,27 @@ function GSVInfoPopOver (container, panorama, coords, panoId, streetEdgeId, regi changeVals('Street Edge ID', currStreetEdgeId); changeVals('Region ID', currRegionId) - // Create GSV link - $('#gsv-link').attr('href', `https://www.google.com/maps/@?api=1&map_action=pano&viewpoint=${currCoords.lat}%2C${currCoords.lng}&heading=${currPov.heading}&pitch=${currPov.pitch}`); - $('#gsv-link').attr('target', '_blank'); + // Create GSV link. + let gsvLink = $('#gsv-link'); + gsvLink.attr('href', `https://www.google.com/maps/@?api=1&map_action=pano&viewpoint=${currCoords.lat}%2C${currCoords.lng}&heading=${currPov.heading}&pitch=${currPov.pitch}`); + gsvLink.attr('target', '_blank'); - // Copy to clipboard - $('#clipboard').click(() => { - $('#clipboard').tooltip('enable'); - $('#clipboard').tooltip('show'); + // Copy to clipboard. + let clipboardElem = $('#clipboard'); + clipboardElem.click(() => { + clipboardElem.tooltip('enable'); + clipboardElem.tooltip('show'); navigator.clipboard.writeText( `Latitude: ${currCoords.lat}°\nLongitude: ${currCoords.lng}°\nPano ID: ${currPanoId}\nStreet Edge ID: ${currStreetEdgeId}\nRegion ID: ${currRegionId}` ); }); - $('#clipboard').on('mouseout', () => { - $('#clipboard').tooltip('disable'); + clipboardElem.on('mouseout', () => { + clipboardElem.tooltip('disable'); }); } /** - * Creates a key-value pair display within the popover + * Creates a key-value pair display within the popover. * @param {String} key Key name of the key-value pair * @param {HTMLElement} dataList List element container to add list item to */ From 67dc706205be16567f948547d324bc5653cd5fcc Mon Sep 17 00:00:00 2001 From: Mikey Saugstad Date: Thu, 13 Oct 2022 09:27:09 -0700 Subject: [PATCH 15/33] Gallery info button now refreshes data on new images --- public/javascripts/Gallery/src/modal/Modal.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/public/javascripts/Gallery/src/modal/Modal.js b/public/javascripts/Gallery/src/modal/Modal.js index 16053ae736..2671b17da7 100644 --- a/public/javascripts/Gallery/src/modal/Modal.js +++ b/public/javascripts/Gallery/src/modal/Modal.js @@ -139,6 +139,13 @@ function Modal(uiModal) { self.timestamps.append(self.labelTimestampData); self.timestamps.append(panoTimestampData); + // Add info button to the right of the label timestamp. + self.infoPopover = new GSVInfoPopOver(self.labelTimestampData, sg.modal().pano.panorama, + sg.modal().pano.getPosition, sg.modal().pano.getPanoId, + function () { return properties['street_edge_id']; }, function () { return properties['region_id']; }, + sg.modal().pano.getPov + ); + // Add severity and tag display to the modal. new SeverityDisplay(self.severity, properties.severity, properties.label_type, true); new TagDisplay(self.tags, properties.tags, true); @@ -170,9 +177,6 @@ function Modal(uiModal) { function openModal() { resetModal(); populateModalDescriptionFields(); - sg.infoPopover = new GSVInfoPopOver(self.labelTimestampData, sg.modal().pano.panorama, - sg.modal().pano.getPosition, sg.modal().pano.getPanoId, function() { return properties['street_edge_id']; }, - function() { return properties['region_id']; }, sg.modal().pano.getPov); self.pano.setPano(properties.gsv_panorama_id, properties.heading, properties.pitch, properties.zoom); self.pano.renderLabel(self.label); self.header.text(i18next.t(util.camelToKebab(properties.label_type))); From 6e70ef02bde40e76a4f8eac29b521c4c51ff66c2 Mon Sep 17 00:00:00 2001 From: Mikey Saugstad Date: Thu, 13 Oct 2022 09:30:39 -0700 Subject: [PATCH 16/33] fixes Gallery info popover not closing when clicking next button --- public/javascripts/common/GSVInfoPopOver.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/javascripts/common/GSVInfoPopOver.js b/public/javascripts/common/GSVInfoPopOver.js index 1c0aba2e98..a3928e7745 100644 --- a/public/javascripts/common/GSVInfoPopOver.js +++ b/public/javascripts/common/GSVInfoPopOver.js @@ -84,7 +84,7 @@ function GSVInfoPopOver (container, panorama, coords, panoId, streetEdgeId, regi $('#clipboard').tooltip(); // Dismiss popover when clicking outside it. Anything without the 'popover-element' class is considered outside. - $(document).on('click', (e) => { + $(document).on('mousedown', (e) => { let tar = $(e.target); if (!tar[0].classList.contains('popover-element')) { $('#info-button').popover('hide'); From 10e82bae1ea2d53c8329e7697f550c2ed935b707 Mon Sep 17 00:00:00 2001 From: Mikey Saugstad Date: Thu, 13 Oct 2022 09:53:07 -0700 Subject: [PATCH 17/33] info button on gallery no longer covered by validation border --- public/javascripts/Gallery/css/modal.css | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/public/javascripts/Gallery/css/modal.css b/public/javascripts/Gallery/css/modal.css index a2461c8581..2ec426fdb1 100644 --- a/public/javascripts/Gallery/css/modal.css +++ b/public/javascripts/Gallery/css/modal.css @@ -105,7 +105,8 @@ justify-content: space-between; width: 100%; font-size: .8vw; - padding-bottom: 1%; + padding-bottom: 0.9%; + padding-top: 0.1%; } .gallery-modal-info-severity { From f6ac85d8d6a0f0b53db4853d686696b5e1a64869 Mon Sep 17 00:00:00 2001 From: Mikey Saugstad Date: Thu, 13 Oct 2022 10:38:29 -0700 Subject: [PATCH 18/33] info button vertically centered in Gallery --- public/javascripts/Gallery/css/modal.css | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/public/javascripts/Gallery/css/modal.css b/public/javascripts/Gallery/css/modal.css index 2ec426fdb1..9f1125289f 100644 --- a/public/javascripts/Gallery/css/modal.css +++ b/public/javascripts/Gallery/css/modal.css @@ -30,8 +30,10 @@ } #info-button { - width: 15px; - margin: 0 3px 3px 7px; + width: 0.9vw; + height: 0.9vw; + margin-left: 5px; + margin-top: 2px; } .modal-severity-header, .modal-tag-header, .modal-temporary-header, .modal-description-header { From 1ba477bc3a0dc2b2ead8b60dc1e41ad19a76899c Mon Sep 17 00:00:00 2001 From: Mikey Saugstad Date: Thu, 13 Oct 2022 10:55:34 -0700 Subject: [PATCH 19/33] adds label ID to info button on Validate and Gallery --- public/javascripts/Gallery/src/modal/Modal.js | 3 ++- public/javascripts/SVValidate/src/Main.js | 8 ++++++-- .../SVValidate/src/panorama/PanoramaContainer.js | 10 ---------- public/javascripts/common/GSVInfoPopOver.js | 10 +++++++--- 4 files changed, 15 insertions(+), 16 deletions(-) diff --git a/public/javascripts/Gallery/src/modal/Modal.js b/public/javascripts/Gallery/src/modal/Modal.js index 2671b17da7..9700b63d60 100644 --- a/public/javascripts/Gallery/src/modal/Modal.js +++ b/public/javascripts/Gallery/src/modal/Modal.js @@ -143,8 +143,9 @@ function Modal(uiModal) { self.infoPopover = new GSVInfoPopOver(self.labelTimestampData, sg.modal().pano.panorama, sg.modal().pano.getPosition, sg.modal().pano.getPanoId, function () { return properties['street_edge_id']; }, function () { return properties['region_id']; }, - sg.modal().pano.getPov + sg.modal().pano.getPov, function () { return properties['label_id']; } ); + console.log(properties['label_id']); // Add severity and tag display to the modal. new SeverityDisplay(self.severity, properties.severity, properties.label_type, true); diff --git a/public/javascripts/SVValidate/src/Main.js b/public/javascripts/SVValidate/src/Main.js index 96e3e88936..080d8f7071 100644 --- a/public/javascripts/SVValidate/src/Main.js +++ b/public/javascripts/SVValidate/src/Main.js @@ -172,8 +172,12 @@ function Main (param) { svv.modalLandscape = new ModalLandscape(svv.ui.modalLandscape); svv.modalNoNewMission = new ModalNoNewMission(svv.ui.modalMission); svv.infoPopover = new GSVInfoPopOver(svv.ui.dateHolder, svv.panorama.getPanorama(), svv.panorama.getPosition, - svv.panorama.getPanoId, svv.panoramaContainer.getCurrentLabelStreetEdgeId, - svv.panoramaContainer.getCurrentLabelRegionId, svv.panorama.getPov); + svv.panorama.getPanoId, + function() { return svv.panoramaContainer.getCurrentLabel().getAuditProperty('streetEdgeId'); }, + function() { return svv.panoramaContainer.getCurrentLabel().getAuditProperty('regionId'); }, + svv.panorama.getPov, + function() { return svv.panoramaContainer.getCurrentLabel().getAuditProperty('labelId'); } + ); svv.missionContainer = new MissionContainer(); svv.missionContainer.createAMission(param.mission, param.progress); diff --git a/public/javascripts/SVValidate/src/panorama/PanoramaContainer.js b/public/javascripts/SVValidate/src/panorama/PanoramaContainer.js index 48b496d78f..c879036a08 100644 --- a/public/javascripts/SVValidate/src/panorama/PanoramaContainer.js +++ b/public/javascripts/SVValidate/src/panorama/PanoramaContainer.js @@ -114,14 +114,6 @@ function PanoramaContainer (labelList) { return labels[getProperty('progress') - 1]; } - function getCurrentLabelStreetEdgeId() { - return getCurrentLabel().getAuditProperty('streetEdgeId'); - } - - function getCurrentLabelRegionId() { - return getCurrentLabel().getAuditProperty('regionId'); - } - /** * Resets the validation interface for a new mission. Loads a new set of label onto the panoramas. */ @@ -166,8 +158,6 @@ function PanoramaContainer (labelList) { self.getProperty = getProperty; self.loadNewLabelOntoPanorama = loadNewLabelOntoPanorama; self.getCurrentLabel = getCurrentLabel; - self.getCurrentLabelStreetEdgeId = getCurrentLabelStreetEdgeId; - self.getCurrentLabelRegionId = getCurrentLabelRegionId; self.setProperty = setProperty; self.reset = reset; self.setLabelList = setLabelList; diff --git a/public/javascripts/common/GSVInfoPopOver.js b/public/javascripts/common/GSVInfoPopOver.js index a3928e7745..1b10640b65 100644 --- a/public/javascripts/common/GSVInfoPopOver.js +++ b/public/javascripts/common/GSVInfoPopOver.js @@ -8,10 +8,11 @@ * @param {function} streetEdgeId Function that returns current Street Edge ID * @param {function} regionId Function that returns current Region ID * @param {function} pov Function that returns current POV + * @param {function} [labelId] Optional function that returns the Label ID. * @returns {GSVInfoPopOver} Popover object, which holds the popover title html, content html, info button html, and * update values method */ -function GSVInfoPopOver (container, panorama, coords, panoId, streetEdgeId, regionId, pov) { +function GSVInfoPopOver (container, panorama, coords, panoId, streetEdgeId, regionId, pov, labelId) { let self = this; function _init() { @@ -48,7 +49,8 @@ function GSVInfoPopOver (container, panorama, coords, panoId, streetEdgeId, regi addListElement('Longitude', dataList); addListElement('Pano ID', dataList); addListElement('Street Edge ID', dataList); - addListElement('Region ID', dataList) + addListElement('Region ID', dataList); + if (labelId) addListElement('Label ID', dataList); self.popoverContent.appendChild(dataList); @@ -111,6 +113,7 @@ function GSVInfoPopOver (container, panorama, coords, panoId, streetEdgeId, regi const currStreetEdgeId = streetEdgeId ? streetEdgeId() : null; const currRegionId = regionId ? regionId() : null; const currPov = pov ? pov() : {heading: 0, pitch: 0}; + const currLabelId = labelId ? labelId() : null; function changeVals(key, val) { if (!val) { @@ -126,7 +129,8 @@ function GSVInfoPopOver (container, panorama, coords, panoId, streetEdgeId, regi changeVals('Longitude', currCoords.lng); changeVals('Pano ID', currPanoId); changeVals('Street Edge ID', currStreetEdgeId); - changeVals('Region ID', currRegionId) + changeVals('Region ID', currRegionId); + if (currLabelId) changeVals('Label ID', currLabelId); // Create GSV link. let gsvLink = $('#gsv-link'); From 6bd60c5c45989d42af64d87f82bc7ce1c3d7cf19 Mon Sep 17 00:00:00 2001 From: Mikey Saugstad Date: Thu, 13 Oct 2022 11:38:56 -0700 Subject: [PATCH 20/33] Explore and Validate info buttons are now white --- public/javascripts/Gallery/src/Main.js | 1 - public/javascripts/Gallery/src/modal/Modal.js | 2 +- public/javascripts/SVLabel/css/svl.css | 5 +++-- .../javascripts/SVLabel/img/misc/gsv_info_btn_white.svg | 8 ++++++++ public/javascripts/SVLabel/src/SVLabel/Main.js | 4 +++- public/javascripts/SVValidate/css/svv-panorama.css | 5 +++-- public/javascripts/SVValidate/src/Main.js | 2 +- public/javascripts/common/GSVInfoPopOver.js | 6 ++++-- 8 files changed, 23 insertions(+), 10 deletions(-) create mode 100644 public/javascripts/SVLabel/img/misc/gsv_info_btn_white.svg diff --git a/public/javascripts/Gallery/src/Main.js b/public/javascripts/Gallery/src/Main.js index d0e58b381f..084e0b2d02 100644 --- a/public/javascripts/Gallery/src/Main.js +++ b/public/javascripts/Gallery/src/Main.js @@ -74,7 +74,6 @@ function Main (params) { sg.tagContainer = new CardFilter(sg.ui.cardFilter, sg.labelTypeMenu, sg.cityMenu); sg.cardContainer = new CardContainer(sg.ui.cardContainer); sg.modal = sg.cardContainer.getModal; - // sg.infoPopover = new GSVInfoPopOver($('.pano-timestamp'), sg.modal().pano.panorama, sg.modal().pano.getPosition, sg.modal().pano.getPanoId, null, null, sg.modal().pano.getPov); // Initialize data collection. sg.form = new Form(params.dataStoreUrl, params.beaconDataStoreUrl) sg.tracker = new Tracker(); diff --git a/public/javascripts/Gallery/src/modal/Modal.js b/public/javascripts/Gallery/src/modal/Modal.js index 9700b63d60..0ccb89d1a4 100644 --- a/public/javascripts/Gallery/src/modal/Modal.js +++ b/public/javascripts/Gallery/src/modal/Modal.js @@ -143,7 +143,7 @@ function Modal(uiModal) { self.infoPopover = new GSVInfoPopOver(self.labelTimestampData, sg.modal().pano.panorama, sg.modal().pano.getPosition, sg.modal().pano.getPanoId, function () { return properties['street_edge_id']; }, function () { return properties['region_id']; }, - sg.modal().pano.getPov, function () { return properties['label_id']; } + sg.modal().pano.getPov, false, function () { return properties['label_id']; } ); console.log(properties['label_id']); diff --git a/public/javascripts/SVLabel/css/svl.css b/public/javascripts/SVLabel/css/svl.css index 9c810667ad..96b0c5981a 100644 --- a/public/javascripts/SVLabel/css/svl.css +++ b/public/javascripts/SVLabel/css/svl.css @@ -152,6 +152,7 @@ input[type="radio"] { #info-button { - margin: 5px; - max-height: 100%; + margin-left: 4px; + margin-top: 7px; + height: 16px; } diff --git a/public/javascripts/SVLabel/img/misc/gsv_info_btn_white.svg b/public/javascripts/SVLabel/img/misc/gsv_info_btn_white.svg new file mode 100644 index 0000000000..b3837391ff --- /dev/null +++ b/public/javascripts/SVLabel/img/misc/gsv_info_btn_white.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/public/javascripts/SVLabel/src/SVLabel/Main.js b/public/javascripts/SVLabel/src/SVLabel/Main.js index 32b2092124..13c48b2eb7 100644 --- a/public/javascripts/SVLabel/src/SVLabel/Main.js +++ b/public/javascripts/SVLabel/src/SVLabel/Main.js @@ -157,7 +157,9 @@ function Main (params) { svl.modalSkip = new ModalSkip(svl.form, svl.onboardingModel, svl.ribbon, svl.taskContainer, svl.tracker, svl.ui.leftColumn, svl.ui.modalSkip); svl.modalExample = new ModalExample(svl.modalModel, svl.onboardingModel, svl.ui.modalExample); - svl.infoPopover = new GSVInfoPopOver(svl.ui.dateHolder, svl.panorama, svl.map.getPosition, svl.map.getPanoId, svl.taskContainer.getCurrentTask().getStreetEdgeId, svl.taskContainer.getCurrentTask().getRegionId, svl.map.getPov); + svl.infoPopover = new GSVInfoPopOver(svl.ui.dateHolder, svl.panorama, svl.map.getPosition, svl.map.getPanoId, + svl.taskContainer.getCurrentTask().getStreetEdgeId, svl.taskContainer.getCurrentTask().getRegionId, + svl.map.getPov, true); // Survey for select users svl.surveyModalContainer = $("#survey-modal-container").get(0); diff --git a/public/javascripts/SVValidate/css/svv-panorama.css b/public/javascripts/SVValidate/css/svv-panorama.css index 64c4230ee9..c624eeed9f 100644 --- a/public/javascripts/SVValidate/css/svv-panorama.css +++ b/public/javascripts/SVValidate/css/svv-panorama.css @@ -32,8 +32,9 @@ } #info-button { - margin: 5px; - max-height: 100%; + margin-left: 4px; + margin-top: 7px; + height: 16px; } /* Black outline around GSV panorama. */ diff --git a/public/javascripts/SVValidate/src/Main.js b/public/javascripts/SVValidate/src/Main.js index 080d8f7071..768d7a43a1 100644 --- a/public/javascripts/SVValidate/src/Main.js +++ b/public/javascripts/SVValidate/src/Main.js @@ -175,7 +175,7 @@ function Main (param) { svv.panorama.getPanoId, function() { return svv.panoramaContainer.getCurrentLabel().getAuditProperty('streetEdgeId'); }, function() { return svv.panoramaContainer.getCurrentLabel().getAuditProperty('regionId'); }, - svv.panorama.getPov, + svv.panorama.getPov, true, function() { return svv.panoramaContainer.getCurrentLabel().getAuditProperty('labelId'); } ); diff --git a/public/javascripts/common/GSVInfoPopOver.js b/public/javascripts/common/GSVInfoPopOver.js index 1b10640b65..647a03b206 100644 --- a/public/javascripts/common/GSVInfoPopOver.js +++ b/public/javascripts/common/GSVInfoPopOver.js @@ -8,11 +8,12 @@ * @param {function} streetEdgeId Function that returns current Street Edge ID * @param {function} regionId Function that returns current Region ID * @param {function} pov Function that returns current POV + * @param {Boolean} whiteIcon Set to true if using white icon, false if using blue icon. * @param {function} [labelId] Optional function that returns the Label ID. * @returns {GSVInfoPopOver} Popover object, which holds the popover title html, content html, info button html, and * update values method */ -function GSVInfoPopOver (container, panorama, coords, panoId, streetEdgeId, regionId, pov, labelId) { +function GSVInfoPopOver (container, panorama, coords, panoId, streetEdgeId, regionId, pov, whiteIcon, labelId) { let self = this; function _init() { @@ -66,7 +67,8 @@ function GSVInfoPopOver (container, panorama, coords, panoId, streetEdgeId, regi self.infoButton = document.createElement('img'); self.infoButton.classList.add('popover-element'); self.infoButton.id = 'info-button'; - self.infoButton.src = '/assets/javascripts/SVLabel/img/misc/gsv_info_btn.png'; + if (whiteIcon) self.infoButton.src = '/assets/javascripts/SVLabel/img/misc/gsv_info_btn_white.svg'; + else self.infoButton.src = '/assets/javascripts/SVLabel/img/misc/gsv_info_btn.png'; self.infoButton.setAttribute('data-toggle', 'popover'); container.append(self.infoButton); From 769469fe9ecf91ebdc05c88abad871e4a26ba681 Mon Sep 17 00:00:00 2001 From: Mikey Saugstad Date: Thu, 13 Oct 2022 11:41:14 -0700 Subject: [PATCH 21/33] moves location of info button images --- .../img/misc => images/icons}/gsv_info_btn.png | Bin .../misc => images/icons}/gsv_info_btn_white.svg | 0 public/javascripts/common/GSVInfoPopOver.js | 4 ++-- 3 files changed, 2 insertions(+), 2 deletions(-) rename public/{javascripts/SVLabel/img/misc => images/icons}/gsv_info_btn.png (100%) rename public/{javascripts/SVLabel/img/misc => images/icons}/gsv_info_btn_white.svg (100%) diff --git a/public/javascripts/SVLabel/img/misc/gsv_info_btn.png b/public/images/icons/gsv_info_btn.png similarity index 100% rename from public/javascripts/SVLabel/img/misc/gsv_info_btn.png rename to public/images/icons/gsv_info_btn.png diff --git a/public/javascripts/SVLabel/img/misc/gsv_info_btn_white.svg b/public/images/icons/gsv_info_btn_white.svg similarity index 100% rename from public/javascripts/SVLabel/img/misc/gsv_info_btn_white.svg rename to public/images/icons/gsv_info_btn_white.svg diff --git a/public/javascripts/common/GSVInfoPopOver.js b/public/javascripts/common/GSVInfoPopOver.js index 647a03b206..41c5a4174c 100644 --- a/public/javascripts/common/GSVInfoPopOver.js +++ b/public/javascripts/common/GSVInfoPopOver.js @@ -67,8 +67,8 @@ function GSVInfoPopOver (container, panorama, coords, panoId, streetEdgeId, regi self.infoButton = document.createElement('img'); self.infoButton.classList.add('popover-element'); self.infoButton.id = 'info-button'; - if (whiteIcon) self.infoButton.src = '/assets/javascripts/SVLabel/img/misc/gsv_info_btn_white.svg'; - else self.infoButton.src = '/assets/javascripts/SVLabel/img/misc/gsv_info_btn.png'; + if (whiteIcon) self.infoButton.src = '/assets/images/icons/gsv_info_btn_white.svg'; + else self.infoButton.src = '/assets/images/icons/gsv_info_btn.png'; self.infoButton.setAttribute('data-toggle', 'popover'); container.append(self.infoButton); From c615967137fe663d2d0421c9f2a8199f65655a31 Mon Sep 17 00:00:00 2001 From: Mikey Saugstad Date: Thu, 13 Oct 2022 13:29:49 -0700 Subject: [PATCH 22/33] simplifies Validate code for keeping track of Label objects --- app/views/mobileValidate.scala.html | 22 +------------ app/views/validation.scala.html | 22 +------------ .../javascripts/SVValidate/src/label/Label.js | 31 +++++++++--------- .../SVValidate/src/label/LabelContainer.js | 5 +-- .../SVValidate/src/panorama/Panorama.js | 2 +- .../src/panorama/PanoramaContainer.js | 32 ++----------------- 6 files changed, 23 insertions(+), 91 deletions(-) diff --git a/app/views/mobileValidate.scala.html b/app/views/mobileValidate.scala.html index 1447011949..f7100bf24c 100644 --- a/app/views/mobileValidate.scala.html +++ b/app/views/mobileValidate.scala.html @@ -212,27 +212,7 @@

@Messages("validate.mission.complete.category")

// Initializes an object of labels from label metadata. // {key, labelMetadata} --> {key, Label}, where key = the index of the label. Object.keys(param.labelList).map(function (key, index) { - let labelMetadata = { - canvasHeight: param.labelList[key].canvas_height, - canvasWidth: param.labelList[key].canvas_width, - canvasX: param.labelList[key].canvas_x, - canvasY: param.labelList[key].canvas_y, - gsvPanoramaId: param.labelList[key].gsv_panorama_id, - imageDate: param.labelList[key].image_date, - labelTimestamp: param.labelList[key].label_timestamp, - heading: param.labelList[key].heading, - labelId: param.labelList[key].label_id, - labelType: param.labelList[key].label_type, - pitch: param.labelList[key].pitch, - zoom: param.labelList[key].zoom, - severity: param.labelList[key].severity, - temporary: param.labelList[key].temporary, - description: param.labelList[key].description, - streetEdgeId: param.labelList[key].street_edge_id, - regionId: param.labelList[key].region_id, - tags: param.labelList[key].tags - }; - param.labelList[key] = new Label(labelMetadata); + param.labelList[key] = new Label(param.labelList[key]); }); } svv.main = new Main(param); diff --git a/app/views/validation.scala.html b/app/views/validation.scala.html index 60e4ea4afa..15589aa8a0 100644 --- a/app/views/validation.scala.html +++ b/app/views/validation.scala.html @@ -267,27 +267,7 @@

// Initializes an object of labels from label metadata. // {key, labelMetadata} --> {key, Label}, where key = the index of the label. Object.keys(param.labelList).map(function (key, index) { - let labelMetadata = { - canvasHeight: param.labelList[key].canvas_height, - canvasWidth: param.labelList[key].canvas_width, - canvasX: param.labelList[key].canvas_x, - canvasY: param.labelList[key].canvas_y, - gsvPanoramaId: param.labelList[key].gsv_panorama_id, - imageDate: param.labelList[key].image_date, - labelTimestamp: param.labelList[key].label_timestamp, - heading: param.labelList[key].heading, - labelId: param.labelList[key].label_id, - labelType: param.labelList[key].label_type, - pitch: param.labelList[key].pitch, - zoom: param.labelList[key].zoom, - severity: param.labelList[key].severity, - temporary: param.labelList[key].temporary, - description: param.labelList[key].description, - streetEdgeId: param.labelList[key].street_edge_id, - regionId: param.labelList[key].region_id, - tags: param.labelList[key].tags - }; - param.labelList[key] = new Label(labelMetadata); + param.labelList[key] = new Label(param.labelList[key]); }); } svv.main = new Main(param); diff --git a/public/javascripts/SVValidate/src/label/Label.js b/public/javascripts/SVValidate/src/label/Label.js index 9297a90d70..ab7a6938e9 100644 --- a/public/javascripts/SVValidate/src/label/Label.js +++ b/public/javascripts/SVValidate/src/label/Label.js @@ -35,7 +35,6 @@ function Label(params) { canvasX: undefined, canvasY: undefined, endTimestamp: undefined, - labelId: undefined, heading: undefined, pitch: undefined, startTimestamp: undefined, @@ -85,24 +84,23 @@ function Label(params) { */ function _init() { if (params) { - if ("canvasHeight" in params) setAuditProperty("canvasHeight", params.canvasHeight); - if ("canvasWidth" in params) setAuditProperty("canvasWidth", params.canvasWidth); - if ("canvasX" in params) setAuditProperty("canvasX", params.canvasX); - if ("canvasY" in params) setAuditProperty("canvasY", params.canvasY); - if ("gsvPanoramaId" in params) setAuditProperty("gsvPanoramaId", params.gsvPanoramaId); - if ("imageDate" in params) setAuditProperty("imageDate", params.imageDate); - if ("labelTimestamp" in params) setAuditProperty("labelTimestamp", params.labelTimestamp); + if ("canvas_height" in params) setAuditProperty("canvasHeight", params.canvas_height); + if ("canvas_width" in params) setAuditProperty("canvasWidth", params.canvas_width); + if ("canvas_x" in params) setAuditProperty("canvasX", params.canvas_x); + if ("canvas_y" in params) setAuditProperty("canvasY", params.canvas_y); + if ("gsv_panorama_id" in params) setAuditProperty("gsvPanoramaId", params.gsv_panorama_id); + if ("image_date" in params) setAuditProperty("imageDate", params.image_date); + if ("label_timestamp" in params) setAuditProperty("labelTimestamp", params.label_timestamp); if ("heading" in params) setAuditProperty("heading", params.heading); - if ("labelId" in params) setAuditProperty("labelId", params.labelId); - if ("labelId" in params) setProperty("labelId", params.labelId); - if ("labelType" in params) setAuditProperty("labelType", params.labelType); + if ("label_id" in params) setAuditProperty("labelId", params.label_id); + if ("label_type" in params) setAuditProperty("labelType", params.label_type); if ("pitch" in params) setAuditProperty("pitch", params.pitch); if ("zoom" in params) setAuditProperty("zoom", params.zoom); if ("severity" in params) setAuditProperty("severity", params.severity); if ("temporary" in params) setAuditProperty("temporary", params.temporary); if ("description" in params) setAuditProperty("description", params.description); - if ("streetEdgeId" in params) setAuditProperty("streetEdgeId", params.streetEdgeId); - if ("regionId" in params) setAuditProperty("regionId", params.regionId); + if ("street_edge_id" in params) setAuditProperty("streetEdgeId", params.street_edge_id); + if ("region_id" in params) setAuditProperty("regionId", params.region_id); if ("tags" in params) setAuditProperty("tags", params.tags); setAuditProperty("isMobile", isMobile()); } @@ -223,6 +221,7 @@ function Label(params) { * NOTE: canvas_x and canvas_y are null when the label is not visible when validation occurs. * * @param validationResult Must be one of the following: {Agree, Disagree, Notsure}. + * @param comment An optional comment submitted with the validation. */ function validate(validationResult, comment) { // This is the POV of the PanoMarker, where the PanoMarker would be loaded at the center @@ -276,21 +275,21 @@ function Label(params) { case "Agree": setProperty("validationResult", 1); svv.missionContainer.getCurrentMission().updateValidationResult(1); - svv.labelContainer.push(getProperties()); + svv.labelContainer.push(getAuditProperty('labelId'), getProperties()); svv.missionContainer.updateAMission(); break; // Disagree option selected. case "Disagree": setProperty("validationResult", 2); svv.missionContainer.getCurrentMission().updateValidationResult(2); - svv.labelContainer.push(getProperties()); + svv.labelContainer.push(getAuditProperty('labelId'), getProperties()); svv.missionContainer.updateAMission(); break; // Not sure option selected. case "NotSure": setProperty("validationResult", 3); svv.missionContainer.getCurrentMission().updateValidationResult(3); - svv.labelContainer.push(getProperties()); + svv.labelContainer.push(getAuditProperty('labelId'), getProperties()); svv.missionContainer.updateAMission(); break; } diff --git a/public/javascripts/SVValidate/src/label/LabelContainer.js b/public/javascripts/SVValidate/src/label/LabelContainer.js index eccc2634f1..803947cc3d 100644 --- a/public/javascripts/SVValidate/src/label/LabelContainer.js +++ b/public/javascripts/SVValidate/src/label/LabelContainer.js @@ -18,9 +18,10 @@ function LabelContainer() { /** * Pushes a label to the list of current labels. + * @param labelId Integer label ID * @param labelMetadata Label metadata (validationProperties object) */ - function push(labelMetadata) { + function push(labelId, labelMetadata) { let data = { canvas_height: svv.canvasHeight, canvas_width: svv.canvasWidth, @@ -28,7 +29,7 @@ function LabelContainer() { canvas_y: labelMetadata.canvasY, end_timestamp: labelMetadata.endTimestamp, heading: labelMetadata.heading, - label_id: labelMetadata.labelId, + label_id: labelId, mission_id: svv.missionContainer.getCurrentMission().getProperty("missionId"), pitch: labelMetadata.pitch, start_timestamp: labelMetadata.startTimestamp, diff --git a/public/javascripts/SVValidate/src/panorama/Panorama.js b/public/javascripts/SVValidate/src/panorama/Panorama.js index 6bdac26fb3..20b9127f30 100644 --- a/public/javascripts/SVValidate/src/panorama/Panorama.js +++ b/public/javascripts/SVValidate/src/panorama/Panorama.js @@ -310,7 +310,7 @@ function Panorama (label) { * Skips the current label on this panorama and fetches a new label for validation. */ function skipLabel () { - svv.panoramaContainer.fetchNewLabel(currentLabel.getProperty('labelId')); + svv.panoramaContainer.fetchNewLabel(currentLabel.getAuditProperty('labelId')); } /** diff --git a/public/javascripts/SVValidate/src/panorama/PanoramaContainer.js b/public/javascripts/SVValidate/src/panorama/PanoramaContainer.js index c879036a08..3497d26341 100644 --- a/public/javascripts/SVValidate/src/panorama/PanoramaContainer.js +++ b/public/javascripts/SVValidate/src/panorama/PanoramaContainer.js @@ -26,34 +26,6 @@ function PanoramaContainer (labelList) { svv.statusExample.updateLabelImage(labelList[0].getAuditProperty('labelType')); } - /** - * Uses label metadata to initialize a new label. - * @param metadata Metadata for the label. - * @returns {Label} Label object for this label. - * @private - */ - function _createSingleLabel (metadata) { - let labelMetadata = { - canvasHeight: metadata.canvas_height, - canvasWidth: metadata.canvas_width, - canvasX: metadata.canvas_x, - canvasY: metadata.canvas_y, - gsvPanoramaId: metadata.gsv_panorama_id, - heading: metadata.heading, - labelId: metadata.label_id, - labelType: metadata.label_type, - pitch: metadata.pitch, - zoom: metadata.zoom, - severity: metadata.severity, - temporary: metadata.temporary, - description: metadata.description, - streetEdgeId: metadata.streetEdgeId, - regionId: metadata.regionId, - tags: metadata.tags - }; - return new Label(labelMetadata); - } - /** * Fetches a single label from the database. When the user clicks skip, need to get more * because missions fetch exactly the number of labels that are needed to complete the mission. @@ -78,7 +50,7 @@ function PanoramaContainer (labelList) { data: JSON.stringify(data), dataType: 'json', success: function (labelMetadata) { - labels.push(_createSingleLabel(labelMetadata)); + labels.push(new Label(labelMetadata)); svv.missionContainer.updateAMissionSkip(); loadNewLabelOntoPanorama(svv.panorama); } @@ -129,7 +101,7 @@ function PanoramaContainer (labelList) { */ function setLabelList (labelList) { Object.keys(labelList).map(function(key, index) { - labelList[key] = _createSingleLabel(labelList[key]); + labelList[key] = new Label(labelList[key]); }); labels = labelList; From f92277fa015320af7ed1b922755552290b7a414c Mon Sep 17 00:00:00 2001 From: Mikey Saugstad Date: Thu, 13 Oct 2022 15:24:12 -0700 Subject: [PATCH 23/33] fixes gsv info button copy to clipboard popover --- .../misc => images/icons}/clipboard_copy.png | Bin public/javascripts/common/GSVInfoPopOver.js | 38 ++++++++++-------- public/stylesheets/main.css | 4 ++ 3 files changed, 25 insertions(+), 17 deletions(-) rename public/{javascripts/SVLabel/img/misc => images/icons}/clipboard_copy.png (100%) diff --git a/public/javascripts/SVLabel/img/misc/clipboard_copy.png b/public/images/icons/clipboard_copy.png similarity index 100% rename from public/javascripts/SVLabel/img/misc/clipboard_copy.png rename to public/images/icons/clipboard_copy.png diff --git a/public/javascripts/common/GSVInfoPopOver.js b/public/javascripts/common/GSVInfoPopOver.js index 41c5a4174c..d111dfb04d 100644 --- a/public/javascripts/common/GSVInfoPopOver.js +++ b/public/javascripts/common/GSVInfoPopOver.js @@ -27,14 +27,14 @@ function GSVInfoPopOver (container, panorama, coords, panoId, streetEdgeId, regi let clipboard = document.createElement('img'); clipboard.classList.add('popover-element'); - clipboard.src = '/assets/javascripts/SVLabel/img/misc/clipboard_copy.png'; + clipboard.src = '/assets/images/icons/clipboard_copy.png'; clipboard.id = 'clipboard'; - clipboard.setAttribute('data-toggle', 'tooltip'); - clipboard.setAttribute('data-placement', 'top'); - clipboard.setAttribute('trigger', 'click'); + clipboard.setAttribute('data-toggle', 'popover'); clipboard.setAttribute('tabindex', 0); - clipboard.setAttribute('title', 'Details copied to clipboard!'); + clipboard.setAttribute( 'data-placement', 'top'); + clipboard.setAttribute( 'data-content', 'Data copied to your clipboard!'); + clipboard.setAttribute('trigger', 'manual'); self.titleBox.appendChild(clipboard); @@ -44,7 +44,7 @@ function GSVInfoPopOver (container, panorama, coords, panoId, streetEdgeId, regi // Add in container for each info type to the popover. let dataList = document.createElement('ul'); - dataList.classList.add('list-group', 'list-group-flush'); + dataList.classList.add('list-group', 'list-group-flush', 'gsv-info-list-group'); addListElement('Latitude', dataList); addListElement('Longitude', dataList); @@ -85,7 +85,7 @@ function GSVInfoPopOver (container, panorama, coords, panoId, streetEdgeId, regi $('.popover-title').addClass('popover-element'); $('.popover-content').addClass('popover-element'); }); - $('#clipboard').tooltip(); + $('#clipboard').popover(); // Dismiss popover when clicking outside it. Anything without the 'popover-element' class is considered outside. $(document).on('mousedown', (e) => { @@ -140,16 +140,20 @@ function GSVInfoPopOver (container, panorama, coords, panoId, streetEdgeId, regi gsvLink.attr('target', '_blank'); // Copy to clipboard. - let clipboardElem = $('#clipboard'); - clipboardElem.click(() => { - clipboardElem.tooltip('enable'); - clipboardElem.tooltip('show'); - navigator.clipboard.writeText( - `Latitude: ${currCoords.lat}°\nLongitude: ${currCoords.lng}°\nPano ID: ${currPanoId}\nStreet Edge ID: ${currStreetEdgeId}\nRegion ID: ${currRegionId}` - ); - }); - clipboardElem.on('mouseout', () => { - clipboardElem.tooltip('disable'); + $('#clipboard').on('click', function(e) { + let clipboardText = `Latitude: ${currCoords.lat}°\nLongitude: ${currCoords.lng}°\nPano ID: ${currPanoId}\nStreet Edge ID: ${currStreetEdgeId}\nRegion ID: ${currRegionId}`; + if (currLabelId) clipboardText += `Label ID: ${currLabelId}`; + navigator.clipboard.writeText(clipboardText); + + // The clipboard popover will only show one time until you close and reopen the info button popover. I have + // no idea why that's happening, but for some reason it works if you put it in a setTimeout. So I have a one + // ms delay before showing the popover. Then it disappears after 1.5 seconds. + setTimeout(function() { + $(e.target).popover('show'); + setTimeout(function() { + $(e.target).popover('hide'); + }, 1500); + }, 1); }); } diff --git a/public/stylesheets/main.css b/public/stylesheets/main.css index 8d374d4248..d952c2a008 100644 --- a/public/stylesheets/main.css +++ b/public/stylesheets/main.css @@ -1246,6 +1246,10 @@ kbd { vertical-align: middle; } +.gsv-info-list-group { + margin-bottom: 8px; +} + .mobile-popover { background-color:rgba(58,58,58, 0.9); color: white; From 519efa7d7740c528233870980c1a4da66e10df22 Mon Sep 17 00:00:00 2001 From: Mikey Saugstad Date: Thu, 13 Oct 2022 15:29:50 -0700 Subject: [PATCH 24/33] removes unused code --- Gruntfile.js | 1 - public/stylesheets/admin.css | 57 ------------------------------------ 2 files changed, 58 deletions(-) diff --git a/Gruntfile.js b/Gruntfile.js index 8d8b37d03f..4401b1cdeb 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -47,7 +47,6 @@ module.exports = function(grunt) { dist_admin: { src: [ 'public/javascripts/Admin/src/*.js', - 'public/javascripts/common/GSVInfoPopOver.js' ], dest: 'public/javascripts/Admin/build/Admin.js' }, diff --git a/public/stylesheets/admin.css b/public/stylesheets/admin.css index 303d3a27ea..0d1fe2b3d8 100644 --- a/public/stylesheets/admin.css +++ b/public/stylesheets/admin.css @@ -93,60 +93,3 @@ left: 405px; bottom: 5px } - -/* GSV Info Popover styling */ -#info-popover-holder { - width: 19px; - height: 19px; - position: absolute; - z-index: 2; - left: 70px; - bottom: 0; - margin: 5px; -} - -#info-button { - width: 19px; - margin-bottom: 4px; -} - -.info-key { - font-weight: bold; -} - -.info-list-item { - display: flex; - justify-content: space-between; -} - -.popover { - width: 350px; - max-width: 350px; -} - -.popover-title { - display: flex; - justify-content: space-between; - height: 36px; -} - -.popover-content { - display: flex; - flex-direction: column; - justify-content: center; -} -#gsv-link { - text-align: center; - width: fit-content; - margin-left: auto; - margin-right: auto; -} - -#clipboard { - max-height: 100%; - cursor: pointer; -} - -#clipboard:active { - opacity: 50%; -} From 9af8cee64a9aeb528259dd7bbe19aec5dec17cd2 Mon Sep 17 00:00:00 2001 From: Mikey Saugstad Date: Thu, 13 Oct 2022 15:37:33 -0700 Subject: [PATCH 25/33] gsv info button switched to pointer cursor --- public/javascripts/Gallery/css/modal.css | 2 +- public/javascripts/SVLabel/css/svl.css | 2 +- public/javascripts/SVValidate/css/svv-panorama.css | 2 +- public/javascripts/common/GSVInfoPopOver.js | 8 ++++---- public/stylesheets/main.css | 4 ++++ 5 files changed, 11 insertions(+), 7 deletions(-) diff --git a/public/javascripts/Gallery/css/modal.css b/public/javascripts/Gallery/css/modal.css index 9f1125289f..6c90f2baef 100644 --- a/public/javascripts/Gallery/css/modal.css +++ b/public/javascripts/Gallery/css/modal.css @@ -29,7 +29,7 @@ display: flex; } -#info-button { +#gsv-info-button { width: 0.9vw; height: 0.9vw; margin-left: 5px; diff --git a/public/javascripts/SVLabel/css/svl.css b/public/javascripts/SVLabel/css/svl.css index 96b0c5981a..9c0f4727a6 100644 --- a/public/javascripts/SVLabel/css/svl.css +++ b/public/javascripts/SVLabel/css/svl.css @@ -151,7 +151,7 @@ input[type="radio"] { } -#info-button { +#gsv-info-button { margin-left: 4px; margin-top: 7px; height: 16px; diff --git a/public/javascripts/SVValidate/css/svv-panorama.css b/public/javascripts/SVValidate/css/svv-panorama.css index c624eeed9f..109ead063c 100644 --- a/public/javascripts/SVValidate/css/svv-panorama.css +++ b/public/javascripts/SVValidate/css/svv-panorama.css @@ -31,7 +31,7 @@ padding: 5px; } -#info-button { +#gsv-info-button { margin-left: 4px; margin-top: 7px; height: 16px; diff --git a/public/javascripts/common/GSVInfoPopOver.js b/public/javascripts/common/GSVInfoPopOver.js index d111dfb04d..83aea73505 100644 --- a/public/javascripts/common/GSVInfoPopOver.js +++ b/public/javascripts/common/GSVInfoPopOver.js @@ -66,7 +66,7 @@ function GSVInfoPopOver (container, panorama, coords, panoId, streetEdgeId, regi // Create info button and add popover attributes. self.infoButton = document.createElement('img'); self.infoButton.classList.add('popover-element'); - self.infoButton.id = 'info-button'; + self.infoButton.id = 'gsv-info-button'; if (whiteIcon) self.infoButton.src = '/assets/images/icons/gsv_info_btn_white.svg'; else self.infoButton.src = '/assets/images/icons/gsv_info_btn.png'; self.infoButton.setAttribute('data-toggle', 'popover'); @@ -74,7 +74,7 @@ function GSVInfoPopOver (container, panorama, coords, panoId, streetEdgeId, regi container.append(self.infoButton); // Enable popovers/tooltips and set options - $('#info-button').popover({ + $('#gsv-info-button').popover({ html: true, placement: 'top', container: 'body', @@ -91,12 +91,12 @@ function GSVInfoPopOver (container, panorama, coords, panoId, streetEdgeId, regi $(document).on('mousedown', (e) => { let tar = $(e.target); if (!tar[0].classList.contains('popover-element')) { - $('#info-button').popover('hide'); + $('#gsv-info-button').popover('hide'); } }); // Dismiss popover whenever panorama changes. panorama.addListener('pano_changed', () => { - $('#info-button').popover('hide'); + $('#gsv-info-button').popover('hide'); }) } diff --git a/public/stylesheets/main.css b/public/stylesheets/main.css index d952c2a008..8892585987 100644 --- a/public/stylesheets/main.css +++ b/public/stylesheets/main.css @@ -1246,6 +1246,10 @@ kbd { vertical-align: middle; } +#gsv-info-button { + cursor: pointer; +} + .gsv-info-list-group { margin-bottom: 8px; } From 22edb667418d65f389a5d38566431d811b24f3df Mon Sep 17 00:00:00 2001 From: Mikey Saugstad Date: Thu, 13 Oct 2022 16:30:10 -0700 Subject: [PATCH 26/33] fixes styling of info button and clipboard popovers --- public/javascripts/common/GSVInfoPopOver.js | 24 ++++++++++++--------- public/stylesheets/main.css | 7 +++++- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/public/javascripts/common/GSVInfoPopOver.js b/public/javascripts/common/GSVInfoPopOver.js index 83aea73505..ce9b1a0d28 100644 --- a/public/javascripts/common/GSVInfoPopOver.js +++ b/public/javascripts/common/GSVInfoPopOver.js @@ -29,12 +29,7 @@ function GSVInfoPopOver (container, panorama, coords, panoId, streetEdgeId, regi clipboard.classList.add('popover-element'); clipboard.src = '/assets/images/icons/clipboard_copy.png'; clipboard.id = 'clipboard'; - clipboard.setAttribute('data-toggle', 'popover'); - clipboard.setAttribute('tabindex', 0); - clipboard.setAttribute( 'data-placement', 'top'); - clipboard.setAttribute( 'data-content', 'Data copied to your clipboard!'); - clipboard.setAttribute('trigger', 'manual'); self.titleBox.appendChild(clipboard); @@ -84,8 +79,15 @@ function GSVInfoPopOver (container, panorama, coords, panoId, streetEdgeId, regi // Add popover-element classes to more elements, making it easier to dismiss popover on when outside it. $('.popover-title').addClass('popover-element'); $('.popover-content').addClass('popover-element'); + + // Initialize the popover for the clipboard. + $('#clipboard').popover({ + placement: 'top', + trigger: 'manual', + html: true, + content: 'Data copied to your clipboard!' + }); }); - $('#clipboard').popover(); // Dismiss popover when clicking outside it. Anything without the 'popover-element' class is considered outside. $(document).on('mousedown', (e) => { @@ -105,10 +107,6 @@ function GSVInfoPopOver (container, panorama, coords, panoId, streetEdgeId, regi * Update the values within the popover. */ function updateVals() { - // Position popover. - let xpos = self.infoButton.getBoundingClientRect().x + (self.infoButton.getBoundingClientRect().width / 2) - 175; - $('.popover').css('left', `${xpos}px`); - // Get info values. const currCoords = coords ? coords() : {lat: null, lng: null}; const currPanoId = panoId ? panoId() : null; @@ -139,6 +137,12 @@ function GSVInfoPopOver (container, panorama, coords, panoId, streetEdgeId, regi gsvLink.attr('href', `https://www.google.com/maps/@?api=1&map_action=pano&viewpoint=${currCoords.lat}%2C${currCoords.lng}&heading=${currPov.heading}&pitch=${currPov.pitch}`); gsvLink.attr('target', '_blank'); + // Position popover. + let infoPopover = $('.popover'); + let infoRect = self.infoButton.getBoundingClientRect(); + let xpos = infoRect.x + (infoRect.width / 2) - (infoPopover.width() / 2); + infoPopover.css('left', `${xpos}px`); + // Copy to clipboard. $('#clipboard').on('click', function(e) { let clipboardText = `Latitude: ${currCoords.lat}°\nLongitude: ${currCoords.lng}°\nPano ID: ${currPanoId}\nStreet Edge ID: ${currStreetEdgeId}\nRegion ID: ${currRegionId}`; diff --git a/public/stylesheets/main.css b/public/stylesheets/main.css index 8892585987..31a61cf5aa 100644 --- a/public/stylesheets/main.css +++ b/public/stylesheets/main.css @@ -723,6 +723,7 @@ p#conditional-text { /* GSV Info Popover styling */ .info-key { font-weight: bold; + margin-right: 20px; } .info-list-item { @@ -731,7 +732,6 @@ p#conditional-text { } .popover { - width: 350px; max-width: 350px; } @@ -762,6 +762,11 @@ p#conditional-text { opacity: 50%; } +.clipboard-tooltip { + font-size: 12px; + white-space: nowrap; +} + @media only screen and (max-device-width: 500px) { #awardnum { width: 100% !important; From 9cde4d38832392d9380af62aefcd0a4226ee3c7d Mon Sep 17 00:00:00 2001 From: Mikey Saugstad Date: Fri, 14 Oct 2022 11:22:27 -0700 Subject: [PATCH 27/33] renames GSVInfoPopOver.js to GSVInfoPopover.js --- Gruntfile.js | 6 +++--- public/javascripts/Gallery/src/modal/Modal.js | 2 +- public/javascripts/SVLabel/src/SVLabel/Main.js | 2 +- public/javascripts/SVValidate/src/Main.js | 2 +- .../common/{GSVInfoPopOver.js => GSVInfoPopover.js} | 4 ++-- 5 files changed, 8 insertions(+), 8 deletions(-) rename public/javascripts/common/{GSVInfoPopOver.js => GSVInfoPopover.js} (98%) diff --git a/Gruntfile.js b/Gruntfile.js index 4401b1cdeb..995ef376e4 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -33,7 +33,7 @@ module.exports = function(grunt) { 'public/javascripts/common/UtilitiesPanomarker.js', 'public/javascripts/common/UtilitiesShape.js', 'public/javascripts/common/UtilitiesSidewalk.js', - 'public/javascripts/common/GSVInfoPopOver.js' + 'public/javascripts/common/GSVInfoPopover.js' ], dest: 'public/javascripts/SVLabel/build/SVLabel.js' }, @@ -72,7 +72,7 @@ module.exports = function(grunt) { 'public/javascripts/SVValidate/src/zoom/*.js', 'public/javascripts/common/Panomarker.js', 'public/javascripts/common/UtilitiesSidewalk.js', - 'public/javascripts/common/GSVInfoPopOver.js' + 'public/javascripts/common/GSVInfoPopover.js' ], dest: 'public/javascripts/SVValidate/build/SVValidate.js' }, @@ -86,7 +86,7 @@ module.exports = function(grunt) { 'public/javascripts/Gallery/src/modal/*.js', 'public/javascripts/Gallery/src/*.js', 'public/javascripts/common/Panomarker.js', - 'public/javascripts/common/GSVInfoPopOver.js' + 'public/javascripts/common/GSVInfoPopover.js' ], dest: 'public/javascripts/Gallery/build/Gallery.js' } diff --git a/public/javascripts/Gallery/src/modal/Modal.js b/public/javascripts/Gallery/src/modal/Modal.js index 0ccb89d1a4..a8da5bf53d 100644 --- a/public/javascripts/Gallery/src/modal/Modal.js +++ b/public/javascripts/Gallery/src/modal/Modal.js @@ -140,7 +140,7 @@ function Modal(uiModal) { self.timestamps.append(panoTimestampData); // Add info button to the right of the label timestamp. - self.infoPopover = new GSVInfoPopOver(self.labelTimestampData, sg.modal().pano.panorama, + self.infoPopover = new GSVInfoPopover(self.labelTimestampData, sg.modal().pano.panorama, sg.modal().pano.getPosition, sg.modal().pano.getPanoId, function () { return properties['street_edge_id']; }, function () { return properties['region_id']; }, sg.modal().pano.getPov, false, function () { return properties['label_id']; } diff --git a/public/javascripts/SVLabel/src/SVLabel/Main.js b/public/javascripts/SVLabel/src/SVLabel/Main.js index 13c48b2eb7..42a1dc82f8 100644 --- a/public/javascripts/SVLabel/src/SVLabel/Main.js +++ b/public/javascripts/SVLabel/src/SVLabel/Main.js @@ -157,7 +157,7 @@ function Main (params) { svl.modalSkip = new ModalSkip(svl.form, svl.onboardingModel, svl.ribbon, svl.taskContainer, svl.tracker, svl.ui.leftColumn, svl.ui.modalSkip); svl.modalExample = new ModalExample(svl.modalModel, svl.onboardingModel, svl.ui.modalExample); - svl.infoPopover = new GSVInfoPopOver(svl.ui.dateHolder, svl.panorama, svl.map.getPosition, svl.map.getPanoId, + svl.infoPopover = new GSVInfoPopover(svl.ui.dateHolder, svl.panorama, svl.map.getPosition, svl.map.getPanoId, svl.taskContainer.getCurrentTask().getStreetEdgeId, svl.taskContainer.getCurrentTask().getRegionId, svl.map.getPov, true); diff --git a/public/javascripts/SVValidate/src/Main.js b/public/javascripts/SVValidate/src/Main.js index 768d7a43a1..7c91303f7e 100644 --- a/public/javascripts/SVValidate/src/Main.js +++ b/public/javascripts/SVValidate/src/Main.js @@ -171,7 +171,7 @@ function Main (param) { svv.modalInfo = new ModalInfo(svv.ui.modalInfo, param.modalText); svv.modalLandscape = new ModalLandscape(svv.ui.modalLandscape); svv.modalNoNewMission = new ModalNoNewMission(svv.ui.modalMission); - svv.infoPopover = new GSVInfoPopOver(svv.ui.dateHolder, svv.panorama.getPanorama(), svv.panorama.getPosition, + svv.infoPopover = new GSVInfoPopover(svv.ui.dateHolder, svv.panorama.getPanorama(), svv.panorama.getPosition, svv.panorama.getPanoId, function() { return svv.panoramaContainer.getCurrentLabel().getAuditProperty('streetEdgeId'); }, function() { return svv.panoramaContainer.getCurrentLabel().getAuditProperty('regionId'); }, diff --git a/public/javascripts/common/GSVInfoPopOver.js b/public/javascripts/common/GSVInfoPopover.js similarity index 98% rename from public/javascripts/common/GSVInfoPopOver.js rename to public/javascripts/common/GSVInfoPopover.js index ce9b1a0d28..9e60f75afa 100644 --- a/public/javascripts/common/GSVInfoPopOver.js +++ b/public/javascripts/common/GSVInfoPopover.js @@ -10,10 +10,10 @@ * @param {function} pov Function that returns current POV * @param {Boolean} whiteIcon Set to true if using white icon, false if using blue icon. * @param {function} [labelId] Optional function that returns the Label ID. - * @returns {GSVInfoPopOver} Popover object, which holds the popover title html, content html, info button html, and + * @returns {GSVInfoPopover} Popover object, which holds the popover title html, content html, info button html, and * update values method */ -function GSVInfoPopOver (container, panorama, coords, panoId, streetEdgeId, regionId, pov, whiteIcon, labelId) { +function GSVInfoPopover (container, panorama, coords, panoId, streetEdgeId, regionId, pov, whiteIcon, labelId) { let self = this; function _init() { From 61038f30b3e3867d0aee2c00b479c1f017e0253e Mon Sep 17 00:00:00 2001 From: Mikey Saugstad Date: Fri, 14 Oct 2022 12:37:58 -0700 Subject: [PATCH 28/33] info button and footer text now selectable on audit page --- app/views/audit.scala.html | 12 +++++++++--- app/views/footer.scala.html | 2 +- public/javascripts/SVLabel/css/svl.css | 8 +++++++- public/javascripts/common/GSVInfoPopover.js | 2 +- 4 files changed, 18 insertions(+), 6 deletions(-) diff --git a/app/views/audit.scala.html b/app/views/audit.scala.html index 9708953690..b3fcee86ed 100644 --- a/app/views/audit.scala.html +++ b/app/views/audit.scala.html @@ -902,9 +902,15 @@

@Messages("surface.problem")

} $(document).ready(function() { - // Solutions to annoying text selection cursor. - // http://forum.jquery.com/topic/chrome-text-select-cursor-on-drag - document.onselectstart = function () { return false; }; + // Prevents text selection with cursor. Fixes https://github.com/ProjectSidewalk/SidewalkWebpage/issues/121. + // We also add the 'audit-selectable' class to a parent of any element that we want to have selectable. + document.onselectstart = function (e) { + if ($(e.target).closest('.audit-selectable').length > 0) { + return true; + } else { + return false; + } + }; enableTouchSupport(); // Advanced Neighborhood Overlay diff --git a/app/views/footer.scala.html b/app/views/footer.scala.html index 55808b631b..d409d3a53d 100644 --- a/app/views/footer.scala.html +++ b/app/views/footer.scala.html @@ -3,7 +3,7 @@ @()(implicit lang: Lang) -