1// initialize variables 2var gQuestionIndex = 0; 3var gQuestionnaireIndex = 0; 4var atLeastOneOrderQuestion = false; 5var atLeastOneAttendeeQuestion = false; 6var atLeastOneTicketTypeQuestion = false; 7 8//let's set request data to an empty array if it's undefined - saves on undefined checks later on to avoid javascript errors 9if (typeof gRequestData == 'undefined') { 10 gRequestData = []; 11} 12 13if(typeof tsTheme == 'undefined') { 14 tsTheme = 'Classic'; 15} 16var questionElementStart = '<span class="question-text">'; 17var questionElementEnd = '</span>'; 18var questionTextBoxClass = 'form-control'; 19var questionTextAreaClass = 'form-control'; 20var questionTicketTypePriceNameStart = '<strong>'; 21var questionTicketTypePriceNameEnd = '</strong><br>'; 22 23// DOCUMENT READY 24$(document).ready(function() { 25 26 if (typeof gManuallyWriteOrderQuestionnaire == 'undefined' && typeof gOrderQuestionnaires != 'undefined') { 27 writeQuestionnaires(gOrderQuestionnaires, '#orderQuestionnaire', 'questionnaire-order', null, null, null, null, null); 28 } 29 30}); 31 32 33// uses variables generated via PHP: 34// gAttendeeQuestionnaires - jsonData of the attendee questionnaire(s) 35 36 37// when a required checkbox is changed, this checks it's siblings 38// and either removes the required attribute from all (if at least one is checked), or adds it to them all if none are
39function questionnaireCheckboxChanged(e) { 40 var atLeastOneChecked = false; 41 var checkboxesToVerify = $(e).closest('.required-checkboxes').find(':checkbox'); 42 43 if($(e).is(':checked')) { 44 atLeastOneChecked = true; 45 } else { 46 checkboxesToVerify.each(function() { 47 if($(this).is(':checked')) { 48 atLeastOneChecked = true; 49 } 50 }); 51 } 52 53 checkboxesToVerify.each(function() { 54 if(atLeastOneChecked) { 55 $(this).removeAttr('required'); 56 } else { 57 $(this).attr('required', 'required'); 58 } 59 }); 60 61 62} 63 64 65/** 66 * Update Questionnaires(usually called when updating the order summary / calculating total..etc) 67 * shows/hides questions that are ticket-type specific 68 * adds/removes per-attendee questions when quantities are increased/decreased 69 */ 70function updateQuestionnaires() { 71 isFrame = window.parent !== window; 72 var quantitiesData = getTicketTypeQuantities(); 73 writeOrDeleteAttendeeQuestionnaires(quantitiesData); 74 hasOrderQuestion(); 75 hasTicketTypeTiedQuestions(quantitiesData); 76 hasAttendeeQuestion(); 77 78 if (!isFrame) { 79 if (atLeastOneOrderQuestion || atLeastOneTicketTypeQuestion) { 80 $('#orderQuestionnaire').slideDown('fast'); 81 } else { 82 $('#orderQuestionnaire').slideUp('fast'); 83 } 84 85 if (atLeastOneAttendeeQuestion) { 86 $('#attendee-questionnaires-area').slideDown('fast'); 87 } else { 88 $('#attendee-questionnaires-area').slideUp('fast'); 89 } 90 } 91} 92 93function hasOrderQuestion() { 94 if ($('.questionnaire-order .question').not('.tied-to-ticket-type').not('.tied-to-question-response').length > 0) { 95 atLeastOneOrderQuestion = true; 96 return true; 97 } else { 98 atLeastOneOrderQuestion = false; 99 return false; 100 } 101} 102 103function hasAttendeeQuestion() { 104 if($('#attendee-questionnaires .questionnaire').length) { 105 atLeastOneAttendeeQuestion = true; 106 return true; 107 } else { 108 atLeastOneAttendeeQuestion = false; 109 return false; 110 } 111} 112 113 114 115// gets objects with id:quantity for both ticket types and ticket type prices 116function getTicketTypeQuantities() { 117 118 var ticketTypeId; 119 var ticketTypePriceId; 120 var ticketsPer; 121 var quantity; 122 var questions; 123 var ticketTypesData = {}; 124 125 $('[id$="Quantity"]').each(function() { 126 ticketTypeId = $(this).attr('data-ticket-type-id'); 127 //for tickets from activity pages, you have to look elsewhere for this info 128 if (typeof ticketTypeId == 'undefined') { 129 ticketTypeId = $(this).siblings('[id$="TicketTypeId"]').val(); 130 } 131 ticketTypePriceId = $(this).attr('data-ticket-type-price-id'); 132 //for tickets from activity pages, you have to look elsewhere for this info 133 if (typeof ticketTypePriceId == 'undefined') { 134 ticketTypePriceId = $(this).siblings('[id$="TicketTypePriceId"]').val(); 135 } 136 ticketsPer = $(this).attr('data-tickets-per'); 137 row = $(this).attr('name').match(/\d+/); 138 ticketTypePriceName = $('[name="data[Ticket]['+row+'][ticket_type_name]"]').val(); 139 140 quantity = $(this).val(); 141 if(quantity == '') { 142 quantity = 0; 143 } 144 145 if(ticketTypesData[ticketTypeId] == undefined) { 146 ticketTypesData[ticketTypeId] = {'quantity':0}; 147 } 148 if(ticketTypesData[ticketTypeId][ticketTypePriceId] == undefined) { 149 ticketTypesData[ticketTypeId][ticketTypePriceId] = {'quantity':0, 'ticketsPer':1, 'ticketTypePriceName':ticketTypePriceName}; 150 } 151 if(ticketsPer == undefined) { 152 ticketsPer = 1; 153 } 154 155 ticketTypesData[ticketTypeId]['quantity'] += parseInt(quantity)*parseInt(ticketsPer); 156 ticketTypesData[ticketTypeId][ticketTypePriceId]['quantity'] += parseInt(quantity)*parseInt(ticketsPer); 157 }); 158 return ticketTypesData; 159} 160 161 162 163 164// writes or deletes attendee questionnaires based on provided {id:quantity, ... object 165function writeOrDeleteAttendeeQuestionnaires(quantitiesData) { 166 167 var existing; 168 169 $.each(quantitiesData, function(ticketTypeId, ticketTypeData) { 170 171 $.each(ticketTypeData, function(ticketTypePriceId, ticketTypePriceData) { 172 173 if (typeof ticketTypePriceData === 'object' && typeof ticketTypePriceData !== null) { 174 175 existing = 0; 176 177 // repeats through existing questionnaires for this ticket type price and delete if over quantity 178 $('.questionnaire-attendee[data-ticket-type-price-id="' + ticketTypePriceId + '"]').each(function() { 179 existing++; 180 if ($(this).attr('data-ticket-type-price-key') >= ticketTypePriceData['quantity']) { 181 $(this).remove(); 182 } 183 }); 184 185 // if(ticketTypePriceData['quantity'] > 0) { 186 // } 187
188 for(i=existing; i<ticketTypePriceData['quantity']; i++) { 189 writeQuestionnaires(gAttendeeQuestionnaires, '#attendee-questionnaires', 'questionnaire-attendee', ticketTypePriceData['ticketTypePriceName'], ticketTypeId, ticketTypePriceId, i, null); 190 } 191 } 192 }); 193 194 }); 195} 196 197 198 199 200// repeat through every question that's tied to a specific ticket type and show or hide it based on at least one quantity 201// NOTE: only used for order questionnaires, since attendee questionnaires just won't write the question in the first place 202function hasTicketTypeTiedQuestions(quantitiesData) { 203 204 //repeat through each order-questionnaire 205 var showAtLeastOne = false; 206 $('.questionnaire-order .question.tied-to-ticket-type').each(function() { 207 ticketTypeIds = $(this).attr('data-ticket-type-id').split(','); 208 showMe = false; 209 ticketTypeIds.forEach(function(e){ 210 if (typeof quantitiesData[e] !== 'undefined' && quantitiesData[e]['quantity'] > 0) { 211 showMe = true; 212 showAtLeastOne = true; 213 } 214 }); 215 216 // show the question if it's questionnaire 217 if (showMe) { // 218 $(this).slideDown('fast').find('[disabled]').removeAttr('disabled'); 219 } else { 220 $(this).slideUp('fast').find('input').attr('disabled', 'disabled'); 221 222 //find out if there were follow up questions and also hide them 223 nextDiv = $(this).next('div'); 224 while (nextDiv.hasClass('tied-to-question-response')) { 225 nextDiv.slideUp('fast').find('input').attr('disabled', 'disabled'); 226 nextDiv = nextDiv.next('div'); 227 } 228 } 229 }); 230 231 if (showAtLeastOne) { 232 atLeastOneTicketTypeQuestion = true; 233 return true; 234 } else { 235 atLeastOneTicketTypeQuestion = false; 236 return false; 237 } 238} 239 240 241 242// Write Questionnaires 243//note: ticketTypeId can be either a string (single id) or an array (multi ids passed with an order specific edit page) 244function writeQuestionnaires(questionnaires, intoElementSelector, questionnaire
244Class, ticketTypePriceName, ticketTypeId, ticketTypePriceId, ticketTypePriceKey, ticketId) { 245 246 if(ticketTypePriceKey == null) { 247 ticketTypePriceKey = 0; 248 } 249 250 if (typeof gRequestData != []) { 251 var hasAnswers = true; 252 } else { 253 var hasAnswers = false; 254 } 255 256 var html = ''; 257 258 // open the wrapper element 259 html += '<div class="questionnaire content ' + questionnaireClass + '"'; 260 261 if(ticketTypeId !== null && !Array.isArray(ticketTypeId)) { 262 html += ' data-ticket-type-id="' + ticketTypeId + '"'; 263 } 264 if(ticketTypePriceId !== null) { 265 html += ' data-ticket-type-price-id="' + ticketTypePriceId + '"'; 266 } 267 if(ticketTypePriceKey !== null) { 268 html += ' data-ticket-type-price-key="' + ticketTypePriceKey + '"'; 269 } 270 html += '>'; 271 272 if(ticketTypePriceName !== null) { 273 html += questionTicketTypePriceNameStart + ticketTypePriceName + ' #' + parseInt(ticketTypePriceKey+1) + questionTicketTypePriceNameEnd; 274 } 275 276 var atLeastOneQuestionWritten = false; 277 var answerNumber = 0; 278 if (typeof ticketId != 'undefined' && ticketId != null) { 279 var tId = ticketId; 280 } else { 281 var tId = '' 282 } 283 $.each(questionnaires, function(i, questionnaire) { 284 var questionnaireIndex = gQuestionnaireIndex; 285 $.each(questionnaire['Question'], function(i, question) { 286 var questionHtml = writeQuestion(question, questionnaire['Questionnaire']['event_id'], ticketTypeId, ticketTypePriceId, questionnaireIndex, tId); 287 if (questionHtml != '') { 288 atLeastOneQuestionWritten = true; 289 html += questionHtml; 290 answerNumber++; 291 } 292 }); 293 gQuestionnaireIndex++; 294 }); 295 296 // close out the wrapper element 297 html += '</div>'; 298 299 if (atLeastOneQuestionWritten) { 300 $(intoElementSelector).append(html); 301 302 // add any callbacks 303 $('.has-follow').on("change", function() { 304 305 // for radio buttons, the 'change' is only triggered on the one selected, not on one that was just automatically unselected by clicking a different one 306 if ($(this).prop('type') == 'radio') { 307 $(this).closest('ul.radio-buttons').find('input').each(function() { 308 checkForFollowUpQuestion(this); 309 }); 310 311 } else if ($(this).prop('type') == 'select-one') { 312 $(this).children('option').each(function() { 313 checkForFollowUpQuestion(this); 314 }); 315 316 } else { 317 checkForFollowUpQuestion(this); 318 } 319 }); 320 } 321} 322 323 324 325 326// Write Question 327// question = question json data 328// eventId = event id 329// selectedTicketTypeId = the type of ticket this question is being written for (used in attendee-specific questionnaires), 330// OR an array of ticket type ids in an order, to know whether to render ticket type specific questions on order questionnaires 331function writeQuestion(question, eventId, selectedTicketTypeId, ticketTypePriceId, questionnaireIndex, ticketId) { 332 //somehow it's getting here with an undefined question occasionally 333 if (typeof question == 'undefined') { 334 return false; 335 } 336 337 //search any gRequestData to see if this question has an answer 338 var hasAnswer = false; 339 var answerItem = []; 340 if (typeof gRequestData['QuestionResponse'] != 'undefined') { 341 $.each(gRequestData['QuestionResponse'], function(idx, value) { 342 if (value['question_id'] == question['id']) { 343 //found an answer, narrow down by ticket id if appropriate 344 if (ticketId != '') { 345 if (value['ticket_id'] != ticketId) { 346 return true; //this is the equivalent of a continue statement in php 347 } 348 } 349 answerItem = value; 350 hasAnswer = true; 351 return false; //this is the equivalent of a break statement in php 352 } 353 }); 354 } 355 356 var html = ''; 357 var disabled = ''; 358 switch (question['response_type']) { 359 case "3": 360 case "4": 361 case "6": 362 var requiredClass = (question['required']) ? 'question_required ' : ''; 363 if (typeof questionnaireNotRequired != 'undefined' && questionnaireNotRequired == true) { 364 requiredClass = ''; 365 } 366 break; 367 default: 368 var requiredClass = (question['required']) ? 'question_required_text ' : ''; 369 if (typeof questionnaireNotRequired != 'undefined' && questionnaireNotRequired == true) { 370 requiredClass = ''; 371 } 372 break; 373 } 374 375 // if the question isn't being written for a specific ticket type 376 // or if it is, but matches the questionnaire's ticket type id, continue to write the question 377 378 //first, find out if the ticket type matches - it's buried in the array 379 foundTTID = false;
380 if (typeof question['QuestionsTicketType'] != 'undefined') { 381 for (x=0; x < question['QuestionsTicketType'].length; x++) { 382 if (Array.isArray(selectedTicketTypeId) && selectedTicketTypeId.includes(question['QuestionsTicketType'][x]['ticket_type_id'])) { 383 foundTTID = true; 384 } else if (question['QuestionsTicketType'][x]['ticket_type_id'] === selectedTicketTypeId) { 385 foundTTID = true; 386 } 387 } 388 } 389 if(selectedTicketTypeId == null 390 || foundTTID //matches ticket type 391 || (typeof question['QuestionsTicketType'] != 'undefined' && question['QuestionsTicketType'].length === 0) 392 || typeof question['QuestionsTicketType'] == 'undefined') { //not limited to a ticket type 393 394 var types = { 1: 'text', 2: 'textarea', 3: 'checkboxes', 4:'radiobuttons', 5:'select', 6:'waiver' }; 395 396 html += '<div class="' + requiredClass + 'question question-' + gQuestionIndex + ' question-type-' + types[question['response_type']]; 397 398 // follow-up question or tied to a specific ticket type 399 if(question['question_option_id'] || question['QuestionsTicketType']?.length > 0) { 400 401 // is a follow-up question 402 if(question['question_option_id']) { 403 html += ' tied-to-question-response" data-question-option-id="' + question['question_option_id'] + '"'; 404 disabled = ' disabled="disabled"'; 405 406 // is tied to a specific ticket-type 407 } else if (question['QuestionsTicketType']?.length > 0) { 408 // if it's an order questionnaire (ie wasn't in response to the selection of a ticket / attendee questionnaire) 409 // for attendee questionnaires, we don't need to trigger that this QUESTION is tied specifically to a type, since the whole thing is tied 410 if(selectedTicketTypeId == null) { 411 html += ' tied-to-ticket-type"'; 412 disabled = ' disabled="disabled"'; 413 } 414 415 //need to build a delimited string of all the associated ticket type ids 416 ticketTypeString = ''; 417 question['QuestionsTicketType'].forEach(function(e){ 418 ticketTypeString += e['ticket_type_id'] + ','; 419 }); 420 ticketTypeString = ticketTypeString.slice(0, -1); 421 422 //then use it as the ticket type id data point 423 html += ' data-ticket-type-id="' + ticketTypeString + '"'; 424 } 425 html += 'style="display:none;"'; 426 } 427 //Add specific ID to support alert if a required checkbox is not filled out 428 if (types[question['response_type']] == 'waiver'){ 429 html += '" id="QuestionResponseDiv' + gQuestionIndex + 'QuestionOptionText'; 430 } 431 html += '">'; 432 433 var required = (question['required']) ? ' required="required"' : ''; 434 if (typeof questionnaireNotRequired != 'undefined' && questionnaireNotRequired == true) { 435 required = ''; 436 } 437 438 //type specific fields 439 if (selectedTicketTypeId) { 440 html += '<input type="hidden" id="QuestionResponse' + gQuestionIndex + 'TicketTypeId" name="data[QuestionResponse][' + gQuestionIndex + '][ticket_type_id]" value="' + selectedTicketTypeId + '">'; 441 html += '<input type="hidden" id="QuestionResponse' + gQuestionIndex + 'TicketTypePriceId" name="data[QuestionResponse][' + gQuestionIndex + '][ticket_type_price_id]" value="' + ticketTypePriceId + '">'; 442 } 443 if (ticketId) { 444 html += '<input type="hidden" id="QuestionResponse' + gQuestionIndex + 'TicketId" name="data[QuestionResponse][' + gQuestionIndex + '][ticket_id]" value="' + ticketId + '">'; 445 } 446 html += '<input type="hidden" id="QuestionResponse' + gQuestionIndex + 'QuestionnaireIndex" name="data[QuestionResponse][' + gQuestionIndex + '][questionnaire_index]" value="' + questionnaireIndex + '">'; 447 html += '<input type="hidden" id="QuestionResponse' + gQuestionIndex + 'EventId" name="data[QuestionResponse][' + gQuestionIndex + '][event_id]" value="' + eventId + '">'; 448 html += '<input type="hidden" id="QuestionResponse' + gQuestionIndex + 'QuestionId" name="data[QuestionResponse][' + gQuestionIndex + '][question_id]" value="' + question['id'] + '">'; 449 html += '<input type="hidden" id="QuestionResponse' + gQuestionIndex + 'QuestionText" name="data[QuestionResponse][' + gQuestionIndex + '][question_text]" value="' + question['question_text'] + '">'; 450 html += '<input type="hidden" id="QuestionResponse' + gQuestionIndex + 'QuestionnaireId" name="data[QuestionResponse][' + gQuestionIndex + '][questionnaire_id]" value="' + question['questionnaire_id'] + '">'; 451 html += '<input type="hidden" id="QuestionResponse' + gQuestionIndex + 'ResponseType" name="data[QuestionResponse][' + gQuestionIndex + '][response_type]" value="' + question['response_type'] + '">'; 452 453 var attendeeName = question['attendee_name'] ? 1 : 0; 454 var attendeeEmail = question['attendee_email'] ? 1 : 0; 455 html += '<input type="hidden" id="QuestionResponse' + gQuestionIndex + 'AttendeeName" name="data[QuestionResponse][' + gQuestionIndex + '][attendee_name]" value="' + attendeeName + '">'; 456 html += '<input type="hidden" id="QuestionResponse' + gQuestionIndex + 'AttendeeEmail" name="data[QuestionResponse][' + gQuestionIndex + '][attendee_email]" value="' + attendeeEmail + '">'; 457 458 if (hasAnswer) { 459 answerNumber = 0; 460 //retrieve the id (or could be multiple ids if this is a checkbox) 461 if (typeof answerItem['id'] == 'undefined') { 462 //this answer's actual data is in a further array - potentially multiple answers 463 var idArray = {}; 464 var idString = ''; 465 $.each(answerItem['question_option_id'], function(x, innerValue){ 466 if (typeof innerValue['id'] == 'undefined') { 467 if (x == 'id') { 468 idArray['id'] = innerValue; 469 } else { 470 idArray['option_id'] = innerValue; 471 } 472 } else { 473 idArray[x] = {}; 474 idArray[x]['id'] = innerValue['id']; 475 idArray[x]['option_id'] = innerValue['option_id']; 476 } 477 }); 478 //now convert to JSON 479 idString = encodeURIComponent(JSON.stringify(idArray)); 480 } else { 481 //this answer's data is available right here 482 var idString = answerItem['id']; 483 } 484 html += '<input type="hidden" id="QuestionResponse' + gQuestionIndex + 'Id" name="data[QuestionResponse][' + gQuestionIndex + '][id]" value="' + idString + '">'; 485 } 486 487 switch (question['response_type']) { 488 489 case '1': // Text 490 var value = ''; 491 if (hasAnswer) { 492 answerStr = answerItem['question_option_text']; 493 var value = answerStr.replace(/["]/g, '"'); 494 } 495 html += questionElementStart + question['question_text'] + questionElementEnd; 496 html += '<input type="' + (attendeeEmail == 1 ? 'email' : 'text') + '" id="QuestionResponse' + gQuestionIndex + 'QuestionOptionText" name="data[QuestionResponse][' + gQuestionIndex + '][question_option_text]" value="' + value + '" class="' + questionTextBoxClass + '"' + required + disabled + '>'; 497 break; 498
499 case '2': // Textarea 500 var value = ''; 501 if (hasAnswer) { 502 answerStr = answerItem['question_option_text']; 503 var value = answerStr.replace(/["]/g, '"'); 504 } 505 html += questionElementStart + question['question_text'] + questionElementEnd; 506 html += '<textarea id="QuestionResponse' + gQuestionIndex + 'QuestionOptionText" name="data[QuestionResponse][' + gQuestionIndex + '][question_option_text]" cols="30" rows="6" class="' + questionTextAreaClass + '"' + required + disabled + '>' + value + '</textarea>'; 507 break; 508 509 case '6': // Waiver 510 var value = ''; 511 if (hasAnswer) { 512 var value = answerItem['question_option_text'] 513 } 514 if (required){ 515 required += ' oninvalid="checkbox_alert(this, this.parentNode.id)"'; 516 } 517 if (question['required'] && tsTheme == 'Classic' && (typeof questionnaireNotRequired == 'undefined' || questionnaireNotRequired != true)) { 518 html += '<div class="checkbox-required" id="QuestionResponseDiv' + gQuestionIndex + 'QuestionOptionText">'; 519 } 520 html += '<label>'; 521 if (value != '') { 522 html += '<input type="checkbox" id="QuestionResponse' + gQuestionIndex + 'QuestionOptionText" name="data[QuestionResponse][' + gQuestionIndex + '][question_option_text]" checked="checked"' + required + disabled + ' class="mr-2">'; 523 } else { 524 html += '<input type="checkbox" id="QuestionResponse' + gQuestionIndex + 'QuestionOptionText" name="data[QuestionResponse][' + gQuestionIndex + '][question_option_text]"' + required + disabled + ' class="mr-2">'; 525 } 526 html += '<span class="question-text" for="QuestionResponse' + gQuestionIndex + 'QuestionOptionId">' + question['question_text'] + '</span>'; 527 528 html += '</label>'; 529 if (typeof question['QuestionOption'][0] != 'undefined') { 530 html += '<div style="font-weight:normal;max-height:150px;overflow:auto;padding-left:20px;">' + question['QuestionOption'][0]['response_text'] + '</div>'; 531 } 532 if (question['required'] && tsTheme == 'Classic' && (typeof questionnaireNotRequired == 'undefined' || questionnaireNotRequired != true)) { 533 html += '</div>'; 534 } 535 break; 536 537 case '3': // Checkboxes 538 case '4': // Radio Buttons 539 case '5': // Dropdown 540 var value = ''; 541 if (hasAnswer) { 542 var value = answerItem['question_option_id'] 543 } 544 html += writeQuestionOptions(question, required, disabled, hasAnswer, value); 545 break; 546 547 } 548 549 html += '</div><!-- close question -->'; 550 gQuestionIndex++; 551 552 // writes any follow-up questions if needed 553 if (question['has_follow'] == true) { 554 $.each(question['QuestionOption'], function(i, option) { 555 if (option['FollowUpQuestion'] && jQuery.isEmptyObject(option['FollowUpQuestion']) == false) { 556 html += writeQuestion(option['FollowUpQuestion'][0], eventId, selectedTicketTypeId, ticketTypePriceId, questionnaireIndex, ticketId); 557 } 558 }); 559 } 560 } 561 562 return html; 563} 564 565 566 567// Write Question Options 568function writeQuestionOptions(question, required, disabled, hasAnswer, value) { 569 570 var optionIndex = 0; 571 var html = ''; 572 var onChangeText = ''; 573 var optionClass = 'no-follow'; 574 575 if (question['has_follow']) { 576 optionClass = 'has-follow'; 577 } 578 579 var requiredScrollIntoViewOnInvalid = ''; 580 if (required) { 581 requiredScrollIntoViewOnInvalid = ' oninvalid="this.scrollIntoView({behavior: \'smooth\', block: \'center\'});"'; 582 } 583 584 switch(question['response_type']) { 585 586 // Checkbox ******************* 587 case '3': 588 html += '<span class="question-text">' + question['question_text'] + '</span>'; 589 html += '<ul class="checkboxes'; 590 if(required) { 591 html += ' required-checkboxes'; 592 } 593 html += '">'; 594 $.each(question['QuestionOption'], function(i, option) { 595 596 //check if max selected - get settings based on sel_quantity 597 var optionSettings = checkSelectedQuantity(option, disabled); 598 599 var checked = ''; 600 //the value might be an array containing a single id-value pair or an array of multiple id-value pairs 601 if (typeof value['id'] == 'undefined') { 602 $.each(value, function(j, val){ 603 if (hasAnswer && val['option_id'] == option['id']) { 604 checked = ' checked="checked" '; 605 } 606 }); 607 } else { 608 if (hasAnswer && value['option_id'] == option['id']) { 609 var checked = ' checked="checked" '; 610 } 611 } 612 613 html += '<li' + optionSettings['additionalAttributes'] + '><label>'; 614 html += '<input type="checkbox" name="data[QuestionResponse][' + gQuestionIndex + '][question_option_id][]" value="' + optionSettings['quantity'] + '" class="' + optionClass + '"' + checked + required + optionSettings['disabled'] + ' onchange="questionnaire
614CheckboxChanged(this);"' + requiredScrollIntoViewOnInvalid + '>' + option['response_text'] + optionSettings['nameAddon']; 615 html += '</label></li>'; 616 }); 617 html += '</ul>'; 618 break; 619 620 621 // Radio ******************* 622 case '4': 623 html += '<span class="question-text">' + question['question_text'] + '</span>'; 624 html += '<ul class="radio-buttons'; 625 if(required) { 626 html += ' required-radio-buttons'; 627 } 628 html += '">'; 629 $.each(question['QuestionOption'], function(i, option) { 630 631 //check if max selected - get settings based on sel_quantity 632 var optionSettings = checkSelectedQuantity(option, disabled); 633 634 var checked = ''; 635 if (hasAnswer && value['option_id'] == option['id']) { 636 var checked = ' checked="checked" '; 637 } 638 639 html += '<li' + optionSettings['additionalAttributes'] + '><label>'; 640 html += '<input type="radio" name="data[QuestionResponse][' + gQuestionIndex + '][question_option_id]" value="' + optionSettings['quantity'] + '" class="' + optionClass + '"' + checked + required + optionSettings['disabled'] + requiredScrollIntoViewOnInvalid + '>' + option['response_text'] + optionSettings['nameAddon']; 641 html += '</label></li>'; 642 }); 643 html += '</ul>'; 644 break; 645 646 647 // Dropdown ******************** 648 case '5': 649 html += '<span class="question-text">' + question['question_text'] + '</span>'; 650 html += '<select id="QuestionResponse' + gQuestionIndex + 'QuestionOptionId" name="data[QuestionResponse][' + gQuestionIndex + '][question_option_id]" class="form-control ' + optionClass + '"' + required + disabled + requiredScrollIntoViewOnInvalid + '>'; 651 html += '<option value="">Select One</option>'; 652 $.each(question['QuestionOption'], function(i, option) { 653 654 //check if max selected - get settings based on sel_quantity 655 var optionSettings = checkSelectedQuantity(option, disabled); 656 657 var checked = ''; 658 if (hasAnswer && value['option_id'] == option['id']) { 659 var checked = ' selected="selected" '; 660 } 661 662 html += '<option ' + checked + ' value="' + optionSettings['quantity'] + '"' + optionSettings['disabled'] + optionSettings['additionalAttributes'] + '>' + option['response_text'] + optionSettings['nameAddon'] + '</option>'; 663 optionIndex++; 664 }); 665 html += '</select>'; 666 break; 667 } 668 669 return html; 670} 671 672 673// run when questions with follow-ups have their values changed 674// determines whether to show or hide any follow-ups 675function checkForFollowUpQuestion(object) { 676 var questionOptionId = $(object).val(); 677 var showFollowUp = false; 678 679 // gets the 'type' of input (or it's nodeName if it's an 'option') 680 var objectType = $(object).prop('type'); 681 if (objectType == undefined) { 682 objectType = $(object).prop('nodeName'); 683 } 684 685 //checks if it the calling element is selected 686 switch (objectType) { 687 688 case 'checkbox': 689 case 'radio': 690 showFollowUp = $(object).prop('checked'); 691 break; 692 693 case 'OPTION': 694 showFollowUp = $(object).prop('selected'); 695 break; 696 } 697 698 if (showFollowUp) { 699 $(object).closest('.questionnaire').find('.tied-to-question-response[data-question-option-id="' + questionOptionId + '"]').slideDown('fast').find('input, select, textarea, option').removeAttr('disabled'); 700 } else { 701 $(object).closest('.questionnaire').find('.tied-to-question-response[data-question-option-id="' + questionOptionId + '"]').slide
701Up('fast').find('input, select, textarea, option').attr('disabled', 'disabled'); 702 } 703 704} 705 706/** 707 * [checkSelectedQuantity description] 708 * @param {[type]} option [the complete array for the option that is to be checked for max limit] 709 * @return {[type]} ['option id', 'disabled status', 'additional style setting', 'additional option text'] 710 */ 711function checkSelectedQuantity(option, disabled) { 712 713 var toReturn = { 714 'quantity': option['id'], 715 'disabled': '', 716 'additionalAttributes': '', 717 'nameAddon': '' 718 }; 719 720 if(disabled == ' disabled="disabled"') { 721 toReturn['disabled'] = disabled; 722 } 723 724 //check if it has a max limit set 725 if(option['max_quantity']){ 726 if(option['sel_quantity'] >= option['max_quantity']){ 727 var toReturn = { 728 'quantity': '0', 729 'disabled': ' disabled="disabled"', 730 'additionalAttributes': ' style="color:#ccc;"', 731 'nameAddon': '(not available)' 732 }; 733 } 734 } 735 736 return toReturn; 737}
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.