Fix map loading and tab navigation v0.4.1
This commit is contained in:
1 parent
e290bd1fff
commit
9b7d302064
9 files changed
+148
-47
No files matched your search
+49
-24
@@ -63,6 +63,7 @@ const elements = {
|
||||
addressSearchButton: $('#address-search-button'),
|
||||
addressResults: $('#address-results'),
|
||||
locationMap: $('#location-map'),
|
||||
mapStatus: $('#map-status'),
|
||||
latitude: $('#latitude-input'),
|
||||
longitude: $('#longitude-input'),
|
||||
locationName: $('#location-name-input'),
|
||||
@@ -609,7 +610,13 @@ function activeTabIndex() {
|
||||
return $$('.tab').findIndex((tab) => tab.classList.contains('active'));
|
||||
}
|
||||
|
||||
function activateTab(tabName, focusTab = false) {
|
||||
function focusFirstControl(tabName) {
|
||||
const panel = document.querySelector(`.tab-panel[data-panel="${tabName}"]`);
|
||||
const first = panel?.querySelector('input:not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), [tabindex]:not([tabindex="-1"])');
|
||||
first?.focus();
|
||||
}
|
||||
|
||||
function activateTab(tabName, focusMode = 'none') {
|
||||
const tabs = $$('.tab');
|
||||
const target = tabs.find((tab) => tab.dataset.tab === tabName);
|
||||
if (!target) return;
|
||||
@@ -620,22 +627,28 @@ function activateTab(tabName, focusTab = false) {
|
||||
item.tabIndex = active ? 0 : -1;
|
||||
});
|
||||
$$('.tab-panel').forEach((panel) => panel.classList.toggle('active', panel.dataset.panel === tabName));
|
||||
if (focusTab) target.focus();
|
||||
|
||||
if (tabName === 'location') {
|
||||
initialiseMap();
|
||||
window.setTimeout(() => {
|
||||
state.map?.invalidateSize();
|
||||
syncMapFromFields(false);
|
||||
if (focusMode === 'field') focusFirstControl(tabName);
|
||||
else if (focusMode === 'tab') target.focus();
|
||||
}, 0);
|
||||
} else if (focusMode === 'field') {
|
||||
window.setTimeout(() => focusFirstControl(tabName), 0);
|
||||
} else if (focusMode === 'tab') {
|
||||
target.focus();
|
||||
}
|
||||
}
|
||||
|
||||
function cycleTabs(delta) {
|
||||
function cycleTabs(delta, focusMode = 'field') {
|
||||
const tabs = $$('.tab');
|
||||
if (!tabs.length) return;
|
||||
const current = Math.max(0, activeTabIndex());
|
||||
const next = (current + delta + tabs.length) % tabs.length;
|
||||
activateTab(tabs[next].dataset.tab, true);
|
||||
activateTab(tabs[next].dataset.tab, focusMode);
|
||||
}
|
||||
|
||||
function markLocationDirty() {
|
||||
@@ -643,21 +656,39 @@ function markLocationDirty() {
|
||||
captureCurrentValues();
|
||||
}
|
||||
|
||||
function setMapStatus(message, isError = false) {
|
||||
if (!elements.mapStatus) return;
|
||||
elements.mapStatus.textContent = message;
|
||||
elements.mapStatus.classList.toggle('error', isError);
|
||||
}
|
||||
|
||||
function initialiseMap() {
|
||||
if (state.map || typeof window.L === 'undefined' || !elements.locationMap) return;
|
||||
if (state.map || !elements.locationMap) return;
|
||||
if (typeof window.L === 'undefined') {
|
||||
setMapStatus('Map library failed to load. Rebuild the container and hard-refresh the page.', true);
|
||||
return;
|
||||
}
|
||||
const config = state.mapConfig || {};
|
||||
state.map = L.map(elements.locationMap, { zoomControl: true }).setView(
|
||||
[Number(config.defaultMapLat ?? 64.5), Number(config.defaultMapLon ?? 11.0)],
|
||||
Number(config.defaultMapZoom ?? 5),
|
||||
);
|
||||
L.tileLayer(config.mapTileUrl || 'https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
||||
maxZoom: 19,
|
||||
attribution: config.mapAttribution || '© OpenStreetMap contributors',
|
||||
}).addTo(state.map);
|
||||
state.map.on('click', (event) => {
|
||||
setLocation(event.latlng.lat, event.latlng.lng, '', true, false);
|
||||
});
|
||||
syncMapFromFields(false);
|
||||
try {
|
||||
state.map = L.map(elements.locationMap, { zoomControl: true }).setView(
|
||||
[Number(config.defaultMapLat ?? 64.5), Number(config.defaultMapLon ?? 11.0)],
|
||||
Number(config.defaultMapZoom ?? 5),
|
||||
);
|
||||
const layer = L.tileLayer(config.mapTileUrl || '/api/map/tiles/{z}/{x}/{y}.png', {
|
||||
maxZoom: 19,
|
||||
attribution: config.mapAttribution || '© OpenStreetMap contributors',
|
||||
}).addTo(state.map);
|
||||
layer.on('loading', () => setMapStatus('Loading map…'));
|
||||
layer.on('load', () => setMapStatus('Click the map to place a pin.'));
|
||||
layer.on('tileerror', () => setMapStatus('Map tiles could not be loaded. Address search and manual coordinates still work.', true));
|
||||
state.map.on('click', (event) => {
|
||||
setLocation(event.latlng.lat, event.latlng.lng, '', true, false);
|
||||
});
|
||||
syncMapFromFields(false);
|
||||
} catch (error) {
|
||||
state.map = null;
|
||||
setMapStatus(error.message || 'The map could not be initialized.', true);
|
||||
}
|
||||
}
|
||||
|
||||
function setMarker(latitude, longitude, center = false) {
|
||||
@@ -786,12 +817,6 @@ for (const radio of $$('input[name="precision"]')) radio.addEventListener('chang
|
||||
|
||||
for (const tab of $$('.tab')) {
|
||||
tab.addEventListener('click', () => activateTab(tab.dataset.tab));
|
||||
tab.addEventListener('keydown', (event) => {
|
||||
if (event.key === 'ArrowLeft') { event.preventDefault(); cycleTabs(-1); }
|
||||
if (event.key === 'ArrowRight') { event.preventDefault(); cycleTabs(1); }
|
||||
if (event.key === 'Home') { event.preventDefault(); activateTab($$('.tab')[0].dataset.tab, true); }
|
||||
if (event.key === 'End') { const tabs = $$('.tab'); event.preventDefault(); activateTab(tabs[tabs.length - 1].dataset.tab, true); }
|
||||
});
|
||||
}
|
||||
activateTab('date');
|
||||
|
||||
@@ -804,7 +829,7 @@ window.addEventListener('keydown', (event) => {
|
||||
const typing = ['INPUT', 'TEXTAREA', 'SELECT'].includes(tag);
|
||||
|
||||
if (event.key === 'Tab' && event.shiftKey && !event.ctrlKey && !event.altKey && !event.metaKey && document.activeElement?.closest('.right-panel')) {
|
||||
event.preventDefault(); cycleTabs(-1); return;
|
||||
event.preventDefault(); event.stopPropagation(); cycleTabs(-1, 'field'); return;
|
||||
}
|
||||
if ((event.ctrlKey || event.metaKey) && event.key.toLowerCase() === 's') {
|
||||
event.preventDefault(); savePhoto(false); return;
|
||||
|
||||
Reference in new issue
Block a user