1DEBUG = false; 2if (typeof console == 'undefined') { 3 DEBUG = false; 4} 5 6$(function() { 7 $('#lockdownmessage').click(function(e) { 8 e.preventDefault(); 9 $('#lockdown-group-form').submit(); 10 return false; 11 }) 12}) 13 14var ProductGroup = function (data) { 15 if (!data) { 16 data = {} 17 } 18 19 20 this.defaultPriceText = ''; 21 this.defaultStcodeText = ''; 22 this.defaultAvailText = ''; 23 24 this.category = data.category || ''; 25 this.products = data.products || []; 26 this.availability = data.availability || []; 27 this.levels = data.levels || []; 28 this.leadtimes = data.leadtimes || []; 29 30 this.supplierleadtimes = data.supplierleadtimes || []; 31 this.supplierleadtimestext = data.supplierleadtimestext || []; 32 33 this.showPhysicalStockLevels = data.showPhysicalStockLevels || []; 34 this.showOutOfStockDueDays = data.showOutOfStockDueDays || []; 35 this.stockLevelInStockText = data.stockLevelInStockText || []; 36 this.stockLevelOutOfStockText = data.stockLevelOutOfStockText || []; 37 this.availabilityFactorDueDays = data.availabilityFactorDueDays || []; 38 this.checkPhysicalStockShowIsSetInWebopts = data.checkPhysicalStockShowIsSetInWebopts || []; 39 40 this.prices = data.prices || []; 41 this.pricesIncExVat = data.pricesIncExVat || []; 42 this.minord = data.minord || []; 43 this.soincr = data.soincr || []; 44 this.splitpack = data.splitpack || []; 45 this.packquan = data.packquan || []; 46 this.combinations = data.combinations || []; 47 this.selectedOptions = data.selectedOptions || []; 48 this.images = data.images || []; 49 this.prodlink = data.prodlink || []; 50 this.ga4data = data.ga4data || []; 51 52 this.lockeddown = data.lockeddown || []; 53 this.loyalty_points_value = data.loyalty_points_value || []; 54 this.loyalty_points_earn = data.loyalty_points_earn || []; 55 56 this.selectedProduct = null; 57 this.priceElement = null; 58 this.stcodeElement = null; 59 this.availElement = null; 60 this.addButton = null; 61 this.wishlistButton = null; 62 this.quoteButton = null; 63 64 this.prodtitle = data.prodtitle || []; 65 66 /** 67 * callbacks for various events 68 * simply add a function to one and it will 69 * be called at the appropriate point 70 */ 71 this.onProductSelected = null; 72 this.onNoProductSelected = null; 73 74 var scope = this; 75 76 this.init = function () { 77 this.addButton = $('#addtobasket').Button(); 78 this.wishlistButton = $('#wishlistsubmitinput').Button(); 79 this.quoteButton = $('#quotesubmitinput').Button(); 80 81 this.selects = $('select.groupedProduct'); 82 this.selectCount = scope.selects.length; 83 this.selects.change(function (e) { 84 scope.selectChanged(e) 85 }); 86 this.priceElement = $('.addtobasket .price'); 87 this.AltpriceElement = $('.alt-unit-price .price'); 88 this.stcodeElement = $('.addtobasket .stcode'); 89 this.availElement = $('.addtobasket .availability'); 90 this.quanElement = $('.addtobasket .ordquan'); 91 this.defaultPriceText = this.priceElement.html(); 92 this.defaultStcodeText = this.stcodeElement.html(); 93 this.defaultAvailText = this.availElement.html(); 94 this.clearProduct(true); 95 this.addtowishlistgroup = $('.addtowishlistgroup'); 96 this.addtoquotegroup = $('.addtoquotegroup'); 97 $(".loyalty_points_paywithpoints").hide(); // initial hide 98 99 this.loyalty_points_value_elem = $('.loyalty_points .loyalty_points_value'); 100 this.loyalty_points_earn_elem = $('.loyalty_points .loyalty_points_earn'); 101 102 /** 103 * only one select with only one option 104 * shouldnt happen if data if ok, but can't hurt to check 105 */ 106 if (this.selectCount == 1 && this.selects[0].children.length == 2) { 107 this.selects[0].selectedIndex = 1; 108 $(this.selects[0]).change(); 109 } 110 111 112 /* 113 * Check the selects and reload the product if all of them are set. 114 * This code will work if back is hit in the browser. 115 */ 116 var allSet = true; 117 var selections = []; 118 for (var i = 0; i < this.selectCount; i++) { 119 if (this.selects[i].selectedIndex === 0) { 120 allSet = false;
121 break; 122 } 123 selections[selections.length] = this.selects[i].selectedIndex; 124 } 125 if (allSet) { 126 for (var i = 0; i < this.selectCount; i++) { 127 this.selects[i].selectedIndex = selections[i]; 128 $(this.selects[i]).change(); 129 } 130 } 131 132 }; 133 134 this.addFavourites = function (prod) { 135 $('#addstockcode').val(this.products[prod]); 136 } 137 138 this.selectChanged = function (e) { 139 140 141 var select = e.target, 142 option = select.selectedIndex, 143 selno = this.selects.index(select); 144 145 // Nothing has been selected in one of the dropdowns so load the category image 146 if(option===0){ 147 updateFavouritesButton(""); 148 showProductImage(""); 149 } 150 151 if(option===0){ 152 updateReviewLink(""); 153 } 154 155 this.clearAhead(selno); 156 157 if (option == 0) { 158 this.selectedOptions[selno] = null; 159 } 160 161 this.selectedOptions[selno] = select.options[option].text; 162 163 var nextSel = this.selects[selno + 1]; 164 165 var valid = this.findValidProducts(); 166 167 if (!valid) { 168 this.clearProduct(); 169 this.onNoProductSelectedCallback(); 170 this.loyalty_points_earn_elem.hide(); 171 //this.addtowishlistgroup.hide(); 172 //this.addtoquotegroup.hide(); 173 return; 174 } 175 176 // we have a winner 177 if (valid.length == 1) { 178 this.setProduct(this.findProduct()); 179 this.addtowishlistgroup.show(); 180 this.addtoquotegroup.show(); 181 } 182 183 // more than one match, populate the next select 184 if (nextSel) { 185 this.populateSelect(nextSel, valid); 186 nextSel.disabled = false; 187 debug("Triggered select change"); 188 debug(select); 189 190 if($(select).hasClass("grp-colour")){ 191 debug("Triggered select change on COLOUR, start next SIZE select"); 192 debug(nextSel); 193 debug("Preselecting next block to swap image"); 194 if($(nextSel).hasClass("grp-size")){ 195 // it has a size selection, preselect it to set the colour image 196 $(nextSel).addClass('active'); 197 $('.grp-size>option:eq(1)').attr('selected', true); 198 $('.grp-size').trigger('change'); 199 } 200 201 202 203 } 204 205 } 206 } 207 208 this.populateSelect = function (select, options) { 209 // keep the first line (choose a...) 210 var first = $(select).find(':first-child'); 211 212 // find the select number 213 var ix = this.selects.index(select); 214 215 $(select).html(first); 216 217 var done = []; 218 219 220 for (var i = 0; i < options.length; i++) { 221 opt = $('<option>'); 222 val = options[i][ix]; 223 224 if ($.inArray(val, done) == -1) { 225 opt.val(val); 226 opt.text(val); 227 $(select).append(opt); 228 } 229 230 done.push(val); 231 } 232 233 if (options.length == 1) { 234 opt.attr('selected', 'selected') 235 $(select).change(); 236 } 237 238 } 239 240 this.findValidProducts = function () { 241 debug('findValidProducts'); 242 243 var options = this.selectedOptions; 244 245 if (options.length == 0) { 246 debug('nothing selected'); 247 return false; 248 } 249 250 /** 251 * go through all the combinations 252 * and see if they match what we have selected so far 253 * if so, add to valid array 254 */ 255 var valid = $.grep(this.combinations, function (product, ix) { 256 for (var i = 0, len = options.length; i < len; i++) { 257 if (product[i] != options[i]) { 258 return false; 259 } 260 } 261 262 return true; 263 }); 264 265 debug(valid); 266 267 if (!valid.length) { 268 return false; 269 } 270 return valid; 271 } 272 273 /** 274 * clear all selects ahead of selno 275 */ 276 this.clearAhead = function (selno) { 277 debug('clearAhead(' + selno + ')'); 278 279 if (selno + 1 >= this.selectCount) { 280 return; 281 } 282 283 var scope = this; 284 285 for (var i = selno + 1; i < this.selects.length; i++) { 286 var select = this.selects[i]; 287 if (select.disabled) { 288 return; 289 } 290 291 debug('clearing select ' + i); 292 debug(select); 293 294 select.selectedIndex = 0; 295 scope.selectedOptions.splice(i - 1, 1); 296 297 if(i!==selno+1){ 298 select.disabled = true; 299 } 300 301 }; 302 303 this.clearProduct(); 304 } 305 306 307 this.setProduct = function (prod) { 308 debug('setProduct'); 309 310 this.priceElement.html(this.prices[prod] + this.pricesIncExVat[prod]); 311 312 if(typeof this.altunits !== "undefined" && typeof this.altunits[prod] !== "undefined" ){ 313 this.AltpriceElement.html(this.altunits[prod]); 314 } 315 316 317 this.selectedProduct = this.products[prod]; 318 this.stcodeElement.html( "<strong>" + this.prodtitle[prod] + "</strong></br>" + "Stock Code: <a href='" + this.prodlink[prod] + "'>" + this.selectedProduct + "</a>"); 319 320 321 322 if (this.selectedProduct!=='N/A'){ 323 updateFavouritesButton(this.selectedProduct); 324 showProductImage(this.selectedProduct); 325 updateReviewLink(this.selectedProduct); 326 } 327 328 329 /* 330 if(typeof this.selectedProduct !== undefined){ 331 $('select.groupedProduct').on("change", function(){ 332 if($('div > form > div.code > span.stcode').text()==='Please select from the options above.'){ 333 $('#accordian-reviews > div > div > div.review').html('There are no reviews for this product yet.'); 334 } 335 else{ 336 $('#accordian-reviews > div > div > div.review').html('There are no reviews for this product yet. <a href="/addreview.p
336hp?product=' + this.selectedProduct + '&category=' + $('input[name="returntoargcategory"]').val() + '">Be the first to add one!</a>'); 337 } 338 }); 339 } 340 */ 341 342 var avail = this.levels[prod]; 343 var supplierleadtime = this.supplierleadtimes[prod]; 344 var availabilityfactor = this.availability[prod]; 345 346 if (supplierleadtime > 0) { 347 //avail = 'Out Of Stock'; 348 avail += ' <i class="fa fa-truck"></i>' + this.supplierleadtimestext[prod]; 349 } 350 if (supplierleadtime == 0) { 351 if (avail > 0 ) { 352 if ( this.showPhysicalStockLevels == true || this.checkPhysicalStockShowIsSetInWebopts == true ){ 353 avail = '<i class="fa fa-check"></i>' + ' ' + avail + ' ' + this.stockLevelInStockText; 354 } else { 355 avail = '<i class="fa fa-check"></i>' + ' ' + this.stockLevelInStockText; 356 } 357 } else { 358 if (typeof this.availabilityFactorDueDays[availabilityfactor] != "undefined") { 359 avail = '<i class="fa fa-truck"></i>' + ' ' + this.availabilityFactorDueDays[availabilityfactor]; 360 } else { 361 if ( (this.showPhysicalStockLevels == true || this.checkPhysicalStockShowIsSetInWebopts == true) && this.showOutOfStockDueDays == true ) { 362 avail = '<i class="fa fa-truck"></i>' + ' ' + this.stockLevelOutOfStockText; 363 } else { 364 avail = '<i class="fa fa-close"></i>' + ' ' + this.stockLevelOutOfStockText; 365 } 366 } 367 } 368 } else { 369 if (avail > 0 ) { 370 if ( this.showPhysicalStockLevels == true || this.checkPhysicalStockShowIsSetInWebopts == true ){ 371 avail = '<i class="fa fa-check"></i>' + avail + ' ' + this.stockLevelInStockText; 372 } else { 373 avail = '<i class="fa fa-check"></i>' + ' ' + this.stockLevelInStockText; 374 } 375 } else { 376 if (typeof this.availabilityFactorDueDays[availabilityfactor] != "undefined") { 377 avail = '<i class="fa fa-truck"></i>' + ' ' + this.availabilityFactorDueDays[availabilityfactor]; 378 } else { 379 if ( (this.showPhysicalStockLevels == true || this.checkPhysicalStockShowIsSetInWebopts == true) && this.showOutOfStockDueDays == true ) { 380 avail = '<i class="fa fa-truck"></i>' + ' ' + this.supplierleadtimestext[prod]; 381 } else { 382 avail = '<i class="fa fa-close"></i>' + ' ' + this.stockLevelOutOfStockText; 383 } 384 } 385 } 386 } 387 388 this.availElement.html(avail); 389 390 var qt = this.getQuantityText(prod); 391 392 this.quanElement.html(qt); 393 $('#prodqty').val("1"); 394 395 $(".loyalty_points_paywithpoints").hide(); 396 if(this.loyalty_points_value[prod] > 0 ){ 397 this.loyalty_points_value_elem.html(this.loyalty_points_earn[prod] ); 398 399 // If logged in Pay with points option 400 sStr = '<input name="withpoints" id="withpointscheck" type="checkbox" value="true" /> <span>Pay with points</span>'; 401 $(".loyalty_points_paywithpoints").html(sStr); 402 $(".loyalty_points_paywithpoints").fadeIn(); 403 } 404 405 // If logged in earn else you could earn 406 if(this.loyalty_points_earn[prod]){ 407 408 var currentqty = $(document).find("input[class*='qty']").val(); 409 410 this.loyalty_points_earn_elem.html(this.loyalty_points_earn[prod]); 411 this.loyalty_points_earn_elem.show(); 412 } 413 414 415 416 $('.groupedbasketformaddstockcode_').val(this.selectedProduct); 417 $('#wishliststockcode').val(this.selectedProduct); 418 $('input[name=addstockcode]').val(this.selectedProduct); 419 420 // Managed baskets add stockcode ect for grouped products - hide normal group product info 421 if ($(".managedbasketform").length > 0) { 422 $(".manged-basket-stockcode").val(this.selectedProduct); 423 $(".manged-basket-stockcode").fadeOut().html("Stock Code: " + this.selectedProduct).fadeIn(); 424 $(".manged-basket-stocklevel").fadeOut().html(avail).fadeIn(); 425 $(".manged-basket-price").fadeOut().html("Price: " + this.prices[prod] + this.pricesIncExVat[prod]).fadeIn(); 426 427 // In stock check? 428 if (avail == 'Out Of Stock') { 429 $("#managedbasket-addtobasket").attr("disabled", true); 430 } else { 431 $("#managedbasket-addtobasket").attr("disabled", false); 432 } 433 } 434 435 this.addButton.Enable(); 436 this.addButton.show(); 437 this.wishlistButton.Enable(); 438 this.quoteButton.Enable(); 439 440 if (this.lockeddown[prod] == 1) { 441 $("#grp-prod-stcode").hide(); 442 $("#grp-prod-stocklevel").hide(); 443 $("#grp-prod-qty").hide(); 444 $("#grp-prod-basketbtn").hide(); 445 $("#grp-prod-wishlist").hide(); 446 $("#grp-prod-lockeddown").show(); 447 $('#lockdownemail').val('Request for ' + this.prodtitle[prod] + ' to be added to the approved list (' + this.products[prod] + ')'); 448 $('#lockdownmessage').val('Request for ' + this.products[prod] + ' to be added to the approved list'); 449 this.addButton.hide(); 450 this.addButton.Disable(); 451 452 } else { 453 $("#grp-prod-stcode").show(); 454 $("#grp-prod-stocklevel").show(); 455 $("#grp-prod-qty").show(); 456 $("#grp-prod-basketbtn").show(); 457 $("#grp-prod-wishlist").show(); 458 $("#grp-prod-lockeddown").hide(); 459 } 460 461 // Alt unit select fix 462 $('select.altunitselect').change(function(){ 463 464 var price = $('.pricespan'); 465 var priceinc = $('.pricespaninc'); 466 var opt = $(this).find('option:selected'); 467 var prc = opt.data('price'); 468 var prcinc = opt.data('priceinc');
469 price.text(prc); 470 priceinc.text("£" + prcinc.toFixed(2)); 471 472 //changes a hidden form element inside the actual form. 473 $(this).parent().parent().find('input#unit').val(opt.val()); 474 }); 475 476 this.onProductSelectedCallback(prod); 477 478 if (this.ga4data.length) { 479 $.ajax({ 480 type: 'POST', 481 url: '/ajaxGA4.php', 482 data: {action: 'view_item', codes: [this.ga4data[prod]]}, 483 success: function (response) { 484 var $el = $(response); 485 $('body').append($el); 486 } 487 }); 488 } 489 490 return true; 491 } 492 493 this.getQuantityText = function (prod) { 494 var mintext, inctext, showmintext = true, showinctext = true; 495 496 if(typeof this.altunits !== "undefined" && typeof this.altunits[prod] !== "undefined" ){ 497 showmintext = false; 498 showinctext = false; 499 } 500 501 if (this.minord[prod] > 1 && showmintext) { 502 mintext = 'A minimum order quantity of ' + this.minord[prod] + ' applies to this product.'; 503 } 504 if (this.soincr[prod] > 1 && showinctext) { 505 inctext = 'This product must be ordered in multiples of ' + this.soincr[prod] + ', quantities will be rounded up as you add them.'; 506 } 507 508 if (!isNaN(this.minord[prod])){ 509 $("#minorder").val(this.minord[prod]); 510 }else{ 511 $("#minorder").val(0); 512 } 513 if (!isNaN(this.soincr[prod])) { 514 $("#soincrtmp").val(this.soincr[prod]); 515 } else { 516 $("#soincrtmp").val(0); 517 } 518 519 var quantext = ''; 520 521 if (mintext) { 522 quantext = mintext; 523 } 524 if (inctext) { 525 quantext = quantext + '<br/>' + inctext; 526 } 527 528 return quantext; 529 } 530 531 /** 532 * no product was selected 533 */ 534 this.clearProduct = function (startup) { 535 debug('clearProduct'); 536 537 this.stcodeElement.html(this.defaultStcodeText); 538 this.priceElement.html(this.defaultPriceText); 539 this.availElement.html(this.defaultAvailText); 540 this.quanElement.html(''); 541 this.selectedProduct = null; 542 this.addButton.Disable(); 543 this.addButton.hide(); 544 this.wishlistButton.Disable(); 545 this.quoteButton.Disable(); 546 547 return false; 548 } 549 550 this.findProduct = function () { 551 debug('findProduct'); 552 553 var num = this.selectedOptions.length; 554 var combo, match; 555 556 if (num < this.selectCount) { 557 return null; 558 } 559 560 for (var i = 0, len = this.combinations.length; i < len; i++) { 561 combo = this.combinations[i]; 562 match = true; 563 564 for (var j = 0; j < num; j++) { 565 if (combo[j] != this.selectedOptions[j]) { 566 match = false; 567 break; 568 } 569 } 570 571 if (match) { 572 return i; 573 } 574 } 575 576 return null; 577 } 578 579 /** 580 * if a callback has been defined, calls it 581 * when a product is selected and passes 582 * in the stockcode and the index 583 */ 584 this.onProductSelectedCallback = function (prod) { 585 if (typeof this.onProductSelected === 'function') { 586 this.onProductSelected(this.selectedProduct, prod); 587 } 588 } 589 590 this.onNoProductSelectedCallback = function () { 591 if (typeof this.onNoProductSelected === 'function') { 592 this.onNoProductSelected(); 593 } 594 } 595 596} 597 598function debug(message) { 599 if (DEBUG) { 600 console.log(message); 601 } 602} 603 604 605function showProductImage(stockcode){ 606 607 var category=$('#categoryid').val(); 608 var show_preview_images=$('#preview_image').val(); 609 610 if(show_preview_images==='true'){ 611 if (typeof stockcode != 'undefined'){ 612 613 $.ajax({ 614 type: 'POST', 615 url: '/productGroupImage.php', 616 data: {'action':'getImage', 'stockcode':stockcode, 'category':category}, 617 dataType: 'json', 618 beforeSend:function(){ 619 // this is where we append a loading image 620 $('.image-section .image .main-product-image').html('<div style="margin-top:40px;" class="loading"><i class="fa fa-spinner fa-spin fa-4x"></i></div>').fadeIn(100); 621 }, 622 cache: false, 623 624 success:function(data){ 625 $('.image-section .image .main-product-image').html(data); 626 $(".lightbox").colorbox({photo: true, width: "80%", height: "80%"}); 627 }, 628 629 error:function(data){ 630 } 631 }); 632 } 633 } 634} 635 636 637function updateFavouritesButton(stockCode){ 638 639 if(typeof stockCode !== 'undefined'){ 640 641 $.ajax({ 642 type: 'POST', 643 format: 'json', 644 url: '/ajaxFavourites.php', 645 data: {stockCode : stockCode, action : 'checkStatus'}, 646 647 success:function(data){ 648 649 if(data.indexOf("isFavourite")!== -1){ 650 $('#wishlistsubmitinput').html('Remove from Favourites <i title="Remove from Favourites" class="fa fa-star"></i>'); 651 } 652 else if(data.indexOf("isNotFavourite")!== -1){ 653 $('#wishlistsubmitinput').html('Add to Favourites <i title="Add to Favourites" class="fa fa-star-o"></i>'); 654 } 655 } 656 }); 657 } 658} 659 660 661 662 663function updateReviewLink(stockcode){ 664 if ( stockcode != ""){ 665 $('#accordian-reviews > div > div > div.review').html('There are no reviews for this product yet. <a href="/addreview.p
665hp?p=' + stockcode + '&c=' + $('input[name="returntoargcategory"]').val() + '">Be the first to add one!</a>'); 666 } 667 else{ 668 $('#accordian-reviews > div > div > div.review').html('Please select a product to add a review to.'); 669 } 670} 671 672 673
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.