1/******/ (function(modules) { // webpackBootstrap 2/******/ // The module cache 3/******/ var installedModules = {}; 4 5/******/ // The require function 6/******/ function __webpack_require__(moduleId) { 7 8/******/ // Check if module is in cache 9/******/ if(installedModules[moduleId]) 10/******/ return installedModules[moduleId].exports; 11 12/******/ // Create a new module (and put it into the cache) 13/******/ var module = installedModules[moduleId] = { 14/******/ exports: {}, 15/******/ id: moduleId, 16/******/ loaded: false 17/******/ }; 18 19/******/ // Execute the module function 20/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); 21 22/******/ // Flag the module as loaded 23/******/ module.loaded = true; 24 25/******/ // Return the exports of the module 26/******/ return module.exports; 27/******/ } 28 29 30/******/ // expose the modules object (__webpack_modules__) 31/******/ __webpack_require__.m = modules; 32 33/******/ // expose the module cache 34/******/ __webpack_require__.c = installedModules; 35 36/******/ // __webpack_public_path__ 37/******/ __webpack_require__.p = ""; 38 39/******/ // Load entry module and return exports 40/******/ return __webpack_require__(0); 41/******/ }) 42/************************************************************************/ 43/******/ ({ 44 45/***/ 0: 46/***/ (function(module, exports, __webpack_require__) { 47 48 __webpack_require__(314); 49 __webpack_require__(315); 50 __webpack_require__(273); 51 __webpack_require__(316); 52 __webpack_require__(317); 53 __webpack_require__(318); 54 __webpack_require__(319); 55 __webpack_require__(320); 56 __webpack_require__(321); 57 58 __webpack_require__(322); 59 __webpack_require__(284); 60 __webpack_require__(324); 61 __webpack_require__(289); 62 __webpack_require__(281); 63 __webpack_require__(326); 64 __webpack_require__(329); 65 __webpack_require__(330); 66 __webpack_require__(279); 67 __webpack_require__(271); 68 __webpack_require__(269); 69 __webpack_require__(274); 70 __webpack_require__(291); 71 __webpack_require__(331); 72 __webpack_require__(299); 73 74 75/***/ }), 76 77/***/ 269: 78/***/ (function(module, exports, __webpack_require__) { 79 80 var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/*! 81 * jQuery Cookie Plugin v1.4.0 82 * https://github.com/carhartl/jquery-cookie 83 * 84 * Copyright 2013 Klaus Hartl 85 * Released under the MIT license 86 */ 87 (function (factory) { 88 if (true) { 89 // AMD. Register as anonymous module. 90 !(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__(270)], __WEBPACK_AMD_DEFINE_FACTORY__ = (factory), __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? (__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); 91 } else { 92 // Browser globals. 93 factory(jQuery); 94 } 95 }(function ($) { 96 97 var pluses = /\+/g; 98 99 function encode(s) { 100 return config.raw ? s : encodeURIComponent(s); 101 } 102 103 function decode(s) { 104 return config.raw ? s : decodeURIComponent(s); 105 } 106 107 function stringifyCookieValue(value) { 108 return encode(config.json ? JSON.stringify(value) : String(value)); 109 } 110 111 function parseCookieValue(s) { 112 if (s.indexOf('"') === 0) { 113 // This is a quoted cookie as according to RFC2068, unescape... 114 s = s.slice(1, -1).replace(/\\"/g, '"').replace(/\\\\/g, '\\'); 115 } 116 117 try { 118 // Replace server-side written pluses with spaces. 119 // If we can't decode the cookie, ignore it, it's unusable. 120 s = decodeURIComponent(s.replace(pluses, ' ')); 121 } catch(e) { 122 return; 123 } 124 125 try { 126 // If we can't parse the cookie, ignore it, it's unusable. 127 return config.json ? JSON.parse(s) : s; 128 } catch(e) {} 129 } 130 131 function read(s, converter) { 132 var value = config.raw ? s : parseCookieValue(s); 133 return $.isFunction(converter) ? converter(value) : value; 134 } 135 136 var config = $.cookie = function (key, value, options) { 137 138 // Write 139 if (value !== undefined && !$.isFunction(value)) { 140 options = $.extend({}, config.defaults, options); 141 142 if (typeof options.expires === 'number') { 143 var days = options.expires, t = options.expires = new Date(); 144 t.setDate(t.getDate() + days); 145 } 146 147 return (document.cookie = [ 148 encode(key), '=', stringifyCookieValue(value), 149 options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE 150 options.path ? '; path=' + options.path : '', 151 options.domain ? '; domain=' + options.domain : '', 152 options.secure ? '; secure' : '' 153 ].join('')); 154 } 155 156 // Read 157 158 var result = key ? undefined : {}; 159 160 // To prevent the for loop in the first place assign an empty array 161 // in case there are no cookies at all. Also prevents odd result when 162 // calling $.cookie(). 163 var cookies = document.cookie ? document.cookie.split('; ') : []; 164 165 for (var i = 0, l = cookies.length; i < l; i++) { 166 var parts = cookies[i].split('='); 167 var name = decode(parts.shift()); 168 var cookie = parts.join('='); 169 170 if (key && key === name) { 171 // If second argument (value) is a function it's a converter... 172 result = read(cookie, value); 173 break; 174 } 175 176 // Prevent storing a cookie that we couldn't decode. 177 if (!key && (cookie = read(cookie)) !== undefined) { 178 result[name] = cookie; 179 } 180 } 181 182 return result; 183 }; 184 185 config.defaults = {}; 186 187 $.removeCookie = function (key, options) { 188 if ($.cookie(key) === undefined) { 189 return false;
190 } 191 192 // Must not alter options, thus extending a fresh object... 193 $.cookie(key, '', $.extend({}, options, { expires: -1 })); 194 return !$.cookie(key); 195 }; 196 197 })); 198 199 200/***/ }), 201 202/***/ 270: 203/***/ (function(module, exports) { 204 205 module.exports = jQuery; 206 207/***/ }), 208 209/***/ 271: 210/***/ (function(module, exports) { 211 212 /*! 213 * jQuery Validation Plugin 1.11.1 214 * 215 * http://bassistance.de/jquery-plugins/jquery-plugin-validation/ 216 * http://docs.jquery.com/Plugins/Validation 217 * 218 * Copyright 2013 Jörn Zaefferer 219 * Released under the MIT license: 220 * http://www.opensource.org/licenses/mit-license.php 221 */ 222 223 (function($) { 224 225 $.extend($.fn, { 226 // http://docs.jquery.com/Plugins/Validation/validate 227 validate: function( options ) { 228 229 // if nothing is selected, return nothing; can't chain anyway 230 if ( !this.length ) { 231 if ( options && options.debug && window.console ) { 232 console.warn( "Nothing selected, can't validate, returning nothing." ); 233 } 234 return; 235 } 236 237 // check if a validator for this form was already created 238 var validator = $.data( this[0], "validator" ); 239 if ( validator ) { 240 return validator; 241 } 242 243 // Add novalidate tag if HTML5. 244 this.attr( "novalidate", "novalidate" ); 245 246 validator = new $.validator( options, this[0] ); 247 $.data( this[0], "validator", validator ); 248 249 if ( validator.settings.onsubmit ) { 250 251 this.validateDelegate( ":submit", "click", function( event ) { 252 if ( validator.settings.submitHandler ) { 253 validator.submitButton = event.target; 254 } 255 // allow suppressing validation by adding a cancel class to the submit button 256 if ( $(event.target).hasClass("cancel") ) { 257 validator.cancelSubmit = true; 258 } 259 260 // allow suppressing validation by adding the html5 formnovalidate attribute to the submit button 261 if ( $(event.target).attr("formnovalidate") !== undefined ) { 262 validator.cancelSubmit = true; 263 } 264 }); 265 266 // validate the form on submit 267 this.submit( function( event ) { 268 if ( validator.settings.debug ) { 269 // prevent form submit to be able to see console output 270 event.preventDefault(); 271 } 272 function handle() { 273 var hidden; 274 if ( validator.settings.submitHandler ) { 275 if ( validator.submitButton ) { 276 // insert a hidden input as a replacement for the missing submit button 277 hidden = $("<input type='hidden'/>").attr("name", validator.submitButton.name).val( $(validator.submitButton).val() ).appendTo(validator.currentForm); 278 } 279 validator.settings.submitHandler.call( validator, validator.currentForm, event ); 280 if ( validator.submitButton ) { 281 // and clean up afterwards; thanks to no-block-scope, hidden can be referenced 282 hidden.remove(); 283 } 284 return false; 285 } 286 return true; 287 } 288 289 // prevent submit for invalid forms or custom submit handlers 290 if ( validator.cancelSubmit ) { 291 validator.cancelSubmit = false; 292 return handle(); 293 } 294 if ( validator.form() ) { 295 if ( validator.pendingRequest ) { 296 validator.formSubmitted = true; 297 return false; 298 } 299 return handle(); 300 } else { 301 validator.focusInvalid(); 302 return false; 303 } 304 }); 305 } 306 307 return validator; 308 }, 309 // http://docs.jquery.com/Plugins/Validation/valid 310 valid: function() { 311 if ( $(this[0]).is("form")) { 312 return this.validate().form(); 313 } else { 314 var valid = true; 315 var validator = $(this[0].form).validate(); 316 this.each(function() { 317 valid = valid && validator.element(this); 318 }); 319 return valid; 320 } 321 }, 322 // attributes: space seperated list of attributes to retrieve and remove 323 removeAttrs: function( attributes ) { 324 var result = {}, 325 $element = this; 326 $.each(attributes.split(/\s/), function( index, value ) { 327 result[value] = $element.attr(value); 328 $element.removeAttr(value); 329 }); 330 return result; 331 }, 332 // http://docs.jquery.com/Plugins/Validation/rules 333 rules: function( command, argument ) { 334 var element = this[0]; 335 336 if ( command ) { 337 var settings = $.data(element.form, "validator").settings; 338 var staticRules = settings.rules; 339 var existingRules = $.validator.staticRules(element); 340 switch(command) { 341 case "add": 342 $.extend(existingRules, $.validator.normalizeRule(argument)); 343 // remove messages from rules, but allow them to be set separetely 344 delete existingRules.messages; 345 staticRules[element.name] = existingRules; 346 if ( argument.messages ) { 347 settings.messages[element.name] = $.extend( settings.messages[element.name], argument.messages ); 348 } 349 break; 350 case "remove": 351 if ( !argument ) { 352 delete staticRules[element.name]; 353 return existingRules; 354 } 355 var filtered = {}; 356 $.each(argument.split(/\s/), function( index, method ) { 357 filtered[method] = existingRules[method]; 358 delete existingRules[method]; 359 }); 360 return filtered; 361 } 362 } 363 364 var data = $.validator.normalizeRules( 365 $.extend( 366 {}, 367 $.validator.classRules(element), 368 $.validator.attributeRules(element), 369 $.validator.dataRules(element), 370 $.validator.staticRules(element) 371 ), element); 372 373 // make sure required is at front 374 if ( data.required ) { 375 var param = data.required; 376 delete data.required; 377 data = $.extend({required: param}, data); 378 } 379 380 return data; 381 } 382 }); 383 384 // Custom selectors 385 $.extend($.expr[":"], {
386 // http://docs.jquery.com/Plugins/Validation/blank 387 blank: function( a ) { return !$.trim("" + $(a).val()); }, 388 // http://docs.jquery.com/Plugins/Validation/filled 389 filled: function( a ) { return !!$.trim("" + $(a).val()); }, 390 // http://docs.jquery.com/Plugins/Validation/unchecked 391 unchecked: function( a ) { return !$(a).prop("checked"); } 392 }); 393 394 // constructor for validator 395 $.validator = function( options, form ) { 396 this.settings = $.extend( true, {}, $.validator.defaults, options ); 397 this.currentForm = form; 398 this.init(); 399 }; 400 401 $.validator.format = function( source, params ) { 402 if ( arguments.length === 1 ) { 403 return function() { 404 var args = $.makeArray(arguments); 405 args.unshift(source); 406 return $.validator.format.apply( this, args ); 407 }; 408 } 409 if ( arguments.length > 2 && params.constructor !== Array ) { 410 params = $.makeArray(arguments).slice(1); 411 } 412 if ( params.constructor !== Array ) { 413 params = [ params ]; 414 } 415 $.each(params, function( i, n ) { 416 source = source.replace( new RegExp("\\{" + i + "\\}", "g"), function() { 417 return n; 418 }); 419 }); 420 return source; 421 }; 422 423 $.extend($.validator, { 424 425 defaults: { 426 messages: {}, 427 groups: {}, 428 rules: {}, 429 errorClass: "error", 430 validClass: "valid", 431 errorElement: "label", 432 focusInvalid: true, 433 errorContainer: $([]), 434 errorLabelContainer: $([]), 435 onsubmit: true, 436 ignore: ":hidden", 437 ignoreTitle: false, 438 onfocusin: function( element, event ) { 439 this.lastActive = element; 440 441 // hide error label and remove error class on focus if enabled 442 if ( this.settings.focusCleanup && !this.blockFocusCleanup ) { 443 if ( this.settings.unhighlight ) { 444 this.settings.unhighlight.call( this, element, this.settings.errorClass, this.settings.validClass ); 445 } 446 this.addWrapper(this.errorsFor(element)).hide(); 447 } 448 }, 449 onfocusout: function( element, event ) { 450 if ( !this.checkable(element) && (element.name in this.submitted || !this.optional(element)) ) { 451 this.element(element); 452 } 453 }, 454 onkeyup: function( element, event ) { 455 if ( event.which === 9 && this.elementValue(element) === "" ) { 456 return; 457 } else if ( element.name in this.submitted || element === this.lastElement ) { 458 this.element(element); 459 } 460 }, 461 onclick: function( element, event ) { 462 // click on selects, radiobuttons and checkboxes 463 if ( element.name in this.submitted ) { 464 this.element(element); 465 } 466 // or option elements, check parent select in that case 467 else if ( element.parentNode.name in this.submitted ) { 468 this.element(element.parentNode); 469 } 470 }, 471 highlight: function( element, errorClass, validClass ) { 472 if ( element.type === "radio" ) { 473 this.findByName(element.name).addClass(errorClass).removeClass(validClass); 474 } else { 475 $(element).addClass(errorClass).removeClass(validClass); 476 } 477 }, 478 unhighlight: function( element, errorClass, validClass ) { 479 if ( element.type === "radio" ) { 480 this.findByName(element.name).removeClass(errorClass).addClass(validClass); 481 } else { 482 $(element).removeClass(errorClass).addClass(validClass); 483 } 484 } 485 }, 486 487 // http://docs.jquery.com/Plugins/Validation/Validator/setDefaults 488 setDefaults: function( settings ) { 489 $.extend( $.validator.defaults, settings ); 490 }, 491 492 messages: { 493 required: "This field is required.", 494 remote: "Please fix this field.", 495 email: "Please enter a valid email address.", 496 url: "Please enter a valid URL.", 497 date: "Please enter a valid date.", 498 dateISO: "Please enter a valid date (ISO).", 499 number: "Please enter a valid number.", 500 digits: "Please enter only digits.", 501 creditcard: "Please enter a valid credit card number.", 502 equalTo: "Please enter the same value again.", 503 maxlength: $.validator.format("Please enter no more than {0} characters."), 504 minlength: $.validator.format("Please enter at least {0} characters."), 505 rangelength: $.validator.format("Please enter a value between {0} and {1} characters long."), 506 range: $.validator.format("Please enter a value between {0} and {1}."), 507 max: $.validator.format("Please enter a value less than or equal to {0}."), 508 min: $.validator.format("Please enter a value greater than or equal to {0}.") 509 }, 510 511 autoCreateRanges: false, 512 513 prototype: { 514 515 init: function() { 516 this.labelContainer = $(this.settings.errorLabelContainer); 517 this.errorContext = this.labelContainer.length && this.labelContainer || $(this.currentForm); 518 this.containers = $(this.settings.errorContainer).add( this.settings.errorLabelContainer ); 519 this.submitted = {}; 520 this.valueCache = {}; 521 this.pendingRequest = 0; 522 this.pending = {}; 523 this.invalid = {}; 524 this.reset(); 525 526 var groups = (this.groups = {}); 527 $.each(this.settings.groups, function( key, value ) { 528 if ( typeof value === "string" ) { 529 value = value.split(/\s/); 530 } 531 $.each(value, function( index, name ) { 532 groups[name] = key; 533 }); 534 }); 535 var rules = this.settings.rules; 536 $.each(rules, function( key, value ) { 537 rules[key] = $.validator.normalizeRule(value); 538 }); 539 540 function delegate(event) {
541 var validator = $.data(this[0].form, "validator"), 542 eventType = "on" + event.type.replace(/^validate/, ""); 543 if ( validator.settings[eventType] ) { 544 validator.settings[eventType].call(validator, this[0], event); 545 } 546 } 547 $(this.currentForm) 548 .validateDelegate(":text, [type='password'], [type='file'], select, textarea, " + 549 "[type='number'], [type='search'] ,[type='tel'], [type='url'], " + 550 "[type='email'], [type='datetime'], [type='date'], [type='month'], " + 551 "[type='week'], [type='time'], [type='datetime-local'], " + 552 "[type='range'], [type='color'] ", 553 "focusin focusout keyup", delegate) 554 .validateDelegate("[type='radio'], [type='checkbox'], select, option", "click", delegate); 555 556 if ( this.settings.invalidHandler ) { 557 $(this.currentForm).bind("invalid-form.validate", this.settings.invalidHandler); 558 } 559 }, 560 561 // http://docs.jquery.com/Plugins/Validation/Validator/form 562 form: function() { 563 this.checkForm(); 564 $.extend(this.submitted, this.errorMap); 565 this.invalid = $.extend({}, this.errorMap); 566 if ( !this.valid() ) { 567 $(this.currentForm).triggerHandler("invalid-form", [this]); 568 } 569 this.showErrors(); 570 return this.valid(); 571 }, 572 573 checkForm: function() { 574 this.prepareForm(); 575 for ( var i = 0, elements = (this.currentElements = this.elements()); elements[i]; i++ ) { 576 this.check( elements[i] ); 577 } 578 return this.valid(); 579 }, 580 581 // http://docs.jquery.com/Plugins/Validation/Validator/element 582 element: function( element ) { 583 element = this.validationTargetFor( this.clean( element ) ); 584 this.lastElement = element; 585 this.prepareElement( element ); 586 this.currentElements = $(element); 587 var result = this.check( element ) !== false; 588 if ( result ) { 589 delete this.invalid[element.name]; 590 } else { 591 this.invalid[element.name] = true; 592 } 593 if ( !this.numberOfInvalids() ) { 594 // Hide error containers on last error 595 this.toHide = this.toHide.add( this.containers ); 596 } 597 this.showErrors(); 598 return result; 599 }, 600 601 // http://docs.jquery.com/Plugins/Validation/Validator/showErrors 602 showErrors: function( errors ) { 603 if ( errors ) { 604 // add items to error list and map 605 $.extend( this.errorMap, errors ); 606 this.errorList = []; 607 for ( var name in errors ) { 608 this.errorList.push({ 609 message: errors[name], 610 element: this.findByName(name)[0] 611 }); 612 } 613 // remove items from success list 614 this.successList = $.grep( this.successList, function( element ) { 615 return !(element.name in errors); 616 }); 617 } 618 if ( this.settings.showErrors ) { 619 this.settings.showErrors.call( this, this.errorMap, this.errorList ); 620 } else { 621 this.defaultShowErrors(); 622 } 623 }, 624 625 // http://docs.jquery.com/Plugins/Validation/Validator/resetForm 626 resetForm: function() { 627 if ( $.fn.resetForm ) { 628 $(this.currentForm).resetForm(); 629 } 630 this.submitted = {}; 631 this.lastElement = null; 632 this.prepareForm(); 633 this.hideErrors(); 634 this.elements().removeClass( this.settings.errorClass ).removeData( "previousValue" ); 635 }, 636 637 numberOfInvalids: function() { 638 return this.objectLength(this.invalid); 639 }, 640 641 objectLength: function( obj ) { 642 var count = 0; 643 for ( var i in obj ) { 644 count++; 645 } 646 return count; 647 }, 648 649 hideErrors: function() { 650 this.addWrapper( this.toHide ).hide(); 651 }, 652 653 valid: function() { 654 return this.size() === 0; 655 }, 656 657 size: function() { 658 return this.errorList.length; 659 }, 660 661 focusInvalid: function() { 662 if ( this.settings.focusInvalid ) { 663 try { 664 $(this.findLastActive() || this.errorList.length && this.errorList[0].element || []) 665 .filter(":visible") 666 .focus() 667 // manually trigger focusin event; without it, focusin handler isn't called, findLastActive won't have anything to find 668 .trigger("focusin"); 669 } catch(e) { 670 // ignore IE throwing errors when focusing hidden elements 671 } 672 } 673 }, 674 675 findLastActive: function() { 676 var lastActive = this.lastActive; 677 return lastActive && $.grep(this.errorList, function( n ) { 678 return n.element.name === lastActive.name; 679 }).length === 1 && lastActive; 680 }, 681 682 elements: function() {
683 var validator = this, 684 rulesCache = {}; 685 686 // select all valid inputs inside the form (no submit or reset buttons) 687 return $(this.currentForm) 688 .find("input, select, textarea") 689 .not(":submit, :reset, :image, [disabled]") 690 .not( this.settings.ignore ) 691 .filter(function() { 692 if ( !this.name && validator.settings.debug && window.console ) { 693 console.error( "%o has no name assigned", this); 694 } 695 696 // select only the first element for each name, and only those with rules specified 697 if ( this.name in rulesCache || !validator.objectLength($(this).rules()) ) { 698 return false; 699 } 700 701 rulesCache[this.name] = true; 702 return true; 703 }); 704 }, 705 706 clean: function( selector ) { 707 return $(selector)[0]; 708 }, 709 710 errors: function() { 711 var errorClass = this.settings.errorClass.replace(" ", "."); 712 return $(this.settings.errorElement + "." + errorClass, this.errorContext); 713 }, 714 715 reset: function() { 716 this.successList = []; 717 this.errorList = []; 718 this.errorMap = {}; 719 this.toShow = $([]); 720 this.toHide = $([]); 721 this.currentElements = $([]); 722 }, 723 724 prepareForm: function() { 725 this.reset(); 726 this.toHide = this.errors().add( this.containers ); 727 }, 728 729 prepareElement: function( element ) { 730 this.reset(); 731 this.toHide = this.errorsFor(element); 732 }, 733 734 elementValue: function( element ) { 735 var type = $(element).attr("type"), 736 val = $(element).val(); 737 738 if ( type === "radio" || type === "checkbox" ) { 739 return $("input[name='" + $(element).attr("name") + "']:checked").val(); 740 } 741 742 if ( typeof val === "string" ) { 743 return val.replace(/\r/g, ""); 744 } 745 return val; 746 }, 747 748 check: function( element ) { 749 element = this.validationTargetFor( this.clean( element ) ); 750 751 var rules = $(element).rules(); 752 var dependencyMismatch = false; 753 var val = this.elementValue(element); 754 var result; 755 756 for (var method in rules ) { 757 var rule = { method: method, parameters: rules[method] }; 758 try { 759 760 result = $.validator.methods[method].call( this, val, element, rule.parameters ); 761 762 // if a method indicates that the field is optional and therefore valid, 763 // don't mark it as valid when there are no other rules 764 if ( result === "dependency-mismatch" ) { 765 dependencyMismatch = true; 766 continue; 767 } 768 dependencyMismatch = false; 769 770 if ( result === "pending" ) { 771 this.toHide = this.toHide.not( this.errorsFor(element) ); 772 return; 773 } 774 775 if ( !result ) { 776 this.formatAndAdd( element, rule ); 777 return false; 778 } 779 } catch(e) { 780 if ( this.settings.debug && window.console ) { 781 console.log( "Exception occurred when checking element " + element.id + ", check the '" + rule.method + "' method.", e ); 782 } 783 throw e; 784 } 785 } 786 if ( dependencyMismatch ) { 787 return; 788 } 789 if ( this.objectLength(rules) ) { 790 this.successList.push(element); 791 } 792 return true; 793 }, 794 795 // return the custom message for the given element and validation method 796 // specified in the element's HTML5 data attribute 797 customDataMessage: function( element, method ) { 798 return $(element).data("msg-" + method.toLowerCase()) || (element.attributes && $(element).attr("data-msg-" + method.toLowerCase())); 799 }, 800 801 // return the custom message for the given element name and validation method 802 customMessage: function( name, method ) { 803 var m = this.settings.messages[name]; 804 return m && (m.constructor === String ? m : m[method]); 805 }, 806 807 // return the first defined argument, allowing empty strings 808 findDefined: function() { 809 for(var i = 0; i < arguments.length; i++) { 810 if ( arguments[i] !== undefined ) { 811 return arguments[i]; 812 } 813 } 814 return undefined; 815 }, 816 817 defaultMessage: function( element, method ) { 818 return this.findDefined( 819 this.customMessage( element.name, method ), 820 this.customDataMessage( element, method ), 821 // title is never undefined, so handle empty string as undefined 822 !this.settings.ignoreTitle && element.title || undefined, 823 $.validator.messages[method], 824 "<strong>Warning: No message defined for " + element.name + "</strong>" 825 ); 826 }, 827 828 formatAndAdd: function( element, rule ) { 829 var message = this.defaultMessage( element, rule.method ), 830 theregex = /\$?\{(\d+)\}/g; 831 if ( typeof message === "function" ) { 832 message = message.call(this, rule.parameters, element); 833 } else if (theregex.test(message)) { 834 message = $.validator.format(message.replace(theregex, "{$1}"), rule.parameters); 835 } 836 this.errorList.push({ 837 message: message, 838 element: element 839 }); 840 841 this.errorMap[element.name] = message; 842 this.submitted[element.name] = message; 843 }, 844 845 addWrapper: function( toToggle ) { 846 if ( this.settings.wrapper ) { 847 toToggle = toToggle.add( toToggle.parent( this.settings.wrapper ) ); 848 } 849 return toToggle; 850 }, 851 852 defaultShowErrors: function() { 853 var i, elements; 854 for ( i = 0; this.errorList[i]; i++ ) { 855 var error = this.errorList[i]; 856 if ( this.settings.highlight ) { 857 this.settings.highlight.call( this, error.element, this.settings.errorClass, this.settings.val
857idClass ); 858 } 859 this.showLabel( error.element, error.message ); 860 } 861 if ( this.errorList.length ) { 862 this.toShow = this.toShow.add( this.containers ); 863 } 864 if ( this.settings.success ) { 865 for ( i = 0; this.successList[i]; i++ ) { 866 this.showLabel( this.successList[i] ); 867 } 868 } 869 if ( this.settings.unhighlight ) { 870 for ( i = 0, elements = this.validElements(); elements[i]; i++ ) { 871 this.settings.unhighlight.call( this, elements[i], this.settings.errorClass, this.settings.validClass ); 872 } 873 } 874 this.toHide = this.toHide.not( this.toShow ); 875 this.hideErrors(); 876 this.addWrapper( this.toShow ).show(); 877 }, 878 879 validElements: function() { 880 return this.currentElements.not(this.invalidElements()); 881 }, 882 883 invalidElements: function() { 884 return $(this.errorList).map(function() { 885 return this.element; 886 }); 887 }, 888 889 showLabel: function( element, message ) { 890 var label = this.errorsFor( element ); 891 if ( label.length ) { 892 // refresh error/success class 893 label.removeClass( this.settings.validClass ).addClass( this.settings.errorClass ); 894 // replace message on existing label 895 label.html(message); 896 } else { 897 // create label 898 label = $("<" + this.settings.errorElement + ">") 899 .attr("for", this.idOrName(element)) 900 .addClass(this.settings.errorClass) 901 .html(message || ""); 902 if ( this.settings.wrapper ) { 903 // make sure the element is visible, even in IE 904 // actually showing the wrapped element is handled elsewhere 905 label = label.hide().show().wrap("<" + this.settings.wrapper + "/>").parent(); 906 } 907 if ( !this.labelContainer.append(label).length ) { 908 if ( this.settings.errorPlacement ) { 909 this.settings.errorPlacement(label, $(element) ); 910 } else { 911 label.insertAfter(element); 912 } 913 } 914 } 915 if ( !message && this.settings.success ) { 916 label.text(""); 917 if ( typeof this.settings.success === "string" ) { 918 label.addClass( this.settings.success ); 919 } else { 920 this.settings.success( label, element ); 921 } 922 } 923 this.toShow = this.toShow.add(label); 924 }, 925 926 errorsFor: function( element ) { 927 var name = this.idOrName(element); 928 return this.errors().filter(function() { 929 return $(this).attr("for") === name; 930 }); 931 }, 932 933 idOrName: function( element ) { 934 return this.groups[element.name] || (this.checkable(element) ? element.name : element.id || element.name); 935 }, 936 937 validationTargetFor: function( element ) { 938 // if radio/checkbox, validate first element in group instead 939 if ( this.checkable(element) ) { 940 element = this.findByName( element.name ).not(this.settings.ignore)[0]; 941 } 942 return element; 943 }, 944 945 checkable: function( element ) { 946 return (/radio|checkbox/i).test(element.type); 947 }, 948 949 findByName: function( name ) { 950 return $(this.currentForm).find("[name='" + name + "']"); 951 }, 952 953 getLength: function( value, element ) { 954 switch( element.nodeName.toLowerCase() ) { 955 case "select": 956 return $("option:selected", element).length; 957 case "input": 958 if ( this.checkable( element) ) { 959 return this.findByName(element.name).filter(":checked").length; 960 } 961 } 962 return value.length; 963 }, 964 965 depend: function( param, element ) { 966 return this.dependTypes[typeof param] ? this.dependTypes[typeof param](param, element) : true; 967 }, 968 969 dependTypes: { 970 "boolean": function( param, element ) { 971 return param; 972 }, 973 "string": function( param, element ) { 974 return !!$(param, element.form).length; 975 }, 976 "function": function( param, element ) { 977 return param(element); 978 } 979 }, 980 981 optional: function( element ) { 982 var val = this.elementValue(element); 983 return !$.validator.methods.required.call(this, val, element) && "dependency-mismatch"; 984 }, 985 986 startRequest: function( element ) { 987 if ( !this.pending[element.name] ) { 988 this.pendingRequest++; 989 this.pending[element.name] = true; 990 } 991 }, 992 993 stopRequest: function( element, valid ) { 994 this.pendingRequest--; 995 // sometimes synchronization fails, make sure pendingRequest is never < 0 996 if ( this.pendingRequest < 0 ) { 997 this.pendingRequest = 0; 998 } 999 delete this.pending[element.name]; 1000 if ( valid && this.pendingRequest === 0 && this.formSubmitted && this.form() ) { 1001 $(this.currentForm).submit(); 1002 this.formSubmitted = false;
1003 } else if (!valid && this.pendingRequest === 0 && this.formSubmitted) { 1004 $(this.currentForm).triggerHandler("invalid-form", [this]); 1005 this.formSubmitted = false; 1006 } 1007 }, 1008 1009 previousValue: function( element ) { 1010 return $.data(element, "previousValue") || $.data(element, "previousValue", { 1011 old: null, 1012 valid: true, 1013 message: this.defaultMessage( element, "remote" ) 1014 }); 1015 } 1016 1017 }, 1018 1019 classRuleSettings: { 1020 required: {required: true}, 1021 email: {email: true}, 1022 url: {url: true}, 1023 date: {date: true}, 1024 dateISO: {dateISO: true}, 1025 number: {number: true}, 1026 digits: {digits: true}, 1027 creditcard: {creditcard: true} 1028 }, 1029 1030 addClassRules: function( className, rules ) { 1031 if ( className.constructor === String ) { 1032 this.classRuleSettings[className] = rules; 1033 } else { 1034 $.extend(this.classRuleSettings, className); 1035 } 1036 }, 1037 1038 classRules: function( element ) { 1039 var rules = {}; 1040 var classes = $(element).attr("class"); 1041 if ( classes ) { 1042 $.each(classes.split(" "), function() { 1043 if ( this in $.validator.classRuleSettings ) { 1044 $.extend(rules, $.validator.classRuleSettings[this]); 1045 } 1046 }); 1047 } 1048 return rules; 1049 }, 1050 1051 attributeRules: function( element ) { 1052 var rules = {}; 1053 var $element = $(element); 1054 var type = $element[0].getAttribute("type"); 1055 1056 for (var method in $.validator.methods) { 1057 var value; 1058 1059 // support for <input required> in both html5 and older browsers 1060 if ( method === "required" ) { 1061 value = $element.get(0).getAttribute(method); 1062 // Some browsers return an empty string for the required attribute 1063 // and non-HTML5 browsers might have required="" markup 1064 if ( value === "" ) { 1065 value = true; 1066 } 1067 // force non-HTML5 browsers to return bool 1068 value = !!value; 1069 } else { 1070 value = $element.attr(method); 1071 } 1072 1073 // convert the value to a number for number inputs, and for text for backwards compability 1074 // allows type="date" and others to be compared as strings 1075 if ( /min|max/.test( method ) && ( type === null || /number|range|text/.test( type ) ) ) { 1076 value = Number(value); 1077 } 1078 1079 if ( value ) { 1080 rules[method] = value; 1081 } else if ( type === method && type !== 'range' ) { 1082 // exception: the jquery validate 'range' method 1083 // does not test for the html5 'range' type 1084 rules[method] = true; 1085 } 1086 } 1087 1088 // maxlength may be returned as -1, 2147483647 (IE) and 524288 (safari) for text inputs 1089 if ( rules.maxlength && /-1|2147483647|524288/.test(rules.maxlength) ) { 1090 delete rules.maxlength; 1091 } 1092 1093 return rules; 1094 }, 1095 1096 dataRules: function( element ) { 1097 var method, value, 1098 rules = {}, $element = $(element); 1099 for (method in $.validator.methods) { 1100 value = $element.data("rule-" + method.toLowerCase()); 1101 if ( value !== undefined ) { 1102 rules[method] = value; 1103 } 1104 } 1105 return rules; 1106 }, 1107 1108 staticRules: function( element ) { 1109 var rules = {}; 1110 var validator = $.data(element.form, "validator"); 1111 if ( validator.settings.rules ) { 1112 rules = $.validator.normalizeRule(validator.settings.rules[element.name]) || {}; 1113 } 1114 return rules; 1115 }, 1116 1117 normalizeRules: function( rules, element ) { 1118 // handle dependency check 1119 $.each(rules, function( prop, val ) { 1120 // ignore rule when param is explicitly false, eg. required:false 1121 if ( val === false ) { 1122 delete rules[prop]; 1123 return; 1124 } 1125 if ( val.param || val.depends ) { 1126 var keepRule = true; 1127 switch (typeof val.depends) { 1128 case "string": 1129 keepRule = !!$(val.depends, element.form).length; 1130 break; 1131 case "function": 1132 keepRule = val.depends.call(element, element); 1133 break; 1134 } 1135 if ( keepRule ) { 1136 rules[prop] = val.param !== undefined ? val.param : true; 1137 } else { 1138 delete rules[prop]; 1139 } 1140 } 1141 }); 1142 1143 // evaluate parameters 1144 $.each(rules, function( rule, parameter ) { 1145 rules[rule] = $.isFunction(parameter) ? parameter(element) : parameter; 1146 }); 1147 1148 // clean number parameters 1149 $.each(['minlength', 'maxlength'], function() { 1150 if ( rules[this] ) { 1151 rules[this] = Number(rules[this]); 1152 } 1153 }); 1154 $.each(['rangelength', 'range'], function() { 1155 var parts; 1156 if ( rules[this] ) { 1157 if ( $.isArray(rules[this]) ) { 1158 rules[this] = [Number(rules[this][0]), Number(rules[this][1])]; 1159 } else if ( typeof rules[this] === "string" ) { 1160 parts = rules[this].split(/[\s,]+/); 1161 rules[this] = [Number(parts[0]), Number(parts[1])]; 1162 } 1163 } 1164 }); 1165 1166 if ( $.validator.autoCreateRanges ) { 1167 // auto-create ranges 1168 if ( rules.min && rules.max ) { 1169 rules.range = [rules.min, rules.max]; 1170 delete rules.min; 1171 delete rules.max; 1172 } 1173 if ( rules.minlength && rules.maxlength ) { 1174 rules.rangelength = [rules.minlength, rules.maxlength]; 1175 delete rules.minlength; 1176 delete rules.maxlength; 1177 } 1178 } 1179 1180 return rules; 1181 }, 1182
vendor: 4,967 bytes, lines 1183-1263
1183 // Converts a simple string to a {string: true} rule, e.g., "required" to {required:true} 1184 normalizeRule: function( data ) { 1185 if ( typeof data === "string" ) { 1186 var transformed = {}; 1187 $.each(data.split(/\s/), function() { 1188 transformed[this] = true; 1189 }); 1190 data = transformed; 1191 } 1192 return data; 1193 }, 1194 1195 // http://docs.jquery.com/Plugins/Validation/Validator/addMethod 1196 addMethod: function( name, method, message ) { 1197 $.validator.methods[name] = method; 1198 $.validator.messages[name] = message !== undefined ? message : $.validator.messages[name]; 1199 if ( method.length < 3 ) { 1200 $.validator.addClassRules(name, $.validator.normalizeRule(name)); 1201 } 1202 }, 1203 1204 methods: { 1205 1206 // http://docs.jquery.com/Plugins/Validation/Methods/required 1207 required: function( value, element, param ) { 1208 // check if dependency is met 1209 if ( !this.depend(param, element) ) { 1210 return "dependency-mismatch"; 1211 } 1212 if ( element.nodeName.toLowerCase() === "select" ) { 1213 // could be an array for select-multiple or a string, both are fine this way 1214 var val = $(element).val(); 1215 return val && val.length > 0; 1216 } 1217 if ( this.checkable(element) ) { 1218 return this.getLength(value, element) > 0; 1219 } 1220 return $.trim(value).length > 0; 1221 }, 1222 1223 // http://docs.jquery.com/Plugins/Validation/Methods/email 1224 email: function( value, element ) { 1225 // contributed by Scott Gonzalez: http://projects.scottsplayground.com/email_address_validation/ 1226 return this.optional(element) || /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$/i.test(value); 1227 }, 1228 1229 // http://docs.jquery.com/Plugins/Validation/Methods/url 1230 url: function( value, element ) { 1231 // contributed by Scott Gonzalez: http://projects.scottsplayground.com/iri/ 1232 return this.optional(element) || /^(https?|s?ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i.test(value); 1233 }, 1234 1235 // http://docs.jquery.com/Plugins/Validation/Methods/date 1236 date: function( value, element ) { 1237 return this.optional(element) || !/Invalid|NaN/.test(new Date(value).toString()); 1238 }, 1239 1240 // http://docs.jquery.com/Plugins/Validation/Methods/dateISO 1241 dateISO: function( value, element ) { 1242 return this.optional(element) || /^\d{4}[\/\-]\d{1,2}[\/\-]\d{1,2}$/.test(value); 1243 }, 1244 1245 // http://docs.jquery.com/Plugins/Validation/Methods/number 1246 number: function( value, element ) { 1247 return this.optional(element) || /^-?(?:\d+|\d{1,3}(?:,\d{3})+)?(?:\.\d+)?$/.test(value); 1248 }, 1249 1250 // http://docs.jquery.com/Plugins/Validation/Methods/digits 1251 digits: function( value, element ) { 1252 return this.optional(element) || /^\d+$/.test(value); 1253 }, 1254 1255 // http://docs.jquery.com/Plugins/Validation/Methods/creditcard 1256 // based on http://en.wikipedia.org/wiki/Luhn 1257 creditcard: function( value, element ) { 1258 if ( this.optional(element) ) { 1259 return "dependency-mismatch"; 1260 } 1261 // accept only spaces, digits and dashes 1262 if ( /[^0-9 \-]+/.test(value) ) { 1263 return false;
1264 } 1265 var nCheck = 0, 1266 nDigit = 0, 1267 bEven = false; 1268 1269 value = value.replace(/\D/g, ""); 1270 1271 for (var n = value.length - 1; n >= 0; n--) { 1272 var cDigit = value.charAt(n); 1273 nDigit = parseInt(cDigit, 10); 1274 if ( bEven ) { 1275 if ( (nDigit *= 2) > 9 ) { 1276 nDigit -= 9; 1277 } 1278 } 1279 nCheck += nDigit; 1280 bEven = !bEven; 1281 } 1282 1283 return (nCheck % 10) === 0; 1284 }, 1285 1286 // http://docs.jquery.com/Plugins/Validation/Methods/minlength 1287 minlength: function( value, element, param ) { 1288 var length = $.isArray( value ) ? value.length : this.getLength($.trim(value), element); 1289 return this.optional(element) || length >= param; 1290 }, 1291 1292 // http://docs.jquery.com/Plugins/Validation/Methods/maxlength 1293 maxlength: function( value, element, param ) { 1294 var length = $.isArray( value ) ? value.length : this.getLength($.trim(value), element); 1295 return this.optional(element) || length <= param; 1296 }, 1297 1298 // http://docs.jquery.com/Plugins/Validation/Methods/rangelength 1299 rangelength: function( value, element, param ) { 1300 var length = $.isArray( value ) ? value.length : this.getLength($.trim(value), element); 1301 return this.optional(element) || ( length >= param[0] && length <= param[1] ); 1302 }, 1303 1304 // http://docs.jquery.com/Plugins/Validation/Methods/min 1305 min: function( value, element, param ) { 1306 return this.optional(element) || value >= param; 1307 }, 1308 1309 // http://docs.jquery.com/Plugins/Validation/Methods/max 1310 max: function( value, element, param ) { 1311 return this.optional(element) || value <= param; 1312 }, 1313 1314 // http://docs.jquery.com/Plugins/Validation/Methods/range 1315 range: function( value, element, param ) { 1316 return this.optional(element) || ( value >= param[0] && value <= param[1] ); 1317 }, 1318 1319 // http://docs.jquery.com/Plugins/Validation/Methods/equalTo 1320 equalTo: function( value, element, param ) { 1321 // bind to the blur event of the target in order to revalidate whenever the target field is updated 1322 // TODO find a way to bind the event just once, avoiding the unbind-rebind overhead 1323 var target = $(param); 1324 if ( this.settings.onfocusout ) { 1325 target.unbind(".validate-equalTo").bind("blur.validate-equalTo", function() { 1326 $(element).valid(); 1327 }); 1328 } 1329 return value === target.val(); 1330 }, 1331 1332 // http://docs.jquery.com/Plugins/Validation/Methods/remote 1333 remote: function( value, element, param ) { 1334 if ( this.optional(element) ) { 1335 return "dependency-mismatch"; 1336 } 1337 1338 var previous = this.previousValue(element); 1339 if (!this.settings.messages[element.name] ) { 1340 this.settings.messages[element.name] = {}; 1341 } 1342 previous.originalMessage = this.settings.messages[element.name].remote; 1343 this.settings.messages[element.name].remote = previous.message; 1344 1345 param = typeof param === "string" && {url:param} || param; 1346 1347 if ( previous.old === value ) { 1348 return previous.valid; 1349 } 1350 1351 previous.old = value; 1352 var validator = this; 1353 this.startRequest(element); 1354 var data = {}; 1355 data[element.name] = value; 1356 $.ajax($.extend(true, { 1357 url: param, 1358 mode: "abort", 1359 port: "validate" + element.name, 1360 dataType: "json", 1361 data: data, 1362 success: function( response ) { 1363 validator.settings.messages[element.name].remote = previous.originalMessage; 1364 var valid = response === true || response === "true"; 1365 if ( valid ) { 1366 var submitted = validator.formSubmitted; 1367 validator.prepareElement(element); 1368 validator.formSubmitted = submitted; 1369 validator.successList.push(element); 1370 delete validator.invalid[element.name]; 1371 validator.showErrors(); 1372 } else { 1373 var errors = {}; 1374 var message = response || validator.defaultMessage( element, "remote" ); 1375 errors[element.name] = previous.message = $.isFunction(message) ? message(value) : message; 1376 validator.invalid[element.name] = true; 1377 validator.showErrors(errors); 1378 } 1379 previous.valid = valid; 1380 validator.stopRequest(element, valid); 1381 } 1382 }, param)); 1383 return "pending"; 1384 } 1385 1386 } 1387 1388 }); 1389 1390 // deprecated, use $.validator.format instead 1391 $.format = $.validator.format; 1392 1393 }(jQuery)); 1394 1395 // ajax mode: abort 1396 // usage: $.ajax({ mode: "abort"[, port: "uniqueport"]}); 1397 // if mode:"abort" is used, the previous request on that port (port can be undefined) is aborted via XMLHttpRequest.abort() 1398 (function($) {
1399 var pendingRequests = {}; 1400 // Use a prefilter if available (1.5+) 1401 if ( $.ajaxPrefilter ) { 1402 $.ajaxPrefilter(function( settings, _, xhr ) { 1403 var port = settings.port; 1404 if ( settings.mode === "abort" ) { 1405 if ( pendingRequests[port] ) { 1406 pendingRequests[port].abort(); 1407 } 1408 pendingRequests[port] = xhr; 1409 } 1410 }); 1411 } else { 1412 // Proxy ajax 1413 var ajax = $.ajax; 1414 $.ajax = function( settings ) { 1415 var mode = ( "mode" in settings ? settings : $.ajaxSettings ).mode, 1416 port = ( "port" in settings ? settings : $.ajaxSettings ).port; 1417 if ( mode === "abort" ) { 1418 if ( pendingRequests[port] ) { 1419 pendingRequests[port].abort(); 1420 } 1421 pendingRequests[port] = ajax.apply(this, arguments); 1422 return pendingRequests[port]; 1423 } 1424 return ajax.apply(this, arguments); 1425 }; 1426 } 1427 }(jQuery)); 1428 1429 // provides delegate(type: String, delegate: Selector, handler: Callback) plugin for easier event delegation 1430 // handler is only called when $(event.target).is(delegate), in the scope of the jquery-object for event.target 1431 (function($) { 1432 $.extend($.fn, { 1433 validateDelegate: function( delegate, type, handler ) { 1434 return this.bind(type, function( event ) { 1435 var target = $(event.target); 1436 if ( target.is(delegate) ) { 1437 return handler.apply(target, arguments); 1438 } 1439 }); 1440 } 1441 }); 1442 }(jQuery)); 1443 1444 1445/***/ }), 1446 1447/***/ 273: 1448/***/ (function(module, exports) { 1449 1450 /* ======================================================================== 1451 * Bootstrap: modal.js v3.3.7 1452 * http://getbootstrap.com/javascript/#modals 1453 * ======================================================================== 1454 * Copyright 2011-2016 Twitter, Inc. 1455 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 1456 * ======================================================================== */ 1457 1458 1459 +function ($) { 1460 'use strict'; 1461 1462 // MODAL CLASS DEFINITION 1463 // ====================== 1464 1465 var Modal = function (element, options) { 1466 this.options = options 1467 this.$body = $(document.body) 1468 this.$element = $(element) 1469 this.$dialog = this.$element.find('.modal-dialog') 1470 this.$backdrop = null 1471 this.isShown = null 1472 this.originalBodyPad = null 1473 this.scrollbarWidth = 0 1474 this.ignoreBackdropClick = false 1475 1476 if (this.options.remote) { 1477 this.$element 1478 .find('.modal-content') 1479 .load(this.options.remote, $.proxy(function () { 1480 this.$element.trigger('loaded.bs.modal') 1481 }, this)) 1482 } 1483 } 1484 1485 Modal.VERSION = '3.3.7' 1486 1487 Modal.TRANSITION_DURATION = 300 1488 Modal.BACKDROP_TRANSITION_DURATION = 150 1489 1490 Modal.DEFAULTS = { 1491 backdrop: true, 1492 keyboard: true, 1493 show: true 1494 } 1495 1496 Modal.prototype.toggle = function (_relatedTarget) { 1497 return this.isShown ? this.hide() : this.show(_relatedTarget) 1498 } 1499 1500 Modal.prototype.show = function (_relatedTarget) { 1501 var that = this 1502 var e = $.Event('show.bs.modal', { relatedTarget: _relatedTarget }) 1503 1504 this.$element.trigger(e) 1505 1506 if (this.isShown || e.isDefaultPrevented()) return 1507 1508 this.isShown = true 1509 1510 this.checkScrollbar() 1511 this.setScrollbar() 1512 this.$body.addClass('modal-open') 1513 1514 this.escape() 1515 this.resize() 1516 1517 this.$element.on('click.dismiss.bs.modal', '[data-dismiss="modal"]', $.proxy(this.hide, this)) 1518 1519 this.$dialog.on('mousedown.dismiss.bs.modal', function () { 1520 that.$element.one('mouseup.dismiss.bs.modal', function (e) { 1521 if ($(e.target).is(that.$element)) that.ignoreBackdropClick = true 1522 }) 1523 }) 1524 1525 this.backdrop(function () { 1526 var transition = $.support.transition && that.$element.hasClass('fade') 1527 1528 if (!that.$element.parent().length) { 1529 that.$element.appendTo(that.$body) // don't move modals dom position 1530 } 1531 1532 that.$element 1533 .show() 1534 .scrollTop(0) 1535 1536 that.adjustDialog() 1537 1538 if (transition) { 1539 that.$element[0].offsetWidth // force reflow 1540 } 1541 1542 that.$element.addClass('in') 1543 1544 that.enforceFocus() 1545 1546 var e = $.Event('shown.bs.modal', { relatedTarget: _relatedTarget }) 1547 1548 transition ? 1549 that.$dialog // wait for modal to slide in 1550 .one('bsTransitionEnd', function () { 1551 that.$element.trigger('focus').trigger(e) 1552 }) 1553 .emulateTransitionEnd(Modal.TRANSITION_DURATION) : 1554 that.$element.trigger('focus').trigger(e) 1555 }) 1556 } 1557 1558 Modal.prototype.hide = function (e) { 1559 if (e) e.preventDefault() 1560 1561 e = $.Event('hide.bs.modal') 1562 1563 this.$element.trigger(e) 1564 1565 if (!this.isShown || e.isDefaultPrevented()) return 1566 1567 this.isShown = false 1568 1569 this.escape() 1570 this.resize() 1571 1572 $(document).off('focusin.bs.modal') 1573 1574 this.$element 1575 .removeClass('in') 1576 .off('click.dismiss.bs.modal') 1577 .off('mouseup.dismiss.bs.modal') 1578 1579 this.$dialog.off('mousedown.dismiss.bs.modal') 1580 1581 $.support.transition && this.$element.hasClass('fade') ? 1582 this.$element 1583 .one('bsTransitionEnd', $.proxy(this.hideModal, this)) 1584 .emulateTransitionEnd(Modal.TRANSITION_DURATION) : 1585 this.hideModal() 1586 } 1587 1588 Modal.prototype.enforceFocus = function () { 1589 $(document) 1590 .off('focusin.bs.modal') // guard against infinite focus loop 1591 .on('focusin.bs.modal', $.proxy(function (e) { 1592 if (document !== e.target && 1593 this.$element[0] !== e.target && 1594 !this.$element.has(e.target).length) { 1595 this.$element.trigger('focus') 1596 } 1597 }, this)) 1598 } 1599 1600 Modal.prototype.escape = function () { 1601 if (this.isShown && this.options.keyboard) { 1602 this.$element.on('keydown.dismiss.bs.modal', $.proxy(function (e) {
vendor: 5,872 bytes, lines 1603-1793
1603 e.which == 27 && this.hide() 1604 }, this)) 1605 } else if (!this.isShown) { 1606 this.$element.off('keydown.dismiss.bs.modal') 1607 } 1608 } 1609 1610 Modal.prototype.resize = function () { 1611 if (this.isShown) { 1612 $(window).on('resize.bs.modal', $.proxy(this.handleUpdate, this)) 1613 } else { 1614 $(window).off('resize.bs.modal') 1615 } 1616 } 1617 1618 Modal.prototype.hideModal = function () { 1619 var that = this 1620 this.$element.hide() 1621 this.backdrop(function () { 1622 that.$body.removeClass('modal-open') 1623 that.resetAdjustments() 1624 that.resetScrollbar() 1625 that.$element.trigger('hidden.bs.modal') 1626 }) 1627 } 1628 1629 Modal.prototype.removeBackdrop = function () { 1630 this.$backdrop && this.$backdrop.remove() 1631 this.$backdrop = null 1632 } 1633 1634 Modal.prototype.backdrop = function (callback) { 1635 var that = this 1636 var animate = this.$element.hasClass('fade') ? 'fade' : '' 1637 1638 if (this.isShown && this.options.backdrop) { 1639 var doAnimate = $.support.transition && animate 1640 1641 this.$backdrop = $(document.createElement('div')) 1642 .addClass('modal-backdrop ' + animate) 1643 .appendTo(this.$body) 1644 1645 this.$element.on('click.dismiss.bs.modal', $.proxy(function (e) { 1646 if (this.ignoreBackdropClick) { 1647 this.ignoreBackdropClick = false 1648 return 1649 } 1650 if (e.target !== e.currentTarget) return 1651 this.options.backdrop == 'static' 1652 ? this.$element[0].focus() 1653 : this.hide() 1654 }, this)) 1655 1656 if (doAnimate) this.$backdrop[0].offsetWidth // force reflow 1657 1658 this.$backdrop.addClass('in') 1659 1660 if (!callback) return 1661 1662 doAnimate ? 1663 this.$backdrop 1664 .one('bsTransitionEnd', callback) 1665 .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) : 1666 callback() 1667 1668 } else if (!this.isShown && this.$backdrop) { 1669 this.$backdrop.removeClass('in') 1670 1671 var callbackRemove = function () { 1672 that.removeBackdrop() 1673 callback && callback() 1674 } 1675 $.support.transition && this.$element.hasClass('fade') ? 1676 this.$backdrop 1677 .one('bsTransitionEnd', callbackRemove) 1678 .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) : 1679 callbackRemove() 1680 1681 } else if (callback) { 1682 callback() 1683 } 1684 } 1685 1686 // these following methods are used to handle overflowing modals 1687 1688 Modal.prototype.handleUpdate = function () { 1689 this.adjustDialog() 1690 } 1691 1692 Modal.prototype.adjustDialog = function () { 1693 var modalIsOverflowing = this.$element[0].scrollHeight > document.documentElement.clientHeight 1694 1695 this.$element.css({ 1696 paddingLeft: !this.bodyIsOverflowing && modalIsOverflowing ? this.scrollbarWidth : '', 1697 paddingRight: this.bodyIsOverflowing && !modalIsOverflowing ? this.scrollbarWidth : '' 1698 }) 1699 } 1700 1701 Modal.prototype.resetAdjustments = function () { 1702 this.$element.css({ 1703 paddingLeft: '', 1704 paddingRight: '' 1705 }) 1706 } 1707 1708 Modal.prototype.checkScrollbar = function () { 1709 var fullWindowWidth = window.innerWidth 1710 if (!fullWindowWidth) { // workaround for missing window.innerWidth in IE8 1711 var documentElementRect = document.documentElement.getBoundingClientRect() 1712 fullWindowWidth = documentElementRect.right - Math.abs(documentElementRect.left) 1713 } 1714 this.bodyIsOverflowing = document.body.clientWidth < fullWindowWidth 1715 this.scrollbarWidth = this.measureScrollbar() 1716 } 1717 1718 Modal.prototype.setScrollbar = function () { 1719 var bodyPad = parseInt((this.$body.css('padding-right') || 0), 10) 1720 this.originalBodyPad = document.body.style.paddingRight || '' 1721 if (this.bodyIsOverflowing) this.$body.css('padding-right', bodyPad + this.scrollbarWidth) 1722 } 1723 1724 Modal.prototype.resetScrollbar = function () { 1725 this.$body.css('padding-right', this.originalBodyPad) 1726 } 1727 1728 Modal.prototype.measureScrollbar = function () { // thx walsh 1729 var scrollDiv = document.createElement('div') 1730 scrollDiv.className = 'modal-scrollbar-measure' 1731 this.$body.append(scrollDiv) 1732 var scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth 1733 this.$body[0].removeChild(scrollDiv) 1734 return scrollbarWidth 1735 } 1736 1737 1738 // MODAL PLUGIN DEFINITION 1739 // ======================= 1740 1741 function Plugin(option, _relatedTarget) { 1742 return this.each(function () { 1743 var $this = $(this) 1744 var data = $this.data('bs.modal') 1745 var options = $.extend({}, Modal.DEFAULTS, $this.data(), typeof option == 'object' && option) 1746 1747 if (!data) $this.data('bs.modal', (data = new Modal(this, options))) 1748 if (typeof option == 'string') data[option](_relatedTarget) 1749 else if (options.show) data.show(_relatedTarget) 1750 }) 1751 } 1752 1753 var old = $.fn.modal 1754 1755 $.fn.modal = Plugin 1756 $.fn.modal.Constructor = Modal 1757 1758 1759 // MODAL NO CONFLICT 1760 // ================= 1761 1762 $.fn.modal.noConflict = function () { 1763 $.fn.modal = old 1764 return this 1765 } 1766 1767 1768 // MODAL DATA-API 1769 // ============== 1770 1771 $(document).on('click.bs.modal.data-api', '[data-toggle="modal"]', function (e) { 1772 var $this = $(this) 1773 var href = $this.attr('href') 1774 var $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))) // strip for ie7 1775 var option = $target.data('bs.modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data()) 1776 1777 if ($this.is('a')) e.preventDefault() 1778 1779 $target.one('show.bs.modal', function (showEvent) { 1780 if (showEvent.isDefaultPrevented()) return // only register focus restorer if modal will actually get shown 1781 $target.one('hidden.bs.modal', function () { 1782 $this.is(':visible') && $this.trigger('focus') 1783 }) 1784 }) 1785 Plugin.call($target, option, this) 1786 }) 1787 1788 }(jQuery); 1789 1790 1791/***/ }), 1792 1793/***/ 274:
1794/***/ (function(module, exports) { 1795 1796 (function () { 1797 1798 $.urlParam = function (name) { 1799 return decodeURIComponent((new RegExp('[?|&]' + name + '=' + '([^&;]+?)(&|#|;|$)').exec(location.search) || [, ""])[1].replace(/\+/g, '%20')) || null; 1800 }; 1801 1802 $.validateErrorPlacement = function (error, element) { 1803 var pos = element.position(); 1804 var widthElem = element.outerWidth(); 1805 1806 1807 var errorBoxAddClass, posLeft, errorBoxCss; 1808 1809 if (element.hasClass('error-pos-left')) { 1810 errorBoxAddClass = 'error-box-left'; 1811 errorBoxCss = {}; 1812 } 1813 else { 1814 errorBoxAddClass = ''; 1815 errorBoxCss = {left: pos.left + widthElem}; 1816 } 1817 1818 element.after('<div class="error-box ' + errorBoxAddClass + '"></div>'); 1819 1820 element.next('.error-box').css({ top: pos.top }).css(errorBoxCss) 1821 .append('<div class="error-arrow"></div>').append(error); 1822 1823 }; 1824 1825 $.validateHighlight = function (element, errorClass, validClass) { 1826 $(element).addClass(errorClass); 1827 $(element).next('.error-box').find('.error-arrow').show(); 1828 }; 1829 1830 $.validateUnhighlight = function (element, errorClass, validClass) { 1831 $(element).removeClass(errorClass).addClass(validClass); 1832 $(element).next('.error-box').find('.error-arrow').hide(); 1833 }; 1834 1835 1836 $.fn.wkdaValidate = function (options) { 1837 1838 if (typeof options === "object") { 1839 options = $.extend(true, options, { 1840 errorClass: 'error', 1841 errorElement: 'div', 1842 errorPlacement: $.validateErrorPlacement, 1843 highlight: $.validateHighlight, 1844 unhighlight: $.validateUnhighlight 1845 }); 1846 } 1847 1848 return this.validate(options); 1849 }; 1850 1851 /** 1852 * add wkdaCookieForm to form AFTER select-chains 1853 */ 1854 $.fn.wkdaCookieForm = function(options) { 1855 1856 var cookieOptions = { expires: 730, json: false, path: '/' }; 1857 1858 var $form = $(this); 1859 1860 var defaults = { 1861 load: true 1862 }; 1863 options = $.extend({}, defaults, options); 1864 1865 var prefix = options.pref; 1866 1867 var cookieName = function(name) { 1868 return 'wkdaCF_' + name; 1869 }; 1870 1871 var setFieldValue = function($field, value) { 1872 1873 if ($field.is('select')) { 1874 var valueExists = $field.find("option[value='" + value + "']").length > 0; 1875 if (valueExists) $field.val(value).change(); 1876 } 1877 else if ($field.is(':radio')) { 1878 var $filtered = $field.filter('[value="' + value + '"]'); 1879 $filtered.prop('checked', true); 1880 } 1881 else { 1882 $field.val(value).change(); 1883 } 1884 }; 1885 1886 var getFieldValue = function($field) { 1887 if ($field.is(':radio')) { 1888 return $field.filter(':checked').val(); 1889 } 1890 else { 1891 return $field.val(); 1892 } 1893 }; 1894 1895 var getField = function(fieldName) { 1896 return $form.find("[name='" + prefix + '[' + fieldName + ']' + "']"); 1897 }; 1898 1899 //-- on submit, read form fields and set cookie 1900 this.submit(function() { 1901 var fields = options.fields; 1902 1903 var values = []; 1904 1905 $.each(fields, function(idx, formName) { 1906 var $field = getField(formName); 1907 var value = getFieldValue($field); 1908 1909 values.push(encodeURIComponent(formName) + '=' + encodeURIComponent(value)); 1910 }); 1911 1912 var valuesLine = values.join('|'); 1913 1914 $.cookie(cookieName(prefix), valuesLine, cookieOptions); 1915 1916 }); 1917 1918 1919 //-- cookie set? 1920 var cookie = $.cookie(cookieName(prefix)); 1921 if (options.load && cookie) { 1922 var changeCallbacks = $.Callbacks(); 1923 1924 $.each(cookie.split('|'), function(idx, part) { 1925 var keyValue = part.split('='); 1926 var fieldName = decodeURIComponent(keyValue[0]); 1927 var fieldValue = decodeURIComponent(keyValue[1]); 1928 1929 var $field = getField(fieldName); 1930 1931 var isTarget = $field.data('select-chain-is-target'); 1932 1933 if (isTarget) { 1934 // dont use 'once' 1935 $field.on('select-chain-complete', function(e) { 1936 setFieldValue($field, fieldValue); 1937 }); 1938 } 1939 else { 1940 changeCallbacks.add(function() { 1941 setFieldValue($field, fieldValue); 1942 }); 1943 } 1944 }); 1945 changeCallbacks.fire(); 1946 } 1947 1948 return this; 1949 }; 1950 1951 $.log = function () {
1952 if ('console' in window) console.log.apply(console, arguments); 1953 }; 1954 1955 }()); 1956 1957 1958/***/ }), 1959 1960/***/ 279: 1961/***/ (function(module, exports) { 1962 1963 /** 1964 * patched version remy's selectChain plugin: 1965 * http://remysharp.com/2007/09/18/auto-populate-multiple-select-boxes/ 1966 * 1967 * added 'beforeSend' and 'complete' ajax handler in settings 1968 */ 1969 1970 (function ($) { 1971 $.fn.selectChain = function (options) { 1972 var defaults = { 1973 key: "id", 1974 value: "label", 1975 group: null, 1976 selectFirstOption: true, 1977 beforeSend: function () { 1978 return true; 1979 }, 1980 complete: jQuery.noop 1981 }; 1982 1983 var settings = $.extend({}, defaults, options); 1984 1985 if (!(settings.target instanceof $)) settings.target = $(settings.target); 1986 1987 return this.each(function () { 1988 var $$ = $(this); 1989 1990 settings.target.data('select-chain-is-target',$$); 1991 1992 $$.change(function () { 1993 var data = null; 1994 if (typeof settings.data == 'string') { 1995 data = settings.data + '&' + this.name + '=' + $$.val(); 1996 } else if (typeof settings.data == 'object') { 1997 data = settings.data; 1998 data[this.name] = $$.val(); 1999 } 2000 2001 /** Clears following select elements if value is changed 2002 * prevents requests being made, instead checks position in defined selectchain-group and clears elements manually 2003 **/ 2004 if (typeof settings.group == 'string' && data[this.name].length < 1) { 2005 var resetSelect = $(settings.group).index($$); 2006 $(settings.group).filter(function (i) { 2007 i+2; 2008 return i > resetSelect; 2009 }).html('') 2010 .attr('disabled', true); 2011 2012 return; 2013 } 2014 2015 $.ajax({ 2016 url: settings.url, 2017 data: data, 2018 type: (settings.type || 'get'), 2019 dataType: 'json', 2020 beforeSend: settings.beforeSend, 2021 complete: function() { 2022 settings.complete(); 2023 }, 2024 success: function (j) { 2025 settings.target.empty(); 2026 2027 var options = [], i = 0, o = null; 2028 2029 for (i = 0; i < j.length; i++) { 2030 // required to get around IE bug (http://support.microsoft.com/?scid=kb%3Ben-us%3B276228) 2031 o = document.createElement("OPTION"); 2032 o.value = typeof j[i] == 'object' ? j[i][settings.key] : j[i]; 2033 o.text = typeof j[i] == 'object' ? j[i][settings.value] : j[i]; 2034 settings.target.get(0).options[i] = o; 2035 } 2036 2037 //select the first option if we have only one option to select from 2038 var selector = j.length == 2 ? 'option:eq(1)' : 'option:first'; 2039 2040 // hand control back to browser for a moment 2041 setTimeout(function () { 2042 if(settings.selectFirstOption){ 2043 settings.target 2044 .find(selector) 2045 .attr('selected', 'selected'); 2046 } 2047 settings.target.trigger('change'); 2048 settings.target.trigger('select-chain-complete'); 2049 }, 0); 2050 }, 2051 error: function (xhr, desc, er) { 2052 // add whatever debug you want here. 2053 //alert("an error occurred"); 2054 } 2055 }); 2056 }); 2057 }); 2058 }; 2059 })(jQuery); 2060 2061 2062/***/ }), 2063 2064/***/ 281: 2065/***/ (function(module, exports, __webpack_require__) { 2066 2067 /* WEBPACK VAR INJECTION */(function(global) {module.exports = global["feedbackQuestionnaireModule"] = __webpack_require__(282); 2068 /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }()))) 2069 2070/***/ }), 2071 2072/***/ 282:
2073/***/ (function(module, exports) { 2074 2075 $(function () { 2076 if ($('div.unsubscribe').length !== 0) { 2077 2078 //IE 8 2079 if (document.documentMode !== undefined && document.documentMode === 8) { 2080 $('.video iframe').hide(); 2081 $('.video img').show(); 2082 2083 $('.form .checkboxes label').each(function () { 2084 var label = $(this); 2085 2086 if (label.prev('input').is(':checked')) { 2087 label.removeClass('checkedi'); 2088 label.prev('input').prop('checked', false); 2089 } else { 2090 label.addClass('checkedi'); 2091 label.prev('input').prop('checked', true); 2092 } 2093 }); 2094 2095 $('.form .checkboxes label').on('click', function () { 2096 var label = $(this); 2097 2098 if (label.prev('input').is(':checked')) { 2099 label.removeClass('checkedi'); 2100 label.prev('input').prop('checked', false); 2101 } else { 2102 label.addClass('checkedi'); 2103 label.prev('input').prop('checked', true); 2104 } 2105 label.prev('input').trigger('change'); 2106 }); 2107 2108 $('.receive input:radio').on('change', function () { 2109 var noEmails = $('#form_receive_4').is(':checked'); 2110 2111 $('#form_sale').next('label').toggleClass('checkedi', noEmails); 2112 $('#form_market').next('label').toggleClass('checkedi', noEmails); 2113 $('#form_offer').next('label').toggleClass('checkedi', noEmails); 2114 $('#form_price').next('label').toggleClass('checkedi', noEmails); 2115 }); 2116 } 2117 2118 if ($('#form_receive_4').is(':checked')) { 2119 $('.detailed').removeClass('hide'); 2120 } 2121 2122 $('.receive input:radio').on('change', function () { 2123 $('.error').addClass('hide'); 2124 $('.warning').addClass('hide'); 2125 $('.detailed').toggleClass('hide', !$('#form_receive_4').is(':checked')); 2126 if (!$('.receive input:checked').is(':checked')) { 2127 $('.error').toggleClass('hide', $('#form_receive_4').is(':checked')); 2128 } 2129 $('#form_sale').prop('checked', $('#form_receive_4').is(':checked')); 2130 $('#form_market').prop('checked', $('#form_receive_4').is(':checked')); 2131 $('#form_offer').prop('checked', $('#form_receive_4').is(':checked')); 2132 $('#form_price').prop('checked', $('#form_receive_4').is(':checked')); 2133 }); 2134 2135 $('#form_survey_3').on('click', function () { 2136 $('.detailed').toggleClass('hide', !$(this).is(':checked')); 2137 }); 2138 2139 $('#form_survey input:radio').on('change', function () { 2140 if ($(this).val() === '4') { 2141 $('#form_other').removeClass('hide'); 2142 $('#form_other').focus(); 2143 } else { 2144 $('#form_other').addClass('hide'); 2145 } 2146 }); 2147 2148 $('#form_sale, #form_market, #form_offer, #form_price').on('change', function () { 2149 if (!$('#form_sale').is(':checked') 2150 && !$('#form_market').is(':checked') 2151 && !$('#form_offer').is(':checked') 2152 && !$('#form_price').is(':checked') 2153 && $('.warning').hasClass('hide') 2154 && !$('.detailed').hasClass('hide')) { 2155 2156 $('.warning').removeClass('hide'); 2157 } else { 2158 $('.warning').addClass('hide'); 2159 } 2160 }); 2161 2162 $('.form').submit(function (e) { 2163 var err = false; 2164 2165 if (!$('.receive input:checked').is(':checked') 2166 && !$('#form_receive_4').is(':checked')) { 2167 err = true; 2168 $('.error').removeClass('hide'); 2169 } 2170 2171 if (err) { 2172 e.preventDefault(); 2173 } 2174 }); 2175 2176 var init = false; 2177 2178 $(window).resize(function () { 2179 waitForFinalEvent(function () { 2180 $('.video').height($('.happy-customers').height()); 2181 $('#player').height($('.happy-customers').height()); 2182 }, 300, "media-height", init); 2183 init = true; 2184 }); 2185 2186 $(window).resize(); 2187 } 2188 }); 2189 2190 var waitForFinalEvent = (function () { 2191 var timers = {}; 2192 2193 return function (callback, ms, uniqueId, init) { 2194 if (!uniqueId) { 2195 uniqueId = "media-height"; 2196 } 2197 if (timers[uniqueId]) { 2198 clearInterval(timers[uniqueId]); 2199 clearTimeout(timers[uniqueId]); 2200 } 2201 if (init === false) { 2202 timers[uniqueId] = setInterval(callback, ms); 2203 } else { 2204 timers[uniqueId] = setTimeout(callback, ms); 2205 } 2206 }; 2207 })(); 2208 2209 /* 2210 ============== 2211 feedback Questionnaire Module 2212 ============== 2213 */ 2214 2215 var feedbackQuestionnaireModule = module.exports = function() { 2216
2217 function init() { 2218 if ($.cookie('wkdaLead') === undefined || $.cookie('wkdaLead') == '') { 2219 var url = window.location.href.split('/'); 2220 $.cookie('wkdaLead', url[url.length - 2]); 2221 } 2222 2223 var cookieData = $.cookie('questionnaireSurvey'); 2224 if (cookieData != undefined && cookieData.lead == $.cookie('wkdaLead') && cookieData.questions.length > 0) { 2225 setQuestionnaireStatus('complete'); 2226 return; 2227 } 2228 2229 getQuestionnaire(function (data) { 2230 if (data.questions != undefined && data.questions.length > 0) { 2231 setQuestionnaireStatus('complete'); 2232 } else { 2233 setQuestionnaireStatus('active'); 2234 } 2235 }); 2236 } 2237 2238 var submitQuestionnaire = function (questionnaire) { 2239 var form = new FormData(); 2240 form.append("type", "customerUnsubscribe"); 2241 var data = [{ 2242 "question": 'unsubscribe-survey', 2243 "question_text": questionnaire.find('.question').attr('question-data'), 2244 "answer": questionnaire.find('.answers input[name="answer"]:checked').val(), 2245 "answer_text": questionnaire.find('.answers input[name="answer"]:checked').attr('answer-data') 2246 }]; 2247 2248 form.append("questions", JSON.stringify(data)); 2249 2250 var settings = { 2251 "async": true, 2252 "crossDomain": true, 2253 "url": "/car/questionnaire/save/" + $.cookie('wkdaLead') + "/", 2254 "method": "POST", 2255 "headers": { 2256 "cache-control": "no-cache" 2257 }, 2258 "processData": false, 2259 "contentType": false, 2260 "mimeType": "multipart/form-data", 2261 "data": form 2262 }; 2263 2264 $.cookie('questionnaireSurvey', JSON.stringify({ 2265 lead: $.cookie('wkdaLead'), 2266 questions: data 2267 })); 2268 $.ajax(settings).complete(function (response) { 2269 setQuestionnaireStatus('complete'); 2270 }); 2271 }; 2272 2273 var getQuestionnaire = function (callback) { 2274 var form = new FormData(); 2275 form.append("type", "customerUnsubscribe"); 2276 var settings = { 2277 "async": true, 2278 "crossDomain": true, 2279 "url": "/car/questionnaire/get/" + $.cookie('wkdaLead') + "/", 2280 "method": "POST", 2281 "headers": { 2282 "cache-control": "no-cache" 2283 }, 2284 "processData": false, 2285 "contentType": false, 2286 "mimeType": "multipart/form-data", 2287 "data": form 2288 }; 2289 2290 $.ajax(settings).complete(function (response) { 2291 var responseData = JSON.parse(response.responseText); 2292 callback(responseData); 2293 }); 2294 }; 2295 2296 var setQuestionnaireStatus = function (status) { 2297 var questionnaire = $('.unsubscribe-q-survey'); 2298 2299 questionnaire.data('status', status); 2300 if (status == 'complete') { 2301 hasSeenCustomerSurvey = true; 2302 questionnaire.find('.not-answered').hide(); 2303 questionnaire.find('.answered').show(); 2304 questionnaire.show(); 2305 } else if (status == 'active') { 2306 questionnaire.show(); 2307 } else if (status == 'inactive') { 2308 questionnaire.hide(); 2309 } 2310 }; 2311 2312 $('.unsubscribe-q-survey .not-answered button').on('click', function () { 2313 submitQuestionnaire($(this).parents('.unsubscribe-q-survey')); 2314 }); 2315 2316 $('.unsubscribe-q-survey .not-answered input[type=radio]').on('click', function () { 2317 $(this).parents('.unsubscribe-q-survey').find('button').prop('disabled', false); 2318 }); 2319 2320 return { init: init}; 2321 }(); 2322 2323 2324/***/ }), 2325 2326/***/ 284: 2327/***/ (function(module, exports, __webpack_require__) { 2328 2329 /* WEBPACK VAR INJECTION */(function(global) {module.exports = global["privateSaleModule"] = __webpack_require__(285); 2330 /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }()))) 2331 2332/***/ }), 2333 2334/***/ 285: 2335/***/ (function(module, exports, __webpack_require__) { 2336 2337 var privateSaleModule = module.exports = function () { 2338 var price, minPrice, zipcode, testdriveHours, testdriveHoursContainer, commentsField, commentsCount, phoneNumber,
2338countryCode; 2339 2340 var isInteger = function(val){ 2341 return String(parseInt(val)) === String(val); 2342 } 2343 2344 var showError = function(container, errorName){ 2345 $(container).parent().find('.error-wrapper').show(); 2346 $(container).parent().find('.error.' + errorName + '-error').show(); 2347 }; 2348 2349 var validatePrice = function() { 2350 var currentPrice = $(price).val(); 2351 if(currentPrice.trim() === ''){ 2352 showError(price, 'required'); 2353 return false; 2354 } 2355 if(isNaN(currentPrice)){ 2356 showError(price, 'not-a-number'); 2357 return false; 2358 } 2359 if(!isInteger(currentPrice)){ 2360 showError(price, 'not-an-integer'); 2361 return false; 2362 } 2363 return true; 2364 }; 2365 2366 var validateMinPrice = function() { 2367 var currentMinPrice = $(minPrice).val(); 2368 if(currentMinPrice.trim() === ''){ 2369 return true; 2370 } 2371 if(isNaN(currentMinPrice)){ 2372 showError(minPrice, 'not-a-number'); 2373 return false; 2374 } 2375 if(!isInteger(currentMinPrice)){ 2376 showError(minPrice, 'not-an-integer'); 2377 return false; 2378 } 2379 2380 return true; 2381 }; 2382 2383 var validateZipcode = function(){ 2384 var currentZipcode = $(zipcode).val(); 2385 if(currentZipcode.trim() === ''){ 2386 showError(zipcode, 'required'); 2387 return false; 2388 } 2389 if(isNaN(currentZipcode)){ 2390 showError(zipcode, 'not-a-number'); 2391 return false; 2392 } 2393 //TODO: get locale to check with each country zipcode 2394 //currently implementation is will validate only with Germany's zipcode regex 2395 var digitsRegs = /^\d+$/; 2396 var hasDigitsOnly = digitsRegs.test(currentZipcode); 2397 var germanyZipcodeRegex = /\b((?:0[1-46-9]\d{3})|(?:[1-357-9]\d{4})|(?:[4][0-24-9]\d{3})|(?:[6][013-9]\d{3}))\b/; 2398 var isValidZipcode = germanyZipcodeRegex.test(currentZipcode); 2399 if(!isValidZipcode || !hasDigitsOnly){ 2400 showError(zipcode, 'not-valid-zipcode'); 2401 return false; 2402 } 2403 return true; 2404 }; 2405 2406 var validatePhoneNumber = function(){ 2407 var number = $(phoneNumber).val(); 2408 var code = $(countryCode).val(); 2409 2410 if(number.trim().length === 0 ){ 2411 showError(phoneNumber, 'required'); 2412 return false; 2413 } 2414 if(!isInteger(number)){ 2415 showError(phoneNumber, 'not-a-number'); 2416 return false; 2417 } 2418 return true; 2419 } 2420 2421 var validateTestdriveHours = function() { 2422 var checkedOptions = $(testdriveHours).filter(':checked'); 2423 2424 if (checkedOptions.length === 0) { 2425 showError(testdriveHoursContainer, 'required'); 2426 return false; 2427 } 2428 2429 return true; 2430 }; 2431 2432 var submitForm = function(event){ 2433 var isValidPrice = validatePrice(); 2434 var isValidMinPrice = validateMinPrice(); 2435 var isValidZipcode = validateZipcode(); 2436 var isValidTestdriveHours = validateTestdriveHours(); 2437 // When returning false the submit doesn't happen 2438 return isValidPrice && isValidMinPrice && isValidZipcode && isValidTestdriveHours; 2439 }; 2440 2441 function preventExceedingLimit(limit, event) { 2442 var field = event.target; 2443 2444 var selectionStart = field.selectionStart; 2445 var selectionEnd = field.selectionEnd; 2446 2447 // If no text selected 2448 if (selectionStart === selectionEnd) { 2449 // Prevent printable key if limit has already been reached 2450 // Also prevent Enter key 2451 if (field.value.length >= limit || event.key === 'Enter') { 2452 // Check for backspace and arrow keys because 2453 // some browsers trigger keypress for them 2454 if (event.keyCode !== 8 && (event.keyCode < 37 || event.keyCode > 40)) { 2455 event.preventDefault(); 2456 } 2457 } 2458 } 2459 } 2460 2461 function setOtherReasonFieldCharactersLimit($otherReasonField) { 2462 var limit = 50; 2463 2464 $otherReasonField.on('keypress', preventExceedingLimit.bind(null, limit)); 2465 2466 $otherReasonField.on('keyup change', function(event) { 2467 var field = event.target; 2468 2469 // Save cursor position in text 2470 var selectionStart = field.selectionStart; 2471 var selectionEnd = field.selectionEnd; 2472 2473 // If limit has been exceeded (i.e. by pasting) 2474 // trim the field content to the established limit 2475 if (field.value.length > limit) { 2476 field.value = field.value.slice(0, limit); 2477 } 2478 2479 // Restore cursor position in text 2480 field.selectionStart = selectionStart; 2481 field.selectionEnd = selectionEnd; 2482 }); 2483 } 2484 2485 var setCommentsFieldCharactersLimitAndCount = function($commentsField) { 2486 var limit = 500; 2487 2488 $commentsField.on('keypress', preventExceedingLimit.bind(null, limit)); 2489 $commentsField.on('keyup', fixFieldContentAndUpdateCounter); 2490 $commentsField.on('change', fixFieldContentAndUpdateCounter); 2491 2492 fixFieldContentAndUpdateCounter({ target: $commentsField[0] }); 2493 2494 function fixFieldContentAndUpdateCounter(event) { 2495 var field = event.target; 2496 2497 // Save cursor position in text 2498 var selectionStart = field.selectionStart; 2499 var selectionEnd = field.selectionEnd; 2500 2501 // Remove any emoji from the field value 2502 clearEmojis(field); 2503 2504 // If limit has been exceeded (i.e. by pasting) 2505 // trim the field content to the established limit 2506 if (field.value.length > limit) { 2507 field.value = field.value.slice(0, limit); 2508 } 2509 2510 // Restore cursor position in text 2511 field.selectionStart = selectionStart; 2512 field.selectionEnd = selectionEnd; 2513 2514 // Update counter 2515 commentsCount.html(event.target.value.length); 2516 } 2517 2518 function clearEmojis(field) { 2519 var emojis = /([\uE000-\uF8FF]|\uD83C[\uDC00-\uDFFF]|\uD83D[\uDC00-\uDFFF]|[\u2694-\u2697]|\uD83E[\uDD10-\uDD5D])/g; 2520 2521 field.value = field.value.replace( 2522 new RegExp(emojis), 2523 '' 2524 ); 2525 } 2526 } 2527 2528 var setForm = function(selector){ 2529 price = $(selector + ' input[name="car_private_sale_type[expectedPrice]"]'); 2530 minPrice = $(selector + ' input[name="car_private_sale_type[painPrice]"]'); 2531 zipcode = $(selector + ' input[name="car_private_sale_type[zipCode]"]'); 2532 testdriveHours = $(selector + ' input[name="car_private_sale_type[testdriveHours][]"]'); 2533 testdriveHoursContainer = $(selector + ' .js-test-drive-hours'); 2534 commentsField = $(selector + ' [name="car_private_sale_type[comments]"]'); 2535 commentsCount = $(selector + ' .js-comments-count'); 2536 var submitButton =$(selector + ' .submit-button-row button'); 2537 var hideErrors = function(e){ 2538 var code = e.which; 2539 //dont remove errors on enter or tab 2540 if (code !== 13 && code !== 9) { 2541 $(selector + ' .error-wrapper').hide(); 2542 $(selector + ' .error-wrapper .error').hide(); 2543 } 2544 }; 2545 $(price).keyup(hideErrors); 2546 $(minPrice).keyup(hideErrors); 2547 $(zipcode).keyup(hideErrors); 2548 $(testdriveHours).change(hideErrors); 2549 $(selector).submit(submitForm); 2550 setCommentsFieldCharactersLimitAndCount(commentsField); 2551 }; 2552 2553 var setPhoneUpdateForm = function(parentSelector, url) { 2554 var jParent = $(parentSelector); 2555 var jTriggerButton = jParent.find('.bcn-phone-trigger'); 2556 var jSaveButton = jParent.find('#phone-save-btn'); 2557 var jErrorBox = $(parentSelector).find('.error-box'); 2558 var jOtherError = $(parentSelector).find('.error-box .error'); 2559 var jEmptyError = $(parentSelector).find('.error-box .error-empty'); 2560 2561 jTriggerButton.click(function(event) { 2562 event.preventDefault(); 2563 jParent.addClass('show'); 2564 }); 2565 2566 jSaveButton.click(function(event) { 2567 event.preventDefault(); 2568 2569 var prefix = jParent.find('select[name="prefix"]').val(); 2570 var phone = jParent.find('input[name="phone"]').val(); 2571 2572 jErrorBox.hide(); 2573 jEmptyError.hide(); 2574 jOtherError.hide(); 2575 2576 if (phone.length > 0) { 2577 $.ajax({ 2578 type: 'POST', 2579 url: url, 2580 data: JSON.stringify({ 2581 phone: prefix + '' + phone, 2582 }), 2583 contentType: "application/json", 2584 success: function() { 2585 jParent.find('.phone span').text(prefix + ' ' + phone); 2586 jErrorBox.hide(); 2587 jParent.removeClass('show'); 2588 }, 2589 error: function() { 2590 jErrorBox.show(); 2591 jEmptyError.hide(); 2592 jOtherError.show(); 2593 } 2594 }); 2595 } else { 2596 jErrorBox.show(); 2597 jEmptyError.show(); 2598 jOtherError.hide(); 2599 } 2600 }); 2601 } 2602 2603 var initDashboard = function(selectors) { 2604 var privateSaleDashboard = __webpack_require__(286); 2605 2606 commentsField = $(selectors.comments); 2607 commentsCount = $(selectors.commentsCounter);
2608 otherReasonField = $('[name=otherReasonDetails]'); 2609 2610 privateSaleDashboard.initPopUpForms(); 2611 privateSaleDashboard.initListingPriceForm(); 2612 privateSaleDashboard.initCommentsForm(); 2613 privateSaleDashboard.initTestdriveForm(); 2614 privateSaleDashboard.initOthersForm(); 2615 2616 privateSaleDashboard.initHeaderMenu(); 2617 privateSaleDashboard.initSidebar(); 2618 2619 setCommentsFieldCharactersLimitAndCount(commentsField); 2620 setOtherReasonFieldCharactersLimit(otherReasonField); 2621 }; 2622 2623 var initViewsChart = function(values, chart){ 2624 var tabletMinWidth = 768; 2625 var aggregate = function(data){ 2626 if(data.length < 15){ 2627 return data; 2628 } 2629 2630 var bucketsSize = Math.ceil(data.length / 7); 2631 var buckets = Array(bucketsSize); 2632 for(var index = 0 ; index < data.length ; index++){ 2633 var currentDay = index; 2634 var bucketIndex = Math.floor(currentDay / 7); 2635 if(buckets[bucketIndex]){ 2636 buckets[bucketIndex].views += data[index].views; 2637 }else{ 2638 buckets[bucketIndex] = { 2639 views: data[index].views, 2640 day: data[index].day, 2641 }; 2642 } 2643 } 2644 2645 return buckets; 2646 }; 2647 var getPaddingLeft = function(maxValue){ 2648 var span = $('<span style="font-size: 12px;">'+maxValue+'</span>'); 2649 $(chart).append(span); 2650 return span.width() + 10; 2651 }; 2652 var getMaxValue = function(data){ 2653 var maxValue = 0; 2654 for (var index = 0 ; index < data.length ; index ++ ){ 2655 var views = ~~data[index].views; 2656 if(data[index].views > maxValue ){ 2657 maxValue = views; 2658 } 2659 } 2660 (maxValue % 2) && maxValue++; 2661 if(maxValue === 0 ){ 2662 maxValue = 10; 2663 } 2664 2665 return maxValue; 2666 }; 2667 var getMobileTickValues = function(data){ 2668 var ticks = []; 2669 var maxTicks = 3; 2670 if(data.length <= maxTicks){ 2671 for(var index = 0 ; index < data.length ; index++){ 2672 ticks.push(data[index].day); 2673 } 2674 }else{ 2675 var firstDay = data[0].day; 2676 var lastDay = data[data.length-1].day; 2677 2678 var format = d3.time.format("%d.%m.%y"); 2679 var diff = +format.parse(lastDay) - +format.parse(firstDay); 2680 var midRange = +format.parse(firstDay) + diff/2; 2681 2682 ticks.push(firstDay); 2683 ticks.push(format(new Date(midRange))); 2684 ticks.push(lastDay); 2685 } 2686 2687 return ticks; 2688 }; 2689 // The following function is used to draw/redraw the chart 2690 var drawChart = function(isDesktop){ 2691 if(chart.destroy){ 2692 // Destroy the chart before redrawing 2693 chart = chart.destroy(); 2694 } 2695 opts.axis = isDesktop ? desktopAxisOpts : mobileAxisOpts; 2696 chart = c3.generate(opts); 2697 }; 2698 var $window = $(window); 2699 var aggregatedValues = aggregate(values); 2700 var maxValue = getMaxValue(aggregatedValues); 2701 var isDesktop = $window.width() >= tabletMinWidth; 2702 var paddingLeft = getPaddingLeft(maxValue); 2703 2704 var opts = { 2705 padding: { 2706 left: paddingLeft, 2707 right: 10, 2708 }, 2709 size: { 2710 height: 95, 2711 }, 2712 bindto: chart, 2713 data: { 2714 x: 'date', 2715 xFormat: '%d.%m.%y', 2716 json : aggregatedValues, 2717 keys:{ 2718 x: 'day', 2719 value: ['views'] 2720 } 2721 }, 2722 legend: { 2723 show: false, 2724 }, 2725 tooltip: { 2726 grouped: false, 2727 contents: function (d, defaultTitleFormat, defaultValueFormat, color) { 2728 var value = d[0].value; 2729 2730 return '<div class="views-chart-tooltip">'+value+'</div>'; 2731 }, 2732 position: function (data, tooltipWidth, height, thisElement) { 2733 var containerWidth, x, y; 2734 var element = document.getElementById("views-chart"); 2735 var paddingY = -10; 2736 containerWidth = element.clientWidth; 2737 x = parseInt(thisElement.getAttribute('cx')) + paddingLeft - (tooltipWidth / 2 ); 2738 if (x + tooltipWidth > containerWidth) { 2739 x = containerWidth - tooltipWidth - 2; 2740 } 2741 y = thisElement.getAttribute('cy'); 2742 y = y - height + paddingY; 2743 return { 2744 top: y, 2745 left: x 2746 }; 2747 } 2748 }, 2749 grid: { 2750 y: { 2751 show: true 2752 } 2753 } 2754 }; 2755 var yAxisOpts = { 2756 max: maxValue, 2757 min: 0, 2758 tick: { 2759 values: [0, Math.floor(maxValue / 2), maxValue], 2760 } 2761 }; 2762 var xAxisPadding = 1000 * 60 * 60 * 24; //half a day padding 2763 if(values.length > 30){ 2764 xAxisPadding *= 3; //one and half a day padding 2765 } 2766 var mobileAxisOpts = { 2767 x: { 2768 type: 'timeseries', 2769 tick: { 2770 format: '%d.%m', 2771 values: getMobileTickValues(aggregatedValues), 2772 }, 2773 padding: { 2774 left: xAxisPadding, 2775 right: xAxisPadding 2776 } 2777 }, 2778 y: yAxisOpts 2779 }; 2780 var desktopAxisOpts = { 2781 x: { 2782 type: 'timeseries', 2783 tick: { 2784 format: '%d.%m', 2785 culling: false, 2786 } 2787 }, 2788 y: yAxisOpts 2789 }; 2790 2791 drawChart(isDesktop); 2792 2793 $(document).ready(function() { 2794 $window.resize(function() { 2795 var currentWidth = $window.width(); 2796 if (currentWidth < tabletMinWidth && isDesktop) { 2797 isDesktop = false;
2798 drawChart(isDesktop); 2799 }else if(currentWidth >= tabletMinWidth && !isDesktop){ 2800 isDesktop = true; 2801 drawChart(isDesktop); 2802 } 2803 }); 2804 }); 2805 } 2806 2807 return { 2808 setForm: setForm, 2809 setPhoneUpdateForm: setPhoneUpdateForm, 2810 initDashboard: initDashboard, 2811 initViewsChart: initViewsChart, 2812 }; 2813 }(); 2814 2815 2816/***/ }), 2817 2818/***/ 286: 2819/***/ (function(module, exports, __webpack_require__) { 2820 2821 var DOM = __webpack_require__(287); 2822 var privateSaleApi = __webpack_require__(288); 2823 2824 // Find and store UI elements 2825 var UI = { 2826 popupForms: { 2827 allPopups: $('.js-popup-form'), 2828 showButtons: $('.js-popup-form-show'), 2829 hideButtons: $('.js-popup-form-hide'), 2830 formKeys: ['callMeBack', 'soldMyCar'] 2831 }, 2832 listingPrice: { 2833 loadingMessage: $('#listing-price-loading-message'), 2834 successMessage: $('#listing-price-success-message'), 2835 errorMessage: $('#listing-price-error-message'), 2836 confirmationDialog: $('#listing-price-confirmation-dialog'), 2837 form: $('#listing-price-form'), 2838 button: $('#listing-price-button') 2839 }, 2840 callMeBack: { 2841 loadingMessage: $('.js-call-me-back-loading-message'), 2842 successMessage: $('.js-call-me-back-success-message'), 2843 errorMessage: $('.js-call-me-back-error-message'), 2844 form: $('#call-me-back-form'), 2845 popupId: 'call-me-back-popup-form', 2846 button: $('#call-me-back-form-button') 2847 }, 2848 soldMyCar: { 2849 loadingMessage: $('#sold-my-car-loading-message'), 2850 successMessage: $('#sold-my-car-success-message'), 2851 errorMessage: $('#sold-my-car-error-message'), 2852 form: $('#sold-my-car-form'), 2853 popupId: 'sold-my-car-popup-form', 2854 button: $('#sold-my-car-form-button') 2855 }, 2856 comments: { 2857 form: $('#comments-form'), 2858 button: $('#comments-form-button'), 2859 loadingMessage: $('#comments-loading-message'), 2860 successMessage: $('#comments-success-message'), 2861 errorMessage: $('#comments-error-message') 2862 }, 2863 testdrive: { 2864 loadingMessage: $('#testdrive-loading-message'), 2865 successMessage: $('#testdrive-success-message'), 2866 errorMessage: $('#testdrive-error-message'), 2867 form: $('#testdrive-form') 2868 }, 2869 others: { 2870 form: $('#others-form'), 2871 loadingMessage: $('#others-form-loading-message'), 2872 errorMessage: $('#others-form-error-message'), 2873 successMessage: $('#others-form-success-message') 2874 } 2875 }; 2876 2877 // Data shared throughout the UI 2878 var sharedData = { 2879 maxListingPrice: Number(UI.listingPrice.form[0].price.value), 2880 minimumPrice: Number(UI.others.form[0].minimumPrice.value), 2881 phoneCode: UI.callMeBack.form[0].phoneCode.value, 2882 phoneNumber: Number(UI.callMeBack.form[0].phoneNumber.value) 2883 }; 2884 2885 /** 2886 * Updates UI elements after one of the private sale dashboard forms is submitted 2887 * Expects a valid key and a jqXHR like object (http://api.jquery.com/jQuery.ajax/#jqXHR) 2888 * @param {Object} request 2889 * @param {Function} request.done 2890 * @param {Function} request.fail 2891 * @param {Function} request.always 2892 * @param {string} key A string representing the form. May be one of the following values: 'listingPrice', 'callMeBack', 'soldMyCar', 'comments', 'testdrive', 'others' 2893 */ 2894 function updateUI(request, key) { 2895 var validKeys = Object.keys(UI); 2896 2897 if ( 2898 typeof request !== 'object' || 2899 typeof request.done !== 'function' || 2900 typeof request.fail !== 'function' || 2901 typeof request.always !== 'function' 2902 ) { 2903 throw new TypeError('Argument request must provide done, fail and always methods'); 2904 } 2905 2906 if (validKeys.indexOf(key) < 0) { 2907 throw new TypeError('Argument key must be one of: ' + validKeys.join(', ')); 2908 } 2909 2910 // Get UI elements 2911 var loadingMessage = UI[key].loadingMessage; 2912 var successMessage = UI[key].successMessage; 2913 var errorMessage = UI[key].errorMessage; 2914 var button = UI[key].button; 2915 var form = UI[key].form; 2916 2917 // Show loading message 2918 DOM.showElement(loadingMessage); 2919 2920 // Disable form fields 2921 DOM.disableForm(form); 2922 2923 // Hide success and error message 2924 DOM.hideElement(successMessage); 2925 DOM.hideElement(errorMessage); 2926 2927 request.done(function() { DOM.showElement(successMessage); }); 2928 request.fail(function() { DOM.showElement(errorMessage); }); 2929 2930 // Always hide loading message when request finishes 2931 // and enable form fields 2932 request.always(function() { 2933 DOM.hideElement(loadingMessage); 2934 DOM.enableForm(form); 2935 }); 2936 } 2937 2938 /** 2939 * Similar to updateUI but performs more actions which are specific for popup forms 2940 * Expects a valid key and a jqXHR like object (http://api.jquery.com/jQuery.ajax/#jqXHR) 2941 * @param {Object} request 2942 * @param {Function} request.done 2943 * @param {Function} request.fail 2944 * @param {Function} request.always 2945 * @param {string} key A string representing the form. May be one of the following values: 'callMeBack', 'soldMyCar' 2946 */ 2947 function updateUIForPopupForm(request, key) { 2948 var allPopups = UI.popupForms.allPopups; 2949 var showButtons = UI.popupForms.showButtons; 2950 2951 // store this popup 2952 var popup = allPopups.filter('#' + UI[key].popupId); 2953 2954 // store show buttons for all popups but this one 2955 var otherPopupShowButtons = showButtons.filter(function() { 2956 return $(this).attr('data-target') !== UI[key].popupId; 2957 }); 2958 2959 // Hide popup 2960 DOM.hideElement(popup); 2961 // Disable show buttons 2962 DOM.disableElement(showButtons); 2963 // update messages related to request status 2964 updateUI(request, key); 2965 2966 // If everything went well 2967 request.always(function() { 2968 // enable all the show buttons without exception 2969 DOM.enableElement(showButtons); 2970 }); 2971 } 2972 2973 /** 2974 * Hides any Status messages such as loading, success and error messages 2975 * from previous AJAX requests 2976 * @param {string} key A string representing the form. May be one of the following values: 'listingPrice', 'callMeBack', 'soldMyCar', 'comments', 'testdrive', 'others'
2977 */ 2978 function hideStatusMessages(key) { 2979 [ 2980 UI[key].errorMessage, 2981 UI[key].successMessage, 2982 UI[key].loadingMessage 2983 ].forEach(DOM.hideElement); 2984 } 2985 2986 function hidePopupFormStatusMessages() { 2987 UI.popupForms.formKeys.forEach(function(key) { 2988 hideStatusMessages(key); 2989 }); 2990 } 2991 2992 /** 2993 * Reusable callback for jQuery.validate 2994 * onShowErrors option 2995 */ 2996 function onShowErrors(key) { 2997 return function(errorMap, errorList) { 2998 if (errorList.length > 0) { 2999 hideStatusMessages(key); 3000 } 3001 3002 this.defaultShowErrors(); 3003 }; 3004 } 3005 3006 /** 3007 * Initialize the functionality of the 3008 * Listing Price form 3009 */ 3010 function initListingPriceForm() { 3011 var dialog = UI.listingPrice.confirmationDialog; 3012 var form = UI.listingPrice.form; 3013 3014 var priceField = $(UI.listingPrice.form[0].price); 3015 var minimumPriceField = $(UI.others.form[0].minimumPrice); 3016 3017 // Confirmation Dialog Cancel action 3018 dialog.find('[data-action="cancel"]').on('click', function() { 3019 DOM.hideElement(dialog); 3020 }); 3021 3022 // Confirmation Dialog Confirm action 3023 dialog.find('[data-action="confirm"]').on('click', function() { 3024 var value = Number(priceField.val()); 3025 var request = privateSaleApi.updateListingPrice(value); 3026 3027 // Take care of status messages 3028 updateUI(request, 'listingPrice'); 3029 3030 // Hide dialog 3031 DOM.hideElement(dialog); 3032 3033 // If request succeeds 3034 request.done(function() { 3035 var listingPrice = value; 3036 var minimumPrice = sharedData.minimumPrice; 3037 // Set the price as new max price 3038 sharedData.maxListingPrice = listingPrice; 3039 // and set minimal price if necessary 3040 if (listingPrice < minimumPrice) { 3041 sharedData.minimumPrice = listingPrice; 3042 minimumPriceField.val(listingPrice); 3043 } 3044 }); 3045 }); 3046 3047 // Validate and handle submit of form 3048 form.validate({ 3049 rules: { 3050 price: { 3051 required: true, 3052 number: true, 3053 digits: true, 3054 max: function() { 3055 return sharedData.maxListingPrice; 3056 } 3057 } 3058 }, 3059 submitHandler: function() { 3060 var value = priceField.val(); 3061 dialog.find('[data-value-name="price"]').html(value); 3062 DOM.showElement(dialog); 3063 }, 3064 errorPlacement: function(error, element) { 3065 if (element.attr('name') === 'price') { 3066 return error.insertAfter('#listing-price'); 3067 } 3068 3069 error.insertAfter(element); 3070 }, 3071 showErrors: onShowErrors('listingPrice') 3072 }); 3073 } 3074 3075 /** 3076 * Initialize the functionality of the 3077 * Call Me Back and Sold My Car popup forms 3078 */ 3079 function initPopUpForms() { 3080 var allPopups = UI.popupForms.allPopups; 3081 var showButtons = UI.popupForms.showButtons; 3082 var hideButtons = UI.popupForms.hideButtons; 3083 3084 var callMeBackForm = UI.callMeBack.form; 3085 var soldMyCarForm = UI.soldMyCar.form; 3086 3087 var callMeBackReasons = callMeBackForm.find('[name="reason"]'); 3088 var soldMyCarReasons = soldMyCarForm.find('[name="reason"]'); 3089 3090 // Enable submit button after choosing a reason 3091 callMeBackReasons.on('change', function() { 3092 DOM.enableElement(UI.callMeBack.button); 3093 // Then remove the event listener since the reason 3094 // can be modified but not removed 3095 callMeBackReasons.off('change'); 3096 }); 3097 3098 // Enable submit button after choosing a reason 3099 soldMyCarReasons.on('change', function() { 3100 DOM.enableElement(UI.soldMyCar.button); 3101 // Then remove the event listener since the reason 3102 // can be modified but not removed 3103 soldMyCarReasons.off('change'); 3104 }); 3105 3106 showButtons.on('click', function(event) { 3107 var popupId = $(event.target).attr('data-target'); 3108 var popup = allPopups.filter('#' + popupId); 3109 3110 // Hide any previous existing popup form status message 3111 hidePopupFormStatusMessages(); 3112 3113 DOM.hideElement(allPopups); 3114 DOM.showElement(popup); 3115 }); 3116 3117 hideButtons.on('click', function(event) { 3118 var popupId = $(event.target).attr('data-target'); 3119 var popup = allPopups.filter('#' + popupId); 3120 3121 DOM.hideElement(popup); 3122 }); 3123 3124 // Validate call me back form 3125 callMeBackForm.validate({ 3126 rules: { 3127 reason: 'required',
3128 otherReasonDetails: { 3129 required: { 3130 depends: function() { 3131 return $('#call-me-back-reason-other').is(':checked'); 3132 } 3133 } 3134 }, 3135 phoneNumber: { required: true, digits: true } 3136 }, 3137 submitHandler: function() { 3138 var phoneNumber = Number(DOM.getFieldValue(callMeBackForm, 'phoneNumber')); 3139 var phoneCode = DOM.getFieldValue(callMeBackForm, 'phoneCode'); 3140 var reason = DOM.getFieldValue(callMeBackForm, 'reason'); 3141 var otherReasonDetails = DOM.getFieldValue(callMeBackForm, 'otherReasonDetails'); 3142 3143 var request = privateSaleApi.requestACall(reason, phoneCode, phoneNumber, otherReasonDetails); 3144 3145 updateUIForPopupForm(request, 'callMeBack'); 3146 3147 request.done(function() { 3148 var othersForm = UI.others.form; 3149 3150 sharedData.phoneNumber = phoneNumber; 3151 sharedData.phoneCode = phoneCode; 3152 3153 DOM.setFieldValue(othersForm, 'phoneNumber', phoneNumber); 3154 DOM.setFieldValue(othersForm, 'phoneCode', phoneCode); 3155 }); 3156 }, 3157 errorPlacement: function(error, element) { 3158 var name = element.attr('name'); 3159 3160 if (name === 'reason' || name === 'otherReasonDetails') { 3161 return error.insertAfter('#call-me-back-reason'); 3162 } 3163 3164 if (name === 'phoneNumber') { 3165 return error.insertAfter('#call-me-back-phone'); 3166 } 3167 3168 error.insertAfter(element); 3169 } 3170 }); 3171 3172 // Validate sold my car form 3173 soldMyCarForm.validate({ 3174 rules: { reason: 'required' }, 3175 submitHandler: function() { 3176 var reason = DOM.getFieldValue(soldMyCarForm, 'reason'); 3177 var request = privateSaleApi.notifyCarIsSold(reason); 3178 3179 updateUIForPopupForm(request, 'soldMyCar'); 3180 }, 3181 errorPlacement: function(error, element) { 3182 var name = element.attr('name'); 3183 3184 if (element.attr('name') === 'reason') { 3185 return error.insertAfter('#sold-my-car-reason'); 3186 } 3187 3188 error.insertAfter(element); 3189 } 3190 }); 3191 } 3192 3193 /** 3194 * Initialize the functionality of the 3195 * user menu dropdown from the page header 3196 */ 3197 function initHeaderMenu() { 3198 var $popup = $('#private-sale-login-menu-popup'); 3199 var $trigger = $('#private-sale-login-menu-trigger'); 3200 var $userNamePlaceholder = $('#private-sale-login-menu-user-name'); 3201 var $userEmailPlaceholder = $('#private-sale-login-menu-user-email'); 3202 var userName = $('#private-sale-sidebar-user-name').text(); 3203 var userEmail = $('#private-sale-sidebar-user-email').text(); 3204 3205 // Use this class to make it visible or not in the DOM. 3206 var visibilityClass = 'is-visible'; 3207 3208 // Rely on variable not in DOM to determine 3209 // whether it's visible or not. 3210 var isVisible = false; 3211 3212 // Fill user name and email in the header popup menu 3213 $userNamePlaceholder.html(userName); 3214 $userEmailPlaceholder.html(userEmail); 3215 3216 // Fill user email in the link that triggers the 3217 // header popup menu 3218 $('#private-sale-login-menu-email').html(userEmail); 3219 3220 function showPopup() { 3221 // prevent attaching the listener multiple times 3222 if (!isVisible) { 3223 // make it visible in the DOM 3224 $popup.addClass(visibilityClass); 3225 // attach listener to hidepopup on click body 3226 // notice adding 'clickable' class name to prevent issue on iOS 3227 $('body').addClass('clickable').on('click', hidePopup); 3228 // make it visible in the logic 3229 isVisible = true; 3230 } 3231 }; 3232 3233 function hidePopup() { 3234 if (isVisible) { 3235 // make it not visible in the DOM 3236 $popup.removeClass(visibilityClass); 3237 // detach listener to hidepopup on click body 3238 // notice removing 'clickable' class name which was added to prevent issue on iOS 3239 $('body').removeClass('clickable').off('click', hidePopup); 3240 // ake it not visible in the logic 3241 isVisible = false; 3242 } 3243 } 3244 3245 // This fn hides the main menu of the page on small screens 3246 // This won't work if [data-navigation-menu] is not there 3247 function hidePageMobileMenu() { 3248 $('[data-navigation-menu] > div').addClass('hide'); 3249 } 3250 3251 // Listen click to trigger link. 3252 $trigger.on('click', function(event) { 3253 event.preventDefault(); 3254 // Stop propagation to body so it doesn't hide the popup. 3255 event.stopPropagation(); 3256 // Toggle the popup 3257 if (isVisible) { 3258 hidePopup() 3259 } else { 3260 showPopup(); 3261 } 3262 }); 3263 3264 // Listen click to navigation popup links. 3265 $popup.on('click', 'a', function() { 3266 // Hide popup when navigating 3267 hidePopup(); 3268 // and close mobile menu. 3269 hidePageMobileMenu(); 3270 }); 3271 3272 // Listen click to the popup box. 3273 $popup.on('click', function(event) { 3274 // Stop propagation to body so it doesn't hide the popup. 3275 // This won't affect clicking the links since they have an 3276 // event listener that takes care of hiding the popup. 3277 event.stopPropagation(); 3278 }); 3279 } 3280 3281 /** 3282 * Initialize the functionality 3283 * of the Comments form 3284 */ 3285 function initCommentsForm() { 3286 UI.comments.form.validate({ 3287 rules: { 3288 max: 500 3289 }, 3290 onfocusout: false, 3291 onkeyup: false, 3292 onclik: false, 3293 submitHandler: function() { 3294 var comments = DOM.getFieldValue(UI.comments.form, 'comments'); 3295 var request = privateSaleApi.updateComments(comments); 3296 3297 updateUI(request, 'comments'); 3298 } 3299 }); 3300 } 3301 3302 /** 3303 * Initialize the functionality 3304 * of the Testdrive form 3305 */ 3306 function initTestdriveForm() { 3307 var form = UI.testdrive.form; 3308 3309 form.validate({ 3310 rules: { 3311 'hours': 'required' 3312 }, 3313 errorPlacement: function(error, element) { 3314 var fieldName = element.attr('name'); 3315 3316 if (fieldName === 'hours') { 3317 return error.insertAfter('#testdrive-hours'); 3318 } 3319 3320 error.insertAfter(element); 3321 }, 3322 submitHandler: function() { 3323 var days = DOM.getFieldValue(form, 'days'); 3324 var hours = DOM.getFieldValue(form, 'hours', true); 3325 3326 var request = privateSaleApi.updateTestDriveAvailability(days, hours); 3327 3328 updateUI(request, 'testdrive'); 3329 }, 3330 showErrors: onShowErrors('testdrive') 3331 }) 3332 } 3333
3334 /** 3335 * Initialize the functionality 3336 * of the Others form 3337 */ 3338 function initOthersForm() { 3339 var form = UI.others.form; 3340 3341 form.validate({ 3342 rules: { 3343 phoneNumber: { 3344 required: true, 3345 digits: true 3346 }, 3347 minimumPrice: { 3348 required: false, 3349 number: true, 3350 digits: true, 3351 } 3352 }, 3353 submitHandler: function() { 3354 var phoneNumber = Number(DOM.getFieldValue(form, 'phoneNumber')); 3355 var phoneCode = DOM.getFieldValue(form, 'phoneCode'); 3356 var minimumPrice = Number(DOM.getFieldValue(form, 'minimumPrice')); 3357 3358 var request = privateSaleApi.updateOtherData(phoneCode, phoneNumber, minimumPrice); 3359 3360 request.done(function() { 3361 var callMeBackForm = UI.callMeBack.form; 3362 3363 sharedData.phoneNumber = phoneNumber; 3364 sharedData.phoneCode = phoneCode; 3365 3366 DOM.setFieldValue(callMeBackForm, 'phoneNumber', phoneNumber); 3367 DOM.setFieldValue(callMeBackForm, 'phoneCode', phoneCode); 3368 }); 3369 3370 updateUI(request, 'others'); 3371 }, 3372 errorPlacement: function(error, element) { 3373 if (element.attr('name') === 'phoneNumber') { 3374 return error.insertAfter('#others-phone'); 3375 } 3376 3377 if (element.attr('name') === 'minimumPrice') { 3378 return error.insertAfter('#others-minimum-price'); 3379 } 3380 3381 error.insertAfter(element); 3382 }, 3383 showErrors: onShowErrors('others') 3384 }) 3385 } 3386 3387 /** 3388 * Initialize the functionality 3389 * of the sticky sidebar 3390 */ 3391 function initSidebar() { 3392 // Get the sidebar once 3393 var $sidebar = $('#private-sale-dashboard-sidebar'); 3394 3395 // init the sidebar if it is visible so we 3396 // get the right top offset instead of 0 3397 if ($sidebar.is(':visible')) { 3398 initSidebarFixedBehavior(); 3399 } else { 3400 // Otherwise listen to resize event 3401 $(window).on('resize', onWindowResize); 3402 } 3403 3404 // it updates the sidebar position once 3405 // and listens to window scroll for updating 3406 // the sidebar position again 3407 function initSidebarFixedBehavior() { 3408 var pageBottomMargin; 3409 var pageTopMargin = pageBottomMargin = 20; 3410 3411 // Get its original top offset minus 20px 3412 // so it starts the fixed behavior 20px above 3413 // This is done in order to keep the top margin 3414 var sidebarTopOffset = $sidebar.offset().top - pageTopMargin; 3415 3416 updateSidebar(); 3417 $(window).scroll(updateSidebar); 3418 3419 // it checks whether the window has scrolled 3420 // below the sidebar top edge and based on that 3421 // decide whether it should has a fixed 3422 // position or not 3423 function updateSidebar(event) { 3424 var scrolled = $(window).scrollTop(); 3425 var contentHeight = $('#private-sale-dashboard-content').outerHeight(); 3426 var sidebarHeight = $sidebar.outerHeight(); 3427 3428 if (scrolled > sidebarTopOffset) { 3429 $sidebar.addClass('is-fixed'); 3430 3431 // if has scrolled in such a way that the bottom of the sidebar has reached the 3432 // bottom of the page container 3433 if (scrolled > (sidebarTopOffset + contentHeight - sidebarHeight - pageBottomMargin - pageTopMargin)) { 3434 // Attach the sidebar to the bottom of the main container 3435 $sidebar 3436 .addClass('has-reached-bottom') 3437 .css({ 3438 bottom: (contentHeight - pageTopMargin) * -1 3439 }); 3440 } else { 3441 // Detach sidebar from the bottom of the container 3442 $sidebar 3443 .removeClass('has-reached-bottom') 3444 .css({ bottom: 'auto' }); 3445 } 3446 } else { 3447 $sidebar.removeClass('is-fixed'); 3448 } 3449 } 3450 } 3451 3452 // it checks whether the sidebar has 3453 // become visible after resizing or not 3454 function onWindowResize() { 3455 // if it is visible now, init the behavior 3456 if ($sidebar.is(':visible')) { 3457 initSidebarFixedBehavior(); 3458 // then remove the listener since 3459 // we don't need it anymore 3460 $(window).off('resize', onWindowResize); 3461 } 3462 } 3463 } 3464 3465 module.exports = { 3466 initPopUpForms: initPopUpForms, 3467 initListingPriceForm: initListingPriceForm, 3468 initHeaderMenu: initHeaderMenu, 3469 initCommentsForm: initCommentsForm, 3470 initTestdriveForm: initTestdriveForm, 3471 initOthersForm: initOthersForm, 3472 initSidebar: initSidebar 3473 }; 3474 3475 3476/***/ }), 3477 3478/***/ 287:
3479/***/ (function(module, exports) { 3480 3481 var hiddenClassName = 'hidden'; 3482 3483 /** 3484 * Displays an element by removing the hidden 3485 * class name from its class name list. It expects 3486 * an object with removeClass method (such as a jQuery object). 3487 * @param {Object} element 3488 * @param {Function} element.removeClass 3489 */ 3490 function showElement(element) { 3491 if (typeof element !== 'object' || typeof element.removeClass !== 'function') { 3492 throw new TypeError('Argument element must be an object with removeClass method'); 3493 } 3494 3495 element.removeClass(hiddenClassName); 3496 } 3497 3498 /** 3499 * Displays an element by adding the hidden 3500 * class name from its class name list. It expects 3501 * an object with addClass method (such as a jQuery object). 3502 * @param {Object} element 3503 * @param {Function} element.addClass 3504 */ 3505 function hideElement(element) { 3506 if (typeof element !== 'object' || typeof element.addClass !== 'function') { 3507 throw new TypeError('Argument element must be an object with addClass method'); 3508 } 3509 3510 element.addClass(hiddenClassName); 3511 } 3512 3513 /** 3514 * Disables an element by adding the disabled attribute with 3515 * value 'disbaled'. It expects an object with attr method 3516 * (such as a jQuery object). 3517 * @param {Object} element 3518 * @param {Function} element.attr 3519 */ 3520 function disableElement(element) { 3521 if (typeof element !== 'object' || typeof element.attr !== 'function') { 3522 throw new TypeError('Argument element must be an object with attr method'); 3523 } 3524 3525 element.attr('disabled', 'disabled'); 3526 } 3527 3528 /** 3529 * Enables an element by removing the disabled attribute. 3530 * It expects an object with attr method (such as a jQuery object). 3531 * @param {Object} element 3532 * @param {Function} element.removeAttr 3533 */ 3534 function enableElement(element) { 3535 if (typeof element !== 'object' || typeof element.removeAttr !== 'function') { 3536 throw new TypeError('Argument element must be an object with removeAttr method'); 3537 } 3538 3539 element.removeAttr('disabled'); 3540 } 3541 3542 /** 3543 * Disables all elements in a form. 3544 * It expects an object with find method (such as a jQuery object). 3545 * @param {Object} form 3546 * @param {Function} form.find 3547 */ 3548 function disableForm(form) { 3549 if (typeof form !== 'object' || typeof form.find !== 'function') { 3550 throw new TypeError('Argument form must be an object with find method'); 3551 } 3552 3553 disableElement(form.find('input, textarea, select, button')); 3554 } 3555 3556 /** 3557 * Enables all elements in a form. 3558 * It expects an object with find method (such as a jQuery object). 3559 * @param {Object} form 3560 * @param {Function} form.find 3561 */ 3562 function enableForm(form) { 3563 if (typeof form !== 'object' || typeof form.find !== 'function') { 3564 throw new TypeError('Argument form must be an object with find method'); 3565 } 3566 3567 enableElement(form.find('input, textarea, select, button')); 3568 } 3569 3570 /** 3571 * Returns the value of a field in a form 3572 * @param {Object} form A jQuery object wrapping a form 3573 * @param {string} fieldName The name of the field from which the value is going to be retrieved 3574 * @param {Boolean} isCheckboxList A boolean value which indicates whether the field is a list of checkbox or not 3575 * @return {string} 3576 */ 3577 function getFieldValue(form, fieldName, isCheckboxList) { 3578 if (form[0][fieldName] === undefined) { 3579 throw new Error('Field ' + fieldName + ' does not exist in the form'); 3580 } 3581 3582 var field = form[0][fieldName]; 3583 3584 if (isCheckboxList === true) { 3585 return Array.from(field).reduce(function(acc, current) { 3586 if (current.checked) { 3587 return acc.concat(current.value); 3588 } 3589 return acc; 3590 }, []); 3591 } 3592 3593 return field.value; 3594 } 3595 3596 /** 3597 * Sets the value of a field in a form 3598 * @param {Object} form A jQuery object wrapping a form 3599 * @param {string} fieldName The name of the field to which the value is going to be set 3600 * @param {string|number} value The value to be set in the field 3601 */ 3602 function setFieldValue(form, fieldName, value) { 3603 if (form[0][fieldName] === undefined) { 3604 throw new Error('Field ' + fieldName + ' does not exist in the form'); 3605 } 3606 form[0][fieldName].value = value; 3607 } 3608 3609 module.exports = { 3610 hideElement: hideElement, 3611 showElement: showElement, 3612 enableElement: enableElement, 3613 disableElement: disableElement, 3614 getFieldValue: getFieldValue, 3615 setFieldValue: setFieldValue, 3616 enableForm: enableForm, 3617 disableForm: disableForm 3618 }; 3619 3620 3621/***/ }), 3622 3623/***/ 288:
3624/***/ (function(module, exports) { 3625 3626 /** 3627 * Returns a string representation of a full URL 3628 * @param {String} path String that indicates the path to the resource 3629 * @throws {TypeError} 3630 */ 3631 function makeUrl(path) { 3632 if (typeof path !== 'string') { 3633 throw new TypeError('Argument path must be an string'); 3634 } 3635 3636 return window.location.pathname + path + '/'; 3637 } 3638 3639 /** 3640 * Makes a post request to the specified path with the specified data and callbacks 3641 * @param {String} path String that indicates the path to the resource 3642 * @param {any} data The data that is sent to the server 3643 * @returns {<jqXHR>} A jqXHR object (http://api.jquery.com/jQuery.ajax/#jqXHR) 3644 * @throws {TypeError} 3645 */ 3646 function post(path, data) { 3647 if (typeof path !== 'string') { 3648 throw new TypeError('Argument path must be an string'); 3649 } 3650 3651 var url = makeUrl(path); 3652 var request = $.post(url, data); 3653 3654 return request; 3655 } 3656 3657 /** 3658 * Updates the listing price in the server 3659 * @param {Number} price An integer value 3660 * @returns {<jqXHR>} A jqXHR object (http://api.jquery.com/jQuery.ajax/#jqXHR) 3661 * @throws {TypeError} 3662 */ 3663 function updateListingPrice(price) { 3664 if (!Number.isInteger(price)) { 3665 throw new TypeError('Argument price must be an integer number'); 3666 } 3667 3668 var data = { price: price }; 3669 3670 return post('listing-price', data); 3671 } 3672 3673 /** 3674 * Requests a call to the user phone 3675 * @param {String} reason A string which value might be one of: 'modification', 'error', 'removal' or 'other' 3676 * @param {String} phoneCode A non empty string value 3677 * @param {Number} phoneNumber An integer value 3678 * @param {String} otherReasonDetails A string value. It's required only if reason argument is 'other' 3679 * @returns {<jqXHR>} A jqXHR object (http://api.jquery.com/jQuery.ajax/#jqXHR) 3680 * @throws {TypeError} 3681 */ 3682 function requestACall(reason, phoneCode, phoneNumber, otherReasonDetails) { 3683 var validReasons = ['modification', 'error', 'removal', 'other']; 3684 3685 if (validReasons.indexOf(reason) < 0) { 3686 throw new TypeError('Argument reason must be one of ' + validReasons.join(', ')); 3687 } 3688 3689 if (typeof phoneCode !== 'string' || phoneCode.trim() === '') { 3690 throw new TypeError('Argument phoneCode must be a non-empty string'); 3691 } 3692 3693 if (!Number.isInteger(phoneNumber)) { 3694 throw new TypeError('Argument phoneNumber must be an integer number'); 3695 } 3696 3697 if (reason === 'other') { 3698 if (typeof otherReasonDetails !== 'string' || otherReasonDetails.trim() === '') { 3699 throw new TypeError('Argument otherReasonDetails must be a non empty string value if argument reason is \`empty\`'); 3700 } 3701 } 3702 3703 var data = { 3704 reason: reason, 3705 phoneCode: phoneCode, 3706 phoneNumber: phoneNumber 3707 }; 3708 3709 // Only add the 'other' reason details if reason is 'other' 3710 if (reason === 'other') { 3711 data.otherReasonDetails = otherReasonDetails; 3712 } 3713 3714 return post('call-me-back', data); 3715 } 3716 3717 /** 3718 * Notify the car has been sold 3719 * @param {String} detail A string which value might be one of: 'testdrive', 'private', 'dealer' or 'keep' 3720 * @returns {<jqXHR>} A jqXHR object (http://api.jquery.com/jQuery.ajax/#jqXHR) 3721 * @throws {TypeError} 3722 */ 3723 function notifyCarIsSold(detail) { 3724 var validDetails = ['testdrive', 'private', 'dealer', 'keep']; 3725 3726 if (validDetails.indexOf(detail) < 0) { 3727 throw new TypeError('Argument detail must be one of ' + validDetails.join(', ')); 3728 } 3729 3730 var data = { detail: detail }; 3731 3732 return post('sold-car', data); 3733 } 3734 3735 /** 3736 * Updates the availability for the test drive in the server 3737 * @param {String} days A string which value might be one of: 'anyday', 'weekdays' or 'weekend' 3738 * @param {String[]} hours An array of strings which values might be one of: 'morning', 'midday', 'afternoon' or 'evening'. 3739 * Each value must not exist more than once inside the array. 3740 * @returns {<jqXHR>} A jqXHR object (http://api.jquery.com/jQuery.ajax/#jqXHR) 3741 * @throws {TypeError} 3742 */ 3743 function updateTestDriveAvailability(days, hours) { 3744 var validDays = ['anyday', 'weekdays', 'weekend']; 3745 var validHours = ['morning', 'midday', 'afternoon', 'evening']; 3746 var uniqueHours = []; 3747 3748 if (validDays.indexOf(days) < 0) { 3749 throw new TypeError('Argument days must be one of ' + validDays.join(', ')); 3750 } 3751 3752 if (!Array.isArray(hours)) { 3753 throw new TypeError('Argument hours must be an array'); 3754 } 3755
3756 hours.forEach(function(hour) { 3757 if (validHours.indexOf(hour) < 0) { 3758 throw new TypeError('Argument hours must only contain string values ' + validDays.join(', ')); 3759 } 3760 3761 if (uniqueHours.indexOf(hour) >= 0) { 3762 throw new TypeError('Argument hours must contain unique values. Found value ' + hour + ' more than once.'); 3763 } 3764 3765 uniqueHours.push(hour); 3766 }); 3767 3768 var data = { 3769 days: days, 3770 hours: uniqueHours 3771 }; 3772 3773 return post('test-drive', data); 3774 } 3775 3776 /** 3777 * Updates comments about the car in the server 3778 * @param {String} comments A string which length must be less than 500 3779 * @returns {<jqXHR>} A jqXHR object (http://api.jquery.com/jQuery.ajax/#jqXHR) 3780 * @throws {TypeError} 3781 */ 3782 function updateComments(comments) { 3783 if (typeof comments !== 'string' || comments.length > 500) { 3784 throw new TypeError('Argument comments must be a string value which length must be less than 500'); 3785 } 3786 3787 var data = { comments: comments }; 3788 3789 return post('comments', data); 3790 } 3791 3792 /** 3793 * Updates additional information related to the private sale 3794 * @param {String} phoneCode A non-empty string 3795 * @param {Number} phoneNumber An integer value 3796 * @param {Number} minimumPrice An integer value 3797 * @returns {<jqXHR>} A jqXHR object (http://api.jquery.com/jQuery.ajax/#jqXHR) 3798 * @throws {TypeError} 3799 */ 3800 function updateOtherData(phoneCode, phoneNumber, minimumPrice) { 3801 if (typeof phoneCode !== 'string' || phoneCode.trim() === '') { 3802 throw new TypeError('Argument phoneCode must be a non-empty string'); 3803 } 3804 3805 if (!Number.isInteger(phoneNumber)) { 3806 throw new TypeError('Argument phoneNumber must be an integer number'); 3807 } 3808 3809 if (!Number.isInteger(minimumPrice)) { 3810 throw new TypeError('Argument minimumPrice must be an integer number'); 3811 } 3812 3813 var data = { 3814 phoneCode: phoneCode, 3815 phoneNumber: phoneNumber, 3816 minimumPrice: minimumPrice 3817 }; 3818 3819 return post('other', data); 3820 } 3821 3822 module.exports = { 3823 updateListingPrice: updateListingPrice, 3824 requestACall: requestACall, 3825 notifyCarIsSold: notifyCarIsSold, 3826 updateTestDriveAvailability: updateTestDriveAvailability, 3827 updateComments: updateComments, 3828 updateOtherData: updateOtherData 3829 }; 3830 3831 3832/***/ }), 3833 3834/***/ 289: 3835/***/ (function(module, exports, __webpack_require__) { 3836 3837 /* WEBPACK VAR INJECTION */(function(global) {module.exports = global["faqTabsModule"] = __webpack_require__(290); 3838 /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }()))) 3839 3840/***/ }), 3841 3842/***/ 290: 3843/***/ (function(module, exports) { 3844 3845 var faqTabsModule = module.exports = function () { 3846 var prefix = '.faq-tabs'; 3847 3848 function initialize() { 3849 // Hide all content, all answers and all close icons 3850 selector('content').hide(); 3851 selector('question-answer').hide(); 3852 selector('close-question').hide(); 3853 3854 replaceAllSvgs(); 3855 setCategorySelectors(); 3856 setSubcategorySelectors(); 3857 setQuestionSelectors(); 3858 selectCategory(getFirstCategory().attr('data-category-id')); 3859 } 3860 3861 function replaceWithInlineSvg(imgURL, $img) { 3862 var imgID = $img.attr('id'); 3863 var imgClass = $img.attr('class'); 3864 3865 $.get(imgURL, function(data) { 3866 // Get the SVG tag, ignore the rest 3867 var $svg = $(data).find('svg'); 3868 // Add replaced image's ID to the new SVG 3869 if(typeof imgID !== 'undefined') { 3870 $svg = $svg.attr('id', imgID); 3871 } 3872 // Add replaced image's classes to the new SVG 3873 if(typeof imgClass !== 'undefined') { 3874 $svg = $svg.attr('class', imgClass + ' replaced-svg'); 3875 } 3876 // Remove any invalid XML tags as per http://validator.w3.org 3877 $svg = $svg.removeAttr('xmlns:a'); 3878 // Replace image with new SVG 3879 $img.replaceWith($svg); 3880 }, 'xml'); 3881 } 3882 3883 // Replace categories and subcategories icons with inline SVGs so we can change color on active 3884 function replaceAllSvgs() { 3885 var svgImgSelectors = prefix + ' img[data-src]'; 3886 3887 $(svgImgSelectors).each(function() { 3888 var $img = $(this); 3889 var imgURL = $img.attr('data-src'); 3890 var ext = imgURL.split('.').pop().toLowerCase(); 3891 3892 if(ext === 'svg') { 3893 replaceWithInlineSvg(imgURL, $img); 3894 } else { 3895 $img.attr('src', imgURL); 3896 } 3897 }); 3898 } 3899 3900 function selector(className) { 3901 return $(prefix + '__' + className); 3902 } 3903 3904 function categoryAttrSelector(className, categoryId) { 3905 return $(prefix + '__' + className + '[data-category-id=\'' + categoryId + '\']'); 3906 } 3907 3908 function subcategoryAttrSelector(className, subcategoryId) { 3909 return $(prefix + '__' + className + '[data-subcategory-id=\'' + subcategoryId + '\']'); 3910 } 3911 3912 function selectFirstSubcategory(categoryId) { 3913 var $subcategory = getFirstSubcategory(categoryId); 3914 if($subcategory) { 3915 // Select first subcategory 3916 selectSubcategory($subcategory.attr('data-subcategory-id')); 3917 } else { 3918 // no subcategories then hide the arrow 3919 selector('subcategory-arrow').hide(); 3920 } 3921 } 3922 3923 function getSelectedCategoryId() { 3924 var $selectedCategory = selector('category.active-category'); 3925 if($selectedCategory) { 3926 return $selectedCategory.attr('data-category-id'); 3927 } 3928 } 3929 3930 function selectCategory(categoryId) { 3931 // De-activate all categories except the one selected 3932 selector('category').removeClass('active-category'); 3933 categoryAttrSelector('category', categoryId).addClass('active-category'); 3934 // Hide all content and show content by selected category 3935 selector('content').hide(); 3936 categoryAttrSelector('content', categoryId).show(); 3937 // Hide all subcategories dropdown and show the one that matches the selected category 3938 selector('subcategories').css('display', 'none'); 3939 categoryAttrSelector('subcategories', categoryId).css('display', 'flex'); 3940 // 3941 selectFirstSubcategory(categoryId); 3942 } 3943 3944 function selectSubcategory(subcategoryId) { 3945 var $subcategory = subcategoryAttrSelector('subcategory', subcategoryId); 3946 // Make sure subcategories arrow is shown 3947 var $subcategoryArrow = selector('subcategory-arrow'); 3948 $subcategoryArrow.show(); 3949 // De-activate all subcategories and activate current selected subcategory 3950 selector('subcategory').removeClass('active-subcategory'); 3951 $subcategory.addClass('active-subcategory'); 3952 // Animated subcategories arrow to the selected subcategory 3953 var centerPoint = ($subcategory.width() / 2) - ($subcategoryArrow.width() / 2); 3954 var newLeft = centerPoint + $subcategory.position().left; 3955 $subcategoryArrow.animate({ 3956 'left': newLeft 3957 }); 3958 } 3959 3960 function getFirstCategory() { 3961 var $category = selector('category'); 3962 if ($category.length) { 3963 return $category.first(); 3964 } 3965 } 3966 3967 function getFirstSubcategory(categoryId) { 3968 var $subcategories = categoryAttrSelector('subcategories', categoryId); 3969 // if subcategories exist for this category 3970 if ($subcategories.length) { 3971 return $subcategories.find(prefix + '__subcategory').first(); 3972 } 3973 } 3974 3975 function jumpToSubcategory(subcategoryId) { 3976 var $jumpEle = $(prefix + ' h3[name=\'subcategory-' + subcategoryId + '\']'); 3977 if($jumpEle.length) { 3978 $('html, body').animate({ 3979 scrollTop: $jumpEle.offset().top 3980 }, 500); 3981 } 3982 } 3983 3984 function setCategorySelectors() { 3985 selector('category').click(function(event) { 3986 event.preventDefault(); 3987 selectCategory($(this).attr('data-category-id')); 3988 }); 3989 } 3990 3991 function setSubcategorySelectors() { 3992 $(prefix + '__subcategory').click(function(event) { 3993 event.preventDefault(); 3994 var subcategoryId = $(this).attr('data-subcategory-id'); 3995 selectSubcategory(subcategoryId); 3996 jumpToSubcategory(subcategoryId); 3997 }); 3998 } 3999 4000 function setQuestionSelectors() { 4001 $(prefix + '__question-title').click(function(event) { 4002 event.preventDefault(); 4003 var $answer = $(this).next(prefix + '__question-answer'); 4004 var $openIcon = $(this).find(prefix + '__open-question'); 4005 var $closeIcon = $(this).find(prefix + '__close-question'); 4006 // Toggle answer 4007 if($answer.is(":visible")) { 4008 $answer.slideUp('fast'); 4009 $openIcon.show(); 4010 $closeIcon.hide(); 4011 $(this).removeClass('active-question'); 4012 } else { 4013 $answer.slideDown('fast'); 4014 $openIcon.hide(); 4015 $closeIcon.show(); 4016 $(this).addClass('active-question'); 4017 } 4018 }); 4019 } 4020 4021 return { 4022 initialize: initialize 4023 }; 4024 }(); 4025 4026 4027/***/ }), 4028 4029/***/ 291:
4030/***/ (function(module, exports) { 4031 4032 /** 4033 * Created by alexz on 18.11.16. 4034 */ 4035 4036 ;(function($) { 4037 'use strict'; 4038 4039 var __debug = false; 4040 var cityModify = {isChanged: false, value: ''}; 4041 4042 var makePUTRequest = function(data, carHash) { 4043 $.ajax({ 4044 url: '/papi/v1/car-details/marketing-property/' + carHash, 4045 beforeSend: function(xhr) { 4046 xhr.overrideMimeType( "application/json; charset=utf-8" ); 4047 }, 4048 type: 'PUT', 4049 dataType: 'json', 4050 contentType: "application/json; charset=utf-8", 4051 headers: {'Content-Type': 'application/json'}, 4052 data: JSON.stringify(data), 4053 success: function(result) { 4054 if (__debug) console.log(result); 4055 } 4056 }); 4057 }; 4058 4059 var checkIfCityModified = function(city) { 4060 if (!cityModify.value.length) { 4061 cityModify.value = city; 4062 } else if (cityModify.value !== city) { 4063 cityModify.isChanged = true; 4064 } 4065 }; 4066 4067 var constructRequest = function(e, valueIndex) { 4068 var result = {}; 4069 var propertyMap = { 4070 city: 3401, 4071 branch: 3402, 4072 date: 3403, 4073 time: 3404, 4074 fname: 3405, 4075 lname: 3406, 4076 telephone: 3407, 4077 interestedIn: 3408 4078 }; 4079 4080 if ( 4081 e.attr('class') == 'branches-ini-item' && 4082 e[0].hasAttribute('data-city') 4083 ){ 4084 result.propertyId = 3401; 4085 result.value = e.attr('data-city'); 4086 checkIfCityModified(e.attr('data-city')); 4087 } else { 4088 result.propertyId = propertyMap[ 4089 e.attr('name') == "mobile[number]" ? 4090 'telephone' : 4091 e.attr('name')]; 4092 4093 result.value = e.is('select') ? 4094 e.attr('name') == 'time' ? 4095 e.find('option:selected').text() : 4096 e.val() 4097 : valueIndex; 4098 } 4099 4100 return result; 4101 }; 4102 4103 var sendData = function(e) { 4104 if (e.isTrigger) return; 4105 4106 var $this = $(this); 4107 4108 if (!$this.val()) return; 4109 4110 var valueIndex = $this.val().length ? 1 : 0; 4111 4112 if ( 4113 $('#carHash').val().length && 4114 $this.attr('id') != "inpulect" && 4115 $this.attr('name') != "mobile[prefix]" 4116 ) { 4117 4118 if (__debug) console.log(constructRequest($this, valueIndex)); 4119 4120 makePUTRequest(constructRequest($this, valueIndex), $('#carHash').val()); 4121 } 4122 }; 4123 4124 var sendCustomSelectData = function() { 4125 if (__debug) console.log(constructRequest($(this))); 4126 4127 makePUTRequest(constructRequest($(this)), $('#carHash').val()); 4128 }; 4129 4130 var sendBranchData = function(e) { 4131 if (!cityModify.isChanged && e.isTrigger) return; 4132 4133 var result = {}; 4134 result.propertyId = 3402; 4135 result.value = $(this).attr('data-id'); 4136 4137 if (__debug) console.log(result); 4138 4139 makePUTRequest(result, $('#carHash').val()); 4140 }; 4141 4142 function sendCity(e){ 4143 var request = {}; 4144 4145 if (e.keyCode == 13) { 4146 request.propertyId = 3401; 4147 request.value = e.currentTarget.value; 4148 4149 if (__debug) console.log(e, 4150 e.currentTarget, 4151 e.currentTarget.value, 4152 'request data is: ', 4153 request 4154 ); 4155 checkIfCityModified(e.currentTarget.value); 4156 makePUTRequest(request, $('#carHash').val()); 4157 } 4158 } 4159 4160 /** 4161 * @param delay - a provide of debug value - is true or false. 4162 * @example $appointmentForm.trackUserData(true); 4163 * @returns {jQueryElement} 4164 */ 4165 4166 $.fn.trackUserData = function(debugingValue) { 4167 var $this = $(this); 4168 __debug = debugingValue; 4169 4170 $this.on('click', '#branches', sendData); 4171 $this.on('click', '.branch', sendBranchData); 4172 $this.find('select:visible').on('change', sendData); 4173 $this.find('input[type=text]:visible').on('blur', sendData); 4174 $this.find('input[type=text]').on('keyup', sendCity); 4175 $('div.branches-ini-item').on('click', sendCustomSelectData); 4176 4177 return $this; 4178 }; 4179 4180 })(jQuery); 4181 4182 4183/***/ }), 4184 4185/***/ 299: 4186/***/ (function(module, exports) { 4187 4188 ;(function($) { 4189 'use strict'; 4190 4191 $.fn.callmeDatetimeFilter = function(cache) { 4192 var $this = $(this); 4193 var $selectedDay = new Date($('select#days.form-control').find(':selected').val()); 4194 var timeNow = new Date(); 4195 4196 $this.prop('selectedIndex', 0); 4197 4198 if ($selectedDay.getDay() !== timeNow.getDay()) { 4199 $this.empty().append(cache); 4200 $this.prop('selectedIndex', 0); 4201 return; 4202 } 4203 4204 $this.find('option').each(function() { 4205 var $option = $(this); 4206 var optTime = $option.val().split(':')[0]; 4207 4208 if (optTime <= timeNow.getHours()) { 4209 $option.remove(); 4210 } 4211 }); 4212 4213 $this.find('optgroup').each(function() { 4214 var hideOptGroup = false;
vendor: 20,844 bytes, lines 4215-4875
4215 var $this = $(this); 4216 4217 if ($this.find('option').length < 1) { 4218 $this.remove(); 4219 } 4220 }); 4221 4222 return $this; 4223 } 4224 })(jQuery); 4225 4226 4227/***/ }), 4228 4229/***/ 314: 4230/***/ (function(module, exports) { 4231 4232 /* ======================================================================== 4233 * Bootstrap: tooltip.js v3.3.7 4234 * http://getbootstrap.com/javascript/#tooltip 4235 * Inspired by the original jQuery.tipsy by Jason Frame 4236 * ======================================================================== 4237 * Copyright 2011-2016 Twitter, Inc. 4238 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 4239 * ======================================================================== */ 4240 4241 4242 +function ($) { 4243 'use strict'; 4244 4245 // TOOLTIP PUBLIC CLASS DEFINITION 4246 // =============================== 4247 4248 var Tooltip = function (element, options) { 4249 this.type = null 4250 this.options = null 4251 this.enabled = null 4252 this.timeout = null 4253 this.hoverState = null 4254 this.$element = null 4255 this.inState = null 4256 4257 this.init('tooltip', element, options) 4258 } 4259 4260 Tooltip.VERSION = '3.3.7' 4261 4262 Tooltip.TRANSITION_DURATION = 150 4263 4264 Tooltip.DEFAULTS = { 4265 animation: true, 4266 placement: 'top', 4267 selector: false, 4268 template: '<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>', 4269 trigger: 'hover focus', 4270 title: '', 4271 delay: 0, 4272 html: false, 4273 container: false, 4274 viewport: { 4275 selector: 'body', 4276 padding: 0 4277 } 4278 } 4279 4280 Tooltip.prototype.init = function (type, element, options) { 4281 this.enabled = true 4282 this.type = type 4283 this.$element = $(element) 4284 this.options = this.getOptions(options) 4285 this.$viewport = this.options.viewport && $($.isFunction(this.options.viewport) ? this.options.viewport.call(this, this.$element) : (this.options.viewport.selector || this.options.viewport)) 4286 this.inState = { click: false, hover: false, focus: false } 4287 4288 if (this.$element[0] instanceof document.constructor && !this.options.selector) { 4289 throw new Error('`selector` option must be specified when initializing ' + this.type + ' on the window.document object!') 4290 } 4291 4292 var triggers = this.options.trigger.split(' ') 4293 4294 for (var i = triggers.length; i--;) { 4295 var trigger = triggers[i] 4296 4297 if (trigger == 'click') { 4298 this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this)) 4299 } else if (trigger != 'manual') { 4300 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin' 4301 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout' 4302 4303 this.$element.on(eventIn + '.' + this.type, this.options.selector, $.proxy(this.enter, this)) 4304 this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this)) 4305 } 4306 } 4307 4308 this.options.selector ? 4309 (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) : 4310 this.fixTitle() 4311 } 4312 4313 Tooltip.prototype.getDefaults = function () { 4314 return Tooltip.DEFAULTS 4315 } 4316 4317 Tooltip.prototype.getOptions = function (options) { 4318 options = $.extend({}, this.getDefaults(), this.$element.data(), options) 4319 4320 if (options.delay && typeof options.delay == 'number') { 4321 options.delay = { 4322 show: options.delay, 4323 hide: options.delay 4324 } 4325 } 4326 4327 return options 4328 } 4329 4330 Tooltip.prototype.getDelegateOptions = function () { 4331 var options = {} 4332 var defaults = this.getDefaults() 4333 4334 this._options && $.each(this._options, function (key, value) { 4335 if (defaults[key] != value) options[key] = value 4336 }) 4337 4338 return options 4339 } 4340 4341 Tooltip.prototype.enter = function (obj) { 4342 var self = obj instanceof this.constructor ? 4343 obj : $(obj.currentTarget).data('bs.' + this.type) 4344 4345 if (!self) { 4346 self = new this.constructor(obj.currentTarget, this.getDelegateOptions()) 4347 $(obj.currentTarget).data('bs.' + this.type, self) 4348 } 4349 4350 if (obj instanceof $.Event) { 4351 self.inState[obj.type == 'focusin' ? 'focus' : 'hover'] = true 4352 } 4353 4354 if (self.tip().hasClass('in') || self.hoverState == 'in') { 4355 self.hoverState = 'in' 4356 return 4357 } 4358 4359 clearTimeout(self.timeout) 4360 4361 self.hoverState = 'in' 4362 4363 if (!self.options.delay || !self.options.delay.show) return self.show() 4364 4365 self.timeout = setTimeout(function () { 4366 if (self.hoverState == 'in') self.show() 4367 }, self.options.delay.show) 4368 } 4369 4370 Tooltip.prototype.isInStateTrue = function () { 4371 for (var key in this.inState) { 4372 if (this.inState[key]) return true 4373 } 4374 4375 return false 4376 } 4377 4378 Tooltip.prototype.leave = function (obj) { 4379 var self = obj instanceof this.constructor ? 4380 obj : $(obj.currentTarget).data('bs.' + this.type) 4381 4382 if (!self) { 4383 self = new this.constructor(obj.currentTarget, this.getDelegateOptions()) 4384 $(obj.currentTarget).data('bs.' + this.type, self) 4385 } 4386 4387 if (obj instanceof $.Event) { 4388 self.inState[obj.type == 'focusout' ? 'focus' : 'hover'] = false 4389 } 4390 4391 if (self.isInStateTrue()) return 4392 4393 clearTimeout(self.timeout) 4394 4395 self.hoverState = 'out' 4396 4397 if (!self.options.delay || !self.options.delay.hide) return self.hide() 4398 4399 self.timeout = setTimeout(function () { 4400 if (self.hoverState == 'out') self.hide() 4401 }, self.options.delay.hide) 4402 } 4403 4404 Tooltip.prototype.show = function () { 4405 var e = $.Event('show.bs.' + this.type) 4406 4407 if (this.hasContent() && this.enabled) { 4408 this.$element.trigger(e) 4409 4410 var inDom = $.contains(this.$element[0].ownerDocument.documentElement, this.$element[0]) 4411 if (e.isDefaultPrevented() || !inDom) return 4412 var that = this 4413 4414 var $tip = this.tip() 4415 4416 var tipId = this.getUID(this.type) 4417 4418 this.setContent() 4419 $tip.attr('id', tipId) 4420 this.$element.attr('aria-describedby', tipId) 4421 4422 if (this.options.animation) $tip.addClass('fade') 4423 4424 var placement = typeof this.options.placement == 'function' ? 4425 this.options.placement.call(this, $tip[0], this.$element[0]) : 4426 this.options.placement 4427 4428 var autoToken = /\s?auto?\s?/i 4429 var autoPlace = autoToken.test(placement) 4430 if (autoPlace) placement = placement.replace(autoToken, '') || 'top' 4431 4432 $tip 4433 .detach() 4434 .css({ top: 0, left: 0, display: 'block' }) 4435 .addClass(placement) 4436 .data('bs.' + this.type, this) 4437 4438 this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element) 4439 this.$element.trigger('inserted.bs.' + this.type) 4440 4441 var pos = this.getPosition() 4442 var actualWidth = $tip[0].offsetWidth 4443 var actualHeight = $tip[0].offsetHeight 4444 4445 if (autoPlace) { 4446 var orgPlacement = placement 4447 var viewportDim = this.getPosition(this.$viewport) 4448 4449 placement = placement == 'bottom' && pos.bottom + actualHeight > viewportDim.bottom ? 'top' : 4450 placement == 'top' && pos.top - actualHeight < viewportDim.top ? 'bottom' : 4451 placement == 'right' && pos.right + actualWidth > viewportDim.width ? 'left' : 4452 placement == 'left' && pos.left - actualWidth < viewportDim.left ? 'right' : 4453 placement 4454 4455 $tip 4456 .removeClass(orgPlacement) 4457 .addClass(placement) 4458 } 4459 4460 var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight) 4461 4462 this.applyPlacement(calculatedOffset, placement) 4463 4464 var complete = function () { 4465 var prevHoverState = that.hoverState 4466 that.$element.trigger('shown.bs.' + that.type) 4467 that.hoverState = null 4468 4469 if (prevHoverState == 'out') that.leave(that) 4470 } 4471 4472 $.support.transition && this.$tip.hasClass('fade') ? 4473 $tip 4474 .one('bsTransitionEnd', complete) 4475 .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) : 4476 complete() 4477 } 4478 } 4479 4480 Tooltip.prototype.applyPlacement = function (offset, placement) { 4481 var $tip = this.tip() 4482 var width = $tip[0].offsetWidth 4483 var height = $tip[0].offsetHeight 4484 4485 // manually read margins because getBoundingClientRect includes difference 4486 var marginTop = parseInt($tip.css('margin-top'), 10) 4487 var marginLeft = parseInt($tip.css('margin-left'), 10) 4488 4489 // we must check for NaN for ie 8/9 4490 if (isNaN(marginTop)) marginTop = 0 4491 if (isNaN(marginLeft)) marginLeft = 0 4492 4493 offset.top += marginTop 4494 offset.left += marginLeft 4495 4496 // $.fn.offset doesn't round pixel values 4497 // so we use setOffset directly with our own function B-0 4498 $.offset.setOffset($tip[0], $.extend({ 4499 using: function (props) { 4500 $tip.css({ 4501 top: Math.round(props.top), 4502 left: Math.round(props.left) 4503 }) 4504 } 4505 }, offset), 0) 4506 4507 $tip.addClass('in') 4508 4509 // check to see if placing tip in new offset caused the tip to resize itself 4510 var actualWidth = $tip[0].offsetWidth 4511 var actualHeight = $tip[0].offsetHeight 4512 4513 if (placement == 'top' && actualHeight != height) { 4514 offset.top = offset.top + height - actualHeight 4515 } 4516 4517 var delta = this.getViewportAdjustedDelta(placement, offset, actualWidth, actualHeight) 4518 4519 if (delta.left) offset.left += delta.left 4520 else offset.top += delta.top 4521 4522 var isVertical = /top|bottom/.test(placement) 4523 var arrowDelta = isVertical ? delta.left * 2 - width + actualWidth : delta.top * 2 - height + actualHeight 4524 var arrowOffsetPosition = isVertical ? 'offsetWidth' : 'offsetHeight' 4525 4526 $tip.offset(offset) 4527 this.replaceArrow(arrowDelta, $tip[0][arrowOffsetPosition], isVertical) 4528 } 4529 4530 Tooltip.prototype.replaceArrow = function (delta, dimension, isVertical) { 4531 this.arrow() 4532 .css(isVertical ? 'left' : 'top', 50 * (1 - delta / dimension) + '%') 4533 .css(isVertical ? 'top' : 'left', '') 4534 } 4535 4536 Tooltip.prototype.setContent = function () { 4537 var $tip = this.tip() 4538 var title = this.getTitle() 4539 4540 $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title) 4541 $tip.removeClass('fade in top bottom left right') 4542 } 4543 4544 Tooltip.prototype.hide = function (callback) { 4545 var that = this 4546 var $tip = $(this.$tip) 4547 var e = $.Event('hide.bs.' + this.type) 4548 4549 function complete() { 4550 if (that.hoverState != 'in') $tip.detach() 4551 if (that.$element) { // TODO: Check whether guarding this code with this `if` is really necessary. 4552 that.$element 4553 .removeAttr('aria-describedby') 4554 .trigger('hidden.bs.' + that.type) 4555 } 4556 callback && callback() 4557 } 4558 4559 this.$element.trigger(e) 4560 4561 if (e.isDefaultPrevented()) return 4562 4563 $tip.removeClass('in') 4564 4565 $.support.transition && $tip.hasClass('fade') ? 4566 $tip 4567 .one('bsTransitionEnd', complete) 4568 .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) : 4569 complete() 4570 4571 this.hoverState = null 4572 4573 return this 4574 } 4575 4576 Tooltip.prototype.fixTitle = function () { 4577 var $e = this.$element 4578 if ($e.attr('title') || typeof $e.attr('data-original-title') != 'string') { 4579 $e.attr('data-original-title', $e.attr('title') || '').attr('title', '') 4580 } 4581 } 4582 4583 Tooltip.prototype.hasContent = function () { 4584 return this.getTitle() 4585 } 4586 4587 Tooltip.prototype.getPosition = function ($element) { 4588 $element = $element || this.$element 4589 4590 var el = $element[0] 4591 var isBody = el.tagName == 'BODY' 4592 4593 var elRect = el.getBoundingClientRect() 4594 if (elRect.width == null) { 4595 // width and height are missing in IE8, so compute them manually; see https://github.com/twbs/bootstrap/issues/14093 4596 elRect = $.extend({}, elRect, { width: elRect.right - elRect.left, height: elRect.bottom - elRect.top }) 4597 } 4598 var isSvg = window.SVGElement && el instanceof window.SVGElement 4599 // Avoid using $.offset() on SVGs since it gives incorrect results in jQuery 3. 4600 // See https://github.com/twbs/bootstrap/issues/20280 4601 var elOffset = isBody ? { top: 0, left: 0 } : (isSvg ? null : $element.offset()) 4602 var scroll = { scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.scrollTop() } 4603 var outerDims = isBody ? { width: $(window).width(), height: $(window).height() } : null 4604 4605 return $.extend({}, elRect, scroll, outerDims, elOffset) 4606 } 4607 4608 Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) { 4609 return placement == 'bottom' ? { top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2 } : 4610 placement == 'top' ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2 } : 4611 placement == 'left' ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } : 4612 /* placement == 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width } 4613 4614 } 4615 4616 Tooltip.prototype.getViewportAdjustedDelta = function (placement, pos, actualWidth, actualHeight) { 4617 var delta = { top: 0, left: 0 } 4618 if (!this.$viewport) return delta 4619 4620 var viewportPadding = this.options.viewport && this.options.viewport.padding || 0 4621 var viewportDimensions = this.getPosition(this.$viewport) 4622 4623 if (/right|left/.test(placement)) { 4624 var topEdgeOffset = pos.top - viewportPadding - viewportDimensions.scroll 4625 var bottomEdgeOffset = pos.top + viewportPadding - viewportDimensions.scroll + actualHeight 4626 if (topEdgeOffset < viewportDimensions.top) { // top overflow 4627 delta.top = viewportDimensions.top - topEdgeOffset 4628 } else if (bottomEdgeOffset > viewportDimensions.top + viewportDimensions.height) { // bottom overflow 4629 delta.top = viewportDimensions.top + viewportDimensions.height - bottomEdgeOffset 4630 } 4631 } else { 4632 var leftEdgeOffset = pos.left - viewportPadding 4633 var rightEdgeOffset = pos.left + viewportPadding + actualWidth 4634 if (leftEdgeOffset < viewportDimensions.left) { // left overflow 4635 delta.left = viewportDimensions.left - leftEdgeOffset 4636 } else if (rightEdgeOffset > viewportDimensions.right) { // right overflow 4637 delta.left = viewportDimensions.left + viewportDimensions.width - rightEdgeOffset 4638 } 4639 } 4640 4641 return delta 4642 } 4643 4644 Tooltip.prototype.getTitle = function () { 4645 var title 4646 var $e = this.$element 4647 var o = this.options 4648 4649 title = $e.attr('data-original-title') 4650 || (typeof o.title == 'function' ? o.title.call($e[0]) : o.title) 4651 4652 return title 4653 } 4654 4655 Tooltip.prototype.getUID = function (prefix) { 4656 do prefix += ~~(Math.random() * 1000000) 4657 while (document.getElementById(prefix)) 4658 return prefix 4659 } 4660 4661 Tooltip.prototype.tip = function () { 4662 if (!this.$tip) { 4663 this.$tip = $(this.options.template) 4664 if (this.$tip.length != 1) { 4665 throw new Error(this.type + ' `template` option must consist of exactly 1 top-level element!') 4666 } 4667 } 4668 return this.$tip 4669 } 4670 4671 Tooltip.prototype.arrow = function () { 4672 return (this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow')) 4673 } 4674 4675 Tooltip.prototype.enable = function () { 4676 this.enabled = true 4677 } 4678 4679 Tooltip.prototype.disable = function () { 4680 this.enabled = false 4681 } 4682 4683 Tooltip.prototype.toggleEnabled = function () { 4684 this.enabled = !this.enabled 4685 } 4686 4687 Tooltip.prototype.toggle = function (e) { 4688 var self = this 4689 if (e) { 4690 self = $(e.currentTarget).data('bs.' + this.type) 4691 if (!self) { 4692 self = new this.constructor(e.currentTarget, this.getDelegateOptions()) 4693 $(e.currentTarget).data('bs.' + this.type, self) 4694 } 4695 } 4696 4697 if (e) { 4698 self.inState.click = !self.inState.click 4699 if (self.isInStateTrue()) self.enter(self) 4700 else self.leave(self) 4701 } else { 4702 self.tip().hasClass('in') ? self.leave(self) : self.enter(self) 4703 } 4704 } 4705 4706 Tooltip.prototype.destroy = function () { 4707 var that = this 4708 clearTimeout(this.timeout) 4709 this.hide(function () { 4710 that.$element.off('.' + that.type).removeData('bs.' + that.type) 4711 if (that.$tip) { 4712 that.$tip.detach() 4713 } 4714 that.$tip = null 4715 that.$arrow = null 4716 that.$viewport = null 4717 that.$element = null 4718 }) 4719 } 4720 4721 4722 // TOOLTIP PLUGIN DEFINITION 4723 // ========================= 4724 4725 function Plugin(option) { 4726 return this.each(function () { 4727 var $this = $(this) 4728 var data = $this.data('bs.tooltip') 4729 var options = typeof option == 'object' && option 4730 4731 if (!data && /destroy|hide/.test(option)) return 4732 if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options))) 4733 if (typeof option == 'string') data[option]() 4734 }) 4735 } 4736 4737 var old = $.fn.tooltip 4738 4739 $.fn.tooltip = Plugin 4740 $.fn.tooltip.Constructor = Tooltip 4741 4742 4743 // TOOLTIP NO CONFLICT 4744 // =================== 4745 4746 $.fn.tooltip.noConflict = function () { 4747 $.fn.tooltip = old 4748 return this 4749 } 4750 4751 }(jQuery); 4752 4753 4754/***/ }), 4755 4756/***/ 315: 4757/***/ (function(module, exports) { 4758 4759 /* ======================================================================== 4760 * Bootstrap: popover.js v3.3.7 4761 * http://getbootstrap.com/javascript/#popovers 4762 * ======================================================================== 4763 * Copyright 2011-2016 Twitter, Inc. 4764 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 4765 * ======================================================================== */ 4766 4767 4768 +function ($) { 4769 'use strict'; 4770 4771 // POPOVER PUBLIC CLASS DEFINITION 4772 // =============================== 4773 4774 var Popover = function (element, options) { 4775 this.init('popover', element, options) 4776 } 4777 4778 if (!$.fn.tooltip) throw new Error('Popover requires tooltip.js') 4779 4780 Popover.VERSION = '3.3.7' 4781 4782 Popover.DEFAULTS = $.extend({}, $.fn.tooltip.Constructor.DEFAULTS, { 4783 placement: 'right', 4784 trigger: 'click', 4785 content: '', 4786 template: '<div class="popover" role="tooltip"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>' 4787 }) 4788 4789 4790 // NOTE: POPOVER EXTENDS tooltip.js 4791 // ================================ 4792 4793 Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype) 4794 4795 Popover.prototype.constructor = Popover 4796 4797 Popover.prototype.getDefaults = function () { 4798 return Popover.DEFAULTS 4799 } 4800 4801 Popover.prototype.setContent = function () { 4802 var $tip = this.tip() 4803 var title = this.getTitle() 4804 var content = this.getContent() 4805 4806 $tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title) 4807 $tip.find('.popover-content').children().detach().end()[ // we use append for html objects to maintain js events 4808 this.options.html ? (typeof content == 'string' ? 'html' : 'append') : 'text' 4809 ](content) 4810 4811 $tip.removeClass('fade top bottom left right in') 4812 4813 // IE8 doesn't accept hiding via the `:empty` pseudo selector, we have to do 4814 // this manually by checking the contents. 4815 if (!$tip.find('.popover-title').html()) $tip.find('.popover-title').hide() 4816 } 4817 4818 Popover.prototype.hasContent = function () { 4819 return this.getTitle() || this.getContent() 4820 } 4821 4822 Popover.prototype.getContent = function () { 4823 var $e = this.$element 4824 var o = this.options 4825 4826 return $e.attr('data-content') 4827 || (typeof o.content == 'function' ? 4828 o.content.call($e[0]) : 4829 o.content) 4830 } 4831 4832 Popover.prototype.arrow = function () { 4833 return (this.$arrow = this.$arrow || this.tip().find('.arrow')) 4834 } 4835 4836 4837 // POPOVER PLUGIN DEFINITION 4838 // ========================= 4839 4840 function Plugin(option) { 4841 return this.each(function () { 4842 var $this = $(this) 4843 var data = $this.data('bs.popover') 4844 var options = typeof option == 'object' && option 4845 4846 if (!data && /destroy|hide/.test(option)) return 4847 if (!data) $this.data('bs.popover', (data = new Popover(this, options))) 4848 if (typeof option == 'string') data[option]() 4849 }) 4850 } 4851 4852 var old = $.fn.popover 4853 4854 $.fn.popover = Plugin 4855 $.fn.popover.Constructor = Popover 4856 4857 4858 // POPOVER NO CONFLICT 4859 // =================== 4860 4861 $.fn.popover.noConflict = function () { 4862 $.fn.popover = old 4863 return this 4864 } 4865 4866 }(jQuery); 4867 4868 4869/***/ }), 4870 4871/***/ 316: 4872/***/ (function(module, exports, __webpack_require__) { 4873 4874 var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/*! 4875 * jQuery Form Plugin
4876 * version: 3.50.0-2014.02.05 4877 * Requires jQuery v1.5 or later 4878 * Copyright (c) 2013 M. Alsup 4879 * Examples and documentation at: http://malsup.com/jquery/form/ 4880 * Project repository: https://github.com/malsup/form 4881 * Dual licensed under the MIT and GPL licenses. 4882 * https://github.com/malsup/form#copyright-and-license 4883 */ 4884 /*global ActiveXObject */ 4885 4886 // AMD support 4887 (function (factory) { 4888 "use strict"; 4889 if (true) { 4890 // using AMD; register as anon module 4891 !(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__(270)], __WEBPACK_AMD_DEFINE_FACTORY__ = (factory), __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? (__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); 4892 } else { 4893 // no AMD; invoke directly 4894 factory( (typeof(jQuery) != 'undefined') ? jQuery : window.Zepto ); 4895 } 4896 } 4897 4898 (function($) { 4899 "use strict"; 4900 4901 /* 4902 Usage Note: 4903 ----------- 4904 Do not use both ajaxSubmit and ajaxForm on the same form. These 4905 functions are mutually exclusive. Use ajaxSubmit if you want 4906 to bind your own submit handler to the form. For example, 4907 4908 $(document).ready(function() { 4909 $('#myForm').on('submit', function(e) { 4910 e.preventDefault(); // <-- important 4911 $(this).ajaxSubmit({ 4912 target: '#output' 4913 }); 4914 }); 4915 }); 4916 4917 Use ajaxForm when you want the plugin to manage all the event binding 4918 for you. For example, 4919 4920 $(document).ready(function() { 4921 $('#myForm').ajaxForm({ 4922 target: '#output' 4923 }); 4924 }); 4925 4926 You can also use ajaxForm with delegation (requires jQuery v1.7+), so the 4927 form does not have to exist when you invoke ajaxForm: 4928 4929 $('#myForm').ajaxForm({ 4930 delegation: true, 4931 target: '#output' 4932 }); 4933 4934 When using ajaxForm, the ajaxSubmit function will be invoked for you 4935 at the appropriate time. 4936 */ 4937 4938 /** 4939 * Feature detection 4940 */ 4941 var feature = {}; 4942 feature.fileapi = $("<input type='file'/>").get(0).files !== undefined; 4943 feature.formdata = window.FormData !== undefined; 4944 4945 var hasProp = !!$.fn.prop; 4946 4947 // attr2 uses prop when it can but checks the return type for 4948 // an expected string. this accounts for the case where a form 4949 // contains inputs with names like "action" or "method"; in those 4950 // cases "prop" returns the element 4951 $.fn.attr2 = function() { 4952 if ( ! hasProp ) { 4953 return this.attr.apply(this, arguments); 4954 } 4955 var val = this.prop.apply(this, arguments); 4956 if ( ( val && val.jquery ) || typeof val === 'string' ) { 4957 return val; 4958 } 4959 return this.attr.apply(this, arguments); 4960 }; 4961 4962 /** 4963 * ajaxSubmit() provides a mechanism for immediately submitting 4964 * an HTML form using AJAX. 4965 */ 4966 $.fn.ajaxSubmit = function(options) { 4967 /*jshint scripturl:true */ 4968 4969 // fast fail if nothing selected (http://dev.jquery.com/ticket/2752) 4970 if (!this.length) { 4971 log('ajaxSubmit: skipping submit process - no element selected'); 4972 return this; 4973 } 4974 4975 var method, action, url, $form = this; 4976 4977 if (typeof options == 'function') { 4978 options = { success: options }; 4979 } 4980 else if ( options === undefined ) { 4981 options = {}; 4982 } 4983 4984 method = options.type || this.attr2('method'); 4985 action = options.url || this.attr2('action'); 4986 4987 url = (typeof action === 'string') ? $.trim(action) : ''; 4988 url = url || window.location.href || ''; 4989 if (url) { 4990 // clean url (don't include hash vaue) 4991 url = (url.match(/^([^#]+)/)||[])[1]; 4992 } 4993 4994 options = $.extend(true, { 4995 url: url, 4996 success: $.ajaxSettings.success, 4997 type: method || $.ajaxSettings.type, 4998 iframeSrc: /^https/i.test(window.location.href || '') ? 'javascript:false' : 'about:blank' 4999 }, options); 5000 5001 // hook for manipulating the form data before it is extracted; 5002 // convenient for use with rich editors like tinyMCE or FCKEditor 5003 var veto = {}; 5004 this.trigger('form-pre-serialize', [this, options, veto]); 5005 if (veto.veto) { 5006 log('ajaxSubmit: submit vetoed via form-pre-serialize trigger'); 5007 return this; 5008 } 5009 5010 // provide opportunity to alter form data before it is serialized 5011 if (options.beforeSerialize && options.beforeSerialize(this, options) === false) { 5012 log('ajaxSubmit: submit aborted via beforeSerialize callback'); 5013 return this; 5014 } 5015 5016 var traditional = options.traditional; 5017 if ( traditional === undefined ) { 5018 traditional = $.ajaxSettings.traditional; 5019 } 5020 5021 var elements = []; 5022 var qx, a = this.formToArray(options.semantic, elements); 5023 if (options.data) { 5024 options.extraData = options.data; 5025 qx = $.param(options.data, traditional); 5026 } 5027 5028 // give pre-submit callback an opportunity to abort the submit 5029 if (options.beforeSubmit && options.beforeSubmit(a, this, options) === false) { 5030 log('ajaxSubmit: submit aborted via beforeSubmit callback'); 5031 return this; 5032 } 5033 5034 // fire vetoable 'validate' event 5035 this.trigger('form-submit-validate', [a, this, options, veto]); 5036 if (veto.veto) { 5037 log('ajaxSubmit: submit vetoed via form-submit-validate trigger'); 5038 return this; 5039 } 5040 5041 var q = $.param(a, traditional); 5042 if (qx) { 5043 q = ( q ? (q + '&' + qx) : qx ); 5044 } 5045 if (options.type.toUpperCase() == 'GET') { 5046 options.url += (options.url.indexOf('?') >= 0 ? '&' : '?') + q; 5047 options.data = null; // data is null for 'get' 5048 } 5049 else { 5050 options.data = q; // data is the query string for 'post' 5051 } 5052 5053 var callbacks = []; 5054 if (options.resetForm) { 5055 callbacks.push(function() { $form.resetForm(); }); 5056 } 5057 if (options.clearForm) { 5058 callbacks.push(function() { $form.clearForm(options.includeHidden); }); 5059 } 5060 5061 // perform a load on the target only if dataType is not provided 5062 if (!options.dataType && options.target) { 5063 var oldSuccess = options.success || function(){}; 5064 callbacks.push(function(data) { 5065 var fn = options.replaceTarget ? 'replaceWith' : 'html'; 5066 $(options.target)[fn](data).each(oldSuccess, arguments); 5067 }); 5068 } 5069 else if (options.success) { 5070 callbacks.push(options.success); 5071 } 5072 5073 options.success = function(data, status, xhr) { // jQuery 1.4+ passes xhr as 3rd arg 5074 var context = options.context || this ; // jQuery 1.4+ supports scope context 5075 for (var i=0, max=callbacks.length; i < max; i++) { 5076 callbacks[i].apply(context, [data, status, xhr || $form, $form]); 5077 } 5078 }; 5079 5080 if (options.error) { 5081 var oldError = options.error; 5082 options.error = function(xhr, status, error) { 5083 var context = options.context || this; 5084 oldError.apply(context, [xhr, status, error, $form]); 5085 }; 5086 } 5087 5088 if (options.complete) { 5089 var oldComplete = options.complete; 5090 options.complete = function(xhr, status) { 5091 var context = options.context || this; 5092 oldComplete.apply(context, [xhr, status, $form]); 5093 }; 5094 } 5095 5096 // are there files to upload? 5097 5098 // [value] (issue #113), also see comment: 5099 // https://github.com/malsup/form/commit/588306aedba1de01388032d5f42a60159eea9228#commitcomment-2180219 5100 var fileInputs = $('input[type=file]:enabled', this).filter(function() { return $(this).val() !== ''; }); 5101 5102 var hasFileInputs = fileInputs.length > 0; 5103 var mp = 'multipart/form-data'; 5104 var multipart = ($form.attr('enctype') == mp || $form.attr('encoding') == mp); 5105 5106 var fileAPI = feature.fileapi && feature.formdata; 5107 log("fileAPI :" + fileAPI); 5108 var shouldUseFrame = (hasFileInputs || multipart) && !fileAPI; 5109 5110 var jqxhr; 5111 5112 // options.iframe allows user to force iframe mode 5113 // 06-NOV-09: now defaulting to iframe mode if file input is detected 5114 if (options.iframe !== false && (options.iframe || shouldUseFrame)) { 5115 // hack to fix Safari hang (thanks to Tim Molendijk for this) 5116 // see: http://groups.google.com/group/jquery-dev/browse_thread/thread/36395b7ab510dd5d 5117 if (options.closeKeepAlive) { 5118 $.get(options.closeKeepAlive, function() { 5119 jqxhr = fileUploadIframe(a); 5120 }); 5121 } 5122 else { 5123 jqxhr = fileUploadIframe(a); 5124 } 5125 } 5126 else if ((hasFileInputs || multipart) && fileAPI) { 5127 jqxhr = fileUploadXhr(a); 5128 } 5129 else { 5130 jqxhr = $.ajax(options); 5131 } 5132 5133 $form.removeData('jqxhr').data('jqxhr', jqxhr); 5134 5135 // clear element array 5136 for (var k=0; k < elements.length; k++) { 5137 elements[k] = null; 5138 } 5139 5140 // fire 'notify' event 5141 this.trigger('form-submit-notify', [this, options]); 5142 return this; 5143 5144 // utility fn for deep serialization 5145 function deepSerialize(extraData){ 5146 var serialized = $.param(extraData, options.traditional).split('&'); 5147 var len = serialized.length; 5148 var result = []; 5149 var i, part; 5150 for (i=0; i < len; i++) { 5151 // #252; undo param space replacement 5152 serialized[i] = serialized[i].replace(/\+/g,' '); 5153 part = serialized[i].split('='); 5154 // #278; use array instead of object storage, favoring array serializations 5155 result.push([decodeURIComponent(part[0]), decodeURIComponent(part[1])]); 5156 } 5157 return result; 5158 } 5159 5160 // XMLHttpRequest Level 2 file uploads (big hat tip to francois2metz) 5161 function fileUploadXhr(a) { 5162 var formdata = new FormData(); 5163 5164 for (var i=0; i < a.length; i++) { 5165 formdata.append(a[i].name, a[i].value); 5166 } 5167 5168 if (options.extraData) { 5169 var serializedData = deepSerialize(options.extraData); 5170 for (i=0; i < serializedData.length; i++) { 5171 if (serializedData[i]) { 5172 formdata.append(serializedData[i][0], serializedData[i][1]); 5173 } 5174 } 5175 } 5176 5177 options.data = null; 5178 5179 var s = $.extend(true, {}, $.ajaxSettings, options, { 5180 contentType: false, 5181 processData: false, 5182 cache: false, 5183 type: method || 'POST' 5184 }); 5185 5186 if (options.uploadProgress) { 5187 // workaround because jqXHR does not expose upload property 5188 s.xhr = function() { 5189 var xhr = $.ajaxSettings.xhr(); 5190 if (xhr.upload) { 5191 xhr.upload.addEventListener('progress', function(event) { 5192 var percent = 0; 5193 var position = event.loaded || event.position; /*event.position is deprecated*/ 5194 var total = event.total; 5195 if (event.lengthComputable) {
5196 percent = Math.ceil(position / total * 100); 5197 } 5198 options.uploadProgress(event, position, total, percent); 5199 }, false); 5200 } 5201 return xhr; 5202 }; 5203 } 5204 5205 s.data = null; 5206 var beforeSend = s.beforeSend; 5207 s.beforeSend = function(xhr, o) { 5208 //Send FormData() provided by user 5209 if (options.formData) { 5210 o.data = options.formData; 5211 } 5212 else { 5213 o.data = formdata; 5214 } 5215 if(beforeSend) { 5216 beforeSend.call(this, xhr, o); 5217 } 5218 }; 5219 return $.ajax(s); 5220 } 5221 5222 // private function for handling file uploads (hat tip to YAHOO!) 5223 function fileUploadIframe(a) { 5224 var form = $form[0], el, i, s, g, id, $io, io, xhr, sub, n, timedOut, timeoutHandle; 5225 var deferred = $.Deferred(); 5226 5227 // #341 5228 deferred.abort = function(status) { 5229 xhr.abort(status); 5230 }; 5231 5232 if (a) { 5233 // ensure that every serialized input is still enabled 5234 for (i=0; i < elements.length; i++) { 5235 el = $(elements[i]); 5236 if ( hasProp ) { 5237 el.prop('disabled', false); 5238 } 5239 else { 5240 el.removeAttr('disabled'); 5241 } 5242 } 5243 } 5244 5245 s = $.extend(true, {}, $.ajaxSettings, options); 5246 s.context = s.context || s; 5247 id = 'jqFormIO' + (new Date().getTime()); 5248 if (s.iframeTarget) { 5249 $io = $(s.iframeTarget); 5250 n = $io.attr2('name'); 5251 if (!n) { 5252 $io.attr2('name', id); 5253 } 5254 else { 5255 id = n; 5256 } 5257 } 5258 else { 5259 $io = $('<iframe name="' + id + '" src="'+ s.iframeSrc +'" />'); 5260 $io.css({ position: 'absolute', top: '-1000px', left: '-1000px' }); 5261 } 5262 io = $io[0]; 5263 5264 5265 xhr = { // mock object 5266 aborted: 0, 5267 responseText: null, 5268 responseXML: null, 5269 status: 0, 5270 statusText: 'n/a', 5271 getAllResponseHeaders: function() {}, 5272 getResponseHeader: function() {}, 5273 setRequestHeader: function() {}, 5274 abort: function(status) { 5275 var e = (status === 'timeout' ? 'timeout' : 'aborted'); 5276 log('aborting upload... ' + e); 5277 this.aborted = 1; 5278 5279 try { // #214, #257 5280 if (io.contentWindow.document.execCommand) { 5281 io.contentWindow.document.execCommand('Stop'); 5282 } 5283 } 5284 catch(ignore) {} 5285 5286 $io.attr('src', s.iframeSrc); // abort op in progress 5287 xhr.error = e; 5288 if (s.error) { 5289 s.error.call(s.context, xhr, e, status); 5290 } 5291 if (g) { 5292 $.event.trigger("ajaxError", [xhr, s, e]); 5293 } 5294 if (s.complete) { 5295 s.complete.call(s.context, xhr, e); 5296 } 5297 } 5298 }; 5299 5300 g = s.global; 5301 // trigger ajax global events so that activity/block indicators work like normal 5302 if (g && 0 === $.active++) { 5303 $.event.trigger("ajaxStart"); 5304 } 5305 if (g) { 5306 $.event.trigger("ajaxSend", [xhr, s]); 5307 } 5308 5309 if (s.beforeSend && s.beforeSend.call(s.context, xhr, s) === false) { 5310 if (s.global) { 5311 $.active--; 5312 } 5313 deferred.reject(); 5314 return deferred; 5315 } 5316 if (xhr.aborted) { 5317 deferred.reject(); 5318 return deferred; 5319 } 5320 5321 // add submitting element to data if we know it 5322 sub = form.clk; 5323 if (sub) { 5324 n = sub.name; 5325 if (n && !sub.disabled) { 5326 s.extraData = s.extraData || {}; 5327 s.extraData[n] = sub.value; 5328 if (sub.type == "image") { 5329 s.extraData[n+'.x'] = form.clk_x; 5330 s.extraData[n+'.y'] = form.clk_y; 5331 } 5332 } 5333 } 5334 5335 var CLIENT_TIMEOUT_ABORT = 1; 5336 var SERVER_ABORT = 2; 5337 5338 function getDoc(frame) { 5339 /* it looks like contentWindow or contentDocument do not 5340 * carry the protocol property in ie8, when running under ssl 5341 * frame.document is the only valid response document, since 5342 * the protocol is know but not on the other two objects. strange? 5343 * "Same origin policy" http://en.wikipedia.org/wiki/Same_origin_policy 5344 */ 5345 5346 var doc = null; 5347 5348 // IE8 cascading access check 5349 try { 5350 if (frame.contentWindow) { 5351 doc = frame.contentWindow.document; 5352 } 5353 } catch(err) { 5354 // IE8 access denied under ssl & missing protocol 5355 log('cannot get iframe.contentWindow document: ' + err); 5356 } 5357 5358 if (doc) { // successful getting content 5359 return doc; 5360 } 5361 5362 try { // simply checking may throw in ie8 under ssl or mismatched protocol 5363 doc = frame.contentDocument ? frame.contentDocument : frame.document; 5364 } catch(err) { 5365 // last attempt 5366 log('cannot get iframe.contentDocument: ' + err); 5367 doc = frame.document; 5368 } 5369 return doc; 5370 } 5371 5372 // Rails CSRF hack (thanks to Yvan Barthelemy) 5373 var csrf_token = $('meta[name=csrf-token]').attr('content'); 5374 var csrf_param = $('meta[name=csrf-param]').attr('content'); 5375 if (csrf_param && csrf_token) { 5376 s.extraData = s.extraData || {}; 5377 s.extraData[csrf_param] = csrf_token; 5378 } 5379 5380 // take a breath so that pending repaints get some cpu time before the upload starts 5381 function doSubmit() { 5382 // make sure form attrs are set 5383 var t = $form.attr2('target'), 5384 a = $form.attr2('action'),
5385 mp = 'multipart/form-data', 5386 et = $form.attr('enctype') || $form.attr('encoding') || mp; 5387 5388 // update form attrs in IE friendly way 5389 form.setAttribute('target',id); 5390 if (!method || /post/i.test(method) ) { 5391 form.setAttribute('method', 'POST'); 5392 } 5393 if (a != s.url) { 5394 form.setAttribute('action', s.url); 5395 } 5396 5397 // ie borks in some cases when setting encoding 5398 if (! s.skipEncodingOverride && (!method || /post/i.test(method))) { 5399 $form.attr({ 5400 encoding: 'multipart/form-data', 5401 enctype: 'multipart/form-data' 5402 }); 5403 } 5404 5405 // support timout 5406 if (s.timeout) { 5407 timeoutHandle = setTimeout(function() { timedOut = true; cb(CLIENT_TIMEOUT_ABORT); }, s.timeout); 5408 } 5409 5410 // look for server aborts 5411 function checkState() { 5412 try { 5413 var state = getDoc(io).readyState; 5414 log('state = ' + state); 5415 if (state && state.toLowerCase() == 'uninitialized') { 5416 setTimeout(checkState,50); 5417 } 5418 } 5419 catch(e) { 5420 log('Server abort: ' , e, ' (', e.name, ')'); 5421 cb(SERVER_ABORT); 5422 if (timeoutHandle) { 5423 clearTimeout(timeoutHandle); 5424 } 5425 timeoutHandle = undefined; 5426 } 5427 } 5428 5429 // add "extra" data to form if provided in options 5430 var extraInputs = []; 5431 try { 5432 if (s.extraData) { 5433 for (var n in s.extraData) { 5434 if (s.extraData.hasOwnProperty(n)) { 5435 // if using the $.param format that allows for multiple values with the same name 5436 if($.isPlainObject(s.extraData[n]) && s.extraData[n].hasOwnProperty('name') && s.extraData[n].hasOwnProperty('value')) { 5437 extraInputs.push( 5438 $('<input type="hidden" name="'+s.extraData[n].name+'">').val(s.extraData[n].value) 5439 .appendTo(form)[0]); 5440 } else { 5441 extraInputs.push( 5442 $('<input type="hidden" name="'+n+'">').val(s.extraData[n]) 5443 .appendTo(form)[0]); 5444 } 5445 } 5446 } 5447 } 5448 5449 if (!s.iframeTarget) { 5450 // add iframe to doc and submit the form 5451 $io.appendTo('body'); 5452 } 5453 if (io.attachEvent) { 5454 io.attachEvent('onload', cb); 5455 } 5456 else { 5457 io.addEventListener('load', cb, false); 5458 } 5459 setTimeout(checkState,15); 5460 5461 try { 5462 form.submit(); 5463 } catch(err) { 5464 // just in case form has element with name/id of 'submit' 5465 var submitFn = document.createElement('form').submit; 5466 submitFn.apply(form); 5467 } 5468 } 5469 finally { 5470 // reset attrs and remove "extra" input elements 5471 form.setAttribute('action',a); 5472 form.setAttribute('enctype', et); // #380 5473 if(t) { 5474 form.setAttribute('target', t); 5475 } else { 5476 $form.removeAttr('target'); 5477 } 5478 $(extraInputs).remove(); 5479 } 5480 } 5481 5482 if (s.forceSync) { 5483 doSubmit(); 5484 } 5485 else { 5486 setTimeout(doSubmit, 10); // this lets dom updates render 5487 } 5488 5489 var data, doc, domCheckCount = 50, callbackProcessed; 5490 5491 function cb(e) { 5492 if (xhr.aborted || callbackProcessed) { 5493 return; 5494 } 5495 5496 doc = getDoc(io); 5497 if(!doc) { 5498 log('cannot access response document'); 5499 e = SERVER_ABORT; 5500 } 5501 if (e === CLIENT_TIMEOUT_ABORT && xhr) { 5502 xhr.abort('timeout'); 5503 deferred.reject(xhr, 'timeout'); 5504 return; 5505 } 5506 else if (e == SERVER_ABORT && xhr) { 5507 xhr.abort('server abort'); 5508 deferred.reject(xhr, 'error', 'server abort'); 5509 return; 5510 } 5511 5512 if (!doc || doc.location.href == s.iframeSrc) { 5513 // response not received yet 5514 if (!timedOut) { 5515 return; 5516 } 5517 } 5518 if (io.detachEvent) { 5519 io.detachEvent('onload', cb); 5520 } 5521 else { 5522 io.removeEventListener('load', cb, false); 5523 } 5524 5525 var status = 'success', errMsg; 5526 try { 5527 if (timedOut) { 5528 throw 'timeout'; 5529 } 5530 5531 var isXml = s.dataType == 'xml' || doc.XMLDocument || $.isXMLDoc(doc); 5532 log('isXml='+isXml); 5533 if (!isXml && window.opera && (doc.body === null || !doc.body.innerHTML)) { 5534 if (--domCheckCount) { 5535 // in some browsers (Opera) the iframe DOM is not always traversable when 5536 // the onload callback fires, so we loop a bit to accommodate 5537 log('requeing onLoad callback, DOM not available'); 5538 setTimeout(cb, 250); 5539 return; 5540 } 5541 // let this fall through because server response could be an empty document 5542 //log('Could not access iframe DOM after mutiple tries.'); 5543 //throw 'DOMException: not available'; 5544 } 5545 5546 //log('response detected'); 5547 var docRoot = doc.body ? doc.body : doc.documentElement; 5548 xhr.responseText = docRoot ? docRoot.innerHTML : null; 5549 xhr.responseXML = doc.XMLDocument ? doc.XMLDocument : doc; 5550 if (isXml) { 5551 s.dataType = 'xml'; 5552 } 5553 xhr.getResponseHeader = function(header){ 5554 var headers = {'content-type': s.dataType}; 5555 return headers[header.toLowerCase()]; 5556 }; 5557 // support for XHR 'status' & 'statusText' emulation : 5558 if (docRoot) { 5559 xhr.status = Number( docRoot.getAttribute('status') ) || xhr.status; 5560 xhr.statusText = docRoot.getAttribute('statusText') || xhr.statusText; 5561 } 5562 5563 var dt = (s.dataType || '').toLowerCase(); 5564 var scr = /(json|script|text)/.test(dt); 5565 if (scr || s.textarea) { 5566 // see if user embedded response in textarea 5567 var ta = doc.getElementsByTagName('textarea')[0]; 5568 if (ta) { 5569 xhr.responseText = ta.value; 5570 // support for XHR 'status' & 'statusText' emulation : 5571 xhr.status = Number( ta.getAttribute('status') ) || xhr.status; 5572 xhr.statusText = ta.getAttribute('statusText') || xhr.statusText; 5573 } 5574 else if (scr) { 5575 // account for browsers injecting pre around json response 5576 var pre = doc.getElementsByTagName('pre')[0]; 5577 var b = doc.getElementsByTagName('body')[0]; 5578 if (pre) { 5579 xhr.responseText = pre.textContent ? pre.textContent : pre.innerText; 5580 } 5581 else if (b) { 5582 xhr.responseText = b.textContent ? b.textContent : b.innerText; 5583 } 5584 } 5585 } 5586 else if (dt == 'xml' && !xhr.responseXML && xhr.responseText) { 5587 xhr.responseXML = toXml(xhr.responseText); 5588 } 5589 5590 try { 5591 data = httpData(xhr, dt, s); 5592 } 5593 catch (err) { 5594 status = 'parsererror'; 5595 xhr.error = errMsg = (err || status); 5596 } 5597 } 5598 catch (err) { 5599 log('error caught: ',err); 5600 status = 'error'; 5601 xhr.error = errMsg = (err || status); 5602 } 5603 5604 if (xhr.aborted) { 5605 log('upload aborted'); 5606 status = null; 5607 } 5608 5609 if (xhr.status) { // we've set xhr.status 5610 status = (xhr.status >= 200 && xhr.status < 300 || xhr.status === 304) ? 'success' : 'error'; 5611 } 5612 5613 // ordering of these callbacks/triggers is odd, but that's how $.ajax does it 5614 if (status === 'success') { 5615 if (s.success) { 5616 s.success.call(s.context, data, 'success', xhr); 5617 } 5618 deferred.resolve(xhr.responseText, 'success', xhr); 5619 if (g) { 5620 $.event.trigger("ajaxSuccess", [xhr, s]); 5621 } 5622 } 5623 else if (status) { 5624 if (errMsg === undefined) { 5625 errMsg = xhr.statusText; 5626 } 5627 if (s.error) { 5628 s.error.call(s.context, xhr, status, errMsg); 5629 } 5630 deferred.reject(xhr, 'error', errMsg); 5631 if (g) { 5632 $.event.trigger("ajaxError", [xhr, s, errMsg]); 5633 } 5634 } 5635 5636 if (g) {
5637 $.event.trigger("ajaxComplete", [xhr, s]); 5638 } 5639 5640 if (g && ! --$.active) { 5641 $.event.trigger("ajaxStop"); 5642 } 5643 5644 if (s.complete) { 5645 s.complete.call(s.context, xhr, status); 5646 } 5647 5648 callbackProcessed = true; 5649 if (s.timeout) { 5650 clearTimeout(timeoutHandle); 5651 } 5652 5653 // clean up 5654 setTimeout(function() { 5655 if (!s.iframeTarget) { 5656 $io.remove(); 5657 } 5658 else { //adding else to clean up existing iframe response. 5659 $io.attr('src', s.iframeSrc); 5660 } 5661 xhr.responseXML = null; 5662 }, 100); 5663 } 5664 5665 var toXml = $.parseXML || function(s, doc) { // use parseXML if available (jQuery 1.5+) 5666 if (window.ActiveXObject) { 5667 doc = new ActiveXObject('Microsoft.XMLDOM'); 5668 doc.async = 'false'; 5669 doc.loadXML(s); 5670 } 5671 else { 5672 doc = (new DOMParser()).parseFromString(s, 'text/xml'); 5673 } 5674 return (doc && doc.documentElement && doc.documentElement.nodeName != 'parsererror') ? doc : null; 5675 }; 5676 var parseJSON = $.parseJSON || function(s) { 5677 /*jslint evil:true */ 5678 return window['eval']('(' + s + ')'); 5679 }; 5680 5681 var httpData = function( xhr, type, s ) { // mostly lifted from jq1.4.4 5682 5683 var ct = xhr.getResponseHeader('content-type') || '', 5684 xml = type === 'xml' || !type && ct.indexOf('xml') >= 0, 5685 data = xml ? xhr.responseXML : xhr.responseText; 5686 5687 if (xml && data.documentElement.nodeName === 'parsererror') { 5688 if ($.error) { 5689 $.error('parsererror'); 5690 } 5691 } 5692 if (s && s.dataFilter) { 5693 data = s.dataFilter(data, type); 5694 } 5695 if (typeof data === 'string') { 5696 if (type === 'json' || !type && ct.indexOf('json') >= 0) { 5697 data = parseJSON(data); 5698 } else if (type === "script" || !type && ct.indexOf("javascript") >= 0) { 5699 $.globalEval(data); 5700 } 5701 } 5702 return data; 5703 }; 5704 5705 return deferred; 5706 } 5707 }; 5708 5709 /** 5710 * ajaxForm() provides a mechanism for fully automating form submission. 5711 * 5712 * The advantages of using this method instead of ajaxSubmit() are: 5713 * 5714 * 1: This method will include coordinates for <input type="image" /> elements (if the element 5715 * is used to submit the form). 5716 * 2. This method will include the submit element's name/value data (for the element that was 5717 * used to submit the form). 5718 * 3. This method binds the submit() method to the form for you. 5719 * 5720 * The options argument for ajaxForm works exactly as it does for ajaxSubmit. ajaxForm merely 5721 * passes the options argument along after properly binding events for submit elements and 5722 * the form itself. 5723 */ 5724 $.fn.ajaxForm = function(options) { 5725 options = options || {}; 5726 options.delegation = options.delegation && $.isFunction($.fn.on); 5727 5728 // in jQuery 1.3+ we can fix mistakes with the ready state 5729 if (!options.delegation && this.length === 0) { 5730 var o = { s: this.selector, c: this.context }; 5731 if (!$.isReady && o.s) { 5732 log('DOM not ready, queuing ajaxForm'); 5733 $(function() { 5734 $(o.s,o.c).ajaxForm(options); 5735 }); 5736 return this; 5737 } 5738 // is your DOM ready? http://docs.jquery.com/Tutorials:Introducing_$(document).ready() 5739 log('terminating; zero elements found by selector' + ($.isReady ? '' : ' (DOM not ready)')); 5740 return this; 5741 } 5742 5743 if ( options.delegation ) { 5744 $(document) 5745 .off('submit.form-plugin', this.selector, doAjaxSubmit) 5746 .off('click.form-plugin', this.selector, captureSubmittingElement) 5747 .on('submit.form-plugin', this.selector, options, doAjaxSubmit) 5748 .on('click.form-plugin', this.selector, options, captureSubmittingElement); 5749 return this; 5750 } 5751 5752 return this.ajaxFormUnbind() 5753 .bind('submit.form-plugin', options, doAjaxSubmit) 5754 .bind('click.form-plugin', options, captureSubmittingElement); 5755 }; 5756 5757 // private event handlers 5758 function doAjaxSubmit(e) { 5759 /*jshint validthis:true */ 5760 var options = e.data; 5761 if (!e.isDefaultPrevented()) { // if event has been canceled, don't proceed 5762 e.preventDefault(); 5763 $(e.target).ajaxSubmit(options); // #365 5764 } 5765 } 5766 5767 function captureSubmittingElement(e) { 5768 /*jshint validthis:true */ 5769 var target = e.target; 5770 var $el = $(target); 5771 if (!($el.is("[type=submit],[type=image]"))) { 5772 // is this a child element of the submit el? (ex: a span within a button) 5773 var t = $el.closest('[type=submit]'); 5774 if (t.length === 0) { 5775 return; 5776 } 5777 target = t[0]; 5778 } 5779 var form = this; 5780 form.clk = target; 5781 if (target.type == 'image') { 5782 if (e.offsetX !== undefined) { 5783 form.clk_x = e.offsetX; 5784 form.clk_y = e.offsetY; 5785 } else if (typeof $.fn.offset == 'function') { 5786 var offset = $el.offset(); 5787 form.clk_x = e.pageX - offset.left; 5788 form.clk_y = e.pageY - offset.top; 5789 } else { 5790 form.clk_x = e.pageX - target.offsetLeft; 5791 form.clk_y = e.pageY - target.offsetTop; 5792 } 5793 } 5794 // clear form vars 5795 setTimeout(function() { form.clk = form.clk_x = form.clk_y = null; }, 100); 5796 } 5797 5798 5799 // ajaxFormUnbind unbinds the event handlers that were bound by ajaxForm 5800 $.fn.ajaxFormUnbind = function() { 5801 return this.unbind('submit.form-plugin click.form-plugin'); 5802 }; 5803 5804 /** 5805 * formToArray() gathers form element data into an array of objects that can 5806 * be passed to any of the following ajax functions: $.get, $.post, or load. 5807 * Each object in the array has both a 'name' and 'value' property. An example of 5808 * an array for a simple login form might be: 5809 * 5810 * [ { name: 'username', value: 'jresig' }, { name: 'password', value: 'secret' } ] 5811 * 5812 * It is this array that is passed to pre-submit callback functions provided to the 5813 * ajaxSubmit() and ajaxForm() methods. 5814 */ 5815 $.fn.formToArray = function(semantic, elements) { 5816 var a = []; 5817 if (this.length === 0) { 5818 return a; 5819 } 5820 5821 var form = this[0]; 5822 var formId = this.attr('id'); 5823 var els = semantic ? form.getElementsByTagName('*') : form.elements; 5824 var els2; 5825 5826 if (els && !/MSIE [678]/.test(navigator.userAgent)) { // #390 5827 els = $(els).get(); // convert to standard array 5828 } 5829 5830 // #386; account for inputs outside the form which use the 'form' attribute 5831 if ( formId ) { 5832 els2 = $(':input[form=' + formId + ']').get(); 5833 if ( els2.length ) { 5834 els = (els || []).concat(els2); 5835 } 5836 } 5837 5838 if (!els || !els.length) { 5839 return a; 5840 } 5841 5842 var i,j,n,v,el,max,jmax;
5843 for(i=0, max=els.length; i < max; i++) { 5844 el = els[i]; 5845 n = el.name; 5846 if (!n || el.disabled) { 5847 continue; 5848 } 5849 5850 if (semantic && form.clk && el.type == "image") { 5851 // handle image inputs on the fly when semantic == true 5852 if(form.clk == el) { 5853 a.push({name: n, value: $(el).val(), type: el.type }); 5854 a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y}); 5855 } 5856 continue; 5857 } 5858 5859 v = $.fieldValue(el, true); 5860 if (v && v.constructor == Array) { 5861 if (elements) { 5862 elements.push(el); 5863 } 5864 for(j=0, jmax=v.length; j < jmax; j++) { 5865 a.push({name: n, value: v[j]}); 5866 } 5867 } 5868 else if (feature.fileapi && el.type == 'file') { 5869 if (elements) { 5870 elements.push(el); 5871 } 5872 var files = el.files; 5873 if (files.length) { 5874 for (j=0; j < files.length; j++) { 5875 a.push({name: n, value: files[j], type: el.type}); 5876 } 5877 } 5878 else { 5879 // #180 5880 a.push({ name: n, value: '', type: el.type }); 5881 } 5882 } 5883 else if (v !== null && typeof v != 'undefined') { 5884 if (elements) { 5885 elements.push(el); 5886 } 5887 a.push({name: n, value: v, type: el.type, required: el.required}); 5888 } 5889 } 5890 5891 if (!semantic && form.clk) { 5892 // input type=='image' are not found in elements array! handle it here 5893 var $input = $(form.clk), input = $input[0]; 5894 n = input.name; 5895 if (n && !input.disabled && input.type == 'image') { 5896 a.push({name: n, value: $input.val()}); 5897 a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y}); 5898 } 5899 } 5900 return a; 5901 }; 5902 5903 /** 5904 * Serializes form data into a 'submittable' string. This method will return a string 5905 * in the format: name1=value1&name2=value2 5906 */ 5907 $.fn.formSerialize = function(semantic) { 5908 //hand off to jQuery.param for proper encoding 5909 return $.param(this.formToArray(semantic)); 5910 }; 5911 5912 /** 5913 * Serializes all field elements in the jQuery object into a query string. 5914 * This method will return a string in the format: name1=value1&name2=value2 5915 */ 5916 $.fn.fieldSerialize = function(successful) { 5917 var a = []; 5918 this.each(function() { 5919 var n = this.name; 5920 if (!n) { 5921 return; 5922 } 5923 var v = $.fieldValue(this, successful); 5924 if (v && v.constructor == Array) { 5925 for (var i=0,max=v.length; i < max; i++) { 5926 a.push({name: n, value: v[i]}); 5927 } 5928 } 5929 else if (v !== null && typeof v != 'undefined') { 5930 a.push({name: this.name, value: v}); 5931 } 5932 }); 5933 //hand off to jQuery.param for proper encoding 5934 return $.param(a); 5935 }; 5936 5937 /** 5938 * Returns the value(s) of the element in the matched set. For example, consider the following form: 5939 * 5940 * <form><fieldset> 5941 * <input name="A" type="text" /> 5942 * <input name="A" type="text" /> 5943 * <input name="B" type="checkbox" value="B1" /> 5944 * <input name="B" type="checkbox" value="B2"/> 5945 * <input name="C" type="radio" value="C1" /> 5946 * <input name="C" type="radio" value="C2" /> 5947 * </fieldset></form> 5948 * 5949 * var v = $('input[type=text]').fieldValue(); 5950 * // if no values are entered into the text inputs 5951 * v == ['',''] 5952 * // if values entered into the text inputs are 'foo' and 'bar' 5953 * v == ['foo','bar'] 5954 * 5955 * var v = $('input[type=checkbox]').fieldValue(); 5956 * // if neither checkbox is checked 5957 * v === undefined 5958 * // if both checkboxes are checked 5959 * v == ['B1', 'B2'] 5960 * 5961 * var v = $('input[type=radio]').fieldValue(); 5962 * // if neither radio is checked 5963 * v === undefined 5964 * // if first radio is checked 5965 * v == ['C1'] 5966 * 5967 * The successful argument controls whether or not the field element must be 'successful' 5968 * (per http://www.w3.org/TR/html4/interact/forms.html#successful-control
5968s). 5969 * The default value of the successful argument is true. If this value is false the value(s) 5970 * for each element is returned. 5971 * 5972 * Note: This method *always* returns an array. If no valid value can be determined the 5973 * array will be empty, otherwise it will contain one or more values. 5974 */ 5975 $.fn.fieldValue = function(successful) { 5976 for (var val=[], i=0, max=this.length; i < max; i++) { 5977 var el = this[i]; 5978 var v = $.fieldValue(el, successful); 5979 if (v === null || typeof v == 'undefined' || (v.constructor == Array && !v.length)) { 5980 continue; 5981 } 5982 if (v.constructor == Array) { 5983 $.merge(val, v); 5984 } 5985 else { 5986 val.push(v); 5987 } 5988 } 5989 return val; 5990 }; 5991 5992 /** 5993 * Returns the value of the field element. 5994 */ 5995 $.fieldValue = function(el, successful) { 5996 var n = el.name, t = el.type, tag = el.tagName.toLowerCase(); 5997 if (successful === undefined) { 5998 successful = true; 5999 } 6000 6001 if (successful && (!n || el.disabled || t == 'reset' || t == 'button' || 6002 (t == 'checkbox' || t == 'radio') && !el.checked || 6003 (t == 'submit' || t == 'image') && el.form && el.form.clk != el || 6004 tag == 'select' && el.selectedIndex == -1)) { 6005 return null; 6006 } 6007 6008 if (tag == 'select') { 6009 var index = el.selectedIndex; 6010 if (index < 0) { 6011 return null; 6012 } 6013 var a = [], ops = el.options; 6014 var one = (t == 'select-one'); 6015 var max = (one ? index+1 : ops.length); 6016 for(var i=(one ? index : 0); i < max; i++) { 6017 var op = ops[i]; 6018 if (op.selected) { 6019 var v = op.value; 6020 if (!v) { // extra pain for IE... 6021 v = (op.attributes && op.attributes.value && !(op.attributes.value.specified)) ? op.text : op.value; 6022 } 6023 if (one) { 6024 return v; 6025 } 6026 a.push(v); 6027 } 6028 } 6029 return a; 6030 } 6031 return $(el).val(); 6032 }; 6033 6034 /** 6035 * Clears the form data. Takes the following actions on the form's input fields: 6036 * - input text fields will have their 'value' property set to the empty string 6037 * - select elements will have their 'selectedIndex' property set to -1 6038 * - checkbox and radio inputs will have their 'checked' property set to false 6039 * - inputs of type submit, button, reset, and hidden will *not* be effected 6040 * - button elements will *not* be effected 6041 */ 6042 $.fn.clearForm = function(includeHidden) { 6043 return this.each(function() { 6044 $('input,select,textarea', this).clearFields(includeHidden); 6045 }); 6046 }; 6047 6048 /** 6049 * Clears the selected form elements. 6050 */ 6051 $.fn.clearFields = $.fn.clearInputs = function(includeHidden) { 6052 var re = /^(?:color|date|datetime|email|month|number|password|range|search|tel|text|time|url|week)$/i; // 'hidden' is not in this list 6053 return this.each(function() { 6054 var t = this.type, tag = this.tagName.toLowerCase(); 6055 if (re.test(t) || tag == 'textarea') { 6056 this.value = ''; 6057 } 6058 else if (t == 'checkbox' || t == 'radio') { 6059 this.checked = false; 6060 } 6061 else if (tag == 'select') { 6062 this.selectedIndex = -1; 6063 } 6064 else if (t == "file") { 6065 if (/MSIE/.test(navigator.userAgent)) { 6066 $(this).replaceWith($(this).clone(true)); 6067 } else { 6068 $(this).val(''); 6069 } 6070 } 6071 else if (includeHidden) { 6072 // includeHidden can be the value true, or it can be a selector string 6073 // indicating a special test; for example: 6074 // $('#myForm').clearForm('.special:hidden') 6075 // the above would clean hidden inputs that have the class of 'special' 6076 if ( (includeHidden === true && /hidden/.test(t)) || 6077 (typeof includeHidden == 'string' && $(this).is(includeHidden)) ) { 6078 this.value = ''; 6079 } 6080 } 6081 }); 6082 }; 6083 6084 /** 6085 * Resets the form data. Causes all form elements to be reset to their original value. 6086 */ 6087 $.fn.resetForm = function() { 6088 return this.each(function() { 6089 // guard against an input with the name of 'reset' 6090 // note that IE reports the reset function as an 'object' 6091 if (typeof this.reset == 'function' || (typeof this.reset == 'object' && !this.reset.nodeType)) { 6092 this.reset(); 6093 } 6094 }); 6095 }; 6096 6097 /** 6098 * Enables or disables any matching elements. 6099 */ 6100 $.fn.enable = function(b) { 6101 if (b === undefined) { 6102 b = true; 6103 } 6104 return this.each(function() { 6105 this.disabled = !b; 6106 }); 6107 }; 6108 6109 /** 6110 * Checks/unchecks any matching checkboxes or radio buttons and 6111 * selects/deselects and matching option elements. 6112 */ 6113 $.fn.selected = function(select) { 6114 if (select === undefined) { 6115 select = true; 6116 } 6117 return this.each(function() { 6118 var t = this.type; 6119 if (t == 'checkbox' || t == 'radio') { 6120 this.checked = select; 6121 } 6122 else if (this.tagName.toLowerCase() == 'option') { 6123 var $sel = $(this).parent('select'); 6124 if (select && $sel[0] && $sel[0].type == 'select-one') { 6125 // deselect all other options 6126 $sel.find('option').selected(false); 6127 } 6128 this.selected = select; 6129 } 6130 }); 6131 }; 6132 6133 // expose debug var 6134 $.fn.ajaxSubmit.debug = false;
6135 6136 // helper fn for console logging 6137 function log() { 6138 if (!$.fn.ajaxSubmit.debug) { 6139 return; 6140 } 6141 var msg = '[jquery.form] ' + Array.prototype.join.call(arguments,''); 6142 if (window.console && window.console.log) { 6143 window.console.log(msg); 6144 } 6145 else if (window.opera && window.opera.postError) { 6146 window.opera.postError(msg); 6147 } 6148 } 6149 6150 })); 6151 6152 6153/***/ }), 6154 6155/***/ 317: 6156/***/ (function(module, exports) { 6157 6158 ;(function($) { 6159 $.fn.fullformWizard = function (options) { 6160 var $$this = $(this); 6161 6162 var wizard = { 6163 settings: { 6164 submitHandle: null, 6165 submitHtml: null, 6166 startStep: ':first', 6167 elementHandle: '.wizard__step', 6168 nextPage: '2', 6169 debug: false, 6170 validate: true, 6171 lastStep: function () {}, 6172 onEdit: function () {}, 6173 onEditCancel: function () {}, 6174 translate: { 6175 buttonEdit: 'edit', 6176 buttonCancel: 'cancel', 6177 buttonSubmit: 'submit', 6178 buttonNext: 'next', 6179 serverResponseError: 'server error' 6180 } 6181 }, 6182 formElements: 'input, select, textarea', 6183 currentStep: null, 6184 savedStep: null, 6185 activeStep: null, 6186 nextStep: null, 6187 prevStep: null, 6188 elements: null, 6189 lastStep: false, 6190 lastStepCompleted: false 6191 }; 6192 6193 wizard.validationSettings = { 6194 debug: wizard.settings.debug, 6195 errorClass: 'error', 6196 errorElement: 'div', 6197 highlight: $.validateHighlight, 6198 unhighlight: $.validateUnhighlight, 6199 errorPlacement: function (error, element) { 6200 var elem = { 6201 height: element.outerHeight(), 6202 width: element.outerWidth(), 6203 position: element.position() 6204 } 6205 6206 var errorHtml = '<div class="error-box">'; 6207 errorHtml += '<div class="error-arrow"></div>'; 6208 errorHtml += '</div>'; 6209 6210 var errorBox = $(errorHtml).append(error); 6211 6212 element.after(errorBox); 6213 6214 var errorWidth = element.next('.error-box').width(); 6215 var errorBoxCss = { 6216 'position': 'absolute', 6217 'top': elem.position.top + elem.height, 6218 'left': elem.position.left, 6219 }; 6220 6221 if (errorWidth > elem.width){ 6222 errorBoxCss['left'] = '50%' 6223 errorBoxCss['margin-left'] = -errorWidth/2; 6224 element.next('.error-box').find('.error-arrow') 6225 .css({ 6226 'left': '50%', 6227 'margin-left': -6, 6228 'position': 'relative' 6229 }) 6230 } 6231 6232 element 6233 .next('.error-box') 6234 .css(errorBoxCss) 6235 .append(error); 6236 } 6237 } 6238 6239 // default submit stuff 6240 wizard.settings.defaultSubmitHandle = 'button[type="submit"]'; 6241 wizard.settings.defaultSubmitHtml = '<div class="submit"><button type="submit">'+wizard.settings.translate.buttonNext+'</button></div>' 6242 6243 // allow overwrite of default settings 6244 $.extend(wizard.settings, options); 6245 6246 wizard.show = function (target) { 6247 if ($(target).is(':visible')) { 6248 return; 6249 } 6250 6251 $(target).slideDown(250, 'linear', function () { 6252 wizard.scrollTo(target); 6253 }); 6254 6255 wizard.updateSteps(); 6256 }; 6257 6258 wizard.scrollTo = function (target) { 6259 // check if targt exists 6260 if (typeof (target.offset()) !== 'undefined') { 6261 var endPosition = target.offset().top; 6262 $('html, body').animate({ 6263 scrollTop: endPosition 6264 }, 150); 6265 } 6266 }; 6267 6268 // updates currentStep and nextStep 6269 wizard.updateSteps = function () { 6270 if (wizard.lastStep) { 6271 return; 6272 } 6273 wizard.completeStep(wizard.currentStep); 6274 wizard.currentStep = wizard.currentStep.next(wizard.settings.elementHandle); 6275 wizard.nextStep = wizard.currentStep.next(wizard.settings.elementHandle); 6276 if (wizard.nextStep.length <= 0) { 6277 wizard.lastStep = true; 6278 } 6279 }; 6280 6281 wizard.enableFormFunctions = function () { 6282 $$this.find('.form__section__edit, '+wizard.settings.submitHandle) 6283 .not('.keep-disabled') 6284 .attr('disabled', false) 6285 .removeClass('disabled'); 6286 } 6287 wizard.disableFormFunctions = function (step) { 6288 $$this.find('.form__section__edit, '+wizard.settings.submitHandle) 6289 .attr('disabled', true) 6290 .addClass('disabled'); 6291 } 6292 6293 /** binds validation to step **/ 6294 wizard.validateStep = function (step) {
6295 var validationTarget = step.get(0); 6296 var settings = wizard.validationSettings; 6297 6298 // check if validation rules are set 6299 if (typeof(wizard.settings.validation) !== 'undefined') { 6300 var validation = wizard.settings.validation[validationTarget.id]; 6301 6302 if (typeof(validation) !== 'undefined') { 6303 settings.rules = validation.rules; 6304 settings.messages = validation.messages; 6305 } 6306 } 6307 6308 step.validate(settings); 6309 } 6310 6311 /** enables all form elements and show form submit elements **/ 6312 wizard.enableStep = function (step) { 6313 wizard.activeStep = step; 6314 6315 $(step).find(wizard.formElements).not('.keep-disabled').attr('disabled', false); 6316 6317 if ($(step).find('.form__section__edit').length > 0) { 6318 $(step).find('button[type="submit"]').parent('div').show(); 6319 } 6320 } 6321 6322 /** disables all form elements and hides form submit elements **/ 6323 wizard.disableStep = function (step) { 6324 wizard.activeStep = null; 6325 6326 $(step).find(wizard.formElements).attr('disabled', true); 6327 $(step).find('button[type="submit"]').parent('div').hide(); 6328 } 6329 6330 /** adds edit elements **/ 6331 wizard.completeStep = function (step) { 6332 6333 wizard.disableStep(step); 6334 6335 if ($(step).is('form')) { 6336 var editButton = '<button type="button" class="form__section__edit">'+wizard.settings.translate.buttonEdit+'</button>', 6337 cancelButton = '<button type="button" class="form__section__cancel">'+wizard.settings.translate.buttonCancel+'</button>'; 6338 // add edit button if not present 6339 if ($(step).find('.form__section__edit').length <= 0) { 6340 $(step).find('.form__section__header').append(editButton); 6341 } 6342 if ($(step).find('.form__section__cancel').length <= 0) { 6343 $(step).find('button[type="submit"]').after(cancelButton); 6344 } 6345 } 6346 } 6347 6348 /** triggered by edit button 6349 /** remove errors, disable active step, highlight edit step **/ 6350 wizard.editStep = function (step) { 6351 wizard.activeStep = null; 6352 wizard.settings.onEdit($$this, step); 6353 6354 wizard.savedStep = step.html(); 6355 6356 // remove errors from current step 6357 $(wizard.currentStep).find(wizard.formElements).removeClass('error'); 6358 $(wizard.currentStep).find('.error-box').remove(); 6359 6360 wizard.disableStep(wizard.currentStep); 6361 wizard.disableFormFunctions(step); 6362 wizard.enableStep(step); 6363 } 6364 6365 wizard.submitStep = function(step, callback) { 6366 6367 var response = { 6368 ok: true, 6369 content: null 6370 } 6371 6372 // configure ajax submit here 6373 // handle errors, response 6374 6375 $(step).ajaxSubmit({ 6376 url: '/customer-evaluation/ajax/submit-step/', 6377 beforeSend: function () { 6378 $$this.find('button').attr('disabled', true); 6379 if (wizard.settings.debug){ 6380 console.log('... submitting data'); 6381 } 6382 }, 6383 success: function (data, statusMsg) { 6384 // TODO: pass server success to response 6385 response.ok = true; 6386 response.content = data; 6387 }, 6388 error: function (data, statusMsg) { 6389 // TODO: pass server error message to response 6390 console.log('ajax error') 6391 }, 6392 complete: function () { 6393 $$this.find('button').not('.keep-disabled').attr('disabled', false); 6394 6395 // return response in callback function 6396 if (typeof(callback) !== 'undefined' && typeof(callback) == 'function') { 6397 callback(response); 6398 } 6399 } 6400 }); 6401 } 6402 6403 wizard.setup = function () { 6404 6405 // find all elements 6406 if (typeof (wizard.settings.elements) === 'undefined') { 6407 wizard.elements = $$this.find(wizard.settings.elementHandle); 6408 } else { 6409 wizard.elements = $(wizard.settings.elements); 6410 wizard.elements.addClass('wizard__step'); 6411 } 6412 6413 // hide all elements, show startElement and all preceeding elements 6414 // if window.location.hash set startstep accordingly 6415 if ( typeof(window.location.hash) !== 'undefinded' && window.location.hash.length > 2) { 6416 // check if hash is a wizard element 6417 var windowHash = wizard.elements.filter(window.location.hash).length; 6418 if (windowHash > 0) { 6419 // overwrite startStep 6420 wizard.settings.startStep = window.location.hash; 6421 } 6422 } 6423 6424 // add binding 6425 $$this.on('click', wizard.settings.submitHandle, function(e) { 6426 e.preventDefault(); 6427 e.stopPropagation(); 6428 6429 var $$form = null; 6430 if (wizard.currentStep.is('form')){ 6431 $$form = wizard.currentStep; 6432 } else { 6433 $$form = wizard.currentStep.find('form'); 6434 } 6435 6436 if ($$form.length > 0) {
6437 if (wizard.settings.validate){ 6438 6439 // check if form is valid and proceed 6440 if($$form.valid()) { 6441 6442 // if all steps are completed submit redirects to nextPage 6443 if (wizard.lastStep && wizard.lastStepCompleted) { 6444 6445 // placing the nextPage var in front of the hash 6446 var newPath = window.location.pathname.replace(/([0-9a-f]{32})(?=\/)/g, wizard.settings.nextPage+'/$1'); 6447 //newPath += window.location.search; 6448 //newPath += window.location.hash; 6449 6450 window.location = newPath; 6451 return; 6452 } 6453 6454 // call laststep function and returns if last step 6455 if (wizard.lastStep) { 6456 wizard.settings.lastStep($$this, wizard.currentStep); 6457 return; 6458 } 6459 6460 wizard.submitStep($$form, function (data) { 6461 if (data.ok) { 6462 // show next step 6463 wizard.show(wizard.nextStep); 6464 6465 var newContent = $(data.content); 6466 $$form.replaceWith(newContent); 6467 6468 // add edit functionality to newContent 6469 wizard.completeStep(newContent); 6470 6471 wizard.enableFormFunctions(); 6472 6473 if (!wizard.lastStepCompleted) { 6474 wizard.enableStep(wizard.currentStep); 6475 } 6476 6477 6478 // rebind validation 6479 wizard.validateStep(newContent); 6480 } 6481 }); 6482 } 6483 } 6484 } else { 6485 // if its not a form but the last step, call lastStep function 6486 if (wizard.lastStep) { 6487 wizard.settings.lastStep($$this, wizard.currentStep); 6488 } 6489 } 6490 }); 6491 6492 $$this.on('submit', wizard.activeStep, function (e) { 6493 e.preventDefault(); 6494 e.stopPropagation(); 6495 6496 if (wizard.settings.validate){ 6497 6498 // check if form is valid and proceed 6499 if(wizard.activeStep.valid()) { 6500 6501 wizard.submitStep(wizard.activeStep, function (data) { 6502 6503 if (data.ok) { 6504 var newContent = $(data.content); 6505 wizard.activeStep.replaceWith(newContent); 6506 6507 // add edit functionality to newContent 6508 wizard.completeStep(newContent); 6509 6510 wizard.enableFormFunctions(); 6511 6512 // highlight step active before edit 6513 if (!wizard.lastStepCompleted) { 6514 wizard.enableStep(wizard.currentStep); 6515 } 6516 // rebind validation 6517 wizard.validateStep(newContent); 6518 } 6519 }); 6520 } 6521 } 6522 }); 6523 6524 // bind click event to edit button 6525 $$this.on('click', '.form__section__edit', function (e) { 6526 var sourceStep = $(this).parents('form'); 6527 e.preventDefault(); 6528 e.stopPropagation(); 6529 6530 wizard.editStep(sourceStep); 6531 }); 6532 6533 6534 // bind click event to cancel button 6535 $('body').on('click', '.form__section__cancel', function (e) { 6536 e.preventDefault(); 6537 e.stopPropagation(); 6538 6539 wizard.activeStep.html(wizard.savedStep); 6540 wizard.savedStep = null; 6541 wizard.settings.onEditCancel($$this, wizard.activeStep); 6542 6543 // disable edit functionality & enable currentStep which is not completed yet 6544 wizard.disableStep(wizard.activeStep); 6545 6546 wizard.enableFormFunctions(); 6547 if (!wizard.lastStepCompleted) { 6548 wizard.enableStep(wizard.currentStep); 6549 } 6550 }); 6551 6552 // bind validation 6553 $.each(wizard.elements, function (i, element) { 6554 if (typeof(element !== 'undefined')) { 6555 var $$element = $(element); 6556 6557 // hide submit button 6558 $$element.find('[type="submit"]').parent('div').hide(); 6559 6560 // call calidation 6561 wizard.validateStep($$element); 6562 } 6563 }) 6564 6565 // init wizard steps 6566 if (wizard.elements.filter(wizard.settings.startStep).length <= 0 || wizard.settings.startStep == ':first') { 6567 wizard.currentStep = wizard.elements.filter(':first'); 6568 } else { 6569 // startStep = last finished step, so define the following step as currentStep 6570 wizard.currentStep = wizard.elements.filter(wizard.settings.startStep).next(wizard.settings.elementHandle); 6571 if (wizard.currentStep.length <= 0) { 6572 wizard.lastStepCompleted = true; 6573 wizard.currentStep = wizard.elements.filter(wizard.settings.startStep); 6574 } 6575 } 6576 6577 wizard.nextStep = wizard.elements.filter(wizard.currentStep).next(wizard.settings.elementHandle); 6578 if (wizard.nextStep.length <= 0) { 6579 wizard.lastStep = true; 6580 } 6581 6582 if (wizard.lastStep && wizard.lastStepCompleted) { 6583 wizard.elements.each(function () { 6584 wizard.completeStep(this); 6585 }); 6586 } else { 6587 wizard.elements.hide() 6588 .filter(wizard.currentStep).show() 6589 .prevAll(wizard.settings.elementHandle).each(function () { 6590 $(this).show(); 6591 wizard.completeStep(this); 6592 }) 6593 } 6594 6595 //wizard.enableStep(wizard.currentStep); 6596 //wizard.editStep(wizard.currentStep); 6597 6598 // APPEND SUBMIT 6599 // check if a submitHandle is defined 6600 if (wizard.settings.submitHandle === null || wizard.settings.submitHtml === null) { 6601 // use default submit elements 6602 $$this.append(wizard.defaultSubmitHtml); 6603 wizard.settings.submitHandle = wizard.defaultSubmitHandle; 6604 } else { 6605 // append custom submit elements 6606 $$this.append(wizard.settings.submitHtml); 6607 } 6608 6609 6610 } 6611 6612 wizard.setup(); 6613 return $$this; 6614 }; 6615 })(jQuery); 6616 6617/***/ }), 6618 6619/***/ 318:
6620/***/ (function(module, exports) { 6621 6622 // as seen here http://stackoverflow.com/questions/18422223/bootstrap-3-modal-vertical-position-center 6623 function adjustModalMaxHeightAndPosition(){ 6624 $('.modal').each(function(){ 6625 if($(this).hasClass('in') === false){ 6626 $(this).show(); /* Need this to get modal dimensions */ 6627 } 6628 var contentHeight = $(window).height() - 60; 6629 var headerHeight = $(this).find('.modal-header').outerHeight() || 2; 6630 var footerHeight = $(this).find('.modal-footer').outerHeight() || 2; 6631 6632 $(this).find('.modal-content').css({ 6633 'max-height': function () { 6634 return contentHeight; 6635 } 6636 }); 6637 6638 $(this).find('.modal-body').css({ 6639 'max-height': function () { 6640 return (contentHeight - (headerHeight + footerHeight)); 6641 } 6642 }); 6643 6644 $(this).find('.modal-dialog').addClass('modal-dialog-center').css({ 6645 'margin-top': function () { 6646 return -($(this).outerHeight() / 2); 6647 }, 6648 'margin-left': function () { 6649 return -($(this).outerWidth() / 2); 6650 } 6651 }); 6652 if($(this).hasClass('in') === false){ 6653 $(this).hide(); /* Hide modal */ 6654 } 6655 }); 6656 } 6657 if ($(window).height() >= 320){ 6658 $(window).resize(adjustModalMaxHeightAndPosition).trigger("resize"); 6659 } 6660 6661/***/ }), 6662 6663/***/ 319: 6664/***/ (function(module, exports, __webpack_require__) { 6665 6666 var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/** 6667 * bootbox.js [v4.2.0] 6668 * 6669 * http://bootboxjs.com/license.txt 6670 */ 6671 6672 // @see https://github.com/makeusabrew/bootbox/issues/180 6673 // @see https://github.com/makeusabrew/bootbox/issues/186 6674 (function (root, factory) { 6675 6676 "use strict"; 6677 if (true) { 6678 // AMD. Register as an anonymous module. 6679 !(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__(270)], __WEBPACK_AMD_DEFINE_FACTORY__ = (factory), __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? (__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); 6680 } else if (typeof exports === "object") { 6681 // Node. Does not work with strict CommonJS, but 6682 // only CommonJS-like environments that support module.exports, 6683 // like Node. 6684 module.exports = factory(require("jquery")); 6685 } else { 6686 // Browser globals (root is window) 6687 root.bootbox = factory(root.jQuery); 6688 } 6689 6690 }(this, function init($, undefined) { 6691 6692 "use strict"; 6693 6694 // the base DOM structure needed to create a modal 6695 var templates = { 6696 dialog: 6697 "<div class='bootbox modal' tabindex='-1' role='dialog'>" + 6698 "<div class='modal-dialog'>" + 6699 "<div class='modal-content'>" + 6700 "<div class='modal-body'><div class='bootbox-body'></div></div>" + 6701 "</div>" + 6702 "</div>" + 6703 "</div>", 6704 header: 6705 "<div class='modal-header'>" + 6706 "<h4 class='modal-title'></h4>" + 6707 "</div>", 6708 footer: 6709 "<div class='modal-footer'></div>", 6710 closeButton: 6711 "<button type='button' class='bootbox-close-button close' data-dismiss='modal' aria-hidden='true'>×</button>", 6712 form: 6713 "<form class='bootbox-form'></form>", 6714 inputs: { 6715 text: 6716 "<input class='bootbox-input bootbox-input-text form-control' autocomplete=off type=text />", 6717 textarea: 6718 "<textarea class='bootbox-input bootbox-input-textarea form-control'></textarea>", 6719 email: 6720 "<input class='bootbox-input bootbox-input-email form-control' autocomplete='off' type='email' />", 6721 select: 6722 "<select class='bootbox-input bootbox-input-select form-control'></select>", 6723 checkbox: 6724 "<div class='checkbox'><label>
6724<input class='bootbox-input bootbox-input-checkbox' type='checkbox' /></label></div>", 6725 date: 6726 "<input class='bootbox-input bootbox-input-date form-control' autocomplete=off type='date' />", 6727 time: 6728 "<input class='bootbox-input bootbox-input-time form-control' autocomplete=off type='time' />", 6729 number: 6730 "<input class='bootbox-input bootbox-input-number form-control' autocomplete=off type='number' />", 6731 password: 6732 "<input class='bootbox-input bootbox-input-password form-control' autocomplete='off' type='password' />" 6733 } 6734 }; 6735 6736 var defaults = { 6737 // default language 6738 locale: "en", 6739 // show backdrop or not 6740 backdrop: true, 6741 // animate the modal in/out 6742 animate: true, 6743 // additional class string applied to the top level dialog 6744 className: null, 6745 // whether or not to include a close button 6746 closeButton: true, 6747 // show the dialog immediately by default 6748 show: true, 6749 // dialog container 6750 container: "body" 6751 }; 6752 6753 // our public object; augmented after our private API 6754 var exports = {}; 6755 6756 /** 6757 * @private 6758 */ 6759 function _t(key) { 6760 var locale = locales[defaults.locale]; 6761 return locale ? locale[key] : locales.en[key]; 6762 } 6763 6764 function processCallback(e, dialog, callback) { 6765 e.stopPropagation(); 6766 e.preventDefault(); 6767 6768 // by default we assume a callback will get rid of the dialog, 6769 // although it is given the opportunity to override this 6770 6771 // so, if the callback can be invoked and it *explicitly returns false* 6772 // then we'll set a flag to keep the dialog active... 6773 var preserveDialog = $.isFunction(callback) && callback(e) === false; 6774 6775 // ... otherwise we'll bin it 6776 if (!preserveDialog) { 6777 dialog.modal("hide"); 6778 } 6779 } 6780 6781 function getKeyLength(obj) { 6782 // @TODO defer to Object.keys(x).length if available? 6783 var k, t = 0; 6784 for (k in obj) { 6785 t ++; 6786 } 6787 return t; 6788 } 6789 6790 function each(collection, iterator) { 6791 var index = 0; 6792 $.each(collection, function(key, value) { 6793 iterator(key, value, index++); 6794 }); 6795 } 6796 6797 function sanitize(options) { 6798 var buttons; 6799 var total; 6800 6801 if (typeof options !== "object") { 6802 throw new Error("Please supply an object of options"); 6803 } 6804 6805 if (!options.message) { 6806 throw new Error("Please specify a message"); 6807 } 6808 6809 // make sure any supplied options take precedence over defaults 6810 options = $.extend({}, defaults, options); 6811 6812 if (!options.buttons) { 6813 options.buttons = {}; 6814 } 6815 6816 // we only support Bootstrap's "static" and false backdrop args 6817 // supporting true would mean you could dismiss the dialog without 6818 // explicitly interacting with it 6819 options.backdrop = options.backdrop ? "static" : false; 6820 6821 buttons = options.buttons; 6822 6823 total = getKeyLength(buttons); 6824 6825 each(buttons, function(key, button, index) { 6826 6827 if ($.isFunction(button)) { 6828 // short form, assume value is our callback. Since button 6829 // isn't an object it isn't a reference either so re-assign it 6830 button = buttons[key] = { 6831 callback: button 6832 }; 6833 } 6834 6835 // before any further checks make sure by now button is the correct type 6836 if ($.type(button) !== "object") { 6837 throw new Error("button with key " + key + " must be an object"); 6838 } 6839 6840 if (!button.label) { 6841 // the lack of an explicit label means we'll assume the key is good enough 6842 button.label = key; 6843 } 6844 6845 if (!button.className) { 6846 if (total <= 2 && index === total-1) { 6847 // always add a primary to the main option in a two-button dialog 6848 button.className = "btn-primary"; 6849 } else { 6850 button.className = "btn-default"; 6851 } 6852 } 6853 }); 6854 6855 return options; 6856 } 6857 6858 /** 6859 * map a flexible set of arguments into a single returned object 6860 * if args.length is already one just return it, otherwise 6861 * use the properties argument to map the unnamed args to 6862 * object properties 6863 * so in the latter case: 6864 * mapArguments(["foo", $.noop], ["message", "callback"]) 6865 * -> { message: "foo", callback: $.noop } 6866 */ 6867 function mapArguments(args, properties) { 6868 var argn = args.length; 6869 var options = {}; 6870 6871 if (argn < 1 || argn > 2) { 6872 throw new Error("Invalid argument length"); 6873 } 6874 6875 if (argn === 2 || typeof args[0] === "string") { 6876 options[properties[0]] = args[0]; 6877 options[properties[1]] = args[1]; 6878 } else { 6879 options = args[0]; 6880 } 6881 6882 return options; 6883 } 6884 6885 /** 6886 * merge a set of default dialog options with user supplied arguments 6887 */ 6888 function mergeArguments(defaults, args, properties) { 6889 return $.extend( 6890 // deep merge 6891 true, 6892 // ensure the target is an empty, unreferenced object 6893 {}, 6894 // the base options object for this type of dialog (often just buttons) 6895 defaults, 6896 // args could be an object or array; if it's an array properties will 6897 // map it to a proper options object 6898 mapArguments( 6899 args, 6900 properties 6901 ) 6902 ); 6903 } 6904 6905 /** 6906 * this entry-level method makes heavy use of composition to take a simple 6907 * range of inputs and return valid options suitable for passing to bootbox.dialog 6908 */ 6909 function mergeDialogOptions(className, labels, properties, args) { 6910 // build up a base set of dialog properties 6911 var baseOptions = { 6912 className: "bootbox-" + className, 6913 buttons: createLabels.apply(null, labels) 6914 }; 6915 6916 // ensure the buttons properties generated, *after* merging 6917 // with user args are still valid against the supplied labels 6918 return validateButtons( 6919 // merge the generated base properties with user supplied arguments 6920 mergeArguments( 6921 baseOptions, 6922 args, 6923 // if args.length > 1, properties specify how each arg maps to an object key 6924 properties 6925 ), 6926 labels 6927 ); 6928 } 6929 6930 /** 6931 * from a given list of arguments return a suitable object of button labels 6932 * all this does is normalise the given labels and translate them where possible 6933 * e.g. "ok", "confirm" -> { ok: "OK, cancel: "Annuleren" } 6934 */ 6935 function createLabels() { 6936 var buttons = {}; 6937 6938 for (var i = 0, j = arguments.length; i < j; i++) { 6939 var argument = arguments[i]; 6940 var key = argument.toLowerCase(); 6941 var value = argument.toUpperCase(); 6942 6943 buttons[key] = { 6944 label: _t(value) 6945 }; 6946 } 6947 6948 return buttons; 6949 } 6950 6951 function validateButtons(options, buttons) { 6952 var allowedButtons = {}; 6953 each(buttons, function(key, value) { 6954 allowedButtons[value] = true; 6955 }); 6956 6957 each(options.buttons, function(key) { 6958 if (allowedButtons[key] === undefined) { 6959 throw new Error("button key " + key + " is not allowed (options are " + buttons.join("\n") + ")"); 6960 } 6961 }); 6962 6963 return options; 6964 } 6965 6966 exports.alert = function() { 6967 var options; 6968 6969 options = mergeDialogOptions("alert", ["ok"], ["message", "callback"], arguments); 6970 6971 if (options.callback && !$.isFunction(options.callback)) { 6972 throw new Error("alert requires callback property to be a function when provided"); 6973 } 6974 6975 /** 6976 * overrides 6977 */ 6978 options.buttons.ok.callback = options.onEscape = function() { 6979 if ($.isFunction(options.callback)) { 6980 return options.callback(); 6981 } 6982 return true; 6983 }; 6984 6985 return exports.dialog(options); 6986 }; 6987 6988 exports.confirm = function() { 6989 var options; 6990 6991 options = mergeDialogOptions("confirm", ["cancel", "confirm"], ["message", "callback"], arguments); 6992 6993 /** 6994 * overrides; undo anything the user tried to set they shouldn't have 6995 */ 6996 options.buttons.cancel.callback = options.onEscape = function() { 6997 return options.callback(false); 6998 }; 6999 7000 options.buttons.confirm.callback = function() { 7001 return options.callback(true); 7002 }; 7003 7004 // confirm specific validation 7005 if (!$.isFunction(options.callback)) { 7006 throw new Error("confirm requires a callback"); 7007 } 7008 7009 return exports.dialog(options); 7010 }; 7011 7012 exports.prompt = function() { 7013 var options; 7014 var defaults; 7015 var dialog; 7016 var form; 7017 var input; 7018 var shouldShow; 7019 var inputOptions; 7020 7021 // we have to create our form first otherwise 7022 // its value is undefined when gearing up our options 7023 // @TODO this could be solved by allowing message to 7024 // be a function instead... 7025 form = $(templates.form); 7026 7027 // prompt defaults are more complex than others in that 7028 // users can override more defaults 7029 // @TODO I don't like that prompt has to do a lot of heavy 7030 // lifting which mergeDialogOptions can *almost* support already 7031 // just because of 'value' and 'inputType' - can we refactor? 7032 defaults = { 7033 className: "bootbox-prompt", 7034 buttons: createLabels("cancel", "confirm"), 7035 value: "", 7036 inputType: "text" 7037 }; 7038 7039 options = validateButtons( 7040 mergeArguments(defaults, arguments, ["title", "callback"]), 7041 ["cancel", "confirm"] 7042 ); 7043 7044 // capture the user's show value;
7044 we always set this to false before 7045 // spawning the dialog to give us a chance to attach some handlers to 7046 // it, but we need to make sure we respect a preference not to show it 7047 shouldShow = (options.show === undefined) ? true : options.show; 7048 7049 // check if the browser supports the option.inputType 7050 var html5inputs = ["date","time","number"]; 7051 var i = document.createElement("input"); 7052 i.setAttribute("type", options.inputType); 7053 if(html5inputs[options.inputType]){ 7054 options.inputType = i.type; 7055 } 7056 7057 /** 7058 * overrides; undo anything the user tried to set they shouldn't have 7059 */ 7060 options.message = form; 7061 7062 options.buttons.cancel.callback = options.onEscape = function() { 7063 return options.callback(null); 7064 }; 7065 7066 options.buttons.confirm.callback = function() { 7067 var value; 7068 7069 switch (options.inputType) { 7070 case "text": 7071 case "textarea": 7072 case "email": 7073 case "select": 7074 case "date": 7075 case "time": 7076 case "number": 7077 case "password": 7078 value = input.val(); 7079 break; 7080 7081 case "checkbox": 7082 var checkedItems = input.find("input:checked"); 7083 7084 // we assume that checkboxes are always multiple, 7085 // hence we default to an empty array 7086 value = []; 7087 7088 each(checkedItems, function(_, item) { 7089 value.push($(item).val()); 7090 }); 7091 break; 7092 } 7093 7094 return options.callback(value); 7095 }; 7096 7097 options.show = false; 7098 7099 // prompt specific validation 7100 if (!options.title) { 7101 throw new Error("prompt requires a title"); 7102 } 7103 7104 if (!$.isFunction(options.callback)) { 7105 throw new Error("prompt requires a callback"); 7106 } 7107 7108 if (!templates.inputs[options.inputType]) { 7109 throw new Error("invalid prompt type"); 7110 } 7111 7112 // create the input based on the supplied type 7113 input = $(templates.inputs[options.inputType]); 7114 7115 switch (options.inputType) { 7116 case "text": 7117 case "textarea": 7118 case "email": 7119 case "date": 7120 case "time": 7121 case "number": 7122 case "password": 7123 input.val(options.value); 7124 break; 7125 7126 case "select": 7127 var groups = {}; 7128 inputOptions = options.inputOptions || []; 7129 7130 if (!inputOptions.length) { 7131 throw new Error("prompt with select requires options"); 7132 } 7133 7134 each(inputOptions, function(_, option) { 7135 7136 // assume the element to attach to is the input... 7137 var elem = input; 7138 7139 if (option.value === undefined || option.text === undefined) { 7140 throw new Error("given options in wrong format"); 7141 } 7142 7143 7144 // ... but override that element if this option sits in a group 7145 7146 if (option.group) { 7147 // initialise group if necessary 7148 if (!groups[option.group]) { 7149 groups[option.group] = $("<optgroup/>").attr("label", option.group); 7150 } 7151 7152 elem = groups[option.group]; 7153 } 7154 7155 elem.append("<option value='" + option.value + "'>" + option.text + "</option>"); 7156 }); 7157 7158 each(groups, function(_, group) { 7159 input.append(group); 7160 }); 7161 7162 // safe to set a select's value as per a normal input 7163 input.val(options.value); 7164 break; 7165 7166 case "checkbox": 7167 var values = $.isArray(options.value) ? options.value : [options.value]; 7168 inputOptions = options.inputOptions || []; 7169 7170 if (!inputOptions.length) { 7171 throw new Error("prompt with checkbox requires options"); 7172 } 7173 7174 if (!inputOptions[0].value || !inputOptions[0].text) { 7175 throw new Error("given options in wrong format"); 7176 } 7177 7178 // checkboxes have to nest within a containing element, so 7179 // they break the rules a bit and we end up re-assigning 7180 // our 'input' element to this container instead 7181 input = $("<div/>"); 7182 7183 each(inputOptions, function(_, option) { 7184 var checkbox = $(templates.inputs[options.inputType]); 7185 7186 checkbox.find("input").attr("value", option.value); 7187 checkbox.find("label").append(option.text); 7188 7189 // we've ensured values is an array so we can always iterate over it 7190 each(values, function(_, value) { 7191 if (value === option.value) { 7192 checkbox.find("input").prop("checked", true); 7193 } 7194 }); 7195 7196 input.append(checkbox); 7197 }); 7198 break; 7199 } 7200 7201 if (options.placeholder) { 7202 input.attr("placeholder", options.placeholder); 7203 } 7204 7205 if(options.pattern){ 7206 input.attr("pattern", options.pattern); 7207 } 7208 7209 // now place it in our form 7210 form.append(input); 7211 7212 form.on("submit", function(e) { 7213 e.preventDefault(); 7214 // @TODO can we actually click *the* button object instead? 7215 // e.g. buttons.confirm.click() or similar 7216 dialog.find(".btn-primary").click(); 7217 }); 7218 7219 dialog = exports.dialog(options); 7220 7221 // clear the existing handler focusing the submit button... 7222 dialog.off("shown.bs.modal"); 7223 7224 // ...and replace it with one focusing our input, if possible 7225 dialog.on("shown.bs.modal", function() { 7226 input.focus(); 7227 }); 7228 7229 if (shouldShow === true) { 7230 dialog.modal("show"); 7231 } 7232 7233 return dialog; 7234 }; 7235 7236 exports.dialog = function(options) { 7237 options = sanitize(options); 7238 7239 var dialog = $(templates.dialog);
7240 var body = dialog.find(".modal-body"); 7241 var buttons = options.buttons; 7242 var buttonStr = ""; 7243 var callbacks = { 7244 onEscape: options.onEscape 7245 }; 7246 7247 each(buttons, function(key, button) { 7248 7249 // @TODO I don't like this string appending to itself; bit dirty. Needs reworking 7250 // can we just build up button elements instead? slower but neater. Then button 7251 // can just become a template too 7252 buttonStr += "<button data-bb-handler='" + key + "' type='button' class='btn " + button.className + "'>" + button.label + "</button>"; 7253 callbacks[key] = button.callback; 7254 }); 7255 7256 body.find(".bootbox-body").html(options.message); 7257 7258 if (options.animate === true) { 7259 dialog.addClass("fade"); 7260 } 7261 7262 if (options.className) { 7263 dialog.addClass(options.className); 7264 } 7265 7266 if (options.title) { 7267 body.before(templates.header); 7268 } 7269 7270 if (options.closeButton) { 7271 var closeButton = $(templates.closeButton); 7272 7273 if (options.title) { 7274 dialog.find(".modal-header").prepend(closeButton); 7275 } else { 7276 closeButton.css("margin-top", "-10px").prependTo(body); 7277 } 7278 } 7279 7280 if (options.title) { 7281 dialog.find(".modal-title").html(options.title); 7282 } 7283 7284 if (buttonStr.length) { 7285 body.after(templates.footer); 7286 dialog.find(".modal-footer").html(buttonStr); 7287 } 7288 7289 7290 /** 7291 * Bootstrap event listeners; used handle extra 7292 * setup & teardown required after the underlying 7293 * modal has performed certain actions 7294 */ 7295 7296 dialog.on("hidden.bs.modal", function(e) { 7297 // ensure we don't accidentally intercept hidden events triggered 7298 // by children of the current dialog. We shouldn't anymore now BS 7299 // namespaces its events; but still worth doing 7300 if (e.target === this) { 7301 dialog.remove(); 7302 } 7303 }); 7304 7305 /* 7306 dialog.on("show.bs.modal", function() { 7307 // sadly this doesn't work; show is called *just* before 7308 // the backdrop is added so we'd need a setTimeout hack or 7309 // otherwise... leaving in as would be nice 7310 if (options.backdrop) { 7311 dialog.next(".modal-backdrop").addClass("bootbox-backdrop"); 7312 } 7313 }); 7314 */ 7315 7316 dialog.on("shown.bs.modal", function() { 7317 dialog.find(".btn-primary:first").focus(); 7318 }); 7319 7320 /** 7321 * Bootbox event listeners; experimental and may not last 7322 * just an attempt to decouple some behaviours from their 7323 * respective triggers 7324 */ 7325 7326 dialog.on("escape.close.bb", function(e) { 7327 if (callbacks.onEscape) { 7328 processCallback(e, dialog, callbacks.onEscape); 7329 } 7330 }); 7331 7332 /** 7333 * Standard jQuery event listeners; used to handle user 7334 * interaction with our dialog 7335 */ 7336 7337 dialog.on("click", ".modal-footer button", function(e) { 7338 var callbackKey = $(this).data("bb-handler"); 7339 7340 processCallback(e, dialog, callbacks[callbackKey]); 7341 7342 }); 7343 7344 dialog.on("click", ".bootbox-close-button", function(e) { 7345 // onEscape might be falsy but that's fine; the fact is 7346 // if the user has managed to click the close button we 7347 // have to close the dialog, callback or not 7348 processCallback(e, dialog, callbacks.onEscape); 7349 }); 7350 7351 dialog.on("keyup", function(e) { 7352 if (e.which === 27) { 7353 dialog.trigger("escape.close.bb"); 7354 } 7355 }); 7356 7357 // the remainder of this method simply deals with adding our 7358 // dialogent to the DOM, augmenting it with Bootstrap's modal 7359 // functionality and then giving the resulting object back 7360 // to our caller 7361 7362 $(options.container).append(dialog); 7363 7364 dialog.modal({ 7365 backdrop: options.backdrop, 7366 keyboard: false, 7367 show: false 7368 }); 7369 7370 if (options.show) { 7371 dialog.modal("show"); 7372 } 7373 7374 // @TODO should we return the raw element here or should 7375 // we wrap it in an object on which we can expose some neater 7376 // methods, e.g. var d = bootbox.alert(); d.hide(); instead 7377 // of d.modal("hide"); 7378 7379 /* 7380 function BBDialog(elem) { 7381 this.elem = elem; 7382 } 7383 7384 BBDialog.prototype = { 7385 hide: function() { 7386 return this.elem.modal("hide"); 7387 }, 7388 show: function() { 7389 return this.elem.modal("show"); 7390 } 7391 }; 7392 */ 7393 7394 return dialog; 7395 7396 }; 7397 7398 exports.setDefaults = function() { 7399 var values = {}; 7400 7401 if (arguments.length === 2) { 7402 // allow passing of single key/value... 7403 values[arguments[0]] = arguments[1]; 7404 } else { 7405 // ... and as an object too 7406 values = arguments[0]; 7407 } 7408 7409 $.extend(defaults, values); 7410 }; 7411 7412 exports.hideAll = function() { 7413 $(".bootbox").modal("hide"); 7414 }; 7415 7416 7417 /** 7418 * standard locales. Please add more according to ISO 639-1 standard. Multiple language variants are 7419 * unlikely to be required. If this gets too large it can be split out into separate JS files. 7420 */ 7421 var locales = { 7422 br : { 7423 OK : "OK", 7424 CANCEL : "Cancelar", 7425 CONFIRM : "Sim" 7426 }, 7427 da : { 7428 OK : "OK", 7429 CANCEL : "Annuller", 7430 CONFIRM : "Accepter" 7431 }, 7432 de : { 7433 OK : "OK", 7434 CANCEL : "Abbrechen", 7435 CONFIRM : "Akzeptieren" 7436 }, 7437 en : { 7438 OK : "OK", 7439 CANCEL : "Cancel", 7440 CONFIRM : "OK" 7441 }, 7442 es : { 7443 OK : "OK", 7444 CANCEL : "Cancelar", 7445 CONFIRM : "Aceptar" 7446 }, 7447 fi : { 7448 OK : "OK", 7449 CANCEL : "Peruuta", 7450 CONFIRM : "OK" 7451 }, 7452 fr : { 7453 OK : "OK", 7454 CANCEL : "Annuler", 7455 CONFIRM : "D'accord" 7456 }, 7457 he : { 7458 OK : "××ש×ר", 7459 CANCEL : "×××××", 7460 CONFIRM : "××ש×ר" 7461 }, 7462 it : { 7463 OK : "OK", 7464 CANCEL : "Annulla", 7465 CONFIRM : "Conferma" 7466 }, 7467 lt : { 7468 OK : "Gerai", 7469 CANCEL : "AtÅ¡aukti", 7470 CONFIRM : "Patvirtinti" 7471 }, 7472 lv : { 7473 OK : "Labi", 7474 CANCEL : "Atcelt", 7475 CONFIRM : "ApstiprinÄt" 7476 }, 7477 nl : { 7478 OK : "OK", 7479 CANCEL : "Annuleren", 7480 CONFIRM : "Accepteren" 7481 }, 7482 no : { 7483 OK : "OK", 7484 CANCEL : "Avbryt", 7485 CONFIRM : "OK" 7486 }, 7487 pl : { 7488 OK : "OK", 7489 CANCEL : "Anuluj", 7490 CONFIRM : "Potwierdź" 7491 }, 7492 ru : { 7493 OK : "OK", 7494 CANCEL : "ÐÑмена", 7495 CONFIRM : "ÐÑимениÑÑ" 7496 }, 7497 sv : { 7498 OK : "OK", 7499 CANCEL : "Avbryt", 7500 CONFIRM : "OK" 7501 }, 7502 tr : { 7503 OK : "Tamam", 7504 CANCEL : "İptal", 7505 CONFIRM : "Onayla" 7506 }, 7507 zh_CN : { 7508 OK : "OK", 7509 CANCEL : "åæ¶", 7510 CONFIRM : "确认" 7511 }, 7512 zh_TW : { 7513 OK : "OK", 7514 CANCEL : "åæ¶", 7515 CONFIRM : "確èª" 7516 } 7517 }; 7518 7519 exports.init = function(_$) { 7520 return init(_$ || $); 7521 }; 7522 7523 return exports; 7524 })); 7525 7526 7527/***/ }), 7528 7529/***/ 320:
7530/***/ (function(module, exports) { 7531 7532 var carModel = { 7533 7534 init: function( settings ){ 7535 carModel.config = { 7536 partClass: 'carmodel__part', 7537 parts: $('.carmodel__part').not('.carmodel__part--disabled'), 7538 modal: $('#popover'), 7539 damagePrefix: 'damage--', 7540 clearAllHandle: null, 7541 setdamageURL: '/customer-evaluation/ajax/record-damage/', 7542 removedamageURL: '/customer-evaluation/ajax/remove-damage/', 7543 removeAllDamagesURL: '/customer-evaluation/ajax/remove-all-damages/', 7544 errorMessages: { 'damage_type' : 'please specify a damage' } 7545 }; 7546 7547 $.extend( carModel.config, settings ); 7548 7549 carModel.setup(); 7550 }, 7551 7552 setup: function() { 7553 7554 carModel.currentLeadId = carModel.config.modal.find('form').data('leadid'); 7555 7556 carModel.config.parts.each(function() { 7557 // attach bootstrap tooltips 7558 $(this).tooltip({ 7559 container: 'body' 7560 }); 7561 7562 // attach bootstrap modal handler 7563 var modalID = carModel.config.modal.attr('id'); 7564 $(this).attr({ 7565 'data-toggle': 'modal', 7566 'data-target': '#' + modalID, 7567 }); 7568 }); 7569 7570 carModel.config.modal 7571 .modal({ 7572 backdrop: true, 7573 show: false 7574 }) 7575 .on('show.bs.modal', function(e) { 7576 carModel.formPopulate(e.relatedTarget); 7577 }); 7578 7579 carModel.config.modal.find('form') 7580 .validate({ 7581 errorClass: 'damage__form__error', 7582 errorElement: 'div', 7583 errorPlacement: function(error, element) { 7584 var parent = $(element).parent(); 7585 error.insertBefore(parent); 7586 }, 7587 submitHandler: function() { 7588 carModel.formSubmit(); 7589 }, 7590 messages: carModel.config.errorMessages 7591 }); 7592 7593 carModel.config.modal.find( $('button[data-dismiss="damage"]') ) 7594 .on('click', function() { 7595 var partId = carModel.config.modal.data('partid'); 7596 7597 carModel.clearDamage(partId); 7598 }); 7599 7600 if (typeof (carModel.config.clearAllHandle) !== null) { 7601 $(carModel.config.clearAllHandle).show().on('click', function (e) { 7602 e.preventDefault(); 7603 e.stopPropagation(); 7604 7605 carModel.clearAllDamages(); 7606 }); 7607 } 7608 }, 7609 7610 formPopulate: function(part) { 7611 var $$this = carModel.config.modal, 7612 $$form = $$this.find('form'), 7613 $$part = $(part), 7614 7615 _partId = $$part.data('partid'), 7616 _title = $$part.data('title'), 7617 _damageType = $$part.data('damagetype'), 7618 _damageDesc = $$part.data('damagedesc'); 7619 7620 $$this.data('partid', _partId); 7621 $$this.find('.damage__form__title').text(_title); 7622 7623 // reset formfields 7624 $$this.find( $('button[data-dismiss="damage"]') ).addClass('hidden'); 7625 $$form.find('textarea').val(''); 7626 $$form.find('div.damage__form__error').remove(); 7627 $$form.find('input[type=radio]').prop('checked', false ); 7628 7629 //console.log(_partId + ' ' + _damageType) 7630 7631 if ( typeof _damageType !== 'undefined' ) { 7632 $$this.find( $('button[data-dismiss="damage"]') ).removeClass('hidden'); 7633 $$form.find('input[value='+ _damageType +']').prop('checked', true); 7634 } 7635 if ( typeof _damageDesc !== 'undefined' ) { 7636 $$form.find('textarea').val(_damageDesc); 7637 } 7638 //getDamages 7639 7640 7641 }, 7642 7643 formSubmit: function() { 7644 var fields = carModel.formGatherValues(); 7645 7646 carModel.setDamage({ 7647 part: fields.part, 7648 type: fields.damage_type, 7649 desc: fields.damage_desc 7650 }); 7651 }, 7652 7653 formGatherValues: function() { 7654 var $$form = carModel.config.modal.find('form'), 7655 formValues = $$form.serializeObject(); 7656 7657 formValues.part = carModel.config.modal.data('partid'); 7658 7659 return formValues; 7660 }, 7661 7662 setDamage: function(damage) { 7663 7664 // ajax stuff 7665 var params = { 7666 lead_hash: carModel.currentLeadId, 7667 part_name: damage.part, 7668 customer_damage_id: damage.type, 7669 customer_description: damage.desc 7670 }; 7671 7672 $.post(carModel.config.setdamageURL, params , function(data) { 7673 // todo: loading 7674 7675 if ( data.ok ) { 7676 carModel.updatePart(damage); 7677 carModel.config.modal.modal('hide'); 7678 carModel.updateView(damage); 7679 } else { 7680 console.error(data); 7681 console.error('something went wrong'); 7682 } 7683 }); 7684 }, 7685 7686 clearDamage: function(part) { 7687 // ajax stuff 7688 var params = {
7689 lead_hash: carModel.currentLeadId, 7690 part_name: part 7691 }; 7692 7693 $.post(carModel.config.removedamageURL, params , function(data) { 7694 // todo: loading 7695 7696 if ( data.ok ) { 7697 carModel.updatePart({ part: part }, 'destroy' ); 7698 carModel.updateView({ part: part }, 'destroy' ); 7699 carModel.config.modal.modal('hide'); 7700 } else { 7701 console.error(data); 7702 console.error('something went wrong'); 7703 } 7704 }); 7705 }, 7706 7707 updatePart: function(damage, action) { 7708 var $$part = $('.'+damage.part); 7709 7710 carModel.config.parts 7711 .filter($$part) 7712 .each(function() { 7713 if (typeof action !== 'undefined' && action == 'destroy') { 7714 $(this) 7715 .removeData('damagetype').removeAttr('data-damagetype') 7716 .removeData('damagedesc').removeAttr('data-damagedesc'); 7717 } else { 7718 $(this).data({ 7719 'damagetype': damage.type, 7720 'damagedesc': damage.desc 7721 }); 7722 } 7723 }); 7724 7725 carModel.formPopulate(damage.part); 7726 }, 7727 7728 clearAllDamages: function () { 7729 $.post(carModel.config.removeAllDamagesURL, {lead_hash: carModel.currentLeadId} , function(data) { 7730 // todo: loading 7731 if ( data.ok ) { 7732 carModel.clearView(); 7733 } else { 7734 console.error(data); 7735 console.error('something went wrong'); 7736 } 7737 }); 7738 }, 7739 7740 clearView: function () { 7741 carModel.config.parts.each(function () { 7742 var regExp = /damage.+?(?=\s|$)/gi; 7743 7744 var _classList = this.className.baseVal; 7745 _classList = _classList.replace(regExp, ''); 7746 7747 this.className.baseVal = _classList; 7748 7749 $(this).removeData('damagetype').removeAttr('data-damagetype') 7750 .removeData('damagedesc').removeAttr('data-damagedesc'); 7751 }); 7752 }, 7753 7754 updateView: function(damage, action) { 7755 var $$part = $('.'+damage.part), 7756 _classList = [ carModel.config.partClass, damage.part ]; 7757 7758 if (typeof damage === 'undefined' || action != 'destroy') { 7759 _classList.push(carModel.config.damagePrefix + damage.type); 7760 } 7761 7762 carModel.config.parts 7763 .filter($$part) 7764 .each(function() { 7765 this.className.baseVal = _classList.join(' '); 7766 }); 7767 } 7768 }; 7769 $.fn.serializeObject = function() { 7770 var o = {}; 7771 var a = this.serializeArray(); 7772 $.each(a, function() { 7773 if (o[this.name] !== undefined) { 7774 if (!o[this.name].push) { 7775 o[this.name] = [o[this.name]]; 7776 } 7777 o[this.name].push(this.value || ''); 7778 } else { 7779 o[this.name] = this.value || ''; 7780 } 7781 }); 7782 return o; 7783 }; 7784 7785/***/ }), 7786 7787/***/ 321: 7788/***/ (function(module, exports) { 7789 7790 ;(function($) { 7791 $.fn.fullformTooltip = function (options) { 7792 var $$this = $(this); 7793 var tooltip = { 7794 settings: { 7795 container: 'body', 7796 trigger: 'manual', 7797 html: true, 7798 placement: 'top', 7799 content: 'blabla', 7800 type: null 7801 } 7802 } 7803 // allow overwrite of default settings 7804 $.extend(tooltip.settings, options); 7805 7806 if (tooltip.settings.type == 'image') { 7807 tooltip.settings.content = function () { 7808 return '<img src="'+$(this).attr('data-tooltip')+'" height="'+$(this).attr('data-tooltip-height')+'" width="'+$(this).attr('data-tooltip-width')+'">'; 7809 } 7810 } 7811 return this.popover(tooltip.settings); 7812 }; 7813 7814 $(function() { 7815 var tooltipVisible = null; 7816 7817 $('.form-tooltip').show(); 7818 7819 $('[data-tooltip]').each(function () { 7820 $(this) 7821 .fullformTooltip({ 7822 type: $(this).attr('data-tooltip-type'), 7823 content: $(this).attr('data-tooltip') 7824 }) 7825 .on('click', function (e) { 7826 //e.stopPropagation(); 7827 }) 7828 }) 7829 .on('show.bs.popover', function () { 7830 tooltipVisible = this.id; 7831 //console.log(tooltipVisible) 7832 }) 7833 .on('hide.bs.popover', function () { 7834 tooltipVisible = null; 7835 }) 7836 .on('shown.bs.popover', function () { 7837 var posTop = $('.popover').css('top'); 7838 $('.popover').css({ 7839 top: parseInt(posTop)- 18 + 'px' 7840 }) 7841 }) 7842 7843 $('label[data-trigger="tooltip"]').on('click', function (e) { 7844 var targetId = $(this).attr('for'); 7845 $('[data-tooltip]').not('#'+targetId).popover('hide'); 7846 $('#'+targetId).popover('show'); 7847 e.preventDefault(); 7848 e.stopPropagation(); 7849 }); 7850 7851 $(document).on('click', function(e) { 7852 if (e.target != document.getElementById(tooltipVisible)) { 7853 $('[data-tooltip]').popover('hide'); 7854 } 7855 }); 7856 }); 7857 })(jQuery); 7858 7859/***/ }), 7860 7861/***/ 322: 7862/***/ (function(module, exports, __webpack_require__) { 7863 7864 /* WEBPACK VAR INJECTION */(function(global) {module.exports = global["reviewModule"] = __webpack_require__(323); 7865 /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }()))) 7866 7867/***/ }), 7868 7869/***/ 323:
7870/***/ (function(module, exports) { 7871 7872 /** 7873 * A module that controls the sticky behaviour of 7874 * the sidebar in some pages. 7875 * @module reviewModule 7876 */ 7877 var reviewModule = module.exports = (function () { 7878 var pageContainer, topOffset; 7879 var padding = 9; 7880 7881 var $aside = $('aside'); 7882 var $main = $('main'); 7883 var $asideContent = $('.aside-content'); 7884 var $window = $(window); 7885 7886 /** 7887 * Returns an integer value without the px unit 7888 * @param {String} px string representation of quantity in px unit (e.g. '10px') 7889 */ 7890 function pxToInt(px) { 7891 var unitlessString = px.replace('px', ''); 7892 return parseInt(unitlessString); 7893 } 7894 7895 /** 7896 * Returns the left offset that should be used for calculations 7897 */ 7898 function getLeftOffset() { 7899 return pxToInt($aside.css('padding-left')) + pxToInt($main.css('padding-right')); 7900 } 7901 7902 /** 7903 * Returns the top offset that should be used for calculations 7904 */ 7905 function getTopOffset() { 7906 return topOffset || 0; 7907 } 7908 7909 /** 7910 * Checks if the the window width is equal or 7911 * larger than the breakpoint 7912 * @param {Number} breakpoint 7913 * @returns {Boolean} 7914 */ 7915 function isOnBreakpoint(breakpoint) { 7916 return $window.width() >= breakpoint; 7917 } 7918 7919 /** 7920 * Sets the style attribute of the element to empty string 7921 * @param {Object} element jQuery object 7922 */ 7923 function removeStyle(element) { 7924 element.attr('style', ''); 7925 } 7926 7927 /** 7928 * Sets the css properties of the aside element in such a way 7929 * that its position is absolute 7930 * @param {Number} left 7931 * @param {Number} top 7932 */ 7933 function setAsideAbsolute(left, top) { 7934 $aside.css({ 7935 left: left, 7936 position: 'absolute', 7937 top: top, 7938 width: $aside.css('width'), 7939 'z-index': 1 7940 }); 7941 } 7942 7943 /** 7944 * Unset the sticky behaviour of the aside element 7945 * @param {Boolean} shouldPositionAbsolute Whether to set the sidebar position to absolute or not 7946 * @param {Number} top Top offset, absolute position only 7947 */ 7948 function unfixAside(shouldPositionAbsolute, top) { 7949 if (shouldPositionAbsolute) { 7950 var left = $main.width() + getLeftOffset(); 7951 7952 setAsideAbsolute(left, top); 7953 } else { 7954 removeStyle($aside); 7955 } 7956 7957 removeStyle($asideContent); 7958 } 7959 7960 /** 7961 * Set aside element positioned at the bottom of the page container 7962 */ 7963 function fixAsideToTheBottom(shouldPositionAbsolute, absolutePositionTop) { 7964 var left = shouldPositionAbsolute ? $main.width() + getLeftOffset() : 'auto'; 7965 var top = pageContainer.outerHeight() - $aside.outerHeight() - getTopOffset() + pageContainer.offset().top - padding; 7966 top = shouldPositionAbsolute ? top - absolutePositionTop - padding*2 : top; 7967 7968 removeStyle($aside); 7969 setAsideAbsolute(left, top); 7970 } 7971 7972 /** 7973 * Set the sticky behaviour of the aside element 7974 */ 7975 function fixAside(shouldPositionAbsolute) { 7976 $asideContent.css({ 'margin-top': $aside.height() }); 7977 $aside.css({ 7978 left: shouldPositionAbsolute? $main.offset().left + $main.width() + getLeftOffset() : $aside.offset().left, 7979 position: 'fixed', 7980 top: padding, 7981 width: $aside.css('width') 7982 }); 7983 } 7984 7985 /** 7986 * Set or unset the sticky behaviour of the aside element based on the params 7987 * and the amount of scrolled pixels 7988 * @param {Number} windowBreakPoint Sets the limit below which the sidebar is not 7989 * @param {Boolean} shouldPositionAbsolute Whether to set the sidebar position to absolute or not 7990 * @param {Number} top Top offset, absolute position only 7991 */ 7992 function updateAside(windowBreakPoint, shouldPositionAbsolute, top) { 7993 var scrolled = $(document).scrollTop(); 7994 var shouldBeFixed = shouldPositionAbsolute ? scrolled > (getTopOffset() + pageContainer.offset().top) : scrolled > getTopOffset(); 7995 var bottomBreakpoint = pageContainer.offset().top + pageContainer.outerHeight() - $aside.outerHeight(); 7996 bottomBreakpoint = shouldPositionAbsolute ? bottomBreakpoint - top - padding*2 : bottomBreakpoint; 7997 var shouldBeFixedToBottom = scrolled > bottomBreakpoint; 7998 7999 $aside.css({ 'z-index': 1000 }); 8000 8001 // If window is big enough to show the sidebar at the right 8002 if (isOnBreakpoint(windowBreakPoint)) { 8003 // If already scrolled past the top of the container 8004 if (shouldBeFixed) { 8005 // if reached the bottom limit 8006 if (shouldBeFixedToBottom) { 8007 fixAsideToTheBottom(shouldPositionAbsolute, top); 8008 // Otherwise (there's still more to scroll) 8009 } else { 8010 fixAside(shouldPositionAbsolute); 8011 } 8012 // Otherwise (scrolled above the top of the sidebar) 8013 } else { 8014 unfixAside(shouldPositionAbsolute, top); 8015 $('#scrollspy-nav ul li:first-child').addClass('active'); 8016 } 8017 // Otherwise (window is not big enough) 8018 } else { 8019 unfixAside(false, top); 8020 } 8021 }; 8022 8023 /** TODO: document this function in a clearer way 8024 * Function for moving form after comment index 8025 * @param {*} commentIndex 8026 */ 8027 function conversionFormInit(commentIndex) { 8028 $('.car-form-smaller') 8029 .removeClass('hide') 8030 .insertAfter( 8031 $('.panel-customer-comment').eq(commentIndex) 8032 ); 8033 }; 8034 8035 /** 8036 * Initialize the sticky behavior for the aside element 8037 * @param {Number} windowBreakPoint Sets the limit below which the sidebar is not 8038 * @param {Boolean} shouldPositionAbsolute Whether to set the sidebar position to absolute or not 8039 * @param {Number} top Top offset, absolute position only 8040 */ 8041 function initSidebar(windowBreakPoint, shouldPositionAbsolute, top) { 8042 // Store the offset now and forever 8043 topOffset = shouldPositionAbsolute ? $aside.offset().top - pageContainer.offset().top : $aside.offset().top; 8044 leftOffset = $aside.offset().left; 8045 8046 // bind updateAside with params 8047 var boundUpdateAside = updateAside.bind(null, windowBreakPoint, shouldPositionAbsolute, top); 8048 8049 // Set listeners for scroll and resize events 8050 $window.scroll(boundUpdateAside); 8051 $window.resize(boundUpdateAside); 8052 8053 // call once 8054 boundUpdateAside(); 8055 } 8056 8057 /** 8058 * Set the selector to position container form. 8059 * @param {String} containerSelector 8060 * @param {Number} windowBreakPoint 8061 * @param {Object}
8061 [cfg] Sticky nav config 8062 * @param {Boolean} [cfg.shouldPositionAbsolute] 8063 * @param {String} [cfg.mainContainerSelector] 8064 * @param {Number} [cfg.top] Top offset, absolute position only 8065 */ 8066 function setForm(containerSelector, windowBreakPoint, cfg) { 8067 // store the container of the page 8068 cfg = cfg || {}; 8069 pageContainer = $(containerSelector); 8070 var mainContainerSelector = cfg.mainContainerSelector || 'main'; 8071 $main = $(mainContainerSelector); 8072 8073 var boundInitSidebar = initSidebar.bind(null, windowBreakPoint, cfg.shouldPositionAbsolute, cfg.top); 8074 8075 // If view is big enough start the sidebar logic 8076 if (isOnBreakpoint(windowBreakPoint)) { 8077 boundInitSidebar(); 8078 } else { // Otherwise, wait until screen is resized to big enough size 8079 $(window).on('resize', onWindowResize); 8080 } 8081 8082 function onWindowResize() { 8083 if (isOnBreakpoint(windowBreakPoint)) { 8084 boundInitSidebar(); 8085 // then remove the initial resize listener 8086 $window.off('resize', onWindowResize); 8087 } 8088 } 8089 8090 // return the container to allow chaining 8091 return pageContainer; 8092 } 8093 8094 return { 8095 setForm: setForm, 8096 conversionFormInit: conversionFormInit, 8097 }; 8098 })(); 8099 8100 8101/***/ }), 8102 8103/***/ 324: 8104/***/ (function(module, exports, __webpack_require__) { 8105 8106 /* WEBPACK VAR INJECTION */(function(global) {module.exports = global["riskFreeSummary"] = __webpack_require__(325); 8107 /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }()))) 8108 8109/***/ }), 8110 8111/***/ 325: 8112/***/ (function(module, exports) { 8113 8114 var riskFreeSummary = (module.exports = (function() { 8115 return function() { 8116 $.post( 8117 "/lp/_service/branchDays/", 8118 { 8119 hash: $("#carHash").val(), 8120 branch: $("#branches").val() 8121 }, 8122 function(days) { 8123 var html = days 8124 .map(function(day) { 8125 return '<option value="' + day.id + '">' + day.label + "</option>"; 8126 }) 8127 .join(""); 8128 8129 $("#days").append(html); 8130 } 8131 ); 8132 }; 8133 })()); 8134 8135 8136/***/ }), 8137 8138/***/ 326: 8139/***/ (function(module, exports, __webpack_require__) { 8140 8141 window.stickyWidget = (function initSticky(window) { 8142 return { 8143 init: init 8144 }; 8145 8146 function init(sidebarSelector, _options) { 8147 var ResizeSensor = __webpack_require__(327); 8148 window.ResizeSensor = ResizeSensor; 8149 var StickySidebar = __webpack_require__(328).default; 8150 8151 var defaults = { 8152 topSpacing: 5, 8153 bottomSpacing: 0, 8154 containerSelector: '.js-sticky-main-container', 8155 innerWrapperSelector: '.js-sticky-widget', 8156 minWidth: 1026, 8157 resizeSensor: true 8158 }; 8159 8160 if (_options) { 8161 for (var attrname in _options) { defaults[attrname] = _options[attrname]; } 8162 } 8163 8164 var options = defaults; 8165 var sidebarSelector = sidebarSelector || '.js-sticky-sidebar'; 8166 var containerSelector = options.containerSelector; 8167 var innerWrapperSelector = options.innerWrapperSelector; 8168 var belowContent = document.querySelector('.js-below-content'); 8169 var stickySidebar = document.querySelector(sidebarSelector); 8170 var stickyElement = document.querySelector(innerWrapperSelector); 8171 var stickyContentContainer = document.querySelector(containerSelector); 8172 8173 var instance = new StickySidebar(stickySidebar, { 8174 topSpacing: 5, 8175 bottomSpacing: 0, 8176 containerSelector: containerSelector, 8177 innerWrapperSelector: innerWrapperSelector, 8178 minWidth: 1026, 8179 resizeSensor: true 8180 }); 8181 8182 8183 new ResizeSensor(stickyElement, function() { 8184 setTimeout(function updateStickyTimeout(){ 8185 instance.updateSticky(); 8186 }, 0); 8187 }); 8188 8189 stickySidebar.addEventListener("affix.breakpoint.stickySidebar", function() { 8190 var sib = belowContent || stickyElement.nextElementSibling; 8191 if(sib) { 8192 removeClass(sib, 'sibbling-affixed'); 8193 sib.style.marginTop = 'auto'; 8194 } 8195 }); 8196 8197 stickySidebar.addEventListener("affix.top.stickySidebar", function() { 8198 var sib = belowContent || stickyElement.nextElementSibling; 8199 var height = outerHeight(stickyElement); 8200 var isAffixed = hasClass(stickySidebar, 'is-affixed'); 8201 if(sib && !isAffixed) { 8202 sib.style.marginTop = height + 'px'; 8203 addClass(sib, 'sibbling-affixed'); 8204 } 8205 }); 8206 8207 stickySidebar.addEventListener("affixed.static.stickySidebar", function() { 8208 var sib = belowContent || stickyElement.nextElementSibling; 8209 if(sib) { 8210 sib.style.marginTop = 'auto'; 8211 removeClass(sib, 'sibbling-affixed'); 8212 } 8213 setTimeout(function() {
8214 instance.calcDimensions(); 8215 }, 0) 8216 }); 8217 } 8218 8219 function hasClass(el, className) { 8220 if (el.classList){ 8221 return el.classList.contains(className); 8222 } else { 8223 return new RegExp('(^| )' + className + '( |$)', 'gi').test(el.className); 8224 } 8225 } 8226 8227 function addClass(el, className) { 8228 if (el.classList) { 8229 el.classList.add(className); 8230 } else { 8231 el.className += ' ' + className; 8232 } 8233 } 8234 8235 function removeClass(el, className) { 8236 if (el.classList) { 8237 el.classList.remove(className); 8238 } else { 8239 el.className = el.className.replace(new RegExp('(^|\\b)' + className.split(' ').join('|') + '(\\b|$)', 'gi'), ' '); 8240 } 8241 } 8242 8243 function outerHeight(el) { 8244 var height = el.offsetHeight; 8245 var style = getComputedStyle(el); 8246 height += parseInt(style.marginTop, 10) + parseInt(style.marginBottom, 10); 8247 return height; 8248 } 8249 })(window); 8250 8251 8252/***/ }), 8253 8254/***/ 327: 8255/***/ (function(module, exports, __webpack_require__) { 8256 8257 var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_RESULT__;'use strict'; 8258 8259 /** 8260 * Copyright Marc J. Schmidt. See the LICENSE file at the top-level 8261 * directory of this distribution and at 8262 * https://github.com/marcj/css-element-queries/blob/master/LICENSE. 8263 */ 8264 (function (root, factory) { 8265 if (true) { 8266 !(__WEBPACK_AMD_DEFINE_FACTORY__ = (factory), __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? (__WEBPACK_AMD_DEFINE_FACTORY__.call(exports, __webpack_require__, exports, module)) : __WEBPACK_AMD_DEFINE_FACTORY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); 8267 } else if (typeof exports === "object") { 8268 module.exports = factory(); 8269 } else { 8270 root.ResizeSensor = factory(); 8271 } 8272 }(typeof window !== 'undefined' ? window : this, function () { 8273 8274 // Make sure it does not throw in a SSR (Server Side Rendering) situation 8275 if (typeof window === "undefined") { 8276 return null; 8277 } 8278 // https://github.com/Semantic-Org/Semantic-UI/issues/3855 8279 // https://github.com/marcj/css-element-queries/issues/257 8280 var globalWindow = typeof window != 'undefined' && window.Math == Math 8281 ? window 8282 : typeof self != 'undefined' && self.Math == Math 8283 ? self 8284 : Function('return this')(); 8285 // Only used for the dirty checking, so the event callback count is limited to max 1 call per fps per sensor. 8286 // In combination with the event based resize sensor this saves cpu time, because the sensor is too fast and 8287 // would generate too many unnecessary events. 8288 var requestAnimationFrame = globalWindow.requestAnimationFrame || 8289 globalWindow.mozRequestAnimationFrame || 8290 globalWindow.webkitRequestAnimationFrame || 8291 function (fn) { 8292 return globalWindow.setTimeout(fn, 20); 8293 }; 8294 8295 /** 8296 * Iterate over each of the provided element(s). 8297 * 8298 * @param {HTMLElement|HTMLElement[]} elements 8299 * @param {Function} callback 8300 */ 8301 function forEachElement(elements, callback){ 8302 var elementsType = Object.prototype.toString.call(elements); 8303 var isCollectionTyped = ('[object Array]' === elementsType 8304 || ('[object NodeList]' === elementsType) 8305 || ('[object HTMLCollection]' === elementsType) 8306 || ('[object Object]' === elementsType) 8307 || ('undefined' !== typeof jQuery && elements instanceof jQuery) //jquery 8308 || ('undefined' !== typeof Elements && elements instanceof Elements) //mootools 8309 ); 8310 var i = 0, j = elements.length; 8311 if (isCollectionTyped) { 8312 for (; i < j; i++) { 8313 callback(elements[i]); 8314 } 8315 } else { 8316 callback(elements); 8317 } 8318 } 8319 8320 /** 8321 * Get element size 8322 * @param {HTMLElement} element 8323 * @returns {Object} {width, height} 8324 */ 8325 function getElementSize(element) { 8326 if (!element.getBoundingClientRect) { 8327 return { 8328 width: element.offsetWidth, 8329 height: element.offsetHeight 8330 } 8331 } 8332 8333 var rect = element.getBoundingClientRect(); 8334 return { 8335 width: Math.round(rect.width), 8336 height: Math.round(rect.height) 8337 } 8338 } 8339 8340 /** 8341 * Apply CSS styles to element. 8342 * 8343 * @param {HTMLElement} element 8344 * @param {Object} style 8345 */ 8346 function setStyle(element, style) { 8347 Object.keys(style).forEach(function(key) { 8348 element.style[key] = style[key]; 8349 }); 8350 } 8351 8352 /** 8353 * Class for dimension change detection. 8354 * 8355 * @param {Element|Element[]|Elements|jQuery} element 8356 * @param {Function} callback 8357 * 8358 * @constructor 8359 */ 8360 var ResizeSensor = function(element, callback) { 8361 /** 8362 * 8363 * @constructor 8364 */ 8365 function EventQueue() { 8366 var q = []; 8367 this.add = function(ev) { 8368 q.push(ev); 8369 }; 8370 8371 var i, j; 8372 this.call = function(sizeInfo) { 8373 for (i = 0, j = q.length; i < j; i++) { 8374 q[i].call(this, sizeInfo); 8375 } 8376 }; 8377 8378 this.remove = function(ev) { 8379 var newQueue = []; 8380 for(i = 0, j = q.length; i < j; i++) { 8381 if(q[i] !== ev) newQueue.push(q[i]); 8382 } 8383 q = newQueue; 8384 }; 8385 8386 this.length = function() { 8387 return q.length; 8388 } 8389 } 8390 8391 /** 8392 * 8393 * @param {HTMLElement} element 8394 * @param {Function} resized 8395 */ 8396 function attachResizeEvent(element, resized) { 8397 if (!element) return; 8398 if (element.resizedAttached) { 8399 element.resizedAttached.add(resized); 8400 return; 8401 } 8402 8403 element.resizedAttached = new EventQueue(); 8404 element.resizedAttached.add(resized); 8405 8406 element.resizeSensor = document.createElement('div'); 8407 element.resizeSensor.dir = 'ltr'; 8408 element.resizeSensor.className = 'resize-sensor'; 8409 8410 var style = { 8411 pointerEvents: 'none', 8412 position: 'absolute', 8413 left: '0px', 8414 top: '0px', 8415 right: '0px', 8416 bottom: '0px', 8417 overflow: 'hidden', 8418 zIndex: '-1', 8419 visibility: 'hidden', 8420 maxWidth: '100%' 8421 }; 8422 var styleChild = { 8423 position: 'absolute', 8424 left: '0px', 8425 top: '0px', 8426 transition: '0s', 8427 }; 8428 8429 setStyle(element.resizeSensor, style); 8430 8431 var expand = document.createElement('div'); 8432 expand.className = 'resize-sensor-expand'; 8433 setStyle(expand, style); 8434 8435 var expandChild = document.createElement('div'); 8436 setStyle(expandChild, styleChild); 8437 expand.appendChild(expandChild); 8438 8439 var shrink = document.createElement('div'); 8440 shrink.className = 'resize-sensor-shrink'; 8441 setStyle(shrink, style); 8442 8443 var shrinkChild = document.createElement('div'); 8444 setStyle(shrinkChild, styleChild); 8445 setStyle(shrinkChild, { width: '200%', height: '200%' }); 8446 shrink.appendChild(shrinkChild); 8447 8448 element.resizeSensor.appendChild(expand); 8449 element.resizeSensor.appendChild(shrink); 8450 element.appendChild(element.resizeSensor); 8451 8452 var computedStyle = window.getComputedStyle(element); 8453 var position = computedStyle ? computedStyle.getPropertyValue('position') : null; 8454 if ('absolute' !== position && 'relative' !== position && 'fixed' !== position) { 8455 element.style.position = 'relative'; 8456 } 8457 8458 var dirty, rafId; 8459 var size = getElementSize(element); 8460 var lastWidth = 0; 8461 var lastHeight = 0; 8462 var initialHiddenCheck = true; 8463 var lastAnimationFrame = 0; 8464 8465 var resetExpandShrink = function () { 8466 var width = element.offsetWidth; 8467 var height = element.offsetHeight; 8468 8469 expandChild.style.width = (width + 10) + 'px'; 8470 expandChild.style.height = (height + 10) + 'px'; 8471 8472 expand.scrollLeft = width + 10; 8473 expand.scrollTop = height + 10; 8474 8475 shrink.scrollLeft = width + 10; 8476 shrink.scrollTop = height + 10; 8477 }; 8478 8479 var reset = function() { 8480 // Check if element is hidden 8481 if (initialHiddenCheck) { 8482 var invisible = element.offsetWidth === 0 && element.offsetHeight === 0; 8483 if (invisible) { 8484 // Check in next frame 8485 if (!lastAnimationFrame){ 8486 lastAnimationFrame = requestAnimationFrame(function(){ 8487 lastAnimationFrame = 0; 8488 8489 reset(); 8490 }); 8491 } 8492 8493 return; 8494 } else { 8495 // Stop checking 8496 initialHiddenCheck = false;
8497 } 8498 } 8499 8500 resetExpandShrink(); 8501 }; 8502 element.resizeSensor.resetSensor = reset; 8503 8504 var onResized = function() { 8505 rafId = 0; 8506 8507 if (!dirty) return; 8508 8509 lastWidth = size.width; 8510 lastHeight = size.height; 8511 8512 if (element.resizedAttached) { 8513 element.resizedAttached.call(size); 8514 } 8515 }; 8516 8517 var onScroll = function() { 8518 size = getElementSize(element); 8519 dirty = size.width !== lastWidth || size.height !== lastHeight; 8520 8521 if (dirty && !rafId) { 8522 rafId = requestAnimationFrame(onResized); 8523 } 8524 8525 reset(); 8526 }; 8527 8528 var addEvent = function(el, name, cb) { 8529 if (el.attachEvent) { 8530 el.attachEvent('on' + name, cb); 8531 } else { 8532 el.addEventListener(name, cb); 8533 } 8534 }; 8535 8536 addEvent(expand, 'scroll', onScroll); 8537 addEvent(shrink, 'scroll', onScroll); 8538 8539 // Fix for custom Elements 8540 requestAnimationFrame(reset); 8541 } 8542 8543 forEachElement(element, function(elem){ 8544 attachResizeEvent(elem, callback); 8545 }); 8546 8547 this.detach = function(ev) { 8548 ResizeSensor.detach(element, ev); 8549 }; 8550 8551 this.reset = function() { 8552 element.resizeSensor.resetSensor(); 8553 }; 8554 }; 8555 8556 ResizeSensor.reset = function(element) { 8557 forEachElement(element, function(elem){ 8558 elem.resizeSensor.resetSensor(); 8559 }); 8560 }; 8561 8562 ResizeSensor.detach = function(element, ev) { 8563 forEachElement(element, function(elem){ 8564 if (!elem) return; 8565 if(elem.resizedAttached && typeof ev === "function"){ 8566 elem.resizedAttached.remove(ev); 8567 if(elem.resizedAttached.length()) return; 8568 } 8569 if (elem.resizeSensor) { 8570 if (elem.contains(elem.resizeSensor)) { 8571 elem.removeChild(elem.resizeSensor); 8572 } 8573 delete elem.resizeSensor; 8574 delete elem.resizedAttached; 8575 } 8576 }); 8577 }; 8578 8579 if (typeof MutationObserver !== "undefined") { 8580 var observer = new MutationObserver(function (mutations) { 8581 for (var i in mutations) { 8582 if (mutations.hasOwnProperty(i)) { 8583 var items = mutations[i].addedNodes; 8584 for (var j = 0; j < items.length; j++) { 8585 if (items[j].resizeSensor) { 8586 ResizeSensor.reset(items[j]); 8587 } 8588 } 8589 } 8590 } 8591 }); 8592 8593 document.addEventListener("DOMContentLoaded", function (event) { 8594 observer.observe(document.body, { 8595 childList: true, 8596 subtree: true, 8597 }); 8598 }); 8599 } 8600 8601 return ResizeSensor; 8602 8603 })); 8604 8605/***/ }), 8606 8607/***/ 328: 8608/***/ (function(module, exports, __webpack_require__) { 8609 8610 /* WEBPACK VAR INJECTION */(function(global) {(function (global, factory) { 8611 true ? factory(exports) : 8612 typeof define === 'function' && define.amd ? define(['exports'], factory) : 8613 (factory((global.StickySidebar = {}))); 8614 }(this, (function (exports) { 'use strict'; 8615 8616 var commonjsGlobal = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}; 8617 8618 8619 8620 function unwrapExports (x) { 8621 return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x; 8622 } 8623 8624 function createCommonjsModule(fn, module) { 8625 return module = { exports: {} }, fn(module, module.exports), module.exports; 8626 } 8627 8628 var stickySidebar = createCommonjsModule(function (module, exports) { 8629 (function (global, factory) { 8630 if (false) { 8631 undefined(['exports'], factory); 8632 } else { 8633 factory(exports); 8634 } 8635 })(commonjsGlobal, function (exports) { 8636 Object.defineProperty(exports, "__esModule", { 8637 value: true 8638 }); 8639 8640 function _classCallCheck(instance, Constructor) { 8641 if (!(instance instanceof Constructor)) { 8642 throw new TypeError("Cannot call a class as a function"); 8643 } 8644 } 8645 8646 var _createClass = function () { 8647 function defineProperties(target, props) { 8648 for (var i = 0; i < props.length; i++) { 8649 var descriptor = props[i]; 8650 descriptor.enumerable = descriptor.enumerable || false; 8651 descriptor.configurable = true; 8652 if ("value" in descriptor) descriptor.writable = true; 8653 Object.defineProperty(target, descriptor.key, descriptor); 8654 } 8655 } 8656 8657 return function (Constructor, protoProps, staticProps) { 8658 if (protoProps) defineProperties(Constructor.prototype, protoProps); 8659 if (staticProps) defineProperties(Constructor, staticProps); 8660 return Constructor; 8661 }; 8662 }(); 8663 8664 /** 8665 * Sticky Sidebar JavaScript Plugin. 8666 * @version 3.3.4 8667 * @author Ahmed Bouhuolia <[email protected]> 8668 * @license The MIT License (MIT) 8669 */ 8670 var StickySidebar = function () { 8671 8672 // ---------------------------------
vendor: 3,490 bytes, lines 8673-8794
8673 // # Define Constants 8674 // --------------------------------- 8675 // 8676 var EVENT_KEY = '.stickySidebar'; 8677 var DEFAULTS = { 8678 /** 8679 * Additional top spacing of the element when it becomes sticky. 8680 * @type {Numeric|Function} 8681 */ 8682 topSpacing: 0, 8683 8684 /** 8685 * Additional bottom spacing of the element when it becomes sticky. 8686 * @type {Numeric|Function} 8687 */ 8688 bottomSpacing: 0, 8689 8690 /** 8691 * Container sidebar selector to know what the beginning and end of sticky element. 8692 * @type {String|False} 8693 */ 8694 containerSelector: false, 8695 8696 /** 8697 * Inner wrapper selector. 8698 * @type {String} 8699 */ 8700 innerWrapperSelector: '.inner-wrapper-sticky', 8701 8702 /** 8703 * The name of CSS class to apply to elements when they have become stuck. 8704 * @type {String|False} 8705 */ 8706 stickyClass: 'is-affixed', 8707 8708 /** 8709 * Detect when sidebar and its container change height so re-calculate their dimensions. 8710 * @type {Boolean} 8711 */ 8712 resizeSensor: true, 8713 8714 /** 8715 * The sidebar returns to its normal position if its width below this value. 8716 * @type {Numeric} 8717 */ 8718 minWidth: false, 8719 8720 withTransForms: false 8721 }; 8722 8723 // --------------------------------- 8724 // # Class Definition 8725 // --------------------------------- 8726 // 8727 /** 8728 * Sticky Sidebar Class. 8729 * @public 8730 */ 8731 8732 var StickySidebar = function () { 8733 8734 /** 8735 * Sticky Sidebar Constructor. 8736 * @constructor 8737 * @param {HTMLElement|String} sidebar - The sidebar element or sidebar selector. 8738 * @param {Object} options - The options of sticky sidebar. 8739 */ 8740 function StickySidebar(sidebar) { 8741 var _this = this; 8742 8743 var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; 8744 8745 _classCallCheck(this, StickySidebar); 8746 8747 this.options = StickySidebar.extend(DEFAULTS, options); 8748 8749 // Sidebar element query if there's no one, throw error. 8750 this.sidebar = 'string' === typeof sidebar ? document.querySelector(sidebar) : sidebar; 8751 if ('undefined' === typeof this.sidebar) throw new Error("There is no specific sidebar element."); 8752 8753 this.sidebarInner = false; 8754 this.container = this.sidebar.parentElement; 8755 8756 // Current Affix Type of sidebar element. 8757 this.affixedType = 'STATIC'; 8758 this.direction = 'down'; 8759 this.support = { 8760 transform: false, 8761 transform3d: false 8762 }; 8763 8764 this._initialized = false; 8765 this._reStyle = false; 8766 this._breakpoint = false; 8767 8768 // Dimensions of sidebar, container and screen viewport. 8769 this.dimensions = { 8770 translateY: 0, 8771 maxTranslateY: 0, 8772 topSpacing: 0, 8773 lastTopSpacing: 0, 8774 bottomSpacing: 0, 8775 lastBottomSpacing: 0, 8776 sidebarHeight: 0, 8777 sidebarWidth: 0, 8778 containerTop: 0, 8779 containerHeight: 0, 8780 viewportHeight: 0, 8781 viewportTop: 0, 8782 lastViewportTop: 0 8783 }; 8784 8785 // Bind event handlers for referencability. 8786 ['handleEvent'].forEach(function (method) { 8787 _this[method] = _this[method].bind(_this); 8788 }); 8789 8790 // Initialize sticky sidebar for first time. 8791 this.initialize(); 8792 } 8793 8794 /**
8795 * Initializes the sticky sidebar by adding inner wrapper, define its container, 8796 * min-width breakpoint, calculating dimensions, adding helper classes and inline style. 8797 * @private 8798 */ 8799 8800 8801 _createClass(StickySidebar, [{ 8802 key: 'initialize', 8803 value: function initialize() { 8804 var _this2 = this; 8805 8806 this._setSupportFeatures(); 8807 8808 // Get sticky sidebar inner wrapper, if not found, will create one. 8809 if (this.options.innerWrapperSelector) { 8810 this.sidebarInner = this.sidebar.querySelector(this.options.innerWrapperSelector); 8811 8812 if (null === this.sidebarInner) this.sidebarInner = false; 8813 } 8814 8815 if (!this.sidebarInner) { 8816 var wrapper = document.createElement('div'); 8817 wrapper.setAttribute('class', 'inner-wrapper-sticky'); 8818 this.sidebar.appendChild(wrapper); 8819 8820 while (this.sidebar.firstChild != wrapper) { 8821 wrapper.appendChild(this.sidebar.firstChild); 8822 }this.sidebarInner = this.sidebar.querySelector('.inner-wrapper-sticky'); 8823 } 8824 8825 // Container wrapper of the sidebar. 8826 if (this.options.containerSelector) { 8827 var containers = document.querySelectorAll(this.options.containerSelector);
8828 containers = Array.prototype.slice.call(containers); 8829 8830 containers.forEach(function (container, item) { 8831 if (!container.contains(_this2.sidebar)) return; 8832 _this2.container = container; 8833 }); 8834 8835 if (!containers.length) throw new Error("The container does not contains on the sidebar."); 8836 } 8837 8838 // If top/bottom spacing is not function parse value to integer. 8839 if ('function' !== typeof this.options.topSpacing) this.options.topSpacing = parseInt(this.options.topSpacing) || 0; 8840 8841 if ('function' !== typeof this.options.bottomSpacing) this.options.bottomSpacing = parseInt(this.options.bottomSpacing) || 0; 8842 8843 // Breakdown sticky sidebar if screen width below `options.minWidth`. 8844 this._widthBreakpoint(); 8845 8846 // Calculate dimensions of sidebar, container and viewport. 8847 this.calcDimensions(); 8848 8849 // Affix sidebar in proper position. 8850 this.stickyPosition(); 8851 8852 // Bind all events. 8853 this.bindEvents(); 8854
8855 // Inform other properties the sticky sidebar is initialized. 8856 this._initialized = true; 8857 } 8858 }, { 8859 key: 'bindEvents', 8860 value: function bindEvents() { 8861 window.addEventListener('resize', this, { passive: true, capture: false }); 8862 window.addEventListener('scroll', this, { passive: true, capture: false }); 8863 8864 this.sidebar.addEventListener('update' + EVENT_KEY, this); 8865 8866 if (this.options.resizeSensor && 'undefined' !== typeof ResizeSensor) { 8867 new ResizeSensor(this.sidebarInner, this.handleEvent); 8868 new ResizeSensor(this.container, this.handleEvent); 8869 } 8870 } 8871 }, { 8872 key: 'handleEvent', 8873 value: function handleEvent(event) { 8874 this.updateSticky(event); 8875 } 8876 }, { 8877 key: 'calcDimensions', 8878 value: function calcDimensions() { 8879 if (this._breakpoint) return; 8880 var dims = this.dimensions; 8881 8882 // Container of sticky sidebar dimensions. 8883 dims.containerTop = StickySidebar.offsetRelative(this.container).top; 8884 dims.containerHeight = this.container.clientHeight; 8885 dims.containerBottom = dims.containerTop + dims.containerHeight; 8886 8887 // Sidebar dimensions. 8888 dims.sidebarHeight = this.sidebarInner.offsetHeight; 8889 dims.sidebarWidth = this.sidebarInner.offsetWidth; 8890 8891 // Screen viewport dimensions. 8892 dims.viewportHeight = window.innerHeight; 8893 8894 // Maximum sidebar translate Y. 8895 dims.maxTranslateY = dims.containerHeight - dims.sidebarHeight; 8896 8897 this._calcDimensionsWithScroll(); 8898 } 8899 }, { 8900 key: '_calcDimensionsWithScroll', 8901 value: function _calcDimensionsWithScroll() { 8902 var dims = this.dimensions; 8903 var horizontalSpacing = parseInt(getComputedStyle(this.sidebar).paddingLeft || 0, 10); 8904 dims.sidebarLeft = StickySidebar.offsetRelative(this.sidebar).left + horizontalSpacing; 8905 8906 dims.viewportTop = document.documentElement.scrollTop || document.body.scrollTop; 8907 dims.viewportBottom = dims.viewportTop + dims.viewportHeight; 8908 dims.viewportLeft = document.documentElement.scrollLeft || document.body.scrollLeft; 8909 8910 dims.topSpacing = this.options.topSpacing; 8911 dims.bottomSpacing = this.options.bottomSpacing; 8912 8913 if ('function' === typeof dims.topSpacing) dims.topSpacing = parseInt(dims.topSpacing(this.sidebar)) || 0; 8914 8915 if ('function' === typeof dims.bottomSpacing) dims.bottomSpacing = parseInt(dims.bottomSpacing(this.sidebar)) || 0; 8916 8917 if ('VIEWPORT-TOP' === this.affixedType) { 8918 // Adjust translate Y in the case decrease top spacing value. 8919 if (dims.topSpacing < dims.lastTopSpacing) { 8920 dims.translateY += dims.lastTopSpacing - dims.topSpacing; 8921 this._reStyle = true; 8922 } 8923 } else if ('VIEWPORT-BOTTOM' === this.affixedType) { 8924 // Adjust translate Y in the case decrease bottom spacing value. 8925 if (dims.bottomSpacing < dims.lastBottomSpacing) { 8926 dims.translateY += dims.lastBottomSpacing - dims.bottomSpacing; 8927 this._reStyle = true; 8928 } 8929 } 8930 8931 dims.lastTopSpacing = dims.topSpacing; 8932 dims.lastBottomSpacing = dims.bottomSpacing; 8933 } 8934 }, { 8935 key: 'isSidebarFitsViewport', 8936 value: function isSidebarFitsViewport() { 8937 var dims = this.dimensions; 8938 var offset = this.scrollDirection === 'down' ? dims.lastBottomSpacing : dims.lastTopSpacing; 8939 return this.dimensions.sidebarHeight + offset < this.dimensions.viewportHeight; 8940 } 8941 }, { 8942 key: 'observeScrollDir', 8943 value: function observeScrollDir() { 8944 var dims = this.dimensions; 8945 if (dims.lastViewportTop === dims.viewportTop) return; 8946 8947 var furthest = 'down' === this.direction ? Math.min : Math.max; 8948 8949 // If the browser is scrolling not in the same direction.
vendor: 5,617 bytes, lines 8950-9080
8950 if (dims.viewportTop === furthest(dims.viewportTop, dims.lastViewportTop)) this.direction = 'down' === this.direction ? 'up' : 'down'; 8951 } 8952 }, { 8953 key: 'getAffixType', 8954 value: function getAffixType() { 8955 this._calcDimensionsWithScroll(); 8956 var dims = this.dimensions; 8957 var colliderTop = dims.viewportTop + dims.topSpacing; 8958 var affixType = this.affixedType; 8959 8960 if (colliderTop <= dims.containerTop || dims.containerHeight <= dims.sidebarHeight) { 8961 dims.translateY = 0; 8962 affixType = 'STATIC'; 8963 } else { 8964 affixType = 'up' === this.direction ? this._getAffixTypeScrollingUp() : this._getAffixTypeScrollingDown(); 8965 } 8966 8967 // Make sure the translate Y is not bigger than container height. 8968 dims.translateY = Math.max(0, dims.translateY); 8969 dims.translateY = Math.min(dims.containerHeight, dims.translateY); 8970 dims.translateY = Math.round(dims.translateY); 8971 8972 dims.lastViewportTop = dims.viewportTop; 8973 return affixType; 8974 } 8975 }, { 8976 key: '_getAffixTypeScrollingDown', 8977 value: function _getAffixTypeScrollingDown() { 8978 var dims = this.dimensions; 8979 var sidebarBottom = dims.sidebarHeight + dims.containerTop; 8980 var colliderTop = dims.viewportTop + dims.topSpacing; 8981 var colliderBottom = dims.viewportBottom - dims.bottomSpacing; 8982 var affixType = this.affixedType; 8983 8984 if (this.isSidebarFitsViewport()) { 8985 if (dims.sidebarHeight + colliderTop >= dims.containerBottom) { 8986 dims.translateY = dims.containerBottom - sidebarBottom; 8987 affixType = 'CONTAINER-BOTTOM'; 8988 } else if (colliderTop >= dims.containerTop) { 8989 dims.translateY = colliderTop - dims.containerTop; 8990 affixType = 'VIEWPORT-TOP'; 8991 } 8992 } else { 8993 if (dims.containerBottom <= colliderBottom) { 8994 dims.translateY = dims.containerBottom - sidebarBottom; 8995 affixType = 'CONTAINER-BOTTOM'; 8996 } else if (sidebarBottom + dims.translateY <= colliderBottom) { 8997 dims.translateY = colliderBottom - sidebarBottom; 8998 affixType = 'VIEWPORT-BOTTOM'; 8999 } else if (dims.containerTop + dims.translateY <= colliderTop && 0 !== dims.translateY && dims.maxTranslateY !== dims.translateY) { 9000 affixType = 'VIEWPORT-UNBOTTOM'; 9001 } 9002 } 9003 9004 return affixType; 9005 } 9006 }, { 9007 key: '_getAffixTypeScrollingUp', 9008 value: function _getAffixTypeScrollingUp() { 9009 var dims = this.dimensions; 9010 var sidebarBottom = dims.sidebarHeight + dims.containerTop; 9011 var colliderTop = dims.viewportTop + dims.topSpacing; 9012 var colliderBottom = dims.viewportBottom - dims.bottomSpacing; 9013 var affixType = this.affixedType; 9014 9015 if (colliderTop <= dims.translateY + dims.containerTop) { 9016 dims.translateY = colliderTop - dims.containerTop; 9017 affixType = 'VIEWPORT-TOP'; 9018 } else if (dims.containerBottom <= colliderBottom) { 9019 dims.translateY = dims.containerBottom - sidebarBottom; 9020 affixType = 'CONTAINER-BOTTOM'; 9021 } else if (!this.isSidebarFitsViewport()) { 9022 9023 if (dims.containerTop <= colliderTop && 0 !== dims.translateY && dims.maxTranslateY !== dims.translateY) { 9024 affixType = 'VIEWPORT-UNBOTTOM'; 9025 } 9026 } 9027 9028 return affixType; 9029 } 9030 }, { 9031 key: '_getStyle', 9032 value: function _getStyle(affixType) { 9033 if ('undefined' === typeof affixType) return; 9034 9035 var style = { inner: {}, outer: {} }; 9036 var dims = this.dimensions; 9037 9038 switch (affixType) { 9039 case 'VIEWPORT-TOP': 9040 style.inner = { position: 'fixed', top: dims.topSpacing, 9041 left: dims.sidebarLeft - dims.viewportLeft, width: dims.sidebarWidth }; 9042 break; 9043 case 'VIEWPORT-BOTTOM': 9044 style.inner = { position: 'fixed', top: 'auto', left: dims.sidebarLeft, 9045 bottom: dims.bottomSpacing, width: dims.sidebarWidth }; 9046 break; 9047 case 'CONTAINER-BOTTOM': 9048 case 'VIEWPORT-UNBOTTOM': 9049 var translate = this._getTranslate(0, dims.translateY + 'px'); 9050 if (translate && this.options.withTransForms) style.inner = { transform: translate };else style.inner = { position: 'absolute', top: dims.translateY, width: dims.sidebarWidth }; 9051 break; 9052 } 9053 9054 switch (affixType) { 9055 case 'VIEWPORT-TOP': 9056 case 'VIEWPORT-BOTTOM': 9057 case 'VIEWPORT-UNBOTTOM': 9058 case 'CONTAINER-BOTTOM': 9059 style.outer = { position: 'relative' }; 9060 break; 9061 } 9062 9063 style.outer = StickySidebar.extend({ height: '', position: '' }, style.outer); 9064 style.inner = StickySidebar.extend({ position: 'relative', top: '', left: '', 9065 bottom: '', width: '', transform: '' }, style.inner); 9066 9067 return style; 9068 } 9069 }, { 9070 key: 'stickyPosition', 9071 value: function stickyPosition(force) { 9072 if (this._breakpoint) { 9073 return; 9074 }; 9075 9076 force = this._reStyle || force || false; 9077 9078 var offsetTop = this.options.topSpacing; 9079 var offsetBottom = this.options.bottomSpacing; 9080
vendor: 5,738 bytes, lines 9081-9213
9081 var affixType = this.getAffixType(); 9082 var style = this._getStyle(affixType); 9083 9084 if ((this.affixedType != affixType || force) && affixType) { 9085 var affixEvent = 'affix.' + affixType.toLowerCase().replace('viewport-', '') + EVENT_KEY; 9086 StickySidebar.eventTrigger(this.sidebar, affixEvent); 9087 9088 if ('STATIC' === affixType) StickySidebar.removeClass(this.sidebar, this.options.stickyClass);else StickySidebar.addClass(this.sidebar, this.options.stickyClass); 9089 9090 for (var key in style.outer) { 9091 var unit = 'number' === typeof style.outer[key] ? 'px' : ''; 9092 this.sidebar.style[key] = style.outer[key] + unit; 9093 } 9094 9095 for (var _key in style.inner) { 9096 var _unit = 'number' === typeof style.inner[_key] ? 'px' : ''; 9097 this.sidebarInner.style[_key] = style.inner[_key] + _unit; 9098 } 9099 9100 var affixedEvent = 'affixed.' + affixType.toLowerCase().replace('viewport-', '') + EVENT_KEY; 9101 StickySidebar.eventTrigger(this.sidebar, affixedEvent); 9102 } else { 9103 if (this._initialized) this.sidebarInner.style.left = (style.inner.left); 9104 } 9105 9106 this.affixedType = affixType; 9107 } 9108 }, { 9109 key: '_widthBreakpoint', 9110 value: function _widthBreakpoint() { 9111 if (window.innerWidth <= this.options.minWidth) { 9112 this.sidebar.removeAttribute('style'); 9113 StickySidebar.removeClass(this.sidebar, this.options.stickyClass); 9114 this.sidebarInner.removeAttribute('style'); 9115 if(!this._breakpoint) { 9116 StickySidebar.eventTrigger(this.sidebar, 'affix.breakpoint.stickySidebar'); 9117 } 9118 this._breakpoint = true; 9119 this.affixedType = 'STATIC'; 9120 } else { 9121 this._breakpoint = false; 9122 } 9123 } 9124 }, { 9125 key: 'updateSticky', 9126 value: function updateSticky() { 9127 var _this3 = this; 9128 9129 var event = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; 9130 9131 if (this._running) return; 9132 this._running = true; 9133 9134 (function (eventType) { 9135 requestAnimationFrame(function () { 9136 switch (eventType) { 9137 // When browser is scrolling and re-calculate just dimensions 9138 // within scroll. 9139 case 'scroll': 9140 _this3._calcDimensionsWithScroll(); 9141 _this3.observeScrollDir(); 9142 _this3.stickyPosition(); 9143 break; 9144 9145 // When browser is resizing or there's no event, observe width 9146 // breakpoint and re-calculate dimensions. 9147 case 'resize': 9148 default: 9149 _this3._widthBreakpoint(); 9150 _this3.calcDimensions(); 9151 _this3.stickyPosition(true); 9152 break; 9153 } 9154 _this3._running = false; 9155 }); 9156 })(event.type); 9157 } 9158 }, { 9159 key: '_setSupportFeatures', 9160 value: function _setSupportFeatures() { 9161 var support = this.support; 9162 9163 support.transform = StickySidebar.supportTransform(); 9164 support.transform3d = StickySidebar.supportTransform(true); 9165 } 9166 }, { 9167 key: '_getTranslate', 9168 value: function _getTranslate() { 9169 var y = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0; 9170 var x = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; 9171 var z = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0; 9172 9173 if (this.support.transform3d) return 'translate3d(' + y + ', ' + x + ', ' + z + ')';else if (this.support.translate) return 'translate(' + y + ', ' + x + ')';else return false; 9174 } 9175 }, { 9176 key: 'destroy', 9177 value: function destroy() { 9178 window.removeEventListener('resize', this, { capture: false }); 9179 window.removeEventListener('scroll', this, { capture: false }); 9180 9181 this.sidebar.classList.remove(this.options.stickyClass); 9182 this.sidebar.style.minHeight = ''; 9183 9184 this.sidebar.removeEventListener('update' + EVENT_KEY, this); 9185 9186 var styleReset = { inner: {}, outer: {} }; 9187 9188 styleReset.inner = { position: '', top: '', left: '', bottom: '', width: '', transform: '' }; 9189 styleReset.outer = { height: '', position: '' }; 9190 9191 for (var key in styleReset.outer) { 9192 this.sidebar.style[key] = styleReset.outer[key]; 9193 }for (var _key2 in styleReset.inner) { 9194 this.sidebarInner.style[_key2] = styleReset.inner[_key2]; 9195 }if (this.options.resizeSensor && 'undefined' !== typeof ResizeSensor) { 9196 ResizeSensor.detach(this.sidebarInner, this.handleEvent); 9197 ResizeSensor.detach(this.container, this.handleEvent); 9198 } 9199 } 9200 }], [{ 9201 key: 'supportTransform', 9202 value: function supportTransform(transform3d) { 9203 var result = false, 9204 property = transform3d ? 'perspective' : 'transform', 9205 upper = property.charAt(0).toUpperCase() + property.slice(1), 9206 prefixes = ['Webkit', 'Moz', 'O', 'ms'], 9207 support = document.createElement('support'), 9208 style = support.style; 9209 9210 (property + ' ' + prefixes.join(upper + ' ') + upper).split(' ').forEach(function (property, i) { 9211 if (style[property] !== undefined) { 9212 result = property; 9213 return false;
9214 } 9215 }); 9216 return result; 9217 } 9218 }, { 9219 key: 'eventTrigger', 9220 value: function eventTrigger(element, eventName, data) { 9221 try { 9222 var event = new CustomEvent(eventName, { detail: data }); 9223 } catch (e) { 9224 var event = document.createEvent('CustomEvent'); 9225 event.initCustomEvent(eventName, true, true, data); 9226 } 9227 element.dispatchEvent(event); 9228 } 9229 }, { 9230 key: 'extend', 9231 value: function extend(defaults, options) { 9232 var results = {}; 9233 for (var key in defaults) { 9234 if ('undefined' !== typeof options[key]) results[key] = options[key];else results[key] = defaults[key]; 9235 } 9236 return results; 9237 } 9238 }, { 9239 key: 'offsetRelative', 9240 value: function offsetRelative(element) { 9241 var result = { left: 0, top: 0 }; 9242 9243 do { 9244 var offsetTop = element.offsetTop; 9245 var offsetLeft = element.offsetLeft; 9246 9247 if (!isNaN(offsetTop)) result.top += offsetTop; 9248 9249 if (!isNaN(offsetLeft)) result.left += offsetLeft; 9250 9251 element = 'BODY' === element.tagName ? element.parentElement : element.offsetParent; 9252 } while (element); 9253 return result; 9254 } 9255 }, { 9256 key: 'addClass', 9257 value: function addClass(element, className) { 9258 if (!StickySidebar.hasClass(element, className)) { 9259 if (element.classList) element.classList.add(className);else element.className += ' ' + className; 9260 } 9261 } 9262 }, { 9263 key: 'removeClass', 9264 value: function removeClass(element, className) { 9265 if (StickySidebar.hasClass(element, className)) { 9266 if (element.classList) element.classList.remove(className);else element.className = element.className.replace(new RegExp('(^|\\b)' + className.split(' ').join('|') + '(\\b|$)', 'gi'), ' '); 9267 } 9268 } 9269 }, { 9270 key: 'hasClass', 9271 value: function hasClass(element, className) { 9272 if (element.classList) return element.classList.contains(className);else return new RegExp('(^| )' + className + '( |$)', 'gi').test(element.className); 9273 } 9274 }, { 9275 key: 'defaults', 9276 get: function () { 9277 return DEFAULTS; 9278 } 9279 }]); 9280 9281 return StickySidebar; 9282 }(); 9283 9284 return StickySidebar; 9285 }(); 9286 9287 exports.default = StickySidebar; 9288 9289 9290 // Global 9291 // ------------------------- 9292 window.StickySidebar = StickySidebar; 9293 }); 9294 }); 9295 9296 var stickySidebar$1 = unwrapExports(stickySidebar); 9297 9298 exports['default'] = stickySidebar$1; 9299 exports.__moduleExports = stickySidebar; 9300 9301 Object.defineProperty(exports, '__esModule', { value: true }); 9302 9303 }))); 9304 9305 /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }()))) 9306 9307/***/ }), 9308 9309/***/ 329: 9310/***/ (function(module, exports) { 9311 9312 window.AccordionView = (function () { 9313 function onAccordionTitleClick(event) { 9314 return event.target.classList.toggle('active'); 9315 } 9316 9317 function create(element) { 9318 if (typeof element !== 'undefined' && element != null) { 9319 element 9320 .querySelectorAll('.accordion-item > .accordion-title') 9321 .forEach(function (e) { 9322 e.addEventListener('click', onAccordionTitleClick); 9323 }); 9324 } 9325 } 9326 9327 return { 9328 create, 9329 }; 9330 })(); 9331 9332 9333/***/ }), 9334 9335/***/ 330: 9336/***/ (function(module, exports) { 9337 9338 window.ScrollableTabs = (function () { 9339 function createHandleScroll(container) { 9340 function handleScroll(e) { 9341 const target = e.target; 9342 9343 const firstHeaderRect = target.firstElementChild.getBoundingClientRect(); 9344 const lastHeaderRect = target.lastElementChild.getBoundingClientRect(); 9345 9346 container 9347 .querySelector('[role=scroll-arrow].left') 9348 .classList.toggle( 9349 'invisible', 9350 target.scrollLeft <= firstHeaderRect.left 9351 ); 9352 9353 let observer; 9354 9355 let options = { 9356 root: null, 9357 rootMargin: "0px", 9358 threshold: 1.0 9359 }; 9360 9361 observer = new IntersectionObserver(hideRightArrow, options); 9362 observer.observe(target.lastElementChild); 9363 9364 } 9365 9366 if (typeof window._ !== 'undefined') { 9367 return _.debounce(handleScroll, 300); 9368 } else { 9369 return handleScroll; 9370 } 9371 } 9372 9373 function hideRightArrow(entries) {
9374 entries.forEach((entry) => { 9375 const rightArrow = document.querySelector(".scrollable-tabs-headers__arrow.right"); 9376 9377 if (entry.isIntersecting) { 9378 rightArrow.style.display = "none"; 9379 } else { 9380 rightArrow.style.display = "block"; 9381 } 9382 }); 9383 } 9384 9385 function handleScrollArrowClick(e) { 9386 const isLeftScroll = 9387 e.target.getAttribute('data-scroll-direction') === 'left'; 9388 9389 const headers = e.target.parentElement.querySelector( 9390 '.scrollable-tabs-headers' 9391 ); 9392 headers.scrollBy({ 9393 left: isLeftScroll ? -100 : 100, 9394 top: 0, 9395 behavior: 'smooth', 9396 }); 9397 } 9398 9399 function onHeaderClick(event) { 9400 const itemId = event.target.getAttribute('data-item-id'); 9401 if ( 9402 typeof itemId === 'undefined' || 9403 itemId == null || 9404 event.target.classList.contains('active') 9405 ) { 9406 return; 9407 } 9408 9409 document 9410 .querySelectorAll( 9411 '.scrollable-tabs-headers__title, .scrollable-tabs-contents__content' 9412 ) 9413 .forEach((item) => item.classList.remove('active')); 9414 9415 event.target.classList.add('active'); 9416 document 9417 .querySelector( 9418 `.scrollable-tabs-contents__content[data-item-id="${itemId}"]` 9419 ) 9420 .classList.add('active'); 9421 9422 event.target.scrollIntoView({ 9423 behavior: 'smooth', 9424 block: 'nearest', 9425 }); 9426 } 9427 9428 function createContentFromData(container, data) { 9429 const headers = container.querySelector('.scrollable-tabs-headers'); 9430 const headersContainer = container.querySelector( 9431 '.scrollable-tabs-headers__container' 9432 ); 9433 const contents = container.querySelector('.scrollable-tabs-contents'); 9434 9435 data.forEach((item, i) => { 9436 if (typeof item === 'undefined' || typeof item.title === 'undefined') { 9437 return false; 9438 } 9439 9440 const header = document.createElement('div'); 9441 9442 header.classList.add('scrollable-tabs-headers__title'); 9443 header.setAttribute('data-item-id', i); 9444 9445 if (typeof item.title === 'object') { 9446 header.append(item.title); 9447 } else { 9448 header.innerHTML = item.title; 9449 } 9450 9451 const content = document.createElement('div'); 9452 content.classList.add('scrollable-tabs-contents__content'); 9453 content.setAttribute('data-item-id', i); 9454 if (typeof item.text === 'object') { 9455 if (Array.isArray(item.text)) { 9456 item.text.forEach(function (x) { 9457 content.append(x); 9458 }); 9459 } else { 9460 content.append(item.text); 9461 } 9462 } else { 9463 content.innerHTML = item.text; 9464 } 9465 9466 if (i === 0) { 9467 header.classList.add('active'); 9468 content.classList.add('active'); 9469 } 9470 9471 headers.append(header); 9472 contents.append(content); 9473 9474 return true; 9475 }); 9476 9477 headersContainer.firstElementChild.insertAdjacentElement( 9478 'afterend', 9479 headers 9480 ); 9481 container.append(headersContainer, contents); 9482 } 9483 9484 function init(element) { 9485 const headers = element.querySelector('.scrollable-tabs-headers'); 9486 const headersContainer = element.querySelector( 9487 '.scrollable-tabs-headers__container' 9488 ); 9489 9490 headersContainer 9491 .querySelectorAll('[role=scroll-arrow]') 9492 .forEach((el) => el.addEventListener('click', handleScrollArrowClick)); 9493 9494 headersContainer 9495 .querySelectorAll('.scrollable-tabs-headers__title') 9496 .forEach((el) => el.addEventListener('click', onHeaderClick)); 9497 9498 headers.addEventListener('scroll', createHandleScroll(headersContainer)); 9499 } 9500 return { 9501 init, 9502 createContentFromData: function (container, data) { 9503 createContentFromData(container, data); 9504 init(container); 9505 }, 9506 }; 9507 })(); 9508 9509 window.BranchDirectionParser = (function () { 9510 function parse(apiContent, cmsContent) { 9511 function getDirections(arr) { 9512 return arr.reduce((acc, element) => { 9513 const header = element.children[0]; 9514 acc.push({ 9515 title: header, 9516 text: element.children[1], 9517 }); 9518 9519 return acc; 9520 }, []); 9521 } 9522 9523 function getOthers(arr) { 9524 const title = arr.shift(); 9525 return [{ title, text: arr }]; 9526 } 9527 9528 function getContentAsElement(content) { 9529 const div = document.createElement('div'); 9530 div.innerHTML = content; 9531 return div; 9532 } 9533 9534 function getDirectionsFromCms(element) { 9535 let arrayOfElemets = [...element.children]; 9536 9537 arrayOfElemets.splice( 9538 0, 9539 arrayOfElemets.findIndex((x) => x.tagName === 'H3') 9540 ); 9541 9542 return getOthers(arrayOfElemets); 9543 } 9544 9545 function getDirectionsFromApi(element) { 9546 let arrayOfElemets = [...element.children]; 9547 return getDirections(arrayOfElemets); 9548 } 9549 9550 function parseDirections() { 9551 const parsedCmsContent = getContentAsElement(cmsContent); 9552 const parsedApiContent = getContentAsElement(apiContent); 9553 9554 return [ 9555 ...getDirectionsFromApi(parsedApiContent), 9556 ...getDirectionsFromCms(parsedCmsContent), 9557 ]; 9558 } 9559 9560 return parseDirections(); 9561 } 9562 return { parse }; 9563 })(); 9564 9565 9566/***/ }), 9567 9568/***/ 331: 9569/***/ (function(module, exports, __webpack_require__) { 9570 9571 __webpack_require__(332); 9572 __webpack_require__(333); 9573 __webpack_require__(334); 9574 __webpack_require__(335); 9575 __webpack_require__(336); 9576 __webpack_require__(337); 9577 __webpack_require__(338); 9578 __webpack_require__(339); 9579 9580 $(function(){ 9581 $(document).trigger('bv:init') 9582 .on('click', 'form [data-bv-submit]', function(e) { 9583 $(e.currentTarget).closest('form').submit(); 9584 }) 9585 .on('success.form.bv', 'form', function(e) { 9586 $(e.currentTarget).bootstrapValidator('defaultSubmit'); 9587 }) 9588 .on('select-auto-json:init',function(){ 9589 $('*[data-select-auto-json]').each(function(ind, obj){ 9590 $controlWrap = $(obj).parents('.control-fx'); 9591 9592 if ($controlWrap.hasClass('current-selection')){ 9593 $(obj).trigger('enable'); 9594 } else if (!$(obj).is(':disabled') && !$controlWrap.before().hasClass('current-selection')){ 9595 $(obj).trigger('enable'); 9596 $controlWrap.addClass('current-selection'); 9597 } 9598 }); 9599 $('select[data-initial-value]').trigger('select:set-initial-value'); 9600 }) 9601 .trigger('select-auto-json:init'); 9602 }); 9603 9604 9605/***/ }), 9606 9607/***/ 332:
9608/***/ (function(module, exports) { 9609 9610 /** 9611 * BootstrapValidator (http://bootstrapvalidator.com) 9612 * The best jQuery plugin to validate form fields. Designed to use with Bootstrap 3 9613 * 9614 * @author https://twitter.com/nghuuphuoc 9615 * @copyright (c) 2013 - 2014 Nguyen Huu Phuoc 9616 * @license Commercial: http://bootstrapvalidator.com/license/ 9617 * Non-commercial: http://creativecommons.org/licenses/by-nc-nd/3.0/ 9618 */ 9619 9620 (function($) { 9621 var BootstrapValidator = function(form, options) { 9622 this.$form = $(form); 9623 this.options = $.extend({}, $.fn.bootstrapValidator.DEFAULT_OPTIONS, options); 9624 9625 this.$invalidFields = $([]); // Array of invalid fields 9626 this.$submitButton = null; // The submit button which is clicked to submit form 9627 this.$hiddenButton = null; 9628 9629 // Validating status 9630 this.STATUS_NOT_VALIDATED = 'NOT_VALIDATED'; 9631 this.STATUS_VALIDATING = 'VALIDATING'; 9632 this.STATUS_INVALID = 'INVALID'; 9633 this.STATUS_VALID = 'VALID'; 9634 9635 // Determine the event that is fired when user change the field value 9636 // Most modern browsers supports input event except IE 7, 8. 9637 // IE 9 supports input event but the event is still not fired if I press the backspace key. 9638 // Get IE version 9639 // https://gist.github.com/padolsey/527683/#comment-7595 9640 var ieVersion = (function() { 9641 var v = 3, div = document.createElement('div'), a = div.all || []; 9642 while (div.innerHTML = '<!--[if gt IE '+(++v)+']><br><![endif]-->', a[0]) {} 9643 return v > 4 ? v : !v; 9644 }()); 9645 9646 var el = document.createElement('div'); 9647 this._changeEvent = (ieVersion === 9 || !('oninput' in el)) ? 'keyup' : 'input'; 9648 9649 // The flag to indicate that the form is ready to submit when a remote/callback validator returns 9650 this._submitIfValid = null; 9651 9652 // Field elements 9653 this._cacheFields = {}; 9654 9655 this._init(); 9656 }; 9657 9658 BootstrapValidator.prototype = { 9659 constructor: BootstrapValidator, 9660 9661 /** 9662 * Init form 9663 */ 9664 _init: function() { 9665 var that = this, 9666 options = { 9667 autoFocus: this.$form.attr('data-bv-autofocus'), 9668 container: this.$form.attr('data-bv-container'), 9669 events: { 9670 formInit: this.$form.attr('data-bv-events-form-init'), 9671 formError: this.$form.attr('data-bv-events-form-error'), 9672 formSuccess: this.$form.attr('data-bv-events-form-success'), 9673 fieldAdded: this.$form.attr('data-bv-events-field-added'), 9674 fieldRemoved: this.$form.attr('data-bv-events-field-removed'), 9675 fieldInit: this.$form.attr('data-bv-events-field-init'), 9676 fieldError: this.$form.attr('data-bv-events-field-error'), 9677 fieldSuccess: this.$form.attr('data-bv-events-field-success'), 9678 fieldStatus: this.$form.attr('data-bv-events-field-status'), 9679 validatorError: this.$form.attr('data-bv-events-validator-error'), 9680 validatorSuccess: this.$form.attr('data-bv-events-validator-success') 9681 }, 9682 excluded: this.$form.attr('data-bv-excluded'), 9683 feedbackIcons: { 9684 valid: this.$form.attr('data-bv-feedbackicons-valid'), 9685 invalid: this.$form.attr('data-bv-feedbackicons-invalid'), 9686 validating: this.$form.attr('data-bv-feedbackicons-validating') 9687 }, 9688 group: this.$form.attr('data-bv-group'), 9689 live: this.$form.attr('data-bv-live'), 9690 message: this.$form.attr('data-bv-message'), 9691 onError: this.$form.attr('data-bv-onerror'), 9692 onSuccess: this.$form.attr('data-bv-onsuccess'), 9693 submitButtons: this.$form.attr('data-bv-submitbuttons'), 9694 threshold: this.$form.attr('data-bv-threshold'), 9695 trigger: this.$form.attr('data-bv-trigger'), 9696 verbose: this.$form.attr('data-bv-verbose'), 9697 fields: {} 9698 }; 9699 9700 this.$form 9701 // Disable client side validation in HTML 5 9702 .attr('novalidate', 'novalidate') 9703 .addClass(this.options.elementClass) 9704 // Disable the default submission first 9705 .on('submit.bv', function(e) { 9706 e.preventDefault(); 9707 that.validate(); 9708 }) 9709 .on('click.bv', this.options.submitButtons, function() { 9710 that.$submitButton = $(this); 9711 // The user just click the submit button 9712 that._submitIfValid = true; 9713 }) 9714 // Find all fields which have either "name" or "data-bv-field" attribute 9715 .find('[name], [data-bv-field]') 9716 .each(function() { 9717 var $field = $(this), 9718 field = $field.attr('name') || $field.attr('data-bv-field'), 9719 opts = that._parseOptions($field); 9720 if (opts) { 9721 $field.attr('data-bv-field', field); 9722 options.fields[field] = $.extend({}, opts, options.fields[field]); 9723 } 9724 }); 9725 9726 this.options = $.extend(true, this.options, options); 9727 9728 // When pressing Enter on any field in the form, the first submit button will do its job. 9729 // The form then will be submitted. 9730 // I create a first hidden submit button 9731 this.$hiddenButton = $('<button/>') 9732 .attr('type', 'submit') 9733 .prependTo(this.$form) 9734 .addClass('bv-hidden-submit') 9735 .css({ display: 'none', width: 0, height: 0 }); 9736 9737 this.$form 9738 .on('click.bv', '[type="submit"]', function(e) { 9739 // #746: Check if the button click handler returns false 9740 if (!e.isDefaultPrevented()) { 9741 var $target = $(e.target), 9742 // The button might contain HTML tag 9743 $button = $target.is('[type="submit"]') ? $target.eq(0) : $target.parent('[type="submit"]').eq(0); 9744 9745 // Don't perform validation when clicking on the submit button/input 9746 // which aren't defined by the 'submitButtons' option 9747 if (that.options.submitButtons && !$button.is(that.options.submitButtons) && !$button.is(that.$hiddenButton)) { 9748 that.$form.off('submit.bv').submit(); 9749 } 9750 } 9751 }); 9752 9753 for (var field in this.options.fields) { 9754 this._initField(field); 9755 } 9756 9757 this.$form.trigger($.Event(this.options.events.formInit), { 9758 bv: this, 9759 options: this.options 9760 }); 9761 9762 // Prepare the events 9763 if (this.options.onSuccess) { 9764 this.$form.on(this.options.events.formSuccess, function(e) { 9765 $.fn.bootstrapValidator.helpers.call(that.options.onSuccess, [e]); 9766 }); 9767 } 9768 if (this.options.onError) { 9769 this.$form.on(this.options.events.formError, function(e) { 9770 $.fn.bootstrapValidator.helpers.call(that.options.onError, [e]); 9771 }); 9772 } 9773 }, 9774 9775 /** 9776 * Parse the validator options from HTML attributes 9777 * 9778 * @param {jQuery} $field The field element 9779 * @returns {Object} 9780 */ 9781 9782 _parseOptions: function($field) { 9783 var field = $field.attr('name') || $field.attr('data-bv-field'), 9784 validators = {}, 9785 validator, 9786 v, // Validator name 9787 attrName, 9788 enabled, 9789 optionName, 9790 optionAttrName, 9791 optionValue, 9792 html5AttrName, 9793 html5AttrMap; 9794 for (v in $.fn.bootstrapValidator.validators) { 9795 validator = $.fn.bootstrapValidator.validators[v]; 9796 attrName = 'data-bv-' + v.toLowerCase(); 9797 enabled = $field.attr(attrName) + ''; 9798 html5AttrMap = ('function' === typeof validator.enableByHtml5) ? validator.enableByHtml5($field) : null; 9799 if ( (html5AttrMap && enabled !== 'false') || 9800 (html5AttrMap !== true && ('' === enabled || 'true' === enabled || attrName === enabled.toLowerCase()))) 9801 { 9802 // Try to parse the options via attributes 9803 validator.html5Attributes = $.extend({}, { message: 'message', onerror: 'onError', onsuccess: 'onSuccess' }, validator.html5Attributes); 9804 validators[v] = $.extend({}, html5AttrMap === true ? {} : html5AttrMap, validators[v]); 9805 9806 for (html5AttrName in validator.html5Attributes) { 9807 optionName = validator.html5Attributes[html5AttrName]; 9808 optionAttrName = 'data-bv-' + v.toLowerCase() + '-' + html5AttrName; 9809 optionValue = $field.attr(optionAttrName); 9810 if (optionValue) { 9811 if ('true' === optionValue || optionAttrName === optionValue.toLowerCase()) { 9812 optionValue = true; 9813 } else if ('false' === optionValue) { 9814 optionValue = false;
9815 } 9816 validators[v][optionName] = optionValue; 9817 } 9818 } 9819 } 9820 } 9821 9822 var opts = { 9823 autoFocus: $field.attr('data-bv-autofocus'), 9824 container: $field.attr('data-bv-container'), 9825 excluded: $field.attr('data-bv-excluded'), 9826 feedbackIcons: $field.attr('data-bv-feedbackicons'), 9827 group: $field.attr('data-bv-group'), 9828 message: $field.attr('data-bv-message'), 9829 onError: $field.attr('data-bv-onerror'), 9830 onStatus: $field.attr('data-bv-onstatus'), 9831 onSuccess: $field.attr('data-bv-onsuccess'), 9832 selector: $field.attr('data-bv-selector'), 9833 threshold: $field.attr('data-bv-threshold'), 9834 trigger: $field.attr('data-bv-trigger'), 9835 verbose: $field.attr('data-bv-verbose'), 9836 validators: validators 9837 }, 9838 emptyOptions = $.isEmptyObject(opts), // Check if the field options are set using HTML attributes 9839 emptyValidators = $.isEmptyObject(validators); // Check if the field validators are set using HTML attributes 9840 9841 if (!emptyValidators || (!emptyOptions && this.options.fields && this.options.fields[field])) { 9842 opts.validators = validators; 9843 return opts; 9844 } else { 9845 return null; 9846 } 9847 }, 9848 9849 /** 9850 * Init field 9851 * 9852 * @param {String|jQuery} field The field name or field element 9853 */ 9854 _initField: function(field) { 9855 var fields = $([]); 9856 switch (typeof field) { 9857 case 'object': 9858 fields = field; 9859 field = field.attr('data-bv-field'); 9860 break; 9861 case 'string': 9862 fields = this.getFieldElements(field); 9863 fields.attr('data-bv-field', field); 9864 break; 9865 default: 9866 break; 9867 } 9868 9869 // We don't need to validate non-existing fields 9870 if (fields.length === 0) { 9871 return; 9872 } 9873 9874 if (this.options.fields[field] === null || this.options.fields[field].validators === null) { 9875 return; 9876 } 9877 9878 var validatorName; 9879 for (validatorName in this.options.fields[field].validators) { 9880 if (!$.fn.bootstrapValidator.validators[validatorName]) { 9881 delete this.options.fields[field].validators[validatorName]; 9882 } 9883 } 9884 if (this.options.fields[field].enabled === null) { 9885 this.options.fields[field].enabled = true; 9886 } 9887 9888 var that = this, 9889 total = fields.length, 9890 type = fields.attr('type'), 9891 updateAll = (total === 1) || ('radio' === type) || ('checkbox' === type), 9892 event = ('radio' === type || 'checkbox' === type || 'file' === type || 'SELECT' === fields.eq(0).get(0).tagName) ? 'change' : this._changeEvent, 9893 trigger = (this.options.fields[field].trigger || this.options.trigger || event).split(' '), 9894 events = $.map(trigger, function(item) { 9895 return item + '.update.bv'; 9896 }).join(' '); 9897 9898 for (var i = 0; i < total; i++) { 9899 var $field = fields.eq(i), 9900 group = this.options.fields[field].group || this.options.group, 9901 $parent = $field.parents(group), 9902 // Allow user to indicate where the error messages are shown 9903 container = ('function' === typeof (this.options.fields[field].container || this.options.container)) ? (this.options.fields[field].container || this.options.container).call(this, $field, this) : (this.options.fields[field].container || this.options.container), 9904 $message = (container && container !== 'tooltip' && container !== 'popover') ? $(container) : this._getMessageContainer($field, group); 9905 9906 if (container && container !== 'tooltip' && container !== 'popover') { 9907 $message.addClass('has-error'); 9908 } 9909 9910 // Remove all error messages and feedback icons 9911 $message.find('.help-block[data-bv-validator][data-bv-for="' + field + '"]').remove(); 9912 $parent.find('i[data-bv-icon-for="' + field + '"]').remove(); 9913 9914 // Whenever the user change the field value, mark it as not val
9914idated yet 9915 /*jshint -W083 */ 9916 $field.off(events).on(events, function() { 9917 that.updateStatus($(this), that.STATUS_NOT_VALIDATED); 9918 }); 9919 9920 // Create help block elements for showing the error messages 9921 $field.data('bv.messages', $message); 9922 for (validatorName in this.options.fields[field].validators) { 9923 $field.data('bv.result.' + validatorName, this.STATUS_NOT_VALIDATED); 9924 9925 if (!updateAll || i === total - 1) { 9926 $('<small/>') 9927 .css('display', 'none') 9928 .addClass('help-block') 9929 .attr('data-bv-validator', validatorName) 9930 .attr('data-bv-for', field) 9931 .attr('data-bv-result', this.STATUS_NOT_VALIDATED) 9932 .html(this._getMessage(field, validatorName)) 9933 .appendTo($message); 9934 } 9935 9936 // Init the validator 9937 if ('function' === typeof $.fn.bootstrapValidator.validators[validatorName].init) { 9938 $.fn.bootstrapValidator.validators[validatorName].init(this, $field, this.options.fields[field].validators[validatorName]); 9939 } 9940 } 9941 9942 // Prepare the feedback icons 9943 // Available from Bootstrap 3.1 (http://getbootstrap.com/css/#forms-control-validation) 9944 if (this.options.fields[field].feedbackIcons !== false && 9945 this.options.fields[field].feedbackIcons !== 'false' && 9946 this.options.feedbackIcons && 9947 this.options.feedbackIcons.validating && 9948 this.options.feedbackIcons.invalid && 9949 this.options.feedbackIcons.valid && 9950 (!updateAll || i === total - 1)) 9951 { 9952 // $parent.removeClass('has-success').removeClass('has-error').addClass('has-feedback'); 9953 // Keep error messages which are populated from back-end 9954 $parent.addClass('has-feedback'); 9955 var $icon = $('<i/>') 9956 .css('display', 'none') 9957 .addClass('form-control-feedback') 9958 .attr('data-bv-icon-for', field) 9959 .insertAfter($field); 9960 9961 // Place it after the container of checkbox/radio 9962 // so when clicking the icon, it doesn't effect to the checkbox/radio element 9963 if ('checkbox' === type || 'radio' === type) { 9964 var $fieldParent = $field.parent(); 9965 if ($fieldParent.hasClass(type)) { 9966 $icon.insertAfter($fieldParent); 9967 } else if ($fieldParent.parent().hasClass(type)) { 9968 $icon.insertAfter($fieldParent.parent()); 9969 } 9970 } 9971 9972 // The feedback icon does not render correctly if there is no label 9973 // https://github.com/twbs/bootstrap/issues/12873 9974 if ($parent.find('label').length === 0) { 9975 $icon.addClass('bv-no-label'); 9976 } 9977 // Fix feedback icons in input-group 9978 if ($parent.find('.input-group').length !== 0) { 9979 $icon.addClass('bv-icon-input-group') 9980 .insertAfter($parent.find('.input-group').eq(0)); 9981 } 9982 9983 // Store the icon as a data of field element 9984 if (!updateAll) { 9985 $field.data('bv.icon', $icon); 9986 } else if (i === total - 1) { 9987 // All fields with the same name have the same icon 9988 fields.data('bv.icon', $icon); 9989 } 9990 9991 if (container) { 9992 $field 9993 // Show tooltip/popover message when field gets focus 9994 .off('focus.container.bv') 9995 .on('focus.container.bv', function() { 9996 switch (container) { 9997 case 'tooltip': 9998 $(this).data('bv.icon').tooltip('show'); 9999 break; 10000 case 'popover': 10001 $(this).data('bv.icon').popover('show'); 10002 break; 10003 default: 10004 break; 10005 } 10006 }) 10007 // and hide them when losing focus 10008 .off('blur.container.bv') 10009 .on('blur.container.bv', function() { 10010 switch (container) { 10011 case 'tooltip': 10012 $(this).data('bv.icon').tooltip('hide'); 10013 break; 10014 case 'popover': 10015 $(this).data('bv.icon').popover('hide'); 10016 break; 10017 default: 10018 break; 10019 } 10020 }); 10021 } 10022 } 10023 } 10024 10025 // Prepare the events 10026 fields 10027 .on(this.options.events.fieldSuccess, function(e, data) { 10028 var onSuccess = that.getOptions(data.field, null, 'onSuccess'); 10029 if (onSuccess) { 10030 $.fn.bootstrapValidator.helpers.call(onSuccess, [e, data]); 10031 } 10032 }) 10033 .on(this.options.events.fieldError, function(e, data) { 10034 var onError = that.getOptions(data.field, null, 'onError'); 10035 if (onError) { 10036 $.fn.bootstrapValidator.helpers.call(onError, [e, data]); 10037 } 10038 }) 10039 .on(this.options.events.fieldStatus, function(e, data) { 10040 var onStatus = that.getOptions(data.field, null, 'onStatus'); 10041 if (onStatus) { 10042 $.fn.bootstrapValidator.helpers.call(onStatus, [e, data]); 10043 } 10044 }) 10045 .on(this.options.events.validatorError, function(e, data) { 10046 var onError = that.getOptions(data.field, data.validator, 'onError'); 10047 if (onError) { 10048 $.fn.bootstrapValidator.helpers.call(onError, [e, data]); 10049 } 10050 }) 10051 .on(this.options.events.validatorSuccess, function(e, data) { 10052 var onSuccess = that.getOptions(data.field, data.validator, 'onSuccess'); 10053 if (onSuccess) { 10054 $.fn.bootstrapValidator.helpers.call(onSuccess, [e, data]); 10055 } 10056 }); 10057 10058 // Set live mode 10059 events = $.map(trigger, function(item) { 10060 return item + '.live.bv'; 10061 }).join(' '); 10062 switch (this.options.live) { 10063 case 'submitted': 10064 break; 10065 case 'disabled': 10066 fields.off(events); 10067 break; 10068 case 'enabled': 10069 /* falls through */ 10070 default: 10071 fields.off(events).on(events, function() { 10072 if (that._exceedThreshold($(this))) { 10073 that.validateField($(this)); 10074 } 10075 }); 10076 break; 10077 } 10078 10079 fields.trigger($.Event(this.options.events.fieldInit), { 10080 bv: this, 10081 field: field, 10082 element: fields 10083 }); 10084 }, 10085 10086 /** 10087 * Get the error message for given field and validator 10088 * 10089 * @param {String} field The field name 10090 * @param {String} validatorName The validator name 10091 * @returns {String} 10092 */ 10093 _getMessage: function(field, validatorName) { 10094 if (!this.options.fields[field] || !$.fn.bootstrapValidator.validators[validatorName] || 10095 !this.options.fields[field].validators || 10096 !this.options.fields[field].validators[validatorName]) 10097 { 10098 return ''; 10099 } 10100 10101 var options = this.options.fields[field].validators[validatorName]; 10102 switch (true) { 10103 case (!!options.message): 10104 return options.message; 10105 case (!!this.options.fields[field].message): 10106 return this.options.fields[field].message; 10107 case (!!$.fn.bootstrapValidator.i18n[validatorName]): 10108 return $.fn.bootstrapValidator.i18n[validatorName]['default']; 10109 default: 10110 return this.options.message; 10111 } 10112 }, 10113 10114 /** 10115 * Get the element to place the error messages 10116 * 10117 * @param {jQuery} $field The field element 10118 * @param {String} group 10119 * @returns {jQuery} 10120 */ 10121 _getMessageContainer: function($field, group) { 10122 var $parent = $field.parent(); 10123 if ($parent.is(group)) { 10124 return $parent; 10125 } 10126
10127 var cssClasses = $parent.attr('class'); 10128 if (!cssClasses) { 10129 return this._getMessageContainer($parent, group); 10130 } 10131 10132 cssClasses = cssClasses.split(' '); 10133 var n = cssClasses.length; 10134 for (var i = 0; i < n; i++) { 10135 if (/^col-(xs|sm|md|lg)-\d+$/.test(cssClasses[i]) || /^col-(xs|sm|md|lg)-offset-\d+$/.test(cssClasses[i])) { 10136 return $parent; 10137 } 10138 } 10139 10140 return this._getMessageContainer($parent, group); 10141 }, 10142 10143 /** 10144 * Called when all validations are completed 10145 */ 10146 _submit: function() { 10147 var isValid = this.isValid(), 10148 eventType = isValid ? this.options.events.formSuccess : this.options.events.formError, 10149 e = $.Event(eventType); 10150 10151 this.$form.trigger(e); 10152 10153 // Call default handler 10154 // Check if whether the submit button is clicked 10155 if (this.$submitButton) { 10156 this[(isValid ? '_onSuccess' : '_onError')](e); 10157 } 10158 }, 10159 10160 /** 10161 * Check if the field is excluded. 10162 * Returning true means that the field will not be validated 10163 * 10164 * @param {jQuery} $field The field element 10165 * @returns {Boolean} 10166 */ 10167 _isExcluded: function($field) { 10168 var excludedAttr = $field.attr('data-bv-excluded'), 10169 // I still need to check the 'name' attribute while initializing the field 10170 field = $field.attr('data-bv-field') || $field.attr('name'); 10171 10172 switch (true) { 10173 case (!!field && this.options.fields && this.options.fields[field] && (this.options.fields[field].excluded === 'true' || this.options.fields[field].excluded === true)): 10174 case (excludedAttr === 'true'): 10175 case (excludedAttr === ''): 10176 return true; 10177 10178 case (!!field && this.options.fields && this.options.fields[field] && (this.options.fields[field].excluded === 'false' || this.options.fields[field].excluded === false)): 10179 case (excludedAttr === 'false'): 10180 return false; 10181 10182 default: 10183 if (this.options.excluded) { 10184 // Convert to array first 10185 if ('string' === typeof this.options.excluded) { 10186 this.options.excluded = $.map(this.options.excluded.split(','), function(item) { 10187 // Trim the spaces 10188 return $.trim(item); 10189 }); 10190 } 10191 10192 var length = this.options.excluded.length; 10193 for (var i = 0; i < length; i++) { 10194 if (('string' === typeof this.options.excluded[i] && $field.is(this.options.excluded[i])) || 10195 ('function' === typeof this.options.excluded[i] && this.options.excluded[i].call(this, $field, this) === true)) 10196 { 10197 return true; 10198 } 10199 } 10200 } 10201 return false; 10202 } 10203 }, 10204 10205 /** 10206 * Check if the number of characters of field value exceed the threshold or not 10207 * 10208 * @param {jQuery} $field The field element 10209 * @returns {Boolean} 10210 */ 10211 _exceedThreshold: function($field) { 10212 var field = $field.attr('data-bv-field'), 10213 threshold = this.options.fields[field].threshold || this.options.threshold; 10214 if (!threshold) { 10215 return true; 10216 } 10217 var cannotType = $.inArray($field.attr('type'), ['button', 'checkbox', 'file', 'hidden', 'image', 'radio', 'reset', 'submit']) !== -1; 10218 return (cannotType || $field.val().length >= threshold); 10219 }, 10220 10221 // --- 10222 // Events 10223 // --- 10224 10225 /** 10226 * The default handler of error.form.bv event. 10227 * It will be called when there is a invalid field 10228 * 10229 * @param {jQuery.Event} e The jQuery event object 10230 */ 10231 _onError: function(e) { 10232 if (e.isDefaultPrevented()) { 10233 return; 10234 } 10235 10236 if ('submitted' === this.options.live) { 10237 // Enable live mode 10238 this.options.live = 'enabled'; 10239 var that = this; 10240 for (var field in this.options.fields) { 10241 /*jshint -W083 */ 10242 (function(f) { 10243 var fields = that.getFieldElements(f); 10244 if (fields.length) { 10245 var type = $(fields[0]).attr('type'), 10246 event = ('radio' === type || 'checkbox' === type || 'file' === type || 'SELECT' === $(fields[0]).get(0).tagName) ? 'change' : that._changeEvent, 10247 trigger = that.options.fields[field].trigger || that.options.trigger || event, 10248 events = $.map(trigger.split(' '), function(item) { 10249 return item + '.live.bv'; 10250 }).join(' '); 10251 10252 fields.off(events).on(events, function() { 10253 if (that._exceedThreshold($(this))) { 10254 that.validateField($(this)); 10255 } 10256 }); 10257 } 10258 })(field); 10259 } 10260 } 10261 10262 // Determined the first invalid field which will be focused on automatically 10263 for (var i = 0; i < this.$invalidFields.length; i++) { 10264 var $field = this.$invalidFields.eq(i), 10265 autoFocus = this._isOptionEnabled($field.attr('data-bv-field'), 'autoFocus'); 10266 if (autoFocus) { 10267 // Activate the tab containing the field if exists 10268 var $tabPane = $field.parents('.tab-pane'), tabId; 10269 if ($tabPane && (tabId = $tabPane.attr('id'))) { 10270 $('a[href="#' + tabId + '"][data-toggle="tab"]').tab('show'); 10271 } 10272 10273 // Focus the field 10274 $field.focus(); 10275 break; 10276 } 10277 } 10278 }, 10279 10280 /** 10281 * The default handler of success.form.bv event. 10282 * It will be called when all the fields are valid 10283 * 10284 * @param {jQuery.Event} e The jQuery event object 10285 */ 10286 _onSuccess: function(e) { 10287 if (e.isDefaultPrevented()) { 10288 return; 10289 } 10290 10291 // Submit the form 10292 this.disableSubmitButtons(true).defaultSubmit(); 10293 }, 10294 10295 /** 10296 * Called after validating a field element 10297 * 10298 * @param {jQuery} $field The field element 10299 * @param {String} [validatorName] The validator name 10300 */ 10301 _onFieldValidated: function($field, validatorName) { 10302 var field = $field.attr('data-bv-field'), 10303 validators = this.options.fields[field].validators, 10304 counter = {}, 10305 numValidators = 0, 10306 data = { 10307 bv: this, 10308 field: field, 10309 element: $field, 10310 validator: validatorName, 10311 result: $field.data('bv.response.' + validatorName) 10312 }; 10313 10314 // Trigger an event after given validator completes 10315 if (validatorName) { 10316 switch ($field.data('bv.result.' + validatorName)) { 10317 case this.STATUS_INVALID: 10318 $field.trigger($.Event(this.options.events.validatorError), data); 10319 break; 10320 case this.STATUS_VALID: 10321 $field.trigger($.Event(this.options.events.validatorSuccess), data); 10322 break; 10323 default: 10324 break; 10325 } 10326 } 10327 10328 counter[this.STATUS_NOT_VALIDATED] = 0; 10329 counter[this.STATUS_VALIDATING] = 0; 10330 counter[this.STATUS_INVALID] = 0; 10331 counter[this.STATUS_VALID] = 0; 10332 10333 for (var v in validators) { 10334 if (validators[v].enabled === false) { 10335 continue; 10336 } 10337 10338 numValidators++; 10339 var result = $field.data('bv.result.' + v); 10340 if (result) { 10341 counter[result]++; 10342 } 10343 } 10344 10345 if (counter[this.STATUS_VALID] === numValidators) { 10346 // Remove from the list of invalid fields 10347 this.$invalidFields = this.$invalidFields.not($field); 10348 10349 $field.trigger($.Event(this.options.events.fieldSuccess), data); 10350 } 10351 // If all validators are completed and there is at least one validator which doesn't pass 10352 else if ((counter[this.STATUS_NOT_VALIDATED] === 0 || !this._isOptionEnabled(field, 'verbose')) && counter[this.STATUS_VALIDATING] === 0 && counter[this.STATUS_INVALID] > 0) { 10353 // Add to the list of invalid fields 10354 this.$invalidFields = this.$invalidFields.add($field); 10355 10356 $field.trigger($.Event(this.options.events.fieldError), data); 10357 } 10358 }, 10359 10360 /** 10361 * Check whether or not a field option is enabled 10362 * 10363 * @param {String} field The field name 10364 * @param {String} option The option name, "verbose", "autoFocus", for example 10365 * @returns {Boolean} 10366 */ 10367 _isOptionEnabled: function(field, option) { 10368 if (this.options.fields[field] && (this.options.fields[field][option] === 'true' || this.options.fields[field][option] === true)) { 10369 return true; 10370 } 10371 if (this.options.fields[field] && (this.options.fields[field][option] === 'false' || this.options.fields[field][option] === false)) { 10372 return false;
10373 } 10374 return this.options[option] === 'true' || this.options[option] === true; 10375 }, 10376 10377 // --- 10378 // Public methods 10379 // --- 10380 10381 /** 10382 * Retrieve the field elements by given name 10383 * 10384 * @param {String} field The field name 10385 * @returns {null|jQuery[]} 10386 */ 10387 getFieldElements: function(field) { 10388 if (!this._cacheFields[field]) { 10389 this._cacheFields[field] = (this.options.fields[field] && this.options.fields[field].selector) ? 10390 $(this.options.fields[field].selector) : 10391 this.$form.find('[name="' + field + '"]'); 10392 } 10393 10394 return this._cacheFields[field]; 10395 }, 10396 10397 /** 10398 * Get the field options 10399 * 10400 * @param {String|jQuery} [field] The field name or field element. If it is not set, the method returns the form options 10401 * @param {String} [validator] The name of validator. It null, the method returns form options 10402 * @param {String} [option] The option name 10403 * @return {String|Object} 10404 */ 10405 getOptions: function(field, validator, option) { 10406 if (!field) { 10407 return option ? this.options[option] : this.options; 10408 } 10409 if ('object' === typeof field) { 10410 field = field.attr('data-bv-field'); 10411 } 10412 if (!this.options.fields[field]) { 10413 return null; 10414 } 10415 10416 var options = this.options.fields[field]; 10417 if (!validator) { 10418 return option ? options[option] : options; 10419 } 10420 if (!options.validators || !options.validators[validator]) { 10421 return null; 10422 } 10423 10424 return option ? options.validators[validator][option] : options.validators[validator]; 10425 }, 10426 10427 /** 10428 * Disable/enable submit buttons 10429 * 10430 * @param {Boolean} disabled Can be true or false 10431 * @returns {BootstrapValidator} 10432 */ 10433 disableSubmitButtons: function(disabled) { 10434 if (!disabled) { 10435 this.$form.find(this.options.submitButtons).removeAttr('disabled'); 10436 } else if (this.options.live !== 'disabled') { 10437 // Don't disable if the live validating mode is disabled 10438 this.$form.find(this.options.submitButtons).attr('disabled', 'disabled'); 10439 } 10440 10441 return this; 10442 }, 10443 10444 /** 10445 * Validate the form 10446 * 10447 * @returns {BootstrapValidator} 10448 */ 10449 validate: function() { 10450 if (!this.options.fields) { 10451 return this; 10452 } 10453 this.disableSubmitButtons(true); 10454 10455 this._submitIfValid = false; 10456 for (var field in this.options.fields) { 10457 this.validateField(field); 10458 } 10459 10460 this._submit(); 10461 this._submitIfValid = true; 10462 10463 return this; 10464 }, 10465 10466 /** 10467 * Validate given field 10468 * 10469 * @param {String|jQuery} field The field name or field element 10470 * @returns {BootstrapValidator} 10471 */ 10472 validateField: function(field) { 10473 var fields = $([]); 10474 switch (typeof field) { 10475 case 'object': 10476 fields = field; 10477 field = field.attr('data-bv-field'); 10478 break; 10479 case 'string': 10480 fields = this.getFieldElements(field); 10481 break; 10482 default: 10483 break; 10484 } 10485 10486 if (fields.length === 0 || !this.options.fields[field] || this.options.fields[field].enabled === false) { 10487 return this; 10488 } 10489 10490 var that = this, 10491 type = fields.attr('type'), 10492 total = ('radio' === type || 'checkbox' === type) ? 1 : fields.length, 10493 updateAll = ('radio' === type || 'checkbox' === type), 10494 validators = this.options.fields[field].validators, 10495 verbose = this._isOptionEnabled(field, 'verbose'), 10496 validatorName, 10497 validateResult; 10498 10499 for (var i = 0; i < total; i++) { 10500 var $field = fields.eq(i); 10501 if (this._isExcluded($field)) { 10502 continue; 10503 } 10504 10505 var stop = false; 10506 for (validatorName in validators) { 10507 if ($field.data('bv.dfs.' + validatorName)) { 10508 $field.data('bv.dfs.' + validatorName).reject(); 10509 } 10510 if (stop) { 10511 break; 10512 } 10513 10514 // Don't validate field if it is already done 10515 var result = $field.data('bv.result.' + validatorName); 10516 if (result === this.STATUS_VALID || result === this.STATUS_INVALID) { 10517 this._onFieldValidated($field, validatorName); 10518 continue; 10519 } else if (validators[validatorName].enabled === false) { 10520 this.updateStatus(updateAll ? field : $field, this.STATUS_VALID, validatorName); 10521 continue; 10522 } 10523 10524 $field.data('bv.result.' + validatorName, this.STATUS_VALIDATING); 10525 validateResult = $.fn.bootstrapValidator.validators[validatorName].validate(this, $field, validators[validatorName]); 10526 10527 // validateResult can be a $.Deferred object ... 10528 if ('object' === typeof validateResult && validateResult.resolve) { 10529 this.updateStatus(updateAll ? field : $field, this.STATUS_VALIDATING, validatorName); 10530 $field.data('bv.dfs.' + validatorName, validateResult); 10531 /*jshint -W083 */ 10532 validateResult.done(function($f, v, response) { 10533 // v is validator name 10534 $f.removeData('bv.dfs.' + v).data('bv.response.' + v, response); 10535 if (response.message) { 10536 that.updateMessage($f, v, response.message); 10537 } 10538 10539 that.updateStatus(updateAll ? $f.attr('data-bv-field') : $f, response.valid ? that.STATUS_VALID : that.STATUS_INVALID, v); 10540 10541 if (response.valid && that._submitIfValid === true) { 10542 // If a remote validator returns true and the form is ready to submit, then do it 10543 that._submit(); 10544 } else if (!response.valid && !verbose) { 10545 stop = true; 10546 } 10547 }); 10548 }
10549 // ... or object { valid: true/false, message: 'dynamic message' } 10550 else if ('object' === typeof validateResult && validateResult.valid !== undefined && validateResult.message !== undefined) { 10551 $field.data('bv.response.' + validatorName, validateResult); 10552 this.updateMessage(updateAll ? field : $field, validatorName, validateResult.message); 10553 this.updateStatus(updateAll ? field : $field, validateResult.valid ? this.STATUS_VALID : this.STATUS_INVALID, validatorName); 10554 if (!validateResult.valid && !verbose) { 10555 break; 10556 } 10557 } 10558 // ... or a boolean value 10559 else if ('boolean' === typeof validateResult) { 10560 $field.data('bv.response.' + validatorName, validateResult); 10561 this.updateStatus(updateAll ? field : $field, validateResult ? this.STATUS_VALID : this.STATUS_INVALID, validatorName); 10562 if (!validateResult && !verbose) { 10563 break; 10564 } 10565 } 10566 } 10567 } 10568 10569 return this; 10570 }, 10571 10572 /** 10573 * Update the error message 10574 * 10575 * @param {String|jQuery} field The field name or field element 10576 * @param {String} validator The validator name 10577 * @param {String} message The message 10578 * @returns {BootstrapValidator} 10579 */ 10580 updateMessage: function(field, validator, message) { 10581 var $fields = $([]); 10582 switch (typeof field) { 10583 case 'object': 10584 $fields = field; 10585 field = field.attr('data-bv-field'); 10586 break; 10587 case 'string': 10588 $fields = this.getFieldElements(field); 10589 break; 10590 default: 10591 break; 10592 } 10593 10594 $fields.each(function() { 10595 $(this).data('bv.messages').find('.help-block[data-bv-validator="' + validator + '"][data-bv-for="' + field + '"]').html(message); 10596 }); 10597 }, 10598 10599 /** 10600 * Update all validating results of field 10601 * 10602 * @param {String|jQuery} field The field name or field element 10603 * @param {String} status The status. Can be 'NOT_VALIDATED', 'VALIDATING', 'INVALID' or 'VALID' 10604 * @param {String} [validatorName] The validator name. If null, the method updates validity result for all validators 10605 * @returns {BootstrapValidator} 10606 */ 10607 updateStatus: function(field, status, validatorName) { 10608 var fields = $([]); 10609 switch (typeof field) { 10610 case 'object': 10611 fields = field; 10612 field = field.attr('data-bv-field'); 10613 break; 10614 case 'string': 10615 fields = this.getFieldElements(field); 10616 break; 10617 default: 10618 break; 10619 } 10620 10621 if (status === this.STATUS_NOT_VALIDATED) { 10622 // Reset the flag 10623 // To prevent the form from doing submit when a deferred validator returns true while typing 10624 this._submitIfValid = false; 10625 } 10626 10627 var that = this, 10628 type = fields.attr('type'), 10629 group = this.options.fields[field].group || this.options.group, 10630 total = ('radio' === type || 'checkbox' === type) ? 1 : fields.length; 10631 10632 for (var i = 0; i < total; i++) { 10633 var $field = fields.eq(i); 10634 if (this._isExcluded($field)) { 10635 continue; 10636 } 10637 10638 var $parent = $field.parents(group), 10639 $message = $field.data('bv.messages'), 10640 $allErrors = $message.find('.help-block[data-bv-validator][data-bv-for="' + field + '"]'), 10641 $errors = validatorName ? $allErrors.filter('[data-bv-validator="' + validatorName + '"]') : $allErrors, 10642 $icon = $field.data('bv.icon'), 10643 container = ('function' === typeof (this.options.fields[field].container || this.options.container)) ? (this.options.fields[field].container || this.options.container).call(this, $field, this) : (this.options.fields[field].container || this.options.container), 10644 isValidField = null; 10645 10646 // Update status 10647 if (validatorName) { 10648 $field.data('bv.result.' + validatorName, status); 10649 } else { 10650 for (var v in this.options.fields[field].validators) { 10651 $field.data('bv.result.' + v, status); 10652 } 10653 } 10654 10655 // Show/hide error elements and feedback icons 10656 $errors.attr('data-bv-result', status); 10657 10658 // Determine the tab containing the element 10659 var $tabPane = $field.parents('.tab-pane'), 10660 tabId, $tab; 10661 if ($tabPane && (tabId = $tabPane.attr('id'))) { 10662 $tab = $('a[href="#' + tabId + '"][data-toggle="tab"]').parent(); 10663 } 10664 10665 switch (status) { 10666 case this.STATUS_VALIDATING: 10667 isValidField = null; 10668 this.disableSubmitButtons(true); 10669 $parent.removeClass('has-success').removeClass('has-error'); 10670 if ($icon) { 10671 $icon.removeClass(this.options.feedbackIcons.valid).removeClass(this.options.feedbackIcons.invalid).addClass(this.options.feedbackIcons.validating).show(); 10672 } 10673 if ($tab) { 10674 $tab.removeClass('bv-tab-success').removeClass('bv-tab-error'); 10675 } 10676 break; 10677 10678 case this.STATUS_INVALID: 10679 isValidField = false;
10680 this.disableSubmitButtons(true); 10681 $parent.removeClass('has-success').addClass('has-error'); 10682 if ($icon) { 10683 $icon.removeClass(this.options.feedbackIcons.valid).removeClass(this.options.feedbackIcons.validating).addClass(this.options.feedbackIcons.invalid).show(); 10684 } 10685 if ($tab) { 10686 $tab.removeClass('bv-tab-success').addClass('bv-tab-error'); 10687 } 10688 break; 10689 10690 case this.STATUS_VALID: 10691 // If the field is valid (passes all validators) 10692 isValidField = ($allErrors.filter('[data-bv-result="' + this.STATUS_NOT_VALIDATED +'"]').length === 0) ? 10693 ($allErrors.filter('[data-bv-result="' + this.STATUS_VALID +'"]').length === $allErrors.length) : // All validators are completed 10694 null; // There are some validators that have not done 10695 if (isValidField !== null) { 10696 this.disableSubmitButtons(this.$submitButton ? !this.isValid() : !isValidField); 10697 if ($icon) { 10698 $icon 10699 .removeClass(this.options.feedbackIcons.invalid).removeClass(this.options.feedbackIcons.validating).removeClass(this.options.feedbackIcons.valid) 10700 .addClass(isValidField ? this.options.feedbackIcons.valid : this.options.feedbackIcons.invalid) 10701 .show(); 10702 } 10703 } 10704 10705 $parent.removeClass('has-error has-success').addClass(this.isValidContainer($parent) ? 'has-success' : 'has-error'); 10706 if ($tab) { 10707 $tab.removeClass('bv-tab-success').removeClass('bv-tab-error').addClass(this.isValidContainer($tabPane) ? 'bv-tab-success' : 'bv-tab-error'); 10708 } 10709 break; 10710 10711 case this.STATUS_NOT_VALIDATED: 10712 /* falls through */ 10713 default: 10714 isValidField = null; 10715 this.disableSubmitButtons(false); 10716 $parent.removeClass('has-success').removeClass('has-error'); 10717 if ($icon) { 10718 $icon.removeClass(this.options.feedbackIcons.valid).removeClass(this.options.feedbackIcons.invalid).removeClass(this.options.feedbackIcons.validating).hide(); 10719 } 10720 if ($tab) { 10721 $tab.removeClass('bv-tab-success').removeClass('bv-tab-error'); 10722 } 10723 break; 10724 } 10725 10726 switch (true) { 10727 // Only show the first error message if it is placed inside a tooltip ... 10728 case ($icon && 'tooltip' === container): 10729 if (isValidField === false) { 10730 $icon.css('cursor', 'pointer').tooltip('destroy').tooltip({ 10731 container: 'body', 10732 html: true, 10733 placement: 'auto top', 10734 title: $allErrors.filter('[data-bv-result="' + that.STATUS_INVALID + '"]').eq(0).html() 10735 }); 10736 }else { 10737 $icon.css('cursor', '').tooltip('destroy'); 10738 } 10739 break; 10740 // ... or popover 10741 case ($icon && 'popover' === container): 10742 if (isValidField === false) { 10743 $icon.css('cursor', 'pointer').popover('destroy').popover({ 10744 container: 'body', 10745 content: $allErrors.filter('[data-bv-result="' + that.STATUS_INVALID + '"]').eq(0).html(), 10746 html: true, 10747 placement: 'auto top', 10748 trigger: 'hover click' 10749 }); 10750 }else{ 10751 $icon.css('cursor', '').popover('destroy'); 10752 } 10753 break; 10754 default: 10755 10756 ($errors[ (status === this.STATUS_INVALID) ? 'show' : 'hide'])(); 10757 10758 break; 10759 } 10760 10761 // Trigger an event 10762 $field.trigger($.Event(this.options.events.fieldStatus), { 10763 bv: this, 10764 field: field, 10765 element: $field, 10766 status: status 10767 }); 10768 this._onFieldValidated($field, validatorName); 10769 } 10770 10771 return this; 10772 }, 10773 10774 /** 10775 * Check the form validity 10776 * 10777 * @returns {Boolean} 10778 */ 10779 isValid: function() { 10780 for (var field in this.options.fields) { 10781 if (!this.isValidField(field)) { 10782 return false;
10783 } 10784 } 10785 10786 return true; 10787 }, 10788 10789 /** 10790 * Check if the field is valid or not 10791 * 10792 * @param {String|jQuery} field The field name or field element 10793 * @returns {Boolean} 10794 */ 10795 isValidField: function(field) { 10796 var fields = $([]); 10797 switch (typeof field) { 10798 case 'object': 10799 fields = field; 10800 field = field.attr('data-bv-field'); 10801 break; 10802 case 'string': 10803 fields = this.getFieldElements(field); 10804 break; 10805 default: 10806 break; 10807 } 10808 if (fields.length === 0 || !this.options.fields[field] || this.options.fields[field].enabled === false) { 10809 return true; 10810 } 10811 10812 var type = fields.attr('type'), 10813 total = ('radio' === type || 'checkbox' === type) ? 1 : fields.length, 10814 $field, validatorName, status; 10815 for (var i = 0; i < total; i++) { 10816 $field = fields.eq(i); 10817 if (this._isExcluded($field)) { 10818 continue; 10819 } 10820 10821 for (validatorName in this.options.fields[field].validators) { 10822 if (this.options.fields[field].validators[validatorName].enabled === false) { 10823 continue; 10824 } 10825 10826 status = $field.data('bv.result.' + validatorName); 10827 if (status !== this.STATUS_VALID) { 10828 return false; 10829 } 10830 } 10831 } 10832 10833 return true; 10834 }, 10835 10836 /** 10837 * Check if all fields inside a given container are valid. 10838 * It's useful when working with a wizard-like such as tab, collapse 10839 * 10840 * @param {String|jQuery} container The container selector or element 10841 * @returns {Boolean} 10842 */ 10843 isValidContainer: function(container) { 10844 var that = this, 10845 map = {}, 10846 $container = ('string' === typeof container) ? $(container) : container; 10847 if ($container.length === 0) { 10848 return true; 10849 } 10850 10851 $container.find('[data-bv-field]').each(function() { 10852 var $field = $(this), 10853 field = $field.attr('data-bv-field'); 10854 if (!that._isExcluded($field) && !map[field]) { 10855 map[field] = $field; 10856 } 10857 }); 10858 10859 for (var field in map) { 10860 var $f = map[field]; 10861 if ($f.data('bv.messages') 10862 .find('.help-block[data-bv-validator][data-bv-for="' + field + '"]') 10863 .filter('[data-bv-result="' + this.STATUS_INVALID +'"]') 10864 .length > 0) 10865 { 10866 return false; 10867 } 10868 } 10869 10870 return true; 10871 }, 10872 10873 /** 10874 * Submit the form using default submission. 10875 * It also does not perform any validations when submitting the form 10876 */ 10877 defaultSubmit: function() { 10878 if (this.$submitButton) { 10879 // Create hidden input to send the submit buttons 10880 $('<input/>') 10881 .attr('type', 'hidden') 10882 .attr('data-bv-submit-hidden', '') 10883 .attr('name', this.$submitButton.attr('name')) 10884 .val(this.$submitButton.val()) 10885 .appendTo(this.$form); 10886 } 10887 10888 // Submit form 10889 this.$form.off('submit.bv').submit(); 10890 }, 10891 10892 // --- 10893 // Useful APIs which aren't used internally 10894 // --- 10895 10896 /** 10897 * Get the list of invalid fields 10898 * 10899 * @returns {jQuery[]} 10900 */ 10901 getInvalidFields: function() { 10902 return this.$invalidFields; 10903 }, 10904 10905 /** 10906 * Returns the clicked submit button 10907 * 10908 * @returns {jQuery} 10909 */ 10910 getSubmitButton: function() { 10911 return this.$submitButton; 10912 }, 10913 10914 /** 10915 * Get the error messages 10916 * 10917 * @param {String|jQuery} [field] The field name or field element 10918 * If the field is not defined, the method returns all error messages of all fields 10919 * @param {String} [validator] The name of validator 10920 * If the validator is not defined, the method returns error messages of all validators 10921 * @returns {String[]} 10922 */ 10923 getMessages: function(field, validator) { 10924 var that = this, 10925 messages = [], 10926 $fields = $([]); 10927 10928 switch (true) { 10929 case (field && 'object' === typeof field): 10930 $fields = field; 10931 break; 10932 case (field && 'string' === typeof field): 10933 var f = this.getFieldElements(field); 10934 if (f.length > 0) { 10935 var type = f.attr('type'); 10936 $fields = ('radio' === type || 'checkbox' === type) ? f.eq(0) : f; 10937 } 10938 break; 10939 default: 10940 $fields = this.$invalidFields; 10941 break; 10942 } 10943 10944 var filter = validator ? '[data-bv-validator="' + validator + '"]' : ''; 10945 $fields.each(function() { 10946 messages = messages.concat( 10947 $(this) 10948 .data('bv.messages') 10949 .find('.help-block[data-bv-for="' + $(this).attr('data-bv-field') + '"][data-bv-result="' + that.STATUS_INVALID + '"]' + filter) 10950 .map(function() { 10951 var v = $(this).attr('data-bv-validator'), 10952 f = $(this).attr('data-bv-for'); 10953 return (that.options.fields[f].validators[v].enabled === false) ? '' : $(this).html(); 10954 }) 10955 .get() 10956 ); 10957 }); 10958 10959 return messages; 10960 }, 10961 10962 /** 10963 * Update the option of a specific validator 10964 * 10965 * @param {String|jQuery} field The field name or field element 10966 * @param {String} validator The validator name 10967 * @param {String} option The option name 10968 * @param {String} value The value to set 10969 * @returns {BootstrapValidator} 10970 */ 10971 updateOption: function(field, validator, option, value) { 10972 if ('object' === typeof field) { 10973 field = field.attr('data-bv-field'); 10974 } 10975 if (this.options.fields[field] && this.options.fields[field].validators[validator]) { 10976 this.options.fields[field].validators[validator][option] = value; 10977 this.updateStatus(field, this.STATUS_NOT_VALIDATED, validator); 10978 } 10979 10980 return this; 10981 }, 10982 10983 /** 10984 * Add a new field 10985 * 10986 * @param {String|jQuery} field The field name or field element 10987 * @param {Object} [options] The validator rules 10988 * @returns {BootstrapValidator} 10989 */ 10990 addField: function(field, options) { 10991 var fields = $([]); 10992 switch (typeof field) { 10993 case 'object': 10994 fields = field; 10995 field = field.attr('data-bv-field') || field.attr('name'); 10996 break; 10997 case 'string': 10998 delete this._cacheFields[field]; 10999 fields = this.getFieldElements(field); 11000 break; 11001 default: 11002 break; 11003 } 11004 11005 fields.attr('data-bv-field', field); 11006 11007 var type = fields.attr('type'), 11008 total = ('radio' === type || 'checkbox' === type) ? 1 : fields.length; 11009 11010 for (var i = 0; i < total; i++) { 11011 var $field = fields.eq(i); 11012 11013 // Try to parse the options from HTML attributes 11014 var opts = this._parseOptions($field); 11015 opts = (opts === null) ? options : $.extend(true, options, opts); 11016 11017 this.options.fields[field] = $.extend(true, this.options.fields[field], opts); 11018 11019 // Update the cache 11020 this._cacheFields[field] = this._cacheFields[field] ? this._cacheFields[field].add($field) : $field; 11021 11022 // Init the element 11023 this._initField(('checkbox' === type || 'radio' === type) ? field : $field); 11024 } 11025 11026 this.disableSubmitButtons(false); 11027 // Trigger an event 11028 this.$form.trigger($.Event(this.options.events.fieldAdded), { 11029 field: field, 11030 element: fields, 11031 options: this.options.fields[field] 11032 }); 11033 11034 return this; 11035 }, 11036 11037 /** 11038 * Remove a given field 11039 * 11040 * @param {String|jQuery} field The field name or field element 11041 * @returns {BootstrapValidator} 11042 */ 11043 removeField: function(field) { 11044 var fields = $([]); 11045 switch (typeof field) { 11046 case 'object': 11047 fields = field; 11048 field = field.attr('data-bv-field') || field.attr('name'); 11049 fields.attr('data-bv-field', field); 11050 break; 11051 case 'string': 11052 fields = this.getFieldElements(field); 11053 break; 11054 default: 11055 break; 11056 } 11057 11058 if (fields.length === 0) { 11059 return this; 11060 } 11061 11062 var type = fields.attr('type'), 11063 total = ('radio' === type || 'checkbox' === type) ? 1 : fields.length; 11064 11065 for (var i = 0; i < total; i++) { 11066 var $field = fields.eq(i); 11067 11068 // Remove from the list of invalid fields 11069 this.$invalidFields = this.$invalidFields.not($field); 11070 11071 // Update the cache 11072 this._cacheFields[field] = this._cacheFields[field].not($field); 11073 } 11074 11075 if (!this._cacheFields[field] || this._cacheFields[field].length === 0) { 11076 delete this.options.fields[field]; 11077 }
11078 if ('checkbox' === type || 'radio' === type) { 11079 this._initField(field); 11080 } 11081 11082 this.disableSubmitButtons(false); 11083 // Trigger an event 11084 this.$form.trigger($.Event(this.options.events.fieldRemoved), { 11085 field: field, 11086 element: fields 11087 }); 11088 11089 return this; 11090 }, 11091 11092 /** 11093 * Reset given field 11094 * 11095 * @param {String|jQuery} field The field name or field element 11096 * @param {Boolean} [resetValue] If true, the method resets field value to empty or remove checked/selected attribute (for radio/checkbox) 11097 * @returns {BootstrapValidator} 11098 */ 11099 resetField: function(field, resetValue) { 11100 var $fields = $([]); 11101 switch (typeof field) { 11102 case 'object': 11103 $fields = field; 11104 field = field.attr('data-bv-field'); 11105 break; 11106 case 'string': 11107 $fields = this.getFieldElements(field); 11108 break; 11109 default: 11110 break; 11111 } 11112 11113 var total = $fields.length; 11114 if (this.options.fields[field]) { 11115 for (var i = 0; i < total; i++) { 11116 for (var validator in this.options.fields[field].validators) { 11117 $fields.eq(i).removeData('bv.dfs.' + validator); 11118 } 11119 } 11120 } 11121
11122 // Mark field as not validated yet 11123 this.updateStatus(field, this.STATUS_NOT_VALIDATED); 11124 11125 if (resetValue) { 11126 var type = $fields.attr('type'); 11127 if ('radio' === type || 'checkbox' === type) { 11128 $fields.removeAttr('checked').removeAttr('selected'); 11129 }else{ 11130 $fields.val(''); 11131 } 11132 } 11133 11134 return this; 11135 }, 11136 11137 /** 11138 * Reset the form 11139 * 11140 * @param {Boolean} [resetValue] If true, the method resets field value to empty or remove checked/selected attribute (for radio/checkbox) 11141 * @returns {BootstrapValidator} 11142 */ 11143 resetForm: function(resetValue) { 11144 for (var field in this.options.fields) { 11145 this.resetField(field, resetValue); 11146 } 11147 11148 this.$invalidFields = $([]); 11149 this.$submitButton = null; 11150 11151 // Enable submit buttons 11152 this.disableSubmitButtons(false); 11153 11154 return this; 11155 }, 11156 11157 /** 11158 * Revalidate given field 11159 * It's used when you need to revalidate the field which its value is updated by other plugin 11160 * 11161 * @param {String|jQuery} field The field name of field element 11162 * @returns {BootstrapValidator} 11163 */ 11164 revalidateField: function(field) { 11165 this.updateStatus(field, this.STATUS_NOT_VALIDATED) 11166 .validateField(field); 11167 11168 return this; 11169 }, 11170 11171 /** 11172 * Enable/Disable all validators to given field 11173 * 11174 * @param {String} field The field name 11175 * @param {Boolean} enabled Enable/Disable field validators 11176 * @param {String} [validatorName] The validator name. If null, all validators will be enabled/disabled 11177 * @returns {BootstrapValidator} 11178 */ 11179 enableFieldValidators: function(field, enabled, validatorName) { 11180 var validators = this.options.fields[field].validators; 11181 11182 // Enable/disable particular validator 11183 if (validatorName && 11184 validators && 11185 validators[validatorName] && 11186 validators[validatorName].enabled !== enabled) 11187 { 11188 this.options.fields[field].validators[validatorName].enabled = enabled; 11189 this.updateStatus(field, this.STATUS_NOT_VALIDATED, validatorName); 11190 } 11191 // Enable/disable all validators 11192 else if (!validatorName && this.options.fields[field].enabled !== enabled) { 11193 this.options.fields[field].enabled = enabled; 11194 for (var v in validators) { 11195 this.enableFieldValidators(field, enabled, v); 11196 } 11197 } 11198 11199 return this; 11200 }, 11201 11202 /** 11203 * Some validators have option which its value is dynamic. 11204 * For example, the zipCode validator has the country option which might be changed dynamically by a select element. 11205 * 11206 * @param {jQuery|String} field The field name or element 11207 * @param {String|Function} option The option which can be determined by: 11208 * - a string 11209 * - name of field which defines the value 11210 * - name of function which returns the value 11211 * - a function returns the value 11212 * 11213 * The callback function has the format of 11214 * callback: function(value, validator, $field) { 11215 * // value is the value of field 11216 * // validator is the BootstrapValidator instance 11217 * // $field is the field element 11218 * } 11219 * 11220 * @returns {String} 11221 */ 11222 getDynamicOption: function(field, option) { 11223 var $field = ('string' === typeof field) ? this.getFieldElements(field) : field, 11224 value = $field.val(); 11225 11226 // Option can be determined by 11227 // ... a function 11228 if ('function' === typeof option) { 11229 return $.fn.bootstrapValidator.helpers.call(option, [value, this, $field]); 11230 } 11231 // ... value of other field 11232 else if ('string' === typeof option) { 11233 var $f = this.getFieldElements(option); 11234 if ($f.length) { 11235 return $f.val(); 11236 } 11237 // ... return value of callback 11238 else { 11239 return $.fn.bootstrapValidator.helpers.call(option, [value, this, $field]) || option; 11240 } 11241 } 11242 11243 return null; 11244 }, 11245 11246 /** 11247 * Destroy the plugin 11248 * It will remove all error messages, feedback icons and turn off the events 11249 */ 11250 destroy: function() { 11251 var field, fields, $field, validator, $icon, group; 11252 for (field in this.options.fields) { 11253 fields = this.getFieldElements(field); 11254 group = this.options.fields[field].group || this.options.group; 11255 for (var i = 0; i < fields.length; i++) { 11256 $field = fields.eq(i); 11257 $field 11258 // Remove all error messages 11259 .data('bv.messages') 11260 .find('.help-block[data-bv-validator][data-bv-for="' + field + '"]').remove().end() 11261 .end() 11262 .removeData('bv.messages') 11263 // Remove feedback classes 11264 .parents(group) 11265 .removeClass('has-feedback has-error has-success') 11266 .end() 11267 // Turn off events 11268 .off('.bv') 11269 .removeAttr('data-bv-field'); 11270 11271 // Remove feedback icons, tooltip/popover container 11272 $icon = $field.data('bv.icon'); 11273 if ($icon) { 11274 var container = ('function' === typeof (this.options.fields[field].container || this.options.container)) ? (this.options.fields[field].container || this.options.container).call(this, $field, this) : (this.options.fields[field].container || this.options.container); 11275 switch (container) { 11276 case 'tooltip': 11277 $icon.tooltip('destroy').remove(); 11278 break; 11279 case 'popover': 11280 $icon.popover('destroy').remove(); 11281 break; 11282 default: 11283 $icon.remove(); 11284 break; 11285 } 11286 } 11287 $field.removeData('bv.icon'); 11288 11289 for (validator in this.options.fields[field].validators) { 11290 if ($field.data('bv.dfs.' + validator)) { 11291 $field.data('bv.dfs.' + validator).reject(); 11292 } 11293 $field.removeData('bv.result.' + validator) 11294 .removeData('bv.response.' + validator) 11295 .removeData('bv.dfs.' + validator); 11296 11297 // Destroy the validator 11298 if ('function' === typeof $.fn.bootstrapValidator.validators[validator].destroy) { 11299 $.fn.bootstrapValidator.validators[validator].destroy(this, $field, this.options.fields[field].validators[validator]); 11300 } 11301 } 11302 } 11303 } 11304 11305 this.disableSubmitButtons(false); // Enable submit buttons 11306 this.$hiddenButton.remove(); // Remove the hidden button 11307 11308 this.$form 11309 .removeClass(this.options.elementClass) 11310 .off('.bv') 11311 .removeData('bootstrapValidator') 11312 // Remove generated hidden elements 11313 .find('[data-bv-submit-hidden]').remove().end() 11314 .find('[type="submit"]').off('click.bv'); 11315 } 11316 }; 11317 11318 // Plugin definition 11319 $.fn.bootstrapValidator = function(option) { 11320 var params = arguments; 11321 return this.each(function() { 11322 var $this = $(this), 11323 data = $this.data('bootstrapValidator'), 11324 options = 'object' === typeof option && option; 11325 if (!data) { 11326 data = new BootstrapValidator(this, options); 11327 $this.data('bootstrapValidator', data); 11328 } 11329 11330 // Allow to call plugin method 11331 if ('string' === typeof option) { 11332 data[option].apply(data, Array.prototype.slice.call(params, 1)); 11333 } 11334 }); 11335 }; 11336 11337 // The default options 11338 // Sorted in alphabetical order 11339 $.fn.bootstrapValidator.DEFAULT_OPTIONS = { 11340 // The first invalid field will be focused automatically 11341 autoFocus: true, 11342 11343 //The error messages container. It can be: 11344 // - 'tooltip' if you want to use Bootstrap tooltip to show error messages 11345 // - 'popover' if you want to use Bootstrap popover to show error messages
11346 // - a CSS selector indicating the container 11347 // In the first two cases, since the tooltip/popover should be small enough, the plugin only shows only one error message 11348 // You also can define the message container for particular field 11349 container: null, 11350 11351 // The form CSS class 11352 elementClass: 'bv-form', 11353 11354 // Use custom event name to avoid window.onerror being invoked by jQuery 11355 // See https://github.com/nghuuphuoc/bootstrapvalidator/issues/630 11356 events: { 11357 formInit: 'init.form.bv', 11358 formError: 'error.form.bv', 11359 formSuccess: 'success.form.bv', 11360 fieldAdded: 'added.field.bv', 11361 fieldRemoved: 'removed.field.bv', 11362 fieldInit: 'init.field.bv', 11363 fieldError: 'error.field.bv', 11364 fieldSuccess: 'success.field.bv', 11365 fieldStatus: 'status.field.bv', 11366 validatorError: 'error.validator.bv', 11367 validatorSuccess: 'success.validator.bv' 11368 }, 11369 11370 // Indicate fields which won't be validated 11371 // By default, the plugin will not validate the following kind of fields: 11372 // - disabled 11373 // - hidden 11374 // - invisible 11375 // 11376 // The setting consists of jQuery filters. Accept 3 formats: 11377 // - A string. Use a comma to separate filter 11378 // - An array. Each element is a filter 11379 // - An array. Each element can be a callback function 11380 // function($field, validator) { 11381 // $field is jQuery object representing the field element 11382 // validator is the BootstrapValidator instance 11383 // return true or false; 11384 // } 11385 // 11386 // The 3 following settings are equivalent: 11387 // 11388 // 1) ':disabled, :hidden, :not(:visible)' 11389 // 2) [':disabled', ':hidden', ':not(:visible)'] 11390 // 3) [':disabled', ':hidden', function($field) { 11391 // return !$field.is(':visible'); 11392 // }] 11393 excluded: [':disabled', ':hidden', ':not(:visible)'], 11394 11395 // Shows ok/error/loading icons based on the field validity. 11396 // This feature requires Bootstrap v3.1.0 or later (http://getbootstrap.com/css/#forms-control-validation). 11397 // Since Bootstrap doesn't provide any methods to know its version, this option cannot be on/off automatically. 11398 // In other word, to use this feature you have to upgrade your Bootstrap to v3.1.0 or later. 11399 // 11400 // Examples: 11401 // - Use Glyphicons icons: 11402 // feedbackIcons: { 11403 // valid: 'glyphicon glyphicon-ok', 11404 // invalid: 'glyphicon glyphicon-remove', 11405 // validating: 'glyphicon glyphicon-refresh' 11406 // } 11407 // - Use FontAwesome icons: 11408 // feedbackIcons: { 11409 // valid: 'fa fa-check', 11410 // invalid: 'fa fa-times', 11411 // validating: 'fa fa-refresh' 11412 // } 11413 feedbackIcons: { 11414 valid: null, 11415 invalid: null, 11416 validating: null 11417 }, 11418 11419 // Map the field name with validator rules 11420 fields: null, 11421 11422 // The CSS selector for indicating the element consists the field 11423 // By default, each field is placed inside the <div class="form-group"></div> 11424 // You should adjust this option if your form group consists of many fields which not all of them need to be validated 11425 group: '.form-group', 11426 11427 // Live validating option 11428 // Can be one of 3 values: 11429 // - enabled: The plugin validates fields as soon as they are changed 11430 // - disabled: Disable the live validating. The error messages are only shown after the form is submitted 11431 // - submitted: The live validating is enabled after the form is submitted 11432 live: 'enabled', 11433 11434 // Default invalid message 11435 message: 'This value is not valid', 11436 11437 // The submit buttons selector 11438 // These buttons will be disabled to prevent the valid form from multiple submissions 11439 submitButtons: '[type="submit"]', 11440 11441 // The field will not be live validated if its length is less than this number of characters 11442 threshold: null, 11443 11444 // Whether to be verbose when validating a field or not. 11445 // Possible values: 11446 // - true: when a field has multiple validators, all of them will be checked, and respectively - if errors occur in 11447 // multiple validators, all of them will be displayed to the user 11448 // - false: when a field has multiple validators, validation for this field will be terminated upon the first encountered error. 11449 // Thus, only the very first error message related to this field will be displayed to the user
vendor: 4,102 bytes, lines 11450-11586
11450 verbose: true 11451 }; 11452 11453 // Available validators 11454 $.fn.bootstrapValidator.validators = {}; 11455 11456 // i18n 11457 $.fn.bootstrapValidator.i18n = {}; 11458 11459 $.fn.bootstrapValidator.Constructor = BootstrapValidator; 11460 11461 // Helper methods, which can be used in validator class 11462 $.fn.bootstrapValidator.helpers = { 11463 /** 11464 * Execute a callback function 11465 * 11466 * @param {String|Function} functionName Can be 11467 * - name of global function 11468 * - name of namespace function (such as A.B.C) 11469 * - a function 11470 * @param {Array} args The callback arguments 11471 */ 11472 call: function(functionName, args) { 11473 if ('function' === typeof functionName) { 11474 return functionName.apply(this, args); 11475 } else if ('string' === typeof functionName) { 11476 if ('()' === functionName.substring(functionName.length - 2)) { 11477 functionName = functionName.substring(0, functionName.length - 2); 11478 } 11479 var ns = functionName.split('.'), 11480 func = ns.pop(), 11481 context = window; 11482 for (var i = 0; i < ns.length; i++) { 11483 context = context[ns[i]]; 11484 } 11485 11486 return (typeof context[func] === 'undefined') ? null : context[func].apply(this, args); 11487 } 11488 }, 11489 11490 /** 11491 * Format a string 11492 * It's used to format the error message 11493 * format('The field must between %s and %s', [10, 20]) = 'The field must between 10 and 20' 11494 * 11495 * @param {String} message 11496 * @param {Array} parameters 11497 * @returns {String} 11498 */ 11499 format: function(message, parameters) { 11500 if (!$.isArray(parameters)) { 11501 parameters = [parameters]; 11502 } 11503 11504 for (var i in parameters) { 11505 message = message.replace('%s', parameters[i]); 11506 } 11507 11508 return message; 11509 }, 11510 11511 /** 11512 * Validate a date 11513 * 11514 * @param {Number} year The full year in 4 digits 11515 * @param {Number} month The month number 11516 * @param {Number} day The day number 11517 * @param {Boolean} [notInFuture] If true, the date must not be in the future 11518 * @returns {Boolean} 11519 */ 11520 date: function(year, month, day, notInFuture) { 11521 if (isNaN(year) || isNaN(month) || isNaN(day)) { 11522 return false; 11523 } 11524 if (day.length > 2 || month.length > 2 || year.length > 4) { 11525 return false; 11526 } 11527 11528 day = parseInt(day, 10); 11529 month = parseInt(month, 10); 11530 year = parseInt(year, 10); 11531 11532 if (year < 1000 || year > 9999 || month <= 0 || month > 12) { 11533 return false; 11534 } 11535 var numDays = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; 11536 // Update the number of days in Feb of leap year 11537 if (year % 400 === 0 || (year % 100 !== 0 && year % 4 === 0)) { 11538 numDays[1] = 29; 11539 } 11540 11541 // Check the day 11542 if (day <= 0 || day > numDays[month - 1]) { 11543 return false; 11544 } 11545 11546 if (notInFuture === true) { 11547 var currentDate = new Date(), 11548 currentYear = currentDate.getFullYear(), 11549 currentMonth = currentDate.getMonth(), 11550 currentDay = currentDate.getDate(); 11551 return (year < currentYear || 11552 (year === currentYear && month - 1 < currentMonth) || 11553 (year === currentYear && month - 1 === currentMonth && day < currentDay)); 11554 } 11555 11556 return true; 11557 }, 11558 11559 /** 11560 * Implement Luhn validation algorithm 11561 * Credit to https://gist.github.com/ShirtlessKirk/2134376 11562 * 11563 * @see http://en.wikipedia.org/wiki/Luhn 11564 * @param {String} value 11565 * @returns {Boolean} 11566 */ 11567 luhn: function(value) { 11568 var length = value.length, 11569 mul = 0, 11570 prodArr = [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9], [0, 2, 4, 6, 8, 1, 3, 5, 7, 9]], 11571 sum = 0; 11572 11573 while (length--) { 11574 sum += prodArr[mul][parseInt(value.charAt(length), 10)]; 11575 mul ^= 1; 11576 } 11577 11578 return (sum % 10 === 0 && sum > 0); 11579 }, 11580 11581 /** 11582 * Implement modulus 11, 10 (ISO 7064) algorithm 11583 * 11584 * @param {String} value 11585 * @returns {Boolean} 11586 */
11587 mod11And10: function(value) { 11588 var check = 5, 11589 length = value.length; 11590 for (var i = 0; i < length; i++) { 11591 check = (((check || 10) * 2) % 11 + parseInt(value.charAt(i), 10)) % 10; 11592 } 11593 return (check === 1); 11594 }, 11595 11596 /** 11597 * Implements Mod 37, 36 (ISO 7064) algorithm 11598 * Usages: 11599 * mod37And36('A12425GABC1234002M') 11600 * mod37And36('002006673085', '0123456789') 11601 * 11602 * @param {String} value 11603 * @param {String} [alphabet] 11604 * @returns {Boolean} 11605 */ 11606 mod37And36: function(value, alphabet) { 11607 alphabet = alphabet || '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'; 11608 var modulus = alphabet.length, 11609 length = value.length, 11610 check = Math.floor(modulus / 2); 11611 for (var i = 0; i < length; i++) { 11612 check = (((check || modulus) * 2) % (modulus + 1) + alphabet.indexOf(value.charAt(i))) % modulus; 11613 } 11614 return (check === 1); 11615 } 11616 }; 11617 11618 // init: 11619 $(document).on('bv:init', function(e){ 11620 var $formInstances = $('[data-bv]'); 11621 $formInstances.each(function (ind, obj) { 11622 var $bvForm = $(obj).bootstrapValidator(); 11623 }); 11624 }); 11625 11626 // if we need to validate the form via ajax: 11627 $(document).on('click', 'form [data-bv-submit]', function(e) { 11628 $(e.currentTarget).closest('form').trigger('submit.bv'); 11629 }); 11630 11631 // Debug form: 11632 /* $(document).on('error.field.bv',function(e){ 11633 console.log('Error Field'); 11634 console.debug(e); 11635 }); 11636 $(document).on('init.field.bv',function(e){ 11637 console.log('init Field'); 11638 console.debug(e); 11639 }); 11640 $(document).on('success.field.bv',function(e){ 11641 console.log('Success Field'); 11642 console.debug(e); 11643 }); 11644 $(document).on('status.field.bv',function(e){ 11645 console.log('Status Field'); 11646 console.debug(e); 11647 }); 11648 $(document).on('error.validator.bv',function(e, data){ 11649 console.log('Error Validator ' + data.validator); 11650 console.debug(e); 11651 }); 11652 $(document).on('init.form.bv',function(e){ 11653 console.log('Form Init'); 11654 console.debug(e); 11655 }); 11656 $(document).on('error.form.bv',function(e){ 11657 console.log('Form Error'); 11658 console.debug(e); 11659 }); 11660 $(document).on('success.form.bv',function(e){ 11661 console.log('Form Success'); 11662 console.debug(e); 11663 }); 11664 $(document).on('added.field.bv',function(e){ 11665 console.log('Added Field'); 11666 console.debug(e); 11667 }); 11668 $(document).on('removed.field.bv',function(e){ 11669 console.log('Removed Field'); 11670 console.debug(e); 11671 });*/ 11672 11673 11674 11675 }(window.jQuery)); 11676 11677 11678/***/ }), 11679 11680/***/ 333: 11681/***/ (function(module, exports) { 11682 11683 /** 11684 * Smart Replace 11685 * 11686 * Adds some variables to the global scope and make them available for replacement. 11687 * 11688 * usage: 11689 * var mreplacements = {}; 11690 * mreplacements.test = 'a test'; 11691 * mstring = "this is {{test}}"; 11692 * res = $.smartReplace.replace(mstring, mreplacements); // this is a test 11693 * 11694 * usage 2: 11695 * add data-autoreplace="objReference" to your html element. 11696 * and the plugin will use the obj in $.smartReplace.objReference to replace the contents of the element. 11697 * 11698 **/ 11699 11700 11701 $(function (){ 11702 $.smartReplace = { 11703 vars: {}, 11704 replace: function (pattern, replacements) { 11705 // function argument overrides global variable: 11706 var reps = $.extend({}, $.smartReplace.vars, replacements); 11707 11708 if (pattern !== undefined && reps !== undefined) { 11709 pattern = pattern.replace(/<%(.[a-zA-Z0-9_\-\[\]]{1,35})%>/g, function (index, varName) { 11710 11711 if (reps[varName] !== undefined) { 11712 return reps[varName]; 11713 } else { 11714 return '{{' + varName + '}}'; 11715 } 11716 11717 }); 11718 } 11719 return pattern; 11720 }, 11721 bulkReplace: function (string, replacements){ 11722 if (string !== undefined && replacements !== undefined){ 11723 for (var rep in replacements){ 11724 11725 if (replacements[rep].regex === true && typeof(replacements[rep].replace) === 'function'){ 11726 var r = new RegExp(replacements[rep].find, "g"); 11727 string = string.replace(r, replacements[rep].replace); 11728 }else {
11729 string = string.replace(replacements[rep].find, replacements[rep].replace); 11730 } 11731 } 11732 return string; 11733 } 11734 }, 11735 edmundsReplacements: [ 11736 {find: 'AWD', replace: 'All Wheel Drive'}, 11737 {find: '4WD', replace: 'Four-wheel Drive'}, 11738 {find: 'SUV', replace: 'Sport Utility Vehicle'}, 11739 {find: 'WB', replace: 'Wheel Base'}, 11740 {find: 'HR', replace: 'High Roof'}, 11741 {find: 'w/', replace: 'With '}, 11742 {find: 'Ext Van', replace: 'Extended Van'}, 11743 {find: 'Pkg', replace: 'Package'}, 11744 {find: 'CVT', replace: 'Continuously Variable Transmission'}, 11745 {find: 'GTS', replace: 'Gran Turismo'}, 11746 {find: '([0-9]{2,3}) ft. SB', replace: function(index, match){ 11747 return match + ' feet Short Box'; 11748 }, regex: true}, 11749 {find: '([0-9]{1})dr', replace: function(index, match){ 11750 return match + ' Doors'; 11751 }, regex: true}, 11752 {find: '([0-9.]{1,3})L', replace: function(index, match){ 11753 return match + ' Liters'; 11754 }, regex: true}, 11755 {find: '([0-9]{1})M', replace: function(index, match){ 11756 return match + '-speed manual transmission'; 11757 }, regex: true}, 11758 {find: '([0-9]{1})A', replace: function(index, match){ 11759 return match + '-speed automatic transmission'; 11760 }, regex: true}, 11761 {find: '([0-9]{1,2})cyl',replace: function(index, match){ 11762 return match + ' Cylinders'; 11763 }, regex: true}, 11764 {find: 'Turbodiesel', replace: 'Turbo Diesel'} 11765 ] 11766 }; 11767 11768 $(document).on('change', 'input, select', function(e){ 11769 var id = $(e.target).prop('name'); 11770 if (id !== undefined){ 11771 $.smartReplace.vars[id]=$(e.target).val(); 11772 }else{ 11773 console.warn('Not a valid input name found!'+ e.currentTarget.toString()); 11774 } 11775 }); 11776 11777 // update action before send forms: 11778 $(document).on('submit', 'form', function(e){ 11779 var action = $.smartReplace.replace( $(e.target).prop('action'), {} ); 11780 $(e.target).prop('action', action); 11781 }); 11782 11783 $('[data-smartreplace]').each(function(ind, obj){ 11784 var oldText = $(obj).text(); 11785 var replacements = $(obj).data('smartreplace'); 11786 var newText = $.smartReplace.bulkReplace(oldText, $.smartReplace[replacements]); 11787 $(obj).text(newText); 11788 }); 11789 11790 }); 11791 11792 11793/***/ }), 11794 11795/***/ 334: 11796/***/ (function(module, exports) { 11797 11798 (function($) { 11799 $.fn.bootstrapValidator.i18n.notEmpty = $.extend( 11800 $.fn.bootstrapValidator.i18n.notEmpty || {}, 11801 {'default': 'Please enter a value'} 11802 ); 11803 11804 $.fn.bootstrapValidator.validators.notEmpty = { 11805 enableByHtml5: function($field) { 11806 var required = $field.attr('required') + ''; 11807 return (required === 'required' || required === 'true'); 11808 }, 11809 11810 /** 11811 * Check if input value is empty or not 11812 * 11813 * @param {BootstrapValidator} validator The validator plugin instance 11814 * @param {jQuery} $field Field element 11815 * @param {Object} options 11816 * @returns {Boolean} 11817 */ 11818 validate: function(validator, $field, options) { 11819 var type = $field.attr('type'); 11820 11821 if (type === 'radio' || type === 'checkbox') { 11822 return validator 11823 .getFieldElements($field.attr('data-bv-field')) 11824 .filter(':checked') 11825 .length > 0; 11826 } 11827 11828 if ( 11829 type === 'number' && 11830 $field.get(0).validity && 11831 $field.get(0).validity.badInput === true 11832 ) { 11833 return true; 11834 } 11835 11836 return ($.trim($field.val()) !== ''); 11837 } 11838 }; 11839 }(window.jQuery)); 11840 11841 11842/***/ }), 11843 11844/***/ 335: 11845/***/ (function(module, exports) { 11846 11847 /** 11848 * Enchained Selects 11849 * 11850 * Enable a select once the user selects an option in a parent select. 11851 * 11852 * usage: 11853 * <select data-enchained-select="#next-select-id">...</select> 11854 **/ 11855 11856 $(function(){ 11857 11858 $(document).on('change','*[data-enchained-select]', function(e){ 11859 $(e.target) 11860 .closest('form').find('.control-fx').removeClass("current-selection"); 11861 // add the new value to smartReplace vars object: 11862 $.smartReplace.vars[ 11863 $(e.target).data('smart-replace-field-name') || $(e.target).attr('id') 11864 ] = $(e.target).val(); 11865 11866 //enable the next select and trigger the changed event: 11867 var nextSelect = $(e.target).data('enchained-select'); 11868 // $(nextSelect).prop('disabled', false); 11869 $(nextSelect).trigger('parent-input:changed', {parent: e.target}); 11870 $(nextSelect).closest('.control-fx').addClass("current-selection"); 11871 }); 11872 11873 $(document).on('change','form select', function(e) { 11874 $(e.target).closest('.control-fx').removeClass("current-selection"); 11875 }); 11876 11877 }); 11878 11879 11880/***/ }), 11881 11882/***/ 336:
11883/***/ (function(module, exports) { 11884 11885 $(function(){ 11886 11887 $(document).on('success.field.bv','[data-next-field-group]',function(e, data){ 11888 11889 // if there is a next field group set enable it by removing its disabled class: 11890 if ( $(e.target).data('next-field-group') !== '') { 11891 $('.form-group' + $(e.target).data('next-field-group') + ' .control-fx').removeClass('disabled'); 11892 } 11893 11894 // enable of disable the field according to the field validation result: 11895 if ( data.bv.isValid() ){ 11896 data.bv.$form.find('.form-submit .control-fx').removeClass('disabled'); 11897 }else{ 11898 data.bv.$form.find('.form-submit .control-fx').addClass('disabled'); 11899 } 11900 11901 }); 11902 11903 $(document).on('error.field.bv','[data-next-field-group]',function(e, data){ 11904 11905 // if there is an error don't release the next field, add it the class disabled: 11906 if ( $(e.target).data('next-field-group') !== '') { 11907 $('.form-group' + $(e.target).data('next-field-group') + ' .control-fx').addClass('disabled'); 11908 } 11909 // enable or disable the field according to the field validation result: 11910 if ( data.bv.isValid() ){ 11911 data.bv.$form.find('.form-submit .control-fx').removeClass('disabled'); 11912 }else{ 11913 data.bv.$form.find('.form-submit .control-fx').addClass('disabled'); 11914 } 11915 11916 }); 11917 11918 }); 11919 11920 11921/***/ }), 11922 11923/***/ 337: 11924/***/ (function(module, exports) { 11925 11926 /** 11927 * Select Auto JSON 11928 * 11929 * Fills automatically a select from an external JSON file. 11930 * 11931 * usage: 11932 * <select data-select-auto-json="{options}">...</select> 11933 * 11934 * { 11935 * "placeholder":"Select a Make...", 11936 * "source":"http://api.edmunds.com/api/vehicle/v2/makes?fmt=json&api_key=xtgymqcwqsuyk3ehjkdy44uf&status=used", 11937 * "parseObject":"makes", 11938 * "labelField":"name", 11939 * "valueField":"niceName" 11940 * } 11941 * 11942 * placeholder and source are selfexplanatory. 11943 * parseObject is the object in the response that you want to parse. (usually data) 11944 * labelField is the field in the object you want to be used as field in the option appended to the select. 11945 * valueField is the field in the object you want to be used as value in the option appended to the select. 11946 **/ 11947 11948 $(function(){ 11949 11950 var jsonResponseCache = {}; 11951 var jsonRequestCallbacks = {}; 11952 11953 $(document).on('enable parent-input:changed', '*[data-select-auto-json]', function(e, data){ 11954 var defaults = { 11955 valueField: 'value', 11956 labelField: 'field', 11957 childValueField: 'value', 11958 childLabelField: 'field', 11959 parseObject: 'data', 11960 sort: false, // string || number || false, in conjunction with sortBy 11961 ignoreEmptyValues: true, 11962 }; 11963 11964 var options = $.extend({}, defaults, $(e.target).data('select-auto-json')); 11965 $(e.target).trigger('disable'); 11966 11967 // only display the loading status of the select when the parent element has a valid value to make the json call: 11968 if (e.type == 'parent-input:changed'){ 11969 if ( $(e.target).closest('form[data-bv]').data('bootstrapValidator').isValidField($(data.parent)) ){ 11970 $(e.target).closest('.control-fx').addClass('loading'); 11971 } 11972 } 11973 11974 11975 function getJSONCached(url, jsonCallback) { 11976 // if there is a cached response for the requested url 11977 if (jsonResponseCache[url] !== undefined) { 11978 // call the callback directly with the response 11979 jsonCallback.call(this, jsonResponseCache[url]); 11980 // if there is no cached response for the requested url 11981 } else { 11982 // if there are no callbacks waiting to be handled for this url (ie. if 11983 // the request is new) 11984 if (jsonRequestCallbacks[url] === undefined) { 11985 // create an array of callbacks 11986 jsonRequestCallbacks[url] = []; 11987 // perform the request 11988 $.getJSON(url, function(json) { 11989 // get the array of callbacks for this url 11990 var jsonCallbacks = jsonRequestCallbacks[url]; 11991 var i; 11992 // cache the response for future use 11993 jsonResponseCache[url] = json; 11994 // call each of the callbacks in the stack for the URL 11995 for (i = 0; i < jsonCallbacks.length; i++) { 11996 jsonCallbacks[i].call(this, json); 11997 } 11998 // delete request callbacks 11999 jsonRequestCallbacks[url] = undefined; 12000 }); 12001 } 12002 // push the callback onto the stack waiting to be executed when the aja
12002x 12003 // call has been completed 12004 jsonRequestCallbacks[url].push(jsonCallback); 12005 } 12006 } 12007 12008 getJSONCached($.smartReplace.replace(options.source, {}), function(json){ 12009 $(e.target).empty(); 12010 $(e.target).append( $('<option></option>').text(options.placeholder).val('')); 12011 var sortBy = options.sortBy || options.labelField; 12012 if (options.sort == 'number'){ 12013 json[options.parseObject].sort(function(a, b){ 12014 return b[sortBy] - a[options.labelField]; 12015 }); 12016 }else if(options.sort == 'string'){ 12017 json[options.parseObject].sort(function(a, b){ 12018 return a[sortBy].localeCompare(b[options.labelField]); 12019 }); 12020 } 12021 12022 $.each(json[options.parseObject], function(key, dataObj){ 12023 var value = dataObj[options.valueField]; 12024 var label = dataObj[options.labelField]; 12025 if ( options.labelReplace !== undefined ){ 12026 var reps = $.smartReplace[options.labelReplace]; 12027 label = $.smartReplace.bulkReplace(label, reps); 12028 } 12029 if (typeof(value) == 'object' ){ 12030 var $optGroup = $('<optgroup>',{label: label}); 12031 for (var i in value){ 12032 var childValue = value[i][options.childValueField]; 12033 var childLabel = value[i][options.childLabelField]; 12034 $optGroup.append($('<option></option>').text(childLabel).val(childValue)); 12035 } 12036 $(e.target).append($optGroup); 12037 12038 }else if(options.ignoreEmptyValues && value === ''){ 12039 }else{ 12040 $(e.target).append($('<option></option>').text(label).val(value)); 12041 } 12042 }); 12043 $(e.target).trigger('select:set-initial-value'); 12044 $(e.target).prop('disabled', false); 12045 $(e.target).closest('.control-fx').removeClass("disabled loading"); 12046 12047 }); 12048 }); 12049 12050 $(document).on('select:set-initial-value', 'select', function(e){ 12051 12052 // try to determine the initial value based on the current options: 12053 if ($(e.target).data('single-option-autoselected')){ 12054 var $emptyOptions = $(e.target).find('[value=""]'); 12055 var $notEmptyOptions = $(e.target).find('option').not($emptyOptions); 12056 if ( $notEmptyOptions.length === 1 ){ 12057 $(e.target).val($notEmptyOptions.get(0).value) 12058 .trigger('change'); 12059 $emptyOptions.remove(); 12060 } 12061 } 12062 12063 // if we don't have a value yet try to load the value from the initial value provided from backend: 12064 var initialValue = $(e.target).data('initial-value') || ''; 12065 12066 if ( 12067 $(e.target).val() === '' && 12068 initialValue !== '' && 12069 $(e.target).find('option[value="' + initialValue + '"]').length === 1 12070 ){ 12071 // If there is an option with the initial value, selected and trigger 12072 // change: 12073 $(e.target).val(initialValue) 12074 .trigger('change'); 12075 $(e.target).find('option[value=""]').attr('disabled', 'disabled'); 12076 } 12077 }); 12078 12079 $(document).on('disable', '*[data-select-auto-json]', function(e){ 12080 var options = $(e.target).data('select-auto-json'); 12081 12082 $(e.target).empty(); 12083 $(e.target).append( $('<option></option>').text(options.placeholder).val('')); 12084 $(e.target).prop('disabled', true); 12085 $(e.target).closest('.control-fx').addClass("disabled"); 12086 12087 $(e.target).closest('form[data-bv]').bootstrapValidator('updateStatus', $(e.target), 'NOT_VALIDATED'); 12088 var nextSelect = $(e.target).data('enchained-select'); 12089 12090 if (nextSelect) { 12091 $(nextSelect).trigger('disable'); 12092 } 12093 }); 12094 12095 }); 12096 12097 12098/***/ }), 12099 12100/***/ 338: 12101/***/ (function(module, exports) { 12102 12103 $(function(){ 12104 12105 // display only one error at a time... 12106 var $document = $(document); 12107 $document.on( 12108 'error.validator.bv', 12109 'form.step1-form *', 12110 function (e, data) { 12111 data 12112 .element 12113 .closest('form') 12114 .find('.has-error small.help-block') 12115 .hide() 12116 .eq(0) 12117 .show(); 12118 } 12119 ); 12120 12121 // enable/disable old flow based on year selection... 12122 $document.on( 12123 'change', 12124 '.step1-form .car-year', 12125 function(e) { 12126 $(e.currentTarget).closest('form') 12127 .find('.car-is-old').val( 12128 ($(e.currentTarget).val() < 0) ? 1 : 0 12129 ); 12130 } 12131 ); 12132 12133 }); 12134 12135 12136/***/ }), 12137 12138/***/ 339:
12139/***/ (function(module, exports) { 12140 12141 /** 12142 * Set initial value of select elements from data structured in cookie 12143 * 12144 * 12145 12146 Sample usage: 12147 12148 1. Create a cookie structured whereby the value of the cookie contains field/ 12149 value pairs separated by pipe characters as follows: 12150 wkdaCF_step1 = "manufacturer=060|maintype=A4|builtDate=2013" 12151 12152 2. Add the data attribute to the select element identifying the cookie and the 12153 variable name within the cookie as follows: 12154 <select 12155 name="selectname" 12156 data-initial-value-cookie="wkdaCF_step1.maintype" 12157 > 12158 */ 12159 $(function(){ 12160 12161 var $cookieDataElementCollection = $('[data-initial-value-cookie]'); 12162 12163 // populate conversion form with any previous search data 12164 function parseStr( 12165 delimitedStr, 12166 tupleDelimiterOperator, 12167 variableAssignmentOperator 12168 ) { 12169 var parsedObject = {}; 12170 var tupleStringsArr; 12171 var i; 12172 var tupleArr; 12173 var tupleName; 12174 var tupleVal; 12175 12176 // default for parsing cookies 12177 tupleDelimiterOperator = tupleDelimiterOperator || ';'; 12178 variableAssignmentOperator = variableAssignmentOperator || '='; 12179 tupleStringsArr = delimitedStr.split(tupleDelimiterOperator); 12180 12181 for (i = 0; i < tupleStringsArr.length; i++) { 12182 tupleArr = tupleStringsArr[i].split(variableAssignmentOperator); 12183 if (tupleArr.length === 2) { 12184 // strip leading and trailing white space from variable names 12185 tupleName = tupleArr[0].replace(/(^\s+|\s$)/g, ''); 12186 tupleVal = tupleArr[1].replace(/(^\s+|\s$)/g, ''); 12187 parsedObject[tupleName] = tupleVal; 12188 } 12189 } 12190 12191 return parsedObject; 12192 } 12193 12194 (function setInitialValues() { 12195 var cookies = parseStr(document.cookie || ''); 12196 12197 $cookieDataElementCollection.each(function() { 12198 var $cookieDataElement = $(this); 12199 var cookieInitialValueVarName = 12200 $cookieDataElement.data('initial-value-cookie'); 12201 var cookieInitialValueVarNameArr = cookieInitialValueVarName.split('.'); 12202 var cookieName = cookieInitialValueVarNameArr[0]; 12203 var cookieVarName = cookieInitialValueVarNameArr[1]; 12204 var formCookieStr = cookies[cookieName]; 12205 var formCookie; 12206 12207 if ($cookieDataElement.val()) { 12208 $cookieDataElement.trigger('change'); 12209 } 12210 12211 if ($cookieDataElement.is(":focus")) { 12212 return false; 12213 } 12214 12215 if (formCookieStr !== undefined) { 12216 formCookie = 12217 parseStr(decodeURIComponent(formCookieStr.replace(/\+/g, '%20')), '|'); 12218 $cookieDataElement 12219 .data( 12220 'initial-value', 12221 formCookie[cookieVarName] 12222 ) 12223 .trigger('select:set-initial-value'); 12224 } 12225 }); 12226 })(); 12227 12228 }); 12229 12230 12231/***/ }) 12232 12233/******/ });
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.