255 lines
7.8 KiB
JavaScript
255 lines
7.8 KiB
JavaScript
import { OHIF } from 'meteor/ohif:core';
|
|
import { Template } from 'meteor/templating';
|
|
import { Blaze } from 'meteor/blaze';
|
|
import { ReactiveVar } from 'meteor/reactive-var';
|
|
import { _ } from 'meteor/underscore';
|
|
import { $ } from 'meteor/jquery';
|
|
|
|
Template.measureFlow.onCreated(() => {
|
|
const instance = Template.instance();
|
|
|
|
instance.state = new ReactiveVar('closed');
|
|
instance.description = new ReactiveVar('');
|
|
instance.descriptionEdit = new ReactiveVar(false);
|
|
|
|
instance.items = [{
|
|
label: 'Category 1',
|
|
value: 'Category 1',
|
|
items: [{
|
|
label: 'Subcategory 1.1',
|
|
value: 'Subcategory 1.1'
|
|
}, {
|
|
label: 'Subcategory 1.2',
|
|
value: 'Subcategory 1.2',
|
|
items: [{
|
|
label: 'Subcategory 1.2.1',
|
|
value: 'Subcategory 1.2.1'
|
|
}, {
|
|
label: 'Subcategory 1.2.2',
|
|
value: 'Subcategory 1.2.2',
|
|
items: [{
|
|
label: 'Subcategory 1.2.2.1',
|
|
value: 'Subcategory 1.2.2.1'
|
|
}, {
|
|
label: 'Subcategory 1.2.2.2',
|
|
value: 'Subcategory 1.2.2.2'
|
|
}]
|
|
}]
|
|
}]
|
|
}, {
|
|
label: 'Category 2',
|
|
value: 'Category 2',
|
|
items: [{
|
|
label: 'Subcategory 2.1',
|
|
value: 'Subcategory 2.1'
|
|
}, {
|
|
label: 'Subcategory 2.2',
|
|
value: 'Subcategory 2.2'
|
|
}, {
|
|
label: 'Subcategory 2.3',
|
|
value: 'Subcategory 2.3'
|
|
}]
|
|
}, {
|
|
label: 'Category 3',
|
|
value: 'Category 3'
|
|
}];
|
|
|
|
const items = [
|
|
'Abdomen/Chest Wall',
|
|
'Adrenal',
|
|
'Bladder',
|
|
'Bone',
|
|
'Brain',
|
|
'Breast',
|
|
'Colon',
|
|
'Esophagus',
|
|
'Extremities',
|
|
'Gallbladder',
|
|
'Kidney',
|
|
'Liver',
|
|
'Lung',
|
|
'Lymph Node',
|
|
'Mediastinum/Hilum',
|
|
'Muscle',
|
|
'Neck',
|
|
'Other Soft Tissue',
|
|
'Ovary',
|
|
'Pancreas',
|
|
'Pelvis',
|
|
'Peritoneum/Omentum',
|
|
'Prostate',
|
|
'Retroperitoneum',
|
|
'Small Bowel',
|
|
'Spleen',
|
|
'Stomach',
|
|
'Subcutaneous'
|
|
];
|
|
|
|
instance.items = [];
|
|
_.each(items, item => {
|
|
instance.items.push({
|
|
label: item,
|
|
value: item
|
|
});
|
|
});
|
|
|
|
const commonItems = [
|
|
'Abdomen/Chest Wall',
|
|
'Lung',
|
|
'Lymph Node',
|
|
'Liver',
|
|
'Mediastinum/Hilum',
|
|
'Pelvis',
|
|
'Peritoneum/Omentum',
|
|
'Retroperitoneum'
|
|
];
|
|
|
|
instance.commonItems = [];
|
|
_.each(commonItems, item => {
|
|
instance.commonItems.push({
|
|
label: item,
|
|
value: item
|
|
});
|
|
});
|
|
});
|
|
|
|
Template.measureFlow.onRendered(() => {
|
|
const instance = Template.instance();
|
|
|
|
// Make the measure flow bounded by the window borders
|
|
instance.$('.measure-flow').bounded();
|
|
});
|
|
|
|
Template.measureFlow.events({
|
|
'click .measure-flow .btn-add, click .measure-flow .btn-rename'(event, instance) {
|
|
// Set the open state for the component
|
|
instance.state.set('open');
|
|
|
|
// Wait template rerender before rendering the selectTree
|
|
Tracker.afterFlush(() => {
|
|
// Get the click position
|
|
const position = {
|
|
left: event.clientX,
|
|
top: event.clientY,
|
|
};
|
|
|
|
// Define the data for selectTreeComponent
|
|
const data = {
|
|
key: 'label',
|
|
items: instance.items,
|
|
commonItems: instance.commonItems,
|
|
hideCommon: instance.data.hideCommon,
|
|
label: 'Assign label',
|
|
searchPlaceholder: 'Search labels',
|
|
storageKey: 'measureLabelCommon',
|
|
treeColumns: instance.data.treeColumns,
|
|
position
|
|
};
|
|
|
|
// Define in which element the selectTree will be rendered in
|
|
const parentElement = instance.$('.measure-flow')[0];
|
|
|
|
// Render the selectTree element
|
|
instance.selectTreeView = Blaze.renderWithData(Template.selectTree, data, parentElement);
|
|
});
|
|
},
|
|
|
|
'click .measure-flow .btn-description'(event, instance) {
|
|
// Fade out the action buttons
|
|
instance.$('.measure-flow .actions').addClass('fadeOut');
|
|
|
|
// Set the description edit mode
|
|
instance.descriptionEdit.set(true);
|
|
|
|
// Wait for DOM re-rendering, resize and focus the description textarea
|
|
Tracker.afterFlush(() => {
|
|
const $textarea = instance.$('textarea');
|
|
$textarea.trigger('input').focus();
|
|
});
|
|
},
|
|
|
|
'input textarea, change textarea'(event, instance) {
|
|
const element = event.currentTarget;
|
|
const $element = $(element);
|
|
|
|
// Resize the textarea based on its content length
|
|
$element.css('max-height', 0);
|
|
$element.height(element.scrollHeight);
|
|
$element.css('max-height', '');
|
|
|
|
// Reposition the measure flow if needed
|
|
const $measureFlow = instance.$('.measure-flow');
|
|
$element.one('transitionend', () => $measureFlow.trigger('spatialChanged'));
|
|
},
|
|
|
|
'keydown textarea'(event, instance) {
|
|
// Unset the description edit mode if ENTER or ESC was pressed
|
|
if (event.which === 13 || event.which === 27) {
|
|
instance.$('.measure-flow .actions').removeClass('fadeOut');
|
|
instance.descriptionEdit.set(false);
|
|
}
|
|
|
|
// Keep the current description if ENTER was pressed
|
|
if (event.which === 13) {
|
|
instance.description.set($(event.currentTarget).val());
|
|
}
|
|
},
|
|
|
|
'click .select-tree-common label'(event, instance) {
|
|
// Set the common section clicked flag
|
|
instance.commonClicked = true;
|
|
},
|
|
|
|
'change .select-tree-root'(event, instance) {
|
|
// Stop here if it's an inner input event
|
|
if (event.target !== event.currentTarget) {
|
|
return;
|
|
}
|
|
|
|
// Store the selectTree component value before it's removed from DOM
|
|
const $treeRoot = $(event.currentTarget);
|
|
instance.value = $treeRoot.data('component').value();
|
|
},
|
|
|
|
'click .tree-leaf input'(event, instance) {
|
|
const $target = $(event.currentTarget);
|
|
const $label = $target.closest('label');
|
|
const $treeRoot = $label.closest('.select-tree-root');
|
|
const $container = $treeRoot.find('.tree-options:first');
|
|
|
|
// Check if the targe click was a label inside common section
|
|
if (instance.commonClicked) {
|
|
const labelTop = $label.position().top;
|
|
const containerCenter = Math.round($container.height() / 2);
|
|
const labelCenter = Math.round($label.height() / 2);
|
|
|
|
// Scroll the options container to make the target input visible
|
|
$container.scrollTop(labelTop - containerCenter + labelCenter);
|
|
}
|
|
|
|
// Change the measure flow state to selected
|
|
instance.state.set('selected');
|
|
|
|
// Get the clicked label window offset
|
|
const labelOffset = $label.offset();
|
|
|
|
// Wait for the DOM re-rendering
|
|
Tracker.afterFlush(() => {
|
|
// Get the measure flow div
|
|
const $measureFlow = instance.$('.measure-flow');
|
|
|
|
// Subtract the label box shadow height from the label's position
|
|
labelOffset.top -= 10;
|
|
|
|
// Reposition the measure flow based on the clicked label position
|
|
$measureFlow.css(labelOffset);
|
|
|
|
// Resize the copied label with same width of the clicked one
|
|
$measureFlow.children('.tree-leaf').width($label.outerWidth());
|
|
});
|
|
|
|
// Wait the fade-out transition and remove the selectTree component
|
|
$container.one('transitionend', event => Blaze.remove(instance.selectTreeView));
|
|
}
|
|
});
|