Creating a notification mechanism

This commit is contained in:
Bruno Alves de Faria 2017-09-29 12:51:39 -03:00
parent 06fe7f0da7
commit 820b2efd88
10 changed files with 217 additions and 2 deletions

View File

@ -32,4 +32,6 @@ import './input/range.html';
import './input/select.html';
import './input/text.html';
import './notification';
import './popover/form.html';

View File

@ -0,0 +1,4 @@
import './notificationArea.html';
import './notificationArea.styl';
import './notificationNote.html';
import './notificationNote.js';

View File

@ -0,0 +1,3 @@
<template name="notificationArea">
<div id="notificationArea" class="notification-area"></div>
</template>

View File

@ -0,0 +1,62 @@
@require '{ohif:design}/app'
.notification-area
position: fixed
right: 0
top: 50px
max-width: 320px
z-index: 10000
.notification-note
opacity: 0
position: relative
transition(opacity 0.5s linear\, max-height 0.5s linear)
width: 300px
z-index: 2
.note-container
padding: 10px
transform(translateY(0))
transition(transform 0.5s linear)
.note-body
margin: 0
padding: 10px
position: relative
&:not(.hide-dismiss)
padding-right: 40px
.note-dismiss
display: block
.note-dismiss
bottom: 0
cursor: pointer
display: none
position: absolute
right: 0
top: 0
width: 40px
i
display: block
font-size: 20px
left: 0
position: absolute
text-align: center
top: 50%
transform(translateY(-50%))
width: 100%
&.in
max-height: auto
opacity: 1
&.out
max-height: 0 !important
opacity: 0
z-index: 1
.note-container
transform(translateY(-100%))

View File

@ -0,0 +1,12 @@
<template name="notificationNote">
<div class="notification-note {{this.class}}">
<div class="note-container">
<div class="note-body alert alert-{{choose this.style 'info'}} {{#if hideDismiss}}hide-dismiss{{/if}}">
<div class="note-text">{{this.text}}</div>
<div class="note-dismiss">
<i class="fa fa-times"></i>
</div>
</div>
</div>
</div>
</template>

View File

@ -0,0 +1,21 @@
import { Meteor } from 'meteor/meteor';
import { Template } from 'meteor/templating';
import { OHIF } from 'meteor/ohif:core';
Template.notificationNote.onRendered(() => {
const instance = Template.instance();
Meteor.setTimeout(() => {
const $note = instance.$('.notification-note');
$note.css('max-height', $note.outerHeight()).addClass('in');
}, 100);
});
Template.notificationNote.events({
'click .note-dismiss'(event, instance) {
if (instance.data.promiseResolve) {
instance.data.promiseResolve();
} else {
OHIF.ui.notifications.dismiss(instance.data.id);
}
}
});

View File

@ -6,6 +6,7 @@ import './dialog/unsavedChangesDialog.js';
import './draggable/draggable.js';
import './dropdown/class.js';
import './dropdown/display.js';
import './notifications/notifications.js';
import './popover/display.js';
import './resizable/resizable.js';
import './unsavedChanges/unsavedChanges.js';

View File

@ -0,0 +1,105 @@
import { Meteor } from 'meteor/meteor';
import { Template } from 'meteor/templating';
import { ReactiveDict } from 'meteor/reactive-dict';
import { Tracker } from 'meteor/tracker';
import { $ } from 'meteor/jquery';
import { OHIF } from 'meteor/ohif:core';
const Notifications = {
currentId: 0,
views: new Map()
};
// Remove the view object from DOM and from views Map
const removeView = (id, view) => {
Notifications.views.delete(id);
Blaze.remove(view);
};
// Dismiss a single notification note by its id
Notifications.dismiss = id => {
const view = Notifications.views.get(id);
if (!view || view.isDestroyed) {
return Notifications.views.delete(id);
}
const node = view.firstNode();
const $note = node && $(node);
if ($note.length) {
$note.addClass('out').one('transitionend', () => removeView(id, view));
} else {
removeView(id, view)
}
};
// Dismiss all notification notes
Notifications.clear = () => Array.from(Notifications.views.keys()).forEach(Notifications.dismiss);
// Display a notification note
Notifications.show = ({ template, promise, text, style, timeout=5000 }) => {
// Check if the given template exists
const templateObject = Template[template];
if (template && !templateObject) {
throw new Meteor.Error('TEMPLATE_NOT_FOUND', `Template ${template} not found.`);
}
// Check if there is a notification area container
const $area = $('#notificationArea');
if (!$area.length) {
throw new Meteor.Error('NOTIFICATION_AREA_NOT_FOUND', `Notification area not found.`);
}
let notificationPromise;
let templateData = {
text,
style,
timeout,
id: Notifications.currentId++
};
if (promise instanceof Promise) {
// Use the given promise to control the notification
notificationPromise = templateData.promise = promise;
} else {
// Create a new promise to control the modal and store its resolve and reject callbacks
let promiseResolve;
let promiseReject;
notificationPromise = new Promise((resolve, reject) => {
promiseResolve = resolve;
promiseReject = reject;
});
// Render the notification passing the promise object and callbacks
_.extend({}, templateData, {
promise: notificationPromise,
promiseResolve,
promiseReject
});
}
const view = Blaze.renderWithData(Template.notificationNote, templateData, $area[0]);
const dismissNotification = () => Notifications.dismiss(templateData.id);
// Add the current view to the list of views to allow clearing all notifications
Notifications.views.set(templateData.id, view);
// Destroy the created notification view when the promise is either resolved or rejected
notificationPromise.then(dismissNotification).catch(dismissNotification);
// Destroy the created notification view if the given timeout time has passed
if (timeout > 0) {
Meteor.setTimeout(() => {
if (templateData.promiseResolve) {
templateData.promiseResolve();
} else {
dismissNotification();
}
}, timeout);
}
// Return the promise to allow callbacks stacking from outside
return notificationPromise;
};
OHIF.ui.notifications = Notifications;

View File

@ -15,7 +15,7 @@
<div class="form-buttons clearfix">
{{#button class='btn btn-danger pull-left' action='resetDefaults'}}Reset to Defaults{{/button}}
{{#button class='btn btn-primary pull-right' action='save'}}Save{{/button}}
{{#button class='btn btn-default pull-right m-r-1' tagAttributes=(extend '' data-dismiss='modal')}}Cancel{{/button}}
{{#button class='btn btn-default pull-right m-r-1' tagAttributes=(extend '' data-dismiss='modal')}}Close{{/button}}
</div>
{{/form}}
</template>

View File

@ -11,7 +11,12 @@ Template.hotkeysForm.onCreated(() => {
const { contextName } = instance.data;
const form = instance.$('form').first().data('component');
const definitions = form.value();
return OHIF.hotkeys.store(contextName, definitions);
const promise = OHIF.hotkeys.store(contextName, definitions);
promise.then(() => OHIF.ui.notifications.show({
text: 'The keyboard shortcut preferences were successfully saved.',
style: 'success'
}));
return promise;
},
resetDefaults() {