Download webapp/static/js/ui-utils.js from itsluckysharma01/NETRA-A_Video_Surveillance_Web_Application: direct link, hf CLI and curl.
- Browser
- Download file 9.46 kB
-
https://huggingface.co/spaces/itsluckysharma01/NETRA-A_Video_Surveillance_Web_Application/resolve/main/webapp/static/js/ui-utils.js
- Command line
-
hf download hf://spaces/itsluckysharma01/NETRA-A_Video_Surveillance_Web_Application/webapp/static/js/ui-utils.js
-
curl -L -o ui-utils.js https://huggingface.co/spaces/itsluckysharma01/NETRA-A_Video_Surveillance_Web_Application/resolve/main/webapp/static/js/ui-utils.js
9.46 kB
| /** | |
| * NETRA UI Utilities | |
| * Enhanced interactivity and utility functions for frontend | |
| */ | |
| // Toast Notification System | |
| class Toast { | |
| constructor() { | |
| this.container = this.ensureContainer(); | |
| } | |
| ensureContainer() { | |
| let container = document.getElementById("toast-container"); | |
| if (!container) { | |
| container = document.createElement("div"); | |
| container.id = "toast-container"; | |
| document.body.appendChild(container); | |
| } | |
| return container; | |
| } | |
| show(message, type = "info", duration = 3000) { | |
| const toast = document.createElement("div"); | |
| toast.className = `toast ${type}`; | |
| toast.textContent = message; | |
| this.container.appendChild(toast); | |
| // Auto remove after duration | |
| setTimeout(() => { | |
| toast.style.animation = "slideInRight 0.3s ease reverse"; | |
| setTimeout(() => toast.remove(), 300); | |
| }, duration); | |
| return toast; | |
| } | |
| success(message, duration = 3000) { | |
| return this.show(message, "success", duration); | |
| } | |
| error(message, duration = 3000) { | |
| return this.show(message, "error", duration); | |
| } | |
| warning(message, duration = 3000) { | |
| return this.show(message, "warning", duration); | |
| } | |
| info(message, duration = 3000) { | |
| return this.show(message, "info", duration); | |
| } | |
| } | |
| // Modal Dialog System | |
| class Modal { | |
| constructor(title, content, options = {}) { | |
| this.title = title; | |
| this.content = content; | |
| this.options = { | |
| closeButton: true, | |
| footer: true, | |
| size: "medium", | |
| onConfirm: null, | |
| onCancel: null, | |
| ...options, | |
| }; | |
| this.element = null; | |
| this.overlay = null; | |
| } | |
| create() { | |
| // Create overlay | |
| this.overlay = document.createElement("div"); | |
| this.overlay.className = "modal-overlay"; | |
| // Create modal | |
| this.element = document.createElement("div"); | |
| this.element.className = `modal modal-${this.options.size}`; | |
| // Create header | |
| const header = document.createElement("div"); | |
| header.className = "modal-header"; | |
| header.innerHTML = `<h2 class="modal-title">${this.title}</h2>`; | |
| if (this.options.closeButton) { | |
| const closeBtn = document.createElement("button"); | |
| closeBtn.className = "modal-close"; | |
| closeBtn.innerHTML = "×"; | |
| closeBtn.onclick = () => this.close(); | |
| header.appendChild(closeBtn); | |
| } | |
| // Create body | |
| const body = document.createElement("div"); | |
| body.className = "modal-body"; | |
| if (typeof this.content === "string") { | |
| body.innerHTML = this.content; | |
| } else { | |
| body.appendChild(this.content); | |
| } | |
| // Create footer | |
| let footer = ""; | |
| if (this.options.footer) { | |
| footer = ` | |
| <div class="modal-footer"> | |
| <button class="btn btn-secondary" onclick="this.closest('.modal').parentElement.nextElementSibling.click()">Cancel</button> | |
| <button class="btn btn-primary" onclick="document.querySelector('.modal-confirm')?.click?.()">Confirm</button> | |
| </div> | |
| `; | |
| } | |
| this.element.appendChild(header); | |
| this.element.appendChild(body); | |
| if (footer) { | |
| this.element.innerHTML += footer; | |
| } | |
| this.overlay.appendChild(this.element); | |
| document.body.appendChild(this.overlay); | |
| // Setup click handler for overlay (close on outside click) | |
| this.overlay.addEventListener("click", (e) => { | |
| if (e.target === this.overlay) { | |
| this.close(); | |
| } | |
| }); | |
| return this; | |
| } | |
| show() { | |
| if (!this.element) this.create(); | |
| this.overlay.classList.add("open"); | |
| return this; | |
| } | |
| close() { | |
| if (this.overlay) { | |
| this.overlay.classList.remove("open"); | |
| setTimeout(() => { | |
| this.overlay?.remove(); | |
| this.element = null; | |
| this.overlay = null; | |
| }, 300); | |
| } | |
| return this; | |
| } | |
| static confirm(title, message, onConfirm, onCancel) { | |
| const modal = new Modal(title, `<p>${message}</p>`, { | |
| footer: true, | |
| onConfirm, | |
| onCancel, | |
| }); | |
| modal.show(); | |
| return modal; | |
| } | |
| static alert(title, message) { | |
| const modal = new Modal(title, `<p>${message}</p>`, { | |
| footer: false, | |
| }); | |
| modal.show(); | |
| return modal; | |
| } | |
| } | |
| // Loading State Manager | |
| class LoadingState { | |
| static setLoading(element, isLoading = true) { | |
| if (!element) return; | |
| if (isLoading) { | |
| element.classList.add("loading"); | |
| element.disabled = true; | |
| const originalText = element.textContent; | |
| element.setAttribute("data-original-text", originalText); | |
| element.innerHTML = `<span class="spinner"></span> Loading...`; | |
| } else { | |
| element.classList.remove("loading"); | |
| element.disabled = false; | |
| const originalText = | |
| element.getAttribute("data-original-text") || element.textContent; | |
| element.textContent = originalText; | |
| } | |
| } | |
| static setLoadingMultiple(elements, isLoading = true) { | |
| elements.forEach((el) => this.setLoading(el, isLoading)); | |
| } | |
| } | |
| // Form Validation | |
| class FormValidator { | |
| static validate(form) { | |
| const errors = {}; | |
| const inputs = form.querySelectorAll("input, textarea, select"); | |
| inputs.forEach((input) => { | |
| const error = this.validateInput(input); | |
| if (error) { | |
| errors[input.name] = error; | |
| } | |
| }); | |
| return { | |
| isValid: Object.keys(errors).length === 0, | |
| errors, | |
| }; | |
| } | |
| static validateInput(input) { | |
| if (input.hasAttribute("required") && !input.value.trim()) { | |
| return `${input.name || "This field"} is required`; | |
| } | |
| if (input.type === "email" && input.value) { | |
| const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; | |
| if (!emailRegex.test(input.value)) { | |
| return "Please enter a valid email address"; | |
| } | |
| } | |
| if (input.minLength && input.value.length < input.minLength) { | |
| return `Minimum length is ${input.minLength} characters`; | |
| } | |
| if (input.maxLength && input.value.length > input.maxLength) { | |
| return `Maximum length is ${input.maxLength} characters`; | |
| } | |
| return null; | |
| } | |
| static showErrors(form, errors) { | |
| // Clear previous errors | |
| form.querySelectorAll(".error-message").forEach((el) => el.remove()); | |
| Object.entries(errors).forEach(([name, message]) => { | |
| const input = form.querySelector(`[name="${name}"]`); | |
| if (input) { | |
| input.classList.add("error"); | |
| const errorEl = document.createElement("div"); | |
| errorEl.className = "error-message"; | |
| errorEl.textContent = message; | |
| input.parentNode.insertBefore(errorEl, input.nextSibling); | |
| } | |
| }); | |
| } | |
| static clearErrors(form) { | |
| form.querySelectorAll(".error-message").forEach((el) => el.remove()); | |
| form | |
| .querySelectorAll(".error") | |
| .forEach((el) => el.classList.remove("error")); | |
| } | |
| } | |
| // Scroll Animation Observer | |
| class ScrollAnimation { | |
| static init() { | |
| const observer = new IntersectionObserver( | |
| (entries) => { | |
| entries.forEach((entry) => { | |
| if (entry.isIntersecting) { | |
| entry.target.style.opacity = "1"; | |
| entry.target.style.transform = "translateY(0)"; | |
| observer.unobserve(entry.target); | |
| } | |
| }); | |
| }, | |
| { | |
| threshold: 0.1, | |
| rootMargin: "0px 0px -50px 0px", | |
| }, | |
| ); | |
| document.querySelectorAll(".reveal").forEach((el) => { | |
| el.style.opacity = "0"; | |
| el.style.transform = "translateY(20px)"; | |
| el.style.transition = "opacity 0.6s ease, transform 0.6s ease"; | |
| observer.observe(el); | |
| }); | |
| } | |
| } | |
| // Network Request Helper | |
| class ApiClient { | |
| static async request(url, options = {}) { | |
| const defaultOptions = { | |
| method: "GET", | |
| headers: { | |
| "Content-Type": "application/json", | |
| }, | |
| ...options, | |
| }; | |
| try { | |
| const response = await fetch(url, defaultOptions); | |
| if (!response.ok) { | |
| throw new Error(`HTTP error! status: ${response.status}`); | |
| } | |
| return await response.json(); | |
| } catch (error) { | |
| console.error("API request failed:", error); | |
| throw error; | |
| } | |
| } | |
| static get(url) { | |
| return this.request(url, { method: "GET" }); | |
| } | |
| static post(url, data) { | |
| return this.request(url, { | |
| method: "POST", | |
| body: JSON.stringify(data), | |
| }); | |
| } | |
| static put(url, data) { | |
| return this.request(url, { | |
| method: "PUT", | |
| body: JSON.stringify(data), | |
| }); | |
| } | |
| static delete(url) { | |
| return this.request(url, { method: "DELETE" }); | |
| } | |
| } | |
| // Page Transitions | |
| class PageTransition { | |
| static fadeOut(element, duration = 300) { | |
| return new Promise((resolve) => { | |
| element.style.opacity = "0"; | |
| element.style.transition = `opacity ${duration}ms ease`; | |
| setTimeout(resolve, duration); | |
| }); | |
| } | |
| static fadeIn(element, duration = 300) { | |
| return new Promise((resolve) => { | |
| element.style.opacity = "0"; | |
| setTimeout(() => { | |
| element.style.transition = `opacity ${duration}ms ease`; | |
| element.style.opacity = "1"; | |
| setTimeout(resolve, duration); | |
| }, 10); | |
| }); | |
| } | |
| } | |
| // Initialize utilities on DOM ready | |
| document.addEventListener("DOMContentLoaded", () => { | |
| ScrollAnimation.init(); | |
| }); | |
| // Export for use in other scripts | |
| window.Toast = Toast; | |
| window.Modal = Modal; | |
| window.LoadingState = LoadingState; | |
| window.FormValidator = FormValidator; | |
| window.ApiClient = ApiClient; | |
| window.PageTransition = PageTransition; | |
| // Create global toast instance | |
| window.toast = new Toast(); | |