Updated lesion dialog to use collections
This commit is contained in:
parent
1d0ae73611
commit
9ce3e5ed86
@ -3,6 +3,7 @@ Meteor.startup(function() {
|
|||||||
mouse: cornerstoneTools.lesion,
|
mouse: cornerstoneTools.lesion,
|
||||||
touch: cornerstoneTools.lesionTouch
|
touch: cornerstoneTools.lesionTouch
|
||||||
});
|
});
|
||||||
|
|
||||||
toolManager.addTool('nonTarget', {
|
toolManager.addTool('nonTarget', {
|
||||||
mouse: cornerstoneTools.nonTarget,
|
mouse: cornerstoneTools.nonTarget,
|
||||||
touch: cornerstoneTools.nonTargetTouch
|
touch: cornerstoneTools.nonTargetTouch
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
<template name="viewer">
|
<template name="viewer">
|
||||||
<div id="viewer">
|
<div id="viewer">
|
||||||
{{ >lesionDialog }}
|
{{ >lesionLocationDialog }}
|
||||||
{{ >nonTargetLesionDialog}}
|
{{ >nonTargetLesionDialog}}
|
||||||
|
|
||||||
{{ >hidingPanel }}
|
{{ >hidingPanel }}
|
||||||
|
|||||||
@ -8,41 +8,70 @@ var cornerstoneTools = (function($, cornerstone, cornerstoneMath, cornerstoneToo
|
|||||||
cornerstoneTools = {};
|
cornerstoneTools = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var configuration = {
|
||||||
|
getLesionLocationCallback: getLesionLocationCallback,
|
||||||
|
changeLesionLocationCallback: changeLesionLocationCallback,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Define a callback to get your text annotation
|
||||||
|
// This could be used, e.g. to open a modal
|
||||||
|
function getLesionLocationCallback(measurementData, eventData, doneCallback) {
|
||||||
|
doneCallback(prompt('Enter your lesion location:'));
|
||||||
|
}
|
||||||
|
|
||||||
|
function changeLesionLocationCallback(measurementData, eventData, doneCallback) {
|
||||||
|
doneCallback(prompt('Change your lesion location:'));
|
||||||
|
}
|
||||||
|
|
||||||
var toolType = "lesion";
|
var toolType = "lesion";
|
||||||
|
|
||||||
///////// BEGIN ACTIVE TOOL ///////
|
///////// BEGIN ACTIVE TOOL ///////
|
||||||
function createNewMeasurement(mouseEventData) {
|
|
||||||
|
function addNewMeasurement(mouseEventData) {
|
||||||
var element = mouseEventData.element;
|
var element = mouseEventData.element;
|
||||||
timepointID = $(element).data('timepointID');
|
|
||||||
var lesionNumber = measurementManagerDAL.getNewLesionNumber(timepointID, true);
|
|
||||||
var lesionCounter = "";
|
|
||||||
|
|
||||||
|
function doneCallback(lesionNumber) {
|
||||||
|
measurementData.lesionName = "Target " + lesionNumber;
|
||||||
|
measurementData.lesionNumber = lesionNumber;
|
||||||
|
measurementData.active = false;
|
||||||
|
cornerstone.updateImage(element);
|
||||||
|
}
|
||||||
|
|
||||||
// ** This stuff should not be done here! We should do this inside addNewMeasurement!** //
|
var measurementData = createNewMeasurement(mouseEventData);
|
||||||
|
|
||||||
// Subscribe CornerstoneMouseup event, when mouse is up, call lesionDialog
|
var eventData = {
|
||||||
$(element).on("CornerstoneToolsMouseUp", function(e) {
|
mouseButtonMask: mouseEventData.which,
|
||||||
|
};
|
||||||
|
|
||||||
|
// associate this data with this imageId so we can render it and manipulate it
|
||||||
|
cornerstoneTools.addToolState(element, toolType, measurementData);
|
||||||
|
|
||||||
|
// since we are dragging to another place to drop the end point, we can just activate
|
||||||
|
// the end point and let the moveHandle move it for us.
|
||||||
|
$(element).off('CornerstoneToolsMouseMove', cornerstoneTools.lesion.mouseMoveCallback);
|
||||||
|
$(element).off('CornerstoneToolsMouseDown', cornerstoneTools.lesion.mouseDownCallback);
|
||||||
|
$(element).off('CornerstoneToolsMouseDownActivate', cornerstoneTools.lesion.mouseDownActivateCallback);
|
||||||
|
|
||||||
// Unsubscribe CornerstoneToolsMouseUp event
|
cornerstone.updateImage(element);
|
||||||
$(element).off("CornerstoneToolsMouseUp");
|
cornerstoneTools.moveNewHandle(mouseEventData, measurementData.handles.end, function() {
|
||||||
|
if (cornerstoneTools.anyHandlesOutsideImage(mouseEventData, measurementData.handles)) {
|
||||||
|
// delete the measurement
|
||||||
|
cornerstoneTools.removeToolState(element, toolType, measurementData);
|
||||||
|
} else {
|
||||||
|
// Set lesionMeasurementData Session
|
||||||
|
var config = cornerstoneTools.lesion.getConfiguration();
|
||||||
|
config.getLesionLocationCallback(measurementData, mouseEventData, doneCallback);
|
||||||
|
}
|
||||||
|
|
||||||
// Set lesionMeasurementData Session
|
$(element).on('CornerstoneToolsMouseMove', eventData, cornerstoneTools.lesion.mouseMoveCallback);
|
||||||
activeLesionMeasurementData.timepointID = timepointID;
|
$(element).on('CornerstoneToolsMouseDown', eventData, cornerstoneTools.lesion.mouseDownCallback);
|
||||||
Session.set("lesionMeasurementData", activeLesionMeasurementData);
|
$(element).on('CornerstoneToolsMouseDownActivate', eventData, cornerstoneTools.lesion.mouseDownActivateCallback);
|
||||||
|
cornerstone.updateImage(element);
|
||||||
// Show LesionDialog
|
|
||||||
$(document).trigger("ShowLesionDialog", [e, activeLesionMeasurementData]);
|
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Set Lesion Name
|
function createNewMeasurement(mouseEventData) {
|
||||||
$(element).on("LesionNameSet", function(e, lesionName) {
|
// Create the measurement data for this tool with the end handle activated
|
||||||
lesionCounter = lesionName;
|
|
||||||
});
|
|
||||||
|
|
||||||
// Subscribe LesionMeasurementCreated
|
|
||||||
$(element).trigger("LesionMeasurementCreated");
|
|
||||||
|
|
||||||
// create the measurement data for this tool with the end handle activated
|
|
||||||
var measurementData = {
|
var measurementData = {
|
||||||
visible: true,
|
visible: true,
|
||||||
active: true,
|
active: true,
|
||||||
@ -70,9 +99,8 @@ var cornerstoneTools = (function($, cornerstone, cornerstoneMath, cornerstoneToo
|
|||||||
},
|
},
|
||||||
imageId: mouseEventData.image.imageId,
|
imageId: mouseEventData.image.imageId,
|
||||||
measurementText: 0,
|
measurementText: 0,
|
||||||
lesionName: "Target " + lesionNumber,
|
lesionName: '',
|
||||||
isDeleted: false,
|
isDeleted: false,
|
||||||
lesionNumber: lesionNumber,
|
|
||||||
isTarget: true,
|
isTarget: true,
|
||||||
uid: uuid.v4()
|
uid: uuid.v4()
|
||||||
};
|
};
|
||||||
@ -136,15 +164,15 @@ var cornerstoneTools = (function($, cornerstone, cornerstoneMath, cornerstoneToo
|
|||||||
}
|
}
|
||||||
|
|
||||||
function updateLesionCollection(lesionData) {
|
function updateLesionCollection(lesionData) {
|
||||||
|
if (!lesionData.active) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (lesionData.active) {
|
if (lesionData.timepointID && lesionData.timepointID !== "") {
|
||||||
if (lesionData.timepointID !== undefined && lesionData.timepointID !== "") {
|
// Update Measurements Collection
|
||||||
// Update Measurements Collection
|
measurementManagerDAL.updateTimepointData(lesionData);
|
||||||
measurementManagerDAL.updateTimepointData(lesionData);
|
} else {
|
||||||
|
activeLesionMeasurementData = lesionData;
|
||||||
} else {
|
|
||||||
activeLesionMeasurementData = lesionData;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -230,63 +258,62 @@ var cornerstoneTools = (function($, cornerstone, cornerstoneMath, cornerstoneToo
|
|||||||
///////// END IMAGE RENDERING ///////
|
///////// END IMAGE RENDERING ///////
|
||||||
|
|
||||||
function updateLesion(e, eventData) {
|
function updateLesion(e, eventData) {
|
||||||
var start = new Date();
|
|
||||||
|
|
||||||
var enabledElement = eventData.enabledElement;
|
var enabledElement = eventData.enabledElement;
|
||||||
|
var element = eventData.enabledElement.element;
|
||||||
var isTarget = eventData.lesionData.isTarget;
|
var isTarget = eventData.lesionData.isTarget;
|
||||||
var lesionNumber = eventData.lesionData.lesionNumber;
|
var lesionNumber = eventData.lesionData.lesionNumber;
|
||||||
var type = eventData.type;
|
var type = eventData.type;
|
||||||
|
|
||||||
// if we have no toolData for this element, return immediately as there is nothing to do
|
// if we have no toolData for this element, return immediately as there is nothing to do
|
||||||
var toolData = cornerstoneTools.getToolState(e.currentTarget, toolType);
|
var toolData = cornerstoneTools.getToolState(e.currentTarget, toolType);
|
||||||
if (toolData === undefined) {
|
if (!toolData) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var data,
|
var data,
|
||||||
i;
|
i;
|
||||||
|
|
||||||
//If type is delete, remove measurement
|
switch (type) {
|
||||||
if (type === "delete") {
|
case "delete":
|
||||||
var deletedDataIndex = -1;
|
//If type is delete, remove measurement
|
||||||
|
var deletedDataIndex = -1;
|
||||||
|
|
||||||
for (i = 0; i < toolData.data.length; i++) {
|
for (i = 0; i < toolData.data.length; i++) {
|
||||||
data = toolData.data[i];
|
data = toolData.data[i];
|
||||||
|
|
||||||
//When click a row of table measurements, measurement will be active and color will be green
|
//When click a row of table measurements, measurement will be active and color will be green
|
||||||
if (data.lesionNumber === eventData.lesionNumber && eventData.type !== "active" && isTarget) {
|
if (data.lesionNumber === lesionNumber && eventData.type !== "active" && isTarget) {
|
||||||
data.visible = false;
|
data.visible = false;
|
||||||
deletedDataIndex = i;
|
deletedDataIndex = i;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (deletedDataIndex >= 0 && deletedDataIndex < toolData.data.length) {
|
if (deletedDataIndex >= 0 && deletedDataIndex < toolData.data.length) {
|
||||||
toolData.data.splice(deletedDataIndex, 1);
|
toolData.data.splice(deletedDataIndex, 1);
|
||||||
}
|
}
|
||||||
} else if (type === "active") {
|
break;
|
||||||
for (i = 0; i < toolData.data.length; i++) {
|
|
||||||
data = toolData.data[i];
|
case "active":
|
||||||
//When click a row of table measurements, measurement will be active and color will be green
|
for (i = 0; i < toolData.data.length; i++) {
|
||||||
if (data.lesionNumber === eventData.lesionData.lesionNumber && eventData.type === "active" && isTarget) {
|
data = toolData.data[i];
|
||||||
data.active = true;
|
//When click a row of table measurements, measurement will be active and color will be green
|
||||||
} else {
|
if (data.lesionNumber === lesionNumber && eventData.type === "active" && isTarget) {
|
||||||
|
data.active = true;
|
||||||
|
} else {
|
||||||
|
data.active = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "inactive":
|
||||||
|
for (i = 0; i < toolData.data.length; i++) {
|
||||||
|
data = toolData.data[i];
|
||||||
|
// Make inactive all lesions for the timepoint
|
||||||
data.active = false;
|
data.active = false;
|
||||||
}
|
}
|
||||||
}
|
break;
|
||||||
} else if (type === "inactive") {
|
|
||||||
for (i = 0; i < toolData.data.length; i++) {
|
|
||||||
data = toolData.data[i];
|
|
||||||
// Make inactive all lesions for the timepoint
|
|
||||||
data.active = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var context = enabledElement.canvas.getContext('2d');
|
|
||||||
|
|
||||||
var end = new Date();
|
|
||||||
var diff = end - start;
|
|
||||||
//console.log(diff + ' ms');
|
|
||||||
|
|
||||||
cornerstone.updateImage(element);
|
cornerstone.updateImage(element);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -298,19 +325,19 @@ var cornerstoneTools = (function($, cornerstone, cornerstoneMath, cornerstoneToo
|
|||||||
if (eventData.type === "active") {
|
if (eventData.type === "active") {
|
||||||
var stackToolDataSource = cornerstoneTools.getToolState(e.currentTarget, 'stack');
|
var stackToolDataSource = cornerstoneTools.getToolState(e.currentTarget, 'stack');
|
||||||
var stackData = stackToolDataSource.data[0];
|
var stackData = stackToolDataSource.data[0];
|
||||||
var imageIdsArr = stackData.imageIds;
|
var imageIds = stackData.imageIds;
|
||||||
var indexOfImage = imageIdsArr.indexOf(eventData.lesionData.imageId);
|
var imageIdIndex = imageIds.indexOf(eventData.lesionData.imageId);
|
||||||
if (indexOfImage > -1) {
|
if (imageIdIndex < 0) {
|
||||||
cornerstone.loadAndCacheImage(stackData.imageIds[indexOfImage]).then(function(image) {
|
return;
|
||||||
cornerstone.displayImage(eventData.enabledElement.element, image);
|
|
||||||
updateLesion(e, eventData);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cornerstone.loadAndCacheImage(imageIds[imageIdIndex]).then(function(image) {
|
||||||
|
cornerstone.displayImage(eventData.enabledElement.element, image);
|
||||||
|
updateLesion(e, eventData);
|
||||||
|
});
|
||||||
} else if (eventData.type === "inactive") {
|
} else if (eventData.type === "inactive") {
|
||||||
updateLesion(e, eventData);
|
updateLesion(e, eventData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//This function is called from cornerstone-viewport.html and updates lesion measurement and makes the lesion active
|
//This function is called from cornerstone-viewport.html and updates lesion measurement and makes the lesion active
|
||||||
@ -321,6 +348,7 @@ var cornerstoneTools = (function($, cornerstone, cornerstoneMath, cornerstoneToo
|
|||||||
// module exports
|
// module exports
|
||||||
cornerstoneTools.lesion = cornerstoneTools.mouseButtonTool({
|
cornerstoneTools.lesion = cornerstoneTools.mouseButtonTool({
|
||||||
createNewMeasurement: createNewMeasurement,
|
createNewMeasurement: createNewMeasurement,
|
||||||
|
addNewMeasurement: addNewMeasurement,
|
||||||
onImageRendered: onImageRendered,
|
onImageRendered: onImageRendered,
|
||||||
pointNearTool: pointNearTool,
|
pointNearTool: pointNearTool,
|
||||||
toolType: toolType
|
toolType: toolType
|
||||||
@ -328,10 +356,14 @@ var cornerstoneTools = (function($, cornerstone, cornerstoneMath, cornerstoneToo
|
|||||||
|
|
||||||
cornerstoneTools.lesionTouch = cornerstoneTools.touchTool({
|
cornerstoneTools.lesionTouch = cornerstoneTools.touchTool({
|
||||||
createNewMeasurement: createNewMeasurement,
|
createNewMeasurement: createNewMeasurement,
|
||||||
|
//addNewMeasurement: addNewMeasurementTouch,
|
||||||
onImageRendered: onImageRendered,
|
onImageRendered: onImageRendered,
|
||||||
pointNearTool: pointNearTool,
|
pointNearTool: pointNearTool,
|
||||||
toolType: toolType
|
toolType: toolType
|
||||||
});
|
});
|
||||||
|
|
||||||
|
cornerstoneTools.lesion.setConfiguration(configuration);
|
||||||
|
|
||||||
return cornerstoneTools;
|
return cornerstoneTools;
|
||||||
|
|
||||||
}($, cornerstone, cornerstoneMath, cornerstoneTools));
|
}($, cornerstone, cornerstoneMath, cornerstoneTools));
|
||||||
@ -1,30 +1,9 @@
|
|||||||
var measurementManagerDAL = (function() {
|
var measurementManagerDAL = (function() {
|
||||||
var trialPatientLocations = [];
|
PatientLocations = new Meteor.Collection(null);
|
||||||
|
|
||||||
// Returns trialPatientLocations array
|
function getLocationName(id) {
|
||||||
function getPatientLocations() {
|
var locationObject = PatientLocations.findOne(id);
|
||||||
return trialPatientLocations;
|
return locationObject.location || "";
|
||||||
}
|
|
||||||
|
|
||||||
function getLocationName(locationUID) {
|
|
||||||
for (var i = 0; i < trialPatientLocations.length; i++) {
|
|
||||||
var locationObject = trialPatientLocations[i];
|
|
||||||
if (locationObject.uid === locationUID) {
|
|
||||||
return locationObject.location.location;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Adds new location to trialPatientLocations array
|
|
||||||
function addPatientLocation(location) {
|
|
||||||
var locationUID = uuid.v4();
|
|
||||||
var locationObject = {
|
|
||||||
uid: locationUID,
|
|
||||||
location: location
|
|
||||||
};
|
|
||||||
trialPatientLocations.push(locationObject);
|
|
||||||
return locationUID;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add timepoint data to Measurements collection
|
// Add timepoint data to Measurements collection
|
||||||
@ -57,7 +36,7 @@ var measurementManagerDAL = (function() {
|
|||||||
lesionUID: uuid.v4(),
|
lesionUID: uuid.v4(),
|
||||||
number: Measurements.find().count() + 1,
|
number: Measurements.find().count() + 1,
|
||||||
lesionNumber: lesionData.lesionNumber,
|
lesionNumber: lesionData.lesionNumber,
|
||||||
isTarget: typeof lesionData.isTarget !== 'undefined'?lesionData.isTarget:true,
|
isTarget: lesionData.isTarget,
|
||||||
locationUID: lesionData.locationUID,
|
locationUID: lesionData.locationUID,
|
||||||
location: getLocationName(lesionData.locationUID),
|
location: getLocationName(lesionData.locationUID),
|
||||||
timepoints: timepointsObject
|
timepoints: timepointsObject
|
||||||
@ -67,9 +46,6 @@ var measurementManagerDAL = (function() {
|
|||||||
|
|
||||||
// Update timepoint data in Measurements collection
|
// Update timepoint data in Measurements collection
|
||||||
function updateTimepointData(lesionData) {
|
function updateTimepointData(lesionData) {
|
||||||
if(typeof lesionData.isTarget === 'undefined') {
|
|
||||||
lesionData.isTarget = true;
|
|
||||||
}
|
|
||||||
// Find the specific lesion to be updated
|
// Find the specific lesion to be updated
|
||||||
var measurement = Measurements.find({
|
var measurement = Measurements.find({
|
||||||
lesionNumber: lesionData.lesionNumber,
|
lesionNumber: lesionData.lesionNumber,
|
||||||
@ -100,10 +76,10 @@ var measurementManagerDAL = (function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check timepointData is found in Measurements collection
|
// Check timepointData is found in Measurements collection
|
||||||
function timepointDataIsFound(lesionData) {
|
function hasTimepointData(lesionData) {
|
||||||
var timepointData = Measurements.findOne({
|
var timepointData = Measurements.findOne({
|
||||||
lesionNumber: lesionData.lesionNumber,
|
lesionNumber: lesionData.lesionNumber,
|
||||||
isTarget: typeof lesionData.isTarget!== 'undefined'?lesionData.isTarget:true
|
isTarget: lesionData.isTarget
|
||||||
});
|
});
|
||||||
if (timepointData) {
|
if (timepointData) {
|
||||||
return true;
|
return true;
|
||||||
@ -113,7 +89,7 @@ var measurementManagerDAL = (function() {
|
|||||||
|
|
||||||
// Adds new timepoint item to tiemepoints array
|
// Adds new timepoint item to tiemepoints array
|
||||||
function addLesionData(lesionData) {
|
function addLesionData(lesionData) {
|
||||||
if (timepointDataIsFound(lesionData)) {
|
if (hasTimepointData(lesionData)) {
|
||||||
// Update data
|
// Update data
|
||||||
updateTimepointData(lesionData);
|
updateTimepointData(lesionData);
|
||||||
} else {
|
} else {
|
||||||
@ -124,10 +100,6 @@ var measurementManagerDAL = (function() {
|
|||||||
|
|
||||||
// Returns new lesion number according to timepointID
|
// Returns new lesion number according to timepointID
|
||||||
function getNewLesionNumber(timepointID, isTarget) {
|
function getNewLesionNumber(timepointID, isTarget) {
|
||||||
|
|
||||||
if (typeof isTarget === 'undefined') {
|
|
||||||
isTarget = true;
|
|
||||||
}
|
|
||||||
// Get all current lesion measurements
|
// Get all current lesion measurements
|
||||||
var measurements = Measurements.find({isTarget: isTarget}).fetch();
|
var measurements = Measurements.find({isTarget: isTarget}).fetch();
|
||||||
|
|
||||||
@ -153,14 +125,11 @@ var measurementManagerDAL = (function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If lesion number is added for any timepoint, returns lesion locationUID
|
// If lesion number is added for any timepoint, returns lesion locationUID
|
||||||
function isLesionNumberAdded(lesionData) {
|
function lesionNumberExists(lesionData) {
|
||||||
if (!timepointDataIsFound(lesionData)) {
|
if (!hasTimepointData(lesionData)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(typeof isTarget === undefined) {
|
|
||||||
isTarget = true;
|
|
||||||
}
|
|
||||||
var measurement = Measurements.find({
|
var measurement = Measurements.find({
|
||||||
lesionNumber: lesionData.lesionNumber,
|
lesionNumber: lesionData.lesionNumber,
|
||||||
isTarget: lesionData.isTarget
|
isTarget: lesionData.isTarget
|
||||||
@ -169,13 +138,10 @@ var measurementManagerDAL = (function() {
|
|||||||
return measurement.locationUID;
|
return measurement.locationUID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
addNewLocation: addPatientLocation,
|
|
||||||
getLocations: getPatientLocations,
|
|
||||||
addLesionData: addLesionData,
|
addLesionData: addLesionData,
|
||||||
getNewLesionNumber: getNewLesionNumber,
|
getNewLesionNumber: getNewLesionNumber,
|
||||||
isLesionNumberAdded: isLesionNumberAdded,
|
lesionNumberExists: lesionNumberExists,
|
||||||
updateTimepointData: updateTimepointData,
|
updateTimepointData: updateTimepointData,
|
||||||
getLocationName: getLocationName
|
getLocationName: getLocationName
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
// Begin Source: src/imageTools/annotation.js
|
|
||||||
(function($, cornerstone, cornerstoneMath, cornerstoneTools) {
|
(function($, cornerstone, cornerstoneMath, cornerstoneTools) {
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
@ -8,14 +7,13 @@
|
|||||||
// Define a callback to get your text annotation
|
// Define a callback to get your text annotation
|
||||||
// This could be used, e.g. to open a modal
|
// This could be used, e.g. to open a modal
|
||||||
function getTextCallback(doneChangingTextCallback) {
|
function getTextCallback(doneChangingTextCallback) {
|
||||||
doneChangingTextCallback(prompt('Enter your annotation:'));
|
doneChangingTextCallback(prompt('Add a non-target lesion name:'));
|
||||||
}
|
}
|
||||||
|
|
||||||
function changeTextCallback(data, doneChangingTextCallback) {
|
function changeTextCallback(data, doneChangingTextCallback) {
|
||||||
doneChangingTextCallback(prompt('Change your annotation:'));
|
doneChangingTextCallback(prompt('Change your annotation:'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
var configuration = {
|
var configuration = {
|
||||||
getTextCallback: getTextCallback,
|
getTextCallback: getTextCallback,
|
||||||
changeTextCallback: changeTextCallback,
|
changeTextCallback: changeTextCallback,
|
||||||
@ -141,16 +139,6 @@
|
|||||||
return (distanceToPoint < 25);
|
return (distanceToPoint < 25);
|
||||||
}
|
}
|
||||||
|
|
||||||
function pointNearToolForText(element, data, coords) {
|
|
||||||
var lineSegment = {
|
|
||||||
start: cornerstone.pixelToCanvas(element, data.linkedTextCoords.start),
|
|
||||||
end: cornerstone.pixelToCanvas(element, data.linkedTextCoords.end)
|
|
||||||
};
|
|
||||||
|
|
||||||
var distanceToPoint = cornerstoneMath.lineSegment.distanceToPoint(lineSegment, coords);
|
|
||||||
return (distanceToPoint < 30);
|
|
||||||
}
|
|
||||||
|
|
||||||
function drawArrow(context, start, end, color, lineWidth) {
|
function drawArrow(context, start, end, color, lineWidth) {
|
||||||
//variables to be used when creating the arrow
|
//variables to be used when creating the arrow
|
||||||
var headLength = 10;
|
var headLength = 10;
|
||||||
@ -185,7 +173,7 @@
|
|||||||
context.fill();
|
context.fill();
|
||||||
}
|
}
|
||||||
|
|
||||||
function suscribeNonTargetToolModifiedEvent(element) {
|
function subcribeNonTargetToolModifiedEvent(element) {
|
||||||
var elementEvents = $._data(element, "events");
|
var elementEvents = $._data(element, "events");
|
||||||
var index = Object.keys(elementEvents).indexOf("NonTargetToolSelected");
|
var index = Object.keys(elementEvents).indexOf("NonTargetToolSelected");
|
||||||
if (index < 0) {
|
if (index < 0) {
|
||||||
@ -197,7 +185,7 @@
|
|||||||
///////// BEGIN IMAGE RENDERING ///////
|
///////// BEGIN IMAGE RENDERING ///////
|
||||||
function onImageRendered(e, eventData) {
|
function onImageRendered(e, eventData) {
|
||||||
|
|
||||||
suscribeNonTargetToolModifiedEvent(e.currentTarget);
|
subcribeNonTargetToolModifiedEvent(e.currentTarget);
|
||||||
|
|
||||||
// if we have no toolData for this element, return immediately as there is nothing to do
|
// if we have no toolData for this element, return immediately as there is nothing to do
|
||||||
var toolData = cornerstoneTools.getToolState(e.currentTarget, toolType);
|
var toolData = cornerstoneTools.getToolState(e.currentTarget, toolType);
|
||||||
@ -229,8 +217,8 @@
|
|||||||
// configurable shadow from CornerstoneTools
|
// configurable shadow from CornerstoneTools
|
||||||
if (config && config.shadow) {
|
if (config && config.shadow) {
|
||||||
context.shadowColor = '#000000';
|
context.shadowColor = '#000000';
|
||||||
context.shadowOffsetX = +1;
|
context.shadowOffsetX = 1;
|
||||||
context.shadowOffsetY = +1;
|
context.shadowOffsetY = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lesion.active) {
|
if (lesion.active) {
|
||||||
@ -303,49 +291,6 @@
|
|||||||
context.restore();
|
context.restore();
|
||||||
|
|
||||||
}
|
}
|
||||||
// ---- Touch tool ----
|
|
||||||
|
|
||||||
///////// BEGIN ACTIVE TOOL ///////
|
|
||||||
function addNewMeasurementTouch(touchEventData) {
|
|
||||||
var element = touchEventData.element;
|
|
||||||
|
|
||||||
function doneChangingTextCallback(text) {
|
|
||||||
if (text !== null) {
|
|
||||||
measurementData.text = text;
|
|
||||||
} else {
|
|
||||||
cornerstoneTools.removeToolState(element, toolType, measurementData);
|
|
||||||
}
|
|
||||||
|
|
||||||
measurementData.active = false;
|
|
||||||
cornerstone.updateImage(element);
|
|
||||||
}
|
|
||||||
|
|
||||||
var measurementData = createNewMeasurement(touchEventData);
|
|
||||||
cornerstoneTools.addToolState(element, toolType, measurementData);
|
|
||||||
$(element).off('CornerstoneToolsTouchDrag', cornerstoneTools.nonTargetTouch.touchMoveCallback);
|
|
||||||
$(element).off('CornerstoneToolsDragStartActive', cornerstoneTools.nonTargetTouch.touchDownActivateCallback);
|
|
||||||
$(element).off('CornerstoneToolsTap', cornerstoneTools.nonTargetTouch.tapCallback);
|
|
||||||
cornerstone.updateImage(element);
|
|
||||||
|
|
||||||
cornerstoneTools.moveNewHandleTouch(touchEventData, measurementData.handles.end, function() {
|
|
||||||
cornerstone.updateImage(element);
|
|
||||||
|
|
||||||
if (cornerstoneTools.anyHandlesOutsideImage(touchEventData, measurementData.handles)) {
|
|
||||||
// delete the measurement
|
|
||||||
cornerstoneTools.removeToolState(element, toolType, measurementData);
|
|
||||||
}
|
|
||||||
|
|
||||||
var config = cornerstoneTools.nonTarget.getConfiguration();
|
|
||||||
if (measurementData.text === undefined) {
|
|
||||||
config.getTextCallback(doneChangingTextCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
$(element).on('CornerstoneToolsTouchDrag', cornerstoneTools.nonTargetTouch.touchMoveCallback);
|
|
||||||
$(element).on('CornerstoneToolsDragStartActive', cornerstoneTools.nonTargetTouch.touchDownActivateCallback);
|
|
||||||
$(element).on('CornerstoneToolsTap', cornerstoneTools.nonTargetTouch.tapCallback);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function doubleClickCallback(e, eventData) {
|
function doubleClickCallback(e, eventData) {
|
||||||
var element = eventData.element;
|
var element = eventData.element;
|
||||||
@ -497,24 +442,10 @@
|
|||||||
createNewMeasurement: createNewMeasurement,
|
createNewMeasurement: createNewMeasurement,
|
||||||
onImageRendered: onImageRendered,
|
onImageRendered: onImageRendered,
|
||||||
pointNearTool: pointNearTool,
|
pointNearTool: pointNearTool,
|
||||||
pointNearToolForText: pointNearToolForText,
|
|
||||||
toolType: toolType,
|
toolType: toolType,
|
||||||
mouseDoubleClickCallback: doubleClickCallback
|
mouseDoubleClickCallback: doubleClickCallback
|
||||||
});
|
});
|
||||||
|
|
||||||
cornerstoneTools.nonTarget.setConfiguration(configuration);
|
cornerstoneTools.nonTarget.setConfiguration(configuration);
|
||||||
|
|
||||||
cornerstoneTools.nonTargetTouch = cornerstoneTools.touchTool({
|
})($, cornerstone, cornerstoneMath, cornerstoneTools);
|
||||||
addNewMeasurement: addNewMeasurementTouch,
|
|
||||||
createNewMeasurement: createNewMeasurement,
|
|
||||||
onImageRendered: onImageRendered,
|
|
||||||
pointNearTool: pointNearTool,
|
|
||||||
pointNearToolForText: pointNearToolForText,
|
|
||||||
toolType: toolType,
|
|
||||||
pressCallback: doubleClickCallback
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
})($, cornerstone, cornerstoneMath, cornerstoneTools);
|
|
||||||
|
|
||||||
// End Source; src/imageTools/annotation.js
|
|
||||||
@ -1,3 +0,0 @@
|
|||||||
<template name="lesionDialog">
|
|
||||||
{{> lesionLocationDialog}}
|
|
||||||
</template>
|
|
||||||
@ -1,24 +0,0 @@
|
|||||||
Template.lesionDialog.onRendered(function () {
|
|
||||||
// This event determines whether or not to show the lesion dialog
|
|
||||||
// If there already exists a lesion with this specific lesion number,
|
|
||||||
// related to the chosen location.
|
|
||||||
|
|
||||||
$(document).on("ShowLesionDialog", function (e, eventData, lesionData) {
|
|
||||||
var locationUID = measurementManagerDAL.isLesionNumberAdded(lesionData);
|
|
||||||
|
|
||||||
if (locationUID) {
|
|
||||||
lesionData.locationUID = locationUID;
|
|
||||||
measurementManagerDAL.updateTimepointData(lesionData);
|
|
||||||
} else {
|
|
||||||
// Show Dialog
|
|
||||||
var dialogPointsOnPage = eventData.currentPoints.page;
|
|
||||||
$("#modal-dialog-container").css({
|
|
||||||
"top": dialogPointsOnPage.y,
|
|
||||||
"left": dialogPointsOnPage.x
|
|
||||||
});
|
|
||||||
|
|
||||||
$("#lesionDialog").modal("show");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
@ -1,19 +1,17 @@
|
|||||||
<template name="lesionLocationDialog">
|
<template name="lesionLocationDialog">
|
||||||
<div class="modal fade" id="lesionDialog" style=" background-color: transparent;">
|
<div id="lesionLocationDialog">
|
||||||
<div id="modal-dialog-container" class="modal-dialog modal-sm" style="position: absolute; border: none; ">
|
<div class="dialogHeader">
|
||||||
<div class="modal-content" style="padding: 10px;">
|
<h4>Select Lesion Location</h4>
|
||||||
<div class="dialogHeader">
|
</div>
|
||||||
<div style="float:left;"><h4>Select Lesion Location</h4></div>
|
<div class="dialogContent">
|
||||||
<div style="float:right;"><button class="btn" id="btnCloseLesionPopup" style="outline: 0; border: none; background-color: transparent;"><i class="fa fa-close"></i></button></div>
|
<div class="lesionLocation">
|
||||||
</div>
|
<label>Lesion Location</label>
|
||||||
<div class="dialogContent" style="margin-bottom: 20px;">
|
<select id="selectLesionLocation">
|
||||||
<div class="lesionLocation">
|
<option value="-1"></option>
|
||||||
<label>Lesion Location</label>
|
{{ #each lesionLocations}}
|
||||||
<select id="selectLesionLocation" style="margin-top:5px;">
|
<option value='{{_id}}'>{{location}}</option>
|
||||||
<option value="-1"></option>
|
{{ /each}}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,90 +1,172 @@
|
|||||||
var lastAddedLesionData;
|
// This event determines whether or not to show the lesion dialog
|
||||||
|
// If there already exists a lesion with this specific lesion number,
|
||||||
|
// related to the chosen location.
|
||||||
|
function getLesionLocationCallback(measurementData, eventData, doneCallback) {
|
||||||
|
// Get the lesion location dialog
|
||||||
|
var lesionDialog = $("#lesionLocationDialog");
|
||||||
|
|
||||||
//fill selectLesionLocation element
|
// Find the select option box
|
||||||
var lesionLocationsArray = [{
|
var selector = lesionDialog.find("select#selectLesionLocation");
|
||||||
|
|
||||||
|
// Get the current element's timepointID
|
||||||
|
// TODO: Change this when we are no longer storing timepointID in the viewport element DOM data
|
||||||
|
measurementData.timepointID = $(eventData.element).data('timepointID');
|
||||||
|
|
||||||
|
// Get a lesion number for this lesion, depending on whether or not the same lesion previously
|
||||||
|
// exists at a different timepoint
|
||||||
|
var lesionNumber = measurementManagerDAL.getNewLesionNumber(measurementData.timepointID, isTarget=true);
|
||||||
|
measurementData.lesionNumber = lesionNumber;
|
||||||
|
|
||||||
|
// Find out if this lesion number is already added in the lesion manager for another timepoint
|
||||||
|
// If it is, stop here because we don't need the dialog.
|
||||||
|
var locationUID = measurementManagerDAL.lesionNumberExists(measurementData);
|
||||||
|
if (locationUID) {
|
||||||
|
measurementData.locationUID = locationUID;
|
||||||
|
measurementManagerDAL.updateTimepointData(measurementData);
|
||||||
|
closeHandler();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// If it isn't, continue to open the dialog and have the user choose a lesion location
|
||||||
|
|
||||||
|
// Attach close handler if the user clicks the close button
|
||||||
|
var close = lesionDialog.find("#btnCloseLesionPopup");
|
||||||
|
close.off('click');
|
||||||
|
close.on('click', function() {
|
||||||
|
closeHandler();
|
||||||
|
});
|
||||||
|
|
||||||
|
function closeHandler() {
|
||||||
|
// Hide the lesion dialog
|
||||||
|
lesionDialog.css('display', 'none');
|
||||||
|
|
||||||
|
// Fire the doneCallback with the lesion number
|
||||||
|
doneCallback(lesionNumber);
|
||||||
|
|
||||||
|
// Get the current value of the select option box
|
||||||
|
var currentValue = selector.find("option:selected").val();
|
||||||
|
|
||||||
|
// Select the first option for the next time the dialog is opened
|
||||||
|
selector.val(currentValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attach keypress handlers so the user can close with the Enter button
|
||||||
|
lesionDialog.off("keypress");
|
||||||
|
lesionDialog.on('keypress', keyPressHandler);
|
||||||
|
|
||||||
|
// This is the keypress callback function
|
||||||
|
function keyPressHandler(e) {
|
||||||
|
// If Enter is pressed, close the dialog
|
||||||
|
if (e.which === 13) {
|
||||||
|
closeHandler();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show the lesion location dialog above
|
||||||
|
lesionDialog.css({
|
||||||
|
top: eventData.currentPoints.page.y - lesionDialog.outerHeight() - 40,
|
||||||
|
left: eventData.currentPoints.page.x - lesionDialog.outerWidth() / 2,
|
||||||
|
display: 'block'
|
||||||
|
});
|
||||||
|
|
||||||
|
// Attach a callback for the select box
|
||||||
|
selector.off('change');
|
||||||
|
selector.on('change', function(e) {
|
||||||
|
// Get the current value of the selector
|
||||||
|
var selectedOptionId = this.value;
|
||||||
|
|
||||||
|
// If the selected option is still the default (-1)
|
||||||
|
// then stop here
|
||||||
|
if (selectedOptionId < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get selected location data
|
||||||
|
var locationObj = LesionLocations.findOne({_id: selectedOptionId});
|
||||||
|
|
||||||
|
|
||||||
|
var id;
|
||||||
|
var existingLocation = PatientLocations.findOne({location: locationObj.location});
|
||||||
|
if (existingLocation) {
|
||||||
|
id = existingLocation._id;
|
||||||
|
} else {
|
||||||
|
// Adds location data to PatientLocation and retrieve the location ID
|
||||||
|
id = PatientLocations.insert({location: locationObj.location});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Link locationUID with active lesion measurementData
|
||||||
|
measurementData.locationUID = id;
|
||||||
|
|
||||||
|
/// Set the isTarget value to true, since this is the target-lesion dialog callback
|
||||||
|
measurementData.isTarget = true;
|
||||||
|
|
||||||
|
// Adds lesion data to timepoints array
|
||||||
|
measurementManagerDAL.addLesionData(measurementData);
|
||||||
|
|
||||||
|
// Close the dialog
|
||||||
|
closeHandler();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function changeLesionLocationCallback(measurementData, eventData, doneCallback) {
|
||||||
|
doneCallback(prompt('Change your lesion location:'));
|
||||||
|
}
|
||||||
|
|
||||||
|
var config = {
|
||||||
|
getLesionLocationCallback: getLesionLocationCallback,
|
||||||
|
changeLesionLocationCallback: changeLesionLocationCallback
|
||||||
|
};
|
||||||
|
|
||||||
|
cornerstoneTools.lesion.setConfiguration(config);
|
||||||
|
|
||||||
|
|
||||||
|
LesionLocations = new Meteor.Collection(null);
|
||||||
|
|
||||||
|
LesionLocations.insert({
|
||||||
location: "Brain Brainstem",
|
location: "Brain Brainstem",
|
||||||
hasDescription: false,
|
hasDescription: false,
|
||||||
description: ""
|
description: ""
|
||||||
}, {
|
});
|
||||||
|
|
||||||
|
LesionLocations.insert({
|
||||||
location: "Brain Cerebellum Left",
|
location: "Brain Cerebellum Left",
|
||||||
hasDescription: false,
|
hasDescription: false,
|
||||||
description: ""
|
description: ""
|
||||||
}, {
|
});
|
||||||
|
|
||||||
|
LesionLocations.insert({
|
||||||
location: "Brain Cerebrum Left",
|
location: "Brain Cerebrum Left",
|
||||||
hasDescription: false,
|
hasDescription: false,
|
||||||
description: ""
|
description: ""
|
||||||
}, {
|
});
|
||||||
|
|
||||||
|
LesionLocations.insert({
|
||||||
location: "Brain Cerebrum Right",
|
location: "Brain Cerebrum Right",
|
||||||
hasDescription: false,
|
hasDescription: false,
|
||||||
description: ""
|
description: ""
|
||||||
}, {
|
});
|
||||||
|
|
||||||
|
LesionLocations.insert({
|
||||||
location: "Brain Multiple Sites",
|
location: "Brain Multiple Sites",
|
||||||
hasDescription: false,
|
hasDescription: false,
|
||||||
description: ""
|
description: ""
|
||||||
}];
|
});
|
||||||
|
|
||||||
|
var lastAddedLesionData;
|
||||||
|
|
||||||
Template.lesionLocationDialog.onRendered(function() {
|
Template.lesionLocationDialog.onRendered(function() {
|
||||||
console.log(this.data);
|
|
||||||
|
|
||||||
function fillSelectLesionLocation() {
|
|
||||||
var el = $("#selectLesionLocation");
|
|
||||||
el.find('option:not(:first)').remove();
|
|
||||||
$.each(lesionLocationsArray, function(key, value) {
|
|
||||||
el.append("<option value='" + key + "'>" + value.location + "</option>");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fill dropdown
|
|
||||||
fillSelectLesionLocation();
|
|
||||||
|
|
||||||
// Observe Measurements Collection Changes
|
// Observe Measurements Collection Changes
|
||||||
Measurements.find().observe({
|
Measurements.find().observe({
|
||||||
added: function(lesionData) {
|
added: function(lesionData) {
|
||||||
lastAddedLesionData = lesionData;
|
lastAddedLesionData = lesionData;
|
||||||
},
|
},
|
||||||
changed: function(lesionData) {
|
changed: function(lesionData) {
|
||||||
console.log("lesionData is changed!");
|
console.log("lesionData has changed!");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
Template.lesionLocationDialog.events({
|
Template.lesionLocationDialog.helpers({
|
||||||
'click button#btnCloseLesionPopup': function(e) {
|
'lesionLocations': function() {
|
||||||
$("#lesionDialog").modal("hide");
|
return LesionLocations.find();
|
||||||
},
|
|
||||||
|
|
||||||
'change select#selectLesionLocation': function(e) {
|
|
||||||
var el = $(e.target);
|
|
||||||
var selectedLocationIndex = el.val();
|
|
||||||
if (selectedLocationIndex < 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get selected location data
|
|
||||||
var locationObj = lesionLocationsArray[selectedLocationIndex];
|
|
||||||
|
|
||||||
// Gets active lesion measurement data that is latest added data
|
|
||||||
var activeLesionMeasurementData = Session.get("lesionMeasurementData");
|
|
||||||
|
|
||||||
// Adds location data to trialPatientLocations array and returns locationUID
|
|
||||||
var locationUID = measurementManagerDAL.addNewLocation(locationObj);
|
|
||||||
|
|
||||||
// Linkk locationUID with activeLesionMeasurementData
|
|
||||||
activeLesionMeasurementData.locationUID = locationUID;
|
|
||||||
|
|
||||||
// Adds lesion data to timepoints array
|
|
||||||
measurementManagerDAL.addLesionData(activeLesionMeasurementData);
|
|
||||||
|
|
||||||
// Trigger location selected event
|
|
||||||
$(document).trigger("lesionLocationSelected", locationObj);
|
|
||||||
|
|
||||||
// Set activeModule parameters in index.html
|
|
||||||
$("#lesionDialog").modal("hide");
|
|
||||||
|
|
||||||
// Select first option
|
|
||||||
el.val($("#selectLesionLocation option:first").val());
|
|
||||||
|
|
||||||
// Set lesion location selected session to prevent open
|
|
||||||
Session.set("lesionLocationSelected", true);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -0,0 +1,19 @@
|
|||||||
|
#lesionLocationDialog
|
||||||
|
display: none
|
||||||
|
position: absolute
|
||||||
|
z-index: 100
|
||||||
|
background: white
|
||||||
|
padding: 10px
|
||||||
|
border-radius: 10px
|
||||||
|
|
||||||
|
#closeLesionPopup
|
||||||
|
outline: 0
|
||||||
|
border: none
|
||||||
|
background-color: transparent
|
||||||
|
|
||||||
|
#selectLesionLocation
|
||||||
|
margin-top: 5px
|
||||||
|
|
||||||
|
.dialogContent
|
||||||
|
margin-bottom: 20px
|
||||||
|
|
||||||
@ -18,11 +18,9 @@ Package.onUse(function (api) {
|
|||||||
api.addFiles('compatibility/nonTargetTool.js', 'client', {bare: true});
|
api.addFiles('compatibility/nonTargetTool.js', 'client', {bare: true});
|
||||||
api.addFiles('compatibility/measurementManagerDAL.js', 'client', {bare: true});
|
api.addFiles('compatibility/measurementManagerDAL.js', 'client', {bare: true});
|
||||||
|
|
||||||
api.addFiles('components/lesionDialog/lesionDialog.html', 'client');
|
|
||||||
api.addFiles('components/lesionDialog/lesionDialog.js', 'client');
|
|
||||||
|
|
||||||
api.addFiles('components/lesionLocationDialog/lesionLocationDialog.html', 'client');
|
api.addFiles('components/lesionLocationDialog/lesionLocationDialog.html', 'client');
|
||||||
api.addFiles('components/lesionLocationDialog/lesionLocationDialog.js', 'client');
|
api.addFiles('components/lesionLocationDialog/lesionLocationDialog.js', 'client');
|
||||||
|
api.addFiles('components/lesionLocationDialog/lesionLocationDialog.styl', 'client');
|
||||||
|
|
||||||
api.addFiles('components/lesionTable/lesionTable.html', 'client');
|
api.addFiles('components/lesionTable/lesionTable.html', 'client');
|
||||||
api.addFiles('components/lesionTable/lesionTable.styl', 'client');
|
api.addFiles('components/lesionTable/lesionTable.styl', 'client');
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user