Compare commits
	
		
			1 Commits
		
	
	
		
			vista-4.2-
			...
			table-colu
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					ca88996d86 | 
@@ -99,10 +99,10 @@ define([
 | 
			
		||||
 | 
			
		||||
    GeneratorMetadataProvider.prototype.getMetadata = function (domainObject) {
 | 
			
		||||
        return _.extend(
 | 
			
		||||
            {},
 | 
			
		||||
            domainObject.telemetry,
 | 
			
		||||
            METADATA_BY_TYPE[domainObject.type]
 | 
			
		||||
        );
 | 
			
		||||
                {},
 | 
			
		||||
                domainObject.telemetry,
 | 
			
		||||
                METADATA_BY_TYPE[domainObject.type]
 | 
			
		||||
            );
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    return GeneratorMetadataProvider;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,9 +1,9 @@
 | 
			
		||||
<span class="h-indicator" ng-controller="DialogLaunchController">
 | 
			
		||||
    <!-- DO NOT ADD SPACES BETWEEN THE SPANS - IT ADDS WHITE SPACE!! -->
 | 
			
		||||
    <div class="c-indicator c-indicator--clickable icon-box-with-arrow s-status-available"><span class="label c-indicator__label">
 | 
			
		||||
        <button ng-click="launchProgress(true)">Known</button>
 | 
			
		||||
        <button ng-click="launchProgress(false)">Unknown</button>
 | 
			
		||||
        <button ng-click="launchError()">Error</button>
 | 
			
		||||
        <button ng-click="launchInfo()">Info</button>
 | 
			
		||||
    <div class="ls-indicator icon-box-with-arrow s-status-available"><span class="label">
 | 
			
		||||
        <a ng-click="launchProgress(true)">Known</a>
 | 
			
		||||
        <a ng-click="launchProgress(false)">Unknown</a>
 | 
			
		||||
        <a ng-click="launchError()">Error</a>
 | 
			
		||||
        <a ng-click="launchInfo()">Info</a>
 | 
			
		||||
    </span></div>
 | 
			
		||||
</span>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,9 +1,9 @@
 | 
			
		||||
<span class="h-indicator" ng-controller="NotificationLaunchController">
 | 
			
		||||
    <!-- DO NOT ADD SPACES BETWEEN THE SPANS - IT ADDS WHITE SPACE!! -->
 | 
			
		||||
    <div class="c-indicator c-indicator--clickable icon-bell s-status-available"><span class="label c-indicator__label">
 | 
			
		||||
        <button ng-click="newInfo()">Success</button>
 | 
			
		||||
        <button ng-click="newError()">Error</button>
 | 
			
		||||
        <button ng-click="newAlert()">Alert</button>
 | 
			
		||||
        <button ng-click="newProgress()">Progress</button>
 | 
			
		||||
    <div class="ls-indicator icon-bell s-status-available"><span class="label">
 | 
			
		||||
        <a ng-click="newInfo()">Success</a>
 | 
			
		||||
        <a ng-click="newError()">Error</a>
 | 
			
		||||
        <a ng-click="newAlert()">Alert</a>
 | 
			
		||||
        <a ng-click="newProgress()">Progress</a>
 | 
			
		||||
    </span></div>
 | 
			
		||||
</span>
 | 
			
		||||
 
 | 
			
		||||
@@ -50,12 +50,10 @@
 | 
			
		||||
        openmct.install(openmct.plugins.Generator());
 | 
			
		||||
        openmct.install(openmct.plugins.ExampleImagery());
 | 
			
		||||
        openmct.install(openmct.plugins.UTCTimeSystem());
 | 
			
		||||
        openmct.install(openmct.plugins.ImportExport());
 | 
			
		||||
        openmct.install(openmct.plugins.AutoflowView({
 | 
			
		||||
            type: "telemetry.panel"
 | 
			
		||||
        }));
 | 
			
		||||
        openmct.install(openmct.plugins.DisplayLayout({
 | 
			
		||||
            showAsView: ['summary-widget', 'example.imagery']
 | 
			
		||||
        }));
 | 
			
		||||
        openmct.install(openmct.plugins.Conductor({
 | 
			
		||||
            menuOptions: [
 | 
			
		||||
                {
 | 
			
		||||
@@ -79,9 +77,12 @@
 | 
			
		||||
        }));
 | 
			
		||||
        openmct.install(openmct.plugins.SummaryWidget());
 | 
			
		||||
        openmct.install(openmct.plugins.Notebook());
 | 
			
		||||
        openmct.install(openmct.plugins.FolderView());
 | 
			
		||||
        openmct.install(openmct.plugins.Tabs());
 | 
			
		||||
        openmct.install(openmct.plugins.FlexibleLayout());
 | 
			
		||||
        openmct.install(openmct.plugins.LADTable());
 | 
			
		||||
        openmct.install(openmct.plugins.Filters(['table', 'telemetry.plot.overlay']));
 | 
			
		||||
        openmct.install(openmct.plugins.ObjectMigration());
 | 
			
		||||
        openmct.install(openmct.plugins.ClearData(['table', 'telemetry.plot.overlay', 'telemetry.plot.stacked']));
 | 
			
		||||
        openmct.start();
 | 
			
		||||
    </script>
 | 
			
		||||
</html>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,10 +1,9 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "openmct",
 | 
			
		||||
  "version": "1.0.0-beta",
 | 
			
		||||
  "version": "0.14.0-SNAPSHOT",
 | 
			
		||||
  "description": "The Open MCT core platform",
 | 
			
		||||
  "dependencies": {},
 | 
			
		||||
  "devDependencies": {
 | 
			
		||||
    "acorn": "6.2.0",
 | 
			
		||||
    "angular": "1.4.14",
 | 
			
		||||
    "angular-route": "1.4.14",
 | 
			
		||||
    "babel-eslint": "8.2.6",
 | 
			
		||||
@@ -56,7 +55,7 @@
 | 
			
		||||
    "node-bourbon": "^4.2.3",
 | 
			
		||||
    "node-sass": "^4.9.2",
 | 
			
		||||
    "painterro": "^0.2.65",
 | 
			
		||||
    "printj": "^1.2.1",
 | 
			
		||||
    "printj": "^1.1.0",
 | 
			
		||||
    "raw-loader": "^0.5.1",
 | 
			
		||||
    "request": "^2.69.0",
 | 
			
		||||
    "split": "^1.0.0",
 | 
			
		||||
 
 | 
			
		||||
@@ -31,6 +31,7 @@ define([
 | 
			
		||||
    "./src/navigation/NavigateAction",
 | 
			
		||||
    "./src/navigation/OrphanNavigationHandler",
 | 
			
		||||
    "./src/windowing/NewTabAction",
 | 
			
		||||
    "./src/windowing/WindowTitler",
 | 
			
		||||
    "./res/templates/browse.html",
 | 
			
		||||
    "./res/templates/browse-object.html",
 | 
			
		||||
    "./res/templates/browse/object-header.html",
 | 
			
		||||
@@ -51,6 +52,7 @@ define([
 | 
			
		||||
    NavigateAction,
 | 
			
		||||
    OrphanNavigationHandler,
 | 
			
		||||
    NewTabAction,
 | 
			
		||||
    WindowTitler,
 | 
			
		||||
    browseTemplate,
 | 
			
		||||
    browseObjectTemplate,
 | 
			
		||||
    objectHeaderTemplate,
 | 
			
		||||
@@ -224,6 +226,14 @@ define([
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "runs": [
 | 
			
		||||
                {
 | 
			
		||||
                    "implementation": WindowTitler,
 | 
			
		||||
                    "depends": [
 | 
			
		||||
                        "navigationService",
 | 
			
		||||
                        "$rootScope",
 | 
			
		||||
                        "$document"
 | 
			
		||||
                    ]
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "implementation": OrphanNavigationHandler,
 | 
			
		||||
                    "depends": [
 | 
			
		||||
 
 | 
			
		||||
@@ -20,20 +20,32 @@
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
export default class ClearDataAction {
 | 
			
		||||
    constructor(openmct, appliesToObjects) {
 | 
			
		||||
        this.name = 'Clear Data';
 | 
			
		||||
        this.description = 'Clears current data for object, unsubscribes and resubscribes to data';
 | 
			
		||||
define(
 | 
			
		||||
    [],
 | 
			
		||||
    function () {
 | 
			
		||||
 | 
			
		||||
        this._openmct = openmct;
 | 
			
		||||
        this._appliesToObjects = appliesToObjects;
 | 
			
		||||
    }
 | 
			
		||||
    invoke(objectPath) {
 | 
			
		||||
        this._openmct.objectViews.emit('clearData', objectPath[0]);
 | 
			
		||||
    }
 | 
			
		||||
    appliesTo(objectPath) {
 | 
			
		||||
        let contextualDomainObject = objectPath[0];
 | 
			
		||||
        /**
 | 
			
		||||
         * Updates the title of the current window to reflect the name
 | 
			
		||||
         * of the currently navigated-to domain object.
 | 
			
		||||
         * @memberof platform/commonUI/browse
 | 
			
		||||
         * @constructor
 | 
			
		||||
         */
 | 
			
		||||
        function WindowTitler(navigationService, $rootScope, $document) {
 | 
			
		||||
            // Look up name of the navigated domain object...
 | 
			
		||||
            function getNavigatedObjectName() {
 | 
			
		||||
                var navigatedObject = navigationService.getNavigation();
 | 
			
		||||
                return navigatedObject && navigatedObject.getModel().name;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        return this._appliesToObjects.filter(type => contextualDomainObject.type === type).length;
 | 
			
		||||
            // Set the window title...
 | 
			
		||||
            function setTitle(name) {
 | 
			
		||||
                $document[0].title = name;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Watch the former, and invoke the latter
 | 
			
		||||
            $rootScope.$watch(getNavigatedObjectName, setTitle);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return WindowTitler;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
);
 | 
			
		||||
							
								
								
									
										78
									
								
								platform/commonUI/browse/test/windowing/WindowTitlerSpec.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								platform/commonUI/browse/test/windowing/WindowTitlerSpec.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,78 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT, Copyright (c) 2014-2018, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * WindowTitlerSpec. Created by vwoeltje on 11/6/14.
 | 
			
		||||
 */
 | 
			
		||||
define(
 | 
			
		||||
    ["../../src/windowing/WindowTitler"],
 | 
			
		||||
    function (WindowTitler) {
 | 
			
		||||
 | 
			
		||||
        describe("The window titler", function () {
 | 
			
		||||
            var mockNavigationService,
 | 
			
		||||
                mockRootScope,
 | 
			
		||||
                mockDocument,
 | 
			
		||||
                mockDomainObject,
 | 
			
		||||
                titler; // eslint-disable-line
 | 
			
		||||
 | 
			
		||||
            beforeEach(function () {
 | 
			
		||||
                mockNavigationService = jasmine.createSpyObj(
 | 
			
		||||
                    'navigationService',
 | 
			
		||||
                    ['getNavigation']
 | 
			
		||||
                );
 | 
			
		||||
                mockRootScope = jasmine.createSpyObj(
 | 
			
		||||
                    '$rootScope',
 | 
			
		||||
                    ['$watch']
 | 
			
		||||
                );
 | 
			
		||||
                mockDomainObject = jasmine.createSpyObj(
 | 
			
		||||
                    'domainObject',
 | 
			
		||||
                    ['getModel']
 | 
			
		||||
                );
 | 
			
		||||
                mockDocument = [{}];
 | 
			
		||||
 | 
			
		||||
                mockDomainObject.getModel.and.returnValue({ name: 'Test name' });
 | 
			
		||||
                mockNavigationService.getNavigation.and.returnValue(mockDomainObject);
 | 
			
		||||
 | 
			
		||||
                titler = new WindowTitler(
 | 
			
		||||
                    mockNavigationService,
 | 
			
		||||
                    mockRootScope,
 | 
			
		||||
                    mockDocument
 | 
			
		||||
                );
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("listens for changes to the name of the navigated object", function () {
 | 
			
		||||
                expect(mockRootScope.$watch).toHaveBeenCalledWith(
 | 
			
		||||
                    jasmine.any(Function),
 | 
			
		||||
                    jasmine.any(Function)
 | 
			
		||||
                );
 | 
			
		||||
                expect(mockRootScope.$watch.calls.mostRecent().args[0]())
 | 
			
		||||
                    .toEqual('Test name');
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("sets the title to the name of the navigated object", function () {
 | 
			
		||||
                mockRootScope.$watch.calls.mostRecent().args[1]("Some name");
 | 
			
		||||
                expect(mockDocument[0].title).toEqual("Some name");
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
@@ -65,8 +65,7 @@ define([
 | 
			
		||||
                    "depends": [
 | 
			
		||||
                        "$document",
 | 
			
		||||
                        "$compile",
 | 
			
		||||
                        "$rootScope",
 | 
			
		||||
                        "$timeout"
 | 
			
		||||
                        "$rootScope"
 | 
			
		||||
                    ]
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
 
 | 
			
		||||
@@ -9,17 +9,17 @@
 | 
			
		||||
                         ng-model="ngModel"
 | 
			
		||||
                         ng-show="ngModel.progressPerc !== undefined"></mct-include>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="c-overlay__button-bar">
 | 
			
		||||
        <button ng-repeat="dialogOption in ngModel.options"
 | 
			
		||||
        <div class="c-overlay__button-bar">
 | 
			
		||||
            <button ng-repeat="dialogOption in ngModel.options"
 | 
			
		||||
                class="c-button"
 | 
			
		||||
                ng-click="dialogOption.callback()">
 | 
			
		||||
            {{dialogOption.label}}
 | 
			
		||||
        </button>
 | 
			
		||||
        <button class="c-button c-button--major"
 | 
			
		||||
                    {{dialogOption.label}}
 | 
			
		||||
            </button>
 | 
			
		||||
            <button class="c-button c-button--major"
 | 
			
		||||
                ng-if="ngModel.primaryOption"
 | 
			
		||||
                ng-click="ngModel.primaryOption.callback()">
 | 
			
		||||
            {{ngModel.primaryOption.label}}
 | 
			
		||||
        </button>
 | 
			
		||||
                    {{ngModel.primaryOption.label}}
 | 
			
		||||
            </button>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
</div>
 | 
			
		||||
 
 | 
			
		||||
@@ -44,9 +44,8 @@ define(
 | 
			
		||||
         * @memberof platform/commonUI/dialog
 | 
			
		||||
         * @constructor
 | 
			
		||||
         */
 | 
			
		||||
        function OverlayService($document, $compile, $rootScope, $timeout) {
 | 
			
		||||
        function OverlayService($document, $compile, $rootScope) {
 | 
			
		||||
            this.$compile = $compile;
 | 
			
		||||
            this.$timeout = $timeout;
 | 
			
		||||
 | 
			
		||||
            // Don't include $document and $rootScope directly;
 | 
			
		||||
            // avoids https://docs.angularjs.org/error/ng/cpws
 | 
			
		||||
@@ -94,14 +93,12 @@ define(
 | 
			
		||||
            scope.key = key;
 | 
			
		||||
            scope.typeClass = typeClass || 't-dialog';
 | 
			
		||||
 | 
			
		||||
            this.$timeout(() => {
 | 
			
		||||
                // Create the overlay element and add it to the document's body
 | 
			
		||||
                element = this.$compile(TEMPLATE)(scope);
 | 
			
		||||
                
 | 
			
		||||
                // Append so that most recent dialog is last in DOM. This means the most recent dialog will be on top when
 | 
			
		||||
                // multiple overlays with the same z-index are active.
 | 
			
		||||
                this.findBody().append(element);
 | 
			
		||||
            });
 | 
			
		||||
            // Create the overlay element and add it to the document's body
 | 
			
		||||
            element = this.$compile(TEMPLATE)(scope);
 | 
			
		||||
            
 | 
			
		||||
            // Append so that most recent dialog is last in DOM. This means the most recent dialog will be on top when
 | 
			
		||||
            // multiple overlays with the same z-index are active.
 | 
			
		||||
            this.findBody().append(element);
 | 
			
		||||
 | 
			
		||||
            return {
 | 
			
		||||
                dismiss: dismiss
 | 
			
		||||
 
 | 
			
		||||
@@ -35,20 +35,16 @@ define(
 | 
			
		||||
                mockTemplate,
 | 
			
		||||
                mockElement,
 | 
			
		||||
                mockScope,
 | 
			
		||||
                mockTimeout,
 | 
			
		||||
                overlayService;
 | 
			
		||||
 | 
			
		||||
            beforeEach(function () {
 | 
			
		||||
                mockDocument = jasmine.createSpyObj("$document", ["find"]);
 | 
			
		||||
                mockCompile = jasmine.createSpy("$compile");
 | 
			
		||||
                mockRootScope = jasmine.createSpyObj("$rootScope", ["$new"]);
 | 
			
		||||
                mockBody = jasmine.createSpyObj("body", ["append"]);
 | 
			
		||||
                mockBody = jasmine.createSpyObj("body", ["prepend"]);
 | 
			
		||||
                mockTemplate = jasmine.createSpy("template");
 | 
			
		||||
                mockElement = jasmine.createSpyObj("element", ["remove"]);
 | 
			
		||||
                mockScope = jasmine.createSpyObj("scope", ["$destroy"]);
 | 
			
		||||
                mockTimeout = function (callback) {
 | 
			
		||||
                    callback();
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                mockDocument.find.and.returnValue(mockBody);
 | 
			
		||||
                mockCompile.and.returnValue(mockTemplate);
 | 
			
		||||
@@ -58,8 +54,7 @@ define(
 | 
			
		||||
                overlayService = new OverlayService(
 | 
			
		||||
                    mockDocument,
 | 
			
		||||
                    mockCompile,
 | 
			
		||||
                    mockRootScope,
 | 
			
		||||
                    mockTimeout
 | 
			
		||||
                    mockRootScope
 | 
			
		||||
                );
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
@@ -72,7 +67,7 @@ define(
 | 
			
		||||
 | 
			
		||||
            it("adds the templated element to the body", function () {
 | 
			
		||||
                overlayService.createOverlay("test", {});
 | 
			
		||||
                expect(mockBody.append).toHaveBeenCalledWith(mockElement);
 | 
			
		||||
                expect(mockBody.prepend).toHaveBeenCalledWith(mockElement);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("places the provided model/key in its template's scope", function () {
 | 
			
		||||
 
 | 
			
		||||
@@ -49,7 +49,7 @@ define(
 | 
			
		||||
                    name: "Properties",
 | 
			
		||||
                    rows: this.properties.map(function (property, index) {
 | 
			
		||||
                        // Property definition is same as form row definition
 | 
			
		||||
                        var row = JSON.parse(JSON.stringify(property.getDefinition()));
 | 
			
		||||
                        var row = Object.create(property.getDefinition());
 | 
			
		||||
                        row.key = index;
 | 
			
		||||
                        return row;
 | 
			
		||||
                    }).filter(function (row) {
 | 
			
		||||
 
 | 
			
		||||
@@ -162,6 +162,9 @@ function (
 | 
			
		||||
        function saveAfterClone(clonedObject) {
 | 
			
		||||
            return this.openmct.editor.save().then(() => {
 | 
			
		||||
                // Force mutation for search indexing
 | 
			
		||||
                clonedObject.useCapability('mutation', (model) => {
 | 
			
		||||
                    return model;
 | 
			
		||||
                });
 | 
			
		||||
                return clonedObject;
 | 
			
		||||
            })
 | 
			
		||||
        }
 | 
			
		||||
@@ -170,14 +173,6 @@ function (
 | 
			
		||||
            return fetchObject(clonedObject.getId())
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        function indexForSearch(savedObject) {
 | 
			
		||||
            savedObject.useCapability('mutation', (model) => {
 | 
			
		||||
                return model;
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            return savedObject;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        function onSuccess(object) {
 | 
			
		||||
            self.notificationService.info("Save Succeeded");
 | 
			
		||||
            return object;
 | 
			
		||||
@@ -199,7 +194,6 @@ function (
 | 
			
		||||
            .then(undirtyOriginals)
 | 
			
		||||
            .then(saveAfterClone)
 | 
			
		||||
            .then(finishEditing)
 | 
			
		||||
            .then(indexForSearch)
 | 
			
		||||
            .then(hideBlockingDialog)
 | 
			
		||||
            .then(onSuccess)
 | 
			
		||||
            .catch(onFailure);
 | 
			
		||||
 
 | 
			
		||||
@@ -64,6 +64,7 @@ define(
 | 
			
		||||
         * @returns boolean
 | 
			
		||||
         */
 | 
			
		||||
        EditorCapability.prototype.inEditContext = function () {
 | 
			
		||||
            console.warn('DEPRECATION WARNING: isEditing checks must be done via openmct.editor.');
 | 
			
		||||
            return this.openmct.editor.isEditing();
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
@@ -73,6 +74,7 @@ define(
 | 
			
		||||
         * @returns {*}
 | 
			
		||||
         */
 | 
			
		||||
        EditorCapability.prototype.isEditContextRoot = function () {
 | 
			
		||||
            console.warn('DEPRECATION WARNING: isEditing checks must be done via openmct.editor.');
 | 
			
		||||
            return this.openmct.editor.isEditing();
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -71,12 +71,6 @@ define(
 | 
			
		||||
                openmct.editor.cancel();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            function isFirstViewEditable(domainObject) {
 | 
			
		||||
                let firstView = openmct.objectViews.get(domainObject)[0];
 | 
			
		||||
 | 
			
		||||
                return firstView && firstView.canEdit && firstView.canEdit(domainObject);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            function navigateAndEdit(object) {
 | 
			
		||||
                let objectPath = object.getCapability('context').getPath(),
 | 
			
		||||
                    url = '#/browse/' + objectPath
 | 
			
		||||
@@ -88,9 +82,7 @@ define(
 | 
			
		||||
 | 
			
		||||
                window.location.href = url;
 | 
			
		||||
 | 
			
		||||
                if (isFirstViewEditable(object.useCapability('adapter'))) {
 | 
			
		||||
                    openmct.editor.edit();
 | 
			
		||||
                }
 | 
			
		||||
                openmct.editor.edit();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            newModel.type = this.type.getKey();
 | 
			
		||||
 
 | 
			
		||||
@@ -66,7 +66,7 @@ define(
 | 
			
		||||
                name: "Properties",
 | 
			
		||||
                rows: this.properties.map(function (property, index) {
 | 
			
		||||
                    // Property definition is same as form row definition
 | 
			
		||||
                    var row = JSON.parse(JSON.stringify(property.getDefinition()));
 | 
			
		||||
                    var row = Object.create(property.getDefinition());
 | 
			
		||||
 | 
			
		||||
                    // Use index as the key into the formValue;
 | 
			
		||||
                    // this correlates to the indexing provided by
 | 
			
		||||
 
 | 
			
		||||
@@ -77,19 +77,14 @@ define([], function () {
 | 
			
		||||
                return promiseFn().then(nextFn);
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
        /**
 | 
			
		||||
         * Clear any existing persistence calls for object with given ID. This ensures only the most recent persistence
 | 
			
		||||
         * call is executed. This should prevent stale objects being persisted and overwriting fresh ones.
 | 
			
		||||
         */
 | 
			
		||||
        if (this.isScheduled(id)) {
 | 
			
		||||
            this.clearTransactionsFor(id);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.clearTransactionFns[id] =
 | 
			
		||||
            this.transactionService.addToTransaction(
 | 
			
		||||
                chain(onCommit, release),
 | 
			
		||||
                chain(onCancel, release)
 | 
			
		||||
            );
 | 
			
		||||
        if (!this.isScheduled(id)) {
 | 
			
		||||
            this.clearTransactionFns[id] =
 | 
			
		||||
                this.transactionService.addToTransaction(
 | 
			
		||||
                    chain(onCommit, release),
 | 
			
		||||
                    chain(onCancel, release)
 | 
			
		||||
                );
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
 
 | 
			
		||||
@@ -93,33 +93,24 @@ define(
 | 
			
		||||
                    expect(mockOnCancel).toHaveBeenCalled();
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                describe("Adds callbacks to transaction", function () {
 | 
			
		||||
                    beforeEach(function () {
 | 
			
		||||
                        spyOn(manager, 'clearTransactionsFor');
 | 
			
		||||
                        manager.clearTransactionsFor.and.callThrough();
 | 
			
		||||
                    });
 | 
			
		||||
                it("ignores subsequent calls for the same object", function () {
 | 
			
		||||
                    manager.addToTransaction(
 | 
			
		||||
                        testId,
 | 
			
		||||
                        jasmine.createSpy(),
 | 
			
		||||
                        jasmine.createSpy()
 | 
			
		||||
                    );
 | 
			
		||||
                    expect(mockTransactionService.addToTransaction.calls.count())
 | 
			
		||||
                        .toEqual(1);
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                    it("and clears pending calls if same object", function () {
 | 
			
		||||
                        manager.addToTransaction(
 | 
			
		||||
                            testId,
 | 
			
		||||
                            jasmine.createSpy(),
 | 
			
		||||
                            jasmine.createSpy()
 | 
			
		||||
                        );
 | 
			
		||||
                        expect(manager.clearTransactionsFor).toHaveBeenCalledWith(testId);
 | 
			
		||||
                    });
 | 
			
		||||
 | 
			
		||||
                    it("and does not clear pending calls if different object", function () {
 | 
			
		||||
                        manager.addToTransaction(
 | 
			
		||||
                            'other-id',
 | 
			
		||||
                            jasmine.createSpy(),
 | 
			
		||||
                            jasmine.createSpy()
 | 
			
		||||
                        );
 | 
			
		||||
                        expect(manager.clearTransactionsFor).not.toHaveBeenCalled();
 | 
			
		||||
                    });
 | 
			
		||||
 | 
			
		||||
                    afterEach(function () {
 | 
			
		||||
                        expect(mockTransactionService.addToTransaction.calls.count()).toEqual(2);
 | 
			
		||||
                    });
 | 
			
		||||
                it("accepts subsequent calls for other objects", function () {
 | 
			
		||||
                    manager.addToTransaction(
 | 
			
		||||
                        'other-id',
 | 
			
		||||
                        jasmine.createSpy(),
 | 
			
		||||
                        jasmine.createSpy()
 | 
			
		||||
                    );
 | 
			
		||||
                    expect(mockTransactionService.addToTransaction.calls.count())
 | 
			
		||||
                        .toEqual(2);
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                it("does not remove callbacks from the transaction", function () {
 | 
			
		||||
 
 | 
			
		||||
@@ -20,8 +20,8 @@
 | 
			
		||||
 at runtime from the About dialog for additional information.
 | 
			
		||||
-->
 | 
			
		||||
<!-- DO NOT ADD SPACES BETWEEN THE SPANS - IT ADDS WHITE SPACE!! -->
 | 
			
		||||
<div class="c-indicator {{ngModel.getCssClass()}}"
 | 
			
		||||
<div class="ls-indicator {{ngModel.getCssClass()}}"
 | 
			
		||||
	 title="{{ngModel.getDescription()}}"
 | 
			
		||||
	 ng-show="ngModel.getText().length > 0">
 | 
			
		||||
	<span class="label c-indicator__label">{{ngModel.getText()}}</span>
 | 
			
		||||
	<span class="label">{{ngModel.getText()}}</span>
 | 
			
		||||
</div>
 | 
			
		||||
 
 | 
			
		||||
@@ -54,7 +54,6 @@ define(
 | 
			
		||||
                    if (isDestroyed) {
 | 
			
		||||
                        return;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    var removeSelectable = openmct.selection.selectable(
 | 
			
		||||
                        element[0],
 | 
			
		||||
                        scope.$eval(attrs.mctSelectable),
 | 
			
		||||
 
 | 
			
		||||
@@ -1,8 +1,8 @@
 | 
			
		||||
<!-- DO NOT ADD SPACES BETWEEN THE SPANS - IT ADDS WHITE SPACE!! -->
 | 
			
		||||
<div ng-show="notifications.length > 0" class="c-indicator c-indicator--clickable s-status-{{highest.severity}} icon-bell"
 | 
			
		||||
<div ng-show="notifications.length > 0" class="ls-indicator s-status-{{highest.severity}} icon-bell"
 | 
			
		||||
      ng-controller="NotificationIndicatorController">
 | 
			
		||||
    <span class="label c-indicator__label">
 | 
			
		||||
        <button ng-click="showNotificationsList()">
 | 
			
		||||
           {{notifications.length}} Notification<span ng-show="notifications.length > 1">s</span></button>
 | 
			
		||||
    </span><span class="c-indicator__count">{{notifications.length}}</span>
 | 
			
		||||
    <span class="label">
 | 
			
		||||
        <a ng-click="showNotificationsList()">
 | 
			
		||||
           {{notifications.length}} Notification<span ng-show="notifications.length > 1">s</span></a>
 | 
			
		||||
    </span><span class="count">{{notifications.length}}</span>
 | 
			
		||||
</div>
 | 
			
		||||
 
 | 
			
		||||
@@ -43,10 +43,23 @@ define([], function () {
 | 
			
		||||
        var mutationTopic = topic('mutation');
 | 
			
		||||
        mutationTopic.listen(function (domainObject) {
 | 
			
		||||
            var persistence = domainObject.getCapability('persistence');
 | 
			
		||||
            var wasActive = transactionService.isActive();
 | 
			
		||||
            cacheService.put(domainObject.getId(), domainObject.getModel());
 | 
			
		||||
 | 
			
		||||
            if (hasChanged(domainObject)) {
 | 
			
		||||
                persistence.persist();
 | 
			
		||||
 | 
			
		||||
                if (!wasActive) {
 | 
			
		||||
                    transactionService.startTransaction();
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                transactionService.addToTransaction(
 | 
			
		||||
                    persistence.persist.bind(persistence),
 | 
			
		||||
                    persistence.refresh.bind(persistence)
 | 
			
		||||
                );
 | 
			
		||||
 | 
			
		||||
                if (!wasActive) {
 | 
			
		||||
                    transactionService.commit();
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -24,27 +24,22 @@ define(
 | 
			
		||||
    ["../../src/runs/TransactingMutationListener"],
 | 
			
		||||
    function (TransactingMutationListener) {
 | 
			
		||||
 | 
			
		||||
        describe("TransactingMutationListener", function () {
 | 
			
		||||
        xdescribe("TransactingMutationListener", function () {
 | 
			
		||||
            var mockTopic,
 | 
			
		||||
                mockMutationTopic,
 | 
			
		||||
                mockCacheService,
 | 
			
		||||
                mockTransactionService,
 | 
			
		||||
                mockDomainObject,
 | 
			
		||||
                mockModel,
 | 
			
		||||
                mockPersistence;
 | 
			
		||||
 | 
			
		||||
            beforeEach(function () {
 | 
			
		||||
                mockTopic = jasmine.createSpy('topic');
 | 
			
		||||
                mockMutationTopic =
 | 
			
		||||
                    jasmine.createSpyObj('mutation', ['listen']);
 | 
			
		||||
                mockCacheService =
 | 
			
		||||
                    jasmine.createSpyObj('cacheService', [
 | 
			
		||||
                        'put'
 | 
			
		||||
                    ]);
 | 
			
		||||
                mockTransactionService =
 | 
			
		||||
                    jasmine.createSpyObj('transactionService', [
 | 
			
		||||
                        'isActive',
 | 
			
		||||
                        'startTransaction',
 | 
			
		||||
                        'addToTransaction',
 | 
			
		||||
                        'commit'
 | 
			
		||||
                    ]);
 | 
			
		||||
                mockDomainObject = jasmine.createSpyObj(
 | 
			
		||||
@@ -57,24 +52,18 @@ define(
 | 
			
		||||
                );
 | 
			
		||||
 | 
			
		||||
                mockTopic.and.callFake(function (t) {
 | 
			
		||||
                    expect(t).toBe('mutation');
 | 
			
		||||
                    return mockMutationTopic;
 | 
			
		||||
                    return (t === 'mutation') && mockMutationTopic;
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                mockDomainObject.getId.and.returnValue('mockId');
 | 
			
		||||
                mockDomainObject.getCapability.and.callFake(function (c) {
 | 
			
		||||
                    expect(c).toBe('persistence');
 | 
			
		||||
                    return mockPersistence;
 | 
			
		||||
                    return (c === 'persistence') && mockPersistence;
 | 
			
		||||
                });
 | 
			
		||||
                mockModel = {};
 | 
			
		||||
                mockDomainObject.getModel.and.returnValue(mockModel);
 | 
			
		||||
 | 
			
		||||
                mockPersistence.persisted.and.returnValue(true);
 | 
			
		||||
 | 
			
		||||
                return new TransactingMutationListener(
 | 
			
		||||
                    mockTopic,
 | 
			
		||||
                    mockTransactionService,
 | 
			
		||||
                    mockCacheService
 | 
			
		||||
                    mockTransactionService
 | 
			
		||||
                );
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
@@ -83,27 +72,48 @@ define(
 | 
			
		||||
                    .toHaveBeenCalledWith(jasmine.any(Function));
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("calls persist if the model has changed", function () {
 | 
			
		||||
                mockModel.persisted = Date.now();
 | 
			
		||||
            [false, true].forEach(function (isActive) {
 | 
			
		||||
                var verb = isActive ? "is" : "isn't";
 | 
			
		||||
 | 
			
		||||
                //Mark the model dirty by setting the mutated date later than the last persisted date.
 | 
			
		||||
                mockModel.modified = mockModel.persisted + 1;
 | 
			
		||||
                function onlyWhenInactive(expectation) {
 | 
			
		||||
                    return isActive ? expectation.not : expectation;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                mockMutationTopic.listen.calls.mostRecent()
 | 
			
		||||
                    .args[0](mockDomainObject);
 | 
			
		||||
                describe("when a transaction " + verb + " active", function () {
 | 
			
		||||
                    var innerVerb = isActive ? "does" : "doesn't";
 | 
			
		||||
 | 
			
		||||
                expect(mockPersistence.persist).toHaveBeenCalled();
 | 
			
		||||
            });
 | 
			
		||||
                    beforeEach(function () {
 | 
			
		||||
                        mockTransactionService.isActive.and.returnValue(isActive);
 | 
			
		||||
                    });
 | 
			
		||||
 | 
			
		||||
            it("does not call persist if the model has not changed", function () {
 | 
			
		||||
                mockModel.persisted = Date.now();
 | 
			
		||||
                    describe("and mutation occurs", function () {
 | 
			
		||||
                        beforeEach(function () {
 | 
			
		||||
                            mockMutationTopic.listen.calls.mostRecent()
 | 
			
		||||
                                .args[0](mockDomainObject);
 | 
			
		||||
                        });
 | 
			
		||||
 | 
			
		||||
                mockModel.modified = mockModel.persisted;
 | 
			
		||||
 | 
			
		||||
                mockMutationTopic.listen.calls.mostRecent()
 | 
			
		||||
                    .args[0](mockDomainObject);
 | 
			
		||||
                        it(innerVerb + " start a new transaction", function () {
 | 
			
		||||
                            onlyWhenInactive(
 | 
			
		||||
                                expect(mockTransactionService.startTransaction)
 | 
			
		||||
                            ).toHaveBeenCalled();
 | 
			
		||||
                        });
 | 
			
		||||
 | 
			
		||||
                expect(mockPersistence.persist).not.toHaveBeenCalled();
 | 
			
		||||
                        it("adds to the active transaction", function () {
 | 
			
		||||
                            expect(mockTransactionService.addToTransaction)
 | 
			
		||||
                                .toHaveBeenCalledWith(
 | 
			
		||||
                                    jasmine.any(Function),
 | 
			
		||||
                                    jasmine.any(Function)
 | 
			
		||||
                                );
 | 
			
		||||
                        });
 | 
			
		||||
 | 
			
		||||
                        it(innerVerb + " immediately commit", function () {
 | 
			
		||||
                            onlyWhenInactive(
 | 
			
		||||
                                expect(mockTransactionService.commit)
 | 
			
		||||
                            ).toHaveBeenCalled();
 | 
			
		||||
                        });
 | 
			
		||||
                    });
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -24,6 +24,7 @@ define([
 | 
			
		||||
    "./src/actions/MoveAction",
 | 
			
		||||
    "./src/actions/CopyAction",
 | 
			
		||||
    "./src/actions/LinkAction",
 | 
			
		||||
    "./src/actions/GoToOriginalAction",
 | 
			
		||||
    "./src/actions/SetPrimaryLocationAction",
 | 
			
		||||
    "./src/services/LocatingCreationDecorator",
 | 
			
		||||
    "./src/services/LocatingObjectDecorator",
 | 
			
		||||
@@ -40,6 +41,7 @@ define([
 | 
			
		||||
    MoveAction,
 | 
			
		||||
    CopyAction,
 | 
			
		||||
    LinkAction,
 | 
			
		||||
    GoToOriginalAction,
 | 
			
		||||
    SetPrimaryLocationAction,
 | 
			
		||||
    LocatingCreationDecorator,
 | 
			
		||||
    LocatingObjectDecorator,
 | 
			
		||||
@@ -102,6 +104,14 @@ define([
 | 
			
		||||
                        "linkService"
 | 
			
		||||
                    ]
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "key": "follow",
 | 
			
		||||
                    "name": "Go To Original",
 | 
			
		||||
                    "description": "Go to the original, un-linked instance of this object.",
 | 
			
		||||
                    "cssClass": "",
 | 
			
		||||
                    "category": "contextual",
 | 
			
		||||
                    "implementation": GoToOriginalAction
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "key": "locate",
 | 
			
		||||
                    "name": "Set Primary Location",
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										60
									
								
								platform/entanglement/src/actions/GoToOriginalAction.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								platform/entanglement/src/actions/GoToOriginalAction.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,60 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT, Copyright (c) 2014-2018, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
define(
 | 
			
		||||
    function () {
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Implements the "Go To Original" action, which follows a link back
 | 
			
		||||
         * to an original instance of an object.
 | 
			
		||||
         *
 | 
			
		||||
         * @implements {Action}
 | 
			
		||||
         * @constructor
 | 
			
		||||
         * @private
 | 
			
		||||
         * @memberof platform/entanglement
 | 
			
		||||
         * @param {ActionContext} context the context in which the action
 | 
			
		||||
         *        will be performed
 | 
			
		||||
         */
 | 
			
		||||
        function GoToOriginalAction(context) {
 | 
			
		||||
            this.domainObject = context.domainObject;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        GoToOriginalAction.prototype.perform = function () {
 | 
			
		||||
            return this.domainObject.getCapability("location").getOriginal()
 | 
			
		||||
                .then(function (originalObject) {
 | 
			
		||||
                    var actionCapability =
 | 
			
		||||
                        originalObject.getCapability("action");
 | 
			
		||||
                    return actionCapability &&
 | 
			
		||||
                            actionCapability.perform("navigate");
 | 
			
		||||
                });
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        GoToOriginalAction.appliesTo = function (context) {
 | 
			
		||||
            var domainObject = context.domainObject;
 | 
			
		||||
            return domainObject && domainObject.hasCapability("location") &&
 | 
			
		||||
                domainObject.getCapability("location").isLink();
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        return GoToOriginalAction;
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										93
									
								
								platform/entanglement/test/actions/GoToOriginalActionSpec.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										93
									
								
								platform/entanglement/test/actions/GoToOriginalActionSpec.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,93 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT, Copyright (c) 2014-2018, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
define(
 | 
			
		||||
    [
 | 
			
		||||
        '../../src/actions/GoToOriginalAction',
 | 
			
		||||
        '../DomainObjectFactory',
 | 
			
		||||
        '../ControlledPromise'
 | 
			
		||||
    ],
 | 
			
		||||
    function (GoToOriginalAction, domainObjectFactory, ControlledPromise) {
 | 
			
		||||
 | 
			
		||||
        describe("The 'go to original' action", function () {
 | 
			
		||||
            var testContext,
 | 
			
		||||
                originalDomainObject,
 | 
			
		||||
                mockLocationCapability,
 | 
			
		||||
                mockOriginalActionCapability,
 | 
			
		||||
                originalPromise,
 | 
			
		||||
                action;
 | 
			
		||||
 | 
			
		||||
            beforeEach(function () {
 | 
			
		||||
                mockLocationCapability = jasmine.createSpyObj(
 | 
			
		||||
                    'location',
 | 
			
		||||
                    ['isLink', 'isOriginal', 'getOriginal']
 | 
			
		||||
                );
 | 
			
		||||
                mockOriginalActionCapability = jasmine.createSpyObj(
 | 
			
		||||
                    'action',
 | 
			
		||||
                    ['perform', 'getActions']
 | 
			
		||||
                );
 | 
			
		||||
                originalPromise = new ControlledPromise();
 | 
			
		||||
                mockLocationCapability.getOriginal.and.returnValue(originalPromise);
 | 
			
		||||
                mockLocationCapability.isLink.and.returnValue(true);
 | 
			
		||||
                mockLocationCapability.isOriginal.and.callFake(function () {
 | 
			
		||||
                    return !mockLocationCapability.isLink();
 | 
			
		||||
                });
 | 
			
		||||
                testContext = {
 | 
			
		||||
                    domainObject: domainObjectFactory({
 | 
			
		||||
                        capabilities: {
 | 
			
		||||
                            location: mockLocationCapability
 | 
			
		||||
                        }
 | 
			
		||||
                    })
 | 
			
		||||
                };
 | 
			
		||||
                originalDomainObject = domainObjectFactory({
 | 
			
		||||
                    capabilities: {
 | 
			
		||||
                        action: mockOriginalActionCapability
 | 
			
		||||
                    }
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                action = new GoToOriginalAction(testContext);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("is applicable to links", function () {
 | 
			
		||||
                expect(GoToOriginalAction.appliesTo(testContext))
 | 
			
		||||
                    .toBeTruthy();
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("is not applicable to originals", function () {
 | 
			
		||||
                mockLocationCapability.isLink.and.returnValue(false);
 | 
			
		||||
                expect(GoToOriginalAction.appliesTo(testContext))
 | 
			
		||||
                    .toBeFalsy();
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("navigates to original objects when performed", function () {
 | 
			
		||||
                expect(mockOriginalActionCapability.perform)
 | 
			
		||||
                    .not.toHaveBeenCalled();
 | 
			
		||||
                action.perform();
 | 
			
		||||
                originalPromise.resolve(originalDomainObject);
 | 
			
		||||
                expect(mockOriginalActionCapability.perform)
 | 
			
		||||
                    .toHaveBeenCalledWith('navigate');
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
@@ -49,7 +49,7 @@ define(
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        ClockIndicator.prototype.getCssClass = function () {
 | 
			
		||||
            return "t-indicator-clock icon-clock no-minify c-indicator--not-clickable";
 | 
			
		||||
            return "t-indicator-clock icon-clock no-collapse float-right";
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        ClockIndicator.prototype.getText = function () {
 | 
			
		||||
 
 | 
			
		||||
@@ -64,30 +64,12 @@ define(['zepto'], function ($) {
 | 
			
		||||
        var tree = this.generateNewIdentifiers(objTree);
 | 
			
		||||
        var rootId = tree.rootId;
 | 
			
		||||
        var rootObj = this.instantiate(tree.openmct[rootId], rootId);
 | 
			
		||||
        var newStyleParent = parent.useCapability('adapter');
 | 
			
		||||
        var newStyleRootObj = rootObj.useCapability('adapter');
 | 
			
		||||
 | 
			
		||||
        if (this.openmct.composition.checkPolicy(newStyleParent, newStyleRootObj)) {
 | 
			
		||||
            // Instantiate all objects in tree with their newly generated ids,
 | 
			
		||||
            // adding each to its rightful parent's composition
 | 
			
		||||
            rootObj.getCapability("location").setPrimaryLocation(parent.getId());
 | 
			
		||||
            this.deepInstantiate(rootObj, tree.openmct, []);
 | 
			
		||||
            parent.getCapability("composition").add(rootObj);
 | 
			
		||||
        } else {
 | 
			
		||||
            var dialog = this.openmct.overlays.dialog({
 | 
			
		||||
                iconClass: 'alert',
 | 
			
		||||
                message: "We're sorry, but you cannot import that object type into this object.",
 | 
			
		||||
                buttons: [
 | 
			
		||||
                    {
 | 
			
		||||
                        label: "Ok",
 | 
			
		||||
                        emphasis: true,
 | 
			
		||||
                        callback: function () {
 | 
			
		||||
                            dialog.dismiss();
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                ]
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
        // Instantiate all objects in tree with their newly genereated ids,
 | 
			
		||||
        // adding each to its rightful parent's composition
 | 
			
		||||
        rootObj.getCapability("location").setPrimaryLocation(parent.getId());
 | 
			
		||||
        this.deepInstantiate(rootObj, tree.openmct, []);
 | 
			
		||||
        parent.getCapability("composition").add(rootObj);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    ImportAsJSONAction.prototype.deepInstantiate = function (parent, tree, seen) {
 | 
			
		||||
@@ -98,17 +80,15 @@ define(['zepto'], function ($) {
 | 
			
		||||
            var newObj;
 | 
			
		||||
 | 
			
		||||
            seen.push(parent.getId());
 | 
			
		||||
 | 
			
		||||
            parentModel.composition.forEach(function (childId) {
 | 
			
		||||
                let keystring = this.openmct.objects.makeKeyString(childId);
 | 
			
		||||
 | 
			
		||||
                if (!tree[keystring] || seen.includes(keystring)) {
 | 
			
		||||
            parentModel.composition.forEach(function (childId, index) {
 | 
			
		||||
                if (!tree[childId] || seen.includes(childId)) {
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                newObj = this.instantiate(tree[keystring], keystring);
 | 
			
		||||
                newObj = this.instantiate(tree[childId], childId);
 | 
			
		||||
                parent.getCapability("composition").add(newObj);
 | 
			
		||||
                newObj.getCapability("location")
 | 
			
		||||
                    .setPrimaryLocation(tree[keystring].location);
 | 
			
		||||
                    .setPrimaryLocation(tree[childId].location);
 | 
			
		||||
                this.deepInstantiate(newObj, tree, seen);
 | 
			
		||||
            }, this);
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -100,7 +100,7 @@ define(
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        CouchIndicator.prototype.getCssClass = function () {
 | 
			
		||||
            return "c-indicator--clickable icon-database " + this.state.statusClass;
 | 
			
		||||
            return "icon-database " + this.state.statusClass;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        CouchIndicator.prototype.getGlyphClass = function () {
 | 
			
		||||
 
 | 
			
		||||
@@ -84,7 +84,7 @@ define(
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        ElasticIndicator.prototype.getCssClass = function () {
 | 
			
		||||
            return "c-indicator--clickable icon-database";
 | 
			
		||||
            return "icon-database";
 | 
			
		||||
        };
 | 
			
		||||
        ElasticIndicator.prototype.getGlyphClass = function () {
 | 
			
		||||
            return this.state.glyphClass;
 | 
			
		||||
 
 | 
			
		||||
@@ -41,7 +41,7 @@ define(
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        LocalStorageIndicator.prototype.getCssClass = function () {
 | 
			
		||||
            return "c-indicator--clickable icon-database s-status-caution";
 | 
			
		||||
            return "icon-database s-status-caution";
 | 
			
		||||
        };
 | 
			
		||||
        LocalStorageIndicator.prototype.getGlyphClass = function () {
 | 
			
		||||
            return 'caution';
 | 
			
		||||
 
 | 
			
		||||
@@ -37,17 +37,75 @@ define(
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Discard failures
 | 
			
		||||
         * Handle persistence failures by providing the user with a
 | 
			
		||||
         * dialog summarizing these failures, and giving the option
 | 
			
		||||
         * to overwrite/cancel as appropriate.
 | 
			
		||||
         * @param {Array} failures persistence failures, as prepared
 | 
			
		||||
         *        by PersistenceQueueHandler
 | 
			
		||||
         * @memberof platform/persistence/queue.PersistenceFailureHandler#
 | 
			
		||||
         */
 | 
			
		||||
        PersistenceFailureHandler.prototype.handle = function handleFailures(failures) {
 | 
			
		||||
 | 
			
		||||
            // Prepare dialog for display
 | 
			
		||||
            var dialogModel = new PersistenceFailureDialog(failures),
 | 
			
		||||
                revisionErrors = dialogModel.model.revised,
 | 
			
		||||
                $q = this.$q;
 | 
			
		||||
 | 
			
		||||
            // Refresh revision information for the domain object associated
 | 
			
		||||
            // with this persistence failure
 | 
			
		||||
            function refresh(failure) {
 | 
			
		||||
                // Refresh the domain object to the latest from persistence
 | 
			
		||||
                return failure.persistence.refresh();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Issue a new persist call for the domain object associated with
 | 
			
		||||
            // this failure.
 | 
			
		||||
            function persist(failure) {
 | 
			
		||||
                // Note that we reissue the persist request here, but don't
 | 
			
		||||
                // return it, to avoid a circular wait. We trust that the
 | 
			
		||||
                // PersistenceQueue will behave correctly on the next round
 | 
			
		||||
                // of flushing.
 | 
			
		||||
                failure.requeue();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Retry persistence (overwrite) for this set of failed attempts
 | 
			
		||||
            function retry(failuresToRetry) {
 | 
			
		||||
                var models = {};
 | 
			
		||||
 | 
			
		||||
                // Cache a copy of the model
 | 
			
		||||
                function cacheModel(failure) {
 | 
			
		||||
                    // Clone...
 | 
			
		||||
                    models[failure.id] = JSON.parse(JSON.stringify(
 | 
			
		||||
                        failure.domainObject.getModel()
 | 
			
		||||
                    ));
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // Mutate a domain object to restore its model
 | 
			
		||||
                function remutate(failure) {
 | 
			
		||||
                    var model = models[failure.id];
 | 
			
		||||
                    return failure.domainObject.useCapability(
 | 
			
		||||
                        "mutation",
 | 
			
		||||
                        function () {
 | 
			
		||||
                            return model;
 | 
			
		||||
                        },
 | 
			
		||||
                        model.modified
 | 
			
		||||
                    );
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // Cache the object models we might want to save
 | 
			
		||||
                failuresToRetry.forEach(cacheModel);
 | 
			
		||||
 | 
			
		||||
                // Strategy here:
 | 
			
		||||
                // * Cache all of the models we might want to save (above)
 | 
			
		||||
                // * Refresh all domain objects (so they are latest versions)
 | 
			
		||||
                // * Re-insert the cached domain object models
 | 
			
		||||
                // * Invoke persistence again
 | 
			
		||||
                return $q.all(failuresToRetry.map(refresh)).then(function () {
 | 
			
		||||
                    return $q.all(failuresToRetry.map(remutate));
 | 
			
		||||
                }).then(function () {
 | 
			
		||||
                    return $q.all(failuresToRetry.map(persist));
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Discard changes for a failed refresh
 | 
			
		||||
            function discard(failure) {
 | 
			
		||||
                var persistence =
 | 
			
		||||
@@ -60,7 +118,19 @@ define(
 | 
			
		||||
                return $q.all(failuresToDiscard.map(discard));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return discardAll(revisionErrors);
 | 
			
		||||
            // Handle user input (did they choose to overwrite?)
 | 
			
		||||
            function handleChoice(key) {
 | 
			
		||||
                // If so, try again
 | 
			
		||||
                if (key === PersistenceFailureConstants.OVERWRITE_KEY) {
 | 
			
		||||
                    return retry(revisionErrors);
 | 
			
		||||
                } else {
 | 
			
		||||
                    return discardAll(revisionErrors);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Prompt for user input, the overwrite if they said so.
 | 
			
		||||
            return this.dialogService.getUserChoice(dialogModel)
 | 
			
		||||
                .then(handleChoice, handleChoice);
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        return PersistenceFailureHandler;
 | 
			
		||||
 
 | 
			
		||||
@@ -74,14 +74,43 @@ define(
 | 
			
		||||
                handler = new PersistenceFailureHandler(mockQ, mockDialogService);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("discards on handle", function () {
 | 
			
		||||
            it("shows a dialog to handle failures", function () {
 | 
			
		||||
                handler.handle(mockFailures);
 | 
			
		||||
                expect(mockDialogService.getUserChoice).toHaveBeenCalled();
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("overwrites on request", function () {
 | 
			
		||||
                mockQ.all.and.returnValue(asPromise([]));
 | 
			
		||||
                handler.handle(mockFailures);
 | 
			
		||||
                // User chooses overwrite
 | 
			
		||||
                mockPromise.then.calls.mostRecent().args[0](Constants.OVERWRITE_KEY);
 | 
			
		||||
                // Should refresh, remutate, and requeue all objects
 | 
			
		||||
                mockFailures.forEach(function (mockFailure, i) {
 | 
			
		||||
                    expect(mockFailure.persistence.refresh).toHaveBeenCalled();
 | 
			
		||||
                    expect(mockFailure.requeue).toHaveBeenCalled();
 | 
			
		||||
                    expect(mockFailure.domainObject.useCapability).toHaveBeenCalledWith(
 | 
			
		||||
                        'mutation',
 | 
			
		||||
                        jasmine.any(Function),
 | 
			
		||||
                        i // timestamp
 | 
			
		||||
                    );
 | 
			
		||||
                    expect(mockFailure.domainObject.useCapability.calls.mostRecent().args[1]())
 | 
			
		||||
                        .toEqual({ id: mockFailure.id, modified: i });
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("discards on request", function () {
 | 
			
		||||
                mockQ.all.and.returnValue(asPromise([]));
 | 
			
		||||
                handler.handle(mockFailures);
 | 
			
		||||
                // User chooses overwrite
 | 
			
		||||
                mockPromise.then.calls.mostRecent().args[0](false);
 | 
			
		||||
                // Should refresh, but not remutate, and requeue all objects
 | 
			
		||||
                mockFailures.forEach(function (mockFailure) {
 | 
			
		||||
                    expect(mockFailure.persistence.refresh).toHaveBeenCalled();
 | 
			
		||||
                    expect(mockFailure.requeue).not.toHaveBeenCalled();
 | 
			
		||||
                    expect(mockFailure.domainObject.useCapability).not.toHaveBeenCalled();
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										19
									
								
								src/MCT.js
									
									
									
									
									
								
							
							
						
						
									
										19
									
								
								src/MCT.js
									
									
									
									
									
								
							@@ -246,25 +246,18 @@ define([
 | 
			
		||||
        this.branding = BrandingAPI.default;
 | 
			
		||||
 | 
			
		||||
        this.legacyRegistry = defaultRegistry;
 | 
			
		||||
 | 
			
		||||
        // Plugin's that are installed by default
 | 
			
		||||
 | 
			
		||||
        this.install(this.plugins.Plot());
 | 
			
		||||
        this.install(this.plugins.TelemetryTable());
 | 
			
		||||
        this.install(this.plugins.DisplayLayout());
 | 
			
		||||
        this.install(PreviewPlugin.default());
 | 
			
		||||
        this.install(LegacyIndicatorsPlugin());
 | 
			
		||||
        this.install(LicensesPlugin.default());
 | 
			
		||||
        this.install(RemoveActionPlugin.default());
 | 
			
		||||
        this.install(this.plugins.ImportExport());
 | 
			
		||||
        this.install(this.plugins.FolderView());
 | 
			
		||||
        this.install(this.plugins.Tabs());
 | 
			
		||||
        this.install(this.plugins.FlexibleLayout());
 | 
			
		||||
        this.install(this.plugins.LADTable());
 | 
			
		||||
        this.install(this.plugins.GoToOriginalAction());
 | 
			
		||||
 | 
			
		||||
        if (typeof BUILD_CONSTANTS !== 'undefined') {
 | 
			
		||||
            this.install(buildInfoPlugin(BUILD_CONSTANTS));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    MCT.prototype = Object.create(EventEmitter.prototype);
 | 
			
		||||
@@ -335,12 +328,6 @@ define([
 | 
			
		||||
     *        MCT; if undefined, MCT will be run in the body of the document
 | 
			
		||||
     */
 | 
			
		||||
    MCT.prototype.start = function (domElement) {
 | 
			
		||||
        if (!this.plugins.DisplayLayout._installed) {
 | 
			
		||||
            this.install(this.plugins.DisplayLayout({
 | 
			
		||||
                showAsView: ['summary-widget']
 | 
			
		||||
            }));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (!domElement) {
 | 
			
		||||
            domElement = document.body;
 | 
			
		||||
        }
 | 
			
		||||
@@ -365,7 +352,7 @@ define([
 | 
			
		||||
        legacyRegistry.enable('adapter');
 | 
			
		||||
 | 
			
		||||
        this.router.route(/^\/$/, () => {
 | 
			
		||||
            this.router.setPath('/browse/');
 | 
			
		||||
            this.router.setPath('/browse/mine');
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
 
 | 
			
		||||
@@ -26,7 +26,6 @@ const OUTSIDE_EDIT_PATH_BLACKLIST = ["copy", "follow", "properties", "move", "li
 | 
			
		||||
export default class LegacyContextMenuAction {
 | 
			
		||||
    constructor(openmct, LegacyAction) {
 | 
			
		||||
        this.openmct = openmct;
 | 
			
		||||
        this.key = LegacyAction.definition.key;
 | 
			
		||||
        this.name = LegacyAction.definition.name;
 | 
			
		||||
        this.description = LegacyAction.definition.description;
 | 
			
		||||
        this.cssClass = LegacyAction.definition.cssClass;
 | 
			
		||||
@@ -34,25 +33,20 @@ export default class LegacyContextMenuAction {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    invoke(objectPath) {
 | 
			
		||||
        this.openmct.objects.getRoot().then((root) => {
 | 
			
		||||
            let pathWithRoot = objectPath.slice();
 | 
			
		||||
            pathWithRoot.push(root);
 | 
			
		||||
        let context = {
 | 
			
		||||
            category: 'contextual',
 | 
			
		||||
            domainObject: this.openmct.legacyObject(objectPath)
 | 
			
		||||
        }
 | 
			
		||||
        let legacyAction = new this.LegacyAction(context);
 | 
			
		||||
 | 
			
		||||
            let context = {
 | 
			
		||||
                category: 'contextual',
 | 
			
		||||
                domainObject: this.openmct.legacyObject(pathWithRoot)
 | 
			
		||||
            }
 | 
			
		||||
            let legacyAction = new this.LegacyAction(context);
 | 
			
		||||
 | 
			
		||||
            if (!legacyAction.getMetadata) {
 | 
			
		||||
                let metadata = Object.create(this.LegacyAction.definition);
 | 
			
		||||
                metadata.context = context;
 | 
			
		||||
                legacyAction.getMetadata = function () {
 | 
			
		||||
                    return metadata;
 | 
			
		||||
                }.bind(legacyAction);
 | 
			
		||||
            }
 | 
			
		||||
            legacyAction.perform();
 | 
			
		||||
        });
 | 
			
		||||
        if (!legacyAction.getMetadata) {
 | 
			
		||||
            let metadata = Object.create(this.LegacyAction.definition);
 | 
			
		||||
            metadata.context = context;
 | 
			
		||||
            legacyAction.getMetadata = function () {
 | 
			
		||||
                return metadata;
 | 
			
		||||
            }.bind(legacyAction);
 | 
			
		||||
        }
 | 
			
		||||
        legacyAction.perform();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    appliesTo(objectPath) {
 | 
			
		||||
 
 | 
			
		||||
@@ -36,7 +36,7 @@ define([
 | 
			
		||||
    './runs/RegisterLegacyTypes',
 | 
			
		||||
    './services/LegacyObjectAPIInterceptor',
 | 
			
		||||
    './views/installLegacyViews',
 | 
			
		||||
    './policies/LegacyCompositionPolicyAdapter',
 | 
			
		||||
    './policies/legacyCompositionPolicyAdapter',
 | 
			
		||||
    './actions/LegacyActionAdapter'
 | 
			
		||||
], function (
 | 
			
		||||
    legacyRegistry,
 | 
			
		||||
 
 | 
			
		||||
@@ -137,7 +137,8 @@ define([
 | 
			
		||||
        function callbackWrapper(series) {
 | 
			
		||||
            callback(createDatum(domainObject, metadata, series, series.getPointCount() - 1));
 | 
			
		||||
        }
 | 
			
		||||
        return capability.subscribe(callbackWrapper, request) || function () {};
 | 
			
		||||
 | 
			
		||||
        return capability.subscribe(callbackWrapper, request);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    LegacyTelemetryProvider.prototype.supportsLimits = function (domainObject) {
 | 
			
		||||
 
 | 
			
		||||
@@ -57,10 +57,8 @@ define([
 | 
			
		||||
        }.bind(this);
 | 
			
		||||
 | 
			
		||||
        handleLegacyMutation = function (legacyObject) {
 | 
			
		||||
            var newStyleObject = utils.toNewFormat(legacyObject.getModel(), legacyObject.getId()),
 | 
			
		||||
                keystring = utils.makeKeyString(newStyleObject.identifier);
 | 
			
		||||
 | 
			
		||||
            this.eventEmitter.emit(keystring + ":*", newStyleObject);
 | 
			
		||||
            var newStyleObject = utils.toNewFormat(legacyObject.getModel(), legacyObject.getId());
 | 
			
		||||
            this.eventEmitter.emit(newStyleObject.identifier.key + ":*", newStyleObject);
 | 
			
		||||
            this.eventEmitter.emit('mutation', newStyleObject);
 | 
			
		||||
        }.bind(this);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -45,30 +45,15 @@ define([
 | 
			
		||||
            view: function (domainObject) {
 | 
			
		||||
                let $rootScope = openmct.$injector.get('$rootScope');
 | 
			
		||||
                let templateLinker = openmct.$injector.get('templateLinker');
 | 
			
		||||
                let scope = $rootScope.$new(true);
 | 
			
		||||
                let scope = $rootScope.$new();
 | 
			
		||||
                let legacyObject = convertToLegacyObject(domainObject);
 | 
			
		||||
                let isDestroyed = false;
 | 
			
		||||
                let unlistenToStatus;
 | 
			
		||||
                let element;
 | 
			
		||||
                scope.domainObject = legacyObject;
 | 
			
		||||
                scope.model = legacyObject.getModel();
 | 
			
		||||
                let child;
 | 
			
		||||
                let parent;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
                return {
 | 
			
		||||
                    show: function (container) {
 | 
			
		||||
                        parent = container;
 | 
			
		||||
                        child = document.createElement('div');
 | 
			
		||||
                        parent.appendChild(child);
 | 
			
		||||
                        let statusCapability = legacyObject.getCapability('status');
 | 
			
		||||
                        unlistenToStatus = statusCapability.listen((newStatus) => {
 | 
			
		||||
                            child.classList.remove('s-status-timeconductor-unsynced');
 | 
			
		||||
 | 
			
		||||
                            if (newStatus.includes('timeconductor-unsynced')) {
 | 
			
		||||
                                child.classList.add('s-status-timeconductor-unsynced');
 | 
			
		||||
                            }
 | 
			
		||||
                        });
 | 
			
		||||
 | 
			
		||||
                        // TODO: implement "gestures" support ?
 | 
			
		||||
                        let uses = legacyView.uses || [];
 | 
			
		||||
                        let promises = [];
 | 
			
		||||
@@ -89,13 +74,12 @@ define([
 | 
			
		||||
                            uses.forEach(function (key, i) {
 | 
			
		||||
                                scope[key] = results[i];
 | 
			
		||||
                            });
 | 
			
		||||
                            element = openmct.$angular.element(child);
 | 
			
		||||
                            templateLinker.link(
 | 
			
		||||
                                scope,
 | 
			
		||||
                                element,
 | 
			
		||||
                                openmct.$angular.element(container),
 | 
			
		||||
                                legacyView
 | 
			
		||||
                            );
 | 
			
		||||
                            child.classList.add('u-contents');
 | 
			
		||||
                            container.classList.add('u-contents');
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        if (promises.length) {
 | 
			
		||||
@@ -108,16 +92,8 @@ define([
 | 
			
		||||
                            link();
 | 
			
		||||
                        }
 | 
			
		||||
                    },
 | 
			
		||||
                    onClearData() {
 | 
			
		||||
                        scope.$broadcast('clearData');
 | 
			
		||||
                    },
 | 
			
		||||
                    destroy: function () {
 | 
			
		||||
                        element.off();
 | 
			
		||||
                        element.remove();
 | 
			
		||||
                        scope.$destroy();
 | 
			
		||||
                        element = null;
 | 
			
		||||
                        scope = null;
 | 
			
		||||
                        unlistenToStatus();
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
 
 | 
			
		||||
@@ -25,34 +25,25 @@ define([
 | 
			
		||||
            cssClass: representation.cssClass,
 | 
			
		||||
            description: representation.description,
 | 
			
		||||
            canView: function (selection) {
 | 
			
		||||
                if (selection.length !== 1 || selection[0].length === 0) {
 | 
			
		||||
                if (!selection[0] || !selection[0].context.item) {
 | 
			
		||||
                    return false;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                let selectionContext = selection[0][0].context;
 | 
			
		||||
 | 
			
		||||
                if (!selectionContext.item) {
 | 
			
		||||
                    return false;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                return selectionContext.item.type === typeDefinition.key;
 | 
			
		||||
                let domainObject = selection[0].context.item;
 | 
			
		||||
                return domainObject.type === typeDefinition.key;
 | 
			
		||||
            },
 | 
			
		||||
            view: function (selection) {
 | 
			
		||||
                let domainObject = selection[0][0].context.item;
 | 
			
		||||
                let domainObject = selection[0].context.item;
 | 
			
		||||
                let $rootScope = openmct.$injector.get('$rootScope');
 | 
			
		||||
                let templateLinker = openmct.$injector.get('templateLinker');
 | 
			
		||||
                let scope = $rootScope.$new(true);
 | 
			
		||||
                let scope = $rootScope.$new();
 | 
			
		||||
                let legacyObject = convertToLegacyObject(domainObject);
 | 
			
		||||
                let isDestroyed = false;
 | 
			
		||||
                let element;
 | 
			
		||||
                scope.domainObject = legacyObject;
 | 
			
		||||
                scope.model = legacyObject.getModel();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
                return {
 | 
			
		||||
                    show: function (container) {
 | 
			
		||||
                        let child = document.createElement('div');
 | 
			
		||||
                        container.appendChild(child);
 | 
			
		||||
                        // TODO: implement "gestures" support ?
 | 
			
		||||
                        let uses = representation.uses || [];
 | 
			
		||||
                        let promises = [];
 | 
			
		||||
@@ -73,10 +64,9 @@ define([
 | 
			
		||||
                            uses.forEach(function (key, i) {
 | 
			
		||||
                                scope[key] = results[i];
 | 
			
		||||
                            });
 | 
			
		||||
                            element = openmct.$angular.element(child)
 | 
			
		||||
                            templateLinker.link(
 | 
			
		||||
                                scope,
 | 
			
		||||
                                element,
 | 
			
		||||
                                openmct.$angular.element(container),
 | 
			
		||||
                                representation
 | 
			
		||||
                            );
 | 
			
		||||
                            container.style.height = '100%';
 | 
			
		||||
@@ -93,11 +83,7 @@ define([
 | 
			
		||||
                        }
 | 
			
		||||
                    },
 | 
			
		||||
                    destroy: function () {
 | 
			
		||||
                        element.off();
 | 
			
		||||
                        element.remove();
 | 
			
		||||
                        scope.$destroy();
 | 
			
		||||
                        element = null;
 | 
			
		||||
                        scope = null;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 
 | 
			
		||||
@@ -28,6 +28,11 @@ export default class Editor extends EventEmitter {
 | 
			
		||||
        super();
 | 
			
		||||
        this.editing = false;
 | 
			
		||||
        this.openmct = openmct;
 | 
			
		||||
        document.addEventListener('drop', (event) => {
 | 
			
		||||
            if (!this.isEditing()) {
 | 
			
		||||
                this.edit();
 | 
			
		||||
            }
 | 
			
		||||
        }, {capture: true});
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -74,11 +79,9 @@ export default class Editor extends EventEmitter {
 | 
			
		||||
     * @private
 | 
			
		||||
     */
 | 
			
		||||
    cancel() {
 | 
			
		||||
        let cancelPromise = this.getTransactionService().cancel();
 | 
			
		||||
        this.getTransactionService().cancel();
 | 
			
		||||
        this.editing = false;
 | 
			
		||||
        this.emit('isEditing', false);
 | 
			
		||||
 | 
			
		||||
        return cancelPromise;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
 
 | 
			
		||||
@@ -22,20 +22,8 @@ define([
 | 
			
		||||
            publicAPI = {};
 | 
			
		||||
            publicAPI.objects = jasmine.createSpyObj('ObjectAPI', [
 | 
			
		||||
                'get',
 | 
			
		||||
                'mutate',
 | 
			
		||||
                'observe',
 | 
			
		||||
                'areIdsEqual'
 | 
			
		||||
                'mutate'
 | 
			
		||||
            ]);
 | 
			
		||||
 | 
			
		||||
            publicAPI.objects.areIdsEqual.and.callFake(function (id1, id2) {
 | 
			
		||||
                return id1.namespace === id2.namespace && id1.key === id2.key;
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            publicAPI.composition = jasmine.createSpyObj('CompositionAPI', [
 | 
			
		||||
                'checkPolicy'
 | 
			
		||||
            ]);
 | 
			
		||||
            publicAPI.composition.checkPolicy.and.returnValue(true);
 | 
			
		||||
 | 
			
		||||
            publicAPI.objects.eventEmitter = jasmine.createSpyObj('eventemitter', [
 | 
			
		||||
                'on'
 | 
			
		||||
            ]);
 | 
			
		||||
@@ -103,7 +91,7 @@ define([
 | 
			
		||||
                beforeEach(function () {
 | 
			
		||||
                    listener = jasmine.createSpy('reorderListener');
 | 
			
		||||
                    composition.on('reorder', listener);
 | 
			
		||||
 | 
			
		||||
                    
 | 
			
		||||
                    return composition.load();
 | 
			
		||||
                });
 | 
			
		||||
                it('', function () {
 | 
			
		||||
@@ -131,16 +119,49 @@ define([
 | 
			
		||||
                    expect(newComposition[2].key).toEqual('a');
 | 
			
		||||
                })
 | 
			
		||||
            });
 | 
			
		||||
            it('supports adding an object to composition', function () {
 | 
			
		||||
                let addListener = jasmine.createSpy('addListener');
 | 
			
		||||
                let mockChildObject = {
 | 
			
		||||
                    identifier: {key: 'mock-key', namespace: ''}
 | 
			
		||||
                };
 | 
			
		||||
                composition.on('add', addListener);
 | 
			
		||||
                composition.add(mockChildObject);
 | 
			
		||||
 | 
			
		||||
                expect(domainObject.composition.length).toBe(4);
 | 
			
		||||
                expect(domainObject.composition[3]).toEqual(mockChildObject.identifier);
 | 
			
		||||
            // TODO: Implement add/removal in new default provider.
 | 
			
		||||
            xit('synchronizes changes between instances', function () {
 | 
			
		||||
                var otherComposition = compositionAPI.get(domainObject);
 | 
			
		||||
                var addListener = jasmine.createSpy('addListener');
 | 
			
		||||
                var removeListener = jasmine.createSpy('removeListener');
 | 
			
		||||
                var otherAddListener = jasmine.createSpy('otherAddListener');
 | 
			
		||||
                var otherRemoveListener = jasmine.createSpy('otherRemoveListener');
 | 
			
		||||
                composition.on('add', addListener);
 | 
			
		||||
                composition.on('remove', removeListener);
 | 
			
		||||
                otherComposition.on('add', otherAddListener);
 | 
			
		||||
                otherComposition.on('remove', otherRemoveListener);
 | 
			
		||||
 | 
			
		||||
                return Promise.all([composition.load(), otherComposition.load()])
 | 
			
		||||
                    .then(function () {
 | 
			
		||||
                        expect(addListener).toHaveBeenCalled();
 | 
			
		||||
                        expect(otherAddListener).toHaveBeenCalled();
 | 
			
		||||
                        expect(removeListener).not.toHaveBeenCalled();
 | 
			
		||||
                        expect(otherRemoveListener).not.toHaveBeenCalled();
 | 
			
		||||
 | 
			
		||||
                        var object = addListener.calls.mostRecent().args[0];
 | 
			
		||||
                        composition.remove(object);
 | 
			
		||||
                        expect(removeListener).toHaveBeenCalled();
 | 
			
		||||
                        expect(otherRemoveListener).toHaveBeenCalled();
 | 
			
		||||
 | 
			
		||||
                        addListener.reset();
 | 
			
		||||
                        otherAddListener.reset();
 | 
			
		||||
                        composition.add(object);
 | 
			
		||||
                        expect(addListener).toHaveBeenCalled();
 | 
			
		||||
                        expect(otherAddListener).toHaveBeenCalled();
 | 
			
		||||
 | 
			
		||||
                        removeListener.reset();
 | 
			
		||||
                        otherRemoveListener.reset();
 | 
			
		||||
                        otherComposition.remove(object);
 | 
			
		||||
                        expect(removeListener).toHaveBeenCalled();
 | 
			
		||||
                        expect(otherRemoveListener).toHaveBeenCalled();
 | 
			
		||||
 | 
			
		||||
                        addListener.reset();
 | 
			
		||||
                        otherAddListener.reset();
 | 
			
		||||
                        otherComposition.add(object);
 | 
			
		||||
                        expect(addListener).toHaveBeenCalled();
 | 
			
		||||
                        expect(otherAddListener).toHaveBeenCalled();
 | 
			
		||||
                    });
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
@@ -163,9 +184,7 @@ define([
 | 
			
		||||
                                key: 'thing'
 | 
			
		||||
                            }
 | 
			
		||||
                        ]);
 | 
			
		||||
                    },
 | 
			
		||||
                    add: jasmine.createSpy('add'),
 | 
			
		||||
                    remove: jasmine.createSpy('remove')
 | 
			
		||||
                    }
 | 
			
		||||
                };
 | 
			
		||||
                domainObject = {
 | 
			
		||||
                    identifier: {
 | 
			
		||||
@@ -195,25 +214,6 @@ define([
 | 
			
		||||
                    });
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
            describe('Calling add or remove', function () {
 | 
			
		||||
                let mockChildObject;
 | 
			
		||||
 | 
			
		||||
                beforeEach(function () {
 | 
			
		||||
                    mockChildObject = {
 | 
			
		||||
                        identifier: {key: 'mock-key', namespace: ''}
 | 
			
		||||
                    };
 | 
			
		||||
                    composition.add(mockChildObject);
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                it('calls add on the provider', function () {
 | 
			
		||||
                    expect(customProvider.add).toHaveBeenCalledWith(domainObject, mockChildObject.identifier);
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                it('calls remove on the provider', function () {
 | 
			
		||||
                    composition.remove(mockChildObject);
 | 
			
		||||
                    expect(customProvider.remove).toHaveBeenCalledWith(domainObject, mockChildObject.identifier);
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        describe('dynamic custom composition', function () {
 | 
			
		||||
 
 | 
			
		||||
@@ -25,6 +25,7 @@ define([
 | 
			
		||||
], function (
 | 
			
		||||
    _
 | 
			
		||||
) {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * A CompositionCollection represents the list of domain objects contained
 | 
			
		||||
     * by another domain object. It provides methods for loading this
 | 
			
		||||
@@ -62,6 +63,7 @@ define([
 | 
			
		||||
        this.onProviderRemove = this.onProviderRemove.bind(this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Listen for changes to this composition.  Supports 'add', 'remove', and
 | 
			
		||||
     * 'load' events.
 | 
			
		||||
@@ -74,9 +76,7 @@ define([
 | 
			
		||||
        if (!this.listeners[event]) {
 | 
			
		||||
            throw new Error('Event not supported by composition: ' + event);
 | 
			
		||||
        }
 | 
			
		||||
        if (!this.mutationListener) {
 | 
			
		||||
            this._synchronize();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (this.provider.on && this.provider.off) {
 | 
			
		||||
            if (event === 'add') {
 | 
			
		||||
                this.provider.on(
 | 
			
		||||
@@ -132,8 +132,6 @@ define([
 | 
			
		||||
 | 
			
		||||
        this.listeners[event].splice(index, 1);
 | 
			
		||||
        if (this.listeners[event].length === 0) {
 | 
			
		||||
            this._destroy();
 | 
			
		||||
 | 
			
		||||
            // Remove provider listener if this is the last callback to
 | 
			
		||||
            // be removed.
 | 
			
		||||
            if (this.provider.off && this.provider.on) {
 | 
			
		||||
@@ -177,9 +175,6 @@ define([
 | 
			
		||||
     */
 | 
			
		||||
    CompositionCollection.prototype.add = function (child, skipMutate) {
 | 
			
		||||
        if (!skipMutate) {
 | 
			
		||||
            if (!this.publicAPI.composition.checkPolicy(this.domainObject, child)) {
 | 
			
		||||
                throw `Object of type ${child.type} cannot be added to object of type ${this.domainObject.type}`;
 | 
			
		||||
            }
 | 
			
		||||
            this.provider.add(this.domainObject, child.identifier);
 | 
			
		||||
        } else {
 | 
			
		||||
            this.emit('add', child);
 | 
			
		||||
@@ -271,19 +266,6 @@ define([
 | 
			
		||||
        this.remove(child, true);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    CompositionCollection.prototype._synchronize = function () {
 | 
			
		||||
        this.mutationListener = this.publicAPI.objects.observe(this.domainObject, '*', (newDomainObject) => {
 | 
			
		||||
            this.domainObject = JSON.parse(JSON.stringify(newDomainObject));
 | 
			
		||||
        });
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    CompositionCollection.prototype._destroy = function () {
 | 
			
		||||
        if (this.mutationListener) {
 | 
			
		||||
            this.mutationListener();
 | 
			
		||||
            delete this.mutationListener;
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Emit events.
 | 
			
		||||
     * @private
 | 
			
		||||
 
 | 
			
		||||
@@ -48,11 +48,24 @@ define([
 | 
			
		||||
        this.listeningTo = {};
 | 
			
		||||
        this.onMutation = this.onMutation.bind(this);
 | 
			
		||||
 | 
			
		||||
        this.cannotContainDuplicates = this.cannotContainDuplicates.bind(this);
 | 
			
		||||
        this.cannotContainItself = this.cannotContainItself.bind(this);
 | 
			
		||||
 | 
			
		||||
        compositionAPI.addPolicy(this.cannotContainDuplicates);
 | 
			
		||||
        compositionAPI.addPolicy(this.cannotContainItself);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @private
 | 
			
		||||
     */
 | 
			
		||||
    DefaultCompositionProvider.prototype.cannotContainDuplicates = function (parent, child) {
 | 
			
		||||
        return this.appliesTo(parent) &&
 | 
			
		||||
            parent.composition.findIndex((composeeId) => {
 | 
			
		||||
                return composeeId.namespace === child.identifier.namespace &&
 | 
			
		||||
                    composeeId.key === child.identifier.key;
 | 
			
		||||
            }) === -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @private
 | 
			
		||||
     */
 | 
			
		||||
@@ -186,18 +199,9 @@ define([
 | 
			
		||||
     * @memberof module:openmct.CompositionProvider#
 | 
			
		||||
     * @method add
 | 
			
		||||
     */
 | 
			
		||||
    DefaultCompositionProvider.prototype.add = function (parent, childId) {
 | 
			
		||||
        if (!this.includes(parent, childId)) {
 | 
			
		||||
            parent.composition.push(childId);
 | 
			
		||||
            this.publicAPI.objects.mutate(parent, 'composition', parent.composition);
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
    /**
 | 
			
		||||
     * @private
 | 
			
		||||
     */
 | 
			
		||||
    DefaultCompositionProvider.prototype.includes = function (parent, childId) {
 | 
			
		||||
        return parent.composition.findIndex(composee =>
 | 
			
		||||
            this.publicAPI.objects.areIdsEqual(composee, childId)) !== -1;
 | 
			
		||||
    DefaultCompositionProvider.prototype.add = function (domainObject, child) {
 | 
			
		||||
        throw new Error('Default Provider does not implement adding.');
 | 
			
		||||
        // TODO: this needs to be synchronized via mutation
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    DefaultCompositionProvider.prototype.reorder = function (domainObject, oldIndex, newIndex) {
 | 
			
		||||
 
 | 
			
		||||
@@ -49,9 +49,6 @@ class ContextMenuAPI {
 | 
			
		||||
     *           a single sentence or short paragraph) of this kind of view
 | 
			
		||||
     * @property {string} cssClass the CSS class to apply to labels for this
 | 
			
		||||
     *           view (to add icons, for instance)
 | 
			
		||||
     * @property {string} key unique key to identify the context menu action
 | 
			
		||||
     *           (used in custom context menu eg table rows, to identify which actions to include)
 | 
			
		||||
     * @property {boolean} hideInDefaultMenu optional flag to hide action from showing in the default context menu (tree item)
 | 
			
		||||
     */
 | 
			
		||||
    /**
 | 
			
		||||
     * @method appliesTo
 | 
			
		||||
@@ -75,21 +72,12 @@ class ContextMenuAPI {
 | 
			
		||||
    /**
 | 
			
		||||
     * @private
 | 
			
		||||
     */
 | 
			
		||||
    _showContextMenuForObjectPath(objectPath, x, y, actionsToBeIncluded) {
 | 
			
		||||
 | 
			
		||||
    _showContextMenuForObjectPath(objectPath, x, y) {
 | 
			
		||||
        let applicableActions = this._allActions.filter((action) => {
 | 
			
		||||
 | 
			
		||||
            if (actionsToBeIncluded) {
 | 
			
		||||
                if (action.appliesTo === undefined && actionsToBeIncluded.includes(action.key)) {
 | 
			
		||||
                    return true;
 | 
			
		||||
                }
 | 
			
		||||
                return action.appliesTo(objectPath, actionsToBeIncluded) && actionsToBeIncluded.includes(action.key);
 | 
			
		||||
            } else {
 | 
			
		||||
                if (action.appliesTo === undefined) {
 | 
			
		||||
                    return true;
 | 
			
		||||
                }
 | 
			
		||||
                return action.appliesTo(objectPath) && !action.hideInDefaultMenu;
 | 
			
		||||
            if (action.appliesTo === undefined) {
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
            return action.appliesTo(objectPath);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        if (this._activeContextMenu) {
 | 
			
		||||
 
 | 
			
		||||
@@ -28,7 +28,7 @@ define(['zepto', './res/indicator-template.html'],
 | 
			
		||||
            this.openmct = openmct;
 | 
			
		||||
            this.element = $(indicatorTemplate)[0];
 | 
			
		||||
 | 
			
		||||
            this.textElement = this.element.querySelector('.js-indicator-text');
 | 
			
		||||
            this.textElement = this.element.querySelector('.indicator-text');
 | 
			
		||||
 | 
			
		||||
            //Set defaults
 | 
			
		||||
            this.text('New Indicator');
 | 
			
		||||
 
 | 
			
		||||
@@ -1,3 +1,3 @@
 | 
			
		||||
<div class="c-indicator c-indicator--clickable c-indicator--simple" title="">
 | 
			
		||||
    <span class="label js-indicator-text c-indicator__label"></span>
 | 
			
		||||
<div class="ls-indicator" title="">
 | 
			
		||||
    <span class="label indicator-text"></span>
 | 
			
		||||
</div>
 | 
			
		||||
 
 | 
			
		||||
@@ -21,10 +21,8 @@
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
define([
 | 
			
		||||
    './object-utils.js',
 | 
			
		||||
    'lodash'
 | 
			
		||||
], function (
 | 
			
		||||
    utils,
 | 
			
		||||
    _
 | 
			
		||||
) {
 | 
			
		||||
    var ANY_OBJECT_EVENT = "mutation";
 | 
			
		||||
@@ -43,9 +41,7 @@ define([
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function qualifiedEventName(object, eventName) {
 | 
			
		||||
        var keystring = utils.makeKeyString(object.identifier);
 | 
			
		||||
 | 
			
		||||
        return [keystring, eventName].join(':');
 | 
			
		||||
        return [object.identifier.key, eventName].join(':');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    MutableObject.prototype.stopListening = function () {
 | 
			
		||||
 
 | 
			
		||||
@@ -36,7 +36,7 @@
 | 
			
		||||
 | 
			
		||||
    .c-message {
 | 
			
		||||
        display: flex;
 | 
			
		||||
        align-items: center;
 | 
			
		||||
        align-items: flex-start;
 | 
			
		||||
 | 
			
		||||
        > * + * {
 | 
			
		||||
            margin-left: $interiorMarginLg;
 | 
			
		||||
@@ -66,17 +66,6 @@
 | 
			
		||||
            font-size: 1.2em; // TEMP
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        &--simple {
 | 
			
		||||
            // Icon and text elements only
 | 
			
		||||
            &:before {
 | 
			
		||||
                font-size: 30px !important;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [class*='__text'] {
 | 
			
		||||
                font-size: 1.25em;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /************************** LEGACY */
 | 
			
		||||
        &.message-severity-info:before {
 | 
			
		||||
            @include legacyMessage();
 | 
			
		||||
@@ -93,7 +82,7 @@
 | 
			
		||||
        &.message-severity-error:before {
 | 
			
		||||
            @include legacyMessage();
 | 
			
		||||
            content: $glyph-icon-alert-triangle;
 | 
			
		||||
            color: $colorWarningHi;
 | 
			
		||||
            color: $colorWarningLo;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Messages in a list
 | 
			
		||||
 
 | 
			
		||||
@@ -69,7 +69,6 @@
 | 
			
		||||
            flex: 1 1 auto;
 | 
			
		||||
            display: flex;
 | 
			
		||||
            flex-direction: column;
 | 
			
		||||
            overflow: hidden;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        &__top-bar {
 | 
			
		||||
@@ -93,7 +92,6 @@
 | 
			
		||||
            display: flex;
 | 
			
		||||
            flex-direction: column;
 | 
			
		||||
            flex: 1 1 auto;
 | 
			
		||||
            height: 0; // Chrome 73 overflow bug fix
 | 
			
		||||
            overflow: auto;
 | 
			
		||||
            padding-right: $interiorMargin; // fend off scroll bar
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -280,11 +280,7 @@ define([
 | 
			
		||||
        if (!provider) {
 | 
			
		||||
            return Promise.reject('No provider found');
 | 
			
		||||
        }
 | 
			
		||||
        return provider.request.apply(provider, arguments).catch((rejected) => {
 | 
			
		||||
            this.openmct.notifications.error('Error requesting telemetry data, see console for details');
 | 
			
		||||
            console.error(rejected);
 | 
			
		||||
            return Promise.reject(rejected);
 | 
			
		||||
        });
 | 
			
		||||
        return provider.request.apply(provider, arguments);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
 
 | 
			
		||||
@@ -38,7 +38,7 @@ define([
 | 
			
		||||
            canEdit: function (domainObject) {
 | 
			
		||||
                return domainObject.type === 'LadTableSet';
 | 
			
		||||
            },
 | 
			
		||||
            view: function (domainObject, isEditing, objectPath) {
 | 
			
		||||
            view: function (domainObject) {
 | 
			
		||||
                let component;
 | 
			
		||||
 | 
			
		||||
                return {
 | 
			
		||||
@@ -49,8 +49,7 @@ define([
 | 
			
		||||
                            },
 | 
			
		||||
                            provide: {
 | 
			
		||||
                                openmct,
 | 
			
		||||
                                domainObject,
 | 
			
		||||
                                objectPath
 | 
			
		||||
                                domainObject
 | 
			
		||||
                            },
 | 
			
		||||
                            el: element,
 | 
			
		||||
                            template: '<lad-table-set></lad-table-set>'
 | 
			
		||||
 
 | 
			
		||||
@@ -21,7 +21,7 @@
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
define([
 | 
			
		||||
    './components/LADTable.vue',
 | 
			
		||||
    './components/LadTable.vue',
 | 
			
		||||
    'vue'
 | 
			
		||||
], function (
 | 
			
		||||
    LadTableComponent,
 | 
			
		||||
@@ -38,7 +38,7 @@ define([
 | 
			
		||||
            canEdit: function (domainObject) {
 | 
			
		||||
                return domainObject.type === 'LadTable';
 | 
			
		||||
            },
 | 
			
		||||
            view: function (domainObject, isEditing, objectPath) {
 | 
			
		||||
            view: function (domainObject) {
 | 
			
		||||
                let component;
 | 
			
		||||
 | 
			
		||||
                return {
 | 
			
		||||
@@ -49,8 +49,7 @@ define([
 | 
			
		||||
                            },
 | 
			
		||||
                            provide: {
 | 
			
		||||
                                openmct,
 | 
			
		||||
                                domainObject,
 | 
			
		||||
                                objectPath
 | 
			
		||||
                                domainObject
 | 
			
		||||
                            },
 | 
			
		||||
                            el: element,
 | 
			
		||||
                            template: '<lad-table-component></lad-table-component>'
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,3 @@
 | 
			
		||||
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT, Copyright (c) 2014-2018, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
@@ -22,7 +21,7 @@
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
    <tr @contextmenu.prevent="showContextMenu">
 | 
			
		||||
    <tr>
 | 
			
		||||
        <td>{{name}}</td>
 | 
			
		||||
        <td>{{timestamp}}</td>
 | 
			
		||||
        <td :class="valueClass">
 | 
			
		||||
@@ -36,25 +35,15 @@
 | 
			
		||||
</style>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
 | 
			
		||||
const CONTEXT_MENU_ACTIONS = [
 | 
			
		||||
    'viewHistoricalData',
 | 
			
		||||
    'remove'
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
    inject: ['openmct', 'objectPath'],
 | 
			
		||||
    inject: ['openmct'],
 | 
			
		||||
    props: ['domainObject'],
 | 
			
		||||
    data() {
 | 
			
		||||
        let currentObjectPath = this.objectPath.slice();
 | 
			
		||||
        currentObjectPath.unshift(this.domainObject);
 | 
			
		||||
 | 
			
		||||
        return {
 | 
			
		||||
            name: this.domainObject.name,
 | 
			
		||||
            timestamp: '---',
 | 
			
		||||
            value: '---',
 | 
			
		||||
            valueClass: '',
 | 
			
		||||
            currentObjectPath
 | 
			
		||||
            valueClass: ''
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
    methods: {
 | 
			
		||||
@@ -84,15 +73,11 @@ export default {
 | 
			
		||||
                .request(this.domainObject, {strategy: 'latest'})
 | 
			
		||||
                .then((array) => this.updateValues(array[array.length - 1]));
 | 
			
		||||
 | 
			
		||||
        },
 | 
			
		||||
        showContextMenu(event) {
 | 
			
		||||
           this.openmct.contextMenu._showContextMenuForObjectPath(this.currentObjectPath, event.x, event.y, CONTEXT_MENU_ACTIONS);
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
    mounted() {
 | 
			
		||||
        this.metadata = this.openmct.telemetry.getMetadata(this.domainObject);
 | 
			
		||||
        this.formats = this.openmct.telemetry.getFormatMap(this.metadata);
 | 
			
		||||
        this.keyString = this.openmct.objects.makeKeyString(this.domainObject.identifier);
 | 
			
		||||
 | 
			
		||||
        this.limitEvaluator = openmct
 | 
			
		||||
            .telemetry
 | 
			
		||||
 
 | 
			
		||||
@@ -41,10 +41,10 @@
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import lodash from 'lodash';
 | 
			
		||||
import LadRow from './LADRow.vue';
 | 
			
		||||
import LadRow from './LadRow.vue';
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
    inject: ['openmct', 'domainObject', 'objectPath'],
 | 
			
		||||
    inject: ['openmct', 'domainObject'],
 | 
			
		||||
    components: {
 | 
			
		||||
        LadRow
 | 
			
		||||
    },
 | 
			
		||||
 
 | 
			
		||||
@@ -52,7 +52,7 @@
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
    import lodash from 'lodash';
 | 
			
		||||
    import LadRow from './LADRow.vue';
 | 
			
		||||
    import LadRow from './LadRow.vue';
 | 
			
		||||
 | 
			
		||||
    export default {
 | 
			
		||||
    inject: ['openmct', 'domainObject'],
 | 
			
		||||
 
 | 
			
		||||
@@ -1,18 +0,0 @@
 | 
			
		||||
<template>
 | 
			
		||||
    <div class="c-indicator c-indicator--clickable icon-session">
 | 
			
		||||
        <span class="label c-indicator__label">
 | 
			
		||||
            <button @click="globalClearEmit">Clear All Data</button>
 | 
			
		||||
        </span>
 | 
			
		||||
    </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
export default {
 | 
			
		||||
    inject: ['openmct'],
 | 
			
		||||
    methods: {
 | 
			
		||||
        globalClearEmit() {
 | 
			
		||||
            this.openmct.objectViews.emit('clearData');
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
@@ -1,54 +0,0 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT, Copyright (c) 2014-2019, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
define([
 | 
			
		||||
    './components/globalClearIndicator.vue',
 | 
			
		||||
    './clearDataAction',
 | 
			
		||||
    'vue'
 | 
			
		||||
], function (
 | 
			
		||||
    GlobaClearIndicator,
 | 
			
		||||
    ClearDataAction,
 | 
			
		||||
    Vue
 | 
			
		||||
) {
 | 
			
		||||
    return function plugin(appliesToObjects) {
 | 
			
		||||
        appliesToObjects = appliesToObjects || [];
 | 
			
		||||
 | 
			
		||||
        return function install(openmct) {
 | 
			
		||||
            let component = new Vue ({
 | 
			
		||||
                    provide: {
 | 
			
		||||
                        openmct
 | 
			
		||||
                    },
 | 
			
		||||
                    components: {
 | 
			
		||||
                        GlobalClearIndicator: GlobaClearIndicator.default
 | 
			
		||||
                    },
 | 
			
		||||
                    template: '<GlobalClearIndicator></GlobalClearIndicator>'
 | 
			
		||||
                }),
 | 
			
		||||
                indicator = {
 | 
			
		||||
                    element: component.$mount().$el
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
            openmct.indicators.add(indicator);
 | 
			
		||||
 | 
			
		||||
            openmct.contextMenu.registerAction(new ClearDataAction.default(openmct, appliesToObjects));
 | 
			
		||||
        };
 | 
			
		||||
    };
 | 
			
		||||
});
 | 
			
		||||
@@ -1,62 +0,0 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT, Copyright (c) 2014-2018, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
import ClearDataActionPlugin  from '../plugin.js';
 | 
			
		||||
import ClearDataAction from '../clearDataAction.js';
 | 
			
		||||
 | 
			
		||||
describe('When the Clear Data Plugin is installed,', function () {
 | 
			
		||||
    var mockObjectViews = jasmine.createSpyObj('objectViews', ['emit']),
 | 
			
		||||
        mockIndicatorProvider = jasmine.createSpyObj('indicators', ['add']),
 | 
			
		||||
        mockContextMenuProvider = jasmine.createSpyObj('contextMenu', ['registerAction']),
 | 
			
		||||
        openmct = {
 | 
			
		||||
            objectViews: mockObjectViews,
 | 
			
		||||
            indicators: mockIndicatorProvider,
 | 
			
		||||
            contextMenu: mockContextMenuProvider,
 | 
			
		||||
            install: function (plugin) {
 | 
			
		||||
                plugin(this);
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        mockObjectPath = [
 | 
			
		||||
            {name: 'mockObject1'},
 | 
			
		||||
            {name: 'mockObject2'}
 | 
			
		||||
        ];
 | 
			
		||||
 | 
			
		||||
    it('Global Clear Indicator is installed', function () {
 | 
			
		||||
        openmct.install(ClearDataActionPlugin([]));
 | 
			
		||||
 | 
			
		||||
        expect(mockIndicatorProvider.add).toHaveBeenCalled();
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('Clear Data context menu action is installed', function () {
 | 
			
		||||
        openmct.install(ClearDataActionPlugin([]));
 | 
			
		||||
 | 
			
		||||
        expect(mockContextMenuProvider.registerAction).toHaveBeenCalled();
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('clear data action emits a clearData event when invoked', function () {
 | 
			
		||||
        let action = new ClearDataAction(openmct);
 | 
			
		||||
 | 
			
		||||
        action.invoke(mockObjectPath);
 | 
			
		||||
 | 
			
		||||
        expect(mockObjectViews.emit).toHaveBeenCalledWith('clearData', mockObjectPath[0]);
 | 
			
		||||
    });
 | 
			
		||||
});
 | 
			
		||||
@@ -1,78 +0,0 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT, Copyright (c) 2014-2018, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
define([
 | 
			
		||||
    './components/AlphanumericFormatView.vue',
 | 
			
		||||
    'vue'
 | 
			
		||||
], function (AlphanumericFormatView, Vue) {
 | 
			
		||||
 | 
			
		||||
    function AlphanumericFormatViewProvider(openmct, options) {
 | 
			
		||||
        function isTelemetryObject(selectionPath) {
 | 
			
		||||
            let selectedObject = selectionPath[0].context.item;
 | 
			
		||||
            let parentObject = selectionPath[1].context.item;
 | 
			
		||||
            return parentObject && 
 | 
			
		||||
                parentObject.type === 'layout' &&
 | 
			
		||||
                selectedObject &&
 | 
			
		||||
                openmct.telemetry.isTelemetryObject(selectedObject) &&
 | 
			
		||||
                !options.showAsView.includes(selectedObject.type)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return {
 | 
			
		||||
            key: 'alphanumeric-format',
 | 
			
		||||
            name: 'Alphanumeric Format',
 | 
			
		||||
            canView: function (selection) {
 | 
			
		||||
                if (selection.length === 0 || selection[0].length === 1) {
 | 
			
		||||
                    return false;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                return selection.every(isTelemetryObject);
 | 
			
		||||
            },
 | 
			
		||||
            view: function (domainObject, isEditing, objectPath) {
 | 
			
		||||
                let component;
 | 
			
		||||
                return {
 | 
			
		||||
                    show: function (element) {
 | 
			
		||||
                        component = new Vue({
 | 
			
		||||
                            provide: {
 | 
			
		||||
                                openmct,
 | 
			
		||||
                                objectPath
 | 
			
		||||
                            },
 | 
			
		||||
                            components: {
 | 
			
		||||
                                AlphanumericFormatView: AlphanumericFormatView.default
 | 
			
		||||
                            },
 | 
			
		||||
                            template: '<alphanumeric-format-view></alphanumeric-format-view>',
 | 
			
		||||
                            el: element
 | 
			
		||||
                        });
 | 
			
		||||
                    },
 | 
			
		||||
                    destroy: function () {
 | 
			
		||||
                        component.$destroy();
 | 
			
		||||
                        component = undefined;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            priority: function () {
 | 
			
		||||
                return 1;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return AlphanumericFormatViewProvider;
 | 
			
		||||
});
 | 
			
		||||
@@ -28,17 +28,11 @@ define([], function () {
 | 
			
		||||
            key: "layout",
 | 
			
		||||
            description: "A toolbar for objects inside a display layout.",
 | 
			
		||||
            forSelection: function (selection) {
 | 
			
		||||
                if (!selection || selection.length === 0) {
 | 
			
		||||
                    return false;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                let selectionPath = selection[0];
 | 
			
		||||
                let selectedObject = selectionPath[0];
 | 
			
		||||
                let selectedParent = selectionPath[1];
 | 
			
		||||
 | 
			
		||||
                // Apply the layout toolbar if the selected object is inside a layout, or the main layout is selected.
 | 
			
		||||
                return (selectedParent && selectedParent.context.item && selectedParent.context.item.type === 'layout') ||
 | 
			
		||||
                    (selectedObject.context.item && selectedObject.context.item.type === 'layout');
 | 
			
		||||
                // Apply the layout toolbar if the selected object
 | 
			
		||||
                // is inside a layout, or the main layout is selected.
 | 
			
		||||
                return (selection &&
 | 
			
		||||
                    ((selection[1] && selection[1].context.item && selection[1].context.item.type === 'layout') ||
 | 
			
		||||
                        (selection[0].context.item && selection[0].context.item.type === 'layout')));
 | 
			
		||||
            },
 | 
			
		||||
            toolbar: function (selection) {
 | 
			
		||||
                const DIALOG_FORM = {
 | 
			
		||||
@@ -79,72 +73,190 @@ define([], function () {
 | 
			
		||||
                    return openmct.$injector.get('dialogService').getUserInput(form, {});
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                function getPath(selectionPath) {
 | 
			
		||||
                    return `configuration.items[${selectionPath[0].context.index}]`;
 | 
			
		||||
                function getPath() {
 | 
			
		||||
                    return `configuration.items[${selection[0].context.index}]`;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                function getAllTypes(selection) {
 | 
			
		||||
                    return selection.filter(selectionPath => {
 | 
			
		||||
                        let type = selectionPath[0].context.layoutItem.type;
 | 
			
		||||
                        return type === 'text-view' ||
 | 
			
		||||
                            type === 'telemetry-view' ||
 | 
			
		||||
                            type === 'box-view' ||
 | 
			
		||||
                            type === 'image-view' ||
 | 
			
		||||
                            type === 'line-view' ||
 | 
			
		||||
                            type === 'subobject-view';
 | 
			
		||||
                let selectedParent = selection[1] && selection[1].context.item,
 | 
			
		||||
                    selectedObject = selection[0].context.item,
 | 
			
		||||
                    layoutItem = selection[0].context.layoutItem,
 | 
			
		||||
                    toolbar = [];
 | 
			
		||||
 | 
			
		||||
                if (selectedObject && selectedObject.type === 'layout') {
 | 
			
		||||
                    toolbar.push({
 | 
			
		||||
                        control: "menu",
 | 
			
		||||
                        domainObject: selectedObject,
 | 
			
		||||
                        method: function (option) {
 | 
			
		||||
                            let name = option.name.toLowerCase();
 | 
			
		||||
                            let form = DIALOG_FORM[name];
 | 
			
		||||
                            if (form) {
 | 
			
		||||
                                getUserInput(form)
 | 
			
		||||
                                    .then(element => selection[0].context.addElement(name, element));
 | 
			
		||||
                            } else {
 | 
			
		||||
                                selection[0].context.addElement(name);
 | 
			
		||||
                            }
 | 
			
		||||
                        },
 | 
			
		||||
                        key: "add",
 | 
			
		||||
                        icon: "icon-plus",
 | 
			
		||||
                        label: "Add",
 | 
			
		||||
                        options: [
 | 
			
		||||
                            {
 | 
			
		||||
                                "name": "Box",
 | 
			
		||||
                                "class": "icon-box-round-corners"
 | 
			
		||||
                            },
 | 
			
		||||
                            {
 | 
			
		||||
                                "name": "Line",
 | 
			
		||||
                                "class": "icon-line-horz"
 | 
			
		||||
                            },
 | 
			
		||||
                            {
 | 
			
		||||
                                "name": "Text",
 | 
			
		||||
                                "class": "icon-font"
 | 
			
		||||
                            },
 | 
			
		||||
                            {
 | 
			
		||||
                                "name": "Image",
 | 
			
		||||
                                "class": "icon-image"
 | 
			
		||||
                            }
 | 
			
		||||
                        ]
 | 
			
		||||
                    });
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                function getAddButton(selection, selectionPath) {
 | 
			
		||||
                    if (selection.length === 1) {
 | 
			
		||||
                        selectionPath = selectionPath || selection[0];
 | 
			
		||||
                        return {
 | 
			
		||||
                            control: "menu",
 | 
			
		||||
                            domainObject: selectionPath[0].context.item,
 | 
			
		||||
                            method: function (option) {
 | 
			
		||||
                                let name = option.name.toLowerCase();
 | 
			
		||||
                                let form = DIALOG_FORM[name];
 | 
			
		||||
                                if (form) {
 | 
			
		||||
                                    getUserInput(form)
 | 
			
		||||
                                        .then(element => selectionPath[0].context.addElement(name, element));
 | 
			
		||||
                                } else {
 | 
			
		||||
                                    selectionPath[0].context.addElement(name);
 | 
			
		||||
                                }
 | 
			
		||||
                            },
 | 
			
		||||
                            key: "add",
 | 
			
		||||
                            icon: "icon-plus",
 | 
			
		||||
                            label: "Add",
 | 
			
		||||
                            options: [
 | 
			
		||||
                                {
 | 
			
		||||
                                    "name": "Box",
 | 
			
		||||
                                    "class": "icon-box-round-corners"
 | 
			
		||||
                                },
 | 
			
		||||
                                {
 | 
			
		||||
                                    "name": "Line",
 | 
			
		||||
                                    "class": "icon-line-horz"
 | 
			
		||||
                                },
 | 
			
		||||
                                {
 | 
			
		||||
                                    "name": "Text",
 | 
			
		||||
                                    "class": "icon-font"
 | 
			
		||||
                                },
 | 
			
		||||
                                {
 | 
			
		||||
                                    "name": "Image",
 | 
			
		||||
                                    "class": "icon-image"
 | 
			
		||||
                                }
 | 
			
		||||
                            ]
 | 
			
		||||
                        };
 | 
			
		||||
                    }
 | 
			
		||||
                if (!layoutItem) {
 | 
			
		||||
                    return toolbar;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                function getToggleFrameButton(selectedParent, selection) {
 | 
			
		||||
                    return {
 | 
			
		||||
                let separator = {
 | 
			
		||||
                    control: "separator"
 | 
			
		||||
                };
 | 
			
		||||
                let remove = {
 | 
			
		||||
                    control: "button",
 | 
			
		||||
                    domainObject: selectedParent,
 | 
			
		||||
                    icon: "icon-trash",
 | 
			
		||||
                    title: "Delete the selected object",
 | 
			
		||||
                    method: function () {
 | 
			
		||||
                        let removeItem = selection[1].context.removeItem;
 | 
			
		||||
                        let prompt = openmct.overlays.dialog({
 | 
			
		||||
                            iconClass: 'alert',
 | 
			
		||||
                            message: `Warning! This action will remove this item from the Display Layout. Do you want to continue?`,
 | 
			
		||||
                            buttons: [
 | 
			
		||||
                                {
 | 
			
		||||
                                    label: 'Ok',
 | 
			
		||||
                                    emphasis: 'true',
 | 
			
		||||
                                    callback: function () {
 | 
			
		||||
                                        removeItem(layoutItem, selection[0].context.index);
 | 
			
		||||
                                        prompt.dismiss();
 | 
			
		||||
                                    }
 | 
			
		||||
                                },
 | 
			
		||||
                                {
 | 
			
		||||
                                    label: 'Cancel',
 | 
			
		||||
                                    callback: function () {
 | 
			
		||||
                                        prompt.dismiss();
 | 
			
		||||
                                    }
 | 
			
		||||
                                }
 | 
			
		||||
                            ]
 | 
			
		||||
                        });
 | 
			
		||||
                    }
 | 
			
		||||
                };
 | 
			
		||||
                let stackOrder = {
 | 
			
		||||
                    control: "menu",
 | 
			
		||||
                    domainObject: selectedParent,
 | 
			
		||||
                    icon: "icon-layers",
 | 
			
		||||
                    title: "Move the selected object above or below other objects",
 | 
			
		||||
                    options: [
 | 
			
		||||
                        {
 | 
			
		||||
                            name: "Move to Top",
 | 
			
		||||
                            value: "top",
 | 
			
		||||
                            class: "icon-arrow-double-up"
 | 
			
		||||
                        },
 | 
			
		||||
                        {
 | 
			
		||||
                            name: "Move Up",
 | 
			
		||||
                            value: "up",
 | 
			
		||||
                            class: "icon-arrow-up"
 | 
			
		||||
                        },
 | 
			
		||||
                        {
 | 
			
		||||
                            name: "Move Down",
 | 
			
		||||
                            value: "down",
 | 
			
		||||
                            class: "icon-arrow-down"
 | 
			
		||||
                        },
 | 
			
		||||
                        {
 | 
			
		||||
                            name: "Move to Bottom",
 | 
			
		||||
                            value: "bottom",
 | 
			
		||||
                            class: "icon-arrow-double-down"
 | 
			
		||||
                        }
 | 
			
		||||
                    ],
 | 
			
		||||
                    method: function (option) {
 | 
			
		||||
                        selection[1].context.orderItem(option.value, selection[0].context.index);
 | 
			
		||||
                    }
 | 
			
		||||
                };
 | 
			
		||||
                let useGrid = {
 | 
			
		||||
                    control: "toggle-button",
 | 
			
		||||
                    domainObject: selectedParent,
 | 
			
		||||
                    property: function () {
 | 
			
		||||
                        return getPath() + ".useGrid";
 | 
			
		||||
                    },
 | 
			
		||||
                    options: [
 | 
			
		||||
                        {
 | 
			
		||||
                            value: false,
 | 
			
		||||
                            icon: "icon-grid-snap-to",
 | 
			
		||||
                            title: "Grid snapping enabled"
 | 
			
		||||
                        },
 | 
			
		||||
                        {
 | 
			
		||||
                            value: true,
 | 
			
		||||
                            icon: "icon-grid-snap-no",
 | 
			
		||||
                            title: "Grid snapping disabled"
 | 
			
		||||
                        }
 | 
			
		||||
                    ]
 | 
			
		||||
                };
 | 
			
		||||
                let x = {
 | 
			
		||||
                    control: "input",
 | 
			
		||||
                    type: "number",
 | 
			
		||||
                    domainObject: selectedParent,
 | 
			
		||||
                    property: function () {
 | 
			
		||||
                        return getPath() + ".x";
 | 
			
		||||
                    },
 | 
			
		||||
                    label: "X:",
 | 
			
		||||
                    title: "X position"
 | 
			
		||||
                },
 | 
			
		||||
                y = {
 | 
			
		||||
                    control: "input",
 | 
			
		||||
                    type: "number",
 | 
			
		||||
                    domainObject: selectedParent,
 | 
			
		||||
                    property: function () {
 | 
			
		||||
                        return getPath() + ".y";
 | 
			
		||||
                    },
 | 
			
		||||
                    label: "Y:",
 | 
			
		||||
                    title: "Y position",
 | 
			
		||||
                },
 | 
			
		||||
                width = {
 | 
			
		||||
                    control: 'input',
 | 
			
		||||
                    type: 'number',
 | 
			
		||||
                    domainObject: selectedParent,
 | 
			
		||||
                    property: function () {
 | 
			
		||||
                        return getPath() + ".width";
 | 
			
		||||
                    },
 | 
			
		||||
                    label: 'W:',
 | 
			
		||||
                    title: 'Resize object width'
 | 
			
		||||
                },
 | 
			
		||||
                height = {
 | 
			
		||||
                    control: 'input',
 | 
			
		||||
                    type: 'number',
 | 
			
		||||
                    domainObject: selectedParent,
 | 
			
		||||
                    property: function () {
 | 
			
		||||
                        return getPath() + ".height";
 | 
			
		||||
                    },
 | 
			
		||||
                    label: 'H:',
 | 
			
		||||
                    title: 'Resize object height'
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
                if (layoutItem.type === 'subobject-view') {
 | 
			
		||||
                    if (toolbar.length > 0) {
 | 
			
		||||
                        toolbar.push(separator);
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    toolbar.push({
 | 
			
		||||
                        control: "toggle-button",
 | 
			
		||||
                        domainObject: selectedParent,
 | 
			
		||||
                        applicableSelectedItems: selection.filter(selectionPath => 
 | 
			
		||||
                            selectionPath[0].context.layoutItem.type === 'subobject-view'
 | 
			
		||||
                        ),
 | 
			
		||||
                        property: function (selectionPath) {
 | 
			
		||||
                            return getPath(selectionPath) + ".hasFrame";
 | 
			
		||||
                        property: function () {
 | 
			
		||||
                            return getPath() + ".hasFrame";
 | 
			
		||||
                        },
 | 
			
		||||
                        options: [
 | 
			
		||||
                            {
 | 
			
		||||
@@ -158,186 +270,52 @@ define([], function () {
 | 
			
		||||
                                title: "Frame hidden"
 | 
			
		||||
                            }
 | 
			
		||||
                        ]
 | 
			
		||||
                    };
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                function getRemoveButton(selectedParent, selectionPath, selection) {
 | 
			
		||||
                    return {
 | 
			
		||||
                        control: "button",
 | 
			
		||||
                        domainObject: selectedParent,
 | 
			
		||||
                        icon: "icon-trash",
 | 
			
		||||
                        title: "Delete the selected object",
 | 
			
		||||
                        method: function () {
 | 
			
		||||
                            let removeItem = selectionPath[1].context.removeItem;
 | 
			
		||||
                            let prompt = openmct.overlays.dialog({
 | 
			
		||||
                                iconClass: 'alert',
 | 
			
		||||
                                message: `Warning! This action will remove this item from the Display Layout. Do you want to continue?`,
 | 
			
		||||
                                buttons: [
 | 
			
		||||
                                    {
 | 
			
		||||
                                        label: 'Ok',
 | 
			
		||||
                                        emphasis: 'true',
 | 
			
		||||
                                        callback: function () {
 | 
			
		||||
                                            removeItem(getAllTypes(selection));
 | 
			
		||||
                                            prompt.dismiss();
 | 
			
		||||
                                        }
 | 
			
		||||
                                    },
 | 
			
		||||
                                    {
 | 
			
		||||
                                        label: 'Cancel',
 | 
			
		||||
                                        callback: function () {
 | 
			
		||||
                                            prompt.dismiss();
 | 
			
		||||
                                        }
 | 
			
		||||
                                    }
 | 
			
		||||
                                ]
 | 
			
		||||
                            });
 | 
			
		||||
                        }
 | 
			
		||||
                    };
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                function getStackOrder(selectedParent, selectionPath) {
 | 
			
		||||
                    return {
 | 
			
		||||
                        control: "menu",
 | 
			
		||||
                        domainObject: selectedParent,
 | 
			
		||||
                        icon: "icon-layers",
 | 
			
		||||
                        title: "Move the selected object above or below other objects",
 | 
			
		||||
                        options: [
 | 
			
		||||
                            {
 | 
			
		||||
                                name: "Move to Top",
 | 
			
		||||
                                value: "top",
 | 
			
		||||
                                class: "icon-arrow-double-up"
 | 
			
		||||
                            },
 | 
			
		||||
                            {
 | 
			
		||||
                                name: "Move Up",
 | 
			
		||||
                                value: "up",
 | 
			
		||||
                                class: "icon-arrow-up"
 | 
			
		||||
                            },
 | 
			
		||||
                            {
 | 
			
		||||
                                name: "Move Down",
 | 
			
		||||
                                value: "down",
 | 
			
		||||
                                class: "icon-arrow-down"
 | 
			
		||||
                            },
 | 
			
		||||
                            {
 | 
			
		||||
                                name: "Move to Bottom",
 | 
			
		||||
                                value: "bottom",
 | 
			
		||||
                                class: "icon-arrow-double-down"
 | 
			
		||||
                            }
 | 
			
		||||
                        ],
 | 
			
		||||
                        method: function (option) {
 | 
			
		||||
                            selectionPath[1].context.orderItem(option.value, getAllTypes(selection));
 | 
			
		||||
                        }
 | 
			
		||||
                    };
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                function getXInput(selectedParent, selection) {
 | 
			
		||||
                    if (selection.length === 1) {
 | 
			
		||||
                        return {
 | 
			
		||||
                            control: "input",
 | 
			
		||||
                            type: "number",
 | 
			
		||||
                            domainObject: selectedParent,
 | 
			
		||||
                            applicableSelectedItems: getAllTypes(selection),
 | 
			
		||||
                            property: function (selectionPath) {
 | 
			
		||||
                                return getPath(selectionPath) + ".x";
 | 
			
		||||
                            },
 | 
			
		||||
                            label: "X:",
 | 
			
		||||
                            title: "X position"
 | 
			
		||||
                        };
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                function getYInput(selectedParent, selection) {
 | 
			
		||||
                    if (selection.length === 1) {
 | 
			
		||||
                        return {
 | 
			
		||||
                            control: "input",
 | 
			
		||||
                            type: "number",
 | 
			
		||||
                            domainObject: selectedParent,
 | 
			
		||||
                            applicableSelectedItems: getAllTypes(selection),
 | 
			
		||||
                            property: function (selectionPath) {
 | 
			
		||||
                                return getPath(selectionPath) + ".y";
 | 
			
		||||
                            },
 | 
			
		||||
                            label: "Y:",
 | 
			
		||||
                            title: "Y position",
 | 
			
		||||
                        };
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                function getWidthInput(selectedParent, selection) {
 | 
			
		||||
                    if (selection.length === 1) {
 | 
			
		||||
                        return {
 | 
			
		||||
                            control: 'input',
 | 
			
		||||
                            type: 'number',
 | 
			
		||||
                            domainObject: selectedParent,
 | 
			
		||||
                            applicableSelectedItems: getAllTypes(selection),
 | 
			
		||||
                            property: function (selectionPath) {
 | 
			
		||||
                                return getPath(selectionPath) + ".width";
 | 
			
		||||
                            },
 | 
			
		||||
                            label: 'W:',
 | 
			
		||||
                            title: 'Resize object width'
 | 
			
		||||
                        };
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                function getHeightInput(selectedParent, selection) {
 | 
			
		||||
                    if (selection.length === 1) {
 | 
			
		||||
                        return {
 | 
			
		||||
                            control: 'input',
 | 
			
		||||
                            type: 'number',
 | 
			
		||||
                            domainObject: selectedParent,
 | 
			
		||||
                            applicableSelectedItems: getAllTypes(selection),
 | 
			
		||||
                            property: function (selectionPath) {
 | 
			
		||||
                                return getPath(selectionPath) + ".height";
 | 
			
		||||
                            },
 | 
			
		||||
                            label: 'H:',
 | 
			
		||||
                            title: 'Resize object height'
 | 
			
		||||
                        };
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                function getX2Input(selectedParent, selection) {
 | 
			
		||||
                    if (selection.length === 1) {
 | 
			
		||||
                        return {
 | 
			
		||||
                            control: "input",
 | 
			
		||||
                            type: "number",
 | 
			
		||||
                            domainObject: selectedParent,
 | 
			
		||||
                            applicableSelectedItems: selection.filter(selectionPath => {
 | 
			
		||||
                                return selectionPath[0].context.layoutItem.type === 'line-view';
 | 
			
		||||
                            }),
 | 
			
		||||
                            property: function (selectionPath) {
 | 
			
		||||
                                return getPath(selectionPath) + ".x2";
 | 
			
		||||
                            },
 | 
			
		||||
                            label: "X2:",
 | 
			
		||||
                            title: "X2 position"
 | 
			
		||||
                        };
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                function getY2Input(selectedParent, selection) {
 | 
			
		||||
                    if (selection.length === 1) {
 | 
			
		||||
                        return {
 | 
			
		||||
                            control: "input",
 | 
			
		||||
                            type: "number",
 | 
			
		||||
                            domainObject: selectedParent,
 | 
			
		||||
                            applicableSelectedItems: selection.filter(selectionPath => {
 | 
			
		||||
                                return selectionPath[0].context.layoutItem.type === 'line-view';
 | 
			
		||||
                            }),
 | 
			
		||||
                            property: function (selectionPath) {
 | 
			
		||||
                                return getPath(selectionPath) + ".y2";
 | 
			
		||||
                            },
 | 
			
		||||
                            label: "Y2:",
 | 
			
		||||
                            title: "Y2 position",
 | 
			
		||||
                        };
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                function getTextSizeMenu(selectedParent, selection) {
 | 
			
		||||
                    });
 | 
			
		||||
                    toolbar.push(separator);
 | 
			
		||||
                    toolbar.push(stackOrder);
 | 
			
		||||
                    toolbar.push(x);
 | 
			
		||||
                    toolbar.push(y);
 | 
			
		||||
                    toolbar.push(width);
 | 
			
		||||
                    toolbar.push(height);
 | 
			
		||||
                    toolbar.push(useGrid);
 | 
			
		||||
                    toolbar.push(separator);
 | 
			
		||||
                    toolbar.push(remove);
 | 
			
		||||
                } else {
 | 
			
		||||
                    const TEXT_SIZE = [8, 9, 10, 11, 12, 13, 14, 15, 16, 20, 24, 30, 36, 48, 72, 96, 128];
 | 
			
		||||
                    return {
 | 
			
		||||
                    let fill = {
 | 
			
		||||
                        control: "color-picker",
 | 
			
		||||
                        domainObject: selectedParent,
 | 
			
		||||
                        property: function () {
 | 
			
		||||
                            return getPath() + ".fill";
 | 
			
		||||
                        },
 | 
			
		||||
                        icon: "icon-paint-bucket",
 | 
			
		||||
                        title: "Set fill color"
 | 
			
		||||
                    },
 | 
			
		||||
                    stroke = {
 | 
			
		||||
                        control: "color-picker",
 | 
			
		||||
                        domainObject: selectedParent,
 | 
			
		||||
                        property: function () {
 | 
			
		||||
                            return getPath() + ".stroke";
 | 
			
		||||
                        },
 | 
			
		||||
                        icon: "icon-line-horz",
 | 
			
		||||
                        title: "Set border color"
 | 
			
		||||
                    },
 | 
			
		||||
                    color = {
 | 
			
		||||
                        control: "color-picker",
 | 
			
		||||
                        domainObject: selectedParent,
 | 
			
		||||
                        property: function () {
 | 
			
		||||
                            return getPath() + ".color";
 | 
			
		||||
                        },
 | 
			
		||||
                        icon: "icon-font",
 | 
			
		||||
                        mandatory: true,
 | 
			
		||||
                        title: "Set text color",
 | 
			
		||||
                        preventNone: true
 | 
			
		||||
                    },
 | 
			
		||||
                    size = {
 | 
			
		||||
                        control: "select-menu",
 | 
			
		||||
                        domainObject: selectedParent,
 | 
			
		||||
                        applicableSelectedItems: selection.filter(selectionPath => {
 | 
			
		||||
                            let type = selectionPath[0].context.layoutItem.type;
 | 
			
		||||
                            return type === 'text-view' || type === 'telemetry-view';
 | 
			
		||||
                        }),
 | 
			
		||||
                        property: function (selectionPath) {
 | 
			
		||||
                            return getPath(selectionPath) + ".size";
 | 
			
		||||
                        property: function () {
 | 
			
		||||
                            return getPath() + ".size";
 | 
			
		||||
                        },
 | 
			
		||||
                        title: "Set text size",
 | 
			
		||||
                        options: TEXT_SIZE.map(size => {
 | 
			
		||||
@@ -346,128 +324,13 @@ define([], function () {
 | 
			
		||||
                            };
 | 
			
		||||
                        })
 | 
			
		||||
                    };
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                function getFillMenu(selectedParent, selection) {
 | 
			
		||||
                    return {
 | 
			
		||||
                        control: "color-picker",
 | 
			
		||||
                        domainObject: selectedParent,
 | 
			
		||||
                        applicableSelectedItems: selection.filter(selectionPath => {
 | 
			
		||||
                            let type = selectionPath[0].context.layoutItem.type;
 | 
			
		||||
                            return type === 'text-view' ||
 | 
			
		||||
                                type === 'telemetry-view' ||
 | 
			
		||||
                                type === 'box-view';
 | 
			
		||||
                        }),
 | 
			
		||||
                        property: function (selectionPath) {
 | 
			
		||||
                            return getPath(selectionPath) + ".fill";
 | 
			
		||||
                        },
 | 
			
		||||
                        icon: "icon-paint-bucket",
 | 
			
		||||
                        title: "Set fill color"
 | 
			
		||||
                    };
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                function getStrokeMenu(selectedParent, selection) {
 | 
			
		||||
                    return {
 | 
			
		||||
                        control: "color-picker",
 | 
			
		||||
                        domainObject: selectedParent,
 | 
			
		||||
                        applicableSelectedItems: selection.filter(selectionPath => {
 | 
			
		||||
                            let type = selectionPath[0].context.layoutItem.type;
 | 
			
		||||
                            return type === 'text-view' ||
 | 
			
		||||
                                type === 'telemetry-view' ||
 | 
			
		||||
                                type === 'box-view' ||
 | 
			
		||||
                                type === 'image-view' ||
 | 
			
		||||
                                type === 'line-view';
 | 
			
		||||
                        }),
 | 
			
		||||
                        property: function (selectionPath) {
 | 
			
		||||
                            return getPath(selectionPath) + ".stroke";
 | 
			
		||||
                        },
 | 
			
		||||
                        icon: "icon-line-horz",
 | 
			
		||||
                        title: "Set border color"
 | 
			
		||||
                    };
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                function getTextColorMenu(selectedParent, selection) {
 | 
			
		||||
                    return {
 | 
			
		||||
                        control: "color-picker",
 | 
			
		||||
                        domainObject: selectedParent,
 | 
			
		||||
                        applicableSelectedItems: selection.filter(selectionPath => {
 | 
			
		||||
                            let type = selectionPath[0].context.layoutItem.type;
 | 
			
		||||
                            return type === 'text-view' || type === 'telemetry-view';
 | 
			
		||||
                        }),
 | 
			
		||||
                        property: function (selectionPath) {
 | 
			
		||||
                            return getPath(selectionPath) + ".color";
 | 
			
		||||
                        },
 | 
			
		||||
                        icon: "icon-font",
 | 
			
		||||
                        mandatory: true,
 | 
			
		||||
                        title: "Set text color",
 | 
			
		||||
                        preventNone: true
 | 
			
		||||
                    };
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                function getURLButton(selectedParent, selection) {
 | 
			
		||||
                    return {
 | 
			
		||||
                        control: "button",
 | 
			
		||||
                        domainObject: selectedParent,
 | 
			
		||||
                        applicableSelectedItems: selection.filter(selectionPath => {
 | 
			
		||||
                            return selectionPath[0].context.layoutItem.type === 'image-view';
 | 
			
		||||
                        }),
 | 
			
		||||
                        property: function (selectionPath) {
 | 
			
		||||
                            return getPath(selectionPath);
 | 
			
		||||
                        },
 | 
			
		||||
                        icon: "icon-image",
 | 
			
		||||
                        title: "Edit image properties",
 | 
			
		||||
                        dialog: DIALOG_FORM['image']
 | 
			
		||||
                    };
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                function getTextButton(selectedParent, selection) {
 | 
			
		||||
                        return {
 | 
			
		||||
                            control: "button",
 | 
			
		||||
                            domainObject: selectedParent,
 | 
			
		||||
                            applicableSelectedItems: selection.filter(selectionPath => {
 | 
			
		||||
                                return selectionPath[0].context.layoutItem.type === 'text-view';
 | 
			
		||||
                            }),
 | 
			
		||||
                            property: function (selectionPath) {
 | 
			
		||||
                                return getPath(selectionPath);
 | 
			
		||||
                            },
 | 
			
		||||
                            icon: "icon-gear",
 | 
			
		||||
                            title: "Edit text properties",
 | 
			
		||||
                            dialog: DIALOG_FORM['text']
 | 
			
		||||
                        };
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                function getTelemetryValueMenu(selectionPath, selection) {
 | 
			
		||||
                    if (selection.length === 1) {
 | 
			
		||||
                        return {
 | 
			
		||||
                            control: "select-menu",
 | 
			
		||||
                            domainObject: selectionPath[1].context.item,
 | 
			
		||||
                            applicableSelectedItems: selection.filter(selectionPath => {
 | 
			
		||||
                                return selectionPath[0].context.layoutItem.type === 'telemetry-view';
 | 
			
		||||
                            }),
 | 
			
		||||
                            property: function (selectionPath) {
 | 
			
		||||
                                return getPath(selectionPath) + ".value";
 | 
			
		||||
                            },
 | 
			
		||||
                            title: "Set value",
 | 
			
		||||
                            options: openmct.telemetry.getMetadata(selectionPath[0].context.item).values().map(value => {
 | 
			
		||||
                                return {
 | 
			
		||||
                                    name: value.name,
 | 
			
		||||
                                    value: value.key
 | 
			
		||||
                                }
 | 
			
		||||
                            })
 | 
			
		||||
                        };
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                function getDisplayModeMenu(selectedParent, selection) {
 | 
			
		||||
                    if (selection.length === 1) {
 | 
			
		||||
                        return {
 | 
			
		||||
                    if (layoutItem.type === 'telemetry-view') {
 | 
			
		||||
                        let displayMode = {
 | 
			
		||||
                            control: "select-menu",
 | 
			
		||||
                            domainObject: selectedParent,
 | 
			
		||||
                            applicableSelectedItems: selection.filter(selectionPath => {
 | 
			
		||||
                                return selectionPath[0].context.layoutItem.type === 'telemetry-view';
 | 
			
		||||
                            }),
 | 
			
		||||
                            property: function (selectionPath) {
 | 
			
		||||
                                return getPath(selectionPath) + ".displayMode";
 | 
			
		||||
                            property: function () {
 | 
			
		||||
                                return getPath() + ".displayMode";
 | 
			
		||||
                            },
 | 
			
		||||
                            title: "Set display mode",
 | 
			
		||||
                            options: [
 | 
			
		||||
@@ -484,196 +347,146 @@ define([], function () {
 | 
			
		||||
                                    value: "value"
 | 
			
		||||
                                }
 | 
			
		||||
                            ]
 | 
			
		||||
                        },
 | 
			
		||||
                        value = {
 | 
			
		||||
                            control: "select-menu",
 | 
			
		||||
                            domainObject: selectedParent,
 | 
			
		||||
                            property: function () {
 | 
			
		||||
                                return getPath() + ".value";
 | 
			
		||||
                            },
 | 
			
		||||
                            title: "Set value",
 | 
			
		||||
                            options: openmct.telemetry.getMetadata(selectedObject).values().map(value => {
 | 
			
		||||
                                return {
 | 
			
		||||
                                    name: value.name,
 | 
			
		||||
                                    value: value.key
 | 
			
		||||
                                }
 | 
			
		||||
                            })
 | 
			
		||||
                        };
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                function getSeparator() {
 | 
			
		||||
                    return {
 | 
			
		||||
                        control: "separator"
 | 
			
		||||
                    };
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                function isMainLayoutSelected(selectionPath) {
 | 
			
		||||
                    let selectedObject = selectionPath[0].context.item;
 | 
			
		||||
                    return selectedObject && selectedObject.type === 'layout' &&
 | 
			
		||||
                        !selectionPath[0].context.layoutItem;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (isMainLayoutSelected(selection[0])) {
 | 
			
		||||
                    return [getAddButton(selection)];
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                let toolbar = {
 | 
			
		||||
                    'add-menu': [],
 | 
			
		||||
                    'toggle-frame': [],
 | 
			
		||||
                    'display-mode': [],
 | 
			
		||||
                    'telemetry-value': [],
 | 
			
		||||
                    'style': [],
 | 
			
		||||
                    'text-style': [],
 | 
			
		||||
                    'position': [],
 | 
			
		||||
                    'text': [],
 | 
			
		||||
                    'url': [],
 | 
			
		||||
                    'remove': [],
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
                selection.forEach(selectionPath => {
 | 
			
		||||
                    let selectedParent = selectionPath[1].context.item;
 | 
			
		||||
                    let layoutItem = selectionPath[0].context.layoutItem;
 | 
			
		||||
 | 
			
		||||
                    if (layoutItem.type === 'subobject-view') {
 | 
			
		||||
                        if (toolbar['add-menu'].length === 0 && selectionPath[0].context.item.type === 'layout') {
 | 
			
		||||
                            toolbar['add-menu'] = [getAddButton(selection, selectionPath)];
 | 
			
		||||
                        }
 | 
			
		||||
                        if (toolbar['toggle-frame'].length === 0) {
 | 
			
		||||
                            toolbar['toggle-frame'] = [getToggleFrameButton(selectedParent, selection)];
 | 
			
		||||
                        }
 | 
			
		||||
                        if (toolbar['position'].length === 0) {
 | 
			
		||||
                            toolbar['position'] = [
 | 
			
		||||
                                getStackOrder(selectedParent, selectionPath),
 | 
			
		||||
                                getXInput(selectedParent, selection),
 | 
			
		||||
                                getYInput(selectedParent, selection),
 | 
			
		||||
                                getHeightInput(selectedParent, selection),
 | 
			
		||||
                                getWidthInput(selectedParent, selection)
 | 
			
		||||
                            ];
 | 
			
		||||
                        }
 | 
			
		||||
                        if (toolbar['remove'].length === 0) {
 | 
			
		||||
                            toolbar['remove'] = [getRemoveButton(selectedParent, selectionPath, selection)];
 | 
			
		||||
                        }
 | 
			
		||||
                    } else if (layoutItem.type === 'telemetry-view') {
 | 
			
		||||
                        if (toolbar['display-mode'].length === 0) {
 | 
			
		||||
                            toolbar['display-mode'] = [getDisplayModeMenu(selectedParent, selection)];
 | 
			
		||||
                        }
 | 
			
		||||
                        if (toolbar['telemetry-value'].length === 0) {
 | 
			
		||||
                            toolbar['telemetry-value'] = [getTelemetryValueMenu(selectionPath, selection)];
 | 
			
		||||
                        }
 | 
			
		||||
                        if (toolbar['style'].length < 2) {
 | 
			
		||||
                            toolbar['style'] = [
 | 
			
		||||
                                getFillMenu(selectedParent, selection),
 | 
			
		||||
                                getStrokeMenu(selectedParent, selection)
 | 
			
		||||
                            ];
 | 
			
		||||
                        }
 | 
			
		||||
                        if (toolbar['text-style'].length === 0) {
 | 
			
		||||
                            toolbar['text-style'] = [
 | 
			
		||||
                                getTextColorMenu(selectedParent, selection),
 | 
			
		||||
                                getTextSizeMenu(selectedParent, selection)
 | 
			
		||||
                            ];
 | 
			
		||||
                        }
 | 
			
		||||
                        if (toolbar['position'].length === 0) {
 | 
			
		||||
                            toolbar['position'] = [
 | 
			
		||||
                                getStackOrder(selectedParent, selectionPath),
 | 
			
		||||
                                getXInput(selectedParent, selection),
 | 
			
		||||
                                getYInput(selectedParent, selection),
 | 
			
		||||
                                getHeightInput(selectedParent, selection),
 | 
			
		||||
                                getWidthInput(selectedParent, selection)
 | 
			
		||||
                            ];
 | 
			
		||||
                        }
 | 
			
		||||
                        if (toolbar['remove'].length === 0) {
 | 
			
		||||
                            toolbar['remove'] = [getRemoveButton(selectedParent, selectionPath, selection)];
 | 
			
		||||
                        }
 | 
			
		||||
                        toolbar = [
 | 
			
		||||
                            displayMode,
 | 
			
		||||
                            separator,
 | 
			
		||||
                            value,
 | 
			
		||||
                            separator,
 | 
			
		||||
                            fill,
 | 
			
		||||
                            stroke,
 | 
			
		||||
                            color,
 | 
			
		||||
                            separator,
 | 
			
		||||
                            size,
 | 
			
		||||
                            separator,
 | 
			
		||||
                            stackOrder,
 | 
			
		||||
                            x,
 | 
			
		||||
                            y,
 | 
			
		||||
                            height,
 | 
			
		||||
                            width,
 | 
			
		||||
                            useGrid,
 | 
			
		||||
                            separator,
 | 
			
		||||
                            remove
 | 
			
		||||
                        ];
 | 
			
		||||
                    } else if (layoutItem.type === 'text-view') {
 | 
			
		||||
                        if (toolbar['style'].length < 2) {
 | 
			
		||||
                            toolbar['style'] = [
 | 
			
		||||
                                getFillMenu(selectedParent, selection),
 | 
			
		||||
                                getStrokeMenu(selectedParent, selection)
 | 
			
		||||
                            ];
 | 
			
		||||
                        }
 | 
			
		||||
                        if (toolbar['text-style'].length === 0) {
 | 
			
		||||
                            toolbar['text-style'] = [
 | 
			
		||||
                                getTextColorMenu(selectedParent, selection),
 | 
			
		||||
                                getTextSizeMenu(selectedParent, selection)
 | 
			
		||||
                            ];
 | 
			
		||||
                        }
 | 
			
		||||
                        if (toolbar['position'].length === 0) {
 | 
			
		||||
                            toolbar['position'] = [
 | 
			
		||||
                                getStackOrder(selectedParent, selectionPath),
 | 
			
		||||
                                getXInput(selectedParent, selection),
 | 
			
		||||
                                getYInput(selectedParent, selection),
 | 
			
		||||
                                getHeightInput(selectedParent, selection),
 | 
			
		||||
                                getWidthInput(selectedParent, selection)
 | 
			
		||||
                            ];
 | 
			
		||||
                        }
 | 
			
		||||
                        if (toolbar['text'].length === 0) {
 | 
			
		||||
                            toolbar['text'] = [getTextButton(selectedParent, selection)];
 | 
			
		||||
                        }
 | 
			
		||||
                        if (toolbar['remove'].length === 0) {
 | 
			
		||||
                            toolbar['remove'] = [getRemoveButton(selectedParent, selectionPath, selection)];
 | 
			
		||||
                        }
 | 
			
		||||
                        let text = {
 | 
			
		||||
                            control: "button",
 | 
			
		||||
                            domainObject: selectedParent,
 | 
			
		||||
                            property: function () {
 | 
			
		||||
                                return getPath();
 | 
			
		||||
                            },
 | 
			
		||||
                            icon: "icon-gear",
 | 
			
		||||
                            title: "Edit text properties",
 | 
			
		||||
                            dialog: DIALOG_FORM['text']
 | 
			
		||||
                        };
 | 
			
		||||
                        toolbar = [
 | 
			
		||||
                            fill,
 | 
			
		||||
                            stroke,
 | 
			
		||||
                            separator,
 | 
			
		||||
                            color,
 | 
			
		||||
                            size,
 | 
			
		||||
                            separator,
 | 
			
		||||
                            stackOrder,
 | 
			
		||||
                            x,
 | 
			
		||||
                            y,
 | 
			
		||||
                            height,
 | 
			
		||||
                            width,
 | 
			
		||||
                            useGrid,
 | 
			
		||||
                            separator,
 | 
			
		||||
                            text,
 | 
			
		||||
                            separator,
 | 
			
		||||
                            remove
 | 
			
		||||
                        ];
 | 
			
		||||
                    } else if (layoutItem.type === 'box-view') {
 | 
			
		||||
                        if (toolbar['style'].length < 2) {
 | 
			
		||||
                            toolbar['style'] = [
 | 
			
		||||
                                getFillMenu(selectedParent, selection),
 | 
			
		||||
                                getStrokeMenu(selectedParent, selection)
 | 
			
		||||
                            ];
 | 
			
		||||
                        }
 | 
			
		||||
                        if (toolbar['position'].length === 0) {
 | 
			
		||||
                            toolbar['position'] = [
 | 
			
		||||
                                getStackOrder(selectedParent, selectionPath),
 | 
			
		||||
                                getXInput(selectedParent, selection),
 | 
			
		||||
                                getYInput(selectedParent, selection),
 | 
			
		||||
                                getHeightInput(selectedParent, selection),
 | 
			
		||||
                                getWidthInput(selectedParent, selection)
 | 
			
		||||
                            ];
 | 
			
		||||
                        }
 | 
			
		||||
                        if (toolbar['remove'].length === 0) {
 | 
			
		||||
                            toolbar['remove'] = [getRemoveButton(selectedParent, selectionPath, selection)];
 | 
			
		||||
                        }
 | 
			
		||||
                        toolbar = [
 | 
			
		||||
                            fill,
 | 
			
		||||
                            stroke,
 | 
			
		||||
                            separator,
 | 
			
		||||
                            stackOrder,
 | 
			
		||||
                            x,
 | 
			
		||||
                            y,
 | 
			
		||||
                            height,
 | 
			
		||||
                            width,
 | 
			
		||||
                            useGrid,
 | 
			
		||||
                            separator,
 | 
			
		||||
                            remove
 | 
			
		||||
                        ];
 | 
			
		||||
                    } else if (layoutItem.type === 'image-view') {
 | 
			
		||||
                        if (toolbar['style'].length === 0) {
 | 
			
		||||
                            toolbar['style'] = [
 | 
			
		||||
                                getStrokeMenu(selectedParent, selection)
 | 
			
		||||
                            ];
 | 
			
		||||
                        }
 | 
			
		||||
                        if (toolbar['position'].length === 0) {
 | 
			
		||||
                            toolbar['position'] = [
 | 
			
		||||
                                getStackOrder(selectedParent, selectionPath),
 | 
			
		||||
                                getXInput(selectedParent, selection),
 | 
			
		||||
                                getYInput(selectedParent, selection),
 | 
			
		||||
                                getHeightInput(selectedParent, selection),
 | 
			
		||||
                                getWidthInput(selectedParent, selection)
 | 
			
		||||
                            ];
 | 
			
		||||
                        }
 | 
			
		||||
                        if (toolbar['url'].length === 0) {
 | 
			
		||||
                            toolbar['url'] = [getURLButton(selectedParent, selection)];
 | 
			
		||||
                        }
 | 
			
		||||
                        if (toolbar['remove'].length === 0) {
 | 
			
		||||
                            toolbar['remove'] = [getRemoveButton(selectedParent, selectionPath, selection)];
 | 
			
		||||
                        }
 | 
			
		||||
                        let url = {
 | 
			
		||||
                            control: "button",
 | 
			
		||||
                            domainObject: selectedParent,
 | 
			
		||||
                            property: function () {
 | 
			
		||||
                                return getPath();
 | 
			
		||||
                            },
 | 
			
		||||
                            icon: "icon-image",
 | 
			
		||||
                            title: "Edit image properties",
 | 
			
		||||
                            dialog: DIALOG_FORM['image']
 | 
			
		||||
                        };
 | 
			
		||||
                        toolbar = [
 | 
			
		||||
                            stroke,
 | 
			
		||||
                            separator,
 | 
			
		||||
                            stackOrder,
 | 
			
		||||
                            x,
 | 
			
		||||
                            y,
 | 
			
		||||
                            height,
 | 
			
		||||
                            width,
 | 
			
		||||
                            useGrid,
 | 
			
		||||
                            separator,
 | 
			
		||||
                            url,
 | 
			
		||||
                            separator,
 | 
			
		||||
                            remove
 | 
			
		||||
                        ];
 | 
			
		||||
                    } else if (layoutItem.type === 'line-view') {
 | 
			
		||||
                        if (toolbar['style'].length === 0) {
 | 
			
		||||
                            toolbar['style'] = [
 | 
			
		||||
                                getStrokeMenu(selectedParent, selection)
 | 
			
		||||
                            ];
 | 
			
		||||
                        }
 | 
			
		||||
                        if (toolbar['position'].length === 0) {
 | 
			
		||||
                            toolbar['position'] = [
 | 
			
		||||
                                getStackOrder(selectedParent, selectionPath),
 | 
			
		||||
                                getXInput(selectedParent, selection),
 | 
			
		||||
                                getYInput(selectedParent, selection),
 | 
			
		||||
                                getX2Input(selectedParent, selection),
 | 
			
		||||
                                getY2Input(selectedParent, selection)
 | 
			
		||||
                            ];
 | 
			
		||||
                        }
 | 
			
		||||
                        if (toolbar['remove'].length === 0) {
 | 
			
		||||
                            toolbar['remove'] = [getRemoveButton(selectedParent, selectionPath, selection)];
 | 
			
		||||
                        }
 | 
			
		||||
                        let x2 = {
 | 
			
		||||
                            control: "input",
 | 
			
		||||
                            type: "number",
 | 
			
		||||
                            domainObject: selectedParent,
 | 
			
		||||
                            property: function () {
 | 
			
		||||
                                return getPath() + ".x2";
 | 
			
		||||
                            },
 | 
			
		||||
                            label: "X2:",
 | 
			
		||||
                            title: "X2 position"
 | 
			
		||||
                        },
 | 
			
		||||
                        y2 = {
 | 
			
		||||
                            control: "input",
 | 
			
		||||
                            type: "number",
 | 
			
		||||
                            domainObject: selectedParent,
 | 
			
		||||
                            property: function () {
 | 
			
		||||
                                return getPath() + ".y2";
 | 
			
		||||
                            },
 | 
			
		||||
                            label: "Y2:",
 | 
			
		||||
                            title: "Y2 position",
 | 
			
		||||
                        };
 | 
			
		||||
                        toolbar = [
 | 
			
		||||
                            stroke,
 | 
			
		||||
                            separator,
 | 
			
		||||
                            stackOrder,
 | 
			
		||||
                            x,
 | 
			
		||||
                            y,
 | 
			
		||||
                            x2,
 | 
			
		||||
                            y2,
 | 
			
		||||
                            useGrid,
 | 
			
		||||
                            separator,
 | 
			
		||||
                            remove
 | 
			
		||||
                        ];
 | 
			
		||||
                    }
 | 
			
		||||
                });
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                let toolbarArray = Object.values(toolbar);
 | 
			
		||||
                return _.flatten(toolbarArray.reduce((accumulator, group, index) => {
 | 
			
		||||
                    group = group.filter(control => control !== undefined);
 | 
			
		||||
 | 
			
		||||
                    if (group.length > 0) {
 | 
			
		||||
                        accumulator.push(group);
 | 
			
		||||
 | 
			
		||||
                        if (index < toolbarArray.length - 1) {
 | 
			
		||||
                            accumulator.push(getSeparator());
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    return accumulator;
 | 
			
		||||
                }, []));
 | 
			
		||||
                return toolbar;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -95,7 +95,7 @@ define(
 | 
			
		||||
         * @param {number[]} pixelDelta the offset from the
 | 
			
		||||
         *        original position, in pixels
 | 
			
		||||
         */
 | 
			
		||||
        LayoutDrag.prototype.getAdjustedPositionAndDimensions = function (pixelDelta) {
 | 
			
		||||
        LayoutDrag.prototype.getAdjustedPosition = function (pixelDelta) {
 | 
			
		||||
            var gridDelta = toGridDelta(this.gridSize, pixelDelta);
 | 
			
		||||
            return {
 | 
			
		||||
                position: max(add(
 | 
			
		||||
@@ -109,16 +109,6 @@ define(
 | 
			
		||||
            };
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        LayoutDrag.prototype.getAdjustedPosition = function (pixelDelta) {
 | 
			
		||||
            var gridDelta = toGridDelta(this.gridSize, pixelDelta);
 | 
			
		||||
            return {
 | 
			
		||||
                position: max(add(
 | 
			
		||||
                    this.rawPosition.position,
 | 
			
		||||
                    multiply(gridDelta, this.posFactor)
 | 
			
		||||
                ), [0, 0])
 | 
			
		||||
            };
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        return LayoutDrag;
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,90 +0,0 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT, Copyright (c) 2014-2018, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
    <div class="c-properties" v-if="isEditing">
 | 
			
		||||
        <div class="c-properties__header">Alphanumeric Format</div>
 | 
			
		||||
        <ul class="c-properties__section">
 | 
			
		||||
            <li class="c-properties__row">
 | 
			
		||||
                <div class="c-properties__label" title="Printf formatting for the selected telemetry">
 | 
			
		||||
                    <label for="telemetryPrintfFormat">Format</label>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="c-properties__value">
 | 
			
		||||
                    <input id="telemetryPrintfFormat"
 | 
			
		||||
                        type="text"
 | 
			
		||||
                        @change="formatTelemetry"
 | 
			
		||||
                        :value="telemetryFormat"
 | 
			
		||||
                        :placeholder="nonMixedFormat ? '' : 'Mixed'"
 | 
			
		||||
                    >
 | 
			
		||||
                </div>
 | 
			
		||||
            </li>
 | 
			
		||||
        </ul>
 | 
			
		||||
    </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
    export default {
 | 
			
		||||
        inject: ['openmct'],
 | 
			
		||||
        data() {
 | 
			
		||||
            let selectionPath = this.openmct.selection.get()[0];
 | 
			
		||||
            return {
 | 
			
		||||
                isEditing: this.openmct.editor.isEditing(),
 | 
			
		||||
                telemetryFormat: undefined,
 | 
			
		||||
                nonMixedFormat: false
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        methods: {
 | 
			
		||||
            toggleEdit(isEditing) {
 | 
			
		||||
                this.isEditing = isEditing;
 | 
			
		||||
            },
 | 
			
		||||
            formatTelemetry(event) {
 | 
			
		||||
                let newFormat = event.currentTarget.value;
 | 
			
		||||
                this.openmct.selection.get().forEach(selectionPath => {
 | 
			
		||||
                    selectionPath[0].context.updateTelemetryFormat(newFormat);    
 | 
			
		||||
                });
 | 
			
		||||
                this.telemetryFormat = newFormat;
 | 
			
		||||
            },
 | 
			
		||||
            handleSelection(selection) {
 | 
			
		||||
                if (selection.length === 0 || selection[0].length < 2) {
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                let format = selection[0][0].context.layoutItem.format;
 | 
			
		||||
                this.nonMixedFormat = selection.every(selectionPath => {
 | 
			
		||||
                    return selectionPath[0].context.layoutItem.format === format;
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                this.telemetryFormat = this.nonMixedFormat ? format : '';
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        mounted() {
 | 
			
		||||
            this.openmct.editor.on('isEditing', this.toggleEdit);
 | 
			
		||||
            this.openmct.selection.on('change', this.handleSelection);
 | 
			
		||||
            this.handleSelection(this.openmct.selection.get());
 | 
			
		||||
        },
 | 
			
		||||
        destroyed() {
 | 
			
		||||
            this.openmct.editor.off('isEditing', this.toggleEdit);
 | 
			
		||||
            this.openmct.selection.off('change', this.handleSelection);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
</script>
 | 
			
		||||
@@ -23,8 +23,7 @@
 | 
			
		||||
<template>
 | 
			
		||||
    <layout-frame :item="item"
 | 
			
		||||
                  :grid-size="gridSize"
 | 
			
		||||
                  @move="(gridDelta) => $emit('move', gridDelta)"
 | 
			
		||||
                  @endMove="() => $emit('endMove')">
 | 
			
		||||
                  @endDrag="(item, updates) => $emit('endDrag', item, updates)">
 | 
			
		||||
        <div class="c-box-view"
 | 
			
		||||
             :style="style">
 | 
			
		||||
        </div>
 | 
			
		||||
@@ -55,7 +54,8 @@
 | 
			
		||||
                x: 1,
 | 
			
		||||
                y: 1,
 | 
			
		||||
                width: 10, 
 | 
			
		||||
                height: 5
 | 
			
		||||
                height: 5,
 | 
			
		||||
                useGrid: true
 | 
			
		||||
            };
 | 
			
		||||
        },
 | 
			
		||||
        inject: ['openmct'],
 | 
			
		||||
 
 | 
			
		||||
@@ -23,11 +23,8 @@
 | 
			
		||||
<template>
 | 
			
		||||
    <div class="l-layout"
 | 
			
		||||
         @dragover="handleDragOver"
 | 
			
		||||
         @click.capture="bypassSelection"
 | 
			
		||||
         @drop="handleDrop"
 | 
			
		||||
         :class="{
 | 
			
		||||
            'is-multi-selected': selectedLayoutItems.length > 1
 | 
			
		||||
            }">
 | 
			
		||||
         @click="bypassSelection"
 | 
			
		||||
         @drop="handleDrop">
 | 
			
		||||
        <!-- Background grid -->
 | 
			
		||||
        <div class="l-layout__grid-holder c-grid">
 | 
			
		||||
            <div class="c-grid__x l-grid l-grid-x"
 | 
			
		||||
@@ -42,39 +39,18 @@
 | 
			
		||||
                   :is="item.type"
 | 
			
		||||
                   :item="item"
 | 
			
		||||
                   :key="item.id"
 | 
			
		||||
                   :gridSize="gridSize"
 | 
			
		||||
                   :gridSize="item.useGrid ? gridSize : [1, 1]"
 | 
			
		||||
                   :initSelect="initSelectIndex === index"
 | 
			
		||||
                   :index="index"
 | 
			
		||||
                   :multiSelect="selectedLayoutItems.length > 1"
 | 
			
		||||
                   @move="move"
 | 
			
		||||
                   @endMove="endMove"
 | 
			
		||||
                   @endLineResize='endLineResize'
 | 
			
		||||
                   @formatChanged='updateTelemetryFormat'>
 | 
			
		||||
                   @endDrag="endDrag"
 | 
			
		||||
        >
 | 
			
		||||
        </component>
 | 
			
		||||
        <edit-marquee v-if='showMarquee'
 | 
			
		||||
                      :gridSize="gridSize"
 | 
			
		||||
                      :selectedLayoutItems="selectedLayoutItems"
 | 
			
		||||
                      @endResize="endResize">
 | 
			
		||||
        </edit-marquee>
 | 
			
		||||
    </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<style lang="scss">
 | 
			
		||||
    @import "~styles/sass-base";
 | 
			
		||||
 | 
			
		||||
    @mixin displayMarquee($c) {
 | 
			
		||||
        > .c-frame-edit {
 | 
			
		||||
            // All other frames
 | 
			
		||||
            //@include test($c, 0.4);
 | 
			
		||||
            display: block;
 | 
			
		||||
        }
 | 
			
		||||
        > .c-frame > .c-frame-edit {
 | 
			
		||||
            // Line object frame
 | 
			
		||||
            //@include test($c, 0.4);
 | 
			
		||||
            display: block;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .l-layout {
 | 
			
		||||
        @include abs();
 | 
			
		||||
        display: flex;
 | 
			
		||||
@@ -94,7 +70,7 @@
 | 
			
		||||
        .l-shell__main-container {
 | 
			
		||||
            &[s-selected],
 | 
			
		||||
            &[s-selected-parent] {
 | 
			
		||||
                // Display grid and allow edit marquee to display in main layout holder when editing
 | 
			
		||||
                // Display grid in main layout holder when editing
 | 
			
		||||
                > .l-layout {
 | 
			
		||||
                    background: $editUIGridColorBg;
 | 
			
		||||
 | 
			
		||||
@@ -108,7 +84,7 @@
 | 
			
		||||
        .l-layout__frame {
 | 
			
		||||
            &[s-selected],
 | 
			
		||||
            &[s-selected-parent] {
 | 
			
		||||
                // Display grid and allow edit marquee to display in nested layouts when editing
 | 
			
		||||
                // Display grid in nested layouts when editing
 | 
			
		||||
                > * > * > .l-layout {
 | 
			
		||||
                    background: $editUIGridColorBg;
 | 
			
		||||
                    box-shadow: inset $editUIGridColorFg 0 0 2px 1px;
 | 
			
		||||
@@ -119,21 +95,10 @@
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /*********************** EDIT MARQUEE CONTROL */
 | 
			
		||||
        *[s-selected-parent] {
 | 
			
		||||
            > .l-layout {
 | 
			
		||||
                // When main shell layout is the parent
 | 
			
		||||
                @include displayMarquee(deeppink);
 | 
			
		||||
            }
 | 
			
		||||
            > * > * > * {
 | 
			
		||||
                // When a sub-layout is the parent
 | 
			
		||||
                @include displayMarquee(blue);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
</style>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
    import uuid from 'uuid';
 | 
			
		||||
 | 
			
		||||
@@ -143,7 +108,6 @@
 | 
			
		||||
    import TextView from './TextView.vue'
 | 
			
		||||
    import LineView from './LineView.vue'
 | 
			
		||||
    import ImageView from './ImageView.vue'
 | 
			
		||||
    import EditMarquee from './EditMarquee.vue'
 | 
			
		||||
 | 
			
		||||
    const ITEM_TYPE_VIEW_MAP = {
 | 
			
		||||
        'subobject-view': SubobjectView,
 | 
			
		||||
@@ -159,10 +123,8 @@
 | 
			
		||||
        down: -1,
 | 
			
		||||
        bottom: Number.NEGATIVE_INFINITY
 | 
			
		||||
    };
 | 
			
		||||
    const DRAG_OBJECT_TRANSFER_PREFIX = 'openmct/domain-object/';
 | 
			
		||||
 | 
			
		||||
    let components = ITEM_TYPE_VIEW_MAP;
 | 
			
		||||
    components['edit-marquee'] = EditMarquee;
 | 
			
		||||
    const DRAG_OBJECT_TRANSFER_PREFIX = 'openmct/domain-object/';
 | 
			
		||||
 | 
			
		||||
    function getItemDefinition(itemType, ...options) {
 | 
			
		||||
        let itemView = ITEM_TYPE_VIEW_MAP[itemType];
 | 
			
		||||
@@ -179,8 +141,7 @@
 | 
			
		||||
            let domainObject = JSON.parse(JSON.stringify(this.domainObject));
 | 
			
		||||
            return {
 | 
			
		||||
                internalDomainObject: domainObject,
 | 
			
		||||
                initSelectIndex: undefined,
 | 
			
		||||
                selection: []
 | 
			
		||||
                initSelectIndex: undefined
 | 
			
		||||
            };
 | 
			
		||||
        },
 | 
			
		||||
        computed: {
 | 
			
		||||
@@ -189,145 +150,82 @@
 | 
			
		||||
            },
 | 
			
		||||
            layoutItems() {
 | 
			
		||||
                return this.internalDomainObject.configuration.items;
 | 
			
		||||
            },
 | 
			
		||||
            selectedLayoutItems() {
 | 
			
		||||
                return this.layoutItems.filter(item => {
 | 
			
		||||
                    return this.itemIsInCurrentSelection(item);
 | 
			
		||||
                });
 | 
			
		||||
            },
 | 
			
		||||
            showMarquee() {
 | 
			
		||||
                let selectionPath = this.selection[0];
 | 
			
		||||
                let singleSelectedLine = this.selection.length === 1 &&
 | 
			
		||||
                    selectionPath[0].context.layoutItem && selectionPath[0].context.layoutItem.type === 'line-view';
 | 
			
		||||
                return selectionPath && selectionPath.length > 1 && !singleSelectedLine;
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        inject: ['openmct', 'options', 'objectPath'],
 | 
			
		||||
        inject: ['openmct'],
 | 
			
		||||
        props: ['domainObject'],
 | 
			
		||||
        components: components,
 | 
			
		||||
        components: ITEM_TYPE_VIEW_MAP,
 | 
			
		||||
        methods: {
 | 
			
		||||
            addElement(itemType, element) {
 | 
			
		||||
                this.addItem(itemType + '-view', element);
 | 
			
		||||
            },
 | 
			
		||||
            setSelection(selection) {
 | 
			
		||||
                this.selection = selection;
 | 
			
		||||
                if (selection.length === 0) {
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (this.removeSelectionListener) {
 | 
			
		||||
                    this.removeSelectionListener();
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                let itemIndex = selection[0].context.index;
 | 
			
		||||
 | 
			
		||||
                if (itemIndex !== undefined) {
 | 
			
		||||
                    this.attachSelectionListener(itemIndex);
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            itemIsInCurrentSelection(item) {
 | 
			
		||||
                return this.selection.some(selectionPath =>
 | 
			
		||||
                    selectionPath[0].context.layoutItem && selectionPath[0].context.layoutItem.id === item.id);
 | 
			
		||||
            attachSelectionListener(index) {
 | 
			
		||||
                let path = `configuration.items[${index}].useGrid`;
 | 
			
		||||
                this.removeSelectionListener = this.openmct.objects.observe(this.internalDomainObject, path, function (value) {
 | 
			
		||||
                    let item = this.layoutItems[index];
 | 
			
		||||
 | 
			
		||||
                    if (value) {
 | 
			
		||||
                        item.x = Math.round(item.x / this.gridSize[0]);
 | 
			
		||||
                        item.y = Math.round(item.y / this.gridSize[1]);
 | 
			
		||||
                        item.width = Math.round(item.width / this.gridSize[0]);
 | 
			
		||||
                        item.height = Math.round(item.height / this.gridSize[1]);
 | 
			
		||||
 | 
			
		||||
                        if (item.x2) {
 | 
			
		||||
                            item.x2 = Math.round(item.x2 / this.gridSize[0]);
 | 
			
		||||
                        }
 | 
			
		||||
                        if (item.y2) {
 | 
			
		||||
                            item.y2 = Math.round(item.y2 / this.gridSize[1]);
 | 
			
		||||
                        }
 | 
			
		||||
                    } else {
 | 
			
		||||
                        item.x = this.gridSize[0] * item.x;
 | 
			
		||||
                        item.y = this.gridSize[1] * item.y;
 | 
			
		||||
                        item.width = this.gridSize[0] * item.width;
 | 
			
		||||
                        item.height = this.gridSize[1] * item.height;
 | 
			
		||||
 | 
			
		||||
                        if (item.x2) {
 | 
			
		||||
                            item.x2 = this.gridSize[0] * item.x2;
 | 
			
		||||
                        }
 | 
			
		||||
                        if (item.y2) {
 | 
			
		||||
                            item.y2 = this.gridSize[1] * item.y2;
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    item.useGrid = value;
 | 
			
		||||
                    this.mutate(`configuration.items[${index}]`, item);
 | 
			
		||||
                }.bind(this));
 | 
			
		||||
            },
 | 
			
		||||
            bypassSelection($event) {
 | 
			
		||||
                if (this.dragInProgress) {
 | 
			
		||||
                    if ($event) {
 | 
			
		||||
                        $event.stopImmediatePropagation();
 | 
			
		||||
                    }
 | 
			
		||||
                    this.dragInProgress = false;
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            endLineResize(item, updates) {
 | 
			
		||||
            endDrag(item, updates) {
 | 
			
		||||
                this.dragInProgress = true;
 | 
			
		||||
                setTimeout(function () {
 | 
			
		||||
                    this.dragInProgress = false;
 | 
			
		||||
                }.bind(this), 0);
 | 
			
		||||
 | 
			
		||||
                let index = this.layoutItems.indexOf(item);
 | 
			
		||||
                Object.assign(item, updates);
 | 
			
		||||
                this.mutate(`configuration.items[${index}]`, item);
 | 
			
		||||
            },
 | 
			
		||||
            endResize(scaleWidth, scaleHeight, marqueeStart, marqueeOffset) {
 | 
			
		||||
                this.dragInProgress = true;
 | 
			
		||||
                this.layoutItems.forEach(item => {
 | 
			
		||||
                    if (this.itemIsInCurrentSelection(item)) {
 | 
			
		||||
                        let itemXInMarqueeSpace = item.x - marqueeStart.x;
 | 
			
		||||
                        let itemXInMarqueeSpaceAfterScale = Math.round(itemXInMarqueeSpace * scaleWidth);
 | 
			
		||||
                        item.x = itemXInMarqueeSpaceAfterScale + marqueeOffset.x + marqueeStart.x;
 | 
			
		||||
 | 
			
		||||
                        let itemYInMarqueeSpace = item.y - marqueeStart.y;
 | 
			
		||||
                        let itemYInMarqueeSpaceAfterScale = Math.round(itemYInMarqueeSpace * scaleHeight);
 | 
			
		||||
                        item.y = itemYInMarqueeSpaceAfterScale + marqueeOffset.y + marqueeStart.y;
 | 
			
		||||
 | 
			
		||||
                        if (item.x2) {
 | 
			
		||||
                            let itemX2InMarqueeSpace = item.x2 - marqueeStart.x;
 | 
			
		||||
                            let itemX2InMarqueeSpaceAfterScale = Math.round(itemX2InMarqueeSpace * scaleWidth);
 | 
			
		||||
                            item.x2 = itemX2InMarqueeSpaceAfterScale + marqueeOffset.x + marqueeStart.x;
 | 
			
		||||
                        } else {
 | 
			
		||||
                            item.width = Math.round(item.width * scaleWidth);
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        if (item.y2) {
 | 
			
		||||
                            let itemY2InMarqueeSpace = item.y2 - marqueeStart.y;
 | 
			
		||||
                            let itemY2InMarqueeSpaceAfterScale = Math.round(itemY2InMarqueeSpace * scaleHeight);
 | 
			
		||||
                            item.y2 = itemY2InMarqueeSpaceAfterScale + marqueeOffset.y + marqueeStart.y;
 | 
			
		||||
                        } else {
 | 
			
		||||
                            item.height = Math.round(item.height * scaleHeight);
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                });
 | 
			
		||||
                this.mutate("configuration.items", this.layoutItems);
 | 
			
		||||
            },
 | 
			
		||||
            move(gridDelta) {
 | 
			
		||||
                this.dragInProgress = true;
 | 
			
		||||
 | 
			
		||||
                if (!this.initialPositions) {
 | 
			
		||||
                    this.initialPositions = {};
 | 
			
		||||
                    _.cloneDeep(this.selectedLayoutItems).forEach(selectedItem => {
 | 
			
		||||
                        if (selectedItem.type === 'line-view') {
 | 
			
		||||
                            this.initialPositions[selectedItem.id] = [selectedItem.x, selectedItem.y, selectedItem.x2, selectedItem.y2];
 | 
			
		||||
                            this.startingMinX2 = this.startingMinX2 !== undefined ? Math.min(this.startingMinX2, selectedItem.x2) : selectedItem.x2;
 | 
			
		||||
                            this.startingMinY2 = this.startingMinY2 !== undefined ? Math.min(this.startingMinY2, selectedItem.y2) : selectedItem.y2;
 | 
			
		||||
                        } else {
 | 
			
		||||
                            this.initialPositions[selectedItem.id] = [selectedItem.x, selectedItem.y];
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        this.startingMinX = this.startingMinX !== undefined ? Math.min(this.startingMinX, selectedItem.x) : selectedItem.x;
 | 
			
		||||
                        this.startingMinY = this.startingMinY !== undefined ? Math.min(this.startingMinY, selectedItem.y) : selectedItem.y;
 | 
			
		||||
                    });
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                let layoutItems = this.layoutItems.map(item => {
 | 
			
		||||
                    if (this.initialPositions[item.id]) {
 | 
			
		||||
                        this.updateItemPosition(item, gridDelta);
 | 
			
		||||
                    }
 | 
			
		||||
                    return item;
 | 
			
		||||
                });
 | 
			
		||||
            },
 | 
			
		||||
            updateItemPosition(item, gridDelta) {
 | 
			
		||||
                let startingPosition = this.initialPositions[item.id];
 | 
			
		||||
                let [startingX, startingY, startingX2, startingY2] = startingPosition;
 | 
			
		||||
 | 
			
		||||
                if (this.startingMinX + gridDelta[0] >= 0) {
 | 
			
		||||
                    if (item.x2 !== undefined) {
 | 
			
		||||
                        if (this.startingMinX2 + gridDelta[0] >= 0) {
 | 
			
		||||
                            item.x = startingX + gridDelta[0];
 | 
			
		||||
                        }
 | 
			
		||||
                    } else {
 | 
			
		||||
                        item.x = startingX + gridDelta[0];
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (this.startingMinY + gridDelta[1] >= 0) {
 | 
			
		||||
                    if (item.y2 !== undefined) {
 | 
			
		||||
                        if (this.startingMinY2 + gridDelta[1] >= 0) {
 | 
			
		||||
                            item.y = startingY + gridDelta[1];
 | 
			
		||||
                        }
 | 
			
		||||
                    } else {
 | 
			
		||||
                        item.y = startingY + gridDelta[1];
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (item.x2 !== undefined && this.startingMinX2 + gridDelta[0] >= 0 && this.startingMinX + gridDelta[0] >= 0) {
 | 
			
		||||
                    item.x2 = startingX2 + gridDelta[0];
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (item.y2 !== undefined && this.startingMinY2 + gridDelta[1] >= 0 && this.startingMinY + gridDelta[1] >= 0) {
 | 
			
		||||
                    item.y2 = startingY2 + gridDelta[1];
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            endMove() {
 | 
			
		||||
                this.mutate('configuration.items', this.layoutItems);
 | 
			
		||||
                this.initialPositions = undefined;
 | 
			
		||||
                this.startingMinX = undefined;
 | 
			
		||||
                this.startingMinY = undefined;
 | 
			
		||||
                this.startingMinX2 = undefined;
 | 
			
		||||
                this.startingMinY2 = undefined;
 | 
			
		||||
            },
 | 
			
		||||
            mutate(path, value) {
 | 
			
		||||
                this.openmct.objects.mutate(this.internalDomainObject, path, value);
 | 
			
		||||
            },
 | 
			
		||||
@@ -385,8 +283,9 @@
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            isTelemetry(domainObject) {
 | 
			
		||||
                if (this.openmct.telemetry.isTelemetryObject(domainObject) && 
 | 
			
		||||
                    !this.options.showAsView.includes(domainObject.type)) {
 | 
			
		||||
                if (this.openmct.telemetry.isTelemetryObject(domainObject)
 | 
			
		||||
                    && domainObject.type !== 'summary-widget'
 | 
			
		||||
                    && domainObject.type !== 'example.imagery') {
 | 
			
		||||
                    return true;
 | 
			
		||||
                } else {
 | 
			
		||||
                    return false;
 | 
			
		||||
@@ -415,15 +314,11 @@
 | 
			
		||||
                    this.objectViewMap[keyString] = true;
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            removeItem(selectedItems) {
 | 
			
		||||
                let indices = [];
 | 
			
		||||
            removeItem(item, index) {
 | 
			
		||||
                this.initSelectIndex = -1;
 | 
			
		||||
                selectedItems.forEach(selectedItem => {
 | 
			
		||||
                    indices.push(selectedItem[0].context.index);
 | 
			
		||||
                    this.untrackItem(selectedItem[0].context.layoutItem);
 | 
			
		||||
                });
 | 
			
		||||
                _.pullAt(this.layoutItems, indices);
 | 
			
		||||
                this.layoutItems.splice(index, 1);
 | 
			
		||||
                this.mutate("configuration.items", this.layoutItems);
 | 
			
		||||
                this.untrackItem(item);
 | 
			
		||||
                this.$el.click();
 | 
			
		||||
            },
 | 
			
		||||
            untrackItem(item) {
 | 
			
		||||
@@ -489,80 +384,21 @@
 | 
			
		||||
                this.mutate("configuration.items", layoutItems);
 | 
			
		||||
                this.$el.click();
 | 
			
		||||
            },
 | 
			
		||||
            orderItem(position, selectedItems) {
 | 
			
		||||
            orderItem(position, index) {
 | 
			
		||||
                let delta = ORDERS[position];
 | 
			
		||||
                let indices = [];
 | 
			
		||||
                let newIndex = -1;
 | 
			
		||||
                let items = [];
 | 
			
		||||
                let newIndex = Math.max(Math.min(index + delta, this.layoutItems.length - 1), 0);
 | 
			
		||||
                let item = this.layoutItems[index];
 | 
			
		||||
 | 
			
		||||
                Object.assign(items, this.layoutItems);
 | 
			
		||||
                this.selectedLayoutItems.forEach(selectedItem => {
 | 
			
		||||
                    indices.push(this.layoutItems.indexOf(selectedItem));
 | 
			
		||||
                });
 | 
			
		||||
                indices.sort((a, b) => a - b);
 | 
			
		||||
                if (newIndex !== index) {
 | 
			
		||||
                    this.layoutItems.splice(index, 1);
 | 
			
		||||
                    this.layoutItems.splice(newIndex, 0, item);
 | 
			
		||||
                    this.mutate('configuration.items', this.layoutItems);
 | 
			
		||||
 | 
			
		||||
                if (position === 'top' || position === 'up') {
 | 
			
		||||
                    indices.reverse();
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (position === 'top' || position === 'bottom') {
 | 
			
		||||
                    this.moveToTopOrBottom(position, indices, items, delta);
 | 
			
		||||
                } else {
 | 
			
		||||
                    this.moveUpOrDown(position, indices, items, delta);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                this.mutate('configuration.items', this.layoutItems);
 | 
			
		||||
            },
 | 
			
		||||
            moveUpOrDown(position, indices, items, delta) {
 | 
			
		||||
                let previousItemIndex = -1;
 | 
			
		||||
                let newIndex = -1;
 | 
			
		||||
 | 
			
		||||
                indices.forEach((itemIndex, index) => {
 | 
			
		||||
                    let isAdjacentItemSelected = position === 'up' ?
 | 
			
		||||
                        itemIndex + 1 === previousItemIndex :
 | 
			
		||||
                        itemIndex - 1 === previousItemIndex;
 | 
			
		||||
 | 
			
		||||
                    if (index > 0 && isAdjacentItemSelected) {
 | 
			
		||||
                        if (position === 'up') {
 | 
			
		||||
                            newIndex -= 1;
 | 
			
		||||
                        } else {
 | 
			
		||||
                            newIndex += 1;
 | 
			
		||||
                        }
 | 
			
		||||
                    } else {
 | 
			
		||||
                        newIndex = Math.max(Math.min(itemIndex + delta, this.layoutItems.length - 1), 0);
 | 
			
		||||
                    if (this.removeSelectionListener) {
 | 
			
		||||
                        this.removeSelectionListener();
 | 
			
		||||
                        this.attachSelectionListener(newIndex);
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    previousItemIndex = itemIndex;
 | 
			
		||||
                    this.updateItemOrder(newIndex, itemIndex, items);
 | 
			
		||||
                });
 | 
			
		||||
            },
 | 
			
		||||
            moveToTopOrBottom(position, indices, items, delta) {
 | 
			
		||||
                let newIndex = -1;
 | 
			
		||||
 | 
			
		||||
                indices.forEach((itemIndex, index) => {
 | 
			
		||||
                    if (index === 0) {
 | 
			
		||||
                        newIndex = Math.max(Math.min(itemIndex + delta, this.layoutItems.length - 1), 0);
 | 
			
		||||
                    } else {
 | 
			
		||||
                        if (position === 'top') {
 | 
			
		||||
                            newIndex -= 1;
 | 
			
		||||
                        } else {
 | 
			
		||||
                            newIndex += 1;
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    this.updateItemOrder(newIndex, itemIndex, items);
 | 
			
		||||
                });
 | 
			
		||||
            },
 | 
			
		||||
            updateItemOrder(newIndex, itemIndex, items) {
 | 
			
		||||
                if (newIndex !== itemIndex) {
 | 
			
		||||
                    this.layoutItems.splice(itemIndex, 1);
 | 
			
		||||
                    this.layoutItems.splice(newIndex, 0, items[itemIndex]);
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            updateTelemetryFormat(item, format) {
 | 
			
		||||
                let index = _.findIndex(this.layoutItems, item);
 | 
			
		||||
                item.format = format;
 | 
			
		||||
                this.mutate(`configuration.items[${index}]`, item);
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        mounted() {
 | 
			
		||||
@@ -577,10 +413,14 @@
 | 
			
		||||
            this.composition.load();
 | 
			
		||||
        },
 | 
			
		||||
        destroyed: function () {
 | 
			
		||||
            this.openmct.selection.off('change', this.setSelection);
 | 
			
		||||
            this.openmct.off('change', this.setSelection);
 | 
			
		||||
            this.composition.off('add', this.addChild);
 | 
			
		||||
            this.composition.off('remove', this.removeChild);
 | 
			
		||||
            this.unlisten();
 | 
			
		||||
 | 
			
		||||
            if (this.removeSelectionListener) {
 | 
			
		||||
                this.removeSelectionListener();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
</script>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,233 +0,0 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT, Copyright (c) 2014-2018, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
        <!-- Resize handles -->
 | 
			
		||||
        <div class="c-frame-edit" :style="style">
 | 
			
		||||
            <div class="c-frame-edit__handle c-frame-edit__handle--nw"
 | 
			
		||||
                 @mousedown="startResize([1,1], [-1,-1], $event)"></div>
 | 
			
		||||
            <div class="c-frame-edit__handle c-frame-edit__handle--ne"
 | 
			
		||||
                 @mousedown="startResize([0,1], [1,-1], $event)"></div>
 | 
			
		||||
            <div class="c-frame-edit__handle c-frame-edit__handle--sw"
 | 
			
		||||
                 @mousedown="startResize([1,0], [-1,1], $event)"></div>
 | 
			
		||||
            <div class="c-frame-edit__handle c-frame-edit__handle--se"
 | 
			
		||||
                 @mousedown="startResize([0,0], [1,1], $event)"></div>
 | 
			
		||||
        </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<style lang="scss">
 | 
			
		||||
    @import "~styles/sass-base";
 | 
			
		||||
 | 
			
		||||
    .c-frame-edit {
 | 
			
		||||
        // In Layouts, this is the editing rect and handles
 | 
			
		||||
        display: none; // Set to display: block in DisplayLayout.vue
 | 
			
		||||
        pointer-events: none;
 | 
			
		||||
        @include abs();
 | 
			
		||||
        border: $editMarqueeBorder;
 | 
			
		||||
 | 
			
		||||
        &__handle {
 | 
			
		||||
            $d: 6px;
 | 
			
		||||
            $o: floor($d * -0.5);
 | 
			
		||||
            background: $editFrameColorHandleFg;
 | 
			
		||||
            box-shadow: $editFrameColorHandleBg 0 0 0 2px;
 | 
			
		||||
            pointer-events: all;
 | 
			
		||||
            position: absolute;
 | 
			
		||||
            width: $d; height: $d;
 | 
			
		||||
            top: auto; right: auto; bottom: auto; left: auto;
 | 
			
		||||
 | 
			
		||||
            &:before {
 | 
			
		||||
                // Extended hit area
 | 
			
		||||
                @include abs(-10px);
 | 
			
		||||
                content: '';
 | 
			
		||||
                display: block;
 | 
			
		||||
                z-index: 0;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            &:hover {
 | 
			
		||||
                background: $editUIColor;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            &--nwse {
 | 
			
		||||
                cursor: nwse-resize;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            &--nw {
 | 
			
		||||
                cursor: nw-resize;
 | 
			
		||||
                left: $o; top: $o;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            &--ne {
 | 
			
		||||
                cursor: ne-resize;
 | 
			
		||||
                right: $o; top: $o;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            &--se {
 | 
			
		||||
                cursor: se-resize;
 | 
			
		||||
                right: $o; bottom: $o;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            &--sw {
 | 
			
		||||
                cursor: sw-resize;
 | 
			
		||||
                left: $o; bottom: $o;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
</style>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
    import LayoutDrag from './../LayoutDrag'
 | 
			
		||||
 | 
			
		||||
    export default {
 | 
			
		||||
        inject: ['openmct'],
 | 
			
		||||
        props: {
 | 
			
		||||
            selectedLayoutItems: Array,
 | 
			
		||||
            gridSize: Array
 | 
			
		||||
        },        
 | 
			
		||||
        data() {
 | 
			
		||||
            return {
 | 
			
		||||
                dragPosition: undefined
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        computed: {
 | 
			
		||||
            style() {
 | 
			
		||||
                let x = Number.POSITIVE_INFINITY;
 | 
			
		||||
                let y = Number.POSITIVE_INFINITY;
 | 
			
		||||
                let width = Number.NEGATIVE_INFINITY;
 | 
			
		||||
                let height = Number.NEGATIVE_INFINITY;
 | 
			
		||||
 | 
			
		||||
                this.selectedLayoutItems.forEach(item => {
 | 
			
		||||
                    if (item.x2 !== undefined) {
 | 
			
		||||
                        let lineWidth = Math.abs(item.x - item.x2);
 | 
			
		||||
                        let lineMinX = Math.min(item.x, item.x2);
 | 
			
		||||
                        x = Math.min(lineMinX, x);
 | 
			
		||||
                        width = Math.max(lineWidth + lineMinX, width);
 | 
			
		||||
                    } else {
 | 
			
		||||
                        x = Math.min(item.x, x);
 | 
			
		||||
                        width = Math.max(item.width + item.x, width);
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    if (item.y2 !== undefined) {
 | 
			
		||||
                        let lineHeight = Math.abs(item.y - item.y2);
 | 
			
		||||
                        let lineMinY = Math.min(item.y, item.y2);
 | 
			
		||||
                        y = Math.min(lineMinY, y);
 | 
			
		||||
                        height = Math.max(lineHeight + lineMinY, height);
 | 
			
		||||
                    } else {
 | 
			
		||||
                        y = Math.min(item.y, y);
 | 
			
		||||
                        height = Math.max(item.height + item.y, height);
 | 
			
		||||
                    }
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                if (this.dragPosition) {
 | 
			
		||||
                    [x, y] = this.dragPosition.position;
 | 
			
		||||
                    [width, height] = this.dragPosition.dimensions;
 | 
			
		||||
                } else {
 | 
			
		||||
                    width = width - x;
 | 
			
		||||
                    height = height - y;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                this.marqueePosition = {
 | 
			
		||||
                    x: x,
 | 
			
		||||
                    y: y,
 | 
			
		||||
                    width: width,
 | 
			
		||||
                    height: height
 | 
			
		||||
                }
 | 
			
		||||
                return this.getMarqueeStyle(x, y, width, height);
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        methods: {
 | 
			
		||||
            getMarqueeStyle(x, y, width, height) {
 | 
			
		||||
                return {
 | 
			
		||||
                    left: (this.gridSize[0] * x) + 'px',
 | 
			
		||||
                    top: (this.gridSize[1] * y) + 'px',
 | 
			
		||||
                    width: (this.gridSize[0] * width) + 'px',
 | 
			
		||||
                    height: (this.gridSize[1] * height) + 'px'
 | 
			
		||||
                };
 | 
			
		||||
            },
 | 
			
		||||
            updatePosition(event) {
 | 
			
		||||
                let currentPosition = [event.pageX, event.pageY];
 | 
			
		||||
                this.initialPosition = this.initialPosition || currentPosition;
 | 
			
		||||
                this.delta = currentPosition.map(function (value, index) {
 | 
			
		||||
                    return value - this.initialPosition[index];
 | 
			
		||||
                }.bind(this));
 | 
			
		||||
            },
 | 
			
		||||
            startResize(posFactor, dimFactor, event) {
 | 
			
		||||
                document.body.addEventListener('mousemove', this.continueResize);
 | 
			
		||||
                document.body.addEventListener('mouseup', this.endResize);
 | 
			
		||||
                this.marqueeStartPosition = {
 | 
			
		||||
                    position: [this.marqueePosition.x, this.marqueePosition.y],
 | 
			
		||||
                    dimensions: [this.marqueePosition.width, this.marqueePosition.height]
 | 
			
		||||
                };
 | 
			
		||||
                this.updatePosition(event);
 | 
			
		||||
                this.activeDrag = new LayoutDrag(this.marqueeStartPosition, posFactor, dimFactor, this.gridSize);
 | 
			
		||||
                event.preventDefault();
 | 
			
		||||
            },
 | 
			
		||||
            continueResize(event) {
 | 
			
		||||
                event.preventDefault();
 | 
			
		||||
                this.updatePosition(event);
 | 
			
		||||
                this.dragPosition = this.activeDrag.getAdjustedPositionAndDimensions(this.delta);
 | 
			
		||||
            },
 | 
			
		||||
            endResize(event) {
 | 
			
		||||
                document.body.removeEventListener('mousemove', this.continueResize);
 | 
			
		||||
                document.body.removeEventListener('mouseup', this.endResize);
 | 
			
		||||
                this.continueResize(event);
 | 
			
		||||
 | 
			
		||||
                let marqueeStartWidth = this.marqueeStartPosition.dimensions[0];
 | 
			
		||||
                let marqueeStartHeight = this.marqueeStartPosition.dimensions[1];
 | 
			
		||||
                let marqueeStartX = this.marqueeStartPosition.position[0];
 | 
			
		||||
                let marqueeStartY = this.marqueeStartPosition.position[1];
 | 
			
		||||
 | 
			
		||||
                let marqueeEndX = this.dragPosition.position[0];
 | 
			
		||||
                let marqueeEndY = this.dragPosition.position[1];
 | 
			
		||||
                let marqueeEndWidth = this.dragPosition.dimensions[0];
 | 
			
		||||
                let marqueeEndHeight = this.dragPosition.dimensions[1];
 | 
			
		||||
 | 
			
		||||
                let scaleWidth =  marqueeEndWidth / marqueeStartWidth;
 | 
			
		||||
                let scaleHeight =  marqueeEndHeight / marqueeStartHeight;
 | 
			
		||||
 | 
			
		||||
                let marqueeStart = {
 | 
			
		||||
                    x: marqueeStartX,
 | 
			
		||||
                    y: marqueeStartY,
 | 
			
		||||
                    height: marqueeStartWidth,
 | 
			
		||||
                    width: marqueeStartHeight
 | 
			
		||||
                };
 | 
			
		||||
                let marqueeEnd = {
 | 
			
		||||
                    x: marqueeEndX,
 | 
			
		||||
                    y: marqueeEndY,
 | 
			
		||||
                    width: marqueeEndWidth,
 | 
			
		||||
                    height: marqueeEndHeight
 | 
			
		||||
                };
 | 
			
		||||
                let marqueeOffset = {
 | 
			
		||||
                    x: marqueeEnd.x - marqueeStart.x,
 | 
			
		||||
                    y: marqueeEnd.y - marqueeStart.y
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
                this.$emit('endResize', scaleWidth, scaleHeight, marqueeStart, marqueeOffset);
 | 
			
		||||
                this.dragPosition = undefined;
 | 
			
		||||
                this.initialPosition = undefined;
 | 
			
		||||
                this.marqueeStartPosition = undefined;
 | 
			
		||||
                this.delta = undefined;
 | 
			
		||||
                event.preventDefault();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
</script>
 | 
			
		||||
@@ -23,8 +23,7 @@
 | 
			
		||||
<template>
 | 
			
		||||
    <layout-frame :item="item"
 | 
			
		||||
                  :grid-size="gridSize"
 | 
			
		||||
                  @move="(gridDelta) => $emit('move', gridDelta)"
 | 
			
		||||
                  @endMove="() => $emit('endMove')">
 | 
			
		||||
                  @endDrag="(item, updates) => $emit('endDrag', item, updates)">
 | 
			
		||||
        <div class="c-image-view"
 | 
			
		||||
             :style="style">
 | 
			
		||||
        </div>
 | 
			
		||||
@@ -57,7 +56,8 @@
 | 
			
		||||
                y: 1,
 | 
			
		||||
                width: 10,
 | 
			
		||||
                height: 5,
 | 
			
		||||
                url: element.url
 | 
			
		||||
                url: element.url,
 | 
			
		||||
                useGrid: true
 | 
			
		||||
            };
 | 
			
		||||
        },
 | 
			
		||||
        inject: ['openmct'],
 | 
			
		||||
 
 | 
			
		||||
@@ -24,14 +24,25 @@
 | 
			
		||||
    <div class="l-layout__frame c-frame"
 | 
			
		||||
         :class="{
 | 
			
		||||
             'no-frame': !item.hasFrame,
 | 
			
		||||
             'u-inspectable': inspectable
 | 
			
		||||
             'u-inspectable': inspectable,
 | 
			
		||||
             'is-resizing': isResizing
 | 
			
		||||
         }"
 | 
			
		||||
         :style="style">
 | 
			
		||||
 | 
			
		||||
        <slot></slot>
 | 
			
		||||
 | 
			
		||||
        <div class="c-frame-edit__move"
 | 
			
		||||
             @mousedown="startMove([1,1], [0,0], $event)">
 | 
			
		||||
        <!-- Drag handles -->
 | 
			
		||||
        <div class="c-frame-edit">
 | 
			
		||||
            <div class="c-frame-edit__move"
 | 
			
		||||
                 @mousedown="startDrag([1,1], [0,0], $event, 'move')"></div>
 | 
			
		||||
            <div class="c-frame-edit__handle c-frame-edit__handle--nw"
 | 
			
		||||
                 @mousedown="startDrag([1,1], [-1,-1], $event, 'resize')"></div>
 | 
			
		||||
            <div class="c-frame-edit__handle c-frame-edit__handle--ne"
 | 
			
		||||
                 @mousedown="startDrag([0,1], [1,-1], $event, 'resize')"></div>
 | 
			
		||||
            <div class="c-frame-edit__handle c-frame-edit__handle--sw"
 | 
			
		||||
                 @mousedown="startDrag([1,0], [-1,1], $event, 'resize')"></div>
 | 
			
		||||
            <div class="c-frame-edit__handle c-frame-edit__handle--se"
 | 
			
		||||
                 @mousedown="startDrag([0,0], [1,1], $event, 'resize')"></div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
</template>
 | 
			
		||||
@@ -39,7 +50,7 @@
 | 
			
		||||
<style lang="scss">
 | 
			
		||||
    @import "~styles/sass-base";
 | 
			
		||||
 | 
			
		||||
    /******************* FRAME */
 | 
			
		||||
    /******************************* FRAME */
 | 
			
		||||
    .c-frame {
 | 
			
		||||
        display: flex;
 | 
			
		||||
        flex-direction: column;
 | 
			
		||||
@@ -48,15 +59,124 @@
 | 
			
		||||
        > *:first-child {
 | 
			
		||||
            flex: 1 1 auto;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        &:not(.no-frame) {
 | 
			
		||||
            background: $colorBodyBg;
 | 
			
		||||
            border: $browseFrameBorder;
 | 
			
		||||
            padding: $interiorMargin;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .c-frame-edit__move {
 | 
			
		||||
    .c-frame-edit {
 | 
			
		||||
        // In Layouts, this is the editing rect and handles
 | 
			
		||||
        // In Fixed Position, this is a wrapper element
 | 
			
		||||
        @include abs();
 | 
			
		||||
        display: none;
 | 
			
		||||
 | 
			
		||||
        &__move {
 | 
			
		||||
            @include abs();
 | 
			
		||||
            cursor: move;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        &__handle {
 | 
			
		||||
            $d: 6px;
 | 
			
		||||
            $o: floor($d * -0.5);
 | 
			
		||||
            background: $editFrameColorHandleFg;
 | 
			
		||||
            box-shadow: $editFrameColorHandleBg 0 0 0 2px;
 | 
			
		||||
            display: none; // Set to block via s-selected selector
 | 
			
		||||
            position: absolute;
 | 
			
		||||
            width: $d; height: $d;
 | 
			
		||||
            top: auto; right: auto; bottom: auto; left: auto;
 | 
			
		||||
 | 
			
		||||
            &:before {
 | 
			
		||||
                // Extended hit area
 | 
			
		||||
                @include abs(-10px);
 | 
			
		||||
                content: '';
 | 
			
		||||
                display: block;
 | 
			
		||||
                z-index: 0;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            &:hover {
 | 
			
		||||
                background: $editUIColor;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            &--nwse {
 | 
			
		||||
                cursor: nwse-resize;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            &--nw {
 | 
			
		||||
                cursor: nw-resize;
 | 
			
		||||
                left: $o; top: $o;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            &--ne {
 | 
			
		||||
                cursor: ne-resize;
 | 
			
		||||
                right: $o; top: $o;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            &--se {
 | 
			
		||||
                cursor: se-resize;
 | 
			
		||||
                right: $o; bottom: $o;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            &--sw {
 | 
			
		||||
                cursor: sw-resize;
 | 
			
		||||
                left: $o; bottom: $o;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .c-so-view.has-complex-content + .c-frame-edit {
 | 
			
		||||
        // Target frames that hold domain objects that include header elements, as opposed to drawing and alpha objects
 | 
			
		||||
        // Make the __move element a more affordable drag UI element
 | 
			
		||||
        .c-frame-edit__move {
 | 
			
		||||
            @include userSelectNone();
 | 
			
		||||
            background: $editFrameMovebarColorBg;
 | 
			
		||||
            box-shadow: rgba(black, 0.2) 0 1px;
 | 
			
		||||
            bottom: auto;
 | 
			
		||||
            height: 0; // Height is set on hover on s-selected.c-frame
 | 
			
		||||
            opacity: 0.8;
 | 
			
		||||
            max-height: 100%;
 | 
			
		||||
            overflow: hidden;
 | 
			
		||||
            text-align: center;
 | 
			
		||||
 | 
			
		||||
            &:before {
 | 
			
		||||
                // Grippy
 | 
			
		||||
                $h: 4px;
 | 
			
		||||
                $tbOffset: ($editFrameMovebarH - $h) / 2;
 | 
			
		||||
                $lrOffset: 25%;
 | 
			
		||||
                @include grippy($editFrameMovebarColorFg);
 | 
			
		||||
                content: '';
 | 
			
		||||
                display: block;
 | 
			
		||||
                position: absolute;
 | 
			
		||||
                top: $tbOffset; right: $lrOffset; bottom: $tbOffset; left: $lrOffset;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            &:hover {
 | 
			
		||||
                background: $editFrameHovMovebarColorBg;
 | 
			
		||||
                &:before { @include grippy($editFrameHovMovebarColorFg); }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .is-editing {
 | 
			
		||||
        /******************* STYLES FOR C-FRAME WHILE EDITING */
 | 
			
		||||
        .c-frame {
 | 
			
		||||
            $moveBarOutDelay: 500ms;
 | 
			
		||||
            &.no-frame {
 | 
			
		||||
                border: $editFrameBorder; // Base border style for a frame element while editing.
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            &-edit {
 | 
			
		||||
                display: contents;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            &-edit__move,
 | 
			
		||||
            .c-so-view {
 | 
			
		||||
                transition: $transOut;
 | 
			
		||||
                transition-delay: $moveBarOutDelay;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            &:not([s-selected]) {
 | 
			
		||||
                &:hover {
 | 
			
		||||
                    border: $editFrameBorderHov;
 | 
			
		||||
@@ -68,110 +188,37 @@
 | 
			
		||||
                border: $editFrameSelectedBorder;
 | 
			
		||||
                box-shadow: $editFrameSelectedShdw;
 | 
			
		||||
 | 
			
		||||
                .c-frame-edit__move {
 | 
			
		||||
                    cursor: move;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /******************* DEFAULT STYLES FOR -EDIT__MOVE */
 | 
			
		||||
        // All object types
 | 
			
		||||
        .c-frame-edit__move {
 | 
			
		||||
            @include abs();
 | 
			
		||||
            display: block;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Has-complex-content objects
 | 
			
		||||
        .c-so-view.has-complex-content {
 | 
			
		||||
            transition: $transOut;
 | 
			
		||||
            transition-delay: $moveBarOutDelay;
 | 
			
		||||
 | 
			
		||||
            > .c-so-view__local-controls {
 | 
			
		||||
                transition: transform 250ms ease-in-out;
 | 
			
		||||
                transition-delay: $moveBarOutDelay;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            + .c-frame-edit__move {
 | 
			
		||||
                display: none;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .l-layout {
 | 
			
		||||
            /******************* 0 - 1 ITEM SELECTED */
 | 
			
		||||
            &:not(.is-multi-selected) {
 | 
			
		||||
                > .l-layout__frame[s-selected] {
 | 
			
		||||
                    > .c-so-view.has-complex-content {
 | 
			
		||||
                        > .c-so-view__local-controls {
 | 
			
		||||
                            transition: transform $transOutTime ease-in-out;
 | 
			
		||||
                            transition-delay: $moveBarOutDelay;
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        + .c-frame-edit__move {
 | 
			
		||||
                            transition: $transOut;
 | 
			
		||||
                            transition-delay: $moveBarOutDelay;
 | 
			
		||||
                            @include userSelectNone();
 | 
			
		||||
                            background: $editFrameMovebarColorBg;
 | 
			
		||||
                            box-shadow: rgba(black, 0.2) 0 1px;
 | 
			
		||||
                            bottom: auto;
 | 
			
		||||
                            display: block;
 | 
			
		||||
                            height: 0; // Height is set on hover below
 | 
			
		||||
                            opacity: 0.8;
 | 
			
		||||
                            max-height: 100%;
 | 
			
		||||
                            overflow: hidden;
 | 
			
		||||
                            text-align: center;
 | 
			
		||||
 | 
			
		||||
                            &:before {
 | 
			
		||||
                                // Grippy
 | 
			
		||||
                                $h: 4px;
 | 
			
		||||
                                $tbOffset: ($editFrameMovebarH - $h) / 2;
 | 
			
		||||
                                $lrOffset: 25%;
 | 
			
		||||
                                @include grippy($editFrameMovebarColorFg);
 | 
			
		||||
                                content: '';
 | 
			
		||||
                                display: block;
 | 
			
		||||
                                position: absolute;
 | 
			
		||||
                                top: $tbOffset;
 | 
			
		||||
                                right: $lrOffset;
 | 
			
		||||
                                bottom: $tbOffset;
 | 
			
		||||
                                left: $lrOffset;
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    &:hover {
 | 
			
		||||
                        > .c-so-view.has-complex-content {
 | 
			
		||||
                            transition: $transIn;
 | 
			
		||||
                            transition-delay: 0s;
 | 
			
		||||
                            padding-top: $editFrameMovebarH + $interiorMarginSm;
 | 
			
		||||
 | 
			
		||||
                            > .c-so-view__local-controls {
 | 
			
		||||
                                transform: translateY($editFrameMovebarH);
 | 
			
		||||
                                transition: transform $transInTime ease-in-out;
 | 
			
		||||
                                transition-delay: 0s;
 | 
			
		||||
                            }
 | 
			
		||||
 | 
			
		||||
                            + .c-frame-edit__move {
 | 
			
		||||
                                transition: $transIn;
 | 
			
		||||
                                transition-delay: 0s;
 | 
			
		||||
                                height: $editFrameMovebarH;
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            /******************* > 1 ITEMS SELECTED */
 | 
			
		||||
            &.is-multi-selected {
 | 
			
		||||
                .l-layout__frame[s-selected] {
 | 
			
		||||
                    > .c-so-view.has-complex-content + .c-frame-edit__move {
 | 
			
		||||
                > .c-frame-edit {
 | 
			
		||||
                    [class*='__handle'] {
 | 
			
		||||
                        display: block;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .l-layout__frame:not(.is-resizing) {
 | 
			
		||||
            // Show and animate the __move bar for sub-object views with complex content
 | 
			
		||||
            &:hover > .c-so-view.has-complex-content {
 | 
			
		||||
                // Move content down so the __move bar doesn't cover it.
 | 
			
		||||
                padding-top: $editFrameMovebarH;
 | 
			
		||||
                transition: $transIn;
 | 
			
		||||
 | 
			
		||||
                &.c-so-view--no-frame {
 | 
			
		||||
                    // Move content down with a bit more space
 | 
			
		||||
                    padding-top: $editFrameMovebarH + $interiorMarginSm;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // Show the move bar
 | 
			
		||||
                + .c-frame-edit .c-frame-edit__move {
 | 
			
		||||
                    height: $editFrameMovebarH;
 | 
			
		||||
                    transition: $transIn;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
</style>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
    import LayoutDrag from './../LayoutDrag'
 | 
			
		||||
 | 
			
		||||
@@ -181,9 +228,21 @@
 | 
			
		||||
            item: Object,
 | 
			
		||||
            gridSize: Array
 | 
			
		||||
        },
 | 
			
		||||
        data() {
 | 
			
		||||
            return {
 | 
			
		||||
                dragPosition: undefined,
 | 
			
		||||
                isResizing: undefined
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        computed: {
 | 
			
		||||
            style() {
 | 
			
		||||
                let {x, y, width, height} = this.item;
 | 
			
		||||
 | 
			
		||||
                if (this.dragPosition) {
 | 
			
		||||
                    [x, y] = this.dragPosition.position;
 | 
			
		||||
                    [width, height] = this.dragPosition.dimensions;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                return {
 | 
			
		||||
                    left: (this.gridSize[0] * x) + 'px',
 | 
			
		||||
                    top: (this.gridSize[1] * y) + 'px',
 | 
			
		||||
@@ -205,40 +264,36 @@
 | 
			
		||||
                    return value - this.initialPosition[index];
 | 
			
		||||
                }.bind(this));
 | 
			
		||||
            },
 | 
			
		||||
            startMove(posFactor, dimFactor, event) {
 | 
			
		||||
                document.body.addEventListener('mousemove', this.continueMove);
 | 
			
		||||
                document.body.addEventListener('mouseup', this.endMove);
 | 
			
		||||
            startDrag(posFactor, dimFactor, event, type) {
 | 
			
		||||
                document.body.addEventListener('mousemove', this.continueDrag);
 | 
			
		||||
                document.body.addEventListener('mouseup', this.endDrag);
 | 
			
		||||
 | 
			
		||||
                this.dragPosition = {
 | 
			
		||||
                    position: [this.item.x, this.item.y]
 | 
			
		||||
                    position: [this.item.x, this.item.y],
 | 
			
		||||
                    dimensions: [this.item.width, this.item.height]
 | 
			
		||||
                };
 | 
			
		||||
                this.updatePosition(event);
 | 
			
		||||
                this.activeDrag = new LayoutDrag(this.dragPosition, posFactor, dimFactor, this.gridSize);
 | 
			
		||||
                this.isResizing = type === 'resize';
 | 
			
		||||
                event.preventDefault();
 | 
			
		||||
            },
 | 
			
		||||
            continueMove(event) {
 | 
			
		||||
            continueDrag(event) {
 | 
			
		||||
                event.preventDefault();
 | 
			
		||||
                this.updatePosition(event);
 | 
			
		||||
                let newPosition = this.activeDrag.getAdjustedPosition(this.delta);
 | 
			
		||||
 | 
			
		||||
                if (!_.isEqual(newPosition, this.dragPosition)) {
 | 
			
		||||
                    this.dragPosition = newPosition;
 | 
			
		||||
                    this.$emit('move', this.toGridDelta(this.delta));
 | 
			
		||||
                }
 | 
			
		||||
                this.dragPosition = this.activeDrag.getAdjustedPosition(this.delta);
 | 
			
		||||
            },
 | 
			
		||||
            endMove(event) {
 | 
			
		||||
                document.body.removeEventListener('mousemove', this.continueMove);
 | 
			
		||||
                document.body.removeEventListener('mouseup', this.endMove);
 | 
			
		||||
                this.continueMove(event);
 | 
			
		||||
                this.$emit('endMove');
 | 
			
		||||
            endDrag(event) {
 | 
			
		||||
                document.body.removeEventListener('mousemove', this.continueDrag);
 | 
			
		||||
                document.body.removeEventListener('mouseup', this.endDrag);
 | 
			
		||||
                this.continueDrag(event);
 | 
			
		||||
                let [x, y] = this.dragPosition.position;
 | 
			
		||||
                let [width, height] = this.dragPosition.dimensions;
 | 
			
		||||
                this.$emit('endDrag', this.item, {x, y, width, height});
 | 
			
		||||
                this.dragPosition = undefined;
 | 
			
		||||
                this.initialPosition = undefined;
 | 
			
		||||
                this.delta = undefined;
 | 
			
		||||
                this.isResizing = undefined;
 | 
			
		||||
                event.preventDefault();
 | 
			
		||||
            },
 | 
			
		||||
            toGridDelta(pixelDelta) {
 | 
			
		||||
                return pixelDelta.map((v, i) => {
 | 
			
		||||
                    return Math.round(v / this.gridSize[i]);
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -30,9 +30,9 @@
 | 
			
		||||
            </line>
 | 
			
		||||
        </svg>
 | 
			
		||||
 | 
			
		||||
        <div class="c-frame-edit__move"
 | 
			
		||||
             @mousedown="startDrag($event)"></div>
 | 
			
		||||
        <div class="c-frame-edit" v-if="showFrameEdit">
 | 
			
		||||
        <div class="c-frame-edit">
 | 
			
		||||
            <div class="c-frame-edit__move"
 | 
			
		||||
                 @mousedown="startDrag($event)"></div>
 | 
			
		||||
            <div class="c-frame-edit__handle"
 | 
			
		||||
                 :class="startHandleClass"
 | 
			
		||||
                 @mousedown="startDrag($event, 'start')"></div>
 | 
			
		||||
@@ -66,7 +66,8 @@
 | 
			
		||||
                y: 10,
 | 
			
		||||
                x2: 10,
 | 
			
		||||
                y2: 5,
 | 
			
		||||
                stroke: '#717171'
 | 
			
		||||
                stroke: '#717171',
 | 
			
		||||
                useGrid: true
 | 
			
		||||
            };
 | 
			
		||||
        },
 | 
			
		||||
        inject: ['openmct'],
 | 
			
		||||
@@ -75,31 +76,24 @@
 | 
			
		||||
            gridSize: Array,
 | 
			
		||||
            initSelect: Boolean,
 | 
			
		||||
            index: Number,
 | 
			
		||||
            multiSelect: Boolean
 | 
			
		||||
        },
 | 
			
		||||
        data() {
 | 
			
		||||
            return {
 | 
			
		||||
                dragPosition: undefined,
 | 
			
		||||
                dragging: undefined,
 | 
			
		||||
                selection: []
 | 
			
		||||
                dragPosition: undefined
 | 
			
		||||
            };
 | 
			
		||||
        },
 | 
			
		||||
        computed: {
 | 
			
		||||
            showFrameEdit() {
 | 
			
		||||
                let layoutItem = this.selection.length > 0 && this.selection[0][0].context.layoutItem;
 | 
			
		||||
                return !this.multiSelect && layoutItem && layoutItem.id === this.item.id;
 | 
			
		||||
            },
 | 
			
		||||
            position() {
 | 
			
		||||
                let {x, y, x2, y2} = this.item;
 | 
			
		||||
                if (this.dragging && this.dragPosition) {
 | 
			
		||||
                if (this.dragPosition) {
 | 
			
		||||
                    ({x, y, x2, y2} = this.dragPosition);
 | 
			
		||||
                }
 | 
			
		||||
                return {x, y, x2, y2};
 | 
			
		||||
            },
 | 
			
		||||
            style() {
 | 
			
		||||
                let {x, y, x2, y2} = this.position;
 | 
			
		||||
                let width = Math.max(this.gridSize[0] * Math.abs(x - x2), 1);
 | 
			
		||||
                let height = Math.max(this.gridSize[1] * Math.abs(y - y2), 1);
 | 
			
		||||
                let width = this.gridSize[0] * Math.abs(x - x2);
 | 
			
		||||
                let height = this.gridSize[1] * Math.abs(y - y2);
 | 
			
		||||
                let left = this.gridSize[0] * Math.min(x, x2);
 | 
			
		||||
                let top = this.gridSize[1] * Math.min(y, y2);
 | 
			
		||||
                return {
 | 
			
		||||
@@ -181,27 +175,13 @@
 | 
			
		||||
                event.preventDefault();
 | 
			
		||||
                let pxDeltaX = this.startPosition[0] - event.pageX;
 | 
			
		||||
                let pxDeltaY = this.startPosition[1] - event.pageY;
 | 
			
		||||
                let newPosition = this.calculateDragPosition(pxDeltaX, pxDeltaY);
 | 
			
		||||
 | 
			
		||||
                if (!this.dragging) {
 | 
			
		||||
                    if (!_.isEqual(newPosition, this.dragPosition)) {
 | 
			
		||||
                        let gridDelta = [event.pageX - this.startPosition[0], event.pageY - this.startPosition[1]];
 | 
			
		||||
                        this.dragPosition = newPosition;
 | 
			
		||||
                        this.$emit('move', this.toGridDelta(gridDelta));
 | 
			
		||||
                    }
 | 
			
		||||
                } else {
 | 
			
		||||
                    this.dragPosition = newPosition;
 | 
			
		||||
                }
 | 
			
		||||
                this.dragPosition = this.calculateDragPosition(pxDeltaX, pxDeltaY);
 | 
			
		||||
            },
 | 
			
		||||
            endDrag(event) {
 | 
			
		||||
                document.body.removeEventListener('mousemove', this.continueDrag);
 | 
			
		||||
                document.body.removeEventListener('mouseup', this.endDrag);
 | 
			
		||||
                let {x, y, x2, y2} = this.dragPosition;
 | 
			
		||||
                if (!this.dragging) {
 | 
			
		||||
                    this.$emit('endMove');
 | 
			
		||||
                } else {
 | 
			
		||||
                    this.$emit('endLineResize', this.item, {x, y, x2, y2});
 | 
			
		||||
                }
 | 
			
		||||
                this.$emit('endDrag', this.item, {x, y, x2, y2});
 | 
			
		||||
                this.dragPosition = undefined;
 | 
			
		||||
                this.dragging = undefined;
 | 
			
		||||
                event.preventDefault();
 | 
			
		||||
@@ -211,7 +191,6 @@
 | 
			
		||||
                let gridDeltaY = Math.round(pxDeltaY / this.gridSize[0]); // TODO: should this be gridSize[1]?
 | 
			
		||||
                let {x, y, x2, y2} = this.item;
 | 
			
		||||
                let dragPosition = {x, y, x2, y2};
 | 
			
		||||
 | 
			
		||||
                if (this.dragging === 'start') {
 | 
			
		||||
                    dragPosition.x -= gridDeltaX;
 | 
			
		||||
                    dragPosition.y -= gridDeltaY;
 | 
			
		||||
@@ -226,14 +205,6 @@
 | 
			
		||||
                    dragPosition.y2 -= gridDeltaY;
 | 
			
		||||
                }
 | 
			
		||||
                return dragPosition;
 | 
			
		||||
            },
 | 
			
		||||
            setSelection(selection) {
 | 
			
		||||
                this.selection = selection;
 | 
			
		||||
            },
 | 
			
		||||
            toGridDelta(pixelDelta) {
 | 
			
		||||
                return pixelDelta.map((v, i) => {
 | 
			
		||||
                    return Math.round(v / this.gridSize[i]);
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        watch: {
 | 
			
		||||
@@ -246,7 +217,6 @@
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        mounted() {
 | 
			
		||||
            this.openmct.selection.on('change', this.setSelection);
 | 
			
		||||
            this.context = {
 | 
			
		||||
                layoutItem: this.item,
 | 
			
		||||
                index: this.index
 | 
			
		||||
@@ -258,7 +228,6 @@
 | 
			
		||||
            if (this.removeSelectable) {
 | 
			
		||||
                this.removeSelectable();
 | 
			
		||||
            }
 | 
			
		||||
            this.openmct.selection.off('change', this.setSelection);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 </script>
 | 
			
		||||
 
 | 
			
		||||
@@ -22,12 +22,10 @@
 | 
			
		||||
<template>
 | 
			
		||||
    <layout-frame :item="item"
 | 
			
		||||
                  :grid-size="gridSize"
 | 
			
		||||
                  :title="domainObject && domainObject.name"
 | 
			
		||||
                  @move="(gridDelta) => $emit('move', gridDelta)"
 | 
			
		||||
                  @endMove="() => $emit('endMove')">
 | 
			
		||||
                  @endDrag="(item, updates) => $emit('endDrag', item, updates)">
 | 
			
		||||
        <object-frame v-if="domainObject"
 | 
			
		||||
                      :domain-object="domainObject"
 | 
			
		||||
                      :object-path="currentObjectPath"
 | 
			
		||||
                      :object-path="objectPath"
 | 
			
		||||
                      :has-frame="item.hasFrame"
 | 
			
		||||
                      :show-edit-view="false"
 | 
			
		||||
                      ref="objectFrame">
 | 
			
		||||
@@ -68,10 +66,11 @@
 | 
			
		||||
                x: position[0],
 | 
			
		||||
                y: position[1],
 | 
			
		||||
                identifier: domainObject.identifier,
 | 
			
		||||
                hasFrame: hasFrameByDefault(domainObject.type)
 | 
			
		||||
                hasFrame: hasFrameByDefault(domainObject.type),
 | 
			
		||||
                useGrid: true
 | 
			
		||||
            };
 | 
			
		||||
        },
 | 
			
		||||
        inject: ['openmct', 'objectPath'],
 | 
			
		||||
        inject: ['openmct'],
 | 
			
		||||
        props: {
 | 
			
		||||
            item: Object,
 | 
			
		||||
            gridSize: Array,
 | 
			
		||||
@@ -81,7 +80,7 @@
 | 
			
		||||
        data() {
 | 
			
		||||
            return {
 | 
			
		||||
                domainObject: undefined,
 | 
			
		||||
                currentObjectPath: []
 | 
			
		||||
                objectPath: []
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        components: {
 | 
			
		||||
@@ -100,7 +99,7 @@
 | 
			
		||||
        methods: {
 | 
			
		||||
            setObject(domainObject) {
 | 
			
		||||
                this.domainObject = domainObject;
 | 
			
		||||
                this.currentObjectPath = [this.domainObject].concat(this.objectPath.slice());
 | 
			
		||||
                this.objectPath = [this.domainObject].concat(this.openmct.router.path);
 | 
			
		||||
                this.$nextTick(function () {
 | 
			
		||||
                    let childContext = this.$refs.objectFrame.getSelectionContext();
 | 
			
		||||
                    childContext.item = domainObject;
 | 
			
		||||
 
 | 
			
		||||
@@ -23,12 +23,10 @@
 | 
			
		||||
 <template>
 | 
			
		||||
     <layout-frame :item="item"
 | 
			
		||||
                   :grid-size="gridSize"
 | 
			
		||||
                   @move="(gridDelta) => $emit('move', gridDelta)"
 | 
			
		||||
                   @endMove="() => $emit('endMove')">
 | 
			
		||||
                   @endDrag="(item, updates) => $emit('endDrag', item, updates)">
 | 
			
		||||
        <div class="c-telemetry-view"
 | 
			
		||||
             :style="styleObject"
 | 
			
		||||
             v-if="domainObject"
 | 
			
		||||
             @contextmenu.prevent="showContextMenu">
 | 
			
		||||
             v-if="domainObject">
 | 
			
		||||
            <div v-if="showLabel"
 | 
			
		||||
                  class="c-telemetry-view__label">
 | 
			
		||||
                <div class="c-telemetry-view__label-text">{{ domainObject.name }}</div>
 | 
			
		||||
@@ -80,11 +78,9 @@
 | 
			
		||||
 | 
			
		||||
 <script>
 | 
			
		||||
    import LayoutFrame from './LayoutFrame.vue'
 | 
			
		||||
    import printj from 'printj'
 | 
			
		||||
 | 
			
		||||
    const DEFAULT_TELEMETRY_DIMENSIONS = [10, 5],
 | 
			
		||||
          DEFAULT_POSITION = [1, 1],
 | 
			
		||||
          CONTEXT_MENU_ACTIONS = ['viewHistoricalData'];
 | 
			
		||||
          DEFAULT_POSITION = [1, 1];
 | 
			
		||||
 | 
			
		||||
    export default {
 | 
			
		||||
        makeDefinition(openmct, gridSize, domainObject, position) {
 | 
			
		||||
@@ -100,12 +96,13 @@
 | 
			
		||||
                displayMode: 'all',
 | 
			
		||||
                value: metadata.getDefaultDisplayValue(),
 | 
			
		||||
                stroke: "transparent",
 | 
			
		||||
                fill: "transparent",
 | 
			
		||||
                fill: "",
 | 
			
		||||
                color: "",
 | 
			
		||||
                size: "13px"
 | 
			
		||||
                size: "13px",
 | 
			
		||||
                useGrid: true
 | 
			
		||||
            };
 | 
			
		||||
        },
 | 
			
		||||
        inject: ['openmct', 'objectPath'],
 | 
			
		||||
        inject: ['openmct'],
 | 
			
		||||
        props: {
 | 
			
		||||
            item: Object,
 | 
			
		||||
            gridSize: Array,
 | 
			
		||||
@@ -146,10 +143,6 @@
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (this.item.format) {
 | 
			
		||||
                    return printj.sprintf(this.item.format, this.datum[this.valueMetadata.key]);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                return this.valueFormatter && this.valueFormatter.format(this.datum);
 | 
			
		||||
            },
 | 
			
		||||
            telemetryClass() {
 | 
			
		||||
@@ -165,8 +158,7 @@
 | 
			
		||||
            return {
 | 
			
		||||
                datum: undefined,
 | 
			
		||||
                formats: undefined,
 | 
			
		||||
                domainObject: undefined,
 | 
			
		||||
                currentObjectPath: undefined
 | 
			
		||||
                domainObject: undefined
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        watch: {
 | 
			
		||||
@@ -176,9 +168,6 @@
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                this.context.index = newIndex;
 | 
			
		||||
            },
 | 
			
		||||
            item(newItem) {
 | 
			
		||||
                this.context.layoutItem = newItem;
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        methods: {
 | 
			
		||||
@@ -187,8 +176,7 @@
 | 
			
		||||
                let options = {
 | 
			
		||||
                    start: bounds.start,
 | 
			
		||||
                    end: bounds.end,
 | 
			
		||||
                    size: 1,
 | 
			
		||||
                    strategy: 'latest'
 | 
			
		||||
                    size: 1
 | 
			
		||||
                };
 | 
			
		||||
                this.openmct.telemetry.request(this.domainObject, options)
 | 
			
		||||
                    .then(data => {
 | 
			
		||||
@@ -221,30 +209,19 @@
 | 
			
		||||
            },
 | 
			
		||||
            setObject(domainObject) {
 | 
			
		||||
                this.domainObject = domainObject;
 | 
			
		||||
                this.keyString = this.openmct.objects.makeKeyString(domainObject.identifier);
 | 
			
		||||
                this.metadata = this.openmct.telemetry.getMetadata(this.domainObject);
 | 
			
		||||
                this.limitEvaluator = this.openmct.telemetry.limitEvaluator(this.domainObject);
 | 
			
		||||
                this.formats = this.openmct.telemetry.getFormatMap(this.metadata);
 | 
			
		||||
                this.requestHistoricalData();
 | 
			
		||||
                this.subscribeToObject();
 | 
			
		||||
 | 
			
		||||
                this.currentObjectPath = this.objectPath.slice();
 | 
			
		||||
                this.currentObjectPath.unshift(this.domainObject);
 | 
			
		||||
 | 
			
		||||
                this.context = {
 | 
			
		||||
                    item: domainObject,
 | 
			
		||||
                    layoutItem: this.item,
 | 
			
		||||
                    index: this.index,
 | 
			
		||||
                    updateTelemetryFormat: this.updateTelemetryFormat
 | 
			
		||||
                    index: this.index
 | 
			
		||||
                };
 | 
			
		||||
                this.removeSelectable = this.openmct.selection.selectable(
 | 
			
		||||
                    this.$el, this.context, this.initSelect);
 | 
			
		||||
            },
 | 
			
		||||
            updateTelemetryFormat(format) {
 | 
			
		||||
                this.$emit('formatChanged', this.item, format);
 | 
			
		||||
            },
 | 
			
		||||
            showContextMenu(event) {
 | 
			
		||||
                this.openmct.contextMenu._showContextMenuForObjectPath(this.currentObjectPath, event.x, event.y, CONTEXT_MENU_ACTIONS);
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        mounted() {
 | 
			
		||||
 
 | 
			
		||||
@@ -23,8 +23,7 @@
 | 
			
		||||
 <template>
 | 
			
		||||
    <layout-frame :item="item"
 | 
			
		||||
                  :grid-size="gridSize"
 | 
			
		||||
                  @move="(gridDelta) => $emit('move', gridDelta)"
 | 
			
		||||
                  @endMove="() => $emit('endMove')">
 | 
			
		||||
                  @endDrag="(item, updates) => $emit('endDrag', item, updates)">
 | 
			
		||||
        <div class="c-text-view"
 | 
			
		||||
             :style="style">
 | 
			
		||||
            {{ item.text }}
 | 
			
		||||
@@ -60,7 +59,8 @@
 | 
			
		||||
                y: 1,
 | 
			
		||||
                width: 10,
 | 
			
		||||
                height: 5,
 | 
			
		||||
                text: element.text
 | 
			
		||||
                text: element.text,
 | 
			
		||||
                useGrid: true
 | 
			
		||||
            };
 | 
			
		||||
        },
 | 
			
		||||
        inject: ['openmct'],
 | 
			
		||||
 
 | 
			
		||||
@@ -25,9 +25,8 @@ import Vue from 'vue'
 | 
			
		||||
import objectUtils from '../../api/objects/object-utils.js'
 | 
			
		||||
import DisplayLayoutType from './DisplayLayoutType.js'
 | 
			
		||||
import DisplayLayoutToolbar from './DisplayLayoutToolbar.js'
 | 
			
		||||
import AlphaNumericFormatViewProvider from './AlphanumericFormatViewProvider.js'
 | 
			
		||||
 | 
			
		||||
export default function DisplayLayoutPlugin(options) {
 | 
			
		||||
export default function () {
 | 
			
		||||
    return function (openmct) {
 | 
			
		||||
        openmct.objectViews.addProvider({
 | 
			
		||||
            key: 'layout.view',
 | 
			
		||||
@@ -37,7 +36,7 @@ export default function DisplayLayoutPlugin(options) {
 | 
			
		||||
            canEdit: function (domainObject) {
 | 
			
		||||
                return domainObject.type === 'layout';
 | 
			
		||||
            },
 | 
			
		||||
            view: function (domainObject, isEditing, objectPath) {
 | 
			
		||||
            view: function (domainObject) {
 | 
			
		||||
                let component;
 | 
			
		||||
                return {
 | 
			
		||||
                    show(container) {
 | 
			
		||||
@@ -48,22 +47,19 @@ export default function DisplayLayoutPlugin(options) {
 | 
			
		||||
                            template: '<layout ref="displayLayout" :domain-object="domainObject"></layout>',
 | 
			
		||||
                            provide: {
 | 
			
		||||
                                openmct,
 | 
			
		||||
                                objectUtils,
 | 
			
		||||
                                options,
 | 
			
		||||
                                objectPath
 | 
			
		||||
                                objectUtils
 | 
			
		||||
                            },
 | 
			
		||||
                            el: container,
 | 
			
		||||
                            data () {
 | 
			
		||||
                                return {
 | 
			
		||||
                                    domainObject: domainObject
 | 
			
		||||
                                };
 | 
			
		||||
                                }
 | 
			
		||||
                            }
 | 
			
		||||
                        });
 | 
			
		||||
                    },
 | 
			
		||||
                    getSelectionContext() {
 | 
			
		||||
                        return {
 | 
			
		||||
                            item: domainObject,
 | 
			
		||||
                            supportsMultiSelect: true,
 | 
			
		||||
                            addElement: component && component.$refs.displayLayout.addElement,
 | 
			
		||||
                            removeItem: component && component.$refs.displayLayout.removeItem,
 | 
			
		||||
                            orderItem: component && component.$refs.displayLayout.orderItem
 | 
			
		||||
@@ -79,8 +75,7 @@ export default function DisplayLayoutPlugin(options) {
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
        openmct.types.addType('layout', DisplayLayoutType());
 | 
			
		||||
        openmct.toolbars.addProvider(new DisplayLayoutToolbar(openmct, options));
 | 
			
		||||
        openmct.inspectorViews.addProvider(new AlphaNumericFormatViewProvider(openmct, options));
 | 
			
		||||
        openmct.toolbars.addProvider(new DisplayLayoutToolbar(openmct));
 | 
			
		||||
        openmct.composition.addPolicy((parent, child) => {
 | 
			
		||||
            if (parent.type === 'layout' && child.type === 'folder') {
 | 
			
		||||
                return false;
 | 
			
		||||
@@ -88,6 +83,5 @@ export default function DisplayLayoutPlugin(options) {
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
        DisplayLayoutPlugin._installed = true;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -42,10 +42,7 @@
 | 
			
		||||
 | 
			
		||||
                <!-- Checkbox list, NOT editing -->
 | 
			
		||||
                <template v-if="filter.possibleValues && !isEditing">
 | 
			
		||||
                    <span 
 | 
			
		||||
                        v-if="persistedFilters[filter.comparator]">
 | 
			
		||||
                        {{persistedFilters[filter.comparator].join(', ')}}
 | 
			
		||||
                    </span>
 | 
			
		||||
                    <span>{{persistedFilters[filter.comparator].join(', ')}}</span>
 | 
			
		||||
                </template>
 | 
			
		||||
            </div>
 | 
			
		||||
        </li>
 | 
			
		||||
 
 | 
			
		||||
@@ -5,11 +5,11 @@
 | 
			
		||||
            <span class="c-disclosure-triangle is-enabled flex-elem"
 | 
			
		||||
              :class="{'c-disclosure-triangle--expanded': expanded}"></span>
 | 
			
		||||
            <div class="c-tree__item__label">
 | 
			
		||||
                <div class="c-object-label">
 | 
			
		||||
                    <div class="c-object-label__type-icon"
 | 
			
		||||
                <div class="t-object-label l-flex-row flex-elem grows">
 | 
			
		||||
                    <div class="t-item-icon flex-elem"
 | 
			
		||||
                         :class="objectCssClass">
 | 
			
		||||
                    </div>
 | 
			
		||||
                    <div class="c-object-label__name flex-elem grows">{{ filterObject.name }}</div>
 | 
			
		||||
                    <div class="t-title-label flex-elem grows">{{ filterObject.name }}</div>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
@@ -63,37 +63,22 @@ export default {
 | 
			
		||||
 | 
			
		||||
            if (filterValue && filterValue[comparator]) {
 | 
			
		||||
                if (value === false) {
 | 
			
		||||
                    let filteredValueName = filterValue[comparator].filter(v => v !== valueName);
 | 
			
		||||
 | 
			
		||||
                    if (filteredValueName.length === 0) {
 | 
			
		||||
                        delete this.updatedFilters[key];
 | 
			
		||||
                    } else {
 | 
			
		||||
                        filterValue[comparator] = filteredValueName;
 | 
			
		||||
                    }
 | 
			
		||||
                    filterValue[comparator] = filterValue[comparator].filter(v => v !== valueName);
 | 
			
		||||
                } else {
 | 
			
		||||
                    filterValue[comparator].push(valueName);
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                if (!this.updatedFilters[key]) {
 | 
			
		||||
                    this.$set(this.updatedFilters, key, {});
 | 
			
		||||
                    this.updatedFilters[key] = {};
 | 
			
		||||
                }
 | 
			
		||||
                this.$set(this.updatedFilters[key], comparator, [value ? valueName : undefined]);
 | 
			
		||||
                this.updatedFilters[key][comparator] = [value ? valueName : undefined];
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            this.$emit('updateFilters', this.keyString, this.updatedFilters);
 | 
			
		||||
        },
 | 
			
		||||
        updateTextFilter(key, comparator, value) {
 | 
			
		||||
            if (value.trim() === '') {
 | 
			
		||||
                if (this.updatedFilters[key]) {
 | 
			
		||||
                    delete this.updatedFilters[key];
 | 
			
		||||
                    this.$emit('updateFilters', this.keyString, this.updatedFilters);
 | 
			
		||||
                }
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (!this.updatedFilters[key]) {
 | 
			
		||||
                this.$set(this.updatedFilters, key, {});
 | 
			
		||||
                this.$set(this.updatedFilters[key], comparator, '');
 | 
			
		||||
                this.updatedFilters[key] = {};
 | 
			
		||||
            }
 | 
			
		||||
            this.updatedFilters[key][comparator] = value;
 | 
			
		||||
            this.$emit('updateFilters', this.keyString, this.updatedFilters);
 | 
			
		||||
 
 | 
			
		||||
@@ -23,18 +23,17 @@ export default {
 | 
			
		||||
        FilterObject
 | 
			
		||||
    },
 | 
			
		||||
    inject: [
 | 
			
		||||
        'openmct'
 | 
			
		||||
        'openmct',
 | 
			
		||||
        'providedObject'
 | 
			
		||||
    ],
 | 
			
		||||
    data() {
 | 
			
		||||
        let providedObject = this.openmct.selection.get()[0][0].context.item;
 | 
			
		||||
        let persistedFilters = {};
 | 
			
		||||
 | 
			
		||||
        if (providedObject.configuration && providedObject.configuration.filters) {
 | 
			
		||||
            persistedFilters = providedObject.configuration.filters;
 | 
			
		||||
        if (this.providedObject.configuration && this.providedObject.configuration.filters) {
 | 
			
		||||
            persistedFilters = this.providedObject.configuration.filters;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return {
 | 
			
		||||
            providedObject,
 | 
			
		||||
            persistedFilters,
 | 
			
		||||
            children: {}
 | 
			
		||||
        }
 | 
			
		||||
@@ -59,18 +58,14 @@ export default {
 | 
			
		||||
        removeChildren(identifier) {
 | 
			
		||||
            let keyString = this.openmct.objects.makeKeyString(identifier);
 | 
			
		||||
            this.$delete(this.children, keyString);
 | 
			
		||||
            delete this.persistedFilters[keyString];
 | 
			
		||||
            this.mutateConfigurationFilters();
 | 
			
		||||
            this.persistFilters(keyString);
 | 
			
		||||
        },
 | 
			
		||||
        persistFilters(keyString, userSelects) {
 | 
			
		||||
            this.persistedFilters[keyString] = userSelects;
 | 
			
		||||
            this.mutateConfigurationFilters();
 | 
			
		||||
            this.openmct.objects.mutate(this.providedObject, 'configuration.filters', this.persistedFilters);
 | 
			
		||||
        },
 | 
			
		||||
        updatePersistedFilters(filters) {
 | 
			
		||||
            this.persistedFilters = filters;
 | 
			
		||||
        },
 | 
			
		||||
        mutateConfigurationFilters() {
 | 
			
		||||
            this.openmct.objects.mutate(this.providedObject, 'configuration.filters', this.persistedFilters);
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
    mounted(){
 | 
			
		||||
@@ -78,14 +73,13 @@ export default {
 | 
			
		||||
        this.composition.on('add', this.addChildren);
 | 
			
		||||
        this.composition.on('remove', this.removeChildren);
 | 
			
		||||
        this.composition.load();
 | 
			
		||||
 | 
			
		||||
        this.unobserve = this.openmct.objects.observe(this.providedObject, 'configuration.filters', this.updatePersistedFilters);
 | 
			
		||||
        this.unobserveAllMutation = this.openmct.objects.observe(this.providedObject, '*', (mutatedObject) => this.providedObject = mutatedObject);
 | 
			
		||||
    },
 | 
			
		||||
    beforeDestroy() {
 | 
			
		||||
        this.composition.off('add', this.addChildren);
 | 
			
		||||
        this.composition.off('remove', this.removeChildren);
 | 
			
		||||
        this.unobserve();
 | 
			
		||||
        this.unobserveAllMutation();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 
 | 
			
		||||
@@ -33,20 +33,23 @@ define([
 | 
			
		||||
            key: 'filters-inspector',
 | 
			
		||||
            name: 'Filters Inspector View',
 | 
			
		||||
            canView: function (selection) {
 | 
			
		||||
                if (selection.length === 0 || selection[0].length === 0) {
 | 
			
		||||
                if (selection.length === 0) {
 | 
			
		||||
                    return false;
 | 
			
		||||
                }
 | 
			
		||||
                let object = selection[0][0].context.item;
 | 
			
		||||
                let object = selection[0].context.item;
 | 
			
		||||
 | 
			
		||||
                return object && supportedObjectTypesArray.some(type => object.type === type);
 | 
			
		||||
            },
 | 
			
		||||
            view: function (selection) {
 | 
			
		||||
                let component;
 | 
			
		||||
                let providedObject = selection[0].context.item;
 | 
			
		||||
 | 
			
		||||
                return {
 | 
			
		||||
                    show: function (element) {
 | 
			
		||||
                        component = new Vue({
 | 
			
		||||
                            provide: {
 | 
			
		||||
                                openmct
 | 
			
		||||
                                openmct,
 | 
			
		||||
                                providedObject
 | 
			
		||||
                            },
 | 
			
		||||
                            components: {
 | 
			
		||||
                                FiltersView: FiltersView.default
 | 
			
		||||
@@ -56,10 +59,8 @@ define([
 | 
			
		||||
                        });
 | 
			
		||||
                    },
 | 
			
		||||
                    destroy: function () {
 | 
			
		||||
                        if (component) {
 | 
			
		||||
                            component.$destroy();
 | 
			
		||||
                            component = undefined;
 | 
			
		||||
                        }
 | 
			
		||||
                        component.$destroy();
 | 
			
		||||
                        component = undefined;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
 
 | 
			
		||||
@@ -106,6 +106,9 @@
 | 
			
		||||
    .c-fl {
 | 
			
		||||
        @include abs();
 | 
			
		||||
        display: flex;
 | 
			
		||||
        flex-direction: column; // TEMP: only needed to support temp-toolbar element
 | 
			
		||||
 | 
			
		||||
        > * + * {  margin-top: $interiorMargin; }
 | 
			
		||||
 | 
			
		||||
        .temp-toolbar {
 | 
			
		||||
            flex: 0 0 auto;
 | 
			
		||||
@@ -113,8 +116,7 @@
 | 
			
		||||
 | 
			
		||||
        &__container-holder {
 | 
			
		||||
            display: flex;
 | 
			
		||||
            flex: 1 1 100%; // Must be 100% to work
 | 
			
		||||
            overflow: auto;
 | 
			
		||||
            flex: 1 1 100%; // Must needs to be 100% to work
 | 
			
		||||
 | 
			
		||||
            // Columns by default
 | 
			
		||||
            flex-direction: row;
 | 
			
		||||
@@ -290,6 +292,11 @@
 | 
			
		||||
            margin-bottom: $interiorMargin;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        &__object-view {
 | 
			
		||||
            flex: 1 1 auto;
 | 
			
		||||
            overflow: auto;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        &__size-indicator {
 | 
			
		||||
            $size: 35px;
 | 
			
		||||
 | 
			
		||||
@@ -415,7 +422,6 @@ import Container from '../utils/container';
 | 
			
		||||
import Frame from '../utils/frame';
 | 
			
		||||
import ResizeHandle from  './resizeHandle.vue';
 | 
			
		||||
import DropHint from './dropHint.vue';
 | 
			
		||||
import RemoveAction from '../../remove/RemoveAction.js';
 | 
			
		||||
 | 
			
		||||
const MIN_CONTAINER_SIZE = 5;
 | 
			
		||||
 | 
			
		||||
@@ -507,7 +513,7 @@ export default {
 | 
			
		||||
                remove associated domainObjects from composition
 | 
			
		||||
            */
 | 
			
		||||
            container.frames.forEach(f => {
 | 
			
		||||
                this.removeFromComposition(f.domainObjectIdentifier);
 | 
			
		||||
                this.composition.remove({identifier: f.domainObjectIdentifier});
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            this.containers.splice(containerIndex, 1);
 | 
			
		||||
@@ -522,7 +528,6 @@ export default {
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            sizeToFill(this.containers);
 | 
			
		||||
            this.setSelectionToParent();
 | 
			
		||||
            this.persist();
 | 
			
		||||
        },
 | 
			
		||||
        moveFrame(toContainerIndex, toFrameIndex, frameId, fromContainerIndex) {
 | 
			
		||||
@@ -556,23 +561,20 @@ export default {
 | 
			
		||||
        deleteFrame(frameId) {
 | 
			
		||||
            let container = this.containers
 | 
			
		||||
                .filter(c => c.frames.some(f => f.id === frameId))[0];
 | 
			
		||||
            let containerIndex = this.containers.indexOf(container);
 | 
			
		||||
            let frame = container
 | 
			
		||||
                .frames
 | 
			
		||||
                .filter((f => f.id === frameId))[0];
 | 
			
		||||
            let frameIndex = container.frames.indexOf(frame);
 | 
			
		||||
 | 
			
		||||
            this.removeFromComposition(frame.domainObjectIdentifier)
 | 
			
		||||
                .then(() => {
 | 
			
		||||
                    sizeToFill(container.frames)
 | 
			
		||||
                    this.setSelectionToParent();
 | 
			
		||||
                });
 | 
			
		||||
        },
 | 
			
		||||
        removeFromComposition(identifier) {
 | 
			
		||||
            return this.openmct.objects.get(identifier).then((childDomainObject) => {
 | 
			
		||||
                this.RemoveAction.removeFromComposition(this.domainObject, childDomainObject);
 | 
			
		||||
            });
 | 
			
		||||
        },
 | 
			
		||||
        setSelectionToParent() {
 | 
			
		||||
            this.$el.click();
 | 
			
		||||
            /*
 | 
			
		||||
                remove associated domainObject from composition
 | 
			
		||||
            */
 | 
			
		||||
            this.composition.remove({identifier: frame.domainObjectIdentifier});
 | 
			
		||||
 | 
			
		||||
            container.frames.splice(frameIndex, 1);
 | 
			
		||||
            sizeToFill(container.frames);
 | 
			
		||||
            this.persist(containerIndex);
 | 
			
		||||
        },
 | 
			
		||||
        allowContainerDrop(event, index) {
 | 
			
		||||
            if (!event.dataTransfer.types.includes('containerid')) {
 | 
			
		||||
@@ -663,8 +665,6 @@ export default {
 | 
			
		||||
        this.composition.on('remove', this.removeChildObject);
 | 
			
		||||
        this.composition.on('add', this.addFrame);
 | 
			
		||||
 | 
			
		||||
        this.RemoveAction = new RemoveAction(this.openmct);
 | 
			
		||||
 | 
			
		||||
        this.unobserve = this.openmct.objects.observe(this.domainObject, '*', this.updateDomainObject);
 | 
			
		||||
    },
 | 
			
		||||
    beforeDestroy() {
 | 
			
		||||
 
 | 
			
		||||
@@ -79,14 +79,12 @@ export default {
 | 
			
		||||
        },
 | 
			
		||||
        setSelection() {
 | 
			
		||||
            this.$nextTick(function () {
 | 
			
		||||
                if (this.$refs && this.$refs.objectFrame) {
 | 
			
		||||
                    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);
 | 
			
		||||
                }
 | 
			
		||||
                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) {
 | 
			
		||||
 
 | 
			
		||||
@@ -79,12 +79,10 @@ export default {
 | 
			
		||||
    mounted() {
 | 
			
		||||
        document.addEventListener('dragstart', this.setDragging);
 | 
			
		||||
        document.addEventListener('dragend', this.unsetDragging);
 | 
			
		||||
        document.addEventListener('drop', this.unsetDragging);
 | 
			
		||||
    },
 | 
			
		||||
    destroyed() {
 | 
			
		||||
        document.removeEventListener('dragstart', this.setDragging);
 | 
			
		||||
        document.removeEventListener('dragend', this.unsetDragging);
 | 
			
		||||
        document.removeEventListener('drop', this.unsetDragging);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 
 | 
			
		||||
@@ -27,22 +27,28 @@ function ToolbarProvider(openmct) {
 | 
			
		||||
        key: "flex-layout",
 | 
			
		||||
        description: "A toolbar for objects inside a Flexible Layout.",
 | 
			
		||||
        forSelection: function (selection) {
 | 
			
		||||
            let context = selection[0][0].context;
 | 
			
		||||
            let context = selection[0].context;
 | 
			
		||||
 | 
			
		||||
            return (context && context.type &&
 | 
			
		||||
                (context.type === 'flexible-layout' || context.type === 'container' || context.type === 'frame'));
 | 
			
		||||
        },
 | 
			
		||||
        toolbar: function (selection) {
 | 
			
		||||
 | 
			
		||||
            let selectionPath = selection[0],
 | 
			
		||||
                primary = selectionPath[0],
 | 
			
		||||
                secondary = selectionPath[1],
 | 
			
		||||
                tertiary = selectionPath[2],
 | 
			
		||||
            let primary = selection[0],
 | 
			
		||||
                secondary = selection[1],
 | 
			
		||||
                tertiary = selection[2],
 | 
			
		||||
                deleteFrame,
 | 
			
		||||
                toggleContainer,
 | 
			
		||||
                deleteContainer,
 | 
			
		||||
                addContainer,
 | 
			
		||||
                toggleFrame;
 | 
			
		||||
                toggleFrame,
 | 
			
		||||
                separator;
 | 
			
		||||
 | 
			
		||||
            separator = {
 | 
			
		||||
                control: "separator",
 | 
			
		||||
                domainObject: selection[0].context.item,
 | 
			
		||||
                key: "separator"
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            toggleContainer = {
 | 
			
		||||
                control: 'toggle-button',
 | 
			
		||||
@@ -63,12 +69,6 @@ function ToolbarProvider(openmct) {
 | 
			
		||||
                ]
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            function getSeparator() {
 | 
			
		||||
                return {
 | 
			
		||||
                    control: "separator"
 | 
			
		||||
                };
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (primary.context.type === 'frame') {
 | 
			
		||||
                let frameId = primary.context.frameId;
 | 
			
		||||
                let layoutObject = tertiary.context.item;
 | 
			
		||||
@@ -77,11 +77,11 @@ function ToolbarProvider(openmct) {
 | 
			
		||||
                    .containers;
 | 
			
		||||
                let container = containers
 | 
			
		||||
                    .filter(c => c.frames.some(f => f.id === frameId))[0];
 | 
			
		||||
                let containerIndex = containers.indexOf(container);
 | 
			
		||||
                let frame = container && container
 | 
			
		||||
                let frame = container
 | 
			
		||||
                    .frames
 | 
			
		||||
                    .filter((f => f.id === frameId))[0];
 | 
			
		||||
                let frameIndex = container && container.frames.indexOf(frame);
 | 
			
		||||
                let containerIndex = containers.indexOf(container);
 | 
			
		||||
                let frameIndex = container.frames.indexOf(frame);
 | 
			
		||||
 | 
			
		||||
                deleteFrame = {
 | 
			
		||||
                    control: "button",
 | 
			
		||||
@@ -202,9 +202,9 @@ function ToolbarProvider(openmct) {
 | 
			
		||||
            let toolbar = [
 | 
			
		||||
                toggleContainer,
 | 
			
		||||
                addContainer,
 | 
			
		||||
                toggleFrame ? getSeparator() : undefined,
 | 
			
		||||
                toggleFrame ? separator: undefined,
 | 
			
		||||
                toggleFrame,
 | 
			
		||||
                deleteFrame || deleteContainer ? getSeparator() : undefined,
 | 
			
		||||
                deleteFrame || deleteContainer ? separator : undefined,
 | 
			
		||||
                deleteFrame,
 | 
			
		||||
                deleteContainer
 | 
			
		||||
            ];
 | 
			
		||||
 
 | 
			
		||||
@@ -14,7 +14,6 @@ export default {
 | 
			
		||||
    },
 | 
			
		||||
    mounted() {
 | 
			
		||||
        this.composition = this.openmct.composition.get(this.domainObject);
 | 
			
		||||
        this.keystring = this.openmct.objects.makeKeyString(this.domainObject.identifier);
 | 
			
		||||
        if (!this.composition) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
@@ -35,7 +34,7 @@ export default {
 | 
			
		||||
            this.items.push({
 | 
			
		||||
                model: child,
 | 
			
		||||
                type: type.definition,
 | 
			
		||||
                isAlias: this.keystring !== child.location,
 | 
			
		||||
                isAlias: this.domainObject.identifier.key !== child.location,
 | 
			
		||||
                objectPath: [child].concat(this.openmct.router.path),
 | 
			
		||||
                objectKeyString: this.openmct.objects.makeKeyString(child.identifier)
 | 
			
		||||
            });
 | 
			
		||||
 
 | 
			
		||||
@@ -1,54 +0,0 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT, Copyright (c) 2014-2018, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
export default class GoToOriginalAction {
 | 
			
		||||
    constructor(openmct) {
 | 
			
		||||
        this.name = 'Go To Original';
 | 
			
		||||
        this.key = 'goToOriginal';
 | 
			
		||||
        this.description = 'Go to the original unlinked instance of this object';
 | 
			
		||||
 | 
			
		||||
        this._openmct = openmct;
 | 
			
		||||
    }
 | 
			
		||||
    invoke(objectPath) {
 | 
			
		||||
        this._openmct.objects.getOriginalPath(objectPath[0].identifier)
 | 
			
		||||
            .then((originalPath) => {
 | 
			
		||||
                let url = '#/browse/' + originalPath
 | 
			
		||||
                    .map(function (o) {
 | 
			
		||||
                        return o && this._openmct.objects.makeKeyString(o.identifier);
 | 
			
		||||
                    }.bind(this))
 | 
			
		||||
                    .reverse()
 | 
			
		||||
                    .slice(1)
 | 
			
		||||
                    .join('/');
 | 
			
		||||
 | 
			
		||||
                window.location.href = url;
 | 
			
		||||
            });
 | 
			
		||||
    }
 | 
			
		||||
    appliesTo(objectPath) {
 | 
			
		||||
        let parentKeystring = objectPath[1] && this._openmct.objects.makeKeyString(objectPath[1].identifier);
 | 
			
		||||
 | 
			
		||||
        if (!parentKeystring) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return (parentKeystring !== objectPath[0].location);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,28 +0,0 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT, Copyright (c) 2014-2018, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
import GoToOriginalAction from './goToOriginalAction';
 | 
			
		||||
 | 
			
		||||
export default function () {
 | 
			
		||||
    return function (openmct) {
 | 
			
		||||
        openmct.contextMenu.registerAction(new GoToOriginalAction(openmct));
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
@@ -25,240 +25,176 @@ define([
 | 
			
		||||
], function (
 | 
			
		||||
    uuid
 | 
			
		||||
) {
 | 
			
		||||
    return function Migrations(openmct) {
 | 
			
		||||
        function getColumnNameKeyMap(domainObject) {
 | 
			
		||||
            let composition = openmct.composition.get(domainObject);
 | 
			
		||||
            if (composition) {
 | 
			
		||||
                return composition.load().then(composees => {
 | 
			
		||||
                    return composees.reduce((nameKeyMap, composee) => {
 | 
			
		||||
                        let metadata = openmct.telemetry.getMetadata(composee);
 | 
			
		||||
                        if (metadata !== undefined) {
 | 
			
		||||
                            metadata.values().forEach(value => {
 | 
			
		||||
                                nameKeyMap[value.name] = value.key;
 | 
			
		||||
                            });
 | 
			
		||||
                        }
 | 
			
		||||
                        return nameKeyMap;
 | 
			
		||||
                    }, {});
 | 
			
		||||
                });
 | 
			
		||||
            } else {
 | 
			
		||||
                return Promise.resolve([]);
 | 
			
		||||
            }
 | 
			
		||||
    function isTelemetry(domainObject) {
 | 
			
		||||
        if (openmct.telemetry.isTelemetryObject(domainObject)
 | 
			
		||||
            && domainObject.type !== 'summary-widget'
 | 
			
		||||
            && domainObject.type !== 'example.imagery') {
 | 
			
		||||
            return true;
 | 
			
		||||
        } else {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        function isTelemetry(domainObject) {
 | 
			
		||||
            if (openmct.telemetry.isTelemetryObject(domainObject)
 | 
			
		||||
                && domainObject.type !== 'summary-widget'
 | 
			
		||||
                && domainObject.type !== 'example.imagery') {
 | 
			
		||||
                return true;
 | 
			
		||||
            } else {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    function migrateDisplayLayout(domainObject, childObjects) {
 | 
			
		||||
        const DEFAULT_GRID_SIZE = [32, 32];
 | 
			
		||||
        let migratedObject = Object.assign({}, domainObject);
 | 
			
		||||
        let panels = migratedObject.configuration.layout.panels;
 | 
			
		||||
        let items = [];
 | 
			
		||||
 | 
			
		||||
        function migrateDisplayLayout(domainObject, childObjects) {
 | 
			
		||||
            const DEFAULT_GRID_SIZE = [32, 32];
 | 
			
		||||
            let migratedObject = Object.assign({}, domainObject);
 | 
			
		||||
            let panels = migratedObject.configuration.layout.panels;
 | 
			
		||||
            let items = [];
 | 
			
		||||
 | 
			
		||||
            Object.keys(panels).forEach(key => {
 | 
			
		||||
                let panel = panels[key];
 | 
			
		||||
                let domainObject = childObjects[key];
 | 
			
		||||
                let identifier = undefined;
 | 
			
		||||
 | 
			
		||||
                if (isTelemetry(domainObject)) {
 | 
			
		||||
                    // If object is a telemetry point, convert it to a plot and
 | 
			
		||||
                    // replace the object in migratedObject composition with the plot.
 | 
			
		||||
                    identifier = {
 | 
			
		||||
                        key: uuid(),
 | 
			
		||||
                        namespace: migratedObject.identifier.namespace
 | 
			
		||||
                    };
 | 
			
		||||
                    let plotObject = {
 | 
			
		||||
                        identifier: identifier,
 | 
			
		||||
                        location: domainObject.location,
 | 
			
		||||
                        name: domainObject.name,
 | 
			
		||||
                        type: "telemetry.plot.overlay"
 | 
			
		||||
                    };
 | 
			
		||||
                    let plotType = openmct.types.get('telemetry.plot.overlay');
 | 
			
		||||
                    plotType.definition.initialize(plotObject);
 | 
			
		||||
                    plotObject.composition.push(domainObject.identifier);
 | 
			
		||||
                    openmct.objects.mutate(plotObject, 'persisted', Date.now());
 | 
			
		||||
 | 
			
		||||
                    let keyString = openmct.objects.makeKeyString(domainObject.identifier);
 | 
			
		||||
                    let clonedComposition = Object.assign([], migratedObject.composition);
 | 
			
		||||
                    clonedComposition.forEach((identifier, index) => {
 | 
			
		||||
                        if (openmct.objects.makeKeyString(identifier) === keyString) {
 | 
			
		||||
                            migratedObject.composition[index] = plotObject.identifier;
 | 
			
		||||
                        }
 | 
			
		||||
                    });
 | 
			
		||||
                }
 | 
			
		||||
        Object.keys(panels).forEach(key => {
 | 
			
		||||
            let panel = panels[key];
 | 
			
		||||
            let domainObject = childObjects[key];
 | 
			
		||||
 | 
			
		||||
            if (isTelemetry(domainObject)) {
 | 
			
		||||
                items.push({
 | 
			
		||||
                    width: panel.dimensions[0],
 | 
			
		||||
                    height: panel.dimensions[1],
 | 
			
		||||
                    x: panel.position[0],
 | 
			
		||||
                    y: panel.position[1],
 | 
			
		||||
                    identifier: identifier || domainObject.identifier,
 | 
			
		||||
                    useGrid: true,
 | 
			
		||||
                    identifier: domainObject.identifier,
 | 
			
		||||
                    id: uuid(),
 | 
			
		||||
                    type: 'telemetry-view',
 | 
			
		||||
                    displayMode: 'all',
 | 
			
		||||
                    value: openmct.telemetry.getMetadata(domainObject).getDefaultDisplayValue(),
 | 
			
		||||
                    stroke: "transparent",
 | 
			
		||||
                    fill: "",
 | 
			
		||||
                    color: "",
 | 
			
		||||
                    size: "13px"
 | 
			
		||||
                });
 | 
			
		||||
            } else {
 | 
			
		||||
                items.push({
 | 
			
		||||
                    width: panel.dimensions[0],
 | 
			
		||||
                    height: panel.dimensions[1],
 | 
			
		||||
                    x: panel.position[0],
 | 
			
		||||
                    y: panel.position[1],
 | 
			
		||||
                    useGrid: true,
 | 
			
		||||
                    identifier: domainObject.identifier,
 | 
			
		||||
                    id: uuid(),
 | 
			
		||||
                    type: 'subobject-view',
 | 
			
		||||
                    hasFrame: panel.hasFrame
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            migratedObject.configuration.items = items;
 | 
			
		||||
            migratedObject.configuration.layoutGrid = migratedObject.layoutGrid || DEFAULT_GRID_SIZE;
 | 
			
		||||
            delete migratedObject.layoutGrid;
 | 
			
		||||
            delete migratedObject.configuration.layout;
 | 
			
		||||
            return migratedObject;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        function migrateFixedPositionConfiguration(elements, telemetryObjects, gridSize) {
 | 
			
		||||
            const DEFAULT_STROKE = "transparent";
 | 
			
		||||
            const DEFAULT_SIZE = "13px";
 | 
			
		||||
            const DEFAULT_COLOR = "";
 | 
			
		||||
            const DEFAULT_FILL = "";
 | 
			
		||||
            let items = [];
 | 
			
		||||
 | 
			
		||||
            elements.forEach(element => {
 | 
			
		||||
                let item = {
 | 
			
		||||
                    x: element.x,
 | 
			
		||||
                    y: element.y,
 | 
			
		||||
                    width: element.width,
 | 
			
		||||
                    height: element.height,
 | 
			
		||||
                    id: uuid()
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
                if (!element.useGrid) {
 | 
			
		||||
                    item.x = Math.round(item.x / gridSize[0]);
 | 
			
		||||
                    item.y = Math.round(item.y / gridSize[1]);
 | 
			
		||||
                    item.width = Math.round(item.width / gridSize[0]);
 | 
			
		||||
                    item.height = Math.round(item.height / gridSize[1]);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (element.type === "fixed.telemetry") {
 | 
			
		||||
                    item.type = "telemetry-view";
 | 
			
		||||
                    item.stroke = element.stroke || DEFAULT_STROKE;
 | 
			
		||||
                    item.fill = element.fill || DEFAULT_FILL;
 | 
			
		||||
                    item.color = element.color || DEFAULT_COLOR;
 | 
			
		||||
                    item.size = element.size || DEFAULT_SIZE;
 | 
			
		||||
                    item.identifier = telemetryObjects[element.id].identifier;
 | 
			
		||||
                    item.displayMode = element.titled ? 'all' : 'value';
 | 
			
		||||
                    item.value = openmct.telemetry.getMetadata(telemetryObjects[element.id]).getDefaultDisplayValue();
 | 
			
		||||
                } else if (element.type === 'fixed.box') {
 | 
			
		||||
                    item.type = "box-view";
 | 
			
		||||
                    item.stroke = element.stroke || DEFAULT_STROKE;
 | 
			
		||||
                    item.fill = element.fill || DEFAULT_FILL;
 | 
			
		||||
                } else if (element.type === 'fixed.line') {
 | 
			
		||||
                    item.type = "line-view";
 | 
			
		||||
                    item.x2 = element.x2;
 | 
			
		||||
                    item.y2 = element.y2;
 | 
			
		||||
                    item.stroke = element.stroke || DEFAULT_STROKE;
 | 
			
		||||
                    delete item.height;
 | 
			
		||||
                    delete item.width;
 | 
			
		||||
                } else if (element.type === 'fixed.text') {
 | 
			
		||||
                    item.type = "text-view";
 | 
			
		||||
                    item.text = element.text;
 | 
			
		||||
                    item.stroke = element.stroke || DEFAULT_STROKE;
 | 
			
		||||
                    item.fill = element.fill || DEFAULT_FILL;
 | 
			
		||||
                    item.color = element.color || DEFAULT_COLOR;
 | 
			
		||||
                    item.size = element.size || DEFAULT_SIZE;
 | 
			
		||||
                } else if (element.type === 'fixed.image') {
 | 
			
		||||
                    item.type = "image-view";
 | 
			
		||||
                    item.url =element.url;
 | 
			
		||||
                    item.stroke = element.stroke || DEFAULT_STROKE;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                items.push(item);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            return items;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return [
 | 
			
		||||
            {
 | 
			
		||||
                check(domainObject) {
 | 
			
		||||
                    return domainObject.type === 'layout' &&
 | 
			
		||||
                        domainObject.configuration &&
 | 
			
		||||
                        domainObject.configuration.layout;
 | 
			
		||||
                },
 | 
			
		||||
                migrate(domainObject) {
 | 
			
		||||
                    let childObjects = {};
 | 
			
		||||
                    let promises = Object.keys(domainObject.configuration.layout.panels).map(key => {
 | 
			
		||||
                        return openmct.objects.get(key)
 | 
			
		||||
                            .then(object => {
 | 
			
		||||
                                childObjects[key] = object;
 | 
			
		||||
                            });
 | 
			
		||||
                    });
 | 
			
		||||
 | 
			
		||||
                    return Promise.all(promises)
 | 
			
		||||
                        .then(function () {
 | 
			
		||||
                            return migrateDisplayLayout(domainObject, childObjects);
 | 
			
		||||
                        });
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                check(domainObject) {
 | 
			
		||||
                    return domainObject.type === 'telemetry.fixed' &&
 | 
			
		||||
                        domainObject.configuration &&
 | 
			
		||||
                        domainObject.configuration['fixed-display'];
 | 
			
		||||
                },
 | 
			
		||||
                migrate(domainObject) {
 | 
			
		||||
                    const DEFAULT_GRID_SIZE = [64, 16];
 | 
			
		||||
                    let newLayoutObject = {
 | 
			
		||||
                        identifier: domainObject.identifier,
 | 
			
		||||
                        location: domainObject.location,
 | 
			
		||||
                        name: domainObject.name,
 | 
			
		||||
                        type: "layout"
 | 
			
		||||
                    };
 | 
			
		||||
                    let gridSize = domainObject.layoutGrid || DEFAULT_GRID_SIZE;
 | 
			
		||||
                    let layoutType = openmct.types.get('layout');
 | 
			
		||||
                    layoutType.definition.initialize(newLayoutObject);
 | 
			
		||||
                    newLayoutObject.composition = domainObject.composition;
 | 
			
		||||
                    newLayoutObject.configuration.layoutGrid = gridSize;
 | 
			
		||||
 | 
			
		||||
                    let elements = domainObject.configuration['fixed-display'].elements;
 | 
			
		||||
                    let telemetryObjects = {};
 | 
			
		||||
                    let promises = elements.map(element => {
 | 
			
		||||
                        if (element.id) {
 | 
			
		||||
                            return openmct.objects.get(element.id)
 | 
			
		||||
                                .then(object => {
 | 
			
		||||
                                    telemetryObjects[element.id] = object;
 | 
			
		||||
                                });
 | 
			
		||||
                        }
 | 
			
		||||
                    });
 | 
			
		||||
 | 
			
		||||
                    return Promise.all(promises)
 | 
			
		||||
                        .then(function () {
 | 
			
		||||
                            newLayoutObject.configuration.items =
 | 
			
		||||
                                migrateFixedPositionConfiguration(elements, telemetryObjects, gridSize);
 | 
			
		||||
                            return newLayoutObject;
 | 
			
		||||
                        });
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                check(domainObject) {
 | 
			
		||||
                    return domainObject.type === 'table' &&
 | 
			
		||||
                        domainObject.configuration &&
 | 
			
		||||
                        domainObject.configuration.table;
 | 
			
		||||
                },
 | 
			
		||||
                migrate(domainObject) {
 | 
			
		||||
                    let currentTableConfiguration = domainObject.configuration.table || {};
 | 
			
		||||
                    let currentColumnConfiguration = currentTableConfiguration.columns || {};
 | 
			
		||||
                    return getColumnNameKeyMap(domainObject).then(nameKeyMap => {
 | 
			
		||||
                        let hiddenColumns = Object.keys(currentColumnConfiguration).filter(columnName => {
 | 
			
		||||
                            return currentColumnConfiguration[columnName] === false;
 | 
			
		||||
                        }).reduce((hiddenColumnsMap, hiddenColumnName) => {
 | 
			
		||||
                            let key = nameKeyMap[hiddenColumnName];
 | 
			
		||||
                            hiddenColumnsMap[key] = true;
 | 
			
		||||
                            return hiddenColumnsMap;
 | 
			
		||||
                        }, {});
 | 
			
		||||
 | 
			
		||||
                        domainObject.configuration.hiddenColumns = hiddenColumns;
 | 
			
		||||
                        delete domainObject.configuration.table;
 | 
			
		||||
                        return domainObject;
 | 
			
		||||
                    });
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        ];
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        migratedObject.configuration.items = items;
 | 
			
		||||
        migratedObject.configuration.layoutGrid = migratedObject.layoutGrid || DEFAULT_GRID_SIZE;
 | 
			
		||||
        delete migratedObject.layoutGrid;
 | 
			
		||||
        delete migratedObject.configuration.layout;
 | 
			
		||||
        return migratedObject;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function migrateFixedPositionConfiguration(elements, telemetryObjects) {
 | 
			
		||||
        const DEFAULT_STROKE = "transparent";
 | 
			
		||||
        const DEFAULT_SIZE = "13px";
 | 
			
		||||
        const DEFAULT_COLOR = "";
 | 
			
		||||
        const DEFAULT_FILL = "";
 | 
			
		||||
        let items = [];
 | 
			
		||||
 | 
			
		||||
        elements.forEach(element => {
 | 
			
		||||
            let item = {
 | 
			
		||||
                x: element.x,
 | 
			
		||||
                y: element.y,
 | 
			
		||||
                width: element.width,
 | 
			
		||||
                height: element.height,
 | 
			
		||||
                useGrid: element.useGrid,
 | 
			
		||||
                id: uuid()
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            if (element.type === "fixed.telemetry") {
 | 
			
		||||
                item.type = "telemetry-view";
 | 
			
		||||
                item.stroke = element.stroke || DEFAULT_STROKE;
 | 
			
		||||
                item.fill = element.fill || DEFAULT_FILL;
 | 
			
		||||
                item.color = element.color || DEFAULT_COLOR;
 | 
			
		||||
                item.size = element.size || DEFAULT_SIZE;
 | 
			
		||||
                item.identifier = telemetryObjects[element.id].identifier;
 | 
			
		||||
                item.displayMode = element.titled ? 'all' : 'value';
 | 
			
		||||
                item.value = openmct.telemetry.getMetadata(telemetryObjects[element.id]).getDefaultDisplayValue();
 | 
			
		||||
            } else if (element.type === 'fixed.box') {
 | 
			
		||||
                item.type = "box-view";
 | 
			
		||||
                item.stroke = element.stroke || DEFAULT_STROKE;
 | 
			
		||||
                item.fill = element.fill || DEFAULT_FILL;
 | 
			
		||||
            } else if (element.type === 'fixed.line') {
 | 
			
		||||
                item.type = "line-view";
 | 
			
		||||
                item.x2 = element.x2;
 | 
			
		||||
                item.y2 = element.y2;
 | 
			
		||||
                item.stroke = element.stroke || DEFAULT_STROKE;
 | 
			
		||||
                delete item.height;
 | 
			
		||||
                delete item.width;
 | 
			
		||||
            } else if (element.type === 'fixed.text') {
 | 
			
		||||
                item.type = "text-view";
 | 
			
		||||
                item.text = element.text;
 | 
			
		||||
                item.stroke = element.stroke || DEFAULT_STROKE;
 | 
			
		||||
                item.fill = element.fill || DEFAULT_FILL;
 | 
			
		||||
                item.color = element.color || DEFAULT_COLOR;
 | 
			
		||||
                item.size = element.size || DEFAULT_SIZE;
 | 
			
		||||
            } else if (element.type === 'fixed.image') {
 | 
			
		||||
                item.type = "image-view";
 | 
			
		||||
                item.url =element.url;
 | 
			
		||||
                item.stroke = element.stroke || DEFAULT_STROKE;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            items.push(item);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        return items;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return [
 | 
			
		||||
        {
 | 
			
		||||
            check(domainObject) {
 | 
			
		||||
                return domainObject.type === 'layout' && domainObject.configuration.layout;
 | 
			
		||||
            },
 | 
			
		||||
            migrate(domainObject) {
 | 
			
		||||
                let childObjects = {};
 | 
			
		||||
                let promises = Object.keys(domainObject.configuration.layout.panels).map(key => {
 | 
			
		||||
                    return openmct.objects.get(key)
 | 
			
		||||
                        .then(object => {
 | 
			
		||||
                            childObjects[key] = object;
 | 
			
		||||
                        });
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                return Promise.all(promises)
 | 
			
		||||
                    .then(function () {
 | 
			
		||||
                        return migrateDisplayLayout(domainObject, childObjects);
 | 
			
		||||
                    });
 | 
			
		||||
            },
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            check(domainObject) {
 | 
			
		||||
                return domainObject.type === 'telemetry.fixed' && domainObject.configuration['fixed-display'];
 | 
			
		||||
            },
 | 
			
		||||
            migrate(domainObject) {
 | 
			
		||||
                const DEFAULT_GRID_SIZE = [64, 16];
 | 
			
		||||
                let newLayoutObject = {
 | 
			
		||||
                    identifier: domainObject.identifier,
 | 
			
		||||
                    location: domainObject.location,
 | 
			
		||||
                    name: domainObject.name,
 | 
			
		||||
                    type: "layout"
 | 
			
		||||
                };
 | 
			
		||||
                let layoutType = openmct.types.get('layout');
 | 
			
		||||
                layoutType.definition.initialize(newLayoutObject);
 | 
			
		||||
                newLayoutObject.composition = domainObject.composition;
 | 
			
		||||
                newLayoutObject.configuration.layoutGrid = domainObject.layoutGrid || DEFAULT_GRID_SIZE;
 | 
			
		||||
 | 
			
		||||
                let elements = domainObject.configuration['fixed-display'].elements;
 | 
			
		||||
                let telemetryObjects = {};
 | 
			
		||||
                let promises = elements.map(element => {
 | 
			
		||||
                    if (element.id) {
 | 
			
		||||
                        return openmct.objects.get(element.id)
 | 
			
		||||
                            .then(object => {
 | 
			
		||||
                                telemetryObjects[element.id] = object;
 | 
			
		||||
                            });
 | 
			
		||||
                    }
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                return Promise.all(promises)
 | 
			
		||||
                    .then(function () {
 | 
			
		||||
                        newLayoutObject.configuration.items =
 | 
			
		||||
                            migrateFixedPositionConfiguration(elements, telemetryObjects);
 | 
			
		||||
                        return newLayoutObject;
 | 
			
		||||
                    });
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    ];
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
@@ -20,21 +20,19 @@
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
import Migrations from './Migrations.js'
 | 
			
		||||
import migrations from './Migrations.js'
 | 
			
		||||
 | 
			
		||||
export default function () {
 | 
			
		||||
    function needsMigration(domainObject) {        
 | 
			
		||||
        return migrations.some(m => m.check(domainObject));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function migrateObject(domainObject) {
 | 
			
		||||
        return migrations.filter(m => m.check(domainObject))[0]
 | 
			
		||||
            .migrate(domainObject);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return function (openmct) {
 | 
			
		||||
        let migrations = Migrations(openmct);
 | 
			
		||||
 | 
			
		||||
        function needsMigration(domainObject) {
 | 
			
		||||
            return migrations.some(m => m.check(domainObject));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        function migrateObject(domainObject) {
 | 
			
		||||
            return migrations.filter(m => m.check(domainObject))[0]
 | 
			
		||||
                .migrate(domainObject);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let wrappedFunction = openmct.objects.get;
 | 
			
		||||
        openmct.objects.get = function migrate(identifier) {
 | 
			
		||||
            return wrappedFunction.apply(openmct.objects, [identifier])
 | 
			
		||||
@@ -48,6 +46,6 @@ export default function () {
 | 
			
		||||
                    }
 | 
			
		||||
                    return object;
 | 
			
		||||
                });
 | 
			
		||||
        }
 | 
			
		||||
        }        
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 }
 | 
			
		||||
@@ -115,22 +115,10 @@
 | 
			
		||||
                 width: (tickWidth + 30) + 'px'
 | 
			
		||||
             }">
 | 
			
		||||
 | 
			
		||||
            <div class="gl-plot-label gl-plot-y-label" ng-if="!yKeyOptions">
 | 
			
		||||
            <div class="gl-plot-label gl-plot-y-label">
 | 
			
		||||
                {{ yAxis.get('label') }}
 | 
			
		||||
            </div>
 | 
			
		||||
 | 
			
		||||
            <div class="gl-plot-label gl-plot-y-label" ng-if="yKeyOptions.length > 1 && series.length === 1">
 | 
			
		||||
                <select  class="gl-plot-y-label__select"
 | 
			
		||||
                         ng-model="yAxisLabel" ng-change="plot.toggleYAxisLabel(yAxisLabel, yKeyOptions, series[0])">
 | 
			
		||||
                    <option ng-repeat="option in yKeyOptions"
 | 
			
		||||
                            value="{{option.name}}"
 | 
			
		||||
                            ng-selected="option.name === yAxisLabel">
 | 
			
		||||
                        {{option.name}}
 | 
			
		||||
                    </option>
 | 
			
		||||
                </select>
 | 
			
		||||
            </div>
 | 
			
		||||
            
 | 
			
		||||
 | 
			
		||||
            <mct-ticks axis="yAxis">
 | 
			
		||||
                <div ng-repeat="tick in ticks track by tick.text"
 | 
			
		||||
                     class="gl-plot-tick gl-plot-y-tick-label"
 | 
			
		||||
 
 | 
			
		||||
@@ -43,16 +43,12 @@
 | 
			
		||||
    <div class="l-view-section">
 | 
			
		||||
        <div class="c-loading--overlay loading"
 | 
			
		||||
             ng-show="!!currentRequest.pending"></div>
 | 
			
		||||
        <div class="gl-plot child-frame u-inspectable"
 | 
			
		||||
        <div class="gl-plot child-frame"
 | 
			
		||||
            ng-repeat="telemetryObject in telemetryObjects"
 | 
			
		||||
            ng-class="{
 | 
			
		||||
                's-status-timeconductor-unsynced': telemetryObject
 | 
			
		||||
                    .getCapability('status')
 | 
			
		||||
                    .get('timeconductor-unsynced')
 | 
			
		||||
            }"
 | 
			
		||||
            mct-selectable="{
 | 
			
		||||
                item: telemetryObject.useCapability('adapter'),
 | 
			
		||||
                oldItem: telemetryObject
 | 
			
		||||
            }">
 | 
			
		||||
            <mct-overlay-plot domain-object="telemetryObject"></mct-overlay-plot>
 | 
			
		||||
        </div>
 | 
			
		||||
 
 | 
			
		||||
@@ -115,13 +115,11 @@ define([
 | 
			
		||||
 | 
			
		||||
    Collection.prototype.remove = function (model) {
 | 
			
		||||
        var index = this.indexOf(model);
 | 
			
		||||
 | 
			
		||||
        if (index === -1) {
 | 
			
		||||
            throw new Error('model not found in collection.');
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.emit('remove', model, index);
 | 
			
		||||
        this.models.splice(index, 1);
 | 
			
		||||
        this.emit('remove', model, index);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    Collection.prototype.destroy = function (model) {
 | 
			
		||||
 
 | 
			
		||||
@@ -377,19 +377,6 @@ define([
 | 
			
		||||
                delete this.unsubscribe;
 | 
			
		||||
            }
 | 
			
		||||
            this.fetch();
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Clears the plot series, unsubscribes and resubscribes
 | 
			
		||||
         * @public
 | 
			
		||||
         */
 | 
			
		||||
        refresh: function () {
 | 
			
		||||
            this.reset();
 | 
			
		||||
            if (this.unsubscribe) {
 | 
			
		||||
                this.unsubscribe();
 | 
			
		||||
                delete this.unsubscribe;
 | 
			
		||||
            }
 | 
			
		||||
            this.fetch();
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -100,33 +100,19 @@ define([
 | 
			
		||||
        removeTelemetryObject: function (identifier) {
 | 
			
		||||
            var plotObject = this.plot.get('domainObject');
 | 
			
		||||
            if (plotObject.type === 'telemetry.plot.overlay') {
 | 
			
		||||
 | 
			
		||||
                var persistedIndex = _.findIndex(plotObject.configuration.series, function (s) {
 | 
			
		||||
                var index = _.findIndex(plotObject.configuration.series, function (s) {
 | 
			
		||||
                    return _.isEqual(identifier, s.identifier);
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                var configIndex = _.findIndex(this.models, function (m) {
 | 
			
		||||
                    return _.isEqual(m.domainObject.identifier, identifier);
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                /*
 | 
			
		||||
                    when cancelling out of edit mode, the config store and domain object are out of sync
 | 
			
		||||
                    thus it is necesarry to check both and remove the models that are no longer in composition
 | 
			
		||||
                */
 | 
			
		||||
                if (persistedIndex === -1) {
 | 
			
		||||
                    this.remove(this.at(configIndex));
 | 
			
		||||
                } else {
 | 
			
		||||
                    this.remove(this.at(persistedIndex));
 | 
			
		||||
                    // Because this is triggered by a composition change, we have
 | 
			
		||||
                    // to defer mutation of our plot object, otherwise we might
 | 
			
		||||
                    // mutate an outdated version of the plotObject.
 | 
			
		||||
                    setTimeout(function () {
 | 
			
		||||
                        var newPlotObject = this.plot.get('domainObject');
 | 
			
		||||
                        var cSeries = newPlotObject.configuration.series.slice();
 | 
			
		||||
                        cSeries.splice(persistedIndex, 1);
 | 
			
		||||
                        this.openmct.objects.mutate(newPlotObject, 'configuration.series', cSeries);
 | 
			
		||||
                    }.bind(this));
 | 
			
		||||
                }
 | 
			
		||||
                this.remove(this.at(index));
 | 
			
		||||
                // Because this is triggered by a composition change, we have
 | 
			
		||||
                // to defer mutation of our plot object, otherwise we might
 | 
			
		||||
                // mutate an outdated version of the plotObject.
 | 
			
		||||
                setTimeout(function () {
 | 
			
		||||
                    var newPlotObject = this.plot.get('domainObject');
 | 
			
		||||
                    var cSeries = newPlotObject.configuration.series.slice();
 | 
			
		||||
                    cSeries.splice(index, 1);
 | 
			
		||||
                    this.openmct.objects.mutate(newPlotObject, 'configuration.series', cSeries);
 | 
			
		||||
                }.bind(this));
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        onSeriesAdd: function (series) {
 | 
			
		||||
 
 | 
			
		||||
@@ -25,11 +25,23 @@ define([
 | 
			
		||||
 | 
			
		||||
    function ConfigStore() {
 | 
			
		||||
        this.store = {};
 | 
			
		||||
        this.tracking = {};
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ConfigStore.prototype.deleteStore = function (id) {
 | 
			
		||||
        this.store[id].destroy();
 | 
			
		||||
        delete this.store[id];
 | 
			
		||||
    ConfigStore.prototype.track = function (id) {
 | 
			
		||||
        if (!this.tracking[id]) {
 | 
			
		||||
            this.tracking[id] = 0;
 | 
			
		||||
        }
 | 
			
		||||
        this.tracking[id] += 1;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    ConfigStore.prototype.untrack = function (id) {
 | 
			
		||||
        this.tracking[id] -= 1;
 | 
			
		||||
        if (this.tracking[id] <= 0) {
 | 
			
		||||
            delete this.tracking[id];
 | 
			
		||||
            this.store[id].destroy();
 | 
			
		||||
            delete this.store[id];
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    ConfigStore.prototype.add = function (id, config) {
 | 
			
		||||
 
 | 
			
		||||
@@ -49,6 +49,7 @@ define([
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    PlotOptionsController.prototype.destroy = function () {
 | 
			
		||||
        configStore.untrack(this.configId);
 | 
			
		||||
        this.stopListening();
 | 
			
		||||
        this.unlisten();
 | 
			
		||||
    };
 | 
			
		||||
@@ -59,7 +60,7 @@ define([
 | 
			
		||||
            this.$timeout(this.setUpScope.bind(this));
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        configStore.track(this.configId);
 | 
			
		||||
        this.config = this.$scope.config = config;
 | 
			
		||||
        this.$scope.plotSeries = [];
 | 
			
		||||
 | 
			
		||||
@@ -69,15 +70,13 @@ define([
 | 
			
		||||
        this.listenTo(this.$scope, '$destroy', this.destroy, this);
 | 
			
		||||
        this.listenTo(config.series, 'add', this.addSeries, this);
 | 
			
		||||
        this.listenTo(config.series, 'remove', this.resetAllSeries, this);
 | 
			
		||||
 | 
			
		||||
        config.series.forEach(this.addSeries, this);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    PlotOptionsController.prototype.addSeries = function (series, index) {
 | 
			
		||||
        this.$timeout(function () {
 | 
			
		||||
            this.$scope.plotSeries[index] = series;
 | 
			
		||||
            series.locateOldObject(this.$scope.domainObject);
 | 
			
		||||
        }.bind(this));
 | 
			
		||||
        this.$scope.plotSeries[index] = series;
 | 
			
		||||
        series.locateOldObject(this.$scope.domainObject);
 | 
			
		||||
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    PlotOptionsController.prototype.resetAllSeries = function (series, index) {
 | 
			
		||||
 
 | 
			
		||||
@@ -93,8 +93,6 @@ define([
 | 
			
		||||
        this.$scope.series = this.config.series.models;
 | 
			
		||||
        this.$scope.legend = this.config.legend;
 | 
			
		||||
 | 
			
		||||
        this.$scope.yAxisLabel = this.config.yAxis.get('label');
 | 
			
		||||
 | 
			
		||||
        this.cursorGuideVertical = this.$element[0].querySelector('.js-cursor-guide--v');
 | 
			
		||||
        this.cursorGuideHorizontal = this.$element[0].querySelector('.js-cursor-guide--h');
 | 
			
		||||
        this.cursorGuide = false;
 | 
			
		||||
@@ -105,35 +103,9 @@ define([
 | 
			
		||||
        this.listenTo(this.$scope, 'plot:tickWidth', this.onTickWidthChange, this);
 | 
			
		||||
        this.listenTo(this.$scope, 'plot:highlight:set', this.onPlotHighlightSet, this);
 | 
			
		||||
        this.listenTo(this.$scope, 'plot:reinitializeCanvas', this.initCanvas, this);
 | 
			
		||||
 | 
			
		||||
        this.listenTo(this.config.xAxis, 'change:displayRange', this.onXAxisChange, this);
 | 
			
		||||
        this.listenTo(this.config.yAxis, 'change:displayRange', this.onYAxisChange, this);
 | 
			
		||||
 | 
			
		||||
        this.setUpYAxisOptions();
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    MCTPlotController.prototype.setUpYAxisOptions = function () {
 | 
			
		||||
        if (this.$scope.series.length === 1) {
 | 
			
		||||
            let metadata = this.$scope.series[0].metadata;
 | 
			
		||||
 | 
			
		||||
            this.$scope.yKeyOptions = metadata
 | 
			
		||||
                .valuesForHints(['range'])
 | 
			
		||||
                .map(function (o) {
 | 
			
		||||
                    return {
 | 
			
		||||
                        name: o.name,
 | 
			
		||||
                        key: o.key
 | 
			
		||||
                    };
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
            //  set yAxisLabel if none is set yet
 | 
			
		||||
            if (this.$scope.yAxisLabel === 'none') {
 | 
			
		||||
                let yKey = this.$scope.series[0].model.yKey,
 | 
			
		||||
                    yKeyModel = this.$scope.yKeyOptions.filter(o => o.key === yKey)[0];
 | 
			
		||||
 | 
			
		||||
                this.$scope.yAxisLabel = yKeyModel.name;
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            this.$scope.yKeyOptions = undefined;
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    MCTPlotController.prototype.onXAxisChange = function (displayBounds) {
 | 
			
		||||
@@ -310,19 +282,11 @@ define([
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    MCTPlotController.prototype.zoom = function (zoomDirection, zoomFactor) {
 | 
			
		||||
        var currentXaxis = this.$scope.xAxis.get('displayRange'),
 | 
			
		||||
            currentYaxis = this.$scope.yAxis.get('displayRange');
 | 
			
		||||
 | 
			
		||||
        // when there is no plot data, the ranges can be undefined
 | 
			
		||||
        // in which case we should not perform zoom
 | 
			
		||||
        if (!currentXaxis || !currentYaxis) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.freeze();
 | 
			
		||||
        this.trackHistory();
 | 
			
		||||
 | 
			
		||||
        var xAxisDist= (currentXaxis.max - currentXaxis.min) * zoomFactor,
 | 
			
		||||
        var currentXaxis = this.$scope.xAxis.get('displayRange'),
 | 
			
		||||
            currentYaxis = this.$scope.yAxis.get('displayRange'),
 | 
			
		||||
            xAxisDist= (currentXaxis.max - currentXaxis.min) * zoomFactor,
 | 
			
		||||
            yAxisDist = (currentYaxis.max - currentYaxis.min) * zoomFactor;
 | 
			
		||||
 | 
			
		||||
        if (zoomDirection === 'in') {
 | 
			
		||||
@@ -351,26 +315,18 @@ define([
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    MCTPlotController.prototype.wheelZoom = function (event) {
 | 
			
		||||
        const ZOOM_AMT = 0.1;
 | 
			
		||||
        event.preventDefault();
 | 
			
		||||
 | 
			
		||||
        if (!this.positionOverPlot) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let xDisplayRange = this.$scope.xAxis.get('displayRange'),
 | 
			
		||||
            yDisplayRange = this.$scope.yAxis.get('displayRange');
 | 
			
		||||
 | 
			
		||||
        // when there is no plot data, the ranges can be undefined
 | 
			
		||||
        // in which case we should not perform zoom
 | 
			
		||||
        if (!xDisplayRange || !yDisplayRange) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.freeze();
 | 
			
		||||
        window.clearTimeout(this.stillZooming);
 | 
			
		||||
 | 
			
		||||
        let xAxisDist = (xDisplayRange.max - xDisplayRange.min),
 | 
			
		||||
        let xDisplayRange = this.$scope.xAxis.get('displayRange'),
 | 
			
		||||
            yDisplayRange = this.$scope.yAxis.get('displayRange'),
 | 
			
		||||
            xAxisDist = (xDisplayRange.max - xDisplayRange.min),
 | 
			
		||||
            yAxisDist = (yDisplayRange.max - yDisplayRange.min),
 | 
			
		||||
            xDistMouseToMax = xDisplayRange.max - this.positionOverPlot.x,
 | 
			
		||||
            xDistMouseToMin = this.positionOverPlot.x - xDisplayRange.min,
 | 
			
		||||
@@ -393,24 +349,24 @@ define([
 | 
			
		||||
        if (event.wheelDelta < 0) {
 | 
			
		||||
 | 
			
		||||
            this.$scope.xAxis.set('displayRange', {
 | 
			
		||||
                min: xDisplayRange.min + ((xAxisDist * ZOOM_AMT) * xAxisMinDist),
 | 
			
		||||
                max: xDisplayRange.max - ((xAxisDist * ZOOM_AMT) * xAxisMaxDist)
 | 
			
		||||
                min: xDisplayRange.min + ((xAxisDist * 0.01) * xAxisMinDist),
 | 
			
		||||
                max: xDisplayRange.max - ((xAxisDist * 0.01) * xAxisMaxDist)
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            this.$scope.yAxis.set('displayRange', {
 | 
			
		||||
                min: yDisplayRange.min + ((yAxisDist * ZOOM_AMT) * yAxisMinDist),
 | 
			
		||||
                max: yDisplayRange.max - ((yAxisDist * ZOOM_AMT) * yAxisMaxDist)
 | 
			
		||||
                min: yDisplayRange.min + ((yAxisDist * 0.01) * yAxisMinDist),
 | 
			
		||||
                max: yDisplayRange.max - ((yAxisDist * 0.01) * yAxisMaxDist)
 | 
			
		||||
            });
 | 
			
		||||
        } else if (event.wheelDelta >= 0) {
 | 
			
		||||
 | 
			
		||||
            this.$scope.xAxis.set('displayRange', {
 | 
			
		||||
                min: xDisplayRange.min - ((xAxisDist * ZOOM_AMT) * xAxisMinDist),
 | 
			
		||||
                max: xDisplayRange.max + ((xAxisDist * ZOOM_AMT) * xAxisMaxDist)
 | 
			
		||||
                min: xDisplayRange.min - ((xAxisDist * 0.01) * xAxisMinDist),
 | 
			
		||||
                max: xDisplayRange.max + ((xAxisDist * 0.01) * xAxisMaxDist)
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            this.$scope.yAxis.set('displayRange', {
 | 
			
		||||
                min: yDisplayRange.min - ((yAxisDist * ZOOM_AMT) * yAxisMinDist),
 | 
			
		||||
                max: yDisplayRange.max + ((yAxisDist * ZOOM_AMT) * yAxisMaxDist)
 | 
			
		||||
                min: yDisplayRange.min - ((yAxisDist * 0.01) * yAxisMinDist),
 | 
			
		||||
                max: yDisplayRange.max + ((yAxisDist * 0.01) * yAxisMaxDist)
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -521,13 +477,5 @@ define([
 | 
			
		||||
        this.cursorGuide = !this.cursorGuide;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    MCTPlotController.prototype.toggleYAxisLabel = function (label, options, series) {
 | 
			
		||||
        let yAxisObject = options.filter(o => o.name === label)[0];
 | 
			
		||||
 | 
			
		||||
        if (yAxisObject) {
 | 
			
		||||
            series.emit('change:yKey', yAxisObject.key);
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    return MCTPlotController;
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
@@ -63,11 +63,8 @@ define([
 | 
			
		||||
 | 
			
		||||
        $scope.pending = 0;
 | 
			
		||||
 | 
			
		||||
        this.clearData = this.clearData.bind(this);
 | 
			
		||||
 | 
			
		||||
        this.listenTo($scope, 'user:viewport:change:end', this.onUserViewportChangeEnd, this);
 | 
			
		||||
        this.listenTo($scope, '$destroy', this.destroy, this);
 | 
			
		||||
        this.listenTo($scope, 'clearData', this.clearData);
 | 
			
		||||
 | 
			
		||||
        this.config = this.getConfig(this.$scope.domainObject);
 | 
			
		||||
        this.listenTo(this.config.series, 'add', this.addSeries, this);
 | 
			
		||||
@@ -77,7 +74,6 @@ define([
 | 
			
		||||
        this.followTimeConductor();
 | 
			
		||||
 | 
			
		||||
        this.newStyleDomainObject = $scope.domainObject.useCapability('adapter');
 | 
			
		||||
        this.keyString = this.openmct.objects.makeKeyString(this.newStyleDomainObject.identifier);
 | 
			
		||||
 | 
			
		||||
        this.filterObserver = this.openmct.objects.observe(
 | 
			
		||||
            this.newStyleDomainObject,
 | 
			
		||||
@@ -152,6 +148,7 @@ define([
 | 
			
		||||
            });
 | 
			
		||||
            configStore.add(configId, config);
 | 
			
		||||
        }
 | 
			
		||||
        configStore.track(configId);
 | 
			
		||||
        return config;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
@@ -160,8 +157,7 @@ define([
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    PlotController.prototype.destroy = function () {
 | 
			
		||||
        configStore.deleteStore(this.config.id);
 | 
			
		||||
 | 
			
		||||
        configStore.untrack(this.config.id);
 | 
			
		||||
        this.stopListening();
 | 
			
		||||
        if (this.checkForSize) {
 | 
			
		||||
            clearInterval(this.checkForSize);
 | 
			
		||||
@@ -223,7 +219,6 @@ define([
 | 
			
		||||
 | 
			
		||||
    PlotController.prototype.stopLoading = function () {
 | 
			
		||||
        this.$scope.pending -= 1;
 | 
			
		||||
        this.$scope.$digest();
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -267,12 +262,6 @@ define([
 | 
			
		||||
        });
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    PlotController.prototype.clearData = function () {
 | 
			
		||||
        this.config.series.forEach(function (series) {
 | 
			
		||||
            series.refresh();
 | 
			
		||||
        });
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Export view as JPG.
 | 
			
		||||
     */
 | 
			
		||||
 
 | 
			
		||||
@@ -79,15 +79,6 @@ define([
 | 
			
		||||
                    $scope.$broadcast('plot:tickWidth', _.max(tickWidthMap));
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            function compositionReorder(reorderPlan) {
 | 
			
		||||
                let oldComposition = telemetryObjects.slice();
 | 
			
		||||
 | 
			
		||||
                reorderPlan.forEach((reorder) => {
 | 
			
		||||
                    telemetryObjects[reorder.newIndex] = oldComposition[reorder.oldIndex];
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            thisRequest.pending += 1;
 | 
			
		||||
            openmct.objects.get(domainObject.getId())
 | 
			
		||||
                .then(function (obj) {
 | 
			
		||||
@@ -98,12 +89,10 @@ define([
 | 
			
		||||
                    composition = openmct.composition.get(obj);
 | 
			
		||||
                    composition.on('add', addChild);
 | 
			
		||||
                    composition.on('remove', removeChild);
 | 
			
		||||
                    composition.on('reorder', compositionReorder);
 | 
			
		||||
                    composition.load();
 | 
			
		||||
                    unlisten = function () {
 | 
			
		||||
                        composition.off('add', addChild);
 | 
			
		||||
                        composition.off('remove', removeChild);
 | 
			
		||||
                        composition.off('reorder', compositionReorder);
 | 
			
		||||
                    };
 | 
			
		||||
                });
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -23,7 +23,6 @@
 | 
			
		||||
define([
 | 
			
		||||
    'lodash',
 | 
			
		||||
    './utcTimeSystem/plugin',
 | 
			
		||||
    './localTimeSystem/plugin',
 | 
			
		||||
    '../../example/generator/plugin',
 | 
			
		||||
    './autoflow/AutoflowTabularPlugin',
 | 
			
		||||
    './timeConductor/plugin',
 | 
			
		||||
@@ -42,13 +41,10 @@ define([
 | 
			
		||||
    './tabs/plugin',
 | 
			
		||||
    './LADTable/plugin',
 | 
			
		||||
    './filters/plugin',
 | 
			
		||||
    './objectMigration/plugin',
 | 
			
		||||
    './goToOriginalAction/plugin',
 | 
			
		||||
    './clearData/plugin'
 | 
			
		||||
    './objectMigration/plugin'
 | 
			
		||||
], function (
 | 
			
		||||
    _,
 | 
			
		||||
    UTCTimeSystem,
 | 
			
		||||
    LocalTimeSystem,
 | 
			
		||||
    GeneratorPlugin,
 | 
			
		||||
    AutoflowPlugin,
 | 
			
		||||
    TimeConductorPlugin,
 | 
			
		||||
@@ -67,9 +63,7 @@ define([
 | 
			
		||||
    Tabs,
 | 
			
		||||
    LADTable,
 | 
			
		||||
    Filters,
 | 
			
		||||
    ObjectMigration,
 | 
			
		||||
    GoToOriginalAction,
 | 
			
		||||
    ClearData
 | 
			
		||||
    ObjectMigration
 | 
			
		||||
) {
 | 
			
		||||
    var bundleMap = {
 | 
			
		||||
        LocalStorage: 'platform/persistence/local',
 | 
			
		||||
@@ -85,7 +79,6 @@ define([
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    plugins.UTCTimeSystem = UTCTimeSystem;
 | 
			
		||||
    plugins.LocalTimeSystem = LocalTimeSystem;
 | 
			
		||||
 | 
			
		||||
    plugins.ImportExport = ImportExport;
 | 
			
		||||
 | 
			
		||||
@@ -167,8 +160,6 @@ define([
 | 
			
		||||
    plugins.LADTable = LADTable;
 | 
			
		||||
    plugins.Filters = Filters;
 | 
			
		||||
    plugins.ObjectMigration = ObjectMigration.default;
 | 
			
		||||
    plugins.GoToOriginalAction = GoToOriginalAction.default;
 | 
			
		||||
    plugins.ClearData = ClearData;
 | 
			
		||||
 | 
			
		||||
    return plugins;
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
@@ -23,7 +23,6 @@
 | 
			
		||||
export default class RemoveAction {
 | 
			
		||||
    constructor(openmct) {
 | 
			
		||||
        this.name = 'Remove';
 | 
			
		||||
        this.key = 'remove';
 | 
			
		||||
        this.description = 'Remove this object from its containing object.';
 | 
			
		||||
        this.cssClass = "icon-trash";
 | 
			
		||||
 | 
			
		||||
@@ -86,17 +85,16 @@ export default class RemoveAction {
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        this.openmct.objects.mutate(parent, 'composition', composition);
 | 
			
		||||
 | 
			
		||||
        if (this.inNavigationPath(child) && this.openmct.editor.isEditing()) {
 | 
			
		||||
            this.openmct.editor.save();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    appliesTo(objectPath) {
 | 
			
		||||
        let object = objectPath[0];
 | 
			
		||||
        let objectType = object && this.openmct.types.get(object.type);
 | 
			
		||||
        let parent = objectPath[1];
 | 
			
		||||
        let parentType = parent && this.openmct.types.get(parent.type);
 | 
			
		||||
 | 
			
		||||
        return parentType &&
 | 
			
		||||
        return objectType.definition.creatable &&
 | 
			
		||||
            parentType &&
 | 
			
		||||
            parentType.definition.creatable &&
 | 
			
		||||
            Array.isArray(parent.composition);
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user