diff --git a/LesionTracker/client/components/app/app.html b/LesionTracker/client/components/app/app.html index 5fd7a1ab7..0410e9d30 100644 --- a/LesionTracker/client/components/app/app.html +++ b/LesionTracker/client/components/app/app.html @@ -21,13 +21,6 @@ {{/section}} {{/header}} -
-
-
- {{>studylistResult}} -
-
-
-
-
+ + {{>Template.dynamic template=(choose this.template 'studylist') data=this}} diff --git a/LesionTracker/client/components/app/app.js b/LesionTracker/client/components/app/app.js index 8ad73368a..0450bb9f6 100644 --- a/LesionTracker/client/components/app/app.js +++ b/LesionTracker/client/components/app/app.js @@ -1,19 +1,18 @@ import { Template } from 'meteor/templating'; import { Session } from 'meteor/session'; +import { Router } from 'meteor/iron:router'; import { ReactiveVar } from 'meteor/reactive-var'; import { OHIF } from 'meteor/ohif:core'; const studylistContentId = 'studylistTab'; const viewerContentId = 'viewerTab'; -// Define the ViewerData global object -// If there is currently any Session data for this object, -// use this to repopulate the variable +// Define the OHIF.viewer.data global object Template.app.onCreated(() => { const instance = Template.instance(); instance.headerClasses = new ReactiveVar(''); - ViewerData = Session.get('ViewerData') || {}; + OHIF.viewer.data = instance.data.viewerData || {}; OHIF.header.dropdown.setItems([{ action: OHIF.user.audit, @@ -46,24 +45,25 @@ Template.app.onCreated(() => { }]); instance.autorun(() => { - const contentId = Session.get('activeContentId'); - instance.headerClasses.set(contentId === viewerContentId ? '' : 'header-big'); - }); -}); + const currentRoute = Router.current(); + if (!currentRoute) return; + const routeName = currentRoute.route.getName(); + const isViewer = routeName.indexOf('viewer') === 0; -Template.app.onRendered(() => { - const contentId = Session.get('activeContentId'); - if (contentId === viewerContentId) { - switchToTab(contentId); - } + // Add or remove the strech class from body + $(document.body)[isViewer ? 'addClass' : 'removeClass']('stretch'); + + // Set the header on its bigger version if the viewer is not opened + instance.headerClasses.set(isViewer ? '' : 'header-big'); + + // Set the viewer open state on session + Session.set('ViewerOpened', isViewer); + }); }); Template.app.events({ 'click .js-toggle-studyList'(event) { - const contentId = Session.get('activeContentId'); - OHIF.ui.unsavedChanges.presentProactiveDialog('viewer.*', (hasChanges, userChoice) => { - if (hasChanges) { switch (userChoice) { @@ -79,20 +79,12 @@ Template.app.events({ } } - - if (contentId !== studylistContentId) { - switchToTab(studylistContentId); - } else { - switchToTab(viewerContentId); - } - }, { position: { x: event.clientX + 15, y: event.clientY + 15 } }); - } }); @@ -104,7 +96,7 @@ Template.app.helpers({ // If the Viewer has not been opened yet, 'Back to viewer' should // not be displayed - const viewerContentExists = !!Object.keys(ViewerData).length; + const viewerContentExists = !!Object.keys(OHIF.viewer.data).length; if (!viewerContentExists) { return; } diff --git a/LesionTracker/client/components/viewer/viewer.js b/LesionTracker/client/components/viewer/viewer.js index 1b87b9f7c..c9b26d3bd 100644 --- a/LesionTracker/client/components/viewer/viewer.js +++ b/LesionTracker/client/components/viewer/viewer.js @@ -31,12 +31,8 @@ Meteor.startup(() => { }); Template.viewer.onCreated(() => { - Session.set('ViewerReady', false); - const toolManager = OHIF.viewerbase.toolManager; - ViewerData = window.ViewerData || ViewerData; - const instance = Template.instance(); const { TimepointApi, MeasurementApi, ConformanceCriteria } = OHIF.measurements; @@ -59,7 +55,6 @@ Template.viewer.onCreated(() => { instance.data.state.set('leftSidebar', Session.get('leftSidebar')); instance.data.state.set('rightSidebar', Session.get('rightSidebar')); - const contentId = instance.data.contentId; const viewportUtils = OHIF.viewerbase.viewportUtils; OHIF.viewer.functionList = $.extend(OHIF.viewer.functionList, { @@ -84,18 +79,16 @@ Template.viewer.onCreated(() => { linkStackScroll: viewportUtils.linkStackScroll }); - if (ViewerData[contentId].loadedSeriesData) { + if (OHIF.viewer.data.loadedSeriesData) { OHIF.log.info('Reloading previous loadedSeriesData'); - OHIF.viewer.loadedSeriesData = ViewerData[contentId].loadedSeriesData; - + OHIF.viewer.loadedSeriesData = OHIF.viewer.data.loadedSeriesData; } else { - OHIF.log.info('Setting default ViewerData'); + OHIF.log.info('Setting default viewer data'); OHIF.viewer.loadedSeriesData = {}; - ViewerData[contentId].loadedSeriesData = {}; - Session.setPersistent('ViewerData', ViewerData); + OHIF.viewer.data.loadedSeriesData = {}; } - Session.set('activeViewport', ViewerData[contentId].activeViewport || false); + Session.set('activeViewport', OHIF.viewer.data.activeViewport || false); // Set lesion tool buttons as disabled if pixel spacing is not available for active element instance.autorun(OHIF.lesiontracker.pixelSpacingAutorunCheck); diff --git a/LesionTracker/client/routes.js b/LesionTracker/client/routes.js index ac8a8e6c2..0f2fdb6c1 100644 --- a/LesionTracker/client/routes.js +++ b/LesionTracker/client/routes.js @@ -1,9 +1,9 @@ import { Meteor } from 'meteor/meteor'; -import { Session } from 'meteor/session'; import { Router } from 'meteor/iron:router'; import { OHIF } from 'meteor/ohif:core'; -Session.setDefault('ViewerData', {}); +// TODO: remove the line below +window.Router = Router; // verifyEmail controls whether emailVerification template will be rendered or not const verifyEmail = Meteor.settings && Meteor.settings.public && Meteor.settings.public.verifyEmail || false; @@ -19,27 +19,21 @@ const data = {}; const routerOptions = { data }; -Router.route('/', function() { - // Check user is logged in - if (Meteor.user() && Meteor.userId()) { +Router.route('/', { + name: 'home', + onBeforeAction: function() { + // Check if user needs to verify its email if (verifyEmail && Meteor.user().emails && !Meteor.user().emails[0].verified) { this.render('emailVerification', routerOptions); } else { - const contentId = Session.get('activeContentId'); - if (!contentId) { - Session.setPersistent('activeContentId', 'studylistTab'); - } - this.render('app', routerOptions); } - } else { - this.render('entrySignIn', routerOptions); } }); Router.route('/viewer/timepoints/:_id', { layoutTemplate: 'layout', - name: 'viewer', + name: 'viewerTimepoint', onBeforeAction: function() { const timepointId = this.params._id; @@ -48,6 +42,47 @@ Router.route('/viewer/timepoints/:_id', { } }); +OHIF.viewer.prepare = ({ studyInstanceUids, timepointId }) => { + // Clear the cornerstone tool data to sync the measurements with the measurements API + cornerstoneTools.globalImageIdSpecificToolStateManager = cornerstoneTools.newImageIdSpecificToolStateManager(); + + return new Promise((resolve, reject) => { + OHIF.studylist.retrieveStudiesMetadata(studyInstanceUids).then(studies => { + // Add additional metadata to our study from the studylist + studies.forEach(study => { + const studylistStudy = OHIF.studylist.collections.Studies.findOne({ + studyInstanceUid: study.studyInstanceUid + }); + + if (!studylistStudy) { + return; + } + + Object.assign(study, studylistStudy); + }); + + resolve(studies); + }).catch(reject); + }); +}; + +Router.route('/viewer/studies/:studyInstanceUids', { + name: 'viewerStudies', + onBeforeAction: function() { + this.render('app', { data: { template: 'loadingText' } }); + + const studyInstanceUids = this.params.studyInstanceUids.split(';'); + OHIF.viewer.prepare({ studyInstanceUids }).then(studies => { + this.render('app', { + data: { + template: 'viewer', + studies + } + }); + }); + } +}); + Router.onBeforeAction(function() { if (!Meteor.userId() && !Meteor.loggingIn()) { this.render('entrySignIn'); diff --git a/OHIFViewer/client/components/ohifViewer/ohifViewer.js b/OHIFViewer/client/components/ohifViewer/ohifViewer.js index a163e3f18..57ba70066 100644 --- a/OHIFViewer/client/components/ohifViewer/ohifViewer.js +++ b/OHIFViewer/client/components/ohifViewer/ohifViewer.js @@ -5,13 +5,6 @@ import { OHIF } from 'meteor/ohif:core'; const studylistContentId = 'studylistTab'; let lastContentId; -// Define the ViewerData global object -// If there is currently any Session data for this object, -// use this to repopulate the variable -Template.ohifViewer.onCreated(() => { - ViewerData = Session.get('ViewerData') || {}; -}); - Template.ohifViewer.events({ 'click .js-toggle-studyList'() { const contentId = Session.get('activeContentId'); @@ -31,11 +24,10 @@ Template.ohifViewer.events({ Template.ohifViewer.helpers({ studyListToggleText() { const contentId = Session.get('activeContentId'); - Session.get('ViewerData'); // If the Viewer has not been opened yet, 'Back to viewer' should // not be displayed - const viewerContentExists = !!Object.keys(ViewerData).length; + const viewerContentExists = !!Object.keys(OHIF.viewer.data).length; if (!viewerContentExists) { return; } diff --git a/OHIFViewer/client/components/viewer/viewer.js b/OHIFViewer/client/components/viewer/viewer.js index 3dd7bd2d2..cdbca4bec 100644 --- a/OHIFViewer/client/components/viewer/viewer.js +++ b/OHIFViewer/client/components/viewer/viewer.js @@ -2,14 +2,13 @@ import { Meteor } from 'meteor/meteor'; import { Session } from 'meteor/session'; import { Template } from 'meteor/templating'; import { ReactiveDict } from 'meteor/reactive-dict'; -import { Tracker } from 'meteor/tracker' - +import { Tracker } from 'meteor/tracker'; import { OHIF } from 'meteor/ohif:core'; + import 'meteor/ohif:cornerstone'; import 'meteor/ohif:viewerbase'; import 'meteor/ohif:metadata'; - /** * Inits OHIF Hanging Protocol's onReady. * It waits for OHIF Hanging Protocol to be ready to instantiate the ProtocolEngine @@ -47,7 +46,6 @@ Meteor.startup(() => { Session.setDefault('leftSidebar', false); Session.setDefault('rightSidebar', false); - OHIF.viewer = OHIF.viewer || {}; OHIF.viewer.defaultTool = 'wwwc'; OHIF.viewer.refLinesEnabled = true; OHIF.viewer.cine = { @@ -77,9 +75,7 @@ Meteor.startup(() => { cornerstoneTools.metaData.addProvider(metadataProvider.provider.bind(metadataProvider)); }); - Template.viewer.onCreated(() => { - Session.set('ViewerReady', false); const instance = Template.instance(); @@ -88,24 +84,22 @@ Template.viewer.onCreated(() => { instance.data.state.set('leftSidebar', Session.get('leftSidebar')); instance.data.state.set('rightSidebar', Session.get('rightSidebar')); - const contentId = instance.data.contentId; - - if (ViewerData[contentId] && ViewerData[contentId].loadedSeriesData) { + if (OHIF.viewer.data && OHIF.viewer.data.loadedSeriesData) { OHIF.log.info('Reloading previous loadedSeriesData'); - OHIF.viewer.loadedSeriesData = ViewerData[contentId].loadedSeriesData; + OHIF.viewer.loadedSeriesData = OHIF.viewer.data.loadedSeriesData; } else { - OHIF.log.info('Setting default ViewerData'); + OHIF.log.info('Setting default viewer data'); OHIF.viewer.loadedSeriesData = {}; - ViewerData[contentId] = {}; - ViewerData[contentId].loadedSeriesData = OHIF.viewer.loadedSeriesData; + OHIF.viewer.data = {}; + OHIF.viewer.data.loadedSeriesData = OHIF.viewer.loadedSeriesData; // Update the viewer data object - ViewerData[contentId].viewportColumns = 1; - ViewerData[contentId].viewportRows = 1; - ViewerData[contentId].activeViewport = 0; + OHIF.viewer.data.viewportColumns = 1; + OHIF.viewer.data.viewportRows = 1; + OHIF.viewer.data.activeViewport = 0; } - Session.set('activeViewport', ViewerData[contentId].activeViewport || 0); + Session.set('activeViewport', OHIF.viewer.data.activeViewport || 0); // @TypeSafeStudies // Clears OHIF.viewer.Studies collection @@ -115,7 +109,7 @@ Template.viewer.onCreated(() => { // Clears OHIF.viewer.StudyMetadataList collection OHIF.viewer.StudyMetadataList.removeAll(); - ViewerData[contentId].studyInstanceUids = []; + OHIF.viewer.data.studyInstanceUids = []; instance.data.studies.forEach(study => { const studyMetadata = new OHIF.metadata.StudyMetadata(study, study.studyInstanceUid); const displaySets = OHIF.viewerbase.sortingManager.getDisplaySets(studyMetadata); @@ -126,10 +120,8 @@ Template.viewer.onCreated(() => { study.displaySets = displaySets; OHIF.viewer.Studies.insert(study); OHIF.viewer.StudyMetadataList.insert(studyMetadata); - ViewerData[contentId].studyInstanceUids.push(study.studyInstanceUid); + OHIF.viewer.data.studyInstanceUids.push(study.studyInstanceUid); }); - - Session.set('ViewerData', ViewerData); }); Template.viewer.onRendered(function() { @@ -154,6 +146,7 @@ Template.viewer.events({ const current = instance.data.state.get('leftSidebar'); instance.data.state.set('leftSidebar', !current); }, + 'click .js-toggle-protocol-editor'() { const instance = Template.instance(); const current = instance.data.state.get('rightSidebar'); diff --git a/OHIFViewer/client/routes.js b/OHIFViewer/client/routes.js index 6ef416552..e09fb2711 100644 --- a/OHIFViewer/client/routes.js +++ b/OHIFViewer/client/routes.js @@ -1,8 +1,6 @@ import { Session } from 'meteor/session'; import { Router } from 'meteor/iron:router'; -Session.setDefault('ViewerData', {}); - Router.configure({ layoutTemplate: 'layout', loadingTemplate: 'layout' @@ -31,4 +29,4 @@ Router.route('/viewer/:_id', { } }); } -}); \ No newline at end of file +}); diff --git a/Packages/ohif-design/styles/common/global.styl b/Packages/ohif-design/styles/common/global.styl index 519222e1c..37c5080a3 100644 --- a/Packages/ohif-design/styles/common/global.styl +++ b/Packages/ohif-design/styles/common/global.styl @@ -1,8 +1,16 @@ @import "{ohif:design}/app" html body + theme('background-color', '$primaryBackgroundColor') font-family: 'Roboto', 'OpenSans', 'HelveticaNeue-Light', 'Helvetica Neue Light', 'Helvetica Neue', Helvetica, Arial, 'Lucida Grande', sans-serif +html body.stretch + height: 100% + minWidth: 0 + overflow: hidden + position: fixed + width: 100% + html hr theme('border-top', '1px solid $uiBorderColor') diff --git a/Packages/ohif-hanging-protocols/client/components/ruleEntryDialog/ruleEntryDialog.js b/Packages/ohif-hanging-protocols/client/components/ruleEntryDialog/ruleEntryDialog.js index 45a7e6a9c..e641faf93 100644 --- a/Packages/ohif-hanging-protocols/client/components/ruleEntryDialog/ruleEntryDialog.js +++ b/Packages/ohif-hanging-protocols/client/components/ruleEntryDialog/ruleEntryDialog.js @@ -138,7 +138,7 @@ function getAbstractPriorValue(imageId) { return; } - const studies = StudyListStudies.find({ + const studies = OHIF.studylist.collections.Studies.find({ patientId: currentStudy.patientId, studyDate: { $lt: currentStudy.studyDate diff --git a/Packages/ohif-lesiontracker/client/lib/studylist/openNewTabWithTimepoint.js b/Packages/ohif-lesiontracker/client/lib/studylist/openNewTabWithTimepoint.js index 3b5900362..d020b192b 100644 --- a/Packages/ohif-lesiontracker/client/lib/studylist/openNewTabWithTimepoint.js +++ b/Packages/ohif-lesiontracker/client/lib/studylist/openNewTabWithTimepoint.js @@ -10,7 +10,7 @@ import { OHIF } from 'meteor/ohif:core'; OHIF.lesiontracker.openNewTabWithTimepoint = timepointId => { const contentId = 'viewerTab'; - const Timepoints = StudyList.timepointApi.timepoints; + const Timepoints = OHIF.studylist.timepointApi.timepoints; const timepoint = Timepoints.findOne({ timepointId: timepointId }); @@ -25,10 +25,8 @@ OHIF.lesiontracker.openNewTabWithTimepoint = timepointId => { throw 'No studies found that are related to this timepoint'; } - ViewerData = window.ViewerData || ViewerData; - - // Update the ViewerData global object - ViewerData[contentId] = { + // Update the OHIF.viewer.data global object + OHIF.viewer.data = { contentId: contentId, studyInstanceUids: data.studyInstanceUids, timepointIds: data.timepointIds, @@ -59,7 +57,7 @@ function getDataFromTimepoint(timepoint) { // Otherwise, this is a follow-up exam, so we should also find the baseline timepoint, // and all studies related to it. We also enforce that the Baseline should have a studyDate // prior to the latest studyDate in the current (Follow-up) Timepoint. - const Timepoints = StudyList.timepointApi.timepoints; + const Timepoints = OHIF.studylist.timepointApi.timepoints; const baseline = Timepoints.findOne({ timepointType: 'baseline', patientId: timepoint.patientId, diff --git a/Packages/ohif-lesiontracker/client/lib/studylist/studylistModification.js b/Packages/ohif-lesiontracker/client/lib/studylist/studylistModification.js index 969d548c4..e757c9ca0 100644 --- a/Packages/ohif-lesiontracker/client/lib/studylist/studylistModification.js +++ b/Packages/ohif-lesiontracker/client/lib/studylist/studylistModification.js @@ -2,11 +2,11 @@ import { Meteor } from 'meteor/meteor'; import { OHIF } from 'meteor/ohif:core'; Meteor.startup(function() { - StudyList.callbacks.dblClickOnStudy = dblClickOnStudy; - StudyList.callbacks.middleClickOnStudy = dblClickOnStudy; + OHIF.studylist.callbacks.dblClickOnStudy = dblClickOnStudy; + OHIF.studylist.callbacks.middleClickOnStudy = dblClickOnStudy; - StudyList.timepointApi = new OHIF.measurements.TimepointApi(); - StudyList.timepointApi.retrieveTimepoints(); + OHIF.studylist.timepointApi = new OHIF.measurements.TimepointApi(); + OHIF.studylist.timepointApi.retrieveTimepoints(); }); /** @@ -14,7 +14,7 @@ Meteor.startup(function() { */ const dblClickOnStudy = data => { // Find the relevant timepoint given the clicked-on study - const timepointApi = StudyList.timepointApi; + const timepointApi = OHIF.studylist.timepointApi; if (!timepointApi) { OHIF.log.warn('No timepoint api on dbl-clicked study?'); return; @@ -37,10 +37,8 @@ const dblClickOnStudy = data => { const openTab = studyInstanceUid => { const contentId = 'viewerTab'; - ViewerData = window.ViewerData || ViewerData; - - // Update the ViewerData global object - ViewerData[contentId] = { + // Update the OHIF.viewer.data global object + OHIF.viewer.data = { contentId: contentId, isUnassociatedStudy: true, studyInstanceUids: [studyInstanceUid] diff --git a/Packages/ohif-measurements/client/components/association/associationModal/associationModal.js b/Packages/ohif-measurements/client/components/association/associationModal/associationModal.js index 1b4109aae..3c1d872a2 100644 --- a/Packages/ohif-measurements/client/components/association/associationModal/associationModal.js +++ b/Packages/ohif-measurements/client/components/association/associationModal/associationModal.js @@ -11,7 +11,7 @@ Template.dialogStudyAssociation.onCreated(() => { instance.data.confirmCallback = (formData, resolve) => { OHIF.log.info('Saving associations'); - const Timepoints = StudyList.timepointApi.timepoints; + const Timepoints = OHIF.studylist.timepointApi.timepoints; // Find the rows of the study association table const $tableRows = instance.$('#studyAssociationTable table tbody tr'); @@ -138,7 +138,7 @@ Template.dialogStudyAssociation.onCreated(() => { }; }); - StudyList.timepointApi.storeTimepoints(); + OHIF.studylist.timepointApi.storeTimepoints(); resolve(); }; diff --git a/Packages/ohif-measurements/client/components/association/associationModal/studyAssociationTable/studyAssociationTable.js b/Packages/ohif-measurements/client/components/association/associationModal/studyAssociationTable/studyAssociationTable.js index 141da35be..a3d4f97d3 100644 --- a/Packages/ohif-measurements/client/components/association/associationModal/studyAssociationTable/studyAssociationTable.js +++ b/Packages/ohif-measurements/client/components/association/associationModal/studyAssociationTable/studyAssociationTable.js @@ -52,7 +52,7 @@ function autoSelectStudies(selectedStudies) { // Fetch autoselected studies based on the date range // Note that we used MongoDB's fetch here so we have a mutable array, // rather than a Cursor - const autoselected = StudyListStudies.find({ + const autoselected = OHIF.studylist.collections.Studies.find({ studyDate: { $gte: range.earliestDate.format('YYYYMMDD'), $lte: range.latestDate.format('YYYYMMDD') diff --git a/Packages/ohif-measurements/client/components/longitudinal/dropdown.js b/Packages/ohif-measurements/client/components/longitudinal/dropdown.js index a37c90838..c940ac853 100644 --- a/Packages/ohif-measurements/client/components/longitudinal/dropdown.js +++ b/Packages/ohif-measurements/client/components/longitudinal/dropdown.js @@ -12,7 +12,7 @@ const getAssociationAssessment = () => { }; // check if timepointApi is available - const timepointApi = StudyList.timepointApi; + const timepointApi = OHIF.studylist.timepointApi; if (timepointApi) { // Get a Cursor pointing to the selected Studies from the StudyList const selectedStudies = OHIF.studylist.getSelectedStudies(); @@ -46,10 +46,8 @@ const viewStudies = () => { const studyInstanceUids = selectedStudies.map(study => study.studyInstanceUid); const contentId = 'viewerTab'; - ViewerData = window.ViewerData || ViewerData; - - // Update the ViewerData global object - ViewerData[contentId] = { + // Update the OHIF.viewer.data global object + OHIF.viewer.data = { contentId: contentId, studyInstanceUids: studyInstanceUids }; @@ -77,7 +75,7 @@ const removeTimepointAssociations = event => { const selectedStudies = OHIF.studylist.getSelectedStudies(); // Find the Timepoint that was previously referenced - const timepointApi = StudyList.timepointApi; + const timepointApi = OHIF.studylist.timepointApi; if (!timepointApi) { OHIF.log.error('Remove Study/Timepoint Association: No Timepoint API found.'); return; diff --git a/Packages/ohif-measurements/client/components/longitudinal/longitudinalStudyListStudy/longitudinalStudyListStudy.html b/Packages/ohif-measurements/client/components/longitudinal/longitudinalStudyListStudy/longitudinalStudyListStudy.html index 6698b545d..a69d2900e 100644 --- a/Packages/ohif-measurements/client/components/longitudinal/longitudinalStudyListStudy/longitudinalStudyListStudy.html +++ b/Packages/ohif-measurements/client/components/longitudinal/longitudinalStudyListStudy/longitudinalStudyListStudy.html @@ -1,5 +1,5 @@