Adapting header to the new structure

This commit is contained in:
Bruno Alves de Faria 2017-03-13 18:24:34 -03:00
parent 2d52c9ef0a
commit e83b5348ff
34 changed files with 395 additions and 154 deletions

View File

@ -28,6 +28,7 @@ aldeed:simple-schema # Third party package to deal with schemas
# OHIF Packages
ohif:design
ohif:core
ohif:header
ohif:cornerstone
ohif:viewerbase
ohif:study-list

View File

@ -92,6 +92,7 @@ ohif:cornerstone@0.0.1
ohif:design@0.0.1
ohif:dicom-services@0.0.1
ohif:hanging-protocols@0.0.1
ohif:header@0.0.1
ohif:lesiontracker@0.0.1
ohif:log@0.0.1
ohif:measurements@0.0.1

View File

@ -1,24 +1,26 @@
<template name="app">
<div class="topBar noselect {{#if onStudyList}}studyList{{/if}}">
<div class="clearfix">
<a target='_blank'
class="brandSection pull-left"
href="http://ohif.org">
<svg class="logoImage">
<use xlink:href={{absoluteUrl "packages/ohif_viewerbase/assets/icons.svg#icon-ohif-logo"}}></use>
</svg>
<div class="logoText">Open Health Imaging Foundation</div>
</a>
{{#header brandHref='http://ohif.org' headerClasses=instance.headerClasses}}
{{#section 'brand'}}
<svg class="logo-image">
<use xlink:href={{absoluteUrl "packages/ohif_viewerbase/assets/icons.svg#icon-ohif-logo"}}></use>
</svg>
<div class="logo-text">Open Health Imaging Foundation</div>
{{/section}}
{{#section 'headerAfterBrand'}}
{{#if studyListToggleText}}
<a class="btn studyListLinkSection pull-left js-toggle-studyList" id="{{dasherize studyListToggleText}}-btn">
{{studyListToggleText}}
</a>
{{/if}}
<div class="userAccountSection pull-right">
{{>userAccountMenu}}
{{/section}}
{{#section 'headerMenu'}}
<span class="user-name pull-left m-r-1">{{userName}}</span>
<div class="menu-toggle pull-right">
<i class="fa fa-cog"></i>
<span class="caret-down"></span>
</div>
</div>
</div>
{{/section}}
{{/header}}
<div id="studylistTabs" class="tab-content">
<div class="tab-pane active" id="studylistTab">
<div class="studylistContainer">

View File

@ -1,3 +1,6 @@
import { Template } from 'meteor/templating';
import { Session } from 'meteor/session';
import { ReactiveVar } from 'meteor/reactive-var';
import { OHIF } from 'meteor/ohif:core';
const studylistContentId = 'studylistTab';
@ -7,12 +10,50 @@ const viewerContentId = 'viewerTab';
// If there is currently any Session data for this object,
// use this to repopulate the variable
Template.app.onCreated(() => {
const instance = Template.instance();
instance.headerClasses = new ReactiveVar('');
ViewerData = Session.get('ViewerData') || {};
OHIF.header.setDropdownItems([{
action: OHIF.user.audit,
text: 'View Audit Log',
iconClasses: 'log',
iconSvgUse: 'packages/ohif_user-management/assets/user-menu-icons.svg#log',
separatorAfter: true
}, {
action: () => OHIF.ui.showDialog('themeSelectorModal'),
text: 'Themes',
iconClasses: 'theme',
iconSvgUse: 'packages/ohif_user-management/assets/user-menu-icons.svg#theme',
separatorAfter: true
}, {
action: () => OHIF.ui.showDialog('serverInformationModal'),
text: 'Server Information',
iconClasses: 'server',
iconSvgUse: 'packages/ohif_user-management/assets/user-menu-icons.svg#server',
separatorAfter: true
}, {
action: OHIF.user.changePassword,
text: 'Change Password',
iconClasses: 'password',
iconSvgUse: 'packages/ohif_user-management/assets/user-menu-icons.svg#password'
}, {
action: OHIF.user.logout,
text: 'Logout',
iconClasses: 'logout',
iconSvgUse: 'packages/ohif_user-management/assets/user-menu-icons.svg#logout'
}]);
instance.autorun(() => {
const contentId = Session.get('activeContentId');
instance.headerClasses.set(contentId === viewerContentId ? '' : 'header-big');
});
});
Template.app.onRendered(() => {
const contentId = Session.get('activeContentId');
if(contentId === viewerContentId) {
if (contentId === viewerContentId) {
switchToTab(contentId);
}
});
@ -56,9 +97,11 @@ Template.app.events({
});
Template.app.helpers({
userName: OHIF.user.getName,
studyListToggleText() {
const contentId = Session.get('activeContentId');
// If the Viewer has not been opened yet, 'Back to viewer' should
// not be displayed
const viewerContentExists = !!Object.keys(ViewerData).length;
@ -82,4 +125,4 @@ Template.app.helpers({
}
});
Session.set('defaultSignInMessage', 'Tumor tracking in your browser.');
Session.set('defaultSignInMessage', 'Tumor tracking in your browser.');

View File

@ -1,45 +1,46 @@
@import "{ohif:design}/app"
$expandedHeight = 160px
body>.header
.logoImage
display: inline-block
height: 100%
float: left
.topBar
height: $topBarHeight
padding: 10px 10px 0
theme('color', '$textPrimaryColor')
theme('background-color', '$primaryBackgroundColor')
transition(all 0.5s ease)
&>.clearfix
position: relative
.brandSection
.brand
height: 30px
display: inline-block
text-decoration: none
.logoImage
.logo-image
display: inline-block
fill: transparent
float: left
height: 100%
margin: 0 8px 0 0
width: 30px
.logoText
.logo-text
display: inline-block
font-family: $logoFontFamily
font-size: 14px
font-weight: $logoFontWeight
theme('color', '$textPrimaryColor')
line-height: 30px
.studyListLinkSection
theme('border-left', '%s solid $uiBorderColor' % $uiBorderThickness)
margin: 3px 0 0 10px
padding: 0 0 0 10px
&#back-to-viewer-btn
border-left: 0
.header-menu
.user-name
font-size: 13px
.menu-toggle
theme('border-left', 'solid 1px $defaultColor')
display: inline-block
height: 18px
padding: 0 8px
.fa
theme('color', '$defaultColor')
font-size: 17px
line-height: 18px
.caret-down
theme('color', '$uiGrayLight')
margin: 0 4px 4px 2px
.btn
theme('color', '$textSecondaryColor')
@ -54,23 +55,29 @@ $expandedHeight = 160px
&:active
theme('color', '$activeColor')
&.studyList
background-color: rgba(21, 25, 30, 0.7)
height: $expandedHeight
.studyListLinkSection
theme('border-left', '%s solid $uiBorderColor' % $uiBorderThickness)
margin: 3px 0 0 10px
padding: 0 0 0 10px
&#back-to-viewer-btn
border-left: 0
&.header-big
padding-left: $studyListPadding
padding-right: $studyListPadding
.brandSection
height: 100%
width: 80%
line-height: $expandedHeight - 10px
.brand
height: 100%
width: 80%
line-height: $topBarExpandedHeight - 10px
.logoImage
width: 50px
margin: 0 20px 0 0
.logo-image
margin: 0 20px 0 0
width: 50px
.logoText
font-size: 30px
.logo-text
font-size: 30px
.studyListLinkSection
border: none

View File

@ -31,14 +31,17 @@ OHIF.mixins.action = new OHIF.Mixin({
// Stop here calling the action if it's a function
if (typeof action === 'function') {
return action.call(this, params);
component.actionResult = action.call(this, params);
return component.actionResult;
}
// Stop here if no API or action was defined
if (!api || !action || typeof api[action] !== 'function') return;
// Call the defined action function
api[action].call(this, params);
component.actionResult = api[action].call(this, params);
return component.actionResult;
}
}
}

View File

@ -1,6 +1,7 @@
import { Meteor } from 'meteor/meteor';
import { Template } from 'meteor/templating';
import { Blaze } from 'meteor/blaze';
import { $ } from 'meteor/jquery';
import { OHIF } from 'meteor/ohif:core';
/*
@ -11,7 +12,7 @@ OHIF.mixins.dropdown = new OHIF.Mixin({
composition: {
onRendered() {
const instance = Template.instance();
const { event, centered } = instance.data.options;
const { event, centered, marginTop } = instance.data.options;
// Destroy the Blaze created view (either created with template calls or with renderWithData)
instance.destroyView = () => {
@ -22,6 +23,12 @@ OHIF.mixins.dropdown = new OHIF.Mixin({
}
};
// Stop here and destroy the view if no items was given
if (!instance.data.items.length) {
instance.data.promiseReject();
return instance.destroyView();
}
// Get the dropdown element to enable position manipulation
const $dropdown = instance.$('.dropdown');
const dropdown = $dropdown[0];
@ -29,20 +36,22 @@ OHIF.mixins.dropdown = new OHIF.Mixin({
dropdown.oncontextmenu = () => false;
const cssBefore = {
'z-index': 10000
};
const cssBefore = { 'z-index': 10000 };
if (event) {
cssBefore.position = 'fixed';
$dropdownMenu.bounded();
}
$dropdownMenu.css(cssBefore).focus();
if (marginTop) {
cssBefore['margin-top'] = marginTop;
}
$dropdownMenu.css(cssBefore);
// Postpone visibility change to allow CSS transitions
Meteor.defer(() => {
// Show the dropdown
$dropdown.addClass('open');
// Show the dropdown and focus the first option
$dropdown.addClass('open').find('a:first').focus();
// Change the dropdown position if mouse event was given
if (event) {
@ -62,9 +71,18 @@ OHIF.mixins.dropdown = new OHIF.Mixin({
},
events: {
'click .form-action.disabled'(event, instance) {
event.preventDefault();
'click .form-action'(event, instance) {
event.stopPropagation();
const $target = $(event.currentTarget);
const isDisabled = $target.hasClass('disabled');
if (isDisabled) {
instance.data.promiseReject();
} else {
const component = $target.data('component');
instance.data.promiseResolve(component.actionResult);
}
instance.destroyView();
},
'click .dropdown'(event, instance) {
@ -73,8 +91,19 @@ OHIF.mixins.dropdown = new OHIF.Mixin({
event.preventDefault();
event.stopPropagation();
} else {
instance.data.promiseReject();
instance.destroyView();
}
},
'blur .dropdown'(event, instance) {
Meteor.defer(() => {
const $focus = $(':focus');
if (!$focus.length || !$.contains(event.currentTarget, $focus[0])) {
instance.data.promiseReject();
instance.destroyView();
}
});
}
}
}

View File

@ -1,3 +0,0 @@
<template name="dropdownBackdrop">
<div class="dropdown-backdrop"></div>
</template>

View File

@ -1,3 +1,19 @@
@import "{ohif:design}/app"
.dropdown
ul.dropdown-menu li
cursor: pointer
outline: none
ul.dropdown-menu
li.divider
margin: 4px 0
li a
outline: none
padding: 8px 20px
svg
display: inline-block
max-width: 18px
max-height: 18px
vertical-align: middle

View File

@ -1,6 +1,5 @@
<template name="dropdownForm">
{{#form (extend this mixins='dropdown' class='dropdown' hideValidationBox=true)}}
{{>dropdownBackdrop}}
<ul class="dropdown-menu {{this.options.menuClasses}}">
{{#if UI.contentBlock}}
{{>UI.contentBlock}}
@ -11,8 +10,13 @@
{{/if}}
<li class="{{#if item.disabled}}disabled{{/if}}">
{{#link item}}
{{#if item.iconClasses}}
<i class="{{item.iconClasses}}"></i>
{{#if item.icon}}
<i class="{{item.icon}} {{item.iconClasses}}"></i>
{{/if}}
{{#if item.iconSvgUse}}
<svg class="{{item.iconClasses}}">
<use xlink:href={{absoluteUrl item.iconSvgUse}}></use>
</svg>
{{/if}}
{{#if item.text}}
<span>{{item.text}}</span>

View File

@ -15,7 +15,6 @@ import './dialog/simple.js';
import './dialog/unsavedChangesDialog.html';
import './dialog/unsavedChangesDialog.js';
import './dropdown/backdrop.html';
import './dropdown/form.html';
import './form/button.html';

View File

@ -3,27 +3,31 @@ import { Blaze } from 'meteor/blaze';
import { OHIF } from 'meteor/ohif:core';
OHIF.ui.showDropdown = (items=[], options={}) => {
let promiseResolve;
let promiseReject;
const promise = new Promise((resolve, reject) => {
promiseResolve = resolve;
promiseReject = reject;
});
// Prepare the method to destroy the view
let view;
const destroyView = () => Blaze.remove(view);
// Create the data object that the dropdown will receive
const templateData = {
items,
options,
destroyView
destroyView,
promise,
promiseResolve,
promiseReject
};
// Render the dialog with the given template and data
const parentElement = options.parentElement || document.body;
view = Blaze.renderWithData(Template.dropdownForm, templateData, parentElement);
};
Meteor.startup(() => {
OHIF.ui.showDropdown([{
text: 'test 1',
action: () => console.warn('test1Clicked'),
separatorAfter: true
}, {
text: 'test 2',
action: () => console.warn('test2Clicked')
}]);
});
// Return the promise to allow callbacks stacking from outside
return promise;
};

View File

@ -2,6 +2,7 @@
// Sizes
$topBarHeight = 40px
$topBarExpandedHeight = 160px
$toolbarHeight = 78px
$toolbarDrawerHeight = 62px
$studiesSidebarMenuWidth = 307px

View File

@ -0,0 +1,14 @@
<template name="header">
<div class="header noselect {{reactive headerClasses}}">
<div class="clearfix">
<a target='_blank' class="brand pull-left" href="{{choose this.brandHref '/'}}">
{{>section 'brand'}}
</a>
{{>section 'headerAfterBrand'}}
<a href='#' class="header-menu pull-right">
{{>section 'headerMenu'}}
</a>
</div>
{{>UI.contentBlock}}
</div>
</template>

View File

@ -0,0 +1,37 @@
import { Meteor } from 'meteor/meteor';
import { Template } from 'meteor/templating';
import { ReactiveVar } from 'meteor/reactive-var';
import { $ } from 'meteor/jquery';
import { OHIF } from 'meteor/ohif:core';
Template.header.onCreated(() => {
const instance = Template.instance();
instance.dropdownOpen = new ReactiveVar(false);
instance.dropdownItems = [];
instance.autorun(() => {
OHIF.header.dropdownObserver.depend();
instance.dropdownItems = OHIF.header.getDropdownItems();
});
});
Template.header.events({
'mousedown .header-menu'(event, instance) {
if (instance.dropdownOpen.get()) {
event.preventDefault();
return $(event.currentTarget).focus();
}
},
'click .header-menu'(event, instance) {
event.preventDefault();
if (instance.dropdownOpen.get()) return;
instance.dropdownOpen.set(true);
const closeHandler = () => Meteor.setTimeout(() => instance.dropdownOpen.set(false), 200);
OHIF.ui.showDropdown(instance.dropdownItems, {
parentElement: event.currentTarget,
menuClasses: 'dropdown-menu-right',
marginTop: '25px'
}).then(closeHandler).catch(closeHandler);
}
});

View File

@ -0,0 +1,23 @@
@import "{ohif:design}/app"
body>.header
height: $topBarHeight
padding: 10px 10px 0
theme('color', '$textPrimaryColor')
theme('background-color', '$primaryBackgroundColor')
transition(all 0.5s ease)
&>.clearfix
position: relative
.header-menu
padding: 4px 0
font-size: 13px
font-weight: 400
line-height: 18px
text-decoration: none
theme('color', '$defaultColor')
&.header-big
height: $topBarExpandedHeight
background-color: rgba(21, 25, 30, 0.7)

View File

@ -0,0 +1,3 @@
import './header/header.html';
import './header/header.js';
import './header/header.styl';

View File

@ -0,0 +1 @@
import './components';

View File

@ -0,0 +1,35 @@
import { Tracker } from 'meteor/tracker';
import { _ } from 'meteor/underscore';
export class Header {
constructor() {
this.dropdownObserver = new Tracker.Dependency();
this._dropdownItems = [];
this.dropdownObserver.changed();
}
clearDropDownItems() {
this._dropdownItems = [];
this.dropdownObserver.changed();
}
setDropdownItems(items) {
this._dropdownItems = items;
this.dropdownObserver.changed();
}
addDropdownItem(item) {
this._dropdownItems.push(item);
this.dropdownObserver.changed();
}
removeDropdownItem(item) {
this._dropdownItems = _.without(this._dropdownItems, item);
this.dropdownObserver.changed();
}
getDropdownItems() {
this.dropdownObserver.depend();
return this._dropdownItems;
}
}

View File

@ -1,12 +0,0 @@
<template name="header">
<div class="header noselect {{headerClasses}}">
<div class="clearfix">
<a target='_blank' class="brand pull-left" href="{{choose this.brandHref '/'}}">
{{>section 'brand'}}
</a>
<div class="header-menu pull-right">
</div>
</div>
</div>
</template>

View File

@ -1,31 +0,0 @@
$expandedHeight = 160px
.header
height: $topBarHeight
padding: 10px 10px 0
theme('color', '$textPrimaryColor')
theme('background-color', '$primaryBackgroundColor')
transition(all 0.5s ease)
&>.clearfix
position: relative
.brand
background-image: url(/packages/pim_webviewer/assets/logo.svg)
background-repeat: no-repeat
background-size: 100%
display: block
font-size: 9px
height: 3.5em
text-decoration: none
width: 34.6em
&.studyList
background-color: rgba(21, 25, 30, 0.7)
height: $expandedHeight
padding-left: $studyListPadding
padding-right: $studyListPadding
.brand
font-size: 16px
margin-top: 44px

View File

@ -1,2 +0,0 @@
import './components/header.html';
import './components/header.styl';

View File

@ -0,0 +1,11 @@
import { OHIF } from 'meteor/ohif:core';
import { Header } from './client/lib/header';
/*
* Defines the base OHIF header object
*/
const header = new Header();
OHIF.header = header;
export { header };

View File

@ -9,11 +9,16 @@ Package.onUse(function(api) {
// Meteor packages
api.use('ecmascript');
api.use('templating');
api.use('underscore');
api.use('stylus');
// OHIF dependencies
api.use('ohif:core', 'client');
// Main module
api.mainModule('main.js', 'client');
// Client imports
api.addFiles('index.js', 'client');
api.addFiles('client/index.js', 'client');
});

View File

@ -0,0 +1,3 @@
import './activeEntry.styl';
import './activeEntry.js';
import './activeEntrySignIn.js';

View File

@ -0,0 +1,15 @@
import './emailVerification/emailVerification.html';
import './emailVerification/emailVerification.styl';
import './emailVerification/emailVerification.js';
import './hipaaLogPage/hipaaLogPage.styl';
import './hipaaLogPage/hipaaLogPage.js';
import './lastLoginModal/lastLoginModal.html';
import './timeoutCountdownDialog/timeoutCountdownDialog.html';
import './timeoutCountdownDialog/timeoutCountdownDialog.js';
import './userAccountMenu/userAccountMenu.html';
import './userAccountMenu/userAccountMenu.styl';
import './userAccountMenu/userAccountMenu.js';

View File

@ -0,0 +1,4 @@
import './active-entry';
import './components';
import './lib';
import './subscriptions';

View File

@ -0,0 +1,6 @@
import { Router } from 'meteor/iron:router';
import { OHIF } from 'meteor/ohif:core';
OHIF.user.audit = () => {
Router.go('/audit');
};

View File

@ -0,0 +1,6 @@
import { Router } from 'meteor/iron:router';
import { OHIF } from 'meteor/ohif:core';
OHIF.user.changePassword = () => {
Router.go('/changePassword');
};

View File

@ -0,0 +1,9 @@
import { Meteor } from 'meteor/meteor';
import { OHIF } from 'meteor/ohif:core';
OHIF.user.getName = () => {
const nameSplit = Meteor.user().profile.fullName.split(' ');
const lastName = nameSplit[nameSplit.length - 1];
nameSplit[nameSplit.length - 1] = lastName.substr(0, 1) + '.';
return nameSplit.join(' ');
};

View File

@ -0,0 +1,4 @@
import './audit';
import './changePassword';
import './getName';
import './logout';

View File

@ -0,0 +1,9 @@
import { Meteor } from 'meteor/meteor';
import { Router } from 'meteor/iron:router';
import { OHIF } from 'meteor/ohif:core';
OHIF.user.logout = () => {
Meteor.logout(function() {
Router.go('/entrySignIn');
});
};

View File

@ -0,0 +1,10 @@
import { OHIF } from 'meteor/ohif:core';
/*
* Defines the base OHIF user object
*/
const user = {};
OHIF.user = user;
export { user };

View File

@ -25,33 +25,17 @@ Package.onUse(function(api) {
api.use('ohif:core');
api.use('ohif:study-list');
// Main module
api.mainModule('main.js', ['client', 'server']);
// Load icons
api.addAssets('assets/user-menu-icons.svg', 'client');
api.addFiles('both/collections.js', ['client', 'server']);
//api.addFiles('both/schema/reviewers.js', ['client', 'server']);
api.addFiles('client/components/userAccountMenu/userAccountMenu.html', 'client');
api.addFiles('client/components/userAccountMenu/userAccountMenu.styl', 'client');
api.addFiles('client/components/userAccountMenu/userAccountMenu.js', 'client');
api.addFiles('client/active-entry/activeEntry.styl', 'client');
api.addFiles('client/active-entry/activeEntry.js', 'client');
api.addFiles('client/active-entry/activeEntrySignIn.js', 'client');
api.addFiles('client/subscriptions.js', 'client');
api.addFiles('client/components/emailVerification/emailVerification.html', 'client');
api.addFiles('client/components/emailVerification/emailVerification.styl', 'client');
api.addFiles('client/components/emailVerification/emailVerification.js', 'client');
api.addFiles('client/components/hipaaLogPage/hipaaLogPage.styl', 'client');
api.addFiles('client/components/hipaaLogPage/hipaaLogPage.js', 'client');
api.addFiles('client/components/timeoutCountdownDialog/timeoutCountdownDialog.html', 'client');
api.addFiles('client/components/timeoutCountdownDialog/timeoutCountdownDialog.js', 'client');
api.addFiles('client/components/lastLoginModal/lastLoginModal.html', 'client');
// Client imports
api.addFiles('client/index.js', 'client');
api.addFiles('server/createDemoUser.js', [ 'server' ]);
api.addFiles('server/reviewers.js', [ 'server' ]);