1 2/** 3========================================================================= 4========================================================================= 5Template Name: Able Pro - Bootstrap Admin Template 6Author: Phoenixcoded 7Support: https://phoenixcoded.authordesk.app 8File: script.js 9Description: this file will contains behavior, properties, 10 functionality and interactions of a small module of ui element 11 which used to build a theme layout. 12========================================================================= 13========================================================================= 14*/ 15'use strict'; 16var flg = '0'; 17 18// Function to handle menu click events (collpase menus and it's submenu also collapse) 19function menu_click() { 20 // Remove click event listeners from navigation menu items 21 var elem = document.querySelectorAll('.pc-navbar li'); 22 for (var j = 0; j < elem.length; j++) { 23 elem[j].removeEventListener('click', function () {}); 24 } 25 26 // Hide submenu items (when menu link not active then submenu hide) 27 var elem = document.querySelectorAll('.pc-navbar li:not(.pc-trigger) .pc-submenu'); 28 for (var j = 0; j < elem.length; j++) { 29 elem[j].style.display = 'none'; 30 } 31 32 // Add click event listeners to main menu items (for first menu level collapse) 33 var pc_link_click = document.querySelectorAll('.pc-navbar > li:not(.pc-caption).pc-hasmenu'); 34 for (var i = 0; i < pc_link_click.length; i++) { 35 pc_link_click[i].addEventListener('click', function (event) { 36 // Prevent parent elements from triggering their events 37 event.stopPropagation(); 38 var targetElement = event.target; 39 if (targetElement.tagName == 'SPAN') { 40 targetElement = targetElement.parentNode; 41 } 42 // Toggle submenu visibility (active remove who has menu link not clicked and it's submenu also hide) 43 if (targetElement.parentNode.classList.contains('pc-trigger')) { 44 targetElement.parentNode.classList.remove('pc-trigger'); 45 slideUp(targetElement.parentNode.children[1], 200); 46 window.setTimeout(() => { 47 targetElement.parentNode.children[1].removeAttribute('style'); 48 targetElement.parentNode.children[1].style.display = 'none'; 49 }, 200); 50 } else { 51 // Close other open submenus 52 var tc = document.querySelectorAll('li.pc-trigger'); 53 for (var t = 0; t < tc.length; t++) { 54 var c = tc[t]; 55 c.classList.remove('pc-trigger'); 56 slideUp(c.children[1], 200); 57 window.setTimeout(() => { 58 c.children[1].removeAttribute('style'); 59 c.children[1].style.display = 'none'; 60 }, 200); 61 } 62 63 // Open clicked submenu (for active menu link) 64 targetElement.parentNode.classList.add('pc-trigger'); 65 var submenu_list = targetElement.children[1]; 66 if (submenu_list) { 67 slideDown(targetElement.parentNode.children[1], 200); 68 } 69 } 70 }); 71 } 72 73 // Initialize SimpleBar for navbar content if available 74 if (document.querySelector('.navbar-content')) { 75 new SimpleBar(document.querySelector('.navbar-content')); 76 } 77 78 // Add click event listeners to submenu items 79 var pc_sub_link_click = document.querySelectorAll('.pc-navbar > li:not(.pc-caption) li.pc-hasmenu'); 80 for (var i = 0; i < pc_sub_link_click.length; i++) { 81 pc_sub_link_click[i].addEventListener('click', function (event) { 82 var targetElement = event.target; 83 if (targetElement.tagName == 'SPAN') { 84 targetElement = targetElement.parentNode; 85 } 86 event.stopPropagation(); 87 // Toggle submenu visibility 88 if (targetElement.parentNode.classList.contains('pc-trigger')) { 89 targetElement.parentNode.classList.remove('pc-trigger'); 90 slideUp(targetElement.parentNode.children[1], 200); 91 } else { 92 // Close other open submenus 93 var tc = targetElement.parentNode.parentNode.children; 94 for (var t = 0; t < tc.length; t++) { 95 var c = tc[t]; 96 c.classList.remove('pc-trigger'); 97 if (c.tagName == 'LI') { 98 c = c.children[0]; 99 } 100 if (c.parentNode.classList.contains('pc-hasmenu')) { 101 slideUp(c.parentNode.children[1], 200); 102 } 103 } 104 105 // Open clicked submenu 106 targetElement.parentNode.classList.add('pc-trigger'); 107 var submenu_list = targetElement.parentNode.children[1]; 108 if (submenu_list) { 109 submenu_list.removeAttribute('style'); 110 slideDown(submenu_list, 200); 111 } 112 } 113 }); 114 } 115} 116 117// Initialize menu click function on DOMContentLoaded (function call on page load
117) 118document.addEventListener('DOMContentLoaded', menu_click); 119 120// Initialize various components on DOMContentLoaded 121document.addEventListener('DOMContentLoaded', function () { 122 // feather icon start 123 feather.replace(); 124 // feather icon end 125 126 // Check for specific layout and add scrollbar if necessary(add scrollbar from 1024 screen size in horizontal layout) 127 if (document.querySelector('body').hasAttribute('data-pc-layout')) { 128 if (document.querySelector('body').getAttribute('data-pc-layout') == 'horizontal') { 129 var docW = window.innerWidth; 130 if (docW <= 1024) { 131 add_scroller(); 132 } 133 } 134 } else { 135 add_scroller(); 136 } 137 138 // Menu collapse click start (when click it's open and close sidebar for mobile screen) 139 var mobile_collapse_over = document.querySelector('#mobile-collapse'); 140 if (mobile_collapse_over) { 141 mobile_collapse_over.addEventListener('click', function () { 142 var mobile_sidebar = document.querySelector('.pc-sidebar'); 143 if (mobile_sidebar) { 144 if (document.querySelector('.pc-sidebar').classList.contains('mob-sidebar-active')) { 145 rm_menu(); 146 } else { 147 document.querySelector('.pc-sidebar').classList.add('mob-sidebar-active'); 148 // add overlay when sidebar open 149 document.querySelector('.pc-sidebar').insertAdjacentHTML('beforeend', '<div class="pc-menu-overlay"></div>'); 150 document.querySelector('.pc-menu-overlay').addEventListener('click', function () { 151 rm_menu(); 152 }); 153 } 154 } 155 }); 156 } 157 // Menu collapse click end 158 159 // header dropdown scrollbar start 160 if (document.querySelector('.header-notification-scroll')) { 161 new SimpleBar(document.querySelector('.header-notification-scroll')); 162 } 163 164 if (document.querySelector('.profile-notification-scroll')) { 165 new SimpleBar(document.querySelector('.profile-notification-scroll')); 166 } 167 // header dropdown scrollbar end 168 169 // component scrollbar start 170 if (document.querySelector('.component-list-card .card-body')) { 171 new SimpleBar(document.querySelector('.component-list-card .card-body')); 172 } 173 // component- dropdown scrollbar end 174 175 // for sidebar close 176 var sidebar_hide = document.querySelector('#sidebar-hide'); 177 if (sidebar_hide) { 178 sidebar_hide.addEventListener('click', function () { 179 if (document.querySelector('.pc-sidebar').classList.contains('pc-sidebar-hide')) { 180 document.querySelector('.pc-sidebar').classList.remove('pc-sidebar-hide'); 181 } else { 182 document.querySelector('.pc-sidebar').classList.add('pc-sidebar-hide'); 183 } 184 }); 185 } 186 187 // for input focus add when click search icon 188 if (document.querySelector('.trig-drp-search')) { 189 const search_drp = document.querySelector('.trig-drp-search'); 190 search_drp.addEventListener('shown.bs.dropdown', (event) => { 191 document.querySelector('.drp-search input').focus(); 192 }); 193 } 194 195 // layout options (when click customizer layout options according to that set value in local storage) 196 setLayout(); 197 var if_layout = document.querySelectorAll('.theme-main-layout'); 198 var layoutValue = 'vertical'; 199 if (if_layout) { 200 var preset_layout = document.querySelectorAll('.theme-main-layout > a'); 201 preset_layout.forEach(function (element) { 202 element.addEventListener('click', function () { 203 // Reload the page after setting the layout for the first time to sync in all open tabs 204 location.reload(); 205 206 document.querySelectorAll('.theme-main-layout > a').forEach(function (el) { 207 el.classList.remove('active'); 208 }); 209 this.classList.add('active'); 210 if (this.getAttribute('data-value') == 'horizontal') { 211 layoutValue = 'horizontal'; 212 } else if (this.getAttribute('data-value') == 'compact') { 213 layoutValue = 'compact'; 214 } else if (this.getAttribute('data-value') == 'tab') { 215 layoutValue = 'tab'; 216 } else if (this.getAttribute('data-value') == 'color-header') { 217 layoutValue = 'color-header'; 218 } else { 219 layoutValue = 'vertical'; 220 } 221 222 // Set data to localStorage 223 localStorage.setItem('layout', layoutValue); 224 225 setLayout(); 226 }); 227 }); 228 } 229}); 230 231// Function to set the layout based on data stored in localStorage 232function setLayout() { 233 var layout = localStorage.getItem('layout'); // Retrieve layout data from localStorage 234 235 // Pass the layout value to main_layout_change function 236 main_layout_change(layout); 237 238 // Load corresponding scripts or perform actions based on the layout value 239 if (layout !== null && layout !== '') { 240 var script = document.createElement('script'); 241 if (layout === 'horizontal') { 242 document.querySelector('.pc-sidebar').classList.add('d-none'); 243 script.src = '../assets/js/layout-horizontal.js'; // Load script for horizontal layout 244 document.body.appendChild(script); 245 } else if (layout === 'color-header') { 246 // Change logo color for color-header layout 247 if (document.querySelector('.pc-sidebar .m-header .logo-lg')) { 248 document.querySelector('.pc-sidebar .m-header .logo-lg').setAttribute('src', '../assets/images/logo-white.svg'); 249 } 250 } else if (layout === 'compact') { 251 script.src = '../assets/js/layout-compact.js'; // Load script for compact layout 252 document.body.appendChild(script); 253 } else if (layout === 'tab') { 254 script.src = '../assets/js/layout-tab.js'; // Load script for tab layout 255 document.body.appendChild(script); 256 } 257 } 258 259 // If no layout data found in localStorage, set default layout to 'vertical' 260 if (layout === null) { 261 main_layout_change('vertical'); 262 localStorage.setItem('layout', 'vertical'); 263 } 264} 265 266// Function to handle menu click and scrollbar initialization 267function add_scroller() { 268 menu_click(); // Call menu_click function 269 // Initialize scrollbar if navbar-content exists 270 if (document.querySelector('.navbar-content')) { 271 new SimpleBar(document.querySelector('.navbar-content')); 272 } 273} 274 275// Function to hide mobile menu (sidebar hide on click overlay) 276function rm_menu() { 277 // Remove active class from mobile menu elements 278 var menu_list = document.querySelector('.pc-sidebar'); 279 if (menu_list) { 280 document.querySelector('.pc-sidebar').classList.remove('mob-sidebar-active'); 281 } 282 if (document.querySelector('.topbar')) { 283 document.querySelector('.topbar').classList.remove('mob-sidebar-active'); 284 } 285 286 // Remove menu overlay elements 287 document.querySelector('.pc-sidebar .pc-menu-overlay').remove(); 288 if (document.querySelector('.topbar .pc-menu-overlay')) { 289 document.querySelector('.topbar .pc-menu-overlay').remove(); 290 } 291} 292 293// Function to remove overlay menu 294function remove_overlay_menu() { 295 // Remove active class and overlay elements 296 document.querySelector('.pc-sidebar').classList.remove('pc-over-menu
296-active'); 297 if (document.querySelector('.topbar')) { 298 document.querySelector('.topbar').classList.remove('mob-sidebar-active'); 299 } 300 document.querySelector('.pc-sidebar .pc-menu-overlay').remove(); 301 document.querySelector('.topbar .pc-menu-overlay').remove(); 302} 303 304// Event listener to initialize tooltips, popovers, and toasts on window load 305window.addEventListener('load', function () { 306 // Initialize tooltips 307 var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]')); 308 var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) { 309 return new bootstrap.Tooltip(tooltipTriggerEl); 310 }); 311 312 // Initialize popovers 313 var popoverTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]')); 314 var popoverList = popoverTriggerList.map(function (popoverTriggerEl) { 315 return new bootstrap.Popover(popoverTriggerEl); 316 }); 317 318 // Initialize toasts 319 var toastElList = [].slice.call(document.querySelectorAll('.toast')); 320 var toastList = toastElList.map(function (toastEl) { 321 return new bootstrap.Toast(toastEl); 322 }); 323 324 // Remove pre-loader after page load 325 var loader = document.querySelector('.loader-bg'); 326 if (loader) { 327 loader.remove(); 328 } 329}); 330 331// Function to mark active menu items based on current page URL 332var elem = document.querySelectorAll('.pc-sidebar .pc-navbar a'); 333for (var l = 0; l < elem.length; l++) { 334 // Check if current URL matches menu item URL 335 var pageUrl = window.location.href.split(/[?#]/)[0]; 336 if (elem[l].href == pageUrl && elem[l].getAttribute('href') != '') { 337 // Add active class to matching menu item and its parent elements 338 elem[l].parentNode.classList.add('active'); 339 elem[l].parentNode.parentNode.parentNode.classList.add('pc-trigger'); 340 elem[l].parentNode.parentNode.parentNode.classList.add('active'); 341 elem[l].parentNode.parentNode.style.display = 'block'; 342 elem[l].parentNode.parentNode.parentNode.parentNode.parentNode.classList.add('pc-trigger'); 343 elem[l].parentNode.parentNode.parentNode.parentNode.style.display = 'block'; 344 } 345} 346 347// Event listener to handle like events (added to favourites) 348// Select all checkboxes inside elements with the 'prod-likes' class 349var tc = document.querySelectorAll('.prod-likes .form-check-input'); 350 351// Loop through each like checkbox 352for (var t = 0; t < tc.length; t++) { 353 var prod_like = tc[t]; // Assign current checkbox to prod_like variable 354 355 // Add event listener to detect changes on the checkbox (checked or unchecked) 356 prod_like.addEventListener('change', function (event) { 357 var currentCheckbox = event.currentTarget; // The checkbox that triggered the event 358 359 if (currentCheckbox.checked) { 360 // If checkbox is checked (i.e., user liked the product) 361 362 // Create and insert the like animation HTML into the DOM 363 currentCheckbox.parentNode.insertAdjacentHTML( 364 'beforeend', 365 '<div class="pc-like">' + 366 '<div class="like-wrapper">' + 367 '<span>' + 368 '<span class="pc-group">' + 369 '<span class="pc-dots"></span>' + 370 '<span class="pc-dots"></span>' + 371 '<span class="pc-dots"></span>' + 372 '<span class="pc-dots"></span>' + 373 '</span>' + 374 '</span>' + 375 '</div>' + 376 '</div>' 377 ); 378 379 // Add animation class to trigger CSS-based animations 380 currentCheckbox.parentNode.querySelector('.pc-like').classList.add('pc-like-animate'); 381 382 // Remove the like animation after 3 seconds to clean up 383 setTimeout(function () { 384 try { 385 currentCheckbox.parentNode.querySelector('.pc-like').remove(); 386 } catch (error) { 387 console.error("Error removing like animation:", error); 388 } 389 }, 3000); 390 391 } else { 392 // If checkbox is unchecked (i.e., user unliked the product) 393 394 // Try to remove the like animation immediately 395 try { 396 currentCheckbox.parentNode.querySelector('.pc-like').remove(); 397 } catch (error) { 398 console.error("Error removing like animation:", error); 399 } 400 } 401 }); 402} 403 404 405// Change authentication logo 406var tc = document.querySelectorAll('.auth-main.v2 .img-brand'); 407for (var t = 0; t < tc.length; t++) { 408 tc[t].setAttribute('src', '../assets/images/logo-white.svg'); 409} 410 411// Functions to handle main layout change (active class add/remove from theme-main-layout according to click) 412function main_layout_change(value) { 413 // Set attribute based on value and update active main layout link 414 document.getElementsByTagName('body')[0].setAttribute('data-pc-layout', value); 415 var control = document.querySelector('.pct-offcanvas'); 416 if (control) { 417 var activeLink = document.querySelector('.theme-main-layout > a.active'); 418 if (activeLink) { 419 activeLink.classList.remove('active'); 420 } 421 var newActiveLink = document.querySelector(".theme-main-layout > a[data-value='" + value + "']"); 422 if (newActiveLink) { 423 newActiveLink.classList.add('active'); 424 } 425 } 426} 427 428 429// Function to remove CSS classes with a given prefix from a DOM node 430function removeClassByPrefix(node, prefix) { 431 // Iterate over class list and remove classes with the specified prefix 432 for (let i = 0; i < node.classList.length; i++) { 433 let value = node.classList[i]; 434 if (value.startsWith(prefix)) { 435 node.classList.remove(value); 436 } 437 } 438} 439 440// Functions for sliding up, sliding down, and toggling visibility of elements 441let slideUp = (target, duration = 0) => { 442 // Slide up animation implementation 443 target.style.transitionProperty = 'height, margin, padding'; 444 target.style.transitionDuration = duration + 'ms'; 445 target.style.boxSizing = 'border-box'; 446 target.style.height = target.offsetHeight + 'px'; 447 target.offsetHeight; 448 target.style.overflow = 'hidden'; 449 target.style.height = 0; 450 target.style.paddingTop = 0; 451 target.style.paddingBottom = 0; 452 target.style.marginTop = 0; 453 target.style.marginBottom = 0; 454}; 455 456let slideDown = (target, duration = 0) => { 457 // Slide down animation implementation 458 target.style.removeProperty('display'); 459 let display = window.getComputedStyle(target).display; 460 461 if (display === 'none') display = 'block'; 462 463 target.style.display = display; 464 let height = target.offsetHeight; 465 target.style.overflow = 'hidden'; 466 target.style.height = 0; 467 target.style.paddingTop = 0; 468 target.style.paddingBottom = 0; 469 target.style.marginTop = 0; 470 target.style.marginBottom = 0; 471 target.offsetHeight; 472 target.style.boxSizing = 'border-box'; 473 target.style.transitionProperty = 'height, margin, padding'; 474 target.style.transitionDuration = duration + 'ms'; 475 target.style.height = height + 'px'; 476 target.style.removeProperty('padding-top'); 477 target.style.removeProperty('padding-bottom'); 478 target.style.removeProperty('margin-top'); 479 target.style.removeProperty('margin-bottom'); 480 window.setTimeout(() => { 481 target.style.removeProperty('height'); 482 target.style.removeProperty('overflow'); 483 target.style.removeProperty('transition-duration'); 484 target.style.removeProperty('transition-property'); 485 }, duration); 486}; 487 488var slideToggle = (target, duration = 0) => { 489 // Slide toggle animation implementation 490 if (window.getComputedStyle(target).display === 'none') { 491 return slideDown(target, duration); 492 } else { 493 return slideUp(target, duration); 494 } 495}; 496 497// ======================================================= 498// =======================================================
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.