Mostly style files and Hanging Protocol changes

This commit is contained in:
Emanuel F. Oliveira 2017-01-16 13:48:23 -02:00
parent 680beb163f
commit 21400c5836
48 changed files with 280 additions and 576 deletions

View File

@ -1,324 +1,3 @@
import { OHIF } from 'meteor/ohif:core'; import { OHIF } from 'meteor/ohif:core';
OHIF.viewer = {}; OHIF.viewer = {};
// Return the display sets map sequence of display sets and viewports
OHIF.viewer.getDisplaySetSequenceMap = () => {
// Get the viewport data list
const viewportDataList = window.layoutManager.viewportData;
// Create a map to control the display set sequence
const sequenceMap = new Map();
// Iterate over each viewport and register its details on the sequence map
viewportDataList.forEach((viewportData, viewportIndex) => {
// Get the current study
const currentStudy = _.findWhere(window.layoutManager.studies, {
studyInstanceUid: viewportData.studyInstanceUid
}) || window.layoutManager.studies[0];
// Get the display sets
const displaySets = currentStudy.displaySets;
// Get the current display set
const displaySet = _.findWhere(displaySets, {
displaySetInstanceUid: viewportData.displaySetInstanceUid
});
// Get the current instance index (using 9999 to sort greater than -1)
let displaySetIndex = _.indexOf(displaySets, displaySet);
displaySetIndex = displaySetIndex < 0 ? 9999 : displaySetIndex;
// Try to get a map entry for current study or create it if not present
let studyViewports = sequenceMap.get(currentStudy);
if (!studyViewports) {
studyViewports = [];
sequenceMap.set(currentStudy, studyViewports);
}
// Register the viewport index and the display set index on the map
studyViewports.push({
viewportIndex,
displaySetIndex
});
});
// Return the generated sequence map
return sequenceMap;
};
// Check if all the display sets and viewports are sequenced
OHIF.viewer.isDisplaySetsSequenced = definedSequenceMap => {
let isSequenced = true;
// Get the studies and display sets sequence map
const sequenceMap = definedSequenceMap || OHIF.viewer.getDisplaySetSequenceMap();
sequenceMap.forEach((studyViewports, study) => {
let lastDisplaySetIndex = null;
let lastViewportIndex = null;
studyViewports.forEach(({ viewportIndex, displaySetIndex }, index) => {
// Check if the sequence is wrong
if (
displaySetIndex !== 9999 &&
lastViewportIndex !== null &&
lastDisplaySetIndex !== null &&
displaySetIndex !== null &&
(viewportIndex - 1 !== lastViewportIndex ||
displaySetIndex - 1 !== lastDisplaySetIndex)
) {
// Set the sequenced flag as false;
isSequenced = false;
}
// Update the last viewport index
lastViewportIndex = viewportIndex;
// Update the last display set index
lastDisplaySetIndex = displaySetIndex;
});
});
return isSequenced;
};
// Check if is possible to move display sets on a specific direction
OHIF.viewer.canMoveDisplaySets = isNext => {
// Get the setting that defines if the display set navigation is multiple
const isMultiple = OHIF.uiSettings.displaySetNavigationMultipleViewports;
// Get the setting that allow display set navigation looping over series
const allowLooping = OHIF.uiSettings.displaySetNavigationLoopOverSeries;
// Return false if no layout manager is not defined yet
if (!window.layoutManager) {
return false;
}
// Get the studies and display sets sequence map
const sequenceMap = OHIF.viewer.getDisplaySetSequenceMap();
// Check if the display sets are sequenced
const isSequenced = OHIF.viewer.isDisplaySetsSequenced(sequenceMap);
// Get Active Viewport Index if isMultiple is false
const activeViewportIndex = !isMultiple ? Session.get('activeViewport') : null;
// Check if is next and looping is blocked
if (isNext && !allowLooping) {
// Check if the end was reached
let endReached = true;
sequenceMap.forEach((studyViewports, study) => {
// Get active viewport index if isMultiple is false ortherwise get last
const studyViewport = studyViewports[activeViewportIndex !== null ? activeViewportIndex : studyViewports.length - 1];
if (!studyViewport) {
return;
}
const viewportIndex = studyViewport.displaySetIndex;
const layoutViewports = studyViewports.length;
const amount = study.displaySets.length;
const move = !isMultiple ? 1 : ((amount % layoutViewports) || layoutViewports);
const lastStepIndex = amount - move;
// 9999 for index means empty viewport, see getDisplaySetSequenceMap function
if (viewportIndex !== 9999 && viewportIndex !== lastStepIndex) {
endReached = false;
}
});
// Return false if end is not reached yet
if ((!isMultiple || isSequenced) && endReached) {
return false;
}
}
// Check if is previous and looping is blocked
if (!isNext && !allowLooping) {
// Check if the begin was reached
let beginReached = true;
if(activeViewportIndex >= 0) {
sequenceMap.forEach((studyViewports, study) => {
// Get active viewport index if isMultiple is false ortherwise get first
const studyViewport = studyViewports[activeViewportIndex !== null ? activeViewportIndex : 0];
if (!studyViewport) {
return;
}
const viewportIndex = studyViewport.displaySetIndex;
const layoutViewports = studyViewports.length;
// 9999 for index means empty viewport, see getDisplaySetSequenceMap function
if (viewportIndex !== 9999 && viewportIndex - layoutViewports !== -layoutViewports) {
beginReached = false;
}
});
}
// Return false if begin is not reached yet
if ((!isMultiple || isSequenced) && beginReached) {
return false;
}
}
return true;
};
// Move display sets forward or backward in the given viewport index
OHIF.viewer.moveSingleViewportDisplaySets = (viewportIndex, isNext) => {
// Get the setting that allow display set navigation looping over series
const allowLooping = OHIF.uiSettings.displaySetNavigationLoopOverSeries;
// Get the selected viewport data
const viewportData = window.layoutManager.viewportData[viewportIndex];
// Get the current study
const currentStudy = _.findWhere(window.layoutManager.studies, {
studyInstanceUid: viewportData.studyInstanceUid
}) || window.layoutManager.studies[0];
// Get the display sets
const displaySets = currentStudy.displaySets;
// Get the current display set
const currentDisplaySet = _.findWhere(displaySets, {
displaySetInstanceUid: viewportData.displaySetInstanceUid
});
// Get the new index and ensure that it will exists in display sets
let newIndex = _.indexOf(displaySets, currentDisplaySet);
if (isNext) {
newIndex++;
if (newIndex >= displaySets.length) {
// Stop here if looping is not allowed
if (!allowLooping) {
return;
}
newIndex = 0;
}
} else {
newIndex--;
if (newIndex < 0) {
// Stop here if looping is not allowed
if (!allowLooping) {
return;
}
newIndex = displaySets.length - 1;
}
}
// Get the display set data for the new index
const newDisplaySetData = displaySets[newIndex];
// Rerender the viewport using the new display set data
window.layoutManager.rerenderViewportWithNewDisplaySet(viewportIndex, newDisplaySetData);
};
// Move multiple display sets forward or backward in all viewports
OHIF.viewer.moveMultipleViewportDisplaySets = isNext => {
// Get the setting that allow display set navigation looping over series
const allowLooping = OHIF.uiSettings.displaySetNavigationLoopOverSeries;
// Create a map to control the display set sequence
const sequenceMap = new OHIF.viewer.getDisplaySetSequenceMap();
// Check if the display sets are sequenced
const isSequenced = OHIF.viewer.isDisplaySetsSequenced(sequenceMap);
const displaySetsToRender = [];
// Iterate over the studies map and move its display sets
sequenceMap.forEach((studyViewports, study) => {
// Sort the viewports on the study by the display set index
studyViewports.sort((a, b) => a.displaySetIndex > b.displaySetIndex);
// Get the study display sets
const displaySets = study.displaySets;
// Calculate the base index
const firstIndex = studyViewports[0].displaySetIndex;
const steps = studyViewports.length;
const rest = firstIndex % steps;
let baseIndex = rest ? firstIndex - rest : firstIndex;
const direction = isNext ? 1 : -1;
baseIndex += steps * direction;
const amount = displaySets.length;
// Check if the indexes are sequenced or will overflow the array bounds
if (baseIndex >= amount) {
const move = (amount % steps) || steps;
const lastStepIndex = amount - move;
if (firstIndex + steps !== lastStepIndex + steps) {
// Reset the index if the display sets are sequenced but shifted
baseIndex = lastStepIndex;
} else if (!allowLooping) {
// Stop here if looping is not allowed
return;
} else {
// Start over the series if looping is allowed
baseIndex = 0;
}
} else if (baseIndex < 0) {
if (firstIndex > 0) {
// Reset the index if the display sets are sequenced but shifted
baseIndex = 0;
} else if (!allowLooping) {
// Stop here if looping is not allowed
return;
} else {
// Go to the series' end if looping is allowed
baseIndex = (amount - 1) - ((amount - 1) % steps);
}
} else if (!isSequenced) {
// Reset the sequence if indexes are not sequenced
baseIndex = 0;
}
// Iterate over the current study viewports
studyViewports.forEach(({ viewportIndex }, index) => {
// Get the new displaySet index to be rendered in viewport
const newIndex = baseIndex + index;
// Get the display set data for the new index
const displaySetData = displaySets[newIndex] || {};
// Add the current display set that on the render list
displaySetsToRender.push(displaySetData);
});
});
// Sort the display sets
const sortingFunction = OHIF.utils.sortBy({
name: 'studyInstanceUid'
}, {
name: 'instanceNumber'
}, {
name: 'seriesNumber'
});
displaySetsToRender.sort((a, b) => sortingFunction(a, b));
// Iterate over each display set data and render on its respective viewport
displaySetsToRender.forEach((data, index) => {
window.layoutManager.rerenderViewportWithNewDisplaySet(index, data);
});
};
// Move display sets forward or backward
OHIF.viewer.moveDisplaySets = isNext => {
//Check if navigation is on a single or multiple viewports
if (OHIF.uiSettings.displaySetNavigationMultipleViewports) {
// Move display sets on multiple viewports
OHIF.viewer.moveMultipleViewportDisplaySets(isNext);
} else {
// Get the selected viewport index
const viewportIndex = Session.get('activeViewport');
// Move display sets on a single viewport
OHIF.viewer.moveSingleViewportDisplaySets(viewportIndex, isNext);
}
};

View File

@ -1,4 +1,4 @@
import { Router } from 'meteor/clinical:router'; import { Router } from 'meteor/iron:router';
Router.route('/playground', function() { Router.route('/playground', function() {
this.render('componentPlayground'); this.render('componentPlayground');

View File

@ -1,8 +1,6 @@
import { OHIF } from 'meteor/ohif:core';
// Allow attaching to jQuery selectors // Allow attaching to jQuery selectors
$.fn.draggable = function() { $.fn.draggable = function(options) {
OHIF.ui.makeDraggable(this); makeDraggable(this, options);
return this; return this;
}; };
@ -13,7 +11,7 @@ $.fn.draggable = function() {
* *
* @param element * @param element
*/ */
OHIF.ui.makeDraggable = function(element) { function makeDraggable(element, options) {
var container = $(window); var container = $(window);
var diffX, var diffX,
diffY, diffY,

View File

@ -1,4 +1,4 @@
@import "{design}/app" @import "{ohif:design}/app"
.resizable .resizable
transform(scale(1)) transform(scale(1))

View File

@ -16,7 +16,8 @@ Package.onUse(function(api) {
api.use('reactive-var'); api.use('reactive-var');
// Router dependencies // Router dependencies
api.use('clinical:router@2.0.18', 'client'); // api.use('clinical:router@2.0.18', 'client');
api.use('iron:router@1.0.13', 'client');
// Component's library dependencies // Component's library dependencies
api.use('natestrauser:select2@4.0.1', 'client'); api.use('natestrauser:select2@4.0.1', 'client');

View File

@ -1,5 +1,5 @@
@import "{design}/styles/imports/animations" @import "{ohif:design}/styles/imports/animations"
@import "{design}/styles/imports/mixins" @import "{ohif:design}/styles/imports/mixins"
@import "{design}/styles/imports/spacings" @import "{ohif:design}/styles/imports/spacings"
@import "{design}/styles/imports/variables" @import "{ohif:design}/styles/imports/variables"
@import "{design}/styles/imports/theme-icons" @import "{ohif:design}/styles/imports/theme-icons"

View File

@ -1,4 +1,4 @@
@import "{design}/app" @import "{ohif:design}/app"
$height = 25px $height = 25px

View File

@ -1,5 +1,5 @@
Package.describe({ Package.describe({
name: 'design', name: 'ohif:design',
summary: 'OHIF Design styles and components', summary: 'OHIF Design styles and components',
version: '0.0.1' version: '0.0.1'
}); });

View File

@ -1,4 +1,4 @@
@import "{design}/app.styl" @import "{ohif:design}/app"
html body html body
font-family: 'Roboto', 'OpenSans', 'HelveticaNeue-Light', 'Helvetica Neue Light', 'Helvetica Neue', Helvetica, Arial, 'Lucida Grande', sans-serif font-family: 'Roboto', 'OpenSans', 'HelveticaNeue-Light', 'Helvetica Neue Light', 'Helvetica Neue', Helvetica, Arial, 'Lucida Grande', sans-serif

View File

@ -1,4 +1,4 @@
@import "{design}/app.styl" @import "{ohif:design}/app"
@keyframes zoomIn @keyframes zoomIn
0% 0%

View File

@ -1,4 +1,4 @@
@import "{design}/app.styl" @import "{ohif:design}/app"
generateSpacings('', $spacer-x, $spacer-y) generateSpacings('', $spacer-x, $spacer-y)

View File

@ -1,4 +1,4 @@
@import "{design}/app" @import "{ohif:design}/app"
.viewerDialogs>.dialog-animated .viewerDialogs>.dialog-animated
&:not(.dialog-closed):not(.dialog-open) &:not(.dialog-closed):not(.dialog-open)

View File

@ -1,4 +1,4 @@
@import "{design}/app" @import "{ohif:design}/app"
.group-radio .group-radio
label label

View File

@ -1,4 +1,4 @@
@import "{design}/app" @import "{ohif:design}/app"
// TODO: [design] can't we use colors that are already in common pallete? // TODO: [design] can't we use colors that are already in common pallete?
$gray1 = #C3C3C3 $gray1 = #C3C3C3

View File

@ -1,4 +1,4 @@
@import "{design}/app" @import "{ohif:design}/app"
.state-error .state-error
&+.tooltip &+.tooltip

View File

@ -17,9 +17,6 @@ HP.studyAttributes = [{
}, { }, {
id: 'studyInstanceUid', id: 'studyInstanceUid',
text: '(x0020000d) Study Instance UID' text: '(x0020000d) Study Instance UID'
}, {
id: 'studyInstanceUid',
text: '(x0020000d) Study Instance UID'
}, { }, {
id: 'studyDate', id: 'studyDate',
text: '(x00080020) Study Date' text: '(x00080020) Study Date'

View File

@ -1,3 +1,12 @@
import { Meteor } from 'meteor/meteor';
import { Template } from 'meteor/templating';
import { Session } from 'meteor/session';
import { Random } from 'meteor/random';
import { $ } from 'meteor/jquery';
import { OHIF } from 'meteor/ohif:core';
import 'meteor/ohif:viewerbase';
/** /**
* Updates the Hanging Protocol Select2 Input * Updates the Hanging Protocol Select2 Input
*/ */
@ -98,7 +107,7 @@ Template.protocolEditor.helpers({
} }
// Retrieve the Stage Model for the current Protocol's active Stage // Retrieve the Stage Model for the current Protocol's active Stage
var stage = ProtocolEngine.getCurrentStageModel(); const stage = ProtocolEngine.getCurrentStageModel();
if (!stage) { if (!stage) {
return; return;
} }
@ -114,14 +123,14 @@ Template.protocolEditor.helpers({
// by removing or adding Viewports to the stage // by removing or adding Viewports to the stage
// //
// First, calculate the difference, if any exists // First, calculate the difference, if any exists
var difference = stage.viewportStructure.getNumViewports() - stage.viewports.length; const difference = stage.viewportStructure.getNumViewports() - stage.viewports.length;
if (difference < 0) { if (difference < 0) {
// Make the viewport difference into a positive value // Make the viewport difference into a positive value
var absDifference = Math.abs(difference); const absDifference = Math.abs(difference);
// If there are more Viewports defined than necessary, remove the extraneous Viewports // If there are more Viewports defined than necessary, remove the extraneous Viewports
var position = stage.viewports.length - absDifference; const position = stage.viewports.length - absDifference;
// Splice extra viewports from the Stage's viewports array // Splice extra viewports from the Stage's viewports array
stage.viewports.splice(position, absDifference); stage.viewports.splice(position, absDifference);
@ -130,9 +139,9 @@ Template.protocolEditor.helpers({
// required amount // required amount
// Count up until the difference in number of Viewports // Count up until the difference in number of Viewports
for (var i = 0; i < difference; i++) { for (let i = 0; i < difference; i++) {
// Instantiate a new Viewport Model // Instantiate a new Viewport Model
var viewport = new HP.Viewport(); const viewport = new HP.Viewport();
// Add new Viewports to the Stage's viewports array // Add new Viewports to the Stage's viewports array
stage.viewports.push(viewport); stage.viewports.push(viewport);
@ -154,7 +163,7 @@ Template.protocolEditor.events({
*/ */
'click #newProtocol'() { 'click #newProtocol'() {
// Clone the default Protocol // Clone the default Protocol
var protocol = HP.defaultProtocol.createClone(); const protocol = HP.defaultProtocol.createClone();
// Change the Protocol name to state that it is New, and give it a timestamp // Change the Protocol name to state that it is New, and give it a timestamp
protocol.name = 'New (created ' + moment().format('h:mm:ss a') + ')'; protocol.name = 'New (created ' + moment().format('h:mm:ss a') + ')';
@ -175,19 +184,19 @@ Template.protocolEditor.events({
* Rename the current Protocol * Rename the current Protocol
*/ */
'click #renameProtocol'() { 'click #renameProtocol'() {
var selectedProtocol = this; const selectedProtocol = this;
if (selectedProtocol.locked) { if (selectedProtocol.locked) {
return; return;
} }
// Define some details for the text entry dialog // Define some details for the text entry dialog
var title = 'Rename Protocol'; const title = 'Rename Protocol';
var instructions = 'Enter a new name'; const instructions = 'Enter a new name';
var currentValue = selectedProtocol.name; const currentValue = selectedProtocol.name;
// Open the text entry dialog with the details above // Open the text entry dialog with the details above
// and fire the callback function when finished. // and fire the callback function when finished.
openTextEntryDialog(title, instructions, currentValue, function(value) { openTextEntryDialog(title, instructions, currentValue, value => {
// Update the name with the entered text // Update the name with the entered text
selectedProtocol.name = value; selectedProtocol.name = value;
@ -211,17 +220,17 @@ Template.protocolEditor.events({
* *
* @param event The Change event for the input * @param event The Change event for the input
*/ */
'change .btn-file :file': function(event) { 'change .btn-file :file'(event) {
// http://www.abeautifulsite.net/whipping-file-inputs-into-shape-with-bootstrap-3/ // http://www.abeautifulsite.net/whipping-file-inputs-into-shape-with-bootstrap-3/
// Find the Input in the DOM // Find the Input in the DOM
var input = $(event.currentTarget); const input = $(event.currentTarget);
// Get the number of selected files // Get the number of selected files
var numFiles = input.get(0).files ? input.get(0).files.length : 1; const numFiles = input.get(0).files ? input.get(0).files.length : 1;
// Get the label of the file // Get the label of the file
var label = input.val().replace(/\\/g, '/').replace(/.*\//, ''); const label = input.val().replace(/\\/g, '/').replace(/.*\//, '');
// Trigger our custom event with the number of files and label // Trigger our custom event with the number of files and label
input.trigger('fileselect', [numFiles, label]); input.trigger('fileselect', [numFiles, label]);
@ -231,15 +240,15 @@ Template.protocolEditor.events({
* *
* @param event The custom fileselect event * @param event The custom fileselect event
*/ */
'fileselect .btn-file :file': function(event) { 'fileselect .btn-file :file'(event) {
// Retreieve the FileList // Retreieve the FileList
var files = event.target.files; const files = event.target.files;
// Create an HTML5 File Reader // Create an HTML5 File Reader
var reader = new FileReader(); const reader = new FileReader();
reader.onload = () => { reader.onload = () => {
var protocolToImport = JSON.parse(reader.result); const protocolToImport = JSON.parse(reader.result);
// Insert the protocol // Insert the protocol
HP.ProtocolStore.addProtocol(protocolToImport); HP.ProtocolStore.addProtocol(protocolToImport);
@ -257,12 +266,14 @@ Template.protocolEditor.events({
* *
* @param event The select2:select event * @param event The select2:select event
*/ */
'select2:select #protocolSelect': function(event) { 'select2:select #protocolSelect'(event) {
// Retrieve the protocolId // Retrieve the protocolId
var protocolId = event.params.data.id; const protocolId = event.params.data.id;
// Retrieve the protocol from the protocol store // Retrieve the Protocol from the HangingProtocols Collection
var selectedProtocol = HP.ProtocolStore.getProtocol(protocolId); const selectedProtocol = HangingProtocols.findOne({
id: protocolId
});
// If it doesn't exist, stop here // If it doesn't exist, stop here
if (!selectedProtocol) { if (!selectedProtocol) {
@ -280,92 +291,85 @@ Template.protocolEditor.events({
$(this).addClass('active').siblings().removeClass('active'); $(this).addClass('active').siblings().removeClass('active');
}, },
/** /**
* Update the protocol with the latest changes to the current Protocol * Update the HangingProtocols Collection with the latest changes to the current Protocol
*/ */
'click #saveProtocol'() { 'click #saveProtocol'() {
var selectedProtocol = this; const selectedProtocol = this;
if (selectedProtocol.locked) { if (selectedProtocol.locked) {
return; return;
} }
// Store the ID for the update call
const id = selectedProtocol._id;
// Remove the MongoDB _id property so that we can
// simplify the $set value
delete selectedProtocol._id;
// Update the Protocol's modifiedDate and modifiedBy User details // Update the Protocol's modifiedDate and modifiedBy User details
selectedProtocol.protocolWasModified(); selectedProtocol.protocolWasModified();
// Update the current Protocol in the database with the latest changes // Update the current Protocol in the database with the latest changes
HP.ProtocolStore.updateProtocol(selectedProtocol.id, selectedProtocol); HangingProtocols.update(id, {
$set: selectedProtocol
});
}, },
/** /**
* Save the current Protocol as a new document * Save the current Protocol as a new document in the HangingProtocols Collection
*/ */
'click #saveAsProtocol'() { 'click #saveAsProtocol'() {
var selectedProtocol = this; const selectedProtocol = this;
// Clone the selected Protocol
var protocol = selectedProtocol.createClone();
// Define some details for the text entry dialog // Define some details for the text entry dialog
var title = 'Save Protocol As'; const title = 'Save Protocol As';
var instructions = 'Enter a new name'; const instructions = 'Enter a new name';
var currentValue = protocol.name; const currentValue = selectedProtocol.name;
// Open the text entry dialog with the details above // Open the text entry dialog with the details above
// and fire the callback function when finished. // and fire the callback function when finished.
openTextEntryDialog(title, instructions, currentValue, function(value) { openTextEntryDialog(title, instructions, currentValue, value => {
// Erase the MongoDB _id
delete selectedProtocol._id;
// Create a new ID for the protocol // Create a new ID for the protocol
protocol.id = Random.id(); selectedProtocol.id = Random.id();
// Update the name with the entered text // Update the name with the entered text
protocol.name = value; selectedProtocol.name = value;
// Unlock the protocol
protocol.locked = false;
// Update the Protocol's modifiedDate and modifiedBy User details // Update the Protocol's modifiedDate and modifiedBy User details
protocol.protocolWasModified(); selectedProtocol.protocolWasModified();
// Insert the new Protocol // Insert the new Protocol
HP.ProtocolStore.addProtocol(protocol); HangingProtocols.insert(selectedProtocol);
// Activate the new Protocol using the ProtocolEngine
ProtocolEngine.setHangingProtocol(protocol);
// Update the protocol selector to display the new Protocols
updateProtocolSelect();
}); });
}, },
/** /**
* Export the currently selected Protocol as a JSON file * Export the currently selected Protocol as a JSON file
*/ */
'click #exportJSON'() { 'click #exportJSON'() {
var selectedProtocol = this; // Tell the User's Browser to download the JSON file by routing a hidden iframe to our
// protocol-export Route. This prevents the tab from changing its current content.
var protocolJSON = JSON.stringify(selectedProtocol, null, 2), const selectedProtocol = this;
currentDate = new Date(), document.getElementById('download_iframe').src = '/protocol-export/' + selectedProtocol.id;
filename = selectedProtocol.name + '-' + (currentDate.getTime().toString()) + '.json',
protocolBlob = new Blob([protocolJSON], { type: 'application/json' });
var downloadElement = document.getElementById('downloadElement');
downloadElement.href = URL.createObjectURL(protocolBlob);
downloadElement.download = filename;
downloadElement.click();
}, },
/** /**
* Delete the currently selected Protocol * Delete the currently selected Protocol
*/ */
'click #deleteProtocol'() { 'click #deleteProtocol'() {
var selectedProtocol = this; const selectedProtocol = this;
if (selectedProtocol.locked) { if (selectedProtocol.locked) {
return; return;
} }
var options = { const options = {
title: 'Delete Protocol', title: 'Delete Protocol',
text: 'Are you sure you would like to remove this Protocol? This cannot be reversed.' text: 'Are you sure you would like to remove this Protocol? This cannot be reversed.'
}; };
showConfirmDialog(() => { OHIF.viewerbase.showConfirmDialog(() => {
// Remove the Protocol // Send a call to remove the Protocol from the HangingProtocols Collection on the server
HP.ProtocolStore.removeProtocol(selectedProtocol.id); Meteor.call('removeHangingProtocol', selectedProtocol._id);
// Reset the ProtocolEngine to the next best match // Reset the ProtocolEngine to the next best match
ProtocolEngine.reset(); ProtocolEngine.reset();

View File

@ -1,4 +1,4 @@
@import "{design}/app.styl" @import "{ohif:design}/app"
$height = 20px $height = 20px

View File

@ -1,6 +1,13 @@
import { OHIF } from 'meteor/ohif:core'; import { $ } from 'meteor/jquery';
import { Session } from 'meteor/session';
import { ReactiveVar } from 'meteor/reactive-var';
import { Template } from 'meteor/templating';
import { Blaze } from 'meteor/blaze';
var keys = { import { OHIF } from 'meteor/ohif:core';
import { Viewerbase } from 'meteor/ohif:viewerbase';
const keys = {
ESC: 27 ESC: 27
}; };
@ -10,7 +17,7 @@ var keys = {
* *
* @param dialog The DOM element of the dialog to close * @param dialog The DOM element of the dialog to close
*/ */
function closeHandler(dialog) { const closeHandler = dialog => {
// Hide the lesion dialog // Hide the lesion dialog
$(dialog).css('display', 'none'); $(dialog).css('display', 'none');
@ -18,8 +25,8 @@ function closeHandler(dialog) {
$('.removableBackdrop').remove(); $('.removableBackdrop').remove();
// Restore the focus to the active viewport // Restore the focus to the active viewport
setFocusToActiveViewport(); Viewerbase.setFocusToActiveViewport();
} };
/** /**
* Displays and updates the UI of the Rule Entry Dialog given a new set of * Displays and updates the UI of the Rule Entry Dialog given a new set of
@ -32,10 +39,10 @@ function closeHandler(dialog) {
*/ */
openRuleEntryDialog = function(attributes, level, rule) { openRuleEntryDialog = function(attributes, level, rule) {
// Get the lesion location dialog // Get the lesion location dialog
var dialog = $('.ruleEntryDialog'); const dialog = $('.ruleEntryDialog');
// Clear any input that is still on the page // Clear any input that is still on the page
var currentValueInput = dialog.find('input.currentValue'); const currentValueInput = dialog.find('input.currentValue');
currentValueInput.val(''); currentValueInput.val('');
// Store the Dialog DOM data, rule level and rule in the template data // Store the Dialog DOM data, rule level and rule in the template data
@ -44,7 +51,7 @@ openRuleEntryDialog = function(attributes, level, rule) {
Template.ruleEntryDialog.rule = rule; Template.ruleEntryDialog.rule = rule;
// Initialize the Select2 search box for the attribute list // Initialize the Select2 search box for the attribute list
var attributeSelect = dialog.find('.attributes'); const attributeSelect = dialog.find('.attributes');
attributeSelect.html('').select2({ attributeSelect.html('').select2({
data: attributes, data: attributes,
placeholder: 'Select an attribute', placeholder: 'Select an attribute',
@ -63,15 +70,15 @@ openRuleEntryDialog = function(attributes, level, rule) {
// If a rule has been provided, use its constraint to find the relevant Comparator // If a rule has been provided, use its constraint to find the relevant Comparator
if (rule && rule.constraint) { if (rule && rule.constraint) {
var validator = Object.keys(rule.constraint)[0]; const validator = Object.keys(rule.constraint)[0];
var validatorOption = Object.keys(rule.constraint[validator])[0]; const validatorOption = Object.keys(rule.constraint[validator])[0];
var comparator = Comparators.findOne({ const comparator = Comparators.findOne({
validator: validator, validator: validator,
validatorOption: validatorOption validatorOption: validatorOption
}); });
// Set the current value input based on the rule constraint // Set the current value input based on the rule constraint
var currentValue = rule.constraint[validator][validatorOption]; const currentValue = rule.constraint[validator][validatorOption];
currentValueInput.val(currentValue); currentValueInput.val(currentValue);
} }
@ -86,10 +93,10 @@ openRuleEntryDialog = function(attributes, level, rule) {
dialog.css('display', 'block'); dialog.css('display', 'block');
// Show the backdrop // Show the backdrop
UI.render(Template.removableBackdrop, document.body); Blaze.render(Template.removableBackdrop, document.body);
// Make sure the context menu is closed when the user clicks away // Make sure the context menu is closed when the user clicks away
$('.removableBackdrop').one('mousedown touchstart', function() { $('.removableBackdrop').one('mousedown touchstart', () => {
closeHandler(dialog); closeHandler(dialog);
}); });
}; };
@ -99,23 +106,23 @@ openRuleEntryDialog = function(attributes, level, rule) {
*/ */
function getActiveViewportImageId() { function getActiveViewportImageId() {
// Retrieve the active viewport index from the Session // Retrieve the active viewport index from the Session
var activeViewport = Session.get('activeViewport'); const activeViewport = Session.get('activeViewport');
if (activeViewport === undefined) { if (activeViewport === undefined) {
return; return;
} }
// Obtain the list of all Viewports on the page // Obtain the list of all Viewports on the page
var viewports = $('.imageViewerViewport'); const viewports = $('.imageViewerViewport');
// Retrieve the active viewport element // Retrieve the active viewport element
var element = viewports.get(activeViewport); const element = viewports.get(activeViewport);
if (!element) { if (!element) {
return; return;
} }
// Obtain the enabled element from Cornerstone // Obtain the enabled element from Cornerstone
try { try {
var enabledElement = cornerstone.getEnabledElement(element); const enabledElement = cornerstone.getEnabledElement(element);
if (!enabledElement) { if (!enabledElement) {
return; return;
} }
@ -128,7 +135,7 @@ function getActiveViewportImageId() {
} }
function getAbstractPriorValue(imageId) { function getAbstractPriorValue(imageId) {
var currentStudy = ViewerStudies.findOne({}, { const currentStudy = ViewerStudies.findOne({}, {
sort: { sort: {
studyDate: -1 studyDate: -1
}, },
@ -139,12 +146,12 @@ function getAbstractPriorValue(imageId) {
return; return;
} }
var priorStudy = cornerstoneTools.metaData.get('study', imageId); const priorStudy = cornerstoneTools.metaData.get('study', imageId);
if (!priorStudy) { if (!priorStudy) {
return; return;
} }
var studies = StudyListStudies.find({ const studies = StudyListStudies.find({
patientId: currentStudy.patientId, patientId: currentStudy.patientId,
studyDate: { studyDate: {
$lt: currentStudy.studyDate $lt: currentStudy.studyDate
@ -155,7 +162,7 @@ function getAbstractPriorValue(imageId) {
} }
}); });
var priorIndex = 0; let priorIndex = 0;
// TODO: Check what the abstract prior value should equal for an unrelated study? // TODO: Check what the abstract prior value should equal for an unrelated study?
studies.forEach(function(study, index) { studies.forEach(function(study, index) {
@ -176,7 +183,7 @@ function getAbstractPriorValue(imageId) {
*/ */
function getCurrentAttributeValue(attribute, level) { function getCurrentAttributeValue(attribute, level) {
// Retrieve the active viewport's imageId. If none exists, stop here // Retrieve the active viewport's imageId. If none exists, stop here
var imageId = getActiveViewportImageId(); const imageId = getActiveViewportImageId();
if (!imageId) { if (!imageId) {
return; return;
} }
@ -193,7 +200,7 @@ function getCurrentAttributeValue(attribute, level) {
// Retrieve the metadata values for the specified level from // Retrieve the metadata values for the specified level from
// the Cornerstone Tools metaData provider // the Cornerstone Tools metaData provider
var metadata = cornerstoneTools.metaData.get(level, imageId); const metadata = cornerstoneTools.metaData.get(level, imageId);
if (metadata[attribute] === undefined) { if (metadata[attribute] === undefined) {
return HP.attributeDefaults[attribute]; return HP.attributeDefaults[attribute];
@ -204,7 +211,7 @@ function getCurrentAttributeValue(attribute, level) {
Template.ruleEntryDialog.onCreated(function() { Template.ruleEntryDialog.onCreated(function() {
// Define the ReactiveVars that will be used to link aspects of the UI // Define the ReactiveVars that will be used to link aspects of the UI
var template = this; const template = this;
// Note: currentValue's initial value must be a string so the template renders properly // Note: currentValue's initial value must be a string so the template renders properly
template.currentValue = new ReactiveVar(''); template.currentValue = new ReactiveVar('');
template.attribute = new ReactiveVar(); template.attribute = new ReactiveVar();
@ -213,12 +220,12 @@ Template.ruleEntryDialog.onCreated(function() {
Template.ruleEntryDialog.onRendered(function() { Template.ruleEntryDialog.onRendered(function() {
// Initialize the Comparators Select2 box // Initialize the Comparators Select2 box
var template = Template.instance(); const template = Template.instance();
template.$('.comparators').select2(); template.$('.comparators').select2();
// Get the default Comparator from the Select2 box and use it to // Get the default Comparator from the Select2 box and use it to
// initialize the comparatorId ReactiveVar // initialize the comparatorId ReactiveVar
var comparatorId = template.$('.comparators').val(); const comparatorId = template.$('.comparators').val();
template.comparatorId.set(comparatorId); template.comparatorId.set(comparatorId);
const dialog = template.$('.ruleEntryDialog'); const dialog = template.$('.ruleEntryDialog');
@ -229,7 +236,7 @@ Template.ruleEntryDialog.helpers({
/** /**
* Returns the Comparators Collection to the Template with reactive rerendering * Returns the Comparators Collection to the Template with reactive rerendering
*/ */
comparators: function() { comparators() {
return Comparators.find(); return Comparators.find();
}, },
/** /**
@ -237,7 +244,7 @@ Template.ruleEntryDialog.helpers({
* *
* @returns {*} Attribute value for the active image * @returns {*} Attribute value for the active image
*/ */
currentValue: function() { currentValue() {
return Template.instance().currentValue.get(); return Template.instance().currentValue.get();
} }
}); });
@ -249,15 +256,15 @@ Template.ruleEntryDialog.events({
* @param event the Click event * @param event the Click event
* @param template The template context * @param template The template context
*/ */
'click #save': function(event, template) { 'click #save'(event, template) {
// Retrieve the input properties to the template // Retrieve the input properties to the template
var dialog = Template.ruleEntryDialog.dialog; const dialog = Template.ruleEntryDialog.dialog;
var level = Template.ruleEntryDialog.level; const level = Template.ruleEntryDialog.level;
// Retrieve the current values for the attribute value and comparatorId // Retrieve the current values for the attribute value and comparatorId
var attribute = template.attribute.get(); const attribute = template.attribute.get();
var comparatorId = template.comparatorId.get(); const comparatorId = template.comparatorId.get();
var currentValue = template.currentValue.get(); const currentValue = template.currentValue.get();
// If currentValue input is undefined, prevent saving this rule // If currentValue input is undefined, prevent saving this rule
if (currentValue === undefined) { if (currentValue === undefined) {
@ -265,14 +272,14 @@ Template.ruleEntryDialog.events({
} }
// Check if we are editing a rule or creating a new one // Check if we are editing a rule or creating a new one
var rule; let rule;
if (Template.ruleEntryDialog.rule) { if (Template.ruleEntryDialog.rule) {
// If we are editing a rule, change the rule data // If we are editing a rule, change the rule data
rule = Template.ruleEntryDialog.rule; rule = Template.ruleEntryDialog.rule;
} else { } else {
// If we are creating a rule, obtain the active Viewport model // If we are creating a rule, obtain the active Viewport model
// from the Protocol and Stage // from the Protocol and Stage
var viewport = getActiveViewportModel(); const viewport = getActiveViewportModel();
// Create a rule depending on the level property of this dialog // Create a rule depending on the level property of this dialog
switch (level) { switch (level) {
@ -296,12 +303,12 @@ Template.ruleEntryDialog.events({
} }
// Find the Comparator from the Comparators Collection given its ID // Find the Comparator from the Comparators Collection given its ID
var comparator = Comparators.findOne({ const comparator = Comparators.findOne({
id: comparatorId id: comparatorId
}); });
// Create a new constraint to add to the rule // Create a new constraint to add to the rule
var constraint = {}; const constraint = {};
constraint[comparator.validator] = {}; constraint[comparator.validator] = {};
constraint[comparator.validator][comparator.validatorOption] = currentValue; constraint[comparator.validator][comparator.validatorOption] = currentValue;
@ -310,7 +317,7 @@ Template.ruleEntryDialog.events({
rule.constraint = constraint; rule.constraint = constraint;
// Instruct the Protocol Engine to update the Layout Manager with new data // Instruct the Protocol Engine to update the Layout Manager with new data
var viewportIndex = Session.get('activeViewport'); const viewportIndex = Session.get('activeViewport');
ProtocolEngine.updateViewports(viewportIndex); ProtocolEngine.updateViewports(viewportIndex);
// Close the dialog // Close the dialog
@ -319,8 +326,8 @@ Template.ruleEntryDialog.events({
/** /**
* Allow the user to click the Cancel button to close the dialog * Allow the user to click the Cancel button to close the dialog
*/ */
'click #cancel': function() { 'click #cancel'() {
var dialog = Template.ruleEntryDialog.dialog; const dialog = Template.ruleEntryDialog.dialog;
closeHandler(dialog); closeHandler(dialog);
}, },
/** /**
@ -329,8 +336,8 @@ Template.ruleEntryDialog.events({
* @param event The Keydown event details * @param event The Keydown event details
* @returns {boolean} Return false to prevent bubbling of the event * @returns {boolean} Return false to prevent bubbling of the event
*/ */
'keydown .ruleEntryDialog': function(event) { 'keydown .ruleEntryDialog'(event) {
var dialog = Template.ruleEntryDialog.dialog; const dialog = Template.ruleEntryDialog.dialog;
// If Esc key is pressed, close the dialog // If Esc key is pressed, close the dialog
if (event.which === keys.ESC) { if (event.which === keys.ESC) {
@ -344,9 +351,9 @@ Template.ruleEntryDialog.events({
* @param event The Change event for the select box * @param event The Change event for the select box
* @param template The current template context * @param template The current template context
*/ */
'change select.attributes': function(event, template) { 'change select.attributes'(event, template) {
// Obtain the user-specified attribute to test against // Obtain the user-specified attribute to test against
var attribute = $(event.currentTarget).val(); const attribute = $(event.currentTarget).val();
// Store it in the ReactiveVar // Store it in the ReactiveVar
template.attribute.set(attribute); template.attribute.set(attribute);
@ -355,10 +362,10 @@ Template.ruleEntryDialog.events({
Template.ruleEntryDialog.selectedAttribute = attribute; Template.ruleEntryDialog.selectedAttribute = attribute;
// Get the level of this dialog // Get the level of this dialog
var level = Template.ruleEntryDialog.level; const level = Template.ruleEntryDialog.level;
// Retrieve the current value of the attribute for the active viewport model // Retrieve the current value of the attribute for the active viewport model
var value = getCurrentAttributeValue(attribute, level); const value = getCurrentAttributeValue(attribute, level);
// Update the ReactiveVar with the user-specified value // Update the ReactiveVar with the user-specified value
template.currentValue.set(value); template.currentValue.set(value);
@ -369,12 +376,12 @@ Template.ruleEntryDialog.events({
* @param event The Change event for the input * @param event The Change event for the input
* @param template The current template context * @param template The current template context
*/ */
'change input.currentValue': function(event, template) { 'change input.currentValue'(event, template) {
// Get the DOM element representing the input box // Get the DOM element representing the input box
var input = $(event.currentTarget); const input = $(event.currentTarget);
// Get the current value of the input // Get the current value of the input
var value = input.val(); let value = input.val();
// If the input is of type 'number', parse it as a Float // If the input is of type 'number', parse it as a Float
if (input.attr('type') === 'number') { if (input.attr('type') === 'number') {
@ -390,9 +397,9 @@ Template.ruleEntryDialog.events({
* @param event The Change event for the select box * @param event The Change event for the select box
* @param template The current template context * @param template The current template context
*/ */
'change select.comparators': function(event, template) { 'change select.comparators'(event, template) {
// Get the current value of the select box // Get the current value of the select box
var comparatorId = $(event.currentTarget).val(); const comparatorId = $(event.currentTarget).val();
// Update the ReactiveVar with the value of the Comparators select box // Update the ReactiveVar with the value of the Comparators select box
template.comparatorId.set(comparatorId); template.comparatorId.set(comparatorId);

View File

@ -1,4 +1,4 @@
@import "{design}/app.styl" @import "{ohif:design}/app"
.ruleEntryDialog .ruleEntryDialog
theme('background', '$uiGrayDarkest', 0.95) theme('background', '$uiGrayDarkest', 0.95)

View File

@ -1,4 +1,4 @@
@import "{design}/app.styl" @import "{ohif:design}/app"
table.ruleTable table.ruleTable
thead thead

View File

@ -1,4 +1,12 @@
var keys = { import { Template } from 'meteor/templating';
import { Session } from 'meteor/session';
import { ReactiveVar } from 'meteor/reactive-var';
import { Blaze } from 'meteor/blaze';
import { $ } from 'meteor/jquery';
import { Viewerbase } from 'meteor/ohif:viewerbase';
const keys = {
ESC: 27 ESC: 27
}; };
@ -8,7 +16,7 @@ var keys = {
* *
* @param dialog The DOM element of the dialog to close * @param dialog The DOM element of the dialog to close
*/ */
function closeHandler(dialog) { const closeHandler = dialog => {
// Hide the lesion dialog // Hide the lesion dialog
$(dialog).css('display', 'none'); $(dialog).css('display', 'none');
@ -16,8 +24,8 @@ function closeHandler(dialog) {
$('.removableBackdrop').remove(); $('.removableBackdrop').remove();
// Restore the focus to the active viewport // Restore the focus to the active viewport
setFocusToActiveViewport(); Viewerbase.setFocusToActiveViewport();
} };
/** /**
* Displays and updates the UI of the Setting Entry Dialog given an * Displays and updates the UI of the Setting Entry Dialog given an
@ -27,40 +35,40 @@ function closeHandler(dialog) {
*/ */
openSettingEntryDialog = function(settingObject) { openSettingEntryDialog = function(settingObject) {
// Get the lesion location dialog // Get the lesion location dialog
var dialog = $('.settingEntryDialog'); const dialog = $('.settingEntryDialog');
// Store the Dialog DOM data, setting level and setting in the template data // Store the Dialog DOM data, setting level and setting in the template data
Template.settingEntryDialog.dialog = dialog; Template.settingEntryDialog.dialog = dialog;
Template.settingEntryDialog.settingObject = settingObject; Template.settingEntryDialog.settingObject = settingObject;
// Initialize the Select2 search box for the attribute list // Initialize the Select2 search box for the attribute list
var settings = Object.keys(HP.displaySettings); const settings = Object.keys(HP.displaySettings);
settings.concat(Object.keys(HP.CustomViewportSettings)); settings.concat(Object.keys(HP.CustomViewportSettings));
var displaySettingsOptions = Object.keys(HP.displaySettings).map(key => { const displaySettingsOptions = Object.keys(HP.displaySettings).map(key => {
return { return {
id: key, id: key,
text: HP.displaySettings[key].text text: HP.displaySettings[key].text
}; };
}); });
var customSettingsOptions = Object.keys(HP.CustomViewportSettings).map(key => { const customSettingsOptions = Object.keys(HP.CustomViewportSettings).map(key => {
return { return {
id: key, id: key,
text: HP.CustomViewportSettings[key].text text: HP.CustomViewportSettings[key].text
}; };
}); });
var settingsOptions = displaySettingsOptions.concat(customSettingsOptions); const settingsOptions = displaySettingsOptions.concat(customSettingsOptions);
var settingSelect = dialog.find('.settings'); const settingSelect = dialog.find('.settings');
settingSelect.html('').select2({ settingSelect.html('').select2({
data: settingsOptions, data: settingsOptions,
placeholder: 'Select a setting', placeholder: 'Select a setting',
allowClear: true allowClear: true
}); });
var settingDetails = { let settingDetails = {
options: [] options: []
}; };
@ -70,7 +78,7 @@ openSettingEntryDialog = function(settingObject) {
settingDetails = HP.CustomViewportSettings[settingObject.id]; settingDetails = HP.CustomViewportSettings[settingObject.id];
} }
var valueSelect = dialog.find('.currentValue'); const valueSelect = dialog.find('.currentValue');
valueSelect.html('').select2({ valueSelect.html('').select2({
data: settingDetails.options, data: settingDetails.options,
placeholder: 'Select a value', placeholder: 'Select a value',
@ -99,14 +107,14 @@ openSettingEntryDialog = function(settingObject) {
Blaze.render(Template.removableBackdrop, document.body); Blaze.render(Template.removableBackdrop, document.body);
// Make sure the context menu is closed when the user clicks away // Make sure the context menu is closed when the user clicks away
$('.removableBackdrop').one('mousedown touchstart', function() { $('.removableBackdrop').one('mousedown touchstart', () => {
closeHandler(dialog); closeHandler(dialog);
}); });
}; };
Template.settingEntryDialog.onCreated(function() { Template.settingEntryDialog.onCreated(function() {
// Define the ReactiveVars that will be used to link aspects of the UI // Define the ReactiveVars that will be used to link aspects of the UI
var template = this; const template = this;
// Note: currentValue's initial value must be a string so the template renders properly // Note: currentValue's initial value must be a string so the template renders properly
template.currentValue = new ReactiveVar(''); template.currentValue = new ReactiveVar('');
@ -126,29 +134,29 @@ Template.settingEntryDialog.events({
* @param event the Click event * @param event the Click event
* @param template The template context * @param template The template context
*/ */
'click #save': function(event, template) { 'click #save'(event, template) {
// Retrieve the input properties to the template // Retrieve the input properties to the template
var dialog = Template.settingEntryDialog.dialog; const dialog = Template.settingEntryDialog.dialog;
// Retrieve the current values for the id and current value // Retrieve the current values for the id and current value
var setting = template.setting.get(); const setting = template.setting.get();
var currentValue = template.currentValue.get(); const currentValue = template.currentValue.get();
// If currentValue input is undefined, prevent saving this setting // If currentValue input is undefined, prevent saving this setting
if (currentValue === undefined) { if (currentValue === undefined) {
return; return;
} }
var viewportSetting = { const viewportSetting = {
id: setting, id: setting,
value: currentValue value: currentValue
}; };
// Obtain the active Viewport model from the Protocol and Stage // Obtain the active Viewport model from the Protocol and Stage
var viewport = getActiveViewportModel(); const viewport = getActiveViewportModel();
// Remove any old rules if the ID has been changes // Remove any old rules if the ID has been changes
var originalSettingObject = Template.settingEntryDialog.settingObject; const originalSettingObject = Template.settingEntryDialog.settingObject;
if (originalSettingObject && originalSettingObject.id) { if (originalSettingObject && originalSettingObject.id) {
delete viewport.viewportSettings[originalSettingObject.id]; delete viewport.viewportSettings[originalSettingObject.id];
} }
@ -157,7 +165,7 @@ Template.settingEntryDialog.events({
viewport.viewportSettings[viewportSetting.id] = viewportSetting.value; viewport.viewportSettings[viewportSetting.id] = viewportSetting.value;
// Instruct the Protocol Engine to update the Layout Manager with new data // Instruct the Protocol Engine to update the Layout Manager with new data
var viewportIndex = Session.get('activeViewport'); const viewportIndex = Session.get('activeViewport');
ProtocolEngine.updateViewports(viewportIndex); ProtocolEngine.updateViewports(viewportIndex);
// Close the dialog // Close the dialog
@ -166,8 +174,8 @@ Template.settingEntryDialog.events({
/** /**
* Allow the user to click the Cancel button to close the dialog * Allow the user to click the Cancel button to close the dialog
*/ */
'click #cancel': function() { 'click #cancel'() {
var dialog = Template.settingEntryDialog.dialog; const dialog = Template.settingEntryDialog.dialog;
closeHandler(dialog); closeHandler(dialog);
}, },
/** /**
@ -176,8 +184,8 @@ Template.settingEntryDialog.events({
* @param event The Keydown event details * @param event The Keydown event details
* @returns {boolean} Return false to prevent bubbling of the event * @returns {boolean} Return false to prevent bubbling of the event
*/ */
'keydown .settingEntryDialog': function(event) { 'keydown .settingEntryDialog'(event) {
var dialog = Template.settingEntryDialog.dialog; const dialog = Template.settingEntryDialog.dialog;
// If Esc key is pressed, close the dialog // If Esc key is pressed, close the dialog
if (event.which === keys.ESC) { if (event.which === keys.ESC) {
@ -191,15 +199,15 @@ Template.settingEntryDialog.events({
* @param event The Change event for the select box * @param event The Change event for the select box
* @param template The current template context * @param template The current template context
*/ */
'change select.settings': function(event, template) { 'change select.settings'(event, template) {
// Obtain the user-specified attribute to test against // Obtain the user-specified attribute to test against
var settingId = $(event.currentTarget).val(); const settingId = $(event.currentTarget).val();
// Store it in the ReactiveVar // Store it in the ReactiveVar
template.setting.set(settingId); template.setting.set(settingId);
// Retrieve the current value from the attribute // Retrieve the current value from the attribute
var settingDetails = { let settingDetails = {
options: [] options: []
}; };
if (settingId && HP.displaySettings[settingId]) { if (settingId && HP.displaySettings[settingId]) {
@ -208,8 +216,8 @@ Template.settingEntryDialog.events({
settingDetails = HP.CustomViewportSettings[settingId]; settingDetails = HP.CustomViewportSettings[settingId];
} }
var dialog = Template.settingEntryDialog.dialog; const dialog = Template.settingEntryDialog.dialog;
var valueSelect = dialog.find('.currentValue'); const valueSelect = dialog.find('.currentValue');
valueSelect.html('').select2({ valueSelect.html('').select2({
data: settingDetails.options, data: settingDetails.options,
placeholder: 'Select a value', placeholder: 'Select a value',
@ -228,9 +236,9 @@ Template.settingEntryDialog.events({
* @param event The Change event for the input * @param event The Change event for the input
* @param template The current template context * @param template The current template context
*/ */
'change select.currentValue': function(event, template) { 'change select.currentValue'(event, template) {
// Get the current value of the select box // Get the current value of the select box
var value = $(event.currentTarget).val(); const value = $(event.currentTarget).val();
// Update the ReactiveVar with the user-specified value // Update the ReactiveVar with the user-specified value
template.currentValue.set(value); template.currentValue.set(value);

View File

@ -1,4 +1,4 @@
@import "{design}/app.styl" @import "{ohif:design}/app"
.settingEntryDialog .settingEntryDialog
theme('border', '1px solid $uiBorderColor', 0.95) theme('border', '1px solid $uiBorderColor', 0.95)

View File

@ -1,4 +1,4 @@
@import "{design}/app.styl" @import "{ohif:design}/app"
table.settingsTable table.settingsTable
thead thead

View File

@ -1,4 +1,4 @@
@import "{design}/app.styl" @import "{ohif:design}/app"
#stageDetails #stageDetails
overflow-y: auto overflow-y: auto

View File

@ -1,4 +1,4 @@
@import "{design}/app.styl" @import "{ohif:design}/app"
#stageSortingContainer #stageSortingContainer
padding: 0 20px padding: 0 20px

View File

@ -1,4 +1,4 @@
@import "{design}/app.styl" @import "{ohif:design}/app"
.textEntryDialog .textEntryDialog
theme('border', '1px solid $uiBorderColor', 0.95) theme('border', '1px solid $uiBorderColor', 0.95)

View File

@ -1,4 +1,9 @@
import { Meteor } from 'meteor/meteor';
import { $ } from 'meteor/jquery';
import { _ } from 'meteor/underscore';
// OHIF Modules
import { OHIF } from 'meteor/ohif:core'; import { OHIF } from 'meteor/ohif:core';
import 'meteor/ohif:viewerbase';
// Define a global variable that will be used to refer to the Protocol Engine // Define a global variable that will be used to refer to the Protocol Engine
// It must be populated by HP.setEngine when the Viewer is initialized and a ProtocolEngine // It must be populated by HP.setEngine when the Viewer is initialized and a ProtocolEngine
@ -74,7 +79,7 @@ HP.addCustomViewportSetting = function(settingId, settingName, options, callback
Meteor.startup(function() { Meteor.startup(function() {
HP.addCustomViewportSetting('wlPreset', 'Window/Level Preset', Object.keys(OHIF.viewer.wlPresets), function(element, optionValue) { HP.addCustomViewportSetting('wlPreset', 'Window/Level Preset', Object.keys(OHIF.viewer.wlPresets), function(element, optionValue) {
if (OHIF.viewer.wlPresets.hasOwnProperty(optionValue)) { if (OHIF.viewer.wlPresets.hasOwnProperty(optionValue)) {
applyWLPreset(optionValue, element); OHIF.viewerbase.wlPresets.applyWLPreset(optionValue, element);
} }
}); });
}); });
@ -191,7 +196,7 @@ HP.ProtocolEngine = class ProtocolEngine {
findMatchByStudy(study) { findMatchByStudy(study) {
var matched = []; var matched = [];
HP.ProtocolStore.getProtocol().forEach(protocol => { HangingProtocols.find().forEach(protocol => {
// Clone the protocol's protocolMatchingRules array // Clone the protocol's protocolMatchingRules array
// We clone it so that we don't accidentally add the // We clone it so that we don't accidentally add the
// numberOfPriorsReferenced rule to the Protocol itself. // numberOfPriorsReferenced rule to the Protocol itself.
@ -220,7 +225,9 @@ HP.ProtocolEngine = class ProtocolEngine {
}); });
if (!matched.length) { if (!matched.length) {
var defaultProtocol = HP.ProtocolStore.getProtocol('defaultProtocol'); var defaultProtocol = HangingProtocols.findOne({
id: 'defaultProtocol'
});
return [{ return [{
score: 1, score: 1,
@ -403,7 +410,7 @@ HP.ProtocolEngine = class ProtocolEngine {
if (!alreadyLoaded) { if (!alreadyLoaded) {
getStudyMetadata(priorStudy.studyInstanceUid, study => { getStudyMetadata(priorStudy.studyInstanceUid, study => {
study.abstractPriorValue = abstractPriorValue; study.abstractPriorValue = abstractPriorValue;
study.displaySets = createStacks(study); study.displaySets = OHIF.viewerbase.sortingManager.getDisplaySets(study);
ViewerStudies.insert(study); ViewerStudies.insert(study);
this.studies.push(study); this.studies.push(study);
this.matchImages(viewport); this.matchImages(viewport);
@ -437,7 +444,7 @@ HP.ProtocolEngine = class ProtocolEngine {
// This tests to make sure there is actually image data in this instance // This tests to make sure there is actually image data in this instance
// TODO: Change this when we add PDF and MPEG support // TODO: Change this when we add PDF and MPEG support
// See https://ohiforg.atlassian.net/browse/LT-227 // See https://ohiforg.atlassian.net/browse/LT-227
if (!isImage(instance.sopClassUid) && !instance.rows) { if (!OHIF.viewerbase.isImage(instance.sopClassUid) && !instance.rows) {
return; return;
} }
@ -482,7 +489,7 @@ HP.ProtocolEngine = class ProtocolEngine {
// If the instance was found, set the displaySet ID // If the instance was found, set the displaySet ID
if (displaySet) { if (displaySet) {
imageDetails.displaySetInstanceUid = displaySet.displaySetInstanceUid; imageDetails.displaySetInstanceUid = displaySet.displaySetInstanceUid;
imageDetails.imageId = getImageId(instance); imageDetails.imageId = OHIF.viewerbase.getImageId(instance);
} }
if ((totalMatchScore > highestImageMatchingScore) || !bestMatch) { if ((totalMatchScore > highestImageMatchingScore) || !bestMatch) {

View File

@ -14,7 +14,7 @@ Package.onUse(function(api) {
api.use('random'); api.use('random');
api.use('templating'); api.use('templating');
api.use('natestrauser:select2@4.0.1', 'client'); api.use('natestrauser:select2@4.0.1', 'client');
api.use('clinical:router'); api.use('iron:router@1.0.13');
api.use('momentjs:moment'); api.use('momentjs:moment');
api.use('validatejs'); api.use('validatejs');

View File

@ -1,4 +1,4 @@
@import "{design}/app" @import "{ohif:design}/app"
#aboutModal #aboutModal
.logo .logo

View File

@ -1,4 +1,4 @@
@import "{design}/app" @import "{ohif:design}/app"
.thumbnailEntry.active .imageThumbnail .thumbnailEntry.active .imageThumbnail
theme('border-color', '$activeColor') theme('border-color', '$activeColor')

View File

@ -1,4 +1,4 @@
@import "{design}/app" @import "{ohif:design}/app"
$seriesCountBackgroundColor = #678696 $seriesCountBackgroundColor = #678696

View File

@ -1,4 +1,4 @@
@import "{design}/app.styl" @import "{ohif:design}/app"
.annotationDialog .annotationDialog
theme('border', '1px solid $uiBorderColor', 0.95) theme('border', '1px solid $uiBorderColor', 0.95)

View File

@ -1,45 +1,47 @@
<template name="cineDialog"> <template name="cineDialog">
{{#form id='cineDialog' class=(getClassNames 'dialog-animated noselect') schema=instance.schema api=instance.api}} <dialog id="cineDialog">
{{>inputHidden key='intervalId'}} {{#form id='cineDialogForm' class=(getClassNames 'dialog-animated noselect') schema=instance.schema api=instance.api}}
<div class="cine-navigation"> {{>inputHidden key='intervalId'}}
<div class="btn-group"> <div class="cine-navigation">
{{#button class='btn' disabled=(displaySetDisabled false) action='displaySetPrevious' title='Previous display set'}} <div class="btn-group">
<i class="fa fa-toggle-up"></i> {{#button class='btn' disabled=(displaySetDisabled false) action='displaySetPrevious' title='Previous display set'}}
{{/button}} <i class="fa fa-toggle-up"></i>
{{#button class='btn' disabled=(displaySetDisabled true) action='displaySetNext' title='Next display set'}} {{/button}}
<i class="fa fa-toggle-down"></i> {{#button class='btn' disabled=(displaySetDisabled true) action='displaySetNext' title='Next display set'}}
{{/button}} <i class="fa fa-toggle-down"></i>
{{/button}}
</div>
</div> </div>
</div> <div class="cine-controls">
<div class="cine-controls"> <div class="btn-group">
<div class="btn-group"> {{#button class='btn' action='cineFirst' title='Skip to first image' disabled=(buttonDisabled)}}
{{#button class='btn' action='cineFirst' title='Skip to first image' disabled=(buttonDisabled)}} <i class="fa fa-fast-backward"></i>
<i class="fa fa-fast-backward"></i> {{/button}}
{{/button}} {{#button class='btn' action='cinePrevious' title='Previous image' disabled=(buttonDisabled)}}
{{#button class='btn' action='cinePrevious' title='Previous image' disabled=(buttonDisabled)}} <i class="fa fa-step-backward"></i>
<i class="fa fa-step-backward"></i> {{/button}}
{{/button}} {{#button class='btn' action='cineToggle' title='Play / Stop' class=(concat 'btn ' (valueIf isPlaying 'active' '')) disabled=(buttonDisabled)}}
{{#button class='btn' action='cineToggle' title='Play / Stop' class=(concat 'btn ' (valueIf isPlaying 'active' '')) disabled=(buttonDisabled)}} {{#if isPlaying}}
{{#if isPlaying}} <i class="fa fa-fw fa-stop"></i>
<i class="fa fa-fw fa-stop"></i> {{else}}
{{else}} <i class="fa fa-fw fa-play"></i>
<i class="fa fa-fw fa-play"></i> {{/if}}
{{/if}} {{/button}}
{{/button}} {{#button class='btn' action='cineNext' title='Next image' disabled=(buttonDisabled)}}
{{#button class='btn' action='cineNext' title='Next image' disabled=(buttonDisabled)}} <i class="fa fa-step-forward"></i>
<i class="fa fa-step-forward"></i> {{/button}}
{{/button}} {{#button class='btn' action='cineLast' title='Skip to last image' disabled=(buttonDisabled)}}
{{#button class='btn' action='cineLast' title='Skip to last image' disabled=(buttonDisabled)}} <i class="fa fa-fast-forward"></i>
<i class="fa fa-fast-forward"></i> {{/button}}
{{/button}} </div>
</div> </div>
</div> <div class="cine-options">
<div class="cine-options"> <div class="fps-section">
<div class="fps-section"> {{#inputRange key='framesPerSecond' class='p-a-0' labelClass='form-group m-a-0' labelAsDiv=true}}
{{#inputRange key='framesPerSecond' class='p-a-0' labelClass='form-group m-a-0' labelAsDiv=true}} {{/inputRange}}
{{/inputRange}} </div>
<span id="fps">{{framerate}} fps</span>
</div> </div>
<span id="fps">{{framerate}} fps</span> {{/form}}
</div> </dialog>
{{/form}}
</template> </template>

View File

@ -1,4 +1,4 @@
@import "{design}/app.styl" @import "{ohif:design}/app"
#cineDialog #cineDialog
theme('border', '2px solid $uiBorderColor', 0.95) theme('border', '2px solid $uiBorderColor', 0.95)

View File

@ -1,4 +1,4 @@
@import "{design}/app.styl" @import "{ohif:design}/app"
#imageViewerViewports #imageViewerViewports
height: 100% height: 100%

View File

@ -1,4 +1,4 @@
@import "{design}/app" @import "{ohif:design}/app"
$imageSliderBorderRadius = 57px $imageSliderBorderRadius = 57px
$imageSliderTrackColor = rgba(0,0,0,0) $imageSliderTrackColor = rgba(0,0,0,0)

View File

@ -1,4 +1,4 @@
@import "{design}/app.styl" @import "{ohif:design}/app"
.imageViewerViewport .imageViewerViewport
width: 100% width: 100%

View File

@ -1,4 +1,4 @@
@import "{design}/app.styl" @import "{ohif:design}/app"
$borderColor = rgba(77, 99, 110, 0.81) $borderColor = rgba(77, 99, 110, 0.81)

View File

@ -1,4 +1,4 @@
@import "{design}/app.styl" @import "{ohif:design}/app"
.imageViewerLoadingIndicator .imageViewerLoadingIndicator
theme('color', '$textSecondaryColor') theme('color', '$textSecondaryColor')

View File

@ -1,4 +1,4 @@
@import "{design}/app" @import "{ohif:design}/app"
$switchSize = 55px $switchSize = 55px
$seriesSpacing = 2px $seriesSpacing = 2px
@ -121,7 +121,7 @@ $seriesSpacing = 2px
width: $switchSize + $seriesSpacing width: $switchSize + $seriesSpacing
.seriesItem .seriesItem
theme('background-color', '$boxBackgroundColor') theme('background-color', '$boxBackgroundColor')Dark
border-radius: 3px border-radius: 3px
height: 15px height: 15px
margin: $seriesSpacing margin: $seriesSpacing
@ -164,10 +164,10 @@ $seriesSpacing = 2px
overflow-x: hidden overflow-x: hidden
overflow-y: scroll overflow-y: scroll
width: calc(100% + 22px) width: calc(100% + 22px)
&.is-mac &.is-mac
padding-right: 22px padding-right: 22px
&.show-scroll-indicator-up:before &.show-scroll-indicator-up:before
&.show-scroll-indicator-down:after &.show-scroll-indicator-down:after
font-family: FontAwesome font-family: FontAwesome
@ -180,11 +180,11 @@ $seriesSpacing = 2px
z-index: 1 z-index: 1
text-align: center text-align: center
left: 0 left: 0
&.show-scroll-indicator-up:before &.show-scroll-indicator-up:before
top: -10px top: -10px
content: '\f102' content: '\f102'
&.show-scroll-indicator-down:after &.show-scroll-indicator-down:after
bottom: 18px bottom: 18px
content: '\f103' content: '\f103'

View File

@ -1,4 +1,4 @@
@import "{design}/app" @import "{ohif:design}/app"
.studyTimepointWrapper .studyTimepointWrapper
overflow: hidden overflow: hidden

View File

@ -1,4 +1,4 @@
@import "{design}/app" @import "{ohif:design}/app"
$timepointButtonHeight = 55px $timepointButtonHeight = 55px

View File

@ -1,4 +1,4 @@
@import "{design}/app" @import "{ohif:design}/app"
$boxBorderColor = transparent $boxBorderColor = transparent
$boxHoverBackgroundColor = #14191E $boxHoverBackgroundColor = #14191E

View File

@ -1,4 +1,4 @@
@import "{design}/app" @import "{ohif:design}/app"
.toolbarSectionButton .toolbarSectionButton
theme('color', '$defaultColor') theme('color', '$defaultColor')

View File

@ -1,4 +1,4 @@
@import "{design}/app" @import "{ohif:design}/app"
$distance = 10px $distance = 10px

View File

@ -1,4 +1,4 @@
@import "{design}/app" @import "{ohif:design}/app"
.viewerMain .viewerMain
width: 100% width: 100%

View File

@ -1,4 +1,4 @@
@import "{design}/app" @import "{ohif:design}/app"
$viewportTagPadding = 20px $viewportTagPadding = 20px
@ -48,3 +48,4 @@ $viewportTagPadding = 20px
margin: 2px margin: 2px
width: 18px width: 18px
height: 18px height: 18px