Dynamic Timeline Rendering (scripts.js)
Relevant source files
The following files were used as context for generating this wiki page:
The scripts.js file is the primary client-side engine for the Campuspal Room Finder application. It is responsible for creating a dynamic, responsive user experience by handling user interactions, fetching data from the server asynchronously, and updating the user interface without requiring full page reloads. Its main duties include managing the AJAX-powered room search, populating and controlling the room details modal, handling the tabbed results interface, and providing UI enhancements for the file upload page.
This script works in close coordination with the Django backend (views.py), the API (api.py as described in the README), and the HTML structure (search.html) to present a seamless flow of information to the user. It listens for DOM events, makes fetch requests to the server, and manipulates the DOM to display results, details, and UI state changes.
Sources: finder/static/finder/js/scripts.js, README.md
Core Architecture and Event Handling
The script initializes its functions once the DOMContentLoaded event fires. It uses event delegation extensively, attaching listeners to parent containers like #results-container to efficiently manage events for dynamically added content, such as timeline rows and tabs.
Sources: finder/static/finder/js/scripts.js:1, finder/static/finder/js/scripts.js:31, finder/static/finder/js/scripts.js:75
Key DOM Elements
The script interacts with several key elements defined in the HTML templates to achieve its functionality.
| Element ID / Class | File | Purpose |
|---|---|---|
#search-form | search.html | The main form for submitting room search criteria. Its submission is intercepted for an AJAX request. |
#results-container | search.html | A container where the dynamic timeline results, rendered by timeline_partial.html, are injected. |
#room-modal | search.html | The modal dialog container, hidden by default. |
#modal-body | search.html | The content area within the modal that is dynamically populated with room details. |
.timeline-row | timeline_partial.html (inferred) | Represents a single room in the timeline. Clicks on this element trigger the details modal. |
.tab-link | timeline_partial.html (inferred) | The buttons used to toggle between "Available" and "Unavailable" room lists. |
.close-button | search.html | The button inside the modal to close it. |
#rooms-drop-zone | upload_excel.html | The drag-and-drop area for the rooms Excel file. |
#timetable-drop-zone | upload_excel.html | The drag-and-drop area for the timetable Excel file. |
Sources: finder/static/finder/js/scripts.js, finder/templates/finder/search.html, finder/templates/finder/upload_excel.html
AJAX Search and Timeline Rendering
The core feature driven by scripts.js is the asynchronous search functionality. Instead of a traditional form submission that reloads the page, the script intercepts the submit event, sends the form data to the backend via an AJAX fetch request, and injects the resulting HTML into the page.
This diagram illustrates the AJAX search and rendering flow:
This flow is initiated by the event listener on the search form. The X-Requested-With: XMLHttpRequest header is crucial, as it signals the search_rooms view in views.py to return a partial HTML template instead of a full page render.
Sources: finder/static/finder/js/scripts.js:8-28, finder/views.py:100-101
Code Example: AJAX Form Submission
// finder/static/finder/js/scripts.js:9-24
searchForm.addEventListener('submit', function(e) {
e.preventDefault();
const formData = new FormData(searchForm);
fetch(searchForm.action, {
method: 'POST',
body: formData,
headers: {
'X-CSRFToken': formData.get('csrfmiddlewaretoken'),
'X-Requested-With': 'XMLHttpRequest'
}
})
.then(response => response.text())
.then(html => {
resultsContainer.innerHTML = html;
})
// ... error handling
});
Sources: finder/static/finder/js/scripts.js:9-24
Room Details Modal
When a user clicks on a room's timeline (.timeline-row), the script fetches detailed information for that specific room and displays it in a modal window.
Modal Interaction Flow
The process involves an API call to a dedicated endpoint that returns room data in JSON format.
The modal can be closed by clicking the close button or by clicking on the backdrop outside the modal content. This is handled by removing the .show class from the modal element, which is styled in CSS to be hidden.
Sources: finder/static/finder/js/scripts.js:31-72, finder/static/finder/css/styles.css:416-426, README.md
Code Example: Fetching and Populating Modal Data
// finder/static/finder/js/scripts.js:32-61
const timelineRow = e.target.closest('.timeline-row');
if (timelineRow) {
const roomId = timelineRow.dataset.roomId;
const day = document.getElementById('id_day').value;
fetch(`/api/room/${roomId}/?day=${day}`)
.then(response => response.json())
.then(data => {
modalBody.innerHTML = `
<h2>${data.room.name}</h2>
<p class="room-building">${data.room.building}</p>
<div class="room-details">
<p><strong>Capacity:</strong> ${data.room.capacity} seats</p>
<p><strong>Amenities:</strong> ${data.room.amenities.join(', ')}</p>
</div>
<h3 class="schedule-title">Schedule for ${day}</h3>
<ul class="schedule-list">
${data.timeline.map(block => `
<li class="schedule-item">
<span class="schedule-time">${block.start} - ${block.end}</span>
<span class="schedule-status ${block.type}">
${block.type === 'free' ? 'Free' : `Booked: ${block.course}`}
</span>
</li>
`).join('')}
</ul>
`;
modal.classList.add('show');
});
}
This snippet demonstrates how the script makes the API call, receives JSON, and constructs the HTML to populate the modal body before displaying it.
Sources: finder/static/finder/js/scripts.js:32-61
Client-Side UI Controls
scripts.js also manages UI interactions that do not require server communication.
Tab Toggling
After a search is performed, results are categorized into "Available" and "Unavailable" tabs. The script handles the logic for switching between these tabs purely on the client side.
This mechanism provides instant feedback to the user by showing and hiding the relevant content sections using CSS classes.
Sources: finder/static/finder/js/scripts.js:75-88, finder/static/finder/css/styles.css:292-295, finder/static/finder/css/styles.css:303-306
File Upload UI
On the /upload/ page, the script enhances the file input forms with drag-and-drop functionality. It listens for dragover, dragleave, and drop events on the drop zone elements. When a file is dropped or selected, the script updates the UI to show the selected file's name and adds a file-selected class for visual feedback.
Sources: finder/static/finder/js/scripts.js:115-156, finder/templates/finder/upload_excel.html:40-54
Summary
scripts.js is a vital component of the Room Finder application, acting as the orchestrator for all dynamic client-side functionality. It leverages modern JavaScript features like fetch and event delegation to create a fluid and interactive user experience. By handling AJAX search requests, managing the room details modal, and controlling UI elements like tabs, it effectively decouples the frontend presentation from the backend logic, resulting in a fast and modern web application.
Sources: finder/static/finder/js/scripts.js, README.md