mirror of
https://github.com/versity/versitygw.git
synced 2026-04-22 05:30:29 +00:00
feat: history back/forward actions on explorer and modals
Most actions within each page is stateless (show modals) or change the URL hash. As it is, those are not tracked and using the back button has no effect. This commits implements two things: - Tracking of the URL hash in the explorer to move from bucket/folders on history change. - Add a history state when a modal is open, so the back button closes the modal.
This commit is contained in:
@@ -221,7 +221,7 @@ under the License.
|
||||
</div>
|
||||
|
||||
<!-- Change Owner Modal -->
|
||||
<div id="owner-modal" class="hidden fixed inset-0 z-50">
|
||||
<div id="owner-modal" class="modal hidden fixed inset-0 z-50">
|
||||
<div class="modal-backdrop absolute inset-0" onclick="closeModal('owner-modal')"></div>
|
||||
<div class="absolute inset-0 flex items-center justify-center p-4">
|
||||
<div class="bg-white rounded-xl shadow-2xl w-full max-w-md relative">
|
||||
@@ -281,7 +281,7 @@ under the License.
|
||||
</div>
|
||||
|
||||
<!-- Create Bucket Modal -->
|
||||
<div id="create-bucket-modal" class="hidden fixed inset-0 z-50">
|
||||
<div id="create-bucket-modal" class="modal hidden fixed inset-0 z-50">
|
||||
<div class="modal-backdrop absolute inset-0" onclick="closeModal('create-bucket-modal')"></div>
|
||||
<div class="absolute inset-0 flex items-center justify-center p-4">
|
||||
<div class="bg-white rounded-xl shadow-2xl w-full max-w-md relative">
|
||||
@@ -353,7 +353,7 @@ under the License.
|
||||
let allBuckets = [];
|
||||
let allUsers = [];
|
||||
let selectedBucket = null;
|
||||
|
||||
|
||||
// ============================================
|
||||
// Custom Dropdown Functions
|
||||
// ============================================
|
||||
|
||||
@@ -344,7 +344,7 @@ under the License.
|
||||
</div>
|
||||
|
||||
<!-- Object Info Modal -->
|
||||
<div id="info-modal" class="hidden fixed inset-0 z-50">
|
||||
<div id="info-modal" class="modal hidden fixed inset-0 z-50">
|
||||
<div class="modal-backdrop absolute inset-0" onclick="closeModal('info-modal')"></div>
|
||||
<div class="absolute inset-0 flex items-center justify-center p-4">
|
||||
<div class="bg-white rounded-xl shadow-2xl w-full max-w-3xl relative max-h-[90vh] flex flex-col">
|
||||
@@ -444,7 +444,7 @@ under the License.
|
||||
<input type="file" id="file-input" class="hidden" multiple onchange="handleFileSelect(event)">
|
||||
|
||||
<!-- Object Versions Modal -->
|
||||
<div id="versions-modal" class="hidden fixed inset-0 z-50">
|
||||
<div id="versions-modal" class="modal hidden fixed inset-0 z-50">
|
||||
<div class="modal-backdrop absolute inset-0" onclick="closeModal('versions-modal')"></div>
|
||||
<div class="absolute inset-0 flex items-center justify-center p-4">
|
||||
<div class="bg-white rounded-xl shadow-2xl w-full max-w-4xl relative max-h-[90vh] flex flex-col">
|
||||
@@ -478,7 +478,7 @@ under the License.
|
||||
</div>
|
||||
|
||||
<!-- Delete Confirmation Modal -->
|
||||
<div id="delete-modal" class="hidden fixed inset-0 z-50">
|
||||
<div id="delete-modal" class="modal hidden fixed inset-0 z-50">
|
||||
<div class="modal-backdrop absolute inset-0" onclick="closeModal('delete-modal')"></div>
|
||||
<div class="absolute inset-0 flex items-center justify-center p-4">
|
||||
<div class="bg-white rounded-xl shadow-2xl w-full max-w-md relative">
|
||||
@@ -504,7 +504,7 @@ under the License.
|
||||
</div>
|
||||
|
||||
<!-- Create Folder Modal -->
|
||||
<div id="create-folder-modal" class="hidden fixed inset-0 z-50">
|
||||
<div id="create-folder-modal" class="modal hidden fixed inset-0 z-50">
|
||||
<div class="modal-backdrop absolute inset-0" onclick="closeModal('create-folder-modal')"></div>
|
||||
<div class="absolute inset-0 flex items-center justify-center p-4">
|
||||
<div class="bg-white rounded-xl shadow-2xl w-full max-w-md relative">
|
||||
@@ -534,7 +534,7 @@ under the License.
|
||||
</div>
|
||||
|
||||
<!-- Create Bucket Modal -->
|
||||
<div id="create-bucket-modal" class="hidden fixed inset-0 z-50">
|
||||
<div id="create-bucket-modal" class="modal hidden fixed inset-0 z-50">
|
||||
<div class="modal-backdrop absolute inset-0" onclick="closeModal('create-bucket-modal')"></div>
|
||||
<div class="absolute inset-0 flex items-center justify-center p-4">
|
||||
<div class="bg-white rounded-xl shadow-2xl w-full max-w-md relative">
|
||||
@@ -564,7 +564,7 @@ under the License.
|
||||
</div>
|
||||
|
||||
<!-- Delete Bucket Modal -->
|
||||
<div id="delete-bucket-modal" class="hidden fixed inset-0 z-50">
|
||||
<div id="delete-bucket-modal" class="modal hidden fixed inset-0 z-50">
|
||||
<div class="modal-backdrop absolute inset-0" onclick="closeModal('delete-bucket-modal')"></div>
|
||||
<div class="absolute inset-0 flex items-center justify-center p-4">
|
||||
<div class="bg-white rounded-xl shadow-2xl w-full max-w-md relative">
|
||||
@@ -598,7 +598,7 @@ under the License.
|
||||
</div>
|
||||
|
||||
<!-- Bucket Info Modal -->
|
||||
<div id="bucket-info-modal" class="hidden fixed inset-0 z-50">
|
||||
<div id="bucket-info-modal" class="modal hidden fixed inset-0 z-50">
|
||||
<div class="modal-backdrop absolute inset-0" onclick="closeModal('bucket-info-modal')"></div>
|
||||
<div class="absolute inset-0 flex items-center justify-center p-4">
|
||||
<div class="bg-white rounded-xl shadow-2xl w-full max-w-2xl relative max-h-[90vh] overflow-y-auto">
|
||||
@@ -736,7 +736,7 @@ under the License.
|
||||
</div>
|
||||
|
||||
<!-- Versioning Modal -->
|
||||
<div id="versioning-modal" class="hidden fixed inset-0 z-50">
|
||||
<div id="versioning-modal" class="modal hidden fixed inset-0 z-50">
|
||||
<div class="modal-backdrop absolute inset-0" onclick="closeModal('versioning-modal')"></div>
|
||||
<div class="absolute inset-0 flex items-center justify-center p-4">
|
||||
<div class="bg-white rounded-xl shadow-2xl w-full max-w-md relative">
|
||||
@@ -778,7 +778,7 @@ under the License.
|
||||
</div>
|
||||
|
||||
<!-- Object Lock Modal -->
|
||||
<div id="object-lock-modal" class="hidden fixed inset-0 z-50">
|
||||
<div id="object-lock-modal" class="modal hidden fixed inset-0 z-50">
|
||||
<div class="modal-backdrop absolute inset-0" onclick="closeModal('object-lock-modal')"></div>
|
||||
<div class="absolute inset-0 flex items-center justify-center p-4">
|
||||
<div class="bg-white rounded-xl shadow-2xl w-full max-w-md relative">
|
||||
@@ -842,7 +842,7 @@ under the License.
|
||||
</div>
|
||||
|
||||
<!-- Bucket Policy Modal -->
|
||||
<div id="bucket-policy-modal" class="hidden fixed inset-0 z-50">
|
||||
<div id="bucket-policy-modal" class="modal hidden fixed inset-0 z-50">
|
||||
<div class="modal-backdrop absolute inset-0" onclick="closeModal('bucket-policy-modal')"></div>
|
||||
<div class="absolute inset-0 flex items-center justify-center p-4">
|
||||
<div class="bg-white rounded-xl shadow-2xl w-full max-w-5xl relative max-h-[90vh] flex flex-col">
|
||||
@@ -1014,7 +1014,7 @@ under the License.
|
||||
</div>
|
||||
|
||||
<!-- Multipart Uploads Modal -->
|
||||
<div id="multipart-uploads-modal" class="hidden fixed inset-0 z-50">
|
||||
<div id="multipart-uploads-modal" class="modal hidden fixed inset-0 z-50">
|
||||
<div class="modal-backdrop absolute inset-0" onclick="closeModal('multipart-uploads-modal')"></div>
|
||||
<div class="absolute inset-0 flex items-center justify-center p-4">
|
||||
<div class="bg-white rounded-xl shadow-2xl w-full max-w-4xl relative max-h-[90vh] flex flex-col">
|
||||
@@ -1141,6 +1141,9 @@ under the License.
|
||||
if (!requireAuth()) {
|
||||
// Will redirect to login
|
||||
} else {
|
||||
// Clear history state on startup (can happen when reloading with popup open)
|
||||
if (history.state?.modal) history.back();
|
||||
|
||||
initSidebarWithRole();
|
||||
updateUserInfo();
|
||||
init();
|
||||
@@ -1164,11 +1167,19 @@ under the License.
|
||||
currentPrefix += '/';
|
||||
}
|
||||
}
|
||||
} else {
|
||||
currentBucket = "";
|
||||
currentPrefix = "";
|
||||
}
|
||||
|
||||
await loadBuckets();
|
||||
}
|
||||
|
||||
|
||||
// Rerun init() on hash change to allow for back/forward when browsing a bucket.
|
||||
window.addEventListener('hashchange', async () => {
|
||||
await init();
|
||||
});
|
||||
|
||||
// ============================================
|
||||
// Logout
|
||||
// ============================================
|
||||
|
||||
@@ -129,13 +129,26 @@ function openModal(modalId) {
|
||||
// Focus first input
|
||||
const firstInput = modal.querySelector('input:not([readonly]), select');
|
||||
if (firstInput) setTimeout(() => firstInput.focus(), 100);
|
||||
|
||||
// Push to history state so the back button can close the modal
|
||||
history.pushState({ modal: true }, '');
|
||||
}
|
||||
}
|
||||
|
||||
function closeModal(modalId) {
|
||||
let navigatingBack = false
|
||||
|
||||
// Close the currently opened modal, manually popping the modal
|
||||
// history state if the modal was closed manually (default). In the
|
||||
// case where the modal was closed due to navigating back, the state
|
||||
// is already popped and we can skip it.
|
||||
function closeModal(modalId, popState = true) {
|
||||
const modal = document.getElementById(modalId);
|
||||
if (modal) {
|
||||
modal.classList.add('hidden');
|
||||
if (popState && history.state?.modal) {
|
||||
navigatingBack = true;
|
||||
history.back();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,6 +158,24 @@ function closeAllModals() {
|
||||
});
|
||||
}
|
||||
|
||||
function closeModalsOnNavigation() {
|
||||
Array.from(document.getElementsByClassName('modal')).forEach((modal) => {
|
||||
if (!modal.classList.contains('hidden')) {
|
||||
closeModal(modal.getAttribute('id'), false);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Catch the back button to close the open modal, if any is open.
|
||||
window.addEventListener('popstate', (e) => {
|
||||
if (navigatingBack) {
|
||||
navigatingBack = false;
|
||||
return;
|
||||
}
|
||||
|
||||
closeModalsOnNavigation();
|
||||
});
|
||||
|
||||
// Close modals on Escape key
|
||||
document.addEventListener('keydown', (e) => {
|
||||
if (e.key === 'Escape') closeAllModals();
|
||||
|
||||
@@ -209,7 +209,7 @@ under the License.
|
||||
</div>
|
||||
|
||||
<!-- Create/Edit User Modal -->
|
||||
<div id="user-modal" class="hidden fixed inset-0 z-50">
|
||||
<div id="user-modal" class="modal hidden fixed inset-0 z-50">
|
||||
<div class="modal-backdrop absolute inset-0" onclick="closeModal('user-modal')"></div>
|
||||
<div class="absolute inset-0 flex items-center justify-center p-4">
|
||||
<div class="bg-white rounded-xl shadow-2xl w-full max-w-lg relative">
|
||||
@@ -298,7 +298,7 @@ under the License.
|
||||
</div>
|
||||
|
||||
<!-- Delete Confirmation Modal -->
|
||||
<div id="delete-modal" class="hidden fixed inset-0 z-50">
|
||||
<div id="delete-modal" class="modal hidden fixed inset-0 z-50">
|
||||
<div class="modal-backdrop absolute inset-0" onclick="closeModal('delete-modal')"></div>
|
||||
<div class="absolute inset-0 flex items-center justify-center p-4">
|
||||
<div class="bg-white rounded-xl shadow-2xl w-full max-w-md relative">
|
||||
@@ -324,7 +324,7 @@ under the License.
|
||||
<script>
|
||||
let allUsers = [];
|
||||
let userToDelete = null;
|
||||
|
||||
|
||||
// ============================================
|
||||
// Custom Dropdown Functions
|
||||
// ============================================
|
||||
|
||||
Reference in New Issue
Block a user