1(function ($) { 2 $(document).ready(function () { 3 4 var dependencies = [ 5 { 6 module: "header", 7 dependencies: ["attachDetach", "overlay", "perfectScrollbar"] 8 }, 9 { 10 module: "menu", 11 dependencies: ["perfectScrollbar"] 12 } 13 ]; 14 15 var themeSettings = { 16 17 // global settings 18 19 productQuantity: { 20 quantityInputSelector: '.qty-input', 21 incrementSelectors: '.increase', 22 decrementSelectors: '.decrease' 23 }, 24 25 // responsive settings 26 27 responsive: [ 28 { 29 breakpoint: 1025, 30 settings: { 31 header: { 32 activeClass: 'active', 33 modules: [ 34 { 35 opener: '.responsive-nav-wrapper .menu-button', 36 closer: '.close-menu', 37 content: '.header-menu', 38 scrollbar: false, 39 overlay: true, 40 disablePageScroll: true 41 }, 42 { 43 opener: '.responsive-nav-wrapper .personal-button', 44 closer: '.close-links', 45 content: '.header-links-wrapper', 46 overlay: true, 47 disablePageScroll: true, 48 }, 49 { 50 opener: '.responsive-nav-wrapper .search-button', 51 closer: '.close-search', 52 content: '.store-search-box', 53 overlay: true, 54 disablePageScroll: true, 55 }, 56 { 57 opener: '.filter-button', 58 closer: '.close-filters', 59 content: '.nopAjaxFilters7Spikes', 60 scrollbar: false, 61 overlay: true, 62 disablePageScroll: true 63 } 64 ] 65 }, 66 filters: { 67 closePanelAfterFiltrationDataAttribute: 'closefilterspanelafterfiltrationinmobile' 68 }, 69 overlay: { 70 overlayElementSelector: '.overlayOffCanvas', 71 overlayClass: 'active', 72 noPageScrollClass: 'scrollYRemove' 73 }, 74 toggle: { 75 blocks: [ 76 { 77 opener: '.block:not(.filter-block) .title', 78 content: '.block:not(.filter-block) .listbox', 79 activeClassOpener: 'opened', 80 animation: { 81 type: 'slide', 82 speed: 'slow' 83 } 84 }, 85 { 86 opener: '.footer-block .title', 87 content: '.footer-block .list', 88 activeClassOpener: 'opened', 89 animation: { 90 type: 'slide', 91 speed: 'slow' 92 } 93 } 94 ] 95 }, 96 equalizer: { 97 blocks: [ 98 { 99 selector: '.cart td.product' 100 } 101 ] 102 } 103 } 104 } 105 ] 106 }; 107 108 var theme = new window.sevenSpikesTheme(themeSettings, dependencies, false); 109
110 theme.init(); 111 112 // invoke custom functions 113 114 handleMobileNavigation(); 115 updateMobileCartQuantity(); 116 handleMenuCategoryItems(); 117 setMenuDropdownPosition(); 118 closePopupOnOverlayClick(); 119 handleProductOverview(); 120 handleProductReviewForm(); 121 applyAdditionalClasses(); 122 handleShoppingCartTable(); 123 clearShoppingCartButton(); 124 handleCheckoutMethods(); 125 126 127 128 // C U S T O M F U N C T I O N S 129 130 131 132 // Set up class names when the navigation panel sticks at the top of the screen, and when the page is scrolled up. 133 134 function handleMobileNavigation() { 135 136 var targetElement = $('.responsive-nav-wrapper'); 137 var demoStrip = $('.header-storetheme'); 138 var lastScrollTop = 0; 139 140 var queryElement = document.querySelector('.responsive-nav-wrapper'); 141 var observer = new IntersectionObserver( 142 ([e]) => e.target.classList.toggle('pinned', e.intersectionRatio < 1), 143 { threshold: [1] } 144 ); 145 observer.observe(queryElement); // detect when sticky element sticks 146 147 if ($(window).outerWidth() >= themeSettings['responsive'][0]['breakpoint']) { 148 setTimeout(function () { 149 targetElement.removeClass('pinned'); 150 }, 100); // set delay, or the class will be added again 151 } 152 $(document).on('themeBreakpoint', function (event, settings, breakpoint) { 153 if (breakpoint !== null) { 154 targetElement.addClass('pinned up'); // mobile 155 } 156 else { 157 targetElement.removeClass('pinned up'); // desktop 158 } 159 }); 160 $(window).on('scroll', function () { 161 162 var scrollTop = $(this).scrollTop(); 163 164 if (scrollTop > lastScrollTop) { 165 targetElement.removeClass('up demo'); // scroll down 166 } 167 else { 168 targetElement.addClass('up'); // scroll up 169 170 if (demoStrip.length > 0) { 171 targetElement.addClass('demo'); // nop-templates demo strip 172 } 173 } 174 lastScrollTop = scrollTop; 175 }); 176 } 177 178 179 180 // Update the "mobile" quantity marker when a product is removed from the flyout cart on desktop. It uses the "desktop" marker which is updated by the core script. 181 182 function updateMobileCartQuantity() { 183 184 $(document).on('removeItemFlyoutCart', function () { 185 186 var productsCountElement = $('.cart-link .cart-qty'); // desktop 187 var mobileQtyElement = $('.cart-button .cart-qty'); // mobile 188 189 if (productsCountElement.length && mobileQtyElement.length) { 190 191 var regex = /\d+/; 192 var productsCountString = productsCountElement.text(); 193 var productsCount = productsCountString.match(regex) || [0]; 194 195 mobileQtyElement.text(productsCount[0]); 196 } 197 }); 198 } 199 200 201 202 // Clone all category menu items and move them into a separate menu. This can't be done in the source code because of widget zone duplication. 203 204 function handleMenuCategoryItems() { 205 206 if ($('.header-menu .nav-panel.modified').length > 0) { 207 208 var targetElement = $('.header-menu .drop-menu .sublist'); 209 var rootCategoryItems = $('.top-menu .root-category, .mega-menu .root-category'); // exclude mega-menu-responsive 210 211 rootCategoryItems.clone(true).appendTo(targetElement); 212 } 213 if (!$('.header-menu .mega-menu').length > 0) { 214 $('.header-menu .drop-menu').addClass('default'); 215 } 216 } 217 218 219 220 // Dynamic offset for Mega Menu dropdown (grid) panels, depending on the space between the top-level menu item and the beginning of the menu. 221 222 function setMenuDropdownPosition() { 223 224 var rootMenuItem = $('.mega-menu > li'); 225 var contentDirection = $('html').attr('dir'); 226 var calculateOffset; 227 228 rootMenuItem.on('mouseenter', function () { 229 230 if (contentDirection == 'rtl') { 231 calculateOffset = ($(this).parent().width() - $(this).position().left - $(this).width()) / 2 * -1; 232 $(this).children('.dropdown').css('right', calculateOffset); 233 } 234 else { 235 calculateOffset = $(this).position().left / 2 * -1; 236 $(this).children('.dropdown').css('left', calculateOffset); 237 } 238 }); 239 } 240 241 242 243 // Workaround for closing "ui-dialog" popups from their screen overlay (as the overlay is a pseudo element, it can't be targeted with JS). 244 245 function closePopupOnOverlayClick() { 246 247 $(document).mousedown(function (e) { 248 // detect left click ("1" = left click, "2" = middle click, "3" = right click) 249 if (e.which == 1) { 250 // "stopPropagation" will deactivate the "Close" button, so "target" is used instead 251 if (!$(e.target).closest('.ui-dialog-titlebar, .ui-dialog-content').length > 0) { 252 $('.ui-dialog-titlebar-close').click(); 253 } 254 } 255 }); 256 } 257 258 259 260 // Set up additional class names on Product Details pages. Set up down-scrolling for associated (grouped) products. 261 262 function handleProductOverview() { 263
264 $('.overview.primary').children().last().addClass('last'); 265 266 var handleQuantityAttributes = function () { 267 $('.attributes .qty-box').siblings('select').addClass('qty-select'); 268 }; 269 handleQuantityAttributes(); 270 $(document).on('nopAjaxCartMiniProductDetailsViewShown', handleQuantityAttributes); 271 272 $('.variant-scroll-button').on('click', function () { 273 $('html, body').animate({ 274 scrollTop: $('.product-variant-list').offset().top - 30 275 }, 1000); 276 }); 277 } 278 279 280 281 // Handle Product Reviews form. Closed by default and opened either on button click or on error message present. 282 283 function handleProductReviewForm() { 284 285 var triggerElement = $('.write-review .trigger'); 286 var targetElement = $('.write-review .fieldset, .ui-tabs .write-review .form-fields'); 287 288 $('a[href="#addreview"]').on('click', function () { 289 triggerElement.hide(); 290 targetElement.slideDown(); 291 }); 292 triggerElement.on('click', function () { 293 triggerElement.hide(); 294 targetElement.slideDown(); 295 }); 296 if ($('.write-review .message-error, .write-review .field-validation-error').length > 0) { 297 triggerElement.hide(); 298 targetElement.slideDown(); 299 } 300 // Quick Tabs elements 301 if (!$('.ui-tabs .product-review-list').length > 0) { 302 $('.ui-tabs').find(triggerElement).click(); 303 } 304 $(document).on('quickTabsRefreshedTab quickTabsLoadedTab', function () { 305 var newTriggerElement = $('.write-review .trigger'); 306 var newTargetElement = $('.write-review .form-fields'); 307 308 newTriggerElement.on('click', function () { 309 newTriggerElement.hide(); 310 newTargetElement.slideDown(); 311 }); 312 if (!$('.ui-tabs .product-review-list').length > 0) { 313 $('.ui-tabs').find(newTriggerElement).click(); 314 } 315 if ($('.write-review .message-error, .write-review .field-validation-error').length > 0) { 316 newTriggerElement.hide(); 317 newTargetElement.slideDown(); 318 319 $('html, body').animate({ 320 scrollTop: newTargetElement.offset().top - 50 321 }, 500); 322 } 323 }); 324 } 325 326 327 328 // Set up additional class names for Featured Categories, Product Filters, Account pages, Cart Collaterals, Checkout Adresses, Profile page, and Private Messages. 329 330 function applyAdditionalClasses() { 331 332 var categoryItemBox = $('.home-page-category-grid .category-item'); 333 categoryItemBox.each(function () { 334 if ($(this).find('.sub-category-list').length > 0) { 335 $(this).addClass('tree'); 336 } 337 }); // distinguish featured categories with and without subcategories 338 339 $('.block.product-filters').removeClass('block').children().addClass('block').find('.filter-title').addClass('title'); 340 341 $('.password-recovery-page form, .account-page, .return-request-page, .user-agreement-page').find('.buttons, .add-button').addClass('account-buttons'); 342 $('.password-recovery-page form, .account-page, .return-request-page, .user-agreement-page').find('.button-1').addClass('account-button'); 343 344 var cartCollaterals = $('.cart-collaterals'); 345 if (cartCollaterals.children().length == 0) { cartCollaterals.addClass('empty'); 346 } // :empty pseudo class doesn't work for empty elements with white space inside, so using JS instead 347 348 $('.checkout-page .address-list-page').addClass('edit-buttons').removeClass('address-list-page'); 349 350 $('.profile-page .latest-posts').find('.quote').prev().addClass('poster'); 351 $('.private-messages col:last-child').addClass('date').removeAttr('width'); 352 } 353 354 355 356 // Handle responsive Shopping Cart tables on mobile resolutions ("add-to-cart" checkboxes, cell footer, and cell height). 357 358 function handleShoppingCartTable() { 359 360 // modify add-to-cart checkboxes and labels to work like buttons 361 362 $('.cart .add-to-cart label').on('click', function () { 363 // detect if label text is visible or not, it's only visible on mobile resolutions 364 if ($(this).width() > 30) { 365 $(this).siblings('input').attr('checked', true); 366 $('#addproduct').click(); 367 } 368 });
369 // constant height of cell footers depending on the number of elements present 370 var subtotalTableCell = $('.cart td.subtotal'); 371 372 subtotalTableCell.each(function () { 373 if ($(this).children('.discount').length > 0) { 374 $(this).siblings('.unit-price').addClass('hide'); 375 } 376 }); 377 } 378 379 380 381 // This activates the custom "Clear Shopping Cart" button on Shopping Cart page (it's an emulation of the "Update Cart" functionality). 382 383 function clearShoppingCartButton() { 384 385 $('.cart-buttons .clear-cart-button').on('click', function (e) { 386 e.preventDefault(); 387 $('.cart [name="removefromcart"]').attr('checked', 'checked'); 388 $('.cart-buttons .update-cart-button').click(); 389 }); 390 } 391 392 393 394 // Detect currently active shipping/payment method and apply custom behavior. Modify class names for consistency. 395 396 function handleCheckoutMethods() { 397 398 var targetElement = $('.method-list li'); 399 400 targetElement.each(function () { 401 if ($(this).find('input').is(':checked')) { 402 $(this).addClass('selected'); 403 } 404 }); 405 targetElement.on('click', function () { 406 $(this).find('input').prop('checked', true); 407 $(this).addClass('selected').siblings('').removeClass('selected'); 408 }); 409 410 $('.method-list .payment-description').toggleClass('payment-description method-description'); 411 412 if ($('.payment-info td').length > 1) { 413 $('.payment-info tr').addClass('inputs'); 414 } 415 } 416 417 418 419 // Trigger additional event on OPC step load. Use the event to apply script to OPC (html markup is not loaded until step load). 420 421 if (window.Checkout) { // check if OPC is present 422 423 var setStepResponse = Checkout.setStepResponse; 424 Checkout.setStepResponse = function (response) { 425 setStepResponse(response); 426 $(document).trigger("opcStepLoad"); 427 }; 428 429 $('#edit-billing-address-button').addClass('edit-address-button'); 430 431 $(document).on("opcStepLoad", function () { 432 $('#edit-shipping-address-button').addClass('edit-address-button'); 433 handleCheckoutMethods(); 434 }); 435 } 436 // Re-apply additional checkout class names on ROPC panel load and on Payment Method refresh (otherwise they won't work in ROPC) 437 $(document).on('nopOnePageCheckoutPanelsLoadedEvent', function () { 438 handleCheckoutMethods(); 439 }); 440 $(document).on('SevenSpikesROPCPaymentMethodsRefresh', function () { 441 handleCheckoutMethods(); 442 }); 443 444 445 446 // FOOTABLE.js initialization //////////////////////////////////////////////////////////////////////////////////////////////////////////////// 447 448 if (typeof $('body').footable == 'function') { 449 $('.recurring-payments .data-table, .downloadable-products-page .data-table, .reward-points-history .data-table, .checkout-page .cart, .order-details-page .data-table, .return-request-page .data-table, .forum-table, .private-messages-page .data-table').footable(); 450 } 451 if ($('.checkout-page').length > 0) { 452 $(document).ajaxSuccess(function () { 453 if ($('.order-summary-content .cart').length > 0) { 454 $('.order-summary-content .cart').footable(); 455 } 456 }); 457 } 458 459 }); // document.ready end 460 461 462 // Bypass perfect-scrollbar.js, no other way to disable it as it's invoked by the Core script. Should be removed from Head.cshtml first. 463 $.fn.perfectScrollbar = function () { return }; 464 465})(jQuery);
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.