A bunch of fixes for TCR (#2250)

* fix add links by drag and drop

* fix dialog component logging errors

* fix search component errors

* fix sort

* remove unused entrydnd file

* remove unnecessary console logs

* fix preview action in embed dropdown, which was throwing a type error

* invoke PreviewAction once in NotebookController and pass into git add -a

* add navigation capability to embeds, and a bunch of cleanup

* code cleanup and avoid calling dismiss twice on overlay destroy, which was throwing a DOM error. Calling code should dismiss the overlay

* only show elements pool if domainObject has composition

* fix error in inspector when no selection is present

* wire up object view expand button

* listen to composition#remove in TabsView

* make reviewer requested changes

* make reviewer requested changes, and fix for an edge case where removed tab is at the end of the array and currentTab is not set properly

* remove array wrapping dynamic classes in embed.html

* add title='View Large' to expand button

* change model variable to domainObject in tabs.vue

* dismiss top level overlay when esc is pressed (only if overlay is dismissable)

* fix link navigation from embeds

* use positive flag dismissable instead of negative notDismissable for overlays

* make overlays dismissable by default, unless set to false
This commit is contained in:
Deep Tailor
2019-01-24 16:23:50 -08:00
committed by Andrew Henry
parent dd31de6935
commit ac11f898d4
15 changed files with 221 additions and 152 deletions

View File

@ -29,13 +29,21 @@ define(
function SnapshotPreviewController($scope, openmct) { function SnapshotPreviewController($scope, openmct) {
$scope.previewImage = function (imageUrl) { $scope.previewImage = function (imageUrl) {
var image = document.createElement('img'); let image = document.createElement('img');
image.src = imageUrl; image.src = imageUrl;
openmct.overlays.overlay( let previewImageOverlay = openmct.overlays.overlay(
{ {
element: image, element: image,
size: 'large' size: 'large',
buttons: [
{
label: 'Done',
callback: function () {
previewImageOverlay.dismiss();
}
}
]
} }
); );
}; };
@ -43,13 +51,13 @@ define(
$scope.annotateImage = function (ngModel, field, imageUrl) { $scope.annotateImage = function (ngModel, field, imageUrl) {
$scope.imageUrl = imageUrl; $scope.imageUrl = imageUrl;
var div = document.createElement('div'), let div = document.createElement('div'),
painterroInstance = {}, painterroInstance = {},
save = false; save = false;
div.id = 'snap-annotation'; div.id = 'snap-annotation';
openmct.overlays.overlay( let annotateImageOverlay = openmct.overlays.overlay(
{ {
element: div, element: div,
size: 'large', size: 'large',
@ -59,6 +67,7 @@ define(
callback: function () { callback: function () {
save = false; save = false;
painterroInstance.save(); painterroInstance.save();
annotateImageOverlay.dismiss();
} }
}, },
{ {
@ -66,6 +75,7 @@ define(
callback: function () { callback: function () {
save = true; save = true;
painterroInstance.save(); painterroInstance.save();
annotateImageOverlay.dismiss();
} }
} }
] ]
@ -97,7 +107,7 @@ define(
}, },
saveHandler: function (image, done) { saveHandler: function (image, done) {
if (save) { if (save) {
var url = image.asBlob(), let url = image.asBlob(),
reader = new window.FileReader(); reader = new window.FileReader();
reader.readAsDataURL(url); reader.readAsDataURL(url);

View File

@ -22,7 +22,7 @@ class Dialog extends Overlay {
super({ super({
element: component.$el, element: component.$el,
size: 'fit', size: 'fit',
notDismissable: true, dismissable: false,
...options ...options
}); });

View File

@ -12,6 +12,7 @@ class Overlay extends EventEmitter {
constructor(options) { constructor(options) {
super(); super();
this.dismissable = options.dismissable !== false ? true : false;
this.container = document.createElement('div'); this.container = document.createElement('div');
this.container.classList.add('l-overlay-wrapper', cssClasses[options.size]); this.container.classList.add('l-overlay-wrapper', cssClasses[options.size]);
@ -20,7 +21,7 @@ class Overlay extends EventEmitter {
dismiss: this.dismiss.bind(this), dismiss: this.dismiss.bind(this),
element: options.element, element: options.element,
buttons: options.buttons, buttons: options.buttons,
notDismissable: options.notDismissable ? true : false dismissable: this.dismissable
}, },
components: { components: {
OverlayComponent: OverlayComponent OverlayComponent: OverlayComponent
@ -35,8 +36,8 @@ class Overlay extends EventEmitter {
dismiss() { dismiss() {
this.emit('destroy'); this.emit('destroy');
this.component.$destroy();
document.body.removeChild(this.container); document.body.removeChild(this.container);
this.component.$destroy();
} }
/** /**

View File

@ -14,6 +14,14 @@ import ProgressDialog from './ProgressDialog';
class OverlayAPI { class OverlayAPI {
constructor() { constructor() {
this.activeOverlays = []; this.activeOverlays = [];
this.dismissLastOverlay = this.dismissLastOverlay.bind(this);
document.addEventListener('keyup', (event) => {
if (event.key === 'Escape') {
this.dismissLastOverlay();
}
});
} }
/** /**
@ -38,14 +46,24 @@ class OverlayAPI {
} }
/** /**
] * A description of option properties that can be passed into the overlay * private
*/
dismissLastOverlay() {
let lastOverlay = this.activeOverlays[this.activeOverlays.length - 1];
if (lastOverlay && lastOverlay.dismissable) {
lastOverlay.dismiss();
}
}
/**
* A description of option properties that can be passed into the overlay
* @typedef options * @typedef options
* @property {object} element DOMElement that is to be inserted/shown on the overlay * @property {object} element DOMElement that is to be inserted/shown on the overlay
* @property {string} size prefered size of the overlay (large, small, fit) * @property {string} size prefered size of the overlay (large, small, fit)
* @property {array} buttons optional button objects with label and callback properties * @property {array} buttons optional button objects with label and callback properties
* @property {function} onDestroy callback to be called when overlay is destroyed * @property {function} onDestroy callback to be called when overlay is destroyed
* @property {boolean} notDismissable to prevent user from dismissing the overlay, calling code * @property {boolean} dismissable allow user to dismiss overlay by using esc, and clicking away
* will need to explicitly dismiss the overlay. * from overlay. Unless set to false, all overlays will be dismissable by default.
*/ */
overlay(options) { overlay(options) {
let overlay = new Overlay(options); let overlay = new Overlay(options);

View File

@ -25,7 +25,7 @@ class ProgressDialog extends Overlay {
super({ super({
element: component.$el, element: component.$el,
size: 'fit', size: 'fit',
notDismissable: true, dismissable: false,
...options ...options
}); });

View File

@ -5,7 +5,7 @@
</div> </div>
<div class="c-overlay__outer"> <div class="c-overlay__outer">
<button class="c-click-icon c-overlay__close-button icon-x-in-circle" <button class="c-click-icon c-overlay__close-button icon-x-in-circle"
v-if="!notDismissable" v-if="dismissable"
@click="destroy"> @click="destroy">
</button> </button>
<div class="c-overlay__contents" ref="element"></div> <div class="c-overlay__contents" ref="element"></div>
@ -129,19 +129,19 @@
<script> <script>
export default { export default {
inject: ['dismiss', 'element', 'buttons', 'notDismissable'], inject: ['dismiss', 'element', 'buttons', 'dismissable'],
mounted() { mounted() {
this.$refs.element.appendChild(this.element); this.$refs.element.appendChild(this.element);
}, },
methods: { methods: {
destroy: function () { destroy: function () {
if (!this.notDismissable) { if (this.dismissable) {
this.dismiss(); this.dismiss();
} }
}, },
buttonClickHandler: function (method) { buttonClickHandler: function (method) {
method(); method();
this.destroy(); this.$emit('destroy');
} }
} }
} }

View File

@ -7,18 +7,19 @@
<div class="c-ne__embed__info"> <div class="c-ne__embed__info">
<div class="c-ne__embed__name"> <div class="c-ne__embed__name">
<a class="c-ne__embed__link" <a class="c-ne__embed__link"
v-on:click="navigate(embed.type)" :href="objectLink"
v-bind:class="[embed.cssClass]">{{embed.name}}</a> :class="embed.cssClass">{{embed.name}}</a>
<a class="c-ne__embed__context-available icon-arrow-down" <a class="c-ne__embed__context-available icon-arrow-down"
v-on:click="toggleActionMenu"></a> @click="toggleActionMenu"></a>
</div> </div>
<div class="hide-menu hidden"> <div class="hide-menu hidden">
<div class="menu-element context-menu-wrapper mobile-disable-select"> <div class="menu-element context-menu-wrapper mobile-disable-select">
<div class="menu context-menu"> <div class="menu context-menu">
<ul> <ul>
<li v-for="action in actions" <li v-for="action in actions"
v-bind:class="[action.cssClass]" :key="action.name"
v-on:click="action.perform(embed, entry)"> :class="action.cssClass"
@click="action.perform(embed, entry)">
{{ action.name }} {{ action.name }}
</li> </li>
</ul> </ul>

View File

@ -1,7 +1,5 @@
<li class="c-notebook__entry c-ne has-local-controls" <li class="c-notebook__entry c-ne has-local-controls"
v-on:drop="dropOnEntry(entry.id, $event)" @drop.prevent="dropOnEntry(entry.id, $event)">
v-on:dragover="dragoverOnEntry"
>
<div class="c-ne__time-and-content"> <div class="c-ne__time-and-content">
<div class="c-ne__time"> <div class="c-ne__time">
<span>{{formatTime(entry.createdOn, 'YYYY-MM-DD')}}</span> <span>{{formatTime(entry.createdOn, 'YYYY-MM-DD')}}</span>
@ -11,18 +9,18 @@
<div class="c-ne__text c-input-inline" <div class="c-ne__text c-input-inline"
contenteditable="true" contenteditable="true"
ref="contenteditable" ref="contenteditable"
v-on:blur="textBlur($event, entry.id)" @blur="textBlur($event, entry.id)"
v-on:focus="textFocus($event, entry.id)" @focus="textFocus($event, entry.id)"
v-bind:key="entry.id"
v-html="entry.text"> v-html="entry.text">
</div> </div>
<div class="c-ne__embeds"> <div class="c-ne__embeds">
<notebook-embed <notebook-embed
v-for="(embed, index) in entry.embeds" v-for="embed in entry.embeds"
:key="index" :key="embed.id"
:embed="embed" :embed="embed"
:entry="entry" :objectPath="embed.objectPath"
></notebook-embed> :entry="entry">
</notebook-embed>
</div> </div>
</div> </div>
</div> </div>
@ -30,6 +28,7 @@
<div class="c-ne__local-controls--hidden"> <div class="c-ne__local-controls--hidden">
<button class="c-click-icon c-click-icon--major icon-trash" <button class="c-click-icon c-click-icon--major icon-trash"
title="Delete this entry" title="Delete this entry"
v-on:click="deleteEntry"></button> @click="deleteEntry">
</button>
</div> </div>
</li> </li>

View File

@ -24,11 +24,10 @@
</div> </div>
<div class="c-notebook__drag-area icon-plus" <div class="c-notebook__drag-area icon-plus"
@click="newEntry($event)" @click="newEntry($event)"
@drop="newEntry($event)" @drop="newEntry($event)">
id="newEntry">
<span class="c-notebook__drag-area__label">To start a new entry, click here or drag and drop any object</span> <span class="c-notebook__drag-area__label">To start a new entry, click here or drag and drop any object</span>
</div> </div>
<div class="c-notebook__entries" ng-mouseover="handleActive()"> <div class="c-notebook__entries">
<ul> <ul>
<notebook-entry <notebook-entry
v-for="(entry,index) in filteredAndSortedEntries" v-for="(entry,index) in filteredAndSortedEntries"

View File

@ -37,25 +37,14 @@ function (
function EmbedController(openmct, domainObject) { function EmbedController(openmct, domainObject) {
this.openmct = openmct; this.openmct = openmct;
this.domainObject = domainObject; this.domainObject = domainObject;
this.objectService = openmct.$injector.get('objectService');
this.navigationService = openmct.$injector.get('navigationService');
this.popupService = openmct.$injector.get('popupService'); this.popupService = openmct.$injector.get('popupService');
this.agentService = openmct.$injector.get('agentService'); this.agentService = openmct.$injector.get('agentService');
this.dialogService = openmct.$injector.get('dialogService');
this.navigate = this.navigate.bind(this);
this.exposedData = this.exposedData.bind(this); this.exposedData = this.exposedData.bind(this);
this.exposedMethods = this.exposedMethods.bind(this); this.exposedMethods = this.exposedMethods.bind(this);
this.toggleActionMenu = this.toggleActionMenu.bind(this); this.toggleActionMenu = this.toggleActionMenu.bind(this);
} }
EmbedController.prototype.navigate = function (embedType) {
this.objectService.getObjects([embedType]).then(function (objects) {
this.navigationService.setNavigation(objects[embedType]);
}.bind(this));
};
EmbedController.prototype.openSnapshot = function (domainObject, entry, embed) { EmbedController.prototype.openSnapshot = function (domainObject, entry, embed) {
function annotateSnapshot(openmct) { function annotateSnapshot(openmct) {
@ -63,20 +52,22 @@ function (
var save = false, var save = false,
painterroInstance = {}, painterroInstance = {},
annotateOverlay = new Vue({ annotateVue = new Vue({
template: '<div id="snap-annotation"></div>' template: '<div id="snap-annotation"></div>'
}), }),
self = this; self = this;
openmct.overlays.overlay({ let annotateOverlay = openmct.overlays.overlay({
element: annotateOverlay.$mount().$el, element: annotateVue.$mount().$el,
size: 'large', size: 'large',
dismissable: false,
buttons: [ buttons: [
{ {
label: 'Cancel', label: 'Cancel',
callback: function () { callback: function () {
save = false; save = false;
painterroInstance.save(); painterroInstance.save();
annotateOverlay.dismiss();
} }
}, },
{ {
@ -84,11 +75,12 @@ function (
callback: function () { callback: function () {
save = true; save = true;
painterroInstance.save(); painterroInstance.save();
annotateOverlay.dismiss();
} }
} }
], ],
onDestroy: function () { onDestroy: function () {
annotateOverlay.$destroy(true); annotateVue.$destroy(true);
} }
}); });
@ -162,14 +154,11 @@ function (
} }
}); });
function onDestroyCallback() {
snapshot.$destroy(true);
}
var snapshotOverlay = this.openmct.overlays.overlay({ var snapshotOverlay = this.openmct.overlays.overlay({
element: snapshot.$mount().$el, element: snapshot.$mount().$el,
onDestroy: onDestroyCallback, onDestroy: () => {snapshot.$destroy(true)},
size: 'large', size: 'large',
dismissable: true,
buttons: [ buttons: [
{ {
label: 'Done', label: 'Done',
@ -199,23 +188,20 @@ function (
return foundId; return foundId;
}; };
EmbedController.prototype.actionToMenuDecorator = function (action) { EmbedController.prototype.populateActionMenu = function (openmct, actions) {
return {
name: action.getMetadata().name,
cssClass: action.getMetadata().cssClass,
perform: action.perform
};
};
EmbedController.prototype.populateActionMenu = function (objectService, actionService) {
return function () { return function () {
var self = this; var self = this;
objectService.getObjects([self.embed.type]).then(function (resp) { openmct.objects.get(self.embed.type).then(function (domainObject) {
var domainObject = resp[self.embed.type], actions.forEach((action) => {
previewAction = actionService.getActions({key: 'mct-preview-action', domainObject: domainObject})[0]; self.actions.push({
cssClass: action.cssClass,
self.actions.push(self.actionToMenuDecorator(previewAction)); name: action.name,
perform: () => {
action.invoke([domainObject].concat(openmct.router.path));
}
});
});
}); });
}; };
}; };
@ -308,11 +294,9 @@ function (
var self = this; var self = this;
return { return {
navigate: self.navigate,
openSnapshot: self.openSnapshot, openSnapshot: self.openSnapshot,
formatTime: self.formatTime, formatTime: self.formatTime,
toggleActionMenu: self.toggleActionMenu, toggleActionMenu: self.toggleActionMenu,
actionToMenuDecorator: self.actionToMenuDecorator,
findInArray: self.findInArray findInArray: self.findInArray
}; };
}; };

View File

@ -30,8 +30,6 @@ function (
function EntryController (openmct, domainObject) { function EntryController (openmct, domainObject) {
this.openmct = openmct; this.openmct = openmct;
this.domainObject = domainObject; this.domainObject = domainObject;
this.dndService = this.openmct.$injector.get('dndService');
this.dialogService = this.openmct.$injector.get('dialogService');
this.currentEntryValue = ''; this.currentEntryValue = '';
@ -106,37 +104,35 @@ function (
}; };
EntryController.prototype.dropOnEntry = function (entryid, event) { EntryController.prototype.dropOnEntry = function (entryid, event) {
var data = event.dataTransfer.getData('openmct/domain-object-path'); var data = event.dataTransfer.getData('openmct/domain-object-path');
if (data) { if (data) {
var selectedObject = JSON.parse(data)[0], var objectPath = JSON.parse(data),
selectedObjectId = selectedObject.identifier.key, domainObject = objectPath[0],
cssClass = this.openmct.types.get(selectedObject.type), domainObjectKey = domainObject.identifier.key,
domainObjectType = this.openmct.types.get(domainObject.type),
cssClass = domainObjectType && domainObjectType.definition ?
domainObjectType.definition.cssClass : 'icon-object-unknown',
entryPos = this.entryPosById(entryid), entryPos = this.entryPosById(entryid),
currentEntryEmbeds = this.domainObject.entries[entryPos].embeds, currentEntryEmbeds = this.domainObject.entries[entryPos].embeds,
newEmbed = { newEmbed = {
type: selectedObjectId,
id: '' + Date.now(), id: '' + Date.now(),
domainObject: domainObject,
objectPath: objectPath,
type: domainObjectKey,
cssClass: cssClass, cssClass: cssClass,
name: selectedObject.name, name: domainObject.name,
snapshot: '' snapshot: ''
}; };
currentEntryEmbeds.push(newEmbed); currentEntryEmbeds.push(newEmbed);
this.openmct.objects.mutate(this.domainObject, 'entries[' + entryPos + '].embeds', currentEntryEmbeds); this.openmct.objects.mutate(this.domainObject, 'entries[' + entryPos + '].embeds', currentEntryEmbeds);
} }
}; };
EntryController.prototype.dragoverOnEntry = function () {
};
EntryController.prototype.exposedData = function () { EntryController.prototype.exposedData = function () {
return { return {
openmct: this.openmct, openmct: this.openmct,
domainObject: this.domainObject, domainObject: this.domainObject,
dialogService: this.dialogService,
currentEntryValue: this.currentEntryValue currentEntryValue: this.currentEntryValue
}; };
}; };
@ -148,8 +144,7 @@ function (
textBlur: this.textBlur, textBlur: this.textBlur,
formatTime: this.formatTime, formatTime: this.formatTime,
deleteEntry: this.deleteEntry, deleteEntry: this.deleteEntry,
dropOnEntry: this.dropOnEntry, dropOnEntry: this.dropOnEntry
dragoverOnEntry: this.dragoverOnEntry
}; };
}; };
return EntryController; return EntryController;

View File

@ -27,7 +27,9 @@ define([
'../../res/templates/notebook.html', '../../res/templates/notebook.html',
'../../res/templates/entry.html', '../../res/templates/entry.html',
'../../res/templates/embed.html', '../../res/templates/embed.html',
'../../../../ui/components/search.vue' '../../../../ui/components/search.vue',
'../../../../ui/preview/PreviewAction',
'../../../../ui/mixins/object-link'
], ],
function ( function (
Vue, Vue,
@ -36,15 +38,16 @@ function (
NotebookTemplate, NotebookTemplate,
EntryTemplate, EntryTemplate,
EmbedTemplate, EmbedTemplate,
search search,
PreviewAction,
objectLinkMixin
) { ) {
function NotebookController(openmct, domainObject) { function NotebookController(openmct, domainObject) {
this.openmct = openmct; this.openmct = openmct;
this.domainObject = domainObject; this.domainObject = domainObject;
this.entrySearch = ''; this.entrySearch = '';
this.objectService = openmct.$injector.get('objectService'); this.previewAction = new PreviewAction.default(openmct);
this.actionService = openmct.$injector.get('actionService');
this.show = this.show.bind(this); this.show = this.show.bind(this);
this.destroy = this.destroy.bind(this); this.destroy = this.destroy.bind(this);
@ -61,11 +64,12 @@ function (
var notebookEmbed = { var notebookEmbed = {
inject:['openmct', 'domainObject'], inject:['openmct', 'domainObject'],
mixins:[objectLinkMixin.default],
props:['embed', 'entry'], props:['embed', 'entry'],
template: EmbedTemplate, template: EmbedTemplate,
data: embedController.exposedData, data: embedController.exposedData,
methods: embedController.exposedMethods(), methods: embedController.exposedMethods(),
beforeMount: embedController.populateActionMenu(self.objectService, self.actionService) beforeMount: embedController.populateActionMenu(self.openmct, [self.previewAction])
}; };
var entryComponent = { var entryComponent = {

View File

@ -15,25 +15,25 @@
v-for="(tab,index) in tabsList" v-for="(tab,index) in tabsList"
:key="index" :key="index"
:class="[ :class="[
{'is-current': tab=== currentTab}, {'is-current': isCurrent(tab)},
tab.type.definition.cssClass tab.type.definition.cssClass
]" ]"
@click="showTab(tab)"> @click="showTab(tab)">
<span class="c-button__label">{{tab.model.name}}</span> <span class="c-button__label">{{tab.domainObject.name}}</span>
</button> </button>
</div> </div>
<div class="c-tabs-view__object-holder" <div class="c-tabs-view__object-holder"
v-for="(object, index) in tabsList" v-for="(tab, index) in tabsList"
:key="index" :key="index"
:class="{'invisible': object !== currentTab}"> :class="{'invisible': !isCurrent(tab)}">
<div class="c-tabs-view__object-name l-browse-bar__object-name--w" <div class="c-tabs-view__object-name l-browse-bar__object-name--w"
:class="currentTab.type.definition.cssClass"> :class="currentTab.type.definition.cssClass">
<div class="l-browse-bar__object-name"> <div class="l-browse-bar__object-name">
{{currentTab.model.name}} {{currentTab.domainObject.name}}
</div> </div>
</div> </div>
<object-view class="c-tabs-view__object" <object-view class="c-tabs-view__object"
:object="object.model"> :object="tab.domainObject">
</object-view> </object-view>
</div> </div>
</div> </div>
@ -87,6 +87,7 @@
<script> <script>
import ObjectView from '../../../ui/components/ObjectView.vue'; import ObjectView from '../../../ui/components/ObjectView.vue';
import _ from 'lodash';
var unknownObjectType = { var unknownObjectType = {
definition: { definition: {
@ -100,22 +101,6 @@ export default {
components: { components: {
ObjectView ObjectView
}, },
mounted () {
if (this.composition) {
this.composition.on('add', this.addItem, this);
this.composition.load();
}
document.addEventListener('dragstart', this.dragstart);
document.addEventListener('dragend', this.dragend);
let dropHint = this.$refs.dropHint;
if (dropHint) {
dropHint.addEventListener('dragenter', this.dragenter);
dropHint.addEventListener('dragleave', this.dragleave);
}
},
data: function () { data: function () {
return { return {
currentTab: {}, currentTab: {},
@ -129,10 +114,10 @@ export default {
showTab(tab) { showTab(tab) {
this.currentTab = tab; this.currentTab = tab;
}, },
addItem (model) { addItem(domainObject) {
let type = this.openmct.types.get(model.type) || unknownObjectType, let type = this.openmct.types.get(domainObject.type) || unknownObjectType,
tabItem = { tabItem = {
model, domainObject,
type: type type: type
}; };
@ -143,6 +128,18 @@ export default {
this.setCurrentTab = false; this.setCurrentTab = false;
} }
}, },
removeItem(identifier) {
let pos = this.tabsList.findIndex(tab =>
tab.domainObject.identifier.namespace === identifier.namespace && tab.domainObject.identifier.key === identifier.key
),
tabToBeRemoved = this.tabsList[pos];
this.tabsList.splice(pos, 1);
if (this.isCurrent(tabToBeRemoved)) {
this.showTab(this.tabsList[this.tabsList.length - 1]);
}
},
onDrop(e) { onDrop(e) {
this.setCurrentTab = true; this.setCurrentTab = true;
}, },
@ -160,10 +157,31 @@ export default {
}, },
dragleave() { dragleave() {
this.allowDrop = false; this.allowDrop = false;
},
isCurrent(tab) {
return _.isEqual(this.currentTab, tab)
}
},
mounted () {
if (this.composition) {
this.composition.on('add', this.addItem);
this.composition.on('remove', this.removeItem);
this.composition.load();
}
document.addEventListener('dragstart', this.dragstart);
document.addEventListener('dragend', this.dragend);
let dropHint = this.$refs.dropHint;
if (dropHint) {
dropHint.addEventListener('dragenter', this.dragenter);
dropHint.addEventListener('dragleave', this.dragleave);
} }
}, },
destroyed() { destroyed() {
this.composition.off('add', this.addItem, this); this.composition.off('add', this.addItem);
this.composition.off('remove', this.removeItem);
document.removeEventListener('dragstart', this.dragstart); document.removeEventListener('dragstart', this.dragstart);
document.removeEventListener('dragend', this.dragend); document.removeEventListener('dragend', this.dragend);

View File

@ -36,10 +36,14 @@
</context-menu-drop-down> </context-menu-drop-down>
</div> </div>
<div class="c-so-view__header__end"> <div class="c-so-view__header__end">
<div class="c-button icon-expand local-controls--hidden"></div> <div class="c-button icon-expand local-controls--hidden"
title="View Large"
@click="expand">
</div>
</div> </div>
</div> </div>
<object-view class="c-so-view__object-view" <object-view class="c-so-view__object-view"
ref="objectView"
:object="domainObject"></object-view> :object="domainObject"></object-view>
</div> </div>
</template> </template>
@ -125,6 +129,21 @@
objectPath: Array, objectPath: Array,
hasFrame: Boolean, hasFrame: Boolean,
}, },
methods: {
expand() {
let objectView = this.$refs.objectView,
parentElement = objectView.$el,
childElement = parentElement.children[0];
this.openmct.overlays.overlay({
element: childElement,
size: 'large',
onDestroy() {
parentElement.append(childElement);
}
});
}
},
components: { components: {
ObjectView, ObjectView,
ContextMenuDropDown, ContextMenuDropDown,

View File

@ -8,7 +8,7 @@
</pane> </pane>
<pane class="c-inspector__elements" <pane class="c-inspector__elements"
handle="before" handle="before"
label="Elements" v-if="isEditing"> label="Elements" v-if="isEditing && hasComposition">
<elements></elements> <elements></elements>
</pane> </pane>
</multipane> </multipane>
@ -224,6 +224,27 @@
Properties, Properties,
Location, Location,
InspectorView InspectorView
},
data() {
return {
hasComposition: false
}
},
methods: {
refreshComposition(selection) {
if (selection[0]) {
let parentObject = selection[0].context.item;
this.hasComposition = !!this.openmct.composition.get(parentObject);
}
}
},
mounted() {
this.openmct.selection.on('change', this.refreshComposition);
this.refreshComposition(this.openmct.selection.get());
},
destroyed() {
this.openmct.selection.off('change', this.refreshComposition);
} }
} }
</script> </script>