765 lines
27 KiB
HTML
Executable File
765 lines
27 KiB
HTML
Executable File
{% extends "rapids/base.html" %}
|
|
{% load static from static %}
|
|
|
|
{% block js %}
|
|
<!--<script type="text/javascript" src="/admin/jsi18n/"></script>-->
|
|
|
|
<script type="text/javascript">
|
|
let normal = false;
|
|
let monitor_directory_handler = false;
|
|
let monitor_interval_id = false;
|
|
|
|
// set to hold the files that are still being processed
|
|
let active_file_inputs = new Set()
|
|
|
|
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;
|
|
}
|
|
|
|
function showEditPopup(url) {
|
|
var win = window.open(url, "Edit",
|
|
'height=500,width=800,resizable=yes,scrollbars=yes');
|
|
return false;
|
|
}
|
|
|
|
function showAddPopup(triggeringLink) {
|
|
var name = triggeringLink.id.replace(/^add_/, '');
|
|
href = triggeringLink.href;
|
|
var win = window.open(href, name, 'height=500,width=800,resizable=yes,scrollbars=yes');
|
|
win.focus();
|
|
return false;
|
|
}
|
|
|
|
function closePopup(win, newID, newRepr, id) {
|
|
$(id + "_to").append('<option value=' + newID + ' title=' + newRepr + ' >' + newRepr + '</option>')
|
|
win.close();
|
|
}
|
|
|
|
document.addEventListener('drop', function (e) {
|
|
e.preventDefault();
|
|
}, false);
|
|
|
|
function getUnusedInputs(inputs) {
|
|
new_inputs = [];
|
|
for (let i = 0; i < inputs.length; i++) {
|
|
input = inputs.get(i);
|
|
|
|
if (!input.value) {
|
|
new_inputs.push(input);
|
|
}
|
|
|
|
}
|
|
|
|
return $(new_inputs);
|
|
|
|
}
|
|
|
|
function getCurrentFiles() {
|
|
inputs = $("#rapid-form input[type=file]");
|
|
|
|
let files = new Set();
|
|
for (let j = 0; j < inputs.length; j++) {
|
|
i = inputs.get(j);
|
|
if (i.files.length > 0) {
|
|
files.add(i.files[0]);
|
|
}
|
|
}
|
|
return files;
|
|
}
|
|
|
|
function extendInputs(n) {
|
|
// Makes sure we have n inputs available
|
|
// returns available inputs
|
|
inputs = getUnusedInputs($("#rapid-form input[type=file][id^=id_images-]"));
|
|
//fileInput = document.getElementById("id_images-0-image");
|
|
|
|
|
|
// Make sure we have enough input targets
|
|
input_diff = (n - inputs.length)
|
|
|
|
if (input_diff > 0) {
|
|
for (let j = 0; j < input_diff; j++) {
|
|
add_input_form()
|
|
}
|
|
|
|
// Need to make sure we include the new ones...
|
|
inputs = getUnusedInputs($("#rapid-form input[type=file][id^=id_images-]"));
|
|
}
|
|
return inputs;
|
|
}
|
|
|
|
function add_input_form() {
|
|
var form_idx = $('#id_images-TOTAL_FORMS').val();
|
|
$('#image_form_set').append($($('#empty_form').html().replace(/__prefix__/g, form_idx)).on("change",
|
|
input_change));
|
|
$('#id_images-TOTAL_FORMS').val(parseInt(form_idx) + 1);
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
function input_change(evt) {
|
|
file = evt.target.files[0];
|
|
$(evt.target).removeClass("image-ident-warning");
|
|
$(evt.target).removeClass("image-ident-ok");
|
|
|
|
|
|
ocr(evt.target);
|
|
|
|
el = evt.target;
|
|
|
|
$(el).find(".temp-thumb").remove();
|
|
if (el.files.length > 0) {
|
|
extra_class = " image-ident-loading";
|
|
if ($(el).hasClass("image-ident-warning")) {
|
|
extra_class = " image-ident-warning";
|
|
} else if ($(el).hasClass("image-ident-ok")) {
|
|
extra_class = " image-ident-ok";
|
|
}
|
|
n = el.id.split("-")[1];
|
|
$(`#drop-filenames span[data-input-id='${el.id}']`).remove();
|
|
$("#drop-filenames").append(
|
|
`<span data-input-id='${el.id}'><span>${n}: ${el.files[0].name}</span><img class='uploading${extra_class}' data-input-id='${el.id}' src=${URL.createObjectURL(el.files[0])}></span>`
|
|
)
|
|
}
|
|
|
|
|
|
//readFileAndProcess();
|
|
readFileAndProcess2();
|
|
|
|
// Check if we have selected a examination type
|
|
if (!$("#id_examination_to option").length) {
|
|
|
|
// Yes we do read the file twice (here and where loading it in the viewer)
|
|
var reader = new FileReader();
|
|
reader.onload = function (file) {
|
|
var arrayBuffer = reader.result;
|
|
// Here we have the file data as an ArrayBuffer. dicomParser requires as input a
|
|
// Uint8Array so we create that here
|
|
var byteArray = new Uint8Array(arrayBuffer);
|
|
extractDicomStudyDescription(byteArray)
|
|
}
|
|
reader.readAsArrayBuffer(file);
|
|
}
|
|
|
|
|
|
}
|
|
|
|
function addFile(f, feedback) {
|
|
let dT = new DataTransfer();
|
|
dT.clearData();
|
|
dT.items.add(f);
|
|
for (let i = 0; i < inputs.length; i++) {
|
|
el = inputs.get(i);
|
|
|
|
if (el.files.length == 0) {
|
|
el.files = dT.files;
|
|
//ocr(el)
|
|
|
|
if (feedback) {
|
|
arr = el.name.split("-");
|
|
arr.splice(2, 1, "feedback_image");
|
|
feedback_el_name = arr.join("-");
|
|
|
|
$(`[name=${feedback_el_name}]`).prop("checked", true);
|
|
}
|
|
|
|
$(el).change();
|
|
return false;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
$(document).ready(function () {
|
|
$("#add_abnormality").appendTo($("label[for='id_abnormality']"));
|
|
$("#add_examination").appendTo($("label[for='id_examination']"));
|
|
$("#add_region").appendTo($("label[for='id_region']"));
|
|
|
|
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) {
|
|
console.log("SHIT", 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(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)
|
|
})
|
|
|
|
// // If you want to use some of the dropped files
|
|
// const dT = new DataTransfer();
|
|
// dT.items.add(evt.dataTransfer.files[0]);
|
|
// dT.items.add(evt.dataTransfer.files[3]);
|
|
// fileInput.files = dT.files;
|
|
|
|
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 = getCurrentFiles();
|
|
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);
|
|
|
|
|
|
|
|
function ifNormal() {
|
|
if (document.getElementById("id_normal").checked) {
|
|
$("#answer_form_set textarea").attr("required", false)
|
|
$('#answer_empty_form textarea').attr("required", false)
|
|
normal = true;
|
|
} else {
|
|
$("#answer_form_set textarea").attr("required", true)
|
|
$('#answer_empty_form textarea').attr("required", true)
|
|
normal = false;
|
|
}
|
|
}
|
|
|
|
$("#id_normal").change(() => ifNormal());
|
|
|
|
ifNormal();
|
|
|
|
$("#rapid-form").on("submit", (evt) => {
|
|
submit = true;
|
|
if (!normal) {
|
|
if ($('#id_answers-TOTAL_FORMS').val() == "0") {
|
|
submit = false;
|
|
add_answers_input_form();
|
|
toastr.error(`Please enter an answers (or select Normal)`);
|
|
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 ocr(input) {
|
|
// Tesseract.recognize(f, "eng",{ logger: m => console.log(m) }
|
|
// ).then(({ data: { text } }) => {
|
|
// console.log(text);
|
|
// l = text.toLowerCase();
|
|
// if (l.includes("accesion") || l.includes("number") || l.search(/(REF|RK9|RH8|RA9)\d+/g)) {
|
|
// console.log("SHIT", this);
|
|
// }
|
|
// })
|
|
|
|
console.log('{% static "worker.min.js" %}');
|
|
console.log('{{ STATIC_URL }}/tesseract-core.wasm.js %}');
|
|
|
|
const worker = Tesseract.createWorker({
|
|
workerPath: '{% static "worker.min.js" %}',
|
|
langPath: '{% static "" %}',
|
|
//langPath: '{{ STATIC_URL }}',
|
|
corePath: '{% static "tesseract-core.wasm.js" %}',
|
|
});
|
|
|
|
const url = URL.createObjectURL(input.files[0]);
|
|
let img = new Image;
|
|
img.src = url;
|
|
|
|
img.onload = function () {
|
|
|
|
|
|
width = img.width;
|
|
|
|
// const rectangle = { left: 0, top: 0, width: width, height: 10 }
|
|
|
|
|
|
(async () => {
|
|
await worker.load();
|
|
await worker.loadLanguage('eng');
|
|
await worker.initialize('eng');
|
|
// const { data: { text } } = await worker.recognize(input.files[0], { rectangle });
|
|
const {
|
|
data: {
|
|
text
|
|
}
|
|
} = await worker.recognize(input.files[0]);
|
|
//console.log(text);
|
|
l = text.toLowerCase();
|
|
$(`img[data-input-id='${input.id}'`).removeClass("image-ident-loading");
|
|
console.log(l);
|
|
if (l.includes("accesion") || l.includes("number") || l.search(
|
|
/(ref|rk9|rh8|ra9|rbz)\d+/g) > -1) {
|
|
console.log("SHIT", input);
|
|
$(input).addClass("image-ident-warning");
|
|
$(`img[data-input-id='${input.id}'`).addClass("image-ident-warning");
|
|
} else {
|
|
$(input).addClass("image-ident-ok");
|
|
|
|
}
|
|
|
|
await worker.terminate();
|
|
})();
|
|
}
|
|
}
|
|
|
|
async function readFileAndProcess2(callback) {
|
|
//$("#single-dicom-viewer").empty()
|
|
//images = []
|
|
//Function that returns a promise to read the file
|
|
const reader = (file) => {
|
|
return new Promise((resolve, reject) => {
|
|
const fileReader = new FileReader();
|
|
fileReader.onload = () => resolve(fileReader);
|
|
fileReader.readAsDataURL(file);
|
|
});
|
|
}
|
|
|
|
// Add file to the process list
|
|
active_file_inputs.add(el)
|
|
const readFile = (file, el) => {
|
|
reader(file).then(reader => {
|
|
console.log("12345", reader)
|
|
$(el).parent().parent().find(".temp-thumb").remove();
|
|
|
|
if (reader.result.startsWith("data:application/octet-stream;base64")) {
|
|
const element = $(`<div class='temp-thumb' src=${reader.result}></div>`).get(0)
|
|
$(el).parent().parent().prepend(element);
|
|
const imageId = cornerstoneWADOImageLoader.wadouri.fileManager.add(
|
|
file
|
|
);
|
|
cornerstone.enable(element);
|
|
cornerstone.loadAndCacheImage(imageId).then(function (image) {
|
|
cornerstone.displayImage(element, image);
|
|
cornerstone.resize(element)
|
|
|
|
});
|
|
|
|
} else {
|
|
var image = new Image();
|
|
image.title = file.name;
|
|
image.src = reader.result;
|
|
image.className = "temp-thumb";
|
|
$(el).parent().parent().prepend(image);
|
|
//images.push(reader.result);
|
|
}
|
|
|
|
active_file_inputs.delete(el)
|
|
console.log("active", active_file_inputs)
|
|
// Only load once all queued files have been processed
|
|
if (active_file_inputs.size < 1) {
|
|
loadViewer();
|
|
}
|
|
});
|
|
}
|
|
|
|
file_set = $("#image_form_set input[type=file]");
|
|
|
|
file_set.each(async (n, el) => {
|
|
if (el.files.length > 0) {
|
|
filename = el.files[0].name;
|
|
// Probably no need to await here anymore
|
|
//await readFile(el.files[0], el);
|
|
|
|
let url = URL.createObjectURL(el.files[0])
|
|
|
|
$(el).parent().parent().find(".temp-thumb").remove();
|
|
|
|
const imageId = `wadouri:${url}`;
|
|
const element = $(`<div class='temp-thumb' src=${imageId}></div>`).get(0)
|
|
$(el).parent().parent().prepend(element);
|
|
cornerstone.enable(element);
|
|
cornerstone.loadAndCacheImage(imageId).then(function (image) {
|
|
cornerstone.displayImage(element, image);
|
|
cornerstone.resize(element)
|
|
|
|
});
|
|
|
|
|
|
active_file_inputs.delete(el)
|
|
console.log("active", active_file_inputs)
|
|
// Only load once all queued files have been processed
|
|
if (active_file_inputs.size < 1) {
|
|
loadViewer();
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
async function readFileAndProcess(callback) {
|
|
//$("#single-dicom-viewer").empty()
|
|
//images = []
|
|
//Function that returns a promise to read the file
|
|
const reader = (file) => {
|
|
return new Promise((resolve, reject) => {
|
|
const fileReader = new FileReader();
|
|
fileReader.onload = () => resolve(fileReader);
|
|
fileReader.readAsDataURL(file);
|
|
});
|
|
}
|
|
|
|
// Add file to the process list
|
|
active_file_inputs.add(el)
|
|
const readFile = (file, el) => {
|
|
reader(file).then(reader => {
|
|
console.log("12345", reader)
|
|
$(el).parent().parent().find(".temp-thumb").remove();
|
|
|
|
if (reader.result.startsWith("data:application/octet-stream;base64")) {
|
|
const element = $(`<div class='temp-thumb' src=${reader.result}></div>`).get(0)
|
|
$(el).parent().parent().prepend(element);
|
|
const imageId = cornerstoneWADOImageLoader.wadouri.fileManager.add(
|
|
file
|
|
);
|
|
cornerstone.enable(element);
|
|
cornerstone.loadAndCacheImage(imageId).then(function (image) {
|
|
cornerstone.displayImage(element, image);
|
|
cornerstone.resize(element)
|
|
|
|
});
|
|
|
|
} else {
|
|
var image = new Image();
|
|
image.title = file.name;
|
|
image.src = reader.result;
|
|
image.className = "temp-thumb";
|
|
$(el).parent().parent().prepend(image);
|
|
//images.push(reader.result);
|
|
}
|
|
|
|
active_file_inputs.delete(el)
|
|
console.log("active", active_file_inputs)
|
|
// Only load once all queued files have been processed
|
|
if (active_file_inputs.size < 1) {
|
|
loadViewer();
|
|
}
|
|
});
|
|
}
|
|
|
|
file_set = $("#image_form_set input[type=file]");
|
|
|
|
file_set.each(async (n, el) => {
|
|
if (el.files.length > 0) {
|
|
filename = el.files[0].name;
|
|
// Probably no need to await here anymore
|
|
await readFile(el.files[0], el);
|
|
}
|
|
})
|
|
}
|
|
|
|
function loadViewer() {
|
|
console.log("LOAD VIEWER")
|
|
// temp fix before starting viewer collapsed
|
|
$("#single-dicom-viewer").show()
|
|
//file_set = $("#image_form_set input[type=file]");
|
|
|
|
//n = 0;
|
|
//for (let i = 0; i < file_set.length; i++) {
|
|
// el = file_set.get(i)
|
|
// if (el.files.length > 0) {
|
|
// n++;
|
|
// }
|
|
//}
|
|
|
|
image_set = $("#image_form_set .temp-thumb").get()//.map(function() { return $(this).attr("src")}).get();
|
|
console.log(image_set);
|
|
//console.log()
|
|
//if (n == image_set.length) {
|
|
const event = new CustomEvent('loadDicomViewer', {
|
|
"detail": image_set
|
|
});
|
|
|
|
window.dispatchEvent(event);
|
|
sortable('.sortable');
|
|
//sortable('.sortable')[0].addEventListener('sortstop', function(e) {
|
|
updateImagePositions();
|
|
//}
|
|
|
|
}
|
|
|
|
function updateImagePositions() {
|
|
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)
|
|
|
|
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 (file_element.files.length > 0) {
|
|
file_name = file_element.files[0].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);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
function extractDicomStudyDescription(byteArray) {
|
|
// 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 %}
|
|
<h2>Submit Rapid</h2>
|
|
<a href="{% url 'rapids:rapid_create_defaults' %}">Edit defaults</a>
|
|
<p>
|
|
<h3>Instructions</h3>
|
|
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.
|
|
If
|
|
the feedback image box is checked they will not be displayed when taking the question.
|
|
</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">
|
|
{% csrf_token %}
|
|
<a href="/rapids/abnormality/create" id="add_abnormality" class="add-popup"
|
|
onclick="return showAddPopup(this);"><img src="{% static '/img/icon-addlink.svg' %}"></a>
|
|
<a href="/rapids/examination/create" id="add_examination" class="add-popup"
|
|
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
|
|
src="{% static '/img/icon-addlink.svg' %}"></a>
|
|
|
|
<table>
|
|
{{ form.as_table }}
|
|
</table>
|
|
<h3>Answers:</h3>
|
|
<input type="button" value="Add More Answers" id="add_more_answers">
|
|
<div id="answer_form_set">
|
|
{% for form in answer_formset %}
|
|
<ul class="no-error answer-formset">
|
|
{{form.non_field_errors}}
|
|
{{form.errors}}
|
|
{{ form.as_ul }}
|
|
</ul>
|
|
{% endfor %}
|
|
</div>
|
|
{{ answer_formset.management_form }}
|
|
<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">
|
|
<input type="submit" class="submit-button" value="Submit and Clone" name="submit-clone">
|
|
</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 %} |