Remove some subscription / reactivity / caching bugs and the unnecessary PatientLocations collection
This commit is contained in:
parent
7d42456f57
commit
9cde04bcfe
@ -1,16 +1,18 @@
|
||||
<template name="viewer">
|
||||
{{#if Template.subscriptionsReady}}
|
||||
<div id="viewer">
|
||||
{{>confirmDeleteDialog}}
|
||||
{{>lesionLocationDialog}}
|
||||
{{>nonTargetLesionDialog}}
|
||||
{{>nonTargetResponseDialog}}
|
||||
{{>timepointTextDialog}}
|
||||
{{ >conformanceCheckFeedback }}
|
||||
|
||||
{{>conformanceCheckFeedback}}
|
||||
{{>hidingPanel}}
|
||||
<div id="viewportAndLesionTable">
|
||||
{{>viewerMain }}
|
||||
{{>lesionTable }}
|
||||
</div>
|
||||
</div>
|
||||
{{else}}
|
||||
{{>loadingText}}
|
||||
{{/if}}
|
||||
</template>
|
||||
@ -1,9 +1,14 @@
|
||||
Session.setDefault('activeViewport', false);
|
||||
|
||||
ViewerStudies = new Meteor.Collection(null);
|
||||
ViewerStudies._debugName = 'ViewerStudies';
|
||||
|
||||
Template.viewer.onCreated(function() {
|
||||
// Attach the Window resize listener
|
||||
$(window).on('resize', handleResize);
|
||||
|
||||
ValidationErrors.remove({});
|
||||
|
||||
var self = this;
|
||||
var firstMeasurementsActivated = false;
|
||||
var contentId = this.data.contentId;
|
||||
@ -97,10 +102,11 @@ Template.viewer.onCreated(function() {
|
||||
Session.set('activeViewport', ViewerData[contentId].activeViewport || false);
|
||||
|
||||
// Set lesion tool buttons as disabled if pixel spacing is not available for active element
|
||||
this.autorun(pixelSpacingAutorunCheck);
|
||||
self.autorun(pixelSpacingAutorunCheck);
|
||||
|
||||
// Update the ViewerStudies collection with the loaded studies
|
||||
ViewerStudies = new Meteor.Collection(null);
|
||||
ViewerStudies.remove({});
|
||||
|
||||
this.data.studies.forEach(function(study) {
|
||||
study.selected = true;
|
||||
ViewerStudies.insert(study);
|
||||
@ -110,11 +116,17 @@ Template.viewer.onCreated(function() {
|
||||
Session.set('patientId', patientId);
|
||||
|
||||
self.autorun(function() {
|
||||
var patientId = Session.get('patientId');
|
||||
self.subscribe('singlePatientTimepoints', patientId);
|
||||
self.subscribe('singlePatientMeasurements', patientId);
|
||||
var dataContext = Template.currentData();
|
||||
self.subscribe('singlePatientAssociatedStudies', dataContext.studies[0].patientId);
|
||||
self.subscribe('singlePatientTimepoints', dataContext.studies[0].patientId);
|
||||
self.subscribe('singlePatientMeasurements', dataContext.studies[0].patientId);
|
||||
|
||||
var subscriptionsReady = self.subscriptionsReady();
|
||||
console.log('autorun viewer.js. Ready: ' + subscriptionsReady);
|
||||
|
||||
if (subscriptionsReady) {
|
||||
TrialResponseCriteria.validateAllDelayed();
|
||||
|
||||
if (self.subscriptionsReady()) {
|
||||
ViewerStudies.find().observe({
|
||||
added: function(study) {
|
||||
// Find the relevant timepoint given the newly added study
|
||||
@ -128,7 +140,7 @@ Template.viewer.onCreated(function() {
|
||||
log.warn('Study added to Viewer has not been associated!');
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Update the added document with its related timepointId
|
||||
ViewerStudies.update(study._id, {
|
||||
$set: {
|
||||
|
||||
68
LesionTracker/client/debugReactivity.js
Normal file
68
LesionTracker/client/debugReactivity.js
Normal file
@ -0,0 +1,68 @@
|
||||
Meteor.startup(function() {
|
||||
var debug = false;
|
||||
|
||||
if (debug === true) {
|
||||
// http://www.meteorpedia.com/read/Debugging_Reactivity
|
||||
|
||||
Meteor.autorun(function(computation) {
|
||||
computation.onInvalidate(function() {
|
||||
console.trace();
|
||||
});
|
||||
});
|
||||
|
||||
var wrappedFind = Meteor.Collection.prototype.find;
|
||||
|
||||
Meteor.Collection.prototype.find = function() {
|
||||
var cursor = wrappedFind.apply(this, arguments);
|
||||
var collectionName = this._name || this._debugName;
|
||||
|
||||
/*cursor.observeChanges({
|
||||
added: function(id, fields) {
|
||||
console.log(collectionName, 'added', id, fields);
|
||||
},
|
||||
changed: function(id, fields) {
|
||||
console.log(collectionName, 'changed', id, fields);
|
||||
},
|
||||
movedBefore: function(id, before) {
|
||||
console.log(collectionName, 'movedBefore', id, before);
|
||||
},
|
||||
removed: function(id) {
|
||||
console.log(collectionName, 'removed', id);
|
||||
}
|
||||
});*/
|
||||
|
||||
cursor.observe({
|
||||
added: function(data) {
|
||||
console.log(collectionName, 'added', data);
|
||||
},
|
||||
changed: function(data) {
|
||||
console.log(collectionName, 'changed', data);
|
||||
},
|
||||
removed: function(data) {
|
||||
console.log(collectionName, 'removed', data);
|
||||
}
|
||||
});
|
||||
|
||||
return cursor;
|
||||
};
|
||||
|
||||
function logRenders() {
|
||||
Object.keys(Template).forEach(function(name) {
|
||||
if (name.indexOf('_') > -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
var template = Template[name];
|
||||
var oldRender = template.rendered;
|
||||
var counter = 0;
|
||||
|
||||
template.rendered = function() {
|
||||
console.log(name, 'render count: ', ++counter);
|
||||
oldRender && oldRender.apply(this, arguments);
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
logRenders();
|
||||
}
|
||||
});
|
||||
@ -1,4 +1,5 @@
|
||||
LesionLocations = new Meteor.Collection(null);
|
||||
LesionLocations._debugName = 'LesionLocations';
|
||||
|
||||
var organGroups = [
|
||||
'Abdominal/Chest Wall',
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
LocationResponses = new Meteor.Collection(null);
|
||||
LocationResponses._debugName = 'LocationResponses';
|
||||
|
||||
LocationResponses.insert({
|
||||
text: 'Complete response',
|
||||
|
||||
@ -1 +0,0 @@
|
||||
PatientLocations = new Meteor.Collection(null);
|
||||
@ -194,11 +194,10 @@
|
||||
y: mouseEventData.currentPoints.image.y - 70,
|
||||
pointNearHandle: pointNearTextBox,
|
||||
active: false,
|
||||
movesIndependently: true,
|
||||
movesIndependently: false,
|
||||
drawnIndependently: true,
|
||||
allowedOutsideImage: true
|
||||
},
|
||||
|
||||
perpendicularStart: {
|
||||
x: mouseEventData.currentPoints.image.x,
|
||||
y: mouseEventData.currentPoints.image.y,
|
||||
@ -208,7 +207,6 @@
|
||||
drawnIndependently: true,
|
||||
index: 2
|
||||
},
|
||||
|
||||
perpendicularEnd: {
|
||||
x: mouseEventData.currentPoints.image.x,
|
||||
y: mouseEventData.currentPoints.image.y,
|
||||
@ -217,7 +215,6 @@
|
||||
drawnIndependently: true,
|
||||
index: 3
|
||||
}
|
||||
|
||||
},
|
||||
imageId: imageId,
|
||||
seriesInstanceUid: seriesInstanceUid,
|
||||
|
||||
@ -141,7 +141,7 @@
|
||||
y: mouseEventData.currentPoints.image.y - 50,
|
||||
pointNearHandle: pointNearTextBox,
|
||||
active: false,
|
||||
movesIndependently: true,
|
||||
movesIndependently: false,
|
||||
drawnIndependently: true,
|
||||
allowedOutsideImage: true
|
||||
}
|
||||
|
||||
@ -59,18 +59,53 @@ Template.associationModal.events({
|
||||
// Sort the study dates, so we can get a range for these values
|
||||
studyDates = studyDates.sort();
|
||||
|
||||
// Create a new timepoint to represent the (baseline or follow-up) studies
|
||||
var timepoint = {
|
||||
timepointType: timepointType,
|
||||
timepointId: uuid.new(),
|
||||
studyInstanceUids: studyInstanceUids,
|
||||
patientId: relatedStudies[0].patientId, // TODO: Revisit this (Should timepoints be related to patientId?)
|
||||
earliestDate: studyDates[0].format('YYYYMMDD'),
|
||||
latestDate: studyDates[studyDates.length - 1].format('YYYYMMDD')
|
||||
};
|
||||
// Check if these studies are already associated with an existing Timepoint
|
||||
var existingTimepoint;
|
||||
if (timepointType === 'baseline') {
|
||||
// If we're trying to associate them to the Baseline, we don't need to
|
||||
// check if the studyInstanceUids are already associated with anything else
|
||||
existingTimepoint = Timepoints.findOne({
|
||||
patientId: relatedStudies[0].patientId,
|
||||
timepointType: 'baseline'
|
||||
});
|
||||
} else {
|
||||
// If we're trying to associate them to a Follow-up, we should check if any
|
||||
// of them are already part of a Follow-up (e.g. Follow-up 1), so that
|
||||
// the rest will also be associated with Follow-up 1.
|
||||
existingTimepoint = Timepoints.findOne({
|
||||
patientId: relatedStudies[0].patientId,
|
||||
studyInstanceUids: {
|
||||
$in: studyInstanceUids
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Insert this timepoint into the Timepoints Collection
|
||||
Timepoints.insert(timepoint);
|
||||
var timepointId;
|
||||
if (existingTimepoint) {
|
||||
// If these studies are already associated with an existing Timepoint,
|
||||
// and the desired timepoint type is the same (e.g. Follow-up), update
|
||||
// this Timepoint instead of creating a new one
|
||||
Timepoints.update(existingTimepoint._id, {
|
||||
$set: {
|
||||
studyInstanceUids: studyInstanceUids
|
||||
}
|
||||
});
|
||||
timepointId = existingTimepoint.timepointId;
|
||||
} else {
|
||||
// Create a new timepoint to represent the (baseline or follow-up) studies
|
||||
var timepoint = {
|
||||
timepointType: timepointType,
|
||||
timepointId: uuid.new(),
|
||||
studyInstanceUids: studyInstanceUids,
|
||||
patientId: relatedStudies[0].patientId,
|
||||
earliestDate: studyDates[0].format('YYYYMMDD'),
|
||||
latestDate: studyDates[studyDates.length - 1].format('YYYYMMDD')
|
||||
};
|
||||
|
||||
// Insert this timepoint into the Timepoints Collection
|
||||
Timepoints.insert(timepoint);
|
||||
timepointId = timepoint.timepointId;
|
||||
}
|
||||
|
||||
// Loop through these studies to associate them with the newly created timepoint
|
||||
relatedStudies.forEach(function(study) {
|
||||
@ -83,7 +118,7 @@ Template.associationModal.events({
|
||||
// If a study already exists, update the entry with the new timepointId
|
||||
Studies.update(existingStudy._id, {
|
||||
$set: {
|
||||
timepointId: timepoint.timepointId
|
||||
timepointId: timepointId
|
||||
}
|
||||
});
|
||||
} else {
|
||||
@ -93,7 +128,7 @@ Template.associationModal.events({
|
||||
delete study._id;
|
||||
|
||||
// Attach the timepointId and insert it into the Studies Collection
|
||||
study.timepointId = timepoint.timepointId;
|
||||
study.timepointId = timepointId;
|
||||
Studies.insert(study);
|
||||
}
|
||||
});
|
||||
|
||||
@ -205,20 +205,6 @@ Template.lesionLocationDialog.events({
|
||||
_id: selectedOptionId
|
||||
});
|
||||
|
||||
var id;
|
||||
var existingLocation = PatientLocations.findOne({
|
||||
location: locationObj.location
|
||||
});
|
||||
if (existingLocation) {
|
||||
id = existingLocation._id;
|
||||
} else {
|
||||
// Adds location data to PatientLocation and retrieve the location ID
|
||||
id = PatientLocations.insert({
|
||||
location: locationObj.location,
|
||||
locationId: locationObj._id
|
||||
});
|
||||
}
|
||||
|
||||
// Add an ID value to the tool data to link it to the Measurements collection
|
||||
if (!measurementData.id) {
|
||||
measurementData.id = 'notready';
|
||||
@ -226,7 +212,6 @@ Template.lesionLocationDialog.events({
|
||||
// Link locationUID with active lesion measurementData
|
||||
measurementData.location = locationObj.location;
|
||||
measurementData.locationId = locationObj.id;
|
||||
measurementData.locationUID = id;
|
||||
|
||||
/// Set the isTarget value to true, since this is the target-lesion dialog callback
|
||||
measurementData.isTarget = true;
|
||||
@ -241,8 +226,7 @@ Template.lesionLocationDialog.events({
|
||||
$set: {
|
||||
location: locationObj.location,
|
||||
locationId: locationObj.id,
|
||||
isNodal: locationObj.isNodal,
|
||||
locationUID: id
|
||||
isNodal: locationObj.isNodal
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -31,10 +31,10 @@ function removeTimepointAssociations() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Update the Studies Collection to remove the link to this Timepoint
|
||||
Studies.update(study._id, {
|
||||
unset: {
|
||||
timepointId: ''
|
||||
// Remove this entry from the Studies Collection
|
||||
Meteor.call('removeAssociatedStudy', study._id, function(error) {
|
||||
if (error) {
|
||||
log.warn(error);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@ -70,27 +70,28 @@ function getLesionLocationCallback(measurementData, eventData) {
|
||||
|
||||
// Find out if this lesion number is already added in the lesion manager for another timepoint
|
||||
// If it is, disable selector location
|
||||
var locationUID = LesionManager.lesionNumberExists(measurementData);
|
||||
if (locationUID) {
|
||||
var locationId = LesionManager.lesionNumberExists(measurementData);
|
||||
if (locationId) {
|
||||
// Add an ID value to the tool data to link it to the Measurements collection
|
||||
measurementData.id = 'notready';
|
||||
|
||||
measurementData.locationUID = locationUID;
|
||||
measurementData.locationId = locationId;
|
||||
|
||||
// Disable the selection of a new location
|
||||
disableLocationSelection(measurementData.locationUID);
|
||||
disableLocationSelection(measurementData.locationId);
|
||||
}
|
||||
|
||||
// Disable selector location to prevent selecting a new location
|
||||
function disableLocationSelection(locationUID) {
|
||||
var locationName = LesionManager.getLocationName(locationUID);
|
||||
selectorLocation.find('option').each(function() {
|
||||
if ($(this).text() === locationName) {
|
||||
// Select location in locations dropdown list
|
||||
selectorLocation.find('option').eq($(this).index()).prop('selected', true);
|
||||
}
|
||||
});
|
||||
|
||||
function disableLocationSelection(locationId) {
|
||||
var locationObject = LesionLocations.findOne({
|
||||
id: locationId
|
||||
});
|
||||
|
||||
if (!locationObject) {
|
||||
return;
|
||||
}
|
||||
|
||||
selectorLocation.find('option[value="' + locationObject._id + '"]').prop('selected', true);
|
||||
selectorLocation.prop('disabled', true);
|
||||
}
|
||||
|
||||
@ -273,26 +274,12 @@ Template.nonTargetLesionDialog.events({
|
||||
_id: selectedOptionId
|
||||
});
|
||||
|
||||
var id;
|
||||
var existingLocation = PatientLocations.findOne({
|
||||
location: locationObj.location
|
||||
});
|
||||
if (existingLocation) {
|
||||
id = existingLocation._id;
|
||||
} else {
|
||||
// Adds location data to PatientLocation and retrieve the location ID
|
||||
id = PatientLocations.insert({
|
||||
location: locationObj.location
|
||||
});
|
||||
}
|
||||
|
||||
if (measurementData.id) {
|
||||
// Update the location data
|
||||
Measurements.update(measurementData.id, {
|
||||
$set: {
|
||||
location: locationObj.location,
|
||||
locationId: locationObj.id,
|
||||
locationUID: id
|
||||
}
|
||||
});
|
||||
} else {
|
||||
@ -300,9 +287,6 @@ Template.nonTargetLesionDialog.events({
|
||||
measurementData.id = 'notready';
|
||||
}
|
||||
|
||||
// Link locationUID with active lesion measurementData
|
||||
measurementData.locationUID = id;
|
||||
|
||||
/// Set the isTarget value to true, since this is the target-lesion dialog callback
|
||||
measurementData.isTarget = false;
|
||||
|
||||
|
||||
@ -76,12 +76,7 @@ Template.studyDateList.events({
|
||||
var loadingIndicator = selectBox.siblings('.loading');
|
||||
loadingIndicator.css('display', 'block');
|
||||
|
||||
Meteor.call('GetStudyMetadata', studyInstanceUid, function(error, study) {
|
||||
if (error) {
|
||||
log.warn(error);
|
||||
return;
|
||||
}
|
||||
|
||||
getStudyMetadata(studyInstanceUid, function(study) {
|
||||
sortStudy(study);
|
||||
|
||||
// Hide the loading indicator
|
||||
|
||||
@ -1,12 +0,0 @@
|
||||
<template name="timepointTextDialog">
|
||||
<div id="timepointTextDialog">
|
||||
<div class="timepointDialogContentWrapper">
|
||||
<div class="dialogContent">
|
||||
<div class="timepointContent">
|
||||
<input type="checkbox" id="checkBoxBaseline" value="ok">
|
||||
<label for="checkBoxBaseline">Baseline</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@ -1,25 +0,0 @@
|
||||
#timepointTextDialog
|
||||
display: none
|
||||
position: absolute
|
||||
z-index: 99
|
||||
|
||||
.timepointDialogContentWrapper
|
||||
position: absolute
|
||||
width: 100px
|
||||
height: 30px
|
||||
padding: 5px
|
||||
background-color: rgba(255,255,255,1)
|
||||
border-top-left-radius: 5px
|
||||
border-top-right-radius: 5px
|
||||
|
||||
.dialogContent
|
||||
margin: 0 auto
|
||||
float: none
|
||||
padding: 0
|
||||
|
||||
.timepointContent
|
||||
font-size: 16px
|
||||
|
||||
#checkBoxBaseline
|
||||
height: 16px
|
||||
width: 16px
|
||||
@ -1,20 +1,3 @@
|
||||
/**
|
||||
* Retrieve a location name (e.g. Liver Right) from the
|
||||
* PatientLocations Collection by id, if it exists. Otherwise,
|
||||
* return an empty string.
|
||||
*
|
||||
* @param id
|
||||
* @returns {*|string}
|
||||
*/
|
||||
function getLocationName(id) {
|
||||
var locationObject = PatientLocations.findOne(id);
|
||||
if (!locationObject || !locationObject.location) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return locationObject.location;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the Timepoint object for a specific Measurement.
|
||||
* If no measurement exists yet, one will be created.
|
||||
@ -33,7 +16,6 @@ function updateLesionData(lesionData) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
var timepoint = Timepoints.findOne({
|
||||
timepointId: study.timepointId
|
||||
});
|
||||
@ -84,7 +66,7 @@ function updateLesionData(lesionData) {
|
||||
|
||||
// Retrieve the location name given the locationUID
|
||||
if (lesionData.locationUID !== undefined) {
|
||||
var locationObj = PatientLocations.findOne({
|
||||
var locationObj = LesionLocations.findOne({
|
||||
locationUID: lesionData.locationUID
|
||||
});
|
||||
|
||||
@ -191,12 +173,11 @@ function lesionNumberExists(lesionData) {
|
||||
return;
|
||||
}
|
||||
|
||||
return measurement.locationUID;
|
||||
return measurement.locationId;
|
||||
}
|
||||
|
||||
LesionManager = {
|
||||
updateLesionData: updateLesionData,
|
||||
getNewLesionNumber: getNewLesionNumber,
|
||||
lesionNumberExists: lesionNumberExists,
|
||||
getLocationName: getLocationName
|
||||
lesionNumberExists: lesionNumberExists
|
||||
};
|
||||
|
||||
@ -50,7 +50,7 @@ function RECIST(image) {
|
||||
shortestDiameter: {
|
||||
numericality: {
|
||||
greaterThanOrEqualTo: 15,
|
||||
message: '^Nodal target lesions must be >= %{count} mm short axis'
|
||||
//message: '^Nodal target lesions must be >= %{count} mm short axis'
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -72,7 +72,7 @@ function RECIST(image) {
|
||||
totalLesionBurden: {
|
||||
numericality: {
|
||||
greaterThanOrEqualTo: 2, // TODO: Check this, the value wasn't specified!
|
||||
message: '^Total lesion burden (SPD target lesions + SPD new lesions) should be greater than %{count}.'
|
||||
//message: '^Total lesion burden (SPD target lesions + SPD new lesions) should be greater than %{count}.'
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -126,7 +126,7 @@ function RECIST(image) {
|
||||
longestDiameter: {
|
||||
numericality: {
|
||||
greaterThanOrEqualTo: 20,
|
||||
message: '^Extranodal lesions must be >= %{count} mm on chest X-ray'
|
||||
//message: '^Extranodal lesions must be >= %{count} mm on chest X-ray'
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -135,7 +135,7 @@ function RECIST(image) {
|
||||
longestDiameter: {
|
||||
numericality: {
|
||||
greaterThanOrEqualTo: 10,
|
||||
message: '^Extranodal target lesions must be >= %{count} mm long axis'
|
||||
//message: '^Extranodal target lesions must be >= %{count} mm long axis'
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -340,6 +340,9 @@ getTrialCriteriaConstraints = function(criteriaType, imageId) {
|
||||
|
||||
// Otherwise, retrieve the series metaData to identify the modality of the image
|
||||
var seriesMetaData = cornerstoneTools.metaData.get('series', imageId);
|
||||
if (!seriesMetaData) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Get the rest of the metaData that has already been loaded by Cornerstone
|
||||
var image = {};
|
||||
@ -363,7 +366,6 @@ getTrialCriteriaConstraints = function(criteriaType, imageId) {
|
||||
});
|
||||
|
||||
if (!study) {
|
||||
log.warn('No study/timepoint association.');
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
// Create a client-only Collection to store our Validation Errors
|
||||
ValidationErrors = new Meteor.Collection(null);
|
||||
ValidationErrors._debugName = 'ValidationErrors';
|
||||
|
||||
// Set Validate.js Library's default options
|
||||
validate.options = {
|
||||
@ -216,8 +217,8 @@ function validateSingleMeasurement(measurementData) {
|
||||
var criteriaType = Session.get('TrialResponseAssessmentCriteria');
|
||||
var currentConstraints = getTrialCriteriaConstraints(criteriaType, measurementData.imageId);
|
||||
|
||||
// If we have no relevant constraints, stop here
|
||||
if (!currentConstraints) {
|
||||
log.warn('No relevant contraints could be applied');
|
||||
return;
|
||||
}
|
||||
|
||||
@ -236,6 +237,11 @@ function validateSingleMeasurement(measurementData) {
|
||||
// Find the specific measurement data for this Measurement at this Timepoint
|
||||
var currentMeasurement = measurement.timepoints[timepointId];
|
||||
|
||||
// Return here if the measurement was removed during validation
|
||||
if (!currentMeasurement) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Include target and nodal flags on the timepoint-specific data so it is easier to validate
|
||||
// TODO: Rethink what to pass to assessSingleMeasurement?
|
||||
currentMeasurement.isTarget = measurement.isTarget;
|
||||
@ -256,10 +262,11 @@ function validateGroups() {
|
||||
var criteriaType = Session.get('TrialResponseAssessmentCriteria');
|
||||
|
||||
Timepoints.find().forEach(function(timepoint) {
|
||||
// TODO: Criteria for the specific image are retrieved from the general set of criteria.
|
||||
// - The acquisitionSliceThickness, for example, may be pulled from the image metadata
|
||||
// - The organ in question, e.g. Chest X-ray, may determine the exact specifications for the current trial criteria
|
||||
// Criteria for the specific image are retrieved from the general set of criteria.
|
||||
var currentConstraints = getTrialCriteriaConstraints(criteriaType);
|
||||
if (!currentConstraints) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Retrieve the current constraints which apply to the specific Timepoint type
|
||||
// (e.g. baseline, followup) that this Measurement is being edited on.
|
||||
@ -289,12 +296,9 @@ function validateAll() {
|
||||
currentMeasurement.lesionNumber = measurement.lesionNumber;
|
||||
currentMeasurement._id = measurement._id;
|
||||
|
||||
// TODO: Criteria for the specific image are retrieved from the general set of criteria.
|
||||
// - The acquisitionSliceThickness, for example, may be pulled from the image metadata
|
||||
// - The organ in question, e.g. Chest X-ray, may determine the exact specifications for the current trial criteria
|
||||
// Criteria for the specific image are retrieved from the general set of criteria.
|
||||
var currentConstraints = getTrialCriteriaConstraints(criteriaType, currentMeasurement.imageId);
|
||||
if (!currentConstraints) {
|
||||
log.warn('No relevant contraints could be applied');
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@ -12,6 +12,10 @@ activateMeasurements = function(element, measurementId, templateData, viewportIn
|
||||
var timepointData = getTimepointObject(imageId);
|
||||
var measurementData = Measurements.findOne(measurementId);
|
||||
|
||||
if (!timepointData) {
|
||||
return;
|
||||
}
|
||||
|
||||
var measurementAtTimepoint = measurementData.timepoints[timepointData.timepointId];
|
||||
if (!measurementAtTimepoint) {
|
||||
return;
|
||||
|
||||
@ -5,11 +5,15 @@ clearTools = function() {
|
||||
var toolStateKeys = Object.keys(toolState).slice(0);
|
||||
|
||||
var viewportElements = $('.imageViewerViewport').not('.empty');
|
||||
var seriesInstanceUIds = []; // Holds seriesInstanceUId of imageViewerViewport elements
|
||||
var seriesInstanceUids = []; // Holds seriesInstanceUid of imageViewerViewport elements
|
||||
viewportElements.each(function(index, element) {
|
||||
var enabledElement = cornerstone.getEnabledElement(element);
|
||||
var series = cornerstoneTools.metaData.get('series', enabledElement.image.imageId);
|
||||
seriesInstanceUIds.push(series.seriesInstanceUid);
|
||||
if (!series) {
|
||||
return;
|
||||
}
|
||||
|
||||
seriesInstanceUids.push(series.seriesInstanceUid);
|
||||
});
|
||||
|
||||
// Set null array for toolState data found by imageId and toolType
|
||||
@ -18,8 +22,12 @@ clearTools = function() {
|
||||
var toolTypeData = toolState[imageId][toolType];
|
||||
if (toolTypeData && toolTypeData.data.length > 0) {
|
||||
var series = cornerstoneTools.metaData.get('series', imageId);
|
||||
// If seriesInstanceUid is found in seriesInstanceUIds, set toolState data as null
|
||||
if (seriesInstanceUIds.indexOf(series.seriesInstanceUid) > -1) {
|
||||
if (!series) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If seriesInstanceUid is found in seriesInstanceUids, set toolState data as null
|
||||
if (seriesInstanceUids.indexOf(series.seriesInstanceUid) > -1) {
|
||||
toolState[imageId][toolType] = {
|
||||
data: []
|
||||
};
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
handleMeasurementAdded = function(e, eventData) {
|
||||
log.info('CornerstoneToolsMeasurementAdded');
|
||||
var measurementData = eventData.measurementData;
|
||||
|
||||
switch (eventData.toolType) {
|
||||
case 'nonTarget':
|
||||
case 'lesion':
|
||||
log.info('CornerstoneToolsMeasurementAdded');
|
||||
LesionManager.updateLesionData(measurementData);
|
||||
TrialResponseCriteria.validateDelayed(measurementData);
|
||||
break;
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
handleMeasurementModified = function(e, eventData) {
|
||||
log.info('CornerstoneToolsMeasurementModified');
|
||||
var measurementData = eventData.measurementData;
|
||||
|
||||
switch (eventData.toolType) {
|
||||
case 'nonTarget':
|
||||
case 'lesion':
|
||||
log.info('CornerstoneToolsMeasurementModified');
|
||||
LesionManager.updateLesionData(measurementData);
|
||||
TrialResponseCriteria.validateDelayed(measurementData);
|
||||
break;
|
||||
|
||||
@ -62,7 +62,7 @@ syncMeasurementAndToolData = function(data) {
|
||||
measurementData.isDeleted = data.isDeleted;
|
||||
measurementData.location = data.location;
|
||||
measurementData.locationUID = data.locationUID;
|
||||
measurementData.patientId = patientId;
|
||||
measurementData.patientId = data.patientId;
|
||||
measurementData.visible = data.visible;
|
||||
measurementData.active = data.active;
|
||||
measurementData.uid = data.uid;
|
||||
|
||||
@ -33,5 +33,8 @@ function dblClickOnStudy(data) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Add the Timepoint name to the Patient name to create the tab title
|
||||
title += ' ' + getTimepointName(timepoint);
|
||||
|
||||
openNewTabWithTimepoint(timepoint.timepointId, title);
|
||||
}
|
||||
@ -29,7 +29,6 @@ Package.onUse(function(api) {
|
||||
// Client-side collections
|
||||
api.addFiles('client/collections/LesionLocations.js', 'client');
|
||||
api.addFiles('client/collections/LocationResponses.js', 'client');
|
||||
api.addFiles('client/collections/PatientLocations.js', 'client');
|
||||
|
||||
// Additional Custom Cornerstone Tools for Lesion Tracker
|
||||
api.addFiles('client/compatibility/lesionTool.js', 'client', {
|
||||
@ -108,9 +107,6 @@ Package.onUse(function(api) {
|
||||
api.addFiles('client/components/nonTargetResponseDialog/nonTargetResponseDialog.styl', 'client');
|
||||
api.addFiles('client/components/nonTargetResponseDialog/nonTargetResponseDialog.js', 'client');
|
||||
|
||||
api.addFiles('client/components/timepointTextDialog/timepointTextDialog.html', 'client');
|
||||
api.addFiles('client/components/timepointTextDialog/timepointTextDialog.styl', 'client');
|
||||
|
||||
api.addFiles('client/components/lesionTrackerWorklistStudy/lesionTrackerWorklistStudy.html', 'client');
|
||||
api.addFiles('client/components/lesionTrackerWorklistStudy/lesionTrackerWorklistStudy.styl', 'client');
|
||||
api.addFiles('client/components/lesionTrackerWorklistStudy/lesionTrackerWorklistStudy.js', 'client');
|
||||
@ -186,7 +182,6 @@ Package.onUse(function(api) {
|
||||
api.export('ValidationErrors', 'client');
|
||||
api.export('LesionLocations', 'client');
|
||||
api.export('LocationResponses', 'client');
|
||||
api.export('PatientLocations', 'client');
|
||||
|
||||
// Export collections spanning both client and server
|
||||
api.export('Measurements', [ 'client', 'server' ]);
|
||||
|
||||
@ -12,6 +12,12 @@ Meteor.publish('studies', function() {
|
||||
return Studies.find();
|
||||
});
|
||||
|
||||
Meteor.publish('singlePatientAssociatedStudies', function(patientId) {
|
||||
return Studies.find({
|
||||
patientId: patientId
|
||||
});
|
||||
});
|
||||
|
||||
Meteor.publish('singlePatientMeasurements', function(patientId) {
|
||||
return Measurements.find({
|
||||
patientId: patientId
|
||||
|
||||
@ -49,5 +49,8 @@ Meteor.methods({
|
||||
},
|
||||
removeTimepoint: function(id) {
|
||||
Timepoints.remove(id);
|
||||
},
|
||||
removeAssociatedStudy: function(id) {
|
||||
Studies.remove(id);
|
||||
}
|
||||
});
|
||||
|
||||
@ -28,10 +28,10 @@ Template.imageThumbnail.onRendered(function() {
|
||||
});
|
||||
|
||||
Template.imageThumbnail.helpers({
|
||||
'percentComplete': function() {
|
||||
percentComplete: function() {
|
||||
var percentComplete = Session.get('CornerstoneThumbnailLoadProgress' + this.thumbnailIndex);
|
||||
if (percentComplete && percentComplete !== 100) {
|
||||
return percentComplete + '%';
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
Template.hangingProtocolButtons.helpers({
|
||||
'isNextAvailable': function() {
|
||||
isNextAvailable: function() {
|
||||
var presentationGroup = Session.get('WindowManagerPresentationGroup');
|
||||
var numPresentationGroups = WindowManager.getNumPresentationGroups();
|
||||
return presentationGroup < numPresentationGroups;
|
||||
},
|
||||
'isPreviousAvailable': function() {
|
||||
isPreviousAvailable: function() {
|
||||
var presentationGroup = Session.get('WindowManagerPresentationGroup');
|
||||
return presentationGroup > 1;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@ -411,6 +411,10 @@ Meteor.startup(function() {
|
||||
cornerstoneTools.magnify.setConfiguration(config);
|
||||
});
|
||||
|
||||
Template.imageViewerViewport.onCreated(function() {
|
||||
console.log('imageViewerViewport onCreated');
|
||||
});
|
||||
|
||||
Template.imageViewerViewport.onRendered(function() {
|
||||
var templateData = Template.currentData();
|
||||
log.info('imageViewerViewport onRendered');
|
||||
@ -455,7 +459,7 @@ Template.imageViewerViewport.onRendered(function() {
|
||||
// TODO: This code block might be refactored
|
||||
// Load previous measurement study when reloading a patient
|
||||
if (!study) {
|
||||
Meteor.call('GetStudyMetadata', this.data.studyInstanceUid, function(error, study) {
|
||||
getStudyMetadata(this.data.studyInstanceUid, function(study) {
|
||||
// Once we have retrieved the data, we sort the series' by series
|
||||
// and instance number in ascending order
|
||||
if (!study) {
|
||||
@ -466,7 +470,7 @@ Template.imageViewerViewport.onRendered(function() {
|
||||
data.study = study;
|
||||
|
||||
setSeries(data, seriesInstanceUid, templateData);
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
data.study = study;
|
||||
@ -482,7 +486,10 @@ Template.imageViewerViewport.onDestroyed(function() {
|
||||
// Try to stop any currently playing clips
|
||||
// Otherwise the interval will continuously throw errors
|
||||
try {
|
||||
cornerstoneTools.stopClip(element);
|
||||
var enabledElement = cornerstone.getEnabledElement(element);
|
||||
if (enabledElement) {
|
||||
cornerstoneTools.stopClip(element);
|
||||
}
|
||||
} catch (error) {
|
||||
log.warn(error);
|
||||
}
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
ViewerWindows = new Meteor.Collection(null);
|
||||
ViewerWindows._debugName = 'ViewerWindows';
|
||||
|
||||
Template.imageViewerViewports.helpers({
|
||||
height: function() {
|
||||
@ -10,14 +11,16 @@ Template.imageViewerViewports.helpers({
|
||||
return 100 / viewportColumns;
|
||||
},
|
||||
viewerWindow: function() {
|
||||
ViewerWindows = new Meteor.Collection(null);
|
||||
log.info('ViewerWindows');
|
||||
//log.info(ViewerWindows.find().fetch());
|
||||
ViewerWindows.remove({});
|
||||
|
||||
log.info("imageViewerViewports viewportArray");
|
||||
log.info('imageViewerViewports viewportArray');
|
||||
|
||||
var viewportRows = this.viewportRows || 1;
|
||||
var viewportColumns = this.viewportColumns || 1;
|
||||
|
||||
var contentId = this.contentId || $("#viewer").parents(".tab-pane.active").attr('id');
|
||||
var contentId = this.contentId || $('#viewer').parents('.tab-pane.active').attr('id');
|
||||
if (this.viewportRows && this.viewportColumns) {
|
||||
viewportRows = this.viewportRows || 1;
|
||||
viewportColumns = this.viewportColumns || 1;
|
||||
@ -47,13 +50,13 @@ Template.imageViewerViewports.helpers({
|
||||
// Update viewerData
|
||||
ViewerData[contentId].viewportRows = viewportRows;
|
||||
ViewerData[contentId].viewportColumns = viewportColumns;
|
||||
Session.set("ViewerData", ViewerData);
|
||||
Session.set('ViewerData', ViewerData);
|
||||
|
||||
this.viewportRows = viewportRows;
|
||||
this.viewportColumns = viewportColumns;
|
||||
|
||||
var numViewports = viewportRows * viewportColumns;
|
||||
for (var i=0; i < numViewports; ++i) {
|
||||
for (var i = 0; i < numViewports; ++i) {
|
||||
var data = {
|
||||
viewportIndex: i,
|
||||
// These two are necessary because otherwise the width and height helpers
|
||||
@ -77,14 +80,17 @@ Template.imageViewerViewports.helpers({
|
||||
ViewerWindows.insert(data);
|
||||
}
|
||||
|
||||
|
||||
// Here we will find out if we need to load any other studies into the viewer
|
||||
|
||||
// We will make a list of unique studyInstanceUids
|
||||
var uniqueStudyInstanceUids = [];
|
||||
|
||||
// Meteor doesn't support Mongo's 'distinct' function, so we have to do this in a loop
|
||||
ViewerWindows.find().forEach(function(window) {
|
||||
var windows = ViewerWindows.find({}, {
|
||||
reactive: false
|
||||
}).fetch();
|
||||
|
||||
windows.forEach(function(window) {
|
||||
var studyInstanceUid = window.studyInstanceUid;
|
||||
if (!studyInstanceUid) {
|
||||
return;
|
||||
@ -99,10 +105,17 @@ Template.imageViewerViewports.helpers({
|
||||
uniqueStudyInstanceUids.push(studyInstanceUid);
|
||||
|
||||
// If any of the associated studies is not already loaded, load it now
|
||||
var loadedStudy = ViewerStudies.findOne({studyInstanceUid: studyInstanceUid});
|
||||
var loadedStudy = ViewerStudies.findOne({
|
||||
studyInstanceUid: studyInstanceUid
|
||||
}, {
|
||||
reactive: false
|
||||
});
|
||||
|
||||
if (!loadedStudy) {
|
||||
// Load the study
|
||||
Meteor.call('GetStudyMetadata', studyInstanceUid, function(error, study) {
|
||||
getStudyMetadata(studyInstanceUid, function(study) {
|
||||
log.info("imageViewerViewports GetStudyMetadata: " + studyInstanceUid);
|
||||
|
||||
// Sort the study's series and instances by series and instance number
|
||||
sortStudy(study);
|
||||
|
||||
@ -112,7 +125,9 @@ Template.imageViewerViewports.helpers({
|
||||
}
|
||||
});
|
||||
|
||||
return ViewerWindows.find();
|
||||
return ViewerWindows.find({}, {
|
||||
reactive: false
|
||||
}).fetch();
|
||||
}
|
||||
});
|
||||
|
||||
@ -122,9 +137,9 @@ var savedSeriesData,
|
||||
|
||||
Template.imageViewerViewports.events({
|
||||
'CornerstoneMouseDoubleClick .imageViewerViewport': function(e) {
|
||||
var container = $(".viewerMain").get(0);
|
||||
var container = $('.viewerMain').get(0);
|
||||
var data;
|
||||
var contentId = this.contentId || $("#viewer").parents(".tab-pane.active").attr('id');
|
||||
var contentId = this.contentId || $('#viewer').parents('.tab-pane.active').attr('id');
|
||||
|
||||
// If there is more than one viewport on screen
|
||||
// And one of them is double-clicked, it should be rendered alone
|
||||
@ -183,4 +198,4 @@ Template.imageViewerViewports.events({
|
||||
$('.imageViewerViewport').eq(0).addClass('zoomed');
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@ -59,7 +59,7 @@ function resultDataToStudyMetadata(resultData) {
|
||||
*/
|
||||
Services.DIMSE.Instances = function(studyInstanceUid) {
|
||||
//var url = buildUrl(server, studyInstanceUid);
|
||||
var result = DIMSE.retrieveInstances(studyInstanceUid);
|
||||
var result = DIMSE.retrieveInstances(studyInstanceUid, null, {0x00080018 : ""});
|
||||
|
||||
console.log("DIMSE Instance retrieval");
|
||||
console.log(result);
|
||||
|
||||
@ -1,5 +1,10 @@
|
||||
<template name="tabContent">
|
||||
<div role="tabpanel" class="tab-pane {{active}}" id="{{contentid}}">
|
||||
{{ >loadingText }}
|
||||
{{>loadingText}}
|
||||
<div class="viewerContainer">
|
||||
<!-- This extra viewerContainer div only exists to be destroyed when switching tabs.
|
||||
It is a workaround because Meteor's onDestroyed and destruction handlers don't fire
|
||||
when removing the actual template from the DOM.-->
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@ -1,4 +1,8 @@
|
||||
.tab-pane
|
||||
.loadingTextDiv
|
||||
h5
|
||||
color: #777
|
||||
color: #777
|
||||
|
||||
.viewerContainer
|
||||
height: 100%
|
||||
width: 100%
|
||||
@ -7,9 +7,9 @@
|
||||
{{ >tabTitle }}
|
||||
{{ /each }}
|
||||
</ul>
|
||||
<div class="tab-content">
|
||||
<div id="worklistTabs" class="tab-content">
|
||||
<div role="tabpanel" class="tab-pane active" id="worklistTab">
|
||||
<div id="worklistContainer" class="container">
|
||||
<div class="worklistContainer">
|
||||
{{> worklistResult }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -11,20 +11,13 @@ ViewerData = Session.get('ViewerData') || {};
|
||||
|
||||
// Create the WorklistTabs collection
|
||||
WorklistTabs = new Meteor.Collection(null);
|
||||
WorklistTabs._debugName = 'WorklistTabs';
|
||||
|
||||
// Define the WorklistStudies Collection
|
||||
// This is a client-side only Collection which
|
||||
// Stores the list of studies in the Worklist
|
||||
WorklistStudies = new Meteor.Collection(null);
|
||||
|
||||
Template.worklist.onCreated(function() {
|
||||
var self = this;
|
||||
if (Worklist.subscriptions) {
|
||||
Worklist.subscriptions.forEach(function(collectionName) {
|
||||
self.subscribe(collectionName);
|
||||
});
|
||||
}
|
||||
});
|
||||
WorklistStudies._debugName = 'WorklistStudies';
|
||||
|
||||
Template.worklist.onRendered(function() {
|
||||
// If there is a tab set as active in the Session,
|
||||
|
||||
@ -9,37 +9,18 @@ body
|
||||
-ms-user-select: none
|
||||
user-select: none
|
||||
|
||||
input.worklist-search
|
||||
height: 25px
|
||||
background-color: #888888
|
||||
width: 100%
|
||||
|
||||
#tblStudyList
|
||||
tr
|
||||
height: 20px
|
||||
|
||||
.patient-name-input
|
||||
width: 100%
|
||||
|
||||
.worklist-input
|
||||
width: 100%
|
||||
|
||||
.modality-input
|
||||
width: 100%
|
||||
|
||||
.patientid-input
|
||||
width: 100%
|
||||
|
||||
.study-description-input
|
||||
width: 100%
|
||||
|
||||
#worklistTab
|
||||
background-color: #202020
|
||||
|
||||
#worklistContainer
|
||||
.worklistContainer
|
||||
background-color: #202020
|
||||
margin: 0 auto
|
||||
color: white
|
||||
width:90%
|
||||
width: 90%
|
||||
padding-top: 10px
|
||||
|
||||
#tabs
|
||||
@ -99,7 +80,7 @@ input.worklist-search
|
||||
.tab-content
|
||||
width: 100%
|
||||
height: calc(100% - 91px)
|
||||
|
||||
|
||||
.tab-pane
|
||||
width: 100%
|
||||
height: 100%
|
||||
@ -1,5 +1,5 @@
|
||||
<template name="worklistResult">
|
||||
<table id="tblStudyList" class="table table-striped noselect">
|
||||
<table id="tblStudyList" class="worklistResult table table-striped noselect">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
|
||||
@ -115,6 +115,20 @@ function search() {
|
||||
});
|
||||
}
|
||||
|
||||
Template.worklistResult.onCreated(function() {
|
||||
console.log('WorklistResult onCreated!');
|
||||
var self = this;
|
||||
if (Worklist.subscriptions) {
|
||||
Worklist.subscriptions.forEach(function(collectionName) {
|
||||
self.subscribe(collectionName);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
Template.worklistResult.onDestroyed(function() {
|
||||
console.log('WorklistResult onDestroyed!');
|
||||
});
|
||||
|
||||
Template.worklistResult.events({
|
||||
'keydown input': function(e) {
|
||||
if (e.which === 13) { // Enter
|
||||
|
||||
@ -15,8 +15,14 @@ table#tblStudyList
|
||||
#numImages.worklist-search, #modality.worklist-search
|
||||
visibility: hidden
|
||||
|
||||
input.worklist-search
|
||||
height: 25px
|
||||
background-color: #888888
|
||||
width: 100%
|
||||
|
||||
tbody
|
||||
tr
|
||||
height: 20px
|
||||
padding: 4px
|
||||
border: 1px solid #282828
|
||||
background-color: black
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
// Maybe we should use regular Worklist collection?
|
||||
WorklistSelectedStudies = new Meteor.Collection(null);
|
||||
WorklistSelectedStudies._debugName = 'WorklistSelectedStudies';
|
||||
|
||||
function handleShiftClick(studyRow, data) {
|
||||
log.info('shiftKey');
|
||||
|
||||
@ -12,8 +12,6 @@ var StudyMetaData = {};
|
||||
* @param failCallback The callback function to be executed when the study retrieval has failed
|
||||
*/
|
||||
getStudyMetadata = function(studyInstanceUid, doneCallback, failCallback) {
|
||||
log.info('worklistStudy getStudyMetadata');
|
||||
|
||||
// If the StudyMetaData cache already has data related to this
|
||||
// studyInstanceUid, then we should fire the doneCallback with this data
|
||||
// and stop here.
|
||||
@ -26,6 +24,8 @@ getStudyMetadata = function(studyInstanceUid, doneCallback, failCallback) {
|
||||
// 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) {
|
||||
log.info('worklistStudy getStudyMetadata: ' + studyInstanceUid);
|
||||
|
||||
if (error) {
|
||||
log.warn(error);
|
||||
failCallback(error);
|
||||
|
||||
@ -8,6 +8,7 @@ switchToTab = function(contentId) {
|
||||
if (!contentId) {
|
||||
return;
|
||||
}
|
||||
|
||||
log.info('Switching to tab: ' + contentId);
|
||||
|
||||
// Use Bootstrap's Tab JavaScript to show the contents of the current tab
|
||||
@ -15,7 +16,8 @@ switchToTab = function(contentId) {
|
||||
$('.tabTitle a[data-target="#' + contentId + '"]').tab('show');
|
||||
|
||||
// Remove any previous Viewers from the DOM
|
||||
$('#viewer').remove();
|
||||
$('.viewerContainer').remove();
|
||||
$('.worklistContainer').remove();
|
||||
|
||||
// Update the 'activeContentId' variable in Session
|
||||
Session.set('activeContentId', contentId);
|
||||
@ -23,7 +25,16 @@ switchToTab = function(contentId) {
|
||||
// If we are switching to the Worklist 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.
|
||||
var container;
|
||||
if (contentId === 'worklistTab') {
|
||||
container = $('.tab-content').find('#worklistTab').get(0);
|
||||
var worklistContainer = document.createElement('div');
|
||||
worklistContainer.classList.add('worklistContainer');
|
||||
container.appendChild(worklistContainer);
|
||||
|
||||
// Use Blaze to render the WorklistResult Template into the container
|
||||
Blaze.render(Template.worklistResult, worklistContainer);
|
||||
|
||||
document.body.style.overflow = null;
|
||||
document.body.style.height = null;
|
||||
document.body.style.minWidth = null;
|
||||
@ -67,10 +78,13 @@ switchToTab = function(contentId) {
|
||||
}
|
||||
|
||||
// Remove the loading text template that is inside the tab container by default
|
||||
var viewerContainer = document.createElement('div');
|
||||
viewerContainer.classList.add('viewerContainer');
|
||||
container.innerHTML = '';
|
||||
container.appendChild(viewerContainer);
|
||||
|
||||
// Use Blaze to render the Viewer Template into the container
|
||||
UI.renderWithData(Template.viewer, data, container);
|
||||
Blaze.renderWithData(Template.viewer, data, viewerContainer);
|
||||
|
||||
// Retrieve the DOM element of the viewer
|
||||
var imageViewer = $('#viewer');
|
||||
@ -87,4 +101,4 @@ switchToTab = function(contentId) {
|
||||
document.body.style.position = 'fixed';
|
||||
}
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
Loading…
Reference in New Issue
Block a user