Compare commits
34 Commits
edit-views
...
edit-param
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
79d1dff02e | ||
|
|
bf3293356e | ||
|
|
7cf53c8b9f | ||
|
|
5ecd742131 | ||
|
|
feee96b899 | ||
|
|
a04bd810bd | ||
|
|
4bf573bc4c | ||
|
|
fc70bed810 | ||
|
|
23b1ca2073 | ||
|
|
0e30fba72d | ||
|
|
a0d2cd5711 | ||
|
|
1c77ef142c | ||
|
|
e4e7ecd74e | ||
|
|
853764d863 | ||
|
|
d0ab59f9da | ||
|
|
21e08709cb | ||
|
|
514896884f | ||
|
|
fc024e583e | ||
|
|
a1aa99837b | ||
|
|
037264b0bf | ||
|
|
7f2f060417 | ||
|
|
6eda100af8 | ||
|
|
782ee9aa37 | ||
|
|
29e94befe8 | ||
|
|
24a1e9ba75 | ||
|
|
edeefe8f2f | ||
|
|
1a06702dbe | ||
|
|
d263723a0c | ||
|
|
666bb41697 | ||
|
|
e254fafb5c | ||
|
|
58048d44b2 | ||
|
|
775e93484e | ||
|
|
0e27234389 | ||
|
|
15d4b1a8e5 |
208
index.html
208
index.html
@@ -36,7 +36,9 @@
|
||||
<body>
|
||||
</body>
|
||||
<script>
|
||||
var THIRTY_MINUTES = 30 * 60 * 1000;
|
||||
const FIVE_MINUTES = 5 * 60 * 1000;
|
||||
const THIRTY_MINUTES = 30 * 60 * 1000;
|
||||
|
||||
[
|
||||
'example/eventGenerator',
|
||||
'example/styleguide'
|
||||
@@ -67,8 +69,8 @@
|
||||
timeSystem: 'utc',
|
||||
clock: 'local',
|
||||
clockOffsets: {
|
||||
start: -25 * 60 * 1000,
|
||||
end: 5 * 60 * 1000
|
||||
start: - THIRTY_MINUTES,
|
||||
end: FIVE_MINUTES
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -79,206 +81,6 @@
|
||||
openmct.install(openmct.plugins.Tabs());
|
||||
openmct.install(openmct.plugins.FlexibleLayout());
|
||||
openmct.install(openmct.plugins.LADTable());
|
||||
openmct.time.clock('local', {start: -THIRTY_MINUTES, end: 0});
|
||||
openmct.time.timeSystem('utc');
|
||||
openmct.start();
|
||||
|
||||
// openmct.toolbars.addProvider({
|
||||
// name: "Testing Toolbar",
|
||||
// key: "testing",
|
||||
// description: "a mock toolbar that exercises all controls",
|
||||
// forSelection: function (selection) {
|
||||
// return true; // always applies.
|
||||
// },
|
||||
// toolbar: function (selection) {
|
||||
// return [
|
||||
// {
|
||||
// control: 'menu',
|
||||
// icon: 'icon-plus',
|
||||
// label: 'Add',
|
||||
// options: [
|
||||
// { name: 'Box', class: 'icon-box', title: 'Add Box' },
|
||||
// { name: 'Line', class: 'icon-line-horz', title: 'Add Line' },
|
||||
// { name: 'Text', class: 'icon-font', title: 'Add Text' },
|
||||
// { name: 'Image', class: 'icon-image', title: 'Add Image' }
|
||||
// ]
|
||||
// },
|
||||
// {
|
||||
// control: 'separator'
|
||||
// },
|
||||
// {
|
||||
// control: 'color-picker',
|
||||
// icon: 'icon-paint-bucket',
|
||||
// value: '#33ff00',
|
||||
// },
|
||||
// {
|
||||
// control: 'color-picker',
|
||||
// icon: 'icon-pencil',
|
||||
// value: '#ffffff',
|
||||
// },
|
||||
// {
|
||||
// control: 'color-picker',
|
||||
// icon: 'icon-font',
|
||||
// value: '#333333',
|
||||
// },
|
||||
//
|
||||
// {
|
||||
// control: 'separator'
|
||||
// },
|
||||
// {
|
||||
// control: 'select-menu',
|
||||
// value: 11,
|
||||
// options: [
|
||||
// { value: 9, name: '9 px' },
|
||||
// { value: 10, name: '10 px' },
|
||||
// { value: 11, name: '11 px' },
|
||||
// { value: 12, name: '12 px' },
|
||||
// { value: 13, name: '13 px' },
|
||||
// { value: 14, name: '14 px' },
|
||||
// { value: 16, name: '16 px' },
|
||||
// { value: 18, name: '18 px' },
|
||||
// { value: 20, name: '20 px' },
|
||||
// { value: 24, name: '24 px' },
|
||||
// { value: 28, name: '28 px' },
|
||||
// { value: 32, name: '32 px' },
|
||||
// { value: 40, name: '40 px' },
|
||||
// { value: 48, name: '48 px' },
|
||||
// { value: 56, name: '56 px' },
|
||||
// { value: 64, name: '64 px' },
|
||||
// { value: 72, name: '72 px' },
|
||||
// { value: 80, name: '80 px' },
|
||||
// { value: 88, name: '88 px' },
|
||||
// { value: 96, name: '96 px' },
|
||||
// { value: 128, name: '128 px' },
|
||||
// { value: 160, name: '160 px' }
|
||||
// ]
|
||||
// },
|
||||
//
|
||||
// {
|
||||
// control: 'separator'
|
||||
// },
|
||||
// {
|
||||
// control: 'menu',
|
||||
// icon: 'icon-layers',
|
||||
// options: [
|
||||
// { name: 'Move to top', class: 'icon-arrow-double-up', title: 'Move to top' },
|
||||
// { name: 'Move up', class: 'icon-arrow-up', title: 'Move up' },
|
||||
// { name: 'Move down', class: 'icon-arrow-down', title: 'Move down' },
|
||||
// { name: 'Move to bottom', class: 'icon-arrow-double-down', title: 'Move to bottom' }
|
||||
// ]
|
||||
// },
|
||||
//
|
||||
// {
|
||||
// control: 'separator'
|
||||
// },
|
||||
// {
|
||||
// control: 'button',
|
||||
// icon: 'icon-gear'
|
||||
// },
|
||||
//
|
||||
// {
|
||||
// control: 'separator'
|
||||
// },
|
||||
// {
|
||||
// control: 'input',
|
||||
// type: 'number',
|
||||
// label: 'X',
|
||||
// value: 1,
|
||||
// title: 'X position'
|
||||
// },
|
||||
// {
|
||||
// control: 'input',
|
||||
// type: 'number',
|
||||
// label: 'Y',
|
||||
// value: 2,
|
||||
// title: 'Y position'
|
||||
// },
|
||||
// {
|
||||
// control: 'input',
|
||||
// type: 'number',
|
||||
// label: 'W',
|
||||
// value: 3,
|
||||
// title: 'Width'
|
||||
// },
|
||||
// {
|
||||
// control: 'input',
|
||||
// type: 'number',
|
||||
// label: 'H',
|
||||
// value: 4,
|
||||
// title: 'Height'
|
||||
// },
|
||||
//
|
||||
// {
|
||||
// control: 'separator'
|
||||
// },
|
||||
// {
|
||||
// control: 'button',
|
||||
// icon: 'icon-trash',
|
||||
// label: 'delete',
|
||||
// modifier: 'caution'
|
||||
// },
|
||||
//
|
||||
// {
|
||||
// control: 'separator'
|
||||
// },
|
||||
// {
|
||||
// control: 'checkbox',
|
||||
// name: 'this is a checkbox',
|
||||
// },
|
||||
// {
|
||||
// control: 'separator'
|
||||
// },
|
||||
// {
|
||||
// control: 'toggle-button',
|
||||
// title: 'Toggle Frame',
|
||||
// property: 'hideFrame',
|
||||
// value: false,
|
||||
// options: [
|
||||
// {
|
||||
// value: true,
|
||||
// icon: 'icon-frame-hide'
|
||||
// },
|
||||
// {
|
||||
// value: false,
|
||||
// icon: 'icon-frame-show'
|
||||
// }
|
||||
// ]
|
||||
// },
|
||||
// {
|
||||
// control: 'toggle-button',
|
||||
// title: 'Snap to grid',
|
||||
// property: 'snapToGrid',
|
||||
// value: true,
|
||||
// options: [
|
||||
// {
|
||||
// value: true,
|
||||
// icon: 'icon-grid-snap-to'
|
||||
// },
|
||||
// {
|
||||
// value: false,
|
||||
// icon: 'icon-grid-snap-no'
|
||||
// }
|
||||
// ]
|
||||
// },
|
||||
// {
|
||||
// control: 'toggle-button',
|
||||
// title: 'Toggle label',
|
||||
// property: 'showLabel',
|
||||
// value: true,
|
||||
// options: [
|
||||
// {
|
||||
// value: true,
|
||||
// icon: 'icon-two-parts-both'
|
||||
// },
|
||||
// {
|
||||
// value: false,
|
||||
// icon: 'icon-two-parts-one-only'
|
||||
// }
|
||||
// ]
|
||||
// }
|
||||
// ];
|
||||
// }
|
||||
// });
|
||||
|
||||
</script>
|
||||
</html>
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
"eventemitter3": "^1.2.0",
|
||||
"exports-loader": "^0.7.0",
|
||||
"express": "^4.13.1",
|
||||
"fast-sass-loader": "^1.4.5",
|
||||
"fast-sass-loader": "1.4.6",
|
||||
"file-loader": "^1.1.11",
|
||||
"file-saver": "^1.3.8",
|
||||
"git-rev-sync": "^1.4.0",
|
||||
|
||||
@@ -10,6 +10,16 @@
|
||||
ng-show="ngModel.progressPerc !== undefined"></mct-include>
|
||||
</div>
|
||||
<div class="bottom-bar">
|
||||
<a ng-repeat="dialogOption in ngModel.options"
|
||||
class="s-button"
|
||||
ng-click="dialogOption.callback()">
|
||||
{{dialogOption.label}}
|
||||
</a>
|
||||
<a class="s-button major"
|
||||
ng-if="ngModel.primaryOption"
|
||||
ng-click="ngModel.primaryOption.callback()">
|
||||
{{ngModel.primaryOption.label}}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -92,16 +92,7 @@ function (
|
||||
* @memberof platform/commonUI/edit.SaveAction#
|
||||
*/
|
||||
SaveAsAction.prototype.perform = function () {
|
||||
// Discard the current root view (which will be the editing
|
||||
// UI, which will have been pushed atop the Browse UI.)
|
||||
function returnToBrowse(object) {
|
||||
if (object) {
|
||||
object.getCapability("action").perform("navigate");
|
||||
}
|
||||
return object;
|
||||
}
|
||||
|
||||
return this.save().then(returnToBrowse);
|
||||
return this.save();
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -169,15 +160,17 @@ function (
|
||||
}
|
||||
|
||||
function saveAfterClone(clonedObject) {
|
||||
return domainObject.getCapability("editor").save()
|
||||
.then(resolveWith(clonedObject));
|
||||
return this.openmct.editor.save().then(() => {
|
||||
// Force mutation for search indexing
|
||||
clonedObject.useCapability('mutation', (model) => {
|
||||
return model;
|
||||
});
|
||||
return clonedObject;
|
||||
})
|
||||
}
|
||||
|
||||
function finishEditing(clonedObject) {
|
||||
return domainObject.getCapability("editor").finish()
|
||||
.then(function () {
|
||||
return fetchObject(clonedObject.getId());
|
||||
});
|
||||
return fetchObject(clonedObject.getId())
|
||||
}
|
||||
|
||||
function onSuccess(object) {
|
||||
@@ -190,7 +183,7 @@ function (
|
||||
if (reason !== "user canceled") {
|
||||
self.notificationService.error("Save Failed");
|
||||
}
|
||||
return false;
|
||||
throw reason;
|
||||
}
|
||||
|
||||
return getParent(domainObject)
|
||||
|
||||
@@ -65,24 +65,29 @@ define(
|
||||
CreateAction.prototype.perform = function () {
|
||||
var newModel = this.type.getInitialModel(),
|
||||
openmct = this.openmct,
|
||||
newObject,
|
||||
editAction;
|
||||
|
||||
function onSave() {
|
||||
openmct.editor.save();
|
||||
}
|
||||
newObject;
|
||||
|
||||
function onCancel() {
|
||||
openmct.editor.cancel();
|
||||
}
|
||||
|
||||
function navigateAndEdit(object) {
|
||||
let objectPath = object.getCapability('context').getPath(),
|
||||
url = '#/browse/' + objectPath
|
||||
.map(function (o) {
|
||||
return o && openmct.objects.makeKeyString(o.getId())
|
||||
})
|
||||
.join('/') + '?edit=true';
|
||||
|
||||
window.location.href = url;
|
||||
}
|
||||
|
||||
newModel.type = this.type.getKey();
|
||||
newModel.location = this.parent.getId();
|
||||
newObject = this.parent.useCapability('instantiation', newModel);
|
||||
|
||||
openmct.editor.edit();
|
||||
editAction = newObject.getCapability("action").getActions("edit")[0];
|
||||
newObject.getCapability("action").perform("save-as").then(onSave, onCancel);
|
||||
newObject.getCapability("action").perform("save-as").then(navigateAndEdit, onCancel);
|
||||
// TODO: support editing object without saving object first.
|
||||
// Which means we have to toggle createwizard afterwards. For now,
|
||||
// We will disable this.
|
||||
|
||||
@@ -43,12 +43,25 @@ define(
|
||||
* Launch a dialog showing a list of current notifications.
|
||||
*/
|
||||
$scope.showNotificationsList = function () {
|
||||
let notificationsList = openmct.notifications.notifications.map(notification => {
|
||||
if (notification.model.severity === 'alert' || notification.model.severity === 'info') {
|
||||
notification.model.primaryOption = {
|
||||
label: 'Dismiss',
|
||||
callback: () => {
|
||||
let currentIndex = notificationsList.indexOf(notification);
|
||||
notification.dismiss();
|
||||
notificationsList.splice(currentIndex, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
return notification;
|
||||
})
|
||||
dialogService.getDialogResponse('overlay-message-list', {
|
||||
dialog: {
|
||||
title: "Messages",
|
||||
//Launch the message list dialog with the models
|
||||
// from the notifications
|
||||
messages: openmct.notifications.notifications
|
||||
messages: notificationsList
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -29,12 +29,13 @@ define(
|
||||
function SnapshotPreviewController($scope, openmct) {
|
||||
|
||||
$scope.previewImage = function (imageUrl) {
|
||||
let image = document.createElement('img');
|
||||
image.src = imageUrl;
|
||||
let imageDiv = document.createElement('div');
|
||||
imageDiv.classList = 'image-main s-image-main';
|
||||
imageDiv.style.backgroundImage = `url(${imageUrl})`;
|
||||
|
||||
let previewImageOverlay = openmct.overlays.overlay(
|
||||
{
|
||||
element: image,
|
||||
element: imageDiv,
|
||||
size: 'large',
|
||||
buttons: [
|
||||
{
|
||||
|
||||
@@ -39,6 +39,7 @@ export default class Editor extends EventEmitter {
|
||||
* Initiate an editing session. This will start a transaction during
|
||||
* which any persist operations will be deferred until either save()
|
||||
* or finish() are called.
|
||||
* @private
|
||||
*/
|
||||
edit() {
|
||||
if (this.editing === true) {
|
||||
@@ -59,6 +60,8 @@ export default class Editor extends EventEmitter {
|
||||
/**
|
||||
* Save any unsaved changes from this editing session. This will
|
||||
* end the current transaction.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
save() {
|
||||
return this.getTransactionService().commit().then((result)=>{
|
||||
@@ -72,6 +75,8 @@ export default class Editor extends EventEmitter {
|
||||
|
||||
/**
|
||||
* End the currently active transaction and discard unsaved changes.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
cancel() {
|
||||
this.getTransactionService().cancel();
|
||||
|
||||
@@ -178,8 +178,12 @@ define([
|
||||
* @method remove
|
||||
*/
|
||||
DefaultCompositionProvider.prototype.remove = function (domainObject, childId) {
|
||||
// TODO: this needs to be synchronized via mutation.
|
||||
throw new Error('Default Provider does not implement removal.');
|
||||
let composition = domainObject.composition.filter(function (child) {
|
||||
return !(childId.namespace === child.namespace &&
|
||||
childId.key === child.key);
|
||||
});
|
||||
|
||||
this.publicAPI.objects.mutate(domainObject, 'composition', composition);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -215,6 +215,19 @@ define([
|
||||
return utils.makeKeyString(identifier);
|
||||
};
|
||||
|
||||
/**
|
||||
* Given any number of identifiers, will return true if they are all equal, otherwise false.
|
||||
* @param {module:openmct.ObjectAPI~Identifier[]} identifiers
|
||||
*/
|
||||
ObjectAPI.prototype.areIdsEqual = function (...identifiers) {
|
||||
return identifiers.map(utils.parseKeyString)
|
||||
.every(identifier => {
|
||||
return identifier === identifiers[0] ||
|
||||
(identifier.namespace === identifiers[0].namespace &&
|
||||
identifier.key === identifiers[0].key);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Uniquely identifies a domain object.
|
||||
*
|
||||
|
||||
@@ -28,9 +28,9 @@ define([], function () {
|
||||
key: "layout",
|
||||
description: "A toolbar for objects inside a display layout.",
|
||||
forSelection: function (selection) {
|
||||
// Apply the layout toolbar if the edit mode is on, and the selected object
|
||||
// Apply the layout toolbar if the selected object
|
||||
// is inside a layout, or the main layout is selected.
|
||||
return (openmct.editor.isEditing() && selection &&
|
||||
return (selection &&
|
||||
((selection[1] && selection[1].context.item && selection[1].context.item.type === 'layout') ||
|
||||
(selection[0].context.item && selection[0].context.item.type === 'layout')));
|
||||
},
|
||||
|
||||
@@ -124,6 +124,8 @@
|
||||
bottom: Number.NEGATIVE_INFINITY
|
||||
};
|
||||
|
||||
const DRAG_OBJECT_TRANSFER_PREFIX = 'openmct/domain-object/';
|
||||
|
||||
function getItemDefinition(itemType, ...options) {
|
||||
let itemView = ITEM_TYPE_VIEW_MAP[itemType];
|
||||
|
||||
@@ -264,12 +266,26 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
handleDragOver($event){
|
||||
$event.preventDefault();
|
||||
containsObject(identifier) {
|
||||
return _.get(this.internalDomainObject, 'composition')
|
||||
.some(childId => this.openmct.objects.areIdsEqual(childId, identifier));
|
||||
},
|
||||
handleDragOver($event) {
|
||||
// Get the ID of the dragged object
|
||||
let draggedKeyString = $event.dataTransfer.types
|
||||
.filter(type => type.startsWith(DRAG_OBJECT_TRANSFER_PREFIX))
|
||||
.map(type => type.substring(DRAG_OBJECT_TRANSFER_PREFIX.length))[0];
|
||||
|
||||
// If the layout already contains the given object, then shortcut the default dragover behavior and
|
||||
// potentially allow drop. Display layouts allow drag drop of duplicate telemetry objects.
|
||||
if (this.containsObject(draggedKeyString)){
|
||||
$event.preventDefault();
|
||||
}
|
||||
},
|
||||
isTelemetry(domainObject) {
|
||||
if (this.openmct.telemetry.isTelemetryObject(domainObject)
|
||||
&& domainObject.type !== 'summary-widget') {
|
||||
&& domainObject.type !== 'summary-widget'
|
||||
&& domainObject.type !== 'example.imagery') {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
|
||||
@@ -26,7 +26,8 @@
|
||||
<object-frame v-if="domainObject"
|
||||
:domain-object="domainObject"
|
||||
:object-path="objectPath"
|
||||
:has-frame="item.hasFrame">
|
||||
:has-frame="item.hasFrame"
|
||||
ref="objectFrame">
|
||||
</object-frame>
|
||||
</layout-frame>
|
||||
</template>
|
||||
@@ -98,13 +99,15 @@
|
||||
setObject(domainObject) {
|
||||
this.domainObject = domainObject;
|
||||
this.objectPath = [this.domainObject].concat(this.openmct.router.path);
|
||||
this.context = {
|
||||
item: domainObject,
|
||||
layoutItem: this.item,
|
||||
index: this.index
|
||||
};
|
||||
this.removeSelectable = this.openmct.selection.selectable(
|
||||
this.$el, this.context, this.initSelect);
|
||||
this.$nextTick(function () {
|
||||
let childContext = this.$refs.objectFrame.getSelectionContext();
|
||||
childContext.item = domainObject;
|
||||
childContext.layoutItem = this.item;
|
||||
childContext.index = this.index;
|
||||
this.context = childContext;
|
||||
this.removeSelectable = this.openmct.selection.selectable(
|
||||
this.$el, this.context, this.initSelect);
|
||||
});
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
class="c-fl-frame__drop-hint"
|
||||
:index="-1"
|
||||
:allow-drop="allowDrop"
|
||||
@object-drop-to="moveOrCreateFrame">
|
||||
@object-drop-to="moveOrCreateNewFrame">
|
||||
</drop-hint>
|
||||
|
||||
<div class="c-fl-container__frames-holder">
|
||||
@@ -47,7 +47,8 @@
|
||||
:key="frame.id"
|
||||
:frame="frame"
|
||||
:index="i"
|
||||
:containerIndex="index">
|
||||
:containerIndex="index"
|
||||
:isEditing="isEditing">
|
||||
</frame-component>
|
||||
|
||||
<drop-hint
|
||||
@@ -55,7 +56,7 @@
|
||||
:key="i"
|
||||
:index="i"
|
||||
:allowDrop="allowDrop"
|
||||
@object-drop-to="moveOrCreateFrame">
|
||||
@object-drop-to="moveOrCreateNewFrame">
|
||||
</drop-hint>
|
||||
|
||||
<resize-handle
|
||||
@@ -65,7 +66,8 @@
|
||||
:orientation="rowsLayout ? 'horizontal' : 'vertical'"
|
||||
@init-move="startFrameResizing"
|
||||
@move="frameResizing"
|
||||
@end-move="endFrameResizing">
|
||||
@end-move="endFrameResizing"
|
||||
:isEditing="isEditing">
|
||||
</resize-handle>
|
||||
</template>
|
||||
</div>
|
||||
@@ -77,14 +79,12 @@ import FrameComponent from './frame.vue';
|
||||
import Frame from '../utils/frame';
|
||||
import ResizeHandle from './resizeHandle.vue';
|
||||
import DropHint from './dropHint.vue';
|
||||
import isEditingMixin from '../mixins/isEditing';
|
||||
|
||||
const MIN_FRAME_SIZE = 5;
|
||||
|
||||
export default {
|
||||
inject:['openmct'],
|
||||
props: ['container', 'index', 'rowsLayout'],
|
||||
mixins: [isEditingMixin],
|
||||
props: ['container', 'index', 'rowsLayout', 'isEditing'],
|
||||
components: {
|
||||
FrameComponent,
|
||||
ResizeHandle,
|
||||
@@ -123,15 +123,12 @@ export default {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
moveOrCreateFrame(insertIndex, event) {
|
||||
moveOrCreateNewFrame(insertIndex, event) {
|
||||
if (event.dataTransfer.types.includes('openmct/domain-object-path')) {
|
||||
// create frame using domain object
|
||||
let domainObject = JSON.parse(event.dataTransfer.getData('openmct/domain-object-path'))[0];
|
||||
this.$emit(
|
||||
'create-frame',
|
||||
'new-frame',
|
||||
this.index,
|
||||
insertIndex,
|
||||
domainObject.identifier
|
||||
insertIndex
|
||||
);
|
||||
return;
|
||||
};
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
<div v-show="isValidTarget">
|
||||
<div class="c-drop-hint c-drop-hint--always-show"
|
||||
:class="{'is-mouse-over': isMouseOver}"
|
||||
@dragover.prevent
|
||||
@dragenter="dragenter"
|
||||
@dragleave="dragleave"
|
||||
@drop="dropHandler">
|
||||
@@ -71,10 +72,12 @@ export default {
|
||||
mounted() {
|
||||
document.addEventListener('dragstart', this.dragstart);
|
||||
document.addEventListener('dragend', this.dragend);
|
||||
document.addEventListener('drop', this.dragend);
|
||||
},
|
||||
destroyed() {
|
||||
document.removeEventListener('dragstart', this.dragstart);
|
||||
document.removeEventListener('dragend', this.dragend);
|
||||
document.removeEventListener('drop', this.dragend);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -22,6 +22,11 @@
|
||||
|
||||
<template>
|
||||
<div class="c-fl">
|
||||
<div
|
||||
id="js-fl-drag-ghost"
|
||||
class="c-fl__drag-ghost">
|
||||
</div>
|
||||
|
||||
<div class="c-fl__empty"
|
||||
v-if="areAllContainersEmpty()">
|
||||
<span class="c-fl__empty-message">This Flexible Layout is currently empty</span>
|
||||
@@ -49,8 +54,9 @@
|
||||
:index="index"
|
||||
:container="container"
|
||||
:rowsLayout="rowsLayout"
|
||||
:isEditing="isEditing"
|
||||
@move-frame="moveFrame"
|
||||
@create-frame="createFrame"
|
||||
@new-frame="setFrameLocation"
|
||||
@persist="persist">
|
||||
</container-component>
|
||||
|
||||
@@ -59,6 +65,7 @@
|
||||
:key="index"
|
||||
:index="index"
|
||||
:orientation="rowsLayout ? 'vertical' : 'horizontal'"
|
||||
:isEditing="isEditing"
|
||||
@init-move="startContainerResizing"
|
||||
@move="containerResizing"
|
||||
@end-move="endContainerResizing">
|
||||
@@ -137,6 +144,23 @@
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
&__drag-ghost{
|
||||
background: $colorItemTreeHoverBg;
|
||||
color: $colorItemTreeHoverFg;
|
||||
border-radius: $basicCr;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: $interiorMarginLg $interiorMarginLg * 2;
|
||||
position: absolute;
|
||||
top: -10000px;
|
||||
z-index: 2;
|
||||
|
||||
&:before {
|
||||
color: $colorKey;
|
||||
margin-right: $interiorMarginSm;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.c-fl-container {
|
||||
@@ -398,7 +422,6 @@ import Container from '../utils/container';
|
||||
import Frame from '../utils/frame';
|
||||
import ResizeHandle from './resizeHandle.vue';
|
||||
import DropHint from './dropHint.vue';
|
||||
import isEditingMixin from '../mixins/isEditing';
|
||||
|
||||
const MIN_CONTAINER_SIZE = 5;
|
||||
|
||||
@@ -443,7 +466,6 @@ function sizeToFill(items) {
|
||||
|
||||
export default {
|
||||
inject: ['openmct', 'layoutObject'],
|
||||
mixins: [isEditingMixin],
|
||||
components: {
|
||||
ContainerComponent,
|
||||
ResizeHandle,
|
||||
@@ -451,9 +473,13 @@ export default {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
domainObject: this.layoutObject
|
||||
domainObject: this.layoutObject,
|
||||
newFrameLocation: []
|
||||
}
|
||||
},
|
||||
props: {
|
||||
isEditing: Boolean
|
||||
},
|
||||
computed: {
|
||||
layoutDirectionStr() {
|
||||
if (this.rowsLayout) {
|
||||
@@ -480,9 +506,27 @@ export default {
|
||||
this.persist();
|
||||
},
|
||||
deleteContainer(containerId) {
|
||||
let container = this.containers.filter(c => c.id === containerId)[0];
|
||||
let containerIndex = this.containers.indexOf(container);
|
||||
let container = this.containers.filter(c => c.id === containerId)[0],
|
||||
containerIndex = this.containers.indexOf(container);
|
||||
|
||||
/*
|
||||
remove associated domainObjects from composition
|
||||
*/
|
||||
container.frames.forEach(f => {
|
||||
this.composition.remove({identifier: f.domainObjectIdentifier});
|
||||
});
|
||||
|
||||
this.containers.splice(containerIndex, 1);
|
||||
|
||||
/*
|
||||
add a container when there are no containers in the FL,
|
||||
to prevent user from not being able to add a frame via
|
||||
drag and drop.
|
||||
*/
|
||||
if (this.containers.length === 0) {
|
||||
this.containers.push(new Container(100));
|
||||
}
|
||||
|
||||
sizeToFill(this.containers);
|
||||
this.persist();
|
||||
},
|
||||
@@ -497,12 +541,22 @@ export default {
|
||||
sizeItems(toContainer.frames, frame);
|
||||
this.persist();
|
||||
},
|
||||
createFrame(containerIndex, insertFrameIndex, objectIdentifier) {
|
||||
let frame = new Frame(objectIdentifier);
|
||||
let container = this.containers[containerIndex];
|
||||
container.frames.splice(insertFrameIndex + 1, 0, frame);
|
||||
sizeItems(container.frames, frame);
|
||||
this.persist();
|
||||
setFrameLocation(containerIndex, insertFrameIndex) {
|
||||
this.newFrameLocation = [containerIndex, insertFrameIndex];
|
||||
},
|
||||
addFrame(domainObject) {
|
||||
if (this.newFrameLocation.length) {
|
||||
let containerIndex = this.newFrameLocation[0],
|
||||
frameIndex = this.newFrameLocation[1],
|
||||
frame = new Frame(domainObject.identifier),
|
||||
container = this.containers[containerIndex];
|
||||
|
||||
container.frames.splice(frameIndex + 1, 0, frame);
|
||||
sizeItems(container.frames, frame);
|
||||
|
||||
this.newFrameLocation = [];
|
||||
this.persist(containerIndex);
|
||||
}
|
||||
},
|
||||
deleteFrame(frameId) {
|
||||
let container = this.containers
|
||||
@@ -512,6 +566,12 @@ export default {
|
||||
.frames
|
||||
.filter((f => f.id === frameId))[0];
|
||||
let frameIndex = container.frames.indexOf(frame);
|
||||
|
||||
/*
|
||||
remove associated domainObject from composition
|
||||
*/
|
||||
this.composition.remove({identifier: frame.domainObjectIdentifier});
|
||||
|
||||
container.frames.splice(frameIndex, 1);
|
||||
sizeToFill(container.frames);
|
||||
this.persist(containerIndex);
|
||||
@@ -584,13 +644,33 @@ export default {
|
||||
} else {
|
||||
this.containers.splice(toIndex, 0, container);
|
||||
}
|
||||
this.persist();
|
||||
},
|
||||
removeChildObject(identifier) {
|
||||
let removeIdentifier = this.openmct.objects.makeKeyString(identifier);
|
||||
|
||||
this.containers.forEach(container => {
|
||||
container.frames = container.frames.filter(frame => {
|
||||
let frameIdentifier = this.openmct.objects.makeKeyString(frame.domainObjectIdentifier);
|
||||
|
||||
return removeIdentifier !== frameIdentifier;
|
||||
});
|
||||
});
|
||||
|
||||
this.persist();
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.composition = this.openmct.composition.get(this.domainObject);
|
||||
this.composition.on('remove', this.removeChildObject);
|
||||
this.composition.on('add', this.addFrame);
|
||||
|
||||
this.unobserve = this.openmct.objects.observe(this.domainObject, '*', this.updateDomainObject);
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.composition.off('remove', this.removeChildObject);
|
||||
this.composition.off('add', this.addFrame);
|
||||
|
||||
this.unobserve();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,8 @@
|
||||
v-if="domainObject"
|
||||
:domain-object="domainObject"
|
||||
:object-path="objectPath"
|
||||
:has-frame="hasFrame">
|
||||
:has-frame="hasFrame"
|
||||
ref="objectFrame">
|
||||
</object-frame>
|
||||
|
||||
<div class="c-fl-frame__size-indicator"
|
||||
@@ -50,12 +51,10 @@
|
||||
<script>
|
||||
import ResizeHandle from './resizeHandle.vue';
|
||||
import ObjectFrame from '../../../ui/components/ObjectFrame.vue';
|
||||
import isEditingMixin from '../mixins/isEditing';
|
||||
|
||||
export default {
|
||||
inject: ['openmct'],
|
||||
props: ['frame', 'index', 'containerIndex'],
|
||||
mixins: [isEditingMixin],
|
||||
props: ['frame', 'index', 'containerIndex', 'isEditing'],
|
||||
data() {
|
||||
return {
|
||||
domainObject: undefined,
|
||||
@@ -73,22 +72,33 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
setDomainObject(object) {
|
||||
console.log('setting object!');
|
||||
this.domainObject = object;
|
||||
this.objectPath = [object];
|
||||
this.setSelection();
|
||||
},
|
||||
setSelection() {
|
||||
let context = {
|
||||
item: this.domainObject,
|
||||
addContainer: this.addContainer,
|
||||
type: 'frame',
|
||||
frameId: this.frame.id
|
||||
};
|
||||
|
||||
this.unsubscribeSelection = this.openmct.selection.selectable(this.$refs.frame, context, false);
|
||||
this.$nextTick(function () {
|
||||
let childContext = this.$refs.objectFrame.getSelectionContext();
|
||||
childContext.item = this.domainObject;
|
||||
childContext.type = 'frame';
|
||||
childContext.frameId = this.frame.id;
|
||||
this.unsubscribeSelection = this.openmct.selection.selectable(
|
||||
this.$refs.frame, childContext, false);
|
||||
});
|
||||
},
|
||||
initDrag(event) {
|
||||
let type = this.openmct.types.get(this.domainObject.type),
|
||||
iconClass = type.definition ? type.definition.cssClass : 'icon-object-unknown';
|
||||
|
||||
if (this.dragGhost) {
|
||||
let originalClassName = this.dragGhost.classList[0];
|
||||
this.dragGhost.className = '';
|
||||
this.dragGhost.classList.add(originalClassName, iconClass);
|
||||
|
||||
this.dragGhost.innerHTML = `<span>${this.domainObject.name}</span>`;
|
||||
event.dataTransfer.setDragImage(this.dragGhost, 0, 0);
|
||||
}
|
||||
|
||||
event.dataTransfer.setData('frameid', this.frame.id);
|
||||
event.dataTransfer.setData('containerIndex', this.containerIndex);
|
||||
}
|
||||
@@ -99,6 +109,8 @@ export default {
|
||||
this.setDomainObject(object);
|
||||
});
|
||||
}
|
||||
|
||||
this.dragGhost = document.getElementById('js-fl-drag-ghost');
|
||||
},
|
||||
beforeDestroy() {
|
||||
if (this.unsubscribeSelection) {
|
||||
|
||||
@@ -29,11 +29,8 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import isEditingMixin from '../mixins/isEditing';
|
||||
|
||||
export default {
|
||||
props: ['orientation', 'index'],
|
||||
mixins: [isEditingMixin],
|
||||
props: ['orientation', 'index', 'isEditing'],
|
||||
data() {
|
||||
return {
|
||||
initialPos: 0,
|
||||
|
||||
@@ -42,8 +42,13 @@ define([
|
||||
let component;
|
||||
|
||||
return {
|
||||
show: function (element) {
|
||||
show: function (element, isEditing) {
|
||||
component = new Vue({
|
||||
data() {
|
||||
return {
|
||||
isEditing: isEditing
|
||||
}
|
||||
},
|
||||
components: {
|
||||
FlexibleLayoutComponent: FlexibleLayoutComponent.default
|
||||
},
|
||||
@@ -52,7 +57,7 @@ define([
|
||||
layoutObject: domainObject
|
||||
},
|
||||
el: element,
|
||||
template: '<flexible-layout-component ref="flexibleLayout"></flexible-layout-component>'
|
||||
template: '<flexible-layout-component ref="flexibleLayout" :isEditing="isEditing"></flexible-layout-component>'
|
||||
});
|
||||
},
|
||||
getSelectionContext: function () {
|
||||
@@ -64,6 +69,9 @@ define([
|
||||
type: 'flexible-layout'
|
||||
};
|
||||
},
|
||||
onEditModeChange: function (isEditing) {
|
||||
component.isEditing = isEditing;
|
||||
},
|
||||
destroy: function (element) {
|
||||
component.$destroy();
|
||||
component = undefined;
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
export default {
|
||||
inject: ['openmct'],
|
||||
data() {
|
||||
return {
|
||||
isEditing: this.openmct.editor.isEditing()
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.openmct.editor.on('isEditing', this.toggleEditing);
|
||||
},
|
||||
destroyed() {
|
||||
this.openmct.editor.off('isEditing', this.toggleEditing);
|
||||
},
|
||||
methods: {
|
||||
toggleEditing(value) {
|
||||
this.isEditing = value;
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -29,7 +29,7 @@ function ToolbarProvider(openmct) {
|
||||
forSelection: function (selection) {
|
||||
let context = selection[0].context;
|
||||
|
||||
return (openmct.editor.isEditing() && context && context.type &&
|
||||
return (context && context.type &&
|
||||
(context.type === 'flexible-layout' || context.type === 'container' || context.type === 'frame'));
|
||||
},
|
||||
toolbar: function (selection) {
|
||||
@@ -53,7 +53,7 @@ function ToolbarProvider(openmct) {
|
||||
toggleContainer = {
|
||||
control: 'toggle-button',
|
||||
key: 'toggle-layout',
|
||||
domainObject: secondary ? secondary.context.item : primary.context.item,
|
||||
domainObject: primary.context.item,
|
||||
property: 'configuration.rowsLayout',
|
||||
options: [
|
||||
{
|
||||
@@ -140,6 +140,8 @@ function ToolbarProvider(openmct) {
|
||||
title: 'Add Container'
|
||||
};
|
||||
|
||||
toggleContainer.domainObject = secondary.context.item;
|
||||
|
||||
} else if (primary.context.type === 'container') {
|
||||
|
||||
deleteContainer = {
|
||||
@@ -151,7 +153,7 @@ function ToolbarProvider(openmct) {
|
||||
|
||||
let prompt = openmct.overlays.dialog({
|
||||
iconClass: 'alert',
|
||||
message: `This action will permanently delete container ${containerIndex + 1} from this Flexible Layout`,
|
||||
message: 'This action will permanently delete this container from this Flexible Layout',
|
||||
buttons: [
|
||||
{
|
||||
label: 'Ok',
|
||||
@@ -202,7 +204,7 @@ function ToolbarProvider(openmct) {
|
||||
addContainer,
|
||||
toggleFrame ? separator: undefined,
|
||||
toggleFrame,
|
||||
deleteFrame || deleteContainer ? separator: undefined,
|
||||
deleteFrame || deleteContainer ? separator : undefined,
|
||||
deleteFrame,
|
||||
deleteContainer
|
||||
];
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
</div>
|
||||
<div class="hide-menu hidden">
|
||||
<div class="menu-element context-menu-wrapper mobile-disable-select">
|
||||
<div class="menu context-menu">
|
||||
<div class="c-menu">
|
||||
<ul>
|
||||
<li v-for="action in actions"
|
||||
:key="action.name"
|
||||
|
||||
@@ -254,13 +254,14 @@ function (
|
||||
// Remove the context menu
|
||||
function dismiss() {
|
||||
container.find('.hide-menu').append(menu);
|
||||
body.off(initiatingEvent, dismiss);
|
||||
menu.off(initiatingEvent, menuClickHandler);
|
||||
body.off(initiatingEvent, menuClickHandler);
|
||||
dismissExistingMenu = undefined;
|
||||
}
|
||||
|
||||
function menuClickHandler(e) {
|
||||
e.stopPropagation();
|
||||
window.setTimeout(() => {
|
||||
dismiss();
|
||||
}, 100);
|
||||
}
|
||||
|
||||
// Dismiss any menu which was already showing
|
||||
@@ -276,11 +277,7 @@ function (
|
||||
marginY: -50
|
||||
});
|
||||
|
||||
// Stop propagation so that clicks or touches on the menu do not close the menu
|
||||
menu.on(initiatingEvent, menuClickHandler);
|
||||
|
||||
body.on(initiatingEvent, dismiss);
|
||||
|
||||
body.on(initiatingEvent, menuClickHandler);
|
||||
};
|
||||
|
||||
EmbedController.prototype.exposedData = function () {
|
||||
|
||||
@@ -30,7 +30,7 @@ define(
|
||||
],
|
||||
function (
|
||||
html2canvas,
|
||||
saveAs
|
||||
{ saveAs }
|
||||
) {
|
||||
|
||||
/**
|
||||
|
||||
@@ -24,16 +24,10 @@ define([
|
||||
return domainObject.type === 'summary-widget';
|
||||
},
|
||||
view: function (domainObject) {
|
||||
var statusService = openmct.$injector.get('statusService');
|
||||
var objectId = objectUtils.makeKeyString(domainObject.identifier);
|
||||
var statuses = statusService.listStatuses(objectId);
|
||||
var isEditing = statuses.indexOf('editing') !== -1;
|
||||
|
||||
if (isEditing) {
|
||||
return new SummaryWidgetEditView(domainObject, openmct);
|
||||
} else {
|
||||
return new SummaryWidgetView(domainObject, openmct);
|
||||
}
|
||||
return new SummaryWidgetView(domainObject, openmct);
|
||||
},
|
||||
edit: function (domainObject) {
|
||||
return new SummaryWidgetEditView(domainObject, openmct);
|
||||
},
|
||||
priority: function (domainObject) {
|
||||
if (domainObject.type === 'summary-widget') {
|
||||
|
||||
@@ -47,8 +47,13 @@ define([
|
||||
let table = new TelemetryTable(domainObject, openmct);
|
||||
let component;
|
||||
return {
|
||||
show: function (element) {
|
||||
show: function (element, isEditing) {
|
||||
component = new Vue({
|
||||
data() {
|
||||
return {
|
||||
isEditing: false
|
||||
}
|
||||
},
|
||||
components: {
|
||||
TableComponent: TableComponent.default,
|
||||
},
|
||||
@@ -58,9 +63,12 @@ define([
|
||||
table
|
||||
},
|
||||
el: element,
|
||||
template: '<table-component></table-component>'
|
||||
template: '<table-component :isEditing="isEditing"></table-component>'
|
||||
});
|
||||
},
|
||||
onEditModeChange(isEditing) {
|
||||
component.isEditing = isEditing;
|
||||
},
|
||||
destroy: function (element) {
|
||||
component.$destroy();
|
||||
component = undefined;
|
||||
|
||||
@@ -73,18 +73,14 @@ const MOVE_COLUMN_DT_TYPE = 'movecolumnfromindex';
|
||||
|
||||
export default {
|
||||
inject: ['openmct'],
|
||||
data() {
|
||||
return {
|
||||
isEditing: this.openmct.editor.isEditing()
|
||||
}
|
||||
},
|
||||
props: {
|
||||
headerKey: String,
|
||||
headerIndex: Number,
|
||||
isHeaderTitle: Boolean,
|
||||
sortOptions: Object,
|
||||
columnWidth: Number,
|
||||
hotzone: Boolean
|
||||
hotzone: Boolean,
|
||||
isEditing: Boolean
|
||||
},
|
||||
computed: {
|
||||
isSortable() {
|
||||
@@ -167,16 +163,7 @@ export default {
|
||||
},
|
||||
sort() {
|
||||
this.$emit("sort");
|
||||
},
|
||||
toggleEditMode(isEditing) {
|
||||
this.isEditing = isEditing;
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.openmct.editor.on('isEditing', this.toggleEditMode);
|
||||
},
|
||||
destroyed() {
|
||||
this.openmct.editor.off('isEditing', this.toggleEditMode);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -48,6 +48,7 @@
|
||||
@resizeColumnEnd="updateConfiguredColumnWidths"
|
||||
:columnWidth="columnWidths[key]"
|
||||
:sortOptions="sortOptions"
|
||||
:isEditing="isEditing"
|
||||
>{{title}}</table-column-header>
|
||||
</tr>
|
||||
<tr class="c-telemetry-table__headers__filter">
|
||||
@@ -61,7 +62,9 @@
|
||||
@dropTargetActive="dropTargetActive"
|
||||
@reorderColumn="reorderColumn"
|
||||
@resizeColumnEnd="updateConfiguredColumnWidths"
|
||||
:columnWidth="columnWidths[key]">
|
||||
:columnWidth="columnWidths[key]"
|
||||
:isEditing="isEditing"
|
||||
>
|
||||
<search class="c-table__search"
|
||||
v-model="filters[key]"
|
||||
v-on:input="filterChanged(key)"
|
||||
@@ -260,6 +263,12 @@ export default {
|
||||
search
|
||||
},
|
||||
inject: ['table', 'openmct', 'csvExporter'],
|
||||
props: {
|
||||
isEditing: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data() {
|
||||
let configuration = this.table.configuration.getConfiguration();
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
v-model="formattedBounds.start"
|
||||
@change="validateAllBounds(); submitForm()" />
|
||||
<date-picker
|
||||
v-if="isFixed && isUTCBased"
|
||||
:default-date-time="formattedBounds.start"
|
||||
:formatter="timeFormatter"
|
||||
@date-selected="startDateSelected"></date-picker>
|
||||
@@ -65,11 +66,11 @@
|
||||
ref="endDate"
|
||||
@change="validateAllBounds(); submitForm()">
|
||||
<date-picker
|
||||
v-if="isFixed && isUTCBased"
|
||||
class="c-ctrl-wrapper--menus-left"
|
||||
:default-date-time="formattedBounds.end"
|
||||
:formatter="timeFormatter"
|
||||
@date-selected="endDateSelected"
|
||||
v-if="isFixed"></date-picker>
|
||||
@date-selected="endDateSelected"></date-picker>
|
||||
</div>
|
||||
|
||||
<div class="c-ctrl-wrapper c-conductor-input c-conductor__end-delta"
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
*****************************************************************************/
|
||||
|
||||
import Conductor from './Conductor.vue';
|
||||
import Vue from 'vue';
|
||||
|
||||
function isTruthy(a) {
|
||||
return !!a;
|
||||
@@ -29,20 +28,17 @@ function isTruthy(a) {
|
||||
|
||||
function validateMenuOption(menuOption, index) {
|
||||
if (menuOption.clock && !menuOption.clockOffsets) {
|
||||
return "clock-based menuOption at index " + index + " is " +
|
||||
"missing required property 'clockOffsets'.";
|
||||
return `Conductor menu option is missing required property 'clockOffsets'. This field is required when configuring a menu option with a clock.\r\n${JSON.stringify(menuOption)}`;
|
||||
}
|
||||
if (!menuOption.timeSystem) {
|
||||
return "menuOption at index " + index + " is missing " +
|
||||
"required property 'timeSystem'.";
|
||||
return `Conductor menu option is missing required property 'timeSystem'\r\n${JSON.stringify(menuOption)}`;
|
||||
}
|
||||
if (!menuOption.bounds && !menuOption.clock) {
|
||||
return "fixed-bounds menuOption at index " + index + " is " +
|
||||
"missing required property 'bounds'";
|
||||
return `Conductor menu option is missing required property 'bounds'. This field is required when configuring a menu option with fixed bounds.\r\n${JSON.stringify(menuOption)}`;
|
||||
}
|
||||
}
|
||||
|
||||
function validateConfiguration(config) {
|
||||
function hasRequiredOptions(config) {
|
||||
if (config === undefined ||
|
||||
config.menuOptions === undefined ||
|
||||
config.menuOptions.length === 0) {
|
||||
@@ -56,7 +52,7 @@ function validateConfiguration(config) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function validateRuntimeConfiguration(config, openmct) {
|
||||
function validateConfiguration(config, openmct) {
|
||||
var systems = openmct.time.getAllTimeSystems()
|
||||
.reduce(function (m, ts) {
|
||||
m[ts.key] = ts;
|
||||
@@ -68,23 +64,19 @@ function validateRuntimeConfiguration(config, openmct) {
|
||||
return m;
|
||||
}, {});
|
||||
|
||||
return config.menuOptions.map(function (menuOption, index) {
|
||||
return config.menuOptions.map(function (menuOption) {
|
||||
if (menuOption.timeSystem && !systems[menuOption.timeSystem]) {
|
||||
return "menuOption at index " + index + " specifies a " +
|
||||
"timeSystem that does not exist: " + menuOption.timeSystem;
|
||||
return `Time system '${menuOption.timeSystem}' has not been registered: \r\n ${JSON.stringify(menuOption)}`;
|
||||
}
|
||||
if (menuOption.clock && !clocks[menuOption.clock]) {
|
||||
return "menuOption at index " + index + " specifies a " +
|
||||
"clock that does not exist: " + menuOption.clock;
|
||||
return `Clock '${menuOption.clock}' has not been registered: \r\n ${JSON.stringify(menuOption)}`;
|
||||
}
|
||||
}).filter(isTruthy).join('\n');
|
||||
}
|
||||
|
||||
function throwIfError(configResult) {
|
||||
if (configResult) {
|
||||
throw new Error("Invalid Time Conductor Configuration: \n" +
|
||||
configResult + '\n' +
|
||||
"https://github.com/nasa/openmct/blob/master/API.md#the-time-conductor");
|
||||
throw new Error(`Invalid Time Conductor Configuration. ${configResult} \r\n https://github.com/nasa/openmct/blob/master/API.md#the-time-conductor`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,27 +93,21 @@ function mountComponent(openmct, configuration) {
|
||||
});
|
||||
}
|
||||
|
||||
export default function (config){
|
||||
|
||||
let configResult = validateConfiguration(config);
|
||||
throwIfError(configResult);
|
||||
|
||||
export default function (config) {
|
||||
return function (openmct) {
|
||||
let configResult = hasRequiredOptions(config) || validateConfiguration(config, openmct);
|
||||
throwIfError(configResult);
|
||||
|
||||
var defaults = config.menuOptions[0];
|
||||
if (defaults.clock) {
|
||||
openmct.time.clock(defaults.clock, defaults.clockOffsets);
|
||||
openmct.time.timeSystem(defaults.timeSystem, openmct.time.bounds());
|
||||
} else {
|
||||
openmct.time.timeSystem(defaults.timeSystem, defaults.bounds);
|
||||
}
|
||||
|
||||
openmct.on('start', function () {
|
||||
configResult = validateRuntimeConfiguration(config, openmct);
|
||||
throwIfError(configResult);
|
||||
|
||||
var defaults = config.menuOptions[0];
|
||||
if (defaults.clock) {
|
||||
openmct.time.clock(defaults.clock, defaults.clockOffsets);
|
||||
openmct.time.timeSystem(defaults.timeSystem, openmct.time.bounds());
|
||||
} else {
|
||||
openmct.time.timeSystem(defaults.timeSystem, defaults.bounds);
|
||||
}
|
||||
|
||||
mountComponent(openmct, config);
|
||||
|
||||
});
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -129,6 +129,10 @@
|
||||
objectPath: Array,
|
||||
hasFrame: Boolean,
|
||||
},
|
||||
components: {
|
||||
ObjectView,
|
||||
ContextMenuDropDown,
|
||||
},
|
||||
methods: {
|
||||
expand() {
|
||||
let objectView = this.$refs.objectView,
|
||||
@@ -142,12 +146,11 @@
|
||||
parentElement.append(childElement);
|
||||
}
|
||||
});
|
||||
},
|
||||
getSelectionContext() {
|
||||
return this.$refs.objectView.getSelectionContext();
|
||||
}
|
||||
},
|
||||
components: {
|
||||
ObjectView,
|
||||
ContextMenuDropDown,
|
||||
},
|
||||
data() {
|
||||
let objectType = this.openmct.types.get(this.domainObject.type),
|
||||
cssClass = objectType && objectType.definition ? objectType.definition.cssClass : 'icon-object-unknown',
|
||||
|
||||
@@ -66,6 +66,7 @@ export default {
|
||||
dragStart(event) {
|
||||
let navigatedObject = this.openmct.router.path[0];
|
||||
let serializedPath = JSON.stringify(this.objectPath);
|
||||
let keyString = this.openmct.objects.makeKeyString(this.domainObject.identifier);
|
||||
|
||||
/*
|
||||
* Cannot inspect data transfer objects on dragover/dragenter so impossible to determine composability at
|
||||
@@ -78,6 +79,7 @@ export default {
|
||||
// serialize domain object anyway, because some views can drag-and-drop objects without composition
|
||||
// (eg. notabook.)
|
||||
event.dataTransfer.setData("openmct/domain-object-path", serializedPath);
|
||||
event.dataTransfer.setData(`openmct/domain-object/${keyString}`, this.domainObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,9 @@ export default {
|
||||
},
|
||||
destroyed() {
|
||||
this.clear();
|
||||
if (this.releaseEditModeHandler) {
|
||||
this.releaseEditModeHandler();
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
view(newView, oldView) {
|
||||
@@ -37,9 +40,26 @@ export default {
|
||||
if (this.currentView) {
|
||||
this.currentView.destroy();
|
||||
this.$el.innerHTML = '';
|
||||
|
||||
if (this.releaseEditModeHandler) {
|
||||
this.releaseEditModeHandler();
|
||||
delete this.releaseEditModeHandler;
|
||||
}
|
||||
}
|
||||
delete this.viewContainer;
|
||||
delete this.currentView;
|
||||
|
||||
if (this.removeSelectable) {
|
||||
this.removeSelectable();
|
||||
delete this.removeSelectable;
|
||||
}
|
||||
},
|
||||
invokeEditModeHandler(editMode) {
|
||||
this.currentView.onEditModeChange(editMode);
|
||||
},
|
||||
toggleEditView(editMode) {
|
||||
this.clear();
|
||||
this.updateView(true);
|
||||
},
|
||||
updateView(immediatelySelect) {
|
||||
this.clear();
|
||||
@@ -50,23 +70,36 @@ export default {
|
||||
this.viewContainer.classList.add('c-object-view','u-contents');
|
||||
this.$el.append(this.viewContainer);
|
||||
let provider = this.openmct.objectViews.getByProviderKey(this.viewKey);
|
||||
|
||||
if (!provider) {
|
||||
provider = this.openmct.objectViews.get(this.currentObject)[0];
|
||||
if (!provider) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
this.currentView = provider.view(this.currentObject);
|
||||
this.currentView.show(this.viewContainer);
|
||||
|
||||
|
||||
if (provider.edit) {
|
||||
if (this.openmct.editor.isEditing()) {
|
||||
this.currentView = provider.edit(this.currentObject);
|
||||
} else {
|
||||
this.currentView = provider.view(this.currentObject, false);
|
||||
}
|
||||
this.openmct.editor.on('isEditing', this.toggleEditView);
|
||||
this.releaseEditModeHandler = () => this.openmct.editor.off('isEditing', this.toggleEditView);
|
||||
} else {
|
||||
this.currentView = provider.view(this.currentObject, this.openmct.editor.isEditing());
|
||||
|
||||
if (this.currentView.onEditModeChange) {
|
||||
this.openmct.editor.on('isEditing', this.invokeEditModeHandler);
|
||||
this.releaseEditModeHandler = () => this.openmct.editor.off('isEditing', this.invokeEditModeHandler);
|
||||
}
|
||||
}
|
||||
this.currentView.show(this.viewContainer, this.openmct.editor.isEditing());
|
||||
|
||||
if (immediatelySelect) {
|
||||
this.removeSelectable = openmct.selection.selectable(
|
||||
this.$el,
|
||||
this.currentView.getSelectionContext ?
|
||||
this.currentView.getSelectionContext() :
|
||||
{ item: this.currentObject },
|
||||
true
|
||||
);
|
||||
this.$el, this.getSelectionContext(), true);
|
||||
}
|
||||
},
|
||||
show(object, viewKey, immediatelySelect) {
|
||||
@@ -87,6 +120,13 @@ export default {
|
||||
this.viewKey = viewKey;
|
||||
this.updateView(immediatelySelect);
|
||||
},
|
||||
getSelectionContext() {
|
||||
if (this.currentView.getSelectionContext) {
|
||||
return this.currentView.getSelectionContext();
|
||||
} else {
|
||||
return { item: this.currentObject };
|
||||
}
|
||||
},
|
||||
onDragOver(event) {
|
||||
if (this.hasComposableDomainObject(event)) {
|
||||
event.preventDefault();
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
<template>
|
||||
<div class="c-elements-pool">
|
||||
<Search class="c-elements-pool__search" @input="applySearch"></Search>
|
||||
<Search class="c-elements-pool__search"
|
||||
:value="currentSearch"
|
||||
@input="applySearch"
|
||||
@clear="applySearch">
|
||||
</Search>
|
||||
<div class="c-elements-pool__elements">
|
||||
<ul class="tree c-tree c-elements-pool__tree" id="inspector-elements-tree"
|
||||
v-if="elements.length > 0">
|
||||
@@ -69,7 +73,8 @@ export default {
|
||||
return {
|
||||
elements: [],
|
||||
isEditing: this.openmct.editor.isEditing(),
|
||||
parentObject: undefined
|
||||
parentObject: undefined,
|
||||
currentSearch: ''
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
|
||||
@@ -235,7 +235,7 @@
|
||||
if (selection[0]) {
|
||||
let parentObject = selection[0].context.item;
|
||||
|
||||
this.hasComposition = !!this.openmct.composition.get(parentObject);
|
||||
this.hasComposition = !!(parentObject && this.openmct.composition.get(parentObject));
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -8,12 +8,14 @@
|
||||
:class="type.cssClass">
|
||||
<span
|
||||
class="l-browse-bar__object-name c-input-inline"
|
||||
v-on:blur="updateName"
|
||||
@blur="updateName"
|
||||
@keydown.enter.prevent
|
||||
@keyup.enter.prevent="updateNameOnEnterKeyPress"
|
||||
contenteditable>
|
||||
{{ domainObject.name }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="l-browse-bar__context-actions c-disclosure-button" @click="showContextMenu"></div>
|
||||
<div class="l-browse-bar__context-actions c-disclosure-button" @click.prevent.stop="showContextMenu"></div>
|
||||
</div>
|
||||
|
||||
<div class="l-browse-bar__end">
|
||||
@@ -22,7 +24,7 @@
|
||||
<button class="c-button--menu"
|
||||
:class="currentView.cssClass"
|
||||
title="Switch view type"
|
||||
@click="toggleViewMenu">
|
||||
@click.stop="toggleViewMenu">
|
||||
<span class="c-button__label">
|
||||
{{ currentView.name }}
|
||||
</span>
|
||||
@@ -41,13 +43,32 @@
|
||||
</div>
|
||||
<!-- Action buttons -->
|
||||
<div class="l-browse-bar__actions">
|
||||
<button class="l-browse-bar__actions__edit c-button icon-notebook"
|
||||
<button class="l-browse-bar__actions__notebook-entry c-button icon-notebook"
|
||||
title="New Notebook entry"
|
||||
@click="snapshot()">
|
||||
</button>
|
||||
<button class="l-browse-bar__actions__notebook-entry c-button c-button--major icon-pencil" title="Edit" v-if="isViewEditable & !isEditing" @click="edit()"></button>
|
||||
<button class="l-browse-bar__actions c-button c-button--major icon-save" title="Save and Finish Editing" v-if="isEditing" @click="saveAndFinishEditing()"></button>
|
||||
<button class="l-browse-bar__actions c-button icon-x" title="Cancel Editing" v-if="isEditing" @click="cancelEditing()"></button>
|
||||
<button class="l-browse-bar__actions__edit c-button c-button--major icon-pencil" title="Edit" v-if="isViewEditable & !isEditing" @click="edit()"></button>
|
||||
|
||||
<div class="l-browse-bar__view-switcher c-ctrl-wrapper c-ctrl-wrapper--menus-left"
|
||||
v-if="isEditing">
|
||||
<button class="c-button--menu c-button--major icon-save" title="Save" @click.stop="toggleSaveMenu"></button>
|
||||
<div class="c-menu" v-show="showSaveMenu">
|
||||
<ul>
|
||||
<li @click="saveAndFinishEditing"
|
||||
class="icon-save"
|
||||
title="Save and Finish Editing">
|
||||
Save and Finish Editing
|
||||
</li>
|
||||
<li @click="saveAndContinueEditing"
|
||||
class="icon-save"
|
||||
title="Save and Continue Editing">
|
||||
Save and Continue Editing
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button class="l-browse-bar__actions c-button icon-x" title="Cancel Editing" v-if="isEditing" @click="promptUserandCancelEditing()"></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -60,17 +81,26 @@ const PLACEHOLDER_OBJECT = {};
|
||||
export default {
|
||||
inject: ['openmct'],
|
||||
methods: {
|
||||
toggleViewMenu: function (event) {
|
||||
event.stopPropagation();
|
||||
toggleViewMenu() {
|
||||
this.showViewMenu = !this.showViewMenu;
|
||||
},
|
||||
updateName: function (event) {
|
||||
toggleSaveMenu() {
|
||||
this.showSaveMenu = !this.showSaveMenu;
|
||||
},
|
||||
closeViewAndSaveMenu() {
|
||||
this.showViewMenu = false;
|
||||
this.showSaveMenu = false;
|
||||
},
|
||||
updateName(event) {
|
||||
// TODO: handle isssues with contenteditable text escaping.
|
||||
if (event.target.innerText !== this.domainObject.name) {
|
||||
this.openmct.objects.mutate(this.domainObject, 'name', event.target.innerText);
|
||||
}
|
||||
},
|
||||
setView: function (view) {
|
||||
updateNameOnEnterKeyPress (event) {
|
||||
event.target.blur();
|
||||
},
|
||||
setView(view) {
|
||||
this.viewKey = view.key;
|
||||
this.openmct.router.updateParams({
|
||||
view: this.viewKey
|
||||
@@ -79,20 +109,48 @@ const PLACEHOLDER_OBJECT = {};
|
||||
edit() {
|
||||
this.openmct.editor.edit();
|
||||
},
|
||||
cancelEditing() {
|
||||
this.openmct.editor.cancel();
|
||||
promptUserandCancelEditing() {
|
||||
let dialog = this.openmct.overlays.dialog({
|
||||
iconClass: 'alert',
|
||||
message: 'Are you sure you want to continue? All unsaved changes will be lost!',
|
||||
buttons: [
|
||||
{
|
||||
label: 'Ok',
|
||||
emphasis: true,
|
||||
callback: () => {
|
||||
this.openmct.editor.cancel();
|
||||
dialog.dismiss();
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'Cancel',
|
||||
callback: () => {
|
||||
dialog.dismiss();
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
},
|
||||
promptUserbeforeNavigatingAway(event) {
|
||||
if(this.openmct.editor.isEditing()) {
|
||||
event.preventDefault();
|
||||
event.returnValue = '';
|
||||
}
|
||||
},
|
||||
saveAndFinishEditing() {
|
||||
this.openmct.editor.save().then(()=> {
|
||||
return this.openmct.editor.save().then(()=> {
|
||||
this.openmct.notifications.info('Save successful');
|
||||
}).catch((error) => {
|
||||
this.openmct.notifications.error('Error saving objects');
|
||||
console.error(error);
|
||||
});
|
||||
},
|
||||
saveAndContinueEditing() {
|
||||
this.saveAndFinishEditing().then(() => {
|
||||
this.openmct.editor.edit();
|
||||
});
|
||||
},
|
||||
showContextMenu(event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
this.openmct.contextMenu._showContextMenuForObjectPath(this.openmct.router.path, event.clientX, event.clientY);
|
||||
},
|
||||
snapshot() {
|
||||
@@ -106,6 +164,7 @@ const PLACEHOLDER_OBJECT = {};
|
||||
data: function () {
|
||||
return {
|
||||
showViewMenu: false,
|
||||
showSaveMenu: false,
|
||||
domainObject: PLACEHOLDER_OBJECT,
|
||||
viewKey: undefined,
|
||||
isEditing: this.openmct.editor.isEditing()
|
||||
@@ -156,15 +215,16 @@ const PLACEHOLDER_OBJECT = {};
|
||||
mounted: function () {
|
||||
this.notebookSnapshot = new NotebookSnapshot(this.openmct);
|
||||
|
||||
document.addEventListener('click', () => {
|
||||
if (this.showViewMenu) {
|
||||
this.showViewMenu = false;
|
||||
}
|
||||
});
|
||||
document.addEventListener('click', this.closeViewAndSaveMenu);
|
||||
window.addEventListener('beforeunload', this.promptUserbeforeNavigatingAway);
|
||||
|
||||
this.openmct.editor.on('isEditing', (isEditing) => {
|
||||
this.isEditing = isEditing;
|
||||
});
|
||||
},
|
||||
beforeDestroy: function () {
|
||||
document.removeEventListener('click', this.closeViewAndSaveMenu);
|
||||
window.removeEventListener('click', this.promptUserbeforeNavigatingAway);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -22,9 +22,6 @@
|
||||
handle="after"
|
||||
label="Browse"
|
||||
collapsable>
|
||||
<div class="l-shell__search">
|
||||
<search class="c-search--major" ref="shell-search"></search>
|
||||
</div>
|
||||
<mct-tree class="l-shell__tree"></mct-tree>
|
||||
</pane>
|
||||
<pane class="l-shell__pane-main">
|
||||
@@ -250,7 +247,6 @@
|
||||
import ObjectView from '../components/ObjectView.vue';
|
||||
import MctTemplate from '../legacy/mct-template.vue';
|
||||
import CreateButton from './CreateButton.vue';
|
||||
import search from '../components/search.vue';
|
||||
import multipane from './multipane.vue';
|
||||
import pane from './pane.vue';
|
||||
import BrowseBar from './BrowseBar.vue';
|
||||
@@ -293,7 +289,6 @@
|
||||
ObjectView,
|
||||
'mct-template': MctTemplate,
|
||||
CreateButton,
|
||||
search,
|
||||
multipane,
|
||||
pane,
|
||||
BrowseBar,
|
||||
@@ -301,34 +296,24 @@
|
||||
Toolbar
|
||||
},
|
||||
mounted() {
|
||||
this.openmct.editor.on('isEditing', (isEditing)=>{
|
||||
this.isEditing = isEditing;
|
||||
});
|
||||
this.openmct.selection.on('change', this.toggleHasToolbar);
|
||||
this.openmct.editor.on('isEditing', this.toggleIsEditing);
|
||||
},
|
||||
data: function () {
|
||||
return {
|
||||
fullScreen: false,
|
||||
conductorComponent: {},
|
||||
isEditing: false
|
||||
conductorComponent: undefined,
|
||||
isEditing: false,
|
||||
hasToolbar: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
toolbar() {
|
||||
let selection = this.openmct.selection.get();
|
||||
let structure = undefined;
|
||||
|
||||
if (!selection[0]) {
|
||||
structure = [];
|
||||
} else {
|
||||
structure = this.openmct.toolbars.get(selection);
|
||||
}
|
||||
|
||||
return this.isEditing && structure.length > 0;
|
||||
return this.isEditing && this.hasToolbar;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
fullScreenToggle() {
|
||||
|
||||
if (this.fullScreen) {
|
||||
this.fullScreen = false;
|
||||
exitFullScreen();
|
||||
@@ -338,8 +323,26 @@
|
||||
}
|
||||
},
|
||||
openInNewTab(event) {
|
||||
event.target.href = window.location.href;
|
||||
window.open(window.location.href);
|
||||
},
|
||||
toggleHasToolbar(selection) {
|
||||
let structure = undefined;
|
||||
|
||||
if (!selection[0]) {
|
||||
structure = [];
|
||||
} else {
|
||||
structure = this.openmct.toolbars.get(selection);
|
||||
}
|
||||
|
||||
this.hasToolbar = structure.length > 0;
|
||||
},
|
||||
toggleIsEditing(isEditing) {
|
||||
this.isEditing = isEditing;
|
||||
}
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.openmct.selection.off('change', this.toggleHasToolbar);
|
||||
this.openmct.editor.off('isEditing', this.toggleIsEditing);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,9 +1,20 @@
|
||||
<template>
|
||||
<div class="c-tree__wrapper">
|
||||
<div class="l-shell__search">
|
||||
<search class="c-search--major" ref="shell-search"
|
||||
:value="searchValue"
|
||||
@input="searchTree"
|
||||
@clear="searchTree">
|
||||
</search>
|
||||
</div>
|
||||
<div
|
||||
v-if="treeItems.length === 0">
|
||||
No results found
|
||||
</div>
|
||||
<ul class="c-tree">
|
||||
<tree-item v-for="child in children"
|
||||
:key="child.id"
|
||||
:node="child">
|
||||
<tree-item v-for="treeItem in treeItems"
|
||||
:key="treeItem.id"
|
||||
:node="treeItem">
|
||||
</tree-item>
|
||||
</ul>
|
||||
</div>
|
||||
@@ -125,28 +136,78 @@
|
||||
|
||||
<script>
|
||||
import treeItem from './tree-item.vue'
|
||||
import search from '../components/search.vue';
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
children: []
|
||||
};
|
||||
},
|
||||
inject: ['openmct'],
|
||||
mounted: function () {
|
||||
this.openmct.objects.get('ROOT')
|
||||
.then(root => this.openmct.composition.get(root).load())
|
||||
.then(children => this.children = children.map((c) => {
|
||||
return {
|
||||
id: this.openmct.objects.makeKeyString(c.identifier),
|
||||
object: c,
|
||||
objectPath: [c]
|
||||
};
|
||||
}))
|
||||
},
|
||||
name: 'mct-tree',
|
||||
components: {
|
||||
search,
|
||||
treeItem
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
searchValue: '',
|
||||
allTreeItems: [],
|
||||
filteredTreeItems: []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
treeItems() {
|
||||
if (this.searchValue === '') {
|
||||
return this.allTreeItems;
|
||||
} else {
|
||||
return this.filteredTreeItems;
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getAllChildren() {
|
||||
this.openmct.objects.get('ROOT')
|
||||
.then(root => this.openmct.composition.get(root).load())
|
||||
.then(children => {
|
||||
this.allTreeItems = children.map(c => {
|
||||
return {
|
||||
id: this.openmct.objects.makeKeyString(c.identifier),
|
||||
object: c,
|
||||
objectPath: [c]
|
||||
};
|
||||
});
|
||||
});
|
||||
},
|
||||
getFilteredChildren() {
|
||||
this.searchService.query(this.searchValue).then(children => {
|
||||
this.filteredTreeItems = children.hits.map(child => {
|
||||
|
||||
let context = child.object.getCapability('context'),
|
||||
object = child.object.useCapability('adapter'),
|
||||
objectPath = [];
|
||||
|
||||
if (context) {
|
||||
objectPath = context.getPath().slice(1)
|
||||
.map(oldObject => oldObject.useCapability('adapter'))
|
||||
.reverse();
|
||||
}
|
||||
|
||||
return {
|
||||
id: this.openmct.objects.makeKeyString(object.identifier),
|
||||
object,
|
||||
objectPath
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
searchTree(value) {
|
||||
this.searchValue = value;
|
||||
|
||||
if (this.searchValue !== '') {
|
||||
this.getFilteredChildren();
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.searchService = this.openmct.$injector.get('searchService');
|
||||
this.getAllChildren();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -183,6 +183,12 @@
|
||||
+ .l-pane {
|
||||
@include userSelectNone();
|
||||
}
|
||||
|
||||
.l-pane {
|
||||
&__handle {
|
||||
background: $colorSplitterHover;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&[class*="--collapsed"] {
|
||||
@@ -368,12 +374,12 @@ export default {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
label: String,
|
||||
resizing: Boolean
|
||||
label: String
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
collapsed: false
|
||||
collapsed: false,
|
||||
resizing: false
|
||||
}
|
||||
},
|
||||
beforeMount() {
|
||||
|
||||
@@ -20,19 +20,31 @@
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
<template>
|
||||
<div class="l-preview-window">
|
||||
<div class="l-preview-window__object-name l-browse-bar__object-name--w" :class="type.cssClass">
|
||||
<span class="l-browse-bar__object-name">
|
||||
{{ domainObject.name }}
|
||||
</span>
|
||||
<context-menu-drop-down :object-path="objectPath"></context-menu-drop-down>
|
||||
<div class="l-preview-window">
|
||||
<div class="l-browse-bar">
|
||||
<div class="l-browse-bar__start">
|
||||
<div class="l-browse-bar__object-name--w"
|
||||
:class="type.cssClass">
|
||||
<span class="l-browse-bar__object-name">
|
||||
{{ domainObject.name }}
|
||||
</span>
|
||||
<context-menu-drop-down :object-path="objectPath"></context-menu-drop-down>
|
||||
</div>
|
||||
</div>
|
||||
<div class="l-browse-bar__end">
|
||||
<div class="l-browse-bar__actions">
|
||||
<button class="l-browse-bar__actions__edit c-button icon-notebook"
|
||||
title="New Notebook entry"
|
||||
@click="snapshot">
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="l-preview-window__object-view">
|
||||
<div ref="objectView"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="l-preview-window__object-view">
|
||||
<div ref="objectView">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
<style lang="scss">
|
||||
@import '~styles/sass-base';
|
||||
|
||||
@@ -63,6 +75,7 @@
|
||||
|
||||
<script>
|
||||
import ContextMenuDropDown from '../../ui/components/contextMenuDropDown.vue';
|
||||
import NotebookSnapshot from '../utils/notebook-snapshot';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
@@ -72,6 +85,12 @@
|
||||
'openmct',
|
||||
'objectPath'
|
||||
],
|
||||
methods: {
|
||||
snapshot() {
|
||||
let element = document.getElementsByClassName("l-preview-window__object-view")[0];
|
||||
this.notebookSnapshot.capture(this.domainObject, element);
|
||||
}
|
||||
},
|
||||
data() {
|
||||
let domainObject = this.objectPath[0];
|
||||
let type = this.openmct.types.get(domainObject.type);
|
||||
@@ -84,7 +103,8 @@
|
||||
mounted() {
|
||||
let viewProvider = this.openmct.objectViews.get(this.domainObject)[0];
|
||||
this.view = viewProvider.view(this.domainObject);
|
||||
this.view.show(this.$refs.objectView);
|
||||
this.view.show(this.$refs.objectView, false);
|
||||
this.notebookSnapshot = new NotebookSnapshot(this.openmct);
|
||||
},
|
||||
destroy() {
|
||||
this.view.destroy();
|
||||
|
||||
@@ -120,6 +120,19 @@ define([], function () {
|
||||
* @memberof module:openmct.View#
|
||||
*/
|
||||
|
||||
/**
|
||||
* Indicates whether or not the application is in edit mode. This supports
|
||||
* views that have distinct visual and behavioral elements when the
|
||||
* navigated object is being edited.
|
||||
*
|
||||
* For cases where a completely separate view is desired for editing purposes,
|
||||
* see {@link openmct.ViewProvider#edit}
|
||||
*
|
||||
* @param {boolean} isEditing
|
||||
* @method show
|
||||
* @memberof module:openmct.View#
|
||||
*/
|
||||
|
||||
/**
|
||||
* Release any resources associated with this view.
|
||||
*
|
||||
@@ -172,7 +185,15 @@ define([], function () {
|
||||
|
||||
/**
|
||||
* An optional function that defines whether or not this view can be used to edit a given object.
|
||||
* If not provided, will default to `false` and the view will not support editing.
|
||||
* If not provided, will default to `false` and the view will not support editing. To support editing,
|
||||
* return true from this function and then -
|
||||
* * Return a {@link openmct.View} from the `view` function, using the `onEditModeChange` callback to
|
||||
* add and remove editing elements from the view
|
||||
* OR
|
||||
* * Return a {@link openmct.View} from the `view` function defining a read-only view.
|
||||
* AND
|
||||
* * Define an {@link openmct.ViewProvider#Edit} function on the view provider that returns an
|
||||
* editing-specific view.
|
||||
*
|
||||
* @method canEdit
|
||||
* @memberof module:openmct.ViewProvider#
|
||||
@@ -211,6 +232,19 @@ define([], function () {
|
||||
* @returns {module:openmct.View} a view of this domain object
|
||||
*/
|
||||
|
||||
/**
|
||||
* Provide an edit-mode specific view of this object.
|
||||
*
|
||||
* If optionally specified, this function will be called when the application
|
||||
* enters edit mode. This will cause the active non-edit mode view and its
|
||||
* dom element to be destroyed.
|
||||
*
|
||||
* @method edit
|
||||
* @memberof module:openmct.ViewProvider#
|
||||
* @param {*} object the object to be edit
|
||||
* @returns {module:openmct.View} an editable view of this domain object
|
||||
*/
|
||||
|
||||
return ViewRegistry;
|
||||
|
||||
});
|
||||
|
||||
@@ -8,13 +8,17 @@ define([
|
||||
let navigateCall = 0;
|
||||
let browseObject;
|
||||
|
||||
function viewObject(object, viewProvider) {
|
||||
function viewObject(object, viewProvider, edit) {
|
||||
openmct.layout.$refs.browseObject.show(object, viewProvider.key, true);
|
||||
openmct.layout.$refs.browseBar.domainObject = object;
|
||||
openmct.layout.$refs.browseBar.viewKey = viewProvider.key;
|
||||
};
|
||||
|
||||
function navigateToPath(path, currentViewKey) {
|
||||
if (edit && viewProvider.canEdit && viewProvider.canEdit(object)) {
|
||||
openmct.editor.edit();
|
||||
}
|
||||
}
|
||||
|
||||
function navigateToPath(path, currentViewKey, edit) {
|
||||
navigateCall++;
|
||||
let currentNavigation = navigateCall;
|
||||
|
||||
@@ -48,7 +52,7 @@ define([
|
||||
.getByProviderKey(currentViewKey)
|
||||
|
||||
if (currentProvider && currentProvider.canView(navigatedObject)) {
|
||||
viewObject(navigatedObject, currentProvider);
|
||||
viewObject(navigatedObject, currentProvider, edit);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -71,18 +75,27 @@ define([
|
||||
if (!navigatePath) {
|
||||
navigatePath = 'mine';
|
||||
}
|
||||
navigateToPath(navigatePath, params.view);
|
||||
|
||||
navigateToPath(navigatePath, params.view, params.edit === 'true');
|
||||
});
|
||||
|
||||
openmct.router.on('change:params', function (newParams, oldParams, changed) {
|
||||
if (changed.view && browseObject) {
|
||||
let provider = openmct
|
||||
.objectViews
|
||||
.getByProviderKey(changed.view);
|
||||
viewObject(browseObject, provider);
|
||||
.objectViews
|
||||
.getByProviderKey(changed.view),
|
||||
edit = newParams.edit === 'true';
|
||||
|
||||
viewObject(browseObject, provider, edit);
|
||||
}
|
||||
});
|
||||
|
||||
openmct.editor.on('isEditing', function (isEditing) {
|
||||
openmct.router.updateParams({
|
||||
edit: isEditing
|
||||
});
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
@@ -7,8 +7,7 @@
|
||||
<input :id="uid"
|
||||
:type="options.type"
|
||||
:value="options.value"
|
||||
v-bind="options.attrs"
|
||||
@change="onChange"/>
|
||||
v-bind="options.attrs"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -31,15 +30,26 @@ export default {
|
||||
uid: `mct-input-id-${inputUniqueId}`
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
if (this.options.type === 'number') {
|
||||
this.$el.addEventListener('input', this.onInput);
|
||||
} else {
|
||||
this.$el.addEventListener('change', this.onChange);
|
||||
}
|
||||
},
|
||||
beforeDestroy() {
|
||||
if (this.options.type === 'number') {
|
||||
this.$el.removeEventListener('input', this.onInput);
|
||||
} else {
|
||||
this.$el.removeEventListener('change', this.onChange);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onChange(event) {
|
||||
let value = event.target.value;
|
||||
|
||||
if (this.options.type === 'number') {
|
||||
value = event.target.valueAsNumber;
|
||||
}
|
||||
|
||||
this.$emit('change', value, this.options);
|
||||
this.$emit('change', event.target.value, this.options);
|
||||
},
|
||||
onInput(event) {
|
||||
this.$emit('change', event.target.valueAsNumber, this.options);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user