Customizing JavaScript Behavior
Relevant source files
The following files were used as context for generating this wiki page:The Vandore Heritage website employs client-side JavaScript to create a dynamic and interactive user experience. The scripts, primarily written using jQuery, handle three main areas of functionality: a sophisticated property filtering system, asynchronous form submissions with validation, and general UI enhancements like animations and dynamic content display. These behaviors are managed across several dedicated script files, which are included in the relevant HTML pages.
The core logic is encapsulated in js/custom.js for property filtering, js/submit-form.js for contact and subscription forms, and js/script.js for global UI effects. These scripts interact with specific HTML structures and CSS classes defined in pages like properties.html and contact.html to manipulate the DOM and respond to user actions.
Property Filtering System
The property listing page (properties.html) features a client-side filtering system that allows users to narrow down properties based on location, price, and number of bedrooms without a page reload. The entire logic is self-contained on the client and operates on data attributes embedded within the HTML of the property cards.
Sources: js/custom.js, properties.html
Architecture and Data Flow
The filtering mechanism relies on data-* attributes on each property card element within the #property-grid. When a user applies filters, the script iterates through each property, checking if its data attributes match the selected filter criteria. Properties that do not match are hidden, and a count of visible properties is updated. Active filters are also displayed as "chips" that can be clicked to remove the filter.
This diagram illustrates the user interaction flow for filtering properties.
Sources: js/custom.js:1-125, properties.html:268-450
Key Components and Attributes
The system is composed of several interconnected HTML elements and JavaScript functions.
| Component | Element Selector / ID | Description | Source Files |
|---|---|---|---|
| Filter Bar (Desktop) | .filter-bar.d-none.d-lg-block | The main filter interface for large screens. Contains inputs for location, price, and bedrooms. | properties.html:245-281 |
| Filter Drawer (Mobile) | #filter-drawer | An offcanvas element providing the same filter controls for mobile devices. | properties.html:215-243 |
| Property Grid | #property-grid | The container for all property card elements. | properties.html:287 |
| Property Card | .col[data-location] | Individual property listings. Filtering logic depends on its data-* attributes. | properties.html:288-450 |
| Filter Chips | #filter-chips | A <span> where small "chip" elements are dynamically added to show active filters. | properties.html:285, js/custom.js:82-106 |
| Property Count | #property-count | Displays the number of currently visible properties. | properties.html:286, js/custom.js:77 |
| Empty State | #empty-state | A message that is shown when no properties match the current filters. | properties.html:451-455, js/custom.js:73-76 |
The filtering logic hinges on these data-* attributes within each property card:
data-location: A string for location-based text search.data-price: A number representing the property price.data-bedrooms: A number for the bedroom count.
Sources: properties.html:288, 311, 334, js/custom.js:48-69
Form Submission Handling
The website uses js/submit-form.js to manage submissions for the contact form and newsletter subscription forms. It intercepts the default form submission, performs client-side validation, and provides immediate user feedback through toast messages, all without a page reload.
Sources: js/submit-form.js, contact.html:247-283, about.html:309-328
Submission Sequence
The script attaches a submit event listener to any element with the class .form. It distinguishes between a contact form and a newsletter subscription based on a hidden input field (<input type="text" name="action" value="subscribe" hidden>).
This sequence diagram shows the process for submitting the contact form.
Sources: js/submit-form.js:2-51, contact.html:247-283
Form Types and Validation
The script handles two types of forms, identified by the action field.
| Form Type | action value | Key Fields | Validation | Success UI |
|---|---|---|---|---|
| Newsletter | subscribe | email | isValidEmail() helper function checks regex. | showToast('.success_msg_subscribe') |
| Contact | (not present) | name, email, message | checkValidity() and isValidEmail(). | .success_msg element is shown. |
The isValidEmail function uses a simple regex to validate the email format. For the contact form, it relies on the browser's built-in validation for required attributes, triggered by checkValidity().
Sources: js/submit-form.js:20-42, 54-57, about.html:310, contact.html:260-275
General UI Enhancements
The js/script.js file contains a collection of jQuery-based scripts that provide sitewide UI improvements, such as scroll-based animations and interactive components.
Sources: js/script.js
Key Features
| Feature | Description | Trigger | Target Elements |
|---|---|---|---|
| Header Glass Effect | Adds the .glass-effect class to the header when the user scrolls more than 100 pixels down the page. | window.on('scroll') | #header |
| Tab Switching | A generic component for switching between content panes by clicking tab buttons. | click on .tab | .tabs and .tab-content |
| Marquee Effect | Creates an infinite scrolling effect by cloning the content of a container multiple times. | Page load | .marquee-container |
| Number Animation | Animates numbers counting up from 0 to a target value when the element scrolls into the viewport. | window.on('scroll') via checkScroll() | .number[data-target] |
| Localization Audit | On page load, this script audits text nodes for data-i18n attributes and hides any elements that appear to be language switchers. | DOMContentLoaded | Various text nodes and potential language switchers. |
Sources: js/script.js:4-104
Number Animation on Scroll
A notable feature is the number animation. The checkScroll function is called on page load and on every scroll event. It checks if elements with the .number class are within the viewport. If an element is visible and hasn't been animated yet, the animateNumber function is called.
The animateNumber function uses requestAnimationFrame to smoothly increment the number from 0 to its target value (defined in data-target) over a specified duration (from data-duration).
// Source: js/script.js:80-96
function animateNumber(element, targetNumber, duration) {
const startTime = performance.now();
const startNumber = 0;
function updateNumber(currentTime) {
const elapsedTime = currentTime - startTime;
const progress = Math.min(elapsedTime / duration, 1);
const currentNumber = Math.floor(startNumber + progress * (targetNumber - startNumber));
element.innerText = formatNumber(currentNumber);
if (progress < 1) {
requestAnimationFrame(updateNumber);
}
}
requestAnimationFrame(updateNumber);
}
This implementation ensures a smooth, performant animation that only runs when the content is visible to the user.
Sources: js/script.js:80-101