cleanup semicolon from js
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { t, i18n } from '../i18n.js';
|
||||
import { t, i18n } from '../i18n.js'
|
||||
|
||||
const CATEGORIES = {
|
||||
electronics: ['phones', 'computers', 'tv_audio', 'gaming', 'appliances'],
|
||||
@@ -9,50 +9,50 @@ const CATEGORIES = {
|
||||
books: ['fiction', 'nonfiction', 'textbooks', 'music_movies'],
|
||||
garden: ['plants', 'tools', 'outdoor_living', 'decoration'],
|
||||
other: ['collectibles', 'art', 'handmade', 'services']
|
||||
};
|
||||
}
|
||||
|
||||
const COUNTRIES = ['ch', 'de', 'at', 'fr', 'it', 'li'];
|
||||
const RADIUS_OPTIONS = [5, 10, 20, 50, 100, 200];
|
||||
const COUNTRIES = ['ch', 'de', 'at', 'fr', 'it', 'li']
|
||||
const RADIUS_OPTIONS = [5, 10, 20, 50, 100, 200]
|
||||
|
||||
class SearchBox extends HTMLElement {
|
||||
static get observedAttributes() {
|
||||
return ['category', 'subcategory', 'country', 'query'];
|
||||
return ['category', 'subcategory', 'country', 'query']
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.loadFiltersFromStorage();
|
||||
super()
|
||||
this.loadFiltersFromStorage()
|
||||
}
|
||||
|
||||
loadFiltersFromStorage() {
|
||||
const saved = localStorage.getItem('searchFilters');
|
||||
const saved = localStorage.getItem('searchFilters')
|
||||
if (saved) {
|
||||
try {
|
||||
const filters = JSON.parse(saved);
|
||||
this.selectedCategory = filters.category || '';
|
||||
this.selectedSubcategory = filters.subcategory || '';
|
||||
this.selectedCountry = filters.country || 'ch';
|
||||
this.selectedRadius = filters.radius || 50;
|
||||
this.useCurrentLocation = filters.useCurrentLocation || false;
|
||||
this.searchQuery = filters.query || '';
|
||||
const filters = JSON.parse(saved)
|
||||
this.selectedCategory = filters.category || ''
|
||||
this.selectedSubcategory = filters.subcategory || ''
|
||||
this.selectedCountry = filters.country || 'ch'
|
||||
this.selectedRadius = filters.radius || 50
|
||||
this.useCurrentLocation = filters.useCurrentLocation || false
|
||||
this.searchQuery = filters.query || ''
|
||||
} catch (e) {
|
||||
this.resetFilters();
|
||||
this.resetFilters()
|
||||
}
|
||||
} else {
|
||||
this.resetFilters();
|
||||
this.resetFilters()
|
||||
}
|
||||
}
|
||||
|
||||
resetFilters() {
|
||||
this.selectedCategory = '';
|
||||
this.selectedSubcategory = '';
|
||||
this.selectedCountry = 'ch';
|
||||
this.selectedRadius = 50;
|
||||
this.useCurrentLocation = false;
|
||||
this.searchQuery = '';
|
||||
this.geoLoading = false;
|
||||
this.currentLat = null;
|
||||
this.currentLng = null;
|
||||
this.selectedCategory = ''
|
||||
this.selectedSubcategory = ''
|
||||
this.selectedCountry = 'ch'
|
||||
this.selectedRadius = 50
|
||||
this.useCurrentLocation = false
|
||||
this.searchQuery = ''
|
||||
this.geoLoading = false
|
||||
this.currentLat = null
|
||||
this.currentLng = null
|
||||
}
|
||||
|
||||
saveFiltersToStorage() {
|
||||
@@ -63,61 +63,61 @@ class SearchBox extends HTMLElement {
|
||||
radius: this.selectedRadius,
|
||||
useCurrentLocation: this.useCurrentLocation,
|
||||
query: this.searchQuery
|
||||
};
|
||||
localStorage.setItem('searchFilters', JSON.stringify(filters));
|
||||
}
|
||||
localStorage.setItem('searchFilters', JSON.stringify(filters))
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
// Override from attributes if provided
|
||||
if (this.hasAttribute('category')) {
|
||||
this.selectedCategory = this.getAttribute('category');
|
||||
this.selectedCategory = this.getAttribute('category')
|
||||
}
|
||||
if (this.hasAttribute('subcategory')) {
|
||||
this.selectedSubcategory = this.getAttribute('subcategory');
|
||||
this.selectedSubcategory = this.getAttribute('subcategory')
|
||||
}
|
||||
if (this.hasAttribute('country')) {
|
||||
this.selectedCountry = this.getAttribute('country');
|
||||
this.selectedCountry = this.getAttribute('country')
|
||||
}
|
||||
if (this.hasAttribute('query')) {
|
||||
this.searchQuery = this.getAttribute('query');
|
||||
this.searchQuery = this.getAttribute('query')
|
||||
}
|
||||
|
||||
this.render();
|
||||
this.setupEventListeners();
|
||||
this.render()
|
||||
this.setupEventListeners()
|
||||
this.unsubscribe = i18n.subscribe(() => {
|
||||
this.render();
|
||||
this.setupEventListeners();
|
||||
});
|
||||
this.render()
|
||||
this.setupEventListeners()
|
||||
})
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
if (this.unsubscribe) this.unsubscribe();
|
||||
if (this.unsubscribe) this.unsubscribe()
|
||||
if (this._closeDropdown) {
|
||||
document.removeEventListener('click', this._closeDropdown);
|
||||
document.removeEventListener('click', this._closeDropdown)
|
||||
}
|
||||
}
|
||||
|
||||
attributeChangedCallback(name, oldValue, newValue) {
|
||||
if (oldValue === newValue) return;
|
||||
if (oldValue === newValue) return
|
||||
|
||||
switch (name) {
|
||||
case 'category':
|
||||
this.selectedCategory = newValue || '';
|
||||
break;
|
||||
this.selectedCategory = newValue || ''
|
||||
break
|
||||
case 'subcategory':
|
||||
this.selectedSubcategory = newValue || '';
|
||||
break;
|
||||
this.selectedSubcategory = newValue || ''
|
||||
break
|
||||
case 'country':
|
||||
this.selectedCountry = newValue || 'ch';
|
||||
break;
|
||||
this.selectedCountry = newValue || 'ch'
|
||||
break
|
||||
case 'query':
|
||||
this.searchQuery = newValue || '';
|
||||
break;
|
||||
this.searchQuery = newValue || ''
|
||||
break
|
||||
}
|
||||
|
||||
if (this.isConnected) {
|
||||
this.render();
|
||||
this.setupEventListeners();
|
||||
this.render()
|
||||
this.setupEventListeners()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,12 +146,12 @@ class SearchBox extends HTMLElement {
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
`;
|
||||
`
|
||||
}
|
||||
|
||||
renderFilters() {
|
||||
// Track which category accordion is expanded
|
||||
this._expandedCategory = this._expandedCategory || '';
|
||||
this._expandedCategory = this._expandedCategory || ''
|
||||
|
||||
return /* html */`
|
||||
<!-- Accordion Category Dropdown -->
|
||||
@@ -263,169 +263,169 @@ class SearchBox extends HTMLElement {
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
`
|
||||
}
|
||||
|
||||
setupEventListeners() {
|
||||
const form = this.querySelector('#search-form');
|
||||
const queryInput = this.querySelector('#search-query');
|
||||
const form = this.querySelector('#search-form')
|
||||
const queryInput = this.querySelector('#search-query')
|
||||
|
||||
// Desktop selects
|
||||
const countrySelect = this.querySelector('#country-select');
|
||||
const radiusSelect = this.querySelector('#radius-select');
|
||||
const countrySelect = this.querySelector('#country-select')
|
||||
const radiusSelect = this.querySelector('#radius-select')
|
||||
|
||||
// Mobile selects
|
||||
const countrySelectMobile = this.querySelector('#country-select-mobile');
|
||||
const radiusSelectMobile = this.querySelector('#radius-select-mobile');
|
||||
const countrySelectMobile = this.querySelector('#country-select-mobile')
|
||||
const radiusSelectMobile = this.querySelector('#radius-select-mobile')
|
||||
|
||||
// Accordion dropdown
|
||||
const categoryTrigger = this.querySelector('#category-trigger');
|
||||
const categoryMenu = this.querySelector('#category-menu');
|
||||
const categoryTrigger = this.querySelector('#category-trigger')
|
||||
const categoryMenu = this.querySelector('#category-menu')
|
||||
|
||||
form?.addEventListener('submit', (e) => {
|
||||
e.preventDefault();
|
||||
this.handleSearch();
|
||||
});
|
||||
e.preventDefault()
|
||||
this.handleSearch()
|
||||
})
|
||||
|
||||
queryInput?.addEventListener('input', (e) => {
|
||||
this.searchQuery = e.target.value;
|
||||
});
|
||||
this.searchQuery = e.target.value
|
||||
})
|
||||
|
||||
// Toggle dropdown
|
||||
if (categoryTrigger && categoryMenu) {
|
||||
categoryTrigger.addEventListener('click', (e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
categoryMenu.classList.toggle('open');
|
||||
});
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
categoryMenu.classList.toggle('open')
|
||||
})
|
||||
}
|
||||
|
||||
// Close dropdown on outside click
|
||||
this._closeDropdown = (e) => {
|
||||
if (!this.contains(e.target)) {
|
||||
categoryMenu?.classList.remove('open');
|
||||
categoryMenu?.classList.remove('open')
|
||||
}
|
||||
};
|
||||
document.addEventListener('click', this._closeDropdown);
|
||||
}
|
||||
document.addEventListener('click', this._closeDropdown)
|
||||
|
||||
// Category accordion headers - toggle expand
|
||||
this.querySelectorAll('.category-accordion > .category-item').forEach(item => {
|
||||
item.addEventListener('click', (e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
const cat = item.dataset.category;
|
||||
const accordion = item.closest('.category-accordion');
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
const cat = item.dataset.category
|
||||
const accordion = item.closest('.category-accordion')
|
||||
|
||||
// Toggle this accordion
|
||||
if (this._expandedCategory === cat) {
|
||||
this._expandedCategory = '';
|
||||
accordion?.classList.remove('expanded');
|
||||
this._expandedCategory = ''
|
||||
accordion?.classList.remove('expanded')
|
||||
} else {
|
||||
// Close other accordions
|
||||
this.querySelectorAll('.category-accordion.expanded').forEach(el => {
|
||||
el.classList.remove('expanded');
|
||||
});
|
||||
this._expandedCategory = cat;
|
||||
accordion?.classList.add('expanded');
|
||||
el.classList.remove('expanded')
|
||||
})
|
||||
this._expandedCategory = cat
|
||||
accordion?.classList.add('expanded')
|
||||
}
|
||||
});
|
||||
});
|
||||
})
|
||||
})
|
||||
|
||||
// "All categories" button
|
||||
this.querySelector('.category-item--all')?.addEventListener('click', (e) => {
|
||||
e.stopPropagation();
|
||||
this.selectedCategory = '';
|
||||
this.selectedSubcategory = '';
|
||||
this._expandedCategory = '';
|
||||
this.saveFiltersToStorage();
|
||||
categoryMenu?.classList.remove('open');
|
||||
this.render();
|
||||
this.setupEventListeners();
|
||||
});
|
||||
e.stopPropagation()
|
||||
this.selectedCategory = ''
|
||||
this.selectedSubcategory = ''
|
||||
this._expandedCategory = ''
|
||||
this.saveFiltersToStorage()
|
||||
categoryMenu?.classList.remove('open')
|
||||
this.render()
|
||||
this.setupEventListeners()
|
||||
})
|
||||
|
||||
// Subcategory items - select category + subcategory
|
||||
this.querySelectorAll('.subcategory-item').forEach(item => {
|
||||
item.addEventListener('click', (e) => {
|
||||
e.stopPropagation();
|
||||
this.selectedCategory = item.dataset.category;
|
||||
this.selectedSubcategory = item.dataset.subcategory;
|
||||
this._expandedCategory = '';
|
||||
this.saveFiltersToStorage();
|
||||
categoryMenu?.classList.remove('open');
|
||||
this.render();
|
||||
this.setupEventListeners();
|
||||
});
|
||||
});
|
||||
e.stopPropagation()
|
||||
this.selectedCategory = item.dataset.category
|
||||
this.selectedSubcategory = item.dataset.subcategory
|
||||
this._expandedCategory = ''
|
||||
this.saveFiltersToStorage()
|
||||
categoryMenu?.classList.remove('open')
|
||||
this.render()
|
||||
this.setupEventListeners()
|
||||
})
|
||||
})
|
||||
|
||||
// Country select handler (both desktop and mobile)
|
||||
const handleCountryChange = (e) => {
|
||||
if (e.target.value === 'current') {
|
||||
this.useCurrentLocation = true;
|
||||
this.requestGeolocation();
|
||||
this.useCurrentLocation = true
|
||||
this.requestGeolocation()
|
||||
} else {
|
||||
this.useCurrentLocation = false;
|
||||
this.selectedCountry = e.target.value;
|
||||
this.useCurrentLocation = false
|
||||
this.selectedCountry = e.target.value
|
||||
}
|
||||
this.saveFiltersToStorage();
|
||||
this.render();
|
||||
this.setupEventListeners();
|
||||
};
|
||||
this.saveFiltersToStorage()
|
||||
this.render()
|
||||
this.setupEventListeners()
|
||||
}
|
||||
|
||||
countrySelect?.addEventListener('change', handleCountryChange);
|
||||
countrySelectMobile?.addEventListener('change', handleCountryChange);
|
||||
countrySelect?.addEventListener('change', handleCountryChange)
|
||||
countrySelectMobile?.addEventListener('change', handleCountryChange)
|
||||
|
||||
// Radius select handler (both desktop and mobile)
|
||||
const handleRadiusChange = (e) => {
|
||||
this.selectedRadius = parseInt(e.target.value);
|
||||
this.saveFiltersToStorage();
|
||||
};
|
||||
this.selectedRadius = parseInt(e.target.value)
|
||||
this.saveFiltersToStorage()
|
||||
}
|
||||
|
||||
radiusSelect?.addEventListener('change', handleRadiusChange);
|
||||
radiusSelectMobile?.addEventListener('change', handleRadiusChange);
|
||||
radiusSelect?.addEventListener('change', handleRadiusChange)
|
||||
radiusSelectMobile?.addEventListener('change', handleRadiusChange)
|
||||
|
||||
// Adjust select width to selected option (desktop only)
|
||||
this.adjustSelectWidth(countrySelect);
|
||||
this.adjustSelectWidth(radiusSelect);
|
||||
this.adjustSelectWidth(countrySelect)
|
||||
this.adjustSelectWidth(radiusSelect)
|
||||
}
|
||||
|
||||
adjustSelectWidth(select) {
|
||||
if (!select) return;
|
||||
if (!select) return
|
||||
|
||||
// Only apply fixed width on desktop (768px+)
|
||||
if (window.innerWidth < 768) {
|
||||
select.style.width = '';
|
||||
return;
|
||||
select.style.width = ''
|
||||
return
|
||||
}
|
||||
|
||||
// Create hidden span to measure text width
|
||||
const measurer = document.createElement('span');
|
||||
measurer.style.cssText = 'position:absolute;visibility:hidden;white-space:nowrap;font:inherit;';
|
||||
select.parentElement.appendChild(measurer);
|
||||
const measurer = document.createElement('span')
|
||||
measurer.style.cssText = 'position:absolute;visibility:hidden;white-space:nowrap;font:inherit;'
|
||||
select.parentElement.appendChild(measurer)
|
||||
|
||||
const selectedOption = select.options[select.selectedIndex];
|
||||
measurer.textContent = selectedOption ? selectedOption.textContent : '';
|
||||
const selectedOption = select.options[select.selectedIndex]
|
||||
measurer.textContent = selectedOption ? selectedOption.textContent : ''
|
||||
|
||||
// Add padding for arrow, icon and buffer
|
||||
select.style.width = (measurer.offsetWidth + 90) + 'px';
|
||||
measurer.remove();
|
||||
select.style.width = (measurer.offsetWidth + 90) + 'px'
|
||||
measurer.remove()
|
||||
}
|
||||
|
||||
handleSearch() {
|
||||
const params = new URLSearchParams();
|
||||
const params = new URLSearchParams()
|
||||
|
||||
if (this.searchQuery) params.set('q', this.searchQuery);
|
||||
if (this.selectedCategory) params.set('category', this.selectedCategory);
|
||||
if (this.selectedSubcategory) params.set('sub', this.selectedSubcategory);
|
||||
if (this.searchQuery) params.set('q', this.searchQuery)
|
||||
if (this.selectedCategory) params.set('category', this.selectedCategory)
|
||||
if (this.selectedSubcategory) params.set('sub', this.selectedSubcategory)
|
||||
|
||||
if (this.useCurrentLocation && this.currentLat && this.currentLng) {
|
||||
params.set('lat', this.currentLat);
|
||||
params.set('lng', this.currentLng);
|
||||
params.set('radius', this.selectedRadius);
|
||||
params.set('lat', this.currentLat)
|
||||
params.set('lng', this.currentLng)
|
||||
params.set('radius', this.selectedRadius)
|
||||
} else if (!this.useCurrentLocation) {
|
||||
params.set('country', this.selectedCountry);
|
||||
params.set('country', this.selectedCountry)
|
||||
}
|
||||
|
||||
this.saveFiltersToStorage();
|
||||
this.saveFiltersToStorage()
|
||||
|
||||
// Emit custom event
|
||||
const event = new CustomEvent('search', {
|
||||
@@ -442,63 +442,63 @@ class SearchBox extends HTMLElement {
|
||||
radius: this.selectedRadius,
|
||||
params: params.toString()
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
const cancelled = !this.dispatchEvent(event);
|
||||
const cancelled = !this.dispatchEvent(event)
|
||||
|
||||
// Navigate to search page unless event was cancelled
|
||||
if (!cancelled && !this.hasAttribute('no-navigate')) {
|
||||
const url = '#/search' + (params.toString() ? '?' + params.toString() : '');
|
||||
window.location.hash = url;
|
||||
const url = '#/search' + (params.toString() ? '?' + params.toString() : '')
|
||||
window.location.hash = url
|
||||
}
|
||||
}
|
||||
|
||||
requestGeolocation() {
|
||||
if (!('geolocation' in navigator)) {
|
||||
this.handleGeoError();
|
||||
return;
|
||||
this.handleGeoError()
|
||||
return
|
||||
}
|
||||
|
||||
this.geoLoading = true;
|
||||
this.updateGeoButton();
|
||||
this.geoLoading = true
|
||||
this.updateGeoButton()
|
||||
|
||||
navigator.geolocation.getCurrentPosition(
|
||||
(position) => {
|
||||
this.currentLat = position.coords.latitude;
|
||||
this.currentLng = position.coords.longitude;
|
||||
this.geoLoading = false;
|
||||
this.updateGeoButton();
|
||||
this.currentLat = position.coords.latitude
|
||||
this.currentLng = position.coords.longitude
|
||||
this.geoLoading = false
|
||||
this.updateGeoButton()
|
||||
},
|
||||
(error) => {
|
||||
console.warn('Geolocation error:', error);
|
||||
this.handleGeoError();
|
||||
console.warn('Geolocation error:', error)
|
||||
this.handleGeoError()
|
||||
},
|
||||
{ timeout: 10000, enableHighAccuracy: false }
|
||||
);
|
||||
)
|
||||
}
|
||||
|
||||
handleGeoError() {
|
||||
// Keep useCurrentLocation = true, just stop loading indicator
|
||||
// User can still search by current location (backend will handle it)
|
||||
this.geoLoading = false;
|
||||
this.updateGeoButton();
|
||||
this.geoLoading = false
|
||||
this.updateGeoButton()
|
||||
}
|
||||
|
||||
updateGeoButton() {
|
||||
const countrySelect = this.querySelector('#country-select');
|
||||
if (!countrySelect) return;
|
||||
const countrySelect = this.querySelector('#country-select')
|
||||
if (!countrySelect) return
|
||||
|
||||
if (this.geoLoading) {
|
||||
countrySelect.disabled = true;
|
||||
const currentOption = countrySelect.querySelector('option[value="current"]');
|
||||
countrySelect.disabled = true
|
||||
const currentOption = countrySelect.querySelector('option[value="current"]')
|
||||
if (currentOption) {
|
||||
currentOption.textContent = `⏳ ${t('search.locating')}`;
|
||||
currentOption.textContent = `⏳ ${t('search.locating')}`
|
||||
}
|
||||
} else {
|
||||
countrySelect.disabled = false;
|
||||
const currentOption = countrySelect.querySelector('option[value="current"]');
|
||||
countrySelect.disabled = false
|
||||
const currentOption = countrySelect.querySelector('option[value="current"]')
|
||||
if (currentOption) {
|
||||
currentOption.textContent = `📍 ${t('search.currentLocation')}`;
|
||||
currentOption.textContent = `📍 ${t('search.currentLocation')}`
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -514,33 +514,33 @@ class SearchBox extends HTMLElement {
|
||||
lat: this.currentLat,
|
||||
lng: this.currentLng,
|
||||
radius: this.selectedRadius
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
setFilters(filters) {
|
||||
if (filters.query !== undefined) this.searchQuery = filters.query;
|
||||
if (filters.category !== undefined) this.selectedCategory = filters.category;
|
||||
if (filters.subcategory !== undefined) this.selectedSubcategory = filters.subcategory;
|
||||
if (filters.country !== undefined) this.selectedCountry = filters.country;
|
||||
if (filters.radius !== undefined) this.selectedRadius = filters.radius;
|
||||
if (filters.useCurrentLocation !== undefined) this.useCurrentLocation = filters.useCurrentLocation;
|
||||
if (filters.query !== undefined) this.searchQuery = filters.query
|
||||
if (filters.category !== undefined) this.selectedCategory = filters.category
|
||||
if (filters.subcategory !== undefined) this.selectedSubcategory = filters.subcategory
|
||||
if (filters.country !== undefined) this.selectedCountry = filters.country
|
||||
if (filters.radius !== undefined) this.selectedRadius = filters.radius
|
||||
if (filters.useCurrentLocation !== undefined) this.useCurrentLocation = filters.useCurrentLocation
|
||||
|
||||
this.saveFiltersToStorage();
|
||||
this.render();
|
||||
this.setupEventListeners();
|
||||
this.saveFiltersToStorage()
|
||||
this.render()
|
||||
this.setupEventListeners()
|
||||
}
|
||||
|
||||
clearFilters() {
|
||||
this.resetFilters();
|
||||
localStorage.removeItem('searchFilters');
|
||||
this.render();
|
||||
this.setupEventListeners();
|
||||
this.resetFilters()
|
||||
localStorage.removeItem('searchFilters')
|
||||
this.render()
|
||||
this.setupEventListeners()
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('search-box', SearchBox);
|
||||
customElements.define('search-box', SearchBox)
|
||||
|
||||
const style = document.createElement('style');
|
||||
const style = document.createElement('style')
|
||||
style.textContent = /* css */`
|
||||
search-box {
|
||||
display: block;
|
||||
@@ -905,7 +905,7 @@ style.textContent = /* css */`
|
||||
background: var(--color-primary-light);
|
||||
color: var(--color-primary);
|
||||
}
|
||||
`;
|
||||
document.head.appendChild(style);
|
||||
`
|
||||
document.head.appendChild(style)
|
||||
|
||||
export { SearchBox, CATEGORIES, COUNTRIES, RADIUS_OPTIONS };
|
||||
export { SearchBox, CATEGORIES, COUNTRIES, RADIUS_OPTIONS }
|
||||
|
||||
Reference in New Issue
Block a user