1class GcaBase { 2 loadPrices() { 3 let detailPrice = $("div[data-price-trigger='detail']"); 4 let listPrices = $("div[data-price-trigger='list']"); 5 let listPids = []; 6 7 if (listPrices && listPrices.length > 0) { 8 listPrices.each(function(i, div) { 9 let currentPrice = $(div).find("[data-type='current']"); 10 let hasCurrentPrice = currentPrice && currentPrice.text().length > 1; 11 if (!hasCurrentPrice) { 12 listPids.push( $(div).data("price-id") ); 13 } 14 }); 15 } 16 17 if (detailPrice.length > 0) { 18 let pid = $(detailPrice).data("price-id"); 19 jQuery.ajax({ 20 url: "/ajax?action=checkPrice&pid=" + pid + "&qty=1", 21 cache: false, 22 type: "get", 23 dataType: "json" 24 }).done(function(data) { 25 let price = data.body; 26 27 if (price !== undefined && price.hasOwnProperty("current")) { 28 let targetEl = $("div[data-price-trigger='detail'][data-price-id='" + pid + "']"); 29 let currentEl = targetEl.find("[data-type=current]"); 30 31 currentEl.html(price.current); 32 currentEl.attr("itemprop","price").attr("content", price["current-raw"]); 33 34 if (price.old) { 35 currentEl.addClass("has-old-price"); 36 targetEl.find("[data-type=old]").html(price.old); 37 targetEl.find("[data-type=old]").attr("itemprop","highPrice").attr("content", price["old-raw"]); 38 } 39 40 if (price.currency) { 41 targetEl.find("[data-type=currency]").attr("itemprop","priceCurrency").attr("content", price.currency); 42 } 43 44 targetEl.find("[data-type=discount]").html(price.discount); 45 targetEl.find("[data-type=vatDesc]").show(); 46 } 47 }); 48 } 49 50 if (listPids && listPids.length > 0) { 51 jQuery.ajax({ 52 url: "/ajax?action=checkPricesInList&pids=" + listPids, 53 cache: false, 54 type: "get", 55 dataType: "json" 56 }).done(function(data) { 57 let prices = data.body; 58 for (let i in prices) { 59 let price = prices[i]; 60 let targetEl = $("div[data-price-trigger='list'][data-price-id='"+price.id+"']"); 61 let currentEl = targetEl.find("[data-type=current]"); 62 63 currentEl.html(price.current); 64 currentEl.attr("itemprop","price").attr("content", price["current-raw"]); 65 66 if (price.old) { 67 currentEl.addClass("has-old-price"); 68 targetEl.find("[data-type=old]").html(price.old); 69 targetEl.find("[data-type=old]").attr("itemprop","highPrice").attr("content", price["old-raw"]); 70 } 71 72 if (price.currency) { 73 targetEl.find("[data-type=currency]").attr("itemprop","priceCurrency").attr("content", price.currency); 74 } 75 76 targetEl.find("[data-type=discount]").html(price.discount); 77 } 78 }); 79 } 80 } 81 82 loadStocks() { 83 let detailStocks = $("span[data-stock-trigger='detail']"); 84 let listStocks = $("div[data-stock-trigger='list']"); 85 let listPids = []; 86 87 if (listStocks && listStocks.length > 0) { 88 listStocks.each(function(i, div) { 89 if ($(div).text().trim().length === 0) { 90 listPids.push( $(div).data("stock-id") ); 91 } 92 }); 93 } 94 95 if (detailStocks.length > 0) { 96 let pid = $(detailStocks).data("stock-id"); 97 jQuery.ajax({ 98 url: "/ajax?action=checkStock&pid="+pid, 99 cache: false, 100 type: "get" 101 }).done(function(data) { 102 let target = $("span[data-stock-trigger='detail'][data-stock-id='"+pid+"']"); 103 target.html(data); 104 }); 105 } 106 107 if (listPids && listPids.length > 0) { 108 jQuery.ajax({ 109 url: "/ajax?action=checkStocksInList&pids="+listPids, 110 cache: false, 111 type: "get" 112 }).done(function(data) { 113 let htmlContent = jQuery.parseHTML(data); 114 let prices = $(htmlContent).find(".productStock"); 115 prices.each(function(i, el) { 116 let target = $("div[data-stock-trigger='list'][data-stock-id='"+el.id+"']"); 117 target.html($(el).html()); 118 }) 119 }); 120 } 121 } 122 123 loadAddToBasketButtons() { 124 let detailButtons = $("[data-addtobasket-trigger='detail']"); 125 let listButtons = $("[data-addtobasket-trigger='list']"); 126 let searchButtons = $("[data-addtobasket-trigger='search']"); 127 let listPids = []; 128 let searchPids = []; 129 130 if (listButtons && listButtons.length > 0) { 131 listButtons.each(function(i, div) { 132 if ($(div).text().trim().length === 0) { 133 listPids.push( $(div).data("addtobasket-id") ); 134 } 135 }); 136 } 137 138 if (searchButtons && searchButtons.length > 0) { 139 searchButtons.each(function(i, span) { 140 if ($(span).text().trim().length === 0) { 141 searchPids.push( $(span).data("addtobasket-id") ); 142 } 143 }); 144 } 145 146 if(detailButtons.length > 0) { 147 let pid = $(detailButtons).data("addtobasket-id"); 148 jQuery.ajax({ 149 url: "/ajax?action=getAddToBasketButtons&type=detail&pid="+pid, 150 cache: false, 151 type: "get" 152 }).done(function(data) { 153 let target = $("[data-addtobasket-trigger='detail'][data-addtobasket-id='"+pid+"']"); 154 target.html( data ); 155 }); 156 } 157 158 if(listPids && listPids.length > 0) { 159 jQuery.ajax({ 160 url: "/ajax?action=getAddToBasketButtons&type=list&pids="+listPids, 161 cache: false, 162 type: "get" 163 }).done(function(data) { 164 let htmlContent = jQuery.parseHTML(data); 165 let buttons = $(htmlContent).find(".addtobasketButton"); 166 buttons.each(function(i, el) { 167 let target = $("[data-addtobasket-trigger='list'][data-addtobasket-id='"+el.id+"']"); 168 target.html( $(el).html() ); 169 }) 170 }); 171 } 172 173 if(searchPids && searchPids.length > 0) { 174 jQuery.ajax({ 175 url: "/ajax?action=getAddToBasketButtons&type=search&pids="+searchPids, 176 cache: false, 177 type: "get" 178 }).done(function(data) { 179 let htmlContent = jQuery.parseHTML(data); 180 let buttons = $(htmlContent).find(".addtobasketButton"); 181 buttons.each(function(i, el) { 182 let target = $("[data-addtobasket-trigger='search'][data-addtobasket-id='"+el.id+"']"); 183 target.html( $(el).html() ); 184 }) 185 }); 186 } 187 } 188 189 loadAddToBasketQtyButtons() { 190 $(document).on("click", ".increaseQty", function(e) { 191 let qtyInput = $(this).prev("input"); 192 let qtyStep = Number(qtyInput.data("qty-step")); 193 let qtyValue = Number(qtyInput.val().replace(",",".")); 194 let newQty = (qtyValue + qtyStep).toFixed(2); 195 qtyInput.val(gca.getNearestQty(newQty, qtyStep)); 196 qtyInput.change() 197 e.stopImmediatePropagation(); 198 }); 199 200 $(document).on("click", ".decreaseQty", function(e) { 201 let qtyInput = $(this).next("input"); 202 let qtyStep = Number(qtyInput.data("qty-step")); 203 let qtyValue = Number(qtyInput.val().replace(",",".")); 204 if (qtyValue > qtyStep) { 205 let newQty = (qtyValue - qtyStep).toFixed(2); 206 qtyInput.val(gca.getNearestQty(newQty, qtyStep)); 207 qtyInput.change() 208 } 209 e.stopImmediatePropagation(); 210 }); 211 } 212 213 getCity(postalCode, callback) { 214 jQuery.ajax({ 215 url: "/ajax?action=getAddressCity&postalcode=" + postalCode, 216 cache: false, 217 type: "get", 218 error: function (xhr, ajaxOptions, thrownError) { 219 callback(null); 220 } 221 }).done(function(city) { 222 callback(city.trim()); 223 }); 224 } 225
226 loadPostCodeInputs() { 227 let self = this; 228 229 $(document).on('blur','.postCodeInput', function() { 230 let code = $(this).val(); 231 let cityId = $(this).data('city_element'); 232 let cityInput = $('input#' + cityId); 233 let countryId = $(this).data('country_element'); 234 let countryInput = $('select#' + countryId); 235 236 if (countryInput.val() === "NO") { 237 self.getCity(code, function(city) { 238 cityInput.val(city); 239 }); 240 } 241 }); 242 } 243 244 loadAdminMenu() { 245 let target = $("[data-ajax_target='top-admin-menu']"); 246 247 if (target.attr("data-entity-id") !== undefined) { 248 let entityType = target.data("entity-type"); 249 let entityId = target.data("entity-id"); 250 let edit = target.data("edit"); 251 252 jQuery.ajax({ 253 dataType: "html", 254 url: "/ajax?action=getAdminMenuV2&entityType=" + entityType + "&entityId=" + entityId + "&edit=" + edit, 255 cache: false, 256 type: "get", 257 success: function(data) { 258 target.html(data); 259 jQuery.getScript( "/themes/javascript/gca.func.admin.js"); 260 }, 261 error: function(jqXHR, textStatus, errorThrown) { 262 //console.log(textStatus); 263 } 264 }); 265 } 266 } 267 268 loadUserButtonLinks() { 269 jQuery.ajax({ 270 dataType: "html", 271 url: "/ajax?action=getUserButtonLinks", 272 cache: false, 273 type: "get" 274 }).done(function(data) { 275 $("[data-ajax_target='user-button-links']").html(data); 276 }); 277 } 278 279 loadBasketAmount() { 280 jQuery.ajax({ 281 url: "/ajax?action=getBasketAmount", 282 cache: false, 283 type: "get" 284 }).done(function(data) { 285 gca.updateAjaxTarget("basket-amount", data); 286 }); 287 } 288 289 loadBasketSize() { 290 jQuery.ajax({ 291 url: "/ajax?action=getBasketSize", 292 cache: false, 293 type: "get" 294 }).done(function(data) { 295 gca.updateAjaxTarget("basket-size", data); 296 }); 297 } 298 299 loadRecentProducts() { 300 jQuery.ajax({ 301 url: "/ajax?action=getRecentProducts", 302 cache: false, 303 type: "get" 304 }).done(function(data) { 305 $("[data-ajax_target='recent-products']").html(data); 306 }); 307 } 308 309 loadProductData() { 310 gca.loadPrices(); 311 gca.loadStocks(); 312 gca.loadAddToBasketButtons(); 313 gca.loadAddToBasketQtyButtons(); 314 } 315 316 loadFavoritesStuff() { 317 jQuery.ajax({ 318 dataType: "json", 319 url: "/ajax?action=getFavorites&type=json", 320 cache: false, 321 type: "get" 322 }).done(function(data) { 323 gca.updateFavoriteIcons(data.favorites); 324 gca.updateFavoritesSize(data.size); 325 }); 326 } 327 328 loadMenu() { 329 let config = { 330 over: function() { 331 $('.dropdown-xl-content', this).stop( true, true ).fadeIn(150); 332 $(this).toggleClass('open'); 333 }, timeout: 100, 334 out: function() { 335 $('.dropdown-xl-content', this).stop( true, true ).fadeOut(150); 336 $(this).toggleClass('open'); 337 } 338 }; 339 340 $(".dropdown-xl-trigger").hoverIntent(config); 341 } 342 343 // TODO: Remove?? 344 loadCookieButton() { 345 $('.cookie-close').click(function(){ 346 $('.cookies').fadeOut(500); 347 }); 348 } 349 350 executeCustomFunctions() { 351 let elements = $('[data-ajax=true][data-update=true]'); 352 let actions = {}; 353 354 if (elements.length > 0) { 355 jQuery.each(elements, function( index, element ) { 356 let action = $(element).data('action'); 357 if (!actions[action]) { 358 actions[action] = []; 359 } 360 actions[action].push(element); 361 }); 362 363 for (let action in actions) { 364 if (actions.hasOwnProperty(action)) { 365 gca.executeFunctionByName(action, window, actions[action]); 366 } 367 } 368 } 369 } 370 371 executeFunctionByName(functionName, context) { 372 let args = Array.prototype.slice.call(arguments, 2); 373 let namespaces = functionName.split("."); 374 let func = namespaces.pop(); 375 for (let i = 0; i < namespaces.length; i++) { 376 context = context[namespaces[i]]; 377 }
378 return context[func].apply(context, args); 379 } 380 381 scrollToTop() { 382 $(window).scroll( function(){ 383 let a = $(window).scrollTop(); 384 if (a > 250) { 385 $('.scrollToTop').addClass('show-scroller'); 386 } 387 else { 388 $('.scrollToTop').removeClass('show-scroller'); 389 } 390 }); 391 $('.scrollToTop').on('click', function() { 392 let completeCalled = false; 393 $("html, body").animate( 394 { scrollTop: "0" }, 395 { 396 complete : function(){ 397 if(!completeCalled){ 398 completeCalled = true; 399 } 400 } 401 } 402 ); 403 }); 404 } 405 406 setupAddToBasketEvents() { 407 $("body").on("click", "button[data-trigger='addToBasket']", function() { 408 let el = $(this); 409 let wrapper = el.closest("[data-itag]"); 410 let iTag = wrapper.data("itag"); 411 let pid = iTag.split("_")[0]; 412 let qty = 1; 413 let withQty = el.data("with-qty"); 414 415 if (withQty) { 416 let input = wrapper.find("input[data-qty-id='" + pid + "']"); 417 if (input.length === 0) { 418 // Fallback.. 419 input = $("input[data-qty-id=" + pid + "]"); 420 } 421 if (input.length === 1) { 422 qty = input.val(); 423 } 424 } 425 else if (el.data("qty-default").length > 0) { 426 qty = el.data("qty-default"); 427 } 428 429 gca.addToBasket2(pid, qty); 430 return false; 431 }); 432 } 433 434 // Favorites 435 getFavorites(callback) { 436 jQuery.ajax({ 437 dataType: "html", 438 url: "/ajax?action=getFavorites", 439 cache: false, 440 type: "get" 441 }).done(function(data) { 442 $("[data-ajax_target='favorites']").html(data); 443 gca.loadFavoritesStuff(); 444 callback(true); 445 }); 446 } 447 448 toggleFavorites(pid) { 449 let element = $("button[data-favorite-id='" + pid + "']"); 450 let label = element.data("title-add"); 451 if (element.attr("data-favorite-state") === "true") { 452 gca.removeFromFavorites(pid); 453 } 454 else { 455 gca.addToFavorites(pid); 456 label = element.data("title-remove"); 457 } 458 element.find("span").text(label); 459 } 460 461 addToFavorites(pid) { 462 jQuery.ajax({ 463 dataType: "json", 464 url: "/ajax?action=addToFavorites&pid="+pid, 465 cache: false, 466 type: "get" 467 }).done(function(data) { 468 gca.updateFavoriteIcons(data.body.favorites); 469 gca.updateFavoritesSize(data.body.size); 470 }); 471 } 472 473 removeFromFavorites(pid) { 474 jQuery.ajax({ 475 dataType: "json", 476 url: "/ajax?action=removeFromFavorites&pid="+pid, 477 cache: false, 478 type: "get" 479 }).done(function(data) { 480 gca.updateFavoriteIcons(data.body.favorites); 481 gca.updateFavoritesSize(data.body.size); 482 if (window.location.href.indexOf("/favorites") > 0) { 483 gca.getFavorites(function (callback) { 484 485 }); 486 } 487 }); 488 } 489 490 addFavoritesToBasket() { 491 jQuery.ajax({ 492 dataType: "html", 493 url: "/ajax?action=addFavoritesToBasket", 494 cache: false, 495 type: "post" 496 }).done(function(data) { 497 gca.updateBasketElements(data); 498 let htmlContent = jQuery.parseHTML(data); 499 let notifications = $(htmlContent).find('div#notifications').html(); 500 $("#notifications").html(notifications); 501 gca.removeNotification(3000); 502 }); 503 } 504 505 updateFavoritesSize(size) { 506 $("[data-ajax_target='favorites-size']").html(size); 507 } 508 509 updateFavoriteIcons(productIds) { 510 let listElements = $(document).find("[data-favorite-type='list']"); 511 let detailElements = $(document).find("[data-favorite-type='detail']"); 512 513 // Mark all as false.. 514 if (listElements.length > 0) { 515 listElements.each(function() { 516 $(this).removeClass("active"); 517 $(this).attr("data-favorite-state", "false"); 518 }); 519 } 520 521 if (detailElements.length > 0) { 522 detailElements.each(function() { 523 $(this).removeClass("active"); 524 $(this).attr("data-favorite-state", "false"); 525 }); 526 } 527 528 // Mark only active.. 529 for (let key in productIds) { 530 let productId = productIds[key]; 531 let activeElement = $(document).find("[data-favorite-id='" + productId + "']"); 532 let label = activeElement.data("title-remove"); 533 534 if (activeElement.length > 0) { 535 if (activeElement.attr('data-favorite-type') === 'detail') { 536 activeElement.addClass("active"); 537 activeElement.attr("data-favorite-state", "true"); 538 activeElement.find("span").text(label); 539 } 540 else { 541 activeElement.addClass("active"); 542 activeElement.attr("data-favorite-state", "true"); 543 activeElement.find("span").text(label); 544 } 545 } 546 } 547 } 548 549 // Breadcrumbs 550 getBreadcrumbs2(type, id, parent) { 551 let url = "/ajax?action=getBreadcrumbs2&type=" + type + "&id=" + id; 552 if (parent) { 553 url = url + "&parent=" + parent; 554 } 555 556 jQuery.ajax({ 557 dataType: "html", 558 url: url, 559 cache: false, 560 type: "get" 561 }).done(function(data) { 562 $("[data-ajax_trigger='breadcrumbs']").html(data); 563 }); 564 } 565 566 setupProductClickEvents() { 567 $(document).on("click", "[data-link-item-type='product']", function() { 568 const el = $(this).closest(".product-block"); 569 gca.pushSelectItemEventToGoogle(el); 570 }) 571 } 572 573 toggleBreadcrumbs() { 574 let toggleButton = $('i.toggle-breadcrumb'); 575 if (toggleButton.hasClass('fa-angle-down')) { 576 toggleButton.removeClass('fa-angle-down').addClass('fa-angle-up') 577 } else { 578 toggleButton.removeClass('fa-angle-up').addClass('fa-angle-down') 579 } 580 581 $('.hidden-breadcrumb').slideToggle(); 582 } 583 584 addMultipleToBasket() { 585 $('.add-more-btn i').attr('hidden', false); 586 let products = []; 587 588 // Get raw input value.. 589 let rawInput = $("#quickCartInput").val(); 590 591 // Split into separate lines.. 592 let lines = rawInput.split(/\r?\n/); 593 594 // Split each line into product number and quantity.. 595 jQuery.each(lines, function(i, value) { 596 let line = jQuery.trim(value); 597 products.push(line.replace('\t', ':')); 598 }); 599 600 let delimitedString = products.join(","); 601 this.addMultipleToBasketAjax(delimitedString); 602 } 603 604 addMultipleToBasketAjax(delimitedString) { 605 jQuery.ajax({ 606 dataType: "html", 607 url: "/ajax?action=addMultipleToBasket&products=" + delimitedString, 608 cache: false, 609 type: "post" 610 }).fail(function(jqXHR, error, errorThrown) { 611 if (jqXHR.status === 405) { 612 jQuery.ajax({ 613 dataType: "html", 614 url: "/ajax?action=notify&type=addToBasketNotAllowed", 615 cache: false, 616 type: "get" 617 }).done(function(data) { 618 gca.notifyAddToBasket(data); 619 $('.add-more-btn i').attr('hidden', true); 620 }); 621 } 622 }).done(function(data) { 623 gca.updateBasketElements(data); 624 gca.loadStocks(); 625 let htmlContent = jQuery.parseHTML(data); 626 let notifications = $(htmlContent).find('div#notifications').html(); 627 $("#notifications").html(notifications); 628 $('.add-more-btn').removeClass('loading'); 629 630 setTimeout(function() { 631 $('.add-more-btn i').attr('hidden', true); 632 633 $("#notifications").find('.alert-success, .alert-warning').fadeOut('slow', function() { 634 $(this).remove(); 635 }); 636 }, 3000); 637 }); 638 } 639 640 updateBasketElements(data) { 641 let htmlContent = jQuery.parseHTML(data); 642 let basketSize = $(htmlContent).find('div#basketSize').text(); 643 let basketAmount = $(htmlContent).find('div#basketAmount').text(); 644 let basketTable = $(htmlContent).find('div#basketTable').html(); 645 let basketAmounts = $(htmlContent).find('div#basketAmounts').html(); 646 gca.updateAjaxTarget("basket-size", basketSize); 647 gca.updateAjaxTarget("basket-amount", basketAmount); 648 gca.updateAjaxTarget("basket-table", basketTable); 649 gca.updateAjaxTarget("basket-amounts", basketAmounts); 650 } 651 652 notifyAddToBasket(data) { 653 let a = $('#notifications'); 654 a.hide().html('<div class="notification">' + data + '</div>').fadeIn('slow'); 655 setTimeout(function() { 656 a.find('.alert-success, .alert-warning').fadeOut('slow', function() { 657 $(this).remove(); 658 }); 659 }, 3000); 660 } 661 662 removeFromBasket(blId, pid, qty) { 663 jQuery.ajax({ 664 dataType: "html", 665 url: "/ajax?action=removeFromBasket&blid=" + blId, 666 cache: false, 667 type: "get" 668 }).done(function(data) { 669 gca.updateBasketElements(data); 670 gca.loadStocks(); 671 if (pid !== undefined && qty !== undefined) { 672 gca.pushRemoveFromBasketEventGoogle(pid, qty); 673 } 674 }); 675 } 676 677 copyBasket(bid) { 678 gca.showPageLoader(); 679 jQuery.ajax({ 680 dataType: "html", 681 url: "/ajax?action=copyBasket&bid="+bid, 682 cache: false, 683 type: "get" 684 }).fail(function(jqXHR, error, errorThrown) { 685 if (jqXHR.status === 405) { 686 jQuery.ajax({ 687 dataType: "html", 688 url: "/ajax?action=notify&key=basket.copy.expired&type=warning", 689 cache: false, 690 type: "get" 691 }).done(function(data) { 692 gca.notifyAddToBasket(data); 693 }); 694 } 695 }).done(function(data) { 696 gca.hidePageLoader(); 697 gca.loadBasketSize(); 698 gca.loadBasketAmount(); 699 700 jQuery.ajax({ 701 dataType: "html", 702 url: "/ajax?action=notify&key=basket.copy.success&type=success", 703 cache: false, 704 type: "get" 705 }).done(function(data) { 706 gca.notifyAddToBasket(data); 707 }); 708 }); 709 } 710 711 checkBasketFreight() { 712 let postcode = $("input[name=postcode]").val(); 713 if (postcode && postcode.length > 0) { 714 jQuery.ajax({ 715 url: "/ajax?action=checkFreight&postcode=" + postcode, 716 cache: false, 717 type: "get" 718 }).done(function(data) { 719 $("#freightResponse").html(data.trim()); 720 const myModalAlternative = new bootstrap.Modal('#freightModal', {}); 721 myModalAlternative.show(); 722 }); 723 } 724 } 725 726 getNearestQty(qty, multiple) { 727 let nearestQty = ((qty / multiple) * multiple); 728 return nearestQty % 1 !== 0 ? nearestQty.toFixed(2) : nearestQty; 729 } 730 731 // Notifications 732 notify(type, message, duration, param1, param2, param3, param4, param5) { 733 jQuery.ajax({ 734 dataType: "html", 735 url: "/ajax?action=notify&type="+encodeURIComponent(type)+"&key="+encodeURIComponent(message)+"¶m1="+encodeURIComponent(param1)+"¶m2="+encodeURIComponent(param2)+"¶m3="+encodeURIComponent(param3)+"¶m4="+encodeURIComponent(param4)+"¶m5="+encodeURIComponent(param5), 736 cache: false, 737 type: "get" 738 }).done(function(element) { 739 $("#notifications").html(element); 740 }); 741 742 if (duration && duration > 0) { 743 setTimeout(function() { 744 $('#notifications').children().hide(function() { 745 $(this).remove(); 746 }); 747 }, (duration*1000)); 748 } 749 } 750 751 checkNotifications() { 752 jQuery.ajax({ 753 dataType: "html", 754 url: "/ajax?action=checkNotifications", 755 cache: false, 756 type: "get" 757 }).done(function(element) { 758 $("#notifications").append(element); 759 }); 760 } 761 762 removeNotification(delay) { 763 setTimeout(function() { 764 $('#notifications').children().hide(function() { 765 $(this).remove(); 766 }); 767 }, delay); 768 } 769 770 // Menu stuff.. 771 toggleOffCanvasMenu(pos) { 772 let element = $(".off-canvas-menu." + pos);
773 let overlay = $(".off-canvas-overlay"); 774 if (element.width() > 0) { 775 element.removeClass("visible"); 776 overlay.hide(); 777 } 778 else { 779 element.addClass("visible"); 780 overlay.show(); 781 } 782 } 783 784 hideOffCanvasMenues() { 785 let leftMenu = $(".off-canvas-menu.left"); 786 let rightMenu = $(".off-canvas-menu.right"); 787 let overlay = $(".off-canvas-overlay"); 788 789 leftMenu.removeClass("visible"); 790 rightMenu.removeClass("visible"); 791 overlay.hide(); 792 } 793 794 // Misc 795 pushRemoveFromBasketEventGoogle(pid, qty) { 796 jQuery.ajax({ 797 dataType: "json", 798 url: "/ajax?action=allowTrack&recipient=google&service=analytics&event=removeFromCart", 799 cache: false, 800 type: "get" 801 }).done(function(allowed) { 802 if (allowed === true) { 803 jQuery.ajax({ 804 dataType: "json", 805 url: "/ajax?action=getProduct&pid="+pid+"&qty="+qty, 806 cache: false, 807 type: "get" 808 }).done(function(product) { 809 if (product.number.length > 0) { 810 dataLayer.push({ 811 'event': 'remove_from_cart', 812 'currency': "NOK", 813 'value': product.price, 814 'items': [ 815 { 816 item_id: product.number, 817 item_name: product.title, 818 price: product.price, 819 quantity: qty 820 } 821 ] 822 }); 823 } 824 }); 825 } 826 }); 827 } 828 829 pushAddToBasketEventGoogle(pid, qty) { 830 jQuery.ajax({ 831 dataType: "json", 832 url: "/ajax?action=allowTrack&recipient=google&service=analytics&event=addToCart", 833 cache: false, 834 type: "get" 835 }).done(function(allowed) { 836 if (allowed === true) { 837 jQuery.ajax({ 838 dataType: "json", 839 url: "/ajax?action=getProduct&pid="+pid+"&qty="+qty, 840 cache: false, 841 type: "get" 842 }).done(function(product) { 843 if (product.number.length > 0) { 844 dataLayer.push({ 845 'event': 'add_to_cart', 846 'currency': "NOK", 847 'value': product.price, 848 'items': [ 849 { 850 item_id: product.number, 851 item_name: product.title, 852 price: product.price, 853 quantity: Number(qty) 854 } 855 ] 856 }); 857 } 858 }); 859 } 860 }); 861 } 862 863 pushAddToBasketEventGoogleLegacy(pid, qty) { 864 jQuery.ajax({ 865 dataType: "json", 866 url: "/ajax?action=allowTrack&recipient=google&event=addToBasket", 867 cache: false, 868 type: "get" 869 }).done(function(allowed) { 870 if (allowed === true) { 871 jQuery.ajax({ 872 dataType: "json", 873 url: "/ajax?action=getProduct&pid="+pid+"&qty="+qty, 874 cache: false, 875 type: "get" 876 }).done(function(product) { 877 if (product.number.length > 0) { 878 dataLayer.push({ 879 'event': 'addToCart', 880 'ecommerce': { 881 'currencyCode': 'NOK', 882 'add': { 883 'products': [{ 884 'name': product.title, 885 'id': product.number, 886 'price': product.price, 887 'brand': product.vendor, 888 'quantity': qty 889 }] 890 } 891 } 892 }); 893 } 894 }); 895 } 896 }); 897 } 898 899 pushProductViewToGoogle(number, title, price, currency) { 900 jQuery.ajax({ 901 dataType: "json", 902 url: "/ajax?action=allowTrack&recipient=google&service=analytics&event=viewItem", 903 cache: false, 904 type: "get" 905 }).done(function(allowed) { 906 if (allowed === true) { 907 dataLayer.push({ecommerce: null}); 908 dataLayer.push({ 909 'event': 'view_item', 910 'ecommerce': { 911 'items': [{ 912 'item_name': title, 913 'item_id': number, 914 'price': price, 915 'currency': currency 916 }] 917 } 918 }); 919 } 920 }); 921 } 922 923 pushProductListsToGoogle() { 924 jQuery.ajax({ 925 dataType: "json", 926 url: "/ajax?action=allowTrack&recipient=google&service=analytics&event=viewItemList", 927 cache: false, 928 type: "get" 929 }).done(function(allowed) { 930 if (allowed === true) { 931 const productLists = $("[data-list-entity='products']"); 932 if (productLists !== undefined) { 933 productLists.each(function(i, listEl) { 934 gca.pushProductListToGoogle($(listEl), true); 935 }); 936 } 937 } 938 }); 939 } 940 941 pushProductListToGoogle(listEl, allowed) { 942 if (listEl !== undefined && listEl.length > 0) { 943 if (allowed) { 944 const listType = listEl.attr("data-product-list-type"); 945 const productElements = listEl.find(".product-block"); 946 let products = []; 947 948 productElements.each(function (i, el) { 949 const sku = $(el).find("[itemprop='sku']").attr("content"); 950 const name = $(el).find("[itemprop='name']").attr("content"); 951 products.push({ 952 "item_id": sku, 953 "item_name": name 954 }); 955 }); 956 957 dataLayer.push({ 958 'event': 'view_item_list', 959 'ecommerce': { 960 'currency': "NOK", 961 'item_list_id': listType, 962 'items': products 963 } 964 }); 965 } 966 else if (allowed === undefined) { 967 jQuery.ajax({ 968 dataType: "json", 969 url: "/ajax?action=allowTrack&recipient=google&service=analytics&event=viewItemList", 970 cache: false, 971 type: "get" 972 }).done(function(allowed) { 973 if (allowed === true) { 974 gca.pushProductListToGoogle(listEl, true); 975 } 976 }); 977 } 978 } 979 } 980 981 pushSelectItemEventToGoogle(el) { 982 if (el !== undefined && el.length > 0) { 983 jQuery.ajax({ 984 dataType: "json", 985 url: "/ajax?action=allowTrack&recipient=google&service=analytics&event=selectItem", 986 cache: false, 987 type: "get" 988 }).done(function(allowed) { 989 if (allowed === true) { 990 const sku = $(el).find("[itemprop='sku']").attr("content"); 991 const name = $(el).find("[itemprop='name']").attr("content"); 992 let listType = ""; 993 994 // Try to find list type.. 995 const listWrapper = $(el).closest("[data-product-list-type]"); 996 if (listWrapper !== undefined && listWrapper.length > 0) { 997 listType = listWrapper.data("product-list-type"); 998 } 999 1000 dataLayer.push({ 1001 'event': 'select_item', 1002 'ecommerce': { 1003 'item_list_id': listType, 1004 'items': [ 1005 { 1006 'item_id': sku, 1007 'item_name': name 1008 } 1009 ] 1010 } 1011 }); 1012 } 1013 }); 1014 } 1015 } 1016 1017 pushAddToBasketEventFacebook(pid, qty) { 1018 jQuery.ajax({ 1019 dataType: "json", 1020 url: "/ajax?action=allowTrack&recipient=facebook&event=addToBasket", 1021 cache: false, 1022 type: "get" 1023 }).done(function(allowed) { 1024 if (allowed === true) { 1025 jQuery.ajax({ 1026 dataType: "json", 1027 url: "/ajax?action=getProduct&pid=" + pid + "&qty=" + qty, 1028 cache: false, 1029 type: "get" 1030 }).done(function (product) { 1031 fbq('track', 'AddToCart', { 1032 content_name: product.title, 1033 content_ids: [product.number], 1034 content_type: 'product', 1035 value: product.price, 1036 currency: product.currency 1037 }); 1038 }); 1039 } 1040 }); 1041 } 1042 1043 pushProductViewToFacebook(number, title, price, currency) { 1044 jQuery.ajax({ 1045 dataType: "json", 1046 url: "/ajax?action=allowTrack&recipient=facebook&event=viewItem", 1047 cache: false, 1048 type: "get" 1049 }).done(function(allowed) { 1050 if (allowed === true) { 1051 fbq('track', 'ViewContent', { 1052 content_type: 'product', 1053 content_ids: [number], 1054 content_name: title, 1055 value: price, 1056 currency: currency 1057 }); 1058 } 1059 }); 1060 } 1061 1062 addWishlistItem(wishlistId, productId, wishlistName) { 1063 let el = $('.added-to-wishlist'); 1064 el.show(); 1065 el.find('.wishlist-dummy').text(wishlistName); 1066 jQuery.ajax({ 1067 dataType: "html", 1068 url: "/ajax-wishlist?action=addWishlistItem&wishlistId="+wishlistId+"&productId="+productId, 1069 cache: true, 1070 type: "get" 1071 }).done(function(data) { 1072 setTimeout(function(){$('.added-to-wishlist').hide();}, 3000); 1073 $("i#wishlist_"+wishlistId).removeClass("fa-angle-right").addClass("fa-check"); 1074 }); 1075 } 1076 1077 toggleWishlistSelector() { 1078 $('#wishlistsSelector').slideToggle(300); 1079 $(this).toggleClass('close'); 1080 } 1081 1082 copyOrder(oid) { 1083 gca.showPageLoader(); 1084 1085 jQuery.ajax({ 1086 dataType: "json", 1087 url: "/ajax?action=copyOrder&oid="+oid, 1088 cache: false, 1089 type: "post" 1090 }).done(function(response) { 1091 let notification = response.notification; 1092 gca.updateAjaxTarget("basket-size", response.meta.size); 1093 gca.updateAjaxTarget("basket-amount", response.meta.amount); 1094 gca.hidePageLoader(); 1095 gca.notify(notification.type, notification.key, notification.duration, notification.param1, notification.param2, notification.param3, notification.param4, notification.param5); 1096 }); 1097 } 1098 1099 updateAjaxTarget(target, content) { 1100 $("[data-ajax_target='" + target + "']").html(content); 1101 } 1102 1103 display(view, pageId) { 1104 let hasPage = pageId !== undefined && pageId.trim().length > 0 1105 if(!hasPage) { 1106 pageId = -1 1107 }
1108 gca.setListView(view, pageId); 1109 let container = $("[data-list-target='products']"); 1110 1111 if (!$(".show-more").is(":visible")) { 1112 if (view === 'list') { 1113 container.find('.product-grid').each(function() { 1114 if (!$(this).hasClass("no-change")) { 1115 $(this).attr('class', 'product-list'); 1116 $(this).find('.product-block').each(function(index, element) { 1117 $(element).parent().addClass("col-fullwidth"); 1118 }); 1119 $(".product-filter .display .grid").removeClass("active"); 1120 $(".product-filter .display .list").addClass("active"); 1121 } 1122 }); 1123 } else { 1124 container.find('.product-list').attr('class', 'product-grid'); 1125 1126 container.find('.products-block .product-block').each(function(index, element) { 1127 $(element).parent().removeClass("col-fullwidth"); 1128 }); 1129 1130 container.find(".product-filter .display .list").removeClass("active"); 1131 container.find(".product-filter .display .grid").addClass("active"); 1132 } 1133 } 1134 } 1135 1136 selectorDropdown() { 1137 let dropdown = $('.selector-dropdown li').on('click', function() { 1138 let isDisabled = $(this).find('a').hasClass("disabled"); 1139 let outPut = $(this).find('a').text(); 1140 let button = $(this).parent().parent().find('.btn-selector span'); 1141 if (!isDisabled) { 1142 button.text(outPut).not('i'); 1143 } 1144 }); 1145 } 1146 1147 1148 scrollToTarget(href) { 1149 $('html, body').animate({ 1150 scrollTop: $(href).offset().top 1151 }, 500, function () { 1152 window.location.hash = href; 1153 }); 1154 } 1155 1156 getUrlParameter(sParam) { 1157 let sPageURL = decodeURIComponent(window.location.search.substring(1)), 1158 sURLVariables = sPageURL.split('&'), 1159 sParameterName, 1160 i; 1161 1162 for (i = 0; i < sURLVariables.length; i++) { 1163 sParameterName = sURLVariables[i].split('='); 1164 1165 if (sParameterName[0] === sParam) { 1166 return sParameterName[1] === undefined ? true : sParameterName[1]; 1167 } 1168 } 1169 }; 1170 1171 addURLParameterWithoutReload(key, value) { 1172 let url = window.location.href; 1173 let urlParts = url.split("?"); 1174 let baseURL = urlParts[0]; 1175 let params = urlParts[1]; 1176 1177 let newParam = key + "=" + value; 1178 url = baseURL + "?" + params + "&" + newParam; 1179 window.history.replaceState(null, null, url); 1180 } 1181 1182 updateURLParameterWithoutReload(key, value) { 1183 let url = window.location.href; 1184 let urlParts = url.split("?"); 1185 let baseURL = urlParts[0]; 1186 let params = urlParts[1]; 1187 let newParams = ""; 1188 let temp = ""; 1189 1190 if (params) { 1191 const parts = params.split("&"); 1192 for (let i = 0; i < parts.length; i++) { 1193 if (parts[i].split('=')[0] !== key){ 1194 newParams += temp + parts[i]; 1195 temp = "&"; 1196 } 1197 } 1198 } 1199 1200 let newParam = temp + key + "=" + value; 1201 url = baseURL + "?" + newParams + newParam; 1202 window.history.replaceState(null, null, url); 1203 } 1204 1205 removeURLParameterWithoutReload(key) { 1206 let url = window.location.href; 1207 let urlParts = url.split("?"); 1208 let baseURL = urlParts[0]; 1209 let params = urlParts[1]; 1210 let newParams = ""; 1211 let temp = ""; 1212 1213 if (params) { 1214 const parts = params.split("&"); 1215 for (let i = 0; i < parts.length; i++) { 1216 if (parts[i].split('=')[0] === key) { 1217 continue; 1218 } 1219 newParams += temp + parts[i]; 1220 temp = "&"; 1221 } 1222 } 1223 1224 url = baseURL; 1225 if (newParams && newParams.length > 0) { 1226 url = baseURL + "?" + newParams; 1227 } 1228 window.history.replaceState(null, null, url); 1229 } 1230 1231 setListView(view, pageId) { 1232 sessionStorage.setItem('listView|' + pageId, view); 1233 } 1234 1235 getCookie(cname) { 1236 let name = cname + "="; 1237 let decodedCookie = decodeURIComponent(document.cookie); 1238 let ca = decodedCookie.split(';'); 1239 for (let i = 0; i < ca.length; i++) { 1240 let c = ca[i]; 1241 while (c.charAt(0) === ' ') { 1242 c = c.substring(1); 1243 } 1244 if (c.indexOf(name) === 0) { 1245 return c.substring(name.length, c.length); 1246 } 1247 } 1248 return ""; 1249 } 1250 1251 createCookie(name, value, days) { 1252 let expires; 1253 1254 if (days) { 1255 let date = new Date(); 1256 date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000)); 1257 expires = "; expires=" + date.toGMTString(); 1258 } else { 1259 expires = ""; 1260 } 1261 document.cookie = encodeURIComponent(name) + "=" + encodeURIComponent(value) + expires + "; path=/"; 1262 } 1263 1264 eraseCookie(name) { 1265 this.createCookie(name, "", -1); 1266 } 1267 1268 getListView(pageId) { 1269 let view = sessionStorage.getItem('listView|' + pageId); 1270 if (view === undefined) { 1271 view = sessionStorage.getItem('listView|undefined'); 1272 } 1273 return view; 1274 } 1275 1276 addToBasket2(pid, qty) { 1277 jQuery.ajax({ 1278 dataType: "json", 1279 url: "/ajax?action=addToBasket&pid="+pid+"&qty="+qty, 1280 cache: false, 1281 type: "post" 1282 }).done(function(response) { 1283 let notification = response.notification; 1284 if (response.status === "OK") { 1285 gca.pushAddToBasketEventGoogle(pid, qty); 1286 gca.pushAddToBasketEventGoogleLegacy(pid, qty); 1287 gca.pushAddToBasketEventFacebook(pid, qty); 1288 gca.updateAjaxTarget("basket-size", response.meta.size); 1289 gca.updateAjaxTarget("basket-amount", response.meta.amount); 1290 } 1291 gca.notify(notification.type, notification.key, notification.duration, notification.param1, notification.param2, notification.param3, notification.param4, notification.param5); 1292 }); 1293 } 1294 1295 handleFirstTab(e) { 1296 if (e.keyCode === 9) { 1297 document.body.classList.add('user-is-tabbing'); 1298 window.removeEventListener('keydown', gca.handleFirstTab); 1299 window.addEventListener('mousedown', gca.handleMouseDownOnce); 1300 } 1301 } 1302 1303 handleMouseDownOnce() { 1304 document.body.classList.remove('user-is-tabbing'); 1305 window.removeEventListener('mousedown', gca.handleMouseDownOnce); 1306 window.addEventListener('keydown', gca.handleFirstTab); 1307 } 1308 1309 isInViewport(element) { 1310 let elementTop = element.offset().top; 1311 let elementBottom = elementTop + element.outerHeight(); 1312 let viewportTop = $(window).scrollTop(); 1313 let viewportBottom = viewportTop + $(window).height(); 1314 return elementBottom > viewportTop && elementTop < viewportBottom; 1315 } 1316 1317 showPageLoader() { 1318 $("#page-loader").attr("hidden", false); 1319 } 1320 1321 hidePageLoader() { 1322 $("#page-loader").attr("hidden", true); 1323 } 1324 1325 openSubCategoriesLevel(id, level) { 1326 jQuery.ajax({ 1327 url: "/ajax?action=getSubCategoryLevel&id=" + id + "&level=" + level, 1328 cache: false, 1329 type: "get" 1330 }).done(function (data) { 1331 let htmlContent = jQuery.parseHTML(data); 1332 let subCategories = $(htmlContent).find('div#subCategories').html(); 1333 1334 if(level === 1) { 1335 gca.updateAjaxTarget("sub-category-level-2", subCategories); 1336 $("#level-2").addClass("show"); 1337 $(".menu-nav > .category-link").addClass("show").attr('onClick', 'gca.oneLevelBack(1);'); 1338 } else if(level === 2) { 1339 gca.updateAjaxTarget("sub-category-level-3", subCategories); 1340 $("#level-3").addClass("show"); 1341 $(".menu-nav > .category-link").addClass("show").attr('onClick', 'gca.oneLevelBack(2);'); 1342 } 1343 }); 1344 } 1345 1346 oneLevelBack(level) { 1347 if(level === 1) { 1348 $("#level-2").removeClass("show"); 1349 $(".menu-nav > .category-link").removeClass("show"); 1350 } else if(level === 2) { 1351 $("#level-3").removeClass("show") 1352 $(".menu-nav > .category-link").attr('onClick', 'gca.oneLevelBack(1);'); 1353 } 1354 } 1355 1356 waitForElement(selector) { 1357 return new Promise(resolve => { 1358 if (document.querySelector(selector)) { 1359 return resolve(document.querySelector(selector)); 1360 } 1361 1362 const observer = new MutationObserver(mutations => { 1363 if (document.querySelector(selector)) { 1364 observer.disconnect(); 1365 resolve(document.querySelector(selector)); 1366 } 1367 }); 1368 1369 observer.observe(document.body, { 1370 childList: true, 1371 subtree: true 1372 }); 1373 }); 1374 } 1375 1376 showLocationTopMenu() { 1377 const locationSelector = document.querySelectorAll('.location-select'); 1378 locationSelector.forEach(locationSelect => { 1379 if (locationSelect !== null && locationSelect.length > 0) { 1380 const location = document.querySelectorAll('.location-select > option:checked'); 1381 const locationTitle = document.querySelectorAll(".locale-button-desktop .dropdown-toggle .
1381international-title"); 1382 const titleFlag = document.querySelectorAll('.locale-button-desktop .dropdown-toggle img'); 1383 1384 location.forEach(local => { 1385 locationTitle.forEach(title => { 1386 title.innerText = local.value.toUpperCase(); 1387 }) 1388 1389 titleFlag.forEach(flag => { 1390 flag.src = "/themes/flags/" + local.value.toLowerCase() + ".svg"; 1391 }) 1392 }) 1393 } 1394 }) 1395 } 1396 1397 showLocationDesktop(el) { 1398 let formEl = document; 1399 if (el !== undefined && el.length > 0) { 1400 formEl = el.closest(".location-form"); 1401 } 1402 1403 const locationSelector = document.querySelectorAll('.location-select'); 1404 1405 locationSelector.forEach(locationSelect => { 1406 if (locationSelect !== null && locationSelect.length > 0) { 1407 const location = formEl.querySelectorAll('.location-select > option:checked'); 1408 const language = formEl.querySelectorAll('.language-select > option:checked'); 1409 const countryFlag = formEl.querySelectorAll(".country-container .country-flag"); 1410 const countryName = formEl.querySelectorAll(".country-container > span"); 1411 const languageFlag = formEl.querySelectorAll(".language-container .country-flag"); 1412 const languageName = formEl.querySelectorAll(".language-container > span"); 1413 const currencyContainer = formEl.querySelectorAll(".active-currency"); 1414 1415 location.forEach(local => { 1416 countryFlag.forEach(flag => { 1417 flag.src = "/themes/flags/" + local.value.toLowerCase() + ".svg"; 1418 }) 1419 1420 countryName.forEach(name => { 1421 name.innerText = local.innerText.trim(); 1422 }) 1423 1424 currencyContainer.forEach(currency => { 1425 currency.innerHTML = local.dataset.currency; 1426 }) 1427 }) 1428 1429 language.forEach(lang => { 1430 languageFlag.forEach(flag => { 1431 flag.src = "/themes/flags/" + lang.dataset.language.toLowerCase() + ".svg"; 1432 }) 1433 1434 languageName.forEach(name => { 1435 name.innerText = lang.innerText.trim(); 1436 }) 1437 }) 1438 1439 const saveBtn = document.querySelectorAll(".locale-button-desktop .btn-primary"); 1440 saveBtn.forEach(btn => { 1441 btn.addEventListener("click", () => { 1442 gca.showLocationTopMenu(); 1443 }) 1444 }) 1445 } 1446 }) 1447 } 1448 1449 debounced(delay, fn) { 1450 let timerId; 1451 return function (...args) { 1452 if (timerId) { 1453 clearTimeout(timerId); 1454 } 1455 timerId = setTimeout(() => { 1456 fn(...args); 1457 timerId = null; 1458 }, delay); 1459 } 1460 } 1461} 1462 1463class GcaRange { 1464 constructor(min, max) { 1465 this.min = min; 1466 this.max = max; 1467 } 1468} 1469
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.