339 lines
12 KiB
HTML
Executable File
339 lines
12 KiB
HTML
Executable File
{% extends "shorts/base.html" %}
|
|
{% load static from static %}
|
|
{% load crispy_forms_tags %}
|
|
|
|
{% block js %}
|
|
<!--<script type="text/javascript" src="/admin/jsi18n/"></script>-->
|
|
|
|
<script type="text/javascript">
|
|
let csrf_token = "{{csrf_token}}";
|
|
let hash_url = "{% url 'shorts:question_by_hash' %}";
|
|
//let monitor_directory_handler = false;
|
|
//let monitor_interval_id = false;
|
|
|
|
// set to hold the files that are still being processed
|
|
let load_viewer = false;
|
|
|
|
// async function listAllFilesAndDirs(dirHandle, files_only) {
|
|
// const files = [];
|
|
// for await (let [name, handle] of dirHandle) {
|
|
// const {
|
|
// kind
|
|
// } = handle;
|
|
// if (handle.kind === 'directory') {
|
|
// if (files_only != true) {
|
|
// files.push({
|
|
// name,
|
|
// handle,
|
|
// kind
|
|
// });
|
|
// }
|
|
// files.push(...await listAllFilesAndDirs(handle));
|
|
// } else {
|
|
// files.push({
|
|
// name,
|
|
// handle,
|
|
// kind
|
|
// });
|
|
// }
|
|
// }
|
|
// return files;
|
|
// }
|
|
|
|
|
|
document.addEventListener('drop', function (e) {
|
|
e.preventDefault();
|
|
}, false);
|
|
|
|
|
|
|
|
|
|
function add_answers_input_form() {
|
|
var form_idx = $('#id_answers-TOTAL_FORMS').val();
|
|
$('#answer_form_set').append($('#answer_empty_form').html().replace(/__prefix__/g, form_idx));
|
|
$(`#id_answers-${form_idx}-status`).val(2);
|
|
$('#id_answers-TOTAL_FORMS').val(parseInt(form_idx) + 1);
|
|
}
|
|
|
|
|
|
|
|
$(document).ready(function () {
|
|
$("#add_examination").appendTo($("#examination-label"));
|
|
|
|
dropContainer = document.getElementById("drop-container");
|
|
|
|
dropContainer.ondragover = function (evt) {
|
|
evt.preventDefault();
|
|
evt.stopPropagation();
|
|
};
|
|
|
|
dropContainer.ondragenter = function (evt) {
|
|
console.log("ENTER")
|
|
console.log(evt)
|
|
$(evt.target).addClass("drop-target-active")
|
|
evt.preventDefault();
|
|
evt.stopPropagation();
|
|
};
|
|
|
|
dropContainer.ondragleave = function (evt) {
|
|
console.log("ENTER")
|
|
console.log(evt)
|
|
$(evt.target).removeClass("drop-target-active")
|
|
evt.preventDefault();
|
|
evt.stopPropagation();
|
|
};
|
|
|
|
dropContainer.ondrop = function (evt) {
|
|
$(evt.target).removeClass("drop-target-active");
|
|
|
|
file_drop_number = evt.dataTransfer.files.length;
|
|
|
|
if (file_drop_number < 1) {
|
|
toastr.warning(`Drop failed (no files), try again.`);
|
|
} else {
|
|
toastr.info(`Loading ${file_drop_number} dropped image(s).`);
|
|
}
|
|
|
|
// Get all input elements
|
|
inputs = extendInputs("rapid-form", file_drop_number);
|
|
|
|
console.log("drop inputs", inputs, evt);
|
|
|
|
|
|
// Loop through each dropped file and try to assign to an
|
|
// input element
|
|
[...evt.dataTransfer.files].forEach((f) => {
|
|
feedback = false;
|
|
if (evt.target.id == "feedback-drop-target") {
|
|
feedback = true;
|
|
}
|
|
addFile(f, feedback)
|
|
})
|
|
|
|
evt.preventDefault();
|
|
evt.stopPropagation();
|
|
};
|
|
|
|
|
|
// $('#directory-picker-button').click(() => {
|
|
// window.showDirectoryPicker().then((handler) => {
|
|
// monitor_directory_handler = handler;
|
|
// monitor_interval_id = setInterval(function () {
|
|
// listAllFilesAndDirs(monitor_directory_handler).then(async function (
|
|
// items) {
|
|
// files_to_add = new Set();
|
|
// current_files = getCurrentFormFiles();
|
|
// current_files_tuple = new Set()
|
|
// for (let elem of current_files) {
|
|
// current_files_tuple.add(
|
|
// `${elem.size}, ${elem.name}, ${elem.lastModified}`
|
|
// );
|
|
// }
|
|
//
|
|
// console.log(current_files_tuple)
|
|
// for (var i = 0; i < items.length; i++) {
|
|
//
|
|
// f = await items[i].handle.getFile()
|
|
// console.log("f", f)
|
|
// if (!current_files_tuple.has(
|
|
// `${f.size}, ${f.name}, ${f.lastModified}`
|
|
// )) {
|
|
// files_to_add.add(f);
|
|
// }
|
|
// }
|
|
//
|
|
// // file objects differ enough that the following does not work
|
|
// //let distinct_set = new Set([...files_to_add].filter(
|
|
// // x => !current_files.has(x)));
|
|
//
|
|
//
|
|
// extendInputs(files_to_add.size);
|
|
// files_to_add.forEach((file) => {
|
|
// addFile(file, false);
|
|
// });
|
|
// });
|
|
// }, 5000);
|
|
// $("#directory-picker-display").text(monitor_directory_handler.name)
|
|
// .after(
|
|
// $(
|
|
// " <span>[clear]</span>").click((evt) => {
|
|
// $(evt.target).remove();
|
|
// $("#directory-picker-display").text("");
|
|
// monitor_directory_handler = false;
|
|
// clearInterval(monitor_interval_id);
|
|
// //const files = await listAllFilesAndDirs(directoryHandle);
|
|
// }));
|
|
// });
|
|
// });
|
|
|
|
|
|
|
|
$('#add_more_images').click(() => {
|
|
add_input_form()
|
|
});
|
|
$('#add_more_answers').click(() => {
|
|
add_answers_input_form()
|
|
});
|
|
|
|
$("input[type=file]").on('change', input_change);
|
|
|
|
$("#rapid-form").on("submit", (evt) => {
|
|
submit = true;
|
|
if (!$normal) {
|
|
if ($('#id_answers-TOTAL_FORMS').val() == "0") {
|
|
submit = false;
|
|
add_answers_input_form();
|
|
toastr.error(`Question that are not normal require an answer`);
|
|
evt.preventDefault();
|
|
}
|
|
|
|
}
|
|
|
|
|
|
if (!$("#id_examination_to option").length) {
|
|
submit = false;
|
|
toastr.error("Please add examination type")
|
|
evt.preventDefault();
|
|
}
|
|
|
|
if (submit) {
|
|
toastr.info(`Submiting question... please wait`, '', {
|
|
"closeButton": false,
|
|
"debug": false,
|
|
"newestOnTop": false,
|
|
"progressBar": true,
|
|
"positionClass": "toast-top-full-width",
|
|
"preventDuplicates": false,
|
|
"onclick": null,
|
|
"showDuration": "300",
|
|
"hideDuration": "1000",
|
|
"timeOut": "5000",
|
|
"extendedTimeOut": "1000",
|
|
"showEasing": "swing",
|
|
"hideEasing": "linear",
|
|
"showMethod": "fadeIn",
|
|
"hideMethod": "fadeOut"
|
|
});
|
|
}
|
|
})
|
|
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
function extractDicomDetails(byteArray) {
|
|
if (!$("#id_examination_to option").length) {
|
|
|
|
// We need to setup a try/catch block because parseDicom will throw an exception
|
|
// if you attempt to parse a non dicom part 10 file (or one that is corrupted)
|
|
try {
|
|
// parse byteArray into a DataSet object using the parseDicom library
|
|
var dataSet = dicomParser.parseDicom(byteArray);
|
|
|
|
// dataSet contains the parsed elements. Each element is available via a property
|
|
// in the dataSet.elements object. The property name is based on the elements group
|
|
// and element in the following format: xggggeeee where gggg is the group number
|
|
// and eeee is the element number with lowercase hex characters.
|
|
|
|
// To access the data for an element, we need to know its type and its tag.
|
|
// We will get the sopInstanceUid from the file which is a string and
|
|
// has the tag (0020,000D)
|
|
var study_description = dataSet.string('x00081030').toLowerCase();
|
|
console.log("STUDY", study_description);
|
|
|
|
// try to match with a study description (if not already selected)
|
|
if ($(`#id_examination_to option`).length < 1) {
|
|
option = $(`#id_examination_from option[title*='${study_description}' i]`);
|
|
|
|
if (option.length) {
|
|
option.appendTo($("#id_examination_to"));
|
|
toastr.success(`Examination set to ${option.attr('title')} from dicom data`);
|
|
} else {
|
|
toastr.warning(
|
|
`Unable to set examination ${study_description} from dicom data (it needs creating)`);
|
|
|
|
}
|
|
}
|
|
|
|
} catch (err) {
|
|
console.log(err);
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
|
|
{{ form.media }}
|
|
{% endblock %}
|
|
|
|
{% block content %}
|
|
|
|
{% if object %}
|
|
{% include "shorts/question_link_header.html" %}
|
|
{% endif %}
|
|
|
|
<h2>Submit Shorts Question</h2>
|
|
<h3>Instructions</h3>
|
|
<p>
|
|
Use this form to create a new short style question/case. Multiple images can be added to a question.
|
|
If the feedback image box is checked they will not be displayed when taking the question.
|
|
</p>
|
|
<p>Once you have created the question with this form you can add relevant findings.
|
|
</p>
|
|
<!-- <div>
|
|
To monitor a directory select it here.<br />
|
|
<button id="directory-picker-button">Pick a directory</button>
|
|
<span id="directory-picker-display">No directory monitored</span>
|
|
</div> -->
|
|
<form action="" method="post" enctype="multipart/form-data" id="rapid-form">
|
|
{% comment %} {% csrf_token %} {% endcomment %}
|
|
<a href="/rapids/examination/create" id="add_examination" class="add-popup"
|
|
onclick="return showAddPopup(this);"><img src="{% static 'img/icon-addlink.svg' %}"></a>
|
|
|
|
{% crispy form form.helper %}
|
|
|
|
<h3>Images:</h3>
|
|
<div id="drop-container" class="drop-target">Drop images here (or use the buttons below)<div
|
|
id="feedback-drop-target">Feedback image?<br />drop those here</div>
|
|
<div id="drop-filenames"></div>
|
|
</div>
|
|
<input type="button" value="Add More Images" id="add_more_images">
|
|
<div id="image_form_set">
|
|
{% for form in image_formset %}
|
|
<ul class="no-error image-formset">
|
|
{{form.non_field_errors}}
|
|
{{form.errors}}
|
|
{{ form.as_ul }}
|
|
</ul>
|
|
{% endfor %}
|
|
</div>
|
|
{{ image_formset.management_form }}
|
|
<input type="submit" class="submit-button" value="Submit" name="submit">
|
|
</form>
|
|
<div id="empty_form" style="display:none">
|
|
<ul class='no_error image-formset'>
|
|
{{ image_formset.empty_form.as_ul }}
|
|
</ul>
|
|
</div>
|
|
<div id="answer_empty_form" style="display:none">
|
|
<ul class='no_error answer-formset'>
|
|
{{ answer_formset.empty_form.as_ul }}
|
|
</ul>
|
|
</div>
|
|
|
|
<div id="single-dicom-viewer" class="rapid-dicom-viewer" data-images="" data-annotations='' style="display:none"></div>
|
|
|
|
{% endblock %}
|
|
|
|
|
|
{% block css %}
|
|
<style>
|
|
.add-popup {
|
|
float: left;
|
|
}
|
|
</style>
|
|
{% endblock css %}
|
|
|