.
This commit is contained in:
@@ -238,8 +238,8 @@
|
|||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<a href="/anatomy/examination/create" id="add_examination" class="add-popup"
|
<a href="/anatomy/examination/create" id="add_examination" class="add-popup"
|
||||||
onclick="return showAddPopup(this);"><img src="{% static 'img/icon-addlink.svg' %}"></a>
|
onclick="return showAddPopup(this);"><img src="{% static 'img/icon-addlink.svg' %}"></a>
|
||||||
<a href="/anatomy/body_part/create" id="add_body_part" class="add-popup"
|
<a href="/anatomy/body_part/create" id="add_body_part" class="add-popup"
|
||||||
onclick="return showAddPopup(this);"><img src="{% static 'img/icon-addlink.svg' %}"></a>
|
onclick="return showAddPopup(this);"><img src="{% static 'img/icon-addlink.svg' %}"></a>
|
||||||
|
|
||||||
{{ form|crispy }}
|
{{ form|crispy }}
|
||||||
<div id="drop-container" class="drop-target">Drop image here
|
<div id="drop-container" class="drop-target">Drop image here
|
||||||
|
|||||||
@@ -5,109 +5,109 @@
|
|||||||
{% block js %}
|
{% block js %}
|
||||||
<!--<script type="text/javascript" src="/admin/jsi18n/"></script>-->
|
<!--<script type="text/javascript" src="/admin/jsi18n/"></script>-->
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
function showEditPopup(url) {
|
function showEditPopup(url) {
|
||||||
var win = window.open(url, "Edit",
|
var win = window.open(url, "Edit",
|
||||||
'height=500,width=800,resizable=yes,scrollbars=yes');
|
'height=500,width=800,resizable=yes,scrollbars=yes');
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
function showAddPopup(triggeringLink) {
|
function showAddPopup(triggeringLink) {
|
||||||
var name = triggeringLink.id.replace(/^add_/, '');
|
var name = triggeringLink.id.replace(/^add_/, '');
|
||||||
href = triggeringLink.href;
|
href = triggeringLink.href;
|
||||||
var win = window.open(href, name, 'height=500,width=800,resizable=yes,scrollbars=yes');
|
var win = window.open(href, name, 'height=500,width=800,resizable=yes,scrollbars=yes');
|
||||||
win.focus();
|
win.focus();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
function closePopup(win, newID, newRepr, id) {
|
function closePopup(win, newID, newRepr, id) {
|
||||||
console.log(id)
|
console.log(id)
|
||||||
$(id + "_to").append('<option value=' + newID + ' title=' + newRepr + ' >' + newRepr + '</option>')
|
$(id + "_to").append('<option value=' + newID + ' title=' + newRepr + ' >' + newRepr + '</option>')
|
||||||
win.close();
|
win.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
document.addEventListener('drop', function (e) { e.preventDefault(); }, false);
|
document.addEventListener('drop', function (e) { e.preventDefault(); }, false);
|
||||||
|
|
||||||
function add_input_form() {
|
function add_input_form() {
|
||||||
var form_idx = $('#id_images-TOTAL_FORMS').val();
|
var form_idx = $('#id_images-TOTAL_FORMS').val();
|
||||||
$('#image_form_set').append($('#empty_form').html().replace(/__prefix__/g, form_idx));
|
$('#image_form_set').append($('#empty_form').html().replace(/__prefix__/g, form_idx));
|
||||||
$('#id_images-TOTAL_FORMS').val(parseInt(form_idx) + 1);
|
$('#id_images-TOTAL_FORMS').val(parseInt(form_idx) + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
function add_answers_input_form() {
|
function add_answers_input_form() {
|
||||||
var form_idx = $('#id_answers-TOTAL_FORMS').val();
|
var form_idx = $('#id_answers-TOTAL_FORMS').val();
|
||||||
$('#answer_form_set').append($('#answer_empty_form').html().replace(/__prefix__/g, form_idx));
|
$('#answer_form_set').append($('#answer_empty_form').html().replace(/__prefix__/g, form_idx));
|
||||||
$('#id_answers-TOTAL_FORMS').val(parseInt(form_idx) + 1);
|
$('#id_answers-TOTAL_FORMS').val(parseInt(form_idx) + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
$("#add_examination").appendTo($("label[for='id_examination']"));
|
$("#add_examination").appendTo($("label[for='id_examination']"));
|
||||||
|
|
||||||
dropContainer = document.getElementById("drop-container");
|
dropContainer = document.getElementById("drop-container");
|
||||||
|
|
||||||
dropContainer.ondragover = function (evt) {
|
dropContainer.ondragover = function (evt) {
|
||||||
evt.preventDefault();
|
evt.preventDefault();
|
||||||
evt.stopPropagation();
|
evt.stopPropagation();
|
||||||
};
|
};
|
||||||
|
|
||||||
dropContainer.ondragenter = function (evt) {
|
dropContainer.ondragenter = function (evt) {
|
||||||
console.log("ENTER")
|
console.log("ENTER")
|
||||||
console.log(evt)
|
console.log(evt)
|
||||||
$(evt.target).addClass("drop-target-active")
|
$(evt.target).addClass("drop-target-active")
|
||||||
evt.preventDefault();
|
evt.preventDefault();
|
||||||
evt.stopPropagation();
|
evt.stopPropagation();
|
||||||
};
|
};
|
||||||
|
|
||||||
dropContainer.ondragleave = function (evt) {
|
dropContainer.ondragleave = function (evt) {
|
||||||
console.log("ENTER")
|
console.log("ENTER")
|
||||||
console.log(evt)
|
console.log(evt)
|
||||||
$(evt.target).removeClass("drop-target-active")
|
$(evt.target).removeClass("drop-target-active")
|
||||||
evt.preventDefault();
|
evt.preventDefault();
|
||||||
evt.stopPropagation();
|
evt.stopPropagation();
|
||||||
};
|
};
|
||||||
|
|
||||||
dropContainer.ondrop = function (evt) {
|
dropContainer.ondrop = function (evt) {
|
||||||
$(evt.target).removeClass("drop-target-active");
|
$(evt.target).removeClass("drop-target-active");
|
||||||
|
|
||||||
|
|
||||||
if (evt.dataTransfer.files.length < 1) {
|
if (evt.dataTransfer.files.length < 1) {
|
||||||
toastr.warning(`Drop failed :( try again?`);
|
toastr.warning(`Drop failed :( try again?`);
|
||||||
} else {
|
} else {
|
||||||
toastr.info(`Adding ${evt.dataTransfer.files.length} files.`);
|
toastr.info(`Adding ${evt.dataTransfer.files.length} files.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get all input elements
|
// Get all input elements
|
||||||
inputs = $("#long-form input[type=file][id^=id_images-]");
|
inputs = $("#long-form input[type=file][id^=id_images-]");
|
||||||
//fileInput = document.getElementById("id_images-0-image");
|
//fileInput = document.getElementById("id_images-0-image");
|
||||||
|
|
||||||
// Make sure we have enough input targets
|
// Make sure we have enough input targets
|
||||||
input_diff = (evt.dataTransfer.files.length - inputs.length)
|
input_diff = (evt.dataTransfer.files.length - inputs.length)
|
||||||
|
|
||||||
if (input_diff > 0) {
|
if (input_diff > 0) {
|
||||||
for (let j = 0; j < input_diff; j++) {
|
for (let j = 0; j < input_diff; j++) {
|
||||||
add_input_form()
|
add_input_form()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Need to make sure we include the new ones...
|
// Need to make sure we include the new ones...
|
||||||
inputs = $("#long-form input[type=file][id^=id_images-]");
|
inputs = $("#long-form input[type=file][id^=id_images-]");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Loop through each dropped file and try to assign to an
|
// Loop through each dropped file and try to assign to an
|
||||||
// input element
|
// input element
|
||||||
[...evt.dataTransfer.files].forEach((f) => {
|
[...evt.dataTransfer.files].forEach((f) => {
|
||||||
let dT = new DataTransfer();
|
let dT = new DataTransfer();
|
||||||
dT.clearData();
|
dT.clearData();
|
||||||
dT.items.add(f);
|
dT.items.add(f);
|
||||||
for (let i = 0; i < inputs.length; i++) {
|
for (let i = 0; i < inputs.length; i++) {
|
||||||
el = inputs.get(i)
|
el = inputs.get(i)
|
||||||
|
|
||||||
if (el.files.length == 0) {
|
if (el.files.length == 0) {
|
||||||
el.files = dT.files;
|
el.files = dT.files;
|
||||||
//ocr(el)
|
//ocr(el)
|
||||||
|
|
||||||
return false
|
return false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
})
|
|
||||||
|
|
||||||
// // If you want to use some of the dropped files
|
// // If you want to use some of the dropped files
|
||||||
// const dT = new DataTransfer();
|
// const dT = new DataTransfer();
|
||||||
@@ -115,31 +115,31 @@
|
|||||||
// dT.items.add(evt.dataTransfer.files[3]);
|
// dT.items.add(evt.dataTransfer.files[3]);
|
||||||
// fileInput.files = dT.files;
|
// fileInput.files = dT.files;
|
||||||
|
|
||||||
loadDicomViewerAndFileImages();
|
loadDicomViewerAndFileImages();
|
||||||
|
|
||||||
evt.preventDefault();
|
evt.preventDefault();
|
||||||
evt.stopPropagation();
|
evt.stopPropagation();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
$('#add_more_images').click(() => { add_input_form() });
|
$('#add_more_images').click(() => { add_input_form() });
|
||||||
$('#add_more_answers').click(() => { add_answers_input_form() });
|
$('#add_more_answers').click(() => { add_answers_input_form() });
|
||||||
|
|
||||||
|
|
||||||
$("input[type=file]").on('change', function () {
|
$("input[type=file]").on('change', function () {
|
||||||
$(this).removeClass("image-ident-warning");
|
$(this).removeClass("image-ident-warning");
|
||||||
$(this).removeClass("image-ident-ok");
|
$(this).removeClass("image-ident-ok");
|
||||||
console.log("input change1");
|
console.log("input change1");
|
||||||
console.log("input change", this);
|
console.log("input change", this);
|
||||||
//ocr(this);
|
//ocr(this);
|
||||||
//LoadDicomViewer();
|
//LoadDicomViewer();
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
sortable('.sortable');
|
sortable('.sortable');
|
||||||
sortable('.sortable')[0].addEventListener('sortupdate', function(e) {
|
sortable('.sortable')[0].addEventListener('sortupdate', function(e) {
|
||||||
/*
|
/*
|
||||||
|
|
||||||
This event is triggered when the user stops sorting and the DOM position has not yet changed.
|
This event is triggered when the user stops sorting and the DOM position has not yet changed.
|
||||||
@@ -153,15 +153,15 @@
|
|||||||
*/
|
*/
|
||||||
//updateImagePositions();
|
//updateImagePositions();
|
||||||
|
|
||||||
$(".temp-thumb").remove()
|
$(".temp-thumb").remove()
|
||||||
loadDicomViewer();
|
loadDicomViewer();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function ocr(input) {
|
function ocr(input) {
|
||||||
// Tesseract.recognize(f, "eng",{ logger: m => console.log(m) }
|
// Tesseract.recognize(f, "eng",{ logger: m => console.log(m) }
|
||||||
// ).then(({ data: { text } }) => {
|
// ).then(({ data: { text } }) => {
|
||||||
// console.log(text);
|
// console.log(text);
|
||||||
@@ -171,186 +171,186 @@
|
|||||||
// }
|
// }
|
||||||
// })
|
// })
|
||||||
|
|
||||||
console.log('{% static "worker.min.js" %}');
|
console.log('{% static "worker.min.js" %}');
|
||||||
console.log('{{ STATIC_URL }}/tesseract-core.wasm.js %}');
|
console.log('{{ STATIC_URL }}/tesseract-core.wasm.js %}');
|
||||||
|
|
||||||
const worker = Tesseract.createWorker({
|
const worker = Tesseract.createWorker({
|
||||||
workerPath: '{% static "worker.min.js" %}',
|
workerPath: '{% static "worker.min.js" %}',
|
||||||
langPath: '{% static "" %}',
|
langPath: '{% static "" %}',
|
||||||
//langPath: '{{ STATIC_URL }}',
|
//langPath: '{{ STATIC_URL }}',
|
||||||
corePath: '{% static "tesseract-core.wasm.js" %}',
|
corePath: '{% static "tesseract-core.wasm.js" %}',
|
||||||
});
|
});
|
||||||
|
|
||||||
const url = URL.createObjectURL(input.files[0]);
|
const url = URL.createObjectURL(input.files[0]);
|
||||||
let img = new Image;
|
let img = new Image;
|
||||||
img.src = url;
|
img.src = url;
|
||||||
|
|
||||||
img.onload = function () {
|
img.onload = function () {
|
||||||
|
|
||||||
|
|
||||||
width = img.width;
|
width = img.width;
|
||||||
|
|
||||||
// const rectangle = { left: 0, top: 0, width: width, height: 10 }
|
// const rectangle = { left: 0, top: 0, width: width, height: 10 }
|
||||||
|
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
await worker.load();
|
await worker.load();
|
||||||
await worker.loadLanguage('eng');
|
await worker.loadLanguage('eng');
|
||||||
await worker.initialize('eng');
|
await worker.initialize('eng');
|
||||||
// const { data: { text } } = await worker.recognize(input.files[0], { rectangle });
|
// const { data: { text } } = await worker.recognize(input.files[0], { rectangle });
|
||||||
const { data: { text } } = await worker.recognize(input.files[0]);
|
const { data: { text } } = await worker.recognize(input.files[0]);
|
||||||
//console.log(text);
|
//console.log(text);
|
||||||
l = text.toLowerCase();
|
l = text.toLowerCase();
|
||||||
$(`img[data-input-id='${input.id}'`).removeClass("image-ident-loading");
|
$(`img[data-input-id='${input.id}'`).removeClass("image-ident-loading");
|
||||||
console.log(l);
|
console.log(l);
|
||||||
if (l.includes("accesion") || l.includes("number") || l.search(/(ref|rk9|rh8|ra9|rbz)\d+/g) > -1) {
|
if (l.includes("accesion") || l.includes("number") || l.search(/(ref|rk9|rh8|ra9|rbz)\d+/g) > -1) {
|
||||||
$(input).addClass("image-ident-warning");
|
$(input).addClass("image-ident-warning");
|
||||||
$(`img[data-input-id='${input.id}'`).addClass("image-ident-warning");
|
$(`img[data-input-id='${input.id}'`).addClass("image-ident-warning");
|
||||||
} else {
|
} else {
|
||||||
$(input).addClass("image-ident-ok");
|
$(input).addClass("image-ident-ok");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
await worker.terminate();
|
await worker.terminate();
|
||||||
})();
|
})();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
async function loadDicomViewerAndFileImages(callback) {
|
async function loadDicomViewerAndFileImages(callback) {
|
||||||
$("#single-dicom-viewer").empty()
|
$("#single-dicom-viewer").empty()
|
||||||
//images = []
|
//images = []
|
||||||
//Function that returns a promise to read the file
|
//Function that returns a promise to read the file
|
||||||
const reader = (file) => {
|
const reader = (file) => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const fileReader = new FileReader();
|
const fileReader = new FileReader();
|
||||||
fileReader.onload = () => resolve(fileReader);
|
fileReader.onload = () => resolve(fileReader);
|
||||||
fileReader.readAsDataURL(file);
|
fileReader.readAsDataURL(file);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const readFile = (file, el) => {
|
const readFile = (file, el) => {
|
||||||
reader(file).then(reader => {
|
reader(file).then(reader => {
|
||||||
var image = new Image();
|
var image = new Image();
|
||||||
image.height = 100;
|
image.height = 100;
|
||||||
image.title = file.name;
|
image.title = file.name;
|
||||||
image.src = reader.result;
|
image.src = reader.result;
|
||||||
image.className = "temp-thumb";
|
image.className = "temp-thumb";
|
||||||
console.log("read" ,el);
|
console.log("read" ,el);
|
||||||
$(el).parent().parent().prepend(image);
|
$(el).parent().parent().prepend(image);
|
||||||
//images.push(reader.result);
|
//images.push(reader.result);
|
||||||
loadViewer(images);
|
loadViewer(images);
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
file_set = $("#image_form_set input[type=file]");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
file_set.each(async (n, el) => {
|
||||||
|
console.log(el);
|
||||||
|
if (el.files.length > 0) {
|
||||||
|
filename = el.files[0].name;
|
||||||
|
await readFile(el.files[0], el);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
console.log("images from files", images);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function loadViewer(images) {
|
||||||
|
|
||||||
file_set = $("#image_form_set input[type=file]");
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
file_set.each(async (n, el) => {
|
|
||||||
console.log(el);
|
|
||||||
if (el.files.length > 0) {
|
|
||||||
filename = el.files[0].name;
|
|
||||||
await readFile(el.files[0], el);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
console.log("images from files", images);
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
function loadViewer(images) {
|
|
||||||
//dicomViewer.loadCornerstone($("#single-dicom-viewer"), null, images, annotations);
|
//dicomViewer.loadCornerstone($("#single-dicom-viewer"), null, images, annotations);
|
||||||
file_set = $("#image_form_set input[type=file]");
|
file_set = $("#image_form_set input[type=file]");
|
||||||
|
|
||||||
n = 0;
|
n = 0;
|
||||||
for (let i = 0; i < file_set.length; i++) {
|
for (let i = 0; i < file_set.length; i++) {
|
||||||
el = file_set.get(i)
|
el = file_set.get(i)
|
||||||
if (el.files.length > 0) {
|
if (el.files.length > 0) {
|
||||||
n++;
|
n++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
image_set = $("#image_form_set img");
|
image_set = $("#image_form_set img");
|
||||||
if (n == image_set.length) {
|
if (n == image_set.length) {
|
||||||
const event = new CustomEvent('loadDicomViewer', { "detail": image_set });
|
const event = new CustomEvent('loadDicomViewer', { "detail": image_set });
|
||||||
|
|
||||||
window.dispatchEvent(event);
|
window.dispatchEvent(event);
|
||||||
sortable('.sortable');
|
sortable('.sortable');
|
||||||
//sortable('.sortable')[0].addEventListener('sortstop', function(e) {
|
//sortable('.sortable')[0].addEventListener('sortstop', function(e) {
|
||||||
updateImagePositions();
|
updateImagePositions();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
function updateImagePositions() {
|
||||||
|
console.log("UP pos");
|
||||||
|
|
||||||
function updateImagePositions() {
|
file_set = $("#image_form_set ul");
|
||||||
console.log("UP pos");
|
|
||||||
|
|
||||||
file_set = $("#image_form_set ul");
|
n = 0;
|
||||||
|
for (let i = 0; i < file_set.length; i++) {
|
||||||
|
ul = file_set.get(i);
|
||||||
|
console.log(ul)
|
||||||
|
|
||||||
n = 0;
|
file_element = $(ul).find("input[type=file]").get(0);
|
||||||
for (let i = 0; i < file_set.length; i++) {
|
|
||||||
ul = file_set.get(i);
|
|
||||||
console.log(ul)
|
|
||||||
|
|
||||||
file_element = $(ul).find("input[type=file]").get(0);
|
|
||||||
|
|
||||||
// If a (new) file is being uploaded we save it's name prior to it being hashed
|
// If a (new) file is being uploaded we save it's name prior to it being hashed
|
||||||
if (file_element.files.length > 0) {
|
if (file_element.files.length > 0) {
|
||||||
file_name = file_element.files[0].name
|
file_name = file_element.files[0].name
|
||||||
$(ul).find("input[type=text]").val(file_name);
|
$(ul).find("input[type=text]").val(file_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file_element.files.length > 0 || $(ul).find(":contains('Currently:')")) {
|
||||||
|
n++;
|
||||||
|
$(ul).find("input[type=number]").val(n);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (file_element.files.length > 0 || $(ul).find(":contains('Currently:')")) {
|
|
||||||
n++;
|
|
||||||
$(ul).find("input[type=number]").val(n);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
}
|
{{ form.media }}
|
||||||
</script>
|
|
||||||
|
|
||||||
{{ form.media }}
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h2>Series Form</h2>
|
<h2>Series Form</h2>
|
||||||
This form will create a image set that can be associated with a long question. If the question has already been created it can be linked below.
|
This form will create a image set that can be associated with a long question. If the question has already been created it can be linked below.
|
||||||
<form action="" method="post" enctype="multipart/form-data" id="long-form">
|
<form action="" method="post" enctype="multipart/form-data" id="long-form">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<a href="/generic/examination/create" id="add_examination" class="add-popup"
|
<a href="/generic/examination/create" id="add_examination" class="add-popup"
|
||||||
onclick="return showAddPopup(this);"><img src="{% static 'img/icon-addlink.svg' %}"></a>
|
onclick="return showAddPopup(this);"><img src="{% static 'img/icon-addlink.svg' %}"></a>
|
||||||
<table>
|
<table>
|
||||||
{{ form.as_table }}
|
{{ form.as_table }}
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<h3>Images:</h3>
|
<h3>Images:</h3>
|
||||||
<input type="button" value="Add More Images" id="add_more_images">
|
<input type="button" value="Add More Images" id="add_more_images">
|
||||||
<div id="drop-container" class="">Drop images here (or use the buttons below). Dropping images here will overwrite existing images in the series. When drag and dropping make sure to drag the first image or the order will not be maintained. Note: dicom images are often not exported in order (although their order can be automatically detected once uploaded)
|
<div id="drop-container" class="">Drop images here (or use the buttons below). Dropping images here will overwrite existing images in the series. When drag and dropping make sure to drag the first image or the order will not be maintained. Note: dicom images are often not exported in order (although their order can be automatically detected once uploaded)
|
||||||
<div id="single-dicom-viewer" class="dicom-viewer" data-images="" data-annotations=''></div>
|
<div id="single-dicom-viewer" class="dicom-viewer" data-images="" data-annotations=''></div>
|
||||||
<div id="drop-filenames"></div>
|
<div id="drop-filenames"></div>
|
||||||
</div>
|
</div>
|
||||||
<div id="image_form_set" class="sortable">
|
<div id="image_form_set" class="sortable">
|
||||||
{% for form in image_formset %}
|
{% for form in image_formset %}
|
||||||
<ul class="no-error image-formset">
|
<ul class="no-error image-formset">
|
||||||
{{form.non_field_errors}}
|
{{form.non_field_errors}}
|
||||||
{{form.errors}}
|
{{form.errors}}
|
||||||
{{ form.as_ul }}
|
{{ 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>
|
</ul>
|
||||||
{% endfor %}
|
|
||||||
</div>
|
</div>
|
||||||
{{ image_formset.management_form }}
|
<div id="images">
|
||||||
<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="images">
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@@ -5,14 +5,14 @@
|
|||||||
{% block js %}
|
{% block js %}
|
||||||
<!--<script type="text/javascript" src="/admin/jsi18n/"></script>-->
|
<!--<script type="text/javascript" src="/admin/jsi18n/"></script>-->
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
let csrf_token = "{{csrf_token}}";
|
let csrf_token = "{{csrf_token}}";
|
||||||
let hash_url = "{% url 'rapids:rapid_question_by_hash' %}";
|
let hash_url = "{% url 'rapids:rapid_question_by_hash' %}";
|
||||||
//let monitor_directory_handler = false;
|
//let monitor_directory_handler = false;
|
||||||
//let monitor_interval_id = false;
|
//let monitor_interval_id = false;
|
||||||
|
|
||||||
// set to hold the files that are still being processed
|
// set to hold the files that are still being processed
|
||||||
let load_viewer = false;
|
let load_viewer = false;
|
||||||
|
|
||||||
// async function listAllFilesAndDirs(dirHandle, files_only) {
|
// async function listAllFilesAndDirs(dirHandle, files_only) {
|
||||||
// const files = [];
|
// const files = [];
|
||||||
@@ -41,80 +41,80 @@
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
|
|
||||||
document.addEventListener('drop', function (e) {
|
document.addEventListener('drop', function (e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
}, false);
|
}, false);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function add_answers_input_form() {
|
function add_answers_input_form() {
|
||||||
var form_idx = $('#id_answers-TOTAL_FORMS').val();
|
var form_idx = $('#id_answers-TOTAL_FORMS').val();
|
||||||
$('#answer_form_set').append($('#answer_empty_form').html().replace(/__prefix__/g, form_idx));
|
$('#answer_form_set').append($('#answer_empty_form').html().replace(/__prefix__/g, form_idx));
|
||||||
$(`#id_answers-${form_idx}-status`).val(2);
|
$(`#id_answers-${form_idx}-status`).val(2);
|
||||||
$('#id_answers-TOTAL_FORMS').val(parseInt(form_idx) + 1);
|
$('#id_answers-TOTAL_FORMS').val(parseInt(form_idx) + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
$("#add_abnormality").appendTo($("#abnormality-label"));
|
$("#add_abnormality").appendTo($("#abnormality-label"));
|
||||||
$("#add_examination").appendTo($("#examination-label"));
|
$("#add_examination").appendTo($("#examination-label"));
|
||||||
$("#add_region").appendTo($("#region-label"));
|
$("#add_region").appendTo($("#region-label"));
|
||||||
|
|
||||||
dropContainer = document.getElementById("drop-container");
|
dropContainer = document.getElementById("drop-container");
|
||||||
|
|
||||||
dropContainer.ondragover = function (evt) {
|
dropContainer.ondragover = function (evt) {
|
||||||
evt.preventDefault();
|
evt.preventDefault();
|
||||||
evt.stopPropagation();
|
evt.stopPropagation();
|
||||||
};
|
};
|
||||||
|
|
||||||
dropContainer.ondragenter = function (evt) {
|
dropContainer.ondragenter = function (evt) {
|
||||||
console.log("ENTER")
|
console.log("ENTER")
|
||||||
console.log(evt)
|
console.log(evt)
|
||||||
$(evt.target).addClass("drop-target-active")
|
$(evt.target).addClass("drop-target-active")
|
||||||
evt.preventDefault();
|
evt.preventDefault();
|
||||||
evt.stopPropagation();
|
evt.stopPropagation();
|
||||||
};
|
};
|
||||||
|
|
||||||
dropContainer.ondragleave = function (evt) {
|
dropContainer.ondragleave = function (evt) {
|
||||||
console.log("ENTER")
|
console.log("ENTER")
|
||||||
console.log(evt)
|
console.log(evt)
|
||||||
$(evt.target).removeClass("drop-target-active")
|
$(evt.target).removeClass("drop-target-active")
|
||||||
evt.preventDefault();
|
evt.preventDefault();
|
||||||
evt.stopPropagation();
|
evt.stopPropagation();
|
||||||
};
|
};
|
||||||
|
|
||||||
dropContainer.ondrop = function (evt) {
|
dropContainer.ondrop = function (evt) {
|
||||||
$(evt.target).removeClass("drop-target-active");
|
$(evt.target).removeClass("drop-target-active");
|
||||||
|
|
||||||
file_drop_number = evt.dataTransfer.files.length;
|
file_drop_number = evt.dataTransfer.files.length;
|
||||||
|
|
||||||
if (file_drop_number < 1) {
|
if (file_drop_number < 1) {
|
||||||
toastr.warning(`Drop failed (no files), try again.`);
|
toastr.warning(`Drop failed (no files), try again.`);
|
||||||
} else {
|
} else {
|
||||||
toastr.info(`Loading ${file_drop_number} dropped image(s).`);
|
toastr.info(`Loading ${file_drop_number} dropped image(s).`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get all input elements
|
// Get all input elements
|
||||||
inputs = extendInputs("rapid-form", file_drop_number);
|
inputs = extendInputs("rapid-form", file_drop_number);
|
||||||
|
|
||||||
console.log("drop inputs", inputs, evt);
|
console.log("drop inputs", inputs, evt);
|
||||||
|
|
||||||
|
|
||||||
// Loop through each dropped file and try to assign to an
|
// Loop through each dropped file and try to assign to an
|
||||||
// input element
|
// input element
|
||||||
[...evt.dataTransfer.files].forEach((f) => {
|
[...evt.dataTransfer.files].forEach((f) => {
|
||||||
feedback = false;
|
feedback = false;
|
||||||
if (evt.target.id == "feedback-drop-target") {
|
if (evt.target.id == "feedback-drop-target") {
|
||||||
feedback = true;
|
feedback = true;
|
||||||
}
|
}
|
||||||
addFile(f, feedback)
|
addFile(f, feedback)
|
||||||
})
|
})
|
||||||
|
|
||||||
evt.preventDefault();
|
evt.preventDefault();
|
||||||
evt.stopPropagation();
|
evt.stopPropagation();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// $('#directory-picker-button').click(() => {
|
// $('#directory-picker-button').click(() => {
|
||||||
@@ -170,71 +170,71 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
$('#add_more_images').click(() => {
|
$('#add_more_images').click(() => {
|
||||||
add_input_form()
|
add_input_form()
|
||||||
});
|
});
|
||||||
$('#add_more_answers').click(() => {
|
$('#add_more_answers').click(() => {
|
||||||
add_answers_input_form()
|
add_answers_input_form()
|
||||||
});
|
});
|
||||||
|
|
||||||
$("input[type=file]").on('change', input_change);
|
$("input[type=file]").on('change', input_change);
|
||||||
|
|
||||||
$("#rapid-form").on("submit", (evt) => {
|
$("#rapid-form").on("submit", (evt) => {
|
||||||
submit = true;
|
submit = true;
|
||||||
if (!$normal) {
|
if (!$normal) {
|
||||||
if ($('#id_answers-TOTAL_FORMS').val() == "0") {
|
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;
|
submit = false;
|
||||||
add_answers_input_form();
|
toastr.error("Please add examination type")
|
||||||
toastr.error(`Question that are not normal require an answer`);
|
|
||||||
evt.preventDefault();
|
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) {
|
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
|
// 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)
|
// if you attempt to parse a non dicom part 10 file (or one that is corrupted)
|
||||||
try {
|
try {
|
||||||
// parse byteArray into a DataSet object using the parseDicom library
|
// parse byteArray into a DataSet object using the parseDicom library
|
||||||
var dataSet = dicomParser.parseDicom(byteArray);
|
var dataSet = dicomParser.parseDicom(byteArray);
|
||||||
|
|
||||||
// dataSet contains the parsed elements. Each element is available via a property
|
// 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
|
// in the dataSet.elements object. The property name is based on the elements group
|
||||||
@@ -244,157 +244,156 @@
|
|||||||
// To access the data for an element, we need to know its type and its tag.
|
// 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
|
// We will get the sopInstanceUid from the file which is a string and
|
||||||
// has the tag (0020,000D)
|
// has the tag (0020,000D)
|
||||||
var study_description = dataSet.string('x00081030').toLowerCase();
|
var study_description = dataSet.string('x00081030').toLowerCase();
|
||||||
console.log("STUDY", study_description);
|
console.log("STUDY", study_description);
|
||||||
|
|
||||||
// try to match with a study description (if not already selected)
|
// try to match with a study description (if not already selected)
|
||||||
if ($(`#id_examination_to option`).length < 1) {
|
if ($(`#id_examination_to option`).length < 1) {
|
||||||
option = $(`#id_examination_from option[title*='${study_description}' i]`);
|
option = $(`#id_examination_from option[title*='${study_description}' i]`);
|
||||||
|
|
||||||
if (option.length) {
|
if (option.length) {
|
||||||
option.appendTo($("#id_examination_to"));
|
option.appendTo($("#id_examination_to"));
|
||||||
toastr.success(`Examination set to ${option.attr('title')} from dicom data`);
|
toastr.success(`Examination set to ${option.attr('title')} from dicom data`);
|
||||||
} else {
|
} else {
|
||||||
toastr.warning(
|
toastr.warning(
|
||||||
`Unable to set examination ${study_description} from dicom data (it needs creating)`);
|
`Unable to set examination ${study_description} from dicom data (it needs creating)`);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (err) {
|
|
||||||
console.log(err);
|
|
||||||
}
|
}
|
||||||
}
|
</script>
|
||||||
}
|
<script type="text/hyperscript">
|
||||||
</script>
|
init
|
||||||
<script type="text/hyperscript">
|
set global $normal to false
|
||||||
init
|
if (#id_normal_0.checked )
|
||||||
set global $normal to false
|
Fade(.abnormal-fields) then
|
||||||
if (#id_normal_0.checked )
|
set global $normal to true then
|
||||||
Fade(.abnormal-fields) then
|
|
||||||
set global $normal to true then
|
|
||||||
remove @required from <#answer_form_set textarea/> then
|
remove @required from <#answer_form_set textarea/> then
|
||||||
remove @required from <#answer_empty_form textarea.required/>
|
remove @required from <#answer_empty_form textarea.required/>
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def Fade(elt)
|
def Fade(elt)
|
||||||
if elt's style's opacity != "0"
|
if elt's style's opacity != "0"
|
||||||
transition element elt opacity to 0 over 350ms
|
transition element elt opacity to 0 over 350ms
|
||||||
transition element elt transform to "translateY(0.25rem)" over 350ms
|
transition element elt transform to "translateY(0.25rem)" over 350ms
|
||||||
hide elt
|
hide elt
|
||||||
else
|
else
|
||||||
show elt
|
show elt
|
||||||
transition element elt opacity to 1 over 350ms
|
transition element elt opacity to 1 over 350ms
|
||||||
transition element elt transform to "translateY(0rem)" over 350ms
|
transition element elt transform to "translateY(0rem)" over 350ms
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
on change from #id_normal_0
|
on change from #id_normal_0
|
||||||
if (#id_normal_0.checked )
|
if (#id_normal_0.checked )
|
||||||
Fade(.abnormal-fields) then
|
Fade(.abnormal-fields) then
|
||||||
set global $normal to true then
|
set global $normal to true then
|
||||||
remove @required from <#answer_form_set textarea/> then
|
remove @required from <#answer_form_set textarea/> then
|
||||||
remove @required from <#answer_empty_form textarea.required/>
|
remove @required from <#answer_empty_form textarea.required/>
|
||||||
end
|
end
|
||||||
on change from #id_normal_1
|
on change from #id_normal_1
|
||||||
if (#id_normal_1.checked )
|
if (#id_normal_1.checked )
|
||||||
Fade(.abnormal-fields) then
|
Fade(.abnormal-fields) then
|
||||||
set global $normal to false then
|
set global $normal to false then
|
||||||
add @required to <#answer_form_set textarea/> then
|
add @required to <#answer_form_set textarea/> then
|
||||||
add @required to <#answer_empty_form textarea.required/>
|
add @required to <#answer_empty_form textarea.required/>
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{{ form.media }}
|
{{ form.media }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
{% if object %}
|
{% if object %}
|
||||||
{% include "rapids/question_link_header.html" %}
|
{% include "rapids/question_link_header.html" %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<h2>Submit Rapid</h2>
|
<h2>Submit Rapid</h2>
|
||||||
<p>
|
<p>
|
||||||
<h3>Instructions</h3>
|
<h3>Instructions</h3>
|
||||||
Abnormality, Region and Laterality are used to categorise within the system (they are not used for marking). String
|
Abnormality, Region and Laterality are used to categorise within the system (they are not used for marking). String
|
||||||
answers that match those added below will be used for automatic marking. Multiple images can be added to a question.
|
answers that match those added below will be used for automatic marking. Multiple images can be added to a question.
|
||||||
If
|
If
|
||||||
the feedback image box is checked they will not be displayed when taking the question.
|
the feedback image box is checked they will not be displayed when taking the question.
|
||||||
</p>
|
</p>
|
||||||
<!-- <div>
|
<!-- <div>
|
||||||
To monitor a directory select it here.<br />
|
To monitor a directory select it here.<br />
|
||||||
<button id="directory-picker-button">Pick a directory</button>
|
<button id="directory-picker-button">Pick a directory</button>
|
||||||
<span id="directory-picker-display">No directory monitored</span>
|
<span id="directory-picker-display">No directory monitored</span>
|
||||||
</div> -->
|
</div> -->
|
||||||
<form action="" method="post" enctype="multipart/form-data" id="rapid-form">
|
<form action="" method="post" enctype="multipart/form-data" id="rapid-form">
|
||||||
{% comment %} {% csrf_token %} {% endcomment %}
|
{% comment %} {% csrf_token %} {% endcomment %}
|
||||||
<a href="/rapids/abnormality/create" id="add_abnormality" class="add-popup"
|
<a href="/rapids/abnormality/create" id="add_abnormality" class="add-popup"
|
||||||
onclick="return showAddPopup(this);"><img src="{% static 'img/icon-addlink.svg' %}"></a>
|
onclick="return showAddPopup(this);"><img src="{% static 'img/icon-addlink.svg' %}"></a>
|
||||||
<a href="/rapids/examination/create" id="add_examination" class="add-popup"
|
<a href="/rapids/examination/create" id="add_examination" class="add-popup"
|
||||||
onclick="return showAddPopup(this);"><img src="{% static 'img/icon-addlink.svg' %}"></a>
|
onclick="return showAddPopup(this);"><img src="{% static 'img/icon-addlink.svg' %}"></a>
|
||||||
<a href="/rapids/region/create" id="add_region" class="add-popup" onclick="return showAddPopup(this);"><img
|
<a href="/rapids/region/create" id="add_region" class="add-popup" onclick="return showAddPopup(this);"><img
|
||||||
src="{% static 'img/icon-addlink.svg' %}"></a>
|
src="{% static 'img/icon-addlink.svg' %}"></a>
|
||||||
|
|
||||||
{% crispy form form.helper %}
|
{% crispy form form.helper %}
|
||||||
|
|
||||||
<div class="abnormal-fields">
|
<div class="abnormal-fields">
|
||||||
<h3>Answers:</h3>
|
<h3>Answers:</h3>
|
||||||
<input type="button" value="Add More Answers" id="add_more_answers">
|
<input type="button" value="Add More Answers" id="add_more_answers">
|
||||||
<div id="answer_form_set">
|
<div id="answer_form_set">
|
||||||
{% for form in answer_formset %}
|
{% for form in answer_formset %}
|
||||||
<ul class="no-error answer-formset">
|
<ul class="no-error answer-formset">
|
||||||
{{form.non_field_errors}}
|
{{form.non_field_errors}}
|
||||||
{{form.errors}}
|
{{form.errors}}
|
||||||
{{ form.as_ul }}
|
{{ form.as_ul }}
|
||||||
</ul>
|
</ul>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
{{ answer_formset.management_form }}
|
{{ answer_formset.management_form }}
|
||||||
</div>
|
</div>
|
||||||
<h3>Images:</h3>
|
<h3>Images:</h3>
|
||||||
<div id="drop-container" class="drop-target">Drop images here (or use the buttons below)<div
|
<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>
|
id="feedback-drop-target">Feedback image?<br />drop those here</div>
|
||||||
<div id="drop-filenames"></div>
|
<div id="drop-filenames"></div>
|
||||||
</div>
|
</div>
|
||||||
<input type="button" value="Add More Images" id="add_more_images">
|
<input type="button" value="Add More Images" id="add_more_images">
|
||||||
<div id="image_form_set">
|
<div id="image_form_set">
|
||||||
{% for form in image_formset %}
|
{% for form in image_formset %}
|
||||||
<ul class="no-error image-formset">
|
<ul class="no-error image-formset">
|
||||||
{{form.non_field_errors}}
|
{{form.non_field_errors}}
|
||||||
{{form.errors}}
|
{{form.errors}}
|
||||||
{{ form.as_ul }}
|
{{ 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>
|
</ul>
|
||||||
{% endfor %}
|
|
||||||
</div>
|
</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>
|
<div id="single-dicom-viewer" class="rapid-dicom-viewer" data-images="" data-annotations='' style="display:none"></div>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
|
||||||
{% block css %}
|
{% block css %}
|
||||||
<style>
|
<style>
|
||||||
.add-popup {
|
.add-popup {
|
||||||
float: left;
|
float: left;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
{% endblock css %}
|
{% endblock css %}
|
||||||
|
|
||||||
@@ -5,14 +5,14 @@
|
|||||||
{% block js %}
|
{% block js %}
|
||||||
<!--<script type="text/javascript" src="/admin/jsi18n/"></script>-->
|
<!--<script type="text/javascript" src="/admin/jsi18n/"></script>-->
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
let csrf_token = "{{csrf_token}}";
|
let csrf_token = "{{csrf_token}}";
|
||||||
let hash_url = "{% url 'shorts:question_by_hash' %}";
|
let hash_url = "{% url 'shorts:question_by_hash' %}";
|
||||||
//let monitor_directory_handler = false;
|
//let monitor_directory_handler = false;
|
||||||
//let monitor_interval_id = false;
|
//let monitor_interval_id = false;
|
||||||
|
|
||||||
// set to hold the files that are still being processed
|
// set to hold the files that are still being processed
|
||||||
let load_viewer = false;
|
let load_viewer = false;
|
||||||
|
|
||||||
// async function listAllFilesAndDirs(dirHandle, files_only) {
|
// async function listAllFilesAndDirs(dirHandle, files_only) {
|
||||||
// const files = [];
|
// const files = [];
|
||||||
@@ -41,78 +41,78 @@
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
|
|
||||||
document.addEventListener('drop', function (e) {
|
document.addEventListener('drop', function (e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
}, false);
|
}, false);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function add_answers_input_form() {
|
function add_answers_input_form() {
|
||||||
var form_idx = $('#id_answers-TOTAL_FORMS').val();
|
var form_idx = $('#id_answers-TOTAL_FORMS').val();
|
||||||
$('#answer_form_set').append($('#answer_empty_form').html().replace(/__prefix__/g, form_idx));
|
$('#answer_form_set').append($('#answer_empty_form').html().replace(/__prefix__/g, form_idx));
|
||||||
$(`#id_answers-${form_idx}-status`).val(2);
|
$(`#id_answers-${form_idx}-status`).val(2);
|
||||||
$('#id_answers-TOTAL_FORMS').val(parseInt(form_idx) + 1);
|
$('#id_answers-TOTAL_FORMS').val(parseInt(form_idx) + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
$("#add_examination").appendTo($("#examination-label"));
|
$("#add_examination").appendTo($("#examination-label"));
|
||||||
|
|
||||||
dropContainer = document.getElementById("drop-container");
|
dropContainer = document.getElementById("drop-container");
|
||||||
|
|
||||||
dropContainer.ondragover = function (evt) {
|
dropContainer.ondragover = function (evt) {
|
||||||
evt.preventDefault();
|
evt.preventDefault();
|
||||||
evt.stopPropagation();
|
evt.stopPropagation();
|
||||||
};
|
};
|
||||||
|
|
||||||
dropContainer.ondragenter = function (evt) {
|
dropContainer.ondragenter = function (evt) {
|
||||||
console.log("ENTER")
|
console.log("ENTER")
|
||||||
console.log(evt)
|
console.log(evt)
|
||||||
$(evt.target).addClass("drop-target-active")
|
$(evt.target).addClass("drop-target-active")
|
||||||
evt.preventDefault();
|
evt.preventDefault();
|
||||||
evt.stopPropagation();
|
evt.stopPropagation();
|
||||||
};
|
};
|
||||||
|
|
||||||
dropContainer.ondragleave = function (evt) {
|
dropContainer.ondragleave = function (evt) {
|
||||||
console.log("ENTER")
|
console.log("ENTER")
|
||||||
console.log(evt)
|
console.log(evt)
|
||||||
$(evt.target).removeClass("drop-target-active")
|
$(evt.target).removeClass("drop-target-active")
|
||||||
evt.preventDefault();
|
evt.preventDefault();
|
||||||
evt.stopPropagation();
|
evt.stopPropagation();
|
||||||
};
|
};
|
||||||
|
|
||||||
dropContainer.ondrop = function (evt) {
|
dropContainer.ondrop = function (evt) {
|
||||||
$(evt.target).removeClass("drop-target-active");
|
$(evt.target).removeClass("drop-target-active");
|
||||||
|
|
||||||
file_drop_number = evt.dataTransfer.files.length;
|
file_drop_number = evt.dataTransfer.files.length;
|
||||||
|
|
||||||
if (file_drop_number < 1) {
|
if (file_drop_number < 1) {
|
||||||
toastr.warning(`Drop failed (no files), try again.`);
|
toastr.warning(`Drop failed (no files), try again.`);
|
||||||
} else {
|
} else {
|
||||||
toastr.info(`Loading ${file_drop_number} dropped image(s).`);
|
toastr.info(`Loading ${file_drop_number} dropped image(s).`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get all input elements
|
// Get all input elements
|
||||||
inputs = extendInputs("rapid-form", file_drop_number);
|
inputs = extendInputs("rapid-form", file_drop_number);
|
||||||
|
|
||||||
console.log("drop inputs", inputs, evt);
|
console.log("drop inputs", inputs, evt);
|
||||||
|
|
||||||
|
|
||||||
// Loop through each dropped file and try to assign to an
|
// Loop through each dropped file and try to assign to an
|
||||||
// input element
|
// input element
|
||||||
[...evt.dataTransfer.files].forEach((f) => {
|
[...evt.dataTransfer.files].forEach((f) => {
|
||||||
feedback = false;
|
feedback = false;
|
||||||
if (evt.target.id == "feedback-drop-target") {
|
if (evt.target.id == "feedback-drop-target") {
|
||||||
feedback = true;
|
feedback = true;
|
||||||
}
|
}
|
||||||
addFile(f, feedback)
|
addFile(f, feedback)
|
||||||
})
|
})
|
||||||
|
|
||||||
evt.preventDefault();
|
evt.preventDefault();
|
||||||
evt.stopPropagation();
|
evt.stopPropagation();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// $('#directory-picker-button').click(() => {
|
// $('#directory-picker-button').click(() => {
|
||||||
@@ -168,71 +168,71 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
$('#add_more_images').click(() => {
|
$('#add_more_images').click(() => {
|
||||||
add_input_form()
|
add_input_form()
|
||||||
});
|
});
|
||||||
$('#add_more_answers').click(() => {
|
$('#add_more_answers').click(() => {
|
||||||
add_answers_input_form()
|
add_answers_input_form()
|
||||||
});
|
});
|
||||||
|
|
||||||
$("input[type=file]").on('change', input_change);
|
$("input[type=file]").on('change', input_change);
|
||||||
|
|
||||||
$("#rapid-form").on("submit", (evt) => {
|
$("#rapid-form").on("submit", (evt) => {
|
||||||
submit = true;
|
submit = true;
|
||||||
if (!$normal) {
|
if (!$normal) {
|
||||||
if ($('#id_answers-TOTAL_FORMS').val() == "0") {
|
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;
|
submit = false;
|
||||||
add_answers_input_form();
|
toastr.error("Please add examination type")
|
||||||
toastr.error(`Question that are not normal require an answer`);
|
|
||||||
evt.preventDefault();
|
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) {
|
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
|
// 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)
|
// if you attempt to parse a non dicom part 10 file (or one that is corrupted)
|
||||||
try {
|
try {
|
||||||
// parse byteArray into a DataSet object using the parseDicom library
|
// parse byteArray into a DataSet object using the parseDicom library
|
||||||
var dataSet = dicomParser.parseDicom(byteArray);
|
var dataSet = dicomParser.parseDicom(byteArray);
|
||||||
|
|
||||||
// dataSet contains the parsed elements. Each element is available via a property
|
// 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
|
// in the dataSet.elements object. The property name is based on the elements group
|
||||||
@@ -242,98 +242,97 @@
|
|||||||
// To access the data for an element, we need to know its type and its tag.
|
// 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
|
// We will get the sopInstanceUid from the file which is a string and
|
||||||
// has the tag (0020,000D)
|
// has the tag (0020,000D)
|
||||||
var study_description = dataSet.string('x00081030').toLowerCase();
|
var study_description = dataSet.string('x00081030').toLowerCase();
|
||||||
console.log("STUDY", study_description);
|
console.log("STUDY", study_description);
|
||||||
|
|
||||||
// try to match with a study description (if not already selected)
|
// try to match with a study description (if not already selected)
|
||||||
if ($(`#id_examination_to option`).length < 1) {
|
if ($(`#id_examination_to option`).length < 1) {
|
||||||
option = $(`#id_examination_from option[title*='${study_description}' i]`);
|
option = $(`#id_examination_from option[title*='${study_description}' i]`);
|
||||||
|
|
||||||
if (option.length) {
|
if (option.length) {
|
||||||
option.appendTo($("#id_examination_to"));
|
option.appendTo($("#id_examination_to"));
|
||||||
toastr.success(`Examination set to ${option.attr('title')} from dicom data`);
|
toastr.success(`Examination set to ${option.attr('title')} from dicom data`);
|
||||||
} else {
|
} else {
|
||||||
toastr.warning(
|
toastr.warning(
|
||||||
`Unable to set examination ${study_description} from dicom data (it needs creating)`);
|
`Unable to set examination ${study_description} from dicom data (it needs creating)`);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (err) {
|
|
||||||
console.log(err);
|
|
||||||
}
|
}
|
||||||
}
|
</script>
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
{{ form.media }}
|
{{ form.media }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
{% if object %}
|
{% if object %}
|
||||||
{% include "shorts/question_link_header.html" %}
|
{% include "shorts/question_link_header.html" %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<h2>Submit Shorts Question</h2>
|
<h2>Submit Shorts Question</h2>
|
||||||
<h3>Instructions</h3>
|
<h3>Instructions</h3>
|
||||||
<p>
|
<p>
|
||||||
Use this form to create a new short style question/case. Multiple images can be added to a question.
|
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.
|
If the feedback image box is checked they will not be displayed when taking the question.
|
||||||
</p>
|
</p>
|
||||||
<p>Once you have created the question with this form you can add relevant findings.
|
<p>Once you have created the question with this form you can add relevant findings.
|
||||||
</p>
|
</p>
|
||||||
<!-- <div>
|
<!-- <div>
|
||||||
To monitor a directory select it here.<br />
|
To monitor a directory select it here.<br />
|
||||||
<button id="directory-picker-button">Pick a directory</button>
|
<button id="directory-picker-button">Pick a directory</button>
|
||||||
<span id="directory-picker-display">No directory monitored</span>
|
<span id="directory-picker-display">No directory monitored</span>
|
||||||
</div> -->
|
</div> -->
|
||||||
<form action="" method="post" enctype="multipart/form-data" id="rapid-form">
|
<form action="" method="post" enctype="multipart/form-data" id="rapid-form">
|
||||||
{% comment %} {% csrf_token %} {% endcomment %}
|
{% comment %} {% csrf_token %} {% endcomment %}
|
||||||
<a href="/rapids/examination/create" id="add_examination" class="add-popup"
|
<a href="/rapids/examination/create" id="add_examination" class="add-popup"
|
||||||
onclick="return showAddPopup(this);"><img src="{% static 'img/icon-addlink.svg' %}"></a>
|
onclick="return showAddPopup(this);"><img src="{% static 'img/icon-addlink.svg' %}"></a>
|
||||||
|
|
||||||
{% crispy form form.helper %}
|
{% crispy form form.helper %}
|
||||||
|
|
||||||
<h3>Images:</h3>
|
<h3>Images:</h3>
|
||||||
<div id="drop-container" class="drop-target">Drop images here (or use the buttons below)<div
|
<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>
|
id="feedback-drop-target">Feedback image?<br />drop those here</div>
|
||||||
<div id="drop-filenames"></div>
|
<div id="drop-filenames"></div>
|
||||||
</div>
|
</div>
|
||||||
<input type="button" value="Add More Images" id="add_more_images">
|
<input type="button" value="Add More Images" id="add_more_images">
|
||||||
<div id="image_form_set">
|
<div id="image_form_set">
|
||||||
{% for form in image_formset %}
|
{% for form in image_formset %}
|
||||||
<ul class="no-error image-formset">
|
<ul class="no-error image-formset">
|
||||||
{{form.non_field_errors}}
|
{{form.non_field_errors}}
|
||||||
{{form.errors}}
|
{{form.errors}}
|
||||||
{{ form.as_ul }}
|
{{ 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>
|
</ul>
|
||||||
{% endfor %}
|
|
||||||
</div>
|
</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>
|
<div id="single-dicom-viewer" class="rapid-dicom-viewer" data-images="" data-annotations='' style="display:none"></div>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
|
||||||
{% block css %}
|
{% block css %}
|
||||||
<style>
|
<style>
|
||||||
.add-popup {
|
.add-popup {
|
||||||
float: left;
|
float: left;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
{% endblock css %}
|
{% endblock css %}
|
||||||
|
|
||||||
Reference in New Issue
Block a user