WIP reorganization

This commit is contained in:
Erik Ziegler committed 2018-12-12 09:10:39 +01:00
1 parent 6706dfe634
commit 054e37dfb7
266 files changed
+98 -620

No files matched your search

+1 -1
View File
@@ -5,7 +5,6 @@ aldeed:schema-index@1.1.1
aldeed:simple-schema@1.5.4
aldeed:template-extension@4.1.0
allow-deny@1.1.0
amplify@1.0.0
autoupdate@1.6.0-beta181.7
babel-compiler@7.2.3
babel-runtime@1.3.0
@@ -36,6 +35,7 @@ ecmascript-runtime-client@0.8.0
ecmascript-runtime-server@0.7.1
ejson@1.1.0
es5-shim@4.8.0
fastclick@1.0.13
fetch@0.1.0
fortawesome:fontawesome@4.7.0
geojson-utils@1.0.10
+67
View File
@@ -0,0 +1,67 @@
import React, { Component } from 'react';
import { withRouter } from 'react-router';
import { Route, Switch } from 'react-router-dom';
import SecretRoute from './SecretRoute.js';
import { OHIF } from 'meteor/ohif:core';
import Provider from "react-redux/es/components/Provider";
const reload = () => window.location.reload();
const Studylist = OHIF.studylist.components.StudyList;
function setContext(context) {
/*Rollbar.configure({
payload: {
context
}
});*/
console.log(context);
}
class App extends Component {
componentDidMount() {
this.unlisten = this.props.history.listen((location, action) => {
setContext(window.location.pathname);
});
}
componentWillUnmount() {
this.unlisten();
}
render() {
return (
<Provider store={window.store}>
<Switch>
<SecretRoute
exact
path="/studylist"
component={Studylist}
auth={this.props.auth}
store={this.props.store}
/>
<SecretRoute
exact
path="/"
component={Studylist}
auth={this.props.auth}
store={this.props.store}
/>
<SecretRoute
exact
path="/viewer"
component={ConnectedViewer}
auth={this.props.auth}
store={this.props.store}
/>
{/*<Route path="/silent-refresh.html" onEnter={reload} />
<Route path="/logout-redirect.html" onEnter={reload} />*/}
<Route render={() =>
<div> Sorry, this page does not exist. </div>}
/>
</Switch>
</Provider>
);
}
}
export default withRouter(App);
@@ -123,7 +123,7 @@ class Viewer extends Component {
}
render() {
return (<Provider store={window.store}>
return (<>
<div className='viewerDialogs'>
<CineDialog/>
</div>
@@ -131,7 +131,7 @@ class Viewer extends Component {
{/*<ToolbarSection/>*/}
<FlexboxLayout studies={this.state.studies}/>
</div>
</Provider>
</>
);
}
}
-1
View File
@@ -12,7 +12,6 @@ Package.onUse(function(api) {
api.versionsFrom('1.7');
api.use('ecmascript');
api.use('standard-app-packages');
api.use('jquery');
api.use('stylus');
api.use('underscore');
-1
View File
@@ -12,7 +12,6 @@ Package.onUse(function(api) {
api.versionsFrom('1.7');
api.use('ecmascript');
api.use('standard-app-packages');
// Our custom packages
api.use('ohif:core');
@@ -0,0 +1,27 @@
import React, { Component } from 'react';
import Blaze from 'meteor/gadicc:blaze-react-component';
class StudyList extends Component {
constructor(props) {
super(props);
}
render() {
return (
<div className='StudyList'>
<Blaze template="studylist" />
</div>
);
}
}
StudyList.propTypes = {
studies: PropTypes.array.isRequired
};
OHIF.studylist.components = {
StudyList
};
export default StudyList;
@@ -1,2 +1,3 @@
import './seriesDetailsModal';
import './studylist';
import './StudyList.js';
@@ -1,22 +0,0 @@
<template name="imageThumbnail">
<div class="imageThumbnail">
<div class="imageThumbnailCanvas">
<img class="static-image"/>
</div>
<div class="imageThumbnailLoadingIndicator
thumbnailLoadingIndicator
{{ #if isLoading }}d-block{{/if}}">
<p>Loading {{percentComplete}}</p>
</div>
<div class="imageThumbnailErrorLoadingIndicator
thumbnailLoadingIndicator
{{ #if hasLoadingError }}d-block{{/if}}">
<p>Error</p>
</div>
{{#if showStackLoadingProgressBar}}
<div class="imageThumbnailProgressBar">
<div class="imageThumbnailProgressBarInner" style="width:{{stackPercentComplete}}%"></div>
</div>
{{/if}}
</div>
</template>
@@ -1,152 +0,0 @@
import { Meteor } from 'meteor/meteor';
import { Template } from 'meteor/templating';
import { Session } from 'meteor/session';
import { OHIF } from 'meteor/ohif:core';
import { cornerstone } from 'meteor/ohif:cornerstone';
/**
* Asynchronous wrapper around Cornerstone's renderToCanvas method.
*
* @param {HTMLElement} canvasElement An HTML <canvas> element
* @param {Image} image A Cornerstone Image
*
* @return {Promise} A promise tracking the progress of the rendering. Resolves empty.
*/
function renderAsync(canvasElement, image) {
return new Promise((resolve, reject) => {
try {
cornerstone.renderToCanvas(canvasElement, image);
resolve();
} catch(error) {
reject(error);
}
});
}
Template.imageThumbnail.onCreated(() => {
const instance = Template.instance();
instance.isLoading = new ReactiveVar(false);
instance.hasLoadingError = new ReactiveVar(false);
// Get the image ID for current thumbnail
instance.getThumbnailImageId = () => {
const settingPath = 'public.ui.useMiddleSeriesInstanceAsThumbnail';
const useMiddleFrame = OHIF.utils.ObjectPath.get(Meteor.settings, settingPath);
const stack = instance.data.thumbnail.stack;
const lastIndex = (stack.numImageFrames || stack.images.length || 1) - 1;
let imageIndex = useMiddleFrame ? Math.floor(lastIndex / 2) : 0;
let imageInstance;
if (stack.isMultiFrame) {
imageInstance = stack.images[0];
} else {
imageInstance = stack.images[imageIndex];
imageIndex = undefined;
}
return imageInstance.getImageId(imageIndex, true);
};
});
Template.imageThumbnail.onRendered(() => {
const instance = Template.instance();
// Declare DOM and jQuery objects
const $parent = instance.$('.imageThumbnail');
const $thumbnailElement = $parent.find('.imageThumbnailCanvas');
instance.refreshImage = () => {
const imageElement = $thumbnailElement.find('img').get(0);
// Activate the loading state
instance.isLoading.set(true);
instance.hasLoadingError.set(false);
// Clear the previous image
imageElement.removeAttribute('src');
// Define a handler for success on image load
const loadSuccess = image => {
// This is an off-screen canvas. It's used to get dataURL images by using
// cornerstone.renderToCanvas function.
const canvasElement = document.createElement('canvas');
canvasElement.width = 193;
canvasElement.height = 123;
// Render the image to canvas to be able to get its dataURL
renderAsync(canvasElement, image).then(() => {
instance.isLoading.set(false);
imageElement.src = canvasElement.toDataURL('image/jpeg', 1);
});
};
// Define a handler for error on image load
const loadError = () => {
instance.isLoading.set(false);
instance.hasLoadingError.set(true);
};
// Call cornerstone image loader with the defined handlers
cornerstone.loadAndCacheImage(instance.imageId).then(loadSuccess, loadError);
};
// Run this computation every time the current study is changed
instance.autorun(() => {
// Check if there is a reactive var set for current study
if (instance.data.currentStudy) {
// Register a dependency from this computation on current study
instance.data.currentStudy.dep.depend();
}
// Depend on external data and re-run this computation when it changes
Template.currentData();
// Get the image ID. If it is the same as the currently rendered imageId,
// refresh the image.
const imageId = instance.getThumbnailImageId();
if (imageId !== instance.imageId) {
instance.imageId = imageId;
instance.refreshImage();
}
});
});
Template.imageThumbnail.helpers({
// Executed every time the thumbnail image loading progress is changed
percentComplete() {
const instance = Template.instance();
// Get the encoded image ID for thumbnail
const encodedImageId = OHIF.string.encodeId(instance.imageId);
// Register a dependency from this computation on Session key
const percentComplete = Session.get('CornerstoneThumbnailLoadProgress' + encodedImageId);
// Return the complete percent amount of the image loading
if (percentComplete && percentComplete !== 100) {
return percentComplete + '%';
}
},
// Return how much the stack has already loaded
stackPercentComplete() {
const stack = Template.instance().data.thumbnail.stack;
const progress = Session.get(`StackProgress:${stack.displaySetInstanceUid}`);
return progress && progress.percentComplete;
},
showStackLoadingProgressBar() {
return OHIF.uiSettings.showStackLoadingProgressBar;
},
isLoading() {
return Template.instance().isLoading.get();
},
hasLoadingError() {
return Template.instance().hasLoadingError.get();
}
});
@@ -1,67 +0,0 @@
@import "{ohif:design}/app"
.thumbnailEntry.active .imageThumbnail
theme('border-color', '$activeColor')
box-shadow: none
transition($sidebarTransition)
.imageThumbnail
theme('box-shadow', 'inset 0 0 0 1px $uiBorderColorDark')
theme('background-color', '$primaryBackgroundColor')
border: 5px solid transparent
border-radius: 12px
height: 135px
margin: 0 auto
padding 1px 7px
position: relative
transition($sidebarTransition)
width: 217px
-moz-background-clip: padding
-webkit-background-clip: padding
background-clip: padding-box
.imageThumbnailClone
margin: 0 !important
&:hover
theme('border-color', '$hoverColor')
box-shadow: none
.imageThumbnailCanvas
height: 100%
overflow: hidden
img
-webkit-user-drag: none
.thumbnailLoadingIndicator
display: none
pointer-events: none
theme('color', '$textSecondaryColor')
height: 20px
width: 100%
top: 0
left: 0
right: 0
bottom: 0
margin: auto
position: absolute
&.d-block
display: block;
p
text-align: center
font-size: 10pt
.imageThumbnailProgressBar
position: relative
width: 100%
height: 3px
top: -5px
.imageThumbnailProgressBarInner
height: 100%
width: 0
border-radius: 5px
theme('background-color', '$activeColor')
@@ -1,99 +0,0 @@
<template name="textMarkerDialogs">
<dialog id="textMarkerOptionsDialog" oncontextmenu="return false" class="textMarkerDialog noselect">
<h5>Spine Labels</h5>
<a class="closeTextMarkerDialogs">{{> iconCrossCircle}}</a>
<div class='optionsDiv'>
<div class="select2-wrapper optionBox">
<label for="startFrom">Label: </label>
<select name="start" id="startFrom" tabindex="-1" class="select2">
<!-- Cervical spine !-->
<option value="C1" selected>C1</option>
<option value="C2">C2</option>
<option value="C3">C3</option>
<option value="C4">C4</option>
<option value="C5">C5</option>
<option value="C6">C6</option>
<option value="C7">C7</option>
<!-- Thoracic spine !-->
<option value="T1">T1</option>
<option value="T2">T2</option>
<option value="T3">T3</option>
<option value="T4">T4</option>
<option value="T5">T5</option>
<option value="T6">T6</option>
<option value="T7">T7</option>
<option value="T8">T8</option>
<option value="T9">T9</option>
<option value="T10">T10</option>
<option value="T11">T11</option>
<option value="T12">T12</option>
<!-- Lumbar spine !-->
<option value="L1">L1</option>
<option value="L2">L2</option>
<option value="L3">L3</option>
<option value="L4">L4</option>
<option value="L5">L5</option>
</select>
</div>
<div class="optionBox">
<div class="btn-group iconSwitch" data-toggle="buttons">
<label for="ascending" class="btn btn-link" title="Add labels from head to feet (down) or feet to head (up)" data-toggle="tooltip" data-container="body">
<input type="checkbox" id="ascending"> <span class="on"><i class="fa fa-long-arrow-up" aria-hidden="true"></i></span> <span class="off"><i class="fa fa-long-arrow-down" aria-hidden="true"></i></span>
</label>
</div>
</div>
<button id="clearLabels" class="btn viewerBtn btn-xs" type="button">
Clear Labels <i class="viewerIcon-clear"></i>
</button>
</div>
</dialog>
<dialog id="textMarkerRelabelDialog" oncontextmenu="return false" class="textMarkerDialog noselect">
<h5>Change Spine Label</h5>
<div class="relabelOptions">
<div class="select2-wrapper optionBox">
<label for="relabelSelect">Label:</label>
<select name="relabelSelect" class="relabelSelect">
<!-- Cervical spine !-->
<option value="C1">C1</option>
<option value="C2">C2</option>
<option value="C3">C3</option>
<option value="C4">C4</option>
<option value="C5">C5</option>
<option value="C6">C6</option>
<option value="C7">C7</option>
<!-- Thoracic spine !-->
<option value="T1">T1</option>
<option value="T2">T2</option>
<option value="T3">T3</option>
<option value="T4">T4</option>
<option value="T5">T5</option>
<option value="T6">T6</option>
<option value="T7">T7</option>
<option value="T8">T8</option>
<option value="T9">T9</option>
<option value="T10">T10</option>
<option value="T11">T11</option>
<option value="T12">T12</option>
<!-- Lumbar spine !-->
<option value="L1">L1</option>
<option value="L2">L2</option>
<option value="L3">L3</option>
<option value="L4">L4</option>
<option value="L5">L5</option>
</select>
</div>
</div>
<div class="relabelButtons">
<button class="relabelRemove btn btn-xs btn-secondary viewerBtn">Delete</button>
<button class="relabelConfirm btn btn-xs viewerBtn">Save</button>
</div>
<div class="dialog arrow">
</div>
</dialog>
</template>
@@ -1,124 +0,0 @@
/**
* @TODO: add this to OHIF's Viewers
*/
import { Template } from 'meteor/templating';
import { $ } from 'meteor/jquery';
import { toolManager } from '../../../lib/toolManager';
import { viewportUtils } from '../../../lib/viewportUtils';
Template.textMarkerDialogs.events({
'change #startFrom'(e) {
const config = cornerstoneTools.textMarker.getConfiguration();
config.current = $(e.target).val();
//console.log("Changed starting point to: " + config.current);
},
'change #ascending'(e) {
const config = cornerstoneTools.textMarker.getConfiguration();
config.ascending = $(e.target).is(':checked');
const currentIndex = config.markers.indexOf(config.current);
config.current = config.markers[currentIndex];
const nextMarker = config.current;
$('#startFrom').val(nextMarker).trigger('change');
//console.log("Changed ascending to: " + config.ascending);
},
'click #clearLabels'() {
const element = viewportUtils.getActiveViewportElement();
const toolType = 'textMarker';
const toolStateManager = cornerstoneTools.globalImageIdSpecificToolStateManager;
const toolState = toolStateManager.toolState;
// We might want to make this a convenience function in cornerstoneTools
const stack = cornerstoneTools.getToolState(element, 'stack');
if (stack && stack.data.length && stack.data[0].imageIds.length) {
const imageIds = stack.data[0].imageIds;
// Clear the tool data for each image in the stack
imageIds.forEach( imageId => {
if(toolState.hasOwnProperty(imageId)) {
const toolData = toolState[imageId];
if (toolData.hasOwnProperty(toolType)) {
delete toolData[toolType];
}
}
});
}
cornerstone.updateImage(element);
},
'click .closeTextMarkerDialogs'() {
toolManager.setActiveTool();
document.getElementById('textMarkerOptionsDialog').close();
$('#spine').removeClass('active');
const defaultTool = toolManager.getDefaultTool();
$('#' + defaultTool).addClass('active');
}
});
Template.textMarkerDialogs.onRendered(function() {
const optionsDialog = $('#textMarkerOptionsDialog');
optionsDialog.draggable();
dialogPolyfill.registerDialog(optionsDialog.get(0));
const relabelDialog = $('#textMarkerRelabelDialog');
relabelDialog.draggable();
dialogPolyfill.registerDialog(relabelDialog.get(0));
$(document).on('click', event => {
if (!$(event.target).closest('.select2-wrapper').length) {
setTimeout(() => {
$('#startFrom, .relabelSelect').select2('close');
}, 200);
}
});
$(document).on('touchmove', event => {
if (!$(event.target).closest('.select2-container').length) {
setTimeout(() => {
$('#startFrom, .relabelSelect').select2('close');
}, 200);
}
});
$(() => {
FastClick.attach(document.body);
const $customSelects = $('#startFrom, .relabelSelect')
$customSelects.select2({
/**
* Adds needsclick class to all DOM elements in the Select2 results list
* so they can be accessible on iOS mobile when FastClick is initiated too.
*/
templateResult(result, container) {
if (!result.id) {
return result.text;
}
container.className += ' needsclick';
return result.text;
},
placeholder: 'C1',
minimumResultsForSearch: -1,
theme: 'viewerDropdown'
});
/**
* Additional to tweaking the templateResult option in Select2,
* add needsclick class to all DOM elements in the Select2 container,
* so they can be accessible on iOS mobile when FastClick is initiated too.
*
* More info about needsclick:
* https://github.com/ftlabs/fastclick#ignore-certain-elements-with-needsclick
*
*/
$customSelects.each( (index, el) =>{
$(el).data('select2').$container.find('*').addClass('needsclick');
});
});
});
@@ -1,147 +0,0 @@
.textMarkerDialog
z-index: 1000
width: 260px
position: absolute
top: auto
left: auto
bottom: 3px
right: 3px
margin: auto
padding:.5em
background-image: linear-gradient(#2E608D, #23557F)
box-sizing: border-box
border: 1px black solid
border-radius: 5px
height: 81px
max-height: 81px
h5
color: #D1EDFB;
font-size: 14px;
line-height: 22px;
font-weight: 600;
cursor:default
.handle
width: 40px;
float: left;
height: 22px;
display: block;
margin-right: 10px;
position: relative;
margin-top: 1px;
margin-left: 1px;
#startFrom
margin-right:10px
#clearLabels
margin-left:10px
float:right
.optionBox
color: #d1edfb
margin-bottom: 5px
float: left
span.subLabel
width: 50px
display: block
float: left
line-height: 30px
> label
color: #d1edfb
float: left
min-width: 40px
line-height: 24px
font-size: 12px
font-weight: 600
.closeTextMarkerDialogs
position: absolute
top: 5px
right: 4px
padding: 5px
cursor: pointer
svg
width: 19px
height: 19px
fill: #d1edfb
&:hover
svg
fill: #FFF
.dialog.arrow
left: 50%
margin-left: -11px
border-top-width: 0
border-bottom-color: #999999
border-bottom-color: rgba(0, 0, 0, 0.25)
border-width: 11px
bottom: -10px
position: absolute
width: 0;
height: 0;
border-left: 10px solid transparent;
border-right: 10px solid transparent;
border-top: 10px solid #23557f;
&:after
content: " "
top: 1px
margin-left: -10px
border-top-width: 0
border-bottom-color: #23557f
border-width: 10px
button.btn-secondary
background-color: #CFE3F5;
border: 1px solid #E5F3FF;
font-size: 12px !important;
color:#0D416D
&:hover
color:#0D416D
#textMarkerRelabelDialog
margin: 0
.relabelOptions
padding: 15px 0px 0px 0px
.relabelSelect
margin-left: 5px
#textMarkerOptionsDialog
.optionsDiv
padding-top: 10px
//Avoids Cine Play and Text Marker dialog to overlap
#textMarkerOptionsDialog[open='open'] ~ #cineDialog[open='open']
bottom: 90px
.relabelButtons
text-align:right
button.viewerBtn
background-color: #5D9ACE;
border: 1px solid #6EAEE4;
font-size: 12px !important;
color:#FFF
line-height: 21px;
&:hover
color:#FFF
.iconSwitch
margin:0px 5px
.btn
span
display: none
.on
display: none
.off
display: block
&.btn-link, &.active, &:active, &:hover, &:focus, &.active:focus
background-color: #225682;
border: 1px solid #7AB0DE;
box-shadow: none;
padding: 1px 7px;
border-radius: 4px;
color: #d1edfb;
box-shadow: none;
outline: none;
&:hover
color:#fff
&.active
.on
display:block
.off
display: none
-4
View File
@@ -154,10 +154,6 @@ Package.onUse(function(api) {
api.addFiles('client/components/viewer/confirmDeleteDialog/confirmDeleteDialog.js', 'client');
api.addFiles('client/components/viewer/confirmDeleteDialog/confirmDeleteDialog.styl', 'client');
api.addFiles('client/components/viewer/textMarkerDialogs/textMarkerDialogs.html', 'client');
api.addFiles('client/components/viewer/textMarkerDialogs/textMarkerDialogs.js', 'client');
api.addFiles('client/components/viewer/textMarkerDialogs/textMarkerDialogs.styl', 'client');
api.addFiles('client/components/viewer/seriesQuickSwitch/seriesQuickSwitch.html', 'client');
api.addFiles('client/components/viewer/seriesQuickSwitch/seriesQuickSwitch.styl', 'client');
api.addFiles('client/components/viewer/seriesQuickSwitch/seriesQuickSwitch.js', 'client');
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Loaded 100 of 266 files, more files were not shown because too many files have changed in this diff. Show more