Replacing studyListContextMenu for dropdown
This commit is contained in:
parent
4daf7d8bf8
commit
485f82f64c
@ -15,7 +15,7 @@ Template.app.onCreated(() => {
|
|||||||
|
|
||||||
ViewerData = Session.get('ViewerData') || {};
|
ViewerData = Session.get('ViewerData') || {};
|
||||||
|
|
||||||
OHIF.header.setDropdownItems([{
|
OHIF.header.dropdown.setItems([{
|
||||||
action: OHIF.user.audit,
|
action: OHIF.user.audit,
|
||||||
text: 'View Audit Log',
|
text: 'View Audit Log',
|
||||||
iconClasses: 'log',
|
iconClasses: 'log',
|
||||||
|
|||||||
@ -20,11 +20,12 @@ OHIF.mixins.action = new OHIF.Mixin({
|
|||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
const component = instance.component;
|
const component = instance.component;
|
||||||
|
|
||||||
// Extract action, params and disabled state
|
// Extract action, disabled state and params
|
||||||
const { action, params, disabled } = instance.data;
|
const { action } = instance.data;
|
||||||
|
const params = instance.data.params ? instance.data.params : event;
|
||||||
|
|
||||||
// Stop here if the component is disabled
|
// Stop here if the component is disabled
|
||||||
if (disabled) return;
|
if (component.$element.hasClass('disabled')) return;
|
||||||
|
|
||||||
// Get the current component's API
|
// Get the current component's API
|
||||||
const api = component.getApi();
|
const api = component.getApi();
|
||||||
|
|||||||
@ -42,7 +42,8 @@ OHIF.mixins.dropdown = new OHIF.Mixin({
|
|||||||
// Close the dropdown resolving or rejecting the promise
|
// Close the dropdown resolving or rejecting the promise
|
||||||
instance.close = (isResolve, result) => {
|
instance.close = (isResolve, result) => {
|
||||||
const method = instance.data[isResolve ? 'promiseResolve' : 'promiseReject'];
|
const method = instance.data[isResolve ? 'promiseResolve' : 'promiseReject'];
|
||||||
method(result);
|
const param = result instanceof Promise ? null : result;
|
||||||
|
method(param);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Stop here and destroy the view if no items was given
|
// Stop here and destroy the view if no items was given
|
||||||
@ -52,7 +53,7 @@ OHIF.mixins.dropdown = new OHIF.Mixin({
|
|||||||
|
|
||||||
dropdown.oncontextmenu = () => false;
|
dropdown.oncontextmenu = () => false;
|
||||||
|
|
||||||
const cssBefore = { 'z-index': 10000 };
|
const cssBefore = {};
|
||||||
if (event) {
|
if (event) {
|
||||||
cssBefore.position = 'fixed';
|
cssBefore.position = 'fixed';
|
||||||
$dropdownMenu.bounded();
|
$dropdownMenu.bounded();
|
||||||
|
|||||||
@ -6,9 +6,13 @@
|
|||||||
|
|
||||||
ul.dropdown-menu
|
ul.dropdown-menu
|
||||||
display: block
|
display: block
|
||||||
|
z-index: 1000
|
||||||
transform(scale(0))
|
transform(scale(0))
|
||||||
transition(transform 0.3s ease)
|
transition(transform 0.3s ease)
|
||||||
|
|
||||||
|
&.dropdown-menu-left
|
||||||
|
transform-origin(0% 0%)
|
||||||
|
|
||||||
&.dropdown-menu-right
|
&.dropdown-menu-right
|
||||||
transform-origin(100% 0%)
|
transform-origin(100% 0%)
|
||||||
|
|
||||||
|
|||||||
38
Packages/ohif-core/client/ui/dropdown/class.js
Normal file
38
Packages/ohif-core/client/ui/dropdown/class.js
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
import { Tracker } from 'meteor/tracker';
|
||||||
|
import { _ } from 'meteor/underscore';
|
||||||
|
import { OHIF } from 'meteor/ohif:core';
|
||||||
|
|
||||||
|
class Dropdown {
|
||||||
|
constructor() {
|
||||||
|
this.observer = new Tracker.Dependency();
|
||||||
|
this._items = [];
|
||||||
|
this.observer.changed();
|
||||||
|
}
|
||||||
|
|
||||||
|
clearItems() {
|
||||||
|
this._items = [];
|
||||||
|
this.observer.changed();
|
||||||
|
}
|
||||||
|
|
||||||
|
setItems(items) {
|
||||||
|
this._items = items;
|
||||||
|
this.observer.changed();
|
||||||
|
}
|
||||||
|
|
||||||
|
addItem(item) {
|
||||||
|
this._items.push(item);
|
||||||
|
this.observer.changed();
|
||||||
|
}
|
||||||
|
|
||||||
|
removeItem(item) {
|
||||||
|
this._items = _.without(this._items, item);
|
||||||
|
this.observer.changed();
|
||||||
|
}
|
||||||
|
|
||||||
|
getItems() {
|
||||||
|
this.observer.depend();
|
||||||
|
return this._items;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
OHIF.ui.Dropdown = Dropdown;
|
||||||
@ -1,29 +0,0 @@
|
|||||||
import { Template } from 'meteor/templating';
|
|
||||||
import { Blaze } from 'meteor/blaze';
|
|
||||||
import { _ } from 'meteor/underscore';
|
|
||||||
import { OHIF } from 'meteor/ohif:core';
|
|
||||||
|
|
||||||
OHIF.ui.showFormDropdown = (templateName, dropdownData) => {
|
|
||||||
// Check if the given template exists
|
|
||||||
const template = Template[templateName];
|
|
||||||
if (!template) {
|
|
||||||
throw {
|
|
||||||
name: 'TEMPLATE_NOT_FOUND',
|
|
||||||
message: `Template ${templateName} not found.`
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prepare the method to destroy the view
|
|
||||||
let view;
|
|
||||||
const destroyView = () => Blaze.remove(view);
|
|
||||||
const templateData = _.extend({}, dropdownData, {
|
|
||||||
destroyView
|
|
||||||
});
|
|
||||||
|
|
||||||
// Render the dialog with the given template and data
|
|
||||||
view = Blaze.renderWithData(template, templateData, document.body);
|
|
||||||
|
|
||||||
// Return the dropdown element to enable position manipulation
|
|
||||||
const dropdown = view.firstNode();
|
|
||||||
return dropdown;
|
|
||||||
};
|
|
||||||
@ -4,7 +4,7 @@ import './dialog/display.js';
|
|||||||
import './dialog/spatial.js';
|
import './dialog/spatial.js';
|
||||||
import './dialog/unsavedChangesDialog.js';
|
import './dialog/unsavedChangesDialog.js';
|
||||||
import './draggable/draggable.js';
|
import './draggable/draggable.js';
|
||||||
import './dropdown/dropdown.js';
|
import './dropdown/class.js';
|
||||||
import './dropdown/form.js';
|
import './dropdown/display.js';
|
||||||
import './resizable/resizable.js';
|
import './resizable/resizable.js';
|
||||||
import './unsavedChanges/unsavedChanges.js';
|
import './unsavedChanges/unsavedChanges.js';
|
||||||
|
|||||||
@ -7,8 +7,8 @@ Template.header.onCreated(() => {
|
|||||||
|
|
||||||
instance.dropdownItems = [];
|
instance.dropdownItems = [];
|
||||||
instance.autorun(() => {
|
instance.autorun(() => {
|
||||||
OHIF.header.dropdownObserver.depend();
|
OHIF.header.dropdown.observer.depend();
|
||||||
instance.dropdownItems = OHIF.header.getDropdownItems();
|
instance.dropdownItems = OHIF.header.dropdown.getItems();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -1,35 +0,0 @@
|
|||||||
import { Tracker } from 'meteor/tracker';
|
|
||||||
import { _ } from 'meteor/underscore';
|
|
||||||
|
|
||||||
export class Header {
|
|
||||||
constructor() {
|
|
||||||
this.dropdownObserver = new Tracker.Dependency();
|
|
||||||
this._dropdownItems = [];
|
|
||||||
this.dropdownObserver.changed();
|
|
||||||
}
|
|
||||||
|
|
||||||
clearDropDownItems() {
|
|
||||||
this._dropdownItems = [];
|
|
||||||
this.dropdownObserver.changed();
|
|
||||||
}
|
|
||||||
|
|
||||||
setDropdownItems(items) {
|
|
||||||
this._dropdownItems = items;
|
|
||||||
this.dropdownObserver.changed();
|
|
||||||
}
|
|
||||||
|
|
||||||
addDropdownItem(item) {
|
|
||||||
this._dropdownItems.push(item);
|
|
||||||
this.dropdownObserver.changed();
|
|
||||||
}
|
|
||||||
|
|
||||||
removeDropdownItem(item) {
|
|
||||||
this._dropdownItems = _.without(this._dropdownItems, item);
|
|
||||||
this.dropdownObserver.changed();
|
|
||||||
}
|
|
||||||
|
|
||||||
getDropdownItems() {
|
|
||||||
this.dropdownObserver.depend();
|
|
||||||
return this._dropdownItems;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,10 +1,10 @@
|
|||||||
import { OHIF } from 'meteor/ohif:core';
|
import { OHIF } from 'meteor/ohif:core';
|
||||||
import { Header } from './client/lib/header';
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Defines the base OHIF header object
|
* Defines the base OHIF header object
|
||||||
*/
|
*/
|
||||||
const header = new Header();
|
const dropdown = new OHIF.ui.Dropdown();
|
||||||
|
const header = { dropdown };
|
||||||
|
|
||||||
OHIF.header = header;
|
OHIF.header = header;
|
||||||
|
|
||||||
|
|||||||
@ -1,13 +1,10 @@
|
|||||||
import { Template } from 'meteor/templating';
|
import { Meteor } from 'meteor/meteor';
|
||||||
import { Random } from 'meteor/random';
|
|
||||||
import { OHIF } from 'meteor/ohif:core';
|
import { OHIF } from 'meteor/ohif:core';
|
||||||
|
|
||||||
// Use Aldeed's meteor-template-extension package to replace the
|
/**
|
||||||
// default StudyListStudy template.
|
* Loads multiple unassociated studies in the Viewer
|
||||||
// See https://github.com/aldeed/meteor-template-extension
|
*/
|
||||||
const defaultTemplate = 'studyContextMenu';
|
const getAssociationAssessment = () => {
|
||||||
|
|
||||||
function getAssociationAssessment() {
|
|
||||||
// default result value
|
// default result value
|
||||||
const assessment = {
|
const assessment = {
|
||||||
selected: 0,
|
selected: 0,
|
||||||
@ -33,49 +30,40 @@ function getAssociationAssessment() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return assessment;
|
return assessment;
|
||||||
}
|
};
|
||||||
|
|
||||||
Template.longitudinalStudyListContextMenu.helpers({
|
/**
|
||||||
|
* Loads multiple unassociated studies in the Viewer
|
||||||
|
*/
|
||||||
|
const viewStudies = () => {
|
||||||
|
OHIF.log.info('viewStudies');
|
||||||
|
const selectedStudies = OHIF.studylist.getSelectedStudies();
|
||||||
|
|
||||||
getAssociationClasses() {
|
if (!selectedStudies || !selectedStudies.length) {
|
||||||
const disabledClass = 'disabled';
|
return;
|
||||||
let classList = '';
|
|
||||||
|
|
||||||
const assessment = getAssociationAssessment();
|
|
||||||
// if (assessment.selected < 1 || assessment.associated > 0) {
|
|
||||||
// TODO: REMOVE - Temporary for RSNA
|
|
||||||
if (assessment.selected < 1) {
|
|
||||||
classList += disabledClass;
|
|
||||||
}
|
|
||||||
|
|
||||||
return classList;
|
|
||||||
},
|
|
||||||
|
|
||||||
getRemoveAssociationClasses() {
|
|
||||||
const disabledClass = 'disabled';
|
|
||||||
let classList = '';
|
|
||||||
|
|
||||||
const assessment = getAssociationAssessment();
|
|
||||||
if (assessment.selected < 1 || assessment.selected !== assessment.associated) {
|
|
||||||
classList += disabledClass;
|
|
||||||
}
|
|
||||||
|
|
||||||
return classList;
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
Template.longitudinalStudyListContextMenu.replaces(defaultTemplate);
|
const title = selectedStudies[0].patientName;
|
||||||
Template[defaultTemplate].inheritsHelpersFrom('longitudinalStudyListContextMenu');
|
const studyInstanceUids = selectedStudies.map(study => study.studyInstanceUid);
|
||||||
|
const contentId = 'viewerTab';
|
||||||
|
|
||||||
StudyList.functions.launchStudyAssociation = () => OHIF.ui.showDialog('dialogStudyAssociation');
|
ViewerData = window.ViewerData || ViewerData;
|
||||||
StudyList.functions.removeTimepointAssociations = removeTimepointAssociations;
|
|
||||||
StudyList.functions.exportSelectedStudies = exportSelectedStudies;
|
// Update the ViewerData global object
|
||||||
StudyList.functions.viewStudies = viewStudies;
|
ViewerData[contentId] = {
|
||||||
|
title: title,
|
||||||
|
contentId: contentId,
|
||||||
|
studyInstanceUids: studyInstanceUids
|
||||||
|
};
|
||||||
|
|
||||||
|
// Switch to the new tab
|
||||||
|
switchToTab(contentId);
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes all present study / timepoint associations from the Clinical Trial
|
* Removes all present study / timepoint associations from the Clinical Trial
|
||||||
*/
|
*/
|
||||||
function removeTimepointAssociations($study, event) {
|
const removeTimepointAssociations = event => {
|
||||||
const dialogSettings = {
|
const dialogSettings = {
|
||||||
title: 'Remove Association',
|
title: 'Remove Association',
|
||||||
message: 'Measurements related to this Study and Timepoint will be erased. Do you really want to delete this association?',
|
message: 'Measurements related to this Study and Timepoint will be erased. Do you really want to delete this association?',
|
||||||
@ -105,47 +93,44 @@ function removeTimepointAssociations($study, event) {
|
|||||||
timepointApi.disassociateStudy(timepointIds, studyInstanceUid);
|
timepointApi.disassociateStudy(timepointIds, studyInstanceUid);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
// ---------- TODO: Remove these duplicated functions below -------------
|
Meteor.startup(() => {
|
||||||
|
OHIF.studylist.dropdown.setItems([{
|
||||||
/**
|
action: viewStudies,
|
||||||
* Exports all selected studies on the studylist
|
text: 'View',
|
||||||
*/
|
separatorAfter: true
|
||||||
function exportSelectedStudies() {
|
}, {
|
||||||
const selectedStudies = OHIF.studylist.getSelectedStudies();
|
action: () => OHIF.ui.showDialog('dialogStudyAssociation'),
|
||||||
|
text: 'Associate',
|
||||||
if (!selectedStudies || !selectedStudies.length) {
|
disabled: () => {
|
||||||
return;
|
const assessment = getAssociationAssessment();
|
||||||
}
|
return assessment.selected < 1;
|
||||||
|
}
|
||||||
OHIF.studylist.exportStudies(selectedStudies);
|
}, {
|
||||||
}
|
action: removeTimepointAssociations,
|
||||||
|
text: 'Remove Association',
|
||||||
/**
|
separatorAfter: true,
|
||||||
* Loads multiple unassociated studies in the Viewer
|
disabled: () => {
|
||||||
*/
|
const assessment = getAssociationAssessment();
|
||||||
function viewStudies() {
|
return assessment.selected < 1 || assessment.selected !== assessment.associated;
|
||||||
OHIF.log.info('viewStudies');
|
}
|
||||||
const selectedStudies = OHIF.studylist.getSelectedStudies();
|
}, {
|
||||||
|
action: OHIF.studylist.viewSeriesDetails,
|
||||||
if (!selectedStudies || !selectedStudies.length) {
|
text: 'View Series Details'
|
||||||
return;
|
}, {
|
||||||
}
|
text: 'Anonymize',
|
||||||
|
disabled: true
|
||||||
const title = selectedStudies[0].patientName;
|
}, {
|
||||||
const studyInstanceUids = selectedStudies.map(study => study.studyInstanceUid);
|
text: 'Send',
|
||||||
const contentId = 'viewerTab';
|
disabled: true,
|
||||||
|
separatorAfter: true
|
||||||
ViewerData = window.ViewerData || ViewerData;
|
}, {
|
||||||
|
action: OHIF.studylist.exportSelectedStudies,
|
||||||
// Update the ViewerData global object
|
text: 'Export',
|
||||||
ViewerData[contentId] = {
|
title: 'Export Selected Studies'
|
||||||
title: title,
|
}, {
|
||||||
contentId: contentId,
|
text: 'Delete',
|
||||||
studyInstanceUids: studyInstanceUids
|
disabled: true
|
||||||
};
|
}]);
|
||||||
|
});
|
||||||
// Switch to the new tab
|
|
||||||
switchToTab(contentId);
|
|
||||||
}
|
|
||||||
@ -3,8 +3,7 @@ import './longitudinalStudyListStudy/longitudinalStudyListStudy.html';
|
|||||||
import './longitudinalStudyListStudy/longitudinalStudyListStudy.styl';
|
import './longitudinalStudyListStudy/longitudinalStudyListStudy.styl';
|
||||||
import './longitudinalStudyListStudy/longitudinalStudyListStudy.js';
|
import './longitudinalStudyListStudy/longitudinalStudyListStudy.js';
|
||||||
|
|
||||||
import './longitudinalStudyListContextMenu/longitudinalStudyListContextMenu.html';
|
|
||||||
import './longitudinalStudyListContextMenu/longitudinalStudyListContextMenu.js';
|
|
||||||
|
|
||||||
import './longitudinalViewportOverlay/longitudinalViewportOverlay.html';
|
import './longitudinalViewportOverlay/longitudinalViewportOverlay.html';
|
||||||
import './longitudinalViewportOverlay/longitudinalViewportOverlay.js';
|
import './longitudinalViewportOverlay/longitudinalViewportOverlay.js';
|
||||||
|
|
||||||
|
import './dropdown.js';
|
||||||
|
|||||||
@ -1,31 +0,0 @@
|
|||||||
<template name="longitudinalStudyListContextMenu">
|
|
||||||
{{#dropdownForm}}
|
|
||||||
<li><a id="viewStudies" type="button" title="View Studies">View</a></li>
|
|
||||||
<li class="divider" role="separator"></li>
|
|
||||||
|
|
||||||
{{#let classes=getAssociationClasses}}
|
|
||||||
<li class="{{classes}}">
|
|
||||||
<a id="launchStudyAssociation" class="{{classes}}"
|
|
||||||
title="Launch Study Association">Associate</a>
|
|
||||||
</li>
|
|
||||||
{{/let}}
|
|
||||||
|
|
||||||
{{#let classes=getRemoveAssociationClasses}}
|
|
||||||
<li class="{{classes}}">
|
|
||||||
<a id="removeTimepointAssociations" type="button" class="{{classes}}"
|
|
||||||
title="Remove Timepoint Association">Remove Association</a>
|
|
||||||
</li>
|
|
||||||
{{/let}}
|
|
||||||
|
|
||||||
<li class="divider" role="separator"></li>
|
|
||||||
<li>
|
|
||||||
<a id="viewSeriesDetails" type="button"
|
|
||||||
title="View Series Details">View Series Details</a>
|
|
||||||
</li>
|
|
||||||
<li class="disabled"><a class="disabled">Anonymize</a></li>
|
|
||||||
<li class="disabled"><a class="disabled">Send</a></li>
|
|
||||||
<li class="divider" role="separator"></li>
|
|
||||||
<li><a id="exportSelectedStudies" title="Export Selected Studies">Export</a></li>
|
|
||||||
<li class="disabled"><a class="disabled">Delete</a></li>
|
|
||||||
{{/dropdownForm}}
|
|
||||||
</template>
|
|
||||||
@ -1,5 +1,4 @@
|
|||||||
import './seriesDetailsModal';
|
import './seriesDetailsModal';
|
||||||
import './serverInformation';
|
import './serverInformation';
|
||||||
import './studyContextMenu';
|
|
||||||
import './studylist';
|
import './studylist';
|
||||||
import './themeSelector';
|
import './themeSelector';
|
||||||
|
|||||||
@ -1,89 +1,23 @@
|
|||||||
import { Template } from 'meteor/templating';
|
|
||||||
import { Meteor } from 'meteor/meteor';
|
import { Meteor } from 'meteor/meteor';
|
||||||
import { OHIF } from 'meteor/ohif:core';
|
import { OHIF } from 'meteor/ohif:core';
|
||||||
import { $ } from 'meteor/jquery';
|
|
||||||
|
|
||||||
/**
|
Meteor.startup(() => {
|
||||||
* This function is used inside the StudyList package to define a right click callback
|
OHIF.studylist.dropdown.setItems([{
|
||||||
*
|
action: OHIF.studylist.viewSeriesDetails,
|
||||||
* @param event
|
text: 'View Series Details'
|
||||||
*/
|
}, {
|
||||||
openStudyContextMenu = event => {
|
text: 'Anonymize',
|
||||||
if (!OHIF.uiSettings.studyListFunctionsEnabled) {
|
disabled: true
|
||||||
return;
|
}, {
|
||||||
}
|
text: 'Send',
|
||||||
|
disabled: true,
|
||||||
StudyList.functions.exportSelectedStudies = exportSelectedStudies;
|
separatorAfter: true
|
||||||
StudyList.functions.viewSeriesDetails = viewSeriesDetails;
|
}, {
|
||||||
|
text: 'Delete',
|
||||||
Template.studyContextMenu.$study = $(event.currentTarget);
|
disabled: true
|
||||||
|
}, {
|
||||||
const dropdown = OHIF.ui.showFormDropdown('studyContextMenu');
|
action: OHIF.studylist.exportSelectedStudies,
|
||||||
const $dropdown = $(dropdown);
|
text: 'Export',
|
||||||
const $dropdownMenu = $dropdown.children('.dropdown-menu');
|
title: 'Export Selected Studies'
|
||||||
|
}]);
|
||||||
dropdown.oncontextmenu = () => false;
|
|
||||||
|
|
||||||
$dropdownMenu.css({
|
|
||||||
visibility: 'hidden',
|
|
||||||
position: 'fixed',
|
|
||||||
'z-index': 10000,
|
|
||||||
}).bounded().focus();
|
|
||||||
|
|
||||||
// Postpone position change to allow boundaries restriction
|
|
||||||
Meteor.defer(() => {
|
|
||||||
$dropdownMenu.css({
|
|
||||||
visibility: 'visible',
|
|
||||||
left: `${event.clientX}px`,
|
|
||||||
top: `${event.clientY}px`
|
|
||||||
}).trigger('spatialChanged');
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Exports all selected studies on the studylist
|
|
||||||
*/
|
|
||||||
function exportSelectedStudies($study, event) {
|
|
||||||
const selectedStudies = OHIF.studylist.getSelectedStudies();
|
|
||||||
const studiesCount = selectedStudies.length;
|
|
||||||
const studyText = studiesCount > 1 ? 'Studies' : 'Study';
|
|
||||||
|
|
||||||
OHIF.ui.showDialog('dialogConfirm', {
|
|
||||||
element: event.element,
|
|
||||||
title: `Export ${studyText}`,
|
|
||||||
message: `Would you like to export ${studiesCount} ${studyText.toLowerCase()}?`
|
|
||||||
}).then(() => {
|
|
||||||
OHIF.studylist.exportStudies(selectedStudies);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Display series details of study in modal
|
|
||||||
*/
|
|
||||||
function viewSeriesDetails() {
|
|
||||||
const selectedStudies = OHIF.studylist.getSelectedStudies();
|
|
||||||
|
|
||||||
if (!selectedStudies) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
OHIF.ui.showDialog('seriesDetailsModal', { selectedStudies });
|
|
||||||
}
|
|
||||||
|
|
||||||
Template.studyContextMenu.events({
|
|
||||||
'click a'(event, instance) {
|
|
||||||
const $target = $(event.currentTarget);
|
|
||||||
|
|
||||||
if ($target.hasClass('disabled')) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const id = $target.attr('id');
|
|
||||||
if (id in StudyList.functions) {
|
|
||||||
const fn = StudyList.functions[id];
|
|
||||||
if (typeof fn === 'function') {
|
|
||||||
fn(Template.studyContextMenu.$study, event);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,3 +1,6 @@
|
|||||||
|
import { Meteor } from 'meteor/meteor';
|
||||||
|
import { Template } from 'meteor/templating';
|
||||||
|
import { Blaze } from 'meteor/blaze';
|
||||||
import { OHIF } from 'meteor/ohif:core';
|
import { OHIF } from 'meteor/ohif:core';
|
||||||
|
|
||||||
// Maybe we should use regular StudyList collection?
|
// Maybe we should use regular StudyList collection?
|
||||||
@ -45,7 +48,7 @@ function doUnselectRow(studyRow, data) {
|
|||||||
studyRow.removeClass('active');
|
studyRow.removeClass('active');
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleShiftClick(studyRow, data) {
|
function handleShiftClick($studyRow, data) {
|
||||||
//OHIF.log.info('shiftKey');
|
//OHIF.log.info('shiftKey');
|
||||||
|
|
||||||
let study, previous = StudyList.previouslySelected ? $(StudyList.previouslySelected) : null;
|
let study, previous = StudyList.previouslySelected ? $(StudyList.previouslySelected) : null;
|
||||||
@ -59,49 +62,49 @@ function handleShiftClick(studyRow, data) {
|
|||||||
|
|
||||||
// Select all rows in between these two rows
|
// Select all rows in between these two rows
|
||||||
if (previous) {
|
if (previous) {
|
||||||
let rowsInBetween;
|
let $rowsInBetween;
|
||||||
if (previous.index() < studyRow.index()) {
|
if (previous.index() < $studyRow.index()) {
|
||||||
// The previously selected row is above (lower index) the
|
// The previously selected row is above (lower index) the
|
||||||
// currently selected row.
|
// currently selected row.
|
||||||
|
|
||||||
// Fill in the rows upwards from the previously selected row
|
// Fill in the rows upwards from the previously selected row
|
||||||
rowsInBetween = previous.nextAll('tr');
|
$rowsInBetween = previous.nextAll('tr');
|
||||||
} else if (previous.index() > studyRow.index()) {
|
} else if (previous.index() > $studyRow.index()) {
|
||||||
// The previously selected row is below the currently
|
// The previously selected row is below the currently
|
||||||
// selected row.
|
// selected row.
|
||||||
|
|
||||||
// Fill in the rows upwards from the previously selected row
|
// Fill in the rows upwards from the previously selected row
|
||||||
rowsInBetween = previous.prevAll('tr');
|
$rowsInBetween = previous.prevAll('tr');
|
||||||
} else {
|
} else {
|
||||||
// nothing to do since previous.index() === studyRow.index()
|
// nothing to do since previous.index() === $studyRow.index()
|
||||||
// the user is shift-clicking the same row...
|
// the user is shift-clicking the same row...
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Loop through the rows in between current and previous selected studies
|
// Loop through the rows in between current and previous selected studies
|
||||||
rowsInBetween.each(function() {
|
$rowsInBetween.forEach(row => {
|
||||||
let row = $(this);
|
const $row = $(row);
|
||||||
|
|
||||||
if (row.hasClass('active')) {
|
if ($row.hasClass('active')) {
|
||||||
// If we find one that is already selected, do nothing
|
// If we find one that is already selected, do nothing
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the relevant studyInstanceUid
|
// Get the relevant studyInstanceUid
|
||||||
let studyInstanceUid = row.attr('studyInstanceUid');
|
let studyInstanceUid = $row.attr('studyInstanceUid');
|
||||||
|
|
||||||
// Retrieve the data context through Blaze
|
// Retrieve the data context through Blaze
|
||||||
let data = Blaze.getData(this);
|
let data = Blaze.getData(this);
|
||||||
|
|
||||||
// Set the current study as selected
|
// Set the current study as selected
|
||||||
doSelectRow(row, data);
|
doSelectRow($row, data);
|
||||||
|
|
||||||
// When we reach the currently clicked-on row, stop the loop
|
// When we reach the currently clicked-on $row, stop the loop
|
||||||
return !row.is(studyRow);
|
return !$row.is($studyRow);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// Set the current study as selected
|
// Set the current study as selected
|
||||||
doSelectSingleRow(studyRow, data);
|
doSelectSingleRow($studyRow, data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -139,59 +142,58 @@ Template.studylistStudy.onRendered(function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
Template.studylistStudy.events({
|
Template.studylistStudy.events({
|
||||||
'click tr.studylistStudy': function(e) {
|
'click tr.studylistStudy'(event, instance) {
|
||||||
var studyRow = $(e.currentTarget);
|
const $studyRow = $(event.currentTarget);
|
||||||
var data = this;
|
const data = instance.data;
|
||||||
|
|
||||||
// Remove the ID so we can directly insert this into our client-side collection
|
// Remove the ID so we can directly insert this into our client-side collection
|
||||||
delete data._id;
|
delete data._id;
|
||||||
|
|
||||||
if (e.shiftKey) {
|
if (event.shiftKey) {
|
||||||
handleShiftClick(studyRow, data);
|
handleShiftClick($studyRow, data);
|
||||||
} else if (e.ctrlKey || e.metaKey) {
|
} else if (event.ctrlKey || event.metaKey) {
|
||||||
handleCtrlClick(studyRow, data);
|
handleCtrlClick($studyRow, data);
|
||||||
} else {
|
} else {
|
||||||
doSelectSingleRow(studyRow, data);
|
doSelectSingleRow($studyRow, data);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'mousedown tr.studylistStudy': function(e) {
|
|
||||||
|
'mousedown tr.studylistStudy'(event, instance) {
|
||||||
// This event handler is meant to handle middle-click on a study
|
// This event handler is meant to handle middle-click on a study
|
||||||
if (e.which !== 2) {
|
if (event.which !== 2) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var data = this;
|
const middleClickOnStudy = StudyList.callbacks.middleClickOnStudy;
|
||||||
var middleClickOnStudy = StudyList.callbacks.middleClickOnStudy;
|
|
||||||
if (middleClickOnStudy && typeof middleClickOnStudy === 'function') {
|
if (middleClickOnStudy && typeof middleClickOnStudy === 'function') {
|
||||||
middleClickOnStudy(data);
|
middleClickOnStudy(instance.data);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'dblclick tr.studylistStudy, doubletap tr.studylistStudy': function(e) {
|
|
||||||
if (e.which !== undefined && e.which !== 1) {
|
'dblclick tr.studylistStudy, doubletap tr.studylistStudy'(event, instance) {
|
||||||
|
if (event.which !== undefined && event.which !== 1) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var data = this;
|
const dblClickOnStudy = StudyList.callbacks.dblClickOnStudy;
|
||||||
var dblClickOnStudy = StudyList.callbacks.dblClickOnStudy;
|
|
||||||
|
|
||||||
if (dblClickOnStudy && typeof dblClickOnStudy === 'function') {
|
if (dblClickOnStudy && typeof dblClickOnStudy === 'function') {
|
||||||
dblClickOnStudy(data);
|
dblClickOnStudy(instance.data);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'contextmenu tr.studylistStudy, press tr.studylistStudy': function(e, template) {
|
|
||||||
|
|
||||||
var studyRow = $(e.currentTarget),
|
'contextmenu tr.studylistStudy, press tr.studylistStudy'(event, instance) {
|
||||||
data = this;
|
const $studyRow = $(event.currentTarget);
|
||||||
|
|
||||||
if (!isStudySelected(data)) {
|
if (!isStudySelected(instance.data)) {
|
||||||
doSelectSingleRow(studyRow, data);
|
doSelectSingleRow($studyRow, instance.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof openStudyContextMenu === 'function') {
|
event.preventDefault();
|
||||||
e.preventDefault();
|
OHIF.ui.showDropdown(OHIF.studylist.dropdown.getItems(), {
|
||||||
openStudyContextMenu(e, template);
|
event,
|
||||||
return false;
|
menuClasses: 'dropdown-menu-left'
|
||||||
}
|
});
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|||||||
25
Packages/ohif-study-list/client/dropdown.js
Normal file
25
Packages/ohif-study-list/client/dropdown.js
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import { Meteor } from 'meteor/meteor';
|
||||||
|
import { OHIF } from 'meteor/ohif:core';
|
||||||
|
|
||||||
|
Meteor.startup(() => {
|
||||||
|
OHIF.studylist.dropdown = new OHIF.ui.Dropdown();
|
||||||
|
|
||||||
|
OHIF.studylist.dropdown.setItems([{
|
||||||
|
action: OHIF.studylist.viewSeriesDetails,
|
||||||
|
text: 'View Series Details'
|
||||||
|
}, {
|
||||||
|
text: 'Anonymize',
|
||||||
|
disabled: true
|
||||||
|
}, {
|
||||||
|
text: 'Send',
|
||||||
|
disabled: true,
|
||||||
|
separatorAfter: true
|
||||||
|
}, {
|
||||||
|
text: 'Delete',
|
||||||
|
disabled: true
|
||||||
|
}, {
|
||||||
|
action: OHIF.studylist.exportSelectedStudies,
|
||||||
|
text: 'Export',
|
||||||
|
title: 'Export Selected Studies'
|
||||||
|
}]);
|
||||||
|
});
|
||||||
@ -1,3 +1,4 @@
|
|||||||
import './collections';
|
import './collections';
|
||||||
import './lib';
|
import './lib';
|
||||||
import './components';
|
import './components';
|
||||||
|
import './dropdown';
|
||||||
|
|||||||
19
Packages/ohif-study-list/client/lib/exportSelectedStudies.js
Normal file
19
Packages/ohif-study-list/client/lib/exportSelectedStudies.js
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import { OHIF } from 'meteor/ohif:core';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exports all selected studies on the studylist
|
||||||
|
* @param event Event that triggered the export
|
||||||
|
*/
|
||||||
|
OHIF.studylist.exportSelectedStudies = event => {
|
||||||
|
const selectedStudies = OHIF.studylist.getSelectedStudies();
|
||||||
|
const studiesCount = selectedStudies.length;
|
||||||
|
const studyText = studiesCount > 1 ? 'Studies' : 'Study';
|
||||||
|
|
||||||
|
OHIF.ui.showDialog('dialogConfirm', {
|
||||||
|
element: event.element,
|
||||||
|
title: `Export ${studyText}`,
|
||||||
|
message: `Would you like to export ${studiesCount} ${studyText.toLowerCase()}?`
|
||||||
|
}).then(() => {
|
||||||
|
OHIF.studylist.exportStudies(selectedStudies);
|
||||||
|
});
|
||||||
|
};
|
||||||
@ -1,5 +1,6 @@
|
|||||||
import './third-party/jquery.twbsPagination.min.js';
|
import './third-party/jquery.twbsPagination.min.js';
|
||||||
|
|
||||||
|
import './exportSelectedStudies.js';
|
||||||
import './exportStudies.js';
|
import './exportStudies.js';
|
||||||
import './getSelectedStudies.js';
|
import './getSelectedStudies.js';
|
||||||
import './getStudyMetadata.js';
|
import './getStudyMetadata.js';
|
||||||
@ -10,3 +11,4 @@ import './queryStudies.js';
|
|||||||
import './retrieveStudyMetadata.js';
|
import './retrieveStudyMetadata.js';
|
||||||
import './studylist.js';
|
import './studylist.js';
|
||||||
import './switchToTab.js';
|
import './switchToTab.js';
|
||||||
|
import './viewSeriesDetails.js';
|
||||||
|
|||||||
10
Packages/ohif-study-list/client/lib/viewSeriesDetails.js
Normal file
10
Packages/ohif-study-list/client/lib/viewSeriesDetails.js
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import { OHIF } from 'meteor/ohif:core';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display series details of study in a modal
|
||||||
|
*/
|
||||||
|
OHIF.studylist.viewSeriesDetails = () => {
|
||||||
|
const selectedStudies = OHIF.studylist.getSelectedStudies();
|
||||||
|
if (!selectedStudies) return;
|
||||||
|
OHIF.ui.showDialog('seriesDetailsModal', { selectedStudies });
|
||||||
|
};
|
||||||
Loading…
Reference in New Issue
Block a user