From 02a0655a24d08fb6e7810390d6b9a171cd8bfb7c Mon Sep 17 00:00:00 2001 From: Aron den Ouden Date: Tue, 1 Oct 2024 20:15:41 +0200 Subject: [PATCH 1/3] fixed multiple location requests --- static/js/nearYouOverlay.js | 51 +++++++++++++++++++------------------ 1 file changed, 26 insertions(+), 25 deletions(-) diff --git a/static/js/nearYouOverlay.js b/static/js/nearYouOverlay.js index 1f3f178..372d9d3 100644 --- a/static/js/nearYouOverlay.js +++ b/static/js/nearYouOverlay.js @@ -105,7 +105,7 @@ var Overlay = L.Class.extend({ self.closeOverlay(); } // Above threshold -> reveal the overlay - else { + else if (!self.isActive) { self.openOverlay(); } }); @@ -171,6 +171,7 @@ var Overlay = L.Class.extend({ this._overlayElement.style.overflowY = 'auto'; this._line.style.display = 'none'; this.getNearYouData(); + console.log("opened overlay!"); }, closeOverlay: function () { @@ -259,31 +260,31 @@ var Overlay = L.Class.extend({ checkPointerAndOpenPopup(stickerID); }); - // Load nearby text (estimated address) - var stickerDivNearby = stickerDivNearbys[i]; - var addressRequest = new XMLHttpRequest(); - addressRequest.onreadystatechange = function(){ - if(this.readyState == 4 && this.status == 200){ - var addressJson = JSON.parse(addressRequest.responseText); - console.log(addressJson); - var text = "Nearby "; - if(addressJson['address']['road'] != undefined){ - text += addressJson['address']['road']; - if(addressJson['address']['house_number'] != undefined){ - text += ' ' + addressJson['address']['house_number']; - } - } - console.log(text); - stickerDivNearby.textContent = text; - } else { - // Error handling for non-200 status codes + // // Load nearby text (estimated address) + // var stickerDivNearby = stickerDivNearbys[i]; + // var addressRequest = new XMLHttpRequest(); + // addressRequest.onreadystatechange = function(){ + // if(this.readyState == 4 && this.status == 200){ + // var addressJson = JSON.parse(addressRequest.responseText); + // console.log(addressJson); + // var text = "Nearby "; + // if(addressJson['address']['road'] != undefined){ + // text += addressJson['address']['road']; + // if(addressJson['address']['house_number'] != undefined){ + // text += ' ' + addressJson['address']['house_number']; + // } + // } + // console.log(text); + // stickerDivNearby.textContent = text; + // } else { + // // Error handling for non-200 status codes - console.error('Request failed with status code ' + this.status + ', readystate: ' + this.readyState); - } - } - console.log('https://nominatim.openstreetmap.org/reverse?lat=' + results[i][1] + '&lon=' + results[i][2] + '&format=json'); - addressRequest.open("GET", 'https://nominatim.openstreetmap.org/reverse?lat=' + results[i][1] + '&lon=' + results[i][2] + '&format=json', true); - addressRequest.send(); + // console.error('Request failed with status code ' + this.status + ', readystate: ' + this.readyState); + // } + // } + // console.log('https://nominatim.openstreetmap.org/reverse?lat=' + results[i][1] + '&lon=' + results[i][2] + '&format=json'); + // addressRequest.open("GET", 'https://nominatim.openstreetmap.org/reverse?lat=' + results[i][1] + '&lon=' + results[i][2] + '&format=json', true); + // addressRequest.send(); } else { // Don't show the div if the amount of divs (10) > amount of stickers From 1a304001ba8828182740ce573194a2dce222e2c2 Mon Sep 17 00:00:00 2001 From: Aron den Ouden Date: Fri, 4 Oct 2024 15:58:34 +0200 Subject: [PATCH 2/3] Rewrote near you overlay code to use fetch instead of XMLHttpRequest, now it is working properly --- static/js/nearYouOverlay.js | 312 ++++++++++++++++-------------------- 1 file changed, 138 insertions(+), 174 deletions(-) diff --git a/static/js/nearYouOverlay.js b/static/js/nearYouOverlay.js index 372d9d3..9d41e9f 100644 --- a/static/js/nearYouOverlay.js +++ b/static/js/nearYouOverlay.js @@ -1,63 +1,8 @@ -// This is a popup in the middle of the screen: -// var Overlay = L.Class.extend({ -// // this is the constructor -// initialize: function (selector, options) { -// L.Util.setOptions(this, options); -// this._selector = selector; - -// // create overlay here -// this._overlayElement = document.createElement('div'); -// this._overlayElement.id = 'overlay'; -// this._overlayElement.style.position = 'fixed'; -// this._overlayElement.style.top = '25%'; -// this._overlayElement.style.left = '25%'; -// this._overlayElement.style.width = '50%'; -// this._overlayElement.style.height = '50%'; -// this._overlayElement.style.backgroundColor = this.options.background; -// this._overlayElement.style.opacity = '0'; -// this._overlayElement.style.transition = 'opacity 0.3s'; -// this._overlayElement.style.zIndex = '-1'; -// this._overlayElement.style.display = 'flex'; -// this._overlayElement.style.alignItems = 'center'; -// this._overlayElement.style.justifyContent = 'center'; -// document.body.appendChild(this._overlayElement); -// }, - -// // these are the default options -// options: { -// isActive: false, -// background: 'rgba(0, 0, 0, 1)', -// }, - -// // this is a public function -// toggle: function () { -// this.isActive = !this.isActive; -// if (this.isActive) { -// this._overlayElement.style.opacity = '1'; -// this._overlayElement.style.zIndex = '999'; -// } else { -// this._overlayElement.style.opacity = '0'; -// this._overlayElement.style.zIndex = '-1'; -// } -// }, -// }); - -// var overlay = new Overlay('#overlay', { background: 'rgba(0, 0, 0, 1)' }); - -// nearYouButton.addEventListener('click', function(){ -// console.log("near you clicked!"); -// overlay.toggle(); -// }); - -// nearYouMobileOverlay = document.createElement('div'); -// nearYouMobileOverlay.id = 'nearYouMobileOverlay'; -// document.body.appendChild(nearYouMobileOverlay); - // Google maps style upwards drag overlay var Overlay = L.Class.extend({ - // this is the constructor + // Overylay constructor initialize: function (selector, options) { - L.Util.setOptions(this, options); + this.isActive = false; this._selector = selector; this._dragStartY = 0; this._overlayHeight = 0; @@ -105,16 +50,11 @@ var Overlay = L.Class.extend({ self.closeOverlay(); } // Above threshold -> reveal the overlay - else if (!self.isActive) { + else { self.openOverlay(); } }); }, - - // Default options - options: { - isActive: false, - }, createStickerDiv: function (i) { stickerDiv = document.createElement('div'); @@ -165,17 +105,18 @@ var Overlay = L.Class.extend({ }, openOverlay: function () { - this.isActive = !this.isActive; this._overlayElement.style.bottom = '0'; this._overlayElement.style.borderRadius = '0px 0px 0px 0px'; this._overlayElement.style.overflowY = 'auto'; this._line.style.display = 'none'; - this.getNearYouData(); - console.log("opened overlay!"); + if (!this.isActive) { + this.getNearYouData(); + } + this.isActive = true; }, closeOverlay: function () { - this.isActive = !this.isActive; + this.isActive = false; this._overlayElement.style.bottom = '-90%'; this._overlayElement.style.borderRadius = '15px 15px 0px 0px'; this._overlayElement.style.overflowY = 'hidden'; @@ -189,8 +130,10 @@ var Overlay = L.Class.extend({ getNearYouData: function () { var self = this; + // Get user location if (navigator.geolocation) { navigator.geolocation.getCurrentPosition(function(position) { + // Use user location to request nearby stickers from database self.requestDBStickers(position); }, showError); } else { @@ -198,127 +141,148 @@ var Overlay = L.Class.extend({ } }, + // Request nearby stickers from database requestDBStickers: function (position) { var self = this; - console.log("Your current position is:"); - console.log(`Latitude : ${position.coords.latitude}`); - console.log(`Longitude: ${position.coords.longitude}`); - if (!position.coords.latitude || !position.coords.longitude) { - return; + throw new Error("Location couldn't be accessed"); } - var request = new XMLHttpRequest(); - - var url = 'getNearYouStickers?'; - url += 'lon=' + position.coords.longitude; - url += '&lat=' + position.coords.latitude; + let nearYouStickersDBUrl = `getNearYouStickers?lon=${position.coords.longitude}&lat=${position.coords.latitude}`; - request.open('GET', url, true); - request.onreadystatechange = function(){ - if(this.readyState == 4){ - if(this.status == 200){ - var results = JSON.parse(this.responseText); - let stickerDivs = document.querySelectorAll('.stickerDiv'); - let stickerDivH1s = document.querySelectorAll('.stickerDivH1'); - let stickerDivImgs = document.querySelectorAll('.stickerDivImg'); - let stickerDivDates = document.querySelectorAll('.stickerDivDate'); - let stickerDivButtons = document.querySelectorAll('.stickerDivButton'); - let stickerDivNearbys = document.querySelectorAll('.stickerDivNearby'); - - for(var i = 0; i < stickerDivH1s.length; i++) { - if (i < results.length) { - stickerDivH1s[i].textContent = `Sticker ${results[i][0]}`; - stickerDivImgs[i].src = results[i][4]; - stickerDivDates[i].textContent = `Posted ${dayjs().to(dayjs(results[i][6]))}` - - stickerDivButtons[i].dataset.id = results[i][0]; - stickerDivButtons[i].dataset.lat = results[i][1]; - stickerDivButtons[i].dataset.long = results[i][2]; - stickerDivButtons[i].addEventListener('click', function(){ - console.log("Button clicked!"); - self.closeOverlay(); - mymap.flyTo([this.getAttribute('data-lat'), this.getAttribute('data-long')], 18); - let stickerID = this.getAttribute('data-id'); - - // Recursive function to check if the pointer with the desired ID is present in the array - function checkPointerAndOpenPopup(stickerID) { - for (var y = 0; y < pointersOnMap.length; y++) { - if (stickerID == pointersOnMap[y].id) { - pointersOnMap[y].pointer.openPopup(); - return; // Exit the function if the pointer is found - } - } - // If the pointer is not found, schedule the function to run again after a short delay - setTimeout(function() { - checkPointerAndOpenPopup(stickerID); - }, 100); - } - - // Call the recursive function to start checking for the pointer with the desired ID - checkPointerAndOpenPopup(stickerID); - }); - - // // Load nearby text (estimated address) - // var stickerDivNearby = stickerDivNearbys[i]; - // var addressRequest = new XMLHttpRequest(); - // addressRequest.onreadystatechange = function(){ - // if(this.readyState == 4 && this.status == 200){ - // var addressJson = JSON.parse(addressRequest.responseText); - // console.log(addressJson); - // var text = "Nearby "; - // if(addressJson['address']['road'] != undefined){ - // text += addressJson['address']['road']; - // if(addressJson['address']['house_number'] != undefined){ - // text += ' ' + addressJson['address']['house_number']; - // } - // } - // console.log(text); - // stickerDivNearby.textContent = text; - // } else { - // // Error handling for non-200 status codes - - // console.error('Request failed with status code ' + this.status + ', readystate: ' + this.readyState); - // } - // } - // console.log('https://nominatim.openstreetmap.org/reverse?lat=' + results[i][1] + '&lon=' + results[i][2] + '&format=json'); - // addressRequest.open("GET", 'https://nominatim.openstreetmap.org/reverse?lat=' + results[i][1] + '&lon=' + results[i][2] + '&format=json', true); - // addressRequest.send(); - } - else { - // Don't show the div if the amount of divs (10) > amount of stickers - stickerDivs[i].style.display = 'none'; - } - // Show the divs - stickerDivs.forEach(function(stickerDiv, index) { - setTimeout(function() { - stickerDiv.classList.add('revealed'); - }, index * 400); - }); - } - } else { - console.error('Error while loading near you stickers!'); + fetch(nearYouStickersDBUrl) + .then(response => { + if (!response.ok) { + throw new Error('Error while fetching near you stickers from database'); } + return response.json(); + }) + .then(results => { + this.processDBStickers(results); + }) + .catch(error => { + console.error(error.message); + }); + }, + + // Use database results to fill all stickers with content + processDBStickers: function (results) { + // Get sticker DOM elements + let stickerDivs = document.querySelectorAll('.stickerDiv'); + let stickerDivH1s = document.querySelectorAll('.stickerDivH1'); + let stickerDivImgs = document.querySelectorAll('.stickerDivImg'); + let stickerDivDates = document.querySelectorAll('.stickerDivDate'); + let stickerDivButtons = document.querySelectorAll('.stickerDivButton'); + let stickerDivNearbys = document.querySelectorAll('.stickerDivNearby'); + + // Iterate over sticker elements + for (let i = 0; i < stickerDivH1s.length; i++) { + if (i < results.length) { + let stickerData = results[i]; + + // Fill sticker with content + this.renderSticker(stickerDivH1s[i], stickerDivImgs[i], stickerDivDates[i], stickerData); + + // Add the 'open on map' button click event + this.addOpenOnmapClickListener(stickerDivButtons[i], stickerData[0], stickerData[1], stickerData[2]); + + // Fetch approximate address given the sticker coordinate + this.fetchStickerAddress(stickerData[1], stickerData[2], stickerDivNearbys[i]); + } else { + // Hide the sticker div when there are more divs than stickers + stickerDivs[i].style.display = 'none'; } } - request.send(); + + // Show the near you stickers + this.revealStickers(stickerDivs); }, - toggle: function () { - this.isActive = !this.isActive; - if (this.isActive) { - this.openOverlay(); - } else { - this.closeOverlay(); + // Fills individual stickers with content + renderSticker: function (stickerDivH1, stickerDivImg, stickerDivDate, stickerData) { + let [stickerID, lat, long, logoID, pictureURL, email, postTime, spots, verified] = stickerData; + + stickerDivH1.textContent = `Sticker ${stickerID}`; + stickerDivImg.src = pictureURL; + stickerDivDate.textContent = `Posted ${dayjs().to(dayjs(postTime))}`; + }, + + // Add 'open on map' button event listener + addOpenOnmapClickListener: function (stickerDivButton, stickerID, lat, long) { + let self = this; + stickerDivButton.dataset.id = stickerID; + stickerDivButton.dataset.lat = lat; + stickerDivButton.dataset.long = long; + + stickerDivButton.addEventListener('click', function () { + let stickerID = this.getAttribute('data-id'); + let lat = this.getAttribute('data-lat'); + let long = this.getAttribute('data-long'); + + self.handleOpenOnMapClick(stickerID, lat, long); + }); + }, + + handleOpenOnMapClick: function (stickerID, lat, long) { + this.closeOverlay(); + mymap.flyTo([lat, long], 18); + + // Stickers are loaded in only when they're in you view + // Therefore, when 'flying' to a sticker we need to 'find' it before we can open it + // This recursive function checks whether the sticker is present, it not tries again later until it is present + + function checkPointerAndOpenPopup(stickerID) { + for (let y = 0; y < pointersOnMap.length; y++) { + if (stickerID == pointersOnMap[y].id) { + pointersOnMap[y].pointer.openPopup(); + return; // Stop when the sticker is found and opened + } + } + // When the sticker isn't found, try again after a small pause + setTimeout(function () { + checkPointerAndOpenPopup(stickerID); + }, 100); } + + // Search for sticker on map and open it + checkPointerAndOpenPopup(stickerID); }, -}); -var overlay = new Overlay('#overlay'); + // Get approximate address of coordinates + fetchStickerAddress: function (lat, long, stickerDivNearby) { + let addressUrl = `https://nominatim.openstreetmap.org/reverse?lat=${lat}&lon=${long}&format=json`; + + fetch(addressUrl) + .then(addressResponse => { + if (!addressResponse.ok) { + throw new Error(`Address request failed with status: ${addressResponse.status}`); + } + return addressResponse.json(); + }) + .then(addressJson => { + let text = "Nearby "; + if (addressJson['address']['road'] != undefined) { + text += addressJson['address']['road']; + if (addressJson['address']['house_number'] != undefined) { + text += ' ' + addressJson['address']['house_number']; + } + } + stickerDivNearby.textContent = text; + }) + .catch(error => { + console.error('Error fetching nearby address:', error); + }); + }, -// nearYouButton.addEventListener('click', function(){ -// console.log("near you clicked!"); -// overlay.toggle(); -// }); + // Show all the stickers with a delay going from top (small delay) to bottom (large delay) + revealStickers: function (stickerDivs) { + stickerDivs.forEach(function (stickerDiv, index) { + setTimeout(function () { + stickerDiv.classList.add('revealed'); + }, index * 400); + }); + }, +}); +var overlay = new Overlay('#overlay'); From 275a5859524f50d648ca476294433d67d16f2fff Mon Sep 17 00:00:00 2001 From: Aron den Ouden Date: Fri, 4 Oct 2024 16:29:02 +0200 Subject: [PATCH 3/3] Refactored again, split some functions up and wrote helper functions mainly for handling DOM element creation --- static/js/nearYouOverlay.js | 235 ++++++++++++++++++------------------ 1 file changed, 116 insertions(+), 119 deletions(-) diff --git a/static/js/nearYouOverlay.js b/static/js/nearYouOverlay.js index 9d41e9f..539ecce 100644 --- a/static/js/nearYouOverlay.js +++ b/static/js/nearYouOverlay.js @@ -1,4 +1,8 @@ // Google maps style upwards drag overlay +const SNAP_THRESHOLD = 0.3; // 30% of the overlay height +const OVERLAY_HIDE_LIMIT = 0.8; // Limit to 80% below screen +const STICKER_REVEAL_DELAY = 400; // Delay between sticker reveal animations + var Overlay = L.Class.extend({ // Overylay constructor initialize: function (selector, options) { @@ -7,103 +11,98 @@ var Overlay = L.Class.extend({ this._dragStartY = 0; this._overlayHeight = 0; - this._overlayElement = document.createElement('div'); - this._overlayElement.id = 'nearYouMobileOverlay'; - - this._line = document.createElement('img'); - this._line.id = 'nearYouMobileLine'; - this._line.src = "./static/img/line.svg"; - this._overlayElement.appendChild(this._line); + this._overlayElement = this.createOverlayElement(); + document.body.appendChild(this._overlayElement); - this._nearYouTopText = document.createElement('h1'); - this._nearYouTopText.id = 'nearYouMobileTopText'; - this._nearYouTopTextText = document.createTextNode("Stickers near you"); - this._nearYouTopText.appendChild(this._nearYouTopTextText); - this._overlayElement.appendChild(this._nearYouTopText); + this.addTouchEventListeners(); + }, + // Create overlay structure + createOverlayElement: function () { + const overlayElement = document.createElement('div'); + overlayElement.id = 'nearYouMobileOverlay'; + + // Assign this._line here to make sure it's accessible + this._line = this.createElement('img', 'nearYouMobileLine', { src: './static/img/line.svg' }); + overlayElement.appendChild(this._line); + + const titleText = this.createElement('h1', 'nearYouMobileTopText', { textContent: "Stickers near you" }); + overlayElement.appendChild(titleText); + for (let i = 0; i < 10; i++) { - this.createStickerDiv(i); + this.createStickerDiv(i, overlayElement); } + + return overlayElement; + }, - document.body.appendChild(this._overlayElement); - - var self = this; - this._overlayElement.addEventListener('touchstart', function(e) { - self._dragStartY = e.touches[0].clientY; - self._overlayHeight = self._overlayElement.clientHeight; - }); - - this._overlayElement.addEventListener('touchmove', function(e) { - var deltaY = e.touches[0].clientY - self._dragStartY; - var newBottom = Math.max(-self._overlayHeight * 0.8, -deltaY); // Limit to 80% below - self._overlayElement.style.bottom = newBottom + 'px'; - if (self._overlayElement.scrollHeight - self._overlayElement.scrollTop === self._overlayElement.clientHeight) { - e.preventDefault(); // Prevent further scrolling - } - }); - - this._overlayElement.addEventListener('touchend', function(e) { - var snapThreshold = -self._overlayHeight * 0.3; // Snap when dragged beyond 30% of the overlay height - - // Under threshold -> snap back to the bottom - if (parseInt(self._overlayElement.style.bottom) < snapThreshold) { - self.closeOverlay(); - } - // Above threshold -> reveal the overlay - else { - self.openOverlay(); - } - }); + // Helper to create elements with attributes + createElement: function (tagName, id, attributes = {}) { + const element = document.createElement(tagName); + element.id = id; + Object.assign(element, attributes); + return element; }, - createStickerDiv: function (i) { - stickerDiv = document.createElement('div'); - stickerDiv.id = `stickerDiv-${i}`; - stickerDiv.classList.add('stickerDiv'); - - stickerDivH1 = document.createElement('h1'); - stickerDivH1.id = `stickerDivH1-${i}`; - stickerDivH1.classList.add('stickerDivH1'); - stickerDivH1Text = document.createTextNode(`stickerDivH1-${i}`); - stickerDivH1.appendChild(stickerDivH1Text); - stickerDiv.appendChild(stickerDivH1); - - stickerDivUser = document.createElement('h3'); - stickerDivUser.id = `stickerDivUser-${i}`; - stickerDivUser.classList.add('stickerDivUser'); - stickerDivUserText = document.createTextNode(`Sticked by ???`); - stickerDivUser.appendChild(stickerDivUserText); - stickerDiv.appendChild(stickerDivUser); - - stickerImg = document.createElement('img'); - stickerImg.id = `stickerDivImg-${i}`; - stickerImg.classList.add('stickerDivImg'); - stickerImg.src = ""; - stickerDiv.appendChild(stickerImg); - - stickerDivDate = document.createElement('h3'); - stickerDivDate.id = `stickerDivDate-${i}`; - stickerDivDate.classList.add('stickerDivDate'); - stickerDivDateText = document.createTextNode(`Posted ???`); - stickerDivDate.appendChild(stickerDivDateText); - stickerDiv.appendChild(stickerDivDate); - - stickerDivNearby = document.createElement('h3'); - stickerDivNearby.id = `stickerDivNearby-${i}`; - stickerDivNearby.classList.add('stickerDivNearby'); - stickerDivNearbyText = document.createTextNode(`Nearby ???`); - stickerDivNearby.appendChild(stickerDivNearbyText); - stickerDiv.appendChild(stickerDivNearby); - - stickerDivButton = document.createElement("button"); - stickerDivButton.id = `stickerDivButton-${i}`; - stickerDivButton.classList.add('stickerDivButton'); - stickerDivButton.innerHTML = "Open on map"; - stickerDiv.appendChild(stickerDivButton); - - this._overlayElement.appendChild(stickerDiv); + // Create individual sticker elements + createStickerDiv: function (i, parentElement) { + const stickerDiv = this.createElement('div', `stickerDiv-${i}`, { className: 'stickerDiv' }); + + const title = this.createElement('h1', `stickerDivH1-${i}`, { textContent: `stickerDivH1-${i}`, className: 'stickerDivH1' }); + stickerDiv.appendChild(title); + + const user = this.createElement('h3', `stickerDivUser-${i}`, { textContent: 'Sticked by ???', className: 'stickerDivUser' }); + stickerDiv.appendChild(user); + + const img = this.createElement('img', `stickerDivImg-${i}`, { src: '', className: 'stickerDivImg' }); + stickerDiv.appendChild(img); + + const date = this.createElement('h3', `stickerDivDate-${i}`, { textContent: 'Posted ???', className: 'stickerDivDate' }); + stickerDiv.appendChild(date); + + const nearby = this.createElement('h3', `stickerDivNearby-${i}`, { textContent: 'Nearby ???', className: 'stickerDivNearby' }); + stickerDiv.appendChild(nearby); + + const button = this.createElement('button', `stickerDivButton-${i}`, { innerHTML: 'Open on map', className: 'stickerDivButton' }); + stickerDiv.appendChild(button); + + parentElement.appendChild(stickerDiv); }, + addTouchEventListeners: function () { + const self = this; + + // Use named functions for event listeners + this._overlayElement.addEventListener('touchstart', this.onTouchStart.bind(self)); + this._overlayElement.addEventListener('touchmove', this.onTouchMove.bind(self)); + this._overlayElement.addEventListener('touchend', this.onTouchEnd.bind(self)); + }, + + onTouchStart: function (e) { + this._dragStartY = e.touches[0].clientY; + this._overlayHeight = this._overlayElement.clientHeight; + }, + + onTouchMove: function (e) { + const deltaY = e.touches[0].clientY - this._dragStartY; + const newBottom = Math.max(-this._overlayHeight * OVERLAY_HIDE_LIMIT, -deltaY); // Limit to OVERLAY_HIDE_LIMIT% below + this._overlayElement.style.bottom = `${newBottom}px`; + if (this._overlayElement.scrollHeight - this._overlayElement.scrollTop === this._overlayElement.clientHeight) { + e.preventDefault(); // Prevent further scrolling + } + }, + + onTouchEnd: function () { + const snapThreshold = -this._overlayHeight * SNAP_THRESHOLD; // Snap when dragged beyond SNAP_THRESHOLD% of the overlay height + + if (parseInt(this._overlayElement.style.bottom) < snapThreshold) { + this.closeOverlay(); + } else { + this.openOverlay(); + } + }, + + openOverlay: function () { this._overlayElement.style.bottom = '0'; this._overlayElement.style.borderRadius = '0px 0px 0px 0px'; @@ -123,19 +122,26 @@ var Overlay = L.Class.extend({ this._overlayElement.scrollTo(0, 0); this._line.style.display = 'block'; let stickerDivs = document.querySelectorAll('.stickerDiv'); - stickerDivs.forEach(function(stickerDiv) { - stickerDiv.classList.remove('revealed'); - }); + stickerDivs.forEach(div => div.classList.remove('revealed')); + }, + + handleGeolocationError: function (error) { + console.error(`Geolocation error: ${error.message}`); + alert("Geolocation is not supported by this browser."); + }, + + handleFetchError: function (error, url) { + console.error(`Error fetching from ${url}: ${error.message}`); }, getNearYouData: function () { - var self = this; - // Get user location + const self = this; if (navigator.geolocation) { - navigator.geolocation.getCurrentPosition(function(position) { + navigator.geolocation.getCurrentPosition( // Use user location to request nearby stickers from database - self.requestDBStickers(position); - }, showError); + position => self.requestDBStickers(position), + error => self.handleGeolocationError(error) + ); } else { alert("Geolocation is not supported by this browser."); } @@ -143,14 +149,11 @@ var Overlay = L.Class.extend({ // Request nearby stickers from database requestDBStickers: function (position) { - var self = this; - if (!position.coords.latitude || !position.coords.longitude) { throw new Error("Location couldn't be accessed"); } - let nearYouStickersDBUrl = `getNearYouStickers?lon=${position.coords.longitude}&lat=${position.coords.latitude}`; - + const nearYouStickersDBUrl = `getNearYouStickers?lon=${position.coords.longitude}&lat=${position.coords.latitude}`; fetch(nearYouStickersDBUrl) .then(response => { if (!response.ok) { @@ -158,32 +161,26 @@ var Overlay = L.Class.extend({ } return response.json(); }) - .then(results => { - this.processDBStickers(results); - }) - .catch(error => { - console.error(error.message); - }); + .then(results => this.processDBStickers(results)) + .catch(error => this.handleFetchError(error, nearYouStickersDBUrl)); }, // Use database results to fill all stickers with content processDBStickers: function (results) { // Get sticker DOM elements - let stickerDivs = document.querySelectorAll('.stickerDiv'); - let stickerDivH1s = document.querySelectorAll('.stickerDivH1'); - let stickerDivImgs = document.querySelectorAll('.stickerDivImg'); - let stickerDivDates = document.querySelectorAll('.stickerDivDate'); - let stickerDivButtons = document.querySelectorAll('.stickerDivButton'); - let stickerDivNearbys = document.querySelectorAll('.stickerDivNearby'); + const stickerDivs = document.querySelectorAll('.stickerDiv'); + const stickerDivH1s = document.querySelectorAll('.stickerDivH1'); + const stickerDivImgs = document.querySelectorAll('.stickerDivImg'); + const stickerDivDates = document.querySelectorAll('.stickerDivDate'); + const stickerDivButtons = document.querySelectorAll('.stickerDivButton'); + const stickerDivNearbys = document.querySelectorAll('.stickerDivNearby'); // Iterate over sticker elements - for (let i = 0; i < stickerDivH1s.length; i++) { + stickerDivH1s.forEach((title, i) => { if (i < results.length) { - let stickerData = results[i]; - + const stickerData = results[i]; // Fill sticker with content - this.renderSticker(stickerDivH1s[i], stickerDivImgs[i], stickerDivDates[i], stickerData); - + this.renderSticker(title, stickerDivImgs[i], stickerDivDates[i], stickerData); // Add the 'open on map' button click event this.addOpenOnmapClickListener(stickerDivButtons[i], stickerData[0], stickerData[1], stickerData[2]); @@ -193,9 +190,9 @@ var Overlay = L.Class.extend({ // Hide the sticker div when there are more divs than stickers stickerDivs[i].style.display = 'none'; } - } + }); - // Show the near you stickers + // Show all stickers this.revealStickers(stickerDivs); },