diff --git a/Packages/lesiontracker/client/components/studyAssociationTable/studyAssociationTable.html b/Packages/lesiontracker/client/components/studyAssociationTable/studyAssociationTable.html index 3be25e148..fadcaa8b2 100644 --- a/Packages/lesiontracker/client/components/studyAssociationTable/studyAssociationTable.html +++ b/Packages/lesiontracker/client/components/studyAssociationTable/studyAssociationTable.html @@ -4,6 +4,8 @@

Instructions

Associate the selected studies with timepoints in the clinical trial.

+

We have automatically retrieved all studies within 14 days ({{formatDA earliestDate}} to {{formatDA latestDate}}) of your selected studies, in case you forgot to + select a study.

@@ -12,6 +14,7 @@ Include Study? Study Date + Patient Name Study Description Timepoint Type @@ -21,25 +24,34 @@ {{ #each relevantStudies }} - + - + {{ #if autoselected}}

+ data-toggle="tooltip" + title="This study was autoselected."> {{formatDA studyDate}}

{{ else }}

{{formatDA studyDate}}

{{ /if }} - + +

{{formatPN patientName}}

+ +

{{studyDescription}}

- + {{ #each timepointOptions }} - + {{ /each }} diff --git a/Packages/lesiontracker/client/components/studyAssociationTable/studyAssociationTable.js b/Packages/lesiontracker/client/components/studyAssociationTable/studyAssociationTable.js index df0a69ee2..001c34f8e 100644 --- a/Packages/lesiontracker/client/components/studyAssociationTable/studyAssociationTable.js +++ b/Packages/lesiontracker/client/components/studyAssociationTable/studyAssociationTable.js @@ -1,5 +1,72 @@ -function autoSelectStudies() { - return []; +/** + * Finds related studies within defined time window of =/- 14 days of selected studies + * @param selectedStudies + * @param range Object + */ +function getDateRange(selectedStudies, range) { + if (range === undefined) { + range = { + days: 14 + }; + } + + if (!selectedStudies.length) { + return; + } + + var earliestStudy = selectedStudies[0]; + var latestStudy = selectedStudies[selectedStudies.length - 1]; + + var earliestDate = moment(earliestStudy.studyDate, 'YYYYMMDD'); + earliestDate.subtract(range); + + var latestDate = moment(latestStudy.studyDate, 'YYYYMMDD'); + latestDate.add(range); + + return { + earliestDate: earliestDate, + latestDate: latestDate + }; +} + +/** + * + * @returns {Array} + */ +function autoSelectStudies(selectedStudies) { + if (!selectedStudies.length) { + return; + } + + var range = getDateRange(selectedStudies); + + var autoselected = WorklistStudies.find({ + studyDate: { + $gte: range.earliestDate.format('YYYYMMDD'), + $lte: range.latestDate.format('YYYYMMDD') + } + }, { + sort: { + studyDate: 1 + } + }).fetch(); + + // Make an array of studyInstanceUids in selectedStudies + var studyInstanceUids = selectedStudies.map(function(selectedStudy) { + return selectedStudy.studyInstanceUid; + }); + + autoselected.forEach(function(study) { + var exists = studyInstanceUids.indexOf(study.studyInstanceUid); + if (exists > -1) { + study.autoselected = false; + return; + } + + study.autoselected = true; + }); + + return autoselected; } Template.studyAssociationTable.helpers({ @@ -10,9 +77,13 @@ Template.studyAssociationTable.helpers({ * @returns {Array.} */ relevantStudies: function() { - var userSelectedStudies = WorklistSelectedStudies.find().fetch() || []; - var autoselected = autoSelectStudies(userSelectedStudies); - return userSelectedStudies.concat(autoselected); + var selectedStudies = WorklistSelectedStudies.find({}, { + sort: { + studyDate: 1 + } + }).fetch() || []; + var autoselected = autoSelectStudies(selectedStudies); + return autoselected; }, /** * This helper returns the list of Timepoint types the user can set for this study @@ -30,7 +101,54 @@ Template.studyAssociationTable.helpers({ name: 'Follow-up' } ]; + }, + earliestDate: function() { + var selectedStudies = WorklistSelectedStudies.find({}, { + sort: { + studyDate: 1 + } + }).fetch(); + var range = getDateRange(selectedStudies); + if (!range) { + return; + } + + return range.earliestDate; + }, + latestDate: function() { + var selectedStudies = WorklistSelectedStudies.find({}, { + sort: { + studyDate: 1 + } + }).fetch(); + var range = getDateRange(selectedStudies); + if (!range) { + return; + } + + return range.latestDate; } }); -//trial criteria! \ No newline at end of file +Template.studyAssociationTable.events({ + 'change input.includeStudy': function(e) { + var checkbox = e.currentTarget; + var studyDataCells = $(checkbox).parents('tr').find('td.studyDataCell'); + if (checkbox.checked === true) { + studyDataCells.removeClass('disabled'); + studyDataCells.find('input').attr('disabled', false); + } else { + studyDataCells.addClass('disabled'); + studyDataCells.find('input').attr('disabled', true); + } + } +}); + +//trial criteria! +/*There shall be Associate option in right-click dialog +If associated, double-click shall go to image view. + If not associated, user shall be directed to Associate Time Points Dialog +Use shall also be allowed to select multiple studies from study list to associate +Associate Time Point dialog shall present selected studies and studies within defined time window of =/- 14 days of selected studies +User should only be able to associate one time point at a time (user should not be able to select both BL and F/U for different studies in associate dialog) + */ \ No newline at end of file diff --git a/Packages/lesiontracker/client/components/studyAssociationTable/studyAssociationTable.styl b/Packages/lesiontracker/client/components/studyAssociationTable/studyAssociationTable.styl index b041bc84c..c24334156 100644 --- a/Packages/lesiontracker/client/components/studyAssociationTable/studyAssociationTable.styl +++ b/Packages/lesiontracker/client/components/studyAssociationTable/studyAssociationTable.styl @@ -13,4 +13,7 @@ margin: 0 3px label - padding: 0 5px \ No newline at end of file + padding: 0 5px + + td.disabled + opacity: 0.2 \ No newline at end of file diff --git a/Packages/viewerbase/lib/helpers/inlineIf.js b/Packages/viewerbase/lib/helpers/inlineIf.js new file mode 100644 index 000000000..2143dd472 --- /dev/null +++ b/Packages/viewerbase/lib/helpers/inlineIf.js @@ -0,0 +1,10 @@ +/** + * Helper for setting checkboxes as checked or unchecked inside templates, + * based on another variable's value + */ +UI.registerHelper("inlineIf", function (value, match, attributeName) { + if(value === match) { + return attributeName; + } + return ''; +}); diff --git a/Packages/viewerbase/package.js b/Packages/viewerbase/package.js index a3f622361..e8550ec7d 100644 --- a/Packages/viewerbase/package.js +++ b/Packages/viewerbase/package.js @@ -155,6 +155,7 @@ Package.onUse(function (api) { api.addFiles('lib/helpers/formatNumberPrecision.js', 'client'); api.addFiles('lib/helpers/formatPN.js', 'client'); api.addFiles('lib/helpers/formatTM.js', 'client'); + api.addFiles('lib/helpers/inlineIf.js', 'client'); // Server-side functions api.addFiles('server/seed.js', 'server'); diff --git a/Packages/worklist/components/studyContextMenu/studyContextMenu.html b/Packages/worklist/components/studyContextMenu/studyContextMenu.html index bd4255250..ebf19fb34 100644 --- a/Packages/worklist/components/studyContextMenu/studyContextMenu.html +++ b/Packages/worklist/components/studyContextMenu/studyContextMenu.html @@ -20,8 +20,10 @@ Anonymize Delete - Share + Send + Export Download + View Series Details diff --git a/Packages/worklist/components/studyContextMenu/studyContextMenu.js b/Packages/worklist/components/studyContextMenu/studyContextMenu.js index cbd417041..e8ee6a122 100644 --- a/Packages/worklist/components/studyContextMenu/studyContextMenu.js +++ b/Packages/worklist/components/studyContextMenu/studyContextMenu.js @@ -36,11 +36,11 @@ openStudyContextMenu = function(e, template) { dialogProperty.top = e.pageY;// - dialog.outerHeight() - 40; dialogProperty.left = e.pageX;// - dialog.outerWidth() / 2; - var pageHeight = $(window).height(); + var pageHeight = $(document.body).height(); dialogProperty.top = Math.max(dialogProperty.top, 0); dialogProperty.top = Math.min(dialogProperty.top, pageHeight - dialog.outerHeight()); - var pageWidth = $(window).width(); + var pageWidth = $(document.body).width(); dialogProperty.left = Math.max(dialogProperty.left, 0); dialogProperty.left = Math.min(dialogProperty.left, pageWidth - dialog.outerWidth()); } diff --git a/Packages/worklist/components/worklistStudy/worklistStudy.js b/Packages/worklist/components/worklistStudy/worklistStudy.js index 6d2b20c2a..b0d5aa263 100644 --- a/Packages/worklist/components/worklistStudy/worklistStudy.js +++ b/Packages/worklist/components/worklistStudy/worklistStudy.js @@ -33,21 +33,28 @@ function handleShiftClick(studyRow, data) { } // Loop through the rows in between current and previous selected studies - rowsInBetween.each(function(index, row) { - if ($(row).is(studyRow)) { - // When we reach the currently clicked-on row, stop - return false; - } else if ($(row).hasClass('active')) { + rowsInBetween.each(function() { + var row = $(this); + + if (row.hasClass('active')) { // If we find one that is already selected, do nothing return; } // Get the relevant studyInstanceUid - var studyInstanceUid = $(row).attr('studyInstanceUid'); + var studyInstanceUid = row.attr('studyInstanceUid'); + + // Retrieve the data context through Blaze + var data = Blaze.getData(this); // Set the current study as selected WorklistSelectedStudies.insert(data); - studyRow.addClass('active'); + row.addClass('active'); + + // When we reach the currently clicked-on row, stop the loop + if (row.is(studyRow)) { + return false; + } return true; }); @@ -77,6 +84,7 @@ function handleCtrlClick(studyRow, data) { // Set this as the previously selected row, so the user can // use Shift to select from this point onwards Worklist.previouslySelected = studyRow; + log.info('Worklist PreviouslySelected set: ' + studyRow.index()); } } @@ -102,6 +110,7 @@ Template.worklistStudy.events({ // Set the previous study to the currently clicked-on study Worklist.previouslySelected = studyRow; + log.info('Worklist PreviouslySelected set: ' + studyRow.index()); // Set the current study as selected WorklistSelectedStudies.insert(data);