1 2 3 4function cp_forms_init($form, form_templates, form_options) { 5 6 initFormStyles({$wrapper: $form}); 7 8 $form.data('form_templates', form_templates); 9 10 $form.find('.removeBlockBtn').click(cp_forms_remove_block_click); 11 $form.find('[id^="addFieldsBtn"]').click(cp_forms_add_field_click); 12 13 $form.submit(cp_forms_submit); 14 15 if(form_options.warnBeforeUnload) 16 { 17 cp_forms_init_warn_before_unload($form); 18 } 19 20 add_client_referrer_data_to_form($form); 21 22 if($form.find('.btn.cpFormSubmit').length > 0) 23 { 24 var $cpFormSubmit = $form.find('.btn.cpFormSubmit').click(function(){$form.submit();}); 25 $form.data("cpFormsSubmitButtons", $cpFormSubmit); 26 } 27} 28 29function add_client_referrer_data_to_form($form) { 30 31 if (cp.config.recruitment.client_referrer_collection_enabled && !cp.in_cp && $form.find('input[name=client_referrer]').length > 0) 32 { 33 var ccd_client_referrer = ccd_client_referrer_cookie(); 34 35 if(ccd_client_referrer != null) 36 { 37 $form.find('input[name=client_referrer]').val(ccd_client_referrer); 38 } 39 } 40} 41 42function cp_forms_init_warn_before_unload($form) { 43 $form.change(cp_forms_on_change); 44 var formHash = $form.serialize().toHash(); 45 $form.data("initial_hash", formHash); 46} 47 48function cp_forms_on_change($form) { 49 cp_forms_update_before_unload($(this).closest('form')); 50} 51 52function cp_forms_update_before_unload($form, turnOff) { 53 if(turnOff === true || $form.serialize().toHash() == $form.data("initial_hash")) 54 { 55 window.onbeforeunload = null; 56 } 57 else { 58 window.onbeforeunload = function(e) { 59 var dialogText = 'You have unsaved changes in your form.'; 60 e.returnValue = dialogText; 61 return dialogText; 62 }; 63 } 64} 65 66function cp_forms_remove_block_click() { 67 68 var $form = $(this).closest('form'); 69 var use_table = $form.find('input[name="use_table"]').val() == 1; 70 71 var id_split = $(this).attr('id').replace("removeBlockBtn", "").split("_"); 72 var block_id = id_split[0]; 73 var grandparent_form_id = id_split[1]; 74 var grandparent_form_seq = id_split[2]; 75 var parent_form_id = id_split[3]; 76 var parent_form_seq = id_split[4]; 77 var block_seq = id_split[5]; 78 79 var block_suffix = block_id+"_"+grandparent_form_id+"_"+grandparent_form_seq+"_"+parent_form_id+"_"+parent_form_seq; 80 81 var $blockWrapper = $('#blockWrapper'+block_suffix+"_"+block_seq); 82 83 var tr_or_div = use_table ? "tr" : "div"; 84 85 numBlocksRemaining = $form.find(tr_or_div+'[id^="blockWrapper'+block_suffix+'_"]').length; 86 87 var animate = numBlocksRemaining > 1; 88 89 var $next = $blockWrapper.next(); 90 var $prev = $blockWrapper.prev(); 91 92 var $closestDivider = $next.is('.blockDivider') ? $blockWrapper.next() : $blockWrapper.prev(); 93 94 var removeDivider = numBlocksRemaining > 1 && $closestDivider.length > 0; 95 96 if(animate) 97 { 98 if(removeDivider) 99 { 100 var animTo = { 101 height: 0 102 , paddingTop: 0 103 , paddingBottom: 0 104 , marginTop: 0 105 , marginBottom: 0 106 , opacity: 0 107 }; 108 109 $closestDivider.animate(animTo, 200, 'easeOutSine', function(){ $(this).remove(); }); 110 } 111 112 $blockWrapper.addClass("removing").find('.blockAnimWrapper').animate(animTo, 200, 'easeOutSine'); 113 114 setTimeout(function(){ 115 $blockWrapper.remove(); 116 }, 200); 117 } 118 else 119 { 120 if(removeDivider) 121 { 122 $closestDivider.remove(); 123 } 124 $blockWrapper.remove(); 125 } 126 127 if(numBlocksRemaining == 1) 128 { 129 cp_forms_add_field($form.find('#addFieldsBtn'+block_suffix), false); 130 } 131 132 cp_forms_update_before_unload($form); 133} 134 135function cp_forms_add_field_click() { 136 cp_forms_add_field($(this)); 137} 138 139function cp_forms_add_field($btn, animate) { 140 141 animate = animate == null ? true : animate; 142 143 var $form = $btn.closest('form'); 144 145 var id_split = $btn.attr('id').split("_"); 146 147 var block_id = id_split[0].replace("addFieldsBtn", ""); 148 var grandparent_form_id = parseInt(id_split[1]); 149 var grandparent_form_seq = parseInt(id_split[2]); 150 var parent_form_id = parseInt(id_split[3]); 151 var parent_form_seq = parseInt(id_split[4]); 152 153 var use_table = $form.find('input[name="use_table"]').val() == 1; 154 155 var dividerHTML = use_table ? '<tr class=\"blockDivider\"><td colspan=\"999\"></td></tr>' : '<div class="blockDivider"></div>'; 156 var tr_or_div = use_table ? "tr" : "div"; 157 158 var last_block_wrapper_selector = tr_or_div+'[id^="blockWrapper'+block_id+'_'+grandparent_form_id+'_'+grandparent_form_seq+'_'+parent_form_id+'_'+parent_form_seq+'_"]'; 159 var $last_block_wrapper = $form.find(last_block_wrapper_selector).last(); 160 161 var newSeq = 0; 162 163 if($last_block_wrapper.length > 0) 164 { 165 var last_block_wrapper_id = $last_block_wrapper.attr("id"); 166 id_split = last_block_wrapper_id.split("_"); 167 newSeq = parseInt(id_split[5]) + 1; 168 } 169 170 var form_html_and_javascript = cp_forms_process_form_templates($form, block_id, grandparent_form_seq, parent_form_seq, newSeq); 171 172 var $block_wrapper = $(form_html_and_javascript.html); 173 174 $block_wrapper.find('.removeBlockBtn').click(cp_forms_remove_block_click); 175 $block_wrapper.find('[id^="addFieldsBtn"]').click(cp_forms_add_field_click); 176 177 var $block_divider = animate ? $(dividerHTML) : ""; 178 179 if($block_wrapper.first().hasClass('blockDivider')) 180 {//block already has a divider - we need this sometimes for subforms 181 $block_wrapper = $block_wrapper.last(); 182 } 183 184 if(use_table) 185 { 186 $btn.closest('tr').before($block_divider, $block_wrapper); 187 } 188 else 189 { 190 $btn.before($block_divider, $block_wrapper); 191 } 192 193 eval(form_html_and_javascript.javascript); 194 initFormStyles({$wrapper: $block_wrapper}); 195 196 if(animate) 197 { 198 var animFrom = { 199 height: 0 200 , paddingTop: 0 201 , paddingBottom: 0 202 , marginTop: 0 203 , marginBottom: 0
204 , opacity: 0 205 }; 206 207 var animTo = { 208 height: $block_divider[0].scrollHeight 209 , paddingTop: $block_divider.css("padding-top") 210 , paddingBottom: $block_divider.css("padding-bottom") 211 , marginTop: $block_divider.css("margin-top") 212 , marginBottom: $block_divider.css("margin-bottom") 213 , opacity: 1 214 }; 215 216 $block_divider.animate(animFrom, 0).animate(animTo, 200, 'easeOutSine', function(){ $block_divider.height(""); }); 217 218 animTo = { 219 height: $block_wrapper[0].scrollHeight 220 , paddingTop: $block_wrapper.css("padding-top") 221 , paddingBottom: $block_wrapper.css("padding-bottom") 222 , marginTop: $block_wrapper.css("margin-top") 223 , marginBottom: $block_wrapper.css("margin-bottom") 224 , opacity: 1 225 }; 226 227 $block_wrapper.find('.blockAnimWrapper').first().animate(animFrom, 0).animate(animTo, 200, 'easeOutSine', function(){ $(this).height("").css('overflow', 'visible'); }); 228 } 229 230 cp_forms_update_before_unload($form); 231} 232 233function cp_forms_process_form_templates($form, template_id, grandparent_form_seq, parent_form_seq, newSeq, html_only, javascript_only) { 234 235 html_only = html_only == null ? false : html_only == true; 236 javascript_only = javascript_only == null ? false : javascript_only == true; 237 238 var form_templates = $form.data('form_templates'); 239 var form_template = form_templates[template_id]; 240 241 var keys = ["{{grandparent_form_seq}}", "{{parent_form_seq}}", "{{seq}}"]; 242 var replacements = [grandparent_form_seq, parent_form_seq, newSeq]; 243 244 var newHTML = ""; 245 var newScripts = ""; 246 247 if(!javascript_only) //normally only used on subsequent recursions 248 { 249 /******************************************/ 250 /******** replace HTML recursively ********/ 251 /******************************************/ 252 253 newHTML = str_replace(keys, replacements, form_template.html); 254 255 var html_regex = /{{subform_html_(\d+)}}/g; 256 var html_result; 257 while ((html_result = html_regex.exec(newHTML)) !== null) { 258 259 var subform = cp_forms_process_form_templates($form, parseInt(html_result[1]), parent_form_seq, newSeq, 0, true); 260 261 newHTML = newHTML.slice(0, html_result.index) + subform.html + newHTML.slice(html_result.index+html_result[0].length); 262 263 // regex is stateful, reset its index as we have modified newHTML 264 html_regex.lastIndex = 0; 265 } 266 } 267 268 if(!html_only) //normally only used on subsequent recursions 269 { 270 /******************************************/ 271 /***** replace javascript recursively *****/ 272 /******************************************/ 273 274 newScripts = str_replace(keys, replacements, form_template.javascript); 275 276 var javascript_regex = new RegExp(/{{subform_javascript_(\d+)}}/g); 277 var javascript_result; 278 while ((javascript_result = javascript_regex.exec(newScripts)) !== null) { 279 280 var subform = cp_forms_process_form_templates($form, parseInt(javascript_result[1]), parent_form_seq, newSeq, 0, false, true); 281 282 newScripts = newScripts.slice(0, javascript_result.index) + subform.javascript + newScripts.slice(javascript_result.index+javascript_result[0].length); 283 284 // regex is stateful, reset its index as we have modified newScripts 285 javascript_regex.lastIndex = 0; 286 } 287 } 288 289 return({html: newHTML, javascript: newScripts}); 290} 291 292function cp_forms_trigger_subform(e) { 293 294 var subforms = $(this).data('subforms'); 295 var val = $(this).val(); 296 var subform_cpda_id = subforms[val]; 297 298 var id_split = $(this).attr('id').split("_"); 299 300 var grandparent_form_id = parseInt(id_split[1]); 301 var grandparent_form_seq = parseInt(id_split[2]); 302 var parent_form_id = parseInt(id_split[3]); 303 var parent_form_seq = parseInt(id_split[4]); 304 var seq = parseInt(id_split[5]); 305 306 for(var i in subforms) 307 { 308 if(subforms.hasOwnProperty(i)) 309 { 310 var subform_id = 'cpForm'+subforms[i]+'_'+grandparent_form_id+'_'+grandparent_form_seq+'_'+parent_form_id+'_'+parent_form_seq+'_'+seq; 311 var $subFormWrapper = $('#'+subform_id); 312 313 if($subFormWrapper.length > 0) 314 { 315 if(typeof $subFormWrapper.data("subformOn") == "undefined") 316 { 317 $subFormWrapper.data("subformOn", $subFormWrapper.hasClass('on')); 318 } 319 320 if(subforms[i] != subform_cpda_id) 321 { 322 if($subFormWrapper.data("subformOn") == true) 323 { 324 cp_forms_subform_anim_close($subFormWrapper); 325 } 326 } 327 else 328 { 329 if($subFormWrapper.data("subformOn") != true) 330 { 331 cp_forms_subform_anim_open($subFormWrapper); 332 } 333 } 334 } 335 } 336 } 337} 338 339function cp_forms_subform_anim_close($subFormWrapper) { 340 341 $subFormWrapper.data("subformOn", false).stop().removeClass('on'); 342 343 var $subFormAnimWrapper = $subFormWrapper.find('.subFormAnimWrapper').first(); 344 345 var animTo = { 346 height: 0 347 , paddingTop: 0 348 , paddingBottom: 0 349 , marginTop: 0 350 , marginBottom: 0 351 , opacity: 0 352 }; 353 354 $subFormAnimWrapper.stop().animate(animTo, 200, 'easeOutSine', function(){ 355 $(this).height(""); 356 $subFormWrapper.addClass('off'); 357 }); 358} 359 360function cp_forms_subform_anim_open($subFormWrapper) { 361 362 $subFormWrapper.data("subformOn", true).stop().removeClass('off').addClass('on'); 363 364 var $subFormAnimWrapper = $subFormWrapper.find('.subFormAnimWrapper').first(); 365 366 var animFrom = { 367 height: 0 368 , paddingTop: 0 369 , paddingBottom: 0 370 , marginTop: 0 371 , marginBottom: 0 372 , opacity: 0 373 }; 374 375 var animTo = { 376 height: $subFormAnimWrapper[0].scrollHeight 377 , paddingTop: $subFormAnimWrapper.css("padding-top") 378 , paddingBottom: $subFormAnimWrapper.css("padding-bottom") 379 , marginTop: $subFormAnimWrapper.css("margin-top") 380 , marginBottom: $subFormAnimWrapper.css("margin-bottom") 381 , opacity: 1 382 }; 383 384 $subFormAnimWrapper.stop().animate(animFrom, 0).animate(animTo, 200, 'easeOutSine', function(){ 385 $(this).css({height: "", overflow: "visible"}); 386 }); 387} 388 389function cp_forms_sort_code_change(e) { 390 if($(this).val().toString().length == 2 && (mobile || this.selectionStart == 2)) 391 { 392 $(this).nextAll("input").first().focus().select(); 393 } 394} 395 396function cp_forms_document_upload_on_complete(id, fileName, responseJSON) { 397
398 var fieldName = this._element.id.replace('_upload_drop_zone', ''); 399 400 var qtip_api = $('#'+fieldName+'_upload_button').removeClass("cpFormsInvalid").qtip('api'); 401 if(typeof qtip_api != "undefined") 402 { 403 qtip_api.destroy(); 404 } 405 406 if(responseJSON.error) 407 { 408 alert(responseJSON.error); 409 } 410 else 411 { 412 $(this._element).find('.qq-upload-list').empty(); 413 414 if(typeof responseJSON.uploadName != "undefined") 415 { 416 cp_forms_document_set_file(fieldName, fileName, responseJSON.uploadName); 417 } 418 } 419} 420 421function cp_forms_document_set_file(fieldName, original_filename, filesystem_filename) { 422 423 original_filename = original_filename.replace(',', ''); 424 425 $('#'+fieldName+'_upload_filename_new').val(original_filename + ',' + filesystem_filename); 426 $('#'+fieldName+'_upload_filename_text').html(original_filename); 427 428 $('#'+fieldName+'_new_file_wrapper').hide(); 429 $('#'+fieldName+'_existing_file_wrapper').show(); 430 431} 432 433function cp_forms_document_remove_click(e) { 434 435 var fieldName = $(this).attr('id').replace('_remove_button', ''); 436 cp_forms_document_remove_file(fieldName); 437 438} 439 440function cp_forms_document_remove_file(fieldName) { 441 442 $('#'+fieldName+'_upload_filename_new').val(''); 443 $('#'+fieldName+'_upload_filename_text').html(''); 444 445 $('#'+fieldName+'_new_file_wrapper').removeClass('processing').show(); 446 $('#'+fieldName+'_existing_file_wrapper').hide(); 447 448} 449 450function cp_forms_document_upload_on_error(id, fileName, errorReason) { 451 alert("Error uploading file, please try again"); 452 var fieldName = this._element.id.replace('_upload_drop_zone', ''); 453 cp_forms_document_remove_file(fieldName); 454} 455 456function cp_forms_document_upload_on_upload() { 457 var fieldName = this._element.id.replace('_upload_drop_zone', ''); 458 $('#'+fieldName+'_new_file_wrapper').addClass('processing'); 459 460 var qtip_api = $('#'+fieldName+'_upload_button').removeClass("cpFormsInvalid").qtip('api'); 461 if(typeof qtip_api != "undefined") 462 { 463 qtip_api.destroy(); 464 } 465} 466 467//has some bug where it sometimes picks up hidden but mandatory fields? 468function cp_client_side_validation($form){ 469 470 471 var error_count = 0; 472 var error_details = { 473 errors : [] 474 ,form_cpda_id : $form.find('input[name=form_cpda_id]').val() 475 ,success : false 476 477 }; 478 479 $form.find('.mandatory').each(function(){ 480 $input_field = $(this).find('input, textarea, select'); 481 $users_input = $input_field.val(); 482 if($users_input.length < 1){ 483 error_count++; 484 error_item = { 485 error_code : 0 486 ,field_name : $input_field.attr("name") 487 ,manditory : true 488 ,field_title : $input_field.attr("placeholder") 489 }; 490 error_details.errors.push(error_item); 491 } 492 }); 493 494 495 $form.find('.set_fieldtype_form_consent_email, .set_fieldtype_form_email').each(function(){ 496 $input_field = $(this).find('input'); 497 $users_input = $input_field.val(); 498 //the length check is to avoid empty optional email addresses failing validation 499 if($users_input.length > 0 && !validateEmail($users_input)){ 500 error_count++; 501 error_item = { 502 error_code : 2 503 ,field_name : $input_field.attr("name") 504 ,manditory : true 505 ,field_title : $input_field.attr("placeholder") 506 }; 507 error_details.errors.push(error_item); 508 } 509 }); 510 511 512 513 if(error_count > 0){ 514 cp_forms_submission_success(error_details, $form, true, null); 515 return false; 516 } 517 518 return true; 519} 520 521function cp_forms_submit(e) { 522 523 e.preventDefault(); 524 525 var $form = $(this); 526 527 if(!navigator.onLine && !cp_client_side_validation($form)){ 528 return false; 529 } 530 531 if(cp_forms_prepare_for_submission($form)) 532 { 533 534 //check if offline. if offline, check for service worker. cache submission if so. 535 //I'm disabling this for now because it should probably be on a flag. we don't have a robust process for handling offline submissions which fail validation. addressible with complete client-side validation. we have partial client side navigation at the moment and it has proven to be buggy, so we can't rely on that yet. 536 if(!navigator.onLine && false){ 537 538 $form_json = $form.serializeArray(); 539 540 let offline_submitted_forms; 541 542 if (localStorage.getItem('offline_submitted_forms')) { 543 offline_submitted_forms = JSON.parse(localStorage.getItem('offline_submitted_forms')); 544 } else { 545 offline_submitted_forms = []; 546 } 547 548 offline_submitted_forms.push($form_json); 549 550 localStorage.setItem('offline_submitted_forms', JSON.stringify(offline_submitted_forms)); 551 console.log("You are offline! We will hold a copy of your form in your local browser storage. We'll check periodically if you are online and then the form will submit."); 552 553 //normally the server responds with some stuff including the form_cpda_id which is then passed to the callbackfunction (if present). in this scenario lets grab it from the hidden form input 554 let form_cpda_id; 555 for (index = 0; index < $form_json.length; ++index) { 556 if($form_json[index]["name"] == "form_cpda_id"){ 557 form_cpda_id = $form_json[index]["value"]; 558 } 559 } 560 561 //and now call the success callback 562 if(typeof cp_forms_callback_success != "function" || cp_forms_callback_success($form, form_cpda_id) === false) 563 { 564 $form.find('.cpFormWrapper').slideUp(300); 565 $form.append('<p class="cpFormDefaultSuccessText">You appear to be offline, but we will submit your form as soon as you come back online.</p>'); 566 } 567 568 } 569 else{ 570 //lets submit 571 var submit_action = $form.attr('action') == null ? "cp_forms.php" : $form.attr('action'); 572 $.ajax({
573 type : 'POST', 574 url : submit_action, 575 dataType : 'json', 576 data: $form.serializeArray(), 577 success : function(data){ 578 cp_forms_processFormResponse(data, $form); 579 }, 580 error: function(XMLHttpRequest, textStatus, errorThrown) { 581 cp_forms_submission_error($form, XMLHttpRequest); 582 } 583 }); 584 } 585 586 587 } 588 589 return false; 590} 591 592function cp_forms_clear_errors($form) { 593 594 $('.qtip').each(function(){ 595 cp_forms_destroy_qtip($(this)); 596 }); 597 598 $form.find(".cpFormsInvalid").each(function(){ 599 cp_forms_destroy_qtip($(this).removeClass("cpFormsInvalid")); 600 }); 601 602} 603 604function cp_forms_destroy_qtip($elm) { 605 var qtip = $elm.qtip('api') ? $elm.qtip('api') : $elm.data('qtip'); 606 if(qtip) 607 { 608 qtip.destroy(true); 609 } 610} 611 612function cp_forms_prepare_for_submission($form) { 613 614 if($form.data("cpFormsSubmitting") != true) 615 { 616 cp_forms_update_before_unload($form, true); 617 618 cp_forms_clear_errors($form); 619 620 $form.data("cpFormsSubmitting", true); 621 $form.data("cpFormsSubmitButtons").addClass('loading'); 622 623 return true; 624 } 625 626 return false; 627} 628 629function cp_forms_submission_error($form, XMLHttpRequest) { 630 cp_forms_update_before_unload($form); 631 $form.data("cpFormsSubmitButtons").removeClass('loading'); 632 $form.data("cpFormsSubmitting", false); 633 if(cp.in_cp) 634 { 635 cp.show_error('Form error', 'cp_forms_submission_error', null, XMLHttpRequest); 636 } 637 else 638 { 639 console.log("Form error: ", XMLHttpRequest.responseText); 640 } 641} 642 643//error codes 644/* 645-1 = this is a custom message from serverside 6460 = mandatory field left blank 6471 = confirm field left blank 6482 = invalid email address 6493 = email address confirm field does not match 6504 = invalid password 6515 = mandatory checkbox not checked 6526 = select menu option not selected 6537 = year range to is less than from 6548 = mandatory value not present 6559 = NMC or HPC PIN must be 8 characters long 65610 = NMC or HPC PIN must contain only letters and numbers 65711 = no data submitted 65812 = invalid captcha 65913 = mandatory yes/no not checked 66014 = multi select menu option not selected 66115 = value is not numeric 66216 = subform missing 66317 = bank account number invalid 66418 = sort code invalid 66519 = mandatory file not uploaded 66620 = date too far in future 66721 = salary lower than minimum wage 66822 = too many options selected 66923 = too many words 67024 = vat number invalid 67125 = email address already in use 67226 = app portal - mandatory data is missing from a subform 67327 = manage my data form too many requests 67428 = date of birth too far in future 67529 = number should be 10 digits 67630 = password confirm field does not match 67731 = National Insurance Number must be 9 characters long 67832 = National Insurance Number must be in the format AA999999A 67933 = must have a from and to date 680*/ 681var cpFormResponseMessages = { 682 "0": "This field cannot be left blank" 683 , "1": "This field cannot be left blank" 684 , "2": "Please type a valid email address" 685 , "3": "Email addresses do not match" 686 , "4": "Password must be at least 8 characters and include at least one letter and one number" 687 , "5": "This field must be checked" 688 , "6": "You must select an option" 689 , "7": "'From' date must not be more recent than 'To'" 690 , "8": "{{field_title}} is missing" 691 , "9": "NMC or HPC PIN must be 8 characters long" 692 , "10": "NMC or HPC PIN must be in the format 99A9999A" 693 , "11": "No data was submitted" 694 , "12": "Captcha check failed, please try again" 695 , "13": "You must answer yes" 696 , "14": "You must select at least one option" 697 , "15": "This field must contain only numbers" 698 , "16": "Some data is missing" 699 , "17": "{{field_title}} must be 8 digits" 700 , "18": "{{field_title}} must be 6 digits" 701 , "19": "No file was uploaded" 702 , "20": "Date too far in future" 703 , "21": "The salary you have specified is lower than minimum wage" 704 , "22": "You must select no more than {{max_options}} options" 705 , "23": "Please enter no more than {{max_words}} words" 706 , "24": "VAT number is invalid" 707 , "25": "Email address is already in use" 708 , "26": "" // app portal - mandatory data is missing from a subform 709 , "27": "You have submitted too many requests, please try again later" 710 , "28": "Invalid Date of Birth" 711 , "29": "{{field_title}} must be {{string_length}} {{string_type}}" 712 , "30": "Passwords do not match" 713 , "33": "You must choose both a 'from' and 'to' date" 714 , "34": "{{field_title}} must be in the format '{{string_format}}'" 715}; 716 717var cpFormMobileResponseMessages = { 718 "0": "{{field_title}} cannot be left blank" 719 , "1": "{{field_title}} cannot be left blank" 720 , "2": "Please type a valid email address" 721 , "3": "Email addresses do not match" 722 , "4": "Password must be at least 8 characters and include at least one letter and one number" 723 , "5": "This field must be checked: {{field_title}}" 724 , "6": "You must select an option: {{field_title}}" 725 , "7": "'From' date must not be more recent than 'To'" 726 , "8": "{{field_title}} is missing"
727 , "9": "NMC or HPC PIN must be 8 characters long" 728 , "10": "NMC or HPC PIN must be in the format 99A9999A" 729 , "11": "No data was submitted" 730 , "12": "Captcha check failed, please try again" 731 , "13": "{{field_title}}: You must answer yes" 732 , "14": "{{field_title}}: You must select at least one option" 733 , "15": "{{field_title}} must contain only numbers" 734 , "16": "Some data is missing" 735 , "17": "{{field_title}} must be 8 digits" 736 , "18": "{{field_title}} must be 6 digits" 737 , "19": "{{field_title}}: No file was uploaded" 738 , "20": "{{field_title}}: Date too far in future" 739 , "21": "The salary you have specified is lower than minimum wage" 740 , "22": "{{field_title}}: You must select no more than {{max_options}} options" 741 , "23": "{{field_title}}: Please enter no more than {{max_words}} words" 742 , "24": "VAT number is invalid" 743 , "25": "{{field_title}}: Email address is already in use" 744 , "26": "" // app portal - mandatory data is missing from a subform 745 , "27": "You have submitted too many requests, please try again later" 746 , "28": "{{field_title}}: Invalid Date of Birth" 747 , "29": "{{field_title}} must be {{string_length}} {{string_type}}" 748 , "30": "Passwords do not match" 749 , "33": "You must choose both a 'from' and 'to' date" 750 , "34": "{{field_title}} must be in the format '{{string_format}}'" 751}; 752 753function cp_forms_processFormResponse(data, $form, divider_cpda_id, skipDefaultFormSubmittedAnimation) { 754 755 var keepLoadingSpinnersOnSuccess = false; 756 skipDefaultFormSubmittedAnimation = skipDefaultFormSubmittedAnimation === true; 757 var showDefaultFormSubmittedAnimation = !skipDefaultFormSubmittedAnimation; 758 759 if(data.success) 760 { 761 if (data.form_cpda_id == "-18") { 762 cp_googleTagManagerTrack('job_application'); 763 cp_facebookPixelTrack('SubmitApplication'); 764 } 765 else 766 { 767 cp_googleTagManagerTrack('form_submission'); 768 cp_facebookPixelTrack('FormSubmission', {form_cpda_id: data.form_cpda_id}); 769 } 770 771 if(typeof cp_forms_callback == "function") 772 { 773 cp_forms_callback(data); 774 } 775 776 if(typeof cp_forms_callback_success == "function") 777 { 778 var callback_success_response = cp_forms_callback_success($form, data.form_cpda_id); 779 780 if(callback_success_response === true || callback_success_response === 1) // return true or a 1 to skip the default submitted animation 781 { 782 showDefaultFormSubmittedAnimation = false; 783 } 784 else if(callback_success_response === 2) // return 2 to skip the default submitted animation AND keep the loading spinners on 785 { 786 showDefaultFormSubmittedAnimation = false; 787 keepLoadingSpinnersOnSuccess = true; 788 } 789 } 790 791 if(showDefaultFormSubmittedAnimation) 792 { 793 $form.find('.cpFormWrapper').slideUp(300); 794 $form.append('<p class="cpFormDefaultSuccessText">Form submitted successfully.</p>'); 795 } 796 } 797 798 return cp_forms_submission_success(data, $form, keepLoadingSpinnersOnSuccess, divider_cpda_id); 799} 800 801function cp_forms_submission_success(data, $form, keepLoadingSpinnersOnSuccess, divider_cpda_id) { 802 803 if(typeof CPO_DEBUG != "undefined" && CPO_DEBUG == true) 804 { 805 console.log("data: ", data); 806 } 807 808 keepLoadingSpinnersOnSuccess = keepLoadingSpinnersOnSuccess == true; 809 810 if(!data.success || !keepLoadingSpinnersOnSuccess) 811 { 812 if(typeof $form.data("cpFormsSubmitButtons") !== "undefined") 813 { 814 $form.data("cpFormsSubmitButtons").removeClass('loading'); 815 } 816 } 817 818 if(data.success) 819 { 820 return true; 821 } 822 823 var responseMessages = mobile ? cpFormMobileResponseMessages : cpFormResponseMessages; 824 825 var $wrapper = $form == null ? $('body') : $form; 826 827 var $container = $('body'); 828 if($form.parents('.cpMain').length > 0) 829 { 830 $container = $('#cpMain'); 831 } 832 833 if($form != null) 834 { 835 $form.data("cpFormsSubmitting", false); 836 } 837 838 if($form.find('.set_fieldtype_form_captcha').length > 0) 839 { 840 grecaptcha.reset(); 841 } 842 843 for(var j in data.errors) 844 { 845 if(data.errors[j].error_code == 26) 846 { 847 $('#popupFormContent').find('form').submit(); 848 return false; 849 } 850 } 851 852 if(typeof window.cpFormsDontFocusOnError == "undefined") 853 { 854 window.cpFormsDontFocusOnError = []; 855 } 856 857 for(var i in data.errors) 858 { 859 if(data.errors.hasOwnProperty(i) && (divider_cpda_id == null || data.errors[i].divider_id == divider_cpda_id)) 860 { 861 var $input = null; 862 863 if(data.errors[i].field_name != null && data.errors[i].field_name != "") 864 { 865 var field_name = data.errors[i].field_name; 866 867 var lookup_name = field_name; 868 if(data.errors[i].subfield_name_suffix) 869 { 870 lookup_name += data.errors[i].subfield_name_suffix; 871 } 872 873 var tokenArray = ["{{field_title}}", "{{max_words}}", "{{max_options}}", "{{string_length}}", "{{string_type}}", "{{string_format}}"]; 874 var tokenReplaceArray = [data.errors[i].field_title, data.errors[i].max_words, data.errors[i].max_options, data.errors[i].string_length, data.errors[i].string_type, data.errors[i].string_format]; 875 var errorMessage = 876 data.errors[i].error_code == -1 ? data.errors[i].custom_error_message 877 : str_replace(tokenArray, tokenReplaceArray, responseMessages[data.errors[i].error_code]); 878 879 if(data.errors[i].error_code != 12 && data.errors[i].error_code != 19) 880 { 881 var fieldNameLastChar = field_name.substr(field_name.length - 1); 882 if(fieldNameLastChar == "*") 883 { 884 var fieldNameWithoutLastChar = field_name.substr(0, field_name.length - 1); 885 $input = $wrapper.find('input[name^="'+fieldNameWithoutLastChar+'"]').first(); 886 if($input.length == 0) 887 { 888 $input = $wrapper.find('textarea[name^="'+fieldNameWithoutLastChar+'"]').first(); 889 890 if($input.length == 0) 891 { 892 if(mobile) 893 { 894 $input = $wrapper.find('select[name^="'+fieldNameWithoutLastChar+'"]').first(); 895 } 896 897 if($input.length == 0) 898 { 899 $input = null; 900 } 901 } 902 } 903 } 904 else 905 { 906 $input = $wrapper.find('input[name="'+lookup_name+'"]'); 907 if($input.length == 0) 908 { 909 $input = $wrapper.find('textarea[name="'+lookup_name+'"]'); 910 911 if($input.length == 0 && mobile) 912 { 913 $input = $wrapper.find('select[name="'+lookup_name+'"]'); 914 } 915 } 916 } 917 918 //if we have found the culprit input 919 if($input != null) 920 { 921 var fieldTypeAndElm = fsGetFieldTypeAndElm($input); 922 if(fieldTypeAndElm != false) 923 { 924 var fieldType = fieldTypeAndElm.fieldType; 925 var $field = fieldTypeAndElm.$elm; 926 var $tinyMCE = null; 927 928 if($field.is("textarea") && typeof tinyMCE != "undefined" && tinyMCE.get(lookup_name)) 929 { 930 fieldType = "html"; 931 $tinyMCE = $(tinyMCE.get(lookup_name).getContainer()); 932 } 933 934 if(!mobile) 935 { 936 var tooltipOptions = { 937 content: errorMessage 938 , position: { 939 my: 'left center' 940 , at: 'right center' 941 , viewport: $(window) 942 , effect: false 943 , container: $container 944 } 945 , show: { 946 event: 'focus mouseenter' 947 , effect: function(offset) { 948 $(this).fadeIn(50); 949 } 950 , ready: i == 0 && window.cpFormsDontFocusOnError.indexOf(parseInt(data.form_cpda_id)) !== -1 951 } 952 , hide: { 953 event: 'blur change mouseleave' 954 , effect: function(offset) { 955 $(this).fadeOut(50); 956 } 957 // event: false 958 } 959 , style: { 960 classes: 'cpErrorTooltip qtip-shadow' 961 , tip: { 962 width: 8 963 } 964 } 965 }; 966 967 $.fn.qtip.zindex = 99999; 968 969 switch(fieldType) { 970 case "select": 971 case "formStyledSelect": 972 break; 973 case "checkbox": 974 case "formStyledCheckbox": 975 case "formStyledPlaceholderCheckbox": 976 tooltipOptions.position.my = 'top left'; 977 tooltipOptions.position.at = 'bottom center'; 978 tooltipOptions.position.adjust = {y: 2}; 979 tooltipOptions.show.ready = true; 980 tooltipOptions.show.event = false; 981 tooltipOptions.hide.event = 'change'; 982 tooltipOptions.hide.target = $input; 983 break; 984 case "formStyledRadio": 985 tooltipOptions.position.my = 'center right'; 986 tooltipOptions.position.at = 'center left'; 987 tooltipOptions.position.adjust = {x: -2}; 988 $field = $field.first().parent().parent(); 989 break; 990 case "html": 991 // tinyMCEObj 992 tooltipOptions.position.my = 'bottom right'; 993 tooltipOptions.position.at = 'top right'; 994 tooltipOptions.position.target = $tinyMCE; 995 tooltipOptions.position.adjust = {x: 2}; 996 tooltipOptions.show.ready = true; 997 tooltipOptions.show.event = false; 998 tooltipOptions.hide.event = false; 999 break; 1000 } 1001 1002 if($field.data("qtipOptions") != undefined) 1003 { 1004 $.extend(tooltipOptions, $field.data("qtipOptions")); 1005 } 1006 else if($field.hasClass("cpFormsTooltipLeft")) 1007 { 1008 tooltipOptions.position.my = 'right center'; 1009 tooltipOptions.position.at = 'left center'; 1010 } 1011 else if($field.hasClass("cpFormsTooltipBottom")) 1012 { 1013 tooltipOptions.position.my = 'top center'; 1014 tooltipOptions.position.at = 'bottom center'; 1015 } 1016 else if($field.hasClass("cpFormsTooltipTop")) 1017 { 1018 tooltipOptions.position.my = 'bottom center'; 1019 tooltipOptions.position.at = 'top center'; 1020 } 1021 else if($field.hasClass("cpFormsTooltipBottomRight")) 1022 { 1023 tooltipOptions.position.my = 'top left'; 1024 tooltipOptions.position.at = 'bottom right'; 1025 } 1026 1027 if(fieldType == "html") 1028 {
1029 $tinyMCE.addClass("cpFormsInvalid"); 1030 } 1031 else if(fieldType == "cp_form_field_address_lookup") 1032 { 1033 CPFormFieldAddressLookup_toggle_manual_mode(true, field_name); 1034 } 1035 1036 $field.addClass("cpFormsInvalid").qtip(tooltipOptions); 1037 } 1038 else 1039 { 1040 alert(errorMessage); 1041 $field.addClass("cpFormsInvalid"); 1042 } 1043 1044 $input.one("change", cp_forms_clearInvalidOnChange); 1045 1046 if(i == 0 && window.cpFormsDontFocusOnError.indexOf(parseInt(data.form_cpda_id)) === -1) 1047 { 1048 $field.focus(); 1049 } 1050 } 1051 else 1052 { 1053 console.error("cp_forms_processFormResponse: couldn't find field '"+lookup_name+"'"); 1054 } 1055 } 1056 } 1057 else if(data.errors[i].error_code == 19) 1058 { 1059 var $field = $('#'+lookup_name+'_upload_button'); 1060 var $input = $('#'+lookup_name+'_upload_filename_new'); 1061 1062 if(!mobile) 1063 { 1064 var tooltipOptions = { 1065 content: errorMessage 1066 , position: { 1067 my: 'left center' 1068 , at: 'right center' 1069 , viewport: $(window) 1070 , effect: false 1071 } 1072 , show: { 1073 ready: true 1074 , event: false 1075 } 1076 , hide: { 1077 event: false 1078 } 1079 , style: { 1080 classes: 'cpErrorTooltip qtip-shadow' 1081 , tip: { 1082 width: 8 1083 } 1084 } 1085 }; 1086 1087 $.fn.qtip.zindex = 99999; 1088 $field.addClass("cpFormsInvalid").qtip(tooltipOptions); 1089 } 1090 else 1091 { 1092 alert(errorMessage); 1093 $field.addClass("cpFormsInvalid").qtip(tooltipOptions); 1094 } 1095 1096 } 1097 else if(data.errors[i].error_code == 12) 1098 { 1099 if(!mobile) 1100 { 1101 var tooltipOptions = { 1102 content: errorMessage 1103 , position: { 1104 my: 'left center' 1105 , at: 'right center' 1106 , viewport: $(document) 1107 , effect: false 1108 } 1109 , show: { 1110 event: 'focus mouseenter' 1111 , effect: function(offset) { 1112 $(this).fadeIn(200); 1113 } 1114 } 1115 , hide: { 1116 event: 'blur change mouseleave' 1117 // event: false 1118 } 1119 , style: { 1120 classes: 'cpErrorTooltip qtip-shadow' 1121 , tip: { 1122 width: 8 1123 } 1124 } 1125 }; 1126 1127 $.fn.qtip.zindex = 99999; 1128 $form.find('.g-recaptcha > div').addClass("cpFormsInvalid").qtip(tooltipOptions); 1129 } 1130 else 1131 { 1132 alert(errorMessage); 1133 $form.find('.g-recaptcha').addClass("cpFormsInvalid"); 1134 } 1135 1136 $input = true; 1137 1138 } 1139 } 1140 1141 if($input == null) 1142 {//this is a general error not associated with a field 1143 //TODO make this prettier 1144 1145 var tokenArray = ["{{field_title}}"]; 1146 var tokenReplaceArray = [data.errors[i].field_title]; 1147 var errorMessage = 1148 data.errors[i].error_code == -1 ? data.errors[i].custom_error_message 1149 : str_replace(tokenArray, tokenReplaceArray, responseMessages[data.errors[i].error_code]); 1150 1151 if(typeof cp_toasts_add == "function" && data.errors[i].use_alert !== true) 1152 { 1153 cp_toasts_add({message: errorMessage, type: 2}) 1154 } 1155 else 1156 { 1157 alert(errorMessage); 1158 } 1159 1160 if(data.errors[i].error_code == -1 && typeof CPO_DEBUG != undefined && CPO_DEBUG == true) 1161 { 1162 console.log("cp_forms_processFormResponse() debug_error_message: ", data.errors[i].debug_error_message); 1163 } 1164 } 1165 } 1166 } 1167 1168 cp_forms_update_before_unload($form); 1169 1170 if(typeof cp_forms_callback == "function") 1171 { 1172 cp_forms_callback(data); 1173 } 1174 return false; 1175} 1176 1177function cp_forms_datepicker_add_clear_button(input) { 1178 setTimeout(function() { 1179 1180 if(mobile) 1181 { 1182 $(input).blur(); 1183 } 1184 1185 var $widget = $(input).datepicker("widget"); 1186 1187 $widget.find('.ui-datepicker-header,.ui-datepicker-calendar').addClass('notranslate'); 1188 1189 var $buttonPane = $widget.find(".ui-datepicker-buttonpane"); 1190 1191 $( "<button>", { 1192 text: "Clear", 1193 click: function() { 1194 $(input).val('').datepicker("hide"); 1195 } 1196 }).appendTo( $buttonPane ).addClass("ui-datepicker-clear ui-state-default ui-priority-primary ui-corner-all"); 1197 }, 1 ); 1198} 1199 1200function CPFormFieldSelectMultipleWithSearch_init(field_id) { 1201 setTimeout(function(){ 1202 var $field_elm = document.getElementById(field_id+'_search_wrapper'); 1203 var $field_elm_select_wrapper = document.getElementById('for'+field_id).querySelectorAll('.selectOptionWrapper'); 1204 var $field_elm_sarch_input = document.getElementById(field_id+'_search_input') 1205 var field_elm_select_wrapper_orig_height = $field_elm_select_wrapper[0].clientHeight; 1206 1207 $field_elm_select_wrapper[0].style.maxHeight = field_elm_select_wrapper_orig_height+'px'; 1208 1209 $field_elm_select_wrapper[0].style.height = $field_elm.clientHeight+'px'; 1210 $field_elm_select_wrapper[0].style.overflow = 'hidden'; 1211 1212 $field_elm_sarch_input.addEventListener('keyup', function() { 1213 if (this.value == '') 1214 { 1215 $field_elm_select_wrapper[0].style.height = $field_elm.clientHeight+'px'; 1216 $field_elm_select_wrapper[0].style.overflow = 'hidden'; 1217 } 1218 else 1219 { 1220 $field_elm_select_wrapper[0].style.height = 'auto'; 1221 $field_elm_select_wrapper[0].style.overflowY = 'auto'; 1222 } 1223 }); 1224 1225 var clearSearchButton = $field_elm_select_wrapper[0].querySelectorAll('.clearSearch')[0]; 1226 if (clearSearchButton) { 1227 clearSearchButton.addEventListener('click', function() { 1228 $field_elm_select_wrapper[0].style.height = $field_elm.clientHeight+'px'; 1229 $field_elm_select_wrapper[0].style.overflow = 'hidden'; 1230 }); 1231 } 1232 }, 2); 1233} 1234 1235function CPFormFieldAddressLookup_init(field_id, restrictCountries) { 1236 if(cp.config.apis.ideal_postcodes_api_key) 1237 { 1238 IdealPostcodes.AddressFinder.setup({ 1239 apiKey: cp.config.apis.ideal_postcodes_api_key, 1240 inputField: '#'+field_id+'_search', 1241 onUnhide: function() { 1242 if(!document.getElementById(field_id+'_manual_fields').classList.contains('manual_mode')) 1243 { 1244 CPFormFieldAddressLookup_toggle_manual_mode(true, field_id); 1245 } 1246 }, 1247 outputFields: { 1248 line_1: '#'+field_id+'_line_1', 1249 line_2: '#'+field_id+'_line_2', 1250 line_3: '#'+field_id+'_line_3', 1251 post_town: '#'+field_id+'_post_town', 1252 postcode: '#'+field_id+'_postcode', 1253 latitude: '#'+field_id+'_latitude', 1254 longitude: '#'+field_id+'_longitude' 1255 }, 1256 restrictCountries: restrictCountries, 1257 onFailedCheck: function (error) { 1258 CPFormFieldAddressLookup_init_address_only(field_id); 1259 console.warn('CPFormFieldAddressLookup failed to initiate with supplied API key. This URL might not be whitelisted, or the number of lookups may have exceeded the daily rate. Error returned was: "'+error.message+'"'); 1260 } 1261 }); 1262 1263 document.getElementById(field_id+'_manual_entry').addEventListener('click', function() 1264 { 1265 CPFormFieldAddressLookup_manual_entry_click(field_id); 1266 }); 1267 1268 // if started in manual mode 1269 if(document.getElementById(field_id+'_manual_fields').classList.contains('manual_mode')) 1270 { 1271 CPFormFieldAddressLookup_toggle_manual_mode(true, field_id, true); 1272 } 1273 } 1274 else 1275 { 1276 CPFormFieldAddressLookup_init_address_only(field_id); 1277 } 1278} 1279 1280function CPFormFieldAddressLookup_init_address_only(field_id) { 1281 document.getElementById(field_id+'_top_wrapper').remove(); 1282 var $manual_field_wrapper = document.getElementById(field_id+'_manual_fields'); 1283 $manual_field_wrapper.classList.add('open','manual_only'); 1284 $manual_field_wrapper.style.height = null; 1285} 1286 1287function CPFormFieldAddressLookup_manual_entry_click(field_id) { 1288 1289 1290 if(document.getElementById(field_id+'_manual_fields').classList.contains('manual_mode')) 1291 { 1292 CPFormFieldAddressLookup_toggle_manual_mode(false, field_id); 1293 } 1294 else 1295 { 1296 CPFormFieldAddressLookup_toggle_manual_mode(true, field_id); 1297 setTimeout(function(){ 1298 document.getElementById(field_id+'_line_1').focus(); 1299 }, 200); 1300 } 1301} 1302 1303function CPFormFieldAddressLookup_toggle_manual_mode(onOff, field_id, from_init) { 1304 1305 var $manual_field_wrapper = document.getElementById(field_id+'_manual_fields'); 1306 1307 // if field is in manual only mode we don't need to do anything 1308 if($manual_field_wrapper.classList.contains('manual_only')) 1309 { 1310 return; 1311 } 1312 1313 var anim_time = 200; 1314 var $manual_entry_p = document.getElementById(field_id+'_manual_entry'); 1315 var $search_wrapper = document.getElementById(field_id+'_search_wrapper'); 1316 1317 if(onOff === true) 1318 { 1319 $manual_field_wrapper.classList.add('manual_mode'); 1320 $manual_entry_p.innerHTML = '↻ Search for address'; 1321 1322 $search_wrapper.style.opacity = 0; 1323 $manual_field_wrapper.style.opacity = 1; 1324 1325 if(from_init !== true) 1326 { 1327 document.getElementById(field_id+'_search').blur(); 1328 1329 $manual_field_wrapper.style.height = $manual_field_wrapper.scrollHeight+'px'; 1330 $manual_field_wrapper.style.opacity = 1; 1331 setTimeout(function(){ 1332 $manual_field_wrapper.classList.add('open'); 1333 $manual_field_wrapper.style.height = ''; 1334 }, anim_time+50); 1335 1336 $search_wrapper.style.height = $search_wrapper.scrollHeight+'px'; 1337 $search_wrapper.classList.remove('open'); 1338 setTimeout(function(){ 1339 $search_wrapper.style.height = '0px'; 1340 }, 2); 1341 } 1342 } 1343 else 1344 { 1345 $manual_field_wrapper.classList.remove('manual_mode'); 1346 $manual_entry_p.innerHTML = 'Enter address manually'; 1347 1348 $search_wrapper.style.opacity = 1; 1349 $manual_field_wrapper.style.opacity = 0; 1350 1351 $manual_field_wrapper.style.height = $manual_field_wrapper.scrollHeight+'px'; 1352 $manual_field_wrapper.classList.remove('open'); 1353 setTimeout(function(){ 1354 $manual_field_wrapper.style.height = '0px'; 1355 }, 2); 1356 1357 $search_wrapper.style.height = $search_wrapper.scrollHeight+'px'; 1358 setTimeout(function(){ 1359 $search_wrapper.classList.add('open'); 1360 $search_wrapper.style.height = ''; 1361 }, anim_time+50); 1362 1363 setTimeout(function(){ 1364 document.getElementById(field_id+'_search').focus(); 1365 }, anim_time+1); 1366 } 1367 1368 1369} 1370 1371function cp_forms_clearInvalidOnChange() { 1372 var fieldTypeAndElm = fsGetFieldTypeAndElm($(this)); 1373 var $elm = fieldTypeAndElm.$elm; 1374 if(fieldTypeAndElm.fieldType == "formStyledRadio") 1375 { 1376 $elm = $elm.parent().parent(); 1377 }
1378 $elm.removeClass("cpFormsInvalid").unbind("change"); 1379 if($elm.qtip('api')) 1380 { 1381 $elm.qtip('api').destroy(); 1382 } 1383} 1384 1385function CPFormFieldDateRange_init(elm_id, date_format, date_range_divider, preset_ranges) { 1386 cp_date_range_init(elm_id, date_format, date_range_divider, preset_ranges, false); 1387} 1388 1389function CPFormFieldDateTimeRange_init(elm_id, date_format, date_range_divider, preset_ranges) { 1390 cp_date_range_init(elm_id, date_format, date_range_divider, preset_ranges, true); 1391} 1392 1393function cp_date_range_init(elm_id, date_format, date_range_divider, preset_ranges, include_time) { 1394 1395 var $datepicker_btn = $('#'+elm_id+'_btn'); 1396 var $datepicker_summary = $('#'+elm_id); 1397 var $datepicker_from = $('#'+elm_id+'_from'); 1398 var $datepicker_to = $('#'+elm_id+'_to'); 1399 1400 var moment_from = $datepicker_from.val(); 1401 var moment_to = $datepicker_to.val(); 1402 1403 var internal_date_format = 'D MMM YYYY HH:mm'; 1404 1405 var moment_today_midnight = moment().utcOffset(cp.default_utc_offset).startOf('day'); 1406 1407 if(moment_from) 1408 { 1409 moment_from = moment(new Date(moment_from*1000)).utcOffset(cp.default_utc_offset); 1410 } 1411 else 1412 { 1413 moment_from = moment_today_midnight; 1414 } 1415 1416 if(moment_to) 1417 { 1418 moment_to = moment(new Date(moment_to*1000)).utcOffset(cp.default_utc_offset); 1419 } 1420 else 1421 { 1422 moment_to = moment().utcOffset(cp.default_utc_offset).endOf('day'); 1423 } 1424 1425 var ranges = []; 1426 var label_lookup = []; 1427 for(var key in preset_ranges) 1428 { 1429 // convert unix timestampts to moment instances 1430 ranges[preset_ranges[key]['name']] = [ 1431 moment(new Date(preset_ranges[key]['from']*1000)), 1432 moment(new Date(preset_ranges[key]['to']*1000)), 1433 ]; 1434 1435 label_lookup[preset_ranges[key]['name']] = key; 1436 } 1437 1438 var config = { 1439 autoApply: true, // does nothing in time picker mode 1440 alwaysShowCalendars: true, 1441 startDate: moment_from.format(internal_date_format), 1442 endDate: moment_to.format(internal_date_format), 1443 // maxDate: '11/25/2021', 1444 opens: 'center', 1445 drops: 'down', 1446 buttonClasses: 'none', 1447 applyButtonClasses: 'none', 1448 cancelClass: 'none', 1449 ranges: ranges, 1450 locale: { 1451 format: internal_date_format, 1452 separator: date_range_divider, 1453 applyLabel: 'Ok', 1454 cancelLabel: 'Cancel', 1455 fromLabel: 'From', 1456 toLabel: 'To', 1457 customRangeLabel: 'Custom', 1458 weekLabel: 'W', 1459 firstDay: 1, 1460 daysOfWeek: ['Su','Mo','Tu','We','Th','Fr','Sa'], 1461 monthNames: [ 1462 'January', 1463 'February', 1464 'March', 1465 'April', 1466 'May', 1467 'June', 1468 'July', 1469 'August', 1470 'September', 1471 'October', 1472 'November', 1473 'December' 1474 ] 1475 } 1476 }; 1477 1478 if(include_time === true) 1479 { 1480 config.timePicker = true; 1481 config.showDropdowns = true; 1482 config.timePicker24Hour = true; 1483 } 1484 1485 $datepicker_btn.daterangepicker(config, function(start, end, label) { 1486 1487 // TODO: Asses if we do actually need utcOffset here, removed for now as it doesn't work correctly during BST 1488 1489 var moment_from = moment(start, internal_date_format)/*.utcOffset(cp.default_utc_offset)*/; 1490 if(include_time !== true) 1491 { 1492 moment_from.startOf('day'); 1493 } 1494 1495 var moment_to = moment(end, internal_date_format)/*.utcOffset(cp.default_utc_offset)*/; 1496 if(include_time !== true) 1497 { 1498 moment_to.endOf("day"); 1499 } 1500 else if(moment_to.format('m') === '59') 1501 { 1502 // when the 59th minute selected, also set seconds to 59 1503 moment_to.endOf("minute"); 1504 } 1505 1506 if(label == 'Custom') 1507 { 1508 label = 1509 moment(start, internal_date_format)/*.utcOffset(cp.default_utc_offset)*/.format(date_format) 1510 + date_range_divider 1511 + moment(end, internal_date_format)/*.utcOffset(cp.default_utc_offset)*/.format(date_format) 1512 ; 1513 } 1514 else if(label == 'Last 24 hours') 1515 { 1516 // set here so that minutes are dynamic 1517 moment_from = moment()/*.utcOffset(cp.default_utc_offset)*/.subtract(1, 'days'); 1518 moment_to = moment()/*.utcOffset(cp.default_utc_offset)*/; 1519 1520 $datepicker_btn.data('daterangepicker').setStartDate(moment_from.format(internal_date_format)); 1521 $datepicker_btn.data('daterangepicker').setEndDate(moment_to.format(internal_date_format)); 1522 } 1523 else if(label == 'Last hour') 1524 { 1525 // set here so that minutes are dynamic 1526 moment_from = moment()/*.utcOffset(cp.default_utc_offset)*/.subtract(1, 'hours'); 1527 moment_to = moment()/*.utcOffset(cp.default_utc_offset)*/; 1528 1529 $datepicker_btn.data('daterangepicker').setStartDate(moment_from.format(internal_date_format)); 1530 $datepicker_btn.data('daterangepicker').setEndDate(moment_to.format(internal_date_format)); 1531 } 1532 1533 $datepicker_btn.find('p').html(label); 1534 1535 var val_from = moment_from.format('X'); 1536 $datepicker_from.val(val_from); 1537 1538 var val_to = moment_to.format('X'); 1539 $datepicker_to.val(val_to); 1540 1541 var val_summary = ''; 1542 1543 if(label != 'Custom' && label_lookup.hasOwnProperty(label)) 1544 { 1545 val_summary = label_lookup[label]; 1546 } 1547 else 1548 { 1549 val_summary = moment_from.format('DD-MM-YYYY-HH:mm:ss') + ',' + moment_to.format('DD-MM-YYYY-HH:mm:ss'); 1550 } 1551 1552 $datepicker_summary.val(val_summary); 1553 // Do this last as other items will likely bind their events to 1554 // the summary field as it uses the un-suffixed field ID 1555 $datepicker_summary[0].dispatchEvent(new Event('change'));
1556 }) 1557 .on('show.daterangepicker', function(ev, picker) { 1558 if(include_time === true) 1559 { 1560 picker.container[0].classList.add('CPFormFieldDateTimeRange'); 1561 } 1562 else 1563 { 1564 picker.container[0].classList.add('CPFormFieldDateRange'); 1565 } 1566 $datepicker_btn.addClass('open'); 1567 }) 1568 .on('hide.daterangepicker', function(ev, picker) { 1569 $datepicker_btn.removeClass('open'); 1570 }) 1571 ; 1572 1573 var daterangepicker_instance = $datepicker_btn.data('daterangepicker'); 1574 daterangepicker_instance.clear_date_range = function(){ cp_date_range_clear(this, $datepicker_btn); }; 1575} 1576 1577function cp_date_range_clear(daterangepicker, $datepicker_btn) { 1578 1579 $datepicker_btn.find('p').html($datepicker_btn.data('default-label')); 1580 daterangepicker.setStartDate(moment().startOf('day')); 1581 daterangepicker.setEndDate(moment().endOf('day')); 1582 1583 var elm_id = $datepicker_btn.data('base-id'); 1584 1585 $('#'+elm_id).changeVal(''); 1586 $('#'+elm_id+'_from').changeVal(''); 1587 $('#'+elm_id+'_to').changeVal(''); 1588 1589}
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.