documentation for all JS files
This commit is contained in:
@@ -1,3 +1,18 @@
|
||||
/**
|
||||
* @fileoverview Provides avatar image preview functionality.
|
||||
* This file handles:
|
||||
* - File selection event handling
|
||||
* - Image preview generation
|
||||
* - Real-time avatar preview updates
|
||||
*/
|
||||
|
||||
/**
|
||||
* Generates a preview of the selected avatar image.
|
||||
* Reads the selected file and updates the preview image element.
|
||||
* @function
|
||||
* @param {Event} event - The file input change event
|
||||
* @param {FileList} event.target.files - The list of selected files
|
||||
*/
|
||||
function previewAvatar(event) {
|
||||
const [file] = event.target.files;
|
||||
if (file) {
|
||||
|
||||
@@ -1,9 +1,33 @@
|
||||
/**
|
||||
* @fileoverview Manages global chat state and polling functionality.
|
||||
* This file implements a singleton ChatManager that handles:
|
||||
* - Message polling and state management
|
||||
* - New message processing and event triggering
|
||||
* - Connection state tracking
|
||||
* - Resource cleanup
|
||||
*/
|
||||
|
||||
// Global state and polling management
|
||||
if (typeof window.ChatManager === 'undefined') {
|
||||
window.ChatManager = (function() {
|
||||
let instance = null;
|
||||
let pollInterval = null;
|
||||
|
||||
/**
|
||||
* @typedef {Object} ConnectionState
|
||||
* @property {boolean} hasJoined - Whether the user has joined the conversation
|
||||
* @property {boolean} isConnected - Current connection status
|
||||
* @property {number|null} lastMessageId - ID of the last received message
|
||||
* @property {number} pollAttempts - Number of failed polling attempts
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} ChatState
|
||||
* @property {Set<number>} addedMessageIds - Set of message IDs that have been processed
|
||||
* @property {Set<Object>} messageQueue - Queue of messages waiting to be processed
|
||||
* @property {ConnectionState} connectionState - Current connection state
|
||||
*/
|
||||
|
||||
const state = {
|
||||
addedMessageIds: new Set(),
|
||||
messageQueue: new Set(),
|
||||
@@ -15,6 +39,13 @@ if (typeof window.ChatManager === 'undefined') {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Initializes a new ChatManager instance for a conversation.
|
||||
* Sets up message tracking and starts polling for new messages.
|
||||
* @function
|
||||
* @param {string} conversationId - The ID of the conversation to manage
|
||||
* @returns {Object} The ChatManager instance
|
||||
*/
|
||||
function init(conversationId) {
|
||||
if (instance) {
|
||||
console.log('[ChatManager] Instance already exists, returning existing instance');
|
||||
@@ -47,6 +78,12 @@ if (typeof window.ChatManager === 'undefined') {
|
||||
return instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts polling for new messages in the conversation.
|
||||
* Polls every 3 seconds and performs an initial fetch.
|
||||
* @function
|
||||
* @param {string} conversationId - The ID of the conversation to poll
|
||||
*/
|
||||
function startPolling(conversationId) {
|
||||
console.log('[ChatManager] Starting polling for conversation:', conversationId);
|
||||
|
||||
@@ -67,6 +104,12 @@ if (typeof window.ChatManager === 'undefined') {
|
||||
fetchNewMessages(conversationId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches new messages from the server.
|
||||
* Uses the last message ID to only fetch new messages.
|
||||
* @function
|
||||
* @param {string} conversationId - The ID of the conversation to fetch messages from
|
||||
*/
|
||||
function fetchNewMessages(conversationId) {
|
||||
const url = `/conversations/${conversationId}/messages`;
|
||||
const params = new URLSearchParams();
|
||||
@@ -107,6 +150,12 @@ if (typeof window.ChatManager === 'undefined') {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes new messages and triggers events for each new message.
|
||||
* Updates the last message ID and tracks processed messages.
|
||||
* @function
|
||||
* @param {Array<Object>} messages - Array of new message objects to process
|
||||
*/
|
||||
function processNewMessages(messages) {
|
||||
console.log('[ChatManager] Processing new messages:', {
|
||||
messageCount: messages.length,
|
||||
@@ -133,6 +182,11 @@ if (typeof window.ChatManager === 'undefined') {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleans up polling resources and resets the instance.
|
||||
* Should be called when the chat is no longer needed.
|
||||
* @function
|
||||
*/
|
||||
function cleanup() {
|
||||
console.log('[ChatManager] Cleaning up polling');
|
||||
if (pollInterval) {
|
||||
@@ -143,6 +197,12 @@ if (typeof window.ChatManager === 'undefined') {
|
||||
}
|
||||
|
||||
return {
|
||||
/**
|
||||
* Gets or creates a ChatManager instance for a conversation.
|
||||
* @function
|
||||
* @param {string} conversationId - The ID of the conversation to manage
|
||||
* @returns {Object} The ChatManager instance
|
||||
*/
|
||||
getInstance: function(conversationId) {
|
||||
if (!instance) {
|
||||
instance = init(conversationId);
|
||||
|
||||
@@ -1,4 +1,22 @@
|
||||
/**
|
||||
* @fileoverview Provides logging functionality for CSS color variables.
|
||||
* This file handles:
|
||||
* - Logging of base color loading status
|
||||
* - Logging of CSS file loading status
|
||||
* - Logging of primary and secondary color values
|
||||
*/
|
||||
|
||||
// Log initial base colors loading
|
||||
console.log('[CSS] Base colors loaded');
|
||||
|
||||
/**
|
||||
* Logs CSS color information when the DOM is fully loaded.
|
||||
* Reports:
|
||||
* - CSS files loading status
|
||||
* - Primary color value from CSS variables
|
||||
* - Secondary color value from CSS variables
|
||||
* @function
|
||||
*/
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
console.log('[CSS] All CSS files loaded');
|
||||
console.log('[CSS] Primary color:', getComputedStyle(document.documentElement).getPropertyValue('--primary-color').trim());
|
||||
|
||||
@@ -1,4 +1,21 @@
|
||||
// Debounce function
|
||||
/**
|
||||
* @fileoverview Manages the contacts filtering functionality.
|
||||
* This file handles:
|
||||
* - Contact search with debounced input
|
||||
* - Filter form submission
|
||||
* - Search state persistence
|
||||
* - Filter clearing functionality
|
||||
*/
|
||||
|
||||
/**
|
||||
* Creates a debounced version of a function that delays its execution
|
||||
* until after a specified wait time has elapsed since the last time it was invoked.
|
||||
* This helps prevent excessive form submissions during rapid user input.
|
||||
* @function
|
||||
* @param {Function} func - The function to debounce
|
||||
* @param {number} wait - The number of milliseconds to delay (300ms default for search)
|
||||
* @returns {Function} A debounced version of the provided function
|
||||
*/
|
||||
function debounce(func, wait) {
|
||||
let timeout;
|
||||
return function(...args) {
|
||||
@@ -7,7 +24,14 @@ function debounce(func, wait) {
|
||||
};
|
||||
}
|
||||
|
||||
// Initialize filter functionality
|
||||
/**
|
||||
* Initializes the contacts filter functionality when the DOM is loaded.
|
||||
* Sets up:
|
||||
* - Auto-submit on select changes
|
||||
* - Debounced search input with cursor position persistence
|
||||
* - Filter clearing functionality
|
||||
* @function
|
||||
*/
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Auto-submit the form on select change
|
||||
document.querySelectorAll('#filterForm select').forEach(function(el) {
|
||||
@@ -41,7 +65,11 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
}
|
||||
}
|
||||
|
||||
// Clear button resets all filters and submits the form
|
||||
/**
|
||||
* Handles the clear filters button click.
|
||||
* Resets all filter inputs and submits the form.
|
||||
* @event
|
||||
*/
|
||||
document.getElementById('clearFilters').addEventListener('click', function() {
|
||||
document.querySelector('#filterForm input[name="search"]').value = '';
|
||||
document.querySelector('#filterForm select[name="role"]').selectedIndex = 0;
|
||||
|
||||
@@ -1,4 +1,23 @@
|
||||
// Initialize chat when document is ready
|
||||
/**
|
||||
* @fileoverview Manages the real-time conversation functionality.
|
||||
* This file handles:
|
||||
* - Chat message display and management
|
||||
* - Message submission with file attachments
|
||||
* - Real-time message updates
|
||||
* - Chat state management
|
||||
* - UI interactions and animations
|
||||
*/
|
||||
|
||||
/**
|
||||
* Initializes the chat functionality when the document is ready.
|
||||
* Sets up:
|
||||
* - Chat state and message tracking
|
||||
* - Message display and submission
|
||||
* - File attachment handling
|
||||
* - Real-time message updates
|
||||
* - Cleanup on page unload
|
||||
* @function
|
||||
*/
|
||||
$(document).ready(function() {
|
||||
const conversationId = window.conversationId; // Set this in the template
|
||||
const currentUserId = window.currentUserId; // Set this in the template
|
||||
@@ -10,7 +29,19 @@ $(document).ready(function() {
|
||||
// Keep track of messages we've already displayed
|
||||
const displayedMessageIds = new Set();
|
||||
|
||||
// Function to append a new message to the chat
|
||||
/**
|
||||
* Appends a new message to the chat interface.
|
||||
* Handles message formatting, attachments, and UI updates.
|
||||
* @function
|
||||
* @param {Object} message - The message object to append
|
||||
* @param {string} message.id - The unique message ID
|
||||
* @param {string} message.content - The message content
|
||||
* @param {string} message.sender_id - The ID of the message sender
|
||||
* @param {string} message.sender_name - The name of the message sender
|
||||
* @param {string} message.sender_avatar - The avatar URL of the sender
|
||||
* @param {string} message.created_at - The message creation timestamp
|
||||
* @param {Array} [message.attachments] - Array of file attachments
|
||||
*/
|
||||
function appendMessage(message) {
|
||||
console.log('[Conversation] Attempting to append message:', {
|
||||
messageId: message.id,
|
||||
@@ -79,14 +110,23 @@ $(document).ready(function() {
|
||||
}
|
||||
});
|
||||
|
||||
// Scroll to bottom of chat messages
|
||||
/**
|
||||
* Scrolls the chat window to the bottom.
|
||||
* @function
|
||||
*/
|
||||
function scrollToBottom() {
|
||||
const chatMessages = document.getElementById('chatMessages');
|
||||
chatMessages.scrollTop = chatMessages.scrollHeight;
|
||||
}
|
||||
scrollToBottom();
|
||||
|
||||
// Listen for new messages
|
||||
/**
|
||||
* Event handler for new messages.
|
||||
* Appends new messages to the chat when received.
|
||||
* @event
|
||||
* @param {Event} event - The event object
|
||||
* @param {Object} message - The new message object
|
||||
*/
|
||||
$(document).on('new_message', function(event, message) {
|
||||
console.log('[Conversation] Received new_message event:', {
|
||||
messageId: message.id,
|
||||
@@ -96,7 +136,11 @@ $(document).ready(function() {
|
||||
appendMessage(message);
|
||||
});
|
||||
|
||||
// Handle file selection
|
||||
/**
|
||||
* Handles file selection for message attachments.
|
||||
* Updates the UI to show selected files.
|
||||
* @event
|
||||
*/
|
||||
$('#fileInput').on('change', function() {
|
||||
const files = Array.from(this.files);
|
||||
if (files.length > 0) {
|
||||
@@ -107,7 +151,14 @@ $(document).ready(function() {
|
||||
}
|
||||
});
|
||||
|
||||
// Handle message form submission
|
||||
/**
|
||||
* Handles message form submission.
|
||||
* Processes text messages and file attachments.
|
||||
* Manages submission state and UI feedback.
|
||||
* @event
|
||||
* @param {Event} e - The form submission event
|
||||
* @returns {boolean} false to prevent default form submission
|
||||
*/
|
||||
let isSubmitting = false;
|
||||
$('#messageForm').off('submit').on('submit', function(e) {
|
||||
e.preventDefault();
|
||||
@@ -202,7 +253,10 @@ $(document).ready(function() {
|
||||
return false;
|
||||
});
|
||||
|
||||
// Clean up on page unload
|
||||
/**
|
||||
* Cleans up chat resources when the page is unloaded.
|
||||
* @event
|
||||
*/
|
||||
$(window).on('beforeunload', function() {
|
||||
console.log('[Conversation] Cleaning up on page unload');
|
||||
chat.cleanup();
|
||||
|
||||
@@ -1,4 +1,20 @@
|
||||
// Debounce function
|
||||
/**
|
||||
* @fileoverview Manages the conversations list functionality.
|
||||
* This file handles:
|
||||
* - Conversation search with debounced input
|
||||
* - Search form submission
|
||||
* - Clear filter functionality
|
||||
*/
|
||||
|
||||
/**
|
||||
* Creates a debounced version of a function that delays its execution
|
||||
* until after a specified wait time has elapsed since the last time it was invoked.
|
||||
* This helps prevent excessive form submissions during rapid user input.
|
||||
* @function
|
||||
* @param {Function} func - The function to debounce
|
||||
* @param {number} wait - The number of milliseconds to delay (300ms default for search)
|
||||
* @returns {Function} A debounced version of the provided function
|
||||
*/
|
||||
function debounce(func, wait) {
|
||||
let timeout;
|
||||
return function(...args) {
|
||||
@@ -7,6 +23,13 @@ function debounce(func, wait) {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the conversations list functionality when the DOM is loaded.
|
||||
* Sets up:
|
||||
* - Search input with debounced form submission (300ms delay)
|
||||
* - Clear filter button to reset search and refresh results
|
||||
* @function
|
||||
*/
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const searchInput = document.getElementById('conversationSearchInput');
|
||||
const form = document.getElementById('conversationFilterForm');
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/**
|
||||
* @fileoverview Manages the conversation creation functionality.
|
||||
* This file handles:
|
||||
* - User selection interface using Select2
|
||||
* - Member management for new conversations
|
||||
* - Form submission with member data
|
||||
* - UI updates and validation
|
||||
*/
|
||||
|
||||
/**
|
||||
* Initializes conversation creation functionality when the document is ready.
|
||||
* Sets up:
|
||||
* - Select2 dropdown for user selection
|
||||
* - Member tracking and management
|
||||
* - Form handling
|
||||
* @function
|
||||
*/
|
||||
$(document).ready(function() {
|
||||
$('.select2').select2({
|
||||
theme: 'bootstrap-5',
|
||||
@@ -11,14 +28,22 @@ $(document).ready(function() {
|
||||
var creatorId = document.querySelector('.member-row').dataset.userId;
|
||||
addedMembers.add(creatorId);
|
||||
|
||||
// Function to show alert modal
|
||||
/**
|
||||
* Shows an alert modal with the specified message.
|
||||
* @function
|
||||
* @param {string} message - The message to display in the alert modal
|
||||
*/
|
||||
function showAlert(message) {
|
||||
$('#alertModalMessage').text(message);
|
||||
var alertModal = new bootstrap.Modal(document.getElementById('alertModal'));
|
||||
alertModal.show();
|
||||
}
|
||||
|
||||
// Handle Add Member button click
|
||||
/**
|
||||
* Handles adding a new member to the conversation.
|
||||
* Validates the selection and updates the UI accordingly.
|
||||
* @event
|
||||
*/
|
||||
$('#addMemberBtn').click(function() {
|
||||
var selectedUserId = $('#user_id').val();
|
||||
var selectedUserName = $('#user_id option:selected').text();
|
||||
@@ -69,6 +94,11 @@ $(document).ready(function() {
|
||||
updateHiddenInputs();
|
||||
});
|
||||
|
||||
/**
|
||||
* Updates the hidden form inputs with the current member list.
|
||||
* Removes existing member inputs and adds new ones for each current member.
|
||||
* @function
|
||||
*/
|
||||
function updateHiddenInputs() {
|
||||
// Remove any existing members inputs
|
||||
$('#conversationForm input[name="members"]').remove();
|
||||
|
||||
@@ -1,3 +1,12 @@
|
||||
/**
|
||||
* @fileoverview Provides debugging and maintenance functionality for the application.
|
||||
* This file handles:
|
||||
* - File system synchronization
|
||||
* - Database state verification
|
||||
* - Orphaned record cleanup
|
||||
* - Mismatch detection and reporting
|
||||
*/
|
||||
|
||||
// File system sync functionality
|
||||
document.getElementById('syncFilesBtn').addEventListener('click', async function() {
|
||||
const btn = this;
|
||||
@@ -162,7 +171,13 @@ document.getElementById('cleanupOrphanedBtn').addEventListener('click', async fu
|
||||
}
|
||||
});
|
||||
|
||||
// Helper function to update mismatch sections
|
||||
/**
|
||||
* Updates a mismatch section in the UI with verification results.
|
||||
* Displays counts and detailed information about mismatches.
|
||||
* @function
|
||||
* @param {string} sectionId - The ID of the section to update
|
||||
* @param {Array} items - Array of mismatch items to display
|
||||
*/
|
||||
function updateMismatchSection(sectionId, items) {
|
||||
const count = document.getElementById(`${sectionId}Count`);
|
||||
const list = document.getElementById(`${sectionId}List`);
|
||||
@@ -211,7 +226,13 @@ function updateMismatchSection(sectionId, items) {
|
||||
`).join('');
|
||||
}
|
||||
|
||||
// Helper function to format file sizes
|
||||
/**
|
||||
* Formats a file size in bytes to a human-readable string.
|
||||
* Converts to appropriate unit (B, KB, MB, GB, TB).
|
||||
* @function
|
||||
* @param {number} bytes - The size in bytes
|
||||
* @returns {string} The formatted size string (e.g., "1.5 MB")
|
||||
*/
|
||||
function formatSize(bytes) {
|
||||
if (bytes === 0) return '0 B';
|
||||
const k = 1024;
|
||||
|
||||
@@ -1,3 +1,14 @@
|
||||
/**
|
||||
* @fileoverview Manages the file grid view functionality.
|
||||
* This file handles:
|
||||
* - File grid and list view rendering
|
||||
* - File sorting and filtering
|
||||
* - File operations (star, restore, delete)
|
||||
* - View preferences
|
||||
* - Search functionality
|
||||
* - File details display
|
||||
*/
|
||||
|
||||
let currentView = 'grid';
|
||||
let lastSelectedIndex = -1;
|
||||
let sortColumn = 'name'; // Set default sort column to name
|
||||
@@ -10,7 +21,12 @@ window.isAdmin = document.body.dataset.isAdmin === 'true';
|
||||
// Check if we're on the trash page
|
||||
const isTrashPage = window.location.pathname.includes('/trash');
|
||||
|
||||
// Initialize the view and fetch files
|
||||
/**
|
||||
* Initializes the file view and fetches files.
|
||||
* Sets up the preferred view and initial file sorting.
|
||||
* @async
|
||||
* @function
|
||||
*/
|
||||
async function initializeView() {
|
||||
try {
|
||||
const response = await fetch('/api/user/preferred_view');
|
||||
@@ -31,6 +47,12 @@ async function initializeView() {
|
||||
sortFiles('name');
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles between grid and list views.
|
||||
* Updates the UI and saves the user's view preference.
|
||||
* @function
|
||||
* @param {string} view - The view to switch to ('grid' or 'list')
|
||||
*/
|
||||
function toggleView(view) {
|
||||
currentView = view;
|
||||
const grid = document.getElementById('fileGrid');
|
||||
@@ -77,6 +99,12 @@ function toggleView(view) {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Sorts files by the specified column.
|
||||
* Handles different data types (string, number, date) appropriately.
|
||||
* @function
|
||||
* @param {string} column - The column to sort by ('name', 'modified', 'type', 'size', 'auto_delete')
|
||||
*/
|
||||
function sortFiles(column) {
|
||||
if (sortColumn === column) {
|
||||
sortDirection *= -1; // Toggle direction
|
||||
@@ -102,6 +130,12 @@ function sortFiles(column) {
|
||||
renderFiles(currentFiles);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the appropriate icon class for a file based on its extension.
|
||||
* @function
|
||||
* @param {string} filename - The name of the file
|
||||
* @returns {string} The Font Awesome icon class for the file type
|
||||
*/
|
||||
function getFileIcon(filename) {
|
||||
const extension = filename.split('.').pop().toLowerCase();
|
||||
|
||||
@@ -127,6 +161,12 @@ function getFileIcon(filename) {
|
||||
return iconMap[extension] || 'fa-file';
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the files in either grid or list view.
|
||||
* Handles both trash and normal file views with appropriate actions.
|
||||
* @function
|
||||
* @param {Array} files - Array of file objects to render
|
||||
*/
|
||||
function renderFiles(files) {
|
||||
if (!files) return;
|
||||
currentFiles = files;
|
||||
@@ -223,6 +263,12 @@ function renderFiles(files) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches files from the server.
|
||||
* Handles both trash and starred file endpoints.
|
||||
* @async
|
||||
* @function
|
||||
*/
|
||||
async function fetchFiles() {
|
||||
try {
|
||||
const endpoint = isTrashPage ? '/api/rooms/trash' : '/api/rooms/starred';
|
||||
@@ -244,6 +290,11 @@ async function fetchFiles() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the CSRF token from various possible locations in the DOM.
|
||||
* @function
|
||||
* @returns {string} The CSRF token or empty string if not found
|
||||
*/
|
||||
function getCsrfToken() {
|
||||
// First try to get it from the meta tag
|
||||
const metaTag = document.querySelector('meta[name="csrf-token"]');
|
||||
@@ -275,6 +326,13 @@ function getCsrfToken() {
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles the star status of a file.
|
||||
* @function
|
||||
* @param {string} filename - The name of the file
|
||||
* @param {string} path - The path of the file
|
||||
* @param {number} roomId - The ID of the room containing the file
|
||||
*/
|
||||
function toggleStar(filename, path = '', roomId) {
|
||||
const csrfToken = getCsrfToken();
|
||||
if (!csrfToken) {
|
||||
@@ -308,6 +366,13 @@ function toggleStar(filename, path = '', roomId) {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Restores a file from the trash.
|
||||
* @function
|
||||
* @param {string} filename - The name of the file
|
||||
* @param {string} path - The path of the file
|
||||
* @param {number} roomId - The ID of the room containing the file
|
||||
*/
|
||||
function restoreFile(filename, path = '', roomId) {
|
||||
const csrfToken = getCsrfToken();
|
||||
if (!csrfToken) {
|
||||
@@ -341,6 +406,13 @@ function restoreFile(filename, path = '', roomId) {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the permanent delete confirmation modal.
|
||||
* @function
|
||||
* @param {string} filename - The name of the file
|
||||
* @param {string} path - The path of the file
|
||||
* @param {number} roomId - The ID of the room containing the file
|
||||
*/
|
||||
function showPermanentDeleteModal(filename, path = '', roomId) {
|
||||
fileToDelete = { filename, path, roomId };
|
||||
document.getElementById('permanentDeleteItemName').textContent = filename;
|
||||
@@ -348,6 +420,10 @@ function showPermanentDeleteModal(filename, path = '', roomId) {
|
||||
modal.show();
|
||||
}
|
||||
|
||||
/**
|
||||
* Permanently deletes a file after confirmation.
|
||||
* @function
|
||||
*/
|
||||
function permanentDeleteFile() {
|
||||
if (!fileToDelete) return;
|
||||
|
||||
@@ -405,6 +481,14 @@ function permanentDeleteFile() {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Navigates to a file or folder.
|
||||
* @function
|
||||
* @param {number} roomId - The ID of the room
|
||||
* @param {string} filename - The name of the file/folder
|
||||
* @param {string} path - The path of the file/folder
|
||||
* @param {string} type - The type of item ('file' or 'folder')
|
||||
*/
|
||||
function navigateToFile(roomId, filename, path, type) {
|
||||
if (type === 'folder') {
|
||||
window.location.href = `/room/${roomId}?path=${encodeURIComponent(path ? path + '/' + filename : filename)}`;
|
||||
@@ -413,11 +497,19 @@ function navigateToFile(roomId, filename, path, type) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the empty trash confirmation modal.
|
||||
* @function
|
||||
*/
|
||||
function showEmptyTrashModal() {
|
||||
const modal = new bootstrap.Modal(document.getElementById('emptyTrashModal'));
|
||||
modal.show();
|
||||
}
|
||||
|
||||
/**
|
||||
* Empties the trash by permanently deleting all trashed files.
|
||||
* @function
|
||||
*/
|
||||
function emptyTrash() {
|
||||
const csrfToken = getCsrfToken();
|
||||
if (!csrfToken) {
|
||||
@@ -465,6 +557,11 @@ function emptyTrash() {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the file details modal.
|
||||
* @function
|
||||
* @param {number} idx - The index of the file in the currentFiles array
|
||||
*/
|
||||
function showDetailsModal(idx) {
|
||||
const item = currentFiles[idx];
|
||||
const icon = item.type === 'folder'
|
||||
@@ -498,6 +595,12 @@ function showDetailsModal(idx) {
|
||||
modal.show();
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a date string to a localized format.
|
||||
* @function
|
||||
* @param {string} dateString - The date string to format
|
||||
* @returns {string} The formatted date string
|
||||
*/
|
||||
function formatDate(dateString) {
|
||||
const date = new Date(dateString);
|
||||
return date.toLocaleString();
|
||||
|
||||
@@ -1,3 +1,21 @@
|
||||
/**
|
||||
* @fileoverview Manages room member management functionality.
|
||||
* This file handles:
|
||||
* - User selection interface using Select2
|
||||
* - Adding new members to a room
|
||||
* - Removing existing members
|
||||
* - Form submission with member data
|
||||
*/
|
||||
|
||||
/**
|
||||
* Initializes member management functionality when the document is ready.
|
||||
* Sets up:
|
||||
* - Select2 dropdown for user selection
|
||||
* - Member removal functionality
|
||||
* - Member addition functionality
|
||||
* - Form submission handling
|
||||
* @function
|
||||
*/
|
||||
$(document).ready(function() {
|
||||
// Initialize Select2 for user selection
|
||||
$('.select2').select2({
|
||||
@@ -5,13 +23,22 @@ $(document).ready(function() {
|
||||
width: '100%'
|
||||
});
|
||||
|
||||
// Handle member removal
|
||||
/**
|
||||
* Handles member removal from the list.
|
||||
* Removes the member row from the UI when the remove button is clicked.
|
||||
* @event
|
||||
*/
|
||||
$(document).on('click', '.btn-remove-member', function() {
|
||||
const memberRow = $(this).closest('.member-row');
|
||||
memberRow.remove();
|
||||
});
|
||||
|
||||
// Handle adding new member
|
||||
/**
|
||||
* Handles adding a new member to the list.
|
||||
* Validates the selection and adds the member if not already present.
|
||||
* Creates a new member row with user details and adds it to the list.
|
||||
* @event
|
||||
*/
|
||||
$('#addMemberBtn').on('click', function() {
|
||||
const select = $('#user_id');
|
||||
const selectedOption = select.find('option:selected');
|
||||
@@ -52,7 +79,12 @@ $(document).ready(function() {
|
||||
select.val(null).trigger('change');
|
||||
});
|
||||
|
||||
// Handle form submission
|
||||
/**
|
||||
* Handles form submission.
|
||||
* Collects all member IDs and adds them as hidden inputs to the form.
|
||||
* @event
|
||||
* @param {Event} e - The form submission event
|
||||
*/
|
||||
$('#membersForm').on('submit', function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
|
||||
@@ -1,3 +1,18 @@
|
||||
/**
|
||||
* @fileoverview Manages room member functionality and permissions.
|
||||
* This file handles:
|
||||
* - User selection interface using Select2
|
||||
* - Room member permissions management
|
||||
* - Auto-saving permission changes
|
||||
*/
|
||||
|
||||
/**
|
||||
* Initializes room member functionality when the document is ready.
|
||||
* Sets up:
|
||||
* - Select2 dropdown for user selection with Bootstrap 5 theme
|
||||
* - Auto-save functionality for permission changes
|
||||
* @function
|
||||
*/
|
||||
$(document).ready(function() {
|
||||
// Initialize Select2 for user selection
|
||||
$('.select2').select2({
|
||||
|
||||
@@ -1,4 +1,20 @@
|
||||
// Debounce function
|
||||
/**
|
||||
* @fileoverview Manages the rooms list view functionality.
|
||||
* This file handles:
|
||||
* - Room list search with debounced input
|
||||
* - Room filter form submission
|
||||
* - Clear filter functionality for the rooms list
|
||||
*/
|
||||
|
||||
/**
|
||||
* Creates a debounced version of a function that delays its execution
|
||||
* until after a specified wait time has elapsed since the last time it was invoked.
|
||||
* This helps prevent excessive form submissions during rapid user input.
|
||||
* @function
|
||||
* @param {Function} func - The function to debounce
|
||||
* @param {number} wait - The number of milliseconds to delay (300ms default for search)
|
||||
* @returns {Function} A debounced version of the provided function
|
||||
*/
|
||||
function debounce(func, wait) {
|
||||
let timeout;
|
||||
return function(...args) {
|
||||
@@ -7,6 +23,13 @@ function debounce(func, wait) {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the rooms list functionality when the DOM is loaded.
|
||||
* Sets up event listeners for:
|
||||
* - Search input with debounced form submission (300ms delay)
|
||||
* - Clear filter button to reset search and refresh results
|
||||
* @function
|
||||
*/
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const searchInput = document.getElementById('roomSearchInput');
|
||||
const form = document.getElementById('roomFilterForm');
|
||||
|
||||
@@ -1,4 +1,19 @@
|
||||
// Debounce function
|
||||
/**
|
||||
* @fileoverview Manages room search and filtering functionality.
|
||||
* This file handles:
|
||||
* - Room search input with debounced submission
|
||||
* - Clear filter functionality
|
||||
* - Form submission for room filtering
|
||||
*/
|
||||
|
||||
/**
|
||||
* Creates a debounced version of a function that delays its execution
|
||||
* until after a specified wait time has elapsed since the last time it was invoked.
|
||||
* @function
|
||||
* @param {Function} func - The function to debounce
|
||||
* @param {number} wait - The number of milliseconds to delay
|
||||
* @returns {Function} A debounced version of the provided function
|
||||
*/
|
||||
function debounce(func, wait) {
|
||||
let timeout;
|
||||
return function(...args) {
|
||||
@@ -7,6 +22,13 @@ function debounce(func, wait) {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes room search and filtering functionality when the DOM is loaded.
|
||||
* Sets up event listeners for:
|
||||
* - Search input with debounced form submission
|
||||
* - Clear filter button
|
||||
* @function
|
||||
*/
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const searchInput = document.getElementById('roomSearchInput');
|
||||
const form = document.getElementById('roomFilterForm');
|
||||
|
||||
@@ -1,4 +1,23 @@
|
||||
/**
|
||||
* @fileoverview Manages file operations and state for the room interface.
|
||||
* This file handles:
|
||||
* - File fetching and state management
|
||||
* - File operations (delete, rename, move, download)
|
||||
* - File selection and batch operations
|
||||
* - Star/unstar functionality
|
||||
* - Navigation and path management
|
||||
*/
|
||||
|
||||
/**
|
||||
* @class FileManager
|
||||
* @classdesc Manages all file-related operations and state in the room interface.
|
||||
* Handles file operations, selection, and navigation.
|
||||
*/
|
||||
export class FileManager {
|
||||
/**
|
||||
* Creates a new FileManager instance.
|
||||
* @param {RoomManager} roomManager - The parent RoomManager instance
|
||||
*/
|
||||
constructor(roomManager) {
|
||||
console.log('[FileManager] Initializing...');
|
||||
this.roomManager = roomManager;
|
||||
@@ -13,6 +32,12 @@ export class FileManager {
|
||||
console.log('[FileManager] Initialized with roomManager:', roomManager);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches files from the server for the current path.
|
||||
* @async
|
||||
* @returns {Promise<Array>} A promise that resolves with the array of files
|
||||
* @throws {Error} If the fetch operation fails
|
||||
*/
|
||||
async fetchFiles() {
|
||||
console.log('[FileManager] Fetching files...');
|
||||
try {
|
||||
@@ -44,6 +69,13 @@ export class FileManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a file from the server.
|
||||
* @async
|
||||
* @param {string} filename - The name of the file to delete
|
||||
* @param {string} [path=''] - The path of the file to delete
|
||||
* @throws {Error} If the delete operation fails
|
||||
*/
|
||||
async deleteFile(filename, path = '') {
|
||||
console.log('[FileManager] Deleting file:', { filename, path });
|
||||
const csrfToken = document.querySelector('meta[name="csrf-token"]').getAttribute('content');
|
||||
@@ -90,6 +122,14 @@ export class FileManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Renames a file on the server.
|
||||
* @async
|
||||
* @param {string} fileId - The ID of the file to rename
|
||||
* @param {string} newName - The new name for the file
|
||||
* @returns {Promise<Object>} A promise that resolves with the result of the rename operation
|
||||
* @throws {Error} If the rename operation fails
|
||||
*/
|
||||
async renameFile(fileId, newName) {
|
||||
console.log('[FileManager] Renaming file:', { fileId, newName });
|
||||
try {
|
||||
@@ -127,6 +167,14 @@ export class FileManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves a file to a new location.
|
||||
* @async
|
||||
* @param {string} fileId - The ID of the file to move
|
||||
* @param {string} targetPath - The target path to move the file to
|
||||
* @returns {Promise<Object>} A promise that resolves with the result of the move operation
|
||||
* @throws {Error} If the move operation fails
|
||||
*/
|
||||
async moveFile(fileId, targetPath) {
|
||||
console.log('[FileManager] Starting moveFile...');
|
||||
console.log('[FileManager] Parameters:', { fileId, targetPath });
|
||||
@@ -178,6 +226,11 @@ export class FileManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the confirmed move operation after user confirmation.
|
||||
* @async
|
||||
* @throws {Error} If the move operation fails
|
||||
*/
|
||||
async moveFileConfirmed() {
|
||||
console.log('[FileManager] Starting moveFileConfirmed...');
|
||||
console.log('[FileManager] Current state:', {
|
||||
@@ -258,6 +311,13 @@ export class FileManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles the star status of a file.
|
||||
* @async
|
||||
* @param {string} filename - The name of the file to toggle star for
|
||||
* @param {string} path - The path of the file
|
||||
* @throws {Error} If the star toggle operation fails
|
||||
*/
|
||||
async toggleStar(filename, path) {
|
||||
console.log('[FileManager] Toggling star for:', filename, 'path:', path);
|
||||
const csrfToken = document.querySelector('meta[name="csrf-token"]').getAttribute('content');
|
||||
@@ -323,6 +383,13 @@ export class FileManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Downloads a single file.
|
||||
* @async
|
||||
* @param {string} filename - The name of the file to download
|
||||
* @param {string} [path=''] - The path of the file
|
||||
* @throws {Error} If the download operation fails
|
||||
*/
|
||||
async downloadFile(filename, path = '') {
|
||||
console.log('[FileManager] Downloading file:', { filename, path });
|
||||
const url = `/api/rooms/${this.roomManager.roomId}/files/${encodeURIComponent(filename)}`;
|
||||
@@ -360,6 +427,11 @@ export class FileManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Downloads multiple selected files as a zip archive.
|
||||
* @async
|
||||
* @throws {Error} If the download operation fails
|
||||
*/
|
||||
async downloadSelected() {
|
||||
console.log('[FileManager] Downloading selected files...');
|
||||
const selectedItems = this.getSelectedItems();
|
||||
@@ -414,6 +486,12 @@ export class FileManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the confirmed delete operation after user confirmation.
|
||||
* Supports both single file and batch deletion.
|
||||
* @async
|
||||
* @throws {Error} If the delete operation fails
|
||||
*/
|
||||
async deleteFileConfirmed() {
|
||||
const csrfToken = document.querySelector('meta[name="csrf-token"]').getAttribute('content');
|
||||
if (this.batchDeleteItems && this.batchDeleteItems.length) {
|
||||
@@ -476,6 +554,12 @@ export class FileManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the file selection based on user interaction.
|
||||
* Supports single selection, CTRL+click for multiple selection, and SHIFT+click for range selection.
|
||||
* @param {number} index - The index of the file being selected
|
||||
* @param {Event} event - The click event that triggered the selection
|
||||
*/
|
||||
updateSelection(index, event) {
|
||||
console.log('[FileManager] Updating selection:', { index, event });
|
||||
|
||||
@@ -521,11 +605,18 @@ export class FileManager {
|
||||
this.roomManager.viewManager.updateMultiSelectUI();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an array of currently selected file objects.
|
||||
* @returns {Array<Object>} Array of selected file objects
|
||||
*/
|
||||
getSelectedItems() {
|
||||
console.log('[FileManager] Getting selected items');
|
||||
return Array.from(this.selectedItems).map(index => this.currentFiles[index]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears all file selections and updates the UI.
|
||||
*/
|
||||
clearSelection() {
|
||||
console.log('[FileManager] Clearing selection');
|
||||
this.selectedItems.clear();
|
||||
@@ -535,6 +626,9 @@ export class FileManager {
|
||||
this.roomManager.viewManager.updateMultiSelectUI();
|
||||
}
|
||||
|
||||
/**
|
||||
* Navigates to the parent folder of the current path.
|
||||
*/
|
||||
navigateToParent() {
|
||||
if (!this.roomManager.currentPath) return;
|
||||
const parts = this.roomManager.currentPath.split('/');
|
||||
|
||||
@@ -1,4 +1,24 @@
|
||||
/**
|
||||
* @fileoverview Manages modal dialogs for the room interface.
|
||||
* This file handles:
|
||||
* - Modal initialization and configuration
|
||||
* - File operations (delete, rename, move)
|
||||
* - Folder creation
|
||||
* - File details display
|
||||
* - Overwrite confirmation
|
||||
* - Batch operations
|
||||
*/
|
||||
|
||||
/**
|
||||
* @class ModalManager
|
||||
* @classdesc Manages all modal dialogs and their interactions in the room interface.
|
||||
* Handles file operations, folder creation, and various confirmation dialogs.
|
||||
*/
|
||||
export class ModalManager {
|
||||
/**
|
||||
* Creates a new ModalManager instance.
|
||||
* @param {RoomManager} roomManager - The parent RoomManager instance
|
||||
*/
|
||||
constructor(roomManager) {
|
||||
this.roomManager = roomManager;
|
||||
|
||||
@@ -16,6 +36,10 @@ export class ModalManager {
|
||||
this.initializeModals();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes event listeners for all modals.
|
||||
* Sets up handlers for delete, new folder, rename, and move operations.
|
||||
*/
|
||||
initializeModals() {
|
||||
// Initialize delete modal
|
||||
if (this.roomManager.canDelete) {
|
||||
@@ -55,6 +79,11 @@ export class ModalManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the delete confirmation modal for a single file.
|
||||
* @param {string} filename - The name of the file to delete
|
||||
* @param {string} [path=''] - The path of the file to delete
|
||||
*/
|
||||
showDeleteModal(filename, path = '') {
|
||||
console.log('[ModalManager] Showing delete modal for:', { filename, path });
|
||||
const fileNameEl = document.getElementById('deleteFileName');
|
||||
@@ -82,6 +111,10 @@ export class ModalManager {
|
||||
this.deleteModal.show();
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the delete confirmation modal for multiple selected files.
|
||||
* Processes all selected checkboxes and prepares for batch deletion.
|
||||
*/
|
||||
showBatchDeleteModal() {
|
||||
const selectedCheckboxes = document.querySelectorAll('.select-item-checkbox:checked');
|
||||
if (selectedCheckboxes.length === 0) return;
|
||||
@@ -130,6 +163,10 @@ export class ModalManager {
|
||||
this.deleteModal.show();
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the rename modal for a file or folder.
|
||||
* @param {string} filename - The current name of the file/folder
|
||||
*/
|
||||
showRenameModal(filename) {
|
||||
document.getElementById('renameError').textContent = '';
|
||||
const ext = filename.includes('.') ? filename.substring(filename.lastIndexOf('.')) : '';
|
||||
@@ -149,6 +186,10 @@ export class ModalManager {
|
||||
}, 100);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the file details modal.
|
||||
* @param {Object} file - The file object containing details to display
|
||||
*/
|
||||
showDetailsModal(file) {
|
||||
const icon = file.type === 'folder'
|
||||
? `<i class='fas fa-folder' style='font-size:2.2rem;color:var(--primary-color);'></i>`
|
||||
@@ -182,6 +223,11 @@ export class ModalManager {
|
||||
this.detailsModal.show();
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the overwrite confirmation modal.
|
||||
* @param {string} filename - The name of the file that would be overwritten
|
||||
* @returns {Promise<string>} A promise that resolves with the user's choice ('skip', 'skip_all', 'overwrite', or 'overwrite_all')
|
||||
*/
|
||||
showOverwriteModal(filename) {
|
||||
return new Promise((resolve) => {
|
||||
const fileNameEl = document.getElementById('overwriteFileName');
|
||||
@@ -206,6 +252,11 @@ export class ModalManager {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the move file modal.
|
||||
* @param {string} fileId - The ID of the file to move
|
||||
* @param {string} path - The current path of the file
|
||||
*/
|
||||
showMoveModal(fileId, path) {
|
||||
console.log('[ModalManager] Showing move modal for file:', { fileId, path });
|
||||
document.getElementById('moveError').textContent = '';
|
||||
@@ -251,6 +302,10 @@ export class ModalManager {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new folder in the current path.
|
||||
* @async
|
||||
*/
|
||||
async createFolder() {
|
||||
const folderName = document.getElementById('folderNameInput').value.trim();
|
||||
if (!folderName) {
|
||||
@@ -290,6 +345,10 @@ export class ModalManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Renames a file or folder.
|
||||
* @async
|
||||
*/
|
||||
async renameFile() {
|
||||
const newName = document.getElementById('renameInput').value.trim();
|
||||
if (!newName) {
|
||||
|
||||
@@ -1,3 +1,13 @@
|
||||
/**
|
||||
* @fileoverview Main room management module that coordinates all room functionality.
|
||||
* This file handles:
|
||||
* - Room initialization and configuration
|
||||
* - Manager coordination (File, View, Upload, Search, Modal)
|
||||
* - Navigation and path management
|
||||
* - Event handling and user interactions
|
||||
* - Permission management
|
||||
*/
|
||||
|
||||
console.log('[RoomManager] Script loaded');
|
||||
|
||||
// Main room.js file - Coordinates all room functionality
|
||||
@@ -9,7 +19,23 @@ import { ModalManager } from './modalManager.js';
|
||||
|
||||
console.log('[RoomManager] All modules imported successfully');
|
||||
|
||||
/**
|
||||
* @class RoomManager
|
||||
* @classdesc Main class that coordinates all room functionality and manages the various
|
||||
* sub-managers (File, View, Upload, Search, Modal).
|
||||
*/
|
||||
class RoomManager {
|
||||
/**
|
||||
* Creates a new RoomManager instance.
|
||||
* @param {Object} config - Configuration object for the room
|
||||
* @param {string} config.roomId - The ID of the room
|
||||
* @param {boolean} config.canDelete - Whether the user can delete files
|
||||
* @param {boolean} config.canShare - Whether the user can share files
|
||||
* @param {boolean} config.canUpload - Whether the user can upload files
|
||||
* @param {boolean} config.canDownload - Whether the user can download files
|
||||
* @param {boolean} config.canRename - Whether the user can rename files
|
||||
* @param {boolean} config.canMove - Whether the user can move files
|
||||
*/
|
||||
constructor(config) {
|
||||
console.log('[RoomManager] Initializing with config:', config);
|
||||
this.roomId = config.roomId;
|
||||
@@ -33,6 +59,11 @@ class RoomManager {
|
||||
this.initialize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the room functionality.
|
||||
* Sets up the view, fetches files, initializes search, and sets up event listeners.
|
||||
* @async
|
||||
*/
|
||||
async initialize() {
|
||||
console.log('[RoomManager] Starting initialization...');
|
||||
// Get current path from URL
|
||||
@@ -68,12 +99,19 @@ class RoomManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Navigates to a subfolder within the current path.
|
||||
* @param {string} folderName - The name of the folder to navigate to
|
||||
*/
|
||||
navigateToFolder(folderName) {
|
||||
console.log('[RoomManager] Navigating to folder:', folderName);
|
||||
const newPath = this.currentPath ? `${this.currentPath}/${folderName}` : folderName;
|
||||
this.navigateTo(newPath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Navigates to the parent folder of the current path.
|
||||
*/
|
||||
navigateToParent() {
|
||||
console.log('[RoomManager] Navigating to parent folder');
|
||||
if (!this.currentPath) return;
|
||||
@@ -84,6 +122,10 @@ class RoomManager {
|
||||
this.navigateTo(newPath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Navigates to a specific path and updates the URL.
|
||||
* @param {string} path - The path to navigate to
|
||||
*/
|
||||
navigateTo(path) {
|
||||
console.log('[RoomManager] Navigating to path:', path);
|
||||
this.currentPath = path;
|
||||
@@ -101,11 +143,20 @@ class RoomManager {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current path from the URL parameters.
|
||||
* @returns {string} The current path from the URL
|
||||
*/
|
||||
getPathFromUrl() {
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
return urlParams.get('path') || '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes event listeners for user interactions.
|
||||
* Sets up handlers for select all, download selected, delete selected,
|
||||
* and click outside to clear selection.
|
||||
*/
|
||||
initializeEventListeners() {
|
||||
console.log('[RoomManager] Setting up event listeners');
|
||||
|
||||
@@ -151,7 +202,10 @@ class RoomManager {
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize the room manager when the DOM is loaded
|
||||
/**
|
||||
* Initializes the room manager when the DOM is loaded.
|
||||
* Creates a new RoomManager instance with configuration from meta tags.
|
||||
*/
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const config = {
|
||||
roomId: document.querySelector('meta[name="room-id"]').getAttribute('content'),
|
||||
|
||||
@@ -1,10 +1,34 @@
|
||||
/**
|
||||
* @fileoverview Manages search functionality for the room interface.
|
||||
* This file handles:
|
||||
* - Quick search input processing
|
||||
* - Debounced search execution
|
||||
* - File filtering based on search terms
|
||||
* - Search state management
|
||||
* - Clear search functionality
|
||||
*/
|
||||
|
||||
/**
|
||||
* @class SearchManager
|
||||
* @classdesc Manages search operations including input handling, debounced search execution,
|
||||
* and file filtering based on search criteria.
|
||||
*/
|
||||
export class SearchManager {
|
||||
/**
|
||||
* Creates a new SearchManager instance.
|
||||
* @param {RoomManager} roomManager - The parent RoomManager instance
|
||||
*/
|
||||
constructor(roomManager) {
|
||||
this.roomManager = roomManager;
|
||||
this.searchInput = document.getElementById('quickSearchInput');
|
||||
this.clearSearchBtn = document.getElementById('clearSearchBtn');
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the search functionality.
|
||||
* Sets up event listeners for search input and clear button.
|
||||
* Creates a debounced search function to prevent excessive searches.
|
||||
*/
|
||||
initialize() {
|
||||
if (!this.searchInput) return;
|
||||
|
||||
@@ -35,6 +59,11 @@ export class SearchManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the search operation on the current file list.
|
||||
* Filters files based on name and type matching the search term.
|
||||
* @param {string} searchTerm - The term to search for
|
||||
*/
|
||||
performSearch(searchTerm) {
|
||||
if (!this.roomManager.fileManager.currentFiles) return;
|
||||
|
||||
@@ -47,6 +76,14 @@ export class SearchManager {
|
||||
this.roomManager.viewManager.renderFiles(filteredFiles);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a debounced version of a function.
|
||||
* Delays the execution of the function until after a specified wait time
|
||||
* has elapsed since the last time it was invoked.
|
||||
* @param {Function} func - The function to debounce
|
||||
* @param {number} wait - The number of milliseconds to delay
|
||||
* @returns {Function} The debounced function
|
||||
*/
|
||||
debounce(func, wait) {
|
||||
let timeout;
|
||||
return function executedFunction(...args) {
|
||||
|
||||
@@ -1,4 +1,24 @@
|
||||
/**
|
||||
* @fileoverview Manages file upload functionality for the room interface.
|
||||
* This file handles:
|
||||
* - File upload initialization and configuration
|
||||
* - Drag and drop file handling
|
||||
* - Upload progress tracking
|
||||
* - File type validation
|
||||
* - Overwrite handling
|
||||
* - Batch upload management
|
||||
*/
|
||||
|
||||
/**
|
||||
* @class UploadManager
|
||||
* @classdesc Manages file upload operations including drag-and-drop, progress tracking,
|
||||
* and handling of file conflicts and validations.
|
||||
*/
|
||||
export class UploadManager {
|
||||
/**
|
||||
* Creates a new UploadManager instance.
|
||||
* @param {RoomManager} roomManager - The parent RoomManager instance
|
||||
*/
|
||||
constructor(roomManager) {
|
||||
this.roomManager = roomManager;
|
||||
this.pendingUploads = [];
|
||||
@@ -19,6 +39,10 @@ export class UploadManager {
|
||||
this.initializeUploadHandlers();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes event handlers for file upload functionality.
|
||||
* Sets up drag and drop handlers and file input change handlers.
|
||||
*/
|
||||
initializeUploadHandlers() {
|
||||
if (!this.roomManager.canUpload) return;
|
||||
|
||||
@@ -44,19 +68,33 @@ export class UploadManager {
|
||||
this.fileInput.addEventListener('change', this.handleFileSelect.bind(this));
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevents default browser behavior for drag and drop events.
|
||||
* @param {Event} e - The event object
|
||||
*/
|
||||
preventDefaults(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}
|
||||
|
||||
/**
|
||||
* Highlights the drop zone when files are dragged over it.
|
||||
*/
|
||||
highlight() {
|
||||
this.dropZoneOverlay.style.display = 'block';
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes highlight from the drop zone.
|
||||
*/
|
||||
unhighlight() {
|
||||
this.dropZoneOverlay.style.display = 'none';
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles files dropped onto the drop zone.
|
||||
* @param {DragEvent} e - The drop event object
|
||||
*/
|
||||
async handleDrop(e) {
|
||||
const dt = e.dataTransfer;
|
||||
const files = dt.files;
|
||||
@@ -66,11 +104,18 @@ export class UploadManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles files selected through the file input.
|
||||
*/
|
||||
async handleFileSelect() {
|
||||
if (!this.fileInput.files.length) return;
|
||||
await this.startUpload(Array.from(this.fileInput.files));
|
||||
}
|
||||
|
||||
/**
|
||||
* Initiates the upload process for a set of files.
|
||||
* @param {Array<File>} files - Array of files to upload
|
||||
*/
|
||||
async startUpload(files) {
|
||||
this.uploadProgressContainer.style.display = 'block';
|
||||
this.uploadProgressBar.style.width = '0%';
|
||||
@@ -85,6 +130,10 @@ export class UploadManager {
|
||||
await this.uploadFilesSequentially();
|
||||
}
|
||||
|
||||
/**
|
||||
* Uploads files one at a time, handling progress and errors.
|
||||
* @async
|
||||
*/
|
||||
async uploadFilesSequentially() {
|
||||
let completedFiles = 0;
|
||||
let currentFileIndex = 0;
|
||||
@@ -182,6 +231,11 @@ export class UploadManager {
|
||||
await processNextFile();
|
||||
}
|
||||
|
||||
/**
|
||||
* Uploads a single file to the server.
|
||||
* @param {FormData} formData - Form data containing the file and upload parameters
|
||||
* @returns {Promise<Object>} Response object containing success status and error message if any
|
||||
*/
|
||||
async uploadFile(formData) {
|
||||
const csrfToken = document.querySelector('meta[name="csrf-token"]').getAttribute('content');
|
||||
const response = await fetch(`/api/rooms/${this.roomManager.roomId}/files/upload`, {
|
||||
@@ -197,6 +251,11 @@ export class UploadManager {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles file type validation errors.
|
||||
* Displays error message with allowed file types.
|
||||
* @param {File} file - The file that failed validation
|
||||
*/
|
||||
handleFileTypeError(file) {
|
||||
const allowedTypes = [
|
||||
'Documents: PDF, DOCX, DOC, TXT, RTF, ODT, MD, CSV',
|
||||
@@ -225,6 +284,12 @@ export class UploadManager {
|
||||
this.uploadProgressBar.className = 'progress-bar bg-danger-opacity-15 text-danger';
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles file existence conflicts during upload.
|
||||
* @param {File} file - The file being uploaded
|
||||
* @param {FormData} formData - Form data for the upload
|
||||
* @returns {Promise<Object>} Object containing continue status
|
||||
*/
|
||||
async handleFileExists(file, formData) {
|
||||
if (this.overwriteAll) {
|
||||
formData.append('overwrite', 'true');
|
||||
|
||||
@@ -1,4 +1,23 @@
|
||||
/**
|
||||
* @fileoverview Manages the file view functionality for the room interface.
|
||||
* This file handles:
|
||||
* - Grid and list view rendering
|
||||
* - File sorting and organization
|
||||
* - Breadcrumb navigation
|
||||
* - File action buttons
|
||||
* - Multi-select functionality
|
||||
*/
|
||||
|
||||
/**
|
||||
* @class ViewManager
|
||||
* @classdesc Manages the visual representation and interaction of files in the room interface.
|
||||
* Handles view switching, file rendering, sorting, and UI updates.
|
||||
*/
|
||||
export class ViewManager {
|
||||
/**
|
||||
* Creates a new ViewManager instance.
|
||||
* @param {RoomManager} roomManager - The parent RoomManager instance
|
||||
*/
|
||||
constructor(roomManager) {
|
||||
console.log('[ViewManager] Initializing...');
|
||||
this.roomManager = roomManager;
|
||||
@@ -8,6 +27,11 @@ export class ViewManager {
|
||||
console.log('[ViewManager] Initialized with roomManager:', roomManager);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the view with user preferences.
|
||||
* Fetches and applies the user's preferred view type.
|
||||
* @async
|
||||
*/
|
||||
async initializeView() {
|
||||
console.log('[ViewManager] Initializing view...');
|
||||
try {
|
||||
@@ -29,6 +53,12 @@ export class ViewManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles between grid and list views.
|
||||
* Updates UI and saves user preference.
|
||||
* @async
|
||||
* @param {string} view - The view type to switch to ('grid' or 'list')
|
||||
*/
|
||||
async toggleView(view) {
|
||||
console.log('[ViewManager] Toggling view to:', view);
|
||||
this.currentView = view;
|
||||
@@ -60,6 +90,11 @@ export class ViewManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the file list in the current view mode.
|
||||
* @async
|
||||
* @param {Array<Object>} files - Array of file objects to render
|
||||
*/
|
||||
async renderFiles(files) {
|
||||
console.log('[ViewManager] Rendering files:', files);
|
||||
const fileGrid = document.getElementById('fileGrid');
|
||||
@@ -83,6 +118,10 @@ export class ViewManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the breadcrumb navigation.
|
||||
* Shows the current path and provides navigation controls.
|
||||
*/
|
||||
renderBreadcrumb() {
|
||||
console.log('[ViewManager] Rendering breadcrumb');
|
||||
const breadcrumb = document.getElementById('breadcrumb');
|
||||
@@ -140,6 +179,11 @@ export class ViewManager {
|
||||
console.log('[ViewManager] Breadcrumb rendered');
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the file list in list view mode.
|
||||
* @async
|
||||
* @param {Array<Object>} files - Array of file objects to render
|
||||
*/
|
||||
async renderListView(files) {
|
||||
console.log('[ViewManager] Rendering list view');
|
||||
const fileGrid = document.getElementById('fileGrid');
|
||||
@@ -172,6 +216,11 @@ export class ViewManager {
|
||||
console.log('[ViewManager] List view rendered');
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the file list in grid view mode.
|
||||
* @async
|
||||
* @param {Array<Object>} files - Array of file objects to render
|
||||
*/
|
||||
async renderGridView(files) {
|
||||
console.log('[ViewManager] Rendering grid view');
|
||||
const fileGrid = document.getElementById('fileGrid');
|
||||
@@ -193,6 +242,12 @@ export class ViewManager {
|
||||
console.log('[ViewManager] Grid view rendered');
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a single file row for list view.
|
||||
* @param {Object} file - The file object to render
|
||||
* @param {number} index - The index of the file in the list
|
||||
* @returns {string} HTML string for the file row
|
||||
*/
|
||||
renderFileRow(file, index) {
|
||||
console.log('[ViewManager] Rendering file row:', { file, index });
|
||||
const isFolder = file.type === 'folder';
|
||||
@@ -226,6 +281,12 @@ export class ViewManager {
|
||||
`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a single file card for grid view.
|
||||
* @param {Object} file - The file object to render
|
||||
* @param {number} index - The index of the file in the list
|
||||
* @returns {string} HTML string for the file card
|
||||
*/
|
||||
renderFileCard(file, index) {
|
||||
console.log('[ViewManager] Rendering file card:', { file, index });
|
||||
const isFolder = file.type === 'folder';
|
||||
@@ -260,6 +321,12 @@ export class ViewManager {
|
||||
`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the action buttons for a file.
|
||||
* @param {Object} file - The file object
|
||||
* @param {number} index - The index of the file in the list
|
||||
* @returns {string} HTML string for the action buttons
|
||||
*/
|
||||
renderFileActions(file, index) {
|
||||
console.log('[ViewManager] Rendering file actions:', { file, index });
|
||||
const actions = [];
|
||||
@@ -321,6 +388,11 @@ export class ViewManager {
|
||||
return actions.join('');
|
||||
}
|
||||
|
||||
/**
|
||||
* Sorts the file list based on current sort settings.
|
||||
* @param {Array<Object>} files - Array of file objects to sort
|
||||
* @returns {Array<Object>} Sorted array of file objects
|
||||
*/
|
||||
sortFiles(files) {
|
||||
console.log('[ViewManager] Sorting files:', {
|
||||
column: this.sortColumn,
|
||||
@@ -342,6 +414,11 @@ export class ViewManager {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the appropriate icon class for a file based on its extension.
|
||||
* @param {string} filename - The name of the file
|
||||
* @returns {string} Font Awesome icon class name
|
||||
*/
|
||||
getFileIcon(filename) {
|
||||
const extension = filename.split('.').pop().toLowerCase();
|
||||
console.log('[ViewManager] Getting icon for file:', { filename, extension });
|
||||
@@ -368,6 +445,11 @@ export class ViewManager {
|
||||
return iconMap[extension] || 'fa-file';
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a file size in bytes to a human-readable string.
|
||||
* @param {number} bytes - The file size in bytes
|
||||
* @returns {string} Formatted file size string
|
||||
*/
|
||||
formatFileSize(bytes) {
|
||||
if (!bytes) return '0 B';
|
||||
|
||||
@@ -383,6 +465,9 @@ export class ViewManager {
|
||||
return `${size.toFixed(1)} ${units[unitIndex]}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the multi-select UI based on current selection state.
|
||||
*/
|
||||
updateMultiSelectUI() {
|
||||
console.log('[ViewManager] Updating multi-select UI');
|
||||
const selectedItems = this.roomManager.fileManager.getSelectedItems();
|
||||
|
||||
@@ -1,3 +1,13 @@
|
||||
/**
|
||||
* @fileoverview Manages the application settings functionality.
|
||||
* This file handles color settings, tab persistence, and UI customization.
|
||||
* It provides functionality to:
|
||||
* - Manage primary and secondary color schemes
|
||||
* - Handle settings tab navigation and persistence
|
||||
* - Convert and manipulate colors (hex, RGB)
|
||||
* - Update UI elements with new color schemes
|
||||
*/
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const primaryColorInput = document.getElementById('primaryColor');
|
||||
const secondaryColorInput = document.getElementById('secondaryColor');
|
||||
@@ -7,7 +17,12 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
const settingsTabs = document.querySelectorAll('#settingsTabs button[data-bs-toggle="tab"]');
|
||||
const tabContent = document.querySelectorAll('.tab-pane');
|
||||
|
||||
// Function to activate a specific tab
|
||||
/**
|
||||
* Activates a specific settings tab and updates the UI accordingly.
|
||||
* Also persists the selected tab in localStorage.
|
||||
* @function
|
||||
* @param {string} tabId - The ID of the tab to activate
|
||||
*/
|
||||
function activateTab(tabId) {
|
||||
// Remove active class from all tabs and content
|
||||
settingsTabs.forEach(tab => {
|
||||
@@ -42,7 +57,12 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
const savedTab = localStorage.getItem('settingsActiveTab') || window.location.hash.substring(1) || 'colors';
|
||||
activateTab(savedTab);
|
||||
|
||||
// Color manipulation functions
|
||||
/**
|
||||
* Converts a hexadecimal color code to RGB values.
|
||||
* @function
|
||||
* @param {string} hex - The hexadecimal color code (e.g., '#FF0000')
|
||||
* @returns {Object|null} Object containing r, g, b values or null if invalid hex
|
||||
*/
|
||||
function hexToRgb(hex) {
|
||||
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
|
||||
return result ? {
|
||||
@@ -52,6 +72,14 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
} : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts RGB values to a hexadecimal color code.
|
||||
* @function
|
||||
* @param {number} r - Red value (0-255)
|
||||
* @param {number} g - Green value (0-255)
|
||||
* @param {number} b - Blue value (0-255)
|
||||
* @returns {string} Hexadecimal color code
|
||||
*/
|
||||
function rgbToHex(r, g, b) {
|
||||
return '#' + [r, g, b].map(x => {
|
||||
const hex = x.toString(16);
|
||||
@@ -59,6 +87,13 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
}).join('');
|
||||
}
|
||||
|
||||
/**
|
||||
* Lightens a color by a specified amount.
|
||||
* @function
|
||||
* @param {string} color - The hexadecimal color to lighten
|
||||
* @param {number} amount - The amount to lighten (0-1)
|
||||
* @returns {string} The lightened hexadecimal color
|
||||
*/
|
||||
function lightenColor(color, amount) {
|
||||
const rgb = hexToRgb(color);
|
||||
if (!rgb) return color;
|
||||
@@ -70,6 +105,13 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Darkens a color by a specified amount.
|
||||
* @function
|
||||
* @param {string} color - The hexadecimal color to darken
|
||||
* @param {number} amount - The amount to darken (0-1)
|
||||
* @returns {string} The darkened hexadecimal color
|
||||
*/
|
||||
function darkenColor(color, amount) {
|
||||
const rgb = hexToRgb(color);
|
||||
if (!rgb) return color;
|
||||
@@ -81,6 +123,13 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates all color-related UI elements based on a new color value.
|
||||
* Updates CSS variables, chart colors, and color previews.
|
||||
* @function
|
||||
* @param {string} color - The new color value in hexadecimal
|
||||
* @param {boolean} isPrimary - Whether this is the primary color (true) or secondary color (false)
|
||||
*/
|
||||
function updateAllColors(color, isPrimary) {
|
||||
const prefix = isPrimary ? 'primary' : 'secondary';
|
||||
|
||||
@@ -162,7 +211,11 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
updateAllColors(secondaryColorInput.value, false);
|
||||
});
|
||||
|
||||
// Initialize colors from database values
|
||||
/**
|
||||
* Initializes the color settings from the current CSS variables.
|
||||
* Updates input values and color previews.
|
||||
* @function
|
||||
*/
|
||||
function initializeColors() {
|
||||
// Get the current computed CSS variable values
|
||||
const computedPrimaryColor = getComputedStyle(document.documentElement).getPropertyValue('--primary-color').trim();
|
||||
|
||||
@@ -1,10 +1,29 @@
|
||||
/**
|
||||
* @fileoverview Manages the starred files functionality for the document management system.
|
||||
* This file handles the starred files view and user view preferences.
|
||||
* It provides functionality to view starred items in either grid or list view
|
||||
* and manages user view preferences for the starred items section.
|
||||
*/
|
||||
|
||||
let currentView = 'grid';
|
||||
|
||||
/**
|
||||
* Initializes the starred files view when the DOM content is loaded.
|
||||
* Sets up the initial view based on user preferences.
|
||||
* @function
|
||||
*/
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Initialize view
|
||||
initializeView();
|
||||
});
|
||||
|
||||
/**
|
||||
* Initializes the view based on user preferences.
|
||||
* Fetches the user's preferred view (grid or list) and applies it.
|
||||
* Falls back to grid view if there's an error.
|
||||
* @async
|
||||
* @function
|
||||
*/
|
||||
async function initializeView() {
|
||||
try {
|
||||
const response = await fetch('/api/user/preferred_view');
|
||||
@@ -18,6 +37,13 @@ async function initializeView() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles between grid and list views for starred files.
|
||||
* Updates the UI and saves the user's view preference.
|
||||
* @function
|
||||
* @param {string} view - The view to switch to ('grid' or 'list')
|
||||
* @throws {Error} If the view preference cannot be saved
|
||||
*/
|
||||
function toggleView(view) {
|
||||
currentView = view;
|
||||
const grid = document.getElementById('fileGrid');
|
||||
|
||||
@@ -1,6 +1,18 @@
|
||||
/**
|
||||
* @fileoverview Manages the trash functionality for the document management system.
|
||||
* This file handles the trash view, empty trash operations, and view preferences.
|
||||
* It provides functionality to view trashed items in grid or list view,
|
||||
* empty the trash, and manage user view preferences.
|
||||
*/
|
||||
|
||||
let currentView = 'grid';
|
||||
|
||||
// Make functions globally available
|
||||
/**
|
||||
* Shows the empty trash confirmation modal.
|
||||
* @function
|
||||
* @global
|
||||
* @throws {Error} If the modal element is not found or if there's an error showing the modal
|
||||
*/
|
||||
window.showEmptyTrashModal = function() {
|
||||
console.log('Showing Empty Trash Modal');
|
||||
const modalEl = document.getElementById('emptyTrashModal');
|
||||
@@ -20,6 +32,16 @@ window.showEmptyTrashModal = function() {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Empties the trash by permanently deleting all trashed files.
|
||||
* This function:
|
||||
* 1. Fetches all trashed files to get their room IDs
|
||||
* 2. Makes API calls to empty trash in each room
|
||||
* 3. Updates the UI to reflect the changes
|
||||
* @function
|
||||
* @global
|
||||
* @throws {Error} If CSRF token is not available or if API calls fail
|
||||
*/
|
||||
window.emptyTrash = function() {
|
||||
console.log('Emptying Trash');
|
||||
const csrfToken = document.querySelector('meta[name="csrf-token"]').getAttribute('content');
|
||||
@@ -85,6 +107,11 @@ window.emptyTrash = function() {
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Initializes the trash view when the DOM content is loaded.
|
||||
* Sets up event listeners for empty trash functionality and initializes the view.
|
||||
* @function
|
||||
*/
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
console.log('DOM Content Loaded');
|
||||
|
||||
@@ -112,6 +139,13 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
initializeView();
|
||||
});
|
||||
|
||||
/**
|
||||
* Initializes the view based on user preferences.
|
||||
* Fetches the user's preferred view (grid or list) and applies it.
|
||||
* Falls back to grid view if there's an error.
|
||||
* @async
|
||||
* @function
|
||||
*/
|
||||
async function initializeView() {
|
||||
try {
|
||||
const response = await fetch('/api/user/preferred_view');
|
||||
@@ -125,6 +159,13 @@ async function initializeView() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles between grid and list views.
|
||||
* Updates the UI and saves the user's view preference.
|
||||
* @function
|
||||
* @param {string} view - The view to switch to ('grid' or 'list')
|
||||
* @throws {Error} If the view preference cannot be saved
|
||||
*/
|
||||
function toggleView(view) {
|
||||
currentView = view;
|
||||
const grid = document.getElementById('fileGrid');
|
||||
|
||||
Reference in New Issue
Block a user