396 lines
14 KiB
HTML
Executable File
396 lines
14 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">
|
|
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) {
|
|
console.log(id)
|
|
$(id + "_to").append('<option value=' + newID + ' title=' + newRepr + ' >' + newRepr + '</option>')
|
|
win.close();
|
|
}
|
|
|
|
document.addEventListener('drop', function (e) { e.preventDefault(); }, false);
|
|
|
|
function add_input_form() {
|
|
var form_idx = $('#id_images-TOTAL_FORMS').val();
|
|
$('#image_form_set').append($('#empty_form').html().replace(/__prefix__/g, form_idx));
|
|
$('#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);
|
|
}
|
|
|
|
|
|
$(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");
|
|
|
|
// Get all input elements
|
|
inputs = $("#rapid-form input[type=file][id^=id_images-]");
|
|
//fileInput = document.getElementById("id_images-0-image");
|
|
|
|
// Make sure we have enough input targets
|
|
input_diff = (evt.dataTransfer.files.length - inputs.length)
|
|
console.log("diff", input_diff)
|
|
|
|
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 = $("#rapid-form input[type=file][id^=id_images-]");
|
|
}
|
|
|
|
// Loop through each dropped file and try to assign to an
|
|
// input element
|
|
[...evt.dataTransfer.files].forEach((f) => {
|
|
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(evt.target.id == "feedback-drop-target") {
|
|
arr = el.name.split("-");
|
|
arr.splice(2, 1, "feedback_image");
|
|
feedback_el_name = arr.join("-");
|
|
|
|
$(`[name=${feedback_el_name}]`).prop("checked", true);
|
|
}
|
|
return false
|
|
}
|
|
}
|
|
})
|
|
|
|
// // 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;
|
|
loadDicomViewer();
|
|
|
|
evt.preventDefault();
|
|
evt.stopPropagation();
|
|
updateFileList();
|
|
};
|
|
|
|
|
|
$('#add_more_images').click(() => { add_input_form() });
|
|
$('#add_more_answers').click(() => { add_answers_input_form() });
|
|
|
|
function updateFileList() {
|
|
$("#drop-filenames").empty()
|
|
$("#image_form_set input[type=file]").each((n, el) => {
|
|
console.log(el);
|
|
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"
|
|
}
|
|
$("#drop-filenames").append(
|
|
`<span>${n}: ${el.files[0].name}</span><img class='uploading${extra_class}' data-input-id='${el.id}' src=${URL.createObjectURL(el.files[0])}>`
|
|
)
|
|
}
|
|
})
|
|
|
|
}
|
|
|
|
$("input[type=file]").on('change', function () {
|
|
$(this).removeClass("image-ident-warning");
|
|
$(this).removeClass("image-ident-ok");
|
|
updateFileList();
|
|
console.log("input change1");
|
|
console.log("input change", this);
|
|
ocr(this);
|
|
});
|
|
|
|
|
|
|
|
function ifNormal(){
|
|
if (document.getElementById("id_normal").checked){
|
|
$("#answer_form_set textarea").attr("required", false)
|
|
} else {
|
|
$("#answer_form_set textarea").attr("required", true)
|
|
}
|
|
}
|
|
|
|
$("#id_normal").change(() => ifNormal());
|
|
|
|
ifNormal();
|
|
|
|
|
|
|
|
|
|
});
|
|
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 loadDicomViewer(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);
|
|
});
|
|
}
|
|
|
|
const readFile = (file, el) => {
|
|
reader(file).then(reader => {
|
|
var image = new Image();
|
|
image.height = 100;
|
|
image.title = file.name;
|
|
image.src = reader.result;
|
|
image.className = "temp-thumb";
|
|
console.log("read" ,el);
|
|
$(el).parent().parent().prepend(image);
|
|
//images.push(reader.result);
|
|
loadViewer();
|
|
});
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
}
|
|
})
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
function loadViewer() {
|
|
//dicomViewer.loadCornerstone($("#single-dicom-viewer"), null, images, annotations);
|
|
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 img");
|
|
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);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
</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>
|
|
<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=''></div>
|
|
|
|
{% endblock %} |