1(function($) { 2 window.Simplecheckout = function(params) { 3 this.params = params; 4 5 this.callback = params.javascriptCallback || function() {}; 6 7 this.selectors = { 8 paymentForm: "#simplecheckout_payment_form", 9 paymentButtons: "#simplecheckout_payment_form .buttons:last", 10 step: ".simplecheckout-step", 11 buttons: "#buttons", 12 buttonPrev: "#simplecheckout_button_prev", 13 buttonNext: "#simplecheckout_button_next", 14 buttonCreate: "#simplecheckout_button_confirm", 15 buttonBack: "#simplecheckout_button_back", 16 stepsMenu: "#simplecheckout_step_menu", 17 stepsMenuItem: ".simple-step", 18 stepsMenuDelimiter: ".simple-step-delimiter", 19 stepsMenuTop: ".simplecheckout-top-menu", 20 stepsMenuBottom: ".simplecheckout-bottom-menu", 21 stepsMenuVerticalItem: ".simple-step-vertical", 22 proceedText: "#simplecheckout_proceed_payment", 23 agreementCheckBox: "#agreement_checkbox", 24 agreementWarning: "#agreement_warning", 25 block: ".simplecheckout-block", 26 overlay: ".simplecheckout_overlay" 27 }; 28 29 this.classes = { 30 stepsMenuCompleted: "simple-step-completed", 31 stepsMenuCurrent: "simple-step-current", 32 stepsMenuVerticalCompleted: "simple-step-vertical-completed" 33 }; 34 35 this.blocks = []; 36 this.$steps = []; 37 this.requestTimerId = 0; 38 this.currentStep = 1; 39 this.saveStepNumber = this.currentStep; 40 this.stepReseted = false; 41 this.isCreateOrderClicked = false; 42 this.backCount = -1; 43 this.$paymentForm = false; 44 this.storageUsed = false; 45 this.paymentFormObserver = null; 46 47 var checkIsInContainer = function($element, selector) { 48 if ($element.parents(selector).length) { 49 return true; 50 } 51 return false; 52 }; 53 54 this.callFunc = function(func, $target) { 55 var self = this; 56 57 if (func && typeof self[func] === "function") { 58 self[func]($target); 59 } else if (func) { 60 //console.log(func + " is not registered"); 61 } 62 }; 63 64 this.registerBlock = function(object) { 65 var self = this; 66 object.setParent(self); 67 self.blocks.push(object); 68 }; 69 70 this.initBlocks = function() { 71 var self = this; 72 for (var i in self.blocks) { 73 if (!self.blocks.hasOwnProperty(i)) continue; 74 75 self.blocks[i].init(); 76 } 77 }; 78 79 this.init = function(disableScroll, changeStep) { 80 var self = this; 81 82 if (typeof disableScroll === "undefined") { 83 disableScroll = false; 84 } 85
86 var callbackForComplexField = function($target) { 87 self.focusedFieldId = '' 88 var func = $target.attr("data-onchange"); 89 if (!func) { 90 func = $target.attr("data-onchange-delayed"); 91 } 92 if (func && typeof self[func] === "function") { 93 self[func]($target); 94 } else if (func) { 95 //console.log(func + " is not registered"); 96 } 97 self.setDirty(); 98 }; 99 100 self.requestTimerId = 0; 101 102 if (!self.isPaymentFormEmpty()) { 103 if (self.$paymentForm) { 104 self.restorePaymentForm(self.$paymentForm); 105 } 106 } else { 107 self.$paymentForm = false; 108 } 109 110 if (self.params.useAutocomplete) { 111 self.initAutocomplete(callbackForComplexField); 112 } 113 114 self.checkIsHuman(); 115 self.addObserver(); 116 self.initPopups(); 117 self.initMasks(); 118 self.initTooltips(!self.params.useAutocomplete); 119 self.initDatepickers(callbackForComplexField); 120 self.initTimepickers(callbackForComplexField); 121 self.initSelect2(); 122 self.initFileUploader(function() { 123 self.overlayAll(); 124 }, function() { 125 self.removeOverlays(); 126 self.setDirty(); 127 }); 128 self.initHandlers(); 129 self.initBlocks(); 130 self.initSteps(changeStep); 131 132 self.initAbandonedCart(); 133 134 if (!disableScroll) { 135 self.scroll(); 136 } 137 138 self.initValidationRules(); 139 140 if (!self.isPaymentFormEmpty() && self.useReloadingOfPaymentForm()) { 141 self.initReloadingOfPaymentForm(); 142 } 143 144 this.syncShippingAndPaymentAddresses(); 145 146 if (typeof self.callback === "function") { 147 try { 148 self.callback(); 149 } catch (e) { 150 console.error(e); 151 } 152 } 153 154 this.checkRedirect(); 155 156 $(window).on("unload", function() { 157 var doSomething = 1; 158 doSomething++; 159 }); 160 }; 161 162 this.useReloadingOfPaymentForm = function() { 163 if (typeof this.params.enableAutoReloaingOfPaymentFrom !== 'undefined' && this.params.enableAutoReloaingOfPaymentFrom) { 164 if (typeof window.simpleTypingSpeed !== 'undefined' && window.simpleTypingSpeed > 1000) { 165 return false; 166 } 167 168 return true; 169 } 170 171 return false; 172 }, 173 174 this.initHandlers = function() { 175 var self = this; 176 $(self.params.mainContainer).find("*[data-onchange], *[data-onclick]").each(function() { 177 var bind = true, 178 $element = $(this); 179 180 for (var i in self.blocks) { 181 if (!self.blocks.hasOwnProperty(i)) continue; 182 183 if (checkIsInContainer($element, self.blocks[i].currentContainer)) { 184 bind = false; 185 break; 186 } 187 } 188 189 if (bind) { 190 var funcOnChange = $element.attr("data-onchange"); 191 192 if (funcOnChange) { 193 $element.on("change", function() { 194 self.setDirty($(this)); 195 self.callFunc(funcOnChange, $element); 196 }); 197 } 198 199 var funcOnClick = $element.attr("data-onclick"); 200 201 if (funcOnClick) { 202 $element.on("click", function() { 203 if ($(this).attr("disabled")) { 204 return; 205 } 206 207 var confirmText = $(this).attr("data-confirm-text"); 208 209 self.setDirty(); 210 211 if (!confirmText || (confirmText && confirm(confirmText))) { 212 self.callFunc(funcOnClick, $element); 213 } 214 }); 215 } 216 } 217 }); 218 }; 219 220 this.skipKey = function(keyCode) { 221 if ($.inArray(keyCode,[9,13,16,17,18,19,20,27,35,36,37,38,39,40,91,93,224]) > -1) { 222 return true; 223 } 224 225 return false; 226 }; 227 228 this.addObserver = function() { 229 var self = this; 230 231 $(self.params.mainContainer).find("input[type=radio], input[type=checkbox], select").on("change", function() { 232 if (!checkIsInContainer($(this), self.selectors.paymentForm) && !checkIsInContainer($(this), "#simplecheckout_login") && !checkIsInContainer($(this), "#slogin")) { 233 self.setDirty($(this)); 234 } 235 }); 236 237 $(self.params.mainContainer).find("input, textarea").on("keydown change paste propertychange keyup input", function(e) { 238 if (self.skipKey(e.keyCode)) { 239 return; 240 } 241 242 if (!checkIsInContainer($(this), self.selectors.paymentForm) && !checkIsInContainer($(this), "#simplecheckout_login") && !checkIsInContainer($(this), "#slogin")) { 243 self.setDirty($(this)); 244 } 245 }); 246 }; 247 248 this.initReloadingOfPaymentForm = function() { 249 var self = this; 250 251 var reload = function(disableScroll) { 252 var $field = $(this); 253 254 if (typeof disableScroll === "undefined") { 255 disableScroll = false; 256 } 257 258 if (!checkIsInContainer($field, self.selectors.paymentForm)) { 259 self.validate(true).then(function(result) { 260 if (result) { 261 self.reloadAll(undefined, disableScroll); 262 } 263 }); 264 } 265 }; 266 267 $(self.params.mainContainer).find("input[data-simple-mask][data-reload-payment-form], input[type=radio][data-reload-payment-form], input[type=checkbox][data-reload-payment-form], select[data-reload-payment-form], input[type=date][data-reload-payment-form], input[type=time][data-reload-payment-form]").on("change", reload); 268 269 var timeoutId = 0; 270 271 $(self.params.mainContainer).find("input[type=text][data-reload-payment-form]:not([data-simple-mask]), input[type=email][data-reload-payment-form]:not([data-simple-mask]), input[type=tel][data-reload-payment-form]:not([data-simple-mask]), textarea[data-reload-payment-form]").on("keydown", function(e) { 272 if (self.skipKey(e.keyCode)) { 273 return; 274 } 275 276 if (timeoutId) { 277 clearTimeout(timeoutId); 278 } 279 280 timeoutId = window.setTimeout(function() { 281 clearTimeout(timeoutId); 282 283 if ($(self.params.mainContainer).data("timeoutId") != timeoutId) { 284 return; 285 } 286 287 reload(true); 288 }, 500); 289 290 $(self.params.mainContainer).data("timeoutId", timeoutId); 291 }); 292 }; 293 294 this.savePaymentForm = function() { 295 var self = this; 296 297 if (!self.isPaymentFormEmpty()) { 298 self.$paymentForm = $(self.params.mainContainer).find(self.selectors.paymentForm).find("input[type=text],select,textarea,input[type=radio]:checked,input[type=checkbox]:checked"); 299 } else { 300 self.$paymentForm = false; 301 } 302 }; 303 304 this.initStorage = function() { 305 var self = this; 306 307 if (!self.storageUsed) { 308 var needReloading = false; 309 310 $(self.params.mainContainer).find("input[type=text], input[type=email], input[type=tel], select, textarea").each(function() { 311 var $el = $(this); 312 var id = $el.attr("id"); 313 var value = localStorage.getItem(id); 314 315 if (id && value) {
316 if ($el.is("select")) { 317 if ($el.find("option[value='" + value + "']").length) { 318 if ($el.val() != value) { 319 $el.val(value); 320 321 if ($el.attr("data-onchange")) { 322 needReloading = true; 323 } 324 } 325 } 326 } else { 327 if ($el.val() != value) { 328 $el.val(value); 329 330 if ($el.attr("data-onchange")) { 331 needReloading = true; 332 } 333 } 334 } 335 } 336 }); 337 338 if (needReloading) { 339 self.reloadAll(); 340 } 341 342 self.storageUsed = true; 343 } 344 345 if (!$(self.params.mainContainer).attr("data-logged")) { 346 $(self.params.mainContainer).find("input[type=text], input[type=email], input[type=tel], select, textarea").on("change", function() { 347 var $el = $(this); 348 349 if (checkIsInContainer($el, "#simplecheckout_customer") || checkIsInContainer($el, "#simplecheckout_shipping_address") || checkIsInContainer($el, "#simplecheckout_payment_address")) { 350 localStorage.setItem($el.attr("id"), $el.val()); 351 } 352 }); 353 } 354 } 355 356 this.checkRedirect = function() { 357 var $redirect = $(this.params.mainContainer).find('#simple_redirect_url'); 358 359 if ($redirect.length) { 360 window.location = $redirect.val(); 361 } 362 } 363 364 this.restorePaymentForm = function($oldForm) { 365 var self = this; 366 var $paymentForm = $(self.params.mainContainer).find(self.selectors.paymentForm); 367 368 $oldForm.each(function() { 369 var $field = $(this); 370 var name = $field.attr("name"); 371 var id = $field.attr("id"); 372 var value = $field.val(); 373 374 if ($field.is("input[type=text]") || $field.is("select") || $field.is("textarea")) { 375 if (name) { 376 $paymentForm.find("[name='" + name + "']").val(value); 377 } else if (id) { 378 $paymentForm.find("#" + id).val(value); 379 } 380 } 381 382 if ($field.is("input[type=radio]") || $field.is("input[type=checkbox]")) { 383 if (name) { 384 $paymentForm.find("[name='" + name + "'][value='" + value + "']").attr("checked", "checked"); 385 } else if (id) { 386 $paymentForm.find("#" + id + "[value='" + value + "']").attr("checked", "checked"); 387 } 388 } 389 }); 390 391 delete $oldForm; 392 }; 393 394 this.initAbandonedCart = function() { 395 var self = this; 396 var $mainContainer = $(self.params.mainContainer); 397 398 $mainContainer.find("input:not([data-onchange=reloadAll],[data-onclick=reloadAll]), select:not([data-onchange=reloadAll],[data-onclick=reloadAll]), textarea:not([data-onchange=reloadAll],[data-onclick=reloadAll])").on('change', function() { 399 $.ajax({
400 url: "index.php?" + self.params.additionalParams + "route=checkout/simplecheckout/abandoned", 401 data: self.createPostData(), 402 type: "POST", 403 dataType: "text" 404 }); 405 }); 406 }; 407 408 this.setDirty = function($element) { 409 var self = this; 410 var $mainContainer = $(self.params.mainContainer); 411 412 self.stopPaymentFormObserving(); 413 414 if (self.useReloadingOfPaymentForm()) { 415 self.savePaymentForm(); 416 417 if ($element && ($element.attr("data-reload-payment-form") || ($element.attr("data-onchange") && $element.attr("data-onchange") == "reloadAll"))) { 418 $mainContainer.find(self.selectors.paymentForm).attr("data-invalid", "true").find("input,select,textarea").attr("disabled", "disabled"); 419 } 420 } else { 421 $mainContainer.find(self.selectors.paymentForm).attr("data-invalid", "true").empty(); 422 } 423 424 $mainContainer.find("*[data-payment-button=true]").remove(); 425 $mainContainer.find(self.selectors.proceedText).hide(); 426 427 self.isCreateOrderClicked = false; 428 429 if (self.currentStep == self.stepsCount) { 430 $mainContainer.find(self.selectors.buttons).show(); 431 $mainContainer.find(self.selectors.buttonCreate).show(); 432 } 433 }; 434 435 this.preventOrderDeleting = function(callback) { 436 var self = this; 437 $.get("index.php?" + self.params.additionalParams + "route=" + self.params.mainRoute + "/prevent_delete", function() { 438 if (typeof callback === "function") { 439 callback(); 440 } 441 }); 442 }; 443 444 this.clickOnConfirmButton = function() { 445 var self = this; 446 var $mainContainer = $(self.params.mainContainer); 447 var $paymentForm = $mainContainer.find(self.selectors.paymentForm); 448 449 if (self.isPaymentFormEmpty()) { 450 return; 451 } 452 453 var gatewayLink = $paymentForm.find(".buttons a:last").attr("href"); 454 var $submitButton = $paymentForm.find(".buttons input[type=button]:last,.buttons input[type=submit]:last,.buttons input[type=image]:last,.buttons button:last,.buttons a.button:last[href='#'],.buttons a.btn:last[href='#'],.buttons a.button:last[href^='javascript'],.buttons a.btn:last[href^='javascript'],.buttons a.button:last:not([href]),.buttons a.btn:last:not([href])"); 455 var $lastButton = $paymentForm.find("input[type=button]:last,input[type=submit]:last,input[type=image]:last,button:last"); 456 var lastLink = $paymentForm.find("a:last").attr("href"); 457 458 var disableButton = function() { 459 $mainContainer.find(self.selectors.buttonCreate).attr("disabled", "disabled"); 460 }; 461 462 var enableButton = function() { 463 $mainContainer.find(self.selectors.buttonCreate).removeAttr("disabled"); 464 }; 465 466 if (typeof gatewayLink !== "undefined" && gatewayLink !== "" && gatewayLink !== "#" && gatewayLink !== "javascript://") { 467 disableButton(); 468 self.preventOrderDeleting(function() { 469 enableButton(); 470 window.location = gatewayLink; 471 self.blockFieldsDuringPayment(); 472 self.proceed(); 473 }); 474 } else if ($submitButton.length) { 475 if ($submitButton.attr("href") == "#" || $submitButton.attr("href") == "javascript://") { 476 $submitButton.removeAttr("href"); 477 } 478 disableButton(); 479 self.preventOrderDeleting(function() { 480 enableButton(); 481 if (!$submitButton.attr("disabled")) { 482 $submitButton.mousedown().click(); 483 self.blockFieldsDuringPayment($submitButton); 484 self.proceed(); 485 } 486 }); 487 } else if ($lastButton.length) { 488 disableButton(); 489 self.preventOrderDeleting(function() { 490 enableButton(); 491 if (!$lastButton.attr("disabled")) { 492 $lastButton.mousedown().click(); 493 self.blockFieldsDuringPayment($lastButton); 494 self.proceed(); 495 } 496 }); 497 } else if (typeof lastLink !== "undefined" && lastLink !== "" && lastLink !== "#" && lastLink !== "javascript://") { 498 disableButton(); 499 self.preventOrderDeleting(function() { 500 enableButton(); 501 window.location = lastLink; 502 self.blockFieldsDuringPayment(); 503 self.proceed(); 504 }); 505 } 506 }; 507 508 this.isPaymentFormValid = function() { 509 var self = this; 510 return !self.isPaymentFormEmpty() && !$(self.params.mainContainer).find(self.selectors.paymentForm).attr("data-invalid") ? true : false; 511 }; 512 513 this.isPaymentFormVisible = function() { 514 var self = this; 515 var $paymentForm = $(self.params.mainContainer).find(self.selectors.paymentForm); 516 var $elements = $paymentForm.find(":visible:not(form)"); 517 var paymentFormHeight = $paymentForm.height(); 518 var ignoreHeight = 50; 519 520 return !self.isPaymentFormEmpty() && $elements.length > 0 && paymentFormHeight > ignoreHeight ? true : false; 521 }; 522 523 this.isPaymentFormEmpty = function() { 524 var self = this; 525 var $paymentForm = $(self.params.mainContainer).find(self.selectors.paymentForm); 526 527 return $paymentForm.length && $paymentForm.find("*").length > 0 ? false : true; 528 }; 529 530 this.startPaymentFormObserving = function() { 531 var self = this; 532 var $paymentForm = $(self.params.mainContainer).find(self.selectors.paymentForm); 533 534 if ($paymentForm.length) { 535 try { 536 var counter = 0; 537 var threshold = 3; 538 539 self.paymentFormObserver = new MutationObserver(function(mutation) { 540 if (counter < threshold) { 541 self.replaceCreateButtonWithConfirm(); 542 } 543 544 counter += 1; 545 }); 546 547 self.paymentFormObserver.observe($paymentForm.get(0), { 548 childList: true, 549 subtree: true, 550 characterData: true, 551 attributes: false 552 }); 553 } catch (e) { 554 555 } 556 } 557 }; 558 559 this.stopPaymentFormObserving = function() { 560 if (this.paymentFormObserver) { 561 this.paymentFormObserver.disconnect(); 562 this.paymentFormObserver = null; 563 } 564 }; 565 566 this.replaceCreateButtonWithConfirm = function() { 567 var self = this; 568 var $mainContainer = $(self.params.mainContainer); 569 var $paymentForm = $(self.params.mainContainer).find(self.selectors.paymentForm); 570 571 if (self.isPaymentFormEmpty()) { 572 return; 573 } 574 575 var $gatewayLink = $paymentForm.find(".buttons a:last"); 576 var $submitButton = $paymentForm.find(".buttons input[type=button]:last,.buttons input[type=submit]:last,.buttons input[type=image]:last,.buttons button:last,.buttons a.button:last[href='#'],.buttons a.btn:last[href='#'],.buttons a.button:last[href^='javascript'],.buttons a.btn:last[href^='javascript'],.buttons a.button:last:not([href]),.buttons a.btn:last:not([href])"); 577 var $lastButton = $paymentForm.find("input[type=button]:last,input[type=submit]:last,input[type=image]:last,button:last"); 578 var $lastLink = $paymentForm.find("a:last"); 579 580 var $obj = false; 581 582 if ($gatewayLink.length) { 583 $obj = $gatewayLink; 584 } else if ($submitButton.length) { 585 $obj = $submitButton; 586 } else if ($lastButton.length) { 587 $obj = $lastButton; 588 } else if ($lastLink.length) { 589 $obj = $lastLink; 590 } 591 592 if ($obj) { 593 if ($obj.attr("href") == "#" || $obj.attr("href") == "javascript://") { 594 $obj.removeAttr("href"); 595 } 596 597 var $clone = $obj.clone(false).removeAttr("onclick").addClass("btn button"); 598 599 $mainContainer.find("*[data-payment-button=true]").remove(); 600 $mainContainer.find(self.selectors.buttonCreate).hide().before($clone); 601 602 $clone 603 .attr("data-payment-button", "true") 604 .bind("mousedown", function() { 605 if ($obj.attr("disabled")) { 606 return; 607 } 608 609 $obj.mousedown(); 610 }) 611 .bind("click", function() { 612 if ($obj.attr("disabled")) { 613 return; 614 } 615 616 self.preventOrderDeleting(function() { 617 self.proceed(); 618 $obj.click(); 619 self.blockFieldsDuringPayment($obj); 620 }); 621 }) 622 .show(); 623 624 $obj.hide(); 625 } else { 626 $mainContainer.find(self.selectors.buttons).hide(); 627 self.preventOrderDeleting(); 628 } 629 }; 630 631 this.blockFieldsDuringPayment = function($button) { 632 var self = this; 633 634 self.disableAllFieldsBeforePayment(); 635 636 if (typeof $button !== "undefined") { 637 var timerId = setInterval(function() { 638 if (!$button.attr("disabled")) { 639 self.enableAllFieldsAfterPayment(); 640 clearInterval(timerId); 641 } 642 }, 250); 643 } 644 }; 645 646 this.disableAllFieldsBeforePayment = function() { 647 var self = this; 648 649 $(self.params.mainContainer).find(self.selectors.block).each(function() { 650 if ($(this).attr("id") == "simplecheckout_payment_form") { 651 return; 652 } 653 $(this).find("input,select,textarea").attr("disabled", "disabled"); 654 $(this).find("[data-onclick]").attr("disabled", "disabled"); 655 }); 656 }; 657 658 this.enableAllFieldsAfterPayment = function() { 659 var self = this; 660 661 $(self.params.mainContainer).find(self.selectors.block).each(function() { 662 if ($(this).attr("id") == "simplecheckout_payment_form") { 663 return; 664 } 665 $(this).find("input:not([data-dummy]),select,textarea").removeAttr("disabled"); 666 $(this).find("[data-onclick]").removeAttr("disabled"); 667 }); 668 }; 669 670 this.proceed = function() { 671 var self = this; 672 if (self.params.displayProceedText && !self.isPaymentFormVisible()) { 673 $(self.params.mainContainer).find(self.selectors.proceedText).show(); 674 } 675 }; 676 677 this.gotoStep = function($target) { 678 var self = this; 679 var step = $target.attr("data-step"); 680 if (step < self.currentStep) { 681 $.when(self.hideCurrentStep()).then(function() { 682 self.currentStep = step; 683 self.saveStepNumber = step; 684 self.setDirty();
685 self.displayCurrentStep(true); 686 }); 687 } else if (step > self.currentStep) { 688 self.nextStep($target); 689 } 690 }; 691 692 this.previousStep = function($target) { 693 var self = this; 694 if (self.currentStep > 1) { 695 $.when(self.hideCurrentStep()).then(function() { 696 self.currentStep--; 697 self.saveStepNumber--; 698 self.setDirty(); 699 self.displayCurrentStep(true); 700 }); 701 } 702 }; 703 704 this.nextStep = function($target) { 705 var self = this; 706 707 if ($target.data("clicked")) { 708 return; 709 } 710 711 $target.data("clicked", true); 712 713 self.validate(false).then(function(result) { 714 if (result) { 715 if (self.currentStep < self.$steps.length) { 716 self.currentStep++; 717 } 718 719 self.hideCurrentStep(); 720 721 self.submitForm(true); 722 } else { 723 if (typeof toastr !== 'undefined' && self.params.notificationCheckForm) { 724 toastr.error(self.params.notificationCheckFormText); 725 } 726 727 $target.data("clicked", false); 728 729 self.scroll(); 730 } 731 }); 732 }; 733 734 this.saveStep = function() { 735 var self = this; 736 if (self.currentStep) { 737 $(self.params.mainContainer).append($("<input/>").attr("type", "hidden").attr("name", "next_step").val(self.currentStep)); 738 } 739 }; 740 741 this.ignorePost = function() { 742 var self = this; 743 $(self.params.mainContainer).append($("<input/>").attr("type", "hidden").attr("name", "ignore_post").val(1)); 744 }; 745 746 this.addSystemFieldsInForm = function() { 747 var self = this; 748 if (self.isCreateOrderClicked) { 749 $(self.params.mainContainer).append($("<input/>").attr("type", "hidden").attr("name", "create_order").val(1)); 750 } 751 if (self.currentStep) { 752 $(self.params.mainContainer).append($("<input/>").attr("type", "hidden").attr("name", "next_step").val(self.currentStep)); 753 } 754 }; 755 756 this.getAgreementCheckboxStep = function() { 757 var step = typeof this.params.agreementCheckboxStep !== "undefined" && this.params.agreementCheckboxStep !== "" ? (this.params.agreementCheckboxStep + 1) : this.stepsCount - 1; 758 759 if (step > this.stepsCount - 1) { 760 step = this.stepsCount - 1; 761 } 762 763 return step; 764 } 765 766 this.setLocationHash = function(hash) { 767 window.location.hash = hash; 768 this.backCount--; 769 }; 770 771 this.initSteps = function(changeStep) { 772 var self = this; 773 var i = 1; 774 var $mainContainer = $(self.params.mainContainer); 775 var $steps = $mainContainer.find(self.selectors.step); 776 777 self.stepReseted = false; 778 self.$steps = []; 779 self.stepsCount = $steps.length || 1; 780 781 $steps.each(function() { 782 var $step = $(this); 783 self.$steps.push($step); 784 // check steps before current for errors and set step with error as current 785 var $errorBlocks = $step.find(self.selectors.block + "[data-error=true]"); 786 if (i < self.currentStep && $errorBlocks.length) { 787 self.currentStep = i; 788 self.stepReseted = true; 789 } 790 i++; 791 }); 792 793 if (self.stepsCount > 1 && !self.stepReseted && (self.currentStep == self.stepsCount || self.currentStep > self.getAgreementCheckboxStep()) && $mainContainer.attr("data-error") == "true") { 794 self.currentStep--; 795 self.stepReseted = true; 796 } 797 798 //a fix for case when some steps are suddenly hidden after aja
798x request 799 if (self.stepsCount > 1 && !self.stepReseted && self.currentStep > self.stepsCount) { 800 self.currentStep = self.stepsCount; 801 } 802 803 $mainContainer.find(self.selectors.paymentButtons).hide(); 804 805 if (!self.isPaymentFormVisible()) { 806 $mainContainer.find(self.selectors.paymentForm).css({ 807 "margin": "0", 808 "padding": "0" 809 }); 810 } 811 812 self.displayCurrentStep(changeStep); 813 }; 814 815 this.hideCurrentStep = function() { 816 var self = this; 817 var $mainContainer = $(self.params.mainContainer); 818 819 $mainContainer.find(self.selectors.agreementWarning).hide(); 820 821 if (typeof self.params.menuType !== "undefined" && self.params.menuType == 2) { 822 $mainContainer.find(self.selectors.buttons).hide(); 823 return $mainContainer.find(self.selectors.step).slideUp("slow"); 824 } else { 825 //return $mainContainer.find(self.selectors.step).hide(); 826 } 827 }; 828 829 this.displayCurrentStep = function(changeStep) { 830 var self = this; 831 var $mainContainer = $(self.params.mainContainer); 832 833 var initButtons = function() { 834 if (self.stepsCount > 1) { 835 if (self.currentStep == 1) { 836 $mainContainer.find(self.selectors.buttonPrev).hide(); 837 } else { 838 $mainContainer.find(self.selectors.buttonBack).hide(); 839 } 840 841 if (self.currentStep < self.stepsCount) { 842 $mainContainer.find(self.selectors.buttonNext).show(); 843 $mainContainer.find(self.selectors.buttonCreate).hide(); 844 } 845 846 $mainContainer.find(self.selectors.agreementCheckBox).hide(); 847 848 if (self.currentStep == self.getAgreementCheckboxStep()) { 849 $mainContainer.find(self.selectors.agreementCheckBox).show(); 850 } 851 } 852 853 if (typeof self.params.stepButtons !== 'undefined' && typeof self.params.stepButtons[self.currentStep] !== 'undefined' && self.params.stepButtons[self.currentStep] != '') { 854 var $button = $mainContainer.find(self.stepsCount > 1 ? self.selectors.buttonNext : self.selectors.buttonCreate); 855 856 if ($button.find('span').length) { 857 $button = $button.find('span'); 858 } 859 860 $button.html(self.params.stepButtons[self.currentStep]); 861 } 862 863 if (self.currentStep == self.stepsCount) { 864 $mainContainer.find(self.selectors.buttonNext).hide(); 865 self.replaceCreateButtonWithConfirm(); 866 self.startPaymentFormObserving(); 867 } 868 }; 869 870 var initStepsMenu = function() { 871 if (typeof self.params.menuType !== "undefined" && self.params.menuType == 2) { 872 for (var i = 1; i < self.stepsCount + 1; i++) { 873 var $topItem = $mainContainer.find(self.selectors.stepsMenuTop + " " + self.selectors.stepsMenuVerticalItem + "[data-step=" + i + "]"); 874 var $bottomItem = $mainContainer.find(self.selectors.stepsMenuBottom + " " + self.selectors.stepsMenuVerticalItem + "[data-step=" + i + "]"); 875 876 if (i <= self.currentStep) { 877 $topItem.show(); 878 $topItem.addClass(self.classes.stepsMenuVerticalCompleted); 879 $bottomItem.hide(); 880 } else { 881 $topItem.removeClass(self.classes.stepsMenuVerticalCompleted); 882 $topItem.hide(); 883 $bottomItem.show(); 884 } 885 } 886 } else { 887 $mainContainer.find(self.selectors.stepsMenu + " " + self.selectors.stepsMenuItem).removeClass(self.classes.stepsMenuCompleted).removeClass(self.classes.stepsMenuCurrent); 888 $mainContainer.find(self.selectors.stepsMenu + " " + self.selectors.stepsMenuDelimiter + " img").attr("src", self.params.additionalPath + self.resources.next); 889 890 for (var i = 1; i < self.currentStep; i++) { 891 $mainContainer.find(self.selectors.stepsMenu + " " + self.selectors.stepsMenuItem + "[data-step=" + i + "]").addClass(self.classes.stepsMenuCompleted); 892 $mainContainer.find(self.selectors.stepsMenu + " " + self.selectors.stepsMenuDelimiter + "[data-step=" + (i + 1) + "] img").attr("src", self.params.additionalPath + self.resources.nextCompleted); 893 } 894 895 $mainContainer.find(self.selectors.stepsMenu + " " + self.selectors.stepsMenuItem + "[data-step=" + self.currentStep + "]").addClass(self.classes.stepsMenuCurrent); 896 } 897 }; 898 899 var hideAllSteps = function() { 900 $mainContainer.find(self.selectors.step).hide(); 901 }; 902 903 var isLastStepHasOnlyPaymentForm = function() { 904 var $lastStep = $mainContainer.find(self.selectors.step + ":last"); 905 return $lastStep.find(self.selectors.block).length == 1 && $lastStep.find(self.selectors.paymentForm).length == 1 ? true : false; 906 }; 907 908 hideAllSteps(); 909 910 if (typeof self.$steps[self.currentStep - 1] !== "undefined") { 911 if (changeStep) { 912 if (typeof self.params.menuType !== "undefined" && self.params.menuType == 2) { 913 self.$steps[self.currentStep - 1].slideDown("slow"); 914 $mainContainer.find(self.selectors.buttons).show(); 915 } else { 916 self.$steps[self.currentStep - 1].show(); 917 918 } 919 } else { 920 self.$steps[self.currentStep - 1].show(); 921 } 922 } 923 924 if (self.stepsCount > 1) { 925 self.setLocationHash("step_" + self.currentStep); 926 } 927 928 initStepsMenu(); 929 initButtons(); 930 931 if (self.currentStep == self.stepsCount && !self.isPaymentFormVisible() && self.isPaymentFormValid() && (isLastStepHasOnlyPaymentForm(
931) || self.isCreateOrderClicked)) { 932 self.clickOnConfirmButton(); 933 if (isLastStepHasOnlyPaymentForm()) { 934 self.currentStep--; 935 } 936 } 937 }; 938 939 this.scroll = function() { 940 var self = this, 941 error = false, 942 top = 10000, 943 bottom = 0; 944 945 var $mainContainer = $(self.params.mainContainer); 946 947 var isOutsideOfViewport = function(y) { 948 if (y < $(window).scrollTop() || y > ($(window).scrollTop() + $(window).height())) { 949 return true; 950 } 951 return false; 952 }; 953 954 if (self.params.popup) { 955 return; 956 } 957 958 if (self.params.scrollToError) { 959 $($mainContainer.find("[data-error=true]:visible")).each(function() { 960 var offset = $(this).offset(); 961 if (offset.top < top) { 962 top = offset.top; 963 } 964 if (offset.bottom > bottom) { 965 bottom = offset.bottom; 966 } 967 }); 968 969 $($mainContainer.find(".simplecheckout-warning-block:visible")).each(function() { 970 var offset = $(this).offset(); 971 if (offset.top < top) { 972 top = offset.top; 973 } 974 if (offset.bottom > bottom) { 975 bottom = offset.bottom; 976 } 977 }); 978 979 $($mainContainer.find(".simplecheckout-rule:visible")).each(function() { 980 if ($(this).parents(".simplecheckout-block").length) { 981 var offset = $(this).parents(".simplecheckout-block").offset(); 982 if (offset.top < top) { 983 top = offset.top; 984 } 985 if (offset.bottom > bottom) { 986 bottom = offset.bottom; 987 } 988 } 989 }); 990 991 if (top < 10000 && isOutsideOfViewport(top)) { 992 $("html, body").animate({ 993 scrollTop: top 994 }, "slow"); 995 error = true; 996 } else if (bottom && isOutsideOfViewport(bottom)) { 997 $("html, body").animate({ 998 scrollTop: bottom 999 }, "slow"); 1000 error = true; 1001 } 1002 } 1003 1004 if ($mainContainer.find(self.selectors.stepsMenu).length && self.currentStep != self.saveStepNumber) { 1005 var menu = $mainContainer.find(self.selectors.stepsMenu + " " + "[data-step=" + self.currentStep + "]:visible"); 1006 1007 if (menu.length) { 1008 top = menu.offset().top; 1009 1010 if (top && isOutsideOfViewport(top)) { 1011 $("html, body").animate({ 1012 scrollTop: top 1013 }, "slow"); 1014 } 1015 } 1016 } 1017 1018 var mainContainerTop = $mainContainer.offset().top; 1019 var mainContainerHeight = $mainContainer.outerHeight(); 1020 1021 if ((mainContainerTop + mainContainerHeight) < $(window).scrollTop()) { 1022 $("html, body").animate({ 1023 scrollTop: mainContainerTop - 50 1024 }, "slow"); 1025 } 1026 1027 if (self.params.scrollToPaymentForm && !error) { 1028 if (self.isPaymentFormVisible()) { 1029 var formTop = $mainContainer.find(self.selectors.paymentForm).offset().top; 1030 var formHeight = $mainContainer.find(self.selectors.paymentForm).outerHeight(); 1031 var scrollTo = 0; 1032 1033 if (formHeight < $(window).height()) { 1034 if (formTop < $(window).scrollTop()) { 1035 scrollTo = formTop; 1036 } else if ((formTop + formHeight) > ($(window).scrollTop() + $(window).height())) { 1037 scrollTo = formTop + formHeight - $(window).height() + 2 * $mainContainer.find(self.selectors.buttons).outerHeight(); 1038 } 1039 } else { 1040 if (isOutsideOfViewport(formTop)) { 1041 scrollTo = formTop; 1042 } 1043 } 1044 1045 if (scrollTo) { 1046 $("html, body").animate({ 1047 scrollTop: scrollTo 1048 }, "slow"); 1049 } 1050 } 1051 } 1052 1053 self.saveStepNumber = self.currentStep; 1054 }; 1055 1056 this.validateAgreements = function(silent) { 1057 var self = this; 1058 1059 var result = true; 1060 1061 var $agreementCheckbox = $(self.params.mainContainer).find(self.selectors.agreementCheckBox).find("input[type=checkbox]"); 1062 var $agreementCheckboxChecked = $(self.params.mainContainer).find(self.selectors.agreementCheckBox).find("input[type=checkbox]:checked"); 1063 var $agreementWarning = $(self.params.mainContainer).find(self.selectors.agreementWarning); 1064 1065 if ($agreementCheckbox.length && $agreementCheckbox.is(":visible") && $agreementCheckbox.length != $agreementCheckboxChecked.length) { 1066 if ($agreementWarning.length) { 1067 if (!silent) { 1068 $agreementWarning.attr("data-error", "true"); 1069 1070 if (self.params.notificationDefault) { 1071 $agreementWarning.show(); 1072 1073 $agreementCheckbox.each(function() { 1074 if ($(this).is(":checked")) { 1075 $(".agreement_" + $(this).val()).hide(); 1076 } else { 1077 $(".agreement_" + $(this).val()).show(); 1078 } 1079 }); 1080 } 1081 1082 if (self.params.notificationToasts) { 1083 $agreementCheckbox.each(function() { 1084 if (!$(this).is(":checked")) { 1085 toastr.error($(".agreement_" + $(this).val()).text()); 1086 } 1087 }); 1088 } 1089 } 1090 1091 result = false; 1092 } 1093 } else { 1094 $agreementWarning.hide().removeAttr("data-error"); 1095 } 1096 1097 return result; 1098 }; 1099 1100 this.validate = function(silent) { 1101 var self = this; 1102 var result = true; 1103 var promises = []; 1104 1105 if (typeof silent === "undefined") { 1106 silent = false; 1107 } 1108 1109 if (!self.validateAgreements(silent)) { 1110 result = false; 1111 } 1112 1113 for (var i in self.blocks) { 1114 if (!self.blocks.hasOwnProperty(i)) continue; 1115
1116 var promise = self.blocks[i].validate(silent).then(function(validatorResult) { 1117 if (!validatorResult) { 1118 result = false; 1119 } 1120 }); 1121 1122 promises.push(promise); 1123 } 1124 1125 if (typeof simpleValidate === 'function') { 1126 if (!simpleValidate()) { 1127 result = false; 1128 } 1129 } 1130 1131 var deferred = $.Deferred(); 1132 1133 $.when.apply($, promises).then(function() { 1134 deferred.resolve(result); 1135 }); 1136 1137 return deferred.promise(); 1138 }; 1139 1140 this.backHistory = function() { 1141 var self = this; 1142 history.go(self.backCount); 1143 }; 1144 1145 this.createOrder = function() { 1146 var self = this; 1147 1148 self.validate(false).then(function(result) { 1149 if (result) { 1150 self.isCreateOrderClicked = true; 1151 self.submitForm(); 1152 } else { 1153 if (typeof toastr !== 'undefined' && self.params.notificationCheckForm) { 1154 toastr.error(self.params.notificationCheckFormText); 1155 } 1156 1157 self.scroll(); 1158 } 1159 }); 1160 }; 1161 1162 this.submitForm = function(changeStep) { 1163 var self = this; 1164 self.requestReloadAll(null, changeStep); 1165 }; 1166 1167 /** 1168 * Adds delay for reload execution on 150 ms, it allows to check sequence of events and to execute only the last request to handle of more events in one reloading 1169 * @param {Function} callback 1170 */ 1171 this.requestReloadAll = function(callback, changeStep) { 1172 var self = this; 1173 if (self.requestTimerId) { 1174 clearTimeout(self.requestTimerId); 1175 self.requestTimerId = 0; 1176 } 1177 self.requestTimerId = window.setTimeout(function() { 1178 self.reloadAll(callback, false, changeStep); 1179 }, 150); 1180 }; 1181 1182 this.overlayAll = function() { 1183 var self = this; 1184 var $mainContainer = $(self.params.mainContainer); 1185 1186 for (var i in self.blocks) { 1187 if (!self.blocks.hasOwnProperty(i)) continue; 1188 1189 self.blocks[i].overlay(); 1190 } 1191 1192 $mainContainer.find(self.selectors.block).each(function() { 1193 if (!$(this).data("initialized")) { 1194 SimplecheckoutBlock.prototype.overlay.apply(self, [$(this)]); 1195 } 1196 }); 1197 1198 $mainContainer.find("[data-onclick]").attr("disabled", "disabled"); 1199 }; 1200 1201 this.removeOverlays = function() { 1202 var self = this; 1203 var $mainContainer = $(self.params.mainContainer); 1204 1205 $mainContainer.find(self.selectors.overlay).remove(); 1206 $mainContainer.find("input:not([data-dummy]),select,textarea").removeAttr("disabled"); 1207 $mainContainer.find("[data-onclick]").removeAttr("disabled"); 1208 }; 1209 1210 this.syncShippingAndPaymentAddresses = function() { 1211 //$("#simplecheckout_payment_address").find("input:not([type=hidden]),select,textarea").on("change", ) 1212 }; 1213 1214 this.createPostData = function() { 1215 var self = this; 1216 var usedBlocks = []; 1217 var fields = []; 1218 1219 var copyFields = function(serializedFields, skipUsed) { 1220 for (var i in serializedFields) { 1221 if (!serializedFields.hasOwnProperty(i)) continue; 1222 1223 var info = serializedFields[i]; 1224 var pair = encodeURIComponent(info.name)+"="+encodeURIComponent(info.value); 1225 1226 if (typeof skipUsed === "undefined" || (skipUsed && $.inArray(pair, fields) == -1)) { 1227 fields.push(pair); 1228 } 1229 } 1230 }; 1231 1232 $(self.params.mainContainer + " .simplecheckout-step:visible .simplecheckout-block:not(#simplecheckout_payment_form)").each(function() { 1233 var $block = $(this); 1234 1235 if ($block.attr("id")) { 1236 usedBlocks.push($block.attr("id")); 1237 } 1238 1239 copyFields(self.serializeFields($block)); 1240 }); 1241 1242 $(self.params.mainContainer + " .simplecheckout-step:not(:visible) .simplecheckout-block:not(#simplecheckout_payment_form)").each(function() { 1243 var $block = $(this); 1244 1245 if ($block.attr("id") && $.inArray($block.attr("id"), usedBlocks) > -1) { 1246 return; 1247 } 1248 1249 copyFields(self.serializeFields($block)); 1250 }); 1251 1252 var otherFields = self.serializeFields($(self.params.mainContainer + " *:not(#simplecheckout_payment_form)")); 1253 1254 copyFields(otherFields, true); 1255 1256 var allFields = self.serializeFields($(self.params.mainContainer));
1257 1258 copyFields(allFields, true); 1259 1260 return fields.join("&"); 1261 } 1262 1263 /** 1264 * Reload all blocks via main controller which includes all registered blocks as childs 1265 * @param {Function} callback 1266 */ 1267 this.reloadAll = function(callback, disableScroll, changeStep) { 1268 var self = this; 1269 1270 if (self.isReloading) { 1271 return; 1272 } 1273 1274 if (typeof disableScroll === "undefined") { 1275 disableScroll = false; 1276 } 1277 1278 if (typeof changeStep === "undefined") { 1279 changeStep = false; 1280 } 1281 1282 self.addSystemFieldsInForm(); 1283 self.isReloading = true; 1284 1285 var postData = self.createPostData(); 1286 var overlayTimeoutId = 0; 1287 1288 $.ajax({ 1289 url: self.params.mainUrl, 1290 data: postData + "&simple_ajax=1", 1291 type: "POST", 1292 dataType: "text", 1293 beforeSend: function() { 1294 $('.tooltip ').remove(); 1295 1296 overlayTimeoutId = window.setTimeout(function() { 1297 if (overlayTimeoutId && !(typeof self.params.menuType !== "undefined" && self.params.menuType == 2 && changeStep)) { 1298 self.overlayAll(); 1299 } 1300 }, 250); 1301 }, 1302 success: function(data) { 1303 clearTimeout(overlayTimeoutId); 1304 overlayTimeoutId = 0; 1305 1306 var newData = $(self.params.mainContainer, $(data)).get(0); 1307 if (!newData && data) { 1308 newData = data; 1309 } 1310 1311 try { 1312 $(self.params.mainContainer).replaceWith(newData); 1313 } catch (e) { 1314 console.error(e); 1315 } 1316 1317 self.init(disableScroll, changeStep); 1318 1319 if (typeof callback === "function") { 1320 callback.call(self); 1321 } 1322 1323 self.removeOverlays(); 1324 self.isReloading = false; 1325 }, 1326 error: function(xhr, ajaxOptions, thrownError) { 1327 clearTimeout(overlayTimeoutId); 1328 overlayTimeoutId = 0; 1329 self.removeOverlays(); 1330 self.isReloading = false; 1331 } 1332 }); 1333 }; 1334 1335 this.reloadBlock = function(container, callback) { 1336 var self = this; 1337 if (self.isReloading) { 1338 return; 1339 } 1340 self.isReloading = true; 1341 var postData = $(self.params.mainContainer).find("input,select,textarea").serialize(); 1342 $.ajax({
1343 url: self.params.mainUrl, 1344 data: postData + "&simple_ajax=1", 1345 type: "POST", 1346 dataType: "text", 1347 beforeSend: function() {}, 1348 success: function(data) { 1349 var newData = $(container, $(data)).get(0); 1350 1351 if (!newData && data) { 1352 newData = data; 1353 } 1354 1355 try { 1356 $(container).replaceWith(newData); 1357 } catch (e) { 1358 console.error(e); 1359 } 1360 1361 self.init(); 1362 1363 if (typeof callback === "function") { 1364 callback.call(self); 1365 } 1366 1367 self.isReloading = false; 1368 }, 1369 error: function(xhr, ajaxOptions, thrownError) { 1370 self.isReloading = false; 1371 } 1372 }); 1373 }; 1374 1375 this.registerBlock(new SimplecheckoutCart("#simplecheckout_cart", "checkout/simplecheckout_cart")); 1376 this.registerBlock(new SimplecheckoutShipping("#simplecheckout_shipping", "checkout/simplecheckout_shipping")); 1377 this.registerBlock(new SimplecheckoutPayment("#simplecheckout_payment", "checkout/simplecheckout_payment")); 1378 this.registerBlock(new SimplecheckoutForm("#simplecheckout_customer", "checkout/simplecheckout_customer")); 1379 this.registerBlock(new SimplecheckoutForm("#simplecheckout_payment_address", "checkout/simplecheckout_payment_address")); 1380 this.registerBlock(new SimplecheckoutForm("#simplecheckout_shipping_address", "checkout/simplecheckout_shipping_address")); 1381 this.registerBlock(new SimplecheckoutComment("#simplecheckout_comment", "checkout/simplecheckout_comment")); 1382 this.registerBlock(new SimplecheckoutBlock("#simplecheckout_summary", "checkout/simplecheckout_summary")); 1383 1384 var login = new SimplecheckoutLogin("#simplecheckout_login", "checkout/simplecheckout_login"); 1385 login.setParent(this); 1386 login.init(); 1387 login.shareMethod("open", "openLoginBox"); 1388 1389 this.instances.push(this); 1390 }; 1391 1392 Simplecheckout.prototype = inherit(window.Simple.prototype); 1393 1394 /** 1395 * It is parent of all blocks 1396 */ 1397 1398 function SimplecheckoutBlock(container, route) { 1399 this.currentContainer = container; 1400 this.currentRoute = route; 1401 } 1402 1403 SimplecheckoutBlock.prototype.setParent = function(object) { 1404 this.simplecheckout = object; 1405 this.params = object.params; 1406 this.resources = object.resources; 1407 }; 1408 1409 SimplecheckoutBlock.prototype.reloadAll = function(callback) { 1410 if (this.simplecheckout) { 1411 this.simplecheckout.requestReloadAll(callback, false); 1412 } else { 1413 this.reload(); 1414 } 1415 }; 1416 1417 SimplecheckoutBlock.prototype.reload = function(callback) { 1418 var self = this; 1419 if (self.isReloading) { 1420 return; 1421 } 1422 self.isReloading = true; 1423 var postData = $(self.params.mainContainer).find(self.currentContainer + ":visible").find("input,select,textarea").serialize(); 1424 $.ajax({
1425 url: "index.php?" + self.params.additionalParams + "route=" + self.currentRoute, 1426 data: postData + "&simple_ajax=1", 1427 type: "POST", 1428 dataType: "text", 1429 beforeSend: function() { 1430 self.overlay(); 1431 }, 1432 success: function(data) { 1433 var newData = $(self.currentContainer, $(data)).get(0); 1434 1435 if (!newData && data) { 1436 newData = data; 1437 } 1438 1439 try { 1440 $(self.params.mainContainer).find(self.currentContainer + ":visible").replaceWith(newData); 1441 } catch (e) { 1442 console.error(e); 1443 } 1444 1445 if (typeof callback === "function") { 1446 callback.call(self); 1447 } 1448 1449 self.removeOverlay(); 1450 self.isReloading = false; 1451 self.init(); 1452 }, 1453 error: function(xhr, ajaxOptions, thrownError) { 1454 self.removeOverlay(); 1455 self.isReloading = false; 1456 } 1457 }); 1458 }; 1459 1460 SimplecheckoutBlock.prototype.load = function(callback, container, params) { 1461 var self = this; 1462 if (self.isLoading) { 1463 return; 1464 } 1465 if (typeof callback !== "function") { 1466 container = callback; 1467 callback = null; 1468 } 1469 if (typeof params === "undefined") { 1470 params = ""; 1471 } 1472 self.isLoading = true; 1473 $.ajax({
1474 url: "index.php?" + self.params.additionalParams + "route=" + self.currentRoute + params, 1475 type: "GET", 1476 dataType: "text", 1477 beforeSend: function() { 1478 self.overlay(); 1479 }, 1480 success: function(data) { 1481 var newData = $(self.currentContainer, $(data)).get(0); 1482 1483 if (!newData && data) { 1484 newData = data; 1485 } 1486 1487 if (newData) { 1488 try { 1489 if (container) { 1490 $(container).html(newData); 1491 } else { 1492 $(self.currentContainer).replaceWith(newData); 1493 } 1494 } catch (e) { 1495 console.error(e); 1496 } 1497 } 1498 1499 if (typeof callback === "function") { 1500 callback(); 1501 } 1502 1503 self.removeOverlay(); 1504 self.isLoading = false; 1505 self.init(); 1506 }, 1507 error: function(xhr, ajaxOptions, thrownError) { 1508 self.removeOverlay(); 1509 self.isLoading = false; 1510 } 1511 }); 1512 }; 1513
1514 SimplecheckoutBlock.prototype.overlay = function(useBlock) { 1515 var self = this; 1516 var $block = (useBlock && $(useBlock)) || $(self.params.mainContainer).find(self.currentContainer); 1517 1518 if ($block.length) { 1519 if (~~$block.height() < 50) { 1520 return; 1521 } 1522 $block.find("input,select,textarea").attr("disabled", "disabled"); 1523 $block.find("[data-onclick]").attr("disabled", "disabled"); 1524 $block.append("<div class='simplecheckout_overlay' id='" + $block.attr("id") + "_overlay'></div>"); 1525 $block.find(".simplecheckout_overlay") 1526 .css({ 1527 "background": "url(" + self.params.additionalParams + self.resources.loading + ") no-repeat center center", 1528 "opacity": 0.4, 1529 "position": "absolute", 1530 "width": $block.width(), 1531 "height": $block.height(), 1532 "z-index": 5000 1533 }) 1534 .offset({ 1535 top: $block.offset().top, 1536 left: $block.offset().left 1537 }); 1538 } 1539 }; 1540 1541 SimplecheckoutBlock.prototype.removeOverlay = function() { 1542 var self = this; 1543 var $mainContainer = $(self.params.mainContainer); 1544 1545 if (typeof self.currentContainer !== "undefined") { 1546 $mainContainer.find(self.currentContainer).find("input:not([data-dummy]),select,textarea").removeAttr("disabled"); 1547 $mainContainer.find(self.currentContainer).find("[data-onclick]").removeAttr("disabled"); 1548 $mainContainer.find(self.currentContainer + "_overlay").remove(); 1549 } 1550 }; 1551 1552 SimplecheckoutBlock.prototype.hasError = function() { 1553 return $(this.params.mainContainer).find(this.currentContainer).attr("data-error") ? true : false; 1554 }; 1555 1556 SimplecheckoutBlock.prototype.init = function(useContainer) { 1557 var self = this; 1558 var $mainContainer = $(self.params.mainContainer); 1559 var $currentContainer = $mainContainer.find(self.currentContainer + ":visible"); 1560 1561 if (!$currentContainer.length) { 1562 return; 1563 } 1564 1565 var callFunc = function(func, $target, e) { 1566 if (func && typeof self[func] === "function") { 1567 self[func]($target, e); 1568 } else if (func) { 1569 //console.log(func + " is not registered"); 1570 } 1571 }; 1572 1573 $currentContainer.find("*[data-onchange]").on("change", function(e) { 1574 if (typeof self.simplecheckout !== "undefined") { 1575 self.simplecheckout.setDirty($(this)); 1576 } 1577 callFunc($(this).attr("data-onchange"), $(this), e); 1578 }); 1579 1580 $currentContainer.find("*[data-onclick]").on("click", function(e) { 1581 if ($(this).attr("disabled")) { 1582 return; 1583 } 1584 1585 if (typeof self.simplecheckout !== "undefined") { 1586 self.simplecheckout.setDirty(); 1587 } 1588 1589 var confirmText = $(this).attr("data-confirm-text"); 1590 1591 if (!confirmText || (confirmText && confirm(confirmText))) { 1592 callFunc($(this).attr("data-onclick"), $(this), e); 1593 } 1594 }); 1595 1596 $currentContainer.find("*[data-onkeydown]").on("keydown", function(e) { 1597 if (typeof self.simplecheckout !== "undefined") { 1598 self.simplecheckout.setDirty(); 1599 } 1600 1601 callFunc($(this).attr("data-onkeydown"), $(this), e); 1602 }); 1603 1604 if (self.isEmpty()) { 1605 ////console.log(self.currentContainer + " is empty"); 1606 } 1607 1608 if (!self.hasError() && $currentContainer.attr("data-hide")) { 1609 $currentContainer.hide(); 1610 } 1611 1612 self.addFocusHandler(); 1613 self.restoreFocus(); 1614 1615 $currentContainer.data("initialized", true); 1616 }; 1617 1618 SimplecheckoutBlock.prototype.validate = function(silent) { 1619 var self = this; 1620 1621 if (typeof silent === "undefined") { 1622 silent = false; 1623 } 1624 1625 return self.simplecheckout.checkRules(self.currentContainer, silent); 1626 }; 1627 1628 SimplecheckoutBlock.prototype.isEmpty = function() { 1629 if ($(this.params.mainContainer).find(this.currentContainer).find("*").length) { 1630 return false; 1631 } 1632 return true; 1633 }; 1634 1635 SimplecheckoutBlock.prototype.shareMethod = function(name, asName) { 1636 SimplecheckoutBlock.prototype[asName] = bind(this[name], this); 1637 }; 1638 1639 SimplecheckoutBlock.prototype.displayWarning = function() { 1640 var container = $(this.params.mainContainer).find(this.currentContainer); 1641 1642 if (this.params.notificationDefault) { 1643 container.find(".simplecheckout-warning-block").show(); 1644 } 1645 1646 if (this.params.notificationToasts) { 1647 container.find(".simplecheckout-warning-block").each(function() { 1648 toastr.error($(this).text()); 1649 }); 1650 } 1651 1652 if (container.find(".simplecheckout-warning-block").length) { 1653 container.attr('data-error', true); 1654 } 1655 }; 1656 1657 SimplecheckoutBlock.prototype.hideWarning = function() { 1658 $(this.params.mainContainer).find(this.currentContainer).find(".simplecheckout-warning-block").hide(); 1659 }; 1660
1661 SimplecheckoutBlock.prototype.focusedFieldId = ""; 1662 1663 SimplecheckoutBlock.prototype.addFocusHandler = function() { 1664 var self = this; 1665 var $currentContainer = $(self.params.mainContainer).find(self.currentContainer + ":visible"); 1666 1667 $currentContainer.find("input,textarea,select").focus(function() { 1668 self.simplecheckout.focusedFieldId = $(this).attr("id"); 1669 }); 1670 1671 $(self.params.mainContainer).find("*:not(input,textarea,select)").focus(function() { 1672 self.simplecheckout.focusedFieldId = ""; 1673 }); 1674 }; 1675 1676 SimplecheckoutBlock.prototype.restoreFocus = function() { 1677 var self = this; 1678 var $currentContainer = $(self.params.mainContainer).find(self.currentContainer + ":visible"); 1679 var focusedFieldId = self.simplecheckout.focusedFieldId; 1680 1681 if (focusedFieldId && $currentContainer) { 1682 var focusedField = $currentContainer.find("#" + focusedFieldId); 1683 1684 if (focusedField.length && focusedField.is(":visible") && ((focusedField.attr("type") && focusedField.attr("type") == "text" && !focusedField.attr("data-type") && !focusedField.attr("data-simple-mask")) || focusedField.is("textarea"))) { 1685 var $field = $currentContainer.find("#" + focusedFieldId); 1686 var value = $field.val(); 1687 $field.val("").focus().val(value); 1688 } 1689 } 1690 }; 1691 1692 function SimplecheckoutCart(container, route) { 1693 this.currentContainer = container; 1694 this.currentRoute = route; 1695 1696 this.init = function() { 1697 var self = this; 1698 SimplecheckoutBlock.prototype.init.apply(self, arguments); 1699 self.initMiniCart(); 1700 }; 1701 1702 this.validate = function(silent) { 1703 var self = this; 1704 var result = true; 1705 var deferred = $.Deferred(); 1706 1707 if (typeof silent === "undefined") { 1708 silent = false; 1709 } 1710 1711 if (!silent && this.hasError()) { 1712 this.displayWarning(); 1713 1714 result = false; 1715 } 1716 1717 deferred.resolve(result); 1718 1719 return deferred.promise(); 1720 }; 1721 1722 this.clearCart = function() { 1723 var self = this; 1724 1725 $.get("index.php?" + self.params.additionalParams + "route=" + self.currentRoute + "/clear", function() { 1726 self.reloadAll(); 1727 }); 1728 }; 1729 1730 this.initMiniCart = function() { 1731 var self = this; 1732 var $mainContainer = $(self.params.mainContainer); 1733 var total = $mainContainer.find("#simplecheckout_cart_total").html(); 1734 var weight = $mainContainer.find("#simplecheckout_cart_weight").text(); 1735 1736 if (total) { 1737 $.each(["#cart_total", "#cart-total", "#cart_menu .s_grand_total", "#cart .tb_items", "#cart .tb_total", "#menu_wrap #cart-total"], function(index, selector) { 1738 $(selector).html(total); 1739 }); 1740 1741 $("#weight").text(weight); 1742 } 1743 }; 1744 1745 this.increaseProductQuantity = function($target) { 1746 1747 var self = this; 1748 1749 var $quantity = $target.parents(".item_qty").find("input"); 1750 var quantity = parseFloat($quantity.val()); 1751 var step = +$quantity.attr("data-minimum") || 1; 1752 1753 console.log(quantity); 1754 1755 if (!isNaN(quantity)) { 1756 $quantity.val(quantity + step); 1757 1758 self.copyCartState($quantity); 1759 1760 if (self.timerId) { 1761 clearTimeout(self.timerId); 1762 self.timerId = 0; 1763 } 1764 1765 self.timerId = window.setTimeout(function() { 1766 self.reloadAll(); 1767 }, 300); 1768 } 1769 }; 1770 1771 this.decreaseProductQuantity = function($target) { 1772 var self = this; 1773 1774 var $quantity = $target.parents(".item_qty").find("input"); 1775 var quantity = parseFloat($quantity.val()); 1776 var step = +$quantity.attr("data-minimum") || 1; 1777 1778 if (!isNaN(quantity) && quantity > step) { 1779 $quantity.val(quantity - step); 1780 1781 self.copyCartState($quantity); 1782 1783 if (self.timerId) { 1784 clearTimeout(self.timerId); 1785 self.timerId = 0; 1786 } 1787 1788 self.timerId = window.setTimeout(function() { 1789 self.reloadAll(); 1790 }, 300); 1791 } 1792 }; 1793 1794 this.changeProductQuantity = function($target) { 1795 var self = this; 1796 1797 if (typeof $target[0] !== "undefined" && typeof $target[0].tagName !== "undefined" && $target[0].tagName !== "INPUT") { 1798 $target = $target.parents("td").find("input"); 1799 } 1800
1801 var $quantity = $target.parents(".item_qty").find("input"); 1802 var quantity = parseFloat($quantity.val()); 1803 var step = +$quantity.attr("data-minimum") || 1; 1804 1805 quantity = Math.round(quantity / step) * step; 1806 1807 if (!quantity) { 1808 quantity = step; 1809 } 1810 1811 if (!isNaN(quantity)) { 1812 $quantity.val(quantity); 1813 1814 self.copyCartState($target); 1815 1816 self.reloadAll(); 1817 } 1818 }; 1819 1820 this.removeProduct = function($target) { 1821 var self = this; 1822 var $currentContainer = $(self.params.mainContainer).find(self.currentContainer + ":visible"); 1823 1824 var productKey = $target.attr("data-product-key"); 1825 1826 var $target = $currentContainer.find("#simplecheckout_remove"); 1827 $target.val(productKey); 1828 self.copyCartState($target); 1829 1830 self.reloadAll(); 1831 }; 1832 1833 this.removeGift = function($target) { 1834 var self = this; 1835 var $currentContainer = $(self.params.mainContainer).find(self.currentContainer + ":visible"); 1836 1837 var giftKey = $target.attr("data-gift-key"); 1838 1839 var $target = $currentContainer.find("#simplecheckout_remove"); 1840 $target.val(giftKey); 1841 self.copyCartState($target); 1842 1843 self.reloadAll(); 1844 }; 1845 1846 this.removeCoupon = function($target) { 1847 var self = this; 1848 var $currentContainer = $(self.params.mainContainer).find(self.currentContainer + ":visible"); 1849 1850 $target = $currentContainer.find("input[name='coupon']"); 1851 $target.val(""); 1852 self.copyCartState($target); 1853 1854 self.reloadAll(); 1855 }; 1856 1857 this.removeReward = function($target) { 1858 var self = this; 1859 var $currentContainer = $(self.params.mainContainer).find(self.currentContainer + ":visible"); 1860 1861 $target = $currentContainer.find("input[name='reward']"); 1862 $target.val(""); 1863 self.copyCartState($target); 1864 1865 self.reloadAll(); 1866 }; 1867 1868 this.removeVoucher = function($target) { 1869 var self = this; 1870 var $currentContainer = $(self.params.mainContainer).find(self.currentContainer + ":visible"); 1871 1872 $target = $currentContainer.find("input[name='voucher']"); 1873 $target.val(""); 1874 self.copyCartState($target); 1875 1876 self.reloadAll(); 1877 }; 1878 1879 this.copyCartState = function($target) { 1880 var $mainContainer = $(this.params.mainContainer); 1881 var name = $target.attr('name'); 1882 var value = $target.val(); 1883 1884 $mainContainer.find('[name="' + name + '"]').each(function() { 1885 if (this != $target[0]) { 1886 $(this).val(value); 1887 } 1888 }); 1889 }; 1890 } 1891 1892 SimplecheckoutCart.prototype = inherit(SimplecheckoutBlock.prototype); 1893 1894 function SimplecheckoutLogin(container, route) { 1895 this.currentContainer = container; 1896 this.currentRoute = route; 1897 1898 this.init = function() { 1899 var self = this; 1900 SimplecheckoutBlock.prototype.init.apply(self, arguments); 1901 }; 1902 1903 this.removeTransformCss = function() { 1904 $(this.params.mainContainer) 1905 .parents() 1906 .filter(function() { 1907 var transformStyle = $(this).css("transform"); 1908 if (transformStyle && transformStyle != "none") { 1909 return true; 1910 } 1911 return false; 1912 }).each(function() { 1913 var style = $(this).css("transform"); 1914 $(this).css("transform", "none").data('transform-style', style); 1915 }); 1916 } 1917 1918 this.restoreTransformCss = function() { 1919 $(this.params.mainContainer) 1920 .parents() 1921 .filter(function() { 1922 return $(this).data("transform-style"); 1923 }).each(function() { 1924 $(this).css("transform", $(this).data("transform-style")).data("transform-style", ""); 1925 }); 1926 } 1927 1928 this.initPopupLayer = function() { 1929 var self = this; 1930 var position = $("#simple_login_layer").parent().css("position"); 1931 if (!$("#simple_login_layer").length || position == "fixed" || position == "relative" || position == "absolute") { 1932 $("#simple_login_layer").remove(); 1933 $("#simple_login").remove(); 1934 $(self.params.mainContainer).append("<div id='simple_login_layer'></div><div id='simple_login'><div id='temp_popup_container'></div></div>"); 1935 $("#simple_login_layer").on("click", function() { 1936 self.close(); 1937 }); 1938 } 1939 1940 self.removeTransformCss(); 1941 1942 $("#simple_login_layer") 1943 .css("position", "fixed") 1944 .css("top", "0") 1945 .css("left", "0") 1946 .css("right", "0") 1947 .css("bottom", "0"); 1948 1949 $("#simple_login_layer").fadeTo(500, 0.8); 1950 }; 1951 1952 this.openPopup = function() { 1953 var self = this; 1954 self.initPopupLayer(); 1955 if (!$(self.currentContainer).html()) { 1956 self.load(function() { 1957 if ($(self.currentContainer).html()) { 1958 self.resizePopup(); 1959 } else { 1960 self.closePopup(); 1961 } 1962 }, "#temp_popup_container"); 1963 } else { 1964 self.hideWarning(); 1965 self.resizePopup(); 1966 } 1967 }; 1968 1969 this.resizePopup = function() { 1970 $("#simple_login").show(); 1971 $("#simple_login").css("height", $(this.currentContainer).outerHeight() + 20); 1972 $("#simple_login").css("top", window.innerHeight / 2 - ($("#simple_login").outerHeight() ? $("#simple_login").outerHeight() : $("#simple_login").height()) / 2); 1973 $("#simple_login").css("left", $(window).width() / 2 - ($("#simple_login").outerWidth() ? $("#simple_login").outerWidth() : $("#simple_login").width()) / 2); 1974 }; 1975 1976 this.closePopup = function() { 1977 var self = this; 1978 $("#simple_login_layer").fadeOut(500, function() { 1979 $(this).hide().css("opacity", "1"); 1980 self.restoreTransformCss(); 1981 }); 1982 $("#simple_login").fadeOut(500, function() { 1983 $(this).hide(); 1984 }); 1985 }; 1986 1987 this.openFlat = function() { 1988 var self = this; 1989 if (!$(self.currentContainer).length) { 1990 $("<div id='temp_flat_container'><img src='" + self.params.additionalPath + self.resources.loading + "'></div>").insertBefore(self.params.loginBoxBefore); 1991 self.load("#temp_flat_container"); 1992 } 1993 self.hideWarning(); 1994 $(self.currentContainer).show(); 1995 }; 1996 1997 this.closeFlat = function() { 1998 $(this.currentContainer).hide(); 1999 }; 2000 2001 this.isOpened = function() { 2002 return $("#temp_flat_container *:visible").length ? true : false; 2003 }; 2004 2005 this.open = function() { 2006 var self = this; 2007 /*if (self.getParam("logged")) { 2008 return; 2009 }*/ 2010 if (self.params.loginBoxBefore) { 2011 self.openFlat(); 2012 } else { 2013 self.openPopup(); 2014 } 2015 }; 2016 2017 this.close = function() { 2018 var self = this; 2019 if (self.params.loginBoxBefore) { 2020 self.closeFlat(); 2021 } else { 2022 self.closePopup(); 2023 } 2024 }; 2025 2026 this.login = function() { 2027 var self = this; 2028 this.reload(function() { 2029 if (!self.hasError()) { 2030 self.closePopup(); 2031 self.closeFlat(); 2032 if (self.simplecheckout) { 2033 self.simplecheckout.saveStep(); 2034 self.simplecheckout.ignorePost(); 2035 self.simplecheckout.reloadAll(); 2036 } else { 2037 window.location.reload(); 2038 } 2039 } else { 2040 self.resizePopup(); 2041 } 2042 }); 2043 }; 2044 2045 this.detectEnterAndLogin = function($target, e) { 2046 if (e.keyCode == 13) { 2047 this.login(); 2048 } 2049 }; 2050 } 2051 2052 SimplecheckoutLogin.prototype = inherit(SimplecheckoutBlock.prototype); 2053 2054 function SimplecheckoutComment(container, route) { 2055 this.currentContainer = container; 2056 this.currentRoute = route; 2057 2058 this.init = function() { 2059 var self = this;
2060 SimplecheckoutBlock.prototype.init.apply(self, arguments); 2061 }; 2062 } 2063 2064 SimplecheckoutComment.prototype = inherit(SimplecheckoutBlock.prototype); 2065 2066 function SimplecheckoutShipping(container, route) { 2067 this.currentContainer = container; 2068 this.currentRoute = route; 2069 2070 this.init = function() { 2071 var self = this; 2072 SimplecheckoutBlock.prototype.init.apply(self, arguments); 2073 }; 2074 2075 this.validate = function(silent) { 2076 var self = this; 2077 var result = true; 2078 var $currentContainer = $(self.params.mainContainer).find(self.currentContainer + ":visible"); 2079 var deferred = $.Deferred(); 2080 2081 if (typeof silent === "undefined") { 2082 silent = false; 2083 } 2084 2085 if ($currentContainer.length && !$currentContainer.find("input:checked").length && !$currentContainer.find("option:selected").length) { 2086 if (!silent) { 2087 self.displayWarning(); 2088 } 2089 result = false; 2090 } 2091 2092 var fieldsValidator = SimplecheckoutBlock.prototype.validate.apply(self, arguments).then(function(validatorResult) { 2093 result = result && validatorResult; 2094 }); 2095 2096 var backendValidator = $.ajax({ 2097 url: "index.php?" + self.params.additionalParams + "route=" + self.currentRoute + "/validate", 2098 data: $currentContainer.find("input:checked,option:selected"), 2099 type: "POST", 2100 dataType: "json", 2101 success: function(json) { 2102 if (json['error']) { 2103 $("<div/>") 2104 .addClass("alert alert-danger simplecheckout-warning-block simplecheckout-validator-result") 2105 .html(json['error']) 2106 .insertBefore($currentContainer.find(".simplecheckout-block-content")); 2107 2108 result = false; 2109 2110 return; 2111 } else { 2112 $currentContainer.find(".simplecheckout-validator-result").remove(); 2113 } 2114 }, 2115 }); 2116 2117 $.when.apply($, [fieldsValidator, backendValidator]).then(function () { 2118 deferred.resolve(result); 2119 }); 2120 2121 return deferred.promise(); 2122 }; 2123 } 2124 2125 SimplecheckoutShipping.prototype = inherit(SimplecheckoutBlock.prototype); 2126 2127 function SimplecheckoutPayment(container, route) { 2128 this.currentContainer = container; 2129 this.currentRoute = route; 2130 2131 this.init = function() { 2132 var self = this; 2133 SimplecheckoutBlock.prototype.init.apply(self, arguments); 2134 }; 2135 2136 this.validate = function(silent) { 2137 var self = this; 2138 var result = true; 2139 var $currentContainer = $(self.params.mainContainer).find(self.currentContainer + ":visible"); 2140 var deferred = $.Deferred(); 2141 2142 if (typeof silent === "undefined") { 2143 silent = false; 2144 } 2145 2146 if ($currentContainer.length && !$currentContainer.find("input:checked").length && !$currentContainer.find("option:selected").length) { 2147 if (!silent) { 2148 self.displayWarning(); 2149 } 2150 result = false; 2151 } 2152 2153 SimplecheckoutBlock.prototype.validate.apply(self, arguments).then(function(validatorResult) { 2154 deferred.resolve(result && validatorResult); 2155 }); 2156 2157 return deferred.promise(); 2158 }; 2159 } 2160 2161 SimplecheckoutPayment.prototype = inherit(SimplecheckoutBlock.prototype); 2162 2163 function SimplecheckoutForm(container, route) { 2164 this.currentContainer = container; 2165 this.currentRoute = route; 2166 2167 this.init = function() { 2168 var self = this;
2169 SimplecheckoutBlock.prototype.init.apply(self, arguments); 2170 }; 2171 2172 this.validate = function(silent) { 2173 var self = this; 2174 var result = true; 2175 var deferred = $.Deferred(); 2176 2177 if (typeof silent === "undefined") { 2178 silent = false; 2179 } 2180 2181 SimplecheckoutBlock.prototype.validate.apply(self, arguments).then(function(validatorResult) { 2182 deferred.resolve(result && validatorResult); 2183 }); 2184 2185 return deferred.promise(); 2186 }; 2187 2188 this.reloadAll = function($element) { 2189 var self = this; 2190 window.setTimeout(function() { 2191 if (!$element.attr("data-valid") || $element.attr("data-valid") == "true") { 2192 SimplecheckoutBlock.prototype.reloadAll.apply(self, arguments); 2193 } 2194 }, 0); 2195 2196 }; 2197 } 2198 2199 SimplecheckoutForm.prototype = inherit(SimplecheckoutBlock.prototype); 2200 2201 (function() { 2202 var inputs = {}; 2203 2204 $(document).on("keyup", "input[type=text],input[type=email],input[type=tel],textarea", function(e) { 2205 if ($.inArray(e.keyCode,[9,13,16,17,18,19,20,27,35,36,37,38,39,40,91,93,224]) > -1) { 2206 return true; 2207 } 2208 2209 var inputId = $(this).attr("id"); 2210 2211 if (inputId) { 2212 var currentTime = new Date().getTime(); 2213 2214 var delta = 500; 2215 2216 if (typeof inputs[inputId] !== 'undefined') { 2217 if ((currentTime - inputs[inputId].time) < 10000) { 2218 delta = (currentTime - inputs[inputId].time + inputs[inputId].delta) / 2; 2219 } 2220 } 2221 2222 inputs[inputId] = { 2223 time: currentTime, 2224 delta: delta 2225 }; 2226 } 2227 2228 var deltaSum = 0; 2229 var deltaCounter = 0; 2230 2231 for (var i in inputs) { 2232 if (!inputs.hasOwnProperty(i)) continue; 2233 2234 deltaSum += inputs[i].delta; 2235 deltaCounter++; 2236 } 2237 2238 if (deltaCounter) { 2239 var speed = deltaSum / deltaCounter; 2240 2241 if (speed > 500) { 2242 window.simpleTypingSpeed = speed; 2243 } else { 2244 window.simpleTypingSpeed = 500; 2245 } 2246 } 2247 }); 2248 })(); 2249})(jQuery || $);
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.