(function () {
'use strict';
var config = window.MeinWeimarCore || {};
var strings = config.strings || {};
var resourceTypes = config.geoResourceTypes || config.resourceTypes || ['places', 'events'];
var resourceLabels = config.resourceLabels || {};
function escapeHtml(value) {
return String(value || '')
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''');
}
function formatDistance(distance) {
if (typeof distance !== 'number') {
return '';
}
return '<span class="mw-card__distance">' + escapeHtml(distance.toFixed(1)) + ' ' + escapeHtml(strings.distanceUnit || '') + '</span>';
}
function formatListingNumber(value) {
var number = Number(value);
if (!isFinite(number)) {
return '';
}
try {
return new Intl.NumberFormat(document.documentElement.lang || undefined, {
maximumFractionDigits: 2
}).format(number);
} catch (error) {
return String(number);
}
}
function listingPrice(listing, resource) {
if (listing.price_label) {
return String(listing.price_label);
}
if (resource === 'classifieds' && String(listing.price_type || '') === 'free') {
return strings.listingPriceFree || '';
}
if (String(listing.price_type || '') === 'on_request') {
return strings.listingPriceOnRequest || '';
}
if (listing.price_amount !== null && typeof listing.price_amount !== 'undefined' && listing.price_amount !== '') {
return formatListingNumber(listing.price_amount) + (listing.price_currency ? ' ' + String(listing.price_currency) : '');
}
return '';
}
function listingSummary(item) {
var listing = item && item.listing && typeof item.listing === 'object' ? item.listing : {};
var resource = item && (item.resource || item.type) || '';
var values = [];
if (resource === 'real-estate') {
var transactions = {
sale: strings.listingTransactionSale,
rent: strings.listingTransactionRent,
lease: strings.listingTransactionRent,
temporary: strings.listingTransactionRent
};
if (transactions[String(listing.transaction_type || '')]) {
values.push(transactions[String(listing.transaction_type)]);
}
if (listing.area !== null && typeof listing.area !== 'undefined' && listing.area !== '') {
values.push(formatListingNumber(listing.area) + ' ' + (strings.listingAreaUnit || ''));
}
if (listing.rooms !== null && typeof listing.rooms !== 'undefined' && listing.rooms !== '') {
values.push(formatListingNumber(listing.rooms) + ' ' + (strings.listingRoomsUnit || ''));
}
}
if (resource === 'jobs' && listing.company_name) {
values.push(String(listing.company_name));
}
var price = listingPrice(listing, resource);
if (price) {
values.push(price);
}
return values.filter(function (value) { return String(value || '').trim() !== ''; }).map(escapeHtml).join(' · ');
}
function renderCard(item) {
var address = item.address || {};
var location = [address.line1, address.postal_code, address.locality].filter(Boolean).join(', ');
var resource = item.resource || item.type || '';
var resourceLabel = resourceLabels[resource] || resource;
var media = item.media && item.media[0] ? item.media[0] : {};
var imageAlt = media.alt || item.title || '';
var image = item.image_url ? '<img class="mw-card__image" src="' + escapeHtml(item.image_url) + '"' +
(media.srcset ? ' srcset="' + escapeHtml(media.srcset) + '" sizes="(max-width: 700px) 100vw, 360px"' : '') +
' loading="lazy" alt="' + escapeHtml(imageAlt) + '">' : '';
var summary = listingSummary(item);
return '<article id="mw-item-' + escapeHtml(item.id) + '" class="mw-card" data-mw-item-id="' + escapeHtml(item.id) + '" tabindex="-1">' +
image +
'<div class="mw-card__content">' +
'<p class="mw-card__type">' + escapeHtml(resourceLabel) + '</p>' +
'<h3 class="mw-card__title"><a href="' + escapeHtml(item.url) + '">' + escapeHtml(item.title) + '</a></h3>' +
(location ? '<p class="mw-card__location">' + escapeHtml(location) + '</p>' : '') +
(summary ? '<p class="mw-card__listing-summary">' + summary + '</p>' : '') +
(item.excerpt ? '<p class="mw-card__excerpt">' + escapeHtml(item.excerpt) + '</p>' : '') +
'<a class="mw-card__details" href="' + escapeHtml(item.url) + '">' + escapeHtml(strings.openDetails || '') + '</a>' +
formatDistance(item.distance_km) +
'</div></article>';
}
function initImageSuggestion(root) {
var toggle = root.querySelector('[data-image-suggestion-toggle]');
var panel = root.querySelector('[data-image-suggestion-panel]');
var form = root.querySelector('[data-image-suggestion-form]');
var file = root.querySelector('[data-image-suggestion-file]');
var preview = root.querySelector('[data-image-suggestion-preview]');
var previewImage = root.querySelector('[data-image-suggestion-preview-image]');
var status = root.querySelector('[data-image-suggestion-status]');
var history = root.querySelector('[data-image-suggestion-history]');
function statusLabel(value) {
return {
submitted: strings.imageSuggestStatusSubmitted,
in_review: strings.imageSuggestStatusInReview,
accepted: strings.imageSuggestStatusAccepted,
rejected: strings.imageSuggestStatusRejected,
needs_info: strings.imageSuggestStatusNeedsInfo
}[value] || strings.imageSuggestStatusSubmitted || '';
}
function formatSuggestionDate(value) {
var raw = String(value || '').trim();
if (!raw) {
return '';
}
var normalized = raw.indexOf('T') === -1 ? raw.replace(' ', 'T') : raw;
if (!/[zZ]|[+-]\d\d:\d\d$/.test(normalized)) {
normalized += 'Z';
}
var parsed = new Date(normalized);
if (isNaN(parsed.getTime())) {
return '';
}
try {
return new Intl.DateTimeFormat(document.documentElement.lang || undefined, {
year: 'numeric',
month: 'short',
day: 'numeric',
hour: '2-digit',
minute: '2-digit'
}).format(parsed);
} catch (error) {
return parsed.toLocaleString();
}
}
function submittedAtLabel(value) {
var date = formatSuggestionDate(value);
if (!date) {
return '';
}
var template = strings.imageSuggestSubmittedAt;
if (typeof template !== 'string' || !template) {
return date;
}
return template.replace('{date}', date).replace('%s', date);
}
function errorMessage(payload) {
var code = payload && typeof payload.code === 'string' ? payload.code : '';
if (code === 'meinweimar_auth_required') {
return strings.imageSuggestErrorAuth || '';
}
if (code.indexOf('rate_limited') !== -1 || code.indexOf('target_limit') !== -1) {
return strings.imageSuggestErrorRateLimit || '';
}
if (code.indexOf('duplicate') !== -1 || code.indexOf('conflict') !== -1 || code.indexOf('transition') !== -1) {
return strings.imageSuggestErrorConflict || '';
}
if (code.indexOf('response_required') !== -1 || code.indexOf('request_message_required') !== -1) {
return strings.imageSuggestResponseRequired || strings.imageSuggestErrorValidation || '';
}
if (code.indexOf('idempotency_required') !== -1) {
return strings.imageSuggestErrorValidation || '';
}
if (code.indexOf('malware') !== -1 || code.indexOf('sanitize') !== -1 || code.indexOf('animation') !== -1 || code.indexOf('scan_') !== -1) {
return strings.imageSuggestErrorSecurity || '';
}
if (code.indexOf('rights') !== -1 || code.indexOf('file_') !== -1 || code.indexOf('upload_') !== -1 || code.indexOf('dimensions') !== -1 || code.indexOf('target_type') !== -1) {
return strings.imageSuggestErrorValidation || '';
}
return strings.imageSuggestErrorGeneric || strings.imageSuggestError || '';
}
function loadHistory() {
if (!history || !config.isLoggedIn) {
return;
}
var query = new URLSearchParams({
target_type: root.getAttribute('data-target-type') || '',
target_id: root.getAttribute('data-target-id') || ''
});
fetch((config.restUrl || '/wp-json/meinweimar/v1/') + 'image-suggestions?' + query.toString(), {
credentials: 'same-origin',
headers: config.restNonce ? { 'X-WP-Nonce': config.restNonce } : {}
}).then(function (response) {
if (!response.ok) {
throw new Error('history_failed');
}
return response.json();
}).then(function (payload) {
var suggestions = payload && Array.isArray(payload.suggestions) ? payload.suggestions : [];
if (!suggestions.length) {
history.hidden = true;
history.innerHTML = '';
return;
}
history.innerHTML = '<h3>' + escapeHtml(strings.imageSuggestHistory || '') + '</h3>' + suggestions.map(function (suggestion) {
var filename = suggestion.original_filename || '';
var submittedAt = submittedAtLabel(suggestion.created_at || '');
var submittedAtMarkup = submittedAt ? ' · <time datetime="' + escapeHtml(suggestion.created_at || '') + '">' + escapeHtml(submittedAt) + '</time>' : '';
var responseForm = '';
if (suggestion.status === 'needs_info') {
responseForm = '<div class="mw-image-suggestion__response">' +
'<p class="mw-image-suggestion__response-prompt">' + escapeHtml(suggestion.request_message || strings.imageSuggestResponseBody || '') + '</p>' +
'<form data-image-suggestion-response-form data-suggestion-id="' + escapeHtml(suggestion.id) + '">' +
'<label for="mw-image-suggestion-response-' + escapeHtml(suggestion.id) + '">' + escapeHtml(strings.imageSuggestResponseLabel || '') + '</label>' +
'<textarea id="mw-image-suggestion-response-' + escapeHtml(suggestion.id) + '" name="response" maxlength="2000" required></textarea>' +
'<button type="submit">' + escapeHtml(strings.imageSuggestResponseSubmit || '') + '</button>' +
'<p class="mw-image-suggestion__response-status" data-image-suggestion-response-status aria-live="polite"></p>' +
'</form></div>';
}
return '<div class="mw-image-suggestion__history-item"><p><strong>' + escapeHtml(statusLabel(suggestion.status)) + '</strong>' +
(filename ? ' · ' + escapeHtml(filename) : '') + submittedAtMarkup + '</p>' + responseForm + '</div>';
}).join('');
history.hidden = false;
}).catch(function () {
history.innerHTML = '<p role="alert">' + escapeHtml(strings.imageSuggestHistoryError || strings.imageSuggestErrorGeneric || '') + '</p>' +
'<button type="button" data-image-suggestion-history-retry>' + escapeHtml(strings.imageSuggestHistoryRetry || '') + '</button>';
history.hidden = false;
var retry = history.querySelector('[data-image-suggestion-history-retry]');
if (retry) {
retry.addEventListener('click', loadHistory);
}
});
}
if (toggle && panel) {
toggle.addEventListener('click', function () {
var expanded = !panel.hidden;
panel.hidden = expanded;
toggle.setAttribute('aria-expanded', expanded ? 'false' : 'true');
});
}
if (!form || !file) {
return;
}
if (history) {
history.addEventListener('submit', function (event) {
var responseForm = event.target.closest('[data-image-suggestion-response-form]');
if (!responseForm) {
return;
}
event.preventDefault();
var textarea = responseForm.querySelector('textarea[name="response"]');
var responseStatus = responseForm.querySelector('[data-image-suggestion-response-status]');
var submit = responseForm.querySelector('[type="submit"]');
var response = textarea ? textarea.value.trim() : '';
if (!response) {
if (responseStatus) {
responseStatus.textContent = strings.imageSuggestResponseRequired || '';
}
return;
}
var suggestionId = responseForm.getAttribute('data-suggestion-id') || '';
var idempotencyKey = responseForm.dataset.imageSuggestionResponseIdempotencyKey || createIdempotencyKey();
responseForm.dataset.imageSuggestionResponseIdempotencyKey = idempotencyKey;
if (submit) {
submit.disabled = true;
}
if (responseStatus) {
responseStatus.textContent = strings.imageSuggestResponseSubmitting || '';
}
fetch((config.restUrl || '/wp-json/meinweimar/v1/') + 'image-suggestions/' + encodeURIComponent(suggestionId), {
method: 'POST',
credentials: 'same-origin',
headers: Object.assign({
'Content-Type': 'application/json',
'Accept': 'application/json'
}, config.restNonce ? { 'X-WP-Nonce': config.restNonce } : {}, {
'Idempotency-Key': idempotencyKey
}),
body: JSON.stringify({ response: response })
}).then(function (result) {
return result.json().catch(function () { return {}; }).then(function (payload) {
if (!result.ok) {
var error = new Error(errorMessage(payload));
error.payload = payload;
throw error;
}
return payload;
});
}).then(function () {
if (responseStatus) {
responseStatus.textContent = strings.imageSuggestResponseSent || '';
}
if (textarea) {
textarea.value = '';
}
delete responseForm.dataset.imageSuggestionResponseIdempotencyKey;
loadHistory();
}).catch(function (error) {
if (responseStatus) {
responseStatus.textContent = error.message || strings.imageSuggestError || '';
}
}).finally(function () {
if (submit) {
submit.disabled = false;
}
});
});
}
file.addEventListener('change', function () {
var selected = file.files && file.files[0];
if (!selected || !preview || !previewImage) {
return;
}
if (previewImage.dataset.objectUrl) {
URL.revokeObjectURL(previewImage.dataset.objectUrl);
}
previewImage.dataset.objectUrl = URL.createObjectURL(selected);
previewImage.src = previewImage.dataset.objectUrl;
preview.hidden = false;
});
form.addEventListener('submit', function (event) {
event.preventDefault();
if (!config.isLoggedIn) {
return;
}
var submit = form.querySelector('[type="submit"]');
var formData = new FormData(form);
formData.append('target_type', root.getAttribute('data-target-type') || '');
formData.append('target_id', root.getAttribute('data-target-id') || '');
if (status) {
status.textContent = strings.imageSuggestSubmitting || '';
}
if (submit) {
submit.disabled = true;
}
var idempotencyKey = root.dataset.imageSuggestionIdempotencyKey || createIdempotencyKey();
root.dataset.imageSuggestionIdempotencyKey = idempotencyKey;
fetch((config.restUrl || '/wp-json/meinweimar/v1/') + 'image-suggestions', {
method: 'POST',
credentials: 'same-origin',
headers: Object.assign(
config.restNonce ? { 'X-WP-Nonce': config.restNonce } : {},
{ 'Idempotency-Key': idempotencyKey }
),
body: formData
}).then(function (response) {
return response.json().catch(function () { return {}; }).then(function (payload) {
if (!response.ok) {
var error = new Error(errorMessage(payload));
error.payload = payload;
throw error;
}
return payload;
});
}).then(function (payload) {
var suggestion = payload && payload.suggestion ? payload.suggestion : {};
if (status) {
status.textContent = (strings.imageSuggestStatus || '') + ': ' + statusLabel(suggestion.status);
}
form.reset();
delete root.dataset.imageSuggestionIdempotencyKey;
if (preview) {
preview.hidden = true;
}
if (previewImage && previewImage.dataset.objectUrl) {
URL.revokeObjectURL(previewImage.dataset.objectUrl);
delete previewImage.dataset.objectUrl;
previewImage.removeAttribute('src');
}
loadHistory();
}).catch(function (error) {
if (status) {
status.textContent = error.message || strings.imageSuggestError || '';
}
}).finally(function () {
if (submit) {
submit.disabled = false;
}
});
});
loadHistory();
}
function createIdempotencyKey() {
if (window.crypto && typeof window.crypto.randomUUID === 'function') {
return window.crypto.randomUUID();
}
return 'mw-' + String(Date.now()) + '-' + String(Math.random()).slice(2);
}
function initAccount(root) {
var form = root.querySelector('[data-mw-account-form]');
var status = root.querySelector('[data-mw-account-status]');
var favorites = root.querySelector('[data-mw-account-favorites]');
var favoritesStatus = root.querySelector('[data-mw-account-favorites-status]');
var favoritesList = root.querySelector('[data-mw-account-favorites-list]');
function safeHref(value) {
var href = String(value || '');
return /^(https?:\/\/|\/)/i.test(href) ? href : '#';
}
function renderFavorites(items) {
if (!favoritesList) {
return;
}
if (!items.length) {
favoritesList.innerHTML = '<p>' + escapeHtml(strings.accountFavoritesEmpty || '') + '</p>';
return;
}
favoritesList.innerHTML = items.map(function (entry) {
var item = entry && entry.item ? entry.item : {};
var media = item.media && item.media[0] ? item.media[0] : {};
var image = item.image_url ? '<img class="mw-account__saved-image" src="' + escapeHtml(item.image_url) + '" alt="' + escapeHtml(media.alt || item.title || '') + '" loading="lazy">' : '';
var address = item.address || {};
var location = [address.line1, address.postal_code, address.locality].filter(Boolean).join(', ');
return '<article class="mw-account__saved-card">' + image +
'<div class="mw-account__saved-content">' +
'<p class="mw-account__saved-type">' + escapeHtml(resourceLabels[item.resource] || item.resource || '') + '</p>' +
'<h4>' + escapeHtml(item.title || '') + '</h4>' +
(location ? '<p>' + escapeHtml(location) + '</p>' : '') +
'<a href="' + escapeHtml(safeHref(item.url)) + '">' + escapeHtml(strings.accountFavoritesOpen || '') + '</a>' +
'</div></article>';
}).join('');
}
function loadFavorites() {
if (!favorites || !favoritesList || !config.isLoggedIn) {
return;
}
if (favoritesStatus) {
favoritesStatus.textContent = strings.accountFavoritesLoading || '';
}
fetch((config.restUrl || '/wp-json/meinweimar/v1/') + 'favorites', {
credentials: 'same-origin',
headers: config.restNonce ? { 'X-WP-Nonce': config.restNonce } : {}
}).then(function (response) {
if (!response.ok) {
throw new Error('favorites_failed');
}
return response.json();
}).then(function (payload) {
renderFavorites(payload && Array.isArray(payload.items) ? payload.items : []);
if (favoritesStatus) {
favoritesStatus.textContent = '';
}
}).catch(function () {
if (favoritesStatus) {
favoritesStatus.textContent = strings.accountFavoritesError || '';
}
});
}
if (!config.isLoggedIn) {
return;
}
form.addEventListener('submit', function (event) {
event.preventDefault();
var submit = form.querySelector('[type="submit"]');
var data = new FormData(form);
var payload = {};
data.forEach(function (value, key) {
payload[key] = value;
});
if (status) {
status.textContent = strings.accountSaving || '';
}
if (submit) {
submit.disabled = true;
}
fetch((config.restUrl || '/wp-json/meinweimar/v1/') + 'me', {
method: 'PUT',
credentials: 'same-origin',
headers: Object.assign({
'Content-Type': 'application/json',
'Accept': 'application/json'
}, config.restNonce ? { 'X-WP-Nonce': config.restNonce } : {}),
body: JSON.stringify(payload)
}).then(function (response) {
if (!response.ok) {
throw new Error('account_update_failed');
}
return response.json();
}).then(function () {
if (status) {
status.textContent = strings.accountSaved || '';
}
}).catch(function () {
if (status) {
status.textContent = strings.accountError || '';
}
}).finally(function () {
if (submit) {
submit.disabled = false;
}
});
});
loadFavorites();
}
function initFavorite(root) {
var toggle = root.querySelector('[data-mw-favorite-toggle]');
var status = root.querySelector('[data-mw-favorite-status]');
if (!toggle || !config.isLoggedIn) {
return;
}
var objectType = root.getAttribute('data-object-type') || '';
var objectId = root.getAttribute('data-object-id') || '';
var saved = false;
var busy = false;
var path = (config.restUrl || '/wp-json/meinweimar/v1/') + 'favorites/' + encodeURIComponent(objectType) + '/' + encodeURIComponent(objectId);
function render() {
toggle.textContent = saved ? (strings.favoriteRemove || '') : (strings.favoriteSave || '');
toggle.setAttribute('aria-pressed', saved ? 'true' : 'false');
toggle.disabled = busy;
}
fetch((config.restUrl || '/wp-json/meinweimar/v1/') + 'favorites', {
credentials: 'same-origin',
headers: config.restNonce ? { 'X-WP-Nonce': config.restNonce } : {}
}).then(function (response) {
if (!response.ok) {
throw new Error('favorites_failed');
}
return response.json();
}).then(function (payload) {
var items = payload && Array.isArray(payload.items) ? payload.items : [];
saved = items.some(function (entry) {
return String(entry.object_type || '') === objectType && String(entry.object_id || '') === objectId;
});
render();
}).catch(function () {
render();
});
toggle.addEventListener('click', function () {
if (busy) {
return;
}
busy = true;
if (status) {
status.textContent = strings.favoriteSaving || '';
}
render();
fetch(path, {
method: saved ? 'DELETE' : 'POST',
credentials: 'same-origin',
headers: Object.assign({ 'Accept': 'application/json' }, config.restNonce ? { 'X-WP-Nonce': config.restNonce } : {})
}).then(function (response) {
return response.json().catch(function () { return {}; }).then(function (payload) {
if (!response.ok) {
throw new Error('favorite_failed');
}
return payload;
});
}).then(function (payload) {
saved = payload.saved === true;
if (status) {
status.textContent = saved ? (strings.favoriteSaved || '') : (strings.favoriteRemoved || '');
}
}).catch(function () {
if (status) {
status.textContent = strings.favoriteError || '';
}
}).finally(function () {
busy = false;
render();
});
});
render();
}
function initDiscovery(root) {
var list = root.querySelector('[data-results]');
var markers = root.querySelector('[data-markers]');
var status = root.querySelector('.mw-discovery__status');
var search = root.querySelector('.mw-discovery__search');
var addressSearch = root.querySelector('[data-address-search]');
var addressSubmit = root.querySelector('[data-address-submit]');
var addressResults = root.querySelector('[data-address-results]');
var locate = root.querySelector('[data-geolocate]');
var sort = root.querySelector('[data-sort]');
var category = root.querySelector('[data-category]');
var categoryChoices = root.querySelectorAll('[data-category-choice]');
var region = root.querySelector('[data-region]');
var schemaFilters = root.querySelectorAll('[data-schema-filter]');
var schemaFilterWrappers = root.querySelectorAll('[data-schema-filter-wrapper]');
var schemaChoiceButtons = root.querySelectorAll('[data-schema-choice-value]');
var radius = root.querySelector('[data-radius]');
var radiusLabel = root.querySelector('[data-radius-label]');
var type = root.getAttribute('data-type') || 'places';
var perPage = root.getAttribute('data-per-page') || '12';
var defaultSearch = root.getAttribute('data-default-search') || '';
var defaultCategory = root.getAttribute('data-default-category') || '';
var defaultRegion = root.getAttribute('data-default-region') || '';
var defaultSort = root.getAttribute('data-default-sort') || 'auto';
var configuredRadius = root.getAttribute('data-default-radius') || '';
var mapEnabled = root.getAttribute('data-map-enabled') !== 'false';
var map = root.querySelector('[data-map]');
var mapPreview = root.querySelector('[data-map-preview]');
var geoPosition = null;
var geoSource = null;
var searchTimer = null;
var addressTimer = null;
var addressRequest = 0;
var latestItems = [];
var defaultRadius = configuredRadius || (config.geo && config.geo.default_radius_km ? config.geo.default_radius_km : 10);
if (search && defaultSearch) {
search.value = defaultSearch;
}
if (sort && sort.querySelector('option[value="' + defaultSort + '"]')) {
sort.value = defaultSort;
}
if (radius && configuredRadius) {
radius.value = configuredRadius;
}
updateRadiusLabel();
function endpointFor(currentType) {
return (config.restUrl || '/wp-json/meinweimar/v1/') + currentType;
}
function paramsFor(values) {
var params = new URLSearchParams(values || {});
if (geoPosition) {
params.set('lat', geoPosition.lat);
params.set('lng', geoPosition.lng);
params.set('radius_km', radiusValue());
}
return params;
}
function radiusValue() {
var value = radius ? Number(radius.value) : Number(defaultRadius);
if (!isFinite(value)) {
value = Number(defaultRadius);
}
return Math.max(0.01, Math.min(50, Math.round(value * 100) / 100));
}
function updateRadiusLabel() {
if (!radiusLabel) {
return;
}
var value = radiusValue();
radiusLabel.textContent = value < 1
? String(Math.round(value * 1000)) + ' ' + (strings.radiusMetersUnit || '')
: String(value).replace('.', ',') + ' ' + (strings.radiusKilometersUnit || '');
}
function discoveryParams() {
var values = {
per_page: perPage,
search: search ? search.value || '' : '',
sort: sort ? sort.value : defaultSort,
};
var categoryValue = category ? category.value : defaultCategory;
var regionValue = region ? region.value : defaultRegion;
if (categoryValue) {
values.category = categoryValue;
if ('all' === type && category) {
var selectedCategory = category.options[category.selectedIndex];
var categoryRoute = selectedCategory ? selectedCategory.getAttribute('data-category-route') || '' : '';
if (categoryRoute) {
values.category_route = categoryRoute;
}
}
}
if (regionValue) {
values.region = regionValue;
}
Array.prototype.forEach.call(schemaFilters, function (filter) {
if (filter.disabled) {
return;
}
var key = filter.getAttribute('data-api-key') || '';
var bound = filter.getAttribute('data-schema-filter-bound') || '';
var value = filter.value || '';
if (bound) {
key += '_' + bound;
}
if (key && value) {
values[key] = value;
}
});
return values;
}
function syncSchemaFilters() {
var categoryValue = category ? String(category.value || '') : '';
var activeValues = {};
function conditionValues(value) {
var values = Array.isArray(value) ? value : [value];
return values.map(function (entry) {
return entry === null || typeof entry === 'undefined' ? '' : String(entry).trim();
}).filter(function (entry) { return entry !== ''; });
}
function conditionMatchesValue(value, condition) {
var values = conditionValues(value);
var operator = String(condition.operator || '');
if ('not_empty' === operator) {
return values.length > 0;
}
if ('equals' === operator) {
return values.indexOf(String(condition.value || '').trim()) !== -1;
}
if ('in' === operator) {
var allowed = Array.isArray(condition.values) ? condition.values.map(function (entry) { return String(entry).trim(); }) : [];
return values.some(function (entry) { return allowed.indexOf(entry) !== -1; });
}
return true;
}
Array.prototype.forEach.call(schemaFilters, function (input) {
var key = input.getAttribute('data-api-key') || '';
var bound = input.getAttribute('data-schema-filter-bound') || '';
if (bound) {
key += '_' + bound;
}
if (key && input.value) {
activeValues[key] = String(input.value);
}
});
Array.prototype.forEach.call(schemaFilterWrappers, function (wrapper) {
var inputs = wrapper.querySelectorAll('[data-schema-filter]');
var categories = [];
var conditions = [];
try {
categories = JSON.parse(wrapper.getAttribute('data-schema-filter-categories') || '[]');
} catch (error) {
categories = [];
}
try {
conditions = JSON.parse(wrapper.getAttribute('data-schema-filter-conditions') || '[]');
} catch (error) {
conditions = [];
}
var visible = !categoryValue || !categories.length || categories.indexOf(categoryValue) !== -1;
if (visible && conditions.length) {
conditions.some(function (condition) {
var field = String(condition.field || '').split('.').pop();
var value = 'category' === field ? categoryValue : (activeValues[field] || '');
if (!conditionMatchesValue(value, condition)) {
visible = false;
return true;
}
return false;
});
}
wrapper.hidden = !visible;
Array.prototype.forEach.call(inputs, function (input) {
input.disabled = !visible;
if (!visible) {
input.value = '';
}
});
});
Array.prototype.forEach.call(categoryChoices, function (button) {
var selected = category && String(category.value || '') === String(button.getAttribute('data-category-choice') || '');
button.classList.toggle('is-active', selected);
button.setAttribute('aria-pressed', selected ? 'true' : 'false');
});
Array.prototype.forEach.call(schemaChoiceButtons, function (button) {
var wrapper = button.closest('[data-schema-filter-wrapper]');
var input = wrapper ? wrapper.querySelector('[data-schema-filter]') : null;
var selected = input && String(input.value || '') === String(button.getAttribute('data-schema-choice-value') || '');
button.classList.toggle('is-active', selected);
button.setAttribute('aria-pressed', selected ? 'true' : 'false');
button.disabled = !input || input.disabled;
});
}
function focusItem(itemId) {
var target = null;
list.querySelectorAll('[data-mw-item-id]').forEach(function (card) {
if (card.getAttribute('data-mw-item-id') === String(itemId)) {
target = card;
}
});
if (!target) {
return;
}
if (mapPreview) {
mapPreview.hidden = true;
mapPreview.innerHTML = '';
}
list.hidden = false;
map.hidden = true;
root.querySelectorAll('.mw-discovery__mode').forEach(function (button) {
var active = button.getAttribute('data-mode') === 'list';
button.classList.toggle('is-active', active);
button.setAttribute('aria-pressed', active ? 'true' : 'false');
});
target.scrollIntoView({ behavior: 'smooth', block: 'center' });
target.focus({ preventScroll: true });
}
function showMapPreview(itemId) {
if (!mapPreview) {
focusItem(itemId);
return;
}
var item = latestItems.filter(function (candidate) {
return String(candidate.id) === String(itemId);
})[0];
if (!item) {
return;
}
var address = item.address || {};
var location = [address.line1, address.postal_code, address.locality].filter(Boolean).join(', ');
mapPreview.innerHTML = '<article class="mw-map-preview-card">' +
'<button class="mw-map-preview-card__close" type="button" aria-label="' + escapeHtml(strings.close || '') + '" data-map-preview-close>×</button>' +
'<p class="mw-card__type">' + escapeHtml(resourceLabels[item.resource || item.type || ''] || item.resource || item.type || '') + '</p>' +
'<h3 class="mw-map-preview-card__title">' + escapeHtml(item.title) + '</h3>' +
(location ? '<p class="mw-map-preview-card__location">' + escapeHtml(location) + '</p>' : '') +
(item.excerpt ? '<p class="mw-map-preview-card__excerpt">' + escapeHtml(item.excerpt) + '</p>' : '') +
'<a class="mw-card__details" href="' + escapeHtml(item.url) + '">' + escapeHtml(strings.openDetails || '') + '</a>' +
'</article>';
mapPreview.hidden = false;
var close = mapPreview.querySelector('[data-map-preview-close]');
if (close) {
close.addEventListener('click', function () {
mapPreview.hidden = true;
mapPreview.innerHTML = '';
});
}
}
function publishMapState(items) {
if (!mapEnabled) {
return;
}
var payload = {
element: map,
items: items.filter(function (item) { return item.geo && item.geo.available; }),
center: geoPosition,
searchPosition: geoSource === 'address' ? geoPosition : null,
userLocation: geoSource === 'gps' ? geoPosition : null,
locationSource: geoSource,
radiusKm: geoPosition ? radiusValue() : null,
onSelect: focusItem
};
root.dispatchEvent(new CustomEvent('meinweimar:map-update', { detail: payload }));
if (window.MeinWeimarMapAdapter && typeof window.MeinWeimarMapAdapter.update === 'function') {
window.MeinWeimarMapAdapter.update(payload);
return;
}
if (markers) {
var tilesConfigured = config.geo && config.geo.capabilities && config.geo.capabilities.tiles === true;
var message = tilesConfigured ? strings.mapAdapterPending : strings.mapProviderPending;
markers.innerHTML = '<p class="mw-discovery__map-state">' + escapeHtml(message || '') + '</p>';
}
}
function load() {
var selectedTypes = type === 'all' ? resourceTypes : [type];
status.textContent = strings.loading || '';
list.innerHTML = '';
if (type === 'all') {
var combinedParams = paramsFor(Object.assign(discoveryParams(), { types: selectedTypes.join(',') }));
fetch(endpointFor('discover') + '?' + combinedParams.toString()).then(function (response) {
if (!response.ok) {
throw new Error('request_failed');
}
return response.json();
}).then(function (response) {
var items = response.items || [];
latestItems = items;
list.innerHTML = items.length ? items.map(renderCard).join('') : '<p class="mw-discovery__empty">' + escapeHtml(strings.noResults || '') + '</p>';
publishMapState(items);
status.textContent = '';
}).catch(function () {
status.textContent = strings.error || '';
});
return;
}
Promise.all(selectedTypes.map(function (currentType) {
var params = paramsFor(discoveryParams());
return fetch(endpointFor(currentType) + '?' + params.toString()).then(function (response) {
if (!response.ok) {
throw new Error('request_failed');
}
return response.json();
});
})).then(function (responses) {
var items = responses.reduce(function (all, response) {
return all.concat(response.items || []);
}, []);
latestItems = items;
list.innerHTML = items.length ? items.map(renderCard).join('') : '<p class="mw-discovery__empty">' + escapeHtml(strings.noResults || '') + '</p>';
publishMapState(items);
status.textContent = '';
}).catch(function () {
status.textContent = strings.error || '';
});
}
function clearAddressResults() {
if (!addressResults) {
return;
}
addressResults.innerHTML = '';
addressResults.hidden = true;
}
function resetLocation() {
var hadLocation = geoPosition !== null || geoSource !== null;
geoPosition = null;
geoSource = null;
if (locate) {
locate.textContent = strings.useLocation || '';
locate.setAttribute('aria-pressed', 'false');
}
if (hadLocation) {
publishMapState(latestItems);
}
}
function renderAddressResults(results) {
if (!addressResults) {
return;
}
var items = Array.isArray(results) ? results.filter(function (result) {
return result && typeof result.label === 'string' && result.label.trim() && isFinite(Number(result.lat)) && isFinite(Number(result.lng));
}) : [];
if (!items.length) {
addressResults.innerHTML = '<p class="mw-discovery__empty">' + escapeHtml(strings.addressSearchNoResults || '') + '</p>';
addressResults.hidden = false;
return;
}
addressResults.innerHTML = items.map(function (result) {
return '<button class="mw-address-result" type="button" role="option" data-address-label="' + escapeHtml(result.label) + '" data-address-lat="' + escapeHtml(result.lat) + '" data-address-lng="' + escapeHtml(result.lng) + '">' +
escapeHtml(result.label) + '<span class="screen-reader-text"> — ' + escapeHtml(strings.addressSearchChoose || '') + '</span></button>';
}).join('');
addressResults.hidden = false;
}
function searchAddress() {
if (!addressSearch || !addressResults) {
return;
}
if (geoSource === 'gps') {
resetLocation();
load();
}
var query = addressSearch.value.trim();
if (query.length < 2) {
clearAddressResults();
return;
}
if (!config.geo || !config.geo.capabilities || config.geo.capabilities.geocoding !== true) {
addressResults.innerHTML = '<p class="mw-discovery__empty">' + escapeHtml(strings.addressSearchUnavailable || '') + '</p>';
addressResults.hidden = false;
return;
}
var requestId = ++addressRequest;
status.textContent = strings.loading || '';
fetch((config.restUrl || '/wp-json/meinweimar/v1/') + 'geo/geocode?' + new URLSearchParams({ q: query, limit: '5' }).toString(), {
credentials: 'same-origin'
}).then(function (response) {
return response.json().catch(function () { return {}; }).then(function (payload) {
if (!response.ok) {
throw new Error('geocoding_failed');
}
return payload;
});
}).then(function (payload) {
if (requestId !== addressRequest) {
return;
}
renderAddressResults(payload && payload.results);
status.textContent = '';
}).catch(function () {
if (requestId !== addressRequest) {
return;
}
addressResults.innerHTML = '<p class="mw-discovery__empty">' + escapeHtml(strings.addressSearchUnavailable || '') + '</p>';
addressResults.hidden = false;
status.textContent = '';
});
}
function selectAddress(button) {
var lat = Number(button.getAttribute('data-address-lat'));
var lng = Number(button.getAttribute('data-address-lng'));
if (!isFinite(lat) || !isFinite(lng)) {
return;
}
geoPosition = { lat: lat, lng: lng };
geoSource = 'address';
if (locate) {
locate.textContent = strings.useLocation || '';
locate.setAttribute('aria-pressed', 'false');
}
addressSearch.value = button.getAttribute('data-address-label') || addressSearch.value;
clearAddressResults();
load();
}
if (locate) {
locate.addEventListener('click', function () {
if (!navigator.geolocation) {
resetLocation();
load();
status.textContent = strings.locationDenied || '';
return;
}
status.textContent = strings.loading || '';
navigator.geolocation.getCurrentPosition(function (position) {
geoPosition = {
lat: position.coords.latitude,
lng: position.coords.longitude
};
geoSource = 'gps';
locate.textContent = strings.locationReady || '';
locate.setAttribute('aria-pressed', 'true');
load();
}, function () {
resetLocation();
load();
status.textContent = strings.locationDenied || '';
}, {
enableHighAccuracy: false,
maximumAge: 300000,
timeout: 10000
});
});
}
root.querySelector('.mw-discovery__submit').addEventListener('click', load);
search.addEventListener('input', function () {
window.clearTimeout(searchTimer);
searchTimer = window.setTimeout(load, 400);
});
search.addEventListener('keydown', function (event) {
if (event.key === 'Enter') {
load();
}
});
if (addressSearch) {
addressSearch.addEventListener('input', function () {
resetLocation();
window.clearTimeout(addressTimer);
if (!addressSearch.value.trim()) {
clearAddressResults();
return;
}
addressTimer = window.setTimeout(searchAddress, 350);
});
addressSearch.addEventListener('keydown', function (event) {
if (event.key === 'Enter') {
event.preventDefault();
searchAddress();
}
});
}
if (addressSubmit) {
addressSubmit.addEventListener('click', searchAddress);
}
if (addressResults) {
addressResults.addEventListener('click', function (event) {
var button = event.target.closest('[data-address-lat][data-address-lng]');
if (button) {
selectAddress(button);
}
});
}
if (sort) {
sort.addEventListener('change', load);
}
if (category) {
category.addEventListener('change', function () {
syncSchemaFilters();
load();
});
}
Array.prototype.forEach.call(categoryChoices, function (button) {
button.addEventListener('click', function () {
if (!category) {
return;
}
category.value = button.getAttribute('data-category-choice') || '';
syncSchemaFilters();
load();
});
});
if (region) {
region.addEventListener('change', load);
}
if (radius) {
radius.addEventListener('input', updateRadiusLabel);
radius.addEventListener('change', function () {
radius.value = String(radiusValue());
updateRadiusLabel();
if (geoPosition) {
load();
}
});
}
syncSchemaFilters();
Array.prototype.forEach.call(schemaFilters, function (filter) {
filter.addEventListener('change', function () {
syncSchemaFilters();
load();
});
});
Array.prototype.forEach.call(schemaChoiceButtons, function (button) {
button.addEventListener('click', function () {
var wrapper = button.closest('[data-schema-filter-wrapper]');
var input = wrapper ? wrapper.querySelector('[data-schema-filter]') : null;
if (!input || input.disabled) {
return;
}
input.value = button.getAttribute('data-schema-choice-value') || '';
syncSchemaFilters();
load();
});
});
root.querySelectorAll('.mw-discovery__mode').forEach(function (button) {
button.setAttribute('aria-pressed', button.getAttribute('data-mode') === 'list' ? 'true' : 'false');
button.addEventListener('click', function () {
root.querySelectorAll('.mw-discovery__mode').forEach(function (item) { item.classList.remove('is-active'); });
button.classList.add('is-active');
var isMap = button.getAttribute('data-mode') === 'map';
map.hidden = !isMap;
list.hidden = isMap;
if (isMap && window.MeinWeimarMapAdapter && typeof window.MeinWeimarMapAdapter.resize === 'function') {
window.MeinWeimarMapAdapter.resize(map);
}
if (isMap) {
// Re-publish after the map becomes visible. This also covers a
// slow Google Maps script that was not ready during the first REST
// response.
publishMapState(latestItems);
}
button.setAttribute('aria-pressed', 'true');
root.querySelectorAll('.mw-discovery__mode').forEach(function (other) {
if (other !== button) {
other.setAttribute('aria-pressed', 'false');
}
});
});
});
load();
}
document.addEventListener('DOMContentLoaded', function () {
document.querySelectorAll('[data-mw-discovery]').forEach(initDiscovery);
document.querySelectorAll('[data-mw-account]').forEach(initAccount);
document.querySelectorAll('[data-mw-favorite]').forEach(initFavorite);
document.querySelectorAll('[data-image-suggestion]').forEach(initImageSuggestion);
document.querySelectorAll('.mw-nav__toggle').forEach(function (button) {
button.addEventListener('click', function () {
var expanded = button.getAttribute('aria-expanded') === 'true';
button.setAttribute('aria-expanded', expanded ? 'false' : 'true');
var list = document.getElementById(button.getAttribute('aria-controls'));
if (list) {
list.hidden = expanded;
}
});
});
});
}());
