PageSourceSearch

https://ceciliassteel.com/store/extensions/novator/storefront/view/novator/js/main.js

js ceciliassteel.com collected 2026-09-26 06:48:41 UTC 24,938 bytes, 743 lines download raw bytes

1let evtName = '';
2//fill default values of common variables if not set
3if (!window.hasOwnProperty("baseUrl")) {
4    window.baseUrl = window.location.protocol
5        + '//'
6        + window.location.host
7        + window.location.pathname.replace('index.php', '');
8}
9if (!window.hasOwnProperty("samesite")) {
10    window.samesite = window.location.protocol === 'https:' ? 'None; secure=1;' : 'lax; secure=0;';
11}
12
13if (!window.hasOwnProperty("cart_url")) {
14    window.cart_url = baseUrl + '?rt=checkout/cart';
15}
16
17if (!window.hasOwnProperty("call_to_order_url")) {
18    window.call_to_order_url = baseUrl + '?rt=content/contact';
19}
20
21if (!window.hasOwnProperty("text_add_cart_confirm")) {
22    window.text_add_cart_confirm = 'Added to cart';
23}
24
25if (!window.hasOwnProperty("cart_ajax_url")) {
26    window.cart_ajax_url = baseUrl + '?rt=r/product/product/addToCart&fc=1';
27}
28if (!window.hasOwnProperty("cart_ajax_update_url")) {
29    window.cart_ajax_update_url = baseUrl + '?rt=r/product/product/updateQuantityCart';
30}
31if (!window.hasOwnProperty("cart_ajax_delete_product_url")) {
32    window.cart_ajax_delete_product_url = baseUrl + '?rt=r/product/product/removeProductFromCart';
33}
34if (!window.hasOwnProperty("search_url")) {
35    window.search_url = baseUrl + '?rt=product/search';
36}
37
38$(document).on('submit','form.needs-validation', function(e){
39    if (!$(this)[0].checkValidity()) {
40        try {
41            resetLockedButton($(this).find('.lock-on-click'));
42        }catch (e) {}
43        e.preventDefault();
44        e.stopPropagation();
45    }
46    $(this).addClass('was-validated');
47});
48
49$(document).ready(function(){
50
51    //dropdown hovers
52    document.querySelectorAll('.dropdown').forEach(function (dropdown) {
53        const toggle = dropdown.querySelector('[data-bs-toggle="dropdown"]');
54        if(!toggle){
55            console.log('invalid html. Dropdown toggle not found in:', dropdown);
56            return;
57        }
58
59        let defaultPlacement,fallbackPlacements;
60        //mega-menu all categories
61        if( toggle.closest('li').classList.contains('category-dropdown')){
62                defaultPlacement = 'bottom-start';
63                fallbackPlacements = [];
64        }
65        //main sf menu
66        else if(toggle.closest('ul').classList.contains('mega-sf-menu')
67            || toggle.closest('li').classList.contains('category-dropdown')){
68            if(toggle.getAttribute('data-dpd-type') === 'category'){
69                defaultPlacement = 'bottom';
70                fallbackPlacements = [];
71            }else {
72                defaultPlacement = 'bottom-start';
73                fallbackPlacements = ['top-end', 'right-start', 'left-start'];
74            }
75        }
76        //content footer menu
77        else if(toggle.closest('ul').classList.contains('parent-ul')){
78            defaultPlacement = 'top-start';
79            fallbackPlacements = ['top-end', 'right-start', 'left-start'];
80        }else{
81            defaultPlacement = 'right-start';
82            fallbackPlacements = ['left-start'];
83        }
84
85        const dropdownInstance = new bootstrap.Dropdown(
86            toggle,
87            {
88                popperConfig: function (defaultConfig) {
89                return {
90                        ...defaultConfig,
91                        placement: defaultPlacement,
92                        modifiers: [
93                            {
94                                name: 'flip',
95                                options: {
96                                    fallbackPlacements: fallbackPlacements,
97                                },
98                            },
99                            {
100                                name: 'preventOverflow',
101                                options: {
102                                    boundary: 'viewport',
103                                },
104                            }
105                        ]
106                    };
107                }
108            }
109        );
110
111        let timeout;
112
113        dropdown.addEventListener('mouseenter', function () {
114            clearTimeout(timeout);
115            dropdownInstance.show();
116        });
117
118        dropdown.addEventListener('mouseleave', function () {
119            timeout = setTimeout(() => {
120                dropdownInstance.hide();
121            }, 300);
122        });
123    });
124
125
126    var searchOffcanvas = $('#searchoffcanvas');
127    var filterKeywordInput = $('input[name=keyword]');
128
129    searchOffcanvas.on('shown.bs.offcanvas', function () {
130        filterKeywordInput.first().attr('disabled', 'disabled');
131        filterKeywordInput.last().removeAttr('disabled');
132    });
133
134    searchOffcanvas.on('hidden.bs.offcanvas', function () {
135        filterKeywordInput.first().removeAttr('disabled');
136        filterKeywordInput.last().attr('disabled', 'disabled');
137    });
138
139    if (filterKeywordInput.first().is(":visible")) {
140        filterKeywordInput.first().removeAttr('disabled');
141    }
142
143    $(window).on('beforeunload', function ( e ) {
144       let link = document.activeElement.href;
145       if(!link || !link.search('download')) {
146           $('#preloader').css('display', 'block');
147       }
148    });
149
150    $(".category-links a.nav-link").hover(
151        function(){
152            let actTab = new bootstrap.Tab($(this));
153            actTab.show();
154            $('[id^="card-"]').removeClass('show').css('display','none');
155            $('#'+actTab._element.id.replace('drp-','card-') + '-pane').addClass('show').css('display','block');
156        }
157    ).on(
158        'click',
159        function(){
160            location = $(this).attr('href')
161        }
162    );
163    $("#megaMenuContent a.subcategory-link").hover(function(){
164        $('[id^="card-"]').removeClass('show').css('display','none');
165        $('#'+$(this).attr('id').replace('child-','card-') + '-pane').addClass('show').css('display','block');
166    });
167
168    let cid = $("#megaMenuContent").find('.active.show').first().attr('data-category-id');
169    if(cid){
170         $('#card-'+cid+'-tab-pane').addClass('active show');
171    }
172
173    if (window.hasOwnProperty("is_retina") && is_retina === true) {
174        if ((window.devicePixelRatio === undefined ? 1 : window.devicePixelRatio) > 1) {
175            document.cookie = 'HTTP_IS_RETINA=1;path=/; samesite=' + samesite;
176        }
177    }
178
179    if (window.hasOwnProperty("cart_ajax_url")) {
180        function add2CartAjax(product_id, option = []) {
181            let senddata = {},
182                result = false;
183            if (product_id) {
184                senddata['product_id'] = product_id;
185            }
186            if(option){
187                senddata['option'] = option;
188            }
189            $.ajax({
190                url: cart_ajax_url,
191                type: 'GET',
192                dataType: 'json',
193                data: senddata,
194                async: false,
195                success: function (data) {
196                    //top cart
197                     $('.nav.topcart span.label-qnty').html(data.item_count);
198                     $('.nav.topcart span.cart_total').html(data.total);
199                     let pList = $('#cartoffcanvas .offcanvas-body');
200                     if (pList) {
201                         pList.html(data.cart_details);
202                     }
203                    result = data;
204                }
205            });
206            return result;
207        }
208
209        //event for adding product to cart by ajax
210        $(document).on('click touchstart', 'a.add-to-cart', function (e) {
211
212            let item = $(this);
213            //check if href provided for product details access
214            if (item.attr('href') && item.attr('href') !== '#') {
215                return true;
216            }
217            e.preventDefault();
218            e.stopPropagation();
219            if(e.handleObj.type === 'click' && evtName === 'touchstart'){
220                evtName = '';
221                return true;
222            }
223            evtName = e.handleObj.type;
224
225            let wrapper = item.parent();
226
227            if (item.attr('data-id')) {
228                let options;
229                let check_cart = wrapper.find('i').first();
230                let icon_cart = wrapper.find('i').last();
231                let spinner = wrapper.children('span');
232                spinner.removeClass('visually-hidden');
233                icon_cart.addClass('visually-hidden');
234                if( item.attr('data-options') && item.attr('data-options').length ) {
235                    options = JSON.parse(item.attr('data-options'));
236                }
237                let data = add2CartAjax(item.attr('data-id'), options);
238                if ( data !== false) {
239                    if(!check_cart.is(":visible")) {
240                        check_cart.toggle("slide:left");
241                    }
242                    spinner.addClass('visually-hidden');
243                    icon_cart.removeClass('visually-hidden');
244
245                    if(ga4_enabled){
246                        let card = item.parents('.card');
247                        let prodName = card.find('.card-title').text();
248                        let productData;
249
250                        $.each(data.products, function(idx){
251                            if(data.products[idx].key == item.attr('data-id')){
252                                productData = data.products[idx];
253                            }
254                        });
255                        let addedQnty = item.next().text()
256                            ? data.added_item_quantity - parseInt(item.next().text(),10)
257                            : data.added_item_quantity;
258                        gtag("event", "add_to_cart", {
259                            currency: default_currency,
260                            value: addedQnty * productData.price_num,
261                            items: [
262                                {
263                                    item_id: item.attr('data-id'),
264                                    item_name: prodName.trim(),
265                                    affiliation: storeName,
266                                    price: productData.price_num.toFixed(2),
267                                    quantity: addedQnty
268                                }
269                            ]
270                        });
271                    }
272
273                    $('.cart_counter').html(data.item_count);
274                    item.find('i').addClass('text-success bi-bag-check-fill').removeClass('bi-bag-fill');
275                }
276            }
277            return false;
278        });
279
280        $(document).on('click touchstart', 'i.bi-bag-check-fill', function (e) {
281            location = cart_url;
282            }
283        );
284        $('#cartoffcanvas').on('shown.bs.offcanvas',function (){
285            $('#theme-switcher').removeClass('d-flex').addClass('d-none');
286        }).on('hidden.bs.offcanvas',function (){
287            $('#theme-switcher').removeClass('d-none').addClass('d-flex');
288        });
289    }
290
291    //dropdown menu fix of parent
292    $('.dropdown>a').on('click', function (e) {
293        e.preventDefault();
294        let href = $(this).attr('href');
295        let target = $(this).attr('target');
296        if(href.substring(0,1) !== '#') {
297            if( !target || target === '_self') {
298                location = href;
299            }else{
300                window.open(href, target);
301            }
302        }
303    });
304
305    $('[data-bs-toggle="popover"]').popover({});
306
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    // List & Grid View
313    $('#list_view_btn').on('click',
314        function () {
315            $('#list_view_btn').addClass('active');
316            $('#product_cell_grid').fadeOut();
317            $('#product_list').fadeIn();
318            $('#grid_view_btn').removeClass('active');
319        }
320    );
321    $('#grid_view_btn').on('click',
322        function () {
323            $('#grid_view_btn').addClass('active');
324            $('#product_list').fadeOut();
325            $('#product_cell_grid').fadeIn();
326            $('#list_view_btn').removeClass('active');
327        }
328    );
329    //search bar on top
330    $('#search_form .search-category').on(
331        'click',
332        function(){
333            $('#search_form .search-category>a').removeClass('selected');
334            let ref = $(this).find('a');
335            ref.addClass('selected');
336            $('input#filter_category_id').val(ref.attr('data-id'))
337            $('#search_form #category_selected').fadeOut(500, function() {
338                $(this).text(ref.text()).fadeIn(500);
339            });
340        }
341    );
342
343    //put submitted or clicked button to loading state
344    $('.lock-on-click').each(function () {
345        let btn = $(this);
346        btn.attr('data-loading-text', '<span class="spinner-grow spinner-grow-sm" role="status" aria-hidden="true"></span>');
347        btn.bind('click', function () {
348            $(this).button('loading');
349        });
350    });
351
352    //reset coupon
353    $('#couponForm').on('click', '#remove_coupon_btn', function () {
354        let $form = $("#coupon_coupon").closest('form');
355        $("#coupon_coupon").val('');
356        $form.append('<input type="hidden" name="reset_coupon" value="true" />');
357        $form.submit();
358        return false;
359    });
360
361    $(document).on(
362        'click keyup',
363        '.minus-qnty, .plus-qnty, input[name^="quantity"]',
364        function(e) {
365
366        let productId = $(this).data('product-id');
367        let qtyInput;
368        if(e.currentTarget.nodeName === 'INPUT'){
369            if(e.type=="click"){ return;}
370            qtyInput = $(this);
371        }else{
372            e.preventDefault();
373            qtyInput =  $(this).siblings("input");
374        }
375
376        let qty = parseInt(qtyInput.val());
377        let min = parseInt(qtyInput.attr('min'));
378        let max = parseInt(qtyInput.attr('max'));
379
380        if ($(this).hasClass('minus-qnty')) {
381            qty = Math.max(qty - 1, 1);
382            if(qty < 1 || (min > 0 && qty < min) ){
383                return false;
384            }
385        } else if ($(this).hasClass('plus-qnty')) {
386            qty++;
387            if(max > 0 && qty > max ){
388                return false;
389            }
390        }
391
392        if(isNaN(qty)){
393            return;
394        }
395
396        if($(this).parents('#cartoffcanvas').length>0) {
397            replaceCartDetailsNv(productId, qty);
398        }else{
399            qtyInput.val(qty).focus().change();
400        }
401    });
402
403    function replaceCartDetailsNv (productId,quantity){
404        $.ajax({
405            url: cart_ajax_update_url,
406            type: 'GET',
407            dataType: 'json',
408            data: {
409                product_key: productId,
410                quantity: quantity
411            },
412            success: function (data) {
413                //top cart
414                $('.cart_counter').html(data.item_count);
415                $('.nav.topcart span.cart_total').html(data.total);
416                $('#cartoffcanvas .offcanvas-body').html(data.cart_details);
417            }
418        });
419    }
420
421
422    $(document).on('click','#delete_product', function() {
423        let product_key = $(this).data('product-key');
424        $.ajax({
425            url: cart_ajax_delete_product_url,
426            type: 'GET',
427            dataType: 'json',
428            data: {
429                product_key: product_key
430            },
431            success: function (data) {
432                //top cart
433                $('.cart_counter').html(data.item_count);
434                $('.nav.topcart span.cart_total').html(data.total);
435                $('#cartoffcanvas .offcanvas-body').html(data.cart_details);
436            }
437        });
438    });
439
440    //process multi-item carousel. rebuild elements
441    $('.product-multi-carousel').each( function(){
442        let items = $(this)[0].querySelectorAll('.carousel-item');
443        let minPerSlide = 4;
444        minPerSlide = items.length < minPerSlide ? items.length : minPerSlide;
445        items.forEach((el) => {
446            let next = el.nextElementSibling
447            for (let i=1; i<minPerSlide; i++) {
448                if (!next) {
449                    // wrap carousel by using first child
450                    next = items[0]
451                }
452                let cloneChild = next.cloneNode(true)
453                el.appendChild(cloneChild.children[0])
454                next = next.nextElementSibling
455            }
456        });
457    });
458
459    $('.theme-change').on('click', function () {
460        let html = $("html");
461        if (html.attr("data-bs-theme")) {
462            html.removeAttr("data-bs-theme", "dark");
463            setCookie("data-bs-theme", "light", 100);
464        } else {
465            html.attr("data-bs-theme", "dark");
466            setCookie("data-bs-theme", "dark", 100);
467        }
468    });
469
470    //capslock check for password fields
471    function enableCapsLockWarnings(container = document) {
472        const passwordFields = container.querySelectorAll('input[type="password"]');
473        passwordFields.forEach(field => {
474
475            const checkCapsLock = (e) => {
476                const warning = $(field).parent().find('.pwdhelp');
477                if (!warning) return;
478                const capsOn = e.getModifierState && e.getModifierState('CapsLock');
479                if(capsOn){
480                    warning.removeClass('d-none');
481                }else{
482                    warning.addClass('d-none');
483                }
484            };
485
486            const attach = () => {
487                window.addEventListener('keydown', checkCapsLock);
488                window.addEventListener('keyup', checkCapsLock);
489            };
490
491            const detach = (e) => {
492                window.removeEventListener('keydown', checkCapsLock);
493                window.removeEventListener('keyup', checkCapsLock);
494                $(field).parent().find('.pwdhelp').addClass('d-none');
495            };
496
497            field.addEventListener('keydown', checkCapsLock);
498            field.addEventListener('keyup', checkCapsLock);
499            field.addEventListener('focus', function(e){
500                attach(e);
501                checkCapsLock(e);
502            });
503            field.addEventListener('blur', detach);
504        });
505    }
506    // Call this once on page load or after dynamic content is added
507    enableCapsLockWarnings();
508});
509
510//put submitted or clicked button to loading state
511$(document).on('click', '.lock-on-click', function () {
512     let btn = $(this);
513     if(!btn.find('span.spinner-border').length) {
514         btn.prepend('<span class="visually-hidden spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>');
515     }
516
517    btn.find('i').addClass('visually-hidden');
518    btn.find('span.spinner-border').removeClass('visually-hidden');
519    btn.addClass('disabled');
520});
521
522function resetLockedButton(btn){
523    if(!btn){ return; }
524    btn.find('i').removeClass('visually-hidden');
525    btn.find('span.spinner-border').addClass('visually-hidden');
526    btn.removeClass('disabled');
527}
528
529$(document).on('click',"#gotop",function () {
530        $("html, body").animate({scrollTop: 0}, "fast");
531        return false;
532    }
533);
534
535$(window).scroll(
536    function () {
537        let gt = $('#gotop');
538        if ($(this).scrollTop() > 50) {
539            gt.fadeIn(500);
540        } else {
541            gt.fadeOut(500);
542        }
543    }
544);
545
546function openModalRemote(id, url) {
547
548    let modal = $(id);
549    let modalBody = $(id + ' .modal-body');
550    modalBody.load(url);
551    modal.modal('show');
552}
553
554// search page
555function contentSearch(url) {
556    url += '&' + $('#search_page_form').serialize();
557    let sortFld = $('#sort');
558    if (sortFld.length>0 && sortFld.val().length>0) {
559        url += '&sort=' + sortFld.val();
560    }
561    window.location = url;
562}
563// product list
564function ResortProductGrid(url) {
565    url += '&sort=' + $('#sort').val();
566    url += '&limit=' + $('#limit').val();
567    location = url;
568}
569
570function bookmark(url, title) {
571    if (window.sidebar) {
572        window.sidebar.addPanel(title, url, "");
573    } else if (document.all) {
574        window.external.AddFavorite(url, title);
575    } else if (window.opera && window.print) {
576        alert('Press ctrl+D to bookmark (Command+D for macs) after you click Ok');
577    } else if (window.chrome) {
578        alert('Press ctrl+D to bookmark (Command+D for macs) after you click Ok');
579    }
580}
581
582//when try to load script from ajax-response
583function loadScript(url, callback) {
584    let script = document.createElement("script")
585    script.type = "text/javascript";
586
587    if (script.readyState) {  //IE
588        script.onreadystatechange = function () {
589            if (script.readyState === "loaded" ||
590                script.readyState === "complete") {
591                script.onreadystatechange = null;
592                callback();
593            }
594        };
595    } else {  //Others
596        script.onload = function () {
597            callback();
598        };
599    }
600
601    script.src = url;
602    document.getElementsByTagName("head")[0].appendChild(script);
603}
604
605function goTo(url, params) {
606    location = url + '&' + params;
607}
608
609function getURLVar(urlVarName) {
610    var urlHalves = String(document.location).toLowerCase().split('?');
611    var urlVarValue = '';
612
613    if (urlHalves[1]) {
614        var urlVars = urlHalves[1].split('&');
615
616        for (var i = 0; i <= (urlVars.length); i++) {
617            if (urlVars[i]) {
618                var urlVarPair = urlVars[i].split('=');
619
620                if (urlVarPair[0] && urlVarPair[0] === urlVarName.toLowerCase()) {
621                    urlVarValue = urlVarPair[1];
622                }
623            }
624        }
625    }
626
627    return urlVarValue;
628}
629
630//function to load modal for messages #msgModal
631// 1. header 2. Message body, 3. on close callback function
632showMsg = function (header, body, callback) {
633    $('#msgModal').modal({
634        backdrop: false,
635        show: false,
636        keyboard: false
637    })
638        .find('.modal-header > h3').text(header).end()
639        .find('.modal-body').html(body).end()
640        .find('.callback-btn').off('click.callback')
641        .on('click.callback', callback).end()
642        .modal('show');
643};
644
645function escapeHtml(text) {
646    return text
647        .replace(/&/g, "&amp;")
648        .replace(/</g, "&lt;")
649        .replace(/>/g, "&gt;")
650        .replace(/"/g, "&quot;")
651        .replace(/'/g, "&#039;");
652}
653
654function setCookie(name,value,days) {
655    let expires = "";
656    if (days) {
657        let date = new Date();
658        date.setTime(date.getTime() + (days*24*60*60*1000));
659        expires = "; expires=" + date.toUTCString();
660    }
661    document.cookie = name + "=" + (value || "")  + expires + "; path=/";
662}
663
664$(document).on("click", "a.share", function(){ shareProduct(this) });
665function shareProduct(elm)
666{
667    let card = $(elm);
668    let data = { "url" : card.attr('data-url'), "title": card.attr('data-title') };
669    if(!data.url){ return;}
670    try {
671        navigator.share(data);
672    }
673    catch(e){
674        navigator.clipboard.writeText(data.url);
675        alert("Copied!");
676    }
677}
678
679function scrollToTab(ID) {
680    let element = document.getElementById('collapse'+ID[0].toUpperCase() + ID.substring(1));
681    let tab = new bootstrap.Tab(document.getElementById(ID));
682    if (element && tab) {
683        tab.show();
684        setTimeout(function() {
685            element.scrollIntoView({ behavior: 'smooth', block: 'start' });
686        }, 100);
687    }
688}
689
690//Google Analytics 4
691function wishlistGA_event_fire(evtName, card){
692    if(!ga4_enabled){
693        console.log('google analytics data collection is disabled')
694        return;
695    }
696
697    let prodName = card.find('.product-name').text().trim();
698    let price = card.find('.prod-price').first().text().trim();
699    gtag("event", evtName, {
700        currency: default_currency,
701        value: price,
702        items: [
703            {
704                item_id: card.attr('data-product-id'),
705                item_name: prodName,
706                affiliation: storeName,
707                price: price ,
708                quantity: 1
709            }
710        ]
711    });
712}
713
714$(document).on('click','.wish', function(e) {
715    e.preventDefault();
716    let that = $(this).find('i.bi');
717    let card = $(this).parents('.card');
718    let productId = card.attr('data-product-id');
719    let added = that.hasClass('bi-heart-fill');
720    let url = added ? wishlist_remove_url : wishlist_add_url;
721    url += '&product_id=' + productId;
722
723    $.ajax({
724        type: 'POST',
725        url: url,
726        dataType: 'json',
727        beforeSend: function () {
728            that.addClass('fa-spin');
729        },
730        complete: function () {
731            that.removeClass('fa-spin');
732        },
733        success: function (data) {
734            let icons = $('.card[data-product-id='+productId+']').find('a.wish').find('i');
735            if (added) {
736                icons.removeClass('bi-heart-fill').addClass('bi-heart');
737            } else {
738                icons.removeClass('bi-heart').addClass('bi-heart-fill');
739                wishlistGA_event_fire("add_to_wishlist", card);
740            }
741        }
742    });
743});

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.