PageSourceSearch

https://www.nordicgym.com/assets/js/bapms.js?261001085505

js nordicgym.com collected 2026-10-10 01:36:51 UTC 127,611 bytes, 2,761 lines download raw bytes

1var productListData = {};
2var productListDataRaw = {};
3var productList__pprLoaded = false;
4var productSingleData = {};
5var checkoutPaymentResponseData = {};
6var productInventory = bjorkInventory();
7
8var WESTORE = {
9    ROUTE: {},
10    CART: {},
11    CHECKOUT: {},
12    PRODUCT_LIST: {},
13    PRODUCT_SINGLE: {},
14    CONFIG: {
15        targetElement: '#store-container',
16        targetElementCart: '#store-container-cart',
17        targetWidgetIcons: '',
18        widget_icons_top: 20,
19        widget_icons_right: 20,
20        widget_icons_expand: true,
21        store_load_method: 'CMS',
22        country: 'SE',
23        url_root: '',
24        url_page_checkout: '',
25        url_page_checkout_confirmation: '',
26        url_page_search: '',
27        url_page_product: '',
28        url_cms_root: '',
29        url_script_product_list: '',
30        url_script_product_single: '',
31        url_script_product_single_quantity: '',
32        url_product_images: '',
33        url_domain_api: 'https://api.epage.se',
34        label_search: 'Search',
35        clog_active: false,
36    },
37    init: function(data) {
38
39        if(data.CONFIG.targetElement)                       { this.CONFIG.targetElement                         = data.CONFIG.targetElement; }
40        if(data.CONFIG.targetElementCart)                   { this.CONFIG.targetElementCart                     = data.CONFIG.targetElementCart; }
41        if(data.CONFIG.targetWidgetIcons)                   { this.CONFIG.targetWidgetIcons                     = data.CONFIG.targetWidgetIcons; }
42        if(data.CONFIG.widget_icons_top)                    { this.CONFIG.widget_icons_top                      = data.CONFIG.widget_icons_top; }
43        if(data.CONFIG.widget_icons_right)                  { this.CONFIG.widget_icons_right                    = data.CONFIG.widget_icons_right; }
44        if(data.CONFIG.widget_icons_expand)                 { this.CONFIG.widget_icons_expand                   = data.CONFIG.widget_icons_expand; }
45        if(data.CONFIG.store_load_method)                   { this.CONFIG.store_load_method                     = data.CONFIG.store_load_method; }
46        if(data.CONFIG.country)                             { this.CONFIG.country                               = data.CONFIG.country; }
47        if(data.CONFIG.url_root)                            { this.CONFIG.url_root                              = data.CONFIG.url_root; }
48        if(data.CONFIG.url_page_checkout)                   { this.CONFIG.url_page_checkout                     = data.CONFIG.url_page_checkout; }
49        if(data.CONFIG.url_page_checkout_confirmation)      { this.CONFIG.url_page_checkout_confirmation        = data.CONFIG.url_page_checkout_confirmation; }
50        if(data.CONFIG.url_page_search)                     { this.CONFIG.url_page_search                       = data.CONFIG.url_page_search; }
51        if(data.CONFIG.url_page_product)                    { this.CONFIG.url_page_product                      = data.CONFIG.url_page_product; }
52        if(data.CONFIG.url_cms_root)                        { this.CONFIG.url_cms_root                          = data.CONFIG.url_cms_root; }
53        if(data.CONFIG.url_script_product_list)             { this.CONFIG.url_script_product_list               = data.CONFIG.url_script_product_list; }
54        if(data.CONFIG.url_script_product_single)           { this.CONFIG.url_script_product_single             = data.CONFIG.url_script_product_single; }
55        if(data.CONFIG.url_script_product_single_quantity)  { this.CONFIG.url_script_product_single_quantity    = data.CONFIG.url_script_product_single_quantity; }
56        if(data.CONFIG.url_product_images)                  { this.CONFIG.url_product_images                    = data.CONFIG.url_product_images; }
57        if(data.CONFIG.url_domain_api)                      { this.CONFIG.url_domain_api                        = data.CONFIG.url_domain_api; }
58        if(data.CONFIG.label_search)                        { this.CONFIG.label_search                          = data.CONFIG.label_search; }
59        if(data.CONFIG.clog_active)                         { this.CONFIG.clog_active                           = data.CONFIG.clog_active; }
60
61        this.ROUTE.init(data.ROUTE);
62        this.CART.init(data.CART);
63        this.CHECKOUT.init(data.CHECKOUT);
64        this.PRODUCT_LIST.init(data.PRODUCT_LIST);
65        this.PRODUCT_SINGLE.init(data.PRODUCT_SINGLE);
66
67        $(window).load(function() {
68            WESTORE.jQueryActions();
69        });
70
71    },
72    clog: function (output) {
73    	if(this.CONFIG.clog_active) { console.log(output); }
74    },
75    clog_time_start: function (output) {
76    	if(this.CONFIG.clog_active) { console.time(output); }
77    },
78    clog_time_end: function (output) {
79    	if(this.CONFIG.clog_active) { console.timeEnd(output); }
80    },
81    get_display_price: function(price) {
82
83        // Cut down to 2 decimals
84        if(!Number.isInteger(price)) {
85            price = Math.round(price * 100) / 100;
86            price = price.toFixed(2);
87        }
88
89        // Adds commas
90        var display_price = new Intl.NumberFormat('en-US', { style: 'currency', currency: 'SEK' }).format(price);
91        display_price = display_price.replaceAll(".00", ""); // Remove trailing .00
92        display_price = display_price.replace(/\xA0/g, ""); // Removes  
93        display_price = display_price.replace("SEK", "");
94        display_price = display_price.replace(",", " ");
95
96        // Adds currency
97        if(this.CONFIG.country == "US") { display_price = `$${display_price}`; }
98        else { display_price = `${display_price} kr`; }
99
100        return display_price;
101
102    },
103    widgetIcons__render: function() {
104
105        var $widgetContainer = $(WESTORE.CONFIG.targetWidgetIcons);
106        var html = "";
107        var cartHTML = "";
108        var searchHTML = "";
109        var searchExpandClass = "";
110
111        if(WESTORE.CONFIG.widget_icons_expand) { searchExpandClass = " expandable collapsed"; }
112
113        // Search html
114        var searchHTML = `
115        <div class="store-widget-item store-widget-item-search">
116            <div class="store-search-text${searchExpandClass}">
117                <input type="text" class="storeWidgetTarget-searchInput" placeholder="${WESTORE.CONFIG.label_search}"></input>
118            </div>
119            <button class="store-widget-button store-search-button storeWidgetTarget-searchButton" type="submit">
120            <svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" role="img" width="24" height="24">
121                <g fill="none" stroke="currentColor" stroke-width="2.1">
122                    <circle cx="10" cy="10" r="8"></circle>
123                    <line y2="23" x2="23" y1="16" x1="16" ></line>
124                </g>
125            </svg>
126            </button>
127        </div>
128        `;
129
130        // Check if Cart icon already exists, then add it
131        if(WESTORE.CART.cart_active && !$(".cart-icon").length) {
132            cartHTML = `
133            <div class="store-widget-item store-widget-item-cart">
134        		<div class="store-widget-button store-cart-button storeWidgetTarget-cartButton">
135        			<div class="store-cart-button-counter storeWidgetTarget-cartButtonCounter hide"></div>
136        			<svg class="store-cart-button-svg" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" role="img" width="24px" height="24px" preserveAspectRatio="xMidYMid meet" viewBox="2 2 20 20">
137        				<g fill="none" stroke="currentColor" stroke-width="1.5">
138            				<path d="M3 3h2l.5 3m0 0L7 15h11l3-9H5.5z"></path>
139            				<circle cx="8" cy="20" r="1"></circle><circle cx="17" cy="20" r="1"></circle>
140                        </g>
141        			</svg>
142        		</div>
143            </div>
144            `;
145        }
146
147        html = `${searchHTML}${cartHTML}`;
148
149        if($widgetContainer.length) {
150            html = `<div id="store-widget-icons">${html}</div>`;
151            $widgetContainer.html(html);
152        }
153        else {
154            html = `<div id="store-widget-icons" style="position: fixed; z-index: 9998; top: ${WESTORE.CONFIG.widget_icons_top}px; right: ${WESTORE.CONFIG.widget_icons_right}px">${html}</div>`;
155            $('body').prepend(html);
156        }
157
158    },
159    widgetIcons__search_expand: function() {
160
161        var $text = $("#store-widget-icons .store-widget-item-search .store-search-text");
162
163        if(WESTORE.CONFIG.widget_icons_expand && $text.hasClass("collapsed")) {
164
165            $text.find('input').focus();
166
167            $text.stop().animate({
168                "opacity": 1,
169                "width": "240px",
170                "padding-left": "24px",
171                "padding-right": "4px"
172            }, 200, function() {
173                $text.addClass("expanded");
174            });
175
176        }
177
178    },
179    widgetIcons__search_collapse: function() {
180
181        var $text = $("#store-widget-icons .store-widget-item-search .store-search-text");
182
183        if(WESTORE.CONFIG.widget_icons_expand && $text.hasClass("expanded")) {
184
185            $text.stop().animate({
186                "opacity": 0,
187                "width": "0px",
188                "padding-left": "0px",
189                "padding-right": "0px"
190            }, 200, function() {
191                $text.find('input').val('').blur();
192                $text.addClass("collapsed");
193            });
194
195        }
196
197    },
198    jQueryActions: function() {
199
200        // Cart button clicked
201        $("body").on("click", ".storeWidgetTarget-cartButton", function(e) {
202            $("#cart").css('display', 'flex');
203        });
204
205        // Search open
206        $("body").on("mouseenter", "#store-widget-icons .store-widget-item-search", function(e) {
207            WESTORE.widgetIcons__search_expand();
208        });
209
210        // Search open
211        $("body").on("mouseleave", "#store-widget-icons .store-widget-item-search", function(e) {
212            WESTORE.widgetIcons__search_collapse();
213        });
214
215        // Search button clicked
216        $("body").on("click", ".storeWidgetTarget-searchButton", function(e) {
217            var $searchInput = $(this).parents('.storeWidgetTarget-search').find('storeWidgetTarget-searchInput');
218            if(!$searchInput.length) { $searchInput = $('input.storeWidgetTarget-searchInput'); }
219            var search_raw = $searchInput.val();
220            var search = encodeURIComponent(search_raw);
221            if(search) {
222
223                var url = WESTORE.CONFIG.url_root+WESTORE.CONFIG.url_page_search+'?search='+search;
224
225                WESTORE.ROUTE.loadPageContent(url);
226
227                if(WESTORE.CONFIG.widget_icons_expand) { WESTORE.widgetIcons__search_collapse(); }
228                else { $("input.storeWidgetTarget-searchInput").val("").blur(); }
229
230            }
231            else {
232                $("input.storeWidgetTarget-searchInput").focus();
233            }
234        });
235
236        // Search enter
237        $('body').on('keydown', 'input.storeWidgetTarget-searchInput', function(e) {
238            if ( e.keyCode == 13 ) {
239                var search_raw = $("input.storeWidgetTarget-searchInput").val();
240                var search = encodeURIComponent(search_raw);
241                if(search) {
242
243                    var url = WESTORE.CONFIG.url_root+WESTORE.CONFIG.url_page_search+'?search='+search;
244                    WESTORE.ROUTE.loadPageContent(url);
245                    if(WESTORE.CONFIG.widget_icons_expand) { WESTORE.widgetIcons__search_collapse(); }
246                    else { $("input.storeWidgetTarget-searchInput").val("").blur(); }
247
248                }
249                else {
250                    $("input.storeWidgetTarget-searchInput").focus();
251                }
252            }
253        });
254
255    },
256
257};
258var contentLoadLastURL = '';
259
260WESTORE.ROUTE = {
261    pages: {
262        index_status_default: 'index',
263        pages: {}
264
265    },
266    init: function(data) {
267
268        if(data.index_status_default) { this.index_status_default = data.index_status_default; }
269        if(data.pages) { this.pages = data.pages; }
270
271        $(function() {
272
273            if(WESTORE.CONFIG.store_load_method == "LIVE_EXTERNAL") {
274                // CONTENT LOAD - When browser history changes (Back, Forward, etc). Is set by window.history.pushState()
275            	window.onpopstate = function(event) {
276
277            	    var stateObj = event.state; // Passed object from replaceState() or pushState()
278
279            		// Trigger windows reload when popstate comes from epLoadType. Ignore other popstates, like anchors
280            		if(stateObj && typeof stateObj === "object") {
281            			if(stateObj.hasOwnProperty('epLoadType')) {
282            				if(stateObj.epLoadType == "normal" || stateObj.epLoadType == "content") {
283            					window.location.href = document.location;
284            				}
285            			}
286            		}
287            	};
288
289            	// CONTENT LOAD - For pages that was normally loaded, replaceState to add "epLoadType = normal" to the stateObj
290            	window.history.replaceState({'epLoadType': 'normal'}, document.title, '');
291
292            }
293
294            $(function() {
295                WESTORE.ROUTE.jQueryActions();
296            });
297
298
299        });
300
301        $(window).load(function() {
302
303            var product_page_set_lists = {'all': productListPageSets['all']};
304            WESTORE.PRODUCT_LIST.load_file_lists(product_page_set_lists, function(status){
305
306                if(status == "success") {
307                    WESTORE.widgetIcons__render();
308                    WESTORE.CART.load_from_localStorage();
309                    //WESTORE.CART.create_cart_from_url("eyIxMDMwIjoiNSIsIjEwMzEiOiI1IiwiMTAzOSI6IjUiLCIxMDQzIjo1fQ");
310                }
311                else {
312                    console.log("Product list(all) could not be loaded. Timeout.")
313                }
314
315            });
316        });
317
318    },
319    // Route data
320    routeData: function(urlBrowser) {
321
322        var pages = this.pages;
323        var pagetype = '';
324        var pageID = 0;
325        var name = '';
326        var title = '';
327        var searchwords = '';
328        var description = '';
329        var index_status = this.index_status_default;
330        var product_urlID = '';
331
332        // Get urlID
333        var urlPagePrefix = WESTORE.CONFIG.url_root; // Ex: "/" or "/sitename/" or "https://www.somedomain.com/"
334        var urlID = urlBrowser;
335        if(urlID.indexOf(urlPagePrefix) === 0) { urlID = urlID.substring(urlPagePrefix.length); } // Left trim urlPagePrefix
336        urlID = urlID.split('?')[0]; // Remove parameters
337
338        // Product page (urlID = "product/...")
339        if(urlID.indexOf(WESTORE.CONFIG.url_page_product) === 0) {
340
341            // This page data will be updated after the product is loaded.
342            // For SEO/Google this is ok. metas that are updated with Javascript will be registrated.
343            var pagename_tmp = "Produkt";
344
345            pagetype = "STORE_PRODUCT_SINGLE";
346            if(WESTORE.CONFIG.country == "US") { pagename_tmp = "Product"; }
347            name = pagename_tmp;
348            title = pagename_tmp;
349            searchwords = pagename_tmp;
350            description = pagename_tmp;
351            index_status = this.index_status_default;
352
353        }
354        // Product list and system pages
355        else if(pages.hasOwnProperty(urlID)) {
356
357            pagetype = pages[urlID].pagetype;
358            pageID = pages[urlID].pageID;
359            name = pages[urlID].name;
360            title = pages[urlID].title;
361            searchwords = pages[urlID].searchwords;
362            description = pages[urlID].description;
363            index_status = pages[urlID].index_status;
364
365        }
366
367        return {urlID: urlID, pagetype: pagetype, pageID: pageID, name: name, title: title, searchwords: searchwords, description: description, index_status: index_status};
368
369    },
370    // Load page from Index header
371    loadPage: function() {
372
373        var urlBrowser = window.location.pathname;
374        var pageData = this.routeData(urlBrowser);
375
376        var urlID = pageData.urlID;
377        var pagetype = pageData.pagetype;
378        var pageID = pageData.pageID;
379
380        // Product single
381        if(pagetype == 'STORE_PRODUCT_SINGLE') {
382
383            product_urlID = urlID;
384            product_urlID = product_urlID.substring(WESTORE.CONFIG.url_page_product.length);
385            if(product_urlID) {
386
387                // Loads file (only loads file if productSingleData is not already set)
388                WESTORE.PRODUCT_SINGLE.load_file(product_urlID, function(product) {
389                    pageData.title = product.site_title;
390                    pageData.description = product.site_description;
391                    pageData.searchwords = product.site_title;
392                    WESTORE.ROUTE.update_metatags(pageData);
393                    WESTORE.PRODUCT_SINGLE.render(product_urlID);
394                });
395            }
396
397        }
398        // Product list
399        // If STORE_PRODUCT_LIST is from CMS, then its loaded from content_load.js instead
400        else if(pageID == 'STORE_SEARCH' || pagetype == 'STORE_PRODUCT_LIST') {
401
402            var listID = pageID;
403            if(pageID == 'STORE_SEARCH') { listID = 'all'; }
404
405            // Loads file (only loads file if productListData is not already set)
406            var product_page_set_lists = {[listID]: productListPageSets[listID]};
407            WESTORE.PRODUCT_LIST.load_file_lists(product_page_set_lists, function(status) {
408
409                if(status == "success") {
410                    var url_base = urlBrowser.split('?')[0]; // Remove parameters
411                    WESTORE.PRODUCT_LIST.render(pageData, url_base);
412                }
413                else {
414                    console.log("Product list("+listID+") could not be loaded. Timeout.")
415                }
416
417            });
418
419        }
420        // Checkout
421        if(pageID == 'STORE_CHECKOUT') {
422
423            $(function() {
424                WESTORE.CHECKOUT.render_page();
425            });
426
427        }
428        // Checkout confirmation
429        if(pageID == 'STORE_CHECKOUT_CONFIRMATION') {
430
431            $(function() {
432                WESTORE.CHECKOUT.render_confirmation_page();
433            });
434
435        }
436
437    },
438    // Load page from Ajax
439    loadPageContent: function(urlBrowser = '') {
440
441        if(contentLoadLastURL != urlBrowser) {
442
443            var pageData = this.routeData(urlBrowser);
444
445            var urlID = pageData.urlID;
446            var pagetype = pageData.pagetype;
447            var pageID = pageData.pageID;
448
449            // Product single
450            if(pagetype == 'STORE_PRODUCT_SINGLE') {
451
452                var product_urlID = urlID;
453                product_urlID = product_urlID.substring(WESTORE.CONFIG.url_page_product.length);
454                if(product_urlID) {
455
456                    WESTORE.ROUTE.contentLoad__animation_start();
457
458                    // Loads file (only loads file if productSingleData is not already set)
459                    WESTORE.PRODUCT_SINGLE.load_file(product_urlID, function(product) {
460
461                        pageData.title = product.site_title;
462                        pageData.description = product.site_description;
463                        pageData.searchwords = product.site_title;
464
465                        WESTORE.ROUTE.contentLoad__done(urlBrowser, pageData);
466                        WESTORE.PRODUCT_SINGLE.render(product_urlID);
467                        WESTORE.ROUTE.contentLoad__animation_done();
468
469                    });
470
471                }
472
473            }
474            // Product list
475            else if(pageID == 'STORE_SEARCH' || pagetype == 'STORE_PRODUCT_LIST') {
476
477                var listID = pageID;
478                if(pageID == 'STORE_SEARCH') { listID = 'all'; }
479
480                WESTORE.ROUTE.contentLoad__animation_start();
481
482                // Loads file (only loads file if productListData is not already set)
483                var product_page_set_lists = {[listID]: productListPageSets[listID]};
484                WESTORE.PRODUCT_LIST.load_file_lists(product_page_set_lists, function(status) {
485
486                    if(status == "success") {
487                        var url_base = urlBrowser.split('?')[0]; // Remove parameters
488                        WESTORE.ROUTE.contentLoad__done(urlBrowser, pageData);
489                        WESTORE.PRODUCT_LIST.render(pageData, url_base);
490                        WESTORE.ROUTE.contentLoad__animation_done();
491                    }
492                    else {
493                        console.log("Product list("+listID+") could not be loaded. Timeout.")
494                    }
495
496                });
497
498            }
499            // Checkout
500            else if(pageID == 'STORE_CHECKOUT') {
501                WESTORE.ROUTE.contentLoad__animation_start();
502                WESTORE.ROUTE.contentLoad__done(urlBrowser, pageData);
503                WESTORE.CHECKOUT.render_page();
504                WESTORE.ROUTE.contentLoad__animation_done();
505            }
506            // Checkout confirmation
507            else if(pageID == 'STORE_CHECKOUT_CONFIRMATION') {
508                WESTORE.ROUTE.contentLoad__animation_start();
509                WESTORE.ROUTE.contentLoad__done(urlBrowser, pageData);
510                WESTORE.CHECKOUT.render_confirmation_page();
511                WESTORE.ROUTE.contentLoad__animation_done();
512            }
513
514        }
515
516    },
517    contentLoad__animation_start: function() {
518
519        if(WESTORE.CONFIG.store_load_method == "CMS") { $('.page-preloader').show(); }
520        else {
521            window.weStoreLoaderTimeOut = setTimeout(function(){
522                $('body').append('<div class="contentLoader"><div class="contentLoaderBar contentLoaderAnimation'+(Math.floor(Math.random()*3)+1)+'"></div></div>');
523            }, 100);
524        }
525
526    },
527    contentLoad__animation_done: function() {
528
529        if(WESTORE.CONFIG.store_load_method == "CMS") { $('.page-preloader').hide(); }
530        else {
531            clearTimeout(window.weStoreLoaderTimeOut);
532            $(".contentLoader").delay(100).fadeOut(100, function() {
533                $(this).remove();
534            });
535        }
536
537    },
538    contentLoad__done: function (urlBrowser, pageData) {
539
540        var pageID = pageData.pageID;
541        var metaTitle = pageData.title;
542        var metaDescription = pageData.description;
543        var metaSearchwords = pageData.searchwords;
544        var metaRobots = pageData.index_status;
545
546        // Windows push state
547        window.history.pushState({'epLoadType': 'content'}, metaTitle, urlBrowser);
548
549        contentLoadLastURL = urlBrowser;
550
551        WESTORE.ROUTE.update_metatags(pageData);
552
553        if(WESTORE.CONFIG.store_load_method == "CMS" || WESTORE.CONFIG.store_load_method == "LIVE_INTERNAL") {
554
555            // Global JavaScript varibles
556            siteData.pageID = pageID;
557
558            //$('#rowlist_CONTENT .rowlist_content_container').html("<div id='store-container' class='row_content'></div>");
559            $('html, body').animate({scrollTop: 0}, 0);
560
561            $(".CSS_TOP_NAV .item.selected").removeClass('selected');
562            $(".CSS_TOP_NAV .item[data-pageID='"+pageID+"']").addClass('selected');
563
564            if(WESTORE.CONFIG.store_load_method == "LIVE_INTERNAL") {
565
566                if(typeof scrollBlockAnimation === "function") { scrollBlockAnimation(); }
567
568                if(pageID) {
569
570                    // API Visitors
571                    $.ajax({
572                        dataType: "script",
573                        url: WESTORE.CONFIG.url_domain_api+"/statistics/visit?id="+siteData.apiID+"&page="+pageID+"&uv="+(Math.floor((Math.random()*1000000)+1)),
574                        cache: true,
575                        success: function(jsRespons) {}
576                    });
577
578                }
579
580            }
581            else {
582
583            }
584
585        }
586
587        // 3rd Party trackers - Must be executed after window.history.pushState() is updated
588        if (typeof ga !== 'undefined') { ga('send', 'pageview'); } // Google analytics
589        if (typeof fbq !== 'undefined') { fbq('track', 'PageView'); } // Facebook Pixel Code
590
591    },
592    update_metatags: function (pageData) {
593
594        if(WESTORE.CONFIG.store_load_method != "CMS") {
595
596            var pageID = pageData.pageID;
597            var metaTitle = pageData.title;
598            var metaDescription = pageData.description;
599            var metaSearchwords = pageData.searchwords;
600            var metaRobots = pageData.index_status;
601
602            $("meta[property='og:site_name']").attr('content', metaTitle);
603            $("meta[property='og:title']").attr('content', metaTitle);
604            $("meta[property='og:description']").attr('content', metaDescription);
605            $("meta[name='twitter:title']").attr('content', metaTitle);
606            $("meta[name='twitter:description']").attr('content', metaDescription);
607            $("meta[name='description']").attr('content', metaDescription);
608            $("meta[name='keywords']").attr('content', metaSearchwords);
609            $("meta[name='robots']").attr('content', metaRobots);
610            $('title').text(metaTitle);
611
612        }
613
614    },
615    jQueryActions: function() {
616
617        // Content load - Checkout link clicked
618        $("body").on("click", "a.storeContentLoadLinkCheckout", function(event) {
619    		event.preventDefault();
620    		WESTORE.ROUTE.loadPageContent($(this).attr('href'));
621            $("#cart").css('display', 'none');
622    	});
623
624        // Content load - Product link clicked
625        $("body").on("click", "a.storeContentLoadLinkProduct", function(event) {
626    		event.preventDefault();
627    		WESTORE.ROUTE.loadPageContent($(this).attr('href'));
628    	});
629
630        // Content load - Product page link clicked
631        $("body").on("click", "a.storeContentLoadLinkPage", function(event) {
632
633            if(WESTORE.CONFIG.store_load_method == "CMS" || WESTORE.CONFIG.store_load_method == "LIVE_INTERNAL") {
634                contentLoad.load($(this), event);
635            }
636            else {
637                event.preventDefault();
638                WESTORE.ROUTE.loadPageContent($(this).attr('href'));
639            }
640
641    	});
642
643    }
644};
645WESTORE.CART = {
646    cartID: 'prdcrt_v4',
647    cart_active: false,
648    cart_is_created: false,
649    cart: {}, // {1001: {id: 1001, urlID: 'some/url', quantity: 1}, 1002: {...}}, productID and urlID is used as Keys to compare
650    label_title: 'Cart',
651    label_table_price: 'Price',
652    label_table_sum: 'Total',
653    label_cart_empty: 'Your cart is empty',
654    label_total_sum: 'Total price',
655    label_button_checkout: 'Go to checkout',
656    label_button_close: 'Keep shopping',
657    init: function(data) {
658
659        if(data.cart_active) { this.cart_active = data.cart_active; }
660
661        if(data.label_title) { this.label_title = data.label_title; }
662        if(data.label_table_price) { this.label_table_price = data.label_table_price; }
663        if(data.label_table_sum) { this.label_table_sum = data.label_table_sum; }
664        if(data.label_cart_empty) { this.label_cart_empty = data.label_cart_empty; }
665        if(data.label_total_sum) { this.label_total_sum = data.label_total_sum; }
666        if(data.label_button_checkout) { this.label_button_checkout = data.label_button_checkout; }
667        if(data.label_button_close) { this.label_button_close = data.label_button_close; }
668
669        $(function() {
670            WESTORE.CART.jQueryActions();
671        });
672
673    },
674    add: function(productData, quantity) {
675
676        if(this.cart_is_created) {
677
678            var cart = this.cart;
679            var productID = productData.productID;
680            quantity = parseInt(quantity);
681
682            if(cart.hasOwnProperty(productID)) {
683                cart[productID].quantity++;
684                WESTORE.clog('Product was added to the cart (increased to '+cart[productID].quantity+')');
685                WESTORE.clog(cart[productID]);
686            }
687            else {
688
689                var product = {
690            		productID: productID,
691            		urlID: productData.urlID,
692            		quantity: quantity,
693            	};
694
695                // Add the product
696                cart[productID] = product;
697
698                WESTORE.clog('Product was added to cart (new)');
699                WESTORE.clog(product);
700
701            }
702
703            this.save_to_localStorage();
704            this.render_products();
705
706        }
707        else {
708            WESTORE.clog('Product could not be added because the cart is not created');
709        }
710
711    },
712    remove: function(productID) {
713
714        var cart = this.cart;
715        if(cart.hasOwnProperty(productID)) {
716
717            // Remove element
718            var $productItem = $("#cart .product-item[data-productID='"+productID+"']");
719            $productItem.remove();
720
721            WESTORE.clog('Product was removed from the cart');
722            WESTORE.clog(cart[productID]);
723
724            delete cart[productID];
725            this.save_to_localStorage();
726            this.render_summary_values();
727
728        }
729
730    },
731    remove_all: function(productID) {
732
733        $("#cart .product-item").remove();
734
735        this.cart = {};
736        this.save_to_localStorage();
737        this.render_summary_values();
738
739        WESTORE.clog('The cart was cleared');
740
741    },
742    quantity_change: function(productID, quantity) {
743
744        var cart = this.cart;
745        if(cart.hasOwnProperty(productID)) {
746
747            quantity = parseInt(quantity);
748            if(!quantity || quantity < 1) { quantity = 1; }
749            else if (quantity > 999) { quantity = 999; }
750
751            var product = WESTORE.CART.get_product(productID);
752            var price_after_deduction = product.price_after_deduction;
753            var total = price_after_deduction * quantity;
754            total = WESTORE.get_display_price(total);
755
756            // Update cart html
757            var $productItem = $("#cart .product-item[data-productID='"+productID+"']");
758            var $input = $productItem.find('input.quantity');
759            $input.val(quantity)
760            $productItem.find('.total').html(total);
761
762            // Update cart quantity
763            if(cart.hasOwnProperty(productID)) {
764                this.cart[productID].quantity = quantity;
765            }
766
767            WESTORE.clog('Product quantity was updated in the cart');
768            WESTORE.clog(cart[productID]);
769
770            this.save_to_localStorage();
771            this.render_summary_values();
772
773        }
774
775    },
776    is_cart_empty: function() {
777        if($.isEmptyObject(this.cart)) { return true; }
778        else { return false; }
779    },
780    get_product: function(productID) {
781
782        var product = {};
783        var productList = productListData['all']['products_object'];
784
785        if(productList.hasOwnProperty(productID)) {
786
787            var productReal = productList[productID];
788
789            var price = productReal.price;
790            var price_deduction_percent = productReal.price_deduction;
791            var price_deduction_amount = price * price_deduction_percent / 100;
792			var price_after_deduction = price - price_deduction_amount;
793
794            display_price = WESTORE.get_display_price(price);
795            display_price_after_deduction = WESTORE.get_display_price(price_after_deduction);
796
797            product = {
798                'title': productReal.title,
799                'price': price,
800                'price_deduction': price_deduction_percent,
801                'price_after_deduction': price_after_deduction,
802                'tax': productReal.tax,
803                'urlID': productReal.urlID,
804                'image': productReal.image
805            };
806
807        }
808
809        return product;
810
811    },
812    create_cart_from_url: function(base64_url) {
813
814        var cart = {};
815        var cart_url_object = base64url_decode(base64_url);
816
817        for (var productID in cart_url_object) {
818
819            var product = this.get_product(productID);
820            var quantity = cart_url_object[productID];
821            quantity = parseInt(quantity);
822
823            // Add the product
824            cart[productID] = {
825        		productID: productID,
826        		urlID: product.urlID,
827        		quantity: quantity,
828        	};
829
830        }
831
832        this.cart = cart;
833        this.save_to_localStorage();
834        this.load_from_localStorage();
835
836    },
837    load_from_localStorage: function() {
838
839        if(this.cart_active) {
840
841            var error = '';
842            if(!$(WESTORE.CONFIG.targetElementCart).length) { error += 'CART ERROR - Container element do not exists.\n'; }
843
844            if(error) {
845                WESTORE.clog('CART - Trying to load cart but error occured\n'+error);
846            }
847            else {
848
849                WESTORE.clog("CART - Start, Loaded existing cart: ");
850
851                var cart = {};
852                var cartID = this.cartID;
853
854                if(localStorage[cartID]) {
855                    var string_base64 = localStorage[cartID];
856                    cart = base64url_decode(string_base64);
857                }
858
859                this.local_cart_cleanup(cart);
860                this.cart = cart;
861
862                WESTORE.clog(cart);
863
864                this.render_cart();
865
866                this.cart_is_created = true;
867
868            }
869
870        }
871        else {
872            WESTORE.clog('CART - Inactive');
873        }
874
875    },
876    local_cart_cleanup: function(cart) {
877
878        for (var productID in cart) {
879
880            var remove = true;
881
882            var product_from_cart = cart[productID];
883            var product_from_db = this.get_product(productID);
884
885            // Match check - productID and urlID is used as Keys to compare product from cart exists in productList
886            if(product_from_cart.hasOwnProperty('urlID') && product_from_db.hasOwnProperty('urlID')) {
887                if(product_from_cart.urlID == product_from_db.urlID) {
888                    remove = false;
889                }
890            }
891
892
893            if(remove) {
894                WESTORE.clog('Product do not exists and is removed from cart');
895                WESTORE.clog(cart[productID]);
896                delete cart[productID];
897                this.save_to_localStorage();
898            }
899
900        }
901
902        this.cart = cart;
903
904    },
905    save_to_localStorage: function() {
906
907        var string_base64 = base64url_encode(this.cart);
908        localStorage[this.cartID] = string_base64;
909
910    },
911    render_cart: function() {
912
913        $cartContainer = $(WESTORE.CONFIG.targetElementCart);
914
915        // Cart html
916        html = `
917        <div id='cart' class=''>
918        	<div class='cart-header'>
919        		<span>${this.label_title}</span>
920        		<span class='button-cross button-close'>
921        			<svg xmlns='http://www.w3.org/2000/svg' class='h-6 w-6' fill='none' viewBox='0 0 24 24' stroke='currentColor'><path stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M6 18L18 6M6 6l12 12'></path></svg>
922        		</span>
923        	</div>
924        	<div class='cart-content'>
925        		<div class='product-list'></div>
926        	</div>
927        	<div class='cart-footer'>
928        		<div class='cart-total-sum hide'>
929        			<span class='cart-total-sum-label'>${this.label_total_sum}:</span>
930        			<span class='cart-total-sum-value'></span>
931        		</div>
932        		<a class='buttons button-checkout hide storeContentLoadLinkCheckout' href='${WESTORE.CONFIG.url_root}checkout'>${this.label_button_checkout}</a>
933        		<span class='buttons button-continue button-close'>${this.label_button_close}</span>
934        	</div>
935        </div>
936        `;
937
938        $cartContainer.html(html);
939        this.render_products();
940
941    },
942    render_products: function(cart) {
943
944        var cart = this.cart;
945        var isEmpty = true;
946
947        var html = `
948        <div class='product-item row-header'>
949            <div class='column'></div>
950            <div class='column'></div>
951            <div class='column'>${this.label_table_price}</div>
952            <div class='column'>${this.label_table_sum}</div>
953            <div class='column'></div>
954            <div class='column'></div>
955        </div>
956        `;
957
958
959        for (var productID in cart) {
960
961            var product = this.get_product(productID);
962            var quantity = cart[productID].quantity;
963            var price = product.price;
964            var price_after_deduction = product.price_after_deduction;
965            var priceTotal = price_after_deduction * quantity;
966
967            var display_price_total = WESTORE.get_display_price(priceTotal);
968            var display_price = WESTORE.get_display_price(price);
969            var display_price_after_deduction = WESTORE.get_display_price(price_after_deduction);
970
971            if(price != price_after_deduction) {
972                display_price = `<span class='display-price-before-deduction'>${display_price}</span> <span class='display-price-after-deduction'>${display_price_after_deduction}</span>`;
973            }
974
975            var productImage = `<img src="${WESTORE.CONFIG.url_root}/assets/images/product_thumbnail_320x320.jpg">`;
976            if(product.image) { productImage = `<img src="${WESTORE.CONFIG.url_product_images}picture_thumbs/${product.image}">`; }
977
978            html += `
979            <div class='product-item row' data-productID='${productID}'>
980                <div class='column thumbnail'><a href='${WESTORE.CONFIG.url_root}product/${product.urlID}'>${productImage}</a></div>
981                <div class='column'>${product.title}</div>
982                <div class='column'>${display_price}</div>
983                <div class='column total'>${display_price_total}</div>
984                <div class='column'><input class='quantity' type='number' min='1' max='999' value='${quantity}'></input></div>
985                <div class='column'><div class='icon icon-bin removeButton'></div></div>
986            </div>
987            `;
988
989        }
990
991        $("#cart .product-list").html(html);
992        this.render_summary_values();
993
994    },
995    render_summary_values: function() {
996
997        var cart = this.cart;
998        var counter = 0;
999        var priceTotal = 0;
1000        var $widgetCounter = $(".storeWidgetTarget-cartButtonCounter");
1001
1002        for (var productID in cart) {
1003            var product = this.get_product(productID);
1004            priceTotal += (product.price_after_deduction * cart[productID].quantity);
1005            counter += cart[productID].quantity;
1006        }
1007
1008        priceTotal = WESTORE.get_display_price(priceTotal);
1009
1010        $("#cart .cart-total-sum-value").html(priceTotal);
1011        $widgetCounter.html(counter); // The global icon
1012
1013        if(counter > 0) {
1014            $("#cart .cart-total-sum").removeClass('hide');
1015            $("#cart .button-checkout").removeClass('hide');
1016            $widgetCounter.removeClass('hide'); // The global icon
1017        }
1018        else {
1019            $("#cart .cart-total-sum").addClass('hide');
1020            $("#cart .button-checkout").addClass('hide');
1021            $("#cart .product-list").html('<div class="empty">'+this.label_cart_empty+'</div>');
1022
1023            $widgetCounter.addClass('hide'); // The global icon
1024        }
1025
1026    },
1027    get_base64_string: function() {
1028
1029        var cart = this.cart;
1030        var products = {};
1031
1032        for (var productID in cart) {
1033            products[productID] = cart[productID].quantity;
1034        }
1035
1036        return btoa(JSON.stringify(products));
1037
1038    },
1039    get_url: function() {
1040
1041        var base64string = this.get_base64_string();
1042        return base64url_encode(base64string);
1043
1044    },
1045    jQueryActions: function() {
1046
1047        $("body").on("click", "#cart .button-close", function(e) {
1048            $("#cart").css('display', 'none');
1049        });
1050
1051        // Remove button clicked
1052        $("body").on("click", "#cart .product-item .removeButton", function(e) {
1053
1054            e.preventDefault();
1055            var productID = $(this).parents('.product-item').attr('data-productID');
1056
1057            // Remove from cart data
1058            WESTORE.CART.remove(productID);
1059
1060        });
1061
1062        // Quantity change
1063        $("body").on("change", "#cart .product-item .quantity", function(e) {
1064
1065            e.preventDefault();
1066
1067            var $input = $(this);
1068            var $productItem = $input.parents('.product-item');
1069            var productID = $productItem.attr('data-productID');
1070            var quantity = parseInt($input.val());
1071
1072            WESTORE.CART.quantity_change(productID, quantity);
1073
1074
1075        });
1076
1077        // When document is clicked
1078        $(document).mousedown(function(event) {
1079
1080            // Check if event action was left mouse button
1081            if(event.which == 1) {
1082                var $clickedTarget = $(event.target);
1083                if($clickedTarget.attr("id") != "cart" && !$clickedTarget.parents("#cart").length) {
1084                    $('#cart').css('display', 'none');
1085                }
1086            }
1087
1088        });
1089
1090    }
1091
1092};
1093WESTORE.CHECKOUT = {
1094    label_title_cart: 'Cart',
1095    label_title_payment: 'Shipping & payment',
1096    label_table_price: 'Price',
1097    label_table_sum: 'Total',
1098    label_cart_empty: 'Your cart is empty',
1099    label_total_sum: 'Total price',
1100    label_total_sum_before: 'Price before discount',
1101    label_total_discount: 'Discount',
1102    label_discountcode_input: 'Discount code',
1103    label_discountcode_button: 'Register',
1104    label_button_back_cart: 'Change',
1105    label_button_payment: 'Go to payment',
1106    label_productOutStock: 'Out of stock',
1107    order_total_sum: 0,
1108    discount_applied_code: '',
1109    discount_applied_data: {},
1110    init: function(data) {
1111
1112        if(data.label_title_cart) { this.label_title_cart = data.label_title_cart; }
1113        if(data.label_title_payment) { this.label_title_payment = data.label_title_payment; }
1114        if(data.label_table_price) { this.label_table_price = data.label_table_price; }
1115        if(data.label_table_sum) { this.label_table_sum = data.label_table_sum; }
1116        if(data.label_total_sum) { this.label_total_sum = data.label_total_sum; }
1117        if(data.label_total_sum_before) { this.label_total_sum_before = data.label_total_sum_before; }
1118        if(data.label_total_discount) { this.label_total_discount = data.label_total_discount; }
1119        if(data.label_discountcode_input) { this.label_discountcode_input = data.label_discountcode_input; }
1120        if(data.label_discountcode_button) { this.label_discountcode_button = data.label_discountcode_button; }
1121        if(data.label_button_back_cart) { this.label_button_back_cart = data.label_button_back_cart; }
1122        if(data.label_button_payment) { this.label_button_payment = data.label_button_payment; }
1123        if(data.label_productOutStock) { this.label_productOutStock = data.label_productOutStock; }
1124
1125        $(function() {
1126            WESTORE.CHECKOUT.jQueryActions();
1127        });
1128
1129    },
1130    quantity_change: function(productID, quantity) {
1131
1132        var cart = this.cart;
1133        if(cart.hasOwnProperty(productID)) {
1134
1135            quantity = parseInt(quantity);
1136            if(!quantity || quantity < 1) { quantity = 1; }
1137            else if (quantity > 999) { quantity = 999; }
1138
1139            var product = WESTORE.CART.get_product(productID);
1140            var price = product.price;
1141            var total = price * quantity;
1142            total = WESTORE.get_display_price(total);
1143
1144            // Update cart html
1145            var $productItem = $("#cart .product-item[data-productID='"+productID+"']");
1146            var $input = $productItem.find('input.quantity');
1147            $input.val(quantity)
1148            $productItem.find('.total').html(total);
1149
1150            // Update checkout html
1151            var $productItem = $("#checkout .product-item[data-productID='"+productID+"']");
1152            var $input = $productItem.find('input.quantity');
1153            $input.val(quantity)
1154            $productItem.find('.total').html(total);
1155
1156            // Update cart quantity
1157            if(cart.hasOwnProperty(productID)) {
1158                this.cart[productID].quantity = quantity;
1159            }
1160
1161            WESTORE.clog('Product quantity was updated in the cart');
1162            WESTORE.clog(cart[productID]);
1163
1164            this.save_to_localStorage();
1165            this.render_summary_values();
1166
1167        }
1168
1169    },
1170    remove: function(productID) {
1171
1172        var cart = this.cart;
1173        if(cart.hasOwnProperty(productID)) {
1174
1175            // Remove element
1176            var $productItem = $("#cart .product-item[data-productID='"+productID+"']");
1177            $productItem.remove();
1178
1179            // Update checkout html
1180            var $productItem = $("#checkout .product-item[data-productID='"+productID+"']");
1181            $productItem.remove();
1182
1183            WESTORE.clog('Product was removed from the cart');
1184            WESTORE.clog(cart[productID]);
1185
1186            delete cart[productID];
1187            this.save_to_localStorage();
1188            this.render_summary_values();
1189
1190        }
1191
1192    },
1193    render_page: function() {
1194
1195        // Resets discount code
1196        WESTORE.CHECKOUT.discount_applied_code = '';
1197        WESTORE.CHECKOUT.discount_applied_data = {};
1198
1199        html = `
1200        <div id="checkout" class="store-content">
1201    		<div class="section section-cart open">
1202    			<div class="title">${this.label_title_cart}</div>
1203    			<div class="content">
1204    				<div class="product-list"></div>
1205                    <div class="checkout-discountcode">
1206                        <input type="text" placeholder="${this.label_discountcode_input}">
1207                        <div class="button-discountcode">${this.label_discountcode_button}</div>
1208                        <div class="checkout-discountcode-response"></div>
1209                    </div>
1210    				<div class="content-footer hide">
1211                        <div class="content-footer-left">
1212                            <div class="checkout-total-table">
1213                                <div class='checkout-total-tr checkout-total-discount-tr hide'>
1214                                    <div class='checkout-total-td'>${this.label_total_sum_before}:</div>
1215                                    <div class='checkout-total-td checkout-total-value-before'></div>
1216                                </div>
1217                                <div class='checkout-total-tr checkout-total-discount-tr hide'>
1218                                    <div class='checkout-total-td'>${this.label_total_discount}:</div>
1219                                    <div class='checkout-total-td checkout-total-value-discount'></div>
1220                                </div>
1221                                <div class='checkout-total-tr'>
1222                                    <div class='checkout-total-td'>${this.label_total_sum}:</div>
1223                                    <div class='checkout-total-td checkout-total-value-sum'></div>
1224                                </div>
1225                            </div>
1226                        </div>
1227                        <div class="content-footer-right">
1228                            <button class="button button-next">${this.label_button_payment}</button>
1229                        </div>
1230    				</div>
1231    			</div>
1232                <div class="error-content"></div>
1233    			<div><button class="button button-change">${this.label_button_back_cart}</button></div>
1234    		</div>
1235
1236    		<div class="section section-payment hide">
1237    			<div class="title">${this.label_title_payment}</div>
1238    			<div class="content">
1239    				<div class="klarna-placeholder">
1240    					<!-- Klarna loads here -->
1241    				</div>
1242    			</div>
1243                <div class="error-content"></div>
1244    		</div>
1245    	</div>
1246        `;
1247
1248        if(WESTORE.CONFIG.store_load_method == "CMS" || WESTORE.CONFIG.store_load_method == "LIVE_INTERNAL") {
1249            html = `
1250            <div class="row_content">
1251                ${html}
1252            </div>
1253            `;
1254        }
1255
1256        $(WESTORE.CONFIG.targetElement).html(html);
1257
1258        WESTORE.CHECKOUT.wait_for_cart(function(status) {
1259            if(status == "success") {
1260                WESTORE.CHECKOUT.render_product_list();
1261            }
1262            else {
1263                WESTORE.clog("CHECKOUT - Products did not load from cart, something went wrong.");
1264            }
1265        });
1266
1267    },
1268    render_product_list: function() {
1269
1270        var cart = WESTORE.CART.cart;
1271        var productsFound = false;
1272
1273        var html = `
1274        <div class='product-item row-header'>
1275            <div class='column'></div>
1276            <div class='column'></div>
1277            <div class='column'>${this.label_table_price}</div>
1278            <div class='column'>${this.label_table_sum}</div>
1279            <div class='column'></div>
1280            <div class='column'></div>
1281            <div class='column'></div>
1282        </div>
1283        `;
1284
1285        for (var productID in cart) {
1286
1287            productsFound = true;
1288            var product = WESTORE.CART.get_product(productID);
1289            var quantity = cart[productID].quantity;
1290            var price = product.price;
1291            var price_after_deduction = product.price_after_deduction;
1292            var priceTotal = price_after_deduction * quantity;
1293
1294            var display_price_total = WESTORE.get_display_price(priceTotal);
1295            var display_price = WESTORE.get_display_price(price);
1296            var display_price_after_deduction = WESTORE.get_display_price(price_after_deduction);
1297
1298            if(price != price_after_deduction) {
1299                display_price = `<span class='display-price-before-deduction'>${display_price}</span> <span class='display-price-after-deduction'>${display_price_after_deduction}</span>`;
1300            }
1301
1302            var productImage = `<img src="${WESTORE.CONFIG.url_root}/assets/images/product_thumbnail_320x320.jpg">`;
1303            if(product.image) { productImage = `<img src="${WESTORE.CONFIG.url_product_images}picture_thumbs/${product.image}">`; }
1304
1305            html += `
1306            <div class='product-item row' data-productID='${productID}'>
1307                <div class='column thumbnail'><a href='${WESTORE.CONFIG.url_cms_root}product/${product.urlID}'>${productImage}</a></div>
1308                <div class='column'>${product.title}</div>
1309                <div class='column'>${display_price}</div>
1310                <div class='column total'>${display_price_total}</div>
1311                <div class='column'><input class='quantity' type='number' min='1' max='999' value='${quantity}'></input></div>
1312                <div class='column'><div class='icon icon-bin removeButton'></div></div>
1313            </div>
1314            `;
1315
1316        }
1317
1318        if(productsFound) {
1319            $("#checkout .product-list").html(html);
1320            $("#checkout .section-cart .content-footer").removeClass('hide');
1321            $("#checkout .section.section-payment").removeClass('hide');
1322            this.render_summary_values();
1323        }
1324
1325    },
1326    render_summary_values: function() {
1327
1328        var cart = WESTORE.CART.cart;
1329        var productsFound = false;
1330        var discount_amount_exists = false;
1331        var discount_data = this.discount_applied_data;
1332        var price_total_sum = 0;
1333
1334        for (var productID in cart) {
1335            var product = WESTORE.CART.get_product(productID);
1336            var quantity = cart[productID].quantity;
1337            var price = product.price;
1338            var price_after_deduction = product.price_after_deduction;
1339            var price_total = price_after_deduction * quantity;
1340
1341            price_total_sum += price_total;
1342            productsFound = true;
1343
1344        }
1345
1346        this.order_total_sum = price_total_sum;
1347
1348        if(productsFound) {
1349
1350            // Check if discount percent or amount will change final sum
1351            if(discount_data.hasOwnProperty('code')) {
1352                var discount_types = ["P", "A", "G"];
1353                if(discount_types.includes(discount_data.type)) {
1354                    if(discount_data.type == "P" && discount_data.percent > 0) { discount_amount_exists = true; }
1355                    else if(discount_data.amount > 0) { discount_amount_exists = true; }
1356                }
1357            }
1358
1359            // Apply discount
1360            if(discount_amount_exists) {
1361
1362                var price_total_sum_discount = 0;
1363                var discount_amount_left = 0;
1364
1365                if(discount_data.type == "P") { price_total_sum_discount = price_total_sum * (discount_data.percent / 100); }
1366                else { price_total_sum_discount = discount_data.amount; }
1367
1368                price_total_sum_discount = this.round_decimals(price_total_sum_discount);
1369
1370                discount_amount_left = price_total_sum_discount - price_total_sum;
1371                if(discount_amount_left < 0) { discount_amount_left = 0; }
1372
1373                if(price_total_sum_discount > price_total_sum) { price_total_sum_discount = price_total_sum; }
1374
1375                var price_total_sum_before = price_total_sum;
1376                price_total_sum = price_total_sum - price_total_sum_discount;
1377
1378                var price_total_sum_before_string = WESTORE.get_display_price(price_total_sum_before);
1379                var price_total_sum_discount_string = WESTORE.get_display_price(price_total_sum_discount);
1380                $("#checkout .checkout-total-value-discount").html("-"+price_total_sum_discount_string);
1381                $("#checkout .checkout-total-value-before").html(price_total_sum_before_string);
1382
1383                if(discount_data.type == "G") {
1384                    var discount_amount_left_string = `(${discount_amount_left}kr kvar)`;
1385                    if(WESTORE.CONFIG.country == "US") { discount_amount_left_string = `($${discount_amount_left} remaining)`; }
1386                    $("#checkout .checkout-discountcode-response .type-giftcard").html(discount_amount_left_string);
1387                }
1388
1389            }
1390
1391            var price_total_sum_string = WESTORE.get_display_price(price_total_sum);
1392            $("#checkout .checkout-total-value-sum").html(price_total_sum_string);
1393
1394            $("#checkout .section-cart .content-footer").removeClass('hide');
1395            $("#checkout .section.section-payment").removeClass('hide');
1396        }
1397        else {
1398            $("#checkout .section-cart .content-footer").addClass('hide');
1399            $("#checkout .section.section-payment").addClass('hide');
1400            $("#checkout .product-list").html('<div class="empty">'+WESTORE.CART.label_cart_empty+'</div>');
1401        }
1402
1403        if(discount_amount_exists) {
1404            $("#checkout .checkout-total-discount-tr").removeClass("hide");
1405        }
1406        else {
1407            $("#checkout .checkout-total-discount-tr").addClass("hide");
1408        }
1409
1410
1411    },
1412    render_confirmation_page: function() {
1413
1414        var urlObject = window.location;
1415        var url_params = new URLSearchParams(urlObject.search);
1416        var html = "";
1417
1418        var siteID = '';
1419        var orderID = '';
1420        if(url_params.has('id')) { siteID = url_params.get('id'); }
1421        if(url_params.has('order_id')) { orderID = url_params.get('order_id'); }
1422
1423        // Resets discount code
1424        WESTORE.CHECKOUT.discount_applied_code = '';
1425        WESTORE.CHECKOUT.discount_applied_data = {};
1426
1427        // Fetch order confirmation page from API
1428        if(siteID && orderID) {
1429
1430            var url = WESTORE.CONFIG.url_domain_api+"/checkout/confirmation";
1431    		var postPara = {'siteID': siteID, 'klarna_order_id': orderID};
1432
1433    		$.post(url, postPara, function(jsonResponse){
1434
1435				if (jsonResponse.status == "success") {
1436
1437					html = jsonResponse.html_snippet;
1438
1439				}
1440                // If klarna confirmation page could not be generated then provide a generic confirmation page
1441				else {
1442
1443                    var orderIDstring = '';
1444
1445                    if(WESTORE.CONFIG.country == "US") {
1446
1447                        if(orderID) {
1448                            orderIDstring = `
1449                            <br><br><br>Your order id is: ${orderID}
1450                            <br><b>${orderID}</b>
1451                            `;
1452                        }
1453
1454                        html = `
1455                        <h1>Thank you for your order!</h1>
1456                        <div class='checkout-confirmation-content'>
1457                            We will now start to process your order.<br>
1458                            A confirmation email from Klarna will be sent to you.
1459                            ${orderIDstring}
1460                        </div>
1461                        `;
1462
1463                    }
1464                    else {
1465
1466                        if(orderID) {
1467                            orderIDstring = `
1468                            <br><br><br>Ditt ordernummer är:
1469                            <br><b>${orderID}</b>
1470                            `;
1471                        }
1472
1473                        html = `
1474                        <h1>Tack för din beställning!</h1>
1475                        <div class='checkout-confirmation-content'>
1476                            Vi kommer nu att börja behandla din beställning.<br>
1477                            Ett bekräftelsemail från klarna kommer skickas till dig.
1478                            ${orderIDstring}
1479                        </div>
1480                        `;
1481
1482                    }
1483
1484				}
1485
1486                html = `
1487                <div id="checkout-confirmation" class="store-content">
1488                    ${html}
1489                </div>
1490                `;
1491
1492                if(WESTORE.CONFIG.store_load_method == "CMS" || WESTORE.CONFIG.store_load_method == "LIVE_INTERNAL") {
1493                    html = `
1494                    <div class="row_content">
1495                        ${html}
1496                    </div>
1497                    `;
1498                }
1499
1500                $(WESTORE.CONFIG.targetElement).html(html);
1501                WESTORE.CART.remove_all();
1502
1503    		});
1504
1505        }
1506
1507    },
1508    wait_for_cart: function(callBackFunction) {
1509
1510        var counter = 0;
1511        var interval = window.setInterval(function() {
1512
1513            if(WESTORE.CART.cart_is_created) {
1514                window.clearInterval(interval);
1515                callBackFunction('success');
1516            }
1517            else if(counter >= 1000) {
1518                window.clearInterval(interval);
1519                callBackFunction('failed'); // Error
1520            }
1521            counter++;
1522
1523        }, 10);
1524
1525    },
1526    round_decimals: function(price) {
1527
1528        // Cut down to 2 decimals
1529        if(price && !Number.isInteger(price)) {
1530            price = Math.round(price * 100) / 100;
1531            price = price.toFixed(2);
1532            price = parseFloat(price);
1533        }
1534
1535        return price;
1536
1537    },
1538    jQueryActions: function() {
1539
1540        var klarna_order_id = '';
1541
1542		// Remove button clicked
1543	    $("body").on("click", "#checkout .product-item .removeButton", function(e) {
1544
1545	        e.preventDefault();
1546			var productID = $(this).parents('.product-item').attr('data-productID');
1547            WESTORE.CHECKOUT.remove(productID);
1548	        WESTORE.CART.remove(productID);
1549
1550	    });
1551
1552		// Quantity change
1553	    $("body").on("change", "#checkout .product-item .quantity", function(e) {
1554
1555	        e.preventDefault();
1556			var $input = $(this);
1557			var $productItem = $input.parents('.product-item');
1558			var productID = $productItem.attr('data-productID');
1559            var quantity = parseInt($input.val());
1560	        WESTORE.CHECKOUT.quantity_change(productID, quantity);
1561            WESTORE.CART.quantity_change(productID, quantity);
1562
1563	    });
1564
1565        // Cart button clicked
1566        var discount_code_inputed = '';
1567        $("body").on("click", "#checkout .button-discountcode", function(e) {
1568
1569            var code = $("#checkout .checkout-discountcode input").val();
1570
1571            if(!code) {
1572                discount_code_inputed = '';
1573                WESTORE.CHECKOUT.discount_applied_code = '';
1574                WESTORE.CHECKOUT.discount_applied_data = {};
1575                $("#checkout .checkout-discountcode-response").html("");
1576                WESTORE.CHECKOUT.render_summary_values();
1577            }
1578            else if(code != discount_code_inputed) {
1579
1580                discount_code_inputed = code;
1581
1582                var url_api = WESTORE.CONFIG.url_domain_api+"/discountcode/get";
1583                var order_amount = WESTORE.CHECKOUT.order_total_sum;
1584
1585                var langCode = 'se';
1586                if(WESTORE.CONFIG.country == "US") { langCode = 'en'; }
1587
1588                WESTORE.CHECKOUT.discount_applied_code = '';
1589                WESTORE.CHECKOUT.discount_applied_data = {};
1590
1591                $.ajax({
1592                    dataType: "json",
1593                    url: url_api,
1594                    type: "post",
1595                	data: {id: siteData.apiID, code: code, order_amount: order_amount, langCode: langCode},
1596                    cache: false,
1597                    success: function(jsonResponse) {
1598
1599                        // Success
1600                        if(jsonResponse.status == 'success') {
1601
1602                            var discountData = jsonResponse.discountcode_data;
1603                            var amount_string = "";
1604                            if(discountData.type == "P") { amount_string = `${discountData.percent}%`; }
1605                            else {
1606
1607                                if(WESTORE.CONFIG.country == "US") { amount_string = `$${discountData.amount}`; }
1608                                else { amount_string = `${discountData.amount}kr`; }
1609
1610                                if(discountData.type == "G") { amount_string = `${amount_string} <span class='type-giftcard'></span>`; }
1611                            }
1612
1613                            $("#checkout .checkout-discountcode-response").html(`<span class='success'>${discountData.code} ${amount_string}</span>`);
1614                            WESTORE.CHECKOUT.discount_applied_code = discountData.code;
1615                            WESTORE.CHECKOUT.discount_applied_data = discountData;
1616
1617                        }
1618                        // Error
1619                        else {
1620
1621                            $("#checkout .checkout-discountcode-response").html("<span class='error'>"+jsonResponse.error_log_message+"</span>");
1622
1623                        }
1624
1625                        if(jsonResponse.hasOwnProperty('devMessages')) {
1626                            WESTORE.clog(jsonResponse.devMessages);
1627                        }
1628
1629                        WESTORE.CHECKOUT.render_summary_values();
1630
1631                    },
1632                    error: function (xhr, ajaxOptions, thrownError) {
1633
1634                        $("#checkout .checkout-discountcode-response").html("<span class='error'>Load error x38101</span>");
1635                        WESTORE.clog('CHECKOUT PAYMENT - Ajax error (Status: '+xhr.status+') (Error: '+thrownError+')');
1636                        WESTORE.CHECKOUT.render_summary_values();
1637
1638                    }
1639
1640                });
1641
1642            }
1643
1644        });
1645
1646		// Button - Cart change
1647        $("body").on("click", "#checkout .section-cart .button-change", function(e) {
1648
1649			$("#checkout .section").removeClass("open").removeClass("completed").removeClass("error");
1650			$("#checkout .section-cart").addClass("open");
1651			$("#checkout .section-payment .klarna-placeholder").html("");
1652			$(document).scrollTop(0);
1653
1654		});
1655
1656		// Button - Go to payment
1657        $("body").on("click", ".section-cart .button-next", function(e) {
1658
1659			if(!WESTORE.CART.is_cart_empty()) {
1660
1661                $("#checkout .section").removeClass("open").removeClass("completed").removeClass("error");
1662				$("#checkout .section-cart").addClass("completed");
1663
1664				$(document).scrollTop(0);
1665
1666                var error_title = "Woopsie Daisy!";
1667                var error_subtitle = "Looks like we hit a bump";
1668                var error_subtitle_multiple = "Looks like we hit a few bumps";
1669                var error_subtitle_end = "We are so sorry this happend!<br>If you need our help, please feel free to contact our support!";
1670
1671                var order_id = klarna_order_id;
1672                var discountcode = WESTORE.CHECKOUT.discount_applied_code;
1673                var cart_items = WESTORE.CART.get_base64_string();
1674                var postURL = WESTORE.CONFIG.url_cms_root+"load/content/checkout/payment?order_id="+order_id+"&discountcode="+discountcode+"&cart_items="+cart_items;
1675                checkoutPaymentResponseData = {};
1676
1677                WESTORE.clog("CHECKOUT PAYMENT - Loading klarna...");
1678
1679                // Call Javascript file
1680                $.ajax({
1681                    dataType: "script",
1682                    url: postURL,
1683                    cache: false,
1684                    success: function(jsContentResponse) {
1685
1686                        var html = '';
1687                        var error = false;
1688                        var error_content = '';
1689                        var error_target = 'payment';
1690
1691                        if (!checkoutPaymentResponseData.hasOwnProperty('data')) {
1692                            error = true;
1693                            error_content = 'No response data';
1694                            WESTORE.clog('CHECKOUT PAYMENT - Ajax error (No response data)');
1695                        }
1696                        else {
1697
1698                            var data = checkoutPaymentResponseData.data;
1699
1700                            // Success
1701                            if(data.status == 'success') {
1702                                if(data.klarnaResponse.hasOwnProperty('order_id')) {
1703                                    klarna_order_id = data.klarnaResponse.order_id;
1704                                }
1705    							if(data.klarnaResponse.hasOwnProperty('html_snippet')) {
1706                                    html = data.klarnaResponse.html_snippet;
1707                                    $("#checkout .section-payment .klarna-placeholder").html(html);
1708                                    $("#checkout .section-payment").addClass("open");
1709                                }
1710    						}
1711                            // Error
1712                            else {
1713
1714                                error = true;
1715
1716                                if(data.hasOwnProperty('errorMessages')) {
1717                                    for (var i = 0; i < data.errorMessages.length; i++) {
1718                                        error_content += '<li>'+data.errorMessages[i]+'</li>';
1719                                    }
1720                                    if(data.errorMessages.length > 1) { error_subtitle = error_subtitle_multiple; }
1721                                }
1722
1723                                // Error status: error-products
1724                                if(data.status == 'error-products') {
1725                                    error_subtitle_end = "We are so sorry!<br>Could you be so kind and see if you can adjust this.<br>If not possible, please feel free to contact our support!";
1726                                    error_target = 'cart';
1727                                }
1728                                // Error status: error-load-payment
1729                                else {
1730                                    error_target = 'vart';
1731                                }
1732
1733                            }
1734
1735                            if(data.hasOwnProperty('devMessages')) {
1736                                WESTORE.clog(data.devMessages);
1737                            }
1738
1739                        }
1740
1741                        if(error) {
1742
1743                            html = `
1744                            <div class='checkout-load-payment-error'>
1745                                <div class='checkout-load-payment-error-title'>${error_title}</div>
1746                                <div class='checkout-load-payment-error-subtitle'>${error_subtitle}</div>
1747                                <div class='checkout-load-payment-error-content'>${error_content}</div>
1748                                <div class='checkout-load-payment-error-subtitle-end'>${error_subtitle_end}</div>
1749                            </div>
1750                            `;
1751
1752                            if(error_target == 'cart') {
1753                                $("#checkout .section-cart").addClass("error");
1754                                $("#checkout .section-cart .error-content").html(html);
1755                            }
1756                            else {
1757                                $("#checkout .section-payment").addClass("error");
1758                                $("#checkout .section-payment .error-content").html(html);
1759                            }
1760
1761                        }
1762
1763                    },
1764                    error: function (xhr, ajaxOptions, thrownError) {
1765
1766                        var html = `
1767                        <div class='checkout-load-payment-error'>
1768                            <div class='checkout-load-payment-error-title'>${error_title}</div>
1769                            <div class='checkout-load-payment-error-subtitle'>${error_subtitle}</div>
1770                            <div class='checkout-load-payment-error-content'>Load error x38101</div>
1771                            <div class='checkout-load-payment-error-subtitle-end'>${error_subtitle_end}</div>
1772                        </div>
1773                        `;
1774
1775                        $("#checkout .section-payment").addClass("error");
1776                        $("#checkout .section-payment .error-content").html(html);
1777                        WESTORE.clog('CHECKOUT PAYMENT - Ajax error (Status: '+xhr.status+') (Error: '+thrownError+')');
1778
1779                    }
1780
1781                });
1782
1783			}
1784
1785		});
1786
1787    }
1788
1789};
1790WESTORE.PRODUCT_LIST = {
1791    called_files: {},
1792    lazyLoad: false,
1793    langCode: 'en',
1794    max_price: 100,
1795    sortID_default: 1001,
1796    label_items_count: 'products found in',
1797    label_items_empty: 'No products here',
1798    label_search_placeholder: 'Search',
1799    label_range_price: 'Price',
1800    label_range_price_unit: '$',
1801    label_range_to: 'to',
1802    label_filter_reset: 'Reset filters',
1803    label_filter_show: 'Show filters',
1804    label_filter_hide: 'Show hits',
1805    label_filter_expand: 'Show more...',
1806    label_filter_collapse: 'Show less...',
1807    label_filter_vendor: 'Brand',
1808    label_sort_title_asc: 'Name, A-Z',
1809    label_sort_title_desc: 'Name, Z-A',
1810    label_sort_brand_asc: 'Brand, A-Z',
1811    label_sort_brand_desc: 'Brand, Z-A',
1812    label_sort_price_asc: 'Price, lowest first',
1813    label_sort_price_desc: 'Price, highest first',
1814    init: function(data) {
1815
1816        if(data.langCode) { this.langCode = data.langCode; }
1817        if(data.max_price) { this.max_price = data.max_price; }
1818        if(data.sortID_default) { this.sortID_default = data.sortID_default; }
1819
1820        if(data.label_items_count) { this.label_items_count = data.label_items_count; }
1821        if(data.label_items_empty) { this.label_items_empty = data.label_items_empty; }
1822        if(data.label_search_placeholder) { this.label_search_placeholder = data.label_search_placeholder; }
1823
1824        if(data.label_range_price) { this.label_range_price = data.label_range_price; }
1825        if(data.label_range_price_unit) { this.label_range_price_unit = data.label_range_price_unit; }
1826        if(data.label_range_to) { this.label_range_to = data.label_range_to; }
1827
1828        if(data.label_filter_reset) { this.label_filter_reset = data.label_filter_reset; }
1829        if(data.label_filter_show) { this.label_filter_show = data.label_filter_show; }
1830        if(data.label_filter_hide) { this.label_filter_hide = data.label_filter_hide; }
1831        if(data.label_filter_expand) { this.label_filter_expand = data.label_filter_expand; }
1832        if(data.label_filter_collapse) { this.label_filter_collapse = data.label_filter_collapse; }
1833        if(data.label_filter_vendor) { this.label_filter_vendor = data.label_filter_vendor; }
1834
1835        if(data.label_sort_title_asc) { this.label_sort_title_asc = data.label_sort_title_asc; }
1836        if(data.label_sort_title_desc) { this.label_sort_title_desc = data.label_sort_title_desc; }
1837        if(data.label_sort_brand_asc) { this.label_sort_brand_asc = data.label_sort_brand_asc; }
1838        if(data.label_sort_brand_desc) { this.label_sort_brand_desc = data.label_sort_brand_desc; }
1839        if(data.label_sort_price_asc) { this.label_sort_price_asc = data.label_sort_price_asc; }
1840        if(data.label_sort_price_desc) { this.label_sort_price_desc = data.label_sort_price_desc; }
1841
1842        this.lazyLoad = data.lazyLoad;
1843
1844        $(function() {
1845            WESTORE.PRODUCT_LIST.jQueryActions();
1846        });
1847
1848    },
1849    load_file_lists: function(lists, callBackFunction) {
1850
1851        //  lists = productListPageSets = {
1852        //      101: {1: {loaded: false}, 2: {loaded: false}},
1853        //      102: {1: {loaded: false}},
1854        //      103: {1: {loaded: false}, 2: {loaded: false}, 3: {loaded: false}},
1855        //  }
1856
1857        var url = WESTORE.CONFIG.url_script_product_list;
1858
1859        for (let listID in lists) {
1860
1861            if(productListPageSets.hasOwnProperty(listID)) {
1862
1863                var list = lists[listID];
1864
1865                // Loop sets in current list
1866                for (let setID in list) {
1867
1868                    var fileID = `${listID}-${setID}`;
1869
1870                    if(!list[setID].loaded) {
1871
1872                        if(productListDataRaw.hasOwnProperty(fileID)) {
1873                            productListPageSets[listID][setID].loaded = true;
1874                        }
1875                        else {
1876
1877                            WESTORE.clog_time_start('FILE('+fileID+') LOAD DONE. TIME'); // This time is not accurate to client network time
1878
1879                            // Load the JavaScript file
1880                            $.ajax({
1881                                dataType: "script",
1882                                url: url.replace('#fileID#', fileID),
1883                                cache: true,
1884                                success: function(jsRespons) {
1885                                    productListPageSets[listID][setID].loaded = true;
1886                                    WESTORE.clog_time_end('FILE('+listID+'-'+setID+') LOAD DONE. TIME'); // This time is not accurate to client network time
1887                                },
1888                                error: function (xhr, ajaxOptions, thrownError) {
1889                                    WESTORE.clog_time_end('FILE('+listID+'-'+setID+') LOAD DONE. TIME');
1890                                    WESTORE.clog('FILE LOAD('+listID+'-'+setID+') STATUS: Failed, time out! (Status: '+xhr.status+') (Error: '+thrownError+')');
1891                                }
1892                            });
1893
1894                        }
1895
1896                    }
1897
1898                }
1899
1900            }
1901
1902        }
1903
1904        var counter = 0;
1905        var interval = 10;
1906        var timout_seconds = 60;
1907        var timout_number = timout_seconds * 1000 / interval;
1908        var interval = window.setInterval(function() {
1909
1910            let allLoaded = true;
1911
1912            for (let listID in lists) {
1913
1914                let list = lists[listID];
1915                for (let setID in list) {
1916                    if(!list[setID].loaded) {
1917                        allLoaded = false;
1918                        break;
1919                    }
1920                }
1921
1922            }
1923
1924            if(allLoaded) {
1925                window.clearInterval(interval);
1926                WESTORE.PRODUCT_LIST.load_file__process_list(lists, callBackFunction);
1927            }
1928            else if(counter >= timout_number) {
1929                window.clearInterval(interval);
1930                callBackFunction('failed'); // Error
1931            }
1932
1933            counter++;
1934
1935        }, 10);
1936
1937    },
1938    load_file__process_list: function(lists, callBackFunction) {
1939
1940        for (let listID in lists) {
1941
1942            let list = lists[listID];
1943
1944            if(!productListData.hasOwnProperty(listID)) {
1945
1946                WESTORE.clog_time_start('RAW DATA PROCESS('+listID+') TIME');
1947
1948                var listData = {
1949                    'page_data': [],
1950                    'products': []
1951                };
1952
1953                var page_data = {};
1954                var products = [];
1955                var products_object = {};
1956
1957                // Loop sets in current list
1958                for (let setID in list) {
1959
1960                    let fileID = `${listID}-${setID}`;
1961                    if(productListDataRaw.hasOwnProperty(fileID)) {
1962
1963                        if(setID == "pagedata") {
1964                            page_data = productListDataRaw[fileID];
1965                        }
1966                        else {
1967
1968                            let productsRaw = productListDataRaw[fileID];
1969
1970                            // Loop all products in the file list
1971                            for (let i = 0; i < productsRaw.length; i++) {
1972                                let product = this.data__product_array_to_object(productsRaw[i]);
1973                                if(listID == 'all') { products_object[ product['id'] ] = product; }
1974                                products.push(product);
1975                            }
1976
1977                        }
1978
1979                    }
1980
1981                }
1982
1983                listData['page_data'] = page_data;
1984                listData['products'] = products;
1985                if(listID == 'all') { listData['products_object'] = products_object; }
1986
1987                productListData[listID] = listData;
1988
1989                WESTORE.clog('RAW DATA PROCESS('+listID+') PRODUCTS: '+products.length);
1990                WESTORE.clog_time_end('RAW DATA PROCESS('+listID+') TIME');
1991
1992                // Start background loading products for remaning pages
1993                if(listID == 'all') {
1994                    WESTORE.clog('START LOADING ALL productListData LISTS...');
1995                    WESTORE.clog_time_start('LOADING ALL productListData TIME');
1996                    WESTORE.PRODUCT_LIST.load_file_lists(productListPageSets, function(){
1997                        WESTORE.clog('DONE LOADING ALL productListData LISTS!');
1998                        WESTORE.clog_time_end('LOADING ALL productListData TIME');
1999                    });
2000                }
2001
2002            }
2003
2004        }
2005
2006        callBackFunction('success');
2007
2008    },
2009    wait_for_list: function(listID, callBackFunction) {
2010
2011        var counter = 0;
2012        var interval = 10;
2013        var timout_seconds = 10;
2014        var timout_number = timout_seconds * 1000 / interval;
2015        var interval = window.setInterval(function() {
2016
2017            if(productListData.hasOwnProperty(listID)) {
2018                window.clearInterval(interval);
2019                callBackFunction('success');
2020            }
2021            else if(counter >= timout_number) {
2022                window.clearInterval(interval);
2023                callBackFunction('failed'); // Error
2024            }
2025            counter++;
2026
2027        }, 10);
2028
2029    },
2030    data__product_array_to_object: function(product) {
2031        return {
2032            'id': product[0],
2033            'urlID': product[1],
2034            'barcode': product[2],
2035            'title': product[3],
2036            'vendor': product[4],
2037            'price': product[5],
2038            'price_deduction': product[6],
2039            'tax': product[7],
2040            'image': product[8]
2041        };
2042    },
2043    render: function(pageData, url_base) {
2044
2045        var render__rowHeader = function (invObj) {
2046
2047            return ``;
2048
2049        }
2050
2051        var render__productItem = function(invObj, product) {
2052
2053            var html = '';
2054
2055            var productImage = '';
2056            var product_image_url = product.image;
2057            if(product_image_url) { productImage = `<img src="${WESTORE.CONFIG.url_product_images}picture_thumbs/${product_image_url}">`; }
2058            else { productImage = `<img src="${WESTORE.CONFIG.url_root}assets/images/product_thumbnail_320x320.jpg">`; }
2059
2060            var price = product.price;
2061            var price_deduction_percent = product.price_deduction;
2062            var price_deduction_amount = price * price_deduction_percent / 100;
2063			var price_after_deduction = price - price_deduction_amount;
2064            var price_deduction_percent_html = "";
2065
2066            display_price = WESTORE.get_display_price(price);
2067            display_price_after_deduction = WESTORE.get_display_price(price_after_deduction);
2068
2069            if(price_deduction_percent) {
2070                display_price = `<span class='display-price-before-deduction'>${display_price}</span> <span class='display-price-after-deduction'>${display_price_after_deduction}</span>`;
2071                price_deduction_percent_html = `<div class="price-deduction-percent">${price_deduction_percent}%</div>`;
2072            }
2073
2074            var dataTags = "";
2075            dataTags += 'data-productID="'+product.id+'" ';
2076            dataTags += 'data-title="'+product.title+'" ';
2077            dataTags += 'data-price="'+price+'" ';
2078            dataTags += 'data-price-deduction="'+price_deduction_percent+'" ';
2079            dataTags += 'data-tax="'+product.tax+'" ';
2080            dataTags += 'data-urlID="'+product.urlID+'" ';
2081            dataTags += 'data-image="'+product.image+'" ';
2082
2083            if(invObj.page_view == "rows") {
2084                html = `
2085                <a class="product-item bi-item bi-item-row storeContentLoadLinkProduct" data-productID="${product.id}" data-page="${invObj.page_number}" href="${WESTORE.CONFIG.url_root}${WESTORE.CONFIG.url_page_product}${product.urlID}">
2086                     <div class="bi-item-td bi-row-image">
2087                         <div class="height-wrapper">
2088                             <div class="height-content">${productImage}</div>
2089                         </div>
2090                         ${price_deduction_percent_html}
2091                     </div>
2092                     <div class="bi-item-td">${product.title}</div>
2093                     <div class="bi-item-td">${product.vendor}</div>
2094                     <div class="bi-item-td td-center">${display_price}</div>
2095                     <data ${dataTags}></data>
2096                </a>
2097                `;
2098            }
2099            else {
2100                html = `
2101                <DIV class="product-item bi-item bi-item-grid" data-productID="${product.id}" data-page="${invObj.page_number}">
2102                     <a class="bi-grid-image color-border-primary-hover storeContentLoadLinkProduct" href="${WESTORE.CONFIG.url_root}${WESTORE.CONFIG.url_page_product}${product.urlID}">
2103                         <div class="height-wrapper">
2104                             <div class="height-content">${productImage}</div>
2105                         </div>
2106                         ${price_deduction_percent_html}
2107                     </a>
2108                     <div class="product-title">${product.title}</div>
2109                     <div class="product-price">${display_price}</div>
2110                     <div class="clear"></div>
2111                     <data ${dataTags}></data>
2112                </DIV>
2113                `;
2114            }
2115
2116            return html;
2117
2118        }
2119
2120        let products = [];
2121        let pageID = pageData.pageID;
2122
2123        let urlObject = window.location;
2124        let url_params = new URLSearchParams(urlObject.search);
2125
2126        let search_active = false;
2127        let search = '';
2128        let sortID = '';
2129        let ranges = '';
2130        let filters = '';
2131        let page_view = '';
2132        let page_size = 0;
2133        let page_number = 0;
2134
2135        // Get values
2136        if(url_params.has('search')) { search = url_params.get('search'); }
2137        if(url_params.has('sortID')) { sortID = url_params.get('sortID'); }
2138        if(url_params.has('ranges')) { ranges = url_params.get('ranges'); }
2139        if(url_params.has('filters')) { filters = url_params.get('filters'); }
2140        if(url_params.has('page_view')) { page_view = url_params.get('page_view'); }
2141        if(url_params.has('page_size')) { page_size = url_params.get('page_size'); }
2142        if(url_params.has('page_number')) { page_number = url_params.get('page_number'); }
2143
2144        // Integers check
2145        if(!Number.isInteger(page_size) || page_size < 0) { page_size = 0; }
2146        if(!Number.isInteger(page_number) || page_number < 0) { page_number = 0; }
2147
2148
2149        let label_items_count = this.label_items_count+' &nbsp;<b>'+pageData.name+'</b>&nbsp; ';
2150        let label_search_placeholder = this.label_search_placeholder;
2151
2152        // Page products
2153        if(pageID && pageData.pagetype == "STORE_PRODUCT_LIST") {
2154            if(productListData.hasOwnProperty(pageID)) {
2155                products = productListData[pageID].products;
2156                navigation = productListData[pageID].page_data.navigation;
2157            }
2158            label_search_placeholder = this.label_search_placeholder+' - '+pageData.name;
2159        }
2160        // Search products
2161        else {
2162            if(productListData.hasOwnProperty('all')) {
2163                products = productListData['all'].products;
2164                navigation = productListData['all'].page_data.navigation;
2165            }
2166            search_active = true;
2167        }
2168
2169        var langCode = 'se';
2170        if(WESTORE.CONFIG.country == "US") { langCode = 'en'; }
2171
2172        let data = {
2173            id: 'cms_products',
2174            selector: '#productlist',
2175            url_base: url_base,
2176            lazyLoad: this.lazyLoad,
2177            lang: langCode,
2178            label_items_count: label_items_count,
2179            label_items_empty: this.label_items_empty,
2180            label_range_to: this.label_range_to,
2181            label_filter_reset: this.label_filter_reset,
2182            label_filter_show: this.label_filter_show,
2183            label_filter_hide: this.label_filter_hide,
2184            label_filter_expand: 'Show more',
2185            label_filter_collapse: 'Show less',
2186            label_search_placeholder: label_search_placeholder,
2187            items: products,
2188            renderItem: render__productItem,
2189            renderItemRowHeader: render__rowHeader,
2190            search: search,
2191            search_fields: ['title', 'vendor', 'urlID', 'barcode'],
2192            search_active: search_active,
2193            page_number: page_number,
2194            page_size: page_size,
2195            page_view: page_view,
2196            sortID: sortID,
2197            sortID_default: this.sortID_default,
2198            sort_structure: {
2199                1001: {field: 'title', direction: 'ASC', label: this.label_sort_title_asc},
2200                1002: {field: 'title', direction: 'DESC', label: this.label_sort_title_desc},
2201                1003: {field: 'price', direction: 'ASC',  label: this.label_sort_price_asc},
2202            	1004: {field: 'price', direction: 'DESC', label: this.label_sort_price_desc},
2203                1005: {field: 'brand', direction: 'ASC', label: this.label_sort_brand_asc},
2204                1006: {field: 'brand', direction: 'DESC', label: this.label_sort_brand_desc},
2205            },
2206            navigation: navigation,
2207            ranges_posted: ranges,
2208            range_structure: {
2209                price: {
2210                    min: 0, max: this.max_price, label: this.label_range_price, unit: this.label_range_price_unit
2211                },
2212            },
2213            filters_posted: filters,
2214            filter_structure: {
2215                'vendor': {label: this.label_filter_vendor}
2216            },
2217        };
2218
2219        // Render page
2220        $(function() {
2221
2222            if(WESTORE.CONFIG.store_load_method == "CMS" || WESTORE.CONFIG.store_load_method == "LIVE_INTERNAL") {
2223
2224                if(pageData.pageID == "STORE_SEARCH") {
2225                    let html = `
2226                    <div class='row_content'>
2227                        <div id='productlist' class='store-content store-content-search'></div>
2228                    </div>
2229                    `;
2230
2231                    $(WESTORE.CONFIG.targetElement).html(html);
2232                }
2233                else {
2234                    let html = `<div id='productlist' class='store-content'></div>`;
2235                    $("#store-container-productlist").html(html);
2236                }
2237
2238            }
2239            else {
2240                let html = `<div id='productlist' class='store-content'></div>`;
2241                $(WESTORE.CONFIG.targetElement).html(html);
2242            }
2243
2244            productInventory.init(data);
2245
2246        });
2247
2248    },
2249    jQueryActions: function() {
2250
2251        // bjorkInventory Navigation clicked
2252        $("body").on("click", ".bjorkInventory .bi-navigation .item", function(event) {
2253
2254            if(WESTORE.CONFIG.store_load_method == "CMS" || WESTORE.CONFIG.store_load_method == "LIVE_INTERNAL") {
2255                contentLoad.load($(this), event);
2256            }
2257            else {
2258                event.preventDefault();
2259                WESTORE.ROUTE.loadPageContent($(this).attr('href'));
2260            }
2261
2262        });
2263
2264    }
2265};
2266
2267WESTORE.PRODUCT_SINGLE = {
2268    called_files: {},
2269    product: {},
2270    stockUsed: true,
2271    label_quantity_end: '',
2272    label_buttonInStock: '',
2273    label_buttonOutStock: '',
2274    init: function(data) {
2275
2276        if(data.label_quantity_end) { this.label_quantity_end = data.label_quantity_end; }
2277        if(data.label_buttonInStock) { this.label_buttonInStock = data.label_buttonInStock; }
2278        if(data.label_buttonOutStock) { this.label_buttonOutStock = data.label_buttonOutStock; }
2279
2280        this.stockUsed = data.stockUsed;
2281
2282        $(function() {
2283            WESTORE.PRODUCT_SINGLE.jQueryActions();
2284        });
2285
2286    },
2287    load_file: function(urlID, callBackFunction) {
2288
2289        // Check list already exists
2290        if(!this.called_files.hasOwnProperty(urlID) && !productSingleData.hasOwnProperty(urlID)) {
2291
2292            // To prevent files from beeing called more then once
2293            this.called_files[urlID] = 'X';
2294
2295            WESTORE.clog('PRODUCT FILE LOAD('+urlID+') LOADING...');
2296            WESTORE.clog_time_start('PRODUCT FILE LOAD('+urlID+') LOAD TIME'); // This time is not accurate to client network time
2297
2298            // Load the JavaScript file
2299            $.ajax({
2300                dataType: "script",
2301                url: WESTORE.CONFIG.url_script_product_single.replace('#urlID#', urlID),
2302                cache: true,
2303                success: function(jsRespons) {
2304
2305                    WESTORE.PRODUCT_SINGLE.load_file_done(urlID, callBackFunction);
2306
2307                },
2308                error: function (xhr, ajaxOptions, thrownError) {
2309                    WESTORE.clog_time_end('PRODUCT FILE LOAD('+urlID+') LOAD TIME');
2310                    WESTORE.clog('PRODUCT FILE LOAD('+urlID+') STATUS: Failed, time out! (Status: '+xhr.status+') (Error: '+thrownError+')');
2311                }
2312            });
2313
2314        }
2315        else {
2316
2317            this.load_file_done(urlID, callBackFunction);
2318
2319        }
2320
2321    },
2322    load_file_done: function(urlID, callBackFunction) {
2323
2324        if(productSingleData.hasOwnProperty(urlID)) {
2325
2326            WESTORE.clog_time_end('PRODUCT FILE LOAD('+urlID+') LOAD TIME'); // This time is not accurate to client network time
2327            WESTORE.clog('PRODUCT FILE LOAD('+urlID+') STATUS: Success!');
2328
2329            var product = productSingleData[urlID];
2330            this.product = product;
2331
2332            // Make sure that product object have fields/property
2333            if(!product.hasOwnProperty('productID'))            { this.product.productID = 0; }
2334            if(!product.hasOwnProperty('urlID'))                { this.product.urlID = ""; }
2335            if(!product.hasOwnProperty('title'))                { this.product.title = ""; }
2336            if(!product.hasOwnProperty('vendor'))               { this.product.vendor = ""; }
2337            if(!product.hasOwnProperty('option_value1'))        { this.product.option_value1 = ""; }
2338            if(!product.hasOwnProperty('option_value2'))        { this.product.option_value2 = ""; }
2339            if(!product.hasOwnProperty('option_value3'))        { this.product.option_value3 = ""; }
2340            if(!product.hasOwnProperty('description_short'))    { this.product.description_short = ""; }
2341            if(!product.hasOwnProperty('description_long'))     { this.product.productID = ""; }
2342            if(!product.hasOwnProperty('price'))                { this.product.price = 0; }
2343            if(!product.hasOwnProperty('tax'))                  { this.product.tax = 0; }
2344            if(!product.hasOwnProperty('pageID'))               { this.product.pageID = 0; }
2345            if(!product.hasOwnProperty('options'))              { this.product.options = []; }
2346            if(!product.hasOwnProperty('variants'))             { this.product.variants = []; }
2347            if(!product.hasOwnProperty('images'))               { this.product.images = []; }
2348            if(!product.hasOwnProperty('picID'))                { this.product.picID = 0; }
2349
2350            callBackFunction(product);
2351
2352        }
2353        else {
2354            WESTORE.clog_time_end('PRODUCT FILE LOAD('+urlID+') LOAD TIME');
2355            WESTORE.clog('PRODUCT FILE LOAD('+urlID+') STATUS: Failed, something went wrong with productSingleData urlID');
2356        }
2357
2358    },
2359    load_file_quantity: function(productID, callBackFunction) {
2360
2361            var url = WESTORE.CONFIG.url_script_product_single_quantity.replace('#productID#', productID);
2362
2363            // Load the js file
2364            $.ajax({
2365                dataType: "script",
2366                url: url,
2367                cache: true,
2368                success: function(jsRespons) {
2369
2370                    var quantity = 0;
2371
2372                    if(jsRespons.length) {
2373                        quantity = jsRespons.replace('//', '');
2374                        quantity = parseInt(quantity);
2375                    }
2376
2377                    callBackFunction(quantity);
2378
2379                },
2380                error: function (xhr, ajaxOptions, thrownError) {
2381                    WESTORE.clog('PRODUCT QUATITY FILE LOAD('+productID+') STATUS: Failed, time out! (Status: '+xhr.status+') (Error: '+thrownError+')');
2382                }
2383            });
2384
2385
2386    },
2387    render: function(urlID) {
2388
2389        var product = this.product;
2390        var colors = {
2391            primary: "#14a3e8",
2392            dark: "#3a3a3a",
2393            bright: "#b1b1b1"
2394        };
2395
2396        var price_deduction_percent_html = "";
2397        var display_price = WESTORE.get_display_price(product.price);
2398        var display_price_after_deduction = WESTORE.get_display_price(product.price_after_deduction);
2399
2400        if(product.price_deduction) {
2401            display_price = `<div class='display-price-before-deduction'>${display_price}</div><div class='display-price-after-deduction'>${display_price_after_deduction}</div>`;
2402            price_deduction_percent_html = `<div class="price-deduction-percent">${product.price_deduction}%</div>`;
2403        }
2404
2405        var dataTags = "";
2406        dataTags += 'data-productID="'+product.productID+'" ';
2407        dataTags += 'data-title="'+product.title+'" ';
2408        dataTags += 'data-price="'+product.price+'" ';
2409        dataTags += 'data-price-deduction="'+product.price_deduction+'" ';
2410        dataTags += 'data-price-after-deduction="'+product.price_deduction+'" ';
2411        dataTags += 'data-tax="'+product.tax+'" ';
2412        dataTags += 'data-urlID="'+product.urlID+'" ';
2413        dataTags += 'data-image="'+product.images[product.picID]+'" ';
2414
2415        html = {};
2416        html.thumbnails = "";
2417        html.options = "";
2418
2419        // Images
2420        for (var picID in product.images) {
2421            let image = product.images[picID];
2422            html.thumbnails += `
2423            <div class="thumbnail" data-picID="${picID}">
2424                <img src="${WESTORE.CONFIG.url_product_images}picture_thumbs/${image}">
2425            </div>
2426            `;
2427        }
2428
2429        // Image - Selected
2430        var product_image_url = product.images[product.picID];
2431        var productImage = `<img src="${WESTORE.CONFIG.url_root}/assets/images/product_thumbnail_320x320.jpg">`;
2432        if(product_image_url) { productImage = `<img src="${WESTORE.CONFIG.url_product_images}${product_image_url}">`; }
2433
2434        // Options html
2435        if(Object.keys(product.options).length) {
2436            for (var optionID in product.options) {
2437
2438                let option = product.options[optionID];
2439                let option_values = ``;
2440
2441                for (var i = 0; i < option.values_available.length; i++) {
2442                    let value = option.values_available[i];
2443                    let selected = "";
2444                    if(value == product['option_value'+optionID]) { selected = "selected"; }
2445                    option_values += `<option value='${value}' ${selected}>${value}</option>`;
2446                }
2447
2448                html.options += `
2449                <div class="option-item">
2450                <div class="title">${option.title}</div>
2451                    <select id="option${optionID}">
2452                        ${option_values}
2453                    </select>
2454                </div>
2455                `;
2456            }
2457            html.options = `<div class="options">${html.options}</div>`;
2458        }
2459
2460        html.all = `
2461        <style>
2462        #product input:focus, select:focus { border-color: ${colors.primary}; }
2463        #product .addButton { background-color: ${colors.primary}; }
2464        #product .addButton.outOfStock { background-color: ${colors.bright}; }
2465        #product .product-image-main .image-next:hover .icon,
2466        #product .product-image-main .image-prev:hover .icon { color: ${colors.dark}; }
2467        </style>
2468
2469        <div id="product" class="store-content">
2470
2471            <div class="section-header">
2472                <div class="breadCrumbs"></div>
2473            </div>
2474            <div class="section-content">
2475				<div class="section-left">
2476
2477					<div class="product-image-main">
2478						<div class="inner">
2479							<div class="image-prev">
2480								<div class="icon icon-cust-arrow-left"></div>
2481							</div>
2482							<div class="image-next">
2483								<div class="icon icon-cust-arrow-right"></div>
2484							</div>
2485							${productImage}
2486						</div>
2487                        ${price_deduction_percent_html}
2488					</div>
2489
2490					<div class="product-image-thumbnails">
2491						${html.thumbnails}
2492					</div>
2493
2494				</div>
2495				<div class="section-right">
2496
2497					<h1>
2498						<div>${product.title}</div>
2499					</h1>
2500
2501					<div class="price">${display_price}</div>
2502
2503					<div class="description-short">${product.description_short}</div>
2504
2505                    ${html.options}
2506                    <div class='stockSection'></div>
2507
2508				</div>
2509			</div>
2510
2511			<div class="section-footer">
2512                <div class="description-long">${product.description_long}</div>
2513			</div>
2514
2515            <data ${dataTags}></data>
2516        </div>
2517        `;
2518
2519        // Render page
2520        $(function() {
2521            var thisObj = WESTORE.PRODUCT_SINGLE;
2522            var container = WESTORE.CONFIG.targetElement;
2523
2524            if(WESTORE.CONFIG.store_load_method == "CMS" || WESTORE.CONFIG.store_load_method == "LIVE_INTERNAL") {
2525                html.all = `
2526                <div class="row_content">
2527                    ${html.all}
2528                </div>
2529                `;
2530            }
2531
2532            $(container).html(html.all);
2533            $(container+" #product .product-image-thumbnails .thumbnail[data-picID='"+product.picID+"']").addClass('selected');
2534
2535            $('.CSS_TOP_NAV .item.selected').removeClass('selected');
2536
2537            // Loads quantity file, then render quantity
2538            thisObj.load_file_quantity(product.productID, function(quantity) {
2539                product.quantity = quantity;
2540                thisObj.product.quantity = quantity;
2541                thisObj.render_quantity();
2542            });
2543
2544            // Breadcrumbs html
2545            if(product.pageID) {
2546                WESTORE.PRODUCT_LIST.wait_for_list(product.pageID, function(status) {
2547
2548                    if(status == "success") {
2549
2550                        let breadCrumbs = productListData[product.pageID].page_data.breadCrumbs;
2551                        if(breadCrumbs.length) {
2552
2553                            let breadCrumbs_html = "";
2554                            for (var i = 0; i < breadCrumbs.length; i++) {
2555                                let breadCrumbItem = breadCrumbs[i];
2556                                breadCrumbs_html += `
2557                                <a href='${breadCrumbItem.url}' class='storeContentLoadLinkPage'>${breadCrumbItem.label}</a>
2558                                <svg xmlns="http://www.w3.org/2000/svg" width="7px" height="10px" style="margin: 0 4px" viewBox="0 0 5 7.89062">
2559                                    <g id="Path_526959" data-name="Path 526959" fill="#8E8E8E">
2560                                        <polygon points=".70703 7.89062 0 7.18359 3.23877 3.94336 0 .70703 .70703 0 4.65283 3.94336 .70703 7.89062"></polygon>
2561                                    </g>
2562                                </svg>
2563                                `;
2564                            }
2565
2566                            breadCrumbs_html += product.title;
2567                            $(container+" #product .breadCrumbs").html(breadCrumbs_html);
2568
2569                        }
2570
2571                    }
2572                    else {
2573                        WESTORE.clog(`Breadcrumbs could not be loaded for this product(${product.productID}).`);
2574                    }
2575
2576                });
2577            }
2578
2579            let option_values_string = "";
2580            if(product.option_value1) { option_values_string = product.option_value1; }
2581            if(product.option_value2) { option_values_string = ", "+product.option_value2; }
2582            if(product.option_value3) { option_values_string = ", "+product.option_value3; }
2583
2584            var tag_manager_item = {
2585                //currency: "USD",
2586                value: product.price,
2587                items: [
2588                    {
2589                        item_id: product.productID,
2590                        item_name: product.title,
2591                        affiliation: "Product single page",
2592                        coupon: "",
2593                        discount: 0,
2594                        index: 0,
2595                        item_brand: product.vendor,
2596                        item_category: "",
2597                        item_category2: "",
2598                        item_category3: "",
2599                        item_category4: "",
2600                        item_category5: "",
2601                        item_list_id: product.pageID,
2602                        item_list_name: product.pageID,
2603                        item_variant: option_values_string,
2604                        location_id: "",
2605                        price: product.price,
2606                        quantity: 1
2607                    }
2608                ]
2609            };
2610
2611            // Google Analytics 4
2612            if (typeof gtag !== 'undefined') {
2613                gtag("event", "view_item", tag_manager_item);
2614            }
2615            // Google Tag Manager
2616            else if (typeof dataLayer !== 'undefined') {
2617                dataLayer.push({'event': 'view_item', 'ecommerce': tag_manager_item});
2618            }
2619
2620
2621        });
2622
2623    },
2624    render_quantity: function() {
2625
2626        var product = this.product;
2627        var buyButtonLabel = this.label_buttonInStock;
2628        var buyButtonStockClass = '';
2629        var html = '';
2630
2631        if(this.stockUsed) {
2632
2633            if(!product.quantity) {
2634                buyButtonStockClass = ' outOfStock';
2635                buyButtonLabel = this.label_buttonOutStock;
2636            }
2637
2638            html = `
2639                <div class='addButton${buyButtonStockClass}'>${buyButtonLabel}</div>
2640                <div class='quantity'>${product.quantity} ${this.label_quantity_end}</div>
2641            `;
2642
2643        }
2644        else {
2645            html = `<div class='addButton'>${buyButtonLabel}</div>`;
2646        }
2647
2648        $(WESTORE.CONFIG.targetElement+' .stockSection').html(html);
2649
2650    },
2651    jQueryActions: function () {
2652
2653        function select_image(picID) {
2654
2655            var images = WESTORE.PRODUCT_SINGLE.product.images;
2656
2657        	if(images.hasOwnProperty(picID)) {
2658
2659        		$("#product .product-image-main img").attr("src", WESTORE.CONFIG.url_product_images+images[picID]);
2660                $("#product .product-image-thumbnails .thumbnail.selected").removeClass("selected");
2661        		$("#product .product-image-thumbnails .thumbnail[data-picID='"+picID+"']").addClass("selected");
2662
2663        	}
2664
2665        }
2666
2667        // Image select
2668        $("body").on("click", "#product .product-image-thumbnails .thumbnail", function(e) {
2669            var picID = $(this).attr('data-picID');
2670            select_image(picID);
2671        });
2672
2673        // Image next
2674        $("body").on("click", "#product .image-next", function(e) {
2675            e.stopPropagation();
2676            var $thumb = $("#product .product-image-thumbnails .thumbnail.selected").next();
2677            if(!$thumb.length) { $thumb = $("#product .product-image-thumbnails .thumbnail").first(); }
2678            var picID = $thumb.attr('data-picID');
2679        	select_image(picID);
2680        });
2681
2682        // Image prev
2683        $("body").on("click", "#product .image-prev", function(e) {
2684
2685            e.stopPropagation();
2686            var $thumb = $("#product .product-image-thumbnails .thumbnail.selected").prev();
2687            if(!$thumb.length) { $thumb = $("#product .product-image-thumbnails .thumbnail").last(); }
2688            var picID = $thumb.attr('data-picID');
2689        	select_image(picID);
2690
2691        });
2692
2693        // Product add button clicked
2694        $("body").on("click", "#product .addButton:not(.outOfStock)", function(e) {
2695
2696            e.preventDefault();
2697
2698            var $product = $(this).parents('#product');
2699            var $data = $product.find('data');
2700            var product = {
2701                productID: $data.attr('data-productID'),
2702                urlID: $data.attr('data-urlID')
2703            };
2704
2705            WESTORE.CART.add(product, 1);
2706
2707        });
2708
2709        // Variant option change
2710        $("body").on("change", "#product .options select", function(e) {
2711
2712            var options = WESTORE.PRODUCT_SINGLE.product.options;
2713            var variants = WESTORE.PRODUCT_SINGLE.product.variants;
2714    		var variant_selected = {};
2715
2716            var optionValue1 = '';
2717    		var optionValue2 = '';
2718    		var optionValue3 = '';
2719            if($("#option1").val() !== undefined) { optionValue1 = $("#option1").val(); }
2720            if($("#option2").val() !== undefined) { optionValue2 = $("#option2").val(); }
2721            if($("#option3").val() !== undefined) { optionValue3 = $("#option3").val(); }
2722
2723            for (var productID in variants) {
2724
2725                let variant = variants[productID];
2726
2727    			variantValue1 = ''+variant['option_value1'];
2728    			variantValue2 = ''+variant['option_value2'];
2729    			variantValue3 = ''+variant['option_value3'];
2730
2731    			// Selected varriant
2732    			if(optionValue1 == variantValue1 && optionValue2 == variantValue2 && optionValue3 == variantValue3) {
2733    				variant_selected = variant;
2734    			}
2735
2736    		}
2737
2738        	// Load variant
2739        	if(variant_selected.hasOwnProperty('urlID')) {
2740        		var urlBrowser = WESTORE.CONFIG.url_root+WESTORE.CONFIG.url_page_product+variant_selected.urlID;
2741                WESTORE.ROUTE.loadPageContent(urlBrowser);
2742        	}
2743
2744        });
2745
2746        // Product breadcrumb clicked
2747        $("body").on("click", "#product .breadcrumbs a", function(event) {
2748
2749            if(WESTORE.CONFIG.store_load_method == "CMS" || WESTORE.CONFIG.store_load_method == "LIVE_INTERNAL") {
2750                contentLoad.load($(this), event);
2751            }
2752            else {
2753                event.preventDefault();
2754                WESTORE.ROUTE.loadPageContent($(this).attr('href'));
2755            }
2756
2757        });
2758
2759    }
2760};
2761WESTORE.init({"CONFIG":{"store_load_method":"LIVE_INTERNAL","url_root":"\/","url_cms_root":"\/","url_script_product_list":"\/products\/lists\/productlist-#fileID#.js?261001085505","url_script_product_single":"\/products\/singles\/js\/#urlID#.js?261001085505","url_script_product_single_quantity":"\/products\/singles\/quantity\/#productID#.js?261001085505","url_product_images":"\/pictures_products\/","country":"US","targetElement":".store-container","targetElementCart":"#store-container-cart","targetWidgetIcons":"","widget_icons_top":20,"widget_icons_right":20,"widget_icons_expand":true,"url_page_checkout":"checkout","url_page_checkout_confirmation":"checkout\/confirmation","url_page_search":"search\/products","url_page_product":"product\/","url_domain_api":"https:\/\/api2.epage.se","label_search":"Search"},"ROUTE":{"index_status_default":"index","pages":{"produkter":{"pageID":"78","pagetype":"STORE_PRODUCT_LIST","name":"Produkter","title":"Produkter \u2013 Nordic Gym","searchwords":"","description":"Tr\u00e4ningsmaskiner och gymutrustning f\u00f6r styrketr\u00e4ning, fitness och kondition.","index_status":"index"},"produkter\/styrketraning":{"pageID":"82","pagetype":"STORE_PRODUCT_LIST","name":"Styrketr\u00e4ning","title":"Kvalitetsprodukter inom Styrketr\u00e4ning \u2013 Nordic Gym","searchwords":"","description":"Uppt\u00e4ck h\u00e5llbar styrketr\u00e4ning med svensktillverkade maskiner fr\u00e5n Nordic Gym. Ergonomisk design och kvalitet som h\u00e5ller f\u00f6r l\u00e5ngsiktig tr\u00e4ning.","index_status":"index"},"produkter\/konditionstraning":{"pageID":"83","pagetype":"STORE_PRODUCT_LIST","name":"Konditionstr\u00e4ning","title":"Kvalitetsprodukter inom Konditionstr\u00e4ning \u2013 Nordic Gym","searchwords":"","description":"Uppt\u00e4ck svensktillverkad konditionstr\u00e4ningsutrustning fr\u00e5n Nordic Gym. H\u00e5llbar design och ergonomisk kvalitet som passar alla tr\u00e4ningsmilj\u00f6er.","index_
2761status":"index"},"produkter\/ovrig-traning":{"pageID":"84","pagetype":"STORE_PRODUCT_LIST","name":"\u00d6vrig tr\u00e4ning","title":"Kvalitetsprodukter inom \u00d6vrig tr\u00e4ning \u2013 Nordic Gym","searchwords":"","description":"Kvalitetsprodukter inom \u00d6vrig tr\u00e4ning","index_status":"index"},"produkter\/tillbehor":{"pageID":"85","pagetype":"STORE_PRODUCT_LIST","name":"Tillbeh\u00f6r","title":"Kvalitetsprodukter inom Tillbeh\u00f6r \u2013 Nordic Gym","searchwords":"","description":"Kvalitetsprodukter inom Tillbeh\u00f6r","index_status":"index"},"produkter\/hemmatraning":{"pageID":"86","pagetype":"STORE_PRODUCT_LIST","name":"Hemmatr\u00e4ning","title":"Kvalitetsprodukter inom Hemmatr\u00e4ning \u2013 Nordic Gym","searchwords":"","description":"Kvalitetsprodukter inom Hemmatr\u00e4ning","index_status":"index"},"produkter\/reservdelar":{"pageID":"87","pagetype":"STORE_PRODUCT_LIST","name":"Reservdelar","title":"Kvalitetsprodukter inom Reservdelar \u2013 Nordic Gym","searchwords":"","description":"Kvalitetsprodukter inom Reservdelar","index_status":"index"},"produkter\/begagnat":{"pageID":"88","pagetype":"STORE_PRODUCT_LIST","name":"Begagnat","title":"Begagnade tr\u00e4ningsmaskiner och gymmaskiner - Nordic Gym","searchwords":"","description":"Kvalitetsprodukter inom begagnade tr\u00e4ningsmaskiner och gymmaskiner","index_
2761status":"index"},"produkter\/styrketraning\/basutrustning":{"pageID":"89","pagetype":"STORE_PRODUCT_LIST","name":"Basutrustning","title":"Kvalitetsprodukter inom Styrketr\u00e4ning \u2192 Basutrustning \u2013 Nordic Gy","searchwords":"","description":"Kvalitetsprodukter inom Styrketr\u00e4ning \u2192 Basutrustning","index_status":"index"},"produkter\/muskelgrupper":{"pageID":"91","pagetype":"STORE_PRODUCT_LIST","name":"Muskelgrupper","title":"Kvalitetsprodukter inom Maskiner med viktmagasin - Nordic Gym","searchwords":"","description":"Kvalitetsprodukter inom Maskiner med viktmagasin \u2192 Styrketr\u00e4ning f\u00f6r Armar, Axlar, Ben, Br\u00f6st, B\u00e5l, Rygg och \u00d6vriga musker","index_status":"index"},"produkter\/muskelgrupper\/armar":{"pageID":"92","pagetype":"STORE_PRODUCT_LIST","name":"Armar","title":"Kvalitetsprodukter inom Styrketr\u00e4ning f\u00f6r Armar - Nordic Gym","searchwords":"","description":"Kvalitetsprodukter inom Maskiner med viktmagasin \u2192 Styrketr\u00e4ning f\u00f6r Armar","index_status":"index"},"produkter\/muskelgrupper\/axlar":{"pageID":"93","pagetype":"STORE_PRODUCT_LIST","name":"Axlar","title":"Kvalitetsprodukter inom Styrketr\u00e4ning f\u00f6r Axlar | Nordic Gym","searchwords":"","description":"Kvalitetsprodukter inom Styrketr\u00e4ning \u2192 Maskiner med viktmagasin f\u00f6r Axlar","index_status":"index"},"produkter\/muskelgrupper\/ben":{"pageID":"94","pagetype":"STORE_PRODUCT_LIST","name":"Ben","title":"Kvalitetsprodukter inom Styrketr\u00e4ning f\u00f6r ben -  Nordic gym","searchwords":"","description":"Kvalitetsprodukter inom Styrketr\u00e4ning \u2192 Maskiner med viktmagasin f\u00f6r Ben","index_status":"index"},"produkter\/muskelgrupper\/brost":{"pageID":"95","pagetype":"STORE_PRODUCT_LIST","name":"Br\u00f6st","title":"Kvalitetsprodukter inom Styrketr\u00e4ning f\u00f6r br\u00f6st - Nordic gym","searchwords":"","description":"Kvalitetsprodukter inom Styrketr\u00e4ning \u2192 Maskiner med viktmagasin f\u00f6r Br\u00f6st","index_status":"index"},"produkter\/muskelgrupper\/bal":{"pageID":"97","pagetype":"STORE_PRODUCT_LIST","name":"B\u00e5l","title":"Kvalitetsprodukter inom Styrketr\u00e4ning f\u00f6r B\u00e5l - Nordic Gym","searchwords":"","description":"Kvalitetsprodukter inom Maskiner med viktmagasin \u2192 Styrketr\u00e4ning f\u00f6r B\u00e5l","index_status":"index"},"produkter\/muskelgrupper\/rygg":{"pageID":"98","pagetype":"STORE_PRODUCT_LIST","name":"Rygg","title":"Kvalitetsprodukter inom Styrketr\u00e4ning f\u00f6r rygg - Nordic gym","searchwords":"","description":"Kvalitetsprodukter inom Styrketr\u00e4ning \u2192 Maskiner med viktmagasin f\u00f6r Rygg","index_status":"index"},"produkter\/muskelgrupper\/ovrigt":{"pageID":"99","pagetype":"STORE_PRODUCT_LIST","name":"\u00d6vrigt","title":"Kvalitetsprodukter inom Styrketr\u00e4ning f\u00f6r \u00f6vriga kroppen - Nordic g","searchwords":"","description":"Kvalitetsprodukter inom Styrketr\u00e4ning \u2192 Maskiner med viktmagasin f\u00f6r \u00d6vrigt","index_status":"index"},"produkter\/styrketraning\/bankar":{"pageID":"100","pagetype":"STORE_PRODUCT_LIST","name":"B\u00e4nkar","title":"Kvalitetsprodukter inom Styrketr\u00e4ning \u2192 B\u00e4nkar \u2013 Nordic Gym","searchwords":"","description":"Svensktillverkade b\u00e4nkar f\u00f6r styrketr\u00e4ning fr\u00e5n Nordic Gym. Ergonomiska och h\u00e5llbara b\u00e4nkar designade f\u00f6r professionella gym och hemmatr\u00e4ning.","index_status":"index"},"produkter\/styrketraning\/maskiner-med-viktmagasin":{"pageID":"101","pagetype":"STORE_PRODUCT_LIST","name":"Maskiner med viktmagasin","title":"Kvalitetsprodukter inom Styrketr\u00e4ning \u2192 Maskiner med viktmagasin","searchwords":"","description":"Svensktillverkade styrketr\u00e4ningsmaskiner med viktmagasin fr\u00e5n Nordic Gym. H\u00e5llbara, ergonomiska maskiner som passar f\u00f6r b\u00e5de kommersiell och privat tr\u00e4nin","index_status":"index"},"produkter\/styrketraning\/draghissar":{"pageID":"102","pagetype":"STORE_PRODUCT_LIST","name":"Draghissar","title":"Kvalitetsprodukter inom Styrketr\u00e4ning \u2192 Draghissar \u2013 Nordic Gym","searchwords":"","description":"Uppt\u00e4ck svensktillverkade draghissar f\u00f6r styr
2761ketr\u00e4ning fr\u00e5n Nordic Gym. Ergonomisk design och h\u00e5llbar kvalitet f\u00f6r professionella och privata gymmilj\u00f6er.","index_status":"index"},"produkter\/styrketraning\/plate-loaded":{"pageID":"103","pagetype":"STORE_PRODUCT_LIST","name":"Plate loaded","title":"Kvalitetsprodukter inom Styrketr\u00e4ning \u2192 Plate loaded \u2013 Nordic Gym","searchwords":"","description":"Uppt\u00e4ck svensktillverkade plate loaded styrketr\u00e4ningsmaskiner fr\u00e5n Nordic Gym. Ergonomisk och h\u00e5llbar design f\u00f6r s\u00e4ker tr\u00e4ning p\u00e5 gym och hemmagym.","index_status":"index"},"produkter\/styrketraning\/stallningar":{"pageID":"104","pagetype":"STORE_PRODUCT_LIST","name":"St\u00e4llningar","title":"Kvalitetsprodukter inom Styrketr\u00e4ning \u2192 St\u00e4llningar \u2013 Nordic Gym","searchwords":"","description":"Svensktillverkade styrketr\u00e4ningsst\u00e4llningar fr\u00e5n Nordic Gym. Ergonomiska och h\u00e5llbara st\u00e4llningar f\u00f6r s\u00e4ker tr\u00e4ning p\u00e5 gym och i hemmamilj\u00f6.","index_status":"index"},"produkter\/styrketraning\/skivstanger":{"pageID":"106","pagetype":"STORE_PRODUCT_LIST","name":"Skivst\u00e4nger","title":"Kvalitetsprodukter inom Styrketr\u00e4ning \u2192 Skivst\u00e4nger \u2013 Nordic Gym","searchwords":"","description":"Utforska skivst\u00e4nger f\u00f6r styrketr\u00e4ning fr\u00e5n Nordic Gym. Svensktillverkade och ergonomiska skivst\u00e4nger som erbjuder h\u00e5llbar kvalitet f\u00f6r effektiv tr\u00e4ning","index_status":"index"},"produkter\/styrketraning\/viktskivor":{"pageID":"107","pagetype":"STORE_PRODUCT_LIST","name":"Viktskivor","title":"Kvalitetsprodukter inom Styrketr\u00e4ning \u2192 Viktskivor \u2013 Nordic Gym","searchwords":"","description":"Utforska svensktillverkade viktskivor f\u00f6r styrketr\u00e4ning fr\u00e5n Nordic Gym. H\u00e5llbara och ergonomiska viktskivor som passar f\u00f6r b\u00e5de gym och hemmatr\u00e4ning.","index_status":"index"},"produkter\/styrketraning\/viktstall":{"pageID":"108","pagetype":"STORE_PRODUCT_LIST","name":"Viktst\u00e4ll","title":"Kvalitetsprodukter inom Styrketr\u00e4ning \u2192 Viktst\u00e4ll \u2013 Nordic Gym","searchwords":"","description":"Utforska svensktillverkade viktst\u00e4ll f\u00f6r styrketr\u00e4ning fr\u00e5n Nordic Gym. H\u00e5llbara och ergonomiska viktst\u00e4ll f\u00f6r s\u00e4ker och organiserad f\u00f6rvaring p\u00e5 gym ","index_status":"index"},"produkter\/styrketraning\/hantlar":{"pageID":"109","pagetype":"STORE_PRODUCT_LIST","name":"Hantlar","title":"Kvalitetsprodukter inom Styrketr\u00e4ning \u2192 Hantlar \u2013 Nordic Gym","searchwords":"","description":"Uppt\u00e4ck svensktillverkade hantlar f\u00f6r styrketr\u00e4ning fr\u00e5n Nordic Gym. Ergonomiska och slitstarka hantlar som passar b\u00e5de f\u00f6r professionellt och hemmabruk.","index_status":"index"},"produkter\/styrketraning\/kettlebells":{"pageID":"110","pagetype":"STORE_PRODUCT_LIST","name":"Kettlebells","title":"Kvalitetsprodukter inom Styrketr\u00e4ning \u2192 Kettlebells \u2013 Nordic Gym","searchwords":"","description":"Utforska svensktillverkade kettlebells f\u00f6r styrketr\u00e4ning fr\u00e5n Nordic Gym. H\u00e5llbara och ergonomiska kettlebells som passar f\u00f6r professionellt och hemmabruk.","index_status":"index"},"produkter\/styrketraning\/cirkeltraning":{"pageID":"111","pagetype":"STORE_PRODUCT_LIST","name":"Cirkeltr\u00e4ning","title":"Kvalitetsprodukter inom Styrketr\u00e4ning \u2192 Cirkeltr\u00e4ning \u2013 Nordic G","searchwords":"","description":"Utforska svensktillverkad utrustning f\u00f6r cirkeltr\u00e4ning inom styrketr\u00e4ning fr\u00e5n Nordic Gym. H\u00e5llbar och ergonomisk design f\u00f6r b\u00e5de gym och hemmatr\u00e4ning.","index_status":"index"},"produkter\/konditionstraning\/cyklar":{"pageID":"112","pagetype":"STORE_PRODUCT_LIST","name":"Cyklar","title":"Kvalitetsprodukter inom Konditionstr\u00e4ning \u2192 Cyklar \u2013 Nordic Gym","searchwords":"","description":"Kvalitetsprodukter inom Konditionstr\u00e4ning \u2192 Cyklar","index_status":"index"},"produkter\/konditionstraning\/lopband":{"pageID":"113","pagetype":"STORE_PRODUCT_LIST","name":"L\u00f6pband","title":"Kvalitetsprodukter inom Konditionstr\u00e4ning \u2192 L\u00f6pband \u2013 Nordic Gym","searchwords":"","description":"Kvalitetsprodukter inom Konditionstr\u00e4ning \u2192 L\u00f6pband","index_
2761status":"index"},"produkter\/konditionstraning\/roddmaskiner":{"pageID":"114","pagetype":"STORE_PRODUCT_LIST","name":"Roddmaskiner","title":"Kvalitetsprodukter inom Konditionstr\u00e4ning \u2192 Roddmaskiner \u2013 Nordic","searchwords":"","description":"Kvalitetsprodukter inom Konditionstr\u00e4ning \u2192 Roddmaskiner","index_status":"index"},"produkter\/konditionstraning\/crosstrainer":{"pageID":"115","pagetype":"STORE_PRODUCT_LIST","name":"Crosstrainer","title":"Kvalitetsprodukter inom Konditionstr\u00e4ning \u2192 Crosstrainer \u2013 Nordic","searchwords":"","description":"Kvalitetsprodukter inom Konditionstr\u00e4ning \u2192 Crosstrainer","index_status":"index"},"produkter\/konditionstraning\/trappmaskiner":{"pageID":"116","pagetype":"STORE_PRODUCT_LIST","name":"Trappmaskiner","title":"Kvalitetsprodukter inom Konditionstr\u00e4ning \u2192 Trappmaskiner \u2013 Nordi","searchwords":"","description":"Kvalitetsprodukter inom Konditionstr\u00e4ning \u2192 Trappmaskiner","index_status":"index"},"produkter\/ovrig-traning\/uxcross":{"pageID":"117","pagetype":"STORE_PRODUCT_LIST","name":"UXCROSS","title":"Kvalitetsprodukter inom \u00d6vrig tr\u00e4ning \u2192 UXCROSS \u2013 Nordic Gym","searchwords":"","description":"Kvalitetsprodukter inom \u00d6vrig tr\u00e4ning \u2192 UXCROSS","index_status":"index"},"produkter\/ovrig-traning\/rorlighet":{"pageID":"118","pagetype":"STORE_PRODUCT_LIST","name":"R\u00f6rlighet","title":"Kvalitetsprodukter inom \u00d6vrig tr\u00e4ning \u2192 R\u00f6rlighet \u2013 Nordic Gym","searchwords":"","description":"Kvalitetsprodukter inom \u00d6vrig tr\u00e4ning \u2192 R\u00f6rlighet","index_status":"index"},"produkter\/ovrig-traning\/kettlebells":{"pageID":"119","pagetype":"STORE_PRODUCT_LIST","name":"Kettlebells","title":"Kvalitetsprodukter inom Styrketr\u00e4ning \u2192 Kettlebells \u2013 Nordic Gym","searchwords":"","description":"Kvalitetsprodukter inom Styrketr\u00e4ning \u2192 Kettlebells","index_status":"index"},"produkter\/ovrig-traning\/bollar":{"pageID":"120","pagetype":"STORE_PRODUCT_LIST","name":"Bollar","title":"Kvalitetsprodukter inom \u00d6vrig tr\u00e4ning \u2192 Bollar \u2013 Nordic Gym","searchwords":"","description":"Kvalitetsprodukter inom \u00d6vrig tr\u00e4ning \u2192 Bollar","index_status":"index"},"produkter\/ovrig-traning\/ovriga-redskap":{"pageID":"121","pagetype":"STORE_PRODUCT_LIST","name":"\u00d6vriga redskap","title":"Kvalitetsprodukter inom \u00d6vrig tr\u00e4ning \u2192 \u00d6vriga redskap \u2013 Nordic","searchwords":"","description":"Kvalitetsprodukter inom \u00d6vrig tr\u00e4ning \u2192 \u00d6vriga redskap","index_status":"index"},"produkter\/tillbehor\/handtag":{"pageID":"122","pagetype":"STORE_PRODUCT_LIST","name":"Handtag","title":"Kvalitetsprodukter inom Tillbeh\u00f6r \u2192 Handtag \u2013 Nordic Gym","searchwords":"","description":"Kvalitetsprodukter inom Tillbeh\u00f6r \u2192 Handtag","index_status":"index"},"produkter\/tillbehor\/stall":{"pageID":"131","pagetype":"STORE_PRODUCT_LIST","name":"St\u00e4ll","title":"Kvalitetsprodukter inom Tillbeh\u00f6r \u2192 St\u00e4ll \u2013 Nordic Gym","searchwords":"","description":"Kvalitetsprodukter inom Tillbeh\u00f6r \u2192 St\u00e4ll","index_status":"index"},"produkter\/tillbehor\/mattor":{"pageID":"132","pagetype":"STORE_PRODUCT_LIST","name":"Mattor","title":"Kvalitetsprodukter inom Tillbeh\u00f6r \u2192 Mattor \u2013 Nordic Gym","searchwords":"","description":"Kvalitetsprodukter inom Tillbeh\u00f6r \u2192 Mattor","index_status":"index"},"produkter\/tillbehor\/underhall":{"pageID":"133","pagetype":"STORE_PRODUCT_LIST","name":"Underh\u00e5ll","title":"Kvalitetsprodukter inom Underh\u00e5ll \u2013 Nordic Gym","searchwords":"","description":"Kvalitetsprodukter inom underh\u00e5ll","index_status":"index"},"search\/products":{"pageID":"STORE_SEARCH","pagetype":"STORE_SYSTEM_PAGE","name":"Search","title":"Search","searchwords":"","description":"Search","index_status":"index"},"checkout":{"pageID":"STORE_CHECKOUT","pagetype":"STORE_SYSTEM_PAGE","name":"Checkout","title":"Checkout","searchwords":"","description":"Checkout","index_
2761status":"index"},"checkout\/confirmation":{"pageID":"STORE_CHECKOUT_CONFIRMATION","pagetype":"STORE_SYSTEM_PAGE","name":"Order confirmation","title":"Order confirmation","searchwords":"","description":"Order confirmation","index_status":"index"},"product":{"pageID":"STORE_PRODUCT","pagetype":"STORE_PRODUCT_PAGE","name":"Product","title":" - Product","searchwords":"","description":" - Product","index_status":"index"}}},"CART":{"cart_active":true,"icon_top":20,"icon_right":20,"label_title":"Cart","label_table_price":"Price","label_table_sum":"Total","label_cart_empty":"Your cart is empty","label_total_sum":"Total price","label_button_checkout":"Go to checkout","label_button_close":"Keep shopping"},"CHECKOUT":{"label_title_cart":"Cart","label_title_payment":"Shipping & payment","label_table_price":"Price","label_table_sum":"Total","label_cart_empty":"Your cart is empty","label_total_sum":"Total price","label_total_sum_before":"Price before discount","label_total_discount":"Discount","label_discountcode_input":"Discount code","label_discountcode_button":"Register","label_button_back_cart":"Change in the cart","label_button_payment":"Go to payment","label_productOutStock":"Out of stock"},"PRODUCT_LIST":{"langCode":"en","lazyLoad":false,"max_price":"4000","sortID_default":"1001","label_items_count":"products found in","label_items_empty":"No products here","label_search_placeholder":"Search","label_range_to":"to","label_range_price":"Price","label_range_price_unit":"$","label_filter_reset":"Reset filters","label_filter_show":"Show filters","label_filter_hide":"Show hits","label_filter_expand":"Show more","label_filter_collapse":"Show less","label_filter_vendor":"Brand","label_sort_title_asc":"Name, A-Z","label_sort_title_desc":"Name, Z-A","label_sort_brand_asc":"Brand, A-Z","label_sort_brand_desc":"Brand, Z-A","label_sort_price_asc":"Price, lowest first","label_sort_price_desc":"Price, highest first"},"PRODUCT_SINGLE":{"stockUsed":true,"label_currency":"Price, highest first","label_quantity_end":"in store","label_buttonInStock":"Add to cart","label_buttonOutStock":"Out of stock"}});

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.