LT-275: Creating measure flow component common section

This commit is contained in:
Bruno Alves de Faria 2016-08-03 11:13:48 -03:00
parent 9a8eaff560
commit bbb7dad905
60 changed files with 391 additions and 156 deletions

View File

@ -8,50 +8,63 @@ $gray4 = #C0C0C0
$gray5 = #9B9B9B
$gray6 = #303030
.select-tree
background-color: white
.select-tree-root
&, a.tree-back, .tree-breadcrumb span, .tree-node, .tree-leaf
transition(all 0.3s ease)
.tree-content
background-color: white
position: relative
&
.tree-search
a.tree-back
.tree-breadcrumb span
.tree-node
.tree-leaf
transition(all 0.3s ease)
&.selected
label.tree-leaf.active
box-shadow: 0 0 0 10px white, inset 0 0 0 200px white
.tree-content
background-color: transparent
&>.tree-content
border-color: transparent
border-radius: 0
.tree-search
opacity: 0
&, .select-tree
&:not(.open)>.tree-content
&>.tree-inputs
&>.tree-breadcrumb
display: none
&>.tree-content>.tree-options
&>.tree-inputs>label:not(.active)
&>.tree-breadcrumb a
&>.tree-breadcrumb span
color: transparent
&>.tree-inputs>label.tree-node:not(.active)
border-color: transparent
.select-tree-root
&>*:first-child
transition(all 0.3s ease)
.select-tree-root.selected
border-color: transparent
border-radius: 0
// height: 26px
&, .select-tree
background-color: transparent
&:not(.open)>.tree-options
&>.tree-inputs, &>.tree-breadcrumb
display: none
&.open>.tree-options
&>.tree-inputs>label:not(.active), &>.tree-breadcrumb a, &>.tree-breadcrumb span
color: transparent
&>.tree-inputs>label.tree-node:not(.active)
border-color: transparent
.tree-search
opacity: 0
&>.tree-options
background-color: transparent
label.tree-leaf.active
box-shadow: 0 0 0 10px white, inset 0 0 0 200px white
.select-tree-root
border: 1px solid $gray3
border-radius: 5px
display: inline-block
overflow: hidden
position: relative
&>.tree-options
&>.tree-content
border: 1px solid $gray3
border-radius: 5px
overflow: hidden
&>.tree-content>.tree-options
transform(scale(1))
transition(height 0.3s ease)
@ -89,10 +102,16 @@ $gray6 = #303030
.select-tree-node
left: 0
overflow: hidden
position: fixed
width: 100%
z-index: 2
&
.tree-content
.tree-inputs
height: 100%
.tree-options
overflow: hidden
position: relative
@ -129,5 +148,87 @@ $gray6 = #303030
transition(box-shadow 0.3s ease)
z-index: 0
&:last-child:after
display: block
content: ''
height: 10px
&.collapsed
z-index: 2
z-index: 1
.select-tree-common
height: 100%
overflow: hidden
padding-left: 6px
position: absolute
right: -100%
top: 0
width: 100%
.content
background-color: $gray6
border: 1px solid $gray5
border-radius: 5px
color: white
opacity: 0.9
padding: 5px 12px 12px
position: absolute
top: 50%
transform(translateY(-50%))
width: calc(100% - 6px)
h5.title
color: $gray5
font-size: 12px
font-weight: normal
line-height: 20px
margin: 0
.select-tree-root
&>.tree-content
transform(scale(0))
transform-origin(100% 50%)
transition(all 0.3s ease)
.select-tree-common .content
margin-left: calc(-100% - 6px)
transition(all 0.3s ease 0.3s)
&.started
&>.tree-content
transform(scale(1))
.select-tree-common .content
margin-left: 0
&.interacted
.select-tree-common
overflow: visible
.content
animation-name: selectTreeCommonCloseLeft
animation-duration: 0.3s
animation-iteration-count: 1
animation-direction: alternate
animation-timing-function: ease-out
animation-fill-mode: forwards
@keyframes selectTreeCommonCloseLeft {
from {
height: 37px
display: table
margin-left: 0
opacity: 1
visibility: visible
}
to {
height: 100%
margin-left: calc(-100% - 6px)
opacity: 0
visibility: hidden
width: calc(100% - 6px)
}
}

View File

@ -0,0 +1,93 @@
<template name="selectTree">
{{#group (extend this
class=(concat
'select-tree '
(valueIf this.root '' 'select-tree-root ')
this.class
)
mixins=(concat 'selectTree ' this.mixins)
)}}
{{>UI.contentBlock}}
<div class="tree-content">
{{#let currentNode=this.currentNode.get}}
{{#if (and (not this.root) (ne this.search false))}}
{{>inputText
label=this.label
labelClass='tree-search'
placeholder=(choose this.searchPlaceholder 'Search')
}}
{{/if}}
<div class="tree-options {{#if currentNode}}collapsed{{/if}}">
{{#if this.root}}
{{>selectTreeBreadcrumb component=this.component}}
{{/if}}
<div class="tree-inputs">
{{#each item in (reactive this.items)}}
{{>inputRadio
class=this.radioClass
name=this.key
value=item.value
label=item.label
labelClass=(valueIf (isArray item.items) 'tree-node' 'tree-leaf')
checked=(eq item.value (reactive this.value))
}}
{{/each}}
</div>
{{#if (and currentNode (isArray currentNode.items))}}
{{>selectTree (clone this
items=currentNode.items
root=(choose this.root this.component)
class='select-tree-node'
)}}
{{/if}}
</div>
{{/let}}
</div>
{{#unless this.root}}
{{>selectTreeCommon this}}
{{/unless}}
{{/group}}
</template>
<template name="selectTreeCommon">
<div class="select-tree-common">
<div class="content">
<h5 class="title">Common</h5>
</div>
</div>
</template>
<template name="selectTreeBreadcrumb">
<div class="tree-breadcrumb clearfix">
{{>selectTreeBreadcrumbParent
component=this.component.parent
index=1
}}
{{#let currentNode=this.component.parent.templateInstance.data.currentNode.get}}
<span class="tree-current-node">{{currentNode.label}}</span>
{{/let}}
</div>
</template>
<template name="selectTreeBreadcrumbParent">
{{#let parent=this.component.parent}}
{{#let parentNode=(reactive parent.templateInstance.data.currentNode)}}
{{#if parentNode}}
{{>selectTreeBreadcrumbParent
component=parent
index=(sum this.index 1)
}}
{{/if}}
<span class="path-link">
<a href="#" class="tree-back" data-index="{{this.index}}">
{{#if parentNode}}
<span>{{parentNode.label}}</span>
{{else}}
<i class="fa fa-fast-backward"></i>
{{/if}}
</a>
{{#if parentNode}}<span>/</span>{{/if}}
</span>
{{/let}}
{{/let}}
</template>

View File

@ -4,16 +4,20 @@ import { _ } from 'meteor/underscore';
import { $ } from 'meteor/jquery';
// TODO: use npm dependency
import transition from 'meteor/ohif:core/lib/third-party/transition-to-from-auto';
import transition from 'meteor/ohif:core/client/lib/third-party/transition-to-from-auto';
Template.selectTree.onRendered(() => {
const instance = Template.instance();
const component = instance.$('.select-tree:first').data('component');
const rootComponent = instance.data.root || component;
const rootInstance = rootComponent.templateInstance;
const $treeRoot = rootInstance.$('.select-tree-root:first').first();
instance.component = component;
// Start the component transitions
$treeRoot.addClass('started');
// Update the component's viewport height
instance.updateHeight = () => {
const height = rootInstance.$('.tree-options:last').data('height');
@ -28,18 +32,9 @@ Template.selectTree.onRendered(() => {
// Put the component in selected state
instance.setSelected = (flag) => {
const $treeRoot = rootInstance.$('.select-tree-root:first').first();
const $firstChild = $treeRoot.children().first();
if (flag) {
const search = rootInstance.$('.tree-search').outerHeight() | 0;
const leaf = $treeRoot.find('.tree-leaf.active').position().top;
const martinTop = search + leaf;
// $firstChild.css('margin-top', -martinTop);
// $treeRoot.css('margin-top', martinTop).addClass('selected');
$treeRoot.addClass('selected');
} else {
// $treeRoot.removeClass('selected').css('margin-top', '');
// $firstChild.css('margin-top', '');
$treeRoot.removeClass('selected');
}
};
@ -60,7 +55,7 @@ Template.selectTree.onRendered(() => {
});
});
const selector = '.select-tree:first>.tree-options>.tree-breadcrumb .path-link';
const selector = '.select-tree:first>.tree-content>.tree-options>.tree-breadcrumb .path-link';
instance.$(selector).css('width', 0).each((index, element) => {
transition({
element: element,
@ -72,7 +67,12 @@ Template.selectTree.onRendered(() => {
});
Template.selectTree.events({
'change .select-tree:first>.tree-options>.tree-inputs>label>input'(event, instance) {
'click .select-tree-root'(event, instance) {
// Detect the first interaction with the component and do the animation
$(event.currentTarget).addClass('interacted');
},
'change .select-tree:first>.tree-content>.tree-options>.tree-inputs>label>input'(event, instance) {
const component = instance.component;
const $target = $(event.target);
const $label = $target.closest('label');
@ -111,7 +111,7 @@ Template.selectTree.events({
}
},
'click .select-tree:first>.tree-options>.tree-breadcrumb .tree-back'(event, instance) {
'click .select-tree:first>.tree-content>.tree-options>.tree-breadcrumb .tree-back'(event, instance) {
const rootComponent = instance.data.root || instance.component;
const rootInstance = rootComponent.templateInstance;

View File

@ -0,0 +1,6 @@
import './lib';
import './components';
import './helpers';
import './ui';
import './routes.js';

View File

@ -1,2 +1,3 @@
import './blaze.js';
import './string.js';
import './user.js';

View File

@ -0,0 +1,32 @@
import { OHIF } from 'meteor/ohif:core';
OHIF.user = {};
// Throw error if there is no user logged in
OHIF.user.validate = () => {
if (!Meteor.userId()) {
throw new Meteor.Error('not-authorized');
}
};
// Get the persistent data by key
OHIF.user.getData = key => {
// Check if there is an user logged in
OHIF.user.validate();
// Get the user persistent data
const data = Meteor.user().profile.persistent;
if (data) {
return data[key];
}
};
// Store the persistent data by giving a key and a value to store
OHIF.user.setData = (key, value) => {
// Check if there is an user logged in
OHIF.user.validate();
// Call the update method on server-side
Meteor.call('userDataSet', key, value);
};

View File

@ -0,0 +1,5 @@
import { Router } from 'meteor/clinical:router';
Router.route('/playground', function() {
this.render('componentPlayground');
});

View File

@ -1,80 +0,0 @@
<template name="selectTree">
{{#group (extend this
class=(concat
'select-tree '
(valueIf this.root '' 'select-tree-root ')
this.class
)
mixins=(concat 'selectTree ' this.mixins)
)}}
{{>UI.contentBlock}}
{{#let currentNode=this.currentNode.get}}
{{#if (and (not this.root) (ne this.search false))}}
{{>inputText
label=this.label
labelClass='tree-search'
placeholder=(choose this.searchPlaceholder 'Search')
}}
{{/if}}
<div class="tree-options {{#if currentNode}}collapsed{{/if}}">
{{#if this.root}}
{{>selectTreeBreadcrumb component=this.component}}
{{/if}}
<div class="tree-inputs">
{{#each item in (reactive this.items)}}
{{>inputRadio
class=this.radioClass
name=this.key
value=item.value
label=item.label
labelClass=(valueIf (isArray item.items) 'tree-node' 'tree-leaf')
checked=(eq item.value (reactive this.value))
}}
{{/each}}
</div>
{{#if (and currentNode (isArray currentNode.items))}}
{{>selectTree (clone this
items=currentNode.items
root=(choose this.root this.component)
class='select-tree-node'
)}}
{{/if}}
</div>
{{/let}}
{{/group}}
</template>
<template name="selectTreeBreadcrumb">
<div class="tree-breadcrumb clearfix">
{{>selectTreeBreadcrumbParent
component=this.component.parent
index=1
}}
{{#let currentNode=this.component.parent.templateInstance.data.currentNode.get}}
<span class="tree-current-node">{{currentNode.label}}</span>
{{/let}}
</div>
</template>
<template name="selectTreeBreadcrumbParent">
{{#let parent=this.component.parent}}
{{#let parentNode=(reactive parent.templateInstance.data.currentNode)}}
{{#if parentNode}}
{{>selectTreeBreadcrumbParent
component=parent
index=(sum this.index 1)
}}
{{/if}}
<span class="path-link">
<a href="#" class="tree-back" data-index="{{this.index}}">
{{#if parentNode}}
<span>{{parentNode.label}}</span>
{{else}}
<i class="fa fa-fast-backward"></i>
{{/if}}
</a>
{{#if parentNode}}<span>/</span>{{/if}}
</span>
{{/let}}
{{/let}}
</template>

View File

@ -1,13 +1,12 @@
export { OHIF } from './ohif.js';
/*
* Defines the base OHIF object
*/
import { Meteor } from 'meteor/meteor';
import { Router } from 'meteor/clinical:router';
const OHIF = {};
import './lib';
import './components';
import './helpers';
import './ui';
// Expose the OHIF object to the client if it is on development mode
if (Meteor.isDevelopment && Meteor.isClient) {
window.OHIF = OHIF;
}
Router.route('/playground', function() {
this.render('componentPlayground');
});
export { OHIF };

View File

@ -1,11 +0,0 @@
/*
* Defines the base OHIF object
*/
const OHIF = {};
if (Meteor.isDevelopment) {
window.OHIF = OHIF;
}
export { OHIF };

View File

@ -23,8 +23,15 @@ Package.onUse(function(api) {
// UI Styles
api.addFiles([
'ui/resizable/resizable.styl'
'client/ui/resizable/resizable.styl'
], 'client');
api.mainModule('main.js', 'client');
api.mainModule('main.js', ['client', 'server']);
// Client imports and routes
api.addFiles('client/index.js', 'client');
// Server imports and methods
api.addFiles('server/index.js', 'server');
});

View File

@ -0,0 +1,2 @@
import './mongo.js';
import './user.js';

View File

@ -0,0 +1,26 @@
import { OHIF } from 'meteor/ohif:core';
import { Meteor } from 'meteor/meteor';
// Mongo data manipulation utilities
class MongoUtils {
// Check if there is an user logged in
static validateUser() {
// Throw error if there is no user logged in
if (!Meteor.userId()) {
throw new Meteor.Error('not-authorized');
}
}
// Generic callback to MongoDB write operations
static writeCallback(error, affected) {
// Throw error if it was not possible to complete the write operation
if (error) {
throw new Meteor.Error('data-write', error);
}
}
}
// Expose the class in the OHIF object
OHIF.MongoUtils = MongoUtils;

View File

@ -0,0 +1,54 @@
import { OHIF } from 'meteor/ohif:core';
import { Meteor } from 'meteor/meteor';
// Manipulate user's persistent data
class UserData {
// Get the persistent data by key
static get(key) {
// Check if there is an user logged in
OHIF.MongoUtils.validateUser();
// Get the user's profile data
const profileData = Meteor.user().profile;
// Return the data if it is set
if (profileData.persistent) {
return profileData.persistent[key];
}
}
// Store the persistent data by giving a key and a value to store
static set(key, value) {
// Check if there is an user logged in
OHIF.MongoUtils.validateUser();
// Build the query to update only the current user's data
var query = {
_id: Meteor.userId()
};
// Build the path to the persistent data with the given key
const persistentPath = `profile.persistent.${key}`;
// Build the data to be updated
var data = {
$set: {
[persistentPath]: value
}
};
// Update the user's profile data with the persistent information
Accounts.users.update(query, data, OHIF.MongoUtils.writeCallback);
}
}
// Register the methods
Meteor.methods({
userDataGet: key => UserData.get(key),
userDataSet: (key, value) => UserData.set(key, value)
});
// Expose the class in the OHIF object
OHIF.UserData = UserData;