SurveyVista/Web/Views/QuestionnaireResponse/DisplayQuestionnaire.cshtml

1034 lines
No EOL
46 KiB
Text

@model ResponseQuestionnaireViewModel
@{
ViewData["Title"] = "DisplayQuestionnaire";
Layout = "~/Views/Shared/_QuestionnaireResponse.cshtml";
}
<style>
body {
height: 100% !important;
background-color: #141c27 !important;
}
#rowSectionError {
display: flex;
flex-wrap: nowrap;
justify-content: space-around;
align-items: center;
align-content: center;
width: 100%;
flex-direction: row;
}
output {
color: white !important;
font-weight: bold;
}
#boxBanner {
display: block;
width: auto;
margin: 5px;
}
.QuestionContainer {
padding-top: 50px;
padding-bottom: 100px;
}
.stepper {
display: flex;
flex-direction: column;
align-items: center;
}
.step-indicator {
width: 150px;
height: 30px;
border-radius: 3px;
background-color: transparent;
margin-bottom: 10px;
display: flex;
justify-content: center;
align-items: center;
color: white; /* Text color */
font-weight: bold;
border: 0.05px solid #294255;
box-shadow: 0px 0px 6px 2px rgba(0,0,0,0.18);
-webkit-box-shadow: 0px 0px 6px 2px rgba(0,0,0,0.18);
-moz-box-shadow: 0px 0px 6px 2px rgba(0,0,0,0.18);
}
.step-indicator.active {
background-color: #33b3ae; /* Primary color for active step */
box-shadow: 0px 0px 21px -4px rgba(0,0,0,0.45);
-webkit-box-shadow: 0px 0px 21px -4px rgba(0,0,0,0.45);
-moz-box-shadow: 0px 0px 21px -4px rgba(0,0,0,0.45);
}
h4, h5, h6, p, label {
color: aliceblue;
}
.card {
box-shadow: 0px 0px 36px -12px rgba(20,101,230,1);
-webkit-box-shadow: 0px 0px 36px -12px rgba(20,101,230,1);
-moz-box-shadow: 0px 0px 36px -12px rgba(20,101,230,1);
border-radius: 10px;
background-color: transparent;
padding: 50px;
}
.form-control {
width: 80%;
margin: 15px 0px 0px 0px;
}
.hidden-textarea {
display: none;
}
.rating .rating-item {
display: inline-block; /* Align items horizontally */
text-align: center; /* Center-align the label and star */
margin: 5px; /* Spacing between rating items */
}
.rating .rating-label {
display: block; /* Ensure the label is on a new line */
margin-bottom: 2px; /* Space between label and star */
font-size: 14px; /* Smaller font size for the label */
color: white;
}
/* Style the stars */
.rating .rating-star {
font-size: 24px; /* Adjust size as needed */
color: #ccc; /* Default color of stars */
cursor: pointer; /* Change cursor to pointer on hover */
transition: color 0.3s ease; /* Smooth transition for color change */
}
/* Style the stars when they are hovered over */
.rating .rating-star:hover,
.rating .rating-star:hover ~ .rating-star {
color: #ffe350; /* Color when hovered */
}
/* Style the stars when they are selected */
.rating .rating-star.selected {
color: #df9d01; /* Color of selected stars */
}
.rank-list {
list-style-type: none;
padding: 0;
}
.rank-list li {
padding: 5px;
margin-bottom: 2px;
color: white
}
.likert {
box-shadow: 0px 0px 7px 0px rgba(20,101,230,1);
-moz-box-shadow: 0px 0px 36px -12px rgba(20, 101, 230, 1);
-webkit-box-shadow: 0px 0px 7px 0px rgba(20,101,230,1);
border-radius: 5px;
background-color: transparent;
padding: 20px;
}
.likert .statement {
margin-bottom: 10px;
}
.likert .responses {
display: flex;
justify-content: space-between;
}
.likert .likert-option {
flex: 1;
text-align: center;
}
.likert label {
display: block;
cursor: pointer;
padding: 20px;
background-color: #33b3ae;
border-radius: 2px;
margin: 3px;
transition: background-color 0.3s;
font-size: 0.8rem;
}
.likert input[type="radio"]:checked + label {
background-color: transparent;
color: white;
font-size: 1rem;
}
.card-deck .card {
cursor: pointer;
padding: 10px;
border: 2px solid transparent;
box-shadow: 0px 0px 36px -12px rgba(20,101,230,1);
-webkit-box-shadow: 0px 0px 5px 0px rgba(20,101,230,1);
-moz-box-shadow: 0px 0px 36px -12px rgba(20, 101, 230, 1);
background-color: transparent;
transition: border 0.3s ease; /* Add transition for a smooth effect */
}
/* img{
border-radius:3px;
box-shadow: 0px 0px 36px -12px rgba(20,101,230,1);
-webkit-box-shadow: 0px 0px 5px 0px rgba(20,101,230,1);
-moz-box-shadow: 0px 0px 36px -12px rgba(20, 101, 230, 1);
}
*/
.card-deck .card:hover {
border: 2px solid #007bff;
transition: border 0.3s ease; /* Ensure the transition applies to the hover state as well */
}
.card-deck .image-card.selected {
border: 4px solid #28a745; /* Green border for selected cards */
}
.card-deck .image-option {
display: block;
}
.card-deck .image-option input[type="radio"] {
display: none; /* Hide radio button */
}
.matrix-question .table {
box-shadow: 0px 0px 7px 0px rgba(20,101,230,1);
-moz-box-shadow: 0px 0px 36px -12px rgba(20, 101, 230, 1);
-webkit-box-shadow: 0px 0px 7px 0px rgba(20,101,230,1);
border-radius: 5px;
background-color: transparent;
padding: 20px;
width: 100%;
}
.matrix-question th, .matrix-question td {
text-align: left; /* Aligns text to the left */
border: 2px solid white;
width: 100%;
}
.matrix-question th {
background-color: #33b3ae; /* Semi-transparent background for headers */
color: white; /* White text color for headers */
}
.matrix-question td {
background-color: #33b3ae; /* Semi-transparent background for headers */
color: white;
text-align: left;
}
input[type="radio"] {
border: 1px solid #007bff !important;
}
.matrix-question input[type="radio"] {
border: 1px solid #007bff !important;
}
.sortable-list {
list-style: none;
padding: 0;
}
.draggable-item:hover {
background-color: #e0e0e0;
}
button {
margin-left: 10px;
}
.draggable-item {
padding: 10px;
margin-bottom: 5px;
background-color: #f8f9fa; /* Light gray background for default state */
border: 1px solid #ccc;
cursor: grab; /* Cursor indicates that this item is draggable */
transition: background-color 0.3s ease; /* Smooth transition for background color */
border-radius: 5px;
margin: 10px;
display: flex; /* Enable flexbox */
align-items: center; /* Center items vertically */
justify-content: space-between; /* Spread out content */
}
.draggable-item.selected {
background-color: #33b3ae;
; /* Blue background for selected state */
color: white; /* White text color for better visibility */
}
.up-button, .down-button {
margin: 0 5px; /* Spacing between buttons */
}
.answer-index {
font-weight: bold;
}
.draggable-item .bi-grip-vertical {
margin-right: auto; /* Pushes all elements to the right of it to the far right */
}
.draggable-item button {
margin-left: 5px; /* Space between buttons */
}
</style>
<div class="QuestionContainer">
<section class="hero container card">
<form id="questionnaireForm" method="post" asp-action="DisplayQuestionnaire">
<input type="hidden" name="Id" value="@Model.Id">
<input type="hidden" name="Title" value="@Model.Title">
<input type="hidden" name="Description" value="@Model.Description">
<!-- Add these new hidden inputs for tracking -->
<input type="hidden" id="questionsShown" name="QuestionsShown" value="">
<input type="hidden" id="questionsSkipped" name="QuestionsSkipped" value="">
<input type="hidden" name="Id" value="@Model.Id">
<input type="hidden" name="Title" value="@Model.Title">
<input type="hidden" name="Description" value="@Model.Description">
<h4>@Model.Title</h4>
<p>@Html.Raw(Model.Description)</p>
<div class="container">
<div class="continaer">
<div class="row">
<div class="col-md-6 col-lg-6 col-sm-12">
<div class="mb-3">
<label for="userName">Your Name</label>
<input type="text" class="form-control" id="userName" name="UserName" placeholder="Enter your name">
</div>
<div class="mb-3">
<label for="Email">Email Address</label>
<input type="email" class="form-control" id="Email" name="Email" placeholder="Enter your email">
</div>
</div>
</div>
</div>
<div class="row align-items-center">
<!-- Stepper -->
<div class="col-md-3">
<div class="stepper">
@for (int i = 0; i < Model.Questions.Count; i++)
{
var question = Model.Questions[i];
string stepClass = i == 0 ? "active" : ""; // Adjusted the index to start from the first question
<div class="step-indicator @(stepClass)" data-step-index="@i">
<span class="step-number">@((i + 1)). </span>
<span class="step-label">@question.Type</span>
</div>
}
</div>
</div>
<!-- Form Content -->
<div class="col-md-9">
@for (int i = 0; i < Model.Questions.Count; i++)
{
var question = Model.Questions[i];
<input type="hidden" name="Id" value="@question.Id">
<input type="hidden" name="Questions[@i].Text" value="@question.Text">
<input type="hidden" name="Questions[@i].Id" value="@question.Id">
<input type="hidden" name="Questions[@i].Type" value="@((int)question.Type)">
@for (int j = 0; j < question.Answers.Count; j++)
{
var answer = question.Answers[j];
<input type="hidden" name="Questions[@i].Answers[@j].Id" value="@answer.Id">
<input type="hidden" name="Questions[@i].Answers[@j].Text" value="@answer.Text">
<!-- Add more hidden fields as needed for other properties of the answer -->
}
<div class="step @(i == 0 ? "active" : "")" data-question-id="@question.Id">
<p class="font-weight-normal">@(i + 1). @question.Text</p>
@switch (question.Type)
{
case QuestionType.Text:
@foreach (var answer in question.Answers)
{
<input type="Text" class="form-control" id="question@(i + 1)" name="Questions[@i].SelectedText" rows="3" placeholder="Enter answer"></input>
<input class="form-control hidden-textarea" id="question@(i + 1)" name="Questions[@i].SelectedAnswerIds" value="@answer.Id" rows="3" placeholder="Enter answer" data-condition="@answer.ConditionJson"></input>
}
break;
case QuestionType.CheckBox:
case QuestionType.Multiple_choice:
case QuestionType.Demographic:
<div class="form-group">
@foreach (var answer in question.Answers)
{
<div class="form-check">
<input class="form-check-input" id="question@(i)_answer@(answer.Id)" type="checkbox" name="Questions[@i].SelectedAnswerIds" value="@answer.Id" data-condition="@answer.ConditionJson">
<label class="form-check-label" for="question@(i)_answer@(answer.Id)">
@answer.Text
</label>
</div>
}
</div>
break;
case QuestionType.TrueFalse:
<div class="form-check">
@foreach (var answer in question.Answers)
{
<div class="form-check">
<input class="form-check-input answer-input" type="radio" id="question@(i)_answer@(answer.Id)" name="Questions[@i].SelectedAnswerIds" value="@answer.Id" data-condition="@answer.ConditionJson">
<label class="form-check-label" for="question@(i)_answer@(answer.Id)">
@answer.Text
</label>
</div>
}
</div>
break;
case QuestionType.Open_ended:
@foreach (var answer in question.Answers)
{
<textarea type="Text" class="form-control" id="question@(i + 1)" name="Questions[@i].SelectedText" value="@answer.Text" rows="3" placeholder="Enter answer"></textarea>
<input type="hidden" class="form-control" id="question@(i + 1)" name="Questions[@i].SelectedAnswerIds" value="@answer.Id" rows="3" placeholder="Enter answer" data-condition="@answer.ConditionJson"></input>
}
break;
case QuestionType.Slider:
@foreach (var answer in question.Answers)
{
<input type="range" class="form-range " id="question@(i + 1)" name="Questions[@i].SelectedText" min="0" max="100" step="1">
<input type="hidden" class="form-range " id="question@(i + 1)" name="Questions[@i].SelectedAnswerIds" value="@answer.Id" min="0" max="100" step="1" data-condition="@answer.ConditionJson">
<output id="question@(i + 1)_output">50</output>
<script>
document.getElementById('question@(i + 1)').addEventListener('input', function () {
document.getElementById('question@(i + 1)_output').value = this.value;
});
</script>
}
break;
case QuestionType.Rating:
<div class="rating" data-question="@i">
@foreach (var answer in question.Answers)
{
<div class="rating-item">
<div class="rating-label">@answer.Text</div>
<input type="radio" id="question@(i)_rating@(answer.Id)"
name="Questions[@i].SelectedAnswerIds"
value="@answer.Id" class="rating-input" hidden data-condition="@answer.ConditionJson">
<label for="question@(i)_rating@(answer.Id)" class="bi bi-star-fill rating-star"></label>
</div>
}
</div>
break;
case QuestionType.Ranking:
<div class="ranking-question">
<p class="ml-3">drag and drop to move the answers</p>
<ul class="sortable-list" id="ranking_@question.Id">
@{
int index = 1; // Initialize the index to start numbering from 1
}
@foreach (var answer in question.Answers)
{
<li class="draggable-item" draggable="true" id="@answer.Id" ondragstart="dragStart(event);" ondragover="allowDrop(event);" ondrop="drop(event);">
<span class="answer-index">@index. </span> @answer.Text
<i class="bi bi-grip-vertical mr-auto"></i>
<input type="hidden" name="Questions[@i].SelectedAnswerIds" value="@answer.Id" data-condition="@answer.ConditionJson">
<button type="button" class="up-button btn btn-primary btn-sm " onclick="moveUp(this.parentElement)">
<i class="bi bi-arrow-up"></i> Up
</button>
<button type="button" class="down-button btn btn-info btn-sm" onclick="moveDown(this.parentElement)">
<i class="bi bi-arrow-down"></i> Down
</button>
</li>
index++; // Increment the index for the next item
}
</ul>
</div>
<script>
function allowDrop(ev) {
ev.preventDefault(); // Necessary to allow a drop event
}
function dragStart(ev) {
ev.dataTransfer.setData("text", ev.target.id); // Stores the id of the draggable item
}
function drop(ev) {
ev.preventDefault();
var data = ev.dataTransfer.getData("text");
var draggedElement = document.getElementById(data);
var dropTarget = ev.target.closest('.draggable-item');
if (dropTarget) {
var targetRect = dropTarget.getBoundingClientRect();
var midPoint = targetRect.top + (targetRect.height / 2); // Calculate the midpoint of the drop target
var list = dropTarget.parentNode;
if (ev.clientY < midPoint) {
// Drop above the target
list.insertBefore(draggedElement, dropTarget);
} else {
// Drop below the target
if (dropTarget.nextSibling) {
list.insertBefore(draggedElement, dropTarget.nextSibling);
} else {
list.appendChild(draggedElement); // In case the target is the last child
}
}
}
}
// Click to select item
document.querySelectorAll('.draggable-item').forEach(item => {
item.addEventListener('click', function () {
// Remove previous selections
removeSelected(this.parentNode);
// Mark this as selected
this.classList.add('selected');
});
});
// Function to remove selected class from siblings
function removeSelected(parent) {
parent.querySelectorAll('.draggable-item').forEach(sibling => {
sibling.classList.remove('selected');
});
}
</script>
break;
case QuestionType.Likert:
<div class="likert">
<div class="statement">
<label>Please indicate your level of agreement with the following statements:</label>
<div class="responses">
@foreach (var answer in question.Answers)
{
<label class="likert-option">
<input class="form-check-input" type="radio" id="question@(i)_answer@(answer.Id)" name="Questions[@i].SelectedAnswerIds" value="@answer.Id" data-condition="@answer.ConditionJson">
@answer.Text
</label>
}
</div>
</div>
</div>
break;
case QuestionType.Matrix:
<div class="matrix-question">
<table class="table table-responsive">
<thead>
<tr>
<th>Question</th>
@foreach (var option in question.Answers) // Assuming these are the consistent answer options across all sub-questions
{
<th>@option.Text</th>
}
</tr>
</thead>
<tbody>
<tr>
<td>@question.Text</td>
@foreach (var option in question.Answers) // Use consistent options for each sub-question
{
<td>
<input type="radio" name="Questions[@i].SelectedAnswerIds" value="@option.Id" data-condition="@option.ConditionJson">
</td>
}
</tr>
</tbody>
</table>
</div>
break;
case QuestionType.Image:
<script>
function selectImageCard(answerId, questionId) {
// Clear previously selected
var cards = document.querySelectorAll('.image-question[data-question-id="' + questionId + '"] .card');
cards.forEach(function (card) {
card.classList.remove('selected');
});
// Set new selected
var selectedCard = document.getElementById('card_' + answerId);
selectedCard.classList.add('selected');
// Set the radio button as checked
var radioButton = document.getElementById('image_answer_' + answerId);
radioButton.checked = true;
}
</script>
<div class="image-question" data-question-id="@question.Id">
<div class="card-deck">
@foreach (var answer in question.Answers)
{
<div class="card image-card" id="card_@answer.Id" onclick="selectImageCard('@answer.Id', '@question.Id')">
<img src="@answer.Text" alt="Image option" class="img-fluid" />
<input type="radio" id="image_answer_@answer.Id" name="Questions[@i].SelectedAnswerIds" value="@answer.Id" hidden data-condition="@answer.ConditionJson" />
</div>
}
</div>
</div>
break;
default:
<div class="alert alert-danger" role="alert">
Unsupported question type.
</div>
break;
}
<div class="mt-3">
@if (i > 0)
{
<button type="button" class="btn btn-secondary btn-sm mr-3 prev" id="BannerButon"><i class="bi bi-arrow-left"></i> Previous </button>
}
@if (i < Model.Questions.Count - 1)
{
<button type="button" class="btn btn-primary btn-sm next" id="BannerButon">Next <i class="bi bi-arrow-right"></i></button>
}
</div>
</div>
}
<div class="User-details" style="display:none;">
<div class="form-group">
<label for="userName">Your Name:</label>
<input type="text" class="form-control" id="userName" name="UserName" placeholder="Enter your name" >
</div>
<div class="form-group">
<label for="userEmail">Email Address:</label>
<input type="email" class="form-control" id="userEmail" name="UserEmail" placeholder="Enter your email" >
</div>
</div>
<button type="submit" class="btn btn-primary submit btn-sm mt-4" id="BannerButon">Submit</button>
</div>
</div>
</div>
</form>
</section>
</div>
@section Scripts {
@{
<partial name="_ValidationScriptsPartial" />
}
<script>
document.addEventListener("DOMContentLoaded", function () {
const form = document.getElementById('questionnaireForm');
if (!form) {
console.error('Form not found!');
return;
}
// Track which questions were shown and skipped - FIXED VARIABLE NAMES
let questionsShownArray = [1]; // Start with question 1
let questionsSkippedArray = [];
let navigationPath = [0]; // Start with question 1 (index 0)
function trackQuestionShown(questionNumber) {
if (!questionsShownArray.includes(questionNumber)) {
questionsShownArray.push(questionNumber);
console.log('Question shown:', questionNumber, 'Total shown:', questionsShownArray);
}
}
function trackQuestionSkipped(questionNumber, reason) {
const skipInfo = {
questionNumber: questionNumber,
reason: reason
};
questionsSkippedArray.push(skipInfo);
console.log('Question skipped:', skipInfo);
}
function updateTrackingInputs() {
document.getElementById('questionsShown').value = JSON.stringify(questionsShownArray);
document.getElementById('questionsSkipped').value = JSON.stringify(questionsSkippedArray);
}
// Get conditions from the CURRENT step only
function getCurrentStepConditions() {
const currentStepElement = steps[currentStep];
const activeConditions = [];
// Only check inputs in the current step
const currentStepInputs = currentStepElement.querySelectorAll('input:checked, input[type="text"]:not([value=""]), textarea:not([value=""])');
currentStepInputs.forEach(input => {
const condition = input.getAttribute('data-condition');
if (condition && condition !== '' && condition !== 'null') {
try {
const conditionData = JSON.parse(condition);
activeConditions.push(conditionData);
} catch (e) {
console.log('Invalid condition JSON:', condition);
}
}
});
return activeConditions;
}
function shouldApplyCondition() {
const conditions = getCurrentStepConditions();
for (let condition of conditions) {
if (condition.ActionType === 1 && condition.TargetQuestionNumber) {
// SkipToQuestion
return { action: 'jumpTo', target: condition.TargetQuestionNumber };
} else if (condition.ActionType === 2 && condition.SkipCount) {
// SkipCount
return { action: 'skip', count: condition.SkipCount };
} else if (condition.ActionType === 3) {
// EndSurvey
return { action: 'end', message: condition.EndMessage };
}
}
return { action: 'continue' };
}
function getCurrentStepNumber() {
return currentStep + 1; // Convert 0-based index to 1-based question number
}
function jumpToQuestion(questionNumber) {
const targetStepIndex = questionNumber - 1; // Convert to 0-based index
if (targetStepIndex >= 0 && targetStepIndex < steps.length) {
const currentQuestionNumber = getCurrentStepNumber();
// Track skipped questions between current and target
for (let i = currentQuestionNumber + 1; i < questionNumber; i++) {
trackQuestionSkipped(i, `Skipped due to jump condition from question ${currentQuestionNumber}`);
}
currentStep = targetStepIndex;
navigationPath.push(currentStep); // Track the path
trackQuestionShown(questionNumber); // Track the target question as shown
showStep(currentStep);
updateStepper();
console.log(`Jumped to question ${questionNumber}, path:`, navigationPath);
}
}
function skipQuestions(skipCount) {
const currentQuestionNumber = getCurrentStepNumber();
const newStepIndex = currentStep + skipCount + 1;
// Track skipped questions
for (let i = 1; i <= skipCount; i++) {
const skippedQuestionNumber = currentQuestionNumber + i;
if (skippedQuestionNumber <= steps.length) {
trackQuestionSkipped(skippedQuestionNumber, `Skipped due to skip condition from question ${currentQuestionNumber}`);
}
}
if (newStepIndex < steps.length) {
currentStep = newStepIndex;
navigationPath.push(currentStep); // Track the path
trackQuestionShown(getCurrentStepNumber()); // Track the new question as shown
showStep(currentStep);
updateStepper();
} else {
// If skip goes beyond last question, show submit
currentStep = steps.length - 1;
navigationPath.push(currentStep);
showStep(currentStep);
updateStepper();
}
console.log(`Skipped ${skipCount} questions, path:`, navigationPath);
}
function endSurvey(endMessage) {
const currentQuestionNumber = getCurrentStepNumber();
// Track all remaining questions as skipped
for (let i = currentQuestionNumber + 1; i <= steps.length; i++) {
trackQuestionSkipped(i, `Survey ended early from question ${currentQuestionNumber}`);
}
// Hide all steps and show end message
steps.forEach(step => step.style.display = 'none');
const endMessageDiv = document.createElement('div');
endMessageDiv.className = 'alert alert-success text-center';
endMessageDiv.innerHTML = `
<h4>Survey Completed</h4>
<p>${endMessage || 'Thank you for completing the survey!'}</p>
`;
const formContainer = document.querySelector('.col-md-9');
formContainer.appendChild(endMessageDiv);
// Hide submit button
submitButton.style.display = 'none';
}
// Rating functionality
$(document).ready(function () {
$('.rating-item').on('click', function () {
$(this).siblings().find('.rating-star').removeClass('selected');
$(this).find('.rating-star').addClass('selected');
$(this).prevAll().find('.rating-star').addClass('selected');
$(this).find('.rating-star').toggleClass('bi-star-fill bi-star');
$(this).find('.rating-input').prop('checked', true);
});
});
// Ranking functionality
if (!window.hasEventListenersAdded) {
const upButtons = document.querySelectorAll('.up-button');
const downButtons = document.querySelectorAll('.down-button');
upButtons.forEach(button => {
button.addEventListener('click', function () {
moveUp(this);
});
});
downButtons.forEach(button => {
button.addEventListener('click', function () {
moveDown(this);
});
});
window.hasEventListenersAdded = true;
}
function moveUp(button) {
var li = button.parentNode;
if (li.previousElementSibling) {
li.parentNode.insertBefore(li, li.previousElementSibling);
}
}
function moveDown(button) {
var li = button.parentNode;
if (li.nextElementSibling) {
li.parentNode.insertBefore(li.nextElementSibling, li);
}
}
// Stepper functionality
const steps = form.querySelectorAll('.step');
const stepIndicators = document.querySelectorAll('.step-indicator');
const submitButton = form.querySelector('.submit');
let currentStep = 0;
form.addEventListener('submit', function (event) {
updateTrackingInputs();
console.log('Form submission with tracking data');
console.log('Questions shown:', questionsShownArray);
console.log('Questions skipped:', questionsSkippedArray);
const formData = new FormData(form);
formData.forEach((value, key) => {
console.log(`${key}: ${value}`);
});
});
function showStep(index) {
steps.forEach((step, i) => {
step.style.display = i === index ? 'block' : 'none';
});
stepIndicators.forEach((indicator, i) => {
if (i === index) {
indicator.classList.add('active');
} else {
indicator.classList.remove('active');
}
});
submitButton.style.display = index === steps.length - 1 ? 'block' : 'none';
}
// Fixed goToNextStep - only applies conditions from current step
function goToNextStep() {
const conditionResult = shouldApplyCondition();
switch (conditionResult.action) {
case 'jumpTo':
console.log(`Applying condition: Jump to question ${conditionResult.target}`);
jumpToQuestion(conditionResult.target);
break;
case 'skip':
console.log(`Applying condition: Skip ${conditionResult.count} questions`);
skipQuestions(conditionResult.count);
break;
case 'end':
console.log('Applying condition: End survey');
endSurvey(conditionResult.message);
break;
case 'continue':
default:
// Normal next step
if (currentStep < steps.length - 1) {
currentStep++;
navigationPath.push(currentStep); // Track normal navigation
trackQuestionShown(getCurrentStepNumber()); // Track question as shown
showStep(currentStep);
updateStepper();
console.log(`Normal next to question ${currentStep + 1}, path:`, navigationPath);
}
break;
}
}
// Fixed goToPrevStep - follows actual navigation path
function goToPrevStep() {
if (navigationPath.length > 1) {
// Remove current step from path
navigationPath.pop();
// Go to previous step in the actual path
currentStep = navigationPath[navigationPath.length - 1];
showStep(currentStep);
updateStepper();
console.log(`Previous to question ${currentStep + 1}, path:`, navigationPath);
} else {
console.log('Already at the first question');
}
}
function updateStepper() {
const currentStepIndex = currentStep;
stepIndicators.forEach((indicator, i) => {
indicator.style.backgroundColor = i === currentStepIndex ? '#33b3ae' : '';
});
}
// Event listeners for next/previous buttons
const nextButtons = form.querySelectorAll('.next');
nextButtons.forEach(button => {
button.addEventListener('click', goToNextStep);
});
const prevButtons = form.querySelectorAll('.prev');
prevButtons.forEach(button => {
button.addEventListener('click', goToPrevStep);
});
// Initialize the form at the first step
showStep(currentStep);
});
// Global functions
function allowDrop(ev) {
ev.preventDefault();
}
function dragStart(ev) {
ev.dataTransfer.setData("text", ev.target.id);
}
function drop(ev) {
ev.preventDefault();
var data = ev.dataTransfer.getData("text");
var draggedElement = document.getElementById(data);
var dropTarget = ev.target.closest('.draggable-item');
if (dropTarget) {
var targetRect = dropTarget.getBoundingClientRect();
var midPoint = targetRect.top + (targetRect.height / 2);
var list = dropTarget.parentNode;
if (ev.clientY < midPoint) {
list.insertBefore(draggedElement, dropTarget);
} else {
if (dropTarget.nextSibling) {
list.insertBefore(draggedElement, dropTarget.nextSibling);
} else {
list.appendChild(draggedElement);
}
}
}
}
function selectImageCard(answerId, questionId) {
var cards = document.querySelectorAll('.image-question[data-question-id="' + questionId + '"] .card');
cards.forEach(function (card) {
card.classList.remove('selected');
});
var selectedCard = document.getElementById('card_' + answerId);
selectedCard.classList.add('selected');
var radioButton = document.getElementById('image_answer_' + answerId);
radioButton.checked = true;
}
function removeSelected(parent) {
parent.querySelectorAll('.draggable-item').forEach(sibling => {
sibling.classList.remove('selected');
});
}
</script>
}