Mercurial > hg > orthanc
diff OrthancServer/OrthancExplorer/explorer.js @ 4044:d25f4c0fa160 framework
splitting code into OrthancFramework and OrthancServer
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Wed, 10 Jun 2020 20:30:34 +0200 |
parents | OrthancExplorer/explorer.js@6dba4fa8a6cb |
children | 4bb7522a63e0 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancServer/OrthancExplorer/explorer.js Wed Jun 10 20:30:34 2020 +0200 @@ -0,0 +1,1570 @@ +// http://stackoverflow.com/questions/1663741/is-there-a-good-jquery-drag-and-drop-file-upload-plugin + + +// Forbid the access to IE +if ($.browser.msie) +{ + alert("Please use Mozilla Firefox or Google Chrome. Microsoft Internet Explorer is not supported."); +} + +// http://jquerymobile.com/demos/1.1.0/docs/api/globalconfig.html +//$.mobile.ajaxEnabled = false; +//$.mobile.page.prototype.options.addBackBtn = true; +//$.mobile.defaultPageTransition = 'slide'; + + +var LIMIT_RESOURCES = 100; + +var currentPage = ''; +var currentUuid = ''; + + +function DeepCopy(obj) +{ + return jQuery.extend(true, {}, obj); +} + + +function ChangePage(page, options) +{ + var first = true; + var value; + + if (options) { + for (var key in options) { + value = options[key]; + if (first) { + page += '?'; + first = false; + } else { + page += '&'; + } + + page += key + '=' + value; + } + } + + window.location.replace('explorer.html#' + page); + /*$.mobile.changePage('#' + page, { + changeHash: true + });*/ +} + + +function Refresh() +{ + if (currentPage == 'patient') + RefreshPatient(); + else if (currentPage == 'study') + RefreshStudy(); + else if (currentPage == 'series') + RefreshSeries(); + else if (currentPage == 'instance') + RefreshInstance(); +} + + +$(document).ready(function() { + var $tree = $('#dicom-tree'); + $tree.tree({ + autoEscape: false + }); + + $('#dicom-tree').bind( + 'tree.click', + function(event) { + if (event.node.is_open) + $tree.tree('closeNode', event.node, true); + else + $tree.tree('openNode', event.node, true); + } + ); + + // Inject the template of the warning about insecure setup as the + // first child of each page + var insecure = $('#template-insecure').html(); + $('[data-role="page"]>[data-role="content"]').prepend(insecure); + + currentPage = $.mobile.pageData.active; + currentUuid = $.mobile.pageData.uuid; + if (!(typeof currentPage === 'undefined') && + !(typeof currentUuid === 'undefined') && + currentPage.length > 0 && + currentUuid.length > 0) + { + Refresh(); + } +}); + +function GetAuthorizationTokensFromUrl() { + var urlVariables = window.location.search.substring(1).split('&'); + var dict = {}; + + for (var i = 0; i < urlVariables.length; i++) { + var split = urlVariables[i].split('='); + + if (split.length == 2 && (split[0] == "token" || split[0] == "auth-token" || split[0] == "authorization")) { + dict[split[0]] = split[1]; + } + } + return dict; +}; + +var authorizationTokens = GetAuthorizationTokensFromUrl(); + +/* Copy the authoziation toekn from the url search parameters into HTTP headers in every request to the Rest API. +Thanks to this behaviour, you may specify a ?token=xxx in your url and this will be passed +as the "token" header in every request to the API allowing you to use the authorization plugin */ +$.ajaxSetup( + { + headers : authorizationTokens + } +); + + +function SplitLongUid(s) +{ + return '<span>' + s.substr(0, s.length / 2) + '</span> <span>' + s.substr(s.length / 2, s.length - s.length / 2) + '</span>'; +} + + +function ParseDicomDate(s) +{ + y = parseInt(s.substr(0, 4), 10); + m = parseInt(s.substr(4, 2), 10) - 1; + d = parseInt(s.substr(6, 2), 10); + + if (y == null || m == null || d == null || + !isFinite(y) || !isFinite(m) || !isFinite(d)) + { + return null; + } + + if (y < 1900 || y > 2100 || + m < 0 || m >= 12 || + d <= 0 || d >= 32) + { + return null; + } + + return new Date(y, m, d); +} + + +function FormatDicomDate(s) +{ + if (s == undefined) + return "No date"; + + var d = ParseDicomDate(s); + if (d == null) + return '?'; + else + return d.toString('dddd, MMMM d, yyyy'); +} + +function FormatFloatSequence(s) +{ + if (s == undefined || s.length == 0) + return "-"; + + if (s.indexOf("\\") == -1) + return s; + + var oldValues = s.split("\\"); + var newValues = []; + for (var i = 0; i < oldValues.length; i++) + { + newValues.push(parseFloat(oldValues[i]).toFixed(3)); + } + return newValues.join("\\"); +} + +function Sort(arr, fieldExtractor, isInteger, reverse) +{ + var defaultValue; + if (isInteger) + defaultValue = 0; + else + defaultValue = ''; + + arr.sort(function(a, b) { + var ta = fieldExtractor(a); + var tb = fieldExtractor(b); + var order; + + if (ta == undefined) + ta = defaultValue; + + if (tb == undefined) + tb = defaultValue; + + if (isInteger) + { + ta = parseInt(ta, 10); + tb = parseInt(tb, 10); + order = ta - tb; + } + else + { + if (ta < tb) + order = -1; + else if (ta > tb) + order = 1; + else + order = 0; + } + + if (reverse) + return -order; + else + return order; + }); +} + + +function SortOnDicomTag(arr, tag, isInteger, reverse) +{ + return Sort(arr, function(a) { + return a.MainDicomTags[tag]; + }, isInteger, reverse); +} + + + +function GetResource(uri, callback) +{ + $.ajax({ + url: '..' + uri, + dataType: 'json', + async: false, + cache: false, + success: function(s) { + callback(s); + } + }); +} + + +function CompleteFormatting(node, link, isReverse, count) +{ + if (count != null) + { + node = node.add($('<span>') + .addClass('ui-li-count') + .text(count)); + } + + if (link != null) + { + node = $('<a>').attr('href', link).append(node); + + if (isReverse) + node.attr('data-direction', 'reverse') + } + + node = $('<li>').append(node); + + if (isReverse) + node.attr('data-icon', 'back'); + + return node; +} + + +function FormatMainDicomTags(target, tags, tagsToIgnore) +{ + var v; + + for (var i in tags) + { + if (tagsToIgnore.indexOf(i) == -1) + { + v = tags[i]; + + if (i == "PatientBirthDate" || + i == "StudyDate" || + i == "SeriesDate") + { + v = FormatDicomDate(v); + } + else if (i == "DicomStudyInstanceUID" || + i == "DicomSeriesInstanceUID") + { + v = SplitLongUid(v); + } + else if (i == "ImagePositionPatient" || + i == "ImageOrientationPatient") + { + v = FormatFloatSequence(v); + } + + target.append($('<p>') + .text(i + ': ') + .append($('<strong>').text(v))); + } + } +} + + +function FormatPatient(patient, link, isReverse) +{ + var node = $('<div>').append($('<h3>').text(patient.MainDicomTags.PatientName)); + + FormatMainDicomTags(node, patient.MainDicomTags, [ + "PatientName" + // "OtherPatientIDs" + ]); + + return CompleteFormatting(node, link, isReverse, patient.Studies.length); +} + + + +function FormatStudy(study, link, isReverse, includePatient) +{ + var label; + var node; + + if (includePatient) { + label = study.Label; + } else { + label = study.MainDicomTags.StudyDescription; + } + + node = $('<div>').append($('<h3>').text(label)); + + if (includePatient) { + FormatMainDicomTags(node, study.PatientMainDicomTags, [ + 'PatientName' + ]); + } + + FormatMainDicomTags(node, study.MainDicomTags, [ + 'StudyDescription', + 'StudyTime' + ]); + + return CompleteFormatting(node, link, isReverse, study.Series.length); +} + + + +function FormatSeries(series, link, isReverse) +{ + var c; + var node; + + if (series.ExpectedNumberOfInstances == null || + series.Instances.length == series.ExpectedNumberOfInstances) + { + c = series.Instances.length; + } + else + { + c = series.Instances.length + '/' + series.ExpectedNumberOfInstances; + } + + node = $('<div>') + .append($('<h3>').text(series.MainDicomTags.SeriesDescription)) + .append($('<p>').append($('<em>') + .text('Status: ') + .append($('<strong>').text(series.Status)))); + + FormatMainDicomTags(node, series.MainDicomTags, [ + "SeriesDescription", + "SeriesTime", + "Manufacturer", + "ImagesInAcquisition", + "SeriesDate", + "ImageOrientationPatient" + ]); + + return CompleteFormatting(node, link, isReverse, c); +} + + +function FormatInstance(instance, link, isReverse) +{ + var node = $('<div>').append($('<h3>').text('Instance: ' + instance.IndexInSeries)); + + FormatMainDicomTags(node, instance.MainDicomTags, [ + "AcquisitionNumber", + "InstanceNumber", + "InstanceCreationDate", + "InstanceCreationTime" + ]); + + return CompleteFormatting(node, link, isReverse); +} + + +$('[data-role="page"]').live('pagebeforeshow', function() { + $.ajax({ + url: '../system', + dataType: 'json', + async: false, + cache: false, + success: function(s) { + if (s.Name != "") { + $('.orthanc-name').html($('<a>') + .addClass('ui-link') + .attr('href', 'explorer.html') + .text(s.Name) + .append(' » ')); + } + + // New in Orthanc 1.5.8 + if ('IsHttpServerSecure' in s && + !s.IsHttpServerSecure) { + $('.warning-insecure').show(); + } else { + $('.warning-insecure').hide(); + } + } + }); +}); + + + +$('#lookup').live('pagebeforeshow', function() { + // NB: "GenerateDicomDate()" is defined in "query-retrieve.js" + var target = $('#lookup-study-date'); + $('option', target).remove(); + target.append($('<option>').attr('value', '').text('Any date')); + target.append($('<option>').attr('value', GenerateDicomDate(0)).text('Today')); + target.append($('<option>').attr('value', GenerateDicomDate(-1)).text('Yesterday')); + target.append($('<option>').attr('value', GenerateDicomDate(-7) + '-').text('Last 7 days')); + target.append($('<option>').attr('value', GenerateDicomDate(-31) + '-').text('Last 31 days')); + target.append($('<option>').attr('value', GenerateDicomDate(-31 * 3) + '-').text('Last 3 months')); + target.append($('<option>').attr('value', GenerateDicomDate(-365) + '-').text('Last year')); + target.selectmenu('refresh'); + + $('#lookup-result').hide(); +}); + + +$('#lookup-submit').live('click', function() { + var lookup; + + $('#lookup-result').hide(); + + lookup = { + 'Level' : 'Study', + 'Expand' : true, + 'Limit' : LIMIT_RESOURCES + 1, + 'Query' : { + 'StudyDate' : $('#lookup-study-date').val() + } + }; + + $('#lookup-form input').each(function(index, input) { + if (input.value.length != 0) { + if (input.id == 'lookup-patient-id') { + lookup['Query']['PatientID'] = input.value; + } + else if (input.id == 'lookup-patient-name') { + lookup['Query']['PatientName'] = input.value; + } + else if (input.id == 'lookup-accession-number') { + lookup['Query']['AccessionNumber'] = input.value; + } + else if (input.id == 'lookup-study-description') { + lookup['Query']['StudyDescription'] = input.value; + } + else { + console.error('Unknown lookup field: ' + input.id); + } + } + }); + + $.ajax({ + url: '../tools/find', + type: 'POST', + data: JSON.stringify(lookup), + dataType: 'json', + async: false, + error: function() { + alert('Error during lookup'); + }, + success: function(studies) { + FormatListOfStudies('#lookup-result ul', '#lookup-alert', '#lookup-count', studies); + $('#lookup-result').show(); + } + }); + + return false; +}); + + +$('#find-patients').live('pagebeforeshow', function() { + GetResource('/patients?expand&since=0&limit=' + (LIMIT_RESOURCES + 1), function(patients) { + var target = $('#all-patients'); + var count, showAlert, p; + + + $('li', target).remove(); + + SortOnDicomTag(patients, 'PatientName', false, false); + + if (patients.length <= LIMIT_RESOURCES) { + count = patients.length; + showAlert = false; + } + else { + count = LIMIT_RESOURCES; + showAlert = true; + } + + for (var i = 0; i < count; i++) { + p = FormatPatient(patients[i], '#patient?uuid=' + patients[i].ID); + target.append(p); + } + + target.listview('refresh'); + + if (showAlert) { + $('#count-patients').text(LIMIT_RESOURCES); + $('#alert-patients').show(); + } else { + $('#alert-patients').hide(); + } + }); +}); + + + +function FormatListOfStudies(targetId, alertId, countId, studies) +{ + var target = $(targetId); + var patient, study, s; + var count, showAlert; + + $('li', target).remove(); + + for (var i = 0; i < studies.length; i++) { + patient = studies[i].PatientMainDicomTags.PatientName; + study = studies[i].MainDicomTags.StudyDescription; + + s = ""; + if (typeof patient === 'string') { + s = patient; + } + + if (typeof study === 'string') { + if (s.length > 0) { + s += ' - '; + } + + s += study; + } + + studies[i]['Label'] = s; + } + + Sort(studies, function(a) { return a.Label }, false, false); + + if (studies.length <= LIMIT_RESOURCES) { + count = studies.length; + showAlert = false; + } + else { + count = LIMIT_RESOURCES; + showAlert = true; + } + + for (var i = 0; i < count; i++) { + s = FormatStudy(studies[i], '#study?uuid=' + studies[i].ID, false, true); + target.append(s); + } + + target.listview('refresh'); + + if (showAlert) { + $(countId).text(LIMIT_RESOURCES); + $(alertId).show(); + } else { + $(alertId).hide(); + } +} + + +$('#find-studies').live('pagebeforeshow', function() { + GetResource('/studies?expand&since=0&limit=' + (LIMIT_RESOURCES + 1), function(studies) { + FormatListOfStudies('#all-studies', '#alert-studies', '#count-studies', studies); + }); +}); + + + +function SetupAnonymizedOrModifiedFrom(buttonSelector, resource, resourceType, field) +{ + if (field in resource) + { + $(buttonSelector).closest('li').show(); + $(buttonSelector).click(function(e) { + window.location.assign('explorer.html#' + resourceType + '?uuid=' + resource[field]); + }); + } + else + { + $(buttonSelector).closest('li').hide(); + } +} + + + +function RefreshPatient() +{ + var pageData, target, v; + + if ($.mobile.pageData) { + pageData = DeepCopy($.mobile.pageData); + + GetResource('/patients/' + pageData.uuid, function(patient) { + GetResource('/patients/' + pageData.uuid + '/studies', function(studies) { + SortOnDicomTag(studies, 'StudyDate', false, true); + + $('#patient-info li').remove(); + $('#patient-info') + .append('<li data-role="list-divider">Patient</li>') + .append(FormatPatient(patient)) + .listview('refresh'); + + target = $('#list-studies'); + $('li', target).remove(); + + for (var i = 0; i < studies.length; i++) { + if (i == 0 || studies[i].MainDicomTags.StudyDate != studies[i - 1].MainDicomTags.StudyDate) + { + target.append($('<li>') + .attr('data-role', 'list-divider') + .text(FormatDicomDate(studies[i].MainDicomTags.StudyDate))); + } + + target.append(FormatStudy(studies[i], '#study?uuid=' + studies[i].ID)); + } + + SetupAnonymizedOrModifiedFrom('#patient-anonymized-from', patient, 'patient', 'AnonymizedFrom'); + SetupAnonymizedOrModifiedFrom('#patient-modified-from', patient, 'patient', 'ModifiedFrom'); + + target.listview('refresh'); + + // Check whether this patient is protected + $.ajax({ + url: '../patients/' + pageData.uuid + '/protected', + type: 'GET', + dataType: 'text', + async: false, + cache: false, + success: function (s) { + v = (s == '1') ? 'on' : 'off'; + $('#protection').val(v).slider('refresh'); + } + }); + + currentPage = 'patient'; + currentUuid = pageData.uuid; + }); + }); + } +} + + +function RefreshStudy() +{ + var pageData, target; + + if ($.mobile.pageData) { + pageData = DeepCopy($.mobile.pageData); + + GetResource('/studies/' + pageData.uuid, function(study) { + GetResource('/patients/' + study.ParentPatient, function(patient) { + GetResource('/studies/' + pageData.uuid + '/series', function(series) { + SortOnDicomTag(series, 'SeriesDate', false, true); + + $('#study .patient-link').attr('href', '#patient?uuid=' + patient.ID); + $('#study-info li').remove(); + $('#study-info') + .append('<li data-role="list-divider">Patient</li>') + .append(FormatPatient(patient, '#patient?uuid=' + patient.ID, true)) + .append('<li data-role="list-divider">Study</li>') + .append(FormatStudy(study)) + .listview('refresh'); + + SetupAnonymizedOrModifiedFrom('#study-anonymized-from', study, 'study', 'AnonymizedFrom'); + SetupAnonymizedOrModifiedFrom('#study-modified-from', study, 'study', 'ModifiedFrom'); + + target = $('#list-series'); + $('li', target).remove(); + for (var i = 0; i < series.length; i++) { + if (i == 0 || series[i].MainDicomTags.SeriesDate != series[i - 1].MainDicomTags.SeriesDate) + { + target.append($('<li>') + .attr('data-role', 'list-divider') + .text(FormatDicomDate(series[i].MainDicomTags.SeriesDate))); + } + + target.append(FormatSeries(series[i], '#series?uuid=' + series[i].ID)); + } + target.listview('refresh'); + + currentPage = 'study'; + currentUuid = pageData.uuid; + }); + }); + }); + } +} + + +function RefreshSeries() +{ + var pageData, target; + + if ($.mobile.pageData) { + pageData = DeepCopy($.mobile.pageData); + + GetResource('/series/' + pageData.uuid, function(series) { + GetResource('/studies/' + series.ParentStudy, function(study) { + GetResource('/patients/' + study.ParentPatient, function(patient) { + GetResource('/series/' + pageData.uuid + '/instances', function(instances) { + Sort(instances, function(x) { return x.IndexInSeries; }, true, false); + + $('#series .patient-link').attr('href', '#patient?uuid=' + patient.ID); + $('#series .study-link').attr('href', '#study?uuid=' + study.ID); + + $('#series-info li').remove(); + $('#series-info') + .append('<li data-role="list-divider">Patient</li>') + .append(FormatPatient(patient, '#patient?uuid=' + patient.ID, true)) + .append('<li data-role="list-divider">Study</li>') + .append(FormatStudy(study, '#study?uuid=' + study.ID, true)) + .append('<li data-role="list-divider">Series</li>') + .append(FormatSeries(series)) + .listview('refresh'); + + SetupAnonymizedOrModifiedFrom('#series-anonymized-from', series, 'series', 'AnonymizedFrom'); + SetupAnonymizedOrModifiedFrom('#series-modified-from', series, 'series', 'ModifiedFrom'); + + target = $('#list-instances'); + $('li', target).remove(); + for (var i = 0; i < instances.length; i++) { + target.append(FormatInstance(instances[i], '#instance?uuid=' + instances[i].ID)); + } + target.listview('refresh'); + + currentPage = 'series'; + currentUuid = pageData.uuid; + }); + }); + }); + }); + } +} + + +function EscapeHtml(value) +{ + var ENTITY_MAP = { + '&': '&', + '<': '<', + '>': '>', + '"': '"', + "'": ''', + '/': '/', + '`': '`', + '=': '=' + }; + + return String(value).replace(/[&<>"'`=\/]/g, function (s) { + return ENTITY_MAP[s]; + }); +} + + +function ConvertForTree(dicom) +{ + var result = []; + var label, c; + + for (var i in dicom) { + if (dicom[i] != null) { + label = (i + '<span class="tag-name"> (<i>' + + EscapeHtml(dicom[i]["Name"]) + + '</i>)</span>: '); + + if (dicom[i]["Type"] == 'String') + { + result.push({ + label: label + '<strong>' + EscapeHtml(dicom[i]["Value"]) + '</strong>', + children: [] + }); + } + else if (dicom[i]["Type"] == 'TooLong') + { + result.push({ + label: label + '<i>Too long</i>', + children: [] + }); + } + else if (dicom[i]["Type"] == 'Null') + { + result.push({ + label: label + '<i>Null</i>', + children: [] + }); + } + else if (dicom[i]["Type"] == 'Sequence') + { + c = []; + for (var j = 0; j < dicom[i]["Value"].length; j++) { + c.push({ + label: 'Item ' + j, + children: ConvertForTree(dicom[i]["Value"][j]) + }); + } + + result.push({ + label: label + '[]', + children: c + }); + } + } + } + + return result; +} + + +function RefreshInstance() +{ + var pageData; + + if ($.mobile.pageData) { + pageData = DeepCopy($.mobile.pageData); + + GetResource('/instances/' + pageData.uuid, function(instance) { + GetResource('/series/' + instance.ParentSeries, function(series) { + GetResource('/studies/' + series.ParentStudy, function(study) { + GetResource('/patients/' + study.ParentPatient, function(patient) { + + $('#instance .patient-link').attr('href', '#patient?uuid=' + patient.ID); + $('#instance .study-link').attr('href', '#study?uuid=' + study.ID); + $('#instance .series-link').attr('href', '#series?uuid=' + series.ID); + + $('#instance-info li').remove(); + $('#instance-info') + .append('<li data-role="list-divider">Patient</li>') + .append(FormatPatient(patient, '#patient?uuid=' + patient.ID, true)) + .append('<li data-role="list-divider">Study</li>') + .append(FormatStudy(study, '#study?uuid=' + study.ID, true)) + .append('<li data-role="list-divider">Series</li>') + .append(FormatSeries(series, '#series?uuid=' + series.ID, true)) + .append('<li data-role="list-divider">Instance</li>') + .append(FormatInstance(instance)) + .listview('refresh'); + + GetResource('/instances/' + instance.ID + '/tags', function(s) { + $('#dicom-tree').tree('loadData', ConvertForTree(s)); + }); + + SetupAnonymizedOrModifiedFrom('#instance-anonymized-from', instance, 'instance', 'AnonymizedFrom'); + SetupAnonymizedOrModifiedFrom('#instance-modified-from', instance, 'instance', 'ModifiedFrom'); + + currentPage = 'instance'; + currentUuid = pageData.uuid; + }); + }); + }); + }); + } +} + +$(document).live('pagebeforehide', function() { + currentPage = ''; + currentUuid = ''; +}); + + + +$('#patient').live('pagebeforeshow', RefreshPatient); +$('#study').live('pagebeforeshow', RefreshStudy); +$('#series').live('pagebeforeshow', RefreshSeries); +$('#instance').live('pagebeforeshow', RefreshInstance); + +$(function() { + $(window).hashchange(function(e, data) { + // This fixes the navigation with the back button and with the anonymization + if ('uuid' in $.mobile.pageData && + currentPage == $.mobile.pageData.active && + currentUuid != $.mobile.pageData.uuid) { + Refresh(); + } + }); +}); + + + + + +function DeleteResource(path) +{ + $.ajax({ + url: path, + type: 'DELETE', + dataType: 'json', + async: false, + success: function(s) { + var ancestor = s.RemainingAncestor; + if (ancestor == null) + $.mobile.changePage('#lookup'); + else + $.mobile.changePage('#' + ancestor.Type.toLowerCase() + '?uuid=' + ancestor.ID); + } + }); +} + + + +function OpenDeleteResourceDialog(path, title) +{ + $(document).simpledialog2({ + // http://dev.jtsage.com/jQM-SimpleDialog/demos2/ + // http://dev.jtsage.com/jQM-SimpleDialog/demos2/options.html + mode: 'button', + animate: false, + headerText: title, + headerClose: true, + width: '500px', + buttons : { + 'OK': { + click: function () { + DeleteResource(path); + }, + icon: "delete", + theme: "c" + }, + 'Cancel': { + click: function () { + } + } + } + }); +} + + + +$('#instance-delete').live('click', function() { + OpenDeleteResourceDialog('../instances/' + $.mobile.pageData.uuid, + 'Delete this instance?'); +}); + +$('#study-delete').live('click', function() { + OpenDeleteResourceDialog('../studies/' + $.mobile.pageData.uuid, + 'Delete this study?'); +}); + +$('#series-delete').live('click', function() { + OpenDeleteResourceDialog('../series/' + $.mobile.pageData.uuid, + 'Delete this series?'); +}); + +$('#patient-delete').live('click', function() { + OpenDeleteResourceDialog('../patients/' + $.mobile.pageData.uuid, + 'Delete this patient?'); +}); + + +$('#instance-download-dicom').live('click', function(e) { + // http://stackoverflow.com/a/1296101 + e.preventDefault(); //stop the browser from following + window.location.href = '../instances/' + $.mobile.pageData.uuid + '/file'; +}); + +$('#instance-download-json').live('click', function(e) { + // http://stackoverflow.com/a/1296101 + e.preventDefault(); //stop the browser from following + window.location.href = '../instances/' + $.mobile.pageData.uuid + '/tags'; +}); + + + +$('#instance-preview').live('click', function(e) { + var pageData, pdf, images; + + if ($.mobile.pageData) { + pageData = DeepCopy($.mobile.pageData); + + pdf = '../instances/' + pageData.uuid + '/pdf'; + $.ajax({ + url: pdf, + cache: false, + success: function(s) { + window.location.assign(pdf); + }, + error: function() { + GetResource('/instances/' + pageData.uuid + '/frames', function(frames) { + if (frames.length == 1) + { + // Viewing a single-frame image + jQuery.slimbox('../instances/' + pageData.uuid + '/preview', '', { + overlayFadeDuration : 1, + resizeDuration : 1, + imageFadeDuration : 1 + }); + } + else + { + // Viewing a multi-frame image + + images = []; + for (var i = 0; i < frames.length; i++) { + images.push([ '../instances/' + pageData.uuid + '/frames/' + i + '/preview' ]); + } + + jQuery.slimbox(images, 0, { + overlayFadeDuration : 1, + resizeDuration : 1, + imageFadeDuration : 1, + loop : true + }); + } + }); + } + }); + } +}); + + + +$('#series-preview').live('click', function(e) { + var pageData, images; + + if ($.mobile.pageData) { + pageData = DeepCopy($.mobile.pageData); + + GetResource('/series/' + pageData.uuid, function(series) { + GetResource('/series/' + pageData.uuid + '/instances', function(instances) { + Sort(instances, function(x) { return x.IndexInSeries; }, true, false); + + images = []; + for (var i = 0; i < instances.length; i++) { + images.push([ '../instances/' + instances[i].ID + '/preview', + (i + 1).toString() + '/' + instances.length.toString() ]) + } + + jQuery.slimbox(images, 0, { + overlayFadeDuration : 1, + resizeDuration : 1, + imageFadeDuration : 1, + loop : true + }); + }); + }); + } +}); + + + + + +function ChooseDicomModality(callback) +{ + var clickedModality = ''; + var clickedPeer = ''; + var items = $('<ul>') + .attr('data-divider-theme', 'd') + .attr('data-role', 'listview'); + + // Retrieve the list of the known DICOM modalities + $.ajax({ + url: '../modalities', + type: 'GET', + dataType: 'json', + async: false, + cache: false, + success: function(modalities) { + var name, item; + + if (modalities.length > 0) + { + items.append('<li data-role="list-divider">DICOM modalities</li>'); + + for (var i = 0; i < modalities.length; i++) { + name = modalities[i]; + item = $('<li>') + .html('<a href="#" rel="close">' + name + '</a>') + .attr('name', name) + .click(function() { + clickedModality = $(this).attr('name'); + }); + items.append(item); + } + } + + // Retrieve the list of the known Orthanc peers + $.ajax({ + url: '../peers', + type: 'GET', + dataType: 'json', + async: false, + cache: false, + success: function(peers) { + var name, item; + + if (peers.length > 0) + { + items.append('<li data-role="list-divider">Orthanc peers</li>'); + + for (var i = 0; i < peers.length; i++) { + name = peers[i]; + item = $('<li>') + .html('<a href="#" rel="close">' + name + '</a>') + .attr('name', name) + .click(function() { + clickedPeer = $(this).attr('name'); + }); + items.append(item); + } + } + + // Launch the dialog + $('#dialog').simpledialog2({ + mode: 'blank', + animate: false, + headerText: 'Choose target', + headerClose: true, + forceInput: false, + width: '100%', + blankContent: items, + callbackClose: function() { + var timer; + function WaitForDialogToClose() { + if (!$('#dialog').is(':visible')) { + clearInterval(timer); + callback(clickedModality, clickedPeer); + } + } + timer = setInterval(WaitForDialogToClose, 100); + } + }); + } + }); + } + }); +} + + +$('#instance-store,#series-store,#study-store,#patient-store').live('click', function(e) { + ChooseDicomModality(function(modality, peer) { + var pageData = DeepCopy($.mobile.pageData); + var url, loading; + + if (modality != '') + { + url = '../modalities/' + modality + '/store'; + loading = '#dicom-store'; + } + + if (peer != '') + { + url = '../peers/' + peer + '/store'; + loading = '#peer-store'; + } + + if (url != '') { + $.ajax({ + url: url, + type: 'POST', + dataType: 'text', + data: pageData.uuid, + async: true, // Necessary to block UI + beforeSend: function() { + $.blockUI({ message: $(loading) }); + }, + complete: function(s) { + $.unblockUI(); + }, + success: function(s) { + }, + error: function() { + alert('Error during store'); + } + }); + } + }); +}); + + +$('#show-tag-name').live('change', function(e) { + var checked = e.currentTarget.checked; + if (checked) + $('.tag-name').show(); + else + $('.tag-name').hide(); +}); + + +$('#patient-archive').live('click', function(e) { + e.preventDefault(); //stop the browser from following + window.location.href = '../patients/' + $.mobile.pageData.uuid + '/archive'; +}); + +$('#study-archive').live('click', function(e) { + e.preventDefault(); //stop the browser from following + window.location.href = '../studies/' + $.mobile.pageData.uuid + '/archive'; +}); + +$('#series-archive').live('click', function(e) { + e.preventDefault(); //stop the browser from following + window.location.href = '../series/' + $.mobile.pageData.uuid + '/archive'; +}); + + +$('#patient-media').live('click', function(e) { + e.preventDefault(); //stop the browser from following + window.location.href = '../patients/' + $.mobile.pageData.uuid + '/media'; +}); + +$('#study-media').live('click', function(e) { + e.preventDefault(); //stop the browser from following + window.location.href = '../studies/' + $.mobile.pageData.uuid + '/media'; +}); + +$('#series-media').live('click', function(e) { + e.preventDefault(); //stop the browser from following + window.location.href = '../series/' + $.mobile.pageData.uuid + '/media'; +}); + + + +$('#protection').live('change', function(e) { + var isProtected = e.target.value == "on"; + $.ajax({ + url: '../patients/' + $.mobile.pageData.uuid + '/protected', + type: 'PUT', + dataType: 'text', + data: isProtected ? '1' : '0', + async: false + }); +}); + + + +function OpenAnonymizeResourceDialog(path, title) +{ + $(document).simpledialog2({ + mode: 'button', + animate: false, + headerText: title, + headerClose: true, + width: '500px', + buttons : { + 'OK': { + click: function () { + $.ajax({ + url: path + '/anonymize', + type: 'POST', + data: '{ "Keep" : [ "SeriesDescription", "StudyDescription" ] }', + dataType: 'json', + async: false, + cache: false, + success: function(s) { + // The following line does not work... + //$.mobile.changePage('explorer.html#patient?uuid=' + s.PatientID); + + window.location.assign('explorer.html#patient?uuid=' + s.PatientID); + //window.location.reload(); + } + }); + }, + icon: "delete", + theme: "c" + }, + 'Cancel': { + click: function () { + } + } + } + }); +} + +$('#instance-anonymize').live('click', function() { + OpenAnonymizeResourceDialog('../instances/' + $.mobile.pageData.uuid, + 'Anonymize this instance?'); +}); + +$('#study-anonymize').live('click', function() { + OpenAnonymizeResourceDialog('../studies/' + $.mobile.pageData.uuid, + 'Anonymize this study?'); +}); + +$('#series-anonymize').live('click', function() { + OpenAnonymizeResourceDialog('../series/' + $.mobile.pageData.uuid, + 'Anonymize this series?'); +}); + +$('#patient-anonymize').live('click', function() { + OpenAnonymizeResourceDialog('../patients/' + $.mobile.pageData.uuid, + 'Anonymize this patient?'); +}); + + +$('#plugins').live('pagebeforeshow', function() { + $.ajax({ + url: '../plugins', + dataType: 'json', + async: false, + cache: false, + success: function(plugins) { + var target = $('#all-plugins'); + $('li', target).remove(); + + plugins.map(function(id) { + return $.ajax({ + url: '../plugins/' + id, + dataType: 'json', + async: false, + cache: false, + success: function(plugin) { + var li = $('<li>'); + var item = li; + + if ('RootUri' in plugin) + { + item = $('<a>'); + li.append(item); + item.click(function() { + window.open(plugin.RootUri); + }); + } + + item.append($('<h1>').text(plugin.ID)); + item.append($('<p>').text(plugin.Description)); + item.append($('<span>').addClass('ui-li-count').text(plugin.Version)); + target.append(li); + } + }); + }); + + target.listview('refresh'); + } + }); +}); + + + +function ParseJobTime(s) +{ + var t = (s.substr(0, 4) + '-' + + s.substr(4, 2) + '-' + + s.substr(6, 5) + ':' + + s.substr(11, 2) + ':' + + s.substr(13)); + var utc = new Date(t); + + // Convert from UTC to local time + return new Date(utc.getTime() - utc.getTimezoneOffset() * 60000); +} + + +function AddJobField(target, description, field) +{ + if (!(typeof field === 'undefined')) { + target.append($('<p>') + .text(description) + .append($('<strong>').text(field))); + } +} + + +function AddJobDateField(target, description, field) +{ + if (!(typeof field === 'undefined')) { + target.append($('<p>') + .text(description) + .append($('<strong>').text(ParseJobTime(field)))); + } +} + + +$('#jobs').live('pagebeforeshow', function() { + $.ajax({ + url: '../jobs?expand', + dataType: 'json', + async: false, + cache: false, + success: function(jobs) { + var target = $('#all-jobs'); + var running, pending, inactive; + + $('li', target).remove(); + + running = $('<li>') + .attr('data-role', 'list-divider') + .text('Currently running'); + + pending = $('<li>') + .attr('data-role', 'list-divider') + .text('Pending jobs'); + + inactive = $('<li>') + .attr('data-role', 'list-divider') + .text('Inactive jobs'); + + target.append(running); + target.append(pending); + target.append(inactive); + + jobs.map(function(job) { + var li = $('<li>'); + var item = $('<a>'); + + li.append(item); + item.attr('href', '#job?uuid=' + job.ID); + item.append($('<h1>').text(job.Type)); + item.append($('<span>').addClass('ui-li-count').text(job.State)); + AddJobField(item, 'ID: ', job.ID); + AddJobField(item, 'Local AET: ', job.Content.LocalAet); + AddJobField(item, 'Remote AET: ', job.Content.RemoteAet); + AddJobDateField(item, 'Creation time: ', job.CreationTime); + AddJobDateField(item, 'Completion time: ', job.CompletionTime); + AddJobDateField(item, 'ETA: ', job.EstimatedTimeOfArrival); + + if (job.State == 'Running' || + job.State == 'Pending' || + job.State == 'Paused') { + AddJobField(item, 'Priority: ', job.Priority); + AddJobField(item, 'Progress: ', job.Progress); + } + + if (job.State == 'Running') { + li.insertAfter(running); + } else if (job.State == 'Pending' || + job.State == 'Paused') { + li.insertAfter(pending); + } else { + li.insertAfter(inactive); + } + }); + + target.listview('refresh'); + } + }); +}); + + +$('#job').live('pagebeforeshow', function() { + var pageData, target; + + if ($.mobile.pageData) { + pageData = DeepCopy($.mobile.pageData); + + $.ajax({ + url: '../jobs/' + pageData.uuid, + dataType: 'json', + async: false, + cache: false, + success: function(job) { + var block, value; + + target = $('#job-info'); + $('li', target).remove(); + + target.append($('<li>') + .attr('data-role', 'list-divider') + .text('General information about the job')); + + { + block = $('<li>'); + for (var i in job) { + if (i == 'CreationTime' || + i == 'CompletionTime' || + i == 'EstimatedTimeOfArrival') { + AddJobDateField(block, i + ': ', job[i]); + } else if (i != 'InternalContent' && + i != 'Content' && + i != 'Timestamp') { + AddJobField(block, i + ': ', job[i]); + } + } + } + + target.append(block); + + target.append($('<li>') + .attr('data-role', 'list-divider') + .text('Detailed information')); + + { + block = $('<li>'); + + for (var item in job.Content) { + var value = job.Content[item]; + if (typeof value !== 'string') { + value = JSON.stringify(value); + } + + AddJobField(block, item + ': ', value); + } + } + + target.append(block); + + target.listview('refresh'); + + $('#job-cancel').closest('.ui-btn').hide(); + $('#job-resubmit').closest('.ui-btn').hide(); + $('#job-pause').closest('.ui-btn').hide(); + $('#job-resume').closest('.ui-btn').hide(); + + if (job.State == 'Running' || + job.State == 'Pending' || + job.State == 'Retry') { + $('#job-cancel').closest('.ui-btn').show(); + $('#job-pause').closest('.ui-btn').show(); + } + else if (job.State == 'Success') { + } + else if (job.State == 'Failure') { + $('#job-resubmit').closest('.ui-btn').show(); + } + else if (job.State == 'Paused') { + $('#job-resume').closest('.ui-btn').show(); + } + } + }); + } +}); + + + +function TriggerJobAction(action) +{ + $.ajax({ + url: '../jobs/' + $.mobile.pageData.uuid + '/' + action, + type: 'POST', + async: false, + cache: false, + complete: function(s) { + window.location.reload(); + } + }); +} + +$('#job-cancel').live('click', function() { + TriggerJobAction('cancel'); +}); + +$('#job-resubmit').live('click', function() { + TriggerJobAction('resubmit'); +}); + +$('#job-pause').live('click', function() { + TriggerJobAction('pause'); +}); + +$('#job-resume').live('click', function() { + TriggerJobAction('resume'); +});