further question editing improvements

This commit is contained in:
Ross
2025-05-12 22:45:08 +01:00
parent 7689bded66
commit 9f5fc09e23
+121 -29
View File
@@ -27,11 +27,19 @@
</div>
{% endif %}
<details class="help-text">
<summary><i class="bi bi-info-circle"></i> Help</summary>
<p>This form allows you to add questions to a case. A example of how the quesiton will be displayed is shown below.</p>
<p>If answers are supplied the question will be automarked</p>
<p>The question system is built using https://github.com/json-editor/json-editor, this allows for highly flexible forms / question design at a cost of some complexity. To help with this a number of preset questions are avalible to choose from (these can then be edited if needed). It is also possible to copy questions from other cases in the collection. </p>
<p>In most cases it is not necessary to edit the JSON schema directly as questions can be added / edited via the GUI.</p>
<p>To save the question schema you need to click the "Save Questions" button at the bottom of the page. The page will then refresh and you can see how questions will be displayed at the bottom of the page.</p>
</details>
Import schema from:
<button class="btn btn-primary btn-sm" type="button" data-bs-toggle="offcanvas" data-bs-target="#offcanvasRight" aria-controls="offcanvasRight"
hx-get="{% url 'atlas:collection_question_schemas' case_detail.collection.id %}"
@@ -47,45 +55,50 @@
</summary>
<p>Title of the question block.</p>
<input id="question_block_title_input" type="text" name="title" value="{{case_detail.question_schema.title}}" class="form-control" placeholder="Question title" aria-label="Question title">
</details>
<details open><summary>Add Question</summary>
</details>
<details><summary>Modify Questions</summary>
<div id="questions-container" style="margin-top: 20px;">
<div id="questions-container" style="margin-top: 20px;">
<!-- Questions will be dynamically rendered here -->
</div>
</details>
<div>
</div>
</details>
<details open id="add-question-block"><summary>Add/Edit Question</summary>
<div>
<label for="question-type-select">Select Question Type:</label>
<select id="question-type-select" class="form-select">
<option value="radio">Multiple Choice (Radio)</option>
<option value="dropdown">Multiple Choice (Dropdown)</option>
<option value="dropdown-select">Multiple Choice (Dropdown - Select2)</option>
<option value="text">Text Input</option>
<option value="textarea">Text Area</option>
<option value="multiselect">Multiselect</option>
<option value="yesno">Yes/No</option>
<option value="truefalse">True/False</option>
</select>
</div>
<option value="number">Number</option>
<option value="range">Range</option>
<div id="options-configurator" style="margin-top: 10px; ">
</select>
</div>
<div id="options-configurator" style="margin-top: 10px; ">
<label>Enter Options:</label>
<div id="question-options-container">
<!-- Individual option input fields will be added here -->
</div>
<button type="button" class="btn btn-secondary btn-sm" id="add-option-button" style="margin-top: 10px;">Add Option</button>
</div>
<div style="margin-top: 10px;">
</div>
<div style="margin-top: 10px;">
<label for="question-title-input">Question Title:</label>
<input id="question-title-input" type="text" class="form-control" placeholder="Enter question title">
</div>
</div>
<div style="margin-top: 10px;">
<div style="margin-top: 10px;">
<label for="question-description-input">Question Description:</label>
<input id="question-description-input" type="text" class="form-control" placeholder="Enter question description">
</div>
</div>
<button class="btn btn-primary btn-sm" id="add-new-question">Add New Question</button>
<button class="btn btn-secondary btn-sm" id="reset-question-options">Reset</button>
</details>
</details>
<div class="offcanvas offcanvas-end" tabindex="-1" id="offcanvasRight" aria-labelledby="offcanvasRightLabel"
>
@@ -101,7 +114,7 @@
<form method="POST">
{% csrf_token %}
{{ form.as_p }}
<button type="submit" value="save" name="submit">Submit</button>
<button type="submit" value="save" name="submit">Save Questions</button>
</form>
{% comment %} <h2>Blank form</h2>
@@ -219,7 +232,10 @@
});
// Reset the question options
resetQuestionOptionsButton.addEventListener('click', () => {
resetQuestionOptionsButton.onclick = resetQuestion;
function resetQuestion() {
// Clear the title and description fields
questionTitleInput.value = '';
questionDescriptionInput.value = '';
@@ -240,14 +256,13 @@
addNewQuestionButton.onclick = addNewQuestion;
toastr.success('Question options have been reset.');
});
}
// Add a new question
addNewQuestionButton.onclick = addNewQuestion;
function addNewQuestion() {
// Get the current content from the editor
try {
try {
currentContent = JSON.parse(question_editor.get().text);
} catch {
currentContent = JSON.parse(JSON.stringify(question_editor.get().json));
@@ -300,6 +315,15 @@ try {
description: description,
questionType: selectedType, // Add questionType property
};
} else if (selectedType === 'dropdown-select') {
newQuestion = {
enum: options.length > 0 ? options : ["Option 1", "Option 2", "Option 3"], // Default options if none provided
type: "string",
title: title,
format: "select2",
description: description,
questionType: selectedType, // Add questionType property
};
} else if (selectedType === 'multiselect') {
newQuestion = {
type: "array",
@@ -331,8 +355,33 @@ try {
description: description,
questionType: selectedType, // Add questionType property
};
} else if (selectedType === 'textarea') {
newQuestion = {
type: "string",
title: title,
format: "textarea", // Use textarea format
description: description,
questionType: selectedType, // Add questionType property
};
} else if (selectedType === 'number') {
newQuestion = {
type: "number",
title: title,
description: description,
questionType: selectedType, // Add questionType property
};
} else if (selectedType === 'range') {
newQuestion = {
type: "range",
title: title,
description: description,
minimum: 0, // Default minimum value
maximum: 100, // Default maximum value
questionType: selectedType, // Add questionType property
};
}
newQuestion.propertyOrder = current_question_number; // Set the property order
// Add the new question to the properties
currentContent.properties[`question_${current_question_number}`] = newQuestion;
@@ -343,7 +392,7 @@ try {
renderQuestions(); // Re-render the questions list
}
function renderQuestions() {
function renderQuestions() {
questionsContainer.innerHTML = ''; // Clear the container
try {
@@ -399,7 +448,7 @@ function renderQuestions() {
} catch (error) {
console.error('Error rendering questions:', error);
}
}
}
// Drag-and-drop event handlers
let draggedElement = null;
@@ -417,7 +466,7 @@ function renderQuestions() {
}
function handleDrop(e) {
function handleDrop(e) {
e.preventDefault();
if (draggedElement !== this) {
const draggedIndex = parseInt(draggedElement.getAttribute('data-index'));
@@ -466,7 +515,7 @@ function handleDrop(e) {
toastr.error('Failed to reorder questions.');
}
}
}
}
function handleDragEnd() {
this.classList.remove('dragging');
@@ -494,7 +543,7 @@ function handleDrop(e) {
// Initial render of questions
renderQuestions();
function editQuestion(questionKey) {
function editQuestion(questionKey) {
try {
let currentContent;
try {
@@ -541,14 +590,17 @@ function editQuestion(questionKey) {
addNewQuestionButton.onclick = () => {
saveEditedQuestion(questionKey);
};
document.getElementById('add-question-block').open = true; // Open the question block
document.getElementById('add-question-block').scrollIntoView({ behavior: 'smooth', block: "center" }); // Scroll to the question block
}
} catch (error) {
console.error('Error editing question:', error);
toastr.error('Failed to edit the question.');
}
}
}
function saveEditedQuestion(questionKey) {
function saveEditedQuestion(questionKey) {
try {
let currentContent;
try {
@@ -575,23 +627,63 @@ function saveEditedQuestion(questionKey) {
// Update the editor with the modified question
currentContent.properties[questionKey] = question;
question_editor.update({ json: currentContent });
toastr.success(`Question "${question.title}" updated successfully.`);
renderQuestions(); // Re-render the questions list
// Reset the "Add New Question" button
addNewQuestionButton.textContent = 'Add New Question';
addNewQuestionButton.onclick = addNewQuestion;
resetQuestion(); // Reset the question options
}
} catch (error) {
console.error('Error saving edited question:', error);
toastr.error('Failed to save the question.');
}
}
});
}
});
</script>
<style>
/* Style the <details> block */
details {
margin: 20px 0;
padding: 15px;
border: 1px solid #ddd;
border-radius: 5px;
background-color:rgba(13, 8, 8, 0.86);
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
transition: all 0.3s ease;
}
/* Style the <summary> element */
details summary {
font-weight: bold;
font-size: 1.1em;
cursor: pointer;
margin-bottom: 10px;
color: #333;
}
/* Add hover effect to <summary> */
details summary:hover {
color: #007bff;
}
/* Add padding to the content inside <details> */
details > *:not(summary) {
margin-top: 10px;
padding-left: 10px;
}
/* Add a border to the expanded <details> */
details[open] {
border-color: #007bff;
background-color: black;
}
</style>
{% endblock %}