Replacing switchToTab with routes
This commit is contained in:
1 parent
0cf4dbf13f
commit
7718d31a77
46 files changed
+358
-753
No files matched your search
@@ -0,0 +1,5 @@
|
||||
import { OHIF } from 'meteor/ohif:core';
|
||||
|
||||
Object.assign(OHIF.studylist, {
|
||||
callbacks: {}
|
||||
});
|
||||
@@ -1 +1,2 @@
|
||||
import './studies.js';
|
||||
import './subscriptions.js';
|
||||
@@ -0,0 +1,11 @@
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import { OHIF } from 'meteor/ohif:core';
|
||||
|
||||
// Define the Studies Collection. This is a client-side only Collection which stores the list of
|
||||
// studies in the StudyList
|
||||
Meteor.startup(() => {
|
||||
const Studies = new Meteor.Collection(null);
|
||||
Studies._debugName = 'Studies';
|
||||
|
||||
OHIF.studylist.collections.Studies = Studies;
|
||||
});
|
||||
@@ -1,5 +1,4 @@
|
||||
import './studylist.html';
|
||||
import './studylist.js';
|
||||
import './studylist.styl';
|
||||
|
||||
import './studylistStudy/studylistStudy.html';
|
||||
|
||||
@@ -1,13 +1,5 @@
|
||||
<template name="studylist">
|
||||
<div id="studylistTabs" class="tab-content">
|
||||
<div role="tabpanel" class="tab-pane active" id="studylistTab">
|
||||
<div class="studylistContainer">
|
||||
{{>studylistResult (clone this)}}
|
||||
</div>
|
||||
</div>
|
||||
<div role="tabpanel" class="tab-pane" id="viewerTab">
|
||||
<div class="viewerContainer">
|
||||
</div>
|
||||
</div>
|
||||
<div class="study-list-wrapper">
|
||||
{{>studylistResult (clone this)}}
|
||||
</div>
|
||||
</template>
|
||||
@@ -1,44 +0,0 @@
|
||||
/**
|
||||
* Template: StudyList
|
||||
*
|
||||
* This is the main component of the StudyList package
|
||||
*/
|
||||
|
||||
// Define the ViewerData global object
|
||||
// If there is currently any Session data for this object,
|
||||
// use this to repopulate the variable
|
||||
ViewerData = Session.get('ViewerData') || {};
|
||||
|
||||
// Define the StudyListStudies Collection
|
||||
// This is a client-side only Collection which
|
||||
// Stores the list of studies in the StudyList
|
||||
StudyListStudies = new Meteor.Collection(null);
|
||||
StudyListStudies._debugName = 'StudyListStudies';
|
||||
|
||||
Session.setDefault('activeContentId', 'studylistTab');
|
||||
|
||||
Template.studylist.onCreated(() => {
|
||||
const instance = Template.instance();
|
||||
|
||||
if (StudyList.subscriptions) {
|
||||
StudyList.subscriptions.forEach(subscriptionName => {
|
||||
instance.subscribe(subscriptionName);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
Template.studylist.onRendered(() => {
|
||||
const instance = Template.instance();
|
||||
if (instance.data && instance.data.studyInstanceUid) {
|
||||
const studyInstanceUid = instance.data.studyInstanceUid;
|
||||
openNewTab(studyInstanceUid);
|
||||
} else {
|
||||
// If there is a tab set as active in the Session,
|
||||
// switch to that now.
|
||||
console.log('studylist onRendered');
|
||||
const contentId = Session.get('activeContentId');
|
||||
if (contentId !== 'studylistTab' && ViewerData && ViewerData[contentId]) {
|
||||
switchToTab(contentId);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -1,34 +1,13 @@
|
||||
@import "{ohif:design}/app"
|
||||
|
||||
body
|
||||
theme('background-color', '$primaryBackgroundColor')
|
||||
|
||||
#tblStudyList
|
||||
tr
|
||||
height: 20px
|
||||
|
||||
#studylistTab
|
||||
theme('background-color', '$primaryBackgroundColor')
|
||||
|
||||
.studylistContainer
|
||||
.study-list-wrapper
|
||||
theme('background-color', '$primaryBackgroundColor')
|
||||
color: white
|
||||
margin: 2px auto 0
|
||||
height: calc(100% - 91px)
|
||||
position: relative
|
||||
width: 100%
|
||||
|
||||
.tab-content
|
||||
width: 100%
|
||||
height: calc(100% - 91px)
|
||||
|
||||
.loadingTextDiv
|
||||
theme('color', '$textSecondaryColor')
|
||||
font-size: 30px
|
||||
|
||||
.tab-pane
|
||||
width: 100%
|
||||
height: 100%
|
||||
|
||||
.viewerContainer
|
||||
height: 100%
|
||||
width: 100%
|
||||
+8
-14
@@ -1,14 +1,8 @@
|
||||
<template name="studylistResult">
|
||||
<div class="studyListToolbar clearfix">
|
||||
<div class="header pull-left">
|
||||
Study List
|
||||
</div>
|
||||
<div class="studyCount pull-right">
|
||||
{{numberOfStudies}}
|
||||
</div>
|
||||
<div class="pull-right">
|
||||
{{>studylistToolbar}}
|
||||
</div>
|
||||
<div class="header pull-left">Study List</div>
|
||||
<div class="studyCount pull-right">{{numberOfStudies}}</div>
|
||||
<div class="pull-right">{{>studylistToolbar}}</div>
|
||||
</div>
|
||||
<div class="theadBackground">
|
||||
</div>
|
||||
@@ -74,18 +68,18 @@
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="studyListData">
|
||||
{{#each study in studies}}
|
||||
{{>studylistStudy (clone study this)}}
|
||||
{{/each}}
|
||||
{{#each study in studies}}
|
||||
{{>studylistStudy (clone study this)}}
|
||||
{{/each}}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<!-- Pagination -->
|
||||
{{> studylistPagination }}
|
||||
{{>studylistPagination}}
|
||||
|
||||
{{#if session "showLoadingText"}}
|
||||
{{>loadingText}}
|
||||
{{ else }}
|
||||
{{else}}
|
||||
{{#unless numberOfStudies}}
|
||||
<div class="notFound">No matching results</div>
|
||||
{{/unless}}
|
||||
|
||||
+23
-21
@@ -1,11 +1,16 @@
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import { Template } from 'meteor/templating';
|
||||
import { Session } from 'meteor/session';
|
||||
import { ReactiveVar } from 'meteor/reactive-var';
|
||||
import { ReactiveDict } from 'meteor/reactive-dict';
|
||||
import { moment } from 'meteor/momentjs:moment';
|
||||
import { OHIF } from 'meteor/ohif:core';
|
||||
|
||||
Session.setDefault('showLoadingText', true);
|
||||
|
||||
Template.studylistResult.helpers({
|
||||
/**
|
||||
* Returns a sorted instance of the StudyListStudies Collection
|
||||
* by Patient name and Study Date in Ascending order.
|
||||
* Returns a ascending sorted instance of the Studies Collection by Patient name and Study Date
|
||||
*/
|
||||
studies() {
|
||||
const instance = Template.instance();
|
||||
@@ -26,7 +31,7 @@ Template.studylistResult.helpers({
|
||||
const offset = rowsPerPage * currentPage;
|
||||
const limit = offset + rowsPerPage;
|
||||
|
||||
studies = StudyListStudies.find({}, {
|
||||
studies = OHIF.studylist.collections.Studies.find({}, {
|
||||
sort: sortOption
|
||||
}).fetch();
|
||||
|
||||
@@ -42,7 +47,7 @@ Template.studylistResult.helpers({
|
||||
},
|
||||
|
||||
numberOfStudies() {
|
||||
return StudyListStudies.find().count();
|
||||
return OHIF.studylist.collections.Studies.find().count();
|
||||
},
|
||||
|
||||
sortingColumnsIcons() {
|
||||
@@ -65,9 +70,9 @@ Template.studylistResult.helpers({
|
||||
}
|
||||
});
|
||||
|
||||
var studyDateFrom;
|
||||
var studyDateTo;
|
||||
var filter;
|
||||
let studyDateFrom;
|
||||
let studyDateTo;
|
||||
let filter;
|
||||
|
||||
/**
|
||||
* Transforms an input string into a search filter for
|
||||
@@ -106,9 +111,6 @@ function replaceUndefinedColumnValue(text) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
|
||||
/**
|
||||
* Convert string to study date
|
||||
*/
|
||||
@@ -122,10 +124,10 @@ function convertStringToStudyDate(dateStr) {
|
||||
|
||||
/**
|
||||
* Runs a search for studies matching the studylist query parameters
|
||||
* Inserts the identified studies into the StudyListStudies Collection
|
||||
* Inserts the identified studies into the Studies Collection
|
||||
*/
|
||||
function search() {
|
||||
console.log('search()');
|
||||
OHIF.log.info('search()');
|
||||
|
||||
// Show loading message
|
||||
Session.set('showLoadingText', true);
|
||||
@@ -138,7 +140,7 @@ function search() {
|
||||
studyDescription: getFilter($('input#studyDescription').val()),
|
||||
studyDateFrom: studyDateFrom,
|
||||
studyDateTo: studyDateTo,
|
||||
modalitiesInStudy: $('input#modality').val() ? $('input#modality').val() : ""
|
||||
modalitiesInStudy: $('input#modality').val() ? $('input#modality').val() : ''
|
||||
};
|
||||
|
||||
// Make sure that modality has a reasonable value, since it is occasionally
|
||||
@@ -146,10 +148,10 @@ function search() {
|
||||
const modality = replaceUndefinedColumnValue($('input#modality').val());
|
||||
|
||||
// Clear all current studies
|
||||
StudyListStudies.remove({});
|
||||
OHIF.studylist.collections.Studies.remove({});
|
||||
|
||||
Meteor.call('StudyListSearch', filter, (error, studies) => {
|
||||
console.log('StudyListSearch');
|
||||
OHIF.log.info('StudyListSearch');
|
||||
if (error) {
|
||||
OHIF.log.warn(error);
|
||||
return;
|
||||
@@ -172,8 +174,8 @@ function search() {
|
||||
// Convert numberOfStudyRelatedInstance string into integer
|
||||
study.numberOfStudyRelatedInstances = !isNaN(study.numberOfStudyRelatedInstances) ? parseInt(study.numberOfStudyRelatedInstances) : undefined;
|
||||
|
||||
// Insert any matching studies into the StudyListStudies Collection
|
||||
StudyListStudies.insert(study);
|
||||
// Insert any matching studies into the Studies Collection
|
||||
OHIF.studylist.collections.Studies.insert(study);
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -181,7 +183,7 @@ function search() {
|
||||
|
||||
const getRowsPerPage = () => sessionStorage.getItem('rowsPerPage');
|
||||
|
||||
// Wraps ReactiveVar equalsFunc function. Whenever ReactiveVar is
|
||||
// Wraps ReactiveVar equalsFunc function. Whenever ReactiveVar is
|
||||
// set to a new value, it will save it in the Session Storage.
|
||||
// The return is the default ReactiveVar equalsFunc if available
|
||||
// or values are === compared
|
||||
@@ -200,9 +202,10 @@ Template.studylistResult.onCreated(() => {
|
||||
// Rows per page
|
||||
// Check session storage or set 25 as default
|
||||
const cachedRowsPerPage = getRowsPerPage();
|
||||
if(!cachedRowsPerPage) {
|
||||
if (!cachedRowsPerPage) {
|
||||
setRowsPerPage(0, 25);
|
||||
}
|
||||
|
||||
const rowsPerPage = getRowsPerPage();
|
||||
instance.rowsPerPage = new ReactiveVar(parseInt(rowsPerPage, 10), setRowsPerPage);
|
||||
|
||||
@@ -214,8 +217,7 @@ Template.studylistResult.onCreated(() => {
|
||||
const sortOptionSession = Session.get('sortOption');
|
||||
if (sortOptionSession) {
|
||||
instance.sortingColumns.set(sortOptionSession);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
instance.sortingColumns.set({
|
||||
patientName: 1,
|
||||
studyDate: 1,
|
||||
|
||||
+15
-12
@@ -76,6 +76,9 @@ $bodyCellHeight = 40px
|
||||
text-align: center
|
||||
|
||||
table#tblStudyList
|
||||
tr
|
||||
height: 20px
|
||||
|
||||
thead
|
||||
white-space: nowrap
|
||||
|
||||
@@ -172,10 +175,10 @@ $bodyCellHeight = 40px
|
||||
|
||||
@media only screen and (max-width: 1362px)
|
||||
$tablePadding = 5%
|
||||
|
||||
|
||||
#studyListContainer
|
||||
padding: 0 $tablePadding
|
||||
|
||||
|
||||
table#tblStudyList
|
||||
thead,
|
||||
tbody
|
||||
@@ -190,10 +193,10 @@ $bodyCellHeight = 40px
|
||||
|
||||
@media only screen and (max-width: 1161px)
|
||||
$tablePadding = 3%
|
||||
|
||||
|
||||
#studyListContainer
|
||||
padding: 0 $tablePadding
|
||||
|
||||
|
||||
table#tblStudyList
|
||||
thead,
|
||||
tbody
|
||||
@@ -208,31 +211,31 @@ $bodyCellHeight = 40px
|
||||
|
||||
@media only screen and (max-width: 1069px)
|
||||
$tablePaddingMediumScreen = 5px
|
||||
|
||||
|
||||
.theadBackground
|
||||
height: 101px
|
||||
|
||||
.studyListToolbar
|
||||
padding: 0 $tablePaddingMediumScreen
|
||||
|
||||
|
||||
#studyListContainer
|
||||
padding: 0
|
||||
|
||||
table#tblStudyList
|
||||
thead > tr > th
|
||||
|
||||
|
||||
&:first-child
|
||||
padding-left: $tablePaddingMediumScreen
|
||||
|
||||
&:last-child
|
||||
padding-right: $tablePaddingMediumScreen
|
||||
|
||||
|
||||
input.worklist-search
|
||||
padding: 10px
|
||||
|
||||
|
||||
div.sortingCell
|
||||
padding: 10px 5px
|
||||
|
||||
|
||||
i
|
||||
width: auto
|
||||
|
||||
@@ -242,8 +245,8 @@ $bodyCellHeight = 40px
|
||||
|
||||
&:last-child
|
||||
padding-right: $tablePaddingMediumScreen
|
||||
|
||||
|
||||
.worklistPagination
|
||||
.row
|
||||
margin-left: 0
|
||||
margin-right: 0
|
||||
margin-right: 0
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
<template name="studylistStudy">
|
||||
<tr class="studylistStudy noselect">
|
||||
<tr class="studylistStudy noselect {{#if this.selected}}active{{/if}}">
|
||||
<td class="patientName">
|
||||
{{formatPN patientName}}
|
||||
</td>
|
||||
@@ -19,4 +19,4 @@
|
||||
{{studyDescription}}
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
</template>
|
||||
+60
-84
@@ -1,100 +1,82 @@
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import { Template } from 'meteor/templating';
|
||||
import { Blaze } from 'meteor/blaze';
|
||||
import { OHIF } from 'meteor/ohif:core';
|
||||
|
||||
// Maybe we should use regular StudyList collection?
|
||||
StudyListSelectedStudies = new Meteor.Collection(null);
|
||||
StudyListSelectedStudies._debugName = 'StudyListSelectedStudies';
|
||||
|
||||
function isStudySelected(study) {
|
||||
// Search StudyListSelectedStudies for given study and return true if found
|
||||
let count = StudyListSelectedStudies.find({
|
||||
studyInstanceUid: study.studyInstanceUid
|
||||
}).count();
|
||||
return count > 0;
|
||||
}
|
||||
|
||||
// Clear all selected studies
|
||||
function doClearStudySelections() {
|
||||
// Clear all selected studies
|
||||
StudyListSelectedStudies.remove({});
|
||||
$('tr.studylistStudy').removeClass('active');
|
||||
OHIF.studylist.collections.Studies.update({}, {
|
||||
$set: { selected: false }
|
||||
}, { multi: true });
|
||||
}
|
||||
|
||||
function doSelectRow(studyRow, data) {
|
||||
// Insert current study into selection list if it's not there already...
|
||||
if (!isStudySelected(data)) {
|
||||
StudyListSelectedStudies.insert(data);
|
||||
function doSelectRow($studyRow, data) {
|
||||
// Mark the current study as selected if it's not marked yet
|
||||
if (!data.selected) {
|
||||
const filter = { studyInstanceUid: data.studyInstanceUid };
|
||||
const modifiers = { $set: { selected: true } };
|
||||
OHIF.studylist.collections.Studies.update(filter, modifiers);
|
||||
}
|
||||
// Make sure the study row has "active" class
|
||||
studyRow.addClass('active');
|
||||
// Set this as the previously selected row, so the user can
|
||||
// use Shift to select from this point onwards
|
||||
StudyList.previouslySelected = studyRow;
|
||||
|
||||
// Set it as the previously selected row, so the user can use Shift to select from this point on
|
||||
OHIF.studylist.$lastSelectedRow = $studyRow;
|
||||
}
|
||||
|
||||
function doSelectSingleRow(studyRow, data) {
|
||||
function doSelectSingleRow($studyRow, data) {
|
||||
// Clear all selected studies
|
||||
doClearStudySelections();
|
||||
// ... And add selected row to selection list
|
||||
doSelectRow(studyRow, data);
|
||||
|
||||
// Add selected row to selection list
|
||||
doSelectRow($studyRow, data);
|
||||
}
|
||||
|
||||
function doUnselectRow(studyRow, data) {
|
||||
// Find the current studyInstanceUid in the stored list and remove it
|
||||
StudyListSelectedStudies.remove({
|
||||
studyInstanceUid: data.studyInstanceUid
|
||||
});
|
||||
studyRow.removeClass('active');
|
||||
function doUnselectRow($studyRow, data) {
|
||||
// Find the current studyInstanceUid in the stored list and mark as unselected
|
||||
const filter = { studyInstanceUid: data.studyInstanceUid };
|
||||
const modifiers = { $set: { selected: false } };
|
||||
OHIF.studylist.collections.Studies.update(filter, modifiers);
|
||||
}
|
||||
|
||||
function handleShiftClick($studyRow, data) {
|
||||
//OHIF.log.info('shiftKey');
|
||||
|
||||
let study, previous = StudyList.previouslySelected ? $(StudyList.previouslySelected) : null;
|
||||
if (previous && previous.length > 0) {
|
||||
study = Blaze.getData(previous.get(0));
|
||||
if (!isStudySelected(study)) {
|
||||
previous = void 0; // undefined
|
||||
StudyList.previouslySelected = previous;
|
||||
let study;
|
||||
let $previousRow = OHIF.studylist.$lastSelectedRow;
|
||||
if ($previousRow && $previousRow.length > 0) {
|
||||
study = Blaze.getData($previousRow.get(0));
|
||||
if (!study.selected) {
|
||||
$previousRow = $(); // undefined
|
||||
OHIF.studylist.$lastSelectedRow = $previousRow;
|
||||
}
|
||||
}
|
||||
|
||||
// Select all rows in between these two rows
|
||||
if (previous) {
|
||||
if ($previousRow.length) {
|
||||
let $rowsInBetween;
|
||||
if (previous.index() < $studyRow.index()) {
|
||||
if ($previousRow.index() < $studyRow.index()) {
|
||||
// The previously selected row is above (lower index) the
|
||||
// currently selected row.
|
||||
|
||||
// Fill in the rows upwards from the previously selected row
|
||||
$rowsInBetween = previous.nextAll('tr');
|
||||
} else if (previous.index() > $studyRow.index()) {
|
||||
$rowsInBetween = $previousRow.nextAll('tr');
|
||||
} else if ($previousRow.index() > $studyRow.index()) {
|
||||
// The previously selected row is below the currently
|
||||
// selected row.
|
||||
|
||||
// Fill in the rows upwards from the previously selected row
|
||||
$rowsInBetween = previous.prevAll('tr');
|
||||
$rowsInBetween = $previousRow.prevAll('tr');
|
||||
} else {
|
||||
// nothing to do since previous.index() === $studyRow.index()
|
||||
// nothing to do since $previousRow.index() === $studyRow.index()
|
||||
// the user is shift-clicking the same row...
|
||||
return;
|
||||
}
|
||||
|
||||
// Loop through the rows in between current and previous selected studies
|
||||
$rowsInBetween.forEach(row => {
|
||||
$rowsInBetween.each((index, row) => {
|
||||
const $row = $(row);
|
||||
|
||||
if ($row.hasClass('active')) {
|
||||
// If we find one that is already selected, do nothing
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the relevant studyInstanceUid
|
||||
let studyInstanceUid = $row.attr('studyInstanceUid');
|
||||
|
||||
// Retrieve the data context through Blaze
|
||||
let data = Blaze.getData(this);
|
||||
const data = Blaze.getData(row);
|
||||
|
||||
// If we find one that is already selected, do nothing
|
||||
if (data.selected) return;
|
||||
|
||||
// Set the current study as selected
|
||||
doSelectRow($row, data);
|
||||
@@ -108,37 +90,31 @@ function handleShiftClick($studyRow, data) {
|
||||
}
|
||||
}
|
||||
|
||||
function handleCtrlClick(studyRow, data) {
|
||||
//OHIF.log.info('ctrlKey');
|
||||
if (isStudySelected(data)) {
|
||||
doUnselectRow(studyRow, data);
|
||||
} else {
|
||||
doSelectRow(studyRow, data);
|
||||
OHIF.log.info('StudyList PreviouslySelected set: ' + studyRow.index());
|
||||
}
|
||||
function handleCtrlClick($studyRow, data) {
|
||||
const handler = data.selected ? doUnselectRow : doSelectRow;
|
||||
handler($studyRow, data);
|
||||
}
|
||||
|
||||
Template.studylistStudy.onRendered(function() {
|
||||
let instance = this,
|
||||
data = instance.data,
|
||||
row = instance.$('tr.studylistStudy').first();
|
||||
Template.studylistStudy.onRendered(() => {
|
||||
const instance = Template.instance();
|
||||
const data = instance.data;
|
||||
const $row = instance.$('tr.studylistStudy').first();
|
||||
|
||||
// Enable HammerJS to allow touch support
|
||||
let mc = new Hammer.Manager(row.get(0)),
|
||||
doubleTapRecognizer = new Hammer.Tap({
|
||||
event: 'doubletap',
|
||||
taps: 2,
|
||||
interval: 500,
|
||||
threshold: 30,
|
||||
posThreshold: 30
|
||||
});
|
||||
const mc = new Hammer.Manager($row.get(0));
|
||||
const doubleTapRecognizer = new Hammer.Tap({
|
||||
event: 'doubletap',
|
||||
taps: 2,
|
||||
interval: 500,
|
||||
threshold: 30,
|
||||
posThreshold: 30
|
||||
});
|
||||
mc.add(doubleTapRecognizer);
|
||||
|
||||
// Check if current row has been previously selected
|
||||
if (isStudySelected(data)) {
|
||||
doSelectRow(row, data);
|
||||
if (data.selected) {
|
||||
doSelectRow($row, data);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
Template.studylistStudy.events({
|
||||
@@ -164,7 +140,7 @@ Template.studylistStudy.events({
|
||||
return;
|
||||
}
|
||||
|
||||
const middleClickOnStudy = StudyList.callbacks.middleClickOnStudy;
|
||||
const middleClickOnStudy = OHIF.studylist.callbacks.middleClickOnStudy;
|
||||
if (middleClickOnStudy && typeof middleClickOnStudy === 'function') {
|
||||
middleClickOnStudy(instance.data);
|
||||
}
|
||||
@@ -175,7 +151,7 @@ Template.studylistStudy.events({
|
||||
return;
|
||||
}
|
||||
|
||||
const dblClickOnStudy = StudyList.callbacks.dblClickOnStudy;
|
||||
const dblClickOnStudy = OHIF.studylist.callbacks.dblClickOnStudy;
|
||||
|
||||
if (dblClickOnStudy && typeof dblClickOnStudy === 'function') {
|
||||
dblClickOnStudy(instance.data);
|
||||
@@ -185,7 +161,7 @@ Template.studylistStudy.events({
|
||||
'contextmenu tr.studylistStudy, press tr.studylistStudy'(event, instance) {
|
||||
const $studyRow = $(event.currentTarget);
|
||||
|
||||
if (!isStudySelected(instance.data)) {
|
||||
if (!instance.data.selected) {
|
||||
doSelectSingleRow($studyRow, instance.data);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import './base';
|
||||
import './collections';
|
||||
import './lib';
|
||||
import './components';
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { OHIF } from 'meteor/ohif:core';
|
||||
|
||||
OHIF.studylist.getSelectedStudies = () => {
|
||||
return StudyListSelectedStudies.find({}, {
|
||||
return OHIF.studylist.collections.Studies.find({ selected: true }, {
|
||||
sort: {
|
||||
studyDate: 1
|
||||
}
|
||||
|
||||
@@ -1,82 +0,0 @@
|
||||
import { OHIF } from 'meteor/ohif:core';
|
||||
import 'meteor/ohif:viewerbase';
|
||||
|
||||
// DEPRECATED - use OHIF.studylist.retrieveStudyMetadata instead
|
||||
// Define the StudyMetaData object. This is used as a cache
|
||||
// to store study meta data information to prevent unnecessary
|
||||
// calls to the server
|
||||
var StudyMetaData = {};
|
||||
|
||||
/**
|
||||
* Retrieves study metadata using a server call, and fires a callback
|
||||
* when completed.
|
||||
*
|
||||
* @params {string} studyInstanceUid The UID of the Study to be retrieved
|
||||
* @params {function} doneCallback The callback function to be executed when the study retrieval has finished
|
||||
* @param failCallback The callback function to be executed when the study retrieval has failed
|
||||
*/
|
||||
getStudyMetadata = function(studyInstanceUid, doneCallback, failCallback) {
|
||||
// If the StudyMetaData cache already has data related to this
|
||||
// studyInstanceUid, then we should fire the doneCallback with this data
|
||||
// and stop here.
|
||||
var study = StudyMetaData[studyInstanceUid];
|
||||
if (study) {
|
||||
doneCallback(study);
|
||||
return;
|
||||
}
|
||||
|
||||
console.time('getStudyMetadata');
|
||||
|
||||
// If no study metadata is in the cache variable, we need to retrieve it from
|
||||
// the server with a call.
|
||||
Meteor.call('GetStudyMetadata', studyInstanceUid, function(error, study) {
|
||||
console.timeEnd('getStudyMetadata');
|
||||
|
||||
if (Meteor.user && Meteor.user()) {
|
||||
var hipaaEvent = {
|
||||
eventType: 'viewed',
|
||||
userId: Meteor.userId(),
|
||||
userName: Meteor.user().profile.fullName,
|
||||
collectionName: 'Study',
|
||||
recordId: studyInstanceUid,
|
||||
patientId: study.patientId,
|
||||
patientName: study.patientName
|
||||
};
|
||||
HipaaLogger.logEvent(hipaaEvent);
|
||||
}
|
||||
|
||||
if (error) {
|
||||
OHIF.log.warn(error);
|
||||
failCallback(error);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!study) {
|
||||
throw "GetStudyMetadata: No study data returned from server";
|
||||
}
|
||||
|
||||
// Once we have retrieved the data, we sort the series' by series
|
||||
// and instance number in ascending order
|
||||
OHIF.viewerbase.sortStudy(study);
|
||||
|
||||
// Updates WADO-RS metaDataManager
|
||||
OHIF.viewerbase.updateMetaDataManager(study);
|
||||
|
||||
// Add additional metadata to our study from the studylist
|
||||
var studylistStudy = StudyListStudies.findOne({
|
||||
studyInstanceUid: study.studyInstanceUid
|
||||
});
|
||||
|
||||
if (!studylistStudy) {
|
||||
// return;
|
||||
}
|
||||
|
||||
$.extend(study, studylistStudy);
|
||||
|
||||
// Then we store this data in the cache variable
|
||||
StudyMetaData[studyInstanceUid] = study;
|
||||
|
||||
// Finally, we fire the doneCallback with this study meta data
|
||||
doneCallback(study);
|
||||
});
|
||||
};
|
||||
@@ -26,8 +26,8 @@ const getStudyPriors = study => {
|
||||
const patientID = study.getTagValue(PATIENT_ID); // PatientID
|
||||
const studyDate = study.getTagValue(STUDY_DATE); // StudyDate
|
||||
|
||||
// Find prior studies in global StudyListStudies Minimongo collection
|
||||
const cursor = StudyListStudies.find({
|
||||
// Find prior studies in global Studies Minimongo collection
|
||||
const cursor = OHIF.studylist.collections.Studies.find({
|
||||
patientId: patientID,
|
||||
studyDate: {
|
||||
$lt: studyDate
|
||||
|
||||
@@ -3,12 +3,9 @@ import './third-party/jquery.twbsPagination.min.js';
|
||||
import './exportSelectedStudies.js';
|
||||
import './exportStudies.js';
|
||||
import './getSelectedStudies.js';
|
||||
import './getStudyMetadata.js';
|
||||
import './getStudiesMetadata.js';
|
||||
import './importStudies.js';
|
||||
import './openNewTab.js';
|
||||
import './queryStudies.js';
|
||||
import './retrieveStudiesMetadata.js';
|
||||
import './retrieveStudyMetadata.js';
|
||||
import './studylist.js';
|
||||
import './switchToTab.js';
|
||||
import './viewSeriesDetails.js';
|
||||
@@ -1,27 +0,0 @@
|
||||
import { Random } from 'meteor/random';
|
||||
import { OHIF } from 'meteor/ohif:core';
|
||||
|
||||
/**
|
||||
* Opens a new tab in the tabbed studylist environment using
|
||||
* a given study and new tab title.
|
||||
*
|
||||
* @param studyInstanceUid The UID of the Study to be opened
|
||||
*/
|
||||
const openNewTab = studyInstanceUid => {
|
||||
OHIF.log.info('openNewTab');
|
||||
|
||||
// Generate a unique ID to represent this tab
|
||||
// We can't just use the Mongo entry ID because
|
||||
// then it will change after hot-reloading.
|
||||
const contentId = Random.id();
|
||||
|
||||
// Update the ViewerData global object
|
||||
ViewerData = window.ViewerData || ViewerData;
|
||||
ViewerData[contentId] = {
|
||||
contentId: contentId,
|
||||
studyInstanceUids: [studyInstanceUid]
|
||||
};
|
||||
|
||||
// Switch to the new tab
|
||||
switchToTab(contentId);
|
||||
};
|
||||
+9
-16
@@ -7,10 +7,9 @@ import { OHIF } from 'meteor/ohif:core';
|
||||
* and waits for all of the results to be returned.
|
||||
*
|
||||
* @param studyInstanceUids The UIDs of the Studies to be retrieved
|
||||
* @param doneCallback The callback function to be executed when the study retrieval has finished
|
||||
* @param failCallback The callback function to be executed when the study retrieval has failed
|
||||
* @return Promise
|
||||
*/
|
||||
OHIF.studylist.getStudiesMetadata = (studyInstanceUids, doneCallback, failCallback) => {
|
||||
OHIF.studylist.retrieveStudiesMetadata = (studyInstanceUids, doneCallback, failCallback) => {
|
||||
// Check to make sure studyInstanceUids were actually input
|
||||
if (!studyInstanceUids || !studyInstanceUids.length) {
|
||||
if (failCallback && typeof failCallback === 'function') {
|
||||
@@ -20,8 +19,7 @@ OHIF.studylist.getStudiesMetadata = (studyInstanceUids, doneCallback, failCallba
|
||||
return;
|
||||
}
|
||||
|
||||
// Create an empty array to store the Promises for each metaData
|
||||
// retrieval call
|
||||
// Create an empty array to store the Promises for each metaData retrieval call
|
||||
const promises = [];
|
||||
|
||||
// Loop through the array of studyInstanceUids
|
||||
@@ -35,15 +33,10 @@ OHIF.studylist.getStudiesMetadata = (studyInstanceUids, doneCallback, failCallba
|
||||
});
|
||||
|
||||
// When all of the promises are complete, this callback runs
|
||||
Promise.all(promises).then(studies => {
|
||||
// Pass the studies array to the doneCallback, if one exists
|
||||
if (doneCallback && typeof doneCallback === 'function') {
|
||||
doneCallback(studies);
|
||||
}
|
||||
}).catch(error => {
|
||||
OHIF.log.warn(error);
|
||||
if (failCallback && typeof failCallback === 'function') {
|
||||
failCallback(error);
|
||||
}
|
||||
});
|
||||
const promise = Promise.all(promises);
|
||||
|
||||
// Warn the error on console if some retrieval failed
|
||||
promise.catch(error => OHIF.log.warn(error));
|
||||
|
||||
return promise;
|
||||
};
|
||||
@@ -62,13 +62,11 @@ OHIF.studylist.retrieveStudyMetadata = studyInstanceUid => {
|
||||
OHIF.viewerbase.updateMetaDataManager(study);
|
||||
|
||||
// Add additional metadata to our study from the studylist
|
||||
const studylistStudy = StudyListStudies.findOne({
|
||||
const studylistStudy = OHIF.studylist.collections.Studies.findOne({
|
||||
studyInstanceUid: study.studyInstanceUid
|
||||
});
|
||||
|
||||
if (!studylistStudy) {
|
||||
// return;
|
||||
} else {
|
||||
if (studylistStudy) {
|
||||
Object.assign(study, studylistStudy);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { OHIF } from 'meteor/ohif:core';
|
||||
import { Viewerbase } from 'meteor/ohif:viewerbase';
|
||||
// Classes
|
||||
import { OHIFStudyMetadataSource } from './OHIFStudyMetadataSource';
|
||||
@@ -11,15 +12,14 @@ StudyList = {
|
||||
getStudyPriors,
|
||||
getStudyPriorsMap
|
||||
},
|
||||
callbacks: {},
|
||||
classes: {
|
||||
OHIFStudyMetadataSource,
|
||||
OHIFStudySummary
|
||||
}
|
||||
};
|
||||
|
||||
StudyList.callbacks.dblClickOnStudy = dblClickOnStudy;
|
||||
StudyList.callbacks.middleClickOnStudy = dblClickOnStudy;
|
||||
OHIF.studylist.callbacks.dblClickOnStudy = dblClickOnStudy;
|
||||
OHIF.studylist.callbacks.middleClickOnStudy = dblClickOnStudy;
|
||||
|
||||
function dblClickOnStudy(data) {
|
||||
openNewTab(data.studyInstanceUid);
|
||||
|
||||
@@ -1,153 +0,0 @@
|
||||
import { Blaze } from 'meteor/blaze';
|
||||
import { Session } from 'meteor/session';
|
||||
import { jQuery, $ } from 'meteor/jquery';
|
||||
import { Template } from 'meteor/templating';
|
||||
|
||||
import { OHIF } from 'meteor/ohif:core';
|
||||
|
||||
/**
|
||||
* Switches to a new tab in the tabbed studylist container
|
||||
* This function renders either the StudyList or the Viewer template with new data.
|
||||
*
|
||||
* @param contentId The unique ID of the tab to be switched to
|
||||
*/
|
||||
switchToTab = function(contentId) {
|
||||
if (!contentId) {
|
||||
return;
|
||||
}
|
||||
|
||||
OHIF.log.info('Switching to tab: ' + contentId);
|
||||
|
||||
// Clear the cornerstone tool data to sync the measurements with the measurements API
|
||||
cornerstoneTools.globalImageIdSpecificToolStateManager = cornerstoneTools.newImageIdSpecificToolStateManager();
|
||||
|
||||
$('.tab-content .tab-pane').removeClass('active');
|
||||
if (contentId !== 'studylistTab') {
|
||||
$('.tab-content .tab-pane#viewerTab').addClass('active');
|
||||
} else {
|
||||
$('.tab-content .tab-pane#' + contentId).addClass('active');
|
||||
}
|
||||
|
||||
// Remove any previous Viewers from the DOM
|
||||
$('.viewerContainer').remove();
|
||||
$('.studylistContainer').remove();
|
||||
|
||||
// Update the 'activeContentId' variable in Session
|
||||
Session.set('activeContentId', contentId);
|
||||
|
||||
// If we are switching to the StudyList tab, reset any CSS styles
|
||||
// that have been applied to prevent scrolling in the Viewer.
|
||||
// Then stop here, since nothing needs to be re-rendered.
|
||||
let container;
|
||||
if (contentId === 'studylistTab') {
|
||||
container = $('.tab-content').find('#studylistTab').get(0);
|
||||
|
||||
if (!container) {
|
||||
return;
|
||||
}
|
||||
|
||||
const studylistContainer = document.createElement('div');
|
||||
studylistContainer.classList.add('studylistContainer');
|
||||
container.appendChild(studylistContainer);
|
||||
|
||||
// Use Blaze to render the StudyListResult Template into the container
|
||||
Blaze.render(Template.studylistResult, studylistContainer);
|
||||
|
||||
document.body.style.overflow = null;
|
||||
document.body.style.height = null;
|
||||
document.body.style.minWidth = null;
|
||||
document.body.style.position = null;
|
||||
return;
|
||||
}
|
||||
|
||||
// Tab was closed at some point, stop here
|
||||
ViewerData = window.ViewerData || ViewerData;
|
||||
if (!ViewerData[contentId]) {
|
||||
return;
|
||||
}
|
||||
|
||||
container = $('.tab-content').find('#viewerTab').get(0);
|
||||
container.innerHTML = '';
|
||||
|
||||
// Use Blaze to render the Loading Template into the container
|
||||
// viewStudiesInTab will clear this container
|
||||
Blaze.renderWithData(Template.loadingText, {}, container);
|
||||
|
||||
const studies = ViewerData[contentId].studies;
|
||||
|
||||
if (studies) {
|
||||
// ViewerData already has the meta data (in cases when studylist is launched externally)
|
||||
viewStudiesInTab(contentId, studies);
|
||||
} else {
|
||||
// Use the stored ViewerData global object to retrieve the studyInstanceUid
|
||||
// related to this tab
|
||||
const studyInstanceUids = ViewerData[contentId].studyInstanceUids;
|
||||
|
||||
// Attempt to retrieve the meta data (it might be cached)
|
||||
OHIF.studylist.getStudiesMetadata(studyInstanceUids, function(studies) {
|
||||
viewStudiesInTab(contentId, studies);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const viewStudiesInTab = (contentId, studies) => {
|
||||
// Tab closed while study data was being retrieved, stop here
|
||||
if (!ViewerData[contentId]) {
|
||||
OHIF.log.warn('Tab closed while study data was being retrieved');
|
||||
return;
|
||||
}
|
||||
|
||||
// Once we have the study data, store it in a structure with
|
||||
// any other saved data about this tab (e.g. layout structure)
|
||||
const data = jQuery.extend({}, ViewerData[contentId]);
|
||||
data.studies = studies;
|
||||
|
||||
// TODO: check if this is necessary. Since the typo bug
|
||||
// was fixed (it was contentid instead of contentId)
|
||||
data.contentId = contentId;
|
||||
|
||||
if (ViewerData[contentId].studies && ViewerData[contentId].studies.length) {
|
||||
data.studies = ViewerData[contentId].studies;
|
||||
}
|
||||
|
||||
// Add additional metadata to our study from the studylist
|
||||
data.studies.forEach(study => {
|
||||
const studylistStudy = StudyListStudies.findOne({
|
||||
studyInstanceUid: study.studyInstanceUid
|
||||
});
|
||||
|
||||
if (!studylistStudy) {
|
||||
return;
|
||||
}
|
||||
|
||||
$.extend(study, studylistStudy);
|
||||
});
|
||||
|
||||
// Get tab content container given the contentId string
|
||||
// If no such container exists, stop here because something is wrong
|
||||
const container = $('.tab-content').find('#viewerTab').get(0);
|
||||
|
||||
// Remove the loading text template that is inside the tab container by default
|
||||
const viewerContainer = document.createElement('div');
|
||||
viewerContainer.classList.add('viewerContainer');
|
||||
container.innerHTML = '';
|
||||
container.appendChild(viewerContainer);
|
||||
|
||||
// Use Blaze to render the Viewer Template into the container
|
||||
Blaze.renderWithData(Template.viewer, data, viewerContainer);
|
||||
|
||||
// Retrieve the DOM element of the viewer
|
||||
const imageViewer = $('#viewer');
|
||||
|
||||
// If it is present in the DOM (it should be), then apply
|
||||
// styles to prevent page scrolling and overscrolling on mobile devices
|
||||
if (imageViewer) {
|
||||
document.body.style.overflow = 'hidden';
|
||||
document.body.style.height = '100%';
|
||||
document.body.style.width = '100%';
|
||||
document.body.style.minWidth = 0;
|
||||
|
||||
// Prevent overscroll on mobile devices
|
||||
document.body.style.position = 'fixed';
|
||||
}
|
||||
};
|
||||
Reference in new issue
Block a user