1var BS = (typeof BS !== "undefined") ? BS : {}; 2 3(function($, BS, WA) { 4 5 BS.CartUtils = { 6 status: { 7 SUCCESS: 1, 8 ERROR: 0 9 } 10 }; 11 12 var Cart = function(user, options, translations) { 13 14 var defaults = { 15 buttonSelector: ".bs-add-to-cart", 16 cartSelector: ".bs-cart-container", 17 triggerSelector: ".bs-cart-trigger", 18 delegate: false, 19 catchOn: "body", 20 initShowDelay: 1500, 21 removeDelay: 8000 22 }; 23 24 var self = this; 25 var idPrefix = "cartItem-"; 26 var dataAttr = "product-id"; 27 var requests = {}; 28 var undoEnabled = false; 29 var requestTypes = { 30 ADD: 1, 31 REMOVE: 2 32 }; 33 34 var location = window.location.host; 35 36 this.texts = { 37 notInStock: "", 38 notBoughtMin: "", 39 quantity: "", 40 removeItem: "" 41 }; 42 43 $.extend(self.texts, translations); 44 var cartOptions = $.extend({}, defaults, options); 45 46 var cartAjaxReceiver = "/wa_script/basket_ajax.php"; 47 var cartBody, cartList, cartTotal, cartTrigger, cartCount; 48 var addToCartBtn, undo, undoTimeoutId, userId; 49 50 if(typeof user === "undefined") 51 { 52 throw "An user ID is not set!"; 53 } 54 else 55 { 56 userId = user; 57 } 58 59 var cartWrapper = $(cartOptions.cartSelector); 60 61 if(cartWrapper.length > 0) 62 { 63 //store jQuery objects 64 cartBody = cartWrapper.find('.body'); 65 cartList = cartBody.find('ul').eq(0); 66 cartTotal = cartWrapper.find('.checkout').find('span'); 67 cartTrigger = cartWrapper.children(cartOptions.triggerSelector); 68 cartCount = cartTrigger.children('.count'); 69 addToCartBtn = null; 70 undo = cartWrapper.find('.undo'); 71 72 registerEvents(); 73 } 74 75 /** 76 * 77 * @param HTMLElement button 78 * @param Event event 79 */ 80 function handleBtnClickEvent(button, event) 81 { 82 //event.preventDefault(); 83 addToCart($(button)); 84 } 85 86 function refreshAddToCartButtons() 87 { 88 if(!cartOptions.delegate) 89 { 90 if(addToCartBtn) 91 { 92 addToCartBtn.off("click.BS.Cart"); 93 } 94 addToCartBtn = $(cartOptions.buttonSelector); 95 addToCartBtn.on("click.BS.Cart", function(event) { 96 handleBtnClickEvent(this, event); 97 }); 98 } 99 } 100 101 function registerEvents() 102 { 103 //add product to cart 104 if(cartOptions.delegate) 105 { 106 $(cartOptions.catchOn).on("click.BS.Cart", cartOptions.buttonSelector, function(event) { 107 handleBtnClickEvent(this, event); 108 }); 109 } 110 else 111 { 112 refreshAddToCartButtons(); 113 } 114 115 //open/close cart 116 cartTrigger.on('click.BS.Cart', function(event){ 117 event.preventDefault(); 118 toggleCart(); 119 }); 120 121 //close cart when clicking on the .cd-cart-container::before (bg layer) 122 cartWrapper.on('click.BS.Cart', function(event){ 123 if( $(event.target).is($(this)) ) toggleCart(true); 124 }); 125 126 //delete an item from the cart 127 cartList.on('click.BS.Cart', '.delete-item', function(event){ 128 event.preventDefault(); 129 if(isActionAllowed(parseInt($(event.target).parents('.product').data(dataAttr)), requestTypes.REMOVE)) 130 { 131 removeProduct($(event.target).parents('.product')); 132 } 133 }); 134 135 //reinsert item deleted from the cart 136 undo.on('click.BS.Cart', 'a', function(event){ 137 event.preventDefault(); 138 if(isUndoEnabled()) 139 { 140 disableUndo(); 141 clearInterval(undoTimeoutId); 142 undoAjax(function(id) { 143 var deleted = cartList.find('.deleted'), 144 deletedQty; 145 deleted.data(dataAttr, id); 146 deleted.attr("id", idPrefix + id); 147 deletedQty = parseNumber(deleted.find(".quantity").text()); 148 deleted.addClass('undo-deleted').one('webkitAnimationEnd oanimationend msAnimationEnd animationend', function(){ 149 $(this).off('webkitAnimationEnd oanimationend msAnimationEnd animationend').removeClass('deleted undo-deleted').removeAttr('style'); 150 quickUpdateCart(deletedQty); 151 }); 152 loadCartItems(function(data) { 153 updateCartTotal(data.response_data.totals.total_price); 154 }); 155 }); 156 } 157 }); 158 } 159 160 /** 161 * Tries to add an item to the cart via AJAX request 162 * On success runs supplied callback function 163 * @param form 164 * @param callback 165 */ 166 function addToCartAjax(form, callback, button) 167 { 168 var form_action = form.attr("action"), 169 requestToken = ""; 170 var variant_id = 0; 171 if (WA.Url_translator.enabled === true) 172 { 173 var blizzi = BS.Basket.explode("pid=", form_action); 174 var blizzi2 = BS.Basket.explode("&vid=", blizzi[1]); 175 var product_id = blizzi2[0]; 176 if (typeof (blizzi2[1]) !== "undefined") 177 { 178 variant_id = blizzi2[1]; 179 } 180 } 181 else 182 { 183 var blizzi = BS.Basket.explode("/", form_action); 184 var product_id = blizzi[6]; 185 if (typeof (blizzi[7]) !== "undefined") 186 { 187 variant_id = blizzi[7]; 188 } 189 } 190 var add_product_info = form[0].querySelectorAll('button[type=submit]')[0].dataset.productInfo || null; 191 add_basket_v6(variant_id, product_id, form, button, callback, add_product_info); 192 } 193 194 function add_basket_v6(variant_id, product_id, form, button, callback, add_product_info = null) 195 { 196 var quantity, quantityInput; 197 quantityInput = form.find(".quantity-input"); 198 if(quantityInput.length) 199 { 200 quantity = quantityInput.val(); 201 } 202 else 203 { 204 quantity = 1; 205 } 206 quantity = BS.Basket.calcMultiplesInc(form[0], quantity); 207 208 var random_id = Math.floor((Math.random() * 10000) + 1); 209 requestToken = generateRequestToken(); 210 var request = { 211 method: "add", 212 kusy: quantity, 213 item: product_id, 214 item_variant: variant_id, 215 variant_selected: form.find("input[name=variant_selected]").length == 0 ? "" : form.find("input[name=variant_selected]").val(), 216 ciselnik1: form.find("select[name=ciselnik1]").length == 0 ? "" : form.find("select[name=ciselnik1]").val(), 217 ciselnik2: form.find("select[name=ciselnik2]").length == 0 ? "" : form.find("select[name=ciselnik2]").val(), 218 ciselnik3: form.find("select[name=ciselnik3]").length == 0 ? "" : form.find("select[name=ciselnik3]").val(), 219 poznamka: "", 220 stock: form.find("input[name=stock]").length == 0 ? "" : form.find("input[name=stock]").val(), 221 availability: form.find("input[name=availability]").length == 0 ? "" : form.find("input[name=availability]").val(), 222 delivery_to_day: form.find("input[name=delivery_to_day]").length == 0 ? "" : form.find("input[name=delivery_to_day]").val(), 223 number: form.find("input[name=number]").length == 0 ? "" : form.find("input[name=number]").val(), 224 parameter1: form.find("input[name=parameter1]").length == 0 ? "" : form.find("input[name=parameter1]").val(), 225 parameter2: form.find("input[name=parameter2]").length == 0 ? "" : form.find("input[name=parameter2]").val(), 226 parameter3: form.find("input[name=parameter3]").length == 0 ? "" : form.find("input[name=parameter3]").val(), 227 manufacturer: form.find("input[name=manufacturer]").length == 0 ? "" : form.find("input[name=manufacturer]").val(), 228 ean: form.find("input[name=ean]").length == 0 ? "" : form.find("input[name=ean]").val(), 229 id: userId, 230 do_not_save_session: "1", 231 get_aditional_info: "0", 232 new_cart: "1", 233 add_product_info: add_product_info 234 }; 235 236 if(button !== null) 237 { 238 addRequest(requestToken, request, requestTypes.ADD, {button: button}); 239 } 240 else 241 { 242 //user didn't click on buy button 243 addRequest(requestToken, request, requestTypes.ADD, {animateCart: true}); 244 } 245 dispatchAjaxStartedEvent(requestToken); 246 $.post(cartAjaxReceiver, request, function(data) { 247 if(data.status === "1") 248 { 249 250 BS.Basket.notifyMultiplesInc(data); 251 252 dispatchItemAddedToCartEvent(requestToken); 253 dispatchAjaxFinishedEvent(requestToken, BS.CartUtils.status.SUCCESS); 254 255 //fetch current cart items 256 if(typeof callback === "function") 257 { 258 callback(data); 259 } 260 } 261 else if(data.status === "3") 262 { 263 dispatchAjaxFinishedEvent(requestToken, BS.CartUtils.status.ERROR); 264 //min quantity required 265 BS.ui.popMessage.alert(self.texts.notBoughtMin + " " + data.response); 266 } 267 else if(data.status === "2") 268 { 269 dispatchAjaxFinishedEvent(requestToken, BS.CartUtils.status.ERROR); 270 //not in stock, or other error 271 BS.ui.popMessage.alert(self.texts.notInStock); 272 } 273 removeRequest(requestToken); 274 }, "json"); 275 } 276 277 /** 278 * Loads cart items via AJAX call and runs a callback function 279 * @param callback 280 */ 281 function loadCartItems(callback) 282 { 283 $.get(cartAjaxReceiver + '?cart=1&show_easy_content=1&id=' + userId, function(data) { 284 if(typeof callback === "function") 285 { 286 callback(data); 287 BS.event.trigger('basket.content.loaded', { content: cartWrapper }); 288 } 289 }, "json"); 290 } 291 292 /** 293 * Removes an item from cart 294 * On success runs callback function 295 * @param id 296 * @param callback 297 */ 298 function removeFromCartAjax(id, callback) 299 { 300 var token = generateRequestToken(); 301 addRequest(token, parseInt(id), requestTypes.REMOVE); 302 $.get(cartAjaxReceiver + "?method=remove&id_record=" + id + "&id=" + userId, function(data) { 303 if(data === "1") 304 { 305 callback(); 306 } 307 else 308 { 309 //error 310 } 311 removeRequest(token); 312 }); 313 } 314 315 /** 316 * Does undo operation and return recently deleted item to the cart 317 * @param callback 318 */ 319 function undoAjax(callback) 320 { 321 $.get(cartAjaxReceiver + "?undo=1&id=" + userId, function(data) { 322 if(data.status === "1") 323 { 324 callback(data.new_id); 325 } 326 }, "json"); 327 } 328 329 /** 330 * Toggles visible of the cart 331 * @param bool 332 */ 333 function toggleCart(bool) { 334 var cartIsOpen = ( typeof bool === 'undefined' ) ? cartWrapper.hasClass('cart-open') : bool; 335 336 if( cartIsOpen ) { 337 cartWrapper.removeClass('cart-open'); 338 //reset undo 339 clearInterval(undoTimeoutId); 340 undo.removeClass('visible'); 341 cartList.find('.deleted').remove(); 342 343 setTimeout(function(){ 344 cartBody.scrollTop(0); 345 //check if cart empty to hide it 346 if(isCartEmpty()) hideCart(); 347 }, 500); 348 } else { 349 cartWrapper.addClass('cart-open'); 350 } 351 } 352 353 function isCartEmpty() { 354 return Number(cartCount.find('li').eq(0).text()) === 0; 355 } 356 357 /** 358 * Adds item to the cart. 359 * @param trigger element (button) 360 */ 361 function addToCart(trigger) { 362 //send added product via AJAX 363 var form = trigger.closest("form"); 364 addFromForm(form, trigger); 365 366 } 367 368 function addFromForm(form, button) { 369 addToCartAjax(form, function() { 370 loadCartItems(function(data) { 371 updateCartItems(data.response_data.totals, data.response_data.items); 372 }); 373 }, button); 374 } 375 376 /** 377 * Updates items in the cart (quantity etc.) and adds new items 378 * @param totals 379 * @param items 380 */ 381 function updateCartItems(totals, items) 382 { 383 var qty, 384 item, 385 newQty, 386 currentQty; 387 //iterate through items 388 //if ID is not in the list, add it; otherwise update 389 for(var key in items) 390 { 391 qty = 0; 392 item = $("#cartItem-" + key); 393 if(!!item.length) 394 { 395 //already in the cart, update price and quantity 396 newQty = parseNumber(items[key].qty); 397 currentQty = parseNumber(getItemQuantity(item)); 398 if(currentQty !== newQty) 399 { 400 qty = newQty - currentQty; 401 } 402 updateItem(item, items[key].price, items[key].qty); 403 } 404 else 405 { 406 //add new item to the cart 407 addProduct(items[key]); 408 qty = parseNumber(items[key].qty); 409 } 410 411 if(qty !== 0) 412 { 413 updateCartCount(qty, true); 414 } 415 } 416 updateCartTotal(totals.total_price); 417 showCart(); 418 } 419 420 421 /** 422 * Show the cart to the user 423 */ 424 function showCart() 425 { 426 cartWrapper.removeClass('empty'); 427 } 428 429 /** 430 * Hide the cart 431 */ 432 function hideCart() 433 { 434 cartWrapper.addClass("empty"); 435 } 436 437 /** 438 * Updates item's detail in the cart 439 * @param item 440 * @param price 441 * @param qty 442 */ 443 function updateItem(item, price, qty) 444 { 445 item.find("span.price").html(price); 446 item.find("div.quantity label").children().eq(0).html(qty); 447 } 448 449 function getItemQuantity(item) 450 { 451 return item.find("div.quantity label").children().eq(0).text(); 452 } 453 454 /** 455 * Adds an item to the cart (DOM) 456 * @param addedItem 457 */ 458 function addProduct(addedItem) { 459 //take image of the product from the page 460 var productAdded = $('<li class="product" id="' + idPrefix + addedItem.id + '">' + 461 '<div class="product-image">' + 462 '<a href="/' + addedItem.link + '">' + 463 '<img src="' + addedItem.image + '" alt="" title="">' + 464 '</a>' + 465 '</div>' + 466 '<div class="product-details">' + 467 '<h3>' + 468 '<a href="/' + addedItem.link + '">' + addedItem.name + '</a>' + 469 '</h3>' + 470 '<span class="price">' + addedItem.price + '</span>' + 471 '<div class="actions">' + 472 '<a href="#0" class="delete-item">' + self.texts.removeItem + 473 '</a>' + 474 '<div class="quantity">' + 475 '<label for="product-qty'+ addedItem.id +'">' + self.texts.quantity + ' <span>' + addedItem.qty + '</span></label>' + 476 //'<span class="select">' + 477 //'<select id="producty-qty-'+ addedItem.id +'" name="quantity"><option value="1">1</option><option value="2">2</option><option value="3">3</option><option value="4">4</option><option value="5">5</option><option value="6">6</option><option value="7">7</option><option value="8">8</option><option value="9">9</option>' + 478 //'</select>' + 479 //'</span>' + 480 '</div>' + 481 (addedItem.reservation ? addedItem.reservation.html : '') + 482 '</div>' + 483 '</div>' + 484 '</li>'); 485 productAdded.data(dataAttr, addedItem.id); 486 cartList.prepend(productAdded); 487 } 488 489 /** 490 * Removes an item from the cart 491 * @param product element 492 */ 493 function removeProduct(product) { 494 clearInterval(undoTimeoutId); 495 cartList.find('.deleted').remove(); 496 497 //send Ajax request and delete from SESSION 498 removeFromCartAjax(product.data(dataAttr), function() { 499 BS.Conversion.getEvent('', '', '', 'remove_from_cart'); 500 501 var topPosition = product.offset().top - cartBody.children('ul').offset().top; 502// var productQuantity = Number(product.find('.quantity').find('select').val()); 503// var productTotPrice = Number(product.find('.price').text().replace('$', '')) * productQuantity; 504 505 product.css('top', topPosition+'px').addClass('deleted'); 506 updateCartCount(-parseNumber(product.find(".quantity").text()));
506 507 enableUndo(); 508 loadCartItems(function(data) { 509 if(data.empty === "1") 510 { 511 //at this point, the cart is completely empty so just set the total price to zero 512 setCartTotalToZero(); 513 } 514 else 515 { 516 updateCartTotal(data.response_data.totals.total_price); 517 } 518 }); 519 520 //wait 8sec before completely remove the item 521 undoTimeoutId = setTimeout(function(){ 522 undo.removeClass('visible'); 523 cartList.find('.deleted').remove(); 524 }, cartOptions.removeDelay); 525 }); 526 } 527 528 /** 529 * Quickly update counter, don't bother with animations and whatnot 530 * @param qty number total quantity 531 */ 532 function quickUpdateCart(qty) { 533 var quantity, 534 total; 535 quantity = Number(cartCount.find('li').eq(0).text()); 536 total = quantity + qty; 537 cartCount.find('li').eq(0).text(total); 538 cartCount.find('li').eq(1).text(total); 539 } 540 541 /** 542 * Update cart items count 543 * @param quantity how much to add/subtract (ie 1, -1 etc.) 544 * @param animate do a little animation 545 */ 546 function updateCartCount(quantity, animate) { 547 var qty = ((typeof quantity !== "undefined") ? quantity : 1); 548 var current = formatNumber(Number(cartCount.find('li').eq(0).text()) + qty); 549 cartCount.find("li").eq(1).text(current); 550 if(!cartWrapper.hasClass('empty') && typeof animate !== "undefined" && animate) 551 { 552 cartCount.addClass('update-count'); 553 setTimeout(function() { 554 cartCount.find('li').eq(0).text(current); 555 }, 150); 556 557 setTimeout(function() { 558 cartCount.removeClass('update-count'); 559 }, 200); 560 } 561 else 562 { 563 cartCount.find('li').eq(0).text(current); 564 } 565 } 566 567 /** 568 * Set the cart total price to zero. 569 */ 570 function setCartTotalToZero() 571 { 572 //use regexp to replace any number in a string 573 //we also want to preserve any currency signs, etc. 574 var pattern = /[0-9](?:[0-9]|(?: |\s)(?=[0-9]))*(?:[,.][0-9]+)?/g; 575 var totalPrice = cartTotal.html(); 576 cartTotal.html(totalPrice.replace(pattern, 0)); 577 } 578 579 /** 580 * Update total price 581 * @param price 582 */ 583 function updateCartTotal(price) { 584 cartTotal.html( price ); 585 } 586 587 /** 588 * Parse string containing a number convert it to its number reprezentation. 589 * Return null on failure 590 * @param number 591 * @returns Number|null 592 */ 593 function parseNumber(number) 594 { 595 var parsed = /(\d+(?:[\.,]\d+)?)/.exec(number); 596 if(parsed) 597 { 598 return Number(parsed[1].replace(",", ".")); 599 } 600 else 601 { 602 return null; 603 } 604 } 605 606 /** 607 * Formats given number. 608 * @param (number) number 609 * @returns (number) 610 */ 611 function formatNumber(number) 612 { 613 if(Math.abs(number % 1) === 0) 614 { 615 //number is an integer 616 return number; 617 } 618 else 619 { 620 //it's a floating point value, let's round it 621 return roundNumber(number, number.toString().split(".")[1].length === 1 ? 1 : 2); 622 } 623 } 624 625 /** 626 * Round the number. 627 * @param (number) number 628 * @param (int) precision 629 * @returns {number} 630 */ 631 function roundNumber(number, precision) 632 { 633 if(!isNaN(number) 634 && !isNaN(precision)) 635 { 636 var factor = Math.pow(10, parseInt(precision)); 637 var rounded = Math.round(number * factor); 638 return rounded / factor; 639 } 640 else 641 { 642 return 0; 643 } 644 } 645 646 function dispatchAjaxFinishedEvent(token, status) 647 { 648 var request = fetchRequest(token); 649 if(request.extra.button) 650 { 651 request.extra.button.trigger("done.BS.Cart", {requestToken: token, requestStatus: status}); 652 } 653 else if(request.extra.animateCart) 654 { 655 var element = cartWrapper.find(".bs-cart-trigger"); 656 element.on("animationend", function(e) { 657 if(e.originalEvent.animationName === "shake") 658 { 659 element.removeClass("shake"); 660 } 661 }); 662 element.addClass("shake"); 663 } 664 } 665 666 function dispatchItemAddedToCartEvent(token) 667 { 668 var request = fetchRequest(token); 669 cartWrapper.trigger("itemAdded.BS.Cart", [request.data]); 670 } 671 672 function dispatchAjaxStartedEvent(token) 673 { 674 var request = fetchRequest(token); 675 if(request.extra.button) 676 { 677 request.extra.button.trigger("start.BS.Cart", {requestToken: token}); 678 } 679 } 680 681 function generateRequestToken() 682 { 683 //length 36 684 var chars = "0123456789abcdefghijklmnopqrstuvwxyz", 685 token = "", 686 index; 687 for(var i = 0; i < 11; i++) 688 { 689 index = Math.floor(Math.random() * (35 - 0 + 1)) + 0; 690 token += chars[index]; 691 } 692 return token; 693 } 694 695 function isActionAllowed(productID, action) 696 { 697 var allow = true; 698 for(var key in requests) 699 { 700 if(requests.hasOwnProperty(key) 701 && requests[key].type === action 702 && requests[key].product === productID) 703 { 704 allow = false;
705 break; 706 } 707 } 708 return allow; 709 } 710 711 function addRequest(token, request, type, additionalData) 712 { 713 requests[token] = { 714 type: type, 715 product: request.item, 716 data: request 717 }; 718 if(typeof additionalData !== "undefined") 719 { 720 requests[token]["extra"] = additionalData; 721 } 722 return true; 723 } 724 725 function removeRequest(token) 726 { 727 return delete requests[token]; 728 } 729 730 function fetchRequest(token) 731 { 732 if(requests.hasOwnProperty(token)) 733 { 734 return requests[token]; 735 } 736 else 737 { 738 return false; 739 } 740 } 741 742 function enableUndo() 743 { 744 undo.addClass('visible'); 745 undoEnabled = true; 746 } 747 748 function disableUndo() 749 { 750 undo.removeClass('visible'); 751 undoEnabled = false; 752 } 753 754 function isUndoEnabled() 755 { 756 return undoEnabled; 757 } 758 759 /** 760 * Initialize the cart 761 * (Loads contents via AJAX) 762 */ 763 this.init = function() 764 { 765 loadCartItems(function (data) { 766 if(data.empty !== "1") 767 { 768 //add all items to the cart 769 var items = data.response_data.items; 770 for(var key in items) 771 { 772 addProduct(items[key]); 773 } 774 //update cart info 775 updateCartTotal(data.response_data.totals.total_price); 776 quickUpdateCart(data.response_data.totals.total_qty); 777 setTimeout(function() { 778 showCart(); 779 }, cartOptions.initShowDelay); 780 } 781 }); 782 }; 783 784 /** 785 * Znovu zaregistruje události tlaÄÃtek 786 */ 787 this.reloadButtons = function() 788 { 789 refreshAddToCartButtons(); 790 }; 791 792 this.addItem = function(form, button) 793 { 794 addFromForm($(form), typeof button !== "undefined" ? $(button) : null); 795 }; 796 797 this.isEmpty = function() 798 { 799 return isCartEmpty(); 800 }; 801 802 this.showCartBtn = function() 803 { 804 showCart(); 805 }; 806 807 this.hideCartBtn = function() 808 { 809 hideCart(); 810 }; 811 812 /** 813 * Returns outer most wrapper element 814 * @return HTMLElement 815 */ 816 this.getCartElement = function() 817 { 818 return cartWrapper.get(0); 819 } 820 }; 821 822 BS.Cart = Cart; 823})(jQuery, BS, WA);
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.