LT-253: Creating dynamic form components
This commit is contained in:
parent
88f737644f
commit
cb875b1913
@ -15,6 +15,8 @@ tracker # Meteor's client-side reactive programming library
|
||||
es5-shim # ECMAScript 5 compatibility for older browsers.
|
||||
ecmascript # Enable ECMAScript2015+ syntax in app code
|
||||
|
||||
ohif:core
|
||||
|
||||
insecure # Allow all DB writes from clients (for prototyping)
|
||||
cornerstone
|
||||
worklist
|
||||
|
||||
@ -90,6 +90,7 @@ natestrauser:select2@4.0.2
|
||||
npm-bcrypt@0.8.6_3
|
||||
npm-mongo@1.4.45
|
||||
observe-sequence@1.0.12
|
||||
ohif:core@0.0.1
|
||||
ordered-dict@1.0.8
|
||||
orthanc-remote@0.0.1
|
||||
peppelg:bootstrap-3-modal@1.0.4
|
||||
|
||||
@ -1,3 +1,6 @@
|
||||
import { OHIF } from 'meteor/ohif:core';
|
||||
OHIF.viewer = OHIF.viewer || {};
|
||||
|
||||
Template.viewer.onCreated(function() {
|
||||
// Attach the Window resize listener
|
||||
$(window).on('resize', handleResize);
|
||||
@ -7,10 +10,6 @@ Template.viewer.onCreated(function() {
|
||||
|
||||
log.info('viewer onCreated');
|
||||
|
||||
OHIF = window.OHIF || {
|
||||
viewer: {}
|
||||
};
|
||||
|
||||
OHIF.viewer.loadIndicatorDelay = 500;
|
||||
OHIF.viewer.defaultTool = 'wwwc';
|
||||
OHIF.viewer.refLinesEnabled = true;
|
||||
@ -57,7 +56,7 @@ Template.viewer.onCreated(function() {
|
||||
}
|
||||
|
||||
var contentId = this.data.contentId;
|
||||
|
||||
|
||||
if (ViewerData[contentId].loadedSeriesData) {
|
||||
log.info('Reloading previous loadedSeriesData');
|
||||
|
||||
@ -66,7 +65,7 @@ Template.viewer.onCreated(function() {
|
||||
} else {
|
||||
log.info('Setting default ViewerData');
|
||||
OHIF.viewer.loadedSeriesData = {};
|
||||
|
||||
|
||||
ViewerData[contentId].loadedSeriesData = OHIF.viewer.loadedSeriesData;
|
||||
|
||||
// Update the viewer data object
|
||||
@ -80,7 +79,7 @@ Template.viewer.onCreated(function() {
|
||||
|
||||
// Update the ViewerStudies collection with the loaded studies
|
||||
ViewerStudies.remove({});
|
||||
|
||||
|
||||
this.data.studies.forEach(function(study) {
|
||||
study.selected = true;
|
||||
ViewerStudies.insert(study);
|
||||
|
||||
@ -6,7 +6,7 @@ label.radio-option
|
||||
height: 0
|
||||
width: 0
|
||||
span
|
||||
padding-left: 20px
|
||||
padding-left: 23px
|
||||
position: relative
|
||||
&:before
|
||||
background: white
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
import { OHIF } from 'meteor/ohif:core';
|
||||
|
||||
Template.matchedProtocols.onRendered(function() {
|
||||
$('#matchedProtocols button').tooltip(OHIF.viewer.tooltipConfig);
|
||||
});
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
import { OHIF } from 'meteor/ohif:core';
|
||||
|
||||
// Define a global variable that will be used to refer to the Protocol Engine
|
||||
// It must be populated by HP.setEngine when the Viewer is initialized and a ProtocolEngine
|
||||
// is instantiated on top of the LayoutManager. If the global ProtocolEngine variable remains
|
||||
@ -214,7 +216,7 @@ HP.ProtocolEngine = class ProtocolEngine {
|
||||
score: matchedDetails.score,
|
||||
protocol: protocol
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (!matched.length) {
|
||||
@ -300,7 +302,7 @@ HP.ProtocolEngine = class ProtocolEngine {
|
||||
if (!protocol.protocolMatchingRules) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
var studies = WorklistStudies.find({
|
||||
patientId: study.patientId,
|
||||
studyDate: {
|
||||
|
||||
@ -4,10 +4,10 @@ SimpleSchema.extendOptions({
|
||||
allowedSelect2Values: Match.Optional(Array),
|
||||
});
|
||||
|
||||
export const AdditionalFinding = new SimpleSchema({
|
||||
export const schema = new SimpleSchema({
|
||||
measurableDisease: {
|
||||
type: String,
|
||||
label: 'Measurable Disease',
|
||||
label: 'Measurable disease',
|
||||
allowedValues: ['Present', 'Absent'],
|
||||
defaultValue: 'Absent',
|
||||
optional: true
|
||||
@ -7,6 +7,13 @@
|
||||
</div>
|
||||
{{>radioOptionGroup (stateDataWithKey "measurableDisease")}}
|
||||
</div>
|
||||
|
||||
<!-- <h4>Testing dynamic components</h4>
|
||||
{{#form id="testForm" schema=currentSchema}}
|
||||
{{>inputText key='test' label='testing'}}
|
||||
{{>groupRadio mixins='schemaData' key='acceptableImageQuality'}}
|
||||
{{/form}} -->
|
||||
|
||||
<div class="row">
|
||||
<div class="header">
|
||||
Supplementary Measurements
|
||||
|
||||
@ -1,14 +1,12 @@
|
||||
import { Template } from 'meteor/templating';
|
||||
import { ReactiveDict } from 'meteor/reactive-dict';
|
||||
|
||||
// TODO: Check why I can't use absolute paths for this? Keeps saying module not found
|
||||
import { AdditionalFinding } from '../../../both/schema/additionalFinding';
|
||||
import { schema as AdditionalFindingsSchema } from 'meteor/lesiontracker/both/schema/additionalFindings';
|
||||
|
||||
Template.additionalFindings.onCreated(function additionalFindingsOnCreated() {
|
||||
console.log('additionalFindingsOnCreated');
|
||||
const instance = Template.instance();
|
||||
|
||||
instance.currentSchema = AdditionalFinding;
|
||||
instance.currentSchema = AdditionalFindingsSchema;
|
||||
instance.state = new ReactiveDict();
|
||||
|
||||
if (!instance.data.currentTimepointId) {
|
||||
|
||||
@ -25,21 +25,22 @@
|
||||
.header
|
||||
height: 33px
|
||||
line-height: 33px
|
||||
font-weight: 400
|
||||
font-weight: bold
|
||||
font-size: 14px
|
||||
padding: 0 10px
|
||||
padding: 1px 13px 0
|
||||
color: $textPrimaryColor
|
||||
background-color: $uiGrayDark
|
||||
background-color: $uiGray
|
||||
|
||||
.form-group
|
||||
padding: 10px
|
||||
padding: 7px 11px
|
||||
color: $textPrimaryColor
|
||||
|
||||
&:not(:last-child)
|
||||
border-bottom: $uiBorderThickness solid $uiBorderColorDark
|
||||
|
||||
h5
|
||||
font-weight: 300
|
||||
font-weight: bold
|
||||
margin-bottom: 8px
|
||||
|
||||
.control-label
|
||||
font-size: 14px
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
import { OHIF } from 'meteor/ohif:core';
|
||||
|
||||
Template.toolbarSection.helpers({
|
||||
// Returns true if the view shall be split in two viewports
|
||||
splitView() {
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
import { OHIF } from 'meteor/ohif:core';
|
||||
|
||||
Template.toolbarSectionButton.helpers({
|
||||
activeClass() {
|
||||
const instance = Template.instance();
|
||||
|
||||
@ -1,5 +1,8 @@
|
||||
import { OHIF } from 'meteor/ohif:core';
|
||||
import { TimepointApi } from 'meteor/lesiontracker/lib/api/timepoint';
|
||||
|
||||
OHIF.viewer = OHIF.viewer || {};
|
||||
|
||||
Session.setDefault('activeViewport', false);
|
||||
Session.setDefault('leftSidebar', null);
|
||||
Session.setDefault('rightSidebar', null);
|
||||
@ -22,10 +25,6 @@ Template.viewer.onCreated(() => {
|
||||
|
||||
var contentId = instance.data.contentId;
|
||||
|
||||
OHIF = OHIF || window.OHIF || {
|
||||
viewer: {}
|
||||
};
|
||||
|
||||
OHIF.viewer.loadIndicatorDelay = 3000;
|
||||
OHIF.viewer.defaultTool = 'wwwc';
|
||||
OHIF.viewer.refLinesEnabled = true;
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
import { OHIF } from 'meteor/ohif:core';
|
||||
|
||||
/**
|
||||
* Activates a set of lesions when lesion table row is clicked
|
||||
*
|
||||
|
||||
@ -35,7 +35,7 @@ Package.onUse(function(api) {
|
||||
api.addFiles('log.js', [ 'client', 'server' ]);
|
||||
|
||||
// Schema
|
||||
api.addFiles('both/schema/additionalFinding.js', [ 'client', 'server' ]);
|
||||
api.addFiles('both/schema/additionalFindings.js', [ 'client', 'server' ]);
|
||||
|
||||
// Client-side collections
|
||||
api.addFiles('client/collections/LesionLocations.js', 'client');
|
||||
|
||||
49
Packages/ohif-core/components/base/component.js
Normal file
49
Packages/ohif-core/components/base/component.js
Normal file
@ -0,0 +1,49 @@
|
||||
import { OHIF } from 'meteor/ohif:core';
|
||||
|
||||
/*
|
||||
* Base component to template instances of all dynamic components
|
||||
*/
|
||||
class Component {
|
||||
|
||||
// Set up the component
|
||||
constructor(templateInstance) {
|
||||
// Store the component in the current view
|
||||
templateInstance.view._component = this;
|
||||
|
||||
// Create an object to register section's content
|
||||
templateInstance.sections = {};
|
||||
|
||||
// Store the template instance in the component
|
||||
this.templateInstance = templateInstance;
|
||||
|
||||
// Store the component's registered sub-components
|
||||
this.registeredItems = new Set();
|
||||
}
|
||||
|
||||
// Self register the component in its first parent component
|
||||
registerSelf() {
|
||||
const parent = OHIF.blaze.getParentComponent(this.templateInstance.view);
|
||||
if (parent) {
|
||||
// Store this component's parent in a property
|
||||
this.parent = parent;
|
||||
|
||||
// Add this component in its parent's registered items list
|
||||
parent.registeredItems.add(this);
|
||||
}
|
||||
}
|
||||
|
||||
// Self unregister the component in its first parent component
|
||||
unregisterSelf() {
|
||||
const parent = OHIF.blaze.getParentComponent(this.templateInstance.view);
|
||||
if (parent) {
|
||||
// Remove the parent property from this component
|
||||
delete this.parent;
|
||||
|
||||
// Remove this component from its parent's registered items list
|
||||
parent.registeredItems.delete(this);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
OHIF.Component = Component;
|
||||
26
Packages/ohif-core/components/base/index.js
Normal file
26
Packages/ohif-core/components/base/index.js
Normal file
@ -0,0 +1,26 @@
|
||||
// Core files
|
||||
import './component.js';
|
||||
import './mixin.js';
|
||||
import './template.js';
|
||||
|
||||
// Mixins
|
||||
import './mixins/component.js';
|
||||
import './mixins/form.js';
|
||||
import './mixins/formItem.js';
|
||||
import './mixins/group.js';
|
||||
import './mixins/groupRadio.js';
|
||||
import './mixins/input.js';
|
||||
import './mixins/schemaData.js';
|
||||
import './mixins/select.js';
|
||||
import './mixins/select2.js';
|
||||
|
||||
// Templates
|
||||
import './templates/custom.html';
|
||||
import './templates/div.html';
|
||||
import './templates/form.html';
|
||||
import './templates/input.html';
|
||||
import './templates/select.html';
|
||||
|
||||
// wrappers
|
||||
import './wrappers/label.html';
|
||||
import './wrappers/title.html';
|
||||
126
Packages/ohif-core/components/base/mixin.js
Normal file
126
Packages/ohif-core/components/base/mixin.js
Normal file
@ -0,0 +1,126 @@
|
||||
import { OHIF } from 'meteor/ohif:core';
|
||||
import { _ } from 'meteor/underscore';
|
||||
|
||||
// Create an object to store all the application mixins
|
||||
OHIF.mixins = {};
|
||||
|
||||
// Class to manage new mixins and its dependencies
|
||||
class Mixin {
|
||||
|
||||
// Create the mixin instance
|
||||
constructor({ dependencies, composition }) {
|
||||
// Store the mixin dependencies
|
||||
this.dependencies = dependencies || '';
|
||||
|
||||
// Store the mixin composition
|
||||
this.composition = composition;
|
||||
}
|
||||
|
||||
// Initialize the mixin applying all its composition functions
|
||||
init(template, data, applied, behaviors) {
|
||||
const dependenciesArray = this.dependencies.split(' ');
|
||||
_.each(dependenciesArray, dependency => {
|
||||
// Go to next dependency if the current dependency string is blank
|
||||
if (!dependency) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the dependent mixin to be initizalized
|
||||
const mixin = Mixin.getMixin(dependency);
|
||||
|
||||
// Initizalize the mixin dependencies recursively
|
||||
mixin.init(template, data, applied, behaviors);
|
||||
});
|
||||
|
||||
// Apply the mixin's composition behaviors to the template
|
||||
this.apply(template, data, applied, behaviors);
|
||||
}
|
||||
|
||||
// Add the mixin's composition behaviors to the template
|
||||
apply(template, data, applied, behaviors) {
|
||||
// Ignore if the mixin was already applied to the template
|
||||
if (_.contains(applied, this)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Store the mixin's composition
|
||||
const composition = this.composition;
|
||||
|
||||
// Iterate over each behavior
|
||||
_.each(behaviors, behavior => {
|
||||
// Execute something only after all the mixins are done
|
||||
let functionName = behavior;
|
||||
if (functionName === 'onMixins') {
|
||||
functionName = 'onRendered';
|
||||
}
|
||||
|
||||
if (behavior === 'onData' && composition[behavior]) {
|
||||
// If it's just data manipulation, call it immediately
|
||||
composition[behavior](data);
|
||||
} else if (composition[behavior]) {
|
||||
// Register the behavior in the template
|
||||
template[functionName](composition[behavior]);
|
||||
}
|
||||
});
|
||||
|
||||
// Set the current mixin's state as applied
|
||||
applied.push(this);
|
||||
}
|
||||
|
||||
// Initialize all data manipulation mixins
|
||||
static initData(data) {
|
||||
// Split the mixins by space
|
||||
const mixinsArray = data.mixins.split(' ');
|
||||
_.each(mixinsArray, mixinName => {
|
||||
// Ignore blank strings
|
||||
if (!mixinName) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the current mixin
|
||||
const mixin = Mixin.getMixin(mixinName);
|
||||
|
||||
// Initialize the data manipulation composition
|
||||
mixin.init(null, data, [], ['onData']);
|
||||
});
|
||||
}
|
||||
|
||||
// Initialize all the template's mixins
|
||||
static initAll(template, data) {
|
||||
// Split the mixins by space
|
||||
const mixinsArray = data.mixins.split(' ');
|
||||
_.each(mixinsArray, mixinName => {
|
||||
// Ignore blank strings
|
||||
if (!mixinName) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the current mixin
|
||||
const mixin = Mixin.getMixin(mixinName);
|
||||
|
||||
// Initialize blaze default compositions
|
||||
mixin.init(template, data, [], ['onCreated', 'onRendered', 'onDestroyed', 'events', 'helpers']);
|
||||
|
||||
// Execute some behaviors after all mixins are applied
|
||||
mixin.init(template, data, [], ['onMixins']);
|
||||
});
|
||||
}
|
||||
|
||||
// Get a mixin by name
|
||||
static getMixin(mixinName) {
|
||||
// Get the mixin from mixins object
|
||||
const mixin = OHIF.mixins[mixinName];
|
||||
|
||||
// Throw an error if the mixin does not exists
|
||||
if (!mixin) {
|
||||
throw new Error(`Mixin ${mixinName} not found.`);
|
||||
}
|
||||
|
||||
// Return the found mixin
|
||||
return mixin;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Store the Mixin class inside the shared OHIF object
|
||||
OHIF.Mixin = Mixin;
|
||||
16
Packages/ohif-core/components/base/mixins/component.js
Normal file
16
Packages/ohif-core/components/base/mixins/component.js
Normal file
@ -0,0 +1,16 @@
|
||||
import { OHIF } from 'meteor/ohif:core';
|
||||
import { Template } from 'meteor/templating';
|
||||
|
||||
/*
|
||||
* component: create the base structure to aplly specific component mixins
|
||||
*/
|
||||
OHIF.mixins.component = new OHIF.Mixin({
|
||||
composition: {
|
||||
onCreated() {
|
||||
const instance = Template.instance();
|
||||
|
||||
// Declare a property that will be shared among all dependent mixins
|
||||
instance.component = new OHIF.Component(this);
|
||||
}
|
||||
}
|
||||
});
|
||||
50
Packages/ohif-core/components/base/mixins/form.js
Normal file
50
Packages/ohif-core/components/base/mixins/form.js
Normal file
@ -0,0 +1,50 @@
|
||||
import { OHIF } from 'meteor/ohif:core';
|
||||
import { Template } from 'meteor/templating';
|
||||
|
||||
/*
|
||||
* form: controls a form and its registered inputs
|
||||
*/
|
||||
OHIF.mixins.form = new OHIF.Mixin({
|
||||
dependencies: 'group',
|
||||
composition: {
|
||||
onCreated() {
|
||||
const instance = Template.instance();
|
||||
const component = instance.component;
|
||||
|
||||
// Define the form's data schema
|
||||
const schema = instance.data.schema;
|
||||
component.schema = schema && schema.newContext();
|
||||
|
||||
// Check if the form data is valid in its schema
|
||||
component.validate = () => {
|
||||
// Assume validation result as true
|
||||
let result = true;
|
||||
|
||||
// Return true if there's no data schema defined
|
||||
if (!component.schema) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// Iterate over each registered form item and validate it
|
||||
component.registeredItems.forEach(child => {
|
||||
const key = child.templateInstance.data.key;
|
||||
|
||||
// Change result to false if any form item is invalid
|
||||
if (key && !child.validate()) {
|
||||
result = false;
|
||||
}
|
||||
});
|
||||
|
||||
// Return the validation result
|
||||
return result;
|
||||
};
|
||||
},
|
||||
onRendered() {
|
||||
const instance = Template.instance();
|
||||
const component = instance.component;
|
||||
|
||||
// Set the component main and style elements
|
||||
component.$style = component.$element = instance.$('form').first();
|
||||
}
|
||||
}
|
||||
});
|
||||
154
Packages/ohif-core/components/base/mixins/formItem.js
Normal file
154
Packages/ohif-core/components/base/mixins/formItem.js
Normal file
@ -0,0 +1,154 @@
|
||||
import { OHIF } from 'meteor/ohif:core';
|
||||
import { Template } from 'meteor/templating';
|
||||
import { _ } from 'meteor/underscore';
|
||||
import { $ } from 'meteor/jquery';
|
||||
|
||||
/*
|
||||
* formItem: create a generic controller for form items
|
||||
* It may be used to manage all components that belong to forms
|
||||
*/
|
||||
OHIF.mixins.formItem = new OHIF.Mixin({
|
||||
dependencies: 'component',
|
||||
composition: {
|
||||
|
||||
onCreated() {
|
||||
const instance = Template.instance();
|
||||
const component = instance.component;
|
||||
|
||||
// Register the component in the parent component
|
||||
component.registerSelf();
|
||||
|
||||
// Declare the component elements that will be manipulated
|
||||
component.$element = $();
|
||||
component.$style = $();
|
||||
component.$wrapper = $();
|
||||
|
||||
// Get or set the component's value using jQuery's val method
|
||||
component.value = value => {
|
||||
const isGet = _.isUndefined(value);
|
||||
if (isGet) {
|
||||
return component.$element.val();
|
||||
}
|
||||
|
||||
component.$element.val(value).trigger('change');
|
||||
};
|
||||
|
||||
// Disable or enable the component
|
||||
component.disable = isDisable => {
|
||||
component.$element.prop('disabled', !!isDisable);
|
||||
};
|
||||
|
||||
// Set or unset component's readonly property
|
||||
component.readonly = isReadonly => {
|
||||
component.$element.prop('readonly', !!isReadonly);
|
||||
};
|
||||
|
||||
// Show or hide the component
|
||||
component.show = isShow => {
|
||||
const method = isShow ? 'show' : 'hide';
|
||||
component.$wrapper[method]();
|
||||
};
|
||||
|
||||
// Add or remove a state from the component
|
||||
component.state = (state, flag) => {
|
||||
component.$wrapper.toggleClass(`state-${state}`, !!flag);
|
||||
};
|
||||
|
||||
// Set the component in error state and display the error message
|
||||
component.error = errorMessage => {
|
||||
// Set the component error state
|
||||
component.state('error', errorMessage);
|
||||
|
||||
// Set or remove the error message
|
||||
if (errorMessage) {
|
||||
component.$element.trigger('errorin');
|
||||
component.$wrapper.attr('data-error', errorMessage);
|
||||
} else {
|
||||
component.$element.trigger('errorout');
|
||||
component.$wrapper.removeAttr('data-error', errorMessage);
|
||||
}
|
||||
};
|
||||
|
||||
// Check if the component value is valid in its form's schema
|
||||
component.validate = () => {
|
||||
// Get the component's form
|
||||
const form = component.parent;
|
||||
|
||||
// Get the form's data schema
|
||||
const schema = form && form.schema;
|
||||
|
||||
// Get the current component's key
|
||||
const key = instance.data.key;
|
||||
|
||||
// Return true if validation is not needed
|
||||
if (!key || !schema || !component.$wrapper.is(':visible')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Create the data document for validation
|
||||
const document = {
|
||||
[key]: component.value()
|
||||
};
|
||||
|
||||
// Check if the document validation failed
|
||||
if (!schema.validateOne(document, key)) {
|
||||
// Set the component in error state and display the message
|
||||
component.error(schema.keyErrorMessage(key));
|
||||
|
||||
// Return false for validation
|
||||
return false;
|
||||
}
|
||||
|
||||
// Remove the component error state and message
|
||||
component.error(false);
|
||||
|
||||
// Return true for validation
|
||||
return true;
|
||||
};
|
||||
|
||||
},
|
||||
|
||||
onRendered() {
|
||||
const instance = Template.instance();
|
||||
const component = instance.component;
|
||||
|
||||
// Set the element to be controlled
|
||||
component.$element = instance.$(':input:first');
|
||||
|
||||
// Set the element to be styled
|
||||
component.$style = component.$element;
|
||||
|
||||
// Set the most outer wrapper element
|
||||
component.$wrapper = instance.wrapper.$('*').first();
|
||||
},
|
||||
|
||||
onDestroyed() {
|
||||
const instance = Template.instance();
|
||||
|
||||
// Register the component in the parent component
|
||||
instance.component.unregisterSelf();
|
||||
},
|
||||
|
||||
onMixins() {
|
||||
const instance = Template.instance();
|
||||
const component = instance.component;
|
||||
|
||||
// Set the component in jQuery data after all mixins are rendered
|
||||
component.$element.data('component', component);
|
||||
},
|
||||
|
||||
events: {
|
||||
|
||||
// TODO: [design] remove log, show error box/hint over the wrapper
|
||||
errorin(event, instance) {
|
||||
console.log('ERROR when validating component', instance.component);
|
||||
},
|
||||
|
||||
// TODO: [design] hide error box/hint
|
||||
errorout(event, instance) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
50
Packages/ohif-core/components/base/mixins/group.js
Normal file
50
Packages/ohif-core/components/base/mixins/group.js
Normal file
@ -0,0 +1,50 @@
|
||||
import { OHIF } from 'meteor/ohif:core';
|
||||
import { Template } from 'meteor/templating';
|
||||
import { _ } from 'meteor/underscore';
|
||||
|
||||
/*
|
||||
* group: controls a group and its registered items
|
||||
*/
|
||||
OHIF.mixins.group = new OHIF.Mixin({
|
||||
dependencies: 'formItem',
|
||||
composition: {
|
||||
onCreated() {
|
||||
const instance = Template.instance();
|
||||
const component = instance.component;
|
||||
|
||||
// Get or set the child components values
|
||||
component.value = value => {
|
||||
const isGet = _.isUndefined(value);
|
||||
if (isGet) {
|
||||
const result = {};
|
||||
component.registeredItems.forEach(child => {
|
||||
const key = child.templateInstance.data.key;
|
||||
if (key) {
|
||||
result[key] = child.value();
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
const groupValue = typeof value === 'object' ? value : {};
|
||||
component.registeredItems.forEach(child => {
|
||||
const key = child.templateInstance.data.key;
|
||||
const childValue = _.isUndefined(groupValue[key]) ? null : groupValue[key];
|
||||
child.value(childValue);
|
||||
});
|
||||
component.$element.trigger('change');
|
||||
};
|
||||
|
||||
// Disable or enable the component
|
||||
component.disable = isDisable => {
|
||||
component.registeredItems.forEach(child => child.disable(isDisable));
|
||||
};
|
||||
|
||||
// Set or unset component's readonly property
|
||||
component.readonly = isReadonly => {
|
||||
component.registeredItems.forEach(child => child.readonly(isReadonly));
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
});
|
||||
30
Packages/ohif-core/components/base/mixins/groupRadio.js
Normal file
30
Packages/ohif-core/components/base/mixins/groupRadio.js
Normal file
@ -0,0 +1,30 @@
|
||||
import { OHIF } from 'meteor/ohif:core';
|
||||
import { Template } from 'meteor/templating';
|
||||
import { _ } from 'meteor/underscore';
|
||||
|
||||
/*
|
||||
* groupRadio: controls all the radio inputs inside the group
|
||||
*/
|
||||
OHIF.mixins.groupRadio = new OHIF.Mixin({
|
||||
dependencies: 'group',
|
||||
composition: {
|
||||
|
||||
onCreated() {
|
||||
const instance = Template.instance();
|
||||
const component = instance.component;
|
||||
|
||||
// Get the selected radio's value or select a radio based on value
|
||||
component.value = value => {
|
||||
const isGet = _.isUndefined(value);
|
||||
const $elements = $();
|
||||
component.registeredItems.forEach(child => $elements.add(child.$element));
|
||||
if (isGet) {
|
||||
return $elements.filter(':checked').val();
|
||||
}
|
||||
|
||||
$elements.filter(`[value='${value}']`).prop('checked', true).trigger('change');
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
18
Packages/ohif-core/components/base/mixins/input.js
Normal file
18
Packages/ohif-core/components/base/mixins/input.js
Normal file
@ -0,0 +1,18 @@
|
||||
import { OHIF } from 'meteor/ohif:core';
|
||||
import { Template } from 'meteor/templating';
|
||||
|
||||
/*
|
||||
* input: controls a basic input
|
||||
*/
|
||||
OHIF.mixins.input = new OHIF.Mixin({
|
||||
dependencies: 'formItem',
|
||||
composition: {
|
||||
onRendered() {
|
||||
const instance = Template.instance();
|
||||
const component = instance.component;
|
||||
|
||||
// Set the element to be controlled
|
||||
component.$element = instance.$('input:first');
|
||||
}
|
||||
}
|
||||
});
|
||||
46
Packages/ohif-core/components/base/mixins/schemaData.js
Normal file
46
Packages/ohif-core/components/base/mixins/schemaData.js
Normal file
@ -0,0 +1,46 @@
|
||||
import { OHIF } from 'meteor/ohif:core';
|
||||
import { Blaze } from 'meteor/blaze';
|
||||
import { Template } from 'meteor/templating';
|
||||
import { _ } from 'meteor/underscore';
|
||||
|
||||
/*
|
||||
* schemaData: change the component data based on its form's schema data
|
||||
*/
|
||||
OHIF.mixins.schemaData = new OHIF.Mixin({
|
||||
dependencies: 'formItem',
|
||||
composition: {
|
||||
|
||||
onData() {
|
||||
const data = Template.currentData();
|
||||
|
||||
const parent = OHIF.blaze.getParentComponent(Blaze.currentView);
|
||||
|
||||
// Get the parent component schema
|
||||
const schema = parent && parent.schema;
|
||||
|
||||
// Get the current component's key
|
||||
const key = data.key;
|
||||
|
||||
// Stop here if there's no key or schema defined
|
||||
if (!key || !schema) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the current schema data using component's key
|
||||
const currentSchema = schema._schema[key];
|
||||
|
||||
// Stop here if there's no schema data for current key
|
||||
if (!currentSchema) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Use schema's label if it was not defined
|
||||
if (!data.label) {
|
||||
data.label = new ReactiveVar(currentSchema.label);
|
||||
}
|
||||
|
||||
// TODO: [design] convert allowedValues to items and find a way to get key/value pairs
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
18
Packages/ohif-core/components/base/mixins/select.js
Normal file
18
Packages/ohif-core/components/base/mixins/select.js
Normal file
@ -0,0 +1,18 @@
|
||||
import { OHIF } from 'meteor/ohif:core';
|
||||
import { Template } from 'meteor/templating';
|
||||
|
||||
/*
|
||||
* input: controls a basic select
|
||||
*/
|
||||
OHIF.mixins.select = new OHIF.Mixin({
|
||||
dependencies: 'formItem',
|
||||
composition: {
|
||||
onRendered() {
|
||||
const instance = Template.instance();
|
||||
const component = instance.component;
|
||||
|
||||
// Set the element to be controlled
|
||||
component.$element = instance.$('select:first');
|
||||
}
|
||||
}
|
||||
});
|
||||
18
Packages/ohif-core/components/base/mixins/select2.js
Normal file
18
Packages/ohif-core/components/base/mixins/select2.js
Normal file
@ -0,0 +1,18 @@
|
||||
import { OHIF } from 'meteor/ohif:core';
|
||||
import { Template } from 'meteor/templating';
|
||||
|
||||
/*
|
||||
* input: controls a select2 component
|
||||
*/
|
||||
OHIF.mixins.select2 = new OHIF.Mixin({
|
||||
dependencies: 'select',
|
||||
composition: {
|
||||
onRendered() {
|
||||
const instance = Template.instance();
|
||||
const component = instance.component;
|
||||
|
||||
// Set the element to be controlled
|
||||
component.$element = instance.$('select:first');
|
||||
}
|
||||
}
|
||||
});
|
||||
106
Packages/ohif-core/components/base/template.js
Normal file
106
Packages/ohif-core/components/base/template.js
Normal file
@ -0,0 +1,106 @@
|
||||
import { OHIF } from 'meteor/ohif:core';
|
||||
import { _ } from 'meteor/underscore';
|
||||
|
||||
// Create a new custom template for the base component
|
||||
Template.baseComponent = new Template('baseComponent', () => {});
|
||||
|
||||
// Inject some custom behaviors in the view's construction function
|
||||
Template.baseComponent.constructView = function(contentFunc, elseFunc) {
|
||||
// Get the data passed to the template
|
||||
const data = Template.currentData();
|
||||
|
||||
// Check the base template. If it's not informed set as the custom base
|
||||
data.base || (data.base = 'baseCustom');
|
||||
|
||||
// Get the base template object
|
||||
const baseTemplate = Template[data.base];
|
||||
|
||||
// Throw an error if the base template does not exists
|
||||
if (!baseTemplate) {
|
||||
throw new Error(`Template ${data.base} not found.`);
|
||||
}
|
||||
|
||||
// Declare the template object and name it as base name + 'Component'
|
||||
const template = OHIF.blaze.cloneTemplate(baseTemplate, data.base + 'Component');
|
||||
|
||||
// Extract the render function from the base template
|
||||
template.renderFunction = baseTemplate.renderFunction;
|
||||
|
||||
// Check for the mixins. If it's not informed set the lowest level mixin
|
||||
const mixins = data.mixins || 'component';
|
||||
|
||||
// Init the data manipulation mixins
|
||||
OHIF.Mixin.initData(data);
|
||||
|
||||
// Create and fill a list of wrappers that will enclose the component
|
||||
const wrappers = [];
|
||||
if (data.wrappers) {
|
||||
const wrappersList = data.wrappers.split(' ');
|
||||
_.each(wrappersList, wrapper => wrapper && wrappers.push(wrapper));
|
||||
}
|
||||
|
||||
// Declare a variable to store the wrapper instances that will be rendered
|
||||
const wrapperInstances = [];
|
||||
|
||||
// Declare the content function to render the component
|
||||
let contentFunction = () => {
|
||||
// Create the most inner content function
|
||||
const innerContentFunction = () => {
|
||||
// Assign properties to all wrappers after template's creation
|
||||
template.onCreated(() => {
|
||||
const instance = Template.instance();
|
||||
|
||||
// Assign the template most outer wrapper
|
||||
instance.wrapper = wrapperInstances[0] || instance;
|
||||
|
||||
// Iterate over all wrappers and assign the component to them
|
||||
wrapperInstances.forEach(wrappeInstance => {
|
||||
wrappeInstance.component = instance.component;
|
||||
});
|
||||
});
|
||||
|
||||
// Return the view instance
|
||||
return template.constructView(contentFunc, elseFunc);
|
||||
};
|
||||
|
||||
// Apply the mixins to the component
|
||||
OHIF.Mixin.initAll(template, data);
|
||||
|
||||
// Return the recursive function for wrappers
|
||||
return Blaze.With(data, innerContentFunction);
|
||||
};
|
||||
|
||||
let wrapper;
|
||||
while (wrapper = wrappers.shift()) {
|
||||
// Get the wrapper template
|
||||
const wrapperTemplate = Template[wrapper];
|
||||
|
||||
// Throw an error if the wrapper template does not exists
|
||||
if (!wrapperTemplate) {
|
||||
throw new Error(`Template ${data.base} not found.`);
|
||||
}
|
||||
|
||||
// Clone the wrapper template to avoid assigning duplicated handlers
|
||||
const currentTemplate = OHIF.blaze.cloneTemplate(wrapperTemplate);
|
||||
|
||||
// Store the child content function to render it inside the wrapper
|
||||
const childContentFunction = contentFunction;
|
||||
|
||||
// Create a function that will enable the recursion for wrappers
|
||||
const enclosingContentFunction = () => {
|
||||
// Add the current wrapper's instance to the wrapper instances list
|
||||
currentTemplate.onCreated(() => wrapperInstances.push(Template.instance()));
|
||||
|
||||
// Return the wrapper view instance with its child as content
|
||||
return currentTemplate.constructView(childContentFunction, elseFunc);
|
||||
};
|
||||
|
||||
// Replace the content function enclosing it recursively
|
||||
contentFunction = () => {
|
||||
return Blaze.With(data, enclosingContentFunction);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
return contentFunction(contentFunc, elseFunc);
|
||||
};
|
||||
3
Packages/ohif-core/components/base/templates/custom.html
Normal file
3
Packages/ohif-core/components/base/templates/custom.html
Normal file
@ -0,0 +1,3 @@
|
||||
<template name="baseCustom">
|
||||
{{>UI.contentBlock}}
|
||||
</template>
|
||||
9
Packages/ohif-core/components/base/templates/div.html
Normal file
9
Packages/ohif-core/components/base/templates/div.html
Normal file
@ -0,0 +1,9 @@
|
||||
<template name="baseDiv">
|
||||
<div
|
||||
id="{{this.id}}"
|
||||
class="{{this.class}}"
|
||||
{{this.tagAttributes}}
|
||||
>
|
||||
{{>UI.contentBlock}}
|
||||
</div>
|
||||
</template>
|
||||
16
Packages/ohif-core/components/base/templates/form.html
Normal file
16
Packages/ohif-core/components/base/templates/form.html
Normal file
@ -0,0 +1,16 @@
|
||||
<template name="baseForm">
|
||||
<form
|
||||
id="{{this.id}}"
|
||||
class="{{this.class}}"
|
||||
name="{{this.name}}"
|
||||
action="{{this.action}}"
|
||||
method="{{this.method}}"
|
||||
autocomplete="{{this.autocomplete}}"
|
||||
enctype="{{this.enctype}}"
|
||||
novalidate="{{this.novalidate}}"
|
||||
target="{{this.target}}"
|
||||
{{this.tagAttributes}}
|
||||
>
|
||||
{{>UI.contentBlock}}
|
||||
</form>
|
||||
</template>
|
||||
11
Packages/ohif-core/components/base/templates/input.html
Normal file
11
Packages/ohif-core/components/base/templates/input.html
Normal file
@ -0,0 +1,11 @@
|
||||
<template name="baseInput">
|
||||
<input
|
||||
type="{{choose this.type 'text'}}"
|
||||
id="{{this.id}}"
|
||||
class="{{this.class}}"
|
||||
name="{{this.name}}"
|
||||
value="{{reactive this.value}}"
|
||||
{{this.tagAttributes}}
|
||||
>
|
||||
{{>UI.contentBlock}}
|
||||
</template>
|
||||
16
Packages/ohif-core/components/base/templates/select.html
Normal file
16
Packages/ohif-core/components/base/templates/select.html
Normal file
@ -0,0 +1,16 @@
|
||||
<template name="baseSelect">
|
||||
<select
|
||||
id="{{this.id}}"
|
||||
class="{{this.class}}"
|
||||
name="{{this.name}}"
|
||||
{{this.tagAttributes}}
|
||||
>
|
||||
{{>UI.contentBlock}}
|
||||
{{#each item in (reactive this.items)}}
|
||||
<option
|
||||
value="{{item.value}}"
|
||||
selected="{{#if eq item.value (reactive this.value)}}selected{{/if}}"
|
||||
>{{item.label}}</option>
|
||||
{{/each}}
|
||||
</select>
|
||||
</template>
|
||||
11
Packages/ohif-core/components/base/wrappers/label.html
Normal file
11
Packages/ohif-core/components/base/wrappers/label.html
Normal file
@ -0,0 +1,11 @@
|
||||
<template name="wrapperLabel">
|
||||
<label class="wrapperLabel {{this.labelClass}}">
|
||||
{{#if this.labelAfter}}
|
||||
{{>UI.contentBlock}}
|
||||
{{/if}}
|
||||
<span class="wrapperLabelText">{{reactive this.label}}</span>
|
||||
{{#unless this.labelAfter}}
|
||||
{{>UI.contentBlock}}
|
||||
{{/unless}}
|
||||
</label>
|
||||
</template>
|
||||
11
Packages/ohif-core/components/base/wrappers/title.html
Normal file
11
Packages/ohif-core/components/base/wrappers/title.html
Normal file
@ -0,0 +1,11 @@
|
||||
<template name="wrapperTitle">
|
||||
<div class="wrapperTitle {{this.labelClass}}">
|
||||
{{#if this.labelAfter}}
|
||||
{{>UI.contentBlock}}
|
||||
{{/if}}
|
||||
<span class="wrapperTitleText">{{reactive this.label}}</span>
|
||||
{{#unless this.labelAfter}}
|
||||
{{>UI.contentBlock}}
|
||||
{{/unless}}
|
||||
</div>
|
||||
</template>
|
||||
8
Packages/ohif-core/components/bootstrap/form/form.html
Normal file
8
Packages/ohif-core/components/bootstrap/form/form.html
Normal file
@ -0,0 +1,8 @@
|
||||
<template name="form">
|
||||
{{#baseComponent (extend this
|
||||
base="baseForm"
|
||||
mixins=(concat "form " this.mixins)
|
||||
)}}
|
||||
{{>UI.contentBlock}}
|
||||
{{/baseComponent}}
|
||||
</template>
|
||||
8
Packages/ohif-core/components/bootstrap/form/group.html
Normal file
8
Packages/ohif-core/components/bootstrap/form/group.html
Normal file
@ -0,0 +1,8 @@
|
||||
<template name="group">
|
||||
{{#baseComponent (extend this
|
||||
base="baseDiv"
|
||||
mixins=(concat "group " this.mixins)
|
||||
)}}
|
||||
{{>UI.contentBlock}}
|
||||
{{/baseComponent}}
|
||||
</template>
|
||||
7
Packages/ohif-core/components/bootstrap/index.js
Normal file
7
Packages/ohif-core/components/bootstrap/index.js
Normal file
@ -0,0 +1,7 @@
|
||||
import './form/form.html';
|
||||
import './form/group.html';
|
||||
|
||||
import './input/groupRadio.html';
|
||||
import './input/radio.html';
|
||||
import './input/select.html';
|
||||
import './input/text.html';
|
||||
@ -0,0 +1,20 @@
|
||||
<template name="groupRadio">
|
||||
{{#group (extend this
|
||||
class=(concat 'form-group ' this.class)
|
||||
wrappers=(concat ''
|
||||
this.wrappers
|
||||
(valueIf reactive this.label 'wrapperTitle ' '')
|
||||
)
|
||||
)}}
|
||||
{{>UI.contentBlock}}
|
||||
{{#each item in (reactive this.items)}}
|
||||
{{>inputRadio
|
||||
class=this.radioClass
|
||||
name=this.key
|
||||
value=item.value
|
||||
label=item.label
|
||||
checked=(eq item.value (reactive this.value))
|
||||
}}
|
||||
{{/each}}
|
||||
{{/group}}
|
||||
</template>
|
||||
14
Packages/ohif-core/components/bootstrap/input/radio.html
Normal file
14
Packages/ohif-core/components/bootstrap/input/radio.html
Normal file
@ -0,0 +1,14 @@
|
||||
<template name="inputRadio">
|
||||
{{#baseComponent (extend this
|
||||
base='baseInput'
|
||||
mixins=(concat 'input ' this.mixins)
|
||||
labelAfter=(valueIf (isDefined this.labelAfter) this.labelAfter true)
|
||||
labelClass=(concat 'checkboxLabel' this.labelClass)
|
||||
wrappers=(concat ''
|
||||
this.wrappers
|
||||
(valueIf reactive this.label 'wrapperLabel ' '')
|
||||
)
|
||||
)}}
|
||||
{{>UI.contentBlock}}
|
||||
{{/baseComponent}}
|
||||
</template>
|
||||
13
Packages/ohif-core/components/bootstrap/input/select.html
Normal file
13
Packages/ohif-core/components/bootstrap/input/select.html
Normal file
@ -0,0 +1,13 @@
|
||||
<template name="inputSelect">
|
||||
{{#baseComponent (extend this
|
||||
base='baseSelect'
|
||||
class=(concat 'form-control ' this.class)
|
||||
mixins=(concat 'select ' this.mixins)
|
||||
wrappers=(concat ''
|
||||
this.wrappers
|
||||
(valueIf reactive this.label 'wrapperLabel ' '')
|
||||
)
|
||||
)}}
|
||||
{{>UI.contentBlock}}
|
||||
{{/baseComponent}}
|
||||
</template>
|
||||
13
Packages/ohif-core/components/bootstrap/input/text.html
Normal file
13
Packages/ohif-core/components/bootstrap/input/text.html
Normal file
@ -0,0 +1,13 @@
|
||||
<template name="inputText">
|
||||
{{#baseComponent (extend this
|
||||
base='baseInput'
|
||||
class=(concat 'form-control ' this.class)
|
||||
mixins=(concat 'input ' this.mixins)
|
||||
wrappers=(concat ''
|
||||
this.wrappers
|
||||
(valueIf reactive this.label 'wrapperLabel ' '')
|
||||
)
|
||||
)}}
|
||||
{{>UI.contentBlock}}
|
||||
{{/baseComponent}}
|
||||
</template>
|
||||
2
Packages/ohif-core/components/index.js
Normal file
2
Packages/ohif-core/components/index.js
Normal file
@ -0,0 +1,2 @@
|
||||
import './base';
|
||||
import './bootstrap';
|
||||
26
Packages/ohif-core/helpers/blaze.js
Normal file
26
Packages/ohif-core/helpers/blaze.js
Normal file
@ -0,0 +1,26 @@
|
||||
import { Template } from 'meteor/templating';
|
||||
import { Session } from 'meteor/session';
|
||||
import { ReactiveVar } from 'meteor/reactive-var';
|
||||
|
||||
/**
|
||||
* Global Blaze UI helpers to work with Blaze
|
||||
*/
|
||||
|
||||
// Return the current template instance
|
||||
Template.registerHelper('instance', () => {
|
||||
return Template.instance();
|
||||
});
|
||||
|
||||
// Return the session value for the given key
|
||||
Template.registerHelper('session', key => {
|
||||
return Session.get(key);
|
||||
});
|
||||
|
||||
// Return the value for given parameter regardless if it's reactive or not
|
||||
Template.registerHelper('reactive', parameter => {
|
||||
if (parameter instanceof ReactiveVar) {
|
||||
return parameter.get();
|
||||
}
|
||||
|
||||
return parameter;
|
||||
});
|
||||
59
Packages/ohif-core/helpers/data.js
Normal file
59
Packages/ohif-core/helpers/data.js
Normal file
@ -0,0 +1,59 @@
|
||||
import { _ } from 'meteor/underscore';
|
||||
import { Template } from 'meteor/templating';
|
||||
|
||||
/**
|
||||
* Global Blaze UI helpers to manipulate data
|
||||
*/
|
||||
|
||||
// Base extend function to be used by extend and clone helpers
|
||||
const extend = (...argsArray) => {
|
||||
// Create the resulting object
|
||||
const result = argsArray[0] || {};
|
||||
|
||||
// Extract the Spacebars kw hash
|
||||
const kwHash = _.last(argsArray).hash;
|
||||
|
||||
// Extract the given objects
|
||||
const objects = _.initial(argsArray);
|
||||
|
||||
// Iterate over the given objects
|
||||
_.each(objects, current => {
|
||||
// Stop here if the current argument is not an object
|
||||
if (typeof current !== 'object') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Extend the resulting object with the current argument object
|
||||
_.extend(result, current);
|
||||
});
|
||||
|
||||
// Extend the resulting object with the Spacebars kw hash
|
||||
_.extend(result, kwHash);
|
||||
|
||||
// Return the resulting object
|
||||
return result;
|
||||
};
|
||||
|
||||
// Extend the first argument object it with the other argument objects
|
||||
Template.registerHelper('extend', (...argsArray) => {
|
||||
return extend(...argsArray);
|
||||
});
|
||||
|
||||
// Create a new object and extends it with the argument objects
|
||||
Template.registerHelper('clone', (...argsArray) => {
|
||||
const newArgs = argsArray.slice();
|
||||
newArgs.unshift({});
|
||||
return extend(...newArgs);
|
||||
});
|
||||
|
||||
// Return the first thrut value in the given arguments
|
||||
Template.registerHelper('choose', (...argsArray) => {
|
||||
// Iterate over the given objects
|
||||
for (let i = 0; i < argsArray.length; i++) {
|
||||
// Check if the current value is truth
|
||||
if (!!argsArray[i]) {
|
||||
// Return the current value
|
||||
return argsArray[i];
|
||||
}
|
||||
}
|
||||
});
|
||||
4
Packages/ohif-core/helpers/index.js
Normal file
4
Packages/ohif-core/helpers/index.js
Normal file
@ -0,0 +1,4 @@
|
||||
import './blaze';
|
||||
import './data';
|
||||
import './logical';
|
||||
import './string';
|
||||
@ -1,3 +1,6 @@
|
||||
import { _ } from 'meteor/underscore';
|
||||
import { Template } from 'meteor/templating';
|
||||
|
||||
/**
|
||||
* Global Blaze UI helpers to work with logical operations
|
||||
*/
|
||||
@ -63,6 +66,15 @@ Template.registerHelper('choose', (...values) => {
|
||||
return result;
|
||||
});
|
||||
|
||||
// Return the second parameter if the first is true or the third if it's false
|
||||
Template.registerHelper('valueIf', (condition, valueIfTrue, valueIfFalse) => {
|
||||
if (condition) {
|
||||
return valueIfTrue;
|
||||
}
|
||||
|
||||
return valueIfFalse;
|
||||
});
|
||||
|
||||
// Check if the value is different from undefined
|
||||
Template.registerHelper('isDefined', value => {
|
||||
return typeof value !== 'undefined';
|
||||
16
Packages/ohif-core/helpers/string.js
Normal file
16
Packages/ohif-core/helpers/string.js
Normal file
@ -0,0 +1,16 @@
|
||||
import { _ } from 'meteor/underscore';
|
||||
import { Template } from 'meteor/templating';
|
||||
|
||||
/**
|
||||
* Global Blaze UI helpers to work with Strings
|
||||
*/
|
||||
|
||||
// Concatenate the give strings
|
||||
Template.registerHelper('concat', (...args) => {
|
||||
const values = _.initial(args, 1);
|
||||
let result = '';
|
||||
_.each(values, value => {
|
||||
result += value || '';
|
||||
});
|
||||
return result;
|
||||
});
|
||||
42
Packages/ohif-core/lib/blaze.js
Normal file
42
Packages/ohif-core/lib/blaze.js
Normal file
@ -0,0 +1,42 @@
|
||||
import { OHIF } from 'meteor/ohif:core';
|
||||
|
||||
OHIF.blaze = {};
|
||||
|
||||
// Clone a template and return the clone
|
||||
OHIF.blaze.cloneTemplate = (template, newName) => {
|
||||
if (!template){
|
||||
return;
|
||||
}
|
||||
|
||||
const name = newName || template.viewName;
|
||||
const clone = new Template(name, template.renderFunction);
|
||||
clone.inheritsEventsFrom(template);
|
||||
clone.inheritsHelpersFrom(template);
|
||||
clone.inheritsHooksFrom(template);
|
||||
return clone;
|
||||
};
|
||||
|
||||
// Navigate upwards the component and get the parent with the given view name
|
||||
OHIF.blaze.getParentView = (view, parentViewName) => {
|
||||
let currentView = view;
|
||||
while (currentView) {
|
||||
if (currentView.name === parentViewName) {
|
||||
break;
|
||||
}
|
||||
|
||||
currentView = currentView.originalParentView || currentView.parentView;
|
||||
}
|
||||
|
||||
return currentView;
|
||||
};
|
||||
|
||||
// Search for the parent component of the given view
|
||||
OHIF.blaze.getParentComponent = (view) => {
|
||||
let currentView = view;
|
||||
while (currentView) {
|
||||
currentView = currentView.originalParentView || currentView.parentView;
|
||||
if (currentView && currentView._component) {
|
||||
return currentView._component;
|
||||
}
|
||||
}
|
||||
};
|
||||
1
Packages/ohif-core/lib/index.js
Normal file
1
Packages/ohif-core/lib/index.js
Normal file
@ -0,0 +1 @@
|
||||
import './blaze.js';
|
||||
6
Packages/ohif-core/main.js
Normal file
6
Packages/ohif-core/main.js
Normal file
@ -0,0 +1,6 @@
|
||||
export { OHIF } from './ohif.js';
|
||||
|
||||
import './lib';
|
||||
import './components';
|
||||
import './helpers';
|
||||
import './ui';
|
||||
11
Packages/ohif-core/ohif.js
Normal file
11
Packages/ohif-core/ohif.js
Normal file
@ -0,0 +1,11 @@
|
||||
/*
|
||||
* Defines the base OHIF object
|
||||
*/
|
||||
|
||||
const OHIF = {};
|
||||
|
||||
if (Meteor.isDevelopment) {
|
||||
window.OHIF = OHIF;
|
||||
}
|
||||
|
||||
export { OHIF };
|
||||
15
Packages/ohif-core/package.js
Normal file
15
Packages/ohif-core/package.js
Normal file
@ -0,0 +1,15 @@
|
||||
Package.describe({
|
||||
name: 'ohif:core',
|
||||
summary: 'OHIF core components, helpers and UI functions',
|
||||
version: '0.0.1'
|
||||
});
|
||||
|
||||
Package.onUse(function(api) {
|
||||
api.versionsFrom('1.3.4.1');
|
||||
|
||||
api.use('ecmascript');
|
||||
api.use('standard-app-packages');
|
||||
api.use('jquery');
|
||||
|
||||
api.mainModule('main.js', 'client');
|
||||
});
|
||||
2
Packages/ohif-core/ui/index.js
Normal file
2
Packages/ohif-core/ui/index.js
Normal file
@ -0,0 +1,2 @@
|
||||
import './draggable/draggable.js';
|
||||
import './resizable/resizable.js';
|
||||
@ -11,7 +11,7 @@
|
||||
class="form-control js-form-update">
|
||||
{{#each option in allowedValues}}
|
||||
<option value="{{option}}"
|
||||
selected="{{#if equals selectedOptionValue option}}selected{{/if}}">
|
||||
selected="{{#if eq selectedOptionValue option}}selected{{/if}}">
|
||||
{{option}}
|
||||
</option>
|
||||
{{/each}}
|
||||
@ -20,4 +20,4 @@
|
||||
</div>
|
||||
{{ /with }}
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
@ -1,10 +0,0 @@
|
||||
import { Template } from 'meteor/templating';
|
||||
|
||||
/**
|
||||
* Compares two variables are equal in value
|
||||
*
|
||||
* @returns {boolean}
|
||||
*/
|
||||
Template.registerHelper('equals', function(a, b) {
|
||||
return a === b;
|
||||
});
|
||||
@ -1,35 +1,34 @@
|
||||
Package.describe({
|
||||
name: 'reactive-form-controls',
|
||||
summary: 'A set of basic form controls that store their state in a ReactiveDict',
|
||||
version: '0.0.1'
|
||||
});
|
||||
|
||||
Package.onUse(function(api) {
|
||||
api.versionsFrom('1.3.4.1');
|
||||
|
||||
api.use('standard-app-packages');
|
||||
api.use('ecmascript');
|
||||
api.use('jquery');
|
||||
api.use('stylus');
|
||||
api.use('reactive-dict');
|
||||
api.use('templating');
|
||||
api.use('natestrauser:select2@4.0.1', 'client');
|
||||
|
||||
api.addFiles('client/helpers/getSchema.js', ['client']);
|
||||
api.addFiles('client/helpers/isInvalidKey.js', ['client']);
|
||||
api.addFiles('client/helpers/stateDataWithKey.js', ['client']);
|
||||
api.addFiles('client/helpers/equals.js', ['client']);
|
||||
|
||||
api.addFiles('client/components/helpBlock/helpBlock.html', ['client']);
|
||||
api.addFiles('client/components/helpBlock/helpBlock.js', ['client']);
|
||||
|
||||
api.addFiles('client/components/radioOptionGroup/radioOptionGroup.html', ['client']);
|
||||
api.addFiles('client/components/radioOptionGroup/radioOptionGroup.js', ['client']);
|
||||
|
||||
api.addFiles('client/components/selectInput/selectInput.html', ['client']);
|
||||
api.addFiles('client/components/selectInput/selectInput.js', ['client']);
|
||||
|
||||
api.addFiles('client/components/select2Input/select2Input.html', ['client']);
|
||||
api.addFiles('client/components/select2Input/select2Input.js', ['client']);
|
||||
|
||||
});
|
||||
Package.describe({
|
||||
name: 'reactive-form-controls',
|
||||
summary: 'A set of basic form controls that store their state in a ReactiveDict',
|
||||
version: '0.0.1'
|
||||
});
|
||||
|
||||
Package.onUse(function(api) {
|
||||
api.versionsFrom('1.3.4.1');
|
||||
|
||||
api.use('standard-app-packages');
|
||||
api.use('ecmascript');
|
||||
api.use('jquery');
|
||||
api.use('stylus');
|
||||
api.use('reactive-dict');
|
||||
api.use('templating');
|
||||
api.use('natestrauser:select2@4.0.1', 'client');
|
||||
|
||||
api.addFiles('client/helpers/getSchema.js', ['client']);
|
||||
api.addFiles('client/helpers/isInvalidKey.js', ['client']);
|
||||
api.addFiles('client/helpers/stateDataWithKey.js', ['client']);
|
||||
|
||||
api.addFiles('client/components/helpBlock/helpBlock.html', ['client']);
|
||||
api.addFiles('client/components/helpBlock/helpBlock.js', ['client']);
|
||||
|
||||
api.addFiles('client/components/radioOptionGroup/radioOptionGroup.html', ['client']);
|
||||
api.addFiles('client/components/radioOptionGroup/radioOptionGroup.js', ['client']);
|
||||
|
||||
api.addFiles('client/components/selectInput/selectInput.html', ['client']);
|
||||
api.addFiles('client/components/selectInput/selectInput.js', ['client']);
|
||||
|
||||
api.addFiles('client/components/select2Input/select2Input.html', ['client']);
|
||||
api.addFiles('client/components/select2Input/select2Input.js', ['client']);
|
||||
|
||||
});
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
import { OHIF } from 'meteor/ohif:core';
|
||||
|
||||
toggleCinePlay = function() {
|
||||
var element = getActiveViewportElement();
|
||||
var playClipToolData = cornerstoneTools.getToolState(element, 'playClip');
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
import { OHIF } from 'meteor/ohif:core';
|
||||
|
||||
Template.gridLayout.helpers({
|
||||
height: function() {
|
||||
var rows = this.rows || 1;
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
import { OHIF } from 'meteor/ohif:core';
|
||||
|
||||
var allCornerstoneEvents = 'CornerstoneToolsMouseDown CornerstoneToolsMouseDownActivate ' +
|
||||
'CornerstoneToolsMouseClick CornerstoneToolsMouseDrag CornerstoneToolsMouseUp ' +
|
||||
'CornerstoneToolsMouseWheel CornerstoneToolsTap CornerstoneToolsTouchPress ' +
|
||||
@ -115,7 +117,7 @@ function loadSeriesIntoViewport(data, templateData) {
|
||||
templateData.imageId = imageId;
|
||||
|
||||
// Save the current image ID inside the ViewportLoading object.
|
||||
//
|
||||
//
|
||||
// The ViewportLoading object relates the viewport elements with whichever
|
||||
// image is currently being loaded into them. This is useful so that we can
|
||||
// place progress (download %) for each image inside the proper viewports.
|
||||
@ -144,7 +146,7 @@ function loadSeriesIntoViewport(data, templateData) {
|
||||
}
|
||||
|
||||
// Update the enabled element with the image and viewport data
|
||||
// This is not usually necessary, but we need them stored in case
|
||||
// This is not usually necessary, but we need them stored in case
|
||||
// a sopClassUid-specific viewport setting is present.
|
||||
enabledElement.image = image;
|
||||
enabledElement.viewport = cornerstone.getDefaultViewport(enabledElement.canvas, image);
|
||||
@ -564,4 +566,4 @@ Template.imageViewerViewport.events({
|
||||
var viewportIndex = $('.imageViewerViewport').index(e.currentTarget);
|
||||
layoutManager.toggleEnlargement(viewportIndex);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
import { OHIF } from 'meteor/ohif:core';
|
||||
|
||||
Meteor.startup(function() {
|
||||
cornerstoneTools.loadHandlerManager.setStartLoadHandler(startLoadingHandler);
|
||||
cornerstoneTools.loadHandlerManager.setEndLoadHandler(doneLoadingHandler);
|
||||
@ -67,4 +69,4 @@ Template.loadingIndicator.helpers({
|
||||
return percentComplete + '%';
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
import { OHIF } from 'meteor/ohif:core';
|
||||
|
||||
toggleCinePlay = function(element) {
|
||||
var viewports = $('.imageViewerViewport');
|
||||
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
import { OHIF } from 'meteor/ohif:core';
|
||||
|
||||
function getDefaultButtonData() {
|
||||
var buttonData = [];
|
||||
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
import { OHIF } from 'meteor/ohif:core';
|
||||
|
||||
applyWLPreset = function(presetName, element) {
|
||||
log.info("Applying WL Preset: " + presetName);
|
||||
var viewport = cornerstone.getViewport(element);
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
import { OHIF } from 'meteor/ohif:core';
|
||||
|
||||
/**
|
||||
* This function disables reference lines for a specific viewport element.
|
||||
* It also enables reference lines for all other viewports with the
|
||||
* It also enables reference lines for all other viewports with the
|
||||
* class .imageViewerViewport.
|
||||
*
|
||||
* @param element {node} DOM Node representing the viewport element
|
||||
@ -36,4 +38,4 @@ displayReferenceLines = function(element) {
|
||||
|
||||
cornerstoneTools.referenceLines.tool.enable(element, OHIF.viewer.updateImageSynchronizer);
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
OHIF = window.OHIF || {};
|
||||
import { OHIF } from 'meteor/ohif:core';
|
||||
|
||||
Meteor.startup(function() {
|
||||
|
||||
@ -31,7 +31,7 @@ Meteor.startup(function() {
|
||||
WLPresetBone: ['NUMPAD4', '4'],
|
||||
WLPresetBrain: ['NUMPAD5', '5']
|
||||
};
|
||||
|
||||
|
||||
// For now
|
||||
OHIF.viewer.hotkeys = OHIF.viewer.defaultHotkeys;
|
||||
|
||||
@ -262,7 +262,7 @@ function bindHotkey(hotkey, task) {
|
||||
} else {
|
||||
fn = hotkeyFunctions[task];
|
||||
|
||||
// If the function doesn't exist in the
|
||||
// If the function doesn't exist in the
|
||||
// hotkey function list, try the viewer-specific function list
|
||||
if (!fn && OHIF.viewer && OHIF.viewer.functionList) {
|
||||
fn = OHIF.viewer.functionList[task];
|
||||
|
||||
@ -1,38 +0,0 @@
|
||||
// Return the current template instance
|
||||
Template.registerHelper('instance', () => {
|
||||
return Template.instance();
|
||||
});
|
||||
|
||||
// Return the session value for the given key
|
||||
Template.registerHelper('session', key => {
|
||||
return Session.get(key);
|
||||
});
|
||||
|
||||
// Create a new object and extends it with the argument objects
|
||||
Template.registerHelper('extend', (...argsArray) => {
|
||||
// Create the resulting object
|
||||
const result = {};
|
||||
|
||||
// Extract the Spacebars kw hash
|
||||
const kwHash = _.last(argsArray).hash;
|
||||
|
||||
// Extract the given objects
|
||||
const objects = _.initial(argsArray);
|
||||
|
||||
// Iterate over the given objects
|
||||
_.each(objects, current => {
|
||||
// Stop here if the current argument is not an object
|
||||
if (typeof current !== 'object') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Extend the resulting object with the current argument object
|
||||
_.extend(result, current);
|
||||
});
|
||||
|
||||
// Extend the resulting object with the Spacebars kw hash
|
||||
_.extend(result, kwHash);
|
||||
|
||||
// Return the resulting object
|
||||
return result;
|
||||
});
|
||||
@ -1,3 +1,5 @@
|
||||
import { OHIF } from 'meteor/ohif:core';
|
||||
|
||||
var activeTool = 'wwwc';
|
||||
var defaultTool = 'wwwc';
|
||||
|
||||
|
||||
@ -117,9 +117,6 @@ Package.onUse(function(api) {
|
||||
api.addFiles('lib/toolManager.js', 'client');
|
||||
api.addFiles('lib/enablePrefetchOnElement.js', 'client');
|
||||
api.addFiles('lib/displayReferenceLines.js', 'client');
|
||||
api.addFiles('lib/ui/draggable/draggable.js', 'client');
|
||||
api.addFiles('lib/ui/resizable/resizable.js', 'client');
|
||||
api.addFiles('lib/ui/resizable/resizable.styl', 'client');
|
||||
api.addFiles('lib/toggleDialog.js', 'client');
|
||||
api.addFiles('lib/setActiveViewport.js', 'client');
|
||||
api.addFiles('lib/switchToImageByIndex.js', 'client');
|
||||
@ -168,7 +165,6 @@ Package.onUse(function(api) {
|
||||
api.export('LayoutManager', 'client');
|
||||
|
||||
// Global objects
|
||||
api.export('OHIF', 'client');
|
||||
api.export('ClientId', 'client');
|
||||
|
||||
// Collections
|
||||
@ -177,8 +173,6 @@ Package.onUse(function(api) {
|
||||
// UI Helpers
|
||||
api.addFiles([
|
||||
'lib/helpers/formatDA.js',
|
||||
'lib/helpers/blaze.js',
|
||||
'lib/helpers/logical.js',
|
||||
'lib/helpers/formatJSDate.js',
|
||||
'lib/helpers/jsDateFromNow.js',
|
||||
'lib/helpers/formatNumberPrecision.js',
|
||||
|
||||
Loading…
Reference in New Issue
Block a user