mirror of
https://github.com/nasa/openmct.git
synced 2025-06-25 10:44:21 +00:00
Compare commits
5 Commits
recent-obj
...
dialog-ser
Author | SHA1 | Date | |
---|---|---|---|
be5da7fa72 | |||
5e3acc4363 | |||
196f49fca6 | |||
f9cb753fce | |||
9bc1630cb4 |
@ -1,7 +1,7 @@
|
||||
<div class="c-ne__embed">
|
||||
<div class="c-ne__embed__snap-thumb"
|
||||
v-if="embed.snapshot"
|
||||
v-on:click="openSnapshot">
|
||||
v-on:click="openSnapshot(domainObject, entry, embed)">
|
||||
<img v-bind:src="embed.snapshot.src">
|
||||
</div>
|
||||
<div class="c-ne__embed__info">
|
||||
|
@ -15,7 +15,7 @@
|
||||
<div class="flex-elem holder flex-can-shrink s-snapshot-datetime">
|
||||
SNAPSHOT {{formatTime(embed.createdOn, 'YYYY-MM-DD HH:mm:ss')}}
|
||||
</div>
|
||||
<a class="s-button icon-pencil" title="Annotate">
|
||||
<a class="s-button icon-pencil" title="Annotate" v-on:click="annotateSnapshot">
|
||||
<span class="title-label">Annotate</span>
|
||||
</a>
|
||||
</div>
|
||||
|
@ -23,16 +23,16 @@
|
||||
define([
|
||||
'moment',
|
||||
'zepto',
|
||||
'../utils/SnapshotOverlay',
|
||||
'../../res/templates/snapshotTemplate.html',
|
||||
'vue'
|
||||
'vue',
|
||||
'painterro'
|
||||
],
|
||||
function (
|
||||
Moment,
|
||||
$,
|
||||
SnapshotOverlay,
|
||||
SnapshotTemplate,
|
||||
Vue
|
||||
Vue,
|
||||
Painterro
|
||||
) {
|
||||
function EmbedController (openmct, domainObject) {
|
||||
this.openmct = openmct;
|
||||
@ -52,11 +52,102 @@ function (
|
||||
|
||||
EmbedController.prototype.navigate = function (embedType) {
|
||||
this.objectService.getObjects([embedType]).then(function (objects) {
|
||||
this.navigationService.setNavigation(objects[embedType]);
|
||||
this.navigationService.setNavigation(objects[embedType]);
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
EmbedController.prototype.openSnapshot = function () {
|
||||
EmbedController.prototype.openSnapshot = function (domainObject, entry, embed) {
|
||||
|
||||
function annotateSnapshot(openmct) {
|
||||
return function () {
|
||||
|
||||
var save = false,
|
||||
painterroInstance = {},
|
||||
annotateOverlay = new Vue({
|
||||
template: '<div id="snap-annotation"></div>'
|
||||
}),
|
||||
self = this;
|
||||
|
||||
var options = {
|
||||
cssClass: 'l-large-view',
|
||||
onDestroy: function () {
|
||||
annotateOverlay.$destroy(true);
|
||||
},
|
||||
buttons: [
|
||||
{
|
||||
label: 'Cancel',
|
||||
callback: function () {
|
||||
save = false;
|
||||
painterroInstance.save();
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'Save',
|
||||
callback: function () {
|
||||
save = true;
|
||||
painterroInstance.save();
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
openmct.OverlayService.show(annotateOverlay.$mount().$el, options);
|
||||
|
||||
painterroInstance = Painterro({
|
||||
id: 'snap-annotation',
|
||||
activeColor: '#ff0000',
|
||||
activeColorAlpha: 1.0,
|
||||
activeFillColor: '#fff',
|
||||
activeFillColorAlpha: 0.0,
|
||||
backgroundFillColor: '#000',
|
||||
backgroundFillColorAlpha: 0.0,
|
||||
defaultFontSize: 16,
|
||||
defaultLineWidth: 2,
|
||||
defaultTool: 'ellipse',
|
||||
hiddenTools: ['save', 'open', 'close', 'eraser', 'pixelize', 'rotate', 'settings', 'resize'],
|
||||
translation: {
|
||||
name: 'en',
|
||||
strings: {
|
||||
lineColor: 'Line',
|
||||
fillColor: 'Fill',
|
||||
lineWidth: 'Size',
|
||||
textColor: 'Color',
|
||||
fontSize: 'Size',
|
||||
fontStyle: 'Style'
|
||||
}
|
||||
},
|
||||
saveHandler: function (image, done) {
|
||||
if (save) {
|
||||
var entryPos = self.findInArray(domainObject.entries, entry.id),
|
||||
embedPos = self.findInArray(entry.embeds, embed.id);
|
||||
|
||||
if (entryPos !== -1 && embedPos !== -1) {
|
||||
var url = image.asBlob(),
|
||||
reader = new window.FileReader();
|
||||
|
||||
reader.readAsDataURL(url);
|
||||
reader.onloadend = function () {
|
||||
var snapshot = reader.result,
|
||||
snapshotObject = {
|
||||
src: snapshot,
|
||||
type: url.type,
|
||||
size: url.size,
|
||||
modified: Date.now()
|
||||
},
|
||||
dirString = 'entries[' + entryPos + '].embeds[' + embedPos + '].snapshot';
|
||||
|
||||
openmct.objects.mutate(domainObject, dirString, snapshotObject);
|
||||
};
|
||||
}
|
||||
} else {
|
||||
console.log('You cancelled the annotation!!!');
|
||||
}
|
||||
done(true);
|
||||
}
|
||||
}).show(embed.snapshot.src);
|
||||
};
|
||||
}
|
||||
|
||||
var self = this,
|
||||
snapshot = new Vue({
|
||||
template: SnapshotTemplate,
|
||||
@ -66,15 +157,22 @@ function (
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
formatTime: self.formatTime
|
||||
formatTime: self.formatTime,
|
||||
annotateSnapshot: annotateSnapshot(self.openmct),
|
||||
findInArray: self.findInArray
|
||||
}
|
||||
});
|
||||
|
||||
function onDestroyCallback() {
|
||||
snapshot.$destroy(true);
|
||||
}
|
||||
var options = {
|
||||
onDestroy: onDestroyCallback,
|
||||
cssClass: 'l-large-view'
|
||||
};
|
||||
|
||||
this.openmct.OverlayService.show(snapshot.$mount().$el, {onDestroy: onDestroyCallback, cssClass: 'l-large-view'});
|
||||
|
||||
this.openmct.OverlayService.show(snapshot.$mount().$el, options);
|
||||
};
|
||||
|
||||
EmbedController.prototype.formatTime = function (unixTime, timeFormat) {
|
||||
@ -125,23 +223,20 @@ function (
|
||||
var entryPosition = self.findInArray(self.domainObject.entries, entry.id),
|
||||
embedPosition = self.findInArray(entry.embeds, embed.id);
|
||||
|
||||
var warningDialog = self.dialogService.showBlockingMessage({
|
||||
self.openmct.OverlayService.showBlockingMessage({
|
||||
severity: "error",
|
||||
title: "This action will permanently delete this embed. Do you wish to continue?",
|
||||
options: [{
|
||||
label: "OK",
|
||||
actionText: 'This Action will permanently delete this embed. Do you wish to continue?',
|
||||
buttons: [{
|
||||
label: "No",
|
||||
callback: function () {}
|
||||
},
|
||||
{
|
||||
label: "Yes",
|
||||
callback: function () {
|
||||
entry.embeds.splice(embedPosition, 1);
|
||||
var dirString = 'entries[' + entryPosition + '].embeds';
|
||||
|
||||
self.openmct.objects.mutate(self.domainObject, dirString, entry.embeds);
|
||||
|
||||
warningDialog.dismiss();
|
||||
}
|
||||
},{
|
||||
label: "Cancel",
|
||||
callback: function () {
|
||||
warningDialog.dismiss();
|
||||
}
|
||||
}]
|
||||
});
|
||||
@ -207,7 +302,8 @@ function (
|
||||
openSnapshot: self.openSnapshot,
|
||||
formatTime: self.formatTime,
|
||||
toggleActionMenu: self.toggleActionMenu,
|
||||
actionToMenuDecorator: self.actionToMenuDecorator
|
||||
actionToMenuDecorator: self.actionToMenuDecorator,
|
||||
findInArray: self.findInArray
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -81,21 +81,18 @@ function (
|
||||
|
||||
if (entryPos !== -1) {
|
||||
|
||||
var errorDialog = this.dialogService.showBlockingMessage({
|
||||
this.openmct.OverlayService.showBlockingMessage({
|
||||
severity: "error",
|
||||
title: "This action will permanently delete this Notebook entry. Do you wish to continue?",
|
||||
options: [{
|
||||
label: "OK",
|
||||
actionText: "This action will permanently delete this Notebook entry. Do you wish to continue?",
|
||||
buttons: [{
|
||||
label: "No",
|
||||
callback: function () {}
|
||||
},
|
||||
{
|
||||
label: "Yes",
|
||||
callback: function () {
|
||||
domainObject.entries.splice(entryPos, 1);
|
||||
openmct.objects.mutate(domainObject, 'entries', domainObject.entries);
|
||||
|
||||
errorDialog.dismiss();
|
||||
}
|
||||
},{
|
||||
label: "Cancel",
|
||||
callback: function () {
|
||||
errorDialog.dismiss();
|
||||
}
|
||||
}]
|
||||
});
|
||||
|
@ -60,7 +60,7 @@ function (
|
||||
this.container = container;
|
||||
|
||||
var notebookEmbed = {
|
||||
inject:['openmct'],
|
||||
inject:['openmct', 'domainObject'],
|
||||
props:['embed', 'entry'],
|
||||
template: EmbedTemplate,
|
||||
data: embedController.exposedData,
|
||||
@ -81,7 +81,7 @@ function (
|
||||
|
||||
var notebookVue = Vue.extend({
|
||||
template: NotebookTemplate,
|
||||
provide: {openmct: self.openmct},
|
||||
provide: {openmct: self.openmct, domainObject: self.domainObject},
|
||||
components: {
|
||||
'notebook-entry': entryComponent,
|
||||
'search': search.default
|
||||
|
@ -40,7 +40,8 @@ $inputTextP: $inputTextPTopBtm $inputTextPLeftRight;
|
||||
$menuLineH: 1.5rem;
|
||||
$treeItemIndent: 16px;
|
||||
$treeTypeIconW: 18px;
|
||||
$overlayOuterMargin: 5%;
|
||||
$overlayOuterMarginLg: 5%;
|
||||
$overlayOuterMarginDialog: 20%;
|
||||
$overlayInnerMargin: 25px;
|
||||
|
||||
/*************** Items */
|
||||
|
91
src/ui/overlayService/blockingMessage.vue
Normal file
91
src/ui/overlayService/blockingMessage.vue
Normal file
@ -0,0 +1,91 @@
|
||||
<template>
|
||||
<div class="c-message"
|
||||
v-bind:class="">
|
||||
<!-- This element is displayed within the overlay service as well as in the list of messages
|
||||
Uses flex-row -->
|
||||
<div class="c-message__icon"
|
||||
:class="['message-severity-' + model.severity]"></div>
|
||||
<div class="c-message__text">
|
||||
<!-- Uses flex-column -->
|
||||
<div class="c-message__title"
|
||||
v-if="model.title">
|
||||
{{model.title}}
|
||||
</div>
|
||||
<div class="c-message__hint"
|
||||
v-if="model.hint">
|
||||
{{model.hint}}
|
||||
<span v-if="model.timestamp">[{{model.timestamp}}]</span>
|
||||
</div>
|
||||
<div class="c-message__action-text"
|
||||
v-if="model.actionText">
|
||||
{{model.actionText}}
|
||||
</div>
|
||||
|
||||
<div class="c-message__actions"
|
||||
v-if="model.primaryOption">
|
||||
<a class="c-button c-button--major"
|
||||
@click="model.primaryOption.callback()">
|
||||
{{model.primaryOption.label}}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
@import "~styles/sass-base";
|
||||
|
||||
.c-message {
|
||||
display: flex;
|
||||
padding: $interiorMarginLg;
|
||||
|
||||
> * + * {
|
||||
@include test();
|
||||
margin-left: $interiorMarginLg;
|
||||
}
|
||||
|
||||
&__icon {
|
||||
$s: 50px;
|
||||
flex: 0 0 auto;
|
||||
min-width: $s;
|
||||
min-height: $s;
|
||||
|
||||
&.message-severity {
|
||||
// TEMP: TODO: replace with SVG background assets
|
||||
&-alert {
|
||||
background: $colorAlert;
|
||||
}
|
||||
|
||||
&-error {
|
||||
background: $colorFormError;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__text {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1 1 auto;
|
||||
|
||||
> * + * {
|
||||
@include test();
|
||||
margin-top: $interiorMargin;
|
||||
}
|
||||
}
|
||||
|
||||
// __text elements
|
||||
&__title,
|
||||
&__action-text {
|
||||
font-size: 1.2em; // TEMP
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
inject:['model']
|
||||
}
|
||||
</script>
|
@ -8,9 +8,19 @@
|
||||
v-on:click="destroy">
|
||||
</button>
|
||||
<div class="c-overlay__contents" ref="element"></div>
|
||||
<div class="c-overlay__button-bar">
|
||||
<div class="c-overlay__button-bar" v-if="!buttons">
|
||||
<button class="c-button c-button--major"
|
||||
v-on:click="destroy">Done</button>
|
||||
v-on:click="destroy">
|
||||
Done
|
||||
</button>
|
||||
</div>
|
||||
<div class="c-overlay__button-bar" v-if="buttons">
|
||||
<button class="c-button c-button--major"
|
||||
v-for="(button, index) in buttons"
|
||||
:key="index"
|
||||
@click="buttonClickHandler(button.callback)">
|
||||
{{button.label}}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -19,6 +29,13 @@
|
||||
<style lang="scss">
|
||||
@import "~styles/sass-base";
|
||||
|
||||
@mixin overlaySizing($marginTB: 5%, $marginLR: $marginTB, $width: auto, $height: auto) {
|
||||
position: absolute;
|
||||
top: $marginTB; right: $marginLR; bottom: $marginTB; left: $marginLR;
|
||||
width: $width;
|
||||
height: $height;
|
||||
}
|
||||
|
||||
.l-overlay-wrapper {
|
||||
// Created by overlayService.js, contains this template.
|
||||
// Acts as an anchor for one or more overlays.
|
||||
@ -62,7 +79,26 @@
|
||||
margin-top: $interiorMargin;
|
||||
}
|
||||
|
||||
body.desktop & {
|
||||
|
||||
// Overlay types, styling independent of platform.
|
||||
.l-large-view & {
|
||||
// Default
|
||||
}
|
||||
|
||||
.l-dialog & {
|
||||
//
|
||||
}
|
||||
|
||||
.l-message & {
|
||||
&__outer {
|
||||
// background: orange;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
body.desktop {
|
||||
.c-overlay {
|
||||
&__blocker {
|
||||
@include abs();
|
||||
background: $colorOvrBlocker;
|
||||
@ -71,21 +107,49 @@
|
||||
}
|
||||
|
||||
&__outer {
|
||||
$m: $overlayOuterMargin;
|
||||
top: $m; right: $m; bottom: $m; left: $m;
|
||||
border-radius: $overlayCr;
|
||||
box-shadow: rgba(black, 0.5) 0 2px 25px;
|
||||
// Defaults to l-large-view
|
||||
@include overlaySizing($overlayOuterMarginLg);
|
||||
}
|
||||
}
|
||||
|
||||
// Overlay types, styling for desktop.
|
||||
.l-large-view {
|
||||
// Default
|
||||
}
|
||||
|
||||
.l-dialog {
|
||||
.c-overlay__outer {
|
||||
@include overlaySizing($overlayOuterMarginDialog);
|
||||
}
|
||||
}
|
||||
|
||||
.l-message {
|
||||
.c-overlay__outer {
|
||||
@include overlaySizing(auto);
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
inject: ['destroy', 'element'],
|
||||
inject: ['destroy', 'element', 'buttons'],
|
||||
mounted() {
|
||||
this.$refs.element.appendChild(this.element);
|
||||
},
|
||||
methods: {
|
||||
buttonClickHandler: function (method) {
|
||||
method();
|
||||
this.destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
@ -22,15 +22,19 @@
|
||||
|
||||
define([
|
||||
'./overlay.vue',
|
||||
'./blockingMessage.vue',
|
||||
'vue'
|
||||
], function (
|
||||
OverlayComponent,
|
||||
BlockingMessage,
|
||||
Vue
|
||||
) {
|
||||
|
||||
function OverlayService() {
|
||||
this.activeOverlays = [];
|
||||
this.overlayId = 0;
|
||||
|
||||
this.showBlockingMessage = this.showBlockingMessage.bind(this);
|
||||
}
|
||||
|
||||
OverlayService.prototype.show = function (element, options) {
|
||||
@ -43,45 +47,96 @@ define([
|
||||
component = new Vue({
|
||||
provide: {
|
||||
destroy: this.destroy.bind(this),
|
||||
element: element
|
||||
element: element,
|
||||
buttons: options.buttons
|
||||
},
|
||||
components: {
|
||||
OverlayComponent: OverlayComponent.default
|
||||
},
|
||||
template: '<overlay-component></overlay-component>'
|
||||
});
|
||||
}),
|
||||
dialog = {};
|
||||
|
||||
|
||||
overlay.classList.add('l-overlay-wrapper', overlayTypeCssClass);
|
||||
document.body.appendChild(overlay);
|
||||
|
||||
overlay.appendChild(component.$mount().$el);
|
||||
|
||||
this.activeOverlays.push({
|
||||
var overlayObject = {
|
||||
overlay: overlay,
|
||||
component: component,
|
||||
onDestroy: options.onDestroy,
|
||||
id: this.overlayId
|
||||
});
|
||||
id: this.overlayId,
|
||||
dialog: dialog
|
||||
};
|
||||
|
||||
dialog.dismiss = function () {
|
||||
let pos = findInArray(overlayObject.id, this.activeOverlays);
|
||||
|
||||
if (pos !== -1) {
|
||||
if (overlayObject.onDestroy && typeof overlayObject.onDestroy === 'function') {
|
||||
overlayObject.onDestroy();
|
||||
}
|
||||
|
||||
overlayObject.component.$destroy(true);
|
||||
document.body.removeChild(overlayObject.overlay);
|
||||
this.activeOverlays.splice(pos, 1);
|
||||
|
||||
if (this.activeOverlays.length) {
|
||||
this.activeOverlays[this.activeOverlays.length - 1].overlay.classList.remove('invisible');
|
||||
}
|
||||
}
|
||||
}.bind(this);
|
||||
|
||||
this.activeOverlays.push(overlayObject);
|
||||
this.overlayId++;
|
||||
|
||||
return dialog;
|
||||
};
|
||||
|
||||
OverlayService.prototype.destroy = function () {
|
||||
var lastActiveOverlayObject = this.activeOverlays.pop(),
|
||||
lastActiveOverlay = lastActiveOverlayObject.overlay,
|
||||
lastActiveComponent = lastActiveOverlayObject.component;
|
||||
var lastActiveOverlayObject = this.activeOverlays[this.activeOverlays.length - 1];
|
||||
|
||||
if (lastActiveOverlayObject.onDestroy && typeof lastActiveOverlayObject.onDestroy === 'function') {
|
||||
lastActiveOverlayObject.onDestroy();
|
||||
}
|
||||
|
||||
lastActiveComponent.$destroy(true);
|
||||
document.body.removeChild(lastActiveOverlay);
|
||||
|
||||
if (this.activeOverlays.length) {
|
||||
this.activeOverlays[this.activeOverlays.length - 1].overlay.classList.remove('invisible');
|
||||
}
|
||||
lastActiveOverlayObject.dialog.dismiss(lastActiveOverlayObject.id);
|
||||
};
|
||||
|
||||
OverlayService.prototype.showBlockingMessage = function (model) {
|
||||
let component = new Vue({
|
||||
provide: {
|
||||
model: model
|
||||
},
|
||||
components: {
|
||||
BlockingMessage: BlockingMessage.default
|
||||
},
|
||||
template: '<blocking-message></blocking-message>'
|
||||
});
|
||||
|
||||
function destroy() {
|
||||
component.$destroy(true);
|
||||
}
|
||||
|
||||
let options = {
|
||||
cssClass: 'l-message',
|
||||
onDestroy: destroy,
|
||||
buttons: model.buttons
|
||||
};
|
||||
|
||||
return this.show(component.$mount().$el, options);
|
||||
};
|
||||
|
||||
function findInArray(id, array) {
|
||||
var found = -1;
|
||||
|
||||
array.forEach(function (o,i) {
|
||||
if (o.id === id) {
|
||||
found = i;
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
return OverlayService;
|
||||
});
|
||||
|
Reference in New Issue
Block a user