1/*! https://mths.be/cssescape v1.5.1 by @mathias | MIT license */ 2;(function(root, factory) { 3 // https://github.com/umdjs/umd/blob/master/returnExports.js 4 if (typeof exports == 'object') { 5 // For Node.js. 6 module.exports = factory(root); 7 } else if (typeof define == 'function' && define.amd) { 8 // For AMD. Register as an anonymous module. 9 define([], factory.bind(root, root)); 10 } else { 11 // For browser globals (not exposing the function separately). 12 factory(root); 13 } 14}(typeof global != 'undefined' ? global : this, function(root) { 15 16 if (root.CSS && root.CSS.escape) { 17 return root.CSS.escape; 18 } 19 20 // https://drafts.csswg.org/cssom/#serialize-an-identifier 21 var cssEscape = function(value) { 22 if (arguments.length == 0) { 23 throw new TypeError('`CSS.escape` requires an argument.'); 24 } 25 var string = String(value); 26 var length = string.length; 27 var index = -1; 28 var codeUnit; 29 var result = ''; 30 var firstCodeUnit = string.charCodeAt(0); 31 while (++index < length) { 32 codeUnit = string.charCodeAt(index); 33 // Note: thereâs no need to special-case astral symbols, surrogate 34 // pairs, or lone surrogates. 35 36 // If the character is NULL (U+0000), then the REPLACEMENT CHARACTER 37 // (U+FFFD). 38 if (codeUnit == 0x0000) { 39 result += '\uFFFD'; 40 continue; 41 } 42 43 if ( 44 // If the character is in the range [\1-\1F] (U+0001 to U+001F) or is 45 // U+007F, [â¦] 46 (codeUnit >= 0x0001 && codeUnit <= 0x001F) || codeUnit == 0x007F || 47 // If the character is the first character and is in the range [0-9] 48 // (U+0030 to U+0039), [â¦] 49 (index == 0 && codeUnit >= 0x0030 && codeUnit <= 0x0039) || 50 // If the character is the second character and is in the range [0-9] 51 // (U+0030 to U+0039) and the first character is a `-` (U+002D), [â¦] 52 ( 53 index == 1 && 54 codeUnit >= 0x0030 && codeUnit <= 0x0039 && 55 firstCodeUnit == 0x002D 56 ) 57 ) { 58 // https://drafts.csswg.org/cssom/#escape-a-character-as-code-point 59 result += '\\' + codeUnit.toString(16) + ' '; 60 continue; 61 } 62 63 if ( 64 // If the character is the first character and is a `-` (U+002D), and 65 // there is no second character, [â¦] 66 index == 0 && 67 length == 1 && 68 codeUnit == 0x002D 69 ) { 70 result += '\\' + string.charAt(index); 71 continue; 72 } 73 74 // If the character is not handled by one of the above rules and is 75 // greater than or equal to U+0080, is `-` (U+002D) or `_` (U+005F), or 76 // is in one of the ranges [0-9] (U+0030 to U+0039), [A-Z] (U+0041 to 77 // U+005A), or [a-z] (U+0061 to U+007A), [â¦] 78 if ( 79 codeUnit >= 0x0080 || 80 codeUnit == 0x002D || 81 codeUnit == 0x005F || 82 codeUnit >= 0x0030 && codeUnit <= 0x0039 || 83 codeUnit >= 0x0041 && codeUnit <= 0x005A || 84 codeUnit >= 0x0061 && codeUnit <= 0x007A 85 ) { 86 // the character itself 87 result += string.charAt(index); 88 continue; 89 } 90 91 // Otherwise, the escaped character. 92 // https://drafts.csswg.org/cssom/#escape-a-character 93 result += '\\' + string.charAt(index); 94 95 } 96 return result; 97 }; 98 99 if (!root.CSS) { 100 root.CSS = {}; 101 } 102 103 root.CSS.escape = cssEscape; 104 return cssEscape; 105 106})); 107 108// We will place our functions into an object so that they can be referenced as required 109// (e.g. so we can 'off' them and 'on' a custom function instead 110// 111// Ensure we have a place to put our local (named) functions 112if (typeof esolution === 'undefined') 113{ 114 esolution = {}; 115} 116if (typeof esolution.basket === 'undefined') 117{ 118 esolution.basket = {}; 119}
120if (typeof esolution.basket.hooks === 'undefined') 121{ 122 esolution.basket.hooks = []; 123} 124 125esolution.basket.add_hook = function(event_name, closure) { 126 esolution.basket.hooks.push({ 127 event_name: event_name, 128 closure: closure 129 }); 130 return true 131}; 132 133esolution.basket.trigger_hook = function(event_name, details) { 134 for(var i = 0; i < esolution.basket.hooks.length; i++) 135 { 136 var ebh = esolution.basket.hooks[i]; 137 if(ebh.event_name === event_name) 138 { 139 ebh.closure( event_name, details ); 140 } 141 } 142}; 143 144esolution.basket.submit_form_cti_buy = function(event) { 145 event.preventDefault(); 146 147 var form = $(event.target); 148 149 form.children(".cti_buy_button").each(function(index) { 150 // commented below lines :/ 151 /*//if a link with cti_buy_button exists in a form, submit the form instead of following the link 152 $(".cti_buy_button").data('text', $(".cti_buy_button").html()); //Store the current button text for potential re-use 153 // csr43877 - NAIT is using a slider which clones elements so "this" might not be the element we find later. Search the same way we search while processing the response, and save the html for possible restoring later 154 let active_id = $(".cti_buy_button").attr('id'); // note: all elements with a class of cti_buy_button, even though there should be only one, should have the same ids:/ 155 let active_elt = $('#' + active_id + '.cti_buy_button'); 156 active_elt.data('text', $(".cti_buy_button").html());*/ 157 $(this).data('text', $(this).html()); 158 if ($(this).text() != '') { 159 $(this).html('<i class="fa fa-spinner fa-spin"></i> '+esolution.tr('Adding...')); 160 } else { 161 $(this).html('<i class="fa fa-spinner fa-spin"></i>'); 162 } 163 }); 164 165 var query_string = form.serialize(); // build our form data 166 query_string += "&view=Json&template=Json"; // append our template & view 167 $.ajax({ 168 type: form.attr('method'), 169 url: '/Basket/ajaxAddItem', 170 data: query_string, 171 success: function(json) 172 { 173 $("body").trigger("cti.basket",new Array(json)); 174 if(json?.errors?.length === 0 || (json?.errors?.length === 1 && json?.errors[0]?.length === 0)){ 175 $("body").trigger("cti.basket/UpsellSuggestions",json); 176 } 177 }, 178 error: function(json) { 179 $("body").trigger("cti.basket",new Array(json)); 180 }, 181 dataType: "json" 182 }); 183}; 184 185esolution.basket.clicked_cti_buy_button_clone = null; 186 187esolution.basket.on_click_cti_buy_button = function(event){ 188 event.preventDefault(); 189 esolution.basket.clicked_cti_buy_button_clone = $(this)[0].cloneNode(true); // DOM object 190 if ($(this).parents("form").data("validate") == undefined || $(this).parents("form").data("validate") == "1") { 191 // validate data attribute does not exist or exists and is set to "1" 192 $(this).parents("form")[0].requestSubmit(); 193 } 194}; 195 196// polyfill code for the JS function requestSubmit... 197// may be deleted in the future when the function requestSubmit() is available on all browsers 198(function(prototype) { 199 if (typeof prototype.requestSubmit == "function") return 200 201 prototype.requestSubmit = function(submitter) { 202 //console.log("prototype.requestSubmit substitute function "); 203 if (submitter) { 204 validateSubmitter(submitter, this) 205 submitter.click() 206 } else { 207 submitter = document.createElement("input") 208 submitter.type = "submit" 209 submitter.hidden = true 210 this.appendChild(submitter) 211 submitter.click() 212 this.removeChild(submitter) 213 } 214 } 215 216 function validateSubmitter(submitter, form) { 217 submitter instanceof HTMLElement || raise(TypeError, "parameter 1 is not of type 'HTMLElement'") 218 submitter.type == "submit" || raise(TypeError, "The specified element is not a submit button") 219 submitter.form == form || raise(DOMException, "The specified element is not owned by this form element", "NotFoundError") 220 } 221 222 function raise(errorConstructor, message, name) { 223 throw new errorConstructor("Failed to execute 'requestSubmit' on 'HTMLFormElement': " + message + ".", name) 224 } 225})(HTMLFormElement.prototype); 226 227esolution.basket.diff_basket_states = function( old_items, new_items ) 228{ 229 if( typeof old_items === 'undefined' ) old_items = new_items; //on first call the cart will be undefined, this will initialize the cart to the current state and trap future diffs 230 try { 231 // Let's construct basket item objects for everything on the left 232 for(var i = 0; i < old_items.length; i++) 233 { 234 old_items[i] = new BasketItem(old_items[i]); // re-assign with new Item object 235 } 236 // Next, construct basket item objects for everything on the right 237 for(var j = 0; j < new_items.length; j++) 238 { 239 new_items[j] = new BasketItem(new_items[j]); 240 } 241 // Now we want to calculate signatures of each indiviual item, compare them to right signatures, and assign to the appropriate array 242 var updates = []; 243 var inserts = []; 244 var same = []; 245 for(var r = 0; r < new_items.length; r++) 246 { 247 // here we're iterating on the RIGHT (new) side of things 248 var right_ob = new_items[r]; 249 var right = new_items[r].generateSignature(); 250 // next we need to iterate on the LEFT inside of the RIGHT 251 if( old_items.length === 0 ) 252 { 253 // we have NO old items, let's pop this into insert then 254 inserts.push({ 255 signature: right, 256 item: right_ob, 257 index: r 258 }); 259 } 260 else { 261 for(var l = 0; l < old_items.length; l++) 262 { 263 var left_ob = old_items[l]; 264 var left = old_items[l].generateSignature(); 265 if(left === right) 266 { 267 same.push( { signature: right, item: right_ob, index: r } ); 268 } 269 else if( left_ob.generateSubSignature([ left_ob.item, left_ob.desc ]) === right_ob.generateSubSignature([ right_ob.item, right_ob.desc ]) ) 270 { 271 var state = 'UPDATE'; 272 if ( typeof left_ob.text !== 'undefined' && left_ob.text !== null && typeof right_ob.text !== 'undefined' && right_ob.text !== null ) 273 { 274 // this MAY be a same item BUT with different text properties (ie, special order items, etc) 275 // let's iterate on some of the properties we have in TEXT instead 276 var left_text_keys = Object.keys(left_ob.text); 277 var right_text_keys = Object.keys(right_ob.text); 278 var left_opands = []; 279 var right_opands = []; 280 var common_properties = []; 281 // we want to iterate on the two objects to reliably match common propreties, to see if we can determine if they're related or not 282 for(var rightprop1 = 0; rightprop1 < right_text_keys.length; rightprop1++) { 283 var rkey = right_text_keys[rightprop1]; 284 for(var leftprop1 = 0; leftprop1 < left_text_keys.length; leftprop1++) { 285 var lkey = left_text_keys[leftprop1]; 286 if(rkey === lkey) { 287 common_properties.push(rkey); 288 } 289 } 290 } 291 if(common_properties.length > 0) { 292 // we have some common properties, let's iterate and build ourselves both the left and right common properties at the same time 293 // then we'll push our side-specific additional data into the array 294 for(var comprop1 = 0; comprop1 < common_properties.length; comprop1++) 295 { 296 left_opands.push(left_ob.text[common_properties[comprop1]]); 297 right_opands.push(right_ob.text[common_properties[comprop1]]); 298 } 299 left_opands.push(left_ob.item); 300 left_opands.push(left_ob.desc); 301 right_opands.push(right_ob.item); 302 right_opands.push(right_ob.desc); 303 }
304 if(left_opands.length > 0 && right_opands.length > 0) 305 { 306 // we now have something we can operate on! 307 var left_sig = left_ob.generateSubSignature( left_opands ); 308 var right_sig = right_ob.generateSubSignature( right_opands ); 309 if(left_sig === right_sig) { 310 state = 'UPDATE'; 311 } 312 else if(left_sig !== right_sig) { 313 state = 'INSERT'; 314 } 315 } 316 } 317 if(state === 'UPDATE') { 318 updates.push( { signature: right, item: right_ob, index: r } ); 319 } 320 else if(state === 'INSERT') { 321 inserts.push( { signature: right, item: right_ob, index: r } ); 322 } 323 } 324 else if(l === old_items.length-1) 325 { 326 // we've got our last item, let's check if we need to delete or not 327 var is_found = false; 328 for(var u1 = 0; u1 < updates.length; u1++) 329 { 330 if( updates[u1].signature === right ) 331 { 332 is_found = true; 333 } 334 } 335 for(var i1 = 0; i1 < inserts.length; i1++) 336 { 337 if( inserts[i1].signature === right ) 338 { 339 is_found = true; 340 } 341 } 342 for(var s1 = 0; s1 < same.length; s1++) 343 { 344 if( same[s1].signature === right ) 345 { 346 is_found = true; 347 } 348 } 349 if( !is_found ) 350 { 351 inserts.push( { signature: right, item: right_ob, index: r }); 352 } 353 } 354 } 355 } 356 } 357 358 // let's now deal with the updates/inserts for items, and the same items, they're not in any of our RIGHT arrays, so we can quickly iterate like below 359 var deletes = []; 360 for(var i = 0; i < old_items.length; i++) 361 { 362 var left_signature = old_items[i].generateSignature(); 363 var left_sub_signature = old_items[i].generateSubSignature( 364 [ 365 old_items[i].item, 366 old_items[i].desc 367 ] 368 ); 369 var item_found = false; 370 updates.forEach(function(update) { 371 if( update.signature === left_signature || update.signature === left_sub_signature ) 372 { 373 item_found = true; 374 } 375 }); 376 inserts.forEach(function(insert) { 377 if( insert.signature === left_signature || insert.signature === left_sub_signature ) 378 { 379 item_found = true; 380 } 381 }); 382 same.forEach(function(same) { 383 if( same.signature === left_signature || same.signature === left_sub_signature ) 384 { 385 item_found = true; 386 } 387 }); 388 if( !item_found ) 389 { 390 deletes.push( { signature: left_signature, item: old_items[i] } ); 391 } 392 } 393 394 inserts.forEach(function(insert) { 395 esolution.basket.trigger_hook('item.added', { 396 signature: insert.signature, 397 item: insert.item 398 }); 399 }); 400 401 updates.forEach(function(update) { 402 esolution.basket.trigger_hook('item.changed', { 403 signature: update.signature, 404 item: update.item 405 }); 406 }); 407 408 deletes.forEach(function(deleted) { 409 esolution.basket.trigger_hook('item.deleted', { 410 signature: deleted.signature, 411 item: deleted.item 412 }); 413 }); 414 } catch (e) { 415 console.log('caught error when trying to diff basket states, falling through to existing logic.', e); 416 } 417}; 418 419esolution.basket.change_button_state = function ( button ) { 420 421 if(button.text() != '') 422 { 423 button.html(button.data('qty') +' '+esolution.tr("IN CART", "")); 424 } 425 else 426 { 427 button.html(button.data('text')); 428 } 429 button.css('background-color', '#228B22'); 430 button.css('border-color', '#228B22'); 431 button.css('color', '#FFFFFF'); 432 button.css('background-image', 'none'); 433}; 434 435esolution.basket.on_cti_basket = function (e, json){ 436 //store the last data we've updated the page with so that we can rerender without a server pull 437 esolution.basket.old_cart_data = esolution.basket.cart_data; 438 esolution.basket.cart_data = json; 439//pwo 2021, commendting the following lines, they are incorrect 440//on first call to this function the previous state of the cart will ALWAYS be undefined, the 441//diff function must detect undefined and set it to the current cart to initialize the state of the cart for future diffs 442// if( typeof esolution.basket.old_cart_data.items === 'undefined') { 443// esolution.basket.old_cart_data.items = []; // to prevent nulled/undefined entries 444// } 445 //Update the buy button on basket update event 446 //console.log(json); 447 // 448 // We'll roll through the events, then through 'regular' items 449 // It's possible to update the same button both times, if events are handled in the 'regular' basket 450 for( var i = 0; i < json.events.length; i++ ) 451 { 452 var thisevent = json.events[i]; 453 var button = $(".event-"+thisevent); 454 if(button.text() != '') 455 { 456 //button.html('On Itinerary'); 457 button.html(esolution.tr('In Cart')); 458 } 459 } 460 461 esolution.basket.diff_basket_states( esolution.basket.old_cart_data.items, esolution.basket.cart_data.items ); 462 463 //var items = esolution.basket.cart_data.items; 464 // Line above was commented and replace with line below. The items object will now be a copy, rather than, a reference to esolution.basket.cart_data.items. 465 // This is required for the quantity on the buy button when the basket has multiple items all with the same item number but not coalesced. 466 // Without the copy, when the for loop code below finishes, it alters the property "qty" in one of the items in the object esolution.basket.cart_data.items. 467 // With the copy, the "qty" property is not altered:) 468 var items = JSON.parse(JSON.stringify(esolution.basket.cart_data.items)); 469 var aggregate_items = { }; 470 var aggregate_items_arr = []; 471 472 for( var i = 0; i < items.length; i++ ) 473 { 474 var item = items[i];
475 if( typeof( aggregate_items[ item.item ] ) === 'undefined' ) 476 { 477 aggregate_items[ item.item ] = []; 478 aggregate_items[ item.item ][ item.used ] = item; 479 } 480 else if( typeof( aggregate_items[ item.item ][ item.used ] ) === 'undefined' ) 481 { 482 aggregate_items[ item.item ][ item.used ] = item; 483 } 484 else 485 { 486 if (typeof(item.qty) == "number") { 487 aggregate_items[item.item][ item.used ].qty = parseInt(aggregate_items[item.item][ item.used ].qty) + item.qty; 488 } else if (typeof(item.qty) == "string") { 489 aggregate_items[item.item][ item.used ].qty = parseInt(aggregate_items[item.item][ item.used ].qty) + parseInt(item.qty); 490 } 491 } 492 } 493 494 for( var j = 0; j < Object.keys(aggregate_items).length; j++ ) 495 { 496 var ji = Object.keys(aggregate_items)[j]; 497 for( var k = 0; k < Object.keys(aggregate_items[ji]).length; k++ ) 498 { 499 var ki = Object.keys(aggregate_items[ji])[k]; 500 aggregate_items_arr.push( aggregate_items[ji][ki] ); 501 } 502 } 503 504 var button; 505 506 for( var i = 0; i < aggregate_items_arr.length; i++ ) 507 { 508 var item = aggregate_items_arr[i]; 509 //change the button style to secondary, then change the button text 510 if (item.used=="") { 511 button = $("#" + CSS.escape(item.item) + ".cti_buy_button, " + // id selector is for legacy views 512 "." + CSS.escape(item.item) + ".cti_buy_button, " + // *** 513 "[data-item=" + CSS.escape(item.item) + "][data-used=''].cti_buy_button, " + 514 "[data-item=" + CSS.escape(item.item) + "]:not([data-used]).cti_buy_button"); 515 } else if (item.used=="US") { 516 button = $("#" + CSS.escape(item.item) + ".cti_buy_button, " + // id selector is for legacy views 517 "." + CSS.escape(item.item) + ".cti_buy_button, " + // *** 518 "[data-item=" + CSS.escape(item.item) + "][data-used='US'].cti_buy_button"); 519 } 520 521 if(!button.data('qty')){ 522 button.data('qty', 0); 523 } 524 if(item.qty === button.data('qty')) { item.qty = 0; } 525 button.data('qty', button.data('qty')+parseInt(item.qty)); // in cases where quantity doesn't change, I presume nil is the answer, but just to be safe teh above line will reset the count to nil, so we don't duplicate falsely 526 esolution.basket.change_button_state( button ); 527 } 528 $("input[name=qty]").val("1"); 529 $('.buy-form').hide(); 530 $('#cti-buy-form-wrapper').hide(); 531 //} 532 //Reset the 'qty' data attributes so that the in cart quantity on the button does not double the next time an item is added 533 for( var i = 0; i < json.items.length; i++ ) 534 { 535 var item = json.items[i]; 536 button = $("#" + CSS.escape(item.item) + ".cti_buy_button," + 537 "." + CSS.escape(item.item) + ".cti_buy_button, " + // *** 538 "[data-item=" + CSS.escape(item.item) + "][data-used=''].cti_buy_button," + 539 "[data-item=" + CSS.escape(item.item) + "]:not([data-used]).cti_buy_button," + 540 "[data-item=" + CSS.escape(item.item) + "][data-used='US'].cti_buy_button"); 541 if(button.data('qty')){ 542 button.data('qty', 0); 543 } 544 } 545 //console.log(json); 546 //Update add to cart buttons for items with an error 547 for( var i = 0; i < json.errors.length; i++ ) 548 { 549 var error = json.errors[i]; 550 551 if (Object.keys(error).length > 0) { // this check is required as json.errors may be an array of length 1 with no data 552 553 if (error.used=="" || error.used=="NW" ) { 554 button = $("#" + CSS.escape(error.item) + ".cti_buy_button, " + // id selector is for legacy views 555 "." + CSS.escape(error.item) + ".cti_buy_button, " + // *** 556 "[data-item=" + CSS.escape(error.item) + "]:not([data-used]).cti_buy_button, " + 557 "[data-item=" + CSS.escape(error.item) + "][data-used=''].cti_buy_button"); 558 } else if (error.used=="US") { 559 button = $("#" + CSS.escape(error.item) + ".cti_buy_button, " + // id selector is for legacy views 560 "." + CSS.escape(error.item) + ".cti_buy_button, " + // *** 561 "[data-item=" + CSS.escape(error.item) + "][data-used='US'].cti_buy_button"); 562 } 563 564 if(button.text() != '') 565 {
566 // We can get here because we're validating a form, or because the item is out of stock. Let's see if we had "form":"some form" in the error response 567 if (typeof(error.form) !== 'undefined') 568 { 569 button.html('Validating...'); 570 } 571 else 572 { 573 var qty_in_cart; 574 for( var i = 0; i < aggregate_items_arr.length; i++ ) 575 { 576 var item = aggregate_items_arr[i]; 577 if (item.item == error.item && item.used == error.used) { 578 qty_in_cart = button.data('qty')+parseInt(item.qty); // note: reesearch button.data('qty') 579 } 580 } 581 if (qty_in_cart) { 582 button.html(qty_in_cart + " " + esolution.tr("IN CART")); // possible: consider limit? onorder? price on button? 583 } else { 584 button.html("Out of Stock"); // The majority of errors are due to an item being out of stock - this should be improved once the checkout is rebuilt 585 } 586 //button.html(aggregate_items_arr[i]["qty"]+' '+tr("IN CART", "")+' Out of Stock'); 587 } 588 } 589 else 590 { 591 button.html(button.data('text')); 592 } 593 button.css('background-color', '#B22222'); 594 button.css('border-color', '#B22222'); 595 button.css('color', '#FFFFFF'); 596 button.css('background-image', 'none'); 597 if( typeof error.form != 'undefined' ) 598 { 599 esolution.basket.trigger_hook('form_validate', { 600 error: error, 601 form_toggler: document.querySelector('#cti-buy-form') 602 }); 603 $("#cti-buy-form").html( error.form ); 604 $("#cti-buy-form-wrapper").show(); 605 $("body").css("overflow-y", "hidden"); 606 //console.log("overflow-y hidden"); 607 608 // let's see if we just inserted any scripts into the DOM, and if so we'll execute them 609 $("#cti-buy-form").find('script').each(function() { 610 let form_script = this.innerText; 611 eval(form_script)//run script inside form 612 }); 613 } 614 else 615 { 616 $("#cti-buy-form-wrapper").fadeOut(); 617 $("body").css("overflow-y", "visible"); 618 } 619 } 620 } 621 622}; 623 624esolution.basket.on_click_cti_waitlist_button = function(e) { 625 e.preventDefault(); 626 627 // when the customer clicks the 'register for waitlist' button, we intercept the flow and do an ajax request to fetch the configured registration form 628 // the 'register' button must be in a form that includes the item (hidden input with name 'item') 629 630 //build our form data 631 var form = $(e.target).closest('form'); 632 var query_string = form.serialize(); 633 //append our template & view 634 query_string += "&view=Json&template=Json"; 635 $.ajax({ 636 type: form.attr('method'), 637 url: '/Basket/itemunavailable', 638 data: query_string, 639 success: function(json) 640 { 641 //console.log(json); 642 if (typeof(json.errors) !== 'undefined') { 643 let error = json.errors[0]; 644 if (typeof(error.form) !== 'undefined') { 645 $("#cti-buy-form").html( error.form ); 646 $("#cti-buy-form-wrapper").show(); 647 648 // let's see if we just inserted any scripts into the DOM, and if so we'll execute them 649 $("#cti-buy-form").find('script').each(function() { 650 let form_script = this.innerText; 651 eval(form_script); 652 }); 653 } 654 } 655 656 }, 657 error: function(json) { //ERROR 658 //console.log("error"); 659 }, 660 dataType: "json" 661 }); 662}; 663 664 665esolution.basket.on_submit_cti_waitlist_registration = function(e) { 666 e.preventDefault(); 667 var form = $(e.target).closest('form'); 668 var query_string = form.serialize(); 669 var url = form.attr('action'); 670 671 console.log("Submitting waitlist registration"); 672 $.ajax({ 673 type: form.attr('method'), 674 url: url, 675 data: query_string, 676 success: function(json) 677 { 678 if( typeof(json.message) !== 'undefined') { 679 $("#cti-buy-form").html( json.message ); 680 //$("#cti-buy-form-wrapper").show(); 681 } 682 }, 683 error: function(json) { //ERROR 684 //console.log("error"); 685 }, 686 dataType: "json" 687 }); 688 689}; 690 691 692 693esolution.basket.on_refresh_count_event = function() { 694 $.ajax({ 695 type: "GET", 696 url: '/Basket/json?view=Json&template=Json', 697 success: function(json) { 698 $("body").trigger("cti.basket", new Array(json)); 699 }, 700 dataType: "json" 701 }); 702}; 703 704esolution.basket.on_click_cti_remove_button = function(e) { 705//if a link with cti_buy_button exists in a form, submit the form instead of following the link 706 e.preventDefault(); 707 var name = $(this).attr('name'); 708 $.ajax({ 709 type: "GET", 710 url: '/Basket/ajaxRemoveIndex?view=Json&template=Json', 711 data: { 712 index:name 713 }, 714 success: function(json) 715 { 716 $("body").trigger("cti.basket",new Array(json)); 717 $('.'+CSS.escape(name)).css('background-color', ''); 718 $('.'+CSS.escape(name)).css('color', ''); 719 } 720 }); 721}; 722 723 724esolution.basket.on_click_cti_buy_form_close = function(e){ 725 e.preventDefault(); 726 $("#cti-buy-form-wrapper").hide(); 727 window.location.reload(); 728 729 /* NOTE: this is only correct under limited conditions. The cti_buy_form popup is used for much more than buy forms, most of which do not have any such id */ 730 // Note: The item number appears to be one of the classes in the class html attribute. 731 let selector_id = (esolution.basket.clicked_cti_buy_button_clone.id ? "#" + esolution.basket.clicked_cti_buy_button_clone.id : ""); 732 let selector_classes = "." + esolution.basket.clicked_cti_buy_button_clone.className.split(" ").join("."); 733 button = $(selector_id ? selector_id : "" + selector_classes ? selector_classes : ""); 734 // Upon closing the form and not submitting form, there are two options... 735 // Option 1 ... Write "Item Unavailable" on button(s) with the same classes as the button clicked. 736 //button.html("Item Unavailable"); 737 // Option 2... Reset button(s) with the same classes as the button clicked to the state before the button was clicked. 738 button.html(esolution.basket.clicked_cti_buy_button_clone.innerHTML); 739 button.css('background-color', esolution.basket.clicked_cti_buy_button_clone.style.backgroundColor); 740 button.css('border-color', esolution.basket.clicked_cti_buy_button_clone.style.borderColor); 741 button.css('color', esolution.basket.clicked_cti_buy_button_clone.style.color); 742 button.css('background-image', esolution.basket.clicked_cti_buy_button_clone.style.backgroundImage); 743 744 if( esolution.basket.cart_data.errors.length > 0 ) { 745 esolution.basket.cart_data.errors = []; 746 }
747 esolution.basket.update(); 748}; 749 750 751 752 753$(function(){ 754 755 //on load pull the ajax basket and trigger a refresh 756 /*$.ajax({ 757 url:"/Basket/json?template=Json", 758 success: function(json) 759 { 760 $("body").trigger("cti.basket",new Array(json)); 761 }, 762 dataType: "json" 763 });*/ 764 765 //bind all forms named cti_buy to an ajax post 766 $("body").on("submit","form[name=cti_buy]",esolution.basket.submit_form_cti_buy); 767 768 //if a link with cti_buy_button exists in a form, submit the form instead of following the link 769 $(".cti_buy_button").on("click",esolution.basket.on_click_cti_buy_button); 770 771 //Update the buy button on basket update event 772 $("body").on("cti.basket",esolution.basket.on_cti_basket); 773 774 $("body").on("refreshCountEvent", esolution.basket.on_refresh_count_event); 775 776 //if a link with cti_buy_button exists in a form, submit the form instead of following the link 777 $("body").on("click",".cti_remove_button",esolution.basket.on_click_cti_remove_button); 778 779 $("body").on("click",".cti-buy-form-close",esolution.basket.on_click_cti_buy_form_close); 780 781 // attach to all "unavailable" buttons to load a form which will be loaded into the cti-buy-form-wrapper / cti-buy-form 782 // this implements the waitlist registration form, and the submit action on that form 783 $("body").on("click",".cti_waitlist_button",esolution.basket.on_click_cti_waitlist_button); 784 $("body").on("click",".cti_waitlist_close_button",esolution.basket.on_click_cti_buy_form_close); 785 $("body").on("click",".cti_waitlist_registration_submit",esolution.basket.on_submit_cti_waitlist_registration) 786 787 //append a container for inserting forms to the bottom of the dom, if length of matching elements is 0 (false) (eg CourseSearchView includes its own wrapper div). If it exists, we'll use it 788 if( !$('div#cti-buy-form-wrapper').length ) { 789 $('body').append("<div id='cti-buy-form-wrapper'><a href='#' class='cti-buy-form-close'><i class='fa fa-times-circle fa-fw'></i></a><div id='cti-buy-form'></div></div>"); 790 } 791/* 792 // sample from course search view 793 <div id="cti-buy-form-wrapper" style="display:none"><div style="float:right;width:30px;text-align:right; padding: 2px 10px 2px 0px;"><a href="#" class="cti-buy-form-close"><i class="fa fa-times-circle fa-fw"></i></a></div> 794 <div id="cti-buy-form"></div></div> 795*/ 796 797});
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.